/****************************************************************************/
/* Copyright 1992, 1993 MBARI                                               */
/****************************************************************************/
/* Summary  : IBC Dual Vicor Board Functions                                */
/* Filename : vicor.c                                                       */
/* Author   : Andrew Pearce                                                 */
/* Project  : New ROV IBC Based Data Concentrator                           */
/* Version  : 1.0                                                           */
/* Created  : 09/28/92                                                      */
/* Modified : 04/01/93                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: /usr/tiburon/.cvsroot/micro/ibc/boards/vicor/vicor.c,v 1.3 1997/05/19 23:36:23 audo Exp $
 * $Log: vicor.c,v $
 * Revision 1.3  1997/05/19 23:36:23  audo
 * ibc_card.h -- clean up include paths
 * vicor.h -- Fixed temperature scaling and status
 *
 * Revision 1.2  1997/05/07 15:33:16  pean
 * Cleaned up Include files and makefile for new directory structure.
 *
 * Revision 1.1.1.1  1997/05/02 18:51:32  pean
 * Initial check in of IBC microcontroller software
 *
 * Revision 1.1  93/07/02  09:41:41  09:41:41  pean (Andrew Pearce)
 * Initial revision
 *
*/
/****************************************************************************/

#pragma model(196)
#pragma nosignedchar

#include "C:/C96/include/80C196.h"      /* 80196 Register mapping           */
#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 "microdef.h"                   /* Microcontroller definitions      */
#include "microlib.h"                   /* Microcontroller Library decls.   */
#include "malloc.h"                     /* Malloc support routines          */
#include "microCmd.h"                   /* microcontroller commands         */
#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 "vicor.h"                      /* IBC Dual Vicor Board Definitions */

MLocal vicorBoardEntry vicorBoard0;     /* Vicor Board 0 IBC Data Structure */
MLocal vicorBoardEntry vicorBoard1;     /* Vicor Board 1 IBC Data Structure */

                                        /* Forward declarations for MLocals */
MLocal Void dualVicorSwitchPsu(vicorBoardEntry* vicorBoard, Byte psu,
     Word state);
    
/****************************************************************************/
/* Function    : dualVicorBoardAdd                                          */
/* Purpose     : Adds a vicor board entry to IBC Card Table                 */
/* Inputs      : Pointer to IBC Board Table, table size, vicor board address*/
/*               vicor board configuration                                  */
/* Outputs     : None                                                       */
/****************************************************************************/
    Int16
dualVicorBoardAdd( IBC_BoardEntry *IBC_CardTable[], Int16 maxCards,
    Int16 cardCount, Byte *vicorAddr, vicorPsuConfig vicorConfig )
{
                                /* Add entry for one Dual Vicor Card        */
    return ( dualVicorBoardInit( &IBC_CardTable[cardCount],
            maxCards - cardCount, vicorAddr, vicorConfig ));
} /* dualVicorBoardAdd() */

/****************************************************************************/
/* Function    : dualVicorBoardInit                                         */
/* Purpose     : Dual Vicor Board Initialization routine                    */
/* Inputs      : Pointer to IBC Board Table, table size, vicor board address*/
/*               vicor board configuration                                  */
/* Outputs     : None                                                       */
/****************************************************************************/
    Int16
