From 9d7164cfdb611c2f864d535ae5794f23db3d84f7 Mon Sep 17 00:00:00 2001 From: Daniel Krueger Date: Fri, 19 Dec 2008 11:41:57 -0800 Subject: Staging: add epl stack This is the openPOWERLINK network stack from systec electronic. It's a bit messed up as there is a driver mixed into the middle of it, lots of work needs to be done to unwind the different portions to make it sane. Cc: Daniel Krueger Cc: Ronald Sieber Signed-off-by: Greg Kroah-Hartman --- drivers/staging/epl/EplNmtMnu.c | 2798 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 2798 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..80453601a4a --- /dev/null +++ b/drivers/staging/epl/EplNmtMnu.c @@ -0,0 +1,2798 @@ +/**************************************************************************** + + (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