feat(vd960DBN): offlog 协议导出命令分发 — log_stat/log_query/log_clear 落地
协议先行 (08893d5, MQTT V1.06 + TCP JSON V1.02) 的固件侧实现:
- offlog 新增导出 API: enabled/seq_last/type_str/evt_to_json
(seq_first=seq_last-count+1, idx=start_seq-seq_first, count≤4)
- MQTT iot_handle_publish 三分支: log_stat/log_query/log_clear
(log_query 响应 static buf 防大栈; log_clear 阻塞~2.8s 主循环可接受)
- TCP JSON 三 handler + cmd 表 (需鉴权)
- 单测新增 test_export_json (8 例全过): boot rst 大端/coil sub/evt_retry/data:null/seq 公式
- devlog V3.9
This commit is contained in:
@@ -344,6 +344,104 @@ int offlog_read_idx(uint16_t idx, OfflogEvt *out)
|
||||
return offlog_evt_read_at(read_off, out);
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* 协议导出 (MQTT V1.06 / TCP JSON V1.02 共用)
|
||||
*===========================================================================*/
|
||||
uint8_t offlog_enabled(void)
|
||||
{
|
||||
return _ready;
|
||||
}
|
||||
|
||||
uint32_t offlog_seq_last(void)
|
||||
{
|
||||
return (_wr_seq > 0) ? (_wr_seq - 1) : 0;
|
||||
}
|
||||
|
||||
const char *offlog_type_str(uint8_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case OFFLOG_EVT_BOOT: return "boot";
|
||||
case OFFLOG_EVT_IOT_CONNECT: return "iot_connect";
|
||||
case OFFLOG_EVT_IOT_READY: return "iot_ready";
|
||||
case OFFLOG_EVT_IOT_DISCONN: return "iot_disconnect";
|
||||
case OFFLOG_EVT_IOT_RECONN: return "iot_reconn";
|
||||
case OFFLOG_EVT_EVT_RETRY: return "evt_retry";
|
||||
case OFFLOG_EVT_EVT_GIVEUP: return "evt_giveup";
|
||||
case OFFLOG_EVT_COIL: return "coil";
|
||||
case OFFLOG_EVT_TIME_ANCHOR: return "time_anchor";
|
||||
case OFFLOG_EVT_LOG_CLEAR: return "log_clear";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* 线圈事件子类型: 1=进 2=出 3=断开 4=恢复
|
||||
(与 iot_mqtt_srv.c offlog_coil 调用一致) */
|
||||
static const char *offlog_coil_sub_str(uint8_t sub)
|
||||
{
|
||||
switch (sub) {
|
||||
case 1: return "car_enter";
|
||||
case 2: return "car_leave";
|
||||
case 3: return "loop_cut";
|
||||
case 4: return "loop_restore";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* payload 大端 uint32 (与 offlog_boot/offlog_coil 写入一致) */
|
||||
static uint32_t offlog_payload_u32(const uint8_t *p)
|
||||
{
|
||||
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
|
||||
}
|
||||
|
||||
/* 记录 → JSON 对象 (data 按事件类型组装; 无参数事件 data=null)
|
||||
回返 snprintf 写入长度; 调用方须保证 buf_len 充足 (一条最大约130B) */
|
||||
int offlog_evt_to_json(const OfflogEvt *e, char *buf, int buf_len)
|
||||
{
|
||||
const char *type = offlog_type_str(e->type);
|
||||
char data[96];
|
||||
|
||||
switch (e->type) {
|
||||
case OFFLOG_EVT_BOOT:
|
||||
snprintf(data, sizeof(data), "{\"rst\":%lu}",
|
||||
(unsigned long)offlog_payload_u32(e->payload));
|
||||
break;
|
||||
case OFFLOG_EVT_IOT_DISCONN:
|
||||
snprintf(data, sizeof(data), "{\"reason\":%u}", e->payload[0]);
|
||||
break;
|
||||
case OFFLOG_EVT_IOT_RECONN:
|
||||
snprintf(data, sizeof(data), "{\"backoff_ms\":%lu}",
|
||||
(unsigned long)offlog_payload_u32(e->payload));
|
||||
break;
|
||||
case OFFLOG_EVT_EVT_RETRY:
|
||||
snprintf(data, sizeof(data), "{\"msg_id\":%lu,\"retry\":%u}",
|
||||
(unsigned long)offlog_payload_u32(e->payload), e->payload[4]);
|
||||
break;
|
||||
case OFFLOG_EVT_EVT_GIVEUP:
|
||||
snprintf(data, sizeof(data), "{\"msg_id\":%lu}",
|
||||
(unsigned long)offlog_payload_u32(e->payload));
|
||||
break;
|
||||
case OFFLOG_EVT_COIL:
|
||||
snprintf(data, sizeof(data), "{\"sub\":\"%s\",\"ch\":%u,\"value\":%lu}",
|
||||
offlog_coil_sub_str(e->payload[0]), e->payload[1],
|
||||
(unsigned long)offlog_payload_u32(e->payload + 2));
|
||||
break;
|
||||
default:
|
||||
data[0] = '\0'; /* iot_connect/iot_ready/time_anchor/log_clear → null */
|
||||
break;
|
||||
}
|
||||
|
||||
if (data[0] == '\0') {
|
||||
return snprintf(buf, buf_len,
|
||||
"{\"seq\":%lu,\"boot_seq\":%u,\"ts_ms\":%lu,\"unix_ts\":%lu,\"type\":\"%s\",\"data\":null}",
|
||||
(unsigned long)e->seq, (unsigned)e->boot_seq,
|
||||
(unsigned long)e->ts_ms, (unsigned long)e->unix_ts, type);
|
||||
}
|
||||
return snprintf(buf, buf_len,
|
||||
"{\"seq\":%lu,\"boot_seq\":%u,\"ts_ms\":%lu,\"unix_ts\":%lu,\"type\":\"%s\",\"data\":%s}",
|
||||
(unsigned long)e->seq, (unsigned)e->boot_seq,
|
||||
(unsigned long)e->ts_ms, (unsigned long)e->unix_ts, type, data);
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* 清空 (审计: 清空后写一条 LOG_CLEAR)
|
||||
*===========================================================================*/
|
||||
|
||||
Reference in New Issue
Block a user