Added SerialBoot, a command line program written in C for both Windows and Linux to perform firmware updates through the PC's serial port using the OpenBLT bootloader.

git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@84 5dc33758-31d5-4daf-9ae8-b24bf3d40d73
This commit is contained in:
Frank Voorburg 2014-05-23 09:32:19 +00:00
parent e5e739f85a
commit d07c3d783a
14 changed files with 2573 additions and 0 deletions

BIN
Host/SerialBoot.exe Normal file

Binary file not shown.

View File

@ -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 <http://www.gnu.org/licenses/>.
#
# 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 <license.html>.
#
# \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 ******************************

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* assertion module */
#include <sb_types.h> /* C types */
#include <stdio.h> /* standard I/O library */
#include <string.h> /* 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<argc; paramIdx++)
{
/* is this the device name? */
if ( (argv[paramIdx][0] == '-') && (argv[paramIdx][1] == 'd') && (paramDfound == SB_FALSE) )
{
/* copy the device name and set flag that this parameter was found */
strcpy(serialDeviceName, &argv[paramIdx][2]);
paramDfound = SB_TRUE;
}
/* is this the device name? */
else if ( (argv[paramIdx][0] == '-') && (argv[paramIdx][1] == 'b') && (paramBfound == SB_FALSE) )
{
/* extract the baudrate and set flag that this parameter was found */
sscanf(&argv[paramIdx][2], "%u", &serialBaudrate);
paramBfound = SB_TRUE;
}
/* still here so it must be the filename */
else if (srecordfound == SB_FALSE)
{
/* copy the file name and set flag that this parameter was found */
strcpy(srecordFileName, &argv[paramIdx][0]);
srecordfound = SB_TRUE;
}
}
/* verify if all parameters were found */
if ( (paramDfound == SB_FALSE) || (paramBfound == SB_FALSE) || (srecordfound == SB_FALSE) )
{
return SB_FALSE;
}
/* still here so the parsing was successful */
return SB_TRUE;
} /*** end of ParseCommandLine ***/
/*********************************** end of main.c *************************************/

View File

