/****************************************************************************/
/* Copyright 1992 to 1996 MBARI                                             */
/****************************************************************************/
/* Summary  : IBC GF/5V Controller Board Data Manager Functions for VxWorks */
/* Filename : gf_5vDm.c                                                     */
/* Author   : Andrew Pearce                                                 */
/* Project  : Tiburon Data Concentrator                                     */
/* Version  : Version 1.0                                                   */
/* Created  : 06/08/93                                                      */
/* Modified : 02/12/96                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: gf_5vDm.c,v 1.1 93/07/01 14:34:24 pean Exp $
 * $Log:        gf_5vDm.c,v $
 * Revision 1.1  93/07/01  14:34:24  14:34:24  pean (Andrew Pearce)
 * Initial revision
 *
 */
/****************************************************************************/

#include <vxWorks.h>                /* vxWorks system declarations          */
#include <semLib.h>                 /* vxWorks semaphore functions          */
#include <taskLib.h>                /* vxWorks task library functions       */
#include <wdLib.h>                  /* vxWorks watch dog timer functions    */
#include <systime.h>                /* vxWorks time and date functions      */
#include <msgQLib.h>                /* vxWorks Message Queue Library        */

#include <mbariTypes.h>             /* MBARI style guide type declarations  */
#include <mbariConst.h>             /* Miscellaneous MBARI constants        */

#include "sio32.h"                  /* SIO32 hardware and driver information*/
#include <sio32Server.h>            /* Sio32 server communication services  */
#include <sio32Client.h>            /* Sio32 client communication services  */
#include <powerTypes.h>             /* Power management Data Types          */
#include <powerDM.h>                /* Power/Switching Data Manager Items   */

#include <datamgr.h>                /* Data Manager declarations            */
#include <dm_errno.h>               /* Data Manager error declarations      */

#define Boolean MBool               /* Map microcontroller Boolean to MBool */

#include "microdef.h"               /* Microcontroller Definitions          */
#include "microcmd.h"               /* Microcontroller commands             */
#include "timer.h"                  /* Microcontroler Timer Definitions     */
#include "ibc_card.h"               /* IBC Card Types                       */
#include "ibc_cmd.h"                /* IBC Serial Commands                  */
#include "filter.h"                 /* General Filter Definitions           */
#include "gf_board.h"               /* GF/5V Controller Board Definitions   */

#include "microDm.h"                /* Micro Data Manager Items & Functions */

#include "switch.h"                 /* IBC Function Libarary Definitions    */

#include "gfSystem.h"               /* Ground Fault System Definitions      */
#include "gf_5v.h"                  /* GF/5V Board Data Types               */
#include "gf_5vDm.h"                /* Defines & Functions for gf_5vDm.c    */

/*****************************************************************************/
/* Function    : createIbcGf5vDmItems                                        */
/* Purpose     : Initialize Data Manager Items for GF/5V Controller Board    */
/* Inputs      : Pointer to structure containing IBC GF/5V Data Manager Items*/
/*               and IBC Data Concentrator Name                              */
/* Outputs     : None, but Data Manager Items change                         */
/*****************************************************************************/
    STATUS
