#include "IbcComponent.h"
#include "vxUtils.h"
#include "ibcItemNames.h"
#include "DmError.h"
#include "DmErrno.h"

extern "C"
{
# include "gf_5vDm.h"
# include "gf5vDef.h"
# include "gf_5v.h"
# include "lps.h"
# include "hps.h"
# include "vspCmd.h"
# include "vicorBoard.h"
# include "usrTime.h"
# include "ibc_cmd.h"
# include "ibc_card.h"
};

#define dprintf if (debug) logMsg

inline const char *IbcCard::name()
{
  return _name;
}

const char *IbcCard::_systemName = "";
const char *IbcCard::_appName = "";


IbcCard::IbcCard(const char *componentName,
		 Word cardAddr, sio32Chan *channel)
{
  _cardAddr = cardAddr;
  _sio32Chan = channel;

  char dmPrefix[MaxDmNameLen];
  sprintf(dmPrefix, "%s.%s.", _systemName, _appName);
  
  _dmPrefix = strdup(dmPrefix);
  _name = strdup(componentName);

  _microSampleMillisec = 500;
  
}


IbcCard::~IbcCard()
{
  free((void *)_dmPrefix);
  free((void *)_systemName);
  free((void *)_appName);
  free((void *)_name);
}


MBool IbcCard::isSwitchCard()
{
  return FALSE;
}


void IbcCard::setSampleInterval(Nat32 millisec)
{
  _microSampleMillisec = millisec;
}


Nat32 IbcCard::sampleInterval()
{
  return _microSampleMillisec;
}



void IbcCard::setSystemName(const char *systemName)
{
  _systemName = strdup(systemName);
}


void IbcCard::setAppName(const char *appName)
{
  _appName = strdup(appName);
}


const char *IbcCard::systemName()
{
  return _systemName;
}


const char *IbcCard::appName()
{
  return _appName;
}


Word IbcCard::cardAddr()
{
  return _cardAddr;
}


Gf5vCard::Gf5vCard(const char *componentName,
		   Word cardAddr, sio32Chan *channel, 
		   Int16 cardNo)

  : IbcCard(componentName, cardAddr, channel)
{
  bzero((char *)&dmItems, sizeof(dmItems));

  if (createIbcGf5vDmItems(&dmItems, _dmPrefix, _appName) != OK)
  {
    setError("Gf5vCard::Gf5vCard() - createIbcGf5vDmItems() failed");
    return;
    
#if 0
    throw IbcAppError(IbcAppError::DataMgr, _name, 
		      "Gf5vCard::Gf5vCard() - createIbcGf5vDmItems() failed");
#endif
  }
  initIbcGf5vAlarmProvider(&dmItems);
  handleResetEvent();

}


Gf5vCard::~Gf5vCard()
{
}



STATUS Gf5vCard::handleResetEvent()
{
  STATUS status = OK;
  
  updateIbcGf5vDmItems(_sio32Chan, _cardAddr, &dmItems, _appName);

  if (ibcGf5vSetChargeTimes(_sio32Chan, _cardAddr, &dmItems, 
			    LOW_VOLTAGE_GF_CHARGE_TIME, 
			    LOW_VOLTAGE_GF_CHARGE_TIME,
			    LOW_VOLTAGE_GF_CHARGE_TIME, 
			    LOW_VOLTAGE_GF_CHARGE_TIME) != OK)
  {
    setError("Gf5vCard::handleResetEvent() - "
	     "ibcGf5vSetChargeTimes() failed");

    status = ERROR;
    
#if 0    
    throw IbcAppError(IbcAppError::Micro, _name,
		      "Gf5vCard::handleResetEvent() - "
		      "ibcGf5vSetChargeTimes() failed");
#endif
  }
  

  if (enableGf5vMonitoring(_sio32Chan, _cardAddr, &dmItems, TRUE) != OK)
  {
    setError("Gf5vCard::handleResetEvent() - "
	     "enableGf5vMonitoring() failed");

    status = ERROR;
    
#if 0 
    throw IbcAppError(IbcAppError::Micro, _name,
		      "Gf5vCard::handleResetEvent() - "
		      "enableGf5vMonitoring() failed");
#endif

  }
  

  if (runGf5vBoardSelftest(_sio32Chan, _cardAddr, &dmItems) != OK)
  {
    setError("Gf5vCard::handleResetEvent() - runGf5vBoard() failed");
    status = ERROR;
    
#if 0
    throw IbcAppError(IbcAppError::Micro, _name,
		      "Gf5vCard::handleResetEvent() - "
		      "runGf5vBoard() failed");
#endif

  }
  
  return status;
}



STATUS Gf5vCard::startMonitoring(DmMonitor *dmMonitor)
{

  dmMonitor->addMonitoredItem(dmItems.gf_enable);
  dmMonitor->addMonitoredItem(dmItems.selftestCmd);
  dmMonitor->addMonitoredItem(dmItems.tempWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.tempAlarmThresh);
  dmMonitor->addMonitoredItem(dmItems.voltageWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.voltageAlarmThresh);
  dmMonitor->addMonitoredItem(dmItems.busCapacitance);
  dmMonitor->addMonitoredItem(dmItems.gfChan[0].chargeTime);
  dmMonitor->addMonitoredItem(dmItems.gfChan[1].chargeTime);
  dmMonitor->addMonitoredItem(dmItems.gfChan[2].chargeTime);
  dmMonitor->addMonitoredItem(dmItems.gfChan[3].chargeTime);
  return OK;
}


