Index: CommBuffers.c =================================================================== diff -u --- CommBuffers.c (revision 0) +++ CommBuffers.c (revision 423aa34698d30a44e3b12b74e4243c3a8b5821de) @@ -0,0 +1,445 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 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) Sean +* @date (last) 30-Jul-2024 +* +* @author (original) Sean +* @date (original) 30-Jul-2024 +* +***************************************************************************/ + +#include // For memcpy() + +#include "CommBuffers.h" +#include "Messaging.h" +#ifdef _TD_ +#include "SystemCommTD.h" +#endif +#ifdef _DD_ +#include "SystemCommDD.h" +#endif +#ifdef _RO_ +#include "SystemCommRO.h" +#endif +#include "Timers.h" + +/** + * @addtogroup CommBuffers + * @{ + */ + +// ********** private definitions ********** + +#define COMM_BUFFER_LENGTH 768 ///< 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 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 + * The initCommBuffers function initializes the CommBuffers unit. + * @details Inputs: none + * @details Outputs: CommBuffers unit initialized. + * @return none + *************************************************************************/ +void initCommBuffers( void ) +{ + S32 b; + + // Reset and zero out all buffers + for ( b = 0; b < NUM_OF_COMM_BUFFERS; b++ ) + { + clearBuffer( (COMM_BUFFER_T)b ); + } +} + +/*********************************************************************//** + * @brief + * The clearBuffer function clears (empties) a given buffer. + * @note This function is thread safe. IRQ interrupts are disabled while + * buffers are being cleared. + * @details Inputs: none + * @details Outputs: given buffer is cleared. + * @param buffer ID of 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 given + * communication buffer. + * @note This function will add to the active side of the double buffer. + * @note This function is thread safe. IRQ interrupts are disabled during + * buffer operations. + * @details Alarm: ALARM_ID_XX_SOFTWARE_FAULT if given buffer is invalid or + * it is full. + * @details Inputs: commBufferByteCount[], activeDoubleBuffer[] + * @details Outputs: commBuffers[], commBufferByteCount[] + * @param buffer ID of buffer to add data to + * @param data Pointer to byte array containing data to add to buffer + * @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; + + // 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) + + if ( ( FALSE == isOnlyCANNode() ) || ( FALSE == isCANBoxForXmit( (CAN_MESSAGE_BOX_T)buffer ) ) ) + { + // Thread protection for queue operations + _disable_IRQ(); + + 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 + + // 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 + _enable_IRQ(); + } + + // If buffer was full, check persistence - trigger s/w fault if persists + if ( TRUE == bufferFull ) + { + 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_TD_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 + { +#ifdef _TD_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_ADD_INVALID_BUFFER, buffer ) +#endif +#ifdef _DD_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_ADD_INVALID_BUFFER, buffer ) +#endif +#ifdef _RO_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_ADD_INVALID_BUFFER, buffer ) +#endif + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getFromCommBuffer function fills a given byte array with a specified + * number of bytes from a given buffer and returns the number of bytes + * retrieved from the buffer. + * @note This function will draw from the inactive side of the double buffer + * and, if needed, switch double buffers to draw the rest of the requested data. + * @note This function is thread safe. IRQ interrupts are disabled during buffer + * operations. + * @details Alarm: ALARM_ID_XX_SOFTWARE_FAULT if given buffer is invalid. + * @details Inputs: commBuffers[], commBufferByteCount[], activeDoubleBuffer[] + * @details Outputs: commBuffers[], commBufferByteCount[], activeDoubleBuffer[], + * and the given data array is populated with data from the buffer. + * @param buffer ID of buffer to retrieve data from + * @param data Pointer to byte array to populate with buffer data + * @param len Number of bytes to retrieve from buffer into given byte array. + * @return the number of bytes retrieved. + *************************************************************************/ +U32 getFromCommBuffer( COMM_BUFFER_T buffer, U08* data, U32 len ) +{ + U32 result = 0; + + // 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 ) ) ) + { + U32 activeBuffer = activeDoubleBuffer[ buffer ]; + U32 inactiveBuffer = GET_TOGGLE( activeBuffer, 0, 1 ); + U32 bytesInInactiveBuffer = commBufferByteCount[ buffer ][ inactiveBuffer ]; + U32 sizeOfFirstConsumption = MIN( len, bytesInInactiveBuffer ); + + // See what we can get from inactive buffer + getDataFromInactiveBuffer( buffer, data, sizeOfFirstConsumption ); // Will switch double buffers if we empty inactive buffer + // Will return # of bytes consumed + result = sizeOfFirstConsumption; + // Do we need more from active buffer? + if ( len > sizeOfFirstConsumption ) + { + U32 remNumOfBytes = len - sizeOfFirstConsumption; + U08 *remPtr = data + sizeOfFirstConsumption; + + getDataFromInactiveBuffer( buffer, remPtr, remNumOfBytes ); + // Will return # of bytes consumed + result += remNumOfBytes; + } + } + // Release thread protection + _enable_IRQ(); + } + else // Invalid buffer given + { +#ifdef _TD_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_GET_INVALID_BUFFER, buffer ) +#endif +#ifdef _DD_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_GET_INVALID_BUFFER, buffer ) +#endif +#ifdef _RO_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_GET_INVALID_BUFFER, buffer ) +#endif + } + + return result; +} + +/*********************************************************************//** + * @brief + * The peekFromCommBuffer function fills a given byte array with a given + * number of bytes from a given buffer. + * @note This function does NOT consume the bytes - it only peeks at them. + * A call to numberOfBytesInCommBuffer() should be made prior to calling + * this function to determine how many bytes are currently in the buffer. + * @warning Do not call this function with a "len" greater than the number + * of bytes currently in the buffer. + * @details Alarm: ALARM_ID_XX_SOFTWARE_FAULT if given buffer is invalid. + * @details Inputs: commBuffers[], commBufferByteCount[], activeDoubleBuffer[] + * @details Outputs: given array populated with requested number of bytes from the buffer. + * @param buffer ID of buffer to retrieve data from + * @param data Pointer to byte array to populate with buffer data + * @param len Number of bytes to retrieve from the given buffer. + * @return the number of bytes retrieved. + *************************************************************************/ +U32 peekFromCommBuffer( COMM_BUFFER_T buffer, U08 *data, U32 len ) +{ + U32 numOfBytesPeeked = 0; + + // 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 ) ) ) + { + U32 activeBuffer = activeDoubleBuffer[ buffer ]; + U32 inactiveBuffer = GET_TOGGLE( activeBuffer, 0, 1 ); + U32 bytesInInactiveBuffer = commBufferByteCount[ buffer ][ inactiveBuffer ]; + + if ( len <= bytesInInactiveBuffer ) + { + memcpy( data, &commBuffers[ buffer ][ inactiveBuffer ][ 0 ], len ); + numOfBytesPeeked = len; + } + else // Will need to get the rest from active buffer + { + U32 remNumOfBytes = len - bytesInInactiveBuffer; + U08 *remPtr = data + bytesInInactiveBuffer; + + memcpy( data, &commBuffers[ buffer ][ inactiveBuffer ][ 0 ], bytesInInactiveBuffer ); + memcpy( remPtr, &commBuffers[ buffer ][ activeBuffer ][ 0 ], remNumOfBytes ); + numOfBytesPeeked = bytesInInactiveBuffer + remNumOfBytes; + } + } + // Release thread protection + _enable_IRQ(); + } + else // Invalid buffer given + { +#ifdef _TD_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_PEEK_INVALID_BUFFER, buffer ) +#endif +#ifdef _DD_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_PEEK_INVALID_BUFFER, buffer ) +#endif +#ifdef _RO_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_PEEK_INVALID_BUFFER, buffer ) +#endif + } + + return numOfBytesPeeked; +} + +/*********************************************************************//** + * @brief + * The numberOfBytesInCommBuffer function determines how many bytes + * are currently contained in a given comm buffer. Both sides of the + * double buffers are considered for this. + * @details Alarm: ALARM_ID_XX_SOFTWARE_FAULT if given buffer is invalid. + * @details Inputs: activeDoubleBuffer[], commBufferByteCount[] + * @details Outputs: none + * @param buffer ID of buffer to get byte count for + * @return the number of bytes currently in the given comm buffer. + *************************************************************************/ +U32 numberOfBytesInCommBuffer( COMM_BUFFER_T buffer ) +{ + U32 result = 0; + + // Verify given buffer + if ( buffer < NUM_OF_COMM_BUFFERS ) + { + U32 activeBuffer = activeDoubleBuffer[ buffer ]; + U32 inactiveBuffer = GET_TOGGLE( activeBuffer, 0, 1 ); + + result = commBufferByteCount[ buffer ][ inactiveBuffer ] + commBufferByteCount[ buffer ][ activeBuffer ]; + } + else // Invalid buffer + { +#ifdef _TD_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_COUNT_INVALID_BUFFER, buffer ) +#endif +#ifdef _DD_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_COUNT_INVALID_BUFFER, buffer ) +#endif +#ifdef _RO_ + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_RO_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_COUNT_INVALID_BUFFER, buffer ) +#endif + } + + return result; +} + +/*********************************************************************//** + * @brief + * The switchDoubleBuffer function switches the active and inactive sides + * of the given buffer. + * @warning 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[] + * @details Outputs: activeDoubleBuffer[], commBufferByteCount[] + * @param buffer ID of buffer to switch double buffers + * @return the new active side of the given double buffer (0 or 1) + *************************************************************************/ +static U32 switchDoubleBuffer( COMM_BUFFER_T buffer ) +{ + U32 activeBuffer = activeDoubleBuffer[ buffer ]; + U32 inactiveBuffer = GET_TOGGLE( activeBuffer, 0, 1 ); + + // Ensure inactive buffer is reset before making active + commBufferByteCount[ buffer ][ inactiveBuffer ] = 0; + // Switch buffers + activeDoubleBuffer[ buffer ] = inactiveBuffer; + + // Return the new active buffer (was just inactive) + return inactiveBuffer; +} + +/*********************************************************************//** + * @brief + * The getDataFromInactiveBuffer function retrieves a given number of bytes + * from the inactive side of a given buffer. + * @warning This function should only be called by getFromCommBuffer(). + * Parameters will be pre-validated there. + * @details Inputs: commBuffers[], activeDoubleBuffer[], commBufferByteCount[] + * @details Outputs: commBuffers[], activeDoubleBuffer[], commBufferByteCount[] + * @param buffer ID of buffer to get data from inactive side of + * @param data Pointer to byte array to populate with data from inactive + * side of buffer + * @param len Number of bytes to get from the buffer + * @return none + *************************************************************************/ +static void getDataFromInactiveBuffer( COMM_BUFFER_T buffer, U08 *data, U32 len ) +{ + U32 activeBuffer = activeDoubleBuffer[ buffer ]; + U32 inactiveBuffer = GET_TOGGLE( activeBuffer, 0, 1 ); + U32 bytesInInactiveBuffer = commBufferByteCount[ buffer ][ inactiveBuffer ]; + + // Get the requested data from inactive buffer + memcpy( data, &commBuffers[ buffer ][ inactiveBuffer ][ 0 ], len ); + + if ( len < bytesInInactiveBuffer ) + { + U08 *endPtr = (&commBuffers[ buffer ][ inactiveBuffer ][ 0 ] + len); + + // Move un-consumed data in inactive buffer to start of inactive buffer + memcpy( &commBuffers[ buffer ][ inactiveBuffer ][ 0 ], endPtr, ( bytesInInactiveBuffer - len ) ); + // Reduce byte count for inactive buffer by # of bytes consumed + commBufferByteCount[ buffer ][ inactiveBuffer ] -= len; + } + else + { + // Inactive buffer has been emptied so switch double buffers + switchDoubleBuffer( buffer ); // Switch will zero count off inactive buffer + } +} + +/**@}*/ Index: CommBuffers.h =================================================================== diff -u --- CommBuffers.h (revision 0) +++ CommBuffers.h (revision 423aa34698d30a44e3b12b74e4243c3a8b5821de) @@ -0,0 +1,104 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 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.h +* +* @author (last) Sean +* @date (last) 30-Jul-2024 +* +* @author (original) Sean +* @date (original) 30-Jul-2024 +* +***************************************************************************/ + +#ifndef __COMM_BUFFERS_H__ +#define __COMM_BUFFERS_H__ + +/** + * @defgroup CommBuffers CommBuffers + * @brief The communication buffers unit provides buffering services for + * incoming and outgoing CAN data. A separate buffer is provided for each + * CAN ID (channel) so that frame order is maintained for a given channel. + * + * @addtogroup CommBuffers + * @{ + */ + +// ********** public definitions ********** + +/// Enumeration of CAN communication buffers. Buffers are ordered by priority. +typedef enum Comm_Buffers +{ + COMM_BUFFER_NOT_USED = 0, ///< CAN message boxes start at 1 so we will not use this buffer +#ifdef _TD_ + COMM_BUFFER_OUT_CAN_TD_ALARM, ///< Buffer for outgoing TD alarm messages + COMM_BUFFER_IN_CAN_DD_ALARM, ///< Buffer for incoming DD alarm messages + COMM_BUFFER_IN_CAN_RO_ALARM, ///< Buffer for incoming RO alarm messages + COMM_BUFFER_IN_CAN_UI_ALARM, ///< Buffer for incoming UI alarm messages + COMM_BUFFER_OUT_CAN_TD_2_DD, ///< Buffer for outgoing TD to DD messages + COMM_BUFFER_IN_CAN_DD_2_TD, ///< Buffer for incoming DD to HD messages + COMM_BUFFER_OUT_CAN_TD_2_UI, ///< Buffer for outgoing TD to UI messages + COMM_BUFFER_IN_CAN_UI_2_TD, ///< Buffer for incoming UI to TD messages + COMM_BUFFER_OUT_CAN_TD_BROADCAST, ///< Buffer for outgoing TD broadcast messages + COMM_BUFFER_IN_CAN_DD_BROADCAST, ///< Buffer for incoming DD broadcast messages + COMM_BUFFER_IN_CAN_RO_BROADCAST, ///< Buffer for incoming RO broadcast messages + COMM_BUFFER_IN_CAN_UI_BROADCAST, ///< Buffer for incoming UI broadcast messages +#endif +#ifdef _DD_ +typedef enum Comm_Buffers +{ + COMM_BUFFER_IN_CAN_TD_ALARM, ///< Buffer for incoming TD alarm messages + COMM_BUFFER_OUT_CAN_DD_ALARM, ///< Buffer for outgoing DD alarm messages + COMM_BUFFER_IN_CAN_RO_ALARM, ///< Buffer for incoming RO alarm messages + COMM_BUFFER_IN_CAN_UI_ALARM, ///< Buffer for incoming UI alarm messages + COMM_BUFFER_IN_CAN_TD_2_DD, ///< Buffer for incoming TD to DD messages + COMM_BUFFER_OUT_CAN_DD_2_TD, ///< Buffer for outgoing DD to TD messages + COMM_BUFFER_OUT_CAN_DD_2_RO, ///< Buffer for outgoing DD to RO messages + COMM_BUFFER_IN_CAN_RO_2_DD, ///< Buffer for incoming RO to DD messages + COMM_BUFFER_IN_CAN_TD_BROADCAST, ///< Buffer for incoming TD broadcast messages + COMM_BUFFER_OUT_CAN_DD_BROADCAST, ///< Buffer for outgoing DD broadcast messages + COMM_BUFFER_IN_CAN_RO_BROADCAST, ///< Buffer for incoming RO broadcast messages + COMM_BUFFER_IN_CAN_UI_BROADCAST, ///< Buffer for incoming UI broadcast messages +} COMM_BUFFER_T; +#endif +#ifdef _RO_ + // TODO - Dara to populate +#endif + COMM_BUFFER_IN_CAN_PC, ///< Buffer for incoming PC messages + COMM_BUFFER_OUT_CAN_PC, ///< Buffer for outgoing messages to PC + NUM_OF_COMM_BUFFERS ///< Number of CAN communication buffers +} COMM_BUFFER_T; + +/**@}*/ + +#ifdef _TD_ +#include "TDCommon.h" +#endif +#ifdef _DD_ +#include "DDCommon.h" +#endif +#ifdef _RD_ +#include "ROCommon.h" +#endif + +/** + * @addtogroup CommBuffers + * @{ + */ + +// ********** public function prototypes ********** + +void initCommBuffers( void ); +void clearBuffer( COMM_BUFFER_T buffer ); +BOOL addToCommBuffer( COMM_BUFFER_T buffer, U08 *data, U32 len ); +U32 getFromCommBuffer( COMM_BUFFER_T buffer, U08 *data, U32 len ); +U32 peekFromCommBuffer( COMM_BUFFER_T buffer, U08 *data, U32 len ); +U32 numberOfBytesInCommBuffer( COMM_BUFFER_T buffer ); + +/**@}*/ + +#endif