Index: firmware/App/Services/Download.c =================================================================== diff -u -rb8160225a28a2ba4d6dff4d0433e55465c737a14 -rc74c1d99a011dd0fb7f98f183faecda675221fce --- firmware/App/Services/Download.c (.../Download.c) (revision b8160225a28a2ba4d6dff4d0433e55465c737a14) +++ firmware/App/Services/Download.c (.../Download.c) (revision c74c1d99a011dd0fb7f98f183faecda675221fce) @@ -1,9 +1,3 @@ -/* - * Download.c - * - * Created on: Aug 21, 2024 - * Author: fw - */ #include "can.h" // TODO remove for testing only @@ -16,50 +10,71 @@ #include "SystemComm.h" #include "Utilities.h" -#define SW_UPDATE_FINAL_MSG_INDEX 0xFFFF -#define SHIFT_BITS_TO_GET_TARGET 4 +/** + * @addtogroup Download + * @{ + */ -static const U32 NUM_OF_CAN_BYTES_FOR_UPDATE = SW_UPDATE_FLASH_BUFFER_SIZE + CAN_MESSAGE_PAYLOAD_SIZE; +// ********** private definitions ********** +#define SW_UPDATE_FINAL_MSG_INDEX 0xFFFF ///< Software update final message index. +#define SHIFT_BITS_TO_GET_TARGET 4 ///< Shift bits by 4 to get the update target. + +// ********** private data ********** + +static const U32 NUM_OF_CAN_BYTES_FOR_UPDATE = SW_UPDATE_FLASH_BUFFER_SIZE + CAN_MESSAGE_PAYLOAD_SIZE; ///< Number of CAN bytes for update. + +/// Software update response status structure typedef struct { - U08 msgID; - U08 msgAckNackStatus; - U16 cyberRandom; - U32 msgCRC; + U08 msgID; ///< Message ID. + U08 msgAckNackStatus; ///< Message ack or nack status. + U16 cyberRandom; ///< Message cyber random. + U32 msgCRC; ///< Message CRC. } SW_UPDATE_RESP_STATUS_T; +/// Software update command status structure typedef struct { - U08 msgID; - U08 updateCmd; - U16 cyberRandom; - U32 msgCRC; + U08 msgID; ///< Message ID. + U08 updateCmd; ///< Update command. + U16 cyberRandom; ///< Cyber random. + U32 msgCRC; ///< Message CRC. } SW_UPDATE_CMD_STATUS_T; +/// Software update receive update status structure typedef struct { - U08 msgID; - U08 updateDest; - U16 updatePayloadLen; - U32 msgCRC; - U08 SWUpdateBuffer[ SW_UPDATE_FLASH_BUFFER_SIZE ]; + U08 msgID; ///< Message ID. + U08 updateDest; ///< Update destination (FW, FPGA). + U16 updatePayloadLen; ///< Update payload length in bytes. + U32 msgCRC; ///< Message CRC. + U08 SWUpdateBuffer[ SW_UPDATE_FLASH_BUFFER_SIZE ]; ///< Software update buffer. } SW_UPDATE_RCV_STATUS_T; -static SW_UPDATE_RCV_STATUS_T SWUpdateRCVStatus; -static SW_UPDATE_CMD_T SWUpdateCommandState; -static SW_UPDATE_CAN_MAIL_BOX_T thisStackMailBox; -static U32 sizeToWrite; +static SW_UPDATE_RCV_STATUS_T SWUpdateRCVStatus; ///< Software update receive status. +static SW_UPDATE_CMD_T SWUpdateCommandState; ///< Software update command state. +static SW_UPDATE_CAN_MAIL_BOX_T thisStackMailBox; ///< The mailbox of this stack. +static U32 sizeToWrite; ///< Size to write to destination. -static U32 REMOVETHEVAR = 0; +static U32 REMOVETHEVAR = 0; // TODO remove -static void processIncomingCmdMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ); -static void processIncomingUpdateMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ); +// ********** private function prototypes ********** + +static void handleIncomingCmdMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ); +static void handleIncomingUpdateMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ); static void prepareResponseMessage( U08 respOfMsgID, ACK_NACK_STATUS_T ackNack, SW_UPDATE_RESP_STATUS_T* respBuffer ); static void clearSWUpdateBuffer( void ); static ACK_NACK_STATUS_T handleFirmwareUpdate( void ); static ACK_NACK_STATUS_T handleFPGAUpdate( void ); +/*********************************************************************//** + * @brief + * The initDownload function initializes the download unit. + * @details \b Inputs: none + * @details \b Outputs: thisStackMailBox + * @return none + *************************************************************************/ void initDownload( void ) { thisStackMailBox = RECEIVE_MSG_ID[ BL_STACK_ID ]; @@ -68,36 +83,74 @@ clearSWUpdateCommandState(); } +/*********************************************************************//** + * @brief + * The execDownload function executes the download state machine. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none TODO change the design to a state machine + *************************************************************************/ void execDownload( void ) { // TODO make this a state machine - processIncomingCmdMessage( SW_UPDATE_COMMAD ); - processIncomingUpdateMessage( thisStackMailBox ); + handleIncomingCmdMessage( SW_UPDATE_COMMAD ); + handleIncomingUpdateMessage( thisStackMailBox ); } +/*********************************************************************//** + * @brief + * The getSWUpdateCommandState function returns the current software update + * command state. + * @details \b Inputs: SWUpdateCommandState + * @details \b Outputs: none + * @return current software update command state + *************************************************************************/ SW_UPDATE_CMD_T getSWUpdateCommandState( void ) { return SWUpdateCommandState; } +/*********************************************************************//** + * @brief + * The getSWUpdateDestination function returns the current software update + * destination (firmware or FPGA). + * @details \b Inputs: SWUpdateRCVStatus + * @details \b Outputs: none + * @return current software update destination + *************************************************************************/ SW_UPDATE_DESINTATION_T getSWUpdateDestination( void ) { return (SW_UPDATE_DESINTATION_T)SWUpdateRCVStatus.updateDest; } +/*********************************************************************//** + * @brief + * The clearSWUpdateCommandState function clears the software update command + * state to idle state. + * @details \b Inputs: none + * @details \b Outputs: SWUpdateCommandState + * @return none + *************************************************************************/ void clearSWUpdateCommandState( void ) { SWUpdateCommandState = UPDATE_CMD_IDLE; } +/*********************************************************************//** + * @brief + * The sendFPGAAckNackStatus function sends the ack or nack status to the + * application. + * @details \b Inputs: SWUpdateRCVStatus, thisStackMailBox + * @details \b Outputs: none + * @param ack or nack status to be sent + * @return none + *************************************************************************/ void sendFPGAAckNackStatus( ACK_NACK_STATUS_T ackNackStatus ) { SW_UPDATE_RESP_STATUS_T resp; - BOOL status = FALSE; // TODO do we need this? - prepareResponseMessage( SWUpdateRCVStatus.msgID, ackNackStatus, &resp ); - status = sendAckNackStatusFromFirmware( (U08*)&resp ); + sendAckNackStatusFromFirmware( (U08*)&resp ); clearCommBuffer( thisStackMailBox ); } @@ -108,12 +161,24 @@ // ********** private functions ********** -static void processIncomingCmdMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ) +/*********************************************************************//** + * @brief + * The handleIncomingCmdMessage function handles the incoming command message + * from the CAN bus. Once the entire message has been received, it is processed + * and the corresponding destination is informed that an update is available. + * @details \b Inputs: SWUpdateCmdStatus + * @details \b Outputs: SWUpdateCmdStatus + * @param mailbox of the buffer that has been received + * @return none + *************************************************************************/ +static void handleIncomingCmdMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ) { + // Peek into the number of bytes received for the command buffer S32 bytesInBuffer = getNumberOfBytesInBuffer( mailBox ); if ( bytesInBuffer == CAN_MESSAGE_PAYLOAD_SIZE ) { + // If the command buffer has been received, get it from the comm buffer and process it SW_UPDATE_CMD_STATUS_T SWUpdateCmdStatus; SW_UPDATE_RESP_STATUS_T resp; @@ -125,6 +190,7 @@ U08 msgID = SWUpdateCmdStatus.msgID; SW_UPDATE_DESINTATION_T dest = (SW_UPDATE_DESINTATION_T)( SWUpdateCmdStatus.updateCmd >> SHIFT_BITS_TO_GET_TARGET ); // TODO add more logic for other stacks + // Calculate the CRC of the message and ack or nack based on the matching of the CRCs calcCRC = crc32( calcCRC, (U08*)&SWUpdateCmdStatus, sizeof( SW_UPDATE_CMD_STATUS_T ) - sizeof( U32 ) ); hasCRCPassed = ( SWUpdateCmdStatus.msgCRC == calcCRC ? TRUE : FALSE ); @@ -139,18 +205,31 @@ if ( UPDATE_FPGA == dest ) { + // If the update destination is FPGA, signal FPGA to prepare for the update. signalFPGAToPrepareForUpdate(); } } + // Send the result of the command received prepareResponseMessage( msgID, ackStatus, &resp ); sendAckNackStatusFromFirmware( (U08*)&resp ); clearCommBuffer( mailBox ); } } -static void processIncomingUpdateMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ) +/*********************************************************************//** + * @brief + * The handleIncomingUpdateMessage function handles the incoming update message + * from the CAN bus. Once the entire update message has been received, it then + * is sent to the corresponding destination that is under update. + * @details \b Inputs: SWUpdateRCVStatus + * @details \b Outputs: SWUpdateRCVStatus + * @param mailbox of the buffer that has been received + * @return none + *************************************************************************/ +static void handleIncomingUpdateMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ) { + // Peek into the comm buffer to see if the entire data has been received S32 bytesInBuffer = getNumberOfBytesInBuffer( mailBox ); if ( bytesInBuffer == NUM_OF_CAN_BYTES_FOR_UPDATE ) @@ -165,9 +244,11 @@ getCommBuffer( mailBox, (U08*)&SWUpdateRCVStatus, NUM_OF_CAN_BYTES_FOR_UPDATE ); + // Create a local buffer and copy the header into the buffer excluding the CRC so only 4 bytes of ID, Destination, and payload length memcpy( bufferWithNoCRC, (U08*)&SWUpdateRCVStatus, sizeof( U32 ) ); + // Copy the entire update buffer that is going either to firmware or FPGA into the local buffer. memcpy( &bufferWithNoCRC[ sizeof( U32 ) ], SWUpdateRCVStatus.SWUpdateBuffer, sizeof( SWUpdateRCVStatus.SWUpdateBuffer ) ); - + // Calculate the CRC of the local copied buffer and compare it against the message CRC calcCRC = crc32( calcCRC, bufferWithNoCRC, sizeof( bufferWithNoCRC ) ); hasCRCPassed = ( SWUpdateRCVStatus.msgCRC == calcCRC ? TRUE : FALSE ); @@ -177,6 +258,7 @@ if ( TRUE == hasCRCPassed ) { + // CRC passed, call the corresponding the handlers to update either FPGA or firmware switch ( SWUpdateRCVStatus.updateDest ) { case UPDATE_FIRMWARE: @@ -193,13 +275,27 @@ } } + // TODo send nack if the CRC failed + //prepareResponseMessage( SWUpdateRCVStatus.msgID, ackNackStatus, &resp ); //status = sendAckNackStatusFromFirmware( (U08*)&resp ); // TODO do we have to retry if send failed? clearCommBuffer( mailBox ); // TODo does this need to be here? How about resync? //clearSWUpdateBuffer(); // TODO uncomment } } +/*********************************************************************//** + * @brief + * The prepareResponseMessage function prepares the message body that is + * used to respond to the updater app. + * @details \b Inputs: none + * @details \b Outputs: none + * @param message ID that is being responded for + * @param ack nack status + * @param response buffer which is the pointer to the buffer that is used + * to be sent to the app + * @return none + *************************************************************************/ static void prepareResponseMessage( U08 respOfMsgID, ACK_NACK_STATUS_T ackNack, SW_UPDATE_RESP_STATUS_T* respBuffer ) { U32 calcCRC = 0; @@ -210,11 +306,27 @@ respBuffer->msgCRC = crc32( calcCRC, (U08*)&respBuffer, sizeof( SW_UPDATE_RESP_STATUS_T ) - sizeof( U32 ) ); } +/*********************************************************************//** + * @brief + * The clearSWUpdateBuffer function clears the software update buffer. + * @details \b Inputs: none + * @details \b Outputs: SWUpdateRCVStatus + * @return none + *************************************************************************/ static void clearSWUpdateBuffer( void ) { memset( &SWUpdateRCVStatus, 0x0, sizeof( SW_UPDATE_RCV_STATUS_T ) ); } +/*********************************************************************//** + * @brief + * The handleFirmwareUpdate function handles the firmware update data. This + * function checks that the message is not the final message and then signal + * the non-volatile memory to update the flash. + * @details \b Inputs: SWUpdateRCVStatus + * @details \b Outputs: none + * @return Ack if the write was successful otherwise, Nack + *************************************************************************/ static ACK_NACK_STATUS_T handleFirmwareUpdate( void ) { SW_UPDATE_RESP_STATUS_T resp; @@ -237,10 +349,21 @@ return ackStatus; } +/*********************************************************************//** + * @brief + * The handleFPGAUpdate function handles the FPGA update data. This + * function checks that the message is not the final message and then signals + * the FPGA driver to update the FPGA. + * @details \b Inputs: SWUpdateRCVStatus + * @details \b Outputs: none + * @return Ack if the write was successful otherwise, Nack + *************************************************************************/ static ACK_NACK_STATUS_T handleFPGAUpdate( void ) { ACK_NACK_STATUS_T ackStatus = NACK; + // TODO why the firmware handler is slightly different? Make them consistent. + if ( SWUpdateRCVStatus.updatePayloadLen != SW_UPDATE_FINAL_MSG_INDEX ) { sizeToWrite = SWUpdateRCVStatus.updatePayloadLen;