STATUS Gf5vCard::processDmChanges(DmGroup *dmGroup)
{
  MBool debug = FALSE;
  
  Int32 chargeTimes[GF_MAX_CHANS];
  Int16 tempWarn, tempAlarm;
  Int16 voltageWarn, voltageAlarm;
  Nat16 busCapacitance;
  MBool gfEnable;
  Errno err;
  
  if (!dmGroup->itemsChanged())
    return OK;

  if (dmGroup->itemChanged(dmItems.gf_enable))
  {
    dprintf("Gf5vCard::processDmChanges() - gf_enable changed\n");
    
    dm_read(dmItems.gf_enable, (char *) &gfEnable,
	    sizeof(gfEnable), (DM_Time *) NULL);

    IBC_gf5vEnableGf( _sio32Chan, _cardAddr, gfEnable);
  } 

  if (dmGroup->itemChanged(dmItems.selftestCmd))
  {
    dprintf("Gf5vCard::processDmChanges() - selftest changed\n");
    IBC_gf5vRunSelftest(_sio32Chan, _cardAddr);
  }

  /* GF/5V Card Temperature Thresholds    */
  if (dmGroup->itemChanged(dmItems.tempWarnThresh) ||
      dmGroup->itemChanged(dmItems.tempAlarmThresh))
  {
    dprintf("Gf5vCard::processDmChanges() - "
	    "temp alarm threshold()s changed\n");

    /* Read Temp Thresholds from DMgr    */
    dm_read(dmItems.tempWarnThresh, (char *) &tempWarn,
            sizeof(tempWarn), (DM_Time *) NULL);

    dm_read(dmItems.tempAlarmThresh, (char *) &tempAlarm,
            sizeof(tempAlarm), (DM_Time *) NULL);

    IBC_gf5vSetTempThresh( _sio32Chan, _cardAddr, tempWarn, tempAlarm);
  } 

  /* GF/5V Card Voltage Thresholds        */
  if (dmGroup->itemChanged(dmItems.voltageWarnThresh) ||
      dmGroup->itemChanged(dmItems.voltageAlarmThresh))

  {
    dprintf("Gf5vCard::processDmChanges() - "
	    "voltage alarm thresholds changed\n");

    /* Read Voltage Thresholds from DMgr */
    dm_read(dmItems.voltageWarnThresh, (char *) &voltageWarn,
            sizeof(voltageWarn), (DM_Time *) NULL);

    dm_read(dmItems.voltageAlarmThresh, (char *) &voltageAlarm,
            sizeof(voltageAlarm), (DM_Time *) NULL);

    IBC_gf5vSetVoltageThresh( _sio32Chan, _cardAddr,
			     voltageWarn, voltageAlarm );
  } 

  if (dmGroup->itemChanged(dmItems.busCapacitance))
  {
    dprintf( 
	    "Gf5vCard::processDmChanges() - bus capacitance changed\n");

    dm_read(dmItems.busCapacitance, (char *) &busCapacitance,
            sizeof(busCapacitance), (DM_Time *) NULL);

    IBC_gf5vSetBusCapacitance( _sio32Chan, _cardAddr, busCapacitance );
  } 

  /* GF/5V Card Charge Up Times           */

  if (dmGroup->itemChanged(dmItems.gfChan[0].chargeTime) ||
      dmGroup->itemChanged(dmItems.gfChan[1].chargeTime) ||
      dmGroup->itemChanged(dmItems.gfChan[2].chargeTime) ||
      dmGroup->itemChanged(dmItems.gfChan[3].chargeTime))
  {
    dprintf( 
	    "Gf5vCard::processDmChanges() - chargetime(s) changed\n");

    /* Read Charge Times from DMgr          */
    dm_read(dmItems.gfChan[0].chargeTime, (char *) &chargeTimes[0],
            sizeof(chargeTimes[0]), (DM_Time *) NULL);

    dm_read(dmItems.gfChan[1].chargeTime, (char *) &chargeTimes[1],
            sizeof(chargeTimes[1]), (DM_Time *) NULL);

    dm_read(dmItems.gfChan[2].chargeTime, (char *) &chargeTimes[2],
            sizeof(chargeTimes[2]), (DM_Time *) NULL);

    dm_read(dmItems.gfChan[3].chargeTime, (char *) &chargeTimes[3],
            sizeof(chargeTimes[3]), (DM_Time *) NULL);

    IBC_gf5vSetChargeTimes( _sio32Chan, _cardAddr, chargeTimes );
  }

  return OK;
}


MBool Gf5vCard::handleSrq(Word requestCode, Byte *packet)
{
  return processIbcGf5vSRQ(requestCode, packet, _cardAddr, &dmItems);
}


STATUS Gf5vCard::handleResetSrq()
{
  return updateIbcGf5vAlarmsDm(_sio32Chan, _cardAddr, &dmItems);
}


STATUS Gf5vCard::startSampling()
{
  initIbcGf5vProvider(&dmItems, _microSampleMillisec * 1000);
  return OK;
}


STATUS Gf5vCard::sampleMicro()
{
  return updateNewIbcGf5vDm(_sio32Chan, _cardAddr, &dmItems);
}


IBC_BoardType Gf5vCard::type()
{
  return GROUND_FAULT;
}


CpuCard::CpuCard(const char *componentName,
		 Word cardAddr, sio32Chan *channel,
		 ibcCardConfig *cardConfig)
 
  : IbcCard(componentName, cardAddr, channel)
{
  bzero((char *)&dmItems, sizeof(dmItems));

  if (createIbcCpuDmItems(&dmItems, _dmPrefix, _appName) != OK)
  {
    setError("CpuCard::CpuCard() - createIbcCpuDmItems() failed");
    return;

#if 0
    throw IbcAppError(IbcAppError::DataMgr, _name,
		      "CpuCard::CpuCard() - createIbcCpuDmItems() failed");
#endif

  }
  _cardConfig = cardConfig;
}


CpuCard::~CpuCard()
{
}


STATUS CpuCard::handleResetEvent()
{
  return initIbcHumidityThreshDm(_sio32Chan, 
				 dmItems.humidityWarnThresh,
				 dmItems.humidityAlarmThresh);
}


MBool CpuCard::handleSrq(Word requestCode, Byte *packet)
{
  return processIbcCpuSRQ(requestCode, packet, &dmItems);
}


STATUS CpuCard::handleResetSrq()
{
  return initIbcCpuDmItems(&dmItems, _sio32Chan, _appName, *_cardConfig);
}


STATUS CpuCard::startMonitoring(DmMonitor *dmMonitor)
{
  dmMonitor->addMonitoredItem(dmItems.microDm.resetEvent);
  dmMonitor->addMonitoredItem(dmItems.microDm.resetCmd);
  dmMonitor->addMonitoredItem(dmItems.humidityWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.humidityAlarmThresh);
  return OK;
}


STATUS CpuCard::processDmChanges(DmGroup *dmGroup)
{
  MBool debug = FALSE;
  
  if (!dmGroup->itemsChanged())
    return OK;
  
  STATUS status = OK;
  
  if (dmGroup->itemChanged(dmItems.humidityWarnThresh) ||
      dmGroup->itemChanged(dmItems.humidityAlarmThresh))
  {
    dprintf("CpuCard::processDmChanges() - "
	    "humidity alarm threshold(s) changed\n");

    status = writeIbcHumidityThresh(_sio32Chan, 
				    dmItems.humidityWarnThresh,
				    dmItems.humidityAlarmThresh);
  }
  return status;
}


STATUS CpuCard::startSampling()
{
  initIbcCpuProvider(&dmItems, _microSampleMillisec * 1000);
  return OK;
}


STATUS CpuCard::sampleMicro()
{
  return updateIbcHumidityDm(_sio32Chan, dmItems.microHumidity);
}



IBC_BoardType CpuCard::type()
{
  return CPU196;
}


QuadSerialCard::QuadSerialCard(const char *componentName,
			       Word cardAddr, sio32Chan *channel, 
			       Int16 cardNo)

  : IbcCard(componentName, cardAddr, channel)
{
  for (int i = 0; i < 4; i++)
    _serialDevices[i] = 0;

  bzero((char *)&dmItems, sizeof(dmItems));

  if (createIbcQuadSerDmItems(&dmItems, _dmPrefix, _appName, cardNo) != OK)
  {
    setError("QuadSerialCard::QuadSerialCard() - "
	     "createIbcQuadSerDmItems() failed");
    return;
    
#if 0
    throw IbcAppError(IbcAppError::DataMgr, _name,
		      "QuadSerialCard::QuadSerialCard() - "
		      "createIbcQuadSerDmItems() failed");
#endif

  }

  initIbcQuadSerAlarmProvider(&dmItems);
  handleResetEvent();
}


QuadSerialCard::~QuadSerialCard()
{
}


STATUS QuadSerialCard::addDevice(SerialDevice *device, unsigned int channelNo)
{
  if (channelNo > 3) {
    setError("QuadSerialCard::addDevice() - invalid channel number");
    return ERROR;
  }

  if (_serialDevices[channelNo] != 0) {
    setError("QuadSerialCard::addDevice() - channel already occupied");
    return ERROR;
  }

  _serialDevices[channelNo] = device;
}


