Przeglądaj źródła

Erste Version zur Verwendung mit Flash Utils.

Rind 5 lat temu
rodzic
commit
e33fc3dff9

+ 174 - 625
demo/main.c

@@ -1,12 +1,14 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
-#include <errno.h>
+#include <byteswap.h>
 #include <unistd.h>
+#include <stddef.h>
+#include <time.h>
+#include <errno.h>
 #include <gfaserial.h>
-#include <byteswap.h>
 #include <gfabootlmast.h>
-#include "bl_commands.h"
+#include "../libmininet/dbghlp.h"
 
 #ifdef _TARGET_BUILD
 #define _DEVICE_NAME				"/dev/ttyO4"
@@ -14,587 +16,122 @@
 #define _DEVICE_NAME				"/dev/tty0"
 #endif	//	_TARGET_BUILD
 
-#define _SLAVE_NODE_ADDR			0xFF
+#define _NODE_ADDR					0x11
 #define _BL_MATERIAL				"G.Z.40015 P01"
-#define _BL_SERIAL					"18-080015 1409" // "012345678901234"
-
-#define TRACE(...)					printf(__VA_ARGS__), fflush(stdout)
-
-#if 0
-#define TRACE_FRAME(f)				GfaMininetMasterDumpFrame(stdout, f)
-#else
-#define TRACE_FRAME(f)
-#endif
-
-#define _countof(a)					(sizeof(a) / sizeof(*a))
+#define _BL_SERIAL					"18-080015 1409"
+#define _IMG_FILE_PATH				"/opt/sflash/OLS-1V1_0009_crc.bin"
+//#define _IMG_FILE_PATH				"/opt/sflash/test.jpg"
 
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
+#define _BAUD_HI					115200 // 921600 460800 230400 115200
+#define _BAUD_LO					19200
 
-#define GFA_APP_BOOTLOADER_START_ADDRESS								((uint32_t)0x00000000)
-#define GFA_APP_APPLICATION_START_ADDRESS								((uint32_t)0x00002000)
-#define GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH								16		// including the zero terminator
-#define GFA_APP_MAX_IMG_NAME_BUILD_LENGTH								24		// including the zero terminator
-#define GFA_APP_IMG_HEADER_PREFIX_0										((uint32_t)0xFF01FF02)
-#define GFA_APP_IMG_HEADER_PREFIX_1										((uint32_t)0xFF03FF04)
+// gfativaflashutil
+/////////////////////////////////////////////////////////////////////////////
 
-////////////////////////////////////////////////////////////////////////////////////
-
-typedef struct _GFA_APP_IMG_HEADER
+static uint64_t _Timespec2Ns(const struct timespec *pts)
 {
-	const uintptr_t		nPrefix0;
-	const uintptr_t		nPrefix1;
-	const uintptr_t		nImgLength;
-	const uintptr_t		nImgCRC32;
-	const uintptr_t		nReserved[4];
-	union
-	{
-		struct
-		{
-			const char * const	pszImgMaterialNum;
-			const char * const	pszImgNameBuild;
-		}app;
-		struct
-		{
-			const char szImgMaterialNum[GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH];
-			const char szImgNameBuild[GFA_APP_MAX_IMG_NAME_BUILD_LENGTH];
-		}bl;
-	};
-}GFA_APP_IMG_HEADER, *LPGFA_APP_IMG_HEADER;
-typedef const GFA_APP_IMG_HEADER *LPCGFA_APP_IMG_HEADER;
-
-////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////
-
-static ssize_t _DataPayloadFromMininetFrame(LPCGFA_MININET_FRAME pFrame, void *pData, size_t nCbData)
-{
-	if(pFrame && pData && nCbData)
-	{
-		if(pFrame->len > 6)
-		{
-			size_t nDatalen = (size_t)pFrame->len - 6;
-
-			if(nDatalen <= nCbData)
-			{
-				memcpy(pData, &pFrame->data.by[1], nDatalen);
-				return (ssize_t)nDatalen;
-			}
-		}
-	}
-
-	errno = EINVAL;
-	return -1;
+	if(pts)
+		return (uint64_t)pts->tv_sec * 1000000000 + (uint64_t)pts->tv_nsec;
+	return (uint64_t)-1;
 }
 
-////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
 
-static ssize_t _PollBlData(HGFAMINEMST hMst, void *pData, size_t nCbData, uint32_t nTimeoutMS)
+static int64_t _TimespecDiff(const struct timespec *pts1, const struct timespec *pts2)
 {
-	if(hMst && pData && nCbData)
-	{
-		size_t s, nReceived = 0;
-		struct timeval tvRX;
-		ssize_t nRet = -1;
-		uint8_t cmd[32];
-		uint8_t txb[32];
-		uint8_t rxb[512];
-		uint8_t *pszData = (uint8_t*)pData;
-		tvRX.tv_sec		= nTimeoutMS / 1000;
-		tvRX.tv_usec	= (nTimeoutMS % 1000) * 1000;
-
-		GfaMininetMasterSaveTimeouts(hMst);
-		GfaMininetMasterSetTimeouts(hMst, &tvRX, NULL);
-
-		while(nReceived < nCbData)
-		{
-	        s = GfaBLM_BuildCmdDataPacket("BU", NULL, 0, cmd, sizeof(cmd), true);
-			nRet = GfaMininetMasterBuildFrame(hMst, _SLAVE_NODE_ADDR, 0, cmd, s, txb, sizeof(txb));
-
-			if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nRet)) <= 0)
-			{
-				nRet = -1;
-				break;
-			}
-
-			if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) > 0)
-			{
-				uint8_t nIndex;
-				nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, _SLAVE_NODE_ADDR, rxb, nRet, true, &nIndex);
-
-				if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
-				{
-					TRACE_FRAME((LPCGFA_MININET_FRAME)rxb);
-
-					if((nRet = _DataPayloadFromMininetFrame((LPCGFA_MININET_FRAME)rxb, pszData, nCbData - nReceived)) > 0)
-					{
-						pszData += nRet;
-						nReceived += nRet;
-					}
-	            }
-				else if(nRet == MINET_SLAVE_RESPONSE_ACK)
-				{
-					TRACE("\nACK ...\n");
-				}
-			}
-			else
-			{
-				nReceived = nRet;
-				break;
-			}
-		}
-
-		GfaMininetMasterRestoreTimeouts(hMst);
-		return nReceived;
-	}
-
-	errno = EINVAL;
-	return -1;
-}
-
-static int _BlPing(HGFAMINEMST hMst)
-{
-	uint8_t nIndex;
-	ssize_t nRet, nLen;
-	uint8_t nCmd = COMMAND_PING;
-	char txb[32], rxb[32], cmd[8], ack[2];
-
-    size_t s = GfaBLM_BuildCmdDataPacket("BU", &nCmd, 1, cmd, sizeof(cmd), true);
-    nLen = GfaMininetMasterBuildFrame(hMst, _SLAVE_NODE_ADDR, 0, cmd, s, txb, sizeof(txb));
-	TRACE_FRAME((LPCGFA_MININET_FRAME)txb);
-
-	if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) < nLen)
-		return nRet;
-
-	if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) < 0)
-		return nRet;
+	int64_t nRet = 0;
 
-	nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, _SLAVE_NODE_ADDR, rxb, nRet, true, &nIndex);
-
-	if(	(nRet == MINET_SLAVE_RESPONSE_SUCCESS) ||
-		(nRet == MINET_SLAVE_RESPONSE_ACK))
-	{
-		if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
-		{
-			TRACE_FRAME((LPCGFA_MININET_FRAME)rxb);
-			if((nRet = _DataPayloadFromMininetFrame((LPCGFA_MININET_FRAME)rxb, ack, 2)) != 2)
-				return -1;
-		}
-		else
-		{
-			if((nRet = _PollBlData(hMst, ack, 2, 200)) != 2)
-				return -1;
-		}
-
-		if(ack[0] == 0)
-		{
-			return (ack[1] == COMMAND_ACK);
-		}
-    }
-	else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+	if(pts1 && pts2)
 	{
-    }
-
-	return -1;
-}
-
-static int _BlGetStatus(HGFAMINEMST hMst, uint8_t *pbStatus)
-{
-	uint8_t nIndex;
-	ssize_t nRet, nLen;
-	uint8_t nCmd = COMMAND_GET_STATUS;
-	char txb[32], rxb[32], cmd[8], ack[3], stat[3];
-
-    size_t s = GfaBLM_BuildCmdDataPacket("BU", &nCmd, 1, cmd, sizeof(cmd), true);
-    nLen = GfaMininetMasterBuildFrame(hMst, _SLAVE_NODE_ADDR, 0, cmd, s, txb, sizeof(txb));
-	TRACE_FRAME((LPCGFA_MININET_FRAME)txb);
-
-	if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) < nLen)
-		return nRet;
-
-	if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) < 0)
-		return nRet;
-
-	nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, _SLAVE_NODE_ADDR, rxb, nRet, true, &nIndex);
-
-	if(	(nRet == MINET_SLAVE_RESPONSE_SUCCESS) ||
-		(nRet == MINET_SLAVE_RESPONSE_ACK))
-	{
-		if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
-		{
-			TRACE_FRAME((LPCGFA_MININET_FRAME)rxb);
-			if((nRet = _DataPayloadFromMininetFrame((LPCGFA_MININET_FRAME)rxb, ack, 2)) != 2)
-				return -1;
-		}
-		else
-		{
-			if((nRet = _PollBlData(hMst, ack, 2, 200)) != 2)
-				return -1;
-		}
-
-		if(ack[0] == 0)
-		{
-			if(ack[1] == COMMAND_ACK)
-			{
-				if((nRet = _PollBlData(hMst, stat, 3, 200)) != 3)
-					return -1;
-
-				if((stat[0] == 3) && (stat[1] == stat[2]))
-				{
-					if(pbStatus)
-						*pbStatus = stat[2];
-				    nLen = GfaMininetMasterBuildFrame(hMst, _SLAVE_NODE_ADDR, 0, "BU\xCC", 3, txb, sizeof(txb));
-					TRACE_FRAME((LPCGFA_MININET_FRAME)txb);
-
-					if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) != nLen)
-						return nRet;
-
-					if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) <= 0)
-						return nRet;
-
-					nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, _SLAVE_NODE_ADDR, rxb, nRet, true, &nIndex);
-					return 0;
-				}
-				else
-				{
-				}
-			}
-		}
-    }
-	else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
-	{
-		// TODO!
-    }
-
-	return -1;
-}
-
-static int _BlSetBaudrate(HGFAMINEMST hMst, uint32_t nNewBaudrate)
-{
-	uint8_t nIndex;
-	size_t s;
-	ssize_t nRet, nLen;
-	char txb[32], rxb[32], cmd[8];
-	uint32_t nBaudrate = bswap_32(nNewBaudrate);
-
-	s = GfaBLM_BuildCmdDataPacket("BB", &nBaudrate, sizeof(nBaudrate), cmd, sizeof(cmd), false);
-    nLen = GfaMininetMasterBuildFrame(hMst, _SLAVE_NODE_ADDR, 0, cmd, s, txb, sizeof(txb));
-	TRACE_FRAME((LPCGFA_MININET_FRAME)txb);
-
-	if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) != nLen)
-		return nRet;
-
-	if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) < 0)
-		return nRet;
-
-	nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, _SLAVE_NODE_ADDR, rxb, nRet, true, &nIndex);
-
-	if(nRet == MINET_SLAVE_RESPONSE_ACK)
-	{
-		GFA_SER_CFG_PARAMS scp;
-
-		if((nRet = GfaMininetMasterGetConfigParams(hMst, &scp, sizeof(scp))) == sizeof(scp))
-		{
-			scp.baud = nNewBaudrate;
-            return GfaMininetMasterSetConfigParams(hMst, &scp, sizeof(scp));
-		}
+		uint64_t t1 = _Timespec2Ns(pts1);
+		uint64_t t2 = _Timespec2Ns(pts2);
+		nRet = (int64_t)(t1 - t2);
 	}
 
-	return -1;
+	return nRet;
 }
 
-static int _BlDumpMemory(HGFAMINEMST hMst, uint32_t nAddress, uint32_t nCntDwords, void *pBuffer, size_t nCbBuffer)
+#ifdef _DEBUG
+static void _BuCmdDownloadStatus(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, int nCtx, int nErrorCode)
+#else	//	_DEBUG
+static void _BuCmdDownloadStatus(uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, int nCtx, int nErrorCode)
+#endif	//	_DEBUG
 {
-	uint8_t nIndex;
-	size_t s;
-	ssize_t nRet, nLen;
-	char txb[32], rxb[128], cmd[10], dmp[sizeof(uint32_t) * nCntDwords];
-
-	if(nCntDwords > 16)
-		nCntDwords = 16;
-
-	if((nCntDwords * sizeof(uint32_t)) > nCbBuffer)
-		return -1;
-
-	struct _MEM
+	static struct timespec tsStart, tsEnd;
+	int64_t nInterval;
+	
+	switch(nCtx)
 	{
-		uint32_t nAddr;
-		uint32_t nCount;
-	}mem = {bswap_32(nAddress), bswap_32(nCntDwords)};
-
-	s = GfaBLM_BuildCmdDataPacket("BD", &mem, sizeof(mem), cmd, sizeof(cmd), false);
-    nLen = GfaMininetMasterBuildFrame(hMst, _SLAVE_NODE_ADDR, 0, cmd, s, txb, sizeof(txb));
-	TRACE_FRAME((LPCGFA_MININET_FRAME)txb);
-
-	if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) != nLen)
-		return nRet;
-
-	if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) < 0)
-		return nRet;
-
-	nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, _SLAVE_NODE_ADDR, rxb, nRet, true, &nIndex);
-
-	if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
-	{
-		TRACE_FRAME((LPCGFA_MININET_FRAME)rxb);
-		if((nRet = _DataPayloadFromMininetFrame((LPCGFA_MININET_FRAME)rxb, dmp, sizeof(uint32_t) * nCntDwords)) != (ssize_t)(sizeof(uint32_t) * nCntDwords))
-			return -1;
-		memcpy(pBuffer, dmp, sizeof(uint32_t) * nCntDwords);
-		return 0;
-	}
-	else if(nRet == MINET_SLAVE_RESPONSE_ACK)
-	{
-		if((nRet = _PollBlData(hMst, dmp, sizeof(uint32_t) * nCntDwords, 200)) != (ssize_t)(sizeof(uint32_t) * nCntDwords))
-			return -1;
-		memcpy(pBuffer, dmp, sizeof(uint32_t) * nCntDwords);
-		return 0;
-	}
-
-	return -1;
-}
-
-static int _BlReadMaterialAndSerial(HGFAMINEMST hMst, char *pszMaterial, size_t nCbMaterial, char *pszSerial, size_t nCbSerial)
-{
-	uint8_t nIndex;
-	ssize_t nRet, nLen;
-	char txb[32], rxb[64], data[32];
-
-	if(!pszMaterial || (nCbMaterial < 16) || !pszSerial || (nCbSerial < 16))
-		return -1;
-
-    nLen = GfaMininetMasterBuildFrame(hMst, _SLAVE_NODE_ADDR, 0, "BR", 2, txb, sizeof(txb));
-	TRACE_FRAME((LPCGFA_MININET_FRAME)txb);
-
-	if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) != nLen)
-		return nRet;
-
-	if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) < 0)
-		return nRet;
-
-	nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, _SLAVE_NODE_ADDR, rxb, nRet, true, &nIndex);
-
-	if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
-	{
-		TRACE_FRAME((LPCGFA_MININET_FRAME)rxb);
-		if((nRet = _DataPayloadFromMininetFrame((LPCGFA_MININET_FRAME)rxb, data, sizeof(data))) != sizeof(data))
-			return -1;
-		memcpy(pszMaterial, data, 16);
-		pszMaterial[15] = '\0';
-		memcpy(pszSerial, &data[16], 16);
-		pszSerial[15] = '\0';
-		return 0;
-	}
-	else if(nRet == MINET_SLAVE_RESPONSE_ACK)
-	{
-		if((nRet = _PollBlData(hMst, data, sizeof(data), 200)) != (ssize_t)sizeof(data))
-			return -1;
-		memcpy(pszMaterial, data, 16);
-		pszMaterial[15] = '\0';
-		memcpy(pszSerial, &data[16], 16);
-		pszSerial[15] = '\0';
-		return 0;
-	}
-
-	return -1;
-}
-
-static int _BlWriteMaterialAndSerial(HGFAMINEMST hMst, const char *pszMaterial, const char *pszSerial)
-{
-	uint8_t nIndex;
-	size_t s;
-	ssize_t nRet, nLen;
-	size_t nLenMaterial, nLenSerial;
-	struct _TS
-	{
-		char szMaterial[16];
-		char szSerial[16];
-	}ts;
-	char txb[64], rxb[32], cmd[64];
-
-	if(!pszMaterial || !pszSerial)
-		return -1;
-
-	nLenMaterial	= strlen(pszMaterial);
-	nLenSerial		= strlen(pszSerial);
-
-	if((nLenMaterial > 15) || (nLenSerial > 15))
-		return -1;
-
-	memcpy(ts.szMaterial, pszMaterial, nLenMaterial);
-	if(nLenMaterial < 15)
-		memset(&ts.szMaterial[nLenMaterial], ' ', 15 - nLenMaterial);
-	ts.szMaterial[15] = '\0';
-
-	memcpy(ts.szSerial, pszSerial, nLenSerial);
-	if(nLenSerial < 15)
-		memset(&ts.szSerial[nLenSerial], ' ', 15 - nLenSerial);
-	ts.szSerial[15] = '\0';
-
-	s = GfaBLM_BuildCmdDataPacket("BW", &ts, sizeof(ts), cmd, sizeof(cmd), false);
-    nLen = GfaMininetMasterBuildFrame(hMst, _SLAVE_NODE_ADDR, 0, cmd, s, txb, sizeof(txb));
-	TRACE_FRAME((LPCGFA_MININET_FRAME)txb);
-
-	if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) != nLen)
-		return nRet;
-
-	if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) < 0)
-		return nRet;
-
-	nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, _SLAVE_NODE_ADDR, rxb, nRet, true, &nIndex);
-
-	if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
-	{
-		TRACE_FRAME((LPCGFA_MININET_FRAME)rxb);
-		return 0;
-	}
-	else if(nRet == MINET_SLAVE_RESPONSE_ACK)
-	{
-		return 0;
-	}
-
-	return -1;
-}
-
-static int _BlExecute(HGFAMINEMST hMst)
-{
-	uint8_t nIndex;
-	ssize_t nRet, nLen;
-	char txb[32], rxb[32];
-
-    nLen = GfaMininetMasterBuildFrame(hMst, _SLAVE_NODE_ADDR, 0, "BE", 2, txb, sizeof(txb));
-	TRACE_FRAME((LPCGFA_MININET_FRAME)txb);
-
-	if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) != nLen)
-		return nRet;
-
-	if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) < 0)
-		return nRet;
-
-	nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, _SLAVE_NODE_ADDR, rxb, nRet, true, &nIndex);
-
-	if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
-	{
-		TRACE_FRAME((LPCGFA_MININET_FRAME)rxb);
-		// TODO: application response
-	}
-	else if(nRet == MINET_SLAVE_RESPONSE_ACK)
-	{
-		return 0;
+	case 0:
+		TRACE("\n%s:%d: %s!\n", pszFile, nLine, GfaBlmStrError(nErrorCode));
+		break;
+	case 1:
+		clock_gettime(CLOCK_MONOTONIC, &tsStart);
+		TRACE("Start download of %u Bytes to Node 0x%02hhX @ 0x%X.\n", nCbData, nNodeAddr, nFlashStartAddr);
+		break;
+	case 2:
+		break;
+	case 3:
+		clock_gettime(CLOCK_MONOTONIC, &tsEnd);
+		nInterval = _TimespecDiff(&tsEnd, &tsStart);
+		TRACE("Erased Flash in %lld ms.\n", nInterval / 1000000);
+		break;
+	default:
+		break;
 	}