createIbcGf5vDmItems( ibcGf5vDmItems *gf5vDmItems, const char* ibcDmPrefix,
    const char* ibcDataCon )
{
    Int32   item;                   /* Counter for DM Item Initialization   */
    Errno   status;                 /* Result of dm_create function call    */

    struct                          /* Data Manager Item Table for table    */
    {                               /* driven item initialization           */
        DM_Item *dmItem;            /* pointer to actual dm item handle     */
        char    *errorMsg;          /* Message to display of dmCreate fails */
        char    *name;              /* Data Manager Item Name               */
        DM_Type type;               /* Data Manager Item Type               */
        DM_Num  len;                /* Data Manager Item Element Count      */
    } gf5vDmInit[] =

      {  { &gf5vDmItems->gf_enable,             "GF/5V Monitor Enable",
              GF_5V_ENABLE_DM,                     DM_MBOOL, 1 },

        { &gf5vDmItems->offsetCurrent,          "GF/5V Offset Current",
              GF_5V_OFFSET_CURRENT_DM,             DM_INT16, 1 },

        { &gf5vDmItems->selftestCmd,            "GF/5V Self Test Command",
              GF_5V_SELFTEST_CMD_DM,               DM_EMPTY, 1 },

        { &gf5vDmItems->selftestStatus,         "GF/5V Self Test Status",
               GF_5V_SELFTEST_STATUS_DM,           DM_ENUM,  1 },

        { &gf5vDmItems->temperature,            "GF/5V Temperature",
              GF_5V_TEMPERATURE_DM,                DM_INT16, 1 },

        { &gf5vDmItems->tempWarnThresh,         "GF/5V Warning Temperature",
              GF_5V_TEMP_WARN_THRESH_DM,           DM_INT16, 1 },

        { &gf5vDmItems->tempAlarmThresh,        "GF/5V Alarm Temperature",
              GF_5V_TEMP_ALARM_THRESH_DM,          DM_INT16, 1 },

        { &gf5vDmItems->tempAlarm,              "GF/5V Temperature Alarm",
              GF_5V_TEMP_ALARM_DM,                 DM_ENUM,  1 },

        { &gf5vDmItems->vicorVoltage,           "GF/5V Vicor Voltage",
              GF_5V_VICOR_VOLTAGE_DM,              DM_INT16, 1 },

        { &gf5vDmItems->voltageWarnThresh,      "GF/5V Warning Voltage",
              GF_5V_VICOR_VOLT_WARN_THRESH_DM,     DM_INT16, 1 },

        { &gf5vDmItems->voltageAlarmThresh,     "GF/5V Alarm Voltage",
              GF_5V_VICOR_VOLT_ALARM_THRESH_DM,    DM_INT16, 1 },

        { &gf5vDmItems->voltageAlarm,           "GF/5V Voltage Alarm",
              GF_5V_VICOR_VOLTAGE_ALARM_DM,        DM_ENUM, 1 },

        { &gf5vDmItems->busCapacitance,         "GF/5V Bus Capacitance",
              GF_5V_BUS_CAPACITANCE_DM,            DM_NAT16, 1 },

        { &gf5vDmItems->capacitorCurrent,       "GF/5V Capacitor Current",
              GF_5V_BUS_CAPACITOR_CURRENT_DM,      DM_INT16, 1 },

        { &gf5vDmItems->gfChan[0].chargeTime,   "GF/5V Chan 0 Charge Time",
              GF_5V_CHAN0_CHARGE_TIME_DM,          DM_INT32, 1 },

        { &gf5vDmItems->gfChan[0].faultCurrent, "GF/5V Chan 0 Fault Current",
              GF_5V_CHAN0_FAULT_CURRENT_DM,        DM_INT16, 1 },

        { &gf5vDmItems->gfChan[0].alarmStatus,  "GF/5V Chan 0 Alarm Status",
              GF_5V_CHAN0_GF_ALARM_DM,             DM_ENUM,  1 },


        { &gf5vDmItems->gfChan[1].chargeTime,   "GF/5V Chan 1 Charge Time",
              GF_5V_CHAN1_CHARGE_TIME_DM,          DM_INT32, 1 },

        { &gf5vDmItems->gfChan[1].faultCurrent, "GF/5V Chan 1 Fault Current",
              GF_5V_CHAN1_FAULT_CURRENT_DM,        DM_INT16, 1 },

        { &gf5vDmItems->gfChan[1].alarmStatus,  "GF/5V Chan 1 Alarm Status",
              GF_5V_CHAN1_GF_ALARM_DM,             DM_ENUM, 1 },


        { &gf5vDmItems->gfChan[2].chargeTime,   "GF/5V Chan 2 Charge Time",
              GF_5V_CHAN2_CHARGE_TIME_DM,          DM_INT32, 1 },

        { &gf5vDmItems->gfChan[2].faultCurrent, "GF/5V Chan 2 Fault Current",
              GF_5V_CHAN2_FAULT_CURRENT_DM,        DM_INT16, 1 },

        { &gf5vDmItems->gfChan[2].alarmStatus,  "GF/5V Chan 2 Alarm Status",
              GF_5V_CHAN2_GF_ALARM_DM,             DM_ENUM,  1 },


        { &gf5vDmItems->gfChan[3].chargeTime,   "GF/5V Chan 3 Charge Time",
              GF_5V_CHAN3_CHARGE_TIME_DM,          DM_INT32, 1 },

        { &gf5vDmItems->gfChan[3].faultCurrent, "GF/5V Chan 3 Fault Current",
              GF_5V_CHAN3_FAULT_CURRENT_DM,        DM_INT16, 1 },

        { &gf5vDmItems->gfChan[3].alarmStatus,  "GF/5V Chan 3 Alarm Status",
              GF_5V_CHAN3_GF_ALARM_DM,             DM_ENUM,  1 },

        { &gf5vDmItems->chanUpdate,             "GF/5V Channel Update",
              GF_5V_CHAN_UPDATE_STATUS_DM,         DM_NAT16, 1 },

        { NO_ITEM, NULL, NULL, DM_ENDT, 0 } };

                                    /* Clear list of Data Manager Item handles*/
    bzero(gf5vDmItems, sizeof(ibcGf5vDmItems));

                                   /* Initialize Data Manager Items from table*/
    for (item = 0; gf5vDmInit[item].dmItem != NO_ITEM; item++)
    {
        if ((*gf5vDmInit[item].dmItem =
             initMicroDmItem(ibcDmPrefix, gf5vDmInit[item].name,
             gf5vDmInit[item].type, gf5vDmInit[item].len)) == ERROR)

        {                           /* Error occurred so print message & exit */
            logMsg("%s: Error Initializing %s DM Item\n",
                ibcDataCon, gf5vDmInit[item].errorMsg);
            return(ERROR);
        } /* if */
    } /* for */

    return(OK);                     /* All IBC GF/5V Data Mgr items created   */
} /* createIbcGf5vDmItems() */

    Void
