/****************************************************************************/
/* Copyright 1992 to 1998 MBARI                                             */
/****************************************************************************/
/* Summary  : Power IBC Interface Module for VxWorks                        */
/* Filename : power_ibc.c                                                   */
/* Author   : Andrew Pearce                                                 */
/* Project  : Tiburon ROV                                                   */
/* Version  : Version 1.0                                                   */
/* Created  : 06/11/93                                                      */
/* Modified : 05/05/98                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: pwr_ibc.c,v 1.3 96/08/05 09:40:48 pean Exp $
 * $Log:        pwr_ibc.c,v $
 * Revision 1.3  96/08/05  09:40:48  09:40:48  pean (Andrew Pearce)
 * Installed in vehicle. Prior to microTask mods
 *
 * Revision 1.2  93/07/01  14:35:14  14:35:14  pean (Andrew Pearce)
 * Version after bench testing with power can
 *
 * Revision 1.1  93/06/14  13:22:30  13:22:30  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 <systime.h>                /* vxWorks time and date functions      */
#include <strLib.h>                 /* vxWorks string function library      */
#include <msgQLib.h>                /* vxWorks Message Queue Library        */

#include <mbariTypes.h>             /* MBARI style guide type declarations  */
#include <mbariConst.h>             /* Miscellaneous constants              */

#include <rovPriority.h>            /* MBARI Rov Application Priorities     */
#include <usrTime.h>                /* MBARI time and date functions        */

#include <datamgr.h>                /* Data Manager declarations            */
#include <dm_errno.h>               /* Data Manager error declarations      */

#include "powerAlloc.h"             /* Device Power Requirements            */
#include "powerDM.h"                /* Power System Data Manager Items      */
#include "powerTypes.h"             /* Power management Data Types          */
#include "console.h"                /* Topside Console Data Manager Items   */

#include "sio32Drv.h"                  /* Sio32 hardware and driver information*/
#include "sio32Server.h"            /* Sio32 server communication services  */
#include "sio32Client.h"            /* Sio32 client communication services  */
#include "powerIbc.h"               /* Power Can IBC Data Manager Items     */

#include "applic.h"                 /* Microcontroller applications         */
#include "microcmd.h"               /* Microcontroller commands             */
#include "microDm.h"                /* Micro Data Manager Items & Functions */
#include "microTask.h"              /* Microcontroller Task IO definitions  */

#define Boolean MBool               /* Map microcontroller Boolean to MBool */

#include "timer.h"                  /* IBC Micro Timer Definitions          */
#include "ibc_card.h"               /* IBC Card Types                       */
#include "ibc_cmd.h"                /* IBC Serial Commands                  */
#include "filter.h"                 /* IBC General IIR Filter Routines      */
#include "low_pwr.h"                /* Low Power Switch Board Definitions   */
#include "gf_board.h"               /* GF/5V Controller Board Definitions   */
#include "pwr_ibc.h"                /* Power Can Definitions                */

#include "ibc.h"                    /* Function Prototypes for ibc.c        */
#include "switch.h"                 /* IBC Power Switch Function Definitions*/
#include "ibcDm.h"                  /* IBC CPU Board Data Manager Functions */
#include "lpsDm.h"                  /* IBC LPS Board Data Manager Functions */
#include "hpsDm.h"                  /* IBC HPS Board Data Manager Functions */
#include "gf_5vDm.h"                /* IBC Ground Fault Board DMgr Functions*/
#include "gf_5v.h"                  /* IBC Ground Fault Board Definitions   */
#include "regenDm.h"                /* IBC Regen Board DMgr Functions       */

#ifdef PWR_IBC_A
#include "pwr_ibc_a.h"              /* Power IBC A Can Configuration        */
#else
#include "pwr_ibc_b.h"              /* Power IBC B Can Configuration        */
#endif

#define PWR_IBC_DM_PERIOD    200000 /* Power IBC Data provider period 2 Hz  */
#define HUMIDITY_DM_PERIOD  2000000 /* Humidity sensor provider period .5Hz */
#define FAN_SPEED_DM_PERIOD 2000000 /* Fan Speed provider period .5 Hz      */

#define NUM_TASKS                 3 /* Number of co-operating tasks         */

typedef struct                      /* Power IBC A IBC Data Manager Items   */
{
    ibcCpuDmItems   ibcDm;          /* IBC CPU Data Manager Items           */
    ibcRegenDmItems regenDm;        /* Regen Board Data Manager Items       */
    ibcGf5vDmItems  gf5vDm;         /* GF/5V Board Data Manager Items       */

    ibcLpsDmItems lpsDm[LPS_BOARDS];/* LPS Board Data Manager Items         */
    ibcHpsDmItems hpsDm[HPS_BOARDS];/* HPS Board Data Manager Items         */

    DM_Item waterAlarmStatus;       /* Water Alarm Detected TRUE/FALSE      */
    DM_Item waterAlarmThresh;       /* Water Alarm Threshold                */
    DM_Item fanSpeed;               /* Can Fan Speed                        */

    DM_Item gfMonitorDisableDm;     /* Disable Ground Fault for GFI Box     */
} pwrIbcDmItems;

#define MIN_240V_BUS_VOLTAGE_WARN   200 /* Minimum Bus Voltage Warning 200V */
#define MIN_240V_BUS_VOLTAGE_ALARM  195 /* Minimum Bus Voltage Alarm   195V */
#define MAX_240V_BUS_VOLTAGE_WARN   310 /* Maximum Bus Voltage Warning 310V */
#define MAX_240V_BUS_VOLTAGE_ALARM  320 /* Maximum Bus Voltage Alarm   320V */

#define MIN_48V_BUS_VOLTAGE_WARN  39000 /* Minimum Bus Voltage Warning 39V  */
#define MIN_48V_BUS_VOLTAGE_ALARM 38000 /* Minimum Bus Voltage Alarm   38V  */

#define THRUSTER_CURRENT_WARNING  27000 /* Thruster Current Warning 27 Amps */
#define THRUSTER_CURRENT_ALARM    29000 /* Thruster Current Alarm   30 Amps */
                                        /* Maximum expected thruster current*/
                                        /* observed to be 24 Amps           */

/****************************************************************************/

Void PWR_IBC_InTask(Reg pwrIbcDmItems *dmItems,  microIOControl *microIOCtrl);
Void PWR_IBC_OutTask(Reg pwrIbcDmItems* dmItems, microIOControl *microIOCtrl);

MLocal Void initPwrIbcDmItems(pwrIbcDmItems* dmItems, sio32Chan* dataChan);
MLocal Word processPwrIbcSRQ(Reg pwrIbcDmItems* dmItems,
    microIOControl *microIOCtrl);

/****************************************************************************/
/* Function    : pwrCanGetWaterAlarm                                        */
/* Purpose     : Read water alarm status from Power IBC microcontroller     */
/* Inputs      : Sio32 socket and pointer to water alarm status             */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
pwrCanGetWaterAlarm( sio32Chan *IBC_SerialChan, MBool *waterAlarmStatus )
{
                                    /* Send command to microcontroller      */
    return( microCommand(IBC_SerialChan, PWR_IBC_APP | GET_WATER_ALARM,
                        waterAlarmStatus) );
} /* pwrCanGetWaterAlarm() */

/***************************************************************************/
/* Function    : pwrCanSetWaterAlarmThresh                                  */
/* Purpose     : Send water alarm threshold value to Power IBC micro        */
/* Inputs      : Sio32 channel, water alarm threshold value                 */
/* Outputs     : Return OK or ERROR                                         */
/****************************************************************************/
    LOCAL STATUS
pwrCanSetWaterAlarmThresh( Reg sio32Chan *IBC_SerialChan,
    Int16 waterAlarmThresh )
{
    Word    status;                 /* Command Result from microcontroller  */

                                    /* Send command to microcontroller      */
    if ( sendMicroCommand( IBC_SerialChan, &status, sizeof(status),
         2, PWR_IBC_APP | SET_WATER_ALARM_THRESH, waterAlarmThresh )
         == ERROR ) return(ERROR);

                                    /* Check command result                 */
    return (wordFromBuf(&status, 0) == CMD_OK ? OK : ERROR);
} /* pwrCanSetWaterAlarmThresh() */

/****************************************************************************/
/* Function    : pwrCanGetWaterAlarmThresh                                  */
/* Purpose     : Reads water alarm threshold value from Power IBC micro     */
/* Inputs      : Sio32 channel, pointer to water alarm threshold            */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
pwrCanGetWaterAlarmThresh( sio32Chan *IBC_SerialChan, MBool *waterAlarmThresh )
{
                                    /* Send command to microcontroller      */
    return (microCommand( IBC_SerialChan,
                 PWR_IBC_APP | GET_WATER_ALARM_THRESH, waterAlarmThresh) );
} /* pwrCanGetWaterAlarmThresh() */

/****************************************************************************/
/* Function    : initWaterAlarmThreshDm                                     */
/* Purpose     : Read Water Alarm Threshold and update data manager item    */
/* Inputs      : Sio32 channel, water alarm threshold dm item handle        */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
initWaterAlarmThreshDm( sio32Chan *IBC_SerialChan, DM_Item waterAlarmThreshDm )
{
    Int16   waterAlarmThresh;           /* Water Alarm Threshold from IBC   */

                                        /* Get Water Alarm Threshold        */
    if (pwrCanGetWaterAlarmThresh( IBC_SerialChan, &waterAlarmThresh ) != OK)
        return (ERROR);

                                        /* We MUST use urgent open here as  */
                                        /* another task is normal provider  */
    dm_urgent_open(waterAlarmThreshDm, DM_STATIC);
    writeDmItem(waterAlarmThreshDm, &waterAlarmThresh,sizeof(waterAlarmThresh));
    dm_urgent_close(waterAlarmThreshDm);

    return(OK);
} /* initWaterAlarmThreshDm() */

/****************************************************************************/
/* Function    : writeWaterAlarmThresh                                      */
/* Purpose     : Get water alarm threshold value from dm and send to IBC    */
/* Inputs      : Sio32 channel, water threshold dm item handle              */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
writeWaterAlarmThresh( sio32Chan *sio32DataChan, DM_Item waterAlarmThreshDm )
{
    Errno   status;                     /* Result of dm_read                */
    Int16   waterAlarmThresh;           /* Water Alarm Threshold            */

                                        /* Read Water Alarm Thresh from dmgr*/
    status = dm_read( waterAlarmThreshDm, (char *) &waterAlarmThresh,
         sizeof(waterAlarmThresh), (DM_Time *) NULL);
                                        /* Check for successful dm_read     */
    if ((status == SUCCESS) || (status == EDM_NOPROVIDER))
                                        /* Send value to IBC CPU            */
        if (pwrCanSetWaterAlarmThresh( sio32DataChan, waterAlarmThresh) == OK)
            return (OK);

    return(ERROR);
} /* writeWaterAlarmThresh() */

/****************************************************************************/
/* Function    : updateWaterAlarmsDm                                        */
/* Purpose     : Reads micro Water Alarm status & updates dmgr item         */
/* Inputs      : Sio32 chan & water alarm status data manager item handles  */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateWaterAlarmsDm( sio32Chan *sio32DataChan, DM_Item waterAlarmDm)
{
    MBool waterAlarmStatus;         /* Microcontroller Water Alarm Status   */

                                    /* Read Water Alarm Status              */
    if (pwrCanGetWaterAlarm(sio32DataChan, &waterAlarmStatus) != OK)
        return(ERROR);

    waterAlarmStatus = (waterAlarmStatus ? TRUE : FALSE);

                                    /* Write water alarm status to Dmgr     */
    return ( writeDmItem(waterAlarmDm, &waterAlarmStatus,
         sizeof(waterAlarmStatus)) );
} /* updateWaterAlarmsDm() */

