Rind 5 anos atrás
pai
commit
fde6dc3353
12 arquivos alterados com 1484 adições e 255 exclusões
  1. 1 0
      .gitignore
  2. 666 0
      cmdopt.c
  3. 91 0
      cmdopt.h
  4. 47 0
      error.c
  5. 45 0
      error.h
  6. 10 2
      gfativaflashutil.pro
  7. 306 0
      image.c
  8. 33 0
      image.h
  9. 165 231
      main.c
  10. 1 22
      main.h
  11. 82 0
      output.c
  12. 37 0
      output.h

+ 1 - 0
.gitignore

@@ -8,5 +8,6 @@
 Debug/
 Profile/
 Release/
+install/
 *.pro.user
 *.bak

+ 666 - 0
cmdopt.c

@@ -0,0 +1,666 @@
+#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 <unistd.h>
+#include <stddef.h>
+#include <time.h>
+#include <errno.h>
+#include <getopt.h>
+#include <gfaserial.h>
+#include <gfabootlmast.h>
+#include "main.h"
+#include "cmdopt.h"
+#include "error.h"
+#include "output.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define _IS_POWER_OF_2(x)						(!!(x) && !((x) & ((x) - 1)))
+#define _IS_VALID_STATION_NUMBER(s)				(((s) > 0) && ((s) <= 99))
+#define _IS_VALID_BLOCK_SIZE(s)					(((s) >= CMD_OPT_MIN_SEND_BLOCK_SIZE) && ((s) <= CMD_OPT_MAX_SEND_BLOCK_SIZE) && !((s) & 0x03))
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define _OV_HAS_UPLOAD_IMG						((uint32_t)0x00000001)
+#define _OV_HAS_SHOW_FILE_IMG_INFO				((uint32_t)0x00000002)
+#define _OV_HAS_SHOW_DEV_IMG_INFO				((uint32_t)0x00000004)
+#define _OV_HAS_VALIDATE_IMG					((uint32_t)0x00000008)
+#define _OV_HAS_SHOW_MAT_SER					((uint32_t)0x00000010)
+#define _OV_HAS_SET_MAT_SER						((uint32_t)0x00000020)
+#define _OV_HAS_BOOT_PING						((uint32_t)0x00000040)
+
+#define _OV_HAS_IMG_FILE						((uint32_t)0x00001000)
+#define _OV_HAS_ITF_NAME						((uint32_t)0x00002000)
+#define _OV_HAS_BLOCK_SIZE						((uint32_t)0x00004000)
+#define _OV_HAS_APP_ADDR						((uint32_t)0x00008000)
+#define _OV_HAS_BAUD_RATE						((uint32_t)0x00010000)
+#define _OV_HAS_STATION_NUMBER					((uint32_t)0x00020000)
+#define _OV_HAS_NODE_ADDR						((uint32_t)0x00040000)
+#define _OV_HAS_SLAVE_ADDR						((uint32_t)0x00080000)
+#define _OV_HAS_SET_MATERIAL					((uint32_t)0x00100000)
+#define _OV_HAS_SET_SERIAL						((uint32_t)0x00200000)
+#define _OV_HAS_PING_INTERVAL					((uint32_t)0x00400000)
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define _OV_CMD_MASK							((uint32_t)0x00000FFF)
+#define _OV_OPT_MASK							(~_OV_CMD_MASK)
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define _REQ_CONNECTION_OPTS					(_OV_HAS_ITF_NAME | _OV_HAS_SLAVE_ADDR)
+
+#define _REQ_OPTS_UPLOAD_IMG					(_OV_HAS_IMG_FILE | _OV_HAS_APP_ADDR | _REQ_CONNECTION_OPTS)
+#define _REQ_OPTS_SHOW_IMG_INFO_OFFLINE			_OV_HAS_IMG_FILE
+#define _REQ_OPTS_SHOW_IMG_INFO_ONLINE			_REQ_CONNECTION_OPTS
+#define _REQ_OPTS_VALIDATE_IMG					(_OV_HAS_IMG_FILE | _OV_HAS_APP_ADDR | _REQ_CONNECTION_OPTS)
+#define _REQ_OPTS_SHOW_MAT_SER					_REQ_CONNECTION_OPTS
+#define _REQ_OPTS_SET_MAT_SER					_REQ_CONNECTION_OPTS
+#define _REQ_OPTS_BOOT_PING						_REQ_CONNECTION_OPTS
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define _OPT_CONNECTION_OPTS					(_OV_HAS_BAUD_RATE | _OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR)
+
+#define _OPT_OPTS_UPLOAD_IMG					(_OV_HAS_IMG_FILE | _OV_HAS_APP_ADDR | _OPT_CONNECTION_OPTS)
+#define _OPT_OPTS_SHOW_IMG_INFO_OFFLINE			_OV_HAS_SLAVE_ADDR
+#define _OPT_OPTS_SHOW_IMG_INFO_ONLINE			_OPT_CONNECTION_OPTS
+#define _OPT_OPTS_VALIDATE_IMG					_OPT_CONNECTION_OPTS
+#define _OPT_OPTS_SHOW_MAT_SER					_OPT_CONNECTION_OPTS
+#define _OPT_OPTS_SET_MAT_SER					_OPT_CONNECTION_OPTS
+#define _OPT_OPTS_BOOT_PING						(_OPT_CONNECTION_OPTS | _OV_HAS_PING_INTERVAL)
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define _GET_OPTS(m)							((m) & _OV_OPT_MASK)
+#define _GET_CMD(m)								((m) & _OV_CMD_MASK)
+#define _HAS_CMD(m)								(!!_GET_CMD(m))
+#define _HAS_VALID_CMD(m)						(_HAS_CMD(m) && _IS_POWER_OF_2(_GET_CMD(m)))
+#define _IS_OFFLINE_CMD(m)						(_GET_CMD(m) == _OV_HAS_SHOW_FILE_IMG_INFO)
+#define _HAS_REQUIRED_OPTIONS(m, r)				((_GET_OPTS(m) & (r)) == (r))
+#define _GET_MISSING_OPTS(m, r)					((_GET_OPTS(m) ^ (r)) & (r))
+#define _GET_UNUSED_OPTS(m, r, o)				((_GET_OPTS(m) ^ (r)) & ~(o))
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define _OPT_STRING_UPLOAD_IMG					"upload-img"
+#define _OPT_STRING_VALIDATE_IMG				"validate-img"
+#define _OPT_STRING_SHOW_FILE_IMG_INFO			"show-file-img-info"
+#define _OPT_STRING_SHOW_DEV_IMG_INFO			"show-dev-img-info"
+#define _OPT_STRING_SHOW_MAT_SER				"show-mat-ser"
+#define _OPT_STRING_SET_MATERIAL				"set-material"
+#define _OPT_STRING_SET_SERIAL					"set-serial"
+#define _OPT_STRING_BOOT_PING					"boot-ping"
+#define _OPT_STRING_ITF_NAME					"itf-name"
+#define _OPT_STRING_BAUD_RATE					"baud-rate"
+#define _OPT_STRING_STATION_NUMBER				"stat-num"
+#define _OPT_STRING_NODE_ADDR					"node-addr"
+#define _OPT_STRING_SLAVE_ADDR					"stat-num or node-addr"
+#define _OPT_STRING_APP_BASE_ADDR				"app-addr"
+#define _OPT_STRING_BLOCK_SIZE					"block-size"
+#define _OPT_STRING_PING_INTERVAL				"ping-int"
+#define _OPT_STRING_VERBOSITY					"verbosity"
+#define _OPT_STRING_HELP						"help"
+#define _OPT_STRING_IMG_FILE					"<IMG FILE>"
+
+#define _MAX_CMD_LENGTH							18
+#define _MAX_OPT_LENGTH							10
+
+/////////////////////////////////////////////////////////////////////////////
+
+int g_nVerbosity = CMD_OPT_DEFAULT_VERBOSITY;
+
+/////////////////////////////////////////////////////////////////////////////
+
+static const uint8_t g_nodeTable[] =
+{
+	// 1 - 99
+	0x11,	0x12,	0x13,	0x14,	0x15,	0x16,	0x17,	0x18,	0x19,	0x1A,
+	0x21,	0x22,	0x23,	0x24,	0x25,	0x26,	0x27,	0x28,	0x29,	0x2A,
+	0x31,	0x32,	0x33,	0x34,	0x35,	0x36,	0x37,	0x38,	0x39,	0x3A,
+	0x41,	0x42,	0x43,	0x44,	0x45,	0x46,	0x47,	0x48,	0x49,	0x4A,
+	0x51,	0x52,	0x53,	0x54,	0x55,	0x56,	0x57,	0x58,	0x59,	0x5A,
+	0x61,	0x62,	0x63,	0x64,	0x65,	0x66,	0x67,	0x68,	0x69,	0x6A,
+	0x71,	0x72,	0x73,	0x74,	0x75,	0x76,	0x77,	0x78,	0x79,	0x7A,
+	0x81,	0x82,	0x83,	0x84,	0x85,	0x86,	0x87,	0x88,	0x89,	0x8A,
+	0x91,	0x92,	0x93,	0x94,	0x95,	0x96,	0x97,	0x98,	0x99,	0x9A,
+	0xA1,	0xA2,	0xA3,	0xA4,	0xA5,	0xA6,	0xA7,	0xA8,	0xA9
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+static const char* _GetOptName(uint32_t nOpt)
+{
+	switch(nOpt)
+	{
+	case _OV_HAS_UPLOAD_IMG:
+		return _OPT_STRING_UPLOAD_IMG;
+	case _OV_HAS_VALIDATE_IMG:
+		return _OPT_STRING_VALIDATE_IMG;
+	case _OV_HAS_SHOW_FILE_IMG_INFO:
+		return _OPT_STRING_SHOW_FILE_IMG_INFO;
+	case _OV_HAS_SHOW_DEV_IMG_INFO:
+		return _OPT_STRING_SHOW_DEV_IMG_INFO;
+	case _OV_HAS_SHOW_MAT_SER:
+		return _OPT_STRING_SHOW_MAT_SER;
+	case _OV_HAS_BOOT_PING:
+		return _OPT_STRING_BOOT_PING;
+	case _OV_HAS_PING_INTERVAL:
+		return _OPT_STRING_PING_INTERVAL;
+	case _OV_HAS_ITF_NAME:
+		return _OPT_STRING_ITF_NAME;
+	case _OV_HAS_BLOCK_SIZE:
+		return _OPT_STRING_BLOCK_SIZE;
+	case _OV_HAS_APP_ADDR:
+		return _OPT_STRING_APP_BASE_ADDR;
+	case _OV_HAS_BAUD_RATE:
+		return _OPT_STRING_BAUD_RATE;
+	case _OV_HAS_STATION_NUMBER:
+		return _OPT_STRING_STATION_NUMBER;
+	case _OV_HAS_NODE_ADDR:
+		return _OPT_STRING_NODE_ADDR;
+	case _OV_HAS_SLAVE_ADDR:
+		return _OPT_STRING_SLAVE_ADDR;
+	case _OV_HAS_SET_MATERIAL:
+		return _OPT_STRING_SET_MATERIAL;
+	case _OV_HAS_SET_SERIAL:
+		return _OPT_STRING_SET_SERIAL;
+	case _OV_HAS_IMG_FILE:
+		return _OPT_STRING_IMG_FILE;
+	default:
+		return NULL;
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+const char* GfaTfuCmdOpt2String(uint32_t nOpts)
+{
+	static char szOptStr[600];
+
+	if(nOpts)
+	{
+		int nCount = 0;
+		uint32_t nMask = 1;
+		memset(szOptStr, '\0', sizeof(szOptStr));
+		
+		while(nMask)
+		{
+			if(nOpts & nMask)
+			{
+				const char *pszOptName = _GetOptName(nMask);
+				if(pszOptName)
+				{
+					if(nCount++)
+						strcat(szOptStr, ", ");
+					strcat(szOptStr, pszOptName);
+				}
+			}
+			
+			nMask <<= 1;
+		}
+		
+		return szOptStr;
+	}
+	
+	return "";
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static const struct option g_lo[] =
+{
+	{
+		_OPT_STRING_UPLOAD_IMG,
+		no_argument,
+		NULL,
+		ov_upload_img
+	},
+	{
+		_OPT_STRING_VALIDATE_IMG,
+		no_argument,
+		NULL,
+		ov_validate_img
+	},
+	{
+		_OPT_STRING_SHOW_FILE_IMG_INFO,
+		no_argument,
+		NULL,
+		ov_show_file_img_info
+	},
+	{
+		_OPT_STRING_SHOW_DEV_IMG_INFO,
+		no_argument,
+		NULL,
+		ov_show_dev_img_info
+	},
+	{
+		_OPT_STRING_SHOW_MAT_SER,
+		no_argument,
+		NULL,
+		ov_show_mat_ser
+	},
+	{
+		_OPT_STRING_SET_MATERIAL,
+		optional_argument,
+		NULL,
+		ov_set_material
+	},
+	{
+		_OPT_STRING_SET_SERIAL,
+		optional_argument,
+		NULL,
+		ov_set_serial
+	},
+	{
+		_OPT_STRING_BOOT_PING,
+		no_argument,
+		NULL,
+		ov_boot_ping
+	},
+	{
+		_OPT_STRING_PING_INTERVAL,
+		required_argument,
+		NULL,
+		ov_ping_interval
+	},
+	{
+		_OPT_STRING_ITF_NAME,
+		required_argument,
+		NULL,
+		ov_itf_name
+	},
+	{
+		_OPT_STRING_BAUD_RATE,
+		required_argument,
+		NULL,
+		ov_baud_rate
+	},
+	{
+		_OPT_STRING_STATION_NUMBER,
+		required_argument,
+		NULL,
+		ov_station_number
+	},
+	{
+		_OPT_STRING_NODE_ADDR,
+		required_argument,
+		NULL,
+		ov_node_addr
+	},
+	{
+		_OPT_STRING_APP_BASE_ADDR,
+		required_argument,
+		NULL,
+		ov_app_addr
+	},
+	{
+		_OPT_STRING_BLOCK_SIZE,
+		required_argument,
+		NULL,
+		ov_block_size
+	},
+	{
+		_OPT_STRING_VERBOSITY,
+		required_argument,
+		NULL,
+		ov_verbosity
+	},
+	{
+		_OPT_STRING_HELP,
+		no_argument,
+		NULL,
+		ov_help
+	},
+	{
+		NULL,
+		0,
+		NULL,
+		0
+	}
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+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;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaTfuCmdOptInitOpts(LPCMD_LINE_ARGS pcla)
+{
+	memset(pcla, 0, sizeof(CMD_LINE_ARGS));
+	pcla->nBaudrate		= CMD_OPT_DEFAULT_BAUDRATE;
+	pcla->nVerbosity	= CMD_OPT_DEFAULT_VERBOSITY;
+	pcla->nBlockSize	= CMD_OPT_DEFAULT_SEND_BLOCK_SIZE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaTfuCmdOptParse(int argc, char* argv[], LPCMD_LINE_ARGS pcla)
+{
+	int opt, nCount = 0;
+	pcla->nOptFlags = 0;
+
+	while((opt = getopt_long(argc, argv, "-a:b:v:n:s:i:?", g_lo, NULL)) != -1)
+	{
+		const char *arg = optarg;
+
+		switch(opt)
+		{
+		case ov_img_file:
+			if(arg)
+			{
+				pcla->pszImgFile = arg;
+				pcla->nOptFlags |= _OV_HAS_IMG_FILE;
+			}
+			break;
+		case ov_itf_name:
+			if(arg)
+			{
+				pcla->pszDevName = arg;
+				pcla->nOptFlags |= _OV_HAS_ITF_NAME;
+			}
+			break;
+		case ov_show_dev_img_info:
+			pcla->bShowDevImgInfo = true;
+			pcla->nOptFlags |= _OV_HAS_SHOW_DEV_IMG_INFO;
+			break;
+		case ov_show_file_img_info:
+			pcla->bShowFileImgInfo = true;
+			pcla->nOptFlags |= _OV_HAS_SHOW_FILE_IMG_INFO;
+			break;
+		case ov_show_mat_ser:
+			pcla->bShowMatSer = true;
+			pcla->nOptFlags |= _OV_HAS_SHOW_MAT_SER;
+			break;
+		case ov_validate_img:
+			pcla->bValidateImg = true;
+			pcla->nOptFlags |= _OV_HAS_VALIDATE_IMG;
+			break;
+		case ov_upload_img:
+			pcla->bUploadImg = true;
+			pcla->nOptFlags |= _OV_HAS_UPLOAD_IMG;
+			break;
+		case ov_boot_ping:
+			pcla->bPing = true;
+			pcla->nOptFlags |= _OV_HAS_BOOT_PING;
+			break;
+		case ov_ping_interval:
+			pcla->nPingIntervalSec = (int32_t)_ArgStr2Num(arg, 0);
+			if(pcla->nPingIntervalSec > 0)
+				pcla->nOptFlags |= _OV_HAS_PING_INTERVAL;
+			break;
+		case ov_set_material:
+			if(arg)
+			{
+				pcla->pszMaterial = arg;
+				pcla->nOptFlags |= _OV_HAS_SET_MATERIAL;
+				if(pcla->nOptFlags & _OV_HAS_SET_SERIAL)
+					pcla->nOptFlags |= _OV_HAS_SET_MAT_SER;
+			}
+			break;
+		case ov_set_serial:
+			if(arg)
+			{
+				pcla->pszSerial = arg;
+				pcla->nOptFlags |= _OV_HAS_SET_SERIAL;
+				if(pcla->nOptFlags & _OV_HAS_SET_MATERIAL)
+					pcla->nOptFlags |= _OV_HAS_SET_MAT_SER;
+			}
+			break;
+		case ov_block_size:
+			pcla->nBlockSize = (uint32_t)_ArgStr2Num(arg, CMD_OPT_DEFAULT_SEND_BLOCK_SIZE);
+			pcla->nOptFlags |= _OV_HAS_BLOCK_SIZE;
+			break;
+		case ov_app_addr:
+			pcla->nStartAddr = (uint32_t)_ArgStr2Num(arg, (uint32_t)-1);
+			pcla->nOptFlags |= _OV_HAS_APP_ADDR;
+			break;
+		case ov_baud_rate:
+			pcla->nBaudrate = (uint32_t)_ArgStr2Num(arg, CMD_OPT_DEFAULT_BAUDRATE);
+			pcla->nOptFlags |= _OV_HAS_BAUD_RATE;
+			break;
+		case ov_station_number:
+			pcla->nStationNr = (uint8_t)_ArgStr2Num(arg, 0);
+			pcla->nOptFlags |= _OV_HAS_STATION_NUMBER;
+			pcla->nOptFlags |= _OV_HAS_SLAVE_ADDR;
+			break;
+		case ov_node_addr:
+			pcla->nNodeAddr = (uint8_t)_ArgStr2Num(arg, 0);
+			pcla->nOptFlags |= _OV_HAS_NODE_ADDR;
+			pcla->nOptFlags |= _OV_HAS_SLAVE_ADDR;
+			break;
+		case ov_verbosity:
+			pcla->nVerbosity = (int)_ArgStr2Num(arg, CMD_OPT_DEFAULT_VERBOSITY);
+			break;
+		case ov_help:
+			pcla->bShowHelp = true;
+			break;
+		}
+
+		++nCount;
+	}
+
+	if(nCount == 0)
+		pcla->bShowHelp = true;
+
+	return nCount;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaTfuCmdOptProcess(LPCMD_LINE_ARGS pcla)
+{
+	/////////////////////////////////////////////////////////////////////////
+	// If help is requested, do nothing else
+
+	if(pcla->bShowHelp)
+		return 1;
+
+	/////////////////////////////////////////////////////////////////////////
+	// adjust verbosity
+
+	if(pcla->nVerbosity < CMD_OPT_MIN_VERBOSITY)
+		pcla->nVerbosity = CMD_OPT_MIN_VERBOSITY;
+	else if(pcla->nVerbosity > CMD_OPT_MAX_VERBOSITY)
+		pcla->nVerbosity = CMD_OPT_MAX_VERBOSITY;
+	g_nVerbosity = pcla->nVerbosity;
+
+	/////////////////////////////////////////////////////////////////////////
+	// validate commands
+
+	pcla->nCmdFlags = _GET_CMD(pcla->nOptFlags);
+	if(!_HAS_CMD(pcla->nOptFlags))
+	{
+		if(!(pcla->nOptFlags & (_OV_HAS_SET_MATERIAL | _OV_HAS_SET_SERIAL)))
+			return GFA_FU_ERROR_NOTHING_TO_DO;
+	}
+	else if(!_HAS_VALID_CMD(pcla->nOptFlags))
+		return GFA_FU_ERROR_MULTIPLE_COMMANDS;
+
+	/////////////////////////////////////////////////////////////////////////
+	// validate connection options if required
+
+	if(!_IS_OFFLINE_CMD(pcla->nOptFlags))
+	{
+		if(!GfaSerialIsValidBaudrate(pcla->nBaudrate))
+			return GFA_FU_ERROR_INVALID_BAUDRATE;
+		else if((pcla->nOptFlags & (_OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR)) == (_OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR))
+			return GFA_FU_ERROR_NODE_STATION_MUTEX;
+		else if(pcla->nOptFlags & _OV_HAS_STATION_NUMBER)
+		{
+			if(!_IS_VALID_STATION_NUMBER(pcla->nStationNr))
+				return GFA_FU_ERROR_INVALID_STATION_NUM;
+			pcla->nNodeAddr = g_nodeTable[pcla->nStationNr - 1];
+		}
+		else if((pcla->nOptFlags & _OV_HAS_NODE_ADDR) && (NODE_IS_MULTICAST(pcla->nNodeAddr) || (pcla->nNodeAddr < MINET_MIN_NODE_ADDRESS)))
+			return GFA_FU_ERROR_INVALID_NODE_ADDR;
+	}
+
+	/////////////////////////////////////////////////////////////////////////
+	// validate command options
+
+	switch(pcla->nCmdFlags)
+	{
+	case _OV_HAS_UPLOAD_IMG:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_UPLOAD_IMG))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_UPLOAD_IMG);
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		else if((pcla->nOptFlags & _OV_HAS_BLOCK_SIZE) && !_IS_VALID_BLOCK_SIZE(pcla->nBlockSize))
+			return GFA_FU_ERROR_INVALID_BLOCK_SIZE;
+		else if(pcla->nStartAddr == (uint32_t)-1)
+			return GFA_FU_ERROR_INVALID_APP_START_ADDR;
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_UPLOAD_IMG, _OPT_OPTS_UPLOAD_IMG);
+		pcla->bNeedImgFile = true;
+		break;
+	case _OV_HAS_SHOW_FILE_IMG_INFO:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_SHOW_IMG_INFO_OFFLINE))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_SHOW_IMG_INFO_OFFLINE);
+			pcla->bIsOffline = true;
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_SHOW_IMG_INFO_OFFLINE, _OPT_OPTS_SHOW_IMG_INFO_OFFLINE);
+		pcla->bNeedImgFile = true;
+		break;
+	case _OV_HAS_SHOW_DEV_IMG_INFO:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_SHOW_IMG_INFO_ONLINE))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_SHOW_IMG_INFO_ONLINE);
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_SHOW_IMG_INFO_ONLINE, _OPT_OPTS_SHOW_IMG_INFO_ONLINE);
+		break;
+	case _OV_HAS_VALIDATE_IMG:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_VALIDATE_IMG))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_VALIDATE_IMG);
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_VALIDATE_IMG, _OPT_OPTS_VALIDATE_IMG);
+		pcla->bNeedImgFile = true;
+		break;
+	case _OV_HAS_SHOW_MAT_SER:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_SHOW_MAT_SER))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_SHOW_MAT_SER);
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_SHOW_MAT_SER, _OPT_OPTS_SHOW_MAT_SER);
+		break;
+	case _OV_HAS_SET_MAT_SER:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_SET_MAT_SER))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_SET_MAT_SER);
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_SET_MAT_SER, _OPT_OPTS_SET_MAT_SER);
+		break;
+	case _OV_HAS_BOOT_PING:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_BOOT_PING))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_BOOT_PING);
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		else if(pcla->nPingIntervalSec < 0)
+			return GFA_FU_ERROR_INVALID_COMMAND_OPT;
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_BOOT_PING, _OPT_OPTS_BOOT_PING);
+		break;
+	default:
+		if(pcla->nOptFlags & (_OV_HAS_SET_MATERIAL | _OV_HAS_SET_SERIAL))
+			return GFA_FU_ERROR_MAT_OR_SER_MISSING;
+		return 1;
+	}
+
+	return 0;
+}
+
+#if 0
+static void _PrintOptionLine(const char *pszOpt, int nMaxOptLen, char cShortOpt, const char *pszDesc)
+{
+	char szOptBuf[256];
+}
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// Examples:
+//
+// ./gfativaflashutil --upload-img --itf-name="/dev/ttyO4" --baud-rate=115200 --app-addr=0x2000 --stat-num=1 "/opt/GfA/gfativaflashutil/OLS-1V1_0009_crc.bin"
+// ./gfativaflashutil --validate-img --itf-name="/dev/ttyO4" --app-addr=0x2000 --node-addr=0x11 "/opt/GfA/gfativaflashutil/OLS-1V1_0009_crc.bin"
+// ./gfativaflashutil --show-mat-ser --itf-name="/dev/ttyO4" --stat-num=1
+// ./gfativaflashutil --set-material="" --set-serial="" --itf-name="/dev/ttyO4" --baud-rate=115200 --node-addr=0x11
+// ./gfativaflashutil --show-file-img-info "/opt/GfA/gfativaflashutil/OLS-1V1_0009_crc.bin"
+// ./gfativaflashutil --show-dev-img-info --itf-name="/dev/ttyO4" --baud-rate=115200 --node-addr=0x11
+// ./gfativaflashutil --boot-ping --ping-int=2 --itf-name="/dev/ttyO4" --baud-rate=115200 --node-addr=0x11 --stat-num=1
+//
+
+void GfaTfuCmdOptDisplayHelp(void)
+{
+	printf("gfativaflashutil v%d.%d GfA GmbH (%s %s)\n\n", GFA_FU_VER_MAJOR, GFA_FU_VER_MINOR, __DATE__, __TIME__);
+	printf(" Usage: gfativaflashutil COMMAND [OPTIONS] [IMG FILE]\n\n");
+	printf(" COMMANDS (only one at a time can be executed):\n");
+	printf("  --%-*s   Upload <IMG FILE> to the device.\n", _MAX_CMD_LENGTH, _OPT_STRING_UPLOAD_IMG);
+	printf("  --%-*s   Validate <IMG FILE> with the device. (Attempts to\n", _MAX_CMD_LENGTH, _OPT_STRING_VALIDATE_IMG);
+	printf("    %-*s   match the material numbers as well).\n", _MAX_CMD_LENGTH, "");
+	printf("  --%-*s   Validate <IMG FILE> offline and display image\n", _MAX_CMD_LENGTH, _OPT_STRING_SHOW_FILE_IMG_INFO);
+	printf("    %-*s   information.\n", _MAX_CMD_LENGTH, "");
+	printf("  --%-*s   Display bootloader and (if available) application\n", _MAX_CMD_LENGTH, _OPT_STRING_SHOW_DEV_IMG_INFO);
+	printf("    %-*s   image information of the target device.\n", _MAX_CMD_LENGTH, "");
+	printf("  --%-*s   Display the material and serial number of the\n", _MAX_CMD_LENGTH, _OPT_STRING_SHOW_MAT_SER);
+	printf("    %-*s   target device.\n", _MAX_CMD_LENGTH, "");
+	printf("  --%-*s   Set the material number of the target device. This\n", _MAX_CMD_LENGTH, _OPT_STRING_SET_MATERIAL);
+	printf("    %-*s   command works only in combination with --%s.\n", _MAX_CMD_LENGTH, "", _OPT_STRING_SET_SERIAL);
+	printf("  --%-*s   Set the serial number of the target device. This\n", _MAX_CMD_LENGTH, _OPT_STRING_SET_SERIAL);
+	printf("    %-*s   command works only in combination with --%s.\n", _MAX_CMD_LENGTH, "", _OPT_STRING_SET_MATERIAL);
+	printf("  --%-*s   Ping the target device either once or continually\n", _MAX_CMD_LENGTH, _OPT_STRING_BOOT_PING);
+	printf("    %-*s   dependig on the parameter --%s.\n\n", _MAX_CMD_LENGTH, "", _OPT_STRING_PING_INTERVAL);
+	printf(" OPTIONS:\n");
+	printf("  --%-*s -d <INTERFACE>    The name of the communication interface.\n", _MAX_OPT_LENGTH, _OPT_STRING_ITF_NAME);
+	printf("  --%-*s -s <STATION NUM>  Station number. Will be mapped internally\n", _MAX_OPT_LENGTH, _OPT_STRING_STATION_NUMBER);
+	printf("    %-*s                   to a node address. Must not be used in\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                   combination with --%s.\n", _MAX_OPT_LENGTH, "", _OPT_STRING_NODE_ADDR);
+	printf("  --%-*s -n <NODE ADDR>    The target's node address. Must not be used\n", _MAX_OPT_LENGTH, _OPT_STRING_NODE_ADDR);
+	printf("    %-*s                   in combination with --%s.\n", _MAX_OPT_LENGTH, "", _OPT_STRING_STATION_NUMBER);
+	printf("  --%-*s -b <BAUDRATE>     Baud-rate to use for some (but not all)\n", _MAX_OPT_LENGTH, _OPT_STRING_BAUD_RATE);
+	printf("    %-*s                   commands. Because a baud-rate switch\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                   involves data transfer as well, it will\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                   only be used with commands that require big\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                   amounts of data to be transferred!\n", _MAX_OPT_LENGTH, "");
+	printf("  --%-*s -a <BASE ADDR>    Flash address where to load <IMG FILE>.\n", _MAX_OPT_LENGTH, _OPT_STRING_APP_BASE_ADDR);
+	printf("  --%-*s -p <BLOCK SIZE>   Size of an upload-block (4-76, must be a\n", _MAX_OPT_LENGTH, _OPT_STRING_BLOCK_SIZE);
+	printf("    %-*s                   multiple of 4!). This option is only used\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                   with the --%s command. Defaults to %d.\n", _MAX_OPT_LENGTH, "", _OPT_STRING_UPLOAD_IMG, CMD_OPT_DEFAULT_SEND_BLOCK_SIZE);
+	printf("  --%-*s -i <SECONDS>      The optional ping interval in seconds. If a\n", _MAX_OPT_LENGTH, _OPT_STRING_PING_INTERVAL);
+	printf("    %-*s                   value greater than 0 is provided, a ping will\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                   be made every <SECONDS> seconds. If the value\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                   is 0 (the default), only one ping will be\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                   executed before the application exits.\n", _MAX_OPT_LENGTH, "");
+	printf("  --%-*s -v <0-4>          Verbosity. 0 = quiet, 1 = error, 2 = info,\n", _MAX_OPT_LENGTH, _OPT_STRING_VERBOSITY);
+	printf("    %-*s                   3 = status, 4 = debug.\n", _MAX_OPT_LENGTH, "");
+	printf("  --%-*s -?                Show this help\n", _MAX_OPT_LENGTH, _OPT_STRING_HELP);
+	printf("\n");
+}
+
+/*
+	printf("    %-*s   \n", _MAX_CMD_LENGTH, "");
+	printf("    %-*s   \n", _MAX_OPT_LENGTH, "");
+*/

