Index: firmware/App/Services/CommBuffers.c =================================================================== diff -u -r5bec978fa9cce89bbf8c559f0844b7528a10c0d1 -rd5c5b1d2bc42b166f1ccff1aa4b2441db8f06d4b --- firmware/App/Services/CommBuffers.c (.../CommBuffers.c) (revision 5bec978fa9cce89bbf8c559f0844b7528a10c0d1) +++ firmware/App/Services/CommBuffers.c (.../CommBuffers.c) (revision d5c5b1d2bc42b166f1ccff1aa4b2441db8f06d4b) @@ -1,88 +1,115 @@ -/************************************************************************** - * - * 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) Dara Navaei +* @date (last) 02-Oct-2020 +* +* @author (original) Dara Navaei +* @date (original) 05-Nov-2019 +* +***************************************************************************/ #include #include // for memcpy() -#include "CommBuffers.h" +#include "CommBuffers.h" +#include "SystemComm.h" +#include "SystemCommMessages.h" +#include "Timers.h" +/** + * @addtogroup CommBuffers + * @{ + */ + // ********** 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 COMM_BUFFER_LENGTH 512 ///< max bytes in each comm buffer (each side of double buffer is this size) +#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 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 U32 firstBufferOverflowTimeStamp = 0; ///< time stamp of a prior overflow event - allows for an overflow persistence check // ********** private function prototypes ********** 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 * Outputs : CommBuffers module initialized. - * @param none * @return none *************************************************************************/ 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; - for ( d = 0; d < DOUBLE_BUFFERS; d++ ) - { - commBufferByteCount[ b ][ d ] = 0; - for ( i = 0; i < COMM_BUFFER_LENGTH; i++ ) - { - commBuffers[ b ][ d ][ i ] = 0; - } - } + clearBuffer( (COMM_BUFFER_T)b ); } } -/************************************************************************* - * @brief addToCommBuffer - * 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 - * This function should only be called from the background, general, or \n +/*********************************************************************//** + * @brief + * The clearBuffer function clears (empties) a given buffer. + * Caller should ensure buffer won't be used while this function is clearing + * the buffer. + * @details + * Inputs : none + * Outputs : given buffer is cleared. + * @param buffer the buffer to clear + * @return none + *************************************************************************/ +void clearBuffer( COMM_BUFFER_T buffer ) +{ + if ( buffer < NUM_OF_COMM_BUFFERS ) + { + S32 d; + + // thread protection for queue operations + _disable_IRQ(); + + activeDoubleBuffer[ buffer ] = 0; + for ( d = 0; d < DOUBLE_BUFFERS; d++ ) + { + commBufferByteCount[ buffer ][ d ] = 0; + memset( &commBuffers[ buffer ][ d ][ 0 ], 0, COMM_BUFFER_LENGTH ); + } + + // release thread protection + _enable_IRQ(); + } +} + +/*********************************************************************//** + * @brief + * The addToCommBuffer function adds data of specified length to a specified + * communication buffer. S/W fault if buffer too full to add data. + * This function will always add to the active double buffer. + * This function should only be called from the background, general, or * priority tasks (BG or IRQ) for thread safety. * @details * Inputs : commBufferByteCount[], activeDoubleBuffer[] * Outputs : commBuffers[], commBufferByteCount[] - * @param buffer : which comm buffer to add data to - * @param data : pointer to byte array containing data to add - * @param len : length of data (in bytes) + * @param buffer which comm buffer to add data to + * @param data pointer to byte array containing data to add + * @param len length of data (in bytes) * @return TRUE if data added to buffer successfully, FALSE if not *************************************************************************/ BOOL addToCommBuffer( COMM_BUFFER_T buffer, U08* data, U32 len ) @@ -92,65 +119,96 @@ // 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) + U32 currentActiveBufCount; // where to start adding new data to buffer (after existing data) + + if ( ( FALSE == isHDOnlyCANNode() ) || ( FALSE == isCANBoxForXmit( (CAN_MESSAGE_BOX_T)buffer ) ) ) + { + // thread protection for queue operations + _disable_IRQ(); - // add requires brief thread protection because there may be multiple sources for transmits trying to add data to a buffer. - _disable_IRQ(); - bufferGetLock[ buffer ] = TRUE; + activeBuffer = activeDoubleBuffer[ buffer ]; + currentActiveBufCount = commBufferByteCount[ buffer ][ activeBuffer ]; - activeBuffer = activeDoubleBuffer[ buffer ]; - currentActiveBufCount = commBufferByteCount[ buffer ][ activeBuffer ]; + // check to make sure buffer is not too full to service this add + if ( len <= ( COMM_BUFFER_LENGTH - currentActiveBufCount ) ) + { + U08 *buffPtr; // buffer destination for added data - // check to make sure buffer is not too full to service this add - if ( len <= ( COMM_BUFFER_LENGTH - currentActiveBufCount ) ) - { - U08 *buffPtr; // buffer destination for added data - - // set destination pointer to end of active buffer data - buffPtr = &commBuffers[ buffer ][ activeBuffer ][ currentActiveBufCount ]; - // copy source data to destination buffer - 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; + // set destination pointer to end of active buffer data + buffPtr = &commBuffers[ buffer ][ activeBuffer ][ currentActiveBufCount ]; + // copy source data to destination buffer + 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; + // data successfully added to buffer + result = TRUE; + } + else // buffer too full to add this much data + { + bufferFull = TRUE; + } // release thread protection - bufferGetLock[ buffer ] = FALSE; - _enable_IRQ(); - // data successfully added to buffer - result = TRUE; - } - else // buffer too full to add this much data + _enable_IRQ(); + } + + // if buffer was full, check persistence - trigger s/w fault if persists + if ( TRUE == bufferFull ) { - // 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 ) +#ifdef DEBUG_ENABLED + char debugStr[ 100 ]; + sprintf( debugStr, "Buf OF:#%3d,%3d, %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", buffer, len, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7] ); + sendDebugData( (U08*)debugStr, strlen(debugStr) ); + sendDebugDataToUI( (U08*)debugStr ); +#endif + clearBuffer( buffer ); + // 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_HD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_ADD_TOO_MUCH_DATA, (U32)buffer ) + } + } + else // first overflow - set time stamp for persistence check + { + firstBufferOverflowTimeStamp = getMSTimerCount(); + } } + 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_HD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_ADD_INVALID_BUFFER, buffer ) } return result; } -/************************************************************************* - * @brief getFromCommBuffer - * 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 - * double buffer first and, if needed, switch double buffers to draw the \n +/*********************************************************************//** + * @brief + * The getFromCommBuffer function fills a given byte array with a given + * number of bytes from a given buffer and returns the number of bytes + * retrieved from the buffer. This function will draw from the inactive + * double buffer first and, if needed, switch double buffers to draw the * rest of the requested data. - * Only one function in one thread should be calling this function for a given \n + * Only one function in one thread should be calling this function for a given * buffer. * @details * Inputs : commBuffers[], commBufferByteCount[], activeDoubleBuffer[] - * Outputs : commBuffers[], commBufferByteCount[], activeDoubleBuffer[], \n + * Outputs : commBuffers[], commBufferByteCount[], activeDoubleBuffer[], * and the given data array is populated with data from the buffer. - * @param buffer : which comm buffer to retrieve data from - * @param data : pointer to byte array to stuff data into - * @param len : # of bytes to retrieve into given data array. + * @param buffer which comm buffer to retrieve data from + * @param data pointer to byte array to stuff data into + * @param len number of bytes to retrieve into given data array. * @return the number of bytes retrieved. *************************************************************************/ U32 getFromCommBuffer( COMM_BUFFER_T buffer, U08* data, U32 len ) @@ -160,6 +218,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 ) ) ) { @@ -183,29 +243,31 @@ 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_HD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_GET_INVALID_BUFFER, buffer ) } return result; } -/************************************************************************* - * @brief peekFromCommBuffer - * 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 - * should be made before calling this function to determine how many bytes \n - * are currently in the buffer. Do not call this function with a "len" \n +/*********************************************************************//** + * @brief + * The peekFromCommBuffer function fills a given byte array with a given + * number of bytes from a given buffer. This function does NOT consume + * the bytes - it only peeks at them. A call to numberOfBytesInCommBuffer() + * should be made before calling this function to determine how many bytes + * are currently in the buffer. Do not call this function with a "len" * longer than what is currently in the buffer. * @details * Inputs : commBuffers[], commBufferByteCount[], activeDoubleBuffer[] - * Outputs : given array populated with requested # of bytes from the buffer. - * @param buffer : which comm buffer to retrieve data from - * @param data : pointer to byte array to stuff data into - * @param len : # of bytes to retrieve into given data array. + * Outputs : given array populated with requested number of bytes from the buffer. + * @param buffer which comm buffer to retrieve data from + * @param data pointer to byte array to stuff data into + * @param len number of bytes to retrieve into given data array. * @return the number of bytes retrieved. *************************************************************************/ U32 peekFromCommBuffer( COMM_BUFFER_T buffer, U08 *data, U32 len ) @@ -215,6 +277,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 ) ) ) { @@ -237,24 +301,26 @@ 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_HD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_PEEK_INVALID_BUFFER, buffer ) } return numOfBytesPeeked; } -/************************************************************************* - * @brief numberOfBytesInCommBuffer - * The numberOfBytesInCommBuffer function determines how many bytes \n - * are currently contained in a given comm buffer. Both double buffers \n +/*********************************************************************//** + * @brief + * The numberOfBytesInCommBuffer function determines how many bytes + * are currently contained in a given comm buffer. Both double buffers * are considered for this. * @details * Inputs : activeDoubleBuffer[], commBufferByteCount[] * Outputs : none - * @param buffer : which comm buffer to get byte count for + * @param buffer which comm buffer to get byte count for * @return the number of bytes in the given comm buffer. *************************************************************************/ U32 numberOfBytesInCommBuffer( COMM_BUFFER_T buffer ) @@ -267,33 +333,26 @@ U32 activeBuffer = activeDoubleBuffer[ buffer ]; U32 inactiveBuffer = GET_TOGGLE( activeBuffer, 0, 1 ); - if ( FALSE == bufferGetLock[ buffer ] ) - { - result = commBufferByteCount[ buffer ][ inactiveBuffer ] + commBufferByteCount[ buffer ][ activeBuffer ]; - } - else - { - result = commBufferByteCount[ buffer ][ inactiveBuffer ]; - } + result = commBufferByteCount[ buffer ][ inactiveBuffer ] + commBufferByteCount[ buffer ][ activeBuffer ]; } 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_HD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_COUNT_INVALID_BUFFER, buffer ) } return result; } -/************************************************************************* - * @brief switchDoubleBuffer - * 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 +/*********************************************************************//** + * @brief + * The switchDoubleBuffer function switches the active and inactive buffers + * for the given buffer. + * This function should only be called when the current inactive buffer has * been emptied. Any unconsumed data in inactive buffer will be lost. * @details * Inputs : activeDoubleBuffer[] * Outputs : activeDoubleBuffer[], commBufferByteCount[] - * @param buffer : which comm buffer to switch double buffers on + * @param buffer which comm buffer to switch double buffers on * @return the new active buffer for the given buffer. *************************************************************************/ static U32 switchDoubleBuffer( COMM_BUFFER_T buffer ) @@ -310,17 +369,17 @@ return inactiveBuffer; } -/************************************************************************* - * @brief getDataFromInactiveBuffer - * The getDataFromInactiveBuffer function retrieves a given number of bytes \n - * from the inactive buffer of a given buffer. This function should only be \n +/*********************************************************************//** + * @brief + * The getDataFromInactiveBuffer function retrieves a given number of bytes + * from the inactive buffer of a given buffer. This function should only be * called by getFromCommBuffer(). Params will be pre-validated there. * @details * Inputs : commBuffers[], activeDoubleBuffer[], commBufferByteCount[] * Outputs : commBuffers[], activeDoubleBuffer[], commBufferByteCount[] - * @param buffer : which comm buffer get data from - * @param data : pointer to byte array to populate with data - * @param len : # of bytes to get from comm buffer + * @param buffer which comm buffer get data from + * @param data pointer to byte array to populate with data + * @param len number of bytes to get from comm buffer * @return none *************************************************************************/ static void getDataFromInactiveBuffer( COMM_BUFFER_T buffer, U08 *data, U32 len ) @@ -347,3 +406,5 @@ switchDoubleBuffer( buffer ); // switch will zero count off inactive buffer } } + +/**@}*/