/************************************************************************/
/* 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};

MLocal char		*taskStateName[] = 
	{"Running", "Ready", "Blocked", "Suspended", "Deleted", "Invalid"};


/************************************************************************/
/* Function	   : taskKill												*/
/* Purpose	   : Kill a task, or perform exit routines					*/
/* Inputs	   : TaskHandle												*/
/* Outputs	   : None													*/
/************************************************************************/
void taskKill(TaskHandle_t td)
{
	if ((td != NULL) && (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;

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

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

	vTaskSetThreadLocalStoragePointer(NULL, ConsoleP, &dfltSerDesc);
	vTaskSetThreadLocalStoragePointer(NULL, DrvrP, NULL);
	vTaskSetThreadLocalStoragePointer(NULL, Malloc1, NULL);
	vTaskSetThreadLocalStoragePointer(NULL, Malloc2, NULL);

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

	taskKill(NULL);							/* Do exit routines, never rtns*/
}


/************************************************************************/
/* 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	   : delay_secs												*/
/* Purpose	   : Delay a number of secondss								*/
/* Inputs	   : Number of seconds to delay								*/
/* Outputs	   : None													*/
/************************************************************************/
void delay_secs(Nat32 secs)
{
	Nat32	curDelay, secsRemaining;

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

} /* delay_secs() */


/************************************************************************/
/* Function	   : getTaskStateName										*/
/* Purpose	   : Return string representing state of a task				*/
/* Inputs	   : eTaskState (can obtain from eTaskGetState())			*/
/* Outputs	   : String ptr												*/
/************************************************************************/
char *getTaskStateName(eTaskState state)
{
	if (state < NumberOf(taskStateName))
		return(taskStateName[state]);

	return("Unknown");

} /* getTaskStateName() */

