/************************************************************************** * * Copyright (c) 2024-2025 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file TestSupport.c * * @author (last) Sean Nash * @date (last) 10-Sep-2025 * * @author (original) Sean Nash * @date (original) 01-Aug-2024 * ***************************************************************************/ #include "Common.h" #include "Messaging.h" #include "Timers.h" /** * @addtogroup TestSupport * @{ */ // ********** private definitions ********** #define TEST_CONFIG_ENABLE_KEY 0xDABA36B2 ///< Release software configuration enable key. #define TEST_CONFIG_DISABLE_KEY 0x00000000 ///< Release software configuration disable key. #define DIALIN_CHECK_IN_TIMEOUT_MS ( 8 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Dialin check in timeout in milliseconds. // ********** private data ********** static U32 testConfig[ NUM_OF_TEST_CONFIGS ]; ///< Release software configuration. static U32 dialinCheckInTimeStamp; ///< Dialin checkin time stamp. static BOOL signalRecoverFromFaultMode; ///< Boolean flag to allow the user to recover from fault mode in test configurations. // ********** private function prototypes ********** /*********************************************************************//** * @brief * The getU08OverrideValue function extracts the appropriate unsigned byte * value from a given unsigned integer override record according to the record state. * @details \b Inputs: none * @details \b Outputs: none * @param ovU32 pointer to a floating point override record * @return either the real or overridden unsigned byte value from the record *************************************************************************/ U08 getU08OverrideValue( OVERRIDE_U32_T *ovU32 ) { U08 result = (U08)( ovU32->data & MASK_OFF_U32_MSBS ); if ( OVERRIDE_KEY == ovU32->override ) { result = (U08)( ovU32->ovData & MASK_OFF_U32_MSBS ); } return result; } /*********************************************************************//** * @brief * The getU16OverrideValue function extracts the appropriate unsigned short * value from a given unsigned integer override record according to the * record state. * @details \b Inputs: none * @details \b Outputs: none * @param ovU32 pointer to a floating point override record * @return either the real or overridden unsigned short value from the record *************************************************************************/ U16 getU16OverrideValue( OVERRIDE_U32_T *ovU32 ) { U16 result = (U16)( ovU32->data & MASK_OFF_MSW ); if ( OVERRIDE_KEY == ovU32->override ) { result = (U16)( ovU32->ovData & MASK_OFF_MSW ); } return result; } /*********************************************************************//** * @brief * The getS32OverrideValue function extracts the appropriate signed integer * value from a given signed integer override record according to the * record state. * @details \b Inputs: none * @details \b Outputs: none * @param ovS32 pointer to a signed integer override record * @return either the real or overridden signed integer value from the record *************************************************************************/ S32 getS32OverrideValue( OVERRIDE_S32_T *ovS32 ) { S32 result = ovS32->data; if ( OVERRIDE_KEY == ovS32->override ) { result = ovS32->ovData; } return result; } /*********************************************************************//** * @brief * The getU32OverrideValue function extracts the appropriate unsigned integer * value from a given unsigned integer override record according to the * record state. * @details \b Inputs: none * @details \b Outputs: none * @param ovU32 pointer to an unsigned integer override record * @return either the real or overridden unsigned integer value from the record *************************************************************************/ U32 getU32OverrideValue( OVERRIDE_U32_T *ovU32 ) { U32 result = ovU32->data; if ( OVERRIDE_KEY == ovU32->override ) { result = ovU32->ovData; } return result; } /*********************************************************************//** * @brief * The getF32OverrideValue function extracts the appropriate floating point * value from a given float override record according to the record state. * @details \b Inputs: none * @details \b Outputs: none * @param ovF32 pointer to a floating point override record * @return either the real or overridden floating point value from the record *************************************************************************/ F32 getF32OverrideValue( OVERRIDE_F32_T *ovF32 ) { F32 result = ovF32->data; if ( OVERRIDE_KEY == ovF32->override ) { result = ovF32->ovData; } return result; } /*********************************************************************//** * @brief * The getOverridePayloadFromMessage function extracts the override payload * record from a given override message. * @details \b Inputs: none * @details \b Outputs: none * @param message Pointer to an override message * @param override Pointer to override payload record to populate from the * given override message. * @return Type of override received *************************************************************************/ OVERRIDE_TYPE_T getOverridePayloadFromMessage( MESSAGE_T *message, TEST_OVERRIDE_PAYLOAD_T *override ) { OVERRIDE_TYPE_T reset = OVERRIDE_INVALID; // Verify payload length if ( sizeof(TEST_OVERRIDE_PAYLOAD_T) == message->hdr.payloadLen ) { memcpy( override, message->payload, sizeof(TEST_OVERRIDE_PAYLOAD_T) ); reset = ( TRUE == override->reset ? OVERRIDE_RESET_OVERRIDE : OVERRIDE_OVERRIDE ); } return reset; } /*********************************************************************//** * @brief * The getOverrideArrayPayloadFromMessage function extracts the override array * payload record from a given override array message. * @details \b Inputs: none * @details \b Outputs: none * @param message Pointer to an override message * @param override Pointer to override array payload record to populate from the * given override array message. * @return Type of override received *************************************************************************/ OVERRIDE_TYPE_T getOverrideArrayPayloadFromMessage( MESSAGE_T *message, TEST_OVERRIDE_ARRAY_PAYLOAD_T *override ) { OVERRIDE_TYPE_T reset = OVERRIDE_INVALID; // Verify payload length if ( sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) == message->hdr.payloadLen ) { memcpy( override, message->payload, sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) ); reset = ( TRUE == override->reset ? OVERRIDE_RESET_OVERRIDE : OVERRIDE_OVERRIDE ); } return reset; } /*********************************************************************//** * @brief * The u32BroadcastIntervalOverride function sets the override for a given * U32 broadcast interval override record. * @details \b Inputs: none * @details \b Outputs: none * @param message Override message from Dialin which includes the U32 override * value (in ms). * @param override Pointer to the override record to set * @param taskIntvlMS Task interval (in ms) * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL u32BroadcastIntervalOverride( MESSAGE_T *message, OVERRIDE_U32_T *override, U32 taskIntvlMS ) { BOOL result = FALSE; TEST_OVERRIDE_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverridePayloadFromMessage( message, &payload ); // Verify tester has logged in with f/w and override type is valid if ( ( TRUE == isTestingActivated() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { result = TRUE; if ( OVERRIDE_OVERRIDE == ovType ) { U32 value = payload.state.u32; U32 intvl = value / taskIntvlMS; override->ovData = intvl; override->override = OVERRIDE_KEY; } else { override->override = OVERRIDE_RESET; override->ovData = override->ovInitData; } } return result; } /*********************************************************************//** * @brief * The u32Override function sets the override for a given U32 override record. * @details \b Inputs: none * @details \b Outputs: none * @param message Override message from Dialin which includes the U32 override * value. * @param override Pointer to the override record to set * @param min Minimum value that should be allowed * @param max Maximum value that should be allowed * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL u32Override( MESSAGE_T *message, OVERRIDE_U32_T *override, U32 min, U32 max ) { BOOL result = FALSE; TEST_OVERRIDE_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverridePayloadFromMessage( message, &payload ); // Verify tester has logged in with f/w and override type is valid if ( ( TRUE == isTestingActivated() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { if ( OVERRIDE_OVERRIDE == ovType ) { U32 value = payload.state.u32; if ( ( value >= min ) && ( value <= max ) ) { result = TRUE; override->ovData = value; override->override = OVERRIDE_KEY; } } else { result = TRUE; override->override = OVERRIDE_RESET; override->ovData = override->ovInitData; } } return result; } /*********************************************************************//** * @brief * The f32Override function sets the override for a given F32 override record. * @details \b Inputs: none * @details \b Outputs: none * @param message Override message from Dialin which includes the F32 override * value. * @param override Pointer to the override record to set * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL f32Override( MESSAGE_T *message, OVERRIDE_F32_T *override ) { BOOL result = FALSE; TEST_OVERRIDE_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverridePayloadFromMessage( message, &payload ); // Verify tester has logged in with f/w and override type is valid if ( ( TRUE == isTestingActivated() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { result = TRUE; if ( OVERRIDE_OVERRIDE == ovType ) { F32 value = payload.state.f32; override->ovData = value; override->override = OVERRIDE_KEY; } else { override->override = OVERRIDE_RESET; override->ovData = override->ovInitData; } } return result; } /*********************************************************************//** * @brief * The s32Override function sets the override for a given S32 override record. * @details \b Inputs: none * @details \b Outputs: none * @param message Override message from Dialin which includes the S32 override * value. * @param override Pointer to the override record to set * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL s32Override( MESSAGE_T *message, OVERRIDE_S32_T *override ) { BOOL result = FALSE; TEST_OVERRIDE_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverridePayloadFromMessage( message, &payload ); // Verify tester has logged in with f/w and override type is valid if ( ( TRUE == isTestingActivated() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { result = TRUE; if ( OVERRIDE_OVERRIDE == ovType ) { S32 value = payload.state.s32; override->ovData = value; override->override = OVERRIDE_KEY; } else { override->override = OVERRIDE_RESET; override->ovData = override->ovInitData; } } return result; } /*********************************************************************//** * @brief * The u32ArrayOverride function sets the override for a given array of U32 * override records. * @details \b Inputs: none * @details \b Outputs: none * @param message Override message from Dialin which includes the U32 override * value and the array index. * @param override Pointer to the array of override records * @param maxIndex Maximum array index to allow * @param min Minimum value that should be allowed * @param max Maximum value that should be allowed * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL u32ArrayOverride( MESSAGE_T *message, OVERRIDE_U32_T *override, U32 maxIndex, U32 min, U32 max ) { BOOL result = FALSE; TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverrideArrayPayloadFromMessage( message, &payload ); // Verify tester has logged in with f/w and override type is valid if ( ( TRUE == isTestingActivated() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { U32 index = payload.index; // Verify index of override if ( index <= maxIndex ) { if ( OVERRIDE_OVERRIDE == ovType ) { U32 value = payload.state.u32; if ( ( value >= min ) && ( value <= max ) ) { result = TRUE; override[ index ].ovData = value; override[ index ].override = OVERRIDE_KEY; } } else { result = TRUE; override[ index ].override = OVERRIDE_RESET; override[ index ].ovData = override[ index ].ovInitData; } } } return result; } /*********************************************************************//** * @brief * The f32ArrayOverride function sets the override for a given array of F32 * override records. * @details \b Inputs: none * @details \b Outputs: none * @param message Override message from Dialin which includes the F32 override * value and the array index. * @param override Pointer to the array of override records * @param maxIndex Maximum array index to allow * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL f32ArrayOverride( MESSAGE_T *message, OVERRIDE_F32_T *override, U32 maxIndex ) { BOOL result = FALSE; TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverrideArrayPayloadFromMessage( message, &payload ); // Verify tester has logged in with f/w and override type is valid if ( ( TRUE == isTestingActivated() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { U32 index = payload.index; // Verify voltage index of override if ( index <= maxIndex ) { result = TRUE; if ( OVERRIDE_OVERRIDE == ovType ) { F32 value = payload.state.f32; override[ index ].ovData = value; override[ index ].override = OVERRIDE_KEY; } else { override[ index ].override = OVERRIDE_RESET; override[ index ].ovData = override[ index ].ovInitData; } } } return result; } /*********************************************************************//** * @brief * The s32ArrayOverride function sets the override for a given array of S32 * override records. * @details \b Inputs: none * @details \b Outputs: none * @param message Override message from Dialin which includes the S32 override * value and the array index. * @param override Pointer to the array of override records * @param maxIndex Maximum array index to allow * @return TRUE if override is successful, FALSE if not *************************************************************************/ BOOL s32ArrayOverride( MESSAGE_T *message, OVERRIDE_S32_T *override, U32 maxIndex ) { BOOL result = FALSE; TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverrideArrayPayloadFromMessage( message, &payload ); // Verify tester has logged in with f/w and override type is valid if ( ( TRUE == isTestingActivated() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { U32 index = payload.index; // Verify voltage index of override if ( index <= maxIndex ) { result = TRUE; if ( OVERRIDE_OVERRIDE == ovType ) { S32 value = payload.state.s32; override[ index ].ovData = value; override[ index ].override = OVERRIDE_KEY; } else { override[ index ].override = OVERRIDE_RESET; override[ index ].ovData = override[ index ].ovInitData; } } } return result; } // ********** Release software configurations functions ********** /*********************************************************************//** * @brief * The initTestConfigs function initializes the test software configurations. * @details \b Inputs: none * @details \b Outputs: signalRecoverFromFaultMode * @return none *************************************************************************/ void initTestConfigs( void ) { resetAllTestConfigs(); signalRecoverFromFaultMode = FALSE; } /*********************************************************************//** * @brief * The setTestConfig function sets the test configuration. * @warning Dialin must be logged into related firmware stack to set the * test configuration successfully. * @details \b Inputs: none * @details \b Outputs: testConfig * @param config which test configuration to set * @return TRUE if the set configuration was successful otherwise, FALSE *************************************************************************/ BOOL setTestConfig( TEST_CONFIG_T config ) { BOOL status = FALSE; if ( TRUE == isTestingActivated() ) { testConfig[ config ] = TEST_CONFIG_ENABLE_KEY; status = TRUE; } return status; } /*********************************************************************//** * @brief * The resetTestConfig function resets a given test configuration. * @warning Dialin must be logged into related firmware stack to reset the * test configuration successfully. * @details \b Inputs: none * @details \b Outputs: testConfig * @param config which test configuration to reset * @return TRUE if the reset configuration was successful otherwise, FALSE *************************************************************************/ BOOL resetTestConfig( TEST_CONFIG_T config ) { BOOL status = FALSE; if ( TRUE == isTestingActivated() ) { testConfig[ config ] = TEST_CONFIG_DISABLE_KEY; status = TRUE; } return status; } /*********************************************************************//** * @brief * The getTestConfigStatus function gets the status of the given test * configuration. * @details \b Inputs: testConfig * @details \b Outputs: none * @param config the test configuration to get status of * @return TRUE if the test configuration is enabled, otherwise FALSE *************************************************************************/ BOOL getTestConfigStatus( TEST_CONFIG_T config ) { BOOL status = FALSE; if ( TEST_CONFIG_ENABLE_KEY == testConfig[ config ] ) { status = TRUE; } return status; } /*********************************************************************//** * @brief * The sendTestConfigStatusToDialin function sends the test configuration * status to dialin. * @details \b Message \b sent: MSG_ID_TD_SEND_TEST_CONFIGURATION * @details \b Inputs: testConfig * @details \b Outputs: none * @return TRUE if the test configuration message is successfully queued for * transmit, otherwise FALSE *************************************************************************/ BOOL sendTestConfigStatusToDialin( void ) { BOOL result = FALSE; MESSAGE_T msg; TEST_CONFIG_T config; BOOL configStatus; U08 *payloadPtr = msg.payload; if ( TRUE == isTestingActivated() ) { // Create a message record blankMessage( &msg ); #ifdef _DD_ msg.hdr.msgID = MSG_ID_DD_SEND_TEST_CONFIGURATION; #endif #ifdef _TD_ msg.hdr.msgID = MSG_ID_TD_SEND_TEST_CONFIGURATION; #endif msg.hdr.payloadLen = MIN( sizeof( testConfig ), ( sizeof( BOOL ) * MAX_TEST_CONFIGS ) ); for ( config = TEST_CONFIG_FIRST; config < NUM_OF_TEST_CONFIGS; ++config ) { configStatus = getTestConfigStatus( config ); if ( (U32)config >= MAX_TEST_CONFIGS ) { break; } else { memcpy( payloadPtr, (U08*)&configStatus, sizeof( BOOL ) ); payloadPtr += sizeof( BOOL ); } } // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer #ifdef _DD_ result = serializeMessage( msg, COMM_BUFFER_OUT_DD_CAN_PC, ACK_NOT_REQUIRED ); #endif #ifdef _TD_ result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_PC, ACK_NOT_REQUIRED ); #endif } return result; } /*********************************************************************//** * @brief * The resetAllTestConfigs function resets all of the test configurations. * @warning Dialin must be logged into related firmware stack to reset the * test configurations successfully. * @details \b Inputs: none * @details \b Outputs: testConfig * @return TRUE if the reset was successful, otherwise FALSE *************************************************************************/ BOOL resetAllTestConfigs( void ) { BOOL status = FALSE; if ( TRUE == isTestingActivated() ) { TEST_CONFIG_T config; for ( config = TEST_CONFIG_FIRST; config < NUM_OF_TEST_CONFIGS; ++config ) { testConfig[ config ] = TEST_CONFIG_DISABLE_KEY; } status = TRUE; } return status; } /*********************************************************************//** * @brief * The setDialinCheckInTimeStamp function registers a check-in from Dialin. * @details \b Inputs: none * @details \b Outputs: dialinCheckInTimeStamp * @return none *************************************************************************/ void setDialinCheckInTimeStamp( void ) { dialinCheckInTimeStamp = getMSTimerCount(); } /*********************************************************************//** * @brief * The hasDialinCheckInExpired function checks whether the check-in from * Dialin has expired. * @details \b Inputs: dialinCheckInTimeStamp * @details \b Outputs: none * @return TRUE if the check-in has expired, otherwise FALSE *************************************************************************/ BOOL hasDialinCheckInExpired( void ) { BOOL status = FALSE; if ( ( TRUE == didTimeout( dialinCheckInTimeStamp, DIALIN_CHECK_IN_TIMEOUT_MS ) ) && ( TRUE == isTestingActivated() ) ) { // If the dialin check in has timed out and tester has logged in check for the expiration value status = TRUE; } return status; } /*********************************************************************//** * @brief * The setRecoverFromFaultModeSignal function handles the recover from fault * mode signal from Dialin. * @warning Dialin must be logged into related firmware stack to set the * recover from fault mode flag successfully. * @details \b Inputs: none * @details \b Outputs: signalRecoverFromFaultMode * @return none *************************************************************************/ void setRecoverFromFaultModeSignal( void ) { if ( TRUE == isTestingActivated() ) { signalRecoverFromFaultMode = TRUE; } } /*********************************************************************//** * @brief * The hasRecoverFromFaultModeBeenSet function gets the state of the * recover from fault mode flag. * @details \b Inputs: signalRecoverFromFaultMode * @details \b Outputs: none * @return TRUE if the recover from fault mode flag is set, otherwise FALSE *************************************************************************/ BOOL hasRecoverFromFaultModeBeenSet( void ) { return signalRecoverFromFaultMode; } /**@}*/