#ifdef PWR_IBC_A
/****************************************************************************/
/* Function    : updateFanSpeedDm                                           */
/* Purpose     : Reads Power Can Fan Speed value & updates dmgr item        */
/* Inputs      : Sio32 chan & fan speed data manager item handle            */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateFanSpeedDm( sio32Chan *sio32DataChan, DM_Item fanSpeedDm )
{
    Int16 fanSpeed;                 /* Power Can Fan Speed Sensor Value     */

                                    /* Read Fan Speed from micro            */
    if (microCommand(sio32DataChan, PWR_IBC_APP | GET_FAN_SPEED,
                     &fanSpeed) != OK) return(ERROR);
                                    /* Write Fan Speed value to Data Manager*/
    return (writeDmItem(fanSpeedDm, &fanSpeed, sizeof(fanSpeed) ));
} /* updateFanSpeedDm() */

#endif

/****************************************************************************/
/* Function    : createPowerIbcAppDmItems                                   */
/* Purpose     : Create Data Manager Items specific to Power IBC A          */
/* Inputs      : Pointer to structure of DM items, Power IBC DMgr prefix,   */
/*               Power IBC Data Concentrator Name                           */
/* Outputs     : Returns OK or ERROR                                        */
/***************************************************************************/
    LOCAL STATUS
createPowerAppDmItems( pwrIbcDmItems *pwrDmItems, const char* pwrDmPrefix,
    const char* pwrDataConName )
{
    dmItemList pwrIbcDmInit[] =     /* Data Manager Item Table for init     */

      { { &pwrDmItems->waterAlarmStatus,    "Water Alarm",
                HOUSING_WATER_ALARM_DM,         DM_MBOOL, 1 },

        { &pwrDmItems->waterAlarmThresh,    "Water Alarm Threshold",
                WATER_ALARM_THRESH_DM,          DM_NAT16, 1 },

        { &pwrDmItems->gfMonitorDisableDm,  "Ground Fault Monitor Disable",
                GF_MONITOR_DISABLE_DM,           DM_MBOOL, 1 },

#ifdef PWR_IBC_A
        { &pwrDmItems->fanSpeed,            "Fan Speed",
                FAN_SPEED_DM,                   DM_INT16, 1 },
#endif

        { NO_ITEM, NULL, NULL, DM_ENDT, 0 } };

                                   /* Create Power IBC Data Manager Items    */
    return (initMicroDmItemList(pwrIbcDmInit, pwrDmPrefix, pwrDataConName));
} /* createPowerAppDmItems() */

/****************************************************************************/
/* Function    : PWR_IBC_Task                                               */
/* Purpose     : Initializes communication with Power Can Data Concentrator.*/
/*               Provides interface between Power Data Concentrator and Data*/
/*               Manager items.                                             */
/* Inputs      : SIO32 serial channel number for Power Data Concentrator    */
/*               Physically maps the Data Concentrators to a serial channel */
/* Outputs     : Normally runs forever, but returns ERROR on fatal error    */
/****************************************************************************/
    STATUS
