/************************************************************************** * * Copyright (c) 2019-2021 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 * * @author (last) Sean Nash * @date (last) 12-Nov-2021 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 * ***************************************************************************/ #include // For memcpy() #include "can.h" #include "sci.h" #include "sys_dma.h" #include "Comm.h" #include "Interrupts.h" #include "OperationModes.h" #include "SystemComm.h" #include "SystemCommMessages.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup SystemComm * @{ */ // ********** private definitions ********** #define NUM_OF_CAN_OUT_BUFFERS 5 ///< Number of CAN buffers for transmit #define NUM_OF_CAN_IN_BUFFERS 7 ///< Number of CAN buffers for receiving #define NUM_OF_MSG_IN_BUFFERS 7 ///< Number of Msg buffers for receiving #define CAN_XMIT_PACKET_TIMEOUT_MS 200 ///< If transmitted CAN frame does not cause a transmit complete interrupt within this time, re-send or move on #define MAX_XMIT_RETRIES 5 ///< Maximum number of retries on no transmit complete interrupt timeout #define UI_COMM_TIMEOUT_IN_MS 5000 ///< UI has not checked in for this much time #define DG_COMM_TIMEOUT_IN_MS 2000 ///< DG has not checked in for this much time #define MAX_COMM_CRC_FAILURES 5 ///< Maximum number of CRC errors within window period before alarm #define MAX_COMM_CRC_FAILURE_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) ///< CRC error window #define MSG_NOT_ACKED_TIMEOUT_MS 150 ///< Maximum time for a Denali message that requires ACK to be ACK'd #define MSG_NOT_ACKED_TIMEOUT_MS_INIT 5000 ///< Maximum time for a Denali message that requires ACK to be ACK'd on the INIT state for the first (UI version request) message of the POST #define MSG_NOT_ACKED_MAX_RETRIES 3 ///< Maximum number of times a message that requires ACK that was not ACK'd can be re-sent before alarm #define PENDING_ACK_LIST_SIZE 25 ///< Maximum number of Denali messages that can be pending ACK at any given time #pragma pack(push, 1) /// Record for transmitted message that is pending acknowledgement from receiver. typedef struct { BOOL used; U16 seqNo; U16 retries; U32 timeStamp; COMM_BUFFER_T channel; U32 msgSize; U08 msg[ MAX_ACK_MSG_SIZE ]; } PENDING_ACK_RECORD_T; #pragma pack(pop) // ********** private data ********** /// Array of out-going CAN buffers. const COMM_BUFFER_T CAN_OUT_BUFFERS[ NUM_OF_CAN_OUT_BUFFERS ] = { COMM_BUFFER_OUT_CAN_HD_ALARM, COMM_BUFFER_OUT_CAN_HD_2_DG, COMM_BUFFER_OUT_CAN_HD_2_UI, COMM_BUFFER_OUT_CAN_HD_BROADCAST, COMM_BUFFER_OUT_CAN_PC }; /// Array of in-coming CAN buffers. const COMM_BUFFER_T MSG_IN_BUFFERS[ NUM_OF_MSG_IN_BUFFERS ] = { COMM_BUFFER_IN_CAN_DG_ALARM, COMM_BUFFER_IN_CAN_UI_ALARM, COMM_BUFFER_IN_CAN_DG_2_HD, COMM_BUFFER_IN_CAN_DG_BROADCAST, COMM_BUFFER_IN_CAN_UI_2_HD, COMM_BUFFER_IN_CAN_UI_BROADCAST, COMM_BUFFER_IN_CAN_PC, }; static U08 lastCANPacketSent[ CAN_MESSAGE_PAYLOAD_SIZE ]; ///< Keep last packet sent on CAN bus in case we need to re-send. static CAN_MESSAGE_BOX_T lastCANPacketSentChannel = (CAN_MESSAGE_BOX_T)0; ///< Keep channel last packet was sent on CAN bus in case we need to re-send. static U32 lastCANPacketSentTimeStamp = 0; ///< Keep time last packet sent on CAN bus so we can timeout on transmission attempt. static volatile PENDING_ACK_RECORD_T pendingAckList[ PENDING_ACK_LIST_SIZE ]; ///< List of outgoing messages that are awaiting an ACK static volatile BOOL hdIsOnlyCANNode = TRUE; ///< Flag indicating whether HD is alone on CAN bus. static U32 canXmitRetryCtr = 0; ///< Counter for CAN transmit retries. static volatile BOOL dgIsCommunicating = FALSE; ///< Has DG sent a message since last check static U32 timeOfLastDGCheckIn = 0; ///< Last time DG checked in static volatile BOOL uiIsCommunicating = FALSE; ///< Has UI sent a message since last check static U32 timeOfLastUICheckIn = 0; ///< Last time UI checked in static volatile BOOL uiDidCommunicate = FALSE; ///< Has UI every sent a message #ifdef EMC_TEST_BUILD static U32 badCANCount; // Test code in support of EMC testing #endif // ********** private function prototypes ********** static void clearCANXmitBuffers( void ); static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ); static U32 transmitNextCANPacket( void ); static void processIncomingData( void ); static S32 parseMessageFromBuffer( U08 *data, U32 len ); static void consumeBufferPaddingBeforeSync( COMM_BUFFER_T buffer ); static void processReceivedMessages( void ); static void processReceivedMessage( MESSAGE_T *message ); static void checkForCommTimeouts( void ); static void checkTooManyBadMsgCRCs( void ); static BOOL matchACKtoPendingACKList( S16 seqNo ); static void checkPendingACKList( void ); /*********************************************************************//** * @brief * The initSystemComm function initializes the SystemComm module. * @details Inputs: none * @details Outputs: SystemComm module initialized. * @return none *************************************************************************/ void initSystemComm( void ) { U32 i; // Initialize bad message CRC time windowed count initTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC, MAX_COMM_CRC_FAILURES, MAX_COMM_CRC_FAILURE_WINDOW_MS ); // Initialize pending ACK list for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) { pendingAckList[ i ].used = FALSE; } } /*********************************************************************//** * @brief * The checkInFromDG function checks in the DG with the HD - indicating that * the DG is communicating. * @details Inputs: none * @details Outputs: dgIsCommunicating * @return none *************************************************************************/ void checkInFromDG( void ) { dgIsCommunicating = TRUE; timeOfLastDGCheckIn = getMSTimerCount(); if ( TRUE == isAlarmActive( ALARM_ID_DG_COMM_TIMEOUT ) ) { clearAlarmCondition( ALARM_ID_DG_COMM_TIMEOUT ); } } /*********************************************************************//** * @brief * The checkInFromUI function checks in the UI with the HD - indicating that * the UI is communicating. * @details Inputs: none * @details Outputs: uiIsCommunicating * @return none *************************************************************************/ void checkInFromUI( void ) { if ( FALSE == uiDidCommunicate ) { // Start DG check-in timer when UI first communicates timeOfLastDGCheckIn = getMSTimerCount(); } uiIsCommunicating = TRUE; timeOfLastUICheckIn = getMSTimerCount(); uiDidCommunicate = TRUE; } /*********************************************************************//** * @brief * The isDGCommunicating function determines whether the DG is communicating * with the HD. * @details Inputs: dgIsCommunicating * @details Outputs: none * @return TRUE if DG has checked in since last call, FALSE if not *************************************************************************/ BOOL isDGCommunicating( void ) { return dgIsCommunicating; } /*********************************************************************//** * @brief * The isUICommunicating function determines whether the UI is communicating * with the HD. * @details Inputs: uiIsCommunicating * @details Outputs: none * @return TRUE if UI has checked in since last call, FALSE if not *************************************************************************/ BOOL isUICommunicating( void ) { BOOL result = uiIsCommunicating; uiIsCommunicating = FALSE; return result; } /*********************************************************************//** * @brief * The uiCommunicated function determines whether the UI has communicated. * @details Inputs: uiDidCommunicate * @details Outputs: none * @return TRUE if UI has communicated since power up, FALSE if not *************************************************************************/ BOOL uiCommunicated( void ) { return uiDidCommunicate; } /*********************************************************************//** * @brief * The isHDOnlyCANNode function determines whether the HD is the only node * currently on the CAN bus. * @details Inputs: hdIsOnlyCANNode * @details Outputs: none * @return TRUE if HD is only node on CAN bus, FALSE if not *************************************************************************/ BOOL isHDOnlyCANNode( void ) { return hdIsOnlyCANNode; } /*********************************************************************//** * @brief * The execSystemCommRx function manages received data from other sub-systems. * @details Inputs: none * @details Outputs: Incoming messages parsed and processed. * @return none *************************************************************************/ void execSystemCommRx( void ) { // Parse messages from comm buffers and queue them processIncomingData(); // Process received messages in the queue processReceivedMessages(); // Check for sub-system comm timeouts checkForCommTimeouts(); // Check ACK list for messages that need to be re-sent because they have not been ACK'd checkPendingACKList(); } /*********************************************************************//** * @brief * The execSystemCommTx function manages data to be transmitted to other * sub-systems. * @details Inputs: none * @details Outputs: Outgoing messages transmitted. * @return none *************************************************************************/ void execSystemCommTx( void ) { // Do not transmit if no other nodes on CAN bus if ( FALSE == hdIsOnlyCANNode ) { // If CAN transmitter is idle, start transmitting any pending packets if ( FALSE == isCAN1TransmitInProgress() ) { transmitNextCANPacket(); } else { // Generally, transmitter should not be busy at time of this function call - check timeout just in case so we do not get stuck waiting forever if ( TRUE == didTimeout( lastCANPacketSentTimeStamp, CAN_XMIT_PACKET_TIMEOUT_MS ) ) { // Assume last packet was not successfully transmitted. Re-send last packet. if ( ++canXmitRetryCtr <= MAX_XMIT_RETRIES ) { // Ensure we have a previous CAN packet/channel to resend - canTransmit() channel param MUST be valid if ( ( lastCANPacketSentChannel > COMM_BUFFER_NOT_USED ) && ( lastCANPacketSentChannel <= COMM_BUFFER_LAST_CAN_BUFFER ) ) { canTransmit( canREG1, lastCANPacketSentChannel, lastCANPacketSent ); } } // We must be only node on CAN bus - nobody is ACKing our transmitted frames else { hdIsOnlyCANNode = TRUE; // Set only CAN node flag canXmitRetryCtr = MAX_XMIT_RETRIES; signalCANXmitsCompleted(); // Clear pending xmit flag clearCANXmitBuffers(); // Clear xmit buffers - nothing is going out right now } } } } } /*********************************************************************//** * @brief * The handleCANMsgInterrupt function handles a CAN message interrupt. * This may have occurred because a CAN packet transmission has completed * or because a CAN packet has been received. The appropriate handler is * called. * @details Inputs: none * @details Outputs: message interrupt handled * @param srcCANBox which CAN message box triggered this interrupt * @return none *************************************************************************/ void handleCANMsgInterrupt( CAN_MESSAGE_BOX_T srcCANBox ) { // Message interrupt is for a transmit message box? if ( TRUE == isCANBoxForXmit( srcCANBox ) ) { U32 bytesXmitted; bytesXmitted = transmitNextCANPacket(); // If nothing more to send, signal that transmitter is available if ( 0 == bytesXmitted ) { signalCANXmitsCompleted(); } } else if ( TRUE == isCANBoxForRecv( srcCANBox ) ) { U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; // Get CAN packet received on given CAN message box if ( FALSE != canIsRxMessageArrived( canREG1, srcCANBox ) ) { U32 result = canGetData( canREG1, srcCANBox, data ); // If packet retrieved, add to buffer if ( result != 0 ) { // Add CAN packet to appropriate comm buffer based on the message box it came in on (s/b same #) addToCommBuffer( srcCANBox, data, CAN_MESSAGE_PAYLOAD_SIZE ); } } } else { // Should not get here - not an active message box SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_CAN_MESSAGE_BOX, srcCANBox ) } } /*********************************************************************//** * @brief * The isCANBoxForXmit function determines whether a given CAN message box * is configured for transmit. * @details Inputs: CAN_OUT_BUFFERS[] * @details Outputs: none * @param srcCANBox which CAN message box to check * @return TRUE if the given CAN message box is configured for transmit, FALSE if not. *************************************************************************/ BOOL isCANBoxForXmit( CAN_MESSAGE_BOX_T srcCANBox ) { BOOL result = FALSE; U32 i; for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) { if ( CAN_OUT_BUFFERS[ i ] == srcCANBox ) { result = TRUE; break; } } return result; } /*********************************************************************//** * @brief * The isCANBoxForRecv function determines whether a given CAN message box * is configured for receiving. * @details Inputs: MSG_IN_BUFFERS[] * @details Outputs: none * @param srcCANBox which CAN message box to check * @return TRUE if the given CAN message box is configured for receiving, FALSE if not. *************************************************************************/ BOOL isCANBoxForRecv( CAN_MESSAGE_BOX_T srcCANBox ) { BOOL result = FALSE; U32 i; for ( i = 0; i < NUM_OF_CAN_IN_BUFFERS; i++ ) { if ( MSG_IN_BUFFERS[ i ] == srcCANBox ) { result = TRUE; break; } } return result; } /*********************************************************************//** * @brief * The clearCANXmitBuffers function clears all CAN transmit buffers. * @details Inputs: CAN_OUT_BUFFERS[] * @details Outputs: CAN transmit buffers cleared. * @return none *************************************************************************/ static void clearCANXmitBuffers( void ) { U32 i; for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) { clearBuffer( CAN_OUT_BUFFERS[ i ] ); } } /************************************************************************* ********************** TRANSMIT SUPPORT FUNCTIONS ************************ *************************************************************************/ /*********************************************************************//** * @brief * The findNextHighestPriorityCANPacketToTransmit function gets the next * 8 byte packet and initiates a CAN transmit on the appropriate CAN channel. * @details Inputs: Output CAN Comm Buffer(s) * @details Outputs: none * @return buffer with highest priority CAN packet to transmit, * COMM_BUFFER_NOT_USED if not CAN packets pending transmit found *************************************************************************/ static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ) { COMM_BUFFER_T result = COMM_BUFFER_NOT_USED; U32 i; // Search for next priority CAN packet to transmit for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) { if ( numberOfBytesInCommBuffer( CAN_OUT_BUFFERS[ i ] ) >= CAN_MESSAGE_PAYLOAD_SIZE ) { result = CAN_OUT_BUFFERS[ i ]; break; // Found highest priority packet to transmit - we are done } } return result; } /*********************************************************************//** * @brief * The transmitNextCANPacket function gets the next 8 byte packet and initiates * a CAN transmit on the appropriate CAN channel. * @details Inputs: Output CAN Comm Buffers * @details Outputs: CAN packet transmit initiated. * @return number of bytes transmitted *************************************************************************/ static U32 transmitNextCANPacket( void ) { U32 result = 0; COMM_BUFFER_T buffer = findNextHighestPriorityCANPacketToTransmit(); // If a buffer is found with a packet to transmit, get packet from buffer and transmit it if ( buffer != COMM_BUFFER_NOT_USED ) { U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; U32 dataSize = getFromCommBuffer( buffer, data, CAN_MESSAGE_PAYLOAD_SIZE ); CAN_MESSAGE_BOX_T mBox = buffer; // CAN message boxes and comm buffers are aligned // If there is another CAN packet to send, send it if ( dataSize == CAN_MESSAGE_PAYLOAD_SIZE ) { // We are transmitting another packet - signal transmitter is busy signalCANXmitsInitiated(); // Remember packet data being transmitted here in case transmission fails and we need to re-send memcpy( lastCANPacketSent, data, CAN_MESSAGE_PAYLOAD_SIZE ); lastCANPacketSentChannel = mBox; lastCANPacketSentTimeStamp = getMSTimerCount(); if ( 0 != canTransmit( canREG1, mBox, data ) ) { result = CAN_MESSAGE_PAYLOAD_SIZE; } else { signalCANXmitsCompleted(); SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_SYSTEM_CMMM_CAN_TRANSMIT_REJECTED, (U32)mBox ) } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_SYSTEM_COMM_INVALID_FRAME_SIZE, ((U32)buffer << 16) | dataSize ) } } return result; } /************************************************************************* ********************** RECEIVE SUPPORT FUNCTIONS ************************* *************************************************************************/ /*********************************************************************//** * @brief * The processIncomingData function parses out messages from the Input * Comm Buffers and adds them to the Received Message Queue. * @details Inputs: Input Comm Buffers * @details Outputs: Parsed message(s) added to Received Message Queue * @return none *************************************************************************/ static void processIncomingData( void ) { U08 data[ 512 ]; // Message work space U32 i; BOOL badCRCDetected = FALSE; // Queue any received messages for ( i = 0; i < NUM_OF_MSG_IN_BUFFERS; i++ ) { BOOL messagesInBuffer = TRUE; // Assume true at first to get into while loop while ( TRUE == messagesInBuffer ) { U32 numOfBytesInBuffer; // Assume false so we do not get stuck in loop. Set to true only if we find another complete message in buffer messagesInBuffer = FALSE; // Since messages can have 8-byte alignment padding left unconsumed by last get, get padding out of buffer consumeBufferPaddingBeforeSync( MSG_IN_BUFFERS[ i ] ); // Do we have enough bytes in buffer for smallest message? numOfBytesInBuffer = numberOfBytesInCommBuffer( MSG_IN_BUFFERS[ i ] ); if ( numOfBytesInBuffer >= MESSAGE_OVERHEAD_SIZE ) { // Peek at minimum of all bytes available or max message size (+1 for sync byte) U32 bytesPeeked = peekFromCommBuffer( MSG_IN_BUFFERS[ i ], data, MIN( numOfBytesInBuffer, sizeof( MESSAGE_WRAPPER_T ) + 1 ) ); S32 msgSize = parseMessageFromBuffer( data, bytesPeeked ); hdIsOnlyCANNode = FALSE; // Since we are getting a message, this indicates we are not the only node on the CAN bus canXmitRetryCtr = 0; if ( msgSize > 0 ) // Valid, complete message found? { MESSAGE_WRAPPER_T rcvMsg; U08 *dataPtr = data+1; // Skip over sync byte // Consume message (+sync byte) msgSize = getFromCommBuffer( MSG_IN_BUFFERS[ i ], data, msgSize + 1 ); // Convert received message data to a message and add to message queue messagesInBuffer = TRUE; // Keep processing this buffer // Blank the new message record blankMessageInWrapper( &rcvMsg ); // Copy message header portion of message data to the new message memcpy( &(rcvMsg.msg.hdr), dataPtr, sizeof(MESSAGE_HEADER_T) ); dataPtr += sizeof(MESSAGE_HEADER_T); // Copy message payload portion of message data to the new message memcpy( &(rcvMsg.msg.payload), dataPtr, rcvMsg.msg.hdr.payloadLen ); dataPtr += rcvMsg.msg.hdr.payloadLen; // Copy CRC portion of message data to the new message rcvMsg.crc = *dataPtr; // Add new message to queue for later processing addToMsgQueue( MSG_Q_IN, &rcvMsg ); // If message from DG broadcast channel, update DG comm status if ( COMM_BUFFER_IN_CAN_DG_BROADCAST == MSG_IN_BUFFERS[ i ] ) { dgIsCommunicating = TRUE; timeOfLastDGCheckIn = getMSTimerCount(); } } else if ( -1 == msgSize ) // Candidate message with bad CRC found? { badCRCDetected = TRUE; #ifdef EMC_TEST_BUILD badCANCount++; broadcastCANErrorCount( badCANCount ); #endif getFromCommBuffer( MSG_IN_BUFFERS[ i ], data, 1 ); // Consume sync byte so we can re-sync messagesInBuffer = TRUE; // Keep processing this buffer } // Looks like there is a complete message in the comm buffer } // Enough data left in comm buffer to possibly be a complete message } // While loop to get all complete messages for each comm buffer } // For loop to check all comm buffers for messages // If any bad CRCs detected, see if too many if ( TRUE == badCRCDetected ) { checkTooManyBadMsgCRCs(); } } /*********************************************************************//** * @brief * The consumeBufferPaddingBeforeSync function removes any bytes in a given * buffer that lie before a sync byte. * @details Inputs: none * @details Outputs: Any padding at front of buffer is consumed. * @param buffer the comm buffer to process * @return none *************************************************************************/ static void consumeBufferPaddingBeforeSync( COMM_BUFFER_T buffer ) { U08 data; U32 numOfBytesInBuffer = numberOfBytesInCommBuffer( buffer ); // Consume bytes out of buffer 1 at a time until we find the sync byte or it is empty while ( numOfBytesInBuffer > 0 ) { peekFromCommBuffer( buffer, &data, 1 ); if ( MESSAGE_SYNC_BYTE == data ) { break; // We found a sync - we are done } else // Not a sync byte, so consume it { getFromCommBuffer( buffer, &data, 1 ); numOfBytesInBuffer = numberOfBytesInCommBuffer( buffer ); } } } /*********************************************************************//** * @brief * The parseMessageFromBuffer function looks for a complete message in a * given buffer. If a message is found, its size is returned. * @details Inputs: none * @details Outputs: none * @param data pointer to byte array to search for a message * @param len number of bytes in the data to search * @return size of message if found, zero if no complete message found, * -1 if message found but CRC fails. *************************************************************************/ static S32 parseMessageFromBuffer( U08 *data, U32 len ) { U32 i; U32 payloadSize; U32 msgSize; S32 result = 0; for ( i = 0; i < len; i++ ) { // Find sync byte if ( MESSAGE_SYNC_BYTE == data[ i ] ) { U32 pos = i + 1; // Skip past sync byte implemented U32 remSize = len - pos; // If a minimum sized msg would fit in remaining, continue if ( remSize >= MESSAGE_OVERHEAD_SIZE ) { payloadSize = data[ pos + sizeof(MESSAGE_HEADER_T) - sizeof(U08) ]; msgSize = MESSAGE_OVERHEAD_SIZE + payloadSize; // We now know the size of the message - we can now know if full message is contained in buffer if ( msgSize <= remSize ) { // Check CRC to make sure it is a valid message if ( data[i+msgSize] == crc8( &data[pos], msgSize - 1 ) ) { result = msgSize; // We found a complete, valid message of this size } else // CRC failed { result = -1; // We found a complete, invalid message } } } break; } } return result; } /*********************************************************************//** * @brief * The processReceivedMessages function processes any messages in the * received message queues. * @details Inputs: Received Message Queues * @details Outputs: Message(s) processed. * @return none *************************************************************************/ static void processReceivedMessages( void ) { BOOL isThereMsgRcvd = TRUE; // Assume TRUE at first to get into while loop MESSAGE_WRAPPER_T message; while ( TRUE == isThereMsgRcvd ) { // See if any messages received isThereMsgRcvd = getFromMsgQueue( MSG_Q_IN, &message ); if ( TRUE == isThereMsgRcvd ) { // CRC should be good because we checked it during parsing before adding to queue - but check it again for good measure if ( message.crc == crc8( (U08*)(&message), sizeof(MESSAGE_HEADER_T) + message.msg.hdr.payloadLen ) ) { // If ACK, mark pending message ACK'd if ( MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK == message.msg.hdr.msgID ) { matchACKtoPendingACKList( message.msg.hdr.seqNo ); } else { // If received message requires ACK, queue one up if ( message.msg.hdr.seqNo < 0 ) { sendACKMsg( &message.msg ); } // Process the received message processReceivedMessage( &message.msg ); } } else // CRC failed { #ifdef EMC_TEST_BUILD badCANCount++; broadcastCANErrorCount( badCANCount ); #endif checkTooManyBadMsgCRCs(); } } } } /*********************************************************************//** * @brief * The checkForCommTimeouts function checks for sub-system communication * timeout errors. * @details Inputs: timeOfLastDGCheckIn, timeOfLastUICheckIn * @details Outputs: possibly a comm t/o alarm * @return none *************************************************************************/ static void checkForCommTimeouts( void ) { if ( TRUE == uiDidCommunicate ) { if ( TRUE == didTimeout( timeOfLastUICheckIn, UI_COMM_TIMEOUT_IN_MS ) ) { #ifndef DISABLE_UI_COMM_TO_ALARM activateAlarmNoData( ALARM_ID_UI_COMM_TIMEOUT ); #endif } if ( TRUE == didTimeout( timeOfLastDGCheckIn, DG_COMM_TIMEOUT_IN_MS ) ) { #ifndef RUN_WITHOUT_DG activateAlarmNoData( ALARM_ID_DG_COMM_TIMEOUT ); dgIsCommunicating = FALSE; #endif } } } /*********************************************************************//** * @brief * The checkTooManyBadMsgCRCs function checks for too many bad message CRCs * within a set period of time. Assumed function is being called when a new * bad CRC is detected so a new bad CRC will be added to the list. * @details Inputs: badCRCTimeStamps[], badCRCListIdx, badCRCListCount * @details Outputs: possibly a "too many bad CRCs" alarm * @return none *************************************************************************/ static void checkTooManyBadMsgCRCs( void ) { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC ) ) { #ifndef DISABLE_CRC_ERROR SET_ALARM_WITH_1_U32_DATA( ALARM_ID_COMM_TOO_MANY_BAD_CRCS, (U32)ALARM_SOURCE_HD ); #endif } } /*********************************************************************//** * @brief * The addMsgToPendingACKList function adds a given message to the pending * ACK list. Messages in this list will require receipt of an ACK message * for this particular message within a limited time. * @details Inputs: pendingAckList[] * @details Outputs: pendingAckList[] * @param msg pointer to msg within the message data * @param msgData pointer to message data to add to pending ACK list * @param len number of bytes of message data * @return TRUE if message added successfully, FALSE if not *************************************************************************/ BOOL addMsgToPendingACKList( MESSAGE_T *msg, COMM_BUFFER_T channel, U08 *msgData, U32 len ) { BOOL result = FALSE; U32 i; // Find first open slot in pending ACK list and add given msg data to it for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) { _disable_IRQ(); // Slot selection needs interrupt protection if ( FALSE == pendingAckList[ i ].used ) { S16 seqNo = msg->hdr.seqNo * -1; // Remove ACK bit from seq # pendingAckList[ i ].used = TRUE; _enable_IRQ(); pendingAckList[ i ].seqNo = seqNo; pendingAckList[ i ].channel = channel; pendingAckList[ i ].timeStamp = getMSTimerCount(); pendingAckList[ i ].retries = MSG_NOT_ACKED_MAX_RETRIES; pendingAckList[ i ].msgSize = len; memcpy( (U08*)pendingAckList[ i ].msg, msgData, len ); result = TRUE; break; } else { _enable_IRQ(); } } return result; } /*********************************************************************//** * @brief * The matchACKtoPendingACKList function searches the pending ACK list to * see if the sequence # from a received ACK msg matches any. If found, * the list entry is removed. * @details Inputs: pendingAckList[] * @details Outputs: pendingAckList[] * @param seqNo sequence # to match to an entry in the list * @return TRUE if a match was found, FALSE if not *************************************************************************/ static BOOL matchACKtoPendingACKList( S16 seqNo ) { BOOL result = FALSE; U32 i; // Find match for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) { if ( ( TRUE == pendingAckList[ i ].used ) && ( pendingAckList[ i ].seqNo == seqNo ) ) { // Remove message pending ACK from list pendingAckList[ i ].used = FALSE; result = TRUE; break; } } return result; } /*********************************************************************//** * @brief * The checkPendingACKList function searches the pending ACK list to * see if any have expired. Any such messages will be queued for retransmission * and if max retries reached a fault is triggered. * @details Inputs: pendingAckList[] * @details Outputs: pendingAckList[] * @return none *************************************************************************/ static void checkPendingACKList( void ) { U32 i; // Find expired messages pending ACK for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) { // Pending ACK expired? U32 timeoutPeriod = MSG_NOT_ACKED_TIMEOUT_MS; // set the timeout as default if ( MODE_INIT == getCurrentOperationMode() ) { // change it to longer timeout if the HD is in INIT state timeoutPeriod = MSG_NOT_ACKED_TIMEOUT_MS_INIT; } if ( ( TRUE == pendingAckList[ i ].used ) && ( TRUE == didTimeout( pendingAckList[ i ].timeStamp, timeoutPeriod ) ) ) { // If retries left, reset and resend pending message if ( pendingAckList[ i ].retries > 0 ) { // Re-queue message for transmit pendingAckList[ i ].retries--; pendingAckList[ i ].timeStamp = getMSTimerCount(); addToCommBuffer( pendingAckList[ i ].channel, (U08*)pendingAckList[ i ].msg, pendingAckList[ i ].msgSize ); } // If no retries left, alarm else { U16 msgID; memcpy( &msgID, (U08*)&pendingAckList[ i ].msg[ sizeof( U08 ) + sizeof( U16) ], sizeof( U16 ) ); SET_ALARM_WITH_1_U32_DATA( ALARM_ID_CAN_MESSAGE_NOT_ACKED, (U32)msgID ); pendingAckList[ i ].used = FALSE; // Take pending message off of list } } } } /*********************************************************************//** * @brief * The processReceivedMessage function processes a given message. * @details Inputs: none * @details Outputs: message processed * @param message pointer to message to process * @return none *************************************************************************/ static void processReceivedMessage( MESSAGE_T *message ) { U16 msgID = message->hdr.msgID; // Handle any messages from other sub-systems switch ( msgID ) { case MSG_ID_OFF_BUTTON_PRESS: handleOffButtonConfirmMsgFromUI( message ); break; case MSG_ID_ALARM_TRIGGERED: handleAlarmTriggered( message ); break; case MSG_ID_ALARM_CONDITION_CLEARED: handleAlarmCleared( message ); break; case MSG_ID_UI_ALARM_USER_ACTION: handleAlarmUserAction( message ); break; case MSG_ID_DG_CHECK_IN: handleDGCheckIn( message ); break; case MSG_ID_UI_CHECK_IN: handleUICheckIn( message ); break; case MSG_ID_LOAD_CELL_READINGS: handleLoadCellReadingsFromDG( message ); break; case MSG_ID_USER_UF_PAUSE_RESUME_REQUEST: handleUFPauseResumeRequest( message ); break; case MSG_ID_USER_UF_SETTINGS_CHANGE_REQUEST: handleChangeUFSettingsRequest( message ); break; case MSG_ID_USER_SALINE_BOLUS_REQUEST: handleSalineBolusRequest( message ); break; case MSG_ID_USER_CONFIRM_UF_SETTINGS_CHANGE: handleChangeUFSettingsConfirmation( message ); break; case MSG_ID_USER_TREATMENT_TIME_CHANGE_REQUEST: handleChangeTreatmentDurationRequest( message ); break; case MSG_ID_USER_BLOOD_DIAL_RATE_CHANGE_REQUEST: handleChangeBloodDialysateRateChangeRequest( message ); break; case MSG_ID_REQUEST_FW_VERSIONS: handleFWVersionRequest( message ); handleHDSerialNumberRequest(); break; case MSG_ID_DG_VERSION: handleDGVersionResponse( message ); break; case MSG_ID_DG_TEMPERATURE_DATA: handleDGTemperatureData( message ); break; case MSG_ID_DG_DIALYSATE_FLOW_METER_DATA: handleDialysateFlowData( message ); break; case MSG_ID_DG_OP_MODE: handleDGOpMode( message ); break; case MSG_ID_DG_RESERVOIRS_DATA: handleDGReservoirData( message ); break; case MSG_ID_USER_REQUEST_ALARM_SILENCE: handleUIAlarmSilenceRequest( message ); break; case MSG_ID_UI_NEW_TREATMENT_PARAMS: handleTreatmentParametersFromUI( message ); break; case MSG_ID_UI_INITIATE_TREATMENT_REQUEST: handleInitiateTreatmentRequest( message ); break; case MSG_ID_UI_USER_CONFIRM_TREATMENT_PARAMS: handleUIUserConfirmTreatmentParameters( message ); break; case MSG_ID_UI_PRESSURE_LIMITS_CHANGE_REQUEST: handleChangePressureLimitsRequest( message ); break; case MSG_ID_UI_HEPARIN_PAUSE_RESUME_REQUEST: handleHeparinCommandRequest( message ); break; case MSG_ID_UI_SET_ALARM_AUDIO_VOLUME_LEVEL_CMD: handleAlarmAudioVolumeSetCmd( message ); break; case MSG_ID_UI_SET_UF_VOLUME_PARAMETER: handleUFVolumeSetRequest( message ); break; case MSG_ID_UI_SAMPLE_WATER_CMD: handleSampleWaterCmd( message ); break; case MSG_ID_UI_SAMPLE_WATER_RESULT: handleSampleWaterResult( message ); break; case MSG_ID_UI_CONSUMABLE_INSTALL_CONFIRM: handleConsumableInstallConfirm( message ); break; case MSG_ID_UI_INSTALLATION_CONFIRM: handleInstallationConfirm( message ); break; case MSG_ID_UI_START_PRIME_REQUEST: handleStartPrimeCmd( message ); break; case MSG_ID_UI_PATIENT_CONNECTION_BEGIN_REQUEST: handleContinueToTreatmentCmd( message ); break; case MSG_ID_UI_PATIENT_CONNECTION_CONFIRM: handlePatientConnectionConfirmCmd( message ); break; case MSG_ID_UI_START_TREATMENT_REQUEST: handleStartTreatmentRequest( message ); break; case MSG_ID_UI_RINSEBACK_CMD: handlRinsebackCmd( message ); break; case MSG_ID_UI_RECIRC_CMD: handleTreatmentRecircCmd( message ); break; case MSG_ID_UI_TX_END_CMD: handleTreatmentEndCmd( message ); break; case MSG_ID_UI_PATIENT_DISCONNECTION_CONFIRM: handlePatientDisconnectionConfirmCmd( message ); break; case MSG_ID_UI_DISPOSABLE_REMOVAL_CONFIRM: handleDisposableRemovalConfirmCmd( message ); break; case MSG_ID_UI_TREATMENT_LOG_DATA_REQUEST: handleUITreatmentLogDataRequest( message ); break; case MSG_ID_UI_DISINFECT_REQUEST: handleUIDisinfectRequest( message ); break; case MSG_ID_DG_COMMAND_RESPONSE: handleDGCmdResp( message ); break; case MSG_ID_DG_FLUSH_DATA: handleFlushUIStateReadingFromDG( message ); break; case MSG_ID_DG_HEAT_DISINFECT_DATA: handleHeatDisinfectUIStateReadingFromDG( message ); break; case MSG_ID_DG_CHEM_DISINFECT_DATA: handleChemDisinfectUIStateReadingFromDG( message ); break; case MSG_ID_UI_HD_SET_RTC_REQUEST: handleUIClockSyncRequest( message ); break; case MSG_ID_DG_POST_FINAL_TEST_RESULT: handleDGPOSTFinalResult( message ); break; case MSG_ID_UI_POST_FINAL_TEST_RESULT: handleUIPOSTFinalResult( message ); break; case MSG_ID_HD_UI_VERSION_INFO_RESPONSE: handleUIVersionResponse( message ); break; case MSG_ID_UI_ACTIVE_ALARMS_LIST_REQUEST: handleUIActiveAlarmsListRequest( message ); break; case MSG_ID_HD_SET_STANDBY_DISINFECT_SUB_MODE_REQUEST: handleSetHDStandbyDisinfectSubmodeRequest( message ); break; case MSG_ID_UI_REQUEST_SERVICE_INFO: handleHDServiceScheduleRequest( message ); break; case MSG_ID_REQUEST_HD_USAGE_INFO: handleHDUsageInfoRequest( message ); break; case MSG_ID_HD_STOP_RTC_CLOCK: handleStopHDRTCClock( message ); break; case MSG_ID_DG_CONCENTRATE_MIXING_RATIOS_DATA: handleDGMixingRatios( message ); break; // NOTE: this always must be the last case case MSG_ID_TESTER_LOGIN_REQUEST: handleTesterLogInRequest( message ); break; default: // Un-recognized or un-handled message ID received - ignore break; } // Handle any test messages if tester has logged in successfully if ( ( msgID > MSG_ID_FIRST_TESTER_MESSAGE ) && ( msgID <= END_OF_MSG_IDS ) && ( TRUE == isTestingActivated() ) ) { switch ( msgID ) { case MSG_ID_OFF_BUTTON_STATE_OVERRIDE: handleTestOffButtonStateOverrideRequest( message ); break; case MSG_ID_STOP_BUTTON_STATE_OVERRIDE: handleTestStopButtonStateOverrideRequest( message ); break; case MSG_ID_ALARM_LAMP_PATTERN_OVERRIDE: handleTestAlarmLampPatternOverrideRequest( message ); break; case MSG_ID_WATCHDOG_TASK_CHECKIN_OVERRIDE: handleTestWatchdogCheckInStateOverrideRequest( message ); break; case MSG_ID_ALARM_STATE_OVERRIDE: handleTestAlarmStateOverrideRequest( message ); break; case MSG_ID_ALARM_TIME_OVERRIDE: handleTestAlarmTimeOverrideRequest( message ); break; case MSG_ID_BLOOD_FLOW_SET_PT_OVERRIDE: handleTestBloodFlowSetPointOverrideRequest( message ); break; case MSG_ID_BLOOD_FLOW_MEAS_OVERRIDE: handleTestBloodFlowMeasuredOverrideRequest( message ); break; case MSG_ID_BLOOD_PUMP_MC_MEAS_SPEED_OVERRIDE: handleTestBloodPumpMCMeasuredSpeedOverrideRequest( message ); break; case MSG_ID_BLOOD_PUMP_MC_MEAS_CURR_OVERRIDE: handleTestBloodPumpMCMeasuredCurrentOverrideRequest( message ); break; case MSG_ID_BLOOD_FLOW_SEND_INTERVAL_OVERRIDE: handleTestBloodFlowBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_TREATMENT_TIME_REMAINING_OVERRIDE: handleTestTreatmentTimeRemainingOverrideRequest( message ); break; case MSG_ID_BLOOD_PUMP_MEAS_SPEED_OVERRIDE: handleTestBloodPumpMeasuredSpeedOverrideRequest( message ); break; case MSG_ID_BLOOD_PUMP_MEAS_ROTOR_SPEED_OVERRIDE: handleTestBloodPumpRotorMeasuredSpeedOverrideRequest( message ); break; case MSG_ID_DIAL_IN_FLOW_SET_PT_OVERRIDE: handleTestDialInFlowSetPointOverrideRequest( message ); break; case MSG_ID_DIAL_IN_FLOW_MEAS_OVERRIDE: handleTestDialInFlowMeasuredOverrideRequest( message ); break; case MSG_ID_DIAL_IN_PUMP_MC_MEAS_SPEED_OVERRIDE: handleTestDialInPumpMCMeasuredSpeedOverrideRequest( message ); break; case MSG_ID_DIAL_IN_PUMP_MC_MEAS_CURR_OVERRIDE: handleTestDialInPumpMCMeasuredCurrentOverrideRequest( message ); break; case MSG_ID_DIAL_IN_FLOW_SEND_INTERVAL_OVERRIDE: handleTestDialInFlowBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_DIAL_IN_PUMP_MEAS_SPEED_OVERRIDE: handleTestDialInPumpMeasuredSpeedOverrideRequest( message ); break; case MSG_ID_DIAL_IN_PUMP_MEAS_ROTOR_SPEED_OVERRIDE: handleTestDialInPumpRotorMeasuredSpeedOverrideRequest( message ); break; case MSG_ID_PRESSURE_ARTERIAL_OVERRIDE: handleTestArterialPressureOverrideRequest( message ); break; case MSG_ID_PRESSURE_VENOUS_OVERRIDE: handleTestVenousPressureOverrideRequest( message ); break; case MSG_ID_OCCLUSION_BLOOD_PUMP_OVERRIDE: handleTestBloodPumpOcclusionOverrideRequest( message ); break; case MSG_ID_PRES_OCCL_SEND_INTERVAL_OVERRIDE: handleTestPresOcclBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_SET_RTC_DATE_TIME: handleSetRTCTimestamp( message ); break; case MSG_ID_DIAL_OUT_FLOW_SEND_INTERVAL_OVERRIDE: handleTestDialOutFlowBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_DIAL_OUT_UF_REF_VOLUME_OVERRIDE: handleTestDialOutUFReferenceVolumeOverrideRequest( message ); break; case MSG_ID_DIAL_OUT_UF_MEAS_VOLUME_OVERRIDE: handleTestDialOutUFMeasuredVolumeOverrideRequest( message ); break; case MSG_ID_DIAL_OUT_PUMP_MC_MEAS_SPEED_OVERRIDE: handleTestDialOutPumpMCMeasuredSpeedOverrideRequest( message ); break; case MSG_ID_DIAL_OUT_PUMP_MC_MEAS_CURR_OVERRIDE: handleTestDialOutPumpMCMeasuredCurrentOverrideRequest( message ); break; case MSG_ID_DIAL_OUT_PUMP_MEAS_SPEED_OVERRIDE: handleTestDialOutPumpMeasuredSpeedOverrideRequest( message ); break; case MSG_ID_DIAL_OUT_PUMP_MEAS_ROTOR_SPEED_OVERRIDE: handleTestDialOutPumpMeasuredRotorSpeedOverrideRequest( message ); break; case MSG_ID_DIAL_OUT_LOAD_CELL_WEIGHT_OVERRIDE: handleTestDialOutLoadCellWeightOverrideRequest( message ); break; case MSG_ID_HD_SAFETY_SHUTDOWN_OVERRIDE: handleTestHDSafetyShutdownOverrideRequest( message ); break; case MSG_ID_HD_ACCEL_OVERRIDE: handleTestHDAccelOverrideRequest( message ); break; case MSG_ID_HD_ACCEL_MAX_OVERRIDE: handleTestHDAccelMaxOverrideRequest( message ); break; case MSG_ID_HD_ACCEL_SEND_INTERVAL_OVERRIDE: handleTestHDAccelBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_DIAL_OUT_FLOW_SET_PT_OVERRIDE: handleTestDialOutFlowSetPointOverrideRequest( message ); break; case MSG_ID_HD_SET_PARAMETER_TREATMENT_PARAMETER: handleTestSetTreatmentParameter( message ); break; case MSG_ID_VALVES_STATES_PUBLISH_INTERVAL_OVERRIDE: handleTestHDValvesBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_HD_VALVES_HOME: handleHomeHDValve( message ); break; case MSG_ID_HD_VALVES_SET_AIR_TRAP_VALVE: handleSetAirTrapValve( message ); break; case MSG_ID_HD_VALVES_POSITION_OVERRIDE: handleSetHDValvePositionOverrideRequest( message ); break; #ifdef DEBUG_ENABLED case MSG_ID_HD_VALVES_SET_PWM_OVERRIDE: handleSetHDValvePWMOverrideRequest( message ); break; #endif case MSG_ID_HD_AIR_TRAP_SEND_INTERVAL_OVERRIDE: handleSetAirTrapBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_HD_AIR_TRAP_LEVEL_SENSOR_OVERRIDE: handleSetAirTrapLevelSensorOverrideRequest( message ); break; case MSG_ID_HD_SOFTWARE_RESET_REQUEST: handleHDSoftwareResetRequest( message ); break; case MSG_ID_BLOOD_ROTOR_COUNT_OVERRIDE: handleHDBloodPumpRotorCountOverrideRequest( message ); break; case MSG_ID_SET_ARTERIAL_PRESSURE_OFFSET: handleHDSetArterialPressureOffsetRequest( message ); break; case MSG_ID_BLOOD_PUMP_HOME_CMD: handleTestBloodPumpHomeRequest( message ); break; case MSG_ID_DIAL_IN_PUMP_HOME_CMD: handleTestDialInPumpHomeRequest( message ); break; case MSG_ID_DIAL_OUT_PUMP_HOME_CMD: handleTestDialOutPumpHomeRequest( message ); break; case MSG_ID_SUPER_CLEAR_ALARMS_CMD: handleTestSuperClearAlarmsRequest( message ); break; case MSG_ID_HD_SET_OP_MODE_REQUEST: handleTestSetOpModeRequest( message ); break; case MSG_ID_HD_FLUID_LEAK_SEND_INTERVAL_OVERRIDE: handleSetFluidLeakBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_HD_FLUID_LEAK_STATE_OVERRIDE: handleSetFluidLeakStateOverrideRequest( message ); break; case MSG_ID_HD_BLOOD_LEAK_DATA_SEND_INTERVAL_OVERRIDE: handleSetBloodLeakDataBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_HD_BLOOD_LEAK_STATUS_OVERRIDE: handleSetBloodLeakStatusOverrideRequest( message ); break; case MSG_ID_HD_BLOOD_LEAK_ZERO_REQUEST: handleBloodLeakZeroRequest( message ); break; case MSG_ID_HD_BUBBLES_DATA_SEND_INTERVAL_OVERRIDE: handleSetBubblesDataBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_HD_BUBBLE_STATUS_OVERRIDE: handleSetBubbleStatusOverrideRequest( message ); break; case MSG_ID_HD_BUBBLE_SELF_TEST_REQUEST: handleBubbleSelfTestRequest( message ); break; case MSG_ID_HD_BLOOD_PRIME_VOLUME_OVERRIDE: handleBloodPrimeVolumeOverrideRequest( message ); break; case MSG_ID_HD_SWITCHES_STATUS_OVERRIDE: handleSetSwitchesStatusOverrideRequest( message ); break; case MSG_ID_HD_SWITCHES_PUBLISH_INTERVAL_OVERRIDE: handleTestSwitchesPublishIntervalOverrideRequest( message ); break; case MSG_ID_HD_BATTERY_REMAINING_PERCENT_OVERRIDE: handleBatteryRemainingPercentOverrideRequest( message ); break; case MSG_ID_HD_RINSEBACK_VOLUME_OVERRIDE: handleRinsebackVolumeOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_SEND_INTERVAL_OVERRIDE: handleTestSyringePumpDataBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_OPERATION_REQUEST: handleTestSyringePumpOperationRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_MEASURED_RATE_OVERRIDE: handleTestSyringePumpMeasuredRateOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_MEASURED_FORCE_OVERRIDE: handleTestSyringePumpMeasuredForceOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_SYRINGE_DETECT_OVERRIDE: handleTestSyringePumpMeasuredSyringeDetectOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_MEASURED_HOME_OVERRIDE: handleTestSyringePumpMeasuredHomeOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_MEASURED_POSITION_OVERRIDE: handleTestSyringePumpMeasuredPositionOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_MEASURED_VOLUME_OVERRIDE: handleTestSyringePumpMeasuredVolumeOverrideRequest( message ); break; case MSG_ID_HD_VALVES_CURRENT_OVERRIDE: handleTestValvesCurrentOverrideRequest( message ); break; case MSG_ID_HD_VALVES_POSITION_COUNT_OVERRIDE: handleTestValvesPositionCountOverrideRequest( message ); break; case MSG_ID_HD_MONITORED_VOLTAGES_SEND_INTERVAL_OVERRIDE: handleTestMonitoredVoltagesSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_MONITORED_VOLTAGES_OVERRIDE: handleTestMonitoredVoltageOverrideRequest( message ); break; case MSG_ID_HD_ALARM_INFO_SEND_INTERVAL_OVERRIDE: handleTestAlarmInfoSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_ALARM_AUDIO_VOLUME_LEVEL_OVERRIDE: handleTestAlarmAudioVolumeOverrideRequest( message ); break; case MSG_ID_HD_ALARM_AUDIO_CURRENT_HG_OVERRIDE: handleTestAlarmAudioCurrentHgOverrideRequest( message ); break; case MSG_ID_HD_ALARM_AUDIO_CURRENT_LG_OVERRIDE: handleTestAlarmAudioCurrentLgOverrideRequest( message ); break; case MSG_ID_HD_ALARM_BACKUP_AUDIO_CURRENT_OVERRIDE: handleTestAlarmBackupAudioCurrentOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_STATUS_OVERRIDE: handleTestSyringePumpStatusOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_ENCODER_STATUS_OVERRIDE: handleTestSyringePumpEncoderStatusOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_ADC_DAC_STATUS_OVERRIDE: handleTestSyringePumpADCandDACStatusOverrideRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_ADC_READ_COUNTER_OVERRIDE: handleTestSyringePumpADCReadCtrOverrideRequest( message ); break; case MSG_ID_HD_TEMPERATURES_VALUE_OVERRIDE: handleTestTemperaturesValueOverrideRequest( message ); break; case MSG_ID_HD_TEMPERATURES_PUBLISH_INTERVAL_OVERRIDE: handleTestTemperaturesBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_HD_FANS_PUBLISH_INTERVAL_OVERRIDE: handleTestFansBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_HD_FANS_RPM_OVERRIDE: handleFansRPMOverride( message ); break; case MSG_ID_HD_SET_CALIBRATION_RECORD: handleSetHDCalibrationRecord( message ); break; case MSG_ID_HD_GET_CALIBRATION_RECORD: handleGetHDCalibrationRecord( message ); break; case MSG_ID_HD_SET_SYSTEM_RECORD: handleSetHDSystemRecord( message ); break; case MSG_ID_HD_GET_SYSTEM_RECORD: handleGetHDSystemRecord( message ); break; case MSG_ID_HD_GET_SERVICE_RECORD: handleGetHDServiceRecord( message ); break; case MSG_ID_HD_SET_SERVICE_RECORD: handleSetHDServiceRecord( message ); break; case MSG_ID_HD_ALARM_STATUS_PUBLISH_INTERVAL_OVERRIDE: handleTestAlarmStatusSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_TREATMENT_TIME_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestTreatmentTimeDataSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_TREATMENT_RANGES_PUBLISH_INTERVAL_OVERRIDE: handleTestTreatmentRangesSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_TREATMENT_STOP_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestTreatmentStopDataSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_BLOOD_PRIME_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestBloodPrimeDataSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_RINSEBACK_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestRinsebackDataSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_STANDBY_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestStandbyModeDataSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_OP_MODE_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestOpModeDataSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_PRE_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestPreTreatmentModeDataSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestTreatmentModeSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_POST_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestPostTreatmentModeSendIntervalOverrideRequest( message ); break; case MSG_ID_HD_BLOCK_MESSAGE_TRANSMISSION: handleTestBlockMessagesRequest( message ); break; case MSG_ID_HD_SYRINGE_PUMP_FORCE_SENSOR_DAC_CALIBRATE: handleTestSyringePumpForceSensorCalibrateRequest( message ); break; case MSG_ID_HD_FAN_RPM_ALARM_START_TIME_OVERRIDE: handleTestFansRPMAlarmStartTimeOffsetOverrideRequest( message ); break; default: // Unrecognized message ID received - ignore break; } } } /**@}*/