瀏覽代碼

Sicherung aktueller Stand

Rind 5 年之前
父節點
當前提交
5387b5647a
共有 13 個文件被更改,包括 2131 次插入330 次删除
  1. 509 109
      cmdopt.c
  2. 46 17
      cmdopt.h
  3. 21 1
      error.c
  4. 17 5
      error.h
  5. 4 2
      gfativaflashutil.pro
  6. 36 30
      image.c
  7. 6 6
      image.h
  8. 890 131
      main.c
  9. 1 0
      main.h
  10. 398 0
      modbmst.c
  11. 109 0
      modbmst.h
  12. 83 25
      output.c
  13. 11 4
      output.h

+ 509 - 109
cmdopt.c

@@ -22,7 +22,7 @@
 
 
 #define _IS_POWER_OF_2(x)						(!!(x) && !((x) & ((x) - 1)))
 #define _IS_POWER_OF_2(x)						(!!(x) && !((x) & ((x) - 1)))
 #define _IS_VALID_STATION_NUMBER(s)				(((s) > 0) && ((s) <= 99))
 #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 _IS_VALID_BLOCK_SIZE(s)					(((s) >= GFA_BOOTLOADER_MIN_SEND_DATA_BLOCK_SIZE) && ((s) <= GFA_BOOTLOADER_MAX_SEND_DATA_BLOCK_SIZE) && !((s) & 0x03))
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
@@ -33,18 +33,29 @@
 #define _OV_HAS_SHOW_MAT_SER					((uint32_t)0x00000010)
 #define _OV_HAS_SHOW_MAT_SER					((uint32_t)0x00000010)
 #define _OV_HAS_SET_MAT_SER						((uint32_t)0x00000020)
 #define _OV_HAS_SET_MAT_SER						((uint32_t)0x00000020)
 #define _OV_HAS_BOOT_PING						((uint32_t)0x00000040)
 #define _OV_HAS_BOOT_PING						((uint32_t)0x00000040)
+#define _OV_HAS_START_BOOT						((uint32_t)0x00000080)
+#define _OV_HAS_RESET_BOOT						((uint32_t)0x00000100)
+#define _OV_HAS_RESCUE_BOOT						((uint32_t)0x00000200)
+#define _OV_HAS_MODBUS_START_BOOT				((uint32_t)0x00000400)
 
 
 #define _OV_HAS_IMG_FILE						((uint32_t)0x00001000)
 #define _OV_HAS_IMG_FILE						((uint32_t)0x00001000)
 #define _OV_HAS_ITF_NAME						((uint32_t)0x00002000)
 #define _OV_HAS_ITF_NAME						((uint32_t)0x00002000)
 #define _OV_HAS_BLOCK_SIZE						((uint32_t)0x00004000)
 #define _OV_HAS_BLOCK_SIZE						((uint32_t)0x00004000)
 #define _OV_HAS_APP_ADDR						((uint32_t)0x00008000)
 #define _OV_HAS_APP_ADDR						((uint32_t)0x00008000)
-#define _OV_HAS_BAUD_RATE						((uint32_t)0x00010000)
+#define _OV_HAS_X_BAUD_RATE						((uint32_t)0x00010000)
 #define _OV_HAS_STATION_NUMBER					((uint32_t)0x00020000)
 #define _OV_HAS_STATION_NUMBER					((uint32_t)0x00020000)
 #define _OV_HAS_NODE_ADDR						((uint32_t)0x00040000)
 #define _OV_HAS_NODE_ADDR						((uint32_t)0x00040000)
 #define _OV_HAS_SLAVE_ADDR						((uint32_t)0x00080000)
 #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_MATERIAL						((uint32_t)0x00100000)
+#define _OV_HAS_SERIAL							((uint32_t)0x00200000)
 #define _OV_HAS_PING_INTERVAL					((uint32_t)0x00400000)
 #define _OV_HAS_PING_INTERVAL					((uint32_t)0x00400000)
+#define _OV_HAS_NO_SHOW_PROGRESS				((uint32_t)0x00800000)
+#define _OV_HAS_PAGE_ERASE_TIME					((uint32_t)0x01000000)
+#define _OV_HAS_MODBUS_SLAVE_ID					((uint32_t)0x02000000)
+#define _OV_HAS_MODBUS_CTRL_REG					((uint32_t)0x04000000)
+//#define _OV_HAS_INIT_BAUD_RATE					((uint32_t)0x08000000)
+//#define _OV_HAS_MODBUS_BAUD_RATE				((uint32_t)0x10000000)
+//#define _OV_HAS_MODBUS_PARITY					((uint32_t)0x20000000)
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
@@ -55,25 +66,33 @@
 
 
 #define _REQ_CONNECTION_OPTS					(_OV_HAS_ITF_NAME | _OV_HAS_SLAVE_ADDR)
 #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_UPLOAD_IMG					(_OV_HAS_IMG_FILE | _REQ_CONNECTION_OPTS)
 #define _REQ_OPTS_SHOW_IMG_INFO_OFFLINE			_OV_HAS_IMG_FILE
 #define _REQ_OPTS_SHOW_IMG_INFO_OFFLINE			_OV_HAS_IMG_FILE
 #define _REQ_OPTS_SHOW_IMG_INFO_ONLINE			_REQ_CONNECTION_OPTS
 #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_VALIDATE_IMG					(_OV_HAS_IMG_FILE | _REQ_CONNECTION_OPTS)
 #define _REQ_OPTS_SHOW_MAT_SER					_REQ_CONNECTION_OPTS
 #define _REQ_OPTS_SHOW_MAT_SER					_REQ_CONNECTION_OPTS
-#define _REQ_OPTS_SET_MAT_SER					_REQ_CONNECTION_OPTS
+#define _REQ_OPTS_SET_MAT_SER					(_REQ_CONNECTION_OPTS | _OV_HAS_MATERIAL | _OV_HAS_SERIAL)
 #define _REQ_OPTS_BOOT_PING						_REQ_CONNECTION_OPTS
 #define _REQ_OPTS_BOOT_PING						_REQ_CONNECTION_OPTS
+#define _REQ_OPTS_START_BOOT					_REQ_CONNECTION_OPTS
+#define _REQ_OPTS_RESET_BOOT					_REQ_CONNECTION_OPTS
+#define _REQ_OPTS_RESCUE_BOOT					_REQ_CONNECTION_OPTS
+#define _REQ_OPTS_MODBUS_START_BOOT				(_OV_HAS_ITF_NAME | _OV_HAS_MODBUS_SLAVE_ID)
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
-#define _OPT_CONNECTION_OPTS					(_OV_HAS_BAUD_RATE | _OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR)
+#define _OPT_CONNECTION_OPTS					(/*_OV_HAS_INIT_BAUD_RATE | */_OV_HAS_X_BAUD_RATE | _OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR | _OV_HAS_MODBUS_SLAVE_ID)
 
 
-#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 _OPT_OPTS_UPLOAD_IMG					(_OV_HAS_IMG_FILE | _OV_HAS_APP_ADDR | _OPT_CONNECTION_OPTS | _OV_HAS_NO_SHOW_PROGRESS | _OV_HAS_PAGE_ERASE_TIME)
+#define _OPT_OPTS_SHOW_IMG_INFO_OFFLINE			_OV_HAS_APP_ADDR
+#define _OPT_OPTS_SHOW_IMG_INFO_ONLINE			(_OPT_CONNECTION_OPTS | _OV_HAS_APP_ADDR)
+#define _OPT_OPTS_VALIDATE_IMG					(_OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR | _OV_HAS_APP_ADDR/* | _OV_HAS_INIT_BAUD_RATE*/)
+#define _OPT_OPTS_SHOW_MAT_SER					(_OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR/* | _OV_HAS_INIT_BAUD_RATE*/)
+#define _OPT_OPTS_SET_MAT_SER					(_OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR/* | _OV_HAS_INIT_BAUD_RATE*/)
+#define _OPT_OPTS_BOOT_PING						(_OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR | _OV_HAS_PING_INTERVAL/* | _OV_HAS_INIT_BAUD_RATE*/)
+#define _OPT_OPTS_START_BOOT					(_OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR/* | _OV_HAS_INIT_BAUD_RATE*/)
+#define _OPT_OPTS_RESET_BOOT					(_OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR/* | _OV_HAS_INIT_BAUD_RATE*/)
+#define _OPT_OPTS_RESCUE_BOOT					(_OV_HAS_STATION_NUMBER | _OV_HAS_NODE_ADDR/* | _OV_HAS_INIT_BAUD_RATE*/)
+#define _OPT_OPTS_MODBUS_START_BOOT				(_OV_HAS_MODBUS_CTRL_REG/* | _OV_HAS_MODBUS_BAUD_RATE | _OV_HAS_MODBUS_PARITY*/)
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
@@ -93,23 +112,35 @@
 #define _OPT_STRING_SHOW_FILE_IMG_INFO			"show-file-img-info"
 #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_DEV_IMG_INFO			"show-dev-img-info"
 #define _OPT_STRING_SHOW_MAT_SER				"show-mat-ser"
 #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_SET_MAT_SER					"set-mat-ser"
+#define _OPT_STRING_BOOT_PING					"ping-target"
+#define _OPT_STRING_START_BOOT					"start-boot"
+#define _OPT_STRING_RESET_BOOT					"reset-boot"
+#define _OPT_STRING_RESCUE_BOOT					"revive-boot"
+#define _OPT_STRING_MODBUS_START_BOOT			"mb-start-boot"
 #define _OPT_STRING_ITF_NAME					"itf-name"
 #define _OPT_STRING_ITF_NAME					"itf-name"
-#define _OPT_STRING_BAUD_RATE					"baud-rate"
+//#define _OPT_STRING_INIT_BAUD_RATE				"init-baud-rate"
+#define _OPT_STRING_X_BAUD_RATE					"x-baud-rate"
+//#define _OPT_STRING_MODBUS_BAUD_RATE			"mb-baud-rate"
+//#define _OPT_STRING_MODBUS_PARITY				"mb-parity"
 #define _OPT_STRING_STATION_NUMBER				"stat-num"
 #define _OPT_STRING_STATION_NUMBER				"stat-num"
 #define _OPT_STRING_NODE_ADDR					"node-addr"
 #define _OPT_STRING_NODE_ADDR					"node-addr"
+#define _OPT_STRING_MATERIAL					"material"
+#define _OPT_STRING_SERIAL						"serial"
 #define _OPT_STRING_SLAVE_ADDR					"stat-num or node-addr"
 #define _OPT_STRING_SLAVE_ADDR					"stat-num or node-addr"
 #define _OPT_STRING_APP_BASE_ADDR				"app-addr"
 #define _OPT_STRING_APP_BASE_ADDR				"app-addr"
 #define _OPT_STRING_BLOCK_SIZE					"block-size"
 #define _OPT_STRING_BLOCK_SIZE					"block-size"
 #define _OPT_STRING_PING_INTERVAL				"ping-int"
 #define _OPT_STRING_PING_INTERVAL				"ping-int"
+#define _OPT_STRING_PAGE_ERASE_TIME				"page-erase-time"
+#define _OPT_STRING_NO_SHOW_PROGRESS			"no-progress"
+#define _OPT_STRING_MODBUS_SLAVE_ID				"mb-slave-id"
+#define _OPT_STRING_MODBUS_CTRL_REG				"mb-bl-ctrl-reg"
 #define _OPT_STRING_VERBOSITY					"verbosity"
 #define _OPT_STRING_VERBOSITY					"verbosity"
 #define _OPT_STRING_HELP						"help"
 #define _OPT_STRING_HELP						"help"
 #define _OPT_STRING_IMG_FILE					"<IMG FILE>"
 #define _OPT_STRING_IMG_FILE					"<IMG FILE>"
 
 
 #define _MAX_CMD_LENGTH							18
 #define _MAX_CMD_LENGTH							18
-#define _MAX_OPT_LENGTH							10
+#define _MAX_OPT_LENGTH							15
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
@@ -150,33 +181,140 @@ static const char* _GetOptName(uint32_t nOpt)
 		return _OPT_STRING_SHOW_MAT_SER;
 		return _OPT_STRING_SHOW_MAT_SER;
 	case _OV_HAS_BOOT_PING:
 	case _OV_HAS_BOOT_PING:
 		return _OPT_STRING_BOOT_PING;
 		return _OPT_STRING_BOOT_PING;
+	case _OV_HAS_START_BOOT:
+		return _OPT_STRING_START_BOOT;
+	case _OV_HAS_RESET_BOOT:
+		return _OPT_STRING_RESET_BOOT;
+	case _OV_HAS_RESCUE_BOOT:
+		return _OPT_STRING_RESCUE_BOOT;
+	case _OV_HAS_MODBUS_START_BOOT:
+		return _OPT_STRING_MODBUS_START_BOOT;
 	case _OV_HAS_PING_INTERVAL:
 	case _OV_HAS_PING_INTERVAL:
 		return _OPT_STRING_PING_INTERVAL;
 		return _OPT_STRING_PING_INTERVAL;
+	case _OV_HAS_NO_SHOW_PROGRESS:
+		return _OPT_STRING_NO_SHOW_PROGRESS;
 	case _OV_HAS_ITF_NAME:
 	case _OV_HAS_ITF_NAME:
 		return _OPT_STRING_ITF_NAME;
 		return _OPT_STRING_ITF_NAME;
 	case _OV_HAS_BLOCK_SIZE:
 	case _OV_HAS_BLOCK_SIZE:
 		return _OPT_STRING_BLOCK_SIZE;
 		return _OPT_STRING_BLOCK_SIZE;
 	case _OV_HAS_APP_ADDR:
 	case _OV_HAS_APP_ADDR:
 		return _OPT_STRING_APP_BASE_ADDR;
 		return _OPT_STRING_APP_BASE_ADDR;
-	case _OV_HAS_BAUD_RATE:
-		return _OPT_STRING_BAUD_RATE;
+//	case _OV_HAS_INIT_BAUD_RATE:
+//		return _OPT_STRING_INIT_BAUD_RATE;
+	case _OV_HAS_X_BAUD_RATE:
+		return _OPT_STRING_X_BAUD_RATE;
+//	case _OV_HAS_MODBUS_BAUD_RATE:
+//		return _OPT_STRING_MODBUS_BAUD_RATE;
+//	case _OV_HAS_MODBUS_PARITY:
+//		return _OPT_STRING_MODBUS_PARITY;
+	case _OV_HAS_PAGE_ERASE_TIME:
+		return _OPT_STRING_PAGE_ERASE_TIME;
 	case _OV_HAS_STATION_NUMBER:
 	case _OV_HAS_STATION_NUMBER:
 		return _OPT_STRING_STATION_NUMBER;
 		return _OPT_STRING_STATION_NUMBER;
 	case _OV_HAS_NODE_ADDR:
 	case _OV_HAS_NODE_ADDR:
 		return _OPT_STRING_NODE_ADDR;
 		return _OPT_STRING_NODE_ADDR;
 	case _OV_HAS_SLAVE_ADDR:
 	case _OV_HAS_SLAVE_ADDR:
 		return _OPT_STRING_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_MATERIAL:
+		return _OPT_STRING_MATERIAL;
+	case _OV_HAS_SERIAL:
+		return _OPT_STRING_SERIAL;
+	case _OV_HAS_SET_MAT_SER:
+		return _OPT_STRING_SET_MAT_SER;
 	case _OV_HAS_IMG_FILE:
 	case _OV_HAS_IMG_FILE:
 		return _OPT_STRING_IMG_FILE;
 		return _OPT_STRING_IMG_FILE;
+	case _OV_HAS_MODBUS_SLAVE_ID:
+		return _OPT_STRING_MODBUS_SLAVE_ID;
+	case _OV_HAS_MODBUS_CTRL_REG:
+		return _OPT_STRING_MODBUS_CTRL_REG;
 	default:
 	default:
 		return NULL;
 		return NULL;
 	}
 	}
 }
 }
 
 