STATUS QuadSerialCard::handleResetEvent()
{
//  return updateIbcQuadSerItems(_sio32Chan, _cardAddr, &dmItems);
  
  for (int i = 0; i < 4; i++) {
    if (_serialDevices[i])
      _serialDevices[i]->handleResetEvent();
  }

  return OK;
}


STATUS QuadSerialCard::startMonitoring(DmMonitor *dmMonitor)
{
  for (int i = 0; i < 4; i++) {
    if (_serialDevices[i])
      _serialDevices[i]->startMonitoring(dmMonitor);
  }

  return OK;
}


STATUS QuadSerialCard::processDmChanges(DmGroup *dmGroup)
{
  for (int i = 0; i < 4; i++) {
    if (_serialDevices[i])
      _serialDevices[i]->processDmChanges(dmGroup);
  }

  return OK;
}


STATUS QuadSerialCard::startSampling()
{
  for (int i = 0; i < 4; i++) {
    if (_serialDevices[i])
      _serialDevices[i]->startSampling();
  }

  return OK;
}


STATUS QuadSerialCard::sampleMicro()
{
  for (int i = 0; i < 4; i++) {
    if (_serialDevices[i])
      _serialDevices[i]->sampleMicro();
  }

  return OK;
}


STATUS QuadSerialCard::handleResetSrq()
{
  for (int i = 0; i < 4; i++) {
    if (_serialDevices[i])
      _serialDevices[i]->handleResetSrq();
  }

  return updateIbcQuadSerAlarmsDm(_sio32Chan, _cardAddr, &dmItems);
}


MBool QuadSerialCard::handleSrq(Word requestCode, Byte *packet)
{
  for (int i = 0; i < 4; i++) {
    if (_serialDevices[i])
      _serialDevices[i]->handleSrq(requestCode, packet);
  }

  return processIbcQuadSerSRQ(requestCode, packet, _cardAddr, &dmItems);
}


IBC_BoardType QuadSerialCard::type()
{
  return QUAD_SERIAL;
}



AtoDChannel::AtoDChannel(const char *name, 
			 Flt32 (*scaleFunction)(Word data),
			 IbcCard *parent)
{
  char itemName[MaxDmNameLen];
  
  sprintf(itemName, "%s.%s.%s.%s", 
	  parent->systemName(), parent->appName(), parent->name(), name);

  dmObject = new DmFlt32Object(itemName);
  scaleValue = scaleFunction;
}


AtoDChannel::~AtoDChannel()
{
}


QuadAtoDCard::QuadAtoDCard(const char *name, Word cardAddr, 
			   sio32Chan *channel, Word getAtoDCmd)
  : IbcCard(name, cardAddr, channel)
{
  _getAtoDCmd = getAtoDCmd;
}


QuadAtoDCard::~QuadAtoDCard()
{
}


AtoDChannel *QuadAtoDCard::addChannel(const char *name, 
				      Flt32 (*scaleFunction)(Word data))
{
  if (_aToDChannels.size() >= 4)
  {
    // Already defined max number of channels
    setError("Too many channels");  
    return NULL;
  }
  
  AtoDChannel *channel = new AtoDChannel(name, scaleFunction, this);
  _aToDChannels.add((void **)&channel);
  
  return channel;
}



STATUS QuadAtoDCard::handleResetEvent()
{
  return OK;
}


STATUS QuadAtoDCard::startMonitoring(DmMonitor *dmMonitor)
{
  return OK;
}


STATUS QuadAtoDCard::processDmChanges(DmGroup *dmGroup)
{
  return OK;
}


STATUS QuadAtoDCard::startSampling()
{
  AtoDChannel *aToDChannel;
  
  for (int i = 0; i < _aToDChannels.size(); i++)
  {
    _aToDChannels.get(i, (void **)&aToDChannel);
    aToDChannel->dmObject->startProvide(_microSampleMillisec * 1000);
  }
}


STATUS QuadAtoDCard::sampleMicro()
{
  MBool debug = FALSE;
  
  Word reply[6];
  
  char errorBuf[errorMsgSize];
  
  dprintf("QuadAtoDCard::sampleMicro()\n");

  if (sendMicroCommand(_sio32Chan, &reply, sizeof(Word)*6, 2, 
		       IBC_CPU_APP | ADC_READ_VALUES, _cardAddr) == ERROR)
  {
    logMsg("QuadAtoDCard::sampleMicro() - "
	   "sendMicroCommand() returned error\n");
    
    return ERROR;
  }

  Word status;
  
  if ((status = wordFromBuf(&reply, 0)) != CMD_OK)
  {
    sprintf(errorBuf, "QuadAtoDCard::sampleMicro() - "
	    "wordFromBuf() returned %d\n", status);

    setError(errorBuf);
    logMsg(errorBuf);
    return ERROR;
  }    

  Int16 cmdStatus;
  Word data[4];
  Int16 nChannels;
  
  wordsFromBuf(reply, 6, &cmdStatus, &nChannels,
	       &data[0], &data[1], &data[2], &data[3]);

  DM_Time t;
  gettimeofday(&t, NULL);
  
  dprintf("QuadAtoDCard::sampleMicro() - %d channels\n", 
	  _aToDChannels.size());

  for (int i = 0; i < _aToDChannels.size(); i++)
  {
    AtoDChannel *aToDChannel;
    _aToDChannels.get(i, (void **)&aToDChannel);
    Flt32 value = aToDChannel->scaleValue(data[i]);
    Errno err;
    if ((err = aToDChannel->dmObject->write(value, &t)) != SUCCESS)
    {
      char errorBuf[errorMsgSize];
      sprintDmError(err, "QuadAtoDCard::sampleMicro()", errorBuf);
      logMsg(errorBuf);
    }
  }

  return OK;
}


MBool QuadAtoDCard::handleSrq(Word requestCode, Byte *packet)
{
  return FALSE;
}


STATUS QuadAtoDCard::handleResetSrq()
{
  return OK;
}


IBC_BoardType QuadAtoDCard::type()
{
  return QUAD_A_TO_D;
}



SwitchCard::SwitchCard(const char *componentName,
		       sio32Chan *channel)

  : IbcCard(componentName, 0, channel)
{
  _maxChannels = 1;
}



SwitchCard::SwitchCard(const char *componentName,
		       Word cardAddr,
		       sio32Chan *channel,
		       SwitchChannel *parent,         
		       SystemBus bus,
		       LoadDivision division)

  : IbcCard(componentName, cardAddr, channel)
{
  _parentSwitch = parent;
  _bus = bus;
  _loadDivision = division;
  _maxChannels = 1;
}


SwitchCard::~SwitchCard()
{
  for (int i = 0; i < _switchChannels.size(); i++)
  {
    SwitchChannel *switchChannel;
    _switchChannels.get(i, (void **)&switchChannel);
    delete switchChannel;
  }
}


MBool SwitchCard::isSwitchCard()
{
  return TRUE;
}


SwitchChannel *SwitchCard::addChannel(const char *channelName,
				      Nat16 power,
				      SwitchMethod switchMethod,
				      SwitchStatus defaultStatus,
				      Nat16 channelNo,
				      SwitchChannel *parent)
{
  if (_switchChannels.size() >= _maxChannels)
  {
    logMsg("SwitchCard::addChannel() - "
	   "card %s, channel %s, already have %d channels\n", 
	   name, channelName, _switchChannels.size());
	   
    setError("Too many channels");
    return NULL;

#if 0    
    throw IbcAppError(IbcAppError::MaxChannels, _name,
		      "SwitchCard::addChannel()");
#endif
  }
  
  SwitchChannel *switchChannel = new SwitchChannel(channelName);
  switchChannel->_cardAddr = _cardAddr;
  switchChannel->_bus = _bus;
  switchChannel->_power = power;
  switchChannel->_division = _loadDivision;
  switchChannel->_defaultStatus = defaultStatus;
  switchChannel->_channelNo = channelNo;
  switchChannel->_switchMethod = switchMethod;

  if (parent)
    switchChannel->_parent = &parent->_entry;
  else
    switchChannel->_parent = NULL;
  
  _switchChannels.add((void **)&switchChannel);

  return switchChannel;
}