dualVicorBoardInit( IBC_BoardEntry *IBC_CardTable[], Int16 maxCards,
     Byte *boardBaseAddr, vicorPsuConfig vicorConfig )
{
    vicorBoardEntry* dualVicor;         /* Pointer to Dual Vicor Data       */
    Int16 psu;                          /* Power Supply Loop Counter        */
    Byte  old_ioc1;                     /* Current value of 80C196 IOC1 Reg */

    if (maxCards <= 0)                  /* No room in IBC Card Table        */
        return(0);                      /* So return zero                   */

                                        /* Check for board 0 pseudo-address */
    if (boardBaseAddr == (Byte *) DUAL_VICOR_0_ADDR)
        dualVicor = &vicorBoard0;       /* Copy Vicor 0 Data Structure Ptr  */

                                        /* Check for board 1 pseudo-address */
    else if (boardBaseAddr == (Byte *) DUAL_VICOR_1_ADDR)
        dualVicor = &vicorBoard1;       /* Copy Vicor 1 Data Structure Ptr  */

    else                                /* Bad pseudo-address specified so  */
        return(0);                      /* return 0 - no boards "found"     */

                                        /* If Vicor Board 1 selected then   */
    if (boardBaseAddr == (Byte *) DUAL_VICOR_1_ADDR)
    {                                   /* SET HSO.4 and HSO.5 TO OUTPUTS   */

        intDisable;                     /* Disable interrupts to change WRS */
        wsr = HWINDOW15;                /* Select horizontal reg window 15  */
        old_ioc1 = ioc1;                /* Read old value from IOC1         */
        wsr = HWINDOW0;                 /* Select horizontal reg window 0   */
                                        /* Write new value to IOC1          */
        ioc1 = old_ioc1 | IOC1_HSO_4_ENABLE | IOC1_HSO_5_ENABLE;
        intEnable;                      /* Re-enable interrupts             */
    } /* if */
                                        /* Fill out board entry structure   */
    dualVicor->IBC_Board.baseAddress   = boardBaseAddr;
    dualVicor->IBC_Board.boardType     = DUAL_VICOR;
    dualVicor->IBC_Board.intrLevel     = IBC_INT_LVL_OFF;

    dualVicor->psuConfig = vicorConfig; /* Save board configuration value   */

    for (psu = DUAL_VICOR_PSU0; psu <= DUAL_VICOR_PSU1; psu++)
    {
                                        /* Clear alarm status flags         */
        dualVicor->vicor[psu].status.psuAlarm      = FALSE;
        dualVicor->vicor[psu].status.vicorEnable   = FALSE;
        dualVicor->vicor[psu].status.vicorTempAlarm = (unsigned) MICRO_ALARM_OK;

                                        /* Set default alarm thresholds     */
        if (dualVicor->psuConfig == DUAL_VICOR_TWO_MINI_MODS)
        {                               /* Thresholds for two Vicor board   */
            dualVicor->vicor[psu].tempWarning  = DUAL_VICOR_TWO_TEMP_WARN;
            dualVicor->vicor[psu].tempAlarm    = DUAL_VICOR_TWO_TEMP_ALARM;
        } /* if */
        else
        {                               /* Thresholds for one Vicor Board   */
            dualVicor->vicor[psu].tempWarning  = DUAL_VICOR_ONE_TEMP_WARN;
            dualVicor->vicor[psu].tempAlarm    = DUAL_VICOR_ONE_TEMP_ALARM;
        } /* if */
                                        /* Initialize tempreature filter    */
        dualVicor->vicor[psu].filteredTemperature = 0;
        initIIRFilter(&dualVicor->vicor[psu].tempFilter, DUAL_VICOR_MAX_TEMP);
    } /* for */
                                        /* Switch Vicor PSU Output OFF      */
    dualVicorSwitchPsu( dualVicor, DUAL_VICOR_PSU0, OFF );
    dualVicorSwitchPsu( dualVicor, DUAL_VICOR_PSU1, OFF );

                                       /* Add Vicor data struct to IBC Table*/
    IBC_CardTable[0] = (IBC_BoardEntry *) dualVicor;

    return(1);                          /* Return number of boards "found"  */
} /* dualVicorBoardInit() */