+static const char* _GetOptValue(uint32_t nOpt, LPCMD_LINE_ARGS pcla)
+{
+	static char szValue[32];
+
+	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_START_BOOT:
+		return _OPT_STRING_START_BOOT;
+	case _OV_HAS_RESET_BOOT:
+		return _OPT_STRING_RESET_BOOT;
+	case _OV_HAS_RESCUE_BOOT:
+		return _OPT_STRING_RESCUE_BOOT;
+	case _OV_HAS_MODBUS_START_BOOT:
+		return _OPT_STRING_MODBUS_START_BOOT;
+
+	case _OV_HAS_PING_INTERVAL:
+		snprintf(szValue, sizeof(szValue) - 1, "%d", pcla->nPingIntervalSec);
+		break;
+	case _OV_HAS_ITF_NAME:
+		return pcla->pszDevName ? pcla->pszDevName : "empty";
+	case _OV_HAS_BLOCK_SIZE:
+		snprintf(szValue, sizeof(szValue) - 1, "%u", pcla->nBlockSize);
+		break;
+	case _OV_HAS_APP_ADDR:
+		snprintf(szValue, sizeof(szValue) - 1, "0x%X", pcla->nStartAddr);
+		break;
+//	case _OV_HAS_INIT_BAUD_RATE:
+//		snprintf(szValue, sizeof(szValue) - 1, "%u", pcla->nInitBaudrate);
+//		break;
+	case _OV_HAS_X_BAUD_RATE:
+		snprintf(szValue, sizeof(szValue) - 1, "%u", pcla->nElevBaudrate);
+		break;
+//	case _OV_HAS_MODBUS_BAUD_RATE:
+//		snprintf(szValue, sizeof(szValue) - 1, "%u", pcla->nModbBaudrate);
+//		break;
+//	case _OV_HAS_MODBUS_PARITY:
+//		snprintf(szValue, sizeof(szValue) - 1, "%c", pcla->modbParity);
+//		break;
+	case _OV_HAS_PAGE_ERASE_TIME:
+		snprintf(szValue, sizeof(szValue) - 1, "%u", pcla->nPageErsaeTime);
+		break;
+	case _OV_HAS_STATION_NUMBER:
+		snprintf(szValue, sizeof(szValue) - 1, "%hhu", pcla->nStationNr);
+		break;
+	case _OV_HAS_NODE_ADDR:
+		snprintf(szValue, sizeof(szValue) - 1, "0x%02hhX", pcla->nNodeAddr);
+		break;
+	case _OV_HAS_SLAVE_ADDR:
+		return _OPT_STRING_SLAVE_ADDR;
+	case _OV_HAS_MATERIAL:
+		return pcla->pszMaterial ? pcla->pszMaterial : "empty";
+	case _OV_HAS_SERIAL:
+		return pcla->pszSerial ? pcla->pszSerial : "empty";
+	case _OV_HAS_IMG_FILE:
+		return pcla->pszImgFile ? pcla->pszImgFile : "empty";
+	case _OV_HAS_NO_SHOW_PROGRESS:
+		return pcla->bNoProgressBlock ? "true" : "false";
+	case _OV_HAS_MODBUS_SLAVE_ID:
+		snprintf(szValue, sizeof(szValue) - 1, "%hhu", pcla->nModbusSlvID);
+		break;
+	case _OV_HAS_MODBUS_CTRL_REG:
+		snprintf(szValue, sizeof(szValue) - 1, "%hu", pcla->nModbusCtrlReg);
+		break;
+	default:
+		return "empty";
+	}
+
+	szValue[31] = '\0';
+	return szValue;
+}
+
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
 const char* GfaTfuCmdOpt2String(uint32_t nOpts)
 const char* GfaTfuCmdOpt2String(uint32_t nOpts)
@@ -188,7 +326,7 @@ const char* GfaTfuCmdOpt2String(uint32_t nOpts)
 		int nCount = 0;
 		int nCount = 0;
 		uint32_t nMask = 1;
 		uint32_t nMask = 1;
 		memset(szOptStr, '\0', sizeof(szOptStr));
 		memset(szOptStr, '\0', sizeof(szOptStr));
-		
+
 		while(nMask)
 		while(nMask)
 		{
 		{
 			if(nOpts & nMask)
 			if(nOpts & nMask)
@@ -201,13 +339,13 @@ const char* GfaTfuCmdOpt2String(uint32_t nOpts)
 					strcat(szOptStr, pszOptName);
 					strcat(szOptStr, pszOptName);
 				}
 				}
 			}
 			}
-			
+
 			nMask <<= 1;
 			nMask <<= 1;
 		}
 		}
-		
+
 		return szOptStr;
 		return szOptStr;
 	}
 	}
-	
+
 	return "";
 	return "";
 }
 }
 
 
@@ -246,16 +384,28 @@ static const struct option g_lo[] =
 		ov_show_mat_ser
 		ov_show_mat_ser
 	},
 	},
 	{
 	{
-		_OPT_STRING_SET_MATERIAL,
-		optional_argument,
+		_OPT_STRING_SET_MAT_SER,
+		no_argument,
 		NULL,
 		NULL,
-		ov_set_material
+		ov_set_mat_ser
 	},
 	},
 	{
 	{
-		_OPT_STRING_SET_SERIAL,
-		optional_argument,
+		_OPT_STRING_MATERIAL,
+		required_argument,
 		NULL,
 		NULL,
-		ov_set_serial
+		ov_material
+	},
+	{
+		_OPT_STRING_SERIAL,
+		required_argument,
+		NULL,
+		ov_serial
+	},
+	{
+		_OPT_STRING_NO_SHOW_PROGRESS,
+		no_argument,
+		NULL,
+		ov_no_progress
 	},
 	},
 	{
 	{
 		_OPT_STRING_BOOT_PING,
 		_OPT_STRING_BOOT_PING,
@@ -263,6 +413,30 @@ static const struct option g_lo[] =
 		NULL,
 		NULL,
 		ov_boot_ping
 		ov_boot_ping
 	},
 	},
+	{
+		_OPT_STRING_START_BOOT,
+		no_argument,
+		NULL,
+		ov_start_boot
+	},
+	{
+		_OPT_STRING_RESET_BOOT,
+		no_argument,
+		NULL,
+		ov_reset_boot
+	},
+	{
+		_OPT_STRING_RESCUE_BOOT,
+		no_argument,
+		NULL,
+		ov_rescue_boot
+	},
+	{
+		_OPT_STRING_MODBUS_START_BOOT,
+		no_argument,
+		NULL,
+		ov_mb_start_boot
+	},
 	{
 	{
 		_OPT_STRING_PING_INTERVAL,
 		_OPT_STRING_PING_INTERVAL,
 		required_argument,
 		required_argument,
@@ -275,12 +449,30 @@ static const struct option g_lo[] =
 		NULL,
 		NULL,
 		ov_itf_name
 		ov_itf_name
 	},
 	},
+/*	{
+		_OPT_STRING_INIT_BAUD_RATE,
+		required_argument,
+		NULL,
+		ov_init_baud_rate
+	},*/
 	{
 	{
-		_OPT_STRING_BAUD_RATE,
+		_OPT_STRING_X_BAUD_RATE,
 		required_argument,
 		required_argument,
 		NULL,
 		NULL,
-		ov_baud_rate
+		ov_x_baud_rate
 	},
 	},
+/*	{
+		_OPT_STRING_MODBUS_BAUD_RATE,
+		required_argument,
+		NULL,
+		ov_mb_baud_rate
+	},*/
+/*	{
+		_OPT_STRING_MODBUS_PARITY,
+		required_argument,
+		NULL,
+		ov_mb_parity
+	},*/
 	{
 	{
 		_OPT_STRING_STATION_NUMBER,
 		_OPT_STRING_STATION_NUMBER,
 		required_argument,
 		required_argument,
@@ -293,6 +485,12 @@ static const struct option g_lo[] =
 		NULL,
 		NULL,
 		ov_node_addr
 		ov_node_addr
 	},
 	},
+	{
+		_OPT_STRING_PAGE_ERASE_TIME,
+		required_argument,
+		NULL,
+		ov_page_erase_time
+	},
 	{
 	{
 		_OPT_STRING_APP_BASE_ADDR,
 		_OPT_STRING_APP_BASE_ADDR,
 		required_argument,
 		required_argument,
@@ -305,6 +503,18 @@ static const struct option g_lo[] =
 		NULL,
 		NULL,
 		ov_block_size
 		ov_block_size
 	},
 	},
+	{
+		_OPT_STRING_MODBUS_SLAVE_ID,
+		required_argument,
+		NULL,
+		ov_mb_slave_id
+	},
+	{
+		_OPT_STRING_MODBUS_CTRL_REG,
+		required_argument,
+		NULL,
+		ov_mb_ctrl_reg
+	},
 	{
 	{
 		_OPT_STRING_VERBOSITY,
 		_OPT_STRING_VERBOSITY,
 		required_argument,
 		required_argument,
@@ -341,14 +551,22 @@ static int64_t _ArgStr2Num(const char *pszNum, int64_t nDefault)
 	return nDefault;
 	return nDefault;
 }
 }
 
 
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
 void GfaTfuCmdOptInitOpts(LPCMD_LINE_ARGS pcla)
 void GfaTfuCmdOptInitOpts(LPCMD_LINE_ARGS pcla)
 {
 {
 	memset(pcla, 0, sizeof(CMD_LINE_ARGS));
 	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;
+	pcla->nBootBaudrate		= CMD_OPT_DEFAULT_BAUDRATE;
+	pcla->nInitBaudrate		= CMD_OPT_DEFAULT_BAUDRATE;
+	pcla->nModbBaudrate		= CMD_OPT_DEFAULT_BAUDRATE;
+	pcla->modbParity		= CMD_OPT_DEFAULT_MODBUS_PARITY;
+	pcla->nBlockSize		= GFA_BOOTLOADER_DEF_SEND_DATA_BLOCK_SIZE;
+	pcla->nStartAddr		= CMD_OPT_DEFAULT_APP_BASE_ADDRESS;
+	pcla->nPageErsaeTime	= CMD_OPT_DEFAULT_PAGE_ERASE_TIME;
+	pcla->nVerbosity		= CMD_OPT_DEFAULT_VERBOSITY;
+	pcla->nModbusCtrlReg	= CMD_OPT_DEFAULT_MODBUS_START_REGISTER;
 }
 }
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
@@ -358,7 +576,7 @@ int GfaTfuCmdOptParse(int argc, char* argv[], LPCMD_LINE_ARGS pcla)
 	int opt, nCount = 0;
 	int opt, nCount = 0;
 	pcla->nOptFlags = 0;
 	pcla->nOptFlags = 0;
 
 
-	while((opt = getopt_long(argc, argv, "-a:b:v:n:s:i:?", g_lo, NULL)) != -1)
+	while((opt = getopt_long(argc, argv, "-a:d:e:i:n:p:s:v:x:?", g_lo, NULL)) != -1)
 	{
 	{
 		const char *arg = optarg;
 		const char *arg = optarg;
 
 
@@ -367,7 +585,10 @@ int GfaTfuCmdOptParse(int argc, char* argv[], LPCMD_LINE_ARGS pcla)
 		case ov_img_file:
 		case ov_img_file:
 			if(arg)
 			if(arg)
 			{
 			{
+				const char *pszFileBase = strrchr(arg, '/');
 				pcla->pszImgFile = arg;
 				pcla->pszImgFile = arg;
+				if(pszFileBase)
+					pcla->pszImgFileBase = ++pszFileBase;
 				pcla->nOptFlags |= _OV_HAS_IMG_FILE;
 				pcla->nOptFlags |= _OV_HAS_IMG_FILE;
 			}
 			}
 			break;
 			break;
@@ -390,6 +611,10 @@ int GfaTfuCmdOptParse(int argc, char* argv[], LPCMD_LINE_ARGS pcla)
 			pcla->bShowMatSer = true;
 			pcla->bShowMatSer = true;
 			pcla->nOptFlags |= _OV_HAS_SHOW_MAT_SER;
 			pcla->nOptFlags |= _OV_HAS_SHOW_MAT_SER;
 			break;
 			break;
+		case ov_set_mat_ser:
+			pcla->bSetMatSer = true;
+			pcla->nOptFlags |= _OV_HAS_SET_MAT_SER;
+			break;
 		case ov_validate_img:
 		case ov_validate_img:
 			pcla->bValidateImg = true;
 			pcla->bValidateImg = true;
 			pcla->nOptFlags |= _OV_HAS_VALIDATE_IMG;
 			pcla->nOptFlags |= _OV_HAS_VALIDATE_IMG;
@@ -402,40 +627,72 @@ int GfaTfuCmdOptParse(int argc, char* argv[], LPCMD_LINE_ARGS pcla)
 			pcla->bPing = true;
 			pcla->bPing = true;
 			pcla->nOptFlags |= _OV_HAS_BOOT_PING;
 			pcla->nOptFlags |= _OV_HAS_BOOT_PING;
 			break;
 			break;
+		case ov_start_boot:
+			pcla->bStartBoot = true;
+			pcla->nOptFlags |= _OV_HAS_START_BOOT;
+			break;
+		case ov_reset_boot:
+			pcla->bResetBoot = true;
+			pcla->nOptFlags |= _OV_HAS_RESET_BOOT;
+			break;
+		case ov_rescue_boot:
+			pcla->bReviveBoot = true;
+			pcla->nOptFlags |= _OV_HAS_RESCUE_BOOT;
+			break;
+		case ov_mb_start_boot:
+			pcla->bModbusStartBoot = true;
+			pcla->nOptFlags |= _OV_HAS_MODBUS_START_BOOT;
+			break;
 		case ov_ping_interval:
 		case ov_ping_interval:
 			pcla->nPingIntervalSec = (int32_t)_ArgStr2Num(arg, 0);
 			pcla->nPingIntervalSec = (int32_t)_ArgStr2Num(arg, 0);
 			if(pcla->nPingIntervalSec > 0)
 			if(pcla->nPingIntervalSec > 0)
 				pcla->nOptFlags |= _OV_HAS_PING_INTERVAL;
 				pcla->nOptFlags |= _OV_HAS_PING_INTERVAL;
 			break;
 			break;
-		case ov_set_material:
-			if(arg)
+		case ov_material:
+			if(arg && *arg)
 			{
 			{
 				pcla->pszMaterial = arg;
 				pcla->pszMaterial = arg;
-				pcla->nOptFlags |= _OV_HAS_SET_MATERIAL;
-				if(pcla->nOptFlags & _OV_HAS_SET_SERIAL)
-					pcla->nOptFlags |= _OV_HAS_SET_MAT_SER;
+				pcla->nOptFlags |= _OV_HAS_MATERIAL;
 			}
 			}
 			break;
 			break;
-		case ov_set_serial:
-			if(arg)
+		case ov_serial:
+			if(arg && *arg)
 			{
 			{
 				pcla->pszSerial = arg;
 				pcla->pszSerial = arg;
-				pcla->nOptFlags |= _OV_HAS_SET_SERIAL;
-				if(pcla->nOptFlags & _OV_HAS_SET_MATERIAL)
-					pcla->nOptFlags |= _OV_HAS_SET_MAT_SER;
+				pcla->nOptFlags |= _OV_HAS_SERIAL;
 			}
 			}
 			break;
 			break;
+		case ov_no_progress:
+			pcla->bNoProgressBlock = true;
+			pcla->nOptFlags |= _OV_HAS_NO_SHOW_PROGRESS;
+			break;
 		case ov_block_size:
 		case ov_block_size:
-			pcla->nBlockSize = (uint32_t)_ArgStr2Num(arg, CMD_OPT_DEFAULT_SEND_BLOCK_SIZE);
+			pcla->nBlockSize = (uint32_t)_ArgStr2Num(arg, GFA_BOOTLOADER_DEF_SEND_DATA_BLOCK_SIZE);
 			pcla->nOptFlags |= _OV_HAS_BLOCK_SIZE;
 			pcla->nOptFlags |= _OV_HAS_BLOCK_SIZE;
 			break;
 			break;
 		case ov_app_addr:
 		case ov_app_addr:
-			pcla->nStartAddr = (uint32_t)_ArgStr2Num(arg, (uint32_t)-1);
+			pcla->nStartAddr = (uint32_t)_ArgStr2Num(arg, CMD_OPT_DEFAULT_APP_BASE_ADDRESS);
 			pcla->nOptFlags |= _OV_HAS_APP_ADDR;
 			pcla->nOptFlags |= _OV_HAS_APP_ADDR;
 			break;
 			break;
-		case ov_baud_rate:
-			pcla->nBaudrate = (uint32_t)_ArgStr2Num(arg, CMD_OPT_DEFAULT_BAUDRATE);
-			pcla->nOptFlags |= _OV_HAS_BAUD_RATE;
+/*		case ov_init_baud_rate:
+			pcla->nInitBaudrate = (uint32_t)_ArgStr2Num(arg, CMD_OPT_DEFAULT_BAUDRATE);
+			pcla->nOptFlags |= _OV_HAS_INIT_BAUD_RATE;
+			break;*/
+		case ov_x_baud_rate:
+			pcla->nElevBaudrate = (uint32_t)_ArgStr2Num(arg, 0);
+			pcla->nOptFlags |= _OV_HAS_X_BAUD_RATE;
+			break;
+/*		case ov_mb_baud_rate:
+			pcla->nModbBaudrate = (uint32_t)_ArgStr2Num(arg, CMD_OPT_DEFAULT_BAUDRATE);
+			pcla->nOptFlags |= _OV_HAS_MODBUS_BAUD_RATE;
+			break;*/
+/*		case ov_mb_parity:
+			pcla->modbParity = toupper(*arg);
+			pcla->nOptFlags |= _OV_HAS_MODBUS_PARITY;
+			break;*/
+		case ov_page_erase_time:
+			pcla->nPageErsaeTime = (uint32_t)_ArgStr2Num(arg, CMD_OPT_DEFAULT_PAGE_ERASE_TIME);
+			pcla->nOptFlags |= _OV_HAS_PAGE_ERASE_TIME;
 			break;
 			break;
 		case ov_station_number:
 		case ov_station_number:
 			pcla->nStationNr = (uint8_t)_ArgStr2Num(arg, 0);
 			pcla->nStationNr = (uint8_t)_ArgStr2Num(arg, 0);
@@ -447,6 +704,14 @@ int GfaTfuCmdOptParse(int argc, char* argv[], LPCMD_LINE_ARGS pcla)
 			pcla->nOptFlags |= _OV_HAS_NODE_ADDR;
 			pcla->nOptFlags |= _OV_HAS_NODE_ADDR;
 			pcla->nOptFlags |= _OV_HAS_SLAVE_ADDR;
 			pcla->nOptFlags |= _OV_HAS_SLAVE_ADDR;
 			break;
 			break;
+		case ov_mb_slave_id:
+			pcla->nModbusSlvID = (uint8_t)_ArgStr2Num(arg, 0xFF);
+			pcla->nOptFlags |= _OV_HAS_MODBUS_SLAVE_ID;
+			break;
+		case ov_mb_ctrl_reg:
+			pcla->nModbusCtrlReg = (uint16_t)_ArgStr2Num(arg, CMD_OPT_DEFAULT_MODBUS_START_REGISTER);
+			pcla->nOptFlags |= _OV_HAS_MODBUS_CTRL_REG;
+			break;
 		case ov_verbosity:
 		case ov_verbosity:
 			pcla->nVerbosity = (int)_ArgStr2Num(arg, CMD_OPT_DEFAULT_VERBOSITY);
 			pcla->nVerbosity = (int)_ArgStr2Num(arg, CMD_OPT_DEFAULT_VERBOSITY);
 			break;
 			break;
@@ -489,7 +754,7 @@ int GfaTfuCmdOptProcess(LPCMD_LINE_ARGS pcla)
 	pcla->nCmdFlags = _GET_CMD(pcla->nOptFlags);
 	pcla->nCmdFlags = _GET_CMD(pcla->nOptFlags);
 	if(!_HAS_CMD(pcla->nOptFlags))
 	if(!_HAS_CMD(pcla->nOptFlags))
 	{
 	{
-		if(!(pcla->nOptFlags & (_OV_HAS_SET_MATERIAL | _OV_HAS_SET_SERIAL)))
+		if(!(pcla->nOptFlags & (_OV_HAS_MATERIAL | _OV_HAS_SERIAL)))
 			return GFA_FU_ERROR_NOTHING_TO_DO;
 			return GFA_FU_ERROR_NOTHING_TO_DO;
 	}
 	}
 	else if(!_HAS_VALID_CMD(pcla->nOptFlags))
 	else if(!_HAS_VALID_CMD(pcla->nOptFlags))
@@ -500,7 +765,15 @@ int GfaTfuCmdOptProcess(LPCMD_LINE_ARGS pcla)
 
 
 	if(!_IS_OFFLINE_CMD(pcla->nOptFlags))
 	if(!_IS_OFFLINE_CMD(pcla->nOptFlags))
 	{
 	{
-		if(!GfaSerialIsValidBaudrate(pcla->nBaudrate))
+		if(	(pcla->modbParity != 'E') && 
+			(pcla->modbParity != 'O') &&
+			(pcla->modbParity != 'N'))
+			return GFA_FU_ERROR_INVALID_PARITY;
+		if(!pcla->nElevBaudrate)
+			pcla->nElevBaudrate = pcla->nInitBaudrate;
+		if(!GfaSerialIsValidBaudrate(pcla->nInitBaudrate))
+			return GFA_FU_ERROR_INVALID_BAUDRATE;
+		else if(!GfaSerialIsValidBaudrate(pcla->nElevBaudrate))
 			return GFA_FU_ERROR_INVALID_BAUDRATE;
 			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))
 		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;
 			return GFA_FU_ERROR_NODE_STATION_MUTEX;
@@ -536,7 +809,6 @@ int GfaTfuCmdOptProcess(LPCMD_LINE_ARGS pcla)
 		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_SHOW_IMG_INFO_OFFLINE))
 		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->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_SHOW_IMG_INFO_OFFLINE);
