#include "MicroDm.h"

#ifndef UNIX
# define Boolean MBool
# include "msgQLib.h"
# include "sio32.h"
# include "sio32Server.h"
# include "sio32Client.h"
# include "microDm.h"
# include "ibc_card.h"
# include "filter.h"
# include "gf_board.h"
# include "vxUtils.h"
#endif

#include "microcmd.h"
#include "ibcDm.h"
#include "pduMicro.h"
#include "microDm.h"
#include "ersDcon.h"
#include "lightingDcon.h"
#include "powerIbc.h"
#include "vmeIbc.h"
#include "cameraDcon.h"
#include "sensorDcon.h"
#include "sonarDcon.h"
#include "gf_5vDm.h"
#include "moogdef.h"
#include "thrusterDM.h"
#include "acMicro.h"

DmIbcCardConfig::DmIbcCardConfig(const char *name)
  : DmObject(name, 1)
{
  _arraySize = IBC_MAX_CARDS + 1;
  createItem(DM_NAT16);
}

 
DmIbcCardConfig::~DmIbcCardConfig()
{
}


Errno DmIbcCardConfig::read(IbcCardConfig *config, DM_Time *t)
{
  return dm_read(_handle, (void *)config, sizeof(IbcCardConfig), t);
}


Errno DmIbcCardConfig::write(IbcCardConfig *config, DM_Time *t)
{
  return dm_write(_handle, (void *)config, sizeof(IbcCardConfig), t);
}



ComponentDmObjects::ComponentDmObjects(const char *name, const char *dmPrefix)
{
  if (name) 
    _name = strdup(name);
  else
  {
    setError("Null name specified");
    return;
  }
  
  if (dmPrefix) 
  {
    char prefix[MaxDmNameLen];
    strcpy(prefix, dmPrefix);
    // Ensure that prefix is terminated with '.'
    if (strlen(prefix) && *(prefix + strlen(prefix) - 1) != '.')
    {
      strcat(prefix, ".");
    }
    
    _dmPrefix = strdup(prefix);
  }
  else
  {
    setError("Null dmPrefix specified");
    return;
  }
}


ComponentDmObjects::~ComponentDmObjects()  
{
  if (_dmPrefix)
    free(_dmPrefix);

  if (_name)
    free(_name);
}


Errno ComponentDmObjects::startConsuming(Period period, SEM_ID wakeupSem)
{
  DmObject *dmObject;
  Errno err;
  
  for (int i = 0; i < _dmObjects.size(); i++)
  {
    _dmObjects.get(i, &dmObject);
    if ((err = dmObject->startConsume(period, wakeupSem)) != SUCCESS)
      return err;
  }
  return SUCCESS;
}


Errno ComponentDmObjects::startProviding(Period period)
{
  DmObject *dmObject;
  Errno err;
  
  for (int i = 0; i < _dmObjects.size(); i++)
  {
    _dmObjects.get(i, &dmObject);
    if ((err = dmObject->startProvide(period)) != SUCCESS)
      return err;
  }
  return SUCCESS;
}


DmObject *ComponentDmObjects::add(const char *name, DmObjectType type,
				  int len)
{
  DmObject *dmObject;
  char errorBuf[errorMsgSize];
  
  switch (type)
  {
    case DmEnumType:
    dmObject = new DmEnumObject(name);
    break;
    
    case DmBooleanType:
    dmObject = new DmBooleanObject(name);
    break;
    
    case DmNat16Type:
    dmObject = new DmNat16Object(name);
    break;
    
    case DmNat32Type:
    dmObject = new DmNat32Object(name);
    break;

    case DmInt16Type:
    dmObject = new DmInt16Object(name);
    break;
    
    case DmInt32Type:
    dmObject = new DmInt32Object(name);
    break;

    case DmFlt32Type:
    dmObject = new DmFlt32Object(name);
    break;
    
    case DmFlt64Type:
    dmObject = new DmFlt64Object(name);
    break;

    case DmEmptyType:
    dmObject = new DmEmptyObject(name);
    break;

    case DmStringType:
    dmObject = new DmStringObject(name, len);
    break;

    default:
    sprintf(errorBuf, "Unsupported DmObjectType: %d");
    setError(errorBuf);
    return NULL;
  }

  if (dmObject->error())
  {
    dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return NULL;
  }
  
  _dmObjects.add(&dmObject);
  return dmObject;
}


