1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-04-13 armink the first version
9 * 2022-05-17 Meco Man improve and beautify
10 */
11
12 #include <sys/time.h>
13 #include <rtdevice.h>
14
15 static struct rt_device rtc_dev;
16
17 #ifdef BSP_USING_ALARM
18 static struct rt_rtc_wkalarm wkalarm;
19 static struct rt_timer alarm_time;
20
alarm_timeout(void * param)21 static void alarm_timeout(void *param)
22 {
23 rt_alarm_update(param, 1);
24 }
25
soft_rtc_alarm_update(struct rt_rtc_wkalarm * palarm)26 static void soft_rtc_alarm_update(struct rt_rtc_wkalarm *palarm)
27 {
28 rt_tick_t next_tick;
29
30 if (palarm->enable)
31 {
32 next_tick = RT_TICK_PER_SECOND;
33 rt_timer_control(&alarm_time, RT_TIMER_CTRL_SET_TIME, &next_tick);
34 rt_timer_start(&alarm_time);
35 }
36 else
37 {
38 rt_timer_stop(&alarm_time);
39 }
40 }
41 #endif /* BSP_USING_ALARM */
42
get_rtc_timeval(struct timeval * tv)43 static void get_rtc_timeval(struct timeval *tv)
44 {
45 #ifdef _WIN32
46 struct tm newtime = { 0 };
47 SYSTEMTIME sys_time;
48
49 GetSystemTime(&sys_time); /* get RTC from Windows */
50
51 newtime.tm_year = sys_time.wYear - 1900;
52 newtime.tm_mon = sys_time.wMonth - 1;
53 newtime.tm_mday = sys_time.wDay;
54 newtime.tm_hour = sys_time.wHour;
55 newtime.tm_min = sys_time.wMinute;
56 newtime.tm_sec = sys_time.wSecond;
57
58 tv->tv_sec = timegm(&newtime);
59 tv->tv_usec = sys_time.wMilliseconds * 1000UL;
60 #else
61 tv->tv_sec = 0;
62 tv->tv_usec = 0;
63 #endif
64 }
65
pc_rtc_control(rt_device_t dev,int cmd,void * args)66 static rt_err_t pc_rtc_control(rt_device_t dev, int cmd, void *args)
67 {
68 RT_ASSERT(dev != RT_NULL);
69
70 switch (cmd)
71 {
72 case RT_DEVICE_CTRL_RTC_GET_TIME:
73 {
74 struct timeval tv;
75 get_rtc_timeval(&tv);
76 *(time_t*) args = tv.tv_sec;
77 break;
78 }
79 case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
80 {
81 get_rtc_timeval((struct timeval *) args);
82 break;
83 }
84 #ifdef BSP_USING_ALARM
85 case RT_DEVICE_CTRL_RTC_SET_TIME:
86 {
87 soft_rtc_alarm_update(&wkalarm);
88 break;
89 }
90 case RT_DEVICE_CTRL_RTC_GET_ALARM:
91 {
92 *((struct rt_rtc_wkalarm *)args) = wkalarm;
93 break;
94 }
95 case RT_DEVICE_CTRL_RTC_SET_ALARM:
96 {
97 wkalarm = *((struct rt_rtc_wkalarm *)args);
98 soft_rtc_alarm_update(&wkalarm);
99 break;
100 }
101 #endif /* BSP_USING_ALARM */
102 default:
103 return -RT_ERROR;
104 }
105
106 return RT_EOK;
107 }
108
109 #ifdef RT_USING_DEVICE_OPS
110 const static struct rt_device_ops pc_rtc_ops =
111 {
112 RT_NULL,
113 RT_NULL,
114 RT_NULL,
115 RT_NULL,
116 RT_NULL,
117 pc_rtc_control
118 };
119 #endif
120
rt_pc_rtc_init(void)121 int rt_pc_rtc_init(void)
122 {
123 /* make sure only one 'rtc' device */
124 RT_ASSERT(!rt_device_find("rtc"));
125
126 #ifdef BSP_USING_ALARM
127 rt_timer_init(&alarm_time,
128 "alarm",
129 alarm_timeout,
130 &rtc_dev,
131 0,
132 RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT);
133 #endif
134
135 rtc_dev.type = RT_Device_Class_RTC;
136
137 /* register rtc device */
138 #ifdef RT_USING_DEVICE_OPS
139 rtc_dev.ops = &pc_rtc_ops;
140 #else
141 rtc_dev.init = RT_NULL;
142 rtc_dev.open = RT_NULL;
143 rtc_dev.close = RT_NULL;
144 rtc_dev.read = RT_NULL;
145 rtc_dev.write = RT_NULL;
146 rtc_dev.control = pc_rtc_control;
147 #endif
148 rtc_dev.user_data = RT_NULL; /* no private */
149
150 rt_device_register(&rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR);
151 return 0;
152 }
153 INIT_BOARD_EXPORT(rt_pc_rtc_init);
154