#ifndef _TASKSYNCHRONIZER_H
#define _TASKSYNCHRONIZER_H

#include "MicroDm.h"
#include "DeviceInterface.h"
#include "ErrorHandler.h"

///////////////////////////////////////////////////////////////////
// Task number identifiers
enum TaskNo 
{
  MicroAppTask = SRQ_TASK,
  MicroSamplerTask = IN_TASK,
  DmMonitorTask = OUT_TASK
};


/*
CLASS 
TaskSynchronizer

DESCRIPTION
Provides inter-task synchronization services

AUTHOR
Tom O'Reilly
*/
class TaskSynchronizer : public ErrorHandler
{
  public:
  
  ///////////////////////////////////////////////////////////////////
  // Constructor
  // [input] name: Name of synchronizer
  // [input] nTasks: Number of tasks to be synchronized (normally 3)
  // [input] microDm: MicroDm object
  // [input] device: DeviceInterface
  TaskSynchronizer(const char *name, 
		   unsigned nTasks,
		   MicroDm *microDm,
		   DeviceInterface *device
		   );

  ~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);  
  
  ///////////////////////////////////////////////////////////////////
  // Set state of device link
  // [input] state: Desired link state
  void setDeviceLinkState(DeviceInterface::LinkState state);
  
  ///////////////////////////////////////////////////////////////////
  // Return state of device link
  DeviceInterface::LinkState deviceLinkState();
  
  ///////////////////////////////////////////////////////////////////
  // Set configuration state of device
  // [input] state: Desired configuration state (TRUE or FALSE)
  void setDeviceConfigured(MBool state);

  ///////////////////////////////////////////////////////////////////
  // Call when device resets. Return 0 on success, -1 on error
  int handleDeviceReset();

  ///////////////////////////////////////////////////////////////////
  // Save pid of specified task
  // [input] taskNo: TaskNo of task
  // [input] pid: Pid of task
  int setTaskId(TaskNo taskNo, pid_t pid);
  
  ///////////////////////////////////////////////////////////////////
  // Return count of device resets
  int nDeviceResets();

  ///////////////////////////////////////////////////////////////////
  // Set whether resets will be broadcast or not (via DataManager)
  // [input] value: TRUE to broadcast reset info
  void broadcastResets(MBool value);
  
  protected:
  
  DeviceInterface::LinkState _deviceLinkState;
  MBool _deviceConfigured;

  struct TaskData
  {
    // Process (task) id
    pid_t pid;

    // Wakeup semaphore for task
    SEM_ID sem;
  };

  unsigned _nDeviceResets;
  MBool _broadcastResets;
  
  unsigned _nTasks;
  TaskData *_tasks;

  MicroDm *_microDm;
  DmBooleanObject *_dmCommError;
  DeviceInterface *_device;
};


#endif