/****************************************************************************/
/* Function    : dualVicorSwitchPsu                                         */
/* Purpose     : Dual Vicor Board Switch Vicor Output On/Off function       */
/* Inputs      : Vicor board data structure, psu module number, state       */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
dualVicorSwitchPsu(vicorBoardEntry* vicorBoard, Byte psu, Word state)
{
                                        /* Vicor Board 0 Address specified? */
    if (vicorBoard->IBC_Board.baseAddress == (Byte *) DUAL_VICOR_0_ADDR)
    {                                   /* Vicor Board 0                    */
        if (psu == DUAL_VICOR_PSU0)     /* PSU Module 0 ?                   */
        {                               /* Vicor Board 0, Module 0          */
            if (state == ON )           /* Is desired state ON or OFF ?     */
                                        /* Set Vicor Board 0, Module 0 ON   */
                writeIoport1(  (DUAL_VICOR0_PSU0_CTRL), OR_PORT);
            else                        /* Set Vicor Board 0, Module 0 OFF  */
                writeIoport1( ~(DUAL_VICOR0_PSU0_CTRL), AND_PORT);
                                        /* Save Vicor Enable Signal State   */
            vicorBoard->vicor[psu].status.vicorEnable = state;
        } /* if */

        else if (psu == DUAL_VICOR_PSU1)/* PSU Module 1 ?                   */
        {                               /* Vicor Board 0, Module 1          */
            if (state == ON )           /* Is desired state ON or OFF ?     */
                                        /* Set Vicor Board 0, Module 1 ON   */
                writeIoport1(  (DUAL_VICOR0_PSU1_CTRL), OR_PORT);
            else                        /* Set Vicor Board 0, Module 1 OFF  */
                writeIoport1( ~(DUAL_VICOR0_PSU1_CTRL), AND_PORT);

                                        /* Save Vicor Enable Signal State   */
            vicorBoard->vicor[psu].status.vicorEnable = state;
        } /* if */
    } /* if */
                                        /* Vicor Board 1 Address specified? */
    if (vicorBoard->IBC_Board.baseAddress == (Byte *) DUAL_VICOR_1_ADDR)
    {
        intDisable;             /* Disable Interrupts while changing HSO    */
                                /* Wait for HSO holding register to empty   */
        while (ios0 & IOS0_HOLD_REG_FULL);

        if (psu == DUAL_VICOR_PSU0)     /* PSU Module 0 ?                   */
        {                               /* Vicor Board 1, Module 0          */
            if (state == ON )           /* Is desired state ON or OFF ?     */
            {                           /* Set Vicor Board 1, Module 0 ON   */
                hso_command = HSO_CMD_USE_T1 | HSO_CMD_NO_INTR |
                             HSO_CMD_CLR_PIN | DUAL_VICOR1_PSU0_CTRL;
                hso_time = timer1 + HSO_MIN_STATE_TIME;
            } /* if */
            else
            {                           /* Set Vicor Board 1, Module 0 OFF  */
                hso_command = HSO_CMD_USE_T1 | HSO_CMD_NO_INTR |
                             HSO_CMD_SET_PIN | DUAL_VICOR1_PSU0_CTRL;
                hso_time = timer1 + HSO_MIN_STATE_TIME;
            } /* else */
                                        /* Save Vicor Enable Signal State   */
            vicorBoard->vicor[psu].status.vicorEnable = state;
        } /* if */

        else if (psu == DUAL_VICOR_PSU1)/* PSU Module 1 ?                   */
        {                               /* Vicor Board 1, Module 1          */
            if (state == ON )           /* Is desired state ON or OFF ?     */
            {                           /* Set Vicor Board 1, Module 1 ON   */
                hso_command = HSO_CMD_USE_T1 | HSO_CMD_NO_INTR |
                             HSO_CMD_CLR_PIN | DUAL_VICOR1_PSU1_CTRL;
                hso_time = timer1 + HSO_MIN_STATE_TIME;
            } /* if */
            else
            {                           /* Set Vicor Board 1, Module 1 OFF  */
                hso_command = HSO_CMD_USE_T1 | HSO_CMD_NO_INTR |
                             HSO_CMD_SET_PIN | DUAL_VICOR1_PSU1_CTRL;
                hso_time = timer1 + HSO_MIN_STATE_TIME;
            } /* else */
                                        /* Save Vicor Enable Signal State   */
            vicorBoard->vicor[psu].status.vicorEnable = state;
        } /* if */

        intEnable;              /* Re-enable interrupts after changing HSO   */
    } /* if */
} /* dualVicorSwitchPsu() */