-
-	return -1;
 }
 
-static int _BlIsExecuting(HGFAMINEMST hMst)
+#ifdef _DEBUG
+static void _BuCmdSendDataStatus(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nCbBlock, uint32_t nCbData, int nCtx, int nErrorCode)
+#else	//	_DEBUG
+static void _BuCmdSendDataStatus(uint8_t nNodeAddr, uint32_t nCbBlock, uint32_t nCbData, int nCtx, int nErrorCode)
+#endif	//	_DEBUG
 {
-	uint8_t nIndex;
-	ssize_t nRet, nLen;
-	char txb[32], rxb[32];
-
-    nLen = GfaMininetMasterBuildFrame(hMst, _SLAVE_NODE_ADDR, 0, "BU", 2, txb, sizeof(txb));
-	TRACE_FRAME((LPCGFA_MININET_FRAME)txb);
-
-	if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) != nLen)
-		return nRet;
-
-	if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) < 0)
-		return nRet;
-
-	nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, _SLAVE_NODE_ADDR, rxb, nRet, true, &nIndex);
-
-	if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+	static struct timespec tsStart, tsEnd;
+	static uint32_t nBlockNr;
+	int64_t nInterval;
+	
+	switch(nCtx)
 	{
-		TRACE_FRAME((LPCGFA_MININET_FRAME)rxb);
-		// TODO: application response
-		return 1;
-	}
-	else if(nRet == MINET_SLAVE_RESPONSE_ACK)
-	{
-		return 0;
+	case 0:
+		TRACE("\n%s:%d: %s!\n", pszFile, nLine, GfaBlmStrError(nErrorCode));
+		break;
+	case 1:
+		nBlockNr = 0;
+		clock_gettime(CLOCK_MONOTONIC, &tsStart);
+		TRACE("Start sending data to Node 0x%02hhX - block size: %u bytes.\n", nNodeAddr, nCbBlock);
+		break;
+	case 2:
+#if 1
+		if(nBlockNr > 0)
+			TRACE("\b\b\b\b\b\b");
+		TRACE("%06u", nCbData);
+#endif
+		++nBlockNr;
+		break;
+	case 3:
+		clock_gettime(CLOCK_MONOTONIC, &tsEnd);
+		nInterval = _TimespecDiff(&tsEnd, &tsStart);
+		TRACE("\nSent %u blocks to Node 0x%02hhX in %llu ms.\n", nBlockNr, nNodeAddr, nInterval / 1000000);
+		break;
+	default:
+		break;
 	}
-
-	return -1;
 }
 
-static int _BlGetImgInfo(HGFAMINEMST hMst, uint32_t *pnImgLength, uint32_t *pnImgCRC32)
+static void _TraceImageInfo(const char *pszContext, LPCGFA_IMG_INFO pii)
 {
-	if(hMst && pnImgLength && pnImgCRC32)
+	if(pszContext && pii && pii->nImgLength != 0xFFFFFFFF && pii->nImgCRC32 != 0xFFFFFFFF)
 	{
-		ssize_t nRet = 0;
-		int nDumpIndex = 0;
-		bool bNeedMore;
-		uint32_t i, nDumpAddr, nDumpLen, nBufLen;
-		uint32_t aDump[24] = {0};
-
-		for(i = 0; i < 257; i += 16)
-		{
-			nDumpAddr = GFA_APP_BOOTLOADER_START_ADDRESS + i * sizeof(uint32_t);
-			nBufLen = nDumpLen = 16;
-
-			do
-			{
-				bNeedMore = false;
-
-				if((nRet = _BlDumpMemory(hMst, nDumpAddr, nDumpLen, &aDump[nDumpIndex], sizeof(aDump) - nDumpIndex * sizeof(uint32_t))) == 0)
-				{
-					uint32_t j;
-					LPCGFA_APP_IMG_HEADER paih;
-//					TRACE("Address: %08X, Length: %2u\n", nDumpAddr, nDumpLen);
-
-					for(j = nDumpIndex; j < (nDumpLen + nDumpIndex); ++j)
-					{
-						aDump[j] = bswap_32(aDump[j]);
-					}
-
-					for(j = 0; j < nBufLen; ++j)
-					{
-						paih = (LPCGFA_APP_IMG_HEADER)&aDump[j];
-
-						if(paih->nPrefix0 == GFA_APP_IMG_HEADER_PREFIX_0)
-						{
-							if(j < (nBufLen - 1))
-							{
-								if(paih->nPrefix1 == GFA_APP_IMG_HEADER_PREFIX_1)
-								{
-									if(j < (nBufLen - 3))
-									{
-										*pnImgLength	= paih->nImgLength;
-										*pnImgCRC32		= paih->nImgCRC32;
-										return 0;
-									}
-									else
-									{
-										nDumpAddr	+= nDumpLen * sizeof(uint32_t);
-										nDumpIndex	= nDumpLen;
-										nDumpLen	= 2;
-										nBufLen		+= nDumpLen;
-										bNeedMore	= true;
-										break;
-									}
-								}
-							}
-							else
-							{
-								nDumpAddr	+= nDumpLen * sizeof(uint32_t);
-								nDumpIndex	= nDumpLen;
-								nDumpLen	= 3;
-								nBufLen		+= nDumpLen;
-								bNeedMore	= true;
-								break;
-							}
-						}
-					}
-				}
-			}
-			while(bNeedMore);
-		}
-
-		return -1;
+		TRACE("%s Image Information:\n", pszContext);
+		TRACE("  Length:  %u\n", pii->nImgLength);
+		TRACE("  CRC32:   0x%08X\n", pii->nImgCRC32);
+		TRACE("  Mat.Nr.: %s\n", pii->szImgMaterialNum);
+		TRACE("  Build:   %s\n", pii->szImgNameBuild);
 	}
-
-	errno = EINVAL;
-	return -1;
 }
 
+////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////
 
 int main(void)
@@ -603,18 +140,19 @@ int main(void)
 
 	////////////////////////////////////////////////////////////////////////////////
 
-	GFA_MININET_MST_CFG_PARAMS mmcp;
-	memset(&mmcp, 0, sizeof(mmcp));
+	GFA_BLM_CFG_PARAMS blmcp;
+	memset(&blmcp, 0, sizeof(blmcp));
 
-	if(GfaSerialGetDeviceInterface(&mmcp.devcfg.itf))
+	if(GfaSerialGetDeviceInterface(&blmcp.mmcp.devcfg.itf))
 	{
+		HGFABLM hBlm;
 		GFA_SER_CFG_PARAMS scp;
 		memset(&scp, 0, sizeof(scp));
 
 		////////////////////////////////////////////////////////////////////////////
 		// serial interface parameters
 
-		scp.baud			= 19200;
+		scp.baud			= _BAUD_LO;
 		scp.data			= 8;
 		scp.stop			= 1;
 		scp.parity			= 'N';
@@ -625,91 +163,102 @@ int main(void)
 		////////////////////////////////////////////////////////////////////////////
 		// mininet master configuration
 
-		mmcp.devcfg.pszDeviceName	= _DEVICE_NAME;
-		mmcp.devcfg.pDevParams		= &scp;
-		mmcp.devcfg.nSizeDevParams	= sizeof(scp);
+		blmcp.mmcp.devcfg.pszDeviceName		= _DEVICE_NAME;
+		blmcp.mmcp.devcfg.pDevParams		= &scp;
+		blmcp.mmcp.devcfg.nSizeDevParams	= sizeof(scp);
+		blmcp.pfnBuCmdDownloadStatus		= _BuCmdDownloadStatus;
+		blmcp.pfnBuCmdSendDataStatus		= _BuCmdSendDataStatus;
 
 		////////////////////////////////////////////////////////////////////////////
 		////////////////////////////////////////////////////////////////////////////
 		////////////////////////////////////////////////////////////////////////////
 
-		HGFAMINEMST hMst = GfaMininetMasterOpen(&mmcp);
-
-		if(hMst)
+		if((hBlm = GfaBlmOpen(&blmcp)))
 		{
-			uint8_t status;
+			uint32_t nImgCRC32;
+			GFA_BL_APP_IMG_INFO aii;
+			GFA_BLM_EXEC_CONTEXT ctx;
 			char szMaterial[16], szSerial[16];
-			uint32_t nImgLength = 0, nImgCRC32 = 0;
-
-            if((nRet = GfaMininetMasterResetSlaveIndex(hMst, _SLAVE_NODE_ADDR)) == 0)
-            	TRACE("\nReset Slave index.\n");
 
-            if((nRet = _BlIsExecuting(hMst)) != 0)
-            {
-				if((nRet = _BlExecute(hMst)) == 0)
-				{
-					TRACE("Executing Bootloader.\n");
-
-		            if((nRet = GfaMininetMasterResetSlaveIndex(hMst, _SLAVE_NODE_ADDR)) == 0)
-		            	TRACE("Reset Slave index.\n");
-				}
-	        }
-	        else
-	        {
-				TRACE("Bootloader is already executing.\n");
-	        }
-
-			if((nRet = _BlSetBaudrate(hMst, 115200)) == 0)
-			{
-				TRACE("Set Baudrate: %u\n", 115200);
-	        }
-
-			if((nRet = _BlPing(hMst)) == 1)
+			do
 			{
-				TRACE("Ping ok!\n");
-	        }
+//	            GfaBlmSetVerbosity(hBlm, 4);
+
+	            if((nRet = GfaBlmResetSlaveIndex(hBlm, _NODE_ADDR)) != 0)
+		        {
+					TRACE("%s!\n", GfaBlmStrError(errno));
+					break;
+		        }
+
+		        if((ctx = GfaBlmGetExecutionContext(hBlm, _NODE_ADDR)) == GfaBlmCtx_Err)
+		        {
+					TRACE("%s!\n", GfaBlmStrError(errno));
+					break;
+		        }
+		        
+		        TRACE("Currently running: %s\n", (ctx == GfaBlmCtx_App) ? "Application" : "Bootloader");
+
+	            if(ctx == GfaBlmCtx_App)
+	            {
+					if((nRet = GfaBlmBootloaderExecute(hBlm, _NODE_ADDR, &nImgCRC32, 500)) != 0)
+					{
+						TRACE("%s!\n", GfaBlmStrError(errno));
+						break;
+					}
+				}
 
-			if((nRet = _BlGetStatus(hMst, &status)) == 0)
-			{
-				TRACE("Status: 0x%02hhX\n", status);
-	        }
+				if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, _NODE_ADDR, _BAUD_HI)) != 0)
+				{
+					TRACE("%s!\n", GfaBlmStrError(errno));
+					break;
+		        }
 
-            if((nRet = _BlGetImgInfo(hMst, &nImgLength, &nImgCRC32)) == 0)
-			{
-				TRACE("Bootloader Img. Length: %u, Bootloader Img. CRC: 0x%08X\n", nImgLength, nImgCRC32);
-	        }
+	//            GfaBlmSetVerbosity(hBlm, 3);
 
-			if((nRet = _BlWriteMaterialAndSerial(hMst, "Material 1", "123456789-1")) == 0)
-			{
-				TRACE("Set Material and Serial Numbers ...\n");
-	        }
+	            if((nRet = GfaBlmBUCmdSendDataFile(hBlm, _NODE_ADDR, _IMG_FILE_PATH, 0x2000, 76, 5000)) == 0)
+	            {
+	//	            GfaBlmSetVerbosity(hBlm, 4);
 
-			if((nRet = _BlReadMaterialAndSerial(hMst, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) == 0)
-			{
-				TRACE("Material: \"%s\", Serial: \"%s\"\n", szMaterial, szSerial);
-	        }
+					TRACE("Resetting slave ...\n");
 
-			if((nRet = _BlWriteMaterialAndSerial(hMst, _BL_MATERIAL, _BL_SERIAL)) == 0)
-			{
-				TRACE("Set Material and Serial Numbers ...\n");
-	        }
+		            if((nRet = GfaBlmBUCmdReset(hBlm, _NODE_ADDR, 500)) != 0)
+		            {
+						TRACE("%s!\n", GfaBlmStrError(errno));
+						break;
+		            }
 
-			if((nRet = _BlReadMaterialAndSerial(hMst, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) == 0)
-			{
-				TRACE("Material: \"%s\", Serial: \"%s\"\n", szMaterial, szSerial);
-	        }
+	//	            GfaBlmSetVerbosity(hBlm, 0);
 
-			if((nRet = _BlSetBaudrate(hMst, 19200)) == 0)
-			{
-				TRACE("Set Baudrate: %u\n", 19200);
-	        }
+			        if((ctx = GfaBlmGetExecutionContext(hBlm, _NODE_ADDR)) == GfaBlmCtx_Err)
+		            {
+						TRACE("%s!\n", GfaBlmStrError(errno));
+						break;
+		            }
 
-			if((nRet = _BlPing(hMst)) == 1)
-			{
-				TRACE("Ping ok!\n");
-	        }
+			        TRACE("%s\n", (ctx == GfaBlmCtx_App) ? "Application started." : "Application failed to start!");
+	            }
+	            else
+	            {
+					TRACE("%s!\n", GfaBlmStrError(errno));
+					break;
+	            }
+	            
+	//            GfaBlmSetVerbosity(hBlm, 4);
+
+		        if((nRet = GfaBlmGetInfoBI(hBlm, _NODE_ADDR, &aii)) == 0)
+		        {
+		        	_TraceImageInfo("Bootloader", &aii.bl);
+		        	_TraceImageInfo("Application", &aii.app);
+		        }
+	            else if((nRet = GfaBlmGetInfoBD(hBlm, _NODE_ADDR, &aii)) > -2)
+				{
+		        	_TraceImageInfo("Bootloader", &aii.bl);
+		        	_TraceImageInfo("Application", &aii.app);
+		        }
+		    }
+		    while(false);
 
-			GfaMininetMasterClose(hMst);
+			GfaBlmClose(hBlm); // important!!!
 		}
 	}
 

