diff --git a/docs/src/mnem_maps/cfe_time_cmd_mnem_map b/docs/src/mnem_maps/cfe_time_cmd_mnem_map index fc8f2cfbc..641f5008b 100644 --- a/docs/src/mnem_maps/cfe_time_cmd_mnem_map +++ b/docs/src/mnem_maps/cfe_time_cmd_mnem_map @@ -31,4 +31,5 @@ TIME_ADD1HZSTCF=$sc_$cpu_TIME_Add1HzSTCF \ TIME_SUB1HZSTCF=$sc_$cpu_TIME_Sub1HzSTCF \ TIME_STOPADD1HZ=$sc_$cpu_TIME_StopAdd1Hz \ TIME_STOPSUB1HZ=$sc_$cpu_TIME_StopSub1Hz \ -TIME_SETSIGNAL=$sc_$cpu_TIME_SetSignal +TIME_SETSIGNAL=$sc_$cpu_TIME_SetSignal \ +TIME_SETPRINT=$sc_$cpu_TIME_SetPrint diff --git a/modules/core_api/fsw/inc/cfe_error.h b/modules/core_api/fsw/inc/cfe_error.h index bd7138478..6e8a5e3b0 100644 --- a/modules/core_api/fsw/inc/cfe_error.h +++ b/modules/core_api/fsw/inc/cfe_error.h @@ -1362,6 +1362,15 @@ char *CFE_ES_StatusToString(CFE_Status_t status, CFE_StatusString_t *status_stri * */ #define CFE_TIME_BAD_ARGUMENT ((CFE_Status_t)0xce000005) + +/** + * @brief Time Format Production Too Long + * + * The formatting of a time into a string would overflow the + * output buffer length of CFE_TIME_PRINTED_STRING_SIZE. + * + */ +#define CFE_TIME_FORMAT_TOO_LONG ((CFE_Status_t)0xce000006) /**@}*/ #endif /* CFE_ERROR_H */ diff --git a/modules/core_api/fsw/inc/cfe_time_api_typedefs.h b/modules/core_api/fsw/inc/cfe_time_api_typedefs.h index 548a84db1..0055dfd23 100644 --- a/modules/core_api/fsw/inc/cfe_time_api_typedefs.h +++ b/modules/core_api/fsw/inc/cfe_time_api_typedefs.h @@ -42,7 +42,10 @@ */ #define CFE_TIME_PRINTED_STRING_SIZE \ - 24 /**< \brief Required size of buffer to be passed into #CFE_TIME_Print (includes null terminator) */ + 32 /**< \brief Required size of buffer to be passed into #CFE_TIME_Print (includes null terminator) */ + +#define CFE_TIME_FORMAT_SIZE \ + 32 /**< \brief The maximum length we will accept for the format string (incl. null)--affects cmd and tlm */ /*****************************************************************************/ /* diff --git a/modules/time/config/default_cfe_time_extern_typedefs.h b/modules/time/config/default_cfe_time_extern_typedefs.h index 455c1f8af..88ccbb439 100644 --- a/modules/time/config/default_cfe_time_extern_typedefs.h +++ b/modules/time/config/default_cfe_time_extern_typedefs.h @@ -279,4 +279,29 @@ enum CFE_TIME_SetState */ typedef uint8 CFE_TIME_SetState_Enum_t; +enum CFE_TIME_PrintTimestamp +{ + /** + * @brief Print timestamp using format string. + */ + CFE_TIME_PrintTimestamp_DateTime = 0, + + /** + * @brief Print secs+micros since start/reset. + */ + CFE_TIME_PrintTimestamp_SecsSinceStart = 1, + + /** + * @brief Do not print timestamps at all. + */ + CFE_TIME_PrintTimestamp_None = 2 +}; + +/** + * @brief Time print status values (how to print timestamps) + * + * @sa enum CFE_TIME_PrintTimestamp + */ +typedef uint8 CFE_TIME_PrintTimestamp_Enum_t; + #endif /* CFE_TIME_EXTERN_TYPEDEFS_H */ diff --git a/modules/time/config/default_cfe_time_fcncodes.h b/modules/time/config/default_cfe_time_fcncodes.h index 6fe06e1f8..e7f5463ca 100644 --- a/modules/time/config/default_cfe_time_fcncodes.h +++ b/modules/time/config/default_cfe_time_fcncodes.h @@ -689,6 +689,28 @@ ** \sa #CFE_TIME_SET_STATE_CC, #CFE_TIME_SET_SOURCE_CC */ #define CFE_TIME_SET_SIGNAL_CC 15 /* set clock signal (pri vs red) */ + +/** \cfetimecmd Set Print Format Options +** +** \par Description +** This command sets the time print mode/format (used by EVS when sending +** to stdout, and by ES for syslog messages). +** +** \cfecmdmnemonic \TIME_SETPRINT +** +** \par Command Structure +** #CFE_TIME_SetPrintCmd_t +** +** \par Command Verification +** Successful execution of this command may be verified by examining +** housekeeping output from the TIME module. +** +** \par Criticality +** This command is non-critical, usually used in ground systems and +** doing ground tests. +*/ +#define CFE_TIME_SET_PRINT_CC 16 /* set print format command */ + /** \} */ #endif diff --git a/modules/time/config/default_cfe_time_interface_cfg.h b/modules/time/config/default_cfe_time_interface_cfg.h index 151d38c09..7721430d5 100644 --- a/modules/time/config/default_cfe_time_interface_cfg.h +++ b/modules/time/config/default_cfe_time_interface_cfg.h @@ -198,4 +198,17 @@ */ #define CFE_MISSION_TIME_FS_FACTOR 789004800 +/** + ** \brief On boot, define the time print type. + */ +#define CFE_TIME_PRINT_DEFAULT CFE_TIME_PrintTimestamp_DateTime + +/** + ** \brief On boot, the CFE_TIME_Print() function will use + ** the following strftime-like (+ microseconds) format + ** when "printing" times. (Only relevant if CFE_TIME_PRINT_DEFAULT + ** is set to CFE_TIME_PrintTimestamp_DateTime.) + */ +#define CFE_TIME_PRINTFMT_DEFAULT "%Y-%j %H:%M:%S.%f" + #endif diff --git a/modules/time/config/default_cfe_time_msgstruct.h b/modules/time/config/default_cfe_time_msgstruct.h index a471f315e..c45aa368d 100644 --- a/modules/time/config/default_cfe_time_msgstruct.h +++ b/modules/time/config/default_cfe_time_msgstruct.h @@ -97,6 +97,24 @@ typedef struct CFE_TIME_SetStateCmd CFE_TIME_StateCmd_Payload_t Payload; /**< \brief Command payload */ } CFE_TIME_SetStateCmd_t; +/** + * \brief Payload for the command to set the time print format + */ +typedef struct CFE_TIME_SetPrintCmd_Payload +{ + CFE_TIME_PrintTimestamp_Enum_t PrintTimestamp; + char PrintFormat[CFE_TIME_FORMAT_SIZE]; +} CFE_TIME_SetPrintCmd_Payload_t; + +/** + * \brief Command to set the time print format + */ +typedef struct CFE_TIME_SetPrintCmd +{ + CFE_MSG_CommandHeader_t CommandHeader; /**< \brief Command header */ + CFE_TIME_SetPrintCmd_Payload_t Payload; +} CFE_TIME_SetPrintCmd_t; + /** * \brief Set time data source command payload */ @@ -273,6 +291,9 @@ typedef struct CFE_TIME_HousekeepingTlm_Payload uint32 SubsecsDelay; /**< \cfetlmmnemonic \TIME_1HZDLYSSECS \brief Current 1 Hz SCTF Delay (sub-seconds) */ #endif + + CFE_TIME_PrintTimestamp_Enum_t PrintTimestamp; + char PrintFormat[CFE_TIME_FORMAT_SIZE]; } CFE_TIME_HousekeepingTlm_Payload_t; typedef struct CFE_TIME_HousekeepingTlm diff --git a/modules/time/fsw/inc/cfe_time_eventids.h b/modules/time/fsw/inc/cfe_time_eventids.h index 9ea5eb239..a99f25feb 100644 --- a/modules/time/fsw/inc/cfe_time_eventids.h +++ b/modules/time/fsw/inc/cfe_time_eventids.h @@ -448,6 +448,17 @@ * message pipe. */ #define CFE_TIME_LEN_ERR_EID 49 + +/** + * \brief TIME Invalid Print Format Event ID + * + * \par Type: ERROR + * + * \par Cause: + * + * Invalid print format string or other print option specified. + */ +#define CFE_TIME_PRINTFORMAT_ERR_EID 50 /**\}*/ #endif /* CFE_TIME_EVENTS_H */ diff --git a/modules/time/fsw/src/cfe_time_api.c b/modules/time/fsw/src/cfe_time_api.c index f8e8b35b6..972326468 100644 --- a/modules/time/fsw/src/cfe_time_api.c +++ b/modules/time/fsw/src/cfe_time_api.c @@ -567,27 +567,77 @@ uint32 CFE_TIME_Micro2SubSecs(uint32 MicroSeconds) *-----------------------------------------------------------------*/ CFE_Status_t 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; + uint32 mic = (CFE_TIME_Sub2MicroSecs(TimeToPrint.Subseconds) + CFE_MISSION_TIME_EPOCH_MICROS) / 10; + time_t sec = TimeToPrint.Seconds + CFE_MISSION_TIME_EPOCH_SECONDS; // epoch is Jan 1, 1980 + size_t OutChrs = 0; // tracks how many chars we've put into PrintBuffer struct tm tm; + size_t TimeSz; if (PrintBuffer == NULL) { return CFE_TIME_BAD_ARGUMENT; } - 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'; + switch (CFE_TIME_Global.PrintTimestamp) + { + case CFE_TIME_PrintTimestamp_DateTime: + gmtime_r(&sec, &tm); + + /* + ** `PrintFormatMillis` points at the `%f` in PrintFormat, if there is a `%f`. + */ + if (CFE_TIME_Global.PrintFormatMillis) + { + /* ...blot out the `%f`, temporarily. */ + CFE_TIME_Global.PrintFormatMillis[0] = '\0'; + } + + TimeSz = strftime(PrintBuffer, CFE_TIME_PRINTED_STRING_SIZE, CFE_TIME_Global.PrintFormat, &tm); + + if (TimeSz == 0) + { + return CFE_TIME_FORMAT_TOO_LONG; + } + + OutChrs += TimeSz; + + if (CFE_TIME_Global.PrintFormatMillis) + { + /* unblot */ + CFE_TIME_Global.PrintFormatMillis[0] = '%'; + + if (OutChrs + 6 > CFE_TIME_PRINTED_STRING_SIZE) + { + return CFE_TIME_FORMAT_TOO_LONG; + } + + OutChrs += snprintf(PrintBuffer + OutChrs, CFE_TIME_PRINTED_STRING_SIZE - OutChrs, "%05d", mic); + + /* it's likely the `%f` is last in the format string, check if there's any remainder...*/ + if (CFE_TIME_Global.PrintFormatMillis[2]) + { + TimeSz = strftime(PrintBuffer + OutChrs, CFE_TIME_PRINTED_STRING_SIZE, CFE_TIME_Global.PrintFormatMillis + 2, &tm); + + if (TimeSz == 0) + { + return CFE_TIME_FORMAT_TOO_LONG; + } + + OutChrs += TimeSz; + } + } + PrintBuffer[OutChrs] = '\0'; + break; + + case CFE_TIME_PrintTimestamp_SecsSinceStart: + OutChrs += snprintf(PrintBuffer, CFE_TIME_PRINTED_STRING_SIZE, "%ld.%06d", (long int)sec, mic); + PrintBuffer[OutChrs] = '\0'; + break; + + default: + PrintBuffer[0] = '\0'; + break; + } return CFE_SUCCESS; } diff --git a/modules/time/fsw/src/cfe_time_dispatch.c b/modules/time/fsw/src/cfe_time_dispatch.c index fcd6e08fd..4c261cc46 100644 --- a/modules/time/fsw/src/cfe_time_dispatch.c +++ b/modules/time/fsw/src/cfe_time_dispatch.c @@ -240,6 +240,13 @@ void CFE_TIME_TaskPipe(const CFE_SB_Buffer_t *SBBufPtr) } break; + case CFE_TIME_SET_PRINT_CC: + if (CFE_TIME_VerifyCmdLength(&SBBufPtr->Msg, sizeof(CFE_TIME_SetPrintCmd_t))) + { + CFE_TIME_SetPrintCmd((const CFE_TIME_SetPrintCmd_t *)SBBufPtr); + } + break; + default: CFE_TIME_Global.CommandErrorCounter++; diff --git a/modules/time/fsw/src/cfe_time_task.c b/modules/time/fsw/src/cfe_time_task.c index f392e6627..f51a81648 100644 --- a/modules/time/fsw/src/cfe_time_task.c +++ b/modules/time/fsw/src/cfe_time_task.c @@ -1090,3 +1090,14 @@ int32 CFE_TIME_Sub1HZAdjustmentCmd(const CFE_TIME_Sub1HZAdjustmentCmd_t *data) CFE_TIME_1HzAdjImpl(&data->Payload, CFE_TIME_AdjustDirection_SUBTRACT); return CFE_SUCCESS; } + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +int32 CFE_TIME_SetPrintCmd(const CFE_TIME_SetPrintCmd_t *data) +{ + return CFE_TIME_SetPrintFormat(data->Payload.PrintTimestamp, data->Payload.PrintFormat); +} diff --git a/modules/time/fsw/src/cfe_time_utils.c b/modules/time/fsw/src/cfe_time_utils.c index d0cdb3bc5..06d623261 100644 --- a/modules/time/fsw/src/cfe_time_utils.c +++ b/modules/time/fsw/src/cfe_time_utils.c @@ -353,6 +353,11 @@ void CFE_TIME_InitData(void) */ CFE_MSG_Init(CFE_MSG_PTR(CFE_TIME_Global.Local1HzCmd.CommandHeader), CFE_SB_ValueToMsgId(CFE_TIME_1HZ_CMD_MID), sizeof(CFE_TIME_Global.Local1HzCmd)); + + /* + ** Configure the default time print format. + */ + CFE_TIME_SetPrintFormat(CFE_TIME_PRINT_DEFAULT, CFE_TIME_PRINTFMT_DEFAULT); } /*---------------------------------------------------------------- @@ -408,6 +413,9 @@ void CFE_TIME_GetHkData(const CFE_TIME_Reference_t *Reference) CFE_TIME_Global.HkPacket.Payload.SecondsDelay = Reference->AtToneDelay.Seconds; CFE_TIME_Global.HkPacket.Payload.SubsecsDelay = Reference->AtToneDelay.Subseconds; #endif + + strncpy(CFE_TIME_Global.HkPacket.Payload.PrintFormat, CFE_TIME_Global.PrintFormat, CFE_TIME_FORMAT_SIZE); + CFE_TIME_Global.HkPacket.Payload.PrintTimestamp = CFE_TIME_Global.PrintTimestamp; } /*---------------------------------------------------------------- @@ -1035,3 +1043,55 @@ int32 CFE_TIME_CleanUpApp(CFE_ES_AppId_t AppId) return Status; } + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +int32 CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_Enum_t PrintTimestamp, const char *PrintFormat) +{ + if (PrintTimestamp < 0 || PrintTimestamp > CFE_TIME_PrintTimestamp_None) + { + return CFE_TIME_BAD_ARGUMENT; + } + + CFE_TIME_Global.PrintTimestamp = PrintTimestamp; + + if (PrintTimestamp == CFE_TIME_PrintTimestamp_DateTime) + { + char *PctF; + + /* null pointer or empty string */ + if (PrintFormat == NULL || PrintFormat[0] == '\0') + { + return CFE_TIME_BAD_ARGUMENT; + } + + CFE_TIME_Global.PrintFormatMillis = NULL; + + strncpy(CFE_TIME_Global.PrintFormat, PrintFormat, CFE_TIME_FORMAT_SIZE); + + /* find the (first) "%f", and mark it so that when we call CFE_TIME_Print() it can quickly process it. */ + PctF = CFE_TIME_Global.PrintFormat; + while (PctF[0] != '\0') { + if (PctF[0] == '%') + { + switch (PctF[1]) + { + case 'f': + CFE_TIME_Global.PrintFormatMillis = PctF; + break; + case '\0': + break; + default: + PctF++; /* skip forward two chars */ + } + } + PctF++; + } + } + + return CFE_SUCCESS; +} diff --git a/modules/time/fsw/src/cfe_time_utils.h b/modules/time/fsw/src/cfe_time_utils.h index 8c9502bac..08e35fd9f 100644 --- a/modules/time/fsw/src/cfe_time_utils.h +++ b/modules/time/fsw/src/cfe_time_utils.h @@ -312,6 +312,24 @@ typedef struct ** One callback per app is allowed */ CFE_TIME_SynchCallbackRegEntry_t SynchCallback[CFE_PLATFORM_ES_MAX_APPLICATIONS]; + + /* + ** What form should CFE_TIME_Print produce. + */ + CFE_TIME_PrintTimestamp_Enum_t PrintTimestamp; + + /* + ** For formatted CFE_TIME_Print output, use this format string. + */ + char PrintFormat[CFE_TIME_FORMAT_SIZE]; + + /* + ** For strftime-style formats, the `%f` conversion spec may be specified. + ** When the PrintFormat is specified/updated, this pointer will + ** point to the location of the `%f` in the PrintFormat string, or will + ** be NULL if `%f` is not being used. + */ + char *PrintFormatMillis; } CFE_TIME_Global_t; /* @@ -867,4 +885,16 @@ int32 CFE_TIME_Sub1HZAdjustmentCmd(const CFE_TIME_Sub1HZAdjustmentCmd_t *data); */ int32 CFE_TIME_SubAdjustCmd(const CFE_TIME_SubAdjustCmd_t *data); +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Time task ground command (print format adjust) + */ +int32 CFE_TIME_SetPrintCmd(const CFE_TIME_SetPrintCmd_t *data); + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Utility function to set the print format option. + */ +int32 CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_Enum_t PrintTimestamp, const char *PrintFormat); + #endif /* CFE_TIME_UTILS_H */ diff --git a/modules/time/ut-coverage/time_UT.c b/modules/time/ut-coverage/time_UT.c index 20161b427..5da088e5e 100644 --- a/modules/time/ut-coverage/time_UT.c +++ b/modules/time/ut-coverage/time_UT.c @@ -98,6 +98,8 @@ static const UT_TaskPipeDispatchId_t UT_TPID_CFE_TIME_CMD_SUB_1HZ_ADJUSTMENT_CC static const UT_TaskPipeDispatchId_t UT_TPID_CFE_TIME_INVALID_MID = {.MsgId = CFE_SB_MSGID_RESERVED, .CommandCode = 0}; static const UT_TaskPipeDispatchId_t UT_TPID_CFE_TIME_CMD_INVALID_CC = { .MsgId = CFE_SB_MSGID_WRAP_VALUE(CFE_TIME_CMD_MID), .CommandCode = 0x7F}; +static const UT_TaskPipeDispatchId_t UT_TPID_CFE_TIME_SET_PRINT_CC = { + .MsgId = CFE_SB_MSGID_WRAP_VALUE(CFE_TIME_CMD_MID), .CommandCode = CFE_TIME_SET_PRINT_CC}; /* ** Global variables @@ -906,6 +908,76 @@ void Test_Print(void) UtAssert_MIR("Confirm adding seconds = %u, subseconds = %u to configured EPOCH results in time %s", (unsigned int)time.Seconds, (unsigned int)time.Subseconds, timeBuf); } + + /* Test with different format */ + CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_DateTime, "%Y-%m-%d %H:%M"); + + CFE_UtAssert_SUCCESS(CFE_TIME_Print(timeBuf, time)); + if (usingDefaultEpoch) + { + strcpy(expectedBuf, "2013-01-01 02:03"); + UtAssert_STRINGBUF_EQ(timeBuf, sizeof(timeBuf), expectedBuf, sizeof(expectedBuf)); + } + else + { + UtAssert_MIR("Confirm adding seconds = %u, subseconds = %u to configured EPOCH results in time %s", + (unsigned int)time.Seconds, (unsigned int)time.Subseconds, timeBuf); + } + + /* Test with three milliseconds spec, we only handle one and strftime ignores it */ + CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_DateTime, "%%f.%f.%f.%f"); + + CFE_UtAssert_SUCCESS(CFE_TIME_Print(timeBuf, time)); + if (usingDefaultEpoch) + { + strcpy(expectedBuf, "%f.49999.%f.%f"); + UtAssert_STRINGBUF_EQ(timeBuf, sizeof(timeBuf), expectedBuf, sizeof(expectedBuf)); + } + else + { + UtAssert_MIR("Confirm adding seconds = %u, subseconds = %u to configured EPOCH results in time %s", + (unsigned int)time.Seconds, (unsigned int)time.Subseconds, timeBuf); + } + + CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_SecsSinceStart, NULL); + + CFE_UtAssert_SUCCESS(CFE_TIME_Print(timeBuf, time)); + if (usingDefaultEpoch) + { + strcpy(expectedBuf, "49999.49999"); + UtAssert_STRINGBUF_EQ(timeBuf, sizeof(timeBuf), expectedBuf, sizeof(expectedBuf)); + } + else + { + UtAssert_MIR("Confirm adding seconds = %u, subseconds = %u to configured EPOCH results in time %s", + (unsigned int)time.Seconds, (unsigned int)time.Subseconds, timeBuf); + } + + /* Test with too-long of a format */ + CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_DateTime, "%Y%Y%Y%Y%Y%Y%Y%Y%Y%Y%Y"); + + UtAssert_INT32_EQ(CFE_TIME_Print(timeBuf, time), CFE_TIME_FORMAT_TOO_LONG); + + /* Test with too-long of a %f format */ + CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_DateTime, "012345678901234567890123456%f"); + + UtAssert_INT32_EQ(CFE_TIME_Print(timeBuf, time), CFE_TIME_FORMAT_TOO_LONG); + + /* Test with "none" option */ + CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_None, NULL); + CFE_TIME_Global.PrintTimestamp = CFE_TIME_PrintTimestamp_None; + CFE_UtAssert_SUCCESS(CFE_TIME_Print(timeBuf, time)); + UtAssert_STRINGBUF_EQ(timeBuf, sizeof(timeBuf), "", 1); + + /* Test with DateTime option and empty format */ + UtAssert_INT32_NEQ(CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_DateTime, ""), CFE_SUCCESS); + + /* test some invalid PrintTimestamp options */ + UtAssert_INT32_NEQ(CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_None + 1, ""), CFE_SUCCESS); + UtAssert_INT32_NEQ(CFE_TIME_SetPrintFormat(-1, ""), CFE_SUCCESS); + + /* reset to nominal */ + CFE_UtAssert_SUCCESS(CFE_TIME_SetPrintFormat(CFE_TIME_PrintTimestamp_DateTime, "%Y-%j %H:%M:%S.%f")); } /* @@ -1331,6 +1403,7 @@ void Test_PipeCmds(void) CFE_TIME_SubAdjustCmd_t subadjcmd; CFE_TIME_Add1HZAdjustmentCmd_t add1hzadjcmd; CFE_TIME_Sub1HZAdjustmentCmd_t sub1hzadjcmd; + CFE_TIME_SetPrintCmd_t setprcmd; } CmdBuf; UT_SoftwareBusSnapshot_Entry_t LocalSnapshotData = {.MsgId = CFE_SB_MSGID_WRAP_VALUE(CFE_TIME_HK_TLM_MID)}; @@ -1928,6 +2001,26 @@ void Test_PipeCmds(void) UT_InitData(); UT_CallTaskPipe(CFE_TIME_TaskPipe, &CmdBuf.message, sizeof(CmdBuf.onehzcmd), UT_TPID_CFE_TIME_1HZ_CMD); UtAssert_NONZERO(UT_GetStubCount(UT_KEY(CFE_PSP_GetTime))); + + /* Test sending a print timestamp command */ + UT_InitData(); + memset(&CmdBuf, 0, sizeof(CmdBuf)); + CFE_TIME_Global.PrintTimestamp = -1; + strcpy(CFE_TIME_Global.PrintFormat, ""); + CmdBuf.setprcmd.Payload.PrintTimestamp = CFE_TIME_PrintTimestamp_SecsSinceStart; + UT_CallTaskPipe(CFE_TIME_TaskPipe, &CmdBuf.message, sizeof(CmdBuf.setprcmd), UT_TPID_CFE_TIME_SET_PRINT_CC); + UtAssert_UINT32_EQ(CFE_TIME_Global.PrintTimestamp, CFE_TIME_PrintTimestamp_SecsSinceStart); + + /* Test sending another print timestamp command */ + UT_InitData(); + memset(&CmdBuf, 0, sizeof(CmdBuf)); + CFE_TIME_Global.PrintTimestamp = -1; + strcpy(CFE_TIME_Global.PrintFormat, ""); + CmdBuf.setprcmd.Payload.PrintTimestamp = CFE_TIME_PrintTimestamp_DateTime; + strcpy(CmdBuf.setprcmd.Payload.PrintFormat, "%Y-%j %H:%M:%S.%f"); + UT_CallTaskPipe(CFE_TIME_TaskPipe, &CmdBuf.message, sizeof(CmdBuf.setprcmd), UT_TPID_CFE_TIME_SET_PRINT_CC); + UtAssert_UINT32_EQ(CFE_TIME_Global.PrintTimestamp, CFE_TIME_PrintTimestamp_DateTime); + UtAssert_StrCmp(CFE_TIME_Global.PrintFormat, CmdBuf.setprcmd.Payload.PrintFormat, "Print Format '%s'", CFE_TIME_Global.PrintFormat); } /*