initIbcGf5vProvider( ibcGf5vDmItems* gf5vDmItems, Period period )
{
    dm_start_provider(gf5vDmItems->offsetCurrent,    period);
    dm_start_provider(gf5vDmItems->temperature,      period);
    dm_start_provider(gf5vDmItems->vicorVoltage,     period);
    dm_start_provider(gf5vDmItems->capacitorCurrent, period);
    dm_start_provider(gf5vDmItems->chanUpdate,       DM_STATIC);

    dm_start_provider(gf5vDmItems->gfChan[0].faultCurrent, DM_STATIC);
    dm_start_provider(gf5vDmItems->gfChan[1].faultCurrent, DM_STATIC);
    dm_start_provider(gf5vDmItems->gfChan[2].faultCurrent, DM_STATIC);
    dm_start_provider(gf5vDmItems->gfChan[3].faultCurrent, DM_STATIC);
} /* initIbcGf5vProvider() */

    Void
initIbcGf5vAlarmProvider( ibcGf5vDmItems* gf5vDmItems )
{
    dm_start_provider(gf5vDmItems->selftestStatus, DM_STATIC);
    dm_start_provider(gf5vDmItems->tempAlarm,      DM_STATIC);
    dm_start_provider(gf5vDmItems->voltageAlarm,   DM_STATIC);

    dm_start_provider(gf5vDmItems->gfChan[0].alarmStatus,  DM_STATIC);
    dm_start_provider(gf5vDmItems->gfChan[1].alarmStatus,  DM_STATIC);
    dm_start_provider(gf5vDmItems->gfChan[2].alarmStatus,  DM_STATIC);
    dm_start_provider(gf5vDmItems->gfChan[3].alarmStatus,  DM_STATIC);
} /* initIbcGf5vAlarmProvider() */


    DWord
initIbcGf5vConsumer( ibcGf5vDmItems* gf5vDmItems, gf5vUpdateBits *gf5vBits,
    SEM_ID updateSem )
{
    DWord gf5vGroup;

    gf5vGroup = dm_create_group();    /* Create Data Manager Group for GF/5V */

    dm_start_consumer(gf5vDmItems->gf_enable,   DM_STATIC, updateSem);
    dm_start_consumer(gf5vDmItems->selftestCmd, DM_STATIC, updateSem);

    dm_start_consumer(gf5vDmItems->tempWarnThresh,     DM_STATIC, updateSem);
    dm_start_consumer(gf5vDmItems->tempAlarmThresh,    DM_STATIC, updateSem);

    dm_start_consumer(gf5vDmItems->voltageWarnThresh,  DM_STATIC, updateSem);
    dm_start_consumer(gf5vDmItems->voltageAlarmThresh, DM_STATIC, updateSem);

    dm_start_consumer(gf5vDmItems->busCapacitance, DM_STATIC, updateSem);

    dm_start_consumer(gf5vDmItems->gfChan[0].chargeTime,  DM_STATIC, updateSem);
    dm_start_consumer(gf5vDmItems->gfChan[1].chargeTime,  DM_STATIC, updateSem);
    dm_start_consumer(gf5vDmItems->gfChan[2].chargeTime,  DM_STATIC, updateSem);
    dm_start_consumer(gf5vDmItems->gfChan[3].chargeTime,  DM_STATIC, updateSem);

    dm_group_add_item(gf5vGroup, gf5vDmItems->gf_enable,
         &gf5vBits->gfEnableBit );

    dm_group_add_item(gf5vGroup, gf5vDmItems->selftestCmd,
         &gf5vBits->selftestBit );

    dm_group_add_item(gf5vGroup, gf5vDmItems->tempWarnThresh,
         &gf5vBits->tempWarnBit );

    dm_group_add_item(gf5vGroup, gf5vDmItems->tempAlarmThresh,
         &gf5vBits->tempAlarmBit);

    dm_group_add_item(gf5vGroup, gf5vDmItems->voltageWarnThresh,
         &gf5vBits->voltageWarnBit );

    dm_group_add_item(gf5vGroup, gf5vDmItems->voltageAlarmThresh,
         &gf5vBits->voltageAlarmBit);

    dm_group_add_item(gf5vGroup, gf5vDmItems->busCapacitance,
         &gf5vBits->busCapBit );

    dm_group_add_item(gf5vGroup, gf5vDmItems->gfChan[0].chargeTime,
         &gf5vBits->chan0ChargeBit);

    dm_group_add_item(gf5vGroup, gf5vDmItems->gfChan[1].chargeTime,
         &gf5vBits->chan1ChargeBit);

    dm_group_add_item(gf5vGroup, gf5vDmItems->gfChan[2].chargeTime,
         &gf5vBits->chan2ChargeBit);

    dm_group_add_item(gf5vGroup, gf5vDmItems->gfChan[3].chargeTime,
         &gf5vBits->chan3ChargeBit);

    return (gf5vGroup);
} /* initIbcGf5vConsumer() */

    STATUS
