/*
* co_commtask.c - contains communication task of canopen library
*
* Copyright (c) 2012-2023 emotas embedded communication GmbH
*-------------------------------------------------------------------
* $Id: co_commtask.c 51990 2024-01-25 12:15:47Z boe $
*
*
*-------------------------------------------------------------------
*
*
*/

/********************************************************************/
/**
* \brief communication task routines
*
* \file co_commtask.c
* contains communication task functions of canopen library
*
*/


/* header of standard C - libraries
---------------------------------------------------------------------------*/

/* header of project specific types
---------------------------------------------------------------------------*/
#include <gen_define.h>
#include <co_datatype.h>
#include <co_timer.h>
#include <co_drv.h>
#include <co_commtask.h>
#ifdef CANOPEN_SUPPORTED
# include <co_odaccess.h>
# include <co_led.h>
# include <co_nmt.h>
#endif /* CANOPEN_SUPPORTED */
#include "ico_cobhandler.h"
#include "ico_queue.h"
#include "ico_commtask.h"
#include "ico_timer.h"
#include "ico_event.h"
#ifdef CANOPEN_SUPPORTED
# include "ico_indication.h"
# include "ico_nmt.h"
# include <co_pdo.h>
# include "ico_pdo.h"
# include "ico_sync.h"
# include "ico_emcy.h"
# include "ico_time.h"
#endif /* CANOPEN_SUPPORTED */
#if defined(CO_SDO_SERVER_CNT) || defined(CO_SDO_CLIENT_CNT)
# include "co_sdo.h"
#endif /* defined(CO_SDO_SERVER_CNT) || defined(CO_SDO_CLIENT_CNT) */
#ifdef CO_SDO_SERVER_CNT
# ifndef CANOPEN_SUPPORTED
#  include "ico_indication.h"
#  include <co_odaccess.h>
# endif /* CANOPEN_SUPPORTED */
# include "ico_sdoserver.h"
#endif /* CO_SDO_SERVER_CNT */
#ifdef CO_SDO_CLIENT_CNT
# include "ico_sdoclient.h"
#endif /* CO_SDO_CLIENT_CNT */
#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 USER_RECEIVE_MSG_CNT
# include "ico_user.h"
#endif /* USER_RECEIVE_MSG_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 J1939_SUPPORTED
# include "ico_j1939.h"
#endif /* J1939_SUPPORTED */
#ifdef CO_USDO_SUPPORTED
# include "ico_usdo.h"
#endif /* CO_USDO_SUPPORTED */
#ifdef CO_ESDO_SUPPORTED
# include "ico_esdoserver.h"
#  ifdef CO_ESDO_CLIENT_SUPPORTED
#   include "ico_esdoclient.h"
#  endif /* CO_ESDO_CLIENT_SUPPORTED */
#endif /* CO_ESDO_SUPPORTED */
#ifdef CO_IDNEGO_SUPPORTED
# include "ico_idnego.h"
#endif /* CO_IDNEGO_SUPPORTED */
#ifdef ISOTP_SUPPORTED
# include "iiso_tp.h"
#endif /* ISOTP_SUPPORTED */
#ifdef RAWCAN_SUPPORTED
# include "ico_rawcan.h"
#endif /* RAWCAN_SUPPORTED */
#ifdef J1939_SDG_SUPPORTED
# include "ij1939_sdg.h"
#endif /* J1939_SDG_SUPPORTED */
#ifdef CO_REDUNDANCY
# include <co_redundancy.h>
#endif /* CO_REDUNDANCY */

/* constant definitions
---------------------------------------------------------------------------*/
#ifdef CO_EVENT_DYNAMIC_CAN
# ifdef CO_EVENT_PROFILE_CAN
#  define CO_EVENT_CAN_CNT	(CO_EVENT_DYNAMIC_CAN + CO_EVENT_PROFILE_CAN)
# else /* CO_EVENT_PROFILE_CAN */
#  define CO_EVENT_CAN_CNT	(CO_EVENT_DYNAMIC_CAN)
# endif /* CO_EVENT_PROFILE_CAN */
#else /* CO_EVENT_DYNAMIC_CAN */
# ifdef CO_EVENT_PROFILE_CAN
#  define CO_EVENT_CAN_CNT	(CO_EVENT_PROFILE_CAN)
# endif /* CO_EVENT_PROFILE_CAN */
#endif /* CO_EVENT_DYNAMIC_CAN */