STATUS SwitchCard::buildSwitch(SEM_ID dmUpdateSem, SEM_ID powerStatusSem,
			       PowerNameGenerator *nameGenerator)
{
  MBool debug = FALSE;
  
  STATUS status = OK;
    
  dprintf("**** Building switch ****%s\n", name());
  
  for (int i = 0; i < _switchChannels.size(); i++)
  {
    SwitchChannel *switchChannel;
    _switchChannels.get(i, (void **)&switchChannel);

    if (nameGenerator)
      nameGenerator->addChannel(switchChannel->name());

    dprintf("SwitchCard::buildSwitch() - build switch \"%s\"\n",
	    switchChannel->name());

    dprintf("SwitchCard::buildSwitch() - parent=%x\n", 
	    switchChannel->_parent);
      
    dprintf("SwitchCard::buildSwitch() - &switchChannel->_entry=%x\n", 
	    &switchChannel->_entry);

    char dmPrefix[MaxDmNameLen];

#if 0
    // NOTE: Use this prefix once powermanager is upgraded
    sprintf(dmPrefix, "%s.%s.%s.%s.%s", 
	    _systemName, PowerMgrAppName, _appName, _name,
	    switchChannel->name()); 

#endif
    

    // NOTE: Old powerDM.h file does NOT include switch card name in 
    // DM item name, only switch channel name
    sprintf(dmPrefix, "%s.%s.%s.%s", 
	    _systemName, PowerMgrAppName, _appName, 
	    switchChannel->name()); 

    char reqName[MaxDmNameLen];
    char statusName[MaxDmNameLen];
    char powerReqName[MaxDmNameLen];
    char powerStatusName[MaxDmNameLen];
    char powerOkName[MaxDmNameLen];

    sprintf(reqName, "%s.%s", dmPrefix, PowerSwitchReqName);
    sprintf(statusName, "%s.%s", dmPrefix, PowerSwitchStatusName);
    sprintf(powerReqName, "%s.%s", dmPrefix, PowerMgrReqName);
    sprintf(powerOkName, "%s.%s", dmPrefix, PowerMgrOkName);

    Errno err;
    char errorBuf[errorMsgSize];
    char descrip[100];
    sprintf(descrip, "%s %s", _appName, _name);
  
    if (initIbcSwitchEntry(&switchChannel->_entry, 
			   _sio32Chan, 
			   switchChannel->_power, 
			   (systemBus )_bus,
			   (loadDivision )_loadDivision, 
			   type(), 
			   _cardAddr, 
			   switchChannel->_channelNo,
			   reqName, statusName, dmUpdateSem,
			   powerReqName, powerOkName, powerStatusSem, 
			   _appName, descrip) != OK)
    {
      logMsg("SwitchCard::buildSwitch() - initIbcSwitchEntry() failed\n");
      status = ERROR;
    }

    if ((err = connectSwitchItems(switchChannel)) != OK)
    {
      sprintDmError(err, "SwitchCard::buildSwitch(), connectSwitchItems()",
		    errorBuf);
      
      logMsg("%s\n", errorBuf);
      status = ERROR;
    }
  
    if (switchChannel->_parent)
    {
      ibcAddSwitchInSeries(switchChannel->_parent,
			   &switchChannel->_entry);
    }  
    switchChannel->_built = TRUE;
  }
  
  return status;
}


STATUS SwitchCard::startMonitoring(DmMonitor *dmMonitor)
{
  MBool debug = FALSE;
  dprintf("SwitchCard::startMonitoring() - card %s, %d channels\n",
	  name(), _switchChannels.size());
  
  for (int i = 0; i < _switchChannels.size(); i++)
  {
    SwitchChannel *switchChannel;
    _switchChannels.get(i, (void **)&switchChannel);
    
    if (!switchChannel->_built)
      return ERROR;

    dmMonitor->addMonitoredItem(switchChannel->_entry.switchRequestDm);
  }
  
  return OK;
}


STATUS SwitchCard::processDmChanges(DmGroup *dmGroup)
{
  MBool debug = FALSE;
  
  for (int i = 0; i < _switchChannels.size(); i++)
  {
    SwitchChannel *switchChannel;
    _switchChannels.get(i, (void **)&switchChannel);

    if (!switchChannel->_built)
      return ERROR;

    if (switchChannel->_switchMethod == SwitchedByFramework &&
	dmGroup->itemChanged(switchChannel->_entry.switchRequestDm))
    {
      dprintf("SwitchCard::processDmChanges() - "
	      "switch req from \"%s\"\n", switchChannel->name());

      ibcProcessSwitchRequest(&switchChannel->_entry);
    }
  }
  return OK;
}


STATUS SwitchCard::setDefaultStatus()
{
  if (type() == NULL_IBC_BOARD)
    // Don't do anything to ExternalSwitch
    return OK;
  
  for (int i = 0; i < _switchChannels.size(); i++)
  {
    SwitchChannel *switchChannel;
    _switchChannels.get(i, (void **)&switchChannel);

    if (!switchChannel->_built)
      return ERROR;
    
    switchChannel->set(switchChannel->defaultStatus());
  }
}


int SwitchCard::nSwitchChannels()
{
  return _switchChannels.size();
}


SwitchChannel *SwitchCard::switchChannel(unsigned i)
{
  if (i >= _switchChannels.size())
    return NULL;
  
  SwitchChannel *switchChannel;
  _switchChannels.get(i, (void **)&switchChannel);
  return switchChannel;
}


SwitchChannel::SwitchChannel(const char *name)
{
  _name = strdup(name);
  _built = FALSE;
}


SwitchChannel::~SwitchChannel()
{
  free((void *)name);
}


const char *SwitchChannel::name()
{
  return _name;
}


MBool SwitchChannel::newRequest(DmGroup *dmGroup)
{
  return dmGroup->itemChanged(_entry.switchRequestDm);
}


switchEntry *SwitchChannel::entry()
{
  return &_entry;
}


void SwitchChannel::set(SwitchStatus request, MBool viaSwitchRequest)
{
  if (!viaSwitchRequest && request == SwitchOff)
    ibcSetSwitchStateOff(&_entry);
  else
    ibcSetSwitchState(&_entry, (switchStatus )request);
}


void SwitchChannel::switchOn(MBool bypassSwitchRequest)
{
  set(SwitchOn, bypassSwitchRequest);
}


void SwitchChannel::switchOff(MBool bypassSwitchRequest)
{
  set(SwitchOff, bypassSwitchRequest);
}


void SwitchChannel::processSwitchRequest()
{
  ibcProcessSwitchRequest(&_entry);
}


STATUS SwitchChannel::setThresholdsDm(Int16 warningThreshold,
				    Int16 alarmThreshold)
{
  urgentWriteDmItem(_entry.currentWarnThreshDm,
		    &warningThreshold, sizeof(warningThreshold));

  urgentWriteDmItem(_entry.currentAlarmThreshDm,
		    &alarmThreshold, sizeof(alarmThreshold));

  return OK;
}