Gf5vDm::Gf5vDm(const char *name, const char *dmPrefix)
  : ComponentDmObjects(name, dmPrefix)
{
  if (error())
    return;
  
  char dmItemName[MaxDmNameLen];
  char errorBuf[errorMsgSize];
  
  strcpy(dmItemName, _dmPrefix);
  char *namePtr = dmItemName + strlen(dmItemName);

  DmObject *dmObject;
  
  strcpy(namePtr, GF_5V_SELFTEST_CMD_DM);
  dmObject = selfTestCmd = new DmEmptyObject(dmItemName);
  if (selfTestCmd->error())
  {
    selfTestCmd->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);
  
  strcpy(namePtr, GF_5V_SELFTEST_STATUS_DM);
  dmObject = selfTest = new DmEnumObject(dmItemName);
  if (selfTest->error())
  {
    selfTest->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);
  
  strcpy(namePtr, GF_5V_VICOR_VOLTAGE_DM);
  dmObject = vicorVoltage = new DmInt16Object(dmItemName);
  if (vicorVoltage->error())
  {
    vicorVoltage->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);

  strcpy(namePtr, GF_5V_OFFSET_CURRENT_DM);
  dmObject = offsetCurrent = new DmInt16Object(dmItemName);
  if (offsetCurrent->error())
  {
    offsetCurrent->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);

  strcpy(namePtr, GF_5V_ENABLE_DM);
  dmObject = scanEnabled = new DmBooleanObject(dmItemName);
  if (scanEnabled->error())
  {
    scanEnabled->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);
  
  for (int chan = 0; chan < N_GF5V_CHANNELS; chan++)
  {
    strcpy(namePtr, currentDmName(chan));
    
    dmObject = current[chan] = new DmInt16Object(dmItemName);
    if (current[chan]->error())
    {
      current[chan]->errorMsg(errorBuf);
      setError(errorBuf);
      return;
    }
    _dmObjects.add(&dmObject);

    strcpy(namePtr, chargeTimeDmName(chan));

    dmObject = chargeTime[chan] = new DmInt32Object(dmItemName);
    if (chargeTime[chan]->error())
    {
      chargeTime[chan]->errorMsg(errorBuf);
      setError(errorBuf);
      return;
    }
    _dmObjects.add(&dmObject);
  }

  strcpy(namePtr, GF_5V_CHAN_UPDATE_STATUS_DM);
  dmObject = sampledChannel = new DmInt16Object(dmItemName);
  if (sampledChannel->error())
  {
    sampledChannel->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);

  strcpy(namePtr, GF_5V_TEMPERATURE_DM);
  dmObject = temp = new DmInt16Object(dmItemName);
  if (temp->error())
  {
    temp->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);

  strcpy(namePtr, GF_5V_BUS_CAPACITANCE_DM);
  dmObject = busCapacitance = new DmNat16Object(dmItemName);
  if (busCapacitance->error())
  {
    busCapacitance->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);

  strcpy(namePtr, GF_5V_BUS_CAPACITOR_CURRENT_DM);
  dmObject = busCapacitorCurrent = new DmInt16Object(dmItemName);
  if (busCapacitorCurrent->error())
  {
    busCapacitorCurrent->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);
}


Gf5vDm::~Gf5vDm()
{
}


char *Gf5vDm::currentDmName(int chan)
{
  char *namePtr;
  
  switch (chan)
  {
    case 0:
    namePtr = GF_5V_CHAN0_FAULT_CURRENT_DM;
    break;
      
    case 1:
    namePtr = GF_5V_CHAN1_FAULT_CURRENT_DM;
    break;
      
    case 2:
    namePtr = GF_5V_CHAN2_FAULT_CURRENT_DM;
    break;
      
    case 3:
    namePtr = GF_5V_CHAN3_FAULT_CURRENT_DM;
    break;
  }  

  return namePtr;
}


