Index: firmware/App/Services/CommBuffers.c =================================================================== diff -u -rb64c49fdcf2b6d95e61e63f8e258c4e600935bbd -r0dec8744af40d0c87a6d7cd1923920c1c2bd1d2f --- firmware/App/Services/CommBuffers.c (.../CommBuffers.c) (revision b64c49fdcf2b6d95e61e63f8e258c4e600935bbd) +++ firmware/App/Services/CommBuffers.c (.../CommBuffers.c) (revision 0dec8744af40d0c87a6d7cd1923920c1c2bd1d2f) @@ -1,48 +1,48 @@ -/************************************************************************** - * - * Copyright (c) 2019-2020 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 CommBuffers.c - * - * @date 08-Oct-2019 - * @author S. Nash - * - * @brief CommBuffers service module. Provides data buffering functionality. \n - * Data coming in via CAN/UART Rx interrupts can be placed in a buffer to \n - * be processed at a later time. Data is double buffered to prevent \n - * contention between Rx/Tx interrupts and the processing thread(s). \n - * Data to be transmitted via CAN/UART can be placed in a buffer to be sent \n - * when the transmitter becomes available. \n - * If a buffer becomes too full to service more data, a s/w fault is triggered. - * - **************************************************************************/ +/************************************************************************** +* +* Copyright (c) 2019-2020 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 CommBuffers.c +* +* @author (last) Quang Nguyen +* @date (last) 21-Jul-2020 +* +* @author (original) Dara Navaei +* @date (original) 05-Nov-2019 +* +***************************************************************************/ #include // for memcpy() #include "CommBuffers.h" +#include "SystemCommMessages.h" +#include "Timers.h" // ********** private definitions ********** #define COMM_BUFFER_LENGTH 512 // max bytes in each comm buffer (double if you count double buffers) #define DOUBLE_BUFFERS 2 // need 2 buffers for double buffering +#define BUFFER_OVERFLOW_PERSISTENCE_MS 5000 // how many ms buffer overflows must persist before fault // ********** private data ********** static volatile U32 commBufferByteCount[ NUM_OF_COMM_BUFFERS ][ DOUBLE_BUFFERS ]; // for each buffer, how many bytes does it contain? (also index to next available) static volatile U32 activeDoubleBuffer[ NUM_OF_COMM_BUFFERS ]; // for each buffer, which double buffer is being fed right now? static U08 commBuffers[ NUM_OF_COMM_BUFFERS ][ DOUBLE_BUFFERS ][ COMM_BUFFER_LENGTH ]; // each is double buffered to avoid thread contention static volatile BOOL bufferGetLock[ NUM_OF_COMM_BUFFERS ]; // prevent getter from accessing active buffer while add in progress +static U32 firstBufferOverflowTimeStamp = 0; // time stamp of a prior overflow event - allows for an overflow persistence check // ********** private function prototypes ********** +static void clearBuffer( COMM_BUFFER_T buffer ); static U32 switchDoubleBuffer( COMM_BUFFER_T buffer ); static void getDataFromInactiveBuffer( COMM_BUFFER_T buffer, U08 *data, U32 len ); /************************************************************************* - * @brief initCommBuffers + * @brief * The initCommBuffers function initializes the CommBuffers module. * @details * Inputs : none @@ -52,25 +52,46 @@ *************************************************************************/ void initCommBuffers( void ) { - S32 b,d,i; + S32 b; // reset and zero out all buffers for ( b = 0; b < NUM_OF_COMM_BUFFERS; b++ ) { - activeDoubleBuffer[ b ] = 0; + clearBuffer( (COMM_BUFFER_T)b ); + } +} + +/************************************************************************* + * @brief + * The clearBuffer function clears (empties) a given buffer. \n + * Caller should ensure buffer won't be used while this function is clearing \n + * the buffer. + * @details + * Inputs : none + * Outputs : given buffer is cleared. + * @param buffer : the buffer to clear + * @return none + *************************************************************************/ +static void clearBuffer( COMM_BUFFER_T buffer ) +{ + if ( buffer < NUM_OF_COMM_BUFFERS ) + { + S32 d,i; + + activeDoubleBuffer[ buffer ] = 0; for ( d = 0; d < DOUBLE_BUFFERS; d++ ) { - commBufferByteCount[ b ][ d ] = 0; + commBufferByteCount[ buffer ][ d ] = 0; for ( i = 0; i < COMM_BUFFER_LENGTH; i++ ) { - commBuffers[ b ][ d ][ i ] = 0; + commBuffers[ buffer ][ d ][ i ] = 0; } } } } /************************************************************************* - * @brief addToCommBuffer + * @brief * The addToCommBuffer function adds data of specified length to a specified \n * communication buffer. S/W fault if buffer too full to add data. \n * This function will always add to the active double buffer. \n @@ -91,10 +112,11 @@ // verify given buffer if ( buffer < NUM_OF_COMM_BUFFERS ) { + BOOL bufferFull = FALSE; U32 activeBuffer; U32 currentActiveBufCount; // where to start adding new data to buffer (after existing data) - // add requires brief thread protection because there may be multiple sources for transmits trying to add data to a buffer. + // thread protection for queue operations _disable_IRQ(); bufferGetLock[ buffer ] = TRUE; @@ -112,30 +134,60 @@ memcpy( buffPtr, data, len ); // adjust buffer count per this data add (also reserves space to add data before releasing thread protection) commBufferByteCount[ buffer ][ activeBuffer ] += len; - // release thread protection - bufferGetLock[ buffer ] = FALSE; - _enable_IRQ(); // data successfully added to buffer result = TRUE; } else // buffer too full to add this much data { - // release thread protection - bufferGetLock[ buffer ] = FALSE; - _enable_IRQ(); - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_ADD_TOO_MUCH_DATA, len ) + bufferFull = TRUE; + clearBuffer( buffer ); } + // release thread protection + bufferGetLock[ buffer ] = FALSE; + _enable_IRQ(); + // if buffer was full, check persistence - trigger s/w fault if persists + if ( TRUE == bufferFull ) + { + // not first overflow? + if ( firstBufferOverflowTimeStamp != 0 ) + { + // if buffer overflows persists, fault + if ( calcTimeSince( firstBufferOverflowTimeStamp ) > BUFFER_OVERFLOW_PERSISTENCE_MS ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_ADD_TOO_MUCH_DATA, len ) + } + } + else // first overflow - set time stamp for persistence check + { + firstBufferOverflowTimeStamp = getMSTimerCount(); + } +#ifdef DEBUG_ENABLED + { + // TODO - temporary debug code - remove later + char debugStr[ 256 ]; + sprintf( debugStr, "Comm Buffer Overflow:%5d \n", (U32)buffer ); + sendDebugData( (U08*)debugStr, strlen(debugStr) ); + } +#endif + } + else + { // if good for persistence time period, reset persistence check + if ( ( firstBufferOverflowTimeStamp != 0 ) && ( calcTimeSince( firstBufferOverflowTimeStamp ) > BUFFER_OVERFLOW_PERSISTENCE_MS ) ) + { + firstBufferOverflowTimeStamp = 0; + } + } } else // invalid buffer given { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_ADD_INVALID_BUFFER, buffer ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_ADD_INVALID_BUFFER, buffer ) } return result; } /************************************************************************* - * @brief getFromCommBuffer + * @brief * The getFromCommBuffer function fills a given byte array with a given \n * number of bytes from a given buffer and returns the number of bytes \n * retrieved from the buffer. This function will draw from the inactive \n @@ -159,6 +211,8 @@ // verify given buffer if ( buffer < NUM_OF_COMM_BUFFERS ) { + // thread protection for queue operations + _disable_IRQ(); // verify requested # of bytes to get are in the buffer if ( ( len <= ( COMM_BUFFER_LENGTH * DOUBLE_BUFFERS ) ) && ( len <= numberOfBytesInCommBuffer( buffer ) ) ) { @@ -182,17 +236,19 @@ result += remNumOfBytes; } } + // release thread protection + _enable_IRQ(); } else // invalid buffer given { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_GET_INVALID_BUFFER, buffer ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_GET_INVALID_BUFFER, buffer ) } return result; } /************************************************************************* - * @brief peekFromCommBuffer + * @brief * The peekFromCommBuffer function fills a given byte array with a given \n * number of bytes from a given buffer. This function does NOT consume \n * the bytes - it only peeks at them. A call to numberOfBytesInCommBuffer() \n @@ -214,6 +270,8 @@ // verify given buffer if ( buffer < NUM_OF_COMM_BUFFERS ) { + // thread protection for queue operations + _disable_IRQ(); // verify requested # of bytes to peek are in the buffer if ( ( len <= ( COMM_BUFFER_LENGTH * DOUBLE_BUFFERS ) ) && ( len <= numberOfBytesInCommBuffer( buffer ) ) ) { @@ -236,17 +294,19 @@ numOfBytesPeeked = bytesInInactiveBuffer + remNumOfBytes; } } + // release thread protection + _enable_IRQ(); } else // invalid buffer given { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_PEEK_INVALID_BUFFER, buffer ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_PEEK_INVALID_BUFFER, buffer ) } return numOfBytesPeeked; } /************************************************************************* - * @brief numberOfBytesInCommBuffer + * @brief * The numberOfBytesInCommBuffer function determines how many bytes \n * are currently contained in a given comm buffer. Both double buffers \n * are considered for this. @@ -277,14 +337,14 @@ } else // invalid buffer { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_COUNT_INVALID_BUFFER, buffer ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_COUNT_INVALID_BUFFER, buffer ) } return result; } /************************************************************************* - * @brief switchDoubleBuffer + * @brief * The switchDoubleBuffer function switches the active and inactive buffers \n * for the given buffer. \n * This function should only be called when the current inactive buffer has \n @@ -310,7 +370,7 @@ } /************************************************************************* - * @brief getDataFromInactiveBuffer + * @brief * The getDataFromInactiveBuffer function retrieves a given number of bytes \n * from the inactive buffer of a given buffer. This function should only be \n * called by getFromCommBuffer(). Params will be pre-validated there.