openblt/Host/Source/SerialBoot/main.c

366 lines
14 KiB
C

/************************************************************************************//**
* \file main.c
* \brief SerialBoot program source file.
* \ingroup SerialBoot
* \internal
*----------------------------------------------------------------------------------------
* C O P Y R I G H T
*----------------------------------------------------------------------------------------
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
*
*----------------------------------------------------------------------------------------
* L I C E N S E
*----------------------------------------------------------------------------------------
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You have received a copy of the GNU General Public License along with OpenBLT. It
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
*
* \endinternal
****************************************************************************************/
/****************************************************************************************
* Include files
****************************************************************************************/
#include <stdio.h> /* standard I/O functions */
#include <string.h> /* for string library */
#include "xcploader.h" /* XCP loader module */
#include "xcptpuart.h" /* XCP transport layer for UART */
#include "firmware.h" /* Firmware module */
#include "srecparser.h" /* S-record parser */
#include "timeutil.h" /* for time utilities module */
/****************************************************************************************
* Macro definitions
****************************************************************************************/
/* Program return codes. */
#define RESULT_OK (0)
#define RESULT_COMMANDLINE_ERROR (1)
#define RESULT_FIRMWARE_LOAD_ERROR (2)
#define RESULT_PROGRAM_START_ERROR (3)
#define RESULT_MEMORY_ERASE_ERROR (4)
#define RESULT_PROGRAM_STOP_ERROR (5)
#define RESULT_MEMORY_PROGRAM_ERROR (6)
/****************************************************************************************
* Local data declarations
****************************************************************************************/
/** \brief The firmware filename that is specified at the command line. */
static char *firmwareFilename;
/** \brief XCP loader settings. */
static tXcpSettings xcpSettings =
{
.timeoutT1 = 1000,
.timeoutT3 = 2000,
.timeoutT4 = 10000,
.timeoutT5 = 1000,
.timeoutT7 = 2000
};
/** \brief XCP UART transport layer settings. */
static tXcpTpUartSettings xcpTpUartSettings =
{
.baudrate = SERIALPORT_BR57600,
.portname = "/dev/ttyS0"
};
/****************************************************************************************
* Function prototypes
****************************************************************************************/
static void DisplayProgramInfo(void);
static void DisplayProgramUsage(void);
static bool ParseCommandLine(int argc, char *argv[]);
/************************************************************************************//**
** \brief This is the program entry point.
** \param argc Number of program arguments.
** \param argv Array with program arguments.
** \return Program return code. 0 for success, error code otherwise.
**
****************************************************************************************/
int main(int argc, char *argv[])
{
int result = RESULT_OK;
uint32_t fwBaseAddress;
uint32_t fwTotalSize;
uint32_t segmentIdx;
const tFirmwareSegment *segment;
/* -------------------- Display info ----------------------------------------------- */
/* inform user about the program */
DisplayProgramInfo();
/* -------------------- Process command line --------------------------------------- */
/* start out by making sure program was started with the correct parameters */
if (!ParseCommandLine(argc, argv))
{
/* parameters invalid. inform user about how this program works */
DisplayProgramUsage();
return RESULT_COMMANDLINE_ERROR;
}
/* -------------------- Initialization --------------------------------------------- */
/* initialize the XCP loader module using the UART transport layer. */
XcpLoaderInit(&xcpSettings, XcpTpUartGetTransport(), &xcpTpUartSettings);
/* initialize the firmware module and link the S-recorder parser */
FirmwareInit(SRecParserGetParser());
/* -------------------- Parse the firmware file ------------------------------------ */
/* attempt to load the firmware file */
printf("Loading firmware file..."); fflush(stdout);
if (!FirmwareLoadFromFile(firmwareFilename))
{
/* set error code and abort */
printf("ERROR\n");
result = RESULT_FIRMWARE_LOAD_ERROR;
goto finish;
}
printf("OK\n");
/* determine firmware base address and total size */
for (segmentIdx=0; segmentIdx<FirmwareGetSegmentCount(); segmentIdx++)
{
segment = FirmwareGetSegment(segmentIdx);
/* is this the first segment? */
if (segmentIdx == 0)
{
/* initialize */
fwBaseAddress = segment->base;
fwTotalSize = segment->length;
}
else
{
/* update */
if (segment->base < fwBaseAddress)
{
fwBaseAddress = segment->base;
}
fwTotalSize += segment->length;
}
}
/* display some firmware statistics */
printf("-> Number of segments: %u\n", FirmwareGetSegmentCount());
printf("-> Base memory address: 0x%08x\n", fwBaseAddress);
printf("-> Total data bytes: %u\n", fwTotalSize);
/* -------------------- Connect to target ------------------------------------------ */
printf("Connecting to bootloader..."); fflush(stdout);
if (!XcpLoaderConnect())
{
/* no response. prompt the user to reset the system */
printf("TIMEOUT\nReset your microcontroller..."); fflush(stdout);
/* now keep retrying until we get a response */
while (!XcpLoaderConnect())
{
/* delay a bit to not pump up the CPU load */
TimeUtilDelayMs(20);
}
}
printf("OK\n");
/* -------------------- Start the programming session ------------------------------ */
/* attempt to start the programming session */
printf("Starting programming session..."); fflush(stdout);
if (!XcpLoaderStartProgrammingSession())
{
/* set error code and abort */
printf("ERROR\n");
result = RESULT_PROGRAM_START_ERROR;
goto finish;
}
printf("OK\n");
/* -------------------- Erase memory ----------------------------------------------- */
/* erase each segment one at a time */
for (segmentIdx=0; segmentIdx<FirmwareGetSegmentCount(); segmentIdx++)
{
segment = FirmwareGetSegment(segmentIdx);
/* attempt to erase memory */
printf("Erasing %u bytes starting at 0x%08x...", segment->length, segment->base); fflush(stdout);
if (!XcpLoaderClearMemory(segment->base, segment->length))
{
/* set error code and abort */
printf("ERROR\n");
result = RESULT_MEMORY_ERASE_ERROR;
goto finish;
}
printf("OK\n");
}
/* -------------------- Program data ----------------------------------------------- */
/* program each segment one at a time */
for (segmentIdx=0; segmentIdx<FirmwareGetSegmentCount(); segmentIdx++)
{
segment = FirmwareGetSegment(segmentIdx);
/* attempt to program memory */
printf("Programming %u bytes starting at 0x%08x...", segment->length, segment->base); fflush(stdout);
if (!XcpLoaderProgramData(segment->base, segment->length, segment->data))
{
/* set error code and abort */
printf("ERROR\n");
result = RESULT_MEMORY_PROGRAM_ERROR;
goto finish;
}
printf("OK\n");
}
/* -------------------- Stop the programming session ------------------------------- */
/* attempt to stop the programming session */
printf("Finishing programming session..."); fflush(stdout);
if (!XcpLoaderStopProgrammingSession())
{
/* set error code and abort */
printf("ERROR\n");
result = RESULT_PROGRAM_STOP_ERROR;
goto finish;
}
printf("OK\n");
/* -------------------- Cleanup ---------------------------------------------------- */
finish:
/* uninitialize the firmware module */
FirmwareDeinit();
/* uninitialize the XCP loader module. note that this automatically disconnects the
* slave, if connected, by requesting it to perform a reset.
*/
XcpLoaderDeinit();
/* give result back */
return result;
} /*** end of main ***/
/************************************************************************************//**
** \brief Outputs information to the user about this program.
** \return none.
**
****************************************************************************************/
static void DisplayProgramInfo(void)
{
printf("-------------------------------------------------------------------------\n");
printf("SerialBoot version 2.00. Performs firmware updates via the serial port\n");
printf("for a microcontroller based system that runs the OpenBLT bootloader.\n\n");
printf("Copyright (c) by Feaser http://www.feaser.com\n");
printf("-------------------------------------------------------------------------\n");
} /*** end of DisplayProgramInfo ***/
/************************************************************************************//**
** \brief Outputs information to the user about how to use this program.
** \return none.
**
****************************************************************************************/
static void DisplayProgramUsage(void)
{
printf("Usage: SerialBoot -d[device] -b[baudrate] [s-record file]\n\n");
#ifdef PLATFORM_WIN32
printf("Example: SerialBoot -dCOM4 -b57600 myfirmware.s19\n");
printf(" -> Connects to COM4, configures a communication speed of 57600\n");
#else
printf("Example: SerialBoot -d/dev/ttyS0 -b57600 myfirmware.s19\n");
printf(" -> Connects to ttyS0, configures a communication speed of 57600\n");
#endif
printf(" bits/second and programs the myfirmware.s19 file in non-\n");
printf(" volatile memory of the microcontroller using OpenBLT.\n");
printf(" Supported baudrates are: 9600, 19200, 38400, 57600 and\n");
printf(" 115200 bits/second.\n");
printf("-------------------------------------------------------------------------\n");
} /*** end of DisplayProgramUsage ***/
/************************************************************************************//**
** \brief Parses the command line arguments. A fixed amount of arguments is expected.
** The program should be called as:
** SerialBoot -d[device] -b[baudrate] [s-record file]
** \param argc Number of program parameters.
** \param argv array to program parameter strings.
** \return True if successful, false otherwise.
**
****************************************************************************************/
static bool ParseCommandLine(int argc, char *argv[])
{
uint8_t paramIdx;
bool firmwareFileFound = false;
uint32_t baudrateValue;
/* make sure that enough arguments were specified. this program needs at least 2. the
* first one is always the program name and the second one is the s-record file.
*/
if (argc < 2)
{
return false;
}
/* loop through all the command line parameters, just skip the 1st one because this
* is the name of the program, which we are not interested in.
*/
for (paramIdx=1; paramIdx<argc; paramIdx++)
{
/* is this the device name? */
if ( (argv[paramIdx][0] == '-') && (argv[paramIdx][1] == 'd') )
{
/* set the device name */
xcpTpUartSettings.portname = &argv[paramIdx][2];
continue;
}
/* is this the baudrate? */
if ( (argv[paramIdx][0] == '-') && (argv[paramIdx][1] == 'b') )
{
/* extract the baudrate */
sscanf(&argv[paramIdx][2], "%u", &baudrateValue);
/* convert to the baudrate type */
switch (baudrateValue)
{
case 115200:
xcpTpUartSettings.baudrate = SERIALPORT_BR115200;
break;
case 57600:
xcpTpUartSettings.baudrate = SERIALPORT_BR57600;
break;
case 38400:
xcpTpUartSettings.baudrate = SERIALPORT_BR38400;
break;
case 19200:
xcpTpUartSettings.baudrate = SERIALPORT_BR19200;
break;
case 9600:
xcpTpUartSettings.baudrate = SERIALPORT_BR9600;
break;
default:
/* unsupported baudrate specified */
return false;
}
continue;
}
/* still here so it must be the filename */
else
{
/* set the file name and set flag that this parameter was found */
firmwareFilename = &argv[paramIdx][0];
firmwareFileFound = true;
}
}
/* verify if all required parameters were found */
if (!firmwareFileFound)
{
return false;
}
/* still here so the parsing was successful */
return true;
} /*** end of ParseCommandLine ***/
/*********************************** end of main.c *************************************/