From eae0863a1cf09d5f2f6f6af5df405dc9b727fac5 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sun, 27 Apr 2014 18:11:09 +1000 Subject: 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. --- cpukit/rtems/src/clockgettod.c | 107 +++++++++++++++++++++++++++++++++++------ 1 file changed, 93 insertions(+), 14 deletions(-) (limited to 'cpukit/rtems/src/clockgettod.c') 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 #include +#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; } -- cgit v1.2.3