Procházet zdrojové kódy

Erste Version zur Ansicht.

Rind před 5 roky
revize
0f87b84a7d

+ 12 - 0
demo/.gitignore

@@ -0,0 +1,12 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
+
+Debug/
+Profile/
+Release/
+*.pro.user
+*.bak

+ 24 - 0
demo/demo.pro

@@ -0,0 +1,24 @@
+TEMPLATE = app
+CONFIG += console
+CONFIG -= app_bundle
+CONFIG -= qt
+
+CONFIG(debug, debug|release) {
+    QMAKE_CXXFLAGS -= -Os
+    QMAKE_CFLAGS -= -Os
+    QMAKE_CXXFLAGS += -D_DEBUG
+    QMAKE_CFLAGS += -D_DEBUG
+}
+
+linux-buildroot-g++ {
+    QMAKE_CXXFLAGS += -D_TARGET_BUILD
+    QMAKE_CFLAGS += -D_TARGET_BUILD
+	target.path += /opt/GfA/mininet/demo
+	INSTALLS += target
+}
+
+QMAKE_LIBS += -lgfamininetd
+QMAKE_INCDIR += ../ti
+#QMAKE_LIBDIR += $$OUT_PWD/../../../libmininet/Debug/Desktop_Qt_5_7_0_GCC_64bit
+
+SOURCES += main.c

+ 717 - 0
demo/main.c

@@ -0,0 +1,717 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <gfaserial.h>
+#include <byteswap.h>
+#include <gfabootlmast.h>
+#include "bl_commands.h"
+
+#ifdef _TARGET_BUILD
+#define _DEVICE_NAME				"/dev/ttyO4"
+#else
+#define _DEVICE_NAME				"/dev/tty0"
+#endif	//	_TARGET_BUILD
+
+#define _SLAVE_NODE_ADDR			0xFF
+#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 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)
+
+////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_APP_IMG_HEADER
+{
+	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;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+static ssize_t _PollBlData(HGFAMINEMST hMst, void *pData, size_t nCbData, uint32_t nTimeoutMS)
+{
+	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;
+
+	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)
+	{
+    }
+
+	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));
+		}
+	}
+
+	return -1;
+}
+
+static int _BlDumpMemory(HGFAMINEMST hMst, uint32_t nAddress, uint32_t nCntDwords, void *pBuffer, size_t nCbBuffer)
+{
+	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
+	{
+		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;
+	}
+
+	return -1;
+}
+
+static int _BlIsExecuting(HGFAMINEMST hMst)
+{
+	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)
+	{
+		TRACE_FRAME((LPCGFA_MININET_FRAME)rxb);
+		// TODO: application response
+		return 1;
+	}
+	else if(nRet == MINET_SLAVE_RESPONSE_ACK)
+	{
+		return 0;
+	}
+
+	return -1;
+}
+
+static int _BlGetImgInfo(HGFAMINEMST hMst, uint32_t *pnImgLength, uint32_t *pnImgCRC32)
+{
+	if(hMst && pnImgLength && pnImgCRC32)
+	{
+		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;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+int main(void)
+{
+	ssize_t nRet = 0;
+
+	////////////////////////////////////////////////////////////////////////////////
+
+	GFA_MININET_MST_CFG_PARAMS mmcp;
+	memset(&mmcp, 0, sizeof(mmcp));
+
+	if(GfaSerialGetDeviceInterface(&mmcp.devcfg.itf))
+	{
+		GFA_SER_CFG_PARAMS scp;
+		memset(&scp, 0, sizeof(scp));
+
+		////////////////////////////////////////////////////////////////////////////
+		// serial interface parameters
+
+		scp.baud			= 19200;
+		scp.data			= 8;
+		scp.stop			= 1;
+		scp.parity			= 'N';
+#ifdef _TARGET_BUILD
+		scp.bHandleTxEcho	= true;
+#endif	//	_TARGET_BUILD
+
+		////////////////////////////////////////////////////////////////////////////
+		// mininet master configuration
+
+		mmcp.devcfg.pszDeviceName	= _DEVICE_NAME;
+		mmcp.devcfg.pDevParams		= &scp;
+		mmcp.devcfg.nSizeDevParams	= sizeof(scp);
+
+		////////////////////////////////////////////////////////////////////////////
+		////////////////////////////////////////////////////////////////////////////
+		////////////////////////////////////////////////////////////////////////////
+
+		HGFAMINEMST hMst = GfaMininetMasterOpen(&mmcp);
+
+		if(hMst)
+		{
+			uint8_t status;
+			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)
+			{
+				TRACE("Ping ok!\n");
+	        }
+
+			if((nRet = _BlGetStatus(hMst, &status)) == 0)
+			{
+				TRACE("Status: 0x%02hhX\n", status);
+	        }
+
+            if((nRet = _BlGetImgInfo(hMst, &nImgLength, &nImgCRC32)) == 0)
+			{
+				TRACE("Bootloader Img. Length: %u, Bootloader Img. CRC: 0x%08X\n", nImgLength, nImgCRC32);
+	        }
+
+			if((nRet = _BlWriteMaterialAndSerial(hMst, "Material 1", "123456789-1")) == 0)
+			{
+				TRACE("Set Material and Serial Numbers ...\n");
+	        }
+
+			if((nRet = _BlReadMaterialAndSerial(hMst, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) == 0)
+			{
+				TRACE("Material: \"%s\", Serial: \"%s\"\n", szMaterial, szSerial);
+	        }
+
+			if((nRet = _BlWriteMaterialAndSerial(hMst, _BL_MATERIAL, _BL_SERIAL)) == 0)
+			{
+				TRACE("Set Material and Serial Numbers ...\n");
+	        }
+
+			if((nRet = _BlReadMaterialAndSerial(hMst, szMaterial, sizeof(szMaterial), szSerial, sizeof(szSerial))) == 0)
+			{
+				TRACE("Material: \"%s\", Serial: \"%s\"\n", szMaterial, szSerial);
+	        }
+
+			if((nRet = _BlSetBaudrate(hMst, 19200)) == 0)
+			{
+				TRACE("Set Baudrate: %u\n", 19200);
+	        }
+
+			if((nRet = _BlPing(hMst)) == 1)
+			{
+				TRACE("Ping ok!\n");
+	        }
+
+			GfaMininetMasterClose(hMst);
+		}
+	}
+
+    return nRet;
+}

+ 12 - 0
libmininet/.gitignore

@@ -0,0 +1,12 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
+
+Debug/
+Profile/
+Release/
+*.pro.user
+*.bak

+ 50 - 0
libmininet/gfabootlmast.c

@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <gfaserial.h>
+#include <gfamininetmst.h>
+#include <byteswap.h>
+#include "bl_commands.h"
+#include "gfabootlmast.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+uint8_t GfaBLM_BU_DataCheckSum(const void *pData, size_t nCbData)
+{
+	uint8_t chk = 0;
+	const uint8_t *pbData = (const uint8_t*)pData;
+	while(nCbData--) {
+		chk += *pbData++;
+	}
+	return chk;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+size_t GfaBLM_BuildCmdDataPacket(const char *pszCmd, const void *pCmdData, size_t nCbCmdData, void *pPacket, size_t nCbPacket, bool bAddLenAndCheck)
+{
+	size_t nLen = strlen(pszCmd);
+	uint8_t *pbPacket = (uint8_t*)pPacket;
+	
+	if(nCbPacket < (nLen + nCbCmdData + ((pCmdData && nCbCmdData && bAddLenAndCheck) ? 2 : 0)))
+		return 0;
+
+	memcpy(pbPacket, pszCmd, nLen);
+	pbPacket += nLen;
+
+	if(pCmdData && nCbCmdData)
+	{
+		if(bAddLenAndCheck)
+		{
+			*pbPacket++ = nCbCmdData + 2;
+			*pbPacket++ = GfaBLM_BU_DataCheckSum(pCmdData, nCbCmdData);
+			nLen += 2;
+		}
+		memcpy(pbPacket, pCmdData, nCbCmdData);
+		nLen += nCbCmdData;
+	}
+
+	return nLen;
+}

+ 28 - 0
libmininet/gfabootlmast.h

@@ -0,0 +1,28 @@
+// gfabootlmast.h :
+//
+
+#if !defined(AGD_GFABOOTLMAST_H__9BEF8C2B_D667_41C2_A0F0_6F1CC86DCF36__INCLUDED_)
+#define AGD_GFABOOTLMAST_H__9BEF8C2B_D667_41C2_A0F0_6F1CC86DCF36__INCLUDED_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/time.h>
+#include <gfamininetmst.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// 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);
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_GFABOOTLMAST_H__9BEF8C2B_D667_41C2_A0F0_6F1CC86DCF36__INCLUDED_)

+ 61 - 0
libmininet/gfagenericdev.h

@@ -0,0 +1,61 @@
+// gfagenericdev.h :
+//
+
+#if !defined(AGD_GFAGENERICDEV_H__D0E1325F_D1A0_41DB_9FB4_0BC91A60EC98__INCLUDED_)
+#define AGD_GFAGENERICDEV_H__D0E1325F_D1A0_41DB_9FB4_0BC91A60EC98__INCLUDED_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// gfagenericdev.h - Declarations:
+
+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_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);
+typedef ssize_t		(*PFN_GFA_GENERIC_DEV_RECEIVE)			(HGFADEVICE hDev, void *pBuf, size_t nCbToRead);
+typedef ssize_t		(*PFN_GFA_GENERIC_DEV_READ)				(HGFADEVICE hDev, void *pBuf, size_t nCbToRead);
+typedef ssize_t		(*PFN_GFA_GENERIC_DEV_POP)				(HGFADEVICE hDev, uint8_t *pb);
+typedef ssize_t		(*PFN_GFA_GENERIC_DEV_PEEK)				(HGFADEVICE hDev);
+typedef ssize_t		(*PFN_GFA_GENERIC_DEV_TRANSMIT)			(HGFADEVICE hDev, const void *pData, size_t nCbData);
+typedef ssize_t		(*PFN_GFA_GENERIC_DEV_WRITE)			(HGFADEVICE hSer, const void *pData, size_t nCbData);
+typedef ssize_t		(*PFN_GFA_GENERIC_DEV_PUSH)				(HGFADEVICE hSer, uint8_t b);
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_GENERIC_DEVICE_INTERFACE
+{
+	PFN_GFA_GENERIC_DEV_OPEN			pfnOpen;
+	PFN_GFA_GENERIC_DEV_CLOSE			pfnClose;
+	PFN_GFA_GENERIC_DEV_GET_CONFIG		pfnGetConfig;
+	PFN_GFA_GENERIC_DEV_SET_CONFIG		pfnSetConfig;
+	PFN_GFA_GENERIC_DEV_GET_TIMEOUTS	pfnGetTimeouts;
+	PFN_GFA_GENERIC_DEV_SET_TIMEOUTS	pfnSetTimeouts;
+	PFN_GFA_GENERIC_DEV_PURGE_RX_BUFFER	pfnPurgeRXBuffer;
+	PFN_GFA_GENERIC_DEV_RECEIVE			pfnReceive;
+	PFN_GFA_GENERIC_DEV_READ			pfnRead;
+	PFN_GFA_GENERIC_DEV_POP				pfnPop;
+	PFN_GFA_GENERIC_DEV_PEEK			pfnPeek;
+	PFN_GFA_GENERIC_DEV_TRANSMIT		pfnTransmit;
+	PFN_GFA_GENERIC_DEV_WRITE			pfnWrite;
+	PFN_GFA_GENERIC_DEV_PUSH			pfnPush;
+}GFA_GENERIC_DEVICE_INTERFACE, *LPGFA_GENERIC_DEVICE_INTERFACE;
+typedef const GFA_GENERIC_DEVICE_INTERFACE *LPCGFA_GENERIC_DEVICE_INTERFACE;
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_GFAGENERICDEV_H__D0E1325F_D1A0_41DB_9FB4_0BC91A60EC98__INCLUDED_)