char *Gf5vDm::currentAlarmDmName(int chan)
{
  char *namePtr;
  
  switch (chan)
  {
    case 0:
    namePtr = GF_5V_CHAN0_GF_ALARM_DM;
    break;
      
    case 1:
    namePtr = GF_5V_CHAN1_GF_ALARM_DM;
    break;
      
    case 2:
    namePtr = GF_5V_CHAN2_GF_ALARM_DM;
    break;
      
    case 3:
    namePtr = GF_5V_CHAN3_GF_ALARM_DM;
    break;
  }  

  return namePtr;
}


char *Gf5vDm::chargeTimeDmName(int chan)
{
  char *namePtr;
  
  switch (chan)
  {
    case 0:
    namePtr = GF_5V_CHAN0_CHARGE_TIME_DM;
    break;
      
    case 1:
    namePtr = GF_5V_CHAN1_CHARGE_TIME_DM;
    break;
      
    case 2:
    namePtr = GF_5V_CHAN2_CHARGE_TIME_DM;
    break;
      
    case 3:
    namePtr = GF_5V_CHAN3_CHARGE_TIME_DM;
    break;
  }  

  return namePtr;
}



MicroDm::MicroDm(const char *name, const char *dmPrefix)  
  : ComponentDmObjects(name, dmPrefix)
{
  if (error())
    return;
  
  char dmItemName[MaxDmNameLen];
  char errorBuf[errorMsgSize];
  
  strcpy(dmItemName, _dmPrefix);
  char *namePtr = dmItemName + strlen(dmItemName);
  DmObject *dmObject;
  
  strcpy(namePtr, MICRO_RESET_CMD_DM);
  resetCmd = new DmEmptyObject(dmItemName);
  dmObject = resetCmd;
  
  if (resetCmd->error())
  {
    resetCmd->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);
  
  strcpy(namePtr, MICRO_RESET_EVENT_DM);
  resetEvent = new DmEmptyObject(dmItemName);
  dmObject = resetEvent;

  if (resetEvent->error())
  {
    resetEvent->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }  
  _dmObjects.add(&dmObject);

  strcpy(namePtr, RAM_TEST_STATUS_DM);
  ramTestStatus = new DmBooleanObject(dmItemName);
  dmObject = ramTestStatus;
  
  if (ramTestStatus->error())
  {
    ramTestStatus->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }  
  _dmObjects.add(&dmObject);

  strcpy(namePtr, SOFTWARE_REV_DM);
  softwareRev = new DmStringObject(dmItemName, SOFTWARE_REV_LEN);
  dmObject = softwareRev;
  
  if (softwareRev->error())
  {
    softwareRev->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }  
  _dmObjects.add(&dmObject);

  strcpy(namePtr, MICRO_IDENT_DM);
  id = new DmStringObject(dmItemName, MICRO_ID_LEN);
  dmObject = id;
  
  if (id->error())
  {
    id->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }  
  _dmObjects.add(&dmObject);

  strcpy(namePtr, MICRO_SERIAL_NO_DM);
  microSerialNo = new DmStringObject(dmItemName, MICRO_SERNO_LEN);
  dmObject = microSerialNo;
  
  if (microSerialNo->error())
  {
    microSerialNo->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }  
  _dmObjects.add(&dmObject);
}


MicroDm::~MicroDm()  
{
}


