static char Alarm_id[] = "$Header: /usr/tiburon/unix/gui/tmacs/RCS/OAlarm.cc,v 1.1 1997/11/20 08:21:27 oreilly Exp $";


/*
$Log: OAlarm.cc,v $
Revision 1.1  1997/11/20 08:21:27  oreilly
Initial revision

Revision 1.7  97/08/12  14:13:50  14:13:50  oreilly (Thomas C. O'Reilly)
Added thresholds and monitor items to GraduatedAlarm

Revision 1.6  97/06/16  15:59:30  15:59:30  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.5  97/05/06  16:22:19  16:22:19  oreilly (Thomas C. O'Reilly)
Ensure that alarms have priority Priority3 as default

Revision 1.4  97/05/02  13:02:19  13:02:19  oreilly (Thomas C. O'Reilly)
GfAlarm::CriticalMnem changed is "Alarm"

Revision 1.3  97/03/20  12:28:24  12:28:24  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.2  96/10/28  09:11:25  09:11:25  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.1  96/07/22  10:41:09  10:41:09  oreilly (Thomas C. O'Reilly)
First external release

*/
#include <stdlib.h>
#include <time.h>
#include "Alarm.h"

#include "nav_if.h"
#include "vme_ibc.h"
#include "telemDiag.h"

#define dprintf if (debug) fprintf

const char *const Alarm::MotorStatusTypeMnem = "Motor";
const char *const Alarm::IbcTypeMnem = "Micro";
const char *const Alarm::GfTypeMnem = "Gf";
const char *const Alarm::GfTestTypeMnem = "GfTest";
const char *const Alarm::Gf5vTestTypeMnem = "Gf5vTest";
const char *const Alarm::BooleanTypeMnem = "Boolean";
const char *const Alarm::QuadSerPsuTypeMnem = "QuadSerPsuStatus";
const char *const Alarm::NavPsuTypeMnem = "NavPsuStatus";
const char *const Alarm::VmePsuTypeMnem = "VmePsuStatus";
const char *const Alarm::TelemPsuTypeMnem = "TelemPsuStatus";
const char *const Alarm::EventTypeMnem = "Event";
const char *const Alarm::UnkValueMnem = "Unknown!";

const char *const BooleanAlarm::TrueMnem = "Alarm";
const char *const BooleanAlarm::FalseMnem = "Ok";

const char *const PsuAlarm::TrueMnem = "Alarm";
const char *const PsuAlarm::FalseMnem = "Ok";

const char *const IbcAlarm::AlarmMnem = "Alarm";
const char *const IbcAlarm::WarningMnem = "Warning";
const char *const IbcAlarm::OkMnem = "Ok";
const char *const IbcAlarm::WarningThresholdSuffix = "_WARN_THRESHOLD";
const char *const IbcAlarm::AlarmThresholdSuffix = "_ALARM_THRESHOLD";

const char *const GfAlarm::NormalMnem = "Ok";
const char *const GfAlarm::AdvisoryMnem = "Advisory";
const char *const GfAlarm::WarningMnem = "Warning";
const char *const GfAlarm::CriticalMnem = "Alarm";

const char *const GfTestAlarm::OkMnem = "Ok";
const char *const GfTestAlarm::FailOnMnem = "FailOn";
const char *const GfTestAlarm::FailOffMnem = "FailOff";

const char *const Gf5vTestAlarm::NotRunMnem = "NotRun";
const char *const Gf5vTestAlarm::AtodFailedMnem = "AtodFail";
const char *const Gf5vTestAlarm::SelfTestFailedMnem = "TestFail";
const char *const Gf5vTestAlarm::SelfTestPassedMnem = "Ok";

const char *const MotorStatusAlarm::UnkStatusMnem = "Unknown";
const char *const MotorStatusAlarm::NoFaultMnem = "Ok";
const char *const MotorStatusAlarm::ControlVoltMnem = "UnderVolt";
const char *const MotorStatusAlarm::ControlTempMnem = "Temp";
const char *const MotorStatusAlarm::StallMnem = "Stalled";
const char *const MotorStatusAlarm::ResolverMnem = "ResFail";
const char *const MotorStatusAlarm::OverCurrMnem = "OverCurr";
const char *const MotorStatusAlarm::FaultMnem = "Fault";


