/*
* co_nmt.c - contains NMT services
*
* Copyright (c) 2012-2024 emotas embedded communication GmbH
*-------------------------------------------------------------------
* $Id: co_nmt.c 54458 2024-06-28 09:15:11Z boe $
*
*
*-------------------------------------------------------------------
*
*
*/

/********************************************************************/
/**
* \brief Network Managment(NMT) handler
*
* \file co_nmt.c
* contains routines for NMT handling
*
*/


/* header of standard C - libraries
---------------------------------------------------------------------------*/
#include <stdlib.h>

/* header of project specific types
---------------------------------------------------------------------------*/
#include <gen_define.h>
#include <co_datatype.h>
#include <co_timer.h>
#include <co_commtask.h>
#include <co_common.h>
#include <co_drv.h>
#include <co_led.h>
#include <co_odaccess.h>
#include <co_store.h>
#include <co_nmt.h>
#include <co_sdo.h>
#include <co_pdo.h>
#include "ico_common.h"
#include "ico_cobhandler.h"
#include "ico_queue.h"
#include "ico_event.h"
#include "ico_indication.h"
#include "ico_sdoserver.h"
#include "ico_sdoclient.h"
#include "ico_pdo.h"
#include "ico_nmt.h"
#include "ico_sync.h"
#include "ico_emcy.h"
#include "ico_odaccess.h"
#include "ico_time.h"
#include "ico_store.h"
#ifdef CO_LSS_SUPPORTED
# include "ico_lss.h"
#endif /* CO_LSS_SUPPORTED */
#ifdef CO_LSS_MASTER_SUPPORTED
# include "ico_lss.h"
#endif /* CO_LSS_MASTER_SUPPORTED */
#ifdef CO_EVENT_SLEEP
# include "ico_sleep.h"
#endif /* CO_EVENT_SLEEP */
#ifdef CO_SRD_SUPPORTED
# include "ico_srd.h"
#endif /* CO_SRD_SUPPORTED */
#ifdef CO_NETWORK_ROUTING_CNT
# include "ico_network.h"
#endif /* CO_NETWORK_ROUTING_CNT */
#ifdef CO_GFC_SUPPORTED
# include "ico_gfc.h"
#endif /* CO_GFC_SUPPORTED */
#ifdef CO_SRDO_SUPPORTED
# include "ico_srdo.h"
#endif /* CO_SRDO_SUPPORTED */
#ifdef CO_IDNEGO_SUPPORTED
# include "ico_idnego.h"
#endif /* CO_IDNEGO_SUPPORTED */


/* constant definitions
---------------------------------------------------------------------------*/


/* local defined data types
---------------------------------------------------------------------------*/

/* list of external used functions, if not in headers
---------------------------------------------------------------------------*/
#ifdef CO_EVENT_STATIC_NMT
extern CO_CONST CO_EVENT_NMT_T coEventNmtInd;
#endif /* CO_EVENT_STATIC_NMT */


/* list of global defined functions
---------------------------------------------------------------------------*/

/* list of local defined functions
---------------------------------------------------------------------------*/
static void nmtReset(CO_LINE_DECL);
static RET_T nmtResetComm(CO_LINE_DECL);
static void nmtResetAppl(CO_LINE_DECL);

/* external variables
---------------------------------------------------------------------------*/

/* global variables
---------------------------------------------------------------------------*/

/* local defined variables
---------------------------------------------------------------------------*/
static UNSIGNED8		nodeId[CO_LINE_ARRAY_DECL] = { 127u };
static CO_NMT_STATE_T	nmtState[CO_LINE_ARRAY_DECL] = {CO_NMT_STATE_RESET_NODE};
#ifdef CO_EVENT_NMT_CNT
static CO_EVENT_NMT_T	nmtTable[CO_EVENT_NMT_CNT];
static UNSIGNED8		nmtTableCnt = 0u;
#endif /* CO_EVENT_NMT_CNT */
static COB_REFERENZ_T	nmtCob[CO_LINE_ARRAY_DECL];
static UNSIGNED8		persistantNodeId[CO_LINE_ARRAY_DECL];
static CO_NODE_ID_T	nodeIdFunction[CO_LINE_ARRAY_DECL];


