/* * Download.c * * Created on: Aug 21, 2024 * Author: fw */ #include "can.h" // TODO remove for testing only #include // For memcpy and memset #include "CommBuffers.h" #include "Download.h" #include "FPGA.h" #include "NVDataMgmt.h" #include "SystemComm.h" #include "Utilities.h" #define SW_UPDATE_FINAL_MSG_INDEX 0xFFFF #define SHIFT_BITS_TO_GET_TARGET 4 static const U32 NUM_OF_CAN_BYTES_FOR_UPDATE = SW_UPDATE_FLASH_BUFFER_SIZE + CAN_MESSAGE_PAYLOAD_SIZE; typedef struct { U08 msgID; U08 msgAckNackStatus; U16 cyberRandom; U32 msgCRC; } SW_UPDATE_RESP_STATUS_T; typedef struct { U08 msgID; U08 updateCmd; U16 cyberRandom; U32 msgCRC; } SW_UPDATE_CMD_STATUS_T; typedef struct { U08 msgID; U08 updateDest; U16 cyberIndex; U32 msgCRC; U08 SWUpdateBuffer[ SW_UPDATE_FLASH_BUFFER_SIZE ]; } 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 U32 REMOVETHEVAR = 0; static void processIncomingCmdMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ); static void processIncomingUpdateMessage( 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 ); void initDownload( void ) { thisStackMailBox = RECEIVE_MSG_ID[ BL_STACK_ID ]; clearSWUpdateBuffer(); clearSWUpdateCommandState(); } void execDownload( void ) { // TODO make this a state machine processIncomingCmdMessage( SW_UPDATE_COMMAD ); processIncomingUpdateMessage( thisStackMailBox ); } SW_UPDATE_CMD_T getSWUpdateCommandState( void ) { return SWUpdateCommandState; } void clearSWUpdateCommandState( void ) { SWUpdateCommandState = UPDATE_CMD_IDLE; } 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 ); clearCommBuffer( thisStackMailBox ); } U08 getTempRemoveMSGID() { return SWUpdateRCVStatus.msgID; } // ********** private functions ********** static void processIncomingCmdMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ) { S32 bytesInBuffer = getNumberOfBytesInBuffer( mailBox ); if ( bytesInBuffer == CAN_MESSAGE_PAYLOAD_SIZE ) { SW_UPDATE_CMD_STATUS_T SWUpdateCmdStatus; SW_UPDATE_RESP_STATUS_T resp; getCommBuffer( mailBox, (U08*)&SWUpdateCmdStatus, sizeof( SW_UPDATE_CMD_STATUS_T ) ); BOOL status = FALSE; BOOL hasCRCPassed = FALSE; ACK_NACK_STATUS_T ackStatus = NACK; U32 calcCRC = 0; 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 calcCRC = crc32( calcCRC, (U08*)&SWUpdateCmdStatus, MAX_CRC_CALC_DATA_SIZE ); hasCRCPassed = ( SWUpdateCmdStatus.msgCRC == calcCRC ? TRUE : FALSE ); // TODO remove hasCRCPassed = TRUE; // TODO remove if ( TRUE == hasCRCPassed ) { ackStatus = ACK; SWUpdateCommandState = (SW_UPDATE_CMD_T)( SWUpdateCmdStatus.updateCmd & MASK_OFF_NIBBLE_MSB ); if ( UPDATE_FPGA == dest ) { signalFPGAToPrepareForUpdate(); } } prepareResponseMessage( msgID, ackStatus, &resp ); status = sendAckNackStatusFromFirmware( (U08*)&resp ); clearCommBuffer( mailBox ); } } static void processIncomingUpdateMessage( SW_UPDATE_CAN_MAIL_BOX_T mailBox ) { S32 bytesInBuffer = getNumberOfBytesInBuffer( mailBox ); if ( bytesInBuffer == NUM_OF_CAN_BYTES_FOR_UPDATE ) { SW_UPDATE_RESP_STATUS_T resp; BOOL status = FALSE; U32 calcCRC = 0; BOOL hasCRCPassed = FALSE; ACK_NACK_STATUS_T ackNackStatus = NACK; getCommBuffer( mailBox, (U08*)&SWUpdateRCVStatus, NUM_OF_CAN_BYTES_FOR_UPDATE ); calcCRC = crc32( calcCRC, SWUpdateRCVStatus.SWUpdateBuffer, MAX_CRC_CALC_DATA_SIZE ); // TODO fix the CRC length hasCRCPassed = ( SWUpdateRCVStatus.msgCRC == calcCRC ? TRUE : FALSE ); // TODO remove hasCRCPassed = TRUE; // TODO remove if ( TRUE == hasCRCPassed ) { switch ( SWUpdateRCVStatus.updateDest ) { case UPDATE_FIRMWARE: ackNackStatus = handleFirmwareUpdate(); break; case UPDATE_FPGA: ackNackStatus = handleFPGAUpdate(); break; default: // Do nothing break; } } //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 } } static void prepareResponseMessage( U08 respOfMsgID, ACK_NACK_STATUS_T ackNack, SW_UPDATE_RESP_STATUS_T* respBuffer ) { U32 calcCRC = 0; respBuffer->msgID = respOfMsgID; respBuffer->msgAckNackStatus = ackNack; respBuffer->cyberRandom = 0; respBuffer->msgCRC = crc32( calcCRC, (U08*)&respBuffer, sizeof( SW_UPDATE_RESP_STATUS_T ) - sizeof( U32 ) ); } static void clearSWUpdateBuffer( void ) { memset( &SWUpdateRCVStatus, 0x0, sizeof( SW_UPDATE_RCV_STATUS_T ) ); } static ACK_NACK_STATUS_T handleFirmwareUpdate( void ) { SW_UPDATE_RESP_STATUS_T resp; ACK_NACK_STATUS_T ackStatus = ACK; BOOL status = FALSE; if ( SWUpdateRCVStatus.cyberIndex != SW_UPDATE_FINAL_MSG_INDEX ) { _disable_IRQ(); status = handleUpdatingFlash( SWUpdateRCVStatus.SWUpdateBuffer ); ackStatus = ( TRUE == status ? ACK : NACK ); _enable_IRQ(); } prepareResponseMessage( SWUpdateRCVStatus.msgID, ackStatus, &resp ); status = sendAckNackStatusFromFirmware( (U08*)&resp ); // TODO do we have to retry if send failed? clearCommBuffer( thisStackMailBox ); // TODo does this need to be here? How about resync? return ackStatus; } static ACK_NACK_STATUS_T handleFPGAUpdate( void ) { ACK_NACK_STATUS_T ackStatus = NACK; if ( SWUpdateRCVStatus.cyberIndex != SW_UPDATE_FINAL_MSG_INDEX ) { U16 removeThis; U08 index = 0; U32 counter; U08 test[8]; sizeToWrite = SW_UPDATE_FLASH_BUFFER_SIZE; BOOL done = FALSE; /*for ( removeThis = 0; removeThis < SW_UPDATE_FLASH_BUFFER_SIZE; ++removeThis ) { test[ index ] = SWUpdateRCVStatus.SWUpdateBuffer[removeThis]; if ( index == 7 ) { canTransmit( canREG1, (U32)SW_TEST, test ); // Transmit the FPGA back up to make sure we totally received what we sent for ( counter = 0; counter < 6000; counter++ ) {} index = 0; } else { index += 1; } // TODO this is temporary until the ROTTING is removed from the APP // SWUpdateRCVStatus.SWUpdateBuffer[ removeThis ] = 0xFF & ( SWUpdateRCVStatus.SWUpdateBuffer[removeThis] - 27 ); }*/ // 3192290 // 1596144 if ( ( 1596144 - REMOVETHEVAR < SW_UPDATE_FLASH_BUFFER_SIZE ) && ( REMOVETHEVAR != 0 ) ) { sizeToWrite = 1596144 - REMOVETHEVAR; REMOVETHEVAR += sizeToWrite; done = TRUE; } else { REMOVETHEVAR += SW_UPDATE_FLASH_BUFFER_SIZE; } signalFPGAToWriteToFlash( SWUpdateRCVStatus.SWUpdateBuffer, sizeToWrite ); if ( TRUE == done ) { signalFPGAToSelfConfigure(); } } else { SW_UPDATE_RESP_STATUS_T resp; prepareResponseMessage( SWUpdateRCVStatus.msgID, ACK, &resp ); sendAckNackStatusFromFirmware( (U08*)&resp ); } return ackStatus; }