Index: firmware/App/Services/CommBuffers.c =================================================================== diff -u -rf2652e85c8676d0356fea2690cfd9cac716ca795 -r5645305f9349c5c64be5560982bdf1abd5edb0fb --- firmware/App/Services/CommBuffers.c (.../CommBuffers.c) (revision f2652e85c8676d0356fea2690cfd9cac716ca795) +++ firmware/App/Services/CommBuffers.c (.../CommBuffers.c) (revision 5645305f9349c5c64be5560982bdf1abd5edb0fb) @@ -1,257 +1,213 @@ -/* - * CommBuffers.c - * - * Created on: Aug 2, 2024 - * Author: fw - */ -#include "string.h" // For memcpy -#include "can.h" +#include // For memcpy #include "CommBuffers.h" #include "Utilities.h" -#define NUM_OF_FW_STACKS 3 -#define CAN_MESSAGE_PAYLOAD_SIZE 8 -#define SW_UPDATE_FINAL_MSG_INDEX 0xFFFF +/** + * @addtogroup CommBuffers + * @{ + */ -typedef struct -{ - U08 msgID; - U08 updateCmd; - U16 cyberRandom; - U32 msgCRC; -} SW_UPDATE_CMD_STATUS_T; +// ********** private definitions ********** -typedef struct -{ - U32 SWUpdateFrameCount; - U08 msgID; - U08 updateDest; - U16 cyberIndex; - U32 msgCRC; - U08 SWUpdateBuffer[ SW_UPDATE_FLASH_BUFFER_SIZE ]; -} SW_UPDATE_RCV_STATUS_T; +#define UPDATE_PACKET_SIZE_BYTES ( SW_UPDATE_FLASH_BUFFER_SIZE + CAN_MESSAGE_FRAME_SIZE_BYTES ) ///< Software update packet size in bytes. +/// Software update buffer structure typedef struct { - U08 msgID; - U08 msgAckNackStatus; - U16 cyberRandom; - U32 msgCRC; -} SW_UPDATE_RESP_STATUS_T; + U32 SWUpdateNumOfFramesCount; ///< Software update number of frame count. + U32 SWUpdateFrameCount; ///< Software update frame count. + U08 SWUpdateBuffer[ UPDATE_PACKET_SIZE_BYTES ]; ///< Software update buffer. +} SW_UPDATE_BUFFER_T; -static const U32 NUM_OF_CAN_FRAMES_TO_UPDATE = ( SW_UPDATE_FLASH_BUFFER_SIZE + CAN_MESSAGE_PAYLOAD_SIZE ) / CAN_MESSAGE_PAYLOAD_SIZE; +// ********** private data ********** -static const SW_UPDATE_CAN_MAIL_BOXES_T RECEIVE_MSG_ID[ NUM_OF_FW_STACKS ] = -{ - SW_UPDATE_TD_UPDATE, - SW_UPDATE_DD_UPDATE, - SW_UPDATE_RO_UPDATE -}; +static SW_UPDATE_BUFFER_T SWUpdateBuffer[ NUM_OF_SW_UPDATE_MBOXES ]; ///< Software update buffer array. -static SW_UPDATE_CMD_STATUS_T SWUpdateCmdStatus; -static SW_UPDATE_RCV_STATUS_T SWUpdateRcvStatus; -static SW_UPDATE_BUFFER_STATUS_T SWUpdateBufferStatus; +// ********** private function prototypes ******** -static U32 FORTESTREMOVE = 0; - -static void consumeReceivedUpdateCANFrame( U08* data ); -static void processReceivedUpdateCANFrame( void ); -static void processRecievedCmdCANFrame( U08* data ); - +/*********************************************************************//** + * @brief + * The initCommBuffers function initializes the CommBuffers unit. + * @details Inputs: none + * @details Outputs: CommBuffers unit initialized. + * @return none + *************************************************************************/ void initCommBuffers( void ) { - clearSWUpdateBuffer( TRUE ); - clearSWUpdateBuffer( FALSE ); + SW_UPDATE_CAN_MAIL_BOX_T mailBox; + + for ( mailBox = SW_UPDATE_NOT_USED; mailBox < NUM_OF_SW_UPDATE_MBOXES; mailBox++ ) + { + clearCommBuffer( mailBox ); + } } -void handleCANMsgInterrupt( SW_UPDATE_CAN_MAIL_BOXES_T MailBox ) +/*********************************************************************//** + * @brief + * The addToCommBuffer function adds data of specified length to a given + * communication buffer. + * @note This function is thread safe. IRQ interrupts are disabled during + * buffer operations. + * @details Inputs: SWUpdateBuffer[] + * @details Outputs: SWUpdateBuffer[] + * @param mailbox 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( SW_UPDATE_CAN_MAIL_BOX_T mailBox, U08* data, U32 len ) { - // TODO do we need check the range of the messages? + BOOL status = FALSE; - U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; - - if ( SW_UPDATE_COMMAD == MailBox ) + if ( mailBox < NUM_OF_SW_UPDATE_MBOXES ) { - if ( FALSE != canIsRxMessageArrived( canREG1, MailBox ) ) + _disable_IRQ(); + U32 currentFrameCount = SWUpdateBuffer[ mailBox ].SWUpdateFrameCount; + + // Check if the number of bytes is less than the allowed bytes in the mailbox buffer. + if ( ( currentFrameCount * CAN_MESSAGE_FRAME_SIZE_BYTES ) <= UPDATE_PACKET_SIZE_BYTES ) { - U32 result = canGetData( canREG1, MailBox, data ); + U32 currentBufferIndex = currentFrameCount * len; - if ( result != 0 ) - { - processRecievedCmdCANFrame( data ); - } - } - } - else - { - SW_UPDATE_CAN_MAIL_BOXES_T thisStackMailBox = RECEIVE_MSG_ID[ BL_STACK_ID ]; + // Copy the received can frame into the buffer + memcpy( SWUpdateBuffer[ mailBox ].SWUpdateBuffer + currentBufferIndex, data, len ); - if ( thisStackMailBox == MailBox ) - { - if ( FALSE != canIsRxMessageArrived( canREG1, MailBox ) ) + switch ( mailBox ) { - U32 result = canGetData( canREG1, MailBox, data ); + case SW_UPDATE_COMMAD: + case SW_UPDATE_FFU_BROADCAST: + // A command is only 1 frame of 8 bytes. + SWUpdateBuffer[ mailBox ].SWUpdateNumOfFramesCount = NUM_OF_CMD_CAN_FRAMES; + break; - if ( result != 0 ) - { - consumeReceivedUpdateCANFrame( data ); - } + case SW_UPDATE_TD_UPDATE: + case SW_UPDATE_DD_UPDATE: + if ( 0 == SWUpdateBuffer[ mailBox ].SWUpdateFrameCount ) + { + // If the received command is a software update mailbox and if the frame count is 0, so it is the overhead frame. + // In the overhead frame the 2nd and 3rd bytes are payload length and the two payloads are bitwised to get the payload length. + U08 updatePayloadLenMSB = SWUpdateBuffer[ mailBox ].SWUpdateBuffer[ SW_UPDATE_LEN_MSB_INDEX ]; + U08 updatePayloadLenLSB = SWUpdateBuffer[ mailBox ].SWUpdateBuffer[ SW_UPDATE_LEN_LSB_INDEX ]; + U16 updatePayloadLength = updatePayloadLenMSB << SHIFT_8_BITS_FOR_BYTE_SHIFT | updatePayloadLenLSB; + // Per the payload length, calculate the number of frames of 8 bytes that are needed to receive the entire update message. + // Round up the number of frames with (payload length + 1 can frame (8 bytes) - 1) / 1 can frame (8 bytes) + // After calculating the number of frames needed to receive the entire update payload add one more frame for the overhead frame. + SWUpdateBuffer[ mailBox ].SWUpdateNumOfFramesCount = ( updatePayloadLength + CAN_MESSAGE_FRAME_SIZE_BYTES - 1 ) / CAN_MESSAGE_FRAME_SIZE_BYTES; + SWUpdateBuffer[ mailBox ].SWUpdateNumOfFramesCount += 1; + } + break; + + default: + // Do nothing. There are other mailboxes that do not need to be processed. + break; } + + // Increment the current frame count + SWUpdateBuffer[ mailBox ].SWUpdateFrameCount += 1; + status = TRUE; } + _enable_IRQ(); } -} -void getSWUpdateBufferStatus( SW_UPDATE_BUFFER_STATUS_T* status ) -{ - memcpy( status, &SWUpdateBufferStatus, sizeof( SW_UPDATE_BUFFER_STATUS_T ) ); + return status; } - -void getSWUpdateBuffer( U08* data ) +/*********************************************************************//** + * @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. + * 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 Inputs: SWUpdateBuffer[] + * @details Outputs: none + * @param mailbox 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. + *************************************************************************/ +BOOL getCommBuffer( SW_UPDATE_CAN_MAIL_BOX_T mailBox, U08* data, U32 len ) { - memcpy( data, &SWUpdateRcvStatus.SWUpdateBuffer, sizeof( SWUpdateRcvStatus.SWUpdateBuffer ) ); -} + BOOL status = FALSE; -void sendAckNackStatusFromFirmware( ACK_NACK_STATUS_T status, BOOL cmd ) -{ - SW_UPDATE_RESP_STATUS_T resp; - - U32 calcCRC = 0; - - resp.msgID = ( TRUE == cmd ? SWUpdateCmdStatus.msgID : SWUpdateRcvStatus.msgID ); - resp.msgAckNackStatus = status; - resp.cyberRandom = 0; - resp.msgCRC = crc32( calcCRC, (U08*)&resp, sizeof( SW_UPDATE_RESP_STATUS_T ) - sizeof( U32 ) ); - - if ( 0 != canTransmit( canREG1, (U32)SW_UPDATE_RESP, (U08*)&resp ) ) + if ( ( mailBox < NUM_OF_SW_UPDATE_MBOXES ) && ( len <= UPDATE_PACKET_SIZE_BYTES ) ) { - clearSWUpdateBuffer( cmd ); + _disable_IRQ(); + memcpy( data, SWUpdateBuffer[ mailBox ].SWUpdateBuffer, len ); + status = TRUE; + _enable_IRQ(); } -} -void clearSWUpdateBuffer( BOOL cmd ) -{ - if ( FALSE == cmd ) - { - memset( &SWUpdateRcvStatus, 0x0, sizeof( SW_UPDATE_RCV_STATUS_T ) ); - memset( &SWUpdateBufferStatus, 0x0, sizeof( SW_UPDATE_BUFFER_STATUS_T ) ); - } - else - { - memset( &SWUpdateCmdStatus, 0x0, sizeof( SW_UPDATE_CMD_STATUS_T ) ); - } + return status; } - -// ********** private functions ********** - -static void consumeReceivedUpdateCANFrame( U08* data ) +/*********************************************************************//** + * @brief + * The isMessageComplete function checks whether a message (command or update) + * has been fully received. + * @details Inputs: SWUpdateBuffer[] + * @details Outputs: none + * @param mailbox ID of buffer to check the completeness of the message + * @return TRUE if the messages has been fully received, otherwise FALSE + *************************************************************************/ +BOOL isMessageComplete( SW_UPDATE_CAN_MAIL_BOX_T mailBox ) { - if ( SWUpdateRcvStatus.SWUpdateFrameCount <= NUM_OF_CAN_FRAMES_TO_UPDATE ) + BOOL status = FALSE; + U32 frameCnt = 0; + U32 numOfFramesCnt = 0; + + switch ( mailBox ) { - if ( 0 == SWUpdateRcvStatus.SWUpdateFrameCount ) - { - memcpy( &SWUpdateRcvStatus.msgID, data, sizeof( U08 ) ); - data += sizeof( U08 ); - memcpy( &SWUpdateRcvStatus.updateDest, data, sizeof( U08 ) ); - data += sizeof( U08 ); - memcpy( &SWUpdateRcvStatus.cyberIndex, data, sizeof( U16 ) ); - data += sizeof( U16 ); - memcpy( &SWUpdateRcvStatus.msgCRC, data, sizeof( U32 ) ); - } - else - { - U32 currentBufferIndex = ( SWUpdateRcvStatus.SWUpdateFrameCount - 1 ) * CAN_MESSAGE_PAYLOAD_SIZE; + case SW_UPDATE_COMMAD: + case SW_UPDATE_FFU_BROADCAST: + frameCnt = SWUpdateBuffer[ mailBox ].SWUpdateFrameCount; + numOfFramesCnt = SWUpdateBuffer[ mailBox ].SWUpdateNumOfFramesCount; + break; - memcpy( SWUpdateRcvStatus.SWUpdateBuffer + currentBufferIndex, data, CAN_MESSAGE_PAYLOAD_SIZE ); - } + case SW_UPDATE_TD_UPDATE: + case SW_UPDATE_DD_UPDATE: + frameCnt = SWUpdateBuffer[ mailBox ].SWUpdateFrameCount; + numOfFramesCnt = SWUpdateBuffer[ mailBox ].SWUpdateNumOfFramesCount; + break; - SWUpdateRcvStatus.SWUpdateFrameCount++; + default: + // Do nothing. There are other mailboxes that do not need to be processed. + break; + } - //if ( NUM_OF_CAN_FRAMES_TO_UPDATE == SWUpdateRcvStatus.SWUpdateFrameCount ) - if ( SWUpdateRcvStatus.SWUpdateFrameCount % NUM_OF_CAN_FRAMES_TO_UPDATE == 0 ) - { - processReceivedUpdateCANFrame(); - - // TODO REmove - if ( FORTESTREMOVE == 1 ) - { - BOOL test = FALSE; - } - FORTESTREMOVE++; - //sendAckNackStatusFromFirmware( ACK, FALSE ); - //clearSWUpdateBuffer( FALSE ); - // TODO Remove - } - else - { - //SWUpdateRcvStatus.SWUpdateFrameCount++; - } + // Check if the frame count is not 0 meaning that at least one frame is received prior to checking for the completion. + if ( ( frameCnt > 0 ) && ( frameCnt == numOfFramesCnt ) ) + { + status = TRUE; } + + return status; } -static void processReceivedUpdateCANFrame( void ) +/*********************************************************************//** + * @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 clearCommBuffer( SW_UPDATE_CAN_MAIL_BOX_T mailBox ) { - U32 calcCRC = 0; - BOOL hasCRCPassed = FALSE; - - calcCRC = crc32( calcCRC, SWUpdateRcvStatus.SWUpdateBuffer, MAX_CRC_CALC_DATA_SIZE ); - hasCRCPassed = ( SWUpdateRcvStatus.msgCRC == calcCRC ? TRUE : FALSE ); - - // TODO remove - hasCRCPassed = TRUE; - // TODO remove - - if ( TRUE == hasCRCPassed ) + _disable_IRQ(); + if ( mailBox < NUM_OF_SW_UPDATE_MBOXES ) { - switch ( SWUpdateRcvStatus.updateDest ) - { - case UPDATE_FIRMWARE: - if ( SWUpdateRcvStatus.cyberIndex != SW_UPDATE_FINAL_MSG_INDEX ) - { - SWUpdateBufferStatus.isSWUpdateBufferReady = TRUE; - SWUpdateBufferStatus.dest = UPDATE_FIRMWARE; - } - else - { - sendAckNackStatusFromFirmware( ACK, FALSE ); - clearSWUpdateBuffer( FALSE ); - } - break; - - case UPDATE_FPGA: - SWUpdateBufferStatus.isSWUpdateBufferReady = TRUE; - SWUpdateBufferStatus.dest = UPDATE_FPGA; - break; - - default: - // Do nothing - break; - } + memset( &SWUpdateBuffer[ mailBox ], 0x0, sizeof( SW_UPDATE_BUFFER_T ) ); } + _enable_IRQ(); } -static void processRecievedCmdCANFrame( U08* data ) -{ - ACK_NACK_STATUS_T ackStatus; +// ********** private functions ********** - U32 calcCRC = 0; - BOOL hasCRCPassed = FALSE; +/**@}*/ - memcpy( &SWUpdateCmdStatus.msgID, data, sizeof( U08 ) ); - data += sizeof( U08 ); - memcpy( &SWUpdateCmdStatus.updateCmd, data, sizeof( U08 ) ); - data += sizeof( U08 ); - memcpy( &SWUpdateCmdStatus.cyberRandom, data, sizeof( U16 ) ); - data += sizeof( U16 ); - memcpy( &SWUpdateCmdStatus.msgCRC, data, sizeof( U32 ) ); - - calcCRC = crc32( calcCRC, (U08*)&SWUpdateCmdStatus, sizeof( SW_UPDATE_CMD_STATUS_T ) - sizeof( U32 ) ); - hasCRCPassed = ( SWUpdateRcvStatus.msgCRC == calcCRC ? TRUE : FALSE ); - ackStatus = ( TRUE == hasCRCPassed ? ACK : NACK ); - - sendAckNackStatusFromFirmware( ackStatus, TRUE ); -} -