1 /****************************************************************************
3 (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4 www.systec-electronic.com
8 Description: source file for NMT-MN-Module
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions
16 1. Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in the
21 documentation and/or other materials provided with the distribution.
23 3. Neither the name of SYSTEC electronic GmbH nor the names of its
24 contributors may be used to endorse or promote products derived
25 from this software without prior written permission. For written
26 permission, please contact info@systec-electronic.com.
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32 COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
34 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
36 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
38 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 POSSIBILITY OF SUCH DAMAGE.
43 If a provision of this License is or becomes illegal, invalid or
44 unenforceable in any jurisdiction, that shall not affect:
45 1. the validity or enforceability in that jurisdiction of any other
46 provision of this License; or
47 2. the validity or enforceability in other jurisdictions of that or
48 any other provision of this License.
50 -------------------------------------------------------------------------
52 $RCSfile: EplNmtMnu.c,v $
56 $Revision: 1.18 $ $Date: 2008/11/19 09:52:24 $
63 -------------------------------------------------------------------------
67 2006/06/09 k.t.: start of the implementation
69 ****************************************************************************/
71 #include "user/EplNmtMnu.h"
72 #include "user/EplTimeru.h"
73 #include "user/EplIdentu.h"
74 #include "user/EplStatusu.h"
75 #include "user/EplObdu.h"
76 #include "user/EplDlluCal.h"
77 #include "Benchmark.h"
79 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
81 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) == 0) && (EPL_OBD_USE_KERNEL == FALSE)
82 #error "EPL NmtMnu module needs EPL module OBDU or OBDK!"
85 //=========================================================================//
87 // P R I V A T E D E F I N I T I O N S //
89 //=========================================================================//
91 //---------------------------------------------------------------------------
93 //---------------------------------------------------------------------------
95 // TracePoint support for realtime-debugging
96 #ifdef _DBG_TRACE_POINTS_
97 void PUBLIC TgtDbgSignalTracePoint (BYTE bTracePointNumber_p);
98 void PUBLIC TgtDbgPostTraceValue (DWORD dwTraceValue_p);
99 #define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p)
100 #define TGT_DBG_POST_TRACE_VALUE(v) TgtDbgPostTraceValue(v)
102 #define TGT_DBG_SIGNAL_TRACE_POINT(p)
103 #define TGT_DBG_POST_TRACE_VALUE(v)
105 #define EPL_NMTMNU_DBG_POST_TRACE_VALUE(Event_p, uiNodeId_p, wErrorCode_p) \
106 TGT_DBG_POST_TRACE_VALUE((kEplEventSinkNmtMnu << 28) | (Event_p << 24) \
107 | (uiNodeId_p << 16) | wErrorCode_p)
110 // defines for flags in node info structure
111 #define EPL_NMTMNU_NODE_FLAG_ISOCHRON 0x0001 // CN is being accessed isochronously
112 #define EPL_NMTMNU_NODE_FLAG_NOT_SCANNED 0x0002 // CN was not scanned once -> decrement SignalCounter and reset flag
113 #define EPL_NMTMNU_NODE_FLAG_HALTED 0x0004 // boot process for this CN is halted
114 #define EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED 0x0008 // NMT command was just issued, wrong NMT states will be tolerated
115 #define EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ 0x0300 // counter for StatusRequest timer handle
116 #define EPL_NMTMNU_NODE_FLAG_COUNT_LONGER 0x0C00 // counter for longer timeouts timer handle
117 #define EPL_NMTMNU_NODE_FLAG_INC_STATREQ 0x0100 // increment for StatusRequest timer handle
118 #define EPL_NMTMNU_NODE_FLAG_INC_LONGER 0x0400 // increment for longer timeouts timer handle
119 // These counters will be incremented at every timer start
120 // and copied to timerarg. When the timer event occures
121 // both will be compared and if unequal the timer event
122 // will be discarded, because it is an old one.
124 // defines for timer arguments to draw a distinction between serveral events
125 #define EPL_NMTMNU_TIMERARG_NODE_MASK 0x000000FFL // mask that contains the node-ID
126 #define EPL_NMTMNU_TIMERARG_IDENTREQ 0x00010000L // timer event is for IdentRequest
127 #define EPL_NMTMNU_TIMERARG_STATREQ 0x00020000L // timer event is for StatusRequest
128 #define EPL_NMTMNU_TIMERARG_LONGER 0x00040000L // timer event is for longer timeouts
129 #define EPL_NMTMNU_TIMERARG_STATE_MON 0x00080000L // timer event for StatusRequest to monitor execution of NMT state changes
130 #define EPL_NMTMNU_TIMERARG_COUNT_SR 0x00000300L // counter for StatusRequest
131 #define EPL_NMTMNU_TIMERARG_COUNT_LO 0x00000C00L // counter for longer timeouts
132 // The counters must have the same position as in the node flags above.
134 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_STATREQ(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
135 pNodeInfo_p->m_wFlags = \
136 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \
137 & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \
138 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
139 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_STATREQ | uiNodeId_p | \
140 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
141 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
143 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
144 pNodeInfo_p->m_wFlags = \
145 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \
146 & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \
147 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
148 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_IDENTREQ | uiNodeId_p | \
149 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
150 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
152 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
153 pNodeInfo_p->m_wFlags = \
154 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_LONGER) \
155 & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER) \
156 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_LONGER); \
157 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p | \
158 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER); \
159 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
161 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_STATE_MON(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
162 pNodeInfo_p->m_wFlags = \
163 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \
164 & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \
165 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
166 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_STATE_MON | uiNodeId_p | \
167 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
168 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
171 // defines for global flags
172 #define EPL_NMTMNU_FLAG_HALTED 0x0001 // boot process is halted
173 #define EPL_NMTMNU_FLAG_APP_INFORMED 0x0002 // application was informed about possible NMT state change
175 // return pointer to node info structure for specified node ID
176 // d.k. may be replaced by special (hash) function if node ID array is smaller than 254
177 #define EPL_NMTMNU_GET_NODEINFO(uiNodeId_p) (&EplNmtMnuInstance_g.m_aNodeInfo[uiNodeId_p - 1])
179 //---------------------------------------------------------------------------
181 //---------------------------------------------------------------------------
185 kEplNmtMnuIntNodeEventNoIdentResponse = 0x00,
186 kEplNmtMnuIntNodeEventIdentResponse = 0x01,
187 kEplNmtMnuIntNodeEventBoot = 0x02,
188 kEplNmtMnuIntNodeEventExecReset = 0x03,
189 kEplNmtMnuIntNodeEventConfigured = 0x04,
190 kEplNmtMnuIntNodeEventNoStatusResponse = 0x05,
191 kEplNmtMnuIntNodeEventStatusResponse = 0x06,
192 kEplNmtMnuIntNodeEventHeartbeat = 0x07,
193 kEplNmtMnuIntNodeEventNmtCmdSent = 0x08,
194 kEplNmtMnuIntNodeEventTimerIdentReq = 0x09,
195 kEplNmtMnuIntNodeEventTimerStatReq = 0x0A,
196 kEplNmtMnuIntNodeEventTimerStateMon = 0x0B,
197 kEplNmtMnuIntNodeEventTimerLonger = 0x0C,
198 kEplNmtMnuIntNodeEventError = 0x0D,
200 } tEplNmtMnuIntNodeEvent;
205 kEplNmtMnuNodeStateUnknown = 0x00,
206 kEplNmtMnuNodeStateIdentified = 0x01,
207 kEplNmtMnuNodeStateResetConf = 0x02, // CN reset after configuration update
208 kEplNmtMnuNodeStateConfigured = 0x03, // BootStep1 completed
209 kEplNmtMnuNodeStateReadyToOp = 0x04, // BootStep2 completed
210 kEplNmtMnuNodeStateComChecked = 0x05, // Communication checked successfully
211 kEplNmtMnuNodeStateOperational = 0x06, // CN is in NMT state OPERATIONAL
213 } tEplNmtMnuNodeState;
218 tEplTimerHdl m_TimerHdlStatReq; // timer to delay StatusRequests and IdentRequests
219 tEplTimerHdl m_TimerHdlLonger; // 2nd timer for NMT command EnableReadyToOp and CheckCommunication
220 tEplNmtMnuNodeState m_NodeState; // internal node state (kind of sub state of NMT state)
221 DWORD m_dwNodeCfg; // subindex from 0x1F81
222 WORD m_wFlags; // flags: CN is being accessed isochronously
224 } tEplNmtMnuNodeInfo;
229 tEplNmtMnuNodeInfo m_aNodeInfo[EPL_NMT_MAX_NODE_ID];
230 tEplTimerHdl m_TimerHdlNmtState; // timeout for stay in NMT state
231 unsigned int m_uiMandatorySlaveCount;
232 unsigned int m_uiSignalSlaveCount;
233 unsigned long m_ulStatusRequestDelay; // in [ms] (object 0x1006 * EPL_C_NMT_STATREQ_CYCLE)
234 unsigned long m_ulTimeoutReadyToOp; // in [ms] (object 0x1F89/5)
235 unsigned long m_ulTimeoutCheckCom; // in [ms] (object 0x1006 * MultiplexedCycleCount)
236 WORD m_wFlags; // global flags
237 DWORD m_dwNmtStartup; // object 0x1F80 NMT_StartUp_U32
238 tEplNmtMnuCbNodeEvent m_pfnCbNodeEvent;
239 tEplNmtMnuCbBootEvent m_pfnCbBootEvent;
241 } tEplNmtMnuInstance;
244 //---------------------------------------------------------------------------
246 //---------------------------------------------------------------------------
248 static tEplNmtMnuInstance EplNmtMnuInstance_g;
251 //---------------------------------------------------------------------------
252 // local function prototypes
253 //---------------------------------------------------------------------------
255 static tEplKernel PUBLIC EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p);
257 static tEplKernel PUBLIC EplNmtMnuCbIdentResponse(
258 unsigned int uiNodeId_p,
259 tEplIdentResponse* pIdentResponse_p);
261 static tEplKernel PUBLIC EplNmtMnuCbStatusResponse(
262 unsigned int uiNodeId_p,
263 tEplStatusResponse* pStatusResponse_p);
265 static tEplKernel EplNmtMnuCheckNmtState(
266 unsigned int uiNodeId_p,
267 tEplNmtMnuNodeInfo* pNodeInfo_p,
268 tEplNmtState NodeNmtState_p,
270 tEplNmtState LocalNmtState_p);
272 static tEplKernel EplNmtMnuStartBootStep1(void);
274 static tEplKernel EplNmtMnuStartBootStep2(void);
276 static tEplKernel EplNmtMnuStartCheckCom(void);
278 static tEplKernel EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p, tEplNmtMnuNodeInfo* pNodeInfo_p);
280 static tEplKernel EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p, tEplNmtMnuNodeInfo* pNodeInfo_p);
282 static tEplKernel EplNmtMnuStartNodes(void);
284 static tEplKernel EplNmtMnuProcessInternalEvent(
285 unsigned int uiNodeId_p,
286 tEplNmtState NodeNmtState_p,
288 tEplNmtMnuIntNodeEvent NodeEvent_p);
290 static tEplKernel EplNmtMnuReset(void);
294 //=========================================================================//
296 // P U B L I C F U N C T I O N S //
298 //=========================================================================//
300 //---------------------------------------------------------------------------
302 // Function: EplNmtMnuInit
304 // Description: init first instance of the module
311 // Returns: tEplKernel = errorcode
316 //---------------------------------------------------------------------------
318 tEplKernel EplNmtMnuInit(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p,
319 tEplNmtMnuCbBootEvent pfnCbBootEvent_p)
323 Ret = EplNmtMnuAddInstance(pfnCbNodeEvent_p, pfnCbBootEvent_p);
329 //---------------------------------------------------------------------------
331 // Function: EplNmtMnuAddInstance
333 // Description: init other instances of the module
340 // Returns: tEplKernel = errorcode
345 //---------------------------------------------------------------------------
347 tEplKernel EplNmtMnuAddInstance(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p,
348 tEplNmtMnuCbBootEvent pfnCbBootEvent_p)
352 Ret = kEplSuccessful;
354 // reset instance structure
355 EPL_MEMSET(&EplNmtMnuInstance_g, 0, sizeof (EplNmtMnuInstance_g));
357 if ((pfnCbNodeEvent_p == NULL) || (pfnCbBootEvent_p == NULL))
359 Ret = kEplNmtInvalidParam;
362 EplNmtMnuInstance_g.m_pfnCbNodeEvent = pfnCbNodeEvent_p;
363 EplNmtMnuInstance_g.m_pfnCbBootEvent = pfnCbBootEvent_p;
365 // initialize StatusRequest delay
366 EplNmtMnuInstance_g.m_ulStatusRequestDelay = 5000L;
368 // register NmtMnResponse callback function
369 Ret = EplDlluCalRegAsndService(kEplDllAsndNmtRequest, EplNmtMnuCbNmtRequest, kEplDllAsndFilterLocal);
377 //---------------------------------------------------------------------------
379 // Function: EplNmtMnuDelInstance
381 // Description: delete instance
388 // Returns: tEplKernel = errorcode
393 //---------------------------------------------------------------------------
395 tEplKernel EplNmtMnuDelInstance()
399 Ret = kEplSuccessful;
401 // deregister NmtMnResponse callback function
402 Ret = EplDlluCalRegAsndService(kEplDllAsndNmtRequest, NULL, kEplDllAsndFilterNone);
404 Ret = EplNmtMnuReset();
411 //---------------------------------------------------------------------------
413 // Function: EplNmtMnuSendNmtCommandEx
415 // Description: sends the specified NMT command to the specified node.
417 // Parameters: uiNodeId_p = node ID to which the NMT command will be sent
418 // NmtCommand_p = NMT command
420 // Returns: tEplKernel = error code
424 //---------------------------------------------------------------------------
426 tEplKernel EplNmtMnuSendNmtCommandEx(unsigned int uiNodeId_p,
427 tEplNmtCommand NmtCommand_p,
428 void* pNmtCommandData_p,
429 unsigned int uiDataSize_p)
431 tEplKernel Ret = kEplSuccessful;
432 tEplFrameInfo FrameInfo;
433 BYTE abBuffer[EPL_C_DLL_MINSIZE_NMTCMDEXT];
434 tEplFrame* pFrame = (tEplFrame*) abBuffer;
435 BOOL fSoftDeleteNode = FALSE;
437 if ((uiNodeId_p == 0) || (uiNodeId_p > EPL_C_ADR_BROADCAST))
438 { // invalid node ID specified
439 Ret = kEplInvalidNodeId;
443 if ((pNmtCommandData_p != NULL) && (uiDataSize_p > (EPL_C_DLL_MINSIZE_NMTCMDEXT - EPL_C_DLL_MINSIZE_NMTCMD)))
445 Ret = kEplNmtInvalidParam;
449 // $$$ d.k. may be check in future versions if the caller wants to perform prohibited state transitions
450 // the CN should not perform these transitions, but the expected NMT state will be changed and never fullfilled.
453 EPL_MEMSET(pFrame, 0x00, sizeof(abBuffer));
454 AmiSetByteToLe(&pFrame->m_le_bDstNodeId, (BYTE) uiNodeId_p);
455 AmiSetByteToLe(&pFrame->m_Data.m_Asnd.m_le_bServiceId, (BYTE) kEplDllAsndNmtCommand);
456 AmiSetByteToLe(&pFrame->m_Data.m_Asnd.m_Payload.m_NmtCommandService.m_le_bNmtCommandId,
458 if ((pNmtCommandData_p != NULL) && (uiDataSize_p > 0))
459 { // copy command data to frame
460 EPL_MEMCPY(&pFrame->m_Data.m_Asnd.m_Payload.m_NmtCommandService.m_le_abNmtCommandData[0], pNmtCommandData_p, uiDataSize_p);
463 // build info structure
464 FrameInfo.m_NetTime.m_dwNanoSec = 0;
465 FrameInfo.m_NetTime.m_dwSec = 0;
466 FrameInfo.m_pFrame = pFrame;
467 FrameInfo.m_uiFrameSize = sizeof(abBuffer);
470 #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_DLLU)) != 0)
471 Ret = EplDlluCalAsyncSend(&FrameInfo, // pointer to frameinfo
472 kEplDllAsyncReqPrioNmt); // priority
474 if (Ret != kEplSuccessful)
479 EPL_DBGLVL_NMTMN_TRACE2("NMTCmd(%02X->%02X)\n", NmtCommand_p, uiNodeId_p);
481 switch (NmtCommand_p)
483 case kEplNmtCmdStartNode:
484 case kEplNmtCmdEnterPreOperational2:
485 case kEplNmtCmdEnableReadyToOperate:
487 // nothing left to do,
488 // because any further processing is done
489 // when the NMT command is actually sent
493 case kEplNmtCmdStopNode:
495 fSoftDeleteNode = TRUE;
499 case kEplNmtCmdResetNode:
500 case kEplNmtCmdResetCommunication:
501 case kEplNmtCmdResetConfiguration:
502 case kEplNmtCmdSwReset:
511 // remove CN from isochronous phase;
512 // This must be done here and not when NMT command is actually sent
513 // because it will be too late and may cause unwanted errors
514 if (uiNodeId_p != EPL_C_ADR_BROADCAST)
516 if (fSoftDeleteNode == FALSE)
517 { // remove CN immediately from isochronous phase
518 Ret = EplDlluCalDeleteNode(uiNodeId_p);
521 { // remove CN from isochronous phase softly
522 Ret = EplDlluCalSoftDeleteNode(uiNodeId_p);
526 { // do it for all active CNs
527 for (uiNodeId_p = 1; uiNodeId_p <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiNodeId_p++)
529 if ((EPL_NMTMNU_GET_NODEINFO(uiNodeId_p)->m_dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN | EPL_NODEASSIGN_NODE_EXISTS)) != 0)
531 if (fSoftDeleteNode == FALSE)
532 { // remove CN immediately from isochronous phase
533 Ret = EplDlluCalDeleteNode(uiNodeId_p);
536 { // remove CN from isochronous phase softly
537 Ret = EplDlluCalSoftDeleteNode(uiNodeId_p);
547 //---------------------------------------------------------------------------
549 // Function: EplNmtMnuSendNmtCommand
551 // Description: sends the specified NMT command to the specified node.
553 // Parameters: uiNodeId_p = node ID to which the NMT command will be sent
554 // NmtCommand_p = NMT command
556 // Returns: tEplKernel = error code
560 //---------------------------------------------------------------------------
562 tEplKernel EplNmtMnuSendNmtCommand(unsigned int uiNodeId_p,
563 tEplNmtCommand NmtCommand_p)
565 tEplKernel Ret = kEplSuccessful;
567 Ret = EplNmtMnuSendNmtCommandEx(uiNodeId_p, NmtCommand_p, NULL, 0);
573 //---------------------------------------------------------------------------
575 // Function: EplNmtMnuTriggerStateChange
577 // Description: triggers the specified node command for the specified node.
579 // Parameters: uiNodeId_p = node ID for which the node command will be executed
580 // NodeCommand_p = node command
582 // Returns: tEplKernel = error code
586 //---------------------------------------------------------------------------
588 tEplKernel EplNmtMnuTriggerStateChange(unsigned int uiNodeId_p,
589 tEplNmtNodeCommand NodeCommand_p)
591 tEplKernel Ret = kEplSuccessful;
592 tEplNmtMnuIntNodeEvent NodeEvent;
595 WORD wErrorCode = EPL_E_NO_ERROR;
597 if ((uiNodeId_p == 0) || (uiNodeId_p >= EPL_C_ADR_BROADCAST))
599 Ret = kEplInvalidNodeId;
603 switch (NodeCommand_p)
605 case kEplNmtNodeCommandBoot:
607 NodeEvent = kEplNmtMnuIntNodeEventBoot;
611 case kEplNmtNodeCommandConfOk:
613 NodeEvent = kEplNmtMnuIntNodeEventConfigured;
617 case kEplNmtNodeCommandConfErr:
619 NodeEvent = kEplNmtMnuIntNodeEventError;
620 wErrorCode = EPL_E_NMT_BPO1_CF_VERIFY;
624 case kEplNmtNodeCommandConfReset:
626 NodeEvent = kEplNmtMnuIntNodeEventExecReset;
631 { // invalid node command
636 // fetch current NMT state
638 Ret = EplObduReadEntry(0x1F8E, uiNodeId_p, &bNmtState, &ObdSize);
639 if (Ret != kEplSuccessful)
644 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
645 (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
653 //---------------------------------------------------------------------------
655 // Function: EplNmtMnuCbNmtStateChange
657 // Description: callback function for NMT state changes
659 // Parameters: NmtStateChange_p = NMT state change event
661 // Returns: tEplKernel = error code
666 //---------------------------------------------------------------------------
668 tEplKernel PUBLIC EplNmtMnuCbNmtStateChange(tEplEventNmtStateChange NmtStateChange_p)
670 tEplKernel Ret = kEplSuccessful;
672 // do work which must be done in that state
673 switch (NmtStateChange_p.m_NewNmtState)
675 // EPL stack is not running
676 /* case kEplNmtGsOff:
679 // first init of the hardware
680 case kEplNmtGsInitialising:
683 // init of the manufacturer-specific profile area and the
684 // standardised device profile area
685 case kEplNmtGsResetApplication:
690 // init of the communication profile area
691 case kEplNmtGsResetCommunication:
696 // build the configuration with infos from OD
697 case kEplNmtGsResetConfiguration:
702 // read object 0x1F80 NMT_StartUp_U32
704 Ret = EplObduReadEntry(0x1F80, 0, &EplNmtMnuInstance_g.m_dwNmtStartup, &ObdSize);
705 if (Ret != kEplSuccessful)
710 // compute StatusReqDelay = object 0x1006 * EPL_C_NMT_STATREQ_CYCLE
711 ObdSize = sizeof (dwTimeout);
712 Ret = EplObduReadEntry(0x1006, 0, &dwTimeout, &ObdSize);
713 if (Ret != kEplSuccessful)
719 EplNmtMnuInstance_g.m_ulStatusRequestDelay = dwTimeout * EPL_C_NMT_STATREQ_CYCLE / 1000L;
720 if (EplNmtMnuInstance_g.m_ulStatusRequestDelay == 0L)
722 EplNmtMnuInstance_g.m_ulStatusRequestDelay = 1L; // at least 1 ms
725 // $$$ fetch and use MultiplexedCycleCount from OD
726 EplNmtMnuInstance_g.m_ulTimeoutCheckCom = dwTimeout * EPL_C_NMT_STATREQ_CYCLE / 1000L;
727 if (EplNmtMnuInstance_g.m_ulTimeoutCheckCom == 0L)
729 EplNmtMnuInstance_g.m_ulTimeoutCheckCom = 1L; // at least 1 ms
733 // fetch ReadyToOp Timeout from OD
734 ObdSize = sizeof (dwTimeout);
735 Ret = EplObduReadEntry(0x1F89, 5, &dwTimeout, &ObdSize);
736 if (Ret != kEplSuccessful)
742 // convert [us] to [ms]
746 dwTimeout = 1L; // at least 1 ms
748 EplNmtMnuInstance_g.m_ulTimeoutReadyToOp = dwTimeout;
752 EplNmtMnuInstance_g.m_ulTimeoutReadyToOp = 0L;
757 //-----------------------------------------------------------
758 // CN part of the state machine
760 // node liste for EPL-Frames and check timeout
761 case kEplNmtCsNotActive:
766 // node process only async frames
767 case kEplNmtCsPreOperational1:
772 // node process isochronus and asynchronus frames
773 case kEplNmtCsPreOperational2:
778 // node should be configured und application is ready
779 case kEplNmtCsReadyToOperate:
785 case kEplNmtCsOperational:
790 // node stopped by MN
791 // -> only process asynchronus frames
792 case kEplNmtCsStopped:
798 // -> normal ethernet communication
799 case kEplNmtCsBasicEthernet:
804 //-----------------------------------------------------------
805 // MN part of the state machine
807 // node listens for EPL-Frames and check timeout
808 case kEplNmtMsNotActive:
813 // node processes only async frames
814 case kEplNmtMsPreOperational1:
817 tEplTimerArg TimerArg;
821 // clear global flags, e.g. reenable boot process
822 EplNmtMnuInstance_g.m_wFlags = 0;
824 // reset IdentResponses and running IdentRequests and StatusRequests
825 Ret = EplIdentuReset();
826 Ret = EplStatusuReset();
829 Ret = EplNmtMnuReset();
831 // 2008/11/18 d.k. reset internal node info is not necessary,
832 // because timer flags are important and other
833 // things are reset by EplNmtMnuStartBootStep1().
835 EPL_MEMSET(EplNmtMnuInstance_g.m_aNodeInfo,
837 sizeof (EplNmtMnuInstance_g.m_aNodeInfo));
840 // inform DLL about NMT state change,
841 // so that it can clear the asynchonous queues and start the reduced cycle
842 Event.m_EventSink = kEplEventSinkDllk;
843 Event.m_EventType = kEplEventTypeDllkStartReducedCycle;
844 EPL_MEMSET(&Event.m_NetTime, 0x00, sizeof(Event.m_NetTime));
847 Ret = EplEventuPost(&Event);
848 if (Ret != kEplSuccessful)
854 // d.k.: skip this step if was just done before, e.g. because of a ResetNode command from a diagnostic node
855 if (NmtStateChange_p.m_NmtEvent == kEplNmtEventTimerMsPreOp1)
857 BENCHMARK_MOD_07_TOGGLE(9);
859 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
861 kEplNmtCmdResetNode);
863 Ret = EplNmtMnuSendNmtCommand(EPL_C_ADR_BROADCAST, kEplNmtCmdResetNode);
864 if (Ret != kEplSuccessful)
869 // start network scan
870 Ret = EplNmtMnuStartBootStep1();
872 // start timer for 0x1F89/2 MNTimeoutPreOp1_U32
873 ObdSize = sizeof (dwTimeout);
874 Ret = EplObduReadEntry(0x1F89, 2, &dwTimeout, &ObdSize);
875 if (Ret != kEplSuccessful)
884 dwTimeout = 1L; // at least 1 ms
886 TimerArg.m_EventSink = kEplEventSinkNmtMnu;
887 TimerArg.m_ulArg = 0;
888 Ret = EplTimeruModifyTimerMs(&EplNmtMnuInstance_g.m_TimerHdlNmtState, dwTimeout, TimerArg);
893 // node processes isochronous and asynchronous frames
894 case kEplNmtMsPreOperational2:
896 // add identified CNs to isochronous phase
897 // send EnableReadyToOp to all identified CNs
898 Ret = EplNmtMnuStartBootStep2();
900 // wait for NMT state change of CNs
904 // node should be configured und application is ready
905 case kEplNmtMsReadyToOperate:
907 // check if PRes of CNs are OK
908 // d.k. that means wait CycleLength * MultiplexCycleCount (i.e. start timer)
909 // because Dllk checks PRes of CNs automatically in ReadyToOp
910 Ret = EplNmtMnuStartCheckCom();
915 case kEplNmtMsOperational:
917 // send StartNode to CNs
918 // wait for NMT state change of CNs
919 Ret = EplNmtMnuStartNodes();
924 // -> normal ethernet communication
925 case kEplNmtMsBasicEthernet:
932 // TRACE0("EplNmtMnuCbNmtStateChange(): unhandled NMT state\n");
940 //---------------------------------------------------------------------------
942 // Function: EplNmtMnuCbCheckEvent
944 // Description: callback funktion for NMT events before they are actually executed.
945 // The EPL API layer must forward NMT events from NmtCnu module.
946 // This module will reject some NMT commands while MN.
948 // Parameters: NmtEvent_p = outstanding NMT event for approval
950 // Returns: tEplKernel = error code
951 // kEplReject = reject the NMT event
955 //---------------------------------------------------------------------------
957 tEplKernel PUBLIC EplNmtMnuCbCheckEvent(tEplNmtEvent NmtEvent_p)
959 tEplKernel Ret = kEplSuccessful;
965 //---------------------------------------------------------------------------
967 // Function: EplNmtuProcessEvent
969 // Description: processes events from event queue
971 // Parameters: pEvent_p = pointer to event
973 // Returns: tEplKernel = errorcode
977 //---------------------------------------------------------------------------
979 EPLDLLEXPORT tEplKernel PUBLIC EplNmtMnuProcessEvent(
984 Ret = kEplSuccessful;
987 switch(pEvent_p->m_EventType)
990 case kEplEventTypeTimer:
992 tEplTimerEventArg* pTimerEventArg = (tEplTimerEventArg*)pEvent_p->m_pArg;
993 unsigned int uiNodeId;
995 uiNodeId = (unsigned int) (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_NODE_MASK);
1000 tEplNmtMnuNodeInfo* pNodeInfo;
1002 pNodeInfo = EPL_NMTMNU_GET_NODEINFO(uiNodeId);
1005 Ret = EplObduReadEntry(0x1F8E, uiNodeId, &bNmtState, &ObdSize);
1006 if (Ret != kEplSuccessful)
1011 if ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_IDENTREQ) != 0L)
1013 if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ)
1014 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR))
1015 { // this is an old (already deleted or modified) timer
1016 // but not the current timer
1018 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerIdentReq,
1020 ((pNodeInfo->m_NodeState << 8)
1026 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerIdentReq,
1028 ((pNodeInfo->m_NodeState << 8)
1030 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1031 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1033 Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1034 (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1036 kEplNmtMnuIntNodeEventTimerIdentReq);
1039 else if ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_STATREQ) != 0L)
1041 if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ)
1042 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR))
1043 { // this is an old (already deleted or modified) timer
1044 // but not the current timer
1046 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq,
1048 ((pNodeInfo->m_NodeState << 8)
1054 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq,
1056 ((pNodeInfo->m_NodeState << 8)
1058 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1059 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1061 Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1062 (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1064 kEplNmtMnuIntNodeEventTimerStatReq);
1067 else if ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_STATE_MON) != 0L)
1069 if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ)
1070 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR))
1071 { // this is an old (already deleted or modified) timer
1072 // but not the current timer
1074 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStateMon,
1076 ((pNodeInfo->m_NodeState << 8)
1082 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq,
1084 ((pNodeInfo->m_NodeState << 8)
1086 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1087 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1089 Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1090 (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1092 kEplNmtMnuIntNodeEventTimerStateMon);
1095 else if ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_LONGER) != 0L)
1097 if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER)
1098 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_LO))
1099 { // this is an old (already deleted or modified) timer
1100 // but not the current timer
1102 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerLonger,
1104 ((pNodeInfo->m_NodeState << 8)
1110 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerLonger,
1112 ((pNodeInfo->m_NodeState << 8)
1114 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER) >> 6)
1115 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_LO) >> 8)));
1117 Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1118 (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1120 kEplNmtMnuIntNodeEventTimerLonger);
1125 { // global timer event
1130 case kEplEventTypeHeartbeat:
1132 tEplHeartbeatEvent* pHeartbeatEvent = (tEplHeartbeatEvent*)pEvent_p->m_pArg;
1134 Ret = EplNmtMnuProcessInternalEvent(pHeartbeatEvent->m_uiNodeId,
1135 pHeartbeatEvent->m_NmtState,
1136 pHeartbeatEvent->m_wErrorCode,
1137 kEplNmtMnuIntNodeEventHeartbeat);
1141 case kEplEventTypeNmtMnuNmtCmdSent:
1143 tEplFrame* pFrame = (tEplFrame*)pEvent_p->m_pArg;
1144 unsigned int uiNodeId;
1145 tEplNmtCommand NmtCommand;
1148 uiNodeId = AmiGetByteFromLe(&pFrame->m_le_bDstNodeId);
1149 NmtCommand = (tEplNmtCommand) AmiGetByteFromLe(&pFrame->m_Data.m_Asnd.m_Payload.m_NmtCommandService.m_le_bNmtCommandId);
1153 case kEplNmtCmdStartNode:
1154 bNmtState = (BYTE) (kEplNmtCsOperational & 0xFF);
1157 case kEplNmtCmdStopNode:
1158 bNmtState = (BYTE) (kEplNmtCsStopped & 0xFF);
1161 case kEplNmtCmdEnterPreOperational2:
1162 bNmtState = (BYTE) (kEplNmtCsPreOperational2 & 0xFF);
1165 case kEplNmtCmdEnableReadyToOperate:
1166 // d.k. do not change expected node state, because of DS 1.0.0 7.3.1.2.1 Plain NMT State Command
1167 // and because node may not change NMT state within EPL_C_NMT_STATE_TOLERANCE
1168 bNmtState = (BYTE) (kEplNmtCsPreOperational2 & 0xFF);
1171 case kEplNmtCmdResetNode:
1172 case kEplNmtCmdResetCommunication:
1173 case kEplNmtCmdResetConfiguration:
1174 case kEplNmtCmdSwReset:
1175 bNmtState = (BYTE) (kEplNmtCsNotActive & 0xFF);
1176 // EplNmtMnuProcessInternalEvent() sets internal node state to kEplNmtMnuNodeStateUnknown
1177 // after next unresponded IdentRequest/StatusRequest
1184 // process as internal event which update expected NMT state in OD
1185 if (uiNodeId != EPL_C_ADR_BROADCAST)
1187 Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1188 (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1190 kEplNmtMnuIntNodeEventNmtCmdSent);
1194 { // process internal event for all active nodes (except myself)
1196 for (uiNodeId = 1; uiNodeId <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiNodeId++)
1198 if ((EPL_NMTMNU_GET_NODEINFO(uiNodeId)->m_dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN | EPL_NODEASSIGN_NODE_EXISTS)) != 0)
1200 Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1201 (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1203 kEplNmtMnuIntNodeEventNmtCmdSent);
1205 if (Ret != kEplSuccessful)
1218 Ret = kEplNmtInvalidEvent;
1228 //---------------------------------------------------------------------------
1230 // Function: EplNmtMnuGetRunningTimerStatReq
1232 // Description: returns a bit field with running StatReq timers
1233 // just for debugging purposes
1235 // Parameters: (none)
1237 // Returns: tEplKernel = error code
1241 //---------------------------------------------------------------------------
1243 tEplKernel PUBLIC EplNmtMnuGetDiagnosticInfo(unsigned int* puiMandatorySlaveCount_p,
1244 unsigned int* puiSignalSlaveCount_p,
1247 tEplKernel Ret = kEplSuccessful;
1249 if ((puiMandatorySlaveCount_p == NULL)
1250 || (puiSignalSlaveCount_p == NULL)
1251 || (pwFlags_p == NULL))
1253 Ret = kEplNmtInvalidParam;
1257 *puiMandatorySlaveCount_p = EplNmtMnuInstance_g.m_uiMandatorySlaveCount;
1258 *puiSignalSlaveCount_p = EplNmtMnuInstance_g.m_uiSignalSlaveCount;
1259 *pwFlags_p = EplNmtMnuInstance_g.m_wFlags;
1266 //---------------------------------------------------------------------------
1268 // Function: EplNmtMnuGetRunningTimerStatReq
1270 // Description: returns a bit field with running StatReq timers
1271 // just for debugging purposes
1273 // Parameters: (none)
1275 // Returns: tEplKernel = error code
1279 //---------------------------------------------------------------------------
1281 DWORD EplNmtMnuGetRunningTimerStatReq(void)
1283 tEplKernel Ret = kEplSuccessful;
1284 unsigned int uiIndex;
1285 tEplNmtMnuNodeInfo* pNodeInfo;
1287 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1288 for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++)
1290 if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateConfigured)
1292 // reset flag "scanned once"
1293 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_SCANNED;
1295 Ret = EplNmtMnuNodeBootStep2(uiIndex, pNodeInfo);
1296 if (Ret != kEplSuccessful)
1300 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1301 // signal slave counter shall be decremented if StatusRequest was sent once to a CN
1302 // mandatory slave counter shall be decremented if mandatory CN is ReadyToOp
1311 //=========================================================================//
1313 // P R I V A T E F U N C T I O N S //
1315 //=========================================================================//
1317 //---------------------------------------------------------------------------
1319 // Function: EplNmtMnuCbNmtRequest
1321 // Description: callback funktion for NmtRequest
1323 // Parameters: pFrameInfo_p = Frame with the NmtRequest
1325 // Returns: tEplKernel = error code
1330 //---------------------------------------------------------------------------
1332 static tEplKernel PUBLIC EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p)
1334 tEplKernel Ret = kEplSuccessful;
1336 // $$$ perform NMTRequest
1341 //---------------------------------------------------------------------------
1343 // Function: EplNmtMnuCbIdentResponse
1345 // Description: callback funktion for IdentResponse
1347 // Parameters: uiNodeId_p = node ID for which IdentReponse was received
1348 // pIdentResponse_p = pointer to IdentResponse
1349 // is NULL if node did not answer
1351 // Returns: tEplKernel = error code
1355 //---------------------------------------------------------------------------
1357 static tEplKernel PUBLIC EplNmtMnuCbIdentResponse(
1358 unsigned int uiNodeId_p,
1359 tEplIdentResponse* pIdentResponse_p)
1361 tEplKernel Ret = kEplSuccessful;
1363 if (pIdentResponse_p == NULL)
1364 { // node did not answer
1365 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1367 EPL_E_NMT_NO_IDENT_RES, // was EPL_E_NO_ERROR
1368 kEplNmtMnuIntNodeEventNoIdentResponse);
1371 { // node answered IdentRequest
1372 tEplObdSize ObdSize;
1374 WORD wErrorCode = EPL_E_NO_ERROR;
1375 tEplNmtState NmtState = (tEplNmtState) (AmiGetByteFromLe(&pIdentResponse_p->m_le_bNmtStatus) | EPL_NMT_TYPE_CS);
1377 // check IdentResponse $$$ move to ProcessIntern, because this function may be called also if CN
1379 // check DeviceType (0x1F84)
1381 Ret = EplObduReadEntry(0x1F84, uiNodeId_p, &dwDevType, &ObdSize);
1382 if (Ret != kEplSuccessful)
1386 if (dwDevType != 0L)
1387 { // actually compare it with DeviceType from IdentResponse
1388 if (AmiGetDwordFromLe(&pIdentResponse_p->m_le_dwDeviceType) != dwDevType)
1389 { // wrong DeviceType
1390 NmtState = kEplNmtCsNotActive;
1391 wErrorCode = EPL_E_NMT_BPO1_DEVICE_TYPE;
1395 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1398 kEplNmtMnuIntNodeEventIdentResponse);
1406 //---------------------------------------------------------------------------
1408 // Function: EplNmtMnuCbStatusResponse
1410 // Description: callback funktion for StatusResponse
1412 // Parameters: uiNodeId_p = node ID for which IdentReponse was received
1413 // pIdentResponse_p = pointer to IdentResponse
1414 // is NULL if node did not answer
1416 // Returns: tEplKernel = error code
1420 //---------------------------------------------------------------------------
1422 static tEplKernel PUBLIC EplNmtMnuCbStatusResponse(
1423 unsigned int uiNodeId_p,
1424 tEplStatusResponse* pStatusResponse_p)
1426 tEplKernel Ret = kEplSuccessful;
1428 if (pStatusResponse_p == NULL)
1429 { // node did not answer
1430 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1432 EPL_E_NMT_NO_STATUS_RES, // was EPL_E_NO_ERROR
1433 kEplNmtMnuIntNodeEventNoStatusResponse);
1436 { // node answered StatusRequest
1437 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1438 (tEplNmtState) (AmiGetByteFromLe(&pStatusResponse_p->m_le_bNmtStatus) | EPL_NMT_TYPE_CS),
1440 kEplNmtMnuIntNodeEventStatusResponse);
1447 //---------------------------------------------------------------------------
1449 // Function: EplNmtMnuStartBootStep1
1451 // Description: starts BootStep1
1453 // Parameters: (none)
1455 // Returns: tEplKernel = error code
1459 //---------------------------------------------------------------------------
1461 static tEplKernel EplNmtMnuStartBootStep1(void)
1463 tEplKernel Ret = kEplSuccessful;
1464 unsigned int uiSubIndex;
1465 unsigned int uiLocalNodeId;
1467 tEplObdSize ObdSize;
1469 // $$$ d.k.: save current time for 0x1F89/2 MNTimeoutPreOp1_U32
1471 // start network scan
1472 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1473 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1475 uiLocalNodeId = EplObduGetNodeId();
1476 for (uiSubIndex = 1; uiSubIndex <= 254; uiSubIndex++)
1479 Ret = EplObduReadEntry(0x1F81, uiSubIndex, &dwNodeCfg, &ObdSize);
1480 if (Ret != kEplSuccessful)
1484 if (uiSubIndex != uiLocalNodeId)
1486 // reset flags "not scanned" and "isochronous"
1487 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_wFlags &= ~(EPL_NMTMNU_NODE_FLAG_ISOCHRON | EPL_NMTMNU_NODE_FLAG_NOT_SCANNED);
1489 if (uiSubIndex == EPL_C_ADR_DIAG_DEF_NODE_ID)
1490 { // diagnostic node must be scanned by MN in any case
1491 dwNodeCfg |= (EPL_NODEASSIGN_NODE_IS_CN | EPL_NODEASSIGN_NODE_EXISTS);
1492 // and it must be isochronously accessed
1493 dwNodeCfg &= ~EPL_NODEASSIGN_ASYNCONLY_NODE;
1496 // save node config in local node info structure
1497 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_dwNodeCfg = dwNodeCfg;
1498 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_NodeState = kEplNmtMnuNodeStateUnknown;
1500 if ((dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN | EPL_NODEASSIGN_NODE_EXISTS)) != 0)
1501 { // node is configured as CN
1502 // identify the node
1503 Ret = EplIdentuRequestIdentResponse(uiSubIndex, EplNmtMnuCbIdentResponse);
1504 if (Ret != kEplSuccessful)
1509 // set flag "not scanned"
1510 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_wFlags |= EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1511 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1512 // signal slave counter shall be decremented if IdentRequest was sent once to a CN
1514 if ((dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
1515 { // node is a mandatory CN
1516 EplNmtMnuInstance_g.m_uiMandatorySlaveCount++;
1517 // mandatory slave counter shall be decremented if mandatory CN was configured successfully
1523 if ((dwNodeCfg & (EPL_NODEASSIGN_MN_PRES | EPL_NODEASSIGN_NODE_EXISTS)) != 0)
1524 { // MN shall send PRes
1525 tEplDllNodeInfo DllNodeInfo;
1527 EPL_MEMSET(&DllNodeInfo, 0, sizeof (DllNodeInfo));
1528 DllNodeInfo.m_uiNodeId = uiLocalNodeId;
1530 Ret = EplDlluCalAddNode(&DllNodeInfo);
1540 //---------------------------------------------------------------------------
1542 // Function: EplNmtMnuStartBootStep2
1544 // Description: starts BootStep2.
1545 // That means add nodes to isochronous phase and send
1546 // NMT EnableReadyToOp.
1548 // Parameters: (none)
1550 // Returns: tEplKernel = error code
1554 //---------------------------------------------------------------------------
1556 static tEplKernel EplNmtMnuStartBootStep2(void)
1558 tEplKernel Ret = kEplSuccessful;
1559 unsigned int uiIndex;
1560 tEplNmtMnuNodeInfo* pNodeInfo;
1563 if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0)
1564 { // boot process is not halted
1565 // add nodes to isochronous phase and send NMT EnableReadyToOp
1566 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1567 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1568 // reset flag that application was informed about possible state change
1569 EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED;
1571 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1572 for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++)
1574 if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateConfigured)
1576 Ret = EplNmtMnuNodeBootStep2(uiIndex, pNodeInfo);
1577 if (Ret != kEplSuccessful)
1582 // set flag "not scanned"
1583 pNodeInfo->m_wFlags |= EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1585 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1586 // signal slave counter shall be decremented if StatusRequest was sent once to a CN
1588 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
1589 { // node is a mandatory CN
1590 EplNmtMnuInstance_g.m_uiMandatorySlaveCount++;
1593 // mandatory slave counter shall be decremented if mandatory CN is ReadyToOp
1603 //---------------------------------------------------------------------------
1605 // Function: EplNmtMnuNodeBootStep2
1607 // Description: starts BootStep2 for the specified node.
1608 // This means the CN is added to isochronous phase if not
1609 // async-only and it gets the NMT command EnableReadyToOp.
1610 // The CN must be in node state Configured, when it enters
1611 // BootStep2. When BootStep2 finishes, the CN is in node state
1613 // If TimeoutReadyToOp in object 0x1F89/5 is configured,
1614 // TimerHdlLonger will be started with this timeout.
1616 // Parameters: uiNodeId_p = node ID
1617 // pNodeInfo_p = pointer to internal node info structure
1619 // Returns: tEplKernel = error code
1623 //---------------------------------------------------------------------------
1625 static tEplKernel EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p, tEplNmtMnuNodeInfo* pNodeInfo_p)
1627 tEplKernel Ret = kEplSuccessful;
1628 tEplDllNodeInfo DllNodeInfo;
1630 tEplObdSize ObdSize;
1631 tEplTimerArg TimerArg;
1633 dwNodeCfg = pNodeInfo_p->m_dwNodeCfg;
1634 if ((dwNodeCfg & EPL_NODEASSIGN_ASYNCONLY_NODE) == 0)
1635 { // add node to isochronous phase
1636 DllNodeInfo.m_uiNodeId = uiNodeId_p;
1638 Ret = EplObduReadEntry(0x1F92, uiNodeId_p, &DllNodeInfo.m_dwPresTimeout, &ObdSize);
1639 if (Ret != kEplSuccessful)
1645 Ret = EplObduReadEntry(0x1F8B, uiNodeId_p, &DllNodeInfo.m_wPreqPayloadLimit, &ObdSize);
1646 if (Ret != kEplSuccessful)
1652 Ret = EplObduReadEntry(0x1F8D, uiNodeId_p, &DllNodeInfo.m_wPresPayloadLimit, &ObdSize);
1653 if (Ret != kEplSuccessful)
1658 pNodeInfo_p->m_wFlags |= EPL_NMTMNU_NODE_FLAG_ISOCHRON;
1660 Ret = EplDlluCalAddNode(&DllNodeInfo);
1661 if (Ret != kEplSuccessful)
1668 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
1670 kEplNmtCmdEnableReadyToOperate);
1672 Ret = EplNmtMnuSendNmtCommand(uiNodeId_p, kEplNmtCmdEnableReadyToOperate);
1673 if (Ret != kEplSuccessful)
1678 if (EplNmtMnuInstance_g.m_ulTimeoutReadyToOp != 0L)
1680 // when the timer expires the CN must be ReadyToOp
1681 EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(
1682 pNodeInfo_p, uiNodeId_p, TimerArg);
1683 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
1684 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p;
1685 Ret = EplTimeruModifyTimerMs(&pNodeInfo_p->m_TimerHdlLonger, EplNmtMnuInstance_g.m_ulTimeoutReadyToOp, TimerArg);
1693 //---------------------------------------------------------------------------
1695 // Function: EplNmtMnuStartCheckCom
1697 // Description: starts CheckCommunication
1699 // Parameters: (none)
1701 // Returns: tEplKernel = error code
1705 //---------------------------------------------------------------------------
1707 static tEplKernel EplNmtMnuStartCheckCom(void)
1709 tEplKernel Ret = kEplSuccessful;
1710 unsigned int uiIndex;
1711 tEplNmtMnuNodeInfo* pNodeInfo;
1714 if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0)
1715 { // boot process is not halted
1716 // wait some time and check that no communication error occurs
1717 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1718 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1719 // reset flag that application was informed about possible state change
1720 EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED;
1722 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1723 for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++)
1725 if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateReadyToOp)
1727 Ret = EplNmtMnuNodeCheckCom(uiIndex, pNodeInfo);
1728 if (Ret == kEplReject)
1729 { // timer was started
1730 // wait until it expires
1731 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
1732 { // node is a mandatory CN
1733 EplNmtMnuInstance_g.m_uiMandatorySlaveCount++;
1736 else if (Ret != kEplSuccessful)
1741 // set flag "not scanned"
1742 pNodeInfo->m_wFlags |= EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1744 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1745 // signal slave counter shall be decremented if timeout elapsed and regardless of an error
1746 // mandatory slave counter shall be decremented if timeout elapsed and no error occured
1751 Ret = kEplSuccessful;
1758 //---------------------------------------------------------------------------
1760 // Function: EplNmtMnuNodeCheckCom
1762 // Description: checks communication of the specified node.
1763 // That means wait some time and if no error occured everything
1766 // Parameters: uiNodeId_p = node ID
1767 // pNodeInfo_p = pointer to internal node info structure
1769 // Returns: tEplKernel = error code
1773 //---------------------------------------------------------------------------
1775 static tEplKernel EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p, tEplNmtMnuNodeInfo* pNodeInfo_p)
1777 tEplKernel Ret = kEplSuccessful;
1779 tEplTimerArg TimerArg;
1781 dwNodeCfg = pNodeInfo_p->m_dwNodeCfg;
1782 if (((dwNodeCfg & EPL_NODEASSIGN_ASYNCONLY_NODE) == 0)
1783 && (EplNmtMnuInstance_g.m_ulTimeoutCheckCom != 0L))
1784 { // CN is not async-only and timeout for CheckCom was set
1786 // check communication,
1787 // that means wait some time and if no error occured everything is OK;
1789 // start timer (when the timer expires the CN must be still ReadyToOp)
1790 EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(
1791 pNodeInfo_p, uiNodeId_p, TimerArg);
1792 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
1793 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p;
1794 Ret = EplTimeruModifyTimerMs(&pNodeInfo_p->m_TimerHdlLonger, EplNmtMnuInstance_g.m_ulTimeoutCheckCom, TimerArg);
1796 // update mandatory slave counter, because timer was started
1797 if (Ret == kEplSuccessful)
1803 { // timer was not started
1804 // assume everything is OK
1805 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateComChecked;
1813 //---------------------------------------------------------------------------
1815 // Function: EplNmtMnuStartNodes
1817 // Description: really starts all nodes which are ReadyToOp and CheckCom did not fail
1819 // Parameters: (none)
1821 // Returns: tEplKernel = error code
1825 //---------------------------------------------------------------------------
1827 static tEplKernel EplNmtMnuStartNodes(void)
1829 tEplKernel Ret = kEplSuccessful;
1830 unsigned int uiIndex;
1831 tEplNmtMnuNodeInfo* pNodeInfo;
1834 if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0)
1835 { // boot process is not halted
1836 // send NMT command Start Node
1837 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1838 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1839 // reset flag that application was informed about possible state change
1840 EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED;
1842 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1843 for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++)
1845 if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateComChecked)
1847 if ((EplNmtMnuInstance_g.m_dwNmtStartup & EPL_NMTST_STARTALLNODES) == 0)
1849 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
1851 kEplNmtCmdStartNode);
1853 Ret = EplNmtMnuSendNmtCommand(uiIndex, kEplNmtCmdStartNode);
1854 if (Ret != kEplSuccessful)
1860 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
1861 { // node is a mandatory CN
1862 EplNmtMnuInstance_g.m_uiMandatorySlaveCount++;
1865 // set flag "not scanned"
1866 pNodeInfo->m_wFlags |= EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1868 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1869 // signal slave counter shall be decremented if StatusRequest was sent once to a CN
1870 // mandatory slave counter shall be decremented if mandatory CN is OPERATIONAL
1874 // $$$ inform application if EPL_NMTST_NO_STARTNODE is set
1876 if ((EplNmtMnuInstance_g.m_dwNmtStartup & EPL_NMTST_STARTALLNODES) != 0)
1878 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
1879 EPL_C_ADR_BROADCAST,
1880 kEplNmtCmdStartNode);
1882 Ret = EplNmtMnuSendNmtCommand(EPL_C_ADR_BROADCAST, kEplNmtCmdStartNode);
1883 if (Ret != kEplSuccessful)
1895 //---------------------------------------------------------------------------
1897 // Function: EplNmtMnuProcessInternalEvent
1899 // Description: processes internal node events
1901 // Parameters: uiNodeId_p = node ID
1902 // NodeNmtState_p = NMT state of CN
1903 // NodeEvent_p = occured events
1905 // Returns: tEplKernel = error code
1910 //---------------------------------------------------------------------------
1912 static tEplKernel EplNmtMnuProcessInternalEvent(
1913 unsigned int uiNodeId_p,
1914 tEplNmtState NodeNmtState_p,
1916 tEplNmtMnuIntNodeEvent NodeEvent_p)
1918 tEplKernel Ret = kEplSuccessful;
1919 tEplNmtState NmtState;
1920 tEplNmtMnuNodeInfo* pNodeInfo;
1921 tEplTimerArg TimerArg;
1923 pNodeInfo = EPL_NMTMNU_GET_NODEINFO(uiNodeId_p);
1924 NmtState = EplNmtuGetNmtState();
1925 if (NmtState <= kEplNmtMsNotActive)
1926 { // MN is not active
1930 switch (NodeEvent_p)
1932 case kEplNmtMnuIntNodeEventIdentResponse:
1936 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
1938 pNodeInfo->m_NodeState);
1940 if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)
1942 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateIdentified;
1945 // reset flags ISOCHRON and NMT_CMD_ISSUED
1946 pNodeInfo->m_wFlags &= ~(EPL_NMTMNU_NODE_FLAG_ISOCHRON
1947 | EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED);
1949 if ((NmtState == kEplNmtMsPreOperational1)
1950 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
1952 // decrement only signal slave count
1953 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
1954 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1957 // update object 0x1F8F NMT_MNNodeExpState_AU8 to PreOp1 (even if local state >= PreOp2)
1958 bNmtState = (BYTE) (kEplNmtCsPreOperational1 & 0xFF);
1959 Ret = EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState, 1);
1961 // check NMT state of CN
1962 Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, NodeNmtState_p, wErrorCode_p, NmtState);
1963 if (Ret != kEplSuccessful)
1965 if (Ret == kEplReject)
1967 Ret = kEplSuccessful;
1972 // request StatusResponse immediately,
1973 // because we want a fast boot-up of CNs
1974 Ret = EplStatusuRequestStatusResponse(uiNodeId_p, EplNmtMnuCbStatusResponse);
1975 if (Ret != kEplSuccessful)
1977 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
1981 if (Ret == kEplInvalidOperation)
1982 { // the only situation when this should happen is, when
1983 // StatusResponse was already requested from within
1984 // the StatReq timer event.
1985 // so ignore this error.
1986 Ret = kEplSuccessful;
1994 if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)
1996 // inform application
1997 Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
1998 kEplNmtNodeEventFound,
2001 (pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0);
2002 if (Ret == kEplReject)
2003 { // interrupt boot process on user request
2004 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2006 ((pNodeInfo->m_NodeState << 8)
2009 Ret = kEplSuccessful;
2012 else if (Ret != kEplSuccessful)
2014 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2016 ((pNodeInfo->m_NodeState << 8)
2023 // continue BootStep1
2026 case kEplNmtMnuIntNodeEventBoot:
2029 // $$$ check identification (vendor ID, product code, revision no, serial no)
2031 if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateIdentified)
2033 // $$$ check software
2035 // check/start configuration
2036 // inform application
2037 Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
2038 kEplNmtNodeEventCheckConf,
2041 (pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0);
2042 if (Ret == kEplReject)
2043 { // interrupt boot process on user request
2044 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventBoot,
2046 ((pNodeInfo->m_NodeState << 8)
2049 Ret = kEplSuccessful;
2052 else if (Ret != kEplSuccessful)
2054 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventBoot,
2056 ((pNodeInfo->m_NodeState << 8)
2062 else if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)
2068 // $$$ d.k.: currently we assume configuration is OK
2070 // continue BootStep1
2073 case kEplNmtMnuIntNodeEventConfigured:
2075 if ((pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified)
2076 && (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf))
2082 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateConfigured;
2084 if (NmtState == kEplNmtMsPreOperational1)
2086 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
2087 { // decrement mandatory CN counter
2088 EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2093 // put optional node to next step (BootStep2)
2094 Ret = EplNmtMnuNodeBootStep2(uiNodeId_p, pNodeInfo);
2099 case kEplNmtMnuIntNodeEventNoIdentResponse:
2101 if ((NmtState == kEplNmtMsPreOperational1)
2102 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2104 // decrement only signal slave count
2105 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2106 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2109 if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)
2111 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateUnknown;
2114 // $$$ d.k. check start time for 0x1F89/2 MNTimeoutPreOp1_U32
2115 // $$$ d.k. check individual timeout 0x1F89/6 MNIdentificationTimeout_U32
2116 // if mandatory node and timeout elapsed -> halt boot procedure
2117 // trigger IdentRequest again (if >= PreOp2, after delay)
2118 if (NmtState >= kEplNmtMsPreOperational2)
2120 EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ(
2121 pNodeInfo, uiNodeId_p, TimerArg);
2122 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
2123 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_IDENTREQ | uiNodeId_p;
2125 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventNoIdentResponse,
2127 ((pNodeInfo->m_NodeState << 8)
2129 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
2130 | ((TimerArg.m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
2132 Ret = EplTimeruModifyTimerMs(&pNodeInfo->m_TimerHdlStatReq, EplNmtMnuInstance_g.m_ulStatusRequestDelay, TimerArg);
2135 { // trigger IdentRequest immediately
2136 Ret = EplIdentuRequestIdentResponse(uiNodeId_p, EplNmtMnuCbIdentResponse);
2141 case kEplNmtMnuIntNodeEventStatusResponse:
2143 if ((NmtState >= kEplNmtMsPreOperational2)
2144 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2146 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2147 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2148 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2151 // check NMT state of CN
2152 Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, NodeNmtState_p, wErrorCode_p, NmtState);
2153 if (Ret != kEplSuccessful)
2155 if (Ret == kEplReject)
2157 Ret = kEplSuccessful;
2162 if (NmtState == kEplNmtMsPreOperational1)
2164 // request next StatusResponse immediately
2165 Ret = EplStatusuRequestStatusResponse(uiNodeId_p, EplNmtMnuCbStatusResponse);
2166 if (Ret != kEplSuccessful)
2168 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2174 else if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_ISOCHRON) == 0)
2176 // not isochronously accessed CN (e.g. async-only or stopped CN)
2177 EPL_NMTMNU_SET_FLAGS_TIMERARG_STATREQ(
2178 pNodeInfo, uiNodeId_p, TimerArg);
2179 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
2180 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_STATREQ | uiNodeId_p;
2182 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventStatusResponse,
2184 ((pNodeInfo->m_NodeState << 8)
2186 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
2187 | ((TimerArg.m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
2189 Ret = EplTimeruModifyTimerMs(&pNodeInfo->m_TimerHdlStatReq, EplNmtMnuInstance_g.m_ulStatusRequestDelay, TimerArg);
2195 case kEplNmtMnuIntNodeEventNoStatusResponse:
2197 // function CheckNmtState sets node state to unknown if necessary
2199 if ((NmtState >= kEplNmtMsPreOperational2)
2200 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2202 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2203 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2204 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2207 // check NMT state of CN
2208 Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, NodeNmtState_p, wErrorCode_p, NmtState);
2209 if (Ret != kEplSuccessful)
2211 if (Ret == kEplReject)
2213 Ret = kEplSuccessful;
2221 case kEplNmtMnuIntNodeEventError:
2222 { // currently only issued on kEplNmtNodeCommandConfErr
2224 if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified)
2230 // check NMT state of CN
2231 Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, kEplNmtCsNotActive, wErrorCode_p, NmtState);
2232 if (Ret != kEplSuccessful)
2234 if (Ret == kEplReject)
2236 Ret = kEplSuccessful;
2244 case kEplNmtMnuIntNodeEventExecReset:
2246 if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified)
2252 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateResetConf;
2254 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2256 (((NodeNmtState_p & 0xFF) << 8)
2257 | kEplNmtCmdResetConfiguration));
2259 // send NMT reset configuration to CN for activation of configuration
2260 Ret = EplNmtMnuSendNmtCommand(uiNodeId_p, kEplNmtCmdResetConfiguration);
2265 case kEplNmtMnuIntNodeEventHeartbeat:
2268 if ((NmtState >= kEplNmtMsPreOperational2)
2269 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2271 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2272 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2273 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2276 // check NMT state of CN
2277 Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, NodeNmtState_p, wErrorCode_p, NmtState);
2278 if (Ret != kEplSuccessful)
2280 if (Ret == kEplReject)
2282 Ret = kEplSuccessful;
2290 case kEplNmtMnuIntNodeEventTimerIdentReq:
2292 EPL_DBGLVL_NMTMN_TRACE1("TimerStatReq->IdentReq(%02X)\n", uiNodeId_p);
2293 // trigger IdentRequest again
2294 Ret = EplIdentuRequestIdentResponse(uiNodeId_p, EplNmtMnuCbIdentResponse);
2295 if (Ret != kEplSuccessful)
2297 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2299 (((NodeNmtState_p & 0xFF) << 8)
2301 if (Ret == kEplInvalidOperation)
2302 { // this can happen because of a bug in EplTimeruLinuxKernel.c
2303 // so ignore this error.
2304 Ret = kEplSuccessful;
2311 case kEplNmtMnuIntNodeEventTimerStateMon:
2313 // reset NMT state change flag
2314 // because from now on the CN must have the correct NMT state
2315 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED;
2317 // continue with normal StatReq processing
2320 case kEplNmtMnuIntNodeEventTimerStatReq:
2322 EPL_DBGLVL_NMTMN_TRACE1("TimerStatReq->StatReq(%02X)\n", uiNodeId_p);
2323 // request next StatusResponse
2324 Ret = EplStatusuRequestStatusResponse(uiNodeId_p, EplNmtMnuCbStatusResponse);
2325 if (Ret != kEplSuccessful)
2327 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2329 (((NodeNmtState_p & 0xFF) << 8)
2331 if (Ret == kEplInvalidOperation)
2332 { // the only situation when this should happen is, when
2333 // StatusResponse was already requested while processing
2334 // event IdentResponse.
2335 // so ignore this error.
2336 Ret = kEplSuccessful;
2343 case kEplNmtMnuIntNodeEventTimerLonger:
2345 switch (pNodeInfo->m_NodeState)
2347 case kEplNmtMnuNodeStateConfigured:
2348 { // node should be ReadyToOp but it is not
2350 // check NMT state which shall be intentionally wrong, so that ERROR_TREATMENT will be started
2351 Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, kEplNmtCsNotActive, EPL_E_NMT_BPO2, NmtState);
2352 if (Ret != kEplSuccessful)
2354 if (Ret == kEplReject)
2356 Ret = kEplSuccessful;
2364 case kEplNmtMnuNodeStateReadyToOp:
2365 { // CheckCom finished successfully
2367 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateComChecked;
2369 if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0)
2371 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2372 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2373 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2376 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
2378 // decrement mandatory slave counter
2379 EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2381 if (NmtState != kEplNmtMsReadyToOperate)
2383 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2385 (((NodeNmtState_p & 0xFF) << 8)
2386 | kEplNmtCmdStartNode));
2388 // start optional CN
2389 Ret = EplNmtMnuSendNmtCommand(uiNodeId_p, kEplNmtCmdStartNode);
2402 case kEplNmtMnuIntNodeEventNmtCmdSent:
2406 // update expected NMT state with the one that results
2407 // from the sent NMT command
2408 bNmtState = (BYTE) (NodeNmtState_p & 0xFF);
2410 // write object 0x1F8F NMT_MNNodeExpState_AU8
2411 Ret = EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState, 1);
2412 if (Ret != kEplSuccessful)
2417 if (NodeNmtState_p == kEplNmtCsNotActive)
2418 { // restart processing with IdentRequest
2419 EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ(
2420 pNodeInfo, uiNodeId_p, TimerArg);
2423 { // monitor NMT state change with StatusRequest after
2424 // the corresponding delay;
2425 // until then wrong NMT states will be ignored
2426 EPL_NMTMNU_SET_FLAGS_TIMERARG_STATE_MON(
2427 pNodeInfo, uiNodeId_p, TimerArg);
2429 // set NMT state change flag
2430 pNodeInfo->m_wFlags |= EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED;
2433 Ret = EplTimeruModifyTimerMs(&pNodeInfo->m_TimerHdlStatReq, EplNmtMnuInstance_g.m_ulStatusRequestDelay, TimerArg);
2435 // finish processing, because NmtState_p is the expected and not the current state
2445 // check if network is ready to change local NMT state and this was not done before
2446 if ((EplNmtMnuInstance_g.m_wFlags & (EPL_NMTMNU_FLAG_HALTED | EPL_NMTMNU_FLAG_APP_INFORMED)) == 0)
2447 { // boot process is not halted
2450 case kEplNmtMsPreOperational1:
2452 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount == 0)
2453 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0))
2454 { // all optional CNs scanned once and all mandatory CNs configured successfully
2455 EplNmtMnuInstance_g.m_wFlags |= EPL_NMTMNU_FLAG_APP_INFORMED;
2456 // inform application
2457 Ret = EplNmtMnuInstance_g.m_pfnCbBootEvent(kEplNmtBootEventBootStep1Finish,
2460 if (Ret != kEplSuccessful)
2462 if (Ret == kEplReject)
2464 // wait for application
2465 Ret = kEplSuccessful;
2470 Ret = EplNmtuNmtEvent(kEplNmtEventAllMandatoryCNIdent);
2475 case kEplNmtMsPreOperational2:
2477 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount == 0)
2478 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0))
2479 { // all optional CNs checked once for ReadyToOp and all mandatory CNs are ReadyToOp
2480 EplNmtMnuInstance_g.m_wFlags |= EPL_NMTMNU_FLAG_APP_INFORMED;
2481 // inform application
2482 Ret = EplNmtMnuInstance_g.m_pfnCbBootEvent(kEplNmtBootEventBootStep2Finish,
2485 if (Ret != kEplSuccessful)
2487 if (Ret == kEplReject)
2489 // wait for application
2490 Ret = kEplSuccessful;
2495 Ret = EplNmtuNmtEvent(kEplNmtEventEnterReadyToOperate);
2500 case kEplNmtMsReadyToOperate:
2502 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount == 0)
2503 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0))
2504 { // all CNs checked for errorless communication
2505 EplNmtMnuInstance_g.m_wFlags |= EPL_NMTMNU_FLAG_APP_INFORMED;
2506 // inform application
2507 Ret = EplNmtMnuInstance_g.m_pfnCbBootEvent(kEplNmtBootEventCheckComFinish,
2510 if (Ret != kEplSuccessful)
2512 if (Ret == kEplReject)
2514 // wait for application
2515 Ret = kEplSuccessful;
2519 // enter Operational
2520 Ret = EplNmtuNmtEvent(kEplNmtEventEnterMsOperational);
2525 case kEplNmtMsOperational:
2527 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount == 0)
2528 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0))
2529 { // all optional CNs scanned once and all mandatory CNs are OPERATIONAL
2530 EplNmtMnuInstance_g.m_wFlags |= EPL_NMTMNU_FLAG_APP_INFORMED;
2531 // inform application
2532 Ret = EplNmtMnuInstance_g.m_pfnCbBootEvent(kEplNmtBootEventOperational,
2535 if (Ret != kEplSuccessful)
2537 if (Ret == kEplReject)
2539 // ignore error code
2540 Ret = kEplSuccessful;
2560 //---------------------------------------------------------------------------
2562 // Function: EplNmtMnuCheckNmtState
2564 // Description: checks the NMT state, i.e. evaluates it with object 0x1F8F
2565 // NMT_MNNodeExpState_AU8 and updates object 0x1F8E
2566 // NMT_MNNodeCurrState_AU8.
2567 // It manipulates m_NodeState in internal node info structure.
2569 // Parameters: uiNodeId_p = node ID
2570 // NodeNmtState_p = NMT state of CN
2572 // Returns: tEplKernel = error code
2573 // kEplReject = CN was in wrong state and has been reset
2577 //---------------------------------------------------------------------------
2579 static tEplKernel EplNmtMnuCheckNmtState(
2580 unsigned int uiNodeId_p,
2581 tEplNmtMnuNodeInfo* pNodeInfo_p,
2582 tEplNmtState NodeNmtState_p,
2584 tEplNmtState LocalNmtState_p)
2586 tEplKernel Ret = kEplSuccessful;
2587 tEplObdSize ObdSize;
2590 tEplNmtState ExpNmtState;
2593 // read object 0x1F8F NMT_MNNodeExpState_AU8
2594 Ret = EplObduReadEntry(0x1F8F, uiNodeId_p, &bNmtState, &ObdSize);
2595 if (Ret != kEplSuccessful)
2600 // compute expected NMT state
2601 ExpNmtState = (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS);
2602 // compute BYTE of current NMT state
2603 bNmtState = ((BYTE) NodeNmtState_p & 0xFF);
2605 if (ExpNmtState == kEplNmtCsNotActive)
2606 { // ignore the current state, because the CN shall be not active
2610 else if ((ExpNmtState == kEplNmtCsPreOperational2)
2611 && (NodeNmtState_p == kEplNmtCsReadyToOperate))
2612 { // CN switched to ReadyToOp
2613 // delete timer for timeout handling
2614 Ret = EplTimeruDeleteTimer(&pNodeInfo_p->m_TimerHdlLonger);
2615 if (Ret != kEplSuccessful)
2619 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateReadyToOp;
2621 // update object 0x1F8F NMT_MNNodeExpState_AU8 to ReadyToOp
2622 Ret = EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState, 1);
2623 if (Ret != kEplSuccessful)
2628 if ((pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
2629 { // node is a mandatory CN -> decrement counter
2630 EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2632 if (LocalNmtState_p >= kEplNmtMsReadyToOperate)
2633 { // start procedure CheckCommunication for this node
2634 Ret = EplNmtMnuNodeCheckCom(uiNodeId_p, pNodeInfo_p);
2635 if (Ret != kEplSuccessful)
2640 if ((LocalNmtState_p == kEplNmtMsOperational)
2641 && (pNodeInfo_p->m_NodeState == kEplNmtMnuNodeStateComChecked))
2643 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
2645 (((NodeNmtState_p & 0xFF) << 8)
2646 | kEplNmtCmdStartNode));
2648 // immediately start optional CN, because communication is always OK (e.g. async-only CN)
2649 Ret = EplNmtMnuSendNmtCommand(uiNodeId_p, kEplNmtCmdStartNode);
2650 if (Ret != kEplSuccessful)
2658 else if ((ExpNmtState == kEplNmtCsReadyToOperate)
2659 && (NodeNmtState_p == kEplNmtCsOperational))
2660 { // CN switched to OPERATIONAL
2661 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateOperational;
2663 if ((pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
2664 { // node is a mandatory CN -> decrement counter
2665 EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2669 else if ((ExpNmtState != NodeNmtState_p)
2670 && !((ExpNmtState == kEplNmtCsPreOperational1)
2671 && (NodeNmtState_p == kEplNmtCsPreOperational2)))
2672 { // CN is not in expected NMT state (without the exceptions above)
2675 if ((pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0)
2677 // decrement only signal slave count if checked once
2678 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2679 pNodeInfo_p->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2682 if (pNodeInfo_p->m_NodeState == kEplNmtMnuNodeStateUnknown)
2683 { // CN is already in state unknown, which means that it got
2684 // NMT reset command earlier
2688 // -> CN is in wrong NMT state
2689 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateUnknown;
2691 if (wErrorCode_p == 0)
2692 { // assume wrong NMT state error
2693 if ((pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED) != 0)
2694 { // NMT command has been just issued;
2695 // ignore wrong NMT state until timer expires;
2696 // other errors like LOSS_PRES_TH are still processed
2700 wErrorCode_p = EPL_E_NMT_WRONG_STATE;
2703 BENCHMARK_MOD_07_TOGGLE(9);
2705 // $$$ start ERROR_TREATMENT and inform application
2706 Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
2707 kEplNmtNodeEventError,
2710 (pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0);
2711 if (Ret != kEplSuccessful)
2716 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
2718 (((NodeNmtState_p & 0xFF) << 8)
2719 | kEplNmtCmdResetNode));
2722 // store error code in NMT command data for diagnostic purpose
2723 AmiSetWordToLe(&wbeErrorCode, wErrorCode_p);
2724 Ret = EplNmtMnuSendNmtCommandEx(uiNodeId_p, kEplNmtCmdResetNode, &wbeErrorCode, sizeof (wbeErrorCode));
2725 if (Ret == kEplSuccessful)
2733 // check if NMT_MNNodeCurrState_AU8 has to be changed
2735 Ret = EplObduReadEntry(0x1F8E, uiNodeId_p, &bNmtStatePrev, &ObdSize);
2736 if (Ret != kEplSuccessful)
2740 if (bNmtState != bNmtStatePrev)
2742 // update object 0x1F8E NMT_MNNodeCurrState_AU8
2743 Ret = EplObduWriteEntry(0x1F8E, uiNodeId_p, &bNmtState, 1);
2744 if (Ret != kEplSuccessful)
2748 Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
2749 kEplNmtNodeEventNmtState,
2752 (pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0);
2753 if (Ret != kEplSuccessful)
2763 //---------------------------------------------------------------------------
2765 // Function: EplNmtMnuReset
2767 // Description: reset internal structures, e.g. timers
2771 // Returns: tEplKernel = error code
2775 //---------------------------------------------------------------------------
2777 static tEplKernel EplNmtMnuReset(void)
2782 Ret = EplTimeruDeleteTimer(&EplNmtMnuInstance_g.m_TimerHdlNmtState);
2784 for (iIndex = 1; iIndex <= tabentries (EplNmtMnuInstance_g.m_aNodeInfo); iIndex++)
2786 // delete timer handles
2787 Ret = EplTimeruDeleteTimer(&EPL_NMTMNU_GET_NODEINFO(iIndex)->m_TimerHdlStatReq);
2788 Ret = EplTimeruDeleteTimer(&EPL_NMTMNU_GET_NODEINFO(iIndex)->m_TimerHdlLonger);
2795 #endif // #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)