PWR_IBC_Task( Nat16 serialChannel )
{
    pwrIbcDmItems  dmItems;         /* Power IBC Data Manager handles       */
    microIOControl microIOCtrl;     /* Microcontroller IO Task control      */
    Int16 board;                    /* LPS & HPS Board Index                */

                                   /* Initialize serial channel and task   */
                                    /* synchronization resources            */
    if (initMicroTaskIO( &microIOCtrl, NUM_TASKS, serialChannel,
       pwrDmPrefix, strcat("/sio32/", pwrIbc), NO_ITEM) == ERROR)
    {
        logMsg("Error initializing IO for %s", pwrIbc);
        return(ERROR);
    } /* if */
                                    /* Clear Power Can Data Manager Items    */
    bzero((char *) &dmItems, sizeof(dmItems));

#ifdef PWR_IBC_A                   /* Make static power request for Power Can*/
    staticPowerMgrRequest( POWER_CAN_PWR_REQ_DM, POWER_CAN_PWR_OK_DM,
                           POWER_CAN_POWER, A240, HOTEL );
#endif
                                   /* Create IBC CPU Data Manager Items      */
    if (createIbcCpuDmItems(&dmItems.ibcDm, pwrDmPrefix, pwrDataConName)
        == ERROR)
    {                              /* Error occurred so print message & exit */
        sio32ChanDestroy( serialChannel, &microIOCtrl.sio32DataChan );
        return(ERROR);
    } /* if */
                                   /* Create Power IBC Application Items     */
    if (createPowerAppDmItems(&dmItems, pwrDmPrefix, pwrDataConName)
         == ERROR)
    {                              /* Error occurred so print message & exit */
        sio32ChanDestroy( serialChannel, &microIOCtrl.sio32DataChan );
        return(ERROR);
    } /* if */
                                    /* Declare this task a provider of items */
    dm_start_provider(dmItems.waterAlarmStatus,    DM_STATIC);

                                    /* Create Regen Board Data Manager Items */
    createIbcRegenDmItems( &dmItems.regenDm, pwrDmPrefix, pwrDataConName );
    initIbcRegenAlarmProvider( &dmItems.regenDm );

                                    /* Create GF/5V Board Data Manager Items */
    createIbcGf5vDmItems( &dmItems.gf5vDm, pwrDmPrefix, pwrDataConName );
    initIbcGf5vAlarmProvider( &dmItems.gf5vDm );

    for (board = 0; board < LPS_BOARDS; board++)
    {                               /* Create LPS Data Manager Items         */
        createIbcLpsDmItems( &dmItems.lpsDm[board], pwrDmPrefix,
            pwrDataConName, board );

        initIbcLpsAlarmProvider( &dmItems.lpsDm[board] );
    } /* for */

    for (board = 0; board < HPS_BOARDS; board++)
    {                               /* Create HPS Board Data Manager Items   */
        createIbcHpsDmItems(&dmItems.hpsDm[board], pwrDmPrefix,
            pwrDataConName, board );

        initIbcHpsAlarmProvider( &dmItems.hpsDm[board] );
    } /* for */

                                /* Initialize Power IBC Data Output Task     */
    if ((microIOCtrl.childTasks[OUT_TASK].taskId =
         taskSpawn("pwrIbcOut", PWR_IBC_OUT_PRIORITY, 0, PWR_IBC_OUT_STACKSIZE,
         (FUNCPTR) PWR_IBC_OutTask, (int) &dmItems, (int) &microIOCtrl,
         0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    {
                                    /* Close serial communication channel    */
        sio32ChanDestroy( serialChannel, &microIOCtrl.sio32DataChan );
        logMsg("Power IBC: Error spawning %s data output task\n", pwrIbc);
        return(ERROR);
    } /* if */

                                /* Initialize Power IBC Data Input Task      */
    if (( microIOCtrl.childTasks[IN_TASK].taskId =
         taskSpawn( "pwrIbcIn", PWR_IBC_IN_PRIORITY, 0, PWR_IBC_IN_STACKSIZE,
         (FUNCPTR) PWR_IBC_InTask, (int) &dmItems, (int) &microIOCtrl,
         0, 0, 0, 0, 0, 0, 0, 0) ) == ERROR)
    {
                                   /* Delete Power IBC A OutputTask          */
        taskDelete(microIOCtrl.childTasks[OUT_TASK].taskId);
        sio32ChanDestroy( serialChannel, &microIOCtrl.sio32DataChan );
        logMsg("Power IBC: Error spawning %s data input task\n", pwrIbc);
        return(ERROR);
    } /* if */

    FOREVER
    {                               /* Check if Power DCon is switched on    */
        if ((microDevPowerSwitchState(&microIOCtrl) != SWITCH_ON) ||
           ((microDevPowerSwitchState(&microIOCtrl) == SWITCH_ON) &&
            (microIOCtrl.resetEventCount != 0)))

                                    /* Process SRQ's from  micro             */
           while(processPwrIbcSRQ(&dmItems, &microIOCtrl) != MICRO_RESET_SRQ);

        microIOCtrl.resetEventCount++;   /* Count reset events ffrom micro   */

                                    /* Reset event received from Micro so    */
                                    /* Mark serial coms link as up           */
        setSerialLinkState(&microIOCtrl, LINK_UP);

                                    /* Initialize Static IBC DM Items        */
        if (initIbcCpuDmItems( &dmItems.ibcDm, &microIOCtrl.sio32DataChan,
            pwrDataConName, ibcCardSet) == OK)
        {                           /* Initialize Power IBC Application Items*/
            initPwrIbcDmItems( &dmItems, &microIOCtrl.sio32DataChan );
            updateIbcRegenAlarmsDm( &microIOCtrl.sio32DataChan,
               REGEN_BOARD_ADDR, &dmItems.regenDm );

            updateIbcGf5vAlarmsDm( &microIOCtrl.sio32DataChan, GF5V_BOARD_ADDR,
               &dmItems.gf5vDm );

            for (board = 0; board < LPS_BOARDS; board++)
                updateIbcLpsAlarmsDm(&microIOCtrl.sio32DataChan,
                    lpsBoardAddr[board], &dmItems.lpsDm[board] );

            for (board = 0; board < HPS_BOARDS; board++)
                updateIbcHpsAlarmsDm(&microIOCtrl.sio32DataChan,
                    hpsBoardAddr[board], &dmItems.hpsDm[board] );

                                     /* Wake up output task to configure micro*/
            semGive(microIOCtrl.childTasks[OUT_TASK].taskSyncSem);
        } /* if */
        else
            setSerialLinkState(&microIOCtrl, LINK_DOWN);

    } /* FOREVER */

                                    /* Delete Child Tasks                     */
    taskDelete(microIOCtrl.childTasks[IN_TASK].taskId);
    taskDelete(microIOCtrl.childTasks[OUT_TASK].taskId);

                                    /* Close serial communication channel    */
    sio32ChanDestroy( serialChannel, &microIOCtrl.sio32DataChan );

                        /* dm_stop_provider, dm_stop_consumer, etc are NOT   */
                        /* required when the task exits as the Data Manager  */
                        /* does this automatically when the task is deleted  */
                        /* via taskDeleteHookAdd() and dm_task_exit functions*/

    return(OK);         /* That's all folks                                  */
} /* PWR_IBC_Task() */

/*****************************************************************************/
/* Function    : initPwrIbcDmItems                                           */
/* Purpose     : Reads parameters from Power IBC & update Data Manager items */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : None, but Data Manager Items change                         */
/*****************************************************************************/
    LOCAL Void
initPwrIbcDmItems( pwrIbcDmItems* dmItems, sio32Chan* pwrIbcDataChan )
{
                                /* Set Micro Water Alarms initial value      */
    if (updateWaterAlarmsDm(pwrIbcDataChan, dmItems->waterAlarmStatus) == ERROR)
        logMsg("Power IBC: Error checking IBC A water alarm status\n");

} /* initPwrIbcDmItems() */

#ifdef PWR_IBC_A                    /* Configure for Power Can IBC A         */

/*****************************************************************************/
/* Function    : PWR_IBC_OutTask                                             */
/* Purpose     : Power IBC Output Task. Read DM items & write them to PWR IBC*/
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : Normally runs forever, but exits if error occurs            */
/*****************************************************************************/
    Void
PWR_IBC_OutTask(Reg pwrIbcDmItems *dmItems, Reg microIOControl *microIOCtrl)
{
    DM_Group cpuGroup;              /* CPU & Misc Item Data Manager Group    */
    DM_Group regenGroup;            /* Regen Board Data Manager Group        */
    DM_Group gf5vGroup;             /* GF/5V Board Data Manager Group        */
    DM_Group lpsGroup[LPS_BOARDS];  /* LPS Board Data Manager Group          */
    DM_Group hpsGroup[HPS_BOARDS];  /* HPS Board Data Manager Group          */

    SEM_ID  dmUpdateSem;            /* Data Manager Item Change wakeup sem   */
    SEM_ID  powerReqSem;            /* Power Request Update Semaphore        */

    Int16 board;                    /* HPS Board Index                       */
    MBool gfDisable;                /* Disables GF Monitoring                */

    cpuUpdateBits   ibcCpuBits;     /* CPU Board Parameter Update Bits       */
    regenUpdateBits regenBits;      /* Regen Board Parameter Update Bits     */
    gf5vUpdateBits  gf5vBits;       /* GF/5V Board Paramater Update Bits     */
    lpsUpdateBits   lpsBits[LPS_BOARDS];  /* LPS Board Paramater Update Bits */
    hpsUpdateBits   hpsBits[HPS_BOARDS];  /* HPS Board Parameter Update Bits */

    DWord   pwrIbcGroupBits;        /* Holds dm_group_changes bit vector     */
    DWord   waterAlarmThreshBit;    /* Water alarm threshold item change bit */

    DWord   lpsEnableBit[LPS_BOARDS]; /* LPS Enable Request change bit       */
    DWord   ersDconSwitchBit;       /* Emergency Rec DCon Switch Request bit */
    DWord   cameraDconSwitchBit;    /* Camera DCon Switch Request bit        */
    DWord   toolsled48VSwitchBit;   /* Toolsled 48V Bus Switch Request bit   */
    DWord   spare48VSwitchBit;      /* Spare 48V Bus Switch Request bit      */

    DWord   portHorizSwitchBit;     /* Port Thruster Switch Request bit      */
    DWord   stbdHorizSwitchBit;     /* Starbord Thruster Switch Request bit  */
    DWord   portVertSwitchBit;      /* Port Vertical Switch Request bit      */

    DWord   backupLightsSwitchBit;  /* Backup Lighting Switch Request bit    */
    DWord   toolsled240VSwitchBit;  /* Toolsled 240V Bus Switch Request bit  */
    DWord   vbMotorSwitchBit;       /* Variable Boyancy Switch Request bit   */
    DWord   portPanTiltSwitchBit;   /* Port Pan & Tilt Switch Request bit    */

    switchEntry emergencyDconSwitch;/* Emergency Recovery DCon Switch        */
    switchEntry cameraDconSwitch;   /* Camera Recovery DCon Switch           */
    switchEntry toolsled48VSwitch;  /* Toolsled 48V Bus Power Switch         */
    switchEntry spare48VSwitch;     /* Spare 48V Switch                      */
    switchEntry portPanTiltSwitch;  /* Port Pan & Tilt Can Switch            */

    switchEntry portHorizSwitch;    /* Port Horizontal Thruster Switch       */
    switchEntry stbdHorizSwitch;    /* Starbord Horizontal Thruster Switch   */
    switchEntry portVertSwitch;     /* Port Vertical Thruster Switch         */

    switchEntry backupLightsSwitch; /* Backup Lighting Switch                */
    switchEntry toolsled240VSwitch; /* Toolsled 240V Bus Power Switch        */
    switchEntry vbMotorSwitch;      /* Variable Buoyancy System Power Switch */

                                    /* Power IBC LPS Output Enable switches  */
    switchEntry lpsEnableSwitch[LPS_BOARDS];

                                    /* Create switch & power sync semaphores */
    if ( ((dmUpdateSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL) ||
         ((powerReqSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL) )
    {
        logMsg("Power IBC: Error initializing IBC A Input Task Resources\n");
        return;
    } /* if */

    initIbcSwitchEntry( &lpsEnableSwitch[0], SERIAL_CHAN,
        VICOR_STANDBY_POWER,        A48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],      LPS_VICOR_ENABLE,
        PWR_A_LPS0_48V_ENABLE_SWITCH_REQ_DM, PWR_A_LPS0_48V_ENABLE_STATUS_DM,
        dmUpdateSem,
        PWR_A_LPS0_48V_ENABLE_PWR_REQ_DM,    PWR_A_LPS0_48V_ENABLE_PWR_OK_DM,
        powerReqSem,                pwrDataConName,      "LPS 0 48V Enable");

    initIbcSwitchEntry( &lpsEnableSwitch[1], SERIAL_CHAN,
        VICOR_STANDBY_POWER,        A48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[1],      LPS_VICOR_ENABLE,
        PWR_A_LPS1_48V_ENABLE_SWITCH_REQ_DM, PWR_A_LPS1_48V_ENABLE_STATUS_DM,
        dmUpdateSem,
        PWR_A_LPS1_48V_ENABLE_PWR_REQ_DM,    PWR_A_LPS1_48V_ENABLE_PWR_OK_DM,
        powerReqSem,                pwrDataConName,      "LPS 1 48V Enable");

    initIbcSwitchEntry( &emergencyDconSwitch, SERIAL_CHAN,
        EMERGENCY_REC_POWER,            A48,                  HOTEL,
        LOW_POWER_SWITCH,            lpsBoardAddr[0],   ERS_DCON_SWITCH_CHAN,
        ERS_DCON_SWITCH_REQ_DM,      ERS_DCON_SWITCH_STATUS_DM,
        dmUpdateSem,
        ERS_DCON_PWR_REQ_DM,         ERS_DCON_PWR_OK_DM, powerReqSem,
        pwrDataConName,                 "Emergency Recovery DCon Switch ");

    initIbcSwitchEntry( &cameraDconSwitch,    SERIAL_CHAN,
        CAMERA_DCON_POWER,              A48,                  HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],   CAMERA_DCON_SWITCH_CHAN,
        CAMERA_DCON_SWITCH_REQ_DM,  CAMERA_DCON_SWITCH_STATUS_DM, dmUpdateSem,
        CAMERA_DCON_PWR_REQ_DM,     CAMERA_DCON_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                 "Camera Data Concentrator Switch");

    initIbcSwitchEntry( &toolsled48VSwitch,    SERIAL_CHAN,
        TOOLSLED_48V_POWER,             A48,                  TOOLS,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],   TOOLSLED_48V_SWITCH_CHAN,
        TOOLSLED_48V_SWITCH_REQ_DM, TOOLSLED_48V_SWITCH_STATUS_DM, dmUpdateSem,
        TOOLSLED_48V_PWR_REQ_DM,    TOOLSLED_48V_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                 "Toolsled 48V Bus Switch");

    initIbcSwitchEntry( &spare48VSwitch,    SERIAL_CHAN,
        SPARE_48V_POWER,               A48,                  TOOLS,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],   SPARE_48V_SWITCH_CHAN,
        SPARE_48V_SWITCH_REQ_DM, SPARE_48V_SWITCH_STATUS_DM, dmUpdateSem,
        SPARE_48V_PWR_REQ_DM,    SPARE_48V_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                 "Spare 48V Switch");

    initIbcSwitchEntry( &portPanTiltSwitch,   SERIAL_CHAN,
        PAN_TILT_DCON_POWER,            A48,                  HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[1], PORT_PAN_TILT_SWITCH_CHAN,
        PORT_PAN_TILT_DCON_SWITCH_REQ_DM,
        PORT_PAN_TILT_DCON_SWITCH_STATUS_DM, dmUpdateSem,
        PORT_PAN_TILT_DCON_PWR_REQ_DM,
        PORT_PAN_TILT_DCON_PWR_OK_DM,        powerReqSem,
        pwrDataConName,             "Port Pan & Tilt Switch" );

    initIbcSwitchEntry( &portHorizSwitch,  SERIAL_CHAN,
        THRUSTER_STANDBY_POWER,         A240,                 HOTEL,
        HIGH_POWER_SWITCH,              hpsBoardAddr[PORT_HORIZ_THRUST_HPS], 0,
        THRUSTER_PORT_HORIZ_SWITCH_REQ_DM,
        THRUSTER_PORT_HORIZ_SWITCH_STATUS_DM, dmUpdateSem,
        THRUSTER_PORT_HORIZ_PWR_REQ_DM,
        THRUSTER_PORT_HORIZ_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                "Port Horizontal Thruster Switch");

    initIbcSwitchEntry( &stbdHorizSwitch,  SERIAL_CHAN,
        THRUSTER_STANDBY_POWER,         A240,                 HOTEL,
        HIGH_POWER_SWITCH,              hpsBoardAddr[STBD_HORIZ_THRUST_HPS], 0,
        THRUSTER_STBD_HORIZ_SWITCH_REQ_DM,
        THRUSTER_STBD_HORIZ_SWITCH_STATUS_DM, dmUpdateSem,
        THRUSTER_STBD_HORIZ_PWR_REQ_DM,
        THRUSTER_STBD_HORIZ_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                "Starbord Horiz Thruster Switch");

    initIbcSwitchEntry( &portVertSwitch,  SERIAL_CHAN,
        THRUSTER_STANDBY_POWER,         A240,                 HOTEL,
        HIGH_POWER_SWITCH,              hpsBoardAddr[PORT_VERT_THRUST_HPS], 0,
        THRUSTER_PORT_VERT_SWITCH_REQ_DM,
        THRUSTER_PORT_VERT_SWITCH_STATUS_DM, dmUpdateSem,
        THRUSTER_PORT_VERT_PWR_REQ_DM,
        THRUSTER_PORT_VERT_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                "Port Vertical Thruster Switch");

    initIbcSwitchEntry( &backupLightsSwitch,  SERIAL_CHAN,
        BACKUP_LIGHT_POWER,             A240,                 LIGHTS,
        HIGH_POWER_SWITCH,              hpsBoardAddr[BACKUP_LIGHT_HPS], 0,
        BACKUP_LIGHT_SWITCH_REQ_DM,
        BACKUP_LIGHT_SWITCH_STATUS_DM,  dmUpdateSem,
        BACKUP_LIGHT_PWR_REQ_DM,
        BACKUP_LIGHT_PWR_OK_DM,         powerReqSem,
        pwrDataConName,                "Backup Lighting Switch");

    initIbcSwitchEntry( &toolsled240VSwitch,  SERIAL_CHAN,
        TOOLSLED_240V_POWER,            A240,                 TOOLS,
        HIGH_POWER_SWITCH,              hpsBoardAddr[TOOLSLED_240V_HPS], 0,
        TOOLSLED_240V_SWITCH_REQ_DM,
        TOOLSLED_240V_SWITCH_STATUS_DM, dmUpdateSem,
        TOOLSLED_240V_PWR_REQ_DM,
        TOOLSLED_240V_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                "Toolsled 240V Bus Switch");

    initIbcSwitchEntry( &vbMotorSwitch,       SERIAL_CHAN,
        VB_MOTOR_POWER,                A240,                 TOOLS,
        HIGH_POWER_SWITCH,             hpsBoardAddr[VB_MOTOR_HPS], 0,
        VB_MOTOR_SWITCH_REQ_DM,
        VB_MOTOR_SWITCH_STATUS_DM,    dmUpdateSem,
        VB_MOTOR_PWR_REQ_DM,
        VB_MOTOR_PWR_OK_DM,           powerReqSem,
        pwrDataConName,               "Variable Buoyancy Motor Switch");

                                  /* Devices on Power Can Low Power Switches*/
    ibcAddSwitchInSeries( &lpsEnableSwitch[0], &emergencyDconSwitch);
    ibcAddSwitchInSeries( &lpsEnableSwitch[0], &cameraDconSwitch);
    ibcAddSwitchInSeries( &lpsEnableSwitch[0], &toolsled48VSwitch);
    ibcAddSwitchInSeries( &lpsEnableSwitch[0], &spare48VSwitch);

    ibcAddSwitchInSeries( &lpsEnableSwitch[1], &portPanTiltSwitch);

    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &emergencyDconSwitch,
         pwrDataConName, "Emergency Recovery DCon",  ERS_DCON_SWITCH_CHAN,
         ERS_DCON_CURRENT_DM,                ERS_DCON_CURRENT_ALARM_DM,
         ERS_DCON_CURRENT_WARN_LVL_DM,       ERS_DCON_CURRENT_ALARM_LVL_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &cameraDconSwitch,
         pwrDataConName, "Camera DCon",      CAMERA_DCON_SWITCH_CHAN,
         CAMERA_DCON_CURRENT_DM,             CAMERA_DCON_CURRENT_ALARM_DM,
         CAMERA_DCON_CURRENT_WARN_LVL_DM,    CAMERA_DCON_CURRENT_ALARM_LVL_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &toolsled48VSwitch,
         pwrDataConName, "Toolsled 48V Bus", TOOLSLED_48V_SWITCH_CHAN,
         TOOLSLED_48V_CURRENT_DM,            TOOLSLED_48V_CURRENT_ALARM_DM,
         TOOLSLED_48V_CURRENT_WARN_LVL_DM,   TOOLSLED_48V_CURRENT_ALARM_LVL_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &spare48VSwitch,
         pwrDataConName, "Spare 48V",        SPARE_48V_SWITCH_CHAN,
         SPARE_48V_CURRENT_DM,               SPARE_48V_CURRENT_ALARM_DM,
         SPARE_48V_CURRENT_WARN_LVL_DM,      SPARE_48V_CURRENT_ALARM_LVL_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[1], &portPanTiltSwitch,
         pwrDataConName, "Port Pan & Tilt DCon", PORT_PAN_TILT_SWITCH_CHAN,
         PORT_PAN_TILTS_CURRENT_DM,
         PORT_PAN_TILTS_CURRENT_ALARM_DM,
         PORT_PAN_TILTS_CURRENT_WARN_LVL_DM,
         PORT_PAN_TILTS_CURRENT_ALARM_LVL_DM );

    ibcConnectHpsDmItems( &dmItems->hpsDm[STBD_HORIZ_THRUST_HPS],
         &stbdHorizSwitch, pwrDataConName, "Starbord Horizontal Thruster",
         STBD_HORIZ_THRUST_CURRENT_DM,
         STBD_HORIZ_THRUST_CURRENT_ALARM_DM,
         STBD_HORIZ_THRUST_CURRENT_WARN_LVL_DM,
         STBD_HORIZ_THRUST_CURRENT_ALARM_LVL_DM,
         STBD_HORIZ_THRUST_SWITCH_TRIP_DM );

    ibcConnectHpsDmItems( &dmItems->hpsDm[PORT_HORIZ_THRUST_HPS],
         &portHorizSwitch, pwrDataConName, "Port Horizontal Thruster",
         PORT_HORIZ_THRUST_CURRENT_DM,
         PORT_HORIZ_THRUST_CURRENT_ALARM_DM,
         PORT_HORIZ_THRUST_CURRENT_WARN_LVL_DM,
         PORT_HORIZ_THRUST_CURRENT_ALARM_LVL_DM,
         PORT_HORIZ_THRUST_SWITCH_TRIP_DM );

    ibcConnectHpsDmItems( &dmItems->hpsDm[PORT_VERT_THRUST_HPS],
         &portVertSwitch, pwrDataConName, "Port Vertical Thruster",
         PORT_VERT_THRUST_CURRENT_DM,
         PORT_VERT_THRUST_CURRENT_ALARM_DM,
         PORT_VERT_THRUST_CURRENT_WARN_LVL_DM,
         PORT_VERT_THRUST_CURRENT_ALARM_LVL_DM,
         PORT_VERT_THRUST_SWITCH_TRIP_DM );

    ibcConnectHpsDmItems( &dmItems->hpsDm[BACKUP_LIGHT_HPS],
         &backupLightsSwitch, pwrDataConName, "Backup Lights",
         BACKUP_LIGHT_CURRENT_DM,
         BACKUP_LIGHT_CURRENT_ALARM_DM,
         BACKUP_LIGHT_CURRENT_WARN_LVL_DM,
         BACKUP_LIGHT_CURRENT_ALARM_LVL_DM,
         BACKUP_LIGHT_SWITCH_TRIP_DM );

    ibcConnectHpsDmItems( &dmItems->hpsDm[TOOLSLED_240V_HPS],
         &toolsled240VSwitch, pwrDataConName, "Toolsled 240V Bus",
         TOOLSLED_240V_CURRENT_DM,
         TOOLSLED_240V_CURRENT_ALARM_DM,
         TOOLSLED_240V_CURRENT_WARN_LVL_DM,
         TOOLSLED_240V_CURRENT_ALARM_LVL_DM,
         TOOLSLED_240V_SWITCH_TRIP_DM );

    ibcConnectHpsDmItems( &dmItems->hpsDm[VB_MOTOR_HPS],
         &vbMotorSwitch, pwrDataConName, "Variable Buoyancy Motor",
         VARIABLE_BUOYANCY_CURRENT_DM,
         VARIABLE_BUOYANCY_CURRENT_ALARM_DM,
         VARIABLE_BUOYANCY_CURRENT_WARN_LVL_DM,
         VARIABLE_BUOYANCY_CURRENT_ALARM_LVL_DM,
         VARIABLE_BUOYANCY_SWITCH_TRIP_DM );

    cpuGroup = initIbcCpuConsumer(&dmItems->ibcDm, &ibcCpuBits, dmUpdateSem);

                                    /* Use CPU Group for Water Alarm Thresh  */
    dm_start_consumer(dmItems->waterAlarmThresh,   DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->gfMonitorDisableDm, DM_STATIC, dmUpdateSem);
    dm_group_add_item(cpuGroup, dmItems->waterAlarmThresh,
                      &waterAlarmThreshBit);

    regenGroup =                     /* Create Regen Board Data Manager Group*/
        initIbcRegenConsumer(&dmItems->regenDm, &regenBits, dmUpdateSem);

    gf5vGroup = initIbcGf5vConsumer( &dmItems->gf5vDm, &gf5vBits, dmUpdateSem );

                                      /* Create LPS Data Manager Group       */
    for (board = 0; board < LPS_BOARDS; board++)
    {
        lpsGroup[board] = initIbcLpsConsumer( &dmItems->lpsDm[board],
            &lpsBits[board], dmUpdateSem );

                                      /* Add Switch Requests to DM Group     */
        dm_group_add_item(cpuGroup,
           lpsEnableSwitch[board].switchRequestDm, &lpsEnableBit[board]);
    } /* for */

    for (board = 0; board < HPS_BOARDS; board++)
        hpsGroup[board] = initIbcHpsConsumer(&dmItems->hpsDm[board],
            &hpsBits[board], dmUpdateSem);

                                /* Define associated Ground Fault board      */
    ibcHpsDefineGfBoard( &portHorizSwitch, GF5V_BOARD_ADDR );
    ibcHpsDefineGfBoard( &stbdHorizSwitch, GF5V_BOARD_ADDR );
    ibcHpsDefineGfBoard( &portVertSwitch,  GF5V_BOARD_ADDR );
    ibcHpsDefineGfBoard( &vbMotorSwitch,   GF5V_BOARD_ADDR );

                                      /* Add Switch Requests to DM Group     */
    dm_group_add_item(cpuGroup, emergencyDconSwitch.switchRequestDm,
                      &ersDconSwitchBit);

    dm_group_add_item(cpuGroup, cameraDconSwitch.switchRequestDm,
                      &cameraDconSwitchBit);

    dm_group_add_item(cpuGroup, toolsled48VSwitch.switchRequestDm,
                      &toolsled48VSwitchBit);

    dm_group_add_item(cpuGroup, spare48VSwitch.switchRequestDm,
                      &spare48VSwitchBit);

    dm_group_add_item(cpuGroup, portHorizSwitch.switchRequestDm,
                      &portHorizSwitchBit);

    dm_group_add_item(cpuGroup, stbdHorizSwitch.switchRequestDm,
                      &stbdHorizSwitchBit);

    dm_group_add_item(cpuGroup, portVertSwitch.switchRequestDm,
                      &portVertSwitchBit);

    dm_group_add_item(cpuGroup, backupLightsSwitch.switchRequestDm,
                      &backupLightsSwitchBit);

    dm_group_add_item(cpuGroup, toolsled240VSwitch.switchRequestDm,
                      &toolsled240VSwitchBit);

    dm_group_add_item(cpuGroup, vbMotorSwitch.switchRequestDm,
                      &vbMotorSwitchBit);

    dm_group_add_item(cpuGroup, portPanTiltSwitch.switchRequestDm,
                      &portPanTiltSwitchBit);

    FOREVER
    {                               /* Mark micro configuration as invalid    */
        microIOCtrl->microConfigured = FALSE;

                                    /* Wait for micro reset via SRQ Task      */
        semTake(microIOCtrl->childTasks[OUT_TASK].taskSyncSem, WAIT_FOREVER);

        ibcSetSwitchState( &portHorizSwitch,     SWITCH_OFF );
        ibcSetSwitchState( &stbdHorizSwitch,     SWITCH_OFF );
        ibcSetSwitchState( &portVertSwitch,      SWITCH_OFF );

                                    /* Initialize DM item values and default */
                                    /* IBC Switch states                     */
        ibcSetSwitchState( &emergencyDconSwitch, SWITCH_ON );
        ibcSetSwitchState( &cameraDconSwitch,    SWITCH_ON );
        ibcSetSwitchState( &toolsled48VSwitch,   SWITCH_OFF );
        ibcSetSwitchState( &spare48VSwitch,      SWITCH_OFF );

        ibcSetSwitchState( &backupLightsSwitch,  SWITCH_OFF );
        ibcSetSwitchState( &toolsled240VSwitch,  SWITCH_OFF );
        ibcSetSwitchState( &vbMotorSwitch,       SWITCH_OFF );
        ibcSetSwitchState( &portPanTiltSwitch,   SWITCH_OFF );

        for (board = 0; board < LPS_BOARDS; board++)
            ibcSetSwitchState (&lpsEnableSwitch[board], SWITCH_ON );

        /* We need to initialize default state of Data manager Items here     */

        initIbcHumidityThreshDm( SERIAL_CHAN,
            dmItems->ibcDm.humidityWarnThresh,
            dmItems->ibcDm.humidityAlarmThresh );

        initWaterAlarmThreshDm ( SERIAL_CHAN, dmItems->waterAlarmThresh );

        initIbcRegenDmItems( SERIAL_CHAN, REGEN_BOARD_ADDR,
            &dmItems->regenDm, pwrDataConName );

        ibcRegenSetBusVoltageAlarmThresh(SERIAL_CHAN, REGEN_BOARD_ADDR,
            &dmItems->regenDm,
            MIN_240V_BUS_VOLTAGE_WARN, MIN_240V_BUS_VOLTAGE_ALARM,
            MAX_240V_BUS_VOLTAGE_WARN, MAX_240V_BUS_VOLTAGE_ALARM);

        updateIbcGf5vDmItems( SERIAL_CHAN, GF5V_BOARD_ADDR, &dmItems->gf5vDm,
            pwrDataConName );

        dm_read( dmItems->gfMonitorDisableDm, (char *) &gfDisable,
             sizeof(gfDisable), (DM_Time *) NULL );

        if (gfDisable)
        {
            enableGf5vMonitoring(SERIAL_CHAN, GF5V_BOARD_ADDR,
                &dmItems->gf5vDm, FALSE );

            clearIbcGf5vAlarmsDm(&dmItems->gf5vDm);
        } /* if */
        else
        {                            /* Set default charge time for PWR IBC A*/
            ibcGf5vSetChargeTimes(SERIAL_CHAN, GF5V_BOARD_ADDR,
                &dmItems->gf5vDm,
                HIGH_VOLTAGE_GF_CHARGE_TIME, HIGH_VOLTAGE_GF_CHARGE_TIME,
                HIGH_VOLTAGE_GF_CHARGE_TIME, HIGH_VOLTAGE_GF_CHARGE_TIME );

            enableGf5vMonitoring(SERIAL_CHAN, GF5V_BOARD_ADDR,
                &dmItems->gf5vDm, TRUE );

            runGf5vBoardSelftest(SERIAL_CHAN, GF5V_BOARD_ADDR,
                &dmItems->gf5vDm );
        } /* else */

        for (board = 0; board < LPS_BOARDS; board++)
        {
            updateIbcLpsDmItems( SERIAL_CHAN, lpsBoardAddr[board],
               &dmItems->lpsDm[board], pwrDataConName );

            setLpsVoltageThresh( SERIAL_CHAN, lpsBoardAddr[board],
                &dmItems->lpsDm[board],
                MIN_48V_BUS_VOLTAGE_WARN, MIN_48V_BUS_VOLTAGE_ALARM);
        } /* for */

        if (ibcSwitchGangOutputs( &portPanTiltSwitch ) != OK)
            printf("Port Pan/Tilt Output Gang Enable Failed\n");

        if (ibcSwitchSetCurrentThresh(&portPanTiltSwitch, 8000, 10000) != OK)
           printf("Port Pan/Tilt Error Setting Switch Current Threshold\n");

        ibcSwitchSetCurrentThresh( &portHorizSwitch,
            THRUSTER_CURRENT_WARNING, THRUSTER_CURRENT_ALARM );

        ibcSwitchSetCurrentThresh( &stbdHorizSwitch,
            THRUSTER_CURRENT_WARNING, THRUSTER_CURRENT_ALARM );

        ibcSwitchSetCurrentThresh( &portVertSwitch,
            THRUSTER_CURRENT_WARNING, THRUSTER_CURRENT_ALARM );

        ibcSwitchSetCurrentThresh( &vbMotorSwitch,
            THRUSTER_CURRENT_WARNING, THRUSTER_CURRENT_ALARM );

                                    /* Ask Data Manager which items changed  */
        pwrIbcGroupBits = dm_get_group_changes(cpuGroup);

                                    /* Flag that micro has been configured   */
        microIOCtrl->microConfigured = TRUE;

                                    /* Wake up input task to read from micro */
        semGive(microIOCtrl->childTasks[IN_TASK].taskSyncSem);

        while (microIOCtrl->serialLinkState == LINK_UP)
        {                           /* Repeat while serial link is up        */
                                    /* Wait for any data items to change     */
            semTake(dmUpdateSem, WAIT_FOREVER);

                                    /* Ask Data Manager which items changed  */
            pwrIbcGroupBits = dm_get_group_changes(cpuGroup);

                                    /* Check if micro Reset Event occurred   */
            if (pwrIbcGroupBits & ibcCpuBits.resetEventBit)
                break;              /* Exit loop and re-initialize DM items  */

            taskSafe();             /* Prevent task from being deleted during*/
                                    /* serial IO and Data Manager updates    */

                                    /* Power Can LPS Output Enable Request  */
            if (pwrIbcGroupBits & lpsEnableBit[0])
                ibcProcessSwitchRequest( &lpsEnableSwitch[0] );

            if (pwrIbcGroupBits & lpsEnableBit[1])
                ibcProcessSwitchRequest( &lpsEnableSwitch[1] );

                                    /* Emergency DCon Power Switch Request   */
            if (pwrIbcGroupBits & ersDconSwitchBit)
                ibcProcessSwitchRequest( &emergencyDconSwitch );

                                    /* Camera DCon Power Switch Request      */
            if (pwrIbcGroupBits & cameraDconSwitchBit)
                ibcProcessSwitchRequest( &cameraDconSwitch );

                                    /* Toolsled 48V Bus Power Switch Request */
            if (pwrIbcGroupBits & toolsled48VSwitchBit)
                ibcProcessSwitchRequest( &toolsled48VSwitch );

                                    /* Spare 48V Power Switch Request        */
            if (pwrIbcGroupBits & spare48VSwitchBit)
                ibcProcessSwitchRequest( &spare48VSwitch );

                                    /* Port Horiz Thruster Switch Request    */
            if (pwrIbcGroupBits & portHorizSwitchBit)
                ibcProcessSwitchRequest( &portHorizSwitch );

                                    /* Starbord Horiz Thruster Switch Request*/
            if (pwrIbcGroupBits & stbdHorizSwitchBit)
                ibcProcessSwitchRequest( &stbdHorizSwitch );

                                    /* Port Vert Thruster Switch Request     */
            if (pwrIbcGroupBits & portVertSwitchBit)
                ibcProcessSwitchRequest( &portVertSwitch );

                                    /* Backup Lights Power Switch Request    */
            if (pwrIbcGroupBits & backupLightsSwitchBit)
                ibcProcessSwitchRequest( &backupLightsSwitch );

                                    /* Toolsled 240V Bus Power Switch Request*/
            if (pwrIbcGroupBits & toolsled240VSwitchBit)
                ibcProcessSwitchRequest( &toolsled240VSwitch );

                                    /* Variable Buoyancy System Switch Request*/
            if (pwrIbcGroupBits & vbMotorSwitchBit)
                ibcProcessSwitchRequest( &vbMotorSwitch );

                                    /* Port Pan & Tilt Power Switch Request  */
            if (pwrIbcGroupBits & portPanTiltSwitchBit)
                ibcProcessSwitchRequest( &portPanTiltSwitch );

                                   /* Check for Regen Board Parameter Update*/
            ibcRegenUpdateCheck( SERIAL_CHAN, REGEN_BOARD_ADDR,
                              &dmItems->regenDm, &regenBits, regenGroup );

                                    /* Check for GF/5V Board Parameter Update */
            ibcGf5vUpdateCheck( SERIAL_CHAN, GF5V_BOARD_ADDR,
                              &dmItems->gf5vDm, &gf5vBits, gf5vGroup );

                                    /* Check for LPS Board Parameter Update  */
            for (board = 0; board < LPS_BOARDS; board++)
                ibcLpsUpdateCheck( SERIAL_CHAN, lpsBoardAddr[board],
                      &dmItems->lpsDm[board], &lpsBits[board],
                      lpsGroup[board] );

            for (board = 0; board < HPS_BOARDS; board++)
                ibcHpsUpdateCheck( SERIAL_CHAN, hpsBoardAddr[board],
                      &dmItems->hpsDm[board], &hpsBits[board],
                      hpsGroup[board] );

                                    /* Send Set Humidity Alarm Threshold cmd */
            if ((pwrIbcGroupBits & ibcCpuBits.humidityWarnThreshBit) ||
                (pwrIbcGroupBits & ibcCpuBits.humidityAlarmThreshBit))
                writeIbcHumidityThresh(SERIAL_CHAN,
                    dmItems->ibcDm.humidityWarnThresh,
                    dmItems->ibcDm.humidityAlarmThresh);

                                    /* Send Set Water Alarm Threshold cmd    */
            if (pwrIbcGroupBits & waterAlarmThreshBit)
                writeWaterAlarmThresh(SERIAL_CHAN, dmItems->waterAlarmThresh);

                                    /* Check if Reset Command request occurred*/
            if (pwrIbcGroupBits & ibcCpuBits.resetCmdBit)
            {                       /* Mark serial link as down               */
                setSerialLinkState(microIOCtrl, LINK_DOWN);
                                    /* Manual reset so ammounce it            */
                microIOCtrl->announceResets = TRUE;
                                    /* Send Reset Command to Microcontroller  */
                microResetCmd(SERIAL_CHAN);
                break;              /* Exit loop and wait for RESET           */
            } /* if */

            taskUnsafe();           /* Task may now be safely deleted         */

        } /* while (LINK_UP) */
    } /* FOREVER */

                        /* dm_stop_provider, dm_stop_consumer, dm_delete_group*/
                        /* etc are NOT required when the task exits as the    */
                        /* Data Manager does this automatically when the task */
                        /* is deleted via the taskDeleteHookAdd() and         */
                        /* dm_task_exit functions.                            */

                        /* That's all folks !                                 */
} /* PWR_IBC_OutTask() */

