feat(iot_mqtt): loop_data 上报调度升级三档 — car_state 沿立即上报

原双速率下进/出车沿最坏等 300ms 门控。改为三档:
- 立即档: 任一通道 car_state 翻转沿 → 直通间隔门控立即发布
- 快速档: |variation|>阈值 → 300ms (不变)
- 空闲档: 配置 interval, 默认 60s (不变)

要点:
- car_edge 优先级最高; 快照仍在门控后刷新, 同沿只触发一次立即档
- 防洪泛天然有界: Loop 事件帧最快 150ms/帧 且 car_state 为防抖后状态
- 协议 §5.2 补上报节奏说明; tests/test_report_cadence.c 8 组全过
This commit is contained in:
wangfq
2026-07-15 16:56:21 +08:00
parent 3e28174b40
commit a457b81916
4 changed files with 135 additions and 18 deletions
@@ -572,11 +572,14 @@ static void iot_process_recv(void) {
}
/*===========================================================================
* 传感器数据上报 (双速率: 空闲态按 interval 上报, 变化态 300ms 快速上报)
* 传感器数据上报 (三档调度)
* 立即档: car_state 翻转沿 → 直通门控立即上报 (进/出车不等间隔)
* 快速档: |variation| > 阈值 → 300ms
* 空闲档: 按配置 interval (默认 60s, 最小 1s)
*
* Step 1 — 消费 Loop MCU 新帧 → 更新缓存
* Step 2 — 对所有通道检测 variation, 决定上报间隔
* Step 3 — 间隔门控: 时间到了才从缓存发布
* Step 1 — 消费 Loop MCU 新帧 → 事件沿检测 + 更新缓存
* Step 2 — 判定上报档位 (car_edge / fast_mode / idle)
* Step 3 — 间隔门控 (car_edge 直通)
*===========================================================================*/
void iot_mqtt_publish_sensor(void) {
static uint8_t _last_car_state[4] = {0};
@@ -611,31 +614,33 @@ void iot_mqtt_publish_sensor(void) {
/* 尚无缓存数据 → 不发 */
if (!_cached_sr_valid) return;
/*--- Step 2: 判断是否进入变化态 (任一通道 |variation|>=阈值, 或 car_state 翻转沿) ---*/
/*--- Step 2: 判定上报档位 (三档) ---
car_edge : 任一通道 car_state 翻转沿 → 【立即上报】直通间隔门控
fast_mode : 任一通道 |variation|>阈值 → 300ms 快速档
否则 : 空闲档, 按配置 interval (默认 60s, 最小 1s) */
uint32_t interval_ms;
uint8_t fast_mode = 0;
uint8_t car_edge = 0;
{
uint8_t i;
for (i = 0; i < _cached_sr.coil_count; i++) {
/* car_state 翻转沿(进车/出车)优先级最高, 命中即定档 */
if (_last_car_state[i] != _cached_sr.coils[i].car_state) {
car_edge = 1;
break;
}
// 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;
break;
}
/* car_state 翻转沿(进车/出车) 同样触发快速上报
注: 能走到这里 fast_mode 必为 0 (置 1 即 break), 无需再判 */
if (_last_car_state[i] != _cached_sr.coils[i].car_state) {
fast_mode = 1;
break;
fast_mode = 1; /* 记录但不 break: 后续通道可能有沿(优先级更高) */
}
}
}
if (fast_mode) {
interval_ms = IOT_MQTT_FAST_INTERVAL_MS; // 300ms
if (fast_mode || car_edge) {
interval_ms = IOT_MQTT_FAST_INTERVAL_MS; // 300ms (car_edge 时门控被直通, 仅作记录)
} else {
/* 空闲态: 使用配置的 interval (秒→毫秒), 最小 1s */
uint32_t cfg_ms = (uint32_t)g_report_cfg.interval * 1000;
@@ -643,12 +648,15 @@ void iot_mqtt_publish_sensor(void) {
? cfg_ms : IOT_MQTT_IDLE_INTERVAL_MIN_MS;
}
/*--- Step 3: 间隔门控 ---*/
/*--- Step 3: 间隔门控 (car_edge 直通: 进/出车立即上报, 不等间隔) ---
防洪泛天然有界: Loop MCU 事件帧最快 150ms 一帧, 且发布后快照即同步,
同一个沿不会重复触发立即档 */
{
uint32_t now = mstick();
if (_last_publish_ms != 0
if (!car_edge
&& _last_publish_ms != 0
&& (now - _last_publish_ms) < interval_ms) {
return; // 未到间隔; _last_car_state 不刷新, 翻转沿保持"待发", 持续顶住 fast_mode
return; // 未到间隔; _last_car_state 不刷新, 翻转沿保持"待发"
}
_last_publish_ms = now;
}