硬件
RT-THREAD ART-PI开发板,使用4G模块EC200进行时钟同步。
现象
msh />ntp_sync
[I/ntp] Get local time from NTP server: Fri May 28 23:02:58 2021
[I/ntp] 1622214178
[I/ntp] year:2000, month:3, day:4
[I/ntp] hour:23, min:2, sec:58
[I/ntp] Get local time from NTP server: Fri May 28 23:02:58 2021
使用ntp_sync进行网络时钟同步。年月日时间没有同步,时分秒时间同步了。
解决
修改packages\netutils\ntp\ntp.c文件中代码。
struct tm *cur_tm;
cur_tm = localtime(&cur_time);
set_time(cur_tm->tm_hour, cur_tm->tm_min, cur_tm->tm_sec);
set_date(cur_tm->tm_year + 1900, cur_tm->tm_mon + 1, cur_tm->tm_mday);
更改为
struct tm *cur_tm;
struct tm cur_tm_t;
cur_tm = &cur_tm_t;
localtime_r(&cur_time, cur_tm);
set_time(cur_tm->tm_hour, cur_tm->tm_min, cur_tm->tm_sec);
set_date(cur_tm->tm_year + 1900, cur_tm->tm_mon + 1, cur_tm->tm_mday);
或者使用设备操作替换
rt_device_control(rt_device_find("rtc"), RT_DEVICE_CTRL_RTC_SET_TIME, &cur_time);
问题分析
函数localtime调用流程。
graph LR
A[localtime] --> B[localtime_r]
B --> C[gmtime_r]
其中它返回的地址是localtime函数中声明的静态变量static struct tm tmp。
其中cur_tm指针指向struct tm tmp的地址。而后面的函数set_time(cur_tm->tm_hour, cur_tm->tm_min, cur_tm->tm_sec);会调用localtime函数,同时更改静态变量的值,同步更新cur_tm->tm_year等值。造成set_date函数中参数变化,影响年月日的设置。
使用localtime_r函数,将值保存在声明的局部变量,可修复bug。
set_time中包含localtime(),影响cur_tm指针指向的变量。
rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)
{
time_t now;
struct tm p_tm;
struct tm tm_new;
rt_device_t device;
rt_err_t ret = -RT_ERROR;
/ get current time /
now = time(RT_NULL);
/ lock scheduler. /
rt_enter_critical();
/ converts calendar time into local time. /
p_tm = localtime(&now);
/ copy the statically located variable /
rt_memcpy(&tm_new, p_tm, sizeof(struct tm));
/ unlock scheduler. /
rt_exit_critical();
/ update time. /
tm_new.tm_hour = hour;
tm_new.tm_min = minute;
tm_new.tm_sec = second;
/ converts the local time into the calendar time. /
now = mktime(&tm_new);
device = rt_device_find("rtc");
if (device == RT_NULL)
{
return -RT_ERROR;
}
/ update to RTC device. */
ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &now);
return ret;
}
原作者:HVOK_6419