-			pcla->bIsOffline = true;
 			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
 			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->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_SHOW_IMG_INFO_OFFLINE, _OPT_OPTS_SHOW_IMG_INFO_OFFLINE);
@@ -573,6 +845,11 @@ int GfaTfuCmdOptProcess(LPCMD_LINE_ARGS pcla)
 			pcla->nMissingOptFlags = _GET_MISSING_OPTS(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;
 			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
 		}
 		}
+		if(	(strlen(pcla->pszMaterial) >= GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH) ||
+			(strlen(pcla->pszSerial) >= GFA_APP_MAX_IMG_SERIAL_NUM_LENGTH))
+		{
+			return GFA_FU_ERROR_MAT_OR_SER_TOO_LONG;
+		}
 		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_SET_MAT_SER, _OPT_OPTS_SET_MAT_SER);
 		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_SET_MAT_SER, _OPT_OPTS_SET_MAT_SER);
 		break;
 		break;
 	case _OV_HAS_BOOT_PING:
 	case _OV_HAS_BOOT_PING:
@@ -585,39 +862,128 @@ int GfaTfuCmdOptProcess(LPCMD_LINE_ARGS pcla)
 			return GFA_FU_ERROR_INVALID_COMMAND_OPT;
 			return GFA_FU_ERROR_INVALID_COMMAND_OPT;
 		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_BOOT_PING, _OPT_OPTS_BOOT_PING);
 		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_BOOT_PING, _OPT_OPTS_BOOT_PING);
 		break;
 		break;
+	case _OV_HAS_START_BOOT:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_START_BOOT))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_START_BOOT);
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_START_BOOT, _OPT_OPTS_START_BOOT);
+		break;
+	case _OV_HAS_RESET_BOOT:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_RESET_BOOT))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_RESET_BOOT);
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_RESET_BOOT, _OPT_OPTS_RESET_BOOT);
+		break;
+	case _OV_HAS_RESCUE_BOOT:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_RESCUE_BOOT))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_RESCUE_BOOT);
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_RESCUE_BOOT, _OPT_OPTS_RESCUE_BOOT);
+		break;
+	case _OV_HAS_MODBUS_START_BOOT:
+		if(!_HAS_REQUIRED_OPTIONS(pcla->nOptFlags, _REQ_OPTS_MODBUS_START_BOOT))
+		{
+			pcla->nMissingOptFlags = _GET_MISSING_OPTS(pcla->nOptFlags, _REQ_OPTS_MODBUS_START_BOOT);
+			return GFA_FU_ERROR_MISSING_COMMAND_OPT;
+		}
+		pcla->nUnusedOptFlags = _GET_UNUSED_OPTS(pcla->nOptFlags, _REQ_OPTS_MODBUS_START_BOOT, _OPT_OPTS_MODBUS_START_BOOT) & ~_OV_HAS_SLAVE_ADDR;
+		break;
 	default:
 	default:
-		if(pcla->nOptFlags & (_OV_HAS_SET_MATERIAL | _OV_HAS_SET_SERIAL))
-			return GFA_FU_ERROR_MAT_OR_SER_MISSING;
 		return 1;
 		return 1;
 	}
 	}
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-#if 0
-static void _PrintOptionLine(const char *pszOpt, int nMaxOptLen, char cShortOpt, const char *pszDesc)
+void GfaTfuCmdOptDumpOptions(LPCMD_LINE_ARGS pcla)
 {
 {
-	char szOptBuf[256];
+	if(pcla)
+	{
+		uint32_t nMask, nOpts = 0;
+		TRACE3("****************************\n");
+		TRACE3("COMMAND: %s\n", _GetOptName(pcla->nCmdFlags));
+		TRACE3("OPTIONS:\n");
+
+		switch(pcla->nCmdFlags)
+		{
+		case _OV_HAS_UPLOAD_IMG:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_UPLOAD_IMG | _OPT_OPTS_UPLOAD_IMG) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		case _OV_HAS_SHOW_FILE_IMG_INFO:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_SHOW_IMG_INFO_OFFLINE | _OPT_OPTS_SHOW_IMG_INFO_OFFLINE) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		case _OV_HAS_SHOW_DEV_IMG_INFO:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_SHOW_IMG_INFO_ONLINE | _OPT_OPTS_SHOW_IMG_INFO_ONLINE) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		case _OV_HAS_VALIDATE_IMG:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_VALIDATE_IMG | _OPT_OPTS_VALIDATE_IMG) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		case _OV_HAS_SHOW_MAT_SER:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_SHOW_MAT_SER | _OPT_OPTS_SHOW_MAT_SER) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		case _OV_HAS_SET_MAT_SER:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_SET_MAT_SER | _OPT_OPTS_SET_MAT_SER) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		case _OV_HAS_BOOT_PING:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_BOOT_PING | _OPT_OPTS_BOOT_PING) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		case _OV_HAS_START_BOOT:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_START_BOOT | _OPT_OPTS_START_BOOT) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		case _OV_HAS_RESET_BOOT:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_RESET_BOOT | _OPT_OPTS_RESET_BOOT) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		case _OV_HAS_RESCUE_BOOT:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_RESCUE_BOOT | _OPT_OPTS_RESCUE_BOOT) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		case _OV_HAS_MODBUS_START_BOOT:
+			nOpts = pcla->nOptFlags & (_REQ_OPTS_MODBUS_START_BOOT | _OPT_OPTS_MODBUS_START_BOOT) & ~_OV_HAS_SLAVE_ADDR;
+			break;
+		default:
+			return;
+		}
+
+		for(nMask = 1; nMask; nMask <<= 1)
+		{
+			if(nOpts & nMask)
+			{
+				TRACE3("  %-*s: %s\n", _MAX_OPT_LENGTH, _GetOptName(nMask), _GetOptValue(nMask, pcla));
+			}
+		}
+		if(pcla->nUnusedOptFlags)
+			TRACE3("  %-*s: %s\n", _MAX_OPT_LENGTH, "IGNORED", GfaTfuCmdOpt2String(pcla->nUnusedOptFlags));
+		TRACE3("****************************\n\n");
+	}
 }
 }
-#endif
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 // Examples:
 // 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
+// ./gfativaflashutil --upload-img --itf-name="/dev/ttyO4" --init-baud-rate 9600 -elev-baud-rate 115200 -s1 "/opt/GfA/gfativaflashutil/OLS-1V1_0009_crc_9600Baud.bin" -v3
+// ./gfativaflashutil --validate-img --itf-name="/dev/ttyO4" --app-addr=0x2000 --node-addr=0x11 "/opt/GfA/gfativaflashutil/OLS-1V1_0009_crc.bin" -v3
+// ./gfativaflashutil --show-mat-ser --itf-name="/dev/ttyO4" --stat-num=1 -v3
+// ./gfativaflashutil --set-mat-ser --itf-name="/dev/ttyO4" --elev-baud-rate=115200 --node-addr=0x11 -v3 --material="G.Z.40015 P01" --serial="18-080015 1409"
+// ./gfativaflashutil --show-file-img-info "/opt/GfA/gfativaflashutil/OLS-1V1_0009_crc.bin" -a0x2000 -v3
+// ./gfativaflashutil --show-dev-img-info --itf-name="/dev/ttyO4" --elev-baud-rate=115200 --node-addr=0x11 -v3
+// ./gfativaflashutil --ping-target --ping-int=1 --itf-name="/dev/ttyO4" --node-addr=0x11 -v3
+// ./gfativaflashutil --start-boot --itf-name="/dev/ttyO4" --node-addr=0x11 -v3
+// ./gfativaflashutil --reset-boot --itf-name="/dev/ttyO4" --node-addr=0x11 -v3
+// ./gfativaflashutil --mb-start-boot --itf-name="/dev/ttyO4" --mb-slave-id 100 -v3
+//
 //
 //
 
 
 void GfaTfuCmdOptDisplayHelp(void)
 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("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(" USAGE: gfativaflashutil COMMAND [OPTIONS] [IMG FILE]\n\n");
+
+	printf(" COMMANDS (only one command can be executed at one go):\n");
 	printf("  --%-*s   Upload <IMG FILE> to the device.\n", _MAX_CMD_LENGTH, _OPT_STRING_UPLOAD_IMG);
 	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   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   match the material numbers as well).\n", _MAX_CMD_LENGTH, "");
@@ -627,40 +993,74 @@ void GfaTfuCmdOptDisplayHelp(void)
 	printf("    %-*s   image information of the target device.\n", _MAX_CMD_LENGTH, "");
 	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   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   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("  --%-*s   Set the material and serial number of the\n", _MAX_CMD_LENGTH, _OPT_STRING_SET_MAT_SER);
+	printf("    %-*s   target device.\n", _MAX_CMD_LENGTH, "");
+	printf("  --%-*s   Ping the target device either once or continuously\n", _MAX_CMD_LENGTH, _OPT_STRING_BOOT_PING);
+	printf("    %-*s   dependig on the parameter --%s.\n", _MAX_CMD_LENGTH, "", _OPT_STRING_PING_INTERVAL);
+	printf("  --%-*s   Start the bootloader if an application is running.\n", _MAX_CMD_LENGTH, _OPT_STRING_START_BOOT);
+	printf("  --%-*s   Reset the bootloader if no application is running.\n", _MAX_CMD_LENGTH, _OPT_STRING_RESET_BOOT);
+	printf("    %-*s   If there is a valid application image in flash, it\n", _MAX_CMD_LENGTH, "");
+	printf("    %-*s   will be subsequently started.\n", _MAX_CMD_LENGTH, "");
+	printf("  --%-*s   Start the bootloader if a modbus application is\n", _MAX_CMD_LENGTH, _OPT_STRING_MODBUS_START_BOOT);
+	printf("    %-*s   running.\n", _MAX_CMD_LENGTH, "");
+	printf("  --%-*s   Try to re-establish communication with the bootloader\n", _MAX_CMD_LENGTH, _OPT_STRING_RESCUE_BOOT);
+	printf("    %-*s   if it's in a non-responsive state. This may arise\n", _MAX_CMD_LENGTH, "");
+	printf("    %-*s   after a failed image upload due to an interrupted\n", _MAX_CMD_LENGTH, "");
+	printf("    %-*s   communication line or any transmission failures. It\n", _MAX_CMD_LENGTH, "");
+	printf("    %-*s   seems, that a verbosity of 4 in combination with high\n", _MAX_CMD_LENGTH, "");
+	printf("    %-*s   baud rates can cause this problem.\n", _MAX_CMD_LENGTH, "");
+	printf("\n");
+
 	printf(" OPTIONS:\n");
 	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("  --%-*s -d <INTERFACE> The name of the communication interface.\n", _MAX_OPT_LENGTH, _OPT_STRING_ITF_NAME);
+	printf("  --%-*s -s <STATION>   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>      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 -x <BAUDRATE>  Extended baud-rate to use for some (but not\n", _MAX_OPT_LENGTH, _OPT_STRING_X_BAUD_RATE);
+	printf("    %-*s                all) 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 a\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                great amount 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                Defaults to 0x%X.\n", _MAX_OPT_LENGTH, "", CMD_OPT_DEFAULT_APP_BASE_ADDRESS);
+	printf("  --%-*s    <MATERIAL>  The material number to be set with the\n", _MAX_OPT_LENGTH, _OPT_STRING_MATERIAL);
+	printf("    %-*s                --%s command.\n", _MAX_OPT_LENGTH, "", _OPT_STRING_SET_MAT_SER);
+	printf("  --%-*s    <SERIAL>    The serial number to be set with the\n", _MAX_OPT_LENGTH, _OPT_STRING_SERIAL);
+	printf("    %-*s                --%s command.\n", _MAX_OPT_LENGTH, "", _OPT_STRING_SET_MAT_SER);
+	printf("  --%-*s -p <BLOCK SIZE Size of an upload-block in bytes. (4-76,\n", _MAX_OPT_LENGTH, _OPT_STRING_BLOCK_SIZE);
+	printf("    %-*s                must be a multiple of 4!). This option is\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                only used with the --%s command.\n", _MAX_OPT_LENGTH, "", _OPT_STRING_UPLOAD_IMG);
+	printf("    %-*s                Defaults to %d. There is usually no need\n", _MAX_OPT_LENGTH, "", GFA_BOOTLOADER_DEF_SEND_DATA_BLOCK_SIZE);
+	printf("    %-*s                to alter this value.\n", _MAX_OPT_LENGTH, "");
+	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\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                will be made every <SECONDS> seconds. If\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                the value is 0 (the default), only one ping\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                will be executed. Use Ctrl + 'C' to abort a\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                continuous ping.\n", _MAX_OPT_LENGTH, "");
+	printf("  --%-*s                Don't show block upload progress. This\n", _MAX_OPT_LENGTH, _OPT_STRING_NO_SHOW_PROGRESS);
+	printf("    %-*s                option is especially useful when redirecting\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                the program output to a file.\n", _MAX_OPT_LENGTH, "");
+	printf("  --%-*s -e <MILLISEC>  Timeout in milliseconds for erasing one\n", _MAX_OPT_LENGTH, _OPT_STRING_PAGE_ERASE_TIME);
+	printf("    %-*s                flash page (usually 1 Kb). This value will\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                be multiplied with the number of pages to\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                be erased. This option is only used with\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                the --%s command. Defaults to %d ms.\n", _MAX_OPT_LENGTH, "", _OPT_STRING_UPLOAD_IMG, CMD_OPT_DEFAULT_PAGE_ERASE_TIME);
+	printf("    %-*s                It's usually not necessary to increase this\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                value.\n", _MAX_OPT_LENGTH, "");
+	printf("  --%-*s    <SLAVEID>   The address of the modbus slave, if there is\n", _MAX_OPT_LENGTH, _OPT_STRING_MODBUS_SLAVE_ID);
+	printf("    %-*s                any. This option is only used with the\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                --%s command.\n", _MAX_OPT_LENGTH, "", _OPT_STRING_MODBUS_START_BOOT);
+	printf("  --%-*s    <REGISTER>  Address of the first of the modbus registers\n", _MAX_OPT_LENGTH, _OPT_STRING_MODBUS_CTRL_REG);
+	printf("    %-*s                that control the start of the bootloader.\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                This option is only used with the\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                --%s command. Defaults to %d.\n", _MAX_OPT_LENGTH, "", _OPT_STRING_MODBUS_START_BOOT, CMD_OPT_DEFAULT_MODBUS_START_REGISTER);
+	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. Be careful using a\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                verbosity of 4 with commands that can cause\n", _MAX_OPT_LENGTH, "");
+	printf("    %-*s                heavy data transfer like --%s!\n", _MAX_OPT_LENGTH, "", _OPT_STRING_UPLOAD_IMG);
+	printf("  --%-*s -?             Show this help\n", _MAX_OPT_LENGTH, _OPT_STRING_HELP);
 	printf("\n");
 	printf("\n");
 }
 }
