mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-08-28 07:40:18 +08:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user