#ifndef _TASKSYNCHRONIZER_H
#define _TASKSYNCHRONIZER_H

#include "eventobject.h"
#include "errorhandler.h"

///////////////////////////////////////////////////////////////////
// Task number identifiers
typedef enum TaskNo 
{
  MicroAppTask,
  MicroPeriodicTask,
  MicroEventTask
};

/*------------------------------------------------------------------
CLASS 
TaskSynchronizer

DESCRIPTION
Provides inter-task synchronization services

AUTHOR
Tom O'Reilly. Modified by D.Cline for the Genosensor project
Modifications not required for the LRS project.
------------------------------------------------------------------*/
class TaskSynchronizer: public ErrorHandler
{
  public:
  
  ///////////////////////////////////////////////////////////////////
  // Constructor
  // [input] name: Name of synchronizer
  // [input] nTasks: Number of tasks to be synchronized (normally 3)
  TaskSynchronizer(const char *name,  unsigned nTasks );

  ~TaskSynchronizer();
  
  ///////////////////////////////////////////////////////////////////
  // Give semaphore to specified task
  // [input] taskNo: TaskNo of recipient task
  int semGive(TaskNo taskNo);
  
  ///////////////////////////////////////////////////////////////////
  // Wait for wakeup call
  // [input] thisTaskNo: TaskNo of calling task  
  // [input] timeout: Timeout (clock ticks)
  int semTake(TaskNo thisTaskNo, int timeout = WAIT_FOREVER);  
  
  ///////////////////////////////////////////////////////////////////
  // Save pid of specified task
  // [input] taskNo: TaskNo of task
  // [input] pid: Pid of task
  int setTaskId(TaskNo taskNo, DWord pid);

  ///////////////////////////////////////////////////////////////////
  // Sets task shutdown 
  // This is called by the tasks just before they exit their 
  // TaskBase::run() methods
  void setTaskShutdown(TaskNo taskNo);

  ///////////////////////////////////////////////////////////////////
  // Wait for semaphore given by task just before exiting  
  void waitForShutdown(TaskNo taskNo, int timeout);
  
  ///////////////////////////////////////////////////////////////////
  // Sets task reset 
  // This is called by the tasks after they're reset and waiting for
  // wakeup
  void setTaskReset(TaskNo taskNo);

  ///////////////////////////////////////////////////////////////////
  // Wait for semaphore given by task just after reset
  void waitForReset(TaskNo taskNo, int timeout);
  
  ///////////////////////////////////////////////////////////////////  
  // Sets the shutdown variable to TRUE. This is used to break out of
  // the run methods of all tasks syncronized with the tasksyncronizer
  // d.cline added
  void shutdown();	 

  ///////////////////////////////////////////////////////////////////  
  // Sets the reset variable to <state>. This is used to break out of
  // the run methods of all tasks syncronized with the tasksyncronizer
  // d.cline added
  void reset(Boolean state);

  ///////////////////////////////////////////////////////////////////
  // d.cline added thread mutex class. Is used to lock critical sections
  // in the MicroEventHandler, and MicroPeriodicHandler classes.
  ThreadMutex  _mutex;		
   
  ///////////////////////////////////////////////////////////////////
  // If TRUE, shutdown all the tasks
  MBool _shutdown;		//d.cline added

  ///////////////////////////////////////////////////////////////////
  // If FALSE, reset all the tasks
  MBool _reset;			//d.cline added

  protected:
  
  struct TaskData
  {
    // Process (task) id
    DWord pid;

	// Wakeup semaphore for task
    BinarySemaphore *sem;

	// Shutdown semaphore for task
	BinarySemaphore *shutdownSem;

	// Reset semaphore for task
	BinarySemaphore *resetSem;
  };

  unsigned _nTasks;
  TaskData *_tasks;

};


#endif
