当前位置: 首页 > news >正文

【JT/T 808协议】808 协议开发笔记 ② ( 终端注册 | 终端注册应答 | 字符编码转换网站 )

文章目录

  • 一、消息头 数据
    • 1、消息头拼接
    • 2、消息 ID 字段
    • 3、消息体属性 字段
    • 4、终端手机号 字段
    • 5、终端流水号 字段
  • 二、消息体 数据
  • 三、校验码计算
  • 四、最终计算结果
  • 五、终端注册应答
    • 1、分解终端应答数据
    • 2、终端应答 消息体 数据
  • 六、字符编码转换网站





一、消息头 数据




1、消息头拼接


808 协议的消息头结构如下 :

+----------+-------------+----------------+--------+------------+----------------+
| 消息ID   | 消息体属性   | 终端手机号      | 流水号 | 总包数     | 包序号         |
| 2字节    | 2字节       | 6字节(BCD)     | 2字节  | 2字节(可选)| 2字节(可选)    |
+----------+-------------+----------------+--------+------------+----------------+

这是生成的 终端注册 消息头数据 :

消息头数据 :

01 00 00 36 01 85 11 88 88 88 00 01

参考 下图进行解析 :

在这里插入图片描述


2、消息 ID 字段


0 ~ 1 字节 是消息 ID , " 01 00 00 36 01 85 11 88 88 88 00 01 "

0x0100 是 终端注册的 消息 ID ;

在这里插入图片描述


3、消息体属性 字段


2 ~ 3 字节 是消息体属性 , " 01 00 00 36 01 85 11 88 88 88 00 01 " , 也就是 00 36 ,

将其拆解成二进制形式 为

0000 0000 0011 0110

参考下面的 位数 进行对应 ,

保留位 是 00 , 分包位 是 0 , 数据加密方式是 000 ,

消息体长度是 00 0011 0110 , 对应的十六进制为 0x36 , 十进制为 54 , 消息体长度 54 字节 ;

在这里插入图片描述


4、终端手机号 字段


4 ~ 9 字节 是 终端手机号 , " 01 00 00 36 01 85 11 88 88 88 00 01 " , 也就是 18511888888 十一位手机号 , 前面加上一个 0 ;

这是 BCD 编码 , 每个字节 高四位 表示一个数字 , 第四位表示一个数字 ;

