JT808封包解包实例
一、JT808 协议介绍
1.1 BCD 码
BCD(Binary-Coded Decimal,二进制编码的十进制)是一种用于表示十进制数的编码方法。在 BCD 编码中,每个十进制数字(0 到 9)都用四位二进制数来表示。这种编码方式的优点是便于在人机交互中显示和处理十进制数,因为它直接对应于人类习惯的十进制系统。
例如,十进制数字 5 在 BCD 中表示为 0101,数字 9 表示为 1001。
1.1.1 BCD 编码的特点
1.不使用所有的四位二进制组合:由于每个数字仅使用四位来表示 0 到 9,共 10 个可能的值,因此有些组合(如 1010 到 1111)在标准 BCD 中是未使用的。
2.易于转换:BCD 编码使得数字的转换和显示更为简单,特别是在需要频繁进行十进制与二进制转换的应用中。
1.1.2 使用场景
1.金融计算:因为 BCD 可以精确表示十进制数,避免了浮点数运算中的舍入误差。
2.数字显示设备:如电子表、计算器等,需要直接显示十进制数的设备常使用 BCD。
3.嵌入式系统:一些嵌入式系统为了简化十进制数的处理,也会采用 BCD 编码。
1.2 JT808 协议数据编码
1.2.1 JT808 介绍
JT808 是中国交通部发布的《道路运输车辆卫星定位系统终端通讯协议及数据格式》的简称。该协议规定了道路运输车辆卫星定位系统终端与监控中心之间的通讯协议和数据格式。协议采用的通信方式应符合 JT/T 794 中的相关规定,通信协议采用 TCP 或 UDP,平台 作为服务器端,终端作为客户端。当数据通信链路异常时,终端可以采用 SMS 消息方式进行通信。
1.2.2 JT808 报文数据格式
1.2.2.1 数据类型
1.2.2.2 传输规则
协议采用大端模式(big-endian)的网络字节序来传递字和双字。
约定如下:
1.字节(BYTE)的传输约定:按照字节流的方式传输;
2.字(WORD)的传输约定:先传递高八位,再传递低八位;
3.双字(DWORD)的传输约定:先传递高 24 位,然后传递高 16 位,再传递高八位,
最后传递低八位。
1.2.2.3 消息构成
每条消息由标识位、消息头、消息体和校验码组成,消息结构图如下图所示:
1.2.2.3.1 标识位
采用 0x7e 表示,若校验码、消息头以及消息体中出现 0x7e,则要进行转义处理,转义规则定义如下:
0x7e <————> 0x7d 后紧跟一个 0x02;
0x7d <————> 0x7d 后紧跟一个 0x01。
转义处理过程如下:
发送消息时:消息封装——> 计算并填充校验码——> 转义;
接收消息时:转义还原——> 验证校验码——> 解析消息。
示例:
发送一包内容为 0x30 0x7e 0x08 0x7d 0x55 的数据包,则经过封装如下:0x7e 0x30 7d 0x02 0x08 0x7d
0x01 0x55 0x7e。
1.2.2.3.2 消息头
数据加密方式:
——bit10~bit12 为数据加密标识位;
——当此三位都为 0,表示消息体不加密;
——当第 10 位为 1,表示消息体经过 RSA 算法加密;
——其他保留。
分包:
当消息体属性中第 13 位为 1 时表示消息体为长消息,进行分包发送处理,具体分包信 5
息由消息包封装项决定;若第 13 位为 0,则消息头中无消息包封装项字段。
消息包封装项内容
1.2.2.3.3 校验码
校验码指从消息头开始,同后一字节异或,直到校验码前一个字节,占用一个字节。
二、演示功能概述
本文使用 Air780EP 核心板,运用 LuatOS 数据格式转换函数,完成 JT808 数据帧格式的封包和解包,具体实验如下:
1、构建立通用应答数据帧(协议可参考第五章节 JT808 协议 8.1 与 8.2);
2、构建终端注册数据帧(协议可参考第五章节 JT808 协议 8.5);
3、构建位置信息汇报数据帧(协议可参考第五章节 JT808 协议 8.18);
4、构建一个完整的 JT808 注册数据帧(协议可参考 4.4.1 、8.5)
5、解析一个完整 JT808 终端注册应答数据帧(协议可参考 4.4.1、8.1 与 8.2)
三、准备硬件环境
参考:硬件环境清单第二章节内容,准备以及组装好硬件环境。
四、软件环境
“凡事预则立,不预则废。”在详细阐述本功能示例之前,我们需先精心筹备好以下软件环境。
1. Luatools工具;
2. 内核固件文件(底层core固件文件):LuatOS-SoC_V2002_Air780EP;参考项目使用的内核固件;
3. luatos需要的脚本和资源文件
lib脚本文件:使用Luatools烧录时,勾选 添加默认lib 选项,使用默认lib脚本文件;
4、JT808 协议
准备好软件环境之后,接下来查看如何烧录项目文件到Air780EP核心板,将本篇文章中演示使用的项目文件烧录到Air780EP核心板中。
5.1 开发板按钮与指示灯图示与说明
5.2 硬件安装与连接
5.2.1 SIM 卡安装
5.2.2 实物连接图
注:开发板与电脑通过 TYPE-C 线连接,用于通信与供电,所以必须使用具有 USB 通信功能的 TYPE-C 线才可以;
六、代码示例介绍
6.1 完整程序清单
注:完整复制后保存为 main.lua,可直接使用
-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "JT808"
VERSION = "2.0.0"
--[[
本demo演示使用string.pack与unpack函数,实现JT808 终端注册协议数据生成与解析
]]
--加载sys库
sys = require("sys")
-- Air780EP的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
pm.power(pm.PWK_MODE, false)
end
local netLed = require("netLed")
--GPIO27配置为输出,用作网络指示灯
local LEDA= gpio.setup(27, 0, gpio.PULLUP)
-- 自定义位运算函数
local bit = {}
--终端消息ID
T_COMMON_RSP = 0x0001
T_REGISTER = 0x0100
function bit.bxor(a, b)
return a ~ b -- 按位异或
end
--十六进制转二进制
local function hexToBinary(hexStr)
local binaryData = {}
for i = 1, #hexStr, 2 do
local byte = tonumber(hexStr:sub(i, i+1), 16) -- 每两个字符转换为一个字节
table.insert(binaryData, string.char(byte))
end
return table.concat(binaryData) -- 拼接成二进制字符串
end
--字符串转字节数组
local function stringToBytes(hexStr)
local bytes = {}
for i = 1, #hexStr, 2 do
local byteStr = hexStr:sub(i, i+1)
local byte = tonumber(byteStr, 16)
table.insert(bytes, byte)
end
return bytes
end
--BCD编码
local function encodeBcdNum(d, n)
if d:len() < n then
return (string.rep('0', n - d:len()) .. d):fromHex()
else
return (d:sub(1, n)):fromHex()
end
end
--计算异或校验(十六进制字符串)
local function calculateXor(data)
local sum = 0
for i = 1, #data, 2 do
local byte = tonumber(data:sub(i, i+1), 16)
-- 检查是否转换成功
if not byte then
error(string.format("Invalid hex character: '%s' at position %d", byteStr, i))
end
-- 打印当前字节的值(十六进制和十进制)
--print(string.format("当前字节: %s (十进制: %d)", byteStr, byte))
if not byte then
error("Invalid hex character in input string!")
end
sum = bit.bxor(sum, byte)
-- 打印异或后的中间结果
--print(string.format("异或后 sum = %d (十六进制: 0x%X)", sum, sum))
end
return sum
end
--
local function calCrc(hexStr)
-- 解析hexStr转换为十六进制字符数组
local byteArray = HexOutput(hexStr)
-- 计算 CRC
local crc = calculateXor(byteArray)
log.info("CRCxor:",crc)
-- 返回 CRC 值
return crc
end
--将时间转换为BCD格式
function timeToBCD()
local t = os.date("*t")
-- 转换为BCD格式
local year = string.format("%02d", t.year % 100)
local month = string.format("%02d", t.month)
local day = string.format("%02d", t.day)
local hour = string.format("%02d", t.hour)
local min = string.format("%02d", t.min)
local sec = string.format("%02d", t.sec)
-- 组合BCD格式字符串
local bcdTime = year .. month .. day .. hour .. min .. sec
return bcdTime
end
--构建通用应答
function cmnRsp(svrSeq, svrId, result)
return string.pack('>HHb', svrSeq, svrId, result)
-- >表示使用大端字节序;
-- HH 表示两个 16 位无符号整数(svrSeq 和 svrId);
-- b 表示一个 8 位有符号整数(result)
end
--构建设备注册
function register(ProvinceId,CityId,ManufactureId,TerminalModule,TerminalId,CarColor,CarId)
local termMd = TerminalModule..string.rep(string.char(0), 16 - (TerminalModule):len())..string.rep(string.char(0), 4)
--log.info("HexDataByteLength:",#termMd)
--log.info("HexData is: ",termMd)
return string.pack('>HHc5c20c7Bc11',ProvinceId,CityId,ManufactureId,termMd,TerminalId:fromHex(),CarColor,CarId)
end
--构建位置信息汇报
function locRpt(alarm, status, lat, lng, alt, spd, course, tm, extInfo)
-- 使用 '>iiiiHHH' 格式打包数据
return string.pack('>iiiiHHH', alarm, status, lat, lng, alt, spd, course)..tm:fromHex().. extInfo
end
function HexOutput(data)
log.info("HexDataByteLength:",#data)
local hex = ""
for i = 1, #data do
hex = hex.. string.format("%02x", string.byte(data, i))
end
log.info("HexData is: ",hex)
return hex
end
--封装一个完整的JT808终端注册数据帧
function encodeReg(phoneNo,tSendSeq)
--消息体
local msgBody = register(12,123,'10001','GT808','00000000000002',0,'41048063212')
--消息头
local msgHead =string.pack('>HH',T_REGISTER,msgBody:len())..encodeBcdNum(phoneNo,12)..tSendSeq
local curSeq = tSendSeq
tSendSeq = (tSendSeq == 0xFFFF) and 0 or (tSendSeq + 1)
--校验码
HexOutput(msgHead .. msgBody)
local frame = msgHead .. msgBody
log.info("encodeReg Frame length is: ",#frame)
local crc = calCrc(frame)
--转义
local s = msgHead .. msgBody .. string.char(crc)
s = s:gsub('\125', '\125\1') -- 7D -> 7D 01
s = s:gsub('\126', '\125\2') -- 7E -> 7D 02
return string.char(0x7E) .. s .. string.char(0x7E), curSeq
end
function decodeCmnRsp(s)
log.info("hereNow.",s)
--local start, tail, msg = s:find('^(7E[^7E]+7E)$')
--local decPacket, msgAttr = {}
-- 检查是否以 7E 开头和结尾
if not s:match("^7E") or not s:match("7E$") then
log.warn("prot.decode", "packet does not start or end with 7E")
return nil
end
-- 匹配以 7E 开头和结尾的数据包
local start, tail, msg = s:find('^(7E.+7E)$') -- 改为允许中间部分包含 7E
log.info("start:", start)
log.info("tail:", tail)
log.info("msg:", msg)
if not msg then
-- 如果未匹配到
log.warn('prot.decode', 'wait packet complete')
return nil
end
--反转义
msg = msg:gsub('\125\2', '\126') -- 7D 02 -> 7E
msg = msg:gsub('\125\1', '\125') -- 7D 01 -> 7D
log.info("msg:", msg,msg:len())
if msg:len() < 13 then
log.error('prot.decode', 'packet len is too short')
return s:sub(tail + 1, -1), nil
end
local hexArray = stringToBytes(msg)
local dataHexStr = msg:sub(3, -5)
log.info("消息体和其字节长度:", dataHexStr,dataHexStr:len())
local crcVal = calculateXor(dataHexStr)
print("XOR校验值:", crcVal)
if crcVal ~= hexArray[#hexArray-1] then
log.error('prot.decode', 'crc value error!')
return s:sub(tail + 1, -1), nil
else
log.info("XOR:校验通过")
end
----------------------------解析消息id
msgdata = msg:sub(3, 6)
-- 转换为二进制数据
local binaryData = hexToBinary(msgdata)
-- 解析二进制数据
msgId = string.unpack(">H", binaryData)
-- 输出结果
log.info("消息id十六进制:", string.format("0x%04X", msgId))
----------------------------解析应答结果
msgdata = msg:sub(7, 8)
-- 转换为二进制数据
local binaryData = hexToBinary(msgdata)
-- 解析二进制数据
result = string.unpack(">B", binaryData)
-- 输出结果
log.info("结果十六进制:", string.format("0x%02X", result))
----------------------------解析鉴权码
msgdata = msg:sub(9, 10)
-- 转换为二进制数据
local binaryData = hexToBinary(msgdata)
-- 解析二进制数据
result = string.unpack(">B", binaryData)
-- 输出结果
log.info("鉴权码十六进制:", string.format("0x%02X", result))
----------------------------解析电话号码
msgdata = msg:sub(11, 22)
-- 转换为二进制数据
local binaryData = hexToBinary(msgdata)
-- 解析二进制数据
local b1, b2, b3, b4, b5, b6 = string.unpack(">BBBBBB", binaryData)
-- 格式化输出为 6 字节的十六进制字符串
local TerminalPhoneNo = string.format("0x%02X%02X%02X%02X%02X%02X", b1, b2, b3, b4, b5, b6)
-- 输出电话号码
log.info("电话号码十六进制:", TerminalPhoneNo)
----------------------------解析标头流水号
msgdata = msg:sub(23, 26)
-- 转换为二进制数据
local binaryData = hexToBinary(msgdata)
-- 解析二进制数据
local ManualMsgNum = string.unpack(">H", binaryData)
-- 输出结果
log.info("标头流水号十六进制:", string.format("0x%04X", ManualMsgNum))
----------------------------解析标尾流水号
msgdata = msg:sub(23, 26)
-- 转换为二进制数据
local binaryData = hexToBinary(msgdata)
-- 解析二进制数据
local MsgNum = string.unpack(">H", binaryData)
-- 输出结果
log.info("标尾流水号十六进制:", string.format("0x%04X", MsgNum))
----------------------------解析鉴权码
msgdata = msg:sub(33, 50)
-- 转换为二进制数据
local binaryData = hexToBinary(msgdata)
local b1, b2, b3, b4, b5, b6, b7, b8, b9 = string.unpack(">BBBBBBBBB", binaryData)
-- 格式化输出为 6 字节的十六进制字符串
local JianquanCode = string.format("0x%02X%02X%02X%02X%02X%02X%02X%02X%02X", b1, b2, b3, b4, b5, b6, b7, b8, b9)
-- 输出结果
log.info("鉴权码十六进制:", JianquanCode)
end
--新建任务,每休眠2000ms继续一次
sys.taskInit(function()
--实验1:构建立通用应答数据帧,协议可参考JT808协议8.1与8.2
--输入参数:
--应答流水号为123,
--应答 ID为456,
--结果为1,
local data = cmnRsp(123, 456, 1)
HexOutput(data) --HexDataByteLength:5,HexData is:007b01c801 007b为123,01c8为456,1为1
--实验2:构建终端注册数据帧,协议可参考JT808协议8.5
--输入参数:
--12, --省域 ID WORD
--123, --市县域 ID WORD
--'10001', --制造商 ID BYTE[5]
--'GT808' --终端型号 BYTE[20]
--'00000000000002', --终端 ID BYTE[7]
--0, --车牌颜色 BYTE
--'41048063212') --车辆标识 STRING VIN或车牌号均为固定长度,这里假设字符串长度为11
local data = register(12,123,'10001','GT808','00000000000002',0,'41048063212')
HexOutput(data)--[HexDataByteLength:] 48,[HexData is: ]
--输出解析:
--000c,对应12, --省域 ID WORD
--007b,对应123, --市县域 ID WORD
--3130303031,对应'10001', --制造商 ID BYTE[5]
--4754383038,对应'GT808' --终端型号 BYTE[20],不足字节补0
--0000000000
--0000000000
--0000000000
--00000000000002 对应'00000000000002', --终端 ID BYTE[7]
--000, --车牌颜色 BYTE
--3431303438303633323132,对应'41048063212') --车辆标识 STRING
--实验3:构建位置信息汇报数据帧,协议可参考JT808协议8.18
--输入参数:
--0, 报警标志 DWORD
--1, 状态位 DWORD
--12345678, 纬度 DWORD
--87654321, 经度 DWORD
--100, 高程 WORD
--60, 速度 WORD
--180, 方向 WORD
--os.time(), 时间 BCD[6] YY-MM-DD-hh-mm-ss(GMT+8 时间,本标准中之后涉及的时间均采用此时区)
--"extra"
local time = timeToBCD();
log.info("CurrentTime: ",time)
local data = locRpt(0, 1, 12345678, 87654321, 100, 60, 180, time, "extra")
HexOutput(data)--[HexDataByteLength:] 33,[HexData is: ] 000000000000000100bc614e05397fb10064003c00b42411241232046578747261
--输出解析:
--00000000,对应 0, 报警标志 DWORD,4字节
--00000001,对应 1, 状态位 DWORD
--00bc614e,对应 12345678, 纬度 DWORD
--05397fb1, 对应 87654321, 经度 DWORD
--0064,对应 100, 高程 WORD
--003c,对应60, 速度 WORD
--00b4,对应180, 方向 WORD
--241124123204,对应时间 BCD[6] 24-11-24-12-32-04
--6578747261,对应"extra"
--实验4:构建一个完整的JT808注册数据帧
--输入参数:
--'018068821447',手机号不足 12位,则在前补充数字,大陆手机号补充数字 0
--'101',消息流水号
local data = encodeReg('018068821447','101')
HexOutput(data) --[HexDataByteLength:] 64
--[HexData is: ] 7e01000030018068821447313031000c007b3130303031475438303800000000000000000000000000000000000000000002003431303438303633323132627e
--输出解析:
--7e,标识位固定为0x7e
--0100,消息 ID
--0030,消息体属性
--018068821447,手机号
--313031,消息流水号
--000c007b3130303031475438303800000000000000000000000000000000000000000002003431303438303633323132,注册消息体
--62,校验
--7e,标识位固定为0x7e
--实验5:解析JT808终端注册应答数据帧
local hexStr = '7E8100000C0404571031660030003000736875616E67776569E07E'
decodeCmnRsp(hexStr)
end)
-- 这里演示4G模块上网后,会自动点亮网络灯,方便用户判断模块是否正常开机
sys.taskInit(function()
while true do
sys.wait(6000)
if mobile.status() == 1 then
gpio.set(27, 1)
else
gpio.set(27, 0)
mobile.reset()
end
end
end)
-- 用户代码已结束---------------------------------------------
-- 运行lua task,只能调用一次,而且必须写在末尾
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!
七、功能验证
7.1 开机
按图 1 所示通过 TYPE-C 线将开发板与电脑连接无误后,开发板电源指示红灯常亮,网络指示灯灭,如下图:
此时按下开机键,约 2 秒后释放,等待几秒网络指示绿灯常亮,即开机成功,如下图:
此时电脑设备管理器中会发现下图所示几个设备,即代表开机成功!
7.2 打开 Luatool 软件工具并进入项目管理测试页面
7.3 按序号步骤创建项目
7.4 按如下步骤进行程序烧录
注:如果出现下图警告,请点“确认”(首次使用该软件一定要升级到最新版本),如无,则忽略!
7.5 观察下载过程后确认烧录结果
7.6 关闭项目管理界面,回到调试页面,观察日志输出
7.6.1 实验一:构建立通用应答数据帧
--实验1:构建立通用应答数据帧,协议可参考JT808协议8.1与8.2
--输入参数:
--应答流水号为123,
--应答 ID为456,
--结果为1,
local data = cmnRsp(123, 456, 1)
HexOutput(data) --HexDataByteLength:5,HexData is:007b01c801 007b为123,01c8为456,1为1
日志输出:
[2024-11-25 14:52:05.334][000000000.358] I/user.HexDataByteLength: 5
[2024-11-25 14:52:05.335][000000000.359] I/user.HexData is: 007b01c801
7.6.2 实验二:构建终端注册数据帧
--实验2:构建终端注册数据帧,协议可参考JT808协议8.5
--输入参数:
--12, --省域 ID WORD
--123, --市县域 ID WORD
--'10001', --制造商 ID BYTE[5]
--'GT808' --终端型号 BYTE[20]
--'00000000000002', --终端 ID BYTE[7]
--0, --车牌颜色 BYTE
--'41048063212') --车辆标识 STRING VIN或车牌号均为固定长度,这里假设字符串长度为11
local data = register(12,123,'10001','GT808','00000000000002',0,'41048063212')
HexOutput(data)--[HexDataByteLength:] 48,[HexData is: ]
--输出解析:
--000c,对应12, --省域 ID WORD
--007b,对应123, --市县域 ID WORD
--3130303031,对应'10001', --制造商 ID BYTE[5]
--4754383038,对应'GT808' --终端型号 BYTE[20],不足字节补0
--0000000000 --0000000000
--0000000000
--00000000000002 对应'00000000000002', --终端 ID BYTE[7]
--000, --车牌颜色 BYTE
--3431303438303633323132,对应'41048063212') --车辆标识 STRING
日志输出
[2024-11-25 14:52:05.336][000000000.360] I/user.HexDataByteLength: 48
[2024-11-25 14:52:05.337][000000000.367] I/user.HexData is: 000c007b3130303031475438303800000000000000000000000000000000000000000002003431303438303633323132
7.6.3 实验三:构建位置信息汇报数据帧
--实验3:构建位置信息汇报数据帧,协议可参考JT808协议8.18
--输入参数:
--0, 报警标志 DWORD
--1, 状态位 DWORD
--12345678, 纬度 DWORD
--87654321, 经度 DWORD
--100, 高程 WORD
--60, 速度 WORD
--180, 方向 WORD
--os.time(), 时间 BCD[6] YY-MM-DD-hh-mm-ss(GMT+8 时间,本标准中之后涉及的时间均采用此时区)
--"extra"
local time = timeToBCD();
log.info("CurrentTime: ",time)
local data = locRpt(0, 1, 12345678, 87654321, 100, 60, 180, time, "extra")
HexOutput(data)--[HexDataByteLength:] 33,[HexData is: ] 000000000000000100bc614e05397fb10064003c00b42411241232046578747261
--输出解析:
--00000000,对应 0, 报警标志 DWORD,4字节
--00000001,对应 1, 状态位 DWORD
--00bc614e,对应 12345678, 纬度 DWORD
--05397fb1, 对应 87654321, 经度 DWORD
--0064,对应 100, 高程 WORD
--003c,对应60, 速度 WORD
--00b4,对应180, 方向 WORD
--241124123204,对应时间 BCD[6] 24-11-24-12-32-04
--6578747261,对应"extra"
日志输出
[2024-11-25 14:52:05.340][000000000.371] I/user.HexDataByteLength: 33
[2024-11-25 14:52:05.341][000000000.387] I/user.HexData is: 000000000000000100bc614e05397fb10064003c00b40001010000006578747261
7.6.4 实验四:构建一个完整的 JT808 注册数据帧
--实验4:构建一个完整的JT808注册数据帧
--输入参数:
--'018068821447',手机号不足 12位,则在前补充数字,大陆手机号补充数字 0
--'101',消息流水号
local data = encodeReg('018068821447','101')
HexOutput(data) --[HexDataByteLength:] 64
--[HexData is: ] 7e01000030018068821447313031000c007b3130303031475438303800000000000000000000000000000000000000000002003431303438303633323132627e
--输出解析:
--7e,标识位固定为0x7e
--0100,消息 ID
--0030,消息体属性
--018068821447,手机号
--313031,消息流水号
--000c007b3130303031475438303800000000000000000000000000000000000000000002003431303438303633323132,注册消息体
--62,校验
--7e,标识位固定为0x7e
日志输出
[2024-11-25 14:52:05.356][000000000.425] I/user.HexDataByteLength: 64
[2024-11-25 14:52:05.357][000000000.438] I/user.HexData is: 7e01000030018068821447313031000c007b3130303031475438303800000000000000000000000000000000000000000002003431303438303633323132627e
7.6.5 实验五:解析一个完整 JT808 终端注册应答数据帧
--实验5:解析JT808终端注册应答数据帧
local hexStr = '7E8100000C0404571031660030003000736875616E67776569E07E'
decodeCmnRsp(hexStr)
日志输出
[2024-11-25 14:52:05.366][000000000.461] XOR校验值: 224
[2024-11-25 14:52:05.383][000000000.462] I/user.XOR:校验通过
[2024-11-25 14:52:05.384][000000000.465] I/user.消息id十六进制: 0x8100
[2024-11-25 14:52:05.385][000000000.467] I/user.结果十六进制: 0x00
[2024-11-25 14:52:05.386][000000000.469] I/user.鉴权码十六进制: 0x0C
[2024-11-25 14:52:05.388][000000000.472] I/user.电话号码十六进制: 0x040457103166
[2024-11-25 14:52:05.389][000000000.476] I/user.标头流水号十六进制: 0x0030
[2024-11-25 14:52:05.390][000000000.478] I/user.标尾流水号十六进制: 0x0030
[2024-11-25 14:52:05.391][000000000.483] I/user.鉴权码十六进制: 0x736875616E67776569
7.6.6 完整日志截图
总结
至此,我们已使用 Air780EP 开发板使用数据格式转换函数实现对 JT808 协议常用数据包的组建与解析。
给读者的话
本篇文章由
肇朔
开发;本篇文章描述的内容,如果有错误、细节缺失、细节不清晰或者其他任何问题,总之就是无法解决您遇到的问题;
请登录合宙技术交流论坛,点击文档找错赢奖金-Air780EP-LuatOS-软件指南-通用数据库-JT808封包解包实例;
用截图标注+文字描述的方式跟帖回复,记录清楚您发现的问题;
我们会迅速核实并且修改文档;
同时也会为您累计找错积分,您还可能赢取月度找错奖金!