/*
* co_sleep.c - contains sleep services
*
* Copyright (c) 2013-2023 emotas embedded communication GmbH
*-------------------------------------------------------------------
* $Id: co_sleep.c 49616 2023-09-26 14:22:08Z boe $
*
*
*-------------------------------------------------------------------
*
*
*/

/********************************************************************/
/**
* \brief Sleep and Wakeup Handling
*
* \file co_sleep.c
* contains routines for sleep/wakeup handling
*
*/


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

/* header of project specific types
---------------------------------------------------------------------------*/
#include <gen_define.h>

#include <co_datatype.h>
#include <co_memcpy.h>
#include <co_timer.h>
#include <co_drv.h>
#include <co_commtask.h>
#include <co_sleep.h>
#include <co_nmt.h>
#include "ico_cobhandler.h"
#include "ico_queue.h"
#include "ico_indication.h"
#include "ico_nmt.h"
#include "ico_sleep.h"

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

#ifdef CO_EVENT_SLEEP

#define CO_SLEEP_MASTER_CAN_ID		0x691u
#define CO_SLEEP_SLAVE_CAN_ID		0x690u
#define CO_SLEEP_REQ_SLEEP_CAN_ID	0x692u

#define CO_SLEEP_CMD_QUERY			0x01u
#define CO_SLEEP_CMD_SLEEP			0x02u
#define CO_SLEEP_STATE_REQ			0x03u
#define CO_SLEEP_STATE_OBJECTION	0x81u

#ifdef CO_SLEEP_447
# ifdef CO_NMT_MASTER
#  define CO_SLEEP_447_CNT	14
# else /* CO_NMT_MASTER */
#  define CO_SLEEP_447_CNT	1
# endif /* CO_NMT_MASTER */

# define CO_SLEEP_447_LAST_NODE	(CO_SLEEP_447_CNT + 2)
#endif /* CO_SLEEP_447 */


#ifndef CO_SLEEP_PREPARE_TIME
# ifdef CO_SLEEP_447
#  define CO_SLEEP_PREPARE_TIME 50u /* 50ms */
# else /* CO_SLEEP_447 */
#  define CO_SLEEP_PREPARE_TIME 1000u /* 1000ms */
# endif /* CO_SLEEP_447 */
#endif /* CO_SLEEP_PREPARE_TIME */


/* local defined data types
---------------------------------------------------------------------------*/
typedef struct {
		UNSIGNED8	status;		/* wake up state */
		UNSIGNED8	reason;		/* wake up reason */
		COB_REFERENZ_T	sleepCob;
} WAKEUP_T;

typedef enum {
	SLEEP_STATE_AWAKE,
	SLEEP_STATE_OBJECTION,
	SLEEP_STATE_SLEEP
#ifdef CO_NMT_MASTER
	, SLEEP_STATE_PREPARE
#endif /* CO_NMT_MASTER */
} SLEEP_STATE_T;

/* list of external used functions, if not in headers
---------------------------------------------------------------------------*/
#ifdef CO_EVENT_STATIC_SLEEP
extern CO_CONST CO_EVENT_SLEEP_T coEventSleepInd;
#endif /* CO_EVENT_STATIC_SLEEP */


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

/* list of local defined functions
---------------------------------------------------------------------------*/
static UNSIGNED8 callSleepInd(CO_LINE_DECL, CO_SLEEP_MODE_T sleepMode, UNSIGNED8 node);
static void sleepSilent(CO_LINE_DECL, void *ptr);
static void sleepDoze(CO_LINE_DECL, void *ptr);
static void sleepWakeUpMessage(CO_LINE_DECL, void *ptr);
#ifdef CO_NMT_MASTER
static void sleepNoObjection(CO_LINE_DECL, void *ptr);
#endif /* CO_NMT_MASTER */

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

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