#else /* PWR_IBC_B */

/*****************************************************************************/
/* Function    : PWR_IBC_OutTask                                             */
/* Purpose     : Power IBC Output Task. Read DM items & write them to PWR IBC*/
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : Normally runs forever, but exits if error occurs            */
/*****************************************************************************/
     Void
PWR_IBC_OutTask(Reg pwrIbcDmItems *dmItems, Reg microIOControl *microIOCtrl)
{
    DM_Group cpuGroup;              /* CPU & Misc Item Data Manager Group    */
    DM_Group regenGroup;            /* Regen Board Data Manager Group        */
    DM_Group gf5vGroup;             /* GF/5V Board Data Manager Group        */
    DM_Group lpsGroup[LPS_BOARDS];  /* LPS Board Data Manager Group          */
    DM_Group hpsGroup[HPS_BOARDS];  /* HPS Board Data Manager Group          */

    SEM_ID  dmUpdateSem;            /* Data Manager Item Change wakeup sem   */
    SEM_ID  powerReqSem;            /* Power Request Update Semaphore        */

    Int16 board;                    /* LPS & HPS Board Index                 */
    MBool gfDisable;                /* Enables GF Monitoring                 */

    cpuUpdateBits   ibcCpuBits;     /* CPU Board Parameter Update Bits       */
    regenUpdateBits regenBits;      /* Regen Board Parameter Update Bits     */
    gf5vUpdateBits  gf5vBits;       /* GF/5V Board Paramater Update Bits     */
    lpsUpdateBits   lpsBits[LPS_BOARDS];  /* LPS Board Paramater Update Bits */
    hpsUpdateBits   hpsBits[HPS_BOARDS];  /* HPS Board Parameter Update Bits */

    DWord   pwrIbcGroupBits;        /* Holds dm_group_changes bit vector     */
    DWord   waterAlarmThreshBit;    /* Water alarm threshold item change bit */

    DWord   lpsEnableBit[LPS_BOARDS]; /* LPS Enable Request change bit       */
    DWord   sonarDconSwitchBit;     /* Sonar DCon Switch Request bit         */
    DWord   sensorDconSwitchBit;    /* Sensor DCon Switch Request bit        */
    DWord   manip48VSwitchBit;      /* Manipulator 48V Switch Request bit    */
    DWord   runningLightSwitchBit;  /* Vehicle Running Light Switch Req bit  */
    DWord   stbdPanTiltSwitchBit;   /* Stbd Pan & Tilt Switch Request bit    */

    DWord   fwdLatSwitchBit;        /* Fwd Lat Thruster Switch Request bit   */
    DWord   aftLatSwitchBit;        /* Aft Lat Thruster Switch Request bit   */
    DWord   stbdVertSwitchBit;      /* Stbd Vertical Switch Request bit      */

    DWord   lightDcon48VSwitchBit;  /* Lighting DCon 48V Switch Request bit  */
    DWord   lightDcon240VSwitchBit; /* Lighting DCon 240V Switch Request bit */

    switchEntry sonarDconSwitch;    /* Sonar Data Concentrator Switch        */
    switchEntry sensorDconSwitch;   /* Sensor Data Concentrator Switch       */
    switchEntry manip48VSwitch;     /* Manipulator 48V Power Switch          */
    switchEntry runningLightSwitch; /* Vehicle Running Power Switch          */

    switchEntry fwdLatSwitch;       /* Fwd Lateral Thruster Switch           */
    switchEntry aftLatSwitch;       /* Aft Lateral Thruster Switch           */
    switchEntry stbdVertSwitch;     /* Stbd Vertical Thruster Switch         */

    switchEntry stbdPanTiltSwitch;  /* Stbd Pan & Tilt Can Switch            */
    switchEntry lightDcon48VSwitch; /* Lighting DCon 48V Switch              */
    switchEntry lightDcon240VSwitch;/* Lighting DCon 240V Switch             */

                                    /* Power IBC LPS Output Enable switches  */
    switchEntry lpsEnableSwitch[LPS_BOARDS];

                                    /* Create switch & power sync semaphores */
    if ( ((dmUpdateSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL) ||
         ((powerReqSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL) )
    {
        logMsg("Power IBC: Error initializing IBC B Input Task Resources\n");
        return;
    } /* if */

    initIbcSwitchEntry( &lpsEnableSwitch[0], SERIAL_CHAN,
        VICOR_STANDBY_POWER,        B48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],      LPS_VICOR_ENABLE,
        PWR_B_LPS0_48V_ENABLE_SWITCH_REQ_DM, PWR_B_LPS0_48V_ENABLE_STATUS_DM,
        dmUpdateSem,
        PWR_B_LPS0_48V_ENABLE_PWR_REQ_DM,    PWR_B_LPS0_48V_ENABLE_PWR_OK_DM,
        powerReqSem,                pwrDataConName,      "LPS 0 48V Enable");

    initIbcSwitchEntry( &lpsEnableSwitch[1], SERIAL_CHAN,
        VICOR_STANDBY_POWER,        B48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[1],      LPS_VICOR_ENABLE,
        PWR_B_LPS1_48V_ENABLE_SWITCH_REQ_DM, PWR_B_LPS1_48V_ENABLE_STATUS_DM,
        dmUpdateSem,
        PWR_B_LPS1_48V_ENABLE_PWR_REQ_DM,    PWR_B_LPS1_48V_ENABLE_PWR_OK_DM,
        powerReqSem,                pwrDataConName,      "LPS 1 48V Enable");

    initIbcSwitchEntry( &sonarDconSwitch,     SERIAL_CHAN,
        SONAR_DCON_POWER,               B48,                  HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],   SONAR_DCON_SWITCH_CHAN,
        SONAR_DCON_SWITCH_REQ_DM,   SONAR_DCON_SWITCH_STATUS_DM,
        dmUpdateSem,
        SONAR_DCON_PWR_REQ_DM,      SONAR_DCON_PWR_OK_DM, powerReqSem,
        pwrDataConName,                 "Sonar DCon Switch ");

    initIbcSwitchEntry( &sensorDconSwitch,    SERIAL_CHAN,
        SENSOR_DCON_POWER,              B48,                  HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],    SENSOR_DCON_SWITCH_CHAN,
        SENSOR_DCON_SWITCH_REQ_DM,  SENSOR_DCON_SWITCH_STATUS_DM, dmUpdateSem,
        SENSOR_DCON_PWR_REQ_DM,     SENSOR_DCON_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                 "Sensor Data Concentrator Switch");

    initIbcSwitchEntry( &manip48VSwitch,      SERIAL_CHAN,
        MANIPULATOR_48V_POWER,          B48,                  TOOLS,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],    MANIP_48V_SWITCH_CHAN,
        MANIP_48V_SWITCH_REQ_DM,    MANIP_48V_SWITCH_STATUS_DM,   dmUpdateSem,
        MANIP_48V_PWR_REQ_DM,       MANIP_48V_PWR_OK_DM,          powerReqSem,
        pwrDataConName,                 "Manipulator 48V Switch");

    initIbcSwitchEntry( &runningLightSwitch,      SERIAL_CHAN,
        RUNNING_LIGHT_POWER,           B48,                  HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],  RUNNING_LIGHT_SWITCH_CHAN,
        RUN_LIGHT_SWITCH_REQ_DM,    RUN_LIGHT_SWITCH_STATUS_DM, dmUpdateSem,
        RUN_LIGHT_PWR_REQ_DM,       RUN_LIGHT_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                 "Vehicle Running Light Switch");

    initIbcSwitchEntry( &stbdPanTiltSwitch,   SERIAL_CHAN,
        PAN_TILT_DCON_POWER,            B48,                  HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[1], STBD_PAN_TILT_SWITCH_CHAN,
        STBD_PAN_TILT_DCON_SWITCH_REQ_DM,
        STBD_PAN_TILT_DCON_SWITCH_STATUS_DM, dmUpdateSem,
        STBD_PAN_TILT_DCON_PWR_REQ_DM,
        STBD_PAN_TILT_DCON_PWR_OK_DM,        powerReqSem,
        pwrDataConName,             "Starboard Pan & Tilt Switch" );

    initIbcSwitchEntry( &lightDcon48VSwitch,  SERIAL_CHAN,
        LIGHTING_DCON_48V_POWER,           B48,                 LIGHTS,
        LOW_POWER_SWITCH,           lpsBoardAddr[1],  LIGHTING_DCON_SWITCH_CHAN,
        LIGHTING_DCON_48V_SWITCH_REQ_DM,
        LIGHTING_DCON_48V_SWITCH_STATUS_DM, dmUpdateSem,
        LIGHTING_DCON_48V_PWR_REQ_DM,
        LIGHTING_DCON_48V_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                 "Lighting DCon 48V Switch");

    initIbcSwitchEntry( &fwdLatSwitch,  SERIAL_CHAN,
        THRUSTER_STANDBY_POWER,         B240,                 HOTEL,
        HIGH_POWER_SWITCH,              hpsBoardAddr[FWD_LAT_THRUST_HPS], 0,
        THRUSTER_FWD_LAT_SWITCH_REQ_DM,
        THRUSTER_FWD_LAT_SWITCH_STATUS_DM, dmUpdateSem,
        THRUSTER_FWD_LAT_PWR_REQ_DM,
        THRUSTER_FWD_LAT_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                 "Forward Lateral Thruster Switch");

    initIbcSwitchEntry( &aftLatSwitch,  SERIAL_CHAN,
        THRUSTER_STANDBY_POWER,         B240,                 HOTEL,
        HIGH_POWER_SWITCH,              hpsBoardAddr[AFT_LAT_THRUST_HPS], 0,
        THRUSTER_AFT_LAT_SWITCH_REQ_DM,
        THRUSTER_AFT_LAT_SWITCH_STATUS_DM, dmUpdateSem,
        THRUSTER_AFT_LAT_PWR_REQ_DM,
        THRUSTER_AFT_LAT_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                "Aft Lateral Thruster Switch");

    initIbcSwitchEntry( &stbdVertSwitch,  SERIAL_CHAN,
        THRUSTER_STANDBY_POWER,         B240,                 HOTEL,
        HIGH_POWER_SWITCH,              hpsBoardAddr[STBD_VERT_THRUST_HPS], 0,
        THRUSTER_STBD_VERT_SWITCH_REQ_DM,
        THRUSTER_STBD_VERT_SWITCH_STATUS_DM, dmUpdateSem,
        THRUSTER_STBD_VERT_PWR_REQ_DM,
        THRUSTER_STBD_VERT_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                 "Stbd Vertical Thruster Switch");

    initIbcSwitchEntry( &lightDcon240VSwitch,  SERIAL_CHAN,
        LIGHTING_DCON_240V_POWER,          B240,                 LIGHTS,
        HIGH_POWER_SWITCH,              hpsBoardAddr[LIGHTING_DCON_240V_HPS], 0,
        LIGHTING_DCON_240V_SWITCH_REQ_DM,
        LIGHTING_DCON_240V_SWITCH_STATUS_DM, dmUpdateSem,
        LIGHTING_DCON_240V_PWR_REQ_DM,
        LIGHTING_DCON_240V_PWR_OK_DM,        powerReqSem,
        pwrDataConName,                 "Lighting DCon 240V Switch");

                                  /* Devices on Power Can Low Power Switches*/
    ibcAddSwitchInSeries( &lpsEnableSwitch[0], &sonarDconSwitch);
    ibcAddSwitchInSeries( &lpsEnableSwitch[0], &sensorDconSwitch);
    ibcAddSwitchInSeries( &lpsEnableSwitch[0], &manip48VSwitch);
    ibcAddSwitchInSeries( &lpsEnableSwitch[0], &runningLightSwitch);

    ibcAddSwitchInSeries( &lpsEnableSwitch[1], &stbdPanTiltSwitch);
    ibcAddSwitchInSeries( &lpsEnableSwitch[1], &runningLightSwitch);


    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &sonarDconSwitch,
         pwrDataConName, "Sonar DCon",       SONAR_DCON_SWITCH_CHAN,
         SONAR_DCON_CURRENT_DM,              SONAR_DCON_CURRENT_ALARM_DM,
         SONAR_DCON_CURRENT_WARN_LVL_DM,     SONAR_DCON_CURRENT_ALARM_LVL_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &sensorDconSwitch,
         pwrDataConName, "Sensor DCon",      SENSOR_DCON_SWITCH_CHAN,
         SENSOR_DCON_CURRENT_DM,             SENSOR_DCON_CURRENT_ALARM_DM,
         SENSOR_DCON_CURRENT_WARN_LVL_DM,    SENSOR_DCON_CURRENT_ALARM_LVL_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &manip48VSwitch,
         pwrDataConName, "Manipulator 48V",  MANIP_48V_SWITCH_CHAN,
         MANIP_48V_CURRENT_DM,               MANIP_48V_CURRENT_ALARM_DM,
         MANIP_48V_CURRENT_WARN_LVL_DM,      MANIP_48V_CURRENT_ALARM_LVL_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &runningLightSwitch,
         pwrDataConName, "Vehicle Running Light",  RUNNING_LIGHT_SWITCH_CHAN,
         RUNNING_LIGHT_CURRENT_DM,          RUNNING_LIGHT_CURRENT_ALARM_DM,
         RUNNING_LIGHT_CURRENT_WARN_LVL_DM, RUNNING_LIGHT_CURRENT_ALARM_LVL_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[1], &stbdPanTiltSwitch,
         pwrDataConName, "Stbd Pan & Tilt DCon", STBD_PAN_TILT_SWITCH_CHAN,
         STBD_PAN_TILTS_CURRENT_DM,
         STBD_PAN_TILTS_CURRENT_ALARM_DM,
         STBD_PAN_TILTS_CURRENT_WARN_LVL_DM,
         STBD_PAN_TILTS_CURRENT_ALARM_LVL_DM );

    ibcConnectLpsDmItems( &dmItems->lpsDm[1], &lightDcon48VSwitch,
         pwrDataConName, "Lighting DCon 48V", LIGHTING_DCON_SWITCH_CHAN,
         LIGHTING_DCON_48V_CURRENT_DM,
         LIGHTING_DCON_48V_CURRENT_ALARM_DM,
         LIGHTING_DCON_48V_CURRENT_WARN_LVL_DM,
         LIGHTING_DCON_48V_CURRENT_ALARM_LVL_DM );

    ibcConnectHpsDmItems( &dmItems->hpsDm[FWD_LAT_THRUST_HPS],
         &fwdLatSwitch, pwrDataConName, "Forward Lateral Thruster",
         FWD_LAT_THRUST_CURRENT_DM,
         FWD_LAT_THRUST_CURRENT_ALARM_DM,
         FWD_LAT_THRUST_CURRENT_WARN_LVL_DM,
         FWD_LAT_THRUST_CURRENT_ALARM_LVL_DM,
         FWD_LAT_THRUST_SWITCH_TRIP_DM );

    ibcConnectHpsDmItems( &dmItems->hpsDm[AFT_LAT_THRUST_HPS],
         &aftLatSwitch, pwrDataConName, "Aft Lateral Thruster",
         AFT_LAT_THRUST_CURRENT_DM,
         AFT_LAT_THRUST_CURRENT_ALARM_DM,
         AFT_LAT_THRUST_CURRENT_WARN_LVL_DM,
         AFT_LAT_THRUST_CURRENT_ALARM_LVL_DM,
         AFT_LAT_THRUST_SWITCH_TRIP_DM );

    ibcConnectHpsDmItems( &dmItems->hpsDm[STBD_VERT_THRUST_HPS],
         &stbdVertSwitch, pwrDataConName, "Stbd Vertical Thruster",
         STBD_VERT_THRUST_CURRENT_DM,
         STBD_VERT_THRUST_CURRENT_ALARM_DM,
         STBD_VERT_THRUST_CURRENT_WARN_LVL_DM,
         STBD_VERT_THRUST_CURRENT_ALARM_LVL_DM,
         STBD_VERT_THRUST_SWITCH_TRIP_DM );

    ibcConnectHpsDmItems( &dmItems->hpsDm[LIGHTING_DCON_240V_HPS],
         &lightDcon240VSwitch, pwrDataConName, "Lighting DCon 240V",
         LIGHTING_DCON_240V_CURRENT_DM,
         LIGHTING_DCON_240V_CURRENT_ALARM_DM,
         LIGHTING_DCON_240V_CURRENT_WARN_LVL_DM,
         LIGHTING_DCON_240V_CURRENT_ALARM_LVL_DM,
         LIGHTING_DCON_240V_SWITCH_TRIP_DM );


     if (ibcHpsSetCurrentThresh(&dmItems->hpsDm[FWD_LAT_THRUST_HPS],
         SERIAL_CHAN, hpsBoardAddr[FWD_LAT_THRUST_HPS], 29000, 31000) != OK)
         printf ("Error setting Fwd Lat Current Alarm Thrsholds\n");

    ibcAddSwitchInSeries( &lightDcon48VSwitch,  &lightDcon240VSwitch );

    cpuGroup = initIbcCpuConsumer(&dmItems->ibcDm, &ibcCpuBits, dmUpdateSem);

                                    /* Use CPU Group for Water Alarm Thresh  */
    dm_start_consumer(dmItems->waterAlarmThresh, DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->gfMonitorDisableDm, DM_STATIC, dmUpdateSem);
    dm_group_add_item(cpuGroup, dmItems->waterAlarmThresh,
                      &waterAlarmThreshBit);

    regenGroup =                     /* Create Regen Board Data Manager Group*/
        initIbcRegenConsumer(&dmItems->regenDm, &regenBits, dmUpdateSem);

    gf5vGroup = initIbcGf5vConsumer( &dmItems->gf5vDm, &gf5vBits, dmUpdateSem );

                                      /* Create LPS Data Manager Group       */
    for (board = 0; board < LPS_BOARDS; board++)
    {
        lpsGroup[board] = initIbcLpsConsumer( &dmItems->lpsDm[board],
             &lpsBits[board], dmUpdateSem );
                                      /* Add Switch Requests to DM Group     */
        dm_group_add_item(cpuGroup,
           lpsEnableSwitch[board].switchRequestDm, &lpsEnableBit[board]);
    } /* for */
                                      /* Create HPS Data Manager Group       */
    for (board = 0; board < HPS_BOARDS; board++)
        hpsGroup[board] = initIbcHpsConsumer(&dmItems->hpsDm[board],
             &hpsBits[board], dmUpdateSem);

                                /* Define associated Ground Fault board      */
    ibcHpsDefineGfBoard( &aftLatSwitch,   GF5V_BOARD_ADDR );
    ibcHpsDefineGfBoard( &fwdLatSwitch,   GF5V_BOARD_ADDR );
    ibcHpsDefineGfBoard( &stbdVertSwitch, GF5V_BOARD_ADDR );

                                      /* Add Switch Requests to DM Group     */
    dm_group_add_item(cpuGroup, sonarDconSwitch.switchRequestDm,
                      &sonarDconSwitchBit);

    dm_group_add_item(cpuGroup, sensorDconSwitch.switchRequestDm,
                      &sensorDconSwitchBit);

    dm_group_add_item(cpuGroup, manip48VSwitch.switchRequestDm,
                      &manip48VSwitchBit);

    dm_group_add_item(cpuGroup, runningLightSwitch.switchRequestDm,
                      &runningLightSwitchBit);

    dm_group_add_item(cpuGroup, stbdPanTiltSwitch.switchRequestDm,
                      &stbdPanTiltSwitchBit);

    dm_group_add_item(cpuGroup, fwdLatSwitch.switchRequestDm,
                      &fwdLatSwitchBit);

    dm_group_add_item(cpuGroup, aftLatSwitch.switchRequestDm,
                      &aftLatSwitchBit);

    dm_group_add_item(cpuGroup, stbdVertSwitch.switchRequestDm,
                      &stbdVertSwitchBit);

    dm_group_add_item(cpuGroup, lightDcon8VSwitch.switchRequestDm,
                      &lightDcon48VSwitchBit);

    dm_group_add_item(cpuGroup, lightDcon240VSwitch.switchRequestDm,
                      &lightDcon240VSwitchBit);

    FOREVER
    {                               /* Mark micro configuration as invalid    */
        microIOCtrl->microConfigured = FALSE;

                                    /* Wait for micro reset via SRQ Task      */
        semTake(microIOCtrl->childTasks[OUT_TASK].taskSyncSem, WAIT_FOREVER);

        ibcSetSwitchState( &fwdLatSwitch,        SWITCH_OFF );
        ibcSetSwitchState( &aftLatSwitch,        SWITCH_OFF );
        ibcSetSwitchState( &stbdVertSwitch,      SWITCH_OFF );

                                    /* Initialize DM item values and default */
                                    /* IBC Switch states                     */
        ibcSetSwitchState( &sonarDconSwitch,     SWITCH_ON  );
        ibcSetSwitchState( &manip48VSwitch,      SWITCH_OFF );
        ibcSetSwitchState( &lightDcon48VSwitch,  SWITCH_ON  );
        ibcSetSwitchState( &lightDcon240VSwitch, SWITCH_OFF );
        ibcSetSwitchState( &stbdPanTiltSwitch,   SWITCH_OFF );

        ibcSetSwitchState( &sensorDconSwitch,    SWITCH_ON );
        ibcSetSwitchState( &runningLightSwitch,  SWITCH_ON );

        for (board = 0; board < LPS_BOARDS; board++)
            ibcSetSwitchState (&lpsEnableSwitch[board], SWITCH_ON );

        /* We need to initialize default state of Data manager Items here     */

        initIbcHumidityThreshDm( SERIAL_CHAN,
            dmItems->ibcDm.humidityWarnThresh,
            dmItems->ibcDm.humidityAlarmThresh );

        initWaterAlarmThreshDm ( SERIAL_CHAN, dmItems->waterAlarmThresh );

        initIbcRegenDmItems( SERIAL_CHAN, REGEN_BOARD_ADDR,
            &dmItems->regenDm, pwrDataConName );

        ibcRegenSetBusVoltageAlarmThresh(SERIAL_CHAN, REGEN_BOARD_ADDR,
            &dmItems->regenDm,
            MIN_240V_BUS_VOLTAGE_WARN, MIN_240V_BUS_VOLTAGE_ALARM,
            MAX_240V_BUS_VOLTAGE_WARN, MAX_240V_BUS_VOLTAGE_ALARM);

        updateIbcGf5vDmItems( SERIAL_CHAN, GF5V_BOARD_ADDR, &dmItems->gf5vDm,
            pwrDataConName );

        dm_read( dmItems->gfMonitorDisableDm, (char *) &gfDisable,
             sizeof(gfDisable), (DM_Time *) NULL );

        if (gfDisable)
        {
            enableGf5vMonitoring(SERIAL_CHAN, GF5V_BOARD_ADDR,
                &dmItems->gf5vDm, FALSE );

            clearIbcGf5vAlarmsDm(&dmItems->gf5vDm);
        } /* if */
        else
        {                            /* Set default charge time for PWR IBC A*/
            ibcGf5vSetChargeTimes(SERIAL_CHAN, GF5V_BOARD_ADDR,
                &dmItems->gf5vDm,
                LOW_VOLTAGE_GF_CHARGE_TIME, LOW_VOLTAGE_GF_CHARGE_TIME,
                LOW_VOLTAGE_GF_CHARGE_TIME, LOW_VOLTAGE_GF_CHARGE_TIME );

            enableGf5vMonitoring(SERIAL_CHAN, GF5V_BOARD_ADDR,
                &dmItems->gf5vDm, TRUE );

            runGf5vBoardSelftest(SERIAL_CHAN, GF5V_BOARD_ADDR,
                &dmItems->gf5vDm );
        } /* else */

        for (board = 0; board < LPS_BOARDS; board++)
        {
            updateIbcLpsDmItems( SERIAL_CHAN, lpsBoardAddr[board],
                    &dmItems->lpsDm[board], pwrDataConName );

            setLpsVoltageThresh( SERIAL_CHAN, lpsBoardAddr[board],
                &dmItems->lpsDm[board],
                MIN_48V_BUS_VOLTAGE_WARN, MIN_48V_BUS_VOLTAGE_ALARM);
        } /* for */

        if (ibcSwitchGangOutputs( &stbdPanTiltSwitch ) != OK)
            printf("Stbd Pan/Tilt Output Gang Enable Failed\n");

        if (ibcSwitchSetCurrentThresh(&stbdPanTiltSwitch, 8000, 10000) != OK)
           printf("Stbd Pan/Tilt Error Setting Switch Current Threshold\n");

        ibcSwitchSetCurrentThresh( &aftLatSwitch,
            THRUSTER_CURRENT_WARNING, THRUSTER_CURRENT_ALARM );

        ibcSwitchSetCurrentThresh( &fwdLatSwitch,
            THRUSTER_CURRENT_WARNING, THRUSTER_CURRENT_ALARM );

        ibcSwitchSetCurrentThresh( &stbdVertSwitch,
            THRUSTER_CURRENT_WARNING, THRUSTER_CURRENT_ALARM );

                                    /* Ask Data Manager which items changed  */
        pwrIbcGroupBits = dm_get_group_changes(cpuGroup);

                                    /* Flag that micro has been configured    */
        microIOCtrl->microConfigured = TRUE;

                                    /* Wake up input task to read from micro  */
        semGive(microIOCtrl->childTasks[IN_TASK].taskSyncSem);

        while (microIOCtrl->serialLinkState == LINK_UP)
        {                           /* Repeat while serial link is up        */
                                    /* Wait for any data items to change     */
            semTake(dmUpdateSem, WAIT_FOREVER);

                                   /* Ask Data Manager which items changed  */
            pwrIbcGroupBits = dm_get_group_changes(cpuGroup);

                                    /* Check if micro Reset Event occurred   */
            if (pwrIbcGroupBits & ibcCpuBits.resetEventBit)
                break;              /* Exit loop and re-initialize DM items  */

            taskSafe();             /* Prevent task from being deleted during*/
                                    /* serial IO and Data Manager updates    */

                                    /* Power Can LPS Output Enable Request  */
            if (pwrIbcGroupBits & lpsEnableBit[0])
                ibcProcessSwitchRequest( &lpsEnableSwitch[0] );

            if (pwrIbcGroupBits & lpsEnableBit[1])
                ibcProcessSwitchRequest( &lpsEnableSwitch[1] );

                                    /* Sonar DCon Power Switch Request       */
            if (pwrIbcGroupBits & sonarDconSwitchBit)
                ibcProcessSwitchRequest( &sonarDconSwitch );

                                    /* Sensor DCon Power Switch Request      */
            if (pwrIbcGroupBits & sensorDconSwitchBit)
                ibcProcessSwitchRequest( &sensorDconSwitch );

                                    /* Manipulator 48V Power Switch Request  */
            if (pwrIbcGroupBits & manip48VSwitchBit)
                ibcProcessSwitchRequest( &manip48VSwitch );

                                    /* Vehicle Running Light Switch Request  */
            if (pwrIbcGroupBits & runningLightSwitchBit)
                ibcProcessSwitchRequest( &runningLightSwitch );

                                    /* Forward Lateral Thruster Switch Req   */
            if (pwrIbcGroupBits & fwdLatSwitchBit)
                ibcProcessSwitchRequest( &fwdLatSwitch );

                                    /* Aft Lateral Thruster Switch Request   */
            if (pwrIbcGroupBits & aftLatSwitchBit)
                ibcProcessSwitchRequest( &aftLatSwitch );

                                    /* Stbd Vert Thruster Switch Request     */
            if (pwrIbcGroupBits & stbdVertSwitchBit)
                ibcProcessSwitchRequest( &stbdVertSwitch );

                                    /* Lighting DCon 48V Switch Request      */
            if (pwrIbcGroupBits & lightDcon48VSwitchBit)
                ibcProcessSwitchRequest( &lightDcon48VSwitch );

                                    /* Lighting DCon 240V Switch Request     */
            if (pwrIbcGroupBits & lightDcon240VSwitchBit)
                ibcProcessSwitchRequest( &lightDcon240VSwitch );

                                    /* Stbd Pan & Tilt Power Switch Request */
            if (pwrIbcGroupBits & stbdPanTiltSwitchBit)
                ibcProcessSwitchRequest( &stbdPanTiltSwitch );

                                   /* Check for Regen Board Parameter Update*/
            ibcRegenUpdateCheck( SERIAL_CHAN, REGEN_BOARD_ADDR,
                              &dmItems->regenDm, &regenBits, regenGroup );

                                    /* Check for GF/5V Board Parameter Update */
            ibcGf5vUpdateCheck( SERIAL_CHAN, GF5V_BOARD_ADDR,
                              &dmItems->gf5vDm, &gf5vBits, gf5vGroup );

                                    /* Check for LPS Board Parameter Update  */
            for (board = 0; board < LPS_BOARDS; board++)
                ibcLpsUpdateCheck( SERIAL_CHAN, lpsBoardAddr[board],
                    &dmItems->lpsDm[board], &lpsBits[board], lpsGroup[board] );

            for (board = 0; board < HPS_BOARDS; board++)
                ibcHpsUpdateCheck( SERIAL_CHAN, hpsBoardAddr[board],
                    &dmItems->hpsDm[board], &hpsBits[board], hpsGroup[board] );

                                    /* Send Set Humidity Alarm Threshold cmd */
            if ((pwrIbcGroupBits & ibcCpuBits.humidityWarnThreshBit) ||
                (pwrIbcGroupBits & ibcCpuBits.humidityAlarmThreshBit))
                writeIbcHumidityThresh(SERIAL_CHAN,
                    dmItems->ibcDm.humidityWarnThresh,
                    dmItems->ibcDm.humidityAlarmThresh);

                                    /* Send Set Water Alarm Threshold cmd    */
            if (pwrIbcGroupBits & waterAlarmThreshBit)
                writeWaterAlarmThresh(SERIAL_CHAN, dmItems->waterAlarmThresh);

                                    /* Check if Reset Command request occurred*/
            if (pwrIbcGroupBits & ibcCpuBits.resetCmdBit)
            {                       /* Mark serial link as down               */
                setSerialLinkState(microIOCtrl, LINK_DOWN);
                                    /* Manual reset so ammounce it            */
                microIOCtrl->announceResets = TRUE;
                                    /* Send Reset Command to Microcontroller  */
                microResetCmd(SERIAL_CHAN);
                break;              /* Exit loop and wait for RESET           */
            } /* if */

            taskUnsafe();           /* Task may now be safely deleted         */

        } /* while (LINK_UP) */
    } /* FOREVER */

                        /* dm_stop_provider, dm_stop_consumer, dm_delete_group*/
                        /* etc are NOT required when the task exits as the    */
                        /* Data Manager does this automatically when the task */
                        /* is deleted via the taskDeleteHookAdd() and         */
                        /* dm_task_exit functions.                            */

                        /* That's all folks !                                 */
} /* PWR_IBC_OutTask() */