Alarm::Alarm()
{
  _dmObject = NULL;
  _prevAcknowledged = _acknowledged = TRUE;
  _itemMnemonic = NULL;
  _associatedItem = NULL;
  
  _writeTime.tv_sec = time(NULL);
  _writeTime.tv_usec = 0;

  _priority = Priority3;
  _dmForward = NULL;
}

Alarm::~Alarm()
{
  if (_itemMnemonic)
    free(_itemMnemonic);

  if (_associatedItem)
    free(_associatedItem);
}


AlarmType Alarm::mnemonicType(char *mnemonic)
{
  if (!strcmp(mnemonic, MotorStatusTypeMnem))
    return MotorStatusAlarmType;

  else if (!strcmp(mnemonic, IbcTypeMnem))
    return IbcAlarmType;
  
  else if (!strcmp(mnemonic, GfTypeMnem))
    return GfAlarmType;
  
  else if (!strcmp(mnemonic, GfTestTypeMnem))
    return GfTestAlarmType;
  
  else if (!strcmp(mnemonic, Gf5vTestTypeMnem))
    return Gf5vTestAlarmType;
  
  else if (!strcmp(mnemonic, BooleanTypeMnem))
    return BooleanAlarmType;

  else if (!strcmp(mnemonic, QuadSerPsuTypeMnem))
    return QuadSerPsuAlarmType;

  else if (!strcmp(mnemonic, NavPsuTypeMnem))
    return NavPsuAlarmType;

  else if (!strcmp(mnemonic, VmePsuTypeMnem))
    return VmePsuAlarmType;
  
  else if (!strcmp(mnemonic, TelemPsuTypeMnem))
    return TelemPsuAlarmType;

  else if (!strcmp(mnemonic, EventTypeMnem))
    return EventAlarmType;
  
  else
    return UnkAlarmType;
}


char *Alarm::typeMnemonic(AlarmType type)
{
  static char *ptr;
  
  switch (type)
  {
    case MotorStatusAlarmType:
    ptr = (char *)MotorStatusTypeMnem;
    break;
    
    case IbcAlarmType:
    ptr = (char *)IbcTypeMnem;
    break;
    
    case GfAlarmType:
    ptr = (char *)GfTypeMnem;
    break;
    
    case GfTestAlarmType:
    ptr = (char *)GfTestTypeMnem;
    break;
    
    case Gf5vTestAlarmType:
    ptr = (char *)Gf5vTestTypeMnem;
    break;

    case BooleanAlarmType:
    ptr = (char *)BooleanTypeMnem;
    break;

    case QuadSerPsuAlarmType:
    ptr = (char *)QuadSerPsuTypeMnem;
    break;

    case NavPsuAlarmType:
    ptr = (char *)NavPsuTypeMnem;
    break;
    
    case VmePsuAlarmType:
    ptr = (char *)VmePsuTypeMnem;
    break;

    case TelemPsuAlarmType:
    ptr = (char *)TelemPsuTypeMnem;
    break;

    case EventAlarmType:
    ptr = (char *)EventTypeMnem;
    break;
    
    default:
    fprintf(stderr, "Alarm::typeMnem() - no mnemonic for type %d\n", type);
    exit(1);
  }
  return ptr;
}


int Alarm::mnemonicValue(AlarmType type, char *mnemonic)
{
  switch (type)
  {
    case MotorStatusAlarmType:
    return MotorStatusAlarm::mnemonicValue(mnemonic);
    
    case IbcAlarmType:
    return IbcAlarm::mnemonicValue(mnemonic);
    
    case GfAlarmType:
    return GfAlarm::mnemonicValue(mnemonic);
    
    case GfTestAlarmType:
    return GfTestAlarm::mnemonicValue(mnemonic);
    
    case Gf5vTestAlarmType:
    return Gf5vTestAlarm::mnemonicValue(mnemonic);
    
    case BooleanAlarmType:
    return BooleanAlarm::mnemonicValue(mnemonic);

    case QuadSerPsuAlarmType:
    case NavPsuAlarmType:
    case VmePsuAlarmType:
    case TelemPsuAlarmType:
    return PsuAlarm::mnemonicValue(mnemonic);

    default:
    return -1;
  }
}