/* local defined variables
---------------------------------------------------------------------------*/
#ifdef CO_EVENT_SLEEP_CNT
static CO_EVENT_SLEEP_T	sleepTable[CO_EVENT_SLEEP];
static UNSIGNED8		sleepTableCnt = 0u;
#endif /* CO_EVENT_SLEEP_CNT */
static CO_TIMER_T		sleepTimer[CO_LINE_ARRAY_DECL];
static CO_TIMER_T		awakeTimer[CO_LINE_ARRAY_DECL];
static COB_REFERENZ_T	sleepMasterCob[CO_LINE_ARRAY_DECL];
#ifdef CO_SLEEP_454
static COB_REFERENZ_T	sleepSlaveCob[CO_LINE_ARRAY_DECL];
static COB_REFERENZ_T	sleepRequestCob[CO_LINE_ARRAY_DECL];
#endif /* CO_SLEEP_454 */
#ifdef CO_SLEEP_447
static COB_REFERENZ_T	sleepSlaveCob[CO_SLEEP_447_CNT];
#endif /* CO_SLEEP_447 */
static SLEEP_STATE_T	sleepState[CO_LINE_ARRAY_DECL] = { SLEEP_STATE_AWAKE };


/***************************************************************************/
/**
* \internal
*
* \brief coNmtMsgHandler - handle received NMT mesages
*
*
* \return none
*
*/
void icoSleepMsgHandler(
		CO_LINE_TYPE			CO_LINE,	/* can line */
		CO_CONST CO_REC_DATA_T	*pRec		/* pointer to receive data */
	)
{
UNSIGNED8	error;
UNSIGNED8	trData[CO_CAN_MAX_DATA_LEN];	/* data */

	if (pRec->msg.len != 8u)  {
		return;
	}

	/* message from master */
	if (pRec->msg.canId == CO_SLEEP_MASTER_CAN_ID)  {
		/* query sleep objection ? */
		if (pRec->msg.data[0] == CO_SLEEP_CMD_QUERY)  {
			/* check, if sleep is possible */
			error = callSleepInd(CO_LINE, CO_SLEEP_MODE_CHECK, 0u);
			if (error != 0u)  {
				/* answer error */
				MEMSET(&trData[0], 0, 8u);
				trData[0] = CO_SLEEP_STATE_OBJECTION;
				trData[1] = error;
#ifdef CO_SLEEP_454
				(void)icoTransmitMessage(CO_LINE, sleepSlaveCob[CO_LINE], &trData[0], 0u);
#elif defined(CO_SLEEP_447)
				(void)icoTransmitMessage(CO_LINE, sleepSlaveCob[pRec->spec], &trData[0], 0u);
#endif /* CO_SLEEP_447 */
			} else {
				sleepState[CO_LINE] = SLEEP_STATE_OBJECTION;
			}
		}

		/* sleep mode ? */
		if (pRec->msg.data[0] == CO_SLEEP_CMD_SLEEP)  {
			/* goto sleep start mode */
			coSleepModeStart(CO_LINE, CO_SLEEP_WAITTIME);
		}
	}

	/* objection from slave */
#ifdef CO_SLEEP_454
	if (pRec->msg.canId == CO_SLEEP_SLAVE_CAN_ID)  {
#endif /* CO_SLEEP_454 */
#ifdef CO_SLEEP_447
	if ((pRec->msg.canId >= CO_SLEEP_SLAVE_CAN_ID)
	 && (pRec->msg.canId < (CO_SLEEP_SLAVE_CAN_ID + CO_SLEEP_447_CNT)))  {
#endif /* CO_SLEEP_447 */

		if ((sleepState[CO_LINE] == SLEEP_STATE_OBJECTION)
		 && (pRec->msg.data[0] == CO_SLEEP_STATE_OBJECTION))  {
			(void)coTimerStop(CO_LINE, &sleepTimer[CO_LINE]);
			(void)callSleepInd(CO_LINE, CO_SLEEP_MODE_OBJECTION,
				(UNSIGNED8)(pRec->spec + 2u));
		}
	}

#ifdef CO_SLEEP_454
	if (pRec->msg.canId == CO_SLEEP_REQ_SLEEP_CAN_ID)  {
#endif /* CO_SLEEP_454 */
#ifdef CO_SLEEP_447
	if ((pRec->msg.canId >= CO_SLEEP_REQ_SLEEP_CAN_ID)
	 && (pRec->msg.canId < (CO_SLEEP_REQ_SLEEP_CAN_ID + CO_SLEEP_447_CNT)))  {
#endif /* CO_SLEEP_447 */

		(void)callSleepInd(CO_LINE, CO_SLEEP_MODE_REQUEST_SLEEP,
				(UNSIGNED8)(pRec->spec + 2u));
	}
}


#ifdef CO_NMT_MASTER
/***************************************************************************/
/**
*
* \brief coSleepModeCheck - check nodes for sleep mode
*
* This function sends the sleep objection command
* If an answer is received, the registered indication function is called.
* If no answer was received, the function starts automatically
* coSleepModeStart() - to start sleep mode.
*
*
* \return none
*
*/
void coSleepModeCheck(
		CO_LINE_TYPE	CO_LINE,	/**< can line */
		UNSIGNED16		waitTime	/**< time timeout value in ms */
	)
{
UNSIGNED8	trData[CO_CAN_MAX_DATA_LEN];	/* data */
CO_NMT_MASTER_STATE_T	masterState;

	masterState = icoNmtMasterGetState(CO_LINE);
	if (masterState != CO_NMT_MASTER_STATE_MASTER)  {
		return;
	}
	/* send objection command */
	MEMSET(&trData[0], 0, 8u);
	trData[0] = CO_SLEEP_CMD_QUERY;
	(void)icoTransmitMessage(CO_LINE, sleepMasterCob[CO_LINE], &trData[0], 0u);

	/* start timeout timer */
	(void)coTimerStart(CO_LINE, &sleepTimer[CO_LINE], waitTime * 1000ul,
		sleepNoObjection, NULL, CO_TIMER_ATTR_ROUNDUP); /*lint !e960 */
		/* Derogation MisraC2004 R.16.9 function identifier used without '&'
		 * or parenthesized parameter */

	sleepState[CO_LINE] = SLEEP_STATE_OBJECTION;
}


/***************************************************************************/
/**
* \internal
*
* \brief sleepNoObjection - timeout and no objection received
*
* \return none
*
*/
static void sleepNoObjection(
		CO_LINE_TYPE	CO_LINE,	/* can line */
		void			*ptr
	)
{
UNSIGNED8	err;
(void)ptr;

	sleepState[CO_LINE] = SLEEP_STATE_PREPARE;

	err = callSleepInd(CO_LINE, CO_SLEEP_MODE_PREPARE, 0);
	if (err == 0)  {
		coSleepModeStart(CO_LINE, CO_SLEEP_PREPARE_TIME);
	}
}
#endif /* CO_NMT_MASTER */


/***************************************************************************/
/**
*
* \brief coSleepModeStart - start sleep mode
*
* This function starts the sleep mode.
* First a timer is started, then the CAN traffic is stopped
* and the CPU is going to sleep.
*
* Each step is indicated by the function
* registered by coEventRegister_SLEEP().
*
*
* \return none
*
*/
void coSleepModeStart(
		CO_LINE_TYPE	CO_LINE,		/**< can line */
		UNSIGNED16		waitTime		/**< wait time before stop CAN in ms */
	)
{
#ifdef CO_NMT_MASTER
UNSIGNED8	trData[CO_CAN_MAX_DATA_LEN];	/* data */
CO_NMT_MASTER_STATE_T	masterState;

	masterState = icoNmtMasterGetState(CO_LINE);
	if (masterState == CO_NMT_MASTER_STATE_MASTER)  {
		/* if master, send sleep command */
		MEMSET(&trData[0], 0, 8u);
		trData[0] = CO_SLEEP_CMD_SLEEP;
		(void)icoTransmitMessage(CO_LINE, sleepMasterCob[CO_LINE], &trData[0], 0u);
	}
#endif /* CO_NMT_MASTER */

	/* if waitTime == 0, set ist to 1 */
	if (waitTime == 0u)  {
		waitTime++;
	}

	(void)coTimerStart(CO_LINE, &sleepTimer[CO_LINE], waitTime * 1000ul,
		sleepSilent, NULL, CO_TIMER_ATTR_ROUNDUP);	/*lint !e960 */
		/* Derogation MisraC2004 R.16.9 function identifier used without '&'
		 * or parenthesized parameter */

	sleepState[CO_LINE] = SLEEP_STATE_SLEEP;
}


/***************************************************************************/
/**
* \internal
*
* \brief sleepSilent
*
*
* \return none
*
*/
static void sleepSilent(
		CO_LINE_TYPE	CO_LINE,	/* can line */
		void			*ptr
	)
{
UNSIGNED8	error;
(void)ptr;

	error = callSleepInd(CO_LINE, CO_SLEEP_MODE_SILENT, 0u);
	if (error == 0u)  {
		/* ok, disable CAN traffic */
		icoQueueDisable(CO_LINE, CO_TRUE);

		/* start timer before sleep will be active */
		(void)coTimerStart(CO_LINE, &sleepTimer[CO_LINE], 1000000ul,
			sleepDoze, NULL, CO_TIMER_ATTR_ROUNDUP); /*lint !e960 */
		/* Derogation MisraC2004 R.16.9 function identifier used without '&'
		 * or parenthesized parameter */
	} else {
		sleepState[CO_LINE] = SLEEP_STATE_AWAKE;
	}
}


/***************************************************************************/
/**
* \internal
*
* \brief sleepDoze
*
*
* \return none
*
*/
static void sleepDoze(
		CO_LINE_TYPE	CO_LINE,	/* can line */
		void			*ptr
	)
{
UNSIGNED8	error;
(void)ptr;

	error = callSleepInd(CO_LINE, CO_SLEEP_MODE_DOZE, 0u);
	if (error != 0u)  {
		icoQueueDisable(CO_LINE, CO_FALSE);
		sleepState[CO_LINE] = SLEEP_STATE_AWAKE;
	}
}


/***************************************************************************/
/**
*
* \brief coSleepAwake - awake from sleep
*
* This function have to called after the processor is awaked.
* It transmit the wake up message, repeat it after the given repeatTime
* and reinitializes the communication handling.
*
* \return none
*
*/
void coSleepAwake(
		CO_LINE_TYPE	CO_LINE,	/**< can line */
		BOOL_T			master,		/**< wake up master */
		UNSIGNED8		status,		/**< wake up state (only for slaves) */
		UNSIGNED8		reason,		/**< wake up reason */
		UNSIGNED16		repeatTime	/**< time interval for repeat wake up message*/
	)
{
	/* if already awaked, return */
	if (sleepState[CO_LINE] != SLEEP_STATE_SLEEP)  {
		return;
	}

	coSleepWakeUp(CO_LINE, master, status, reason, repeatTime);
}


/***************************************************************************/
/**
*
* \brief coSleepWakeUp - awake from sleep
*
* This function can be called to send the wake up message
* independ form the actual sleep state.
* It transmit the wake up message, repeat it after the given repeatTime
* and reinitializes the communication handling.
*
* \return none
*
*/
void coSleepWakeUp(
		CO_LINE_TYPE	CO_LINE,	/**< can line */
		BOOL_T			master,		/**< wake up master */
		UNSIGNED8		status,		/**< wake up state (only for slaves) */
		UNSIGNED8		reason,		/**< wake up reason */
		UNSIGNED16		repeatTime	/**< time interval for repeat wake up message*/
	)
{
static WAKEUP_T	wakeUpData[CO_LINE_ARRAY_DECL];
#ifdef CO_LSS_SUPPORTED
UNSIGNED8	nodeId = CO_NODE_ID;
#endif /* CO_LSS_SUPPORTED */

	(void)coCommTask(CO_LINE);
	icoQueueDisable(CO_LINE, CO_FALSE);
	sleepState[CO_LINE] = SLEEP_STATE_AWAKE;

	/* transmit wakeup */
	wakeUpData[CO_LINE].reason = reason;
	if (master == CO_TRUE)  {
		wakeUpData[CO_LINE].status = 0x82u;
		wakeUpData[CO_LINE].sleepCob = sleepMasterCob[CO_LINE];
	} else {
		wakeUpData[CO_LINE].status = status;
#ifdef CO_SLEEP_454
		wakeUpData[CO_LINE].sleepCob = sleepSlaveCob[CO_LINE];
#endif /* CO_SLEEP_454 */
#ifdef CO_SLEEP_447
		wakeUpData[CO_LINE].sleepCob = sleepSlaveCob[0];
#endif /* CO_SLEEP_447 */
	}
	sleepWakeUpMessage(CO_LINE, &wakeUpData[CO_LINE]);

	/* start timer for repeat wake up message */
	(void)coTimerStart(CO_LINE, &awakeTimer[CO_LINE], repeatTime * 1000ul,
		sleepWakeUpMessage, &wakeUpData[CO_LINE], CO_TIMER_ATTR_ROUNDUP); /*lint !e960 */
		/* Derogation MisraC2004 R.16.9 function identifier used without '&'
		 * or parenthesized parameter */

#ifdef CO_LSS_SUPPORTED
	/* fixes node-id ? */
	if (nodeId == 255u)  {
		icoNmtResetNodeId(CO_LINE);
	} else
#endif /* CO_LSS_SUPPORTED */
	{
		(void)coNmtLocalStateReq(CO_LINE, CO_NMT_STATE_RESET_COMM);
	}
}


/***************************************************************************/
/**
* \internal
*
* \brief sleepWakeUpMessage - transmit sleep wake message
*
* \return none
*
*/
static void sleepWakeUpMessage(
		CO_LINE_TYPE	CO_LINE,	/* can line */
		void			*ptr
	)
{
UNSIGNED8	trData[CO_CAN_MAX_DATA_LEN];	/* data */
WAKEUP_T	*pWakeUp = (WAKEUP_T *)ptr;

	MEMSET(&trData[0], 0, 8u);
	trData[0] = pWakeUp->status;
	trData[1] = pWakeUp->reason;
	(void)icoTransmitMessage(CO_LINE, pWakeUp->sleepCob, &trData[0], 0u);
}


/***************************************************************************/
/**
*
* \brief coSleepModeActive - check if sleep mode is active
*
*
* \return none
*
*/
BOOL_T coSleepModeActive(
		CO_LINE_TYPE	CO_LINE		/**< can line */
	)
{
	if (sleepState[CO_LINE] == SLEEP_STATE_SLEEP)  {
		return(CO_TRUE);
	}

	return(CO_FALSE);
}

#ifdef CO_SLEEP_454
/***************************************************************************/
/**
* \internal
*
* \brief icoSleepSetMasterSlave - set master state
*
* \return none
*
*/
void icoSleepSetMasterSlave(
		CO_LINE_TYPE	CO_LINE,		/* can line */
		CO_NMT_MASTER_STATE_T mState
	)
{

	if (mState == CO_NMT_MASTER_STATE_SLAVE)  {
		(void)icoCobChangeType(CO_LINE, sleepMasterCob[CO_LINE], CO_COB_TYPE_RECEIVE);
		(void)icoCobChangeType(CO_LINE, sleepSlaveCob[CO_LINE], CO_COB_TYPE_TRANSMIT);
		(void)icoCobChangeType(CO_LINE, sleepRequestCob[CO_LINE], CO_COB_TYPE_TRANSMIT);
	} else {
		(void)icoCobChangeType(CO_LINE, sleepMasterCob[CO_LINE], CO_COB_TYPE_TRANSMIT);
		(void)icoCobChangeType(CO_LINE, sleepSlaveCob[CO_LINE], CO_COB_TYPE_RECEIVE);
		(void)icoCobChangeType(CO_LINE, sleepRequestCob[CO_LINE], CO_COB_TYPE_RECEIVE);
	}
}
#endif /* CO_SLEEP_454 */

#ifdef CO_NMT_MASTER
#else /* CO_NMT_MASTER */
/***************************************************************************/
/**
*
* \brief coSleepRequestSleep - request sleep mode to master
*
* Request sleep mode from master by sending sleep request.
*
* \return none
*
*/
void coSleepRequestSleep(
		CO_LINE_TYPE	CO_LINE		/**< can line */
	)
{
UNSIGNED8	trData[CO_CAN_MAX_DATA_LEN];	/* data */

	/* send objection command */
	MEMSET(&trData[0], 0, 8u);
	trData[0] = CO_SLEEP_STATE_REQ;
# ifdef CO_SLEEP_454
	(void)icoTransmitMessage(CO_LINE, sleepRequestCob[CO_LINE], &trData[0], 0u);
# endif /* CO_SLEEP_454 */
# ifdef CO_SLEEP_447
	(void)icoTransmitMessage(CO_LINE, sleepSlaveCob[0], &trData[0], 0u);
# endif /* CO_SLEEP_447 */
}
#endif /* CO_NMT_MASTER */


/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
#ifdef CO_EVENT_SLEEP_CNT
/***************************************************************************/
/**
* \brief coEventRegister_SLEEP - register SLEEP event
*
* register indication function for SLEEP events
*
* \return RET_T
*
*/

RET_T coEventRegister_SLEEP(
		CO_EVENT_SLEEP_T pFunction	/**< pointer to function */
	)
{
	/* set new indication function as first at the list */
	if (sleepTableCnt >= CO_EVENT_SLEEP_CNT)  {
		return(RET_EVENT_NO_RESSOURCE);
	}

	sleepTable[sleepTableCnt] = pFunction;	/* save function pointer */
	sleepTableCnt++;

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


/***************************************************************************/
/*
* \internal
*
* \brief callSleepInd - call user specific indications
*
*
* \return RET_T
*
*/
static UNSIGNED8 callSleepInd(
		CO_LINE_TYPE	CO_LINE,	/* can line */
		CO_SLEEP_MODE_T	sleepMode,
		UNSIGNED8		node
	)
{
UNSIGNED8	retVal = 0u;
#ifdef CO_EVENT_SLEEP_CNT
UNSIGNED8	i;

	for (i = 0u; i < sleepTableCnt; i++)  {
		retVal = sleepTable[i](CO_LINE, sleepMode, node);
		if (retVal != 0u)  {
			return(retVal);
		}
	}
#endif /* CO_EVENT_SLEEP_CNT */

#ifdef CO_EVENT_STATIC_SLEEP
	retVal = coEventSleepInd(CO_LINE, sleepMode, node);
#endif /* CO_EVENT_STATIC_SLEEP */

	return(retVal);
}


/***************************************************************************/
/*
* \internal
*
* \brief coResetSleep - reset comm for Sleep
*
* If own nodeId is unknown (LSS device),
* 0 is used
*
* \return none
*
*/
void icoSleepReset(
		CO_LINE_TYPE	CO_LINE,		/* can line */
		UNSIGNED8 master,		/* device is master */
		UNSIGNED8 nodeId		/* own node id */
	)
{
#ifdef CO_SLEEP_447
UNSIGNED8	i;
#else /* CO_SLEEP_447 */
(void)master;
(void)nodeId;
#endif /* CO_SLEEP_447 */

	(void)icoCobSet(CO_LINE, sleepMasterCob[CO_LINE], CO_SLEEP_MASTER_CAN_ID, CO_COB_RTR_NONE, 8u);

#ifdef CO_SLEEP_454
	(void)icoCobSet(CO_LINE, sleepSlaveCob[CO_LINE], CO_SLEEP_SLAVE_CAN_ID, CO_COB_RTR_NONE, 8u);
	(void)icoCobSet(CO_LINE, sleepRequestCob[CO_LINE], CO_SLEEP_REQ_SLEEP_CAN_ID, CO_COB_RTR_NONE, 8u);
#endif /* CO_SLEEP_454 */

#ifdef CO_SLEEP_447
	if (master != 0)  {
		for (i = 0; i < CO_SLEEP_447_CNT; i++)  {
			(void)icoCobSet(CO_LINE, sleepSlaveCob[i], CO_SLEEP_SLAVE_CAN_ID + 2 + i,
					CO_COB_RTR_NONE, 8u);
		}
	} else {
		/* slave */
		(void)icoCobSet(CO_LINE, sleepSlaveCob[0], CO_SLEEP_SLAVE_CAN_ID + nodeId,
					CO_COB_RTR_NONE, 8u);
	}
#endif /* CO_SLEEP_447 */
}


/***************************************************************************/
/**
* \internal
*
* \brief icoSleepVarInit
*
*
* \return none
*
*/
void icoSleepVarInit(
		void
	)
{
CO_LINE_TYPE	CO_LINE;

	for (CO_LINE = 0; CO_LINE < CO_MULTI_LINE_CNT; CO_LINE++)
	{
		sleepState[CO_LINE] = SLEEP_STATE_AWAKE;

		sleepMasterCob[CO_LINE] = CO_INVALID_COB_REF;
#ifdef CO_SLEEP_454
		sleepSlaveCob[CO_LINE] = CO_INVALID_COB_REF;
		sleepRequestCob[CO_LINE] = CO_INVALID_COB_REF;
#endif /* CO_SLEEP_454 */
	}

#ifdef CO_EVENT_SLEEP_CNT
	sleepTableCnt = 0u;
#endif /* CO_EVENT_SLEEP_CNT */
}


/***************************************************************************/
/**
* \internal
*
* \brief icoSleepInit - init Sleep functionality
*
* This function initializes the Sleep functionality
*
* If parameter master is unequal 0 the node will be initialized as NMT master.
*
* \return RET_T
*
*/
RET_T icoSleepInit(
		CO_LINE_TYPE	CO_LINE,	/* can line */
		UNSIGNED8		master		/* master mode */
	)
{
#ifdef CO_SLEEP_447
UNSIGNED16	i;

	if (master != 0u)  {
		sleepMasterCob[CO_LINE] = icoCobCreate(CO_LINE, CO_COB_TYPE_TRANSMIT, CO_SERVICE_SLEEP, 0u);
		for (i = 0u; i < CO_SLEEP_447_CNT; i++)  {
			sleepSlaveCob[i] = icoCobCreate(CO_LINE, CO_COB_TYPE_RECEIVE, CO_SERVICE_SLEEP, i);
		}


	} else {
		sleepMasterCob[CO_LINE] = icoCobCreate(CO_LINE, CO_COB_TYPE_RECEIVE, CO_SERVICE_SLEEP, 0u);
		sleepSlaveCob[0] = icoCobCreate(CO_LINE, CO_COB_TYPE_TRANSMIT, CO_SERVICE_SLEEP, 0u);
	}

	if (sleepMasterCob[CO_LINE] == CO_INVALID_COB_REF)  {
		return(RET_NO_COB_AVAILABLE);
	}

	for (i = 0u; i < CO_SLEEP_447_CNT; i++)  {
		if (sleepSlaveCob[i] == CO_INVALID_COB_REF)  {
			return(RET_NO_COB_AVAILABLE);
		}
	}
#endif /* CO_SLEEP_447 */

#ifdef CO_SLEEP_454
	if (master != 0u)  {
		sleepMasterCob[CO_LINE] = icoCobCreate(CO_LINE, CO_COB_TYPE_TRANSMIT, CO_SERVICE_SLEEP, 0u);
		sleepSlaveCob[CO_LINE] = icoCobCreate(CO_LINE, CO_COB_TYPE_RECEIVE, CO_SERVICE_SLEEP, 0u);
		sleepRequestCob[CO_LINE] = icoCobCreate(CO_LINE, CO_COB_TYPE_RECEIVE, CO_SERVICE_SLEEP, 0u);
	} else {
		sleepMasterCob[CO_LINE] = icoCobCreate(CO_LINE, CO_COB_TYPE_RECEIVE, CO_SERVICE_SLEEP, 0u);
		sleepSlaveCob[CO_LINE] = icoCobCreate(CO_LINE, CO_COB_TYPE_TRANSMIT, CO_SERVICE_SLEEP, 0u);
		sleepRequestCob[CO_LINE] = icoCobCreate(CO_LINE, CO_COB_TYPE_TRANSMIT, CO_SERVICE_SLEEP, 0u);
	}

	if ((sleepMasterCob[CO_LINE] == CO_INVALID_COB_REF) || (sleepSlaveCob[CO_LINE] == CO_INVALID_COB_REF)
	 || (sleepRequestCob[CO_LINE] == CO_INVALID_COB_REF))  {

		return(RET_NO_COB_AVAILABLE);
	}
#endif /* CO_SLEEP_454 */

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