/************************************************************************** * * Copyright (c) 2024-2024 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 Messaging.c * * @author (last) Sean * @date (last) 30-Jul-2024 * * @author (original) Sean * @date (original) 30-Jul-2024 * ***************************************************************************/ #include // For memcpy() #include "AirPump.h" #include "AirTrap.h" #include "AlarmMgmt.h" #include "BloodFlow.h" #include "Bubbles.h" #include "Buttons.h" #include "Compatible.h" #include "CpldInterface.h" #include "DDInterface.h" #include "Ejector.h" #include "FpgaTD.h" #include "LevelSensors.h" #include "Messaging.h" #include "ModeTxParams.h" #include "ModeStandby.h" #include "OperationModes.h" #include "PAL.h" #include "Pressures.h" #include "RotaryValve.h" #include "StateTxDialysis.h" #include "StateTxPaused.h" #include "Switches.h" #include "SystemCommTD.h" #include "Utilities.h" #include "Valve3Way.h" #include "Valves.h" #include "Voltages.h" #include "WatchdogMgmt.h" /** * @addtogroup Messaging * @{ */ // ********** private definitions ********** #define MAX_MSGS_BLOCKED_FOR_XMIT 8 ///< Maximum number of messages to block transmission for. #pragma pack(push,1) /// Payload record structure for block message transmission request. typedef struct { U16 blockedMessages[ MAX_MSGS_BLOCKED_FOR_XMIT ]; ///< Blocked messages. } BLOCKED_MSGS_DATA_T; #pragma pack(pop) /// Array of CAN communication buffers to respond on (aligned with enum Comm_Buffers). static const COMM_BUFFER_T tdResponseBuffers[ NUM_OF_COMM_BUFFERS ] = { COMM_BUFFER_NOT_USED, ///< CAN message boxes start at 1 so we will not use this buffer COMM_BUFFER_NOT_USED, ///< Buffer for outgoing TD alarm messages so no response buffer COMM_BUFFER_OUT_CAN_TD_ALARM, ///< Buffer for responding to incoming DD alarm messages COMM_BUFFER_OUT_CAN_TD_ALARM, ///< Buffer for responding to incoming RO alarm messages COMM_BUFFER_OUT_CAN_TD_ALARM, ///< Buffer for responding to incoming UI alarm messages COMM_BUFFER_NOT_USED, ///< Buffer for outgoing TD to DD messages so no response buffer COMM_BUFFER_OUT_CAN_TD_2_DD, ///< Buffer for responding to incoming DD to TD messages COMM_BUFFER_NOT_USED, ///< Buffer for outgoing TD to UI messages so no response buffer COMM_BUFFER_OUT_CAN_TD_2_UI, ///< Buffer for responding to incoming UI to TD messages COMM_BUFFER_NOT_USED, ///< Buffer for outgoing TD broadcast messages so no response buffer COMM_BUFFER_OUT_CAN_TD_BROADCAST, ///< Buffer for responding to incoming DD broadcast messages COMM_BUFFER_OUT_CAN_TD_BROADCAST, ///< Buffer for responding to incoming RO broadcast messages COMM_BUFFER_OUT_CAN_TD_BROADCAST, ///< Buffer for responding to incoming UI broadcast messages COMM_BUFFER_OUT_CAN_PC, ///< Buffer for responding to incoming PC to RO messages COMM_BUFFER_NOT_USED, ///< Buffer for outgoing TD to PC messages so no response buffer }; typedef BOOL (*MsgFuncPtr)( MESSAGE_T* ); /// Message handling look-up table record type. typedef struct { U16 msgID; ///< ID of received message to handle. MsgFuncPtr msgHandler; ///< Pointer to message handling function associated with a message ID. } MSG_HANDLER_LOOKUP_T; /// Message handling function lookup table static const MSG_HANDLER_LOOKUP_T MSG_FUNCTION_HANDLER_LOOKUP[] = { { MSG_ID_ALARM_TRIGGERED, &handleAlarmTriggered }, { MSG_ID_ALARM_CONDITION_CLEARED, &handleAlarmConditionCleared }, { MSG_ID_UI_ALARM_USER_ACTION_REQUEST, &handleAlarmUserAction }, { MSG_ID_UI_ACTIVE_ALARMS_LIST_REQUEST, &handleActiveAlarmListRequest }, { MSG_ID_FW_VERSIONS_REQUEST, &handleVersionRequestMessage }, { MSG_ID_UI_CHECK_IN, &handleUICheckIn }, { MSG_ID_DD_OP_MODE_DATA, &setDDOpMode }, { MSG_ID_DD_PRESSURES_DATA, &setDialysatePressure }, { MSG_ID_UI_TREATMENT_PARAMS_TO_VALIDATE, &validateAndSetTreatmentParameters }, { MSG_ID_UI_ULTRAFILTRATION_VOLUME_TO_VALIDATE, &validateAndSetUFVolume }, { MSG_ID_UI_TREATMENT_PARAMS_CONFIRMED, &signalUserConfirmationOfTreatmentParameters }, { MSG_ID_UI_INITIATE_TREATMENT_WORKFLOW, &signalUserInitiateTreatment }, { MSG_ID_UI_UF_PAUSE_RESUME_REQUEST, &signalPauseResumeUF }, { MSG_ID_TESTER_LOGIN_REQUEST, &handleTesterLogInRequest }, { MSG_ID_TD_SOFTWARE_RESET_REQUEST, &testTDSoftwareResetRequest }, { MSG_ID_TD_BUBBLE_OVERRIDE_REQUEST, &testBubbleDetectOverride }, { MSG_ID_TD_BUBBLE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testBubblesDataPublishIntervalOverride }, { MSG_ID_TD_VOLTAGE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testVoltageDataPublishIntervalOverride }, { MSG_ID_TD_VOLTAGE_OVERRIDE_REQUEST, &testVoltageOverride }, { MSG_ID_TD_PRESSURE_OVERRIDE_REQUEST, &testPressureSensorOverride }, { MSG_ID_TD_PRESSURE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testPressuresDataPublishIntervalOverride }, { MSG_ID_TD_AIR_PUMP_SET_STATE_REQUEST, &testSetAirPump }, { MSG_ID_TD_AIR_PUMP_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testAirPumpDataPublishIntervalOverride }, { MSG_ID_TD_SWITCHES_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testSwitchesDataPublishIntervalOverride }, { MSG_ID_TD_SWITCH_STATE_OVERRIDE_REQUEST, &testSwitchOverride }, { MSG_ID_TD_OFF_BUTTON_OVERRIDE_REQUEST, &testOffButtonOverride }, { MSG_ID_TD_STOP_BUTTON_OVERRIDE_REQUEST, &testStopButtonOverride }, { MSG_ID_TD_ALARM_LAMP_PATTERN_OVERRIDE_REQUEST, &testAlarmLampPatternOverride }, { MSG_ID_TD_ALARM_AUDIO_LEVEL_OVERRIDE_REQUEST, &testAlarmAudioVolumeLevelOverride }, { MSG_ID_TD_ALARM_AUDIO_CURRENT_HG_OVERRIDE_REQUEST, &testPrimaryAlarmAudioCurrentHGOverride }, { MSG_ID_TD_ALARM_AUDIO_CURRENT_LG_OVERRIDE_REQUEST, &testPrimaryAlarmAudioCurrentLGOverride }, { MSG_ID_TD_BACKUP_ALARM_AUDIO_CURRENT_OVERRIDE_REQUEST, &testBackupAlarmAudioCurrentOverride }, { MSG_ID_TD_AIR_TRAP_LEVEL_OVERRIDE_REQUEST, &testLevelSensorOverride }, { MSG_ID_TD_AIR_TRAP_LEVEL_RAW_OVERRIDE_REQUEST, &testRawLevelSensorOverride }, { MSG_ID_TD_AIR_TRAP_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testAirTrapDataPublishIntervalOverride }, { MSG_ID_TD_3_WAY_VALVE_SET_STATE_REQUEST, &testSet3WayValve }, { MSG_ID_TD_ROTARY_PINCH_VALVE_SET_POS_REQUEST, &testSetValve }, { MSG_ID_TD_ROTARY_PINCH_VALVE_STATUS_OVERRIDE_REQUEST, &testValveStatusOverride }, { MSG_ID_TD_ROTARY_PINCH_VALVE_POSITION_OVERRIDE_REQUEST, &testValveEncoderPositionOverride }, { MSG_ID_TD_VALVES_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testValvesDataPublishIntervalOverride }, { MSG_ID_TD_PINCH_VALVE_SET_POSITION_REQUEST, &testValveSetABCCmdPosition }, { MSG_ID_TD_PINCH_VALVE_HOME_REQUEST, &testHomeValve }, { MSG_ID_TD_ALARM_STATUS_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testAlarmStatusPublishIntervalOverride }, { MSG_ID_TD_ALARM_INFO_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testAlarmInfoPublishIntervalOverride }, { MSG_ID_TD_ALARM_START_TIME_OVERRIDE_REQUEST, &testSetAlarmStartTimeOverride }, { MSG_ID_TD_ALARM_CLEAR_ALL_ALARMS_REQUEST, &testClearAllAlarms }, { MSG_ID_TD_WATCHDOG_OVERRIDE_REQUEST, &testWatchdogTaskCheckInOverride }, { MSG_ID_TD_ALARM_STATE_OVERRIDE_REQUEST, &testAlarmStateOverride }, { MSG_ID_TD_SAFETY_SHUTDOWN_OVERRIDE_REQUEST, &testSafetyShutdownOverride }, { MSG_ID_TD_BLOOD_PUMP_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testBloodFlowDataPublishIntervalOverride }, { MSG_ID_TD_BLOOD_PUMP_SET_FLOW_RATE_REQUEST, &testSetTargetBloodFlowRateOverride }, { MSG_ID_TD_BLOOD_PUMP_SET_SPEED_REQUEST, &testSetBloodPumpSpeedOverride }, { MSG_ID_TD_BLOOD_PUMP_MEASURED_FLOW_RATE_OVERRIDE_REQUEST, &testMeasuredBloodFlowRateOverride }, { MSG_ID_TD_BLOOD_PUMP_MEASURED_MOTOR_SPEED_OVERRIDE_REQUEST, &testMeasuredBloodPumpSpeedOverride }, { MSG_ID_TD_BLOOD_PUMP_MEASURED_ROTOR_SPEED_OVERRIDE_REQUEST, &testMeasuredBloodPumpRotorSpeedOverride }, { MSG_ID_TD_BLOOD_PUMP_ROTOR_COUNT_OVERRIDE_REQUEST, &testBloodPumpRotorCountOverride }, { MSG_ID_TD_TMP_PRESSURE_OVERRIDE_REQUEST, &testTMPOverride }, { MSG_ID_TD_REQ_CURRENT_TREATMENT_PARAMETERS, &testTxParamsRequest }, { MSG_ID_TD_SET_TREATMENT_PARAMETER, &testSetTreatmentParameter }, { MSG_ID_TD_OP_MODE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testSetOpModePublishIntervalOverride }, { MSG_ID_TD_OP_MODE_OVERRIDE_REQUEST, &testSetOperationMode }, { MSG_ID_TD_EJECTOR_MOTOR_SET_SPEED_REQUEST, &testSetEjectorMotorSpeed }, { MSG_ID_TD_EJECTOR_COMMAND, &testEjectorCommand }, { MSG_ID_TD_SET_AIR_TRAP_CONTROL, &testSetAirTrapControl }, { MSG_ID_TD_HOME_BLOOD_PUMP, &testHomeBloodPump }, { MSG_ID_TD_BLOOD_FLOW_ALPHA_Y_INTERCEPT_OVERRIDE_REQUEST, &testBPFlowAlphaYInterceptOverride }, { MSG_ID_TD_BLOOD_FLOW_WEAR_A_TERM_OVERRIDE_REQUEST, &testBPFlowWearATermOverride }, { MSG_ID_TD_BLOOD_FLOW_WEAR_B_TERM_OVERRIDE_REQUEST, &testBPFlowWearBTermOverride }, { MSG_ID_TD_SET_TEST_CONFIGURATION, &testSetTestConfiguration }, { MSG_ID_TD_GET_TEST_CONFIGURATION, &testGetTestConfiguration }, { MSG_ID_TD_RESET_ALL_TEST_CONFIGURATIONS, &testResetAllTestConfigurations }, { MSG_ID_TD_AIR_PUMP_POWER_RAISE_OVERRIDE_REQUEST, &testAirPumpPowerRaiseOverride }, { MSG_ID_TD_AIR_PUMP_POWER_LOWER_OVERRIDE_REQUEST, &testAirPumpPowerLowerOverride }, }; #define NUM_OF_FUNCTION_HANDLERS (sizeof(MSG_FUNCTION_HANDLER_LOOKUP) / sizeof(MSG_HANDLER_LOOKUP_T)) // ********** private data ********** static BOOL testerLoggedIn = FALSE; ///< Flag indicates whether an external tester (connected PC) has sent a valid login message. static volatile U16 nextSeqNo = 1; ///< Value of sequence number to use for next transmitted message. /// List of message IDs that are requested not to be transmitted. static BLOCKED_MSGS_DATA_T blockedMessagesForXmit = { 0, 0, 0, 0, 0, 0, 0, 0 }; /// UI version information static UI_VERSIONS_T uiVersionRecord = { 0, 0, 0, 0, 0 }; // ********** private function prototypes ********** static MsgFuncPtr getMsgHandler( U16 msgID ); static BOOL sendTestAckResponseMsg( MSG_ID_T msgID, BOOL ack ); static BOOL sendAckResponseMsg( MSG_ID_T msgID, COMM_BUFFER_T buffer, BOOL ack ); /*********************************************************************//** * @brief * The serializeMessage function serializes a given message into an array * of bytes that conform to our CAN message format. A sequence number is added * and the ACK bit of the sequence number is set if ACK is required per parameter. * A sync byte is inserted at the beginning and an 8-bit CRC is appended to * the end. The serialized message data is queued for transmission in the given * buffer. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT on failure to add a message to the * pending ACK list (list is full). * @details \b Inputs: blockedMessagesForXmit * @details \b Outputs: given buffer is populated with serialized message data and * queued for transmit. * @param msg message to serialize * @param buffer outgoing buffer where serialized message should be queued * @param ackReq Flag indicates whether an acknowledgement from receiver is required? * @return Number of bytes of serialized message data added to the given buffer. *************************************************************************/ U32 serializeMessage( MESSAGE_T msg, COMM_BUFFER_T buffer, BOOL ackReq ) { BOOL result = 0; BOOL blocked = FALSE; U32 msgSize = 0; U32 sizeMod, sizePad; U32 i; U08 crc; U08 data[ MAX_ACK_MSG_SIZE ]; // Byte array to populate with message data #ifdef TEST_AIR_TRAP_ALPHA_TESTING return 0; #endif #ifdef TEST_PINCH_VALVES return 0; #endif // Check to see if tester has requested this message not be transmited if ( TRUE == isTestingActivated() ) { U32 i; for ( i = 0; i < MAX_MSGS_BLOCKED_FOR_XMIT; i++ ) { if ( msg.hdr.msgID == blockedMessagesForXmit.blockedMessages[ i ] ) { blocked = TRUE; break; } } } // Serialize and queue message for transmission unless this message is blocked if ( blocked != TRUE ) { // Prefix data with message sync byte data[ msgSize++ ] = MESSAGE_SYNC_BYTE; // Set sequence # and ACK bit (unless this is an ACK to a received message) if ( msg.hdr.msgID != MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK ) { // Thread protect next sequence # access & increment _disable_IRQ(); msg.hdr.seqNo = nextSeqNo; nextSeqNo = INC_WRAP( nextSeqNo, MIN_MSG_SEQ_NO, MAX_MSG_SEQ_NO ); _enable_IRQ(); if ( TRUE == ackReq ) { msg.hdr.seqNo *= -1; } } // Calculate message CRC crc = crc8( (U08*)(&msg), sizeof( MESSAGE_HEADER_T ) + msg.hdr.payloadLen ); // Serialize message header data memcpy( &data[ msgSize ], &( msg.hdr ), sizeof( MESSAGE_HEADER_T ) ); msgSize += sizeof( MESSAGE_HEADER_T ); // Serialize message payload (only used bytes per payloadLen field) memcpy( &data[ msgSize ], &( msg.payload ), msg.hdr.payloadLen ); msgSize += msg.hdr.payloadLen; // Add 8-bit CRC data[ msgSize++ ] = crc; // Pad with zero bytes to get length a multiple of CAN_FRAME_PAYLOAD_SIZE (8) sizeMod = msgSize % CAN_FRAME_PAYLOAD_SIZE; sizePad = ( sizeMod == 0 ? 0 : CAN_FRAME_PAYLOAD_SIZE - sizeMod ); for ( i = 0; i < sizePad; i++ ) { data[ msgSize++ ] = 0; } #ifndef _RELEASE_ // if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ACK_ERRORS ) != SW_CONFIG_ENABLE_VALUE ) #endif { // If ACK required, add to pending ACK list if ( TRUE == ackReq ) { if ( FALSE == addMsgToPendingACKList( &msg, buffer, data, msgSize ) ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_MSG_PENDING_ACK_LIST_FULL, (U32)(msg.hdr.msgID) ) } } } // Add serialized message data to appropriate out-going comm buffer result = addToCommBuffer( buffer, data, msgSize ); } else { result = TRUE; // If message blocked, return successful transmission } return result; } /*********************************************************************//** * @brief * The sendACKMsg function constructs and queues for transmit an ACK message * for a given received message. * @details \b Inputs: none * @details \b Outputs: ACK message constructed and queued for transmit on broadcast * CAN channel. * @param message Pointer to message that is being ACKed * @return TRUE if ACK message queued for transmit successfully, FALSE if not *************************************************************************/ BOOL sendACKMsg( MESSAGE_T *message ) { BOOL result; MESSAGE_T msg; // Create a message record blankMessage( &msg ); // Send ACK back with same seq. #, but w/o ACK bit msg.hdr.seqNo = message->hdr.seqNo * -1; // ACK messages always have this ID msg.hdr.msgID = MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK; // ACK messages always have no payload msg.hdr.payloadLen = 0; // Serialize and queue the message for transmit on broadcast channel result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_TD_BROADCAST, ACK_NOT_REQUIRED ); return result; } /*********************************************************************//** * @brief * The sendAckResponseMsg function constructs a simple response message for * a handled message and queues it for transmit on the appropriate CAN channel. * @details \b Inputs: none * @details \b Outputs: response message constructed and queued for transmit. * @param msgID ID of handled message that we are responding to * @param buffer outgoing buffer that message should be queued to * @param ack TRUE to ACK, FALSE to NAK * @return TRUE if response message successfully queued for transmit, FALSE if not *************************************************************************/ static BOOL sendAckResponseMsg( MSG_ID_T msgID, COMM_BUFFER_T buffer, BOOL ack ) { BOOL result; MESSAGE_T msg; ACK_RESPONSE_PAYLOAD_T cmd; cmd.acknowledgement = ack; // Create a message record blankMessage( &msg ); msg.hdr.msgID = msgID; msg.hdr.payloadLen = sizeof( ACK_RESPONSE_PAYLOAD_T ); memcpy( &msg.payload, &cmd, sizeof( ACK_RESPONSE_PAYLOAD_T ) ); // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, buffer, ACK_NOT_REQUIRED ); return result; } /*********************************************************************//** * @brief * The getMsgHandler function finds the appropriate handler function for * a given message. * @details \b Inputs: MSG_FUNCTION_HANDLER_LOOKUP[], MSG_FUNCTION_HANDLERS[] * @details \b Outputs: none * @param msgID ID of message to find handler function for * @return pointer to appropriate function to handle the given message *************************************************************************/ static MsgFuncPtr getMsgHandler( U16 msgID ) { U32 i; MsgFuncPtr func = 0; // Search for the index associated with the given override command message ID and then use index to get the handling function for ( i = 0; i < NUM_OF_FUNCTION_HANDLERS; i++ ) { if ( MSG_FUNCTION_HANDLER_LOOKUP[i].msgID == msgID ) { func = MSG_FUNCTION_HANDLER_LOOKUP[i].msgHandler; break; } } return func; } /*********************************************************************//** * @brief * The handleIncomingMessage function calls the appropriate handler function * for a given message and sends appropriate ACK/NAK response. * @details \b Inputs: none * @details \b Outputs: Appropriate message handler function called * @param message Incoming message to handle * @return none *************************************************************************/ void handleIncomingMessage( MESSAGE_T *message ) { BOOL ack = FALSE; // assume we will NAK until we have successful handling of message COMM_BUFFER_T respBuffer = tdResponseBuffers[ message->in_buffer ]; // if Dialin message, ensure Dialin is logged in before processing it if ( ( message->hdr.msgID <= MSG_ID_FIRST_TD_TESTER_MESSAGE ) || ( TRUE == isTestingActivated() ) ) { MsgFuncPtr msgFuncPtr; // Find the appropriate message handling function to call msgFuncPtr = getMsgHandler( message->hdr.msgID ); // Ensure a handler is found before calling it if ( msgFuncPtr != 0 ) { // Call the appropriate message handling function ack = (*msgFuncPtr)( message ); } } // ACK/NAK request if ( message->hdr.msgID < MSG_ID_FIRST_TD_TESTER_MESSAGE ) { // Already ACK'd msg if required prior to this function // if ( respBuffer != COMM_BUFFER_NOT_USED ) // { // sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, respBuffer, ack ); // } } else { sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, ack ); } } /*********************************************************************//** * @brief * The handleVersionRequestMessage function handles a UI request for TD * version information. * @details \b Message \b Sent: MSG_ID_TD_VERSION_RESPONSE * @details \b Inputs: none * @details \b Outputs: uiVersionRecord * @param message Pointer to the UI version request message which contains * the UI version information as well. * @return TRUE if request handled successfully, FALSE if not *************************************************************************/ BOOL handleVersionRequestMessage( MESSAGE_T *message ) { BOOL result = FALSE; if ( message->hdr.payloadLen == sizeof( UI_VERSIONS_T ) ) { TD_VERSIONS_T tdVersionRecord; // Record UI version information memcpy( (U08*)(&uiVersionRecord), &message->payload, sizeof( UI_VERSIONS_T ) ); // Build TD version record tdVersionRecord.major = TD_VERSION_MAJOR; tdVersionRecord.minor = TD_VERSION_MINOR; tdVersionRecord.micro = TD_VERSION_MICRO; tdVersionRecord.build = TD_VERSION_BUILD; getFPGAVersions( &tdVersionRecord.fpgaId, &tdVersionRecord.fpgaMajor, &tdVersionRecord.fpgaMinor, &tdVersionRecord.fpgaLab ); tdVersionRecord.compatibilityRev = SW_COMPATIBILITY_REV; // Send TD version information result = sendMessage( MSG_ID_TD_VERSION_RESPONSE, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&tdVersionRecord, sizeof( TD_VERSIONS_T ) ); } return result; } // *********************************************************************** // ***************** Message Sending Helper Functions ******************** // *********************************************************************** /*********************************************************************//** * @brief * The sendEvent function constructs a TD event message and queues the msg * for transmit on the TD=>UI CAN channel. * @details \b Inputs: none * @details \b Outputs: TD event msg constructed and queued for transmit. * @param event Enumeration of event type that occurred * @param dat1 First data associated with event * @param dat2 Second data associated with event * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL sendEvent( TD_EVENT_ID_T event, EVENT_DATA_T dat1, EVENT_DATA_T dat2 ) { BOOL result; MESSAGE_T msg; EVENT_PAYLOAD_T eventStruct; eventStruct.event = (U32)event; eventStruct.dataType1 = (U32)dat1.dataType; eventStruct.data1 = dat1.data; eventStruct.dataType2 = (U32)dat2.dataType; eventStruct.data2 = dat2.data; // Create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_TD_EVENT; // The payload length is the event ID, 2 event datas and the events data types for each of the event data msg.hdr.payloadLen = sizeof( EVENT_PAYLOAD_T ); memcpy( &msg.payload, &eventStruct, sizeof( EVENT_PAYLOAD_T ) ); // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_TD_2_UI, ACK_NOT_REQUIRED ); return result; } /*********************************************************************//** * @brief * The sendOffButtonMsgToUI function constructs an off button msg to the UI * and queues the msg for transmit on the appropriate CAN channel. * @details \b Message \b Sent: MSG_ID_OFF_BUTTON_PRESS_REQUEST * @details \b Inputs: none * @details \b Outputs: Off button msg constructed and queued. * @param prompt 0=prompt user to confirm, 1=cancel prompt, 2=reject user off request * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL sendOffButtonMsgToUI( U08 prompt ) { BOOL result; MESSAGE_T msg; UI_OFF_BUTTON_RESPONSE_PAYLOAD_T cmd; cmd.userRequest = prompt; // Create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_OFF_BUTTON_PRESS_REQUEST; msg.hdr.payloadLen = sizeof( UI_OFF_BUTTON_RESPONSE_PAYLOAD_T ); memcpy( &msg.payload, &cmd, sizeof( UI_OFF_BUTTON_RESPONSE_PAYLOAD_T ) ); // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_TD_2_UI, ACK_REQUIRED ); return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The isTestingActivated function determines whether a tester has successfully * logged in to authorize testing functionality. * @details \b Inputs: testerLoggedIn * @details \b Outputs: none * @return TRUE if a tester has logged in from Dialin, FALSE if not *************************************************************************/ BOOL isTestingActivated( void ) { return testerLoggedIn; } /*********************************************************************//** * @brief * The setTesterStatusToLoggedOut function logs Dialin out due to too much * time since Dialin last checked in. * @details \b Inputs: none * @details \b Outputs: testerLoggedIn * @return none *************************************************************************/ void setTesterStatusToLoggedOut( void ) { testerLoggedIn = FALSE; } /*********************************************************************//** * @brief * The sendTestAckResponseMsg function constructs a simple response message * for a handled test message and queues it for transmit on the TD=>PC CAN * channel. * @details \b Inputs: none * @details \b Outputs: response message constructed and queued for transmit. * @param msgID ID of handled message that we are responding to * @param ack TRUE to ACK, FALSE to NAK * @return TRUE if response message successfully queued for transmit, FALSE if not *************************************************************************/ static BOOL sendTestAckResponseMsg( MSG_ID_T msgID, BOOL ack ) { BOOL result; MESSAGE_T msg; // Create a message record blankMessage( &msg ); msg.hdr.msgID = msgID; msg.hdr.payloadLen = sizeof( U08 ); msg.payload[ 0 ] = (U08)ack; // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_PC, ACK_NOT_REQUIRED ); return result; } /*********************************************************************//** * @brief * The handleUICheckIn function handles a Ui check in message. * @details \b Inputs: none * @details \b Outputs: none * @param message Pointer to the UI check-in message * @return TRUE if check-in successful, FALSE if not *************************************************************************/ BOOL handleUICheckIn( MESSAGE_T *message ) { return TRUE; // no specific handling required. } /*********************************************************************//** * @brief * The handleTesterLogInRequest function handles a Dialin request to login. * @details \b Inputs: none * @details \b Outputs: Dialin logged in if request is authenticated. * @param message Pointer to the Dialin login message * @return TRUE if login successful, FALSE if not *************************************************************************/ BOOL handleTesterLogInRequest( MESSAGE_T *message ) { // Verify pass code // TODO - placeholder - how do we want to authenticate tester? if ( ( 3 == message->hdr.payloadLen ) && ( 0x31 == message->payload[ 0 ] ) && ( 0x32 == message->payload[ 1 ] ) && ( 0x33 == message->payload[ 2 ] ) ) { testerLoggedIn = TRUE; checkInFromUI(); // Allow tasks to begin normal processing when tester has logged in // Set the dialin checkin time stamp until the first checkin message is received from dailin setDialinCheckInTimeStamp(); } else { testerLoggedIn = FALSE; } return testerLoggedIn; } /*********************************************************************//** * @brief * The testTDSoftwareResetRequest function handles a request to reset the * TD firmware processor. * @note If reset is successful, this function will not return. * @details \b Inputs: none * @details \b Outputs: TD processor soft reset if request is valid * @param message Pointer to the reset request message * @return FALSE if reset command rejected *************************************************************************/ BOOL testTDSoftwareResetRequest( MESSAGE_T *message ) { BOOL result = FALSE; // Verify payload length if ( 0 == message->hdr.payloadLen ) { // S/w reset of processor result = TRUE; // Reset will prevent this from getting transmitted though setSystemREG1_SYSECR( (0x2) << 14 ); // Reset processor } sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); return result; } /*********************************************************************//** * @brief * The testSetTestConfiguration function handles a request to set a * test configuration. * @details \b Inputs: none * @details \b Outputs: message handled * @param message a pointer to the message to handle * @return TRUE if command accepted, FALSE if rejected *************************************************************************/ BOOL testSetTestConfiguration( MESSAGE_T *message ) { BOOL result = FALSE; // Verify payload length if ( sizeof( TEST_CONFIG_PAYLOAD_T ) == message->hdr.payloadLen ) { TEST_CONFIG_PAYLOAD_T payload; // copy message payload to local variable memcpy( (U08*)&payload, &message->payload[0], sizeof( TEST_CONFIG_PAYLOAD_T ) ); // Verify given test configuration is valid if ( payload.config < NUM_OF_TEST_CONFIGS ) { result = TRUE; if ( FALSE == payload.reset ) { setTestConfig( (TEST_CONFIG_T)payload.config ); } else { resetTestConfig( (TEST_CONFIG_T)payload.config ); } } } return result; } /*********************************************************************//** * @brief * The testGetTestConfiguration function handles a request to get a * test configuration. * @details \b Inputs: none * @details \b Outputs: message handled * @param message a pointer to the message to handle * @return none *************************************************************************/ BOOL testGetTestConfiguration( MESSAGE_T *message ) { BOOL result = FALSE; // verify payload length if ( 0 == message->hdr.payloadLen ) { result = sendTestConfigStatusToDialin(); } return result; } /*********************************************************************//** * @brief * The testResetTestConfiguration function handles a request to reset all * test configurations. * @details \b Inputs: none * @details \b Outputs: message handled * @param message a pointer to the message to handle * @return none *************************************************************************/ BOOL testResetAllTestConfigurations( MESSAGE_T *message ) { BOOL result = FALSE; // verify payload length if ( 0 == message->hdr.payloadLen ) { result = resetAllTestConfigs(); } return result; } /**@}*/