char *Alarm::valueMnemonic(AlarmType type, int value)
{
  switch (type)
  {
    case MotorStatusAlarmType:
    return MotorStatusAlarm::valueMnemonic(value);
    
    case IbcAlarmType:
    return IbcAlarm::valueMnemonic(value);
    
    case GfAlarmType:
    return GfAlarm::valueMnemonic(value);
    
    case GfTestAlarmType:
    return GfTestAlarm::valueMnemonic(value);
    
    case Gf5vTestAlarmType:
    return Gf5vTestAlarm::valueMnemonic(value);
    
    case BooleanAlarmType:
    return BooleanAlarm::valueMnemonic(value);

    case QuadSerPsuAlarmType:
    case NavPsuAlarmType:
    case VmePsuAlarmType:
    case TelemPsuAlarmType:
    return PsuAlarm::valueMnemonic(value);

    default:
    return (char *)UnkValueMnem;
  }
}


void Alarm::setItemMnemonic(char *mnemonic)
{
  if (_itemMnemonic)
    free(_itemMnemonic);
  
  _itemMnemonic = strdup(mnemonic);
}


#define TiburonPrefix "TIBURON."
#define AlarmSuffix "_ALARM"

char *Alarm::itemMnemonic()
{
  if (_itemMnemonic)
    return _itemMnemonic;
  else
  {
    char *ptr = (char *)_dmObject->getName();
    if (!strncmp(ptr, TiburonPrefix, strlen(TiburonPrefix)))
      // Remove standard tiburon prefix
      ptr += strlen(TiburonPrefix);

    if (strlen(ptr) > strlen(AlarmSuffix))
    {
      char *endPtr = ptr + strlen(ptr) - strlen(AlarmSuffix);
      if (!strncmp(endPtr, AlarmSuffix, strlen(AlarmSuffix)))
      {
	static char buf[512];
	strcpy(buf, ptr);
	buf[strlen(buf) - strlen(AlarmSuffix)] = '\0';
	ptr = buf;
      }
    }
    return ptr;
  }
}


void Alarm::acknowledge(MBool yesNo)
{
  _prevAcknowledged = _acknowledged;
  _acknowledged = yesNo;

  if (_dmForward)
    forward();
}


int Alarm::setForwarding(MBool forward)
{
  if (!forward)
  { 
    if (_dmForward)
      delete _dmForward;
    
    _dmForward = NULL;
  }
  else
  {
    if (!_dmForward)
    {
      char itemName[MaxDmNameLen];
      strcpy(itemName, _dmObject->getName());
      strcat(itemName, ".ACK");
      _dmForward = new DmNat16Object(itemName);
      if (_dmForward->error())
      {
	return -1;
      }
      Errno err;
      if ((err = _dmForward->startProvide(DM_ASYNC, MultiProviders)) 
	  != SUCCESS)
      {
	return -1;
      }
    }
    Alarm::forward();
  }

  return 0;
}


MBool Alarm::forwarding()
{
  if (_dmForward)
    return TRUE;
  else
    return FALSE;
}


int Alarm::forward()
{
  if (!_dmForward)
    return -1;
  
  Nat16 data;
  data = (_acknowledged << 8) | (0xFF & _priority);

  DM_Time t;
  t.tv_sec = time(NULL);
  t.tv_usec = 0;
  
  if (_dmForward->write(data, &t) != SUCCESS)
    return -1;
  
  return 0;
}


EventAlarm::EventAlarm(const char *name) : Alarm()
{
  _dmObject = _dmEmptyObject = new DmEmptyObject(name);
}


EventAlarm::~EventAlarm()
{
}


int EventAlarm::update()  
{
  DM_Time t;
  if (_dmEmptyObject->read(&t) != SUCCESS)
    return -1;

  _prevAcknowledged = _acknowledged;
 
  if (tval2sec(&t) > tval2sec(&_writeTime))  
    // Event occurred since last read
    acknowledge(FALSE);

  _writeTime.tv_sec = t.tv_sec;
  _writeTime.tv_usec = t.tv_usec;
  
  
  return 0;
}


ValueAlarm::ValueAlarm() : Alarm()
{
  _ackAllChanges = FALSE;
}


