/****************************************************************************/
/* Copyright 1992 to 1996 MBARI                                             */
/****************************************************************************/
/* Summary  : IBC Low Power Switch Board Functions                          */
/* Filename : low_pwr.c                                                     */
/* Author   : Andrew Pearce                                                 */
/* Project  : Tiburon ROV IBC Based Data Concentrator                       */
/* Version  : 1.0                                                           */
/* Created  : 09/17/92                                                      */
/* Modified : 04/03/96                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: /usr/tiburon/.cvsroot/micro/ibc/boards/low_pwr/low_pwr.c,v 1.2 1997/05/07 15:30:50 pean Exp $
 * $Log: low_pwr.c,v $
 * Revision 1.2  1997/05/07 15:30:50  pean
 * Cleaned up Include files and makefile for new directory structure.
 *
 * Revision 1.1.1.1  1997/05/02 18:51:30  pean
 * Initial check in of IBC microcontroller software
 *
 * Revision 1.2  93/07/02  09:35:48  09:35:48  pean (Andrew Pearce)
 * Minor bug fixes and enhancements for Prototype Vehicle Tests
 *
 * Revision 1.1  93/03/12  11:59:30  11:59:30  pean (Andrew Pearce)
 * Initial revision
 *
*/
/****************************************************************************/

#pragma model(196)
#pragma nosignedchar

#include "C:/C96/include/stddef.h"      /* C Standard Definitions           */
#include "const.h"                      /* Misc. constants - TRUE/FALSE etc */
#include "types.h"                      /* MBARI style guide declarations   */
#include "microasm.h"                   /* Assembly language functions      */
#include "malloc.h"                     /* Malloc support routines          */
#include "microdef.h"                   /* Microcontroller Definitions      */
#include "microCmd.h"                   /* microcontroller commands         */
#include "microlib.h"                   /* Microcontroller Library decls.   */
#include "timer.h"                      /* Timer library definitions        */
#include "applay.h"                     /* Application layer funcitions     */

#include "filter.h"                     /* General Filter Routines          */
#include "ibc_card.h"                   /* IBC Board Types and Addresses    */
#include "ibc_cmd.h"                    /* Core IBC application definitions */
#include "ibc.h"                        /* IBC Function Library Definitions */
#include "ibc_asm.h"                    /* IBC Assembly Language Functions  */
#include "pic.h"                        /* Intel 82C59 Interrupt Controller */

#include "low_pwr.h"                    /* IBC Low Power Switch Board Defs  */

                                        /* Forward declarations for MLocals */
MLocal Int16 LPS_BoardSwitchCtrl( LPS_BoardEntry *LPS_Board, Byte control );
MLocal Void LPS_CheckCurrent( LPS_BoardEntry *LPS_Board, Int16 chan );
MLocal Void LPS_SetVoltageToZero( LPS_BoardEntry *LPS_Board );
MLocal Void LPS_SetCurrentToZero( LPS_BoardEntry *LPS_Board, Int16 chan );

/****************************************************************************/
/* Function    : LPS_BoardSearch                                            */
/* Purpose     : Scans IBC backplane looking for Low Power Switch Boards    */
/* Inputs      : Pointer to IBC Board Entry Table and maximum table size    */
/* Outputs     : Returns number of boards found                             */
/****************************************************************************/
    Int16
LPS_BoardSearch( IBC_BoardEntry *IBC_Boards[], Int16 maxCards )
{
    Byte  *addr;                        /* LPS Board base address           */
    Int16 board;                        /* Counts number of LPS board found */
    IBC_BoardEntry *boardEntry;         /* Pointer to LPS board data struct */

    board = 0;                          /* Set board count to zero          */
    if (maxCards > 0)                   /* Check for space in IBC Card Table*/
    {                                   /* Search for Low Power Switch Brds */
        for (addr =  (Byte *) LOW_PWR_SWITCH_12V_0_ADDR;
             addr <= (Byte *) LOW_PWR_SWITCH_XXV_3_ADDR;
             addr+= (LOW_PWR_SWITCH_12V_1_ADDR - LOW_PWR_SWITCH_12V_0_ADDR) )
        {                               /* NULL boardEntry if board missing */
            if ((boardEntry = (IBC_BoardEntry *) LPS_BoardInit(addr)) != NULL)
            {                           /* Add LPS data struct to IBC Table */
                IBC_Boards[board++] = boardEntry;
                if (board == maxCards)  /* Check if IBC Card Table is full  */
                    return(board);      /* Return number of LPS boards found*/
            } /* if */
        } /* for */
    } /* if */

    return(board);                      /* Return number of LPS boards found*/
} /* LPS_BoardSearch() */

/****************************************************************************/
/* Function    : LPS_BoardInit                                              */
/* Purpose     : Low Power Switch Board Initialization routine              */
/* Inputs      : Base address of Low Power Switch Board                     */
/* Outputs     : Returns pointer to IBC board data structure                */
/****************************************************************************/
    LPS_BoardEntry*
