/****************************************************************************/
/* Copyright 1992, 1993 MBARI                                               */
/****************************************************************************/
/* Summary  : IBC Dual Vicor Board Data Manager Functions for VxWorks       */
/* Filename : vicor.c                                                       */
/* Author   : Andrew Pearce                                                 */
/* Project  : New ROV                                                       */
/* Version  : Version 1.0                                                   */
/* Created  : 06/10/93                                                      */
/* Modified : 06/10/93                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: /usr/tiburon/vw/ibc/lib/RCS/vicorDm.c,v 1.1 1998/02/09 19:29:31 oreilly Exp oreilly $
 * $Log: vicorDm.c,v $
 * Revision 1.1  1998/02/09 19:29:31  oreilly
 * Initial revision
 *
 * Revision 1.1  93/07/01  14:34:35  14:34:35  pean (Andrew Pearce)
 * Initial revision
 *
 *
 */
/****************************************************************************/

#include <vxWorks.h>                /* vxWorks system declarations          */
#include <semLib.h>                 /* vxWorks semaphore functions          */
#include <taskLib.h>                /* vxWorks task library functions       */
#include <wdLib.h>                  /* vxWorks watch dog timer functions    */
#include <systime.h>                /* vxWorks time and date functions      */
#include <msgQLib.h>                /* vxWorks Message Queue Library        */

#include <mbariTypes.h>             /* MBARI style guide type declarations  */
#include <mbariConst.h>             /* Miscellaneous MBARI constants        */

#include "sio32.h"                  /* SIO32 hardware and driver information*/
#include <sio32Server.h>            /* Sio32 server communication services  */
#include <sio32Client.h>            /* Sio32 client communication services  */
#include <powerTypes.h>             /* Power management Data Types          */
#include <powerDM.h>                /* Power/Switching Data Manager Items   */

#include <datamgr.h>                /* Data Manager declarations            */
#include <dm_errno.h>               /* Data Manager error declarations      */

#define Boolean MBool               /* Map microcontroller Boolean to MBool */

#include "microcmd.h"               /* Microcontroller commands             */
#include "ibc_card.h"               /* IBC Card Types                       */
#include "ibc_cmd.h"                /* IBC Serial Commands                  */
#include "filter.h"                 /* General Filter Routines              */
#include "vicor.h"                  /* Dual Vicor Board Definitions         */

#include "microDm.h"                /* Micro Data Manager Items & Functions */
#include "switch.h"                 /* IBC Function Libarary Definitions    */
#include "vicorDm.h"                /* Defines & Functions for vicorDm.c    */

/*****************************************************************************/
/* Function    : createIbcVicorDmItems                                       */
/* Purpose     : Initialize Data Manager Items for IBC Dual Vicor Board      */
/* Inputs      : Pointer to structure containing IBC Dual Vicor Items        */
/*               and IBC Data Concentrator Name                              */
/* Outputs     : None, but Data Manager Items change                         */
/*****************************************************************************/
    STATUS