-
-/*
-	printf("    %-*s   \n", _MAX_CMD_LENGTH, "");
-	printf("    %-*s   \n", _MAX_OPT_LENGTH, "");
-*/

+ 46 - 17
cmdopt.h

@@ -4,6 +4,9 @@
 #if !defined(AGD_CMDOPT_H__7551B3DB_D0BF_4746_A615_1BD0DC828D23__INCLUDED_)
 #if !defined(AGD_CMDOPT_H__7551B3DB_D0BF_4746_A615_1BD0DC828D23__INCLUDED_)
 #define AGD_CMDOPT_H__7551B3DB_D0BF_4746_A615_1BD0DC828D23__INCLUDED_
 #define AGD_CMDOPT_H__7551B3DB_D0BF_4746_A615_1BD0DC828D23__INCLUDED_
 
 
+#include <stdint.h>
+#include <stdbool.h>
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif	//	__cplusplus
 #endif	//	__cplusplus
@@ -16,28 +19,41 @@ extern "C" {
 #define CMD_OPT_MAX_VERBOSITY						4
 #define CMD_OPT_MAX_VERBOSITY						4
 #define CMD_OPT_DEFAULT_VERBOSITY					2
 #define CMD_OPT_DEFAULT_VERBOSITY					2
 #define CMD_OPT_DEFAULT_BAUDRATE					19200
 #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
+#define CMD_OPT_DEFAULT_PAGE_ERASE_TIME				20
+#define CMD_OPT_DEFAULT_APP_BASE_ADDRESS			0x2000
+#define CMD_OPT_DEFAULT_MODBUS_START_REGISTER		46
+#define CMD_OPT_DEFAULT_MODBUS_PARITY				'E'
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
 typedef enum _OptValues
 typedef enum _OptValues
 {
 {
 	ov_img_file			= 1,
 	ov_img_file			= 1,
-	ov_itf_name,
 	ov_show_dev_img_info,
 	ov_show_dev_img_info,
 	ov_show_file_img_info,
 	ov_show_file_img_info,
-	ov_show_mat_ser,
 	ov_validate_img,
 	ov_validate_img,
 	ov_upload_img,
 	ov_upload_img,
+	ov_show_mat_ser,
+	ov_set_mat_ser,
 	ov_boot_ping,
 	ov_boot_ping,
-	ov_set_material,
-	ov_set_serial,
-	ov_block_size,
+	ov_start_boot,
+	ov_reset_boot,
+	ov_rescue_boot,
+	ov_mb_start_boot,
+	ov_material,
+	ov_serial,
+	ov_no_progress,
+//	ov_init_baud_rate,
+//	ov_mb_baud_rate,
+//	ov_mb_parity,
+	ov_mb_slave_id,
+	ov_mb_ctrl_reg,
+	ov_x_baud_rate		= 'x',
+	ov_page_erase_time	= 'e',
+	ov_itf_name			= 'd',
+	ov_block_size		= 'p',
 	ov_ping_interval	= 'i',
 	ov_ping_interval	= 'i',
 	ov_app_addr			= 'a',
 	ov_app_addr			= 'a',
-	ov_baud_rate		= 'b',
 	ov_station_number	= 's',
 	ov_station_number	= 's',
 	ov_node_addr		= 'n',
 	ov_node_addr		= 'n',
 	ov_verbosity		= 'v',
 	ov_verbosity		= 'v',
@@ -50,6 +66,7 @@ typedef struct _CMD_LINE_ARGS
 {
 {
 	uint8_t nNodeAddr;
 	uint8_t nNodeAddr;
 	uint8_t nStationNr;
 	uint8_t nStationNr;
+	uint8_t nModbusSlvID;
 	bool bShowHelp;
 	bool bShowHelp;
 	bool bShowDevImgInfo;
 	bool bShowDevImgInfo;
 	bool bShowFileImgInfo;
 	bool bShowFileImgInfo;
@@ -58,31 +75,43 @@ typedef struct _CMD_LINE_ARGS
 	bool bValidateImg;
 	bool bValidateImg;
 	bool bUploadImg;
 	bool bUploadImg;
 	bool bPing;
 	bool bPing;
-	bool bIsOffline;
+	bool bStartBoot;
+	bool bResetBoot;
+	bool bReviveBoot;
 	bool bNeedImgFile;
 	bool bNeedImgFile;
+	bool bNoProgressBlock;
+	bool bModbusStartBoot;
+	uint8_t modbParity;
+	int16_t nModbusCtrlReg;
 	int32_t nPingIntervalSec;
 	int32_t nPingIntervalSec;
-	uint32_t nBaudrate;
+	uint32_t nBootBaudrate;
+	uint32_t nInitBaudrate;
+	uint32_t nElevBaudrate;
+	uint32_t nModbBaudrate;
 	uint32_t nBlockSize;
 	uint32_t nBlockSize;
 	uint32_t nStartAddr;
 	uint32_t nStartAddr;
+	uint32_t nPageErsaeTime;
 	const char *pszDevName;
 	const char *pszDevName;
 	const char *pszImgFile;
 	const char *pszImgFile;
+	const char *pszImgFileBase;
 	const char *pszMaterial;
 	const char *pszMaterial;
 	const char *pszSerial;
 	const char *pszSerial;
-	int nVerbosity;
 	uint32_t nOptFlags;
 	uint32_t nOptFlags;
 	uint32_t nCmdFlags;
 	uint32_t nCmdFlags;
 	uint32_t nMissingOptFlags;
 	uint32_t nMissingOptFlags;
 	uint32_t nUnusedOptFlags;
 	uint32_t nUnusedOptFlags;
+	int nVerbosity;
 }CMD_LINE_ARGS, *LPCMD_LINE_ARGS;
 }CMD_LINE_ARGS, *LPCMD_LINE_ARGS;
 typedef const CMD_LINE_ARGS *LPCCMD_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);
+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		GfaTfuCmdOptDumpOptions(LPCMD_LINE_ARGS pcla);
+void		GfaTfuCmdOptDisplayHelp(void);
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 21 - 1
error.c

@@ -11,6 +11,8 @@ const char* GfaTfuStrError(int nError)
 		return "Invalid command line argument";
 		return "Invalid command line argument";
 	case GFA_FU_ERROR_INVALID_BAUDRATE:
 	case GFA_FU_ERROR_INVALID_BAUDRATE:
 		return "Invalid baudrate";
 		return "Invalid baudrate";
+	case GFA_FU_ERROR_INVALID_PARITY:
+		return "Invalid parity";
 	case GFA_FU_ERROR_INVALID_NODE_ADDR:
 	case GFA_FU_ERROR_INVALID_NODE_ADDR:
 		return "Invalid node address";
 		return "Invalid node address";
 	case GFA_FU_ERROR_INVALID_STATION_NUM:
 	case GFA_FU_ERROR_INVALID_STATION_NUM:
@@ -25,6 +27,8 @@ const char* GfaTfuStrError(int nError)
 		return "Either a node address or a station number may be provided";
 		return "Either a node address or a station number may be provided";
 	case GFA_FU_ERROR_MAT_OR_SER_MISSING:
 	case GFA_FU_ERROR_MAT_OR_SER_MISSING:
 		return "Both material and serial number must be provided";
 		return "Both material and serial number must be provided";
+	case GFA_FU_ERROR_MAT_OR_SER_TOO_LONG:
+		return "Material or serial number too long";
 	case GFA_FU_ERROR_IMG_HEADER_NOT_FOUND:
 	case GFA_FU_ERROR_IMG_HEADER_NOT_FOUND:
 		return "Image file header not found";
 		return "Image file header not found";
 	case GFA_FU_ERROR_INVALID_IMG_SIZE:
 	case GFA_FU_ERROR_INVALID_IMG_SIZE:
@@ -32,7 +36,7 @@ const char* GfaTfuStrError(int nError)
 	case GFA_FU_ERROR_INVALID_IMG_CRC32:
 	case GFA_FU_ERROR_INVALID_IMG_CRC32:
 		return "Invalid image CRC32";
 		return "Invalid image CRC32";
 	case GFA_FU_ERROR_MATERIAL_NUM_NO_MATCH:
 	case GFA_FU_ERROR_MATERIAL_NUM_NO_MATCH:
-		return "Image material number does not match EEPROM";
+		return "Image material number does not match the target";
 	case GFA_FU_ERROR_MULTIPLE_COMMANDS:
 	case GFA_FU_ERROR_MULTIPLE_COMMANDS:
 		return "Multiple commands not allowed";
 		return "Multiple commands not allowed";
 	case GFA_FU_ERROR_INVALID_COMMAND_OPT:
 	case GFA_FU_ERROR_INVALID_COMMAND_OPT:
@@ -41,6 +45,22 @@ const char* GfaTfuStrError(int nError)
 		return "Missing required option(s)";
 		return "Missing required option(s)";
 	case GFA_FU_ERROR_INVALID_APP_START_ADDR:
 	case GFA_FU_ERROR_INVALID_APP_START_ADDR:
 		return "Invalid app start address";
 		return "Invalid app start address";
+	case GFA_MB_ERROR_ILLEGAL_FUNCTION:
+		return "Invalid modbus function";
+	case GFA_MB_ERROR_ILLEGAL_DATA_ADDRESS:
+		return "Invalid modbus data address";
+	case GFA_MB_ERROR_ILLEGAL_DATA_VALUE:
+		return "Illegal modbus data value";
+	case GFA_MB_ERROR_SLAVE_DEVICE_FAILURE:
+		return "Modbus slave device failure";
+	case GFA_MB_ERROR_ACKNOWLEDGE:
+		return "Modbus error acknowledge";
+	case GFA_MB_ERROR_SLAVE_DEVICE_BUSY:
+		return "Modbus slave device busy";
+	case GFA_MB_ERROR_NEGATIVE_ACKNOWLEDGE:
+		return "Modbus error negative acknowledge";
+	case GFA_MB_ERROR_MEMORY_PARITY_ERROR:
+		return "Modbus parity error";
 	default:
 	default:
 		return GfaBlmStrError(nError);
 		return GfaBlmStrError(nError);
 	}
 	}

+ 17 - 5
error.h

@@ -13,6 +13,7 @@ extern "C" {
 
 
 #define MAKE_GFA_FU_ERROR(c)					(0x81000000 | c)
 #define MAKE_GFA_FU_ERROR(c)					(0x81000000 | c)
 #define MAKE_GFA_IMG_ERROR(c)					(0x82000000 | c)
 #define MAKE_GFA_IMG_ERROR(c)					(0x82000000 | c)
+#define MAKE_GFA_MODBUS_ERROR(c)				(0x84000000 | c)
 
 
 #define GFA_FU_ERROR_INVALID_CMDLINE_ARG		MAKE_GFA_FU_ERROR(1)
 #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_BAUDRATE			MAKE_GFA_FU_ERROR(2)
@@ -22,11 +23,12 @@ extern "C" {
 #define GFA_FU_ERROR_INVALID_DEVICE_NAME		MAKE_GFA_FU_ERROR(6)
 #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_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_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_MAT_OR_SER_TOO_LONG		MAKE_GFA_FU_ERROR(9)
+#define GFA_FU_ERROR_MULTIPLE_COMMANDS			MAKE_GFA_FU_ERROR(10)
+#define GFA_FU_ERROR_INVALID_COMMAND_OPT		MAKE_GFA_FU_ERROR(11)
+#define GFA_FU_ERROR_MISSING_COMMAND_OPT		MAKE_GFA_FU_ERROR(12)
+#define GFA_FU_ERROR_INVALID_APP_START_ADDR		MAKE_GFA_FU_ERROR(13)
+#define GFA_FU_ERROR_INVALID_PARITY				MAKE_GFA_FU_ERROR(14)
 #define GFA_FU_ERROR_NOTHING_TO_DO				MAKE_GFA_FU_ERROR(20)
 #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_IMG_HEADER_NOT_FOUND		MAKE_GFA_IMG_ERROR(1)
@@ -34,6 +36,16 @@ extern "C" {
 #define GFA_FU_ERROR_INVALID_IMG_CRC32			MAKE_GFA_IMG_ERROR(3)
 #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)
 #define GFA_FU_ERROR_MATERIAL_NUM_NO_MATCH		MAKE_GFA_IMG_ERROR(4)
 
 
+
+#define GFA_MB_ERROR_ILLEGAL_FUNCTION			MAKE_GFA_MODBUS_ERROR(1)
+#define GFA_MB_ERROR_ILLEGAL_DATA_ADDRESS		MAKE_GFA_MODBUS_ERROR(2)
+#define GFA_MB_ERROR_ILLEGAL_DATA_VALUE			MAKE_GFA_MODBUS_ERROR(3)
+#define GFA_MB_ERROR_SLAVE_DEVICE_FAILURE		MAKE_GFA_MODBUS_ERROR(4)
+#define GFA_MB_ERROR_ACKNOWLEDGE				MAKE_GFA_MODBUS_ERROR(5)
+#define GFA_MB_ERROR_SLAVE_DEVICE_BUSY			MAKE_GFA_MODBUS_ERROR(6)
+#define GFA_MB_ERROR_NEGATIVE_ACKNOWLEDGE		MAKE_GFA_MODBUS_ERROR(7)
+#define GFA_MB_ERROR_MEMORY_PARITY_ERROR		MAKE_GFA_MODBUS_ERROR(8)
+
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
 const char* GfaTfuStrError(int nError);
 const char* GfaTfuStrError(int nError);

+ 4 - 2
gfativaflashutil.pro

@@ -29,11 +29,13 @@ SOURCES += main.c \
     image.c \
     image.c \
     cmdopt.c \
     cmdopt.c \
     error.c \
     error.c \
-    output.c
+    output.c \
+    modbmst.c
 
 
 HEADERS += \
 HEADERS += \
     main.h \
     main.h \
     image.h \
     image.h \
     cmdopt.h \
     cmdopt.h \
     error.h \
     error.h \
-    output.h
+    output.h \
+    modbmst.h

+ 36 - 30
image.c

@@ -129,44 +129,50 @@ static bool _MatchWildcardStrings(const char *pszMatNumEEPROM, const char *pszMa
 
 
 HIMGFILE GfaTfuImageFileOpen(const char *pszFilename, uint32_t nStartAddr, bool bReadOnly)
 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))
+	if(pszFilename && *pszFilename)
 	{
 	{
-		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)
+		struct stat stat;
+		int oflag = (bReadOnly ? O_RDONLY : O_RDWR) | O_EXCL;
+		int fd = open(pszFilename, oflag);
+
+		if(	(fd >= 0) &&
+			(fstat(fd, &stat) == 0))
 		{
 		{
-			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));
+			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((pIf->paih = GfaTfuImageFileLookupImgInfo(pIf, &pIf->ii)))
+			if(p != MAP_FAILED)
 			{
 			{
-				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;
-			}
+				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));
 
 
-			nErr = errno;
-			GfaTfuImageFileClose(pIf);
-			errno = nErr;
+				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;
 	}
 	}
 
 
+	errno = EINVAL;
 	return NULL;
 	return NULL;
 }
 }
 
 

+ 6 - 6
image.h

@@ -18,13 +18,13 @@ 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);
+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);
+bool		GfaTfuImageFileMatchMaterialNum(HIMGFILE hIf, const char *pszImgMaterialNum);
 LPCGFA_APP_IMG_HEADER GfaTfuImageFileLookupImgInfo(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
 #ifdef __cplusplus

+ 890 - 131
main.c

@@ -8,26 +8,43 @@
 #include <ctype.h>
 #include <ctype.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <stddef.h>
 #include <stddef.h>
+#include <signal.h>
 #include <time.h>
 #include <time.h>
 #include <errno.h>
 #include <errno.h>
 #include <getopt.h>
 #include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <gfaserial.h>
 #include <gfaserial.h>
 #include <gfabootlmast.h>
 #include <gfabootlmast.h>
 #include "main.h"
 #include "main.h"
 #include "cmdopt.h"
 #include "cmdopt.h"
 #include "image.h"
 #include "image.h"
-#include "error.h"
 #include "output.h"
 #include "output.h"
+#include "modbmst.h"
+#include "error.h"
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
-static int _UploadImg(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
+#define _AUTO_BAUD					1
+#define _MODBUS_DETECT				1
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define _ABBR_BOOTLOADER			"Boot"
+#define _ABBR_APPLICATION			"Appl"
+#define _ABBR_MININET				"MiNe"
+#define _ABBR_MODBUS				"ModB"
+
+/////////////////////////////////////////////////////////////////////////////
+
+static bool							g_bSig = false;
+
+/////////////////////////////////////////////////////////////////////////////
+
+static void _SigHandler(int sig)
 {
 {
-	UNUSED(hIf);
-	UNUSED(hBlm);
-	UNUSED(pcla);
-	UNUSED(ctx);
-	return 0;
+	g_bSig = !!sig;
+	TRACE3("\n");
 }
 }
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
@@ -47,34 +64,67 @@ static int _ShowDevImgInfo(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GF
     }
     }
     else
     else
 	{
 	{
-        if(pcla->nBaudrate != CMD_OPT_DEFAULT_BAUDRATE)
+		bool bStartApp = false;
+
+		if(ctx == GfaBlmCtx_App)
+		{
+			TRACE3("Application doesn't recognize BI command!\n");
+			TRACE3("Starting bootloader.\n");
+
+			if((nRet = GfaBlmBootloaderExecute(hBlm, pcla->nNodeAddr, NULL, 1000)) != 0)
+			{
+				TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+				return nRet;
+			}
+
+			bStartApp = true;
+		}
+
+        if(pcla->nElevBaudrate != pcla->nInitBaudrate)
         {
         {
-			TRACE3("Setting baudrate to %u.\n", pcla->nBaudrate);
+			TRACE3("Setting baud-rate to %u.\n", pcla->nElevBaudrate);
 
 
-			if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, pcla->nNodeAddr, pcla->nBaudrate)) != 0)
+			if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, pcla->nNodeAddr, pcla->nElevBaudrate)) != 0)
 			{
 			{
-				TRACE1("%s!\n", GfaTfuStrError(errno));
+				TRACE1("Error: %s!\n", GfaTfuStrError(errno));
 				return nRet;
 				return nRet;
 	        }
 	        }
         }
         }
 
 
