设备的RTC大部分场景是有用的,但RTC芯片增加了成本,而实现NTP网络协议又增加了系统的复杂性。如果物联网系统能够提供NTP校时是性价比最高的方案。
1. IOT平台的NTP支持
1)设备开发的系统级Topic
在腾讯云iotexplorer的产品开发>设备开发>Topic列表
设备端pub一个”请求“,格式正确的化,iot hub会回复一个,设备端需要sub这个主题进行解析。
2)腾讯云文档接口描述
根据文档就知道了具体流程,和消息报文的格式。
2. 实现过程
2.1 设备端 pub/sub topic
代码语言:javascript复制void mqtt_report_task_entry(void *arg) {
// 初始mqtt链接
// ...
// sub 其他主题:property report reply, data
// ...
// sub 系统
size = snprintf(ntp_replay_topic_name, TOPIC_NAME_MAX_SIZE, "$sys/operation/result/%s/%s", product_id, device_name);
if (size < 0 || size > sizeof(ntp_replay_topic_name) - 1) {
printf("sub topic 2 content length not enough! content size:%d buf size:%d", size, (int)sizeof(ntp_replay_topic_name));
}
// 注册回调函数处理ntp回复报文 ntp_message_handler
if (tos_tf_module_mqtt_sub(ntp_replay_topic_name, QOS0, ntp_message_handler) != 0) {
printf("module mqtt sub 2 failn");
} else {
printf("module mqtt sub 2 successn");
}
// 循环处理pub主题
while (1) {
// 等待sem信号,以及fifo传来pub主题类型
tos_sem_pend(&status_change, TOS_TIME_FOREVER);
err = tos_chr_fifo_pop(&status_fifo, &dev_status);
// 其他主题发送请求
// ...
// 1: ntp time sync
else if (dev_status == PUB_TYPE_NTP) {
snprintf(payload, sizeof(payload), SYS_MQTT_GET_RESOURCE_TIME);
if (tos_tf_module_mqtt_pub(ntp_topic_name, QOS0, payload) != 0) {
printf("module mqtt pub failn");
// break;
continue;
} else {
printf("module mqtt pub successn");
}
}
}
}
2.2 sub 回调函数处理数据
代码语言:javascript复制 void ntp_message_handler(mqtt_message_t* msg)
{
// {
// "type": "get",
// "time": 1621562342,
// "ntptime1": 1621562342773,
// "ntptime2": 1621562342773
// }
cJSON* cjson_root = NULL;
cJSON* cjson_time = NULL;
cJSON* cjson_ntptime1 = NULL;
cJSON* cjson_ntptime2 = NULL;
uint32_t time_get = 0;
uint64_t ntptime1 = 0;
uint64_t ntptime2 = 0;
cjson_root = cJSON_Parse((char*)msg->payload 1);
if (cjson_root == NULL) {
printf("report reply message parser failrn");
goto end;
}
cjson_time = cJSON_GetObjectItem(cjson_root, "time");
if (cjson_time == NULL) {
printf("report reply message parser failrn");
goto end;
}
time_get = cjson_time->valueint;
cjson_ntptime1 = cJSON_GetObjectItem(cjson_root, "ntptime1");
if (cjson_ntptime1 == NULL) {
printf("report reply message parser failrn");
goto end;
}
ntptime1 = cjson_ntptime1->valuelonglong;
cjson_ntptime2 = cJSON_GetObjectItem(cjson_root, "ntptime2");
if (cjson_ntptime2 == NULL) {
printf("report reply message parser failrn");
goto end;
}
ntptime2 = cjson_ntptime2->valuelonglong;
printf("time_get:%drn", time_get);
printf("ntptime1:%lld rn", ntptime1);
printf("ntptime2:%lld rn", ntptime2);
tos_systick_set(ntptime2);
g_last_time = ntptime2;
g_sys_status.ntp_ok = 1;
retry_wait = 0;
end:
cJSON_Delete(cjson_root);
cjson_root = NULL;
return;
}
2.3 使用RTC
代码语言:javascript复制void get_localtime()
{
k_tick_t now;
struct tm *time_info_get;
//shanghai 8: 28800
now = tos_systick_get() / 1000 28800 ;
time_info_get = localtime(&now);
g_time_info = *time_info_get;
}
void disp_date_time(u8 mode)
{
char lcd_buf[30] = {0};
get_localtime();
if(mode)
{
sprintf(lcd_buf, "M-d-d", g_time_info.tm_year 1900, g_time_info.tm_mon 1, g_time_info.tm_mday);
LCD_ShowString(0,80,lcd_buf, WHITE, BLACK, 32, 0);
}
sprintf(lcd_buf, "d:d:d", g_time_info.tm_hour, g_time_info.tm_min, g_time_info.tm_sec);
LCD_ShowString(0,110,lcd_buf, WHITE, BLACK, 32, 0);
}
3. CJson 64bit支持
cJSON本身不支持64位的整形数据解析和增加,k_tick_t是64bit长整型,需要修改。
主要参照《cJSON支持64位数据解析_zh7152106的博客》实现。