updateIbcGf5vDm( sio32Chan *sio32DataChan, Word boardAddr,
    ibcGf5vDmItems *gf5vDmItems )
{
    Int16 faultCurrents[GF_MAX_CHANS], offsetCurrent;
    Int16 temperature, vicorVoltage;

    if (IBC_gf5vGetFaultCurrents( sio32DataChan, boardAddr, faultCurrents,
            &offsetCurrent, &vicorVoltage ) != OK)
        return (ERROR);

    if (IBC_gf5vGetTemperature( sio32DataChan, boardAddr, &temperature ) != OK)
        return (ERROR);

    writeDmItem( gf5vDmItems->gfChan[0].faultCurrent, &faultCurrents[0],
                sizeof(faultCurrents[0]) );

    writeDmItem( gf5vDmItems->gfChan[1].faultCurrent, &faultCurrents[1],
                sizeof(faultCurrents[1]) );

    writeDmItem( gf5vDmItems->gfChan[2].faultCurrent, &faultCurrents[2],
                sizeof(faultCurrents[2]) );

    writeDmItem( gf5vDmItems->gfChan[3].faultCurrent, &faultCurrents[3],
                sizeof(faultCurrents[3]) );

    writeDmItem( gf5vDmItems->offsetCurrent, &offsetCurrent,
                sizeof(offsetCurrent) );

    writeDmItem( gf5vDmItems->temperature, &temperature,
                sizeof(temperature) );

    return ( writeDmItem(gf5vDmItems->vicorVoltage, &vicorVoltage,
                sizeof(vicorVoltage) ) );
} /* updateIbcGf5vDm() */

    STATUS
updateNewIbcGf5vDm( sio32Chan *sio32DataChan, Word boardAddr,
    ibcGf5vDmItems *gf5vDmItems )
{
    Int16 faultCurrents[GF_MAX_CHANS], offsetCurrent;
    Int16 temperature, vicorVoltage;
    Word  chanUpdate;

    if (IBC_NewGf5vGetFaultCurrents( sio32DataChan, boardAddr, faultCurrents,
        &chanUpdate, &offsetCurrent, &vicorVoltage ) != OK)
        return (ERROR);

    if (IBC_gf5vGetTemperature( sio32DataChan, boardAddr, &temperature ) != OK)
        return (ERROR);

    if (chanUpdate)
    {
      if (chanUpdate & (1 << 0))
          writeDmItem( gf5vDmItems->gfChan[0].faultCurrent, &faultCurrents[0],
                sizeof(faultCurrents[0]) );

      if (chanUpdate & (1 << 1))
          writeDmItem( gf5vDmItems->gfChan[1].faultCurrent, &faultCurrents[1],
                sizeof(faultCurrents[1]) );

      if (chanUpdate & (1 << 2))
          writeDmItem( gf5vDmItems->gfChan[2].faultCurrent, &faultCurrents[2],
                sizeof(faultCurrents[2]) );

       if (chanUpdate & (1 << 3))
          writeDmItem( gf5vDmItems->gfChan[3].faultCurrent, &faultCurrents[3],
                sizeof(faultCurrents[3]) );

      writeDmItem( gf5vDmItems->chanUpdate, &chanUpdate, sizeof(chanUpdate) );
    } /* if */

    writeDmItem( gf5vDmItems->offsetCurrent, &offsetCurrent,
                sizeof(offsetCurrent) );

    writeDmItem( gf5vDmItems->temperature, &temperature,
                sizeof(temperature) );

    return ( writeDmItem(gf5vDmItems->vicorVoltage, &vicorVoltage,
                sizeof(vicorVoltage) ) );

} /* updateNewIbcGf5vDm() */

    STATUS
