diff --git a/doc/GBT 32960.3-2016 电动汽车远程服务与管理系统技术规范 第3部分:通讯协议及数据格式.pdf b/doc/GBT 32960.3-2016 电动汽车远程服务与管理系统技术规范 第3部分:通讯协议及数据格式.pdf new file mode 100644 index 0000000..cd34858 Binary files /dev/null and b/doc/GBT 32960.3-2016 电动汽车远程服务与管理系统技术规范 第3部分:通讯协议及数据格式.pdf differ diff --git a/doc/GBT32960-2016电动汽车远程服务与管理系统技术规范 第1部分:总则.pdf b/doc/GBT32960-2016电动汽车远程服务与管理系统技术规范 第1部分:总则.pdf deleted file mode 100644 index d3b4384..0000000 Binary files a/doc/GBT32960-2016电动汽车远程服务与管理系统技术规范 第1部分:总则.pdf and /dev/null differ diff --git a/doc/GBT32960-2016电动汽车远程服务与管理系统技术规范 第2部分:车载终端.pdf b/doc/GBT32960-2016电动汽车远程服务与管理系统技术规范 第2部分:车载终端.pdf deleted file mode 100644 index fb07c21..0000000 Binary files a/doc/GBT32960-2016电动汽车远程服务与管理系统技术规范 第2部分:车载终端.pdf and /dev/null differ diff --git a/doc/GBT32960-2016电动汽车远程服务与管理系统技术规范 第3部分:通信协议及数据格式.pdf b/doc/GBT32960-2016电动汽车远程服务与管理系统技术规范 第3部分:通信协议及数据格式.pdf deleted file mode 100644 index 6a20c44..0000000 Binary files a/doc/GBT32960-2016电动汽车远程服务与管理系统技术规范 第3部分:通信协议及数据格式.pdf and /dev/null differ diff --git a/doc/GBT32960.md b/doc/GBT32960.md new file mode 100644 index 0000000..e6f6f13 --- /dev/null +++ b/doc/GBT32960.md @@ -0,0 +1,1483 @@ +# @36node/protocol-32960 文档 + +> 支援 +> +> - 32960 国标协议 GB/T 32960.3-2016 +> - 上海巴士扩展协议 v1.4 + +## 概述 + +目前这个项目是一个 32960 的解析库,完全兼容《GB-T 32960 国标》,即《GB/T 32960.3 电动汽车远程服务与管理系统技术规范:通讯协议及数据格式》是用于新能源车辆远程服务平台间通讯的指导标准,可应用于车载通讯模块与远程服务平台间的通讯。 + +本项目目前支持 32960 的解析,校验以及日志输出。 + +## 基本数据包 + +首先我们来看一下整个 32960 包的二进制组成。 +一个完整的数据包应由起始符、命令单元(命令标志、应答标志)、识别码、数据加密方式、数据单元长度、数据单元和校验码组成,数据包结构和定义如下表所示。 + +| 起始字节 | 定义 | 数据类型 | 描述及要求 | 备注 | +| :--------- | :------------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------- | +| 0 | 起始符 | STRING | 固定为 ASCII 字符‘##’,用“0x23 | 0x23”表示。 | | +| 2 | 命令单元(命令标识) | BYTE | 命令表示定义见 3.1 | | +| 3 | 命令单元(应答标志) | BYTE | 应答标志定义见 3.2 | | +| 4 | 唯一标识码 | STRING | 当传输车辆数据时,应使用车辆 VIN,其字码应符合 GB16735 的规定,如传输其他数据,则使用唯一自定义编码 | +| 21 | 数据单元加密方式 | BYTE | 0x01:数据不加密;0x02:数据经过 RSA 算法加密;0x03:数据经过 AES128 位算法加密;“0xFE”表示异 常,“0xFF”表示无效,其他预留。 | | +| 22 | 数据单位长度 | WORD | 数据单元长度是数据单元的总字节数,有效值范围:0 ~ 65531。 | | +| 24 | 数据单元 | - | 数据单元格式和定义所在文件见下表 | +| 倒数第一位 | 校验码 | BYTE | 采用 BCC(异或校验)法,校验范围从命令单元的第一个字节开始,同后一字结异或,直到校验码前一字节  为止,校验码占用一个字节,当数据单元存在加密时,应先加密后校验,先校验后解密 | + +--- + +### 二进制数据类型说明 + +在 32960 协议中所有出现的二进制数据格式的描述如下: + +| 数据类型 | 描述及要求 | +| :------- | :---------------------------------------------------------------------------------------------------------------------------------------- | +| BYTE | 无符号单字节整型(字节,8 位) | +| WORD | 无符号单字节整型(字节,16 位) | +| DWORD | 无符号单字节整型(字节,32 位) | +| BYTE[n] | n 字节 | +| STRING | ASCII 字符码,若无数据则放一个 0 终结符,编码表示参见 GB/T 1988 所述含汉字时,采用区位码编码,占用 2 个字节,编码表示参见 GB 18030 所述。 | + +--- + +### 原始数据包结构图例 + +对二进制格式按照基本数据包格式进行数据划分: + +![原始包数据结构](https://ws2.sinaimg.cn/large/006tNc79gy1g25izlq1b0j30p80cm7h1.jpg) + +--- + +### 命令标志 + +| 编码 | 定义 | 方向 | +| :---------- | :----------------- | :----- | +| Ox01 | 车辆登入 | 上行 | +| Ox02 | 实时信息上报 | 上行 | +| Ox03 | 补发信息上报 | 上行 | +| Ox04 | 车辆登出 | 上行 | +| Ox05 | 平台登入 | 上行 | +| Ox06 | 平台登出 | 上行 | +| Ox07 | 心跳 | 上行 | +| Ox08 | 终端校时 | 上行 | +| Ox09 ~ Ox7F | 上行数据系统预留 | 上行 | +| Ox80 | 查询命令 | 上行 | +| Ox81 | 设置命令 | 上行 | +| Ox82 | 车载终端控制命令 | 下行 | +| Ox83 ~ OxBF | 下行数据系统预留 | 下行 | +| OxCO ~ OxFE | 平台交换自定义数据 | 自定义 | + +--- + +### 应答标志 + +| 编码 | 定义 | 说明 | +| :--- | :------- | :----------------------------- | +| Ox01 | 成功 | 接收到信息正确 | +| Ox02 | 错误 | 设置未成功 | +| Ox03 | VIN 重复 | VIN 重复错误 | +| OxFE | 命令 | 表示数据包为命令包,而非应答包 | + +### 时间定义 + +| 数据表示内容 | 长度(字节) | 数据类型 | 有效值范围 | +| :----------- | :----------- | :------- | :--------- | +| 年 | 1 | BYTE | 0 ~ 99 | +| 月 | 1 | BYTE | 0 ~ 12 | +| 日 | 1 | BYTE | 0 ~ 31 | +| 小时 | 1 | BYTE | 0 ~ 24 | +| 分钟 | 1 | BYTE | 0 ~ 59 | +| 秒 | 1 | BYTE | 0 ~ 59 | + +--- + +## 数据单元 + +数据单元是二进制数据中的主要承载实际上传数据的部分,由于格式比较复杂,根据不同的`命令标志`进行解析。每一个解析部分,都分为四部分: + +1. 二进制样例 +2. 二进制格式说明 +3. 解析结果样例 +4. 解析结果说明 + +其中解析结果整体格式是一致的: + +```js +{ + command: string, // 命令标志 详见每一节 + flag: "COMMAND", // 应答标志 + vin: "LZYTBGBW6J1014194", // 车辆vin码 + encrypt: "NONE", // 是否加密 + length: 30, + body: { + at: "2018-10-30T12:35:54.000Z", // 数据采集时间 + sn: 253, + iccid: "89860402101700179779", + subSysNm: 1, + subSysNmLen: 0, + subSysSn: [], + }, +} + +// 命令标志 +{ + VEHICLE_LOGIN: "VEHICLE_LOGIN", // 车辆登入 0x01 + REALTIME_REPORT: "REALTIME_REPORT", // 实时信息上报 0x02 + REISSUE_REPORT: "REISSUE_REPORT", // 补发信息上报 0x03 + VEHICLE_LOGOUT: "VEHICLE_LOGOUT", // 车辆登出 0x04 + PLATFORM_LOGIN: "PLATFORM_LOGIN", // 平台登入0x05 + PLATFORM_LOGOUT: "PLATFORM_LOGOUT", // 平台登出0x06 + HEARTBEAT: "HEARTBEAT", // 心跳 0x07 + TIME: "TIME", // 车辆校时 0x08 +}; + +// 应答标志 +{ + SUCCESS: "SUCCESS", // 成功 + FAIL: "FAIL", // 错误 + VIN_DUP: "VIN_DUP", // vin 重复 + COMMAND: "COMMAND", // 命令 +}; + +// 加密标志 +{ + NONE: "NONE", // 未加密 + RSA: "RSA", + AES128: "AES128", +}; +``` + +### 车辆登录 + +#### 车辆登录二进制样例 + +```sh +232301fe4c5a595442474257364a3130313431393401001e120a1e14233600fd383938363034303231303137303031373937373901005c +``` + +#### 车辆登录二进制格式说明 + +| 数据表示内容 | 长度/字节 | 数据类型 | 描述及要求 | +| :--------------------- | :-------- | :------- | :---------------------------------------------------------------------------------- | +| 数据采集时间 | 6 | BYET[6] | [见时间定义表](#时间定义) | +| 登入流水号 | 2 | WORD | 车载终端每登入一次登入流水号自动加 1,从 1 开始循环累加,最大值 65531,循环周期为天 | +| ICCID | 20 | STRING | SIM 卡 ICCID 号(ICCID 应为终端从 SIM 卡获取的值,不应该人为填写或修改) | +| 可充电储能子系统数 | 1 | BYTE | 可充电储能子系统数 n,有效值范围:0~250 | +| 可充电储能系统编码长度 | 1 | BYTE | 可充电储能系统编码长度 m,有效值范围:0~50,“0”表示不上传该编码 | +| 可充电储能系统编码 | n\*m | STRING | 可充电储能系统编码宜为终端从车辆获取的值 | + +#### 车辆登录解析结果样例 + +```js +{ + command: "VEHICLE_LOGIN", + flag: "COMMAND", + vin: "LZYTBGBW6J1014194", // 车辆vin码 + encrypt: "NONE", + length: 30, + body: { + at: "2018-10-30T12:35:54.000Z", // 数据上报时间 + sn: 253, + iccid: "89860402101700179779", + subSysNm: 1, + subSysNmLen: 0, + subSysSn: [], + }, +} +``` + +#### 车辆登录解析结果说明 + +request body 格式说明: + +| 字段 | 数据内容 | 类型 | 数据说明 | +| :---------- | :--------------------- | :------- | :---------------------------------------------------------------------------------- | +| at | 数据采集时间 | date | iso 格式 | +| sn | 登入流水号 | integer | 车载终端每登入一次登入流水号自动加 1,从 1 开始循环累加,最大值 65531,循环周期为天 | +| iccid | ICCID | string | SIM 卡 ICCID 号(ICCID 应为终端从 SIM 卡获取的值,不应该人为填写或修改) | +| subSysNm | 可充电储能子系统数 | integer | 可充电储能子系统数 n,有效值范围:0~250 | +| subSysNmLen | 可充电储能系统编码长度 | integer | 可充电储能系统编码长度 m,有效值范围:0~50,“0”表示不上传该编码 | +| subSysSn | 可充电储能系统编码 | [string] | 可充电储能系统编码宜为终端从车辆获取的值 | + +--- + +### 实时上报和补发信息 + +车辆实际数据信息都是通过实时上报和补发信息两个途径上传。 + +#### 二进制样例 + +```sh +232302fe4c5a59544147425732453130353434393101007f120a1e142400010103010000001b390b164925da39023e41b6000102010104284e204e2028000027100500073d270801dcda6a06013f0cbf015b0cb2010246014e400700000000000000000080003000000003e803e8ffffffffffffffffffffffffffff1649feca00000000000000000000ffff00000000ff280028282802c7 +``` + +#### 二进制格式说明 + +| 数据表示内容 | 长度/字节 | 数据类型 | 描述及要求 | +| :---------------- | :-------- | :------- | :----------------------------------- | +| 数据采集时间 | 6 | BYTE[6] | [时间定义表](#时间定义) | +| 信息类型标志(1) | 1 | BYTE | [信息类型标志类型](#数据单元) | +| 信息体(1) | - | BYTE | 根据信息类型不同,长度和数据类型不同 | +| ...... | - | - | ...... | +| 信息类型标志(n) | 1 | BYTE | | +| 信息体(n) | - | - | | + +#### 解析结果样例 + +```js +{ + command: "REALTIME_REPORT", + flag: "COMMAND", + vin: "LZYTAGBW2E1054491", + encrypt: "NONE", + length: 127, + body: { + at: "2018-10-30T12:36:00.000Z", + vehicle: { + type: "VEHICLE", + status: "ON", + chargeStatus: "UNCHARGED", + mode: "ELECTRIC", + speed: 0, + mileage: 178407.5, + voltage: 570.5, + current: -31, + soc: 0.57, + dcStatus: "OFF", + shift: "D", + resistance: 16822, + aptv: 0, + brake: 0.01, + }, + motor: { + type: "MOTOR", + count: 1, + motors: [ + { + no: 1, + status: "READY", + controlTemp: 0, + speed: 0, + torque: 0, + temp: 0, + voltage: 0, + current: 0, + }, + ], + }, + location: { type: "LOCATION", state: 0, lng: 121.4482, lat: 31.25105 }, + extreme: { + type: "EXTREME", + maxVoltageSubSysNo: 1, + maxVoltageSingNo: 63, + maxVoltage: 3.263, + minVoltageSubSysNo: 1, + minVoltageSingNo: 91, + minVoltage: 3.25, + maxNtcSubSysNo: 1, + maxNtcNo: 2, + maxNtc: 30, + minNtcSubSysNo: 1, + minNtcNo: 78, + minNtc: 24, + }, + alarm: { + type: "ALARM", + maxLevel: 0, + uas: { + ressChargeOver: 0, + motorTemp: 0, + highVolMuteStatus: 0, + motorControlTemp: 0, + dcdcStatus: 0, + brake: 0, + dcdcTemp: 0, + insulation: 0, + batteryBadConsistency: 0, + ressNotMatch: 0, + socJump: 0, + socOver: 0, + batteryLow: 0, + batteryOver: 0, + socLow: 0, + ressVolLow: 0, + ressVolOver: 0, + batteryTempOver: 0, + tempDiff: 0, + }, + ressLen: 0, + ressList: [], + mortorLen: 0, + mortorList: [], + engineLen: 0, + engineList: [], + otherLen: 0, + otherList: [], + }, + customExt: { + type: "CUSTOM_EXT", + dataLen: 48, + pressure1: 0, + pressure2: 0, + batteryVoltage: 0, + dcov: -900, + dcoc: -900, + cv: 570.5, + rc: 5522.6, + cp: 0, + totalCharge: 0, + totalDischarge: 0, + bpiRes: 0, + bniRes: 0, + motorContTemp: 0, + airMode: "OFF", + airTemp: 0, + insideTemp: 0, + outsideTemp: 0, + middleDoorStatus: "CLOSE", + frontDoorStatus: "CLOSE", + handbrakeStatus: "OFF", + keyPosition: "ON", + }, + ], + }, +} +``` + +#### 解析结果说明 + +具体解析结果查看信息体部分 + +--- + +### 车辆登出 + +#### 车辆登出二进制样例 + +```js +232304fe4c53464430333230344a43303031353935010008120a1e1424110014e9 +``` + +#### 车辆登出二进制格式说明 + +| 数据表示内容 | 长度/字节 | 数据类型 | 描述及要求 | +| :----------- | :-------- | :------- | :----------------------------- | +| 登出时间 | 6 | BYTE[6] | [时间定义表](#时间定义) | +| 登出流水号 | 2 | WORD | 登出流水号和当前登入流水号一致 | + +#### 车辆登出解析结果样例 + +```js +{ + command: "VEHICLE_LOGOUT", + flag: "COMMAND", + vin: "LSFD03204JC001595", + encrypt: "NONE", + length: 8, + body: { at: "2018-10-30T12:36:17.000Z", sn: 20 }, +} +``` + +#### 车辆登出解析结果说明 + +| 字段 | 数据内容 | 类型 | 数据说明 | +| :--- | :--------- | :------ | :----------------------------- | +| at | 登出时间 | date | ios 格式 | +| sn | 登出流水号 | integer | 登出流水号和当前登入流水号一致 | + +--- + +### 平台登入 + +#### 平台登入二进制样例 + +```sh +120A07150D2900027975746F6E67000000000000313231000000000000000000000000000000000001 +``` + +#### 平台登入二进制格式说明 + +| 数据表示内容 | 长度/字节 | 数据类型 | 描述及要求 | +| :----------- | :-------- | :------- | :------------------------------------------------------------------------------------------------------- | +| 平台登入时间 | 6 | BYTE[6] | [时间定义表](#时间定义) | +| 登入流水号 | 2 | WORD | 下级平台每登入一次,登入流水号自动加 1,从 1 开始循环累加,最大值为 65531,循环周期为一天 | +| 平台用户名 | 12 | STRING | 平台登入用户名 | +| 平台  密码 | 20 | STRING | 平台登入密码 | +| 加密规则 | 1 | BYTE | 0x01:数据不加密;0x02:数据经过 RSA 加密;0x03:数据经过 AES128 加密;0xFE 表示异常,0xFF 表示无效其他预留 | + +#### 平台登入解析结果样例 + +```js +{ + command: "PLATFORM_LOGIN", + flag: "COMMAND", + vin: "LSFD03204JC001595", + encrypt: "NONE", + length: 8, + body: { + at: "2018-10-07T13:13:41.000Z", + sn: 2, + username: "yutong", + password: "ssssss", + encrypt: "NONE", + }, +} +``` + +#### 平台登入解析结果说明 + +| 字段 | 数据内容 | 类型 | 数据说明 | +| :------- | :--------- | :------ | :----------------------------- | +| at | 登出时间 | date | ios 格式 | +| sn | 登出流水号 | integer | 登出流水号和当前登入流水号一致 | +| username | 平台方 | string | 密码输出隐藏 | + +--- + +### 平台登出 + +#### 平台登出二进制样例 + +```sh +232306FE4C5A595441474257394A313030343136340100081206161015150046E8 +``` + +#### 平台登出二进制格式说明 + +| 数据表示内容 | 长度/字节 | 数据类型 | 描述及要求 | +| :----------- | :-------- | :------- | :----------------------------- | +| 登出时间 | 6 | BYTE[6] | [时间定义表](#时间定义) | +| 登出流水号 | 2 | WORD | 登出流水号和当前登入流水号一致 | + +#### 平台登出解析结果样例 + +```js +{ + body: { at: "2018-06-22T08:21:21.000Z", sn: 70 }, + command: "PLATFORM_LOGOUT", + encrypt: "NONE", + flag: "COMMAND", + length: 8, + vin: "LZYTAGBW9J1004164", +} +``` + +#### 平台登出解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :--- | :--------- | :------ | :----------------------------- | +| at | 登出时间 | date | ISO string | +| sn | 登出流水号 | integer | 登出流水号和当前登入流水号一致 | + +--- + +### 心跳 + +#### 心跳二进制样例 + +```js +232307FE4838323230363530303030303030303030010000BB +``` + +心跳就是一个没有数据 body 的包。 + +#### 心跳解析结果样例 + +```js +{ + command: "HEARTBEAT", + flag: "COMMAND", + vin: "LZYTBGCW5J1035715", // 车辆vin 码 + encrypt: "NONE", + length: 0, +} +``` + +--- + +## 信息体 + +实时信息上报和补发信息上报中的数据主要在信息体中。信息体又分为很多种类。 + +// 信息体 +{ + vehicle: "VEHICLE", // 整车数据 + motor: "MOTOR", // 电机数据 + fuelcell: "FUELCELL", // 燃料电池数据 + engine: "ENGINE", // 发动机数据 + location: "LOCATION", // 位置数据 + extreme: "EXTREME", // 极值数据 + alarm: "ALARM", // 报警数据 + ressVoltage: "RESS_VOLTAGE", // 可充电储能装置电压数据 + ressTemperature: "RESS_TEMPERATURE", // 可充电储能装置温度数据 + customExt: "CUSTOM_EXT", // 上海巴士自定义扩展数据 + tenSeconds: "TEN_SECONDS", // 十秒上传数据 + adas: "ADAS", // ADAS 数据 +}; + +信息体的数据位于 `request.body` 中,信息体部分的数据样例只展示信息体本身部分。省略 request.body 的其它部分。 +一个 32960 包里不管是实时信息上报还是补发信息上报,都有可能包含 1 个或者多个信息体。 +32960 协议并没有对哪些数据走补发有所规定,但是本解析其中的 `ADAS` 和 `TEN_SECONDS` 一定会走补发。它们是上海巴士v1.4协议中规定的累积10s数据。 + +特殊格式说明: + +1. `NAN`代表这个数值异常 +2. 如果某个值不存在代表 这个值无效或者终端未上传 +3. 每个 string enum 类型,都有个"ABNORMAL"的值,代表数据异常 + +--- + +### 整车数据 + +0x01 VEHICLE + +#### 整车数据二进制样例 + +```sh +# 只包含整车数据部分 +0103010032000013881b58000032013e01d21465 +``` + +#### 整车数据二进制格式说明 + +| 数据表示内容 | 长度/字节 | 类型 | 描述及要求 | +| :------------- | :-------- | :---- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 车辆状态 | 1 | BYTE | 0X01:车辆启动宅;0x02:熄火,0x03:其他状态;0xFE:表示异常,0xFF:表示无效;取仪表外发的此数据,充电时仪表也要外发此数据 | +| 充电状态 | 1 | BYTE | 0X01:停车充电,0x02:行驶充电,0x03:未充电状态;0x04:充电完成;0xFE:表示异常,0xFF:表示无效; | +| 运行模式 | 1 | BYTE | 0X01:纯电;0x02:混动,0x03:燃油;0xFE:表示异常,0xFF:表示无效; | +| 车速 | 2 | WORD | 有效值范围:0 ~ 2200(表示 0km/h ~ 220km/h),最小计量单位: 0.1km/h,0xFF,0xFE:表示异常,0xFF,0xFF:表示无效; | +| 累计里程 | 4 | DWORD | 有效值范围: 0 ~ 9999999(表示 0km ~ 999999.9km),最小计量单位 0.1km,0xFF,0xFE:表示异常,0xFF,0xFF:表示无效;取仪表外发的此数据,充电时仪表也要外发此数据 | +| 总电压 | 2 | WORD | 有效值范围:0 ~ 10000(表示 0V ~ 1000V),最小计量单位: 0.1V,0xFF,0xFE:表示异常,0xFF,0xFF:表示无效; | +| 总电流 | 2 | WORD | 有效值范围:0 ~ 20000(偏移量 1000A,表示-1000A ~ +1000A),最小计量单位: 0.1A,0xFF,0xFE:表示异常,0xFF,0xFF:表示无效; | +| SOC | 1 | BYTE | 有效值范围:0 ~ 100(表示 0% ~ 100%),最小计量单位: 1%,0xFF,0xFE:表示异常,0xFF,0xFF:表示无效; | +| DC-DC 状态 | 1 | BYTE | 0X01:工作,0x02:断开;0xFE:表示异常,0xFF:表示无效; | +| 档位 | 1 | BYTE | [档位定义](#档位状态为定义) | +| 绝缘电阻 | 2 | WORD | 有效值范围:0 ~ 60000(表示 0kΩ ~ 100kΩ),最小计量单位: 1kΩ | +| 加速踏板行程值 | 1 | BYTE | 有效值范围:0 ~ 100(表示 0%~ 100%),最小计量单元:1%,“0xFE”表示异常,“0xFF”表示无效。 | +| 制动踏板状态 | 1 | BYTE | 有效值范围:0 ~ 100(表示 0%~ 100%),最小计量单元: 1%,“0”表示制动关的状态。 在无具体行程值情况下 “0x65”即“101”表示制动有效状态,“0xFE”表示异常, “0xFF”表示无效。 | + +#### 档位状态为定义 + +| Bit7 | Bit6 | Bit5 | Bit4 | Bit3 Bit2 Bit1 Bit0 | +| :-------------------- | :-------------------- | :----------------------- | :----------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | +| 预留,预留为用 0 表示 | 预留,预留为用 0 表示 | 1:有驱动力,0:无驱动力 | 1:有制动力;0:无制动力 | 档位: 0000: 空挡;0001:1 挡;0010:2 挡;0011: 3 挡;0100:4 挡;0101:5 挡;0110:6 挡;1101:......倒挡;1110: 自动 D 挡;1111:停车倒挡 | + +#### 整车解析结果样例 + +```js +{ + type: "VEHICLE", + status: "ON", + chargeStatus: "UNCHARGED", + mode: "ELECTRIC", + speed: 0, + mileage: 178407.5, + voltage: 570.5, + current: -31, + soc: 0.57, + dcStatus: "OFF", + shift: "D", + resistance: 16822, + aptv: 0, + brake: 0.01, +} +``` + +#### 整车解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :----------- | :------------- | :---------- | :------------------------------------------------------------------------------------------------- | +| status | 车辆状态 | string enum | "ON": 启动, "OFF": 熄火, "OTHER": 其他 | +| chargeStatus | 充电状态 | string enum | "PARK_CHARGING": 停车充电, "MOVE_CHARGING": 行驶充电, "UNCHARGED": 未充电状态, "COMPETE": 充电完成 | +| mode | 运行模式 | string enum | "ELECTRIC": 电动, "MIXED": 混动, "FUEL": 燃油 | +| speed | 车速 | float | 0 ~ 220 0.1km/h | +| mileage | 累计里程 | float | 0 ~ 999999.9 0.1km | +| voltage | 总电压 | float | 0 ~ 1000 0.1V | +| current | 总电流 | float | -1000 ~ 1000 0.1A | +| soc | SOC | float | 0 ~ 1 0.01 | +| dcStatus | DC-OC 状态 | string enum | "ON":工作, "OFF": 断开 | +| shift | 档位 | enum | 见下面车辆档位注释 | +| resistance | 绝缘电阻 | integer | 0 ~ 60000 1kΩ | +| aptv | 加速踏板行程值 | float | 0 ~ 1 0.01 | +| brake | 制动踏板状态 | float | 0 ~ 1 0.01 | + +--- + +```js +// 车辆档位 +[ + "N", // 空挡 + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "R", // 倒挡 + "D", // 自动 + "P", // 驻车 +]; +``` + +### 驱动电机数据 + +#### 驱动电机二进制样例 + +```sh +# 仅包含驱动电机二进制数据 +0202014B639C3A346D187C271001014B639C3A346D187C2710 +``` + +#### 驱动电机二进制格式说明 + +| 数据表示内容 | 长度/字节 | 数据类型 | 描述及要求 | +| :------------------- | :--------------------------- | :------- | :------------------------------------------------------- | +| 驱动电机个数 | 1 | BYTE | 有效值 1 ~ 253 | +| 驱动电机总成信息列表 | 每个驱动电机总成信息长度之和 | - | 按驱动电机序号依次排列,每个驱动电机数据格式和定义见下表 | + +#### 每个驱动电机数据格式和定义 + +| 数据表示内容 | 长度/字节 | 数据类型 | 描述及要求 | +| :--------------------- | :--------------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------- | +| 驱动电机序号 | 1 | BYTE | 驱动电机顺序号,有效值 1 ~ 253 | +| 驱动电机状态 | 每个驱动电机总成信息长度之和 | BYTE | 0X01:耗电,0x02:发电,0x03:关闭状态;0x04:准备状态;0xFE:表示异常,0xFF:表示无效; | +| 驱动电机控制器温度 | 1 | BYTE | 有效值范围 0 ~ 250(数据偏移量 40℃,表示-40 ℃ ~ +210℃),最小计量单位:1℃,0xFE:表示异常,0xFF:表示无效; | +| 驱动电机转速 | 2 | WORD | 有效值范围:0 ~ 65531(偏移量 2000,表示-20000r/min ~ 45531 r/min),最小计量单位: 1r/min,0xFF,0xFE:表示异常,0xFF,0xFF:表示无效; | +| 驱动电机转矩 | 2 | WORD | 有效值范围:0 ~ 65531(偏移量 2000,表示-2000N/m ~ 4553.1 N/m),最小计量单位: 0.1N/m,0xFF,0xFE:表示异常,0xFF,0xFF:表示无效; | +| 驱动电机温度 | 1 | BYTE | 有效值范围 0 ~ 250(数据偏移量 40℃,表示-40 ℃ ~ +210℃),最小计量单位:1℃,0xFE:表示异常,0xFF:表示无效; | +| 电机控制器输入电压 | 2 | WORD | 有效值范围 0 ~ 600000(表示 0V ~ 6000V),最小计量单位 0.1V,0xFE:表示异常,0xFF:表示无效; | +| 电机控制器直流母线电流 | 2 | WORD | 有效值范围 0 ~ 200000(数值偏移量 1000A,表示-1000A ~ 1000A),最小计量单位 0.1A,0xFF,0xFE:表示异常,0xFF,0xFF:表示无效; | + +#### 驱动电机解析结果样例 + +```js +{ + type: "MOTOR", + count: 1, + motors: [ + { + no: 1, + status: "READY", + controlTemp: 0, + speed: 0, + torque: 0, + temp: 0, + voltage: 0, + current: 0, + }, + ], +} +``` + +#### 驱动电机解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :----- | :------------------- | :------- | :---------------------------------------- | +| count | 驱动电机个数 | interger | 1 ~ 253 | +| motors | 驱动电机总成信息列表 | array | [每个驱动电机信息数据](#每个驱动电机数据) | + +#### 每个驱动电机数据 + +| 字段 | 数据内容 | 类型 | 说明 | +| :---------- | :--------------------- | :---------- | :----------------------------------------------------------------------- | +| no | 驱动电机序号 | integer | 1 ~ 253 | +| status | 驱动电机状态 | string enum | "CONSUMPTION"//耗电,"GENERATION"//发电,"OFF"//关闭状态,"READY"//准备" | +| controlTemp | 驱动电机控制器温度 | integer | -40 ~ 210 1℃ | +| speed | 驱动电机转速 | integer | -20000 ~ 45531 1r/min | +| torque | 驱动电机转矩 | float | -2000N/m ~ 4553.1 0.1N/m | +| temp | 驱动电机温度 | integer | -40 ~ +210 1℃ | +| voltage | 电机控制器输入电压 | float | 0 ~ 6000 0.1V | +| current | 电机控制器直线母线电流 | float | -1000 ~ 1000 0.1A | + +--- + +### 燃料电池数据 (没有收到过相关数据) + +0x03 FUELCELL + +#### 燃料电池二进制样例 + +#### 燃料电池二进制格式说明 + +| 数据内容 | 字节 | 数据类型 | 有效值范围 | 分辨率 | 偏移量 | 异常 | 无效 | 其他 | +| :--------------------- | :--- | :------- | :--------- | :----- | :----- | :----- | :----- | :--------------- | +| 燃料电池电压 | 2 | WORD | 0 ~ 20000 | 0.1V | | OxFFFE | OxFFFF | +| 燃料电池电流 | 2 | WORD | 0 ~ 20000 | 0.1A | | OxFFFE | OxFFFF | +| 燃料消耗率 | 2 | WORD | 0 ~ 60000 | 0.01 | | OxFFFE | OxFFFF | +| 燃料电池温度探针总数 | 2 | WORD | 0 ~ 65531 | | | OxFFFE | OxFFFF | +| 探针温度值 | 1\*N | BYTE[N] | 0 ~ 240 | | 40 | OxFE | OxFF | +| 氢系统中最高温度 | 2 | WORD | 0 ~ 2400 | 0.1℃ | 40 | OxFFFE | OxFFFF | +| 氢气最高温度传感器代号 | 1 | BYTE | 1 ~ 252 | | | OxFE | OxFF | +| 氢气最高浓度 | 2 | WORD | 0 ~ 60000 | 1mg/kg | | OxFFFE | OxFFFF | +| 氢气最高浓度传感器代号 | 1 | BYTE | 1 ~ 252 | | | OxFE | OxFF | +| 氢气最高压力 | 2 | WORD | 0 ~ 1000 | 0.1MPa | | OxFFFE | OxFFFF | +| 氢气最高压力传感器代号 | 1 | BYTE | 1 ~ 252 | | | OxFE | OxFF | +| 高压 DC/DC 状态 | 1 | BYTE | | | | OxFE | OxFF | 01:工作;02:断开 | + +#### 燃料电池解析结果样例 + +#### 燃料电池解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :-------------- | :--------------------- | :--------------- | :------------------- | +| voltage | 燃料电池电压 | float | 0 ~ 2000 0.1V | +| current | 燃料电池电流 | float | 0 ~ 2000 0.1A | +| conRate | 燃料消耗率 | float | 0 ~ 600 0.01kg/100km | +| probeCount | 燃料电池温度探针总数 | integer | 0 ~ 65531 | +| ntcs | 探针温度值 | array< integer > | -40 ~ 200 1℃ | +| maxNtc | 氢系统中最高温度 | float | -40 ~ 200 0.1℃ | +| maxNtcNo | 氢气最高温度传感器代号 | integer | 1 ~ 252 | +| hcOfh | 氢气最高浓度 | integer | 0 ~ 50000 1mg/kg | +| hcOfhNo | 氢气最高浓度传感器代号 | integer | 1 ~ 252 | +| maxVoltageOfh | 氢气最高压力 | float | 0 ~ 100 0.1MPa | +| maxVoltageOfhNo | 氢气最高压力传感器代号 | integer | 1 ~ 252 | +| dc | 高压 DC/DC 状态 | string enum | ON:工作;OFF:断开 | + +--- + +### 发动机数据 (没有收到过相关数据,未经测试) + +0x04 ENGINE + +#### 发动机数据二进制样例 + +#### 发动机数据二进制格式说明 + +| 数据表示内容 | 长度/字节 | 数据类型 | 有效值范围 | 分辨率 | 偏移量 | 异常 | 无效 | 其他 | +| :----------- | :-------- | :------- | :--------- | :---------- | :----- | :----- | :----- | :---------------------------- | +| 发动机状态 | 1 | BYTE | | | | OxFE | OxFF | Ox01:启动状态;Ox02:关闭状态 | +| 曲轴转速 | 2 | WORD | 0 ~ 60000 | 1r/min | | OxFFFE | OxFFFF | +| 燃料消耗率 | 2 | WORD | 0 ~ 60000 | 0.01L/100km | | OxFFFE | OxFFFF | + +#### 发动机数据解析结果样例 + +#### 发动机数据解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :------ | :--------- | :---------- | :------------------------- | +| state | 发动机状态 | string enum | ON:启动状态;OFF:关闭状态 | +| csSpeed | 曲轴转速 | integer | 0 ~ 60000 1r/min | +| fcRate | 燃料消耗率 | float | 0 ~ 600 0.01L/100km | + +--- + +### 位置数据 + +#### 位置数据二进制样例 + +```sh +# 仅包含位置数据部分 +00072733A101CF049C +``` + +#### 位置数据二进制格式说明 + +| 数据表示内容 | 长度/字节 | 数据类型 | 描述及要求 | +| :----------- | :-------- | :------- | :--------------------------------------------------------- | +| 定位状态 | 1 | BYTE | 状态位定义见表 15 | +| 经度 | 4 | DWORD | 以度为单位的纬度值乘以 10 的六次方,精度精确到百万分之一度 | +| 纬度 | 4 | DWORD | 以度为单位的经度值乘以 10 的六次方,精度精确到百万分之一度 | + +##### 状态为定义 + +| 位 | 状态 | +| :---- | :---------------------------------------------------------------------------------------------------------------- | +| 0 | 0:有效定位;1: 无效定位(当数据通信正常,为不能获取定位信息时,发送最后一次有效定位信息,并将定位状态置为无效) | +| 1 | 0:北纬,1:南纬 | +| 2 | 0:东经,1:西经 | +| 3 ~ 7 | 保留 | + +#### 位置数据解析结果样例 + +```js +{ + type: "LOCATION", + state: 0, + lng: 121.4482, + lat: 31.25105 +} +``` + +#### 位置数据解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :---- | :------- | :------ | :----------- | +| state | 定义状态 | integer | 见状态位定位 | +| lng | 经度 | float | 0.000001 | +| lat | 纬度 | float | 0.000001 | + +--- + +### 极值数据 + +0x06 EXTREME + +#### 极值数据二进制样例 + +```sh +# 仅包含机制部分数据 +0111064001020500010150010540 +``` + +#### 极值数据二进制格式说明 + +| 数据表示内容 | 长度/字节 | 数据类型 | 有效值范围 | 分辨率 | 偏移量 | 说明 | +| :------------------- | :-------- | :------- | :--------- | :----- | :----- | :--------------------------- | +| 最高电压电池子系统号 | 1 | BYTE | 1 ~ 250 | | | 0xFE 表示异常;0xFF 表示无效 | +| 最高电压电池单体代号 | 1 | BYTE | 1 ~ 250 | | | 0xFE 表示异常;0xFF 表示无效 | +| 电池单体电压最高值 | 2 | WORD | 1 ~ 15000 | 0.001V | | 0xFE 表示异常;0xFF 表示无效 | +| 最低电压电池子系代号 | 1 | BYTE | 1 ~ 250 | | | 0xFE 表示异常;0xFF 表示无效 | +| 最低电压电池单体代号 | 1 | BYTE | 1 ~ 250 | | | 0xFE 表示异常;0xFF 表示无效 | +| 电池单体最低电压值 | 2 | WORD | 1 ~ 15000 | 0.001V | | 0xFE 表示异常;0xFF 表示无效 | +| 最高温度子系统号 | 1 | BYTE | 1 ~ 250 | | | 0xFE 表示异常;0xFF 表示无效 | +| 最高温度探针序号 | 1 | BYTE | 1 ~ 250 | | | 0xFE 表示异常;0xFF 表示无效 | +| 最高温度值 | 1 | BYTE | 1 ~ 250 | 1℃ | 40℃ | 0xFE 表示异常;0xFF 表示无效 | +| 最低温度子系统号 | 1 | BYTE | 1 ~ 250 | | | 0xFE 表示异常;0xFF 表示无效 | +| 最低温度探针序号 | 1 | BYTE | 1 ~ 250 | | | 0xFE 表示异常;0xFF 表示无效 | +| 最低温度值 | 1 | BYTE | 1 ~ 250 | 1℃ | 40℃ | 0xFE 表示异常;0xFF 表示无效 | + +#### 极值数据解析结果样例 + +```js +{ + type: "EXTREME", + maxVoltageSubSysNo: 1, + maxVoltageSingNo: 63, + maxVoltage: 3.263, + minVoltageSubSysNo: 1, + minVoltageSingNo: 91, + minVoltage: 3.25, + maxNtcSubSysNo: 1, + maxNtcNo: 2, + maxNtc: 30, + minNtcSubSysNo: 1, + minNtcNo: 78, + minNtc: 24, +} +``` + +#### 极值数据解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :----------------- | :------------------- | :------ | :------------ | +| maxVoltageSubSysNo | 最高电压电池子系统号 | integer | 1~250 | +| maxVoltageSingNo | 最高电压电池单体代号 | integer | 1 ~ 250 | +| maxVoltage | 电池单体电压最高值 | float | 0 ~ 15 0.001V | +| minVoltageSubSysNo | 最低电压电池子系代号 | integer | 1 ~ 250 | +| minVoltageSingNo | 最低电压电池单体代号 | integer | 1 ~ 250 | +| minVoltage | 电池单体最低电压值 | float | 0 ~ 15 0.001V | +| maxNtcSubSysNo | 最高温度子系统号 | integer | 1 ~ 250 | +| maxNtcNo | 最高温度探针序号 | integer | 1 ~ 250 | +| maxNtc | 最高温度值 | integer | -40 ~ 200 1℃ | +| minNtcSubSysNo | 最低温度子系统号 | integer | 1 ~ 250 | +| minNtcNo | 最低温度探针序号 | integer | 1 ~ 250 | +| minNtc | 最低温度值 | integer | -40 ~ 200 1℃ | + +--- + +### 报警数据 + +0x07 ALARM + +#### 报警数据二进制样例 + +```sh +# 仅包含报警部分数据 +0000000000000000000801011B58 +``` + +#### 报警数据二进制格式说明 + +| 数据表示内容 | 类型 | 长度/字节 | 说明 | +| :------------------------- | :---- | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 最高报警等级 | BYTE | 1 | 为当前发生的故障中最高等级,有效值范围: 0 ~ 3 ,0:表示无故障,1:表示一级故障;2 表示 2 级故障,3 表示 3 级故障,3 级故障为最高级别故障,指代驾驶员应立即停车处理或请求救援的故障,具体等级对应的故障内容由厂商自行定义,0xFE 表示异常;0xFF 表示无效 | +| 通用报警标志 | DWORD | 4 | 见下表通用报警标志位定义 | +| 可充电储能装置故障总数 N1 | BYTE | 1 | N1 个可充电储能装置故障,有效值范围:0 ~ 252,0xFE 表示异常;0xFF 表示无效 | +| 可充电储能装置故障代码列表 | DWORD | 4\*N | 扩展性数据,由厂商自行定义,可充电智能装置故障个数等于可充电储能装置故障总数 N1 | +| 驱动电机故障总数 N2 | BYTE | 1 | N2 个可充电储能装置故障,有效值范围:0 ~ 252,0xFE 表示异常;0xFF 表示无效 | +| 驱动电机故障代码列表 | DWORD | 4\*N2 | 扩展性数据,由厂商自行定义,可充电智能装置故障个数等于可充电储能装置故障总数 N12 | +| 发动机故障总数 N3 | BYTE | 1 | N3 个可充电储能装置故障,有效值范围:0 ~ 252,0xFE 表示异常;0xFF 表示无效 | +| 发动机故障列表 | DWORD | 4\*N3 | 扩展性数据,由厂商自行定义,可充电智能装置故障个数等于可充电储能装置故障总数 N3 | +| 其他故障总数 N4 | BYTE | 1 | N4 个可充电储能装置故障,有效值范围:0 ~ 252,0xFE 表示异常;0xFF 表示无效 | +| 其他故障代码列表 | DWORD | 4\*N4 | 扩展性数据,由厂商自行定义,可充电智能装置故障个数等于可充电储能装置故障总数 N4 | + +#### 通用报警标志位定义 + +| 位 | 定义 | 处理说明 | +| :-- | :----------------------------------- | :--------------------- | +| 0 | 1:温度差异报警;0:正常 | 标志维持到报警条件解除 | +| 1 | 1:电池高温报警;0:正常 | 标志维持到报警条件解除 | +| 2 | 1:车载储能装置类型过压报警;0:正常 | 标志维持到报警条件解除 | +| 3 | 1:车载储能装置类型欠压报警;0:正常 | 标志维持到报警条件解除 | +| 4 | 1:SOC 低报警;0:正常 | 标志维持到报警条件解除 | +| 5 | 1:单体电池过压报警;0:正常 | 标志维持到报警条件解除 | +| 6 | 1:单体电池欠压报警;0:正常 | 标志维持到报警条件解除 | +| 7 | 1:SOC 过高报警;0:正常 | 标志维持到报警条件解除 | +| 8 | 1:SOC 跳变报警;0:正常 | 标志维持到报警条件解除 | +| 9 | 1:可充电储能系统不匹配报警;0:正常 | 标志维持到报警条件解除 | +| 10 | 1:电池单体一致性差报警;0:正常 | 标志维持到报警条件解除 | +| 11 | 1:绝缘报警;0:正常 | 标志维持到报警条件解除 | +| 12 | 1:DC-DC 温度报警;0:正常 | 标志维持到报警条件解除 | +| 13 | 1:制动系统报警;0:正常 | 标志维持到报警条件解除 | +| 14 | 1:DC-DC 状态报警;0:正常 | 标志维持到报警条件解除 | +| 15 | 1:驱动电机控制器温度报警;0:正常 | 标志维持到报警条件解除 | +| 16 | 1:高压互锁状态报警;0:正常 | 标志维持到报警条件解除 | +| 17 | 1:驱动电机温度报警;0:正常 | 标志维持到报警条件解除 | +| 18 | 1:车载储能装置类型过充;0:正常 | 标志维持到报警条件解除 | + +#### 报警数据解析结果样例 + +```js +{ + type: "ALARM", + maxLevel: 0, + uas: { + ressChargeOver: false, + motorTemp: false, + highVolMuteStatus: false, + motorControlTemp: false, + dcdcStatus: false, + brake: false, + dcdcTemp: false, + insulation: false, + batteryBadConsistency: false, + ressNotMatch: false, + socJump: false, + socOver: false, + batteryLow: false, + batteryOver: false, + socLow: false, + ressVolLow: false, + ressVolOver: false, + batteryTempOver: false, + tempDiff: false, + }, + ressLen: 0, + ressList: [], + mortorLen: 0, + mortorList: [], + engineLen: 0, + engineList: [], + otherLen: 1, + otherList: [{"type":16,"code":5126,"level":2}], +} +``` + +#### 报警数据解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :------------ | :------------------------- | :------------- | :------------------------------- | +| maxAlarmLevel | 最高报警等级 | integer | 0 ~ 3 | +| uas | 通用报警标志 | object | 通用报警标志位定义见上面定义表 | +| ressLen | 可充电储能装置故障总数 N1 | integer | 0~252 | +| ressList | 可充电储能装置故障代码列表 | array< Fault > | [Fault 解析结果](#Fault解析结果) | +| mortorLen | 驱动电机故障总数 N2 | integer | 0 ~ 252 | +| mortorList | 驱动电机故障代码列表 | array< Fault > | [Fault 解析结果](#Fault解析结果) | +| engineLen | 发动机故障总数 N3 | integer | 0~252 | +| engineList | 发动机故障列表 | array< Fault > | [Fault 解析结果](#Fault解析结果) | +| otherLen | 其他故障总数 N4 | integer | 0~252 | +| otherList | 其他故障代码列表 | array< Fault > | [Fault 解析结果](#Fault解析结果) | + +##### Fault 解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :---- | :--------- | :------ | :--- | +| type | 故障码类型 | integer | | +| code | 故障编码 | integer | | +| level | 故障级别 | integer | 0~3 | + +通用报警标志 + +```js +"ressChargeOver"; // 车载储能装置类型过充 +"motorTemp"; // 驱动电机温度报警 +"highVolMuteStatus"; // 高压互锁状态报警 +"motorControlTemp"; // 驱动电机控制器温度报警 +"dcdcStatus"; // DC-DC 状态报警 +"brake"; // 制动系统报警 +"dcdcTemp"; // DC-DC 温度报警 +"insulation"; // 绝缘报警 +"batteryBadConsistency"; // 电池单体一致性差报警 +"ressNotMatch"; // 可充电储能系统不匹配报警 +"socJump"; // SOC 跳变报警 +"socOver"; // SOC 过高报警 +"batteryLow"; // 单体电池欠压报警 +"batteryOver"; // 单体电池过压报警 +"socLow"; // SOC 低报警 +"ressVolLow"; // 车载储能装置类型欠压报警 +"ressVolOver"; // 车载储能装置类型过压报警 +"batteryTempOver"; // 电池高温报警 +"tempDiff"; // 温度差异报警 +``` + +--- + +### 可充电储能装置电压数据 + +0x08 RESS_VOLTAGE + +#### 可充电储能装置电压数据二进制样例 + +```sh +# 仅包含报警部分数据 +01011B583A98001100011106400500064006400640064006400640064006400640064006400640064006400640 +``` + +#### 可充电储能装置电压数据二进制格式说明 + +// TODO: 暂缺 + +#### 可充电储能装置电压数据解析结果样例 + +```js +{ + type: "RESS_VOLTAGE", + subCount: 1, + subSystems: [ + { + batteryCount: 17, + batteryVols: [ + 1.6, + 1.28, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + 1.6, + ], + current: 500, + frameBatteryCount: 17, + frameStartBatteryNo: 1, + no: 1, + voltage: 700, + }, + ], +} + +``` + +#### 可充电储能装置电压数据解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :--------- | :------------------- | :------------------- | :-------------------------------------------------------- | +| subCount | 可充电储能子系统个数 | integer | | +| subSystems | 可充电储能装置电压 | array< RessVoltage > | [可充电储能装置电压数据结构](#可充电储能装置电压数据结构) | + +##### 可充电储能装置电压数据结构 + +| 字段 | 数据内容 | 类型 | 说明 | +| :------------------ | :------------------- | :------------- | :------------- | +| no | 可充电储能子系统编号 | integer | | +| voltage | 可充电储能装置电压 | float | 0.1v | +| current | 可充电储能装置电压 | float | -1000 ~ ? 0.1A | +| batteryCount | 单体电池总数 | integer | | +| frameStartBatteryNo | 本帧起始电池序号 | integer | | +| frameBatteryCount | 本帧单体电池总数 | integer | | +| batteryVols | 单体电池电压 | array< float > | 0.001v | + +--- + +### 可充电储能装置温度数据 + +0x09 RESS_TEMPERATURE + +#### 可充电储能装置温度数据二进制样例 + +```sh +# 仅包含可充电储能装置温度数据 +010100055040404040 +``` + +#### 可充电储能装置温度数据二进制格式说明 + +// TODO:暂无 + +#### 可充电储能装置温度数据解析结果样例 + +```js +{ + subCount: 1, + subSystems: [ + { no: 1, probeCount: 5, temps: [40, 24, 24, 24, 24] } + ], +} +``` + +#### 可充电储能装置温度数据解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :--------- | :------------------- | :----------------------- | :-------------------------------------------------------- | +| subCount | 可充电储能子系统个数 | integer | | +| subSystems | 可充电储能装置温度 | array< RessTemperature > | [可充电储能装置温度数据结构](#可充电储能装置温度数据结构) | + +##### 可充电储能装置温度数据结构 + +| 字段 | 数据内容 | 类型 | 说明 | +| :--------- | :--------------------- | :--------------- | :----------- | +| no | 可充电储能子系统编号 | integer | | +| probeCount | 可充电储能温度探针个数 | float | 0.1v | +| temps | 温度 | array< integer > | -40 ~ 200 1℃ | + +--- + +### 自定义扩展数据 + +#### 自定义扩展数据二进制样例 + +0x80 CUSTOM_EXT + +#### 自定义扩展数据二进制格式说明 + +| 数据表示内容 | 长度/字节 | 数据类型 | 描述及要求 | +| :------------- | :-------- | :------- | :--------------------------------------------------- | +| 自定义数据长度 | 2 | WORD | 自定义数据长度 n,有效范围 1 ~ 65531 | +| 自定义数据 | 1\*N |  BYTE[N] | 拓展性数据,由用户自行定义 [自定义数据](#自定义数据) | + +##### 自定义数据 + +| 数据内容 | 长度/字节 | 数据类型 | 描述及要求 | +| :-------------- | :-------- | :------- | :---------------------------------------------------------------------------------------------------------------------------- | +| 气压 1 | 1 | BYTE | 分辨率:4kPa,偏移量:0,有效值范围: 0~1000kpa,“FE”表示异常,“FF”表示无效 | +| 气压 2 | 1 | BYTE | 分辨率:4kPa ,偏移量:0 ,有效值范围:0~1000kpa,“FE”表示异常,“FF”表示无效 | +| 蓄电池电压 | 1 | BYTE | 分辨率:0.5V/bit,偏移量:0,有效值范围:0~32V,“FE”表示异常,“FF”表示无效 | +| DCDC 输出电压 | 2 | WORD | 分辨率:0.1V,偏移量:-1000,有效值 范围:0~32V,“FF,FF”表示无效 | +| DCDC 输出电流 | 2 | WORD | 分辨率:0.1A,偏移量:-1000,有效值范围:-1000~1000A, “0xFF,0xFE”异常,“0xFF,0xFF”无效。 | +| DCDC 散热器温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃,“FF”表示无效 | +| DCAC 散热器温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃,“FF”表示无效 | +| 左前轮胎压力 | 1 | BYTE | 分辨率:4kPa,偏移量:0,有效值范围:0~1000kpa, “FE”表示异常,“FF”表示无效 | +| 左前轮胎温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃, “FF”表示无效 | +| 右前轮胎压力 | 1 | BYTE | 分辨率:4kPa,偏移量:0,有效值范围:0~1000kpa, “FE”表示异常,“FF”表示无效 | +| 右前轮胎温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃, “FF”表示无效 | +| 左后 1 轮胎压力 | 1 | BYTE | 分辨率:4kPa,偏移量:0,有效值范围:0~1000kpa, “FE”表示异常,“FF”表示无效 | +| 左后 1 轮胎温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃, “FF”表示无效 | +| 左后 2 轮胎压力 | 1 | BYTE | 分辨率:4kPa,偏移量:0,有效值范围:0~1000kpa, “FE”表示异常,“FF”表示无效 | +| 左后 2 轮胎温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃, “FF”表示无效 | +| 右后 1 轮胎压力 | 1 | BYTE | 分辨率:4kPa,偏移量:0,有效值范围:0~1000kpa, “FE”表示异常,“FF”表示无效 | +| 右后 1 轮胎温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃, “FF”表示无效 | +| 右后 2 轮胎压力 | 1 | BYTE | 分辨率:4kPa,偏移量:0,有效值范围:0~1000kpa, “FE”表示异常,“FF”表示无效 | +| 右后 2 轮胎温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃, “FF”表示无效 | +| 充电电压 | 2 | WORD | 有效值范围:0 ~ 10000(表示 0V ~ 1000V),最小计量单元:0.1V,“0xFF,0xFE”表示异常,“0xFF,0xFF”表示无效。 | +| 充电电流 | 2 | WORD | 有效值范围: 0 ~ 20000(偏移量 1000A,表示-1000A ~+1000A),最小计量单元:0.1A,“0xFF,0xFE”表示异常, “0xFF,0xFF”表示无效。 | +| 充电电量 | 2 | WORD | 分辨率:0.1KWH,偏移量:0,有效值范围:0~ 6553.5KWH | +| 累积充电电量 | 4 | WORD | 分辨率:0.1KWH,偏移量:0,有效值范围:0~ 429496729.41KWH | +| 累积放电电量 | 4 | WORD | 分辨率:0.1KWH,偏移量:0,有效值范 围:0~ 429496729.41KWH | +| 瞬时电耗 | 2 | WORD | 分辨率:0.1KWH,偏移量:0,有效值范围:0~ 6553.5KWH | +| 电池正绝缘电阻 | 2 | WORD | 分辨率:1KΩ,偏移量:0,有效值范围:0~60000 KΩ,“FF,FF”表示无效 | +| 电池负绝缘电阻 | 2 | WORD | 分辨率:1KΩ,偏移量:0,有效值范围:0~60000 KΩ,“FF,FF”表示无效 | +| 电机控制器温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃, “FF”表示无效 | +| 空调开启模式 | 1 | BYTE | 0x00:关闭 0x01 新风 0x02 制热 0x03 制冷 0xFF 无效 | +| 空调设定温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃, “FF”表示无效 | +| 车厢内实际温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃, “FF”表示无效 | +| 车外温度 | 1 | BYTE | 分辨率:1℃,偏移量:-40,有效值范围:-40~210℃, “FF”表示无效 | +| 钥匙位置 | bit1~0 | BYTE bit | 0:OFF,1:ACC,2:ON,3:START | +| 手刹状态 | bit3~2 | BYTE bit | 0:表示无信号,1:表示有信号,2:表示 异常,3:表示无效 | +| 前门状态 | bit5~4 | BYTE bit | 0:表示无信号,1:表示 开,2:表示 异常,3:表示无效 | +| 中门状态 | bit7~6 | BYTE bit | 0:表示无信号,1:表示 开,2:表示 异常,3:表示无效 | + +#### 自定义扩展数据解析结果样例 + +```js +# 数据仅包含自定义扩展item +{ + type: "CUSTOM_EXT", + dataLen: 48, + pressure1: 0, + pressure2: 0, + batteryVoltage: 0, + dcov: -900, + dcoc: -900, + cv: 570.5, + rc: 5522.6, + cp: 0, + totalCharge: 0, + totalDischarge: 0, + bpiRes: 0, + bniRes: 0, + motorContTemp: 0, + airMode: "OFF", + airTemp: 0, + insideTemp: 0, + outsideTemp: 0, + middleDoorStatus: "CLOSE", + frontDoorStatus: "CLOSE", + handbrakeStatus: "OFF", + keyPosition: "ON", +} +``` + +#### 自定义扩展数据解析结果说明 + +| 字段 | 数据内容 | 类型 | 分辨率 | 说明 | +| :--------------- | :-------------- | :------ | :----- | :-------------------------------------------------------------------------------- | +| dataLen | 自定义数据长度 | integer | | 字节长度 | +| pressure1 | 气压 1 | integer | 4kPa | 0~1000kpa | +| pressure2 | 气压 2 | integer | 4kPa | 0~1000kpa | +| batteryVoltage | 蓄电池电压 | float | 0.5V | 0~32V | +| dcov | DCDC 输出电压 | float | 0.1V | 0~32V | +| dcoc | DCDC 输出电流 | float | 0.1A | -1000~1000A | +| dcTemp | DCDC 散热器温度 | integer | 1℃ | -40~210℃ | +| acTemp | DCAC 散热器温度 | integer | 1℃ | -40~210℃ | +| lftp | 左前轮胎压力 | integer | 4kPa | 0~1000kPa | +| lftt | 左前轮胎温度 | integer | 1℃ | -40~210℃ | +| rftp | 右前轮胎压力 | integer | 4kPa | 0~1000kPa | +| rftt | 右前轮胎温度 | integer | 1℃ | -40~210℃ | +| lr1tp | 左后 1 轮胎压力 | integer | 4kPa | 0~1000kPa | +| lr1tt | 左后 1 轮胎温度 | integer | 1℃ | -40~210℃ | +| lr2tp | 左后 2 轮胎压力 | integer | 4kPa | 0~1000kPa | +| lr2tt | 左后 2 轮胎温度 | integer | 1℃ | -40~210℃ | +| rr1tp | 右后 1 轮胎压力 | integer | 4kPa | 0~1000kPa | +| rr1tt | 右后 1 轮胎温度 | integer | 1℃ | -40~210℃ | +| rr2tp | 右后 2 轮胎压力 | integer | 4kPa | 0~1000kPa | +| rr2tt | 右后 2 轮胎温度 | integer | 1℃ | -40~210℃ | +| cv | 充电电压 | float | 0.1V | 0V ~ 1000V | +| rc | 充电电流 | float | 0.1A | -1000~1000A | +| cp | 充电电量 | float | 0.1KWH | 0~ 6553.5KWH | +| totalCharge | 累积充电电量 | float | 0.1KWH | 0~ 429496729.41KWH | +| totalDischarge | 累积放电电量 | float | 0.1KWH | 0~ 429496729.41KWH | +| instantPower | 瞬时电耗 | float | 0.1KWH | 0~ 6553.5KWH | +| bpiRes | 电池正绝缘电阻 | integer | 1KΩ | 0~60000 KΩ | +| bniRes | 电池负绝缘电阻 | integer | 1KΩ | 0~60000 KΩ | +| apTemp | 气泵扇热器温度 | integer | 1℃ | -40~210℃ | +| motorContTemp | 电机控制器温度 | integer | 1℃ | -40~210℃ | +| airMode | 空调模式 | string | | WIND: "进风", OFF: "关", REFRIGERATION: "制冷", HEATING: "制热", ABNORMAL: "异常" | +| airTemp | 空调设定温度 | integer | 1℃ | -40~210℃ | +| insideTemp | 车厢内实际温度 | integer | 1℃ | -40~210℃ | +| outsideTemp | 车外温度 | integer | 1℃ | -40~210℃ | +| middleDoorStatus | 中门状态 | string | | CLOSE: "关闭", OPEN: "开启", ABNORMAL: "异常" | +| frontDoorStatus | 前门状态 | string | | CLOSE: "关闭", OPEN: "开启", ABNORMAL: "异常" | +| handbrakeStatus | 手刹状态 | string | | ON: "开", OFF: "关", ABNORMAL: "异常" | +| keyPosition | 钥匙位置 | string | | OFF: 关, ACC: 通电, ON: 开, START: 启动 | + +--- + +### 十秒上传数据 + +0x81 TEN_SECONDS + +只通过 REISSUE_REPORT 上报 + +#### 十秒上传数据二进制样例 + +```js +0100020003000004271001000200030000042710010002000300000427100100020003000004271001000200030000042710010002000300000427100100020003000004271001000200030000042710010002000300000427100100020003000004271061; +``` + +#### 十秒上传数据二进制格式说明 + +十秒上传一共会有十组数据,连续,下面表格是其中一组的数据格式 + +| 数据内容 | 长度/字节 | 数据类型类型 | 描述 | +| :----------- | :-------- | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 0x01 | 1 | BYTE | 加速踏板标识类型 | +| 加速踏板行程 | 1 | BYTE | 有效值范围:0 ~ 100(表示 0%~ 100%),最小计量单元:1%,“0xFE”表示异常,“0xFF”表示无效。 | +| 0x02 | 1 | BYTE | 制动踏板标识类型 | +| 制动踏板 | 1 | BYTE | 有效值范围:0 ~ 100(表示 0%~ 100%),最小计量单元 1%,“0”表示制动关的状态;在无具体行程值情况下,用“0x65” 即“101”表示制动有效状态,“0xFE” 表示异常 “0xFF”标识无效 | +| 0x03 | 1 | BYTE | 车速标识类型 | +| 车速 | 2 | WORD | 有效值范围:0 ~ 2200(表示 0 km/h ~ 220 km/h),最小计量单元:0.1km/h,“0xFF,0xFE”表示异常,“0xFF,0xFF”表 示无效 | +| 0x04 | 1 | BYTE | 总电流标识类型 | +| 总电流 | 2 | WORD | 有效值范围: 0 ~ 20000(偏移量 1000A,表示-1000A ~+1000A),最小计量单元:0.1A,“0xFF,0xFE”表示异常, “0xFF,0xFF”表示无效 | + +#### 十秒上传数据解析结果样例 + +```js + { + command: "REISSUE_REPORT", + flag: "COMMAND", + vin: "LWXCS201711070000", + encrypt: "NONE", + length: 107, + body: { + at: new Date("2018-06-21T05:49:47.000Z"), + items: [ + { + type: "TEN_SECONDS", + datas: [{ + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: 0, + }, { + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: 0, + }, { + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: 0, + }, { + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: 0, + }, { + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: 0, + }, { + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: 0, + }, { + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: 0, + }, { + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: 0, + }, { + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: 0, + }, { + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: 0, + }], + }, + ], + }, +``` + +#### 十秒上传解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :----------- | :----------- | :---- | :--------------------------------------------- | +| accPedal | 加速踏板行程 | float | 0 ~ 1 (精度 0.01) 如果 > 1,表示无法获得具体值 | +| brake | 制动踏板 | float | 0 ~ 1 (精度 0.01) 如果 > 1,表示无法获得具体值 | +| speed | 车速 | float | 0km/h ~ 220km/h 0.1km/h | +| totalCurrent | 总电流 | float | -1000A ~ 1000A 0.1A | + +--- + +### 主动安全数据 + +0x82 ADAS + +只通过 REISSUE_REPORT 上报 + +#### 主动安全数据二进制样例 + +```sh +# 仅包含一组 adas 数据,实际上应该有 10 组 +0100020003000004271005000678070008f409010a010b400c000d0010 +``` + +#### 主动安全数据二进制格式说明 + +| 数据内容 | 长度/字节 | 数据类型类型 | 描述 | +| :----------------------- | :-------- | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 0x01 | 1 | BYTE | 加速踏板标识类型 | +| 加速踏板行程 | 1 | BYTE | 有效值范围:0 ~ 100(表示 0%~ 100%),最小计量单元:1%,“0xFE”表示异常,“0xFF”表示无效。 | +| 0x02 | 1 | BYTE | 制动踏板标识类型 | +| 制动踏板 | 1 | BYTE | 有效值范围:0 ~ 100(表示 0%~ 100%),最小计量单元 1%,“0”表示制动关的状态;在无具体行程值情况下,用“0x65” 即“101”表示制动有效状态,“0xFE” 表示异常 “0xFF”标识无效 | +| 0x03 | 1 | BYTE | 车速标识类型 | +| 车速 | 2 | WORD | 有效值范围:0 ~ 2200(表示 0 km/h ~ 220 km/h),最小计量单元:0.1km/h,“0xFF,0xFE”表示异常,“0xFF,0xFF”表 示无效 | +| 0x04 | 1 | BYTE | 总电流标识类型 | +| 总电流 | 2 | WORD | 有效值范围: 0 ~ 20000(偏移量 1000A,表示-1000A ~+1000A),最小计量单元:0.1A,“0xFF,0xFE”表示异常, “0xFF,0xFF”表示无效 | +| 0x05 | 1 | BYTE | 超速显示标识符 | +| 超速值 | 1 | BYTE | 范围:0-7 分辨率:5km/h,偏移量:0 | +| 0x06 | 1 | BYTE | 车辆前方障碍物相对横向距离标识 | +| 前方障碍物横向相对距离 | 1 | BYTE |  分辨率:0.1m/bit,偏移量:-12, 范围-12m~12m | +| 0x07 | 1 | BYTE | 车辆前方障碍物相对  纵向距离标识 | +| 前方障碍物相对纵向距离 | 1 | BYTE | 范围 0-250m | +| 0x08 | 1 | BYTE | 车辆前方障碍物相对  速度标识 | +| 车辆前方障碍物相对速度 | 1 | BYTE | 偏移量-50 范围-50-50(m/s) | +| 0x09 | 1 | BYTE | ADAS 系统状态 1 | +| 蜂鸣器预警 | 1 | Bit4-bit1 | 0001 有效,其他无效 | +| 方向盘震动器预警 | | Bit8-bit5 | 0001 有效,其他无效 | +| 0x0A | 1 | BYTE | ADAS 系统状态 2 | +| 前方碰撞预警 | 1 | Bit2-bit1 | 01:有,00:无 | +| 左车道偏离预警 | | Bit4-bit3 | 01:有,00:无 | +| 右车道偏离预警 | | Bit6-bit5 | 01:有,00:无 | +| 行人碰撞预警 | | Bit2-bit1 | 01:有,00:无 | +| 0x0B | 1 | BYTE | ADAS 系统状态 3 | +| 碰撞缓解制动系统预警等级 | 1 | Bit8-bit7 | 0:无效,1:一级预警;2:二级预警 | +| 碰撞缓解制动系统状态 | | Bit6-bit5 | 00:不显示,01:CMCS 关闭,10:CMCS 故障, | +| 碰撞缓解制动系统开关状态 | | Bit4-bit3 | 00:无,01:有 | +| 保留 | | Bit2-bit1 | | +| 0x0C | 1 | BYTE | 障碍物类型标识 | +| 障碍物类型 | 1 | BYTE | VOID:无,PEOPLE:人,2:VEHICLE; | +| 0x0D | 1 | Bit2-bit1 | ADAS 故障码 | +| ADAS 故障码 | 2 | BYTE | 具体含义未知 | + +#### 主动安全数据解析结果样例 + +```js +{ + type: "ADAS", + datas: [{ + accPedal: 0, + brake: 0, + speed: 0, + totalCurrent: -900, + overSpeed: 0, + lateralDistance: 0, // 前方障碍物横向距离 + verticalDistance: 0, // 前方障碍物纵向距离 + relativeVelocity: 0, // 与前方障碍物的相对速度 + wheelWarning: false, // 方向盘振动器预警 + buzzerWarning: false, // 蜂鸣器预警 + pWarning: false, // 行人碰撞预警 + rWarning: false, // 右车道偏离预警 + lWarning: false, // 左车道偏离预警 + cWarning: false, // 前方碰撞预警 + cmcs: "NORMAL", // 碰撞缓解制动系统状态 + reserved: 0, + crbs: false, // 碰撞缓解制动系统开关状态 + cmcsLevel: 0, // 碰撞缓解制动系统预警等级 + obstacleType: "VOID", // 障碍物类型 + fault: 16, +} +``` + +#### 主动安全数据解析结果说明 + +| 字段 | 数据内容 | 类型 | 说明 | +| :--------------- | :----------------------- | :---------- | :------------------------------------------------------- | +| accPedal | 加速踏板行程 | float | 0 ~ 1 (精度 0.01) 如果 > 1,表示无法获得具体值 | +| brake | 制动踏板 | float | 0 ~ 1 (精度 0.01) 如果 > 1,表示无法获得具体值 | +| speed | 车速 | float | 0km/h ~ 220km/h 0.1km/h | +| totalCurrent | 总电流 | float | -1000A ~ 1000A 0.1A | +| overSpeed | 超速值 | integer | 0 ~ 35 5km/h | +| lateralDistance | 前方障碍物横向相对距离 | float | -12M ~ 12M 0.1M 车辆左侧为负,车辆右侧为正 | +| verticalDistance | 前方障碍物相对纵向距离 | integer | 0M ~ 250M | +| relativeVelocity | 车辆前方障碍物相对速度 | integer | -50 ~ 50(m/s)1m/s | +| buzzerWarning | 蜂鸣器预警 | boolean | | +| wheelWarning | 方向盘震动器预警 | boolean | | +| cWarning | 前方碰撞预警 | boolean | | +| lWarning | 左车道偏离预警 | boolean | | +| rWarning | 右车道偏离预警 | boolean | | +| pWarning | 行人碰撞预警 | boolean | | +| cmcsLevel | 碰撞缓解制动系统预警等级 | integer | 0:无效,1:一级预警;2:二级预警 | +| cmcs | 碰撞缓解制动系统状态 | string enum | NORMAL: CMCS 正常;CLOSE: CMCS 关闭;ABNORMAL:CMSC 故障 | +| crbs | 碰撞缓解制动系统开关状态 | boolean | | +| obstacleType | 障碍物类型 | integer | VOID: 无;PEOPLE: 人;VEHICLE: 车 | +| reserved | 保留 | integer | | +| fault | ADAS 故障码 | integer | | \ No newline at end of file diff --git a/src/JTNE.Protocol.Benchmark/JTNESerializerContext.cs b/src/JTNE.Protocol.Benchmark/JTNESerializerContext.cs index 66b74ee..5f278fd 100644 --- a/src/JTNE.Protocol.Benchmark/JTNESerializerContext.cs +++ b/src/JTNE.Protocol.Benchmark/JTNESerializerContext.cs @@ -34,8 +34,8 @@ namespace JTNE.Protocol.Benchmark for (int i = 0; i < N; i++) { JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = JTNEAskId.Success.ToByteValue(); - jTNEPackage.MsgId = JTNEMsgId.uploadim.ToByteValue(); + jTNEPackage.AskId = JTNEAskId.Success; + jTNEPackage.MsgId = JTNEMsgId.UploadIM; jTNEPackage.VIN = "123456789"; JTNE_0x02 jTNE_0X02 = new JTNE_0x02(); jTNE_0X02.Values = new Dictionary(); diff --git a/src/JTNE.Protocol.Test/Extensions/JTNEPackageExtensionsTest.cs b/src/JTNE.Protocol.Test/Extensions/JTNEPackageExtensionsTest.cs index 378fae3..5b64dc1 100644 --- a/src/JTNE.Protocol.Test/Extensions/JTNEPackageExtensionsTest.cs +++ b/src/JTNE.Protocol.Test/Extensions/JTNEPackageExtensionsTest.cs @@ -13,7 +13,7 @@ namespace JTNE.Protocol.Test.Extensions [Fact] public void Test1() { - JTNEPackage jTNEPackage= JTNEMsgId.login.Create("123456789", JTNEAskId.CMD, new JTNE_0x01 + JTNEPackage jTNEPackage= JTNEMsgId.Login.Create("123456789", JTNEAskId.CMD, new JTNE_0x01 { PDATime = DateTime.Parse("2019-01-22 23:55:56"), LoginNum = 1, diff --git a/src/JTNE.Protocol.Test/JTNEHeaderPackageTest.cs b/src/JTNE.Protocol.Test/JTNEHeaderPackageTest.cs index 4ec5720..11ccbff 100644 --- a/src/JTNE.Protocol.Test/JTNEHeaderPackageTest.cs +++ b/src/JTNE.Protocol.Test/JTNEHeaderPackageTest.cs @@ -21,7 +21,7 @@ namespace JTNE.Protocol.Test { JTNEHeaderPackage jTNEHeaderPackage = new JTNEHeaderPackage (); jTNEHeaderPackage.VIN = "123456789"; jTNEHeaderPackage.AskId = JTNEAskId.CMD.ToByteValue (); - jTNEHeaderPackage.MsgId = JTNEMsgId.login.ToByteValue (); + jTNEHeaderPackage.MsgId = JTNEMsgId.Login.ToByteValue (); JTNE_0x01 jTNE_0X01 = new JTNE_0x01 (); jTNE_0X01.PDATime = DateTime.Parse ("2019-01-22 23:55:56"); jTNE_0X01.LoginNum = 1; @@ -42,7 +42,7 @@ namespace JTNE.Protocol.Test { var data = "232301FE313233343536373839000000000000000001002A130116173738000131323334353637383939383736353433323130300304313233343435363739383730FD".ToHexBytes (); JTNEHeaderPackage jTNEHeaderPackage = JTNESerializer.Deserialize (data); Assert.Equal (JTNEAskId.CMD.ToByteValue (), jTNEHeaderPackage.AskId); - Assert.Equal (JTNEMsgId.login.ToByteValue (), jTNEHeaderPackage.MsgId); + Assert.Equal (JTNEMsgId.Login.ToByteValue (), jTNEHeaderPackage.MsgId); Assert.Equal ("123456789", jTNEHeaderPackage.VIN); JTNE_0x01 jTNE_0X01 = JTNESerializer.Deserialize (jTNEHeaderPackage.Bodies); Assert.Equal (DateTime.Parse ("2019-01-22 23:55:56"), jTNE_0X01.PDATime); @@ -60,8 +60,8 @@ namespace JTNE.Protocol.Test { JTNEGlobalConfigs.Instance.Encoding = Encoding.GetEncoding ("GB18030"); var data = "23 23 05 FE 30 30 30 30 30 30 30 30 30 30 30 30 30 32 31 31 31 01 00 29 14 07 14 13 26 22 00 01 CD FE BA A3 B9 E3 CC A9 BF D5 B8 DB CD FE BA A3 B9 E3 CC A9 BF D5 B8 DB B3 B5 C1 AA CD F2 01 02 01 A1".ToHexBytes (); var package = JTNESerializer.Deserialize (data); - Assert.Equal (JTNEAskId.CMD.ToByteValue (), package.AskId); - Assert.Equal (JTNEMsgId.platformlogin.ToByteValue (), package.MsgId); + Assert.Equal (JTNEAskId.CMD, package.AskId); + Assert.Equal (JTNEMsgId.PlatformLogin, package.MsgId); Assert.Equal (41, package.DataUnitLength); Assert.NotNull (package.Bodies); @@ -75,5 +75,29 @@ namespace JTNE.Protocol.Test { Assert.Equal (JTNEEncryptMethod.None, loginbody.EncryptMethod); } + + [Fact] + public void TestGenerateReply(){ + JTNEGlobalConfigs.Instance.Encoding = Encoding.GetEncoding ("GB18030"); + var data = "23 23 05 FE 30 30 30 30 30 30 30 30 30 30 30 30 30 32 31 31 31 01 00 29 14 07 14 13 26 22 00 01 CD FE BA A3 B9 E3 CC A9 BF D5 B8 DB CD FE BA A3 B9 E3 CC A9 BF D5 B8 DB B3 B5 C1 AA CD F2 01 02 01 A1".ToHexBytes (); + var package = JTNESerializer.Deserialize (data); + var reply = package.GenerateReply(JTNEAskId.Success); + Assert.NotNull(reply); + var bytes = JTNESerializer.Serialize(reply); + output.WriteLine(bytes.ToHexString()); + + } + } + + public static class JTNEReplyExtensions{ + + public static JTNEPackage GenerateReply(this JTNEPackage source,JTNEAskId askId){ + return new JTNEPackage(){ + MsgId = source.MsgId, + AskId = askId, + VIN = source.VIN, + DataUnitLength = 0 + }; + } } } \ No newline at end of file diff --git a/src/JTNE.Protocol.Test/Package/JTNE_0x01_PackageTest.cs b/src/JTNE.Protocol.Test/Package/JTNE_0x01_PackageTest.cs index 04736e6..27fb99d 100644 --- a/src/JTNE.Protocol.Test/Package/JTNE_0x01_PackageTest.cs +++ b/src/JTNE.Protocol.Test/Package/JTNE_0x01_PackageTest.cs @@ -15,8 +15,8 @@ namespace JTNE.Protocol.Test.Package public void Test1() { JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = JTNEAskId.CMD.ToByteValue(); - jTNEPackage.MsgId = JTNEMsgId.login.ToByteValue(); + jTNEPackage.AskId = JTNEAskId.CMD; + jTNEPackage.MsgId = JTNEMsgId.Login; jTNEPackage.VIN = "123456789"; JTNE_0x01 jTNE_0X01 = new JTNE_0x01(); jTNE_0X01.PDATime = DateTime.Parse("2019-01-22 23:55:56"); @@ -39,8 +39,8 @@ namespace JTNE.Protocol.Test.Package { var data = "232301FE313233343536373839000000000000000001002A130116173738000131323334353637383939383736353433323130300304313233343435363739383730FD".ToHexBytes(); JTNEPackage jTNEPackage = JTNESerializer.Deserialize(data); - Assert.Equal(JTNEAskId.CMD.ToByteValue(), jTNEPackage.AskId); - Assert.Equal(JTNEMsgId.login.ToByteValue(), jTNEPackage.MsgId); + Assert.Equal(JTNEAskId.CMD, jTNEPackage.AskId); + Assert.Equal(JTNEMsgId.Login, jTNEPackage.MsgId); Assert.Equal("123456789", jTNEPackage.VIN); JTNE_0x01 jTNE_0X01 = jTNEPackage.Bodies as JTNE_0x01; @@ -68,8 +68,8 @@ namespace JTNE.Protocol.Test.Package } }); JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = JTNEAskId.CMD.ToByteValue(); - jTNEPackage.MsgId = JTNEMsgId.login.ToByteValue(); + jTNEPackage.AskId = JTNEAskId.CMD; + jTNEPackage.MsgId = JTNEMsgId.Login; jTNEPackage.VIN = "123456789"; jTNEPackage.EncryptMethod = JTNEEncryptMethod.AES128; JTNE_0x01 jTNE_0X01 = new JTNE_0x01(); @@ -103,8 +103,8 @@ namespace JTNE.Protocol.Test.Package }); var data = "232301FE31323334353637383900000000000000000300307C9AAF67FB9408A75FAFC1C87F1E2AECD79DDAB8219016A5DD0911283922805EF450045EA3611C0D5CFBFD8F2581CEED30".ToHexBytes(); JTNEPackage jTNEPackage = JTNESerializer.Deserialize(data); - Assert.Equal(JTNEAskId.CMD.ToByteValue(), jTNEPackage.AskId); - Assert.Equal(JTNEMsgId.login.ToByteValue(), jTNEPackage.MsgId); + Assert.Equal(JTNEAskId.CMD, jTNEPackage.AskId); + Assert.Equal(JTNEMsgId.Login, jTNEPackage.MsgId); Assert.Equal("123456789", jTNEPackage.VIN); Assert.Equal(JTNEEncryptMethod.AES128, jTNEPackage.EncryptMethod); diff --git a/src/JTNE.Protocol.Test/Package/JTNE_0x02_PackageTest.cs b/src/JTNE.Protocol.Test/Package/JTNE_0x02_PackageTest.cs index 8ba535b..5dd8cda 100644 --- a/src/JTNE.Protocol.Test/Package/JTNE_0x02_PackageTest.cs +++ b/src/JTNE.Protocol.Test/Package/JTNE_0x02_PackageTest.cs @@ -15,8 +15,8 @@ namespace JTNE.Protocol.Test.Package public void Test1() { JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = JTNEAskId.Success.ToByteValue(); - jTNEPackage.MsgId = JTNEMsgId.uploadim.ToByteValue(); + jTNEPackage.AskId = JTNEAskId.Success; + jTNEPackage.MsgId = JTNEMsgId.UploadIM; jTNEPackage.VIN = "123456789"; JTNE_0x02 jTNE_0X02 = new JTNE_0x02(); jTNE_0X02.Values = new Dictionary(); diff --git a/src/JTNE.Protocol.Test/Package/JTNE_0x04_PackageTest.cs b/src/JTNE.Protocol.Test/Package/JTNE_0x04_PackageTest.cs index 104e8b6..a3cc0a9 100644 --- a/src/JTNE.Protocol.Test/Package/JTNE_0x04_PackageTest.cs +++ b/src/JTNE.Protocol.Test/Package/JTNE_0x04_PackageTest.cs @@ -14,8 +14,8 @@ namespace JTNE.Protocol.Test.Package public void Test1() { JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = JTNEAskId.CMD.ToByteValue(); - jTNEPackage.MsgId = JTNEMsgId.loginout.ToByteValue(); + jTNEPackage.AskId = JTNEAskId.CMD; + jTNEPackage.MsgId = JTNEMsgId.Logout; jTNEPackage.VIN = "123456789"; JTNE_0x04 jTNE_0X04 = new JTNE_0x04(); jTNE_0X04.LogoutTime = DateTime.Parse("2019-01-23 23:55:56"); @@ -30,8 +30,8 @@ namespace JTNE.Protocol.Test.Package { var data = "232304FE31323334353637383900000000000000000100081301171737380001DE".ToHexBytes(); JTNEPackage jTNEPackage = JTNESerializer.Deserialize(data); - Assert.Equal(JTNEAskId.CMD.ToByteValue(), jTNEPackage.AskId); - Assert.Equal(JTNEMsgId.loginout.ToByteValue(), jTNEPackage.MsgId); + Assert.Equal(JTNEAskId.CMD, jTNEPackage.AskId); + Assert.Equal(JTNEMsgId.Logout, jTNEPackage.MsgId); Assert.Equal("123456789", jTNEPackage.VIN); JTNE_0x04 jTNE_0X04 = jTNEPackage.Bodies as JTNE_0x04; Assert.Equal(DateTime.Parse("2019-01-23 23:55:56"), jTNE_0X04.LogoutTime); diff --git a/src/JTNE.Protocol.Test/Package/JTNE_0x05_PackageTest.cs b/src/JTNE.Protocol.Test/Package/JTNE_0x05_PackageTest.cs index 2c42291..79d02c5 100644 --- a/src/JTNE.Protocol.Test/Package/JTNE_0x05_PackageTest.cs +++ b/src/JTNE.Protocol.Test/Package/JTNE_0x05_PackageTest.cs @@ -11,8 +11,8 @@ namespace JTNE.Protocol.Test.Package { [Fact] public void Test1 () { JTNEPackage jTNEPackage = new JTNEPackage (); - jTNEPackage.AskId = JTNEAskId.CMD.ToByteValue (); - jTNEPackage.MsgId = JTNEMsgId.platformlogin.ToByteValue (); + jTNEPackage.AskId = JTNEAskId.CMD; + jTNEPackage.MsgId = JTNEMsgId.PlatformLogin; jTNEPackage.VIN = "123456789"; JTNE_0x05 jTNE_0X05 = new JTNE_0x05 (); jTNE_0X05.LoginTime = DateTime.Parse ("2019-01-23 23:55:56"); @@ -28,8 +28,8 @@ namespace JTNE.Protocol.Test.Package { public void Test2 () { var data = "232305FE31323334353637383900000000000000000100291301171737381A0A536D616C6C43686935313800313233343536373839303132333435363738390001FF".ToHexBytes (); JTNEPackage jTNEPackage = JTNESerializer.Deserialize (data); - Assert.Equal (JTNEAskId.CMD.ToByteValue (), jTNEPackage.AskId); - Assert.Equal (JTNEMsgId.platformlogin.ToByteValue (), jTNEPackage.MsgId); + Assert.Equal (JTNEAskId.CMD, jTNEPackage.AskId); + Assert.Equal (JTNEMsgId.PlatformLogin, jTNEPackage.MsgId); Assert.Equal ("123456789", jTNEPackage.VIN); JTNE_0x05 jTNE_0X05 = jTNEPackage.Bodies as JTNE_0x05; Assert.Equal (DateTime.Parse ("2019-01-23 23:55:56"), jTNE_0X05.LoginTime); diff --git a/src/JTNE.Protocol.Test/Package/JTNE_0x06_PackageTest.cs b/src/JTNE.Protocol.Test/Package/JTNE_0x06_PackageTest.cs index 28a0c79..f490ce1 100644 --- a/src/JTNE.Protocol.Test/Package/JTNE_0x06_PackageTest.cs +++ b/src/JTNE.Protocol.Test/Package/JTNE_0x06_PackageTest.cs @@ -14,8 +14,8 @@ namespace JTNE.Protocol.Test.Package public void Test1() { JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = JTNEAskId.CMD.ToByteValue(); - jTNEPackage.MsgId = JTNEMsgId.platformlogout.ToByteValue(); + jTNEPackage.AskId = JTNEAskId.CMD; + jTNEPackage.MsgId = JTNEMsgId.PlatformLogout; jTNEPackage.VIN = "123456789"; JTNE_0x06 jTNE_0X06 = new JTNE_0x06(); jTNE_0X06.LogoutTime = DateTime.Parse("2019-01-23 23:55:56"); @@ -30,8 +30,8 @@ namespace JTNE.Protocol.Test.Package { var data = "232306FE31323334353637383900000000000000000100081301171737380001DC".ToHexBytes(); JTNEPackage jTNEPackage = JTNESerializer.Deserialize(data); - Assert.Equal(JTNEAskId.CMD.ToByteValue(), jTNEPackage.AskId); - Assert.Equal(JTNEMsgId.platformlogout.ToByteValue(), jTNEPackage.MsgId); + Assert.Equal(JTNEAskId.CMD, jTNEPackage.AskId); + Assert.Equal(JTNEMsgId.PlatformLogout, jTNEPackage.MsgId); Assert.Equal("123456789", jTNEPackage.VIN); JTNE_0x06 jTNE_0X06 = jTNEPackage.Bodies as JTNE_0x06; Assert.Equal(DateTime.Parse("2019-01-23 23:55:56"), jTNE_0X06.LogoutTime); diff --git a/src/JTNE.Protocol.Test/Package/JTNE_0x07_PackageTest.cs b/src/JTNE.Protocol.Test/Package/JTNE_0x07_PackageTest.cs index 61211a4..5fe3f01 100644 --- a/src/JTNE.Protocol.Test/Package/JTNE_0x07_PackageTest.cs +++ b/src/JTNE.Protocol.Test/Package/JTNE_0x07_PackageTest.cs @@ -14,8 +14,8 @@ namespace JTNE.Protocol.Test.Package public void Test1() { JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = JTNEAskId.CMD.ToByteValue(); - jTNEPackage.MsgId = JTNEMsgId.heartbeat.ToByteValue(); + jTNEPackage.AskId = JTNEAskId.CMD; + jTNEPackage.MsgId = JTNEMsgId.HeartBeat; jTNEPackage.VIN = "123456789"; var hex = JTNESerializer.Serialize(jTNEPackage).ToHexString(); Assert.Equal("232307FE3132333435363738390000000000000000010000C9", hex); @@ -26,8 +26,8 @@ namespace JTNE.Protocol.Test.Package { var data = "232307FE3132333435363738390000000000000000010000C9".ToHexBytes(); JTNEPackage jTNEPackage = JTNESerializer.Deserialize(data); - Assert.Equal(JTNEAskId.CMD.ToByteValue(), jTNEPackage.AskId); - Assert.Equal(JTNEMsgId.heartbeat.ToByteValue(), jTNEPackage.MsgId); + Assert.Equal(JTNEAskId.CMD, jTNEPackage.AskId); + Assert.Equal(JTNEMsgId.HeartBeat, jTNEPackage.MsgId); Assert.Equal("123456789", jTNEPackage.VIN); Assert.Null(jTNEPackage.Bodies); } diff --git a/src/JTNE.Protocol.Test/Package/JTNE_0x08_PackageTest.cs b/src/JTNE.Protocol.Test/Package/JTNE_0x08_PackageTest.cs index c460e15..c075262 100644 --- a/src/JTNE.Protocol.Test/Package/JTNE_0x08_PackageTest.cs +++ b/src/JTNE.Protocol.Test/Package/JTNE_0x08_PackageTest.cs @@ -14,8 +14,8 @@ namespace JTNE.Protocol.Test.Package public void Test1() { JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = JTNEAskId.CMD.ToByteValue(); - jTNEPackage.MsgId = JTNEMsgId.checktime.ToByteValue(); + jTNEPackage.AskId = JTNEAskId.CMD; + jTNEPackage.MsgId = JTNEMsgId.CheckTime; jTNEPackage.VIN = "123456789"; var hex = JTNESerializer.Serialize(jTNEPackage).ToHexString(); Assert.Equal("232308FE3132333435363738390000000000000000010000C6", hex); @@ -26,8 +26,8 @@ namespace JTNE.Protocol.Test.Package { var data = "232308FE3132333435363738390000000000000000010000C6".ToHexBytes(); JTNEPackage jTNEPackage = JTNESerializer.Deserialize(data); - Assert.Equal(JTNEAskId.CMD.ToByteValue(), jTNEPackage.AskId); - Assert.Equal(JTNEMsgId.checktime.ToByteValue(), jTNEPackage.MsgId); + Assert.Equal(JTNEAskId.CMD, jTNEPackage.AskId); + Assert.Equal(JTNEMsgId.CheckTime, jTNEPackage.MsgId); Assert.Equal("123456789", jTNEPackage.VIN); Assert.Null(jTNEPackage.Bodies); } diff --git a/src/JTNE.Protocol/Enums/JTNEAskId.cs b/src/JTNE.Protocol/Enums/JTNEAskId.cs index 83972a5..7ada9a4 100644 --- a/src/JTNE.Protocol/Enums/JTNEAskId.cs +++ b/src/JTNE.Protocol/Enums/JTNEAskId.cs @@ -1,29 +1,23 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JTNE.Protocol.Enums -{ +namespace JTNE.Protocol.Enums { /// /// 应答标志 /// - public enum JTNEAskId:byte - { + public enum JTNEAskId : byte { /// /// 接收到的信息正确 /// - Success=0x01, + Success = 0x01, /// /// 设置未成功 /// - Error=0x02, + Error = 0x02, /// /// VIN重复错误 /// - VinRepeatError=0x03, + VinRepeatError = 0x03, /// /// 数据包为命令包,而非应答包 /// - CMD=0xFE + CMD = 0xFE } -} +} \ No newline at end of file diff --git a/src/JTNE.Protocol/Enums/JTNEMsgId.cs b/src/JTNE.Protocol/Enums/JTNEMsgId.cs index a242f88..d8bf546 100644 --- a/src/JTNE.Protocol/Enums/JTNEMsgId.cs +++ b/src/JTNE.Protocol/Enums/JTNEMsgId.cs @@ -1,66 +1,64 @@ -using JTNE.Protocol.Attributes; -using JTNE.Protocol.MessageBody; -using System; +using System; using System.Collections.Generic; using System.Text; +using JTNE.Protocol.Attributes; +using JTNE.Protocol.MessageBody; -namespace JTNE.Protocol.Enums -{ +namespace JTNE.Protocol.Enums { /// /// 命令单元 /// - public enum JTNEMsgId:byte - { + public enum JTNEMsgId : byte { /// /// 车辆登入 /// - [JTNEBodiesType(typeof(JTNE_0x01))] - login = 0x01, + [JTNEBodiesType (typeof (JTNE_0x01))] + Login = 0x01, /// /// 实时信息上传 /// - [JTNEBodiesType(typeof(JTNE_0x02))] - uploadim = 0x02, + [JTNEBodiesType (typeof (JTNE_0x02))] + UploadIM = 0x02, /// /// 补传信息上传 /// - uploadsup = 0x03, + UploadSup = 0x03, /// /// 车辆登出 /// - [JTNEBodiesType(typeof(JTNE_0x04))] - loginout = 0x04, + [JTNEBodiesType (typeof (JTNE_0x04))] + Logout = 0x04, /// /// 平台登入 /// - [JTNEBodiesType(typeof(JTNE_0x05))] - platformlogin = 0x05, + [JTNEBodiesType (typeof (JTNE_0x05))] + PlatformLogin = 0x05, /// /// 平台登出 /// - [JTNEBodiesType(typeof(JTNE_0x06))] - platformlogout = 0x06, + [JTNEBodiesType (typeof (JTNE_0x06))] + PlatformLogout = 0x06, /// - /// 心跳 + /// 心跳包 /// - [JTNEBodiesType(typeof(JTNE_0x07))] - heartbeat = 0x07, + [JTNEBodiesType (typeof (JTNE_0x07))] + HeartBeat = 0x07, /// /// 终端校时 /// - [JTNEBodiesType(typeof(JTNE_0x08))] - checktime = 0x08, + [JTNEBodiesType (typeof (JTNE_0x08))] + CheckTime = 0x08, /// /// 查询命令 /// - query = 0x80, + Query = 0x80, /// /// 设置命令 /// - settings = 0x81, + Settings = 0x81, /// /// 控制命令 /// - control = 0x82 + Control = 0x82 } -} +} \ No newline at end of file diff --git a/src/JTNE.Protocol/Extensions/JTNEEnumExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEEnumExtensions.cs index 26fab03..48b6ff4 100644 --- a/src/JTNE.Protocol/Extensions/JTNEEnumExtensions.cs +++ b/src/JTNE.Protocol/Extensions/JTNEEnumExtensions.cs @@ -4,22 +4,19 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -namespace JTNE.Protocol.Extensions -{ +namespace JTNE.Protocol.Extensions { /// /// 枚举扩展 /// - public static class JT808EnumExtensions - { + public static class JT808EnumExtensions { /// /// 转为整型 /// /// /// /// - public static int ToValue(this T t) where T : struct - { - return Convert.ToInt32(t); + public static int ToValue (this T t) where T : struct { + return Convert.ToInt32 (t); } /// @@ -28,9 +25,8 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static ushort ToUInt16Value(this T t) where T : struct - { - return Convert.ToUInt16(t); + public static ushort ToUInt16Value (this T t) where T : struct { + return Convert.ToUInt16 (t); } /// @@ -39,9 +35,8 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static byte ToByteValue(this T t) where T : struct - { - return Convert.ToByte(t); + public static byte ToByteValue (this T t) where T : struct { + return Convert.ToByte (t); } /// @@ -50,9 +45,8 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static string ToValueString(this T t) where T : struct - { - return Convert.ToInt32(t).ToString(); + public static string ToValueString (this T t) where T : struct { + return Convert.ToInt32 (t).ToString (); } /// @@ -61,18 +55,16 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static T ToEnum(this string value) where T : struct - { - return (T)Enum.Parse(typeof(T), value); + public static T ToEnum (this string value) where T : struct { + return (T) Enum.Parse (typeof (T), value); } /// /// 获取枚举字符串 /// /// - public static string GetName(this Enum valueEnum) - { - return valueEnum.ToString(); + public static string GetName (this Enum valueEnum) { + return valueEnum.ToString (); } /// @@ -80,10 +72,9 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static string GetDescription(this Enum value) - { - var attribute = value.GetAttribute(); - return attribute == null ? value.ToString() : attribute.Description; + public static string GetDescription (this Enum value) { + var attribute = value.GetAttribute (); + return attribute == null ? value.ToString () : attribute.Description; } /// @@ -92,24 +83,21 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static bool IsEnumValid(this int enumValue) - { - return Enum.IsDefined(typeof(TEnum), enumValue); + public static bool IsEnumValid (this int enumValue) { + return Enum.IsDefined (typeof (TEnum), enumValue); } /// /// 获取DescriptionAttribute特性枚举及描述 /// - /// + /// /// - public static Dictionary GetDescriptionAttributeDictionary(this Enum value) - { - Dictionary dictionary = new Dictionary(); - var fields = value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public); - foreach (var fi in fields) - { - DescriptionAttribute attr = Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute), false) as DescriptionAttribute; - dictionary.Add(fi.Name, attr != null ? attr.Description : ""); + public static Dictionary GetDescriptionAttributeDictionary (this Enum value) { + Dictionary dictionary = new Dictionary (); + var fields = value.GetType ().GetFields (BindingFlags.Static | BindingFlags.Public); + foreach (var fi in fields) { + DescriptionAttribute attr = Attribute.GetCustomAttribute (fi, typeof (DescriptionAttribute), false) as DescriptionAttribute; + dictionary.Add (fi.Name, attr != null ? attr.Description : ""); } return dictionary; } @@ -117,27 +105,24 @@ namespace JTNE.Protocol.Extensions /// /// 获取DisplayNameAttribute特性枚举值的描述 /// - /// 枚举值 + /// 枚举值 /// - public static string GetDisplayName(this Enum value) - { - var attribute = value.GetAttribute(); - return attribute == null ? value.ToString() : attribute.DisplayName; + public static string GetDisplayName (this Enum value) { + var attribute = value.GetAttribute (); + return attribute == null ? value.ToString () : attribute.DisplayName; } /// /// 获取DisplayNameAttribute特性枚举及描述 /// - /// + /// /// - public static Dictionary GetDisplayNameAttributeDictionary(this Enum value) - { - Dictionary dictionary = new Dictionary(); - var fields = value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public); - foreach (var fi in fields) - { - DisplayNameAttribute attr = Attribute.GetCustomAttribute(fi, typeof(DisplayNameAttribute), false) as DisplayNameAttribute; - dictionary.Add(fi.Name, attr != null ? attr.DisplayName : ""); + public static Dictionary GetDisplayNameAttributeDictionary (this Enum value) { + Dictionary dictionary = new Dictionary (); + var fields = value.GetType ().GetFields (BindingFlags.Static | BindingFlags.Public); + foreach (var fi in fields) { + DisplayNameAttribute attr = Attribute.GetCustomAttribute (fi, typeof (DisplayNameAttribute), false) as DisplayNameAttribute; + dictionary.Add (fi.Name, attr != null ? attr.DisplayName : ""); } return dictionary; } @@ -148,17 +133,13 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static T GetAttribute(this Enum value) where T : Attribute - { - try - { - var type = value.GetType(); - var memberInfo = type.GetMember(value.ToString()); - var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false); - return (T)attributes[0]; - } - catch - { + public static T GetAttribute (this Enum value) where T : Attribute { + try { + var type = value.GetType (); + var memberInfo = type.GetMember (value.ToString ()); + var attributes = memberInfo[0].GetCustomAttributes (typeof (T), false); + return (T) attributes[0]; + } catch { return default; } } @@ -171,37 +152,29 @@ namespace JTNE.Protocol.Extensions /// 位数(8,16,32) /// 是否忽略未知数据 /// - public static IEnumerable GetEnumTypes(this int value, int digit, bool ignoreUnknown=false) where T : Enum - { - List values = new List(); - for (int i = 0; i < digit; i++) - { - if (Math.Pow(2, i) <= value) continue; - values.Add((T)Enum.ToObject(typeof(T), (int)Math.Pow(2, i - 1))); - value = value - (int)Math.Pow(2, i - 1); + public static IEnumerable GetEnumTypes (this int value, int digit, bool ignoreUnknown = false) where T : Enum { + List values = new List (); + for (int i = 0; i < digit; i++) { + if (Math.Pow (2, i) <= value) continue; + values.Add ((T) Enum.ToObject (typeof (T), (int) Math.Pow (2, i - 1))); + value = value - (int) Math.Pow (2, i - 1); i = 0; if (value <= 0) break; } - if (ignoreUnknown) - { - List results = new List(); - foreach (var item in values) - { - foreach (string itemChild in Enum.GetNames(typeof(T))) - { - if (item.ToString() == itemChild) - { - results.Add(item); + if (ignoreUnknown) { + List results = new List (); + foreach (var item in values) { + foreach (string itemChild in Enum.GetNames (typeof (T))) { + if (item.ToString () == itemChild) { + results.Add (item); break; } } } return results; - } - else - { + } else { return values; } } } -} +} \ No newline at end of file diff --git a/src/JTNE.Protocol/Extensions/JTNEPackageExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEPackageExtensions.cs index 080f3d4..f63f94e 100644 --- a/src/JTNE.Protocol/Extensions/JTNEPackageExtensions.cs +++ b/src/JTNE.Protocol/Extensions/JTNEPackageExtensions.cs @@ -1,15 +1,13 @@ -using JTNE.Protocol.Enums; -using System; +using System; using System.Collections.Generic; using System.Text; +using JTNE.Protocol.Enums; -namespace JTNE.Protocol.Extensions -{ +namespace JTNE.Protocol.Extensions { /// /// /// - public static class JTNEPackageExtensions - { + public static class JTNEPackageExtensions { /// /// /// @@ -19,12 +17,11 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static JTNEPackage Create(this JTNEMsgId msgId,string vin, JTNEAskId askId, TJTNEBodies bodies) - where TJTNEBodies : JTNEBodies - { - JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = askId.ToByteValue(); - jTNEPackage.MsgId = msgId.ToByteValue(); + public static JTNEPackage Create (this JTNEMsgId msgId, string vin, JTNEAskId askId, TJTNEBodies bodies) + where TJTNEBodies : JTNEBodies { + JTNEPackage jTNEPackage = new JTNEPackage (); + jTNEPackage.AskId = askId; + jTNEPackage.MsgId = msgId; jTNEPackage.Bodies = bodies; jTNEPackage.VIN = vin; return jTNEPackage; @@ -37,11 +34,10 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static JTNEPackage Create(this JTNEMsgId msgId, string vin, JTNEAskId askId) - { - JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = askId.ToByteValue(); - jTNEPackage.MsgId = msgId.ToByteValue(); + public static JTNEPackage Create (this JTNEMsgId msgId, string vin, JTNEAskId askId) { + JTNEPackage jTNEPackage = new JTNEPackage (); + jTNEPackage.AskId = askId; + jTNEPackage.MsgId = msgId; jTNEPackage.VIN = vin; return jTNEPackage; } @@ -55,12 +51,11 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static JTNEPackage CreateCustomMsgId(this byte msgId, string vin, JTNEAskId askId, TJTNEBodies bodies) - where TJTNEBodies : JTNEBodies - { - JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = askId.ToByteValue(); - jTNEPackage.MsgId = msgId; + public static JTNEPackage CreateCustomMsgId (this byte msgId, string vin, JTNEAskId askId, TJTNEBodies bodies) + where TJTNEBodies : JTNEBodies { + JTNEPackage jTNEPackage = new JTNEPackage (); + jTNEPackage.AskId = askId; + jTNEPackage.MsgId = (JTNEMsgId) msgId; jTNEPackage.Bodies = bodies; jTNEPackage.VIN = vin; return jTNEPackage; @@ -73,13 +68,12 @@ namespace JTNE.Protocol.Extensions /// /// /// - public static JTNEPackage CreateCustomMsgId(this byte msgId, string vin, JTNEAskId askId) - { - JTNEPackage jTNEPackage = new JTNEPackage(); - jTNEPackage.AskId = askId.ToByteValue(); - jTNEPackage.MsgId = msgId; + public static JTNEPackage CreateCustomMsgId (this byte msgId, string vin, JTNEAskId askId) { + JTNEPackage jTNEPackage = new JTNEPackage (); + jTNEPackage.AskId = askId; + jTNEPackage.MsgId = (JTNEMsgId) msgId; jTNEPackage.VIN = vin; return jTNEPackage; } } -} +} \ No newline at end of file diff --git a/src/JTNE.Protocol/Formatters/JTNEPackageFormatter.cs b/src/JTNE.Protocol/Formatters/JTNEPackageFormatter.cs index 8f73403..3b39944 100644 --- a/src/JTNE.Protocol/Formatters/JTNEPackageFormatter.cs +++ b/src/JTNE.Protocol/Formatters/JTNEPackageFormatter.cs @@ -26,9 +26,9 @@ namespace JTNE.Protocol.Formatters { JTNEPackage jTNEPackage = new JTNEPackage (); offset += 2; // 3.命令标识 - jTNEPackage.MsgId = JTNEBinaryExtensions.ReadByteLittle (bytes, ref offset); + jTNEPackage.MsgId = (JTNEMsgId)JTNEBinaryExtensions.ReadByteLittle (bytes, ref offset); // 4.应答标识 - jTNEPackage.AskId = JTNEBinaryExtensions.ReadByteLittle (bytes, ref offset); + jTNEPackage.AskId = (JTNEAskId)JTNEBinaryExtensions.ReadByteLittle (bytes, ref offset); // 5.VIN jTNEPackage.VIN = JTNEBinaryExtensions.ReadStringLittle (bytes, ref offset, 17); // 6.数据加密方式 @@ -39,7 +39,7 @@ namespace JTNE.Protocol.Formatters { // 8.1.根据数据加密方式进行解码 // 8.2.解析出对应数据体 if (jTNEPackage.DataUnitLength > 0) { - Type jTNEBodiesImplType = JTNEMsgIdFactory.GetBodiesImplTypeByMsgId (jTNEPackage.MsgId); + Type jTNEBodiesImplType = JTNEMsgIdFactory.GetBodiesImplTypeByMsgId ((byte)jTNEPackage.MsgId); if (jTNEBodiesImplType != null) { int bodyReadSize = 0; try { @@ -76,9 +76,9 @@ namespace JTNE.Protocol.Formatters { // 2.起始符2 offset += JTNEBinaryExtensions.WriteByteLittle (bytes, offset, value.BeginFlag2); // 3.命令标识 - offset += JTNEBinaryExtensions.WriteByteLittle (bytes, offset, value.MsgId); + offset += JTNEBinaryExtensions.WriteByteLittle (bytes, offset, (byte)value.MsgId); // 4.应答标识 - offset += JTNEBinaryExtensions.WriteByteLittle (bytes, offset, value.AskId); + offset += JTNEBinaryExtensions.WriteByteLittle (bytes, offset, (byte)value.AskId); // 5.VIN offset += JTNEBinaryExtensions.WriteStringPadRightLittle (bytes, offset, value.VIN, 17); // 6.数据加密方式 @@ -86,7 +86,7 @@ namespace JTNE.Protocol.Formatters { // 7.记录当前偏移量 int tmpOffset = offset; // 8.数据体 - Type jTNEBodiesImplType = JTNEMsgIdFactory.GetBodiesImplTypeByMsgId (value.MsgId); + Type jTNEBodiesImplType = JTNEMsgIdFactory.GetBodiesImplTypeByMsgId ((byte)value.MsgId); int messageBodyOffset = 0; if (jTNEBodiesImplType != null) { if (value.Bodies != null) { diff --git a/src/JTNE.Protocol/Internal/JTNEMsgIdFactory.cs b/src/JTNE.Protocol/Internal/JTNEMsgIdFactory.cs index 24892a2..620cece 100644 --- a/src/JTNE.Protocol/Internal/JTNEMsgIdFactory.cs +++ b/src/JTNE.Protocol/Internal/JTNEMsgIdFactory.cs @@ -1,48 +1,39 @@ -using JTNE.Protocol.Attributes; -using JTNE.Protocol.Enums; -using JTNE.Protocol.Extensions; -using System; +using System; using System.Collections.Generic; using System.Text; +using JTNE.Protocol.Attributes; +using JTNE.Protocol.Enums; +using JTNE.Protocol.Extensions; -namespace JTNE.Protocol.Internal -{ - internal static class JTNEMsgIdFactory - { - private static readonly Dictionary map; +namespace JTNE.Protocol.Internal { + internal static class JTNEMsgIdFactory { + private static readonly Dictionary map = new Dictionary (); - static JTNEMsgIdFactory() - { - map = new Dictionary(); - InitMap(); + static JTNEMsgIdFactory () { + InitMap (); } - internal static Type GetBodiesImplTypeByMsgId(byte msgId) =>map.TryGetValue(msgId, out Type type) ? type : null; + internal static Type GetBodiesImplTypeByMsgId (byte msgId) => map.TryGetValue (msgId, out Type type) ? type : null; - private static void InitMap() - { - foreach(var item in Enum.GetNames(typeof(JTNEMsgId))) - { - JTNEMsgId msgId = item.ToEnum(); - JTNEBodiesTypeAttribute jT808BodiesTypeAttribute = msgId.GetAttribute(); - map.Add((byte)msgId, jT808BodiesTypeAttribute?.JT808BodiesType); - } + private static void InitMap () { + foreach (JTNEMsgId msgId in Enum.GetValues (typeof (JTNEMsgId))) { + JTNEBodiesTypeAttribute jT808BodiesTypeAttribute = msgId.GetAttribute (); + map.Add ((byte) msgId, jT808BodiesTypeAttribute?.JT808BodiesType); + } } - internal static void SetMap(byte msgId) - where TJTNEBodies : JTNEBodies - { - if(!map.ContainsKey(msgId)) - map.Add(msgId, typeof(TJTNEBodies)); + internal static void SetMap (byte msgId) + where TJTNEBodies : JTNEBodies { + if (!map.ContainsKey (msgId)) + map.Add (msgId, typeof (TJTNEBodies)); } - internal static void ReplaceMap(byte msgId) - where TJTNEBodies : JTNEBodies - { - if (!map.ContainsKey(msgId)) - map.Add(msgId, typeof(TJTNEBodies)); + internal static void ReplaceMap (byte msgId) + where TJTNEBodies : JTNEBodies { + if (!map.ContainsKey (msgId)) + map.Add (msgId, typeof (TJTNEBodies)); else - map[msgId] = typeof(TJTNEBodies); + map[msgId] = typeof (TJTNEBodies); } } -} +} \ No newline at end of file diff --git a/src/JTNE.Protocol/JTNEGlobalConfigs.cs b/src/JTNE.Protocol/JTNEGlobalConfigs.cs index 6f45257..95b06a2 100644 --- a/src/JTNE.Protocol/JTNEGlobalConfigs.cs +++ b/src/JTNE.Protocol/JTNEGlobalConfigs.cs @@ -21,9 +21,9 @@ namespace JTNE.Protocol { } /// - /// 字符串编码,默认 GB18030 + /// 字符串编码 /// - public Encoding Encoding { get; set;} + public Encoding Encoding { get; set; } /// /// @@ -41,35 +41,40 @@ namespace JTNE.Protocol { /// 平台流水号 /// public IPlatformMsgSNDistributed PlatformMsgSNDistributed { get; private set; } + /// /// 跳过校验码 /// 测试的时候需要手动修改值,避免验证 /// 默认:false /// public bool SkipCRCCode { get; private set; } + /// /// 消息数据体加密算法 /// RSA=>IJTNEEncryptImpl /// AES=>IJTNEEncryptImpl /// public Func DataBodiesEncrypt { get; private set; } + /// /// 平台登入加密算法 /// RSA=>IJTNEEncryptImpl /// AES=>IJTNEEncryptImpl /// public Func PlatformLoginEncrypt { get; private set; } + /// /// 注册自定义消息 /// /// - /// + /// /// public JTNEGlobalConfigs Register_CustomMsgId (byte customMsgId) where TJTNEBodies : JTNEBodies { JTNEMsgIdFactory.SetMap (customMsgId); return instance.Value; } + /// /// 重写消息 /// @@ -93,6 +98,7 @@ namespace JTNE.Protocol { } return instance.Value; } + /// /// /// @@ -108,12 +114,12 @@ namespace JTNE.Protocol { /// /// /// - /// 自定义类型编码 - /// 继承JTNE.Protocol.MessageBody.JTNE_0x81_Body + /// 自定义类型编码 + /// 继承JTNE.Protocol.MessageBody.JTNE_0x81_Body /// - public JTNEGlobalConfigs Register_JTNE0x81CustomDepenedBody (byte DependerParamId, byte DependedParamId) { - if (!JTNE_0x81_Body.JTNE_0x81LengthOfADependOnValueOfB.ContainsKey (DependerParamId)) { - JTNE_0x81_Body.JTNE_0x81LengthOfADependOnValueOfB.Add (DependerParamId, DependedParamId); + public JTNEGlobalConfigs Register_JTNE0x81CustomDepenedBody (byte dependerId, byte dependedId) { + if (!JTNE_0x81_Body.JTNE_0x81LengthOfADependOnValueOfB.ContainsKey (dependerId)) { + JTNE_0x81_Body.JTNE_0x81LengthOfADependOnValueOfB.Add (dependerId, dependedId); } return instance.Value; } diff --git a/src/JTNE.Protocol/JTNEPackage.cs b/src/JTNE.Protocol/JTNEPackage.cs index 345e600..8aedcfe 100644 --- a/src/JTNE.Protocol/JTNEPackage.cs +++ b/src/JTNE.Protocol/JTNEPackage.cs @@ -26,12 +26,12 @@ namespace JTNE.Protocol /// 命令标识 /// /// - public byte MsgId { get; set; } + public JTNEMsgId MsgId { get; set; } /// /// 应答标志 /// /// - public byte AskId { get; set; } + public JTNEAskId AskId { get; set; } /// /// 车辆识别码 /// diff --git a/src/JTNE.Protocol/JTNESerializer.cs b/src/JTNE.Protocol/JTNESerializer.cs index 38c65c5..1bd539b 100644 --- a/src/JTNE.Protocol/JTNESerializer.cs +++ b/src/JTNE.Protocol/JTNESerializer.cs @@ -1,52 +1,42 @@ -using JTNE.Protocol.Extensions; -using System; +using System; using System.Runtime.CompilerServices; +using JTNE.Protocol.Extensions; -[assembly: InternalsVisibleTo("JTNE.Protocol.Test")] +[assembly : InternalsVisibleTo ("JTNE.Protocol.Test")] -namespace JTNE.Protocol -{ +namespace JTNE.Protocol { /// /// /// - public static class JTNESerializer - { - public static byte[] Serialize(JTNEPackage jTNEPackage, int minBufferSize = 256) - { - return Serialize(jTNEPackage, minBufferSize); + public static class JTNESerializer { + public static byte[] Serialize (JTNEPackage jTNEPackage, int minBufferSize = 256) { + return Serialize (jTNEPackage, minBufferSize); } - public static JTNEPackage Deserialize(ReadOnlySpan bytes) - { - return Deserialize(bytes); + public static JTNEPackage Deserialize (ReadOnlySpan bytes) { + return Deserialize (bytes); } - public static byte[] Serialize(T obj, int minBufferSize = 256) - { - var formatter = JTNEFormatterExtensions.GetFormatter(); - byte[] buffer = JTNEArrayPool.Rent(minBufferSize); - try - { - var len = formatter.Serialize(ref buffer, 0, obj); - return buffer.AsSpan(0, len).ToArray(); - } - finally - { - JTNEArrayPool.Return(buffer); + public static byte[] Serialize (T obj, int minBufferSize = 256) { + var formatter = JTNEFormatterExtensions.GetFormatter (); + byte[] buffer = JTNEArrayPool.Rent (minBufferSize); + try { + var len = formatter.Serialize (ref buffer, 0, obj); + return buffer.AsSpan (0, len).ToArray (); + } finally { + JTNEArrayPool.Return (buffer); } } - public static T Deserialize(ReadOnlySpan bytes) - { - var formatter = JTNEFormatterExtensions.GetFormatter(); + public static T Deserialize (ReadOnlySpan bytes) { + var formatter = JTNEFormatterExtensions.GetFormatter (); int readSize; - return formatter.Deserialize(bytes,out readSize); + return formatter.Deserialize (bytes, out readSize); } - public static dynamic Deserialize(ReadOnlySpan bytes,Type type) - { - var formatter = JTNEFormatterExtensions.GetFormatter(type); - return JTNEFormatterResolverExtensions.JTNEDynamicDeserialize(formatter,bytes,out int readSize); + public static dynamic Deserialize (ReadOnlySpan bytes, Type type) { + var formatter = JTNEFormatterExtensions.GetFormatter (type); + return JTNEFormatterResolverExtensions.JTNEDynamicDeserialize (formatter, bytes, out int readSize); } } -} +} \ No newline at end of file