/************************************************************************** * * Copyright (c) 2019-2019 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 interrupt and the thread that is consuming the data \n * at a later time. \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. * **************************************************************************/ #include "Common.h" #include "CommBuffers.h" // ********** private definitions ********** // ********** private data ********** static U32 commBufferByteCount[NUM_OF_COMM_BUFFERS][2]; // for each buffer, how many bytes does it contain? (also index to next available) static U32 activeDoubleBuffers[NUM_OF_COMM_BUFFERS]; // for each buffer, which double buffer is being fed right now? static U08 commBuffers[NUM_OF_COMM_BUFFERS][2][COMM_BUFFER_LENGTH]; // each is double buffered to avoid thread contention // ********** private function prototypes ********** static U32 switchDoubleBuffer( COMM_BUFFER_T buffer ); static U32 getRemainingByteCapacity( COMM_BUFFER_T buffer ); static BOOL isCommBufferEmpty( COMM_BUFFER_T buffer ); /************************************************************************* * @brief initCommBuffers * The initCommBuffers function initializes the CommBuffers module. * @details * Inputs : none * Outputs : CommBuffers module initialized. * @param none * @return none *************************************************************************/ void initCommBuffers( void ) { S32 b,l,d; // reset and zero out all buffers for ( b = 0; b < NUM_OF_COMM_BUFFERS; b++ ) { activeDoubleBuffers[b] = 0; for ( d = 0; d < 2; d++ ) { commBufferByteCount[b][d] = 0; for ( l = 0; l < COMM_BUFFER_LENGTH; l++ ) { commBuffers[b][d][l] = 0; } } } } /************************************************************************* * @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 * Only one function in one thread should be calling this function. It is \n * assumed that this thread will be higher priority than the thread calling \n * the getFromCommBuffer() function so no thread protection is given. * @details * Inputs : commBufferByteCount[], activeDoubleBuffers[] * 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) * @return TRUE if data added to buffer successfully, FALSE if not *************************************************************************/ BOOL addToCommBuffer( COMM_BUFFER_T buffer, U08* data, U32 len ) { BOOL result = FALSE; U32 activeBuffer = activeDoubleBuffers[buffer]; // verify given buffer if ( buffer < NUM_OF_COMM_BUFFERS ) { // check to make sure buffer is not too full to service this add if ( len <= getRemainingByteCapacity( buffer ) ) { U08 *buffPtr; // buffer destination for added data U08 *srcPtr; // data source U32 dstIndex; // where to start adding bytes in destination buffer U32 i; // get destination pointer to first available byte in buffer dstIndex = commBufferByteCount[buffer][activeBuffer]; buffPtr = &commBuffers[buffer][activeBuffer][dstIndex]; // get source pointer to start of given data array srcPtr = data; // copy source data to destination buffer for ( i = 0; i < len; i++ ) { *buffPtr++ = *srcPtr++; } // adjust buffer count per this data add commBufferByteCount[buffer][activeBuffer] += len; // data successfully added to buffer result = TRUE; } else // buffer too full to add this much data { // TODO - s/w fault? } } else // invalid buffer given { // TODO - s/w fault } return result; } /************************************************************************* * @brief getFromCommBuffer * The getFromCommBuffer function fills a given byte array with data from \n * a given buffer and returns the number of bytes retrieved from the buffer. \n * Only one function in one thread should be calling this function. * @details * Inputs : commBuffers[], commBufferByteCount[] * Outputs : commBufferByteCount[], activeDoubleBuffers[] * @param buffer : which comm buffer to retrieve data from * @param data : pointer to byte array to stuff data into * @param maxLen : maximum # of bytes to retrieve into given data array. * @return the number of bytes retrieved. *************************************************************************/ U32 getFromCommBuffer( COMM_BUFFER_T buffer, U08* data, U32 maxLen ) { U32 result = 0; // verify given buffer if ( buffer < NUM_OF_COMM_BUFFERS ) { // check to see if anything in buffer if ( FALSE == isCommBufferEmpty( buffer ) ) { // switch double buffer (now we'll read from what was active buffer and Rx interrupts will feed new active buffer) U32 activeBuffer = switchDoubleBuffer( buffer ); U32 inactiveBuffer = ( activeBuffer == 0 ? 1 : 0 ); U32 bytesRetrieved = commBufferByteCount[buffer][inactiveBuffer]; // ensure caller's data buffer can hold the data we have to retrieve if ( bytesRetrieved <= maxLen ) { U08 *buffPtr; // buffer source for retrieved data U08 *dstPtr; // buffer destination for retrieved data U32 i; // get source pointer to start of comm buffer buffPtr = &commBuffers[buffer][inactiveBuffer][0]; // get destination pointer to start of given data array dstPtr = data; // copy source data to destination buffer for ( i = 0; i < bytesRetrieved; i++ ) { *dstPtr++ = *buffPtr++; } // reset inactive buffer after data retrieved from it commBufferByteCount[buffer][inactiveBuffer] = 0; // set result to # of bytes received result = bytesRetrieved; } else // not enough space in caller's buffer { // TODO - s/w fault? } } else // buffer is empty { // result already set to zero } } else // invalid buffer given { // TODO - s/w fault } return result; } /************************************************************************* * @brief switchDoubleBuffer * The switchDoubleBuffer function switches the active and inactive buffers \n * for the given buffer. * @details * Inputs : activeDoubleBuffers[] * Outputs : activeDoubleBuffers[], commBufferByteCount[] * @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 ) { U32 activeBuffer = activeDoubleBuffers[buffer]; U32 inactiveBuffer = ( activeBuffer == 0 ? 1 : 0 ); // ensure inactive buffer is reset before making active commBufferByteCount[buffer][inactiveBuffer] = 0; // switch buffers activeDoubleBuffers[buffer] = inactiveBuffer; // return the new active buffer (was just inactive) return inactiveBuffer; } /************************************************************************* * @brief getRemainingByteCapacity * The getRemainingByteCapacity function determines the remaining capacity \n * of the given buffer. * @details * Inputs : commBufferByteCount[], activeDoubleBuffers[] * Outputs : none * @param buffer : which comm buffer to check the capacity of * @return the number of bytes of capacity remaining in the buffer. *************************************************************************/ static U32 getRemainingByteCapacity( COMM_BUFFER_T buffer ) { U32 result; U32 activeBuffer = activeDoubleBuffers[buffer]; result = COMM_BUFFER_LENGTH - commBufferByteCount[buffer][activeBuffer]; return result; } /************************************************************************* * @brief isCommBufferEmpty * The isCommBufferEmpty function determines whether a given comm buffer \n * is empty. * @details * Inputs : commBufferByteCount[], activeDoubleBuffers[] * Outputs : none * @param buffer : which comm buffer to check for empty * @return TRUE if the given comm buffer is empty, FALSE if not *************************************************************************/ static BOOL isCommBufferEmpty( COMM_BUFFER_T buffer ) { BOOL result = FALSE; U32 activeBuffer = activeDoubleBuffers[buffer]; if ( commBufferByteCount[buffer][activeBuffer] == 0 ) { result = TRUE; } return result; }