updatePowerCanIbcGf5vDm( sio32Chan *sio32DataChan, Word boardAddr,
    ibcGf5vDmItems *gf5vDmItems )
{
    Int16 faultCurrents[GF_MAX_CHANS], offsetCurrent, capacitorCurrent;
    Int16 temperature, vicorVoltage;
    Word  chanUpdate;

    if (IBC_PowerCanGf5vGetFaultCurrents( sio32DataChan, boardAddr, faultCurrents,
        &chanUpdate, &offsetCurrent, &capacitorCurrent, &vicorVoltage ) != OK)
        return (ERROR);

    if (IBC_gf5vGetTemperature( sio32DataChan, boardAddr, &temperature ) != OK)
        return (ERROR);

    if (chanUpdate)
    {
      if (chanUpdate & (1 << 0))
          writeDmItem( gf5vDmItems->gfChan[0].faultCurrent, &faultCurrents[0],
                sizeof(faultCurrents[0]) );

      if (chanUpdate & (1 << 1))
          writeDmItem( gf5vDmItems->gfChan[1].faultCurrent, &faultCurrents[1],
                sizeof(faultCurrents[1]) );

      if (chanUpdate & (1 << 2))
          writeDmItem( gf5vDmItems->gfChan[2].faultCurrent, &faultCurrents[2],
                sizeof(faultCurrents[2]) );

       if (chanUpdate & (1 << 3))
          writeDmItem( gf5vDmItems->gfChan[3].faultCurrent, &faultCurrents[3],
                sizeof(faultCurrents[3]) );

      writeDmItem( gf5vDmItems->chanUpdate, &chanUpdate, sizeof(chanUpdate) );
    } /* if */

    writeDmItem( gf5vDmItems->offsetCurrent, &offsetCurrent,
                sizeof(offsetCurrent) );

    writeDmItem( gf5vDmItems->capacitorCurrent, &capacitorCurrent,
                sizeof(capacitorCurrent) );

    writeDmItem( gf5vDmItems->temperature, &temperature,
                sizeof(temperature) );

    return ( writeDmItem(gf5vDmItems->vicorVoltage, &vicorVoltage,
                sizeof(vicorVoltage) ) );

} /* updatePowerCanIbcGf5vDm() */

    STATUS
updateIbcGf5vAlarmsDm( sio32Chan *sio32DataChan, Word boardAddr,
    ibcGf5vDmItems *gf5vDmItems )
{
    gf5v_gfTestStatus selftestStatus;
    gfStatus     gfAlarms[GF_MAX_CHANS];
    ibcAlarm     tempAlarm, voltageAlarm;
    gfStatus     offset = (gfStatus) GF_CURRENT_NORMAL_SRQ;

    if (IBC_gf5vGetAlarmStatus( sio32DataChan, boardAddr, gfAlarms,
        &tempAlarm, &voltageAlarm, &selftestStatus ) != OK)
        return (ERROR);

    if (gfAlarms[0] > GF_CRITICAL) gfAlarms[0] -= offset;
    if (gfAlarms[1] > GF_CRITICAL) gfAlarms[1] -= offset;
    if (gfAlarms[2] > GF_CRITICAL) gfAlarms[2] -= offset;
    if (gfAlarms[3] > GF_CRITICAL) gfAlarms[3] -= offset;

                                    /* Write alarm status to Data Manager */
    writeDmItem(gf5vDmItems->tempAlarm,    &tempAlarm,    sizeof(tempAlarm));
    writeDmItem(gf5vDmItems->voltageAlarm, &voltageAlarm, sizeof(voltageAlarm));

    writeDmItem(gf5vDmItems->gfChan[0].alarmStatus, &gfAlarms[0],
                        sizeof(gfAlarms[0]) );

    writeDmItem(gf5vDmItems->gfChan[1].alarmStatus, &gfAlarms[1],
                        sizeof(gfAlarms[1]) );

    writeDmItem(gf5vDmItems->gfChan[2].alarmStatus, &gfAlarms[2],
                        sizeof(gfAlarms[2]) );

    writeDmItem(gf5vDmItems->gfChan[3].alarmStatus, &gfAlarms[3],
                        sizeof(gfAlarms[3]) );

    return (writeDmItem(gf5vDmItems->selftestStatus, &selftestStatus,
                        sizeof(selftestStatus) ));

} /* updateIbcGf5vAlarmsDm() */

/*****************************************************************************/
/* Function    : updateIbcGf5vDmItems                                       */
/* Purpose     : Reads GF/5V Board parameters from IBC & update Data Manager */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : None, but Data Manager Items change                         */
/*****************************************************************************/
    Void