+ 91 - 0
cmdopt.h

@@ -0,0 +1,91 @@
+// cmdopt.h :
+//
+
+#if !defined(AGD_CMDOPT_H__7551B3DB_D0BF_4746_A615_1BD0DC828D23__INCLUDED_)
+#define AGD_CMDOPT_H__7551B3DB_D0BF_4746_A615_1BD0DC828D23__INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// cmdopt.h - Declarations:
+// http://man7.org/linux/man-pages/man3/getopt.3.html
+
+#define CMD_OPT_MIN_VERBOSITY						0
+#define CMD_OPT_MAX_VERBOSITY						4
+#define CMD_OPT_DEFAULT_VERBOSITY					2
+#define CMD_OPT_DEFAULT_BAUDRATE					19200
+#define CMD_OPT_MIN_SEND_BLOCK_SIZE					4
+#define CMD_OPT_MAX_SEND_BLOCK_SIZE					76
+#define CMD_OPT_DEFAULT_SEND_BLOCK_SIZE				CMD_OPT_MAX_SEND_BLOCK_SIZE
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef enum _OptValues
+{
+	ov_img_file			= 1,
+	ov_itf_name,
+	ov_show_dev_img_info,
+	ov_show_file_img_info,
+	ov_show_mat_ser,
+	ov_validate_img,
+	ov_upload_img,
+	ov_boot_ping,
+	ov_set_material,
+	ov_set_serial,
+	ov_block_size,
+	ov_ping_interval	= 'i',
+	ov_app_addr			= 'a',
+	ov_baud_rate		= 'b',
+	ov_station_number	= 's',
+	ov_node_addr		= 'n',
+	ov_verbosity		= 'v',
+	ov_help				= '?'
+}OptValues;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _CMD_LINE_ARGS
+{
+	uint8_t nNodeAddr;
+	uint8_t nStationNr;
+	bool bShowHelp;
+	bool bShowDevImgInfo;
+	bool bShowFileImgInfo;
+	bool bShowMatSer;
+	bool bSetMatSer;
+	bool bValidateImg;
+	bool bUploadImg;
+	bool bPing;
+	bool bIsOffline;
+	bool bNeedImgFile;
+	int32_t nPingIntervalSec;
+	uint32_t nBaudrate;
+	uint32_t nBlockSize;
+	uint32_t nStartAddr;
+	const char *pszDevName;
+	const char *pszImgFile;
+	const char *pszMaterial;
+	const char *pszSerial;
+	int nVerbosity;
+	uint32_t nOptFlags;
+	uint32_t nCmdFlags;
+	uint32_t nMissingOptFlags;
+	uint32_t nUnusedOptFlags;
+}CMD_LINE_ARGS, *LPCMD_LINE_ARGS;
+typedef const CMD_LINE_ARGS *LPCCMD_LINE_ARGS;
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaTfuCmdOptInitOpts(LPCMD_LINE_ARGS pcla);
+int GfaTfuCmdOptParse(int argc, char* argv[], LPCMD_LINE_ARGS pcla);
+int GfaTfuCmdOptProcess(LPCMD_LINE_ARGS pcla);
+const char* GfaTfuCmdOpt2String(uint32_t nOpts);
+void GfaTfuCmdOptDisplayHelp(void);
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_CMDOPT_H__7551B3DB_D0BF_4746_A615_1BD0DC828D23__INCLUDED_)