ValueAlarm::~ValueAlarm()
{
  // Free members of ValuePriority list
  ValuePriority *vp;
  int size = _valuePriority.size();
  for (int i = 0; i < size; i++)
  {
    _valuePriority.get(i, &vp);
    delete vp;
  }
}


Priority ValueAlarm::highestSetPriority()
{
  Priority maxPriority = NoPriority;
  ValuePriority *vp;
  for (int i = 0; i < _valuePriority.size(); i++)
  {
    _valuePriority.get(i, &vp);
    maxPriority = higherPriority(vp->priority, maxPriority);
  }

  return maxPriority;
}


void ValueAlarm::setPriority(int value, Priority priority)
{
  ValuePriority *newVp = new ValuePriority(value, priority);
  ValuePriority *vp;
  int size = _valuePriority.size();
  MBool found = FALSE;
  for (int i = 0; i < size; i++)
  {
    _valuePriority.get(i, &vp);
    if (vp->value == value)
    {
      _valuePriority.set(i, &newVp);
      found = TRUE;
      break;
    }
  }
  if (!found)
    _valuePriority.add(&newVp);

  if (priority != NoPriority)
  {
    // Keep track of highest set priority
    _priority = highestSetPriority();
  }
  
  if (_dmForward)
    forward();
}


Priority ValueAlarm::priority(int value)
{
  if (value == NoAlarmValue)
    // Default priority
    return _priority;
  
  ValuePriority *vp;

  // First determine if priority has been explicitly specified for value  
  int size = _valuePriority.size();
  for (int i = 0; i < size; i++)
  {
    _valuePriority.get(i, &vp);
    if (vp->value == value)
      return vp->priority;
  }

  // Return default priority
  return _priority;
}


BooleanAlarm::BooleanAlarm(const char *name) : ValueAlarm()
{
  _dmObject = _dmBooleanObject = new DmBooleanObject(name);
  _value = okayValue();
  setPriority(okayValue(), NoPriority);
}


BooleanAlarm::~BooleanAlarm()
{
}


int BooleanAlarm::update()
{
  MBool val;
  DM_Time t;
  
  if (_dmBooleanObject->read(&val, &t) != SUCCESS)
    return -1;

  _prevAcknowledged = _acknowledged;
  _prevValue = _value;
  
  if (val) val = 1;
  
  if (tval2sec(&t) > tval2sec(&_writeTime))
  {
    // Item was written to since last read
    if (_ackAllChanges)
      // Must acknowledge no matter what present state
      acknowledge(FALSE);

    else if (val && val != _value)
    {
      // Must acknowledge if just changed to TRUE state
      acknowledge(FALSE);
    }
  }
  
  _value = val;
  _writeTime.tv_sec = t.tv_sec;
  _writeTime.tv_usec = t.tv_usec;
  
  return 0;
}


int BooleanAlarm::mnemonicValue(char *mnemonic)
{
  if (!strcmp(mnemonic, TrueMnem))
    return 1;
  else if (!strcmp(mnemonic, FalseMnem))
    return 0;
  else
    return -1;
}


char *BooleanAlarm::valueMnemonic(int value)
{
  static char *ptr;
  
  switch (value)
  {
    case 1:
    ptr = (char *)TrueMnem;
    break;
    
    case 0:
    ptr = (char *)FalseMnem;
    break;
    
    default:
    ptr = (char *)UnkValueMnem;
  }
  return ptr;
}


PsuAlarm::PsuAlarm(const char *name) : ValueAlarm()
{
  _dmObject = _dmNat16Object = new DmNat16Object(name);
  _value = okayValue();
  setPriority(okayValue(), NoPriority);
}


PsuAlarm::~PsuAlarm()
{
}


int PsuAlarm::update()
{
  Nat16 val;
  DM_Time t;
  
  if (_dmNat16Object->read(&val, &t) != SUCCESS)
    return -1;

  _prevAcknowledged = _acknowledged;
  _prevValue = _value;
  
  if (tval2sec(&t) > tval2sec(&_writeTime))
  {
    // Item was written to since last read
    if (_ackAllChanges)
      // Must acknowledge no matter what present state
      acknowledge(FALSE);

    else if (val && val != _value)
    {
      // Must acknowledge if just changed to TRUE state
      acknowledge(FALSE);
    }
  }
  
  _value = val;
  _writeTime.tv_sec = t.tv_sec;
  _writeTime.tv_usec = t.tv_usec;
  
  return 0;
}