createIbcVicorDmItems( vicorDmItems *vicorDm, const char *ibcDmPrefix,
    const char *ibcDataCon )
{
    Int32   item;                   /* Counter for DM Item Initialization   */
    Errno   status;                 /* Result of dm_create function call    */

    struct                          /* Data Manager Item Table for table    */
    {                               /* driven item initialization           */
        DM_Item *dmItem;            /* pointer to actual dm item handle     */
        char    *errorMsg;          /* Message to display of dmCreate fails */
        char    *name;              /* Data Manager Item Name               */
        DM_Type type;               /* Data Manager Item Type               */
        DM_Num  len;                /* Data Manager Item Element Count      */
    } vicorDmInit[] =

      { { &vicorDm[0].vicorTemperature, "Dual Vicor 0 Temperature",
              VICOR_PSU0_TEMP_DM,              DM_INT16, 1 },

        { &vicorDm[0].tempWarnThresh,   "Dual Vicor 0 Temp Warning",
              VICOR_PSU0_TEMP_WARN_THRESH_DM,  DM_INT16, 1 },

        { &vicorDm[0].tempAlarmThresh,  "Dual Vicor 0 Alarm Warning",
              VICOR_PSU0_TEMP_ALARM_THRESH_DM, DM_INT16, 1 },

        { &vicorDm[0].tempAlarm,        "Dual Vicor 0 Temp Alarm",
              VICOR_PSU0_TEMP_ALARM_DM,         DM_ENUM, 1 },

        { &vicorDm[0].psuErrorAlarm,    "Dual Vicor 0 Error Alarm",
              VICOR_PSU0_ERROR_ALARM_DM,        DM_MBOOL, 1 },


        { &vicorDm[1].vicorTemperature, "Dual Vicor 1 Temperature",
              VICOR_PSU1_TEMP_DM,              DM_INT16, 1 },

        { &vicorDm[1].tempWarnThresh,   "Dual Vicor 1 Temp Warning",
              VICOR_PSU1_TEMP_WARN_THRESH_DM,  DM_INT16, 1 },

        { &vicorDm[1].tempAlarmThresh,  "Dual Vicor 1 Alarm Warning",
              VICOR_PSU1_TEMP_ALARM_THRESH_DM, DM_INT16, 1 },

        { &vicorDm[1].tempAlarm,        "Dual Vicor 1 Temp Alarm",
              VICOR_PSU1_TEMP_ALARM_DM,        DM_ENUM, 1 },

        { &vicorDm[1].psuErrorAlarm,    "Dual Vicor 1 Error Alarm",
              VICOR_PSU1_ERROR_ALARM_DM,       DM_MBOOL, 1 },


        { NO_ITEM, NULL, NULL, DM_ENDT, 0 } };

                                    /* Clear list of Data Manager Item handles*/
    bzero(&vicorDm[0], sizeof(vicorDmItems));
    bzero(&vicorDm[1], sizeof(vicorDmItems));

                                   /* Initialize Data Manager Items from table*/
    for (item = 0; vicorDmInit[item].dmItem != NO_ITEM; item++)
    {
        if ((*vicorDmInit[item].dmItem =
             initMicroDmItem(ibcDmPrefix, vicorDmInit[item].name,
             vicorDmInit[item].type, vicorDmInit[item].len)) == ERROR)

        {                           /* Error occurred so print message & exit */
            logMsg("%s: Error Initializing %s DM Item\n",
                ibcDataCon, vicorDmInit[item].errorMsg);
            return(ERROR);
        } /* if */
    } /* for */

    return(OK);                     /* All IBC Dual Vicor DMgr items created  */
} /* createIbcVicorDmItems() */

    STATUS
ibcConnectVicorDmItems( vicorDmItems *vicor, switchEntry *device,
         const char *dataConName,    const char *itemName,   Nat16 vicorPsu,
         char *temperature,          char *temperatureAlarm,
         char *tempWarnThresh,       char *tempAlarmThresh )
{
                                    /* Temperature Data Manager Items         */
    if ( (device->temperatureDm = initMicroDmItem(POWER_DM_PREFIX,
          temperature, DM_INT16, 1)) == ERROR) return(ERROR);

                                    /* Temperature Warning Thresh Dm Item     */
    if ( (device->tempWarnThreshDm = initMicroDmItem(POWER_DM_PREFIX,
          tempWarnThresh, DM_INT16, 1)) == ERROR) return(ERROR);

                                    /* Temperature Alarm Thresh Dm Item       */
    if ( (device->tempAlarmThreshDm = initMicroDmItem(POWER_DM_PREFIX,
          tempAlarmThresh, DM_INT16, 1)) == ERROR) return(ERROR);

                                    /* Temperature Alarm Status Dm Item       */
    if ( (device->tempAlarmDm = initMicroDmItem(POWER_DM_PREFIX,
          temperatureAlarm, DM_ENUM, 1)) == ERROR) return(ERROR);


    if (vicorPsu == DUAL_VICOR_PSU0)
    {
        dm_connect(vicor[0].vicorTemperature,  device->temperatureDm);
        dm_connect(device->tempWarnThreshDm,   vicor[0].tempWarnThresh);
        dm_connect(device->tempAlarmThreshDm,  vicor[0].tempAlarmThresh);
        dm_connect(device->tempAlarmDm,        vicor[0].tempAlarm);
    } /* if */
    else
    {
        dm_connect(vicor[1].vicorTemperature,  device->temperatureDm);
        dm_connect(device->tempWarnThreshDm,   vicor[1].tempWarnThresh);
        dm_connect(device->tempAlarmThreshDm,  vicor[1].tempAlarmThresh);
        dm_connect(device->tempAlarmDm,        vicor[1].tempAlarm);
    } /* else */

    vicor[0].deviceSwitch = device; /* Save switchEntry ptr in hps struct so  */
    vicor[1].deviceSwitch = device; /* we can set switch state to POWER_ERROR */
                                    /* when a trip event occurs               */

    return(OK);
} /* ibcConnectVicorItems() */


    Void