/***************************************************************************/
/**
* \internal
*
* \brief coNmtMsgHandler - handle received NMT mesages
*
*
* \return none
*
*/
void icoNmtMsgHandler(
		CO_LINE_TYPE	CO_LINE,
		CO_CONST CO_REC_DATA_T *pNmtRec		/* pointer to receive data */
	)
{
RET_T	retVal;

	/* switch depending on cob-id - start with NMT command */
	if (pNmtRec->msg.canId == 0u)  {

		/* check for correct message len */
		if (pNmtRec->msg.len != 2u)  {
			return;
		}

		/* node id = own node id or = 0 ? */
		if ((pNmtRec->msg.data[1] == nodeId[CO_LINE]) || (pNmtRec->msg.data[1] == 0u))  {
			/* new state command */
			switch (pNmtRec->msg.data[0])  {
				case 1u:
					icoNmtStateChange(CO_LINE, CO_NMT_STATE_OPERATIONAL, CO_TRUE);
					break;
				case 2u:
					icoNmtStateChange(CO_LINE, CO_NMT_STATE_STOPPED, CO_TRUE);
					break;
				case 128u:
					icoNmtStateChange(CO_LINE, CO_NMT_STATE_PREOP, CO_TRUE);
					break;
				case 129u:
					icoNmtStateChange(CO_LINE, CO_NMT_STATE_RESET_NODE, CO_TRUE);
					nmtResetAppl(CO_LINE);
					retVal = nmtResetComm(CO_LINE);
					if (retVal == RET_OK)  {
						icoNmtStateChange(CO_LINE, CO_NMT_STATE_PREOP, CO_TRUE);
					}
					break;
				case 130u:
					retVal = nmtResetComm(CO_LINE);
					if (retVal == RET_OK)  {
						icoNmtStateChange(CO_LINE, CO_NMT_STATE_PREOP, CO_TRUE);
					}
					break;
				default:
					break;
			}
		}
	}

	/* NMT error control message ? */
	if (pNmtRec->msg.canId > 0x700u)  {
		/* check for correct message len */
		if (pNmtRec->msg.len != 1u)  {
			return;
		}

		icoNmtErrorCtrlHandler(CO_LINE, pNmtRec);
	}
}