STATUS SwitchChannel::setThresholds(Int16 warningThreshold,
				    Int16 alarmThreshold)
{
  return ibcSwitchSetCurrentThresh(&_entry, 
				   warningThreshold, alarmThreshold);
}


SwitchStatus SwitchChannel::request()
{
  DM_Time t;

  switchStatus request;

  Errno err;
  
  if ((err = dm_read(_entry.switchRequestDm, &request, sizeof(request), &t)) 
      != SUCCESS)
  {
    char errorBuf[errorMsgSize];
    sprintDmError(err, "SwitchChannel::request(), dm_read()", errorBuf);
    logMsg(errorBuf);
    return SwitchOff;
  }
  
  return (SwitchStatus )request;
}


SwitchStatus SwitchChannel::status()
{
  DM_Time t;

  switchStatus status;

  Errno err;
  
  if ((err = dm_read(_entry.switchStatusDm, &status, sizeof(status), &t)) 
      != SUCCESS)
  {
    char errorBuf[errorMsgSize];
    sprintDmError(err, "SwitchChannel::status(), dm_read()", errorBuf);
    logMsg(errorBuf);
    return SwitchOff;
  }
  
  return (SwitchStatus )status;
}


SwitchStatus SwitchChannel::defaultStatus()
{
  return _defaultStatus;
}


ExternalSwitch::ExternalSwitch(const char *componentName,
			       const char *switchReqName,     
			       const char *switchStatusName,  
			       sio32Chan *channel)

: SwitchCard(componentName, channel)

{
  MBool debug = FALSE;
  
  _switchReqName = strdup(switchReqName);
  _switchStatusName = strdup(switchStatusName);

  _switchChannel = addChannel(componentName, 
			      0, 
			      SwitchedByFramework,
			      SwitchOn,
			      0,
			      NULL);

  dprintf("ExternalSwitch::ExternalSwitch(), name %s, #chan=%d\n",
	  name(), _switchChannels.size());
}


ExternalSwitch::~ExternalSwitch()
{
  free((void *)_switchReqName);
  free((void *)_switchStatusName);
}


STATUS ExternalSwitch::handleResetEvent()
{
  return OK;
}


STATUS ExternalSwitch::buildSwitch(SEM_ID dmUpdateSem, 
				   SEM_ID powerStatusSem,
				   PowerNameGenerator *nameGenerator)
{
  MBool debug = FALSE;
  
  char descrip[100];
  sprintf(descrip, "%s %s", _appName, _name);
  
  dprintf("ExternalSwitch::buildSwitch() - "
	  "reqName=%s, statusName=%s\n",
	  _switchReqName, _switchStatusName);

  if (duplicateIbcSwitchEntry(&_switchChannel->_entry,
			      (char *)_switchReqName, 
			      (char *)_switchStatusName, 
			      dmUpdateSem,
			      _appName, descrip) != OK)
  {
    logMsg("ExternalSwitch::buildSwitch() - "
	   "duplicateIbcSwitchEntry() failed\n");
    
    return ERROR;
  }

  _switchChannel->_built = TRUE;
  return OK;
}


STATUS ExternalSwitch::processDmChanges(DmGroup *dmGroup)
{
  MBool debug = FALSE;
  
  dprintf("ExternalSwitch::processDmChanges(), switch %s, #channels=%d\n", 
	  name(), _switchChannels.size());
  
  if (!_switchChannel->_built)
  {
    logMsg("ExternalSwitch::processDmChanges() - switch channel not built\n");
    return ERROR;
  }
  
  if (dmGroup->itemChanged(_switchChannel->_entry.switchRequestDm))
  {
    dprintf("ExternalSwitch::processDmChanges() - "
	    "switch req detected\n");
    
    ibcProcessDupSwitchRequest(&_switchChannel->_entry);
  }
  else
    dprintf("ExternalSwitch::processDmChanges() - no change\n");
  
  return OK;
}


STATUS ExternalSwitch::startSampling()
{
  return OK;
}


STATUS ExternalSwitch::sampleMicro()
{
  return OK;
}


MBool ExternalSwitch::handleSrq(Word requestCode, Byte *packet)
{
  // SRQ doesn't originate in external switch
  return FALSE;
}


STATUS ExternalSwitch::handleResetSrq()
{
  return OK;
}


STATUS ExternalSwitch::connectSwitchItems(SwitchChannel *channel)
{
  return OK;
}


SwitchChannel *ExternalSwitch::switchChannel()
{
  return _switchChannel;
}


IBC_BoardType ExternalSwitch::type()
{
  return NULL_IBC_BOARD;
}



MultiSwitchCard::MultiSwitchCard(const char *componentName,
				 Word cardAddr,
				 sio32Chan *channel,
				 SwitchChannel *parent,         
				 SystemBus bus,
				 LoadDivision division)

  : SwitchCard(componentName, cardAddr, channel, parent, bus, division)
{
  _channelParent = _parentSwitch;
  _nAddedChannels = 0;
}


MultiSwitchCard::~MultiSwitchCard()
{
}


SwitchChannel *MultiSwitchCard::addChannel(const char *name,
					   Nat16 power,
					   SwitchMethod switchMethod,
					   SwitchStatus defaultStatus)
{
  MBool debug = FALSE;
  dprintf("MultiSwitchCard::addChannel() - \"%s\": _channelParent=%x\n",
	  _name, _channelParent);
  
  return SwitchCard::addChannel(name, power, switchMethod, defaultStatus, 
				_nAddedChannels++, _channelParent); 
}

				   


LpsCard::LpsCard(const char *componentName,
		 Word cardAddr,
		 sio32Chan *channel,
		 Int16 cardNo,
		 SwitchChannel *parent,         
		 SystemBus bus,
		 LoadDivision division)

  : MultiSwitchCard(componentName, cardAddr, channel, parent, bus, division)
{
  bzero((char *)&dmItems, sizeof(dmItems));

  if (createIbcLpsDmItems(&dmItems, _dmPrefix, _appName, cardNo) != OK)
  {
    setError("LpsCard::LpsCard() - createIbcLpsDmItems() failed");
    return;
    
#if 0
    throw IbcAppError(IbcAppError::DataMgr, _name,
		      "LpsCard::LpsCard() - createIbcLpsDmItems() failed");
#endif
  }

  _maxChannels = 4;

  initIbcLpsAlarmProvider(&dmItems);
  handleResetEvent();
}


LpsCard::~LpsCard()
{
}


STATUS LpsCard::handleResetEvent()
{
  // Read LPS parameters from IBC and update DM
  updateIbcLpsDmItems(_sio32Chan, _cardAddr, &dmItems, _appName);

  return OK;
}


STATUS LpsCard::connectSwitchItems(SwitchChannel *channel)
{
  MBool debug = FALSE;

  char currentName[MaxDmNameLen];
  char currentAlarmName[MaxDmNameLen];
  char currentWarnThreshName[MaxDmNameLen];
  char currentAlarmThreshName[MaxDmNameLen];

  sprintf(currentName, "%s.%s.%s", 
	  _appName, channel->name(), SwitchCurrentName);
                 
  sprintf(currentAlarmName, "%s.%s.%s", 
	  _appName, channel->name(), SwitchCurrentAlarmName);

  sprintf(currentWarnThreshName, "%s.%s.%s", 
	  _appName, channel->name(), SwitchCurrentWarnThreshName);

  sprintf(currentAlarmThreshName, "%s.%s.%s", 
	  _appName, channel->name(), SwitchCurrentAlarmThreshName);
  
  return ibcConnectLpsDmItems(&dmItems, channel->entry(), 
			      _appName, channel->name(),
			      channel->entry()->channel, 
			      currentName, currentAlarmName,
			      currentWarnThreshName, currentAlarmThreshName);
}