+ 47 - 0
error.c

@@ -0,0 +1,47 @@
+#include <gfabootlmast.h>
+#include "error.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+const char* GfaTfuStrError(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_INVALID_STATION_NUM:
+		return "Invalid station number";
+	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";
+	case GFA_FU_ERROR_NODE_STATION_MUTEX:
+		return "Either a node address or a station number may be provided";
+	case GFA_FU_ERROR_MAT_OR_SER_MISSING:
+		return "Both material and serial number must be provided";
+	case GFA_FU_ERROR_IMG_HEADER_NOT_FOUND:
+		return "Image file header not found";
+	case GFA_FU_ERROR_INVALID_IMG_SIZE:
+		return "Invalid image file size";
+	case GFA_FU_ERROR_INVALID_IMG_CRC32:
+		return "Invalid image CRC32";
+	case GFA_FU_ERROR_MATERIAL_NUM_NO_MATCH:
+		return "Image material number does not match EEPROM";
+	case GFA_FU_ERROR_MULTIPLE_COMMANDS:
+		return "Multiple commands not allowed";
+	case GFA_FU_ERROR_INVALID_COMMAND_OPT:
+		return "Invalid command option";
+	case GFA_FU_ERROR_MISSING_COMMAND_OPT:
+		return "Missing required option(s)";
+	case GFA_FU_ERROR_INVALID_APP_START_ADDR:
+		return "Invalid app start address";
+	default:
+		return GfaBlmStrError(nError);
+	}
+}