IbcDm::IbcDm(const char *name, const char *dmPrefix)
  : MicroDm(name, dmPrefix)
{
  char dmItemName[MaxDmNameLen];
  char errorBuf[errorMsgSize];
  
  strcpy(dmItemName, _dmPrefix);
  char *namePtr = dmItemName + strlen(dmItemName);
  DmObject *dmObject;
  
  strcpy(namePtr, HUMIDITY_DM);
  dmObject = humidity = new DmNat16Object(dmItemName);
  if (humidity->error())
  {
    humidity->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);

  strcpy(namePtr, IBC_CARD_ERROR_DM);
  dmObject = cardError = new DmNat16Object(dmItemName);
  if (cardError->error())
  {
    cardError->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }  
  _dmObjects.add(&dmObject);
 
  strcpy(namePtr, IBC_CARD_CONFIG_DM);
  dmObject = cardConfig = new DmIbcCardConfig(dmItemName);
  if (cardConfig->error())
  {
    cardConfig->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);
  
  gf5vDm = new Gf5vDm("gf5vDm", _dmPrefix);
  if (gf5vDm->error())
  {
    gf5vDm->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
}


IbcDm::~IbcDm()
{
}  



ThreeByFiveDm::ThreeByFiveDm(const char *name, const char *dmPrefix)
  : MicroDm(name, dmPrefix)
{
  if (error())
    return;
  
  char dmItemName[MaxDmNameLen];
  char errorBuf[errorMsgSize];
  
  strcpy(dmItemName, _dmPrefix);
  char *namePtr = dmItemName + strlen(dmItemName);

  DmObject *dmObject;
  
  strcpy(namePtr, TEMPERATURE_DM);
  dmObject = microTemp = new DmInt16Object(dmItemName);
  if (microTemp->error())
  {
    microTemp->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);
}


ThreeByFiveDm::~ThreeByFiveDm()
{
}


Gf5vAlarmDm::Gf5vAlarmDm(const char *name, const char *dmPrefix)
  : ComponentDmObjects(name, dmPrefix)
{
  if (error())
    return;
  
  char dmItemName[MaxDmNameLen];
  char errorBuf[errorMsgSize];
  
  strcpy(dmItemName, _dmPrefix);
  char *namePtr = dmItemName + strlen(dmItemName);

  DmObject *dmObject;

  strcpy(namePtr, GF_5V_SELFTEST_STATUS_DM);
  dmObject = selfTest = new DmEnumObject(dmItemName);
  if (selfTest->error())
  {
    selfTest->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);

  strcpy(namePtr, GF_5V_TEMP_ALARM_DM);
  dmObject = temp = new DmEnumObject(dmItemName);
  if (temp->error())
  {
    temp->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);
  
  strcpy(namePtr, GF_5V_VICOR_VOLTAGE_ALARM_DM);
  dmObject = vicorVoltage = new DmEnumObject(dmItemName);
  if (vicorVoltage->error())
  {
    vicorVoltage->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);

  for (int chan = 0; chan < N_GF5V_CHANNELS; chan++)
  {
    strcpy(namePtr, currentDmName(chan));  
  }
  
}


Gf5vAlarmDm::~Gf5vAlarmDm()
{
}


char *Gf5vAlarmDm::currentDmName(int chan)
{
  char *namePtr;
  
  switch (chan)
  {
    case 0:
    namePtr = GF_5V_CHAN0_GF_ALARM_DM;
    break;
      
    case 1:
    namePtr = GF_5V_CHAN1_GF_ALARM_DM;
    break;
      
    case 2:
    namePtr = GF_5V_CHAN2_GF_ALARM_DM;
    break;
      
    case 3:
    namePtr = GF_5V_CHAN3_GF_ALARM_DM;
    break;
  }  

  return namePtr;
}


MicroAlarmDm::MicroAlarmDm(const char *name, const char *dmPrefix)
  : ComponentDmObjects(name, dmPrefix)
{
}


IbcAlarmDm::IbcAlarmDm(const char *name, const char *dmPrefix)
  : MicroAlarmDm(name, dmPrefix)
{
  if (error())
    return;
  
  char dmItemName[MaxDmNameLen];
  char errorBuf[errorMsgSize];
  
  strcpy(dmItemName, _dmPrefix);
  char *namePtr = dmItemName + strlen(dmItemName);

  DmObject *dmObject;

  strcpy(namePtr, HUMIDITY_WARN_THRESH_DM);
  dmObject = humidityWarnThreshold = new DmNat16Object(dmItemName);
  if (dmObject->error())
  {
    dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);

  strcpy(namePtr, HUMIDITY_ALARM_THRESH_DM);
  dmObject = humidityAlarmThreshold = new DmNat16Object(dmItemName);
  if (dmObject->error())
  {
    dmObject->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);

  strcpy(namePtr, HUMIDITY_ALARM_DM);
  dmObject = humidity = new DmEnumObject(dmItemName);
  if (humidity->error())
  {
    humidity->errorMsg(errorBuf);
    setError(errorBuf);
    return;
  }
  _dmObjects.add(&dmObject);
}