LPS_BoardInit( Byte *boardBaseAddr )
{
    LPS_BoardEntry *LPS_Board;          /* Pointer to board entry           */
    Int16 chan;                         /* LPS Channel index                */

                                        /* Check if board exists and also   */
                                        /* Clear any pending A/D interrupt  */
                                        /* Returns OK if board asserts xack */
    if ( ibcBusReadByte( boardBaseAddr + LPS_AtoD_REG) == ERROR )
        return(( LPS_BoardEntry *) NULL);
                                        /* Board doesn't exist return NULL  */

                                        /* Allocate space for board entry   */
    LPS_Board = (LPS_BoardEntry *) malloc( sizeof (LPS_BoardEntry) );
    if (LPS_Board == (LPS_BoardEntry *) NULL )
            return( (LPS_BoardEntry *) NULL);
                                        /* Insufficient memory return ERROR */

                                        /* Fill out board entry structure   */
    LPS_Board->IBC_Board.baseAddress = boardBaseAddr;
    LPS_Board->IBC_Board.boardType   = LOW_POWER_SWITCH;
    LPS_Board->IBC_Board.intrLevel   = IBC_INT_LVL_OFF;

    LPS_Board->state = LPS_CURRENT;
    LPS_Board->switchState = 0;         /* Clear switch state               */
                                        /* Enable vicor, set all switches   */
                                        /* off and turn on the LED          */
    LPS_BoardSwitchCtrl( LPS_Board,  LPS_BOARD_VICOR_ON | LPS_BOARD_LED_ON );

    LPS_Board->vicorTempWarning  = LPS_VICOR_TEMP_WARNING;
    LPS_Board->vicorTempAlarm    = LPS_VICOR_TEMP_ALARM;
    LPS_Board->switchTempWarning = LPS_SWITCH_TEMP_WARNING;
    LPS_Board->switchTempAlarm   = LPS_SWITCH_TEMP_ALARM;


    switch ((Int16) boardBaseAddr)
    {
        case LOW_PWR_SWITCH_12V_0_ADDR:
        case LOW_PWR_SWITCH_12V_1_ADDR:
        case LOW_PWR_SWITCH_12V_2_ADDR:
        case LOW_PWR_SWITCH_12V_3_ADDR:
                                        /* 12 V Board so use 12 thresholds  */
             LPS_Board->voltageWarning = LPS_12V_VOLTAGE_WARN;
             LPS_Board->voltageAlarm   = LPS_12V_VOLTAGE_ALARM;
             break;

        case LOW_PWR_SWITCH_24V_0_ADDR:
        case LOW_PWR_SWITCH_24V_1_ADDR:
        case LOW_PWR_SWITCH_24V_2_ADDR:
        case LOW_PWR_SWITCH_24V_3_ADDR:
                                        /* 24 V Board so use 24 thresholds  */
             LPS_Board->voltageWarning = LPS_24V_VOLTAGE_WARN;
             LPS_Board->voltageAlarm   = LPS_24V_VOLTAGE_ALARM;
             break;

        case LOW_PWR_SWITCH_48V_0_ADDR:
        case LOW_PWR_SWITCH_48V_1_ADDR:
        case LOW_PWR_SWITCH_48V_2_ADDR:
        case LOW_PWR_SWITCH_48V_3_ADDR:
                                        /* 48 V Board so use 48 thresholds  */
             LPS_Board->voltageWarning = LPS_48V_VOLTAGE_WARN;
             LPS_Board->voltageAlarm = LPS_48V_VOLTAGE_ALARM;
             break;

        default:
                                        /* Undefined voltage so zero thresh */
             LPS_Board->voltageWarning = 0;
             LPS_Board->voltageAlarm = 0;
             break;
    } /* switch */

                                        /* Clear alarm status flags         */
    LPS_Board->alarmStatus.vicorTempAlarm    = (unsigned) MICRO_ALARM_OK;
    LPS_Board->alarmStatus.vicorVoltageAlarm = (unsigned) MICRO_ALARM_OK;
    LPS_Board->alarmStatus.sw3TempAlarm      = (unsigned) MICRO_ALARM_OK;


    for (chan = 0; chan < LPS_MAX_CHANS; chan++)
    {
                                        /* Initialize current filter params */
        LPS_Board->lpsChan[chan].filteredCurrent = 0;
        initIIRFilter(&LPS_Board->lpsChan[chan].filter, LPS_MAX_CURRENT);

                                        /* Initialize default alarm levels  */
        LPS_Board->lpsChan[chan].currentWarning     = LPS_CURRENT_WARNING;
        LPS_Board->lpsChan[chan].currentAlarm       = LPS_CURRENT_ALARM;
        LPS_Board->lpsChan[chan].currentAlarmStatus = MICRO_ALARM_OK;

        LPS_Board->lpsChan[chan].checkCurrent = FALSE;
        LPS_Board->lpsChan[chan].gangOutputs  = FALSE;
    } /* for */

    LPS_Board->filteredVicorTemp = 0;   /* Initialize vicor temp filter     */
    initIIRFilter(&LPS_Board->vicorTempFilter, LPS_MAX_TEMP);

    LPS_Board->filteredVicorVoltage = 0;/* Initialize vicor voltage filter  */
    initIIRFilter(&LPS_Board->vicorVoltageFilter, LPS_MAX_VOLTAGE);

    LPS_Board->filteredSw3Temp = 0;     /* Initialize switch 3 temp filter  */
    initIIRFilter(&LPS_Board->sw3TempFilter, LPS_MAX_TEMP);

                                        /* Create timer for switch delays   */
    LPS_Board->switchOnTimer = timerCreate();
    LPS_Board->switchOnDelay = 0;       /* Disable switch delays by default */
    LPS_Board->checkVoltage = TRUE;     /* Enable voltage checking          */

    return (LPS_Board);                 /* Return pointer to LPS data struct*/
} /* LPS_BoardInit() */

/****************************************************************************/
/* Function    : LPS_BoardSwitchCtrl                                        */
/* Purpose     : Low Power Switch Board - Write byte to switch control reg  */
/* Inputs      : Pointer to LPS Board data structure & control byte         */
/* Outputs     : Returns result of IBC Bus Write - OK or ERROR if timeout   */
/****************************************************************************/
    MLocal Int16
