diff --git a/modules/core_api/fsw/inc/cfe_time.h b/modules/core_api/fsw/inc/cfe_time.h index d4dfbc943..ac2cf98ce 100644 --- a/modules/core_api/fsw/inc/cfe_time.h +++ b/modules/core_api/fsw/inc/cfe_time.h @@ -691,8 +691,6 @@ CFE_Status_t CFE_TIME_UnregisterSynchCallback(CFE_TIME_SynchCallbackPtr_t Callba ** - \c \\0 = trailing null ** ** \par Assumptions, External Events, and Notes: -** - This function calls strftime to format the output. Systems without this -** C99-standard function will have to write their own implementation. ** - The value of the time argument is simply added to the configuration ** definitions for the ground epoch and converted into a fixed length ** string in the buffer provided by the caller. @@ -708,12 +706,8 @@ CFE_Status_t CFE_TIME_UnregisterSynchCallback(CFE_TIME_SynchCallbackPtr_t Callba ** ** \param[in] TimeToPrint The time to print into the character array. ** -** \return Execution status, see \ref CFEReturnCodes -** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS -** \retval #CFE_TIME_BAD_ARGUMENT \copybrief CFE_TIME_BAD_ARGUMENT -** ******************************************************************************/ -CFE_Status_t CFE_TIME_Print(char *PrintBuffer, CFE_TIME_SysTime_t TimeToPrint); +void CFE_TIME_Print(char *PrintBuffer, CFE_TIME_SysTime_t TimeToPrint); /*****************************************************************************/ /** diff --git a/modules/core_api/ut-stubs/src/cfe_time_handlers.c b/modules/core_api/ut-stubs/src/cfe_time_handlers.c index c277bb721..ec9f8b5e9 100644 --- a/modules/core_api/ut-stubs/src/cfe_time_handlers.c +++ b/modules/core_api/ut-stubs/src/cfe_time_handlers.c @@ -45,14 +45,13 @@ * Default handler for CFE_TIME_Print coverage stub function * *------------------------------------------------------------*/ -CFE_Status_t UT_DefaultHandler_CFE_TIME_Print(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +void UT_DefaultHandler_CFE_TIME_Print(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) { char * PrintBuffer = UT_Hook_GetArgValueByName(Context, "PrintBuffer", char *); CFE_TIME_SysTime_t TimeToPrint = UT_Hook_GetArgValueByName(Context, "TimeToPrint", CFE_TIME_SysTime_t); snprintf(PrintBuffer, CFE_TIME_PRINTED_STRING_SIZE, "UT %u.%u -", (unsigned int)TimeToPrint.Seconds, (unsigned int)TimeToPrint.Subseconds); - return CFE_SUCCESS; } /*------------------------------------------------------------ diff --git a/modules/core_api/ut-stubs/src/cfe_time_stubs.c b/modules/core_api/ut-stubs/src/cfe_time_stubs.c index ca99702db..999f06008 100644 --- a/modules/core_api/ut-stubs/src/cfe_time_stubs.c +++ b/modules/core_api/ut-stubs/src/cfe_time_stubs.c @@ -305,16 +305,12 @@ uint32 CFE_TIME_Micro2SubSecs(uint32 MicroSeconds) * Generated stub function for CFE_TIME_Print() * ---------------------------------------------------- */ -CFE_Status_t CFE_TIME_Print(char *PrintBuffer, CFE_TIME_SysTime_t TimeToPrint) +void CFE_TIME_Print(char *PrintBuffer, CFE_TIME_SysTime_t TimeToPrint) { - UT_GenStub_SetupReturnBuffer(CFE_TIME_Print, CFE_Status_t); - UT_GenStub_AddParam(CFE_TIME_Print, char *, PrintBuffer); UT_GenStub_AddParam(CFE_TIME_Print, CFE_TIME_SysTime_t, TimeToPrint); UT_GenStub_Execute(CFE_TIME_Print, Basic, UT_DefaultHandler_CFE_TIME_Print); - - return UT_GenStub_GetReturnValue(CFE_TIME_Print, CFE_Status_t); } /* diff --git a/modules/time/config/default_cfe_time_interface_cfg.h b/modules/time/config/default_cfe_time_interface_cfg.h index 151d38c09..3e614f154 100644 --- a/modules/time/config/default_cfe_time_interface_cfg.h +++ b/modules/time/config/default_cfe_time_interface_cfg.h @@ -151,14 +151,23 @@ ** \cfetimecfg Default EPOCH Values ** ** \par Description: -** Default ground time epoch values (from Jan. 1, 1970 00:00:00) +** Default ground time epoch values ** Note: these values are used only by the CFE_TIME_Print() API function ** ** \par Limits +** Year - must be within 136 years +** Day - Jan 1 = 1, Feb 1 = 32, etc. +** Hour - 0 to 23 +** Minute - 0 to 59 +** Second - 0 to 59 ** Micros - 0 to 999999 */ -#define CFE_MISSION_TIME_EPOCH_SECONDS 315532800 /* Jan. 1, 1980 00:00:00 */ -#define CFE_MISSION_TIME_EPOCH_MICROS 0 +#define CFE_MISSION_TIME_EPOCH_YEAR 1980 +#define CFE_MISSION_TIME_EPOCH_DAY 1 +#define CFE_MISSION_TIME_EPOCH_HOUR 0 +#define CFE_MISSION_TIME_EPOCH_MINUTE 0 +#define CFE_MISSION_TIME_EPOCH_SECOND 0 +#define CFE_MISSION_TIME_EPOCH_MICROS 0 /** ** \cfetimecfg Time File System Factor diff --git a/modules/time/fsw/src/cfe_time_api.c b/modules/time/fsw/src/cfe_time_api.c index f8e8b35b6..1cd7e99d7 100644 --- a/modules/time/fsw/src/cfe_time_api.c +++ b/modules/time/fsw/src/cfe_time_api.c @@ -34,8 +34,6 @@ #include -#include - /*---------------------------------------------------------------- * * Implemented per public API @@ -565,30 +563,150 @@ uint32 CFE_TIME_Micro2SubSecs(uint32 MicroSeconds) * See description in header file for argument/return detail * *-----------------------------------------------------------------*/ -CFE_Status_t CFE_TIME_Print(char *PrintBuffer, CFE_TIME_SysTime_t TimeToPrint) +void CFE_TIME_Print(char *PrintBuffer, CFE_TIME_SysTime_t TimeToPrint) { - size_t FmtLen = 0; - uint32 Micros = (CFE_TIME_Sub2MicroSecs(TimeToPrint.Subseconds) + CFE_MISSION_TIME_EPOCH_MICROS) / 10; - struct tm tm; + uint32 NumberOfYears; + uint32 NumberOfDays; + uint32 NumberOfHours; + uint32 NumberOfMinutes; + uint32 NumberOfSeconds; + uint32 NumberOfMicros; + uint32 DaysInThisYear; + + bool StillCountingYears = true; if (PrintBuffer == NULL) { - return CFE_TIME_BAD_ARGUMENT; + CFE_ES_WriteToSysLog("%s: Failed invalid arguments\n", __func__); + return; + } + + /* + ** Convert the cFE time (offset from epoch) into calendar time... + */ + NumberOfMicros = CFE_TIME_Sub2MicroSecs(TimeToPrint.Subseconds) + CFE_MISSION_TIME_EPOCH_MICROS; + + NumberOfMinutes = (NumberOfMicros / 60000000) + (TimeToPrint.Seconds / 60) + CFE_MISSION_TIME_EPOCH_MINUTE; + NumberOfMicros = NumberOfMicros % 60000000; + + NumberOfSeconds = (NumberOfMicros / 1000000) + (TimeToPrint.Seconds % 60) + CFE_MISSION_TIME_EPOCH_SECOND; + NumberOfMicros = NumberOfMicros % 1000000; + /* + ** Adding the epoch "seconds" after computing the minutes avoids + ** overflow problems when the input time value (seconds) is + ** at, or near, 0xFFFFFFFF... + */ + while (NumberOfSeconds >= 60) + { + NumberOfMinutes++; + NumberOfSeconds -= 60; + } + + /* + ** Compute the years/days/hours/minutes... + */ + NumberOfHours = (NumberOfMinutes / 60) + CFE_MISSION_TIME_EPOCH_HOUR; + NumberOfMinutes = (NumberOfMinutes % 60); + + /* + ** Unlike hours and minutes, epoch days are counted as Jan 1 = day 1... + */ + NumberOfDays = (NumberOfHours / 24) + (CFE_MISSION_TIME_EPOCH_DAY - 1); + NumberOfHours = (NumberOfHours % 24); + + NumberOfYears = CFE_MISSION_TIME_EPOCH_YEAR; + + /* + ** Convert total number of days into years and remainder days... + */ + while (StillCountingYears) + { + /* + ** Set number of days in this year (leap year?)... + */ + DaysInThisYear = 365; + + if ((NumberOfYears % 4) == 0) + { + if ((NumberOfYears % 100) != 0) + { + DaysInThisYear = 366; + } + else if ((NumberOfYears % 400) == 0) + { + DaysInThisYear = 366; + } + else + { + /* Do Nothing. Non-leap year. */ + } + } + + /* + ** When we have less than a years worth of days, we're done... + */ + if (NumberOfDays < DaysInThisYear) + { + StillCountingYears = false; + } + else + { + /* + ** Add a year and remove the number of days in that year... + */ + NumberOfYears++; + NumberOfDays -= DaysInThisYear; + } } - time_t sec = TimeToPrint.Seconds + CFE_MISSION_TIME_EPOCH_SECONDS; // epoch is Jan 1, 1980 - gmtime_r(&sec, &tm); - FmtLen = strftime(PrintBuffer, CFE_TIME_PRINTED_STRING_SIZE - 6, "%Y-%j-%H:%M:%S", &tm); - PrintBuffer += FmtLen; - *(PrintBuffer++) = '.'; - - *(PrintBuffer++) = '0' + (char)((Micros % 100000) / 10000); - *(PrintBuffer++) = '0' + (char)((Micros % 10000) / 1000); - *(PrintBuffer++) = '0' + (char)((Micros % 1000) / 100); - *(PrintBuffer++) = '0' + (char)((Micros % 100) / 10); - *(PrintBuffer++) = '0' + (char)(Micros % 10); - *PrintBuffer = '\0'; - return CFE_SUCCESS; + /* + ** Unlike hours and minutes, days are displayed as Jan 1 = day 1... + */ + NumberOfDays++; + + /* + ** After computing microseconds, convert to 5 digits from 6 digits... + */ + NumberOfMicros = NumberOfMicros / 10; + + /* + ** Build formatted output string (yyyy-ddd-hh:mm:ss.xxxxx)... + */ + *PrintBuffer++ = '0' + (char)(NumberOfYears / 1000); + NumberOfYears = NumberOfYears % 1000; + *PrintBuffer++ = '0' + (char)(NumberOfYears / 100); + NumberOfYears = NumberOfYears % 100; + *PrintBuffer++ = '0' + (char)(NumberOfYears / 10); + *PrintBuffer++ = '0' + (char)(NumberOfYears % 10); + *PrintBuffer++ = '-'; + + *PrintBuffer++ = '0' + (char)(NumberOfDays / 100); + NumberOfDays = NumberOfDays % 100; + *PrintBuffer++ = '0' + (char)(NumberOfDays / 10); + *PrintBuffer++ = '0' + (char)(NumberOfDays % 10); + *PrintBuffer++ = '-'; + + *PrintBuffer++ = '0' + (char)(NumberOfHours / 10); + *PrintBuffer++ = '0' + (char)(NumberOfHours % 10); + *PrintBuffer++ = ':'; + + *PrintBuffer++ = '0' + (char)(NumberOfMinutes / 10); + *PrintBuffer++ = '0' + (char)(NumberOfMinutes % 10); + *PrintBuffer++ = ':'; + + *PrintBuffer++ = '0' + (char)(NumberOfSeconds / 10); + *PrintBuffer++ = '0' + (char)(NumberOfSeconds % 10); + *PrintBuffer++ = '.'; + + *PrintBuffer++ = '0' + (char)(NumberOfMicros / 10000); + NumberOfMicros = NumberOfMicros % 10000; + *PrintBuffer++ = '0' + (char)(NumberOfMicros / 1000); + NumberOfMicros = NumberOfMicros % 1000; + *PrintBuffer++ = '0' + (char)(NumberOfMicros / 100); + NumberOfMicros = NumberOfMicros % 100; + *PrintBuffer++ = '0' + (char)(NumberOfMicros / 10); + *PrintBuffer++ = '0' + (char)(NumberOfMicros % 10); + *PrintBuffer++ = '\0'; } /*---------------------------------------------------------------- diff --git a/modules/time/ut-coverage/time_UT.c b/modules/time/ut-coverage/time_UT.c index 20161b427..3a4961ac1 100644 --- a/modules/time/ut-coverage/time_UT.c +++ b/modules/time/ut-coverage/time_UT.c @@ -821,7 +821,7 @@ void Test_ConvertTime(void) ** ** NOTE: Test results depend on the epoch values in cfe_mission_cfg.h (the ** tests below assume an epoch of 1980-001-00:00:00.00000). Full -** coverage is possible only when CFE_MISSION_TIME_EPOCH_SECONDS > 0 +** coverage is possible only when CFE_MISSION_TIME_EPOCH_SECOND > 0 */ void Test_Print(void) { @@ -834,7 +834,8 @@ void Test_Print(void) UtPrintf("Begin Test Print"); - if (CFE_MISSION_TIME_EPOCH_SECONDS != 0 || CFE_MISSION_TIME_EPOCH_MICROS != 0) + if (CFE_MISSION_TIME_EPOCH_YEAR != 1980 || CFE_MISSION_TIME_EPOCH_DAY != 1 || CFE_MISSION_TIME_EPOCH_HOUR != 0 || + CFE_MISSION_TIME_EPOCH_MINUTE != 0 || CFE_MISSION_TIME_EPOCH_SECOND != 0 || CFE_MISSION_TIME_EPOCH_MICROS != 0) { UtPrintf("Custom epoch time requires manual inspection for CFE_TIME_Print"); usingDefaultEpoch = false; @@ -842,10 +843,11 @@ void Test_Print(void) /* Test print with null print buffer argument */ UT_InitData(); - UtAssert_INT32_EQ(CFE_TIME_Print(NULL, time), CFE_TIME_BAD_ARGUMENT); + UtAssert_VOIDCALL(CFE_TIME_Print(NULL, time)); + CFE_UtAssert_SYSLOG(TIME_SYSLOG_MSGS[6]); /* Test with zero time value */ - CFE_UtAssert_SUCCESS(CFE_TIME_Print(timeBuf, time)); + CFE_TIME_Print(timeBuf, time); if (usingDefaultEpoch) { strcpy(expectedBuf, "1980-001-00:00:00.00000"); @@ -858,12 +860,12 @@ void Test_Print(void) } /* Test with a time value that causes seconds >= 60 when - * CFE_MISSION_TIME_EPOCH_SECONDS > 0 + * CFE_MISSION_TIME_EPOCH_SECOND > 0 */ time.Subseconds = 0; time.Seconds = 59; - CFE_UtAssert_SUCCESS(CFE_TIME_Print(timeBuf, time)); + CFE_TIME_Print(timeBuf, time); if (usingDefaultEpoch) { strcpy(expectedBuf, "1980-001-00:00:59.00000"); @@ -879,7 +881,7 @@ void Test_Print(void) time.Subseconds = 215000; time.Seconds = 1041472984; - CFE_UtAssert_SUCCESS(CFE_TIME_Print(timeBuf, time)); + CFE_TIME_Print(timeBuf, time); if (usingDefaultEpoch) { strcpy(expectedBuf, "2013-001-02:03:04.00005"); @@ -891,14 +893,14 @@ void Test_Print(void) (unsigned int)time.Seconds, (unsigned int)time.Subseconds, timeBuf); } - /* Test with sufficiently-large seconds and subseconds values */ - time.Subseconds = 0x7fffffff; - time.Seconds = 0x7fffffff; + /* Test with maximum seconds and subseconds values */ + time.Subseconds = 0xffffffff; + time.Seconds = 0xffffffff; - CFE_UtAssert_SUCCESS(CFE_TIME_Print(timeBuf, time)); + CFE_TIME_Print(timeBuf, time); if (usingDefaultEpoch) { - strcpy(expectedBuf, "2048-019-03:14:07.49999"); + strcpy(expectedBuf, "2116-038-06:28:15.99999"); UtAssert_STRINGBUF_EQ(timeBuf, sizeof(timeBuf), expectedBuf, sizeof(expectedBuf)); } else