/****************************************************************************/
/* Function    : dualVicorPsuStatus                                         */
/* Purpose     : Returns PSU Output Status Signal for specified PSU module  */
/* Inputs      : Vicor board data structure, PSU module number              */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Int16
dualVicorPsuStatus(vicorBoardEntry* vicorBoard, Byte psu)
{                                       /* Vicor Board 0 ?                  */
    if (vicorBoard->IBC_Board.baseAddress == (Byte *) DUAL_VICOR_0_ADDR)
    {                                   /* Vicor Board 0 specified          */
        if (psu == DUAL_VICOR_PSU0)     /* Vicor 0 Module 0 or Module 1 ?   */
                                        /* Read Output Status for Module 0  */
           return( (ioport0 & DUAL_VICOR0_PSU0_STATUS) ? ON : OFF );
        else                /* Read Output Status for Module 1  */
           return( (ioport0 & DUAL_VICOR0_PSU1_STATUS) ? ON : OFF );
    } /* if */

    else
    {                                   /* Vicor Board 1 specified          */
        if (psu == DUAL_VICOR_PSU0)     /* Vicor 0 Module 0 or Module 1 ?   */
                                        /* Read Output Status for Module 0  */
           return( (ioport0 & DUAL_VICOR1_PSU0_STATUS) ? ON : OFF );
        else                           /* Read Output Status for Module 1  */
           return( (ioport0 & DUAL_VICOR1_PSU1_STATUS) ? ON : OFF );
    } /* else */
} /* dualVicorPsuStatus() */

/****************************************************************************/
/* Function    : dualVicorPsuState                                          */
/* Purpose     : Returns Vicor Board Status Word containing bits which      */
/*               represent expected and actual Vicor PSU Output States      */
/* Inputs      : Vicor board data structure                                 */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Int16
dualVicorPsuState( vicorBoardEntry *vicorBoard )
{
    Word psuState = 0;                  /* Initially clear status word      */

    if ( vicorBoard == NULL)            /* Check for valid Vicor Data Struct*/
     return (ERROR);                    /* NULL board entry so return ERROR */

                                        /* Check expected PSU 0 state and   */
    if (vicorBoard->vicor[DUAL_VICOR_PSU0].status.vicorEnable)
        psuState |= DUAL_VICOR_PSU0_ON; /* set appropriate status bit       */

                                        /* Check expected PSU 1 state and   */
    if (vicorBoard->vicor[DUAL_VICOR_PSU1].status.vicorEnable)
        psuState |= DUAL_VICOR_PSU1_ON; /* set appropriate status bit       */

                                        /* Check actual PSU 0 state and     */
    if (dualVicorPsuStatus( vicorBoard, DUAL_VICOR_PSU0 ) == ON )
                                        /* set appropriate status bit       */
        psuState |= DUAL_VICOR_PSU0_STATUS;

                                       /* If Vicor 1, PSU 1 is installed   */
    if (vicorBoard->psuConfig == DUAL_VICOR_TWO_MINI_MODS)
    {                                  /* Check actual PSU 1 state and     */
        if (dualVicorPsuStatus( vicorBoard, DUAL_VICOR_PSU1 ) == ON )
                                       /* set appropriate status bit       */
              psuState |= DUAL_VICOR_PSU1_STATUS;
    } /* if */

    return(psuState);                  /* Return Vicor Board status Word   */
} /* dualVicorPsuState() */

