diff --git a/Host/SerialBoot.exe b/Host/SerialBoot.exe new file mode 100644 index 00000000..013dd247 Binary files /dev/null and b/Host/SerialBoot.exe differ diff --git a/Host/Source/SerialBoot/CMakeLists.txt b/Host/Source/SerialBoot/CMakeLists.txt new file mode 100644 index 00000000..85fc0554 --- /dev/null +++ b/Host/Source/SerialBoot/CMakeLists.txt @@ -0,0 +1,70 @@ +#**************************************************************************************** +# \file CMakeLists.txt +# \brief CMake descriptor file for SerialBoot command line demonstration program. +# \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 should have received a copy of the GNU General Public License along with OpenBLT. +# If not, see . +# +# A special exception to the GPL is included to allow you to distribute a combined work +# that includes OpenBLT without being obliged to provide the source code for any +# proprietary components. The exception text is included at the bottom of the license +# file . +# +# \endinternal +#**************************************************************************************** + +# Specify the version being used aswell as the language +cmake_minimum_required(VERSION 2.8) + +# Specify the project name +project(SerialBoot) + +# Set the port directory, which is platform specific +IF(WIN32) + set(PROJECT_PORT_DIR ${PROJECT_SOURCE_DIR}/port/win32) + 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) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_LINUX") +ENDIF(WIN32) + +# Build debug version by default +set(CMAKE_BUILD_TYPE "Debug") + +# Set include directories +include_directories("${PROJECT_SOURCE_DIR}" "${PROJECT_PORT_DIR}" "${PROJECT_SOURCE_DIR}/port") + +# Get header files +file(GLOB_RECURSE INCS "*.h") + +# Add sources +add_executable( + SerialBoot + main.c + xcpmaster.c + srecord.c + ${PROJECT_PORT_DIR}/xcptransport.c + ${PROJECT_PORT_DIR}/timeutil.c + ${INCS} +) + + +#*********************************** end of CMakeLists.txt ****************************** \ No newline at end of file diff --git a/Host/Source/SerialBoot/main.c b/Host/Source/SerialBoot/main.c new file mode 100644 index 00000000..369619ec --- /dev/null +++ b/Host/Source/SerialBoot/main.c @@ -0,0 +1,335 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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. +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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 *****************************/ diff --git a/Host/Source/SerialBoot/port/linux/xcptransport.c b/Host/Source/SerialBoot/port/linux/xcptransport.c new file mode 100644 index 00000000..18e429dd --- /dev/null +++ b/Host/Source/SerialBoot/port/linux/xcptransport.c @@ -0,0 +1,299 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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 "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; + + /* 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); + /* 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; + } + /* 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, 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; + } + } + + /* 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/timeutil.h b/Host/Source/SerialBoot/port/timeutil.h new file mode 100644 index 00000000..86840b2e --- /dev/null +++ b/Host/Source/SerialBoot/port/timeutil.h @@ -0,0 +1,44 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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 *********************************/ diff --git a/Host/Source/SerialBoot/port/win32/timeutil.c b/Host/Source/SerialBoot/port/win32/timeutil.c new file mode 100644 index 00000000..97411d53 --- /dev/null +++ b/Host/Source/SerialBoot/port/win32/timeutil.c @@ -0,0 +1,65 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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 *********************************/ diff --git a/Host/Source/SerialBoot/port/win32/xcptransport.c b/Host/Source/SerialBoot/port/win32/xcptransport.c new file mode 100644 index 00000000..c9fc979d --- /dev/null +++ b/Host/Source/SerialBoot/port/win32/xcptransport.c @@ -0,0 +1,262 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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)) + +/** \brief The smallest time in millisecond that the UART is configured for. */ +#define UART_RX_TIMEOUT_MIN_MS (5) + + +/**************************************************************************************** +* 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; + if (!SetCommState(hUart, &dcbSerialParams)) + { + XcpTransportClose(); + return SB_FALSE; + } + + /* set communication timeout parameters */ + timeouts.ReadIntervalTimeout = UART_RX_TIMEOUT_MIN_MS; + timeouts.ReadTotalTimeoutConstant = UART_RX_TIMEOUT_MIN_MS; + timeouts.ReadTotalTimeoutMultiplier = 1; + timeouts.WriteTotalTimeoutConstant = UART_RX_TIMEOUT_MIN_MS; + timeouts.WriteTotalTimeoutMultiplier = 1; + 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, 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; + } + } + + /* 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/xcptransport.h b/Host/Source/SerialBoot/port/xcptransport.h new file mode 100644 index 00000000..795ecdea --- /dev/null +++ b/Host/Source/SerialBoot/port/xcptransport.h @@ -0,0 +1,56 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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 *****************************/ diff --git a/Host/Source/SerialBoot/sb_types.h b/Host/Source/SerialBoot/sb_types.h new file mode 100644 index 00000000..de019cd5 --- /dev/null +++ b/Host/Source/SerialBoot/sb_types.h @@ -0,0 +1,70 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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 *********************************/ diff --git a/Host/Source/SerialBoot/srecord.c b/Host/Source/SerialBoot/srecord.c new file mode 100644 index 00000000..75bbf88f --- /dev/null +++ b/Host/Source/SerialBoot/srecord.c @@ -0,0 +1,453 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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/srecord.h b/Host/Source/SerialBoot/srecord.h new file mode 100644 index 00000000..1caf6d0a --- /dev/null +++ b/Host/Source/SerialBoot/srecord.h @@ -0,0 +1,80 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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 **********************************/ diff --git a/Host/Source/SerialBoot/xcpmaster.c b/Host/Source/SerialBoot/xcpmaster.c new file mode 100644 index 00000000..c05e4b78 --- /dev/null +++ b/Host/Source/SerialBoot/xcpmaster.c @@ -0,0 +1,694 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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/xcpmaster.h b/Host/Source/SerialBoot/xcpmaster.h new file mode 100644 index 00000000..9447b540 --- /dev/null +++ b/Host/Source/SerialBoot/xcpmaster.h @@ -0,0 +1,71 @@ +/************************************************************************************//** +* \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 should have received a copy of the GNU General Public License along with OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \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 ********************************/