+ 45 - 0
error.h

@@ -0,0 +1,45 @@
+// error.h :
+//
+
+#if !defined(AGD_ERROR_H__B5B6949A_73B3_45C0_984A_805EF4135A19__INCLUDED_)
+#define AGD_ERROR_H__B5B6949A_73B3_45C0_984A_805EF4135A19__INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// error.h - Declarations:
+
+#define MAKE_GFA_FU_ERROR(c)					(0x81000000 | c)
+#define MAKE_GFA_IMG_ERROR(c)					(0x82000000 | c)
+
+#define GFA_FU_ERROR_INVALID_CMDLINE_ARG		MAKE_GFA_FU_ERROR(1)
+#define GFA_FU_ERROR_INVALID_BAUDRATE			MAKE_GFA_FU_ERROR(2)
+#define GFA_FU_ERROR_INVALID_NODE_ADDR			MAKE_GFA_FU_ERROR(3)
+#define GFA_FU_ERROR_INVALID_STATION_NUM		MAKE_GFA_FU_ERROR(4)
+#define GFA_FU_ERROR_INVALID_BLOCK_SIZE			MAKE_GFA_FU_ERROR(5)
+#define GFA_FU_ERROR_INVALID_DEVICE_NAME		MAKE_GFA_FU_ERROR(6)
+#define GFA_FU_ERROR_NODE_STATION_MUTEX			MAKE_GFA_FU_ERROR(7)
+#define GFA_FU_ERROR_MAT_OR_SER_MISSING			MAKE_GFA_FU_ERROR(8)
+#define GFA_FU_ERROR_MULTIPLE_COMMANDS			MAKE_GFA_FU_ERROR(9)
+#define GFA_FU_ERROR_INVALID_COMMAND_OPT		MAKE_GFA_FU_ERROR(10)
+#define GFA_FU_ERROR_MISSING_COMMAND_OPT		MAKE_GFA_FU_ERROR(11)
+#define GFA_FU_ERROR_INVALID_APP_START_ADDR		MAKE_GFA_FU_ERROR(12)
+
+#define GFA_FU_ERROR_NOTHING_TO_DO				MAKE_GFA_FU_ERROR(20)
+
+#define GFA_FU_ERROR_IMG_HEADER_NOT_FOUND		MAKE_GFA_IMG_ERROR(1)
+#define GFA_FU_ERROR_INVALID_IMG_SIZE			MAKE_GFA_IMG_ERROR(2)
+#define GFA_FU_ERROR_INVALID_IMG_CRC32			MAKE_GFA_IMG_ERROR(3)
+#define GFA_FU_ERROR_MATERIAL_NUM_NO_MATCH		MAKE_GFA_IMG_ERROR(4)
+
+/////////////////////////////////////////////////////////////////////////////
+
+const char* GfaTfuStrError(int nError);
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_ERROR_H__B5B6949A_73B3_45C0_984A_805EF4135A19__INCLUDED_)