/****************************************************************************/
/* Function    : dualVicorPsuTemp                                           */
/* Purpose     : Read Dual Vicor Board Vicor Temperature Sensor             */
/* Inputs      : Dual Vicor Board data structure and PSU Module number      */
/* Outputs     : Returns Temperature reading in degrees                     */
/****************************************************************************/
    MLocal Nat16
dualVicorPsuTemp(vicorBoardEntry* vicorBoard, Byte psu)
{
    Int16 vicorTemp;                    /* Vicor PSU module temperature     */

                                        /* Vicor Board 0 address specified ?*/
    if (vicorBoard->IBC_Board.baseAddress == (Byte *) DUAL_VICOR_0_ADDR)
    {                                   /* Vicor Board 0 address            */
        if (psu == DUAL_VICOR_PSU0)     /* PSU Module 0 or 1 ?              */
           vicorTemp = readAnalogChannel(DUAL_VICOR0_PSU0_TEMP) + 512;
        else                            /* Read appropriate PSU temperature */
           vicorTemp = readAnalogChannel(DUAL_VICOR0_PSU1_TEMP) + 512;
    } /* if */


    else
    {                                   /* Vicor Board 1 address            */
        if (psu == DUAL_VICOR_PSU0)     /* PSU Module 0 or 1 ?              */
            vicorTemp = readAnalogChannel(DUAL_VICOR1_PSU0_TEMP) + 512;
                                       /* Read appropriate PSU temperature */
        else if (vicorBoard->psuConfig == DUAL_VICOR_TWO_MINI_MODS)
               vicorTemp = readAnalogChannel(DUAL_VICOR1_PSU1_TEMP) + 512;
        else
	{
               vicorTemp = 0;           /* Single Vicor, so no temperature  */
        }
    } /* else */
                                        /* Return temperature in degrees    */
    return( DUAL_VICOR_DEGREES(vicorTemp) );
} /* dualVicorPsuTemp() */

/****************************************************************************/
/* Function    : dualVicorSwitchControlCmd                                  */
/* Purpose     : Process command to Enable/Disable Vicor PSU output         */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
   Void
dualVicorSwitchControlCmd( IBC_BoardEntry* IBC_CardTable[],
        Int16 IBC_CardCount, Byte *commandBuf )
{
    Nat16 card;                 /* Card index into Card Table               */
    Word  command;              /* Serial command - discarded               */
    Byte *boardAddr;            /* Vicor Board base address from command buf*/
    Word  psu;                  /* Vicor Board PSU from command buffer      */
    Word  state;                /* Vicor Board desired PSU state            */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 4, &command, &boardAddr, &psu, &state);

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, DUAL_VICOR) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */

    if (state) state = ON;      /* Map external representation to internal  */
                                /* Set specified Vicor PSU to desired state */
    dualVicorSwitchPsu( (vicorBoardEntry*) IBC_CardTable[card], psu, state );

    replyToCommand(1, CMD_OK);  /* Report CMD_OK to serial port             */
} /* dualVicorSwitchControlCmd() */

/****************************************************************************/
/* Function    : dualVicorStatusCmd                                         */
/* Purpose     : Process command to read state of Vicor PSU Outputs         */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None, but switch state is modified                         */
/****************************************************************************/
    Void
dualVicorStatusCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Byte    *boardAddr;         /* Vicor 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, DUAL_VICOR) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */

    replyToCommand(2, CMD_OK,   /* Send Dual Vicor Status to serial port    */
        dualVicorPsuState((vicorBoardEntry *) IBC_CardTable[card]));
} /* dualVicorStatusCmd() */

