#include "TaskControl.h"
#ifdef UNIX
# include <malloc.h>
#else
# include <stdlib.h>
#endif

TaskControl::TaskControl(const char *name, 
			 Nat16 nTasks,
			 MicroInterface *micro,
			 const char *microDmPrefix,
			 const char *powerDmItemName
			 )
{
  _microDm = new MicroDm(name, microDmPrefix);

  _microDm->resetEvent->startProvide(DM_STATIC);
  _microDm->ramTestStatus->startProvide(DM_STATIC);
  _microDm->softwareRev->startProvide(DM_STATIC);
  _microDm->id->startProvide(DM_STATIC);
  _microDm->microSerialNo->startProvide(DM_STATIC);
  
  _microIF = micro;

  if (initIOControl(nTasks, microDmPrefix, powerDmItemName) != OK)
  {
    setError("TaskControl::TaskControl() - initIOControl() failed");
    return;
  }
}


TaskControl::~TaskControl()
{
}


int TaskControl::wakeupTask(microTaskId task)
{
  semGive(_microIoControl.childTasks[task].taskSyncSem);
  return 0;
}


int TaskControl::wait(microTaskId thisTask, int timeout)
{
  semTake(_microIoControl.childTasks[thisTask].taskSyncSem, timeout);
  return 0;
}


int TaskControl::microResetCount()
{
  return _microIoControl.resetEventCount;
}


int TaskControl::microResetOccurred()
{
  Int trys;

  if (_microIoControl.announceResets)
  {
    // Write datamgr resetEvent item
    if (microResetEventDm(_microDm->resetEvent->getHandle()) == ERROR)
    {
      setError("microResetEventDm() failed");
    }
  }    

  // Mark serial com link as up
  setSerialLinkState(&_microIoControl, LINK_UP);

  // Try to enable IO channel
  for (trys = 0; trys < MICRO_ENABLE_TRYS; trys++)
  {
    if (microCmdEnable(&_microIoControl.sio32DataChan) != ERROR) 
      break;

    taskDelay(sysClkRateGet() / 5);
  }  

  if (trys >= MICRO_ENABLE_TRYS)
  {
    setSerialLinkState(&_microIoControl, LINK_DOWN);
    setError("Error Enabling Microcontroller\n");
    return ERROR;
  }

  // Initialize Micro datamanager items
  if (updateMicroIdentDm(&_microIoControl.sio32DataChan, 
			 _microDm->id->getHandle()) == ERROR)
  {
    setError("Error reading Identification String");
  }

  if (updateSerialNoDm(&_microIoControl.sio32DataChan,
		       _microDm->microSerialNo->getHandle()) == ERROR)
  {
    setError("Error reading Micro Serial Number");
  }
  
  if (updateSoftwareRevDm(&_microIoControl.sio32DataChan, 
			  _microDm->softwareRev->getHandle()) == ERROR)
  {
    setError("Error reading Software Revision");
  }

  if (updateMicroRamTestDm(&_microIoControl.sio32DataChan, 
			   _microDm->ramTestStatus->getHandle()) == ERROR)
  {
    setError("Error checking micro RAM Test");
  }
  
  return OK;
}


MBool TaskControl::microLinkUp()
{
  if (_microIoControl.serialLinkState == LINK_UP)
    return TRUE;
  else
    return FALSE;
}


serialComState TaskControl::microLinkState()
{
  return _microIoControl.serialLinkState;
}


void TaskControl::setMicroLinkState(serialComState state)
{
  setSerialLinkState(&_microIoControl, state);
}


switchStatus TaskControl::powerSwitchState()
{
  return microDevPowerSwitchState(&_microIoControl);
}


STATUS TaskControl::initIOControl(Nat16 numTasks,
				  const char *prefix, 
				  const char *powerDmItemName )
{
  Nat16 task;

  _microIoControl.powerSwitchDm   = NO_ITEM;
  _microIoControl.powerSwitchSem  = SEM_NULL;

  _microIoControl.resetEventCount = 0;
  _microIoControl.announceResets  = FALSE;
  _microIoControl.microConfigured = FALSE;
  _microIoControl.serialLinkState = LINK_DOWN;

  if ((_microIoControl.comErrorDm = 
       initMicroDmItem(prefix, COM_LINK_ERROR_DM, DM_MBOOL, 1)) 
      == ERROR) return ERROR;

  dm_start_provider (_microIoControl.comErrorDm, DM_STATIC);
  writeBooleanDmItem(_microIoControl.comErrorDm, FALSE);

  if (powerDmItemName != NULL)
  {				   /* Create Power Switch DM Item handle    */
    if ((_microIoControl.powerSwitchDm = 
	 initMicroDmItem("", (char *) powerDmItemName, DM_ENUM, 1)) 
	== ERROR) return ERROR;

    if ((_microIoControl.powerSwitchSem = 
	 semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == SEM_NULL)
      return ERROR;

    dm_start_consumer(_microIoControl.powerSwitchDm, DM_STATIC,
		      _microIoControl.powerSwitchSem);
  } /* if */

  memcpy(&_microIoControl.sio32DataChan, _microIF->serialChan(),
	 sizeof(sio32Chan));
  
  /* pean 10-25-96. Temporary fix to check  */
  /* if the micro is up and running         */
  if (microCmdEnable(&_microIoControl.sio32DataChan) == OK)
    _microIoControl.serialLinkState = LINK_UP;	

  numTasks--;			   /* Don't include parent SRQ Task         */
  _microIoControl.numChildTasks = numTasks;

  if ((_microIoControl.childTasks = (microChildTask *) 
       malloc(sizeof(microChildTask) * numTasks)) == (microChildTask *) NULL)
    return ERROR;

  for (task = 0; task < numTasks; task++)
  {                              /* Create task synchronization sem       */
    if ((_microIoControl.childTasks[task].taskSyncSem =  
	 semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == SEM_NULL)
    {
      free (_microIoControl.childTasks);
      return ERROR;
    } /* if */

    _microIoControl.childTasks[task].taskId = 0;
  } /* for */

  return OK;
  
} 