+ 10 - 2
gfativaflashutil.pro

@@ -25,7 +25,15 @@ linux-buildroot-g++ {
 #QMAKE_INCDIR += ../ti
 #QMAKE_LIBDIR += $$OUT_PWD/../../../libmininet/Debug/Desktop_Qt_5_7_0_GCC_64bit
 
-SOURCES += main.c
+SOURCES += main.c \
+    image.c \
+    cmdopt.c \
+    error.c \
+    output.c
 
 HEADERS += \
-    main.h
+    main.h \
+    image.h \
+    cmdopt.h \
+    error.h \
+    output.h

+ 306 - 0
image.c

@@ -0,0 +1,306 @@
+#include <stdio.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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <gfaserial.h>
+#include <gfabootlmast.h>
+#include "main.h"
+#include "image.h"
+#include "error.h"
+#include "output.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _IMAGE_FILE
+{
+	void *p;
+	uint32_t nStartAddr;
+	struct stat stat;
+	GFA_IMG_INFO ii;
+	LPCGFA_APP_IMG_HEADER paih;
+}IMAGE_FILE, *LPIMAGE_FILE;
+typedef const IMAGE_FILE *LPCIMAGE_FILE;
+
+/////////////////////////////////////////////////////////////////////////////
+
+static uint32_t g_pdw32CRC32Table[] =
+{
+	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+	0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+	0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+	0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+	0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+	0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+	0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+	0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+	0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+	0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+	0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+	0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+	0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+	0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+	0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+	0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+	0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+	0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+	0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+static uint32_t _CalcCRC32(const void *pData, uint32_t nCbData, uint32_t dw32CRC)
+{
+    uint8_t ui8Char;
+    const uint8_t *pbData = (const uint8_t*)pData;
+
+    while(nCbData--)
+    {
+        ui8Char = *pbData++;
+        dw32CRC = (dw32CRC >> 8) ^ g_pdw32CRC32Table[(dw32CRC & 0xFF) ^ ui8Char];
+    }
+
+    return(dw32CRC);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static uint32_t _CalcImgCRC32(HIMGFILE hIf)
+{
+	LPIMAGE_FILE pIf = (LPIMAGE_FILE)hIf;
+
+	const void *pSection1 = pIf->p;
+	const void *pSection2 = pIf->paih->nReserved;
+	size_t nCbSection1 = (void*)&pIf->paih->nImgCRC32 - pSection1;
+	size_t nCbSection2 = pIf->stat.st_size - (nCbSection1 + 4);
+
+	uint32_t nCRC32 = 0xffffffff;
+	nCRC32 = _CalcCRC32(pSection1, nCbSection1, nCRC32);
+	nCRC32 = _CalcCRC32(pSection2, nCbSection2, nCRC32);
+	nCRC32 ^= 0xffffffff;
+	return nCRC32;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static bool _MatchWildcardStrings(const char *pszMatNumEEPROM, const char *pszMatNumImg, size_t nRequiredLength)
+{
+	size_t nLen = 0;
+	char cEEPROM, cImg;
+
+	while(*pszMatNumEEPROM)
+	{
+		cImg	= *pszMatNumImg++;
+		cEEPROM	= *pszMatNumEEPROM++;
+		if((cImg != cEEPROM) && (cImg != '*'))
+			return false;
+		++nLen;
+	}
+
+	return nLen == nRequiredLength;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+HIMGFILE GfaTfuImageFileOpen(const char *pszFilename, uint32_t nStartAddr, bool bReadOnly)
+{
+	struct stat stat;
+	int oflag = (bReadOnly ? O_RDONLY : O_RDWR) | O_EXCL;
+	int fd = open(pszFilename, oflag);
+
+	if(	(fd >= 0) &&
+		(fstat(fd, &stat) == 0))
+	{
+		int nErr;
+		int prot = bReadOnly ? PROT_READ : (PROT_READ | PROT_WRITE);
+		void *p = mmap(NULL, (size_t)stat.st_size, prot, MAP_PRIVATE, fd, 0);
+		nErr = errno;
+		close(fd);
+		errno = nErr;
+
+		if(p != MAP_FAILED)
+		{
+			LPIMAGE_FILE pIf = (LPIMAGE_FILE)malloc(sizeof(IMAGE_FILE));
+			memset(pIf, 0, sizeof(IMAGE_FILE));
+			pIf->p = p;
+			pIf->nStartAddr = nStartAddr;
+			memcpy(&pIf->stat, &stat, sizeof(struct stat));
+
+			if((pIf->paih = GfaTfuImageFileLookupImgInfo(pIf, &pIf->ii)))
+			{
+				if(pIf->ii.nImgLength != pIf->stat.st_size)
+					errno = GFA_FU_ERROR_INVALID_IMG_SIZE;
+				else if(_CalcImgCRC32(pIf) != pIf->paih->nImgCRC32)
+					errno = GFA_FU_ERROR_INVALID_IMG_CRC32;
+				else
+					return pIf;
+			}
+
+			nErr = errno;
+			GfaTfuImageFileClose(pIf);
+			errno = nErr;
+		}
+	}
+
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaTfuImageFileClose(HIMGFILE hIf)
+{
+	if(hIf)
+	{
+		LPIMAGE_FILE pIf = (LPIMAGE_FILE)hIf;
+		munmap(pIf->p, pIf->stat.st_size);
+		free(pIf);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+size_t GfaTfuImageFileGetSize(HIMGFILE hIf)
+{
+	if(hIf)
+	{
+		LPIMAGE_FILE pIf = (LPIMAGE_FILE)hIf;
+		return pIf->stat.st_size;
+	}
+
+	errno = EINVAL;
+	return (size_t)-1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void* GfaTfuImageFileGetData(HIMGFILE hIf)
+{
+	if(hIf)
+	{
+		LPIMAGE_FILE pIf = (LPIMAGE_FILE)hIf;
+		return pIf->p;
+	}
+
+	errno = EINVAL;
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaTfuImageFileGetInfo(HIMGFILE hIf, LPGFA_IMG_INFO pii)
+{
+	if(hIf && pii)
+	{
+		LPIMAGE_FILE pIf = (LPIMAGE_FILE)hIf;
+		memcpy(pii, &pIf->ii, sizeof(GFA_IMG_INFO));
+		return true;
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+LPCGFA_APP_IMG_HEADER GfaTfuImageFileLookupImgInfo(HIMGFILE hIf, LPGFA_IMG_INFO pii)
+{
+	if(hIf && pii)
+	{
+		int i;
+		LPIMAGE_FILE pIf	= (LPIMAGE_FILE)hIf;
+		uint32_t *pImg		= (uint32_t*)pIf->p;
+		size_t  nSize		= pIf->stat.st_size;
+
+		if(nSize > (257 * sizeof(uint32_t)))
+		{
+			errno = GFA_FU_ERROR_IMG_HEADER_NOT_FOUND;
+
+			for(i = 0; i < 257; ++i)
+			{
+				LPGFA_APP_IMG_HEADER paih = (LPGFA_APP_IMG_HEADER)pImg++;
+
+				if(	(paih->nPrefix0 == GFA_APP_IMG_HEADER_PREFIX_0) &&
+					(paih->nPrefix1 == GFA_APP_IMG_HEADER_PREFIX_1))
+				{
+					if((i * sizeof(uint32_t) + sizeof(GFA_APP_IMG_HEADER)) <= nSize)
+					{
+						ssize_t nOffsetMat = (size_t)paih->app.pszImgMaterialNum - pIf->nStartAddr;
+						ssize_t nOffsetBld = (size_t)paih->app.pszImgNameBuild   - pIf->nStartAddr;
+
+						if(	(nOffsetMat > 0) &&
+							(((size_t)nOffsetMat + GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH) <= nSize) &&
+							(nOffsetBld > 0) &&
+							(((size_t)nOffsetBld + GFA_APP_MAX_IMG_NAME_BUILD_LENGTH) <= nSize))
+						{
+							pii->nImgLength	= paih->nImgLength;
+							pii->nImgCRC32	= paih->nImgCRC32;
+							memcpy(pii->szImgMaterialNum, (const char*)pIf->p + nOffsetMat, GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH);
+							pii->szImgMaterialNum[GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH - 1] = '\0';
+							memcpy(pii->szImgNameBuild, (const char*)pIf->p + nOffsetBld, GFA_APP_MAX_IMG_NAME_BUILD_LENGTH);
+							pii->szImgNameBuild[GFA_APP_MAX_IMG_NAME_BUILD_LENGTH - 1] = '\0';
+							return paih;
+						}
+					}
+
+					errno = GFA_FU_ERROR_INVALID_IMG_SIZE;
+					break;
+				}
+			}
+		}
+		else
+		{
+			errno = GFA_FU_ERROR_INVALID_IMG_SIZE;
+		}
+
+		return NULL;
+	}
+
+	errno = EINVAL;
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaTfuImageFileMatchMaterialNum(HIMGFILE hIf, const char *pszMatNumEEPROM)
+{
+	if(hIf && pszMatNumEEPROM)
+	{
+		LPIMAGE_FILE pIf = (LPIMAGE_FILE)hIf;
+
+		if(!_MatchWildcardStrings(pszMatNumEEPROM, pIf->ii.szImgMaterialNum, GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH - 1))
+		{
+			errno = GFA_FU_ERROR_MATERIAL_NUM_NO_MATCH;
+			return false;
+		}
+
+		return true;
+	}
+
+	errno = EINVAL;
+	return false;
+}

+ 33 - 0
image.h

@@ -0,0 +1,33 @@
+// image.h :
+//
+
+#if !defined(AGD_IMAGE_H__25CFBDD3_F43A_4E40_B20D_6605E1211D4E__INCLUDED_)
+#define AGD_IMAGE_H__25CFBDD3_F43A_4E40_B20D_6605E1211D4E__INCLUDED_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// image.h - Declarations:
+
+typedef void										*HIMGFILE;
+
+/////////////////////////////////////////////////////////////////////////////
+
+HIMGFILE GfaTfuImageFileOpen(const char *pszFilename, uint32_t nStartAddr, bool bReadOnly);
+void GfaTfuImageFileClose(HIMGFILE hIf);
+size_t GfaTfuImageFileGetSize(HIMGFILE hIf);
+void* GfaTfuImageFileGetData(HIMGFILE hIf);
+bool GfaTfuImageFileGetInfo(HIMGFILE hIf, LPGFA_IMG_INFO pii);
+LPCGFA_APP_IMG_HEADER GfaTfuImageFileLookupImgInfo(HIMGFILE hIf, LPGFA_IMG_INFO pii);
+bool GfaTfuImageFileMatchMaterialNum(HIMGFILE hIf, const char *pszImgMaterialNum);
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_IMAGE_H__25CFBDD3_F43A_4E40_B20D_6605E1211D4E__INCLUDED_)

+ 165 - 231
main.c

@@ -6,7 +6,6 @@
 #include <limits.h>
 #include <string.h>
 #include <ctype.h>
-#include <byteswap.h>
 #include <unistd.h>
 #include <stddef.h>
 #include <time.h>
@@ -15,277 +14,165 @@
 #include <gfaserial.h>
 #include <gfabootlmast.h>
 #include "main.h"
+#include "cmdopt.h"
+#include "image.h"
+#include "error.h"
+#include "output.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
+static int _UploadImg(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 {
-	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;
+	UNUSED(hIf);
+	UNUSED(hBlm);
+	UNUSED(pcla);
+	UNUSED(ctx);
+	return 0;
+}
 
 /////////////////////////////////////////////////////////////////////////////
 
-static int g_nVerbosity = _DEFAULT_VERBOSITY;
+static int _ShowDevImgInfo(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
+{
+	int nRet;
+	GFA_BL_APP_IMG_INFO aii;
+	UNUSED(hIf);
 
-/////////////////////////////////////////////////////////////////////////////
+	TRACE3("Getting image information.\n");
 
-static const char* _StrError(int nError)
-{
-	switch(nError)
+    if((ctx == GfaBlmCtx_App) && ((nRet = GfaBlmGetInfoBI(hBlm, pcla->nNodeAddr, &aii)) == 0))
+    {
+    	GfaTfuDumpImageInfo("Bootloader", &aii.bl);
+    	GfaTfuDumpImageInfo("Application", &aii.app);
+    }
+    else
 	{
-	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);
-	}
-}
+        if(pcla->nBaudrate != CMD_OPT_DEFAULT_BAUDRATE)
+        {
+			TRACE3("Setting baudrate to %u.\n", pcla->nBaudrate);
 
-/////////////////////////////////////////////////////////////////////////////
+			if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, pcla->nNodeAddr, pcla->nBaudrate)) != 0)
+			{
+				TRACE1("%s!\n", GfaTfuStrError(errno));
+				return nRet;
+	        }
+        }
 
-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;
-}
+		if((nRet = GfaBlmGetInfoBD(hBlm, pcla->nNodeAddr, &aii)) > -2)
+		{
+	    	GfaTfuDumpImageInfo("Bootloader", &aii.bl);
+	    	GfaTfuDumpImageInfo("Application", &aii.app);
+	    }
 
-/////////////////////////////////////////////////////////////////////////////
+        if(pcla->nBaudrate != CMD_OPT_DEFAULT_BAUDRATE)
+        {
+			TRACE3("Setting baudrate to %u.\n", CMD_OPT_DEFAULT_BAUDRATE);
 
-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);
-	}
+			if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, pcla->nNodeAddr, CMD_OPT_DEFAULT_BAUDRATE)) != 0)
+			{
+				TRACE1("%s!\n", GfaTfuStrError(errno));
+				return nRet;
+	        }
+        }
+    }
+	return 0;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
-static int64_t _ArgStr2Num(const char *pszNum, int64_t nDefault)
+static int _ValidateImg(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 {
-	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;
+	UNUSED(hIf);
+	UNUSED(hBlm);
+	UNUSED(pcla);
+	UNUSED(ctx);
+	return 0;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
-static void _InitCmdLineArgs(LPCMD_LINE_ARGS pcla)
+static int _ShowMatSer(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 {
-	memset(pcla, 0, sizeof(CMD_LINE_ARGS));
-	pcla->nBaudrate		= _DEFAULT_BAUDRATE;
-	pcla->nVerbosity	= _DEFAULT_VERBOSITY;
-	pcla->nBlockSize	= _DEFAULT_SEND_BLOCK_SIZE;
-}
+	int nRet;
+	char szMaterial[16], szSerial[16];
+	UNUSED(hIf);
+	UNUSED(ctx);
 
-/////////////////////////////////////////////////////////////////////////////
-// 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;
+	TRACE3("Reading material and serial number.\n");
 
-	while((c = getopt(argc, argv, "-ib:v::n:sp:d:")) != -1)
+	if((nRet = GfaBlmReadMaterialAndSerialID(hBlm, pcla->nNodeAddr, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) != 0)
 	{
-		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;
+		TRACE1("%s!\n", GfaTfuStrError(errno));
+		return nRet;
 	}
-	
-	if(nCount == 0)
-		pcla->bShowHelp = true;
 
-	return nCount;
+	TRACE2("Material and Serial number:\n");
+	TRACE2("  Mat.Nr.: %s\n", szMaterial);
+	TRACE2("  Serial:  %s\n", szSerial);
+	return nRet;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
-static int _ProcessCmdLineArgs(LPCMD_LINE_ARGS pcla)
+static int _SetMatSer(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 {
-	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;
-
+	UNUSED(hIf);
+	UNUSED(hBlm);
+	UNUSED(pcla);
+	UNUSED(ctx);
 	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
+static int _Ping(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 {
+	UNUSED(hIf);
+	UNUSED(hBlm);
+	UNUSED(pcla);
+	UNUSED(ctx);
+	return 0;
 }
-#endif
 
-/////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 int main(int argc, char* argv[])
 {
 	int nRet;
+	HIMGFILE hIf = NULL;
 	HGFABLM hBlm = NULL;
 	CMD_LINE_ARGS cla;
 
 	/////////////////////////////////////////////////////////////////////////
 	// process command line
 
-	_InitCmdLineArgs(&cla);
-	nRet = _ParseCmdLineArgs(argc, argv, &cla);
-	
-	if((nRet = _ProcessCmdLineArgs(&cla)) != 0)
+	TRACE1("\n");
+
+	GfaTfuCmdOptInitOpts(&cla);
+	nRet = GfaTfuCmdOptParse(argc, argv, &cla);
+
+	if((nRet = GfaTfuCmdOptProcess(&cla)) != 0)
 	{
 		if(nRet > 0)
 		{
-			_DisplayHelp();
+			GfaTfuCmdOptDisplayHelp();
 			return 0;
 		}
+		else if(nRet == (int)GFA_FU_ERROR_MISSING_COMMAND_OPT)
+			TRACE0("Error: %s: %s!\n", GfaTfuStrError(nRet), GfaTfuCmdOpt2String(cla.nMissingOptFlags));
+		else if(nRet == (int)GFA_FU_ERROR_MULTIPLE_COMMANDS)
+			TRACE0("Error: %s: %s!\n", GfaTfuStrError(nRet), GfaTfuCmdOpt2String(cla.nCmdFlags));
+		else
+			TRACE0("Error: %s!\n", GfaTfuStrError(nRet));
 
-		TRACE0("Error: %s!\n", _StrError(nRet));
 		return nRet;
 	}
 
-	g_nVerbosity = cla.nVerbosity;
-	
+	if(cla.nUnusedOptFlags)
+	{
+		TRACE3("Warning: The following options are ignored: %s!\n", GfaTfuCmdOpt2String(cla.nUnusedOptFlags));
+	}
+
 	/////////////////////////////////////////////////////////////////////////
 
 	do
@@ -293,16 +180,36 @@ int main(int argc, char* argv[])
 		GFA_BLM_CFG_PARAMS blmcp;
 		memset(&blmcp, 0, sizeof(blmcp));
 
+		if(cla.bNeedImgFile)
+		{
+			TRACE3("Opening image file %s.\n", cla.pszImgFile);
+
+		    if(!(hIf = GfaTfuImageFileOpen(cla.pszImgFile, GFA_APP_APPLICATION_START_ADDRESS, true)))
+		    {
+				TRACE1("%s!\n", GfaTfuStrError(errno));
+				break;
+		    }
+		    
+		    if(cla.bShowFileImgInfo)
+		    {
+		    	GFA_IMG_INFO ii;
+		    	GfaTfuImageFileGetInfo(hIf, &ii);
+			    GfaTfuDumpImageInfo(cla.pszImgFile, &ii);
+			}
+			
+			if(cla.bIsOffline)
+				break;
+		}
+
 		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.baud			= CMD_OPT_DEFAULT_BAUDRATE; // start with default baudrate
 			scp.data			= 8;
 			scp.stop			= 1;
 			scp.parity			= 'N';
@@ -311,7 +218,7 @@ int main(int argc, char* argv[])
 #endif	//	_TARGET_BUILD
 
 			/////////////////////////////////////////////////////////////////
-			// mininet device configuration
+			// mininet master device configuration
 
 			blmcp.mmcp.devcfg.pszDeviceName		= cla.pszDevName;
 			blmcp.mmcp.devcfg.pDevParams		= &scp;
@@ -320,23 +227,25 @@ int main(int argc, char* argv[])
 			/////////////////////////////////////////////////////////////////
 			// bootloader master configuration
 
-//			blmcp.pfnBuCmdDownloadStatus		= _BuCmdDownloadStatus;
-//			blmcp.pfnBuCmdSendDataStatus		= _BuCmdSendDataStatus;
+			blmcp.pfnBuCmdDownloadStatus		= GfaTfuOnDownloadStatus;
+			blmcp.pfnBuCmdSendDataStatus		= GfaTfuOnSendDataStatus;
 
 			/////////////////////////////////////////////////////////////////
 			// open a bootloader master instance
 
-			TRACE3("\nOpening bootloader master.\n");
+			TRACE3("Opening bootloader master.\n");
 
 			if((hBlm = GfaBlmOpen(&blmcp)))
 			{
+				GFA_BLM_EXEC_CONTEXT ctx;
+
 				GfaBlmSetVerbosity(hBlm, cla.nVerbosity);
 
 				TRACE3("Initializing slave index.\n");
 
 				if((nRet = GfaBlmResetSlaveIndex(hBlm, cla.nNodeAddr)) != 0)
 		        {
-					TRACE1("%s!\n", _StrError(errno));
+					TRACE1("%s!\n", GfaTfuStrError(errno));
 					break;
 		        }
 
@@ -344,35 +253,49 @@ int main(int argc, char* argv[])
 
 		        if((ctx = GfaBlmGetExecutionContext(hBlm, cla.nNodeAddr)) == GfaBlmCtx_Err)
 		        {
-					TRACE1("%s!\n", _StrError(errno));
+					TRACE1("%s!\n", GfaTfuStrError(errno));
 					break;
 		        }
 
 		        TRACE3("Currently running: %s.\n", (ctx == GfaBlmCtx_App) ? "Application" : "Bootloader");
+				
+				if(cla.bUploadImg)
+					nRet = _UploadImg(hIf, hBlm, &cla, ctx);
+				else if(cla.bShowDevImgInfo)
+					nRet = _ShowDevImgInfo(hIf, hBlm, &cla, ctx);
+				else if(cla.bValidateImg)
+					nRet = _ValidateImg(hIf, hBlm, &cla, ctx);
+				else if(cla.bShowMatSer)
+					nRet = _ShowMatSer(hIf, hBlm, &cla, ctx);
+				else if(cla.bSetMatSer)
+					nRet = _SetMatSer(hIf, hBlm, &cla, ctx);
+				else if(cla.bPing)
+					nRet = _Ping(hIf, hBlm, &cla, ctx);
 
+#if 0
 	            if(ctx == GfaBlmCtx_App)
 	            {
 					TRACE3("Starting bootloader.\n");
 
 					if((nRet = GfaBlmBootloaderExecute(hBlm, cla.nNodeAddr, NULL, 1000)) != 0)
 					{
-						TRACE1("%s!\n", _StrError(errno));
+						TRACE1("%s!\n", GfaTfuStrError(errno));
 						break;
 					}
 				}
 
-		        if(cla.nBaudrate != _DEFAULT_BAUDRATE)
+		        if(cla.nBaudrate != CMD_OPT_DEFAULT_BAUDRATE)
 		        {
 					TRACE3("Setting baudrate to %u.\n", cla.nBaudrate);
 
 					if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, cla.nNodeAddr, cla.nBaudrate)) != 0)
 					{
-						TRACE1("%s!\n", _StrError(errno));
+						TRACE1("%s!\n", GfaTfuStrError(errno));
 						break;
 			        }
 		        }
 
-				if(cla.bShowImgInfo)
+				if(cla.bShowDevImgInfo)
 				{
 					GFA_BL_APP_IMG_INFO aii;
 
@@ -380,13 +303,13 @@ int main(int argc, char* argv[])
 
 			        if((nRet = GfaBlmGetInfoBI(hBlm, cla.nNodeAddr, &aii)) == 0)
 			        {
-			        	_TraceImageInfo("Bootloader", &aii.bl);
-			        	_TraceImageInfo("Application", &aii.app);
+			        	GfaTfuDumpImageInfo("Bootloader", &aii.bl);
+			        	GfaTfuDumpImageInfo("Application", &aii.app);
 			        }
 		            else if((nRet = GfaBlmGetInfoBD(hBlm, cla.nNodeAddr, &aii)) > -2)
 					{
-			        	_TraceImageInfo("Bootloader", &aii.bl);
-			        	_TraceImageInfo("Application", &aii.app);
+			        	GfaTfuDumpImageInfo("Bootloader", &aii.bl);
+			        	GfaTfuDumpImageInfo("Application", &aii.app);
 			        }
 				}
 
@@ -398,10 +321,13 @@ int main(int argc, char* argv[])
 
 					if((nRet = GfaBlmReadMaterialAndSerialID(hBlm, cla.nNodeAddr, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) != 0)
 					{
-						TRACE1("%s!\n", _StrError(errno));
+						TRACE1("%s!\n", GfaTfuStrError(errno));
 						break;
 					}
 
+					if(hIf)
+						GfaTfuImageFileMatchMaterialNum(hIf, szMaterial);
+
 					TRACE2("Material and Serial number:\n");
 					TRACE2("  Mat.Nr.: %s\n", szMaterial);
 					TRACE2("  Serial:  %s\n", szSerial);
@@ -411,19 +337,20 @@ int main(int argc, char* argv[])
 
 	            if((nRet = GfaBlmBUCmdReset(hBlm, cla.nNodeAddr, 1000)) != 0)
 		        {
-					TRACE1("%s!\n", _StrError(errno));
+					TRACE1("%s!\n", GfaTfuStrError(errno));
 					break;
 		        }
+#endif
 			}
 			else
 	        {
-				TRACE1("%s!\n", _StrError(errno));
+				TRACE1("%s!\n", GfaTfuStrError(errno));
 				break;
 	        }
 		}
 		else
         {
-			TRACE1("%s!\n", _StrError(errno));
+			TRACE1("%s!\n", GfaTfuStrError(errno));
 			break;
         }
 	}
@@ -431,10 +358,17 @@ int main(int argc, char* argv[])
 
 	if(hBlm)
 	{
-		TRACE3("Closing bootloader master.\n\n");
+		TRACE3("Closing bootloader master.\n");
 		GfaBlmClose(hBlm);
 	}
 
+	if(hIf)
+	{
+		TRACE3("Closing image file.\n");
+		GfaTfuImageFileClose(hIf);
+	}
+
+	TRACE1("\n");
 	return 0;
 }
 

+ 1 - 22
main.h

@@ -15,28 +15,7 @@ extern "C" {
 #define GFA_FU_VER_MINOR						0
 #define GFA_FU_VER_REVISION						0
 
-/////////////////////////////////////////////////////////////////////////////
-
-#define TRACE(...)								fprintf(stdout, __VA_ARGS__), fflush(stdout)
-#define ETRACE(...)								fprintf(stderr, __VA_ARGS__), fflush(stderr)
-
-#define TRACE0(...)								_cprintf(0, __VA_ARGS__)
-#define TRACE1(...)								_cprintf(1, __VA_ARGS__)
-#define TRACE2(...)								_cprintf(2, __VA_ARGS__)
-#define TRACE3(...)								_cprintf(3, __VA_ARGS__)
-#define TRACE4(...)								_cprintf(4, __VA_ARGS__)
-
-/////////////////////////////////////////////////////////////////////////////
-
-#define MAKE_GFA_FU_ERROR(c)					(0x81000000 | c)
-
-#define GFA_FU_ERROR_INVALID_CMDLINE_ARG		MAKE_GFA_FU_ERROR(1)
-#define GFA_FU_ERROR_INVALID_BAUDRATE			MAKE_GFA_FU_ERROR(2)
-#define GFA_FU_ERROR_INVALID_NODE_ADDR			MAKE_GFA_FU_ERROR(3)
-#define GFA_FU_ERROR_INVALID_BLOCK_SIZE			MAKE_GFA_FU_ERROR(4)
-#define GFA_FU_ERROR_INVALID_DEVICE_NAME		MAKE_GFA_FU_ERROR(5)
-
-#define GFA_FU_ERROR_NOTHING_TO_DO				MAKE_GFA_FU_ERROR(10)
+#define UNUSED(x)								(void)x
 
 /////////////////////////////////////////////////////////////////////////////
 #ifdef __cplusplus

+ 82 - 0
output.c

@@ -0,0 +1,82 @@
+#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 <unistd.h>
+#include <stddef.h>
+#include <time.h>
+#include <errno.h>
+#include "main.h"
+#include "cmdopt.h"
+#include "error.h"
+#include "output.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+extern int g_nVerbosity;
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaTfuPrintF(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;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaTfuDumpImageInfo(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);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaTfuOnDownloadStatus(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, int nCtx, int nErrorCode)
+{
+	UNUSED(pszFile);
+	UNUSED(nLine);
+	UNUSED(nNodeAddr);
+	UNUSED(nFlashStartAddr);
+	UNUSED(nCbData);
+	UNUSED(nCtx);
+	UNUSED(nErrorCode);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaTfuOnSendDataStatus(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nCbBlock, uint32_t nCbData, int nCtx, int nErrorCode)
+{
+	UNUSED(pszFile);
+	UNUSED(nLine);
+	UNUSED(nNodeAddr);
+	UNUSED(nCbBlock);
+	UNUSED(nCbData);
+	UNUSED(nCtx);
+	UNUSED(nErrorCode);
+}

+ 37 - 0
output.h

@@ -0,0 +1,37 @@
+// output.h :
+//
+
+#if !defined(AGD_OUTPUT_H__77A3E0A7_F59F_49E5_950F_D3465B3FDCAB__INCLUDED_)
+#define AGD_OUTPUT_H__77A3E0A7_F59F_49E5_950F_D3465B3FDCAB__INCLUDED_
+
+#include <gfabootlmast.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// output.h - Declarations:
+
+#define TRACE(...)								fprintf(stdout, __VA_ARGS__), fflush(stdout)
+#define ETRACE(...)								fprintf(stderr, __VA_ARGS__), fflush(stderr)
+
+#define TRACE0(...)								GfaTfuPrintF(0, __VA_ARGS__)
+#define TRACE1(...)								GfaTfuPrintF(1, __VA_ARGS__)
+#define TRACE2(...)								GfaTfuPrintF(2, __VA_ARGS__)
+#define TRACE3(...)								GfaTfuPrintF(3, __VA_ARGS__)
+#define TRACE4(...)								GfaTfuPrintF(4, __VA_ARGS__)
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaTfuPrintF(int verb, const char *pszFormat, ...);
+void GfaTfuDumpImageInfo(const char *pszContext, LPCGFA_IMG_INFO pii);
+
+void GfaTfuOnDownloadStatus(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, int nCtx, int nErrorCode);
+void GfaTfuOnSendDataStatus(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nCbBlock, uint32_t nCbData, int nCtx, int nErrorCode);
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_OUTPUT_H__77A3E0A7_F59F_49E5_950F_D3465B3FDCAB__INCLUDED_)