updateIbcGf5vDmItems( sio32Chan* sio32DataChan, Word boardAddr,
    ibcGf5vDmItems* gf5vDmItems, const char* ibcDataCon )
{
    MBool gfEnable = FALSE;

    Int16 tempWarn, tempAlarm;
    Int16 voltageWarn, voltageAlarm;
    Int32 chargeTimes[GF_MAX_CHANS];

    if (IBC_gf5vGetTempThresh( sio32DataChan, boardAddr, &tempWarn, &tempAlarm)
         == ERROR)
    {
        logMsg("%s: Error reading GF/5V Temp Alarm Thresholds\n", ibcDataCon);
        return;
    } /* if */

    if (IBC_gf5vGetVoltageThresh( sio32DataChan, boardAddr,
        &voltageWarn, &voltageAlarm ) == ERROR)
    {
        logMsg("%s: Error reading GF/5V Voltage Alarm Thresholds\n",
               ibcDataCon);
        return;
    } /* if */

    if (IBC_gf5vGetChargeTimes( sio32DataChan, boardAddr, chargeTimes) == ERROR)
    {
        logMsg("%s: Error reading GF/5V Charge Times\n", ibcDataCon);
        return;
    } /* if */

    urgentWriteDmItem( gf5vDmItems->gf_enable, &gfEnable, sizeof(gfEnable) );

    urgentWriteDmItem( gf5vDmItems->tempWarnThresh,
                      &tempWarn, sizeof(tempWarn) );

    urgentWriteDmItem( gf5vDmItems->tempAlarmThresh,
                      &tempAlarm, sizeof(tempAlarm) );

    urgentWriteDmItem( gf5vDmItems->voltageWarnThresh,
                      &voltageWarn, sizeof(voltageWarn) );

    urgentWriteDmItem( gf5vDmItems->voltageAlarmThresh,
                      &voltageAlarm, sizeof(voltageAlarm) );

    urgentWriteDmItem( gf5vDmItems->gfChan[0].chargeTime,
                      &chargeTimes[0], sizeof(chargeTimes[0]) );

    urgentWriteDmItem( gf5vDmItems->gfChan[1].chargeTime,
                      &chargeTimes[1], sizeof(chargeTimes[1]) );

    urgentWriteDmItem( gf5vDmItems->gfChan[2].chargeTime,
                      &chargeTimes[2], sizeof(chargeTimes[2]) );

    urgentWriteDmItem( gf5vDmItems->gfChan[3].chargeTime,
                      &chargeTimes[3], sizeof(chargeTimes[3]) );

} /* updateIbcGf5vDmItems() */

    STATUS
ibcConnectGf5vDmItems( ibcGf5vDmItems *gf5vDmItems, gfChanItems *device,
    Nat16 chan, char *gfChargeTime, char *gfCurrent, char *gfAlarmStatus)
{
                                    /* GF Charge Time Data Manager Item       */
    if ( (device->chargeTime = initMicroDmItem(GF_SYSTEM_DM_PREFIX,
          gfChargeTime,  DM_INT32, 1)) == ERROR) return(ERROR);

                                    /* GF Current Data Manager Item           */
    if ( (device->faultCurrent = initMicroDmItem(GF_SYSTEM_DM_PREFIX,
          gfCurrent,     DM_INT16, 1)) == ERROR) return(ERROR);

                                    /* GF Alarm Status Dm Item                */
    if ( (device->alarmStatus = initMicroDmItem(GF_SYSTEM_DM_PREFIX,
          gfAlarmStatus, DM_ENUM, 1)) == ERROR) return(ERROR);

    dm_connect(device->chargeTime, gf5vDmItems->gfChan[chan].chargeTime);

    dm_connect(gf5vDmItems->gfChan[chan].faultCurrent, device->faultCurrent);
    dm_connect(gf5vDmItems->gfChan[chan].alarmStatus,  device->alarmStatus);

    return(OK);
} /* ibcConnectGf5vItems() */

/****************************************************************************/
/* Function    : ibcGf5vSetChargeTimes                                      */
/* Purpose     : Set GF/5V Board Charge Up times data manager items         */
/* Inputs      : GF/5V Board item handle structure & charge times           */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    STATUS
ibcGf5vSetChargeTimes( sio32Chan *sio32SerialChan, Word boardAddr,
    ibcGf5vDmItems* gf5vDmItems,
    Int32 charge0, Int32 charge1, Int32 charge2, Int32 charge3 )
{
    Int32 chan;
    Int32 chargeTimes[GF_MAX_CHANS];

    chargeTimes[0] = charge0;
    chargeTimes[1] = charge1;
    chargeTimes[2] = charge2;
    chargeTimes[3] = charge3;

    for (chan = 0; chan < GF_MAX_CHANS; chan++)
        urgentWriteDmItem( gf5vDmItems->gfChan[chan].chargeTime,
            &chargeTimes[chan], sizeof(chargeTimes[chan]) );

    return (IBC_gf5vSetChargeTimes( sio32SerialChan, boardAddr, chargeTimes ));
} /* ibcGf5vSetChargeTimes() */

    STATUS
enableGf5vMonitoring(sio32Chan *sio32DataChan, Word boardAddr,
    ibcGf5vDmItems* gf5vDmItems, MBool gfEnable )
{
    if (gfEnable) gfEnable = ~FALSE;

    urgentWriteDmItem( gf5vDmItems->gf_enable, &gfEnable, sizeof(gfEnable) );
    return (IBC_gf5vEnableGf( sio32DataChan, boardAddr, gfEnable ));
} /* enableGf5vMonitoring() */

    STATUS
