From 1e9c978f366c4efd8b1f6a489d31660ba6b75592 Mon Sep 17 00:00:00 2001 From: JimMoen Date: Sun, 17 Dec 2023 21:30:49 +0800 Subject: [PATCH 1/3] fix(gw_jt808): split anonymous true/false conf schema --- .../src/emqx_jt808_auth.erl | 2 +- .../src/emqx_jt808_channel.erl | 4 +- .../src/emqx_jt808_schema.erl | 42 ++++++++---- .../test/emqx_jt808_SUITE.erl | 64 ++++++++----------- 4 files changed, 59 insertions(+), 53 deletions(-) diff --git a/apps/emqx_gateway_jt808/src/emqx_jt808_auth.erl b/apps/emqx_gateway_jt808/src/emqx_jt808_auth.erl index aeba537e8..0e5949ba7 100644 --- a/apps/emqx_gateway_jt808/src/emqx_jt808_auth.erl +++ b/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}) -> diff --git a/apps/emqx_gateway_jt808/src/emqx_jt808_channel.erl b/apps/emqx_gateway_jt808/src/emqx_jt808_channel.erl index 052065ef5..12776a261 100644 --- a/apps/emqx_gateway_jt808/src/emqx_jt808_channel.erl +++ b/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, diff --git a/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl b/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl index 35d8f962d..70e9753bd 100644 --- a/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl +++ b/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl @@ -49,24 +49,38 @@ 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} + ]; +fields(anonymous_true) -> + [ + {allow_anonymous, + sc(hoconsc:union([true]), #{desc => ?DESC(allow_anonymous), required => true})} + ]; +fields(anonymous_false) -> + [ + {allow_anonymous, + sc(hoconsc:union([false]), #{desc => ?DESC(allow_anonymous), required => true})}, + {registry, fun registry_url/1}, + {authentication, fun authentication_url/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. +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. registry_url(type) -> binary(); registry_url(desc) -> ?DESC(?FUNCTION_NAME); diff --git a/apps/emqx_gateway_jt808/test/emqx_jt808_SUITE.erl b/apps/emqx_gateway_jt808/test/emqx_jt808_SUITE.erl index d9200bc9e..8644fe66f 100644 --- a/apps/emqx_gateway_jt808/test/emqx_jt808_SUITE.erl +++ b/apps/emqx_gateway_jt808/test/emqx_jt808_SUITE.erl @@ -38,43 +38,35 @@ %% <<"jt808/000123456789/000123456789/dn">> -define(JT808_DN_TOPIC, <>). --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" ->>). +%% 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, "\" + } + } +} +">>). --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_ANONYMOUS, <<" +gateway.jt808 { + listeners.tcp.default { + bind = ", ?PORT_STR, " + } + proto { + auth { + allow_anonymous = true + } + } +} +">>). all() -> emqx_common_test_helpers:all(?MODULE). From f38ab4bd3986774644ed4c73443c44308985ad8a Mon Sep 17 00:00:00 2001 From: JimMoen Date: Mon, 18 Dec 2023 01:36:10 +0800 Subject: [PATCH 2/3] fix(gw_jt808): same struct `proto.auth` to persistent reg/auth URL --- .../src/emqx_jt808_schema.erl | 39 +++++---- .../test/emqx_jt808_SUITE.erl | 79 ++++++++++++++++++- 2 files changed, 101 insertions(+), 17 deletions(-) diff --git a/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl b/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl index 70e9753bd..3e0c31f5d 100644 --- a/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl +++ b/apps/emqx_gateway_jt808/src/emqx_jt808_schema.erl @@ -62,13 +62,32 @@ 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})}, - {registry, fun registry_url/1}, - {authentication, fun authentication_url/1} + sc(hoconsc:union([false]), #{desc => ?DESC(allow_anonymous), required => true})} + ] ++ fields_reg_auth_required(true). + +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 + } + )} ]. jt808_frame_max_length(type) -> @@ -82,18 +101,6 @@ jt808_frame_max_length(required) -> jt808_frame_max_length(_) -> undefined. -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. - -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. - up_topic(type) -> binary(); up_topic(desc) -> ?DESC(?FUNCTION_NAME); up_topic(default) -> ?DEFAULT_UP_TOPIC; diff --git a/apps/emqx_gateway_jt808/test/emqx_jt808_SUITE.erl b/apps/emqx_gateway_jt808/test/emqx_jt808_SUITE.erl index 8644fe66f..20aae1acb 100644 --- a/apps/emqx_gateway_jt808/test/emqx_jt808_SUITE.erl +++ b/apps/emqx_gateway_jt808/test/emqx_jt808_SUITE.erl @@ -62,7 +62,7 @@ gateway.jt808 { } proto { auth { - allow_anonymous = true + allow_anonymous = true } } } @@ -80,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]. @@ -2677,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">> => <>, + <<"authentication">> => <>, + <<"BADKEY_registry_url">> => <> + } + }, + 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">> => <>, + %% <<"authentication">> => <> + } + }, + 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">> + }. From 725e7a17bb08c10394a803afb32f1a4beaf75112 Mon Sep 17 00:00:00 2001 From: JimMoen Date: Mon, 18 Dec 2023 03:21:49 +0800 Subject: [PATCH 3/3] docs(gw_jt808): fix and reformat data exchange guide --- .../doc/Data_Exchange_Guide_CN.md | 439 +++++++++++------- 1 file changed, 260 insertions(+), 179 deletions(-) diff --git a/apps/emqx_gateway_jt808/doc/Data_Exchange_Guide_CN.md b/apps/emqx_gateway_jt808/doc/Data_Exchange_Guide_CN.md index d786369d2..4f2c4c41c 100644 --- a/apps/emqx_gateway_jt808/doc/Data_Exchange_Guide_CN.md +++ b/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 + + +- 位置附加信息项列表, 在 `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 + + +#### 提问应答 `"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