diff --git a/README.md b/README.md index e330074..12a360d 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,192 @@ -# JT809协议开发 +# JT809协议 ## 瞎逼逼: -  现在有了[JT808](https://github.com/SmallChi/GPSPlatform/blob/master/JT808.md)的基础,对JT809就只剩搬砖了。 +> 该JT809协议是参考[MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp)一款二进制序列化器,借鉴其思想,不得不说站在巨人的肩膀上搬砖就是爽歪歪。 -> 该JT809协议是参考[MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp)一款二进制序列化器,站在巨人的肩膀上搬砖就是爽歪歪。 +> 在github上面搜索竟然没有针对.NET开源的809协议库,难度做GPS行业的.NET很少人吗?可能是藏着,掖着<( ̄3 ̄)> <( ̄3 ̄)> <( ̄3 ̄)> 。 -> 这GB的文档不得不说,太坑了。。。 +> 不得不说这GB的文档,太坑了。。。 + +> 现在有了[JT808](https://github.com/SmallChi/GPSPlatform/blob/master/JT808.md)的基础,对JT809就只剩搬砖了。 + +## 前提条件 + +1. 掌握进制转换:二进制转十六进制; +2. 掌握什么叫BCD编码、Hex编码; +3. 掌握各种位移、异或; +4. 掌握常用反射; +5. 掌握快速ctrl+c、ctrl+v; +6. 掌握以上装逼技能,就可以开始搬砖了。 + +## JT809数据结构解析 + +### 数据包[JT809Package] +|头标识|数据头|数据体|CRC校验码|尾标识 +|:------:|:------:|:------:|:------:|:------:| +| BeginFlag | JT809Header | JT809Bodies | CRCCode | EndFlag | +| 5B | - | - | - | 5D | + +### 数据头[JT809Header] + +|数据长度|报文序列号|业务数据类型|下级平台接入码|协议版本号标识|报文加密标识位|数据加密的密匙| +|:------:|:------:|:------:|:------:|:------:|:------:|:------:| +| MsgLength | MsgSN | MsgID | MsgGNSSCENTERID | Version | EndFlag |EncryptFlag | EncryptKey | + +### 数据体[JT809Bodies] + +> 根据对应业务数据类型:MsgID + +|车牌号|车辆颜色|子业务类型标识|后续数据长度|子业务数据体 +|:------:|:------:|:------:|:------:|:------:| +| VehicleNo | VehicleColor | SubBusinessType | DataLength | JT809SubBodies | + +### 子数据体[JT809SubBodies] + +> 根据对应子业务数据类型 SubBusinessType 处理子业务数据体(JT809SubBodies)。 + +***注意:数据内容(除去头和尾标识)进行转义判断*** + +转义规则如下: +1. 若数据内容中有出现字符 0x5b 的,需替换为字符 0x5a 紧跟字符 0x01; +2. 若数据内容中有出现字符 0x5a 的,需替换为字符 0x5a 紧跟字符 0x02; +3. 若数据内容中有出现字符 0x5d 的,需替换为字符 0x5e 紧跟字符 0x01; +4. 若数据内容中有出现字符 0x5e 的,需替换为字符 0x5e 紧跟字符 0x02. + +反转义的原因:确认JT809协议的TCP消息边界。 + +### 举个栗子 + +1. 组包: +> 业务数据类型 MsgID:从链路报警信息交互消息 +> 子业务类型标识 SubBusinessType:报警督办请求消息 + +``` +JT809Package jT809Package = new JT809Package(); + +jT809Package.Header = new JT809Header +{ + MsgSN = 1666, + EncryptKey = 9999, + EncryptFlag= JT809Header_Encrypt.None, + Version = new JT809Header_Version(1, 0, 0), + MsgID = JT809Enums.JT809BusinessType.DOWN_WARN_MSG, + MsgGNSSCENTERID = 20180920, +}; + +jT809Package.Bodies = new JT809_0x9400 +{ + VehicleNo="粤A12345", + VehicleColor= JT809Enums.JT809VehicleColorType.黄色, + SubBusinessType= JT809Enums.JT809SubBusinessType.DOWN_WARN_MSG_URGE_TODO_REQ, +}; + +JT809_0x9400_0x9401 jT809_0x9400_0x9401 = new JT809_0x9400_0x9401 +{ + WarnSrc = JT809WarnSrc.车载终端, + WarnType = JT809WarnType.疲劳驾驶报警, + WarnTime = DateTime.Parse("2018-09-27 10:24:00"), + SupervisionID = "123FFAA1", + SupervisionEndTime = DateTime.Parse("2018-09-27 11:24:00"), + SupervisionLevel = 3, + Supervisor = "smallchi", + SupervisorTel = "12345678901", + SupervisorEmail = "123456@qq.com" +}; + +jT809Package.Bodies.JT809SubBodies = jT809_0x9400_0x9401; + +byte[] data = JT809Serializer.Serialize(jT809Package); + +string hex = data.ToHexString(); + +// 输出结果Hex: +// 5B 00 00 00 92 00 00 06 82 94 00 01 33 EF B8 01 00 00 00 00 00 27 0F D4 C1 41 31 32 33 34 35 00 00 00 00 00 00 00 00 00 00 00 00 00 02 94 01 00 00 00 5C 01 00 02 00 00 00 00 5A 01 AC 3F 40 12 3F FA A1 00 00 00 00 5A 01 AC 4D 50 03 73 6D 61 6C 6C 63 68 69 00 00 00 00 00 00 00 00 31 32 33 34 35 36 37 38 39 30 31 00 00 00 00 00 00 00 00 00 31 32 33 34 35 36 40 71 71 2E 63 6F 6D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BA D8 5D +``` + +2. 手动解包: +``` +1.原包: +5B 00 00 00 92 00 00 06 82 94 00 01 33 EF B8 01 00 00 00 00 00 27 0F D4 C1 41 31 32 33 34 35 00 00 00 00 00 00 00 00 00 00 00 00 00 02 94 01 00 00 00 5C 01 00 02 00 00 00 00 (5A 01) AC 3F 40 12 3F FA A1 00 00 00 00 (5A 01) AC 4D 50 03 73 6D 61 6C 6C 63 68 69 00 00 00 00 00 00 00 00 31 32 33 34 35 36 37 38 39 30 31 00 00 00 00 00 00 00 00 00 31 32 33 34 35 36 40 71 71 2E 63 6F 6D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BA D8 5D + +2.进行反转义 +5A 01 ->5B +5A 02 ->5A +5E 01 ->5D +5E 02 ->5E +反转义后 +5B 00 00 00 92 00 00 06 82 94 00 01 33 EF B8 01 00 00 00 00 00 27 0F D4 C1 41 31 32 33 34 35 00 00 00 00 00 00 00 00 00 00 00 00 00 02 94 01 00 00 00 5C 01 00 02 00 00 00 00 5B AC 3F 40 12 3F FA A1 00 00 00 00 5B AC 4D 50 03 73 6D 61 6C 6C 63 68 69 00 00 00 00 00 00 00 00 31 32 33 34 35 36 37 38 39 30 31 00 00 00 00 00 00 00 00 00 31 32 33 34 35 36 40 71 71 2E 63 6F 6D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BA D8 5D + +3.拆解 +5B --头标识 +00 00 00 92 --数据头->数据长度 +00 00 06 82 --数据头->报文序列号 +94 00 --数据头->业务数据类型 +01 33 EF B8 --数据头->下级平台接入码,上级平台给下级平台分配唯一标识码 +01 00 00 --数据头->协议版本号标识 +00 --数据头->报文加密标识位 +00 00 27 0F --数据头->数据加密的密匙 +D4 C1 41 31 32 33 34 35 00 00 00 00 00 00 00 00 00 00 00 00 00 --数据体->车牌号 +02 --数据体->车辆颜色 +94 01 --数据体->子业务类型标识 +00 00 00 5C --数据体->后续数据长度 +01 --子数据体->报警信息来源 +00 02 --子数据体->报警类型 +00 00 00 00 5B AC 3F 40 --子数据体->报警时间UTCDateTime +12 3F FA A1 --子数据体->报警督办ID +00 00 00 00 5B AC 4D 50 --子数据体->督办截止时间 +03 --子数据体->督办级别 +73 6D 61 6C 6C 63 68 69 00 00 00 00 00 00 00 00 --子数据体->督办人 +31 32 33 34 35 36 37 38 39 30 31 00 00 00 00 00 00 00 00 00 --子数据体->督办联系电话 +31 32 33 34 35 36 40 71 71 2E 63 6F 6D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 --子数据体->督办联系电子邮件 +BA D8 --CRC校验码 +5D --尾标识 +``` + +3. 程序解包: +``` +//1.转成byte数组 +var bytes = "5B 00 00 00 92 00 00 06 82 94 00 01 33 EF B8 01 00 00 00 00 00 27 0F D4 C1 41 31 32 33 34 35 00 00 00 00 00 00 00 00 00 00 00 00 00 02 94 01 00 00 00 5C 01 00 02 00 00 00 00 5A 01 AC 3F 40 12 3F FA A1 00 00 00 00 5A 01 AC 4D 50 03 73 6D 61 6C 6C 63 68 69 00 00 00 00 00 00 00 00 31 32 33 34 35 36 37 38 39 30 31 00 00 00 00 00 00 00 00 00 31 32 33 34 35 36 40 71 71 2E 63 6F 6D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BA D8 5D".ToHexBytes(); + +//2.将数组反序列化 +JT809Package jT809Package = JT809Serializer.Deserialize(bytes); + +//3.数据包头 +Assert.Equal((uint)146, jT809Package.Header.MsgLength); +Assert.Equal((uint)1666, jT809Package.Header.MsgSN); +Assert.Equal((uint)9999, jT809Package.Header.EncryptKey); +Assert.Equal(JT809Header_Encrypt.None, jT809Package.Header.EncryptFlag); +Assert.Equal((uint)20180920, jT809Package.Header.MsgGNSSCENTERID); +Assert.Equal(JT809Enums.JT809BusinessType.DOWN_WARN_MSG, jT809Package.Header.MsgID); +Assert.Equal(new JT809Header_Version(1, 0, 0).ToString(), jT809Package.Header.Version.ToString()); + +//4.数据包体 +JT809_0x9400 jT809_0X400 = (JT809_0x9400)jT809Package.Bodies; +Assert.Equal("粤A12345", jT809_0X400.VehicleNo); +Assert.Equal(JT809Enums.JT809VehicleColorType.黄色, jT809_0X400.VehicleColor); +Assert.Equal(JT809Enums.JT809SubBusinessType.DOWN_WARN_MSG_URGE_TODO_REQ, jT809_0X400.SubBusinessType); +Assert.Equal((uint)92, jT809_0X400.DataLength); + +//5.子数据包体 +JT809_0x9400_0x9401 jT809_0x9400_0x9401 = (JT809_0x9400_0x9401)jT809_0X400.JT809SubBodies; +Assert.Equal(JT809WarnSrc.车载终端, jT809_0x9400_0x9401.WarnSrc); +Assert.Equal(JT809WarnType.疲劳驾驶报警, jT809_0x9400_0x9401.WarnType); +Assert.Equal(DateTime.Parse("2018-09-27 10:24:00"), jT809_0x9400_0x9401.WarnTime); +Assert.Equal("123FFAA1", jT809_0x9400_0x9401.SupervisionID); +Assert.Equal(DateTime.Parse("2018-09-27 11:24:00"), jT809_0x9400_0x9401.SupervisionEndTime); +Assert.Equal(3, jT809_0x9400_0x9401.SupervisionLevel); +Assert.Equal("smallchi", jT809_0x9400_0x9401.Supervisor); +Assert.Equal("12345678901", jT809_0x9400_0x9401.SupervisorTel); +Assert.Equal("123456@qq.com", jT809_0x9400_0x9401.SupervisorEmail); + +``` ## JT809协议消息对照表 ### 链路管理类 +#### 主链路 + |序号|消息ID|完成情况|消息体名称| |:------:|:------:|:------:|:------:| | 1 | 0x1001 | √ | 主链路登录请求消息 | @@ -22,14 +197,19 @@ | 6 | 0x1006 | √ | 主链路连接保持应答消息 | | 7 | 0x1007 | √ | 主链路断开通知消息 | | 8 | 0x1008 | √ | 下级平台主动关闭链路通知消息 | -| 9 | 0x9001 | √ | 从链路连接请求消息 | -| 10 | 0x9002 | √ | 从链路连接应答消息 | -| 11 | 0x9003 | √ | 从链路注销请求消息 | -| 12 | 0x9004 | √ | 从链路注销应答消息 | -| 13 | 0x9005 | √ | 从链路连接保持请求消息 | -| 14 | 0x9006 | √ | 从链路连接保持应答消息 | -| 15 | 0x9007 | √ | 从链路断开通知消息 | -| 16 | 0x9008 | √ | 上级平台主动关闭链路通知消息 | + +#### 从链路 + +|序号|消息ID|完成情况|消息体名称| +|:------:|:------:|:------:|:------:| +| 1 | 0x9001 | √ | 从链路连接请求消息 | +| 2 | 0x9002 | √ | 从链路连接应答消息 | +| 3 | 0x9003 | √ | 从链路注销请求消息 | +| 4 | 0x9004 | √ | 从链路注销应答消息 | +| 5 | 0x9005 | √ | 从链路连接保持请求消息 | +| 6 | 0x9006 | √ | 从链路连接保持应答消息 | +| 7 | 0x9007 | √ | 从链路断开通知消息 | +| 8 | 0x9008 | √ | 上级平台主动关闭链路通知消息 | ### 信息统计类 diff --git a/src/JT809.Protocol/JT809Header.cs b/src/JT809.Protocol/JT809Header.cs index 76e4c7c..41d42cf 100644 --- a/src/JT809.Protocol/JT809Header.cs +++ b/src/JT809.Protocol/JT809Header.cs @@ -35,7 +35,7 @@ namespace JT809.Protocol /// public uint MsgGNSSCENTERID { get; set; } /// - /// 协议版本好标识,上下级平台之间采用的标准协议版 + /// 协议版本号标识,上下级平台之间采用的标准协议版 /// 编号;长度为 3 个字节来表示,0x01 0x02 0x0F 标识 /// 的版本号是 v1.2.15,以此类推。 ///