/****************************************************************************/
/* Function    : dualVicorTemperatureCmd                                    */
/* Purpose     : Process command to read filtered temperature measurement   */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
dualVicorTemperatureCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
         Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Byte    *boardAddr;         /* Vicor Board base address from command buf*/
    vicorBoardEntry* vicorBoard;/* Pointer to Dual Vicor Data               */

                                /* 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, DUAL_VICOR) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Get pointer to Vicor Board data structure*/
    vicorBoard = (vicorBoardEntry *) IBC_CardTable[card];

    replyToCommand(3, CMD_OK,   /* Send filtered temperatures               */
        vicorBoard->vicor[DUAL_VICOR_PSU0].filteredTemperature,
        vicorBoard->vicor[DUAL_VICOR_PSU1].filteredTemperature);
} /* dualVicorTemperatureCmd() */

/****************************************************************************/
/* Function    : dualVicorSetTempThreshCmd                                  */
/* Purpose     : Process command to set temperature warning & alarm points  */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
dualVicorSetTempThreshCmd( IBC_BoardEntry* IBC_CardTable[],
    Int16 IBC_CardCount, Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Word    command;            /* Serial command - discarded               */
    Byte    *boardAddr;         /* Vicor Board base address from command buf*/
    vicorBoardEntry* vicorBoard;/* Pointer to Dual Vicor Data               */

    Int16   tempWarn0, tempAlarm0;      /* Vicor Module 0 temp thresholds   */
    Int16   tempWarn1, tempAlarm1;      /* Vicor Module 1 temp thresholds   */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 6, &command, &boardAddr, &tempWarn0,
                &tempAlarm0, &tempWarn1, &tempAlarm1);

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, DUAL_VICOR) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Get pointer to Vicor Board data structure*/
    vicorBoard = (vicorBoardEntry *) IBC_CardTable[card];

                                /* Store new thresholds in LPS data struct  */
    vicorBoard->vicor[DUAL_VICOR_PSU0].tempWarning = tempWarn0;
    vicorBoard->vicor[DUAL_VICOR_PSU0].tempAlarm   = tempAlarm0;
    vicorBoard->vicor[DUAL_VICOR_PSU1].tempWarning = tempWarn1;
    vicorBoard->vicor[DUAL_VICOR_PSU1].tempAlarm   = tempAlarm1;

    replyToCommand(1, CMD_OK);  /* Report OK to serial port                 */
} /* dualVicorSetTempThreshCmd() */

/****************************************************************************/
/* Function    : dualVicorGetTempThreshCmd                                  */
/* Purpose     : Process command to read temperature warning & alarm points */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
dualVicorGetTempThreshCmd( IBC_BoardEntry* IBC_CardTable[],
    Int16 IBC_CardCount, Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Byte    *boardAddr;         /* Vicor Board base address from command buf*/
    vicorBoardEntry* vicorBoard;/* Pointer to Dual Vicor Data               */

                                /* 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, DUAL_VICOR) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Get pointer to Vicor Board data structure*/
    vicorBoard = (vicorBoardEntry *) IBC_CardTable[card];

    replyToCommand(5, CMD_OK,   /* Send threshold values to serial port     */
         (Word) vicorBoard->vicor[DUAL_VICOR_PSU0].tempWarning,
         (Word) vicorBoard->vicor[DUAL_VICOR_PSU0].tempAlarm,
         (Word) vicorBoard->vicor[DUAL_VICOR_PSU1].tempWarning,
         (Word) vicorBoard->vicor[DUAL_VICOR_PSU1].tempAlarm );

} /* dualVicorGetTempThreshCmd() */

/****************************************************************************/
/* Function    : dualVicorGetAlarmStatusCmd                                 */
/* Purpose     : Process command to read Dual Vicor Board Alarm Status      */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
dualVicorGetAlarmStatusCmd(IBC_BoardEntry* IBC_CardTable[],
    Int16 IBC_CardCount, Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Byte    *boardAddr;         /* Vicor Board base address from command buf*/
    vicorBoardEntry *vicorBoard;/* Vicor 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, DUAL_VICOR) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */
                                /* Extract pointer to Regen data structure  */
    vicorBoard = (vicorBoardEntry *) IBC_CardTable[card];

                                /* Send Alarm Status to serial port         */
    replyToCommand(5, CMD_OK,
       (microAlarm) vicorBoard->vicor[DUAL_VICOR_PSU0].status.vicorTempAlarm,
       (microAlarm) vicorBoard->vicor[DUAL_VICOR_PSU1].status.vicorTempAlarm,

       (Word) vicorBoard->vicor[DUAL_VICOR_PSU0].status.psuAlarm,
       (Word) vicorBoard->vicor[DUAL_VICOR_PSU1].status.psuAlarm );
} /* regenGetAlarmStatusCmd() */