LPS_BoardSwitchCtrl( LPS_BoardEntry *LPS_Board, Byte control )
{
    if ( LPS_Board == NULL )            /* Check for valid LPS data struct  */
         return (ERROR);

    LPS_Board->switchState = control;   /* Save control byte in LPS struct  */
                                        /* Write byte to switch control reg */
                                        /* Return result of ibcBusWriteByte */
    return( ibcBusWriteByte( LPS_Board->IBC_Board.baseAddress
         + LPS_SWITCH_CTRL_REG, LPS_Board->switchState ));
} /* LPS_BoardSwitchCtrl() */

/****************************************************************************/
/* Function    : LPS_BoardSwitchState                                       */
/* Purpose     : Return Switch state bits for Low Power Switch              */
/* Inputs      : LPS Board data structure, channel                          */
/* Outputs     : Returns Switch state                                       */
/****************************************************************************/
    MBool
LPS_BoardSwitchState( LPS_BoardEntry *LPS_Board, Nat16 chan )
{
    if ( LPS_Board == NULL)             /* Check for valid LPS data struct  */
         return (FALSE);

    return ( (LPS_Board->switchState & (1 << chan)) ? TRUE : FALSE);
} /* LPS_BoardSwitchState() */

/****************************************************************************/
/* Function    : LPS_BoardEnableVoltageCheck                                */
/* Purpose     : Enables vicor voltage checking                             */
/* Inputs      : LPS Board data structure, channel No & desired switch state*/
/* Outputs     : Returns result of IBC Bus Write - OK or ERROR if timeout   */
/****************************************************************************/
    MLocal Void
LPS_BoardEnableVoltageCheck( LPS_BoardEntry *LPS_Board )
{
    LPS_Board->checkVoltage = TRUE;     /* Enable voltage checking          */
} /* LPS_BoardEnableVoltageCheck() */

/****************************************************************************/
/* Function    : LPS_BoardVicorCtrl                                         */
/* Purpose     : Controls state of Low Power Switch Board Vicor Output      */
/* Inputs      : LPS Board data structure, desired vicor output state       */
/* Outputs     : Returns result of IBC Bus Write - OK or ERROR if timeout   */
/****************************************************************************/
    Int16
LPS_BoardVicorCtrl( LPS_BoardEntry *LPS_Board, MBool vicorState )
{
    Int16 status;                       /* Vicor closure status             */

    if ( LPS_Board == NULL )            /* Check for valid LPS data struct  */
        return (ERROR);

                                /* Create appropriate control register byte */
    if (vicorState)             /* Desired Vicor state is Enabled           */
        LPS_Board->switchState |= LPS_BOARD_VICOR_ON;
    else                        /* Desired Vicor state if Disabled          */
        LPS_Board->switchState &= ~LPS_BOARD_VICOR_ON;

                                /* Enable or disable Vicor Power Supply     */
    status = LPS_BoardSwitchCtrl( LPS_Board, LPS_Board->switchState );
		    
    if ((vicorState == OFF) && (status == OK))
        LPS_SetVoltageToZero( LPS_Board ); /* Set Filtered Voltage to zero  */

    return(status);
} /* LPS_BoardVicorCtrl() */

/****************************************************************************/
/* Function    : LPS_BoardSwitch                                            */
/* Purpose     : Controls state of Low Power Switch Board channel switch    */
/* Inputs      : LPS Board data structure, channel No & desired switch state*/
/* Outputs     : Returns result of IBC Bus Write - OK or ERROR if timeout   */
/****************************************************************************/
    Int16
LPS_BoardSwitch( LPS_BoardEntry *LPS_Board, Byte chan, MBool state )
{
    Byte switchControl;                 /* Switch register control byte     */
    Int16 status;                       /* Switch closure status            */

    if ( LPS_Board == NULL )            /* Check for valid LPS data struct  */
        return (ERROR);

                                        /* Is gang output mode enabled ?    */
    if (LPS_Board->lpsChan[chan].gangOutputs)
                                        /* Byte for switching 2 channels on */
        switchControl = (3 << (chan & 0xfe));
    else                                /* Byte for swicthing 1 channel on  */
        switchControl = (1 << chan);

    if (state == ON)                    /* Desired switch state is On       */
    {
                                        /* Set physical channel switch On   */
        status = (LPS_BoardSwitchCtrl(LPS_Board,
               LPS_Board->switchState | switchControl));

        if (LPS_Board->switchOnDelay)   /* Optional switch on delay         */
        {
            LPS_Board->checkVoltage = FALSE;    /* Disable voltage checking */
            timerStart(LPS_Board->switchOnTimer, LPS_Board->switchOnDelay,
                LPS_BoardEnableVoltageCheck, (Int16) LPS_Board);
        } /* if */
    } /* if */
    else                                /* Desired switch state is Off      */
    {                                   /* Set physical channel switch Off  */
       status = (LPS_BoardSwitchCtrl(LPS_Board,
               LPS_Board->switchState & ~switchControl));
       LPS_SetCurrentToZero(LPS_Board, chan);
    } /* else */

    return (status);                    /* Return result of switch closure  */
} /* LPS_BoardSwitch() */

/****************************************************************************/
/* Function    : LPS_BoardReadAtoD                                          */
/* Purpose     : Read 8 bit value from A to D for channel no specified      */
/* Inputs      : LPS Board data structure and A to D channel number         */
/* Outputs     : Returns A to D convertor value or ERROR if timeout         */
/****************************************************************************/
    MLocal Int16
