Quellcode durchsuchen

Merge pull request #12190 from JimMoen/EMQX-11526-jt808-auth-init-function-caluse

EMQX 11526 jt808 auth init function caluse
JianBo He vor 2 Jahren
Ursprung
Commit
a6aad1400e

+ 260 - 178
apps/emqx_gateway_jt808/doc/Data_Exchange_Guide_CN.md

@@ -1,8 +1,6 @@
-# emqx-jt808
+# JT/T 808 2013 网关数据交换格式
 
-JT/T 808 2013 协议接入网关
-
-该文档定义了 Plugins **emqx_jt808** 和 **EMQX** 之间数据交换的格式
+该文档定义了 **emqx_jt808** 和 **EMQX** 之间数据交换的格式
 
 约定:
 - Payload 采用 Json 格式进行组装
@@ -13,35 +11,35 @@ Json 结构示例
 ## 终端到服务器
 ```json
 {
-    "header" : {
-        "msg_id" : 1,
-        "encrypt": 0,
-        "len": VAL,
-        "phone": 13900000000,
-        "msg_sn": 0
-        },
-    "body": {
-        "seq": 1,
-        "id": 1,
-        "result": 0
-        }
+  "header" : {
+    "msg_id" : 1,
+    "encrypt": 0,
+    "len": VAL,
+    "phone": 13900000000,
+    "msg_sn": 0
+  },
+  "body": {
+    "seq": 1,
+    "id": 1,
+    "result": 0
+  }
 }
 ```
 
 ## 服务器到终端
 ```json
 {
-    "header": {
-        "msg_id": 32769,
-        "encrypt": 0,
-        "phone": 13900000000,
-        "msg_sn": 0
-        },
-    "body": {
-        "seq": 1,
-        "id": 1,
-        "result": 0
-        }
+  "header": {
+    "msg_id": 32769,
+    "encrypt": 0,
+    "phone": 13900000000,
+    "msg_sn": 0
+  },
+  "body": {
+    "seq": 1,
+    "id": 1,
+    "result": 0
+  }
 }
 ```
 
@@ -75,7 +73,8 @@ Json 结构示例
 
 ### 消息体字段对照表
 
-- 终端通用应答 `"msg_id": 1` 0x0001
+#### 终端通用应答 `"msg_id": 1` 0x0001
+
 | Field      | Json Key name | Value Type | Value Type in Json |
 |:----------:|:-------------:|:----------:|:------------------:|
 | 应答流水号 | seq           | word       | integer            |
@@ -83,7 +82,8 @@ Json 结构示例
 | 结果       | result        | byte       | integer            |
 
 
-- 平台通用应答 `"msg_id": 32769` 0x8001
+#### 平台通用应答 `"msg_id": 32769` 0x8001
+
 | Field      | Json Key name | Value Type | Value Type in Json |
 |:----------:|:-------------:|:----------:|:------------------:|
 | 应答流水号 | seq           | word       | integer            |
@@ -91,11 +91,13 @@ Json 结构示例
 | 结果       | result        | byte       | integer            |
 
 
-- 终端心跳 `"msg_id": 2` 0x0002
+#### 终端心跳 `"msg_id": 2` 0x0002
+
 空 Json
 
 
-- 补传分包请求 `"msg_id": 32771` 0x8003
+#### 补传分包请求 `"msg_id": 32771` 0x8003
+
 | Field          | Json Key name | Value Type     | Value Type in Json |
 |:--------------:|:-------------:|:--------------:|:------------------:|
 | 原始消息流水号 | seq           | word           | integer            |
@@ -103,7 +105,8 @@ Json 结构示例
 | 重传包 ID 列表 | ids           | byte(2*length) | list of integer    |
 
 
-- 终端注册 `"msg_id": 256` 0x0100
+#### 终端注册 `"msg_id": 256` 0x0100
+
 | Field     | Json Key name  | Value Type | Value Type in Json |
 |:---------:|:--------------:|:----------:|:------------------:|
 | 省域 ID   | province       | word       | integer            |
@@ -115,28 +118,34 @@ Json 结构示例
 | 车辆标识  | license_number | string     | string             |
 
 
-- 终端注册应答 `"msg_id": 33024` 0x8100
+#### 终端注册应答 `"msg_id": 33024` 0x8100
+
 | Field      | Json Key name | Value Type | Value Type in Json |
 |:----------:|:-------------:|:----------:|:------------------:|
 | 应答流水号 | seq           | word       | integer            |
 | 结果       | result        | byte       | integer            |
 
 只有成功后才有此字段
+
 | Optional Field | Json Key name | Value Type | Value Type in JSON |
+|:--------------:|---------------|------------|--------------------|
 | 鉴权码         | auth_code     | string     | string             |
 
 
-- 终端注销 `"msg_id": 3` 0x0003
+#### 终端注销 `"msg_id": 3` 0x0003
+
 空 Json
 
 
-- 终端鉴权 `"msg_id": 258` 0x0102
+#### 终端鉴权 `"msg_id": 258` 0x0102
+
 | Field  | Json Key name | Value Type | Value Type in Json |
 |:------:|:-------------:|:----------:|:------------------:|
 | 鉴权码 | code          | string     | string             |
 
 
-- 设置终端参数 `"msg_id": 33027` 0x8103
+#### 设置终端参数 `"msg_id": 33027` 0x8103
+
 | Field      | Json Key name | Value Type | Value Type in Json                                     |
 |:----------:|:-------------:|:----------:|:------------------------------------------------------:|
 | 参数总数   | length        | byte       | integer                                                |
@@ -147,11 +156,13 @@ Json 结构示例
 参数 ID 说明见协议规定.
 
 
-- 查询终端参数 `"msg_id": 33028` 0x8104
+#### 查询终端参数 `"msg_id": 33028` 0x8104
+
 空 Json
 
 
-- 查询指定终端参数 `"msg_id": 33030` 0x8106
+#### 查询指定终端参数 `"msg_id": 33030` 0x8106
+
 | Field        | Json Key name | Value Type     | Value Type in Json               |
 |:------------:|:-------------:|:--------------:|:--------------------------------:|
 | 参数总数     | length        | byte           | integer                          |
@@ -160,7 +171,8 @@ Json 结构示例
 参数 ID 列表中元素为 integer
 
 