initIbcVicorProvider( vicorDmItems *vicorItems, Period period )
{
    dm_start_provider(vicorItems[0].vicorTemperature, period);
    dm_start_provider(vicorItems[1].vicorTemperature, period);
} /* initIbcVicorProvider() */

    Void
initIbcVicorAlarmProvider( vicorDmItems *vicorItems )
{
    dm_start_provider(vicorItems[0].tempAlarm, DM_STATIC);
    dm_start_provider(vicorItems[0].psuErrorAlarm, DM_STATIC);

    dm_start_provider(vicorItems[1].tempAlarm, DM_STATIC);
    dm_start_provider(vicorItems[1].psuErrorAlarm, DM_STATIC);
} /* initIbcVicorAlarmProvider() */


    DWord
initIbcVicorConsumer( vicorDmItems *vicorItems, vicorUpdateBits *vicorBits,
               SEM_ID updateSem )
{
    DWord vicorGroup;

    vicorGroup = dm_create_group();    /* Create Data Manager Group for Vicor */

    dm_start_consumer(vicorItems[0].tempWarnThresh,  DM_STATIC, updateSem);
    dm_start_consumer(vicorItems[0].tempAlarmThresh, DM_STATIC, updateSem);

    dm_start_consumer(vicorItems[1].tempWarnThresh,  DM_STATIC, updateSem);
    dm_start_consumer(vicorItems[1].tempAlarmThresh, DM_STATIC, updateSem);

    dm_group_add_item(vicorGroup, vicorItems[0].tempWarnThresh,
         &vicorBits->psu0TempWarnBit );

    dm_group_add_item(vicorGroup, vicorItems[0].tempAlarmThresh,
         &vicorBits->psu0TempAlarmBit );

    dm_group_add_item(vicorGroup, vicorItems[1].tempWarnThresh,
         &vicorBits->psu1TempWarnBit );

    dm_group_add_item(vicorGroup, vicorItems[1].tempAlarmThresh,
         &vicorBits->psu1TempAlarmBit );

    return (vicorGroup);
} /* initIbcVicorConsumer() */

    STATUS
updateIbcVicorDm( sio32Chan *sio32DataChan, Word boardAddr,
    vicorDmItems *vicor )
{
    Int16 psu0VicorTemp, psu1VicorTemp;

    if (IBC_DualVicorGetTemperature( sio32DataChan, boardAddr,
        &psu0VicorTemp, &psu1VicorTemp) != OK)
        return (ERROR);

    writeDmItem(vicor[0].vicorTemperature, &psu0VicorTemp,
                        sizeof(psu0VicorTemp) );

    return (writeDmItem(vicor[1].vicorTemperature, &psu1VicorTemp,
                        sizeof(psu1VicorTemp) ));
} /* updateIbcVicorDm() */

    STATUS