int PsuAlarm::mnemonicValue(char *mnemonic)
{
  if (!strcmp(mnemonic, TrueMnem))
    return 1;
  else if (!strcmp(mnemonic, FalseMnem))
    return 0;
  else
    return -1;
}


char *PsuAlarm::valueMnemonic(int value)
{
  static char *ptr;
  
  if (value)
    // A non-zero value indicates a PSU alarm
    ptr = (char *)TrueMnem;
  else
    ptr = (char *)FalseMnem;
  
  return ptr;
}


QuadSerPsuAlarm::QuadSerPsuAlarm(const char *name) : PsuAlarm(name)
{
}


QuadSerPsuAlarm::~QuadSerPsuAlarm()
{
}



const char *QuadSerPsuAlarm::valueDescription()
{
  static char buf[100];

  if (_value == okayValue())
    return FalseMnem;

  char *bitDescr;
  int setBits = 0;
  buf[0] = '\0';
  
  if (!(_value & PS1_FLT_BIT) || (_value & FGND1_FLT_BIT))
  {
    if (setBits++)
      strcat(buf, ", ");
    
    sprintf(buf, "FAULT (0x%x)", _value);
  }

  return (const char *)buf;
}


NavPsuAlarm::NavPsuAlarm(const char *name) : PsuAlarm(name)
{
}


NavPsuAlarm::~NavPsuAlarm()
{
}


int NavPsuAlarm::update()
{
  int status;
  
  if ((status = PsuAlarm::update()) != 0)
    return status;

  /* For NAV PSU, bottom-side software takes clear-bit as error,
     and set-bit as okay. So take 1's complement of value read from
     bottom-side. */
  _value = ~_value;
  return 0;
}


const char *NavPsuAlarm::valueDescription()
{
  static char buf[100];

  if (_value == okayValue())
    return FalseMnem;

  char *bitDescr;
  int setBits = 0;
  buf[0] = '\0';
  
  /* Note that bottom-side software uses convention that set-bit is 
     okay, and clear-bit is error. Tmacs assumes the reverse (update()
     function takes 1's complement of dm value). So bitmask names
     seen here are a bit misleading. */
  if (_value & NAV_5V_POS_PSU_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "+5V-RAIL");
  }
  
  if (_value & NAV_5V_NEG_PSU_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "-5V-RAIL");
  }

  if (_value & NAV_15V_POS_PSU_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "+15V-RAIL");
  }

  if (!_value & NAV_15V_NEG_PSU_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "-15V-RAIL");
  }

  if (!_value & NAV_COMPASS_PSU_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "COMPASS");
  }

  if (!_value & NAV_SYNCRO_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "SYNCH");
  }

  return (const char *)buf;
}


VmePsuAlarm::VmePsuAlarm(const char *name) : PsuAlarm(name)
{
}


VmePsuAlarm::~VmePsuAlarm()
{
}


int VmePsuAlarm::update()
{
  int status;
  
  if ((status = PsuAlarm::update()) != 0)
    return status;

  /* For VME PSU, bottom-side software takes clear-bit as error,
     and set-bit as okay. So take 1's complement of value read from
     bottom-side. */
  _value = ~_value;
  return 0;
}


const char *VmePsuAlarm::valueDescription()
{
  static char buf[100];

  if (_value == okayValue())
    return FalseMnem;

  char *bitDescr;
  int setBits = 0;
  buf[0] = '\0';
  
  if (_value & PSU_5V_A1_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "+5V-A1");
  }
  
  if (_value & PSU_5V_B1_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "+5V-B1");
  }

  if (_value & PSU_5V_A2_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "+5V-A2");
  }
  
  if (_value & PSU_5V_B2_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "+5V-B2");
  }

  if (_value & PSU_12V_A1_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "+12V-A1");
  }
  
  if (_value & PSU_12V_B1_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "+12V-B1");
  }

  if (_value & PSU_12V_A2_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "+12V-A2");
  }
  
  if (_value & PSU_12V_B2_OK)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "+12V-B2");
  }

  return (const char *)buf;
}


