//------------------------------------------------------------------------------ static BOOL processCnStateChange(tNmtState newNmtState_p, tOplkError* pRet_p) { tOplkError ret = kErrorOk; BOOL fHandled = TRUE; UINT32 basicEthernetTimeout; tObdSize obdSize; switch (newNmtState_p) { // node listens for POWERLINK frames and check timeout case kNmtCsNotActive: // create timer to switch automatically to BasicEthernet if no MN // is available in the network // read NMT_CNBasicEthernetTimeout_U32 from OD obdSize = sizeof(basicEthernetTimeout); ret = obd_readEntry(0x1F99, 0x00, &basicEthernetTimeout, &obdSize); if (ret != kErrorOk) break; if (basicEthernetTimeout != 0) { // BasicEthernet is enabled ret = setupNmtTimerEvent(basicEthernetTimeout, kNmtEventTimerBasicEthernet); // potential error is forwarded to event queue which generates error event } break; // node processes only async frames case kNmtCsPreOperational1: break; // node processes isochronous and asynchronous frames case kNmtCsPreOperational2: ret = nmtu_postNmtEvent(kNmtEventEnterReadyToOperate); break; // node should be configured and application is ready case kNmtCsReadyToOperate: break; // normal work state case kNmtCsOperational: break; // node stopped by MN // -> only process asynchronous frames case kNmtCsStopped: break; // no POWERLINK cycle // -> normal ethernet communication case kNmtCsBasicEthernet: break; default: fHandled = FALSE; break; } *pRet_p = ret; return fHandled; }
//------------------------------------------------------------------------------ static BOOL processMnStateChange(tNmtState newNmtState_p, tOplkError* pRet_p) { tOplkError ret = kErrorOk; BOOL fHandled = TRUE; UINT32 waitTime; UINT32 startUp; tNmtEvent timerEvent = kNmtEventTimerMsPreOp1; tObdSize obdSize; switch (newNmtState_p) { // node listens for POWERLINK frames and check timeout case kNmtMsNotActive: // create timer to switch automatically to BasicEthernet/PreOp1 if no other MN active in network // check NMT_StartUp_U32.Bit13 obdSize = sizeof(startUp); ret = obd_readEntry(0x1F80, 0x00, &startUp, &obdSize); if (ret != kErrorOk) break; if ((startUp & NMT_STARTUP_BASICETHERNET) != 0) { // NMT_StartUp_U32.Bit13 == 1 -> new state BasicEthernet timerEvent = kNmtEventTimerBasicEthernet; } // intentional fall through case kNmtRmsNotActive: // read NMT_BootTime_REC.MNWaitNotAct_U32 from OD obdSize = sizeof(waitTime); ret = obd_readEntry(0x1F89, 0x01, &waitTime, &obdSize); if (ret != kErrorOk) break; ret = setupNmtTimerEvent(waitTime, timerEvent); // potential error is forwarded to event queue which generates error event break; // node processes only async frames case kNmtMsPreOperational1: // create timer to switch automatically to PreOp2 if MN identified all mandatory CNs // read NMT_BootTime_REC.MNWaitPreOp1_U32 from OD obdSize = sizeof(waitTime); ret = obd_readEntry(0x1F89, 0x03, &waitTime, &obdSize); if (ret != kErrorOk) { // ignore error, because this timeout is optional waitTime = 0; } if (waitTime == 0) { // delay is deactivated, immediately post timer event ret = nmtu_postNmtEvent(kNmtEventTimerMsPreOp2); } else { ret = setupNmtTimerEvent(waitTime, kNmtEventTimerMsPreOp2); } // potential error is forwarded to event queue which generates error event break; // node processes isochronous and asynchronous frames case kNmtMsPreOperational2: break; // node should be configured and application is ready case kNmtMsReadyToOperate: break; // normal work state case kNmtMsOperational: break; // no POWERLINK cycle // -> normal ethernet communication case kNmtMsBasicEthernet: break; default: fHandled = FALSE; break; } *pRet_p = ret; return fHandled; }
//------------------------------------------------------------------------------ static tOplkError configureDll(void) { tOplkError ret = kErrorOk; UINT32 nodeCfg; tObdSize obdSize; tDllNodeInfo dllNodeInfo; UINT index; UINT8 count; // read number of nodes from object 0x1F81/0 obdSize = sizeof(count); ret = obd_readEntry(0x1F81, 0, &count, &obdSize); if ((ret == kErrorObdIndexNotExist) || (ret == kErrorObdSubindexNotExist)) { return kErrorOk; } else if (ret != kErrorOk) { return ret; } for (index = 1; index <= count; index++) { obdSize = sizeof(nodeCfg); ret = obd_readEntry(0x1F81, index, &nodeCfg, &obdSize); if (ret == kErrorObdSubindexNotExist) { // not all subindexes of object 0x1F81 have to exist continue; } else if (ret != kErrorOk) { return ret; } if ((nodeCfg & (NMT_NODEASSIGN_NODE_EXISTS | NMT_NODEASSIGN_ASYNCONLY_NODE)) == NMT_NODEASSIGN_NODE_EXISTS) { // node exists and runs in isochronous phase dllNodeInfo.nodeId = index; obdSize = sizeof(dllNodeInfo.presPayloadLimit); ret = obd_readEntry(0x1F8D, index, &dllNodeInfo.presPayloadLimit, &obdSize); if ((ret == kErrorObdIndexNotExist) || (ret == kErrorObdSubindexNotExist)) { dllNodeInfo.presPayloadLimit = 0; } else if (ret != kErrorOk) { return ret; } #if defined(CONFIG_INCLUDE_NMT_MN) if ((nodeCfg & (NMT_NODEASSIGN_NODE_IS_CN | NMT_NODEASSIGN_PRES_CHAINING)) == NMT_NODEASSIGN_NODE_IS_CN) { // node is CN obdSize = sizeof(dllNodeInfo.preqPayloadLimit); ret = obd_readEntry(0x1F8B, index, &dllNodeInfo.preqPayloadLimit, &obdSize); if (ret != kErrorOk) return ret; obdSize = sizeof(dllNodeInfo.presTimeoutNs); ret = obd_readEntry(0x1F92, index, &dllNodeInfo.presTimeoutNs, &obdSize); if (ret != kErrorOk) return ret; } else { dllNodeInfo.presTimeoutNs = 0; dllNodeInfo.preqPayloadLimit = 0; } #endif // if defined(INCLUDE_CONFIG_NMT_MN) ret = dllucal_configNode(&dllNodeInfo); if (ret != kErrorOk) return ret; } } return ret; }
//------------------------------------------------------------------------------ static BOOL processGeneralStateChange(tNmtState newNmtState_p, tOplkError* pRet_p) { tOplkError ret = kErrorOk; UINT nodeId; BOOL fHandled = TRUE; #if defined(CONFIG_INCLUDE_NMT_RMN) UINT32 startUp; tObdSize obdSize; #endif switch (newNmtState_p) { // POWERLINK stack is not running case kNmtGsOff: break; // first init of the hardware case kNmtGsInitialising: ret = nmtu_postNmtEvent(kNmtEventEnterResetApp); break; // init of the manufacturer-specific profile area and the // standardised device profile area case kNmtGsResetApplication: ret = nmtu_postNmtEvent(kNmtEventEnterResetCom); break; // init of the communication profile area case kNmtGsResetCommunication: ret = nmtu_postNmtEvent(kNmtEventEnterResetConfig); break; // build the configuration with infos from OD case kNmtGsResetConfiguration: #if NMT_MAX_NODE_ID > 0 // configure the DLL (PReq/PRes payload limits and PRes timeout) ret = configureDll(); if (ret != kErrorOk) { break; } #endif // NMT_MAX_NODE_ID > 0 #if defined(CONFIG_INCLUDE_NMT_RMN) obdSize = sizeof(startUp); ret = obd_readEntry(0x1F80, 0x00, &startUp, &obdSize); if (ret != kErrorOk) break; if ((startUp & NMT_STARTUP_REDUNDANCY) != 0) { // NMT_StartUp_U32.Bit14 == 1 ret = nmtu_postNmtEvent(kNmtEventEnterRmsNotActive); break; } #endif // get node ID from OD nodeId = obd_getNodeId(); //check node ID if not should be master or slave if (nodeId == C_ADR_MN_DEF_NODE_ID) { // node shall be MN #if defined(CONFIG_INCLUDE_NMT_MN) ret = nmtu_postNmtEvent(kNmtEventEnterMsNotActive); #else DEBUG_LVL_ERROR_TRACE("processGeneralStateChange(): no MN functionality implemented\n"); #endif } else { // node shall be CN ret = nmtu_postNmtEvent(kNmtEventEnterCsNotActive); } break; default: fHandled = FALSE; break; } *pRet_p = ret; return fHandled; }
//------------------------------------------------------------------------------ tOplkError cfmu_processNodeEvent(UINT nodeId_p, tNmtNodeEvent nodeEvent_p, tNmtState nmtState_p) { tOplkError ret = kErrorOk; static UINT32 leSignature; tCfmNodeInfo* pNodeInfo = NULL; tObdSize obdSize; UINT32 expConfTime = 0; UINT32 expConfDate = 0; tIdentResponse* pIdentResponse = NULL; BOOL fDoUpdate = FALSE; BOOL fDoNetConf = FALSE; if ((nodeEvent_p != kNmtNodeEventCheckConf) && (nodeEvent_p != kNmtNodeEventUpdateConf) && (nodeEvent_p != kNmtNodeEventFound) && ((nodeEvent_p != kNmtNodeEventNmtState) || (nmtState_p != kNmtCsNotActive))) return ret; if ((pNodeInfo = allocNodeInfo(nodeId_p)) == NULL) return kErrorInvalidNodeId; if (pNodeInfo->cfmState != kCfmStateIdle) { // Send abort if SDO command is not undefined if (pNodeInfo->sdoComConHdl != UINT_MAX) { // Set node CFM state to an intermediate state to catch the SDO callback pNodeInfo->cfmState = kCfmStateInternalAbort; ret = sdocom_abortTransfer(pNodeInfo->sdoComConHdl, SDO_AC_DATA_NOT_TRANSF_DUE_LOCAL_CONTROL); if (ret != kErrorOk) return ret; // close connection ret = sdocom_undefineConnection(pNodeInfo->sdoComConHdl); pNodeInfo->sdoComConHdl = UINT_MAX; if (ret != kErrorOk) { DEBUG_LVL_CFM_TRACE("SDO Free Error!\n"); return ret; } } // Set node CFM state to idle pNodeInfo->cfmState = kCfmStateIdle; } if ((nodeEvent_p == kNmtNodeEventFound) || ((nodeEvent_p == kNmtNodeEventNmtState) && (nmtState_p == kNmtCsNotActive))) { // just close SDO connection in case of IdentResponse or loss of connection return ret; } pNodeInfo->curDataSize = 0; // fetch pointer to ConciseDCF from object 0x1F22 // (this allows the application to link its own memory to this object) pNodeInfo->pDataConciseDcf = (UINT8*)obd_getObjectDataPtr(0x1F22, nodeId_p); if (pNodeInfo->pDataConciseDcf == NULL) return kErrorCfmNoConfigData; obdSize = obd_getDataSize(0x1F22, nodeId_p); pNodeInfo->bytesRemaining = (UINT32)obdSize; pNodeInfo->eventCnProgress.totalNumberOfBytes = pNodeInfo->bytesRemaining; #if (CONFIG_CFM_CONFIGURE_CYCLE_LENGTH != FALSE) pNodeInfo->eventCnProgress.totalNumberOfBytes += sizeof(UINT32); #endif pNodeInfo->eventCnProgress.bytesDownloaded = 0; pNodeInfo->eventCnProgress.error = kErrorOk; if (obdSize < sizeof(UINT32)) { pNodeInfo->eventCnProgress.error = kErrorCfmInvalidDcf; ret = callCbProgress(pNodeInfo); if (ret != kErrorOk) return ret; return pNodeInfo->eventCnProgress.error; } identu_getIdentResponse(nodeId_p, &pIdentResponse); if (pIdentResponse == NULL) { DEBUG_LVL_CFM_TRACE("CN%x Ident Response is NULL\n", nodeId_p); return kErrorInvalidNodeId; } #if defined(CONFIG_INCLUDE_NMT_RMN) if (ami_getUint32Le(&pIdentResponse->featureFlagsLe) & PLK_FEATURE_CFM) { UINT subindex; // add size of network configuration (domains in CFM_ConciseDcfList_ADOM) for (subindex = 1; subindex <= NMT_MAX_NODE_ID; subindex++) { obdSize = obd_getDataSize(0x1F22, subindex); // Download only cDCFs with at least one entry if (obdSize > 4) pNodeInfo->eventCnProgress.totalNumberOfBytes += (UINT32)obdSize; } fDoNetConf = TRUE; } #endif pNodeInfo->entriesRemaining = ami_getUint32Le(pNodeInfo->pDataConciseDcf); pNodeInfo->pDataConciseDcf += sizeof(UINT32); pNodeInfo->bytesRemaining -= sizeof(UINT32); pNodeInfo->eventCnProgress.bytesDownloaded += sizeof(UINT32); if (pNodeInfo->entriesRemaining == 0) { pNodeInfo->eventCnProgress.error = kErrorCfmNoConfigData; ret = callCbProgress(pNodeInfo); if (ret != kErrorOk) return ret; } else if (nodeEvent_p == kNmtNodeEventUpdateConf) fDoUpdate = TRUE; else { obdSize = sizeof(expConfDate); ret = obd_readEntry(0x1F26, nodeId_p, &expConfDate, &obdSize); if (ret != kErrorOk) { DEBUG_LVL_CFM_TRACE("CN%x Error Reading 0x1F26 returns 0x%X\n", nodeId_p, ret); } obdSize = sizeof(expConfTime); ret = obd_readEntry(0x1F27, nodeId_p, &expConfTime, &obdSize); if (ret != kErrorOk) { DEBUG_LVL_CFM_TRACE("CN%x Error Reading 0x1F27 returns 0x%X\n", nodeId_p, ret); } if ((expConfDate != 0) || (expConfTime != 0)) { // expected configuration date or time is set if ((ami_getUint32Le(&pIdentResponse->verifyConfigurationDateLe) != expConfDate) || (ami_getUint32Le(&pIdentResponse->verifyConfigurationTimeLe) != expConfTime)) { // update configuration because date or time differ from the expected value fDoUpdate = TRUE; } // store configuration in CN at the end of the download pNodeInfo->fDoStore = TRUE; pNodeInfo->eventCnProgress.totalNumberOfBytes += sizeof(UINT32); } else { // expected configuration date and time is not set fDoUpdate = TRUE; // do not store configuration in CN at the end of the download pNodeInfo->fDoStore = FALSE; } } #if (CONFIG_CFM_CONFIGURE_CYCLE_LENGTH != FALSE) obdSize = sizeof(cfmInstance_g.leCycleLength); ret = obd_readEntryToLe(0x1006, 0x00, &cfmInstance_g.leCycleLength, &obdSize); if (ret != kErrorOk) { // local OD access failed DEBUG_LVL_CFM_TRACE("Local OBD read failed %d\n", ret); return ret; } #endif if ((fDoUpdate == FALSE) && !(fDoNetConf && (pNodeInfo->entriesRemaining == 0))) { pNodeInfo->cfmState = kCfmStateIdle; // current version is already available on the CN, no need to write new values, we can continue DEBUG_LVL_CFM_TRACE("CN%x - Cfg Upto Date\n", nodeId_p); ret = downloadCycleLength(pNodeInfo); if (ret == kErrorReject) { pNodeInfo->cfmState = kCfmStateUpToDate; } } else if (nodeEvent_p == kNmtNodeEventUpdateConf) { pNodeInfo->cfmState = kCfmStateDownload; ret = downloadObject(pNodeInfo); if (ret == kErrorOk) { // SDO transfer started ret = kErrorReject; } } else { pNodeInfo->cfmState = kCfmStateWaitRestore; #if defined(CONFIG_INCLUDE_NMT_RMN) if (pNodeInfo->entriesRemaining == 0) { DEBUG_LVL_CFM_TRACE("CN%x - CFM Network-Cfg Update. Restoring Default...\n"); } else #endif { DEBUG_LVL_CFM_TRACE("CN%x - Cfg Mismatch | MN Expects: %lx-%lx ", nodeId_p, expConfDate, expConfTime); DEBUG_LVL_CFM_TRACE("CN Has: %lx-%lx. Restoring Default...\n", ami_getUint32Le(&pIdentResponse->verifyConfigurationDateLe), ami_getUint32Le(&pIdentResponse->verifyConfigurationTimeLe)); } //Restore Default Parameters pNodeInfo->eventCnProgress.totalNumberOfBytes += sizeof(leSignature); ami_setUint32Le(&leSignature, 0x64616F6C); pNodeInfo->eventCnProgress.objectIndex = 0x1011; pNodeInfo->eventCnProgress.objectSubIndex = 0x01; ret = sdoWriteObject(pNodeInfo, &leSignature, sizeof(leSignature)); if (ret == kErrorOk) { // SDO transfer started ret = kErrorReject; } else { // error occurred DEBUG_LVL_CFM_TRACE("CfmCbEvent(Node): sdoWriteObject() returned 0x%02X\n", ret); } } return ret; }