...
The block MCTC SPI Header contains the following elements:
Code Block | ||
---|---|---|
| ||
/**< SPI cyclic data header */ typedef struct { uint16_t crc_le16; /**< checksum */ uint8_t seq; /**< sequence number */ uint8_t lenData; /**< data length */ } GOAL_MI_MCTC_SPI_CYCLIC_T; |
...
For uGOAL this is determined within the SAPI module:
Code Block | ||
---|---|---|
| ||
/****************************************************************************/ /** Basic cyclic communication function * * This function initiates SPI transfer and dispatches received data to * upper layers data callback and RPC handling. * */ void sapi_loop( void ) { /* update frame header */ sapi_pdUpdateHeader(sendData, GOAL_MI_MCTC_LEN - sizeof(GOAL_MI_MCTC_SPI_CYCLIC_T)); /* transfer data via SPI */ plat_spiTransfer((const char *) &sendData[0], (char *) receiveData, BUF_LENGTH); /* control LED if Connection valid or Wink active */ if (true == sapi_pdCheckHeader(receiveData, GOAL_MI_MCTC_LEN - sizeof(GOAL_MI_MCTC_SPI_CYCLIC_T))) { /* inform application */ som_dataCb(&receiveData[0], &sendData[0]); /* trigger RPC */ goal_miMctcDmCbRead(); } } |
...
For GOAL based applications this can be determined in the function goal_miMctcSpiProcessTask within the goal_mi_mctc_spi.c module:
Code Block | ||
---|---|---|
| ||
do { /* check frame CRC */ res = goal_miMctcCrc(&pBufSpi[sizeof(GOAL_MI_MCTC_SPI_CYCLIC_T)], pHdr->lenData, GOAL_le16toh_p(&pHdr->crc_le16)); if (GOAL_RES_ERR(res)) { break; } /* check sequence counter */ if (pMiMctcSpi->seqCyclicRem != pHdr->seq) { /* inform MI MCTC that connection is running */ goal_miMctcMonitorRx(pMiMctc, GOAL_TRUE); /* re-arm watchdog */ pMiMctcSpi->tsTout = tsNow + pMiMctc->cfgToutValue; /* update seen sequence */ pMiMctcSpi->seqCyclicRem = pHdr->seq; } if (pHdr->lenData) { /* process MI DM incoming data */ goal_miDmReadSync(pMiMctcSpi->pMiDmRead, &pBufSpi[sizeof(GOAL_MI_MCTC_SPI_CYCLIC_T)]); } } while (0); |
...
Following code shows the state machine in exceprts:
Code Block | ||
---|---|---|
| ||
/****************************************************************************/ /** MCTC MI - RPC Sync Loop */ void goal_miMctcRpcSyncLoop( MCTC_INST_T *pMiMctc /**< MI MCTC handle */ ) { GOAL_STATUS_T res = GOAL_OK; /* result */ GOAL_BOOL_T flgSetupLocal = GOAL_FALSE; /* local setup done flag */ GOAL_BOOL_T flgSetupRemote = GOAL_FALSE; /* remote setup done flag */ GOAL_MCTC_T *pHdlMctcTx = NULL; /* call handle */ /* leave if not in sync-mode */ if ((GOAL_MI_MCTC_RPC_STATE_RUN == pMiMctc->stateRpc) || (GOAL_MI_MCTC_RPC_STATE_STOP == pMiMctc->stateRpc)) { return; } /* check if send is permitted */ if (GOAL_TRUE != goal_miMctcRpcSendAllow(pMiMctc)) { return; } /* handle state machine */ switch (pMiMctc->stateRpc) { case GOAL_MI_MCTC_RPC_STATE_RUN_ONCE: /* .... */ break; /* initialize synchronisation */ case GOAL_MI_MCTC_RPC_STATE_SYNC_INIT: goal_logDbg("state: SYNC_INIT"); /* reset sync state */ GOAL_MASK_SET(pMiMctc->flgRpc, GOAL_MI_MCTC_RPC_FLG_SYNC_REQ); GOAL_MASK_CLR(pMiMctc->flgRpc, GOAL_MI_MCTC_RPC_FLG_SYNC_ACK); pMiMctc->seqRpcLocal = 0; pMiMctc->seqRpcLocalAck = 0; pMiMctc->seqRpcRemoteAck = 0; pMiMctc->stateRpc = GOAL_MI_MCTC_RPC_STATE_SYNC_REQ; /* intended fallthrough */ GOAL_TARGET_FALLTHROUGH; /* request synchronisation from partner */ case GOAL_MI_MCTC_RPC_STATE_SYNC_REQ: goal_logDbg("state: SYNC_REQ"); /* send RPC sync frame until ACK is received */ if (!(GOAL_MI_MCTC_RPC_FLG_SYNC_ACK & pMiMctc->flgRpcRemote)) { /* send sync request frame */ goal_miMctcRpcSend(pMiMctc, NULL, 0); break; } /* request acknowledge of first sequence */ GOAL_MASK_CLR(pMiMctc->flgRpc, GOAL_MI_MCTC_RPC_FLG_SYNC_REQ); GOAL_MASK_SET(pMiMctc->flgRpc, GOAL_MI_MCTC_RPC_FLG_REQ_ACK); pMiMctc->seqRpcLocal = 1; pMiMctc->stateRpc = GOAL_MI_MCTC_RPC_STATE_SYNC_ACK_LOCAL; /* intended fallthrough */ GOAL_TARGET_FALLTHROUGH; case GOAL_MI_MCTC_RPC_STATE_SYNC_ACK_LOCAL: goal_logDbg("state: SYNC_ACK_LOCAL"); /* send empty sequence 1 until ACK is received and we confirmed remote sequence */ if (1 != pMiMctc->seqRpcLocalAck) { /* send empty RPC request */ goal_miMctcRpcSend(pMiMctc, NULL, 0); break; } /* wait for remote sync */ pMiMctc->stateRpc = GOAL_MI_MCTC_RPC_STATE_SYNC_ACK_REMOTE; break; case GOAL_MI_MCTC_RPC_STATE_SYNC_ACK_REMOTE: goal_logDbg("state: SYNC_ACK_REMOTE"); if (0 == pMiMctc->seqRpcRemoteAck) { /* send empty RPC request */ goal_miMctcRpcSend(pMiMctc, NULL, 0); break; } /* enter run mode */ GOAL_MASK_CLR(pMiMctc->flgRpc, GOAL_MI_MCTC_RPC_FLG_REQ_ACK); pMiMctc->stateRpc = GOAL_MI_MCTC_RPC_STATE_RUN_ONCE; break; } } |
...
For uGOAL application, the following defines need to be set in goal_config.h:
Code Block | ||
---|---|---|
| ||
/* for debugging purpose disable any timeout detection on the peer */ #define CONFIG_UGOAL_TIMEOUT_RPC 0 #define CONFIG_UGOAL_TIMEOUT_MEDIA 0 |
...
For GOAL based application, following code needs to be called before any other functions. So best place the following calls in appl_init():
Code Block | ||
---|---|---|
| ||
#include <goal_media/goal_mi_mctc_spi.h> /****************************************************************************/ /** Application Init * * Build up the device structure and initialize the Profinet stack. */ GOAL_STATUS_T appl_init( void ) { GOAL_STATUS_T res = GOAL_OK; /* result */ /* disable media and RPC timeout */ goal_miMctcCfgTout(0); goal_miMctcSpiCfgTout(0); /* initialize DD */ res = goal_ddInit(); if (GOAL_RES_ERR(res)) { goal_logErr("Initialization of DD failed"); } /* ..... */ } |
...