-		if((nRet = GfaBlmGetInfoBD(hBlm, pcla->nNodeAddr, &aii)) > -2)
+		if((nRet = GfaBlmGetInfoBD(hBlm, pcla->nNodeAddr, pcla->nStartAddr, &aii)) > -2)
 		{
 		{
 	    	GfaTfuDumpImageInfo("Bootloader", &aii.bl);
 	    	GfaTfuDumpImageInfo("Bootloader", &aii.bl);
 	    	GfaTfuDumpImageInfo("Application", &aii.app);
 	    	GfaTfuDumpImageInfo("Application", &aii.app);
 	    }
 	    }
+	    else
+	    {
+			TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+			return nRet;
+	    }
 
 
-        if(pcla->nBaudrate != CMD_OPT_DEFAULT_BAUDRATE)
+        if(pcla->nElevBaudrate != pcla->nInitBaudrate)
         {
         {
-			TRACE3("Setting baudrate to %u.\n", CMD_OPT_DEFAULT_BAUDRATE);
+			TRACE3("Setting baud-rate to %u.\n", pcla->nInitBaudrate);
 
 
-			if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, pcla->nNodeAddr, CMD_OPT_DEFAULT_BAUDRATE)) != 0)
+			if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, pcla->nNodeAddr, pcla->nInitBaudrate)) != 0)
 			{
 			{
-				TRACE1("%s!\n", GfaTfuStrError(errno));
+				TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+				return nRet;
+	        }
+        }
+
+        if(bStartApp)
+        {
+			TRACE3("Starting application.\n");
+
+            if((nRet = GfaBlmBUCmdReset(hBlm, pcla->nNodeAddr, pcla->nInitBaudrate)) != 0)
+	        {
+				TRACE1("Error: %s!\n", GfaTfuStrError(errno));
 				return nRet;
 				return nRet;
 	        }
 	        }
         }
         }
     }
     }
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -82,10 +132,31 @@ static int _ShowDevImgInfo(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GF
 
 
 static int _ValidateImg(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 static int _ValidateImg(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 {
 {
-	UNUSED(hIf);
-	UNUSED(hBlm);
-	UNUSED(pcla);
+	int nRet;
+   	GFA_IMG_INFO ii;
+	char szMaterial[16], szSerial[16];
 	UNUSED(ctx);
 	UNUSED(ctx);
+
+	TRACE3("Reading material number.\n");
+
+	if((nRet = GfaBlmReadMaterialAndSerialID(hBlm, pcla->nNodeAddr, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) != 0)
+	{
+		TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+		return nRet;
+	}
+
+	GfaTfuImageFileGetInfo(hIf, &ii);
+
+	TRACE2("Material number target: \"%s\"\n", szMaterial);
+	TRACE2("Material number file:   \"%s\"\n", ii.szImgMaterialNum);
+
+	if(!GfaTfuImageFileMatchMaterialNum(hIf, szMaterial))
+	{
+		TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+		return -1;
+	}
+
+	TRACE2("\"%s\" - Image is valid for target @ node 0x%02hhX!\n", pcla->pszImgFileBase, pcla->nNodeAddr);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -94,7 +165,7 @@ static int _ValidateImg(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_B
 static int _ShowMatSer(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 static int _ShowMatSer(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 {
 {
 	int nRet;
 	int nRet;
-	char szMaterial[16], szSerial[16];
+	char szMaterial[GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH], szSerial[GFA_APP_MAX_IMG_SERIAL_NUM_LENGTH];
 	UNUSED(hIf);
 	UNUSED(hIf);
 	UNUSED(ctx);
 	UNUSED(ctx);
 
 
@@ -102,13 +173,18 @@ static int _ShowMatSer(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BL
 
 
 	if((nRet = GfaBlmReadMaterialAndSerialID(hBlm, pcla->nNodeAddr, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) != 0)
 	if((nRet = GfaBlmReadMaterialAndSerialID(hBlm, pcla->nNodeAddr, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) != 0)
 	{
 	{
-		TRACE1("%s!\n", GfaTfuStrError(errno));
+		TRACE1("Error: %s!\n", GfaTfuStrError(errno));
 		return nRet;
 		return nRet;
 	}
 	}
 
 
+	if(szMaterial[0] == '\xFF')
+		strcpy(szMaterial, "not set");
+	if(szSerial[0] == '\xFF')
+		strcpy(szSerial, "not set");
+
 	TRACE2("Material and Serial number:\n");
 	TRACE2("Material and Serial number:\n");
-	TRACE2("  Mat.Nr.: %s\n", szMaterial);
-	TRACE2("  Serial:  %s\n", szSerial);
+	TRACE2("  Mat.Nr.: \"%s\"\n", szMaterial);
+	TRACE2("  Serial:  \"%s\"\n", szSerial);
 	return nRet;
 	return nRet;
 }
 }
 
 
@@ -116,38 +192,686 @@ static int _ShowMatSer(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BL
 
 
 static int _SetMatSer(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 static int _SetMatSer(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 {
 {
+	int nRet;
+	bool bStartApp = false;
+
+	if(ctx == GfaBlmCtx_App)
+	{
+		TRACE3("Starting bootloader.\n");
+
+		if((nRet = GfaBlmBootloaderExecute(hBlm, pcla->nNodeAddr, NULL, 1000)) != 0)
+		{
+			TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+			return nRet;
+		}
+
+		bStartApp = true;
+	}
+
+	TRACE3("Setting material and serial number.\n");
+	TRACE2("  Mat.Nr.: \"%s\"\n", pcla->pszMaterial);
+	TRACE2("  Serial:  \"%s\"\n", pcla->pszSerial);
+
+	if((nRet = GfaBlmWriteMaterialAndSerialID(hBlm, pcla->nNodeAddr, pcla->pszMaterial, pcla->pszSerial)) != 0)
+	{
+		TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+		return nRet;
+	}
+
+	TRACE2("Material and serial number successfully set!\n");
+
+    if(bStartApp)
+    {
+		TRACE3("Starting application.\n");
+
+        if((nRet = GfaBlmBUCmdReset(hBlm, pcla->nNodeAddr, pcla->nInitBaudrate)) != 0)
+        {
+			TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+			return nRet;
+        }
+    }
+
+	return _ShowMatSer(hIf, hBlm, pcla, ctx);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static int _Ping(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
+{
+	int nRet;
+	time_t t;
+	char szTime[64];
+	struct timespec tsStart, tsEnd, ts = {0, 0};
+	int64_t nIntervalBoot = 0, nIntervalMini = 0, nIntervalModB = 0;
+	HGFAMINEMST hMst	= GfaBlmGetMininetMasterHandle(hBlm);
+	HMINETDEV hDev		= GfaMininetMasterGetDeviceHandle(hMst);
+	HGFAMBMST hMbm		= NULL;
+	GFA_SER_CFG_PARAMS scp, scpSave;
 	UNUSED(hIf);
 	UNUSED(hIf);
-	UNUSED(hBlm);
-	UNUSED(pcla);
-	UNUSED(ctx);
+
+	if(ctx == GfaBlmCtx_ModB)
+	{
+		if(!(hMbm = GfaMbMstOpen(hDev)))
+			return -1;
+
+		if(GfaMininetDeviceGetConfigParams(hDev, &scp, sizeof(scp)) != sizeof(scp))
+		{
+			GfaMbMstClose(hMbm);
+			return -1;
+		}
+
+		memcpy(&scpSave, &scp, sizeof(scpSave));
+		scp.parity	= pcla->modbParity;
+		scp.baud	= pcla->nModbBaudrate;
+
+		if(GfaMininetDeviceSetConfigParams(hDev, &scp, sizeof(scp)) != 0)
+		{
+			GfaMbMstClose(hMbm);
+			return -1;
+		}
+	}
+
+	do
+	{
+		t = time(NULL);
+		strftime(szTime, sizeof(szTime), "%T", localtime(&t));
+		GfaTfuGetClock(&tsStart);
+		
+		if(ctx == GfaBlmCtx_ModB)
+		{
+			if((nRet = GfaMbMstPing(hMbm, pcla->nModbusSlvID)) == 0)
+			{
+				GfaTfuGetClock(&tsEnd);
+				nIntervalModB = GfaTfuClockDiff(&tsEnd, &tsStart);
+				TRACE2("Slave 0x%02hhX [%s] ping success [%.1f ms] - %s.\n", pcla->nModbusSlvID, _ABBR_MODBUS, (double)nIntervalModB / 1000000.0, szTime);
+			}
+			else
+			{
+				TRACE1("Slave 0x%02hhX [%s] ping error: %s - %s.\n", pcla->nModbusSlvID, _ABBR_MODBUS, GfaTfuStrError(errno), szTime);
+			}
+		}
+		else if((nRet = GfaBlmMininetPing(hBlm, pcla->nNodeAddr)) == 0)
+		{
+			GfaTfuGetClock(&tsEnd);
+			nIntervalMini = GfaTfuClockDiff(&tsEnd, &tsStart);
+			GfaTfuGetClock(&tsStart);
+
+			if((nRet = GfaBlmBUCmdPing(hBlm, pcla->nNodeAddr)) != 0)
+			{
+				if(	(ctx == GfaBlmCtx_Boot) ||
+					(errno != -MINET_SLAVE_STATUS_INDEX_INVALID_PARAM))
+				{
+					if(errno == -MINET_SLAVE_STATUS_INDEX_ERROR)
+					{
+						if((nRet = GfaBlmResetSlaveIndex(hBlm, pcla->nNodeAddr)) != 0)
+				        {
+							TRACE1("Node 0x%02hhX [%s] ping error: %s - %s.\n", pcla->nNodeAddr, (ctx == GfaBlmCtx_Boot) ? _ABBR_BOOTLOADER : _ABBR_APPLICATION, GfaTfuStrError(errno), szTime);
+							break;
+				        }
+
+				        if((ctx = GfaBlmGetExecutionContext(hBlm, pcla->nNodeAddr)) == GfaBlmCtx_Err)
+				        {
+							TRACE1("Node 0x%02hhX ping error: %s - %s.\n", pcla->nNodeAddr, GfaTfuStrError(errno), szTime);
+							break;
+				        }
+
+				        continue;
+					}
+				}
+				else
+				{
+					nRet = 0;
+				}
+			}
+
+			if(nRet == 0)
+			{
+				GfaTfuGetClock(&tsEnd);
+				nIntervalBoot = GfaTfuClockDiff(&tsEnd, &tsStart);
+				TRACE2("Node 0x%02hhX [%s] ping success [%.1f ms] - %s.\n", pcla->nNodeAddr, (ctx == GfaBlmCtx_Boot) ? _ABBR_BOOTLOADER : _ABBR_APPLICATION, (double)nIntervalBoot / 1000000.0, szTime);
+			}
+			else
+			{
+				TRACE2("Node 0x%02hhX [%s] ping success [%.1f ms] - %s.\n", pcla->nNodeAddr, _ABBR_MININET, (double)nIntervalMini / 1000000.0, szTime);
+				TRACE1("Node 0x%02hhX [%s] ping error: %s - %s.\n", pcla->nNodeAddr, (ctx == GfaBlmCtx_Boot) ? _ABBR_BOOTLOADER : _ABBR_APPLICATION, GfaTfuStrError(errno), szTime);
+			}
+		}
+		else
+		{
+			if(errno == -MINET_SLAVE_STATUS_INDEX_ERROR)
+			{
+				if((nRet = GfaBlmResetSlaveIndex(hBlm, pcla->nNodeAddr)) != 0)
+		        {
+					TRACE1("Node 0x%02hhX [%s] ping error: %s - %s.\n", pcla->nNodeAddr, (ctx == GfaBlmCtx_Boot) ? _ABBR_BOOTLOADER : _ABBR_APPLICATION, GfaTfuStrError(errno), szTime);
+					break;
+		        }
+
+		        continue;
+		    }
+
+			TRACE1("Node 0x%02hhX [%s] ping error: %s - %s.\n", pcla->nNodeAddr, _ABBR_MININET, GfaTfuStrError(errno), szTime);
+		}
+
+		if(pcla->nPingIntervalSec > 0)
+		{
+			ts.tv_sec = pcla->nPingIntervalSec;
+			if(nanosleep(&ts, NULL) < 0)
+				break;
+		}
+	}
+	while(pcla->nPingIntervalSec && !g_bSig);
+
+	if(hMbm)
+	{
+		GfaMbMstClose(hMbm);
+
+		if(GfaMininetDeviceSetConfigParams(hDev, &scpSave, sizeof(scpSave)) != 0)
+			return -1;
+	}
+	return nRet;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static int _UploadImg(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
+{
+	int nRet;
+	uint32_t nCntFlashPages;
+	size_t nImgLength;
+	const void *pImgData;
+
+	if((nRet = _ValidateImg(hIf, hBlm, pcla, ctx)) == 0)
+	{
+		if(ctx == GfaBlmCtx_App)
+		{
+			TRACE3("Starting bootloader.\n");
+
+			if((nRet = GfaBlmBootloaderExecute(hBlm, pcla->nNodeAddr, NULL, 1000)) != 0)
+			{
+				TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+				return nRet;
+			}
+		}
+
+        if(pcla->nElevBaudrate != pcla->nBootBaudrate)
+        {
+			TRACE3("Setting baud-rate to %u.\n", pcla->nElevBaudrate);
+
+			if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, pcla->nNodeAddr, pcla->nElevBaudrate)) != 0)
+			{
+				TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+				return nRet;
+	        }
+        }
+
+		pImgData		= GfaTfuImageFileGetData(hIf);
+		nImgLength		= GfaTfuImageFileGetSize(hIf);
+		nCntFlashPages	= (nImgLength + GFA_BOOTLOADER_FLASH_PAGE_SIZE - 1) / GFA_BOOTLOADER_FLASH_PAGE_SIZE;
+
+        if((nRet = GfaBlmBUCmdDownload(hBlm, pcla->nNodeAddr, pcla->nStartAddr, nImgLength, nCntFlashPages * pcla->nPageErsaeTime)) == 0)
+        {
+	    	if((nRet = GfaBlmBUCmdSendData(hBlm, pcla->nNodeAddr, pImgData, nImgLength, pcla->nBlockSize)) != 0)
+	    	{
+		        if(pcla->nElevBaudrate != pcla->nBootBaudrate)
+		        {
+					TRACE3("Trying to reset baud-rate to %u.\n", pcla->nBootBaudrate);
+
+					if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, pcla->nNodeAddr, pcla->nBootBaudrate)) != 0)
+					{
+						TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+			        }
+		        }
+
+				return -1;
+	    	}
+	    }
+	    else
+        {
+	        if(pcla->nElevBaudrate != pcla->nBootBaudrate)
+	        {
+				TRACE3("Trying to reset baud-rate to %u.\n", pcla->nBootBaudrate);
+
+				if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, pcla->nNodeAddr, pcla->nBootBaudrate)) != 0)
+				{
+					TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+		        }
+	        }
+
+			return -1;
+        }
+
+		TRACE3("Starting application.\n");
+
+        if((nRet = GfaBlmBUCmdReset(hBlm, pcla->nNodeAddr, pcla->nInitBaudrate)) != 0)
+        {
+			TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+			return nRet;
+        }
+	}
+
+	return nRet;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static int _StartBootloader(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
+{
+	int nRet;
+	UNUSED(hIf);
+
+	if(ctx == GfaBlmCtx_Boot)
+	{
+		TRACE2("Bootloader already executing!\n");
+		return 0; // no error
+	}
+
+	TRACE3("Starting bootloader.\n");
+
+	if((nRet = GfaBlmBootloaderExecute(hBlm, pcla->nNodeAddr, NULL, 1000)) != 0)
+	{
+		TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+		return nRet;
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
-static int _Ping(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
+static int _ResetBootloader(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
 {
 {
+	int nRet;
 	UNUSED(hIf);
 	UNUSED(hIf);
-	UNUSED(hBlm);
-	UNUSED(pcla);
-	UNUSED(ctx);
+
+	if(ctx == GfaBlmCtx_App)
+	{
+		TRACE2("Application already executing!\n");
+		return 0; // no error
+	}
+
+	TRACE3("Resetting bootloader.\n");
+
+    if((nRet = GfaBlmBUCmdReset(hBlm, pcla->nNodeAddr, pcla->nInitBaudrate)) != 0)
+    {
+		TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+		return nRet;
+    }
+
+#if 0
+	TRACE3("Detecting running image.\n");
+
+    if((ctx = GfaBlmGetExecutionContext(hBlm, pcla->nNodeAddr)) == GfaBlmCtx_Err)
+    {
+		TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+		return nRet;
+    }
+
+    TRACE3("Currently running: %s.\n", (ctx == GfaBlmCtx_App) ? "Application" : "Bootloader");
+#endif
 	return 0;
 	return 0;
 }
 }
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
+static int _ReviveBootloader(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx, bool bSilent)
+{
+	int nLen, nRet, nCnt = 0;
+	uint8_t nStatus;
+	struct timespec ts = {0, 250000000};
+	UNUSED(hIf);
+
+	if(ctx == GfaBlmCtx_App)
+	{
+		TRACE1("Bootloader not executing!\n");
+		return 0;
+	}
+
+	uint8_t data[128], frm[256], rx[256], cmd[256];
+	size_t nCbData = sizeof(data);
+	HGFAMINEMST hMst = GfaBlmGetMininetMasterHandle(hBlm);
+	memset(data, 0, sizeof(data));
+
+	if(!bSilent)
+		TRACE2("Reviving bootloader.\n");
+
+	while(!g_bSig)
+    {
+    	nLen = GfaBlmBuildCmdDataPacket("BU", 0, data, nCbData, cmd, sizeof(cmd), false);
+    	nLen = GfaMininetMasterBuildFrame(hMst, pcla->nNodeAddr, 0, cmd, nLen, frm, sizeof(frm));
+
+		if((nRet = GfaMininetMasterTransmitFrame(hMst, frm, nLen)) != nLen)
+	    {
+			TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+			return -1;
+	    }
+
+	    if((nRet = GfaMininetMasterReceiveFrame(hMst, rx, sizeof(rx), true)) <= 0)
+	    {
+			TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+			return -1;
+	    }
+
+	    nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, pcla->nNodeAddr, rx, nRet, true, &nStatus);
+
+	    if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+	    {
+			TRACE1("Error: %s!\n", GfaTfuStrError(-nStatus));
+			return -1;
+	    }
+	    else if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+	    {
+			nCbData = 0;
+	    }
+	    else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+	    {
+			nCbData = sizeof(data);
+			++nCnt;
+	    }
+
+	    if(nCnt >= 3)
+	    	return 0;
+
+		if(nanosleep(&ts, NULL) < 0)
+			break;
+	}
+
+	return nRet;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static int _ModbusStartBootloader(HIMGFILE hIf, HGFABLM hBlm, LPCCMD_LINE_ARGS pcla, GFA_BLM_EXEC_CONTEXT ctx)
+{
+	HGFAMINEMST hMst	= GfaBlmGetMininetMasterHandle(hBlm);
+	HMINETDEV hDev		= GfaMininetMasterGetDeviceHandle(hMst);
+	UNUSED(hIf);
+	UNUSED(ctx);
+
+	TRACE3("Starting bootloader.\n");
+
+	if(hDev)
+	{
+		HGFAMBMST hMbm = GfaMbMstOpen(hDev);
+
+		if(hMbm)
+		{
+			int nRet;
+			GFA_SER_CFG_PARAMS scp, scpSave;
+			struct timeval tvRX = {0, 500000};
+			uint16_t regs[2];
+
+			if(GfaMininetDeviceGetConfigParams(hDev, &scp, sizeof(scp)) != sizeof(scp))
+				return -1;
+			memcpy(&scpSave, &scp, sizeof(scpSave));
+			scp.parity	= pcla->modbParity;
+			scp.baud	= pcla->nModbBaudrate;
+			if(GfaMininetDeviceSetConfigParams(hDev, &scp, sizeof(scp)) != 0)
+				return -1;
+
+			GfaMininetMasterSaveTimeouts(hMst);
+			GfaMininetMasterSetTimeouts(hMst, &tvRX, NULL);
+
+			TRACE4("Reading modbus registers %hu and %hu.\n", pcla->nModbusCtrlReg, pcla->nModbusCtrlReg + 1);
+
+            if((nRet = GfaMbMstReadHoldingRegisters(hMbm, pcla->nModbusSlvID, pcla->nModbusCtrlReg, 2, regs)) == 0)
+            {
+				GfaMbMstWaitFrameDelay(hMbm);
+
+				TRACE4("Writing modbus registers %hu and %hu - values: 0x%04hX and 0x%04hX\n", pcla->nModbusCtrlReg + 2, pcla->nModbusCtrlReg + 3, regs[0], regs[1]);
+
+	            if((nRet = GfaMbMstWriteMultipleRegisters(hMbm, pcla->nModbusSlvID, pcla->nModbusCtrlReg + 2, 2, regs)) != 0)
+		        {
+					TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+		        }
+
+				usleep(GFA_BOOTLOADER_EXEC_WAIT_TIME * 1000);
+			}
+			else
+			{
+				TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+			}
+
+			GfaMininetMasterRestoreTimeouts(hMst);
+			if(pcla->nNodeAddr)
+				GfaMininetMasterResetLocalIndex(hMst, pcla->nNodeAddr);
+			GfaMbMstClose(hMbm);
+			if(GfaMininetDeviceSetConfigParams(hDev, &scpSave, sizeof(scpSave)) != 0)
+				return -1;
+			return nRet;
+		}
+	}
+
+	TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+#if _AUTO_BAUD
+static bool _AutoBaud(HGFABLM hBlm, LPCMD_LINE_ARGS pcla)
+{
+	const uint32_t nBaudrates[] = {19200, 9600, 38400, 57600, 115200, 230400, 4800, 460800/*, 921600, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400*/};
+	const uint8_t nParities[] = {'N'/*, 'E', 'O'*/};
+	uint32_t i, j;
+	HGFAMINEMST hMst	= GfaBlmGetMininetMasterHandle(hBlm);
+	HMINETDEV hDev		= GfaMininetMasterGetDeviceHandle(hMst);
+
+	if(hDev)
+	{
+		HGFAMBMST hMbm;
+		GFA_SER_CFG_PARAMS scp, scpSave;
+
+		if(GfaMininetDeviceGetConfigParams(hDev, &scp, sizeof(scp)) != sizeof(scp))
+			return false;
+		memcpy(&scpSave, &scp, sizeof(scpSave));
+
+		hMbm = GfaMbMstOpen(hDev);
+
+		if(hMbm)
+		{
+			int nRet;
+			bool bHit = false;
+			struct timeval tvRX = {0, 100000};
+
+			GfaMininetMasterSaveTimeouts(hMst);
+			GfaMininetMasterSetTimeouts(hMst, &tvRX, NULL);
+
+			for(i = 0; i < _countof(nParities); ++i)
+			{
+				scp.parity = nParities[i];
+
+				for(j = 0; j < _countof(nBaudrates); ++j)
+				{
+					scp.baud = nBaudrates[j];
+
+					if(GfaMininetDeviceSetConfigParams(hDev, &scp, sizeof(scp)) != 0)
+					{
+						nRet = -1;
+						break;
+					}
+					if((nRet = GfaBlmResetSlaveIndex(hBlm, pcla->nNodeAddr)) == 0)
+	            	{
+	            		pcla->nInitBaudrate = nBaudrates[j];
+	            		if(!pcla->nElevBaudrate)
+	            			pcla->nElevBaudrate = pcla->nInitBaudrate;
+	            		bHit = true;
+	            		TRACE3("Detected connection @ %u,8,1,%c\n", scp.baud, scp.parity);
+	            		break;
+	            	}
+					usleep(10000);
+	            }
+
+	            if(bHit)
+	            	break;
+	        }
+
+			GfaMininetMasterRestoreTimeouts(hMst);
+			GfaMbMstClose(hMbm);
+			if(nRet)
+			{
+				GfaMininetDeviceSetConfigParams(hDev, &scpSave, sizeof(scpSave));
+				return false;
+			}
+			return true;
+		}
+	}
+
+	return false;
+}
+#endif	//	_AUTO_BAUD
+
+/////////////////////////////////////////////////////////////////////////////
+
+#if _MODBUS_DETECT
+static bool _DetectModbusApplication(HGFABLM hBlm, LPCMD_LINE_ARGS pcla)
+{
+	const uint32_t nBaudrates[] = {19200, 9600, 38400, 57600, 115200, 230400, 4800, 460800/*, 921600, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400*/};
+	const uint8_t nParities[] = {'E', 'O'/*, 'N'*/};
+	uint32_t i, j;
+	HGFAMINEMST hMst	= GfaBlmGetMininetMasterHandle(hBlm);
+	HMINETDEV hDev		= GfaMininetMasterGetDeviceHandle(hMst);
+
+	if(hDev)
+	{
+		HGFAMBMST hMbm;
+		GFA_SER_CFG_PARAMS scp, scpSave;
+
+		if(GfaMininetDeviceGetConfigParams(hDev, &scp, sizeof(scp)) != sizeof(scp))
+			return false;
+		memcpy(&scpSave, &scp, sizeof(scpSave));
+
+		hMbm = GfaMbMstOpen(hDev);
+
+		if(hMbm)
+		{
+			int nRet;
+			bool bHit = false;
+			struct timeval tvRX = {0, 200000};
+			uint16_t regs[2];
+
+			GfaMininetMasterSaveTimeouts(hMst);
+			GfaMininetMasterSetTimeouts(hMst, &tvRX, NULL);
+
+			for(i = 0; i < _countof(nParities); ++i)
+			{
+				scp.parity = nParities[i];
+
+				for(j = 0; j < _countof(nBaudrates); ++j)
+				{
+					scp.baud = nBaudrates[j];
+
+					if(GfaMininetDeviceSetConfigParams(hDev, &scp, sizeof(scp)) != 0)
+					{
+						nRet = -1;
+						break;
+					}
+	            	if((nRet = GfaMbMstReadHoldingRegisters(hMbm, pcla->nModbusSlvID, pcla->nModbusCtrlReg, 2, regs)) == 0)
+	            	{
+						pcla->modbParity = nParities[i];
+	            		pcla->nModbBaudrate = nBaudrates[j];
+	            		TRACE3("Detected modbus application @ %u,8,1,%c\n", pcla->nModbBaudrate, pcla->modbParity);
+	            		bHit = true;
+						GfaMbMstWaitFrameDelay(hMbm);
+	            		break;
+	            	}
+					GfaMbMstWaitFrameDelay(hMbm);
+	            }
+
+	            if(bHit)
+	            	break;
+	        }
+
+			GfaMininetMasterRestoreTimeouts(hMst);
+			GfaMbMstClose(hMbm);
+			if(GfaMininetDeviceSetConfigParams(hDev, &scpSave, sizeof(scpSave)) != 0)
+				return false;
+			return (nRet == 0);
+		}
+	}
+
+	return false;
+}
+#endif	//	_MODBUS_DETECT
+
+/////////////////////////////////////////////////////////////////////////////
+
+static void _OnUploadProgress(const char *pszFile, int nLine, LPGFA_BLM_DL_PROGRESS_PARAMS pdlpp)
+{
+	if(pdlpp)
+	{
+		static struct timespec tsStart, tsEnd;
+		static uint32_t nBlockNr;
+		LPCCMD_LINE_ARGS pcla = (LPCCMD_LINE_ARGS)pdlpp->pParam;
+		int64_t nInterval = 0;
+		char szPercString[8];
+		int nPerc;
+
+		switch(pdlpp->nCtx)
+		{
+		case GBDPS_Error:
+//#ifdef _DEBUG
+#if 0
+			TRACE1("Error: %s:%d: %s!\n", pszFile, nLine, GfaBlmStrError(pdlpp->nErrorCode));
+#else	//	_DEBUG
+			UNUSED(pszFile);
+			UNUSED(nLine);
+			TRACE1("Error: %s!\n", GfaBlmStrError(pdlpp->nErrorCode));
+#endif	//	_DEBUG
+			break;
+		case GBDPS_StartEraseFlash:
+			TRACE2("Start download of %u bytes to node 0x%02hhX @ address 0x%X.\n", pdlpp->nCbTotal, pdlpp->nNodeAddr, pdlpp->nFlashStartAddr);
+			TRACE2("Erasing %u flash pages.\n", pdlpp->nCntFlashPages);
+			GfaTfuGetClock(&tsStart);
+			break;
+		case GBDPS_EndEraseFlash:
+			GfaTfuGetClock(&tsEnd);
+			nInterval = GfaTfuClockDiff(&tsEnd, &tsStart);
+			TRACE2("Erased %u flash pages in %lld ms (%.1f ms/page).\n", pdlpp->nCntFlashPages, nInterval / 1000000, ((double)nInterval / 1000000.0) / (double)pdlpp->nCntFlashPages);
+			break;
+		case GBDPS_StartUploadBlocks:
+			nBlockNr = 0;
+			TRACE2("Start sending data to node 0x%02hhX - block size: %u bytes.\n", pdlpp->nNodeAddr, pdlpp->nCbBlock);
+			GfaTfuGetClock(&tsStart);
+			break;
+		case GBDPS_UploadBlock:
+			if(!pcla || !pcla->bNoProgressBlock)
+			{
+				nPerc = GfaTfuGetPercentString(pdlpp->nCbSent, pdlpp->nCbTotal, szPercString, sizeof(szPercString));
+//				if(!(nPerc % 5))
+				{
+					if((pcla->nVerbosity < 4) && (nBlockNr > 0))
+						TRACE2("\b\b\b\b\b");
+					TRACE2("%s", szPercString);
+				}
+			}
+			++nBlockNr;
+			break;
+		case GBDPS_EndUploadBlocks:
+			GfaTfuGetClock(&tsEnd);
+			nInterval = GfaTfuClockDiff(&tsEnd, &tsStart);
+			if(!pcla || !pcla->bNoProgressBlock)
+				TRACE2(" - Done.\n");
+			TRACE2("Sent %u blocks to node 0x%02hhX in %llu ms (%.1f Kb/s).\n", nBlockNr, pdlpp->nNodeAddr, nInterval / 1000000, (double)pdlpp->nCbTotal / ((double)nInterval / 1000000000.0) / 1024.0);
+			break;
+		}
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
 int main(int argc, char* argv[])
 int main(int argc, char* argv[])
 {
 {
-	int nRet;
+	int nRet = 0;
 	HIMGFILE hIf = NULL;
 	HIMGFILE hIf = NULL;
 	HGFABLM hBlm = NULL;
 	HGFABLM hBlm = NULL;
 	CMD_LINE_ARGS cla;
 	CMD_LINE_ARGS cla;
+	struct sigaction sa;
 
 
 	/////////////////////////////////////////////////////////////////////////
 	/////////////////////////////////////////////////////////////////////////
 	// process command line
 	// process command line
 
 
-	TRACE1("\n");
-
 	GfaTfuCmdOptInitOpts(&cla);
 	GfaTfuCmdOptInitOpts(&cla);
 	nRet = GfaTfuCmdOptParse(argc, argv, &cla);
 	nRet = GfaTfuCmdOptParse(argc, argv, &cla);
 
 
@@ -168,10 +892,26 @@ int main(int argc, char* argv[])
 		return nRet;
 		return nRet;
 	}
 	}
 
 
-	if(cla.nUnusedOptFlags)
-	{
-		TRACE3("Warning: The following options are ignored: %s!\n", GfaTfuCmdOpt2String(cla.nUnusedOptFlags));
-	}
+	GfaTfuCmdOptDumpOptions(&cla);
+
+	/////////////////////////////////////////////////////////////////////////
+	// configure signal handling
+
+	memset(&sa, 0, sizeof(sa));
+
+	sa.sa_handler = _SigHandler;
+    sigaction(SIGHUP, &sa, NULL);	// handles user's terminal disconnect
+    sigaction(SIGQUIT, &sa, NULL);	// handles Ctrl + '\'
+	sigaction(SIGTERM, &sa, NULL);	// handles normal termination
+	sigaction(SIGABRT, &sa, NULL);	// handles abnormal termination (i.e. abort())
+	sigaction(SIGINT, &sa, NULL);	// handles Ctrl + 'C'
+
+	sa.sa_handler = SIG_IGN;
+    sigaction(SIGTSTP, &sa, NULL);	// ignores Ctrl + 'Z'
+    sigaction(SIGSTOP, &sa, NULL);	// ignores Stop
+    sigaction(SIGCONT, &sa, NULL);	// ignores Continue
+    sigaction(SIGCHLD, &sa, NULL);	// ignores child process termination
+    sigaction(0, &sa, NULL);		// ignores shell termination
 
 
 	/////////////////////////////////////////////////////////////////////////
 	/////////////////////////////////////////////////////////////////////////
 
 
@@ -184,21 +924,19 @@ int main(int argc, char* argv[])
 		{
 		{
 			TRACE3("Opening image file %s.\n", cla.pszImgFile);
 			TRACE3("Opening image file %s.\n", cla.pszImgFile);
 
 
-		    if(!(hIf = GfaTfuImageFileOpen(cla.pszImgFile, GFA_APP_APPLICATION_START_ADDRESS, true)))
+		    if(!(hIf = GfaTfuImageFileOpen(cla.pszImgFile, cla.nStartAddr, true)))
 		    {
 		    {
-				TRACE1("%s!\n", GfaTfuStrError(errno));
+				TRACE1("Error: %s!\n", GfaTfuStrError(errno));
 				break;
 				break;
 		    }
 		    }
-		    
+
 		    if(cla.bShowFileImgInfo)
 		    if(cla.bShowFileImgInfo)
 		    {
 		    {
 		    	GFA_IMG_INFO ii;
 		    	GFA_IMG_INFO ii;
 		    	GfaTfuImageFileGetInfo(hIf, &ii);
 		    	GfaTfuImageFileGetInfo(hIf, &ii);
 			    GfaTfuDumpImageInfo(cla.pszImgFile, &ii);
 			    GfaTfuDumpImageInfo(cla.pszImgFile, &ii);
-			}
-			
-			if(cla.bIsOffline)
 				break;
 				break;
+			}
 		}
 		}
 
 
 		if(GfaSerialGetDeviceInterface(&blmcp.mmcp.devcfg.itf))
 		if(GfaSerialGetDeviceInterface(&blmcp.mmcp.devcfg.itf))
@@ -209,10 +947,10 @@ int main(int argc, char* argv[])
 			/////////////////////////////////////////////////////////////////
 			/////////////////////////////////////////////////////////////////
 			// serial device configuration
 			// serial device configuration
 
 
-			scp.baud			= CMD_OPT_DEFAULT_BAUDRATE; // start with default baudrate
+			scp.baud			= cla.bModbusStartBoot ? cla.nModbBaudrate : cla.nInitBaudrate; // start with initial baud-rate
 			scp.data			= 8;
 			scp.data			= 8;
 			scp.stop			= 1;
 			scp.stop			= 1;
-			scp.parity			= 'N';
+			scp.parity			= cla.bModbusStartBoot ? cla.modbParity : 'N'; // modbus slaves use parity, mininet slaves not
 #ifdef _TARGET_BUILD
 #ifdef _TARGET_BUILD
 			scp.bHandleTxEcho	= true;
 			scp.bHandleTxEcho	= true;
 #endif	//	_TARGET_BUILD
 #endif	//	_TARGET_BUILD
@@ -227,8 +965,8 @@ int main(int argc, char* argv[])
 			/////////////////////////////////////////////////////////////////
 			/////////////////////////////////////////////////////////////////
 			// bootloader master configuration
 			// bootloader master configuration
 
 
-			blmcp.pfnBuCmdDownloadStatus		= GfaTfuOnDownloadStatus;
-			blmcp.pfnBuCmdSendDataStatus		= GfaTfuOnSendDataStatus;
+			blmcp.pfnDlProgress					= _OnUploadProgress;
+			blmcp.pUserParam					= &cla;
 
 
 			/////////////////////////////////////////////////////////////////
 			/////////////////////////////////////////////////////////////////
 			// open a bootloader master instance
 			// open a bootloader master instance
@@ -238,119 +976,141 @@ int main(int argc, char* argv[])
 			if((hBlm = GfaBlmOpen(&blmcp)))
 			if((hBlm = GfaBlmOpen(&blmcp)))
 			{
 			{
 				GFA_BLM_EXEC_CONTEXT ctx;
 				GFA_BLM_EXEC_CONTEXT ctx;
+#if _MODBUS_DETECT
+				bool bModbusAppDetected = false;
+#endif	//	_MODBUS_DETECT
 
 
 				GfaBlmSetVerbosity(hBlm, cla.nVerbosity);
 				GfaBlmSetVerbosity(hBlm, cla.nVerbosity);
 
 
-				TRACE3("Initializing slave index.\n");
-
-				if((nRet = GfaBlmResetSlaveIndex(hBlm, cla.nNodeAddr)) != 0)
-		        {
-					TRACE1("%s!\n", GfaTfuStrError(errno));
-					break;
-		        }
-
-				TRACE3("Detecting running image.\n");
-
-		        if((ctx = GfaBlmGetExecutionContext(hBlm, cla.nNodeAddr)) == GfaBlmCtx_Err)
-		        {
-					TRACE1("%s!\n", GfaTfuStrError(errno));
+				if(cla.bModbusStartBoot)
+				{
+					nRet = _ModbusStartBootloader(hIf, hBlm, &cla, GfaBlmCtx_Err);
 					break;
 					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");
+				TRACE3("Connecting to target.\n");
 
 
-					if((nRet = GfaBlmBootloaderExecute(hBlm, cla.nNodeAddr, NULL, 1000)) != 0)
-					{
-						TRACE1("%s!\n", GfaTfuStrError(errno));
+#if _AUTO_BAUD
+				if(!_AutoBaud(hBlm, &cla))
+				{
+#if _MODBUS_DETECT
+		        	if(!cla.nModbusSlvID || !(bModbusAppDetected = _DetectModbusApplication(hBlm, &cla)))
+#endif	//	_MODBUS_DETECT
+		        	{
+						TRACE1("Error: %s!\n", GfaTfuStrError(errno));
 						break;
 						break;
-					}
+		        	}
 				}
 				}
-
-		        if(cla.nBaudrate != CMD_OPT_DEFAULT_BAUDRATE)
+#else	//	_AUTO_BAUD
+				if((nRet = GfaBlmResetSlaveIndex(hBlm, cla.nNodeAddr)) != 0)
 		        {
 		        {
-					TRACE3("Setting baudrate to %u.\n", cla.nBaudrate);
-
-					if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, cla.nNodeAddr, cla.nBaudrate)) != 0)
-					{
-						TRACE1("%s!\n", GfaTfuStrError(errno));
+		        	if(errno == ETIMEDOUT)
+		        	{
+		        		if(cla.nBootBaudrate != cla.nInitBaudrate)
+		        		{
+							TRACE3("Failed with baud-rate %u. Retrying with %u.\n", cla.nInitBaudrate, cla.nBootBaudrate);
+							GfaBlmSetDeviceBaudrate(hBlm, cla.nBootBaudrate);
+
+							if((nRet = GfaBlmResetSlaveIndex(hBlm, cla.nNodeAddr)) != 0)
+					        {
+#if _MODBUS_DETECT
+					        	if(!cla.nModbusSlvID || !(bModbusAppDetected = _DetectModbusApplication(hBlm, &cla)))
+#endif	//	_MODBUS_DETECT
+					        	{
+									TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+									break;
+					        	}
+					        }
+					    }
+					    else
+					    {
+#if _MODBUS_DETECT
+				        	if(!cla.nModbusSlvID || !(bModbusAppDetected = _DetectModbusApplication(hBlm, &cla)))
+#endif	//	_MODBUS_DETECT
+				        	{
+								TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+								break;
+				        	}
+					    }
+		        	}
+		        	else
+		        	{
+						TRACE1("Error: %s!\n", GfaTfuStrError(errno));
 						break;
 						break;
-			        }
+					}
 		        }
 		        }
+#endif	//	_AUTO_BAUD
 
 
-				if(cla.bShowDevImgInfo)
-				{
-					GFA_BL_APP_IMG_INFO aii;
-
-					TRACE3("Getting image information.\n");
+#if _MODBUS_DETECT
+		        if(bModbusAppDetected)
+		        {
+					ctx = GfaBlmCtx_ModB;
 
 
-			        if((nRet = GfaBlmGetInfoBI(hBlm, cla.nNodeAddr, &aii)) == 0)
-			        {
-			        	GfaTfuDumpImageInfo("Bootloader", &aii.bl);
-			        	GfaTfuDumpImageInfo("Application", &aii.app);
-			        }
-		            else if((nRet = GfaBlmGetInfoBD(hBlm, cla.nNodeAddr, &aii)) > -2)
+					if(cla.bUploadImg || cla.bShowDevImgInfo || cla.bSetMatSer || cla.bStartBoot)
 					{
 					{
-			        	GfaTfuDumpImageInfo("Bootloader", &aii.bl);
-			        	GfaTfuDumpImageInfo("Application", &aii.app);
-			        }
-				}
+						if((nRet = _ModbusStartBootloader(hIf, hBlm, &cla, ctx)) != 0)
+							break;
 
 
-				if(cla.bShowMatSer)
-				{
-					char szMaterial[16], szSerial[16];
+						ctx = GfaBlmCtx_Boot;
 
 
-					TRACE3("Reading material and serial number.\n");
-
-					if((nRet = GfaBlmReadMaterialAndSerialID(hBlm, cla.nNodeAddr, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) != 0)
+						if(cla.bStartBoot)
+							break;
+					}
+					else if(!cla.bPing)
 					{
 					{
-						TRACE1("%s!\n", GfaTfuStrError(errno));
 						break;
 						break;
 					}
 					}
+		        }
+		        else
+#endif	//	_MODBUS_DETECT
+				{
+					TRACE3("Detecting running image.\n");
 
 
-					if(hIf)
-						GfaTfuImageFileMatchMaterialNum(hIf, szMaterial);
+					ctx = GfaBlmGetExecutionContext(hBlm, cla.nNodeAddr);
 
 
-					TRACE2("Material and Serial number:\n");
-					TRACE2("  Mat.Nr.: %s\n", szMaterial);
-					TRACE2("  Serial:  %s\n", szSerial);
-				}
+			        if(	(ctx == GfaBlmCtx_Err) ||
+			        	(ctx == GfaBlmCtx_Boot))
+			        {
+			        	if((nRet = _ReviveBootloader(hIf, hBlm, &cla, ctx, true)) != 0)
+			        	{
+							TRACE1("Error: %s!\n", GfaTfuStrError(errno));
+							break;
+						}
 
 
-				TRACE3("Resetting slave.\n");
+						ctx = GfaBlmCtx_Boot;
+			        }
 
 
-	            if((nRet = GfaBlmBUCmdReset(hBlm, cla.nNodeAddr, 1000)) != 0)
-		        {
-					TRACE1("%s!\n", GfaTfuStrError(errno));
-					break;
-		        }
-#endif
+			        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);
+				else if(cla.bStartBoot)
+					nRet = _StartBootloader(hIf, hBlm, &cla, ctx);
+				else if(cla.bResetBoot)
+					nRet = _ResetBootloader(hIf, hBlm, &cla, ctx);
+				else if(cla.bReviveBoot)
+					nRet = _ReviveBootloader(hIf, hBlm, &cla, ctx, false);
 			}
 			}
 			else
 			else
 	        {
 	        {
-				TRACE1("%s!\n", GfaTfuStrError(errno));
+				TRACE1("Error: %s!\n", GfaTfuStrError(errno));
 				break;
 				break;
 	        }
 	        }
 		}
 		}
 		else
 		else
         {
         {
-			TRACE1("%s!\n", GfaTfuStrError(errno));
+			TRACE1("Error: %s!\n", GfaTfuStrError(errno));
 			break;
 			break;
         }
         }
 	}
 	}
@@ -368,7 +1128,6 @@ int main(int argc, char* argv[])
 		GfaTfuImageFileClose(hIf);
 		GfaTfuImageFileClose(hIf);
 	}
 	}
 
 
-	TRACE1("\n");
-	return 0;
+	return nRet;
 }
 }
 
 

+ 1 - 0
main.h

@@ -16,6 +16,7 @@ extern "C" {
 #define GFA_FU_VER_REVISION						0
 #define GFA_FU_VER_REVISION						0
 
 
 #define UNUSED(x)								(void)x
 #define UNUSED(x)								(void)x
+#define _countof(a)								(sizeof(a) / sizeof(*a))
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 398 - 0
modbmst.c

@@ -0,0 +1,398 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <byteswap.h>
+#include <unistd.h>
+#include <errno.h>
+#include "error.h"
+#include "modbmst.h"
+
+// Table of CRC values for high-order byte
+static const uint8_t g_crcHi[] =
+{
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
+    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
+    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
+    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
+    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
+    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
+    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
+    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
+    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
+    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
+    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
+    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
+    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
+};
+
+// Table of CRC values for low-order byte
+static const uint8_t g_crcLo[] =
+{
+    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
+    0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
+    0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
+    0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
+    0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
+    0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
+    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
+    0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
+    0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
+    0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
+    0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
+    0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
+    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
+    0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
+    0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
+    0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
+    0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
+    0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
+    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
+    0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
+    0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
+    0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
+    0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
+    0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
+    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
+    0x43, 0x83, 0x41, 0x81, 0x80, 0x40
+};
+
+static uint16_t _Crc16(const void *pData, size_t nCbData)
+{
+	const uint8_t *pBuffer = (const uint8_t*)pData;
+    uint8_t crcHi = 0xFF;	// high CRC byte initialized
+    uint8_t crcLo = 0xFF;	// low CRC byte initialized
+    unsigned int i;			// will index into CRC lookup
+
+    while(nCbData--)
+    {
+        i = crcHi ^ *pBuffer++;
+        crcHi = crcLo ^ g_crcHi[i];
+        crcLo = g_crcLo[i];
+    }
+
+    return (((uint16_t)crcHi << 8) | (uint16_t)crcLo);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_MB_MST
+{
+	HMINETDEV hDev;
+}GFA_MB_MST, *LPGFA_MB_MST;
+typedef const GFA_MB_MST *LPCGFA_MB_MST;
+
+/////////////////////////////////////////////////////////////////////////////
+#if 0
+static uint16_t _Crc16(uint16_t nCrc, const void *pData, size_t nCbData)
+{
+	if(pData && nCbData)
+	{
+	    uint8_t x;
+	    const uint8_t *pbData = (const uint8_t*)pData;
+
+		while(nCbData--)
+		{
+		    x = nCrc >> 8 ^ *pbData++;
+		    x ^= (x >> 4);
+		    nCrc = (nCrc << 8) ^ ((uint16_t)(x << 12)) ^ ((uint16_t)(x <<5)) ^ ((uint16_t)x);
+		}
+	}
+
+	return nCrc;
+}
+#endif
+/////////////////////////////////////////////////////////////////////////////
+
+static void _CpyUnalignedUint16(void *pTo, const void *pFrom, size_t nCntWords)
+{
+	size_t i, j;
+	uint8_t *p1 = (uint8_t*)pTo;
+	const uint8_t *p2 = (const uint8_t*)pFrom;
+	for(i = 0; i < nCntWords; i++)
+	{
+		p2 += sizeof(uint16_t);
+		for(j = 0; j < sizeof(uint16_t); j++)
+		{
+			*p1++ = *--p2;
+		}
+		p2 += sizeof(uint16_t);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+HGFAMBMST GfaMbMstOpen(HMINETDEV hDev)
+{
+	if(hDev)
+	{
+		LPGFA_MB_MST pMst = (LPGFA_MB_MST)malloc(sizeof(GFA_MB_MST));
+		memset(pMst, 0, sizeof(GFA_MB_MST));
+		pMst->hDev = hDev;
+		return (HGFAMBMST)pMst;
+	}
+
+	errno = EINVAL;
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaMbMstClose(HGFAMBMST hMst)
+{
+	if(hMst)
+	{
+		LPGFA_MB_MST pMst = (LPGFA_MB_MST)hMst;
+		free(pMst);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMbMstCreateADU(uint8_t slvID, uint8_t func, const void *pData, size_t nCbData, LPMODBUS_RTU_ADU pAdu)
+{
+	if(	pAdu &&
+		(slvID != MODBUS_BROADCAST_ADDRESS) &&
+		(slvID <= MODBUS_MAX_SLAVE_ID))
+	{
+		uint16_t nCRC16;
+		size_t nCbAdu = 2;
+
+		pAdu->slvID	= slvID;
+		pAdu->func	= func;
+
+		if(pData && nCbData)
+		{
+			if((nCbData > MODBUS_MAX_DATA_PAYLOAD))
+			{
+				errno = ENOMEM;
+				return -1;
+			}
+
+			memcpy(pAdu->b, pData, nCbData);
+			nCbAdu += nCbData;
+		}
+		else
+		{
+			nCbData = 0;
+		}
+
+		nCRC16 = _Crc16(pAdu, nCbAdu);
+		_CpyUnalignedUint16(&pAdu->b[nCbData], &nCRC16, 1);
+		nCbAdu += sizeof(nCRC16);
+		return nCbAdu;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaMbMstValidateADU(uint8_t slvID, uint8_t func, LPCMODBUS_RTU_ADU pAdu, size_t nCbAdu, int *pnMbErr)
+{
+	bool bRet;
+	uint16_t nCRC16Received, nCRC16Expected;
+	if(pnMbErr)
+		*pnMbErr = 0;
+	if(pAdu->slvID != slvID)
+	{
+		errno = EPROTO;
+		return false;
+	}
+	else if(pAdu->func != func)
+	{
+		if((pAdu->func != (func | MB_FUNC_ERROR_FLAG)) || (nCbAdu != 5))
+		{
+			errno = EPROTO;
+			return false;
+		}
+		else if(pnMbErr)
+			*pnMbErr = pAdu->b[0];
+	}
+	_CpyUnalignedUint16(&nCRC16Received, ((uint8_t*)pAdu) + nCbAdu - sizeof(uint16_t), sizeof(uint16_t));
+	nCRC16Expected = _Crc16(pAdu, nCbAdu - sizeof(uint16_t));
+	if(!(bRet = (nCRC16Received == nCRC16Expected)))
+		errno = EPROTO;
+	return bRet;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaMbMstWaitFrameDelay(HGFAMBMST hMst)
+{
+	if(hMst)
+	{
+		uint32_t nDelay, nBaudrate;
+		LPGFA_MB_MST pMst = (LPGFA_MB_MST)hMst;
+
+		if(	!GfaMininetDeviceGetBaudrate(pMst->hDev, &nBaudrate) &&
+			nBaudrate <= 19200)
+			nDelay = (350000000 / nBaudrate + 5) / 10;
+		else
+			nDelay = 1750;
+		usleep(nDelay);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMbMstSendADU(HGFAMBMST hMst, LPCMODBUS_RTU_ADU pAdu, size_t nCbAdu)
+{
+	if(hMst && pAdu && nCbAdu >= 4)
+	{
+		LPGFA_MB_MST pMst = (LPGFA_MB_MST)hMst;
+		return GfaMininetDeviceTransmit(pMst->hDev, pAdu, nCbAdu);
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMbMstRecvADU(HGFAMBMST hMst, LPMODBUS_RTU_ADU pAdu, size_t nCbAdu)
+{
+	if(hMst && pAdu && nCbAdu >= 4)
+	{
+		LPGFA_MB_MST pMst = (LPGFA_MB_MST)hMst;
+		return GfaMininetDeviceReceive(pMst->hDev, pAdu, nCbAdu);
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMbMstReadHoldingRegisters(HGFAMBMST hMst, uint8_t slvID, uint16_t nRegStart, uint16_t nRegCount, void *pRegs)
+{
+	if(hMst && pRegs && nRegCount > 0)
+	{
+		int nMBErr;
+		ssize_t nRet;
+		uint8_t func = MB_FUNC_READ_HOLDING_REGISTERS;
+		MODBUS_RTU_ADU adu;
+		size_t nCbExpt = 5 + (nRegCount * sizeof(uint16_t));
+		uint8_t ri[4];
+
+		_CpyUnalignedUint16(&ri[0], &nRegStart, 1);
+		_CpyUnalignedUint16(&ri[2], &nRegCount, 1);
+
+		if((nRet = GfaMbMstCreateADU(slvID, func, &ri, sizeof(ri), &adu)) < 0)
+			return nRet;
+
+		if((nRet = GfaMbMstSendADU(hMst, &adu, nRet)) < 0)
+			return nRet;
+
+		if((nRet = GfaMbMstRecvADU(hMst, &adu, nCbExpt)) <= 0)
+			return -1;
+		
+		if(!GfaMbMstValidateADU(slvID, func, &adu, nRet, &nMBErr))
+			return -1;
+		
+		if(nMBErr)
+		{
+			errno = MAKE_GFA_MODBUS_ERROR(nMBErr);
+			return -1;
+		}
+
+		_CpyUnalignedUint16(pRegs, &adu.b[1], nRegCount);
+		return 0;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMbMstWriteMultipleRegisters(HGFAMBMST hMst, uint8_t slvID, uint16_t nRegStart, uint16_t nRegCount, const void *pRegs)
+{
+	if(hMst && pRegs && nRegCount > 0)
+	{
+		int nMBErr;
+		ssize_t nRet;
+		MODBUS_RTU_ADU adu;
+		uint8_t func = MB_FUNC_WRITE_MULTIPLE_REGISTERS;
+		uint8_t data[MODBUS_MAX_DATA_PAYLOAD];
+
+		_CpyUnalignedUint16(&data[0], &nRegStart, 1);
+		_CpyUnalignedUint16(&data[2], &nRegCount, 1);
+		data[4] = (uint8_t)(nRegCount * sizeof(uint16_t));
+		_CpyUnalignedUint16(&data[5], pRegs, nRegCount);
+
+		if((nRet = GfaMbMstCreateADU(slvID, func, &data, 5 + nRegCount * sizeof(uint16_t), &adu)) < 0)
+			return -1;
+
+		if((nRet = GfaMbMstSendADU(hMst, &adu, nRet)) < 0)
+			return -1;
+
+		if((nRet = GfaMbMstRecvADU(hMst, &adu, 8)) <= 0)
+			return -1;
+		
+		if(!GfaMbMstValidateADU(slvID, func, &adu, nRet, &nMBErr))
+			return -1;
+		
+		if(nMBErr)
+		{
+			errno = MAKE_GFA_MODBUS_ERROR(nMBErr);
+			return -1;
+		}
+		
+		return 0;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaMbMstPing(HGFAMBMST hMst, uint8_t slvID)
+{
+	if(hMst)
+	{
+		int nMBErr;
+		ssize_t nRet;
+		MODBUS_RTU_ADU adu;
+		uint8_t func = MB_FUNC_DIAGNOSTIC;
+		uint16_t data[2] = {MB_SUBFUNC_RETURN_QUERY_DATA, 0x1234};
+
+		if((nRet = GfaMbMstCreateADU(slvID, func, &data, sizeof(data), &adu)) < 0)
+			return -1;
+
+		if((nRet = GfaMbMstSendADU(hMst, &adu, nRet)) < 0)
+			return -1;
+
+		if((nRet = GfaMbMstRecvADU(hMst, &adu, 8)) <= 0)
+			return -1;
+		
+		if(!GfaMbMstValidateADU(slvID, func, &adu, nRet, &nMBErr))
+			return -1;
+		
+		if(nMBErr)
+		{
+			errno = MAKE_GFA_MODBUS_ERROR(nMBErr);
+			return -1;
+		}
+		
+		return (adu.w[1] == data[1]) ? 0 : -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}

+ 109 - 0
modbmst.h

@@ -0,0 +1,109 @@
+// modbmst.h :
+//
+
+#if !defined(AGD_MODBMST_H__7E9090EE_6B4D_4499_8080_03241FAC527B__INCLUDED_)
+#define AGD_MODBMST_H__7E9090EE_6B4D_4499_8080_03241FAC527B__INCLUDED_
+
+#include <gfamininetdev.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// modbmst.h - Declarations:
+
+#define MB_FUNC_READ_COIL_STATUS						((uint8_t)0x01)
+#define MB_FUNC_READ_INPUT_STATUS						((uint8_t)0x02)
+#define MB_FUNC_READ_HOLDING_REGISTERS					((uint8_t)0x03)
+#define MB_FUNC_READ_INPUT_REGISTERS					((uint8_t)0x04)
+#define MB_FUNC_FORCE_SINGLE_COIL						((uint8_t)0x05)
+#define MB_FUNC_PRESET_SINGLE_REGISTER					((uint8_t)0x06)
+#define MB_FUNC_READ_EXCEPTION_STATUS					((uint8_t)0x07)
+#define MB_FUNC_DIAGNOSTIC								((uint8_t)0x08)
+#define MB_FUNC_FETCH_COMM_EVENT_CTR					((uint8_t)0x0B)
+#define MB_FUNC_FETCH_COMM_EVENT_LOG					((uint8_t)0x0C)
+#define MB_FUNC_FORCE_MULTIPLE_COILS					((uint8_t)0x0F)
+#define MB_FUNC_WRITE_MULTIPLE_REGISTERS				((uint8_t)0x10)
+#define MB_FUNC_REPORT_SLAVE_ID							((uint8_t)0x11)
+#define MB_FUNC_READ_GENERAL_REFERENCE					((uint8_t)0x14)
+#define MB_FUNC_WRITE_GENERAL_REFERENCE					((uint8_t)0x15)
+#define MB_FUNC_MASK_WRITE_4X_REGISTER					((uint8_t)0x16)
+#define MB_FUNC_READ_WRITE_4X_REGISTERS					((uint8_t)0x17)
+#define MB_FUNC_READ_FIFO_QUEUE							((uint8_t)0x18)
+
+#define MB_SUBFUNC_RETURN_QUERY_DATA					((uint16_t)0x00)
+#define MB_SUBFUNC_RESTART_COMM_OPTION					((uint16_t)0x01)
+#define MB_SUBFUNC_RETURN_DIAGNOSTIC_REGISTER			((uint16_t)0x02)
+#define MB_SUBFUNC_FORCE_LISTEN_ONLY_MODE				((uint16_t)0x04)
+#define MB_SUBFUNC_CLEAR_CTRS_AND_DIAGNOSTIC_REG		((uint16_t)0x0A)
+#define MB_SUBFUNC_RETURN_BUS_MESSAGE_COUNT				((uint16_t)0x0B)
+#define MB_SUBFUNC_RETURN_BUS_COMM_ERROR_COUNT			((uint16_t)0x0C)
+#define MB_SUBFUNC_RETURN_BUS_EXCEPTION_ERROR_COUNT		((uint16_t)0x0D)
+#define MB_SUBFUNC_RETURN_SLAVE_MESSAGE_COUNT			((uint16_t)0x0E)
+#define MB_SUBFUNC_RETURN_SLAVE_NO_RESPONSE_COUNT		((uint16_t)0x0F)
+#define MB_SUBFUNC_RETURN_SLAVE_NAK_COUNT				((uint16_t)0x10)
+#define MB_SUBFUNC_RETURN_SLAVE_BUSY_COUNT				((uint16_t)0x11)
+#define MB_SUBFUNC_RETURN_BUS_CHAR_OVERRUN_COUNT		((uint16_t)0x12)
+#define MB_SUBFUNC_RETURN_OVERRUN_ERROR_COUNT			((uint16_t)0x13)
+#define MB_SUBFUNC_CLEAR_OVERRUN_COUNTER_AND_FLAG		((uint16_t)0x14)
+
+#define MB_FUNC_ERROR_FLAG								((uint8_t)0x80)
+
+#define MB_ERROR_ILLEGAL_FUNCTION						((uint8_t)0x01)
+#define MB_ERROR_ILLEGAL_DATA_ADDRESS					((uint8_t)0x02)
+#define MB_ERROR_ILLEGAL_DATA_VALUE						((uint8_t)0x03)
+#define MB_ERROR_SLAVE_DEVICE_FAILURE					((uint8_t)0x04)
+#define MB_ERROR_ACKNOWLEDGE							((uint8_t)0x05)
+#define MB_ERROR_SLAVE_DEVICE_BUSY						((uint8_t)0x06)
+#define MB_ERROR_NEGATIVE_ACKNOWLEDGE					((uint8_t)0x07)
+#define MB_ERROR_MEMORY_PARITY_ERROR					((uint8_t)0x08)
+
+#define MODBUS_BROADCAST_ADDRESS						0
+#define MODBUS_MAX_SLAVE_ID								247
+#define MODBUS_MAX_READ_BITS							2000
+#define MODBUS_MAX_WRITE_BITS							1968
+#define MODBUS_MAX_READ_REGISTERS						125
+#define MODBUS_MAX_WRITE_REGISTERS						123
+#define MODBUS_MAX_RW_WRITE_REGISTERS					121
+#define MODBUS_MAX_DATA_PAYLOAD							252
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _MODBUS_RTU_ADU
+{
+	uint8_t slvID;
+	uint8_t func;
+	union
+	{
+		uint8_t  b[254];
+		uint16_t w[127];
+	};
+}__attribute__ ((__aligned__(2),__packed__)) MODBUS_RTU_ADU, *LPMODBUS_RTU_ADU;
+typedef const MODBUS_RTU_ADU *LPCMODBUS_RTU_ADU;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef void		*HGFAMBMST;
+
+/////////////////////////////////////////////////////////////////////////////
+
+HGFAMBMST GfaMbMstOpen(HMINETDEV hDev);
+void GfaMbMstClose(HGFAMBMST hMst);
+ssize_t GfaMbMstSendADU(HGFAMBMST hMst, LPCMODBUS_RTU_ADU pAdu, size_t nCbAdu);
+ssize_t GfaMbMstRecvADU(HGFAMBMST hMst, LPMODBUS_RTU_ADU pAdu, size_t nCbAdu);
+ssize_t GfaMbMstReadHoldingRegisters(HGFAMBMST hMst, uint8_t slvID, uint16_t nRegStart, uint16_t nRegCount, void *pRegs);
+ssize_t GfaMbMstWriteMultipleRegisters(HGFAMBMST hMst, uint8_t slvID, uint16_t nRegStart, uint16_t nRegCount, const void *pRegs);
+void GfaMbMstWaitFrameDelay(HGFAMBMST hMst);
+int GfaMbMstPing(HGFAMBMST hMst, uint8_t slvID);
+
+ssize_t GfaMbMstCreateADU(uint8_t slvID, uint8_t func, const void *pData, size_t nCbData, LPMODBUS_RTU_ADU pAdu);
+bool GfaMbMstValidateADU(uint8_t slvID, uint8_t func, LPCMODBUS_RTU_ADU pAdu, size_t nCbAdu, int *pnMbErr);
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_MODBMST_H__7E9090EE_6B4D_4499_8080_03241FAC527B__INCLUDED_)

+ 83 - 25
output.c

@@ -21,6 +21,18 @@ extern int g_nVerbosity;
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
+int GfaTfuGetPercentString(uint32_t nCur, uint32_t nMax, char *pszString, size_t nCChString)
+{
+	double fCur = (double)nCur;
+	double fMax = (double)nMax;
+	double fPerc = fCur / fMax * 100;
+	int nPerc = (int)fPerc;
+	snprintf(pszString, nCChString, "%3d %%", nPerc);
+	return nPerc;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 int GfaTfuPrintF(int verb, const char *pszFormat, ...)
 int GfaTfuPrintF(int verb, const char *pszFormat, ...)
 {
 {
 	if(verb <= g_nVerbosity)
 	if(verb <= g_nVerbosity)
@@ -41,42 +53,88 @@ int GfaTfuPrintF(int verb, const char *pszFormat, ...)
 
 
 void GfaTfuDumpImageInfo(const char *pszContext, LPCGFA_IMG_INFO pii)
 void GfaTfuDumpImageInfo(const char *pszContext, LPCGFA_IMG_INFO pii)
 {
 {
-	if(	(g_nVerbosity >= 2) &&
-		pszContext &&
-		pii &&
-		(pii->nImgLength != 0xFFFFFFFF) &&
-		(pii->nImgCRC32 != 0xFFFFFFFF))
+	if((g_nVerbosity >= 2) && pszContext && pii)
 	{
 	{
 		TRACE2("%s Image Information:\n", pszContext);
 		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(	(pii->nImgLength != 0xFFFFFFFF) &&
+			(pii->nImgCRC32 != 0xFFFFFFFF))
+		{
+			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);
+		}
+		else
+		{
+			TRACE2("  No valid image found.\n");
+		}
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+uint64_t GfaTfuTimeval2Us(const struct timeval *ptv)
+{
+	if(ptv)
+		return (uint64_t)ptv->tv_sec * 1000000 + (uint64_t)ptv->tv_usec;
+	return (uint64_t)-1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+const struct timeval* GfaTfuUs2Timeval(uint64_t usTime, struct timeval *ptv)
+{
+	if(ptv)
+	{
+		ptv->tv_sec		= usTime / 1000000;
+		ptv->tv_usec	= usTime % 1000000;
 	}
 	}
+
+	return ptv;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+uint64_t GfaTfuTimespec2Ns(const struct timespec *pts)
+{
+	if(pts)
+		return (uint64_t)pts->tv_sec * 1000000000 + (uint64_t)pts->tv_nsec;
+	return (uint64_t)-1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+const struct timespec* GfaTfuNs2Timespec(uint64_t nsTime, struct timespec *pts)
+{
+	if(pts)
+	{
+		pts->tv_sec		= nsTime / 1000000000;
+		pts->tv_nsec	= nsTime % 1000000000;
+	}
+
+	return pts;
 }
 }
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
-void GfaTfuOnDownloadStatus(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, int nCtx, int nErrorCode)
+int64_t GfaTfuClockDiff(const struct timespec *pts1, const struct timespec *pts2)
 {
 {
-	UNUSED(pszFile);
-	UNUSED(nLine);
-	UNUSED(nNodeAddr);
-	UNUSED(nFlashStartAddr);
-	UNUSED(nCbData);
-	UNUSED(nCtx);
-	UNUSED(nErrorCode);
+	int64_t nRet = 0;
+
+	if(pts1 && pts2)
+	{
+		uint64_t t1 = GfaTfuTimespec2Ns(pts1);
+		uint64_t t2 = GfaTfuTimespec2Ns(pts2);
+		nRet = (int64_t)(t1 - t2);
+	}
+
+	return nRet;
 }
 }
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
-void GfaTfuOnSendDataStatus(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nCbBlock, uint32_t nCbData, int nCtx, int nErrorCode)
+void GfaTfuGetClock(struct timespec *pts)
 {
 {
-	UNUSED(pszFile);
-	UNUSED(nLine);
-	UNUSED(nNodeAddr);
-	UNUSED(nCbBlock);
-	UNUSED(nCbData);
-	UNUSED(nCtx);
-	UNUSED(nErrorCode);
+	clock_gettime(CLOCK_MONOTONIC, pts);
 }
 }

+ 11 - 4
output.h

@@ -4,6 +4,8 @@
 #if !defined(AGD_OUTPUT_H__77A3E0A7_F59F_49E5_950F_D3465B3FDCAB__INCLUDED_)
 #if !defined(AGD_OUTPUT_H__77A3E0A7_F59F_49E5_950F_D3465B3FDCAB__INCLUDED_)
 #define AGD_OUTPUT_H__77A3E0A7_F59F_49E5_950F_D3465B3FDCAB__INCLUDED_
 #define AGD_OUTPUT_H__77A3E0A7_F59F_49E5_950F_D3465B3FDCAB__INCLUDED_
 
 
+#include <stdint.h>
+#include <stdbool.h>
 #include <gfabootlmast.h>
 #include <gfabootlmast.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -24,11 +26,16 @@ extern "C" {
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 
 
-int GfaTfuPrintF(int verb, const char *pszFormat, ...);
-void GfaTfuDumpImageInfo(const char *pszContext, LPCGFA_IMG_INFO pii);
+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);
+int			GfaTfuGetPercentString(uint32_t nCur, uint32_t nMax, char *pszString, size_t nCChString);
+uint64_t	GfaTfuTimeval2Us(const struct timeval *ptv);
+uint64_t	GfaTfuTimespec2Ns(const struct timespec *pts);
+const struct timeval* GfaTfuUs2Timeval(uint64_t usTime, struct timeval *ptv);
+const struct timespec* GfaTfuNs2Timespec(uint64_t nsTime, struct timespec *pts);
+int64_t		GfaTfuClockDiff(const struct timespec *pts1, const struct timespec *pts2);
+void		GfaTfuGetClock(struct timespec *pts);
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 #ifdef __cplusplus
 #ifdef __cplusplus