#ifndef CODRV_CAN_DRIVER_HANDLER
# define CODRV_CAN_DRIVER_HANDLER	codrvCanDriverHandler
#endif /* CODRV_CAN_DRIVER_HANDLER */

#define COMM_STATE_TABLE_CNT	14u

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

/* list of external used functions, if not in headers
---------------------------------------------------------------------------*/
#ifdef CO_EVENT_STATIC_CAN
extern CO_CONST CO_EVENT_CAN_STATE_T coEventCanStateInd;
extern CO_CONST CO_EVENT_COMM_T coEventCommInd;
#endif /* CO_EVENT_STATIC_CAN */


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

/* list of local defined functions
---------------------------------------------------------------------------*/
static void serviceManagement(void);
static BOOL_T receiveMessageHandler(void);

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

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

/* local defined variables
---------------------------------------------------------------------------*/
static BOOL_T	eventFlagMsg;
static BOOL_T	eventFlagTimer;
static BOOL_T	eventFlagEventHandler;
static CO_CAN_STATE_T canState;
static CO_COMM_STATE_EVENT_T recQuState;
static CO_COMM_STATE_EVENT_T trQuState;
#ifdef CO_EVENT_CAN_CNT
static UNSIGNED8	canStateTableCnt;
static UNSIGNED8	commEventTableCnt;
static CO_EVENT_CAN_STATE_T	canStateTable[CO_EVENT_CAN_CNT];
static CO_EVENT_COMM_T		commEventTable[CO_EVENT_CAN_CNT];
#endif /* CO_EVENT_CAN_CNT */


/***************************************************************************/
/**
* \brief coCommTask - main communication task
*
* This is the main communication task for the CANopen stack.
* It has to be called cyclically by the application or signal
* driven after each received CAN message or timer event.
*
*
* \return BOOL_T
* \retval CO_TRUE
* 	further actions necessary - call coCommTask again
* \retval CO_FALSE
* 	all actions passed
*/
BOOL_T coCommTask(
		void	/* no parameter */
	)
{
BOOL_T	event;

	/* call protocol handler */
	serviceManagement();

	/* call cob handler */

	/* call queue handler */
	icoQueueHandler();

	/* call driver handler */
	CODRV_CAN_DRIVER_HANDLER();

#ifdef CO_SRDO_SUPPORTED
	icoSrdoTimerCheck();
#endif /* CO_SRDO_SUPPORTED */

#ifdef J1939_SDG_SUPPORTED
	ij1939SdgTimerCheck();
#endif /* J1939_SDG_SUPPORTED */

	event = coCommTaskCheck();

	return(event);
}


/***************************************************************************/
/**
* \brief coCommTaskCheck - check communication tasks
*
* This function checks if all communication task are done.
* If not, it returns true. In this case, coCommTask() should be called again.
*
* \return BOOL_T
* \retval CO_TRUE
* 	further actions necessary - call coCommTask again
* \retval CO_FALSE
* 	all actions passed
*
*/
BOOL_T coCommTaskCheck(
		void	/* no parameter */
	)
{
BOOL_T retVal = CO_FALSE;

	/* check for messages at receive buffer */
	if (coQueueReceiveMessageAvailable() == CO_TRUE)  {
		retVal = CO_TRUE;
	}

	/* check for events */
	if (icoEventsAvailable() == CO_TRUE)  {
		retVal = CO_TRUE;
	}

	return(retVal);
}


/***************************************************************************/
/**
*
* \internal
*
* \brief serviceManagement - call canopen protocol handler
*
* handles all canopen protocol services
* like service management, timer handling, communication state changes....
*
*
* \return void
*
*/
static void serviceManagement(
		void	/* no parameter */
	)
{
	/* message handler - if new messages are available */
	if (eventFlagMsg != CO_FALSE)  {
		eventFlagMsg = CO_FALSE;
		if (receiveMessageHandler() != CO_FALSE)  {
			eventFlagMsg = CO_TRUE;
		}
	}

	/* timer handling - if timer has elapsed */
	if (eventFlagTimer != CO_FALSE)  {
		eventFlagTimer = CO_FALSE;
		icoTimerCheck();
	}

	if (eventFlagEventHandler != CO_FALSE)  {
		eventFlagEventHandler = CO_FALSE;
		icoEventCheck();
	}

	/* communication state changes */
/*	commStateHandler();*/

}


