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)
109 // defines for flags in node info structure
110 #define EPL_NMTMNU_NODE_FLAG_ISOCHRON 0x0001 // CN is being accessed isochronously
111 #define EPL_NMTMNU_NODE_FLAG_NOT_SCANNED 0x0002 // CN was not scanned once -> decrement SignalCounter and reset flag
112 #define EPL_NMTMNU_NODE_FLAG_HALTED 0x0004 // boot process for this CN is halted
113 #define EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED 0x0008 // NMT command was just issued, wrong NMT states will be tolerated
114 #define EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ 0x0300 // counter for StatusRequest timer handle
115 #define EPL_NMTMNU_NODE_FLAG_COUNT_LONGER 0x0C00 // counter for longer timeouts timer handle
116 #define EPL_NMTMNU_NODE_FLAG_INC_STATREQ 0x0100 // increment for StatusRequest timer handle
117 #define EPL_NMTMNU_NODE_FLAG_INC_LONGER 0x0400 // increment for longer timeouts timer handle
118 // These counters will be incremented at every timer start
119 // and copied to timerarg. When the timer event occures
120 // both will be compared and if unequal the timer event
121 // will be discarded, because it is an old one.
123 // defines for timer arguments to draw a distinction between serveral events
124 #define EPL_NMTMNU_TIMERARG_NODE_MASK 0x000000FFL // mask that contains the node-ID
125 #define EPL_NMTMNU_TIMERARG_IDENTREQ 0x00010000L // timer event is for IdentRequest
126 #define EPL_NMTMNU_TIMERARG_STATREQ 0x00020000L // timer event is for StatusRequest
127 #define EPL_NMTMNU_TIMERARG_LONGER 0x00040000L // timer event is for longer timeouts
128 #define EPL_NMTMNU_TIMERARG_STATE_MON 0x00080000L // timer event for StatusRequest to monitor execution of NMT state changes
129 #define EPL_NMTMNU_TIMERARG_COUNT_SR 0x00000300L // counter for StatusRequest
130 #define EPL_NMTMNU_TIMERARG_COUNT_LO 0x00000C00L // counter for longer timeouts
131 // The counters must have the same position as in the node flags above.
133 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_STATREQ(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
134 pNodeInfo_p->m_wFlags = \
135 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \
136 & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \
137 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
138 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_STATREQ | uiNodeId_p | \
139 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
140 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
142 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
143 pNodeInfo_p->m_wFlags = \
144 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \
145 & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \
146 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
147 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_IDENTREQ | uiNodeId_p | \
148 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
149 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
151 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
152 pNodeInfo_p->m_wFlags = \
153 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_LONGER) \
154 & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER) \
155 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_LONGER); \
156 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p | \
157 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER); \
158 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
160 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_STATE_MON(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
161 pNodeInfo_p->m_wFlags = \
162 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \
163 & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \
164 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
165 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_STATE_MON | uiNodeId_p | \
166 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
167 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
169 // defines for global flags
170 #define EPL_NMTMNU_FLAG_HALTED 0x0001 // boot process is halted
171 #define EPL_NMTMNU_FLAG_APP_INFORMED 0x0002 // application was informed about possible NMT state change
173 // return pointer to node info structure for specified node ID
174 // d.k. may be replaced by special (hash) function if node ID array is smaller than 254
175 #define EPL_NMTMNU_GET_NODEINFO(uiNodeId_p) (&EplNmtMnuInstance_g.m_aNodeInfo[uiNodeId_p - 1])
177 //---------------------------------------------------------------------------
179 //---------------------------------------------------------------------------
182 kEplNmtMnuIntNodeEventNoIdentResponse = 0x00,
183 kEplNmtMnuIntNodeEventIdentResponse = 0x01,
184 kEplNmtMnuIntNodeEventBoot = 0x02,
185 kEplNmtMnuIntNodeEventExecReset = 0x03,
186 kEplNmtMnuIntNodeEventConfigured = 0x04,
187 kEplNmtMnuIntNodeEventNoStatusResponse = 0x05,
188 kEplNmtMnuIntNodeEventStatusResponse = 0x06,
189 kEplNmtMnuIntNodeEventHeartbeat = 0x07,
190 kEplNmtMnuIntNodeEventNmtCmdSent = 0x08,
191 kEplNmtMnuIntNodeEventTimerIdentReq = 0x09,
192 kEplNmtMnuIntNodeEventTimerStatReq = 0x0A,
193 kEplNmtMnuIntNodeEventTimerStateMon = 0x0B,
194 kEplNmtMnuIntNodeEventTimerLonger = 0x0C,
195 kEplNmtMnuIntNodeEventError = 0x0D,
197 } tEplNmtMnuIntNodeEvent;
200 kEplNmtMnuNodeStateUnknown = 0x00,
201 kEplNmtMnuNodeStateIdentified = 0x01,
202 kEplNmtMnuNodeStateResetConf = 0x02, // CN reset after configuration update
203 kEplNmtMnuNodeStateConfigured = 0x03, // BootStep1 completed
204 kEplNmtMnuNodeStateReadyToOp = 0x04, // BootStep2 completed
205 kEplNmtMnuNodeStateComChecked = 0x05, // Communication checked successfully
206 kEplNmtMnuNodeStateOperational = 0x06, // CN is in NMT state OPERATIONAL
208 } tEplNmtMnuNodeState;
211 tEplTimerHdl m_TimerHdlStatReq; // timer to delay StatusRequests and IdentRequests
212 tEplTimerHdl m_TimerHdlLonger; // 2nd timer for NMT command EnableReadyToOp and CheckCommunication
213 tEplNmtMnuNodeState m_NodeState; // internal node state (kind of sub state of NMT state)
214 DWORD m_dwNodeCfg; // subindex from 0x1F81
215 WORD m_wFlags; // flags: CN is being accessed isochronously
217 } tEplNmtMnuNodeInfo;
220 tEplNmtMnuNodeInfo m_aNodeInfo[EPL_NMT_MAX_NODE_ID];
221 tEplTimerHdl m_TimerHdlNmtState; // timeout for stay in NMT state
222 unsigned int m_uiMandatorySlaveCount;
223 unsigned int m_uiSignalSlaveCount;
224 unsigned long m_ulStatusRequestDelay; // in [ms] (object 0x1006 * EPL_C_NMT_STATREQ_CYCLE)
225 unsigned long m_ulTimeoutReadyToOp; // in [ms] (object 0x1F89/5)
226 unsigned long m_ulTimeoutCheckCom; // in [ms] (object 0x1006 * MultiplexedCycleCount)
227 WORD m_wFlags; // global flags
228 DWORD m_dwNmtStartup; // object 0x1F80 NMT_StartUp_U32
229 tEplNmtMnuCbNodeEvent m_pfnCbNodeEvent;
230 tEplNmtMnuCbBootEvent m_pfnCbBootEvent;
232 } tEplNmtMnuInstance;
234 //---------------------------------------------------------------------------
236 //---------------------------------------------------------------------------
238 static tEplNmtMnuInstance EplNmtMnuInstance_g;
240 //---------------------------------------------------------------------------
241 // local function prototypes
242 //---------------------------------------------------------------------------
244 static tEplKernel PUBLIC EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p);
246 static tEplKernel PUBLIC EplNmtMnuCbIdentResponse(unsigned int uiNodeId_p,
250 static tEplKernel PUBLIC EplNmtMnuCbStatusResponse(unsigned int uiNodeId_p,
254 static tEplKernel EplNmtMnuCheckNmtState(unsigned int uiNodeId_p,
255 tEplNmtMnuNodeInfo * pNodeInfo_p,
256 tEplNmtState NodeNmtState_p,
258 tEplNmtState LocalNmtState_p);
260 static tEplKernel EplNmtMnuStartBootStep1(void);
262 static tEplKernel EplNmtMnuStartBootStep2(void);
264 static tEplKernel EplNmtMnuStartCheckCom(void);
266 static tEplKernel EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p,
267 tEplNmtMnuNodeInfo * pNodeInfo_p);
269 static tEplKernel EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p,
270 tEplNmtMnuNodeInfo * pNodeInfo_p);
272 static tEplKernel EplNmtMnuStartNodes(void);
274 static tEplKernel EplNmtMnuProcessInternalEvent(unsigned int uiNodeId_p,
275 tEplNmtState NodeNmtState_p,
277 tEplNmtMnuIntNodeEvent
280 static tEplKernel EplNmtMnuReset(void);
282 //=========================================================================//
284 // P U B L I C F U N C T I O N S //
286 //=========================================================================//
288 //---------------------------------------------------------------------------
290 // Function: EplNmtMnuInit
292 // Description: init first instance of the module
299 // Returns: tEplKernel = errorcode
304 //---------------------------------------------------------------------------
306 tEplKernel EplNmtMnuInit(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p,
307 tEplNmtMnuCbBootEvent pfnCbBootEvent_p)
311 Ret = EplNmtMnuAddInstance(pfnCbNodeEvent_p, pfnCbBootEvent_p);
316 //---------------------------------------------------------------------------
318 // Function: EplNmtMnuAddInstance
320 // Description: init other instances of the module
327 // Returns: tEplKernel = errorcode
332 //---------------------------------------------------------------------------
334 tEplKernel EplNmtMnuAddInstance(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p,
335 tEplNmtMnuCbBootEvent pfnCbBootEvent_p)
339 Ret = kEplSuccessful;
341 // reset instance structure
342 EPL_MEMSET(&EplNmtMnuInstance_g, 0, sizeof(EplNmtMnuInstance_g));
344 if ((pfnCbNodeEvent_p == NULL) || (pfnCbBootEvent_p == NULL)) {
345 Ret = kEplNmtInvalidParam;
348 EplNmtMnuInstance_g.m_pfnCbNodeEvent = pfnCbNodeEvent_p;
349 EplNmtMnuInstance_g.m_pfnCbBootEvent = pfnCbBootEvent_p;
351 // initialize StatusRequest delay
352 EplNmtMnuInstance_g.m_ulStatusRequestDelay = 5000L;
354 // register NmtMnResponse callback function
356 EplDlluCalRegAsndService(kEplDllAsndNmtRequest,
357 EplNmtMnuCbNmtRequest,
358 kEplDllAsndFilterLocal);
365 //---------------------------------------------------------------------------
367 // Function: EplNmtMnuDelInstance
369 // Description: delete instance
376 // Returns: tEplKernel = errorcode
381 //---------------------------------------------------------------------------
383 tEplKernel EplNmtMnuDelInstance()
387 Ret = kEplSuccessful;
389 // deregister NmtMnResponse callback function
391 EplDlluCalRegAsndService(kEplDllAsndNmtRequest, NULL,
392 kEplDllAsndFilterNone);
394 Ret = EplNmtMnuReset();
400 //---------------------------------------------------------------------------
402 // Function: EplNmtMnuSendNmtCommandEx
404 // Description: sends the specified NMT command to the specified node.
406 // Parameters: uiNodeId_p = node ID to which the NMT command will be sent
407 // NmtCommand_p = NMT command
409 // Returns: tEplKernel = error code
413 //---------------------------------------------------------------------------
415 tEplKernel EplNmtMnuSendNmtCommandEx(unsigned int uiNodeId_p,
416 tEplNmtCommand NmtCommand_p,
417 void *pNmtCommandData_p,
418 unsigned int uiDataSize_p)
420 tEplKernel Ret = kEplSuccessful;
421 tEplFrameInfo FrameInfo;
422 BYTE abBuffer[EPL_C_DLL_MINSIZE_NMTCMDEXT];
423 tEplFrame *pFrame = (tEplFrame *) abBuffer;
424 BOOL fSoftDeleteNode = FALSE;
426 if ((uiNodeId_p == 0) || (uiNodeId_p > EPL_C_ADR_BROADCAST)) { // invalid node ID specified
427 Ret = kEplInvalidNodeId;
431 if ((pNmtCommandData_p != NULL)
433 (EPL_C_DLL_MINSIZE_NMTCMDEXT - EPL_C_DLL_MINSIZE_NMTCMD))) {
434 Ret = kEplNmtInvalidParam;
437 // $$$ d.k. may be check in future versions if the caller wants to perform prohibited state transitions
438 // the CN should not perform these transitions, but the expected NMT state will be changed and never fullfilled.
441 EPL_MEMSET(pFrame, 0x00, sizeof(abBuffer));
442 AmiSetByteToLe(&pFrame->m_le_bDstNodeId, (BYTE) uiNodeId_p);
443 AmiSetByteToLe(&pFrame->m_Data.m_Asnd.m_le_bServiceId,
444 (BYTE) kEplDllAsndNmtCommand);
445 AmiSetByteToLe(&pFrame->m_Data.m_Asnd.m_Payload.m_NmtCommandService.
446 m_le_bNmtCommandId, (BYTE) NmtCommand_p);
447 if ((pNmtCommandData_p != NULL) && (uiDataSize_p > 0)) { // copy command data to frame
448 EPL_MEMCPY(&pFrame->m_Data.m_Asnd.m_Payload.m_NmtCommandService.
449 m_le_abNmtCommandData[0], pNmtCommandData_p,
452 // build info structure
453 FrameInfo.m_NetTime.m_dwNanoSec = 0;
454 FrameInfo.m_NetTime.m_dwSec = 0;
455 FrameInfo.m_pFrame = pFrame;
456 FrameInfo.m_uiFrameSize = sizeof(abBuffer);
459 #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_DLLU)) != 0)
460 Ret = EplDlluCalAsyncSend(&FrameInfo, // pointer to frameinfo
461 kEplDllAsyncReqPrioNmt); // priority
463 if (Ret != kEplSuccessful) {
467 EPL_DBGLVL_NMTMN_TRACE2("NMTCmd(%02X->%02X)\n", NmtCommand_p,
470 switch (NmtCommand_p) {
471 case kEplNmtCmdStartNode:
472 case kEplNmtCmdEnterPreOperational2:
473 case kEplNmtCmdEnableReadyToOperate:
475 // nothing left to do,
476 // because any further processing is done
477 // when the NMT command is actually sent
481 case kEplNmtCmdStopNode:
483 fSoftDeleteNode = TRUE;
487 case kEplNmtCmdResetNode:
488 case kEplNmtCmdResetCommunication:
489 case kEplNmtCmdResetConfiguration:
490 case kEplNmtCmdSwReset:
499 // remove CN from isochronous phase;
500 // This must be done here and not when NMT command is actually sent
501 // because it will be too late and may cause unwanted errors
502 if (uiNodeId_p != EPL_C_ADR_BROADCAST) {
503 if (fSoftDeleteNode == FALSE) { // remove CN immediately from isochronous phase
504 Ret = EplDlluCalDeleteNode(uiNodeId_p);
505 } else { // remove CN from isochronous phase softly
506 Ret = EplDlluCalSoftDeleteNode(uiNodeId_p);
508 } else { // do it for all active CNs
510 uiNodeId_p <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo);
512 if ((EPL_NMTMNU_GET_NODEINFO(uiNodeId_p)->
513 m_dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN |
514 EPL_NODEASSIGN_NODE_EXISTS)) != 0) {
515 if (fSoftDeleteNode == FALSE) { // remove CN immediately from isochronous phase
516 Ret = EplDlluCalDeleteNode(uiNodeId_p);
517 } else { // remove CN from isochronous phase softly
519 EplDlluCalSoftDeleteNode
530 //---------------------------------------------------------------------------
532 // Function: EplNmtMnuSendNmtCommand
534 // Description: sends the specified NMT command to the specified node.
536 // Parameters: uiNodeId_p = node ID to which the NMT command will be sent
537 // NmtCommand_p = NMT command
539 // Returns: tEplKernel = error code
543 //---------------------------------------------------------------------------
545 tEplKernel EplNmtMnuSendNmtCommand(unsigned int uiNodeId_p,
546 tEplNmtCommand NmtCommand_p)
548 tEplKernel Ret = kEplSuccessful;
550 Ret = EplNmtMnuSendNmtCommandEx(uiNodeId_p, NmtCommand_p, NULL, 0);
556 //---------------------------------------------------------------------------
558 // Function: EplNmtMnuTriggerStateChange
560 // Description: triggers the specified node command for the specified node.
562 // Parameters: uiNodeId_p = node ID for which the node command will be executed
563 // NodeCommand_p = node command
565 // Returns: tEplKernel = error code
569 //---------------------------------------------------------------------------
571 tEplKernel EplNmtMnuTriggerStateChange(unsigned int uiNodeId_p,
572 tEplNmtNodeCommand NodeCommand_p)
574 tEplKernel Ret = kEplSuccessful;
575 tEplNmtMnuIntNodeEvent NodeEvent;
578 WORD wErrorCode = EPL_E_NO_ERROR;
580 if ((uiNodeId_p == 0) || (uiNodeId_p >= EPL_C_ADR_BROADCAST)) {
581 Ret = kEplInvalidNodeId;
585 switch (NodeCommand_p) {
586 case kEplNmtNodeCommandBoot:
588 NodeEvent = kEplNmtMnuIntNodeEventBoot;
592 case kEplNmtNodeCommandConfOk:
594 NodeEvent = kEplNmtMnuIntNodeEventConfigured;
598 case kEplNmtNodeCommandConfErr:
600 NodeEvent = kEplNmtMnuIntNodeEventError;
601 wErrorCode = EPL_E_NMT_BPO1_CF_VERIFY;
605 case kEplNmtNodeCommandConfReset:
607 NodeEvent = kEplNmtMnuIntNodeEventExecReset;
612 { // invalid node command
617 // fetch current NMT state
619 Ret = EplObduReadEntry(0x1F8E, uiNodeId_p, &bNmtState, &ObdSize);
620 if (Ret != kEplSuccessful) {
624 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
625 (tEplNmtState) (bNmtState |
627 wErrorCode, NodeEvent);
633 //---------------------------------------------------------------------------
635 // Function: EplNmtMnuCbNmtStateChange
637 // Description: callback function for NMT state changes
639 // Parameters: NmtStateChange_p = NMT state change event
641 // Returns: tEplKernel = error code
646 //---------------------------------------------------------------------------
648 tEplKernel PUBLIC EplNmtMnuCbNmtStateChange(tEplEventNmtStateChange
651 tEplKernel Ret = kEplSuccessful;
653 // do work which must be done in that state
654 switch (NmtStateChange_p.m_NewNmtState) {
655 // EPL stack is not running
656 /* case kEplNmtGsOff:
659 // first init of the hardware
660 case kEplNmtGsInitialising:
663 // init of the manufacturer-specific profile area and the
664 // standardised device profile area
665 case kEplNmtGsResetApplication:
670 // init of the communication profile area
671 case kEplNmtGsResetCommunication:
676 // build the configuration with infos from OD
677 case kEplNmtGsResetConfiguration:
682 // read object 0x1F80 NMT_StartUp_U32
685 EplObduReadEntry(0x1F80, 0,
686 &EplNmtMnuInstance_g.
687 m_dwNmtStartup, &ObdSize);
688 if (Ret != kEplSuccessful) {
691 // compute StatusReqDelay = object 0x1006 * EPL_C_NMT_STATREQ_CYCLE
692 ObdSize = sizeof(dwTimeout);
693 Ret = EplObduReadEntry(0x1006, 0, &dwTimeout, &ObdSize);
694 if (Ret != kEplSuccessful) {
697 if (dwTimeout != 0L) {
698 EplNmtMnuInstance_g.m_ulStatusRequestDelay =
699 dwTimeout * EPL_C_NMT_STATREQ_CYCLE / 1000L;
700 if (EplNmtMnuInstance_g.
701 m_ulStatusRequestDelay == 0L) {
702 EplNmtMnuInstance_g.m_ulStatusRequestDelay = 1L; // at least 1 ms
704 // $$$ fetch and use MultiplexedCycleCount from OD
705 EplNmtMnuInstance_g.m_ulTimeoutCheckCom =
706 dwTimeout * EPL_C_NMT_STATREQ_CYCLE / 1000L;
707 if (EplNmtMnuInstance_g.m_ulTimeoutCheckCom ==
709 EplNmtMnuInstance_g.m_ulTimeoutCheckCom = 1L; // at least 1 ms
712 // fetch ReadyToOp Timeout from OD
713 ObdSize = sizeof(dwTimeout);
714 Ret = EplObduReadEntry(0x1F89, 5, &dwTimeout, &ObdSize);
715 if (Ret != kEplSuccessful) {
718 if (dwTimeout != 0L) {
719 // convert [us] to [ms]
721 if (dwTimeout == 0L) {
722 dwTimeout = 1L; // at least 1 ms
724 EplNmtMnuInstance_g.m_ulTimeoutReadyToOp =
727 EplNmtMnuInstance_g.m_ulTimeoutReadyToOp = 0L;
732 //-----------------------------------------------------------
733 // CN part of the state machine
735 // node liste for EPL-Frames and check timeout
736 case kEplNmtCsNotActive:
741 // node process only async frames
742 case kEplNmtCsPreOperational1:
747 // node process isochronus and asynchronus frames
748 case kEplNmtCsPreOperational2:
753 // node should be configured und application is ready
754 case kEplNmtCsReadyToOperate:
760 case kEplNmtCsOperational:
765 // node stopped by MN
766 // -> only process asynchronus frames
767 case kEplNmtCsStopped:
773 // -> normal ethernet communication
774 case kEplNmtCsBasicEthernet:
779 //-----------------------------------------------------------
780 // MN part of the state machine
782 // node listens for EPL-Frames and check timeout
783 case kEplNmtMsNotActive:
788 // node processes only async frames
789 case kEplNmtMsPreOperational1:
792 tEplTimerArg TimerArg;
796 // clear global flags, e.g. reenable boot process
797 EplNmtMnuInstance_g.m_wFlags = 0;
799 // reset IdentResponses and running IdentRequests and StatusRequests
800 Ret = EplIdentuReset();
801 Ret = EplStatusuReset();
804 Ret = EplNmtMnuReset();
806 // 2008/11/18 d.k. reset internal node info is not necessary,
807 // because timer flags are important and other
808 // things are reset by EplNmtMnuStartBootStep1().
810 EPL_MEMSET(EplNmtMnuInstance_g.m_aNodeInfo,
812 sizeof (EplNmtMnuInstance_g.m_aNodeInfo));
815 // inform DLL about NMT state change,
816 // so that it can clear the asynchonous queues and start the reduced cycle
817 Event.m_EventSink = kEplEventSinkDllk;
818 Event.m_EventType = kEplEventTypeDllkStartReducedCycle;
819 EPL_MEMSET(&Event.m_NetTime, 0x00,
820 sizeof(Event.m_NetTime));
823 Ret = EplEventuPost(&Event);
824 if (Ret != kEplSuccessful) {
828 // d.k.: skip this step if was just done before, e.g. because of a ResetNode command from a diagnostic node
829 if (NmtStateChange_p.m_NmtEvent ==
830 kEplNmtEventTimerMsPreOp1) {
831 BENCHMARK_MOD_07_TOGGLE(9);
833 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
835 kEplNmtCmdResetNode);
838 EplNmtMnuSendNmtCommand(EPL_C_ADR_BROADCAST,
839 kEplNmtCmdResetNode);
840 if (Ret != kEplSuccessful) {
844 // start network scan
845 Ret = EplNmtMnuStartBootStep1();
847 // start timer for 0x1F89/2 MNTimeoutPreOp1_U32
848 ObdSize = sizeof(dwTimeout);
849 Ret = EplObduReadEntry(0x1F89, 2, &dwTimeout, &ObdSize);
850 if (Ret != kEplSuccessful) {
853 if (dwTimeout != 0L) {
855 if (dwTimeout == 0L) {
856 dwTimeout = 1L; // at least 1 ms
858 TimerArg.m_EventSink = kEplEventSinkNmtMnu;
859 TimerArg.m_ulArg = 0;
861 EplTimeruModifyTimerMs(&EplNmtMnuInstance_g.
863 dwTimeout, TimerArg);
868 // node processes isochronous and asynchronous frames
869 case kEplNmtMsPreOperational2:
871 // add identified CNs to isochronous phase
872 // send EnableReadyToOp to all identified CNs
873 Ret = EplNmtMnuStartBootStep2();
875 // wait for NMT state change of CNs
879 // node should be configured und application is ready
880 case kEplNmtMsReadyToOperate:
882 // check if PRes of CNs are OK
883 // d.k. that means wait CycleLength * MultiplexCycleCount (i.e. start timer)
884 // because Dllk checks PRes of CNs automatically in ReadyToOp
885 Ret = EplNmtMnuStartCheckCom();
890 case kEplNmtMsOperational:
892 // send StartNode to CNs
893 // wait for NMT state change of CNs
894 Ret = EplNmtMnuStartNodes();
899 // -> normal ethernet communication
900 case kEplNmtMsBasicEthernet:
907 // TRACE0("EplNmtMnuCbNmtStateChange(): unhandled NMT state\n");
914 //---------------------------------------------------------------------------
916 // Function: EplNmtMnuCbCheckEvent
918 // Description: callback funktion for NMT events before they are actually executed.
919 // The EPL API layer must forward NMT events from NmtCnu module.
920 // This module will reject some NMT commands while MN.
922 // Parameters: NmtEvent_p = outstanding NMT event for approval
924 // Returns: tEplKernel = error code
925 // kEplReject = reject the NMT event
929 //---------------------------------------------------------------------------
931 tEplKernel PUBLIC EplNmtMnuCbCheckEvent(tEplNmtEvent NmtEvent_p)
933 tEplKernel Ret = kEplSuccessful;
938 //---------------------------------------------------------------------------
940 // Function: EplNmtuProcessEvent
942 // Description: processes events from event queue
944 // Parameters: pEvent_p = pointer to event
946 // Returns: tEplKernel = errorcode
950 //---------------------------------------------------------------------------
952 EPLDLLEXPORT tEplKernel PUBLIC EplNmtMnuProcessEvent(tEplEvent * pEvent_p)
956 Ret = kEplSuccessful;
959 switch (pEvent_p->m_EventType) {
961 case kEplEventTypeTimer:
963 tEplTimerEventArg *pTimerEventArg =
964 (tEplTimerEventArg *) pEvent_p->m_pArg;
965 unsigned int uiNodeId;
968 (unsigned int)(pTimerEventArg->
970 EPL_NMTMNU_TIMERARG_NODE_MASK);
974 tEplNmtMnuNodeInfo *pNodeInfo;
976 pNodeInfo = EPL_NMTMNU_GET_NODEINFO(uiNodeId);
980 EplObduReadEntry(0x1F8E, uiNodeId,
981 &bNmtState, &ObdSize);
982 if (Ret != kEplSuccessful) {
986 if ((pTimerEventArg->
987 m_ulArg & EPL_NMTMNU_TIMERARG_IDENTREQ) !=
991 EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ)
992 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR)) { // this is an old (already deleted or modified) timer
993 // but not the current timer
995 EPL_NMTMNU_DBG_POST_TRACE_VALUE
996 (kEplNmtMnuIntNodeEventTimerIdentReq,
1005 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerIdentReq,
1007 ((pNodeInfo->m_NodeState << 8)
1009 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1010 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1013 EplNmtMnuProcessInternalEvent
1015 (tEplNmtState) (bNmtState |
1018 kEplNmtMnuIntNodeEventTimerIdentReq);
1021 else if ((pTimerEventArg->
1022 m_ulArg & EPL_NMTMNU_TIMERARG_STATREQ)
1026 EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ)
1027 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR)) { // this is an old (already deleted or modified) timer
1028 // but not the current timer
1030 EPL_NMTMNU_DBG_POST_TRACE_VALUE
1031 (kEplNmtMnuIntNodeEventTimerStatReq,
1040 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq,
1042 ((pNodeInfo->m_NodeState << 8)
1044 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1045 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1048 EplNmtMnuProcessInternalEvent
1050 (tEplNmtState) (bNmtState |
1053 kEplNmtMnuIntNodeEventTimerStatReq);
1056 else if ((pTimerEventArg->
1058 EPL_NMTMNU_TIMERARG_STATE_MON) !=
1062 EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ)
1063 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR)) { // this is an old (already deleted or modified) timer
1064 // but not the current timer
1066 EPL_NMTMNU_DBG_POST_TRACE_VALUE
1067 (kEplNmtMnuIntNodeEventTimerStateMon,
1076 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq,
1078 ((pNodeInfo->m_NodeState << 8)
1080 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1081 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1084 EplNmtMnuProcessInternalEvent
1086 (tEplNmtState) (bNmtState |
1089 kEplNmtMnuIntNodeEventTimerStateMon);
1092 else if ((pTimerEventArg->
1093 m_ulArg & EPL_NMTMNU_TIMERARG_LONGER)
1097 EPL_NMTMNU_NODE_FLAG_COUNT_LONGER)
1098 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_LO)) { // this is an old (already deleted or modified) timer
1099 // but not the current timer
1101 EPL_NMTMNU_DBG_POST_TRACE_VALUE
1102 (kEplNmtMnuIntNodeEventTimerLonger,
1111 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerLonger,
1113 ((pNodeInfo->m_NodeState << 8)
1115 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER) >> 6)
1116 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_LO) >> 8)));
1119 EplNmtMnuProcessInternalEvent
1121 (tEplNmtState) (bNmtState |
1124 kEplNmtMnuIntNodeEventTimerLonger);
1127 } else { // global timer event
1132 case kEplEventTypeHeartbeat:
1134 tEplHeartbeatEvent *pHeartbeatEvent =
1135 (tEplHeartbeatEvent *) pEvent_p->m_pArg;
1138 EplNmtMnuProcessInternalEvent(pHeartbeatEvent->
1144 kEplNmtMnuIntNodeEventHeartbeat);
1148 case kEplEventTypeNmtMnuNmtCmdSent:
1150 tEplFrame *pFrame = (tEplFrame *) pEvent_p->m_pArg;
1151 unsigned int uiNodeId;
1152 tEplNmtCommand NmtCommand;
1155 uiNodeId = AmiGetByteFromLe(&pFrame->m_le_bDstNodeId);
1157 (tEplNmtCommand) AmiGetByteFromLe(&pFrame->m_Data.
1159 m_NmtCommandService.
1160 m_le_bNmtCommandId);
1162 switch (NmtCommand) {
1163 case kEplNmtCmdStartNode:
1165 (BYTE) (kEplNmtCsOperational & 0xFF);
1168 case kEplNmtCmdStopNode:
1169 bNmtState = (BYTE) (kEplNmtCsStopped & 0xFF);
1172 case kEplNmtCmdEnterPreOperational2:
1174 (BYTE) (kEplNmtCsPreOperational2 & 0xFF);
1177 case kEplNmtCmdEnableReadyToOperate:
1178 // d.k. do not change expected node state, because of DS 1.0.0 7.3.1.2.1 Plain NMT State Command
1179 // and because node may not change NMT state within EPL_C_NMT_STATE_TOLERANCE
1181 (BYTE) (kEplNmtCsPreOperational2 & 0xFF);
1184 case kEplNmtCmdResetNode:
1185 case kEplNmtCmdResetCommunication:
1186 case kEplNmtCmdResetConfiguration:
1187 case kEplNmtCmdSwReset:
1188 bNmtState = (BYTE) (kEplNmtCsNotActive & 0xFF);
1189 // EplNmtMnuProcessInternalEvent() sets internal node state to kEplNmtMnuNodeStateUnknown
1190 // after next unresponded IdentRequest/StatusRequest
1197 // process as internal event which update expected NMT state in OD
1198 if (uiNodeId != EPL_C_ADR_BROADCAST) {
1199 Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1204 kEplNmtMnuIntNodeEventNmtCmdSent);
1206 } else { // process internal event for all active nodes (except myself)
1210 tabentries(EplNmtMnuInstance_g.
1211 m_aNodeInfo); uiNodeId++) {
1212 if ((EPL_NMTMNU_GET_NODEINFO(uiNodeId)->
1214 (EPL_NODEASSIGN_NODE_IS_CN |
1215 EPL_NODEASSIGN_NODE_EXISTS)) !=
1218 EplNmtMnuProcessInternalEvent
1220 (tEplNmtState) (bNmtState |
1223 kEplNmtMnuIntNodeEventNmtCmdSent);
1225 if (Ret != kEplSuccessful) {
1237 Ret = kEplNmtInvalidEvent;
1246 //---------------------------------------------------------------------------
1248 // Function: EplNmtMnuGetRunningTimerStatReq
1250 // Description: returns a bit field with running StatReq timers
1251 // just for debugging purposes
1253 // Parameters: (none)
1255 // Returns: tEplKernel = error code
1259 //---------------------------------------------------------------------------
1261 tEplKernel PUBLIC EplNmtMnuGetDiagnosticInfo(unsigned int
1262 *puiMandatorySlaveCount_p,
1264 *puiSignalSlaveCount_p,
1267 tEplKernel Ret = kEplSuccessful;
1269 if ((puiMandatorySlaveCount_p == NULL)
1270 || (puiSignalSlaveCount_p == NULL)
1271 || (pwFlags_p == NULL)) {
1272 Ret = kEplNmtInvalidParam;
1276 *puiMandatorySlaveCount_p = EplNmtMnuInstance_g.m_uiMandatorySlaveCount;
1277 *puiSignalSlaveCount_p = EplNmtMnuInstance_g.m_uiSignalSlaveCount;
1278 *pwFlags_p = EplNmtMnuInstance_g.m_wFlags;
1284 //---------------------------------------------------------------------------
1286 // Function: EplNmtMnuGetRunningTimerStatReq
1288 // Description: returns a bit field with running StatReq timers
1289 // just for debugging purposes
1291 // Parameters: (none)
1293 // Returns: tEplKernel = error code
1297 //---------------------------------------------------------------------------
1299 DWORD EplNmtMnuGetRunningTimerStatReq(void)
1301 tEplKernel Ret = kEplSuccessful;
1302 unsigned int uiIndex;
1303 tEplNmtMnuNodeInfo* pNodeInfo;
1305 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1306 for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++)
1308 if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateConfigured)
1310 // reset flag "scanned once"
1311 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_SCANNED;
1313 Ret = EplNmtMnuNodeBootStep2(uiIndex, pNodeInfo);
1314 if (Ret != kEplSuccessful)
1318 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1319 // signal slave counter shall be decremented if StatusRequest was sent once to a CN
1320 // mandatory slave counter shall be decremented if mandatory CN is ReadyToOp
1329 //=========================================================================//
1331 // P R I V A T E F U N C T I O N S //
1333 //=========================================================================//
1335 //---------------------------------------------------------------------------
1337 // Function: EplNmtMnuCbNmtRequest
1339 // Description: callback funktion for NmtRequest
1341 // Parameters: pFrameInfo_p = Frame with the NmtRequest
1343 // Returns: tEplKernel = error code
1348 //---------------------------------------------------------------------------
1350 static tEplKernel PUBLIC EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p)
1352 tEplKernel Ret = kEplSuccessful;
1354 // $$$ perform NMTRequest
1358 //---------------------------------------------------------------------------
1360 // Function: EplNmtMnuCbIdentResponse
1362 // Description: callback funktion for IdentResponse
1364 // Parameters: uiNodeId_p = node ID for which IdentReponse was received
1365 // pIdentResponse_p = pointer to IdentResponse
1366 // is NULL if node did not answer
1368 // Returns: tEplKernel = error code
1372 //---------------------------------------------------------------------------
1374 static tEplKernel PUBLIC EplNmtMnuCbIdentResponse(unsigned int uiNodeId_p,
1378 tEplKernel Ret = kEplSuccessful;
1380 if (pIdentResponse_p == NULL) { // node did not answer
1381 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p, kEplNmtCsNotActive, EPL_E_NMT_NO_IDENT_RES, // was EPL_E_NO_ERROR
1382 kEplNmtMnuIntNodeEventNoIdentResponse);
1383 } else { // node answered IdentRequest
1384 tEplObdSize ObdSize;
1386 WORD wErrorCode = EPL_E_NO_ERROR;
1387 tEplNmtState NmtState =
1388 (tEplNmtState) (AmiGetByteFromLe
1389 (&pIdentResponse_p->
1390 m_le_bNmtStatus) | EPL_NMT_TYPE_CS);
1392 // check IdentResponse $$$ move to ProcessIntern, because this function may be called also if CN
1394 // check DeviceType (0x1F84)
1397 EplObduReadEntry(0x1F84, uiNodeId_p, &dwDevType, &ObdSize);
1398 if (Ret != kEplSuccessful) {
1401 if (dwDevType != 0L) { // actually compare it with DeviceType from IdentResponse
1402 if (AmiGetDwordFromLe(&pIdentResponse_p->m_le_dwDeviceType) != dwDevType) { // wrong DeviceType
1403 NmtState = kEplNmtCsNotActive;
1404 wErrorCode = EPL_E_NMT_BPO1_DEVICE_TYPE;
1408 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1411 kEplNmtMnuIntNodeEventIdentResponse);
1418 //---------------------------------------------------------------------------
1420 // Function: EplNmtMnuCbStatusResponse
1422 // Description: callback funktion for StatusResponse
1424 // Parameters: uiNodeId_p = node ID for which IdentReponse was received
1425 // pIdentResponse_p = pointer to IdentResponse
1426 // is NULL if node did not answer
1428 // Returns: tEplKernel = error code
1432 //---------------------------------------------------------------------------
1434 static tEplKernel PUBLIC EplNmtMnuCbStatusResponse(unsigned int uiNodeId_p,
1435 tEplStatusResponse *
1438 tEplKernel Ret = kEplSuccessful;
1440 if (pStatusResponse_p == NULL) { // node did not answer
1441 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p, kEplNmtCsNotActive, EPL_E_NMT_NO_STATUS_RES, // was EPL_E_NO_ERROR
1442 kEplNmtMnuIntNodeEventNoStatusResponse);
1443 } else { // node answered StatusRequest
1444 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1447 (&pStatusResponse_p->
1451 kEplNmtMnuIntNodeEventStatusResponse);
1457 //---------------------------------------------------------------------------
1459 // Function: EplNmtMnuStartBootStep1
1461 // Description: starts BootStep1
1463 // Parameters: (none)
1465 // Returns: tEplKernel = error code
1469 //---------------------------------------------------------------------------
1471 static tEplKernel EplNmtMnuStartBootStep1(void)
1473 tEplKernel Ret = kEplSuccessful;
1474 unsigned int uiSubIndex;
1475 unsigned int uiLocalNodeId;
1477 tEplObdSize ObdSize;
1479 // $$$ d.k.: save current time for 0x1F89/2 MNTimeoutPreOp1_U32
1481 // start network scan
1482 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1483 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1485 uiLocalNodeId = EplObduGetNodeId();
1486 for (uiSubIndex = 1; uiSubIndex <= 254; uiSubIndex++) {
1489 EplObduReadEntry(0x1F81, uiSubIndex, &dwNodeCfg, &ObdSize);
1490 if (Ret != kEplSuccessful) {
1493 if (uiSubIndex != uiLocalNodeId) {
1494 // reset flags "not scanned" and "isochronous"
1495 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_wFlags &=
1496 ~(EPL_NMTMNU_NODE_FLAG_ISOCHRON |
1497 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED);
1499 if (uiSubIndex == EPL_C_ADR_DIAG_DEF_NODE_ID) { // diagnostic node must be scanned by MN in any case
1501 (EPL_NODEASSIGN_NODE_IS_CN |
1502 EPL_NODEASSIGN_NODE_EXISTS);
1503 // and it must be isochronously accessed
1504 dwNodeCfg &= ~EPL_NODEASSIGN_ASYNCONLY_NODE;
1506 // save node config in local node info structure
1507 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_dwNodeCfg =
1509 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_NodeState =
1510 kEplNmtMnuNodeStateUnknown;
1512 if ((dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN | EPL_NODEASSIGN_NODE_EXISTS)) != 0) { // node is configured as CN
1513 // identify the node
1515 EplIdentuRequestIdentResponse(uiSubIndex,
1516 EplNmtMnuCbIdentResponse);
1517 if (Ret != kEplSuccessful) {
1520 // set flag "not scanned"
1521 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_wFlags |=
1522 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1523 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1524 // signal slave counter shall be decremented if IdentRequest was sent once to a CN
1526 if ((dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN
1527 EplNmtMnuInstance_g.
1528 m_uiMandatorySlaveCount++;
1529 // mandatory slave counter shall be decremented if mandatory CN was configured successfully
1532 } else { // subindex of MN
1533 if ((dwNodeCfg & (EPL_NODEASSIGN_MN_PRES | EPL_NODEASSIGN_NODE_EXISTS)) != 0) { // MN shall send PRes
1534 tEplDllNodeInfo DllNodeInfo;
1536 EPL_MEMSET(&DllNodeInfo, 0,
1537 sizeof(DllNodeInfo));
1538 DllNodeInfo.m_uiNodeId = uiLocalNodeId;
1540 Ret = EplDlluCalAddNode(&DllNodeInfo);
1549 //---------------------------------------------------------------------------
1551 // Function: EplNmtMnuStartBootStep2
1553 // Description: starts BootStep2.
1554 // That means add nodes to isochronous phase and send
1555 // NMT EnableReadyToOp.
1557 // Parameters: (none)
1559 // Returns: tEplKernel = error code
1563 //---------------------------------------------------------------------------
1565 static tEplKernel EplNmtMnuStartBootStep2(void)
1567 tEplKernel Ret = kEplSuccessful;
1568 unsigned int uiIndex;
1569 tEplNmtMnuNodeInfo *pNodeInfo;
1571 if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0) { // boot process is not halted
1572 // add nodes to isochronous phase and send NMT EnableReadyToOp
1573 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1574 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1575 // reset flag that application was informed about possible state change
1576 EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED;
1578 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1580 uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo);
1581 uiIndex++, pNodeInfo++) {
1582 if (pNodeInfo->m_NodeState ==
1583 kEplNmtMnuNodeStateConfigured) {
1585 EplNmtMnuNodeBootStep2(uiIndex, pNodeInfo);
1586 if (Ret != kEplSuccessful) {
1589 // set flag "not scanned"
1590 pNodeInfo->m_wFlags |=
1591 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1593 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1594 // signal slave counter shall be decremented if StatusRequest was sent once to a CN
1596 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN
1597 EplNmtMnuInstance_g.
1598 m_uiMandatorySlaveCount++;
1600 // mandatory slave counter shall be decremented if mandatory CN is ReadyToOp
1609 //---------------------------------------------------------------------------
1611 // Function: EplNmtMnuNodeBootStep2
1613 // Description: starts BootStep2 for the specified node.
1614 // This means the CN is added to isochronous phase if not
1615 // async-only and it gets the NMT command EnableReadyToOp.
1616 // The CN must be in node state Configured, when it enters
1617 // BootStep2. When BootStep2 finishes, the CN is in node state
1619 // If TimeoutReadyToOp in object 0x1F89/5 is configured,
1620 // TimerHdlLonger will be started with this timeout.
1622 // Parameters: uiNodeId_p = node ID
1623 // pNodeInfo_p = pointer to internal node info structure
1625 // Returns: tEplKernel = error code
1629 //---------------------------------------------------------------------------
1631 static tEplKernel EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p,
1632 tEplNmtMnuNodeInfo * pNodeInfo_p)
1634 tEplKernel Ret = kEplSuccessful;
1635 tEplDllNodeInfo DllNodeInfo;
1637 tEplObdSize ObdSize;
1638 tEplTimerArg TimerArg;
1640 dwNodeCfg = pNodeInfo_p->m_dwNodeCfg;
1641 if ((dwNodeCfg & EPL_NODEASSIGN_ASYNCONLY_NODE) == 0) { // add node to isochronous phase
1642 DllNodeInfo.m_uiNodeId = uiNodeId_p;
1645 EplObduReadEntry(0x1F92, uiNodeId_p,
1646 &DllNodeInfo.m_dwPresTimeout, &ObdSize);
1647 if (Ret != kEplSuccessful) {
1653 EplObduReadEntry(0x1F8B, uiNodeId_p,
1654 &DllNodeInfo.m_wPreqPayloadLimit,
1656 if (Ret != kEplSuccessful) {
1662 EplObduReadEntry(0x1F8D, uiNodeId_p,
1663 &DllNodeInfo.m_wPresPayloadLimit,
1665 if (Ret != kEplSuccessful) {
1669 pNodeInfo_p->m_wFlags |= EPL_NMTMNU_NODE_FLAG_ISOCHRON;
1671 Ret = EplDlluCalAddNode(&DllNodeInfo);
1672 if (Ret != kEplSuccessful) {
1678 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
1680 kEplNmtCmdEnableReadyToOperate);
1683 EplNmtMnuSendNmtCommand(uiNodeId_p, kEplNmtCmdEnableReadyToOperate);
1684 if (Ret != kEplSuccessful) {
1688 if (EplNmtMnuInstance_g.m_ulTimeoutReadyToOp != 0L) { // start timer
1689 // when the timer expires the CN must be ReadyToOp
1690 EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(pNodeInfo_p, uiNodeId_p,
1692 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
1693 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p;
1695 EplTimeruModifyTimerMs(&pNodeInfo_p->m_TimerHdlLonger,
1696 EplNmtMnuInstance_g.
1697 m_ulTimeoutReadyToOp, TimerArg);
1704 //---------------------------------------------------------------------------
1706 // Function: EplNmtMnuStartCheckCom
1708 // Description: starts CheckCommunication
1710 // Parameters: (none)
1712 // Returns: tEplKernel = error code
1716 //---------------------------------------------------------------------------
1718 static tEplKernel EplNmtMnuStartCheckCom(void)
1720 tEplKernel Ret = kEplSuccessful;
1721 unsigned int uiIndex;
1722 tEplNmtMnuNodeInfo *pNodeInfo;
1724 if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0) { // boot process is not halted
1725 // wait some time and check that no communication error occurs
1726 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1727 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1728 // reset flag that application was informed about possible state change
1729 EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED;
1731 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1733 uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo);
1734 uiIndex++, pNodeInfo++) {
1735 if (pNodeInfo->m_NodeState ==
1736 kEplNmtMnuNodeStateReadyToOp) {
1737 Ret = EplNmtMnuNodeCheckCom(uiIndex, pNodeInfo);
1738 if (Ret == kEplReject) { // timer was started
1739 // wait until it expires
1740 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN
1741 EplNmtMnuInstance_g.
1742 m_uiMandatorySlaveCount++;
1744 } else if (Ret != kEplSuccessful) {
1747 // set flag "not scanned"
1748 pNodeInfo->m_wFlags |=
1749 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1751 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1752 // signal slave counter shall be decremented if timeout elapsed and regardless of an error
1753 // mandatory slave counter shall be decremented if timeout elapsed and no error occured
1758 Ret = kEplSuccessful;
1764 //---------------------------------------------------------------------------
1766 // Function: EplNmtMnuNodeCheckCom
1768 // Description: checks communication of the specified node.
1769 // That means wait some time and if no error occured everything
1772 // Parameters: uiNodeId_p = node ID
1773 // pNodeInfo_p = pointer to internal node info structure
1775 // Returns: tEplKernel = error code
1779 //---------------------------------------------------------------------------
1781 static tEplKernel EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p,
1782 tEplNmtMnuNodeInfo * pNodeInfo_p)
1784 tEplKernel Ret = kEplSuccessful;
1786 tEplTimerArg TimerArg;
1788 dwNodeCfg = pNodeInfo_p->m_dwNodeCfg;
1789 if (((dwNodeCfg & EPL_NODEASSIGN_ASYNCONLY_NODE) == 0)
1790 && (EplNmtMnuInstance_g.m_ulTimeoutCheckCom != 0L)) { // CN is not async-only and timeout for CheckCom was set
1792 // check communication,
1793 // that means wait some time and if no error occured everything is OK;
1795 // start timer (when the timer expires the CN must be still ReadyToOp)
1796 EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(pNodeInfo_p, uiNodeId_p,
1798 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
1799 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p;
1801 EplTimeruModifyTimerMs(&pNodeInfo_p->m_TimerHdlLonger,
1802 EplNmtMnuInstance_g.
1803 m_ulTimeoutCheckCom, TimerArg);
1805 // update mandatory slave counter, because timer was started
1806 if (Ret == kEplSuccessful) {
1809 } else { // timer was not started
1810 // assume everything is OK
1811 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateComChecked;
1818 //---------------------------------------------------------------------------
1820 // Function: EplNmtMnuStartNodes
1822 // Description: really starts all nodes which are ReadyToOp and CheckCom did not fail
1824 // Parameters: (none)
1826 // Returns: tEplKernel = error code
1830 //---------------------------------------------------------------------------
1832 static tEplKernel EplNmtMnuStartNodes(void)
1834 tEplKernel Ret = kEplSuccessful;
1835 unsigned int uiIndex;
1836 tEplNmtMnuNodeInfo *pNodeInfo;
1838 if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0) { // boot process is not halted
1839 // send NMT command Start Node
1840 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1841 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1842 // reset flag that application was informed about possible state change
1843 EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED;
1845 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1847 uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo);
1848 uiIndex++, pNodeInfo++) {
1849 if (pNodeInfo->m_NodeState ==
1850 kEplNmtMnuNodeStateComChecked) {
1851 if ((EplNmtMnuInstance_g.
1852 m_dwNmtStartup & EPL_NMTST_STARTALLNODES)
1854 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
1856 kEplNmtCmdStartNode);
1859 EplNmtMnuSendNmtCommand(uiIndex,
1860 kEplNmtCmdStartNode);
1861 if (Ret != kEplSuccessful) {
1866 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN
1867 EplNmtMnuInstance_g.
1868 m_uiMandatorySlaveCount++;
1870 // set flag "not scanned"
1871 pNodeInfo->m_wFlags |=
1872 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1874 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1875 // signal slave counter shall be decremented if StatusRequest was sent once to a CN
1876 // mandatory slave counter shall be decremented if mandatory CN is OPERATIONAL
1880 // $$$ inform application if EPL_NMTST_NO_STARTNODE is set
1882 if ((EplNmtMnuInstance_g.
1883 m_dwNmtStartup & EPL_NMTST_STARTALLNODES) != 0) {
1884 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0, EPL_C_ADR_BROADCAST,
1885 kEplNmtCmdStartNode);
1888 EplNmtMnuSendNmtCommand(EPL_C_ADR_BROADCAST,
1889 kEplNmtCmdStartNode);
1890 if (Ret != kEplSuccessful) {
1900 //---------------------------------------------------------------------------
1902 // Function: EplNmtMnuProcessInternalEvent
1904 // Description: processes internal node events
1906 // Parameters: uiNodeId_p = node ID
1907 // NodeNmtState_p = NMT state of CN
1908 // NodeEvent_p = occured events
1910 // Returns: tEplKernel = error code
1915 //---------------------------------------------------------------------------
1917 static tEplKernel EplNmtMnuProcessInternalEvent(unsigned int uiNodeId_p,
1918 tEplNmtState NodeNmtState_p,
1920 tEplNmtMnuIntNodeEvent
1923 tEplKernel Ret = kEplSuccessful;
1924 tEplNmtState NmtState;
1925 tEplNmtMnuNodeInfo *pNodeInfo;
1926 tEplTimerArg TimerArg;
1928 pNodeInfo = EPL_NMTMNU_GET_NODEINFO(uiNodeId_p);
1929 NmtState = EplNmtuGetNmtState();
1930 if (NmtState <= kEplNmtMsNotActive) { // MN is not active
1934 switch (NodeEvent_p) {
1935 case kEplNmtMnuIntNodeEventIdentResponse:
1939 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
1941 pNodeInfo->m_NodeState);
1943 if (pNodeInfo->m_NodeState !=
1944 kEplNmtMnuNodeStateResetConf) {
1945 pNodeInfo->m_NodeState =
1946 kEplNmtMnuNodeStateIdentified;
1948 // reset flags ISOCHRON and NMT_CMD_ISSUED
1949 pNodeInfo->m_wFlags &= ~(EPL_NMTMNU_NODE_FLAG_ISOCHRON
1951 EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED);
1953 if ((NmtState == kEplNmtMsPreOperational1)
1956 m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) !=
1958 // decrement only signal slave count
1959 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
1960 pNodeInfo->m_wFlags &=
1961 ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1963 // update object 0x1F8F NMT_MNNodeExpState_AU8 to PreOp1 (even if local state >= PreOp2)
1964 bNmtState = (BYTE) (kEplNmtCsPreOperational1 & 0xFF);
1966 EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState,
1969 // check NMT state of CN
1971 EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo,
1972 NodeNmtState_p, wErrorCode_p,
1974 if (Ret != kEplSuccessful) {
1975 if (Ret == kEplReject) {
1976 Ret = kEplSuccessful;
1980 // request StatusResponse immediately,
1981 // because we want a fast boot-up of CNs
1983 EplStatusuRequestStatusResponse(uiNodeId_p,
1984 EplNmtMnuCbStatusResponse);
1985 if (Ret != kEplSuccessful) {
1986 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
1990 if (Ret == kEplInvalidOperation) { // the only situation when this should happen is, when
1991 // StatusResponse was already requested from within
1992 // the StatReq timer event.
1993 // so ignore this error.
1994 Ret = kEplSuccessful;
2000 if (pNodeInfo->m_NodeState !=
2001 kEplNmtMnuNodeStateResetConf) {
2002 // inform application
2004 EplNmtMnuInstance_g.
2005 m_pfnCbNodeEvent(uiNodeId_p,
2006 kEplNmtNodeEventFound,
2011 EPL_NODEASSIGN_MANDATORY_CN)
2013 if (Ret == kEplReject) { // interrupt boot process on user request
2014 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2015 (NodeEvent_p, uiNodeId_p,
2016 ((pNodeInfo->m_NodeState << 8)
2019 Ret = kEplSuccessful;
2021 } else if (Ret != kEplSuccessful) {
2022 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2023 (NodeEvent_p, uiNodeId_p,
2024 ((pNodeInfo->m_NodeState << 8)
2030 // continue BootStep1
2033 case kEplNmtMnuIntNodeEventBoot:
2036 // $$$ check identification (vendor ID, product code, revision no, serial no)
2038 if (pNodeInfo->m_NodeState ==
2039 kEplNmtMnuNodeStateIdentified) {
2040 // $$$ check software
2042 // check/start configuration
2043 // inform application
2045 EplNmtMnuInstance_g.
2046 m_pfnCbNodeEvent(uiNodeId_p,
2047 kEplNmtNodeEventCheckConf,
2052 EPL_NODEASSIGN_MANDATORY_CN)
2054 if (Ret == kEplReject) { // interrupt boot process on user request
2055 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2056 (kEplNmtMnuIntNodeEventBoot,
2058 ((pNodeInfo->m_NodeState << 8)
2061 Ret = kEplSuccessful;
2063 } else if (Ret != kEplSuccessful) {
2064 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2065 (kEplNmtMnuIntNodeEventBoot,
2067 ((pNodeInfo->m_NodeState << 8)
2072 } else if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf) { // wrong CN state
2076 // $$$ d.k.: currently we assume configuration is OK
2078 // continue BootStep1
2081 case kEplNmtMnuIntNodeEventConfigured:
2083 if ((pNodeInfo->m_NodeState !=
2084 kEplNmtMnuNodeStateIdentified)
2085 && (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)) { // wrong CN state
2090 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateConfigured;
2092 if (NmtState == kEplNmtMsPreOperational1) {
2093 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // decrement mandatory CN counter
2094 EplNmtMnuInstance_g.
2095 m_uiMandatorySlaveCount--;
2098 // put optional node to next step (BootStep2)
2100 EplNmtMnuNodeBootStep2(uiNodeId_p,
2106 case kEplNmtMnuIntNodeEventNoIdentResponse:
2108 if ((NmtState == kEplNmtMsPreOperational1)
2111 m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) !=
2113 // decrement only signal slave count
2114 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2115 pNodeInfo->m_wFlags &=
2116 ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2119 if (pNodeInfo->m_NodeState !=
2120 kEplNmtMnuNodeStateResetConf) {
2121 pNodeInfo->m_NodeState =
2122 kEplNmtMnuNodeStateUnknown;
2124 // $$$ d.k. check start time for 0x1F89/2 MNTimeoutPreOp1_U32
2125 // $$$ d.k. check individual timeout 0x1F89/6 MNIdentificationTimeout_U32
2126 // if mandatory node and timeout elapsed -> halt boot procedure
2127 // trigger IdentRequest again (if >= PreOp2, after delay)
2128 if (NmtState >= kEplNmtMsPreOperational2) { // start timer
2129 EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ
2130 (pNodeInfo, uiNodeId_p, TimerArg);
2131 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
2132 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_IDENTREQ | uiNodeId_p;
2134 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventNoIdentResponse,
2136 ((pNodeInfo->m_NodeState << 8)
2138 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
2139 | ((TimerArg.m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
2142 EplTimeruModifyTimerMs(&pNodeInfo->
2144 EplNmtMnuInstance_g.
2145 m_ulStatusRequestDelay,
2147 } else { // trigger IdentRequest immediately
2149 EplIdentuRequestIdentResponse(uiNodeId_p,
2150 EplNmtMnuCbIdentResponse);
2155 case kEplNmtMnuIntNodeEventStatusResponse:
2157 if ((NmtState >= kEplNmtMsPreOperational2)
2160 m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) !=
2162 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2163 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2164 pNodeInfo->m_wFlags &=
2165 ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2167 // check NMT state of CN
2169 EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo,
2170 NodeNmtState_p, wErrorCode_p,
2172 if (Ret != kEplSuccessful) {
2173 if (Ret == kEplReject) {
2174 Ret = kEplSuccessful;
2179 if (NmtState == kEplNmtMsPreOperational1) {
2180 // request next StatusResponse immediately
2182 EplStatusuRequestStatusResponse(uiNodeId_p,
2183 EplNmtMnuCbStatusResponse);
2184 if (Ret != kEplSuccessful) {
2185 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2186 (NodeEvent_p, uiNodeId_p, Ret);
2189 } else if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_ISOCHRON) == 0) { // start timer
2190 // not isochronously accessed CN (e.g. async-only or stopped CN)
2191 EPL_NMTMNU_SET_FLAGS_TIMERARG_STATREQ(pNodeInfo,
2194 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
2195 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_STATREQ | uiNodeId_p;
2197 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventStatusResponse,
2199 ((pNodeInfo->m_NodeState << 8)
2201 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
2202 | ((TimerArg.m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
2205 EplTimeruModifyTimerMs(&pNodeInfo->
2207 EplNmtMnuInstance_g.
2208 m_ulStatusRequestDelay,
2215 case kEplNmtMnuIntNodeEventNoStatusResponse:
2217 // function CheckNmtState sets node state to unknown if necessary
2219 if ((NmtState >= kEplNmtMsPreOperational2)
2220 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2222 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2223 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2224 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2227 // check NMT state of CN
2229 EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo,
2230 NodeNmtState_p, wErrorCode_p,
2232 if (Ret != kEplSuccessful) {
2233 if (Ret == kEplReject) {
2234 Ret = kEplSuccessful;
2242 case kEplNmtMnuIntNodeEventError:
2243 { // currently only issued on kEplNmtNodeCommandConfErr
2245 if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified) { // wrong CN state
2249 // check NMT state of CN
2251 EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo,
2253 wErrorCode_p, NmtState);
2254 if (Ret != kEplSuccessful) {
2255 if (Ret == kEplReject) {
2256 Ret = kEplSuccessful;
2264 case kEplNmtMnuIntNodeEventExecReset:
2266 if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified) { // wrong CN state
2271 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateResetConf;
2273 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2278 kEplNmtCmdResetConfiguration));
2280 // send NMT reset configuration to CN for activation of configuration
2282 EplNmtMnuSendNmtCommand(uiNodeId_p,
2283 kEplNmtCmdResetConfiguration);
2288 case kEplNmtMnuIntNodeEventHeartbeat:
2291 if ((NmtState >= kEplNmtMsPreOperational2)
2292 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2294 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2295 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2296 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2299 // check NMT state of CN
2301 EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo,
2302 NodeNmtState_p, wErrorCode_p,
2304 if (Ret != kEplSuccessful) {
2305 if (Ret == kEplReject) {
2306 Ret = kEplSuccessful;
2314 case kEplNmtMnuIntNodeEventTimerIdentReq:
2316 EPL_DBGLVL_NMTMN_TRACE1
2317 ("TimerStatReq->IdentReq(%02X)\n", uiNodeId_p);
2318 // trigger IdentRequest again
2320 EplIdentuRequestIdentResponse(uiNodeId_p,
2321 EplNmtMnuCbIdentResponse);
2322 if (Ret != kEplSuccessful) {
2323 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2325 (((NodeNmtState_p & 0xFF) << 8)
2327 if (Ret == kEplInvalidOperation) { // this can happen because of a bug in EplTimeruLinuxKernel.c
2328 // so ignore this error.
2329 Ret = kEplSuccessful;
2336 case kEplNmtMnuIntNodeEventTimerStateMon:
2338 // reset NMT state change flag
2339 // because from now on the CN must have the correct NMT state
2340 pNodeInfo->m_wFlags &=
2341 ~EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED;
2343 // continue with normal StatReq processing
2346 case kEplNmtMnuIntNodeEventTimerStatReq:
2348 EPL_DBGLVL_NMTMN_TRACE1("TimerStatReq->StatReq(%02X)\n",
2350 // request next StatusResponse
2352 EplStatusuRequestStatusResponse(uiNodeId_p,
2353 EplNmtMnuCbStatusResponse);
2354 if (Ret != kEplSuccessful) {
2355 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2357 (((NodeNmtState_p & 0xFF) << 8)
2359 if (Ret == kEplInvalidOperation) { // the only situation when this should happen is, when
2360 // StatusResponse was already requested while processing
2361 // event IdentResponse.
2362 // so ignore this error.
2363 Ret = kEplSuccessful;
2370 case kEplNmtMnuIntNodeEventTimerLonger:
2372 switch (pNodeInfo->m_NodeState) {
2373 case kEplNmtMnuNodeStateConfigured:
2374 { // node should be ReadyToOp but it is not
2376 // check NMT state which shall be intentionally wrong, so that ERROR_TREATMENT will be started
2378 EplNmtMnuCheckNmtState(uiNodeId_p,
2383 if (Ret != kEplSuccessful) {
2384 if (Ret == kEplReject) {
2385 Ret = kEplSuccessful;
2393 case kEplNmtMnuNodeStateReadyToOp:
2394 { // CheckCom finished successfully
2396 pNodeInfo->m_NodeState =
2397 kEplNmtMnuNodeStateComChecked;
2401 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED)
2403 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2404 EplNmtMnuInstance_g.
2405 m_uiSignalSlaveCount--;
2406 pNodeInfo->m_wFlags &=
2407 ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2412 EPL_NODEASSIGN_MANDATORY_CN) !=
2414 // decrement mandatory slave counter
2415 EplNmtMnuInstance_g.
2416 m_uiMandatorySlaveCount--;
2418 if (NmtState != kEplNmtMsReadyToOperate) {
2419 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2420 (NodeEvent_p, uiNodeId_p,
2421 (((NodeNmtState_p & 0xFF)
2423 | kEplNmtCmdStartNode));
2425 // start optional CN
2427 EplNmtMnuSendNmtCommand
2429 kEplNmtCmdStartNode);
2442 case kEplNmtMnuIntNodeEventNmtCmdSent:
2446 // update expected NMT state with the one that results
2447 // from the sent NMT command
2448 bNmtState = (BYTE) (NodeNmtState_p & 0xFF);
2450 // write object 0x1F8F NMT_MNNodeExpState_AU8
2452 EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState,
2454 if (Ret != kEplSuccessful) {
2458 if (NodeNmtState_p == kEplNmtCsNotActive) { // restart processing with IdentRequest
2459 EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ
2460 (pNodeInfo, uiNodeId_p, TimerArg);
2461 } else { // monitor NMT state change with StatusRequest after
2462 // the corresponding delay;
2463 // until then wrong NMT states will be ignored
2464 EPL_NMTMNU_SET_FLAGS_TIMERARG_STATE_MON
2465 (pNodeInfo, uiNodeId_p, TimerArg);
2467 // set NMT state change flag
2468 pNodeInfo->m_wFlags |=
2469 EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED;
2473 EplTimeruModifyTimerMs(&pNodeInfo->
2475 EplNmtMnuInstance_g.
2476 m_ulStatusRequestDelay,
2479 // finish processing, because NmtState_p is the expected and not the current state
2489 // check if network is ready to change local NMT state and this was not done before
2490 if ((EplNmtMnuInstance_g.m_wFlags & (EPL_NMTMNU_FLAG_HALTED | EPL_NMTMNU_FLAG_APP_INFORMED)) == 0) { // boot process is not halted
2492 case kEplNmtMsPreOperational1:
2494 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount ==
2496 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all optional CNs scanned once and all mandatory CNs configured successfully
2497 EplNmtMnuInstance_g.m_wFlags |=
2498 EPL_NMTMNU_FLAG_APP_INFORMED;
2499 // inform application
2501 EplNmtMnuInstance_g.
2503 (kEplNmtBootEventBootStep1Finish,
2504 NmtState, EPL_E_NO_ERROR);
2505 if (Ret != kEplSuccessful) {
2506 if (Ret == kEplReject) {
2507 // wait for application
2508 Ret = kEplSuccessful;
2515 (kEplNmtEventAllMandatoryCNIdent);
2520 case kEplNmtMsPreOperational2:
2522 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount ==
2524 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all optional CNs checked once for ReadyToOp and all mandatory CNs are ReadyToOp
2525 EplNmtMnuInstance_g.m_wFlags |=
2526 EPL_NMTMNU_FLAG_APP_INFORMED;
2527 // inform application
2529 EplNmtMnuInstance_g.
2531 (kEplNmtBootEventBootStep2Finish,
2532 NmtState, EPL_E_NO_ERROR);
2533 if (Ret != kEplSuccessful) {
2534 if (Ret == kEplReject) {
2535 // wait for application
2536 Ret = kEplSuccessful;
2543 (kEplNmtEventEnterReadyToOperate);
2548 case kEplNmtMsReadyToOperate:
2550 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount ==
2552 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all CNs checked for errorless communication
2553 EplNmtMnuInstance_g.m_wFlags |=
2554 EPL_NMTMNU_FLAG_APP_INFORMED;
2555 // inform application
2557 EplNmtMnuInstance_g.
2559 (kEplNmtBootEventCheckComFinish,
2560 NmtState, EPL_E_NO_ERROR);
2561 if (Ret != kEplSuccessful) {
2562 if (Ret == kEplReject) {
2563 // wait for application
2564 Ret = kEplSuccessful;
2568 // enter Operational
2571 (kEplNmtEventEnterMsOperational);
2576 case kEplNmtMsOperational:
2578 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount ==
2580 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all optional CNs scanned once and all mandatory CNs are OPERATIONAL
2581 EplNmtMnuInstance_g.m_wFlags |=
2582 EPL_NMTMNU_FLAG_APP_INFORMED;
2583 // inform application
2585 EplNmtMnuInstance_g.
2587 (kEplNmtBootEventOperational,
2588 NmtState, EPL_E_NO_ERROR);
2589 if (Ret != kEplSuccessful) {
2590 if (Ret == kEplReject) {
2591 // ignore error code
2592 Ret = kEplSuccessful;
2611 //---------------------------------------------------------------------------
2613 // Function: EplNmtMnuCheckNmtState
2615 // Description: checks the NMT state, i.e. evaluates it with object 0x1F8F
2616 // NMT_MNNodeExpState_AU8 and updates object 0x1F8E
2617 // NMT_MNNodeCurrState_AU8.
2618 // It manipulates m_NodeState in internal node info structure.
2620 // Parameters: uiNodeId_p = node ID
2621 // NodeNmtState_p = NMT state of CN
2623 // Returns: tEplKernel = error code
2624 // kEplReject = CN was in wrong state and has been reset
2628 //---------------------------------------------------------------------------
2630 static tEplKernel EplNmtMnuCheckNmtState(unsigned int uiNodeId_p,
2631 tEplNmtMnuNodeInfo * pNodeInfo_p,
2632 tEplNmtState NodeNmtState_p,
2634 tEplNmtState LocalNmtState_p)
2636 tEplKernel Ret = kEplSuccessful;
2637 tEplObdSize ObdSize;
2640 tEplNmtState ExpNmtState;
2643 // read object 0x1F8F NMT_MNNodeExpState_AU8
2644 Ret = EplObduReadEntry(0x1F8F, uiNodeId_p, &bNmtState, &ObdSize);
2645 if (Ret != kEplSuccessful) {
2648 // compute expected NMT state
2649 ExpNmtState = (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS);
2650 // compute BYTE of current NMT state
2651 bNmtState = ((BYTE) NodeNmtState_p & 0xFF);
2653 if (ExpNmtState == kEplNmtCsNotActive) { // ignore the current state, because the CN shall be not active
2656 } else if ((ExpNmtState == kEplNmtCsPreOperational2)
2657 && (NodeNmtState_p == kEplNmtCsReadyToOperate)) { // CN switched to ReadyToOp
2658 // delete timer for timeout handling
2659 Ret = EplTimeruDeleteTimer(&pNodeInfo_p->m_TimerHdlLonger);
2660 if (Ret != kEplSuccessful) {
2663 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateReadyToOp;
2665 // update object 0x1F8F NMT_MNNodeExpState_AU8 to ReadyToOp
2666 Ret = EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState, 1);
2667 if (Ret != kEplSuccessful) {
2671 if ((pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN -> decrement counter
2672 EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2674 if (LocalNmtState_p >= kEplNmtMsReadyToOperate) { // start procedure CheckCommunication for this node
2675 Ret = EplNmtMnuNodeCheckCom(uiNodeId_p, pNodeInfo_p);
2676 if (Ret != kEplSuccessful) {
2680 if ((LocalNmtState_p == kEplNmtMsOperational)
2681 && (pNodeInfo_p->m_NodeState ==
2682 kEplNmtMnuNodeStateComChecked)) {
2683 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0, uiNodeId_p,
2684 (((NodeNmtState_p & 0xFF) << 8)
2686 kEplNmtCmdStartNode));
2688 // immediately start optional CN, because communication is always OK (e.g. async-only CN)
2690 EplNmtMnuSendNmtCommand(uiNodeId_p,
2691 kEplNmtCmdStartNode);
2692 if (Ret != kEplSuccessful) {
2698 } else if ((ExpNmtState == kEplNmtCsReadyToOperate)
2699 && (NodeNmtState_p == kEplNmtCsOperational)) { // CN switched to OPERATIONAL
2700 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateOperational;
2702 if ((pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN -> decrement counter
2703 EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2706 } else if ((ExpNmtState != NodeNmtState_p)
2707 && !((ExpNmtState == kEplNmtCsPreOperational1)
2708 && (NodeNmtState_p == kEplNmtCsPreOperational2))) { // CN is not in expected NMT state (without the exceptions above)
2712 m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0) {
2713 // decrement only signal slave count if checked once
2714 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2715 pNodeInfo_p->m_wFlags &=
2716 ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2719 if (pNodeInfo_p->m_NodeState == kEplNmtMnuNodeStateUnknown) { // CN is already in state unknown, which means that it got
2720 // NMT reset command earlier
2723 // -> CN is in wrong NMT state
2724 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateUnknown;
2726 if (wErrorCode_p == 0) { // assume wrong NMT state error
2727 if ((pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED) != 0) { // NMT command has been just issued;
2728 // ignore wrong NMT state until timer expires;
2729 // other errors like LOSS_PRES_TH are still processed
2733 wErrorCode_p = EPL_E_NMT_WRONG_STATE;
2736 BENCHMARK_MOD_07_TOGGLE(9);
2738 // $$$ start ERROR_TREATMENT and inform application
2739 Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
2740 kEplNmtNodeEventError,
2745 EPL_NODEASSIGN_MANDATORY_CN)
2747 if (Ret != kEplSuccessful) {
2751 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
2753 (((NodeNmtState_p & 0xFF) << 8)
2754 | kEplNmtCmdResetNode));
2757 // store error code in NMT command data for diagnostic purpose
2758 AmiSetWordToLe(&wbeErrorCode, wErrorCode_p);
2760 EplNmtMnuSendNmtCommandEx(uiNodeId_p, kEplNmtCmdResetNode,
2762 sizeof(wbeErrorCode));
2763 if (Ret == kEplSuccessful) {
2769 // check if NMT_MNNodeCurrState_AU8 has to be changed
2771 Ret = EplObduReadEntry(0x1F8E, uiNodeId_p, &bNmtStatePrev, &ObdSize);
2772 if (Ret != kEplSuccessful) {
2775 if (bNmtState != bNmtStatePrev) {
2776 // update object 0x1F8E NMT_MNNodeCurrState_AU8
2777 Ret = EplObduWriteEntry(0x1F8E, uiNodeId_p, &bNmtState, 1);
2778 if (Ret != kEplSuccessful) {
2781 Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
2782 kEplNmtNodeEventNmtState,
2787 EPL_NODEASSIGN_MANDATORY_CN)
2789 if (Ret != kEplSuccessful) {
2798 //---------------------------------------------------------------------------
2800 // Function: EplNmtMnuReset
2802 // Description: reset internal structures, e.g. timers
2806 // Returns: tEplKernel = error code
2810 //---------------------------------------------------------------------------
2812 static tEplKernel EplNmtMnuReset(void)
2817 Ret = EplTimeruDeleteTimer(&EplNmtMnuInstance_g.m_TimerHdlNmtState);
2819 for (iIndex = 1; iIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo);
2821 // delete timer handles
2823 EplTimeruDeleteTimer(&EPL_NMTMNU_GET_NODEINFO(iIndex)->
2826 EplTimeruDeleteTimer(&EPL_NMTMNU_GET_NODEINFO(iIndex)->
2833 #endif // #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)