updateIbcVicorAlarmsDm( sio32Chan *sio32DataChan, Word boardAddr,
    vicorDmItems *vicor )
{
    Word     alarm[4];
    ibcAlarm psu0TempAlarm, psu1TempAlarm;
    MBool    psu0ErrorAlarm,   psu1ErrorAlarm;

    if (IBC_DualVicorGetAlarmStatus( sio32DataChan, boardAddr,
        &alarm[0], &alarm[1], &alarm[2], &alarm[3]) != OK)
        return (ERROR);

    psu0TempAlarm  = (ibcAlarm) alarm[0];
    psu1TempAlarm  = (ibcAlarm) alarm[1];
    psu0ErrorAlarm = (ibcAlarm) alarm[2];
    psu1ErrorAlarm = (ibcAlarm) alarm[3];

                                    /* Write alarm status to Data Manager */
    writeDmItem(vicor[0].tempAlarm, &psu0TempAlarm, sizeof(psu0TempAlarm) );
    writeDmItem(vicor[1].tempAlarm, &psu1TempAlarm, sizeof(psu1TempAlarm) );

    writeDmItem(vicor[0].psuErrorAlarm, &psu0ErrorAlarm,
        sizeof(psu0ErrorAlarm) );

    return (writeDmItem(vicor[1].psuErrorAlarm, &psu1ErrorAlarm,
        sizeof(psu1ErrorAlarm) ));
} /* updateIbcVicorAlarmsDm() */

/*****************************************************************************/
/* Function    : updateIbcVicorDmItems                                       */
/* Purpose     : Reads Vicor Board parameters from IBC & update Data Manager */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : None, but Data Manager Items change                         */
/*****************************************************************************/
    Void
updateIbcVicorDmItems( sio32Chan *sio32DataChan, Word boardAddr,
                      vicorDmItems *vicor, const char *ibcDataCon )
{
    Int16 psu0TempWarn,  psu0TempAlarm;
    Int16 psu1TempWarn,  psu1TempAlarm;

    if (IBC_DualVicorGetTempThresh( sio32DataChan, boardAddr,
        &psu0TempWarn, &psu0TempAlarm, &psu1TempWarn, &psu1TempAlarm ) == ERROR)
        logMsg("%s: Error reading Vicor Board Temp Alarm Thresholds\n",
               ibcDataCon);

    urgentWriteDmItem( dm_get_connect(vicor[0].tempWarnThresh),
                      &psu0TempWarn,  sizeof(psu0TempWarn));

    urgentWriteDmItem( dm_get_connect(vicor[0].tempAlarmThresh),
                      &psu0TempAlarm,  sizeof(psu0TempAlarm));

    urgentWriteDmItem( dm_get_connect(vicor[1].tempWarnThresh),
                      &psu1TempWarn,  sizeof(psu1TempWarn));

    urgentWriteDmItem( dm_get_connect(vicor[1].tempAlarmThresh),
                      &psu1TempAlarm,  sizeof(psu1TempAlarm));

} /* updateIbcVicorDmItems() */

     Void
ibcVicorUpdateCheck( sio32Chan* sio32DataChan, Word boardAddr,
          vicorDmItems *vicorItems, vicorUpdateBits *vicorBits,
          DM_Group vicorGroup )
{
    DWord vicorGroupBits;           /* Holds dm_group_changes bit vector     */
    Int16 psu0TempWarn,  psu0TempAlarm;
    Int16 psu1TempWarn,  psu1TempAlarm;

                                    /* Ask Data Manager If Vicor items changed*/
    if ( (vicorGroupBits = dm_get_group_changes(vicorGroup)) == (DWord) 0)
        return;

    if ( (vicorGroupBits & vicorBits->psu0TempWarnBit)  ||
         (vicorGroupBits & vicorBits->psu0TempAlarmBit) ||
         (vicorGroupBits & vicorBits->psu1TempWarnBit)  ||
         (vicorGroupBits & vicorBits->psu1TempAlarmBit) )
    {
                                        /* Read Current Thresholds from dmgr*/
        dm_read( vicorItems[0].tempWarnThresh, (char *) &psu0TempWarn,
            sizeof(psu0TempWarn), (DM_Time *) NULL);

        dm_read( vicorItems[0].tempAlarmThresh, (char *) &psu0TempAlarm,
            sizeof(psu0TempAlarm), (DM_Time *) NULL);

        dm_read( vicorItems[1].tempWarnThresh, (char *) &psu1TempWarn,
            sizeof(psu1TempWarn), (DM_Time *) NULL);

        dm_read( vicorItems[1].tempAlarmThresh, (char *) &psu1TempAlarm,
            sizeof(psu1TempAlarm), (DM_Time *) NULL);

       IBC_DualVicorSetTempThresh( sio32DataChan, boardAddr,
            psu0TempWarn, psu0TempAlarm, psu1TempWarn, psu1TempAlarm );
    } /* if */

} /* ibcVicorUpdateCheck() */

    MBool
