Skip to content

Commit

Permalink
Add tests for time types
Browse files Browse the repository at this point in the history
  • Loading branch information
chintal committed Oct 7, 2024
1 parent aaad861 commit a29a883
Show file tree
Hide file tree
Showing 12 changed files with 1,108 additions and 50 deletions.
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ build_flags =
-fdata-sections -ffunction-sections
-std=gnu++11
-Wl,-Map,${BUILD_DIR}/firmware.${PIOPLATFORM}.map -g
-lgcov --coverage -fprofile-abs-path

[env:native]
platform = native
Expand Down
138 changes: 102 additions & 36 deletions src/time/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
* @see time.h
*/

#include <stdio.h>
#include <ds/sllist.h>
#include <ucdm/ucdm.h>
#include <ucdm/descriptor.h>
Expand Down Expand Up @@ -120,12 +121,43 @@ void tm_clear_rdelta(tm_rdelta_t* rdelta){
return;
}

uint8_t tm_check_invalid_rtime(tm_real_t* rtime){
if (rtime->century > 24) {
return 1;
}
if (rtime->year > 99) {
return 2;
}
if (rtime->month < 1 || rtime->month > 12) {
return 3;
}
if (rtime->date < 1 || rtime->date > 31) {
// This should actually check based on month
// and year
return 4;
}
if (rtime->hours > 23) {
return 5;
}
if (rtime->minutes > 59) {
return 6;
}
if (rtime->seconds > 59) {
return 7;
}
if (rtime->millis > 999) {
return 8;
}
return 0;
}


