ChibiOS/HAL  7.0.4
hal_rtc.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 /*
17  Concepts and parts of this file have been contributed by Uladzimir Pylinsky
18  aka barthess.
19  */
20 
21 /**
22  * @file hal_rtc.c
23  * @brief RTC Driver code.
24  *
25  * @addtogroup RTC
26  * @{
27  */
28 
29 #include "hal.h"
30 
31 #if (HAL_USE_RTC == TRUE) || defined(__DOXYGEN__)
32 
33 /*===========================================================================*/
34 /* Driver local definitions. */
35 /*===========================================================================*/
36 
37 /*===========================================================================*/
38 /* Driver exported variables. */
39 /*===========================================================================*/
40 
41 /*===========================================================================*/
42 /* Driver local variables and types. */
43 /*===========================================================================*/
44 
45 /*
46  * Lookup table with months' length
47  */
48 static const uint8_t month_len[12] = {
49  31, 30, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
50 };
51 
52 /*===========================================================================*/
53 /* Driver local functions. */
54 /*===========================================================================*/
55 
56 /*===========================================================================*/
57 /* Driver exported functions. */
58 /*===========================================================================*/
59 
60 /**
61  * @brief RTC Driver initialization.
62  * @note This function is implicitly invoked by @p halInit(), there is
63  * no need to explicitly initialize the driver.
64  *
65  * @init
66  */
67 void rtcInit(void) {
68 
69  rtc_lld_init();
70 }
71 
72 /**
73  * @brief Initializes a generic RTC driver object.
74  * @details The HW dependent part of the initialization has to be performed
75  * outside, usually in the hardware initialization code.
76  *
77  * @param[out] rtcp pointer to RTC driver structure
78  *
79  * @init
80  */
81 void rtcObjectInit(RTCDriver *rtcp) {
82 
83 #if RTC_HAS_STORAGE == TRUE
84  rtcp->vmt = &_rtc_lld_vmt;
85 #else
86  (void)rtcp;
87 #endif
88 }
89 
90 /**
91  * @brief Set current time.
92  * @note This function can be called from any context but limitations
93  * could be imposed by the low level implementation. It is
94  * guaranteed that the function can be called from thread
95  * context.
96  * @note The function can be reentrant or not reentrant depending on
97  * the low level implementation.
98  *
99  * @param[in] rtcp pointer to RTC driver structure
100  * @param[in] timespec pointer to a @p RTCDateTime structure
101  *
102  * @special
103  */
104 void rtcSetTime(RTCDriver *rtcp, const RTCDateTime *timespec) {
105 
106  osalDbgCheck((rtcp != NULL) && (timespec != NULL));
107 
108  rtc_lld_set_time(rtcp, timespec);
109 }
110 
111 /**
112  * @brief Get current time.
113  * @note This function can be called from any context but limitations
114  * could be imposed by the low level implementation. It is
115  * guaranteed that the function can be called from thread
116  * context.
117  * @note The function can be reentrant or not reentrant depending on
118  * the low level implementation.
119  *
120  * @param[in] rtcp pointer to RTC driver structure
121  * @param[out] timespec pointer to a @p RTCDateTime structure
122  *
123  * @special
124  */
125 void rtcGetTime(RTCDriver *rtcp, RTCDateTime *timespec) {
126 
127  osalDbgCheck((rtcp != NULL) && (timespec != NULL));
128 
129  rtc_lld_get_time(rtcp, timespec);
130 }
131 
132 #if (RTC_ALARMS > 0) || defined(__DOXYGEN__)
133 /**
134  * @brief Set alarm time.
135  * @note This function can be called from any context but limitations
136  * could be imposed by the low level implementation. It is
137  * guaranteed that the function can be called from thread
138  * context.
139  * @note The function can be reentrant or not reentrant depending on
140  * the low level implementation.
141  *
142  * @param[in] rtcp pointer to RTC driver structure
143  * @param[in] alarm alarm identifier
144  * @param[in] alarmspec pointer to a @p RTCAlarm structure or @p NULL
145  *
146  * @special
147  */
149  rtcalarm_t alarm,
150  const RTCAlarm *alarmspec) {
151 
152  osalDbgCheck((rtcp != NULL) && (alarm < (rtcalarm_t)RTC_ALARMS));
153 
154  rtc_lld_set_alarm(rtcp, alarm, alarmspec);
155 }
156 
157 /**
158  * @brief Get current alarm.
159  * @note If an alarm has not been set then the returned alarm specification
160  * is not meaningful.
161  * @note This function can be called from any context but limitations
162  * could be imposed by the low level implementation. It is
163  * guaranteed that the function can be called from thread
164  * context.
165  * @note The function can be reentrant or not reentrant depending on
166  * the low level implementation.
167  *
168  * @param[in] rtcp pointer to RTC driver structure
169  * @param[in] alarm alarm identifier
170  * @param[out] alarmspec pointer to a @p RTCAlarm structure
171  *
172  * @special
173  */
175  rtcalarm_t alarm,
176  RTCAlarm *alarmspec) {
177 
178  osalDbgCheck((rtcp != NULL) &&
179  (alarm < (rtcalarm_t)RTC_ALARMS) &&
180  (alarmspec != NULL));
181 
182  rtc_lld_get_alarm(rtcp, alarm, alarmspec);
183 }
184 #endif /* RTC_ALARMS > 0 */
185 
186 #if (RTC_SUPPORTS_CALLBACKS == TRUE) || defined(__DOXYGEN__)
187 /**
188  * @brief Enables or disables RTC callbacks.
189  * @details This function enables or disables the callback, use a @p NULL
190  * pointer in order to disable it.
191  * @note This function can be called from any context but limitations
192  * could be imposed by the low level implementation. It is
193  * guaranteed that the function can be called from thread
194  * context.
195  * @note The function can be reentrant or not reentrant depending on
196  * the low level implementation.
197  *
198  * @param[in] rtcp pointer to RTC driver structure
199  * @param[in] callback callback function pointer or @p NULL
200  *
201  * @special
202  */
203 void rtcSetCallback(RTCDriver *rtcp, rtccb_t callback) {
204 
205  osalDbgCheck(rtcp != NULL);
206 
207  rtc_lld_set_callback(rtcp, callback);
208 }
209 #endif /* RTC_SUPPORTS_CALLBACKS == TRUE */
210 
211 /**
212  * @brief Convert @p RTCDateTime to broken-down time structure.
213  *
214  * @param[in] timespec pointer to a @p RTCDateTime structure
215  * @param[out] timp pointer to a broken-down time structure
216  * @param[out] tv_msec pointer to milliseconds value or @p NULL
217  *
218  * @api
219  */
221  struct tm *timp,
222  uint32_t *tv_msec) {
223  int sec;
224 
225  timp->tm_year = (int)timespec->year + (1980 - 1900);
226  timp->tm_mon = (int)timespec->month - 1;
227  timp->tm_mday = (int)timespec->day;
228  timp->tm_isdst = (int)timespec->dstflag;
229  timp->tm_wday = (int)timespec->dayofweek - 1;
230 
231  sec = (int)timespec->millisecond / 1000;
232  timp->tm_hour = sec / 3600;
233  sec %= 3600;
234  timp->tm_min = sec / 60;
235  timp->tm_sec = sec % 60;
236 
237  if (NULL != tv_msec) {
238  *tv_msec = (uint32_t)timespec->millisecond % 1000U;
239  }
240 }
241 
242 /**
243  * @brief Convert broken-down time structure to @p RTCDateTime.
244  *
245  * @param[in] timp pointer to a broken-down time structure
246  * @param[in] tv_msec milliseconds value
247  * @param[out] timespec pointer to a @p RTCDateTime structure
248  *
249  * @api
250  */
251 void rtcConvertStructTmToDateTime(const struct tm *timp,
252  uint32_t tv_msec,
253  RTCDateTime *timespec) {
254 
255  /*lint -save -e9034 [10.4] Verified assignments to bit fields.*/
256  timespec->year = (uint32_t)timp->tm_year - (1980U - 1900U);
257  timespec->month = (uint32_t)timp->tm_mon + 1U;
258  timespec->day = (uint32_t)timp->tm_mday;
259  timespec->dayofweek = (uint32_t)timp->tm_wday + 1U;
260  if (-1 == timp->tm_isdst) {
261  timespec->dstflag = 0U; /* set zero if dst is unknown */
262  }
263  else {
264  timespec->dstflag = (uint32_t)timp->tm_isdst;
265  }
266  /*lint -restore*/
267  /*lint -save -e9033 [10.8] Verified assignments to bit fields.*/
268  timespec->millisecond = tv_msec + (uint32_t)(((timp->tm_hour * 3600) +
269  (timp->tm_min * 60) +
270  timp->tm_sec) * 1000);
271  /*lint -restore*/
272 }
273 
274 /**
275  * @brief Get current time in format suitable for usage in FAT file system.
276  * @note The information about day of week and DST is lost in DOS
277  * format, the second field loses its least significant bit.
278  *
279  * @param[out] timespec pointer to a @p RTCDateTime structure
280  * @return FAT date/time value.
281  *
282  * @api
283  */
284 uint32_t rtcConvertDateTimeToFAT(const RTCDateTime *timespec) {
285  uint32_t fattime;
286  uint32_t sec, min, hour, day, month;
287 
288  sec = timespec->millisecond / 1000U;
289  hour = sec / 3600U;
290  sec %= 3600U;
291  min = sec / 60U;
292  sec %= 60U;
293  day = timespec->day;
294  month = timespec->month;
295 
296  /* handle DST flag */
297  if (1U == timespec->dstflag) {
298  hour += 1U;
299  if (hour == 24U) {
300  hour = 0U;
301  day += 1U;
302  if (day > month_len[month - 1U]) {
303  day = 1U;
304  month += 1U;
305  }
306  }
307  }
308 
309  fattime = sec >> 1U;
310  fattime |= min << 5U;
311  fattime |= hour << 11U;
312  fattime |= day << 16U;
313  fattime |= month << 21U;
314  fattime |= (uint32_t)timespec->year << 25U;
315 
316  return fattime;
317 }
318 
319 #endif /* HAL_USE_RTC == TRUE */
320 
321 /** @} */
void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec)
Get current time.
Definition: hal_rtc_lld.c:103
uint32_t month
Months 1..12.
Definition: hal_rtc.h:101
uint32_t dstflag
DST correction flag.
Definition: hal_rtc.h:102
uint32_t day
Day of the month 1..31.
Definition: hal_rtc.h:104
void rtcSetAlarm(RTCDriver *rtcp, rtcalarm_t alarm, const RTCAlarm *alarmspec)
Set alarm time.
Definition: hal_rtc.c:148
void rtcGetAlarm(RTCDriver *rtcp, rtcalarm_t alarm, RTCAlarm *alarmspec)
Get current alarm.
Definition: hal_rtc.c:174
HAL subsystem header.
void rtcObjectInit(RTCDriver *rtcp)
Initializes a generic RTC driver object.
Definition: hal_rtc.c:81
void rtc_lld_set_alarm(RTCDriver *rtcp, rtcalarm_t alarm, const RTCAlarm *alarmspec)
Set alarm time.
Definition: hal_rtc_lld.c:122
uint32_t year
Years since 1980.
Definition: hal_rtc.h:100
uint32_t rtcConvertDateTimeToFAT(const RTCDateTime *timespec)
Get current time in format suitable for usage in FAT file system.
Definition: hal_rtc.c:284
uint32_t dayofweek
Day of week 1..7.
Definition: hal_rtc.h:103
Type of a structure representing an RTC alarm time stamp.
Definition: hal_rtc_lld.h:100
void rtc_lld_init(void)
RTC driver identifier.
Definition: hal_rtc_lld.c:69
void rtcSetCallback(RTCDriver *rtcp, rtccb_t callback)
Enables or disables RTC callbacks.
Definition: hal_rtc.c:203
#define RTC_ALARMS
Number of alarms available.
Definition: hal_rtc_lld.h:49
#define osalDbgCheck(c)
Function parameters check.
Definition: osal.h:278
void rtc_lld_get_alarm(RTCDriver *rtcp, rtcalarm_t alarm, RTCAlarm *alarmspec)
Get alarm time.
Definition: hal_rtc_lld.c:141
void rtcGetTime(RTCDriver *rtcp, RTCDateTime *timespec)
Get current time.
Definition: hal_rtc.c:125
void rtcInit(void)
RTC Driver initialization.
Definition: hal_rtc.c:67
Type of a structure representing an RTC date/time stamp.
Definition: hal_rtc.h:98
const struct RTCDriverVMT * vmt
Virtual Methods Table.
Definition: hal_rtc.h:150
void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec)
Set current time.
Definition: hal_rtc_lld.c:88
Structure representing an RTC driver.
Definition: hal_rtc.h:145
void rtcConvertStructTmToDateTime(const struct tm *timp, uint32_t tv_msec, RTCDateTime *timespec)
Convert broken-down time structure to RTCDateTime.
Definition: hal_rtc.c:251
void(* rtccb_t)(RTCDriver *rtcp, rtcevent_t event)
Type of a generic RTC callback.
Definition: hal_rtc_lld.h:94
unsigned int rtcalarm_t
Type of an RTC alarm number.
Definition: hal_rtc.h:93
uint32_t millisecond
Milliseconds since midnight.
Definition: hal_rtc.h:105
void rtcSetTime(RTCDriver *rtcp, const RTCDateTime *timespec)
Set current time.
Definition: hal_rtc.c:104
void rtcConvertDateTimeToStructTm(const RTCDateTime *timespec, struct tm *timp, uint32_t *tv_msec)
Convert RTCDateTime to broken-down time structure.
Definition: hal_rtc.c:220