Staging: add epl stack
[linux-2.6] / drivers / staging / epl / EplNmtMnu.c
1 /****************************************************************************
2
3   (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4       www.systec-electronic.com
5
6   Project:      openPOWERLINK
7
8   Description:  source file for NMT-MN-Module
9
10   License:
11
12     Redistribution and use in source and binary forms, with or without
13     modification, are permitted provided that the following conditions
14     are met:
15
16     1. Redistributions of source code must retain the above copyright
17        notice, this list of conditions and the following disclaimer.
18
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.
22
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.
27
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.
40
41     Severability Clause:
42
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.
49
50   -------------------------------------------------------------------------
51
52                 $RCSfile: EplNmtMnu.c,v $
53
54                 $Author: D.Krueger $
55
56                 $Revision: 1.18 $  $Date: 2008/11/19 09:52:24 $
57
58                 $State: Exp $
59
60                 Build Environment:
61                     GCC V3.4
62
63   -------------------------------------------------------------------------
64
65   Revision History:
66
67   2006/06/09 k.t.:   start of the implementation
68
69 ****************************************************************************/
70
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"
78
79 #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
80
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!"
83 #endif
84
85 //=========================================================================//
86 //                                                                         //
87 //          P R I V A T E   D E F I N I T I O N S                          //
88 //                                                                         //
89 //=========================================================================//
90
91 //---------------------------------------------------------------------------
92 // const defines
93 //---------------------------------------------------------------------------
94
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)
101 #else
102     #define TGT_DBG_SIGNAL_TRACE_POINT(p)
103     #define TGT_DBG_POST_TRACE_VALUE(v)
104 #endif
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)
108
109
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.
123
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.
133
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;
142
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;
151
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;
160
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;
169
170
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
174
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])
178
179 //---------------------------------------------------------------------------
180 // local types
181 //---------------------------------------------------------------------------
182
183 typedef enum
184 {
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,
199
200 } tEplNmtMnuIntNodeEvent;
201
202
203 typedef enum
204 {
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
212
213 } tEplNmtMnuNodeState;
214
215
216 typedef struct
217 {
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
223
224 } tEplNmtMnuNodeInfo;
225
226
227 typedef struct
228 {
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;
240
241 } tEplNmtMnuInstance;
242
243
244 //---------------------------------------------------------------------------
245 // local vars
246 //---------------------------------------------------------------------------
247
248 static tEplNmtMnuInstance   EplNmtMnuInstance_g;
249
250
251 //---------------------------------------------------------------------------
252 // local function prototypes
253 //---------------------------------------------------------------------------
254
255 static tEplKernel PUBLIC EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p);
256
257 static tEplKernel PUBLIC EplNmtMnuCbIdentResponse(
258                                     unsigned int        uiNodeId_p,
259                                     tEplIdentResponse*  pIdentResponse_p);
260
261 static tEplKernel PUBLIC EplNmtMnuCbStatusResponse(
262                                     unsigned int        uiNodeId_p,
263                                     tEplStatusResponse* pStatusResponse_p);
264
265 static tEplKernel EplNmtMnuCheckNmtState(
266                                     unsigned int        uiNodeId_p,
267                                     tEplNmtMnuNodeInfo* pNodeInfo_p,
268                                     tEplNmtState        NodeNmtState_p,
269                                     WORD                wErrorCode_p,
270                                     tEplNmtState        LocalNmtState_p);
271
272 static tEplKernel EplNmtMnuStartBootStep1(void);
273
274 static tEplKernel EplNmtMnuStartBootStep2(void);
275
276 static tEplKernel EplNmtMnuStartCheckCom(void);
277
278 static tEplKernel EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p, tEplNmtMnuNodeInfo* pNodeInfo_p);
279
280 static tEplKernel EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p, tEplNmtMnuNodeInfo* pNodeInfo_p);
281
282 static tEplKernel EplNmtMnuStartNodes(void);
283
284 static tEplKernel EplNmtMnuProcessInternalEvent(
285                                     unsigned int        uiNodeId_p,
286                                     tEplNmtState        NodeNmtState_p,
287                                     WORD                wErrorCode_p,
288                                     tEplNmtMnuIntNodeEvent NodeEvent_p);
289
290 static tEplKernel EplNmtMnuReset(void);
291
292
293
294 //=========================================================================//
295 //                                                                         //
296 //          P U B L I C   F U N C T I O N S                                //
297 //                                                                         //
298 //=========================================================================//
299
300 //---------------------------------------------------------------------------
301 //
302 // Function:    EplNmtMnuInit
303 //
304 // Description: init first instance of the module
305 //
306 //
307 //
308 // Parameters:
309 //
310 //
311 // Returns:     tEplKernel  = errorcode
312 //
313 //
314 // State:
315 //
316 //---------------------------------------------------------------------------
317
318 tEplKernel EplNmtMnuInit(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p,
319                          tEplNmtMnuCbBootEvent pfnCbBootEvent_p)
320 {
321 tEplKernel Ret;
322
323     Ret = EplNmtMnuAddInstance(pfnCbNodeEvent_p, pfnCbBootEvent_p);
324
325     return Ret;
326 }
327
328
329 //---------------------------------------------------------------------------
330 //
331 // Function:    EplNmtMnuAddInstance
332 //
333 // Description: init other instances of the module
334 //
335 //
336 //
337 // Parameters:
338 //
339 //
340 // Returns:     tEplKernel  = errorcode
341 //
342 //
343 // State:
344 //
345 //---------------------------------------------------------------------------
346
347 tEplKernel EplNmtMnuAddInstance(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p,
348                                 tEplNmtMnuCbBootEvent pfnCbBootEvent_p)
349 {
350 tEplKernel Ret;
351
352     Ret = kEplSuccessful;
353
354     // reset instance structure
355     EPL_MEMSET(&EplNmtMnuInstance_g, 0, sizeof (EplNmtMnuInstance_g));
356
357     if ((pfnCbNodeEvent_p == NULL) || (pfnCbBootEvent_p == NULL))
358     {
359         Ret = kEplNmtInvalidParam;
360         goto Exit;
361     }
362     EplNmtMnuInstance_g.m_pfnCbNodeEvent = pfnCbNodeEvent_p;
363     EplNmtMnuInstance_g.m_pfnCbBootEvent = pfnCbBootEvent_p;
364
365     // initialize StatusRequest delay
366     EplNmtMnuInstance_g.m_ulStatusRequestDelay = 5000L;
367
368     // register NmtMnResponse callback function
369     Ret = EplDlluCalRegAsndService(kEplDllAsndNmtRequest, EplNmtMnuCbNmtRequest, kEplDllAsndFilterLocal);
370
371 Exit:
372     return Ret;
373
374 }
375
376
377 //---------------------------------------------------------------------------
378 //
379 // Function:    EplNmtMnuDelInstance
380 //
381 // Description: delete instance
382 //
383 //
384 //
385 // Parameters:
386 //
387 //
388 // Returns:     tEplKernel  = errorcode
389 //
390 //
391 // State:
392 //
393 //---------------------------------------------------------------------------
394
395 tEplKernel EplNmtMnuDelInstance()
396 {
397 tEplKernel  Ret;
398
399     Ret = kEplSuccessful;
400
401     // deregister NmtMnResponse callback function
402     Ret = EplDlluCalRegAsndService(kEplDllAsndNmtRequest, NULL, kEplDllAsndFilterNone);
403
404     Ret = EplNmtMnuReset();
405
406     return Ret;
407
408 }
409
410
411 //---------------------------------------------------------------------------
412 //
413 // Function:    EplNmtMnuSendNmtCommandEx
414 //
415 // Description: sends the specified NMT command to the specified node.
416 //
417 // Parameters:  uiNodeId_p              = node ID to which the NMT command will be sent
418 //              NmtCommand_p            = NMT command
419 //
420 // Returns:     tEplKernel              = error code
421 //
422 // State:
423 //
424 //---------------------------------------------------------------------------
425
426 tEplKernel EplNmtMnuSendNmtCommandEx(unsigned int uiNodeId_p,
427                                     tEplNmtCommand  NmtCommand_p,
428                                     void* pNmtCommandData_p,
429                                     unsigned int uiDataSize_p)
430 {
431 tEplKernel      Ret = kEplSuccessful;
432 tEplFrameInfo   FrameInfo;
433 BYTE            abBuffer[EPL_C_DLL_MINSIZE_NMTCMDEXT];
434 tEplFrame*      pFrame = (tEplFrame*) abBuffer;
435 BOOL            fSoftDeleteNode = FALSE;
436
437     if ((uiNodeId_p == 0) || (uiNodeId_p > EPL_C_ADR_BROADCAST))
438     {   // invalid node ID specified
439         Ret = kEplInvalidNodeId;
440         goto Exit;
441     }
442
443     if ((pNmtCommandData_p != NULL) && (uiDataSize_p > (EPL_C_DLL_MINSIZE_NMTCMDEXT - EPL_C_DLL_MINSIZE_NMTCMD)))
444     {
445         Ret = kEplNmtInvalidParam;
446         goto Exit;
447     }
448
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.
451
452     // build frame
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,
457         (BYTE)NmtCommand_p);
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);
461     }
462
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);
468
469     // send NMT-Request
470 #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_DLLU)) != 0)
471     Ret = EplDlluCalAsyncSend(&FrameInfo,    // pointer to frameinfo
472                            kEplDllAsyncReqPrioNmt); // priority
473 #endif
474     if (Ret != kEplSuccessful)
475     {
476         goto Exit;
477     }
478
479     EPL_DBGLVL_NMTMN_TRACE2("NMTCmd(%02X->%02X)\n", NmtCommand_p, uiNodeId_p);
480
481     switch (NmtCommand_p)
482     {
483         case kEplNmtCmdStartNode:
484         case kEplNmtCmdEnterPreOperational2:
485         case kEplNmtCmdEnableReadyToOperate:
486         {
487             // nothing left to do,
488             // because any further processing is done
489             // when the NMT command is actually sent
490             goto Exit;
491         }
492
493         case kEplNmtCmdStopNode:
494         {
495             fSoftDeleteNode = TRUE;
496             break;
497         }
498
499         case kEplNmtCmdResetNode:
500         case kEplNmtCmdResetCommunication:
501         case kEplNmtCmdResetConfiguration:
502         case kEplNmtCmdSwReset:
503         {
504             break;
505         }
506
507         default:
508             goto Exit;
509     }
510
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)
515     {
516         if (fSoftDeleteNode == FALSE)
517         {   // remove CN immediately from isochronous phase
518             Ret = EplDlluCalDeleteNode(uiNodeId_p);
519         }
520         else
521         {   // remove CN from isochronous phase softly
522             Ret = EplDlluCalSoftDeleteNode(uiNodeId_p);
523         }
524     }
525     else
526     {   // do it for all active CNs
527         for (uiNodeId_p = 1; uiNodeId_p <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiNodeId_p++)
528         {
529             if ((EPL_NMTMNU_GET_NODEINFO(uiNodeId_p)->m_dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN | EPL_NODEASSIGN_NODE_EXISTS)) != 0)
530             {
531                 if (fSoftDeleteNode == FALSE)
532                 {   // remove CN immediately from isochronous phase
533                     Ret = EplDlluCalDeleteNode(uiNodeId_p);
534                 }
535                 else
536                 {   // remove CN from isochronous phase softly
537                     Ret = EplDlluCalSoftDeleteNode(uiNodeId_p);
538                 }
539             }
540         }
541     }
542
543 Exit:
544     return Ret;
545 }
546
547 //---------------------------------------------------------------------------
548 //
549 // Function:    EplNmtMnuSendNmtCommand
550 //
551 // Description: sends the specified NMT command to the specified node.
552 //
553 // Parameters:  uiNodeId_p              = node ID to which the NMT command will be sent
554 //              NmtCommand_p            = NMT command
555 //
556 // Returns:     tEplKernel              = error code
557 //
558 // State:
559 //
560 //---------------------------------------------------------------------------
561
562 tEplKernel EplNmtMnuSendNmtCommand(unsigned int uiNodeId_p,
563                                     tEplNmtCommand  NmtCommand_p)
564 {
565 tEplKernel      Ret = kEplSuccessful;
566
567     Ret = EplNmtMnuSendNmtCommandEx(uiNodeId_p, NmtCommand_p, NULL, 0);
568
569 //Exit:
570     return Ret;
571 }
572
573 //---------------------------------------------------------------------------
574 //
575 // Function:    EplNmtMnuTriggerStateChange
576 //
577 // Description: triggers the specified node command for the specified node.
578 //
579 // Parameters:  uiNodeId_p              = node ID for which the node command will be executed
580 //              NodeCommand_p           = node command
581 //
582 // Returns:     tEplKernel              = error code
583 //
584 // State:
585 //
586 //---------------------------------------------------------------------------
587
588 tEplKernel EplNmtMnuTriggerStateChange(unsigned int uiNodeId_p,
589                                        tEplNmtNodeCommand  NodeCommand_p)
590 {
591 tEplKernel      Ret = kEplSuccessful;
592 tEplNmtMnuIntNodeEvent  NodeEvent;
593 tEplObdSize         ObdSize;
594 BYTE                bNmtState;
595 WORD                wErrorCode = EPL_E_NO_ERROR;
596
597     if ((uiNodeId_p == 0) || (uiNodeId_p >= EPL_C_ADR_BROADCAST))
598     {
599         Ret = kEplInvalidNodeId;
600         goto Exit;
601     }
602
603     switch (NodeCommand_p)
604     {
605         case kEplNmtNodeCommandBoot:
606         {
607             NodeEvent = kEplNmtMnuIntNodeEventBoot;
608             break;
609         }
610
611         case kEplNmtNodeCommandConfOk:
612         {
613             NodeEvent = kEplNmtMnuIntNodeEventConfigured;
614             break;
615         }
616
617         case kEplNmtNodeCommandConfErr:
618         {
619             NodeEvent = kEplNmtMnuIntNodeEventError;
620             wErrorCode = EPL_E_NMT_BPO1_CF_VERIFY;
621             break;
622         }
623
624         case kEplNmtNodeCommandConfReset:
625         {
626             NodeEvent = kEplNmtMnuIntNodeEventExecReset;
627             break;
628         }
629
630         default:
631         {   // invalid node command
632             goto Exit;
633         }
634     }
635
636     // fetch current NMT state
637     ObdSize = 1;
638     Ret = EplObduReadEntry(0x1F8E, uiNodeId_p, &bNmtState, &ObdSize);
639     if (Ret != kEplSuccessful)
640     {
641         goto Exit;
642     }
643
644     Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
645                                         (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
646                                         wErrorCode,
647                                         NodeEvent);
648
649 Exit:
650     return Ret;
651 }
652
653 //---------------------------------------------------------------------------
654 //
655 // Function:    EplNmtMnuCbNmtStateChange
656 //
657 // Description: callback function for NMT state changes
658 //
659 // Parameters:  NmtStateChange_p        = NMT state change event
660 //
661 // Returns:     tEplKernel              = error code
662 //
663 //
664 // State:
665 //
666 //---------------------------------------------------------------------------
667
668 tEplKernel PUBLIC EplNmtMnuCbNmtStateChange(tEplEventNmtStateChange NmtStateChange_p)
669 {
670 tEplKernel      Ret = kEplSuccessful;
671
672     // do work which must be done in that state
673     switch (NmtStateChange_p.m_NewNmtState)
674     {
675         // EPL stack is not running
676 /*        case kEplNmtGsOff:
677             break;
678
679         // first init of the hardware
680         case kEplNmtGsInitialising:
681             break;
682
683         // init of the manufacturer-specific profile area and the
684         // standardised device profile area
685         case kEplNmtGsResetApplication:
686         {
687             break;
688         }
689
690         // init of the communication profile area
691         case kEplNmtGsResetCommunication:
692         {
693             break;
694         }
695 */
696         // build the configuration with infos from OD
697         case kEplNmtGsResetConfiguration:
698         {
699         DWORD           dwTimeout;
700         tEplObdSize     ObdSize;
701
702             // read object 0x1F80 NMT_StartUp_U32
703             ObdSize = 4;
704             Ret = EplObduReadEntry(0x1F80, 0, &EplNmtMnuInstance_g.m_dwNmtStartup, &ObdSize);
705             if (Ret != kEplSuccessful)
706             {
707                 break;
708             }
709
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)
714             {
715                 break;
716             }
717             if (dwTimeout != 0L)
718             {
719                 EplNmtMnuInstance_g.m_ulStatusRequestDelay = dwTimeout * EPL_C_NMT_STATREQ_CYCLE / 1000L;
720                 if (EplNmtMnuInstance_g.m_ulStatusRequestDelay == 0L)
721                 {
722                     EplNmtMnuInstance_g.m_ulStatusRequestDelay = 1L;    // at least 1 ms
723                 }
724
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)
728                 {
729                     EplNmtMnuInstance_g.m_ulTimeoutCheckCom = 1L;    // at least 1 ms
730                 }
731             }
732
733             // fetch ReadyToOp Timeout from OD
734             ObdSize = sizeof (dwTimeout);
735             Ret = EplObduReadEntry(0x1F89, 5, &dwTimeout, &ObdSize);
736             if (Ret != kEplSuccessful)
737             {
738                 break;
739             }
740             if (dwTimeout != 0L)
741             {
742                 // convert [us] to [ms]
743                 dwTimeout /= 1000L;
744                 if (dwTimeout == 0L)
745                 {
746                     dwTimeout = 1L;    // at least 1 ms
747                 }
748                 EplNmtMnuInstance_g.m_ulTimeoutReadyToOp = dwTimeout;
749             }
750             else
751             {
752                 EplNmtMnuInstance_g.m_ulTimeoutReadyToOp = 0L;
753             }
754             break;
755         }
756 /*
757         //-----------------------------------------------------------
758         // CN part of the state machine
759
760         // node liste for EPL-Frames and check timeout
761         case kEplNmtCsNotActive:
762         {
763             break;
764         }
765
766         // node process only async frames
767         case kEplNmtCsPreOperational1:
768         {
769             break;
770         }
771
772         // node process isochronus and asynchronus frames
773         case kEplNmtCsPreOperational2:
774         {
775             break;
776         }
777
778         // node should be configured und application is ready
779         case kEplNmtCsReadyToOperate:
780         {
781             break;
782         }
783
784         // normal work state
785         case kEplNmtCsOperational:
786         {
787             break;
788         }
789
790         // node stopped by MN
791         // -> only process asynchronus frames
792         case kEplNmtCsStopped:
793         {
794             break;
795         }
796
797         // no EPL cycle
798         // -> normal ethernet communication
799         case kEplNmtCsBasicEthernet:
800         {
801             break;
802         }
803 */
804         //-----------------------------------------------------------
805         // MN part of the state machine
806
807         // node listens for EPL-Frames and check timeout
808         case kEplNmtMsNotActive:
809         {
810             break;
811         }
812
813         // node processes only async frames
814         case kEplNmtMsPreOperational1:
815         {
816         DWORD           dwTimeout;
817         tEplTimerArg    TimerArg;
818         tEplObdSize     ObdSize;
819         tEplEvent       Event;
820
821             // clear global flags, e.g. reenable boot process
822             EplNmtMnuInstance_g.m_wFlags = 0;
823
824             // reset IdentResponses and running IdentRequests and StatusRequests
825             Ret = EplIdentuReset();
826             Ret = EplStatusuReset();
827
828             // reset timers
829             Ret = EplNmtMnuReset();
830
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().
834 /*
835             EPL_MEMSET(EplNmtMnuInstance_g.m_aNodeInfo,
836                        0,
837                        sizeof (EplNmtMnuInstance_g.m_aNodeInfo));
838 */
839
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));
845             Event.m_pArg = NULL;
846             Event.m_uiSize = 0;
847             Ret = EplEventuPost(&Event);
848             if (Ret != kEplSuccessful)
849             {
850                 break;
851             }
852
853             // reset all nodes
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)
856             {
857                 BENCHMARK_MOD_07_TOGGLE(9);
858
859                 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
860                                                 EPL_C_ADR_BROADCAST,
861                                                 kEplNmtCmdResetNode);
862
863                 Ret = EplNmtMnuSendNmtCommand(EPL_C_ADR_BROADCAST, kEplNmtCmdResetNode);
864                 if (Ret != kEplSuccessful)
865                 {
866                     break;
867                 }
868             }
869             // start network scan
870             Ret = EplNmtMnuStartBootStep1();
871
872             // start timer for 0x1F89/2 MNTimeoutPreOp1_U32
873             ObdSize = sizeof (dwTimeout);
874             Ret = EplObduReadEntry(0x1F89, 2, &dwTimeout, &ObdSize);
875             if (Ret != kEplSuccessful)
876             {
877                 break;
878             }
879             if (dwTimeout != 0L)
880             {
881                 dwTimeout /= 1000L;
882                 if (dwTimeout == 0L)
883                 {
884                     dwTimeout = 1L; // at least 1 ms
885                 }
886                 TimerArg.m_EventSink = kEplEventSinkNmtMnu;
887                 TimerArg.m_ulArg = 0;
888                 Ret = EplTimeruModifyTimerMs(&EplNmtMnuInstance_g.m_TimerHdlNmtState, dwTimeout, TimerArg);
889             }
890             break;
891         }
892
893         // node processes isochronous and asynchronous frames
894         case kEplNmtMsPreOperational2:
895         {
896             // add identified CNs to isochronous phase
897             // send EnableReadyToOp to all identified CNs
898             Ret = EplNmtMnuStartBootStep2();
899
900             // wait for NMT state change of CNs
901             break;
902         }
903
904         // node should be configured und application is ready
905         case kEplNmtMsReadyToOperate:
906         {
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();
911             break;
912         }
913
914         // normal work state
915         case kEplNmtMsOperational:
916         {
917             // send StartNode to CNs
918             // wait for NMT state change of CNs
919             Ret = EplNmtMnuStartNodes();
920             break;
921         }
922
923         // no EPL cycle
924         // -> normal ethernet communication
925         case kEplNmtMsBasicEthernet:
926         {
927             break;
928         }
929
930         default:
931         {
932 //            TRACE0("EplNmtMnuCbNmtStateChange(): unhandled NMT state\n");
933         }
934     }
935
936     return Ret;
937 }
938
939
940 //---------------------------------------------------------------------------
941 //
942 // Function:    EplNmtMnuCbCheckEvent
943 //
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.
947 //
948 // Parameters:  NmtEvent_p              = outstanding NMT event for approval
949 //
950 // Returns:     tEplKernel              = error code
951 //                      kEplReject      = reject the NMT event
952 //
953 // State:
954 //
955 //---------------------------------------------------------------------------
956
957 tEplKernel PUBLIC EplNmtMnuCbCheckEvent(tEplNmtEvent NmtEvent_p)
958 {
959 tEplKernel      Ret = kEplSuccessful;
960
961     return Ret;
962 }
963
964
965 //---------------------------------------------------------------------------
966 //
967 // Function:    EplNmtuProcessEvent
968 //
969 // Description: processes events from event queue
970 //
971 // Parameters:  pEvent_p        = pointer to event
972 //
973 // Returns:     tEplKernel      = errorcode
974 //
975 // State:
976 //
977 //---------------------------------------------------------------------------
978
979 EPLDLLEXPORT tEplKernel PUBLIC EplNmtMnuProcessEvent(
980             tEplEvent* pEvent_p)
981 {
982 tEplKernel      Ret;
983
984     Ret = kEplSuccessful;
985
986     // process event
987     switch(pEvent_p->m_EventType)
988     {
989         // timer event
990         case kEplEventTypeTimer:
991         {
992         tEplTimerEventArg*  pTimerEventArg = (tEplTimerEventArg*)pEvent_p->m_pArg;
993         unsigned int        uiNodeId;
994
995             uiNodeId = (unsigned int) (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_NODE_MASK);
996             if (uiNodeId != 0)
997             {
998             tEplObdSize         ObdSize;
999             BYTE                bNmtState;
1000             tEplNmtMnuNodeInfo* pNodeInfo;
1001
1002                 pNodeInfo = EPL_NMTMNU_GET_NODEINFO(uiNodeId);
1003
1004                 ObdSize = 1;
1005                 Ret = EplObduReadEntry(0x1F8E, uiNodeId, &bNmtState, &ObdSize);
1006                 if (Ret != kEplSuccessful)
1007                 {
1008                     break;
1009                 }
1010
1011                 if ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_IDENTREQ) != 0L)
1012                 {
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
1017                         // so discard it
1018                         EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerIdentReq,
1019                                                         uiNodeId,
1020                                                         ((pNodeInfo->m_NodeState << 8)
1021                                                          | 0xFF));
1022
1023                         break;
1024                     }
1025 /*
1026                     EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerIdentReq,
1027                                                     uiNodeId,
1028                                                     ((pNodeInfo->m_NodeState << 8)
1029                                                      | 0x80
1030                                                      | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1031                                                      | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1032 */
1033                     Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1034                                                         (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1035                                                         EPL_E_NO_ERROR,
1036                                                         kEplNmtMnuIntNodeEventTimerIdentReq);
1037                 }
1038
1039                 else if ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_STATREQ) != 0L)
1040                 {
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
1045                         // so discard it
1046                         EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq,
1047                                                         uiNodeId,
1048                                                         ((pNodeInfo->m_NodeState << 8)
1049                                                          | 0xFF));
1050
1051                         break;
1052                     }
1053 /*
1054                     EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq,
1055                                                     uiNodeId,
1056                                                     ((pNodeInfo->m_NodeState << 8)
1057                                                      | 0x80
1058                                                      | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1059                                                      | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1060 */
1061                     Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1062                                                         (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1063                                                         EPL_E_NO_ERROR,
1064                                                         kEplNmtMnuIntNodeEventTimerStatReq);
1065                 }
1066
1067                 else if ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_STATE_MON) != 0L)
1068                 {
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
1073                         // so discard it
1074                         EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStateMon,
1075                                                         uiNodeId,
1076                                                         ((pNodeInfo->m_NodeState << 8)
1077                                                          | 0xFF));
1078
1079                         break;
1080                     }
1081 /*
1082                     EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq,
1083                                                     uiNodeId,
1084                                                     ((pNodeInfo->m_NodeState << 8)
1085                                                      | 0x80
1086                                                      | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1087                                                      | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1088 */
1089                     Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1090                                                         (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1091                                                         EPL_E_NO_ERROR,
1092                                                         kEplNmtMnuIntNodeEventTimerStateMon);
1093                 }
1094
1095                 else if ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_LONGER) != 0L)
1096                 {
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
1101                         // so discard it
1102                         EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerLonger,
1103                                                         uiNodeId,
1104                                                         ((pNodeInfo->m_NodeState << 8)
1105                                                          | 0xFF));
1106
1107                         break;
1108                     }
1109 /*
1110                     EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerLonger,
1111                                                     uiNodeId,
1112                                                     ((pNodeInfo->m_NodeState << 8)
1113                                                      | 0x80
1114                                                      | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER) >> 6)
1115                                                      | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_LO) >> 8)));
1116 */
1117                     Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1118                                                         (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1119                                                         EPL_E_NO_ERROR,
1120                                                         kEplNmtMnuIntNodeEventTimerLonger);
1121                 }
1122
1123             }
1124             else
1125             {   // global timer event
1126             }
1127             break;
1128         }
1129
1130         case kEplEventTypeHeartbeat:
1131         {
1132         tEplHeartbeatEvent* pHeartbeatEvent = (tEplHeartbeatEvent*)pEvent_p->m_pArg;
1133
1134             Ret = EplNmtMnuProcessInternalEvent(pHeartbeatEvent->m_uiNodeId,
1135                                                 pHeartbeatEvent->m_NmtState,
1136                                                 pHeartbeatEvent->m_wErrorCode,
1137                                                 kEplNmtMnuIntNodeEventHeartbeat);
1138             break;
1139         }
1140
1141         case kEplEventTypeNmtMnuNmtCmdSent:
1142         {
1143         tEplFrame* pFrame = (tEplFrame*)pEvent_p->m_pArg;
1144         unsigned int        uiNodeId;
1145         tEplNmtCommand      NmtCommand;
1146         BYTE                bNmtState;
1147
1148             uiNodeId = AmiGetByteFromLe(&pFrame->m_le_bDstNodeId);
1149             NmtCommand = (tEplNmtCommand) AmiGetByteFromLe(&pFrame->m_Data.m_Asnd.m_Payload.m_NmtCommandService.m_le_bNmtCommandId);
1150
1151             switch (NmtCommand)
1152             {
1153                 case kEplNmtCmdStartNode:
1154                     bNmtState = (BYTE) (kEplNmtCsOperational & 0xFF);
1155                     break;
1156
1157                 case kEplNmtCmdStopNode:
1158                     bNmtState = (BYTE) (kEplNmtCsStopped & 0xFF);
1159                     break;
1160
1161                 case kEplNmtCmdEnterPreOperational2:
1162                     bNmtState = (BYTE) (kEplNmtCsPreOperational2 & 0xFF);
1163                     break;
1164
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);
1169                     break;
1170
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
1178                     break;
1179
1180                 default:
1181                     goto Exit;
1182             }
1183
1184             // process as internal event which update expected NMT state in OD
1185             if (uiNodeId != EPL_C_ADR_BROADCAST)
1186             {
1187                 Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1188                                                     (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1189                                                     0,
1190                                                     kEplNmtMnuIntNodeEventNmtCmdSent);
1191
1192             }
1193             else
1194             {   // process internal event for all active nodes (except myself)
1195
1196                 for (uiNodeId = 1; uiNodeId <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiNodeId++)
1197                 {
1198                     if ((EPL_NMTMNU_GET_NODEINFO(uiNodeId)->m_dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN | EPL_NODEASSIGN_NODE_EXISTS)) != 0)
1199                     {
1200                         Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1201                                                             (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS),
1202                                                             0,
1203                                                             kEplNmtMnuIntNodeEventNmtCmdSent);
1204
1205                         if (Ret != kEplSuccessful)
1206                         {
1207                             goto Exit;
1208                         }
1209                     }
1210                 }
1211             }
1212
1213             break;
1214         }
1215
1216         default:
1217         {
1218             Ret = kEplNmtInvalidEvent;
1219         }
1220
1221     }
1222
1223 Exit:
1224     return Ret;
1225 }
1226
1227
1228 //---------------------------------------------------------------------------
1229 //
1230 // Function:    EplNmtMnuGetRunningTimerStatReq
1231 //
1232 // Description: returns a bit field with running StatReq timers
1233 //              just for debugging purposes
1234 //
1235 // Parameters:  (none)
1236 //
1237 // Returns:     tEplKernel              = error code
1238 //
1239 // State:
1240 //
1241 //---------------------------------------------------------------------------
1242
1243 tEplKernel PUBLIC EplNmtMnuGetDiagnosticInfo(unsigned int* puiMandatorySlaveCount_p,
1244                                              unsigned int* puiSignalSlaveCount_p,
1245                                              WORD* pwFlags_p)
1246 {
1247 tEplKernel      Ret = kEplSuccessful;
1248
1249     if ((puiMandatorySlaveCount_p == NULL)
1250         || (puiSignalSlaveCount_p == NULL)
1251         || (pwFlags_p == NULL))
1252     {
1253         Ret = kEplNmtInvalidParam;
1254         goto Exit;
1255     }
1256
1257     *puiMandatorySlaveCount_p = EplNmtMnuInstance_g.m_uiMandatorySlaveCount;
1258     *puiSignalSlaveCount_p = EplNmtMnuInstance_g.m_uiSignalSlaveCount;
1259     *pwFlags_p = EplNmtMnuInstance_g.m_wFlags;
1260
1261 Exit:
1262     return Ret;
1263 }
1264
1265
1266 //---------------------------------------------------------------------------
1267 //
1268 // Function:    EplNmtMnuGetRunningTimerStatReq
1269 //
1270 // Description: returns a bit field with running StatReq timers
1271 //              just for debugging purposes
1272 //
1273 // Parameters:  (none)
1274 //
1275 // Returns:     tEplKernel              = error code
1276 //
1277 // State:
1278 //
1279 //---------------------------------------------------------------------------
1280 /*
1281 DWORD EplNmtMnuGetRunningTimerStatReq(void)
1282 {
1283 tEplKernel      Ret = kEplSuccessful;
1284 unsigned int    uiIndex;
1285 tEplNmtMnuNodeInfo* pNodeInfo;
1286
1287     pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1288     for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++)
1289     {
1290         if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateConfigured)
1291         {
1292             // reset flag "scanned once"
1293             pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_SCANNED;
1294
1295             Ret = EplNmtMnuNodeBootStep2(uiIndex, pNodeInfo);
1296             if (Ret != kEplSuccessful)
1297             {
1298                 goto Exit;
1299             }
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
1303         }
1304     }
1305
1306 Exit:
1307     return Ret;
1308 }
1309 */
1310
1311 //=========================================================================//
1312 //                                                                         //
1313 //          P R I V A T E   F U N C T I O N S                              //
1314 //                                                                         //
1315 //=========================================================================//
1316
1317 //---------------------------------------------------------------------------
1318 //
1319 // Function:    EplNmtMnuCbNmtRequest
1320 //
1321 // Description: callback funktion for NmtRequest
1322 //
1323 // Parameters:  pFrameInfo_p            = Frame with the NmtRequest
1324 //
1325 // Returns:     tEplKernel              = error code
1326 //
1327 //
1328 // State:
1329 //
1330 //---------------------------------------------------------------------------
1331
1332 static tEplKernel PUBLIC EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p)
1333 {
1334 tEplKernel      Ret = kEplSuccessful;
1335
1336     // $$$ perform NMTRequest
1337     return Ret;
1338 }
1339
1340
1341 //---------------------------------------------------------------------------
1342 //
1343 // Function:    EplNmtMnuCbIdentResponse
1344 //
1345 // Description: callback funktion for IdentResponse
1346 //
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
1350 //
1351 // Returns:     tEplKernel              = error code
1352 //
1353 // State:
1354 //
1355 //---------------------------------------------------------------------------
1356
1357 static tEplKernel PUBLIC EplNmtMnuCbIdentResponse(
1358                                   unsigned int        uiNodeId_p,
1359                                   tEplIdentResponse* pIdentResponse_p)
1360 {
1361 tEplKernel      Ret = kEplSuccessful;
1362
1363     if (pIdentResponse_p == NULL)
1364     {   // node did not answer
1365         Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1366                                             kEplNmtCsNotActive,
1367                                             EPL_E_NMT_NO_IDENT_RES, // was EPL_E_NO_ERROR
1368                                             kEplNmtMnuIntNodeEventNoIdentResponse);
1369     }
1370     else
1371     {   // node answered IdentRequest
1372     tEplObdSize ObdSize;
1373     DWORD       dwDevType;
1374     WORD        wErrorCode = EPL_E_NO_ERROR;
1375     tEplNmtState NmtState = (tEplNmtState) (AmiGetByteFromLe(&pIdentResponse_p->m_le_bNmtStatus) | EPL_NMT_TYPE_CS);
1376
1377         // check IdentResponse $$$ move to ProcessIntern, because this function may be called also if CN
1378
1379         // check DeviceType (0x1F84)
1380         ObdSize = 4;
1381         Ret = EplObduReadEntry(0x1F84, uiNodeId_p, &dwDevType, &ObdSize);
1382         if (Ret != kEplSuccessful)
1383         {
1384             goto Exit;
1385         }
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;
1392             }
1393         }
1394
1395         Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1396                                             NmtState,
1397                                             wErrorCode,
1398                                             kEplNmtMnuIntNodeEventIdentResponse);
1399     }
1400
1401 Exit:
1402     return Ret;
1403 }
1404
1405
1406 //---------------------------------------------------------------------------
1407 //
1408 // Function:    EplNmtMnuCbStatusResponse
1409 //
1410 // Description: callback funktion for StatusResponse
1411 //
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
1415 //
1416 // Returns:     tEplKernel              = error code
1417 //
1418 // State:
1419 //
1420 //---------------------------------------------------------------------------
1421
1422 static tEplKernel PUBLIC EplNmtMnuCbStatusResponse(
1423                                   unsigned int        uiNodeId_p,
1424                                   tEplStatusResponse* pStatusResponse_p)
1425 {
1426 tEplKernel      Ret = kEplSuccessful;
1427
1428     if (pStatusResponse_p == NULL)
1429     {   // node did not answer
1430         Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1431                                             kEplNmtCsNotActive,
1432                                             EPL_E_NMT_NO_STATUS_RES, // was EPL_E_NO_ERROR
1433                                             kEplNmtMnuIntNodeEventNoStatusResponse);
1434     }
1435     else
1436     {   // node answered StatusRequest
1437         Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1438                                             (tEplNmtState) (AmiGetByteFromLe(&pStatusResponse_p->m_le_bNmtStatus) | EPL_NMT_TYPE_CS),
1439                                             EPL_E_NO_ERROR,
1440                                             kEplNmtMnuIntNodeEventStatusResponse);
1441     }
1442
1443     return Ret;
1444 }
1445
1446
1447 //---------------------------------------------------------------------------
1448 //
1449 // Function:    EplNmtMnuStartBootStep1
1450 //
1451 // Description: starts BootStep1
1452 //
1453 // Parameters:  (none)
1454 //
1455 // Returns:     tEplKernel              = error code
1456 //
1457 // State:
1458 //
1459 //---------------------------------------------------------------------------
1460
1461 static tEplKernel EplNmtMnuStartBootStep1(void)
1462 {
1463 tEplKernel      Ret = kEplSuccessful;
1464 unsigned int    uiSubIndex;
1465 unsigned int    uiLocalNodeId;
1466 DWORD           dwNodeCfg;
1467 tEplObdSize     ObdSize;
1468
1469     // $$$ d.k.: save current time for 0x1F89/2 MNTimeoutPreOp1_U32
1470
1471     // start network scan
1472     EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1473     EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1474     // check 0x1F81
1475     uiLocalNodeId = EplObduGetNodeId();
1476     for (uiSubIndex = 1; uiSubIndex <= 254; uiSubIndex++)
1477     {
1478         ObdSize = 4;
1479         Ret = EplObduReadEntry(0x1F81, uiSubIndex, &dwNodeCfg, &ObdSize);
1480         if (Ret != kEplSuccessful)
1481         {
1482             goto Exit;
1483         }
1484         if (uiSubIndex != uiLocalNodeId)
1485         {
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);
1488
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;
1494             }
1495
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;
1499
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)
1505                 {
1506                     goto Exit;
1507                 }
1508
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
1513
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
1518                 }
1519             }
1520         }
1521         else
1522         {   // subindex of MN
1523             if ((dwNodeCfg & (EPL_NODEASSIGN_MN_PRES | EPL_NODEASSIGN_NODE_EXISTS)) != 0)
1524             {   // MN shall send PRes
1525             tEplDllNodeInfo DllNodeInfo;
1526
1527                 EPL_MEMSET(&DllNodeInfo, 0, sizeof (DllNodeInfo));
1528                 DllNodeInfo.m_uiNodeId = uiLocalNodeId;
1529
1530                 Ret = EplDlluCalAddNode(&DllNodeInfo);
1531             }
1532         }
1533     }
1534
1535 Exit:
1536     return Ret;
1537 }
1538
1539
1540 //---------------------------------------------------------------------------
1541 //
1542 // Function:    EplNmtMnuStartBootStep2
1543 //
1544 // Description: starts BootStep2.
1545 //              That means add nodes to isochronous phase and send
1546 //              NMT EnableReadyToOp.
1547 //
1548 // Parameters:  (none)
1549 //
1550 // Returns:     tEplKernel              = error code
1551 //
1552 // State:
1553 //
1554 //---------------------------------------------------------------------------
1555
1556 static tEplKernel EplNmtMnuStartBootStep2(void)
1557 {
1558 tEplKernel      Ret = kEplSuccessful;
1559 unsigned int    uiIndex;
1560 tEplNmtMnuNodeInfo* pNodeInfo;
1561
1562
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;
1570
1571         pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1572         for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++)
1573         {
1574             if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateConfigured)
1575             {
1576                 Ret = EplNmtMnuNodeBootStep2(uiIndex, pNodeInfo);
1577                 if (Ret != kEplSuccessful)
1578                 {
1579                     goto Exit;
1580                 }
1581
1582                 // set flag "not scanned"
1583                 pNodeInfo->m_wFlags |= EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1584
1585                 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1586                 // signal slave counter shall be decremented if StatusRequest was sent once to a CN
1587
1588                 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
1589                 {   // node is a mandatory CN
1590                     EplNmtMnuInstance_g.m_uiMandatorySlaveCount++;
1591                 }
1592
1593                 // mandatory slave counter shall be decremented if mandatory CN is ReadyToOp
1594             }
1595         }
1596     }
1597
1598 Exit:
1599     return Ret;
1600 }
1601
1602
1603 //---------------------------------------------------------------------------
1604 //
1605 // Function:    EplNmtMnuNodeBootStep2
1606 //
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
1612 //              ReadyToOp.
1613 //              If TimeoutReadyToOp in object 0x1F89/5 is configured,
1614 //              TimerHdlLonger will be started with this timeout.
1615 //
1616 // Parameters:  uiNodeId_p              = node ID
1617 //              pNodeInfo_p             = pointer to internal node info structure
1618 //
1619 // Returns:     tEplKernel              = error code
1620 //
1621 // State:
1622 //
1623 //---------------------------------------------------------------------------
1624
1625 static tEplKernel EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p, tEplNmtMnuNodeInfo* pNodeInfo_p)
1626 {
1627 tEplKernel      Ret = kEplSuccessful;
1628 tEplDllNodeInfo DllNodeInfo;
1629 DWORD           dwNodeCfg;
1630 tEplObdSize     ObdSize;
1631 tEplTimerArg    TimerArg;
1632
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;
1637         ObdSize = 4;
1638         Ret = EplObduReadEntry(0x1F92, uiNodeId_p, &DllNodeInfo.m_dwPresTimeout, &ObdSize);
1639         if (Ret != kEplSuccessful)
1640         {
1641             goto Exit;
1642         }
1643
1644         ObdSize = 2;
1645         Ret = EplObduReadEntry(0x1F8B, uiNodeId_p, &DllNodeInfo.m_wPreqPayloadLimit, &ObdSize);
1646         if (Ret != kEplSuccessful)
1647         {
1648             goto Exit;
1649         }
1650
1651         ObdSize = 2;
1652         Ret = EplObduReadEntry(0x1F8D, uiNodeId_p, &DllNodeInfo.m_wPresPayloadLimit, &ObdSize);
1653         if (Ret != kEplSuccessful)
1654         {
1655             goto Exit;
1656         }
1657
1658         pNodeInfo_p->m_wFlags |= EPL_NMTMNU_NODE_FLAG_ISOCHRON;
1659
1660         Ret = EplDlluCalAddNode(&DllNodeInfo);
1661         if (Ret != kEplSuccessful)
1662         {
1663             goto Exit;
1664         }
1665
1666     }
1667
1668     EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
1669                                     uiNodeId_p,
1670                                     kEplNmtCmdEnableReadyToOperate);
1671
1672     Ret = EplNmtMnuSendNmtCommand(uiNodeId_p, kEplNmtCmdEnableReadyToOperate);
1673     if (Ret != kEplSuccessful)
1674     {
1675         goto Exit;
1676     }
1677
1678     if (EplNmtMnuInstance_g.m_ulTimeoutReadyToOp != 0L)
1679     {   // start timer
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);
1686     }
1687
1688 Exit:
1689     return Ret;
1690 }
1691
1692
1693 //---------------------------------------------------------------------------
1694 //
1695 // Function:    EplNmtMnuStartCheckCom
1696 //
1697 // Description: starts CheckCommunication
1698 //
1699 // Parameters:  (none)
1700 //
1701 // Returns:     tEplKernel              = error code
1702 //
1703 // State:
1704 //
1705 //---------------------------------------------------------------------------
1706
1707 static tEplKernel EplNmtMnuStartCheckCom(void)
1708 {
1709 tEplKernel      Ret = kEplSuccessful;
1710 unsigned int    uiIndex;
1711 tEplNmtMnuNodeInfo* pNodeInfo;
1712
1713
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;
1721
1722         pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1723         for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++)
1724         {
1725             if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateReadyToOp)
1726             {
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++;
1734                     }
1735                 }
1736                 else if (Ret != kEplSuccessful)
1737                 {
1738                     goto Exit;
1739                 }
1740
1741                 // set flag "not scanned"
1742                 pNodeInfo->m_wFlags |= EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1743
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
1747             }
1748         }
1749     }
1750
1751     Ret = kEplSuccessful;
1752
1753 Exit:
1754     return Ret;
1755 }
1756
1757
1758 //---------------------------------------------------------------------------
1759 //
1760 // Function:    EplNmtMnuNodeCheckCom
1761 //
1762 // Description: checks communication of the specified node.
1763 //              That means wait some time and if no error occured everything
1764 //              is OK.
1765 //
1766 // Parameters:  uiNodeId_p              = node ID
1767 //              pNodeInfo_p             = pointer to internal node info structure
1768 //
1769 // Returns:     tEplKernel              = error code
1770 //
1771 // State:
1772 //
1773 //---------------------------------------------------------------------------
1774
1775 static tEplKernel EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p, tEplNmtMnuNodeInfo* pNodeInfo_p)
1776 {
1777 tEplKernel      Ret = kEplSuccessful;
1778 DWORD           dwNodeCfg;
1779 tEplTimerArg    TimerArg;
1780
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
1785
1786         // check communication,
1787         // that means wait some time and if no error occured everything is OK;
1788
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);
1795
1796         // update mandatory slave counter, because timer was started
1797         if (Ret == kEplSuccessful)
1798         {
1799             Ret = kEplReject;
1800         }
1801     }
1802     else
1803     {   // timer was not started
1804         // assume everything is OK
1805         pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateComChecked;
1806     }
1807
1808 //Exit:
1809     return Ret;
1810 }
1811
1812
1813 //---------------------------------------------------------------------------
1814 //
1815 // Function:    EplNmtMnuStartNodes
1816 //
1817 // Description: really starts all nodes which are ReadyToOp and CheckCom did not fail
1818 //
1819 // Parameters:  (none)
1820 //
1821 // Returns:     tEplKernel              = error code
1822 //
1823 // State:
1824 //
1825 //---------------------------------------------------------------------------
1826
1827 static tEplKernel EplNmtMnuStartNodes(void)
1828 {
1829 tEplKernel      Ret = kEplSuccessful;
1830 unsigned int    uiIndex;
1831 tEplNmtMnuNodeInfo* pNodeInfo;
1832
1833
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;
1841
1842         pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1843         for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++)
1844         {
1845             if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateComChecked)
1846             {
1847                 if ((EplNmtMnuInstance_g.m_dwNmtStartup & EPL_NMTST_STARTALLNODES) == 0)
1848                 {
1849                     EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
1850                                                     uiIndex,
1851                                                     kEplNmtCmdStartNode);
1852
1853                     Ret = EplNmtMnuSendNmtCommand(uiIndex, kEplNmtCmdStartNode);
1854                     if (Ret != kEplSuccessful)
1855                     {
1856                         goto Exit;
1857                     }
1858                 }
1859
1860                 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
1861                 {   // node is a mandatory CN
1862                     EplNmtMnuInstance_g.m_uiMandatorySlaveCount++;
1863                 }
1864
1865                 // set flag "not scanned"
1866                 pNodeInfo->m_wFlags |= EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1867
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
1871             }
1872         }
1873
1874         // $$$ inform application if EPL_NMTST_NO_STARTNODE is set
1875
1876         if ((EplNmtMnuInstance_g.m_dwNmtStartup & EPL_NMTST_STARTALLNODES) != 0)
1877         {
1878             EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
1879                                             EPL_C_ADR_BROADCAST,
1880                                             kEplNmtCmdStartNode);
1881
1882             Ret = EplNmtMnuSendNmtCommand(EPL_C_ADR_BROADCAST, kEplNmtCmdStartNode);
1883             if (Ret != kEplSuccessful)
1884             {
1885                 goto Exit;
1886             }
1887         }
1888     }
1889
1890 Exit:
1891     return Ret;
1892 }
1893
1894
1895 //---------------------------------------------------------------------------
1896 //
1897 // Function:    EplNmtMnuProcessInternalEvent
1898 //
1899 // Description: processes internal node events
1900 //
1901 // Parameters:  uiNodeId_p              = node ID
1902 //              NodeNmtState_p          = NMT state of CN
1903 //              NodeEvent_p             = occured events
1904 //
1905 // Returns:     tEplKernel              = error code
1906 //
1907 //
1908 // State:
1909 //
1910 //---------------------------------------------------------------------------
1911
1912 static tEplKernel EplNmtMnuProcessInternalEvent(
1913                                     unsigned int        uiNodeId_p,
1914                                     tEplNmtState        NodeNmtState_p,
1915                                     WORD                wErrorCode_p,
1916                                     tEplNmtMnuIntNodeEvent NodeEvent_p)
1917 {
1918 tEplKernel          Ret = kEplSuccessful;
1919 tEplNmtState        NmtState;
1920 tEplNmtMnuNodeInfo* pNodeInfo;
1921 tEplTimerArg        TimerArg;
1922
1923     pNodeInfo = EPL_NMTMNU_GET_NODEINFO(uiNodeId_p);
1924     NmtState = EplNmtuGetNmtState();
1925     if (NmtState <= kEplNmtMsNotActive)
1926     {   // MN is not active
1927         goto Exit;
1928     }
1929
1930     switch (NodeEvent_p)
1931     {
1932         case kEplNmtMnuIntNodeEventIdentResponse:
1933         {
1934         BYTE    bNmtState;
1935
1936             EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
1937                                             uiNodeId_p,
1938                                             pNodeInfo->m_NodeState);
1939
1940             if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)
1941             {
1942                 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateIdentified;
1943             }
1944
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);
1948
1949             if ((NmtState == kEplNmtMsPreOperational1)
1950                 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
1951             {
1952                 // decrement only signal slave count
1953                 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
1954                 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1955             }
1956
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);
1960
1961             // check NMT state of CN
1962             Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, NodeNmtState_p, wErrorCode_p, NmtState);
1963             if (Ret != kEplSuccessful)
1964             {
1965                 if (Ret == kEplReject)
1966                 {
1967                     Ret = kEplSuccessful;
1968                 }
1969                 break;
1970             }
1971
1972             // request StatusResponse immediately,
1973             // because we want a fast boot-up of CNs
1974             Ret = EplStatusuRequestStatusResponse(uiNodeId_p, EplNmtMnuCbStatusResponse);
1975             if (Ret != kEplSuccessful)
1976             {
1977                 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
1978                                                 uiNodeId_p,
1979                                                 Ret);
1980
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;
1987                 }
1988                 else
1989                 {
1990                     break;
1991                 }
1992             }
1993
1994             if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)
1995             {
1996                 // inform application
1997                 Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
1998                                                            kEplNmtNodeEventFound,
1999                                                            NodeNmtState_p,
2000                                                            EPL_E_NO_ERROR,
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,
2005                                                     uiNodeId_p,
2006                                                     ((pNodeInfo->m_NodeState << 8)
2007                                                      | Ret));
2008
2009                     Ret = kEplSuccessful;
2010                     break;
2011                 }
2012                 else if (Ret != kEplSuccessful)
2013                 {
2014                     EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2015                                                     uiNodeId_p,
2016                                                     ((pNodeInfo->m_NodeState << 8)
2017                                                      | Ret));
2018
2019                     break;
2020                 }
2021             }
2022
2023             // continue BootStep1
2024         }
2025
2026         case kEplNmtMnuIntNodeEventBoot:
2027         {
2028
2029             // $$$ check identification (vendor ID, product code, revision no, serial no)
2030
2031             if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateIdentified)
2032             {
2033                 // $$$ check software
2034
2035                 // check/start configuration
2036                 // inform application
2037                 Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
2038                                                            kEplNmtNodeEventCheckConf,
2039                                                            NodeNmtState_p,
2040                                                            EPL_E_NO_ERROR,
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,
2045                                                     uiNodeId_p,
2046                                                     ((pNodeInfo->m_NodeState << 8)
2047                                                      | Ret));
2048
2049                     Ret = kEplSuccessful;
2050                     break;
2051                 }
2052                 else if (Ret != kEplSuccessful)
2053                 {
2054                     EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventBoot,
2055                                                     uiNodeId_p,
2056                                                     ((pNodeInfo->m_NodeState << 8)
2057                                                      | Ret));
2058
2059                     break;
2060                 }
2061             }
2062             else if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)
2063             {   // wrong CN state
2064                 // ignore event
2065                 break;
2066             }
2067
2068             // $$$ d.k.: currently we assume configuration is OK
2069
2070             // continue BootStep1
2071         }
2072
2073         case kEplNmtMnuIntNodeEventConfigured:
2074         {
2075             if ((pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified)
2076                 && (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf))
2077             {   // wrong CN state
2078                 // ignore event
2079                 break;
2080             }
2081
2082             pNodeInfo->m_NodeState = kEplNmtMnuNodeStateConfigured;
2083
2084             if (NmtState == kEplNmtMsPreOperational1)
2085             {
2086                 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
2087                 {   // decrement mandatory CN counter
2088                     EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2089                 }
2090             }
2091             else
2092             {
2093                 // put optional node to next step (BootStep2)
2094                 Ret = EplNmtMnuNodeBootStep2(uiNodeId_p, pNodeInfo);
2095             }
2096             break;
2097         }
2098
2099         case kEplNmtMnuIntNodeEventNoIdentResponse:
2100         {
2101             if ((NmtState == kEplNmtMsPreOperational1)
2102                 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2103             {
2104                 // decrement only signal slave count
2105                 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2106                 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2107             }
2108
2109             if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)
2110             {
2111                 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateUnknown;
2112             }
2113
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)
2119             {   // start timer
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;
2124 /*
2125                 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventNoIdentResponse,
2126                                                 uiNodeId_p,
2127                                                 ((pNodeInfo->m_NodeState << 8)
2128                                                  | 0x80
2129                                                  | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
2130                                                  | ((TimerArg.m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
2131 */
2132                 Ret = EplTimeruModifyTimerMs(&pNodeInfo->m_TimerHdlStatReq, EplNmtMnuInstance_g.m_ulStatusRequestDelay, TimerArg);
2133             }
2134             else
2135             {   // trigger IdentRequest immediately
2136                 Ret = EplIdentuRequestIdentResponse(uiNodeId_p, EplNmtMnuCbIdentResponse);
2137             }
2138             break;
2139         }
2140
2141         case kEplNmtMnuIntNodeEventStatusResponse:
2142         {
2143             if ((NmtState >= kEplNmtMsPreOperational2)
2144                 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2145             {
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;
2149             }
2150
2151             // check NMT state of CN
2152             Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, NodeNmtState_p, wErrorCode_p, NmtState);
2153             if (Ret != kEplSuccessful)
2154             {
2155                 if (Ret == kEplReject)
2156                 {
2157                     Ret = kEplSuccessful;
2158                 }
2159                 break;
2160             }
2161
2162             if (NmtState == kEplNmtMsPreOperational1)
2163             {
2164                 // request next StatusResponse immediately
2165                 Ret = EplStatusuRequestStatusResponse(uiNodeId_p, EplNmtMnuCbStatusResponse);
2166                 if (Ret != kEplSuccessful)
2167                 {
2168                     EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2169                                                     uiNodeId_p,
2170                                                     Ret);
2171                 }
2172
2173             }
2174             else if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_ISOCHRON) == 0)
2175             {   // start timer
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;
2181 /*
2182                 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventStatusResponse,
2183                                                 uiNodeId_p,
2184                                                 ((pNodeInfo->m_NodeState << 8)
2185                                                  | 0x80
2186                                                  | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
2187                                                  | ((TimerArg.m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
2188 */
2189                 Ret = EplTimeruModifyTimerMs(&pNodeInfo->m_TimerHdlStatReq, EplNmtMnuInstance_g.m_ulStatusRequestDelay, TimerArg);
2190             }
2191
2192             break;
2193         }
2194
2195         case kEplNmtMnuIntNodeEventNoStatusResponse:
2196         {
2197             // function CheckNmtState sets node state to unknown if necessary
2198 /*
2199             if ((NmtState >= kEplNmtMsPreOperational2)
2200                 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2201             {
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;
2205             }
2206 */
2207             // check NMT state of CN
2208             Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, NodeNmtState_p, wErrorCode_p, NmtState);
2209             if (Ret != kEplSuccessful)
2210             {
2211                 if (Ret == kEplReject)
2212                 {
2213                     Ret = kEplSuccessful;
2214                 }
2215                 break;
2216             }
2217
2218             break;
2219         }
2220
2221         case kEplNmtMnuIntNodeEventError:
2222         {   // currently only issued on kEplNmtNodeCommandConfErr
2223
2224             if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified)
2225             {   // wrong CN state
2226                 // ignore event
2227                 break;
2228             }
2229
2230             // check NMT state of CN
2231             Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, kEplNmtCsNotActive, wErrorCode_p, NmtState);
2232             if (Ret != kEplSuccessful)
2233             {
2234                 if (Ret == kEplReject)
2235                 {
2236                     Ret = kEplSuccessful;
2237                 }
2238                 break;
2239             }
2240
2241             break;
2242         }
2243
2244         case kEplNmtMnuIntNodeEventExecReset:
2245         {
2246             if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified)
2247             {   // wrong CN state
2248                 // ignore event
2249                 break;
2250             }
2251
2252             pNodeInfo->m_NodeState = kEplNmtMnuNodeStateResetConf;
2253
2254             EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2255                                             uiNodeId_p,
2256                                             (((NodeNmtState_p & 0xFF) << 8)
2257                                             | kEplNmtCmdResetConfiguration));
2258
2259             // send NMT reset configuration to CN for activation of configuration
2260             Ret = EplNmtMnuSendNmtCommand(uiNodeId_p, kEplNmtCmdResetConfiguration);
2261
2262             break;
2263         }
2264
2265         case kEplNmtMnuIntNodeEventHeartbeat:
2266         {
2267 /*
2268             if ((NmtState >= kEplNmtMsPreOperational2)
2269                 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2270             {
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;
2274             }
2275 */
2276             // check NMT state of CN
2277             Ret = EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo, NodeNmtState_p, wErrorCode_p, NmtState);
2278             if (Ret != kEplSuccessful)
2279             {
2280                 if (Ret == kEplReject)
2281                 {
2282                     Ret = kEplSuccessful;
2283                 }
2284                 break;
2285             }
2286
2287             break;
2288         }
2289
2290         case kEplNmtMnuIntNodeEventTimerIdentReq:
2291         {
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)
2296             {
2297                 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2298                                                 uiNodeId_p,
2299                                                 (((NodeNmtState_p & 0xFF) << 8)
2300                                                  | Ret));
2301                 if (Ret == kEplInvalidOperation)
2302                 {   // this can happen because of a bug in EplTimeruLinuxKernel.c
2303                     // so ignore this error.
2304                     Ret = kEplSuccessful;
2305                 }
2306             }
2307
2308             break;
2309         }
2310
2311         case kEplNmtMnuIntNodeEventTimerStateMon:
2312         {
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;
2316
2317             // continue with normal StatReq processing
2318         }
2319
2320         case kEplNmtMnuIntNodeEventTimerStatReq:
2321         {
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)
2326             {
2327                 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2328                                                 uiNodeId_p,
2329                                                 (((NodeNmtState_p & 0xFF) << 8)
2330                                                  | Ret));
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;
2337                 }
2338             }
2339
2340             break;
2341         }
2342
2343         case kEplNmtMnuIntNodeEventTimerLonger:
2344         {
2345             switch (pNodeInfo->m_NodeState)
2346             {
2347                 case kEplNmtMnuNodeStateConfigured:
2348                 {   // node should be ReadyToOp but it is not
2349
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)
2353                     {
2354                         if (Ret == kEplReject)
2355                         {
2356                             Ret = kEplSuccessful;
2357                         }
2358                         break;
2359                     }
2360
2361                     break;
2362                 }
2363
2364                 case kEplNmtMnuNodeStateReadyToOp:
2365                 {   // CheckCom finished successfully
2366
2367                     pNodeInfo->m_NodeState = kEplNmtMnuNodeStateComChecked;
2368
2369                     if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0)
2370                     {
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;
2374                     }
2375
2376                     if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
2377                     {
2378                         // decrement mandatory slave counter
2379                         EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2380                     }
2381                     if (NmtState != kEplNmtMsReadyToOperate)
2382                     {
2383                         EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2384                                                         uiNodeId_p,
2385                                                         (((NodeNmtState_p & 0xFF) << 8)
2386                                                         | kEplNmtCmdStartNode));
2387
2388                         // start optional CN
2389                         Ret = EplNmtMnuSendNmtCommand(uiNodeId_p, kEplNmtCmdStartNode);
2390                     }
2391                     break;
2392                 }
2393
2394                 default:
2395                 {
2396                     break;
2397                 }
2398             }
2399             break;
2400         }
2401
2402         case kEplNmtMnuIntNodeEventNmtCmdSent:
2403         {
2404         BYTE    bNmtState;
2405
2406             // update expected NMT state with the one that results
2407             // from the sent NMT command
2408             bNmtState = (BYTE) (NodeNmtState_p & 0xFF);
2409
2410             // write object 0x1F8F NMT_MNNodeExpState_AU8
2411             Ret = EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState, 1);
2412             if (Ret != kEplSuccessful)
2413             {
2414                 goto Exit;
2415             }
2416
2417             if (NodeNmtState_p == kEplNmtCsNotActive)
2418             {   // restart processing with IdentRequest
2419                 EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ(
2420                         pNodeInfo, uiNodeId_p, TimerArg);
2421             }
2422             else
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);
2428
2429                 // set NMT state change flag
2430                 pNodeInfo->m_wFlags |= EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED;
2431             }
2432
2433             Ret = EplTimeruModifyTimerMs(&pNodeInfo->m_TimerHdlStatReq, EplNmtMnuInstance_g.m_ulStatusRequestDelay, TimerArg);
2434
2435             // finish processing, because NmtState_p is the expected and not the current state
2436             goto Exit;
2437         }
2438
2439         default:
2440         {
2441             break;
2442         }
2443     }
2444
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
2448         switch (NmtState)
2449         {
2450             case kEplNmtMsPreOperational1:
2451             {
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,
2458                                                                NmtState,
2459                                                                EPL_E_NO_ERROR);
2460                     if (Ret != kEplSuccessful)
2461                     {
2462                         if (Ret == kEplReject)
2463                         {
2464                             // wait for application
2465                             Ret = kEplSuccessful;
2466                         }
2467                         break;
2468                     }
2469                     // enter PreOp2
2470                     Ret = EplNmtuNmtEvent(kEplNmtEventAllMandatoryCNIdent);
2471                 }
2472                 break;
2473             }
2474
2475             case kEplNmtMsPreOperational2:
2476             {
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,
2483                                                                NmtState,
2484                                                                EPL_E_NO_ERROR);
2485                     if (Ret != kEplSuccessful)
2486                     {
2487                         if (Ret == kEplReject)
2488                         {
2489                             // wait for application
2490                             Ret = kEplSuccessful;
2491                         }
2492                         break;
2493                     }
2494                     // enter ReadyToOp
2495                     Ret = EplNmtuNmtEvent(kEplNmtEventEnterReadyToOperate);
2496                 }
2497                 break;
2498             }
2499
2500             case kEplNmtMsReadyToOperate:
2501             {
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,
2508                                                                NmtState,
2509                                                                EPL_E_NO_ERROR);
2510                     if (Ret != kEplSuccessful)
2511                     {
2512                         if (Ret == kEplReject)
2513                         {
2514                             // wait for application
2515                             Ret = kEplSuccessful;
2516                         }
2517                         break;
2518                     }
2519                     // enter Operational
2520                     Ret = EplNmtuNmtEvent(kEplNmtEventEnterMsOperational);
2521                 }
2522                 break;
2523             }
2524
2525             case kEplNmtMsOperational:
2526             {
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,
2533                                                                NmtState,
2534                                                                EPL_E_NO_ERROR);
2535                     if (Ret != kEplSuccessful)
2536                     {
2537                         if (Ret == kEplReject)
2538                         {
2539                             // ignore error code
2540                             Ret = kEplSuccessful;
2541                         }
2542                         break;
2543                     }
2544                 }
2545                 break;
2546             }
2547
2548             default:
2549             {
2550                 break;
2551             }
2552         }
2553     }
2554
2555 Exit:
2556     return Ret;
2557 }
2558
2559
2560 //---------------------------------------------------------------------------
2561 //
2562 // Function:    EplNmtMnuCheckNmtState
2563 //
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.
2568 //
2569 // Parameters:  uiNodeId_p              = node ID
2570 //              NodeNmtState_p          = NMT state of CN
2571 //
2572 // Returns:     tEplKernel              = error code
2573 //                  kEplReject          = CN was in wrong state and has been reset
2574 //
2575 // State:
2576 //
2577 //---------------------------------------------------------------------------
2578
2579 static tEplKernel EplNmtMnuCheckNmtState(
2580                                     unsigned int        uiNodeId_p,
2581                                     tEplNmtMnuNodeInfo* pNodeInfo_p,
2582                                     tEplNmtState        NodeNmtState_p,
2583                                     WORD                wErrorCode_p,
2584                                     tEplNmtState        LocalNmtState_p)
2585 {
2586 tEplKernel      Ret = kEplSuccessful;
2587 tEplObdSize     ObdSize;
2588 BYTE            bNmtState;
2589 BYTE            bNmtStatePrev;
2590 tEplNmtState    ExpNmtState;
2591
2592     ObdSize = 1;
2593     // read object 0x1F8F NMT_MNNodeExpState_AU8
2594     Ret = EplObduReadEntry(0x1F8F, uiNodeId_p, &bNmtState, &ObdSize);
2595     if (Ret != kEplSuccessful)
2596     {
2597         goto Exit;
2598     }
2599
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);
2604
2605     if (ExpNmtState == kEplNmtCsNotActive)
2606     {   // ignore the current state, because the CN shall be not active
2607         Ret = kEplReject;
2608         goto Exit;
2609     }
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)
2616         {
2617             goto Exit;
2618         }
2619         pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateReadyToOp;
2620
2621         // update object 0x1F8F NMT_MNNodeExpState_AU8 to ReadyToOp
2622         Ret = EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState, 1);
2623         if (Ret != kEplSuccessful)
2624         {
2625             goto Exit;
2626         }
2627
2628         if ((pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
2629         {   // node is a mandatory CN -> decrement counter
2630             EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2631         }
2632         if (LocalNmtState_p >= kEplNmtMsReadyToOperate)
2633         {   // start procedure CheckCommunication for this node
2634             Ret = EplNmtMnuNodeCheckCom(uiNodeId_p, pNodeInfo_p);
2635             if (Ret != kEplSuccessful)
2636             {
2637                 goto Exit;
2638             }
2639
2640             if ((LocalNmtState_p == kEplNmtMsOperational)
2641                 && (pNodeInfo_p->m_NodeState == kEplNmtMnuNodeStateComChecked))
2642             {
2643                 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
2644                                                 uiNodeId_p,
2645                                                 (((NodeNmtState_p & 0xFF) << 8)
2646                                                 | kEplNmtCmdStartNode));
2647
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)
2651                 {
2652                     goto Exit;
2653                 }
2654             }
2655         }
2656
2657     }
2658     else if ((ExpNmtState == kEplNmtCsReadyToOperate)
2659              && (NodeNmtState_p == kEplNmtCsOperational))
2660     {   // CN switched to OPERATIONAL
2661         pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateOperational;
2662
2663         if ((pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0)
2664         {   // node is a mandatory CN -> decrement counter
2665             EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2666         }
2667
2668     }
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)
2673     WORD wbeErrorCode;
2674
2675         if ((pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0)
2676         {
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;
2680         }
2681
2682         if (pNodeInfo_p->m_NodeState == kEplNmtMnuNodeStateUnknown)
2683         {   // CN is already in state unknown, which means that it got
2684             // NMT reset command earlier
2685             goto Exit;
2686         }
2687
2688         // -> CN is in wrong NMT state
2689         pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateUnknown;
2690
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
2697                 goto Exit;
2698             }
2699
2700             wErrorCode_p = EPL_E_NMT_WRONG_STATE;
2701         }
2702
2703         BENCHMARK_MOD_07_TOGGLE(9);
2704
2705         // $$$ start ERROR_TREATMENT and inform application
2706         Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
2707                                                    kEplNmtNodeEventError,
2708                                                    NodeNmtState_p,
2709                                                    wErrorCode_p,
2710                                                    (pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0);
2711         if (Ret != kEplSuccessful)
2712         {
2713             goto Exit;
2714         }
2715
2716         EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
2717                                         uiNodeId_p,
2718                                         (((NodeNmtState_p & 0xFF) << 8)
2719                                         | kEplNmtCmdResetNode));
2720
2721         // reset CN
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)
2726         {
2727             Ret = kEplReject;
2728         }
2729
2730         goto Exit;
2731     }
2732
2733     // check if NMT_MNNodeCurrState_AU8 has to be changed
2734     ObdSize = 1;
2735     Ret = EplObduReadEntry(0x1F8E, uiNodeId_p, &bNmtStatePrev, &ObdSize);
2736     if (Ret != kEplSuccessful)
2737     {
2738         goto Exit;
2739     }
2740     if (bNmtState != bNmtStatePrev)
2741     {
2742         // update object 0x1F8E NMT_MNNodeCurrState_AU8
2743         Ret = EplObduWriteEntry(0x1F8E, uiNodeId_p, &bNmtState, 1);
2744         if (Ret != kEplSuccessful)
2745         {
2746             goto Exit;
2747         }
2748         Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
2749                                                kEplNmtNodeEventNmtState,
2750                                                NodeNmtState_p,
2751                                                wErrorCode_p,
2752                                                (pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0);
2753         if (Ret != kEplSuccessful)
2754         {
2755             goto Exit;
2756         }
2757     }
2758
2759 Exit:
2760     return Ret;
2761 }
2762
2763 //---------------------------------------------------------------------------
2764 //
2765 // Function:    EplNmtMnuReset
2766 //
2767 // Description: reset internal structures, e.g. timers
2768 //
2769 // Parameters:  void
2770 //
2771 // Returns:     tEplKernel              = error code
2772 //
2773 // State:
2774 //
2775 //---------------------------------------------------------------------------
2776
2777 static tEplKernel EplNmtMnuReset(void)
2778 {
2779 tEplKernel  Ret;
2780 int         iIndex;
2781
2782     Ret = EplTimeruDeleteTimer(&EplNmtMnuInstance_g.m_TimerHdlNmtState);
2783
2784     for (iIndex = 1; iIndex <= tabentries (EplNmtMnuInstance_g.m_aNodeInfo); iIndex++)
2785     {
2786         // delete timer handles
2787         Ret = EplTimeruDeleteTimer(&EPL_NMTMNU_GET_NODEINFO(iIndex)->m_TimerHdlStatReq);
2788         Ret = EplTimeruDeleteTimer(&EPL_NMTMNU_GET_NODEINFO(iIndex)->m_TimerHdlLonger);
2789     }
2790
2791     return Ret;
2792 }
2793
2794
2795 #endif // #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
2796
2797 // EOF
2798