/***************************************************************************/
/**
* \internal
*
* \brief icoNmtStateChange - setup new state change
*
*
* \return none
*
*/
void icoNmtStateChange(
		CO_LINE_TYPE	CO_LINE,
		CO_NMT_STATE_T	reqState,		/* new requested state */
		BOOL_T			cmdFromMaster	/* command comes from master */
	)
{
RET_T	retVal;
#ifdef CO_EVENT_NMT_CNT
UNSIGNED8			cnt;
#endif /* CO_EVENT_NMT_CNT */

	/* ignore same command */
	if (nmtState[CO_LINE] == reqState)  {
		return;
	}

	/* ignore message if we don't have a node id */
	if ((nodeId[CO_LINE] < 1u) || (nodeId[CO_LINE] > 127u))  {
		return;
	}

	/* no command from master ? */
	if (cmdFromMaster != CO_TRUE)  {
		/* only in state OPERATIONAL allowed */
		if (nmtState[CO_LINE] != CO_NMT_STATE_OPERATIONAL)  {
			return;
		}
	}

#ifdef CO_SRDO_SUPPORTED
	if (reqState == CO_NMT_STATE_OPERATIONAL)  {
		retVal = icoSrdoCheckOperational(CO_LINE);
		if (retVal != RET_OK)  {
			return;
		}
	} else
#endif /* CO_SRDO_SUPPORTED */
	{
		/* normally user indication is ok */
		retVal = RET_OK;
	}


#ifdef CO_EVENT_NMT
	/* only in state OPER the change state can be aborted by user */
	if (reqState == CO_NMT_STATE_OPERATIONAL)  {
		/* check all indications for correct return value */

# ifdef CO_EVENT_NMT_CNT
		cnt = nmtTableCnt;
		while (cnt > 0u)  {
			cnt--;

			/* check user indication */
			retVal = nmtTable[cnt](CO_LINE, CO_FALSE, reqState);
			if (retVal != RET_OK)  {
				break;
			}
		}
# endif /* CO_EVENT_NMT_CNT */

# ifdef CO_EVENT_STATIC_NMT
		if (retVal == RET_OK)  {
			retVal = coEventNmtInd(CO_LINE, CO_FALSE, reqState);
		}
# endif /* CO_EVENT_STATIC_NMT */
	}
#endif /* CO_EVENT_NMT */

	/* execute only if retval was ok */
	if (retVal == RET_OK)  {
		/* set new nmt state */
		nmtState[CO_LINE] = reqState;

#ifdef CO_EVENT_LED
		switch (nmtState[CO_LINE])  {
			case CO_NMT_STATE_PREOP:
				coLedSetGreen(CO_LINE, CO_LED_STATE_BLINKING);
				break;
			case CO_NMT_STATE_OPERATIONAL:
				coLedSetGreen(CO_LINE, CO_LED_STATE_ON);
				break;
			case CO_NMT_STATE_STOPPED:
				coLedSetGreen(CO_LINE, CO_LED_STATE_FLASH_1);
				break;
			default:
				break;
		}
#endif /* CO_EVENT_LED */

#ifdef CO_EVENT_NMT
# ifdef CO_EVENT_NMT_CNT
		/* call all user indications */
		cnt = nmtTableCnt;
		while (cnt > 0u)  {
			cnt--;
			/* call user indication */
			(void)nmtTable[cnt](CO_LINE, CO_TRUE, reqState);
		}
# endif /* CO_EVENT_NMT_CNT */

# ifdef CO_EVENT_STATIC_NMT
		(void)coEventNmtInd(CO_LINE, CO_TRUE, reqState);
# endif /* CO_EVENT_STATIC_NMT */
#endif /* CO_EVENT_NMT */


		/* new state == OPER ? */
		if (reqState == CO_NMT_STATE_OPERATIONAL)  {

#ifdef CO_PDO_TRANSMIT_CNT
			/* transmit async PDOs and start pdo event timer */
			icoPdoOperational(CO_LINE);
#endif /* CO_PDO_TRANSMIT_CNT */

#ifdef CO_SRDO_SUPPORTED
			icoSrdoOperational(CO_LINE);
#endif /* CO_SRDO_SUPPORTED */

		} else {

#ifdef CO_PDO_TRANSMIT_CNT
			/* stop event timers */
			icoPdoPreOperational(CO_LINE);
#endif /* CO_PDO_TRANSMIT_CNT */

#ifdef CO_SRDO_SUPPORTED
			icoSrdoPreOperational(CO_LINE);
#endif /* CO_SRDO_SUPPORTED */

		}
	}
}


#ifdef CO_EVENT_NMT_CNT
/***************************************************************************/
/**
* \brief coEventRegister_NMT - register NMT event
*
* register indication function for NMT events
*
* \return RET_T
*
*/

RET_T coEventRegister_NMT(
		CO_EVENT_NMT_T pFunction	/**< pointer to function */
	)
{
	/* set new indication function as first at the list */
	if (nmtTableCnt >= CO_EVENT_NMT_CNT)  {
		return(RET_EVENT_NO_RESSOURCE);
	}

	nmtTable[nmtTableCnt] = pFunction;	/* save function pointer */
	nmtTableCnt++;

	return(RET_OK);
}
#endif /* CO_EVENT_NMT_CNT */


/***************************************************************************/
/**
* \internal
*
* \brief get persistant node id
*
*
* \return node id
*
*/
UNSIGNED8	icoNmtPersistantNodeIdGet(
		CO_LINE_TYPE	CO_LINE		/* can line */
	)
{
UNSIGNED8	nId;

	if (nodeIdFunction[CO_LINE] != NULL)  {
		nId = nodeIdFunction[CO_LINE](CO_LINE);
	} else {
		nId = persistantNodeId[CO_LINE];
	}

	return(nId);
}


/***************************************************************************/
/**
* \internal
*
* \brief reset application services
*
*
* \return none
*
*/
static void nmtResetAppl(
		CO_LINE_TYPE	CO_LINE		/* can line */
	)
{
	/* init event handler queue */
	icoEventInit();

#ifdef CO_LSS_SUPPORTED
	icoLssResetAppl(CO_LINE);
#endif /* CO_LSS_SUPPORTED */

	icoOdReset(CO_LINE, 0x2000u, 0x9fffu);
	(void)icoStoreLoadReq(CO_LINE, CO_STORE_AREA_APPL);

	coQueueInit(CO_LINE);
}