LPS_BoardReadAtoD( LPS_BoardEntry *LPS_Board, Int16 channel )
{
    Nat16 ticks = LPS_ATOD_TIMEOUT;     /* Conversion loop timeout          */

    if ( LPS_Board == NULL )            /* Check for valid LPS data struct  */
         return (ERROR);
                                        /* Start A/D conversion for channel */
    ibcBusWriteByte( LPS_Board->IBC_Board.baseAddress + LPS_AtoD_REG,
        (Byte) (LPS_AtoD_SINGLE_ENDED | channel) );

                                        /* Wait for conversion to complete  */
    while(((PIC_intStatus() & (1 << LPS_Board->IBC_Board.intrLevel)) == 0)
         && ( --ticks ));
                                        /* Read A to D conversion result    */
    return(ibcBusReadByte( LPS_Board->IBC_Board.baseAddress + LPS_AtoD_REG ));
} /* LPS_BoardReadAtoD() */

/****************************************************************************/
/* Function    : LPS_SetVoltageToZero                                       */
/* Purpose     : Set voltage to zero for LPS Board switch channel           */
/* Inputs      : Pointer to LPS Board data structure, channel               */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
LPS_SetVoltageToZero( LPS_BoardEntry *LPS_Board )
{
    LPS_Board->filteredVicorVoltage = 0;/* Initialize vicor voltage filter  */
    initIIRFilter(&LPS_Board->vicorVoltageFilter, LPS_MAX_VOLTAGE);
} /* LPS_SetVoltageToZero */

/****************************************************************************/
/* Function    : LPS_BoardInterruptOn                                       */
/* Purpose     : Generate Interrupt from Low Power Switch Board             */
/* Inputs      : Pointer to LPS Board data structure                        */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_BoardInterruptOn( LPS_BoardEntry *LPS_Board )
{
    Int16 delay;                        /* Used for short delay loop        */
                                        /* Start A/D conversion             */
    ibcBusWriteByte( LPS_Board->IBC_Board.baseAddress + LPS_AtoD_REG,
        (Byte) (LPS_AtoD_SINGLE_ENDED | LPS_VICOR_TEMP_CHAN) );
                                        /* Short delay for end of conversion*/
    for (delay = 0; delay < 50; delay++);
} /* LPS_BoardInterruptOn() */

/****************************************************************************/
/* Function    : LPS_SetCurrentToZero                                       */
/* Purpose     : Set current to zero for LPS Board switch channel           */
/* Inputs      : Pointer to LPS Board data structure, channel               */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
LPS_SetCurrentToZero( LPS_BoardEntry *LPS_Board, Int16 chan )
{
    if (LPS_Board->lpsChan[chan].gangOutputs)
    {
        chan &= 0xfe;                   /* Get lower channel of gang pair  */
        LPS_Board->lpsChan[chan + 1].filteredCurrent = 0;
        initIIRFilter(&LPS_Board->lpsChan[chan + 1].filter, LPS_MAX_CURRENT);
    } /* if */

    LPS_Board->lpsChan[chan].filteredCurrent = 0;
    initIIRFilter(&LPS_Board->lpsChan[chan].filter, LPS_MAX_CURRENT);
    LPS_CheckCurrent(LPS_Board, chan);
} /* LPS_SetCurrentToZero */

    Void
LPS_measureCurrent(LPS_BoardEntry *LPS_Board, Int16 chan)
{
    if ((LPS_Board->lpsChan[chan].gangOutputs) && (chan & 0x01))
        return;                 /* Do nothing for even ganged channels */

    if ( (LPS_Board->switchState & (1 << chan)) &&
         (IIRfilter( LPS_MILLIAMPS(
            LPS_BoardReadAtoD(LPS_Board, LPS_SW0_CURRENT_CHAN + chan )),
            &LPS_Board->lpsChan[chan].filteredCurrent,
            &LPS_Board->lpsChan[chan].filter) == OK) )
    {
        if (LPS_Board->lpsChan[chan].gangOutputs)
        {
            if ( (LPS_Board->switchState & (1 << (chan + 1))) &&
                 (IIRfilter( LPS_MILLIAMPS(
                   LPS_BoardReadAtoD(LPS_Board, LPS_SW0_CURRENT_CHAN + chan + 1)),
                   &LPS_Board->lpsChan[chan + 1].filteredCurrent,
                   &LPS_Board->lpsChan[chan + 1].filter) == OK) )

                                         /* Sum currents for channel pair   */
            LPS_Board->lpsChan[chan].filteredCurrent +=
            LPS_Board->lpsChan[chan + 1].filteredCurrent;
        } /* if */

        LPS_CheckCurrent( LPS_Board, chan );
    } /* if */
} /* LPS_measureCurrent() */

/****************************************************************************/
/* Function    : LPS_BoardInterruptOff                                      */
/* Purpose     : Clear Interrupt from Low Power Switch Board                */
/* Inputs      : Pointer to LPS Board data structure                        */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_BoardInterruptOff( LPS_BoardEntry *LPS_Board )
{                                       /* Read A to D result to clear intr */
    ibcBusReadByte( LPS_Board->IBC_Board.baseAddress + LPS_AtoD_REG);
} /* LPS_BoardInterruptOff() */

/****************************************************************************/
/* Function    : LPS_VicorControlCmd                                        */
/* Purpose     : Process command to Enable/Disable Vicor PSU output         */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None, but Vicor output state is modified                   */
/****************************************************************************/
    Void
