12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <malloc.h>
- #include <time.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <termios.h>
- #include <unistd.h>
- #include <ctype.h>
- #include <sys/file.h>
- #include "gfamininetmst.h"
- #include "dbghlp.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 MAX_DATA_PAYLOAD_LENGTH 250
- #define MAX_SAVE_TIMOUT_DEPTH 8
- #define _TRACE_UNEXPECTED 1
- /////////////////////////////////////////////////////////////////////////////
- typedef enum _GfaMininetRxStates
- {
- GfaRxMNS_Stx,
- GfaRxMNS_Len,
- GfaRxMNS_Node,
- GfaRxMNS_Index,
- GfaRxMNS_Data,
- GfaRxMNS_Zero,
- GfaRxMNS_Check
- }GfaMininetRxStates, *LPGfaMininetRxStates;
- #if _TRACE_UNEXPECTED
- static const char *g_pszExpected[] =
- {
- "STX or ACK",
- "Length (>= 5)",
- "Node Addr.",
- "Index (< 0x3F)",
- "Data",
- "STX-Zero",
- "CRC32"
- };
- #define TRACE_UNEXPECTED(p, s, b) if(p->nVerbosity >= 4) \
- fprintf(p->pDumpCtx, "%s: Expected: %s - Received: 0x%02hhX\n", __FUNCTION__, g_pszExpected[s], b)
- #else // _TRACE_UNEXPECTED
- #define TRACE_UNEXPECTED(p, s, b) (void)0
- #endif // _TRACE_UNEXPECTED
- /////////////////////////////////////////////////////////////////////////////
- typedef struct _GFA_MININET_MASTER
- {
- HMINETDEV hDev;
- struct timeval tvRXSave[MAX_SAVE_TIMOUT_DEPTH];
- struct timeval tvTXSave[MAX_SAVE_TIMOUT_DEPTH];
- struct timespec tsStart;
- int nVerbosity;
- int nSaveToIndex;
- FILE *pDumpCtx;
- uint8_t nIndexTable[256];
- }GFA_MININET_MASTER, *LPGFA_MININET_MASTER;
- typedef const GFA_MININET_MASTER *LPCGFA_MININET_MASTER;
- /////////////////////////////////////////////////////////////////////////////
- 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;
- }
- /////////////////////////////////////////////////////////////////////////////
- static int _CountStxBytes(const void *pData, size_t nCbData)
- {
- int nStx = 0;
- const uint8_t *pbData = (const uint8_t*)pData;
- uint8_t b, n = 0;
- while(nCbData > 0)
- {
- b = *pbData++;
- if((n == STX) && (b == 0))
- {
- ++nStx;
- ++nCbData;
- }
- n = b;
-
- --nCbData;
- }
- return nStx;
- }
- /////////////////////////////////////////////////////////////////////////////
- HGFAMINEMST GfaMininetMasterOpen(LPCGFA_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;
- pMst->pDumpCtx = stdout;
- clock_gettime(CLOCK_MONOTONIC, &pMst->tsStart);
- 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;
- if(pMst->nSaveToIndex < MAX_SAVE_TIMOUT_DEPTH)
- {
- int nIndex = pMst->nSaveToIndex++;
- return GfaMininetMasterGetTimeouts(hMst, &pMst->tvRXSave[nIndex], &pMst->tvTXSave[nIndex]);
- }
- else
- {
- errno = EPERM;
- return false;
- }
- }
- errno = EINVAL;
- return false;
- }
- /////////////////////////////////////////////////////////////////////////////
- bool GfaMininetMasterRestoreTimeouts(HGFAMINEMST hMst)
- {
- if(hMst)
- {
- LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
- if(pMst->nSaveToIndex > 0)
- {
- int nIndex = --pMst->nSaveToIndex;
- return GfaMininetMasterSetTimeouts(hMst, &pMst->tvRXSave[nIndex], &pMst->tvTXSave[nIndex]);
- }
- else
- {
- errno = EPERM;
- return false;
- }
- }
- 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;
- }
- /////////////////////////////////////////////////////////////////////////////
- bool GfaMininetMasterIsValidBaudrate(HGFAMINEMST hMst, uint32_t nBaudrate)
- {
- if(hMst)
- {
- LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
- return GfaMininetDeviceIsValidBaudrate(pMst->hDev, nBaudrate);
- }
- errno = EINVAL;
- return false;
- }
- /////////////////////////////////////////////////////////////////////////////
- int GfaMininetMasterGetBaudrate(HGFAMINEMST hMst, uint32_t *pnBaudrate)
- {
- if(hMst)
- {
- LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
- return GfaMininetDeviceGetBaudrate(pMst->hDev, pnBaudrate);
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- int GfaMininetMasterSetBaudrate(HGFAMINEMST hMst, uint32_t nBaudrate)
- {
- if(hMst)
- {
- LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
- return GfaMininetDeviceSetBaudrate(pMst->hDev, nBaudrate);
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- HMINETDEV GfaMininetMasterGetDeviceHandle(HGFAMINEMST hMst)
- {
- if(hMst)
- {
- LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
- return pMst->hDev;
- }
- errno = EINVAL;
- return NULL;
- }
- /////////////////////////////////////////////////////////////////////////////
- uint8_t GfaMininetMasterCalcChk(const void *pData, size_t nCbData, bool bProcessSTX)
- {
- size_t i = 0;
- uint16_t chk = 0;
- 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(bProcessSTX && (i > 3))
- 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, true);
- ++nLen;
- return nLen;
- }
- errno = EINVAL;
- return 0;
- }
- /////////////////////////////////////////////////////////////////////////////
- int GfaMininetMasterResetSlaveIndex(HGFAMINEMST hMst, uint8_t nNode)
- {
- if(hMst)
- {
- LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
- ssize_t nLen, nRet;
- uint8_t nIndex;
- uint8_t txb[16];
- uint8_t rxb[16];
- nLen = GfaMininetMasterBuildFrame(hMst, nNode, RESET_INDEX, "\x1b\x52", 2, txb, sizeof(txb));
- if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) != nLen)
- {
- GfaMininetDevicePurgeRXBuffer(pMst->hDev);
- return -1;
- }
- if(!NODE_IS_BROADCAST(nNode) && !NODE_IS_GROUPCAST(nNode))
- {
- // we expect a response
- if((nRet = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), false)) <= 0)
- return -1;
- if((nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, nNode, rxb, nRet, false, &nIndex)) == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
- {
- if(nIndex == MINET_SLAVE_STATUS_INDEX_RESET_DONE)
- return GfaMininetMasterResetLocalIndex(hMst, nNode);
- else
- {
- errno = nIndex;
- nRet = -1;
- }
- }
- else
- {
- errno = EPROTO;
- nRet = -1;
- }
- }
- else
- {
- // we don't expect a response. so let's just hope that all slaves have received the request and have performed an index reset!
- return GfaMininetMasterResetLocalIndex(hMst, nNode);
- }
- return nRet;
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- int 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 GfaMininetMasterPurgeDeviceRXBuffer(HGFAMINEMST hMst)
- {
- if(hMst)
- {
- LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
- return GfaMininetDevicePurgeRXBuffer(pMst->hDev);
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- int GfaMininetMasterPingSlave(HGFAMINEMST hMst, uint8_t nNode)
- {
- if(hMst)
- {
- uint8_t nIndex;
- ssize_t nRet, nLen;
- char txb[32], rxb[32];
- nLen = GfaMininetMasterBuildFrame(hMst, nNode, 0, NULL, 0, txb, sizeof(txb));
- if((nRet = GfaMininetMasterTransmitFrame(hMst, txb, nLen)) < nLen)
- return -1;
- if((nLen = GfaMininetMasterReceiveFrame(hMst, rxb, sizeof(rxb), true)) <= 0)
- return -1;
- nRet = GfaMininetMasterEvaluateSlaveResponse(hMst, nNode, rxb, nLen, true, &nIndex);
- if(nRet == MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE)
- {
- if(nIndex == MINET_SLAVE_STATUS_INDEX_INVALID_PARAM)
- return 0;
- else
- {
- errno = -(int)nIndex;
- return -1;
- }
- }
- return -1;
- }
- 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)
- {
- bool bIsStatusIndex = false;
- LPCGFA_MININET_FRAME pf = (LPCGFA_MININET_FRAME)pFrame;
- /////////////////////////////////////////////////////////////////////
- if(nCbFrame == 0)
- {
- errno = MINET_SLAVE_RESPONSE_ERROR_INVALID_LENGTH;
- return -1;
- }
- else 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 MINET_SLAVE_STATUS_INDEX_RESET_DONE:
- case MINET_SLAVE_STATUS_INDEX_ERROR:
- case MINET_SLAVE_STATUS_INDEX_CMD_ERROR:
- case MINET_SLAVE_STATUS_INDEX_INVALID_PARAM:
- case MINET_SLAVE_STATUS_INDEX_UNKNOWN_CMD:
- case MINET_SLAVE_STATUS_INDEX_CMD_ALREADY_EX:
- bIsStatusIndex = true;
- break;
- default:
- 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, false))
- {
- errno = MINET_SLAVE_RESPONSE_ERROR_INVALID_CHECKSUM;
- return -1;
- }
- else
- {
- return bIsStatusIndex ? MINET_SLAVE_RESPONSE_INDEX_IS_STATUS_CODE : MINET_SLAVE_RESPONSE_SUCCESS;
- }
- }
- }
- errno = EINVAL;
- 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;
- GfaMininetMasterDumpFrame(hMst, pMst->pDumpCtx, (LPCGFA_MININET_FRAME)pData, true, NULL);
- 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;
- GfaMininetMasterDumpFrame(hMst, pMst->pDumpCtx, (LPCGFA_MININET_FRAME)pBuffer, false, NULL);
- break;
- }
- else
- {
- TRACE_UNEXPECTED(pMst, nState, b);
- }
- 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)
- {
- TRACE_UNEXPECTED(pMst, nState, b);
- 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)
- {
- TRACE_UNEXPECTED(pMst, nState, b);
- 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)
- {
- TRACE_UNEXPECTED(pMst, nState, b);
- nState = GfaRxMNS_Len;
- continue;
- }
- else if(b < MIN_INDEX)
- {
- TRACE_UNEXPECTED(pMst, nState, b);
- 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)
- {
- TRACE_UNEXPECTED(pMst, nState, b);
- nCbDataPayloadRcv = nCbDataPayloadExp = 0;
- nState = GfaRxMNS_Len;
- continue;
- }
- else if(b >= 5)
- {
- TRACE_UNEXPECTED(pMst, nState, b);
- pFrameRx->len = b;
- nCbDataPayloadRcv = 0;
- nCbDataPayloadExp = b - 5;
- nState = GfaRxMNS_Node;
- continue;
- }
- else
- {
- TRACE_UNEXPECTED(pMst, nState, b);
- 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)
- {
- TRACE_UNEXPECTED(pMst, nState, b);
- nCbDataPayloadRcv = nCbDataPayloadExp = 0;
- nState = GfaRxMNS_Len;
- continue;
- }
- c = GfaMininetMasterCalcChk(pFrameRx, pFrameRx->len - 1, false);
- if(b == c)
- {
- if((size_t)pFrameRx->len <= nCbBuffer)
- {
- pFrameRx->data.by[nCbDataPayloadRcv] = b;
- nRet = pFrameRx->len;
- memcpy(pBuffer, pFrameRx, nRet);
- GfaMininetMasterDumpFrame(hMst, pMst->pDumpCtx, (LPCGFA_MININET_FRAME)pFrameRx, false, NULL);
- }
- else
- {
- errno = ENOMEM;
- nRet = -1;
- }
- }
- else
- {
- pFrameRx->data.by[nCbDataPayloadRcv] = b;
- GfaMininetMasterDumpFrame(hMst, pMst->pDumpCtx, (LPCGFA_MININET_FRAME)pFrameRx, false, "CRC32!!!");
- errno = EPROTO;
- nRet = -1;
- }
- bLoop = false;
- break;
- ////////////////////////////////////////////////////////////////////////
- default:
- nRet = -1;
- bLoop = false;
- break;
- }
- }
- while(bLoop);
- return nRet;
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaMininetMasterGetDataFromFrame(const void *pFrame, size_t nCbFrame, void *pData, size_t nCbData)
- {
- if(pFrame && (nCbFrame >= 5) && pData && (nCbData > 0))
- {
- LPCGFA_MININET_FRAME pf = (LPCGFA_MININET_FRAME)pFrame;
- if(pf->len == 5)
- return 0; // no data
- else if(pf->len > 5)
- {
- if(nCbFrame >= pf->len)
- {
- size_t nDatalen = (size_t)pf->len - 5;
- if(nDatalen <= nCbData)
- {
- memcpy(pData, pf->data.by, nDatalen);
- return (ssize_t)nDatalen;
- }
- else
- {
- errno = ENOMEM;
- return -1;
- }
- }
- }
- else
- {
- errno = EPROTO;
- return -1;
- }
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaMininetMasterGetDataFromSlaveFrame(const void *pFrame, size_t nCbFrame, void *pData, size_t nCbData)
- {
- uint8_t data[256];
- ssize_t nRet = GfaMininetMasterGetDataFromFrame(pFrame, nCbFrame, data, sizeof(data));
- if(nRet > 0)
- {
- if(data[0] == SLAVE_IND)
- {
- if(--nRet <= (ssize_t)nCbData)
- {
- if(nRet > 0)
- memcpy(pData, &data[1], nRet);
- }
- else
- {
- errno = ENOMEM;
- nRet = -1;
- }
- }
- else
- {
- errno = EPROTO;
- nRet = -1;
- }
- }
- return nRet;
- }
- /////////////////////////////////////////////////////////////////////////////
- void GfaMininetMasterDumpFrame(HGFAMINEMST hMst, FILE *pf, LPCGFA_MININET_FRAME pFrame, bool bTX, const char *pszAnnotation)
- {
- if(hMst && pf)
- {
- LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
- if(pMst->nVerbosity >= 4)
- {
- struct timespec tsCur, tsIntv;
- clock_gettime(CLOCK_MONOTONIC, &tsCur);
- uint64_t nInterval = TimespecDiff(&tsCur, &pMst->tsStart);
- Ns2Timespec(nInterval, &tsIntv);
- if(pFrame)
- {
- if(pFrame->stx == ACK)
- {
- fprintf(pf, "\n///////////////////////////////////////\n");
- fprintf(pf, "// %ld.%03ld\n", tsIntv.tv_sec, tsIntv.tv_nsec / 1000000);
- fprintf(pf, "// %s:\n", bTX ? "TX" : "RX");
- fprintf(pf, "ACK: 06 (6)\n");
- }
- else if(pFrame->len >= 5)
- {
- int i, nCbData = pFrame->len - 5;
- fprintf(pf, "\n///////////////////////////////////////\n");
- fprintf(pf, "// %ld.%03ld\n", tsIntv.tv_sec, tsIntv.tv_nsec / 1000000);
- fprintf(pf, "// %s:\n", bTX ? "TX" : "RX");
- fprintf(pf, "STX: %02hhX (%hhu)\n", pFrame->stx, pFrame->stx);
- fprintf(pf, "Length: %02hhX (%hhu)\n", pFrame->len, pFrame->len);
- fprintf(pf, "Node: %02hhX (%hhu)\n", pFrame->node, pFrame->node);
- fprintf(pf, "Index: %02hhX (%hhu)\n", pFrame->index, pFrame->index);
- fprintf(pf, "Data: ");
- nCbData += _CountStxBytes(pFrame->data.by, nCbData);
- for(i = 0; i < nCbData; i++)
- {
- if((i < 2) && (pFrame->data.by[i] >= 0x41) && (pFrame->data.by[i] <= 0x5A))
- fprintf(pf, "<%c>", (char)pFrame->data.by[i]);
- else
- fprintf(pf, "[%02hhX]", (char)pFrame->data.by[i]);
- }
- fprintf(pf, "\nCRC: %02hhX (%hhu)\n", pFrame->data.by[i], pFrame->data.by[i]);
- if(pszAnnotation)
- fprintf(pf, "Annot.: %s\n", pszAnnotation);
- }
- }
- else
- {
- fprintf(pf, "\n///////////////////////////////////////\n");
- fprintf(pf, "// %ld:%03ld\n", tsIntv.tv_sec, tsIntv.tv_nsec / 1000000);
- fprintf(pf, "// %s:\n", bTX ? "TX" : "RX");
- fprintf(pf, "Invalid Mininet-Frame!\n");
- }
- fprintf(pf, "\n");
- fflush(pf);
- }
- }
- }
- /////////////////////////////////////////////////////////////////////////////
- int GfaMininetMasterSetVerbosity(HGFAMINEMST hMst, int nVerbosity)
- {
- if(hMst)
- {
- LPGFA_MININET_MASTER pMst = (LPGFA_MININET_MASTER)hMst;
- if(nVerbosity < 0)
- nVerbosity = 0;
- else if(nVerbosity > 4)
- nVerbosity = 4;
- pMst->nVerbosity = nVerbosity;
- return 0;
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- const char* GfaMininetMasterStrError(int nErrorCode)
- {
- switch(nErrorCode)
- {
- case MINET_SLAVE_RESPONSE_ERROR_STX_ERROR:
- return "First byte in Mininet Frame is neither STX nor ACK";
- case MINET_SLAVE_RESPONSE_ERROR_INVALID_ARGUMENT:
- return "An invalid argument was passed to GfaMininetMasterEvaluateSlaveResponse";
- case MINET_SLAVE_RESPONSE_ERROR_INVALID_LENGTH:
- return "Invalid Mininet Frame length";
- case MINET_SLAVE_RESPONSE_ERROR_INVALID_SLAVE_INDICATOR:
- return "Invalid Mininet slave indicator";
- case MINET_SLAVE_RESPONSE_ERROR_INCOMPLETE_DATA:
- return "Not enough data for Mininet Frame";
- case MINET_SLAVE_RESPONSE_ERROR_INVALID_NODE_ADDRESS:
- return "Invalid Mininet Node address";
- case MINET_SLAVE_RESPONSE_ERROR_INDEX_OUT_OF_RANGE:
- return "Mininet Index out of range";
- case MINET_SLAVE_RESPONSE_ERROR_INDEX_NO_MATCH:
- return "Mininet Index no match";
- case MINET_SLAVE_RESPONSE_ERROR_INVALID_CHECKSUM:
- return "Mininet Checksum error";
- case -MINET_SLAVE_STATUS_INDEX_RESET_DONE:
- return "Mininet index reset done";
- case -MINET_SLAVE_STATUS_INDEX_ERROR:
- return "Mininet index error";
- case -MINET_SLAVE_STATUS_INDEX_CMD_ERROR:
- return "Mininet command error";
- case -MINET_SLAVE_STATUS_INDEX_INVALID_PARAM:
- return "Mininet invalid parameter";
- case -MINET_SLAVE_STATUS_INDEX_UNKNOWN_CMD:
- return "Mininet unknown command";
- case -MINET_SLAVE_STATUS_INDEX_CMD_ALREADY_EX:
- return "Mininet command alearx executing";
- default:
- return strerror(nErrorCode);
- }
- }
|