#endif /* PWR_IBC_B */

/*****************************************************************************/
/* Function    : PWR_IBC_InTask                                              */
/* Purpose     : Power IBC Input Task. Wakes up periodically, read data from */
/*               the Power IBC and write Data Manager Items                  */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : Normally runs forever, but exits if error occurs            */
/*****************************************************************************/
    Void
PWR_IBC_InTask(Reg pwrIbcDmItems* dmItems, Reg microIOControl *microIOCtrl)
{
    SEM_ID  wakeupSem;              /* Used by watch dog to wake up this task*/
    Int32   updates = 0;            /* Counts dm updates for rate calculation*/
    Int16   board;                  /* HPS Board Index                       */

                                    /* Wakeup semaphore for provider rate    */
    if ((wakeupSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL)
    {
        logMsg("Power IBC: Error createing %s Input Task Resources\n", pwrIbc);
        return;
    } /* if */
                                  /* Provider Task for non-static data items*/
    initIbcCpuProvider  (&dmItems->ibcDm,   HUMIDITY_DM_PERIOD);
    initIbcRegenProvider(&dmItems->regenDm, PWR_IBC_DM_PERIOD);
    initIbcGf5vProvider (&dmItems->gf5vDm,  PWR_IBC_DM_PERIOD);

    for (board = 0; board < LPS_BOARDS; board++)
        initIbcLpsProvider(&dmItems->lpsDm[board],  PWR_IBC_DM_PERIOD);

    for (board = 0; board < HPS_BOARDS; board++)
        initIbcHpsProvider(&dmItems->hpsDm[board],  PWR_IBC_DM_PERIOD);

                                    /* Declare this task a provider of items  */
#ifdef PWR_IBC_A
    dm_start_provider(dmItems->fanSpeed, FAN_SPEED_DM_PERIOD);
#endif

    FOREVER
    {                               /* Wait for IBC Coms to be initialized   */
        semTake(microIOCtrl->childTasks[IN_TASK].taskSyncSem, WAIT_FOREVER);

        while (microIOCtrl->serialLinkState == LINK_UP)
        {
            taskSafe();             /* Prevent task from being deleted during */
                                    /* serial IO and Data Manager updates     */

            updateIbcRegenDm(SERIAL_CHAN, REGEN_BOARD_ADDR, &dmItems->regenDm);
            updatePowerCanIbcGf5vDm(SERIAL_CHAN,  GF5V_BOARD_ADDR,
                &dmItems->gf5vDm);

            for (board = 0; board < LPS_BOARDS; board++)
                updateIbcLpsDm( SERIAL_CHAN,  lpsBoardAddr[board],
                    &dmItems->lpsDm[board] );

            for (board = 0; board < HPS_BOARDS; board++)
                updateIbcHpsDm( SERIAL_CHAN,  hpsBoardAddr[board],
                    &dmItems->hpsDm[board] );

            if ((updates % (HUMIDITY_DM_PERIOD / PWR_IBC_DM_PERIOD)) == 0)
                updateIbcHumidityDm(SERIAL_CHAN, dmItems->ibcDm.microHumidity);

#ifdef PWR_IBC_A
            if ((updates % (FAN_SPEED_DM_PERIOD / PWR_IBC_DM_PERIOD)) == 0)
                updateFanSpeedDm( SERIAL_CHAN, dmItems->fanSpeed );
#endif

            taskUnsafe();           /* Task may now be deleted safely         */

                                    /* Increment & range check update counter */
            if (++updates == 10000) updates = 0;

                                    /* Pend until sem timeout wakes us up     */
            semTake(wakeupSem, sysClkRateGet() /
                 (USECS_PER_SEC / PWR_IBC_DM_PERIOD));
        } /* while */
    } /* FOREVER */

    semDelete(wakeupSem);           /* semaphore resources                    */


                        /* dm_stop_provider, dm_stop_consumer, dm_delete_group*/
                        /* etc are NOT required when the task exits as the    */
                        /* Data Manager does this automatically when the task */
                        /* is deleted via the taskDeleteHookAdd() and         */
                        /* dm_task_exit functions.                            */

} /* PWR_IBC_InTask() *//* That's all folks !                                 */

/******************************************************************************/
/* Function    : processPwrIbcSRQ                                             */
/* Purpose     : Decode Service Request from Power IBC & dispatch handler     */
/* Inputs      : Array of DM items, Data & SRQ serial channels                */
/* Outputs     : Returns SRQ Received & many DM items are changed             */
/******************************************************************************/
    LOCAL Word
processPwrIbcSRQ(Reg pwrIbcDmItems* dmItems, microIOControl *microIOCtrl)
{
    Int16 board;                    /* HPS Board Index                        */
    Word srqRequest;                /* Service Request Value                  */
    Word alarmStatus;               /* Microcontroller Alarm Status Word     */
    Byte buffer[SRQ_PACKET_LEN];    /* Buffer for micro communications data   */

                                    /* Wait for Service Requests              */
    if (readSRQPacket(SERIAL_CHAN, buffer, SRQ_PACKET_LEN, WAIT_FOREVER)
        == ERROR) return (ERROR);
                                    /* Service Request received so process it */
    srqRequest = wordFromBuf(buffer, 0);

    switch (srqRequest)             /* Decode Service Request from micro      */
    {
      case MICRO_RESET_SRQ:         /* Microcontroller Reset Occurred         */
                                    /* Post Reset Event DM Item               */
        if (microIOCtrl->announceResets)
            microResetEventDm(dmItems->ibcDm.microDm.resetEvent);
        break;

      case WATER_ALARM_ON_SRQ:      /* Water Alarm Active                     */
        writeBooleanDmItem(dmItems->waterAlarmStatus, TRUE);
        break;

      case WATER_ALARM_OFF_SRQ:     /* Water Alarm Inactive                   */
        writeBooleanDmItem(dmItems->waterAlarmStatus, FALSE);
        break;

      default:
        if (processIbcCpuSRQ(srqRequest, buffer, &dmItems->ibcDm) != TRUE)

            if (processIbcGf5vSRQ(srqRequest,  buffer, GF5V_BOARD_ADDR,
                &dmItems->gf5vDm  ) != TRUE)

            if (processIbcRegenSRQ(srqRequest, buffer, REGEN_BOARD_ADDR,
                &dmItems->regenDm  ) != TRUE)

             if (processIbcLpsSRQ(srqRequest, buffer, lpsBoardAddr[0],
                &dmItems->lpsDm[0] ) != TRUE)

             if (processIbcLpsSRQ(srqRequest, buffer, lpsBoardAddr[1],
                &dmItems->lpsDm[1] ) != TRUE)

             {
                 for (board = 0; board < HPS_BOARDS; board++)
                     if (processIbcHpsSRQ(srqRequest, buffer,
                         hpsBoardAddr[board], &dmItems->hpsDm[board]) == TRUE)
                             return( FALSE );

                 printf("%s: Unrecognized SRQ 0x%x\n", pwrDataConName,
                   srqRequest);
             } /* if */
        break;

    } /* switch */

    return(srqRequest);                 /* Return SRQ received to caller      */
} /* processPwrIbcSRQ() */



4 **