summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2014-04-27 18:11:09 +1000
committerChris Johns <chrisj@rtems.org>2014-05-22 16:38:01 +1000
commiteae0863a1cf09d5f2f6f6af5df405dc9b727fac5 (patch)
treecc3bc828b32b96ab52a3af260e4e411209a5a488
parentrtems: Simplify rtems_semaphore_obtain() (diff)
downloadrtems-eae0863a1cf09d5f2f6f6af5df405dc9b727fac5.tar.bz2
rtems: Fix sp2038 test.
Avoid using newlib's gmtime_r call which fails with a max signed int. Add an RTEMS specific version for 1/1/1988 to 31/12/2100. Update sp2038 to test every day from 1/1/1988 to 31/12/2100. Only days need be tested as the code splits the seconds based on days.
-rw-r--r--cpukit/rtems/src/clockgettod.c107
-rw-r--r--testsuites/sptests/sp2038/init.c37
2 files changed, 130 insertions, 14 deletions
diff --git a/cpukit/rtems/src/clockgettod.c b/cpukit/rtems/src/clockgettod.c
index 743e1ecb42..eb01f0ffdc 100644
--- a/cpukit/rtems/src/clockgettod.c
+++ b/cpukit/rtems/src/clockgettod.c
@@ -22,13 +22,74 @@
#include <rtems/score/todimpl.h>
#include <rtems/config.h>
+#define RTEMS_SECS_PER_MINUTE (60UL)
+#define RTEMS_MINUTE_PER_HOUR (60UL)
+#define RTEMS_SECS_PER_HOUR (RTEMS_SECS_PER_MINUTE * RTEMS_MINUTE_PER_HOUR)
+#define RTEMS_HOURS_PER_DAY (24UL)
+#define RTEMS_SECS_PER_DAY (RTEMS_SECS_PER_HOUR * RTEMS_HOURS_PER_DAY)
+#define RTEMS_DAYS_PER_YEAR (365UL)
+#define RTEMS_YEAR_BASE (1970UL)
+
+extern const uint16_t _TOD_Days_to_date[2][13];
+
+static bool _Leap_year(
+ uint32_t year
+)
+{
+ return (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0);
+}
+
+static uint32_t _Leap_years_before(
+ uint32_t year
+)
+{
+ year -= 1;
+ return (year / 4) - (year / 100) + (year / 400);
+}
+
+static uint32_t _Leap_years_between(
+ uint32_t from, uint32_t to
+)
+{
+ return _Leap_years_before( to ) - _Leap_years_before( from + 1 );
+}
+
+static uint32_t _Year_day_as_month(
+ uint32_t year, uint32_t *day
+)
+{
+ const uint16_t* days_to_date;
+ uint32_t month = 0;
+
+ if ( _Leap_year( year ) )
+ days_to_date = _TOD_Days_to_date[1];
+ else
+ days_to_date = _TOD_Days_to_date[0];
+
+ days_to_date += 2;
+
+ while (month < 11) {
+ if (*day < *days_to_date)
+ break;
+ ++month;
+ ++days_to_date;
+ }
+
+ *day -= *(days_to_date - 1);
+
+ return month;
+}
+
rtems_status_code rtems_clock_get_tod(
rtems_time_of_day *time_buffer
)
{
- rtems_time_of_day *tmbuf = time_buffer;
- struct tm time;
struct timeval now;
+ uint32_t days;
+ uint32_t day_secs;
+ uint32_t year;
+ uint32_t year_days;
+ uint32_t leap_years;
if ( !time_buffer )
return RTEMS_INVALID_ADDRESS;
@@ -39,18 +100,36 @@ rtems_status_code rtems_clock_get_tod(
/* Obtain the current time */
_TOD_Get_timeval( &now );
- /* Split it into a closer format */
- gmtime_r( &now.tv_sec, &time );
-
- /* Now adjust it to the RTEMS format */
- tmbuf->year = time.tm_year + 1900;
- tmbuf->month = time.tm_mon + 1;
- tmbuf->day = time.tm_mday;
- tmbuf->hour = time.tm_hour;
- tmbuf->minute = time.tm_min;
- tmbuf->second = time.tm_sec;
- tmbuf->ticks = now.tv_usec /
- rtems_configuration_get_microseconds_per_tick();
+ /* How many days and how many seconds in the day ? */
+ days = now.tv_sec / RTEMS_SECS_PER_DAY;
+ day_secs = now.tv_sec % RTEMS_SECS_PER_DAY;
+
+ /* How many non-leap year years ? */
+ year = ( days / RTEMS_DAYS_PER_YEAR ) + RTEMS_YEAR_BASE;
+
+ /* Determine the number of leap years. */
+ leap_years = _Leap_years_between( RTEMS_YEAR_BASE, year );
+
+ /* Adjust the remaining number of days based on the leap years. */
+ year_days = ( days - leap_years ) % RTEMS_DAYS_PER_YEAR;
+
+ /* Adjust the year and days in the year if in the leap year overflow. */
+ if ( leap_years > ( days % RTEMS_DAYS_PER_YEAR ) ) {
+ year -= 1;
+ if ( _Leap_year( year ) ) {
+ year_days += 1;
+ }
+ }
+
+ time_buffer->year = year;
+ time_buffer->month = _Year_day_as_month( year, &year_days ) + 1;
+ time_buffer->day = year_days + 1;
+ time_buffer->hour = day_secs / RTEMS_SECS_PER_HOUR;
+ time_buffer->minute = day_secs % RTEMS_SECS_PER_HOUR;
+ time_buffer->second = time_buffer->minute % RTEMS_SECS_PER_MINUTE;
+ time_buffer->minute = time_buffer->minute / RTEMS_SECS_PER_MINUTE;
+ time_buffer->ticks = now.tv_usec /
+ rtems_configuration_get_microseconds_per_tick( );
return RTEMS_SUCCESSFUL;
}
diff --git a/testsuites/sptests/sp2038/init.c b/testsuites/sptests/sp2038/init.c
index 9fac38a23c..e5a3906ee6 100644
--- a/testsuites/sptests/sp2038/init.c
+++ b/testsuites/sptests/sp2038/init.c
@@ -283,12 +283,49 @@ static void test_leap_year(void)
rtems_test_assert(test_status == false);
}
+static bool test_year_is_leap_year(uint32_t year)
+{
+ return (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0);
+}
+
+static void test_every_day(void)
+{
+ rtems_time_of_day every_day = {
+ .year = 1970,
+ .month = 1,
+ .day = 1,
+ .hour = 0,
+ .minute = 1,
+ .second = 2
+ };
+ const int days_per_month[2][12] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+ };
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_time_of_day now;
+
+ for (every_day.year = 1988; every_day.year <= 2100; ++every_day.year) {
+ int leap_year = test_year_is_leap_year(every_day.year) ? 1 : 0;
+ for (every_day.month = 1; every_day.month <= 12; ++every_day.month) {
+ int days = days_per_month[leap_year][every_day.month - 1];
+ for (every_day.day = 1; every_day.day <= days; ++every_day.day) {
+ sc = rtems_clock_set(&every_day);
+ ASSERT_SC(sc);
+ sc = rtems_clock_get_tod(&now);
+ ASSERT_SC(sc);
+ rtems_test_assert(memcmp(&now, &every_day, sizeof(now)) == 0);
+ }
+ }
+ }
+}
rtems_task Init(rtems_task_argument argument)
{
TEST_BEGIN();
test_tod_to_seconds();
+ test_every_day();
test_problem_year();
test_leap_year();