LPS_VicorControlCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
    Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Word    command;            /* Serial command - discarded               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    Word    vicorState;         /* LPS Board desired vicor state            */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 3, &command, &boardAddr, &vicorState);

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

                                /* Enable or disable Vicor Power Supply     */
    if (LPS_BoardVicorCtrl(LPS_Board, vicorState) == OK)
        replyToCommand(1, CMD_OK);      /* Report status to serial port     */
    else
        replyToCommand(1, CMD_ERROR);   /* Report ERROR to serial port      */
} /* LPS_VicorControlCmd() */

/****************************************************************************/
/* Function    : LPS_SwitchControlCmd                                       */
/* Purpose     : Process command to set Low Power Switch channel On or Off  */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None, but switch state is modified                         */
/****************************************************************************/
    Void
LPS_SwitchControlCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
    Byte *commandBuf )
{
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    Word    chan;               /* LPS Board Switch from command buffer     */
    Word    state;              /* LPS Board desired switch state           */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */
    Nat16   card;               /* Card index into Card Table               */
    Word    command;            /* Serial command - discarded               */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 4, &command, &boardAddr, &chan, &state);

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */

                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

    if (state) state = ON;      /* Translate any non-zero value to ON       */
                                /* Change physical switch state             */
    if (LPS_BoardSwitch( LPS_Board, (Byte) chan, (MBool) state) != ERROR)
        replyToCommand(1, CMD_OK);      /* Report status to serial port     */
    else
        replyToCommand(1, CMD_ERROR);   /* Report ERROR to serial port      */

     if (state == OFF)
         LPS_SetCurrentToZero(LPS_Board, chan);
     else
         for (state = 0; state < LPS_CURRENT_READS; state++)
            LPS_measureCurrent(LPS_Board, chan);
} /* LPS_SwitchControlCmd() */

/****************************************************************************/
/* Function    : LPS_SwitchStatusCmd                                        */
/* Purpose     : Process command to read state of LPS switches and vicor    */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None, but switch state is modified                         */
/****************************************************************************/
    Void
LPS_SwitchStatusCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    Nat16   card;               /* Card index into Card Table               */

                                /* Extract command and arguments from buffer*/
    boardAddr = (Byte*) wordFromBuf(commandBuf, sizeof(Word));

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Report LPS switch status to serial port  */
    replyToCommand (2, CMD_OK,
            (Word) ((LPS_BoardEntry *) IBC_CardTable[card])->switchState);
} /* LPS_SwitchStatusCmd() */

/****************************************************************************/
/* Function    : LPS_SetCurrentThreshCmd                                    */
/* Purpose     : Process command to set current warning & alarm set points  */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_SetCurrentThreshCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Word    command;            /* Serial command word - ignored            */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */
    Int16   chan;               /* LPS output channel index                 */

    Int16   currentWarn[LPS_MAX_CHANS];    /* Current warning thresholds    */
    Int16   currentAlarm[LPS_MAX_CHANS];   /* Current alarm threshold       */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 10, &command, &boardAddr,
         &currentWarn[0], &currentAlarm[0],
         &currentWarn[1], &currentAlarm[1],
         &currentWarn[2], &currentAlarm[2],
         &currentWarn[3], &currentAlarm[3]);

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */

                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

                                /* Store new thresholds in LPS data struct  */
    for (chan = 0; chan <  LPS_MAX_CHANS; chan++)
    {
       LPS_Board->lpsChan[chan].currentWarning = currentWarn[chan];
       LPS_Board->lpsChan[chan].currentAlarm = currentAlarm[chan];
    } /* for */

    replyToCommand(1, CMD_OK);  /* Report OK to serial port                 */
} /* LPS_SetCurrentThreshCmd() */

/****************************************************************************/
/* Function    : LPS_GetCurrentThreshCmd                                    */
/* Purpose     : Process command to read current warning & alarm set points */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_GetCurrentThreshCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

                                /* Extract LPS board address from buffer    */
    boardAddr = (Byte*) wordFromBuf(commandBuf, sizeof(Word));

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
            boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                          /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

                                /* Put threshold values in serial buffer    */
                                /* and send buffer to serial port           */
    replyToCommand(9, CMD_OK,
        (Word) LPS_Board->lpsChan[0].currentWarning,
        (Word) LPS_Board->lpsChan[0].currentAlarm,

        (Word) LPS_Board->lpsChan[1].currentWarning,
        (Word) LPS_Board->lpsChan[1].currentAlarm,

        (Word) LPS_Board->lpsChan[2].currentWarning,
        (Word) LPS_Board->lpsChan[2].currentAlarm,

        (Word) LPS_Board->lpsChan[3].currentWarning,
        (Word) LPS_Board->lpsChan[3].currentAlarm );
} /* LPS_GetCurrentThreshCmd() */

/****************************************************************************/
/* Function    : LPS_SetTempThreshCmd                                       */
/* Purpose     : Process command to set temperature warning & alarm points  */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_SetTempThreshCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Word    command;            /* Serial command - discarded               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

    Int16   vicorTempWarn, vicorTempAlarm;      /* Vicor temp thresholds    */
    Int16   switchTempWarn, switchTempAlarm;    /* Switch 3 temp thresholds */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 6, &command, &boardAddr,
         &vicorTempWarn, &vicorTempAlarm, &switchTempWarn, &switchTempAlarm);

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

                                /* Store new thresholds in LPS data struct  */
    LPS_Board->vicorTempWarning  = vicorTempWarn;
    LPS_Board->vicorTempAlarm    = vicorTempAlarm;
    LPS_Board->switchTempWarning = switchTempWarn;
    LPS_Board->switchTempAlarm   = switchTempAlarm;

    replyToCommand(1, CMD_OK);  /* Report OK to serial port                 */
} /* LPS_SetTempThreshCmd() */

