开发包源码下载

1.开发包介绍

此开发主要是针对AOVX的产品,对设备上行数据进行解码以及平台下行控制命令进行组包的工具包。采用了Java SpringBoot2.x框架。
开发主要是实现了对设备上报数据的解包,将设备上报的二进制流数据转成我们所熟知的JSON字符串。

2.源码介绍

项目名称为:jt808-decode,方法入口类为DataParse.

此类中包含了两个方法:
(1)receiveData(String rowData):接收设备上报的原始数据(16进制),并将数据转成JSON字符串
(2)splitData(String rowData):对设备上报的原始数据进行拆包详解,返回一个拆包分段的介绍

项目中包含了3个包文件:
(1)constant:定义了解析设备原始数据过程中用到的一些常量或者枚举定义

(2)model:定义了一些解包过程中的实体类

(3)utils:方法工具包,里面是解包过程中使用的一些方法类

2.1.receiveData(String rowData)

根据不同的消息ID调用不同的解析方法解析:

/**
     * Receive the data reported by the device (hex) and parse it into a JSON string
     * @param rowData Data reported by the device (hex)
     * @return json
     */
    public static String receiveData(String rowData) throws Exception {
        if(StringUtils.isBlank(rowData)){
            return null;
        }
        //Convert Hex string to ByteBuf
        ByteBuf byteBuf = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(rowData));
        Object obj= Jt808PacketUtil.decodeJt808Packet(byteBuf);
        String resultJson="";
        if(obj==null){
            ReferenceCountUtil.release(byteBuf);
            return null;
        }else{
            Jt808Message jt808Msg= Jt808ProtocolDecoder.decode((ByteBuf)obj);
            switch (jt808Msg.getMsgId()){
                case 0x0001:
                    CommonReplyParam commonReplyParam= Message0001Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    resultJson=JSON.toJSONString(commonReplyParam);
                    break;
                case 0x0002:
                    Heartbeat heartbeat= Message0002Parser.parse(jt808Msg);
                    heartbeat.setReplyMsg(Jt808PacketUtil.reply8001(jt808Msg));
                    resultJson=JSON.toJSONString(heartbeat);
                    break;
                case 0x0100:
                    TerminalRegisterInfo registerInfo=Message0100Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    registerInfo.setReplyMsg(Jt808PacketUtil.reply8100(jt808Msg,registerInfo.getAuthCode()));
                    resultJson=JSON.toJSONString(registerInfo);
                    break;
                case 0x0102:
                    TerminalAuthInfo authInfo=Message0102Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    authInfo.setReplyMsg(Jt808PacketUtil.reply8001(jt808Msg));
                    resultJson=JSON.toJSONString(authInfo);
                    break;
                case 0x0104:
                    DeviceParam deviceParam=Message0104Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    resultJson=JSON.toJSONString(deviceParam);
                    break;
                case 0x0200:
                    Location location= Message0200Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    location.setReplyMsg(Jt808PacketUtil.reply8001(jt808Msg));
                    resultJson=JSON.toJSONString(location);
                    break;
                case 0x0900:
                    PassThroughData throughData=Message0900Parser.parser(jt808Msg,jt808Msg.getMsgBody());
                    resultJson=JSON.toJSONString(throughData);
                    break;
                default:
                    break;
            }
        }
        return resultJson;
    }

2.2.splitData(String rowData)

按照协议内容格式对数据进行拆分说明