/***************************************************************************/
/**
*
* \internal
*
* \brief receiveMessageHandler - handles new receive messages
*
* handles new message from CAN
* read it from queue handler and call approproate service function
*
* \return message available
* \retval CO_FALSE
*	no message available
* \retval CO_TRUE
*	message available
*/
static BOOL_T receiveMessageHandler(
		void	/* no parameter */
	)
{
CO_REC_DATA_T	recData;
BOOL_T		avail;

	/* get next message from Queue handler */
	avail = icoQueueGetReceiveMessage(&recData);
	if (avail == CO_FALSE)  {
		return(avail);
	}


	switch (recData.service)  {
#ifdef CANOPEN_SUPPORTED
		case CO_SERVICE_NMT:
			icoNmtMsgHandler(&recData);
			break;
#endif /* CANOPEN_SUPPORTED */

#ifdef CO_GFC_SUPPORTED
		case CO_SERVICE_GFC_RECEIVE:
			icoGfcHandler();
			break;
#endif /* CO_GFC_SUPPORTED */

#ifdef CO_SRDO_SUPPORTED
		case CO_SERVICE_SRDO_RECEIVE:
			icoSrdoHandler(&recData);
			break;
#endif /* CO_SRDO_SUPPORTED */

#ifdef CO_SYNC_SUPPORTED
		case CO_SERVICE_SYNC_RECEIVE:
			/* check for correct message len */
			if (recData.msg.len == 0u)  {
				recData.msg.data[0] = 0u;
			}
			if (recData.msg.len < 2u)  {
				icoSyncHandler(recData.msg.data[0]);
			}
			break;
#endif /* CO_SYNC_SUPPORTED */

#ifdef CO_PDO_RECEIVE_CNT
		case CO_SERVICE_PDO_RECEIVE:
			icoPdoReceiveHandler(&recData);
			break;
#endif /* CO_PDO_RECEIVE_CNT */

#ifdef CANOPEN_SUPPORTED
		case CO_SERVICE_ERRCTRL:
			icoNmtErrorCtrlHandler(&recData);
			break;
#endif /* CANOPEN_SUPPORTED */

#ifdef CO_SDO_SERVER_CNT
		case CO_SERVICE_SDO_SERVER:
			icoSdoServerHandler(&recData
# ifdef CO_SDO_NETWORKING
				, 0u
# endif /* CO_SDO_NETWORKING */
				);
			break;
#endif /* CO_SDO_SERVER_CNT */

#ifdef CO_USDO_SUPPORTED
		case CO_SERVICE_USDO_SERVER:
			icoUsdoServerHandler(&recData);
			break;
# ifdef CO_USDO_CLIENT_SUPPORTED
		case CO_SERVICE_USDO_CLIENT:
			icoUsdoClientHandler(&recData);
			break;
# endif /* CO_USDO_CLIENT_SUPPORTED */
#endif /* CO_USDO_SUPPORTED */

#ifdef CO_SDO_CLIENT_CNT
		case CO_SERVICE_SDO_CLIENT:
			icoSdoClientHandler(&recData);
			break;
#endif /* CO_SDO_CLIENT_CNT */

#ifdef CO_EMCY_CONSUMER_CNT
		case CO_SERVICE_EMCY_RECEIVE:
			icoEmcyConsumerHandler(&recData);
			break;
#endif /* CO_EMCY_CONSUMER_CNT */

#ifdef CO_PDO_TRANSMIT_CNT
		case CO_SERVICE_PDO_TRANSMIT:
			icoPdoRtrHandler(&recData);
			break;
#endif /* CO_PDO_TRANSMIT_CNT */

#ifdef CO_TIME_SUPPORTED
		case CO_SERVICE_TIME_RECEIVE:
			/* check for correct message len */
			if (recData.msg.len == 6u)  {
				icoTimeHandler(&recData.msg.data[0]);
			}
			break;
#endif /* CO_TIME_SUPPORTED */

#ifdef CO_LSS_SUPPORTED
		case CO_SERVICE_LSS_S_RECEIVE:
			icoLssHandler(&recData);
			break;
#endif /* CO_LSS_SUPPORTED */

#ifdef CO_LSS_MASTER_SUPPORTED
		case CO_SERVICE_LSS_M_RECEIVE:
			icoLssMasterHandler(&recData);
			break;
#endif /* CO_LSS_MASTER_SUPPORTED */

#ifdef CO_FLYING_MASTER_SUPPORTED
		case CO_SERVICE_FLYMA:
			icoNmtFlymaHandler(&recData);
			break;
#endif /* CO_FLYING_MASTER_SUPPORTED */

#ifdef CO_GUARDING_CNT
		case CO_SERVICE_GUARDING:
			icoGuardingHandler(&recData);
			break;
#endif /* CO_GUARDING_CNT */

#ifdef CO_EVENT_SLEEP
		case CO_SERVICE_SLEEP:
			icoSleepMsgHandler(&recData);
			break;
#endif /* CO_EVENT_SLEEP */

#ifdef USER_RECEIVE_MSG_CNT
		case CO_SERVICE_USER:
			icoUserHandler(&recData);
			break;
#endif /* USER_RECEIVE_MSG_CNT */

#ifdef J1939_SUPPORTED
		case CO_SERVICE_J1939_RECEIVE:
			ij1939ServiceHandler(&recData);
			break;
#endif /* J1939_SUPPORTED */

#ifdef CO_ESDO_SUPPORTED
		case CO_SERVICE_ESDO_SERVER:
			icoEsdoServerHandler(&recData);
			break;
#endif /* CO_ESDO_SUPPORTED */

#ifdef CO_ESDO_CLIENT_SUPPORTED
		case CO_SERVICE_ESDO_CLIENT:
			icoEsdoClientHandler(&recData);
			break;
#endif /* CO_ESDO_CLIENT_SUPPORTED */

#ifdef ISOTP_SERVER_CONNECTION_CNT
		case CO_SERVICE_ISOTP_SERVER:
			iisoTpMessageHandler(&recData);
			break;
#endif /* ISOTP_SERVER_CONNECTION_CNT */

#ifdef CO_IDNEGO_SUPPORTED
		case CO_SERVICE_IDNEGO_RECEIVE:
			icoIdNegoHandler(&recData);
			break;
#endif /* CO_IDNEGO_SUPPORTED */

#ifdef RAWCAN_SUPPORTED
		case CO_SERVICE_RAWCAN_RECEIVE:
			irawcanServiceHandler(&recData);
			break;
#endif /* CAN_RAW_SUPPORTED */

		default:
			break;
	}

	return(avail);
}