/***************************************************************************/
/**
* \internal
*
* \brief reset communication parameter and services
*
*
* \return none
*
*/
static RET_T nmtResetComm(
		CO_LINE_TYPE	CO_LINE		/* can line */
	)
{
#ifdef CO_EVENT_SLEEP
# ifdef CO_NMT_MASTER
CO_NMT_MASTER_STATE_T mState = CO_NMT_MASTER_STATE_SLAVE;
# endif /* CO_NMT_MASTER */
#endif /* CO_EVENT_SLEEP */

	nodeId[CO_LINE] = icoNmtPersistantNodeIdGet(CO_LINE);

	/* disable all cobs */
	icoCobDisableAll(CO_LINE, CO_SERVICE_CANOPEN_START, CO_SERVICE_CANOPEN_END);

	nmtReset(CO_LINE);

#ifdef CO_LSS_SUPPORTED
	icoLssReset(CO_LINE, &nodeId[CO_LINE]);
	if (nodeId[CO_LINE] == 255u)  {
# ifdef CO_NO_NODE_ID_LED
		coLedSetGreen(CO_LINE, CO_LED_STATE_FLICKERING);
# endif /* CO_NO_NODE_ID_LED */
		return(RET_INVALID_NODEID);
	}
#endif /* CO_LSS_SUPPORTED */

#ifdef CO_EVENT_SLEEP
# ifdef CO_NMT_MASTER
	mState = icoNmtMasterGetState(CO_LINE);

	if (mState == CO_NMT_MASTER_STATE_MASTER)  {
		icoSleepReset(CO_LINE, 1u, nodeId[CO_LINE]);
	} else
# endif /* CO_NMT_MASTER */
	{
		icoSleepReset(CO_LINE, 0u, nodeId[CO_LINE]);
	}
#endif /* CO_EVENT_SLEEP */

#ifdef CO_IDNEGO_SUPPORTED
	icoIdNegoReset(CO_LINE, &nodeId[CO_LINE]);
#endif /* CO_IDNEGO_SUPPORTED */

	if ((nodeId[CO_LINE] < 1u) || (nodeId[CO_LINE] > 127u))  {
		return(RET_INVALID_NODEID);
	}

	/* reset objcect dictionary */
	icoOdReset(CO_LINE, 0x1000u, 0x1fffu);

	/* setup predefined connection set */

#ifdef CO_SDO_SERVER_CNT
		icoSdoServerSetDefaultValue(CO_LINE);
#endif /* CO_SDO_SERVER_CNT */


#ifdef CO_SDO_CLIENT_CNT
		icoSdoClientSetDefaultValue(CO_LINE);
#endif /*  CO_SDO_CLIENT_CNT */

#if defined(CO_PDO_TRANSMIT_CNT) || defined(CO_PDO_RECEIVE_CNT)
	icoPdoSetDefaultValue(CO_LINE);
#endif /* defined(CO_PDO_TRANSMIT_CNT) || defined(CO_PDO_RECEIVE_CNT) */

	icoErrorCtrlSetDefaultValue(CO_LINE);

#ifdef CO_SYNC_SUPPORTED
	icoSyncSetDefaultValue(CO_LINE);
#endif /* CO_SYNC_SUPPORTED */

#ifdef CO_EMCY_PRODUCER
	icoEmcyProducerSetDefaultValue(CO_LINE);
#endif /* CO_EMCY_PRODUCER */

#ifdef CO_EMCY_CONSUMER_CNT
	icoEmcyConsumerSetDefaultValue(CO_LINE);
#endif /* CO_EMCY_CONSUMER_CNT */

#ifdef CO_TIME_SUPPORTED
	icoTimeSetDefaultValue(CO_LINE);
#endif /* CO_TIME_SUPPORTED */

#if defined(CO_NMT_MASTER) || defined(CO_SELF_STARTING_DEVICE)
	icoNmtSetDefaultValue(CO_LINE);
# ifdef CO_FLYING_MASTER_SUPPORTED
	icoFlymaSetDefaultValue(CO_LINE);
# endif /* # ifdef CO_FLYING_MASTER_SUPPORTED */
#endif /* defined(CO_NMT_MASTER) || defined(CO_SELF_STARTING_DEVICE) */

#ifdef CO_NETWORK_ROUTING_CNT
	icoNetworkSetDefaultValue(CO_LINE);
#endif /* CO_NETWORK_ROUTING_CNT */

#ifdef CO_SRDO_SUPPORTED
	icoSrdoSetDefaultValue(CO_LINE);
#endif /* CO_SRDO_SUPPORTED */

	/* load stored parameter */
	(void)icoStoreLoadReq(CO_LINE, CO_STORE_AREA_COMM);


	/* call reset services */
#ifdef CO_SDO_SERVER_CNT
	icoSdoServerReset(CO_LINE);
#endif /* CO_SDO_SERVER_CNT */


#ifdef CO_SDO_CLIENT_CNT
	icoSdoClientReset(CO_LINE);
#endif /*  CO_SDO_CLIENT_CNT */

#if defined(CO_PDO_TRANSMIT_CNT) || defined(CO_PDO_RECEIVE_CNT)
	icoPdoReset(CO_LINE);
#endif /* defined(CO_PDO_TRANSMIT_CNT) || defined(CO_PDO_RECEIVE_CNT) */

#ifdef CO_SRDO_SUPPORTED
	icoSrdoReset(CO_LINE);
#endif /* CO_SRDO_SUPPORTED */

	icoNmtStateChange(CO_LINE, CO_NMT_STATE_RESET_COMM, CO_TRUE);
	icoNmtStateChange(CO_LINE, CO_NMT_STATE_PREOP, CO_TRUE);
	icoErrorCtrlReset(CO_LINE);

#ifdef CO_SYNC_SUPPORTED
	icoSyncReset(CO_LINE);
#endif /* CO_SYNC_SUPPORTED */

#ifdef CO_EMCY_PRODUCER
	icoEmcyReset(CO_LINE);
#endif /* CO_EMCY_PRODUCER */

#ifdef CO_EMCY_CONSUMER_CNT
	icoEmcyConsumerReset(CO_LINE);
#endif /* CO_EMCY_CONSUMER_CNT */

#ifdef CO_TIME_SUPPORTED
	icoTimeReset(CO_LINE);
#endif /* CO_TIME_SUPPORTED */

#ifdef CO_LSS_MASTER_SUPPORTED
	icoLssMasterReset(CO_LINE);
#endif /* CO_LSS_MASTER_SUPPORTED */

#ifdef CO_NMT_MASTER
	icoNmtMasterReset(CO_LINE);

# ifdef CO_FLYING_MASTER_SUPPORTED
	icoNmtFlymaReset(CO_LINE);
# endif /* CO_FLYING_MASTER_SUPPORTED */
#endif /* CO_NMT_MASTER */

#ifdef CO_STORE_SUPPORTED
# ifdef CO_AUTO_STORE_HANDLED_BY_APPLICATION
	icoStoreReset(CO_LINE);
# endif /* CO_AUTO_STORE_HANDLED_BY_APPLICATION */
#endif /* CO_STORE_SUPPORTED */

#ifdef CO_SRD_SUPPORTED
	icoSrdReset(CO_LINE);
#endif /* CO_SRD_SUPPORTED */

#ifdef CO_GFC_SUPPORTED
	icoGfcReset(CO_LINE);
#endif /* CO_GFC_SUPPORTED */

#ifndef CO_NMT_MASTER
# ifdef CO_SELF_STARTING_DEVICE
	icoNmtApplyObj(CO_LINE);
# endif /* CO_SELF_STARTING_DEVICE */
#endif /* !CO_NMT_MASTER */

	(void)icoHbProdStart(CO_LINE, CO_FALSE);

	return(RET_OK);
}