@ -0,0 +1,74 @@
/************************************************************************************//**
* \file port\linux\timeutil.c
* \brief Time utility source file.
* \ingroup SerialBoot
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2014 by Feaser http://www.feaser.com All rights reserved
*
*----------------------------------------------------------------------------------------
* L I C E N S E
*----------------------------------------------------------------------------------------
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with OpenBLT.
* If not, see <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* assertion module */
#include <sb_types.h> /* C types */
#include <unistd.h> /* UNIX standard functions */
#include <fcntl.h> /* file control definitions */
#include <time.h> /* 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 *****************************/

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* assertion module */
#include <sb_types.h> /* C types */
#include <stdio.h> /* standard I/O library */
#include <string.h> /* string function definitions */
#include <unistd.h> /* UNIX standard functions */
#include <fcntl.h> /* file control definitions */
#include <errno.h> /* error number definitions */
#include <termios.h> /* 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<len; cnt++)
{
xcpUartBuffer[cnt+1] = data[cnt];
}
bytesSent = write(hUart, xcpUartBuffer, xcpUartLen);
if (bytesSent != xcpUartLen)
{
return SB_FALSE;
}
/* ------------------------ XCP packet reception ----------------------------------- */
/* determine timeout time */
timeoutTime = TimeUtilGetSystemTimeMs() + timeOutMs + UART_RX_TIMEOUT_MIN_MS;
/* read the first byte, which contains the length of the xcp packet that follows */
bytesToRead = 1;
uartReadDataPtr = &responsePacket.len;
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;
}
}
/* 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 *****************************/

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \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 *********************************/

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* assertion module */
#include <sb_types.h> /* C types */
#include <windows.h> /* 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 *********************************/

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* assertion module */
#include <sb_types.h> /* C types */
#include <windows.h> /* for WIN32 library */
#include <string.h> /* 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<len; cnt++)
{
xcpUartBuffer[cnt+1] = data[cnt];
}
/* first submit the XCP packet for transmission */
if (!WriteFile(hUart, xcpUartBuffer, xcpUartLen, &dwWritten, SB_NULL))
{
return SB_FALSE;
}
/* double check that all bytes were actually transmitted */
if (dwWritten != xcpUartLen)
{
return SB_FALSE;
}
/* ------------------------ XCP packet reception ----------------------------------- */
/* determine timeout time */
timeoutTime = TimeUtilGetSystemTimeMs() + timeOutMs + UART_RX_TIMEOUT_MIN_MS;
/* read the first byte, which contains the length of the xcp packet that follows */
dwToRead = 1;
uartReadDataPtr = &responsePacket.len;
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;
}
}
/* 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 *****************************/

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \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 *****************************/

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \endinternal
****************************************************************************************/
#ifndef SB_TYPES_H
#define SB_TYPES_H
/****************************************************************************************
* Include files
****************************************************************************************/
#include <stdio.h> /* 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 *********************************/

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* assertion module */
#include <sb_types.h> /* C types */
#include <string.h> /* for strcpy etc. */
#include <ctype.h> /* 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; i<parseResults->length; 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; i<parseResults->length; 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; i<parseResults->length; 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 **********************************/

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \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 **********************************/

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <assert.h> /* assertion module */
#include <sb_types.h> /* 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<XCP_MASTER_CONNECT_RETRIES; cnt++)
{
/* send the connect command */
if (XcpMasterSendCmdConnect() == SB_TRUE)
{
/* connected so no need to retry */
return SB_TRUE;
}
}
/* still here so could not connect */
return SB_FALSE;
} /*** end of XcpMasterConnect ***/
/************************************************************************************//**
** \brief Disconnect the slave.
** \return SB_TRUE is successfull, SB_FALSE otherwise.
**
****************************************************************************************/
sb_uint8 XcpMasterDisconnect(void)
{
/* send reset command instead of the disconnect. this causes the user program on the
* slave to automatically start again if present.
*/
return XcpMasterSendCmdProgramReset();
} /*** end of XcpMasterDisconnect ***/
/************************************************************************************//**
** \brief Puts a connected slave in programming session.
** \return SB_TRUE is successfull, SB_FALSE otherwise.
**
****************************************************************************************/
sb_uint8 XcpMasterStartProgrammingSession(void)
{
/* place the slave in programming mode */
return XcpMasterSendCmdProgramStart();
} /*** end of XcpMasterStartProgrammingSession ***/
/************************************************************************************//**
** \brief Stops the programming session by sending a program command with size 0 and
** then resetting the slave.
** \return SB_TRUE is successfull, SB_FALSE otherwise.
**
****************************************************************************************/
sb_uint8 XcpMasterStopProgrammingSession(void)
{
/* stop programming by sending the program command with size 0 */
if (XcpMasterSendCmdProgram(0, SB_NULL) == SB_FALSE)
{
return SB_FALSE;
}
/* request a reset of the slave */
return XcpMasterSendCmdProgramReset();
} /*** end of XcpMasterStopProgrammingSession ***/
/************************************************************************************//**
** \brief Erases non volatile memory on the slave.
** \param addr Base memory address for the erase operation.
** \param len Number of bytes to erase.
** \return SB_TRUE is successfull, SB_FALSE otherwise.
**
****************************************************************************************/
sb_uint8 XcpMasterClearMemory(sb_uint32 addr, sb_uint32 len)
{
/* first set the MTA pointer */
if (XcpMasterSendCmdSetMta(addr) == SB_FALSE)
{
return SB_FALSE;
}
/* now perform the erase operation */
return XcpMasterSendCmdProgramClear(len);
} /*** end of XcpMasterClearMemory ***/
/************************************************************************************//**
** \brief Reads data from the slave's memory.
** \param addr Base memory address for the read operation
** \param len Number of bytes to read.
** \param data Destination buffer for storing the read data bytes.
** \return SB_TRUE is successfull, SB_FALSE otherwise.
**
****************************************************************************************/
sb_uint8 XcpMasterReadData(sb_uint32 addr, sb_uint32 len, sb_uint8 data[])
{
sb_uint8 currentReadCnt;
sb_uint32 bufferOffset = 0;
/* first set the MTA pointer */
if (XcpMasterSendCmdSetMta(addr) == SB_FALSE)
{
return SB_FALSE;
}
/* perform segmented upload of the data */
while (len > 0)
{
/* set the current read length to make optimal use of the available packet data. */
currentReadCnt = len % (xcpMaxDto - 1);
if (currentReadCnt == 0)
{
currentReadCnt = (xcpMaxDto - 1);
}
/* upload some data */
if (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_index<length; data_index++)
{
data[data_index] = responsePacketPtr->data[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; cnt<length; cnt++)
{
packetData[cnt+2] = data[cnt];
}
/* send the packet */
if (XcpTransportSendPacket(packetData, length+2, 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 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 ********************************/

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <license.html>.
*
* \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 ********************************/