-- 查询终端应答参数 `"msg_id": 260` 0x0104
+#### 查询终端应答参数 `"msg_id": 260` 0x0104
+
 | Field        | Json Key name | Value Type | Value Type in Json                                     |
 |:------------:|:-------------:|:----------:|:------------------------------------------------------:|
 | 应答流水号   | seq           | word       | integer                                                |
@@ -172,18 +184,21 @@ Json 结构示例
 参数 ID 说明见协议规定.
 
 
-- 终端控制 `"msg_id": 33029 ` 0x8105
+#### 终端控制 `"msg_id": 33029 ` 0x8105
+
 | Field    | Json Key name | Value Type | Value Type in Json |
 |:--------:|:-------------:|:----------:|:------------------:|
 | 命令字   | command       | byte       | integer            |
 | 命令参数 | param         | string     | string             |
 
 
-- 查询终端属性 `"msg_id": 33031` 0x8107
+#### 查询终端属性 `"msg_id": 33031` 0x8107
+
 空 Json
 
 
-- 查询终端属性应答 `"msg_id": 263` 0x0107
+#### 查询终端属性应答 `"msg_id": 263` 0x0107
+
 | Field             | Json Key name    | Value Type | Value Type in Json |
 |:-----------------:|:----------------:|:----------:|:------------------:|
 | 终端类型          | type             | word       | integer            |
@@ -196,10 +211,11 @@ Json 结构示例
 | GNSS 模块属性     | gnss_prop        | byte       | integer            |
 | 通信模块属性      | comm_prop        | byte       | integer            |
 
+- 终端硬件版本号长度、终端固件版本号长度,将被用于二进制报文解析,不向上暴露
 
 
-- 下发终端升级包 `"msg_id": 33032` 0x8108
+#### 下发终端升级包 `"msg_id": 33032` 0x8108
+
 | Field          | Json Key name | Value Type | Value Type in Json     |
 |:--------------:|:-------------:|:----------:|:----------------------:|
 | 升级类型       | type          | byte       | integer                |
@@ -210,14 +226,16 @@ Json 结构示例
 | 升级数据包     | firmware      | binary     | string(base64 encoded) |
 
 
-- 终端升级结果通知 `"msg_id": 264` 0x0108
+#### 终端升级结果通知 `"msg_id": 264` 0x0108
+
 | Field    | Json Key name | Value Type | Value Type in Json |
 |:--------:|:-------------:|:----------:|:------------------:|
 | 升级类型 | type          | byte       | integer            |
 | 升级结果 | result        | byte       | integer            |
 
 
-- 位置信息汇报 `"msg_id": 512` 0x0200
+#### 位置信息汇报 `"msg_id": 512` 0x0200
+
 | Field                | Json Key name | Value Type | Value Type in Json |
 |:--------------------:|:-------------:|:----------:|:------------------:|
 | 报警标志             | alarm         | dword      | integer            |
@@ -230,11 +248,13 @@ Json 结构示例
 | 时间                 | time          | bcd(6)     | string             |
 
 | Optional Field     | Json Key name | Value Type | Value Type in JSON |
+|:------------------:|:-------------:|:----------:|:------------------:|
 | 位置附加信息项列表 | extra         | -          | map                |
 
-%% TODO: refine alarm mroe details
+<!-- TODO: refine alarm mroe details -->
+
+- 位置附加信息项列表, 在 `extra` 中
 
-位置附加信息项列表, 在 `extra` 中
 | Field (附加信息描述)              | Json Key name   | Value Type | Value Type in Json     |
 |:---------------------------------:|:---------------:|:----------:|:----------------------:|
 | 里程                              | mileage         | dword      | integer                |
@@ -250,44 +270,51 @@ Json 结构示例
 | 无线通信网络信号强度              | rssi            | byte       | integer                |
 | GNSS 定位卫星数                   | gnss_sat_num    | byte       | integer                |
 | 后续自定义信息长度                | custome         | -          | string(base64 encoded) |
-| %% TODO 自定义区域                |                 |            |                        |
+| ## TODO 自定义区域                |                 |            |                        |
+
+- 超速报警附加信息(长度1或5), 置于 map `overspeed_alarm` 内
 
-超速报警附加信息(长度1或5), 置于 map `overspeed_alarm` 内
 | Field    | Json Key name | Value Type | Value Type in Json |
 |:--------:|:-------------:|:----------:|:------------------:|
 | 位置类型 | type          | byte       | integer            |
 
 | Optional Field | Json Key name | Value Type | Value Type in JSON |
+|:--------------:|:-------------:|:----------:|:------------------:|
 | 区域或路段 ID  | id            | dword      | integer            |
 
 
-进出区域/路线报警附加信息, 置于 map `in_out_alarm` 内
+- 进出区域/路线报警附加信息, 置于 map `in_out_alarm` 内
+
 | Field         | Json Key name | Value Type | Value Type in Json |
 |:-------------:|:-------------:|:----------:|:------------------:|
 | 位置类型      | type          | byte       | integer            |
 | 区域或路段 ID | id            | dword      | integer            |
-| 方向          | direction     | byte       | integer                   |
+| 方向          | direction     | byte       | integer            |
+
+- 路段行驶时间不足/过长报警附加信息, 置于 map `path_time_alarm` 内
 
-路段行驶时间不足/过长报警附加信息, 置于 map `path_time_alarm` 内
 | Field        | Json Key name | Value Type | Value Type in Json |
 |:------------:|:-------------:|:----------:|:------------------:|
 | 路段 ID      | id            | dword      | integer            |
 | 路段行驶时间 | time          | word       | integer            |
 | 结果         | result        | byte       | integer            |
 
-IO 状态位, 置于 map `io_status` 内
+- IO 状态位, 置于 map `io_status` 内
+
 | Field        | Json Key name | Value Type | Value Type in Json |
 |:------------:|:-------------:|:----------:|:------------------:|
 | 深度休眠状态 | deep_sleep    | 1 bit      | integer            |
 | 休眠状态     | sleep         | 1 bit      | integer            |
 