void tm_sdelta_from_rdelta(tm_rdelta_t* rdelta, tm_sdelta_t* sdelta){
uint64_t result;
result = rdelta->days * TIME_SECONDS_PER_DAY * 1000;
result += rdelta->hours * TIME_SECONDS_PER_HOUR * 1000;
result += rdelta->minutes * TIME_SECONDS_PER_MINUTE * 1000;
result += rdelta->seconds * 1000;
result = rdelta->days * TIME_SECONDS_PER_DAY * 1000LL;
result += rdelta->hours * TIME_SECONDS_PER_HOUR * 1000LL;
result += rdelta->minutes * TIME_SECONDS_PER_MINUTE * 1000LL;
result += rdelta->seconds * 1000LL;
result += rdelta->millis;
if (rdelta->sgn) {
result = result * -1;
Expand All @@ -136,22 +168,23 @@ void tm_sdelta_from_rdelta(tm_rdelta_t* rdelta, tm_sdelta_t* sdelta){
void tm_rdelta_from_sdelta(tm_sdelta_t* sdelta, tm_rdelta_t* rdelta){
tm_clear_rdelta(rdelta);
tm_sdelta_t sdelta_copy = *sdelta;

if (sdelta < 0){
if (sdelta_copy < 0){
rdelta->sgn = 1;
sdelta_copy *= -1;
}

rdelta->days = sdelta_copy / (TIME_SECONDS_PER_DAY * 1000LL);
sdelta_copy -= rdelta->days * (TIME_SECONDS_PER_DAY * 1000LL);

rdelta->hours = sdelta_copy / (TIME_SECONDS_PER_HOUR * 1000LL);
sdelta_copy -= rdelta->hours * (TIME_SECONDS_PER_HOUR * 1000LL);

rdelta->minutes = sdelta_copy / (TIME_SECONDS_PER_MINUTE * 1000LL);
sdelta_copy -= rdelta->minutes * (TIME_SECONDS_PER_MINUTE * 1000LL);

rdelta->days = sdelta_copy / (TIME_SECONDS_PER_DAY * 1000);
sdelta_copy -= rdelta->days * (TIME_SECONDS_PER_DAY * 1000);

rdelta->hours = sdelta_copy / (TIME_SECONDS_PER_HOUR * 1000);
sdelta_copy -= rdelta->hours * (TIME_SECONDS_PER_HOUR * 1000);

rdelta->minutes = sdelta_copy / (TIME_SECONDS_PER_MINUTE * 1000);
sdelta_copy -= rdelta->minutes * (TIME_SECONDS_PER_MINUTE * 1000);

rdelta->seconds = sdelta_copy / 1000;
sdelta_copy -= rdelta->seconds * 1000;
rdelta->seconds = sdelta_copy / 1000LL;
sdelta_copy -= rdelta->seconds * 1000LL;

rdelta->millis = sdelta_copy;
return;
Expand All @@ -160,53 +193,69 @@ void tm_rdelta_from_sdelta(tm_sdelta_t* sdelta, tm_rdelta_t* rdelta){
static const int16_t days_to_month[]=
{0, 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};

static const int8_t days_in_month[]=
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

static uint16_t gyear(tm_real_t * rtime);

static uint16_t gyear(tm_real_t * rtime){
return ((uint16_t)(rtime->century) * 100 + rtime->year);
uint16_t result = (uint16_t)(rtime->century) * 100 + rtime->year;
return (result);
}

void tm_stime_from_rtime(tm_real_t* rtime, tm_system_t * stime){
uint16_t days = rtime->date - 1;
int32_t days = rtime->date - 1;
uint16_t syear = 0;
uint8_t years = 0;
int16_t years = 0;

if (!use_epoch){
return;
}

days += days_to_month[rtime->month];
syear = gyear(&tm_internal_epoch);
years = (uint8_t)(gyear(rtime) - syear);
years = (int16_t)(gyear(rtime) - syear);
if (rtime->month < 3){
years --;
} else {
uint16_t lyear = gyear(rtime);
if ((!(lyear % 4) && (lyear % 100)) || !(lyear % 400)){
days ++;
}
}

days += (years * 365);
while (years){

while (years > 0){
if ((!(syear % 4) && (syear % 100)) || !(syear % 400)){
days ++;
}
syear ++;
years --;
}

*stime = (( days * TIME_SECONDS_PER_DAY * 1000) +
( rtime->hours * TIME_SECONDS_PER_HOUR * 1000) +
(rtime->minutes * TIME_SECONDS_PER_MINUTE * 1000) +
(rtime->seconds * 1000) + rtime->millis +
while (years < 0){
if ((!(syear % 4) && (syear % 100)) || !(syear % 400)){
days --;
}
syear --;
years ++;
}

*stime = (( days * TIME_SECONDS_PER_DAY * 1000LL) +
( rtime->hours * TIME_SECONDS_PER_HOUR * 1000LL) +
(rtime->minutes * TIME_SECONDS_PER_MINUTE * 1000LL) +
(rtime->seconds * 1000LL) + rtime->millis +
tm_leapseconds - tm_internal_epoch_offset);
}

// TODO Untested. Horribly unoptimized.

void tm_rtime_from_stime(tm_system_t* stime, tm_real_t* rtime){
if (!use_epoch){
return;
}

*rtime = tm_internal_epoch;
tm_system_t stime_internal = *stime + tm_internal_epoch_offset - tm_leapseconds;

uint32_t days = stime_internal / (TIME_SECONDS_PER_DAY * 1000);
uint32_t remaining_ms = stime_internal % (TIME_SECONDS_PER_DAY * 1000);

Expand All @@ -219,18 +268,35 @@ void tm_rtime_from_stime(tm_system_t* stime, tm_real_t* rtime){

uint16_t year = gyear(&tm_internal_epoch);
while (days >= 365) {
uint16_t leap_adjustment = ((!(year % 4) && (year % 100)) || !(year % 400)) ? 366 : 365;

uint16_t leap_adjustment = ((!((year+1)% 4) && ((year+1) % 100)) || !((year+1) % 400)) ? 366 : 365;
if (days < leap_adjustment) break;
days -= leap_adjustment;
year++;
}


// Calculate month, starting from march
uint8_t next_month = 3;
uint8_t next_month_days = 31;
while (days >= next_month_days) {
days -= next_month_days;
if (next_month == 12) {
year ++;
next_month = 1;
} else {
next_month ++;
}
rtime->month = next_month;

if (next_month == 2 && ((!(year % 4) && (year % 100)) || !(year % 400))){
next_month_days = 29;
} else {
next_month_days = days_in_month[next_month];
}
}
rtime->date = days + 1; // Days are 1-indexed
rtime->year = year % 100;
rtime->century = year / 100;

// TODO
rtime->month = 0;
rtime->date = 0;
}

/*
Expand Down
38 changes: 28 additions & 10 deletions src/time/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@

#define TIME_SYSTICK_PERIOD_uS 1000

#define TIME_TICKS_PER_SECOND (uint32_t)(1000000 / TIME_SYSTICK_PERIOD_uS)
#define TIME_TICKS_PER_SECOND (int32_t)(1000000 / TIME_SYSTICK_PERIOD_uS)
#define TIME_TICKS_PER_MINUTE (TIME_TICKS_PER_SECOND * 60)
#define TIME_TICKS_PER_HOUR (TIME_TICKS_PER_MINUTE * 60)
#define TIME_TICKS_PER_DAY (TIME_TICKS_PER_HOUR * 24)

#define TIME_SECONDS_PER_MINUTE (uint32_t)(60)
#define TIME_SECONDS_PER_MINUTE (int32_t)(60)
#define TIME_SECONDS_PER_HOUR (TIME_SECONDS_PER_MINUTE * 60)
#define TIME_SECONDS_PER_DAY (TIME_SECONDS_PER_HOUR * 24)

Expand Down Expand Up @@ -142,6 +142,13 @@ typedef int64_t tm_sdelta_t;
* UTC time (GMT+0000). See the documentation of time.h for further detail
* about the interpretation of time by this library.
*
* This library does no implicit validation of the data provided, and
* values outside expected ranges of each component of the real time
* can cause unexpected behaviour and crashes. If applications use
* uexternal or unsanitized sources to initizalize this type, then the
* application must also validate the input. One option to do so would
* be to initialize the tm_real_t and then use tm_check_invalid_rtime().
*
*/
typedef struct TM_REAL_t{
uint8_t century;
Expand All @@ -166,11 +173,11 @@ typedef struct TM_REAL_t{
*/
typedef struct TM_RDELTA_t{
uint8_t sgn;
uint16_t millis;
uint8_t seconds;
uint8_t minutes;
uint8_t hours;
uint16_t days;
uint16_t millis;
} tm_rdelta_t;


Expand Down Expand Up @@ -256,33 +263,44 @@ uint16_t tm_init(uint16_t ucdm_address);
void tm_install_descriptor(void);

/**
* @brief Clear a time_system_t instance.
* @brief Clear a tm_system_t instance.
*
* @param stime Pointer to the time_system_t to clear.
* @param stime Pointer to the tm_system_t to clear.
*/
void tm_clear_stime(tm_system_t* stime);

/**
* @brief Clear a time_sdelta_t instance.
* @brief Clear a tm_sdelta_t instance.
*
* @param sdelta Pointer to the time_sdelta_t to clear.
*/
void tm_clear_sdelta(tm_sdelta_t* sdelta);

/**
* @brief Clear a time_real_t instance.
* @brief Clear a tm_real_t instance.
*
* @param rtime Pointer to the time_real_t to clear.
*/
void tm_clear_rtime(tm_real_t* rtime);

/**
* @brief Clear a time_delta_t instance.
* @brief Clear a tm_rdelta_t instance.
*
* @param rdelta Pointer to the time_delta_t to clear.
*/
void tm_clear_rdelta(tm_rdelta_t* rdelta);


/**
* @brief Validate a tm_real_t instance.
*
* Returns 0 for valid tm_real_t, non-zero for
* out of bounds.
*
* @param rtime Pointer to the tm_rtime_t to validate.
*/
uint8_t tm_check_invalid_rtime(tm_real_t* rtime);

/**@}*/

/**
Expand Down Expand Up @@ -313,10 +331,10 @@ static inline void tm_current_time(tm_system_t * stime){
static inline int8_t tm_cmp_stime(tm_system_t * t1, tm_system_t * t2);

static inline int8_t tm_cmp_stime(tm_system_t * t1, tm_system_t * t2){
if (t1 < t2){
if (*t1 < *t2){
return (-1);
}
else if (t1 > t2){
else if (*t1 > *t2){
return (1);
}
return 0;
Expand Down
1 change: 0 additions & 1 deletion test/scaffold/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,5 @@ void tearDown(void) {
// expected to be reentrant or reversible, consider using
// setUp and tearDown instead.
void libinit(void){
tm_install_descriptor();
tm_init(0);
}
13 changes: 13 additions & 0 deletions test/test_epoch/test_epoch.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <unity.h>
#include <time/time.h>
#include "../scaffold/common.c"

// TODO
// Test change of epoch, calculation of internal epoch offset,
// epoch change handlers, etc

int main( int argc, char **argv) {
tm_init(0);
UNITY_BEGIN();
UNITY_END();
}
1 change: 1 addition & 0 deletions test/test_meta/test_meta.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "../scaffold/common.c"

void test_descriptor_version(void) {
tm_install_descriptor();
char readbuffer[20];
descriptor_custom_t * desc = descriptor_find(DESCRIPTOR_TAG_LIBVERSION);
TEST_ASSERT_NOT_NULL(desc);
Expand Down
Loading

0 comments on commit a29a883

Please sign in to comment.