| /**************************************************************************** |
| |
| (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29 |
| www.systec-electronic.com |
| |
| Project: openPOWERLINK |
| |
| Description: source file for NMT-MN-Module |
| |
| License: |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions |
| are met: |
| |
| 1. Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| |
| 2. Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| 3. Neither the name of SYSTEC electronic GmbH nor the names of its |
| contributors may be used to endorse or promote products derived |
| from this software without prior written permission. For written |
| permission, please contact info@systec-electronic.com. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| POSSIBILITY OF SUCH DAMAGE. |
| |
| Severability Clause: |
| |
| If a provision of this License is or becomes illegal, invalid or |
| unenforceable in any jurisdiction, that shall not affect: |
| 1. the validity or enforceability in that jurisdiction of any other |
| provision of this License; or |
| 2. the validity or enforceability in other jurisdictions of that or |
| any other provision of this License. |
| |
| ------------------------------------------------------------------------- |
| |
| $RCSfile: EplNmtMnu.c,v $ |
| |
| $Author: D.Krueger $ |
| |
| $Revision: 1.18 $ $Date: 2008/11/19 09:52:24 $ |
| |
| $State: Exp $ |
| |
| Build Environment: |
| GCC V3.4 |
| |
| ------------------------------------------------------------------------- |
| |
| Revision History: |
| |
| 2006/06/09 k.t.: start of the implementation |
| |
| ****************************************************************************/ |
| |
| #include "user/EplNmtMnu.h" |
| #include "user/EplTimeru.h" |
| #include "user/EplIdentu.h" |
| #include "user/EplStatusu.h" |
| #include "user/EplObdu.h" |
| #include "user/EplDlluCal.h" |
| #include "Benchmark.h" |
| |
| #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0) |
| |
| #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) == 0) && (EPL_OBD_USE_KERNEL == FALSE) |
| #error "EPL NmtMnu module needs EPL module OBDU or OBDK!" |
| #endif |
| |
| //=========================================================================// |
| // // |
| // P R I V A T E D E F I N I T I O N S // |
| // // |
| //=========================================================================// |
| |
| //--------------------------------------------------------------------------- |
| // const defines |
| //--------------------------------------------------------------------------- |
| |
| // TracePoint support for realtime-debugging |
| #ifdef _DBG_TRACE_POINTS_ |
| void PUBLIC TgtDbgSignalTracePoint(BYTE bTracePointNumber_p); |
| void PUBLIC TgtDbgPostTraceValue(DWORD dwTraceValue_p); |
| #define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p) |
| #define TGT_DBG_POST_TRACE_VALUE(v) TgtDbgPostTraceValue(v) |
| #else |
| #define TGT_DBG_SIGNAL_TRACE_POINT(p) |
| #define TGT_DBG_POST_TRACE_VALUE(v) |
| #endif |
| #define EPL_NMTMNU_DBG_POST_TRACE_VALUE(Event_p, uiNodeId_p, wErrorCode_p) \ |
| TGT_DBG_POST_TRACE_VALUE((kEplEventSinkNmtMnu << 28) | (Event_p << 24) \ |
| | (uiNodeId_p << 16) | wErrorCode_p) |
| |
| // defines for flags in node info structure |
| #define EPL_NMTMNU_NODE_FLAG_ISOCHRON 0x0001 // CN is being accessed isochronously |
| #define EPL_NMTMNU_NODE_FLAG_NOT_SCANNED 0x0002 // CN was not scanned once -> decrement SignalCounter and reset flag |
| #define EPL_NMTMNU_NODE_FLAG_HALTED 0x0004 // boot process for this CN is halted |
| #define EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED 0x0008 // NMT command was just issued, wrong NMT states will be tolerated |
| #define EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ 0x0300 // counter for StatusRequest timer handle |
| #define EPL_NMTMNU_NODE_FLAG_COUNT_LONGER 0x0C00 // counter for longer timeouts timer handle |
| #define EPL_NMTMNU_NODE_FLAG_INC_STATREQ 0x0100 // increment for StatusRequest timer handle |
| #define EPL_NMTMNU_NODE_FLAG_INC_LONGER 0x0400 // increment for longer timeouts timer handle |
| // These counters will be incremented at every timer start |
| // and copied to timerarg. When the timer event occures |
| // both will be compared and if unequal the timer event |
| // will be discarded, because it is an old one. |
| |
| // defines for timer arguments to draw a distinction between serveral events |
| #define EPL_NMTMNU_TIMERARG_NODE_MASK 0x000000FFL // mask that contains the node-ID |
| #define EPL_NMTMNU_TIMERARG_IDENTREQ 0x00010000L // timer event is for IdentRequest |
| #define EPL_NMTMNU_TIMERARG_STATREQ 0x00020000L // timer event is for StatusRequest |
| #define EPL_NMTMNU_TIMERARG_LONGER 0x00040000L // timer event is for longer timeouts |
| #define EPL_NMTMNU_TIMERARG_STATE_MON 0x00080000L // timer event for StatusRequest to monitor execution of NMT state changes |
| #define EPL_NMTMNU_TIMERARG_COUNT_SR 0x00000300L // counter for StatusRequest |
| #define EPL_NMTMNU_TIMERARG_COUNT_LO 0x00000C00L // counter for longer timeouts |
| // The counters must have the same position as in the node flags above. |
| |
| #define EPL_NMTMNU_SET_FLAGS_TIMERARG_STATREQ(pNodeInfo_p, uiNodeId_p, TimerArg_p) \ |
| pNodeInfo_p->m_wFlags = \ |
| ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \ |
| & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \ |
| | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \ |
| TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_STATREQ | uiNodeId_p | \ |
| (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \ |
| TimerArg_p.m_EventSink = kEplEventSinkNmtMnu; |
| |
| #define EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ(pNodeInfo_p, uiNodeId_p, TimerArg_p) \ |
| pNodeInfo_p->m_wFlags = \ |
| ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \ |
| & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \ |
| | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \ |
| TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_IDENTREQ | uiNodeId_p | \ |
| (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \ |
| TimerArg_p.m_EventSink = kEplEventSinkNmtMnu; |
| |
| #define EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(pNodeInfo_p, uiNodeId_p, TimerArg_p) \ |
| pNodeInfo_p->m_wFlags = \ |
| ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_LONGER) \ |
| & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER) \ |
| | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_LONGER); \ |
| TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p | \ |
| (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER); \ |
| TimerArg_p.m_EventSink = kEplEventSinkNmtMnu; |
| |
| #define EPL_NMTMNU_SET_FLAGS_TIMERARG_STATE_MON(pNodeInfo_p, uiNodeId_p, TimerArg_p) \ |
| pNodeInfo_p->m_wFlags = \ |
| ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \ |
| & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \ |
| | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \ |
| TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_STATE_MON | uiNodeId_p | \ |
| (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \ |
| TimerArg_p.m_EventSink = kEplEventSinkNmtMnu; |
| |
| // defines for global flags |
| #define EPL_NMTMNU_FLAG_HALTED 0x0001 // boot process is halted |
| #define EPL_NMTMNU_FLAG_APP_INFORMED 0x0002 // application was informed about possible NMT state change |
| |
| // return pointer to node info structure for specified node ID |
| // d.k. may be replaced by special (hash) function if node ID array is smaller than 254 |
| #define EPL_NMTMNU_GET_NODEINFO(uiNodeId_p) (&EplNmtMnuInstance_g.m_aNodeInfo[uiNodeId_p - 1]) |
| |
| //--------------------------------------------------------------------------- |
| // local types |
| //--------------------------------------------------------------------------- |
| |
| typedef enum { |
| kEplNmtMnuIntNodeEventNoIdentResponse = 0x00, |
| kEplNmtMnuIntNodeEventIdentResponse = 0x01, |
| kEplNmtMnuIntNodeEventBoot = 0x02, |
| kEplNmtMnuIntNodeEventExecReset = 0x03, |
| kEplNmtMnuIntNodeEventConfigured = 0x04, |
| kEplNmtMnuIntNodeEventNoStatusResponse = 0x05, |
| kEplNmtMnuIntNodeEventStatusResponse = 0x06, |
| kEplNmtMnuIntNodeEventHeartbeat = 0x07, |
| kEplNmtMnuIntNodeEventNmtCmdSent = 0x08, |
| kEplNmtMnuIntNodeEventTimerIdentReq = 0x09, |
| kEplNmtMnuIntNodeEventTimerStatReq = 0x0A, |
| kEplNmtMnuIntNodeEventTimerStateMon = 0x0B, |
| kEplNmtMnuIntNodeEventTimerLonger = 0x0C, |
| kEplNmtMnuIntNodeEventError = 0x0D, |
| |
| } tEplNmtMnuIntNodeEvent; |
| |
| typedef enum { |
| kEplNmtMnuNodeStateUnknown = 0x00, |
| kEplNmtMnuNodeStateIdentified = 0x01, |
| kEplNmtMnuNodeStateResetConf = 0x02, // CN reset after configuration update |
| kEplNmtMnuNodeStateConfigured = 0x03, // BootStep1 completed |
| kEplNmtMnuNodeStateReadyToOp = 0x04, // BootStep2 completed |
| kEplNmtMnuNodeStateComChecked = 0x05, // Communication checked successfully |
| kEplNmtMnuNodeStateOperational = 0x06, // CN is in NMT state OPERATIONAL |
| |
| } tEplNmtMnuNodeState; |
| |
| typedef struct { |
| tEplTimerHdl m_TimerHdlStatReq; // timer to delay StatusRequests and IdentRequests |
| tEplTimerHdl m_TimerHdlLonger; // 2nd timer for NMT command EnableReadyToOp and CheckCommunication |
| tEplNmtMnuNodeState m_NodeState; // internal node state (kind of sub state of NMT state) |
| DWORD m_dwNodeCfg; // subindex from 0x1F81 |
| WORD m_wFlags; // flags: CN is being accessed isochronously |
| |
| } tEplNmtMnuNodeInfo; |
| |
| typedef struct { |
| tEplNmtMnuNodeInfo m_aNodeInfo[EPL_NMT_MAX_NODE_ID]; |
| tEplTimerHdl m_TimerHdlNmtState; // timeout for stay in NMT state |
| unsigned int m_uiMandatorySlaveCount; |
| unsigned int m_uiSignalSlaveCount; |
| unsigned long m_ulStatusRequestDelay; // in [ms] (object 0x1006 * EPL_C_NMT_STATREQ_CYCLE) |
| unsigned long m_ulTimeoutReadyToOp; // in [ms] (object 0x1F89/5) |
| unsigned long m_ulTimeoutCheckCom; // in [ms] (object 0x1006 * MultiplexedCycleCount) |
| WORD m_wFlags; // global flags |
| DWORD m_dwNmtStartup; // object 0x1F80 NMT_StartUp_U32 |
| tEplNmtMnuCbNodeEvent m_pfnCbNodeEvent; |
| tEplNmtMnuCbBootEvent m_pfnCbBootEvent; |
| |
| } tEplNmtMnuInstance; |
| |
| //--------------------------------------------------------------------------- |
| // local vars |
| //--------------------------------------------------------------------------- |
| |
| static tEplNmtMnuInstance EplNmtMnuInstance_g; |
| |
| //--------------------------------------------------------------------------- |
| // local function prototypes |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel PUBLIC EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p); |
| |
| static tEplKernel PUBLIC EplNmtMnuCbIdentResponse(unsigned int uiNodeId_p, |
| tEplIdentResponse * |
| pIdentResponse_p); |
| |
| static tEplKernel PUBLIC EplNmtMnuCbStatusResponse(unsigned int uiNodeId_p, |
| tEplStatusResponse * |
| pStatusResponse_p); |
| |
| static tEplKernel EplNmtMnuCheckNmtState(unsigned int uiNodeId_p, |
| tEplNmtMnuNodeInfo * pNodeInfo_p, |
| tEplNmtState NodeNmtState_p, |
| WORD wErrorCode_p, |
| tEplNmtState LocalNmtState_p); |
| |
| static tEplKernel EplNmtMnuStartBootStep1(void); |
| |
| static tEplKernel EplNmtMnuStartBootStep2(void); |
| |
| static tEplKernel EplNmtMnuStartCheckCom(void); |
| |
| static tEplKernel EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p, |
| tEplNmtMnuNodeInfo * pNodeInfo_p); |
| |
| static tEplKernel EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p, |
| tEplNmtMnuNodeInfo * pNodeInfo_p); |
| |
| static tEplKernel EplNmtMnuStartNodes(void); |
| |
| static tEplKernel EplNmtMnuProcessInternalEvent(unsigned int uiNodeId_p, |
| tEplNmtState NodeNmtState_p, |
| WORD wErrorCode_p, |
| tEplNmtMnuIntNodeEvent |
| NodeEvent_p); |
| |
| static tEplKernel EplNmtMnuReset(void); |
| |
| //=========================================================================// |
| // // |
| // P U B L I C F U N C T I O N S // |
| // // |
| //=========================================================================// |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuInit |
| // |
| // Description: init first instance of the module |
| // |
| // |
| // |
| // Parameters: |
| // |
| // |
| // Returns: tEplKernel = errorcode |
| // |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| tEplKernel EplNmtMnuInit(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p, |
| tEplNmtMnuCbBootEvent pfnCbBootEvent_p) |
| { |
| tEplKernel Ret; |
| |
| Ret = EplNmtMnuAddInstance(pfnCbNodeEvent_p, pfnCbBootEvent_p); |
| |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuAddInstance |
| // |
| // Description: init other instances of the module |
| // |
| // |
| // |
| // Parameters: |
| // |
| // |
| // Returns: tEplKernel = errorcode |
| // |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| tEplKernel EplNmtMnuAddInstance(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p, |
| tEplNmtMnuCbBootEvent pfnCbBootEvent_p) |
| { |
| tEplKernel Ret; |
| |
| Ret = kEplSuccessful; |
| |
| // reset instance structure |
| EPL_MEMSET(&EplNmtMnuInstance_g, 0, sizeof(EplNmtMnuInstance_g)); |
| |
| if ((pfnCbNodeEvent_p == NULL) || (pfnCbBootEvent_p == NULL)) { |
| Ret = kEplNmtInvalidParam; |
| goto Exit; |
| } |
| EplNmtMnuInstance_g.m_pfnCbNodeEvent = pfnCbNodeEvent_p; |
| EplNmtMnuInstance_g.m_pfnCbBootEvent = pfnCbBootEvent_p; |
| |
| // initialize StatusRequest delay |
| EplNmtMnuInstance_g.m_ulStatusRequestDelay = 5000L; |
| |
| // register NmtMnResponse callback function |
| Ret = |
| EplDlluCalRegAsndService(kEplDllAsndNmtRequest, |
| EplNmtMnuCbNmtRequest, |
| kEplDllAsndFilterLocal); |
| |
| Exit: |
| return Ret; |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuDelInstance |
| // |
| // Description: delete instance |
| // |
| // |
| // |
| // Parameters: |
| // |
| // |
| // Returns: tEplKernel = errorcode |
| // |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| tEplKernel EplNmtMnuDelInstance() |
| { |
| tEplKernel Ret; |
| |
| Ret = kEplSuccessful; |
| |
| // deregister NmtMnResponse callback function |
| Ret = |
| EplDlluCalRegAsndService(kEplDllAsndNmtRequest, NULL, |
| kEplDllAsndFilterNone); |
| |
| Ret = EplNmtMnuReset(); |
| |
| return Ret; |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuSendNmtCommandEx |
| // |
| // Description: sends the specified NMT command to the specified node. |
| // |
| // Parameters: uiNodeId_p = node ID to which the NMT command will be sent |
| // NmtCommand_p = NMT command |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| tEplKernel EplNmtMnuSendNmtCommandEx(unsigned int uiNodeId_p, |
| tEplNmtCommand NmtCommand_p, |
| void *pNmtCommandData_p, |
| unsigned int uiDataSize_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| tEplFrameInfo FrameInfo; |
| BYTE abBuffer[EPL_C_DLL_MINSIZE_NMTCMDEXT]; |
| tEplFrame *pFrame = (tEplFrame *) abBuffer; |
| BOOL fSoftDeleteNode = FALSE; |
| |
| if ((uiNodeId_p == 0) || (uiNodeId_p > EPL_C_ADR_BROADCAST)) { // invalid node ID specified |
| Ret = kEplInvalidNodeId; |
| goto Exit; |
| } |
| |
| if ((pNmtCommandData_p != NULL) |
| && (uiDataSize_p > |
| (EPL_C_DLL_MINSIZE_NMTCMDEXT - EPL_C_DLL_MINSIZE_NMTCMD))) { |
| Ret = kEplNmtInvalidParam; |
| goto Exit; |
| } |
| // $$$ d.k. may be check in future versions if the caller wants to perform prohibited state transitions |
| // the CN should not perform these transitions, but the expected NMT state will be changed and never fullfilled. |
| |
| // build frame |
| EPL_MEMSET(pFrame, 0x00, sizeof(abBuffer)); |
| AmiSetByteToLe(&pFrame->m_le_bDstNodeId, (BYTE) uiNodeId_p); |
| AmiSetByteToLe(&pFrame->m_Data.m_Asnd.m_le_bServiceId, |
| (BYTE) kEplDllAsndNmtCommand); |
| AmiSetByteToLe(&pFrame->m_Data.m_Asnd.m_Payload.m_NmtCommandService. |
| m_le_bNmtCommandId, (BYTE) NmtCommand_p); |
| if ((pNmtCommandData_p != NULL) && (uiDataSize_p > 0)) { // copy command data to frame |
| EPL_MEMCPY(&pFrame->m_Data.m_Asnd.m_Payload.m_NmtCommandService. |
| m_le_abNmtCommandData[0], pNmtCommandData_p, |
| uiDataSize_p); |
| } |
| // build info structure |
| FrameInfo.m_NetTime.m_dwNanoSec = 0; |
| FrameInfo.m_NetTime.m_dwSec = 0; |
| FrameInfo.m_pFrame = pFrame; |
| FrameInfo.m_uiFrameSize = sizeof(abBuffer); |
| |
| // send NMT-Request |
| #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_DLLU)) != 0) |
| Ret = EplDlluCalAsyncSend(&FrameInfo, // pointer to frameinfo |
| kEplDllAsyncReqPrioNmt); // priority |
| #endif |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| EPL_DBGLVL_NMTMN_TRACE2("NMTCmd(%02X->%02X)\n", NmtCommand_p, |
| uiNodeId_p); |
| |
| switch (NmtCommand_p) { |
| case kEplNmtCmdStartNode: |
| case kEplNmtCmdEnterPreOperational2: |
| case kEplNmtCmdEnableReadyToOperate: |
| { |
| // nothing left to do, |
| // because any further processing is done |
| // when the NMT command is actually sent |
| goto Exit; |
| } |
| |
| case kEplNmtCmdStopNode: |
| { |
| fSoftDeleteNode = TRUE; |
| break; |
| } |
| |
| case kEplNmtCmdResetNode: |
| case kEplNmtCmdResetCommunication: |
| case kEplNmtCmdResetConfiguration: |
| case kEplNmtCmdSwReset: |
| { |
| break; |
| } |
| |
| default: |
| goto Exit; |
| } |
| |
| // remove CN from isochronous phase; |
| // This must be done here and not when NMT command is actually sent |
| // because it will be too late and may cause unwanted errors |
| if (uiNodeId_p != EPL_C_ADR_BROADCAST) { |
| if (fSoftDeleteNode == FALSE) { // remove CN immediately from isochronous phase |
| Ret = EplDlluCalDeleteNode(uiNodeId_p); |
| } else { // remove CN from isochronous phase softly |
| Ret = EplDlluCalSoftDeleteNode(uiNodeId_p); |
| } |
| } else { // do it for all active CNs |
| for (uiNodeId_p = 1; |
| uiNodeId_p <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); |
| uiNodeId_p++) { |
| if ((EPL_NMTMNU_GET_NODEINFO(uiNodeId_p)-> |
| m_dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN | |
| EPL_NODEASSIGN_NODE_EXISTS)) != 0) { |
| if (fSoftDeleteNode == FALSE) { // remove CN immediately from isochronous phase |
| Ret = EplDlluCalDeleteNode(uiNodeId_p); |
| } else { // remove CN from isochronous phase softly |
| Ret = |
| EplDlluCalSoftDeleteNode |
| (uiNodeId_p); |
| } |
| } |
| } |
| } |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuSendNmtCommand |
| // |
| // Description: sends the specified NMT command to the specified node. |
| // |
| // Parameters: uiNodeId_p = node ID to which the NMT command will be sent |
| // NmtCommand_p = NMT command |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| tEplKernel EplNmtMnuSendNmtCommand(unsigned int uiNodeId_p, |
| tEplNmtCommand NmtCommand_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| |
| Ret = EplNmtMnuSendNmtCommandEx(uiNodeId_p, NmtCommand_p, NULL, 0); |
| |
| //Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuTriggerStateChange |
| // |
| // Description: triggers the specified node command for the specified node. |
| // |
| // Parameters: uiNodeId_p = node ID for which the node command will be executed |
| // NodeCommand_p = node command |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| tEplKernel EplNmtMnuTriggerStateChange(unsigned int uiNodeId_p, |
| tEplNmtNodeCommand NodeCommand_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| tEplNmtMnuIntNodeEvent NodeEvent; |
| tEplObdSize ObdSize; |
| BYTE bNmtState; |
| WORD wErrorCode = EPL_E_NO_ERROR; |
| |
| if ((uiNodeId_p == 0) || (uiNodeId_p >= EPL_C_ADR_BROADCAST)) { |
| Ret = kEplInvalidNodeId; |
| goto Exit; |
| } |
| |
| switch (NodeCommand_p) { |
| case kEplNmtNodeCommandBoot: |
| { |
| NodeEvent = kEplNmtMnuIntNodeEventBoot; |
| break; |
| } |
| |
| case kEplNmtNodeCommandConfOk: |
| { |
| NodeEvent = kEplNmtMnuIntNodeEventConfigured; |
| break; |
| } |
| |
| case kEplNmtNodeCommandConfErr: |
| { |
| NodeEvent = kEplNmtMnuIntNodeEventError; |
| wErrorCode = EPL_E_NMT_BPO1_CF_VERIFY; |
| break; |
| } |
| |
| case kEplNmtNodeCommandConfReset: |
| { |
| NodeEvent = kEplNmtMnuIntNodeEventExecReset; |
| break; |
| } |
| |
| default: |
| { // invalid node command |
| goto Exit; |
| } |
| } |
| |
| // fetch current NMT state |
| ObdSize = 1; |
| Ret = EplObduReadEntry(0x1F8E, uiNodeId_p, &bNmtState, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p, |
| (tEplNmtState) (bNmtState | |
| EPL_NMT_TYPE_CS), |
| wErrorCode, NodeEvent); |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuCbNmtStateChange |
| // |
| // Description: callback function for NMT state changes |
| // |
| // Parameters: NmtStateChange_p = NMT state change event |
| // |
| // Returns: tEplKernel = error code |
| // |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| tEplKernel PUBLIC EplNmtMnuCbNmtStateChange(tEplEventNmtStateChange |
| NmtStateChange_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| |
| // do work which must be done in that state |
| switch (NmtStateChange_p.m_NewNmtState) { |
| // EPL stack is not running |
| /* case kEplNmtGsOff: |
| break; |
| |
| // first init of the hardware |
| case kEplNmtGsInitialising: |
| break; |
| |
| // init of the manufacturer-specific profile area and the |
| // standardised device profile area |
| case kEplNmtGsResetApplication: |
| { |
| break; |
| } |
| |
| // init of the communication profile area |
| case kEplNmtGsResetCommunication: |
| { |
| break; |
| } |
| */ |
| // build the configuration with infos from OD |
| case kEplNmtGsResetConfiguration: |
| { |
| DWORD dwTimeout; |
| tEplObdSize ObdSize; |
| |
| // read object 0x1F80 NMT_StartUp_U32 |
| ObdSize = 4; |
| Ret = |
| EplObduReadEntry(0x1F80, 0, |
| &EplNmtMnuInstance_g. |
| m_dwNmtStartup, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| break; |
| } |
| // compute StatusReqDelay = object 0x1006 * EPL_C_NMT_STATREQ_CYCLE |
| ObdSize = sizeof(dwTimeout); |
| Ret = EplObduReadEntry(0x1006, 0, &dwTimeout, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| break; |
| } |
| if (dwTimeout != 0L) { |
| EplNmtMnuInstance_g.m_ulStatusRequestDelay = |
| dwTimeout * EPL_C_NMT_STATREQ_CYCLE / 1000L; |
| if (EplNmtMnuInstance_g. |
| m_ulStatusRequestDelay == 0L) { |
| EplNmtMnuInstance_g.m_ulStatusRequestDelay = 1L; // at least 1 ms |
| } |
| // $$$ fetch and use MultiplexedCycleCount from OD |
| EplNmtMnuInstance_g.m_ulTimeoutCheckCom = |
| dwTimeout * EPL_C_NMT_STATREQ_CYCLE / 1000L; |
| if (EplNmtMnuInstance_g.m_ulTimeoutCheckCom == |
| 0L) { |
| EplNmtMnuInstance_g.m_ulTimeoutCheckCom = 1L; // at least 1 ms |
| } |
| } |
| // fetch ReadyToOp Timeout from OD |
| ObdSize = sizeof(dwTimeout); |
| Ret = EplObduReadEntry(0x1F89, 5, &dwTimeout, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| break; |
| } |
| if (dwTimeout != 0L) { |
| // convert [us] to [ms] |
| dwTimeout /= 1000L; |
| if (dwTimeout == 0L) { |
| dwTimeout = 1L; // at least 1 ms |
| } |
| EplNmtMnuInstance_g.m_ulTimeoutReadyToOp = |
| dwTimeout; |
| } else { |
| EplNmtMnuInstance_g.m_ulTimeoutReadyToOp = 0L; |
| } |
| break; |
| } |
| /* |
| //----------------------------------------------------------- |
| // CN part of the state machine |
| |
| // node liste for EPL-Frames and check timeout |
| case kEplNmtCsNotActive: |
| { |
| break; |
| } |
| |
| // node process only async frames |
| case kEplNmtCsPreOperational1: |
| { |
| break; |
| } |
| |
| // node process isochronus and asynchronus frames |
| case kEplNmtCsPreOperational2: |
| { |
| break; |
| } |
| |
| // node should be configured und application is ready |
| case kEplNmtCsReadyToOperate: |
| { |
| break; |
| } |
| |
| // normal work state |
| case kEplNmtCsOperational: |
| { |
| break; |
| } |
| |
| // node stopped by MN |
| // -> only process asynchronus frames |
| case kEplNmtCsStopped: |
| { |
| break; |
| } |
| |
| // no EPL cycle |
| // -> normal ethernet communication |
| case kEplNmtCsBasicEthernet: |
| { |
| break; |
| } |
| */ |
| //----------------------------------------------------------- |
| // MN part of the state machine |
| |
| // node listens for EPL-Frames and check timeout |
| case kEplNmtMsNotActive: |
| { |
| break; |
| } |
| |
| // node processes only async frames |
| case kEplNmtMsPreOperational1: |
| { |
| DWORD dwTimeout; |
| tEplTimerArg TimerArg; |
| tEplObdSize ObdSize; |
| tEplEvent Event; |
| |
| // clear global flags, e.g. reenable boot process |
| EplNmtMnuInstance_g.m_wFlags = 0; |
| |
| // reset IdentResponses and running IdentRequests and StatusRequests |
| Ret = EplIdentuReset(); |
| Ret = EplStatusuReset(); |
| |
| // reset timers |
| Ret = EplNmtMnuReset(); |
| |
| // 2008/11/18 d.k. reset internal node info is not necessary, |
| // because timer flags are important and other |
| // things are reset by EplNmtMnuStartBootStep1(). |
| /* |
| EPL_MEMSET(EplNmtMnuInstance_g.m_aNodeInfo, |
| 0, |
| sizeof (EplNmtMnuInstance_g.m_aNodeInfo)); |
| */ |
| |
| // inform DLL about NMT state change, |
| // so that it can clear the asynchonous queues and start the reduced cycle |
| Event.m_EventSink = kEplEventSinkDllk; |
| Event.m_EventType = kEplEventTypeDllkStartReducedCycle; |
| EPL_MEMSET(&Event.m_NetTime, 0x00, |
| sizeof(Event.m_NetTime)); |
| Event.m_pArg = NULL; |
| Event.m_uiSize = 0; |
| Ret = EplEventuPost(&Event); |
| if (Ret != kEplSuccessful) { |
| break; |
| } |
| // reset all nodes |
| // d.k.: skip this step if was just done before, e.g. because of a ResetNode command from a diagnostic node |
| if (NmtStateChange_p.m_NmtEvent == |
| kEplNmtEventTimerMsPreOp1) { |
| BENCHMARK_MOD_07_TOGGLE(9); |
| |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(0, |
| EPL_C_ADR_BROADCAST, |
| kEplNmtCmdResetNode); |
| |
| Ret = |
| EplNmtMnuSendNmtCommand(EPL_C_ADR_BROADCAST, |
| kEplNmtCmdResetNode); |
| if (Ret != kEplSuccessful) { |
| break; |
| } |
| } |
| // start network scan |
| Ret = EplNmtMnuStartBootStep1(); |
| |
| // start timer for 0x1F89/2 MNTimeoutPreOp1_U32 |
| ObdSize = sizeof(dwTimeout); |
| Ret = EplObduReadEntry(0x1F89, 2, &dwTimeout, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| break; |
| } |
| if (dwTimeout != 0L) { |
| dwTimeout /= 1000L; |
| if (dwTimeout == 0L) { |
| dwTimeout = 1L; // at least 1 ms |
| } |
| TimerArg.m_EventSink = kEplEventSinkNmtMnu; |
| TimerArg.m_ulArg = 0; |
| Ret = |
| EplTimeruModifyTimerMs(&EplNmtMnuInstance_g. |
| m_TimerHdlNmtState, |
| dwTimeout, TimerArg); |
| } |
| break; |
| } |
| |
| // node processes isochronous and asynchronous frames |
| case kEplNmtMsPreOperational2: |
| { |
| // add identified CNs to isochronous phase |
| // send EnableReadyToOp to all identified CNs |
| Ret = EplNmtMnuStartBootStep2(); |
| |
| // wait for NMT state change of CNs |
| break; |
| } |
| |
| // node should be configured und application is ready |
| case kEplNmtMsReadyToOperate: |
| { |
| // check if PRes of CNs are OK |
| // d.k. that means wait CycleLength * MultiplexCycleCount (i.e. start timer) |
| // because Dllk checks PRes of CNs automatically in ReadyToOp |
| Ret = EplNmtMnuStartCheckCom(); |
| break; |
| } |
| |
| // normal work state |
| case kEplNmtMsOperational: |
| { |
| // send StartNode to CNs |
| // wait for NMT state change of CNs |
| Ret = EplNmtMnuStartNodes(); |
| break; |
| } |
| |
| // no EPL cycle |
| // -> normal ethernet communication |
| case kEplNmtMsBasicEthernet: |
| { |
| break; |
| } |
| |
| default: |
| { |
| // TRACE0("EplNmtMnuCbNmtStateChange(): unhandled NMT state\n"); |
| } |
| } |
| |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuCbCheckEvent |
| // |
| // Description: callback funktion for NMT events before they are actually executed. |
| // The EPL API layer must forward NMT events from NmtCnu module. |
| // This module will reject some NMT commands while MN. |
| // |
| // Parameters: NmtEvent_p = outstanding NMT event for approval |
| // |
| // Returns: tEplKernel = error code |
| // kEplReject = reject the NMT event |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| tEplKernel PUBLIC EplNmtMnuCbCheckEvent(tEplNmtEvent NmtEvent_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtuProcessEvent |
| // |
| // Description: processes events from event queue |
| // |
| // Parameters: pEvent_p = pointer to event |
| // |
| // Returns: tEplKernel = errorcode |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| EPLDLLEXPORT tEplKernel PUBLIC EplNmtMnuProcessEvent(tEplEvent * pEvent_p) |
| { |
| tEplKernel Ret; |
| |
| Ret = kEplSuccessful; |
| |
| // process event |
| switch (pEvent_p->m_EventType) { |
| // timer event |
| case kEplEventTypeTimer: |
| { |
| tEplTimerEventArg *pTimerEventArg = |
| (tEplTimerEventArg *) pEvent_p->m_pArg; |
| unsigned int uiNodeId; |
| |
| uiNodeId = |
| (unsigned int)(pTimerEventArg-> |
| m_ulArg & |
| EPL_NMTMNU_TIMERARG_NODE_MASK); |
| if (uiNodeId != 0) { |
| tEplObdSize ObdSize; |
| BYTE bNmtState; |
| tEplNmtMnuNodeInfo *pNodeInfo; |
| |
| pNodeInfo = EPL_NMTMNU_GET_NODEINFO(uiNodeId); |
| |
| ObdSize = 1; |
| Ret = |
| EplObduReadEntry(0x1F8E, uiNodeId, |
| &bNmtState, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| break; |
| } |
| |
| if ((pTimerEventArg-> |
| m_ulArg & EPL_NMTMNU_TIMERARG_IDENTREQ) != |
| 0L) { |
| if ((pNodeInfo-> |
| m_wFlags & |
| EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) |
| != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR)) { // this is an old (already deleted or modified) timer |
| // but not the current timer |
| // so discard it |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE |
| (kEplNmtMnuIntNodeEventTimerIdentReq, |
| uiNodeId, |
| ((pNodeInfo-> |
| m_NodeState << 8) |
| | 0xFF)); |
| |
| break; |
| } |
| /* |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerIdentReq, |
| uiNodeId, |
| ((pNodeInfo->m_NodeState << 8) |
| | 0x80 |
| | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6) |
| | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8))); |
| */ |
| Ret = |
| EplNmtMnuProcessInternalEvent |
| (uiNodeId, |
| (tEplNmtState) (bNmtState | |
| EPL_NMT_TYPE_CS), |
| EPL_E_NO_ERROR, |
| kEplNmtMnuIntNodeEventTimerIdentReq); |
| } |
| |
| else if ((pTimerEventArg-> |
| m_ulArg & EPL_NMTMNU_TIMERARG_STATREQ) |
| != 0L) { |
| if ((pNodeInfo-> |
| m_wFlags & |
| EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) |
| != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR)) { // this is an old (already deleted or modified) timer |
| // but not the current timer |
| // so discard it |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE |
| (kEplNmtMnuIntNodeEventTimerStatReq, |
| uiNodeId, |
| ((pNodeInfo-> |
| m_NodeState << 8) |
| | 0xFF)); |
| |
| break; |
| } |
| /* |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq, |
| uiNodeId, |
| ((pNodeInfo->m_NodeState << 8) |
| | 0x80 |
| | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6) |
| | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8))); |
| */ |
| Ret = |
| EplNmtMnuProcessInternalEvent |
| (uiNodeId, |
| (tEplNmtState) (bNmtState | |
| EPL_NMT_TYPE_CS), |
| EPL_E_NO_ERROR, |
| kEplNmtMnuIntNodeEventTimerStatReq); |
| } |
| |
| else if ((pTimerEventArg-> |
| m_ulArg & |
| EPL_NMTMNU_TIMERARG_STATE_MON) != |
| 0L) { |
| if ((pNodeInfo-> |
| m_wFlags & |
| EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) |
| != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR)) { // this is an old (already deleted or modified) timer |
| // but not the current timer |
| // so discard it |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE |
| (kEplNmtMnuIntNodeEventTimerStateMon, |
| uiNodeId, |
| ((pNodeInfo-> |
| m_NodeState << 8) |
| | 0xFF)); |
| |
| break; |
| } |
| /* |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq, |
| uiNodeId, |
| ((pNodeInfo->m_NodeState << 8) |
| | 0x80 |
| | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6) |
| | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8))); |
| */ |
| Ret = |
| EplNmtMnuProcessInternalEvent |
| (uiNodeId, |
| (tEplNmtState) (bNmtState | |
| EPL_NMT_TYPE_CS), |
| EPL_E_NO_ERROR, |
| kEplNmtMnuIntNodeEventTimerStateMon); |
| } |
| |
| else if ((pTimerEventArg-> |
| m_ulArg & EPL_NMTMNU_TIMERARG_LONGER) |
| != 0L) { |
| if ((pNodeInfo-> |
| m_wFlags & |
| EPL_NMTMNU_NODE_FLAG_COUNT_LONGER) |
| != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_LO)) { // this is an old (already deleted or modified) timer |
| // but not the current timer |
| // so discard it |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE |
| (kEplNmtMnuIntNodeEventTimerLonger, |
| uiNodeId, |
| ((pNodeInfo-> |
| m_NodeState << 8) |
| | 0xFF)); |
| |
| break; |
| } |
| /* |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerLonger, |
| uiNodeId, |
| ((pNodeInfo->m_NodeState << 8) |
| | 0x80 |
| | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER) >> 6) |
| | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_LO) >> 8))); |
| */ |
| Ret = |
| EplNmtMnuProcessInternalEvent |
| (uiNodeId, |
| (tEplNmtState) (bNmtState | |
| EPL_NMT_TYPE_CS), |
| EPL_E_NO_ERROR, |
| kEplNmtMnuIntNodeEventTimerLonger); |
| } |
| |
| } else { // global timer event |
| } |
| break; |
| } |
| |
| case kEplEventTypeHeartbeat: |
| { |
| tEplHeartbeatEvent *pHeartbeatEvent = |
| (tEplHeartbeatEvent *) pEvent_p->m_pArg; |
| |
| Ret = |
| EplNmtMnuProcessInternalEvent(pHeartbeatEvent-> |
| m_uiNodeId, |
| pHeartbeatEvent-> |
| m_NmtState, |
| pHeartbeatEvent-> |
| m_wErrorCode, |
| kEplNmtMnuIntNodeEventHeartbeat); |
| break; |
| } |
| |
| case kEplEventTypeNmtMnuNmtCmdSent: |
| { |
| tEplFrame *pFrame = (tEplFrame *) pEvent_p->m_pArg; |
| unsigned int uiNodeId; |
| tEplNmtCommand NmtCommand; |
| BYTE bNmtState; |
| |
| uiNodeId = AmiGetByteFromLe(&pFrame->m_le_bDstNodeId); |
| NmtCommand = |
| (tEplNmtCommand) AmiGetByteFromLe(&pFrame->m_Data. |
| m_Asnd.m_Payload. |
| m_NmtCommandService. |
| m_le_bNmtCommandId); |
| |
| switch (NmtCommand) { |
| case kEplNmtCmdStartNode: |
| bNmtState = |
| (BYTE) (kEplNmtCsOperational & 0xFF); |
| break; |
| |
| case kEplNmtCmdStopNode: |
| bNmtState = (BYTE) (kEplNmtCsStopped & 0xFF); |
| break; |
| |
| case kEplNmtCmdEnterPreOperational2: |
| bNmtState = |
| (BYTE) (kEplNmtCsPreOperational2 & 0xFF); |
| break; |
| |
| case kEplNmtCmdEnableReadyToOperate: |
| // d.k. do not change expected node state, because of DS 1.0.0 7.3.1.2.1 Plain NMT State Command |
| // and because node may not change NMT state within EPL_C_NMT_STATE_TOLERANCE |
| bNmtState = |
| (BYTE) (kEplNmtCsPreOperational2 & 0xFF); |
| break; |
| |
| case kEplNmtCmdResetNode: |
| case kEplNmtCmdResetCommunication: |
| case kEplNmtCmdResetConfiguration: |
| case kEplNmtCmdSwReset: |
| bNmtState = (BYTE) (kEplNmtCsNotActive & 0xFF); |
| // EplNmtMnuProcessInternalEvent() sets internal node state to kEplNmtMnuNodeStateUnknown |
| // after next unresponded IdentRequest/StatusRequest |
| break; |
| |
| default: |
| goto Exit; |
| } |
| |
| // process as internal event which update expected NMT state in OD |
| if (uiNodeId != EPL_C_ADR_BROADCAST) { |
| Ret = EplNmtMnuProcessInternalEvent(uiNodeId, |
| (tEplNmtState) |
| (bNmtState | |
| EPL_NMT_TYPE_CS), |
| 0, |
| kEplNmtMnuIntNodeEventNmtCmdSent); |
| |
| } else { // process internal event for all active nodes (except myself) |
| |
| for (uiNodeId = 1; |
| uiNodeId <= |
| tabentries(EplNmtMnuInstance_g. |
| m_aNodeInfo); uiNodeId++) { |
| if ((EPL_NMTMNU_GET_NODEINFO(uiNodeId)-> |
| m_dwNodeCfg & |
| (EPL_NODEASSIGN_NODE_IS_CN | |
| EPL_NODEASSIGN_NODE_EXISTS)) != |
| 0) { |
| Ret = |
| EplNmtMnuProcessInternalEvent |
| (uiNodeId, |
| (tEplNmtState) (bNmtState | |
| EPL_NMT_TYPE_CS), |
| 0, |
| kEplNmtMnuIntNodeEventNmtCmdSent); |
| |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| } |
| } |
| } |
| |
| break; |
| } |
| |
| default: |
| { |
| Ret = kEplNmtInvalidEvent; |
| } |
| |
| } |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuGetRunningTimerStatReq |
| // |
| // Description: returns a bit field with running StatReq timers |
| // just for debugging purposes |
| // |
| // Parameters: (none) |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| tEplKernel PUBLIC EplNmtMnuGetDiagnosticInfo(unsigned int |
| *puiMandatorySlaveCount_p, |
| unsigned int |
| *puiSignalSlaveCount_p, |
| WORD * pwFlags_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| |
| if ((puiMandatorySlaveCount_p == NULL) |
| || (puiSignalSlaveCount_p == NULL) |
| || (pwFlags_p == NULL)) { |
| Ret = kEplNmtInvalidParam; |
| goto Exit; |
| } |
| |
| *puiMandatorySlaveCount_p = EplNmtMnuInstance_g.m_uiMandatorySlaveCount; |
| *puiSignalSlaveCount_p = EplNmtMnuInstance_g.m_uiSignalSlaveCount; |
| *pwFlags_p = EplNmtMnuInstance_g.m_wFlags; |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuGetRunningTimerStatReq |
| // |
| // Description: returns a bit field with running StatReq timers |
| // just for debugging purposes |
| // |
| // Parameters: (none) |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| /* |
| DWORD EplNmtMnuGetRunningTimerStatReq(void) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| unsigned int uiIndex; |
| tEplNmtMnuNodeInfo* pNodeInfo; |
| |
| pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo; |
| for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++) |
| { |
| if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateConfigured) |
| { |
| // reset flag "scanned once" |
| pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_SCANNED; |
| |
| Ret = EplNmtMnuNodeBootStep2(uiIndex, pNodeInfo); |
| if (Ret != kEplSuccessful) |
| { |
| goto Exit; |
| } |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount++; |
| // signal slave counter shall be decremented if StatusRequest was sent once to a CN |
| // mandatory slave counter shall be decremented if mandatory CN is ReadyToOp |
| } |
| } |
| |
| Exit: |
| return Ret; |
| } |
| */ |
| |
| //=========================================================================// |
| // // |
| // P R I V A T E F U N C T I O N S // |
| // // |
| //=========================================================================// |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuCbNmtRequest |
| // |
| // Description: callback funktion for NmtRequest |
| // |
| // Parameters: pFrameInfo_p = Frame with the NmtRequest |
| // |
| // Returns: tEplKernel = error code |
| // |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel PUBLIC EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| |
| // $$$ perform NMTRequest |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuCbIdentResponse |
| // |
| // Description: callback funktion for IdentResponse |
| // |
| // Parameters: uiNodeId_p = node ID for which IdentReponse was received |
| // pIdentResponse_p = pointer to IdentResponse |
| // is NULL if node did not answer |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel PUBLIC EplNmtMnuCbIdentResponse(unsigned int uiNodeId_p, |
| tEplIdentResponse * |
| pIdentResponse_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| |
| if (pIdentResponse_p == NULL) { // node did not answer |
| Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p, kEplNmtCsNotActive, EPL_E_NMT_NO_IDENT_RES, // was EPL_E_NO_ERROR |
| kEplNmtMnuIntNodeEventNoIdentResponse); |
| } else { // node answered IdentRequest |
| tEplObdSize ObdSize; |
| DWORD dwDevType; |
| WORD wErrorCode = EPL_E_NO_ERROR; |
| tEplNmtState NmtState = |
| (tEplNmtState) (AmiGetByteFromLe |
| (&pIdentResponse_p-> |
| m_le_bNmtStatus) | EPL_NMT_TYPE_CS); |
| |
| // check IdentResponse $$$ move to ProcessIntern, because this function may be called also if CN |
| |
| // check DeviceType (0x1F84) |
| ObdSize = 4; |
| Ret = |
| EplObduReadEntry(0x1F84, uiNodeId_p, &dwDevType, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| if (dwDevType != 0L) { // actually compare it with DeviceType from IdentResponse |
| if (AmiGetDwordFromLe(&pIdentResponse_p->m_le_dwDeviceType) != dwDevType) { // wrong DeviceType |
| NmtState = kEplNmtCsNotActive; |
| wErrorCode = EPL_E_NMT_BPO1_DEVICE_TYPE; |
| } |
| } |
| |
| Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p, |
| NmtState, |
| wErrorCode, |
| kEplNmtMnuIntNodeEventIdentResponse); |
| } |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuCbStatusResponse |
| // |
| // Description: callback funktion for StatusResponse |
| // |
| // Parameters: uiNodeId_p = node ID for which IdentReponse was received |
| // pIdentResponse_p = pointer to IdentResponse |
| // is NULL if node did not answer |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel PUBLIC EplNmtMnuCbStatusResponse(unsigned int uiNodeId_p, |
| tEplStatusResponse * |
| pStatusResponse_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| |
| if (pStatusResponse_p == NULL) { // node did not answer |
| Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p, kEplNmtCsNotActive, EPL_E_NMT_NO_STATUS_RES, // was EPL_E_NO_ERROR |
| kEplNmtMnuIntNodeEventNoStatusResponse); |
| } else { // node answered StatusRequest |
| Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p, |
| (tEplNmtState) |
| (AmiGetByteFromLe |
| (&pStatusResponse_p-> |
| m_le_bNmtStatus) | |
| EPL_NMT_TYPE_CS), |
| EPL_E_NO_ERROR, |
| kEplNmtMnuIntNodeEventStatusResponse); |
| } |
| |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuStartBootStep1 |
| // |
| // Description: starts BootStep1 |
| // |
| // Parameters: (none) |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel EplNmtMnuStartBootStep1(void) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| unsigned int uiSubIndex; |
| unsigned int uiLocalNodeId; |
| DWORD dwNodeCfg; |
| tEplObdSize ObdSize; |
| |
| // $$$ d.k.: save current time for 0x1F89/2 MNTimeoutPreOp1_U32 |
| |
| // start network scan |
| EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0; |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0; |
| // check 0x1F81 |
| uiLocalNodeId = EplObduGetNodeId(); |
| for (uiSubIndex = 1; uiSubIndex <= 254; uiSubIndex++) { |
| ObdSize = 4; |
| Ret = |
| EplObduReadEntry(0x1F81, uiSubIndex, &dwNodeCfg, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| if (uiSubIndex != uiLocalNodeId) { |
| // reset flags "not scanned" and "isochronous" |
| EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_wFlags &= |
| ~(EPL_NMTMNU_NODE_FLAG_ISOCHRON | |
| EPL_NMTMNU_NODE_FLAG_NOT_SCANNED); |
| |
| if (uiSubIndex == EPL_C_ADR_DIAG_DEF_NODE_ID) { // diagnostic node must be scanned by MN in any case |
| dwNodeCfg |= |
| (EPL_NODEASSIGN_NODE_IS_CN | |
| EPL_NODEASSIGN_NODE_EXISTS); |
| // and it must be isochronously accessed |
| dwNodeCfg &= ~EPL_NODEASSIGN_ASYNCONLY_NODE; |
| } |
| // save node config in local node info structure |
| EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_dwNodeCfg = |
| dwNodeCfg; |
| EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_NodeState = |
| kEplNmtMnuNodeStateUnknown; |
| |
| if ((dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN | EPL_NODEASSIGN_NODE_EXISTS)) != 0) { // node is configured as CN |
| // identify the node |
| Ret = |
| EplIdentuRequestIdentResponse(uiSubIndex, |
| EplNmtMnuCbIdentResponse); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| // set flag "not scanned" |
| EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_wFlags |= |
| EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount++; |
| // signal slave counter shall be decremented if IdentRequest was sent once to a CN |
| |
| if ((dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN |
| EplNmtMnuInstance_g. |
| m_uiMandatorySlaveCount++; |
| // mandatory slave counter shall be decremented if mandatory CN was configured successfully |
| } |
| } |
| } else { // subindex of MN |
| if ((dwNodeCfg & (EPL_NODEASSIGN_MN_PRES | EPL_NODEASSIGN_NODE_EXISTS)) != 0) { // MN shall send PRes |
| tEplDllNodeInfo DllNodeInfo; |
| |
| EPL_MEMSET(&DllNodeInfo, 0, |
| sizeof(DllNodeInfo)); |
| DllNodeInfo.m_uiNodeId = uiLocalNodeId; |
| |
| Ret = EplDlluCalAddNode(&DllNodeInfo); |
| } |
| } |
| } |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuStartBootStep2 |
| // |
| // Description: starts BootStep2. |
| // That means add nodes to isochronous phase and send |
| // NMT EnableReadyToOp. |
| // |
| // Parameters: (none) |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel EplNmtMnuStartBootStep2(void) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| unsigned int uiIndex; |
| tEplNmtMnuNodeInfo *pNodeInfo; |
| |
| if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0) { // boot process is not halted |
| // add nodes to isochronous phase and send NMT EnableReadyToOp |
| EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0; |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0; |
| // reset flag that application was informed about possible state change |
| EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED; |
| |
| pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo; |
| for (uiIndex = 1; |
| uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); |
| uiIndex++, pNodeInfo++) { |
| if (pNodeInfo->m_NodeState == |
| kEplNmtMnuNodeStateConfigured) { |
| Ret = |
| EplNmtMnuNodeBootStep2(uiIndex, pNodeInfo); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| // set flag "not scanned" |
| pNodeInfo->m_wFlags |= |
| EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount++; |
| // signal slave counter shall be decremented if StatusRequest was sent once to a CN |
| |
| if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN |
| EplNmtMnuInstance_g. |
| m_uiMandatorySlaveCount++; |
| } |
| // mandatory slave counter shall be decremented if mandatory CN is ReadyToOp |
| } |
| } |
| } |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuNodeBootStep2 |
| // |
| // Description: starts BootStep2 for the specified node. |
| // This means the CN is added to isochronous phase if not |
| // async-only and it gets the NMT command EnableReadyToOp. |
| // The CN must be in node state Configured, when it enters |
| // BootStep2. When BootStep2 finishes, the CN is in node state |
| // ReadyToOp. |
| // If TimeoutReadyToOp in object 0x1F89/5 is configured, |
| // TimerHdlLonger will be started with this timeout. |
| // |
| // Parameters: uiNodeId_p = node ID |
| // pNodeInfo_p = pointer to internal node info structure |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p, |
| tEplNmtMnuNodeInfo * pNodeInfo_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| tEplDllNodeInfo DllNodeInfo; |
| DWORD dwNodeCfg; |
| tEplObdSize ObdSize; |
| tEplTimerArg TimerArg; |
| |
| dwNodeCfg = pNodeInfo_p->m_dwNodeCfg; |
| if ((dwNodeCfg & EPL_NODEASSIGN_ASYNCONLY_NODE) == 0) { // add node to isochronous phase |
| DllNodeInfo.m_uiNodeId = uiNodeId_p; |
| ObdSize = 4; |
| Ret = |
| EplObduReadEntry(0x1F92, uiNodeId_p, |
| &DllNodeInfo.m_dwPresTimeout, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| ObdSize = 2; |
| Ret = |
| EplObduReadEntry(0x1F8B, uiNodeId_p, |
| &DllNodeInfo.m_wPreqPayloadLimit, |
| &ObdSize); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| ObdSize = 2; |
| Ret = |
| EplObduReadEntry(0x1F8D, uiNodeId_p, |
| &DllNodeInfo.m_wPresPayloadLimit, |
| &ObdSize); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| pNodeInfo_p->m_wFlags |= EPL_NMTMNU_NODE_FLAG_ISOCHRON; |
| |
| Ret = EplDlluCalAddNode(&DllNodeInfo); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| } |
| |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(0, |
| uiNodeId_p, |
| kEplNmtCmdEnableReadyToOperate); |
| |
| Ret = |
| EplNmtMnuSendNmtCommand(uiNodeId_p, kEplNmtCmdEnableReadyToOperate); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| if (EplNmtMnuInstance_g.m_ulTimeoutReadyToOp != 0L) { // start timer |
| // when the timer expires the CN must be ReadyToOp |
| EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(pNodeInfo_p, uiNodeId_p, |
| TimerArg); |
| // TimerArg.m_EventSink = kEplEventSinkNmtMnu; |
| // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p; |
| Ret = |
| EplTimeruModifyTimerMs(&pNodeInfo_p->m_TimerHdlLonger, |
| EplNmtMnuInstance_g. |
| m_ulTimeoutReadyToOp, TimerArg); |
| } |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuStartCheckCom |
| // |
| // Description: starts CheckCommunication |
| // |
| // Parameters: (none) |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel EplNmtMnuStartCheckCom(void) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| unsigned int uiIndex; |
| tEplNmtMnuNodeInfo *pNodeInfo; |
| |
| if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0) { // boot process is not halted |
| // wait some time and check that no communication error occurs |
| EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0; |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0; |
| // reset flag that application was informed about possible state change |
| EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED; |
| |
| pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo; |
| for (uiIndex = 1; |
| uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); |
| uiIndex++, pNodeInfo++) { |
| if (pNodeInfo->m_NodeState == |
| kEplNmtMnuNodeStateReadyToOp) { |
| Ret = EplNmtMnuNodeCheckCom(uiIndex, pNodeInfo); |
| if (Ret == kEplReject) { // timer was started |
| // wait until it expires |
| if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN |
| EplNmtMnuInstance_g. |
| m_uiMandatorySlaveCount++; |
| } |
| } else if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| // set flag "not scanned" |
| pNodeInfo->m_wFlags |= |
| EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount++; |
| // signal slave counter shall be decremented if timeout elapsed and regardless of an error |
| // mandatory slave counter shall be decremented if timeout elapsed and no error occured |
| } |
| } |
| } |
| |
| Ret = kEplSuccessful; |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuNodeCheckCom |
| // |
| // Description: checks communication of the specified node. |
| // That means wait some time and if no error occured everything |
| // is OK. |
| // |
| // Parameters: uiNodeId_p = node ID |
| // pNodeInfo_p = pointer to internal node info structure |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p, |
| tEplNmtMnuNodeInfo * pNodeInfo_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| DWORD dwNodeCfg; |
| tEplTimerArg TimerArg; |
| |
| dwNodeCfg = pNodeInfo_p->m_dwNodeCfg; |
| if (((dwNodeCfg & EPL_NODEASSIGN_ASYNCONLY_NODE) == 0) |
| && (EplNmtMnuInstance_g.m_ulTimeoutCheckCom != 0L)) { // CN is not async-only and timeout for CheckCom was set |
| |
| // check communication, |
| // that means wait some time and if no error occured everything is OK; |
| |
| // start timer (when the timer expires the CN must be still ReadyToOp) |
| EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(pNodeInfo_p, uiNodeId_p, |
| TimerArg); |
| // TimerArg.m_EventSink = kEplEventSinkNmtMnu; |
| // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p; |
| Ret = |
| EplTimeruModifyTimerMs(&pNodeInfo_p->m_TimerHdlLonger, |
| EplNmtMnuInstance_g. |
| m_ulTimeoutCheckCom, TimerArg); |
| |
| // update mandatory slave counter, because timer was started |
| if (Ret == kEplSuccessful) { |
| Ret = kEplReject; |
| } |
| } else { // timer was not started |
| // assume everything is OK |
| pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateComChecked; |
| } |
| |
| //Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuStartNodes |
| // |
| // Description: really starts all nodes which are ReadyToOp and CheckCom did not fail |
| // |
| // Parameters: (none) |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel EplNmtMnuStartNodes(void) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| unsigned int uiIndex; |
| tEplNmtMnuNodeInfo *pNodeInfo; |
| |
| if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0) { // boot process is not halted |
| // send NMT command Start Node |
| EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0; |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0; |
| // reset flag that application was informed about possible state change |
| EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED; |
| |
| pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo; |
| for (uiIndex = 1; |
| uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); |
| uiIndex++, pNodeInfo++) { |
| if (pNodeInfo->m_NodeState == |
| kEplNmtMnuNodeStateComChecked) { |
| if ((EplNmtMnuInstance_g. |
| m_dwNmtStartup & EPL_NMTST_STARTALLNODES) |
| == 0) { |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(0, |
| uiIndex, |
| kEplNmtCmdStartNode); |
| |
| Ret = |
| EplNmtMnuSendNmtCommand(uiIndex, |
| kEplNmtCmdStartNode); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| } |
| |
| if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN |
| EplNmtMnuInstance_g. |
| m_uiMandatorySlaveCount++; |
| } |
| // set flag "not scanned" |
| pNodeInfo->m_wFlags |= |
| EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount++; |
| // signal slave counter shall be decremented if StatusRequest was sent once to a CN |
| // mandatory slave counter shall be decremented if mandatory CN is OPERATIONAL |
| } |
| } |
| |
| // $$$ inform application if EPL_NMTST_NO_STARTNODE is set |
| |
| if ((EplNmtMnuInstance_g. |
| m_dwNmtStartup & EPL_NMTST_STARTALLNODES) != 0) { |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(0, EPL_C_ADR_BROADCAST, |
| kEplNmtCmdStartNode); |
| |
| Ret = |
| EplNmtMnuSendNmtCommand(EPL_C_ADR_BROADCAST, |
| kEplNmtCmdStartNode); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| } |
| } |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuProcessInternalEvent |
| // |
| // Description: processes internal node events |
| // |
| // Parameters: uiNodeId_p = node ID |
| // NodeNmtState_p = NMT state of CN |
| // NodeEvent_p = occured events |
| // |
| // Returns: tEplKernel = error code |
| // |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel EplNmtMnuProcessInternalEvent(unsigned int uiNodeId_p, |
| tEplNmtState NodeNmtState_p, |
| WORD wErrorCode_p, |
| tEplNmtMnuIntNodeEvent |
| NodeEvent_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| tEplNmtState NmtState; |
| tEplNmtMnuNodeInfo *pNodeInfo; |
| tEplTimerArg TimerArg; |
| |
| pNodeInfo = EPL_NMTMNU_GET_NODEINFO(uiNodeId_p); |
| NmtState = EplNmtuGetNmtState(); |
| if (NmtState <= kEplNmtMsNotActive) { // MN is not active |
| goto Exit; |
| } |
| |
| switch (NodeEvent_p) { |
| case kEplNmtMnuIntNodeEventIdentResponse: |
| { |
| BYTE bNmtState; |
| |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p, |
| uiNodeId_p, |
| pNodeInfo->m_NodeState); |
| |
| if (pNodeInfo->m_NodeState != |
| kEplNmtMnuNodeStateResetConf) { |
| pNodeInfo->m_NodeState = |
| kEplNmtMnuNodeStateIdentified; |
| } |
| // reset flags ISOCHRON and NMT_CMD_ISSUED |
| pNodeInfo->m_wFlags &= ~(EPL_NMTMNU_NODE_FLAG_ISOCHRON |
| | |
| EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED); |
| |
| if ((NmtState == kEplNmtMsPreOperational1) |
| && |
| ((pNodeInfo-> |
| m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != |
| 0)) { |
| // decrement only signal slave count |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount--; |
| pNodeInfo->m_wFlags &= |
| ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| } |
| // update object 0x1F8F NMT_MNNodeExpState_AU8 to PreOp1 (even if local state >= PreOp2) |
| bNmtState = (BYTE) (kEplNmtCsPreOperational1 & 0xFF); |
| Ret = |
| EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState, |
| 1); |
| |
| // check NMT state of CN |
| Ret = |
| EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, |
| NodeNmtState_p, wErrorCode_p, |
| NmtState); |
| if (Ret != kEplSuccessful) { |
| if (Ret == kEplReject) { |
| Ret = kEplSuccessful; |
| } |
| break; |
| } |
| // request StatusResponse immediately, |
| // because we want a fast boot-up of CNs |
| Ret = |
| EplStatusuRequestStatusResponse(uiNodeId_p, |
| EplNmtMnuCbStatusResponse); |
| if (Ret != kEplSuccessful) { |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p, |
| uiNodeId_p, |
| Ret); |
| |
| if (Ret == kEplInvalidOperation) { // the only situation when this should happen is, when |
| // StatusResponse was already requested from within |
| // the StatReq timer event. |
| // so ignore this error. |
| Ret = kEplSuccessful; |
| } else { |
| break; |
| } |
| } |
| |
| if (pNodeInfo->m_NodeState != |
| kEplNmtMnuNodeStateResetConf) { |
| // inform application |
| Ret = |
| EplNmtMnuInstance_g. |
| m_pfnCbNodeEvent(uiNodeId_p, |
| kEplNmtNodeEventFound, |
| NodeNmtState_p, |
| EPL_E_NO_ERROR, |
| (pNodeInfo-> |
| m_dwNodeCfg & |
| EPL_NODEASSIGN_MANDATORY_CN) |
| != 0); |
| if (Ret == kEplReject) { // interrupt boot process on user request |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE |
| (NodeEvent_p, uiNodeId_p, |
| ((pNodeInfo->m_NodeState << 8) |
| | Ret)); |
| |
| Ret = kEplSuccessful; |
| break; |
| } else if (Ret != kEplSuccessful) { |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE |
| (NodeEvent_p, uiNodeId_p, |
| ((pNodeInfo->m_NodeState << 8) |
| | Ret)); |
| |
| break; |
| } |
| } |
| // continue BootStep1 |
| } |
| |
| case kEplNmtMnuIntNodeEventBoot: |
| { |
| |
| // $$$ check identification (vendor ID, product code, revision no, serial no) |
| |
| if (pNodeInfo->m_NodeState == |
| kEplNmtMnuNodeStateIdentified) { |
| // $$$ check software |
| |
| // check/start configuration |
| // inform application |
| Ret = |
| EplNmtMnuInstance_g. |
| m_pfnCbNodeEvent(uiNodeId_p, |
| kEplNmtNodeEventCheckConf, |
| NodeNmtState_p, |
| EPL_E_NO_ERROR, |
| (pNodeInfo-> |
| m_dwNodeCfg & |
| EPL_NODEASSIGN_MANDATORY_CN) |
| != 0); |
| if (Ret == kEplReject) { // interrupt boot process on user request |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE |
| (kEplNmtMnuIntNodeEventBoot, |
| uiNodeId_p, |
| ((pNodeInfo->m_NodeState << 8) |
| | Ret)); |
| |
| Ret = kEplSuccessful; |
| break; |
| } else if (Ret != kEplSuccessful) { |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE |
| (kEplNmtMnuIntNodeEventBoot, |
| uiNodeId_p, |
| ((pNodeInfo->m_NodeState << 8) |
| | Ret)); |
| |
| break; |
| } |
| } else if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf) { // wrong CN state |
| // ignore event |
| break; |
| } |
| // $$$ d.k.: currently we assume configuration is OK |
| |
| // continue BootStep1 |
| } |
| |
| case kEplNmtMnuIntNodeEventConfigured: |
| { |
| if ((pNodeInfo->m_NodeState != |
| kEplNmtMnuNodeStateIdentified) |
| && (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)) { // wrong CN state |
| // ignore event |
| break; |
| } |
| |
| pNodeInfo->m_NodeState = kEplNmtMnuNodeStateConfigured; |
| |
| if (NmtState == kEplNmtMsPreOperational1) { |
| if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // decrement mandatory CN counter |
| EplNmtMnuInstance_g. |
| m_uiMandatorySlaveCount--; |
| } |
| } else { |
| // put optional node to next step (BootStep2) |
| Ret = |
| EplNmtMnuNodeBootStep2(uiNodeId_p, |
| pNodeInfo); |
| } |
| break; |
| } |
| |
| case kEplNmtMnuIntNodeEventNoIdentResponse: |
| { |
| if ((NmtState == kEplNmtMsPreOperational1) |
| && |
| ((pNodeInfo-> |
| m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != |
| 0)) { |
| // decrement only signal slave count |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount--; |
| pNodeInfo->m_wFlags &= |
| ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| } |
| |
| if (pNodeInfo->m_NodeState != |
| kEplNmtMnuNodeStateResetConf) { |
| pNodeInfo->m_NodeState = |
| kEplNmtMnuNodeStateUnknown; |
| } |
| // $$$ d.k. check start time for 0x1F89/2 MNTimeoutPreOp1_U32 |
| // $$$ d.k. check individual timeout 0x1F89/6 MNIdentificationTimeout_U32 |
| // if mandatory node and timeout elapsed -> halt boot procedure |
| // trigger IdentRequest again (if >= PreOp2, after delay) |
| if (NmtState >= kEplNmtMsPreOperational2) { // start timer |
| EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ |
| (pNodeInfo, uiNodeId_p, TimerArg); |
| // TimerArg.m_EventSink = kEplEventSinkNmtMnu; |
| // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_IDENTREQ | uiNodeId_p; |
| /* |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventNoIdentResponse, |
| uiNodeId_p, |
| ((pNodeInfo->m_NodeState << 8) |
| | 0x80 |
| | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6) |
| | ((TimerArg.m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8))); |
| */ |
| Ret = |
| EplTimeruModifyTimerMs(&pNodeInfo-> |
| m_TimerHdlStatReq, |
| EplNmtMnuInstance_g. |
| m_ulStatusRequestDelay, |
| TimerArg); |
| } else { // trigger IdentRequest immediately |
| Ret = |
| EplIdentuRequestIdentResponse(uiNodeId_p, |
| EplNmtMnuCbIdentResponse); |
| } |
| break; |
| } |
| |
| case kEplNmtMnuIntNodeEventStatusResponse: |
| { |
| if ((NmtState >= kEplNmtMsPreOperational2) |
| && |
| ((pNodeInfo-> |
| m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != |
| 0)) { |
| // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount--; |
| pNodeInfo->m_wFlags &= |
| ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| } |
| // check NMT state of CN |
| Ret = |
| EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, |
| NodeNmtState_p, wErrorCode_p, |
| NmtState); |
| if (Ret != kEplSuccessful) { |
| if (Ret == kEplReject) { |
| Ret = kEplSuccessful; |
| } |
| break; |
| } |
| |
| if (NmtState == kEplNmtMsPreOperational1) { |
| // request next StatusResponse immediately |
| Ret = |
| EplStatusuRequestStatusResponse(uiNodeId_p, |
| EplNmtMnuCbStatusResponse); |
| if (Ret != kEplSuccessful) { |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE |
| (NodeEvent_p, uiNodeId_p, Ret); |
| } |
| |
| } else if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_ISOCHRON) == 0) { // start timer |
| // not isochronously accessed CN (e.g. async-only or stopped CN) |
| EPL_NMTMNU_SET_FLAGS_TIMERARG_STATREQ(pNodeInfo, |
| uiNodeId_p, |
| TimerArg); |
| // TimerArg.m_EventSink = kEplEventSinkNmtMnu; |
| // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_STATREQ | uiNodeId_p; |
| /* |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventStatusResponse, |
| uiNodeId_p, |
| ((pNodeInfo->m_NodeState << 8) |
| | 0x80 |
| | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6) |
| | ((TimerArg.m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8))); |
| */ |
| Ret = |
| EplTimeruModifyTimerMs(&pNodeInfo-> |
| m_TimerHdlStatReq, |
| EplNmtMnuInstance_g. |
| m_ulStatusRequestDelay, |
| TimerArg); |
| } |
| |
| break; |
| } |
| |
| case kEplNmtMnuIntNodeEventNoStatusResponse: |
| { |
| // function CheckNmtState sets node state to unknown if necessary |
| /* |
| if ((NmtState >= kEplNmtMsPreOperational2) |
| && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0)) |
| { |
| // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount--; |
| pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| } |
| */ |
| // check NMT state of CN |
| Ret = |
| EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, |
| NodeNmtState_p, wErrorCode_p, |
| NmtState); |
| if (Ret != kEplSuccessful) { |
| if (Ret == kEplReject) { |
| Ret = kEplSuccessful; |
| } |
| break; |
| } |
| |
| break; |
| } |
| |
| case kEplNmtMnuIntNodeEventError: |
| { // currently only issued on kEplNmtNodeCommandConfErr |
| |
| if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified) { // wrong CN state |
| // ignore event |
| break; |
| } |
| // check NMT state of CN |
| Ret = |
| EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, |
| kEplNmtCsNotActive, |
| wErrorCode_p, NmtState); |
| if (Ret != kEplSuccessful) { |
| if (Ret == kEplReject) { |
| Ret = kEplSuccessful; |
| } |
| break; |
| } |
| |
| break; |
| } |
| |
| case kEplNmtMnuIntNodeEventExecReset: |
| { |
| if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified) { // wrong CN state |
| // ignore event |
| break; |
| } |
| |
| pNodeInfo->m_NodeState = kEplNmtMnuNodeStateResetConf; |
| |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p, |
| uiNodeId_p, |
| (((NodeNmtState_p & |
| 0xFF) << 8) |
| | |
| kEplNmtCmdResetConfiguration)); |
| |
| // send NMT reset configuration to CN for activation of configuration |
| Ret = |
| EplNmtMnuSendNmtCommand(uiNodeId_p, |
| kEplNmtCmdResetConfiguration); |
| |
| break; |
| } |
| |
| case kEplNmtMnuIntNodeEventHeartbeat: |
| { |
| /* |
| if ((NmtState >= kEplNmtMsPreOperational2) |
| && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0)) |
| { |
| // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount--; |
| pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| } |
| */ |
| // check NMT state of CN |
| Ret = |
| EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, |
| NodeNmtState_p, wErrorCode_p, |
| NmtState); |
| if (Ret != kEplSuccessful) { |
| if (Ret == kEplReject) { |
| Ret = kEplSuccessful; |
| } |
| break; |
| } |
| |
| break; |
| } |
| |
| case kEplNmtMnuIntNodeEventTimerIdentReq: |
| { |
| EPL_DBGLVL_NMTMN_TRACE1 |
| ("TimerStatReq->IdentReq(%02X)\n", uiNodeId_p); |
| // trigger IdentRequest again |
| Ret = |
| EplIdentuRequestIdentResponse(uiNodeId_p, |
| EplNmtMnuCbIdentResponse); |
| if (Ret != kEplSuccessful) { |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p, |
| uiNodeId_p, |
| (((NodeNmtState_p & 0xFF) << 8) |
| | Ret)); |
| if (Ret == kEplInvalidOperation) { // this can happen because of a bug in EplTimeruLinuxKernel.c |
| // so ignore this error. |
| Ret = kEplSuccessful; |
| } |
| } |
| |
| break; |
| } |
| |
| case kEplNmtMnuIntNodeEventTimerStateMon: |
| { |
| // reset NMT state change flag |
| // because from now on the CN must have the correct NMT state |
| pNodeInfo->m_wFlags &= |
| ~EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED; |
| |
| // continue with normal StatReq processing |
| } |
| |
| case kEplNmtMnuIntNodeEventTimerStatReq: |
| { |
| EPL_DBGLVL_NMTMN_TRACE1("TimerStatReq->StatReq(%02X)\n", |
| uiNodeId_p); |
| // request next StatusResponse |
| Ret = |
| EplStatusuRequestStatusResponse(uiNodeId_p, |
| EplNmtMnuCbStatusResponse); |
| if (Ret != kEplSuccessful) { |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p, |
| uiNodeId_p, |
| (((NodeNmtState_p & 0xFF) << 8) |
| | Ret)); |
| if (Ret == kEplInvalidOperation) { // the only situation when this should happen is, when |
| // StatusResponse was already requested while processing |
| // event IdentResponse. |
| // so ignore this error. |
| Ret = kEplSuccessful; |
| } |
| } |
| |
| break; |
| } |
| |
| case kEplNmtMnuIntNodeEventTimerLonger: |
| { |
| switch (pNodeInfo->m_NodeState) { |
| case kEplNmtMnuNodeStateConfigured: |
| { // node should be ReadyToOp but it is not |
| |
| // check NMT state which shall be intentionally wrong, so that ERROR_TREATMENT will be started |
| Ret = |
| EplNmtMnuCheckNmtState(uiNodeId_p, |
| pNodeInfo, |
| kEplNmtCsNotActive, |
| EPL_E_NMT_BPO2, |
| NmtState); |
| if (Ret != kEplSuccessful) { |
| if (Ret == kEplReject) { |
| Ret = kEplSuccessful; |
| } |
| break; |
| } |
| |
| break; |
| } |
| |
| case kEplNmtMnuNodeStateReadyToOp: |
| { // CheckCom finished successfully |
| |
| pNodeInfo->m_NodeState = |
| kEplNmtMnuNodeStateComChecked; |
| |
| if ((pNodeInfo-> |
| m_wFlags & |
| EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) |
| != 0) { |
| // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational |
| EplNmtMnuInstance_g. |
| m_uiSignalSlaveCount--; |
| pNodeInfo->m_wFlags &= |
| ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| } |
| |
| if ((pNodeInfo-> |
| m_dwNodeCfg & |
| EPL_NODEASSIGN_MANDATORY_CN) != |
| 0) { |
| // decrement mandatory slave counter |
| EplNmtMnuInstance_g. |
| m_uiMandatorySlaveCount--; |
| } |
| if (NmtState != kEplNmtMsReadyToOperate) { |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE |
| (NodeEvent_p, uiNodeId_p, |
| (((NodeNmtState_p & 0xFF) |
| << 8) |
| | kEplNmtCmdStartNode)); |
| |
| // start optional CN |
| Ret = |
| EplNmtMnuSendNmtCommand |
| (uiNodeId_p, |
| kEplNmtCmdStartNode); |
| } |
| break; |
| } |
| |
| default: |
| { |
| break; |
| } |
| } |
| break; |
| } |
| |
| case kEplNmtMnuIntNodeEventNmtCmdSent: |
| { |
| BYTE bNmtState; |
| |
| // update expected NMT state with the one that results |
| // from the sent NMT command |
| bNmtState = (BYTE) (NodeNmtState_p & 0xFF); |
| |
| // write object 0x1F8F NMT_MNNodeExpState_AU8 |
| Ret = |
| EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState, |
| 1); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| if (NodeNmtState_p == kEplNmtCsNotActive) { // restart processing with IdentRequest |
| EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ |
| (pNodeInfo, uiNodeId_p, TimerArg); |
| } else { // monitor NMT state change with StatusRequest after |
| // the corresponding delay; |
| // until then wrong NMT states will be ignored |
| EPL_NMTMNU_SET_FLAGS_TIMERARG_STATE_MON |
| (pNodeInfo, uiNodeId_p, TimerArg); |
| |
| // set NMT state change flag |
| pNodeInfo->m_wFlags |= |
| EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED; |
| } |
| |
| Ret = |
| EplTimeruModifyTimerMs(&pNodeInfo-> |
| m_TimerHdlStatReq, |
| EplNmtMnuInstance_g. |
| m_ulStatusRequestDelay, |
| TimerArg); |
| |
| // finish processing, because NmtState_p is the expected and not the current state |
| goto Exit; |
| } |
| |
| default: |
| { |
| break; |
| } |
| } |
| |
| // check if network is ready to change local NMT state and this was not done before |
| if ((EplNmtMnuInstance_g.m_wFlags & (EPL_NMTMNU_FLAG_HALTED | EPL_NMTMNU_FLAG_APP_INFORMED)) == 0) { // boot process is not halted |
| switch (NmtState) { |
| case kEplNmtMsPreOperational1: |
| { |
| if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount == |
| 0) |
| && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all optional CNs scanned once and all mandatory CNs configured successfully |
| EplNmtMnuInstance_g.m_wFlags |= |
| EPL_NMTMNU_FLAG_APP_INFORMED; |
| // inform application |
| Ret = |
| EplNmtMnuInstance_g. |
| m_pfnCbBootEvent |
| (kEplNmtBootEventBootStep1Finish, |
| NmtState, EPL_E_NO_ERROR); |
| if (Ret != kEplSuccessful) { |
| if (Ret == kEplReject) { |
| // wait for application |
| Ret = kEplSuccessful; |
| } |
| break; |
| } |
| // enter PreOp2 |
| Ret = |
| EplNmtuNmtEvent |
| (kEplNmtEventAllMandatoryCNIdent); |
| } |
| break; |
| } |
| |
| case kEplNmtMsPreOperational2: |
| { |
| if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount == |
| 0) |
| && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all optional CNs checked once for ReadyToOp and all mandatory CNs are ReadyToOp |
| EplNmtMnuInstance_g.m_wFlags |= |
| EPL_NMTMNU_FLAG_APP_INFORMED; |
| // inform application |
| Ret = |
| EplNmtMnuInstance_g. |
| m_pfnCbBootEvent |
| (kEplNmtBootEventBootStep2Finish, |
| NmtState, EPL_E_NO_ERROR); |
| if (Ret != kEplSuccessful) { |
| if (Ret == kEplReject) { |
| // wait for application |
| Ret = kEplSuccessful; |
| } |
| break; |
| } |
| // enter ReadyToOp |
| Ret = |
| EplNmtuNmtEvent |
| (kEplNmtEventEnterReadyToOperate); |
| } |
| break; |
| } |
| |
| case kEplNmtMsReadyToOperate: |
| { |
| if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount == |
| 0) |
| && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all CNs checked for errorless communication |
| EplNmtMnuInstance_g.m_wFlags |= |
| EPL_NMTMNU_FLAG_APP_INFORMED; |
| // inform application |
| Ret = |
| EplNmtMnuInstance_g. |
| m_pfnCbBootEvent |
| (kEplNmtBootEventCheckComFinish, |
| NmtState, EPL_E_NO_ERROR); |
| if (Ret != kEplSuccessful) { |
| if (Ret == kEplReject) { |
| // wait for application |
| Ret = kEplSuccessful; |
| } |
| break; |
| } |
| // enter Operational |
| Ret = |
| EplNmtuNmtEvent |
| (kEplNmtEventEnterMsOperational); |
| } |
| break; |
| } |
| |
| case kEplNmtMsOperational: |
| { |
| if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount == |
| 0) |
| && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all optional CNs scanned once and all mandatory CNs are OPERATIONAL |
| EplNmtMnuInstance_g.m_wFlags |= |
| EPL_NMTMNU_FLAG_APP_INFORMED; |
| // inform application |
| Ret = |
| EplNmtMnuInstance_g. |
| m_pfnCbBootEvent |
| (kEplNmtBootEventOperational, |
| NmtState, EPL_E_NO_ERROR); |
| if (Ret != kEplSuccessful) { |
| if (Ret == kEplReject) { |
| // ignore error code |
| Ret = kEplSuccessful; |
| } |
| break; |
| } |
| } |
| break; |
| } |
| |
| default: |
| { |
| break; |
| } |
| } |
| } |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuCheckNmtState |
| // |
| // Description: checks the NMT state, i.e. evaluates it with object 0x1F8F |
| // NMT_MNNodeExpState_AU8 and updates object 0x1F8E |
| // NMT_MNNodeCurrState_AU8. |
| // It manipulates m_NodeState in internal node info structure. |
| // |
| // Parameters: uiNodeId_p = node ID |
| // NodeNmtState_p = NMT state of CN |
| // |
| // Returns: tEplKernel = error code |
| // kEplReject = CN was in wrong state and has been reset |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel EplNmtMnuCheckNmtState(unsigned int uiNodeId_p, |
| tEplNmtMnuNodeInfo * pNodeInfo_p, |
| tEplNmtState NodeNmtState_p, |
| WORD wErrorCode_p, |
| tEplNmtState LocalNmtState_p) |
| { |
| tEplKernel Ret = kEplSuccessful; |
| tEplObdSize ObdSize; |
| BYTE bNmtState; |
| BYTE bNmtStatePrev; |
| tEplNmtState ExpNmtState; |
| |
| ObdSize = 1; |
| // read object 0x1F8F NMT_MNNodeExpState_AU8 |
| Ret = EplObduReadEntry(0x1F8F, uiNodeId_p, &bNmtState, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| // compute expected NMT state |
| ExpNmtState = (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS); |
| // compute BYTE of current NMT state |
| bNmtState = ((BYTE) NodeNmtState_p & 0xFF); |
| |
| if (ExpNmtState == kEplNmtCsNotActive) { // ignore the current state, because the CN shall be not active |
| Ret = kEplReject; |
| goto Exit; |
| } else if ((ExpNmtState == kEplNmtCsPreOperational2) |
| && (NodeNmtState_p == kEplNmtCsReadyToOperate)) { // CN switched to ReadyToOp |
| // delete timer for timeout handling |
| Ret = EplTimeruDeleteTimer(&pNodeInfo_p->m_TimerHdlLonger); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateReadyToOp; |
| |
| // update object 0x1F8F NMT_MNNodeExpState_AU8 to ReadyToOp |
| Ret = EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState, 1); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| if ((pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN -> decrement counter |
| EplNmtMnuInstance_g.m_uiMandatorySlaveCount--; |
| } |
| if (LocalNmtState_p >= kEplNmtMsReadyToOperate) { // start procedure CheckCommunication for this node |
| Ret = EplNmtMnuNodeCheckCom(uiNodeId_p, pNodeInfo_p); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| if ((LocalNmtState_p == kEplNmtMsOperational) |
| && (pNodeInfo_p->m_NodeState == |
| kEplNmtMnuNodeStateComChecked)) { |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(0, uiNodeId_p, |
| (((NodeNmtState_p & 0xFF) << 8) |
| | |
| kEplNmtCmdStartNode)); |
| |
| // immediately start optional CN, because communication is always OK (e.g. async-only CN) |
| Ret = |
| EplNmtMnuSendNmtCommand(uiNodeId_p, |
| kEplNmtCmdStartNode); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| } |
| } |
| |
| } else if ((ExpNmtState == kEplNmtCsReadyToOperate) |
| && (NodeNmtState_p == kEplNmtCsOperational)) { // CN switched to OPERATIONAL |
| pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateOperational; |
| |
| if ((pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN -> decrement counter |
| EplNmtMnuInstance_g.m_uiMandatorySlaveCount--; |
| } |
| |
| } else if ((ExpNmtState != NodeNmtState_p) |
| && !((ExpNmtState == kEplNmtCsPreOperational1) |
| && (NodeNmtState_p == kEplNmtCsPreOperational2))) { // CN is not in expected NMT state (without the exceptions above) |
| WORD wbeErrorCode; |
| |
| if ((pNodeInfo_p-> |
| m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0) { |
| // decrement only signal slave count if checked once |
| EplNmtMnuInstance_g.m_uiSignalSlaveCount--; |
| pNodeInfo_p->m_wFlags &= |
| ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED; |
| } |
| |
| if (pNodeInfo_p->m_NodeState == kEplNmtMnuNodeStateUnknown) { // CN is already in state unknown, which means that it got |
| // NMT reset command earlier |
| goto Exit; |
| } |
| // -> CN is in wrong NMT state |
| pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateUnknown; |
| |
| if (wErrorCode_p == 0) { // assume wrong NMT state error |
| if ((pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED) != 0) { // NMT command has been just issued; |
| // ignore wrong NMT state until timer expires; |
| // other errors like LOSS_PRES_TH are still processed |
| goto Exit; |
| } |
| |
| wErrorCode_p = EPL_E_NMT_WRONG_STATE; |
| } |
| |
| BENCHMARK_MOD_07_TOGGLE(9); |
| |
| // $$$ start ERROR_TREATMENT and inform application |
| Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p, |
| kEplNmtNodeEventError, |
| NodeNmtState_p, |
| wErrorCode_p, |
| (pNodeInfo_p-> |
| m_dwNodeCfg & |
| EPL_NODEASSIGN_MANDATORY_CN) |
| != 0); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| |
| EPL_NMTMNU_DBG_POST_TRACE_VALUE(0, |
| uiNodeId_p, |
| (((NodeNmtState_p & 0xFF) << 8) |
| | kEplNmtCmdResetNode)); |
| |
| // reset CN |
| // store error code in NMT command data for diagnostic purpose |
| AmiSetWordToLe(&wbeErrorCode, wErrorCode_p); |
| Ret = |
| EplNmtMnuSendNmtCommandEx(uiNodeId_p, kEplNmtCmdResetNode, |
| &wbeErrorCode, |
| sizeof(wbeErrorCode)); |
| if (Ret == kEplSuccessful) { |
| Ret = kEplReject; |
| } |
| |
| goto Exit; |
| } |
| // check if NMT_MNNodeCurrState_AU8 has to be changed |
| ObdSize = 1; |
| Ret = EplObduReadEntry(0x1F8E, uiNodeId_p, &bNmtStatePrev, &ObdSize); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| if (bNmtState != bNmtStatePrev) { |
| // update object 0x1F8E NMT_MNNodeCurrState_AU8 |
| Ret = EplObduWriteEntry(0x1F8E, uiNodeId_p, &bNmtState, 1); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p, |
| kEplNmtNodeEventNmtState, |
| NodeNmtState_p, |
| wErrorCode_p, |
| (pNodeInfo_p-> |
| m_dwNodeCfg & |
| EPL_NODEASSIGN_MANDATORY_CN) |
| != 0); |
| if (Ret != kEplSuccessful) { |
| goto Exit; |
| } |
| } |
| |
| Exit: |
| return Ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // Function: EplNmtMnuReset |
| // |
| // Description: reset internal structures, e.g. timers |
| // |
| // Parameters: void |
| // |
| // Returns: tEplKernel = error code |
| // |
| // State: |
| // |
| //--------------------------------------------------------------------------- |
| |
| static tEplKernel EplNmtMnuReset(void) |
| { |
| tEplKernel Ret; |
| int iIndex; |
| |
| Ret = EplTimeruDeleteTimer(&EplNmtMnuInstance_g.m_TimerHdlNmtState); |
| |
| for (iIndex = 1; iIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); |
| iIndex++) { |
| // delete timer handles |
| Ret = |
| EplTimeruDeleteTimer(&EPL_NMTMNU_GET_NODEINFO(iIndex)-> |
| m_TimerHdlStatReq); |
| Ret = |
| EplTimeruDeleteTimer(&EPL_NMTMNU_GET_NODEINFO(iIndex)-> |
| m_TimerHdlLonger); |
| } |
| |
| return Ret; |
| } |
| |
| #endif // #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0) |
| |
| // EOF |