-模拟量, 置于 map  `analog` 内
+- 模拟量, 置于 map  `analog` 内
+
 | Field    | Json Key name | Value Type | Value Type in Json |
 |:--------:|:-------------:|:----------:|:------------------:|
 | 模拟量 0 | ad0           | 16 bits    | integer            |
 | 模拟量 1 | ad1           | 16 bits    | integer            |
 
-扩展车辆信号状态位, 置于 map `extra` 内
+- 扩展车辆信号状态位, 置于 map `extra` 内
+
 | Field        | Json Key name   | Value Type | Value Type in Json                         |
 |:------------:|:---------------:|:----------:|:------------------------------------------:|
 | 信号         | signal          | - 2 bits   | map, `{"low_beam": VAL, "high_beam": VAL}` |
@@ -305,7 +332,8 @@ IO 状态位, 置于 map `io_status` 内
 | 加热器工作   | heater          | 1 bit      | integer                                    |
 | 离合器状态   | cluth           | 1 bit      | integer                                    |
 
-信号状态, 置于 map `signal` 内
+- 信号状态, 置于 map `signal` 内
+
 | Field      | Json Key name | Value Type | Value Type in Json |
 |:----------:|:-------------:|:----------:|:------------------:|
 | 近光灯信号 | low_beam      | 1 bit      | integer            |
@@ -313,107 +341,113 @@ IO 状态位, 置于 map `io_status` 内
 
 example:
