|
@@ -0,0 +1,440 @@
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdint.h>
|
|
|
+#include <stdbool.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <stdarg.h>
|
|
|
+#include <limits.h>
|
|
|
+#include <string.h>
|
|
|
+#include <ctype.h>
|
|
|
+#include <byteswap.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <stddef.h>
|
|
|
+#include <time.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <getopt.h>
|
|
|
+#include <gfaserial.h>
|
|
|
+#include <gfabootlmast.h>
|
|
|
+#include "main.h"
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#define _MIN_VERBOSITY 0
|
|
|
+#define _MAX_VERBOSITY 4
|
|
|
+#define _DEFAULT_VERBOSITY 2
|
|
|
+#define _DEFAULT_BAUDRATE 19200
|
|
|
+#define _DEFAULT_SEND_BLOCK_SIZE 76
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+typedef struct _CMD_LINE_ARGS
|
|
|
+{
|
|
|
+ uint8_t nNodeAddr;
|
|
|
+ bool bShowHelp;
|
|
|
+ bool bShowImgInfo;
|
|
|
+ bool bShowMatSer;
|
|
|
+ int nVerbosity;
|
|
|
+ uint32_t nBaudrate;
|
|
|
+ uint32_t nBlockSize;
|
|
|
+ const char *pszDevName;
|
|
|
+ const char *pszImgFile;
|
|
|
+}CMD_LINE_ARGS, *LPCMD_LINE_ARGS;
|
|
|
+typedef const CMD_LINE_ARGS *LPCCMD_LINE_ARGS;
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+static int g_nVerbosity = _DEFAULT_VERBOSITY;
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+static const char* _StrError(int nError)
|
|
|
+{
|
|
|
+ switch(nError)
|
|
|
+ {
|
|
|
+ case GFA_FU_ERROR_INVALID_CMDLINE_ARG:
|
|
|
+ return "Invalid command line argument";
|
|
|
+ case GFA_FU_ERROR_INVALID_BAUDRATE:
|
|
|
+ return "Invalid baudrate";
|
|
|
+ case GFA_FU_ERROR_INVALID_NODE_ADDR:
|
|
|
+ return "Invalid node address";
|
|
|
+ case GFA_FU_ERROR_NOTHING_TO_DO:
|
|
|
+ return "Nothing to do";
|
|
|
+ case GFA_FU_ERROR_INVALID_BLOCK_SIZE:
|
|
|
+ return "Invalid block size";
|
|
|
+ case GFA_FU_ERROR_INVALID_DEVICE_NAME:
|
|
|
+ return "Missing device name";
|
|
|
+ default:
|
|
|
+ return GfaBlmStrError(nError);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+static int _cprintf(int verb, const char *pszFormat, ...)
|
|
|
+{
|
|
|
+ if(verb <= g_nVerbosity)
|
|
|
+ {
|
|
|
+ int nRet;
|
|
|
+ FILE *pf = (verb <= 1) ? stderr : stdout;
|
|
|
+ va_list args;
|
|
|
+ va_start(args, pszFormat);
|
|
|
+ nRet = vfprintf(pf, pszFormat, args);
|
|
|
+ fflush(pf);
|
|
|
+ va_end(args);
|
|
|
+ return nRet;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+static void _TraceImageInfo(const char *pszContext, LPCGFA_IMG_INFO pii)
|
|
|
+{
|
|
|
+ if( (g_nVerbosity >= 2) &&
|
|
|
+ pszContext &&
|
|
|
+ pii &&
|
|
|
+ (pii->nImgLength != 0xFFFFFFFF) &&
|
|
|
+ (pii->nImgCRC32 != 0xFFFFFFFF))
|
|
|
+ {
|
|
|
+ TRACE2("%s Image Information:\n", pszContext);
|
|
|
+ TRACE2(" Length: %u\n", pii->nImgLength);
|
|
|
+ TRACE2(" CRC32: 0x%08X\n", pii->nImgCRC32);
|
|
|
+ TRACE2(" Mat.Nr.: %s\n", pii->szImgMaterialNum);
|
|
|
+ TRACE2(" Build: %s\n", pii->szImgNameBuild);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+static int64_t _ArgStr2Num(const char *pszNum, int64_t nDefault)
|
|
|
+{
|
|
|
+ if(pszNum && *pszNum)
|
|
|
+ {
|
|
|
+ char *pszEnd = NULL;
|
|
|
+ int64_t n = strtoll(pszNum, &pszEnd, 0);
|
|
|
+ if((((n == LLONG_MIN) || (n == LLONG_MAX)) && (errno == ERANGE)) || *pszEnd)
|
|
|
+ return nDefault;
|
|
|
+ return n;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nDefault;
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+static void _InitCmdLineArgs(LPCMD_LINE_ARGS pcla)
|
|
|
+{
|
|
|
+ memset(pcla, 0, sizeof(CMD_LINE_ARGS));
|
|
|
+ pcla->nBaudrate = _DEFAULT_BAUDRATE;
|
|
|
+ pcla->nVerbosity = _DEFAULT_VERBOSITY;
|
|
|
+ pcla->nBlockSize = _DEFAULT_SEND_BLOCK_SIZE;
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+// http://man7.org/linux/man-pages/man3/getopt.3.html
|
|
|
+
|
|
|
+static int _ParseCmdLineArgs(int argc, char* argv[], LPCMD_LINE_ARGS pcla)
|
|
|
+{
|
|
|
+ int c, nCount = 0;
|
|
|
+
|
|
|
+ while((c = getopt(argc, argv, "-ib:v::n:sp:d:")) != -1)
|
|
|
+ {
|
|
|
+ const char *arg = optarg;
|
|
|
+
|
|
|
+ switch(c)
|
|
|
+ {
|
|
|
+ case 'i':
|
|
|
+ pcla->bShowImgInfo = true;
|
|
|
+ break;
|
|
|
+ case 'b':
|
|
|
+ pcla->nBaudrate = (uint32_t)_ArgStr2Num(arg, _DEFAULT_BAUDRATE);
|
|
|
+ break;
|
|
|
+ case 'n':
|
|
|
+ pcla->nNodeAddr = (uint8_t)_ArgStr2Num(arg, 0);
|
|
|
+ break;
|
|
|
+ case 'v':
|
|
|
+ pcla->nVerbosity = (int)_ArgStr2Num(arg, _DEFAULT_VERBOSITY);
|
|
|
+ break;
|
|
|
+ case 's':
|
|
|
+ pcla->bShowMatSer = true;
|
|
|
+ break;
|
|
|
+ case 'p':
|
|
|
+ pcla->nBlockSize = (uint32_t)_ArgStr2Num(arg, _DEFAULT_SEND_BLOCK_SIZE);
|
|
|
+ break;
|
|
|
+ case 'd':
|
|
|
+ pcla->pszDevName = arg;
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ pcla->pszImgFile = arg;
|
|
|
+ break;
|
|
|
+ case '?':
|
|
|
+ pcla->bShowHelp = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ ++nCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(nCount == 0)
|
|
|
+ pcla->bShowHelp = true;
|
|
|
+
|
|
|
+ return nCount;
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+static int _ProcessCmdLineArgs(LPCMD_LINE_ARGS pcla)
|
|
|
+{
|
|
|
+ int nToDo = 0;
|
|
|
+
|
|
|
+ if(pcla->bShowHelp)
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ if(pcla->nVerbosity < _MIN_VERBOSITY)
|
|
|
+ pcla->nVerbosity = _MIN_VERBOSITY;
|
|
|
+ else if(pcla->nVerbosity > _MAX_VERBOSITY)
|
|
|
+ pcla->nVerbosity = _MAX_VERBOSITY;
|
|
|
+
|
|
|
+ if(!GfaSerialIsValidBaudrate(pcla->nBaudrate))
|
|
|
+ return GFA_FU_ERROR_INVALID_BAUDRATE;
|
|
|
+
|
|
|
+ if(!pcla->pszDevName)
|
|
|
+ return GFA_FU_ERROR_INVALID_DEVICE_NAME;
|
|
|
+
|
|
|
+ if(NODE_IS_MULTICAST(pcla->nNodeAddr) || (pcla->nNodeAddr < 0x11))
|
|
|
+ return GFA_FU_ERROR_INVALID_NODE_ADDR;
|
|
|
+
|
|
|
+ if((pcla->nBlockSize < 4) || (pcla->nBlockSize > _DEFAULT_SEND_BLOCK_SIZE) || pcla->nBlockSize & 0x03)
|
|
|
+ return GFA_FU_ERROR_INVALID_BLOCK_SIZE;
|
|
|
+
|
|
|
+ if(pcla->bShowImgInfo)
|
|
|
+ ++nToDo;
|
|
|
+ if(pcla->bShowMatSer)
|
|
|
+ ++nToDo;
|
|
|
+
|
|
|
+ if(nToDo == 0)
|
|
|
+ return GFA_FU_ERROR_NOTHING_TO_DO;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+static void _DisplayHelp(void)
|
|
|
+{
|
|
|
+ printf("gfativaflashutil v%d.%d GfA GmbH (%s %s)\n", GFA_FU_VER_MAJOR, GFA_FU_VER_MINOR, __DATE__, __TIME__);
|
|
|
+ printf(" Usage: gfativaflashutil [OPTIONS] [IMG FILE]>\n\n");
|
|
|
+ printf(" -b <BAUDRATE> baudrate\n");
|
|
|
+ printf(" -n <NODE ADDR> node address\n");
|
|
|
+ printf(" -d <DEVICE NAME> name of the device interface\n");
|
|
|
+ printf(" -p <BLOCK SIZE> size of a download-block (4-76, must be a multiple of 4!)\n");
|
|
|
+ printf(" -i display image information\n");
|
|
|
+ printf(" -s display material and serial numbers\n");
|
|
|
+ printf(" -v <0-4> verbosity. 0=quiet, 1=error, 2=info, 3=status, 4=debug\n");
|
|
|
+ printf(" -? shows this help\n");
|
|
|
+ printf("\n");
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#if 0
|
|
|
+#ifdef _DEBUG
|
|
|
+static void _BuCmdDownloadStatus(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, int nCtx, int nErrorCode)
|
|
|
+#else // _DEBUG
|
|
|
+static void _BuCmdDownloadStatus(uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, int nCtx, int nErrorCode)
|
|
|
+#endif // _DEBUG
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#ifdef _DEBUG
|
|
|
+static void _BuCmdSendDataStatus(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nCbBlock, uint32_t nCbData, int nCtx, int nErrorCode)
|
|
|
+#else // _DEBUG
|
|
|
+static void _BuCmdSendDataStatus(uint8_t nNodeAddr, uint32_t nCbBlock, uint32_t nCbData, int nCtx, int nErrorCode)
|
|
|
+#endif // _DEBUG
|
|
|
+{
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+int main(int argc, char* argv[])
|
|
|
+{
|
|
|
+ int nRet;
|
|
|
+ HGFABLM hBlm = NULL;
|
|
|
+ CMD_LINE_ARGS cla;
|
|
|
+
|
|
|
+ /////////////////////////////////////////////////////////////////////////
|
|
|
+ // process command line
|
|
|
+
|
|
|
+ _InitCmdLineArgs(&cla);
|
|
|
+ nRet = _ParseCmdLineArgs(argc, argv, &cla);
|
|
|
+
|
|
|
+ if((nRet = _ProcessCmdLineArgs(&cla)) != 0)
|
|
|
+ {
|
|
|
+ if(nRet > 0)
|
|
|
+ {
|
|
|
+ _DisplayHelp();
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ TRACE0("Error: %s!\n", _StrError(nRet));
|
|
|
+ return nRet;
|
|
|
+ }
|
|
|
+
|
|
|
+ g_nVerbosity = cla.nVerbosity;
|
|
|
+
|
|
|
+ /////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+ do
|
|
|
+ {
|
|
|
+ GFA_BLM_CFG_PARAMS blmcp;
|
|
|
+ memset(&blmcp, 0, sizeof(blmcp));
|
|
|
+
|
|
|
+ if(GfaSerialGetDeviceInterface(&blmcp.mmcp.devcfg.itf))
|
|
|
+ {
|
|
|
+ GFA_BLM_EXEC_CONTEXT ctx;
|
|
|
+ GFA_SER_CFG_PARAMS scp;
|
|
|
+ memset(&scp, 0, sizeof(scp));
|
|
|
+
|
|
|
+ /////////////////////////////////////////////////////////////////
|
|
|
+ // serial device configuration
|
|
|
+
|
|
|
+ scp.baud = _DEFAULT_BAUDRATE; // start with default baudrate
|
|
|
+ scp.data = 8;
|
|
|
+ scp.stop = 1;
|
|
|
+ scp.parity = 'N';
|
|
|
+#ifdef _TARGET_BUILD
|
|
|
+ scp.bHandleTxEcho = true;
|
|
|
+#endif // _TARGET_BUILD
|
|
|
+
|
|
|
+ /////////////////////////////////////////////////////////////////
|
|
|
+ // mininet device configuration
|
|
|
+
|
|
|
+ blmcp.mmcp.devcfg.pszDeviceName = cla.pszDevName;
|
|
|
+ blmcp.mmcp.devcfg.pDevParams = &scp;
|
|
|
+ blmcp.mmcp.devcfg.nSizeDevParams = sizeof(scp);
|
|
|
+
|
|
|
+ /////////////////////////////////////////////////////////////////
|
|
|
+ // bootloader master configuration
|
|
|
+
|
|
|
+// blmcp.pfnBuCmdDownloadStatus = _BuCmdDownloadStatus;
|
|
|
+// blmcp.pfnBuCmdSendDataStatus = _BuCmdSendDataStatus;
|
|
|
+
|
|
|
+ /////////////////////////////////////////////////////////////////
|
|
|
+ // open a bootloader master instance
|
|
|
+
|
|
|
+ TRACE3("\nOpening bootloader master.\n");
|
|
|
+
|
|
|
+ if((hBlm = GfaBlmOpen(&blmcp)))
|
|
|
+ {
|
|
|
+ GfaBlmSetVerbosity(hBlm, cla.nVerbosity);
|
|
|
+
|
|
|
+ TRACE3("Initializing slave index.\n");
|
|
|
+
|
|
|
+ if((nRet = GfaBlmResetSlaveIndex(hBlm, cla.nNodeAddr)) != 0)
|
|
|
+ {
|
|
|
+ TRACE1("%s!\n", _StrError(errno));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ TRACE3("Detecting running image.\n");
|
|
|
+
|
|
|
+ if((ctx = GfaBlmGetExecutionContext(hBlm, cla.nNodeAddr)) == GfaBlmCtx_Err)
|
|
|
+ {
|
|
|
+ TRACE1("%s!\n", _StrError(errno));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ TRACE3("Currently running: %s.\n", (ctx == GfaBlmCtx_App) ? "Application" : "Bootloader");
|
|
|
+
|
|
|
+ if(ctx == GfaBlmCtx_App)
|
|
|
+ {
|
|
|
+ TRACE3("Starting bootloader.\n");
|
|
|
+
|
|
|
+ if((nRet = GfaBlmBootloaderExecute(hBlm, cla.nNodeAddr, NULL, 1000)) != 0)
|
|
|
+ {
|
|
|
+ TRACE1("%s!\n", _StrError(errno));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(cla.nBaudrate != _DEFAULT_BAUDRATE)
|
|
|
+ {
|
|
|
+ TRACE3("Setting baudrate to %u.\n", cla.nBaudrate);
|
|
|
+
|
|
|
+ if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, cla.nNodeAddr, cla.nBaudrate)) != 0)
|
|
|
+ {
|
|
|
+ TRACE1("%s!\n", _StrError(errno));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(cla.bShowImgInfo)
|
|
|
+ {
|
|
|
+ GFA_BL_APP_IMG_INFO aii;
|
|
|
+
|
|
|
+ TRACE3("Getting image information.\n");
|
|
|
+
|
|
|
+ if((nRet = GfaBlmGetInfoBI(hBlm, cla.nNodeAddr, &aii)) == 0)
|
|
|
+ {
|
|
|
+ _TraceImageInfo("Bootloader", &aii.bl);
|
|
|
+ _TraceImageInfo("Application", &aii.app);
|
|
|
+ }
|
|
|
+ else if((nRet = GfaBlmGetInfoBD(hBlm, cla.nNodeAddr, &aii)) > -2)
|
|
|
+ {
|
|
|
+ _TraceImageInfo("Bootloader", &aii.bl);
|
|
|
+ _TraceImageInfo("Application", &aii.app);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(cla.bShowMatSer)
|
|
|
+ {
|
|
|
+ char szMaterial[16], szSerial[16];
|
|
|
+
|
|
|
+ TRACE3("Reading material and serial number.\n");
|
|
|
+
|
|
|
+ if((nRet = GfaBlmReadMaterialAndSerialID(hBlm, cla.nNodeAddr, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) != 0)
|
|
|
+ {
|
|
|
+ TRACE1("%s!\n", _StrError(errno));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ TRACE2("Material and Serial number:\n");
|
|
|
+ TRACE2(" Mat.Nr.: %s\n", szMaterial);
|
|
|
+ TRACE2(" Serial: %s\n", szSerial);
|
|
|
+ }
|
|
|
+
|
|
|
+ TRACE3("Resetting slave.\n");
|
|
|
+
|
|
|
+ if((nRet = GfaBlmBUCmdReset(hBlm, cla.nNodeAddr, 1000)) != 0)
|
|
|
+ {
|
|
|
+ TRACE1("%s!\n", _StrError(errno));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TRACE1("%s!\n", _StrError(errno));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TRACE1("%s!\n", _StrError(errno));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ while(false);
|
|
|
+
|
|
|
+ if(hBlm)
|
|
|
+ {
|
|
|
+ TRACE3("Closing bootloader master.\n\n");
|
|
|
+ GfaBlmClose(hBlm);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|