JT809
JT809协议、GB809协议、道路运输车辆卫星定位系统-平台数据交换协议(支持2011、2019版本)
Install / Use
/learn @SmallChi/JT809README
JT809协议
前提条件
- 掌握进制转换:二进制转十六进制;
- 掌握BCD编码、Hex编码;
- 掌握各种位移、异或;
- 掌握常用反射;
- 掌握JObject的用法;
- 掌握快速ctrl+c、ctrl+v;
- 掌握Span<T>的基本用法;
- 掌握以上装逼技能,就可以开始搬砖了。
JT809数据结构解析
数据包[JT809Package]
|头标识|数据头|数据体|CRC校验码|尾标识 |:------:|:------:|:------:|:------:|:------:| | BeginFlag | JT809Header | JT809Bodies | CRCCode | EndFlag | | 5B | - | - | - | 5D |
数据头[JT809Header]
|数据长度|报文序列号|业务数据类型|下级平台接入码|协议版本号标识|报文加密标识位|数据加密的密匙|发送消息的系统时间(2019版本)| |:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:| | MsgLength | MsgSN | BusinessType | MsgGNSSCENTERID | Version |EncryptFlag | EncryptKey |Time|
数据体[JT809Bodies]
根据对应业务数据类型:BusinessType
|车牌号|车辆颜色|子业务类型标识|后续数据长度|子业务数据体 |:------:|:------:|:------:|:------:|:------:| | VehicleNo | VehicleColor | SubBusinessType | DataLength | JT809SubBodies |
子数据体[JT809SubBodies]
根据对应子业务数据类型 SubBusinessType 处理子业务数据体(JT809SubBodies)。
注意:数据内容(除去头和尾标识)进行转义判断
转义规则如下:
- 若数据内容中有出现字符 0x5b 的,需替换为字符 0x5a 紧跟字符 0x01;
- 若数据内容中有出现字符 0x5a 的,需替换为字符 0x5a 紧跟字符 0x02;
- 若数据内容中有出现字符 0x5d 的,需替换为字符 0x5e 紧跟字符 0x01;
- 若数据内容中有出现字符 0x5e 的,需替换为字符 0x5e 紧跟字符 0x02.
反转义的原因:确认JT809协议的TCP消息边界。
举个栗子1
1.组包:
业务数据类型 BusinessType:从链路报警信息交互消息
子业务类型标识 SubBusinessType:报警督办请求消息
JT809Package jT809Package = new JT809Package();
jT809Package.Header = new JT809Header
{
MsgSN = 1666,
EncryptKey = 9999,
EncryptFlag= JT809Header_Encrypt.None,
Version = new JT809Header_Version(1, 0, 0),
BusinessType = JT809BusinessType.从链路报警信息交互消息.ToUInt16Value(),
MsgGNSSCENTERID = 20180920,
};
JT809_0x9400 bodies = new JT809_0x9400
{
VehicleNo="粤A12345",
VehicleColor= JT809VehicleColorType.黄色,
SubBusinessType= JT809SubBusinessType.报警督办请求消息.ToUInt16Value(),
};
JT809_0x9400_0x9401 jT809_0x9400_0x9401 = new JT809_0x9400_0x9401
{
WarnSrc = JT809WarnSrc.车载终端,
WarnType = JT809WarnType.疲劳驾驶报警.ToUInt16Value(),
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"
};
bodies.SubBodies = jT809_0x9400_0x9401;
jT809Package.Bodies = bodies;
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(JT809BusinessType.从链路报警信息交互消息, (JT809BusinessType)jT809Package.Header.BusinessType);
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(JT809VehicleColorType.黄色, jT809_0X400.VehicleColor);
Assert.Equal(JT809SubBusinessType.报警督办请求消息, (JT809SubBusinessType)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.疲劳驾驶报警, (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);
举个栗子2
// 根据业务类型创建对应包
JT809Package jT809Package = JT809BusinessType.从链路报警信息交互消息.Create_从链路报警信息交互消息(
new JT809Header
{
MsgSN = 1666,
EncryptKey = 9999,
EncryptFlag = JT809Header_Encrypt.None,
Version = new JT809Header_Version(1, 0, 0),
MsgGNSSCENTERID = 20180920,
}, new JT809_0x9400
{
VehicleNo = "粤A12345",
VehicleColor = JT809VehicleColorType.黄色,
SubBusinessType = JT809SubBusinessType.报警督办请求消息.ToUInt16Value(),
SubBodies = JT809SubBusinessType.报警督办请求消息.Create_报警督办请求消息(
new JT809_0x9400_0x9401
{
WarnSrc = JT809WarnSrc.车载终端,
WarnType = JT809WarnType.疲劳驾驶报警.ToUInt16Value(),
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"
})
}
);
var hex = JT809Serializer.Serialize(jT809Package).ToHexString();
举个栗子3
static void Main(string[] args)
{
class JT809GlobalConfig: GlobalConfigBase
{
public override JT809EncryptOptions EncryptOptions { get; set; }= new JT809EncryptOptions()
{
IA1 = 20000000,
IC1 = 20000000,
M1 = 30000000
};
public override string ConfigId => "JT809GlobalConfig";
}
JT809Serializer JT809Serializer = new JT809Serializer(new JT809GlobalConfig());
// todo:
}
举个栗子4
如何在项目中同时使用809的2011和2019版本
IServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddJT809Configure(new JT809_2011_Config());
serviceDescriptors.AddJT809Configure(new JT809_2019_Config());
JT809Serializer JT809_2011_Serializer= ServiceProvider.GetRequiredService<JT809_2011_Config>().GetSerializer();
JT809Serializer JT809_2019_Serializer = ServiceProvider.GetRequiredService<JT809_2019_Config>().GetSerializer();
public class JT809_2011_Config: JT809GlobalConfigBase
{
public override st
Related Skills
node-connect
334.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
82.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
334.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
82.3kCommit, push, and open a PR