processIbcVicorSRQ( Word srqRequest, Byte *buffer, Word vicorBoardAddr,
                 vicorDmItems *vicor )
{
    Word boardAddr;                 /* IBC Board Address                      */
    Word psu;                       /* IBC Board Power Supply Unit Number     */
    Word status;                    /* IBC Alarm Status Word                  */
    ibcAlarm alarmStatus;           /* IBC Alarm Status                       */

    switch (srqRequest)
    {
        case DUAL_VICOR_PSU_ERR_ON_SRQ: /* Dual Vicor PSU Error Alarm On      */
            wordsFromBuf(buffer, 3, &srqRequest, &boardAddr, &psu);

            if ( (boardAddr != vicorBoardAddr) || (psu > DUAL_VICOR_MAX_PSU) )
                return(FALSE);          /* Address missmatch                 */

            writeBooleanDmItem(vicor[psu].psuErrorAlarm, TRUE);
            ibcSwitchPowerError(vicor[psu].deviceSwitch);
            break;

        case DUAL_VICOR_PSU_ERR_OFF_SRQ:/* Dual Vicor PSU Error Alarm Off     */
            wordsFromBuf(buffer, 3, &srqRequest, &boardAddr, &psu);

            if ( (boardAddr != vicorBoardAddr) || (psu > DUAL_VICOR_MAX_PSU) )
                return(FALSE);          /* Address missmatch                 */

            writeBooleanDmItem(vicor[psu].psuErrorAlarm, FALSE);
            break;

        case DUAL_VICOR_TEMP_ALARM_SRQ:
            wordsFromBuf(buffer, 4, &srqRequest, &status, &boardAddr, &psu);
            alarmStatus = (ibcAlarm) status;

            if ( (boardAddr != vicorBoardAddr) || (psu > DUAL_VICOR_MAX_PSU) )
                return(FALSE);          /* Address missmatch                 */

            writeDmItem(vicor[psu].tempAlarm, &alarmStatus,
                        sizeof(alarmStatus));

                                        /* Set Switch State to POWER_ERROR   */
            if (alarmStatus == MICRO_ALARM)
                ibcSwitchPowerError(vicor[psu].deviceSwitch);

            break;

        default:
            return(FALSE);              /* SRQ Request not recognized        */

    } /* switch */

    return(TRUE);                       /* SRQ Request recognized            */
} /* processIbcVicorSRQ() */

/****************************************************************************/
/* Function    : updateDualVicorPsu                                         */
/* Purpose     : Reads IBC Dual Vicor Board status & updates dmgr items     */
/* Inputs      : Sio32 chan & Dual Vicor Status status data manager items   */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateDualVicorPsu( sio32Chan *sio32DataChan, Word  boardAddr,
        DM_Item vicorPsu0State, DM_Item vicorPsu1State )
{
    MBool vicorStatus;              /* IBC Dual Vicor Board Status          */

    if (IBC_DualVicorGetStatus(sio32DataChan, boardAddr, DUAL_VICOR_PSU0,
         &vicorStatus) != OK) return(ERROR);

                                    /* Write actual PSU state to Dmgr       */
    if (writeDmItem(vicorPsu0State, &vicorStatus, sizeof(vicorStatus)) )
         return(ERROR);

    if (IBC_DualVicorGetStatus(sio32DataChan, boardAddr, DUAL_VICOR_PSU1,
         &vicorStatus) != OK) return(ERROR);

                                    /* Write actual PSU state to Dmgr       */
    return (writeDmItem(vicorPsu1State, &vicorStatus, sizeof(vicorStatus)) );
} /* updateDualVicorPsu() */