TelemPsuAlarm::TelemPsuAlarm(const char *name) : PsuAlarm(name)
{
}


TelemPsuAlarm::~TelemPsuAlarm()
{
}


int TelemPsuAlarm::update()
{
  int status;
  
  if ((status = PsuAlarm::update()) != 0)
    return status;

  /* For TELEM PSU, bottom-side software takes clear-bit as error,
     and set-bit as okay. So take 1's complement of value read from
     bottom-side. */
  _value = ~_value;
  return 0;
}


const char *TelemPsuAlarm::valueDescription()
{
  static char buf[100];

  if (_value == okayValue())
    return FalseMnem;

  char *bitDescr;
  int setBits = 0;
  buf[0] = '\0';
  
  if (_value & PS1_GOOD_BIT)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "PS1");
  }

  if (_value & PS2_GOOD_BIT)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "PS2");
  }

  if (_value & PS3_GOOD_BIT)
  {
    if (setBits++)
      strcat(buf, ", ");
    
    strcat(buf, "PS3");
  }
}


EnumAlarm::EnumAlarm(const char *name) : ValueAlarm()
{
  _dmObject = _dmEnumObject = new DmEnumObject(name);
}


EnumAlarm::~EnumAlarm()
{
}


int EnumAlarm::update()
{
  Int32 val;
  DM_Time t;
  MBool debug = FALSE;
  
  if (_dmEnumObject->read(&val, &t) != SUCCESS)
    return -1;

  dprintf(stderr, "update() - %s val=%d\n", name(), val);
  
  _prevAcknowledged = _acknowledged;
  _prevValue = _value;
  
  if (tval2sec(&t) > tval2sec(&_writeTime))
  {
    // Item was written to since last read
    if (_ackAllChanges)
    {
      // Must acknowledge no matter what present state
      dprintf(stderr, "update() - ackAllChanges for %s\n", name());
      acknowledge(FALSE);
    }
    
    else if (val != okayValue() && val != _value)
    {
      // Must acknowledge if just changed to non-okay state
      dprintf(stderr, "update() - %s changed from %d to %d\n", 
	      name(), _value, val);
      
      acknowledge(FALSE);
    }
  }
  
  _value = (int )val;
  _writeTime.tv_sec = t.tv_sec;
  _writeTime.tv_usec = t.tv_usec;
  
  return 0;
}


GfTestAlarm::GfTestAlarm(const char *name)
  : EnumAlarm(name)
{
  _value = okayValue();
  setPriority(okayValue(), NoPriority);
}


int GfTestAlarm::mnemonicValue(char *mnemonic)
{
  if (!strcmp(mnemonic, OkMnem))
    return (int )GF_TEST_OK;

  else if (!strcmp(mnemonic, FailOnMnem))
    return (int )GF_TEST_FAIL_ON;

  else if (!strcmp(mnemonic, FailOffMnem))
    return (int )GF_TEST_FAIL_OFF;

  else
    return -1;
}


char *GfTestAlarm::valueMnemonic(int value)
{
  static char *ptr;
  
  switch (value)
  {
    case GF_TEST_OK:
    ptr = (char *)OkMnem;
    break;
    
    case GF_TEST_FAIL_ON:
    ptr = (char *)FailOnMnem;
    break;
    
    case GF_TEST_FAIL_OFF:
    ptr = (char *)FailOffMnem;
    break;
    
    default:
    ptr = (char *)UnkValueMnem;
  }

  return ptr;
}


GraduatedAlarm::GraduatedAlarm(const char *name)
  : EnumAlarm(name)
{
  _monitoredItem = NULL;

  // Generate default monitored item name
  char *ptr = strstr(name, AlarmNameSuffix);
  if (ptr)
  {
    char buf[MaxDmNameLen];
    strncpy(buf, name, ptr - name);
    buf[ptr - name] = '\0';
    _monitoredItem = strdup(buf);
  }
  
}


GraduatedAlarm::~GraduatedAlarm()
{
  if (_monitoredItem) free(_monitoredItem);
}


void GraduatedAlarm::setMonitoredItem(char *itemName)
{
  if (_monitoredItem)
    free(_monitoredItem);
  
  _monitoredItem = strdup(itemName);
}


