Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -ra303cd4258157a8fbcbd8af4dd2bbaadec1a736c -r7acb9d914f79aaa921c95e1a4049594c889bf795 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision a303cd4258157a8fbcbd8af4dd2bbaadec1a736c) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 7acb9d914f79aaa921c95e1a4049594c889bf795) @@ -25,64 +25,131 @@ #include "SystemComm.h" #include "Comm.h" #include "Interrupts.h" -#include "MsgQueues.h" -#include "SystemCommMessages.h" +#include "Timers.h" #include "Utilities.h" +#include "SystemCommMessages.h" #ifdef RM46_EVAL_BOARD_TARGET #include "CPLD.h" #endif // ********** private definitions ********** -#define NUM_OF_CAN_OUT_BUFFERS 5 // # of CAN buffers for transmit -#define NUM_OF_CAN_IN_BUFFERS 3 // # of CAN buffers for receiving -#define NUM_OF_MSG_IN_BUFFERS 4 // # of Msg buffers for receiving +#define NUM_OF_CAN_OUT_BUFFERS 4 // # of CAN buffers for transmit +#define NUM_OF_CAN_IN_BUFFERS 6 // # of CAN buffers for receiving +#ifndef DEBUG_ENABLED + #define NUM_OF_MSG_IN_BUFFERS 6 // # of Msg buffers for receiving +#else + #define NUM_OF_MSG_IN_BUFFERS 7 // # of Msg buffers for receiving - 1 is UART + #define SCI1_RECEIVE_DMA_REQUEST 30 + #define SCI1_TRANSMIT_DMA_REQUEST 31 +#endif -#define SCI1_RECEIVE_DMA_REQUEST 30 -#define SCI1_TRANSMIT_DMA_REQUEST 31 +#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 HD_COMM_TIMEOUT_IN_MS 2000 + +#define MAX_COMM_CRC_FAILURES 5 +#define MAX_COMM_CRC_FAILURE_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) + +#define MSG_NOT_ACKED_TIMEOUT_MS ( MS_PER_SECOND * 1 ) +#define MSG_NOT_ACKED_MAX_RETRIES 3 +#define PENDING_ACK_LIST_SIZE 25 + +#pragma pack(push, 1) + +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 ********** 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_BROADCAST, - COMM_BUFFER_OUT_CAN_DG_2_PC, - COMM_BUFFER_OUT_UART_PC + COMM_BUFFER_OUT_CAN_DG_ALARM, + COMM_BUFFER_OUT_CAN_DG_2_HD, + COMM_BUFFER_OUT_CAN_DG_BROADCAST, + COMM_BUFFER_OUT_CAN_PC }; const COMM_BUFFER_T MSG_IN_BUFFERS[ NUM_OF_MSG_IN_BUFFERS ] = { - COMM_BUFFER_IN_CAN_HD_2_DG, - COMM_BUFFER_IN_CAN_PC_2_DG, - COMM_BUFFER_IN_UART_PC + 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_BROADCAST, + COMM_BUFFER_IN_CAN_PC, +#ifdef DEBUG_ENABLED + COMM_BUFFER_IN_UART_PC +#endif }; -static U08 pcXmitPacket[ PC_MESSAGE_PACKET_SIZE ] = { 0, 0, 0, 0, 0, 0, 0, 0 };// = { 1,2,3,4,5,6,7,8}; +static U08 lastCANPacketSent[ CAN_MESSAGE_PAYLOAD_SIZE ]; +static CAN_MESSAGE_BOX_T lastCANPacketSentChannel = (CAN_MESSAGE_BOX_T)0; +static U32 lastCANPacketSentTimeStamp = 0; + +#ifdef DEBUG_ENABLED +static U08 pcXmitPacket[ PC_MESSAGE_PACKET_SIZE ] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static U08 pcRecvPacket[ PC_MESSAGE_PACKET_SIZE ] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +#endif +static PENDING_ACK_RECORD_T pendingAckList[ PENDING_ACK_LIST_SIZE ]; // list of outgoing messages that are awaiting an ACK + // DMA control records -static g_dmaCTRL pcDMAXmitControlRecord; -static g_dmaCTRL pcDMARecvControlRecord; +static g_dmaCTRL pcDMAXmitControlRecord; // DMA transmit control record (UART-debug) +static g_dmaCTRL pcDMARecvControlRecord; // DMA receive control record (UART-debug) +static volatile BOOL hdIsCommunicating = FALSE; // has HD sent a message since last check +static volatile U32 timeOfLastHDCheckIn = 0; // last time we received an HD broadcast + +static U32 badCRCTimeStamps[ MAX_COMM_CRC_FAILURES ]; // time of last five bad message CRCs (wrapping list) +static U32 badCRCListIdx = 0; // where next bad message CRC time stamp will go in list +static U32 badCRCListCount = 0; // # of bad CRCs in the list + +#ifdef CAN_TEST +U08 dbgRcvdCANFrames[1024][8]; +U32 dbgRcvdCANFrameTS[1024]; +U32 dbgRcvdCANFrameIdx = 0; +U08 dbgXmitCANFrames[1024][8]; +U32 dbgXmitCANFrameTS[1024]; +U32 dbgXmitCANFrameIdx = 0; +#endif + // ********** private function prototypes ********** -static void initUARTAndDMA( void ); +#ifdef DEBUG_ENABLED + static void initUARTAndDMA( void ); + static U32 transmitNextUARTPacket( void ); +#endif + static BOOL isCANBoxForXmit( CAN_MESSAGE_BOX_T srcCANBox ); static BOOL isCANBoxForRecv( CAN_MESSAGE_BOX_T srcCANBox ); static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ); -static void transmitNextCANPacket( void ); -static void transmitNextUARTPacket( void ); +static U32 transmitNextCANPacket( void ); static void processIncomingData( void ); -static U32 parseMessageFromBuffer( U08 *data, U32 len ); +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 initSystemComm * The initSystemComm function initializes the SystemComm module. @@ -94,16 +161,46 @@ *************************************************************************/ void initSystemComm( void ) { + U32 i; + +#ifdef DEBUG_ENABLED // initialize UART and DMA for PC communication initUARTAndDMA(); +#endif - // TODO - remove this test code that sends a packet -// dmaSetCtrlPacket( DMA_CH3, pcDMAXmitControlRecord ); -// dmaSetChEnable( DMA_CH3, DMA_HW ); -// setSCI1DMATransmitInterrupt(); + // initialize bad message CRC list + for ( i = 0; i < MAX_COMM_CRC_FAILURES; i++ ) + { + badCRCTimeStamps[ i ] = 0; + } + + // 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 \n + * with the DG. + * @details + * Inputs : hdIsCommunicating + * Outputs : none + * @param none + * @return TRUE if HD has broadcast since last call, FALSE if not + *************************************************************************/ +BOOL isHDCommunicating( void ) +{ + BOOL result = hdIsCommunicating; + + hdIsCommunicating = FALSE; + + return result; +} + +/************************************************************************* * @brief execSystemCommRx * The execSystemCommRx function manages received data from other sub-systems. * @details @@ -119,6 +216,12 @@ // 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(); } /************************************************************************* @@ -138,12 +241,23 @@ { 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 ) ) + { + // TODO - depending on why we timed out, we may need to reset CAN controller??? + // assume last packet was not successfully transmitted. TODO - Re-send last packet? Or should we move on? + canTransmit( canREG1, lastCANPacketSentChannel, lastCANPacketSent ); + } + } +#ifdef DEBUG_ENABLED // if UART transmitter is idle, start transmitting any pending packets if ( FALSE == isSCI1DMATransmitInProgress() ) { transmitNextUARTPacket(); } +#endif } /************************************************************************* @@ -163,18 +277,47 @@ // message interrupt is for a transmit message box? if ( TRUE == isCANBoxForXmit( srcCANBox ) ) { - transmitNextCANPacket(); + U32 bytesXmitted = transmitNextCANPacket(); + + if ( 0 == bytesXmitted ) + { + signalCANXmitsCompleted(); + } } else if ( TRUE == isCANBoxForRecv( srcCANBox ) ) { - U08 data[CAN_MESSAGE_PAYLOAD_SIZE]; + U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; // get CAN packet received on given CAN message box if ( FALSE != canIsRxMessageArrived( canREG1, srcCANBox ) ) { - canGetData( canREG1, srcCANBox, data ); - // 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 ); + U32 result = canGetData( canREG1, srcCANBox, data ); + + // if packet retrieved, add to buffer + if ( result != 0 ) + { +#ifdef CAN_TEST + if ( dbgRcvdCANFrameIdx >= 1000 ) + { + result = 99; // Break point here + } + else + { + dbgRcvdCANFrameTS[dbgRcvdCANFrameIdx] = getMSTimerCount(); + memcpy( &dbgRcvdCANFrames[dbgRcvdCANFrameIdx][0], data, 8); + dbgRcvdCANFrameIdx++; + } +#endif +//#ifdef DEBUG_ENABLED +// if ( srcCANBox == COMM_BUFFER_IN_CAN_PC ) +// { +// memcpy( &dbgRcvFromDialin[dbgRcvFromDialinIdx], data, CAN_MESSAGE_PAYLOAD_SIZE); +// dbgRcvFromDialinIdx += CAN_MESSAGE_PAYLOAD_SIZE; +// } +//#endif + // 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 @@ -194,6 +337,7 @@ * @param none * @return none *************************************************************************/ +#ifdef DEBUG_ENABLED void handleUARTMsgRecvPacketInterrupt( void ) { // buffer received packet @@ -203,6 +347,7 @@ dmaSetChEnable( DMA_CH1, DMA_HW ); setSCI1DMAReceiveInterrupt(); } +#endif /************************************************************************* * @brief handleUARTMsgXmitPacketInterrupt @@ -214,10 +359,17 @@ * @param none * @return none *************************************************************************/ +#ifdef DEBUG_ENABLED void handleUARTMsgXmitPacketInterrupt( void ) { - transmitNextUARTPacket(); + U32 bytesXmitted = transmitNextUARTPacket(); + + if ( 0 == bytesXmitted ) + { + signalSCI1XmitsCompleted(); + } } +#endif /************************************************************************* * @brief initUARTAndDMA @@ -229,6 +381,7 @@ * @param none * @return none *************************************************************************/ +#ifdef DEBUG_ENABLED static void initUARTAndDMA( void ) { // Enable DMA block transfer complete interrupts @@ -282,6 +435,7 @@ dmaSetChEnable( DMA_CH1, DMA_HW ); setSCI1DMAReceiveInterrupt(); } +#endif /************************************************************************* * @brief isCANBoxForXmit @@ -300,7 +454,7 @@ for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) { - if ( CAN_OUT_BUFFERS[i] == srcCANBox ) + if ( CAN_OUT_BUFFERS[ i ] == srcCANBox ) { result = TRUE; break; @@ -327,7 +481,7 @@ for ( i = 0; i < NUM_OF_CAN_IN_BUFFERS; i++ ) { - if ( MSG_IN_BUFFERS[i] == srcCANBox ) + if ( MSG_IN_BUFFERS[ i ] == srcCANBox ) { result = TRUE; break; @@ -362,9 +516,9 @@ // 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 ) + if ( numberOfBytesInCommBuffer( CAN_OUT_BUFFERS[ i ] ) >= CAN_MESSAGE_PAYLOAD_SIZE ) { - result = CAN_OUT_BUFFERS[i]; + result = CAN_OUT_BUFFERS[ i ]; break; // found highest priority packet to transmit - we're done } } @@ -380,25 +534,59 @@ * Inputs : Output CAN Comm Buffers * Outputs : CAN packet transmit initiated. * @param msg : none - * @return none + * @return # of bytes transmitted *************************************************************************/ -static void transmitNextCANPacket( void ) +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]; + 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 ) { - canTransmit( canREG1, mBox, data ); + // 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(); +#ifdef CAN_TEST + if ( dbgXmitCANFrameIdx > 1000 ) + { + dataSize = 99; // Break point here + } + else + { + dbgXmitCANFrameTS[dbgXmitCANFrameIdx] = getMSTimerCount(); + memcpy( &dbgXmitCANFrames[dbgXmitCANFrameIdx][0], data, 8); + dbgXmitCANFrameIdx++; + } +#endif + if ( 0 != canTransmit( canREG1, mBox, data ) ) + { + result = CAN_MESSAGE_PAYLOAD_SIZE; + } + else + { + signalCANXmitsCompleted(); + // TODO - shouldn't get here, but let's see if we do + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_SOFTWARE_FAULT, (U32)mBox ) + } } + else + { // TODO - shouldn't get here - just testing - set first data to new s/w fault enum later + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, (U32)buffer, (U32)dataSize ) + } } + + return result; } /************************************************************************* @@ -409,20 +597,33 @@ * Inputs : Output UART Comm Buffer(s) * Outputs : UART DMA transmit initiated. * @param msg : none - * @return none + * @return # of bytes transmitted *************************************************************************/ -static void transmitNextUARTPacket( void ) +#ifdef DEBUG_ENABLED +static U32 transmitNextUARTPacket( void ) { - U32 dataSize = getFromCommBuffer( COMM_BUFFER_OUT_UART_PC, pcXmitPacket, PC_MESSAGE_PACKET_SIZE ); + U32 result = 0; + U32 dataPend = numberOfBytesInCommBuffer( COMM_BUFFER_OUT_UART_PC ); + U32 dataSize; - // if there's another UART packet to send, send it - if ( dataSize == PC_MESSAGE_PACKET_SIZE ) + if ( dataPend >= PC_MESSAGE_PACKET_SIZE ) { - dmaSetCtrlPacket( DMA_CH3, pcDMAXmitControlRecord ); - dmaSetChEnable( DMA_CH3, DMA_HW ); - setSCI1DMATransmitInterrupt(); + dataSize = getFromCommBuffer( COMM_BUFFER_OUT_UART_PC, pcXmitPacket, PC_MESSAGE_PACKET_SIZE ); + + // if there's another UART packet to send, send it + if ( dataSize == PC_MESSAGE_PACKET_SIZE ) + { + signalSCI1XmitsInitiated(); + dmaSetCtrlPacket( DMA_CH3, pcDMAXmitControlRecord ); + dmaSetChEnable( DMA_CH3, DMA_HW ); + setSCI1DMATransmitInterrupt(); + result = PC_MESSAGE_PACKET_SIZE; + } } + + return result; } +#endif /************************************************************************* @@ -442,8 +643,9 @@ *************************************************************************/ static void processIncomingData( void ) { - U08 data[sizeof(MESSAGE_WRAPPER_T)+1]; + 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++ ) @@ -458,42 +660,57 @@ 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] ); + consumeBufferPaddingBeforeSync( MSG_IN_BUFFERS[ i ] ); // do we have enough bytes in buffer for smallest message? - numOfBytesInBuffer = numberOfBytesInCommBuffer( MSG_IN_BUFFERS[i] ); + 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) ); - U32 msgSize = parseMessageFromBuffer( data, bytesPeeked ); + U32 bytesPeeked = peekFromCommBuffer( MSG_IN_BUFFERS[ i ], data, MIN( numOfBytesInBuffer, sizeof( MESSAGE_WRAPPER_T ) + 1 ) ); + S32 msgSize = parseMessageFromBuffer( data, bytesPeeked ); - if ( msgSize > 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 ); - // if message data is at least minimum size, convert received message data to a message and add to message queue - if ( msgSize > MESSAGE_OVERHEAD_SIZE ) + 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 == i ) { - MESSAGE_WRAPPER_T rcvMsg; - U08 *dataPtr = data+1; // skip over sync byte - - messagesInBuffer = TRUE; - // 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 cargo 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 ); - } // message is at least as large as minimum size + hdIsCommunicating = 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(); + } } /************************************************************************* @@ -536,35 +753,42 @@ * Outputs : none * @param data : pointer to byte array to search for a message * @param len : # of bytes in the data to search - * @return size of message if found, zero if no complete message found. + * @return size of message if found, zero if no complete message found, \n + * -1 if message found but CRC fails. *************************************************************************/ -static U32 parseMessageFromBuffer( U08 *data, U32 len ) +static S32 parseMessageFromBuffer( U08 *data, U32 len ) { U32 i; - U32 cargoSize; + U32 payloadSize; U32 msgSize; - U32 result = 0; + S32 result = 0; for ( i = 0; i < len; i++ ) { // find sync byte - if ( MESSAGE_SYNC_BYTE == data[i] ) + 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 ) { - cargoSize = data[pos+sizeof(U16)]; - msgSize = MESSAGE_OVERHEAD_SIZE + cargoSize; + 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 ) - { - result = msgSize; // we found a complete message of this size + { // 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; } } @@ -592,43 +816,219 @@ // see if any messages received isThereMsgRcvd = getFromMsgQueue( MSG_Q_IN, &message ); if ( TRUE == isThereMsgRcvd ) - { - // TODO - check CRC before processing a message and if it fails we will... + { // 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 ) ) { - processReceivedMessage( &message.msg ); + // if ACK, mark pending message ACK'd + if ( MSG_ID_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 ); + } + else + { // otherwise, process the received message + processReceivedMessage( &message.msg ); + } + } } else // CRC failed { - // TODO - probably wouldn't want to fault on this. ignore? + checkTooManyBadMsgCRCs(); } } } +} - // TODO - process UART (script) messages too +/************************************************************************* + * @brief checkForCommTimeouts + * The checkForCommTimeouts function checks for sub-system communication \n + * timeout errors. + * @details + * Inputs : timeOfLastDGCheckIn, timeOfLastUICheckIn + * Outputs : possibly a comm t/o alarm + * @param none + * @return none + *************************************************************************/ +static void checkForCommTimeouts( void ) +{ + if ( TRUE == didTimeout( timeOfLastHDCheckIn, HD_COMM_TIMEOUT_IN_MS ) ) + { + //activateAlarmNoData( ALARM_ID_HD_COMM_TIMEOUT ); // TODO - add this alarm + } } /************************************************************************* + * @brief checkTooManyBadMsgCRCs + * The checkTooManyBadMsgCRCs function checks for too many bad message CRCs \n + * within a set period of time. Assumed function is being called when a new \n + * bad CRC is detected so a new bad CRC will be added to the list. + * @details + * Inputs : badCRCTimeStamps[], badCRCListIdx, badCRCListCount + * Outputs : possibly a "too many bad CRCs" alarm + * @return none + *************************************************************************/ +static void checkTooManyBadMsgCRCs( void ) +{ + U32 listTimeInMS; +#ifdef CAN_TEST + static U32 crcErrorCtr = 0; + crcErrorCtr++; +#endif + + // replace oldest bad CRC in list with this new one + badCRCTimeStamps[ badCRCListIdx ] = getMSTimerCount(); + // move list index to next position (may wrap) + badCRCListIdx = INC_WRAP( badCRCListIdx, 0, MAX_COMM_CRC_FAILURES - 1 ); + // update list count + badCRCListCount = INC_CAP( badCRCListCount, MAX_COMM_CRC_FAILURES ); + // check if too many bad CRCs in window of time + listTimeInMS = calcTimeSince( badCRCTimeStamps[ badCRCListIdx ] ); + if ( ( badCRCListCount >= MAX_COMM_CRC_FAILURES ) && ( listTimeInMS <= MAX_COMM_CRC_FAILURE_WINDOW_MS ) ) + { +#ifndef DISABLE_CRC_ERROR +#ifndef CAN_TEST + activateAlarmNoData( ALARM_ID_COMM_TOO_MANY_BAD_CRCS ); +#endif +#endif + } +} + +/************************************************************************* + * @brief addMsgToPendingACKList + * The addMsgToPendingACKList function adds a given message to the pending \n + * ACK list. Messages in this list will require receipt of an ACK message \n + * for this particular message within a limited time. + * @details + * Inputs : pendingAckList[] + * 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 : # 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 matchACKtoPendingACKList + * The matchACKtoPendingACKList function searches the pending ACK list to \n + * see if the sequence # from a received ACK msg matches any. If found, \n + * the list entry is removed. + * @details + * Inputs : pendingAckList[] + * 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 checkPendingACKList + * The checkPendingACKList function searches the pending ACK list to \n + * see if any have expired. Any such messages will be queued for retransmission \n + * and if max retries reached a fault is triggered. + * @details + * Inputs : pendingAckList[] + * Outputs : pendingAckList[] + * @param none + * @return none + *************************************************************************/ +static void checkPendingACKList( void ) +{ + U32 i; + + // find expired messages pending ACK + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + if ( ( TRUE == pendingAckList[ i ].used ) && ( TRUE == didTimeout( pendingAckList[ i ].timeStamp, MSG_NOT_ACKED_TIMEOUT_MS ) ) ) + { + if ( pendingAckList[ i ].retries > 0 ) + { // re-queue message for transmit + pendingAckList[ i ].retries--; + pendingAckList[ i ].timeStamp = getMSTimerCount(); + addToCommBuffer( pendingAckList[ i ].channel, pendingAckList[ i ].msg, pendingAckList[ i ].msgSize ); + } + else + { + U16 msgID; + + memcpy( &msgID, &pendingAckList[ i ].msg[ sizeof( U08 ) + sizeof( U16) ], sizeof( U16 ) ); + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_CAN_MESSAGE_NOT_ACKED, (U32)msgID ); + } + } + } +} + +/************************************************************************* * @brief processReceivedMessage * The processReceivedMessage function processes a given message. * @details * Inputs : none * Outputs : message processed - * @param msg : + * @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 MSD_ID_DG_FILL_START_STOP: - handleDGFillStartStopMessages( message ); - break; - - case MSG_ID_TESTER_LOGIN_REQUEST: + case MSG_ID_DG_TESTER_LOGIN_REQUEST: handleTesterLogInRequest( message ); break; @@ -638,25 +1038,46 @@ } // handle any test messages if tester has logged in successfully - if ( ( msgID > MSG_ID_FIRST_TESTER_MESSAGE ) && ( TRUE == isTestingActivated() ) ) + if ( ( msgID > MSG_ID_FIRST_DG_TESTER_MESSAGE ) && ( msgID <= END_OF_MSG_IDS ) && ( TRUE == isTestingActivated() ) ) { switch ( msgID ) { - case MSG_ID_HD_MESSAGE: - handleTestHDMessageRequest( message ); + case MSG_ID_DG_MESSAGE: + handleTestDGMessageRequest( message ); break; - case MSG_ID_ALARM_LAMP_PATTERN_OVERRIDE: - handleTestAlarmLampPatternOverrideRequest( message ); + case MSG_ID_DG_WATCHDOG_TASK_CHECKIN_OVERRIDE: + handleTestWatchdogCheckInStateOverrideRequest( message ); break; - case MSG_ID_WATCHDOG_TASK_CHECKIN_OVERRIDE: - handleTestWatchdogCheckInStateOverrideRequest( message ); + case MSG_ID_ALARM_STATE_OVERRIDE: + handleTestAlarmStateOverrideRequest( message ); break; + case MSG_ID_DG_SET_RTC_DATE_TIME: + handleSetRTCTimestamp( message ); + break; + + case MSG_ID_LOAD_CELL_A1_OVERRIDE: + handleTestLoadCellA1OverrideRequest( message ); + break; + + case MSG_ID_LOAD_CELL_A2_OVERRIDE: + handleTestLoadCellA2OverrideRequest( message ); + break; + + case MSG_ID_LOAD_CELL_B1_OVERRIDE: + handleTestLoadCellB1OverrideRequest( message ); + break; + + case MSG_ID_LOAD_CELL_B2_OVERRIDE: + handleTestLoadCellB2OverrideRequest( message ); + break; + default: // TODO - unrecognized message ID received - ignore break; } } } +