STATUS LpsCard::startMonitoring(DmMonitor *dmMonitor)
{
  STATUS status = SwitchCard::startMonitoring(dmMonitor);
    
  dmMonitor->addMonitoredItem(dmItems.sw0CurrentWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.sw0CurrentAlarmThresh);
  dmMonitor->addMonitoredItem(dmItems.sw1CurrentWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.sw1CurrentAlarmThresh);
  dmMonitor->addMonitoredItem(dmItems.sw2CurrentWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.sw2CurrentAlarmThresh);
  dmMonitor->addMonitoredItem(dmItems.sw3CurrentWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.sw3CurrentAlarmThresh);
  dmMonitor->addMonitoredItem(dmItems.vicorVoltageWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.vicorVoltageAlarmThresh);
  dmMonitor->addMonitoredItem(dmItems.vicorTempWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.vicorTempAlarmThresh);
  dmMonitor->addMonitoredItem(dmItems.switchTempWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.switchTempAlarmThresh);

  return status;
}


STATUS LpsCard::processDmChanges(DmGroup *dmGroup)
{
  MBool debug = FALSE;
  
  if (!dmGroup->itemsChanged())
    return OK;

  STATUS status = SwitchCard::processDmChanges(dmGroup);

  if (dmGroup->itemChanged(dmItems.sw0CurrentWarnThresh) ||
      dmGroup->itemChanged(dmItems.sw0CurrentAlarmThresh) ||
      dmGroup->itemChanged(dmItems.sw1CurrentWarnThresh) ||
      dmGroup->itemChanged(dmItems.sw1CurrentAlarmThresh) ||
      dmGroup->itemChanged(dmItems.sw2CurrentWarnThresh) ||
      dmGroup->itemChanged(dmItems.sw2CurrentAlarmThresh) ||
      dmGroup->itemChanged(dmItems.sw3CurrentWarnThresh) ||
      dmGroup->itemChanged(dmItems.sw3CurrentAlarmThresh))
  {
    dprintf("LpsCard::processDmChanges() - "
	    "current alarm threshold(s) changed\n");

    if (writeLpsCurrentThresholds(_sio32Chan, _cardAddr, &dmItems) != OK)
      status = ERROR;
  }

  if (dmGroup->itemChanged(dmItems.vicorVoltageWarnThresh) ||
      dmGroup->itemChanged(dmItems.vicorVoltageAlarmThresh))
  {
    dprintf("LpsCard::processDmChanges() - "
	    "voltage alarm threshold(s) changed\n");

    if (writeLpsVoltageThresholds(_sio32Chan, _cardAddr, &dmItems) != OK)
      status = ERROR;
  }

  if (dmGroup->itemChanged(dmItems.vicorTempWarnThresh) ||
      dmGroup->itemChanged(dmItems.vicorTempAlarmThresh) ||
      dmGroup->itemChanged(dmItems.switchTempWarnThresh) ||
      dmGroup->itemChanged(dmItems.switchTempAlarmThresh))
  {
    dprintf("LpsCard::processDmChanges() - "
	    "temp alarm threshold(s) changed\n");

    if (writeLpsTempThresholds(_sio32Chan, _cardAddr, &dmItems) != OK)
      status = ERROR;
  }

  return status;
}


STATUS LpsCard::startSampling()
{
  MBool debug = FALSE;
  dprintf("LpsCard::startSampling() - card %s, period=%d\n", 
	  name(), _microSampleMillisec);
  
  initIbcLpsProvider(&dmItems, _microSampleMillisec * 1000);
  return OK;
}


STATUS LpsCard::sampleMicro()
{
  MBool debug = FALSE;
  dprintf("LpsCard::sampleMicro() - card %s\n", name());
  
  return updateIbcLpsDm(_sio32Chan, _cardAddr, &dmItems);
}


MBool LpsCard::handleSrq(Word requestCode, Byte *packet)
{
  MBool debug = FALSE;
  dprintf("LpsCard::handleSrq() - requestCode 0x%x\n", requestCode);
  return processIbcLpsSRQ(requestCode, packet, _cardAddr, &dmItems);
}


STATUS LpsCard::handleResetSrq()
{
  return updateIbcLpsAlarmsDm(_sio32Chan, _cardAddr, &dmItems);
}


IBC_BoardType LpsCard::type()
{
  return LOW_POWER_SWITCH;
}


VicorLpsCard::VicorLpsCard(const char *cardName,
			   Word cardAddr,
			   sio32Chan *channel,
			   Int16 cardNo,
			   SwitchChannel *parent,
			   SystemBus bus,
			   LoadDivision division,
			   Nat16 vicorPower,
			   SwitchMethod switchMethod,
			   SwitchStatus defaultStatus)

  : LpsCard(cardName, cardAddr, channel, cardNo, parent, bus, division)
{
  // Can have 5 channels - vicor switch plus 4 low power switch channels
  _maxChannels = 1 + 4;
  
  _vicor = SwitchCard::addChannel(cardName, vicorPower, switchMethod, 
				  defaultStatus, LPS_VICOR_ENABLE, parent); 

  _channelParent = _vicor;
}


void VicorLpsCard::enableVicor()
{
  _vicor->set(SwitchOn);
}


void VicorLpsCard::disableVicor()
{
  _vicor->set(SwitchOff);
}


STATUS VicorLpsCard::connectSwitchItems(SwitchChannel *channel)
{
  if (channel->entry()->channel == LPS_VICOR_ENABLE)
    // Vicor channel stuff is not connected
    return OK;
  
  return LpsCard::connectSwitchItems(channel);
}

  
HpsCard::HpsCard(const char *componentName,
		 Word cardAddr,
		 sio32Chan *channel,
		 Int16 cardNo,
		 SwitchChannel *parent, 
		 Nat16 power,
		 SystemBus bus,
		 LoadDivision division,
		 SwitchMethod switchMethod)

  : SwitchCard(componentName, cardAddr, channel, parent, bus, division)
{
  bzero((char *)&dmItems, sizeof(dmItems));

  if (createIbcHpsDmItems(&dmItems, _dmPrefix, _appName, cardNo) != OK)
  {
    setError("HpsCard::HpsCard() - createIbcHpsDmItems() failed");
    return;
    
#if 0
    throw IbcAppError(IbcAppError::DataMgr, _name,
		      "HpsCard::HpsCard() - createIbcHpsDmItems() failed");
#endif
  }

  _switchChannel = addChannel(componentName, power, switchMethod, 
			      SwitchOff, 0, parent);

  initIbcHpsAlarmProvider(&dmItems);
  handleResetEvent();
}


HpsCard::~HpsCard()
{
}


STATUS HpsCard::handleResetEvent()
{
  updateIbcHpsDmItems(_sio32Chan, _cardAddr, &dmItems, _appName);
  return OK;
}


