ChibiOS 21.11.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 */
48static const uint8_t month_len[12] = {
49 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
50};
51
52static const uint16_t accu_month_len[12] = {
53 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
54};
55
56/*===========================================================================*/
57/* Driver local functions. */
58/*===========================================================================*/
59
60/*===========================================================================*/
61/* Driver exported functions. */
62/*===========================================================================*/
63
64/**
65 * @brief RTC Driver initialization.
66 * @note This function is implicitly invoked by @p halInit(), there is
67 * no need to explicitly initialize the driver.
68 *
69 * @init
70 */
71void rtcInit(void) {
72
74}
75
76/**
77 * @brief Initializes a generic RTC driver object.
78 * @details The HW dependent part of the initialization has to be performed
79 * outside, usually in the hardware initialization code.
80 *
81 * @param[out] rtcp pointer to RTC driver structure
82 *
83 * @init
84 */
86
87#if RTC_HAS_STORAGE == TRUE
88 rtcp->vmt = &_rtc_lld_vmt;
89#else
90 (void)rtcp;
91#endif
92}
93
94/**
95 * @brief Set current time.
96 * @note This function can be called from any context but limitations
97 * could be imposed by the low level implementation. It is
98 * guaranteed that the function can be called from thread
99 * context.
100 * @note The function can be reentrant or not reentrant depending on
101 * the low level implementation.
102 *
103 * @param[in] rtcp pointer to RTC driver structure
104 * @param[in] timespec pointer to a @p RTCDateTime structure
105 *
106 * @special
107 */
108void rtcSetTime(RTCDriver *rtcp, const RTCDateTime *timespec) {
109
110 osalDbgCheck((rtcp != NULL) && (timespec != NULL));
111
112 rtc_lld_set_time(rtcp, timespec);
113}
114
115/**
116 * @brief Get current time.
117 * @note This function can be called from any context but limitations
118 * could be imposed by the low level implementation. It is
119 * guaranteed that the function can be called from thread
120 * context.
121 * @note The function can be reentrant or not reentrant depending on
122 * the low level implementation.
123 *
124 * @param[in] rtcp pointer to RTC driver structure
125 * @param[out] timespec pointer to a @p RTCDateTime structure
126 *
127 * @special
128 */
129void rtcGetTime(RTCDriver *rtcp, RTCDateTime *timespec) {
130
131 osalDbgCheck((rtcp != NULL) && (timespec != NULL));
132
133 rtc_lld_get_time(rtcp, timespec);
134}
135
136#if (RTC_ALARMS > 0) || defined(__DOXYGEN__)
137/**
138 * @brief Set alarm time.
139 * @note This function can be called from any context but limitations
140 * could be imposed by the low level implementation. It is
141 * guaranteed that the function can be called from thread
142 * context.
143 * @note The function can be reentrant or not reentrant depending on
144 * the low level implementation.
145 *
146 * @param[in] rtcp pointer to RTC driver structure
147 * @param[in] alarm alarm identifier
148 * @param[in] alarmspec pointer to a @p RTCAlarm structure or @p NULL
149 *
150 * @special
151 */
153 rtcalarm_t alarm,
154 const RTCAlarm *alarmspec) {
155
156 osalDbgCheck((rtcp != NULL) && (alarm < (rtcalarm_t)RTC_ALARMS));
157
158 rtc_lld_set_alarm(rtcp, alarm, alarmspec);
159}
160
161/**
162 * @brief Get current alarm.
163 * @note If an alarm has not been set then the returned alarm specification
164 * is not meaningful.
165 * @note This function can be called from any context but limitations
166 * could be imposed by the low level implementation. It is
167 * guaranteed that the function can be called from thread
168 * context.
169 * @note The function can be reentrant or not reentrant depending on
170 * the low level implementation.
171 *
172 * @param[in] rtcp pointer to RTC driver structure
173 * @param[in] alarm alarm identifier
174 * @param[out] alarmspec pointer to a @p RTCAlarm structure
175 *
176 * @special
177 */
179 rtcalarm_t alarm,
180 RTCAlarm *alarmspec) {
181
182 osalDbgCheck((rtcp != NULL) &&
183 (alarm < (rtcalarm_t)RTC_ALARMS) &&
184 (alarmspec != NULL));
185
186 rtc_lld_get_alarm(rtcp, alarm, alarmspec);
187}
188#endif /* RTC_ALARMS > 0 */
189
190#if (RTC_SUPPORTS_CALLBACKS == TRUE) || defined(__DOXYGEN__)
191/**
192 * @brief Enables or disables RTC callbacks.
193 * @details This function enables or disables the callback, use a @p NULL
194 * pointer in order to disable it.
195 * @note This function can be called from any context but limitations
196 * could be imposed by the low level implementation. It is
197 * guaranteed that the function can be called from thread
198 * context.
199 * @note The function can be reentrant or not reentrant depending on
200 * the low level implementation.
201 *
202 * @param[in] rtcp pointer to RTC driver structure
203 * @param[in] callback callback function pointer or @p NULL
204 *
205 * @special
206 */
207void rtcSetCallback(RTCDriver *rtcp, rtccb_t callback) {
208
209 osalDbgCheck(rtcp != NULL);
210
211 rtc_lld_set_callback(rtcp, callback);
212}
213#endif /* RTC_SUPPORTS_CALLBACKS == TRUE */
214
215/**
216 * @brief Convert @p RTCDateTime to broken-down time structure.
217 *
218 * @param[in] timespec pointer to a @p RTCDateTime structure
219 * @param[out] timp pointer to a broken-down time structure
220 * @param[out] tv_msec pointer to milliseconds value or @p NULL
221 *
222 * @api
223 */
225 struct tm *timp,
226 uint32_t *tv_msec) {
227 int sec, year;
228 bool is_leap_year;
229
230 timp->tm_year = (int)timespec->year + (int)(RTC_BASE_YEAR - 1900U);
231 timp->tm_mon = (int)timespec->month - 1;
232 timp->tm_mday = (int)timespec->day;
233 timp->tm_isdst = (int)timespec->dstflag;
234 timp->tm_wday = (int)timespec->dayofweek % 7;
235
236 sec = (int)timespec->millisecond / 1000;
237 timp->tm_hour = sec / 3600;
238 sec %= 3600;
239 timp->tm_min = sec / 60;
240 timp->tm_sec = sec % 60;
241
242 if (NULL != tv_msec) {
243 *tv_msec = (uint32_t)timespec->millisecond % 1000U;
244 }
245
246 /* Day of the year calculation.*/
247 year = timp->tm_year + 1900;
248 timp->tm_yday = timp->tm_mday - 1;
249 timp->tm_yday += (int)accu_month_len[timp->tm_mon];
250 is_leap_year = (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0);
251 if (is_leap_year && (timp->tm_mon > 1)) {
252 timp->tm_yday++;
253 }
254}
255
256/**
257 * @brief Convert broken-down time structure to @p RTCDateTime.
258 *
259 * @param[in] timp pointer to a broken-down time structure
260 * @param[in] tv_msec milliseconds value
261 * @param[out] timespec pointer to a @p RTCDateTime structure
262 *
263 * @api
264 */
265void rtcConvertStructTmToDateTime(const struct tm *timp,
266 uint32_t tv_msec,
267 RTCDateTime *timespec) {
268
269 /*lint -save -e9034 [10.4] Verified assignments to bit fields.*/
270 timespec->year = (uint32_t)timp->tm_year - (RTC_BASE_YEAR - 1900U);
271 timespec->month = (uint32_t)timp->tm_mon + 1U;
272 timespec->day = (uint32_t)timp->tm_mday;
273 timespec->dayofweek = (((uint32_t)timp->tm_wday + 6U) % 7U) + 1U;
274
275 if (-1 == timp->tm_isdst) {
276 timespec->dstflag = 0U; /* Set zero if dst is unknown.*/
277 }
278 else {
279 timespec->dstflag = (uint32_t)timp->tm_isdst;
280 }
281 /*lint -restore*/
282 /*lint -save -e9033 [10.8] Verified assignments to bit fields.*/
283 timespec->millisecond = tv_msec + (uint32_t)(((timp->tm_hour * 3600) +
284 (timp->tm_min * 60) +
285 timp->tm_sec) * 1000);
286 /*lint -restore*/
287}
288
289/**
290 * @brief Get current time in format suitable for usage in FAT file system.
291 * @note The information about day of week and DST is lost in DOS
292 * format, the second field loses its least significant bit.
293 *
294 * @param[out] timespec pointer to a @p RTCDateTime structure
295 * @return FAT date/time value.
296 *
297 * @api
298 */
299uint32_t rtcConvertDateTimeToFAT(const RTCDateTime *timespec) {
300 uint32_t fattime;
301 uint32_t sec, min, hour, day, month;
302
303 sec = timespec->millisecond / 1000U;
304 hour = sec / 3600U;
305 sec %= 3600U;
306 min = sec / 60U;
307 sec %= 60U;
308 day = timespec->day;
309 month = timespec->month;
310
311 /* Handle DST flag.*/
312 if (1U == timespec->dstflag) {
313 hour += 1U;
314 if (hour == 24U) {
315 hour = 0U;
316 day += 1U;
317 if (day > (uint32_t)month_len[month - 1U]) {
318 day = 1U;
319 month += 1U;
320 }
321 }
322 }
323
324 fattime = sec >> 1U;
325 fattime |= min << 5U;
326 fattime |= hour << 11U;
327 fattime |= day << 16U;
328 fattime |= month << 21U;
329 fattime |= (uint32_t)timespec->year << 25U;
330
331 return fattime;
332}
333
334#endif /* HAL_USE_RTC == TRUE */
335
336/** @} */
#define osalDbgCheck(c)
Function parameters check.
Definition osal.h:284
#define RTC_ALARMS
Number of alarms available.
Definition hal_rtc_lld.h:50
void rtc_lld_init(void)
RTC driver identifier.
Definition hal_rtc_lld.c:69
void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec)
Set current time.
Definition hal_rtc_lld.c:88
void rtcSetTime(RTCDriver *rtcp, const RTCDateTime *timespec)
Set current time.
Definition hal_rtc.c:108
void rtcSetCallback(RTCDriver *rtcp, rtccb_t callback)
Enables or disables RTC callbacks.
Definition hal_rtc.c:207
void rtcConvertStructTmToDateTime(const struct tm *timp, uint32_t tv_msec, RTCDateTime *timespec)
Convert broken-down time structure to RTCDateTime.
Definition hal_rtc.c:265
void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback)
void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec)
Get current time.
static const uint8_t month_len[12]
Definition hal_rtc.c:48
void rtcInit(void)
RTC Driver initialization.
Definition hal_rtc.c:71
void rtc_lld_set_alarm(RTCDriver *rtcp, rtcalarm_t alarm, const RTCAlarm *alarmspec)
Set alarm time.
void rtcSetAlarm(RTCDriver *rtcp, rtcalarm_t alarm, const RTCAlarm *alarmspec)
Set alarm time.
Definition hal_rtc.c:152
void rtcGetTime(RTCDriver *rtcp, RTCDateTime *timespec)
Get current time.
Definition hal_rtc.c:129
void rtcGetAlarm(RTCDriver *rtcp, rtcalarm_t alarm, RTCAlarm *alarmspec)
Get current alarm.
Definition hal_rtc.c:178
void rtcConvertDateTimeToStructTm(const RTCDateTime *timespec, struct tm *timp, uint32_t *tv_msec)
Convert RTCDateTime to broken-down time structure.
Definition hal_rtc.c:224
#define RTC_BASE_YEAR
Base year of the calendar.
Definition hal_rtc.h:45
unsigned int rtcalarm_t
Type of an RTC alarm number.
Definition hal_rtc.h:93
void(* rtccb_t)(RTCDriver *rtcp, rtcevent_t event)
Type of a generic RTC callback.
Definition hal_rtc_lld.h:95
uint32_t rtcConvertDateTimeToFAT(const RTCDateTime *timespec)
Get current time in format suitable for usage in FAT file system.
Definition hal_rtc.c:299
static const uint16_t accu_month_len[12]
Definition hal_rtc.c:52
void rtcObjectInit(RTCDriver *rtcp)
Initializes a generic RTC driver object.
Definition hal_rtc.c:85
void rtc_lld_get_alarm(RTCDriver *rtcp, rtcalarm_t alarm, RTCAlarm *alarmspec)
Get alarm time.
HAL subsystem header.
Type of a structure representing an RTC alarm time stamp.
Type of a structure representing an RTC date/time stamp.
Definition hal_rtc.h:98
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
uint32_t millisecond
Milliseconds since midnight.
Definition hal_rtc.h:105
uint32_t dayofweek
Day of week 1..7.
Definition hal_rtc.h:103
uint32_t month
Months 1..12.
Definition hal_rtc.h:101
uint32_t year
Years since 1980.
Definition hal_rtc.h:100
Structure representing an RTC driver.
Definition hal_rtc.h:145
const struct RTCDriverVMT * vmt
Virtual Methods Table.
Definition hal_rtc.h:150