/***************************************************************************/
/**
*
* \internal
*
* \brief coCommTaskSet - set signal from CAN or timer
*
* This function signals new available messages from CAN or from timer
*
* \return void
*
*/
CO_INLINE void coCommTaskSet(
		CO_COMMTASK_EVENT_T	event
	)
{
	switch (event)  {
		case CO_COMMTASK_EVENT_TIMER:
			eventFlagTimer = CO_TRUE;
			break;
		case CO_COMMTASK_EVENT_MSG_AVAIL:
			eventFlagMsg = CO_TRUE;
			break;
		case CO_COMMTASK_EVENT_NEW_EVENT:
			eventFlagEventHandler = CO_TRUE;
			break;
		default:
			break;
	}
}


/***************************************************************************/
/**
* \brief coCommStateEvent - set a new communication state
*
* This function should be called,
* if a new communication state has been reached.
* <br>
* It sets the LEDs and informs the application about the event.
*
* \return void
*
*/
void coCommStateEvent(
		CO_COMM_STATE_EVENT_T	newEvent		/**< new communication event */
	)
{
typedef enum {
	CST_CAN, CST_TRQ, CST_RECQ, CST_DRV
} COMM_STATE_TYPE_T;

typedef struct {
	CO_COMM_STATE_EVENT_T	event;		/* comm event */
	COMM_STATE_TYPE_T		type;
	CO_CAN_STATE_T			state;		/* goto CAN state */
} CO_NV_STORAGE COMM_STATE_TABLE_T;

static const COMM_STATE_TABLE_T	commTable[COMM_STATE_TABLE_CNT] = {
	{ CO_COMM_STATE_EVENT_REC_QUEUE_FULL,		CST_RECQ,	CO_CAN_STATE_UNCHANGED},
	{ CO_COMM_STATE_EVENT_REC_QUEUE_OVERFLOW,	CST_RECQ,	CO_CAN_STATE_UNCHANGED},
	{ CO_COMM_STATE_EVENT_REC_QUEUE_EMPTY,	CST_RECQ,	CO_CAN_STATE_UNCHANGED},
	{ CO_COMM_STATE_EVENT_TR_QUEUE_FULL,		CST_TRQ,	CO_CAN_STATE_UNCHANGED},
	{ CO_COMM_STATE_EVENT_TR_QUEUE_OVERFLOW,	CST_TRQ,	CO_CAN_STATE_UNCHANGED},
	{ CO_COMM_STATE_EVENT_TR_QUEUE_EMPTY,		CST_TRQ, 	CO_CAN_STATE_UNCHANGED},
	{ CO_COMM_STATE_EVENT_CAN_OVERRUN,		CST_RECQ,	CO_CAN_STATE_UNCHANGED},
	{ CO_COMM_STATE_EVENT_BUS_OFF,			CST_CAN,	CO_CAN_STATE_BUS_OFF },
	{ CO_COMM_STATE_EVENT_BUS_OFF_RECOVERY, 	CST_CAN,	CO_CAN_STATE_BUS_OFF },
	{ CO_COMM_STATE_EVENT_BUS_ON,				CST_CAN,	CO_CAN_STATE_BUS_ON },
	{ CO_COMM_STATE_EVENT_PASSIVE,			CST_CAN,	CO_CAN_STATE_PASSIVE },
	{ CO_COMM_STATE_EVENT_ACTIVE,				CST_CAN,	CO_CAN_STATE_BUS_ON },
	{ CO_COMM_STATE_EVENT_DRV_ERROR,			CST_DRV,	CO_CAN_STATE_UNCHANGED},
	{ CO_COMM_STATE_EVENT_DRV_FILTER_ERROR,	CST_DRV,	CO_CAN_STATE_UNCHANGED}
};
UNSIGNED8	i;
CO_CAN_STATE_T	newCanState = CO_CAN_STATE_UNCHANGED;
CO_COMM_STATE_EVENT_T newState = CO_COMM_STATE_EVENT_NONE;
#ifdef CO_EVENT_CAN_CNT
UNSIGNED8	cnt;
#endif /* CO_EVENT_CAN_CNT */

	i = 0u;
	/* search event at event table */
	while (i < COMM_STATE_TABLE_CNT)  {
		if (commTable[i].event == newEvent)  {
			break;
		}
		i++;
	}

	/* no state found ? */
	if (i == COMM_STATE_TABLE_CNT)  {
		return;
	}

	/* event changes CAN state ? */
	if (commTable[i].state != CO_CAN_STATE_UNCHANGED)  {
		newCanState = commTable[i].state;

		/* new CAN state reached ? */
		if (canState != newCanState)  {
			/* if bus-off, go to preop */
#ifdef CANOPEN_SUPPORTED
			if (newCanState == CO_CAN_STATE_BUS_OFF)  {
				icoErrorBehavior();
			}
#endif /* CANOPEN_SUPPORTED */

#ifdef CO_EVENT_CAN_CNT
			cnt = canStateTableCnt;
			while (cnt > 0u)  {
				cnt--;
				/* call user indication */
				canStateTable[cnt](newCanState);
			}
#endif /* CO_EVENT_CAN_CNT */
#ifdef CO_EVENT_STATIC_CAN
			coEventCanStateInd(newCanState);
#endif /* CO_EVENT_STATIC_CAN */

#ifdef CO_EVENT_LED
			/* set led */
			switch (newCanState)  {
				case CO_CAN_STATE_BUS_OFF:
					coLedSetState(CO_LED_STATE_ON, CO_TRUE);
					break;
				case CO_CAN_STATE_BUS_ON:
					coLedSetState(CO_LED_STATE_ON, CO_FALSE);
					coLedSetState(CO_LED_STATE_FLASH_1, CO_FALSE);
					break;
				case CO_CAN_STATE_PASSIVE:
					coLedSetState(CO_LED_STATE_FLASH_1, CO_TRUE);
					break;
				default:
					break;
			}
#endif /* CO_EVENT_LED */

		}
		canState = newCanState;
	}

	/* check for transmit queue event */
	if (commTable[i].type == CST_TRQ)  {
		if (trQuState != newEvent)  {
			trQuState = newEvent;
			newState = newEvent;
		}
	}

	/* check for receive queue event */
	if (commTable[i].type == CST_RECQ)  {
		if (recQuState != newEvent)  {
			recQuState = newEvent;
			newState = newEvent;
		}
	}

	/* check for generic driver event */
	if (commTable[i].type == CST_DRV)  {
		newState = newEvent;
	}

	/* call user indication */
	if (newState != CO_COMM_STATE_EVENT_NONE)  {
#ifdef CO_EVENT_CAN_CNT
		cnt = commEventTableCnt;
		while (cnt > 0u)  {
			cnt--;
			/* call user indication */
			commEventTable[cnt](newEvent);
		}
#endif /* CO_EVENT_CAN_CNT */
#ifdef CO_EVENT_STATIC_CAN
		coEventCommInd(newEvent);
#endif /* CO_EVENT_STATIC_CAN */
	}
}