+ 268 - 0
libmininet/gfamininetdev.c

@@ -0,0 +1,268 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <gfamininetdev.h>
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_MININET_DEVICE
+{
+	HGFADEVICE hDev;
+	GFA_GENERIC_DEVICE_INTERFACE itf;
+}GFA_MININET_DEVICE, *LPGFA_MININET_DEVICE;
+typedef const GFA_MININET_DEVICE *LPCGFA_MININET_DEVICE;
+
+/////////////////////////////////////////////////////////////////////////////
+
+HMINETDEV GfaMininetDeviceOpen(LPCGFA_MININET_DEV_CFG_PARAMS pmdcp)
+{
+	if(pmdcp && pmdcp->itf.pfnOpen)
+	{
+		HGFADEVICE hDev;
+		
+		if((hDev = (*pmdcp->itf.pfnOpen)(pmdcp->pszDeviceName, pmdcp->pDevParams, pmdcp->nSizeDevParams)))
+		{
+			LPGFA_MININET_DEVICE pDev = malloc(sizeof(GFA_MININET_DEVICE));
+			memset(pDev, 0, sizeof(GFA_MININET_DEVICE));
+			memcpy(&pDev->itf, &pmdcp->itf, sizeof(GFA_GENERIC_DEVICE_INTERFACE));
+			pDev->hDev = hDev;
+			return (HMINETDEV)pDev;
+		}
+
+		return NULL;
+	}
+
+	errno = EINVAL;
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaMininetDeviceClose(HMINETDEV hDev)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnClose)
+			(*pDev->itf.pfnClose)(pDev->hDev);
+		free(pDev);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetDeviceGetConfigParams(HMINETDEV hDev, void *pDevCfgParams, size_t nSizeDevCfgParams)
+{
+	if(hDev && pDevCfgParams && nSizeDevCfgParams)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnGetConfig)
+			return (*pDev->itf.pfnGetConfig)(pDev->hDev, pDevCfgParams, nSizeDevCfgParams);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaMininetDeviceSetConfigParams(HMINETDEV hDev, const void *pDevCfgParams, size_t nSizeDevCfgParams)
+{
+	if(hDev && pDevCfgParams && nSizeDevCfgParams)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnSetConfig)
+			return (*pDev->itf.pfnSetConfig)(pDev->hDev, pDevCfgParams, nSizeDevCfgParams);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaMininetDeviceGetTimeouts(HMINETDEV hDev, struct timeval *ptvRX, struct timeval *ptvTX)
+{
+	if(hDev && (ptvRX || ptvTX))
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnGetTimeouts)
+			return (*pDev->itf.pfnGetTimeouts)(pDev->hDev, ptvRX, ptvTX);
+
+		errno = EOPNOTSUPP;
+		return false;
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaMininetDeviceSetTimeouts(HMINETDEV hDev, const struct timeval *ptvRX, const struct timeval *ptvTX)
+{
+	if(hDev && (ptvRX || ptvTX))
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnSetTimeouts)
+			return (*pDev->itf.pfnSetTimeouts)(pDev->hDev, ptvRX, ptvTX);
+
+		errno = EOPNOTSUPP;
+		return false;
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetDevicePurgeRXBuffer(HMINETDEV hDev)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnPurgeRXBuffer)
+			return (*pDev->itf.pfnPurgeRXBuffer)(pDev->hDev);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t	GfaMininetDeviceReceive(HMINETDEV hDev, void *pBuf, size_t nCbToRead)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnReceive)
+			return (*pDev->itf.pfnReceive)(pDev->hDev, pBuf, nCbToRead);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetDeviceRead(HMINETDEV hDev, void *pBuf, size_t nCbToRead)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnRead)
+			return (*pDev->itf.pfnRead)(pDev->hDev, pBuf, nCbToRead);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetDevicePop(HMINETDEV hDev, uint8_t *pb)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnPop)
+			return (*pDev->itf.pfnPop)(pDev->hDev, pb);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetDevicePeek(HMINETDEV hDev)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnPeek)
+			return (*pDev->itf.pfnPeek)(pDev->hDev);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetDeviceTransmit(HMINETDEV hDev, const void *pData, size_t nCbData)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnTransmit)
+			return (*pDev->itf.pfnTransmit)(pDev->hDev, pData, nCbData);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetDeviceWrite(HMINETDEV hDev, const void *pData, size_t nCbData)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnWrite)
+			return (*pDev->itf.pfnWrite)(pDev->hDev, pData, nCbData);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetDevicePush(HMINETDEV hDev, uint8_t b)
+{
+	if(hDev)
+	{
+		LPGFA_MININET_DEVICE pDev = (LPGFA_MININET_DEVICE)hDev;
+		if(pDev->itf.pfnPush)
+			return (*pDev->itf.pfnPush)(pDev->hDev, b);
+
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	errno = EINVAL;
+	return -1;
+}

+ 55 - 0
libmininet/gfamininetdev.h

@@ -0,0 +1,55 @@
+// gfamininetdev.h :
+//
+
+#if !defined(AGD_GFAMININETDEV_H__A748DF9B_2D65_499F_952B_104B6F1228F7__INCLUDED_)
+#define AGD_GFAMININETDEV_H__A748DF9B_2D65_499F_952B_104B6F1228F7__INCLUDED_
+
+#include <gfagenericdev.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// gfamininetdev.h - Declarations:
+
+typedef void							*HMINETDEV;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_MININET_DEV_CFG_PARAMS
+{
+	const char *pszDeviceName;
+	const void *pDevParams;
+	size_t nSizeDevParams;
+	GFA_GENERIC_DEVICE_INTERFACE itf;
+}GFA_MININET_DEV_CFG_PARAMS, *LPGFA_MININET_DEV_CFG_PARAMS;
+typedef const GFA_MININET_DEV_CFG_PARAMS *LPCGFA_MININET_DEV_CFG_PARAMS;
+
+/////////////////////////////////////////////////////////////////////////////
+
+HMINETDEV GfaMininetDeviceOpen(LPCGFA_MININET_DEV_CFG_PARAMS pmdcp);
+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	GfaMininetDeviceGetTimeouts(HMINETDEV hDev, struct timeval *ptvRX, struct timeval *ptvTX);
+bool	GfaMininetDeviceSetTimeouts(HMINETDEV hDev, const struct timeval *ptvRX, const struct timeval *ptvTX);
+ssize_t	GfaMininetDevicePurgeRXBuffer(HMINETDEV hDev);
+
+ssize_t	GfaMininetDeviceReceive(HMINETDEV hDev, void *pBuf, size_t nCbToRead);			// blocking
+ssize_t GfaMininetDeviceRead(HMINETDEV hDev, void *pBuf, size_t nCbToRead);				// not blocking
+ssize_t GfaMininetDevicePop(HMINETDEV hDev, uint8_t *pb);								// 1 byte, blocking
+ssize_t GfaMininetDevicePeek(HMINETDEV hDev);											// not blocking
+
+ssize_t GfaMininetDeviceTransmit(HMINETDEV hDev, const void *pData, size_t nCbData);	// blocking
+ssize_t GfaMininetDeviceWrite(HMINETDEV hDev, const void *pData, size_t nCbData);		// not blocking
+ssize_t GfaMininetDevicePush(HMINETDEV hDev, uint8_t b);								// 1 byte, blocking
+
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_GFAMININETDEV_H__A748DF9B_2D65_499F_952B_104B6F1228F7__INCLUDED_)

+ 745 - 0
libmininet/gfamininetmst.c

