1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2012-01-29 aozima first version.
9 * 2012-04-12 aozima optimization: find rtc device only first.
10 * 2012-04-16 aozima add scheduler lock for set_date and set_time.
11 * 2018-02-16 armink add auto sync time by NTP
12 */
13
14 #include <time.h>
15 #include <string.h>
16 #include <rtthread.h>
17
18 #ifdef RT_USING_RTC
19
20 /* Using NTP auto sync RTC time */
21 #ifdef RTC_SYNC_USING_NTP
22 /* NTP first sync delay time for network connect, unit: second */
23 #ifndef RTC_NTP_FIRST_SYNC_DELAY
24 #define RTC_NTP_FIRST_SYNC_DELAY (30)
25 #endif
26 /* NTP sync period, unit: second */
27 #ifndef RTC_NTP_SYNC_PERIOD
28 #define RTC_NTP_SYNC_PERIOD (1L*60L*60L)
29 #endif
30 #endif /* RTC_SYNC_USING_NTP */
31
32 /**
33 * Set system date(time not modify).
34 *
35 * @param rt_uint32_t year e.g: 2012.
36 * @param rt_uint32_t month e.g: 12 (1~12).
37 * @param rt_uint32_t day e.g: 31.
38 *
39 * @return rt_err_t if set success, return RT_EOK.
40 *
41 */
set_date(rt_uint32_t year,rt_uint32_t month,rt_uint32_t day)42 rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day)
43 {
44 time_t now;
45 struct tm *p_tm;
46 struct tm tm_new;
47 rt_device_t device;
48 rt_err_t ret = -RT_ERROR;
49
50 /* get current time */
51 now = time(RT_NULL);
52
53 /* lock scheduler. */
54 rt_enter_critical();
55 /* converts calendar time time into local time. */
56 p_tm = localtime(&now);
57 /* copy the statically located variable */
58 memcpy(&tm_new, p_tm, sizeof(struct tm));
59 /* unlock scheduler. */
60 rt_exit_critical();
61
62 /* update date. */
63 tm_new.tm_year = year - 1900;
64 tm_new.tm_mon = month - 1; /* tm_mon: 0~11 */
65 tm_new.tm_mday = day;
66
67 /* converts the local time in time to calendar time. */
68 now = mktime(&tm_new);
69
70 device = rt_device_find("rtc");
71 if (device == RT_NULL)
72 {
73 return -RT_ERROR;
74 }
75
76 /* update to RTC device. */
77 ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &now);
78
79 return ret;
80 }
81
82 /**
83 * Set system time(date not modify).
84 *
85 * @param rt_uint32_t hour e.g: 0~23.
86 * @param rt_uint32_t minute e.g: 0~59.
87 * @param rt_uint32_t second e.g: 0~59.
88 *
89 * @return rt_err_t if set success, return RT_EOK.
90 *
91 */
set_time(rt_uint32_t hour,rt_uint32_t minute,rt_uint32_t second)92 rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)
93 {
94 time_t now;
95 struct tm *p_tm;
96 struct tm tm_new;
97 rt_device_t device;
98 rt_err_t ret = -RT_ERROR;
99
100 /* get current time */
101 now = time(RT_NULL);
102
103 /* lock scheduler. */
104 rt_enter_critical();
105 /* converts calendar time time into local time. */
106 p_tm = localtime(&now);
107 /* copy the statically located variable */
108 memcpy(&tm_new, p_tm, sizeof(struct tm));
109 /* unlock scheduler. */
110 rt_exit_critical();
111
112 /* update time. */
113 tm_new.tm_hour = hour;
114 tm_new.tm_min = minute;
115 tm_new.tm_sec = second;
116
117 /* converts the local time in time to calendar time. */
118 now = mktime(&tm_new);
119
120 device = rt_device_find("rtc");
121 if (device == RT_NULL)
122 {
123 return -RT_ERROR;
124 }
125
126 /* update to RTC device. */
127 ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &now);
128
129 return ret;
130 }
131
132 #ifdef RTC_SYNC_USING_NTP
ntp_sync_thread_enrty(void * param)133 static void ntp_sync_thread_enrty(void *param)
134 {
135 extern time_t ntp_sync_to_rtc(const char *host_name);
136 /* first sync delay for network connect */
137 rt_thread_delay(RTC_NTP_FIRST_SYNC_DELAY * RT_TICK_PER_SECOND);
138
139 while (1)
140 {
141 ntp_sync_to_rtc(NULL);
142 rt_thread_delay(RTC_NTP_SYNC_PERIOD * RT_TICK_PER_SECOND);
143 }
144 }
145
rt_rtc_ntp_sync_init(void)146 int rt_rtc_ntp_sync_init(void)
147 {
148 static rt_bool_t init_ok = RT_FALSE;
149 rt_thread_t thread;
150
151 if (init_ok)
152 {
153 return 0;
154 }
155
156 thread = rt_thread_create("ntp_sync", ntp_sync_thread_enrty, RT_NULL, 1536, 26, 2);
157 if (thread)
158 {
159 rt_thread_startup(thread);
160 }
161 else
162 {
163 return -RT_ENOMEM;
164 }
165
166 init_ok = RT_TRUE;
167
168 return RT_EOK;
169 }
170 INIT_COMPONENT_EXPORT(rt_rtc_ntp_sync_init);
171 #endif /* RTC_SYNC_USING_NTP */
172
173 #ifdef RT_USING_FINSH
174 #include <finsh.h>
175 #include <rtdevice.h>
176
list_date(void)177 void list_date(void)
178 {
179 time_t now;
180
181 now = time(RT_NULL);
182 rt_kprintf("%s\n", ctime(&now));
183 }
184 FINSH_FUNCTION_EXPORT(list_date, show date and time.)
185
186 FINSH_FUNCTION_EXPORT(set_date, set date. e.g: set_date(2010,2,28))
187 FINSH_FUNCTION_EXPORT(set_time, set time. e.g: set_time(23,59,59))
188
189 #if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
date(uint8_t argc,char ** argv)190 static void date(uint8_t argc, char **argv)
191 {
192 if (argc == 1)
193 {
194 time_t now;
195 /* output current time */
196 now = time(RT_NULL);
197 rt_kprintf("%s", ctime(&now));
198 }
199 else if (argc >= 7)
200 {
201 /* set time and date */
202 uint16_t year;
203 uint8_t month, day, hour, min, sec;
204 year = atoi(argv[1]);
205 month = atoi(argv[2]);
206 day = atoi(argv[3]);
207 hour = atoi(argv[4]);
208 min = atoi(argv[5]);
209 sec = atoi(argv[6]);
210 if (year > 2099 || year < 2000)
211 {
212 rt_kprintf("year is out of range [2000-2099]\n");
213 return;
214 }
215 if (month == 0 || month > 12)
216 {
217 rt_kprintf("month is out of range [1-12]\n");
218 return;
219 }
220 if (day == 0 || day > 31)
221 {
222 rt_kprintf("day is out of range [1-31]\n");
223 return;
224 }
225 if (hour > 23)
226 {
227 rt_kprintf("hour is out of range [0-23]\n");
228 return;
229 }
230 if (min > 59)
231 {
232 rt_kprintf("minute is out of range [0-59]\n");
233 return;
234 }
235 if (sec > 59)
236 {
237 rt_kprintf("second is out of range [0-59]\n");
238 return;
239 }
240 set_time(hour, min, sec);
241 set_date(year, month, day);
242 }
243 else
244 {
245 rt_kprintf("please input: date [year month day hour min sec] or date\n");
246 rt_kprintf("e.g: date 2018 01 01 23 59 59 or date\n");
247 }
248 }
249 MSH_CMD_EXPORT(date, get date and time or set [year month day hour min sec]);
250 #endif /* defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) */
251
252 #endif /* RT_USING_FINSH */
253
254 #endif /* RT_USING_RTC */
255