STATUS HpsCard::connectSwitchItems(SwitchChannel *channel)
{
  char currentName[MaxDmNameLen];
  char currentAlarmName[MaxDmNameLen];
  char currentWarnThreshName[MaxDmNameLen];
  char currentAlarmThreshName[MaxDmNameLen];
  char switchTripAlarmName[MaxDmNameLen];

  // Build app-specific portion of DataManager names
  sprintf(currentName, "%s.%s.%s", 
	  _appName, channel->name(), SwitchCurrentName);

  sprintf(currentAlarmName, "%s.%s.%s", 
	  _appName, channel->name(), SwitchCurrentAlarmName);

  sprintf(currentWarnThreshName, "%s.%s.%s", 
	  _appName, channel->name(), SwitchCurrentWarnThreshName);

  sprintf(currentAlarmThreshName, "%s.%s.%s", 
	  _appName, channel->name(), SwitchCurrentAlarmThreshName);
  
  sprintf(switchTripAlarmName, "%s.%s.%s", 
	  _appName, channel->name(), SwitchTripAlarmName);

  return ibcConnectHpsDmItems(&dmItems, channel->entry(), 
			      _appName, channel->name(),
			      currentName, currentAlarmName,
			      currentWarnThreshName, currentAlarmThreshName,
			      switchTripAlarmName);
}


STATUS HpsCard::startMonitoring(DmMonitor *dmMonitor)
{
  STATUS status = SwitchCard::startMonitoring(dmMonitor);

  dmMonitor->addMonitoredItem(dmItems.currentWarnThresh);
  dmMonitor->addMonitoredItem(dmItems.currentAlarmThresh);

  return status;
}


STATUS HpsCard::processDmChanges(DmGroup *dmGroup)
{
  MBool debug = FALSE;
  
  if (!dmGroup->itemsChanged())
    return OK;

  STATUS status = SwitchCard::processDmChanges(dmGroup);

  Nat16 warn, alarm;
  
  if (dmGroup->itemChanged(dmItems.currentWarnThresh) ||
      dmGroup->itemChanged(dmItems.currentAlarmThresh))
  {
    dprintf("HpsCard::processDmChanges() - "
	    "current alarm threshold(s) changed\n");

    dm_read(dmItems.currentWarnThresh, (char *) &warn,
	    sizeof(warn), (DM_Time *) NULL);
	

    dm_read(dmItems.currentAlarmThresh, (char *) &alarm,
	    sizeof(alarm), (DM_Time *) NULL);
	

    if (IBC_HPS_SetCurrentThresh(_sio32Chan, _cardAddr, warn, alarm) != OK)
      status = ERROR;
  }

  return status;
}


STATUS HpsCard::startSampling()
{
  initIbcHpsProvider(&dmItems, _microSampleMillisec * 1000);
  return OK;
}


STATUS HpsCard::sampleMicro()
{  
  return updateIbcHpsDm(_sio32Chan, _cardAddr, &dmItems);
}


MBool HpsCard::handleSrq(Word requestCode, Byte *packet)
{ 
  return processIbcHpsSRQ(requestCode, packet, _cardAddr, &dmItems);
}


STATUS HpsCard::handleResetSrq()
{
  return updateIbcHpsAlarmsDm(_sio32Chan, _cardAddr, &dmItems);
}


void HpsCard::switchOn(MBool usePowerMgr)
{
  SwitchChannel *channel;
  _switchChannels.get(0, (void **)&channel);
  channel->set(SwitchOn, usePowerMgr);
}


void HpsCard::switchOff(MBool usePowerMgr)
{
  _switchChannel->switchOff(usePowerMgr);
}


MBool HpsCard::newRequest(DmGroup *dmGroup)
{
  return _switchChannel->newRequest(dmGroup);
}


void HpsCard::processSwitchRequest()
{
  _switchChannel->processSwitchRequest();
}


IBC_BoardType HpsCard::type()
{
  return HIGH_POWER_SWITCH;
}



VicorCard::VicorCard(const char *componentName,
		     Word cardAddr,
		     sio32Chan *channel,
		     Int16 cardNo,
		     SwitchChannel *parent,     
		     SystemBus bus,
		     LoadDivision division)

  : MultiSwitchCard(componentName, cardAddr, channel, parent, bus, division)
{
  bzero((char *)&dmItems, sizeof(dmItems));

  if (createIbcVicorDmItems(dmItems, _dmPrefix, _appName) != OK)
  {
    setError("VicorLpsCard::VicorLpsCard() - createIbcVicorDmItems() failed");
    return;
    
#if 0
    throw IbcAppError(IbcAppError::DataMgr, _name,
		      "VicorLpsCard::VicorLpsCard() - " 
		      "createIbcVicorDmItems() failed");
#endif
  }

  _maxChannels = 2;

  initIbcVicorAlarmProvider(dmItems);
  handleResetEvent();
}


VicorCard::~VicorCard()
{
}


STATUS VicorCard::handleResetEvent()
{
  updateIbcVicorDmItems(_sio32Chan, _cardAddr, dmItems, _appName); 

  return OK;
}


STATUS VicorCard::connectSwitchItems(SwitchChannel *channel)
{
  char tempName[MaxDmNameLen];
  char tempAlarmName[MaxDmNameLen];
  char tempWarnThreshName[MaxDmNameLen];
  char tempAlarmThreshName[MaxDmNameLen];

  // Build app-specific portion of DataManager names
  sprintf(tempName, "%s.%s.%s", 
	  _appName, channel->name(), IsoTempName);

  sprintf(tempAlarmName, "%s.%s.%s", 
	  _appName, channel->name(), IsoTempAlarmName);

  sprintf(tempWarnThreshName, "%s.%s.%s", 
	  _appName, channel->name(), IsoTempWarnThreshName);

  sprintf(tempAlarmThreshName, "%s.%s.%s", 
	  _appName, channel->name(), IsoTempAlarmThreshName);
  
  return ibcConnectVicorDmItems(dmItems, channel->entry(), 
				_appName, channel->name(),
				channel->entry()->channel, 
				tempName, tempAlarmName,
				tempWarnThreshName, tempAlarmThreshName);
}


STATUS VicorCard::startMonitoring(DmMonitor *dmMonitor)
{
  STATUS status = SwitchCard::startMonitoring(dmMonitor);

  for (int i = 0; i < _switchChannels.size(); i++)
  {
    dmMonitor->addMonitoredItem(dmItems[0].tempWarnThresh);
    dmMonitor->addMonitoredItem(dmItems[0].tempAlarmThresh);
  }

  return status;
}


STATUS VicorCard::processDmChanges(DmGroup *dmGroup)
{
  MBool debug = FALSE;
  
  if (!dmGroup->itemsChanged())
    return OK;
  
  STATUS status = SwitchCard::processDmChanges(dmGroup);

  Int16 psu0TempWarn, psu0TempAlarm;
  Int16 psu1TempWarn, psu1TempAlarm;

  for (int i = 0; i < _switchChannels.size(); i++)
  {
    if (dmGroup->itemChanged(dmItems[i].tempWarnThresh) ||
      dmGroup->itemChanged(dmItems[i].tempAlarmThresh))
    {
      dprintf("VicorCard::processDmChanges() - "
	      "temp alarm threshold(s) changed\n");

      dm_read(dmItems[i].tempWarnThresh, (char *) &psu0TempWarn,
	      sizeof(psu0TempWarn), (DM_Time *) NULL);
       
      dm_read(dmItems[i].tempAlarmThresh, (char *) &psu0TempAlarm,
	      sizeof(psu0TempAlarm), (DM_Time *) NULL);

      if (IBC_DualVicorSetTempThresh(_sio32Chan, _cardAddr,
				     psu0TempWarn, psu0TempAlarm, 
				     psu1TempWarn, psu1TempAlarm ) != OK)
	status = ERROR;
    }
  }
  return status;
}