/****************************************************************************/
/* Function    : LPS_GetTempThreshCmd                                       */
/* Purpose     : Process command to read temperature warning & alarm points */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_GetTempThreshCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

                                /* Extract command and arguments from buffer*/
    boardAddr = (Byte*) wordFromBuf(commandBuf, sizeof(Word));

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

    replyToCommand(5, CMD_OK,   /* Send threshold values to serial port     */
         (Word) LPS_Board->vicorTempWarning,
         (Word) LPS_Board->vicorTempAlarm,
         (Word) LPS_Board->switchTempWarning,
         (Word) LPS_Board->switchTempAlarm);

} /* LPS_GetTempThreshCmd() */

/****************************************************************************/
/* Function    : LPS_GetTemperatureCmd                                      */
/* Purpose     : Process command to read filtered temperature measurements  */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_GetTemperaturesCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

                                /* Extract command and arguments from buffer*/
    boardAddr = (Byte*) wordFromBuf(commandBuf, sizeof(Word));

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

    replyToCommand(3, CMD_OK,   /* Send filtered temperatures               */
         (Word) LPS_Board->filteredVicorTemp,
         (Word) LPS_Board->filteredSw3Temp);
} /* LPS_GetTemperaturesCmd() */

/****************************************************************************/
/* Function    : LPS_SetVoltageThreshCmd                                    */
/* Purpose     : Process command to set voltage warning & alarm points      */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_SetVoltageThreshCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
    Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Word    command;            /* Serial command - discarded               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

    Int16   voltageWarn, voltageAlarm;       /* Vicor Voltage thresholds    */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 4, &command, &boardAddr,
                 &voltageWarn, &voltageAlarm);

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

                                /* Store new thresholds in LPS data struct  */
    LPS_Board->voltageWarning = voltageWarn;
    LPS_Board->voltageAlarm   = voltageAlarm;

    replyToCommand(1, CMD_OK);  /* Report OK to serial port                 */
} /* LPS_SetVoltageThreshCmd() */

/****************************************************************************/
/* Function    : LPS_GetVoltageThreshCmd                                    */
/* Purpose     : Process command to read voltage warning & alarm points     */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_GetVoltageThreshCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

                                /* Extract command and arguments from buffer*/
    boardAddr = (Byte*) wordFromBuf(commandBuf, sizeof(Word));

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

    replyToCommand(3, CMD_OK,   /* Send threshold values to serial port     */
         (Word) LPS_Board->voltageWarning,
         (Word) LPS_Board->voltageAlarm );

} /* LPS_GetVoltageThreshCmd() */

/****************************************************************************/
/* Function    : LPS_GetVoltageCmd                                          */
/* Purpose     : Process command to read filtered vicor output voltage      */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_GetVoltageCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    Nat16   card;               /* Card index into Card Table               */

                                /* Extract command and arguments from buffer*/
    boardAddr = (Byte*) wordFromBuf(commandBuf, sizeof(Word));

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Send filtered voltage reading            */
    replyToCommand(2, CMD_OK, (Word)
        (((LPS_BoardEntry *) IBC_CardTable[card])->filteredVicorVoltage));
} /* LPS_GetVoltageCmd() */

/****************************************************************************/
/* Function    : LPS_RoundCurrent                                           */
/* Purpose     : Rounds a current reading to nearest 100 mAmps              */
/* Inputs      : Current value in mAmps                                     */
/* Outputs     : Rounded current value in mAmps                             */
/****************************************************************************/
    MLocal Int16
LPS_RoundCurrent(Int16 value)
{
    if (value >= 0)
        return (( (value / 100) + ((value % 100) >= 50)) * 100);
    else
        return (( (value / 100) - ((abs(value) % 100) >= 50)) * 100);
} /* LPS_RoundCurrent() */

/****************************************************************************/
/* Function    : LPS_GetCurrentsCmd                                         */
/* Purpose     : Process command to read filtered switch currents           */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_GetCurrentsCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

                                /* Extract command and arguments from buffer*/
    boardAddr = (Byte*) wordFromBuf(commandBuf, sizeof(Word));

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

                                /* Send filtered current reading            */
    replyToCommand(5, CMD_OK,
       LPS_RoundCurrent( LPS_Board->lpsChan[0].filteredCurrent),
       LPS_RoundCurrent( LPS_Board->lpsChan[1].filteredCurrent),
       LPS_RoundCurrent( LPS_Board->lpsChan[2].filteredCurrent),
       LPS_RoundCurrent( LPS_Board->lpsChan[3].filteredCurrent));
} /* LPS_GetCurrentsCmd() */

/****************************************************************************/
/* Function    : LPS_GetAlarmStatusCmd                                      */
/* Purpose     : Process command to read LPS Board Alarm Status             */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_GetAlarmStatusCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

                                /* Extract command and arguments from buffer*/
    boardAddr = (Byte*) wordFromBuf(commandBuf, sizeof(Word));

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

                                /* Send Alarm Status to serial port         */
    replyToCommand(8, CMD_OK,
       LPS_Board->lpsChan[0].currentAlarmStatus,
       LPS_Board->lpsChan[1].currentAlarmStatus,
       LPS_Board->lpsChan[2].currentAlarmStatus,
       LPS_Board->lpsChan[3].currentAlarmStatus,

       (microAlarm) LPS_Board->alarmStatus.vicorTempAlarm,
       (microAlarm) LPS_Board->alarmStatus.sw3TempAlarm,
       (microAlarm) LPS_Board->alarmStatus.vicorVoltageAlarm);
 } /* LPS_GetAlarmStatusCmd() */

