Skip to content

Commit b96033a

Browse files
committed
[soft_rtc]修正GET_TIMESPEC/GET_TIMEVAL 获取 ns/us 的错误; 优化soft_rtc实现
1 parent ba509f9 commit b96033a

File tree

1 file changed

+117
-75
lines changed

1 file changed

+117
-75
lines changed

components/drivers/rtc/dev_soft_rtc.c

Lines changed: 117 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
* Change Logs:
77
* Date Author Notes
88
* 2018-01-30 armink the first version
9+
* 2025-10-30 dongly fix timespec/timeval error, optimize soft_rtc implementation
910
*/
1011

1112
#include <sys/time.h>
12-
#include <string.h>
1313
#include <rtthread.h>
1414
#include <rtdevice.h>
1515

@@ -20,11 +20,11 @@
2020
#ifdef RT_USING_SOFT_RTC
2121

2222
/* 2018-01-30 14:44:50 = RTC_TIME_INIT(2018, 1, 30, 14, 44, 50) */
23-
#define RTC_TIME_INIT(year, month, day, hour, minute, second) \
24-
{.tm_year = year - 1900, .tm_mon = month - 1, .tm_mday = day, .tm_hour = hour, .tm_min = minute, .tm_sec = second}
23+
#define RTC_TIME_INIT(year, month, day, hour, minute, second) \
24+
{ .tm_year = year - 1900, .tm_mon = month - 1, .tm_mday = day, .tm_hour = hour, .tm_min = minute, .tm_sec = second }
2525

2626
#ifndef SOFT_RTC_TIME_DEFAULT
27-
#define SOFT_RTC_TIME_DEFAULT RTC_TIME_INIT(2018, 1, 1, 0, 0 ,0)
27+
#define SOFT_RTC_TIME_DEFAULT RTC_TIME_INIT(2018, 1, 1, 0, 0, 0)
2828
#endif
2929

3030
#ifndef RTC_AUTO_SYNC_FIRST_DELAY
@@ -37,19 +37,20 @@
3737
static struct rt_work rtc_sync_work;
3838

3939
static struct rt_device soft_rtc_dev;
40-
static rt_tick_t init_tick;
41-
static time_t init_time;
42-
static struct timeval init_tv = {0};
43-
4440
#ifdef RT_USING_KTIME
45-
static struct timespec init_ts = {0};
41+
static struct timespec init_ktime_ts = { 0 };
42+
#else
43+
static rt_tick_t init_tick;
4644
#endif
45+
static struct timespec init_ts = { 0 };
4746

4847
#ifdef RT_USING_ALARM
4948

5049
static struct rt_rtc_wkalarm wkalarm;
5150
static struct rt_timer alarm_time;
5251

