mirror of https://github.com/ARMmbed/mbed-os.git
remove usage of mktime/localtime in favor of dedicated functions.
The use of mktime was causing a fault when called in interrupt handler because on GCC it lock the mutex protecting the environment, To overcome this issue, this patch add dedicated routine to convert a time_t into a tm and vice versa. In the process mktime has been optimized and is now an order of magnitude faster than the routines present in the C library.pull/4499/head
parent
96288e3eef
commit
f880e44145
|
@ -0,0 +1,241 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
|
||||
#include "mbed.h"
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
/*
|
||||
* regular is_leap_year, see rtc_api.c for the optimized version
|
||||
*/
|
||||
bool is_leap_year(int year) {
|
||||
year = 1900 + year;
|
||||
if (year % 4) {
|
||||
return false;
|
||||
} else if (year % 100) {
|
||||
return true;
|
||||
} else if (year % 400) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the optimized version of _rtc_is_leap_year against the generic version.
|
||||
*/
|
||||
void test_is_leap_year() {
|
||||
for (int i = 70; i < 138; ++i) {
|
||||
bool expected = is_leap_year(i);
|
||||
bool actual_value = _rtc_is_leap_year(i);
|
||||
|
||||
if (expected != actual_value) {
|
||||
printf ("leap year failed with i = %d\r\n", i);
|
||||
}
|
||||
TEST_ASSERT_EQUAL(expected, actual_value);
|
||||
}
|
||||
}
|
||||
|
||||
struct tm make_time_info(int year, int month, int day, int hours, int minutes, int seconds) {
|
||||
struct tm timeinfo;
|
||||
timeinfo.tm_year = year;
|
||||
timeinfo.tm_mon = month;
|
||||
timeinfo.tm_mday = day;
|
||||
timeinfo.tm_hour = hours;
|
||||
timeinfo.tm_min = minutes;
|
||||
timeinfo.tm_sec = seconds;
|
||||
return timeinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* test out of range values for _rtc_mktime.
|
||||
* The function operates from the 1st of january 1970 at 00:00:00 to the 19th
|
||||
* of january 2038 at 03:14:07.
|
||||
*/
|
||||
void test_mk_time_out_of_range() {
|
||||
tm invalid_lower_bound = make_time_info(
|
||||
69,
|
||||
11,
|
||||
31,
|
||||
23,
|
||||
59,
|
||||
59
|
||||
);
|
||||
|
||||
tm valid_lower_bound = make_time_info(
|
||||
70,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
tm valid_upper_bound = make_time_info(
|
||||
138,
|
||||
0,
|
||||
19,
|
||||
3,
|
||||
14,
|
||||
7
|
||||
);
|
||||
|
||||
tm invalid_upper_bound = make_time_info(
|
||||
138,
|
||||
0,
|
||||
19,
|
||||
3,
|
||||
14,
|
||||
8
|
||||
);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(((time_t) -1), _rtc_mktime(&invalid_lower_bound));
|
||||
TEST_ASSERT_EQUAL_INT(((time_t) 0), _rtc_mktime(&valid_lower_bound));
|
||||
TEST_ASSERT_EQUAL_INT(((time_t) INT_MAX), _rtc_mktime(&valid_upper_bound));
|
||||
TEST_ASSERT_EQUAL_INT(((time_t) -1), _rtc_mktime(&invalid_upper_bound));
|
||||
}
|
||||
|
||||
/*
|
||||
* test mktime over a large set of values
|
||||
*/
|
||||
void test_mk_time() {
|
||||
for (size_t year = 70; year < 137; ++year) {
|
||||
for (size_t month = 0; month < 12; ++month) {
|
||||
for (size_t day = 1; day < 32; ++day) {
|
||||
if (month == 1 && is_leap_year(year) && day == 29) {
|
||||
break;
|
||||
} else if(month == 1 && !is_leap_year(year) && day == 28) {
|
||||
break;
|
||||
} else if (
|
||||
day == 31 &&
|
||||
(month == 3 || month == 5 || month == 8 || month == 10)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t hour = 0; hour < 24; ++hour) {
|
||||
tm time_info = make_time_info(
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
hour,
|
||||
hour % 2 ? 59 : 0,
|
||||
hour % 2 ? 59 : 0
|
||||
);
|
||||
|
||||
time_t expected = mktime(&time_info);
|
||||
time_t actual_value = _rtc_mktime(&time_info);
|
||||
|
||||
char msg[128] = "";
|
||||
if (expected != actual_value) {
|
||||
snprintf(
|
||||
msg, sizeof(msg),
|
||||
"year = %d, month = %d, day = %d, diff = %ld",
|
||||
year, month, day, expected - actual_value
|
||||
);
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual_value, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* test value out of range for localtime
|
||||
*/
|
||||
void test_local_time_limit() {
|
||||
struct tm dummy_value;
|
||||
TEST_ASSERT_FALSE(_rtc_localtime((time_t) -1, &dummy_value));
|
||||
TEST_ASSERT_FALSE(_rtc_localtime((time_t) INT_MIN, &dummy_value));
|
||||
}
|
||||
|
||||
/*
|
||||
* test _rtc_localtime over a large set of values.
|
||||
*/
|
||||
void test_local_time() {
|
||||
for (uint32_t i = 0; i < INT_MAX; i += 3451) {
|
||||
time_t copy = (time_t) i;
|
||||
struct tm* expected = localtime(©);
|
||||
struct tm actual_value;
|
||||
bool result = _rtc_localtime((time_t) i, &actual_value);
|
||||
|
||||
if (
|
||||
expected->tm_sec != actual_value.tm_sec ||
|
||||
expected->tm_min != actual_value.tm_min ||
|
||||
expected->tm_hour != actual_value.tm_hour ||
|
||||
expected->tm_mday != actual_value.tm_mday ||
|
||||
expected->tm_mon != actual_value.tm_mon ||
|
||||
expected->tm_year != actual_value.tm_year ||
|
||||
expected->tm_wday != actual_value.tm_wday ||
|
||||
result == false
|
||||
) {
|
||||
printf("error: i = %lu\r\n", i);
|
||||
}
|
||||
|
||||
TEST_ASSERT_TRUE(result);
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
||||
expected->tm_sec, actual_value.tm_sec, "invalid seconds"
|
||||
);
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
||||
expected->tm_min, actual_value.tm_min, "invalid minutes"
|
||||
);
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
||||
expected->tm_hour, actual_value.tm_hour, "invalid hours"
|
||||
);
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
||||
expected->tm_mday, actual_value.tm_mday, "invalid day"
|
||||
);
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
||||
expected->tm_mon, actual_value.tm_mon, "invalid month"
|
||||
);
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
||||
expected->tm_year, actual_value.tm_year, "invalid year"
|
||||
);
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
|
||||
expected->tm_wday, actual_value.tm_wday, "invalid weekday"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason) {
|
||||
greentea_case_failure_abort_handler(source, reason);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("test is leap year", test_is_leap_year, greentea_failure_handler),
|
||||
Case("test mk time out of range values", test_mk_time_out_of_range, greentea_failure_handler),
|
||||
Case("mk time", test_mk_time, greentea_failure_handler),
|
||||
Case("test local time", test_local_time, greentea_failure_handler),
|
||||
Case("test local time limits", test_local_time_limit, greentea_failure_handler),
|
||||
};
|
||||
|
||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
|
||||
GREENTEA_SETUP(1200, "default_auto");
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
||||
|
||||
int main() {
|
||||
return Harness::run(specification);
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017-2017 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
/*
|
||||
* time constants
|
||||
*/
|
||||
#define SECONDS_BY_MINUTES 60
|
||||
#define MINUTES_BY_HOUR 60
|
||||
#define SECONDS_BY_HOUR (SECONDS_BY_MINUTES * MINUTES_BY_HOUR)
|
||||
#define HOURS_BY_DAY 24
|
||||
#define SECONDS_BY_DAY (SECONDS_BY_HOUR * HOURS_BY_DAY)
|
||||
|
||||
/*
|
||||
* 2 dimensional array containing the number of seconds elapsed before a given
|
||||
* month.
|
||||
* The second index map to the month while the first map to the type of year:
|
||||
* - 0: non leap year
|
||||
* - 1: leap year
|
||||
*/
|
||||
static const uint32_t seconds_before_month[2][12] = {
|
||||
{
|
||||
0,
|
||||
31 * SECONDS_BY_DAY,
|
||||
(31 + 28) * SECONDS_BY_DAY,
|
||||
(31 + 28 + 31) * SECONDS_BY_DAY,
|
||||
(31 + 28 + 31 + 30) * SECONDS_BY_DAY,
|
||||
(31 + 28 + 31 + 30 + 31) * SECONDS_BY_DAY,
|
||||
(31 + 28 + 31 + 30 + 31 + 30) * SECONDS_BY_DAY,
|
||||
(31 + 28 + 31 + 30 + 31 + 30 + 31) * SECONDS_BY_DAY,
|
||||
(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31) * SECONDS_BY_DAY,
|
||||
(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30) * SECONDS_BY_DAY,
|
||||
(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31) * SECONDS_BY_DAY,
|
||||
(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30) * SECONDS_BY_DAY,
|
||||
},
|
||||
{
|
||||
0,
|
||||
31 * SECONDS_BY_DAY,
|
||||
(31 + 29) * SECONDS_BY_DAY,
|
||||
(31 + 29 + 31) * SECONDS_BY_DAY,
|
||||
(31 + 29 + 31 + 30) * SECONDS_BY_DAY,
|
||||
(31 + 29 + 31 + 30 + 31) * SECONDS_BY_DAY,
|
||||
(31 + 29 + 31 + 30 + 31 + 30) * SECONDS_BY_DAY,
|
||||
(31 + 29 + 31 + 30 + 31 + 30 + 31) * SECONDS_BY_DAY,
|
||||
(31 + 29 + 31 + 30 + 31 + 30 + 31 + 31) * SECONDS_BY_DAY,
|
||||
(31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30) * SECONDS_BY_DAY,
|
||||
(31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31) * SECONDS_BY_DAY,
|
||||
(31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30) * SECONDS_BY_DAY,
|
||||
}
|
||||
};
|
||||
|
||||
bool _rtc_is_leap_year(int year) {
|
||||
/*
|
||||
* since in practice, the value manipulated by this algorithm lie in the
|
||||
* range [70 : 138], the algorith can be reduced to: year % 4.
|
||||
* The algorithm valid over the full range of value is:
|
||||
|
||||
year = 1900 + year;
|
||||
if (year % 4) {
|
||||
return false;
|
||||
} else if (year % 100) {
|
||||
return true;
|
||||
} else if (year % 400) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
*/
|
||||
return (year) % 4 ? false : true;
|
||||
}
|
||||
|
||||
time_t _rtc_mktime(const struct tm* time) {
|
||||
// partial check for the upper bound of the range
|
||||
// normalization might happen at the end of the function
|
||||
// this solution is faster than checking if the input is after the 19th of
|
||||
// january 2038 at 03:14:07.
|
||||
if ((time->tm_year < 70) || (time->tm_year > 138)) {
|
||||
return ((time_t) -1);
|
||||
}
|
||||
|
||||
uint32_t result = time->tm_sec;
|
||||
result += time->tm_min * SECONDS_BY_MINUTES;
|
||||
result += time->tm_hour * SECONDS_BY_HOUR;
|
||||
result += (time->tm_mday - 1) * SECONDS_BY_DAY;
|
||||
result += seconds_before_month[_rtc_is_leap_year(time->tm_year)][time->tm_mon];
|
||||
|
||||
if (time->tm_year > 70) {
|
||||
// valid in the range [70:138]
|
||||
uint32_t count_of_leap_days = ((time->tm_year - 1) / 4) - (70 / 4);
|
||||
result += (((time->tm_year - 70) * 365) + count_of_leap_days) * SECONDS_BY_DAY;
|
||||
}
|
||||
|
||||
if (result > INT32_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool _rtc_localtime(time_t timestamp, struct tm* time_info) {
|
||||
if (((int32_t) timestamp) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time_info->tm_sec = timestamp % 60;
|
||||
timestamp = timestamp / 60; // timestamp in minutes
|
||||
time_info->tm_min = timestamp % 60;
|
||||
timestamp = timestamp / 60; // timestamp in hours
|
||||
time_info->tm_hour = timestamp % 24;
|
||||
timestamp = timestamp / 24; // timestamp in days;
|
||||
|
||||
// years start at 70
|
||||
time_info->tm_year = 70;
|
||||
while (true) {
|
||||
if (_rtc_is_leap_year(time_info->tm_year) && timestamp >= 366) {
|
||||
++time_info->tm_year;
|
||||
timestamp -= 366;
|
||||
} else if (!_rtc_is_leap_year(time_info->tm_year) && timestamp >= 365) {
|
||||
++time_info->tm_year;
|
||||
timestamp -= 365;
|
||||
} else {
|
||||
// the remaining days are less than a years
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert days into seconds and find the current month
|
||||
timestamp *= SECONDS_BY_DAY;
|
||||
time_info->tm_mon = 11;
|
||||
bool leap = _rtc_is_leap_year(time_info->tm_year);
|
||||
for (uint32_t i = 0; i < 12; ++i) {
|
||||
if ((uint32_t) timestamp < seconds_before_month[leap][i]) {
|
||||
time_info->tm_mon = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// remove month from timestamp and compute the number of days.
|
||||
// note: unlike other fields, days are not 0 indexed.
|
||||
timestamp -= seconds_before_month[leap][time_info->tm_mon];
|
||||
time_info->tm_mday = (timestamp / SECONDS_BY_DAY) + 1;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
/** \addtogroup platform */
|
||||
/** @{*/
|
||||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017-2017 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MBED_MKTIME_H
|
||||
#define MBED_MKTIME_H
|
||||
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compute if a year is a leap year or not.
|
||||
* year 0 is translated into year 1900 CE.
|
||||
*
|
||||
* @note - For use by the HAL only
|
||||
*/
|
||||
bool _rtc_is_leap_year(int year);
|
||||
|
||||
/*
|
||||
* Thread safe (partial) replacement for mktime.
|
||||
* This function is tailored around the RTC specification and is not a full
|
||||
* replacement for mktime.
|
||||
* The fields from tm used are:
|
||||
* - tm_sec
|
||||
* - tm_min
|
||||
* - tm_hour
|
||||
* - tm_mday
|
||||
* - tm_mon
|
||||
* - tm_year
|
||||
* Other fields are ignored and won't be normalized by the call.
|
||||
* If the time in input is less than UNIX epoch (1st january of 1970 at 00:00:00),
|
||||
* then this function consider the input as invalid and will return time_t(-1).
|
||||
* Values in output range from 0 to INT_MAX.
|
||||
* Leap seconds are not supported.
|
||||
*
|
||||
* @note - For use by the HAL only
|
||||
*/
|
||||
time_t _rtc_mktime(const struct tm* time);
|
||||
|
||||
/*
|
||||
* Thread safe (partial) replacement for localtime.
|
||||
* This function is tailored around the RTC specification and is not a full
|
||||
* replacement for localtime.
|
||||
* The tm fields filled by this function are:
|
||||
* - tm_sec
|
||||
* - tm_min
|
||||
* - tm_hour
|
||||
* - tm_mday
|
||||
* - tm_mon
|
||||
* - tm_year
|
||||
* The time in input shall be in the range [0, INT32_MAX] otherwise the function
|
||||
* will return false and the structure time_info in input will remain untouch.
|
||||
*
|
||||
* @note - For use by the HAL only
|
||||
*/
|
||||
bool _rtc_localtime(time_t timestamp, struct tm* time_info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MBED_MKTIME_H */
|
||||
|
||||
/** @}*/
|
|
@ -18,6 +18,7 @@
|
|||
#include "cmsis.h"
|
||||
#include "sysclk.h"
|
||||
#include "rtc.h"
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
static int rtc_inited = 0;
|
||||
|
||||
|
@ -70,7 +71,7 @@ time_t rtc_read(void)
|
|||
timeinfo.tm_year = (ul_year - 1900);
|
||||
|
||||
/* Convert to timestamp */
|
||||
time_t t = mktime(&timeinfo);
|
||||
time_t t = _rtc_mktime(&timeinfo);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -80,19 +81,22 @@ void rtc_write(time_t t)
|
|||
/* Initialize the RTC is not yet initialized */
|
||||
rtc_init();
|
||||
}
|
||||
struct tm *timeinfo = localtime(&t);
|
||||
struct tm timeinfo;
|
||||
if (st_rtc_localtime(t, &timeinfo) == false) {
|
||||
return;
|
||||
}
|
||||
uint32_t ul_hour, ul_minute, ul_second;
|
||||
uint32_t ul_year, ul_month, ul_day, ul_week;
|
||||
|
||||
ul_second = timeinfo->tm_sec;
|
||||
ul_minute = timeinfo->tm_min;
|
||||
ul_hour = timeinfo->tm_hour;
|
||||
ul_day = timeinfo->tm_mday;
|
||||
ul_week = timeinfo->tm_wday;
|
||||
ul_month = timeinfo->tm_mon;
|
||||
ul_year = timeinfo->tm_year;
|
||||
ul_second = timeinfo.tm_sec;
|
||||
ul_minute = timeinfo.tm_min;
|
||||
ul_hour = timeinfo.tm_hour;
|
||||
ul_day = timeinfo.tm_mday;
|
||||
ul_week = timeinfo.tm_wday;
|
||||
ul_month = timeinfo.tm_mon;
|
||||
ul_year = timeinfo.tm_year;
|
||||
|
||||
/* Set the RTC */
|
||||
rtc_set_time(RTC, ul_hour, ul_minute, ul_second);
|
||||
rtc_set_date(RTC, ul_year, ul_month, ul_day, ul_week);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mbed_error.h"
|
||||
#include "nu_modutil.h"
|
||||
#include "nu_miscutil.h"
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
#define YEAR0 1900
|
||||
//#define EPOCH_YR 1970
|
||||
|
@ -86,7 +87,7 @@ time_t rtc_read(void)
|
|||
timeinfo.tm_sec = rtc_datetime.u32Second;
|
||||
|
||||
// Convert to timestamp
|
||||
time_t t = mktime(&timeinfo);
|
||||
time_t t = _rtc_mktime(&timeinfo);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
@ -98,18 +99,21 @@ void rtc_write(time_t t)
|
|||
}
|
||||
|
||||
// Convert timestamp to struct tm
|
||||
struct tm *timeinfo = localtime(&t);
|
||||
struct tm timeinfo;
|
||||
if (st_rtc_localtime(t, &timeinfo) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
S_RTC_TIME_DATA_T rtc_datetime;
|
||||
|
||||
// Convert S_RTC_TIME_DATA_T to struct tm
|
||||
rtc_datetime.u32Year = timeinfo->tm_year + YEAR0;
|
||||
rtc_datetime.u32Month = timeinfo->tm_mon + 1;
|
||||
rtc_datetime.u32Day = timeinfo->tm_mday;
|
||||
rtc_datetime.u32DayOfWeek = timeinfo->tm_wday;
|
||||
rtc_datetime.u32Hour = timeinfo->tm_hour;
|
||||
rtc_datetime.u32Minute = timeinfo->tm_min;
|
||||
rtc_datetime.u32Second = timeinfo->tm_sec;
|
||||
rtc_datetime.u32Year = timeinfo.tm_year + YEAR0;
|
||||
rtc_datetime.u32Month = timeinfo.tm_mon + 1;
|
||||
rtc_datetime.u32Day = timeinfo.tm_mday;
|
||||
rtc_datetime.u32DayOfWeek = timeinfo.tm_wday;
|
||||
rtc_datetime.u32Hour = timeinfo.tm_hour;
|
||||
rtc_datetime.u32Minute = timeinfo.tm_min;
|
||||
rtc_datetime.u32Second = timeinfo.tm_sec;
|
||||
rtc_datetime.u32TimeScale = RTC_CLOCK_24;
|
||||
|
||||
// NOTE: Timing issue with write to RTC registers. This delay is empirical, not rational.
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mbed_error.h"
|
||||
#include "nu_modutil.h"
|
||||
#include "nu_miscutil.h"
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
#define YEAR0 1900
|
||||
//#define EPOCH_YR 1970
|
||||
|
@ -86,7 +87,7 @@ time_t rtc_read(void)
|
|||
timeinfo.tm_sec = rtc_datetime.u32Second;
|
||||
|
||||
// Convert to timestamp
|
||||
time_t t = mktime(&timeinfo);
|
||||
time_t t = _rtc_mktime(&timeinfo);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
@ -98,18 +99,21 @@ void rtc_write(time_t t)
|
|||
}
|
||||
|
||||
// Convert timestamp to struct tm
|
||||
struct tm *timeinfo = localtime(&t);
|
||||
struct tm timeinfo;
|
||||
if (st_rtc_localtime(t, &timeinfo) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
S_RTC_TIME_DATA_T rtc_datetime;
|
||||
|
||||
// Convert S_RTC_TIME_DATA_T to struct tm
|
||||
rtc_datetime.u32Year = timeinfo->tm_year + YEAR0;
|
||||
rtc_datetime.u32Month = timeinfo->tm_mon + 1;
|
||||
rtc_datetime.u32Day = timeinfo->tm_mday;
|
||||
rtc_datetime.u32DayOfWeek = timeinfo->tm_wday;
|
||||
rtc_datetime.u32Hour = timeinfo->tm_hour;
|
||||
rtc_datetime.u32Minute = timeinfo->tm_min;
|
||||
rtc_datetime.u32Second = timeinfo->tm_sec;
|
||||
rtc_datetime.u32Year = timeinfo.tm_year + YEAR0;
|
||||
rtc_datetime.u32Month = timeinfo.tm_mon + 1;
|
||||
rtc_datetime.u32Day = timeinfo.tm_mday;
|
||||
rtc_datetime.u32DayOfWeek = timeinfo.tm_wday;
|
||||
rtc_datetime.u32Hour = timeinfo.tm_hour;
|
||||
rtc_datetime.u32Minute = timeinfo.tm_min;
|
||||
rtc_datetime.u32Second = timeinfo.tm_sec;
|
||||
rtc_datetime.u32TimeScale = RTC_CLOCK_24;
|
||||
|
||||
// NOTE: Timing issue with write to RTC registers. This delay is empirical, not rational.
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
#include "rtc_api.h"
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
// ensure rtc is running (unchanged if already running)
|
||||
|
||||
|
@ -88,25 +89,28 @@ time_t rtc_read(void) {
|
|||
timeinfo.tm_year = LPC_RTC->YEAR - 1900;
|
||||
|
||||
// Convert to timestamp
|
||||
time_t t = mktime(&timeinfo);
|
||||
time_t t = _rtc_mktime(&timeinfo);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void rtc_write(time_t t) {
|
||||
// Convert the time in to a tm
|
||||
struct tm *timeinfo = localtime(&t);
|
||||
struct tm timeinfo;
|
||||
if (st_rtc_localtime(t, &timeinfo) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pause clock, and clear counter register (clears us count)
|
||||
LPC_RTC->CCR |= 2;
|
||||
|
||||
// Set the RTC
|
||||
LPC_RTC->SEC = timeinfo->tm_sec;
|
||||
LPC_RTC->MIN = timeinfo->tm_min;
|
||||
LPC_RTC->HOUR = timeinfo->tm_hour;
|
||||
LPC_RTC->DOM = timeinfo->tm_mday;
|
||||
LPC_RTC->MONTH = timeinfo->tm_mon + 1;
|
||||
LPC_RTC->YEAR = timeinfo->tm_year + 1900;
|
||||
LPC_RTC->SEC = timeinfo.tm_sec;
|
||||
LPC_RTC->MIN = timeinfo.tm_min;
|
||||
LPC_RTC->HOUR = timeinfo.tm_hour;
|
||||
LPC_RTC->DOM = timeinfo.tm_mday;
|
||||
LPC_RTC->MONTH = timeinfo.tm_mon + 1;
|
||||
LPC_RTC->YEAR = timeinfo.tm_year + 1900;
|
||||
|
||||
// Restart clock
|
||||
LPC_RTC->CCR &= ~((uint32_t)2);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
#include "rtc_api.h"
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
// ensure rtc is running (unchanged if already running)
|
||||
|
||||
|
@ -87,25 +88,28 @@ time_t rtc_read(void) {
|
|||
timeinfo.tm_year = LPC_RTC->YEAR - 1900;
|
||||
|
||||
// Convert to timestamp
|
||||
time_t t = mktime(&timeinfo);
|
||||
time_t t = _rtc_mktime(&timeinfo);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void rtc_write(time_t t) {
|
||||
// Convert the time in to a tm
|
||||
struct tm *timeinfo = localtime(&t);
|
||||
struct tm timeinfo;
|
||||
if (st_rtc_localtime(t, &timeinfo) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pause clock, and clear counter register (clears us count)
|
||||
LPC_RTC->CCR |= 2;
|
||||
|
||||
// Set the RTC
|
||||
LPC_RTC->SEC = timeinfo->tm_sec;
|
||||
LPC_RTC->MIN = timeinfo->tm_min;
|
||||
LPC_RTC->HOUR = timeinfo->tm_hour;
|
||||
LPC_RTC->DOM = timeinfo->tm_mday;
|
||||
LPC_RTC->MONTH = timeinfo->tm_mon + 1;
|
||||
LPC_RTC->YEAR = timeinfo->tm_year + 1900;
|
||||
LPC_RTC->SEC = timeinfo.tm_sec;
|
||||
LPC_RTC->MIN = timeinfo.tm_min;
|
||||
LPC_RTC->HOUR = timeinfo.tm_hour;
|
||||
LPC_RTC->DOM = timeinfo.tm_mday;
|
||||
LPC_RTC->MONTH = timeinfo.tm_mon + 1;
|
||||
LPC_RTC->YEAR = timeinfo.tm_year + 1900;
|
||||
|
||||
// Restart clock
|
||||
LPC_RTC->CCR &= ~((uint32_t)2);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* Ported to NXP LPC43XX by Micromint USA <support@micromint.com>
|
||||
*/
|
||||
#include "rtc_api.h"
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
// ensure rtc is running (unchanged if already running)
|
||||
|
||||
|
@ -101,27 +102,30 @@ time_t rtc_read(void) {
|
|||
timeinfo.tm_year = LPC_RTC->TIME[RTC_TIMETYPE_YEAR] - 1900;
|
||||
|
||||
// Convert to timestamp
|
||||
time_t t = mktime(&timeinfo);
|
||||
time_t t = _rtc_mktime(&timeinfo);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void rtc_write(time_t t) {
|
||||
// Convert the time in to a tm
|
||||
struct tm *timeinfo = localtime(&t);
|
||||
struct tm timeinfo;
|
||||
if (st_rtc_localtime(t, &timeinfo) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pause clock, and clear counter register (clears us count)
|
||||
LPC_RTC->CCR |= 2;
|
||||
|
||||
// Set the RTC
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_SECOND] = timeinfo->tm_sec;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_MINUTE] = timeinfo->tm_min;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_HOUR] = timeinfo->tm_hour;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_DAYOFMONTH] = timeinfo->tm_mday;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_DAYOFWEEK] = timeinfo->tm_wday;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_DAYOFYEAR] = timeinfo->tm_yday;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_MONTH] = timeinfo->tm_mon + 1;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_YEAR] = timeinfo->tm_year + 1900;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_SECOND] = timeinfo.tm_sec;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_MINUTE] = timeinfo.tm_min;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_HOUR] = timeinfo.tm_hour;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_DAYOFMONTH] = timeinfo.tm_mday;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_DAYOFWEEK] = timeinfo.tm_wday;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_DAYOFYEAR] = timeinfo.tm_yday;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_MONTH] = timeinfo.tm_mon + 1;
|
||||
LPC_RTC->TIME[RTC_TIMETYPE_YEAR] = timeinfo.tm_year + 1900;
|
||||
|
||||
// Restart clock
|
||||
LPC_RTC->CCR &= ~((uint32_t)2);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "rtc_api.h"
|
||||
#include "rtc_iodefine.h"
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
|
||||
#define RCR1_VAL_ON (0x08u) // AIE = 1
|
||||
|
@ -213,7 +214,7 @@ time_t rtc_read(void) {
|
|||
|
||||
if (err == 0) {
|
||||
// Convert to timestamp
|
||||
t = mktime(&timeinfo);
|
||||
t = _rtc_mktime(&timeinfo);
|
||||
} else {
|
||||
// Error
|
||||
t = TIME_ERROR_VAL;
|
||||
|
@ -303,7 +304,10 @@ static int rtc_dec16_to_hex(uint16_t dec_val, uint16_t offset, int *hex_val) {
|
|||
*/
|
||||
void rtc_write(time_t t) {
|
||||
|
||||
struct tm *timeinfo = localtime(&t);
|
||||
struct tm timeinfo;
|
||||
if (st_rtc_localtime(t, &timeinfo) == false) {
|
||||
return;
|
||||
}
|
||||
volatile uint16_t dummy_read;
|
||||
|
||||
if (rtc_isenabled() != 0) {
|
||||
|
@ -314,12 +318,12 @@ void rtc_write(time_t t) {
|
|||
dummy_read = (uint16_t)RTC.RCR2;
|
||||
dummy_read = (uint16_t)RTC.RCR2;
|
||||
|
||||
RTC.RSECCNT = rtc_hex8_to_dec(timeinfo->tm_sec);
|
||||
RTC.RMINCNT = rtc_hex8_to_dec(timeinfo->tm_min);
|
||||
RTC.RHRCNT = rtc_hex8_to_dec(timeinfo->tm_hour);
|
||||
RTC.RDAYCNT = rtc_hex8_to_dec(timeinfo->tm_mday);
|
||||
RTC.RMONCNT = rtc_hex8_to_dec(timeinfo->tm_mon + 1);
|
||||
RTC.RYRCNT = rtc_hex16_to_dec(timeinfo->tm_year + 1900);
|
||||
RTC.RSECCNT = rtc_hex8_to_dec(timeinfo.tm_sec);
|
||||
RTC.RMINCNT = rtc_hex8_to_dec(timeinfo.tm_min);
|
||||
RTC.RHRCNT = rtc_hex8_to_dec(timeinfo.tm_hour);
|
||||
RTC.RDAYCNT = rtc_hex8_to_dec(timeinfo.tm_mday);
|
||||
RTC.RMONCNT = rtc_hex8_to_dec(timeinfo.tm_mon + 1);
|
||||
RTC.RYRCNT = rtc_hex16_to_dec(timeinfo.tm_year + 1900);
|
||||
dummy_read = (uint16_t)RTC.RYRCNT;
|
||||
dummy_read = (uint16_t)RTC.RYRCNT;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "rtc_api.h"
|
||||
#include "rtc_iodefine.h"
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
|
||||
#define RCR1_VAL_ON (0x08u) // AIE = 1
|
||||
|
@ -247,7 +248,7 @@ time_t rtc_read(void) {
|
|||
|
||||
if (err == 0) {
|
||||
// Convert to timestamp
|
||||
t = mktime(&timeinfo);
|
||||
t = _rtc_mktime(&timeinfo);
|
||||
} else {
|
||||
// Error
|
||||
t = TIME_ERROR_VAL;
|
||||
|
@ -337,7 +338,10 @@ static int rtc_dec16_to_hex(uint16_t dec_val, uint16_t offset, int *hex_val) {
|
|||
*/
|
||||
void rtc_write(time_t t) {
|
||||
|
||||
struct tm *timeinfo = localtime(&t);
|
||||
struct tm timeinfo;
|
||||
if (st_rtc_localtime(t, &timeinfo) == false) {
|
||||
return;
|
||||
}
|
||||
volatile uint16_t dummy_read;
|
||||
|
||||
if (rtc_isenabled() != 0) {
|
||||
|
@ -348,12 +352,12 @@ void rtc_write(time_t t) {
|
|||
dummy_read = (uint16_t)RTC.RCR2;
|
||||
dummy_read = (uint16_t)RTC.RCR2;
|
||||
|
||||
RTC.RSECCNT = rtc_hex8_to_dec(timeinfo->tm_sec);
|
||||
RTC.RMINCNT = rtc_hex8_to_dec(timeinfo->tm_min);
|
||||
RTC.RHRCNT = rtc_hex8_to_dec(timeinfo->tm_hour);
|
||||
RTC.RDAYCNT = rtc_hex8_to_dec(timeinfo->tm_mday);
|
||||
RTC.RMONCNT = rtc_hex8_to_dec(timeinfo->tm_mon + 1);
|
||||
RTC.RYRCNT = rtc_hex16_to_dec(timeinfo->tm_year + 1900);
|
||||
RTC.RSECCNT = rtc_hex8_to_dec(timeinfo.tm_sec);
|
||||
RTC.RMINCNT = rtc_hex8_to_dec(timeinfo.tm_min);
|
||||
RTC.RHRCNT = rtc_hex8_to_dec(timeinfo.tm_hour);
|
||||
RTC.RDAYCNT = rtc_hex8_to_dec(timeinfo.tm_mday);
|
||||
RTC.RMONCNT = rtc_hex8_to_dec(timeinfo.tm_mon + 1);
|
||||
RTC.RYRCNT = rtc_hex16_to_dec(timeinfo.tm_year + 1900);
|
||||
dummy_read = (uint16_t)RTC.RYRCNT;
|
||||
dummy_read = (uint16_t)RTC.RYRCNT;
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "rtc_api.h"
|
||||
#include "rtc_api_hal.h"
|
||||
#include "mbed_error.h"
|
||||
#include "mbed_mktime.h"
|
||||
|
||||
static RTC_HandleTypeDef RtcHandle;
|
||||
|
||||
|
@ -239,7 +240,7 @@ time_t rtc_read(void)
|
|||
timeinfo.tm_isdst = -1;
|
||||
|
||||
// Convert to timestamp
|
||||
time_t t = mktime(&timeinfo);
|
||||
time_t t = _rtc_mktime(&timeinfo);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
@ -252,20 +253,23 @@ void rtc_write(time_t t)
|
|||
RtcHandle.Instance = RTC;
|
||||
|
||||
// Convert the time into a tm
|
||||
struct tm *timeinfo = localtime(&t);
|
||||
struct tm timeinfo;
|
||||
if (st_rtc_localtime(t, &timeinfo) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fill RTC structures
|
||||
if (timeinfo->tm_wday == 0) {
|
||||
if (timeinfo.tm_wday == 0) {
|
||||
dateStruct.WeekDay = 7;
|
||||
} else {
|
||||
dateStruct.WeekDay = timeinfo->tm_wday;
|
||||
dateStruct.WeekDay = timeinfo.tm_wday;
|
||||
}
|
||||
dateStruct.Month = timeinfo->tm_mon + 1;
|
||||
dateStruct.Date = timeinfo->tm_mday;
|
||||
dateStruct.Year = timeinfo->tm_year - 68;
|
||||
timeStruct.Hours = timeinfo->tm_hour;
|
||||
timeStruct.Minutes = timeinfo->tm_min;
|
||||
timeStruct.Seconds = timeinfo->tm_sec;
|
||||
dateStruct.Month = timeinfo.tm_mon + 1;
|
||||
dateStruct.Date = timeinfo.tm_mday;
|
||||
dateStruct.Year = timeinfo.tm_year - 68;
|
||||
timeStruct.Hours = timeinfo.tm_hour;
|
||||
timeStruct.Minutes = timeinfo.tm_min;
|
||||
timeStruct.Seconds = timeinfo.tm_sec;
|
||||
|
||||
#if !(TARGET_STM32F1)
|
||||
timeStruct.TimeFormat = RTC_HOURFORMAT_24;
|
||||
|
|
Loading…
Reference in New Issue