Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #2358, adds TIME module command to set CFE_TIME_Print() format #2370

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/src/mnem_maps/cfe_time_cmd_mnem_map
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions modules/core_api/fsw/inc/cfe_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
5 changes: 4 additions & 1 deletion modules/core_api/fsw/inc/cfe_time_api_typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

/*****************************************************************************/
/*
Expand Down
25 changes: 25 additions & 0 deletions modules/time/config/default_cfe_time_extern_typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,29 @@ enum CFE_TIME_SetState
*/
typedef uint8 CFE_TIME_SetState_Enum_t;

enum CFE_TIME_PrintState
{
/**
* @brief Print timestamp using format string.
*/
CFE_TIME_PrintState_DateTime = 0,

/**
* @brief Print secs+micros since start/reset.
*/
CFE_TIME_PrintState_SecsSinceStart = 1,

/**
* @brief Do not print timestamps at all.
*/
CFE_TIME_PrintState_None = 2
};

/**
* @brief Time print status values (how to print timestamps)
*
* @sa enum CFE_TIME_PrintState
*/
typedef uint8 CFE_TIME_PrintState_Enum_t;

#endif /* CFE_TIME_EXTERN_TYPEDEFS_H */
22 changes: 22 additions & 0 deletions modules/time/config/default_cfe_time_fcncodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
13 changes: 13 additions & 0 deletions modules/time/config/default_cfe_time_interface_cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_PrintState_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_PrintState_DateTime.)
*/
#define CFE_TIME_PRINTFMT_DEFAULT "%Y-%j %H:%M:%S.%f"

#endif
21 changes: 21 additions & 0 deletions modules/time/config/default_cfe_time_msgstruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_PrintState_Enum_t PrintState;
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
*/
Expand Down Expand Up @@ -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_PrintState_Enum_t PrintState;
char PrintFormat[CFE_TIME_FORMAT_SIZE];
} CFE_TIME_HousekeepingTlm_Payload_t;

typedef struct CFE_TIME_HousekeepingTlm
Expand Down
79 changes: 65 additions & 14 deletions modules/time/fsw/src/cfe_time_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -567,27 +567,78 @@ 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
/* temporary buffer to store the format so we can modify it to blot '%f' */
char FmtBuf[CFE_TIME_FORMAT_SIZE];
char *FmtPtr = FmtBuf;
char *PctF;
size_t OutChrs = 0;
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.PrintState)
{
case CFE_TIME_PrintState_DateTime:
gmtime_r(&sec, &tm);

strncpy(FmtPtr, CFE_TIME_Global.PrintFormat, CFE_TIME_FORMAT_SIZE);

while(*FmtPtr != '\0' && OutChrs < CFE_TIME_PRINTED_STRING_SIZE)
{
/* if we have "%f", call strftime for string before and string after */
PctF = strstr(FmtBuf, "%f");
if (PctF)
{
*PctF = '\0'; /* blot out "%f", for now */
}

TimeSz = strftime(PrintBuffer + OutChrs, CFE_TIME_PRINTED_STRING_SIZE - OutChrs, FmtPtr, &tm);

if (*FmtPtr && TimeSz == 0)
{
/* strftime returns 0 if the buffer is too small */
return CFE_TIME_FORMAT_TOO_LONG;
}

OutChrs += TimeSz;

/* we found/blotted %f above */
if (PctF)
{
/* write %f value */
if (OutChrs < CFE_TIME_PRINTED_STRING_SIZE - 5)
{
OutChrs += snprintf(PrintBuffer + OutChrs, CFE_TIME_PRINTED_STRING_SIZE - OutChrs, "%05d", mic);
}
else
{
return CFE_TIME_FORMAT_TOO_LONG;
}

/* go back through the loop with the remaining format */
FmtPtr = PctF + 2;
}
else
{
PrintBuffer[OutChrs] = '\0'; /* just in case, null-terminate the string */
break; /* break while */
}
}
Comment on lines +592 to +632

Check warning

Code scanning / CodeQL

Unbounded loop

The loop counter OutChrs is not always incremented in the loop body.
break;
case CFE_TIME_PrintState_SecsSinceStart:
OutChrs += snprintf(PrintBuffer, CFE_TIME_PRINTED_STRING_SIZE, "%ld.%06d", (long int)sec, mic);
PrintBuffer[OutChrs] = '\0';
break;
default:
PrintBuffer[0] = '\0';
break;
}
Comment on lines +585 to +641

Check notice

Code scanning / CodeQL

Long switch case

Switch has at least one case that is too long: [CFE_TIME_PrintState_DateTime (46 lines)](1).
return CFE_SUCCESS;
}

Expand Down
7 changes: 7 additions & 0 deletions modules/time/fsw/src/cfe_time_dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)))

Check warning

Code scanning / CodeQL

Side effect in a Boolean expression

This Boolean expression is not side-effect free.
{
CFE_TIME_SetPrintCmd((const CFE_TIME_SetPrintCmd_t *)SBBufPtr);
}
break;

default:

CFE_TIME_Global.CommandErrorCounter++;
Expand Down
13 changes: 13 additions & 0 deletions modules/time/fsw/src/cfe_time_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -1090,3 +1090,16 @@ 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)
{
CFE_TIME_Global.PrintState = data->Payload.PrintState;
strncpy(CFE_TIME_Global.PrintFormat, data->Payload.PrintFormat, CFE_TIME_FORMAT_SIZE);
return CFE_SUCCESS;
}
9 changes: 9 additions & 0 deletions modules/time/fsw/src/cfe_time_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@ 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_Global.PrintState = CFE_TIME_PRINT_DEFAULT;
strncpy(CFE_TIME_Global.PrintFormat, CFE_TIME_PRINTFMT_DEFAULT, CFE_TIME_FORMAT_SIZE);
}

/*----------------------------------------------------------------
Expand Down Expand Up @@ -408,6 +414,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.PrintState = CFE_TIME_Global.PrintState;
}

/*----------------------------------------------------------------
Expand Down
16 changes: 16 additions & 0 deletions modules/time/fsw/src/cfe_time_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,16 @@ 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_PrintState_Enum_t PrintState;

/*
** For formatted CFE_TIME_Print output, use this format string.
*/
char PrintFormat[CFE_TIME_FORMAT_SIZE];
} CFE_TIME_Global_t;

/*
Expand Down Expand Up @@ -867,4 +877,10 @@ 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);

#endif /* CFE_TIME_UTILS_H */
Loading