/****************************************************************************/
/* Function    : LPS_GangOutputsCmd                                         */
/* Purpose     : Process command to Enable/Disable Ganging of LPS outputs   */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None, but LPS data structure is modified                   */
/****************************************************************************/
    Void
LPS_GangOutputsCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
    Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Word    command;            /* Serial command - discarded               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    Word    chan;               /* LPS Board Switch from command buffer     */
    Word    gangOutputs;        /* Gang outputs enable/disable              */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 4, &command, &boardAddr, &chan, &gangOutputs);

                                /* Find card table index for this address   */
    if ( ((card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, LOW_POWER_SWITCH) ) == ERROR) ||
        (chan > LPS_MAX_CHANS))
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to LPS data structure    */
    LPS_Board = (LPS_BoardEntry *) IBC_CardTable[card];

    chan &= 0xfe;               /* Get lowest channel number of the pair    */

                                /* Set gang output flags for both channels  */
    LPS_Board->lpsChan[chan].gangOutputs     = (gangOutputs ? TRUE : FALSE);
    LPS_Board->lpsChan[chan + 1].gangOutputs = (gangOutputs ? TRUE : FALSE);

    replyToCommand(1, CMD_OK);  /* Report status to serial port             */
} /* LPS_GangOutputsCmd() */

/****************************************************************************/
/* Function    : LPS_SetSwitchDelayCmd                                      */
/* Purpose     : Process command to Set Switch Delay Time (10 msec)         */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None, but LPS data structure is modified                   */
/****************************************************************************/
    Void
LPS_SetSwitchDelayCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
    Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Word    command;            /* Serial command - discarded               */
    Byte    *boardAddr;         /* LPS Board base address from command buf  */
    Nat16   delayTime;          /* Switch On Delay 10 msec increments       */
    LPS_BoardEntry *LPS_Board;  /* LPS Board Entry data structure           */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 3, &command, &boardAddr, &delayTime);

                                /* Find card table index for this address   */
    if ((card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                   boardAddr, LOW_POWER_SWITCH) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Save delay time in board data structure  */
    ((LPS_BoardEntry *) IBC_CardTable[card])->switchOnDelay = delayTime;

    replyToCommand(1, CMD_OK);  /* Report status to serial port             */
} /* LPS_SetSwitchDelayCmd() */

/****************************************************************************/
/* Function    : LPS_CheckCurrent                                           */
/* Purpose     : Compare current to alarm threshold & shutdown switch       */
/* Inputs      : LPS Board data structure                                   */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
LPS_CheckCurrent( LPS_BoardEntry *LPS_Board, Int16 chan )
{
    microAlarm alarmStatus;             /* Alarm status from bit field      */

                                        /* Extract current alarm status     */
    alarmStatus = LPS_Board->lpsChan[chan].currentAlarmStatus;

                                        /* Check if current has exceeded the*/
                                        /* current WARNING/ALARM threshold  */
                                        /* & send alarm SRQ's if necessary  */
    if (IBC_AlarmThresholdCheck( LPS_Board->lpsChan[chan].filteredCurrent,
        LPS_Board->lpsChan[chan].currentWarning,
        LPS_Board->lpsChan[chan].currentAlarm,
        LPS_CURRENT_HYSTERESIS, &alarmStatus ) == TRUE)

        writeServiceRequest(4, LPS_CURRENT_ALARM_SRQ, alarmStatus,
                    LPS_Board->IBC_Board.baseAddress, chan);

                                        /* Update current WARNING bit field */
    LPS_Board->lpsChan[chan].currentAlarmStatus = alarmStatus;

    if (alarmStatus == MICRO_ALARM)     /* If Current alarm condition then  */
    {                                   /* switch off LPS channel           */
        LPS_BoardSwitch(LPS_Board, (Byte) chan, OFF);
        LPS_SetCurrentToZero(LPS_Board, chan);
    } /* if */
} /* LPS_CheckCurrent() */

