/************************************************************************************//** * \file xcploader.c * \brief XCP Loader module source file. * \ingroup XcpLoader * \internal *---------------------------------------------------------------------------------------- * C O P Y R I G H T *---------------------------------------------------------------------------------------- * Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved * *---------------------------------------------------------------------------------------- * L I C E N S E *---------------------------------------------------------------------------------------- * This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any later * version. * * OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You have received a copy of the GNU General Public License along with OpenBLT. It * should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy. * * \endinternal ****************************************************************************************/ /**************************************************************************************** * Include files ****************************************************************************************/ #include /* for assertions */ #include /* for standard integer types */ #include /* for NULL declaration */ #include /* for boolean type */ #include "session.h" /* Communication session module */ #include "xcploader.h" /* XCP loader module */ /**************************************************************************************** * Macro definitions ****************************************************************************************/ /* XCP command codes as defined by the protocol currently supported by this module */ #define XCPLOADER_CMD_CONNECT (0xFFu) /**< XCP connect command code. */ #define XCPLOADER_CMD_SET_MTA (0xF6u) /**< XCP set mta command code. */ #define XCPLOADER_CMD_UPLOAD (0xF5u) /**< XCP upload command code. */ #define XCPLOADER_CMD_PROGRAM_START (0xD2u) /**< XCP program start command code. */ #define XCPLOADER_CMD_PROGRAM_CLEAR (0xD1u) /**< XCP program clear command code. */ #define XCPLOADER_CMD_PROGRAM (0xD0u) /**< XCP program command code. */ #define XCPLOADER_CMD_PROGRAM_RESET (0xCFu) /**< XCP program reset command code. */ #define XCPLOADER_CMD_PROGRAM_MAX (0xC9u) /**< XCP program max command code. */ /* XCP response packet IDs as defined by the protocol. */ #define XCPLOADER_CMD_PID_RES (0xFFu) /**< positive response */ /** \brief Maximum timeout for the XCP connect command. */ #define XCPLOADER_CONNECT_TIMEOUT_MS (50u) /** \brief Number of retries to connect to the XCP slave. */ #define XCPLOADER_CONNECT_RETRIES (5u) /**************************************************************************************** * Function prototypes ****************************************************************************************/ /* Protocol functions for linking to the session module. */ static void XcpLoaderInit(void const * settings); static void XcpLoaderTerminate(void); static bool XcpLoaderStart(void); static void XcpLoaderStop(void); static bool XcpLoaderClearMemory(uint32_t address, uint32_t len); static bool XcpLoaderWriteData(uint32_t address, uint32_t len, uint8_t const * data); static bool XcpLoaderReadData(uint32_t address, uint32_t len, uint8_t * data); /* General module specific utility functions. */ static void XcpLoaderSetOrderedLong(uint32_t value, uint8_t *data); /* XCP command functions. */ static bool XcpLoaderSendCmdConnect(void); static bool XcpLoaderSendCmdSetMta(uint32_t address); static bool XcpLoaderSendCmdUpload(uint8_t * data, uint8_t length); static bool XcpLoaderSendCmdProgramStart(void); static bool XcpLoaderSendCmdProgramReset(void); static bool XcpLoaderSendCmdProgram(uint8_t length, uint8_t const * data); static bool XcpLoaderSendCmdProgramMax(uint8_t const * data); static bool XcpLoaderSendCmdProgramClear(uint32_t length); /**************************************************************************************** * Local constant declarations ****************************************************************************************/ /** \brief Protocol structure filled with XCP loader specifics. */ static const tSessionProtocol xcpLoader = { .Init = XcpLoaderInit, .Terminate = XcpLoaderTerminate, .Start = XcpLoaderStart, .Stop = XcpLoaderStop, .ClearMemory = XcpLoaderClearMemory, .WriteData = XcpLoaderWriteData, .ReadData = XcpLoaderReadData }; /**************************************************************************************** * Local data declarations ****************************************************************************************/ /** \brief The settings that should be used by the XCP loader. */ static tXcpLoaderSettings xcpSettings; /** \brief Flag to keep track of the connection status. */ static bool xcpConnected; /** \brief Store the byte ordering of the XCP slave. */ static bool xcpSlaveIsIntel; /** \brief The max number of bytes in the command transmit object (master->slave). */ static uint8_t xcpMaxCto; /** \brief The max number of bytes in the command transmit object (master->slave) during * a programming session. */ static uint8_t xcpMaxProgCto; /** \brief The max number of bytes in the data transmit object (slave->master). */ static uint16_t xcpMaxDto; /***********************************************************************************//** ** \brief Obtains a pointer to the protocol structure, so that it can be linked to ** the communication session module. ** \return Pointer to protocol structure. ** ****************************************************************************************/ tSessionProtocol const * XcpLoaderGetProtocol(void) { return &xcpLoader; } /*** end of XcpLoaderGetProtocol ***/ /************************************************************************************//** ** \brief Initializes the protocol module. ** \param settings Pointer to the structure with protocol settings. ** ****************************************************************************************/ static void XcpLoaderInit(void const * settings) { /* Initialize locals. */ xcpConnected = false; xcpSlaveIsIntel = false; xcpMaxCto = 0; xcpMaxProgCto = 0; xcpMaxDto = 0; /* Check parameter. */ assert(settings != NULL); /* Only continue with valid parameter. */ if (settings != NULL) /*lint !e774 */ { /* shallow copy the XCP settings for later usage */ xcpSettings = *(tXcpLoaderSettings *)settings; /* Check that a valid transport layer was specified. */ assert(xcpSettings.transport != NULL); /* Only access the transport layer if it is valid. */ if (xcpSettings.transport != NULL) /*lint !e774 */ { /* Initialize the transport layer. */ xcpSettings.transport->Init(xcpSettings.transportSettings); } /* Invalidate the transportSettings as it is probably no longer valid outside this * function scope and should also not be used anymore. */ xcpSettings.transportSettings = NULL; } } /*** end of XcpLoaderInit ***/ /************************************************************************************//** ** \brief Terminates the protocol module. ** ****************************************************************************************/ static void XcpLoaderTerminate(void) { /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue with a valid transport layer. */ if (xcpSettings.transport != NULL) /*lint !e774 */ { /* Stop the session. */ XcpLoaderStop(); /* Terminate the transport layer. */ xcpSettings.transport->Terminate(); /* Unlink the transport layer. */ xcpSettings.transport = NULL; } } /*** end of XcpLoaderTerminate ***/ /************************************************************************************//** ** \brief Starts the firmware update session. This is where the connection with the ** target is made and the bootloader on the target is activated. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderStart(void) { bool result = false; uint8_t retryCnt; /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue with a valid transport layer. */ if (xcpSettings.transport != NULL) /*lint !e774 */ { /* Make sure the session is stopped before starting a new one. */ XcpLoaderStop(); /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* Connect the transport layer. */ if (!xcpSettings.transport->Connect()) { /* Could not connect the transport layer. */ result = false; } /* Connect to the target with a finite amount of retries. */ if (result) { for (retryCnt=0; retryCntDisconnect(); /* Update the result. */ result = false; } } /* Place the target in programming mode if connected. */ if (result) { if (!XcpLoaderSendCmdProgramStart()) { result = false; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderStart ***/ /************************************************************************************//** ** \brief Stops the firmware update. This is where the bootloader starts the user ** program on the target if a valid one is present. After this the connection ** with the target is severed. ** ****************************************************************************************/ static void XcpLoaderStop(void) { /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue with a valid transport layer and if actually connected. */ if ( (xcpSettings.transport != NULL) && (xcpConnected) ) /*lint !e774 */ { /* End the programming session by sending the program command with size 0. */ if (XcpLoaderSendCmdProgram(0, NULL)) { /* Disconnect the target. Here the reset command is used instead of the disconnect * command, because the bootloader should start the user program on the target. */ (void)XcpLoaderSendCmdProgramReset(); } /* Disconnect the transport layer. */ xcpSettings.transport->Disconnect(); /* Reset connection status. */ xcpConnected = false; } } /*** end of XcpLoaderStop ***/ /************************************************************************************//** ** \brief Requests the bootloader to erase the specified range of memory on the ** target. The bootloader aligns this range to hardware specified erase ** blocks. ** \param address The starting memory address for the erase operation. ** \param len The total number of bytes to erase from memory. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderClearMemory(uint32_t address, uint32_t len) { bool result = false; /* Check parameters. */ assert(len > 0); /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue if a transport layer is linked and the parameters are valid. */ if ( (len > 0) && (xcpSettings.transport != NULL) && (xcpConnected) ) { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* First set the MTA pointer. */ if (!XcpLoaderSendCmdSetMta(address)) { result = false; } /* Now perform the erase operation. */ if (result) { if (!XcpLoaderSendCmdProgramClear(len)) { result = false; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderClearMemory ***/ /************************************************************************************//** ** \brief Requests the bootloader to program the specified data to memory. In case of ** non-volatile memory, the application needs to make sure the memory range ** was erased beforehand. ** \param address The starting memory address for the write operation. ** \param len The number of bytes in the data buffer that should be written. ** \param data Pointer to the byte array with data to write. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderWriteData(uint32_t address, uint32_t len, uint8_t const * data) { bool result = false; uint8_t currentWriteCnt; uint32_t bufferOffset = 0; /* Check parameters. */ assert(data != NULL); assert(len > 0); /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue if the parameters are valid. */ if ( (data != NULL) && (len > 0) && (xcpSettings.transport != NULL) && /*lint !e774 */ (xcpConnected) ) { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* First set the MTA pointer. */ if (!XcpLoaderSendCmdSetMta(address)) { result = false; } /* Perform segmented programming of the data. */ if (result) { while (len > 0) { /* Set the current write length to make optimal use of the available packet * data. */ currentWriteCnt = len % (xcpMaxProgCto - 1u); if (currentWriteCnt == 0) { currentWriteCnt = (xcpMaxProgCto - 1u); } /* Prepare the packed data for the program command. */ if (currentWriteCnt < (xcpMaxProgCto - 1u)) { /* Program data. */ if (!XcpLoaderSendCmdProgram(currentWriteCnt, &data[bufferOffset])) { result = false; break; } } else { /* Program max data. */ if (!XcpLoaderSendCmdProgramMax(&data[bufferOffset])) { result = false; break; } } /* Update loop variables. */ len -= currentWriteCnt; bufferOffset += currentWriteCnt; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderWriteData ***/ /************************************************************************************//** ** \brief Request the bootloader to upload the specified range of memory. The data is ** stored in the data byte array to which the pointer was specified. ** \param address The starting memory address for the read operation. ** \param len The number of bytes to upload from the target and store in the data ** buffer. ** \param data Pointer to the byte array where the uploaded data should be stored. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderReadData(uint32_t address, uint32_t len, uint8_t * data) { bool result = false; uint8_t currentReadCnt; uint32_t bufferOffset = 0; /* Check parameters. */ assert(data != NULL); assert(len > 0); /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue if the parameters are valid. */ if ( (data != NULL) && (len > 0) && (xcpSettings.transport != NULL) && /*lint !e774 */ (xcpConnected) ) { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* First set the MTA pointer. */ if (!XcpLoaderSendCmdSetMta(address)) { result = false; } /* Perform segmented upload of the data. */ if (result) { while (len > 0) { /* Set the current read length to make optimal use of the available packet * data. */ currentReadCnt = len % (uint8_t)(xcpMaxDto - 1u); if (currentReadCnt == 0) { currentReadCnt = (uint8_t)(xcpMaxDto - 1u); } /* Upload some data */ if (!XcpLoaderSendCmdUpload(&data[bufferOffset], currentReadCnt)) { result = false; break; } /* Update loop variables. */ len -= currentReadCnt; bufferOffset += currentReadCnt; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderReadData ***/ /************************************************************************************//** ** \brief Stores a 32-bit value into a byte buffer taking into account Intel ** or Motorola byte ordering. ** \param value The 32-bit value to store in the buffer. ** \param data Array to the buffer for storage. ** ****************************************************************************************/ static void XcpLoaderSetOrderedLong(uint32_t value, uint8_t *data) { /* Check parameters. */ assert(data != NULL); /* Only continue with valid parameters. */ if (data != NULL) /*lint !e774 */ { if (xcpSlaveIsIntel) { data[3] = (uint8_t)(value >> 24); data[2] = (uint8_t)(value >> 16); data[1] = (uint8_t)(value >> 8); data[0] = (uint8_t)value; } else { data[0] = (uint8_t)(value >> 24); data[1] = (uint8_t)(value >> 16); data[2] = (uint8_t)(value >> 8); data[3] = (uint8_t)value; } } } /*** end of XcpLoaderSetOrderedLong ***/ /************************************************************************************//** ** \brief Sends the XCP Connect command. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderSendCmdConnect(void) { bool result = false; tXcpTransportPacket cmdPacket; tXcpTransportPacket resPacket; /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue with a valid transport layer. */ if (xcpSettings.transport != NULL) /*lint !e774 */ { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* Prepare the command packet. */ cmdPacket.data[0] = XCPLOADER_CMD_CONNECT; cmdPacket.data[1] = xcpSettings.connectMode; cmdPacket.len = 2; /* Send the packet. */ if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, XCPLOADER_CONNECT_TIMEOUT_MS)) { /* Could not send packet or receive response within the specified timeout. */ result = false; } /* Only continue if a response was received. */ if (result) { /* Check if the response was valid. */ if ( (resPacket.len != 8) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) { /* Not a valid or positive response. */ result = false; } } /* Process the response data. */ if (result) { /* Store slave's byte ordering information. */ if ((resPacket.data[2] & 0x01) == 0) { xcpSlaveIsIntel = true; } else { xcpSlaveIsIntel = false; } /* Store max number of bytes the slave allows for master->slave packets. */ xcpMaxCto = resPacket.data[3]; xcpMaxProgCto = xcpMaxCto; /* Store max number of bytes the slave allows for slave->master packets. */ if (xcpSlaveIsIntel) { xcpMaxDto = resPacket.data[4] + (resPacket.data[5] << 8); } else { xcpMaxDto = resPacket.data[5] + (resPacket.data[4] << 8); } /* Double check size configuration. CTO length can be adjusted. DTO not. */ if (xcpMaxCto > XCPLOADER_PACKET_SIZE_MAX) /*lint !e685 */ { xcpMaxCto = XCPLOADER_PACKET_SIZE_MAX; } if (xcpMaxDto > XCPLOADER_PACKET_SIZE_MAX) { result = false; } if ( (xcpMaxCto == 0) || (xcpMaxDto == 0) ) { result = false; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderSendCmdConnect ***/ /************************************************************************************//** ** \brief Sends the XCP Set MTA command. ** \param address New MTA address for the slave. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderSendCmdSetMta(uint32_t address) { bool result = false; tXcpTransportPacket cmdPacket; tXcpTransportPacket resPacket; /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue with a valid transport layer. */ if (xcpSettings.transport != NULL) /*lint !e774 */ { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* Prepare the command packet. */ cmdPacket.data[0] = XCPLOADER_CMD_SET_MTA; cmdPacket.data[1] = 0; /* Reserved. */ cmdPacket.data[2] = 0; /* Reserved. */ cmdPacket.data[3] = 0; /* Address extension not supported. */ /* Set the address taking into account byte ordering. */ XcpLoaderSetOrderedLong(address, &cmdPacket.data[4]); cmdPacket.len = 8; /* Send the packet. */ if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT1)) { /* Could not send packet or receive response within the specified timeout. */ result = false; } /* Only continue if a response was received. */ if (result) { /* Check if the response was valid. */ if ( (resPacket.len != 1) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) { /* Not a valid or positive response. */ result = false; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderSendCmdSetMta ***/ /************************************************************************************//** ** \brief Sends the XCP UPLOAD command. ** \param data Destination data buffer. ** \param length Number of bytes to upload. ** \return SB_TRUE is successfull, SB_FALSE otherwise. ** ****************************************************************************************/ static bool XcpLoaderSendCmdUpload(uint8_t * data, uint8_t length) { bool result = false; tXcpTransportPacket cmdPacket; tXcpTransportPacket resPacket; uint8_t dataIdx; /* Cannot request more data then the max rx data - 1. */ assert(length < xcpMaxDto); assert(data != NULL); /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue with a valid transport layer and valid parameters. */ if ( (length < xcpMaxDto) && (data != NULL) && (xcpSettings.transport != NULL) ) /*lint !e774 */ { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* Prepare the command packet. */ cmdPacket.data[0] = XCPLOADER_CMD_UPLOAD; cmdPacket.data[1] = length; cmdPacket.len = 2; /* Send the packet. */ if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT1)) { /* Could not send packet or receive response within the specified timeout. */ result = false; } /* Only continue if a response was received. */ if (result) { /* Check if the response was valid. */ if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) { /* Not a valid or positive response. */ result = false; } } /* Now store the uploaded data. */ if (result) { for (dataIdx = 0; dataIdx < length; dataIdx++) { data[dataIdx] = resPacket.data[dataIdx + 1]; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderSendCmdUpload ***/ /************************************************************************************//** ** \brief Sends the XCP PROGRAM START command. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderSendCmdProgramStart(void) { bool result = false; tXcpTransportPacket cmdPacket; tXcpTransportPacket resPacket; /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue with a valid transport layer. */ if (xcpSettings.transport != NULL) /*lint !e774 */ { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* Prepare the command packet. */ cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM_START; cmdPacket.len = 1; /* Send the packet. */ if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT3)) { /* Could not send packet or receive response within the specified timeout. */ result = false; } /* Only continue if a response was received. */ if (result) { /* Check if the response was valid. */ if ( (resPacket.len != 7) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) { /* Not a valid or positive response. */ result = false; } } /* Store max number of bytes the slave allows for master->slave packets during the * programming session. */ xcpMaxProgCto = resPacket.data[3]; if (xcpMaxProgCto > XCPLOADER_PACKET_SIZE_MAX) /*lint !e685 */ { xcpMaxProgCto = XCPLOADER_PACKET_SIZE_MAX; } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderSendCmdProgramStart ***/ /************************************************************************************//** ** \brief Sends the XCP PROGRAM RESET command. Note that this command is a bit ** different as in it does not require a response. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderSendCmdProgramReset(void) { bool result = false; tXcpTransportPacket cmdPacket; tXcpTransportPacket resPacket; /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue with a valid transport layer. */ if (xcpSettings.transport != NULL) /*lint !e774 */ { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* Prepare the command packet. */ cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM_RESET; cmdPacket.len = 1; /* Send the packet. Note that it is okay if no response is received as this is * allowed for the program reset command. Just make sure to only process the * response if one was actually received. */ if (xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT5)) { /* Still here so a response was received. check if the reponse was valid. */ if ( (resPacket.len != 1) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) { /* Not a valid or positive response. */ result = false; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderSendCmdProgramReset ***/ /************************************************************************************//** ** \brief Sends the XCP PROGRAM command. ** \param length Number of bytes in the data array to program. ** \param data Array with data bytes to program. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderSendCmdProgram(uint8_t length, uint8_t const * data) { bool result = false; tXcpTransportPacket cmdPacket; tXcpTransportPacket resPacket; uint8_t cnt; /* Verify that this number of bytes actually fits in this command. */ assert((length <= (xcpMaxProgCto-2)) && (xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX)); /*lint !e685 */ if (length > 0) { assert(data != NULL); } /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); /* Only continue with a valid transport layer and valid parameters. */ if ( (length <= (xcpMaxProgCto-2)) && (xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX) && /*lint !e685 */ (xcpSettings.transport != NULL) )/*lint !e774 */ { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* Prepare the command packet */ cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM; cmdPacket.data[1] = length; /* Only access data if it is not a NULL pointer. */ if (data != NULL) { for (cnt=0; cntSendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT5)) { /* Could not send packet or receive response within the specified timeout. */ result = false; } /* Only continue if a response was received. */ if (result) { /* Check if the response was valid. */ if ( (resPacket.len != 1) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) { /* Not a valid or positive response. */ result = false; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderSendCmdProgram ***/ /************************************************************************************//** ** \brief Sends the XCP PROGRAM MAX command. ** \param data Array with data bytes to program. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderSendCmdProgramMax(uint8_t const * data) { bool result = false; tXcpTransportPacket cmdPacket; tXcpTransportPacket resPacket; uint8_t cnt; /* verify that this number of bytes actually fits in this command */ assert(xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX); /*lint !e685 */ assert(data != NULL); /* Only continue with a valid transport layer and valid parameters. */ if ( (xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX) && (data != NULL) && /*lint !e685 */ (xcpSettings.transport != NULL) )/*lint !e774 */ { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* Prepare the command packet. */ cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM_MAX; for (cnt = 0; cnt < (xcpMaxProgCto-1); cnt++) { cmdPacket.data[cnt+1] = data[cnt]; } cmdPacket.len = xcpMaxProgCto; /* Send the packet. */ if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT5)) { /* Could not send packet or receive response within the specified timeout. */ result = false; } /* Only continue if a response was received. */ if (result) { /* Check if the response was valid. */ if ( (resPacket.len != 1) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) { /* Not a valid or positive response. */ result = false; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderSendCmdProgramMax ***/ /************************************************************************************//** ** \brief Sends the XCP PROGRAM CLEAR command. ** \param length Number of elements to clear starting at the MTA address. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static bool XcpLoaderSendCmdProgramClear(uint32_t length) { bool result = false; tXcpTransportPacket cmdPacket; tXcpTransportPacket resPacket; /* Only continue with a valid transport layer. */ if (xcpSettings.transport != NULL) /*lint !e774 */ { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /*Pprepare the command packet. */ cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM_CLEAR; cmdPacket.data[1] = 0; /* Use absolute mode. */ cmdPacket.data[2] = 0; /* Reserved. */ cmdPacket.data[3] = 0; /* Reserved. */ /* Set the erase length taking into account byte ordering. */ XcpLoaderSetOrderedLong(length, &cmdPacket.data[4]); cmdPacket.len = 8; /* Send the packet. */ if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT4)) { /* Could not send packet or receive response within the specified timeout. */ result = false; } /* Only continue if a response was received. */ if (result) { /* Check if the response was valid. */ if ( (resPacket.len != 1) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) { /* Not a valid or positive response. */ result = false; } } } /* Give the result back to the caller. */ return result; } /*** end of XcpLoaderSendCmdProgramClear ***/ /*********************************** end of xcploader.c ********************************/