runGf5vBoardSelftest(sio32Chan *sio32DataChan, Word boardAddr,
    ibcGf5vDmItems* gf5vDmItems )
{
    urgentWriteDmItem( gf5vDmItems->selftestCmd, NULL, 0 );
    return(IBC_gf5vRunSelftest(sio32DataChan, boardAddr));
} /* runGf5vBoardSelftest() */

     Void
ibcGf5vUpdateCheck( sio32Chan* sio32DataChan, Word boardAddr,
     ibcGf5vDmItems* gf5vDmItems, gf5vUpdateBits *gf5vBits, DM_Group gf5vGroup )
{
    DWord gf5vGroupBits;            /* Holds dm_group_changes bit vector     */

    Int32 chargeTimes[GF_MAX_CHANS];
    Int16 tempWarn, tempAlarm;
    Int16 voltageWarn, voltageAlarm;
    Nat16 busCapacitance;
    MBool gfEnable;

                                    /* Ask DMgr If GF/5V items have changed  */
    if ( (gf5vGroupBits = dm_get_group_changes(gf5vGroup)) == (DWord) 0)
        return;

    if (gf5vGroupBits & gf5vBits->gfEnableBit)
    {
        dm_read( gf5vDmItems->gf_enable, (char *) &gfEnable,
            sizeof(gfEnable), (DM_Time *) NULL);

        IBC_gf5vEnableGf( sio32DataChan, boardAddr, gfEnable );
    } /* if */

    if (gf5vGroupBits & gf5vBits->selftestBit)
        IBC_gf5vRunSelftest( sio32DataChan, boardAddr );

                                    /* GF/5V Board Temperature Thresholds    */
    if ( (gf5vGroupBits & gf5vBits->tempWarnBit)  ||
         (gf5vGroupBits & gf5vBits->tempAlarmBit) )
    {
                                        /* Read Temp Thresholds from DMgr    */
        dm_read( gf5vDmItems->tempWarnThresh, (char *) &tempWarn,
            sizeof(tempWarn), (DM_Time *) NULL);

        dm_read( gf5vDmItems->tempAlarmThresh, (char *) &tempAlarm,
            sizeof(tempAlarm), (DM_Time *) NULL);

        IBC_gf5vSetTempThresh( sio32DataChan, boardAddr, tempWarn, tempAlarm);
    } /* if */

                                    /* GF/5V Board Voltage Thresholds        */
    if ( (gf5vGroupBits & gf5vBits->voltageWarnBit)  ||
         (gf5vGroupBits & gf5vBits->voltageAlarmBit) )
    {
                                    /* Read Voltage Thresholds from DMgr */
        dm_read( gf5vDmItems->voltageWarnThresh, (char *) &voltageWarn,
            sizeof(voltageWarn), (DM_Time *) NULL);

        dm_read( gf5vDmItems->voltageAlarmThresh, (char *) &voltageAlarm,
            sizeof(voltageAlarm), (DM_Time *) NULL);

        IBC_gf5vSetVoltageThresh( sio32DataChan, boardAddr,
            voltageWarn, voltageAlarm );
    } /* if */

    if (gf5vGroupBits & gf5vBits->busCapBit)
    {
        dm_read( gf5vDmItems->busCapacitance, (char *) &busCapacitance,
            sizeof(busCapacitance), (DM_Time *) NULL);

        IBC_gf5vSetBusCapacitance( sio32DataChan, boardAddr, busCapacitance );
    } /* if */

                                    /* GF/5V Board Charge Up Times           */
    if ( (gf5vGroupBits & gf5vBits->chan0ChargeBit)  ||
         (gf5vGroupBits & gf5vBits->chan1ChargeBit)  ||
         (gf5vGroupBits & gf5vBits->chan2ChargeBit)  ||
         (gf5vGroupBits & gf5vBits->chan3ChargeBit) )
    {
                                    /* Read Charge Times from DMgr          */
        dm_read( gf5vDmItems->gfChan[0].chargeTime, (char *) &chargeTimes[0],
            sizeof(chargeTimes[0]), (DM_Time *) NULL);

        dm_read( gf5vDmItems->gfChan[1].chargeTime, (char *) &chargeTimes[1],
            sizeof(chargeTimes[1]), (DM_Time *) NULL);

        dm_read( gf5vDmItems->gfChan[2].chargeTime, (char *) &chargeTimes[2],
            sizeof(chargeTimes[2]), (DM_Time *) NULL);

        dm_read( gf5vDmItems->gfChan[3].chargeTime, (char *) &chargeTimes[3],
            sizeof(chargeTimes[3]), (DM_Time *) NULL);

        IBC_gf5vSetChargeTimes( sio32DataChan, boardAddr, chargeTimes );
    } /* if */
} /* ibcGf5vUpdateCheck() */

    MBool
