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 // defines for flags in node info structure
110 #define EPL_NMTMNU_NODE_FLAG_ISOCHRON 0x0001 // CN is being accessed isochronously
111 #define EPL_NMTMNU_NODE_FLAG_NOT_SCANNED 0x0002 // CN was not scanned once -> decrement SignalCounter and reset flag
112 #define EPL_NMTMNU_NODE_FLAG_HALTED 0x0004 // boot process for this CN is halted
113 #define EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED 0x0008 // NMT command was just issued, wrong NMT states will be tolerated
114 #define EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ 0x0300 // counter for StatusRequest timer handle
115 #define EPL_NMTMNU_NODE_FLAG_COUNT_LONGER 0x0C00 // counter for longer timeouts timer handle
116 #define EPL_NMTMNU_NODE_FLAG_INC_STATREQ 0x0100 // increment for StatusRequest timer handle
117 #define EPL_NMTMNU_NODE_FLAG_INC_LONGER 0x0400 // increment for longer timeouts timer handle
118 // These counters will be incremented at every timer start
119 // and copied to timerarg. When the timer event occures
120 // both will be compared and if unequal the timer event
121 // will be discarded, because it is an old one.
122
123 // defines for timer arguments to draw a distinction between serveral events
124 #define EPL_NMTMNU_TIMERARG_NODE_MASK 0x000000FFL // mask that contains the node-ID
125 #define EPL_NMTMNU_TIMERARG_IDENTREQ 0x00010000L // timer event is for IdentRequest
126 #define EPL_NMTMNU_TIMERARG_STATREQ 0x00020000L // timer event is for StatusRequest
127 #define EPL_NMTMNU_TIMERARG_LONGER 0x00040000L // timer event is for longer timeouts
128 #define EPL_NMTMNU_TIMERARG_STATE_MON 0x00080000L // timer event for StatusRequest to monitor execution of NMT state changes
129 #define EPL_NMTMNU_TIMERARG_COUNT_SR 0x00000300L // counter for StatusRequest
130 #define EPL_NMTMNU_TIMERARG_COUNT_LO 0x00000C00L // counter for longer timeouts
131 // The counters must have the same position as in the node flags above.
132
133 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_STATREQ(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
134 pNodeInfo_p->m_wFlags = \
135 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \
136 & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \
137 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
138 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_STATREQ | uiNodeId_p | \
139 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
140 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
141
142 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
143 pNodeInfo_p->m_wFlags = \
144 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \
145 & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \
146 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
147 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_IDENTREQ | uiNodeId_p | \
148 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
149 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
150
151 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
152 pNodeInfo_p->m_wFlags = \
153 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_LONGER) \
154 & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER) \
155 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_LONGER); \
156 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p | \
157 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER); \
158 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
159
160 #define EPL_NMTMNU_SET_FLAGS_TIMERARG_STATE_MON(pNodeInfo_p, uiNodeId_p, TimerArg_p) \
161 pNodeInfo_p->m_wFlags = \
162 ((pNodeInfo_p->m_wFlags + EPL_NMTMNU_NODE_FLAG_INC_STATREQ) \
163 & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) \
164 | (pNodeInfo_p->m_wFlags & ~EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
165 TimerArg_p.m_ulArg = EPL_NMTMNU_TIMERARG_STATE_MON | uiNodeId_p | \
166 (pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ); \
167 TimerArg_p.m_EventSink = kEplEventSinkNmtMnu;
168
169 // defines for global flags
170 #define EPL_NMTMNU_FLAG_HALTED 0x0001 // boot process is halted
171 #define EPL_NMTMNU_FLAG_APP_INFORMED 0x0002 // application was informed about possible NMT state change
172
173 // return pointer to node info structure for specified node ID
174 // d.k. may be replaced by special (hash) function if node ID array is smaller than 254
175 #define EPL_NMTMNU_GET_NODEINFO(uiNodeId_p) (&EplNmtMnuInstance_g.m_aNodeInfo[uiNodeId_p - 1])
176
177 //---------------------------------------------------------------------------
178 // local types
179 //---------------------------------------------------------------------------
180
181 typedef enum {
182 kEplNmtMnuIntNodeEventNoIdentResponse = 0x00,
183 kEplNmtMnuIntNodeEventIdentResponse = 0x01,
184 kEplNmtMnuIntNodeEventBoot = 0x02,
185 kEplNmtMnuIntNodeEventExecReset = 0x03,
186 kEplNmtMnuIntNodeEventConfigured = 0x04,
187 kEplNmtMnuIntNodeEventNoStatusResponse = 0x05,
188 kEplNmtMnuIntNodeEventStatusResponse = 0x06,
189 kEplNmtMnuIntNodeEventHeartbeat = 0x07,
190 kEplNmtMnuIntNodeEventNmtCmdSent = 0x08,
191 kEplNmtMnuIntNodeEventTimerIdentReq = 0x09,
192 kEplNmtMnuIntNodeEventTimerStatReq = 0x0A,
193 kEplNmtMnuIntNodeEventTimerStateMon = 0x0B,
194 kEplNmtMnuIntNodeEventTimerLonger = 0x0C,
195 kEplNmtMnuIntNodeEventError = 0x0D,
196
197 } tEplNmtMnuIntNodeEvent;
198
199 typedef enum {
200 kEplNmtMnuNodeStateUnknown = 0x00,
201 kEplNmtMnuNodeStateIdentified = 0x01,
202 kEplNmtMnuNodeStateResetConf = 0x02, // CN reset after configuration update
203 kEplNmtMnuNodeStateConfigured = 0x03, // BootStep1 completed
204 kEplNmtMnuNodeStateReadyToOp = 0x04, // BootStep2 completed
205 kEplNmtMnuNodeStateComChecked = 0x05, // Communication checked successfully
206 kEplNmtMnuNodeStateOperational = 0x06, // CN is in NMT state OPERATIONAL
207
208 } tEplNmtMnuNodeState;
209
210 typedef struct {
211 tEplTimerHdl m_TimerHdlStatReq; // timer to delay StatusRequests and IdentRequests
212 tEplTimerHdl m_TimerHdlLonger; // 2nd timer for NMT command EnableReadyToOp and CheckCommunication
213 tEplNmtMnuNodeState m_NodeState; // internal node state (kind of sub state of NMT state)
214 DWORD m_dwNodeCfg; // subindex from 0x1F81
215 WORD m_wFlags; // flags: CN is being accessed isochronously
216
217 } tEplNmtMnuNodeInfo;
218
219 typedef struct {
220 tEplNmtMnuNodeInfo m_aNodeInfo[EPL_NMT_MAX_NODE_ID];
221 tEplTimerHdl m_TimerHdlNmtState; // timeout for stay in NMT state
222 unsigned int m_uiMandatorySlaveCount;
223 unsigned int m_uiSignalSlaveCount;
224 unsigned long m_ulStatusRequestDelay; // in [ms] (object 0x1006 * EPL_C_NMT_STATREQ_CYCLE)
225 unsigned long m_ulTimeoutReadyToOp; // in [ms] (object 0x1F89/5)
226 unsigned long m_ulTimeoutCheckCom; // in [ms] (object 0x1006 * MultiplexedCycleCount)
227 WORD m_wFlags; // global flags
228 DWORD m_dwNmtStartup; // object 0x1F80 NMT_StartUp_U32
229 tEplNmtMnuCbNodeEvent m_pfnCbNodeEvent;
230 tEplNmtMnuCbBootEvent m_pfnCbBootEvent;
231
232 } tEplNmtMnuInstance;
233
234 //---------------------------------------------------------------------------
235 // local vars
236 //---------------------------------------------------------------------------
237
238 static tEplNmtMnuInstance EplNmtMnuInstance_g;
239
240 //---------------------------------------------------------------------------
241 // local function prototypes
242 //---------------------------------------------------------------------------
243
244 static tEplKernel PUBLIC EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p);
245
246 static tEplKernel PUBLIC EplNmtMnuCbIdentResponse(unsigned int uiNodeId_p,
247 tEplIdentResponse *
248 pIdentResponse_p);
249
250 static tEplKernel PUBLIC EplNmtMnuCbStatusResponse(unsigned int uiNodeId_p,
251 tEplStatusResponse *
252 pStatusResponse_p);
253
254 static tEplKernel EplNmtMnuCheckNmtState(unsigned int uiNodeId_p,
255 tEplNmtMnuNodeInfo * pNodeInfo_p,
256 tEplNmtState NodeNmtState_p,
257 WORD wErrorCode_p,
258 tEplNmtState LocalNmtState_p);
259
260 static tEplKernel EplNmtMnuStartBootStep1(void);
261
262 static tEplKernel EplNmtMnuStartBootStep2(void);
263
264 static tEplKernel EplNmtMnuStartCheckCom(void);
265
266 static tEplKernel EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p,
267 tEplNmtMnuNodeInfo * pNodeInfo_p);
268
269 static tEplKernel EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p,
270 tEplNmtMnuNodeInfo * pNodeInfo_p);
271
272 static tEplKernel EplNmtMnuStartNodes(void);
273
274 static tEplKernel EplNmtMnuProcessInternalEvent(unsigned int uiNodeId_p,
275 tEplNmtState NodeNmtState_p,
276 WORD wErrorCode_p,
277 tEplNmtMnuIntNodeEvent
278 NodeEvent_p);
279
280 static tEplKernel EplNmtMnuReset(void);
281
282 //=========================================================================//
283 // //
284 // P U B L I C F U N C T I O N S //
285 // //
286 //=========================================================================//
287
288 //---------------------------------------------------------------------------
289 //
290 // Function: EplNmtMnuInit
291 //
292 // Description: init first instance of the module
293 //
294 //
295 //
296 // Parameters:
297 //
298 //
299 // Returns: tEplKernel = errorcode
300 //
301 //
302 // State:
303 //
304 //---------------------------------------------------------------------------
305
EplNmtMnuInit(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p,tEplNmtMnuCbBootEvent pfnCbBootEvent_p)306 tEplKernel EplNmtMnuInit(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p,
307 tEplNmtMnuCbBootEvent pfnCbBootEvent_p)
308 {
309 tEplKernel Ret;
310
311 Ret = EplNmtMnuAddInstance(pfnCbNodeEvent_p, pfnCbBootEvent_p);
312
313 return Ret;
314 }
315
316 //---------------------------------------------------------------------------
317 //
318 // Function: EplNmtMnuAddInstance
319 //
320 // Description: init other instances of the module
321 //
322 //
323 //
324 // Parameters:
325 //
326 //
327 // Returns: tEplKernel = errorcode
328 //
329 //
330 // State:
331 //
332 //---------------------------------------------------------------------------
333
EplNmtMnuAddInstance(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p,tEplNmtMnuCbBootEvent pfnCbBootEvent_p)334 tEplKernel EplNmtMnuAddInstance(tEplNmtMnuCbNodeEvent pfnCbNodeEvent_p,
335 tEplNmtMnuCbBootEvent pfnCbBootEvent_p)
336 {
337 tEplKernel Ret;
338
339 Ret = kEplSuccessful;
340
341 // reset instance structure
342 EPL_MEMSET(&EplNmtMnuInstance_g, 0, sizeof(EplNmtMnuInstance_g));
343
344 if ((pfnCbNodeEvent_p == NULL) || (pfnCbBootEvent_p == NULL)) {
345 Ret = kEplNmtInvalidParam;
346 goto Exit;
347 }
348 EplNmtMnuInstance_g.m_pfnCbNodeEvent = pfnCbNodeEvent_p;
349 EplNmtMnuInstance_g.m_pfnCbBootEvent = pfnCbBootEvent_p;
350
351 // initialize StatusRequest delay
352 EplNmtMnuInstance_g.m_ulStatusRequestDelay = 5000L;
353
354 // register NmtMnResponse callback function
355 Ret =
356 EplDlluCalRegAsndService(kEplDllAsndNmtRequest,
357 EplNmtMnuCbNmtRequest,
358 kEplDllAsndFilterLocal);
359
360 Exit:
361 return Ret;
362
363 }
364
365 //---------------------------------------------------------------------------
366 //
367 // Function: EplNmtMnuDelInstance
368 //
369 // Description: delete instance
370 //
371 //
372 //
373 // Parameters:
374 //
375 //
376 // Returns: tEplKernel = errorcode
377 //
378 //
379 // State:
380 //
381 //---------------------------------------------------------------------------
382
EplNmtMnuDelInstance()383 tEplKernel EplNmtMnuDelInstance()
384 {
385 tEplKernel Ret;
386
387 Ret = kEplSuccessful;
388
389 // deregister NmtMnResponse callback function
390 Ret =
391 EplDlluCalRegAsndService(kEplDllAsndNmtRequest, NULL,
392 kEplDllAsndFilterNone);
393
394 Ret = EplNmtMnuReset();
395
396 return Ret;
397
398 }
399
400 //---------------------------------------------------------------------------
401 //
402 // Function: EplNmtMnuSendNmtCommandEx
403 //
404 // Description: sends the specified NMT command to the specified node.
405 //
406 // Parameters: uiNodeId_p = node ID to which the NMT command will be sent
407 // NmtCommand_p = NMT command
408 //
409 // Returns: tEplKernel = error code
410 //
411 // State:
412 //
413 //---------------------------------------------------------------------------
414
EplNmtMnuSendNmtCommandEx(unsigned int uiNodeId_p,tEplNmtCommand NmtCommand_p,void * pNmtCommandData_p,unsigned int uiDataSize_p)415 tEplKernel EplNmtMnuSendNmtCommandEx(unsigned int uiNodeId_p,
416 tEplNmtCommand NmtCommand_p,
417 void *pNmtCommandData_p,
418 unsigned int uiDataSize_p)
419 {
420 tEplKernel Ret = kEplSuccessful;
421 tEplFrameInfo FrameInfo;
422 BYTE abBuffer[EPL_C_DLL_MINSIZE_NMTCMDEXT];
423 tEplFrame *pFrame = (tEplFrame *) abBuffer;
424 BOOL fSoftDeleteNode = FALSE;
425
426 if ((uiNodeId_p == 0) || (uiNodeId_p > EPL_C_ADR_BROADCAST)) { // invalid node ID specified
427 Ret = kEplInvalidNodeId;
428 goto Exit;
429 }
430
431 if ((pNmtCommandData_p != NULL)
432 && (uiDataSize_p >
433 (EPL_C_DLL_MINSIZE_NMTCMDEXT - EPL_C_DLL_MINSIZE_NMTCMD))) {
434 Ret = kEplNmtInvalidParam;
435 goto Exit;
436 }
437 // $$$ d.k. may be check in future versions if the caller wants to perform prohibited state transitions
438 // the CN should not perform these transitions, but the expected NMT state will be changed and never fullfilled.
439
440 // build frame
441 EPL_MEMSET(pFrame, 0x00, sizeof(abBuffer));
442 AmiSetByteToLe(&pFrame->m_le_bDstNodeId, (BYTE) uiNodeId_p);
443 AmiSetByteToLe(&pFrame->m_Data.m_Asnd.m_le_bServiceId,
444 (BYTE) kEplDllAsndNmtCommand);
445 AmiSetByteToLe(&pFrame->m_Data.m_Asnd.m_Payload.m_NmtCommandService.
446 m_le_bNmtCommandId, (BYTE) NmtCommand_p);
447 if ((pNmtCommandData_p != NULL) && (uiDataSize_p > 0)) { // copy command data to frame
448 EPL_MEMCPY(&pFrame->m_Data.m_Asnd.m_Payload.m_NmtCommandService.
449 m_le_abNmtCommandData[0], pNmtCommandData_p,
450 uiDataSize_p);
451 }
452 // build info structure
453 FrameInfo.m_NetTime.m_dwNanoSec = 0;
454 FrameInfo.m_NetTime.m_dwSec = 0;
455 FrameInfo.m_pFrame = pFrame;
456 FrameInfo.m_uiFrameSize = sizeof(abBuffer);
457
458 // send NMT-Request
459 #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_DLLU)) != 0)
460 Ret = EplDlluCalAsyncSend(&FrameInfo, // pointer to frameinfo
461 kEplDllAsyncReqPrioNmt); // priority
462 #endif
463 if (Ret != kEplSuccessful) {
464 goto Exit;
465 }
466
467 EPL_DBGLVL_NMTMN_TRACE2("NMTCmd(%02X->%02X)\n", NmtCommand_p,
468 uiNodeId_p);
469
470 switch (NmtCommand_p) {
471 case kEplNmtCmdStartNode:
472 case kEplNmtCmdEnterPreOperational2:
473 case kEplNmtCmdEnableReadyToOperate:
474 {
475 // nothing left to do,
476 // because any further processing is done
477 // when the NMT command is actually sent
478 goto Exit;
479 }
480
481 case kEplNmtCmdStopNode:
482 {
483 fSoftDeleteNode = TRUE;
484 break;
485 }
486
487 case kEplNmtCmdResetNode:
488 case kEplNmtCmdResetCommunication:
489 case kEplNmtCmdResetConfiguration:
490 case kEplNmtCmdSwReset:
491 {
492 break;
493 }
494
495 default:
496 goto Exit;
497 }
498
499 // remove CN from isochronous phase;
500 // This must be done here and not when NMT command is actually sent
501 // because it will be too late and may cause unwanted errors
502 if (uiNodeId_p != EPL_C_ADR_BROADCAST) {
503 if (fSoftDeleteNode == FALSE) { // remove CN immediately from isochronous phase
504 Ret = EplDlluCalDeleteNode(uiNodeId_p);
505 } else { // remove CN from isochronous phase softly
506 Ret = EplDlluCalSoftDeleteNode(uiNodeId_p);
507 }
508 } else { // do it for all active CNs
509 for (uiNodeId_p = 1;
510 uiNodeId_p <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo);
511 uiNodeId_p++) {
512 if ((EPL_NMTMNU_GET_NODEINFO(uiNodeId_p)->
513 m_dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN |
514 EPL_NODEASSIGN_NODE_EXISTS)) != 0) {
515 if (fSoftDeleteNode == FALSE) { // remove CN immediately from isochronous phase
516 Ret = EplDlluCalDeleteNode(uiNodeId_p);
517 } else { // remove CN from isochronous phase softly
518 Ret =
519 EplDlluCalSoftDeleteNode
520 (uiNodeId_p);
521 }
522 }
523 }
524 }
525
526 Exit:
527 return Ret;
528 }
529
530 //---------------------------------------------------------------------------
531 //
532 // Function: EplNmtMnuSendNmtCommand
533 //
534 // Description: sends the specified NMT command to the specified node.
535 //
536 // Parameters: uiNodeId_p = node ID to which the NMT command will be sent
537 // NmtCommand_p = NMT command
538 //
539 // Returns: tEplKernel = error code
540 //
541 // State:
542 //
543 //---------------------------------------------------------------------------
544
EplNmtMnuSendNmtCommand(unsigned int uiNodeId_p,tEplNmtCommand NmtCommand_p)545 tEplKernel EplNmtMnuSendNmtCommand(unsigned int uiNodeId_p,
546 tEplNmtCommand NmtCommand_p)
547 {
548 tEplKernel Ret = kEplSuccessful;
549
550 Ret = EplNmtMnuSendNmtCommandEx(uiNodeId_p, NmtCommand_p, NULL, 0);
551
552 //Exit:
553 return Ret;
554 }
555
556 //---------------------------------------------------------------------------
557 //
558 // Function: EplNmtMnuTriggerStateChange
559 //
560 // Description: triggers the specified node command for the specified node.
561 //
562 // Parameters: uiNodeId_p = node ID for which the node command will be executed
563 // NodeCommand_p = node command
564 //
565 // Returns: tEplKernel = error code
566 //
567 // State:
568 //
569 //---------------------------------------------------------------------------
570
EplNmtMnuTriggerStateChange(unsigned int uiNodeId_p,tEplNmtNodeCommand NodeCommand_p)571 tEplKernel EplNmtMnuTriggerStateChange(unsigned int uiNodeId_p,
572 tEplNmtNodeCommand NodeCommand_p)
573 {
574 tEplKernel Ret = kEplSuccessful;
575 tEplNmtMnuIntNodeEvent NodeEvent;
576 tEplObdSize ObdSize;
577 BYTE bNmtState;
578 WORD wErrorCode = EPL_E_NO_ERROR;
579
580 if ((uiNodeId_p == 0) || (uiNodeId_p >= EPL_C_ADR_BROADCAST)) {
581 Ret = kEplInvalidNodeId;
582 goto Exit;
583 }
584
585 switch (NodeCommand_p) {
586 case kEplNmtNodeCommandBoot:
587 {
588 NodeEvent = kEplNmtMnuIntNodeEventBoot;
589 break;
590 }
591
592 case kEplNmtNodeCommandConfOk:
593 {
594 NodeEvent = kEplNmtMnuIntNodeEventConfigured;
595 break;
596 }
597
598 case kEplNmtNodeCommandConfErr:
599 {
600 NodeEvent = kEplNmtMnuIntNodeEventError;
601 wErrorCode = EPL_E_NMT_BPO1_CF_VERIFY;
602 break;
603 }
604
605 case kEplNmtNodeCommandConfReset:
606 {
607 NodeEvent = kEplNmtMnuIntNodeEventExecReset;
608 break;
609 }
610
611 default:
612 { // invalid node command
613 goto Exit;
614 }
615 }
616
617 // fetch current NMT state
618 ObdSize = 1;
619 Ret = EplObduReadEntry(0x1F8E, uiNodeId_p, &bNmtState, &ObdSize);
620 if (Ret != kEplSuccessful) {
621 goto Exit;
622 }
623
624 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
625 (tEplNmtState) (bNmtState |
626 EPL_NMT_TYPE_CS),
627 wErrorCode, NodeEvent);
628
629 Exit:
630 return Ret;
631 }
632
633 //---------------------------------------------------------------------------
634 //
635 // Function: EplNmtMnuCbNmtStateChange
636 //
637 // Description: callback function for NMT state changes
638 //
639 // Parameters: NmtStateChange_p = NMT state change event
640 //
641 // Returns: tEplKernel = error code
642 //
643 //
644 // State:
645 //
646 //---------------------------------------------------------------------------
647
EplNmtMnuCbNmtStateChange(tEplEventNmtStateChange NmtStateChange_p)648 tEplKernel PUBLIC EplNmtMnuCbNmtStateChange(tEplEventNmtStateChange
649 NmtStateChange_p)
650 {
651 tEplKernel Ret = kEplSuccessful;
652
653 // do work which must be done in that state
654 switch (NmtStateChange_p.m_NewNmtState) {
655 // EPL stack is not running
656 /* case kEplNmtGsOff:
657 break;
658
659 // first init of the hardware
660 case kEplNmtGsInitialising:
661 break;
662
663 // init of the manufacturer-specific profile area and the
664 // standardised device profile area
665 case kEplNmtGsResetApplication:
666 {
667 break;
668 }
669
670 // init of the communication profile area
671 case kEplNmtGsResetCommunication:
672 {
673 break;
674 }
675 */
676 // build the configuration with infos from OD
677 case kEplNmtGsResetConfiguration:
678 {
679 DWORD dwTimeout;
680 tEplObdSize ObdSize;
681
682 // read object 0x1F80 NMT_StartUp_U32
683 ObdSize = 4;
684 Ret =
685 EplObduReadEntry(0x1F80, 0,
686 &EplNmtMnuInstance_g.
687 m_dwNmtStartup, &ObdSize);
688 if (Ret != kEplSuccessful) {
689 break;
690 }
691 // compute StatusReqDelay = object 0x1006 * EPL_C_NMT_STATREQ_CYCLE
692 ObdSize = sizeof(dwTimeout);
693 Ret = EplObduReadEntry(0x1006, 0, &dwTimeout, &ObdSize);
694 if (Ret != kEplSuccessful) {
695 break;
696 }
697 if (dwTimeout != 0L) {
698 EplNmtMnuInstance_g.m_ulStatusRequestDelay =
699 dwTimeout * EPL_C_NMT_STATREQ_CYCLE / 1000L;
700 if (EplNmtMnuInstance_g.
701 m_ulStatusRequestDelay == 0L) {
702 EplNmtMnuInstance_g.m_ulStatusRequestDelay = 1L; // at least 1 ms
703 }
704 // $$$ fetch and use MultiplexedCycleCount from OD
705 EplNmtMnuInstance_g.m_ulTimeoutCheckCom =
706 dwTimeout * EPL_C_NMT_STATREQ_CYCLE / 1000L;
707 if (EplNmtMnuInstance_g.m_ulTimeoutCheckCom ==
708 0L) {
709 EplNmtMnuInstance_g.m_ulTimeoutCheckCom = 1L; // at least 1 ms
710 }
711 }
712 // fetch ReadyToOp Timeout from OD
713 ObdSize = sizeof(dwTimeout);
714 Ret = EplObduReadEntry(0x1F89, 5, &dwTimeout, &ObdSize);
715 if (Ret != kEplSuccessful) {
716 break;
717 }
718 if (dwTimeout != 0L) {
719 // convert [us] to [ms]
720 dwTimeout /= 1000L;
721 if (dwTimeout == 0L) {
722 dwTimeout = 1L; // at least 1 ms
723 }
724 EplNmtMnuInstance_g.m_ulTimeoutReadyToOp =
725 dwTimeout;
726 } else {
727 EplNmtMnuInstance_g.m_ulTimeoutReadyToOp = 0L;
728 }
729 break;
730 }
731 /*
732 //-----------------------------------------------------------
733 // CN part of the state machine
734
735 // node liste for EPL-Frames and check timeout
736 case kEplNmtCsNotActive:
737 {
738 break;
739 }
740
741 // node process only async frames
742 case kEplNmtCsPreOperational1:
743 {
744 break;
745 }
746
747 // node process isochronus and asynchronus frames
748 case kEplNmtCsPreOperational2:
749 {
750 break;
751 }
752
753 // node should be configured und application is ready
754 case kEplNmtCsReadyToOperate:
755 {
756 break;
757 }
758
759 // normal work state
760 case kEplNmtCsOperational:
761 {
762 break;
763 }
764
765 // node stopped by MN
766 // -> only process asynchronus frames
767 case kEplNmtCsStopped:
768 {
769 break;
770 }
771
772 // no EPL cycle
773 // -> normal ethernet communication
774 case kEplNmtCsBasicEthernet:
775 {
776 break;
777 }
778 */
779 //-----------------------------------------------------------
780 // MN part of the state machine
781
782 // node listens for EPL-Frames and check timeout
783 case kEplNmtMsNotActive:
784 {
785 break;
786 }
787
788 // node processes only async frames
789 case kEplNmtMsPreOperational1:
790 {
791 DWORD dwTimeout;
792 tEplTimerArg TimerArg;
793 tEplObdSize ObdSize;
794 tEplEvent Event;
795
796 // clear global flags, e.g. reenable boot process
797 EplNmtMnuInstance_g.m_wFlags = 0;
798
799 // reset IdentResponses and running IdentRequests and StatusRequests
800 Ret = EplIdentuReset();
801 Ret = EplStatusuReset();
802
803 // reset timers
804 Ret = EplNmtMnuReset();
805
806 // 2008/11/18 d.k. reset internal node info is not necessary,
807 // because timer flags are important and other
808 // things are reset by EplNmtMnuStartBootStep1().
809 /*
810 EPL_MEMSET(EplNmtMnuInstance_g.m_aNodeInfo,
811 0,
812 sizeof (EplNmtMnuInstance_g.m_aNodeInfo));
813 */
814
815 // inform DLL about NMT state change,
816 // so that it can clear the asynchonous queues and start the reduced cycle
817 Event.m_EventSink = kEplEventSinkDllk;
818 Event.m_EventType = kEplEventTypeDllkStartReducedCycle;
819 EPL_MEMSET(&Event.m_NetTime, 0x00,
820 sizeof(Event.m_NetTime));
821 Event.m_pArg = NULL;
822 Event.m_uiSize = 0;
823 Ret = EplEventuPost(&Event);
824 if (Ret != kEplSuccessful) {
825 break;
826 }
827 // reset all nodes
828 // d.k.: skip this step if was just done before, e.g. because of a ResetNode command from a diagnostic node
829 if (NmtStateChange_p.m_NmtEvent ==
830 kEplNmtEventTimerMsPreOp1) {
831 BENCHMARK_MOD_07_TOGGLE(9);
832
833 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
834 EPL_C_ADR_BROADCAST,
835 kEplNmtCmdResetNode);
836
837 Ret =
838 EplNmtMnuSendNmtCommand(EPL_C_ADR_BROADCAST,
839 kEplNmtCmdResetNode);
840 if (Ret != kEplSuccessful) {
841 break;
842 }
843 }
844 // start network scan
845 Ret = EplNmtMnuStartBootStep1();
846
847 // start timer for 0x1F89/2 MNTimeoutPreOp1_U32
848 ObdSize = sizeof(dwTimeout);
849 Ret = EplObduReadEntry(0x1F89, 2, &dwTimeout, &ObdSize);
850 if (Ret != kEplSuccessful) {
851 break;
852 }
853 if (dwTimeout != 0L) {
854 dwTimeout /= 1000L;
855 if (dwTimeout == 0L) {
856 dwTimeout = 1L; // at least 1 ms
857 }
858 TimerArg.m_EventSink = kEplEventSinkNmtMnu;
859 TimerArg.m_ulArg = 0;
860 Ret =
861 EplTimeruModifyTimerMs(&EplNmtMnuInstance_g.
862 m_TimerHdlNmtState,
863 dwTimeout, TimerArg);
864 }
865 break;
866 }
867
868 // node processes isochronous and asynchronous frames
869 case kEplNmtMsPreOperational2:
870 {
871 // add identified CNs to isochronous phase
872 // send EnableReadyToOp to all identified CNs
873 Ret = EplNmtMnuStartBootStep2();
874
875 // wait for NMT state change of CNs
876 break;
877 }
878
879 // node should be configured und application is ready
880 case kEplNmtMsReadyToOperate:
881 {
882 // check if PRes of CNs are OK
883 // d.k. that means wait CycleLength * MultiplexCycleCount (i.e. start timer)
884 // because Dllk checks PRes of CNs automatically in ReadyToOp
885 Ret = EplNmtMnuStartCheckCom();
886 break;
887 }
888
889 // normal work state
890 case kEplNmtMsOperational:
891 {
892 // send StartNode to CNs
893 // wait for NMT state change of CNs
894 Ret = EplNmtMnuStartNodes();
895 break;
896 }
897
898 // no EPL cycle
899 // -> normal ethernet communication
900 case kEplNmtMsBasicEthernet:
901 {
902 break;
903 }
904
905 default:
906 {
907 // TRACE0("EplNmtMnuCbNmtStateChange(): unhandled NMT state\n");
908 }
909 }
910
911 return Ret;
912 }
913
914 //---------------------------------------------------------------------------
915 //
916 // Function: EplNmtMnuCbCheckEvent
917 //
918 // Description: callback funktion for NMT events before they are actually executed.
919 // The EPL API layer must forward NMT events from NmtCnu module.
920 // This module will reject some NMT commands while MN.
921 //
922 // Parameters: NmtEvent_p = outstanding NMT event for approval
923 //
924 // Returns: tEplKernel = error code
925 // kEplReject = reject the NMT event
926 //
927 // State:
928 //
929 //---------------------------------------------------------------------------
930
EplNmtMnuCbCheckEvent(tEplNmtEvent NmtEvent_p)931 tEplKernel PUBLIC EplNmtMnuCbCheckEvent(tEplNmtEvent NmtEvent_p)
932 {
933 tEplKernel Ret = kEplSuccessful;
934
935 return Ret;
936 }
937
938 //---------------------------------------------------------------------------
939 //
940 // Function: EplNmtuProcessEvent
941 //
942 // Description: processes events from event queue
943 //
944 // Parameters: pEvent_p = pointer to event
945 //
946 // Returns: tEplKernel = errorcode
947 //
948 // State:
949 //
950 //---------------------------------------------------------------------------
951
EplNmtMnuProcessEvent(tEplEvent * pEvent_p)952 EPLDLLEXPORT tEplKernel PUBLIC EplNmtMnuProcessEvent(tEplEvent * pEvent_p)
953 {
954 tEplKernel Ret;
955
956 Ret = kEplSuccessful;
957
958 // process event
959 switch (pEvent_p->m_EventType) {
960 // timer event
961 case kEplEventTypeTimer:
962 {
963 tEplTimerEventArg *pTimerEventArg =
964 (tEplTimerEventArg *) pEvent_p->m_pArg;
965 unsigned int uiNodeId;
966
967 uiNodeId =
968 (unsigned int)(pTimerEventArg->
969 m_ulArg &
970 EPL_NMTMNU_TIMERARG_NODE_MASK);
971 if (uiNodeId != 0) {
972 tEplObdSize ObdSize;
973 BYTE bNmtState;
974 tEplNmtMnuNodeInfo *pNodeInfo;
975
976 pNodeInfo = EPL_NMTMNU_GET_NODEINFO(uiNodeId);
977
978 ObdSize = 1;
979 Ret =
980 EplObduReadEntry(0x1F8E, uiNodeId,
981 &bNmtState, &ObdSize);
982 if (Ret != kEplSuccessful) {
983 break;
984 }
985
986 if ((pTimerEventArg->
987 m_ulArg & EPL_NMTMNU_TIMERARG_IDENTREQ) !=
988 0L) {
989 if ((pNodeInfo->
990 m_wFlags &
991 EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ)
992 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR)) { // this is an old (already deleted or modified) timer
993 // but not the current timer
994 // so discard it
995 EPL_NMTMNU_DBG_POST_TRACE_VALUE
996 (kEplNmtMnuIntNodeEventTimerIdentReq,
997 uiNodeId,
998 ((pNodeInfo->
999 m_NodeState << 8)
1000 | 0xFF));
1001
1002 break;
1003 }
1004 /*
1005 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerIdentReq,
1006 uiNodeId,
1007 ((pNodeInfo->m_NodeState << 8)
1008 | 0x80
1009 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1010 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1011 */
1012 Ret =
1013 EplNmtMnuProcessInternalEvent
1014 (uiNodeId,
1015 (tEplNmtState) (bNmtState |
1016 EPL_NMT_TYPE_CS),
1017 EPL_E_NO_ERROR,
1018 kEplNmtMnuIntNodeEventTimerIdentReq);
1019 }
1020
1021 else if ((pTimerEventArg->
1022 m_ulArg & EPL_NMTMNU_TIMERARG_STATREQ)
1023 != 0L) {
1024 if ((pNodeInfo->
1025 m_wFlags &
1026 EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ)
1027 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR)) { // this is an old (already deleted or modified) timer
1028 // but not the current timer
1029 // so discard it
1030 EPL_NMTMNU_DBG_POST_TRACE_VALUE
1031 (kEplNmtMnuIntNodeEventTimerStatReq,
1032 uiNodeId,
1033 ((pNodeInfo->
1034 m_NodeState << 8)
1035 | 0xFF));
1036
1037 break;
1038 }
1039 /*
1040 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq,
1041 uiNodeId,
1042 ((pNodeInfo->m_NodeState << 8)
1043 | 0x80
1044 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1045 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1046 */
1047 Ret =
1048 EplNmtMnuProcessInternalEvent
1049 (uiNodeId,
1050 (tEplNmtState) (bNmtState |
1051 EPL_NMT_TYPE_CS),
1052 EPL_E_NO_ERROR,
1053 kEplNmtMnuIntNodeEventTimerStatReq);
1054 }
1055
1056 else if ((pTimerEventArg->
1057 m_ulArg &
1058 EPL_NMTMNU_TIMERARG_STATE_MON) !=
1059 0L) {
1060 if ((pNodeInfo->
1061 m_wFlags &
1062 EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ)
1063 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR)) { // this is an old (already deleted or modified) timer
1064 // but not the current timer
1065 // so discard it
1066 EPL_NMTMNU_DBG_POST_TRACE_VALUE
1067 (kEplNmtMnuIntNodeEventTimerStateMon,
1068 uiNodeId,
1069 ((pNodeInfo->
1070 m_NodeState << 8)
1071 | 0xFF));
1072
1073 break;
1074 }
1075 /*
1076 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerStatReq,
1077 uiNodeId,
1078 ((pNodeInfo->m_NodeState << 8)
1079 | 0x80
1080 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
1081 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
1082 */
1083 Ret =
1084 EplNmtMnuProcessInternalEvent
1085 (uiNodeId,
1086 (tEplNmtState) (bNmtState |
1087 EPL_NMT_TYPE_CS),
1088 EPL_E_NO_ERROR,
1089 kEplNmtMnuIntNodeEventTimerStateMon);
1090 }
1091
1092 else if ((pTimerEventArg->
1093 m_ulArg & EPL_NMTMNU_TIMERARG_LONGER)
1094 != 0L) {
1095 if ((pNodeInfo->
1096 m_wFlags &
1097 EPL_NMTMNU_NODE_FLAG_COUNT_LONGER)
1098 != (pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_LO)) { // this is an old (already deleted or modified) timer
1099 // but not the current timer
1100 // so discard it
1101 EPL_NMTMNU_DBG_POST_TRACE_VALUE
1102 (kEplNmtMnuIntNodeEventTimerLonger,
1103 uiNodeId,
1104 ((pNodeInfo->
1105 m_NodeState << 8)
1106 | 0xFF));
1107
1108 break;
1109 }
1110 /*
1111 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventTimerLonger,
1112 uiNodeId,
1113 ((pNodeInfo->m_NodeState << 8)
1114 | 0x80
1115 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_LONGER) >> 6)
1116 | ((pTimerEventArg->m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_LO) >> 8)));
1117 */
1118 Ret =
1119 EplNmtMnuProcessInternalEvent
1120 (uiNodeId,
1121 (tEplNmtState) (bNmtState |
1122 EPL_NMT_TYPE_CS),
1123 EPL_E_NO_ERROR,
1124 kEplNmtMnuIntNodeEventTimerLonger);
1125 }
1126
1127 } else { // global timer event
1128 }
1129 break;
1130 }
1131
1132 case kEplEventTypeHeartbeat:
1133 {
1134 tEplHeartbeatEvent *pHeartbeatEvent =
1135 (tEplHeartbeatEvent *) pEvent_p->m_pArg;
1136
1137 Ret =
1138 EplNmtMnuProcessInternalEvent(pHeartbeatEvent->
1139 m_uiNodeId,
1140 pHeartbeatEvent->
1141 m_NmtState,
1142 pHeartbeatEvent->
1143 m_wErrorCode,
1144 kEplNmtMnuIntNodeEventHeartbeat);
1145 break;
1146 }
1147
1148 case kEplEventTypeNmtMnuNmtCmdSent:
1149 {
1150 tEplFrame *pFrame = (tEplFrame *) pEvent_p->m_pArg;
1151 unsigned int uiNodeId;
1152 tEplNmtCommand NmtCommand;
1153 BYTE bNmtState;
1154
1155 uiNodeId = AmiGetByteFromLe(&pFrame->m_le_bDstNodeId);
1156 NmtCommand =
1157 (tEplNmtCommand) AmiGetByteFromLe(&pFrame->m_Data.
1158 m_Asnd.m_Payload.
1159 m_NmtCommandService.
1160 m_le_bNmtCommandId);
1161
1162 switch (NmtCommand) {
1163 case kEplNmtCmdStartNode:
1164 bNmtState =
1165 (BYTE) (kEplNmtCsOperational & 0xFF);
1166 break;
1167
1168 case kEplNmtCmdStopNode:
1169 bNmtState = (BYTE) (kEplNmtCsStopped & 0xFF);
1170 break;
1171
1172 case kEplNmtCmdEnterPreOperational2:
1173 bNmtState =
1174 (BYTE) (kEplNmtCsPreOperational2 & 0xFF);
1175 break;
1176
1177 case kEplNmtCmdEnableReadyToOperate:
1178 // d.k. do not change expected node state, because of DS 1.0.0 7.3.1.2.1 Plain NMT State Command
1179 // and because node may not change NMT state within EPL_C_NMT_STATE_TOLERANCE
1180 bNmtState =
1181 (BYTE) (kEplNmtCsPreOperational2 & 0xFF);
1182 break;
1183
1184 case kEplNmtCmdResetNode:
1185 case kEplNmtCmdResetCommunication:
1186 case kEplNmtCmdResetConfiguration:
1187 case kEplNmtCmdSwReset:
1188 bNmtState = (BYTE) (kEplNmtCsNotActive & 0xFF);
1189 // EplNmtMnuProcessInternalEvent() sets internal node state to kEplNmtMnuNodeStateUnknown
1190 // after next unresponded IdentRequest/StatusRequest
1191 break;
1192
1193 default:
1194 goto Exit;
1195 }
1196
1197 // process as internal event which update expected NMT state in OD
1198 if (uiNodeId != EPL_C_ADR_BROADCAST) {
1199 Ret = EplNmtMnuProcessInternalEvent(uiNodeId,
1200 (tEplNmtState)
1201 (bNmtState |
1202 EPL_NMT_TYPE_CS),
1203 0,
1204 kEplNmtMnuIntNodeEventNmtCmdSent);
1205
1206 } else { // process internal event for all active nodes (except myself)
1207
1208 for (uiNodeId = 1;
1209 uiNodeId <=
1210 tabentries(EplNmtMnuInstance_g.
1211 m_aNodeInfo); uiNodeId++) {
1212 if ((EPL_NMTMNU_GET_NODEINFO(uiNodeId)->
1213 m_dwNodeCfg &
1214 (EPL_NODEASSIGN_NODE_IS_CN |
1215 EPL_NODEASSIGN_NODE_EXISTS)) !=
1216 0) {
1217 Ret =
1218 EplNmtMnuProcessInternalEvent
1219 (uiNodeId,
1220 (tEplNmtState) (bNmtState |
1221 EPL_NMT_TYPE_CS),
1222 0,
1223 kEplNmtMnuIntNodeEventNmtCmdSent);
1224
1225 if (Ret != kEplSuccessful) {
1226 goto Exit;
1227 }
1228 }
1229 }
1230 }
1231
1232 break;
1233 }
1234
1235 default:
1236 {
1237 Ret = kEplNmtInvalidEvent;
1238 }
1239
1240 }
1241
1242 Exit:
1243 return Ret;
1244 }
1245
1246 //---------------------------------------------------------------------------
1247 //
1248 // Function: EplNmtMnuGetRunningTimerStatReq
1249 //
1250 // Description: returns a bit field with running StatReq timers
1251 // just for debugging purposes
1252 //
1253 // Parameters: (none)
1254 //
1255 // Returns: tEplKernel = error code
1256 //
1257 // State:
1258 //
1259 //---------------------------------------------------------------------------
1260
EplNmtMnuGetDiagnosticInfo(unsigned int * puiMandatorySlaveCount_p,unsigned int * puiSignalSlaveCount_p,WORD * pwFlags_p)1261 tEplKernel PUBLIC EplNmtMnuGetDiagnosticInfo(unsigned int
1262 *puiMandatorySlaveCount_p,
1263 unsigned int
1264 *puiSignalSlaveCount_p,
1265 WORD * pwFlags_p)
1266 {
1267 tEplKernel Ret = kEplSuccessful;
1268
1269 if ((puiMandatorySlaveCount_p == NULL)
1270 || (puiSignalSlaveCount_p == NULL)
1271 || (pwFlags_p == NULL)) {
1272 Ret = kEplNmtInvalidParam;
1273 goto Exit;
1274 }
1275
1276 *puiMandatorySlaveCount_p = EplNmtMnuInstance_g.m_uiMandatorySlaveCount;
1277 *puiSignalSlaveCount_p = EplNmtMnuInstance_g.m_uiSignalSlaveCount;
1278 *pwFlags_p = EplNmtMnuInstance_g.m_wFlags;
1279
1280 Exit:
1281 return Ret;
1282 }
1283
1284 //---------------------------------------------------------------------------
1285 //
1286 // Function: EplNmtMnuGetRunningTimerStatReq
1287 //
1288 // Description: returns a bit field with running StatReq timers
1289 // just for debugging purposes
1290 //
1291 // Parameters: (none)
1292 //
1293 // Returns: tEplKernel = error code
1294 //
1295 // State:
1296 //
1297 //---------------------------------------------------------------------------
1298 /*
1299 DWORD EplNmtMnuGetRunningTimerStatReq(void)
1300 {
1301 tEplKernel Ret = kEplSuccessful;
1302 unsigned int uiIndex;
1303 tEplNmtMnuNodeInfo* pNodeInfo;
1304
1305 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1306 for (uiIndex = 1; uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo); uiIndex++, pNodeInfo++)
1307 {
1308 if (pNodeInfo->m_NodeState == kEplNmtMnuNodeStateConfigured)
1309 {
1310 // reset flag "scanned once"
1311 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_SCANNED;
1312
1313 Ret = EplNmtMnuNodeBootStep2(uiIndex, pNodeInfo);
1314 if (Ret != kEplSuccessful)
1315 {
1316 goto Exit;
1317 }
1318 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1319 // signal slave counter shall be decremented if StatusRequest was sent once to a CN
1320 // mandatory slave counter shall be decremented if mandatory CN is ReadyToOp
1321 }
1322 }
1323
1324 Exit:
1325 return Ret;
1326 }
1327 */
1328
1329 //=========================================================================//
1330 // //
1331 // P R I V A T E F U N C T I O N S //
1332 // //
1333 //=========================================================================//
1334
1335 //---------------------------------------------------------------------------
1336 //
1337 // Function: EplNmtMnuCbNmtRequest
1338 //
1339 // Description: callback funktion for NmtRequest
1340 //
1341 // Parameters: pFrameInfo_p = Frame with the NmtRequest
1342 //
1343 // Returns: tEplKernel = error code
1344 //
1345 //
1346 // State:
1347 //
1348 //---------------------------------------------------------------------------
1349
EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p)1350 static tEplKernel PUBLIC EplNmtMnuCbNmtRequest(tEplFrameInfo * pFrameInfo_p)
1351 {
1352 tEplKernel Ret = kEplSuccessful;
1353
1354 // $$$ perform NMTRequest
1355 return Ret;
1356 }
1357
1358 //---------------------------------------------------------------------------
1359 //
1360 // Function: EplNmtMnuCbIdentResponse
1361 //
1362 // Description: callback funktion for IdentResponse
1363 //
1364 // Parameters: uiNodeId_p = node ID for which IdentReponse was received
1365 // pIdentResponse_p = pointer to IdentResponse
1366 // is NULL if node did not answer
1367 //
1368 // Returns: tEplKernel = error code
1369 //
1370 // State:
1371 //
1372 //---------------------------------------------------------------------------
1373
EplNmtMnuCbIdentResponse(unsigned int uiNodeId_p,tEplIdentResponse * pIdentResponse_p)1374 static tEplKernel PUBLIC EplNmtMnuCbIdentResponse(unsigned int uiNodeId_p,
1375 tEplIdentResponse *
1376 pIdentResponse_p)
1377 {
1378 tEplKernel Ret = kEplSuccessful;
1379
1380 if (pIdentResponse_p == NULL) { // node did not answer
1381 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p, kEplNmtCsNotActive, EPL_E_NMT_NO_IDENT_RES, // was EPL_E_NO_ERROR
1382 kEplNmtMnuIntNodeEventNoIdentResponse);
1383 } else { // node answered IdentRequest
1384 tEplObdSize ObdSize;
1385 DWORD dwDevType;
1386 WORD wErrorCode = EPL_E_NO_ERROR;
1387 tEplNmtState NmtState =
1388 (tEplNmtState) (AmiGetByteFromLe
1389 (&pIdentResponse_p->
1390 m_le_bNmtStatus) | EPL_NMT_TYPE_CS);
1391
1392 // check IdentResponse $$$ move to ProcessIntern, because this function may be called also if CN
1393
1394 // check DeviceType (0x1F84)
1395 ObdSize = 4;
1396 Ret =
1397 EplObduReadEntry(0x1F84, uiNodeId_p, &dwDevType, &ObdSize);
1398 if (Ret != kEplSuccessful) {
1399 goto Exit;
1400 }
1401 if (dwDevType != 0L) { // actually compare it with DeviceType from IdentResponse
1402 if (AmiGetDwordFromLe(&pIdentResponse_p->m_le_dwDeviceType) != dwDevType) { // wrong DeviceType
1403 NmtState = kEplNmtCsNotActive;
1404 wErrorCode = EPL_E_NMT_BPO1_DEVICE_TYPE;
1405 }
1406 }
1407
1408 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1409 NmtState,
1410 wErrorCode,
1411 kEplNmtMnuIntNodeEventIdentResponse);
1412 }
1413
1414 Exit:
1415 return Ret;
1416 }
1417
1418 //---------------------------------------------------------------------------
1419 //
1420 // Function: EplNmtMnuCbStatusResponse
1421 //
1422 // Description: callback funktion for StatusResponse
1423 //
1424 // Parameters: uiNodeId_p = node ID for which IdentReponse was received
1425 // pIdentResponse_p = pointer to IdentResponse
1426 // is NULL if node did not answer
1427 //
1428 // Returns: tEplKernel = error code
1429 //
1430 // State:
1431 //
1432 //---------------------------------------------------------------------------
1433
EplNmtMnuCbStatusResponse(unsigned int uiNodeId_p,tEplStatusResponse * pStatusResponse_p)1434 static tEplKernel PUBLIC EplNmtMnuCbStatusResponse(unsigned int uiNodeId_p,
1435 tEplStatusResponse *
1436 pStatusResponse_p)
1437 {
1438 tEplKernel Ret = kEplSuccessful;
1439
1440 if (pStatusResponse_p == NULL) { // node did not answer
1441 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p, kEplNmtCsNotActive, EPL_E_NMT_NO_STATUS_RES, // was EPL_E_NO_ERROR
1442 kEplNmtMnuIntNodeEventNoStatusResponse);
1443 } else { // node answered StatusRequest
1444 Ret = EplNmtMnuProcessInternalEvent(uiNodeId_p,
1445 (tEplNmtState)
1446 (AmiGetByteFromLe
1447 (&pStatusResponse_p->
1448 m_le_bNmtStatus) |
1449 EPL_NMT_TYPE_CS),
1450 EPL_E_NO_ERROR,
1451 kEplNmtMnuIntNodeEventStatusResponse);
1452 }
1453
1454 return Ret;
1455 }
1456
1457 //---------------------------------------------------------------------------
1458 //
1459 // Function: EplNmtMnuStartBootStep1
1460 //
1461 // Description: starts BootStep1
1462 //
1463 // Parameters: (none)
1464 //
1465 // Returns: tEplKernel = error code
1466 //
1467 // State:
1468 //
1469 //---------------------------------------------------------------------------
1470
EplNmtMnuStartBootStep1(void)1471 static tEplKernel EplNmtMnuStartBootStep1(void)
1472 {
1473 tEplKernel Ret = kEplSuccessful;
1474 unsigned int uiSubIndex;
1475 unsigned int uiLocalNodeId;
1476 DWORD dwNodeCfg;
1477 tEplObdSize ObdSize;
1478
1479 // $$$ d.k.: save current time for 0x1F89/2 MNTimeoutPreOp1_U32
1480
1481 // start network scan
1482 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1483 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1484 // check 0x1F81
1485 uiLocalNodeId = EplObduGetNodeId();
1486 for (uiSubIndex = 1; uiSubIndex <= 254; uiSubIndex++) {
1487 ObdSize = 4;
1488 Ret =
1489 EplObduReadEntry(0x1F81, uiSubIndex, &dwNodeCfg, &ObdSize);
1490 if (Ret != kEplSuccessful) {
1491 goto Exit;
1492 }
1493 if (uiSubIndex != uiLocalNodeId) {
1494 // reset flags "not scanned" and "isochronous"
1495 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_wFlags &=
1496 ~(EPL_NMTMNU_NODE_FLAG_ISOCHRON |
1497 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED);
1498
1499 if (uiSubIndex == EPL_C_ADR_DIAG_DEF_NODE_ID) { // diagnostic node must be scanned by MN in any case
1500 dwNodeCfg |=
1501 (EPL_NODEASSIGN_NODE_IS_CN |
1502 EPL_NODEASSIGN_NODE_EXISTS);
1503 // and it must be isochronously accessed
1504 dwNodeCfg &= ~EPL_NODEASSIGN_ASYNCONLY_NODE;
1505 }
1506 // save node config in local node info structure
1507 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_dwNodeCfg =
1508 dwNodeCfg;
1509 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_NodeState =
1510 kEplNmtMnuNodeStateUnknown;
1511
1512 if ((dwNodeCfg & (EPL_NODEASSIGN_NODE_IS_CN | EPL_NODEASSIGN_NODE_EXISTS)) != 0) { // node is configured as CN
1513 // identify the node
1514 Ret =
1515 EplIdentuRequestIdentResponse(uiSubIndex,
1516 EplNmtMnuCbIdentResponse);
1517 if (Ret != kEplSuccessful) {
1518 goto Exit;
1519 }
1520 // set flag "not scanned"
1521 EPL_NMTMNU_GET_NODEINFO(uiSubIndex)->m_wFlags |=
1522 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1523 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1524 // signal slave counter shall be decremented if IdentRequest was sent once to a CN
1525
1526 if ((dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN
1527 EplNmtMnuInstance_g.
1528 m_uiMandatorySlaveCount++;
1529 // mandatory slave counter shall be decremented if mandatory CN was configured successfully
1530 }
1531 }
1532 } else { // subindex of MN
1533 if ((dwNodeCfg & (EPL_NODEASSIGN_MN_PRES | EPL_NODEASSIGN_NODE_EXISTS)) != 0) { // MN shall send PRes
1534 tEplDllNodeInfo DllNodeInfo;
1535
1536 EPL_MEMSET(&DllNodeInfo, 0,
1537 sizeof(DllNodeInfo));
1538 DllNodeInfo.m_uiNodeId = uiLocalNodeId;
1539
1540 Ret = EplDlluCalAddNode(&DllNodeInfo);
1541 }
1542 }
1543 }
1544
1545 Exit:
1546 return Ret;
1547 }
1548
1549 //---------------------------------------------------------------------------
1550 //
1551 // Function: EplNmtMnuStartBootStep2
1552 //
1553 // Description: starts BootStep2.
1554 // That means add nodes to isochronous phase and send
1555 // NMT EnableReadyToOp.
1556 //
1557 // Parameters: (none)
1558 //
1559 // Returns: tEplKernel = error code
1560 //
1561 // State:
1562 //
1563 //---------------------------------------------------------------------------
1564
EplNmtMnuStartBootStep2(void)1565 static tEplKernel EplNmtMnuStartBootStep2(void)
1566 {
1567 tEplKernel Ret = kEplSuccessful;
1568 unsigned int uiIndex;
1569 tEplNmtMnuNodeInfo *pNodeInfo;
1570
1571 if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0) { // boot process is not halted
1572 // add nodes to isochronous phase and send NMT EnableReadyToOp
1573 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1574 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1575 // reset flag that application was informed about possible state change
1576 EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED;
1577
1578 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1579 for (uiIndex = 1;
1580 uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo);
1581 uiIndex++, pNodeInfo++) {
1582 if (pNodeInfo->m_NodeState ==
1583 kEplNmtMnuNodeStateConfigured) {
1584 Ret =
1585 EplNmtMnuNodeBootStep2(uiIndex, pNodeInfo);
1586 if (Ret != kEplSuccessful) {
1587 goto Exit;
1588 }
1589 // set flag "not scanned"
1590 pNodeInfo->m_wFlags |=
1591 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1592
1593 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1594 // signal slave counter shall be decremented if StatusRequest was sent once to a CN
1595
1596 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN
1597 EplNmtMnuInstance_g.
1598 m_uiMandatorySlaveCount++;
1599 }
1600 // mandatory slave counter shall be decremented if mandatory CN is ReadyToOp
1601 }
1602 }
1603 }
1604
1605 Exit:
1606 return Ret;
1607 }
1608
1609 //---------------------------------------------------------------------------
1610 //
1611 // Function: EplNmtMnuNodeBootStep2
1612 //
1613 // Description: starts BootStep2 for the specified node.
1614 // This means the CN is added to isochronous phase if not
1615 // async-only and it gets the NMT command EnableReadyToOp.
1616 // The CN must be in node state Configured, when it enters
1617 // BootStep2. When BootStep2 finishes, the CN is in node state
1618 // ReadyToOp.
1619 // If TimeoutReadyToOp in object 0x1F89/5 is configured,
1620 // TimerHdlLonger will be started with this timeout.
1621 //
1622 // Parameters: uiNodeId_p = node ID
1623 // pNodeInfo_p = pointer to internal node info structure
1624 //
1625 // Returns: tEplKernel = error code
1626 //
1627 // State:
1628 //
1629 //---------------------------------------------------------------------------
1630
EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p,tEplNmtMnuNodeInfo * pNodeInfo_p)1631 static tEplKernel EplNmtMnuNodeBootStep2(unsigned int uiNodeId_p,
1632 tEplNmtMnuNodeInfo * pNodeInfo_p)
1633 {
1634 tEplKernel Ret = kEplSuccessful;
1635 tEplDllNodeInfo DllNodeInfo;
1636 DWORD dwNodeCfg;
1637 tEplObdSize ObdSize;
1638 tEplTimerArg TimerArg;
1639
1640 dwNodeCfg = pNodeInfo_p->m_dwNodeCfg;
1641 if ((dwNodeCfg & EPL_NODEASSIGN_ASYNCONLY_NODE) == 0) { // add node to isochronous phase
1642 DllNodeInfo.m_uiNodeId = uiNodeId_p;
1643 ObdSize = 4;
1644 Ret =
1645 EplObduReadEntry(0x1F92, uiNodeId_p,
1646 &DllNodeInfo.m_dwPresTimeout, &ObdSize);
1647 if (Ret != kEplSuccessful) {
1648 goto Exit;
1649 }
1650
1651 ObdSize = 2;
1652 Ret =
1653 EplObduReadEntry(0x1F8B, uiNodeId_p,
1654 &DllNodeInfo.m_wPreqPayloadLimit,
1655 &ObdSize);
1656 if (Ret != kEplSuccessful) {
1657 goto Exit;
1658 }
1659
1660 ObdSize = 2;
1661 Ret =
1662 EplObduReadEntry(0x1F8D, uiNodeId_p,
1663 &DllNodeInfo.m_wPresPayloadLimit,
1664 &ObdSize);
1665 if (Ret != kEplSuccessful) {
1666 goto Exit;
1667 }
1668
1669 pNodeInfo_p->m_wFlags |= EPL_NMTMNU_NODE_FLAG_ISOCHRON;
1670
1671 Ret = EplDlluCalAddNode(&DllNodeInfo);
1672 if (Ret != kEplSuccessful) {
1673 goto Exit;
1674 }
1675
1676 }
1677
1678 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
1679 uiNodeId_p,
1680 kEplNmtCmdEnableReadyToOperate);
1681
1682 Ret =
1683 EplNmtMnuSendNmtCommand(uiNodeId_p, kEplNmtCmdEnableReadyToOperate);
1684 if (Ret != kEplSuccessful) {
1685 goto Exit;
1686 }
1687
1688 if (EplNmtMnuInstance_g.m_ulTimeoutReadyToOp != 0L) { // start timer
1689 // when the timer expires the CN must be ReadyToOp
1690 EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(pNodeInfo_p, uiNodeId_p,
1691 TimerArg);
1692 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
1693 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p;
1694 Ret =
1695 EplTimeruModifyTimerMs(&pNodeInfo_p->m_TimerHdlLonger,
1696 EplNmtMnuInstance_g.
1697 m_ulTimeoutReadyToOp, TimerArg);
1698 }
1699
1700 Exit:
1701 return Ret;
1702 }
1703
1704 //---------------------------------------------------------------------------
1705 //
1706 // Function: EplNmtMnuStartCheckCom
1707 //
1708 // Description: starts CheckCommunication
1709 //
1710 // Parameters: (none)
1711 //
1712 // Returns: tEplKernel = error code
1713 //
1714 // State:
1715 //
1716 //---------------------------------------------------------------------------
1717
EplNmtMnuStartCheckCom(void)1718 static tEplKernel EplNmtMnuStartCheckCom(void)
1719 {
1720 tEplKernel Ret = kEplSuccessful;
1721 unsigned int uiIndex;
1722 tEplNmtMnuNodeInfo *pNodeInfo;
1723
1724 if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0) { // boot process is not halted
1725 // wait some time and check that no communication error occurs
1726 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1727 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1728 // reset flag that application was informed about possible state change
1729 EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED;
1730
1731 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1732 for (uiIndex = 1;
1733 uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo);
1734 uiIndex++, pNodeInfo++) {
1735 if (pNodeInfo->m_NodeState ==
1736 kEplNmtMnuNodeStateReadyToOp) {
1737 Ret = EplNmtMnuNodeCheckCom(uiIndex, pNodeInfo);
1738 if (Ret == kEplReject) { // timer was started
1739 // wait until it expires
1740 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN
1741 EplNmtMnuInstance_g.
1742 m_uiMandatorySlaveCount++;
1743 }
1744 } else if (Ret != kEplSuccessful) {
1745 goto Exit;
1746 }
1747 // set flag "not scanned"
1748 pNodeInfo->m_wFlags |=
1749 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1750
1751 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1752 // signal slave counter shall be decremented if timeout elapsed and regardless of an error
1753 // mandatory slave counter shall be decremented if timeout elapsed and no error occured
1754 }
1755 }
1756 }
1757
1758 Ret = kEplSuccessful;
1759
1760 Exit:
1761 return Ret;
1762 }
1763
1764 //---------------------------------------------------------------------------
1765 //
1766 // Function: EplNmtMnuNodeCheckCom
1767 //
1768 // Description: checks communication of the specified node.
1769 // That means wait some time and if no error occured everything
1770 // is OK.
1771 //
1772 // Parameters: uiNodeId_p = node ID
1773 // pNodeInfo_p = pointer to internal node info structure
1774 //
1775 // Returns: tEplKernel = error code
1776 //
1777 // State:
1778 //
1779 //---------------------------------------------------------------------------
1780
EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p,tEplNmtMnuNodeInfo * pNodeInfo_p)1781 static tEplKernel EplNmtMnuNodeCheckCom(unsigned int uiNodeId_p,
1782 tEplNmtMnuNodeInfo * pNodeInfo_p)
1783 {
1784 tEplKernel Ret = kEplSuccessful;
1785 DWORD dwNodeCfg;
1786 tEplTimerArg TimerArg;
1787
1788 dwNodeCfg = pNodeInfo_p->m_dwNodeCfg;
1789 if (((dwNodeCfg & EPL_NODEASSIGN_ASYNCONLY_NODE) == 0)
1790 && (EplNmtMnuInstance_g.m_ulTimeoutCheckCom != 0L)) { // CN is not async-only and timeout for CheckCom was set
1791
1792 // check communication,
1793 // that means wait some time and if no error occured everything is OK;
1794
1795 // start timer (when the timer expires the CN must be still ReadyToOp)
1796 EPL_NMTMNU_SET_FLAGS_TIMERARG_LONGER(pNodeInfo_p, uiNodeId_p,
1797 TimerArg);
1798 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
1799 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_LONGER | uiNodeId_p;
1800 Ret =
1801 EplTimeruModifyTimerMs(&pNodeInfo_p->m_TimerHdlLonger,
1802 EplNmtMnuInstance_g.
1803 m_ulTimeoutCheckCom, TimerArg);
1804
1805 // update mandatory slave counter, because timer was started
1806 if (Ret == kEplSuccessful) {
1807 Ret = kEplReject;
1808 }
1809 } else { // timer was not started
1810 // assume everything is OK
1811 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateComChecked;
1812 }
1813
1814 //Exit:
1815 return Ret;
1816 }
1817
1818 //---------------------------------------------------------------------------
1819 //
1820 // Function: EplNmtMnuStartNodes
1821 //
1822 // Description: really starts all nodes which are ReadyToOp and CheckCom did not fail
1823 //
1824 // Parameters: (none)
1825 //
1826 // Returns: tEplKernel = error code
1827 //
1828 // State:
1829 //
1830 //---------------------------------------------------------------------------
1831
EplNmtMnuStartNodes(void)1832 static tEplKernel EplNmtMnuStartNodes(void)
1833 {
1834 tEplKernel Ret = kEplSuccessful;
1835 unsigned int uiIndex;
1836 tEplNmtMnuNodeInfo *pNodeInfo;
1837
1838 if ((EplNmtMnuInstance_g.m_wFlags & EPL_NMTMNU_FLAG_HALTED) == 0) { // boot process is not halted
1839 // send NMT command Start Node
1840 EplNmtMnuInstance_g.m_uiMandatorySlaveCount = 0;
1841 EplNmtMnuInstance_g.m_uiSignalSlaveCount = 0;
1842 // reset flag that application was informed about possible state change
1843 EplNmtMnuInstance_g.m_wFlags &= ~EPL_NMTMNU_FLAG_APP_INFORMED;
1844
1845 pNodeInfo = EplNmtMnuInstance_g.m_aNodeInfo;
1846 for (uiIndex = 1;
1847 uiIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo);
1848 uiIndex++, pNodeInfo++) {
1849 if (pNodeInfo->m_NodeState ==
1850 kEplNmtMnuNodeStateComChecked) {
1851 if ((EplNmtMnuInstance_g.
1852 m_dwNmtStartup & EPL_NMTST_STARTALLNODES)
1853 == 0) {
1854 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
1855 uiIndex,
1856 kEplNmtCmdStartNode);
1857
1858 Ret =
1859 EplNmtMnuSendNmtCommand(uiIndex,
1860 kEplNmtCmdStartNode);
1861 if (Ret != kEplSuccessful) {
1862 goto Exit;
1863 }
1864 }
1865
1866 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN
1867 EplNmtMnuInstance_g.
1868 m_uiMandatorySlaveCount++;
1869 }
1870 // set flag "not scanned"
1871 pNodeInfo->m_wFlags |=
1872 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1873
1874 EplNmtMnuInstance_g.m_uiSignalSlaveCount++;
1875 // signal slave counter shall be decremented if StatusRequest was sent once to a CN
1876 // mandatory slave counter shall be decremented if mandatory CN is OPERATIONAL
1877 }
1878 }
1879
1880 // $$$ inform application if EPL_NMTST_NO_STARTNODE is set
1881
1882 if ((EplNmtMnuInstance_g.
1883 m_dwNmtStartup & EPL_NMTST_STARTALLNODES) != 0) {
1884 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0, EPL_C_ADR_BROADCAST,
1885 kEplNmtCmdStartNode);
1886
1887 Ret =
1888 EplNmtMnuSendNmtCommand(EPL_C_ADR_BROADCAST,
1889 kEplNmtCmdStartNode);
1890 if (Ret != kEplSuccessful) {
1891 goto Exit;
1892 }
1893 }
1894 }
1895
1896 Exit:
1897 return Ret;
1898 }
1899
1900 //---------------------------------------------------------------------------
1901 //
1902 // Function: EplNmtMnuProcessInternalEvent
1903 //
1904 // Description: processes internal node events
1905 //
1906 // Parameters: uiNodeId_p = node ID
1907 // NodeNmtState_p = NMT state of CN
1908 // NodeEvent_p = occured events
1909 //
1910 // Returns: tEplKernel = error code
1911 //
1912 //
1913 // State:
1914 //
1915 //---------------------------------------------------------------------------
1916
EplNmtMnuProcessInternalEvent(unsigned int uiNodeId_p,tEplNmtState NodeNmtState_p,WORD wErrorCode_p,tEplNmtMnuIntNodeEvent NodeEvent_p)1917 static tEplKernel EplNmtMnuProcessInternalEvent(unsigned int uiNodeId_p,
1918 tEplNmtState NodeNmtState_p,
1919 WORD wErrorCode_p,
1920 tEplNmtMnuIntNodeEvent
1921 NodeEvent_p)
1922 {
1923 tEplKernel Ret = kEplSuccessful;
1924 tEplNmtState NmtState;
1925 tEplNmtMnuNodeInfo *pNodeInfo;
1926 tEplTimerArg TimerArg;
1927
1928 pNodeInfo = EPL_NMTMNU_GET_NODEINFO(uiNodeId_p);
1929 NmtState = EplNmtuGetNmtState();
1930 if (NmtState <= kEplNmtMsNotActive) { // MN is not active
1931 goto Exit;
1932 }
1933
1934 switch (NodeEvent_p) {
1935 case kEplNmtMnuIntNodeEventIdentResponse:
1936 {
1937 BYTE bNmtState;
1938
1939 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
1940 uiNodeId_p,
1941 pNodeInfo->m_NodeState);
1942
1943 if (pNodeInfo->m_NodeState !=
1944 kEplNmtMnuNodeStateResetConf) {
1945 pNodeInfo->m_NodeState =
1946 kEplNmtMnuNodeStateIdentified;
1947 }
1948 // reset flags ISOCHRON and NMT_CMD_ISSUED
1949 pNodeInfo->m_wFlags &= ~(EPL_NMTMNU_NODE_FLAG_ISOCHRON
1950 |
1951 EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED);
1952
1953 if ((NmtState == kEplNmtMsPreOperational1)
1954 &&
1955 ((pNodeInfo->
1956 m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) !=
1957 0)) {
1958 // decrement only signal slave count
1959 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
1960 pNodeInfo->m_wFlags &=
1961 ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
1962 }
1963 // update object 0x1F8F NMT_MNNodeExpState_AU8 to PreOp1 (even if local state >= PreOp2)
1964 bNmtState = (BYTE) (kEplNmtCsPreOperational1 & 0xFF);
1965 Ret =
1966 EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState,
1967 1);
1968
1969 // check NMT state of CN
1970 Ret =
1971 EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo,
1972 NodeNmtState_p, wErrorCode_p,
1973 NmtState);
1974 if (Ret != kEplSuccessful) {
1975 if (Ret == kEplReject) {
1976 Ret = kEplSuccessful;
1977 }
1978 break;
1979 }
1980 // request StatusResponse immediately,
1981 // because we want a fast boot-up of CNs
1982 Ret =
1983 EplStatusuRequestStatusResponse(uiNodeId_p,
1984 EplNmtMnuCbStatusResponse);
1985 if (Ret != kEplSuccessful) {
1986 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
1987 uiNodeId_p,
1988 Ret);
1989
1990 if (Ret == kEplInvalidOperation) { // the only situation when this should happen is, when
1991 // StatusResponse was already requested from within
1992 // the StatReq timer event.
1993 // so ignore this error.
1994 Ret = kEplSuccessful;
1995 } else {
1996 break;
1997 }
1998 }
1999
2000 if (pNodeInfo->m_NodeState !=
2001 kEplNmtMnuNodeStateResetConf) {
2002 // inform application
2003 Ret =
2004 EplNmtMnuInstance_g.
2005 m_pfnCbNodeEvent(uiNodeId_p,
2006 kEplNmtNodeEventFound,
2007 NodeNmtState_p,
2008 EPL_E_NO_ERROR,
2009 (pNodeInfo->
2010 m_dwNodeCfg &
2011 EPL_NODEASSIGN_MANDATORY_CN)
2012 != 0);
2013 if (Ret == kEplReject) { // interrupt boot process on user request
2014 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2015 (NodeEvent_p, uiNodeId_p,
2016 ((pNodeInfo->m_NodeState << 8)
2017 | Ret));
2018
2019 Ret = kEplSuccessful;
2020 break;
2021 } else if (Ret != kEplSuccessful) {
2022 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2023 (NodeEvent_p, uiNodeId_p,
2024 ((pNodeInfo->m_NodeState << 8)
2025 | Ret));
2026
2027 break;
2028 }
2029 }
2030 // continue BootStep1
2031 }
2032
2033 case kEplNmtMnuIntNodeEventBoot:
2034 {
2035
2036 // $$$ check identification (vendor ID, product code, revision no, serial no)
2037
2038 if (pNodeInfo->m_NodeState ==
2039 kEplNmtMnuNodeStateIdentified) {
2040 // $$$ check software
2041
2042 // check/start configuration
2043 // inform application
2044 Ret =
2045 EplNmtMnuInstance_g.
2046 m_pfnCbNodeEvent(uiNodeId_p,
2047 kEplNmtNodeEventCheckConf,
2048 NodeNmtState_p,
2049 EPL_E_NO_ERROR,
2050 (pNodeInfo->
2051 m_dwNodeCfg &
2052 EPL_NODEASSIGN_MANDATORY_CN)
2053 != 0);
2054 if (Ret == kEplReject) { // interrupt boot process on user request
2055 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2056 (kEplNmtMnuIntNodeEventBoot,
2057 uiNodeId_p,
2058 ((pNodeInfo->m_NodeState << 8)
2059 | Ret));
2060
2061 Ret = kEplSuccessful;
2062 break;
2063 } else if (Ret != kEplSuccessful) {
2064 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2065 (kEplNmtMnuIntNodeEventBoot,
2066 uiNodeId_p,
2067 ((pNodeInfo->m_NodeState << 8)
2068 | Ret));
2069
2070 break;
2071 }
2072 } else if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf) { // wrong CN state
2073 // ignore event
2074 break;
2075 }
2076 // $$$ d.k.: currently we assume configuration is OK
2077
2078 // continue BootStep1
2079 }
2080
2081 case kEplNmtMnuIntNodeEventConfigured:
2082 {
2083 if ((pNodeInfo->m_NodeState !=
2084 kEplNmtMnuNodeStateIdentified)
2085 && (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateResetConf)) { // wrong CN state
2086 // ignore event
2087 break;
2088 }
2089
2090 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateConfigured;
2091
2092 if (NmtState == kEplNmtMsPreOperational1) {
2093 if ((pNodeInfo->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // decrement mandatory CN counter
2094 EplNmtMnuInstance_g.
2095 m_uiMandatorySlaveCount--;
2096 }
2097 } else {
2098 // put optional node to next step (BootStep2)
2099 Ret =
2100 EplNmtMnuNodeBootStep2(uiNodeId_p,
2101 pNodeInfo);
2102 }
2103 break;
2104 }
2105
2106 case kEplNmtMnuIntNodeEventNoIdentResponse:
2107 {
2108 if ((NmtState == kEplNmtMsPreOperational1)
2109 &&
2110 ((pNodeInfo->
2111 m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) !=
2112 0)) {
2113 // decrement only signal slave count
2114 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2115 pNodeInfo->m_wFlags &=
2116 ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2117 }
2118
2119 if (pNodeInfo->m_NodeState !=
2120 kEplNmtMnuNodeStateResetConf) {
2121 pNodeInfo->m_NodeState =
2122 kEplNmtMnuNodeStateUnknown;
2123 }
2124 // $$$ d.k. check start time for 0x1F89/2 MNTimeoutPreOp1_U32
2125 // $$$ d.k. check individual timeout 0x1F89/6 MNIdentificationTimeout_U32
2126 // if mandatory node and timeout elapsed -> halt boot procedure
2127 // trigger IdentRequest again (if >= PreOp2, after delay)
2128 if (NmtState >= kEplNmtMsPreOperational2) { // start timer
2129 EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ
2130 (pNodeInfo, uiNodeId_p, TimerArg);
2131 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
2132 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_IDENTREQ | uiNodeId_p;
2133 /*
2134 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventNoIdentResponse,
2135 uiNodeId_p,
2136 ((pNodeInfo->m_NodeState << 8)
2137 | 0x80
2138 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
2139 | ((TimerArg.m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
2140 */
2141 Ret =
2142 EplTimeruModifyTimerMs(&pNodeInfo->
2143 m_TimerHdlStatReq,
2144 EplNmtMnuInstance_g.
2145 m_ulStatusRequestDelay,
2146 TimerArg);
2147 } else { // trigger IdentRequest immediately
2148 Ret =
2149 EplIdentuRequestIdentResponse(uiNodeId_p,
2150 EplNmtMnuCbIdentResponse);
2151 }
2152 break;
2153 }
2154
2155 case kEplNmtMnuIntNodeEventStatusResponse:
2156 {
2157 if ((NmtState >= kEplNmtMsPreOperational2)
2158 &&
2159 ((pNodeInfo->
2160 m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) !=
2161 0)) {
2162 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2163 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2164 pNodeInfo->m_wFlags &=
2165 ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2166 }
2167 // check NMT state of CN
2168 Ret =
2169 EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo,
2170 NodeNmtState_p, wErrorCode_p,
2171 NmtState);
2172 if (Ret != kEplSuccessful) {
2173 if (Ret == kEplReject) {
2174 Ret = kEplSuccessful;
2175 }
2176 break;
2177 }
2178
2179 if (NmtState == kEplNmtMsPreOperational1) {
2180 // request next StatusResponse immediately
2181 Ret =
2182 EplStatusuRequestStatusResponse(uiNodeId_p,
2183 EplNmtMnuCbStatusResponse);
2184 if (Ret != kEplSuccessful) {
2185 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2186 (NodeEvent_p, uiNodeId_p, Ret);
2187 }
2188
2189 } else if ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_ISOCHRON) == 0) { // start timer
2190 // not isochronously accessed CN (e.g. async-only or stopped CN)
2191 EPL_NMTMNU_SET_FLAGS_TIMERARG_STATREQ(pNodeInfo,
2192 uiNodeId_p,
2193 TimerArg);
2194 // TimerArg.m_EventSink = kEplEventSinkNmtMnu;
2195 // TimerArg.m_ulArg = EPL_NMTMNU_TIMERARG_STATREQ | uiNodeId_p;
2196 /*
2197 EPL_NMTMNU_DBG_POST_TRACE_VALUE(kEplNmtMnuIntNodeEventStatusResponse,
2198 uiNodeId_p,
2199 ((pNodeInfo->m_NodeState << 8)
2200 | 0x80
2201 | ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_COUNT_STATREQ) >> 6)
2202 | ((TimerArg.m_ulArg & EPL_NMTMNU_TIMERARG_COUNT_SR) >> 8)));
2203 */
2204 Ret =
2205 EplTimeruModifyTimerMs(&pNodeInfo->
2206 m_TimerHdlStatReq,
2207 EplNmtMnuInstance_g.
2208 m_ulStatusRequestDelay,
2209 TimerArg);
2210 }
2211
2212 break;
2213 }
2214
2215 case kEplNmtMnuIntNodeEventNoStatusResponse:
2216 {
2217 // function CheckNmtState sets node state to unknown if necessary
2218 /*
2219 if ((NmtState >= kEplNmtMsPreOperational2)
2220 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2221 {
2222 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2223 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2224 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2225 }
2226 */
2227 // check NMT state of CN
2228 Ret =
2229 EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo,
2230 NodeNmtState_p, wErrorCode_p,
2231 NmtState);
2232 if (Ret != kEplSuccessful) {
2233 if (Ret == kEplReject) {
2234 Ret = kEplSuccessful;
2235 }
2236 break;
2237 }
2238
2239 break;
2240 }
2241
2242 case kEplNmtMnuIntNodeEventError:
2243 { // currently only issued on kEplNmtNodeCommandConfErr
2244
2245 if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified) { // wrong CN state
2246 // ignore event
2247 break;
2248 }
2249 // check NMT state of CN
2250 Ret =
2251 EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo,
2252 kEplNmtCsNotActive,
2253 wErrorCode_p, NmtState);
2254 if (Ret != kEplSuccessful) {
2255 if (Ret == kEplReject) {
2256 Ret = kEplSuccessful;
2257 }
2258 break;
2259 }
2260
2261 break;
2262 }
2263
2264 case kEplNmtMnuIntNodeEventExecReset:
2265 {
2266 if (pNodeInfo->m_NodeState != kEplNmtMnuNodeStateIdentified) { // wrong CN state
2267 // ignore event
2268 break;
2269 }
2270
2271 pNodeInfo->m_NodeState = kEplNmtMnuNodeStateResetConf;
2272
2273 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2274 uiNodeId_p,
2275 (((NodeNmtState_p &
2276 0xFF) << 8)
2277 |
2278 kEplNmtCmdResetConfiguration));
2279
2280 // send NMT reset configuration to CN for activation of configuration
2281 Ret =
2282 EplNmtMnuSendNmtCommand(uiNodeId_p,
2283 kEplNmtCmdResetConfiguration);
2284
2285 break;
2286 }
2287
2288 case kEplNmtMnuIntNodeEventHeartbeat:
2289 {
2290 /*
2291 if ((NmtState >= kEplNmtMsPreOperational2)
2292 && ((pNodeInfo->m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0))
2293 {
2294 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2295 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2296 pNodeInfo->m_wFlags &= ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2297 }
2298 */
2299 // check NMT state of CN
2300 Ret =
2301 EplNmtMnuCheckNmtState(uiNodeId_p, pNodeInfo,
2302 NodeNmtState_p, wErrorCode_p,
2303 NmtState);
2304 if (Ret != kEplSuccessful) {
2305 if (Ret == kEplReject) {
2306 Ret = kEplSuccessful;
2307 }
2308 break;
2309 }
2310
2311 break;
2312 }
2313
2314 case kEplNmtMnuIntNodeEventTimerIdentReq:
2315 {
2316 EPL_DBGLVL_NMTMN_TRACE1
2317 ("TimerStatReq->IdentReq(%02X)\n", uiNodeId_p);
2318 // trigger IdentRequest again
2319 Ret =
2320 EplIdentuRequestIdentResponse(uiNodeId_p,
2321 EplNmtMnuCbIdentResponse);
2322 if (Ret != kEplSuccessful) {
2323 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2324 uiNodeId_p,
2325 (((NodeNmtState_p & 0xFF) << 8)
2326 | Ret));
2327 if (Ret == kEplInvalidOperation) { // this can happen because of a bug in EplTimeruLinuxKernel.c
2328 // so ignore this error.
2329 Ret = kEplSuccessful;
2330 }
2331 }
2332
2333 break;
2334 }
2335
2336 case kEplNmtMnuIntNodeEventTimerStateMon:
2337 {
2338 // reset NMT state change flag
2339 // because from now on the CN must have the correct NMT state
2340 pNodeInfo->m_wFlags &=
2341 ~EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED;
2342
2343 // continue with normal StatReq processing
2344 }
2345
2346 case kEplNmtMnuIntNodeEventTimerStatReq:
2347 {
2348 EPL_DBGLVL_NMTMN_TRACE1("TimerStatReq->StatReq(%02X)\n",
2349 uiNodeId_p);
2350 // request next StatusResponse
2351 Ret =
2352 EplStatusuRequestStatusResponse(uiNodeId_p,
2353 EplNmtMnuCbStatusResponse);
2354 if (Ret != kEplSuccessful) {
2355 EPL_NMTMNU_DBG_POST_TRACE_VALUE(NodeEvent_p,
2356 uiNodeId_p,
2357 (((NodeNmtState_p & 0xFF) << 8)
2358 | Ret));
2359 if (Ret == kEplInvalidOperation) { // the only situation when this should happen is, when
2360 // StatusResponse was already requested while processing
2361 // event IdentResponse.
2362 // so ignore this error.
2363 Ret = kEplSuccessful;
2364 }
2365 }
2366
2367 break;
2368 }
2369
2370 case kEplNmtMnuIntNodeEventTimerLonger:
2371 {
2372 switch (pNodeInfo->m_NodeState) {
2373 case kEplNmtMnuNodeStateConfigured:
2374 { // node should be ReadyToOp but it is not
2375
2376 // check NMT state which shall be intentionally wrong, so that ERROR_TREATMENT will be started
2377 Ret =
2378 EplNmtMnuCheckNmtState(uiNodeId_p,
2379 pNodeInfo,
2380 kEplNmtCsNotActive,
2381 EPL_E_NMT_BPO2,
2382 NmtState);
2383 if (Ret != kEplSuccessful) {
2384 if (Ret == kEplReject) {
2385 Ret = kEplSuccessful;
2386 }
2387 break;
2388 }
2389
2390 break;
2391 }
2392
2393 case kEplNmtMnuNodeStateReadyToOp:
2394 { // CheckCom finished successfully
2395
2396 pNodeInfo->m_NodeState =
2397 kEplNmtMnuNodeStateComChecked;
2398
2399 if ((pNodeInfo->
2400 m_wFlags &
2401 EPL_NMTMNU_NODE_FLAG_NOT_SCANNED)
2402 != 0) {
2403 // decrement only signal slave count if checked once for ReadyToOp, CheckCom, Operational
2404 EplNmtMnuInstance_g.
2405 m_uiSignalSlaveCount--;
2406 pNodeInfo->m_wFlags &=
2407 ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2408 }
2409
2410 if ((pNodeInfo->
2411 m_dwNodeCfg &
2412 EPL_NODEASSIGN_MANDATORY_CN) !=
2413 0) {
2414 // decrement mandatory slave counter
2415 EplNmtMnuInstance_g.
2416 m_uiMandatorySlaveCount--;
2417 }
2418 if (NmtState != kEplNmtMsReadyToOperate) {
2419 EPL_NMTMNU_DBG_POST_TRACE_VALUE
2420 (NodeEvent_p, uiNodeId_p,
2421 (((NodeNmtState_p & 0xFF)
2422 << 8)
2423 | kEplNmtCmdStartNode));
2424
2425 // start optional CN
2426 Ret =
2427 EplNmtMnuSendNmtCommand
2428 (uiNodeId_p,
2429 kEplNmtCmdStartNode);
2430 }
2431 break;
2432 }
2433
2434 default:
2435 {
2436 break;
2437 }
2438 }
2439 break;
2440 }
2441
2442 case kEplNmtMnuIntNodeEventNmtCmdSent:
2443 {
2444 BYTE bNmtState;
2445
2446 // update expected NMT state with the one that results
2447 // from the sent NMT command
2448 bNmtState = (BYTE) (NodeNmtState_p & 0xFF);
2449
2450 // write object 0x1F8F NMT_MNNodeExpState_AU8
2451 Ret =
2452 EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState,
2453 1);
2454 if (Ret != kEplSuccessful) {
2455 goto Exit;
2456 }
2457
2458 if (NodeNmtState_p == kEplNmtCsNotActive) { // restart processing with IdentRequest
2459 EPL_NMTMNU_SET_FLAGS_TIMERARG_IDENTREQ
2460 (pNodeInfo, uiNodeId_p, TimerArg);
2461 } else { // monitor NMT state change with StatusRequest after
2462 // the corresponding delay;
2463 // until then wrong NMT states will be ignored
2464 EPL_NMTMNU_SET_FLAGS_TIMERARG_STATE_MON
2465 (pNodeInfo, uiNodeId_p, TimerArg);
2466
2467 // set NMT state change flag
2468 pNodeInfo->m_wFlags |=
2469 EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED;
2470 }
2471
2472 Ret =
2473 EplTimeruModifyTimerMs(&pNodeInfo->
2474 m_TimerHdlStatReq,
2475 EplNmtMnuInstance_g.
2476 m_ulStatusRequestDelay,
2477 TimerArg);
2478
2479 // finish processing, because NmtState_p is the expected and not the current state
2480 goto Exit;
2481 }
2482
2483 default:
2484 {
2485 break;
2486 }
2487 }
2488
2489 // check if network is ready to change local NMT state and this was not done before
2490 if ((EplNmtMnuInstance_g.m_wFlags & (EPL_NMTMNU_FLAG_HALTED | EPL_NMTMNU_FLAG_APP_INFORMED)) == 0) { // boot process is not halted
2491 switch (NmtState) {
2492 case kEplNmtMsPreOperational1:
2493 {
2494 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount ==
2495 0)
2496 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all optional CNs scanned once and all mandatory CNs configured successfully
2497 EplNmtMnuInstance_g.m_wFlags |=
2498 EPL_NMTMNU_FLAG_APP_INFORMED;
2499 // inform application
2500 Ret =
2501 EplNmtMnuInstance_g.
2502 m_pfnCbBootEvent
2503 (kEplNmtBootEventBootStep1Finish,
2504 NmtState, EPL_E_NO_ERROR);
2505 if (Ret != kEplSuccessful) {
2506 if (Ret == kEplReject) {
2507 // wait for application
2508 Ret = kEplSuccessful;
2509 }
2510 break;
2511 }
2512 // enter PreOp2
2513 Ret =
2514 EplNmtuNmtEvent
2515 (kEplNmtEventAllMandatoryCNIdent);
2516 }
2517 break;
2518 }
2519
2520 case kEplNmtMsPreOperational2:
2521 {
2522 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount ==
2523 0)
2524 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all optional CNs checked once for ReadyToOp and all mandatory CNs are ReadyToOp
2525 EplNmtMnuInstance_g.m_wFlags |=
2526 EPL_NMTMNU_FLAG_APP_INFORMED;
2527 // inform application
2528 Ret =
2529 EplNmtMnuInstance_g.
2530 m_pfnCbBootEvent
2531 (kEplNmtBootEventBootStep2Finish,
2532 NmtState, EPL_E_NO_ERROR);
2533 if (Ret != kEplSuccessful) {
2534 if (Ret == kEplReject) {
2535 // wait for application
2536 Ret = kEplSuccessful;
2537 }
2538 break;
2539 }
2540 // enter ReadyToOp
2541 Ret =
2542 EplNmtuNmtEvent
2543 (kEplNmtEventEnterReadyToOperate);
2544 }
2545 break;
2546 }
2547
2548 case kEplNmtMsReadyToOperate:
2549 {
2550 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount ==
2551 0)
2552 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all CNs checked for errorless communication
2553 EplNmtMnuInstance_g.m_wFlags |=
2554 EPL_NMTMNU_FLAG_APP_INFORMED;
2555 // inform application
2556 Ret =
2557 EplNmtMnuInstance_g.
2558 m_pfnCbBootEvent
2559 (kEplNmtBootEventCheckComFinish,
2560 NmtState, EPL_E_NO_ERROR);
2561 if (Ret != kEplSuccessful) {
2562 if (Ret == kEplReject) {
2563 // wait for application
2564 Ret = kEplSuccessful;
2565 }
2566 break;
2567 }
2568 // enter Operational
2569 Ret =
2570 EplNmtuNmtEvent
2571 (kEplNmtEventEnterMsOperational);
2572 }
2573 break;
2574 }
2575
2576 case kEplNmtMsOperational:
2577 {
2578 if ((EplNmtMnuInstance_g.m_uiSignalSlaveCount ==
2579 0)
2580 && (EplNmtMnuInstance_g.m_uiMandatorySlaveCount == 0)) { // all optional CNs scanned once and all mandatory CNs are OPERATIONAL
2581 EplNmtMnuInstance_g.m_wFlags |=
2582 EPL_NMTMNU_FLAG_APP_INFORMED;
2583 // inform application
2584 Ret =
2585 EplNmtMnuInstance_g.
2586 m_pfnCbBootEvent
2587 (kEplNmtBootEventOperational,
2588 NmtState, EPL_E_NO_ERROR);
2589 if (Ret != kEplSuccessful) {
2590 if (Ret == kEplReject) {
2591 // ignore error code
2592 Ret = kEplSuccessful;
2593 }
2594 break;
2595 }
2596 }
2597 break;
2598 }
2599
2600 default:
2601 {
2602 break;
2603 }
2604 }
2605 }
2606
2607 Exit:
2608 return Ret;
2609 }
2610
2611 //---------------------------------------------------------------------------
2612 //
2613 // Function: EplNmtMnuCheckNmtState
2614 //
2615 // Description: checks the NMT state, i.e. evaluates it with object 0x1F8F
2616 // NMT_MNNodeExpState_AU8 and updates object 0x1F8E
2617 // NMT_MNNodeCurrState_AU8.
2618 // It manipulates m_NodeState in internal node info structure.
2619 //
2620 // Parameters: uiNodeId_p = node ID
2621 // NodeNmtState_p = NMT state of CN
2622 //
2623 // Returns: tEplKernel = error code
2624 // kEplReject = CN was in wrong state and has been reset
2625 //
2626 // State:
2627 //
2628 //---------------------------------------------------------------------------
2629
EplNmtMnuCheckNmtState(unsigned int uiNodeId_p,tEplNmtMnuNodeInfo * pNodeInfo_p,tEplNmtState NodeNmtState_p,WORD wErrorCode_p,tEplNmtState LocalNmtState_p)2630 static tEplKernel EplNmtMnuCheckNmtState(unsigned int uiNodeId_p,
2631 tEplNmtMnuNodeInfo * pNodeInfo_p,
2632 tEplNmtState NodeNmtState_p,
2633 WORD wErrorCode_p,
2634 tEplNmtState LocalNmtState_p)
2635 {
2636 tEplKernel Ret = kEplSuccessful;
2637 tEplObdSize ObdSize;
2638 BYTE bNmtState;
2639 BYTE bNmtStatePrev;
2640 tEplNmtState ExpNmtState;
2641
2642 ObdSize = 1;
2643 // read object 0x1F8F NMT_MNNodeExpState_AU8
2644 Ret = EplObduReadEntry(0x1F8F, uiNodeId_p, &bNmtState, &ObdSize);
2645 if (Ret != kEplSuccessful) {
2646 goto Exit;
2647 }
2648 // compute expected NMT state
2649 ExpNmtState = (tEplNmtState) (bNmtState | EPL_NMT_TYPE_CS);
2650 // compute BYTE of current NMT state
2651 bNmtState = ((BYTE) NodeNmtState_p & 0xFF);
2652
2653 if (ExpNmtState == kEplNmtCsNotActive) { // ignore the current state, because the CN shall be not active
2654 Ret = kEplReject;
2655 goto Exit;
2656 } else if ((ExpNmtState == kEplNmtCsPreOperational2)
2657 && (NodeNmtState_p == kEplNmtCsReadyToOperate)) { // CN switched to ReadyToOp
2658 // delete timer for timeout handling
2659 Ret = EplTimeruDeleteTimer(&pNodeInfo_p->m_TimerHdlLonger);
2660 if (Ret != kEplSuccessful) {
2661 goto Exit;
2662 }
2663 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateReadyToOp;
2664
2665 // update object 0x1F8F NMT_MNNodeExpState_AU8 to ReadyToOp
2666 Ret = EplObduWriteEntry(0x1F8F, uiNodeId_p, &bNmtState, 1);
2667 if (Ret != kEplSuccessful) {
2668 goto Exit;
2669 }
2670
2671 if ((pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN -> decrement counter
2672 EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2673 }
2674 if (LocalNmtState_p >= kEplNmtMsReadyToOperate) { // start procedure CheckCommunication for this node
2675 Ret = EplNmtMnuNodeCheckCom(uiNodeId_p, pNodeInfo_p);
2676 if (Ret != kEplSuccessful) {
2677 goto Exit;
2678 }
2679
2680 if ((LocalNmtState_p == kEplNmtMsOperational)
2681 && (pNodeInfo_p->m_NodeState ==
2682 kEplNmtMnuNodeStateComChecked)) {
2683 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0, uiNodeId_p,
2684 (((NodeNmtState_p & 0xFF) << 8)
2685 |
2686 kEplNmtCmdStartNode));
2687
2688 // immediately start optional CN, because communication is always OK (e.g. async-only CN)
2689 Ret =
2690 EplNmtMnuSendNmtCommand(uiNodeId_p,
2691 kEplNmtCmdStartNode);
2692 if (Ret != kEplSuccessful) {
2693 goto Exit;
2694 }
2695 }
2696 }
2697
2698 } else if ((ExpNmtState == kEplNmtCsReadyToOperate)
2699 && (NodeNmtState_p == kEplNmtCsOperational)) { // CN switched to OPERATIONAL
2700 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateOperational;
2701
2702 if ((pNodeInfo_p->m_dwNodeCfg & EPL_NODEASSIGN_MANDATORY_CN) != 0) { // node is a mandatory CN -> decrement counter
2703 EplNmtMnuInstance_g.m_uiMandatorySlaveCount--;
2704 }
2705
2706 } else if ((ExpNmtState != NodeNmtState_p)
2707 && !((ExpNmtState == kEplNmtCsPreOperational1)
2708 && (NodeNmtState_p == kEplNmtCsPreOperational2))) { // CN is not in expected NMT state (without the exceptions above)
2709 WORD wbeErrorCode;
2710
2711 if ((pNodeInfo_p->
2712 m_wFlags & EPL_NMTMNU_NODE_FLAG_NOT_SCANNED) != 0) {
2713 // decrement only signal slave count if checked once
2714 EplNmtMnuInstance_g.m_uiSignalSlaveCount--;
2715 pNodeInfo_p->m_wFlags &=
2716 ~EPL_NMTMNU_NODE_FLAG_NOT_SCANNED;
2717 }
2718
2719 if (pNodeInfo_p->m_NodeState == kEplNmtMnuNodeStateUnknown) { // CN is already in state unknown, which means that it got
2720 // NMT reset command earlier
2721 goto Exit;
2722 }
2723 // -> CN is in wrong NMT state
2724 pNodeInfo_p->m_NodeState = kEplNmtMnuNodeStateUnknown;
2725
2726 if (wErrorCode_p == 0) { // assume wrong NMT state error
2727 if ((pNodeInfo_p->m_wFlags & EPL_NMTMNU_NODE_FLAG_NMT_CMD_ISSUED) != 0) { // NMT command has been just issued;
2728 // ignore wrong NMT state until timer expires;
2729 // other errors like LOSS_PRES_TH are still processed
2730 goto Exit;
2731 }
2732
2733 wErrorCode_p = EPL_E_NMT_WRONG_STATE;
2734 }
2735
2736 BENCHMARK_MOD_07_TOGGLE(9);
2737
2738 // $$$ start ERROR_TREATMENT and inform application
2739 Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
2740 kEplNmtNodeEventError,
2741 NodeNmtState_p,
2742 wErrorCode_p,
2743 (pNodeInfo_p->
2744 m_dwNodeCfg &
2745 EPL_NODEASSIGN_MANDATORY_CN)
2746 != 0);
2747 if (Ret != kEplSuccessful) {
2748 goto Exit;
2749 }
2750
2751 EPL_NMTMNU_DBG_POST_TRACE_VALUE(0,
2752 uiNodeId_p,
2753 (((NodeNmtState_p & 0xFF) << 8)
2754 | kEplNmtCmdResetNode));
2755
2756 // reset CN
2757 // store error code in NMT command data for diagnostic purpose
2758 AmiSetWordToLe(&wbeErrorCode, wErrorCode_p);
2759 Ret =
2760 EplNmtMnuSendNmtCommandEx(uiNodeId_p, kEplNmtCmdResetNode,
2761 &wbeErrorCode,
2762 sizeof(wbeErrorCode));
2763 if (Ret == kEplSuccessful) {
2764 Ret = kEplReject;
2765 }
2766
2767 goto Exit;
2768 }
2769 // check if NMT_MNNodeCurrState_AU8 has to be changed
2770 ObdSize = 1;
2771 Ret = EplObduReadEntry(0x1F8E, uiNodeId_p, &bNmtStatePrev, &ObdSize);
2772 if (Ret != kEplSuccessful) {
2773 goto Exit;
2774 }
2775 if (bNmtState != bNmtStatePrev) {
2776 // update object 0x1F8E NMT_MNNodeCurrState_AU8
2777 Ret = EplObduWriteEntry(0x1F8E, uiNodeId_p, &bNmtState, 1);
2778 if (Ret != kEplSuccessful) {
2779 goto Exit;
2780 }
2781 Ret = EplNmtMnuInstance_g.m_pfnCbNodeEvent(uiNodeId_p,
2782 kEplNmtNodeEventNmtState,
2783 NodeNmtState_p,
2784 wErrorCode_p,
2785 (pNodeInfo_p->
2786 m_dwNodeCfg &
2787 EPL_NODEASSIGN_MANDATORY_CN)
2788 != 0);
2789 if (Ret != kEplSuccessful) {
2790 goto Exit;
2791 }
2792 }
2793
2794 Exit:
2795 return Ret;
2796 }
2797
2798 //---------------------------------------------------------------------------
2799 //
2800 // Function: EplNmtMnuReset
2801 //
2802 // Description: reset internal structures, e.g. timers
2803 //
2804 // Parameters: void
2805 //
2806 // Returns: tEplKernel = error code
2807 //
2808 // State:
2809 //
2810 //---------------------------------------------------------------------------
2811
EplNmtMnuReset(void)2812 static tEplKernel EplNmtMnuReset(void)
2813 {
2814 tEplKernel Ret;
2815 int iIndex;
2816
2817 Ret = EplTimeruDeleteTimer(&EplNmtMnuInstance_g.m_TimerHdlNmtState);
2818
2819 for (iIndex = 1; iIndex <= tabentries(EplNmtMnuInstance_g.m_aNodeInfo);
2820 iIndex++) {
2821 // delete timer handles
2822 Ret =
2823 EplTimeruDeleteTimer(&EPL_NMTMNU_GET_NODEINFO(iIndex)->
2824 m_TimerHdlStatReq);
2825 Ret =
2826 EplTimeruDeleteTimer(&EPL_NMTMNU_GET_NODEINFO(iIndex)->
2827 m_TimerHdlLonger);
2828 }
2829
2830 return Ret;
2831 }
2832
2833 #endif // #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
2834
2835 // EOF
2836