/*
* codrv_FreeRTOS.c - contains OS specific function definitions
*
* Copyright (c) 2012-2020 emotas embedded communication GmbH
*-------------------------------------------------------------------
* $Id: codrv_FreeRTOS.c 54858 2024-07-31 14:37:47Z hil $
*
*
*-------------------------------------------------------------------
*
*
*/

/********************************************************************/
/**
* \file
* \brief OS specific function definitions
*
*/

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

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

#include <FreeRTOS.h>
#include <event_groups.h>
#include <task.h>
#include <semphr.h>

#include <codrv_FreeRTOS.h>


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

//#define YIELD_IN_ISR 1

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

/* list of external used functions, if not in headers
--------------------------------------------------------------------------*/
extern void codrvTimerISR(void);			/* Timer interrupt routine */

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

/* list of local defined functions
---------------------------------------------------------------------------*/
static void timerCallback(TimerHandle_t xTimer);
static RET_T codrvCreateLockObjects(void);

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

/* global variables
---------------------------------------------------------------------------*/
SemaphoreHandle_t semphCANopen;			/* CANopen task lock */
SemaphoreHandle_t semphObjDir;			/* object dictionary lock */

/* local defined variables
---------------------------------------------------------------------------*/
static TimerHandle_t timerHandle = NULL;		/* CANopen timer object */


/***************************************************************************/
/**
* \brief codrvOSConfig - OS specific setup
*
* creates and starts the CANopen timer and
* creates objects to lock object directory and CANopen thread
*
* \return RET_T
*/
RET_T codrvOSConfig(void)
{
RET_T retVal = RET_DRV_ERROR;

	/* create objects to lock object directory and CANopen thread */
	retVal = codrvCreateLockObjects();
	if (retVal != RET_OK)  {
		return(retVal);
	}

	/* create and setup CANopen timer */
	retVal = codrvTimerSetup(CO_TIMER_INTERVAL);
	if (retVal != RET_OK)  {
		return(retVal);
	}

	return(RET_OK);
}

/***************************************************************************/
/**
* \brief codrvTimerSetup - initialize timer
*
* Start a cyclic hardware timer to provide timing interval.
* alternatively it can be derived from an other system timer
* with the interval given from the DeviceDesigner.
*
* \returns RET_T
*/
RET_T codrvTimerSetup(
		UNSIGNED32 timerInterval
	)
{
BaseType_t ret = pdPASS;

	/* define CANopenTimer */
	timerHandle = xTimerCreate("CANopenTimer", pdMS_TO_TICKS(timerInterval/1000), pdTRUE,
			(void*)0, timerCallback);
	if (timerHandle == NULL)  {
		return(RET_DRV_ERROR);
	}

	/* start CANopenTimer */
	ret = xTimerStart(timerHandle, 0ul);
	if (ret == pdFAIL)  {
		return(RET_DRV_ERROR);
	}

	return(RET_OK);
}


/***************************************************************************/
/**
* \brief timerCallback - call timer interrupt service routine
*
* \returns void
*/
static void timerCallback(TimerHandle_t xTimer)
{
	(void)xTimer;

	/* call timer interrupt service routine */
	codrvTimerISR();
}


/***************************************************************************/
/**
* \brief codrvCreateLockObjects - create lock objects
*
* Create objects to lock CANopen thread and CANopen object dictionary
*
* \returns RET_T
*/
static RET_T codrvCreateLockObjects(
		void
	)
{
	/* create a mutex to lock the CANopen object dictionary */
	semphObjDir = xSemaphoreCreateMutex();
	if(semphObjDir == NULL)  {
		return(RET_DRV_ERROR);
	}

	/* create a semaphore to lock the CANopen Thread */
	semphCANopen = xSemaphoreCreateBinary();
	if (semphCANopen == NULL)  {
		return(RET_DRV_ERROR);
	}


	return(RET_OK);
}


/***************************************************************************/
/**
* \brief codrvWaitForEvent - wait for timer or CAN event
*
* \returns void
*/
void codrvWaitForEvent(UNSIGNED32 msecTimeout)
{
	/* wait until semaphore is unlocked */
	(void)xSemaphoreTake(semphCANopen, msecTimeout);
}

/***************************************************************************/
void codrvOsSignal_CAN_TRANSMIT(void)
{
	(void)xSemaphoreGive(semphCANopen);
}

/***************************************************************************/
void codrvOsSignal_CAN_TRANSMIT_ISR(void)
{
BaseType_t xHigherPriorityTaskWoken;
	xHigherPriorityTaskWoken = pdFALSE;

	(void)xSemaphoreGiveFromISR(semphCANopen, &xHigherPriorityTaskWoken);
#ifdef YIELD_IN_ISR
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
#endif
}

/***************************************************************************/
void codrvOsSignal_CAN_RECEIVE(void)
{
	(void)xSemaphoreGive(semphCANopen);
}

/***************************************************************************/
void codrvOsSignal_CAN_RECEIVE_ISR(void)
{
BaseType_t xHigherPriorityTaskWoken;

	xHigherPriorityTaskWoken = pdFALSE;
	(void)xSemaphoreGiveFromISR(semphCANopen, &xHigherPriorityTaskWoken);
#ifdef YIELD_IN_ISR
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
#endif
}

/***************************************************************************/
void codrvOsSignal_TIMER(void)
{
	(void)xSemaphoreGive(semphCANopen);
}

/***************************************************************************/
void codrvOsSignal_TIMER_ISR(void)
{
BaseType_t xHigherPriorityTaskWoken;

	xHigherPriorityTaskWoken = pdFALSE;
	(void)xSemaphoreGiveFromISR(semphCANopen, &xHigherPriorityTaskWoken);
#ifdef YIELD_IN_ISR
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
#endif
}

/***************************************************************************/
void codrvOsSignal_CAN_STATE(void)
{
	(void)xSemaphoreGive(semphCANopen);
}

/***************************************************************************/
void codrvOsSignal_CAN_STATE_ISR(void)
{
BaseType_t xHigherPriorityTaskWoken;

	xHigherPriorityTaskWoken = pdFALSE;
	(void)xSemaphoreGiveFromISR(semphCANopen, &xHigherPriorityTaskWoken);
#ifdef YIELD_IN_ISR
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
#endif
}

/***************************************************************************/
void codrvOs_LOCK_OD(void)
{
	(void)xSemaphoreTake(semphObjDir, portMAX_DELAY);
}

/***************************************************************************/
void codrvOs_UNLOCK_OD(void)
{
	(void)xSemaphoreGive(semphObjDir);
}

#endif /* CODRV_USE_FREERTOS */