使用 如下代码 , 可以实现 BCD 编码 到 数字字符串 之间的转换 ;

    /*** 读入数据时通过按位与操作将bcd编码转换成设备编号devId** @param bcd* @return*/public static String bcdToString(byte[] bcd) {// 存储转码后的字符串StringBuilder sb = new StringBuilder();// 循环数组解码 先将每个位上的for (int i = 0; i < bcd.length; i++) {// 转换低字节 十六进制的  0x0f 等于十进制的 15,二进制表示为00001111,直接取到低4位int low = (bcd[i] & 0x0f);// 转换高字节 十六进制的  0xf0 等于十进制的 240,二进制表示为11110000,右移4位的意思是取高4位int high = ((bcd[i] & 0xf0) >> 4);// 如果高字节等于0xf(二进制1111)说明是补的字节,直接抛掉if (high != 0xf) {sb.append(high);}sb.append(low);}// 返回解码字符串return sb.toString();}/*** 写出数据时将我们业务中的devId转换成bcd编码** @param bcd* @return*/public static byte[] strToBcd(String bcd) {// 获取字节数组长度int size = bcd.length() / 2;int remainder = bcd.length() % 2;// 存储BCD码字节byte[] bcdByte = new byte[size + remainder];// 转BCD码for (int i = 0; i < size; i++) {int high = Integer.parseInt(bcd.substring(2 * i, 2 * i + 1));int low = Integer.parseInt(bcd.substring(2 * i + 1, 2 * i + 2));bcdByte[i] = (byte) ((high << 4) | low);}// 如果存在余数,需要填Fif (remainder > 0) {int low = Integer.parseInt(bcd.substring(bcd.length() - 1));bcdByte[bcdByte.length - 1] = (byte) ((0xf << 4) | low);}// 返回BCD码字节数组return bcdByte;}

5、终端流水号 字段


10 ~ 11 字节 是 终端流水号 , " 00 00 00 36 01 85 11 88 88 88 00 01 " ,

终端流水号 , 每次发送数据后 , 自增 1 ;





二、消息体 数据



终端注册 消息体 数据如下 :

0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00    ....BYD..2......
0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0048 - 0063: 00 00 00 00 00 00                                  ......

参考下图进行解析 :

在这里插入图片描述

  • 0 ~ 1 字节 : 是 省域 ID , short 双字节整型 , 下面 蓝色部分是 省域 ID 数据 ;

    0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
    0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0048 - 0063: 00 00 00 00 00 00 …

  • 2 ~ 3 字节 : 市县域 ID , short 整型 , 下面蓝色部分对应数据 ;

    0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
    0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0048 - 0063: 00 00 00 00 00 00

  • 4 ~ 8 字节 : 5 字节数据 , 制造商编码 , 下面蓝色部分是 " BYD " 字符串对应的 ASCII 码 , 后面是 两个 0 ;

    0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
    0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0048 - 0063: 00 00 00 00 00 00

  • 9 ~ 28 字节 : 20 字节的数据 , 终端型号 , 字符 2 对应的 ASCII 码 ; 下面蓝色字体部分 ;

    0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
    0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0048 - 0063: 00 00 00 00 00 00

  • 29 ~ 35 字节 : 7 字节的 二进制数据 , 这里设置的是 0 ;

    0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
    0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0048 - 0063: 00 00 00 00 00 00

  • 36 ~ 36 字节 : 1 字节的 二进制数据 , 颜色代码 ;

    0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
    0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0048 - 0063: 00 00 00 00 00 00

  • 37 ~ 53 字节 : 17 字节的 二进制数据 , VIN 码 , 车架号 , 这里设置默认 0 ;

    0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
    0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
    0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0048 - 0063: 00 00 00 00 00 00





三、校验码计算



终端注册

  • 消息头 :
	0000 - 0015: 01 00 00 36 01 85 11 88 88 88 00 01
  • 消息体 :
	0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00    ....BYD..2......0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................0048 - 0063: 00 00 00 00 00 00                                  ......                                  ....~
  • 校验位 :
	0000 - 0015: E4

将 消息头 + 消息体 两个字节数组 合并后 进行校验 , 使用如下函数 从第一字节开始 进行校验 直到最后一位 ,

    /*** 校验位 校验码指从消息头开始,同后一字节异或,直到校验码前一个字节,占用一个字节。** @return*/public static byte crc(ByteBuf byteBuf) {ByteBuf buf = byteBuf.copy();byte checksum = 0;while (buf.readableBytes() > 0) {checksum ^= buf.readUnsignedByte();}return checksum;}




四、最终计算结果



将上述 消息头 + 消息体 + 校验位 拼装起来 ,

查看 数据中是否有 0x7e 和 0x7d , 进行转义替换 ;

出现 0x7e 的转义处理 : 0x7e <————> 0x7d 后紧跟一个 0x02;
出现 0x7d 的转义处理 : 0x7d <————> 0x7d 后紧跟一个 0x01。


最终的 终端注册数据包为 :

	0000 - 0015: 7E 01 00 00 36 01 85 11 88 88 88 00 01 00 00 00    ~...6.6.........0016 - 0031: 00 42 59 44 00 00 32 00 00 00 00 00 00 00 00 00    .BYD..2.........0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................0048 - 0063: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................0064 - 0079: 00 00 00 E4 7E                                     ....~




五、终端注册应答



返回 终端注册应答 数据 :

	0000 - 0015: 7E 81 00 00 10 01 36 00 10 10 89 00 02 00 01 00    ~.....6.........0016 - 0031: BB CE CE D6 88 E2 47 AC BB 21 30 CE 39 48 7E       ..........089H~

1、分解终端应答数据


前后的 0x7E 是 标识位 ;

倒数第二位 0x48 是 校验位 ;

消息头的结构 :

+----------+-------------+----------------+--------+------------+----------------+
| 消息ID   | 消息体属性   | 终端手机号      | 流水号 | 总包数     | 包序号         |
| 2字节    | 2字节       | 6字节(BCD)     | 2字节  | 2字节(可选)| 2字节(可选)    |
+----------+-------------+----------------+--------+------------+----------------+

消息头提取出来 :

81 00 00 10 01 36 00 10 10 89 00 02

消息体数据提取出来 :

00 01 00 BB CE CE D6 88 E2 47 AC BB 21 30 CE 39 48 7E

参考下图进行解析 ;

在这里插入图片描述


2、终端应答 消息体 数据


消息体数据 :

00 01 00 BB CE CE D6 88 E2 47 AC BB 21 30 CE 39 48 7E

在这里插入图片描述

  • 00 01 是 应答 流水号 ;
  • 00 表示 终端注册 成功 ;
  • BB CE CE D6 88 E2 47 AC BB 21 30 CE 39 是 鉴权码 字符串对应的 二进制数据 ;




六、字符编码转换网站



字符编码转换网站 :

  • GBK 编码转换
  • UTF-8 编码转换
  • URL 编码转换

相关文章:

【JT/T 808协议】808 协议开发笔记 ② ( 终端注册 | 终端注册应答 | 字符编码转换网站 )

文章目录 一、消息头 数据1、消息头拼接2、消息 ID 字段3、消息体属性 字段4、终端手机号 字段5、终端流水号 字段 二、消息体 数据三、校验码计算四、最终计算结果五、终端注册应答1、分解终端应答数据2、终端应答 消息体 数据 六、字符编码转换网站 一、消息头 数据 1、消息头…...

github配置sshkey

使用命令生成sshkey ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 依此会要求输入以下信息&#xff0c;可以使用默认值 设置保存密钥的路径 设置SSH密钥密码&#xff08;备注&#xff1a;空内容表示不设置SSH密钥密码&#xff09; 再次确认SSH密钥密…...

Java数据结构第十二期:走进二叉树的奇妙世界(一)

专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 目录 一、树型结构 1.1. 树的定义 1.2. 树的基本概念 1.3. 树的表示形式 二、二叉树 2.1. 概念 2.2. 两种特殊的二叉树 2.3. 二叉树的性质 2.4. 二叉树的存储 三、二叉树的基本操作 一、树型结构 1.…...

Web的增删改查

准备环境 1. 添加web 点击项目右键——>选择**添加框架**选择**web应用程序** 2.创建lib目录 在web应用程序的**WEB-INF目录下**创建lib目录添加jar包(5个)解压&#xff1a;右键——>选择**添加库** 3.创建Dao层 在src目录下创建包com.zmq在该包下创建dao层添加工具…...

Java 前后端时间格式转换

在 Web 开发里&#xff0c;时间格式处理既常见又关键。由于前端和后端对时间的表示、处理方式存在差异&#xff0c;熟练掌握时间格式的转换方法就显得尤为重要。这篇文章会深入探讨 Java 前后端时间格式转换的相关知识&#xff0c;特别是 Java 时间转换的多种方式&#xff0c;其…...

【用deepseek和chatgpt做算法竞赛】——还得DeepSeek来 -Minimum Cost Trees_5

往期 【用deepseek和chatgpt做算法竞赛】——华为算法精英实战营第十九期-Minimum Cost Trees_0&#xff1a;介绍了题目和背景【用deepseek和chatgpt做算法竞赛】——华为算法精英实战营第十九期-Minimum Cost Trees_1&#xff1a;题目输入的格式说明&#xff0c;选择了邻接表…...

C++ 互斥锁的使用

mutex std::mutex 是C标准库中用于线程同步的互斥锁机制&#xff0c;主要用于保护共享资源&#xff0c;避免多个线程同时访问导致的竞态条件。 它提供了以下功能&#xff1a; 加锁&#xff08;lock&#xff09;&#xff1a;阻塞当前线程&#xff0c;直到获取锁。 解锁&#…...

【Elasticsearch】Retrieve inner hits获取嵌套查询的具体的嵌套文档来源,以及父子文档的来源

Retrieve inner hits 是 Elasticsearch 中的一个功能&#xff0c;用于在嵌套查询或父子查询中&#xff0c;返回导致主文档匹配的具体嵌套对象或子/父文档的详细信息&#xff0c;帮助用户更直观地理解查询结果的来源。 在 Elasticsearch 中&#xff0c;Retrieve inner hits是一…...

C语言中的typedef关键字详解

C语言中的typedef关键字详解 在C语言编程中&#xff0c;typedef 关键字是一个非常实用的特性&#xff0c;它可以帮助我们创建新的类型名&#xff0c;从而简化代码&#xff0c;提高可读性。本文将详细解析typedef的使用方法、场景以及注意事项。 1. typedef简介 typedef 是Ty…...

怎麼利用靜態ISP住宅代理在指紋流覽器中管理社媒帳號?

靜態ISP住宅代理是一種基於真實住宅IP的代理服務。這類代理IP通常由互聯網服務提供商&#xff08;ISP&#xff09;分配&#xff0c;具有非常高的真實性&#xff0c;與普通數據中心代理相比&#xff0c;更不容易被平臺檢測到為“虛假IP”或“代理IP”&#xff0c;靜態ISP住宅代理…...

【多语言生态篇一】【DeepSeek×Java:Spring Boot微服务集成全栈指南 】

(手把手带你从零实现AI能力调用,万字长文预警,建议收藏实操) 一、环境准备:别输在起跑线上 1.1 硬件软件全家桶 JDK版本:必须 ≥17(Spring Boot 3.2+强制要求,低版本直接报错)IDE推荐:IntelliJ IDEA终极版(社区版缺Spring AI插件支持)构建工具:Maven 3.9+ / Grad…...

IOS UITextField 无法隐藏键盘问题

设置UITextField 键盘按钮返回键为“完成”&#xff0c;即return key 设置done .m代码设置代理 //设置代理协议 UITextFieldDelegate&#xff0c; self.mobileTextField.delegate self; ///点击完成键隐藏键盘 - (BOOL)textFieldShouldReturn:(UITextField *)textField{//取…...

einops测试

文章目录 1. einops2. code3. pytorch 1. einops einops 主要是通过爱因斯坦标记法来处理张量矩阵的库&#xff0c;让矩阵处理上非常简单。 conda : conda install conda-forge::einopspython: 2. code import torch import torch.nn as nn import torch.nn.functional as…...

25轻化工程研究生复试面试问题汇总 轻化工程专业知识问题很全! 轻化工程复试全流程攻略 轻化工程考研复试真题汇总

轻化工程复试心里没谱&#xff1f;学姐带你玩转面试准备&#xff01; 是不是总觉得老师会问些刁钻问题&#xff1f;别焦虑&#xff01;其实轻化工程复试套路就那些&#xff0c;看完这篇攻略直接掌握复试通关密码&#xff01;文中有重点面试题可直接背~ 目录 一、这些行为赶紧避…...

小米路由器 AX3000T 降级后无法正常使用,解决办法

问题描述 买了个 AX3000T 路由器&#xff0c;想安装 OpenWRT 或者 安装 Clash 使用&#xff0c;看教程说是需要降级到 v1.0.47 版本。 结果刷机之后路由器无法打开了&#xff0c;一直黄灯亮&#xff0c;中间灭一下&#xff0c;又是黄灯长亮&#xff0c;没有 WIFI 没有连接。以…...

qt5实现表盘的旋转效果,通过提升QLabel类

因为工作需要&#xff0c;需要实现温度的表盘展示效果 实现思路&#xff1a; 通过提示声QLabel控价类&#xff0c;实现报盘的旋转和展示效果 1. 编写一个QLabel的类MyQLabel,实现两个方法 1. void paintEvent(QPaintEvent *event); //重绘函数 2. void valueChanged(int va…...

【HeadFirst系列之HeadFirst设计模式】第7天之命令模式:封装请求,轻松实现解耦!

命令模式&#xff1a;封装请求&#xff0c;轻松实现解耦&#xff01; 大家好&#xff01;今天我们来聊聊设计模式中的命令模式&#xff08;Command Pattern&#xff09;。如果你曾经需要将请求封装成对象&#xff0c;或者希望实现请求的撤销、重做等功能&#xff0c;那么命令模…...

HTTPS(下)

主要讲加密算法RSA&#xff0c;ECDHE TLS的握手涉及四次通信&#xff0c;根据不同的密钥交换算法&#xff0c;TLS 握手流程也会不一样的&#xff0c;现在常用的密钥交换算法有两种&#xff1a;RSA 算法和 ECDHE 算法 正常情况下&#xff0c;需要先TCP三次握手后进行TLS四次握手…...

vue2 和 vue3 中 computer 计算属性的用法

Vue 2 中的 computed 在 Vue 2 中&#xff0c;计算属性是响应式的&#xff0c;并且基于 getter 进行缓存&#xff0c;只有依赖的响应式数据发生变化时才会重新计算。 基本用法 <template><div><p>原始消息&#xff1a;{{ message }}</p><p>反…...

【STM32学习】标准库实现STM32 ADC采集1路、2路、多路

目录 ADC采集 ADC配置步骤 STM32F103C8T6的ADC 输入通道 ​编辑 1路ADC&#xff08;A4 ADC 通道4&#xff09; 1路ADC源码代码链接&#xff1a; 2路ADC&#xff08;A4 ADC 通道4、A5 ADC 通道5&#xff09;基于DMA实现 多路ADC实现采集 ADC采集 ADC配置步骤 使能GPIO…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...