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