/****************************************************************************/
/* Function    : dualVicorCheckTemperature                                  */
/* Purpose     : Compare PSU temperature to alarm setpoints & shutdown Vicor*/
/* Inputs      : LPS Board data structure                                   */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
dualVicorCheckTemperature( vicorBoardEntry *vicorBoard, Byte psu )
{
    microAlarm alarmStatus;             /* Temperature alarm status         */

                                        /* Extract temperature alarm status */
    alarmStatus = (microAlarm) vicorBoard->vicor[psu].status.vicorTempAlarm;

                                        /* Check if temperature has exceeded*/
                                        /* temperature WARN/ALARM thresholds*/
                                        /* and send alarm SRQ's if necessary*/
    if (IBC_AlarmThresholdCheck( vicorBoard->vicor[psu].filteredTemperature,
         (Int16) vicorBoard->vicor[psu].tempWarning,
         (Int16) vicorBoard->vicor[psu].tempAlarm,
         DUAL_VICOR_TEMP_HYSTERISIS, &alarmStatus ) == TRUE)

        writeServiceRequest(4, DUAL_VICOR_TEMP_ALARM_SRQ, alarmStatus,
           vicorBoard->IBC_Board.baseAddress, psu);

                                        /* Update temperature ALARM status  */
    vicorBoard->vicor[psu].status.vicorTempAlarm = (unsigned) alarmStatus;

    if (alarmStatus == MICRO_ALARM)     /* If temperature alarm active      */
                                        /* disable vicor                    */
        dualVicorSwitchPsu( vicorBoard, psu, OFF );
} /* dualVicorCheckTemperature() */

