proto(V1.05): variation 由 2B无符号 扩展为 3B有符号
背景: variation 是遥测量, 用于离线跟踪分析车检器算法。原 2B 无符号 存在两个缺陷: (1)CAPVD域量级~131072, 大车全覆盖时偏差可超65535而回绕, 污染数据; (2)绝对值丢失方向, 分不清'车进入'与'反向漂移'。 改动 (三端联动, 同版本发布): - 协议 DLD960Loop_串口通信协议.md: 变化量 2B->3B有符号补码, 定义 variation=Origin-CAPVD (正=车/裕量, 负=反向漂移); 每单元11->12B, Len 47->51; 补符号扩展说明; 示例报文重算(XOR=FE SUM=38); 修订记录V1.05 - vd960Loop main.c: 组包 uint32->int32, Origin-CAPVD, 3B LE, +-2^23饱和防回绕 - vd960DBN loop_uart_proto.h: variation uint16->int32 - vd960DBN loop_uart_proto.c: 步长11->12, data_len/11->/12, misc偏移右移1B, variation 3B解码+bit23符号扩展 - vd960DBN iot_mqtt_srv.c: fast_mode 阈值判断改 abs(variation)>=10, 正负变化都加速 验证: 本地 gcc 隔离单测 编解码往返/符号扩展/饱和/方向语义/fast_mode 全通过; 大车 diff=100000 旧版回绕34464 新版正确保留。字节账: 帧56B < Loop缓冲64B < DBN缓冲512B < MSS576, 均不溢出。整体固件编译需在 Keil/MounRiver 侧完成。
This commit is contained in:
+15
-10
@@ -214,28 +214,32 @@ SensData:传感数据
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 配置 1 | 1 | freq\_level(2bit), Direction(1bit),freq\_type(1bit), sens(4bit) | 线圈 1 配置freq\_level:高低频,两个比特位,00 表示高频(33nF),01表示中高(43nF), 10表示中低(66nF), 11表示低频(76nF)。Direction: 0 表示触发,1 表示方向判别,freq\_type: 0 表示初始频率,1 表示当前实时频率。sens:低四位表示当前的灵敏度等级 |
|
| 配置 1 | 1 | freq\_level(2bit), Direction(1bit),freq\_type(1bit), sens(4bit) | 线圈 1 配置freq\_level:高低频,两个比特位,00 表示高频(33nF),01表示中高(43nF), 10表示中低(66nF), 11表示低频(76nF)。Direction: 0 表示触发,1 表示方向判别,freq\_type: 0 表示初始频率,1 表示当前实时频率。sens:低四位表示当前的灵敏度等级 |
|
||||||
| 线圈评估条件 | 1 | condition(4bit), loop\_state(1bit),<br>car\_state(1bit),<br>report\_msic(2bit) | loop\_condition 正常(0)有效,环境状态条件(环境状态评估值,值越大,干扰越大),高四位有效。低四位中 ,其中第3位表示线圈状态,0 表示正常,1 表示线圈断开;第 2 位表示有无车,0 表示无车,1 表示有车;低两位表示**杂项类型**,0b00表示时间量,0b01表示线圈断开次数;0b10表示车流量数;0b11表示继电器输出次数 |
|
| 线圈评估条件 | 1 | condition(4bit), loop\_state(1bit),<br>car\_state(1bit),<br>report\_msic(2bit) | loop\_condition 正常(0)有效,环境状态条件(环境状态评估值,值越大,干扰越大),高四位有效。低四位中 ,其中第3位表示线圈状态,0 表示正常,1 表示线圈断开;第 2 位表示有无车,0 表示无车,1 表示有车;低两位表示**杂项类型**,0b00表示时间量,0b01表示线圈断开次数;0b10表示车流量数;0b11表示继电器输出次数 |
|
||||||
| 频率 1 | 3 | frequent | 低字节在前 |
|
| 频率 1 | 3 | frequent | 低字节在前,无符号 |
|
||||||
| 变化量 1 | 2 | variation | 低字节在前 |
|
| 变化量 1 | 3 | variation | **有符号** 3 字节,低字节在前(小端),补码表示。定义 `variation = loop_Origin − loop_CAPVD`(基线 − 当前值)。**正值**表示当前值低于基线(车辆/金属进入,检测裕量方向);**负值**表示当前值高于基线(反向漂移/异常抬升)。值域 ±8388607(±2²³−1),发送端已做饱和限幅,不会回绕。<br>**接收端解析**:读入 3 字节后须做符号扩展——`v = b0\|(b1<<8)\|(b2<<16); if (v & 0x800000) v \|= 0xFF000000;` |
|
||||||
| 杂项 | 4 | in\_out\_passtime/cut\_amount/flow\_amount | **杂项类型**,可能是时间量,也可能是线圈断开次数、车流量数,说明:<br>1、时间量有两种类型,通过时间或车间距,5ms为单位。通过时间是从有车开始到车辆离开的时间(上报时car\_state 为0);车间距是 从上一次车辆离开到有车时候的时间(上报时car\_state 为1)。非0有效。<br>2、线圈断开次数。<br>3、车流量数。<br>4、继电器输出次数。 |
|
| 杂项 | 4 | in\_out\_passtime/cut\_amount/flow\_amount | **杂项类型**,可能是时间量,也可能是线圈断开次数、车流量数,说明:<br>1、时间量有两种类型,通过时间或车间距,5ms为单位。通过时间是从有车开始到车辆离开的时间(上报时car\_state 为0);车间距是 从上一次车辆离开到有车时候的时间(上报时car\_state 为1)。非0有效。<br>2、线圈断开次数。<br>3、车流量数。<br>4、继电器输出次数。 |
|
||||||
|
|
||||||
eg:
|
eg:
|
||||||
|
|
||||||
`7F 00 2F C0 0C 00 12 00 2A 0F 01 07 00 00 00 00 00 D2 00 75 B7 00 01 00 00 00 00 00 12 00 EC 0C 01 02 00 00 00 00 00 92 00 83 C3 00 02 00 00 00 00 00 E2 34`
|
`7F 00 33 C0 0C 00 12 00 2A 0F 01 07 00 00 00 00 00 00 D2 00 75 B7 00 01 00 00 00 00 00 00 12 00 EC 0C 01 02 00 00 00 00 00 00 92 00 83 C3 00 02 00 00 00 00 00 00 FE 38`
|
||||||
|
|
||||||
指令解释
|
指令解释
|
||||||
|
|
||||||
```python
|
```python
|
||||||
7F Magic Byte
|
7F Magic Byte
|
||||||
00 Addr,0 default
|
00 Addr,0 default
|
||||||
2F Len, 0x2F=47个字节(Cmd + Data)
|
33 Len, 0x33=51个字节(Cmd + Data)
|
||||||
C0 Cmd
|
C0 Cmd
|
||||||
0C SensType,传感数据类型,0x0C为 多线圈传感信息,960Loop为 四路线圈车检器,会有4个传感数据单元
|
0C SensType,传感数据类型,0x0C为 多线圈传感信息,960Loop为 四路线圈车检器,会有4个传感数据单元
|
||||||
00 SubPkgFlag,分包标记,00 表示无分包,是一条数据完整的记录。
|
00 SubPkgFlag,分包标记,00 表示无分包,是一条数据完整的记录。
|
||||||
12 00 2A 0F 01 07 00 00 00 00 00:线圈1传感数据单元。0b00 高频,0b0 触发模式,0b1实时频率,0b0010 表示2级灵敏度;0b0000环境正常,0b0线圈正常,0b0当前无车,0b00 表示当前杂项参数为时间量;0x010F2A,频率为69418Hz;0x0007,变化量为7;0x00000000,时间量为为0
|
(每路线圈单元 = 12 字节:config1(1) + eval(1) + freq(3) + variation(3, 有符号) + misc(4))
|
||||||
D2 00 75 B7 00 01 00 00 00 00 00:线圈2传感数据单元。0b11 低频,0b0 触发模式,0b1实时频率,0b0010 表示2级灵敏度;0b0000环境正常,0b0线圈正常,0b0当前无车,0b00 表示当前杂项参数为时间量;0x00B775,频率为46965Hz;0x0001,变化量为1;0x00000000,时间量为为0
|
12 00 2A 0F 01 07 00 00 00 00 00 00:线圈1传感数据单元。0b00 高频,0b0 触发模式,0b1实时频率,0b0010 表示2级灵敏度;0b0000环境正常,0b0线圈正常,0b0当前无车,0b00 表示当前杂项参数为时间量;0x010F2A,频率为69418Hz;0x000007,变化量为 +7(当前值低于基线,正常裕量);0x00000000,时间量为0
|
||||||
12 00 EC 0C 01 02 00 00 00 00 00:线圈3传感数据单元。0b00 高频,0b0 触发模式,0b1实时频率,0b0010 表示2级灵敏度;0b0000环境正常,0b0线圈正常,0b0当前无车,0b00 表示当前杂项参数为时间量;0x010CEC,频率为68844Hz;0x0002,变化量为2;0x00000000,时间量为为0
|
D2 00 75 B7 00 01 00 00 00 00 00 00:线圈2传感数据单元。0b11 低频,0b0 触发模式,0b1实时频率,0b0010 表示2级灵敏度;0b0000环境正常,0b0线圈正常,0b0当前无车,0b00 表示当前杂项参数为时间量;0x00B775,频率为46965Hz;0x000001,变化量为 +1;0x00000000,时间量为0
|
||||||
92 00 83 C3 00 02 00 00 00 00 00:线圈4传感数据单元。0b10 中低,0b0 触发模式,0b1实时频率,0b0010 表示2级灵敏度;0b0000环境正常,0b0线圈正常,0b0当前无车,0b00 表示当前杂项参数为时间量;0x00C383,频率为50051Hz;0x0002,变化量为2;0x00000000,时间量为为0
|
12 00 EC 0C 01 02 00 00 00 00 00 00:线圈3传感数据单元。0b00 高频,0b0 触发模式,0b1实时频率,0b0010 表示2级灵敏度;0b0000环境正常,0b0线圈正常,0b0当前无车,0b00 表示当前杂项参数为时间量;0x010CEC,频率为68844Hz;0x000002,变化量为 +2;0x00000000,时间量为0
|
||||||
E2 34 校验字节
|
92 00 83 C3 00 02 00 00 00 00 00 00:线圈4传感数据单元。0b10 中低,0b0 触发模式,0b1实时频率,0b0010 表示2级灵敏度;0b0000环境正常,0b0线圈正常,0b0当前无车,0b00 表示当前杂项参数为时间量;0x00C383,频率为50051Hz;0x000002,变化量为 +2;0x00000000,时间量为0
|
||||||
|
FE 38 校验字节(XOR=0xFE, SUM=0x38)
|
||||||
|
|
||||||
|
# 变化量为有符号 3 字节小端补码。若某通道 variation 三字节为 F6 FF FF,
|
||||||
|
# 符号扩展后 = 0xFFFFFFF6 = -10,表示当前值高于基线 10(反向漂移/异常抬升)。
|
||||||
```
|
```
|
||||||
|
|
||||||
**注意,如果有续包,最后一包上位机无返回**。中间续包上位机返回传感类型,当前收到包的序列和子包的数量:
|
**注意,如果有续包,最后一包上位机无返回**。中间续包上位机返回传感类型,当前收到包的序列和子包的数量:
|
||||||
@@ -254,4 +258,5 @@ E2 34 校验字节
|
|||||||
| V1.01 | 2026-06-22 | 补充遗漏的接口说明 | wangfq |
|
| V1.01 | 2026-06-22 | 补充遗漏的接口说明 | wangfq |
|
||||||
| V1.02 | 2026-07-02 | 查缺补漏,补充例程说明。 | wangfq |
|
| V1.02 | 2026-07-02 | 查缺补漏,补充例程说明。 | wangfq |
|
||||||
| V1.03 | 2026-07-02 | 0x8A 响应格式 + LEN 计算修正 | wangfq |
|
| V1.03 | 2026-07-02 | 0x8A 响应格式 + LEN 计算修正 | wangfq |
|
||||||
| V1.04 | 2026-07-02 | 主动上报增加继电器输出次数 类型 | wangfq |
|
| V1.04 | 2026-07-02 | 主动上报增加继电器输出次数 类型 | wangfq |
|
||||||
|
| V1.05 | 2026-07-14 | 多线圈上报(0x0C)变化量 variation 由 2 字节无符号扩展为 **3 字节有符号**(补码, 小端),定义 `variation = Origin − CAPVD`(正=车/裕量, 负=反向漂移);每单元 11→12 字节,Len 47→51。接收端须做符号扩展。**Loop 固件与 DBN 固件须同版本发布。** | wangfq |
|
||||||
@@ -97,8 +97,9 @@ typedef struct {
|
|||||||
uint8_t loop_state : 1; // 0=正常, 1=断开
|
uint8_t loop_state : 1; // 0=正常, 1=断开
|
||||||
uint8_t car_state : 1; // 0=无车, 1=有车
|
uint8_t car_state : 1; // 0=无车, 1=有车
|
||||||
uint8_t misc_type : 2; // 0=时间量, 1=断开次数, 2=车流量, 3=继电器输出次数
|
uint8_t misc_type : 2; // 0=时间量, 1=断开次数, 2=车流量, 3=继电器输出次数
|
||||||
uint32_t freq; // 频率 (3 bytes, little-endian)
|
uint32_t freq; // 频率 (3 bytes, little-endian, 无符号)
|
||||||
uint16_t variation; // 变化量 (2 bytes, little-endian)
|
int32_t variation; // 变化量 (3 bytes, little-endian, 有符号补码) — V1.05
|
||||||
|
// = Origin - CAPVD; 正=当前值低于基线(车/裕量), 负=反向漂移
|
||||||
union {
|
union {
|
||||||
uint32_t passtime_ms; // 通过时间/车间距, 50ms单位 (misc_type=0)
|
uint32_t passtime_ms; // 通过时间/车间距, 50ms单位 (misc_type=0)
|
||||||
uint32_t cut_amount; // 线圈断开次数 (misc_type=1)
|
uint32_t cut_amount; // 线圈断开次数 (misc_type=1)
|
||||||
|
|||||||
@@ -412,7 +412,10 @@ void iot_mqtt_publish_sensor(void) {
|
|||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for (i = 0; i < _cached_sr.coil_count; i++) {
|
for (i = 0; i < _cached_sr.coil_count; i++) {
|
||||||
if (_cached_sr.coils[i].variation >= IOT_MQTT_VARIATION_THRESHOLD) {
|
// variation 为有符号(V1.05): 正=车/裕量, 负=反向漂移, 两向显著变化都加速
|
||||||
|
int32_t v = _cached_sr.coils[i].variation;
|
||||||
|
int32_t av = (v >= 0) ? v : -v;
|
||||||
|
if (av >= IOT_MQTT_VARIATION_THRESHOLD) {
|
||||||
fast_mode = 1;
|
fast_mode = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -376,12 +376,12 @@ int lup_parse_set_param_resp(const uint8_t *pkg, uint16_t len, uint8_t *success)
|
|||||||
/*
|
/*
|
||||||
* Parse 0xC0/0x0C — 多路线圈传感信息
|
* Parse 0xC0/0x0C — 多路线圈传感信息
|
||||||
*
|
*
|
||||||
* 每路线圈数据单元 = 11 bytes:
|
* 每路线圈数据单元 = 12 bytes (V1.05):
|
||||||
* [0] 配置1: freq_level(2) | Direction(1) | freq_type(1) | sens(4)
|
* [0] 配置1: freq_level(2) | Direction(1) | freq_type(1) | sens(4)
|
||||||
* [1] 评估条件: condition(4) | loop_state(1) | car_state(1) | misc_type(2)
|
* [1] 评估条件: condition(4) | loop_state(1) | car_state(1) | misc_type(2)
|
||||||
* [2-4] 频率 (3 bytes, LE)
|
* [2-4] 频率 (3 bytes, LE, 无符号)
|
||||||
* [5-6] 变化量 (2 bytes, LE)
|
* [5-7] 变化量 (3 bytes, LE, 有符号补码, = Origin - CAPVD)
|
||||||
* [7-10] 杂项 (4 bytes)
|
* [8-11] 杂项 (4 bytes)
|
||||||
*/
|
*/
|
||||||
int lup_parse_sensor_report(const uint8_t *pkg, uint16_t len, LUP_SensorReport *report)
|
int lup_parse_sensor_report(const uint8_t *pkg, uint16_t len, LUP_SensorReport *report)
|
||||||
{
|
{
|
||||||
@@ -397,17 +397,17 @@ int lup_parse_sensor_report(const uint8_t *pkg, uint16_t len, LUP_SensorReport *
|
|||||||
report->sub_amount = (sub_pkg >> 4) & 0x0F;
|
report->sub_amount = (sub_pkg >> 4) & 0x0F;
|
||||||
report->sub_sequence = sub_pkg & 0x0F;
|
report->sub_sequence = sub_pkg & 0x0F;
|
||||||
|
|
||||||
// 计算线圈数: Value = sensType(1) + SubPkgFlag(1) + coil_count * 11
|
// 计算线圈数: Value = sensType(1) + SubPkgFlag(1) + coil_count * 12
|
||||||
uint16_t val_len = pkg[2]; // LEN field
|
uint16_t val_len = pkg[2]; // LEN field
|
||||||
uint16_t data_offset = 6; // 跳过 7F + Addr + LEN + CMD + SensType + SubPkgFlag
|
uint16_t data_offset = 6; // 跳过 7F + Addr + LEN + CMD + SensType + SubPkgFlag
|
||||||
uint16_t data_len = val_len - 2; // 减去 SensType + SubPkgFlag
|
uint16_t data_len = val_len - 2; // 减去 SensType + SubPkgFlag
|
||||||
|
|
||||||
uint8_t coil_count = data_len / 11;
|
uint8_t coil_count = data_len / 12;
|
||||||
if (coil_count > LUP_COIL_COUNT) coil_count = LUP_COIL_COUNT;
|
if (coil_count > LUP_COIL_COUNT) coil_count = LUP_COIL_COUNT;
|
||||||
report->coil_count = coil_count;
|
report->coil_count = coil_count;
|
||||||
|
|
||||||
for (i = 0; i < coil_count; i++) {
|
for (i = 0; i < coil_count; i++) {
|
||||||
const uint8_t *c = pkg + data_offset + i * 11;
|
const uint8_t *c = pkg + data_offset + i * 12;
|
||||||
|
|
||||||
LUP_CoilSensor *cs = &report->coils[i];
|
LUP_CoilSensor *cs = &report->coils[i];
|
||||||
cs->freq_level = (c[0] >> 6) & 0x03;
|
cs->freq_level = (c[0] >> 6) & 0x03;
|
||||||
@@ -421,9 +421,15 @@ int lup_parse_sensor_report(const uint8_t *pkg, uint16_t len, LUP_SensorReport *
|
|||||||
cs->misc_type = c[1] & 0x03;
|
cs->misc_type = c[1] & 0x03;
|
||||||
|
|
||||||
cs->freq = c[2] | ((uint32_t)c[3] << 8) | ((uint32_t)c[4] << 16);
|
cs->freq = c[2] | ((uint32_t)c[3] << 8) | ((uint32_t)c[4] << 16);
|
||||||
cs->variation = c[5] | ((uint16_t)c[6] << 8);
|
|
||||||
cs->misc.passtime_ms = c[7] | ((uint32_t)c[8] << 8)
|
// 变化量 3B 有符号 (LE) — 读入后须符号扩展 bit23
|
||||||
| ((uint32_t)c[9] << 16) | ((uint32_t)c[10] << 24);
|
{
|
||||||
|
int32_t v = c[5] | ((int32_t)c[6] << 8) | ((int32_t)c[7] << 16);
|
||||||
|
if (v & 0x800000) v |= (int32_t)0xFF000000;
|
||||||
|
cs->variation = v;
|
||||||
|
}
|
||||||
|
cs->misc.passtime_ms = c[8] | ((uint32_t)c[9] << 8)
|
||||||
|
| ((uint32_t)c[10] << 16) | ((uint32_t)c[11] << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -507,12 +507,16 @@ void uart_report_packet_loop_acs(uint8_t flag)
|
|||||||
g_pkg_uart_report.pkg[i++] = (uint8_t)((_frequent >> 8) & 0xFF);
|
g_pkg_uart_report.pkg[i++] = (uint8_t)((_frequent >> 8) & 0xFF);
|
||||||
g_pkg_uart_report.pkg[i++] = (uint8_t)((_frequent >> 16) & 0xFF);
|
g_pkg_uart_report.pkg[i++] = (uint8_t)((_frequent >> 16) & 0xFF);
|
||||||
|
|
||||||
// 变化量 (2B, LE)
|
// 变化量 (3B, LE, 有符号补码) — V1.05
|
||||||
uint32_t variation = (unit->loop_Origin > unit->loop_CAPVD)
|
// 定义: variation = Origin - CAPVD
|
||||||
? (unit->loop_Origin - unit->loop_CAPVD)
|
// 正值 = 当前值低于基线(车辆/金属进入, 检测裕量方向)
|
||||||
: (unit->loop_CAPVD - unit->loop_Origin);
|
// 负值 = 当前值高于基线(反向漂移/异常抬升)
|
||||||
|
int32_t variation = (int32_t)unit->loop_Origin - (int32_t)unit->loop_CAPVD;
|
||||||
|
if (variation > 8388607) variation = 8388607; // +2^23-1 饱和, 防回绕
|
||||||
|
if (variation < -8388608) variation = -8388608; // -2^23 饱和
|
||||||
g_pkg_uart_report.pkg[i++] = (uint8_t)(variation & 0xFF);
|
g_pkg_uart_report.pkg[i++] = (uint8_t)(variation & 0xFF);
|
||||||
g_pkg_uart_report.pkg[i++] = (uint8_t)((variation >> 8) & 0xFF);
|
g_pkg_uart_report.pkg[i++] = (uint8_t)((variation >> 8) & 0xFF);
|
||||||
|
g_pkg_uart_report.pkg[i++] = (uint8_t)((variation >> 16) & 0xFF);
|
||||||
|
|
||||||
// 杂项值 (4B, LE)
|
// 杂项值 (4B, LE)
|
||||||
g_pkg_uart_report.pkg[i++] = (uint8_t)(_misc_val[j] & 0xFF);
|
g_pkg_uart_report.pkg[i++] = (uint8_t)(_misc_val[j] & 0xFF);
|
||||||
|
|||||||
Reference in New Issue
Block a user