/************************************************************************** * * Copyright (c) 2019-2019 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 SystemComm.c * * @date 10-Oct-2019 * @author S. Nash * * @brief SystemComm service module. Provides system message communication \n * functionality. Messages can be queued for transmission. Incoming messages \n * are processed. * **************************************************************************/ #include // for memcpy() #include "Common.h" #include "AlarmLamp.h" #include "BloodFlow.h" #include "Buttons.h" #include "MsgQueues.h" #include "WatchdogMgmt.h" #include "SystemCommMessages.h" #include "SystemComm.h" // ********** private definitions ********** #pragma pack(push,1) typedef struct { U08 confirmed; // 1 = confirmed, 0 = rejected/timed out } OFF_BUTTON_MESSAGE_FROM_UI_PAYLOAD_T; #pragma pack(pop) // ********** private data ********** static BOOL testerLoggedIn = FALSE; // ********** private function prototypes ********** static U32 serializeMessage( MESSAGE_T msg, U08 *data ); static BOOL sendTestAckResponseMsg( MSG_ID_T msgID, BOOL ack ); /************************************************************************* * @brief serializeMessage * The serializeMessage function serializes a given message into a given \n * array of bytes. A sync byte is inserted at the beginning of the message \n * and an 8-bit CRC is appended to the end of the message. The given array \n * must be large enough to hold the message + 1 sync byte and 1 CRC byte and \n * up to 7 CAN padding bytes. * @details * Inputs : none * Outputs : given data array populated with serialized message data. * @param msg : message to serialize * @param data : byte array to populate with message data * @return size (in bytes) of serialized message populated in given data array. *************************************************************************/ static U32 serializeMessage( MESSAGE_T msg, U08 *data ) { U32 msgSize = 0; U32 sizeMod, sizePad; U32 i; // prefix data with message sync byte data[msgSize++] = MESSAGE_SYNC_BYTE; // 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; // TODO - calculate 8-bit CRC data[msgSize++] = 0; // TODO - s/b 8-bit CRC when calc is available // pad with zero bytes to get length a multiple of CAN_MESSAGE_PAYLOAD_SIZE (8) sizeMod = msgSize % CAN_MESSAGE_PAYLOAD_SIZE; sizePad = ( sizeMod == 0 ? 0 : CAN_MESSAGE_PAYLOAD_SIZE - sizeMod ); for ( i = 0; i < sizePad; i++ ) { data[msgSize++] = 0; } return msgSize; } // *********************************************************************** // ********************* MSG_ID_OFF_BUTTON_PRESS ************************* // *********************************************************************** /************************************************************************* * @brief sendOffButtonMsgToUI * The sendOffButtonMsgToUI function constructs an off button msg to the UI \n * and queues the msg for transmit on the appropriate CAN channel. * @details * Inputs : none * Outputs : Off button msg constructed and queued. * @param promptUser : TRUE if UI should prompt user to confirm power off \n * request, FALSE if UI should cancel the prompt. * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL sendOffButtonMsgToUI( BOOL promptUser ) { BOOL result; MESSAGE_T msg; U32 msgSize; U08 data[sizeof(MESSAGE_WRAPPER_T) + 1 + CAN_MESSAGE_PAYLOAD_SIZE]; // must hold full (wrapped) message + sync + any CAN padding // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_OFF_BUTTON_PRESS; msg.hdr.payloadLen = 1; msg.payload[0] = (U08)promptUser; // serialize the message (w/ sync, CRC, and appropriate CAN padding) msgSize = serializeMessage( msg, data ); // add serialized message data to appropriate comm buffer result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_2_UI, data, msgSize ); return result; } /************************************************************************* * @brief handleOffButtonConfirmMsgFromUI * The handleOffButtonConfirmMsgFromUI function handles a response to an \n * off button message to the UI. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleOffButtonConfirmMsgFromUI( MESSAGE_T *message ) { OFF_BUTTON_MESSAGE_FROM_UI_PAYLOAD_T payload; memcpy( &payload, message->payload, sizeof(OFF_BUTTON_MESSAGE_FROM_UI_PAYLOAD_T) ); userConfirmOffButton( payload.confirmed ); } /************************************************************************* * @brief broadcastAlarmStatus * The broadcastAlarmStatus function constructs an alarm status msg to \n * be broadcast and queues the msg for transmit on the appropriate CAN channel. * @details * Inputs : none * Outputs : alarm status msg constructed and queued. * @param almStatus : alarm status record * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastAlarmStatus( COMP_ALARM_STATUS_T almStatus ) { BOOL result; MESSAGE_T msg; U32 msgSize; U08 data[sizeof(MESSAGE_WRAPPER_T) + 1 + CAN_MESSAGE_PAYLOAD_SIZE]; // must hold full (wrapped) message + sync + any CAN padding U08 *payloadPtr = msg.payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_ALARM_STATUS; msg.hdr.payloadLen = sizeof(COMP_ALARM_STATUS_T); memcpy( payloadPtr, &almStatus, sizeof(COMP_ALARM_STATUS_T) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) msgSize = serializeMessage( msg, data ); // add serialized message data to appropriate comm buffer result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_ALARM, data, msgSize ); return result; } /************************************************************************* * @brief broadcastAlarmTriggered * The broadcastAlarmTriggered function constructs an alarm triggered msg to \n * be broadcast and queues the msg for transmit on the appropriate CAN channel. * @details * Inputs : none * Outputs : alarm triggered msg constructed and queued. * @param alarm : ID of alarm triggered * @param almData1 : 1st data associated with alarm * @param almData2 : 2nd data associated with alarm * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastAlarmTriggered( ALARM_ID_T alarm, ALARM_DATA_T almData1, ALARM_DATA_T almData2 ) { BOOL result; MESSAGE_T msg; U32 msgSize; U08 data[sizeof(MESSAGE_WRAPPER_T) + 1 + CAN_MESSAGE_PAYLOAD_SIZE]; // must hold full (wrapped) message + sync + any CAN padding U08 *payloadPtr = msg.payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_ALARM_TRIGGERED; msg.hdr.payloadLen = sizeof(ALARM_ID_T) + sizeof(ALARM_DATA_T) + sizeof(ALARM_DATA_T); memcpy( payloadPtr, &alarm, sizeof(ALARM_ID_T) ); payloadPtr += sizeof(ALARM_ID_T); memcpy( payloadPtr, &almData1, sizeof(ALARM_DATA_T) ); payloadPtr += sizeof(ALARM_DATA_T); memcpy( payloadPtr, &almData2, sizeof(ALARM_DATA_T) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) msgSize = serializeMessage( msg, data ); // add serialized message data to appropriate comm buffer result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_ALARM, data, msgSize ); return result; } /************************************************************************* * @brief broadcastAlarmCleared * The broadcastAlarmCleared function constructs an alarm cleared msg to be \n * broadcast and queues the msg for transmit on the appropriate CAN channel. * @details * Inputs : none * Outputs : alarm cleared msg constructed and queued. * @param alarm : ID of alarm cleared * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastAlarmCleared( ALARM_ID_T alarm ) { BOOL result; MESSAGE_T msg; U32 msgSize; U08 data[sizeof(MESSAGE_WRAPPER_T) + 1 + CAN_MESSAGE_PAYLOAD_SIZE]; // must hold full (wrapped) message + sync + any CAN padding U08 *payloadPtr = msg.payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_ALARM_CLEARED; msg.hdr.payloadLen = sizeof(ALARM_ID_T); memcpy( payloadPtr, &alarm, sizeof(ALARM_ID_T) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) msgSize = serializeMessage( msg, data ); // add serialized message data to appropriate comm buffer result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_ALARM, data, msgSize ); return result; } /************************************************************************* * @brief broadcastBloodFlowData * The broadcastBloodFlowData function constructs a blood flow data msg to \n * be broadcast and queues the msg for transmit on the appropriate CAN channel. * @details * Inputs : none * Outputs : blood flow data msg constructed and queued. * @param flowStPt : Current set point for blood flow * @param measFlow : Latest measured blood flow * @param measSpd : Latest measured blood pump speed * @param measSpd : Latest measured blood pump motor current * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastBloodFlowData( U32 flowStPt, F32 measFlow, F32 measSpd, F32 measCurr ) { BOOL result; MESSAGE_T msg; U32 msgSize; U08 data[sizeof(MESSAGE_WRAPPER_T) + 1 + CAN_MESSAGE_PAYLOAD_SIZE]; // must hold full (wrapped) message + sync + any CAN padding U08 *payloadPtr = msg.payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_BLOOD_FLOW_DATA; msg.hdr.payloadLen = sizeof(U32) + sizeof(F32) + sizeof(F32) + sizeof(F32); memcpy( payloadPtr, &flowStPt, sizeof(U32) ); payloadPtr += sizeof(U32); memcpy( payloadPtr, &measFlow, sizeof(F32) ); payloadPtr += sizeof(F32); memcpy( payloadPtr, &measSpd, sizeof(F32) ); payloadPtr += sizeof(F32); memcpy( payloadPtr, &measCurr, sizeof(F32) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) msgSize = serializeMessage( msg, data ); // add serialized message data to appropriate comm buffer result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_BROADCAST, data, msgSize ); return result; } /************************************************************************* * @brief handleDGCheckIn * The handleDGCheckIn function handles a check-in from the DG. * @details * Inputs : none * Outputs : check in the DG with the SystemComm module. * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleDGCheckIn( MESSAGE_T *message ) { checkInFromDG(); } /************************************************************************* * @brief handleUICheckIn * The handleUICheckIn function handles a check-in from the UI. * @details * Inputs : none * Outputs : check in the UI with the SystemComm module. * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleUICheckIn( MESSAGE_T *message ) { checkInFromUI(); } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /************************************************************************* * @brief sendDebugData * The sendDebugData function sends debug data out to the PC port. * @details * Inputs : none * Outputs : PC serial port * @param dbgData : Pointer to debug data * @param len : # of bytes of debug data * @return TRUE if debug data was successfully queued for transmit, FALSE if not *************************************************************************/ BOOL sendDebugData( U08 *dbgData, U32 len ) { BOOL result; MESSAGE_T msg; U32 msgSize; U08 data[sizeof(MESSAGE_WRAPPER_T) + 1 + CAN_MESSAGE_PAYLOAD_SIZE]; // must hold full (wrapped) message + sync + any CAN padding // create a message record blankMessage( &msg ); msg.hdr.msgID = 2; msg.hdr.payloadLen = len; memcpy( msg.payload, dbgData, len ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) msgSize = serializeMessage( msg, data ); // add serialized message data to appropriate comm buffer result = addToCommBuffer( COMM_BUFFER_OUT_UART_PC, data, msgSize ); return result; } /************************************************************************* * @brief isTestingActivated * The isTestingActivated function determines whether a tester has successfully \n * logged in to activate testing functionality. * @details * Inputs : testerLoggedIn * Outputs : none * @param none * @return TRUE if a tester has logged in to activate testing, FALSE if not *************************************************************************/ BOOL isTestingActivated( void ) { return testerLoggedIn; } /************************************************************************* * @brief sendTestAckResponseMsg * The sendTestAckResponseMsg function constructs a simple response \n * message for a handled test message and queues it for transmit on the \n * appropriate UART channel. * @details * Inputs : none * Outputs : response message constructed and queued for transmit. * @param msgID : ID of handled message that we are responding to * @param ack : TRUE if test message was handled successfully, FALSE if not * @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; U32 msgSize; U08 data[PC_MESSAGE_PACKET_SIZE]; // create a message record blankMessage( &msg ); msg.hdr.msgID = msgID; msg.hdr.payloadLen = 1; msg.payload[0] = (U08)ack; // serialize the message (w/ sync, CRC, and appropriate CAN padding) msgSize = serializeMessage( msg, data ); // add serialized message data to appropriate comm buffer result = addToCommBuffer( COMM_BUFFER_OUT_CAN_PC, data, msgSize ); return result; } /************************************************************************* * @brief handleTesterLogInRequest * The handleTesterLogInRequest function handles a request to login as a \n * tester. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void 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; } else { testerLoggedIn = FALSE; } // respond to would be tester sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, testerLoggedIn ); } /************************************************************************* * @brief handleTestHDMessageRequest * The handleTestHDMessageRequest function handles a request to add an \n * HD message to the received message queue. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleTestHDMessageRequest( MESSAGE_T *message ) { MESSAGE_WRAPPER_T hdMessage; U32 msgLen = (U32)(message->hdr.payloadLen); U08 *msgBytes = (U08*)(&(hdMessage)); BOOL result; memcpy( msgBytes, message->payload, msgLen ); // add HD message to received message queue result = addToMsgQueue( MSG_Q_IN, &hdMessage ); // respond to request sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } /************************************************************************* * @brief handleTestOffButtonStateOverrideRequest * The handleTestOffButtonStateOverrideRequest function handles a request to \n * override the state of the off button. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_OVERRIDE_HANDLER_FUNC( BUTTON_STATE_T, handleTestOffButtonStateOverrideRequest, testSetOffButtonStateOverride, testResetOffButtonStateOverride ) /************************************************************************* * @brief handleTestStopButtonStateOverrideRequest * The handleTestStopButtonStateOverrideRequest function handles a request to \n * override the stop button state. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_OVERRIDE_HANDLER_FUNC( BUTTON_STATE_T, handleTestStopButtonStateOverrideRequest, testSetStopButtonStateOverride, testResetStopButtonStateOverride ) /************************************************************************* * @brief handleTestAlarmLampPatternOverrideRequest * The handleTestAlarmLampPatternOverrideRequest function handles a request to \n * override the alarm lamp pattern. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_OVERRIDE_HANDLER_FUNC( LAMP_PATTERN_T, handleTestAlarmLampPatternOverrideRequest, testSetCurrentLampPatternOverride, testResetCurrentLampPatternOverride ) /************************************************************************* * @brief handleTestWatchdogCheckInStateOverrideRequest * The handleTestWatchdogCheckInStateOverrideRequest function handles a \n * request to override the check-in status of a given task. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_ARRAY_OVERRIDE_HANDLER_FUNC( BOOL, handleTestWatchdogCheckInStateOverrideRequest, testSetWatchdogTaskCheckInOverride, testResetWatchdogTaskCheckInOverride ) /************************************************************************* * @brief handleTestAlarmStateOverrideRequest * The handleTestAlarmStateOverrideRequest function handles a request to \n * override the active status of a given alarm. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_ARRAY_OVERRIDE_HANDLER_FUNC( BOOL, handleTestAlarmStateOverrideRequest, testSetAlarmStateOverride, testResetAlarmStateOverride ) /************************************************************************* * @brief handleTestAlarmTimeOverrideRequest * The handleTestAlarmTimeOverrideRequest function handles a request to \n * override the time since activation of a given alarm. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_ARRAY_OVERRIDE_HANDLER_FUNC( U32, handleTestAlarmTimeOverrideRequest, testSetAlarmStartOverride, testResetAlarmStartOverride ) /************************************************************************* * @brief handleTestAlarmStatusBroadcastIntervalOverrideRequest * The handleTestAlarmStatusBroadcastIntervalOverrideRequest function handles a request to \n * override the broadcast interval for alarm status. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_OVERRIDE_HANDLER_FUNC( U32, handleTestAlarmStatusBroadcastIntervalOverrideRequest, testSetAlarmStatusPublishIntervalOverride, testResetAlarmStatusPublishIntervalOverride ) /************************************************************************* * @brief handleTestBloodFlowSetPointOverrideRequest * The handleTestBloodFlowSetPointOverrideRequest function handles a request to \n * override the set point for the blood flow rate (mL/min). * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_OVERRIDE_HANDLER_FUNC( U32, handleTestBloodFlowSetPointOverrideRequest, testSetTargetBloodFlowRateOverride, testResetTargetBloodFlowRateOverride ) /************************************************************************* * @brief handleTestBloodFlowMeasuredOverrideRequest * The handleTestBloodFlowMeasuredOverrideRequest function handles a request to \n * override the measured blood flow rate (mL/min). * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_OVERRIDE_HANDLER_FUNC( F32, handleTestBloodFlowMeasuredOverrideRequest, testSetMeasuredBloodFlowRateOverride, testResetMeasuredBloodFlowRateOverride ) /************************************************************************* * @brief handleTestBloodPumpMeasuredSpeedOverrideRequest * The handleTestBloodPumpMeasuredSpeedOverrideRequest function handles a request to \n * override the measured blood pump speed (RPM). * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_OVERRIDE_HANDLER_FUNC( F32, handleTestBloodPumpMeasuredSpeedOverrideRequest, testSetMeasuredBloodPumpSpeedOverride, testResetMeasuredBloodPumpSpeedOverride ) /************************************************************************* * @brief handleTestBloodPumpMeasuredCurrentOverrideRequest * The handleTestBloodPumpMeasuredCurrentOverrideRequest function handles a request to \n * override the measured blood pump current (mA). * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_OVERRIDE_HANDLER_FUNC( F32, handleTestBloodPumpMeasuredCurrentOverrideRequest, testSetMeasuredBloodPumpCurrentOverride, testResetMeasuredBloodPumpCurrentOverride ) /************************************************************************* * @brief handleTestBloodFlowBroadcastIntervalOverrideRequest * The handleTestBloodFlowBroadcastIntervalOverrideRequest function handles a request to \n * override the broadcast interval for blood flow data. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_OVERRIDE_HANDLER_FUNC( U32, handleTestBloodFlowBroadcastIntervalOverrideRequest, testSetBloodFlowDataPublishIntervalOverride, testResetBloodFlowDataPublishIntervalOverride )