/****************************************************************************/
/* Function    : dualVicorCheckStatus                                       */
/* Purpose     : Check actual PSU status against desired & report an alarms */
/* Inputs      : Vicor board data structure                                 */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
dualVicorCheckStatus( vicorBoardEntry *vicorBoard )
{
    Int16 vicorStatus;                  /* Vicor status                     */
    Byte buffer[sizeof(Word) * 2];      /* Buffer to hold serial traffic    */

                                        /* Read Vicor Status Word           */
    vicorStatus = dualVicorPsuState( vicorBoard );

                                        /* If PSU 0 is supposed to be on,   */
                                        /* but status says it is off then   */
                                        /* Send SRQ Alarm ON Packet         */
    if  ( ((vicorStatus | DUAL_VICOR_PSU0_ON) !=
           (vicorStatus | DUAL_VICOR_PSU0_STATUS )) &&
         ! (vicorBoard->vicor[DUAL_VICOR_PSU0].status.psuAlarm ))
    {                                   /* Set alarm state flag TRUE        */
            vicorBoard->vicor[DUAL_VICOR_PSU0].status.psuAlarm = TRUE;

                                       /* Send SRQ packet to serial port   */
            writeServiceRequest (3, DUAL_VICOR_PSU_ERR_ON_SRQ,
                 vicorBoard->IBC_Board.baseAddress, DUAL_VICOR_PSU0);
     } /* if */
                                        /* If PSU 0 actual and desired state*/
                                        /* are different and SRQ was sent   */
                                        /* then send SRQ Alarm OFF packet   */
    if ( ((vicorStatus | DUAL_VICOR_PSU0_ON) ==
          (vicorStatus | DUAL_VICOR_PSU0_STATUS )) &&
         (vicorBoard->vicor[DUAL_VICOR_PSU0].status.psuAlarm ))
    {                                   /* Set alarm state flag FALSE       */
            vicorBoard->vicor[DUAL_VICOR_PSU0].status.psuAlarm = FALSE;

                                        /* Send SRQ packet to serial port   */
            writeServiceRequest(3, DUAL_VICOR_PSU_ERR_OFF_SRQ,
                 vicorBoard->IBC_Board.baseAddress, DUAL_VICOR_PSU0);
    } /* if */

                                        /* If PSU 1 is supposed to be on,   */
                                        /* but status says it is off then   */
                                        /* Send SRQ Alarm ON Packet         */
    if  ( ((vicorStatus | DUAL_VICOR_PSU1_ON) !=
           (vicorStatus | DUAL_VICOR_PSU1_STATUS )) &&
         ! (vicorBoard->vicor[DUAL_VICOR_PSU1].status.psuAlarm ))
    {                                   /* Set alarm state flag TRUE        */
            vicorBoard->vicor[DUAL_VICOR_PSU1].status.psuAlarm = TRUE;

                                        /* Send SRQ packet to serial port   */
            writeServiceRequest(3, DUAL_VICOR_PSU_ERR_ON_SRQ,
                 vicorBoard->IBC_Board.baseAddress, DUAL_VICOR_PSU1);
    } /* if */
                                        /* If PSU 1 actual and desired state*/
                                        /* are different and SRQ was sent   */
                                        /* then send SRQ Alarm OFF packet   */
    if ( ((vicorStatus | DUAL_VICOR_PSU1_ON) ==
          (vicorStatus | DUAL_VICOR_PSU1_STATUS )) &&
         (vicorBoard->vicor[DUAL_VICOR_PSU1].status.psuAlarm ))
    {                                   /* Set alarm state flag FALSE       */
            vicorBoard->vicor[DUAL_VICOR_PSU1].status.psuAlarm = FALSE;

                                        /* Send SRQ packet to serial port   */
            writeServiceRequest(3, DUAL_VICOR_PSU_ERR_OFF_SRQ,
                 vicorBoard->IBC_Board.baseAddress, DUAL_VICOR_PSU1);
    } /* if */

} /* dualVicorCheckStatus() */

/****************************************************************************/
/* Function    : dualVicorBoardFunctions                                    */
/* Purpose     : Dual Vicor Board real-time loop functions                  */
/* Inputs      : Dual Vicor Board data structure                            */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
dualVicorFunctions( vicorBoardEntry *vicorBoard )
{
                                        /* Read & Filter PSU 0 Temperature  */
    if (IIRfilter( dualVicorPsuTemp( vicorBoard, DUAL_VICOR_PSU0),
                &vicorBoard->vicor[DUAL_VICOR_PSU0].filteredTemperature,
                &vicorBoard->vicor[DUAL_VICOR_PSU0].tempFilter ) == OK)

                                        /* Check PSU 0 temperature alarms   */
        dualVicorCheckTemperature(vicorBoard, DUAL_VICOR_PSU0);

    if (vicorBoard->psuConfig == DUAL_VICOR_TWO_MINI_MODS)
    {
                                        /* Read & Filter PSU 1 Temperature  */
        if (IIRfilter( dualVicorPsuTemp( vicorBoard, DUAL_VICOR_PSU1),
            &vicorBoard->vicor[DUAL_VICOR_PSU1].filteredTemperature,
            &vicorBoard->vicor[DUAL_VICOR_PSU1].tempFilter ) == OK)

                                          /* Check PSU 1 temperature alarms */
            dualVicorCheckTemperature(vicorBoard, DUAL_VICOR_PSU1);
    } /* if */

    dualVicorCheckStatus(vicorBoard);       /* Check Vicor PSU status       */
} /* dualVicorFunctions() */




