/************************************************************************/
/* Copyright 2002-2016 MBARI											*/
/************************************************************************/
/* Summary  : Miscellaneous multitasking routines for OASIS5 on PIC32	*/
/* Filename : otask.c													*/
/* Author   : Robert Herlien (rah)										*/
/* Project  : OASIS Mooring Replacement (OASIS5)						*/
/* Revision: 1.0														*/
/* Created  : 07/06/2016 from oasis3/4 task.c							*/
/*									    								*/
/* MBARI provides this documentation and code "as is", with no warranty,    */
/* express or implied, of its quality or consistency. It is provided without*/
/* support and without obligation on the part of the Monterey Bay Aquarium  */
/* Research Institute to assist in its use, correction, modification, or    */
/* enhancement. This information should not be published or distributed to  */
/* third parties without specific written permission from MBARI.            */
/*									    								*/
/************************************************************************/
/* Modification History:												*/
/* 23oct2002 rah - OASIS3 task.c created								*/
/* 6jul2016 rah - OASIS5 otask.c created from OASIS3 task.c				*/
/************************************************************************/

#include <mbariTypes.h>					/* MBARI type definitions		*/
#include <mbariConst.h>					/* MBARI constants				*/
#include <oasis.h>						/* OASIS controller definitions	*/

#include <FreeRTOS.h>					/* FreeRTOS definitions			*/
#include <task.h>						/* FreeRTOS/include task.h		*/
#include <FreeRTOSConfig.h>

#include <otask.h>						/* OASIS task routines			*/
#include <sem.h>						/* OASIS semaphore definitions	*/ 
#include <timer.h>						/* Oasis defns of tick rate		*/
#include <serial.h>						/* OASIS serial port definitions*/


typedef struct
{
	void	(*entryPoint)(void *);
	void	*arg;
} TaskRunBlk;


/********************************/
/*		Module Local Data		*/
/********************************/

MLocal SerDesc	dfltSerDesc =
	{SER_CONSOLE, (NO_PTY | BIT8 | STOP1 | FLOW | ECHO | AUTOCR), 0};


/************************************************************************/
/* Function	   : taskKill												*/
/* Purpose	   : Kill a task, or perform exit routines					*/
/* Inputs	   : TaskHandle												*/
/* Outputs	   : None													*/
/************************************************************************/
void taskKill(TaskHandle_t td)
{
	if (td == NULL)
		td = xTaskGetCurrentTaskHandle();
	else if (td != xTaskGetCurrentTaskHandle())
		vTaskSuspend(td);

	remTaskExit(td);						/* Release remote resources	*/
	semTaskExit(td);						/* Release any mutex sems	*/
	mallocTaskExit(td);						/* Release any malloc'd mem	*/
	vTaskDelete(td);						/* Kill task				*/
}


/************************************************************************/
/* Function	   : taskWrapper											*/
/* Purpose	   : Wrapper for task creation								*/
/* Inputs	   : None													*/
/* Outputs	   : Task Descriptor										*/
/************************************************************************/
MLocal void taskWrapper(void *argp)
{
	void	(*entPt)(void *);
	void	*arg;
	TaskHandle_t td;

	if (argp == NULL)
		vTaskDelete(NULL);

	entPt = ((TaskRunBlk *)argp)->entryPoint;
	arg   = ((TaskRunBlk *)argp)->arg;
	td    = xTaskGetCurrentTaskHandle();
	vPortFree(argp);

	vTaskSetThreadLocalStoragePointer(td, ConsoleP, &dfltSerDesc);
	vTaskSetThreadLocalStoragePointer(td, DrvrP, NULL);
	vTaskSetThreadLocalStoragePointer(td, State, (void *)READY);
	vTaskSetThreadLocalStoragePointer(td, StateParm, NULL);
	vTaskSetThreadLocalStoragePointer(td, Malloc1, NULL);
	vTaskSetThreadLocalStoragePointer(td, Malloc2, NULL);

	(*entPt)(arg);						/* Call the function		   */

	remTaskExit(td);					/* Release remote resources	*/
	semTaskExit(td);					/* Release any mutex sems	*/
	mallocTaskExit(td);					/* Release any malloc'd mem	*/
	vTaskDelete(td);					/* Kill task				*/
}


/************************************************************************/
/* Function	   : task_create											*/
/* Purpose	   : Create a task											*/
/* Inputs	   : Entry point, arg, name, stack depth (longs), priority	*/
/* Outputs	   : Task Descriptor										*/
/************************************************************************/
TaskHandle_t task_create(void (*entryPt)(void *), void *argp, char *name,
						 Nat16 stackDepth, Nat32 priority)
{
	TaskHandle_t	createdTask;
	TaskRunBlk		*rp;

	if (priority > MAX_TASK_PRIO)
		priority = MAX_TASK_PRIO;

	if ((rp = pvPortMalloc(sizeof(TaskRunBlk))) == NULL)
		return(NULL);

	rp->entryPoint = entryPt;
	rp->arg = argp;

	if (xTaskCreate(taskWrapper, name, stackDepth, rp, priority, &createdTask)
		!= pdPASS)
		return(NULLTASK);
	
	return(createdTask);

} /* task_create() */


/************************************************************************/
/* Function	   : task_delay												*/
/* Purpose	   : Delay a number of ticks								*/
/* Inputs	   : Number of FreeRTOS ticks to delay						*/
/* Outputs	   : None													*/
/* Comments    : Count is limited to an unsigned long					*/
/*				 Limits delay approx 49 days at 1000 Hz					*/
/************************************************************************/
void task_delay(TickType_t ticks)
{
	vTaskSetThreadLocalStoragePointer(NULL, State, (void *)DELAY);
	vTaskSetThreadLocalStoragePointer(NULL, StateParm, 
									  (void *)(xTaskGetTickCount() + ticks));
	vTaskDelay(ticks);

	vTaskSetThreadLocalStoragePointer(NULL, State, (void *)READY);
}


/************************************************************************/
/* Function	   : delay_secs												*/
/* Purpose	   : Delay a number of seconds								*/
/* Inputs	   : Number of seconds to delay								*/
/* Outputs	   : None													*/
/* Comments    : Delay limited to 136 years								*/
/************************************************************************/
void delay_secs(Nat32 secs)
{
	Nat32	curDelay, secsRemaining;

	vTaskSetThreadLocalStoragePointer(NULL, State, (void *)DELAY);
	vTaskSetThreadLocalStoragePointer(NULL, StateParm, 
									  (void *)(xTaskGetTickCount() + (secs * TICKS_PER_SEC)));

	for (secsRemaining = secs; secsRemaining > 0; )
	{
		curDelay = (secsRemaining > MAX_TICK_SECS) ? MAX_TICK_SECS : secsRemaining;
		vTaskDelay(curDelay * TICKS_PER_SEC);
		secsRemaining -= curDelay;
	}

	vTaskSetThreadLocalStoragePointer(NULL, State, (void *)READY);

} /* delay_secs() */
