diff --git a/Host/SerialBoot.exe b/Host/SerialBoot.exe index 20a4c7fe..5d4e0a54 100644 Binary files a/Host/SerialBoot.exe and b/Host/SerialBoot.exe differ diff --git a/Host/Source/SerialBoot/CMakeLists.txt b/Host/Source/SerialBoot/CMakeLists.txt index 2d1305e2..7aea5017 100644 --- a/Host/Source/SerialBoot/CMakeLists.txt +++ b/Host/Source/SerialBoot/CMakeLists.txt @@ -6,7 +6,7 @@ #---------------------------------------------------------------------------------------- # C O P Y R I G H T #---------------------------------------------------------------------------------------- -# Copyright (c) 2014 by Feaser http://www.feaser.com All rights reserved +# Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved # #---------------------------------------------------------------------------------------- # L I C E N S E @@ -34,7 +34,7 @@ project(SerialBoot) # Set the port directory, which is platform specific IF(WIN32) - set(PROJECT_PORT_DIR ${PROJECT_SOURCE_DIR}/port/win32) + set(PROJECT_PORT_DIR ${PROJECT_SOURCE_DIR}/port/windows) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_WIN32 -D_CRT_SECURE_NO_WARNINGS") ELSEIF(UNIX) set(PROJECT_PORT_DIR ${PROJECT_SOURCE_DIR}/port/linux) @@ -45,7 +45,22 @@ ENDIF(WIN32) set(CMAKE_BUILD_TYPE "Debug") # Set include directories -include_directories("${PROJECT_SOURCE_DIR}" "${PROJECT_PORT_DIR}" "${PROJECT_SOURCE_DIR}/port") +include_directories("${PROJECT_SOURCE_DIR}" "${PROJECT_PORT_DIR}") + +# Set the output directory +set (PROJECT_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../..) + +# Set the output directory for the generic no-config case (e.g. with mingw) +set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIRECTORY} ) +set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIRECTORY} ) +set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIRECTORY} ) +# Set the output directory for multi-config builds (e.g. msvc) +foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) + string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) + set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_OUTPUT_DIRECTORY} ) + set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_OUTPUT_DIRECTORY} ) + set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_OUTPUT_DIRECTORY} ) +endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) # Get header files file(GLOB_RECURSE INCS "*.h") @@ -53,10 +68,12 @@ file(GLOB_RECURSE INCS "*.h") # Add sources add_executable( SerialBoot + firmware.c main.c - xcpmaster.c - srecord.c - ${PROJECT_PORT_DIR}/xcptransport.c + srecparser.c + xcploader.c + xcptpuart.c + ${PROJECT_PORT_DIR}/serialport.c ${PROJECT_PORT_DIR}/timeutil.c ${INCS} ) diff --git a/Host/Source/SerialBoot/firmware.c b/Host/Source/SerialBoot/firmware.c new file mode 100644 index 00000000..1d4e095c --- /dev/null +++ b/Host/Source/SerialBoot/firmware.c @@ -0,0 +1,125 @@ +/************************************************************************************//** +* \file firmware.c +* \brief Firmware module source file. +* \ingroup SerialBoot +* \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 NULL declaration */ +#include /* for assertions */ +#include "firmware.h" /* firmware module */ + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Pointer to the firmware parser that is linked. */ +static tFirmwareParser const * parserPtr = NULL; + + +/************************************************************************************//** +** \brief Initializes the firmware module. +** \param parser Pointer to the firmware parser to link. +** \return None. +** +****************************************************************************************/ +void FirmwareInit(tFirmwareParser const * const parser) +{ + /* verify parameters */ + assert(parser != NULL); + + /* link the firmware parser */ + parserPtr = parser; + /* initialize the firmware parser */ + parserPtr->Init(); +} /*** end of FirmwareInit ***/ + + +/************************************************************************************//** +** \brief Uninitializes the firmware module. +** \return None. +** +****************************************************************************************/ +void FirmwareDeinit(void) +{ + /* make sure the parser is linked */ + assert(parserPtr != NULL); + + /* uninitialize the parser */ + parserPtr->Deinit(); + /* unlink the parser */ + parserPtr = NULL; +} /*** end of FirmwareDeinit ***/ + + +/************************************************************************************//** +** \brief Loads the firmware data from the specified firmware file, using the linked +** parser. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool FirmwareLoadFromFile(char *firmwareFile) +{ + /* make sure the parser is linked */ + assert(parserPtr != NULL); + /* make sure the filename is valid */ + assert(firmwareFile != NULL); + + return parserPtr->LoadFromFile(firmwareFile); +} /*** end of FirmwareLoadFromFile ***/ + + +/************************************************************************************//** +** \brief Returns the number of firmware segments that were loaded by the parser. +** \return Number of firmware segments. +** +****************************************************************************************/ +uint32_t FirmwareGetSegmentCount(void) +{ + /* make sure the parser is linked */ + assert(parserPtr != NULL); + + return parserPtr->GetSegmentCount(); +} /*** end of FirmwareGetSegmentCount ***/ + + +/************************************************************************************//** +** \brief Obtains a pointer to the firmware segment at the specified index. +** \return Pointer to firmware segment if successful, NULL otherwise. +** +****************************************************************************************/ +const tFirmwareSegment *FirmwareGetSegment(uint32_t segmentIdx) +{ + /* make sure the parser is linked */ + assert(parserPtr != NULL); + + return parserPtr->GetSegment(segmentIdx); +} /*** end of FirmwareGetSegment ***/ + + +/*********************************** end of firmware.c *********************************/ + diff --git a/Host/Source/SerialBoot/srecord.h b/Host/Source/SerialBoot/firmware.h similarity index 52% rename from Host/Source/SerialBoot/srecord.h rename to Host/Source/SerialBoot/firmware.h index 7c4fcfb5..a6ff7652 100644 --- a/Host/Source/SerialBoot/srecord.h +++ b/Host/Source/SerialBoot/firmware.h @@ -1,75 +1,84 @@ -/************************************************************************************//** -* \file srecord.h -* \brief Motorola S-record library header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 -****************************************************************************************/ -#ifndef SRECORD_H -#define SRECORD_H - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/** \brief Maximum number of characters that can be on a line in the firmware file. */ -#define SRECORD_MAX_CHARS_PER_LINE (512) - -/** \brief Maximum number of data bytes that can be on a line in the firmware file - * (S-record). - */ -#define SRECORD_MAX_DATA_BYTES_PER_LINE (SRECORD_MAX_CHARS_PER_LINE/2) - - -/**************************************************************************************** -* Type definitions -****************************************************************************************/ -/** \brief Structure type for grouping the parsing results of an S-record file. */ -typedef struct -{ - sb_uint32 address_low; /**< lowest memory address */ - sb_uint32 address_high; /**< lowest memory address */ - sb_uint32 data_bytes_total; /**< total number of data bytes */ -} tSrecordParseResults; - -/** \brief Structure type for grouping the parsing results of an S-record line. */ -typedef struct -{ - sb_uint8 data[SRECORD_MAX_DATA_BYTES_PER_LINE]; /**< array for S1,S2 or S3 data bytes*/ - sb_uint32 address; /**< address on S1,S2 or S3 line */ - sb_uint16 length; /**< number of bytes written to array */ -} tSrecordLineParseResults; - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -sb_uint8 SrecordIsValid(const sb_char *srecordFile); -sb_file SrecordOpen(const sb_char *srecordFile); -void SrecordParse(sb_file srecordHandle, tSrecordParseResults *parseResults); -void SrecordClose(sb_file srecordHandle); -sb_uint8 SrecordParseNextDataLine(sb_file srecordHandle, tSrecordLineParseResults *parseResults); - - -#endif /* SRECORD_H */ -/*********************************** end of srecord.h **********************************/ +/************************************************************************************//** +* \file firmware.h +* \brief Firmware module header file. +* \ingroup SerialBoot +* \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 +****************************************************************************************/ +#ifndef FIRMWARE_H +#define FIRMWARE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include /* for standard integer types */ +#include /* for boolean type */ + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +/** \brief Groups information together of a firmware segments. */ +typedef struct t_firmware_segment +{ + uint32_t base; /**< Start memory address of the segment. */ + uint32_t length; /**< Number of data bytes in the segment. */ + uint8_t *data; /**< Pointer to array with the segment's data bytes. */ +} tFirmwareSegment; + +/** \brief Firmware file parser. */ +typedef struct t_firmware_parser +{ + /** \brief Initialization of the file parser. */ + void (*Init) (void); + /** \brief Uninitializes the file parser. */ + void (*Deinit) (void); + /** \brief Extract the firmware segments from the firmware file. */ + bool (*LoadFromFile) (char *firmwareFile); + /** \brief Obtains the number of segments. */ + uint32_t (*GetSegmentCount) (void); + /** \brief Obtains a segment. */ + const tFirmwareSegment * (*GetSegment) (uint32_t segmentIdx); +} tFirmwareParser; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void FirmwareInit(tFirmwareParser const * const parser); +void FirmwareDeinit(void); +bool FirmwareLoadFromFile(char *firmwareFile); +uint32_t FirmwareGetSegmentCount(void); +const tFirmwareSegment *FirmwareGetSegment(uint32_t segmentIdx); + +#ifdef __cplusplus +} +#endif + +#endif /* FIRMWARE_H */ +/********************************* end of firmware.h ***********************************/ + diff --git a/Host/Source/SerialBoot/main.c b/Host/Source/SerialBoot/main.c index 3fde7457..fa1d9b89 100644 --- a/Host/Source/SerialBoot/main.c +++ b/Host/Source/SerialBoot/main.c @@ -1,330 +1,365 @@ -/************************************************************************************//** -* \file main.c -* \brief SerialBoot command line demonstration program for OpenBLT. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* standard I/O library */ -#include /* string library */ -#include "xcpmaster.h" /* XCP master protocol module */ -#include "srecord.h" /* S-record file handling */ -#include "timeutil.h" /* time utility module */ - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -static void DisplayProgramInfo(void); -static void DisplayProgramUsage(void); -static sb_uint8 ParseCommandLine(sb_int32 argc, sb_char *argv[]); - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/** \brief Program return code if all went ok. */ -#define PROG_RESULT_OK (0) - -/** \brief Program return code if an error occurred. */ -#define PROG_RESULT_ERROR (1) - - -/**************************************************************************************** -* Local data declarations -****************************************************************************************/ -/** \brief Name of the serial device, such as COM4 or /dev/ttyUSB0. */ -static sb_char serialDeviceName[32]; - -/** \brief Serial communication speed in bits per second. */ -static sb_uint32 serialBaudrate; - -/** \brief Name of the S-record file. */ -static sb_char srecordFileName[128]; - - -/************************************************************************************//** -** \brief Program entry point. -** \param argc Number of program parameters. -** \param argv array to program parameter strings. -** \return 0 on success, > 0 on error. -** -****************************************************************************************/ -sb_int32 main(sb_int32 argc, sb_char *argv[]) -{ - sb_file hSrecord; - tSrecordParseResults fileParseResults; - tSrecordLineParseResults lineParseResults; - - /* disable buffering for the standard output to make sure printf does not wait until - * a newline character is detected before outputting text on the console. - */ - setbuf(stdout, SB_NULL); - - /* inform user about the program */ - DisplayProgramInfo(); - - /* start out by making sure program was started with the correct parameters */ - if (ParseCommandLine(argc, argv) == SB_FALSE) - { - /* parameters invalid. inform user about how this program works */ - DisplayProgramUsage(); - return PROG_RESULT_ERROR; - } - - /* -------------------- start the firmware update procedure ------------------------ */ - printf("Starting firmware update for \"%s\" using %s @ %u bits/s\n", srecordFileName, serialDeviceName, serialBaudrate); - - /* -------------------- validating the S-record file ------------------------------- */ - printf("Checking formatting of S-record file \"%s\"...", srecordFileName); - if (SrecordIsValid(srecordFileName) == SB_FALSE) - { - printf("ERROR\n"); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- opening the S-record file ---------------------------------- */ - printf("Opening S-record file \"%s\"...", srecordFileName); - if ((hSrecord = SrecordOpen(srecordFileName)) == SB_NULL) - { - printf("ERROR\n"); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- parsing the S-record file ---------------------------------- */ - printf("Parsing S-record file \"%s\"...", srecordFileName); - SrecordParse(hSrecord, &fileParseResults); - printf("OK\n"); - printf("-> Lowest memory address: 0x%08x\n", fileParseResults.address_low); - printf("-> Highest memory address: 0x%08x\n", fileParseResults.address_high); - printf("-> Total data bytes: %u\n", fileParseResults.data_bytes_total); - - /* -------------------- Open the serial port --------------------------------------- */ - printf("Opening serial port %s...", serialDeviceName); - if (XcpMasterInit(serialDeviceName, serialBaudrate) == SB_FALSE) - { - printf("ERROR\n"); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- Connect to XCP slave --------------------------------------- */ - printf("Connecting to bootloader..."); - if (XcpMasterConnect() == SB_FALSE) - { - /* no response. prompt the user to reset the system */ - printf("TIMEOUT\nReset your microcontroller..."); - } - /* now keep retrying until we get a response */ - while (XcpMasterConnect() == SB_FALSE) - { - /* delay a bit to not pump up the CPU load */ - TimeUtilDelayMs(20); - } - printf("OK\n"); - - /* -------------------- Prepare the programming session ---------------------------- */ - printf("Initializing programming session..."); - if (XcpMasterStartProgrammingSession() == SB_FALSE) - { - printf("ERROR\n"); - XcpMasterDisconnect(); - XcpMasterDeinit(); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- Erase memory ----------------------------------------------- */ - printf("Erasing %u bytes starting at 0x%08x...", fileParseResults.data_bytes_total, fileParseResults.address_low); - if (XcpMasterClearMemory(fileParseResults.address_low, (fileParseResults.address_high - fileParseResults.address_low)) == SB_FALSE) - { - printf("ERROR\n"); - XcpMasterDisconnect(); - XcpMasterDeinit(); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- Program data ----------------------------------------------- */ - printf("Programming data. Please wait..."); - /* loop through all S-records with program data */ - while (SrecordParseNextDataLine(hSrecord, &lineParseResults) == SB_TRUE) - { - if (XcpMasterProgramData(lineParseResults.address, lineParseResults.length, lineParseResults.data) == SB_FALSE) - { - printf("ERROR\n"); - XcpMasterDisconnect(); - XcpMasterDeinit(); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - } - printf("OK\n"); - - /* -------------------- Stop the programming session ------------------------------- */ - printf("Finishing programming session..."); - if (XcpMasterStopProgrammingSession() == SB_FALSE) - { - printf("ERROR\n"); - XcpMasterDisconnect(); - XcpMasterDeinit(); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- Disconnect from XCP slave and perform software reset ------- */ - printf("Performing software reset..."); - if (XcpMasterDisconnect() == SB_FALSE) - { - printf("ERROR\n"); - XcpMasterDeinit(); - SrecordClose(hSrecord); - return PROG_RESULT_ERROR; - } - printf("OK\n"); - - /* -------------------- close the serial port -------------------------------------- */ - XcpMasterDeinit(); - printf("Closed serial port %s\n", serialDeviceName); - - /* -------------------- close the S-record file ------------------------------------ */ - SrecordClose(hSrecord); - printf("Closed S-record file \"%s\"\n", srecordFileName); - - /* all done */ - printf("Firmware successfully updated!\n"); - return PROG_RESULT_OK; -} /*** end of main ***/ - - -/************************************************************************************//** -** \brief Outputs information to the user about this program. -** \return none. -** -****************************************************************************************/ -static void DisplayProgramInfo(void) -{ - printf("-------------------------------------------------------------------------\n"); - printf("SerialBoot version 1.00. Performs firmware updates via the serial port\n"); - printf("for a microcontroller based system that runs the OpenBLT bootloader.\n\n"); - printf("Copyright (c) by Feaser http://www.feaser.com\n"); - printf("-------------------------------------------------------------------------\n"); -} /*** end of DisplayProgramInfo ***/ - - -/************************************************************************************//** -** \brief Outputs information to the user about how to use this program. -** \return none. -** -****************************************************************************************/ -static void DisplayProgramUsage(void) -{ - printf("Usage: SerialBoot -d[device] -b[baudrate] [s-record file]\n\n"); -#ifdef PLATFORM_WIN32 - printf("Example: SerialBoot -dCOM4 -b57600 myfirmware.s19\n"); - printf(" -> Connects to COM4, configures a communication speed of 57600\n"); -#else - printf("Example: SerialBoot -d/dev/ttyS0 -b57600 myfirmware.s19\n"); - printf(" -> Connects to ttyS0, configures a communication speed of 57600\n"); -#endif - printf(" bits/second and programs the myfirmware.s19 file in non-\n"); - printf(" volatile memory of the microcontroller using OpenBLT.\n"); - printf("-------------------------------------------------------------------------\n"); -} /*** end of DisplayProgramUsage ***/ - - -/************************************************************************************//** -** \brief Parses the command line arguments. A fixed amount of arguments is expected. -** The program should be called as: -** SerialBoot -d[device] -b[baudrate] [s-record file] -** \param argc Number of program parameters. -** \param argv array to program parameter strings. -** \return SB_TRUE on success, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 ParseCommandLine(sb_int32 argc, sb_char *argv[]) -{ - sb_uint8 paramIdx; - sb_uint8 paramDfound = SB_FALSE; - sb_uint8 paramBfound = SB_FALSE; - sb_uint8 srecordfound = SB_FALSE; - - /* make sure the right amount of arguments are given */ - if (argc != 4) - { - return SB_FALSE; - } - - /* loop through all the command lina parameters, just skip the 1st one because this - * is the name of the program, which we are not interested in. - */ - for (paramIdx=1; paramIdx /* standard I/O functions */ +#include /* for string library */ +#include "xcploader.h" /* XCP loader module */ +#include "xcptpuart.h" /* XCP transport layer for UART */ +#include "firmware.h" /* Firmware module */ +#include "srecparser.h" /* S-record parser */ +#include "timeutil.h" /* for time utilities module */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/* Program return codes. */ +#define RESULT_OK (0) +#define RESULT_COMMANDLINE_ERROR (1) +#define RESULT_FIRMWARE_LOAD_ERROR (2) +#define RESULT_PROGRAM_START_ERROR (3) +#define RESULT_MEMORY_ERASE_ERROR (4) +#define RESULT_PROGRAM_STOP_ERROR (5) +#define RESULT_MEMORY_PROGRAM_ERROR (6) + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief The firmware filename that is specified at the command line. */ +static char *firmwareFilename; + +/** \brief XCP loader settings. */ +static tXcpSettings xcpSettings = +{ + .timeoutT1 = 1000, + .timeoutT3 = 2000, + .timeoutT4 = 10000, + .timeoutT5 = 1000, + .timeoutT7 = 2000 +}; + +/** \brief XCP UART transport layer settings. */ +static tXcpTpUartSettings xcpTpUartSettings = +{ + .baudrate = SERIALPORT_BR57600, + .portname = "/dev/ttyS0" +}; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +static void DisplayProgramInfo(void); +static void DisplayProgramUsage(void); +static bool ParseCommandLine(int argc, char *argv[]); + + +/************************************************************************************//** +** \brief This is the program entry point. +** \param argc Number of program arguments. +** \param argv Array with program arguments. +** \return Program return code. 0 for success, error code otherwise. +** +****************************************************************************************/ +int main(int argc, char *argv[]) +{ + int result = RESULT_OK; + uint32_t fwBaseAddress; + uint32_t fwTotalSize; + uint32_t segmentIdx; + const tFirmwareSegment *segment; + + /* -------------------- Display info ----------------------------------------------- */ + /* inform user about the program */ + DisplayProgramInfo(); + + /* -------------------- Process command line --------------------------------------- */ + /* start out by making sure program was started with the correct parameters */ + if (!ParseCommandLine(argc, argv)) + { + /* parameters invalid. inform user about how this program works */ + DisplayProgramUsage(); + return RESULT_COMMANDLINE_ERROR; + } + + /* -------------------- Initialization --------------------------------------------- */ + /* initialize the XCP loader module using the UART transport layer. */ + XcpLoaderInit(&xcpSettings, XcpTpUartGetTransport(), &xcpTpUartSettings); + /* initialize the firmware module and link the S-recorder parser */ + FirmwareInit(SRecParserGetParser()); + + /* -------------------- Parse the firmware file ------------------------------------ */ + /* attempt to load the firmware file */ + printf("Loading firmware file..."); fflush(stdout); + if (!FirmwareLoadFromFile(firmwareFilename)) + { + /* set error code and abort */ + printf("ERROR\n"); + result = RESULT_FIRMWARE_LOAD_ERROR; + goto finish; + } + printf("OK\n"); + /* determine firmware base address and total size */ + for (segmentIdx=0; segmentIdxbase; + fwTotalSize = segment->length; + } + else + { + /* update */ + if (segment->base < fwBaseAddress) + { + fwBaseAddress = segment->base; + } + fwTotalSize += segment->length; + } + } + /* display some firmware statistics */ + printf("-> Number of segments: %u\n", FirmwareGetSegmentCount()); + printf("-> Base memory address: 0x%08x\n", fwBaseAddress); + printf("-> Total data bytes: %u\n", fwTotalSize); + + /* -------------------- Connect to target ------------------------------------------ */ + printf("Connecting to bootloader..."); fflush(stdout); + if (!XcpLoaderConnect()) + { + /* no response. prompt the user to reset the system */ + printf("TIMEOUT\nReset your microcontroller..."); fflush(stdout); + /* now keep retrying until we get a response */ + while (!XcpLoaderConnect()) + { + /* delay a bit to not pump up the CPU load */ + TimeUtilDelayMs(20); + } + } + printf("OK\n"); + + /* -------------------- Start the programming session ------------------------------ */ + /* attempt to start the programming session */ + printf("Starting programming session..."); fflush(stdout); + if (!XcpLoaderStartProgrammingSession()) + { + /* set error code and abort */ + printf("ERROR\n"); + result = RESULT_PROGRAM_START_ERROR; + goto finish; + } + printf("OK\n"); + + /* -------------------- Erase memory ----------------------------------------------- */ + /* erase each segment one at a time */ + for (segmentIdx=0; segmentIdxlength, segment->base); fflush(stdout); + if (!XcpLoaderClearMemory(segment->base, segment->length)) + { + /* set error code and abort */ + printf("ERROR\n"); + result = RESULT_MEMORY_ERASE_ERROR; + goto finish; + } + printf("OK\n"); + } + + /* -------------------- Program data ----------------------------------------------- */ + /* program each segment one at a time */ + for (segmentIdx=0; segmentIdxlength, segment->base); fflush(stdout); + if (!XcpLoaderProgramData(segment->base, segment->length, segment->data)) + { + /* set error code and abort */ + printf("ERROR\n"); + result = RESULT_MEMORY_PROGRAM_ERROR; + goto finish; + } + printf("OK\n"); + } + + /* -------------------- Stop the programming session ------------------------------- */ + /* attempt to stop the programming session */ + printf("Finishing programming session..."); fflush(stdout); + if (!XcpLoaderStopProgrammingSession()) + { + /* set error code and abort */ + printf("ERROR\n"); + result = RESULT_PROGRAM_STOP_ERROR; + goto finish; + } + printf("OK\n"); + + /* -------------------- Cleanup ---------------------------------------------------- */ +finish: + /* uninitialize the firmware module */ + FirmwareDeinit(); + /* uninitialize the XCP loader module. note that this automatically disconnects the + * slave, if connected, by requesting it to perform a reset. + */ + XcpLoaderDeinit(); + /* give result back */ + return result; +} /*** end of main ***/ + + +/************************************************************************************//** +** \brief Outputs information to the user about this program. +** \return none. +** +****************************************************************************************/ +static void DisplayProgramInfo(void) +{ + printf("-------------------------------------------------------------------------\n"); + printf("SerialBoot version 2.00. Performs firmware updates via the serial port\n"); + printf("for a microcontroller based system that runs the OpenBLT bootloader.\n\n"); + printf("Copyright (c) by Feaser http://www.feaser.com\n"); + printf("-------------------------------------------------------------------------\n"); +} /*** end of DisplayProgramInfo ***/ + + +/************************************************************************************//** +** \brief Outputs information to the user about how to use this program. +** \return none. +** +****************************************************************************************/ +static void DisplayProgramUsage(void) +{ + printf("Usage: SerialBoot -d[device] -b[baudrate] [s-record file]\n\n"); +#ifdef PLATFORM_WIN32 + printf("Example: SerialBoot -dCOM4 -b57600 myfirmware.s19\n"); + printf(" -> Connects to COM4, configures a communication speed of 57600\n"); +#else + printf("Example: SerialBoot -d/dev/ttyS0 -b57600 myfirmware.s19\n"); + printf(" -> Connects to ttyS0, configures a communication speed of 57600\n"); +#endif + printf(" bits/second and programs the myfirmware.s19 file in non-\n"); + printf(" volatile memory of the microcontroller using OpenBLT.\n"); + printf(" Supported baudrates are: 9600, 19200, 38400, 57600 and\n"); + printf(" 115200 bits/second.\n"); + printf("-------------------------------------------------------------------------\n"); +} /*** end of DisplayProgramUsage ***/ + + +/************************************************************************************//** +** \brief Parses the command line arguments. A fixed amount of arguments is expected. +** The program should be called as: +** SerialBoot -d[device] -b[baudrate] [s-record file] +** \param argc Number of program parameters. +** \param argv array to program parameter strings. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +static bool ParseCommandLine(int argc, char *argv[]) +{ + uint8_t paramIdx; + bool firmwareFileFound = false; + uint32_t baudrateValue; + + /* make sure that enough arguments were specified. this program needs at least 2. the + * first one is always the program name and the second one is the s-record file. + */ + if (argc < 2) + { + return false; + } + + /* loop through all the command line parameters, just skip the 1st one because this + * is the name of the program, which we are not interested in. + */ + for (paramIdx=1; paramIdx /* for NULL declaration */ +#include /* for assertions */ +#include /* UNIX standard functions */ +#include /* POSIX terminal control */ +#include /* file control definitions */ +#include /* system I/O control */ +#include "serialport.h" /* serial port module */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Invalid serial port device handle. */ +#define SERIALPORT_INVALID_HANDLE (-1) + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +static int32_t portHandle = SERIALPORT_INVALID_HANDLE; + + +/**************************************************************************************** +* Local constant declarations +****************************************************************************************/ +/** \brief Lookup table for converting this module's generic baudrate value to a value + * supported by the low level interface. + */ +static const speed_t baudrateLookup[] = +{ + B9600, /**< Index 0 = SERIALPORT_BR9600 */ + B19200, /**< Index 1 = SERIALPORT_BR19200 */ + B38400, /**< Index 2 = SERIALPORT_BR38400 */ + B57600, /**< Index 3 = SERIALPORT_BR57600 */ + B115200 /**< Index 4 = SERIALPORT_BR115200 */ +}; + + +/************************************************************************************//** +** \brief Opens the connection with the serial port configured as 8,N,1 and no flow +** control. +** \param portname The name of the serial port to open, i.e. /dev/ttyUSB0. +** \param baudrate The desired communication speed. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +bool SerialPortOpen(char *portname, tSerialPortBaudrate baudrate) +{ + struct termios options; + int32_t iFlags; + + /* check parameters */ + assert(portname != NULL); + + /* open the port */ + portHandle = open(portname, O_RDWR | O_NOCTTY | O_NDELAY); + /* check the result */ + if (portHandle == SERIALPORT_INVALID_HANDLE) + { + return false; + } + /* configure the device to block during read operations */ + if (fcntl(portHandle, F_SETFL, 0) == -1) + { + SerialPortClose(); + return false; + } + /* get the current options for the port */ + if (tcgetattr(portHandle, &options) == -1) + { + SerialPortClose(); + return false; + } + /* configure the baudrate */ + if (cfsetispeed(&options, baudrateLookup[baudrate]) == -1) + { + SerialPortClose(); + return false; + } + if (cfsetospeed(&options, baudrateLookup[baudrate]) == -1) + { + SerialPortClose(); + return false; + } + + /* input modes - clear indicated ones giving: no break, no CR to NL, + * no parity check, no strip char, no start/stop output (sic) control + */ + options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + /* output modes - clear giving: no post processing such as NL to CR+NL */ + options.c_oflag &= ~(OPOST); + /* control modes - set 8 bit chars */ + options.c_cflag |= (CS8); + /* local modes - clear giving: echoing off, canonical off (no erase with + * backspace, ^U,...), no extended functions, no signal chars (^Z,^C) + */ + options.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + /* configure timeouts */ + options.c_cc[VMIN] = 0; + options.c_cc[VTIME] = 1; /* in units of 1/10th of a second */ + /* set the new options for the port */ + if (tcsetattr(portHandle, TCSAFLUSH, &options) == -1) + { + SerialPortClose(); + return false; + } + /* turn on DTR */ + iFlags = TIOCM_DTR; + ioctl(portHandle, TIOCMBIS, &iFlags); + /* success */ + return true; +} /*** end of SerialPortOpen ***/ + + +/************************************************************************************//** +** \brief Closes the connection with the serial port. +** \return None. +** +****************************************************************************************/ +void SerialPortClose(void) +{ + /* close the port handle if valid */ + if (portHandle != SERIALPORT_INVALID_HANDLE) + { + close(portHandle); + } + /* invalidate handle */ + portHandle = SERIALPORT_INVALID_HANDLE; +} /*** end of SerialPortClose ***/ + + +/************************************************************************************//** +** \brief Writes data to the serial port. +** \param data Pointer to byte array with data to write. +** \param length Number of bytes to write. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +bool SerialPortWrite(uint8_t *data, uint32_t length) +{ + size_t bytesWritten; + + /* check parameters */ + assert(data != NULL); + assert(length > 0); + + /* submit the data for sending */ + bytesWritten = write(portHandle, data, length); + /* check and return the result */ + return (bytesWritten == length); +} /*** end of SerialPortWrite ***/ + + +/************************************************************************************//** +** \brief Reads data from the serial port in a blocking manner. +** \param data Pointer to byte array to store read data. +** \param length Number of bytes to read. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +bool SerialPortRead(uint8_t *data, uint32_t length) +{ + size_t bytesRead; + + /* check parameters */ + assert(data != NULL); + assert(length > 0); + + /* attempt to read the requested data */ + bytesRead = read(portHandle, data, length); + /* check and return the result */ + return (bytesRead == length); +} /*** end of SerialPortRead ***/ + + +/*********************************** end of serialport.c *******************************/ + diff --git a/Host/Source/SerialBoot/port/linux/timeutil.c b/Host/Source/SerialBoot/port/linux/timeutil.c index 79a6db15..7b0d2baa 100644 --- a/Host/Source/SerialBoot/port/linux/timeutil.c +++ b/Host/Source/SerialBoot/port/linux/timeutil.c @@ -1,69 +1,69 @@ -/************************************************************************************//** -* \file port\linux\timeutil.c -* \brief Time utility source file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* UNIX standard functions */ -#include /* file control definitions */ -#include /* time definitions */ - - -/************************************************************************************//** -** \brief Get the system time in milliseconds. -** \return Time in milliseconds. -** -****************************************************************************************/ -sb_uint32 TimeUtilGetSystemTimeMs(void) -{ - struct timeval tv; - - if (gettimeofday(&tv, SB_NULL) != 0) - { - return 0; - } - - return (sb_uint32)((tv.tv_sec * 1000ul) + (tv.tv_usec / 1000ul)); -} /*** end of XcpTransportClose ***/ - - -/************************************************************************************//** -** \brief Performs a delay of the specified amount of milliseconds. -** \param delay Delay time in milliseconds. -** \return none. -** -****************************************************************************************/ -void TimeUtilDelayMs(sb_uint16 delay) -{ - usleep(1000 * delay); -} /*** end of TimeUtilDelayMs **/ - - -/*********************************** end of xcptransport.c *****************************/ +/************************************************************************************//** +* \file port\linux\timeutil.c +* \brief Time utility source file. +* \ingroup SerialBoot +* \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 NULL declaration */ +#include /* UNIX standard functions */ +#include /* time definitions */ +#include "timeutil.h" /* for time utilities module */ + + +/************************************************************************************//** +** \brief Get the system time in milliseconds. +** \return Time in milliseconds. +** +****************************************************************************************/ +uint32_t TimeUtilGetSystemTimeMs(void) +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL) != 0) + { + return 0; + } + + return (uint32_t)((tv.tv_sec * 1000ul) + (tv.tv_usec / 1000ul)); +} /*** end of XcpTransportClose ***/ + + +/************************************************************************************//** +** \brief Performs a delay of the specified amount of milliseconds. +** \param delay Delay time in milliseconds. +** \return none. +** +****************************************************************************************/ +void TimeUtilDelayMs(uint16_t delay) +{ + usleep(1000 * delay); +} /*** end of TimeUtilDelayMs **/ + + +/*********************************** end of timeutil.c *********************************/ + diff --git a/Host/Source/SerialBoot/port/linux/xcptransport.c b/Host/Source/SerialBoot/port/linux/xcptransport.c deleted file mode 100644 index 40229aa9..00000000 --- a/Host/Source/SerialBoot/port/linux/xcptransport.c +++ /dev/null @@ -1,304 +0,0 @@ -/************************************************************************************//** -* \file port\linux\xcptransport.c -* \brief XCP transport layer interface source file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* standard I/O library */ -#include /* string function definitions */ -#include /* UNIX standard functions */ -#include /* file control definitions */ -#include /* error number definitions */ -#include /* POSIX terminal control */ -#include /* system I/O control */ -#include "xcpmaster.h" /* XCP master protocol module */ -#include "timeutil.h" /* time utility module */ - - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/** \brief Invalid UART device/file handle. */ -#define UART_INVALID_HANDLE (-1) - -/** \brief maximum number of bytes in a transmit/receive XCP packet in UART. */ -#define XCP_MASTER_UART_MAX_DATA ((XCP_MASTER_TX_MAX_DATA>XCP_MASTER_RX_MAX_DATA) ? \ - (XCP_MASTER_TX_MAX_DATA+1) : (XCP_MASTER_RX_MAX_DATA+1)) - -/** \brief The smallest time in millisecond that the UART is configured for. */ -#define UART_RX_TIMEOUT_MIN_MS (100) - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -static speed_t XcpTransportGetBaudrateMask(sb_uint32 baudrate); - - -/**************************************************************************************** -* Local data declarations -****************************************************************************************/ -static tXcpTransportResponsePacket responsePacket; -static sb_int32 hUart = UART_INVALID_HANDLE; - - -/************************************************************************************//** -** \brief Initializes the communication interface used by this transport layer. -** \param device Serial communication device name. For example "COM4". -** \param baudrate Communication speed in bits/sec. -** \return SB_TRUE if successful, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpTransportInit(sb_char *device, sb_uint32 baudrate) -{ - struct termios options; - int iFlags; - - /* open the port */ - hUart = open(device, O_RDWR | O_NOCTTY | O_NDELAY); - /* verify the result */ - if (hUart == UART_INVALID_HANDLE) - { - return SB_FALSE; - } - /* configure the device to block during read operations */ - if (fcntl(hUart, F_SETFL, 0) == -1) - { - XcpTransportClose(); - return SB_FALSE; - } - /* get the current options for the port */ - if (tcgetattr(hUart, &options) == -1) - { - XcpTransportClose(); - return SB_FALSE; - } - /* configure the baudrate */ - if (cfsetispeed(&options, XcpTransportGetBaudrateMask(baudrate)) == -1) - { - XcpTransportClose(); - return SB_FALSE; - } - if (cfsetospeed(&options, XcpTransportGetBaudrateMask(baudrate)) == -1) - { - XcpTransportClose(); - return SB_FALSE; - } - /* enable the receiver and set local mode */ - options.c_cflag |= (CLOCAL | CREAD); - /* configure 8-n-1 */ - options.c_cflag &= ~PARENB; - options.c_cflag &= ~CSTOPB; - options.c_cflag &= ~CSIZE; - options.c_cflag |= CS8; - /* disable hardware flow control */ - options.c_cflag &= ~CRTSCTS; - /* configure raw input */ - options.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOE); - /* configure raw output */ - options.c_oflag &= ~OPOST; - /* configure timeouts */ - options.c_cc[VMIN] = 0; - options.c_cc[VTIME] = UART_RX_TIMEOUT_MIN_MS/100; /* 1/10th of a second */ - /* set the new options for the port */ - if (tcsetattr(hUart, TCSAFLUSH, &options) == -1) - { - XcpTransportClose(); - return SB_FALSE; - } - /* turn on DTR */ - iFlags = TIOCM_DTR; - ioctl(hUart, TIOCMBIS, &iFlags); - /* success */ - return SB_TRUE; -} /*** end of XcpTransportInit ***/ - - -/************************************************************************************//** -** \brief Transmits an XCP packet on the transport layer and attemps to receive the -** response within the given timeout. The data in the response packet is -** stored in an internal data buffer that can be obtained through function -** XcpTransportReadResponsePacket(). -** \return SB_TRUE is the response packet was successfully received and stored, -** SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpTransportSendPacket(sb_uint8 *data, sb_uint8 len, sb_uint16 timeOutMs) -{ - sb_uint16 cnt; - static sb_uint8 xcpUartBuffer[XCP_MASTER_UART_MAX_DATA]; /* static to lower stack load */ - sb_uint16 xcpUartLen; - sb_int32 bytesSent; - sb_int32 bytesToRead; - sb_int32 bytesRead; - sb_uint8 *uartReadDataPtr; - sb_uint32 timeoutTime; - sb_uint32 nowTime; - ssize_t result; - - /* ------------------------ XCP packet transmission -------------------------------- */ - /* prepare the XCP packet for transmission on UART. this is basically the same as the - * xcp packet data but just the length of the packet is added to the first byte. - */ - xcpUartLen = len+1; - xcpUartBuffer[0] = len; - for (cnt=0; cnt 0) - { - result = read(hUart, &responsePacket.len, bytesToRead); - if (result != -1) - { - bytesRead = result; - /* one byte should be read and it should contain the packet length, which cannot be 0 */ - if ((bytesRead == bytesToRead) && (responsePacket.len > 0)) - { - /* valid packet length received so stop this loop to continue with the reception - * remaining packet bytes - */ - bytesToRead = 0; - } - } - /* check for timeout if not yet done */ - if ( (bytesToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) ) - { - /* timeout occurred */ - return SB_FALSE; - } - } - - /* read the rest of the packet */ - bytesToRead = responsePacket.len; - uartReadDataPtr = &responsePacket.data[0]; - while(bytesToRead > 0) - { - result = read(hUart, uartReadDataPtr, bytesToRead); - if (result != -1) - { - bytesRead = result; - /* update the bytes that were already read */ - uartReadDataPtr += bytesRead; - bytesToRead -= bytesRead; - } - /* check for timeout if not yet done */ - if ( (bytesToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) ) - { - /* timeout occurred */ - return SB_FALSE; - } - } - /* still here so the complete packet was received */ - return SB_TRUE; -} /*** end of XcpMasterTpSendPacket ***/ - - -/************************************************************************************//** -** \brief Reads the data from the response packet. Make sure to not call this -** function while XcpTransportSendPacket() is active, because the data won't be -** valid then. -** \return Pointer to the response packet data. -** -****************************************************************************************/ -tXcpTransportResponsePacket *XcpTransportReadResponsePacket(void) -{ - return &responsePacket; -} /*** end of XcpTransportReadResponsePacket ***/ - - -/************************************************************************************//** -** \brief Closes the communication channel. -** \return none. -** -****************************************************************************************/ -void XcpTransportClose(void) -{ - /* close the COM port handle if valid */ - if (hUart != UART_INVALID_HANDLE) - { - close(hUart); - } - - /* set handles to invalid */ - hUart = UART_INVALID_HANDLE; -} /*** end of XcpTransportClose ***/ - - -/************************************************************************************//** -** \brief Converts the baudrate value to a bitmask value used by termios. Currently -** supports the most commonly used baudrates. -** \return none. -** -****************************************************************************************/ -static speed_t XcpTransportGetBaudrateMask(sb_uint32 baudrate) -{ - speed_t result; - - switch (baudrate) - { - case 115200: - result = B115200; - break; - case 57600: - result = B57600; - break; - case 38400: - result = B38400; - break; - case 19200: - result = B19200; - break; - case 9600: - default: - result = B9600; - break; - } - return result; -} /*** end of XcpTransportGetBaudrateMask ***/ - - -/*********************************** end of xcptransport.c *****************************/ diff --git a/Host/Source/SerialBoot/port/win32/xcptransport.c b/Host/Source/SerialBoot/port/win32/xcptransport.c deleted file mode 100644 index 3ea1323d..00000000 --- a/Host/Source/SerialBoot/port/win32/xcptransport.c +++ /dev/null @@ -1,265 +0,0 @@ -/************************************************************************************//** -* \file port\win32\xcptransport.c -* \brief XCP transport layer interface source file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* for WIN32 library */ -#include /* string library */ -#include "xcpmaster.h" /* XCP master protocol module */ -#include "timeutil.h" /* time utility module */ - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -#define UART_TX_BUFFER_SIZE (1024) /**< transmission buffer size */ -#define UART_RX_BUFFER_SIZE (1024) /**< reception buffer size */ - -/** \brief maximum number of bytes in a transmit/receive XCP packet in UART. */ -#define XCP_MASTER_UART_MAX_DATA ((XCP_MASTER_TX_MAX_DATA>XCP_MASTER_RX_MAX_DATA) ? \ - (XCP_MASTER_TX_MAX_DATA+1) : (XCP_MASTER_RX_MAX_DATA+1)) - - -/**************************************************************************************** -* Local data declarations -****************************************************************************************/ -static tXcpTransportResponsePacket responsePacket; -static HANDLE hUart = INVALID_HANDLE_VALUE; - - -/************************************************************************************//** -** \brief Initializes the communication interface used by this transport layer. -** \param device Serial communication device name. For example "COM4". -** \param baudrate Communication speed in bits/sec. -** \return SB_TRUE if successful, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpTransportInit(sb_char *device, sb_uint32 baudrate) -{ - COMMTIMEOUTS timeouts = { 0 }; - DCB dcbSerialParams = { 0 }; - char portStr[64] = "\\\\.\\\0"; - - /* construct the COM port name as a string */ - strcat_s(portStr, 59, device); - - /* obtain access to the COM port */ - hUart = CreateFile(portStr, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, 0); - - /* validate COM port handle */ - if (hUart == INVALID_HANDLE_VALUE) - { - return SB_FALSE; - } - - /* get current COM port configuration */ - dcbSerialParams.DCBlength = sizeof(dcbSerialParams); - if (!GetCommState(hUart, &dcbSerialParams)) - { - XcpTransportClose(); - return SB_FALSE; - } - - /* configure the baudrate and 8,n,1 */ - dcbSerialParams.BaudRate = baudrate; - dcbSerialParams.ByteSize = 8; - dcbSerialParams.StopBits = ONESTOPBIT; - dcbSerialParams.Parity = NOPARITY; - dcbSerialParams.fOutX = FALSE; - dcbSerialParams.fInX = FALSE; - dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE; - dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; - - if (!SetCommState(hUart, &dcbSerialParams)) - { - XcpTransportClose(); - return SB_FALSE; - } - - /* set communication timeout parameters */ - timeouts.ReadIntervalTimeout = 0; - timeouts.ReadTotalTimeoutConstant = 0; - timeouts.ReadTotalTimeoutMultiplier = 100; - timeouts.WriteTotalTimeoutConstant = 0; - timeouts.WriteTotalTimeoutMultiplier = 100; - - if (!SetCommTimeouts(hUart, &timeouts)) - { - XcpTransportClose(); - return SB_FALSE; - } - - /* set transmit and receive buffer sizes */ - if(!SetupComm(hUart, UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE)) - { - XcpTransportClose(); - return SB_FALSE; - } - - /* empty the transmit and receive buffers */ - if (!FlushFileBuffers(hUart)) - { - XcpTransportClose(); - return SB_FALSE; - } - /* successfully connected to the serial device */ - return SB_TRUE; -} /*** end of XcpTransportInit ***/ - - -/************************************************************************************//** -** \brief Transmits an XCP packet on the transport layer and attemps to receive the -** response within the given timeout. The data in the response packet is -** stored in an internal data buffer that can be obtained through function -** XcpTransportReadResponsePacket(). -** \return SB_TRUE is the response packet was successfully received and stored, -** SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpTransportSendPacket(sb_uint8 *data, sb_uint8 len, sb_uint16 timeOutMs) -{ - sb_uint32 dwWritten = 0; - sb_uint32 dwRead = 0; - sb_uint32 dwToRead; - sb_uint16 cnt; - static sb_uint8 xcpUartBuffer[XCP_MASTER_UART_MAX_DATA]; /* static to lower stack load */ - sb_uint16 xcpUartLen; - sb_uint8 *uartReadDataPtr; - sb_uint32 timeoutTime; - - /* ------------------------ XCP packet transmission -------------------------------- */ - /* prepare the XCP packet for transmission on UART. this is basically the same as the - * xcp packet data but just the length of the packet is added to the first byte. - */ - xcpUartLen = len+1; - xcpUartBuffer[0] = len; - for (cnt=0; cnt 0) - { - dwRead = 0; - if (ReadFile(hUart, &responsePacket.len, dwToRead, &dwRead, NULL)) - { - /* one byte should be read and it should contain the packet length, which cannot be 0 */ - if ((dwRead == dwToRead) && (responsePacket.len > 0)) - { - /* valid packet length received so stop this loop to continue with the reception - * remaining packet bytes - */ - dwToRead = 0; - } - } - /* check for timeout if not yet done */ - if ( (dwToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) ) - { - /* timeout occurred */ - return SB_FALSE; - } - } - - /* read the rest of the packet */ - dwToRead = responsePacket.len; - uartReadDataPtr = &responsePacket.data[0]; - while(dwToRead > 0) - { - dwRead = 0; - if (ReadFile(hUart, uartReadDataPtr, dwToRead, &dwRead, NULL)) - { - /* update the bytes that were already read */ - uartReadDataPtr += dwRead; - dwToRead -= dwRead; - } - /* check for timeout if not yet done */ - if ( (dwToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) ) - { - /* timeout occurred */ - return SB_FALSE; - } - } - /* still here so the complete packet was received */ - return SB_TRUE; -} /*** end of XcpMasterTpSendPacket ***/ - - -/************************************************************************************//** -** \brief Reads the data from the response packet. Make sure to not call this -** function while XcpTransportSendPacket() is active, because the data won't be -** valid then. -** \return Pointer to the response packet data. -** -****************************************************************************************/ -tXcpTransportResponsePacket *XcpTransportReadResponsePacket(void) -{ - return &responsePacket; -} /*** end of XcpTransportReadResponsePacket ***/ - - -/************************************************************************************//** -** \brief Closes the communication channel. -** \return none. -** -****************************************************************************************/ -void XcpTransportClose(void) -{ - /* close the COM port handle if valid */ - if (hUart != INVALID_HANDLE_VALUE) - { - CloseHandle(hUart); - } - - /* set handles to invalid */ - hUart = INVALID_HANDLE_VALUE; -} /*** end of XcpTransportClose ***/ - - -/*********************************** end of xcptransport.c *****************************/ diff --git a/Host/Source/SerialBoot/port/windows/serialport.c b/Host/Source/SerialBoot/port/windows/serialport.c new file mode 100644 index 00000000..bc2f1f9c --- /dev/null +++ b/Host/Source/SerialBoot/port/windows/serialport.c @@ -0,0 +1,260 @@ +/************************************************************************************//** +* \file port\windows\serialport.c +* \brief Serial port source file. +* \ingroup SerialBoot +* \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 NULL declaration */ +#include /* for windows library */ +#include /* for assertions */ +#include "serialport.h" /* serial port module */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +#define UART_TX_BUFFER_SIZE (1024) /**< transmission buffer size */ +#define UART_RX_BUFFER_SIZE (1024) /**< reception buffer size */ + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +static HANDLE hUart = INVALID_HANDLE_VALUE; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +static uint32_t SerialConvertBaudrate(tSerialPortBaudrate baudrate); + + +/************************************************************************************//** +** \brief Opens the connection with the serial port configured as 8,N,1 and no flow +** control. +** \param portname The name of the serial port to open, i.e. COM4. +** \param baudrate The desired communication speed. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +bool SerialPortOpen(char *portname, tSerialPortBaudrate baudrate) +{ + COMMTIMEOUTS timeouts = { 0 }; + DCB dcbSerialParams = { 0 }; + char portStr[64] = "\\\\.\\\0"; + + /* check parameters */ + assert(portname != NULL); + + /* construct the COM port name as a string */ + strcat_s(portStr, 59, portname); + + /* obtain access to the COM port */ + hUart = CreateFile(portStr, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0); + + /* validate COM port handle */ + if (hUart == INVALID_HANDLE_VALUE) + { + return false; + } + + /* get current COM port configuration */ + dcbSerialParams.DCBlength = sizeof(dcbSerialParams); + if (!GetCommState(hUart, &dcbSerialParams)) + { + CloseHandle(hUart); + return false; + } + + /* configure the baudrate and 8,n,1 */ + dcbSerialParams.BaudRate = SerialConvertBaudrate(baudrate); + dcbSerialParams.ByteSize = 8; + dcbSerialParams.StopBits = ONESTOPBIT; + dcbSerialParams.Parity = NOPARITY; + dcbSerialParams.fOutX = FALSE; + dcbSerialParams.fInX = FALSE; + dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE; + dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; + + if (!SetCommState(hUart, &dcbSerialParams)) + { + CloseHandle(hUart); + return false; + } + + /* set communication timeout parameters */ + timeouts.ReadIntervalTimeout = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.ReadTotalTimeoutMultiplier = 100; + timeouts.WriteTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 100; + + if (!SetCommTimeouts(hUart, &timeouts)) + { + CloseHandle(hUart); + return false; + } + + /* set transmit and receive buffer sizes */ + if (!SetupComm(hUart, UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE)) + { + CloseHandle(hUart); + return false; + } + + /* empty the transmit and receive buffers */ + if (!FlushFileBuffers(hUart)) + { + CloseHandle(hUart); + return false; + } + /* successfully connected to the serial device */ + return true; +} /*** end of SerialPortOpen ***/ + + +/************************************************************************************//** +** \brief Closes the connection with the serial port. +** \return None. +** +****************************************************************************************/ +void SerialPortClose(void) +{ + /* close the COM port handle if valid */ + if (hUart != INVALID_HANDLE_VALUE) + { + CloseHandle(hUart); + } + + /* set handles to invalid */ + hUart = INVALID_HANDLE_VALUE; +} /*** end of SerialPortClose ***/ + + +/************************************************************************************//** +** \brief Writes data to the serial port. +** \param data Pointer to byte array with data to write. +** \param length Number of bytes to write. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +bool SerialPortWrite(uint8_t *data, uint32_t length) +{ + uint32_t dwWritten = 0; + + /* check parameters */ + assert(data != NULL); + assert(length > 0); + + /* submit the data for transmission with the serial port */ + if (!WriteFile(hUart, data, length, &dwWritten, NULL)) + { + return false; + } + /* double check that all bytes were actually transmitted */ + if (dwWritten != length) + { + return false; + } + + /* success */ + return true; +} /*** end of SerialPortWrite ***/ + + +/************************************************************************************//** +** \brief Reads data from the serial port in a blocking manner. +** \param data Pointer to byte array to store read data. +** \param length Number of bytes to read. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +bool SerialPortRead(uint8_t *data, uint32_t length) +{ + uint32_t dwRead = 0; + + /* check parameters */ + assert(data != NULL); + assert(length > 0); + + /* attempt to read data from the serial port */ + if (!ReadFile(hUart, data, length, &dwRead, NULL)) + { + return false; + } + /* double check that all bytes were actually read */ + if (dwRead != length) + { + return false; + } + + /* success */ + return true; +} /*** end of SerialPortRead ***/ + + +/************************************************************************************//** +** \brief Opens the connection with the serial port configured as 8,N,1 and no flow +** control. +** \param portname The name of the serial port to open, i.e. COM4. +** \param baudrate The desired communication speed. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +static uint32_t SerialConvertBaudrate(tSerialPortBaudrate baudrate) +{ + uint32_t result; + + switch (baudrate) + { + case SERIALPORT_BR9600: + result = CBR_9600; + break; + case SERIALPORT_BR19200: + result = CBR_19200; + break; + case SERIALPORT_BR38400: + result = CBR_38400; + break; + case SERIALPORT_BR57600: + result = CBR_57600; + break; + case SERIALPORT_BR115200: + result = CBR_115200; + break; + default: + result = CBR_9600; + break; + } + return result; +} /*** end of SerialConvertBaudrate ***/ + + +/*********************************** end of serialport.c *******************************/ + diff --git a/Host/Source/SerialBoot/port/win32/timeutil.c b/Host/Source/SerialBoot/port/windows/timeutil.c similarity index 82% rename from Host/Source/SerialBoot/port/win32/timeutil.c rename to Host/Source/SerialBoot/port/windows/timeutil.c index 95f9a7bd..714b761c 100644 --- a/Host/Source/SerialBoot/port/win32/timeutil.c +++ b/Host/Source/SerialBoot/port/windows/timeutil.c @@ -1,60 +1,60 @@ -/************************************************************************************//** -* \file port\win32\timeutil.c -* \brief Time utility source file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* for WIN32 library */ - - -/************************************************************************************//** -** \brief Get the system time in milliseconds. -** \return Time in milliseconds. -** -****************************************************************************************/ -sb_uint32 TimeUtilGetSystemTimeMs(void) -{ - return GetTickCount(); -} /*** end of XcpTransportClose ***/ - - -/************************************************************************************//** -** \brief Performs a delay of the specified amount of milliseconds. -** \param delay Delay time in milliseconds. -** \return none. -** -****************************************************************************************/ -void TimeUtilDelayMs(sb_uint16 delay) -{ - Sleep(delay); -} /*** end of TimeUtilDelayMs **/ - - -/*********************************** end of timeutil.c *********************************/ +/************************************************************************************//** +* \file port\windows\timeutil.c +* \brief Time utility source file. +* \ingroup SerialBoot +* \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 windows library */ +#include "timeutil.h" /* for time utilities module */ + + +/************************************************************************************//** +** \brief Get the system time in milliseconds. +** \return Time in milliseconds. +** +****************************************************************************************/ +uint32_t TimeUtilGetSystemTimeMs(void) +{ + return GetTickCount(); +} /*** end of XcpTransportClose ***/ + + +/************************************************************************************//** +** \brief Performs a delay of the specified amount of milliseconds. +** \param delay Delay time in milliseconds. +** \return none. +** +****************************************************************************************/ +void TimeUtilDelayMs(uint16_t delay) +{ + Sleep(delay); +} /*** end of TimeUtilDelayMs **/ + + +/*********************************** end of timeutil.c *********************************/ + diff --git a/Host/Source/SerialBoot/xcpmaster.h b/Host/Source/SerialBoot/serialport.h similarity index 59% rename from Host/Source/SerialBoot/xcpmaster.h rename to Host/Source/SerialBoot/serialport.h index c9fa33e0..e82ab8dd 100644 --- a/Host/Source/SerialBoot/xcpmaster.h +++ b/Host/Source/SerialBoot/serialport.h @@ -1,66 +1,70 @@ -/************************************************************************************//** -* \file xcpmaster.h -* \brief XCP Master header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 -****************************************************************************************/ -#ifndef XCPMASTER_H -#define XCPMASTER_H - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/** \brief Configure number of bytes in the master->slave data packet. Should be at least - * equal or larger than that configured on the slave. - */ -#define XCP_MASTER_TX_MAX_DATA (255) - -/** \brief Configure number of bytes in the slave->master data packet. Should be at least - * equal or larger than that configured on the slave. - */ -#define XCP_MASTER_RX_MAX_DATA (255) - - -/**************************************************************************************** -* Include files -****************************************************************************************/ -#include "xcptransport.h" /* XCP transport layer */ - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -sb_uint8 XcpMasterInit(sb_char *device, sb_uint32 baudrate); -void XcpMasterDeinit(void); -sb_uint8 XcpMasterConnect(void); -sb_uint8 XcpMasterDisconnect(void); -sb_uint8 XcpMasterStartProgrammingSession(void); -sb_uint8 XcpMasterStopProgrammingSession(void); -sb_uint8 XcpMasterClearMemory(sb_uint32 addr, sb_uint32 len); -sb_uint8 XcpMasterReadData(sb_uint32 addr, sb_uint32 len, sb_uint8 data[]); -sb_uint8 XcpMasterProgramData(sb_uint32 addr, sb_uint32 len, sb_uint8 data[]); - - -#endif /* XCPMASTER_H */ -/*********************************** end of xcpmaster.h ********************************/ +/************************************************************************************//** +* \file serialport.h +* \brief Serial port header file. +* \ingroup SerialBoot +* \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 +****************************************************************************************/ +#ifndef SERIALPORT_H +#define SERIALPORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include /* for standard integer types */ +#include /* for boolean type */ + + +/**************************************************************************************** +* Typde definitions +****************************************************************************************/ +/** \brief Enumaration of the supported baudrates. */ +typedef enum +{ + SERIALPORT_BR9600 = 0, /**< 9600 bits/sec */ + SERIALPORT_BR19200 = 1, /**< 19200 bits/sec */ + SERIALPORT_BR38400 = 2, /**< 38400 bits/sec */ + SERIALPORT_BR57600 = 3, /**< 57600 bits/sec */ + SERIALPORT_BR115200 = 4 /**< 115200 bits/sec */ +} tSerialPortBaudrate; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +bool SerialPortOpen(char *portname, tSerialPortBaudrate baudrate); +void SerialPortClose(void); +bool SerialPortWrite(uint8_t *data, uint32_t length); +bool SerialPortRead(uint8_t *data, uint32_t length); + +#ifdef __cplusplus +} +#endif + +#endif /* SERIALPORT_H */ +/********************************* end of serialport.h *********************************/ + diff --git a/Host/Source/SerialBoot/srecord.c b/Host/Source/SerialBoot/srecord.c deleted file mode 100644 index 0faffb23..00000000 --- a/Host/Source/SerialBoot/srecord.c +++ /dev/null @@ -1,448 +0,0 @@ -/************************************************************************************//** -* \file srecord.c -* \brief Motorola S-record library header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include /* for strcpy etc. */ -#include /* for toupper() etc. */ -#include "srecord.h" /* S-record library */ - - -/**************************************************************************************** -* Type definitions -****************************************************************************************/ -/** \brief Enumeration for the different S-record line types. */ -typedef enum -{ - LINE_TYPE_S1, /**< 16-bit address line */ - LINE_TYPE_S2, /**< 24-bit address line */ - LINE_TYPE_S3, /**< 32-bit address line */ - LINE_TYPE_UNSUPPORTED /**< unsupported line */ -} tSrecordLineType; - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -static tSrecordLineType SrecordGetLineType(const sb_char *line); -static sb_uint8 SrecordVerifyChecksum(const sb_char *line); -static sb_uint8 SrecordHexStringToByte(const sb_char *hexstring); -static sb_uint8 SrecordReadLine(sb_file srecordHandle, sb_char *line); - - -/************************************************************************************//** -** \brief Checks if the specified srecordFile exists and contains s-records. -** \param srecordFile The S-record file with full path if applicable. -** \return SB_TRUE on the S-record is valid, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 SrecordIsValid(const sb_char *srecordFile) -{ - sb_file tempHandle; - sb_char line[SRECORD_MAX_CHARS_PER_LINE]; - - /* attempt to open the file */ - tempHandle = SrecordOpen(srecordFile); - /* is the file available? */ - if (tempHandle == SB_NULL) - { - /* cannot open the file */ - return SB_FALSE; - } - /* all lines should be formatted as S-records. read the first one to check this */ - if (SrecordReadLine(tempHandle, line) == SB_FALSE) - { - /* could not read a line. file must be empty */ - SrecordClose(tempHandle); - return SB_FALSE; - } - /* check if the line starts with the 'S' character, followed by a digit */ - if ( (toupper(line[0]) != 'S') || (isdigit(line[1]) == 0) ) - { - SrecordClose(tempHandle); - return SB_FALSE; - } - - /* still here so it is a valid s-record */ - SrecordClose(tempHandle); - return SB_TRUE; -} /*** end of SrecordIsValid ***/ - - -/************************************************************************************//** -** \brief Opens the S-record file for reading. -** \param srecordFile The S-record file with full path if applicable. -** \return The filehandle if successful, SB_NULL otherwise. -** -****************************************************************************************/ -sb_file SrecordOpen(const sb_char *srecordFile) -{ - /* open the file for reading */ - return fopen(srecordFile, "r"); -} /*** end of SrecordOpen ***/ - - -/************************************************************************************//** -** \brief Parse the S-record file to obtain information about its contents. -** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. -** \param parseResults Pointer to where the parse results should be stored. -** \return none. -** -****************************************************************************************/ -void SrecordParse(sb_file srecordHandle, tSrecordParseResults *parseResults) -{ - tSrecordLineParseResults lineResults; - - /* start at the beginning of the file */ - rewind(srecordHandle); - - /* init data structure */ - parseResults->address_high = 0; - parseResults->address_low = 0xffffffff; - parseResults->data_bytes_total = 0; - - /* loop through all S-records with program data */ - while (SrecordParseNextDataLine(srecordHandle, &lineResults) == SB_TRUE) - { - /* update byte total */ - parseResults->data_bytes_total += lineResults.length; - /* is this a new lowest address? */ - if (lineResults.address < parseResults->address_low) - { - parseResults->address_low = lineResults.address; - } - /* is this a new highest address? */ - if ((lineResults.address + lineResults.length - 1) > parseResults->address_high) - { - parseResults->address_high = (lineResults.address + lineResults.length - 1); - } - } - /* reset to the beginning of the file again */ - rewind(srecordHandle); -} /*** end of SrecordParse ***/ - - -/************************************************************************************//** -** \brief Closes the S-record file. -** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. -** \return none. -** -****************************************************************************************/ -void SrecordClose(sb_file srecordHandle) -{ - /* close the file handle if valid */ - if (srecordHandle != SB_NULL) - { - fclose(srecordHandle); - } -} /*** end of SrecordClose ***/ - - -/************************************************************************************//** -** \brief Reads the next S-record with program data, parses it and returns the -** results. -** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. -** \param parseResults Pointer to where the parse results should be stored. -** \return SB_TRUE is valid parse results were stored. SB_FALSE in case of end-of- -** file. -** -****************************************************************************************/ -sb_uint8 SrecordParseNextDataLine(sb_file srecordHandle, tSrecordLineParseResults *parseResults) -{ - sb_char line[SRECORD_MAX_CHARS_PER_LINE]; - sb_uint8 data_line_found = SB_FALSE; - tSrecordLineType lineType; - sb_uint16 bytes_on_line; - sb_uint16 i; - sb_char *linePtr; - - /* first set the length paramter to 0 */ - parseResults->length = 0; - - while (data_line_found == SB_FALSE) - { - /* read the next line from the file */ - if (SrecordReadLine(srecordHandle, line) == SB_FALSE) - { - /* end-of-file encountered */ - return SB_FALSE; - } - /* we now have a line. check if it is a S-record data line */ - lineType = SrecordGetLineType(line); - if (lineType != LINE_TYPE_UNSUPPORTED) - { - /* check if the checksum on the line is correct */ - if (SrecordVerifyChecksum(line) == SB_TRUE) - { - /* found a valid line that can be parsed. loop will stop */ - data_line_found = SB_TRUE; - break; - } - } - } - - /* still here so we have a valid S-record data line. start parsing */ - linePtr = &line[0]; - /* all good so far, now read out the address and databytes for the line */ - switch (lineType) - { - /* ---------------------------- S1 line type ------------------------------------- */ - case LINE_TYPE_S1: - /* adjust pointer to point to byte count value */ - linePtr += 2; - /* read out the number of byte values that follow on the line */ - bytes_on_line = SrecordHexStringToByte(linePtr); - /* read out the 16-bit address */ - linePtr += 2; - parseResults->address = SrecordHexStringToByte(linePtr) << 8; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr); - /* adjust pointer to point to the first data byte after the address */ - linePtr += 2; - /* determine how many data bytes are on the line */ - parseResults->length = bytes_on_line - 3; /* -2 bytes address, -1 byte checksum */ - /* read and store data bytes if requested */ - for (i=0; ilength; i++) - { - parseResults->data[i] = SrecordHexStringToByte(linePtr); - linePtr += 2; - } - break; - - /* ---------------------------- S2 line type ------------------------------------- */ - case LINE_TYPE_S2: - /* adjust pointer to point to byte count value */ - linePtr += 2; - /* read out the number of byte values that follow on the line */ - bytes_on_line = SrecordHexStringToByte(linePtr); - /* read out the 32-bit address */ - linePtr += 2; - parseResults->address = SrecordHexStringToByte(linePtr) << 16; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr) << 8; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr); - /* adjust pointer to point to the first data byte after the address */ - linePtr += 2; - /* determine how many data bytes are on the line */ - parseResults->length = bytes_on_line - 4; /* -3 bytes address, -1 byte checksum */ - /* read and store data bytes if requested */ - for (i=0; ilength; i++) - { - parseResults->data[i] = SrecordHexStringToByte(linePtr); - linePtr += 2; - } - break; - - /* ---------------------------- S3 line type ------------------------------------- */ - case LINE_TYPE_S3: - /* adjust pointer to point to byte count value */ - linePtr += 2; - /* read out the number of byte values that follow on the line */ - bytes_on_line = SrecordHexStringToByte(linePtr); - /* read out the 32-bit address */ - linePtr += 2; - parseResults->address = SrecordHexStringToByte(linePtr) << 24; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr) << 16; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr) << 8; - linePtr += 2; - parseResults->address += SrecordHexStringToByte(linePtr); - /* adjust pointer to point to the first data byte after the address */ - linePtr += 2; - /* determine how many data bytes are on the line */ - parseResults->length = bytes_on_line - 5; /* -4 bytes address, -1 byte checksum */ - /* read and store data bytes if requested */ - for (i=0; ilength; i++) - { - parseResults->data[i] = SrecordHexStringToByte(linePtr); - linePtr += 2; - } - break; - - default: - /* will not happen */ - break; - } - - /* parsing all done */ - return SB_TRUE; -} /*** end of SrecordParseNextDataLine ***/ - - -/************************************************************************************//** -** \brief Inspects a line from a Motorola S-Record file to determine its type. -** \param line A line from the S-Record. -** \return the S-Record line type. -** -****************************************************************************************/ -static tSrecordLineType SrecordGetLineType(const sb_char *line) -{ - /* check if the line starts with the 'S' character, followed by a digit */ - if ( (toupper(line[0]) != 'S') || (isdigit(line[1]) == 0) ) - { - /* not a valid S-Record line type */ - return LINE_TYPE_UNSUPPORTED; - } - /* determine the line type */ - if (line[1] == '1') - { - return LINE_TYPE_S1; - } - if (line[1] == '2') - { - return LINE_TYPE_S2; - } - if (line[1] == '3') - { - return LINE_TYPE_S3; - } - /* still here so not a supported line type found */ - return LINE_TYPE_UNSUPPORTED; -} /*** end of SrecordGetLineType ***/ - - -/************************************************************************************//** -** \brief Inspects an S1, S2 or S3 line from a Motorola S-Record file to -** determine if the checksum at the end is corrrect. -** \param line An S1, S2 or S3 line from the S-Record. -** \return SB_TRUE if the checksum is correct, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 SrecordVerifyChecksum(const sb_char *line) -{ - sb_uint16 bytes_on_line; - sb_uint8 checksum = 0; - - /* adjust pointer to point to byte count value */ - line += 2; - /* read out the number of byte values that follow on the line */ - bytes_on_line = SrecordHexStringToByte(line); - /* byte count is part of checksum */ - checksum += bytes_on_line; - /* adjust pointer to the first byte of the address */ - line += 2; - /* add byte values of address and data, but not the final checksum */ - do - { - /* add the next byte value to the checksum */ - checksum += SrecordHexStringToByte(line); - /* update counter */ - bytes_on_line--; - /* point to next hex string in the line */ - line += 2; - } - while (bytes_on_line > 1); - /* the checksum is calculated by summing up the values of the byte count, address and - * databytes and then taking the 1-complement of the sum's least signigicant byte */ - checksum = ~checksum; - /* finally verify the calculated checksum with the one at the end of the line */ - if (checksum != SrecordHexStringToByte(line)) - { - /* checksum incorrect */ - return SB_FALSE; - } - /* still here so the checksum was correct */ - return SB_TRUE; -} /*** end of SrecordVerifyChecksum ***/ - - -/************************************************************************************//** -** \brief Helper function to convert a sequence of 2 characters that represent -** a hexadecimal value to the actual byte value. -** Example: SrecordHexStringToByte("2f") --> returns 47. -** \param hexstring String beginning with 2 characters that represent a hexa- -** decimal value. -** \return The resulting byte value. -** -****************************************************************************************/ -static sb_uint8 SrecordHexStringToByte(const sb_char *hexstring) -{ - sb_uint8 result = 0; - sb_char c; - sb_uint8 counter; - - /* a hexadecimal character is 2 characters long (i.e 0x4F minus the 0x part) */ - for (counter=0; counter < 2; counter++) - { - /* read out the character */ - c = toupper(hexstring[counter]); - /* check that the character is 0..9 or A..F */ - if ( (c < '0') || (c > 'F') || ( (c > '9') && (c < 'A') ) ) - { - /* character not valid */ - return 0; - } - /* convert character to 4-bit value (check ASCII table for more info) */ - c -= '0'; - if (c > 9) - { - c -= 7; - } - /* add it to the result */ - result = (result << 4) + c; - } - /* return the results */ - return result; -} /*** end of SrecordHexStringToByte ***/ - - -/************************************************************************************//** -** \brief Reads the next line from the S-record file handle. -** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. -** \param line Destination buffer for the line characters. Should be of size -** SRECORD_MAX_CHARS_PER_LINE. -** \return SB_TRUE if successful, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 SrecordReadLine(sb_file srecordHandle, sb_char *line) -{ - /* init the line as an empty line */ - line[0] = '\0'; - - /* loop as long as we find a non-empty line or end-of-file */ - while (line[0] == '\0') - { - if (fgets(line, SRECORD_MAX_CHARS_PER_LINE, srecordHandle) == SB_NULL) - { - /* no more lines available */ - return SB_FALSE; - } - /* replace the line termination with a string termination */ - line[strcspn(line, "\n")] = '\0'; - } - /* still here so not EOF and not and empty line, so success */ - return SB_TRUE; -} /*** end of SrecordReadLine ***/ - - -/*********************************** end of srecord.c **********************************/ diff --git a/Host/Source/SerialBoot/srecparser.c b/Host/Source/SerialBoot/srecparser.c new file mode 100644 index 00000000..d0e089cb --- /dev/null +++ b/Host/Source/SerialBoot/srecparser.c @@ -0,0 +1,751 @@ +/************************************************************************************//** +* \file srecparser.c +* \brief S-record parser source file. +* \ingroup SerialBoot +* \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 NULL declaration */ +#include /* for standard I/O library */ +#include /* for standard library */ +#include /* for string library */ +#include /* for character testing */ +#include /* for assertions */ +#include "srecparser.h" /* S-record parser */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Maximum number of characters that can be on a line in the firmware file. */ +#define SRECORD_MAX_CHARS_PER_LINE (512) + +/** \brief Maximum number of data bytes that can be on a line in the firmware file + * (S-record). + */ +#define SRECORD_MAX_DATA_BYTES_PER_LINE (SRECORD_MAX_CHARS_PER_LINE/2) + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +/** \brief Layout of a firmware segment node in the linked list. */ +typedef struct t_segment_node +{ + /** \brief The firmware segment stored in this node. */ + tFirmwareSegment segment; + /** \brief Pointer to the next node, or NULL if it is the last one. */ + struct t_segment_node *next; +} tSegmentNode; + +/** \brief Enumeration for the different S-record line types. */ +typedef enum +{ + LINE_TYPE_S1, /**< 16-bit address line */ + LINE_TYPE_S2, /**< 24-bit address line */ + LINE_TYPE_S3, /**< 32-bit address line */ + LINE_TYPE_UNSUPPORTED /**< unsupported line */ +} tSrecordLineType; + +/** \brief Structure type for grouping the parsing results of an S-record line. */ +typedef struct +{ + uint8_t data[SRECORD_MAX_DATA_BYTES_PER_LINE]; /**< array for S1,S2 or S3 data bytes */ + uint32_t address; /**< address on S1,S2 or S3 line */ + uint16_t length; /**< number of bytes written to array */ +} tSrecordLineParseResults; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +static void SRecParserInit(void); +static void SRecParserDeinit(void); +static bool SRecParserLoadFromFile(char *firmwareFile); +static uint32_t SRecParserGetSegmentCount(void); +static const tFirmwareSegment *SRecParserGetSegment(uint32_t segmentIdx); +static void SRecParserSegmentListInit(void); +static void SRecParserSegmentListDeinit(void); +static tSegmentNode *SRecParserSegmentListCreateNode(void); +static uint32_t SRecParserSegmentListGetNodeCount(void); +static tSegmentNode *SRecParserSegmentListGetNode(uint32_t nodeIdx); +/* S-record utility functions */ +static bool SrecordParseNextDataLine(FILE* srecordHandle, tSrecordLineParseResults *parseResults); +static tSrecordLineType SrecordGetLineType(const char *line); +static bool SrecordVerifyChecksum(const char *line); +static uint8_t SrecordHexStringToByte(const char *hexstring); +static bool SrecordReadLine(FILE *srecordHandle, char *line); + + + +/**************************************************************************************** +* Local constant declarations +****************************************************************************************/ +/** \brief XCP transport structure filled with CAN specifics. */ +static const tFirmwareParser srecParser = +{ + SRecParserInit, + SRecParserDeinit, + SRecParserLoadFromFile, + SRecParserGetSegmentCount, + SRecParserGetSegment +}; + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Linked list with firmware segments. */ +static tSegmentNode *segmentList; + + +/***********************************************************************************//** +** \brief Obtains a pointer to the parser structure, so that it can be linked to the +** firmware loader module. +** \return Pointer to firmware parser structure. +** +****************************************************************************************/ +tFirmwareParser const * const SRecParserGetParser(void) +{ + return &srecParser; +} /*** end of SRecParserGetParser ***/ + + +/************************************************************************************//** +** \brief Initializes the parser. +** \return None. +** +****************************************************************************************/ +static void SRecParserInit(void) +{ + /* initialize the segment list */ + SRecParserSegmentListInit(); +} /*** end of SRecParserInit ***/ + + +/************************************************************************************//** +** \brief Uninitializes the parser. +** \return None. +** +****************************************************************************************/ +static void SRecParserDeinit(void) +{ + /* uninitialize the segment list */ + SRecParserSegmentListDeinit(); +} /*** end of SRecParserDeinit ***/ + + +/************************************************************************************//** +** \brief Parses the data in the specified firmware file into firmware segments that +** are stored internally in this module. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +static bool SRecParserLoadFromFile(char *firmwareFile) +{ + FILE *fp; + char line[SRECORD_MAX_CHARS_PER_LINE]; + tSrecordLineParseResults lineResults; + tSegmentNode *node; + uint32_t nodeIdx; + bool matchFound; + uint32_t byteIdx; + uint32_t byteOffset; + + /* verify parameters */ + assert(firmwareFile != NULL); + + /* open the file for reading */ + fp = fopen(firmwareFile, "r"); + if (fp == NULL) + { + /* could not open the file */ + return false; + } + /* start at the beginning of the file */ + rewind(fp); + + /* -------------------------- file type validation --------------------------------- */ + /* validate S-record file. all lines should be formatted as S-records. read the first + * one to check this. + */ + if (!SrecordReadLine(fp, line)) + { + /* could not read a line. file must be empty */ + fclose(fp); + return false; + } + /* check if the line starts with the 'S' character, followed by a digit */ + if ( (toupper(line[0]) != 'S') || (isdigit(line[1]) == 0) ) + { + fclose(fp); + return false; + } + + /* -------------------------- extract segment info --------------------------------- */ + /* start at the beginning of the file */ + rewind(fp); + + /* loop through all S-records with program data to obtain segment info */ + while (SrecordParseNextDataLine(fp, &lineResults)) + { + /* reset flag that indicates that the line data was matched to an existing segment */ + matchFound = false; + /* loop through all segment nodes */ + for (nodeIdx=0; nodeIdx < SRecParserSegmentListGetNodeCount(); nodeIdx++) + { + /* get node access */ + node = SRecParserSegmentListGetNode(nodeIdx); + + /* does the line data fit at the start of this node's segment? */ + if ((lineResults.address + lineResults.length) == node->segment.base) + { + /* update the node's segment */ + node->segment.base -= lineResults.length; + node->segment.length += lineResults.length; + /* match found so continue with the next line */ + matchFound = true; + break; + } + /* does the line data fit at the end of this node's segment? */ + else if (lineResults.address == (node->segment.base + node->segment.length)) + { + /* update the node's segment */ + node->segment.length += lineResults.length; + /* match found so continue with the next line */ + matchFound = true; + break; + } + } + /* check if the line data was matched and added to an existing segment */ + if (!matchFound) + { + /* create a new segment */ + node = SRecParserSegmentListCreateNode(); + node->segment.base = lineResults.address; + node->segment.length = lineResults.length; + } + } + + /* -------------------------- allocate data memory --------------------------------- */ + /* loop through all segment nodes */ + for (nodeIdx=0; nodeIdx < SRecParserSegmentListGetNodeCount(); nodeIdx++) + { + /* get node access */ + node = SRecParserSegmentListGetNode(nodeIdx); + /* sanity check */ + assert(node->segment.length > 0); + /* allocate data */ + node->segment.data = malloc(node->segment.length); + /* check results */ + if (node->segment.data == NULL) + { + fclose(fp); + return false; + } + } + + /* -------------------------- extract segment data --------------------------------- */ + /* start at the beginning of the file */ + rewind(fp); + + /* loop through all S-records with program data to obtain segment info */ + while (SrecordParseNextDataLine(fp, &lineResults)) + { + /* loop through all segment nodes */ + for (nodeIdx=0; nodeIdx < SRecParserSegmentListGetNodeCount(); nodeIdx++) + { + /* get node access */ + node = SRecParserSegmentListGetNode(nodeIdx); + /* does the line data belong in this segment? */ + if ( (lineResults.address >= node->segment.base) && \ + ((lineResults.address+lineResults.length) <= (node->segment.base+node->segment.length)) ) + { + /* determine offset of the line data into the segment */ + byteOffset = lineResults.address - node->segment.base; + /* store bytes in this segment */ + for (byteIdx=0; byteIdxsegment.data[byteOffset + byteIdx] = lineResults.data[byteIdx]; + } + /* line data stored, so continue with the next S-record */ + break; + } + } + } + + /* close the file */ + fclose(fp); + /* s-record successfully loaded and parsed */ + return true; +} /*** end of SRecParserLoadFromFile ***/ + + +/************************************************************************************//** +** \brief Returns the number of firmware segments that were loaded by this parser. +** \return Number of firmware segments. +** +****************************************************************************************/ +static uint32_t SRecParserGetSegmentCount(void) +{ + return SRecParserSegmentListGetNodeCount(); +} /*** end of SRecParserGetSegmentCount ***/ + + +/************************************************************************************//** +** \brief Obtains a pointer to the firmware segment at the specified index. +** \return Pointer to firmware segment. +** +****************************************************************************************/ +static const tFirmwareSegment *SRecParserGetSegment(uint32_t segmentIdx) +{ + /* validate the parameter */ + assert(segmentIdx < SRecParserSegmentListGetNodeCount()); + + return &(SRecParserSegmentListGetNode(segmentIdx)->segment); +} /*** end of SRecParserGetSegment ***/ + + +/************************************************************************************//** +** \brief Initializes the linked list with firmware segments. +** \return None. +** +****************************************************************************************/ +static void SRecParserSegmentListInit(void) +{ + segmentList = NULL; +} /*** end of SRecParserSegmentListInit ***/ + + +/************************************************************************************//** +** \brief Uninitializes the linked list with firmware segments. +** \return None. +** +****************************************************************************************/ +static void SRecParserSegmentListDeinit(void) +{ + tSegmentNode *currentNode; + tSegmentNode *nodeToFree; + + /* free all nodes */ + if (segmentList != NULL) + { + currentNode = segmentList; + do + { + /* store pointer to the node that should be released for later usage */ + nodeToFree = currentNode; + /* move to the next node before freeing it */ + currentNode = currentNode->next; + /* sanity check */ + assert(nodeToFree != NULL); + /* free the node */ + if (nodeToFree->segment.data != NULL) + { + free(nodeToFree->segment.data); + } + free(nodeToFree); + } + while(currentNode != NULL); + } +} /*** end of SRecParserSegmentListDeinit ***/ + + +/************************************************************************************//** +** \brief Creates a new node in the linked list with firmware segments. +** \return Pointer to the new node. +** +****************************************************************************************/ +static tSegmentNode *SRecParserSegmentListCreateNode(void) +{ + tSegmentNode *newNode; + tSegmentNode *currentNode; + + /* allocate memory for the node */ + newNode = malloc(sizeof(tSegmentNode)); + assert(newNode != NULL); + + /* initialize the node */ + newNode->next = NULL; + newNode->segment.base = 0x00000000; + newNode->segment.length = 0; + newNode->segment.data = NULL; + + /* add the first node if the list is empty */ + if (segmentList == NULL) + { + segmentList = newNode; + } + /* add the node to the end of the list */ + else + { + /* find last entry in to list */ + currentNode = segmentList; + while(currentNode->next != NULL) + { + currentNode = currentNode->next; + } + /* add the now */ + currentNode->next = newNode; + } + + return newNode; +} /*** end of SRecParserSegmentListCreateNode ***/ + + +/************************************************************************************//** +** \brief Obtains the number of nodes in the linked list with firmware segments. +** \return Number of nodes. +** +****************************************************************************************/ +static uint32_t SRecParserSegmentListGetNodeCount(void) +{ + tSegmentNode *currentNode; + uint32_t nodeCount = 0; + + /* iterate over all nodes to determine to total count */ + if (segmentList != NULL) + { + currentNode = segmentList; + do + { + nodeCount++; + currentNode = currentNode->next; + } + while(currentNode != NULL); + } + + return nodeCount; +} /*** end of SRecParserSegmentListGetNodeCount ***/ + + +/************************************************************************************//** +** \brief Obtains the node at the specified index from the linked list with firmware +** segments. +** \return Pointer to the node. +** +****************************************************************************************/ +static tSegmentNode *SRecParserSegmentListGetNode(uint32_t nodeIdx) +{ + tSegmentNode *currentNode = NULL; + uint32_t currentIdx = 0; + + /* validate the parameter */ + assert(nodeIdx < SRecParserSegmentListGetNodeCount()); + + /* iterate until the specified index is found */ + currentNode = segmentList; + for (currentIdx=0; currentIdxnext; + } + + return currentNode; +} /*** end of SRecParserSegmentListGetNode ***/ + + +/************************************************************************************//** +** \brief Reads the next S-record with program data, parses it and returns the +** results. +** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. +** \param parseResults Pointer to where the parse results should be stored. +** \return SB_TRUE is valid parse results were stored. SB_FALSE in case of end-of- +** file. +** +****************************************************************************************/ +static bool SrecordParseNextDataLine(FILE* srecordHandle, tSrecordLineParseResults *parseResults) +{ + char line[SRECORD_MAX_CHARS_PER_LINE]; + bool data_line_found = false; + tSrecordLineType lineType; + uint16_t bytes_on_line; + uint16_t i; + char *linePtr; + + /* first set the length paramter to 0 */ + parseResults->length = 0; + + while (!data_line_found) + { + /* read the next line from the file */ + if (!SrecordReadLine(srecordHandle, line)) + { + /* end-of-file encountered */ + return false; + } + /* we now have a line. check if it is a S-record data line */ + lineType = SrecordGetLineType(line); + if (lineType != LINE_TYPE_UNSUPPORTED) + { + /* check if the checksum on the line is correct */ + if (SrecordVerifyChecksum(line)) + { + /* found a valid line that can be parsed. loop will stop */ + data_line_found = true; + break; + } + } + } + + /* still here so we have a valid S-record data line. start parsing */ + linePtr = &line[0]; + /* all good so far, now read out the address and databytes for the line */ + switch (lineType) + { + /* ---------------------------- S1 line type ------------------------------------- */ + case LINE_TYPE_S1: + /* adjust pointer to point to byte count value */ + linePtr += 2; + /* read out the number of byte values that follow on the line */ + bytes_on_line = SrecordHexStringToByte(linePtr); + /* read out the 16-bit address */ + linePtr += 2; + parseResults->address = SrecordHexStringToByte(linePtr) << 8; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr); + /* adjust pointer to point to the first data byte after the address */ + linePtr += 2; + /* determine how many data bytes are on the line */ + parseResults->length = bytes_on_line - 3; /* -2 bytes address, -1 byte checksum */ + /* read and store data bytes if requested */ + for (i=0; ilength; i++) + { + parseResults->data[i] = SrecordHexStringToByte(linePtr); + linePtr += 2; + } + break; + + /* ---------------------------- S2 line type ------------------------------------- */ + case LINE_TYPE_S2: + /* adjust pointer to point to byte count value */ + linePtr += 2; + /* read out the number of byte values that follow on the line */ + bytes_on_line = SrecordHexStringToByte(linePtr); + /* read out the 32-bit address */ + linePtr += 2; + parseResults->address = SrecordHexStringToByte(linePtr) << 16; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr) << 8; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr); + /* adjust pointer to point to the first data byte after the address */ + linePtr += 2; + /* determine how many data bytes are on the line */ + parseResults->length = bytes_on_line - 4; /* -3 bytes address, -1 byte checksum */ + /* read and store data bytes if requested */ + for (i=0; ilength; i++) + { + parseResults->data[i] = SrecordHexStringToByte(linePtr); + linePtr += 2; + } + break; + + /* ---------------------------- S3 line type ------------------------------------- */ + case LINE_TYPE_S3: + /* adjust pointer to point to byte count value */ + linePtr += 2; + /* read out the number of byte values that follow on the line */ + bytes_on_line = SrecordHexStringToByte(linePtr); + /* read out the 32-bit address */ + linePtr += 2; + parseResults->address = SrecordHexStringToByte(linePtr) << 24; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr) << 16; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr) << 8; + linePtr += 2; + parseResults->address += SrecordHexStringToByte(linePtr); + /* adjust pointer to point to the first data byte after the address */ + linePtr += 2; + /* determine how many data bytes are on the line */ + parseResults->length = bytes_on_line - 5; /* -4 bytes address, -1 byte checksum */ + /* read and store data bytes if requested */ + for (i=0; ilength; i++) + { + parseResults->data[i] = SrecordHexStringToByte(linePtr); + linePtr += 2; + } + break; + + default: + /* will not happen */ + break; + } + + /* parsing all done */ + return true; +} /*** end of SrecordParseNextDataLine ***/ + + +/************************************************************************************//** +** \brief Inspects a line from a Motorola S-Record file to determine its type. +** \param line A line from the S-Record. +** \return the S-Record line type. +** +****************************************************************************************/ +static tSrecordLineType SrecordGetLineType(const char *line) +{ + /* check if the line starts with the 'S' character, followed by a digit */ + if ( (toupper(line[0]) != 'S') || (isdigit(line[1]) == 0) ) + { + /* not a valid S-Record line type */ + return LINE_TYPE_UNSUPPORTED; + } + /* determine the line type */ + if (line[1] == '1') + { + return LINE_TYPE_S1; + } + if (line[1] == '2') + { + return LINE_TYPE_S2; + } + if (line[1] == '3') + { + return LINE_TYPE_S3; + } + /* still here so not a supported line type found */ + return LINE_TYPE_UNSUPPORTED; +} /*** end of SrecordGetLineType ***/ + + +/************************************************************************************//** +** \brief Inspects an S1, S2 or S3 line from a Motorola S-Record file to +** determine if the checksum at the end is corrrect. +** \param line An S1, S2 or S3 line from the S-Record. +** \return SB_TRUE if the checksum is correct, SB_FALSE otherwise. +** +****************************************************************************************/ +static bool SrecordVerifyChecksum(const char *line) +{ + uint16_t bytes_on_line; + uint8_t checksum = 0; + + /* adjust pointer to point to byte count value */ + line += 2; + /* read out the number of byte values that follow on the line */ + bytes_on_line = SrecordHexStringToByte(line); + /* byte count is part of checksum */ + checksum += bytes_on_line; + /* adjust pointer to the first byte of the address */ + line += 2; + /* add byte values of address and data, but not the final checksum */ + do + { + /* add the next byte value to the checksum */ + checksum += SrecordHexStringToByte(line); + /* update counter */ + bytes_on_line--; + /* point to next hex string in the line */ + line += 2; + } + while (bytes_on_line > 1); + /* the checksum is calculated by summing up the values of the byte count, address and + * databytes and then taking the 1-complement of the sum's least signigicant byte */ + checksum = ~checksum; + /* finally verify the calculated checksum with the one at the end of the line */ + if (checksum != SrecordHexStringToByte(line)) + { + /* checksum incorrect */ + return false; + } + /* still here so the checksum was correct */ + return true; +} /*** end of SrecordVerifyChecksum ***/ + + +/************************************************************************************//** +** \brief Helper function to convert a sequence of 2 characters that represent +** a hexadecimal value to the actual byte value. +** Example: SrecordHexStringToByte("2f") --> returns 47. +** \param hexstring String beginning with 2 characters that represent a hexa- +** decimal value. +** \return The resulting byte value. +** +****************************************************************************************/ +static uint8_t SrecordHexStringToByte(const char *hexstring) +{ + uint8_t result = 0; + char c; + uint8_t counter; + + /* a hexadecimal character is 2 characters long (i.e 0x4F minus the 0x part) */ + for (counter=0; counter < 2; counter++) + { + /* read out the character */ + c = toupper(hexstring[counter]); + /* check that the character is 0..9 or A..F */ + if ( (c < '0') || (c > 'F') || ( (c > '9') && (c < 'A') ) ) + { + /* character not valid */ + return 0; + } + /* convert character to 4-bit value (check ASCII table for more info) */ + c -= '0'; + if (c > 9) + { + c -= 7; + } + /* add it to the result */ + result = (result << 4) + c; + } + /* return the results */ + return result; +} /*** end of SrecordHexStringToByte ***/ + + +/************************************************************************************//** +** \brief Reads the next line from the S-record file handle. +** \param srecordHandle The S-record file handle. It is returned by SrecordOpen. +** \param line Destination buffer for the line characters. Should be of size +** SRECORD_MAX_CHARS_PER_LINE. +** \return SB_TRUE if successful, SB_FALSE otherwise. +** +****************************************************************************************/ +static bool SrecordReadLine(FILE *srecordHandle, char *line) +{ + /* init the line as an empty line */ + line[0] = '\0'; + + /* loop as long as we find a non-empty line or end-of-file */ + while (line[0] == '\0') + { + if (fgets(line, SRECORD_MAX_CHARS_PER_LINE, srecordHandle) == NULL) + { + /* no more lines available */ + return false; + } + /* replace the line termination with a string termination */ + line[strcspn(line, "\n")] = '\0'; + } + /* still here so not EOF and not and empty line, so success */ + return true; +} /*** end of SrecordReadLine ***/ + + +/*********************************** end of srecparser.c *******************************/ + diff --git a/Host/Source/SerialBoot/port/xcptransport.h b/Host/Source/SerialBoot/srecparser.h similarity index 69% rename from Host/Source/SerialBoot/port/xcptransport.h rename to Host/Source/SerialBoot/srecparser.h index 52e5186a..b38e0a2f 100644 --- a/Host/Source/SerialBoot/port/xcptransport.h +++ b/Host/Source/SerialBoot/srecparser.h @@ -1,51 +1,52 @@ -/************************************************************************************//** -* \file port\xcptransport.h -* \brief XCP transport layer interface header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 -****************************************************************************************/ -#ifndef XCPTRANSPORT_H -#define XCPTRANSPORT_H - -/**************************************************************************************** -* Type definitions -****************************************************************************************/ -typedef struct -{ - sb_uint8 data[XCP_MASTER_RX_MAX_DATA]; - sb_uint8 len; -} tXcpTransportResponsePacket; - - -/**************************************************************************************** -* EFunction prototypes -****************************************************************************************/ -sb_uint8 XcpTransportInit(sb_char *device, sb_uint32 baudrate); -sb_uint8 XcpTransportSendPacket(sb_uint8 *data, sb_uint8 len, sb_uint16 timeOutMs); -tXcpTransportResponsePacket *XcpTransportReadResponsePacket(void); -void XcpTransportClose(void); - - -#endif /* XCPTRANSPORT_H */ -/*********************************** end of xcptransport.h *****************************/ +/************************************************************************************//** +* \file srecparser.h +* \brief S-record parser header file. +* \ingroup SerialBoot +* \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 +****************************************************************************************/ +#ifndef SRECPARSER_H +#define SRECPARSER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "firmware.h" /* firmware module */ + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +tFirmwareParser const * const SRecParserGetParser(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SRECPARSER_H */ +/********************************* end of srecparser.h *********************************/ + diff --git a/Host/Source/SerialBoot/port/timeutil.h b/Host/Source/SerialBoot/timeutil.h similarity index 76% rename from Host/Source/SerialBoot/port/timeutil.h rename to Host/Source/SerialBoot/timeutil.h index bb40a8db..911b0d17 100644 --- a/Host/Source/SerialBoot/port/timeutil.h +++ b/Host/Source/SerialBoot/timeutil.h @@ -1,39 +1,52 @@ -/************************************************************************************//** -* \file port\timeutil.h -* \brief Time utility header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 -****************************************************************************************/ -#ifndef TIMEUTIL_H -#define TIMEUTIL_H - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -sb_uint32 TimeUtilGetSystemTimeMs(void); -void TimeUtilDelayMs(sb_uint16 delay); - - -#endif /* TIMEUTIL_H */ -/*********************************** end of timeutil.h *********************************/ +/************************************************************************************//** +* \file timeutil.h +* \brief Time utility header file. +* \ingroup SerialBoot +* \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 +****************************************************************************************/ +#ifndef TIMEUTIL_H +#define TIMEUTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include /* for standard integer types */ + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +uint32_t TimeUtilGetSystemTimeMs(void); +void TimeUtilDelayMs(uint16_t delay); + +#ifdef __cplusplus +} +#endif + +#endif /* TIMEUTIL_H */ +/*********************************** end of timeutil.h *********************************/ diff --git a/Host/Source/SerialBoot/xcploader.c b/Host/Source/SerialBoot/xcploader.c new file mode 100644 index 00000000..40f63b86 --- /dev/null +++ b/Host/Source/SerialBoot/xcploader.c @@ -0,0 +1,755 @@ +/************************************************************************************//** +* \file xcploader.c +* \brief XCP Loader module source file. +* \ingroup SerialBoot +* \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 NULL declaration */ +#include /* for assertions */ +#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 (0xFF) /**< XCP connect command code. */ +#define XCPLOADER_CMD_DISCONNECT (0xFE) /**< XCP disconnect command code. */ +#define XCPLOADER_CMD_SET_MTA (0xF6) /**< XCP set mta command code. */ +#define XCPLOADER_CMD_UPLOAD (0xF5) /**< XCP upload command code. */ +#define XCPLOADER_CMD_PROGRAM_START (0xD2) /**< XCP program start command code. */ +#define XCPLOADER_CMD_PROGRAM_CLEAR (0xD1) /**< XCP program clear command code. */ +#define XCPLOADER_CMD_PROGRAM (0xD0) /**< XCP program command code. */ +#define XCPLOADER_CMD_PROGRAM_RESET (0xCF) /**< XCP program reset command code. */ +#define XCPLOADER_CMD_PROGRAM_MAX (0xC9) /**< XCP program max command code. */ + +/* XCP response packet IDs as defined by the protocol. */ +#define XCPLOADER_CMD_PID_RES (0xFF) /**< positive response */ + +/** \brief Maximum timeout for the XCP connect command. */ +#define XCPLOADER_CONNECT_TIMEOUT_MS (20) + +/** \brief Number of retries to connect to the XCP slave. */ +#define XCPLOADER_CONNECT_RETRIES (5) + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +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 *data); +static bool XcpLoaderSendCmdProgramMax(uint8_t *data); +static bool XcpLoaderSendCmdProgramClear(uint32_t length); +static void XcpLoaderSetOrderedLong(uint32_t value, uint8_t *data); + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Pointer to the XCP transport layer that is linked. */ +static tXcpTransport const * transportPtr = NULL; + +/** \brief The settings that should be used by the XCP loader. */ +static tXcpSettings 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 Initializes the loader module. +** \param settings Pointer to settings structure. +** \param transport Pointer to the transport layer to link. +** \param tpsettings Pointer to transport layer settings structure. +** \return None. +** +****************************************************************************************/ +void XcpLoaderInit(tXcpSettings *settings, tXcpTransport const * const transport, void *tpsettings) +{ + /* verify parameters */ + assert(transport != NULL); + assert(tpsettings != NULL); + assert(settings != NULL); + + /* shallow copy the XCP settings for later usage */ + xcpSettings = *settings; + /* link the XCP transport layer */ + transportPtr = transport; + /* initialize the transport layer */ + transportPtr->Init(tpsettings); + /* init locals */ + xcpConnected = false; + xcpSlaveIsIntel = false; + xcpMaxCto = 0; + xcpMaxProgCto = 0; + xcpMaxDto = 0; +} /*** end of XcpLoaderInit ***/ + + +/************************************************************************************//** +** \brief Uninitializes the loader module. +** \return None. +** +****************************************************************************************/ +void XcpLoaderDeinit(void) +{ + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + + /* disconnect */ + XcpLoaderDisconnect(); + /* uninitialize the transport layer */ + transportPtr->Deinit(); + /* unlink the transport layer */ + transportPtr = NULL; +} /*** end of XcpLoaderDeinit ***/ + + +/************************************************************************************//** +** \brief Connect to the XCP slave. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderConnect(void) +{ + uint8_t retryCnt; + + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + + /* make sure that we are disconnected before connecting */ + XcpLoaderDisconnect(); + + /* connect the transport layer */ + if (!transportPtr->Connect()) + { + return false; + } + + /* try to connect with a finite amount of retries */ + for (retryCnt=0; retryCntDisconnect(); + return false; +} /*** end of XcpLoaderConnect ***/ + + +/***********************************************************************************//** +** \brief Disconnect from the XCP slave. +** \return None. +** +****************************************************************************************/ +void XcpLoaderDisconnect(void) +{ + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + + /* only disconnect if actually connected */ + if (xcpConnected) + { + /* send reset command instead of the disconnect. this causes the user program on the + * slave to automatically start again if present. + */ + XcpLoaderSendCmdProgramReset(); + /* disconnect the transport layer */ + transportPtr->Disconnect(); + /* reset connection status */ + xcpConnected = false; + } +} /*** end of XcpLoaderDisconnect ***/ + + +/************************************************************************************//** +** \brief Puts a connected slave in programming session. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderStartProgrammingSession(void) +{ + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + + /* place the slave in programming mode */ + return XcpLoaderSendCmdProgramStart(); +} /*** end of XcpLoaderStartProgrammingSession ***/ + + +/************************************************************************************//** +** \brief Stops the programming session by sending a program command with size 0 and +** then resetting the slave. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderStopProgrammingSession(void) +{ + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + + /* stop programming by sending the program command with size 0 */ + return XcpLoaderSendCmdProgram(0, NULL); +} /*** end of XcpLoaderStopProgrammingSession ***/ + + +/************************************************************************************//** +** \brief Erases non volatile memory on the slave. +** \param addr Base memory address for the erase operation. +** \param len Number of bytes to erase. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderClearMemory(uint32_t addr, uint32_t len) +{ + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + /* verify parameters */ + assert(len > 0); + + /* first set the MTA pointer */ + if (!XcpLoaderSendCmdSetMta(addr)) + { + return false; + } + /* now perform the erase operation */ + return XcpLoaderSendCmdProgramClear(len); +} /*** end of XcpLoaderClearMemory ***/ + + +/***********************************************************************************//** +** \brief Reads data from the slave's memory. +** \param addr Base memory address for the read operation +** \param len Number of bytes to read. +** \param data Destination buffer for storing the read data bytes. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderReadData(uint32_t addr, uint32_t len, uint8_t *data) +{ + uint8_t currentReadCnt; + uint32_t bufferOffset = 0; + + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + /* verify parameters */ + assert(data != NULL); + assert(len > 0); + + /* first set the MTA pointer */ + if (!XcpLoaderSendCmdSetMta(addr)) + { + return false; + } + /* perform segmented upload of the data */ + while (len > 0) + { + /* set the current read length to make optimal use of the available packet data. */ + currentReadCnt = len % (xcpMaxDto - 1); + if (currentReadCnt == 0) + { + currentReadCnt = (xcpMaxDto - 1); + } + /* upload some data */ + if (!XcpLoaderSendCmdUpload(&data[bufferOffset], currentReadCnt)) + { + return false; + } + /* update loop variables */ + len -= currentReadCnt; + bufferOffset += currentReadCnt; + } + /* still here so all data successfully read from the slave */ + return true; +} /*** end of XcpLoaderReadData ***/ + + +/************************************************************************************//** +** \brief Programs data to the slave's non volatile memory. Note that it must be +** erased first. +** \param addr Base memory address for the program operation +** \param len Number of bytes to program. +** \param data Source buffer with the to be programmed bytes. +** \return True is successful, false otherwise. +** +****************************************************************************************/ +bool XcpLoaderProgramData(uint32_t addr, uint32_t len, uint8_t *data) +{ + uint8_t currentWriteCnt; + uint32_t bufferOffset = 0; + + /* make sure the XCP transport layer is linked */ + assert(transportPtr != NULL); + /* verify parameters */ + assert(data != NULL); + assert(len > 0); + + /* first set the MTA pointer */ + if (!XcpLoaderSendCmdSetMta(addr)) + { + return false; + } + /* perform segmented programming of the data */ + while (len > 0) + { + /* set the current read length to make optimal use of the available packet data. */ + currentWriteCnt = len % (xcpMaxProgCto - 1); + if (currentWriteCnt == 0) + { + currentWriteCnt = (xcpMaxProgCto - 1); + } + /* prepare the packed data for the program command */ + if (currentWriteCnt < (xcpMaxProgCto - 1)) + { + /* program data */ + if (!XcpLoaderSendCmdProgram(currentWriteCnt, &data[bufferOffset])) + { + return false; + } + } + else + { + /* program max data */ + if (!XcpLoaderSendCmdProgramMax(&data[bufferOffset])) + { + return false; + } + } + /* update loop variables */ + len -= currentWriteCnt; + bufferOffset += currentWriteCnt; + } + /* still here so all data successfully programmed */ + return true; +} /*** end of XcpLoaderProgramData ***/ + + +/************************************************************************************//** +** \brief Sends the XCP Connect command. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +static bool XcpLoaderSendCmdConnect(void) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + + /* prepare the command packet */ + cmdPacket.data[0] = XCPLOADER_CMD_CONNECT; + cmdPacket.data[1] = 0; /* normal mode */ + cmdPacket.len = 2; + + /* send the packet */ + if (!transportPtr->SendPacket(&cmdPacket, &resPacket, XCPLOADER_CONNECT_TIMEOUT_MS)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* process response data */ + if ((resPacket.data[2] & 0x01) == 0) + { + /* store slave's byte ordering information */ + xcpSlaveIsIntel = true; + } + /* 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 */ + assert(XCPLOADER_PACKET_SIZE_MAX >= xcpMaxCto); + assert(XCPLOADER_PACKET_SIZE_MAX >= xcpMaxDto); + + /* still here so all went well */ + return true; +} /*** 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) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + + /* 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 (!transportPtr->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT1)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* still here so all went well */ + return true; +} /*** 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) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + uint8_t data_index; + + /* cannot request more data then the max rx data - 1 */ + assert(length < XCPLOADER_PACKET_SIZE_MAX); + assert(data != NULL); + + /* prepare the command packet */ + cmdPacket.data[0] = XCPLOADER_CMD_UPLOAD; + cmdPacket.data[1] = length; + cmdPacket.len = 2; + + /* send the packet */ + if (!transportPtr->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT1)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* now store the uploaded data */ + for (data_index=0; data_indexSendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT3)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* store max number of bytes the slave allows for master->slave packets during the + * programming session + */ + xcpMaxProgCto = resPacket.data[3]; + + /* still here so all went well */ + return true; +} /*** 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) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + + /* prepare the command packet */ + cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM_RESET; + cmdPacket.len = 1; + + /* send the packet, assume the sending itself is ok and check if a response was + * received. + */ + if (!transportPtr->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT5)) + { + /* probably no response received within the specified timeout, but that is allowed + * for the reset command. + */ + return true; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* still here so all went well */ + return true; +} /*** 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 *data) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + uint8_t cnt; + + /* verify that this number of bytes actually first in this command */ + assert(length <= (xcpMaxProgCto-2) && (xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX)); + if (length > 0) + { + assert(data != NULL); + } + + /* prepare the command packet */ + cmdPacket.data[0] = XCPLOADER_CMD_PROGRAM; + cmdPacket.data[1] = length; + for (cnt=0; cntSendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT5)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* still here so all went well */ + return true; +} /*** 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 *data) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + uint8_t cnt; + + /* verify that this number of bytes actually first in this command */ + assert(xcpMaxProgCto <= XCPLOADER_PACKET_SIZE_MAX); + assert(data != NULL); + + /* 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 (!transportPtr->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT5)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* still here so all went well */ + return true; +} /*** 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) +{ + tXcpPacket cmdPacket; + tXcpPacket resPacket; + + /* prepare 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 (!transportPtr->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT4)) + { + /* could not send packet or receive response within the specified timeout */ + return false; + } + + /* still here so a response was received. check if the reponse was valid */ + if ( (resPacket.len == 0) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* not a valid or positive response */ + return false; + } + + /* still here so all went well */ + return true; +} /*** end of XcpLoaderSendCmdProgramClear ***/ + + +/************************************************************************************//** +** \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. +** \return None. +** +****************************************************************************************/ +static void XcpLoaderSetOrderedLong(uint32_t value, uint8_t *data) +{ + 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 ***/ + + +/*********************************** end of xcploader.c ********************************/ + diff --git a/Host/Source/SerialBoot/xcploader.h b/Host/Source/SerialBoot/xcploader.h new file mode 100644 index 00000000..da586aee --- /dev/null +++ b/Host/Source/SerialBoot/xcploader.h @@ -0,0 +1,108 @@ +/************************************************************************************//** +* \file xcploader.h +* \brief XCP Loader module header file. +* \ingroup SerialBoot +* \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 +****************************************************************************************/ +#ifndef XCPLOADER_H +#define XCPLOADER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include /* for standard integer types */ +#include /* for boolean type */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Total number of bytes in a master<->slave data packet. It should be at least + * equal or larger than that configured on the slave. + */ +#define XCPLOADER_PACKET_SIZE_MAX (255) + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +/** \brief XCP protocol specific settings. */ +typedef struct t_xcp_settings +{ + uint16_t timeoutT1; /**< Command response timeout in milliseconds. */ + uint16_t timeoutT3; /**< Start programming timeout in milliseconds. */ + uint16_t timeoutT4; /**< Erase memory timeout in milliseonds. */ + uint16_t timeoutT5; /**< Program memory and reset timeout in milliseonds. */ + uint16_t timeoutT7; /**< Busy wait timer timeout in milliseonds. */ +} tXcpSettings; + + +/** \brief XCP packet type. */ +typedef struct t_xcp_packet +{ + uint8_t data[XCPLOADER_PACKET_SIZE_MAX]; /**< Packet data. */ + uint8_t len; /**< Packet length. */ +} tXcpPacket; + + +/** \brief XCP transport layer. */ +typedef struct t_xcp_transport +{ + /** \brief Initialization of the XCP transpor layer. */ + void (*Init) (void *settings); + /** \brief Uninitializes the XCP transpor layer. */ + void (*Deinit) (void); + /** \brief Connects the XCP transpor layer. */ + bool (*Connect) (void); + /** \brief Disconnects the XCP transpor layer. */ + void (*Disconnect) (void); + /** \brief Sends an XCP packet and waits for the response to come back. */ + bool (*SendPacket) (tXcpPacket *txPacket, tXcpPacket *rxPacket, uint16_t timeout); +} tXcpTransport; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void XcpLoaderInit(tXcpSettings *settings, tXcpTransport const * const transport, void *tpsettings); +void XcpLoaderDeinit(void); +bool XcpLoaderConnect(void); +void XcpLoaderDisconnect(void); +bool XcpLoaderStartProgrammingSession(void); +bool XcpLoaderStopProgrammingSession(void); +bool XcpLoaderClearMemory(uint32_t addr, uint32_t len); +bool XcpLoaderReadData(uint32_t addr, uint32_t len, uint8_t *data); +bool XcpLoaderProgramData(uint32_t addr, uint32_t len, uint8_t *data); + +#ifdef __cplusplus +} +#endif + +#endif /* XCPLOADER_H */ +/********************************* end of xcploader.h **********************************/ + diff --git a/Host/Source/SerialBoot/xcpmaster.c b/Host/Source/SerialBoot/xcpmaster.c deleted file mode 100644 index 62f1ccd8..00000000 --- a/Host/Source/SerialBoot/xcpmaster.c +++ /dev/null @@ -1,689 +0,0 @@ -/************************************************************************************//** -* \file xcpmaster.c -* \brief XCP Master source file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 /* assertion module */ -#include /* C types */ -#include "xcpmaster.h" /* XCP master protocol module */ - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/* XCP command codes as defined by the protocol currently supported by this module */ -#define XCP_MASTER_CMD_CONNECT (0xFF) -#define XCP_MASTER_CMD_DISCONNECT (0xFE) -#define XCP_MASTER_CMD_SET_MTA (0xF6) -#define XCP_MASTER_CMD_UPLOAD (0xF5) -#define XCP_MASTER_CMD_PROGRAM_START (0xD2) -#define XCP_MASTER_CMD_PROGRAM_CLEAR (0xD1) -#define XCP_MASTER_CMD_PROGRAM (0xD0) -#define XCP_MASTER_CMD_PROGRAM_RESET (0xCF) -#define XCP_MASTER_CMD_PROGRAM_MAX (0xC9) - -/* XCP response packet IDs as defined by the protocol */ -#define XCP_MASTER_CMD_PID_RES (0xFF) /* positive response */ - -/* timeout values */ -#define XCP_MASTER_CONNECT_TIMEOUT_MS (20) -#define XCP_MASTER_TIMEOUT_T1_MS (1000) /* standard command timeout */ -#define XCP_MASTER_TIMEOUT_T2_MS (2000) /* build checksum timeout */ -#define XCP_MASTER_TIMEOUT_T3_MS (2000) /* program start timeout */ -#define XCP_MASTER_TIMEOUT_T4_MS (10000) /* erase timeout */ -#define XCP_MASTER_TIMEOUT_T5_MS (1000) /* write and reset timeout */ -#define XCP_MASTER_TIMEOUT_T6_MS (1000) /* user specific connect connect timeout */ -#define XCP_MASTER_TIMEOUT_T7_MS (2000) /* wait timer timeout */ - -/** \brief Number of retries to connect to the XCP slave. */ -#define XCP_MASTER_CONNECT_RETRIES (5) - - -/**************************************************************************************** -* Function prototypes -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdConnect(void); -static sb_uint8 XcpMasterSendCmdSetMta(sb_uint32 address); -static sb_uint8 XcpMasterSendCmdUpload(sb_uint8 data[], sb_uint8 length); -static sb_uint8 XcpMasterSendCmdProgramStart(void); -static sb_uint8 XcpMasterSendCmdProgramReset(void); -static sb_uint8 XcpMasterSendCmdProgram(sb_uint8 length, sb_uint8 data[]); -static sb_uint8 XcpMasterSendCmdProgramMax(sb_uint8 data[]); -static sb_uint8 XcpMasterSendCmdProgramClear(sb_uint32 length); -static void XcpMasterSetOrderedLong(sb_uint32 value, sb_uint8 data[]); - - -/**************************************************************************************** -* Local data declarations -****************************************************************************************/ -/** \brief Store the byte ordering of the XCP slave. */ -static sb_uint8 xcpSlaveIsIntel = SB_FALSE; - -/** \brief The max number of bytes in the command transmit object (master->slave). */ -static sb_uint8 xcpMaxCto; - -/** \brief The max number of bytes in the command transmit object (master->slave) during - * a programming session. - */ -static sb_uint8 xcpMaxProgCto = 0; - -/** \brief The max number of bytes in the data transmit object (slave->master). */ -static sb_uint8 xcpMaxDto; - -/** \brief Internal data buffer for storing the data of the XCP response packet. */ -static tXcpTransportResponsePacket responsePacket; - - -/************************************************************************************//** -** \brief Initializes the XCP master protocol layer. -** \param device Serial communication device name. For example "COM4". -** \param baudrate Communication speed in bits/sec. -** \return SB_TRUE is successful, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpMasterInit(sb_char *device, sb_uint32 baudrate) -{ - /* initialize the underlying transport layer that is used for the communication */ - return XcpTransportInit(device, baudrate); -} /*** end of XcpMasterInit ***/ - - -/************************************************************************************//** -** \brief Uninitializes the XCP master protocol layer. -** \return none. -** -****************************************************************************************/ -void XcpMasterDeinit(void) -{ - XcpTransportClose(); -} /*** end of XcpMasterDeinit ***/ - - -/************************************************************************************//** -** \brief Connect to the XCP slave. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpMasterConnect(void) -{ - sb_uint8 cnt; - - /* try to connect with a finite amount of retries */ - for (cnt=0; cnt 0) - { - /* set the current read length to make optimal use of the available packet data. */ - currentReadCnt = len % (xcpMaxDto - 1); - if (currentReadCnt == 0) - { - currentReadCnt = (xcpMaxDto - 1); - } - /* upload some data */ - if (XcpMasterSendCmdUpload(&data[bufferOffset], currentReadCnt) == SB_FALSE) - { - return SB_FALSE; - } - /* update loop variables */ - len -= currentReadCnt; - bufferOffset += currentReadCnt; - } - /* still here so all data successfully read from the slave */ - return SB_TRUE; -} /*** end of XcpMasterReadData ***/ - - -/************************************************************************************//** -** \brief Programs data to the slave's non volatile memory. Note that it must be -** erased first. -** \param addr Base memory address for the program operation -** \param len Number of bytes to program. -** \param data Source buffer with the to be programmed bytes. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -sb_uint8 XcpMasterProgramData(sb_uint32 addr, sb_uint32 len, sb_uint8 data[]) -{ - sb_uint8 currentWriteCnt; - sb_uint32 bufferOffset = 0; - - /* first set the MTA pointer */ - if (XcpMasterSendCmdSetMta(addr) == SB_FALSE) - { - return SB_FALSE; - } - /* perform segmented programming of the data */ - while (len > 0) - { - /* set the current read length to make optimal use of the available packet data. */ - currentWriteCnt = len % (xcpMaxProgCto - 1); - if (currentWriteCnt == 0) - { - currentWriteCnt = (xcpMaxProgCto - 1); - } - /* prepare the packed data for the program command */ - if (currentWriteCnt < (xcpMaxProgCto - 1)) - { - /* program data */ - if (XcpMasterSendCmdProgram(currentWriteCnt, &data[bufferOffset]) == SB_FALSE) - { - return SB_FALSE; - } - } - else - { - /* program max data */ - if (XcpMasterSendCmdProgramMax(&data[bufferOffset]) == SB_FALSE) - { - return SB_FALSE; - } - } - /* update loop variables */ - len -= currentWriteCnt; - bufferOffset += currentWriteCnt; - } - /* still here so all data successfully programmed */ - return SB_TRUE; -} /*** end of XcpMasterProgramData ***/ - - -/************************************************************************************//** -** \brief Sends the XCP Connect command. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdConnect(void) -{ - sb_uint8 packetData[2]; - tXcpTransportResponsePacket *responsePacketPtr; - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_CONNECT; - packetData[1] = 0; /* normal mode */ - - /* send the packet */ - if (XcpTransportSendPacket(packetData, 2, XCP_MASTER_CONNECT_TIMEOUT_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* process response data */ - if ((responsePacketPtr->data[2] & 0x01) == 0) - { - /* store slave's byte ordering information */ - xcpSlaveIsIntel = SB_TRUE; - } - /* store max number of bytes the slave allows for master->slave packets. */ - xcpMaxCto = responsePacketPtr->data[3]; - xcpMaxProgCto = xcpMaxCto; - /* store max number of bytes the slave allows for slave->master packets. */ - if (xcpSlaveIsIntel == SB_TRUE) - { - xcpMaxDto = responsePacketPtr->data[4] + (responsePacketPtr->data[5] << 8); - } - else - { - xcpMaxDto = responsePacketPtr->data[5] + (responsePacketPtr->data[4] << 8); - } - - /* double check size configuration of the master */ - assert(XCP_MASTER_TX_MAX_DATA >= xcpMaxCto); - assert(XCP_MASTER_RX_MAX_DATA >= xcpMaxDto); - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdConnect ***/ - - -/************************************************************************************//** -** \brief Sends the XCP Set MTA command. -** \param address New MTA address for the slave. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdSetMta(sb_uint32 address) -{ - sb_uint8 packetData[8]; - tXcpTransportResponsePacket *responsePacketPtr; - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_SET_MTA; - packetData[1] = 0; /* reserved */ - packetData[2] = 0; /* reserved */ - packetData[3] = 0; /* address extension not supported */ - - /* set the address taking into account byte ordering */ - XcpMasterSetOrderedLong(address, &packetData[4]); - - /* send the packet */ - if (XcpTransportSendPacket(packetData, 8, XCP_MASTER_TIMEOUT_T1_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdSetMta ***/ - - -/************************************************************************************//** -** \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 sb_uint8 XcpMasterSendCmdUpload(sb_uint8 data[], sb_uint8 length) -{ - sb_uint8 packetData[2]; - tXcpTransportResponsePacket *responsePacketPtr; - sb_uint8 data_index; - - /* cannot request more data then the max rx data - 1 */ - assert(length < XCP_MASTER_RX_MAX_DATA); - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_UPLOAD; - packetData[1] = length; - - /* send the packet */ - if (XcpTransportSendPacket(packetData, 2, XCP_MASTER_TIMEOUT_T1_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* now store the uploaded data */ - for (data_index=0; data_indexdata[data_index+1]; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdUpload ***/ - - -/************************************************************************************//** -** \brief Sends the XCP PROGRAM START command. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdProgramStart(void) -{ - sb_uint8 packetData[1]; - tXcpTransportResponsePacket *responsePacketPtr; - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_PROGRAM_START; - - /* send the packet */ - if (XcpTransportSendPacket(packetData, 1, XCP_MASTER_TIMEOUT_T3_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* store max number of bytes the slave allows for master->slave packets during the - * programming session - */ - xcpMaxProgCto = responsePacketPtr->data[3]; - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdProgramStart ***/ - - -/************************************************************************************//** -** \brief Sends the XCP PROGRAM RESET command. Note that this command is a bit -** different as in it does not require a response. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdProgramReset(void) -{ - sb_uint8 packetData[1]; - tXcpTransportResponsePacket *responsePacketPtr; - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_PROGRAM_RESET; - - /* send the packet, assume the sending itself is ok and check if a response was - * received. - */ - if (XcpTransportSendPacket(packetData, 1, XCP_MASTER_TIMEOUT_T5_MS) == SB_FALSE) - { - /* probably no response received within the specified timeout, but that is allowed - * for the reset command. - */ - return SB_TRUE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdProgramReset ***/ - - -/************************************************************************************//** -** \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 SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdProgram(sb_uint8 length, sb_uint8 data[]) -{ - sb_uint8 packetData[XCP_MASTER_TX_MAX_DATA]; - tXcpTransportResponsePacket *responsePacketPtr; - sb_uint8 cnt; - - /* verify that this number of bytes actually first in this command */ - assert(length <= (xcpMaxProgCto-2) && (xcpMaxProgCto <= XCP_MASTER_TX_MAX_DATA)); - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_PROGRAM; - packetData[1] = length; - for (cnt=0; cntlen == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdProgram ***/ - - -/************************************************************************************//** -** \brief Sends the XCP PROGRAM MAX command. -** \param data Array with data bytes to program. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdProgramMax(sb_uint8 data[]) -{ - sb_uint8 packetData[XCP_MASTER_TX_MAX_DATA]; - tXcpTransportResponsePacket *responsePacketPtr; - sb_uint8 cnt; - - /* verify that this number of bytes actually first in this command */ - assert(xcpMaxProgCto <= XCP_MASTER_TX_MAX_DATA); - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_PROGRAM_MAX; - for (cnt=0; cnt<(xcpMaxProgCto-1); cnt++) - { - packetData[cnt+1] = data[cnt]; - } - - /* send the packet */ - if (XcpTransportSendPacket(packetData, xcpMaxProgCto, XCP_MASTER_TIMEOUT_T5_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdProgramMax ***/ - - -/************************************************************************************//** -** \brief Sends the XCP PROGRAM CLEAR command. -** \return SB_TRUE is successfull, SB_FALSE otherwise. -** -****************************************************************************************/ -static sb_uint8 XcpMasterSendCmdProgramClear(sb_uint32 length) -{ - sb_uint8 packetData[8]; - tXcpTransportResponsePacket *responsePacketPtr; - - /* prepare the command packet */ - packetData[0] = XCP_MASTER_CMD_PROGRAM_CLEAR; - packetData[1] = 0; /* use absolute mode */ - packetData[2] = 0; /* reserved */ - packetData[3] = 0; /* reserved */ - - /* set the erase length taking into account byte ordering */ - XcpMasterSetOrderedLong(length, &packetData[4]); - - - /* send the packet */ - if (XcpTransportSendPacket(packetData, 8, XCP_MASTER_TIMEOUT_T4_MS) == SB_FALSE) - { - /* cound not set packet or receive response within the specified timeout */ - return SB_FALSE; - } - /* still here so a response was received */ - responsePacketPtr = XcpTransportReadResponsePacket(); - - /* check if the reponse was valid */ - if ( (responsePacketPtr->len == 0) || (responsePacketPtr->data[0] != XCP_MASTER_CMD_PID_RES) ) - { - /* not a valid or positive response */ - return SB_FALSE; - } - - /* still here so all went well */ - return SB_TRUE; -} /*** end of XcpMasterSendCmdProgramClear ***/ - - -/************************************************************************************//** -** \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. -** \return none. -** -****************************************************************************************/ -static void XcpMasterSetOrderedLong(sb_uint32 value, sb_uint8 data[]) -{ - if (xcpSlaveIsIntel == SB_TRUE) - { - data[3] = (sb_uint8)(value >> 24); - data[2] = (sb_uint8)(value >> 16); - data[1] = (sb_uint8)(value >> 8); - data[0] = (sb_uint8)value; - } - else - { - data[0] = (sb_uint8)(value >> 24); - data[1] = (sb_uint8)(value >> 16); - data[2] = (sb_uint8)(value >> 8); - data[3] = (sb_uint8)value; - } -} /*** end of XcpMasterSetOrderedLong ***/ - - -/*********************************** end of xcpmaster.c ********************************/ diff --git a/Host/Source/SerialBoot/xcptpuart.c b/Host/Source/SerialBoot/xcptpuart.c new file mode 100644 index 00000000..d3347d55 --- /dev/null +++ b/Host/Source/SerialBoot/xcptpuart.c @@ -0,0 +1,255 @@ +/************************************************************************************//** +* \file xcptpuart.c +* \brief XCP transport layer module for UART source file. +* \ingroup SerialBoot +* \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 NULL declaration */ +#include /* for standard library */ +#include /* for string library */ +#include /* for assertions */ +#include "xcptpuart.h" /* XCP transport layer for UART */ +#include "timeutil.h" /* for time utilities module */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Maximum amount of data bytes that this module supports for XCP packets. */ +#define XCP_TP_UART_MAX_DATA_LEN (256) + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +static void XcpTpUartInit(void *settings); +static void XcpTpUartDeinit(void); +static bool XcpTpUartConnect(void); +static void XcpTpUartDisconnect(void); +static bool XcpTpUartSendPacket(tXcpPacket *txPacket, tXcpPacket *rxPacket, uint16_t timeout); + + +/**************************************************************************************** +* Local constant declarations +****************************************************************************************/ +/** \brief XCP transport structure filled with UART specifics. */ +static const tXcpTransport uartTransport = +{ + XcpTpUartInit, + XcpTpUartDeinit, + XcpTpUartConnect, + XcpTpUartDisconnect, + XcpTpUartSendPacket +}; + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief The settings to use in this transport layer. */ +static tXcpTpUartSettings tpUartSettings; + + +/***********************************************************************************//** +** \brief Obtains a pointer to the XCP UART transport structure, so that it can +** be linked to the XCP loader module. +** \return Pointer to XCP UART transport structure. +** +****************************************************************************************/ +tXcpTransport const * const XcpTpUartGetTransport(void) +{ + return &uartTransport; +} /*** end of XcpTpUartGetTransport ***/ + + +/************************************************************************************//** +** \brief Initializes the transport layer. +** \param settings Pointer to settings structure. +** \return None. +** +****************************************************************************************/ +static void XcpTpUartInit(void *settings) +{ + /* verify parameters */ + assert(settings != NULL); + + /* shallow copy the transport layer settings for layer usage */ + tpUartSettings = *((tXcpTpUartSettings *)settings); + /* the portname is a pointer and it is not gauranteed that it stays valid so we need + * to deep copy this one. note the +1 for '\0' in malloc. + */ + tpUartSettings.portname = malloc(strlen(((tXcpTpUartSettings *)settings)->portname) + 1); + strcpy(tpUartSettings.portname, ((tXcpTpUartSettings *)settings)->portname); +} /*** end of XcpTpUartInit ***/ + + +/************************************************************************************//** +** \brief Uninitializes the transport layer. +** \return None. +** +****************************************************************************************/ +static void XcpTpUartDeinit(void) +{ + /* release memory that was allocated for storing the port name */ + if (tpUartSettings.portname != NULL) + { + free(tpUartSettings.portname); + } +} /*** end of XcpTpUartDeinit ***/ + + +/************************************************************************************//** +** \brief Connects to the transport layer. +** \return True is connected, false otherwise. +** +****************************************************************************************/ +static bool XcpTpUartConnect(void) +{ + /* connect to the serial port */ + return SerialPortOpen(tpUartSettings.portname, tpUartSettings.baudrate); +} /*** end of XcpTpUartConnect ***/ + + +/************************************************************************************//** +** \brief Disconnects from the transport layer. +** \return None. +** +****************************************************************************************/ +static void XcpTpUartDisconnect(void) +{ + /* disconnect from the serial port */ + SerialPortClose(); +} /*** end of XcpTpUartDisconnect ***/ + + +/************************************************************************************//** +** \brief Transmits an XCP packet on the transport layer and attempts to receive the +** response packet within the specified timeout. +** \return True is successful and a response packet was received, false otherwise. +** +****************************************************************************************/ +static bool XcpTpUartSendPacket(tXcpPacket *txPacket, tXcpPacket *rxPacket, uint16_t timeout) +{ + static uint8_t uartBuffer[XCP_TP_UART_MAX_DATA_LEN + 1]; /* static to lower stack load */ + uint8_t byteIdx; + uint32_t responseTimeoutTime; + bool packetReceptionComplete; + + /* verify parameters */ + assert(txPacket != NULL); + assert(txPacket->len <= XCP_TP_UART_MAX_DATA_LEN); + assert(rxPacket != NULL); + assert(timeout > 0); + + + /* prepare the XCP packet for transmission on UART. this is basically the same as the + * xcp packet data but just the length of the packet is added to the first byte. + */ + uartBuffer[0] = txPacket->len; + for (byteIdx=0; byteIdxlen; byteIdx++) + { + uartBuffer[byteIdx + 1] = txPacket->data[byteIdx]; + } + + /* transmit the packet */ + if (!SerialPortWrite(uartBuffer, txPacket->len + 1)) + { + return false; + } + + /* determine timeout time for the response packet */ + responseTimeoutTime = TimeUtilGetSystemTimeMs() + timeout; + + /* initialize packet reception length */ + uartBuffer[0] = 0; + /* poll with timeout detection to receive the first byte. this one contains the + * packet length and cannot be zero. + */ + while (TimeUtilGetSystemTimeMs() < responseTimeoutTime) + { + if (SerialPortRead(&uartBuffer[0], 1)) + { + /* length received. validate it before accepting it */ + if (uartBuffer[0] > 0) + { + /* start of packet received. stop this loop to continue with the + * reception of the packet. + */ + break; + } + } + } + /* check if a valid start of packet was received */ + if (uartBuffer[0] == 0) + { + /* no valid start of packet received, so a timeout occurred. */ + return false; + } + + /* continue with reception of the packet */ + packetReceptionComplete = false; + byteIdx = 1; + /* poll with timeout detection to receive the full packet */ + while (TimeUtilGetSystemTimeMs() < responseTimeoutTime) + { + /* check if the next byte was received */ + if (SerialPortRead(&uartBuffer[byteIdx], 1)) + { + /* check if the packet reception is now complete */ + if (byteIdx == uartBuffer[0]) + { + /* set flag and stop the loop */ + packetReceptionComplete = true; + break; + } + /* increment indexer to the next byte */ + byteIdx++; + } + } + + /* check if a timeout occurred */ + if (!packetReceptionComplete) + { + return false; + } + + /* still here so a full packet was received. copy its contents except the length info + * which is stored in the first byte + */ + for (byteIdx=0; byteIdxdata[byteIdx] = uartBuffer[byteIdx + 1]; + } + rxPacket->len = uartBuffer[0]; + + return true; +} /*** end of XcpTpUartSendPacket ***/ + + +/*********************************** end of xcptpuart.c ********************************/ + diff --git a/Host/Source/SerialBoot/sb_types.h b/Host/Source/SerialBoot/xcptpuart.h similarity index 64% rename from Host/Source/SerialBoot/sb_types.h rename to Host/Source/SerialBoot/xcptpuart.h index 1317ff1f..b227dc93 100644 --- a/Host/Source/SerialBoot/sb_types.h +++ b/Host/Source/SerialBoot/xcptpuart.h @@ -1,65 +1,66 @@ -/************************************************************************************//** -* \file sb_types.h -* \brief Serial Boot type definitions header file. -* \ingroup SerialBoot -* \internal -*---------------------------------------------------------------------------------------- -* C O P Y R I G H T -*---------------------------------------------------------------------------------------- -* Copyright (c) 2014 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 -****************************************************************************************/ -#ifndef SB_TYPES_H -#define SB_TYPES_H - -/**************************************************************************************** -* Include files -****************************************************************************************/ -#include /* standard I/O library */ - - -/**************************************************************************************** -* Macro definitions -****************************************************************************************/ -/** \brief Generic boolean true value. */ -#define SB_TRUE (1u) - -/** \brief Ceneric boolean false value. */ -#define SB_FALSE (0u) - -/** \brief NULL pointer value. */ -#define SB_NULL ((void *)0) - - -/**************************************************************************************** -* Type definitions -****************************************************************************************/ -typedef signed char sb_char; -typedef signed char sb_int8; -typedef signed short sb_int16; -typedef signed int sb_int32; -typedef unsigned char sb_uint8; -typedef unsigned short sb_uint16; -typedef unsigned int sb_uint32; -typedef FILE * sb_file; - - - -#endif /* SB_TYPES_H */ -/*********************************** end of sb_types.h *********************************/ +/************************************************************************************//** +* \file xcptpuart.h +* \brief XCP transport layer module for UART header file. +* \ingroup SerialBoot +* \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 +****************************************************************************************/ +#ifndef XCPTPUART_H +#define XCPTPUART_H + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "xcploader.h" /* XCP loader module */ +#include "serialport.h" /* serial port module */ + + +/*************************************************************************************** +* Type definitions +****************************************************************************************/ +/** \brief Layout of structure with settings specific to the XCP transport layer module + * for UART. + */ +typedef struct t_xcp_tp_uart_settings +{ + tSerialPortBaudrate baudrate; /**< UART communication speed. */ + char *portname; /**< interface port name, i.e. /dev/ttyUSB0. */ +} tXcpTpUartSettings; + + +/*************************************************************************************** +* Function prototypes +****************************************************************************************/ +tXcpTransport const * const XcpTpUartGetTransport(void); + +#ifdef __cplusplus +} +#endif + +#endif /* XCPTPUART_H */ +/********************************* end of xcptpuart.h **********************************/ +