processIbcGf5vSRQ( Word srqRequest, Byte* buffer, Word gf5vBoardAddr,
    ibcGf5vDmItems* gf5vItems )
{
    Word boardAddr;                 /* IBC Board Address                     */
    Word chan;                      /* IBC Board Channel Number              */
    Word status;                    /* IBC Alarm Status Word                 */
    ibcAlarm alarmStatus;           /* IBC Alarm Status                      */
    gfStatus gfAlarm;               /* Ground Fault Alarm Status             */
    gfStatus offset = (gfStatus) GF_CURRENT_NORMAL_SRQ;
    gf5v_gfTestStatus selftestStatus;

    switch (srqRequest)
    {
        case GF_TEMP_ALARM_SRQ:
            wordsFromBuf(buffer, 3, &srqRequest, &status, &boardAddr);
            alarmStatus = (ibcAlarm) status;

            if (boardAddr != gf5vBoardAddr)
                return(FALSE);          /* Address missmatch                 */

            writeDmItem(gf5vItems->tempAlarm, &alarmStatus,
                        sizeof(alarmStatus));
            break;

        case GF_VOLTAGE_ALARM_SRQ:
            wordsFromBuf(buffer, 3, &srqRequest, &status, &boardAddr);
            alarmStatus = (ibcAlarm) status;

            if (boardAddr != gf5vBoardAddr)
                return(FALSE);          /* Address missmatch                 */

            writeDmItem(gf5vItems->voltageAlarm, &alarmStatus,
                        sizeof(alarmStatus));
            break;

         case GF_CURRENT_ALARM_SRQ:
            wordsFromBuf(buffer, 4, &srqRequest, &status, &boardAddr, &chan);

            if ( (boardAddr != gf5vBoardAddr) || (chan > GF_MAX_CHANS) )
                return(FALSE);          /* Address missmatch or bad channel  */

            gfAlarm = (gfStatus) status;

            writeDmItem(gf5vItems->gfChan[chan].alarmStatus, &gfAlarm,
                        sizeof(gfAlarm));
            break;

         case GF_CURRENT_NORMAL_SRQ:
         case GF_CURRENT_ADVISORY_SRQ:
         case GF_CURRENT_WARNING_SRQ:
         case GF_CURRENT_CRITICAL_SRQ:
            wordsFromBuf(buffer, 3, &srqRequest, &boardAddr, &chan);

            if ( (boardAddr != gf5vBoardAddr) || (chan > GF_MAX_CHANS) )
                return(FALSE);          /* Address missmatch or bad channel  */

            gfAlarm = ((gfStatus) srqRequest) - offset;

            writeDmItem(gf5vItems->gfChan[chan].alarmStatus, &gfAlarm,
                        sizeof(gfAlarm));
            break;

        case GF_SELFTEST_STATUS_SRQ:
            wordsFromBuf(buffer, 3, &srqRequest, &status, &boardAddr);
            selftestStatus = (gf5v_gfTestStatus) status;

            if (boardAddr != gf5vBoardAddr)
                return(FALSE);          /* Address missmatch or bad channel  */

            writeDmItem(gf5vItems->selftestStatus, &selftestStatus,
                        sizeof(selftestStatus));
            break;

        default:
            return(FALSE);              /* SRQ Request not recognized        */

    } /* switch */

    return(TRUE);                       /* SRQ Request recognized            */
} /* processIbcGf5vSRQ() */

/****************************************************************************/
/* Function    : setGf5vChargeTimes                                         */
/* Purpose     : Set GF/5V Board Charge Up times data manager items         */
/* Inputs      : GF/5V Board item handle structure & charge times           */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    Void
setGf5vChargeTimes( ibcGf5vDmItems* gf5vDmItems,
    Int32 charge0, Int32 charge1, Int32 charge2, Int32 charge3 )
{
    urgentWriteDmItem( gf5vDmItems->gfChan[0].chargeTime,
                      &charge0, sizeof(charge0) );

    urgentWriteDmItem( gf5vDmItems->gfChan[1].chargeTime,
                      &charge1, sizeof(charge1) );

    urgentWriteDmItem( gf5vDmItems->gfChan[2].chargeTime,
                      &charge2, sizeof(charge2) );

    urgentWriteDmItem( gf5vDmItems->gfChan[3].chargeTime,
                      &charge3, sizeof(charge3) );

} /* setGf5vChargeTimes() */

    Void
clearIbcGf5vAlarmsDm( ibcGf5vDmItems *gf5vDmItems )
{
    Int32        chan;
    gfStatus     gfAlarms[GF_MAX_CHANS] = { GF_NORMAL };

    for (chan = 0; chan < GF_MAX_CHANS; chan++)
      urgentWriteDmItem(gf5vDmItems->gfChan[chan].alarmStatus,
             &gfAlarms[chan], sizeof(gfAlarms[chan]) );
} /* clearIbcGf5vAlarmsDm() */
