feat(mqtt): 设备时钟同步方案B — 平台经 report_config 下发 Unix ts (协议V1.05)
设备无RTC/SNTP, 原上行 ts=mstick()/1000(上电秒数)。方案B: - net_srv.c 新增 dev_time_sync()/dev_time_now(): 门槛≥1600000000挡上电秒数, 已校准返回真Unix, 未校准退回上电秒数; 无符号相减处理mstick 49.7天回绕 - manage_mqtt_recv_message 从下行命令信封 ts 校准 (report_config主同步点) - 全部上行 ts (14处命令响应+initialize+loop_data+event_report) 改 dev_time_now() heartbeat uptime 字段保留 mstick()/1000 (运行时长非时间戳) - 协议 V1.05 §2.3 时间同步 + report_config 兼任同步点职责 - tests/test_dev_time_sync.c 6组全过 平台侧配合: 收到 initialize 后下发 report_config 时 ts 填当前 Unix 时间
This commit is contained in:
@@ -82,6 +82,32 @@ void clear_mqtt_buf(void)
|
||||
memset(mqttBuf, 0, MAX_MQTTBUF_LEN);
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* 设备时钟同步 (方案B, 2026-07-15)
|
||||
* 设备无 RTC/SNTP。上电后本地时间 = 上电秒数。平台在收到 initialize 上线后,
|
||||
* 下发 report_config 命令时于 ts 字段填当前 Unix 时间; 设备据此校准。
|
||||
* 校准后所有上行 ts = 真 Unix 时间; 未校准前退回上电秒数(平台可按量级识别)。
|
||||
* 接受任意下行命令的合法 ts 校准 (report_config 为约定主同步点)。
|
||||
*===========================================================================*/
|
||||
static uint32_t _dev_time_base_unix = 0; // 同步基准 Unix 秒, 0=未同步
|
||||
static uint32_t _dev_time_base_tick = 0; // 同步时刻的 mstick()
|
||||
|
||||
void dev_time_sync(uint32_t unix_ts)
|
||||
{
|
||||
if (unix_ts < 1600000000UL) return; // 合法性门槛(>2020-09), 挡掉上电秒数/0/异常
|
||||
_dev_time_base_unix = unix_ts;
|
||||
_dev_time_base_tick = mstick();
|
||||
PRINT("TIME: synced unix=%lu\n", (unsigned long)unix_ts);
|
||||
}
|
||||
|
||||
uint32_t dev_time_now(void)
|
||||
{
|
||||
if (_dev_time_base_unix == 0) // 未同步 → 退回上电秒数(兼容)
|
||||
return (uint32_t)(mstick() / 1000);
|
||||
/* mstick 无符号相减天然处理 49.7 天回绕 */
|
||||
return _dev_time_base_unix + (uint32_t)((mstick() - _dev_time_base_tick) / 1000);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn mStopIfError
|
||||
*
|
||||
@@ -196,7 +222,8 @@ void dev_initialize_pub(void)
|
||||
|
||||
// V1.03: 上线后发布 initialize,告知服务器设备信息
|
||||
// 格式: {msg_id, cmd:"initialize", ts, data:{dev_serial, model, hard_ver, soft_ver, extra_info:{code,csq,location}}}
|
||||
uint32_t now = (mstick() > 0) ? (uint32_t)(mstick() / 1000) : 0;
|
||||
// 首次上电尚未时钟同步 → ts=上电秒数; 平台收到本消息后经 report_config 回填真 Unix 时间
|
||||
uint32_t now = dev_time_now();
|
||||
char topic[64];
|
||||
snprintf(topic, sizeof(topic), "dld960/%s/dev", g_dev_number_str);
|
||||
sprintf((char *)mBuff,
|
||||
@@ -1116,6 +1143,15 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
uint32_t msg_id = 0;
|
||||
simple_parse_json(msg, "\"msg_id\"", tmp);
|
||||
if(strlen(tmp) > 0) msg_id = (uint32_t)strtoul(tmp, NULL, 10);
|
||||
|
||||
// 方案B: 由下行命令 ts 校准本地时钟。平台在 initialize 上线后经 report_config
|
||||
// 下发真 Unix 时间; dev_time_sync 内部有合法性门槛, 非法/上电秒数会被忽略。
|
||||
// report_config 为约定主同步点, 此处对任意携带合法 ts 的下行命令均校准。
|
||||
{
|
||||
char ts_str[16] = {0};
|
||||
simple_parse_json(msg, "\"ts\"", ts_str);
|
||||
if(strlen(ts_str) > 0) dev_time_sync((uint32_t)strtoul(ts_str, NULL, 10));
|
||||
}
|
||||
|
||||
// 去掉 temp_guide 里的引号
|
||||
char *cmd_str = temp_guide;
|
||||
@@ -1137,7 +1173,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
"\"model\":\"%s\",\"product_code\":\"960001\","
|
||||
"\"sub_code\":{\"net\":%s,\"iot\":%s},"
|
||||
"\"bus\":{\"bus1\":0,\"bus2\":0,\"bus3\":0,\"bus4\":0}}}",
|
||||
msg_id, mstick() / 1000,
|
||||
msg_id, dev_time_now(),
|
||||
g_dev_number_str, HARDWARE_VER, FIRMWARE_VER, PRODUCT_MODEL,
|
||||
g_sub_code_enable.net_enable ? "true" : "false",
|
||||
g_sub_code_enable.iot_enable ? "true" : "false");
|
||||
@@ -1170,7 +1206,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"pwd_verify\","
|
||||
"\"ts\":%lu,\"code\":0,\"msg\":\"success\"}",
|
||||
msg_id, mstick() / 1000);
|
||||
msg_id, dev_time_now());
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
PRINT("IOT: pwd_verify OK\n");
|
||||
} else {
|
||||
@@ -1178,7 +1214,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"pwd_verify\","
|
||||
"\"ts\":%lu,\"code\":2,\"msg\":\"password incorrect\"}",
|
||||
msg_id, mstick() / 1000);
|
||||
msg_id, dev_time_now());
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
}
|
||||
return;
|
||||
@@ -1191,7 +1227,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"dev_serial_set\","
|
||||
"\"ts\":%lu,\"code\":4,\"msg\":\"not implemented yet\"}",
|
||||
msg_id, mstick() / 1000);
|
||||
msg_id, dev_time_now());
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
return;
|
||||
}
|
||||
@@ -1209,7 +1245,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
"\"lssc_ip\":\"%d.%d.%d.%d\","
|
||||
"\"dns\":\"%d.%d.%d.%d\","
|
||||
"\"port\":%d}}",
|
||||
msg_id, mstick() / 1000,
|
||||
msg_id, dev_time_now(),
|
||||
local_net_cfg.lip[0], local_net_cfg.lip[1], local_net_cfg.lip[2], local_net_cfg.lip[3],
|
||||
local_net_cfg.sub[0], local_net_cfg.sub[1], local_net_cfg.sub[2], local_net_cfg.sub[3],
|
||||
local_net_cfg.gw[0], local_net_cfg.gw[1], local_net_cfg.gw[2], local_net_cfg.gw[3],
|
||||
@@ -1285,7 +1321,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"ssc_net_set\","
|
||||
"\"ts\":%lu,\"code\":0,\"msg\":\"success\"}",
|
||||
msg_id, mstick() / 1000);
|
||||
msg_id, dev_time_now());
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
PRINT("IOT: ssc_net_set done\n");
|
||||
return;
|
||||
@@ -1300,7 +1336,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
"\"data\":{"
|
||||
"\"host\":\"%s\",\"port\":%d,"
|
||||
"\"client_id\":\"%s\",\"username\":\"%s\",\"password\":\"%s\"}}",
|
||||
msg_id, mstick() / 1000,
|
||||
msg_id, dev_time_now(),
|
||||
iot_net_info.remote_addr, iot_net_info.mqtt_port,
|
||||
iot_net_info.client_id, iot_net_info.username, iot_net_info.password);
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
@@ -1363,7 +1399,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"iot_net_set\","
|
||||
"\"ts\":%lu,\"code\":0,\"msg\":\"success\"}",
|
||||
msg_id, mstick() / 1000);
|
||||
msg_id, dev_time_now());
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
PRINT("IOT: iot_net_set done\n");
|
||||
return;
|
||||
@@ -1378,7 +1414,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
"\"data\":{"
|
||||
"\"client_id_enable\":%s,"
|
||||
"\"topic_pub\":\"%s\",\"topic_sub\":\"%s\"}}",
|
||||
msg_id, mstick() / 1000,
|
||||
msg_id, dev_time_now(),
|
||||
g_iot_topic.clientid_enable ? "true" : "false",
|
||||
g_iot_topic.topic_pub, g_iot_topic.topic_sub);
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
@@ -1425,7 +1461,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"iot_topic_set\","
|
||||
"\"ts\":%lu,\"code\":0,\"msg\":\"success\"}",
|
||||
msg_id, mstick() / 1000);
|
||||
msg_id, dev_time_now());
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
PRINT("IOT: iot_topic_set done\n");
|
||||
return;
|
||||
@@ -1437,7 +1473,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"pwd_set\","
|
||||
"\"ts\":%lu,\"code\":4,\"msg\":\"not implemented yet\"}",
|
||||
msg_id, mstick() / 1000);
|
||||
msg_id, dev_time_now());
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
return;
|
||||
}
|
||||
@@ -1448,7 +1484,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"factory_reset\","
|
||||
"\"ts\":%lu,\"code\":0,\"msg\":\"success\"}",
|
||||
msg_id, mstick() / 1000);
|
||||
msg_id, dev_time_now());
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
PRINT("IOT: factory_reset — resetting...\n");
|
||||
Delay_Ms(200);
|
||||
@@ -1516,7 +1552,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
"\"data\":{"
|
||||
"\"sensor_type\":%d,\"enable\":%s,\"once\":%s,\"env_eval\":%s,"
|
||||
"\"interval\":%u,\"ack_required\":%s,\"timeout\":%u}}",
|
||||
msg_id, mstick() / 1000,
|
||||
msg_id, dev_time_now(),
|
||||
g_report_cfg.sensor_type,
|
||||
g_report_cfg.enable ? "true" : "false",
|
||||
g_report_cfg.once ? "true" : "false",
|
||||
@@ -1546,7 +1582,7 @@ void manage_mqtt_recv_message(char * msg, int length)
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"msg_id\":%lu,\"cmd\":\"%s\","
|
||||
"\"ts\":%lu,\"code\":4,\"msg\":\"unsupported command\"}",
|
||||
msg_id, cmd_str, mstick() / 1000);
|
||||
msg_id, cmd_str, dev_time_now());
|
||||
mqtt_publish(resp_topic, resp, 1);
|
||||
PRINT("IOT: unsupported cmd=%s\n", cmd_str);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user