@@ -0,0 +1,745 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include "gfamininetmst.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// https://www.racom.eu/eng/support/prot/mininet/index.html
+/////////////////////////////////////////////////////////////////////////////
+
+#define STX							((uint8_t)0x02)
+#define ACK							((uint8_t)0x06)
+#define SLAVE_IND					((uint8_t)0x80)
+
+#define START_INDEX					0x40
+#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))
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef enum _GfaMininetRxStates
+{
+	GfaRxMNS_Stx,
+	GfaRxMNS_Len,
+	GfaRxMNS_Node,
+	GfaRxMNS_Index,
+	GfaRxMNS_Data,
+	GfaRxMNS_Zero,
+	GfaRxMNS_Check
+}GfaMininetRxStates, *LPGfaMininetRxStates;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_MININET_MASTER
+{
+	HMINETDEV hDev;
+	struct timeval tvRXSave;
+	struct timeval tvTXSave;
+	uint8_t nIndexTable[256];
+}GFA_MININET_MASTER, *LPGFA_MININET_MASTER;
+typedef const GFA_MININET_MASTER *LPCGFA_MININET_MASTER;
+
+/////////////////////////////////////////////////////////////////////////////
+
+static bool _IsValidIndex(uint8_t nIndex)
+{
+	return ((nIndex >= MIN_INDEX) && (nIndex <= MAX_INDEX));
+}
+
+static uint8_t _GetNextIndex(HGFAMINEMST hMst, uint8_t nNode)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		uint8_t idx = ++pMst->nIndexTable[nNode];
+		if(idx > MAX_INDEX)
+		{
+			pMst->nIndexTable[nNode] = START_INDEX;
+			idx = pMst->nIndexTable[nNode];
+		}
+		return idx;
+	}
+	return 0xFF;
+}
+
+static uint8_t _GetCurIndex(HGFAMINEMST hMst, uint8_t nNode)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return pMst->nIndexTable[nNode];
+	}
+	return 0xFF;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+HGFAMINEMST GfaMininetMasterOpen(LPGFA_MININET_MST_CFG_PARAMS pmmcp)
+{
+	if(pmmcp)
+	{
+		HMINETDEV hDev = GfaMininetDeviceOpen(&pmmcp->devcfg);
+
+		if(hDev)
+		{
+			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;
+			return (HGFAMINEMST)pMst;
+		}
+
+		return NULL;
+	}
+
+	errno = EINVAL;
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaMininetMasterClose(HGFAMINEMST hMst)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		GfaMininetDeviceClose(pMst->hDev);
+		free(pMst);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaMininetMasterGetTimeouts(HGFAMINEMST hMst, struct timeval *ptvRX, struct timeval *ptvTX)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return GfaMininetDeviceGetTimeouts(pMst->hDev, ptvRX, ptvTX);
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaMininetMasterSetTimeouts(HGFAMINEMST hMst, const struct timeval *ptvRX, const struct timeval *ptvTX)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return GfaMininetDeviceSetTimeouts(pMst->hDev, ptvRX, ptvTX);
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaMininetMasterSaveTimeouts(HGFAMINEMST hMst)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return GfaMininetMasterGetTimeouts(hMst, &pMst->tvRXSave, &pMst->tvTXSave);
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaMininetMasterRestoreTimeouts(HGFAMINEMST hMst)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return GfaMininetMasterSetTimeouts(hMst, &pMst->tvRXSave, &pMst->tvTXSave);
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t	GfaMininetMasterGetConfigParams(HGFAMINEMST hMst, void *pDevParams, size_t nSizeDevParams)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return GfaMininetDeviceGetConfigParams(pMst->hDev, pDevParams, nSizeDevParams);
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaMininetMasterSetConfigParams(HGFAMINEMST hMst, const void *pDevParams, size_t nSizeDevParams)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return GfaMininetDeviceSetConfigParams(pMst->hDev, pDevParams, nSizeDevParams);
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+uint8_t GfaMininetMasterCalcChk(const void *pData, size_t nCbData)
+{
+	size_t i = 0;
+	uint16_t chk = 0;
+	uint8_t cc, lc = 0;
+	const uint8_t *pszData = (const uint8_t*)pData;
+
+	for(i = 0; i < nCbData; ++i)
+	{
+		cc = *pszData++;
+
+		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)
+			lc = cc;
+	}
+
+	if((uint8_t)chk == STX)
+		chk = ~chk;
+	return (uint8_t)chk;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+size_t GfaMininetMasterBuildFrame(HGFAMINEMST hMst, uint8_t nNode, uint8_t nIndex, const void *pDataPayload, size_t nCbDataPayload, void *pFrameBuffer, size_t nCbFrameBuffer)
+{
+	if(hMst && pFrameBuffer && (nCbFrameBuffer >= 5) && (nCbDataPayload <= MAX_DATA_PAYLOAD_LENGTH))
+	{
+		int i = 0;
+		uint8_t b, c;
+		size_t nLen = 4;
+		const uint8_t *pszData = (const uint8_t*)pDataPayload;
+		LPGFA_MININET_FRAME pf = (LPGFA_MININET_FRAME)pFrameBuffer;
+
+		pf->stx		= STX;
+		pf->len		= 5 + nCbDataPayload;
+		pf->node	= nNode;
+		pf->index	= _IsValidIndex(nIndex) ? nIndex : _GetNextIndex(hMst, nNode);
+
+		if(pszData && nCbDataPayload)
+		{
+			while(nCbDataPayload--)
+			{
+				b = *pszData++;
+
+				do
+				{
+					if(++nLen == nCbFrameBuffer)
+					{
+						errno = ENOMEM;
+						return 0;
+					}
+
+					pf->data.by[i++] = b;
+					c = b;
+					b = 0;
+				}
+				while(c == STX);
+			}
+		}
+
+		pf->data.by[i++] = GfaMininetMasterCalcChk(pFrameBuffer, nLen);
+		++nLen;
+		return nLen;
+	}
+
+	errno = EINVAL;
+	return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetMasterResetSlaveIndex(HGFAMINEMST hMst, uint8_t nNode)
+{
+	if(hMst)
+	{
+		ssize_t 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)))
+		{
+			if(!NODE_IS_BROADCAST(nNode) && !NODE_IS_GROUPCAST(nNode))
+			{
+				// 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 == STATUS_INDEX_RESET_DONE)
+						return GfaMininetMasterResetLocalIndex(hMst, nNode);
+					else
+					{
+						errno = nIndex;
+						return -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;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetMasterResetLocalIndex(HGFAMINEMST hMst, uint8_t nNode)
+{
+	if(hMst)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+
+		if(NODE_IS_BROADCAST(nNode))
+			memset(pMst->nIndexTable, START_INDEX, sizeof(pMst->nIndexTable));
+		else if(NODE_IS_GROUPCAST(nNode))
+			memset(&pMst->nIndexTable[nNode], START_INDEX, 10);
+		else
+			pMst->nIndexTable[nNode] = START_INDEX;
+
+		return 0;
+	}
+
+	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)
+	{
+		bool bIsStatusIndex = false;
+		LPCGFA_MININET_FRAME pf = (LPCGFA_MININET_FRAME)pFrame;
+
+		/////////////////////////////////////////////////////////////////////
+
+		if((nCbFrame < 6))
+		{
+			if(bAckPossible && (pf->stx == ACK))
+			{
+				return MINET_SLAVE_RESPONSE_ACK;
+			}
+			else
+			{
+				errno = MINET_SLAVE_RESPONSE_ERROR_INVALID_LENGTH;
+				return -1;
+			}
+		}
+		else
+		{
+			/////////////////////////////////////////////////////////////////
+			// STX / ACK
+
+			if(bAckPossible && (pf->stx == ACK))
+				return MINET_SLAVE_RESPONSE_ACK;
+			else if(pf->stx != STX)
+			{
+				errno =  MINET_SLAVE_RESPONSE_ERROR_STX_ERROR;
+				return -1;
+			}
+
+			/////////////////////////////////////////////////////////////////
+			// Length
+
+			if(pf->len > nCbFrame)
+			{
+				errno = MINET_SLAVE_RESPONSE_ERROR_INCOMPLETE_DATA;
+				return -1;
+			}
+
+			/////////////////////////////////////////////////////////////////
+			// Node address
+
+			if(pf->node != (nNode & 0xF0))
+			{
+				errno = MINET_SLAVE_RESPONSE_ERROR_INVALID_NODE_ADDRESS;
+				return -1;
+			}
+
+			/////////////////////////////////////////////////////////////////
+			// Index range / match / status code
+
+			if(pbIndex)
+				*pbIndex = pf->index;
+
+			if(_IsValidIndex(pf->index))
+			{
+				uint8_t nIndex = _GetCurIndex(hMst, nNode);
+				if(pf->index != nIndex)
+				{
+					errno = MINET_SLAVE_RESPONSE_ERROR_INDEX_NO_MATCH;
+					return -1;
+				}
+			}
+			else if(pf->index < MIN_INDEX)
+			{
+				errno = MINET_SLAVE_RESPONSE_ERROR_INDEX_OUT_OF_RANGE;
+				return -1;
+			}
+			else // pf->index > MAX_INDEX
+			{
+				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:
+					bIsStatusIndex = true;
+					break;
+				default:
+					errno = MINET_SLAVE_RESPONSE_ERROR_INDEX_OUT_OF_RANGE;
+					return -1;
+				}
+			}
+
+			/////////////////////////////////////////////////////////////////
+			// Data / Slave indicator
+
+			if(pf->data.by[0] != SLAVE_IND)
+			{
+				errno = MINET_SLAVE_RESPONSE_ERROR_INVALID_SLAVE_INDICATOR;
+				return -1;
+			}
+
+			/////////////////////////////////////////////////////////////////
+			// Checksum
+
+			if(pf->data.by[pf->len - 5] != GfaMininetMasterCalcChk(pf, pf->len - 1))
+			{
+				errno = MINET_SLAVE_RESPONSE_ERROR_INVALID_CHECKSUM;
+				return -1;
+			}
+			else
+			{
+				return bIsStatusIndex ? MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE : MINET_SLAVE_RESPONSE_SUCCESS;
+			}
+		}
+	}
+
+	errno = MINET_SLAVE_RESPONSE_ERROR_INVALID_ARGUMENT;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetMasterTransmitFrame(HGFAMINEMST hMst, const void *pData, size_t nCbData)
+{
+	if(hMst && pData && nCbData)
+	{
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		return GfaMininetDeviceTransmit(pMst->hDev, pData, nCbData);
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaMininetMasterReceiveFrame(HGFAMINEMST hMst, void *pBuffer, size_t nCbBuffer, bool bAckPossible)
+{
+	if(hMst && pBuffer && nCbBuffer)
+	{
+		uint8_t b, c, buf[256] = {0};
+		bool bLoop = true;
+		GfaMininetRxStates nState = GfaRxMNS_Stx;
+		ssize_t nRet, nCbDataPayloadExp = 0, nCbDataPayloadRcv = 0;
+		LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
+		LPGFA_MININET_FRAME pFrameRx = (LPGFA_MININET_FRAME)buf;
+
+		if(!pBuffer || !nCbBuffer)
+		{
+			errno = EINVAL;
+			return -1;
+		}
+
+		do
+		{
+			switch(nState)
+			{
+			////////////////////////////////////////////////////////////////////////
+			// handle STX
+			case GfaRxMNS_Stx:
+				if((nRet = GfaMininetDevicePop(pMst->hDev, &b)) != 1)
+				{
+					bLoop = false;
+					break;
+				}
+				if(b != STX)
+				{
+					if(bAckPossible && (b == ACK))
+					{
+						*(uint8_t*)pBuffer = b;
+                        nRet = 1;
+                        bLoop = false;
+                        break;
+                    }
+					continue;
+				}
+				pFrameRx->stx = b;
+				++nState;
+				// fall through
+
+			////////////////////////////////////////////////////////////////////////
+			// handle length
+			case GfaRxMNS_Len:
+				if((nRet = GfaMininetDevicePop(pMst->hDev, &b)) != 1)
+				{
+					bLoop = false;
+					break;
+				}
+				if(b < 5)
+				{
+					if(b == STX)
+						continue;
+					else
+					{
+						nState = GfaRxMNS_Stx;
+						continue;
+					}
+				}
+				pFrameRx->len = b;
+				nCbDataPayloadExp = b - 5;
+				++nState;
+				// fall through
+
+			////////////////////////////////////////////////////////////////////////
+			// handle node
+			case GfaRxMNS_Node:
+				if((nRet = GfaMininetDevicePop(pMst->hDev, &b)) != 1)
+				{
+					bLoop = false;
+					break;
+				}
+				if(b == STX)
+				{
+					nState = GfaRxMNS_Len;
+					continue;
+				}
+				pFrameRx->node = b;
+				++nState;
+				// fall through
+
+			////////////////////////////////////////////////////////////////////////
+			// handle index
+			case GfaRxMNS_Index:
+				if((nRet = GfaMininetDevicePop(pMst->hDev, &b)) != 1)
+				{
+					bLoop = false;
+					break;
+				}
+				if(b == STX)
+				{
+					nState = GfaRxMNS_Len;
+					continue;
+				}
+				else if(b < MIN_INDEX)
+				{
+					nState = GfaRxMNS_Stx;
+					continue;
+				}
+				pFrameRx->index = b;
+				++nState;
+				// fall through
+
+			////////////////////////////////////////////////////////////////////////
+			// handle data, if any
+			case GfaRxMNS_Data:
+				if(nCbDataPayloadExp > nCbDataPayloadRcv)
+				{
+					if((nRet = GfaMininetDevicePop(pMst->hDev, &b)) != 1)
+					{
+						bLoop = false;
+						break;
+					}
+					if(b == STX)
+						++nState;
+					pFrameRx->data.by[nCbDataPayloadRcv++] = b;
+					continue;
+				}
+				else
+				{
+					nState = GfaRxMNS_Check;
+					continue;
+				}
+
+			////////////////////////////////////////////////////////////////////////
+			// handle 0
+			case GfaRxMNS_Zero:
+				if((nRet = GfaMininetDevicePop(pMst->hDev, &b)) != 1)
+				{
+					bLoop = false;
+					break;
+				}
+				if(b == 0)
+				{
+					nState = GfaRxMNS_Data;
+					continue;
+				}
+				else if(b == STX)
+				{
+					nCbDataPayloadRcv = nCbDataPayloadExp = 0;
+					nState = GfaRxMNS_Len;
+					continue;
+				}
+				else if(b >= 5)
+				{
+					pFrameRx->len = b;
+					nCbDataPayloadRcv = 0;
+					nCbDataPayloadExp = b - 5;
+					nState = GfaRxMNS_Node;
+					continue;
+				}
+				else
+				{
+					nCbDataPayloadRcv = nCbDataPayloadExp = 0;
+					nState = GfaRxMNS_Stx;
+					continue;
+				}
+
+			////////////////////////////////////////////////////////////////////////
+			// handle Checksum
+			case GfaRxMNS_Check:
+				if((nRet = GfaMininetDevicePop(pMst->hDev, &b)) != 1)
+				{
+					bLoop = false;
+					break;
+				}
+				if(b == STX)
+				{
+					nCbDataPayloadRcv = nCbDataPayloadExp = 0;
+					nState = GfaRxMNS_Len;
+					continue;
+				}
+				c = GfaMininetMasterCalcChk(pFrameRx, pFrameRx->len - 1);
+				if(b == c)
+				{
+					if((size_t)pFrameRx->len <= nCbBuffer)
+					{
+						pFrameRx->data.by[nCbDataPayloadRcv] = b;
+						nRet = pFrameRx->len;
+						memcpy(pBuffer, pFrameRx, nRet);
+					}
+					else
+					{
+						errno = ENOMEM;
+						nRet = -1;
+					}
+				}
+				else
+				{
+					errno = EPROTO;
+					nRet = -1;
+				}
+				bLoop = false;
+				break;
+
+			////////////////////////////////////////////////////////////////////////
+			default:
+				nRet = -1;
+				bLoop = false;
+				break;
+			}
+		}
+		while(bLoop);
+
+		return nRet;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaMininetMasterDumpFrame(FILE *pf, LPCGFA_MININET_FRAME pFrame)
+{
+	if(pf)
+	{
+		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:   ");
+
+			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\n", pFrame->data.by[i], pFrame->data.by[i]);
+		}
+		else
+		{
+			fprintf(pf, "\nInvalid Mininet-Frame!\n");
+		}
+		
+		fflush(pf);
+	}
+}

+ 94 - 0
libmininet/gfamininetmst.h

@@ -0,0 +1,94 @@
+// gfamininetmst.h :
+//
+
+#if !defined(AGD_GFAMININETMST_H__FE13B563_B3D5_4AA2_81FD_B74220CF2D93__INCLUDED_)
+#define AGD_GFAMININETMST_H__FE13B563_B3D5_4AA2_81FD_B74220CF2D93__INCLUDED_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/time.h>
+#include <gfamininetdev.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// gfamininetmst.h - Declarations:
+
+#ifndef ANY_SIZE
+#define ANY_SIZE												1
+#endif	//	ANY_SIZE
+
+#define MINET_SLAVE_RESPONSE_SUCCESS							0
+#define MINET_SLAVE_RESPONSE_ACK								1
+#define MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE				2
+
+#define MINET_SLAVE_RESPONSE_ERROR_STX_ERROR					-1
+#define MINET_SLAVE_RESPONSE_ERROR_INVALID_ARGUMENT				-2
+#define MINET_SLAVE_RESPONSE_ERROR_INVALID_LENGTH				-3
+#define MINET_SLAVE_RESPONSE_ERROR_INVALID_SLAVE_INDICATOR		-4
+#define MINET_SLAVE_RESPONSE_ERROR_INCOMPLETE_DATA				-5
+#define MINET_SLAVE_RESPONSE_ERROR_INVALID_NODE_ADDRESS			-6
+#define MINET_SLAVE_RESPONSE_ERROR_INDEX_OUT_OF_RANGE			-7
+#define MINET_SLAVE_RESPONSE_ERROR_INDEX_NO_MATCH				-8
+#define MINET_SLAVE_RESPONSE_ERROR_INVALID_CHECKSUM				-9
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_MININET_FRAME
+{
+	uint8_t stx;
+	uint8_t len;
+	uint8_t node;
+	uint8_t index;
+	union
+	{
+		uint8_t		by[ANY_SIZE];
+		uint16_t	wo[ANY_SIZE];
+		uint32_t	dw[ANY_SIZE];
+	}data;
+}GFA_MININET_FRAME, *LPGFA_MININET_FRAME;
+typedef const GFA_MININET_FRAME *LPCGFA_MININET_FRAME;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef void													*HGFAMINEMST;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_MININET_MST_CFG_PARAMS
+{
+	GFA_MININET_DEV_CFG_PARAMS devcfg;
+}GFA_MININET_MST_CFG_PARAMS, *LPGFA_MININET_MST_CFG_PARAMS;
+typedef const GFA_MININET_MST_CFG_PARAMS *LPCGFA_MININET_MST_CFG_PARAMS;
+
+/////////////////////////////////////////////////////////////////////////////
+
+HGFAMINEMST	GfaMininetMasterOpen(LPGFA_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);
+ssize_t	GfaMininetMasterTransmitFrame(HGFAMINEMST hMst, const void *pData, size_t nCbData);
+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);
+
+bool	GfaMininetMasterGetTimeouts(HGFAMINEMST hMst, struct timeval *ptvRX, struct timeval *ptvTX);
+bool	GfaMininetMasterSetTimeouts(HGFAMINEMST hMst, const struct timeval *ptvRX, const struct timeval *ptvTX);
+bool	GfaMininetMasterSaveTimeouts(HGFAMINEMST hMst);
+bool	GfaMininetMasterRestoreTimeouts(HGFAMINEMST hMst);
+
+ssize_t	GfaMininetMasterGetConfigParams(HGFAMINEMST hMst, void *pDevParams, size_t nSizeDevParams);
+int		GfaMininetMasterSetConfigParams(HGFAMINEMST hMst, const void *pDevParams, size_t nSizeDevParams);
+
+void	GfaMininetMasterDumpFrame(FILE *pf, LPCGFA_MININET_FRAME pFrame);
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_GFAMININETMST_H__FE13B563_B3D5_4AA2_81FD_B74220CF2D93__INCLUDED_)

+ 738 - 0
libmininet/gfaserial.c

@@ -0,0 +1,738 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include "gfaserial.h"
+
+#define min(a, b)			(((a) < (b)) ? (a) : (b))
+
+/////////////////////////////////////////////////////////////////////////////
+// https://blog.mbedded.ninja/programming/operating-systems/linux/linux-serial-ports-using-c-cpp/#everything-is-a-file
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _GFA_SERIAL_DEVICE
+{
+	int fd;
+	char *pszDeviceName;
+	GFA_SER_CFG_PARAMS cfg;
+	struct termios tty;
+	struct termios ttySave;
+	struct timeval tvRX;
+	struct timeval tvTX;
+	struct timeval tvEcho;
+	struct timeval tvPurge;
+}GFA_SERIAL_DEVICE, *LPGFA_SERIAL_DEVICE;
+typedef const GFA_SERIAL_DEVICE *LPCGFA_SERIAL_DEVICE;
+
+/////////////////////////////////////////////////////////////////////////////
+
+static speed_t _MapBaudrate(uint32_t b)
+{
+	speed_t s;
+
+	switch(b)
+	{
+	case 0:			s = B0; break;
+	case 50:		s = B50; break;
+	case 75:		s = B75; break;
+	case 110:		s = B110; break;
+	case 134:		s = B134; break;
+	case 150:		s = B150; break;
+	case 200:		s = B200; break;
+	case 300:		s = B300; break;
+	case 600:		s = B600; break;
+	case 1200:		s = B1200; break;
+	case 1800:		s = B1800; break;
+	case 2400:		s = B2400; break;
+	case 4800:		s = B4800; break;
+	case 9600:		s = B9600; break;
+	case 19200:		s = B19200; break;
+	case 38400:		s = B38400; break;
+	case 57600:		s = B57600; break;
+	case 115200:	s = B115200; break;
+	case 230400:	s = B230400; break;
+	case 460800:	s = B460800; break;
+	case 921600:	s = B921600; break;
+	default:	    s = (speed_t)-1; break;
+	}
+
+	return s;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static void _SetDefaultTimeouts(LPGFA_SERIAL_DEVICE psd)
+{
+	if(psd)
+	{
+		psd->tvRX.tv_sec		= 0;
+		psd->tvRX.tv_usec		= 200000;
+		psd->tvTX.tv_sec		= 0;
+		psd->tvTX.tv_usec		= 100000;
+		psd->tvEcho.tv_sec		= 0;
+		psd->tvEcho.tv_usec		= 50000;
+		psd->tvPurge.tv_sec		= 0;
+		psd->tvPurge.tv_usec	= 10000;
+	}
+}
+
+static void _CopyTimeval(struct timeval *ptvTo, const struct timeval *ptvFrom)
+{
+	ptvTo->tv_sec	= ptvFrom->tv_sec;
+	ptvTo->tv_usec	= ptvFrom->tv_usec;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static bool _ReadEcho(HGFADEVICE hSer, const void *pData, size_t nWritten)
+{
+	uint8_t b[256];
+	ssize_t nRet;
+	struct timeval tvSave;
+	LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+	ssize_t nLeft = (ssize_t)nWritten, nRead = 0, nToRead;
+	const char *pszData = (const char*)pData;
+
+	if(!nLeft)
+		return false;
+	if(	!GfaSerialGetTimeouts(hSer, &tvSave, NULL) ||
+		!GfaSerialSetTimeouts(hSer, &psd->tvEcho, NULL))
+		return false;
+
+	do
+	{
+		nToRead = min(nLeft, (ssize_t)sizeof(b));
+		if((nRet = GfaSerialReceive(hSer, b, nToRead)) <= 0)
+		{
+			GfaSerialSetTimeouts(hSer, &tvSave, NULL);
+			return false;
+		}
+		if(memcmp(b, pszData, nRet))
+		{
+			GfaSerialSetTimeouts(hSer, &tvSave, NULL);
+			return false;
+		}
+		pszData += nRet;
+		nRead += nRet;
+		nLeft = (ssize_t)nWritten - nRead;
+	}
+	while(nLeft > 0);
+
+	GfaSerialSetTimeouts(hSer, &tvSave, NULL);
+	return (nRead == (ssize_t)nWritten);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+HGFADEVICE GfaSerialOpen(const char *pszDeviceName, LPCGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams)
+{
+	if(pszDeviceName && *pszDeviceName && pscp && nSizeCfgParams >= sizeof(GFA_SER_CFG_PARAMS))
+	{
+		LPGFA_SERIAL_DEVICE psd = malloc(sizeof(GFA_SERIAL_DEVICE));
+		memset(psd, 0, sizeof(GFA_SERIAL_DEVICE));
+		
+		/////////////////////////////////////////////////////////////////////
+		// Open the device
+
+		if((psd->fd = open(pszDeviceName, O_RDWR | O_NONBLOCK)) < 0)
+		{
+			GfaSerialClose(psd);
+		    return NULL;
+		}
+		
+		/////////////////////////////////////////////////////////////////////
+		// Lock device descriptor exclusive
+
+		if(flock(psd->fd, LOCK_EX | LOCK_NB) < 0)
+		{
+			GfaSerialClose(psd);
+		    return NULL;
+		}
+		
+		/////////////////////////////////////////////////////////////////////
+		// Get current config and save it for restore on close
+
+		if(tcgetattr(psd->fd, &psd->tty) != 0)
+		{
+			GfaSerialClose(psd);
+		    return NULL;
+		}
+
+		memcpy(&psd->ttySave, &psd->tty, sizeof(struct termios));
+		
+		/////////////////////////////////////////////////////////////////////
+		// Set new config
+
+		if(GfaSerialSetConfig(psd, pscp, nSizeCfgParams) < 0)
+		{
+			GfaSerialClose(psd);
+		    return NULL;
+		}
+
+		/////////////////////////////////////////////////////////////////////
+		// Set deault timeouts.
+
+		_SetDefaultTimeouts(psd);
+
+		/////////////////////////////////////////////////////////////////////
+		// Everything ok.
+
+		psd->pszDeviceName = strdup(pszDeviceName);
+		GfaSerialPurgeRXBuffer((HGFADEVICE)psd); // clear RX buffer
+		return (HGFADEVICE)psd;
+	}
+
+	errno = EINVAL;
+    return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void GfaSerialClose(HGFADEVICE hSer)
+{
+	if(hSer)
+	{
+		int nErrno = errno;
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+		if(psd->fd >= 0)
+		{
+			tcsetattr(psd->fd, TCSAFLUSH, &psd->ttySave);
+			flock(psd->fd, LOCK_UN | LOCK_NB);
+			close(psd->fd);
+		}
+		if(psd->pszDeviceName)
+			free(psd->pszDeviceName);
+		free(psd);
+		errno = nErrno;
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaSerialGetConfig(HGFADEVICE hSer, LPGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams)
+{
+	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));
+		return sizeof(GFA_SER_CFG_PARAMS);
+	}
+
+	errno = EINVAL;
+    return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GfaSerialSetConfig(HGFADEVICE hSer, LPCGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams)
+{
+	if(hSer && pscp && nSizeCfgParams >= sizeof(GFA_SER_CFG_PARAMS))
+	{
+		int nRet;
+		speed_t s;
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+
+		/////////////////////////////////////////////////////////////////////
+		// Baud Rate
+
+		if((s = _MapBaudrate(pscp->baud)) == (speed_t)-1)
+		{
+			errno = EINVAL;
+		    return -1;
+		}
+
+		if(	((nRet = cfsetispeed(&psd->tty, s)) < 0) ||
+			((nRet = cfsetospeed(&psd->tty, s)) < 0))
+		{
+		    return nRet;
+		}
+
+		/////////////////////////////////////////////////////////////////////
+		// data bits
+
+		switch(pscp->data)
+		{
+		case 5:
+			psd->tty.c_cflag &= ~CSIZE;
+			psd->tty.c_cflag |= CS5; // 5 bits per byte
+			break;
+		case 6:
+			psd->tty.c_cflag &= ~CSIZE;
+			psd->tty.c_cflag |= CS6; // 6 bits per byte
+			break;
+		case 7:
+			psd->tty.c_cflag &= ~CSIZE;
+			psd->tty.c_cflag |= CS7; // 7 bits per byte
+			break;
+		case 8:
+			psd->tty.c_cflag &= ~CSIZE;
+			psd->tty.c_cflag |= CS8; // 8 bits per byte
+			break;
+		default:
+			errno = EINVAL;
+		    return -1;
+		}
+
+		/////////////////////////////////////////////////////////////////////
+		// stop bits
+
+		switch(pscp->stop)
+		{
+		case 1:
+			psd->tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication
+			break;
+		case 2:
+			psd->tty.c_cflag |= CSTOPB;  // Set stop field, two stop bits used in communication
+			break;
+		default:
+			errno = EINVAL;
+		    return -1;
+		}
+
+		/////////////////////////////////////////////////////////////////////
+		// parity
+
+		switch(toupper(pscp->parity))
+		{
+		case 'N':
+			psd->tty.c_cflag &= ~(PARENB | PARODD);	// Clear parity bit, disabling parity
+			break;
+		case 'E':
+			psd->tty.c_cflag |= PARENB;		// Set parity bit, enabling parity
+			psd->tty.c_cflag &= ~PARODD;	// Clear odd parity bit, enabling even parity
+			break;
+		case 'O':
+			psd->tty.c_cflag |= (PARENB | PARODD);	// Set parity bits, enabling odd parity
+			break;
+		default:
+			errno = EINVAL;
+		    return -1;
+		}
+
+		/////////////////////////////////////////////////////////////////////
+		// RTS/CTS flow control
+		// If the CRTSCTS field is set, hardware RTS/CTS flow control is enabled. The most common setting here is to disable it.
+		// Enabling this when it should be disabled can result in your serial port receiving no data, as the sender will buffer
+		// it indefinitely, waiting for you to be “ready”.
+
+		if(pscp->flowHW)
+			psd->tty.c_cflag |= CRTSCTS;  // Enable RTS/CTS hardware flow control
+		else
+			psd->tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
+
+		/////////////////////////////////////////////////////////////////////
+		// Setting CLOCAL disables modem-specific signal lines such as carrier detect. It also
+		// prevents the controlling process from getting sent a SIGHUP signal when a modem disconnect
+		// is detected, which is usually a good thing here. Setting CLOCAL allows us to read data (we definitely want that!).
+
+		psd->tty.c_cflag |= (CREAD | CLOCAL); // Turn on READ & ignore ctrl lines (CLOCAL = 1)
+
+		/////////////////////////////////////////////////////////////////////
+		// UNIX systems provide two basic modes of input, canonical and non-canonical mode. In canonical mode, input is
+		// processed when a new line character is received. The receiving application receives that data line-by-line.
+		// This is usually undesirable when dealing with a serial port, and so we normally want to disable canonical mode.
+		// Also, in canonical mode, some characters such as backspace are treated specially, and are used to edit the
+		// current line of text (erase). Again, we don’t want this feature if processing raw serial data, as it will
+		// cause particular bytes to go missing!
+
+		psd->tty.c_lflag &= ~ICANON;
+
+		/////////////////////////////////////////////////////////////////////
+		// Echo
+		// If this bit is set, sent characters will be echoed back. Because we disabled canonical mode,
+		// I don’t think these bits actually do anything, but it doesn’t harm to disable them just in case!
+
+		psd->tty.c_lflag &= ~ECHO;		// Disable echo
+		psd->tty.c_lflag &= ~ECHOE;		// Disable erasure
+		psd->tty.c_lflag &= ~ECHONL;	// Disable new-line echo
+
+		/////////////////////////////////////////////////////////////////////
+		// Signal chars
+		// When the ISIG bit is set, INTR, QUIT and SUSP characters are interpreted.
+		// We don’t want this with a serial port, so clear this bit.
+
+		psd->tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
+
+		/////////////////////////////////////////////////////////////////////
+		// Software Flow Control (IXOFF, IXON, IXANY)
+		// Clearing IXOFF, IXON and IXANY disables software flow control.
+
+		if(pscp->flowSW)
+			psd->tty.c_iflag |= (IXON | IXOFF); // Turn on s/w flow ctrl
+		else
+			psd->tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
+
+		/////////////////////////////////////////////////////////////////////
+		// Disabling Special Handling Of Bytes On Receive
+		// Clearing all of the following bits disables any special handling of the bytes as they
+		// are received by the serial port, before they are passed to the application. We just want the raw data!
+
+		psd->tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes
+
+		/////////////////////////////////////////////////////////////////////
+		// When configuring a serial port, we want to disable any special handling of output chars/bytes.
+
+		psd->tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
+		psd->tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
+
+		/////////////////////////////////////////////////////////////////////
+		// VMIN and VTIME
+
+		psd->tty.c_cc[VTIME] = psd->tty.c_cc[VMIN] = 0;    // No blocking, return immediately with what is available
+
+		/////////////////////////////////////////////////////////////////////
+		// set configuration
+
+		if((nRet = tcsetattr(psd->fd, TCSAFLUSH, &psd->tty)) == 0)
+			memcpy(&psd->cfg, pscp, sizeof(GFA_SER_CFG_PARAMS));
+		return nRet;
+	}
+
+	errno = EINVAL;
+    return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaSerialGetDeviceInterface(LPGFA_GENERIC_DEVICE_INTERFACE pDevItf)
+{
+	if(pDevItf)
+	{
+		pDevItf->pfnOpen			= (PFN_GFA_GENERIC_DEV_OPEN)GfaSerialOpen;
+		pDevItf->pfnClose			= GfaSerialClose;
+		pDevItf->pfnGetConfig		= (PFN_GFA_GENERIC_DEV_GET_CONFIG)GfaSerialGetConfig;
+		pDevItf->pfnSetConfig		= (PFN_GFA_GENERIC_DEV_SET_CONFIG)GfaSerialSetConfig;
+		pDevItf->pfnGetTimeouts		= GfaSerialGetTimeouts;
+		pDevItf->pfnSetTimeouts		= GfaSerialSetTimeouts;
+		pDevItf->pfnPurgeRXBuffer	= GfaSerialPurgeRXBuffer;
+		pDevItf->pfnReceive			= GfaSerialReceive;
+		pDevItf->pfnRead			= GfaSerialRead;
+		pDevItf->pfnPop				= GfaSerialPop;
+		pDevItf->pfnPeek			= GfaSerialPeek;
+		pDevItf->pfnTransmit		= GfaSerialTransmit;
+		pDevItf->pfnWrite			= GfaSerialWrite;
+		pDevItf->pfnPush			= GfaSerialPush;
+		return true;
+	}
+
+	errno = EINVAL;
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaSerialPurgeRXBuffer(HGFADEVICE hSer)
+{
+	struct timeval tvSave;
+
+	if(hSer && GfaSerialGetTimeouts(hSer, &tvSave, NULL))
+	{
+		uint8_t b[256];
+		ssize_t nRet = 0, nRx;
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+		GfaSerialSetTimeouts(hSer, &psd->tvPurge, NULL);
+
+		while((nRx = GfaSerialReceive(hSer, b, sizeof(b))) > 0)
+			nRet += nRx;
+
+		GfaSerialSetTimeouts(hSer, &tvSave, NULL);
+		return nRet;
+	}
+
+	errno = EINVAL;
+    return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaSerialGetTimeouts(HGFADEVICE hSer, struct timeval *ptvRX, struct timeval *ptvTX)
+{
+	if(hSer && (ptvRX || ptvTX))
+	{
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+		if(ptvRX)
+			memcpy(ptvRX, &psd->tvRX, sizeof(struct timeval));
+		if(ptvTX)
+			memcpy(ptvTX, &psd->tvTX, sizeof(struct timeval));
+		return true;
+	}
+
+	errno = EINVAL;
+    return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool GfaSerialSetTimeouts(HGFADEVICE hSer, const struct timeval *ptvRX, const struct timeval *ptvTX)
+{
+	if(hSer && (ptvRX || ptvTX))
+	{
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+		if(ptvRX)
+			memcpy(&psd->tvRX, ptvRX, sizeof(struct timeval));
+		if(ptvTX)
+			memcpy(&psd->tvTX, ptvTX, sizeof(struct timeval));
+		return true;
+	}
+
+	errno = EINVAL;
+    return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaSerialTransmit(HGFADEVICE hSer, const void *pData, size_t nCbToWrite)
+{
+	if(hSer && pData && nCbToWrite)
+	{
+		fd_set fds;
+		struct timeval tv;
+		ssize_t nRet = 0;
+		ssize_t nWritten = 0;
+		const char *pszData = (const char*)pData;
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+		_CopyTimeval(&tv, &psd->tvTX);
+
+		while(nWritten < (ssize_t)nCbToWrite)
+		{
+			FD_ZERO(&fds);
+			FD_SET(psd->fd, &fds);
+
+			nRet = select(psd->fd + 1, NULL, &fds, NULL, &tv);
+
+			if(nRet < 0)
+				return -1;
+			else if(nRet == 0)
+			{
+				errno = ETIMEDOUT;
+				break;
+			}
+
+			nRet = write(psd->fd, pszData, nCbToWrite - nWritten);
+
+			if(nRet < 0)
+				return -1;
+			else if(nRet == 0)
+			{
+				// should never happen!
+				errno = ENODATA;
+				return -1;
+			}
+			else
+			{
+				if(	psd->cfg.bHandleTxEcho &&
+					!_ReadEcho(hSer, pszData, nRet))
+				{
+					GfaSerialPurgeRXBuffer(hSer);
+					errno = ECOMM;
+					return -1;
+				}
+
+				pszData += nRet;
+				nWritten += nRet;
+			}
+		}
+
+		return nWritten;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaSerialWrite(HGFADEVICE hSer, const void *pData, size_t nCbData)
+{
+	if(hSer && pData && nCbData)
+	{
+		ssize_t nRet;
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+
+		if((nRet = write(psd->fd, pData, nCbData)) > 0)
+		{
+			if(	psd->cfg.bHandleTxEcho &&
+				!_ReadEcho(hSer, pData, nRet))
+			{
+				GfaSerialPurgeRXBuffer(hSer);
+				errno = ECOMM;
+				return -1;
+			}
+		}
+
+		return nRet;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaSerialPush(HGFADEVICE hSer, uint8_t b)
+{
+	if(hSer)
+	{
+		fd_set fds;
+		struct timeval tv;
+		ssize_t nRet = 0;
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+		_CopyTimeval(&tv, &psd->tvTX);
+
+		FD_ZERO(&fds);
+		FD_SET(psd->fd, &fds);
+
+		nRet = select(psd->fd + 1, NULL, &fds, NULL, &tv);
+
+		if(nRet < 0)
+			return -1;
+		else if(nRet == 0)
+		{
+			errno = ETIMEDOUT;
+			return 0;
+		}
+
+		if((nRet = write(psd->fd, &b, 1)) == 1)
+		{
+			if(	psd->cfg.bHandleTxEcho &&
+				!_ReadEcho(hSer, &b, 1))
+			{
+				GfaSerialPurgeRXBuffer(hSer);
+				errno = ECOMM;
+				return -1;
+			}
+		}
+
+		return nRet;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaSerialReceive(HGFADEVICE hSer, void *pBuf, size_t nCbToRead)
+{
+	if(hSer && pBuf && nCbToRead)
+	{
+		fd_set fds;
+		struct timeval tv;
+		ssize_t nRet = 0;
+		ssize_t nRead = 0;
+		char *pszBuf = (char*)pBuf;
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+		_CopyTimeval(&tv, &psd->tvRX);
+
+		while(nRead < (ssize_t)nCbToRead)
+		{
+			FD_ZERO(&fds);
+			FD_SET(psd->fd, &fds);
+
+			nRet = select(psd->fd + 1, &fds, NULL, NULL, &tv);
+
+			if(nRet < 0)
+				return -1;
+			else if(nRet == 0)
+			{
+				errno = ETIMEDOUT;
+				break;
+			}
+
+			nRet = read(psd->fd, pszBuf, nCbToRead - nRead);
+
+			if(nRet < 0)
+				return -1;
+			else if(nRet == 0)
+			{
+				// should never happen!
+				errno = ENODATA;
+				return -1;
+			}
+			else
+			{
+				pszBuf += nRet;
+				nRead += nRet;
+			}
+		}
+
+		return nRead;
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaSerialRead(HGFADEVICE hSer, void *pBuf, size_t nCbToRead)
+{
+	if(hSer && pBuf && nCbToRead)
+	{
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+		return read(psd->fd, pBuf, nCbToRead);
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaSerialPop(HGFADEVICE hSer, uint8_t *pb)
+{
+	if(hSer && pb)
+	{
+		fd_set fds;
+		struct timeval tv;
+		ssize_t nRet = 0;
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+
+		FD_ZERO(&fds);
+		FD_SET(psd->fd, &fds);
+		_CopyTimeval(&tv, &psd->tvRX);
+
+		nRet = select(psd->fd + 1, &fds, NULL, NULL, &tv);
+
+		if(nRet < 0)
+			return -1;
+		else if(nRet == 0)
+		{
+			errno = ETIMEDOUT;
+			return 0;
+		}
+
+		return read(psd->fd, pb, 1);
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+ssize_t GfaSerialPeek(HGFADEVICE hSer)
+{
+	if(hSer)
+	{
+		fd_set fds;
+		struct timeval tvNull = {0, 0};
+		LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
+
+		FD_ZERO(&fds);
+		FD_SET(psd->fd, &fds);
+
+		return select(psd->fd + 1, &fds, NULL, NULL, &tvNull);
+	}
+
+	errno = EINVAL;
+	return -1;
+}

+ 57 - 0
libmininet/gfaserial.h

@@ -0,0 +1,57 @@
+// gfaserial.h :
+//
+
+#if !defined(AGD_GFASERIAL_H__8CCAB1A3_1A01_49EB_BE03_9183B29CA9F4__INCLUDED_)
+#define AGD_GFASERIAL_H__8CCAB1A3_1A01_49EB_BE03_9183B29CA9F4__INCLUDED_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/time.h>
+#include <gfagenericdev.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// gfaserial.h - Declarations:
+
+typedef struct _GFA_SER_CFG_PARAMS
+{
+	uint32_t	baud;
+	uint8_t		data;
+	uint8_t		stop;
+	uint8_t		parity;
+	bool		flowHW;
+	bool		flowSW;
+	bool		bHandleTxEcho;
+}GFA_SER_CFG_PARAMS, *LPGFA_SER_CFG_PARAMS;
+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);
+
+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);
+
+bool GfaSerialGetTimeouts(HGFADEVICE hSer, struct timeval *ptvRX, struct timeval *ptvTX);
+bool GfaSerialSetTimeouts(HGFADEVICE hSer, const struct timeval *ptvRX, const struct timeval *ptvTX);
+ssize_t GfaSerialPurgeRXBuffer(HGFADEVICE hSer);
+
+ssize_t GfaSerialReceive(HGFADEVICE hSer, void *pBuf, size_t nCbToRead); // blocking
+ssize_t GfaSerialRead(HGFADEVICE hSer, void *pBuf, size_t nCbToRead); // not blocking
+ssize_t GfaSerialPop(HGFADEVICE hSer, uint8_t *pb); // 1 byte, blocking
+ssize_t GfaSerialPeek(HGFADEVICE hSer); // not blocking
+
+ssize_t GfaSerialTransmit(HGFADEVICE hSer, const void *pData, size_t nCbData);	// blocking
+ssize_t GfaSerialWrite(HGFADEVICE hSer, const void *pData, size_t nCbData);	// not blocking
+ssize_t GfaSerialPush(HGFADEVICE hSer, uint8_t b);	// 1 byte, blocking
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_GFASERIAL_H__8CCAB1A3_1A01_49EB_BE03_9183B29CA9F4__INCLUDED_)

+ 65 - 0
libmininet/install.sh

@@ -0,0 +1,65 @@
+#!/bin/bash
+set -e
+set -o pipefail
+
+REMPWD="root"
+REMUSR="root@192.168.0.125"
+
+
+TOOLCHAIN_SYSROOT="/opt/GfA/TC_L44104_C493_QT57/usr/arm-buildroot-linux-gnueabihf/sysroot"
+LIBBASENAMEREL="gfamininet"
+LIBBASENAMEDBG="gfamininetd"
+LIBDBGx86_64SRC="Debug/Desktop_Qt_5_7_0_GCC_64bit/lib$LIBBASENAMEDBG.so.1.0.0"
+LIBRELx86_64SRC="Release/Desktop_Qt_5_7_0_GCC_64bit/lib$LIBBASENAMEREL.so.1.0.0"
+LIBDBGARMSRC="Debug/GfA_Device/lib$LIBBASENAMEDBG.so.1.0.0"
+LIBRELARMSRC="Release/GfA_Device/lib$LIBBASENAMEREL.so.1.0.0"
+
+INCSRC1="gfaserial.h"
+INCSRC2="gfamininetmst.h"
+INCSRC3="gfamininetdev.h"
+INCSRC4="gfagenericdev.h"
+INCSRC5="gfabootlmast.h"
+
+LIBDBGx86_64DST="/usr/lib/"
+LIBRELx86_64DST="/usr/lib/"
+INCDSTx86_64DST="/usr/include/"
+
+LIBDBGARMDST_LOC="$TOOLCHAIN_SYSROOT/usr/lib/"
+LIBRELARMDST_LOC="$TOOLCHAIN_SYSROOT/usr/lib/"
+INCDSTARM_LOC="$TOOLCHAIN_SYSROOT/usr/include/"
+
+sudo cp $LIBDBGx86_64SRC $LIBDBGx86_64DST
+sudo cp $LIBRELx86_64SRC $LIBRELx86_64DST
+sudo cp $INCSRC1 $INCDSTx86_64DST
+sudo cp $INCSRC2 $INCDSTx86_64DST
+sudo cp $INCSRC3 $INCDSTx86_64DST
+sudo cp $INCSRC4 $INCDSTx86_64DST
+sudo cp $INCSRC5 $INCDSTx86_64DST
+
+sudo ln -sfnr /usr/lib/lib$LIBBASENAMEDBG.so.1.0.0 /usr/lib/lib$LIBBASENAMEDBG.so.1
+sudo ln -sfnr /usr/lib/lib$LIBBASENAMEDBG.so.1 /usr/lib/lib$LIBBASENAMEDBG.so
+sudo ln -sfnr /usr/lib/lib$LIBBASENAMEREL.so.1.0.0 /usr/lib/lib$LIBBASENAMEREL.so.1
+sudo ln -sfnr /usr/lib/lib$LIBBASENAMEREL.so.1 /usr/lib/lib$LIBBASENAMEREL.so
+
+cp $LIBDBGARMSRC $LIBDBGARMDST_LOC
+cp $LIBRELARMSRC $LIBRELARMDST_LOC
+cp $INCSRC1 $INCDSTARM_LOC
+cp $INCSRC2 $INCDSTARM_LOC
+cp $INCSRC3 $INCDSTARM_LOC
+cp $INCSRC4 $INCDSTARM_LOC
+cp $INCSRC5 $INCDSTARM_LOC
+
+ln -sfnr $TOOLCHAIN_SYSROOT/usr/lib/lib$LIBBASENAMEDBG.so.1.0.0 $TOOLCHAIN_SYSROOT/usr/lib/lib$LIBBASENAMEDBG.so.1
+ln -sfnr $TOOLCHAIN_SYSROOT/usr/lib/lib$LIBBASENAMEDBG.so.1 $TOOLCHAIN_SYSROOT/usr/lib/lib$LIBBASENAMEDBG.so
+ln -sfnr $TOOLCHAIN_SYSROOT/usr/lib/lib$LIBBASENAMEREL.so.1.0.0 $TOOLCHAIN_SYSROOT/usr/lib/lib$LIBBASENAMEREL.so.1
+ln -sfnr $TOOLCHAIN_SYSROOT/usr/lib/lib$LIBBASENAMEREL.so.1 $TOOLCHAIN_SYSROOT/usr/lib/lib$LIBBASENAMEREL.so
+
+pscp -pw $REMPWD $LIBDBGARMSRC $REMUSR:/usr/lib/ > /dev/null
+pscp -pw $REMPWD $LIBRELARMSRC $REMUSR:/usr/lib/ > /dev/null
+
+plink -batch -t -pw $REMPWD $REMUSR ln -sfn /usr/lib/lib$LIBBASENAMEDBG.so.1.0.0 /usr/lib/lib$LIBBASENAMEDBG.so.1
+plink -batch -t -pw $REMPWD $REMUSR ln -sfn /usr/lib/lib$LIBBASENAMEDBG.so.1 /usr/lib/lib$LIBBASENAMEDBG.so
+plink -batch -t -pw $REMPWD $REMUSR ln -sfn /usr/lib/lib$LIBBASENAMEREL.so.1.0.0 /usr/lib/lib$LIBBASENAMEREL.so.1
+plink -batch -t -pw $REMPWD $REMUSR ln -sfn /usr/lib/lib$LIBBASENAMEREL.so.1 /usr/lib/lib$LIBBASENAMEREL.so
+
+echo Done.

+ 31 - 0
libmininet/libmininet.pro

@@ -0,0 +1,31 @@
+TEMPLATE = lib
+TARGET = gfamininet
+#CONFIG += console
+CONFIG -= app_bundle
+CONFIG -= qt
+
+CONFIG(debug, debug|release) {
+    QMAKE_CXXFLAGS -= -Os
+    QMAKE_CFLAGS -= -Os
+    QMAKE_CXXFLAGS += -D_DEBUG
+    QMAKE_CFLAGS += -D_DEBUG
+	TARGET = gfamininetd
+}
+
+SOURCES += \
+    gfaserial.c \
+    gfamininetmst.c \
+    gfamininetdev.c \
+    gfabootlmast.c
+
+linux-buildroot-g++ {
+}
+
+HEADERS += \
+    gfamininetmst.h \
+    gfamininetdev.h \
+    gfagenericdev.h \
+    gfaserial.h \
+    gfabootlmast.h
+
+QMAKE_INCDIR += ../ti

+ 242 - 0
ti/bl_commands.h

@@ -0,0 +1,242 @@
+//*****************************************************************************
+//
+// bl_commands.h - The list of commands and return messages supported by the
+//                 boot loader.
+//
+// Copyright (c) 2006-2017 Texas Instruments Incorporated.  All rights reserved.
+// Software License Agreement
+// 
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+// 
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+// 
+// This is part of revision 2.1.4.178 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_COMMANDS_H__
+#define __BL_COMMANDS_H__
+
+//*****************************************************************************
+//
+// This command is used to receive an acknowledge from the the boot loader
+// proving that communication has been established.  This command is a single
+// byte.
+//
+// The format of the command is as follows:
+//
+//     uint8_t ui8Command[1];
+//
+//     ui8Command[0] = COMMAND_PING;
+//
+//*****************************************************************************
+#define COMMAND_PING            0x20
+
+//*****************************************************************************
+//
+// This command is sent to the boot loader to indicate where to store data and
+// how many bytes will be sent by the COMMAND_SEND_DATA commands that follow.
+// The command consists of two 32-bit values that are both transferred MSB
+// first.  The first 32-bit value is the address to start programming data
+// into, while the second is the 32-bit size of the data that will be sent.
+// This command also triggers an erasure of the full application area in the
+// flash or possibly the entire flash depending on the address used.  This
+// causes the command to take longer to send the ACK/NAK in response to the
+// command.  This command should be followed by a COMMAND_GET_STATUS to ensure
+// that the program address and program size were valid for the microcontroller
+// running the boot loader.
+//
+// The format of the command is as follows:
+//
+//     uint8_t ui8Command[9];
+//
+//     ui8Command[0] = COMMAND_DOWNLOAD;
+//     ui8Command[1] = Program Address [31:24];
+//     ui8Command[2] = Program Address [23:16];
+//     ui8Command[3] = Program Address [15:8];
+//     ui8Command[4] = Program Address [7:0];
+//     ui8Command[5] = Program Size [31:24];
+//     ui8Command[6] = Program Size [23:16];
+//     ui8Command[7] = Program Size [15:8];
+//     ui8Command[8] = Program Size [7:0];
+//
+//*****************************************************************************
+#define COMMAND_DOWNLOAD        0x21
+
+//*****************************************************************************
+//
+// This command is sent to the boot loader to transfer execution control to the
+// specified address.  The command is followed by a 32-bit value, transferred
+// MSB first, that is the address to which execution control is transferred.
+//
+// The format of the command is as follows:
+//
+//     uint8_t ui8Command[5];
+//
+//     ui8Command[0] = COMMAND_RUN;
+//     ui8Command[1] = Run Address [31:24];
+//     ui8Command[2] = Run Address [23:16];
+//     ui8Command[3] = Run Address [15:8];
+//     ui8Command[4] = Run Address [7:0];
+//
+//*****************************************************************************
+#define COMMAND_RUN             0x22
+
+//*****************************************************************************
+//
+// This command returns the status of the last command that was issued.
+// Typically this command should be received after every command is sent to
+// ensure that the previous command was successful or, if unsuccessful, to
+// properly respond to a failure.  The command requires one byte in the data of
+// the packet and the boot loader should respond by sending a packet with one
+// byte of data that contains the current status code.
+//
+// The format of the command is as follows:
+//
+//     uint8_t ui8Command[1];
+//
+//     ui8Command[0] = COMMAND_GET_STATUS;
+//
+// The following are the definitions for the possible status values that can be
+// returned from the boot loader when <tt>COMMAND_GET_STATUS</tt> is sent to
+// the microcontroller.
+//
+//     COMMAND_RET_SUCCESS
+//     COMMAND_RET_UNKNOWN_CMD
+//     COMMAND_RET_INVALID_CMD
+//     COMMAND_RET_INVALID_ADD
+//     COMMAND_RET_FLASH_FAIL
+//     COMMAND_RET_CRC_FAIL
+//
+//*****************************************************************************
+#define COMMAND_GET_STATUS      0x23
+
+//*****************************************************************************
+//
+// This command should only follow a COMMAND_DOWNLOAD command or another
+// COMMAND_SEND_DATA command, if more data is needed.  Consecutive send data
+// commands automatically increment the address and continue programming from
+// the previous location.  The transfer size is limited by the size of the
+// receive buffer in the boot loader (as configured by the BUFFER_SIZE
+// parameter).  The command terminates programming once the number of bytes
+// indicated by the COMMAND_DOWNLOAD command has been received.  Each time this
+// function is called, it should be followed by a COMMAND_GET_STATUS command to
+// ensure that the data was successfully programmed into the flash.  If the
+// boot loader sends a NAK to this command, the boot loader will not increment
+// the current address to allow retransmission of the previous data.
+//
+// The format of the command is as follows:
+//
+//     uint8_t ui8Command[9];
+//
+//     ui8Command[0] = COMMAND_SEND_DATA;
+//     ui8Command[1] = Data[0];
+//     ui8Command[2] = Data[1];
+//     ui8Command[3] = Data[2];
+//     ui8Command[4] = Data[3];
+//     ui8Command[5] = Data[4];
+//     ui8Command[6] = Data[5];
+//     ui8Command[7] = Data[6];
+//     ui8Command[8] = Data[7];
+//
+//*****************************************************************************
+#define COMMAND_SEND_DATA       0x24
+
+//*****************************************************************************
+//
+// This command is used to tell the boot loader to reset.  This is used after
+// downloading a new image to the microcontroller to cause the new application
+// or the new boot loader to start from a reset.  The normal boot sequence
+// occurs and the image runs as if from a hardware reset.  It can also be used
+// to reset the boot loader if a critical error occurs and the host device
+// wants to restart communication with the boot loader.
+//
+// The format of the command is as follows:
+//
+//     uint8_t ui8Command[1];
+//
+//     ui8Command[0] = COMMAND_RESET;
+//
+// The boot loader responds with an ACK signal to the host device before
+// actually executing the software reset on the microcontroller running the
+// boot loader.  This informs the updater application that the command was
+// received successfully and the part will be reset.
+//
+//*****************************************************************************
+#define COMMAND_RESET           0x25
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that the previous command completed successful.
+//
+//*****************************************************************************
+#define COMMAND_RET_SUCCESS     0x40
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that the command sent was an unknown command.
+//
+//*****************************************************************************
+#define COMMAND_RET_UNKNOWN_CMD 0x41
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that the previous command was formatted incorrectly.
+//
+//*****************************************************************************
+#define COMMAND_RET_INVALID_CMD 0x42
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that the previous download command contained an invalid address value.
+//
+//*****************************************************************************
+#define COMMAND_RET_INVALID_ADR 0x43
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that an attempt to program or erase the flash has failed.
+//
+//*****************************************************************************
+#define COMMAND_RET_FLASH_FAIL  0x44
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that the boot loader is configured to check the embedded CRC32 in the
+// downloaded image but the check failed.  This status can only be returned
+// after the last COMMAND_SEND_DATA has been received and processed, and only
+// if CHECK_CRC is defined in the boot loader configuration.
+//
+//*****************************************************************************
+#define COMMAND_RET_CRC_FAIL    0x45
+
+//*****************************************************************************
+//
+// This is the value that is sent to acknowledge a packet.
+//
+//*****************************************************************************
+#define COMMAND_ACK             0xcc
+
+//*****************************************************************************
+//
+// This is the value that is sent to not-acknowledge a packet.
+//
+//*****************************************************************************
+#define COMMAND_NAK             0x33
+
+#endif // __BL_COMMANDS_H__