/***************************************************************************/
/*
* \brief icoCommTaskVarInit - init comm task variables
*
*/
void icoCommTaskVarInit(
		void
	)
{

	{
		eventFlagMsg = CO_FALSE;
		eventFlagTimer = CO_FALSE;
		eventFlagEventHandler = CO_FALSE;

		canState = CO_CAN_STATE_BUS_OFF;
		recQuState = CO_COMM_STATE_EVENT_REC_QUEUE_EMPTY;
		trQuState = CO_COMM_STATE_EVENT_BUS_OFF_RECOVERY;
	}

#ifdef CO_EVENT_CAN_CNT
	canStateTableCnt = 0u;
	commEventTableCnt = 0u;
#endif /* CO_EVENT_CAN_CNT */
}


#ifdef CO_EVENT_CAN_CNT
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/**
* \brief coEventRegister_CAN_STATE - register can state changes
*
* With this function the application can register a function which is called,
* when the CAN state was changed.<br>
* CAN states are:<br>
*	- BUS_OFF
*	- BUS_ON
*	- PASSIV
*	- UNCHANGED
*
* \return	RET_T
*
*/

RET_T coEventRegister_CAN_STATE(
		CO_EVENT_CAN_STATE_T pFunction		/**< pointer to function */
	)
{
RET_T retVal = RET_OK;

	/* set new indication function as first at the list */
	if (canStateTableCnt >= CO_EVENT_CAN_CNT)  {
		retVal = RET_EVENT_NO_RESSOURCE;
	} else {
		canStateTable[canStateTableCnt] = pFunction;	/* save function pointer */
		canStateTableCnt++;
	}
	return(retVal);
}


/***************************************************************************/
/**
* \brief coEventRegister_COMM_EVENT - register communication event changes
*
* With this function the application can register a function which is called,
* when the communication state has been changed.
*	- BUS OFF - no communication possible
*	- CAN OVERRUN - messages was lost
*	- Receice queue full - receive messages is full
*	- Receice queue overrun - receive messages was lost
*	- Transmit queue full - no more messages can be send
*	- Transmit queue overflow - transmit messages was lost
*	- Transmit queue empty - new transmit messages can be send
*
* \return RET_T
*
*/

RET_T coEventRegister_COMM_EVENT(
		CO_EVENT_COMM_T	pFunction	/**< pointer to function */
	)
{
RET_T retVal = RET_OK;

	/* set new indication function as first at the list */
	if (commEventTableCnt >= CO_EVENT_CAN_CNT)  {
		retVal = RET_EVENT_NO_RESSOURCE;
	} else {
		commEventTable[commEventTableCnt] = pFunction;	/* save function pointer */
		commEventTableCnt++;
	}
	return(retVal);
}
#endif /* CO_EVENT_CAN_CNT */