/***************************************************************************/
/**
*
* \brief coNmtGetNodeId - returns actual node id
*
*
* \return node-id
*
*/
UNSIGNED8 coNmtGetNodeId(
		CO_LINE_TYPE	CO_LINE		/* can line */
	)
{
	return(nodeId[CO_LINE]);
}


/***************************************************************************/
/**
* \internal
*
* \brief icoNmtGetCob - returns nmt cob ident
*
*
* \return COB_REFERENCE_T
*
*/
COB_REFERENZ_T icoNmtGetCob(
		CO_LINE_TYPE	CO_LINE		/* can line */
	)
{
	return(nmtCob[CO_LINE]);
}


#ifdef CO_LSS_SUPPORTED
/***************************************************************************/
/**
* \internal
*
* \brief icoNmtResetNodeId - reset node id to invalid
*
* Set the internal node-id to 255.
* Communication is not more possible until a reset comm was called
*
* \return none
*
*/
void icoNmtResetNodeId(
		CO_LINE_TYPE	CO_LINE		/* can line */
	)
{
UNSIGNED8	node;

	/* only possible for fixed node id == 255 */
	node = icoNmtPersistantNodeIdGet(CO_LINE);
	if (node != 255u)  {
		return;
	}

	nodeId[CO_LINE] = 255u;

	/* disable all cobs */
	icoCobDisableAll(CO_LINE, CO_SERVICE_CANOPEN_START, CO_SERVICE_CANOPEN_END);

	/* enable NMT COB */
	nmtReset(CO_LINE);

	icoLssResetNodeId(CO_LINE);
}
#endif /* CO_LSS_SUPPORTED */


