大华条码秤对接经验总结

2,853 阅读3分钟

前言

一个超市里常用的条码秤对接经历

输入图片说明

tcp/ip

该条码秤使用 tcp/ip 协议进行通信,在 java 中,tcp/ip 通信被封装成了 Socket 类,所以使用起来还算简单。

以下是一个简单的 socket 示例

try {
    socket = new Socket();
    InetSocketAddress socketAddress = new InetSocketAddress("192.168.3.150", 4001);
    socket.connect(socketAddress, 10 * 1000);
    socket.setSoTimeout(5 * 1000);
    if (socket.isConnected()) {
        // 向 socket 服务器写入数据
        byte[] bytes = {0x21, 0x30, 0x49, 0x41, 0x0d, 0x0a, 0x03};
        socket.getOutputStream().write(bytes);
        // 接收 socket 服务器返回的数据
        InputStreamReader ipr = new InputStreamReader(socket.getInputStream());
        bufferedReader = new BufferedReader(ipr);
        String str = bufferedReader.readLine();
    }
} catch (IOException error) {
    error.printStackTrace();
}

建议先实例化 socket 再进行连接,因为这样可以通过 setSoTimeout 函数设置超时时间,避免线程阻塞,同时 socket 的连接不能在主线程中进行,否则会报错。

发送数据到条码秤

大华条码秤 socket 服务器的端口为 4001,需要给大华秤盘设置一个固定的 ip 地址。

设置方式如下:

按下功能键 -> 输入9002 -> 按下确认 -> 开始输入 ip 地址,输入 . 需要按下去皮键 -> 在输入主机地址后按下去皮键完成设置

在大华的文档中标明,每个指令都得以 0x0d, 0x0a, 0x03 为结束符,所以可以封装一个函数,如下:

private String sendCommand(byte[] bytes) {
    byte[] suffix = {0x0d, 0x0a, 0x03};
    try {
        if (socket != null && socket.isConnected() && socket.getOutputStream() != null) {

            byte[] command = byteMerger(bytes, suffix);
            socket.getOutputStream().write(command);
            return "SEND_SUCCESS";

        } else {
            return "NOT_CONNECT";
        }
    } catch (IOException e) {
        e.printStackTrace();
        return "SEND_FAIL";
    }
}

private static byte[] byteMerger(byte[] bt1, byte[] bt2){
    byte[] bt3 = new byte[bt1.length + bt2.length];
    System.arraycopy(bt1, 0, bt3, 0, bt1.length);
    System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
    return bt3;
}

首先发送清除 plu 和报表指令到条码秤来初始化条码秤。

输入图片说明

public boolean clearData() {
    if (socket != null && socket.isConnected()) {
        try {
            byte[] bytes = {0x21, 0x30, 0x49, 0x41};
            sendCommand(bytes)
            byte[] bytes2 = {0x21, 0x30, 0x48, 0x41};
            sendCommand(bytes2)
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    } else {
        return false;
    }
}

这里有一点需要注意,因为初始化报表会耗费一定的时间,所以不能在清除报表后立马同步商品数据,否则会导致同步失败。

关于商品数据传入文档描述如下:

输入图片说明

输入图片说明

这里针对几个关键信息作出说明:

  • plu 条码秤中货品的助记码,可在条码秤使用快捷键或录入 plu 码进行搜索
  • code 商品代码,长度7位,用于条码秤打印条码标签后在系统数据库中进行匹配,第一位固定为店名号最后一位,意味着再怎样进行设置打印后都为店名号
  • price 商品价格,单位为分,长度6位,不足需补位0
  • goodsName 商品名,需要转换成区位码转换函数如下
private static String bytes2HexString(byte b) {
    return bytes2HexString(new byte[] { b });
}

private static String bytes2HexString(byte[] b) {
    String ret = "";
    for (int i = 0; i < b.length; i++) {
        String hex = Integer.toHexString(b[i] & 0xFF);
        if (hex.length() == 1) {
            hex = '0' + hex;
        }
        ret += hex.toUpperCase();
    }
    return ret;
}

private String StringToAreaByteCode(String str) {
    String result = "";
    for (int i = 0; i < str.length(); i++) {
        result += charToAreaByteCode(str.charAt(i));
    }

    return result;
}

private String charToAreaByteCode(char str) {
        byte[] bs = new byte[0];
        String singleStr = String.valueOf(str);
        try {
            bs = singleStr.getBytes("GB2312");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        if (bs.length == 2) { // 正常字符
            String s = "";
            String t = "";
            for (int i = 0; i < bs.length; i++) {
                int a = Integer.parseInt(bytes2HexString(bs[i]), 16);
                t = (a - 0x80 - 0x20) + "";
                if(t.length() == 1){
                    t = 0 + t;
                }
                s += t;
            }

            return s;
        } else if (bs.length == 1) { // ascii 码
            String qw = Integer.parseInt(bytes2HexString(bs[0]), 16) - 0x21 + 301 + "";
            while (qw.length() < 4) {
                qw = "0" + qw;
            }
            return qw;
        } else {
            return "";
        }
    }

发送商品数据代码如下:

public boolean setGoods(BarCodeScaleGoods goods) {
    String plu = goods.pluCode;
    String code = goods.code;
    String price = String.valueOf(new Double(goods.price * 100).intValue());
    String goodsName = StringToAreaByteCode(goods.goodsName);
    String unit = goods.unit;

    while (plu.length() < 4) {
        plu = '0' + plu;
    }

    while (price.length() < 6) {
        price = '0' + price;
    }

    String goodsInfo = String.format("!0V%sA%s%s%s00000099901010000000000000000000000000000000000000000000000B%sCDE", plu, code, price, unit, goodsName);
    byte[] bytes = goodsInfo.getBytes();
    String result = sendCommand(bytes);

    if (result.equals("SEND_SUCCESS")) {
        try {
            InputStreamReader ipr = new InputStreamReader(socket.getInputStream());
            bufferedReader = new BufferedReader(ipr);
            String str = bufferedReader.readLine();
            if (str.length() > 0) {
                return true;
            } else {
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    } else {
        return false;
    }
}

因为发送商品数据的指令每个字段没有明确的标识位,大华在解析指令时是以下标来获取信息的,所以得保证每个字段的信息字节数是固定的,所以得对动态的信息进行补位,代码如下:

while (plu.length() < 4) {
    plu = '0' + plu;
}

while (price.length() < 6) {
    price = '0' + price;
}

需在空字节上填充0。

在完成发送后,判断条码秤是否成功录入商品的条件是条码秤有没有返回信息,所以就有以下代码来判断是否录入成功。

if (result.equals("SEND_SUCCESS")) {
    try {
        InputStreamReader ipr = new InputStreamReader(socket.getInputStream());
        bufferedReader = new BufferedReader(ipr);
        String str = bufferedReader.readLine();
        if (str.length() > 0) {
            return true;
        } else {
            return false;
        }
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
} else {
    return false;
}

最后需要同步热键设置,用于快捷键录入商品,文档描述如下:

输入图片说明

代码如下:

public void setHotKey() {
    String str = "!0L00A";
    for (int i = 1; i <= 71; i++) {
        if (String.valueOf(i).length() == 1) {
            str += "000" + i;
        } else if (String.valueOf(i).length() == 2) {
            str += "00" + i;
        }
    }
    str += "B";
    byte[] bytes = str.getBytes();
    sendCommand(bytes);
}