+ 72 - 0
libmininet/dbghlp.c

@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "dbghlp.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+uint64_t Timeval2Us(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* Us2Timeval(uint64_t usTime, struct timeval *ptv)
+{
+	if(ptv)
+	{
+		ptv->tv_sec		= usTime / 1000000;
+		ptv->tv_usec	= usTime % 1000000;
+	}
+
+	return ptv;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+uint64_t Timespec2Ns(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* Ns2Timespec(uint64_t nsTime, struct timespec *pts)
+{
+	if(pts)
+	{
+		pts->tv_sec		= nsTime / 1000000000;
+		pts->tv_nsec	= nsTime % 1000000000;
+	}
+
+	return pts;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int64_t TimespecDiff(const struct timespec *pts1, const struct timespec *pts2)
+{
+	int64_t nRet = 0;
+
+	if(pts1 && pts2)
+	{
+		uint64_t t1 = Timespec2Ns(pts1);
+		uint64_t t2 = Timespec2Ns(pts2);
+		nRet = (int64_t)(t1 - t2);
+	}
+
+	return nRet;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GetTimespec(struct timespec *pts)
+{
+	clock_gettime(CLOCK_MONOTONIC, pts);
+}

+ 38 - 0
libmininet/dbghlp.h

@@ -0,0 +1,38 @@
+// dbghlp.h :
+//
+
+#if !defined(AGD_DBGHLP_H__43902563_76A4_4ADC_8FA2_DD924EAAA095__INCLUDED_)
+#define AGD_DBGHLP_H__43902563_76A4_4ADC_8FA2_DD924EAAA095__INCLUDED_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// dbghlp.h - Declarations:
+
+#ifdef _DEBUG
+#define TRACE(...)								printf(__VA_ARGS__), fflush(stdout)
+#else	//	_DEBUG
+#define TRACE(...)
+#endif	//	_DEBUG
+
+/////////////////////////////////////////////////////////////////////////////
+
+uint64_t Timeval2Us(const struct timeval *ptv);
+const struct timeval* Us2Timeval(uint64_t usTime, struct timeval *ptv);
+
+uint64_t Timespec2Ns(const struct timespec *pts);
+const struct timespec* Ns2Timespec(uint64_t nsTime, struct timespec *pts);
+int64_t TimespecDiff(const struct timespec *pts1, const struct timespec *pts2);
+void GetTimespec(struct timespec *pts);
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_DBGHLP_H__43902563_76A4_4ADC_8FA2_DD924EAAA095__INCLUDED_)

+ 1446 - 4
libmininet/gfabootlmast.c

@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <string.h>
+#include <malloc.h>
 #include <ctype.h>
 #include <errno.h>
 #include <unistd.h>
@@ -8,10 +9,1431 @@
 #include <byteswap.h>
 #include "bl_commands.h"
 #include "gfabootlmast.h"
+#include "dbghlp.h"
+
+////////////////////////////////////////////////////////////////////////////////////
+
+#define _dword_offset(m)						(offsetof(GFA_APP_IMG_HEADER, m) / sizeof(uint32_t) - 2)
+
+#ifdef _DEBUG
+#define _EXEC_CALLBACK(pfn, ...)				if(pfn) (*pfn)(__FILE__, __LINE__, __VA_ARGS__)
+#else	//	_DEBUG
+#define _EXEC_CALLBACK(pfn, ...)				if(pfn) (*pfn)(__VA_ARGS__)
+#endif	//	_DEBUG
+
+#define _BOOTLOADER_EXEC_WAIT_TIME				250
+#define _GFA_MAX_DUMP_DWORDS					16
+#define _MAX_SEND_DATA_BLOCK_SIZE				76
+#define _DEF_SEND_DATA_BLOCK_SIZE				64
+
+////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_BLM
+{
+	HGFAMINEMST hMst;
+	PFN_BU_CMD_DOWNLOAD_STATUS pfnBuCmdDownloadStatus;
+	PFN_BU_CMD_SEND_DATA_STATUS pfnBuCmdSendDataStatus;
+	int nVerbosity;
+}GFA_BLM, *LPGFA_BLM;
+typedef const GFA_BLM *LPCGFA_BLM;
+
+////////////////////////////////////////////////////////////////////////////////////
+
+#define GFA_APP_BOOTLOADER_START_ADDRESS								((uint32_t)0x00000000)
+#define GFA_APP_APPLICATION_START_ADDRESS								((uint32_t)0x00002000)
+#define GFA_APP_IMG_HEADER_PREFIX_0										((uint32_t)0xFF01FF02)
+#define GFA_APP_IMG_HEADER_PREFIX_1										((uint32_t)0xFF03FF04)
+
+////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_APP_IMG_HEADER
+{
+	const uint32_t	nPrefix0;
+	const uint32_t	nPrefix1;
+	const uint32_t	nImgLength;
+	const uint32_t	nImgCRC32;
+	const uint32_t	nReserved[4];
+	union
+	{
+		struct
+		{
+			const char * const	pszImgMaterialNum;
+			const char * const	pszImgNameBuild;
+		}app;
+		struct
+		{
+			const char szImgMaterialNum[GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH];
+			const char szImgNameBuild[GFA_APP_MAX_IMG_NAME_BUILD_LENGTH];
+		}bl;
+	};
+}GFA_APP_IMG_HEADER, *LPGFA_APP_IMG_HEADER;
+typedef const GFA_APP_IMG_HEADER *LPCGFA_APP_IMG_HEADER;
+
+////////////////////////////////////////////////////////////////////////////////////
+
+HGFABLM GfaBlmOpen(LPCGFA_BLM_CFG_PARAMS pblmcfg)
+{
+	if(pblmcfg)
+	{
+		HGFAMINEMST hMst = GfaMininetMasterOpen(&pblmcfg->mmcp);
+
+		if(hMst)
+		{
+			LPGFA_BLM pBlm = malloc(sizeof(GFA_BLM));
+			memset(pBlm, 0, sizeof(GFA_BLM));
+			pBlm->hMst = hMst;
+			pBlm->pfnBuCmdDownloadStatus = pblmcfg->pfnBuCmdDownloadStatus;
+			pBlm->pfnBuCmdSendDataStatus = pblmcfg->pfnBuCmdSendDataStatus;
+			return (HGFABLM)pBlm;
+		}
+
+		return NULL;
+	}
+
+	errno = EINVAL;
+	return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void GfaBlmClose(HGFABLM hBlm)
+{
+	if(hBlm)
+	{
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		GfaMininetMasterClose(pBlm->hMst);
+		free(pBlm);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmResetSlaveIndex(HGFABLM hBlm, uint8_t nNodeAddr)
+{
+	if(hBlm)
+	{
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		return GfaMininetMasterResetSlaveIndex(pBlm->hMst, nNodeAddr);
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaBlmBUCmdPollData(HGFABLM hBlm, uint8_t nNodeAddr, void *pData, size_t nCbData, uint32_t nTimeoutMS)
+{
+	if(hBlm && pData && nCbData && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		size_t s, nReceived = 0;
+		struct timeval tvRX;
+		ssize_t nLen, nRet = -1;
+		uint8_t cmd[32];
+		uint8_t txb[32];
+		uint8_t rxb[512];
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		uint8_t *pszData = (uint8_t*)pData;
+		tvRX.tv_sec		= nTimeoutMS / 1000;
+		tvRX.tv_usec	= (nTimeoutMS % 1000) * 1000;
+
+		GfaMininetMasterSaveTimeouts(pBlm->hMst);
+		GfaMininetMasterSetTimeouts(pBlm->hMst, &tvRX, NULL);
+
+		while(nReceived < nCbData)
+		{
+	        s = GfaBlmBuildCmdDataPacket("BU", 0, NULL, 0, cmd, sizeof(cmd), true);
+			nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, cmd, s, txb, sizeof(txb));
+
+			if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) <= 0)
+			{
+				nRet = -1;
+				break;
+			}
+
+			if((nLen = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) > 0)
+			{
+				uint8_t nIndex;
+				nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nLen, true, &nIndex);
+
+				if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+				{
+					if((nRet = GfaMininetMasterGetDataFromSlaveFrame(rxb, nLen, pszData, nCbData - nReceived)) > 0)
+					{
+						pszData += nRet;
+						nReceived += nRet;
+					}
+	            }
+				else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+				{
+					if(nTimeoutMS > 0)
+					{
+						if(nTimeoutMS >= 100)
+						{
+							usleep(100000);
+							nTimeoutMS -= 100;
+//							TRACE("\nACK ...\n");
+						}
+						else
+						{
+							usleep(nTimeoutMS * 1000);
+							nTimeoutMS = 0;
+//							TRACE("\nACK ...\n");
+						}
+					}
+					else
+					{
+						errno = ETIMEDOUT;
+						nReceived = 0;
+						break;
+					}
+				}
+				else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+				{
+					errno = -(int)nIndex;
+					nReceived = 0;
+					break;
+			    }
+				else
+				{
+					errno = EPROTO;
+					nReceived = 0;
+					break;
+				}
+			}
+			else
+			{
+				nReceived = 0;
+				break;
+			}
+		}
+
+		GfaMininetMasterRestoreTimeouts(pBlm->hMst);
+		return nReceived;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmBUCmdReset(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t nTimeoutMS)
+{
+	if(hBlm)
+	{
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		uint8_t nIndex;
+		size_t s;
+		ssize_t nRet, nLen;
+		uint8_t cmd = COMMAND_RESET;
+		uint8_t cmddata[16];
+		char txb[32], rxb[256], ack[2];
+		
+		if((nRet = GfaBlmBootloaderSetBaudrate(hBlm, nNodeAddr, 19200)) != 0)
+			return -1;
+
+		s = GfaBlmBuildCmdDataPacket("BU", 0, &cmd, 1, cmddata, sizeof(cmddata), true);
+	    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, cmddata, s, txb, sizeof(txb));
+
+		if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+			return nRet;
+		
+		if(NODE_IS_MULTICAST(nNodeAddr))
+			return 0;
+
+		if((nLen = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) < 0)
+			return nLen;
+
+		nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nLen, true, &nIndex);
+
+		if(	(nRet == MINET_SLAVE_RESPONSE_SUCCESS) ||
+			(nRet == MINET_SLAVE_RESPONSE_ACK))
+		{
+			if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+			{
+				if((nRet = GfaMininetMasterGetDataFromSlaveFrame(rxb, nLen, ack, 2)) != 2)
+					return -1;
+			}
+			else
+			{
+				if((nRet = GfaBlmBUCmdPollData(hBlm, nNodeAddr, ack, 2, 200)) != 2)
+					return -1;
+			}
+
+			if(	(ack[0] == 0) &&
+				(ack[1] == COMMAND_ACK))
+			{
+
+				do
+				{
+					if(nTimeoutMS > _BOOTLOADER_EXEC_WAIT_TIME)
+					{
+						usleep(_BOOTLOADER_EXEC_WAIT_TIME * 1000);
+						nTimeoutMS -= _BOOTLOADER_EXEC_WAIT_TIME;
+					}
+					else
+					{
+						usleep(nTimeoutMS * 1000);
+						nTimeoutMS = 0;
+					}
+
+					if((nRet = GfaMininetMasterResetSlaveIndex(pBlm->hMst, nNodeAddr)) == 0)
+						break;
+					GfaMininetMasterPurgeDeviceRXBuffer(pBlm->hMst);
+				}
+				while(nTimeoutMS > 0);
+
+				return nRet;
+			}
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+		{
+			errno = -(int)nIndex;
+			return -1;
+	    }
+
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmBUCmdPing(HGFABLM hBlm, uint8_t nNodeAddr)
+{
+	if(hBlm && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		uint8_t nIndex;
+		ssize_t nRet, nLen;
+		uint8_t nCmd = COMMAND_PING;
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		char txb[32], rxb[32], cmd[8], ack[2];
+
+	    size_t s = GfaBlmBuildCmdDataPacket("BU", 0, &nCmd, 1, cmd, sizeof(cmd), true);
+	    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, cmd, s, txb, sizeof(txb));
+
+		if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) < nLen)
+			return nRet;
+
+		if((nLen = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) < 0)
+			return nLen;
+
+		nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nLen, true, &nIndex);
+
+		if(	(nRet == MINET_SLAVE_RESPONSE_SUCCESS) ||
+			(nRet == MINET_SLAVE_RESPONSE_ACK))
+		{
+			if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+			{
+				if((nRet = GfaMininetMasterGetDataFromSlaveFrame(rxb, nLen, ack, 2)) != 2)
+					return -1;
+			}
+			else
+			{
+				if((nRet = GfaBlmBUCmdPollData(hBlm, nNodeAddr, ack, 2, 200)) != 2)
+					return -1;
+			}
+
+			if(ack[0] == 0)
+			{
+				return (ack[1] == COMMAND_ACK);
+			}
+			else
+			{
+				errno = EPROTO;
+				return -1;
+			}
+	    }
+		else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+		{
+			errno = -(int)nIndex;
+			return -1;
+	    }
+
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmBUCmdGetStatus(HGFABLM hBlm, uint8_t nNodeAddr, uint8_t *pbStatus)
+{
+	if(hBlm && pbStatus && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		uint8_t nIndex;
+		ssize_t nRet, nLen;
+		uint8_t nCmd = COMMAND_GET_STATUS;
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		char txb[32], rxb[32], cmd[8], ack[3], stat[3];
+
+	    size_t s = GfaBlmBuildCmdDataPacket("BU", 0, &nCmd, 1, cmd, sizeof(cmd), true);
+	    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, cmd, s, txb, sizeof(txb));
+
+		if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) < nLen)
+			return nRet;
+
+		if((nLen = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) < 0)
+			return nLen;
+
+		nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nLen, true, &nIndex);
+
+		if(	(nRet == MINET_SLAVE_RESPONSE_SUCCESS) ||
+			(nRet == MINET_SLAVE_RESPONSE_ACK))
+		{
+			if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+			{
+				if((nRet = GfaMininetMasterGetDataFromSlaveFrame(rxb, nLen, ack, 2)) != 2)
+					return -1;
+			}
+			else
+			{
+				if((nRet = GfaBlmBUCmdPollData(hBlm, nNodeAddr, ack, 2, 200)) != 2)
+					return -1;
+			}
+
+			if(ack[0] == 0)
+			{
+				if(ack[1] == COMMAND_ACK)
+				{
+					if((nRet = GfaBlmBUCmdPollData(hBlm, nNodeAddr, stat, 3, 200)) != 3)
+						return -1;
+
+					if((stat[0] == 3) && (stat[1] == stat[2]))
+					{
+						if(pbStatus)
+							*pbStatus = stat[2];
+					    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, "BU\xCC", 3, txb, sizeof(txb));
+
+						if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+							return nRet;
+
+						if((nRet = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) <= 0)
+							return nRet;
+
+						nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nRet, true, &nIndex);
+						return 0;
+					}
+					else
+					{
+						errno = EPROTO;
+						return -1;
+					}
+				}
+				else
+				{
+					errno = EPROTO;
+					return -1;
+				}
+			}
+			else
+			{
+				errno = EPROTO;
+				return -1;
+			}
+	    }
+		else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+		{
+			errno = -(int)nIndex;
+			return -1;
+	    }
+
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmBUCmdDownload(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, uint32_t nTimeoutMS)
+{
+	if(hBlm && nCbData && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		size_t s;
+		ssize_t nRet, nLen;
+		uint8_t nIndex, nStatus;
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		uint32_t nAddr = bswap_32(nFlashStartAddr), nCount = bswap_32(nCbData);
+		uint8_t txb[32], rxb[32], cmd[16], data[9], ack[2];
+		data[0] = COMMAND_DOWNLOAD;
+		struct timeval tv;
+		memcpy(&data[1], &nAddr, sizeof(nAddr));
+		memcpy(&data[5], &nCount, sizeof(nCount));
+		tv.tv_sec	= nTimeoutMS / 1000;
+		tv.tv_usec	= (nTimeoutMS % 1000) * 1000;
+
+		s = GfaBlmBuildCmdDataPacket("BU", 0, data, sizeof(data), cmd, sizeof(cmd), true);
+	    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, cmd, s, txb, sizeof(txb));
+
+		GfaMininetMasterSaveTimeouts(pBlm->hMst);
+		GfaMininetMasterSetTimeouts(pBlm->hMst, &tv, NULL);
+		
+		_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 1, 0);
+
+		if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+		{
+			_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 0, errno);
+			GfaMininetMasterRestoreTimeouts(pBlm->hMst);
+			return -1;
+		}
+		
+		if((nRet = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) <= 0)
+		{
+			_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 0, errno);
+			GfaMininetMasterRestoreTimeouts(pBlm->hMst);
+			return -1;
+		}
+		
+		_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 2, 0);
+		GfaMininetMasterRestoreTimeouts(pBlm->hMst);
+		nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nRet, true, &nIndex);
+
+		if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+		{
+			if((nRet = GfaMininetMasterGetDataFromSlaveFrame(rxb, nLen, ack, 2)) != 2)
+			{
+				_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 0, errno);
+				return -1;
+			}
+
+			if((ack[0] == 0) && (ack[1] == COMMAND_ACK))
+			{
+				if((nRet = GfaBlmBUCmdGetStatus(hBlm, nNodeAddr, &nStatus)))
+				{
+					_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 0, errno);
+					return -1;
+				}
+				if(nStatus == COMMAND_RET_SUCCESS)
+				{
+					_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 3, 0);
+					return 0;
+				}
+			}
+
+			errno = EPROTO;
+			return -1;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+		{
+			if((nRet = GfaBlmBUCmdPollData(hBlm, nNodeAddr, ack, 2, nTimeoutMS)) != 2)
+			{
+				_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 0, errno);
+				return -1;
+			}
+
+			if((ack[0] == 0) && (ack[1] == COMMAND_ACK))
+			{
+				if((nRet = GfaBlmBUCmdGetStatus(hBlm, nNodeAddr, &nStatus)))
+				{
+					_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 0, errno);
+					return -1;
+				}
+				if(nStatus == COMMAND_RET_SUCCESS)
+				{
+					_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 3, 0);
+					return 0;
+				}
+			}
+
+			errno = EPROTO;
+			_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 0, errno);
+			return -1;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+		{
+			errno = -(int)nIndex;
+			_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 0, errno);
+			return -1;
+		}
+		else
+		{
+			errno = EPROTO;
+			_EXEC_CALLBACK(pBlm->pfnBuCmdDownloadStatus, nNodeAddr, nFlashStartAddr, nCbData, 0, errno);
+			return -1;
+		}
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmBUCmdSendDataBlock(HGFABLM hBlm, uint8_t nNodeAddr, const void *pDataBlock, size_t nCbDataBlock)
+{
+	if(hBlm && pDataBlock && nCbDataBlock && (nCbDataBlock <= 250) && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		ssize_t nRet;
+		struct timeval tv;
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		tv.tv_sec	= 0;
+		tv.tv_usec	= 500000;
+		GfaMininetMasterSaveTimeouts(pBlm->hMst);
+		GfaMininetMasterSetTimeouts(pBlm->hMst, &tv, NULL);
+		
+		do
+		{
+			size_t s;
+			ssize_t nLen;
+			uint8_t nIndex, nStatus;
+			uint8_t txb[512], rxb[32], cmd[256], data[256], ack[2];
+			data[0] = COMMAND_SEND_DATA;
+			memcpy(&data[1], pDataBlock, nCbDataBlock);
+
+			s = GfaBlmBuildCmdDataPacket("BU", 0, data, nCbDataBlock + 1, cmd, sizeof(cmd), true);
+		    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, cmd, s, txb, sizeof(txb));
+
+			if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+			{
+				nRet = -1;
+				break;
+			}
+
+			if((nRet = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) <= 0)
+			{
+				nRet = -1;
+				break;
+			}
+
+			nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nRet, true, &nIndex);
+
+			if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+			{
+				if((nRet = GfaMininetMasterGetDataFromSlaveFrame(rxb, nLen, ack, 2)) != 2)
+				{
+					nRet = -1;
+					break;
+				}
+
+				if((ack[0] == 0) && (ack[1] == COMMAND_ACK))
+				{
+					if((nRet = GfaBlmBUCmdGetStatus(hBlm, nNodeAddr, &nStatus)))
+					{
+						nRet = -1;
+						break;
+					}
+					if(nStatus != COMMAND_RET_SUCCESS)
+					{
+						errno = -nStatus;
+						nRet = -1;
+						break;
+					}
+					nRet = 0;
+					break;
+				}
+
+				errno = EPROTO;
+				nRet = -1;
+				break;
+			}
+			else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+			{
+				if((nRet = GfaBlmBUCmdPollData(hBlm, nNodeAddr, ack, 2, 5000)) != 2)
+				{
+					nRet = -1;
+					break;
+				}
+
+				if((ack[0] == 0) && (ack[1] == COMMAND_ACK))
+				{
+					if((nRet = GfaBlmBUCmdGetStatus(hBlm, nNodeAddr, &nStatus)))
+					{
+						nRet = -1;
+						break;
+					}
+					if(nStatus != COMMAND_RET_SUCCESS)
+					{
+						errno = -nStatus;
+						nRet = -1;
+						break;
+					}
+					nRet = 0;
+					break;
+				}
+
+				errno = EPROTO;
+				nRet = -1;
+				break;
+			}
+			else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+			{
+				errno = -(int)nIndex;
+				nRet = -1;
+				break;
+			}
+		}
+		while(false);
+		
+		GfaMininetMasterRestoreTimeouts(pBlm->hMst);
+		return nRet;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmBUCmdSendData(HGFABLM hBlm, uint8_t nNodeAddr, const void *pData, size_t nCbData, size_t nCbBlock)
+{
+	if(hBlm && pData && nCbData && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		int nRet;
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		const uint8_t *pbData = (const uint8_t*)pData;
+		uint32_t nSent = 0;
+
+		if(!nCbBlock || nCbBlock < 4 || nCbBlock > _MAX_SEND_DATA_BLOCK_SIZE)
+			nCbBlock = _DEF_SEND_DATA_BLOCK_SIZE;
+		else
+			nCbBlock &= ~0x03;
+
+		_EXEC_CALLBACK(pBlm->pfnBuCmdSendDataStatus, nNodeAddr, nCbBlock, nSent, 1, 0);
+		
+		while(nCbData >= nCbBlock)
+		{
+			if((nRet = GfaBlmBUCmdSendDataBlock(hBlm, nNodeAddr, pbData, nCbBlock)) != 0)
+			{
+				_EXEC_CALLBACK(pBlm->pfnBuCmdSendDataStatus, nNodeAddr, nCbBlock, nSent, 0, errno);
+				return -1;
+			}
+			nCbData -= nCbBlock;
+			pbData += nCbBlock;
+			nSent += nCbBlock;
+
+			_EXEC_CALLBACK(pBlm->pfnBuCmdSendDataStatus, nNodeAddr, nCbBlock, nSent, 2, 0);
+		}
+		
+		if(nCbData)
+		{
+			if((nRet = GfaBlmBUCmdSendDataBlock(hBlm, nNodeAddr, pbData, nCbData)) != 0)
+			{
+				_EXEC_CALLBACK(pBlm->pfnBuCmdSendDataStatus, nNodeAddr, nCbBlock, nSent, 0, errno);
+				return -1;
+			}
+			nSent += nCbData;
+			nCbData = 0;
+
+			_EXEC_CALLBACK(pBlm->pfnBuCmdSendDataStatus, nNodeAddr, nCbBlock, nSent, 2, 0);
+		}
+
+		_EXEC_CALLBACK(pBlm->pfnBuCmdSendDataStatus, nNodeAddr, nCbBlock, nSent, 3, 0);
+		return 0;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmBUCmdSendDataFile(HGFABLM hBlm, uint8_t nNodeAddr, const char *pszFilename, uint32_t nFlashStartAddr, size_t nCbBlock, uint32_t nTimeoutMS)
+{
+	if(hBlm && pszFilename && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		int nRet = -1;
+		ssize_t nFileLen;
+		FILE *pf = NULL;
+		uint8_t *pBuf = NULL;
+		
+		do
+		{
+			if(!(pf = fopen(pszFilename, "rb")))
+				break;
+		    if(fseek(pf, 0, SEEK_END))
+				break;
+		    if((nFileLen = ftell(pf)) < 0)
+				break;
+		    if(fseek(pf, 0, SEEK_SET))
+				break;
+		    if(	(nFileLen > 0) &&
+		    	(pBuf = (uint8_t*)malloc(nFileLen)) &&
+		    	(fread(pBuf, 1, nFileLen, pf) == (size_t)nFileLen))
+		    {
+		        if((nRet = GfaBlmBUCmdDownload(hBlm, nNodeAddr, nFlashStartAddr, nFileLen, nTimeoutMS)) == 0)
+			    	nRet = GfaBlmBUCmdSendData(hBlm, nNodeAddr, pBuf, nFileLen, nCbBlock);
+		    }
+		}
+		while(false);
+		
+		if(pBuf)
+			free(pBuf);
+		if(pf)
+			fclose(pf);
+
+		return nRet;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+GFA_BLM_EXEC_CONTEXT GfaBlmGetExecutionContext(HGFABLM hBlm, uint8_t nNodeAddr)
+{
+	if(hBlm && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		uint8_t nIndex;
+		ssize_t nRet, nLen;
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		char txb[32], rxb[32];
+
+	    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, "BU", 2, txb, sizeof(txb));
+
+		if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+			return GfaBlmCtx_Err;
+
+		if((nLen = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) <= 0)
+			return GfaBlmCtx_Err;
+
+		nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nLen, true, &nIndex);
+
+		if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+			return GfaBlmCtx_Err;
+		else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+			return GfaBlmCtx_Boot;
+		else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+			return GfaBlmCtx_App;
+
+		return GfaBlmCtx_Err;
+	}
+
+	errno = EINVAL;
+	return GfaBlmCtx_Err;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmBootloaderExecute(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t *pnImgCRC32, uint32_t nTimeoutMS)
+{
+	if(hBlm && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		uint8_t nIndex;
+		uint32_t nImgCRC32;
+		ssize_t nRet, nLen;
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		char txb[32], rxb[32];
+
+	    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, "BE", 2, txb, sizeof(txb));
+
+		if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+			return -1;
+
+		if((nLen = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) < 0)
+			return nLen;
+
+		nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nLen, true, &nIndex);
+
+		if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+		{
+			if((nRet = GfaMininetMasterGetDataFromSlaveFrame(rxb, nLen, &nImgCRC32, sizeof(nImgCRC32))) == 4)
+			{
+				if(pnImgCRC32)
+					*pnImgCRC32 = bswap_32(nImgCRC32);
+
+				do
+				{
+					if(nTimeoutMS > _BOOTLOADER_EXEC_WAIT_TIME)
+					{
+						usleep(_BOOTLOADER_EXEC_WAIT_TIME * 1000);
+						nTimeoutMS -= _BOOTLOADER_EXEC_WAIT_TIME;
+					}
+					else
+					{
+						usleep(nTimeoutMS * 1000);
+						nTimeoutMS = 0;
+					}
+
+					if((nRet = GfaMininetMasterResetSlaveIndex(pBlm->hMst, nNodeAddr)) == 0)
+						break;
+					GfaMininetMasterPurgeDeviceRXBuffer(pBlm->hMst);
+				}
+				while(nTimeoutMS > 0);
+
+				return nRet;
+			}
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+		{
+			return 0;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+		{
+			errno = -(int)nIndex;
+			return -1;
+		}
+
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmBootloaderSetBaudrate(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t nBaudrate)
+{
+	if(hBlm)
+	{
+		uint8_t nIndex;
+		size_t s;
+		ssize_t nRet, nLen;
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		
+		if(GfaMininetMasterIsValidBaudrate(pBlm->hMst, nBaudrate))
+		{
+			char txb[32], rxb[32], cmd[8];
+			uint32_t nBr = bswap_32(nBaudrate);
+
+			s = GfaBlmBuildCmdDataPacket("BB", 0, &nBr, sizeof(nBr), cmd, sizeof(cmd), false);
+		    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, cmd, s, txb, sizeof(txb));
+
+			if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+				return nRet;
+			
+			if(NODE_IS_MULTICAST(nNodeAddr))
+				return 0;
+
+			if((nLen = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) < 0)
+				return nLen;
+
+			nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nLen, true, &nIndex);
+
+			if(nRet == MINET_SLAVE_RESPONSE_ACK)
+			{
+				return GfaMininetMasterSetBaudrate(pBlm->hMst, nBaudrate);
+			}
+			else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+			{
+				errno = -(int)nIndex;
+				return -1;
+			}
+
+			return -1;
+		}
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmBootloaderDump(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t nAddress, uint32_t nCntDwords, void *pBuffer, size_t nCbBuffer)
+{
+	if(hBlm && pBuffer && nCntDwords && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		size_t s;
+		uint8_t nIndex;
+		ssize_t nRet, nLen;
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		uint32_t i, dmp[_GFA_MAX_DUMP_DWORDS];
+		char txb[32], rxb[128], cmd[10];
+
+		if(nCntDwords > _GFA_MAX_DUMP_DWORDS)
+			nCntDwords = _GFA_MAX_DUMP_DWORDS;
+
+		if((nCntDwords * sizeof(uint32_t)) > nCbBuffer)
+		{
+			errno = ENOMEM;
+			return -1;
+		}
+
+		struct _MEM
+		{
+			uint32_t nAddr;
+			uint32_t nCount;
+		}mem = {bswap_32(nAddress), bswap_32(nCntDwords)};
+
+		s = GfaBlmBuildCmdDataPacket("BD", 0, &mem, sizeof(mem), cmd, sizeof(cmd), false);
+	    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, cmd, s, txb, sizeof(txb));
+
+		if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+			return nRet;
+
+		if((nLen = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) < 0)
+			return nLen;
+
+		nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nLen, true, &nIndex);
+
+		if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+		{
+			if((nRet = GfaMininetMasterGetDataFromSlaveFrame(rxb, nLen, dmp, sizeof(uint32_t) * nCntDwords)) != (ssize_t)(sizeof(uint32_t) * nCntDwords))
+				return -1;
+			for(i = 0; i < nCntDwords; ++i)
+			{
+				dmp[i] = bswap_32(dmp[i]);
+			}
+			memcpy(pBuffer, dmp, sizeof(uint32_t) * nCntDwords);
+			return 0;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+		{
+			if((nRet = GfaBlmBUCmdPollData(hBlm, nNodeAddr, dmp, sizeof(uint32_t) * nCntDwords, 200)) != (ssize_t)(sizeof(uint32_t) * nCntDwords))
+				return -1;
+			for(i = 0; i < nCntDwords; ++i)
+			{
+				dmp[i] = bswap_32(dmp[i]);
+			}
+			memcpy(pBuffer, dmp, sizeof(uint32_t) * nCntDwords);
+			return 0;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+		{
+			errno = -(int)nIndex;
+			return -1;
+		}
+
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+int GfaBlmGetImgInfo(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t nDumpAddr, bool bCtxIsApp, LPGFA_IMG_INFO pii)
+{
+	if(hBlm && pii && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		ssize_t nRet = 0;
+		uint32_t i, j, nPfx0Addr = 0;
+		int32_t nPfx0Index = -1, nPfx1Index = -1;
+		uint32_t aDump[_GFA_MAX_DUMP_DWORDS];
+		GFA_APP_IMG_HEADER aih;
+		memset(&aih, 0, sizeof(aih));
+		memset(pii, 0, sizeof(GFA_IMG_INFO));
+
+		for(i = 0; i < 257; i += _GFA_MAX_DUMP_DWORDS)
+		{
+			if((nRet = GfaBlmBootloaderDump(hBlm, nNodeAddr, nDumpAddr, _GFA_MAX_DUMP_DWORDS, aDump, sizeof(aDump))) == 0)
+			{
+				for(j = 0; j < _GFA_MAX_DUMP_DWORDS; ++j, nDumpAddr += sizeof(uint32_t))
+				{
+					switch(aDump[j])
+					{
+					case GFA_APP_IMG_HEADER_PREFIX_0:
+						nPfx0Addr = nDumpAddr;
+						nPfx0Index = i + j;
+						continue;
+					case GFA_APP_IMG_HEADER_PREFIX_1:
+						nPfx1Index = i + j;
+						break;
+					default:
+						break;
+					}
+
+					if((nPfx0Index >= 0) && (nPfx1Index == (nPfx0Index + 1)))
+					{
+						uint32_t nDmpStart = nPfx0Addr + 2 * sizeof(uint32_t), *pDwDst = ((uint32_t*)&aih) + 2;
+						uint32_t nCntDwAvail = 15 - j;
+
+						if(bCtxIsApp)
+						{
+							uint32_t nDwOffsImgMaterialNum = _dword_offset(app.pszImgMaterialNum);
+							uint32_t nDwOffsImgNameBuild = _dword_offset(app.pszImgNameBuild);
+							uint32_t nDwOffsImgCRC32 = _dword_offset(nImgCRC32);
+							size_t nSizeDst = (nDwOffsImgNameBuild + 1) * sizeof(uint32_t);
+							uint32_t nCntDwToDmp, nCntDwToCpy;
+
+							if(nCntDwAvail > nDwOffsImgNameBuild)
+							{
+								// have nImgLength, nImgCRC32, pszImgMaterialNum, pszImgNameBuild
+								// need nothing
+								nCntDwToCpy = nDwOffsImgNameBuild + 1;
+								nCntDwToDmp = 0;
+								memcpy(pDwDst, &aDump[j + 1], nCntDwToCpy * sizeof(uint32_t));
+							}
+							else if(nCntDwAvail == nDwOffsImgNameBuild)
+							{
+								// have nImgLength, nImgCRC32, pszImgMaterialNum
+								// need pszImgNameBuild
+								nCntDwToCpy = nDwOffsImgNameBuild;
+								nCntDwToDmp = 1;
+								nDmpStart += nCntDwToCpy * sizeof(uint32_t);
+								memcpy(pDwDst, &aDump[j + 1], nCntDwToCpy * sizeof(uint32_t));
+								pDwDst += nCntDwToCpy;
+								nSizeDst -= nCntDwToCpy * sizeof(uint32_t);
+							}
+							else if(nCntDwAvail > nDwOffsImgCRC32)
+							{
+								// have nImgLength, nImgCRC32
+								// need pszImgMaterialNum, pszImgNameBuild
+								nCntDwToCpy = 2;
+								nCntDwToDmp = 2;
+								nDmpStart += nDwOffsImgMaterialNum * sizeof(uint32_t);
+								memcpy(pDwDst, &aDump[j + 1], nCntDwToCpy * sizeof(uint32_t));
+								pDwDst += nDwOffsImgMaterialNum;
+								nSizeDst -= nDwOffsImgMaterialNum * sizeof(uint32_t);
+							}
+							else if(nCntDwAvail == nDwOffsImgCRC32)
+							{
+								// have nImgLength
+								// need nImgCRC32, pszImgMaterialNum, pszImgNameBuild
+								nCntDwToCpy = nDwOffsImgCRC32;
+								nCntDwToDmp = 7; // 1 + 4 + 2
+								nDmpStart += sizeof(uint32_t);
+								memcpy(pDwDst, &aDump[j + 1], nCntDwToCpy * sizeof(uint32_t));
+								pDwDst += nCntDwToCpy;
+								nSizeDst -= nCntDwToCpy * sizeof(uint32_t);
+							}
+							else
+							{
+								// have nothing
+								// need nImgLength, nImgCRC32, pszImgMaterialNum, pszImgNameBuild
+								nCntDwToCpy = 0;
+								nCntDwToDmp = nDwOffsImgNameBuild + 1; // 2 + 4 + 2
+							}
+
+							if(nCntDwToDmp)
+							{
+								if((nRet = GfaBlmBootloaderDump(hBlm, nNodeAddr, nDmpStart, nCntDwToDmp, pDwDst, nSizeDst)) != 0)
+									return -1;
+							}
+
+							pii->nImgLength	= aih.nImgLength;
+							pii->nImgCRC32	= aih.nImgCRC32;
+							if((nRet = GfaBlmBootloaderDump(hBlm, nNodeAddr, (uint32_t)aih.app.pszImgMaterialNum, GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH / sizeof(uint32_t), pii->szImgMaterialNum, GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH)) != 0)
+								return -1;
+							if((nRet = GfaBlmBootloaderDump(hBlm, nNodeAddr, (uint32_t)aih.app.pszImgNameBuild, GFA_APP_MAX_IMG_NAME_BUILD_LENGTH / sizeof(uint32_t), pii->szImgNameBuild, GFA_APP_MAX_IMG_NAME_BUILD_LENGTH)) != 0)
+								return -1;
+							pii->szImgMaterialNum[GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH - 1] = '\0';
+							pii->szImgNameBuild[GFA_APP_MAX_IMG_NAME_BUILD_LENGTH - 1] = '\0';
+							return 0;
+						}
+						else
+						{
+							uint32_t nDwOffsImgMaterialNum = _dword_offset(bl.szImgMaterialNum);
+							uint32_t nDwOffsImgNameBuild = _dword_offset(bl.szImgNameBuild);
+							uint32_t nDwOffsImgCRC32 = _dword_offset(nImgCRC32);
+							size_t nSizeDst = nDwOffsImgNameBuild * sizeof(uint32_t) + GFA_APP_MAX_IMG_NAME_BUILD_LENGTH;
+							uint32_t nCntDwToDmp, nCntDwToCpy;
+
+							if(nCntDwAvail >= (nDwOffsImgNameBuild + GFA_APP_MAX_IMG_NAME_BUILD_LENGTH / sizeof(uint32_t)))
+							{
+								// have nImgLength, nImgCRC32, szImgMaterialNum, szImgNameBuild
+								// need nothing
+								nCntDwToCpy = nDwOffsImgNameBuild + GFA_APP_MAX_IMG_NAME_BUILD_LENGTH / sizeof(uint32_t);
+								nCntDwToDmp = 0;
+								memcpy(pDwDst, &aDump[j + 1], nCntDwToCpy * sizeof(uint32_t));
+							}
+							else if(nCntDwAvail > nDwOffsImgMaterialNum)
+							{
+								// have nImgLength, nImgCRC32, szImgMaterialNum
+								// need szImgNameBuild
+								nCntDwToCpy = nCntDwAvail;
+								nCntDwToDmp = nSizeDst / sizeof(uint32_t) - nCntDwToCpy; // (1...3) + 6
+								nDmpStart += nCntDwToCpy * sizeof(uint32_t);
+								memcpy(pDwDst, &aDump[j + 1], nCntDwToCpy * sizeof(uint32_t));
+								pDwDst += nCntDwToCpy;
+								nSizeDst -= nCntDwToCpy * sizeof(uint32_t);
+							}
+							else if(nCntDwAvail > nDwOffsImgCRC32)
+							{
+								// have nImgLength, nImgCRC32
+								// need szImgMaterialNum, szImgNameBuild
+								nCntDwToCpy = 2;
+								nCntDwToDmp = (GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH + GFA_APP_MAX_IMG_NAME_BUILD_LENGTH) / sizeof(uint32_t); // 4 + 6
+								nDmpStart += nDwOffsImgMaterialNum * sizeof(uint32_t);
+								memcpy(pDwDst, &aDump[j + 1], nCntDwToCpy * sizeof(uint32_t));
+								pDwDst += nDwOffsImgMaterialNum;
+								nSizeDst -= nDwOffsImgMaterialNum * sizeof(uint32_t);
+							}
+							else if(nCntDwAvail == nDwOffsImgCRC32)
+							{
+								// have nImgLength
+								// need nImgCRC32, szImgMaterialNum, szImgNameBuild
+								nCntDwToCpy = nDwOffsImgCRC32;
+								nCntDwToDmp = nSizeDst / sizeof(uint32_t) - nCntDwToCpy; // 1 + 4 + 4 + 6
+								nDmpStart += sizeof(uint32_t);
+								memcpy(pDwDst, &aDump[j + 1], nCntDwToCpy * sizeof(uint32_t));
+								pDwDst += nCntDwToCpy;
+								nSizeDst -= nCntDwToCpy * sizeof(uint32_t);
+							}
+							else
+							{
+								// have nothing
+								// need nImgLength, nImgCRC32, pszImgMaterialNum, pszImgNameBuild
+								nCntDwToCpy = 0;
+								nCntDwToDmp = nSizeDst / sizeof(uint32_t); // 2 + 4 + 4 + 6
+							}
+
+							if(nCntDwToDmp)
+							{
+								if((nRet = GfaBlmBootloaderDump(hBlm, nNodeAddr, nDmpStart, nCntDwToDmp, pDwDst, nSizeDst)) != 0)
+									return -1;
+							}
+
+							pii->nImgLength	= aih.nImgLength;
+							pii->nImgCRC32	= aih.nImgCRC32;
+							memcpy(pii->szImgMaterialNum, aih.bl.szImgMaterialNum, GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH);
+							memcpy(pii->szImgNameBuild,   aih.bl.szImgNameBuild,   GFA_APP_MAX_IMG_NAME_BUILD_LENGTH);
+							pii->szImgMaterialNum[GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH - 1] = '\0';
+							pii->szImgNameBuild[GFA_APP_MAX_IMG_NAME_BUILD_LENGTH - 1] = '\0';
+							return 0;
+						}
+					}
+				}
+			}
+			else
+			{
+				break;
+			}
+		}
+
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmGetInfoBD(HGFABLM hBlm, uint8_t nNodeAddr, LPGFA_BL_APP_IMG_INFO paii)
+{
+	if(hBlm && paii && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		int nRet1, nRet2;
+
+		if((nRet1 = GfaBlmGetImgInfo(hBlm, nNodeAddr, GFA_APP_BOOTLOADER_START_ADDRESS, false, &paii->bl)) < 0)
+		{
+			memset(&paii->bl, 0, sizeof(paii->bl));
+			paii->bl.nImgLength = paii->bl.nImgCRC32 = 0xFFFFFFFF;
+		}
+
+		if((nRet2 = GfaBlmGetImgInfo(hBlm, nNodeAddr, GFA_APP_APPLICATION_START_ADDRESS, true, &paii->app)) < 0)
+		{
+			memset(&paii->app, 0, sizeof(paii->app));
+			paii->app.nImgLength = paii->app.nImgCRC32 = 0xFFFFFFFF;
+		}
+
+		return nRet1 + nRet2;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmGetInfoBI(HGFABLM hBlm, uint8_t nNodeAddr, LPGFA_BL_APP_IMG_INFO paii)
+{
+	if(hBlm && paii && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		uint8_t nIndex;
+		ssize_t nRet, nLen;
+		char txb[32], rxb[256];
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+
+	    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, "BI", 2, txb, sizeof(txb));
+
+		if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+			return nRet;
+
+		if((nLen = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) < 0)
+			return nLen;
+
+		nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nLen, true, &nIndex);
+
+		if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+		{
+			if((nRet = GfaMininetMasterGetDataFromSlaveFrame(rxb, nLen, paii, sizeof(GFA_BL_APP_IMG_INFO))) == sizeof(GFA_BL_APP_IMG_INFO))
+			{
+				paii->bl.nImgLength		= bswap_32(paii->bl.nImgLength);
+				paii->bl.nImgCRC32		= bswap_32(paii->bl.nImgCRC32);
+				paii->app.nImgLength	= bswap_32(paii->app.nImgLength);
+				paii->app.nImgCRC32		= bswap_32(paii->app.nImgCRC32);
+
+				return 0;
+			}
+
+			errno = EPROTO;
+			return -1;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+		{
+			errno = EPROTO;
+			return -1;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+		{
+			errno = -(int)nIndex;
+			return -1;
+		}
+
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmReadMaterialAndSerialID(HGFABLM hBlm, uint8_t nNodeAddr, char *pszMaterial, size_t nCbMaterial, char *pszSerial, size_t nCbSerial)
+{
+	if(hBlm && pszMaterial && (nCbMaterial >= 16) && pszSerial && (nCbSerial >= 16) && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		uint8_t nIndex;
+		ssize_t nRet, nLen;
+		char txb[32], rxb[64], data[32];
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+
+	    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, "BR", 2, txb, sizeof(txb));
+
+		if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+			return nRet;
+
+		if((nLen = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) < 0)
+			return nLen;
+
+		nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nLen, true, &nIndex);
+
+		if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+		{
+			if((nRet = GfaMininetMasterGetDataFromSlaveFrame(rxb, nLen, data, sizeof(data))) != 32)
+				return -1;
+			memcpy(pszMaterial, data, 16);
+			pszMaterial[15] = '\0';
+			memcpy(pszSerial, &data[16], 16);
+			pszSerial[15] = '\0';
+			return 0;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+		{
+			if((nRet = GfaBlmBUCmdPollData(hBlm, nNodeAddr, data, sizeof(data), 200)) != (ssize_t)sizeof(data))
+				return -1;
+			memcpy(pszMaterial, data, 16);
+			pszMaterial[15] = '\0';
+			memcpy(pszSerial, &data[16], 16);
+			pszSerial[15] = '\0';
+			return 0;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+		{
+			errno = -(int)nIndex;
+			return -1;
+		}
+
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
 
 /////////////////////////////////////////////////////////////////////////////
 
-uint8_t GfaBLM_BU_DataCheckSum(const void *pData, size_t nCbData)
+int GfaBlmWriteMaterialAndSerialID(HGFABLM hBlm, uint8_t nNodeAddr, const char *pszMaterial, const char *pszSerial)
+{
+	if(hBlm && pszMaterial && pszSerial && !NODE_IS_MULTICAST(nNodeAddr))
+	{
+		uint8_t nIndex;
+		size_t s;
+		ssize_t nRet, nLen;
+		size_t nLenMaterial, nLenSerial;
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+
+		struct _TS
+		{
+			char szMaterial[16];
+			char szSerial[16];
+		}ts;
+		char txb[64], rxb[32], cmd[64];
+
+		nLenMaterial	= strlen(pszMaterial);
+		nLenSerial		= strlen(pszSerial);
+
+		if((nLenMaterial > 15) || (nLenSerial > 15))
+			return -1;
+
+		memcpy(ts.szMaterial, pszMaterial, nLenMaterial);
+		if(nLenMaterial < 15)
+			memset(&ts.szMaterial[nLenMaterial], ' ', 15 - nLenMaterial);
+		ts.szMaterial[15] = '\0';
+
+		memcpy(ts.szSerial, pszSerial, nLenSerial);
+		if(nLenSerial < 15)
+			memset(&ts.szSerial[nLenSerial], ' ', 15 - nLenSerial);
+		ts.szSerial[15] = '\0';
+
+		s = GfaBlmBuildCmdDataPacket("BW", 0, &ts, sizeof(ts), cmd, sizeof(cmd), false);
+	    nLen = GfaMininetMasterBuildFrame(pBlm->hMst, nNodeAddr, 0, cmd, s, txb, sizeof(txb));
+
+		if((nRet = GfaMininetMasterTransmitFrame(pBlm->hMst, txb, nLen)) != nLen)
+			return nRet;
+
+		if((nRet = GfaMininetMasterReceiveFrame(pBlm->hMst, rxb, sizeof(rxb), true)) < 0)
+			return nRet;
+
+		nRet = GfaMininetMasterEvaluateSlaveResponse(pBlm->hMst, nNodeAddr, rxb, nRet, true, &nIndex);
+
+		if(nRet == MINET_SLAVE_RESPONSE_SUCCESS)
+		{
+			return 0;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+		{
+			return 0;
+		}
+		else if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+		{
+			errno = -(int)nIndex;
+			return -1;
+		}
+
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+HGFAMINEMST GfaBlmGetMininetMasterHandle(HGFABLM hBlm)
+{
+	if(hBlm)
+	{
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		return pBlm->hMst;
+	}
+
+	errno = EINVAL;
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmSetVerbosity(HGFABLM hBlm, int nVerbosity)
+{
+	if(hBlm)
+	{
+		LPGFA_BLM pBlm = (LPGFA_BLM)hBlm;
+		if(nVerbosity < 0)
+			nVerbosity = 0;
+		else if(nVerbosity > 4)
+			nVerbosity = 4;
+		pBlm->nVerbosity = nVerbosity;
+		return GfaMininetMasterSetVerbosity(pBlm->hMst, pBlm->nVerbosity);
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+uint8_t GfaBlmDataCheckSum(const void *pData, size_t nCbData)
 {
 	uint8_t chk = 0;
 	const uint8_t *pbData = (const uint8_t*)pData;
@@ -23,11 +1445,12 @@ uint8_t GfaBLM_BU_DataCheckSum(const void *pData, size_t nCbData)
 
 /////////////////////////////////////////////////////////////////////////////
 
-size_t GfaBLM_BuildCmdDataPacket(const char *pszCmd, const void *pCmdData, size_t nCbCmdData, void *pPacket, size_t nCbPacket, bool bAddLenAndCheck)
+size_t GfaBlmBuildCmdDataPacket(const char *pszCmd, uint8_t tiCmd, const void *pCmdData, size_t nCbCmdData, void *pPacket, size_t nCbPacket, bool bAddLenAndCheck)
 {
 	size_t nLen = strlen(pszCmd);
 	uint8_t *pbPacket = (uint8_t*)pPacket;
-	
+	tiCmd = tiCmd; // not yet used
+
 	if(nCbPacket < (nLen + nCbCmdData + ((pCmdData && nCbCmdData && bAddLenAndCheck) ? 2 : 0)))
 		return 0;
 
@@ -39,7 +1462,7 @@ size_t GfaBLM_BuildCmdDataPacket(const char *pszCmd, const void *pCmdData, size_
 		if(bAddLenAndCheck)
 		{
 			*pbPacket++ = nCbCmdData + 2;
-			*pbPacket++ = GfaBLM_BU_DataCheckSum(pCmdData, nCbCmdData);
+			*pbPacket++ = GfaBlmDataCheckSum(pCmdData, nCbCmdData);
 			nLen += 2;
 		}
 		memcpy(pbPacket, pCmdData, nCbCmdData);
@@ -48,3 +1471,22 @@ size_t GfaBLM_BuildCmdDataPacket(const char *pszCmd, const void *pCmdData, size_
 
 	return nLen;
 }
+
+const char* GfaBlmStrError(int nErrorCode)
+{
+	switch(nErrorCode)
+	{
+	case -COMMAND_RET_UNKNOWN_CMD:
+		return "Unknown Bootloader command";
+	case -COMMAND_RET_INVALID_CMD:
+		return "Invalid Bootloader command";
+	case -COMMAND_RET_INVALID_ADR:
+		return "Invalid Flash address";
+	case -COMMAND_RET_FLASH_FAIL:
+		return "Bootloader failed to erase flash";
+	case -COMMAND_RET_CRC_FAIL:
+		return "Invalid Image CRC32";
+	default:
+		return GfaMininetMasterStrError(nErrorCode);
+	}
+}

+ 99 - 2
libmininet/gfabootlmast.h

@@ -18,8 +18,105 @@ extern "C" {
 /////////////////////////////////////////////////////////////////////////////
 // gfabootlmast.h - Declarations:
 
-uint8_t	GfaBLM_BU_DataCheckSum(const void *pData, size_t nCbData);
-size_t	GfaBLM_BuildCmdDataPacket(const char *pszCmd, const void *pCmdData, size_t nCbCmdData, void *pPacket, size_t nCbPacket, bool bAddLenAndCheck);
+typedef void													*HGFABLM;
+
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef _DEBUG
+typedef void (*PFN_BU_CMD_DOWNLOAD_STATUS)(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, int nCtx, int nErrorCode);
+typedef void (*PFN_BU_CMD_SEND_DATA_STATUS)(const char *pszFile, int nLine, uint8_t nNodeAddr, uint32_t nCbBlock, uint32_t nCbData, int nCtx, int nErrorCode);
+#else	//	_DEBUG
+typedef void (*PFN_BU_CMD_DOWNLOAD_STATUS)(uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, int nCtx, int nErrorCode);
+typedef void (*PFN_BU_CMD_SEND_DATA_STATUS)(uint8_t nNodeAddr, uint32_t nCbBlock, uint32_t nCbData, int nCtx, int nErrorCode);
+#endif	//	_DEBUG
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_BLM_CFG_PARAMS
+{
+	GFA_MININET_MST_CFG_PARAMS mmcp;
+	PFN_BU_CMD_DOWNLOAD_STATUS pfnBuCmdDownloadStatus;
+	PFN_BU_CMD_SEND_DATA_STATUS pfnBuCmdSendDataStatus;
+}GFA_BLM_CFG_PARAMS, *LPGFA_BLM_CFG_PARAMS;
+typedef const GFA_BLM_CFG_PARAMS *LPCGFA_BLM_CFG_PARAMS;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef enum _GFA_BLM_EXEC_CONTEXT
+{
+	GfaBlmCtx_Err = -1,
+	GfaBlmCtx_Boot,
+	GfaBlmCtx_App
+}GFA_BLM_EXEC_CONTEXT, *LPGFA_BLM_EXEC_CONTEXT;
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH						16		// including the zero terminator
+#define GFA_APP_MAX_IMG_NAME_BUILD_LENGTH						24		// including the zero terminator
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_IMG_INFO
+{
+	uint32_t nImgLength;
+	uint32_t nImgCRC32;
+	char szImgMaterialNum[GFA_APP_MAX_IMG_MATERIAL_NUM_LENGTH];
+	char szImgNameBuild[GFA_APP_MAX_IMG_NAME_BUILD_LENGTH];
+}GFA_IMG_INFO, *LPGFA_IMG_INFO;
+typedef const GFA_IMG_INFO *LPCGFA_IMG_INFO;
+
+typedef struct _GFA_BL_APP_IMG_INFO
+{
+	GFA_IMG_INFO bl;
+	GFA_IMG_INFO app;
+}GFA_BL_APP_IMG_INFO, *LPGFA_BL_APP_IMG_INFO;
+typedef const GFA_BL_APP_IMG_INFO *LPCGFA_BL_APP_IMG_INFO;
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+HGFABLM	GfaBlmOpen(LPCGFA_BLM_CFG_PARAMS pblmcfg);
+void	GfaBlmClose(HGFABLM hBlm);
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmResetSlaveIndex(HGFABLM hBlm, uint8_t nNodeAddr);
+GFA_BLM_EXEC_CONTEXT GfaBlmGetExecutionContext(HGFABLM hBlm, uint8_t nNodeAddr);
+
+/////////////////////////////////////////////////////////////////////////////
+// GfA commands
+
+int GfaBlmBootloaderExecute(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t *pnImgCRC32, uint32_t nTimeoutMS);
+int GfaBlmBootloaderSetBaudrate(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t nBaudrate);
+int GfaBlmBootloaderDump(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t nAddress, uint32_t nCntDwords, void *pBuffer, size_t nCbBuffer);
+int GfaBlmGetImgInfo(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t nDumpAddr, bool bCtxIsApp, LPGFA_IMG_INFO pii);
+int GfaBlmGetInfoBD(HGFABLM hBlm, uint8_t nNodeAddr, LPGFA_BL_APP_IMG_INFO paii);
+int GfaBlmGetInfoBI(HGFABLM hBlm, uint8_t nNodeAddr, LPGFA_BL_APP_IMG_INFO paii);
+int GfaBlmReadMaterialAndSerialID(HGFABLM hBlm, uint8_t nNodeAddr, char *pszMaterial, size_t nCbMaterial, char *pszSerial, size_t nCbSerial);
+int GfaBlmWriteMaterialAndSerialID(HGFABLM hBlm, uint8_t nNodeAddr, const char *pszMaterial, const char *pszSerial);
+
+/////////////////////////////////////////////////////////////////////////////
+// TI commands
+
+int GfaBlmBUCmdReset(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t nTimeoutMS);
+int GfaBlmBUCmdPing(HGFABLM hBlm, uint8_t nNodeAddr);
+int GfaBlmBUCmdGetStatus(HGFABLM hBlm, uint8_t nNodeAddr, uint8_t *pbStatus);
+ssize_t GfaBlmBUCmdPollData(HGFABLM hBlm, uint8_t nNodeAddr, void *pData, size_t nCbData, uint32_t nTimeoutMS);
+
+int GfaBlmBUCmdDownload(HGFABLM hBlm, uint8_t nNodeAddr, uint32_t nFlashStartAddr, uint32_t nCbData, uint32_t nTimeoutMS);
+int GfaBlmBUCmdSendDataBlock(HGFABLM hBlm, uint8_t nNodeAddr, const void *pDataBlock, size_t nCbDataBlock);
+int GfaBlmBUCmdSendData(HGFABLM hBlm, uint8_t nNodeAddr, const void *pData, size_t nCbData, size_t nCbBlock);
+int GfaBlmBUCmdSendDataFile(HGFABLM hBlm, uint8_t nNodeAddr, const char *pszFilename, uint32_t nFlashStartAddr, size_t nCbBlock, uint32_t nTimeoutMS);
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaBlmSetVerbosity(HGFABLM hBlm, int nVerbosity);
+HGFAMINEMST GfaBlmGetMininetMasterHandle(HGFABLM hBlm);
+uint8_t	GfaBlmDataCheckSum(const void *pData, size_t nCbData);
+size_t	GfaBlmBuildCmdDataPacket(const char *pszCmd, uint8_t tiCmd, const void *pCmdData, size_t nCbCmdData, void *pPacket, size_t nCbPacket, bool bAddLenAndCheck);
+
+const char* GfaBlmStrError(int nErrorCode);
 
 /////////////////////////////////////////////////////////////////////////////
 #ifdef __cplusplus

+ 5 - 1
libmininet/gfagenericdev.h

@@ -16,12 +16,14 @@ extern "C" {
 /////////////////////////////////////////////////////////////////////////////
 // gfagenericdev.h - Declarations:
 
-typedef void							*HGFADEVICE;
+typedef void		*HGFADEVICE;
 
 typedef HGFADEVICE	(*PFN_GFA_GENERIC_DEV_OPEN)				(const char *pszDeviceName, const void *pcp, size_t nSizeCfgParams);
 typedef void		(*PFN_GFA_GENERIC_DEV_CLOSE)			(HGFADEVICE hDev);
 typedef ssize_t		(*PFN_GFA_GENERIC_DEV_GET_CONFIG)		(HGFADEVICE hDev, void *pcp, size_t nSizeCfgParams);
 typedef int			(*PFN_GFA_GENERIC_DEV_SET_CONFIG)		(HGFADEVICE hDev, const void *pcp, size_t nSizeCfgParams);
+typedef bool		(*PFN_GFA_GENERIC_DEV_IS_VALID_BAUD)	(uint32_t nBaudrate);
+typedef int			(*PFN_GFA_GENERIC_DEV_SET_BAUDRATE)		(HGFADEVICE hDev, uint32_t nBaudrate);
 typedef bool		(*PFN_GFA_GENERIC_DEV_GET_TIMEOUTS)		(HGFADEVICE hDev, struct timeval *ptvRX, struct timeval *ptvTX);
 typedef bool		(*PFN_GFA_GENERIC_DEV_SET_TIMEOUTS)		(HGFADEVICE hDev, const struct timeval *ptvRX, const struct timeval *ptvTX);
 typedef ssize_t		(*PFN_GFA_GENERIC_DEV_PURGE_RX_BUFFER)	(HGFADEVICE hDev);
@@ -41,6 +43,8 @@ typedef struct _GFA_GENERIC_DEVICE_INTERFACE
 	PFN_GFA_GENERIC_DEV_CLOSE			pfnClose;
 	PFN_GFA_GENERIC_DEV_GET_CONFIG		pfnGetConfig;
 	PFN_GFA_GENERIC_DEV_SET_CONFIG		pfnSetConfig;
+	PFN_GFA_GENERIC_DEV_IS_VALID_BAUD	pfnIsValidBaudrate;
+	PFN_GFA_GENERIC_DEV_SET_BAUDRATE	pfnSetBaudrate;
 	PFN_GFA_GENERIC_DEV_GET_TIMEOUTS	pfnGetTimeouts;
 	PFN_GFA_GENERIC_DEV_SET_TIMEOUTS	pfnSetTimeouts;
 	PFN_GFA_GENERIC_DEV_PURGE_RX_BUFFER	pfnPurgeRXBuffer;

+ 36 - 0
libmininet/gfamininetdev.c

@@ -89,6 +89,42 @@ int GfaMininetDeviceSetConfigParams(HMINETDEV hDev, const void *pDevCfgParams, s
 
 /////////////////////////////////////////////////////////////////////////////
 
+bool GfaMininetDeviceIsValidBaudrate(HMINETDEV hDev, uint32_t nBaudrate)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnIsValidBaudrate)
+			return (*pDev->itf.pfnIsValidBaudrate)(nBaudrate);
+
+		errno = EOPNOTSUPP;
+		return false;
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaMininetDeviceSetBaudrate(HMINETDEV hDev, uint32_t nBaudrate)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnSetBaudrate)
+			return (*pDev->itf.pfnSetBaudrate)(pDev->hDev, nBaudrate);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 bool GfaMininetDeviceGetTimeouts(HMINETDEV hDev, struct timeval *ptvRX, struct timeval *ptvTX)
 {
 	if(hDev && (ptvRX || ptvTX))

+ 2 - 0
libmininet/gfamininetdev.h

@@ -33,6 +33,8 @@ void	GfaMininetDeviceClose(HMINETDEV hDev);
 
 ssize_t	GfaMininetDeviceGetConfigParams(HMINETDEV hDev, void *pDevParams, size_t nSizeDevParams);
 int		GfaMininetDeviceSetConfigParams(HMINETDEV hDev, const void *pDevParams, size_t nSizeDevParams);
+bool	GfaMininetDeviceIsValidBaudrate(HMINETDEV hDev, uint32_t nBaudrate);
+int		GfaMininetDeviceSetBaudrate(HMINETDEV hDev, uint32_t nBaudrate);
 
 bool	GfaMininetDeviceGetTimeouts(HMINETDEV hDev, struct timeval *ptvRX, struct timeval *ptvTX);
 bool	GfaMininetDeviceSetTimeouts(HMINETDEV hDev, const struct timeval *ptvRX, const struct timeval *ptvTX);

+ 314 - 65
libmininet/gfamininetmst.c

@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <malloc.h>
+#include <time.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <termios.h>
@@ -9,6 +10,7 @@
 #include <ctype.h>
 #include <sys/file.h>
 #include "gfamininetmst.h"
+#include "dbghlp.h"
 
 /////////////////////////////////////////////////////////////////////////////
 // https://www.racom.eu/eng/support/prot/mininet/index.html
@@ -22,17 +24,9 @@
 #define MIN_INDEX					0x3F
 #define MAX_INDEX					0x7F
 #define RESET_INDEX					MIN_INDEX
-#define STATUS_INDEX_RESET_DONE		0xC0
-#define STATUS_INDEX_ERROR			0xC1
-#define STATUS_INDEX_CMD_ERROR		0xC2
-#define STATUS_INDEX_INVALID_PARAM	0xC3
-#define STATUS_INDEX_UNKNOWN_CMD	0xC4
-#define STATUS_INDEX_CMD_ALREADY_EX	0xC8
 
 #define MAX_DATA_PAYLOAD_LENGTH		250
-
-#define NODE_IS_BROADCAST(n)		((n) == 0)
-#define NODE_IS_GROUPCAST(n)		((((n) & 0xF0) != 0) && (((n) & 0x0F) == 0))
+#define MAX_SAVE_TIMOUT_DEPTH		8
 
 /////////////////////////////////////////////////////////////////////////////
 
@@ -52,8 +46,12 @@ typedef enum _GfaMininetRxStates
 typedef struct _GFA_MININET_MASTER
 {
 	HMINETDEV hDev;
-	struct timeval tvRXSave;
-	struct timeval tvTXSave;
+	struct timeval tvRXSave[MAX_SAVE_TIMOUT_DEPTH];
+	struct timeval tvTXSave[MAX_SAVE_TIMOUT_DEPTH];
+	struct timespec tsStart;
+	int nVerbosity;
+	int nSaveToIndex;
+	FILE *pDumpCtx;
 	uint8_t nIndexTable[256];
 }GFA_MININET_MASTER, *LPGFA_MININET_MASTER;
 typedef const GFA_MININET_MASTER *LPCGFA_MININET_MASTER;
@@ -93,7 +91,7 @@ static uint8_t _GetCurIndex(HGFAMINEMST hMst, uint8_t nNode)
 
 /////////////////////////////////////////////////////////////////////////////
 
-HGFAMINEMST GfaMininetMasterOpen(LPGFA_MININET_MST_CFG_PARAMS pmmcp)
+HGFAMINEMST GfaMininetMasterOpen(LPCGFA_MININET_MST_CFG_PARAMS pmmcp)
 {
 	if(pmmcp)
 	{
@@ -104,7 +102,9 @@ HGFAMINEMST GfaMininetMasterOpen(LPGFA_MININET_MST_CFG_PARAMS pmmcp)
 			LPGFA_MININET_MASTER pMst = malloc(sizeof(GFA_MININET_MASTER));
 			memset(pMst, 0, sizeof(GFA_MININET_MASTER));
 			memset(pMst->nIndexTable, START_INDEX, sizeof(pMst->nIndexTable));
-			pMst->hDev = hDev;
+			pMst->hDev			= hDev;
+			pMst->pDumpCtx		= stdout;
+			clock_gettime(CLOCK_MONOTONIC, &pMst->tsStart);
 			return (HGFAMINEMST)pMst;
 		}
 
@@ -162,7 +162,16 @@ bool GfaMininetMasterSaveTimeouts(HGFAMINEMST hMst)
 	if(hMst)
 	{
 		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
-		return GfaMininetMasterGetTimeouts(hMst, &pMst->tvRXSave, &pMst->tvTXSave);
+		if(pMst->nSaveToIndex < MAX_SAVE_TIMOUT_DEPTH)
+		{
+			int nIndex = pMst->nSaveToIndex++;
+			return GfaMininetMasterGetTimeouts(hMst, &pMst->tvRXSave[nIndex], &pMst->tvTXSave[nIndex]);
+		}
+		else
+		{
+			errno = EPERM;
+			return false;
+		}
 	}
 
 	errno = EINVAL;
@@ -176,7 +185,16 @@ bool GfaMininetMasterRestoreTimeouts(HGFAMINEMST hMst)
 	if(hMst)
 	{
 		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
-		return GfaMininetMasterSetTimeouts(hMst, &pMst->tvRXSave, &pMst->tvTXSave);
+		if(pMst->nSaveToIndex > 0)
+		{
+			int nIndex = --pMst->nSaveToIndex;
+			return GfaMininetMasterSetTimeouts(hMst, &pMst->tvRXSave[nIndex], &pMst->tvTXSave[nIndex]);
+		}
+		else
+		{
+			errno = EPERM;
+			return false;
+		}
 	}
 
 	errno = EINVAL;
@@ -213,7 +231,49 @@ int GfaMininetMasterSetConfigParams(HGFAMINEMST hMst, const void *pDevParams, si
 
 /////////////////////////////////////////////////////////////////////////////
 
-uint8_t GfaMininetMasterCalcChk(const void *pData, size_t nCbData)
+bool GfaMininetMasterIsValidBaudrate(HGFAMINEMST hMst, uint32_t nBaudrate)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return GfaMininetDeviceIsValidBaudrate(pMst->hDev, nBaudrate);
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaMininetMasterSetBaudrate(HGFAMINEMST hMst, uint32_t nBaudrate)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return GfaMininetDeviceSetBaudrate(pMst->hDev, nBaudrate);
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+HMINETDEV GfaMininetMasterGetDeviceHandle(HGFAMINEMST hMst)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return pMst->hDev;
+	}
+
+	errno = EINVAL;
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+uint8_t GfaMininetMasterCalcChk(const void *pData, size_t nCbData, bool bProcessSTX)
 {
 	size_t i = 0;
 	uint16_t chk = 0;
@@ -227,17 +287,15 @@ uint8_t GfaMininetMasterCalcChk(const void *pData, size_t nCbData)
 		if(cc || (lc != STX))
 		{
 			chk <<= 1;
-
 			if(chk & 0x0100)
 				chk = (chk + 1) & 0x00FF;
 
 			chk += cc;
-
 			if(chk > 0x00FF)
 				chk = (chk + 1) & 0x00FF;
 		}
 
-		if(i > 4)
+		if(bProcessSTX && (i > 3))
 			lc = cc;
 	}
 
@@ -285,7 +343,7 @@ size_t GfaMininetMasterBuildFrame(HGFAMINEMST hMst, uint8_t nNode, uint8_t nInde
 			}
 		}
 
-		pf->data.by[i++] = GfaMininetMasterCalcChk(pFrameBuffer, nLen);
+		pf->data.by[i++] = GfaMininetMasterCalcChk(pFrameBuffer, nLen, true);
 		++nLen;
 		return nLen;
 	}
@@ -296,39 +354,51 @@ size_t GfaMininetMasterBuildFrame(HGFAMINEMST hMst, uint8_t nNode, uint8_t nInde
 
 /////////////////////////////////////////////////////////////////////////////
 
-ssize_t GfaMininetMasterResetSlaveIndex(HGFAMINEMST hMst, uint8_t nNode)
+int GfaMininetMasterResetSlaveIndex(HGFAMINEMST hMst, uint8_t nNode)
 {
 	if(hMst)
 	{
-		ssize_t nRet;
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		ssize_t nLen, nRet;
 		uint8_t nIndex;
 		uint8_t txb[16];
 		uint8_t rxb[16];
 
-		if(	(nRet = GfaMininetMasterBuildFrame(hMst, nNode, RESET_INDEX, "\x1b\x52", 2, txb, sizeof(txb))) > 0 &&
-			(nRet = GfaMininetMasterTransmitFrame(hMst, txb, nRet)))
+		nLen = GfaMininetMasterBuildFrame(hMst, nNode, RESET_INDEX, "\x1b\x52", 2, txb, sizeof(txb));
+
+		if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) != nLen)
+		{
+			GfaMininetDevicePurgeRXBuffer(pMst->hDev);
+			return -1;
+		}
+
+		if(!NODE_IS_BROADCAST(nNode) && !NODE_IS_GROUPCAST(nNode))
 		{
-			if(!NODE_IS_BROADCAST(nNode) && !NODE_IS_GROUPCAST(nNode))
+			// we expect a response
+			if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), false)) <= 0)
+				return -1;
+
+			if((nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, nNode, rxb, nRet, false, &nIndex)) == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
 			{
-				// we expect a response
-				if(	(nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), false)) > 0 &&
-					(nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, nNode, rxb, nRet, false, &nIndex)) == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
+				if(nIndex == MINET_SLAVE_STATUS_INDEX_RESET_DONE)
+					return GfaMininetMasterResetLocalIndex(hMst, nNode);
+				else
 				{
-					if(nIndex == STATUS_INDEX_RESET_DONE)
-						return GfaMininetMasterResetLocalIndex(hMst, nNode);
-					else
-					{
-						errno = nIndex;
-						return -1;
-					}
+					errno = nIndex;
+					nRet = -1;
 				}
 			}
 			else
 			{
-				// we don't expect a response. so let's just hope that all slaves have received the request and have performed an index reset!
-				return GfaMininetMasterResetLocalIndex(hMst, nNode);
+				errno = EPROTO;
+				nRet = -1;
 			}
 		}
+		else
+		{
+			// we don't expect a response. so let's just hope that all slaves have received the request and have performed an index reset!
+			return GfaMininetMasterResetLocalIndex(hMst, nNode);
+		}
 
 		return nRet;
 	}
@@ -339,7 +409,7 @@ ssize_t GfaMininetMasterResetSlaveIndex(HGFAMINEMST hMst, uint8_t nNode)
 
 /////////////////////////////////////////////////////////////////////////////
 
-ssize_t GfaMininetMasterResetLocalIndex(HGFAMINEMST hMst, uint8_t nNode)
+int GfaMininetMasterResetLocalIndex(HGFAMINEMST hMst, uint8_t nNode)
 {
 	if(hMst)
 	{
@@ -361,6 +431,20 @@ ssize_t GfaMininetMasterResetLocalIndex(HGFAMINEMST hMst, uint8_t nNode)
 
 /////////////////////////////////////////////////////////////////////////////
 
+int	GfaMininetMasterPurgeDeviceRXBuffer(HGFAMINEMST hMst)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return GfaMininetDevicePurgeRXBuffer(pMst->hDev);
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 int GfaMininetMasterEvaluateSlaveResponse(HGFAMINEMST hMst, uint8_t nNode, const void *pFrame, size_t nCbFrame, bool bAckPossible, uint8_t *pbIndex)
 {
 	if(hMst && pFrame && nCbFrame > 0)
@@ -437,12 +521,12 @@ int GfaMininetMasterEvaluateSlaveResponse(HGFAMINEMST hMst, uint8_t nNode, const
 			{
 				switch(pf->index)
 				{
-				case STATUS_INDEX_RESET_DONE:
-				case STATUS_INDEX_ERROR:
-				case STATUS_INDEX_CMD_ERROR:
-				case STATUS_INDEX_INVALID_PARAM:
-				case STATUS_INDEX_UNKNOWN_CMD:
-				case STATUS_INDEX_CMD_ALREADY_EX:
+				case MINET_SLAVE_STATUS_INDEX_RESET_DONE:
+				case MINET_SLAVE_STATUS_INDEX_ERROR:
+				case MINET_SLAVE_STATUS_INDEX_CMD_ERROR:
+				case MINET_SLAVE_STATUS_INDEX_INVALID_PARAM:
+				case MINET_SLAVE_STATUS_INDEX_UNKNOWN_CMD:
+				case MINET_SLAVE_STATUS_INDEX_CMD_ALREADY_EX:
 					bIsStatusIndex = true;
 					break;
 				default:
@@ -463,7 +547,7 @@ int GfaMininetMasterEvaluateSlaveResponse(HGFAMINEMST hMst, uint8_t nNode, const
 			/////////////////////////////////////////////////////////////////
 			// Checksum
 
-			if(pf->data.by[pf->len - 5] != GfaMininetMasterCalcChk(pf, pf->len - 1))
+			if(pf->data.by[pf->len - 5] != GfaMininetMasterCalcChk(pf, pf->len - 1, false))
 			{
 				errno = MINET_SLAVE_RESPONSE_ERROR_INVALID_CHECKSUM;
 				return -1;
@@ -486,6 +570,7 @@ ssize_t GfaMininetMasterTransmitFrame(HGFAMINEMST hMst, const void *pData, size_
 	if(hMst && pData && nCbData)
 	{
 		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		GfaMininetMasterDumpFrame(hMst, pMst->pDumpCtx, (LPCGFA_MININET_FRAME)pData, true, NULL);
 		return GfaMininetDeviceTransmit(pMst->hDev, pData, nCbData);
 	}
 
@@ -531,6 +616,7 @@ ssize_t GfaMininetMasterReceiveFrame(HGFAMINEMST hMst, void *pBuffer, size_t nCb
 						*(uint8_t*)pBuffer = b;
                         nRet = 1;
                         bLoop = false;
+						GfaMininetMasterDumpFrame(hMst, pMst->pDumpCtx, (LPCGFA_MININET_FRAME)pBuffer, false, NULL);
                         break;
                     }
 					continue;
@@ -670,7 +756,7 @@ ssize_t GfaMininetMasterReceiveFrame(HGFAMINEMST hMst, void *pBuffer, size_t nCb
 					nState = GfaRxMNS_Len;
 					continue;
 				}
-				c = GfaMininetMasterCalcChk(pFrameRx, pFrameRx->len - 1);
+				c = GfaMininetMasterCalcChk(pFrameRx, pFrameRx->len - 1, false);
 				if(b == c)
 				{
 					if((size_t)pFrameRx->len <= nCbBuffer)
@@ -678,6 +764,7 @@ ssize_t GfaMininetMasterReceiveFrame(HGFAMINEMST hMst, void *pBuffer, size_t nCb
 						pFrameRx->data.by[nCbDataPayloadRcv] = b;
 						nRet = pFrameRx->len;
 						memcpy(pBuffer, pFrameRx, nRet);
+						GfaMininetMasterDumpFrame(hMst, pMst->pDumpCtx, (LPCGFA_MININET_FRAME)pFrameRx, false, NULL);
 					}
 					else
 					{
@@ -687,6 +774,8 @@ ssize_t GfaMininetMasterReceiveFrame(HGFAMINEMST hMst, void *pBuffer, size_t nCb
 				}
 				else
 				{
+					pFrameRx->data.by[nCbDataPayloadRcv] = b;
+					GfaMininetMasterDumpFrame(hMst, pMst->pDumpCtx, (LPCGFA_MININET_FRAME)pFrameRx, false, "CRC32!!!");
 					errno = EPROTO;
 					nRet = -1;
 				}
@@ -711,35 +800,195 @@ ssize_t GfaMininetMasterReceiveFrame(HGFAMINEMST hMst, void *pBuffer, size_t nCb
 
 /////////////////////////////////////////////////////////////////////////////
 
-void GfaMininetMasterDumpFrame(FILE *pf, LPCGFA_MININET_FRAME pFrame)
+ssize_t	GfaMininetMasterGetDataFromFrame(const void *pFrame, size_t nCbFrame, void *pData, size_t nCbData)
 {
-	if(pf)
+	if(pFrame && (nCbFrame >= 5) && pData && (nCbData > 0))
 	{
-		if(pFrame && pFrame->len >= 5)
-		{
-			int i, nCbData = pFrame->len - 5;
-
-			fprintf(pf, "\nSTX:    %02hhX (%hhu)\n", pFrame->stx, pFrame->stx);
-			fprintf(pf, "Length: %02hhX (%hhu)\n", pFrame->len, pFrame->len);
-			fprintf(pf, "Node:   %02hhX (%hhu)\n", pFrame->node, pFrame->node);
-			fprintf(pf, "Index:  %02hhX (%hhu)\n", pFrame->index, pFrame->index);
-			fprintf(pf, "Data:   ");
+		LPCGFA_MININET_FRAME pf = (LPCGFA_MININET_FRAME)pFrame;
 
-			for(i = 0; i < nCbData; i++)
+		if(pf->len == 5)
+			return 0; // no data
+		else if(pf->len > 5)
+		{
+			if(nCbFrame >= pf->len)
 			{
-				if(pFrame->data.by[i] >= 0x41 && pFrame->data.by[i] <= 0x5A)
-					fprintf(pf, "<%c>", (char)pFrame->data.by[i]);
+				size_t nDatalen = (size_t)pf->len - 5;
+
+				if(nDatalen <= nCbData)
+				{
+					memcpy(pData, pf->data.by, nDatalen);
+					return (ssize_t)nDatalen;
+				}
 				else
-					fprintf(pf, "[%02hhX]", (char)pFrame->data.by[i]);
+				{
+					errno = ENOMEM;
+					return -1;
+				}
 			}
+		}
+		else
+		{
+			errno = EPROTO;
+			return -1;
+		}
+	}
+
+	errno = EINVAL;
+	return -1;
+}
 
-			fprintf(pf, "\nCRC:    %02hhX (%hhu)\n\n", pFrame->data.by[i], pFrame->data.by[i]);
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t	GfaMininetMasterGetDataFromSlaveFrame(const void *pFrame, size_t nCbFrame, void *pData, size_t nCbData)
+{
+	uint8_t data[256];
+	ssize_t nRet = GfaMininetMasterGetDataFromFrame(pFrame, nCbFrame, data, sizeof(data));
+
+	if(nRet > 0)
+	{
+		if(data[0] == SLAVE_IND)
+		{
+			if(--nRet <= (ssize_t)nCbData)
+			{
+				if(nRet > 0)
+					memcpy(pData, &data[1], nRet);
+			}
+			else
+			{
+				errno = ENOMEM;
+				nRet = -1;
+			}
 		}
 		else
 		{
-			fprintf(pf, "\nInvalid Mininet-Frame!\n");
+			errno = EPROTO;
+			nRet = -1;
+		}
+	}
+
+	return nRet;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaMininetMasterDumpFrame(HGFAMINEMST hMst, FILE *pf, LPCGFA_MININET_FRAME pFrame, bool bTX, const char *pszAnnotation)
+{
+	if(hMst && pf)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+
+		if(pMst->nVerbosity >= 4)
+		{
+			struct timespec tsCur, tsIntv;
+			clock_gettime(CLOCK_MONOTONIC, &tsCur);
+			uint64_t nInterval = TimespecDiff(&tsCur, &pMst->tsStart);
+			Ns2Timespec(nInterval, &tsIntv);
+
+			if(pFrame)
+			{
+				if(pFrame->stx == ACK)
+				{
+					fprintf(pf, "\n///////////////////////////////////////\n");
+					fprintf(pf, "// %ld.%03ld\n", tsIntv.tv_sec, tsIntv.tv_nsec / 1000000);
+					fprintf(pf, "// %s:\n", bTX ? "TX" : "RX");
+					fprintf(pf, "ACK:    06 (6)\n");
+				}
+				else if(pFrame->len >= 5)
+				{
+					int i, nCbData = pFrame->len - 5;
+
+					fprintf(pf, "\n///////////////////////////////////////\n");
+					fprintf(pf, "// %ld.%03ld\n", tsIntv.tv_sec, tsIntv.tv_nsec / 1000000);
+					fprintf(pf, "// %s:\n", bTX ? "TX" : "RX");
+					fprintf(pf, "STX:    %02hhX (%hhu)\n", pFrame->stx, pFrame->stx);
+					fprintf(pf, "Length: %02hhX (%hhu)\n", pFrame->len, pFrame->len);
+					fprintf(pf, "Node:   %02hhX (%hhu)\n", pFrame->node, pFrame->node);
+					fprintf(pf, "Index:  %02hhX (%hhu)\n", pFrame->index, pFrame->index);
+					fprintf(pf, "Data:   ");
+
+					for(i = 0; i < nCbData; i++)
+					{
+						if(pFrame->data.by[i] >= 0x41 && pFrame->data.by[i] <= 0x5A)
+							fprintf(pf, "<%c>", (char)pFrame->data.by[i]);
+						else
+							fprintf(pf, "[%02hhX]", (char)pFrame->data.by[i]);
+					}
+
+					fprintf(pf, "\nCRC:    %02hhX (%hhu)\n", pFrame->data.by[i], pFrame->data.by[i]);
+					if(pszAnnotation)
+						fprintf(pf, "Annot.: %s\n", pszAnnotation);
+				}
+			}
+			else
+			{
+				fprintf(pf, "\n///////////////////////////////////////\n");
+				fprintf(pf, "// %ld:%03ld\n", tsIntv.tv_sec, tsIntv.tv_nsec / 1000000);
+				fprintf(pf, "// %s:\n", bTX ? "TX" : "RX");
+				fprintf(pf, "Invalid Mininet-Frame!\n");
+			}
+
+			fprintf(pf, "\n");
+			fflush(pf);
 		}
-		
-		fflush(pf);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaMininetMasterSetVerbosity(HGFAMINEMST hMst, int nVerbosity)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		if(nVerbosity < 0)
+			nVerbosity = 0;
+		else if(nVerbosity > 4)
+			nVerbosity = 4;
+		pMst->nVerbosity = nVerbosity;
+		return 0;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+const char* GfaMininetMasterStrError(int nErrorCode)
+{
+	switch(nErrorCode)
+	{
+	case MINET_SLAVE_RESPONSE_ERROR_STX_ERROR:
+		return "First byte in Mininet Frame is neither STX nor ACK";
+	case MINET_SLAVE_RESPONSE_ERROR_INVALID_ARGUMENT:
+		return "An invalid argument was passed to GfaMininetMasterEvaluateSlaveResponse";
+	case MINET_SLAVE_RESPONSE_ERROR_INVALID_LENGTH:
+		return "Invalid Mininet Frame length";
+	case MINET_SLAVE_RESPONSE_ERROR_INVALID_SLAVE_INDICATOR:
+		return "Invalid Mininet slave indicator";
+	case MINET_SLAVE_RESPONSE_ERROR_INCOMPLETE_DATA:
+		return "Not enough data for Mininet Frame";
+	case MINET_SLAVE_RESPONSE_ERROR_INVALID_NODE_ADDRESS:
+		return "Invalid Mininet Node address";
+	case MINET_SLAVE_RESPONSE_ERROR_INDEX_OUT_OF_RANGE:
+		return "Mininet Index out of range";
+	case MINET_SLAVE_RESPONSE_ERROR_INDEX_NO_MATCH:
+		return "Mininet Index no match";
+	case MINET_SLAVE_RESPONSE_ERROR_INVALID_CHECKSUM:
+		return "Mininet Checksum error";
+	case -MINET_SLAVE_STATUS_INDEX_RESET_DONE:
+		return "Mininet index reset done";
+	case -MINET_SLAVE_STATUS_INDEX_ERROR:
+		return "Mininet index error";
+	case -MINET_SLAVE_STATUS_INDEX_CMD_ERROR:
+		return "Mininet command error";
+	case -MINET_SLAVE_STATUS_INDEX_INVALID_PARAM:
+		return "Mininet invalid parameter";
+	case -MINET_SLAVE_STATUS_INDEX_UNKNOWN_CMD:
+		return "Mininet unknown command";
+	case -MINET_SLAVE_STATUS_INDEX_CMD_ALREADY_EX:
+		return "Mininet command alearx executing";
+	default:
+		return strerror(nErrorCode);
 	}
 }

+ 30 - 5
libmininet/gfamininetmst.h

@@ -34,6 +34,19 @@ extern "C" {
 #define MINET_SLAVE_RESPONSE_ERROR_INDEX_NO_MATCH				-8
 #define MINET_SLAVE_RESPONSE_ERROR_INVALID_CHECKSUM				-9
 
+#define MINET_SLAVE_STATUS_INDEX_RESET_DONE						0xC0
+#define MINET_SLAVE_STATUS_INDEX_ERROR							0xC1
+#define MINET_SLAVE_STATUS_INDEX_CMD_ERROR						0xC2
+#define MINET_SLAVE_STATUS_INDEX_INVALID_PARAM					0xC3
+#define MINET_SLAVE_STATUS_INDEX_UNKNOWN_CMD					0xC4
+#define MINET_SLAVE_STATUS_INDEX_CMD_ALREADY_EX					0xC8
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define NODE_IS_BROADCAST(n)									((n) == 0)
+#define NODE_IS_GROUPCAST(n)									((((n) & 0xF0) != 0) && (((n) & 0x0F) == 0))
+#define NODE_IS_MULTICAST(n)									(NODE_IS_BROADCAST(n) || NODE_IS_GROUPCAST(n))
+
 /////////////////////////////////////////////////////////////////////////////
 
 typedef struct _GFA_MININET_FRAME
@@ -65,7 +78,7 @@ typedef const GFA_MININET_MST_CFG_PARAMS *LPCGFA_MININET_MST_CFG_PARAMS;
 
 /////////////////////////////////////////////////////////////////////////////
 
-HGFAMINEMST	GfaMininetMasterOpen(LPGFA_MININET_MST_CFG_PARAMS pmmcp);
+HGFAMINEMST	GfaMininetMasterOpen(LPCGFA_MININET_MST_CFG_PARAMS pmmcp);
 void		GfaMininetMasterClose(HGFAMINEMST hMst);
 
 size_t	GfaMininetMasterBuildFrame(HGFAMINEMST hMst, uint8_t nNode, uint8_t nIndex, const void *pDataPayload, size_t nCbDataPayload, void *pFrameBuffer, size_t nCbFrameBuffer);
@@ -73,9 +86,9 @@ ssize_t	GfaMininetMasterTransmitFrame(HGFAMINEMST hMst, const void *pData, size_
 ssize_t	GfaMininetMasterReceiveFrame(HGFAMINEMST hMst, void *pBuffer, size_t nCbBuffer, bool bAckPossible);
 int		GfaMininetMasterEvaluateSlaveResponse(HGFAMINEMST hMst, uint8_t nNode, const void *pFrame, size_t nCbFrame, bool bAckPossible, uint8_t *pbIndex);
 
-uint8_t	GfaMininetMasterCalcChk(const void *pData, size_t nCbData);
-ssize_t	GfaMininetMasterResetSlaveIndex(HGFAMINEMST hMst, uint8_t nNode);
-ssize_t	GfaMininetMasterResetLocalIndex(HGFAMINEMST hMst, uint8_t nNode);
+int		GfaMininetMasterResetSlaveIndex(HGFAMINEMST hMst, uint8_t nNode);
+int		GfaMininetMasterResetLocalIndex(HGFAMINEMST hMst, uint8_t nNode);
+int		GfaMininetMasterPurgeDeviceRXBuffer(HGFAMINEMST hMst);
 
 bool	GfaMininetMasterGetTimeouts(HGFAMINEMST hMst, struct timeval *ptvRX, struct timeval *ptvTX);
 bool	GfaMininetMasterSetTimeouts(HGFAMINEMST hMst, const struct timeval *ptvRX, const struct timeval *ptvTX);
@@ -84,8 +97,20 @@ bool	GfaMininetMasterRestoreTimeouts(HGFAMINEMST hMst);
 
 ssize_t	GfaMininetMasterGetConfigParams(HGFAMINEMST hMst, void *pDevParams, size_t nSizeDevParams);
 int		GfaMininetMasterSetConfigParams(HGFAMINEMST hMst, const void *pDevParams, size_t nSizeDevParams);
+bool	GfaMininetMasterIsValidBaudrate(HGFAMINEMST hMst, uint32_t nBaudrate);
+int		GfaMininetMasterSetBaudrate(HGFAMINEMST hMst, uint32_t nBaudrate);
+
+HMINETDEV GfaMininetMasterGetDeviceHandle(HGFAMINEMST hMst);
+
+/////////////////////////////////////////////////////////////////////////////
+
+uint8_t	GfaMininetMasterCalcChk(const void *pData, size_t nCbData, bool bProcessSTX);
+ssize_t	GfaMininetMasterGetDataFromFrame(const void *pFrame, size_t nCbFrame, void *pData, size_t nCbData);
+ssize_t	GfaMininetMasterGetDataFromSlaveFrame(const void *pFrame, size_t nCbFrame, void *pData, size_t nCbData);
+void	GfaMininetMasterDumpFrame(HGFAMINEMST hMst, FILE *pf, LPCGFA_MININET_FRAME pFrame, bool bTX, const char *pszAnnotation);
+int		GfaMininetMasterSetVerbosity(HGFAMINEMST hMst, int nVerbosity);
 
-void	GfaMininetMasterDumpFrame(FILE *pf, LPCGFA_MININET_FRAME pFrame);
+const char* GfaMininetMasterStrError(int nErrorCode);
 
 /////////////////////////////////////////////////////////////////////////////
 #ifdef __cplusplus

+ 30 - 3
libmininet/gfaserial.c

@@ -38,7 +38,6 @@ static speed_t _MapBaudrate(uint32_t b)
 
 	switch(b)
 	{
-	case 0:			s = B0; break;
 	case 50:		s = B50; break;
 	case 75:		s = B75; break;
 	case 110:		s = B110; break;
@@ -219,7 +218,7 @@ void GfaSerialClose(HGFADEVICE hSer)
 
 ssize_t GfaSerialGetConfig(HGFADEVICE hSer, LPGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams)
 {
-	if(hSer && pscp && nSizeCfgParams >= sizeof(GFA_SER_CFG_PARAMS))
+	if(hSer && pscp && nSizeCfgParams == sizeof(GFA_SER_CFG_PARAMS))
 	{
 		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
 		memcpy(pscp, &psd->cfg, sizeof(GFA_SER_CFG_PARAMS));
@@ -234,7 +233,7 @@ ssize_t GfaSerialGetConfig(HGFADEVICE hSer, LPGFA_SER_CFG_PARAMS pscp, size_t nS
 
 int GfaSerialSetConfig(HGFADEVICE hSer, LPCGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams)
 {
-	if(hSer && pscp && nSizeCfgParams >= sizeof(GFA_SER_CFG_PARAMS))
+	if(hSer && pscp && nSizeCfgParams == sizeof(GFA_SER_CFG_PARAMS))
 	{
 		int nRet;
 		speed_t s;
@@ -402,6 +401,25 @@ int GfaSerialSetConfig(HGFADEVICE hSer, LPCGFA_SER_CFG_PARAMS pscp, size_t nSize
 
 /////////////////////////////////////////////////////////////////////////////
 
+int GfaSerialSetBaudrate(HGFADEVICE hSer, uint32_t nBaudrate)
+{
+	if(hSer && GfaSerialIsValidBaudrate(nBaudrate))
+	{
+		GFA_SER_CFG_PARAMS scp;
+
+		if(GfaSerialGetConfig(hSer, &scp, sizeof(scp)) == sizeof(scp))
+		{
+			scp.baud = nBaudrate;
+			return GfaSerialSetConfig(hSer, &scp, sizeof(scp));
+		}
+	}
+
+	errno = EINVAL;
+    return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 bool GfaSerialGetDeviceInterface(LPGFA_GENERIC_DEVICE_INTERFACE pDevItf)
 {
 	if(pDevItf)
@@ -410,6 +428,8 @@ bool GfaSerialGetDeviceInterface(LPGFA_GENERIC_DEVICE_INTERFACE pDevItf)
 		pDevItf->pfnClose			= GfaSerialClose;
 		pDevItf->pfnGetConfig		= (PFN_GFA_GENERIC_DEV_GET_CONFIG)GfaSerialGetConfig;
 		pDevItf->pfnSetConfig		= (PFN_GFA_GENERIC_DEV_SET_CONFIG)GfaSerialSetConfig;
+		pDevItf->pfnIsValidBaudrate = GfaSerialIsValidBaudrate;
+		pDevItf->pfnSetBaudrate		= GfaSerialSetBaudrate;
 		pDevItf->pfnGetTimeouts		= GfaSerialGetTimeouts;
 		pDevItf->pfnSetTimeouts		= GfaSerialSetTimeouts;
 		pDevItf->pfnPurgeRXBuffer	= GfaSerialPurgeRXBuffer;
@@ -429,6 +449,13 @@ bool GfaSerialGetDeviceInterface(LPGFA_GENERIC_DEVICE_INTERFACE pDevItf)
 
 /////////////////////////////////////////////////////////////////////////////
 
+bool GfaSerialIsValidBaudrate(uint32_t nBaudrate)
+{
+	return _MapBaudrate(nBaudrate) != (speed_t)-1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 ssize_t GfaSerialPurgeRXBuffer(HGFADEVICE hSer)
 {
 	struct timeval tvSave;

+ 4 - 1
libmininet/gfaserial.h

@@ -33,9 +33,12 @@ typedef const GFA_SER_CFG_PARAMS *LPCGFA_SER_CFG_PARAMS;
 HGFADEVICE GfaSerialOpen(const char *pszDeviceName, LPCGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams);
 void GfaSerialClose(HGFADEVICE hSer);
 
+bool GfaSerialGetDeviceInterface(LPGFA_GENERIC_DEVICE_INTERFACE pDevItf);
+bool GfaSerialIsValidBaudrate(uint32_t nBaudrate);
+
 ssize_t GfaSerialGetConfig(HGFADEVICE hSer, LPGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams);
 int GfaSerialSetConfig(HGFADEVICE hSer, LPCGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams);
-bool GfaSerialGetDeviceInterface(LPGFA_GENERIC_DEVICE_INTERFACE pDevItf);
+int GfaSerialSetBaudrate(HGFADEVICE hSer, uint32_t nBaudrate);
 
 bool GfaSerialGetTimeouts(HGFADEVICE hSer, struct timeval *ptvRX, struct timeval *ptvTX);
 bool GfaSerialSetTimeouts(HGFADEVICE hSer, const struct timeval *ptvRX, const struct timeval *ptvTX);

+ 7 - 3
libmininet/libmininet.pro

@@ -1,6 +1,5 @@
 TEMPLATE = lib
 TARGET = gfamininet
-#CONFIG += console
 CONFIG -= app_bundle
 CONFIG -= qt
 
@@ -16,7 +15,8 @@ SOURCES += \
     gfaserial.c \
     gfamininetmst.c \
     gfamininetdev.c \
-    gfabootlmast.c
+    gfabootlmast.c \
+    dbghlp.c
 
 linux-buildroot-g++ {
 }
@@ -26,6 +26,10 @@ HEADERS += \
     gfamininetdev.h \
     gfagenericdev.h \
     gfaserial.h \
-    gfabootlmast.h
+    gfabootlmast.h \
+    dbghlp.h
 
 QMAKE_INCDIR += ../ti
+
+# do not create symbolic links
+QMAKE_LN_SHLIB = :