/***************************************************************************/
/**
* \brief coGetNmtState - returns current NMT state
*
* This function returns the current NMT state of the local node.
*
* \return NMT state
*
*/
CO_NMT_STATE_T coNmtGetState(
		CO_LINE_TYPE	CO_LINE		/* can line */
	)
{
	/* for not CANopen lines return always PRE-OP */
	if ((icoProtocolType(CO_LINE) & MP_PROT_TYPE_CANOPEN) == 0u)  {
		return(CO_NMT_STATE_PREOP);
	}

	return(nmtState[CO_LINE]);
}


/***************************************************************************/
/**
* \internal
*
* \brief coResetNmt - reset comm for nmt
*
*
* \return none
*
*/
static void nmtReset(
		CO_LINE_TYPE	CO_LINE		/* can line */
	)
{
#ifdef CO_EVENT_SLEEP
# ifdef CO_NMT_MASTER
CO_NMT_MASTER_STATE_T mState = CO_NMT_MASTER_STATE_SLAVE;
# endif /* CO_NMT_MASTER */
#endif /* CO_EVENT_SLEEP */

	nmtState[CO_LINE] = CO_NMT_STATE_RESET_NODE;

	(void)icoCobSet(CO_LINE, nmtCob[CO_LINE], 0u, CO_COB_RTR_NONE, 2u);

#ifdef CO_EVENT_SLEEP
# ifdef CO_NMT_MASTER
	mState = icoNmtMasterGetState(CO_LINE);

	if (mState == CO_NMT_MASTER_STATE_MASTER)  {
		icoSleepReset(CO_LINE, 1u, 0u);
	} else
# endif /* CO_NMT_MASTER */
	{
		icoSleepReset(CO_LINE, 0u, 0u);
	}
#endif /* CO_EVENT_SLEEP */
}


/***************************************************************************/
/**
*
* \brief coNmtLocalStateReq - request local NMT state change
*
* Be carfule - NMT commands should be generated only by the master
*
* \return RET_T
*
*/
RET_T coNmtLocalStateReq(
		CO_LINE_TYPE	CO_LINE,
		CO_NMT_STATE_T	reqState		/**< new requested state */
	)
{
CO_REC_DATA_T	nmtRec;
UNSIGNED8		cmd;

	switch (reqState)  {
		case CO_NMT_STATE_OPERATIONAL:
			cmd = 1u;
			break;
		case CO_NMT_STATE_STOPPED:
			cmd = 2u;
			break;
		case CO_NMT_STATE_PREOP:
			cmd = 128u;
			break;
		case CO_NMT_STATE_RESET_NODE:
			cmd = 129u;
			break;
		case CO_NMT_STATE_RESET_COMM:
			cmd = 130u;
			break;
		case CO_NMT_STATE_UNKNOWN:
		default:
			return(RET_INVALID_PARAMETER);
	}

	/* simulate command for own node */
	nmtRec.msg.canId = 0u;
	nmtRec.msg.len = 2u;
	nmtRec.msg.data[0] = cmd;
	nmtRec.msg.data[1] = coNmtGetNodeId(CO_LINE);
	icoNmtMsgHandler(CO_LINE, &nmtRec);

	return(RET_OK);
}