-```
+```json
 {
-    "header" : {
-        "msg_id" : 1,
-        "encrypt": 0,
-        "len": VAL,
-        "phone": 13900000000,
-        "msg_sn": 0
-    },
-    "body": {
-        "alarm": VAL,
-        "status": VAL,
-        "latitude": VAL,
-        "longitude": VAL,
-        "altitude": VAL,
-        "speed": VAL,
-        "direction": VAL,
+  "header" : {
+    "msg_id" : 1,
+    "encrypt": 0,
+    "len": VAL,
+    "phone": 13900000000,
+    "msg_sn": 0
+  },
+  "body": {
+    "alarm": VAL,
+    "status": VAL,
+    "latitude": VAL,
+    "longitude": VAL,
+    "altitude": VAL,
+    "speed": VAL,
+    "direction": VAL,
+    "time": VAL,
+    "extra": {
+      "mileage": VAL,
+      "fuel_unit": VAL,
+      "speed": VAL,
+      "alarm_id": VAL,
+      "overspeed_alarm": {
+        "type": VAL,
+        "id": VAL
+      },
+      "in_out_alarm": {
+        "type": VAL,
+        "id": VAL,
+        "direction": VAL
+      },
+      "path_time_alarm": {
+        "id": VAL,
         "time": VAL,
-        "extra": {
-            "mileage": VAL,
-            "fuel_unit": VAL,
-            "speed": VAL,
-            "alarm_id": VAL,
-            "overspeed_alarm": {
-                "type": VAL,
-                "id": VAL
-            },
-            "in_out_alarm": {
-                "type": VAL,
-                "id": VAL,
-                "direction": VAL
-            },
-            "path_time_alarm": {
-                "id": VAL,
-                "time": VAL,
-                "result": VAL
-            },
-            "signal": {
-                "low_beam": VAL,
-                "high_beam": VAL
-            },
-            "right_turn": VAL,
-            "left_turn": VAL,
-            "break": VAL,
-            "reverse": VAL,
-            "fog": VAL,
-            "side_marker": VAL,
-            "horn": VAL,
-            "air_conditioner": VAL,
-            "neutral": VAL,
-            "retarder": VAL,
-            "abs": VAL,
-            "heater": VAL,
-            "cluth": VAL,
-            "io_status": {
-                "deep_sleep": VAL,
-                "sleep": VAL
-            },
-            "analog": {
-                "ad0": VAL,
-                "ad1": VAL
-            }
-        }
+        "result": VAL
+      },
+      "signal": {
+        "low_beam": VAL,
+        "high_beam": VAL
+      },
+      "right_turn": VAL,
+      "left_turn": VAL,
+      "break": VAL,
+      "reverse": VAL,
+      "fog": VAL,
+      "side_marker": VAL,
+      "horn": VAL,
+      "air_conditioner": VAL,
+      "neutral": VAL,
+      "retarder": VAL,
+      "abs": VAL,
+      "heater": VAL,
+      "cluth": VAL,
+      "io_status": {
+        "deep_sleep": VAL,
+        "sleep": VAL
+      },
+      "analog": {
+        "ad0": VAL,
+        "ad1": VAL
+      }
     }
+  }
 }
 ```
 
 
-- 位置信息查询 `"msg_id": 33281` 0x8201
+#### 位置信息查询 `"msg_id": 33281` 0x8201
+
 空 Json
 
 
-- 位置信息查询应答 `"msg_id": 513` 0x0201
+#### 位置信息查询应答 `"msg_id": 513` 0x0201
+
 | Field        | Json Key name | Value Type | Value Type in Json |
 |:------------:|:-------------:|:----------:|:------------------:|
 | 应答流水号   | seq           | word       | integer            |
 | 位置信息汇报 | params        | -          | map                |
 
 
-- 临时位置跟踪控制 `"msg_id": 33282` 0x8202
+#### 临时位置跟踪控制 `"msg_id": 33282` 0x8202
+
 | Field          | Json Key name | Value Type | Value Type in Json |
 |:--------------:|:-------------:|:----------:|:------------------:|
 | 时间间隔       | period        | word       | integer            |
 | 跟踪位置有效期 | expiry        | dword      | integer            |
 
 
-- 人工确认报警消息 `"msg_id": 33283` 0x8203
+#### 人工确认报警消息 `"msg_id": 33283` 0x8203
+
 | Field            | Json Key name | Value Type | Value Type in Json |
 |:----------------:|:-------------:|:----------:|:------------------:|
 | 报警消息流水号   | seq           | word       | integer            |
 | 人工确认报警类型 | type          | dword      | integer            |
 
 
-- 文本信息下发 `"msg_id": 33536` 0x8300
+#### 文本信息下发 `"msg_id": 33536` 0x8300
+
 | Field    | Json Key name | Value Type | Value Type in Json |
 |:--------:|:-------------:|:----------:|:------------------:|
 | 标志     | flag          | byte       | integer            |
 | 文本信息 | text          | string     | string             |
 
 
-- 事件设置 `"msg_id": 33537` 0x8301
+#### 事件设置 `"msg_id": 33537` 0x8301
+
 | Field        | Json Key name | Value Type | Value Type in Json                                                |
 |:------------:|:-------------:|:----------:|:-----------------------------------------------------------------:|
 | 设置类型     | type          | byte       | integer                                                           |
@@ -424,33 +458,37 @@ example:
 | 事件内容     | content       | string     | string                                                            |
 
 
-- 事件报告 `"msg_id": 769` 0x0301
+#### 事件报告 `"msg_id": 769` 0x0301
+
 | Field   | Json Key name | Value Type | Value Type in Json |
 |:-------:|:-------------:|------------|:------------------:|
 | 事件 ID | id            | byte       | integer            |
 
 
-- 提问下发 `"msg_id": 33538` 0x8302
-| Field        | Json Key name | Value Type | Value Type in Json                                              |
-|:------------:|:-------------:|:----------:|:---------------------------------------------------------------:|
-| 标志         | flag          | byte       | integer                                                         |
-| 问题内容长度 | length        | byte       | integer                                                         |
-| 问题         | question      | string     | string                                                          |
+#### 提问下发 `"msg_id": 33538` 0x8302
+
+| Field        | Json Key name | Value Type | Value Type in Json                                             |
+|:------------:|:-------------:|:----------:|:--------------------------------------------------------------:|
+| 标志         | flag          | byte       | integer                                                        |
+| 问题内容长度 | length        | byte       | integer                                                        |
+| 问题         | question      | string     | string                                                         |
 | 候选答案列表 | answers       | list       | list of answer. `[{"id": ID, "len": LEN, "answer": ANS}, ...]` |
-| 答案 ID      | id            | byte       | integer                                                         |
-| 答案内容长度 | len           | byte       | integer                                                         |
-| 答案内容     | answer        | string     | string                                                          |
+| 答案 ID      | id            | byte       | integer                                                        |
+| 答案内容长度 | len           | byte       | integer                                                        |
+| 答案内容     | answer        | string     | string                                                         |
+
+<!-- TODO: len -> length or other length -> len -->
 
-%% TODO: len -> length or other length -> len
+#### 提问应答 `"msg_id": 770` 0x0302
 
-- 提问应答 `"msg_id": 770` 0x0302
 | Field      | Json Key name | Value Type | Value Type in Json |
 |:----------:|:-------------:|:----------:|:------------------:|
 | 应答流水号 | seq           | word       | integer            |
 | 答案 ID    | id            | byte       | integer            |
 
 
-- 信息点播菜单设置 `"msg_id": 33539` 0x8303
+#### 信息点播菜单设置 `"msg_id": 33539` 0x8303
+
 | Field        | Json Key name | Value Type | Value Type in Json |
 |:------------:|:-------------:|:----------:|:------------------:|
 | 设置类型     | type          | byte       | integer            |
@@ -461,14 +499,16 @@ example:
 | 信息名称     | info          | string     | string             |
 
 
-- 信息点播/取消 `"msg_id": 771` 0x0303
+#### 信息点播/取消 `"msg_id": 771` 0x0303
+
 | Field         | Json Key name | Value Type | Value Type in Json |
 |:-------------:|:-------------:|:----------:|:------------------:|
 | 信息类型      | id            | byte       | integer            |
 | 点拨/取消标志 | flag          | byte       | integer            |
 
 
-- 信息服务 `"msg_id": 33540` 0x8304
+#### 信息服务 `"msg_id": 33540` 0x8304
+
 | Field    | Json Key name | Value Type | Value Type in Json |
 |:--------:|:-------------:|:----------:|:------------------:|
 | 信息类型 | type          | byte       | integer            |
@@ -476,14 +516,16 @@ example:
 | 信息内容 | info          | string     | string             |
 
 
-- 电话回拨 `"msg_id": 33792` 0x8400
+#### 电话回拨 `"msg_id": 33792` 0x8400
+
 | Field    | Json Key name | Value Type | Value Type in Json |
 |:--------:|:-------------:|:----------:|:------------------:|
 | 标志     | type          | byte       | integer            |
 | 电话号码 | phone         | string     | string             |
 
 
-- `"msg_id": 33793` 0x8401
+#### 设置电话本 `"msg_id": 33793` 0x8401
+
 | Field      | Json Key name | Value Type | Value Type in Json |
 |:----------:|:-------------:|:----------:|:------------------:|
 | 设置类型   | type          | byte       | integer            |
@@ -496,23 +538,28 @@ example:
 | 联系人     | name          | string     | string             |
 
 联系人项示例
-`[{"type": TYPE, "phone_len", PH_LEN, "phone": PHONE, "name_len": NAME_LEN, "name": NAME}, ...]`
+```json
+[{"type": TYPE, "phone_len", PH_LEN, "phone": PHONE, "name_len": NAME_LEN, "name": NAME}, ...]
+```
+
 
+#### 车辆控制 `"msg_id": 34048` 0x8500
 
-- `"msg_id": 34048` 0x8500
 | Field    | Json Key name | Value Type | Value Type in Json |
 |:--------:|:-------------:|:----------:|:------------------:|
 | 标志控制 | flag          | byte       | integer            |
 
 
-- `"msg_id": 1280` 0x0500
+#### 车辆控制应答 `"msg_id": 1280` 0x0500
+
 | Field              | Json Key name | Value Type | Value Type in Json |
 |:------------------:|:-------------:|:----------:|:------------------:|
 | 应答流水号         | seq           | word       | integer            |
 | 位置信息汇报消息体 | location      | map        | map of location    |
 
 
-- `"msg_id": 34304` 0x8600
+#### 设置圆形区域 `"msg_id": 34304` 0x8600
+
 | Field        | Json Key name      | Value Type | Value Type in Json |
 |:------------:|:------------------:|:----------:|:------------------:|
 | 设置属性     | type               | byte       | integer            |
@@ -529,7 +576,8 @@ example:
 | 超速持续时间 | overspeed_duration | byte       | integer            |
 
 区域列表示例
-`[{"id": ID,
+```json
+[{"id": ID,
    "flag": FLAG,
    "center_latitude": CEN_LAT,
    "center_longitude": CEN_LON,
@@ -540,10 +588,12 @@ example:
    "overspeed_duration", OVERSPEED_DURATION
    },
   ...
- ]`
+ ]
+```
+
 
+#### 删除圆形区域 `"msg_id": 34305` 0x8601
 
-- 删除圆形区域 `"msg_id": 34305` 0x8601
 | Field        | Json Key name | Value Type | Value Type in Json |
 |:------------:|:-------------:|:----------:|:------------------:|
 | 区域数       | length        | byte       | integer            |
@@ -553,7 +603,8 @@ example:
 `[ID1, ID2, ...]`
 
 
-- 设置矩形区域 `"msg_id": 34306` 0x8602
+#### 设置矩形区域 `"msg_id": 34306` 0x8602
+
 | Field        | Json Key name      | Value Type | Value Type in Json       |
 |:------------:|:------------------:|:----------:|:------------------------:|
 | 设置属性     | type               | byte       | integer                  |
@@ -571,7 +622,8 @@ example:
 | 超速持续时间 | overspeed_duration | byte       | integer                  |
 
 
-- 删除矩形区域 `"msg_id": 34307` 0x8603
+#### 删除矩形区域 `"msg_id": 34307` 0x8603
+
 | Field        | Json Key name | Value Type | Value Type in Json |
 |:------------:|:-------------:|:----------:|:------------------:|
 | 区域数       | length        | byte       | integer            |
@@ -579,7 +631,8 @@ example:
 | 区域 ID 1~n  | -             | dword      | integer            |
 
 
-- 设置多边形区域 `"msg_id": 34308` 0x8604
+#### 设置多边形区域 `"msg_id": 34308` 0x8604
+
 | Field        | Json Key name      | Value Type | Value Type in Json |
 |:------------:|:------------------:|:----------:|:------------------:|
 | 区域 ID      | id                 | dword      | integer            |
@@ -594,7 +647,8 @@ example:
 | 顶点经度     | lng                | dword      | integer            |
 
 
-- 删除多边形区域 `"msg_id": 34309` 0x8605
+#### 删除多边形区域 `"msg_id": 34309` 0x8605
+
 | Field        | Json Key name | Value Type | Value Type in Json |
 |:------------:|:-------------:|:----------:|:------------------:|
 | 区域数       | length        | byte       | integer            |
@@ -602,7 +656,8 @@ example:
 | 区域 ID 1~n  | -             | dword      | integer            |
 
 
-- 设置路线 `"msg_id": 34310` 0x8606
+#### 设置路线 `"msg_id": 34310` 0x8606
+
 | Field            | Json Key name      | Value Type | Value Type in Json |
 |:----------------:|:------------------:|:----------:|:------------------:|
 | 路线 ID          | id                 | dword      | integer            |
@@ -623,7 +678,8 @@ example:
 | 路段超速持续时间 | overspeed_duration | byte       | integer            |
 
 
-- `"msg_id": 34311` 0x8607
+#### 删除路线 `"msg_id": 34311` 0x8607
+
 | Field    | Json Key name | Value Type | Value Type in Json |
 |:--------:|:-------------:|:----------:|:------------------:|
 | 路线数   | length        | byte       | integer            |
@@ -631,14 +687,16 @@ example:
 | 路线 ID  | -             | dword      | integer            |
 
 
-- 行驶记录数据采集命令 `"msg_id": 34560` 0x8700
+#### 行驶记录数据采集命令 `"msg_id": 34560` 0x8700
+
 | Field  | Json Key name | Value Type             | Value Type in Json |
 |:------:|:-------------:|:----------------------:|:------------------:|
 | 命令字 | command       | byte                   | integer            |
 | 数据块 | param         | string(base64 encoded) | string             |
 
 
-- 行驶记录数据上传 `"msg_id": 1792` 0x0700
+#### 行驶记录数据上传 `"msg_id": 1792` 0x0700
+
 | Field      | Json Key name | Value Type             | Value Type in Json |
 |:----------:|:-------------:|:----------------------:|:------------------:|
 | 应答流水号 | seq           | word                   | integer            |
@@ -646,25 +704,29 @@ example:
 | 数据块     | data          | string(base64 encoded) | string             |
 
 
-- 行驶记录参数下传命令 `"msg_id": 34561` 0x8701
+#### 行驶记录参数下传命令 `"msg_id": 34561` 0x8701
+
 | Field  | Json Key name | Value Type             | Value Type in Json |
 |:------:|:-------------:|:----------------------:|:------------------:|
 | 命令字 | command       | byte                   | integer            |
 | 数据块 | param         | string(base64 encoded) | string             |
 
 
-- 电子运单上报 `"msg_id": 1793` 0x0701
+#### 电子运单上报 `"msg_id": 1793` 0x0701
+
 | Field        | Json Key name | Value Type             | Value Type in Json |
 |:------------:|:-------------:|:----------------------:|:------------------:|
 | 电子运单长度 | length        | dword                  | integer            |
 | 电子运单内容 | data          | string(base64 encoded) | string             |
 
 
-- 上报驾驶员身份信息请求 `"msg_id": 34562` 0x8702
+#### 上报驾驶员身份信息请求 `"msg_id": 34562` 0x8702
+
 空 Json
 
 
-- 驾驶员身份信息采集上报 `"msg_id": 1794` 0x0702
+#### 驾驶员身份信息采集上报 `"msg_id": 1794` 0x0702
+
 | Field          | Json Key name | Value Type | Value Type in Json |
 |:--------------:|:-------------:|:----------:|:------------------:|
 | 状态           | status        | byte       | integer            |
@@ -676,7 +738,8 @@ example:
 | 证件有效期     | cert_expiry   | string     | string             |
 
 
-- 定位数据批量上传 `"msg_id": 1796` 0x0704
+#### 定位数据批量上传 `"msg_id": 1796` 0x0704
+
 | Field          | Json Key name | Value Type | Value Type in Json |
 |:--------------:|:-------------:|:----------:|:------------------:|
 | 位置数据类型   | type          | byte       | integer            |
@@ -684,7 +747,8 @@ example:
 | 位置汇报数据项 | location      | list       | list of location   |
 
 
-- `"msg_id": 1797` 0x0705
+#### CAN 总线数据上传 `"msg_id": 1797` 0x0705
+
 | Field                | Json Key name | Value Type | Value Type in Json     |
 |:--------------------:|:-------------:|:----------:|:----------------------:|
 | 数据项个数           | length        | word       | integer                |
@@ -697,7 +761,8 @@ example:
 | CAN 数据             | data          | binary     | string(base64 encoded) |
 
 
-- 多媒体时间信息上传 `"msg_id": 2048` 0x0800
+#### 多媒体时间信息上传 `"msg_id": 2048` 0x0800
+
 | Field          | Json Key name | Value Type | Value Type in Json |
 |:--------------:|:-------------:|:----------:|:------------------:|
 | 多媒体数据 ID  | id            | dword      | integer            |
@@ -707,7 +772,8 @@ example:
 | 通道 ID        | channel       | byte       | integer            |
 
 
-- 多媒体数据上传 `"msg_id": 2049` 0x0801
+#### 多媒体数据上传 `"msg_id": 2049` 0x0801
+
 | Field          | Json Key name | Value Type | Value Type in Json     |
 |:--------------:|:-------------:|:----------:|:----------------------:|
 | 多媒体 ID      | id            | dword      | integer                |
@@ -720,7 +786,8 @@ example:
 
 
 
-- 多媒体数据上传应答 `"msg_id": 34816` 0x8800
+#### 多媒体数据上传应答 `"msg_id": 34816` 0x8800
+
 | Field          | Json Key name | Value Type | Value Type in Json |
 |:--------------:|:-------------:|:----------:|:------------------:|
 | 多媒体 ID      | mm_id         | dword      | integer            |
@@ -728,7 +795,8 @@ example:
 | 重传包 ID 列表 | retx_ids      | list       | list of retry IDs  |
 
 
-- 摄像头立即拍摄命令 `"msg_id": 34817` 0x8801
+#### 摄像头立即拍摄命令 `"msg_id": 34817` 0x8801
+
 | Field             | Json Key name | Value Type | Value Type in Json |
 |:-----------------:|:-------------:|:----------:|:------------------:|
 | 通道 ID           | channel_id    | byte       | integer            |
@@ -743,7 +811,8 @@ example:
 | 色度              | chromaticity  | byte       | integer            |
 
 
-- 摄像头立即拍摄应答 `"msg_id": 2053` 0x0805
+#### 摄像头立即拍摄应答 `"msg_id": 2053` 0x0805
+
 | Field          | Json Key name | Value Type     | Value Type in Json |
 |:--------------:|:-------------:|:--------------:|:------------------:|
 | 应答流水号     | seq           | word           | integer            |
@@ -752,7 +821,8 @@ example:
 | 多媒体 ID 列表 | ids           | byte(4*length) | integer            |
 
 
-- 存储多媒体数据检索 `"msg_id": 34818` 0x8802
+#### 存储多媒体数据检索 `"msg_id": 34818` 0x8802
+
 | Field      | Json Key name | Value Type | Value Type in Json |
 |:----------:|:-------------:|:----------:|:------------------:|
 | 多媒体类型 |               | byte       |                    |
@@ -762,7 +832,8 @@ example:
 | 结束时间   |               | string     |                    |
 
 
-- 存储多媒体数据检索应答 `"msg_id": 2050` 0x0802
+#### 存储多媒体数据检索应答 `"msg_id": 2050` 0x0802
+
 | Field            | Json Key name | Value Type | Value Type in Json    |
 |:----------------:|:-------------:|:----------:|:---------------------:|
 | 应答流水号       | seq           | word       | integer               |
@@ -775,7 +846,8 @@ example:
 | 位置信息汇报     | location      | byte(28)   | map                   |
 
 
-- 存储多媒体数据上传命令 `"msg_id": 34819` 0x8803
+#### 存储多媒体数据上传命令 `"msg_id": 34819` 0x8803
+
 | Field      | Json Key name | Value Type | Value Type in Json |
 |:----------:|:-------------:|:----------:|:------------------:|
 | 多媒体类型 | type          | byte       | integer            |
@@ -786,7 +858,8 @@ example:
 | 删除标志   | delete        | byte       | integer            |
 
 
-- 录音开始命令 `"msg_id": 34820` 0x8804
+#### 录音开始命令 `"msg_id": 34820` 0x8804
+
 | Field      | Json Key name | Value Type | Value Type in Json |
 |:----------:|:-------------:|:----------:|:------------------:|
 | 录音命令   | command       | byte       | integer            |
@@ -795,46 +868,54 @@ example:
 | 音频采样率 | rate          | byte       | integer            |
 
 
-- 单条存储多媒体j叔叔检索上传命令 `"msg_id": 34821` 0x8805
+#### 单条存储多媒体j叔叔检索上传命令 `"msg_id": 34821` 0x8805
+
 | Field     | Json Key name | Value Type | Value Type in Json |
 |:---------:|:-------------:|:----------:|:------------------:|
 | 多媒体 ID | id            | dword      | integer            |
 | 删除标志  | flag          | byte       | integer            |
 
 
-- 数据下行透传 `"msg_id": 35072` 0x8900
+#### 数据下行透传 `"msg_id": 35072` 0x8900
+
 | Field        | Json Key name | Value Type | Value Type in Json     |
 |:------------:|:-------------:|:----------:|:----------------------:|
 | 透传消息类型 | type          | byte       | integer                |
 | 透传消息内容 | data          | binary     | string(base64 encoded) |
 
 
-- 数据上行透传 `"msg_id": 2304` 0x0900
+#### 数据上行透传 `"msg_id": 2304` 0x0900
+
 | Field        | Json Key name | Value Type | Value Type in Json     |
 |:------------:|:-------------:|:----------:|:----------------------:|
 | 透传消息类型 | type          | byte       | integer                |
 | 透传消息内容 | data          | binary     | string(base64 encoded) |
 
 
-- 数据压缩上报 `"msg_id": 2305` 0x0901
+#### 数据压缩上报 `"msg_id": 2305` 0x0901
+
 | Field        | Json Key name | Value Type | Value Type in Json     |
 |:------------:|:-------------:|:----------:|:----------------------:|
 | 压缩消息长度 | length        | dword      | integer                |
 | 压缩消息体   | data          | binary     | string(base64 encoded) |
 
 
-- 平台 RSA 公钥 `"msg_id": 35328` 0x8A00
+#### 平台 RSA 公钥 `"msg_id": 35328` 0x8A00
+
 | Field | Json Key name | Value Type | Value Type in Json     |
 |:-----:|:-------------:|:----------:|:----------------------:|
 | e     | e             | dword      | integer                |
 | n     | n             | byte(128)  | string(base64 encoded) |
 
 
-- 终端 RSA 公钥 `"msg_id": 2560` 0x0A00
+#### 终端 RSA 公钥 `"msg_id": 2560` 0x0A00
+
 | Field | Json Key name | Value Type | Value Type in Json     |
 |:-----:|:-------------:|:----------:|:----------------------:|
 | e     | e             | dword      | integer                |
 | n     | n             | byte(128)  | string(base64 encoded) |
 
-- 0x8F00 ~ 0x8FFF
-- 0x0F00 ~ 0x0FFF
+
+#### 保留 0x8F00 ~ 0x8FFF
+
+#### 保留 0x0F00 ~ 0x0FFF

+ 1 - 1
apps/emqx_gateway_jt808/src/emqx_jt808_auth.erl

@@ -16,7 +16,7 @@
 
 init(#{allow_anonymous := true}) ->
     #auth{registry = undefined, authentication = undefined, allow_anonymous = true};
-init(#{registry := Reg, authentication := Auth, allow_anonymous := Anonymous}) ->
+init(#{allow_anonymous := Anonymous = false, registry := Reg, authentication := Auth}) ->
     #auth{registry = Reg, authentication = Auth, allow_anonymous = Anonymous}.
 
 register(_RegFrame, #auth{registry = undefined, allow_anonymous = true}) ->

+ 2 - 2
apps/emqx_gateway_jt808/src/emqx_jt808_channel.erl

@@ -153,7 +153,7 @@ init(
     Options = #{
         ctx := Ctx,
         message_queue_len := MessageQueueLen,
-        proto := ProtoConf
+        proto := #{auth := Auth} = ProtoConf
     }
 ) ->
     % TODO: init rsa_key from user input
@@ -193,7 +193,7 @@ init(
         % TODO: init rsa_key from user input
         dn_topic = maps:get(dn_topic, ProtoConf, ?DEFAULT_DN_TOPIC),
         up_topic = maps:get(up_topic, ProtoConf, ?DEFAULT_UP_TOPIC),
-        auth = emqx_jt808_auth:init(ProtoConf),
+        auth = emqx_jt808_auth:init(Auth),
         inflight = emqx_inflight:new(128),
         mqueue = queue:new(),
         max_mqueue_len = MessageQueueLen,

+ 47 - 26
apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl

@@ -49,36 +49,57 @@ fields(jt808_frame) ->
     ];
 fields(jt808_proto) ->
     [
-        {allow_anonymous, fun allow_anonymous/1},
-        {registry, fun registry_url/1},
-        {authentication, fun authentication_url/1},
+        {auth,
+            sc(
+                hoconsc:union([
+                    ref(anonymous_true), ref(anonymous_false)
+                ])
+            )},
         {up_topic, fun up_topic/1},
         {dn_topic, fun dn_topic/1}
-    ].
-
-jt808_frame_max_length(type) -> non_neg_integer();
-jt808_frame_max_length(desc) -> ?DESC(?FUNCTION_NAME);
-jt808_frame_max_length(default) -> 8192;
-jt808_frame_max_length(required) -> false;
-jt808_frame_max_length(_) -> undefined.
-
-allow_anonymous(type) -> boolean();
-allow_anonymous(desc) -> ?DESC(?FUNCTION_NAME);
-allow_anonymous(default) -> true;
-allow_anonymous(required) -> false;
-allow_anonymous(_) -> undefined.
+    ];
+fields(anonymous_true) ->
+    [
+        {allow_anonymous,
+            sc(hoconsc:union([true]), #{desc => ?DESC(allow_anonymous), required => true})}
+    ] ++ fields_reg_auth_required(false);
+fields(anonymous_false) ->
+    [
+        {allow_anonymous,
+            sc(hoconsc:union([false]), #{desc => ?DESC(allow_anonymous), required => true})}
+    ] ++ fields_reg_auth_required(true).
 
-registry_url(type) -> binary();
-registry_url(desc) -> ?DESC(?FUNCTION_NAME);
-registry_url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")];
-registry_url(required) -> false;
-registry_url(_) -> undefined.
+fields_reg_auth_required(Required) ->
+    [
+        {registry,
+            sc(binary(), #{
+                desc => ?DESC(registry_url),
+                validator => [?NOT_EMPTY("the value of the field 'registry' cannot be empty")],
+                required => Required
+            })},
+        {authentication,
+            sc(
+                binary(),
+                #{
+                    desc => ?DESC(authentication_url),
+                    validator => [
+                        ?NOT_EMPTY("the value of the field 'authentication' cannot be empty")
+                    ],
+                    required => Required
+                }
+            )}
+    ].
 
-authentication_url(type) -> binary();
-authentication_url(desc) -> ?DESC(?FUNCTION_NAME);
-authentication_url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")];
-authentication_url(required) -> false;
-authentication_url(_) -> undefined.
+jt808_frame_max_length(type) ->
+    non_neg_integer();
+jt808_frame_max_length(desc) ->
+    ?DESC(?FUNCTION_NAME);
+jt808_frame_max_length(default) ->
+    8192;
+jt808_frame_max_length(required) ->
+    false;
+jt808_frame_max_length(_) ->
+    undefined.
 
 up_topic(type) -> binary();
 up_topic(desc) -> ?DESC(?FUNCTION_NAME);

+ 106 - 37
apps/emqx_gateway_jt808/test/emqx_jt808_SUITE.erl

@@ -38,43 +38,35 @@
 %% <<"jt808/000123456789/000123456789/dn">>
 -define(JT808_DN_TOPIC, <<?JT808_MOUNTPOINT, ?JT808_PHONE, "/dn">>).
 
--define(CONF_DEFAULT, <<
-    "\n"
-    "gateway.jt808 {\n"
-    "    listeners.tcp.default {\n"
-    "      bind = "
-    ?PORT_STR
-    "\n"
-    "    }\n"
-    "    proto {\n"
-    "      allow_anonymous = false\n"
-    "      registry = "
-    "\""
-    ?PROTO_REG_SERVER_HOST
-    ?PROTO_REG_REGISTRY_PATH
-    "\"\n"
-    "      authentication = "
-    "\""
-    ?PROTO_REG_SERVER_HOST
-    ?PROTO_REG_AUTH_PATH
-    "\"\n"
-    "    }\n"
-    "}\n"
->>).
-
--define(CONF_ANONYMOUS, <<
-    "\n"
-    "gateway.jt808 {\n"
-    "    listeners.tcp.default {\n"
-    "      bind = "
-    ?PORT_STR
-    "\n"
-    "    }\n"
-    "    proto {\n"
-    "      allow_anonymous = true\n"
-    "    }\n"
-    "}\n"
->>).
+%% erlfmt-ignore
+-define(CONF_DEFAULT, <<"
+gateway.jt808 {
+  listeners.tcp.default {
+    bind = ", ?PORT_STR, "
+  }
+  proto {
+    auth {
+      allow_anonymous = false
+      registry = \"", ?PROTO_REG_SERVER_HOST, ?PROTO_REG_REGISTRY_PATH, "\"
+      authentication = \"", ?PROTO_REG_SERVER_HOST, ?PROTO_REG_AUTH_PATH, "\"
+    }
+  }
+}
+">>).
+
+%% erlfmt-ignore
+-define(CONF_ANONYMOUS, <<"
+gateway.jt808 {
+  listeners.tcp.default {
+    bind = ", ?PORT_STR, "
+  }
+  proto {
+    auth {
+      allow_anonymous = true
+    }
+  }
+}
+">>).
 
 all() ->
     emqx_common_test_helpers:all(?MODULE).
@@ -88,6 +80,12 @@ end_per_suite(_Config) ->
 init_per_testcase(Case = t_case02_anonymous_register_and_auth, Config) ->
     Apps = boot_apps(Case, ?CONF_ANONYMOUS, Config),
     [{suite_apps, Apps} | Config];
+init_per_testcase(Case, Config) when
+    Case =:= t_create_ALLOW_invalid_auth_config;
+    Case =:= t_create_DISALLOW_invalid_auth_config
+->
+    Apps = boot_apps(Case, <<>>, Config),
+    [{suite_apps, Apps} | Config];
 init_per_testcase(Case, Config) ->
     Apps = boot_apps(Case, ?CONF_DEFAULT, Config),
     [{suite_apps, Apps} | Config].
@@ -2685,3 +2683,74 @@ t_case34_dl_0x8805_single_mm_data_ctrl(_Config) ->
     {error, timeout} = gen_tcp:recv(Socket, 0, 500),
 
     ok = gen_tcp:close(Socket).
+
+t_create_ALLOW_invalid_auth_config(_Config) ->
+    test_invalid_config(create, true).
+
+t_create_DISALLOW_invalid_auth_config(_Config) ->
+    test_invalid_config(create, false).
+
+t_update_ALLOW_invalid_auth_config(_Config) ->
+    test_invalid_config(update, true).
+
+t_update_DISALLOW_invalid_auth_config(_Config) ->
+    test_invalid_config(update, false).
+
+test_invalid_config(CreateOrUpdate, AnonymousAllowed) ->
+    InvalidConfig = raw_jt808_config(AnonymousAllowed),
+    UpdateResult = create_or_update(CreateOrUpdate, InvalidConfig),
+    ?assertMatch(
+        {error, #{
+            kind := validation_error,
+            reason := matched_no_union_member,
+            path := "gateway.jt808.proto.auth"
+        }},
+        UpdateResult
+    ).
+
+create_or_update(create, InvalidConfig) ->
+    emqx_gateway_conf:load_gateway(jt808, InvalidConfig);
+create_or_update(update, InvalidConfig) ->
+    emqx_gateway_conf:update_gateway(jt808, InvalidConfig).
+
+%% Allow: allow anonymous connection, registry and authentication URL not required.
+raw_jt808_config(Allow = true) ->
+    AuthConfig = #{
+        <<"auth">> => #{
+            <<"allow_anonymous">> => Allow,
+            %% registry and authentication `NOT REQUIRED`, but can be configured
+            <<"registry">> => <<?PROTO_REG_SERVER_HOST, ?PROTO_REG_REGISTRY_PATH>>,
+            <<"authentication">> => <<?PROTO_REG_SERVER_HOST, ?PROTO_REG_AUTH_PATH>>,
+            <<"BADKEY_registry_url">> => <<?PROTO_REG_SERVER_HOST, ?PROTO_REG_REGISTRY_PATH>>
+        }
+    },
+    emqx_utils_maps:deep_merge(raw_jt808_config(), #{<<"proto">> => AuthConfig});
+%% DisAllow: required registry and authentication URL configuration to auth client.
+raw_jt808_config(DisAllow = false) ->
+    AuthConfig = #{
+        <<"auth">> => #{
+            <<"allow_anonymous">> => DisAllow
+            %% registry and authentication are required but missed here
+            %%
+            %% <<"registry">> => <<?PROTO_REG_SERVER_HOST, ?PROTO_REG_REGISTRY_PATH>>,
+            %% <<"authentication">> => <<?PROTO_REG_SERVER_HOST, ?PROTO_REG_AUTH_PATH>>
+        }
+    },
+    emqx_utils_maps:deep_merge(raw_jt808_config(), #{<<"proto">> => AuthConfig}).
+
+raw_jt808_config() ->
+    #{
+        <<"enable">> => true,
+        <<"enable_stats">> => true,
+        <<"frame">> => #{<<"max_length">> => 8192},
+        <<"idle_timeout">> => <<"30s">>,
+        <<"max_retry_times">> => 3,
+        <<"message_queue_len">> => 10,
+        <<"mountpoint">> => <<"jt808/${clientid}/">>,
+        <<"proto">> =>
+            #{
+                <<"dn_topic">> => <<"jt808/${clientid}/${phone}/dn">>,
+                <<"up_topic">> => <<"jt808/${clientid}/${phone}/up">>
+            },
+        <<"retry_interval">> => <<"8s">>
+    }.