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.
This commit is contained in:
Chris Johns
2014-05-22 16:38:01 +10:00
parent a070c8bb81
commit eae0863a1c
2 changed files with 129 additions and 13 deletions
+92 -13
View File
@@ -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 );
/* 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;
/* 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 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;
}
+37
View File
@@ -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();