const char *GraduatedAlarm::monitoredItem()
{
  return (const char *)_monitoredItem;
}


MBool GraduatedAlarm::complete(char *errorBuf)
{
  if (!_monitoredItem)
  {
    sprintf(errorBuf, "monitored item name not specified");
    return FALSE;
  }
  else
    return TRUE;
}


IbcAlarm::IbcAlarm(const char *name)
  : GraduatedAlarm(name)
{
  _value = okayValue();
  setPriority(okayValue(), NoPriority);

  _warningThresholdItem = _alarmThresholdItem = NULL;
}


IbcAlarm::~IbcAlarm()
{
  if (_warningThresholdItem) free(_warningThresholdItem);
  if (_alarmThresholdItem) free(_alarmThresholdItem);
}


int IbcAlarm::mnemonicValue(char *mnemonic)
{
  if (!strcmp(mnemonic, AlarmMnem))
    return (int )MICRO_ALARM;

  else if (!strcmp(mnemonic, WarningMnem))
    return (int )MICRO_WARNING;

  else if (!strcmp(mnemonic, OkMnem))
    return (int )MICRO_ALARM_OK;

  else
    return -1;
}


char *IbcAlarm::valueMnemonic(int value)
{
  static char *ptr;
  
  switch (value)
  {
    case MICRO_ALARM:
    ptr = (char *)AlarmMnem;
    break;
    
    case MICRO_WARNING:
    ptr = (char *)WarningMnem;
    break;
    
    case MICRO_ALARM_OK:
    ptr = (char *)OkMnem;
    break;
    
    default:
    ptr = (char *)UnkValueMnem;
  }
  return ptr;
}


int IbcAlarm::setThresholdItem(int value, char *itemName)
{
  switch (value)
  {
    case MICRO_ALARM:

    if (_alarmThresholdItem) 
      free(_alarmThresholdItem);
    
    _alarmThresholdItem = strdup(itemName);
    break;
    
    case MICRO_WARNING:
    
    if (_warningThresholdItem)
      free(_warningThresholdItem);

    _warningThresholdItem = strdup(itemName);

    break;
    
    default:
    return -1;
  }

  return 0;
}


const char *IbcAlarm::alarmThresholdItem()
{
  return (const char *)_alarmThresholdItem;
}


const char *IbcAlarm::warningThresholdItem()
{
  return (const char *)_warningThresholdItem;
}


MBool IbcAlarm::complete(char *errorBuf)
{
  char *ptr = errorBuf;
  MBool status = TRUE;

  if (!_monitoredItem)
  {
    sprintf(ptr, "monitored item name not set\n");
    ptr += strlen(ptr);
    status = FALSE;
  }
  
  if (!_warningThresholdItem)
  {
    sprintf(ptr, "%s threshold item name not set\n",
	    valueMnemonic(MICRO_WARNING));

    ptr += strlen(ptr);
    
    status = FALSE;
  }
  if (!_alarmThresholdItem)
  {
    sprintf(ptr, "%s threshold item name not set\n",
	    valueMnemonic(MICRO_ALARM));

    ptr += strlen(ptr);

    status = FALSE;
  }
  
  return status;
}


Gf5vTestAlarm::Gf5vTestAlarm(const char *name)
  : EnumAlarm(name)
{
  _value = okayValue();
  setPriority(okayValue(), NoPriority);
}


int Gf5vTestAlarm::mnemonicValue(char *mnemonic)
{
  if (!strcmp(mnemonic, NotRunMnem))
    return (int )GF_TEST_NOT_RUN;

  else if (!strcmp(mnemonic, AtodFailedMnem))
    return (int )GF_ATOD_FAILED;

  else if (!strcmp(mnemonic, SelfTestFailedMnem))
    return (int )GF_SELFTEST_FAILED;

  else if (!strcmp(mnemonic, SelfTestPassedMnem))
    return (int )GF_SELFTEST_PASSED;

  else
    return -1;
}


