/************************************************************************** * * Copyright (c) 2019-2023 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) Michael Garthwaite * @date (last) 11-Sep-2023 * * @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 "DrainPump.h" #include "Heaters.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 HD_COMM_TIMEOUT_IN_MS 2000 ///< HD has not sent any broadcast messages 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 250 ///< maximum time for a Denali message that requires ACK to be ACK'd #define MSG_NOT_ACKED_MAX_RETRIES 10 ///< 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 Delanli messages that can be pending ACK at any given time #define MAX_FPGA_CLOCK_SPEED_ERRORS 3 ///< maximum number of FPGA clock speed errors within window period before alarm #define MAX_FPGA_CLOCK_SPEED_ERROR_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) ///< FPGA clock speed error window #define PENDING_ACK_LIST_OVERRIDE_UI_CHANNEL 1 ///< Value for determining UI channel when Pending ACKs are overriden. #define PENDING_ACK_LIST_OVERRIDE_DG_CHANNEL 2 ///< Value for determining HD channel when Pending ACKs are overriden. #pragma pack(push, 1) /// Record for transmitted message that is pending acknowledgement from receiver. typedef struct { BOOL used; ///< Flag indicates whether the pending ACK slot is used or not U16 seqNo; ///< Sequence number U16 retries; ///< Retry count U32 timeStamp; ///< Message time stamp COMM_BUFFER_T channel; ///< Comm buffer channel U32 msgSize; ///< Message size U08 msg[ MAX_ACK_MSG_SIZE ]; ///< Bytes representation of the message } 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_DG_ALARM, COMM_BUFFER_OUT_CAN_DG_2_HD, COMM_BUFFER_OUT_CAN_DG_2_UI, COMM_BUFFER_OUT_CAN_DG_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_HD_ALARM, COMM_BUFFER_IN_CAN_UI_ALARM, COMM_BUFFER_IN_CAN_HD_2_DG, COMM_BUFFER_IN_CAN_HD_BROADCAST, COMM_BUFFER_IN_CAN_UI_2_DG, 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 PENDING_ACK_RECORD_T pendingAckList[ PENDING_ACK_LIST_SIZE ]; ///< list of outgoing messages that are awaiting an ACK static volatile BOOL dgIsOnlyCANNode = TRUE; ///< flag indicating whether DG is alone on CAN bus. static U32 canXmitRetryCtr = 0; ///< counter for CAN transmit retries. static OVERRIDE_U32_T hdCommunicationStatus = {0, 0, 0, 0}; ///< has HD sent a message since last check static volatile U32 timeOfLastHDCheckIn = 0; ///< last time we received an HD broadcast static OVERRIDE_U32_T pendingACKOverride = { 0, 0, 0, 0 }; ///< Pending ACK override data structure. // ********** 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 FPGA clock speed error time windowed count initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CLOCK_SPEED_ERROR, MAX_FPGA_CLOCK_SPEED_ERRORS, MAX_FPGA_CLOCK_SPEED_ERROR_WINDOW_MS); // initialize pending ACK list for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) { pendingAckList[ i ].used = FALSE; } } /*********************************************************************//** * @brief * The isHDCommunicating function determines whether the HD is communicating * with the DG. * @details Inputs: hdIsCommunicating * @details Outputs: none * @return TRUE if HD has broadcast since last call, FALSE if not *************************************************************************/ BOOL isHDCommunicating( void ) { return getU32OverrideValue( &hdCommunicationStatus ); } /*********************************************************************//** * @brief * The isDGOnlyCANNode function determines whether the DG is the only node * currently on the CAN bus. * @details Inputs: dgIsOnlyCANNode * @details Outputs: none * @return TRUE if DG is only node on CAN bus, FALSE if not *************************************************************************/ BOOL isDGOnlyCANNode( void ) { return dgIsOnlyCANNode; } /*********************************************************************//** * @brief * The execSystemCommRx function manages received data from other sub-systems. * @details Inputs: none * @details Outputs: Incoming frames 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 haven't been ACK'd checkPendingACKList(); if ( TRUE == hasDialinCheckInExpired() ) { // It has been a while since the user logged in but not activity has been received from Dialin so set the tester's status to log out setTesterStatusToLoggedOut(); } } /*********************************************************************//** * @brief * The execSystemCommTx function manages data to be transmitted to other sub-systems. * @details Inputs: none * @details Outputs: Next outgoing frame transmitted. * @return none *************************************************************************/ void execSystemCommTx( void ) { // don't bother with transmitting if no other nodes on CAN bus if ( FALSE == dgIsOnlyCANNode ) { // 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 don't 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 { dgIsOnlyCANNode = 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 } // end - are we retrying xmit or are we alone on CAN bus } // end - pending xmit timeout? } // end - transmit in progress or not } // end - DG not alone on CAN bus } /*********************************************************************//** * @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 = transmitNextCANPacket(); 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 { // shouldn't get here - not an active message box // s/w fault? } } /*********************************************************************//** * @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're 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's another CAN packet to send, send it if ( dataSize == CAN_MESSAGE_PAYLOAD_SIZE ) { // we're 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_DG_SOFTWARE_FAULT, SW_FAULT_ID_CAN_TX_FAULT, (U32)mBox ) } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_CAN_MESSAGE_SIZE, (U32)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 don't get stuck in loop - only set to true 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 ); dgIsOnlyCANNode = FALSE; // if we're getting a message, we can't be alone 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 HD broadcast channel, update HD comm status if ( COMM_BUFFER_IN_CAN_HD_BROADCAST == MSG_IN_BUFFERS[ i ] ) { hdCommunicationStatus.data = (U32)TRUE; timeOfLastHDCheckIn = getMSTimerCount(); } } else if ( -1 == msgSize ) // candidate message with bad CRC found? { badCRCDetected = TRUE; 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 comm 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's empty while ( numOfBytesInBuffer > 0 ) { peekFromCommBuffer( buffer, &data, 1 ); if ( MESSAGE_SYNC_BYTE == data ) { break; // we found a sync - we're 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: If a complete message can be found in buffer contents, it is parsed out. * @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's 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 ); } // otherwise, process the received message processReceivedMessage( &message.msg ); } } else // CRC failed { 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 == didTimeout( timeOfLastHDCheckIn, HD_COMM_TIMEOUT_IN_MS ) ) { hdCommunicationStatus.data = FALSE; setHDOperationMode( 0, 0 ); // If HD off or not connected, consider HD mode is fault. stopHeater( DG_TRIMMER_HEATER ); // If HD off or not connected, ensure trimmer heater is off. } } /*********************************************************************//** * @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 ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_COMM_TOO_MANY_BAD_CRCS, 2 ); // 2 for DG } } /*********************************************************************//** * @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( 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 number from a received ACK msg matches any. If found, * the list entry is removed. * @details Inputs: pendingAckList[] * @details Outputs: pendingAckList[] * @param seqNo sequence number 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 ) ) { result = TRUE; // Remove message pending ACK from list if ( ( ( getU32OverrideValue( &pendingACKOverride ) != PENDING_ACK_LIST_OVERRIDE_UI_CHANNEL ) || ( pendingAckList[ i ].channel != COMM_BUFFER_OUT_CAN_DG_2_UI ) ) && ( ( getU32OverrideValue( &pendingACKOverride ) != PENDING_ACK_LIST_OVERRIDE_DG_CHANNEL ) || ( pendingAckList[ i ].channel != COMM_BUFFER_OUT_CAN_DG_2_HD ) ) ) { pendingAckList[ i ].used = FALSE; } 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 if( TRUE == isHDCommunicating() ) { for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) { // pending ACK expired? if ( ( TRUE == pendingAckList[ i ].used ) && ( TRUE == didTimeout( pendingAckList[ i ].timeStamp, MSG_NOT_ACKED_TIMEOUT_MS ) ) ) { // if retries left, reset and resend pending message. Do not retry when in POST since the UI might not still be responsive if ( pendingAckList[ i ].retries > 0 ) { if ( getCurrentOperationMode() != DG_MODE_INIT ) { // If not in post, limit the number of retries pendingAckList[ i ].retries--; } // Resend message pendingAckList[ i ].timeStamp = getMSTimerCount(); addToCommBuffer( pendingAckList[ i ].channel, pendingAckList[ i ].msg, pendingAckList[ i ].msgSize ); } // if no retries left, alarm else { U16 msgID; memcpy( &msgID, &pendingAckList[ i ].msg[ sizeof( U08 ) + sizeof( U16 ) ], sizeof( U16 ) ); SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_CAN_MESSAGE_NOT_ACKED, (U32)msgID ); pendingAckList[ i ].used = FALSE; // take pending message off of list } } } } else { // Clear pending ACK list for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) { pendingAckList[ i ].used = FALSE; } } } /*********************************************************************//** * @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_POWER_OFF_WARNING: handlePowerOffWarning( message ); break; case MSG_ID_ALARM_CLEARED: handleAlarmClear( message ); break; case MSG_ID_RTC_EPOCH_DATA: handleRTCSyncFromHD( message ); break; case MSG_ID_SET_DG_DIALYSATE_TEMP_TARGETS: handleSetDialysateTemperatureCmd( message ); break; case MSG_ID_FW_VERSIONS_REQUEST: handleFWVersionCmd( message ); handleDGSerialNumberRequest(); break; case MSG_ID_DG_SWITCH_RESERVOIR_CMD_REQUEST: handleSwitchReservoirCmd( message ); break; case MSG_ID_DG_CHANGE_VALVE_SETTING_CMD_REQUEST: handleChangeValveSettingCmd( message ); break; case MSG_ID_DG_FILL_CMD_REQUEST: handleFillCmd( message ); break; case MSG_ID_DG_DRAIN_CMD_REQUEST: handleDrainCmd( message ); break; case MSG_ID_HD_OP_MODE_DATA: handleSetHDOperationMode( message ); break; case MSG_ID_STARTING_STOPPING_TREATMENT_CMD_REQUEST: handleStartStopTreatmentMsg( message ); break; case MSG_ID_DG_SAMPLE_WATER_CMD_REQUEST: handleSampleWaterCmd( message ); break; case MSG_ID_HD_START_STOP_TRIMMER_HEATER_CMD_REQUEST: handleHDStartStopTrimmerHeaterCmd( message ); break; case MSG_ID_DG_PARK_CONCENTRATE_PUMPS_CMD_REQUEST: handleParkConecentratePumpsCmd( message ); break; case MSG_ID_DG_START_STOP_TRIMMER_HEATER_CMD: handleDGStartStopTrimmerHeater( message ); break; case MSG_ID_DG_START_STOP_FLUSH_CMD_REQUEST: handleStartStopDGFlush( message ); break; case MSG_ID_DG_START_STOP_HEAT_DISINFECT_CMD_REQUEST: handleStartStopDGHeatDisinfect( message ); break; case MSG_ID_DG_START_STOP_CHEM_DISINFECT: handleStartStopDGChemicalDisinfect( message ); break; case MSG_ID_DG_START_STOP_CHEM_DISINFECT_FLUSH: handleStartStopDGChemicalDisinfectFlush( message ); break; case MSG_ID_UI_DG_SET_RTC_REQUEST: handleUIClockSyncRequest( message ); break; case MSG_ID_HD_DG_POST_RESULT_REQUEST: handleDGPOSTResultRequest( message ); break; case MSG_ID_UI_SERVICE_INFO_REQUEST: handleDGServiceScheduleRequestToUI( message ); break; case MSG_ID_HD_DG_CONCENTRATE_MIXING_RATIOS_REQUEST: handleDGSendConcentrateMixingRatios( message ); break; case MSG_ID_HD_DG_SERVICE_MODE_REQUEST: handleServiceModeRequest( message ); break; case MSG_ID_HD_DG_USAGE_INFO_REQUEST: handleHDRequestDGUsageInfo( message ); break; case MSG_ID_DG_SET_SERVICE_TIME_REQUEST: handleSetDGServiceTime( message ); break; case MSG_ID_DG_START_STOP_HEAT_DISINFECT_ACTIVE_COOL: handleStartStopDGHeatDisinfectActiveCool( message ); break; case MSG_ID_HD_DG_ALARMS_REQUEST: handleResendAllAlarmsCommand( message ); break; case MSG_ID_UI_SET_DG_RO_MODE: handleSetROOnlyMode( message ); break; case MSG_ID_HD_SEND_CHEM_FLUSH_SAMPLE_PASS_FAIL_TO_DG: handleReceiveChemFlushSampleResultsFromHD( message ); break; case MSG_ID_DG_START_STOP_RO_PERMEATE_SAMPLE_MODE_CMD_REQUEST: handleStartStopDGROPermeateSample( message ); break; case MSG_ID_HD_SEND_RO_PERMEATE_SAMPLE_DISPENSE_REQUEST_TO_DG: handleReceiveROPermeatSampleDispenseRequest( message ); break; case MSG_ID_HD_REQUEST_SERVICE_RECORD_FROM_HD: handleSendDGServiceRecordToHD( message ); break; // NOTE: This case must be last case MSG_ID_DG_TESTER_LOGIN_REQUEST: handleTesterLogInRequest( message ); break; default: // unrecognized message ID received - ok, ignore - may be a test message handled below break; } // handle any test messages if tester has logged in successfully if ( ( msgID > MSG_ID_FIRST_DG_TESTER_MESSAGE ) && ( TRUE == isTestingActivated() ) ) { switch ( msgID ) { case MSG_ID_DG_ALARM_STATE_OVERRIDE: handleTestAlarmStateOverrideRequest( message ); break; case MSG_ID_DG_WATCHDOG_TASK_CHECKIN_OVERRIDE: handleTestWatchdogCheckInStateOverrideRequest( message ); break; case MSG_ID_DG_SET_RTC_DATE_TIME: handleSetRTCTimestamp( message ); break; case MSG_ID_START_STOP_PRIMARY_HEATER: handleStartStopPrimaryHeater ( message ); break; case MSG_ID_LOAD_CELL_OVERRIDE: handleTestLoadCellOverrideRequest( message ); break; case MSG_ID_LOAD_CELLL_SEND_INTERVAL_OVERRIDE: handleTestLoadCellDataBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_PRESSURE_OVERRIDE: handleTestPressureSensorOverrideRequest( message ); break; case MSG_ID_PRESSURE_SEND_INTERVAL_OVERRIDE: handleTestPressureDataBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_MEASURED_FLOW_SENSORS_OVERRIDE: handleTestMeasuredFlowOverrideRequest( message ); break; case MSG_ID_RO_PUMP_SEND_INTERVAL_OVERRIDE: handleTestROPumpDataBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_FLOW_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestFlowSensorsDataBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_DRAIN_PUMP_SET_RPM: handleTestSetDrainPumpRPM( message ); break; case MSG_ID_DRAIN_PUMP_SEND_INTERVAL_OVERRIDE: handleTestDrainPumpDataBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_VALVE_STATE_OVERRIDE: handleTestValveStateOverrideRequest( message ); break; case MSG_ID_DG_VALVES_STATES_PUBLISH_INTERVAL_OVERRIDE: handleTestValvesStatesPublishIntervalOverrideRequest( message ); break; case MSG_ID_DG_SAFETY_SHUTDOWN_OVERRIDE: handleTestDGSafetyShutdownOverrideRequest( message ); break; case MSG_ID_TEMPERATURE_SENSORS_VALUE_OVERRIDE: handleTestTemperatureSensorsOverrideRequest( message ); break; case MSG_ID_TEMPERATURE_SENSORS_PUBLISH_INTERVAL_OVERRIDE: handleTestTemperatureSensorsDataPublishOverrideRequest( message ); break; case MSG_ID_HEATERS_PUBLISH_INTERVAL_ORVERRIDE: handleTestHeatersDataPublishOverrideRequest( message ); break; case MSG_ID_CONDUCTIVITY_OVERRIDE: handleTestSetConductivityOverrideRequest( message ); break; case MSG_ID_CONDUCTIVITY_PUBLISH_INTERVAL_OVERRIDE: handleTestSetConductivityDataPublishIntervalOverrideRequest( message ); break; case MSG_ID_DG_ACCEL_OVERRIDE: handleTestDGAccelOverrideRequest( message ); break; case MSG_ID_DG_ACCEL_MAX_OVERRIDE: handleTestDGAccelMaxOverrideRequest( message ); break; case MSG_ID_DG_ACCEL_SEND_INTERVAL_OVERRIDE: handleTestDGAccelBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_DG_MONITORED_VOLTAGES_SEND_INTERVAL_OVERRIDE: handleTestMonitoredVoltagesSendIntervalOverrideRequest( message ); break; case MSG_ID_DG_MONITORED_VOLTAGES_OVERRIDE: handleTestMonitoredVoltageOverrideRequest( message ); break; case MSG_ID_DRAIN_PUMP_TARGET_OUTLET_FLOW: handleSetDrainPumpTargetOutletFlowLPM( message ); break; case MSG_ID_DG_SWITCHES_STATUS_OVERRIDE: handleSetSwitchesStatusOverrideRequest( message ); break; case MSG_ID_DG_SWITCHES_PUBLISH_INTERVAL_OVERRIDE: handleTestSwitchesPublishIntervalOverrideRequest( message ); break; case MSG_ID_DG_SOFTWARE_RESET_REQUEST: handleDGSoftwareResetRequest( message ); break; case MSG_ID_DG_CONCENTRATE_PUMP_MEASURED_SPEED_OVERRIDE: handleConcentratePumpMeasuredSpeedOverride( message ); break; case MSG_ID_CONCENTRATE_PUMP_TARGET_SPEED_OVERRIDE: handleSetConcentratePumpTargetSpeed( message ); break; case MSG_ID_CONCENTRATE_PUMP_STATE_CHANGE_REQUEST: handleConcentratePumpStateChangeRequest( message ); break; case MSG_ID_CONCENTRATE_PUMP_PUBLISH_INTERVAL_OVERRIDE: handleConcentratePumpPublishIntervalOverride( message ); break; case MSG_ID_DG_THERMISTORS_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestThermistorsDataPublishIntervalOverride( message ); break; case MSG_ID_DG_THERMISTORS_VALUE_OVERRIDE: handleTestThermistorsValueOverride( message ); break; case MSG_ID_DG_FANS_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestFansDataPublishIntervalOverride( message ); break; case MSG_ID_DG_RO_PUMP_DUTY_CYCLE_OVERRIDE: handleTestROPumpDutyCycleOverride( message ); break; case MSG_ID_DG_VALVES_SENSED_STATE_OVERRIDE: handleTestDGValvesSensedStateOverrideRequest( message ); break; case MSG_ID_DG_SET_RO_PUMP_TARGET_FLOW: handleTestROPumpTargetFlowOverride( message ); break; case MSG_ID_DG_RO_PUMP_TARGET_PRESSURE_OVERRIDE: handleROPumpTargetPressureOverride( message ); break; case MSG_ID_DG_START_STOP_UV_REACTORS: handleStartStopUVReactors( message ); break; case MSG_ID_UV_REACTORS_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestUVReactorsDataPublishIntervalOverride( message ); break; case MSG_ID_DG_UV_REACTORS_HEALTH_OVERRIDE: handleTestUVReactorsHealthOverride( message ); break; case MSG_ID_DG_SET_CALIBRATION_RECORD: handleSetDGCalibrationRecord( message ); break; case MSG_ID_DG_GET_CALIBRATION_RECORD: handleGetDGCalibrationRecord( message ); break; case MSG_ID_DG_SET_SYSTEM_RECORD: handleSetDGSystemRecord( message ); break; case MSG_ID_DG_GET_SYSTEM_RECORD: handleGetDGSystemRecord( message ); break; case MSG_ID_DG_GET_SERVICE_RECORD: handleGetDGServiceRecord( message ); break; case MSG_ID_DG_SET_SERVICE_RECORD: handleSetDGServiceRecord( message ); break; case MSG_ID_DG_FLUID_LEAK_SEND_INTERVAL_OVERRIDE: handleSetFluidLeakBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_DG_FLUID_LEAK_STATE_DETECTOR_OVERRIDE: handleSetFluidLeakStateDetectorOverrideRequest( message ); break; case MSG_ID_DG_OP_MODE_PUBLISH_INTERVAL_OVERRIDE: handleSetDGOpModeBroadcastIntervalOverrideRequest( message ); break; case MSG_ID_FILTER_FLUSH_TIME_PERIOD_OVERRIDE: handleFilterFlushTimePeriodOverride(message); break; case MSG_ID_DG_BLOCK_MESSAGE_TRANSMISSION: handleTestBlockMessagesRequest( message ); break; case MSG_ID_DG_STOP_RTC_CLOCK: handleStopDGRTCClock( message ); break; case MSG_ID_DG_DRAIN_PUMP_MEASURED_RPM_OVERRIDE: handleSetDrainPumpMeasuredRPMOverrideRequest( message ); break; case MSG_ID_DG_SUPER_CLEAR_ALARMS_CMD: handleTestSuperClearAlarmsRequest( message ); break; case MSG_ID_DG_ALARM_INFO_SEND_INTERVAL_OVERRIDE: handleTestAlarmInfoSendIntervalOverrideRequest( message ); break; case MSG_ID_DG_SET_FANS_RPM_ALARM_START_TIME_OFFSET: handleTestFansRPMAlarmStartTimeOffsetRequest( message ); break; case MSG_ID_DG_FANS_RPM_OVERRIDE: handleFansRPMOverride( message ); break; case MSG_ID_DG_USED_ACID_VOLUME_ML_OVERRIDE: handleTestUsedAcidVolumeMLOverrideRequest( message ); break; case MSG_ID_DG_USED_BICARB_VOLUME_ML_OVERRIDE: handleTestUsedBicarbVolumeMLOverrideRequest( message ); break; #ifndef _RELEASE_ case MSG_ID_DG_GET_SW_CONFIG_RECORD: handleGetDGSoftwareConfigRecord( message ); break; case MSG_ID_DG_SET_SW_CONFIG_RECORD: handleSetDGSoftwareConfigRecord( message ); break; #endif case MSG_ID_DG_FANS_DUTY_CYCLE_OVERRIDE: handleSetFansDutyCycleOverrideRequest( message ); break; case MSG_ID_DG_HD_COMMUNICATION_STATUS_OVERRIDE: handleTestHDCommunicationStatusOverrideRequest( message ); break; case MSG_ID_DG_SET_PRIMARY_AND_TRIMMER_HEATERS_TARGET_TEMP: handleSetPrimaryAndTrimmerHeatersTargetTemperature( message ); break; case MSG_ID_DG_GET_USAGE_INFO_RECORD: handleGetDGUsageInfoRecord( message ); break; case MSG_ID_DG_SET_USAGE_INFO_RECORD: handleSetDGUsageInfoRecord( message ); break; case MSG_ID_DG_SET_OP_MODE_REQUEST: handleTestSetOpModeRequest( message ); break; case MSG_ID_DG_RESERVOIR_TARE_REQUEST: handleTestTareReservoirRequest( message ); break; case MSG_ID_DG_GEN_IDLE_PUBLISH_INTERVAL_OVERRIDE: handleTestGenIdlePublishIntervalOverride( message ); break; case MSG_ID_DG_DRAIN_PUMP_CURRENT_OVERRIDE: handleSetDrainPumpMeasuredRPMOverrideRequest( message ); break; case MSG_ID_DG_DRAIN_PUMP_DIRECTION_OVERRIDE: handleTestDGDrainPumpDirectionOverrideRequest( message ); break; case MSG_ID_DG_CONC_PUMP_PARK_STATUS_OVERRIDE: handleTestDGConcPumpParkStatusOverrideRequest( message ); break; case MSG_ID_DG_CONC_PUMP_PARK_FAULT_STATUS_OVERRIDE: handleTestDGConcPumpParkFaultStatusOverrideRequest( message ); break; case MSG_ID_DG_CONC_PUMP_PARK_COMMAND: handleTestDGConcPumpParkCommandRequest( message ); break; case MSG_ID_DG_NV_RECORD_CRC_OVERRIDE: handleTestDGNVRecordCRCOverride( message ); break; case MSG_ID_DG_RO_FEEDBACK_VOLTAGE_OVERRIDE: handleTestDGROPumpFeedbackVoltageOverrideRequest( message ); break; case MSG_ID_DG_DIALYSATE_FILL_INTEGRATED_VOLUME_OVERRIDE: handleTestDGFillIntegratedVolumeOverrideRequest( message ); break; case MSG_ID_FILL_MODE_DATA_PUBLISH_INTERVAL_OVERRIDE: handleTestDGFillModeBroadcastOverrideRequest( message ); break; case MSG_ID_DG_HEATERS_DUTY_CYCLE_OVERRIDE: handleTestDGHeatersDutyCycleOverrideRequest( message ); break; case MSD_ID_DG_RTC_CTL_REG1_STATUS_OVERRIDE: handleDGRTCControlReg1StatusOverrideRequest( message ); break; case MSD_ID_DG_RTC_CTL_REG3_STATUS_OVERRIDE: handleDGRTCControlReg3StatusOverrideRequest( message ); break; #ifndef _RELEASE_ case MSG_ID_DG_NELSON_DISINFECT_SUPPORT: handleTestDGNelsonDisinfectSupport( message ); break; #endif case MSG_ID_DG_SET_DIALYSATE_MIXING_RATIOS: handleTestDGSetDialysateMixingRatios( message ); break; case MSG_ID_DG_SET_TEST_CONFIGURATION: handleTestDGSetTestConfig( message ); break; case MSG_ID_DG_GET_TEST_CONFIGURATION: handleTestDGGetTestConfig( message ); break; case MSG_ID_DG_RESET_ALL_TEST_CONFIGURATIONS: handleTestDGResetAllTestConfigs( message ); break; case MSG_ID_DG_DIALIN_CHECK_IN: handleTestDGDialinCheckIn( message ); break; case MSG_ID_DG_GET_LOAD_CELLS_TARE_VALUES: handleTestDGGetLoadCellsTareValues( message ); break; case MSG_ID_DG_SET_LOAD_CELLS_TARE_VALUES: handleTestDGSetLoadCellsTareValues( message ); break; case MSG_ID_DG_SET_COND_SENSOR_CAL_TABLE: handleTestDGSetConductivitySensorCalTable( message ); break; case MSG_ID_DG_SIGNAL_RECOVER_FROM_FAULT_MODE: handleTestDGSetRecoverFromFaultModeSignal( message ); break; case MSG_ID_DG_DRAIN_MODE_BROADCAST_INTERVAL_OVERRIDE: handleTestDGDrainModeBroadcastOverrideRequest( message ); break; case MSG_ID_DG_DIALIN_RO_ONLY_MODE_STATUS_REQUEST: handleDGROStatusRequest( message ); break; case MSG_ID_DG_RAM_STATUS_OVERRIDE: handleTestDGRAMStatusOverrideRequest( message ); break; case MSG_ID_DG_RESERVOIR_BROADCAST_INTERVAL_OVERRIDE: handleTestDGReservoirOverrideRequest( message ); break; case MSG_ID_DG_CAN_RECEIVE_ACK_MESSAGE_OVERRIDE: handleTestDGPendingACKOverrideRequest( message ); break; case MSG_ID_DG_STATE_TIMER_82C_OVERRIDE: handleTestDG82CStateTimerOverride( message ); break; case MSG_ID_DG_STATE_TIMER_77C_OVERRIDE: handleTestDG77CStateTimerOverride( message ); break; case MSG_ID_DG_CHEM_DISINFECT_ACID_OVERRIDE: handleTestChemDisinfectAcidOverride( message ); break; default: // TODO - unrecognized message ID received - ignore break; } } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetHDCommunicationStatus function sets the override * of the HD communication status. * @details Inputs: none * @details Outputs: hdCommunicationStatus * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testSetHDCommunicationStatus( U32 value ) { BOOL result = FALSE; if (TRUE == isTestingActivated() ) { result = TRUE; hdCommunicationStatus.ovData = value; hdCommunicationStatus.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetHDCommuncationStatus function resets the override * of the HD communication status. * @details Inputs: none * @details Outputs: hdCommunicationStatus * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetHDCommuncationStatus( void ) { BOOL result = FALSE; if (TRUE == isTestingActivated() ) { result = TRUE; hdCommunicationStatus.override = OVERRIDE_RESET; hdCommunicationStatus.ovData = hdCommunicationStatus.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetPendingACKOverride function overrides the * pendingACKOverride variable. * @details Inputs: none * @details Outputs: pendingACKOverride * @param value override for pendingACKOverride * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetPendingACKOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; pendingACKOverride.ovData = value; pendingACKOverride.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetPendingACKOverride function resets the override * of the pendingACKOverride variable. * @details Inputs: none * @details Outputs: pendingACKOverride * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetPendingACKOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; pendingACKOverride.override = OVERRIDE_RESET; pendingACKOverride.ovData = pendingACKOverride.ovInitData; } return result; } /**@}*/