/**
     * Introduction to the data unpacking process for hex strings reported by devices
     * @param rowData Data reported by the device (hex)
     * @return
     */
    public static List<String> splitData(String rowData){
        if(StringUtils.isBlank(rowData)){
            return null;
        }
        List<String> dataArr=new ArrayList<>();
        //Convert Hex string to ByteBuf
        ByteBuf byteBuf = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(rowData));
        Object obj= Jt808PacketUtil.decodeJt808Packet(byteBuf);
        if(obj==null){
            ReferenceCountUtil.release(byteBuf);
            return null;
        }else{
            ByteBuf msgBuf= (ByteBuf) obj;
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedByte(),2),"Start Flag"));
            int msgId=msgBuf.readUnsignedShort();
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgId,4),"Message ID"));
            //message body properties
            short msgBodyAttr = msgBuf.readShort();
            //Version ID (version ID 0 refers to the version in 2011 and 1 refers to the version in 2019)
            int versionFlag = (msgBodyAttr & 0b01000000_00000000)>0?1:0;
            //is multi packet?
            boolean multiPacket = (msgBodyAttr & 0b00100000_00000000) > 0;
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBodyAttr,4),"Properties of Message Body"));
            //Terminal phone number array,JT808-2019 is 10 bytes
            byte[] phoneNumberArr;
            if (versionFlag == 1) {
                dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedByte(),2),"Protocol Version"));
                phoneNumberArr = new byte[10];
            } else {
                phoneNumberArr = new byte[6];
            }
            msgBuf.readBytes(phoneNumberArr);
            dataArr.add(String.format("%s-->%s",ByteBufUtil.hexDump(phoneNumberArr),"Device Number"));
            //Message serial number
            int msgFlowId = msgBuf.readUnsignedShort();
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgFlowId,4),"Message serial number"));
            //multi packet?
            if (multiPacket) {
                dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedShort(),4),"Packet Total Count"));
                dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedShort(),4),"Packet Order"));
            }
            //message body length
            int msgBodyLen = msgBodyAttr & 0b00000011_11111111;
            if(msgBodyLen>msgBuf.readableBytes()-2){
                byte[] msgBodyArr=new byte[msgBuf.readableBytes()-2];
                msgBuf.readBytes(msgBodyArr);
                dataArr.add(String.format("%s-->%s",ByteBufUtil.hexDump(msgBodyArr),"Insufficient message body length!"));
            }else{
                ByteBuf msgBodyBuf =msgBuf.readSlice(msgBuf.readableBytes()-2);
                switch (msgId){
                    case 0x0001:
                        dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBodyBuf.readShort(),4),"Response serial number"));
                        dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBodyBuf.readShort(),4),"Response message ID"));
                        dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBodyBuf.readShort(),2),"Results (0: success; 1: failure; 2: message error; 3: not supported)"));
                        break;
                    case 0x0002:
                        if(msgBodyBuf.readableBytes()>0){
                            byte[] msgBodyArr=new byte[msgBodyBuf.readableBytes()];
                            msgBodyBuf.readBytes(msgBodyArr);
                            dataArr.add(String.format("%s-->%s",ByteBufUtil.hexDump(msgBodyArr),"Message Body"));
                        }
                        break;
                    case 0x0100:
                        if(versionFlag == 1){
                            SplitUtil.splitTerminalRegisterInfo(msgBodyBuf,dataArr);
                        }else{
                            SplitUtil.splitTerminalRegisterInfo2019(msgBodyBuf,dataArr);
                        }
                        break;
                    case 0x0102:
                        SplitUtil.splitAuthInfo(msgBodyBuf,dataArr,versionFlag);
                        break;
                    case 0x0104:
                        SplitUtil.splitTerminalParameterResponse(msgBodyBuf,dataArr);
                        break;
                    case 0x0200:
                        SplitUtil.splitLocationInfo(msgBodyBuf,dataArr);
                        break;
                    case 0x0900:
                        dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBodyBuf.readUnsignedByte(),2),"Transparent message type"));
                        if(msgBodyBuf.readableBytes()>0){
                            byte [] msgContentArr=new byte[msgBodyBuf.readableBytes()];
                            msgBodyBuf.readBytes(msgContentArr);
                            dataArr.add(String.format("%s-->%s",ByteBufUtil.hexDump(msgContentArr),"Transparent message content"));
                        }
                        break;
                    default:
                        byte[] msgBodyArr=new byte[msgBodyBuf.readableBytes()];
                        msgBodyBuf.readBytes(msgBodyArr);
                        dataArr.add(String.format("%s-->%s",ByteBufUtil.hexDump(msgBodyArr),"Message Body"));
                        break;
                }
            }
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedByte(),2),"Check Code"));
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedByte(),2),"End Flag"));
        }
        return dataArr;
    }

3.测试

3.1.解码方法效果

调用示例:

    @Test
    public void receiveData() throws Exception {
        String rowData="7E020000CA593054482897004800000000B0080010000000000000000000000000000023030110180430019E310100F00E0136019A04C14B10000083039F03F22C414F56585F414D3330302D474C5F48322E305F424739354D334C415230324130345F56322E302E343A763135F423542160033C41C354216000E04DC33CB74B797D02B8C0F4C114700274BD3EB74B797D02BEBBF60A00090000000000000000F70400000DE3F81D04086459305448289789320420000012218671414D3330302D474C0000F912000F000000000000000000000000000000008C7E";
        String parseDataJson=dataParser.receiveData(rowData);
        System.out.println("ParseData:"+parseDataJson);
    }

输出内容:

{
    "acc": 0,
    "alarmTypeList": [],
    "altitude": 0,
    "battery": 0,
    "direction": 0,
    "expandMap": {
        "wifi": "[{\"rssi\":-61,\"mac\":\"54:21:60:03:3c:41\"},{\"rssi\":-61,\"mac\":\"54:21:60:00:e0:4d\"},{\"rssi\":-64,\"mac\":\"3c:b7:4b:79:7e:b8\"},{\"rssi\":-67,\"mac\":\"f4:c1:14:70:02:74\"},{\"rssi\":-69,\"mac\":\"3e:b7:4b:79:7e:be\"}]",
        "auxiliary": "{\"gnss_time\":\"000000000000\",\"acc_duration\":0,\"position_age\":0,\"hdop\":0}",
        "sensor": "[{\"light\":0,\"accelerometer\":\"x:0,y:0,z:0\",\"data_type\":0}]",
        "software_version": "\"AOVX_AM300-GL_H2.0_BG95M3LAR02A04_V2.0.4:v15\"",
        "device": "{\"iccid\":\"89320420000012218671\",\"imei\":\"0864593054482897\",\"device_type\":\"AM300-GL\\u0000\\u0000\",\"work_model\":4}"
    },
    "gnssTime": "2023-03-01T10:18:04Z",
    "gnssValue": 0,
    "gsmValue": 158,
    "hexMsgId": "0x0200",
    "lat": 0.0,
    "lbsCells": ["310,410,33539,79776528,-97"],
    "locationType": 0,
    "lon": 0.0,
    "mileage": 0.0,
    "msgFlowId": 72,
    "recvTime": "2023-04-27T08:34:11.902Z",
    "replyMsg": "7e80010005593054482897004800480200004c7e",
    "speed": 0.0,
    "statusMap": {
        "operate": 1,
        "load": 0,
        "realtime_data": 1,
        "oil_electric": 0,
        "normal_data": 0,
        "door_lock": 0,
        "oil_circuit": 0,
        "confidential": 0
    },
    "terminalNum": "593054482897",
    "voltage": 3.555
}

3.2.拆包方法效果

调用示例:

    @Test
    public void splitData() throws Exception {
        String rowData="7E020000CA593054482897004800000000B0080010000000000000000000000000000023030110180430019E310100F00E0136019A04C14B10000083039F03F22C414F56585F414D3330302D474C5F48322E305F424739354D334C415230324130345F56322E302E343A763135F423542160033C41C354216000E04DC33CB74B797D02B8C0F4C114700274BD3EB74B797D02BEBBF60A00090000000000000000F70400000DE3F81D04086459305448289789320420000012218671414D3330302D474C0000F912000F000000000000000000000000000000008C7E";

        List<String> splitDataList=dataParser.splitData(rowData);
        System.out.println("SplitData:"+splitDataList);
    }

输出内容:

[
7E- - > Start Flag, 
0200-- > Message ID, 
00 CA-- > Properties of Message Body, 
593054482897-- > Device Number, 
0048-- > Message serial number, 
00000000-- > Alarm flag, 
B0080010-- > Terminal status, 
00000000-- > Latitude, 
00000000-- > Longitude, 
0000-- > Altitude, 
2303-- > Speed, 
1101804-- > Direction, 
30019e310100-- > Datetime, 
F0-- > Extension ID, 
0E- - > Extension information length, 
0136019a04c14b10000083039f03-- > Extension information, 
F2-- > Extension ID, 
2C-- > Extension information length, 
414f56585f414d3330302d474c5f48322e305f424739354d334c415230324130345f56322e302e343a763135-- > Extension information, 
F4-- > Extension ID, 
23-- > Extension information length, 
542160033c41c354216000e04dc33cb74b797eb8c0f4c114700274bd3eb74b797ebebb-- > Extension information, 
F6-- > Extension ID, 
0A-- > Extension information length, 
00090000000000000000-- > Extension information, 
F7-- > Extension ID, 
04-- > Extension information length, 
00000de3-- > Extension information, 
F8-- > Extension ID, 
1D-- > Extension information length, 
04086459305448289789320420000012218671414d3330302d474c0000-- > Extension information, 
F9-- > Extension ID, 
12-- > Extension information length, 
000f00000000000000000000000000000000-- > Extension information, 
8 C-- > Check Code, 
7E- - > End Flag
]

4.协议组包

4.1.组包方法 encodeCommand(String paramsJson)


传入的JSON字符串

4.2.传入JSON参数说明

{"msgFlowId":1,"msgId":33027,"params":{1:10,61488:"AT+QUERY?"},"terminalNum":"12345678901"}
字段名称 字段类型 字段说明
terminalNum String 设备S/N
msgFlowId int 指令流水号(1~65535)
msgId int 协议定义的消息ID,例如:0x8103,0x8104,0x8105
params Map key:value;其中,key:命令ID,value:配置的值

其中0x8103(设置终端参数)

对应的params,可以设置的命令ID以及传入的值说明。

其中0x8104(查询终端参数)

params为空

其中0x8105(终端控制命令)

4.3.组包方法示例

此方法是以0x8103为例,同时设置心跳间隔以及发送AT命令
对应的JSON字符串如下:

{"msgFlowId":1,"msgId":33027,"params":{1:10,61488:"AT+QUERY?"},"terminalNum":"12345678901"}

作者:admin  创建时间:2023-04-26 11:02
最后编辑:admin  更新时间:2024-10-08 16:22