STATUS VicorCard::startSampling()
{
  initIbcVicorProvider(dmItems, _microSampleMillisec * 1000);
  return OK;
}


STATUS VicorCard::sampleMicro()
{
  return updateIbcVicorDm(_sio32Chan, _cardAddr, dmItems);
}


MBool VicorCard::handleSrq(Word requestCode, Byte *packet)
{
  return processIbcVicorSRQ(requestCode, packet, _cardAddr, dmItems);
} 


STATUS VicorCard::handleResetSrq()
{
  return updateIbcVicorAlarmsDm(_sio32Chan, _cardAddr, dmItems);
}


IBC_BoardType VicorCard::type()
{
  return DUAL_VICOR;
}



DigitalOutput::DigitalOutput(const char *systemPrefix,
			     const char *appName,
			     const char *name,
			     int switchChannelNo,
			     SwitchMethod switchMethod)
{
  MBool debug = FALSE;

  _switchChannelNo = switchChannelNo;
  _switchMethod = switchMethod;
  _name = strdup(name);
  
  static char itemName[MaxDmNameLen];

  sprintf(itemName, "%s.%s.%s", systemPrefix, appName, name);

  DmBooleanObject *dmObject = new DmBooleanObject(itemName);
  dmItem = dmObject->getHandle();
}


DigitalOutput::~DigitalOutput()
{
  free((void *)_name);
}



const char *DigitalOutput::name()
{
  return _name;
}


SwitchMethod DigitalOutput::switchMethod()
{
  return _switchMethod;
}


Nat16 DigitalOutput::channelNo()
{
  return _switchChannelNo;
}


IsolatedIoCard::IsolatedIoCard(const char *cardName,
			       Word cardAddr,
			       sio32Chan *channel,
			       Int16 cardNo,
			       SwitchChannel *parent,     
			       SystemBus bus,
			       LoadDivision division,
			       MBool positiveLogic)

  : MultiSwitchCard(cardName, cardAddr, channel, parent, bus, division)
{
  _maxChannels = 8;

  if (positiveLogic)
    _cardType = ISOLATED_IO_POS_TRUE;
  else
    _cardType = ISOLATED_IO;
}


IsolatedIoCard::~IsolatedIoCard()
{
}


SwitchChannel *IsolatedIoCard::addChannel(const char *name,
					  Nat16 power,
					  SwitchMethod switchMethod,
					  SwitchStatus defaultStatus)
{
  if (_switchChannels.size() + _outputs.size() >= _maxChannels)
  {
    setError("Too many channels");
    return NULL;
    
#if 0
    throw IbcAppError(IbcAppError::MaxChannels, _name,
		      "IsolatedIoCard::addChannel() - "
		      "exceeded maximum number of channels");
#endif
  }

  SwitchChannel *channel = SwitchCard::addChannel(name, power,
						  switchMethod,
						  defaultStatus,
						  _nAddedChannels++,
						  _channelParent);

  // Since IsolatedIoCard can contain switch-less outputs, we 
  // need to take these into account when assigning the channelNo
  channel->_channelNo += _outputs.size();
  
  return channel;
}


DigitalOutput *IsolatedIoCard::addOutput(const char *outputName, 
					 SwitchMethod switchMethod)
{
  MBool debug = FALSE;

  if (_switchChannels.size() + _outputs.size() >= _maxChannels)
  {
    setError("IsolatedIoCard::addOutput() - "
	     "Exceeded maximum number of channels");

    return NULL;

#if 0    
    throw IbcAppError(IbcAppError::MaxChannels, _name,
		      "IsolatedIoCard::addOutput() - "
		      "Exceeded maximum number of channels");
#endif    
  }

  DigitalOutput *output = 
    new DigitalOutput(_systemName, _appName, outputName, 
		      _outputs.size() + _switchChannels.size(),
		      switchMethod);

  _outputs.add((void **)&output);
  
  return output;
}



STATUS IsolatedIoCard::handleResetEvent()
{
  return OK;
}


STATUS IsolatedIoCard::startMonitoring(DmMonitor *dmMonitor)
{
  STATUS status = SwitchCard::startMonitoring(dmMonitor);
    
  for (int i = 0; i < _outputs.size(); i++)
  {
    DigitalOutput *output;
    
    _outputs.get(i, (void **)&output);
    dmMonitor->addMonitoredItem(output->dmItem);
  }

  return status;
}


STATUS IsolatedIoCard::processDmChanges(DmGroup *dmGroup)
{
  MBool debug = FALSE;
  
  STATUS status = SwitchCard::processDmChanges(dmGroup);
  
  dprintf("IsolatedIoCard::processDmChanges(), card %s, check %d outputs\n",
	  name(), _outputs.size());

  for (int i = 0; i < _outputs.size(); i++)
  {
    DigitalOutput *output;
    _outputs.get(i, (void **)&output);
    
    if (output->switchMethod() != SwitchedByFramework)
      continue;

    ///////////////////////////////////////////////////////////////
    // DEBUG
    static DmItemSts itemStatus;

    dm_item_status(output->dmItem, &itemStatus);
    static char itemName[MaxDmNameLen];
    strcpy(itemName, itemStatus.is_name);

    dprintf("IsolatedIoCard::processDmChanges() - check item %s\n",
    	    itemName);

    dm_item_status_free(&itemStatus);

    // END DEBUG
    ///////////////////////////////////////////////////////////////

    if (dmGroup->itemChanged(output->dmItem))
    {
      dprintf("IsolatedIoCard::processDmChanges() - "
	      "output %s (chan #%d) changed\n", 
	      output->name(), output->channelNo());

      Errno err;
      MBool value;
      DM_Time t;
    
      if ((err = dm_read(output->dmItem, &value, sizeof(MBool), &t)) 
	  != SUCCESS)
      {
	char errorBuf[errorMsgSize];
	sprintDmError(err, "IsolatedIoCard::processDmChanges()", errorBuf);
	logMsg(errorBuf);
	status = ERROR;
      }
      else
      {
	status = ibcSwitchControl(_sio32Chan, ISOLATED_IO, _cardAddr, 
				  output->channelNo(), 
				  value ? OFF: ON);

	dprintf("IsolatedIoCard::processDmChanges() - "
		"value=%d, status=%d\n", value, status);

	if (status == ERROR)
	{
	  logMsg("IsolatedIoard::processDmChanges() - card %s, output %s "
		 "ERROR status from ibcSwitchControl()\n", 
		 name(), output->name());
	}
      }
    }
  }

  return status;
}


STATUS IsolatedIoCard::startSampling()
{
  return OK;
}


STATUS IsolatedIoCard::sampleMicro()
{
  return OK;
}


MBool IsolatedIoCard::handleSrq(Word requestCode, Byte *packet)
{
  return FALSE;
}


STATUS IsolatedIoCard::handleResetSrq()
{
  return OK;
}


STATUS IsolatedIoCard::connectSwitchItems(SwitchChannel *channel)
{
  fprintf(stderr, "IsolatedIoCard::connectSwitchItems() NOT IMPLEMENTED!\n");
  return ERROR;
}


IBC_BoardType IsolatedIoCard::type()
{
  return _cardType;
}