52+
static RT_DEFINE_SPINLOCK(_spinlock);
53+
5354
static void alarm_timeout(void *param)
5455
{
5556
rt_alarm_update(param, 1);
@@ -73,17 +74,61 @@ static void soft_rtc_alarm_update(struct rt_rtc_wkalarm *palarm)
7374

7475
#endif
7576

76-
static void set_rtc_time(time_t t)
77+
static void set_rtc_time(struct timespec *ts)
7778
{
78-
init_time = t - (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND;
79+
rt_base_t level = rt_spin_lock_irqsave(&_spinlock);
80+
init_ts.tv_sec = ts->tv_sec;
81+
init_ts.tv_nsec = ts->tv_nsec;
82+
#ifdef RT_USING_KTIME
83+
rt_ktime_boottime_get_ns(&init_ktime_ts);
84+
#else
85+
init_tick = rt_tick_get();
86+
#endif
87+
rt_spin_unlock_irqrestore(&_spinlock, level);
7988
#ifdef RT_USING_ALARM
8089
soft_rtc_alarm_update(&wkalarm);
8190
#endif
8291
}
8392

93+
static void get_rtc_time(struct timespec *ts)
94+
{
95+
rt_base_t level;
96+
97+
if (!ts)
98+
return;
99+
100+
level = rt_spin_lock_irqsave(&_spinlock);
101+
#ifdef RT_USING_KTIME
102+
struct timespec current_ts;
103+
rt_ktime_boottime_get_ns(&current_ts);
104+
105+
/* Calculate time difference */
106+
ts->tv_sec = init_ktime_ts.tv_sec + (current_ts.tv_sec - init_ktime_ts.tv_sec);
107+
ts->tv_nsec = init_ktime_ts.tv_nsec + (current_ts.tv_nsec - init_ktime_ts.tv_nsec);
108+
#else
109+
rt_tick_t tick = rt_tick_get_delta(init_tick);
110+
ts->tv_sec = init_ts.tv_sec + tick / RT_TICK_PER_SECOND;
111+
ts->tv_nsec = init_ts.tv_nsec + ((tick % RT_TICK_PER_SECOND) * (1000000000UL / RT_TICK_PER_SECOND));
112+
#endif
113+
/* Handle nanosecond overflow */
114+
if (ts->tv_nsec >= 1000000000L)
115+
{
116+
ts->tv_sec++;
117+
ts->tv_nsec -= 1000000000L;
118+
}
119+
/* Handle nanosecond underflow */
120+
if (ts->tv_nsec < 0)
121+
{
122+
ts->tv_sec--;
123+
ts->tv_nsec += 1000000000L;
124+
}
125+
rt_spin_unlock_irqrestore(&_spinlock, level);
126+
}
127+
84128
static rt_err_t soft_rtc_control(rt_device_t dev, int cmd, void *args)
85129
{
86130
time_t *t;
131+
rt_base_t level;
87132
struct tm time_temp;
88133

89134
RT_ASSERT(dev != RT_NULL);
@@ -93,94 +138,87 @@ static rt_err_t soft_rtc_control(rt_device_t dev, int cmd, void *args)
93138
{
94139
case RT_DEVICE_CTRL_RTC_GET_TIME:
95140
{
96-
t = (time_t *) args;
97-
*t = init_time + (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND;
141+
if (!args)
142+
return -RT_EINVAL;
143+
t = (time_t *)args;
144+
struct timespec ts;
145+
get_rtc_time(&ts);
146+
*t = ts.tv_sec;
98147
break;
99148
}
100149
case RT_DEVICE_CTRL_RTC_SET_TIME:
101150
{
102-
t = (time_t *) args;
103-
set_rtc_time(*t);
151+
if (!args)
152+
return -RT_EINVAL;
153+
t = (time_t *)args;
154+
struct timespec ts = { *t, 0 };
155+
set_rtc_time(&ts);
104156
break;
105157
}
106158
#ifdef RT_USING_ALARM
107159
case RT_DEVICE_CTRL_RTC_GET_ALARM:
160+
if (!args)
161+
return -RT_EINVAL;
108162
*((struct rt_rtc_wkalarm *)args) = wkalarm;
109163
break;
110164
case RT_DEVICE_CTRL_RTC_SET_ALARM:
165+
if (!args)
166+
return -RT_EINVAL;
111167
wkalarm = *((struct rt_rtc_wkalarm *)args);
112168
soft_rtc_alarm_update(&wkalarm);
113169
break;
114170
#endif
115-
#ifdef RT_USING_KTIME
116171
case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
117172
{
118-
struct timeval _tv;
173+
if (!args)
174+
return -RT_EINVAL;
119175
struct timeval *tv = (struct timeval *)args;
120-
rt_ktime_boottime_get_us(&_tv);
121-
tv->tv_sec = init_time + _tv.tv_sec;
122-
tv->tv_usec = init_tv.tv_usec + _tv.tv_usec;
176+
struct timespec ts;
177+
get_rtc_time(&ts);
178+
tv->tv_sec = ts.tv_sec;
179+
tv->tv_usec = ts.tv_nsec / 1000;
123180
break;
124181
}
125182
case RT_DEVICE_CTRL_RTC_SET_TIMEVAL:
126183
{
127-
struct timeval _tv;
184+
if (!args)
185+
return -RT_EINVAL;
128186
struct timeval *tv = (struct timeval *)args;
129-
rt_ktime_boottime_get_us(&_tv);
130-
set_rtc_time(tv->tv_sec);
131-
init_tv.tv_usec = tv->tv_usec - _tv.tv_usec;
187+
struct timespec ts = { tv->tv_sec, tv->tv_usec * 1000 };
188+
set_rtc_time(&ts);
132189
break;
133190
}
134191
case RT_DEVICE_CTRL_RTC_GET_TIMESPEC:
135192
{
136-
struct timespec _ts;
193+
if (!args)
194+
return -RT_EINVAL;
137195
struct timespec *ts = (struct timespec *)args;
138-
rt_ktime_boottime_get_ns(&_ts);
139-
ts->tv_sec = init_time + _ts.tv_sec;
140-
ts->tv_nsec = init_ts.tv_nsec + _ts.tv_nsec;
196+
get_rtc_time(ts);
141197
break;
142198
}
143199
case RT_DEVICE_CTRL_RTC_SET_TIMESPEC:
144200
{
145-
struct timespec _ts;
201+
if (!args)
202+
return -RT_EINVAL;
146203
struct timespec *ts = (struct timespec *)args;
147-
rt_ktime_boottime_get_ns(&_ts);
148-
set_rtc_time(ts->tv_sec);
149-
init_ts.tv_nsec = ts->tv_nsec - _ts.tv_nsec;
204+
set_rtc_time(ts);
150205
break;
151206
}
152207
case RT_DEVICE_CTRL_RTC_GET_TIMERES:
153208
{
209+
if (!args)
210+
return -RT_EINVAL;
154211
struct timespec *ts = (struct timespec *)args;
155-
ts->tv_sec = 0;
212+
level = rt_spin_lock_irqsave(&_spinlock);
213+
ts->tv_sec = 0;
214+
#ifdef RT_USING_KTIME
156215
ts->tv_nsec = (rt_ktime_cputimer_getres() / RT_KTIME_RESMUL);
157-
break;
158-
}
159216
#else
160-
case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
161-
{
162-
struct timeval *tv = (struct timeval *)args;
163-
rt_tick_t tick = rt_tick_get() - init_tick;
164-
tv->tv_sec = init_time + tick / RT_TICK_PER_SECOND;
165-
tv->tv_usec = init_tv.tv_usec + ((tick % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND));
166-
break;
167-
}
168-
case RT_DEVICE_CTRL_RTC_SET_TIMEVAL:
169-
{
170-
struct timeval *tv = (struct timeval *)args;
171-
rt_tick_t tick = rt_tick_get() - init_tick;
172-
set_rtc_time(tv->tv_sec);
173-
init_tv.tv_usec = tv->tv_usec - ((tick % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND));
174-
break;
175-
}
176-
case RT_DEVICE_CTRL_RTC_GET_TIMERES:
177-
{
178-
struct timespec *ts = (struct timespec *)args;
179-
ts->tv_sec = 0;
180217
ts->tv_nsec = (1000UL * 1000 * 1000) / RT_TICK_PER_SECOND;
218+
#endif
219+
rt_spin_unlock_irqrestore(&_spinlock, level);
181220
break;
182221
}
183-
#endif /* RT_USING_KTIME */
184222
default:
185223
return -RT_EINVAL;
186224
}
@@ -189,8 +227,7 @@ static rt_err_t soft_rtc_control(rt_device_t dev, int cmd, void *args)
189227
}
190228

191229
#ifdef RT_USING_DEVICE_OPS
192-
const static struct rt_device_ops soft_rtc_ops =
193-
{
230+
const static struct rt_device_ops soft_rtc_ops = {
194231
RT_NULL,
195232
RT_NULL,
196233
RT_NULL,
@@ -209,7 +246,7 @@ static int rt_soft_rtc_init(void)
209246
{
210247
return 0;
211248
}
212-
/* make sure only one 'rtc' device */
249+
/* Make sure only one 'rtc' device */
213250
#if defined(RT_USING_SOFT_RTC) && defined(BSP_USING_ONCHIP_RTC)
214251
#warning "Please note: Currently only one RTC device is allowed in the system, and the name is "rtc"."
215252
#endif
@@ -221,27 +258,31 @@ static int rt_soft_rtc_init(void)
221258
alarm_timeout,
222259
&soft_rtc_dev,
223260
0,
224-
RT_TIMER_FLAG_SOFT_TIMER|RT_TIMER_FLAG_ONE_SHOT);
261+
RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT);
225262
#endif
226263

264+
#ifdef RT_USING_KTIME
265+
rt_ktime_boottime_get_ns(&init_ktime_ts);
266+
#else
227267
init_tick = rt_tick_get();
228-
init_time = timegm(&time_new);
268+
#endif
269+
init_ts.tv_sec = timegm(&time_new);
229270

230-
soft_rtc_dev.type = RT_Device_Class_RTC;
271+
soft_rtc_dev.type = RT_Device_Class_RTC;
231272

232-
/* register rtc device */
273+
/* Register RTC device */
233274
#ifdef RT_USING_DEVICE_OPS
234-
soft_rtc_dev.ops = &soft_rtc_ops;
275+
soft_rtc_dev.ops = &soft_rtc_ops;
235276
#else
236-
soft_rtc_dev.init = RT_NULL;
237-
soft_rtc_dev.open = RT_NULL;
238-
soft_rtc_dev.close = RT_NULL;
239-
soft_rtc_dev.read = RT_NULL;
240-
soft_rtc_dev.write = RT_NULL;
277+
soft_rtc_dev.init = RT_NULL;
278+
soft_rtc_dev.open = RT_NULL;
279+
soft_rtc_dev.close = RT_NULL;
280+
soft_rtc_dev.read = RT_NULL;
281+
soft_rtc_dev.write = RT_NULL;
241282
soft_rtc_dev.control = soft_rtc_control;
242283
#endif
243284

244-
/* no private */
285+
/* No private data */
245286
soft_rtc_dev.user_data = RT_NULL;
246287

247288
rt_device_register(&soft_rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR);
@@ -259,7 +300,8 @@ rt_err_t rt_soft_rtc_sync(void)
259300
time_t time = 0;
260301

261302
rt_device_control(&soft_rtc_dev, RT_DEVICE_CTRL_RTC_GET_TIME, &time);
262-
set_rtc_time(time);
303+
struct timespec ts = { time, 0 };
304+
set_rtc_time(&ts);
263305
return RT_EOK;
264306
}
265307

@@ -284,15 +326,15 @@ rt_err_t rt_soft_rtc_set_source(const char *name)
284326
#include <finsh.h>
285327
static void cmd_rtc_sync(int argc, char **argv)
286328
{
287-
struct timeval tv = {0};
288-
struct timezone tz = {0};
289-
time_t now = (time_t)0;
329+
struct timeval tv = { 0 };
330+
struct timezone tz = { 0 };
331+
time_t now = (time_t)0;
290332

291333
rt_soft_rtc_sync();
292334

293335
gettimeofday(&tv, &tz);
294336
now = tv.tv_sec;
295-
/* output current time */
337+
/* Output current time */
296338
rt_kprintf("local time: %.*s", 25, ctime(&now));
297339
rt_kprintf("timestamps: %ld\n", (long)tv.tv_sec);
298340
}

0 commit comments

Comments
 (0)