/****************************************************************************/
/* Function    : LPS_CheckTemperatures                                      */
/* Purpose     : Compare temperatures to alarm thresholds & shutdown Vicor  */
/* Inputs      : LPS Board data structure                                   */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
LPS_CheckTemperature( LPS_BoardEntry *LPS_Board )
{
    Int16 chan;                         /* LPS Switch channel counter       */
    microAlarm alarmStatus;             /* Temperature alarm status         */


                                        /* Extract temperature alarm status */
    alarmStatus = (microAlarm) LPS_Board->alarmStatus.vicorTempAlarm;

                                        /* Check if temperature has exceeded*/
                                        /* temperature WARN/ALARM thresholds*/
                                        /* and send alarm SRQ's if necessary*/
    if (IBC_AlarmThresholdCheck( LPS_Board->filteredVicorTemp,
            LPS_Board->vicorTempWarning, LPS_Board->vicorTempAlarm,
            LPS_TEMP_HYSTERESIS, &alarmStatus ) == TRUE)

        writeServiceRequest(3, LPS_VICOR_TEMP_ALARM_SRQ, alarmStatus,
           LPS_Board->IBC_Board.baseAddress);

                                        /* Update temperature ALARM status  */
    LPS_Board->alarmStatus.vicorTempAlarm = (unsigned) alarmStatus;

    if (alarmStatus == MICRO_ALARM)     /* If Temperature alarm active      */
    {
        LPS_BoardSwitchCtrl( LPS_Board, /* disable vicor                    */
            LPS_BOARD_VICOR_OFF | LPS_BOARD_LED_ON );

        LPS_SetVoltageToZero( LPS_Board ); /* Set Filtered Voltage to zero  */

        for (chan = 0; chan < LPS_MAX_CHANS; chan++)
            LPS_SetCurrentToZero(LPS_Board, chan);
    } /* if */

                                        /* ********* SWITCH 3 ALARMS        */

                                        /* Extract temperature ALARM status */
    alarmStatus = (microAlarm) LPS_Board->alarmStatus.sw3TempAlarm;

                                        /* Check if temperature has exceeded*/
                                        /* temperature WARN/ALARM thresholds*/
                                        /* and send alarm SRQ's if necessary*/
    if (IBC_AlarmThresholdCheck( LPS_Board->filteredSw3Temp,
           LPS_Board->switchTempWarning, LPS_Board->switchTempAlarm,
           LPS_TEMP_HYSTERESIS, &alarmStatus ) == TRUE)

        writeServiceRequest(3, LPS_SW3_TEMP_ALARM_SRQ, alarmStatus,
                LPS_Board->IBC_Board.baseAddress);

                                        /* Update temperature WARN bit field*/
    LPS_Board->alarmStatus.sw3TempAlarm = (unsigned) alarmStatus;

    if (alarmStatus == MICRO_ALARM)     /* If Temperature alarm active      */
    {
        LPS_BoardSwitchCtrl( LPS_Board, /* disable vicor                    */
            LPS_BOARD_VICOR_OFF | LPS_BOARD_LED_ON );

        LPS_SetVoltageToZero( LPS_Board ); /* Set Filtered Voltage to zero  */

        for (chan = 0; chan < LPS_MAX_CHANS; chan++)
            LPS_SetCurrentToZero(LPS_Board, chan);
    } /* if */

} /* LPS_CheckTemperature() */

/****************************************************************************/
/* Function    : LPS_CheckVoltage                                           */
/* Purpose     : Compare vicor voltage to alarm thresholds                  */
/* Inputs      : LPS Board data structure                                   */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
LPS_CheckVoltage( LPS_BoardEntry *LPS_Board )
{
    microAlarm alarmStatus;             /* Voltage alarm status             */
                                        /* Exit if vicor is switched off    */
    if ( !(LPS_Board->switchState & LPS_BOARD_VICOR_ON))
        return;

    if (IIRfilter( LPS_VOLTS(           /* Read & Filter Vicor Voltage       */
        LPS_BoardReadAtoD( LPS_Board, LPS_VICOR_VOLTAGE_CHAN )),
        &LPS_Board->filteredVicorVoltage,
        &LPS_Board->vicorVoltageFilter ) != OK)
            return;                     /* Wait for filter to stabilize     */

                                        /* Vicor Voltage checking disabled  */
    if (LPS_Board->checkVoltage == FALSE)
        return;
                                        /* Wait for thresholds from serial  */
                                        /* port for undefined voltage board */
    if ( (LPS_Board->voltageWarning == 0) && (LPS_Board->voltageAlarm == 0) )
        return;
                                        /* Extract voltage alarm status     */
    alarmStatus = (microAlarm) LPS_Board->alarmStatus.vicorVoltageAlarm;

                                        /* Check if voltage is less than    */
                                        /* voltage WARN/ALARM thresholds    */
                                        /* and send alarm SRQ's if necessary*/
    if (IBC_BelowThresholdCheck(
           (Int16) ( ((Nat16) LPS_Board->filteredVicorVoltage) / 10),
           LPS_Board->voltageWarning, LPS_Board->voltageAlarm,
           LPS_VOLTAGE_HYSTERESIS, &alarmStatus ) == TRUE)
    {
            writeServiceRequest(3, LPS_VOLTAGE_ALARM_SRQ, alarmStatus,
                LPS_Board->IBC_Board.baseAddress);
    } /* if */
                                        /* Update voltage alarm bit field */
    LPS_Board->alarmStatus.vicorVoltageAlarm = (unsigned) alarmStatus;
} /* LPS_CheckVoltage() */

/****************************************************************************/
/* Function    : LPS_BoardFunctions                                         */
/* Purpose     : Low Power Switch real-time loop functions                  */
/* Inputs      : LPS Board data structure                                   */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
LPS_BoardFunctions( LPS_BoardEntry *LPS_Board )
{
    Int16 chan;                         /* LPS Switch channel counter       */

    switch (LPS_Board->state++)
    {
      case LPS_CURRENT:                 /* Measure currents for all switches*/
        for (chan = 0; chan < LPS_MAX_CHANS; chan++)
            LPS_measureCurrent(LPS_Board, chan);
        break;

    case LPS_VICOR_TEMP:
        IIRfilter( LPS_DEGREES(         /* Read & Filter Vicor Temperature  */
            LPS_BoardReadAtoD( LPS_Board, LPS_VICOR_TEMP_CHAN )),
            &LPS_Board->filteredVicorTemp, &LPS_Board->vicorTempFilter );

        break;

    case LPS_SW3_TEMP:
        if (IIRfilter( LPS_DEGREES(     /* Read &Filter Switch 3 Temperature */
            LPS_BoardReadAtoD( LPS_Board, LPS_SW3_TEMP_CHAN )),
            &LPS_Board->filteredSw3Temp, &LPS_Board->sw3TempFilter ) == OK)

                                        /* Check temperature warn & alarm    */
            LPS_CheckTemperature( LPS_Board );
        break;

    case LPS_VICOR_VOLTAGE:
        LPS_CheckVoltage( LPS_Board );  /* Measure & check vicor voltage     */
        LPS_Board->state = LPS_CURRENT;
        break;

    } /* switch */
} /* LPS_BoardFunctions() */