/***************************************************************************/
/**
* \internal
*
* \brief icoNmtVarInit - init nmt variables
*
* If node id-function is null, fixed node id from pNodeId is used
*
* \return none
*
*/
void icoNmtVarInit(
		const UNSIGNED8		*pNodeId,
		const CO_NODE_ID_T	*nodeIdFct
	)
{
CO_LINE_TYPE	CO_LINE;

	for (CO_LINE = 0u; CO_LINE < CO_MULTI_LINE_CNT; CO_LINE++)
	{
		nmtCob[CO_LINE] = 0xffffu;
		persistantNodeId[CO_LINE] = pNodeId[CO_LINE];
		nodeIdFunction[CO_LINE] = nodeIdFct[CO_LINE];
		nodeId[CO_LINE] = 127u;
		nmtState[CO_LINE] = CO_NMT_STATE_RESET_NODE;
	}

#ifdef CO_EVENT_NMT_CNT
	nmtTableCnt = 0u;
#endif /* CO_EVENT_NMT_CNT */
}


/***************************************************************************/
/**
* \brief coInitNmt - init NMT functionality
*
* This function initializes the NMT functionality
* and calls an internal reset communication.
*
* If parameter master is unequal 0 the node will be initialized as NMT master.
* If flying master is enabled, the decision for master/slave or flying master
* is done by check object 0x1f80. (parameter master is not used!)
* In this case, the node starts as slave and wait for the master negotiation.
* If the object 0x1f80 is not present, the flying master functionality is not usable.
*
*
* parameter master	flying master supported		object 1f80 present		work as
* 		0					-							-				slave
* 		1					0							-				master
* 		1					1							0				master
* 		1					1							1				flying master
*
* \return RET_T
*
*/
RET_T coNmtInit(
		CO_LINE_TYPE	CO_LINE,
		UNSIGNED8		master			/**< master mode */
	)
{
CO_NMT_MASTER_STATE_T mState;
#ifdef CO_FLYING_MASTER_SUPPORTED
RET_T	retVal;
UNSIGNED32	u32;
#endif /* CO_FLYING_MASTER_SUPPORTED */

	if (master != 0u)  {
#ifdef CO_FLYING_MASTER_SUPPORTED
		/* check if 1f80 is available */
		retVal = coOdGetObj_u32(CO_LINE, 0x1f80u, 0, &u32);
		if (retVal != RET_OK)  {
			/* not avail -> work as master */
			mState = CO_NMT_MASTER_STATE_MASTER;
		} else {
			/* avail -> work as flying master */
			retVal = icoNmtFlymaInit(CO_LINE);
			if (retVal != RET_OK)  {
				return(retVal);
			}
			mState = CO_NMT_MASTER_STATE_POWERON;
		}
#else /* CO_FLYING_MASTER_SUPPORTED */
		mState = CO_NMT_MASTER_STATE_MASTER;
#endif /* CO_FLYING_MASTER_SUPPORTED */
	} else {
		mState = CO_NMT_MASTER_STATE_SLAVE;
	}

	if (mState == CO_NMT_MASTER_STATE_MASTER)  {
		nmtCob[CO_LINE] = icoCobCreate(CO_LINE, CO_COB_TYPE_TRANSMIT, CO_SERVICE_NMT, 0u);
	} else {
		nmtCob[CO_LINE] = icoCobCreate(CO_LINE, CO_COB_TYPE_RECEIVE, CO_SERVICE_NMT, 0u);
	}
	if (nmtCob[CO_LINE] == 0xffffu)  {
		return(RET_NO_COB_AVAILABLE);
	}

#ifdef CO_NMT_MASTER
	icoNmtMasterSetState(CO_LINE, mState);
#endif /* CO_NMT_MASTER */

#ifdef CO_EVENT_SLEEP
	if (icoSleepInit(CO_LINE, master) != RET_OK)  {
		return(RET_NO_COB_AVAILABLE);
	}
#endif /* CO_EVENT_SLEEP */

	nmtResetAppl(CO_LINE);
	(void)nmtResetComm(CO_LINE);

	return(RET_OK);
}