char *Gf5vTestAlarm::valueMnemonic(int value)
{
  char *ptr;
  
  switch (value)
  {
    case GF_TEST_NOT_RUN:
    ptr = (char *)NotRunMnem;
    break;
    
    case GF_ATOD_FAILED:
    ptr = (char *)AtodFailedMnem;
    break;
    
    case GF_SELFTEST_FAILED:
    ptr = (char *)SelfTestFailedMnem;
    break;
    
    case GF_SELFTEST_PASSED:
    ptr = (char *)SelfTestPassedMnem;
    break;
    
    default:
    ptr = (char *)UnkValueMnem;
  }
  return ptr;
}


MotorStatusAlarm::MotorStatusAlarm(const char *name)
  : EnumAlarm(name)
{
  _value = okayValue();
  setPriority(okayValue(), NoPriority);
}


int MotorStatusAlarm::mnemonicValue(char *mnemonic)
{
  if (!strcmp(mnemonic, UnkStatusMnem))
    return STATUS_UNKNOWN;
  
  else if (!strcmp(mnemonic, NoFaultMnem))
    return MOTOR_NO_FAULT;
  
  else if (!strcmp(mnemonic, ControlVoltMnem))
    return MOTOR_CONTROLLER_VOLTS;
  
  else if (!strcmp(mnemonic, ControlTempMnem))
    return MOTOR_CONTROLLER_TEMP;
  
  else if (!strcmp(mnemonic, StallMnem))
    return MOTOR_STALL;
  
  else if (!strcmp(mnemonic, ResolverMnem))
    return MOTOR_RESOLVER;
  
  else if (!strcmp(mnemonic, OverCurrMnem))
    return MOTOR_OVERCURRENT;
  
  else if (!strcmp(mnemonic, FaultMnem))
    return MOTOR_FAULT;
  
  else
    return -1;
}


char *MotorStatusAlarm::valueMnemonic(int value)
{
  char *ptr;
  
  switch (value)
  {
    case STATUS_UNKNOWN:
    ptr = (char *)UnkStatusMnem;
    break;

    case MOTOR_NO_FAULT:
    ptr = (char *)NoFaultMnem;
    break;
    
    case MOTOR_CONTROLLER_VOLTS:
    ptr = (char *)ControlVoltMnem;
    break;
    
    case MOTOR_CONTROLLER_TEMP:
    ptr = (char *)ControlTempMnem;
    break;
    
    case MOTOR_STALL:
    ptr = (char *)StallMnem;
    break;
    
    case MOTOR_RESOLVER:
    ptr = (char *)ResolverMnem;
    break;
    
    case MOTOR_OVERCURRENT:
    ptr = (char *)OverCurrMnem;
    break;
    
    case MOTOR_FAULT:
    ptr = (char *)FaultMnem;
    break;
    
    default:
    ptr = (char *)UnkValueMnem;
  }
  return ptr;
}


GfAlarm::GfAlarm(const char *name)
  : GraduatedAlarm(name)
{
  _value = okayValue();
  setPriority(okayValue(), NoPriority);

  if (_monitoredItem && !strstr(_monitoredItem, GfCurrentSuffix))
  {
    char buf[MaxDmNameLen];
    strcpy(buf, _monitoredItem);
    strcat(buf, GfCurrentSuffix);
    free(_monitoredItem);
    _monitoredItem = strdup(buf);
  }
}


GfAlarm::~GfAlarm()
{
}


int GfAlarm::mnemonicValue(char *str)
{
  if (!strcmp(str, NormalMnem))
    return (int )GF_NORMAL;

  else if (!strcmp(str, AdvisoryMnem))
    return (int )GF_ADVISORY;

  else if (!strcmp(str, WarningMnem))
    return (int )GF_WARNING;

  else if (!strcmp(str, CriticalMnem))
    return (int )GF_CRITICAL;

  else
    return -1;
}


char *GfAlarm::valueMnemonic(int value)
{
  char *ptr;
  
  switch (value)
  {
    case GF_NORMAL:
    ptr = (char *)NormalMnem;
    break;

    case GF_ADVISORY:
    ptr = (char *)AdvisoryMnem;
    break;
    
    case GF_WARNING:
    ptr = (char *)WarningMnem;
    break;
    
    case GF_CRITICAL:
    ptr = (char *)CriticalMnem;
    break;
    
    default:
    ptr = (char *)UnkValueMnem;
  }
  return ptr;
}


