/************************************************************************** * * 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 "Buttons.h" #include "MsgQueues.h" #include "WatchdogMgmt.h" #include "SystemCommMessages.h" #include "SystemComm.h" #include "CPLD.h" #include "OperationModes.h" // ********** private definitions ********** #pragma pack(push,1) typedef struct { U08 confirmed; // 1 = confirmed, 0 = rejected/timed out } OFF_BUTTON_MESSAGE_FROM_UI_CARGO_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 cargo (only used bytes per cargoLen field) memcpy( &data[msgSize], &(msg.cargo), msg.hdr.cargoLen ); msgSize += msg.hdr.cargoLen; // 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_CARGO_SIZE (8) sizeMod = msgSize % CAN_MESSAGE_CARGO_SIZE; sizePad = ( sizeMod == 0 ? 0 : CAN_MESSAGE_CARGO_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 none * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL sendOffButtonMsgToUI( void ) { BOOL result; MESSAGE_T msg; U32 msgSize; U08 data[sizeof(MESSAGE_WRAPPER_T)+1+CAN_MESSAGE_CARGO_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.cargoLen = 0; // 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_DG_2_HD, 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_CARGO_T cargo; memcpy( &cargo, message->cargo, sizeof(OFF_BUTTON_MESSAGE_FROM_UI_CARGO_T) ); userConfirmOffButton( cargo.confirmed ); } /************************************************************************* * @brief handleDGFillStartStopMessages * The handleDGFillStartStopMessages function handles a response to the * start and stop messages thru the CAN bus. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleDGFillStartStopMessages( MESSAGE_T *message ) { # define STOP 0 # define START 1 #ifdef RM46_EVAL_BOARD_TARGET toggleUserLED(); #endif // If we start therapy if (message->cargo[0] == START && getCurrentOperationMode() == MODE_STAN) { requestNewOperationMode(MODE_FILL); sendTestAckResponseMsg((MSG_ID_T)message->hdr.msgID, TRUE); } // We can only stop fill if we are in fill mode else if (message->cargo[0] == STOP && getCurrentOperationMode() == MODE_FILL) { requestNewOperationMode(MODE_STAN); sendTestAckResponseMsg((MSG_ID_T)message->hdr.msgID, TRUE); } else { // TODO: Print to log that either start was called when t he machine was not // in standby or that stop was called when the machine was not in fill sendTestAckResponseMsg((MSG_ID_T)message->hdr.msgID, FALSE); } } /************************************************************************* * 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_CARGO_SIZE]; // must hold full (wrapped) message + sync + any CAN padding // create a message record blankMessage( &msg ); msg.hdr.msgID = 2; msg.hdr.cargoLen = len; memcpy( msg.cargo, 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 ) { //TODO: Disable all login related functions return TRUE; } /************************************************************************* * @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.cargoLen = 1; msg.cargo[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_DG_2_HD, 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.cargoLen ) && ( 0x31 == message->cargo[0] ) && ( 0x32 == message->cargo[1] ) && ( 0x33 == message->cargo[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.cargoLen); U08 *msgBytes = (U08*)(&(hdMessage)); BOOL result; memcpy( msgBytes, message->cargo, 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 *************************************************************************/ void handleTestOffButtonStateOverrideRequest( MESSAGE_T *message ) { TEST_OVERRIDE_CARGO_T cargo; BOOL result = FALSE; // verify cargo length if ( sizeof(TEST_OVERRIDE_CARGO_T) == message->hdr.cargoLen ) { memcpy( &cargo, message->cargo, sizeof(TEST_OVERRIDE_CARGO_T) ); if ( FALSE == cargo.reset ) { result = testSetOffButtonStateOverride( (BUTTON_STATE_T)(cargo.state) ); } else { result = testResetOffButtonStateOverride(); } } // respond to request sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } /************************************************************************* * @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 *************************************************************************/ void handleTestStopButtonStateOverrideRequest( MESSAGE_T *message ) { TEST_OVERRIDE_CARGO_T cargo; BOOL result = FALSE; // verify cargo length if ( sizeof(TEST_OVERRIDE_CARGO_T) == message->hdr.cargoLen ) { memcpy( &cargo, message->cargo, sizeof(TEST_OVERRIDE_CARGO_T) ); if ( FALSE == cargo.reset ) { result = testSetStopButtonStateOverride( (BUTTON_STATE_T)(cargo.state) ); } else { result = testResetStopButtonStateOverride(); } } // respond to request sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } /************************************************************************* * @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 *************************************************************************/ void handleTestAlarmLampPatternOverrideRequest( MESSAGE_T *message ) { TEST_OVERRIDE_CARGO_T cargo; BOOL result = FALSE; // verify cargo length if ( sizeof(TEST_OVERRIDE_CARGO_T) == message->hdr.cargoLen ) { memcpy( &cargo, message->cargo, sizeof(TEST_OVERRIDE_CARGO_T) ); if ( FALSE == cargo.reset ) { result = testSetCurrentLampPatternOverride( (LAMP_PATTERN_T)(cargo.state) ); } else { result = testResetCurrentLampPatternOverride(); } } // respond to request sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } /************************************************************************* * @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 *************************************************************************/ void handleTestWatchdogCheckInStateOverrideRequest( MESSAGE_T *message ) { TEST_OVERRIDE_ARRAY_CARGO_T cargo; BOOL result = FALSE; // verify cargo length if ( sizeof(TEST_OVERRIDE_ARRAY_CARGO_T) == message->hdr.cargoLen ) { memcpy( &cargo, message->cargo, sizeof(TEST_OVERRIDE_ARRAY_CARGO_T) ); if ( FALSE == cargo.reset ) { result = testSetWatchdogTaskCheckInOverride( cargo.index, (BOOL)(cargo.state) ); } else { result = testResetWatchdogTaskCheckInOverride( cargo.index ); } } // respond to request sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); }