/****************************************************************************/
/* Copyright 1992 to 1995 MBARI                                             */
/****************************************************************************/
/* Summary  : SIO32 Serial Diagnostic task for VxWorks                      */
/* Filename : sio32Diag.c                                                   */
/* Author   : Andrew Pearce                                                 */
/* Project  : Tiburon ROV SIO32 Board Microcontroller Interface             */
/* Version  : 1.0                                                           */
/* Created  : 10/14/92                                                      */
/* Modified : 09/12/95                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: sio32Diag.c,v 1.1 96/11/05 10:37:46 pean Exp $
 * $Log:        sio32Diag.c,v $
 * Revision 1.1  96/11/05  10:37:46  10:37:46  pean (Andrew Pearce)
 * Initial revision
 *
 */
/****************************************************************************/

#include <vxWorks.h>                /* vxWorks system declarations          */
#include <lstLib.h>                 /* vxWorks linked list library          */
#include <taskLib.h>                /* vxWorks task library functions       */
#include <wdLib.h>                  /* vxWorks watch dog timer functions    */
#include <semLib.h>                 /* vxWorks semaphore functions          */
#include <msgQLib.h>                /* vxWorks Message Queue Library        */
#include <timers.h>                 /* vxWorks Time/Timer functions         */

#include "mbariTypes.h"             /* mbari style guide type declarations  */
#include "mbariConst.h"             /* Miscellaneous constants              */
#include "ModNum.h"                 /* mbari module numbers for error code  */
#include "rovPriority.h"            /* mbari Rov Application Priorities     */
#include "usrTime.h"                /* mbari time and date functions        */
#include "datamgr.h"                /* Data Manager declarations            */
#include "sio32_card.h"             /* SIO32 Board hardware information     */

#include "sio32Drv.h"               /* SIO32 hardware and driver information*/
#include "sio32Server.h"            /* Sio32 server communication services  */
#include "sio32Client.h"            /* Sio32 client communication services  */

#include "applic.h"                 /* Microcontroller applications         */
#include "microdef.h"               /* Microcotnroller definitions          */
#include "microcmd.h"               /* Microcontroller commands             */
#include "sio32Micro.h"             /* SIO32 Microcontroller commands       */

#include "microCmd.h"               /* Microcontroller serial I/O functions */
#include "microDm.h"                /* Microcontroller Data Manager Items   */
#include "sio32Diag.h"              /* SIO32 Diagnostic Data Manager items  */

#define TEMP_DM_PERIOD      2000000 /* Temperature sensor provider period   */
#define PSU_DM_PERIOD        500000 /* PSU Status provider period           */

#define SIO32_IN_STACK         2000 /* SIO32 Diag Input Task size & TCB     */
#define SIO32_OUT_STACK        2000 /* SIO32 Diag Output Task size & TCB    */

#define PS2_RELAY        23         /* Relay number for PS2 Relay           */
#define PS1_GOOD_BIT     0x01       /* Bit mask for PS1_GOOD signal         */
#define PS2_GOOD_BIT     0x02       /* Bit mask for PS2_GOOD signal         */
#define PS3_GOOD_BIT     0x04       /* Bit mask for PS3_GOOD signal         */


#define SIO32_PORTS PORTS_PER_SIO32

typedef struct                      /* Thruster Data Manager Item Handles   */
{
    microDmItems microDm;           /* Microcontroller Data Manager Items   */

    DM_Item sio32PsuStatus;         /* SIO32 Board Power Supply Status      */
    DM_Item sio32RelayCtrl;         /* SIO32 Breakout Board Relay Control   */
    DM_Item serialStats[SIO32_PORTS];  /* Serial I/O statistics             */

    DM_Item microTemperature;       /* Temperature sensor value deg C       */
    DM_Item temperatureAlarm;       /* Temperature Alarm Detected TRUE/FALSE*/
    DM_Item tempWarnThresh;         /* Temperature Warning Threshold        */
    DM_Item tempAlarmThresh;        /* Temperature Alarm Threshold          */

    DM_Item localGfCurrent;         /* Local Ground Fault Current           */
    DM_Item localGndFaultAlarm;     /* Ground Fault Alarm Detected          */
    DM_Item gndFaultTestStatus;     /* Ground Fault Test Status             */
    DM_Item gndFaultTest;           /* Ground Fault Test Enable             */
    DM_Item gndFaultEnable;         /* Ground Fault Monitoring Enable       */
} sio32DiagDmItems;

/****************************************************************************/

Void sio32DiagInTask(Reg sio32DiagDmItems* dmItems, sio32Chan* sio32DataChan);

Void sio32DiagOutTask(Reg sio32DiagDmItems* dmItems, sio32Chan* sio32DataChan);

MLocal Void sio32DiagDmItemInit( sio32DiagDmItems* dmItems,
    sio32Chan* sio32DataChan);

MLocal Void sio32DiagWaitForSRQ( sio32DiagDmItems* dmItems, sio32Chan*
     sio32DataChan, Int32 sio32DiagInputTask, Int32 sio32DiagOutputTask );

MLocal MBool processSio32SRQ(Reg sio32DiagDmItems* dmItems,
     sio32Chan *sio32DataChan);

/****************************************************************************/
/* Function    : sio32DiagTask                                              */
/* Purpose     : Initializes communication with SIO32 Mezzanine Board micro */
/*               Provides interface between SIO32 Diagnostic Items and Data */
/*               Manager items.                                             */
/* Inputs      : SIO32 serial channel number for SIO32 Microcontroller      */
/* Outputs     : Normally runs forever, but returns ERROR on fatal error    */
/****************************************************************************/
    STATUS
sio32DiagTask( Nat16 sio32DiagSerialChan )
{
    sio32Chan sio32DataChan;        /* Serial chan for normal traffic       */
                                    /* to SIO32 server task on GMS Board    */

    MLocal sio32DiagDmItems dmItems;/* structure containing dm item handles */

    Int32   sio32DiagInputTask;     /* SIO32 micro Input Task Ident         */
    Int32   sio32DiagOutputTask;    /* SIO32 micro Output Task Ident        */

    Int32   chan;
    char    statName[32];

    dmItemList sio32DiagDmInit[] =  /* Data Manager Item Table for table    */

      { { &dmItems.microDm.resetEvent,     "Reset Event",
                MICRO_RESET_EVENT_DM,       DM_EMPTY, 1 },

        { &dmItems.microDm.resetCmd,       "Reset Command",
                MICRO_RESET_CMD_DM,         DM_EMPTY, 1 },

        { &dmItems.microDm.idString,       "Identification",
                MICRO_IDENT_DM,             DM_CHAR, MICRO_ID_LEN  },

        { &dmItems.microDm.serialNo,       "Micro Serial Number",
                MICRO_SERIAL_NO_DM,         DM_CHAR, MICRO_SERNO_LEN },

        { &dmItems.microDm.softwareRev,    "Software Revision",
                SOFTWARE_REV_DM,            DM_CHAR, SOFTWARE_REV_LEN },

        { &dmItems.microDm.ramTest,        "Micro RAM Test",
                RAM_TEST_STATUS_DM,         DM_MBOOL, 1 },

        { &dmItems.sio32PsuStatus,         "SIO32 PSU Status",
                SIO32_PSU_STATUS_DM,        DM_NAT16, 1 },

        { &dmItems.localGfCurrent,        "Local Ground Fault Current",
                LOCAL_GND_FLT_CURRENT_DM,   DM_INT16, 1 },

        { &dmItems.localGndFaultAlarm,     "Local Ground Fault Alarm",
                LOCAL_GND_FLT_ALARM_DM,     DM_ENUM, 1 },

        { &dmItems.gndFaultEnable,         "Ground Fault Enable",
                GND_FLT_ENABLE_DM,          DM_MBOOL, 1 },

        { &dmItems.gndFaultTest,           "Ground Fault Test Enable",
                GND_FLT_TEST_DM,            DM_MBOOL, 1 },

        { &dmItems.gndFaultTestStatus,     "Ground Fault Test Status",
                GND_FLT_TEST_STATUS_DM,     DM_ENUM, 1 },

        { &dmItems.microTemperature,       "Micro Temperature",
                TEMPERATURE_DM,             DM_INT16, 1 },

        { &dmItems.temperatureAlarm,       "Temperature Alarm",
                TEMPERATURE_ALARM_DM,       DM_ENUM, 1 },

        { &dmItems.tempWarnThresh,         "Temperature Warning Threshold",
                TEMP_WARN_THRESH_DM,        DM_INT16, 1 },

        { &dmItems.tempAlarmThresh,        "Temperature Alarm Threshold",
                TEMP_ALARM_THRESH_DM,       DM_INT16, 1 },

        { &dmItems.sio32RelayCtrl,         "SIO32 Relay Control",
                SIO32_RELAY_CONTROL_DM,     DM_NAT32, 1 },

        { NO_ITEM, NULL, NULL, DM_ENDT, 0 } };

                                    /* Initialize SIO32 diag serial channel  */
    if (sio32ChanInit(sio32DiagSerialChan, "/sio32/micro", &sio32DataChan)
        == ERROR)
    {
        logMsg("Error initializing SIO32 Diagnostic Serial Channel\n");
        return(ERROR);
    } /* if */

                                   /* Clear list of Data Manager Item handles*/
    bzero(&dmItems, sizeof(dmItems));

                                   /* Init Data Manager Items from table     */
    if (initMicroDmItemList(sio32DiagDmInit, SIO32_DM_PREFIX, "sio32Diag")
        != OK)
    {                              /* Error occurred so print message & exit */
        sio32ChanDestroy( sio32DiagSerialChan, &sio32DataChan );
        return(ERROR);
    } /* if */

    for (chan = 0; chan < SIO32_PORTS; chan++)
    {
        sprintf(statName, "%s%02d", SIO32_SERIAL_STATS_DM, chan);
        if ((dmItems.serialStats[chan] = initMicroDmItem(SIO32_DM_PREFIX,
             statName, DM_NAT32, 4)) == ERROR)
        {
            logMsg("sio32Diag: Error Initializing Statistics %d DM Item\n",
                   chan);
            return(ERROR);
        } /* if */
    } /* for */
                                    /* Provider for Static Data & Alarms     */
    dm_start_provider(dmItems.microDm.idString,    DM_STATIC);
    dm_start_provider(dmItems.microDm.serialNo,    DM_STATIC);
    dm_start_provider(dmItems.microDm.softwareRev, DM_STATIC);
    dm_start_provider(dmItems.microDm.resetEvent,  DM_STATIC);
    dm_start_provider(dmItems.microDm.ramTest,     DM_STATIC);

    dm_start_provider(dmItems.temperatureAlarm,    DM_STATIC);
    dm_start_provider(dmItems.localGndFaultAlarm,  DM_STATIC);
    dm_start_provider(dmItems.gndFaultTestStatus,  DM_STATIC);

                                    /* Initialize Static Data Manager Items  */
    sio32DiagDmItemInit( &dmItems, &sio32DataChan );

    if (( sio32DiagInputTask =      /* Start SIO32 Diagnostic Data Input Task*/
         taskSpawn("SIO32DiagIn", SIO32_DIAG_IN_PRIORITY, 0, SIO32_IN_STACK,
         (FUNCPTR) sio32DiagInTask, (int) &dmItems, (int) &sio32DataChan,
         0, 0, 0, 0, 0, 0, 0, 0 ) ) == ERROR)
    {
        sio32ChanDestroy( sio32DiagSerialChan, &sio32DataChan );
        logMsg("SIO32 Diag: Error spawning data input task\n");
        return(ERROR);
    } /* if */

    if (( sio32DiagOutputTask =     /* Start Sio32 Diagnostic Data Out Task  */
         taskSpawn("SIO32DiagOut", SIO32_DIAG_OUT_PRIORITY, 0, SIO32_OUT_STACK,
         (FUNCPTR) sio32DiagOutTask, (int) &dmItems, (int) &sio32DataChan,
         0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    {                               /* Delete SIO32 Diag Input Task          */
        taskDelete(sio32DiagInputTask);
                                    /* Close serial communication channel    */
        sio32ChanDestroy( sio32DiagSerialChan, &sio32DataChan );
        logMsg("SIO32 Diag: Error spawning data output task\n");
        return(ERROR);
   } /* if */

    FOREVER
    {
        sio32DiagWaitForSRQ( &dmItems, &sio32DataChan,
                 sio32DiagInputTask, sio32DiagOutputTask );

                                /* Re-initialize dm items when reset received*/
        sio32DiagDmItemInit( &dmItems, &sio32DataChan );

    } /* FOREVER */

    taskDelete(sio32DiagInputTask); /* Delete SIO32 Diagnostic Input Task    */
    taskDelete(sio32DiagOutputTask);/* Delete SIO32 Diagnostic Output Task   */

                                    /* Close serial communication channel    */
    sio32ChanDestroy( sio32DiagSerialChan, &sio32DataChan );

                        /* dm_stop_provider, dm_stop_consumer, etc are NOT   */
                        /* required when the task exits as the Data Manager  */
                        /* does this automatically when the task is deleted  */
                        /* via taskDeleteHookAdd() and dm_task_exit functions*/

    return(OK);         /* That's all folks                                  */
} /* sio32DiagTask() */

/****************************************************************************/
/* Function    : sio32GetTemperature                                        */
/* Purpose     : Returns temperature sensor reading from sio32 micro        */
/* Inputs      : Sio32 channel, pointer to temperature value                */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
sio32GetTemperature( sio32Chan *sio32DataChan, Word *temp )
{
    return (microCommand(sio32DataChan, SIO32_APP | GET_TEMPERATURE, temp));
} /* sio32GetTemperature() */

/****************************************************************************/
/* Function    : sio32GetTempAlarmThresh                                    */
/* Purpose     : Returns temperature alarm threshold from microcontroller   */
/* Inputs      : Sio32 channel, pointer to temp alarm threshold value       */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    STATUS
sio32GetTempAlarmThresh( sio32Chan *sio32DataChan,
        Int16 *tempWarn, Int16 *tempAlarm )
{
    Int16   cmdStatus;              /* Command Status                       */
    Word    reply[3];               /* Command Result from microcontroller  */

                                    /* Send command to microcontroller      */
    if ( sendMicroCommand( sio32DataChan, &reply, sizeof(Word) * 3,
         1, SIO32_APP | GET_TEMP_ALARM_THRESH ) == ERROR )
         return(ERROR);

                                    /* Check if command result is CMD OK    */
    if (wordFromBuf(&reply, 0) != CMD_OK)
        return(ERROR);              /* Command failed so return ERROR       */

                                    /* Command OK so update thresholds      */
    wordsFromBuf(reply, 3, &cmdStatus, tempWarn,  tempAlarm );

    return (OK);                    /* Return OK                            */
} /* sio32GetTempAlarmThresh() */

/****************************************************************************/
/* Function    : sio32GetTempAlarm                                          */
/* Purpose     : Returns temperature alarm status from sio32 microcontroler */
/* Inputs      : Sio32 channel, pointer to temperature alarm status         */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    STATUS
sio32GetTempAlarm( sio32Chan *sio32DataChan, microAlarm *tempAlarmStatus )
{
    Word alarmStatus;
                                /* Get Temperature Alarm Status from micro  */
    if (microCommand(sio32DataChan, SIO32_APP | GET_TEMP_ALARM_STATUS,
         &alarmStatus) !=OK) return(ERROR);

    *tempAlarmStatus = (microAlarm) alarmStatus;
    return(OK);
} /* sio32GetTempAlarm() */

/****************************************************************************/
/* Function    : updateMicroTempDm                                          */
/* Purpose     : Reads micro temperature sensor value & updates dmgr item   */
/* Inputs      : Sio32 chan & temperature sensor data manager item handle   */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateMicroTempDm( sio32Chan *sio32DataChan, DM_Item microTempDm )
{
    Int16   temperature;            /* Micro Temperature Sensor Value       */
                                    /* Read temperature sensor value        */
    if (sio32GetTemperature(sio32DataChan, (Word *) &temperature) != OK)
        return(ERROR);
                                    /* Write temperature to Data Manager    */
    return (writeDmItem(microTempDm, &temperature, sizeof(temperature)));
} /* updateMicroTempDm() */

/****************************************************************************/
/* Function    : updateTempAlarmDm                                          */
/* Purpose     : Reads micro temperature alarm status & updates dmgr item   */
/* Inputs      : Sio32 chan & temperature alarm data manager item handle    */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateTempAlarmDm( sio32Chan *sio32DataChan, DM_Item tempAlarmDm )
{
    microAlarm tempAlarmStatus;         /* Micro temperature alarm status   */
                                        /* Read temperature alarm status    */
    if (sio32GetTempAlarm(sio32DataChan, &tempAlarmStatus) != OK)
        return(ERROR);
                                        /* Write temperature alarm to Dmgr  */
    return(writeDmItem(tempAlarmDm, &tempAlarmStatus, sizeof(tempAlarmStatus)));
} /* updateTempAlarmDm() */

/****************************************************************************/
/* Function    : updateTempAlarm                                            */
/* Purpose     : Update temperature alarm DM item. Temperature updated also */
/*               so alarm status reflects state of temperature              */
/* Inputs      : Temp alarm status, serial chan, temp & temp alarm DM items */
/* Outputs     : None, but data manager items change                        */
/****************************************************************************/
     LOCAL Void
updateTempAlarm(sio32Chan *sio32DataChan, microAlarm tempAlarm,
                 DM_Item tempAlarmDm, Reg DM_Item temperatureDm)
{
                                /* Use urgent calls as task is not provider */
    dm_urgent_open(temperatureDm, DM_STATIC);
                                /* Read temperature and update Dmgr item    */
    updateMicroTempDm(sio32DataChan, temperatureDm);
    dm_urgent_close(temperatureDm);
                                /* Write temperature alarm to Dmgr          */
    writeDmItem(tempAlarmDm, &tempAlarm, sizeof(tempAlarm));
} /* updateTempAlarm() */

/****************************************************************************/
/* Function    : sio32SetTempAlarmThresh                                    */
/* Purpose     : Sets sio32 Temperature Alarm Threshold                     */
/* Inputs      : Sio32 channel, temperature alarm threshold                 */
/* Outputs     : Return OK or ERROR                                         */
/****************************************************************************/
    LOCAL STATUS
sio32SetTempAlarmThresh( Reg sio32Chan *sio32DataChan, Int16 tempWarn,
                        Int16 tempAlarm )
{
    Word    status;                 /* Command Result from microcontroller  */

                                    /* Send command to microcontroller      */
    if ( sendMicroCommand( sio32DataChan, &status, sizeof(status),
         3, SIO32_APP | SET_TEMP_ALARM_THRESH, tempWarn, tempAlarm )
         == ERROR ) return(ERROR);

                                    /* Check command result                 */
    return (wordFromBuf(&status, 0) == CMD_OK ? OK : ERROR);
} /* sio32SetTempAlarmThresh() */

/****************************************************************************/
/* Function    : initTempAlarmThreshDm                                      */
/* Purpose     : Read Temp Alarm Threshold and update data manager item     */
/* Inputs      : Sio32 channel, temp alarm threshold dm item handle         */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
initTempAlarmThreshDm ( sio32Chan *sio32DataChan, DM_Item tempWarnDm,
    DM_Item tempAlarmDm )
{
    Int16  tempWarn, tempAlarm;         /* Temp Alarm Threshold from micro  */

                                        /* Get Temp Alarm Thresh from micro */
    if (sio32GetTempAlarmThresh( sio32DataChan, &tempWarn, &tempAlarm ) != OK)
        return (ERROR);
                                        /* We MUST use urgent open here as  */
                                        /* another task is normal provider  */
    urgentWriteDmItem(tempWarnDm,  &tempWarn,  sizeof(tempWarn));
    urgentWriteDmItem(tempAlarmDm, &tempAlarm, sizeof(tempAlarm));

    return(OK);
} /* initTempAlarmThreshDm() */

/****************************************************************************/
/* Function    : writeTempAlarmThresh                                       */
/* Purpose     : Get temperature alarm threshold and send to sio32 micro    */
/* Inputs      : Sio32 channel, temperature alarm threshold                 */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
writeTempAlarmThresh( sio32Chan *sio32DataChan, DM_Item tempWarnDm,
                DM_Item tempAlarmDm )
{
    Int16   tempWarn, tempAlarm;        /* Temp Alarm Threshold from Dmgr   */
                                        /* Read Temp Alarm Thresh from dmgr */
    if (dm_read( tempWarnDm, (char *) &tempWarn,
         sizeof(tempWarn), (DM_Time *)NULL) == SUCCESS )

        if (dm_read( tempAlarmDm, (char *) &tempAlarm,
             sizeof(tempAlarm), (DM_Time *)NULL) == SUCCESS )
                                        /* Send value to motor micro        */
            if (sio32SetTempAlarmThresh( sio32DataChan, tempWarn, tempAlarm)
                == OK) return (OK);

    return(ERROR);
} /* writeTempAlarmThresh() */

/****************************************************************************/
/* Function    : sio32GetGndFltAlarm                                        */
/* Purpose     : Returns Groud Fault alarm status from sio32 microcontroler */
/* Inputs      : Sio32 channel, pointer to Ground Fault Alarm status        */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    MLocal STATUS
sio32GetGndFltAlarm( sio32Chan *sio32DataChan, gfStatus *gndFltAlarmStatus )
{
    Word gndFltStatus;
                                /* Get Ground Fault Alarm Status from micro*/
    if (microCommand(sio32DataChan, MICRO_APP | GET_GNDFLT_STATUS,
         &gndFltStatus) != OK) return(ERROR);

                                 /* Map to vxWorks ENUM definition         */
    *gndFltAlarmStatus = (gfStatus) gndFltStatus;

    return(OK);
} /* sio32GetGndFltAlarm() */

/****************************************************************************/
/* Function    : sio32GetGndFltTest                                         */
/* Purpose     : Returns Groud Fault test status from sio32 microcontroler  */
/* Inputs      : Sio32 channel, pointer to Ground Fault Test status         */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    MLocal STATUS
sio32GetGndFltTest( sio32Chan *sio32DataChan, gfTestStatus *gndFltTestStatus )
{
    Word gndFltTest;
                                 /* Get Ground Fault Test Status from micro*/
    if (microCommand(sio32DataChan, MICRO_APP | GET_GNDFLT_TEST,
         &gndFltTest) !=OK) return(ERROR);

                                 /* Map to vxWorks MBool definition        */
    *gndFltTestStatus = (gfTestStatus) gndFltTest;

    return(OK);
} /* sio32GetGndFltTest() */

/****************************************************************************/
/* Function    : updateGndFltAlarmDm                                        */
/* Purpose     : Reads Ground Fault alarm status & updates dmgr item        */
/* Inputs      : Sio32 chan & Ground Fault alarm data manager item handle   */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateGndFltAlarmDm( sio32Chan *sio32DataChan, DM_Item gndFltAlarmDm )
{
    gfStatus gfAlarmStatus;             /* Ground Fault alarm status        */

    if (sio32GetGndFltAlarm(sio32DataChan, &gfAlarmStatus) != OK)
        return(ERROR);
                                        /* Write Ground Fault alarm to Dmgr */
    return(writeDmItem(gndFltAlarmDm, &gfAlarmStatus, sizeof(gfAlarmStatus)));
} /* updateGndFltAlarmDm() */

/****************************************************************************/
/* Function    : updateGndFltTestDm                                         */
/* Purpose     : Reads Ground Fault Test status & updates dmgr item         */
/* Inputs      : Sio32 chan & Ground Fault test data manager item handle    */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateGndFltTestDm( sio32Chan *sio32DataChan, DM_Item gndFltTestDm )
{
    gfTestStatus gndFltTestStatus;      /* Ground Fault alarm status        */

    if (sio32GetGndFltTest(sio32DataChan, &gndFltTestStatus) != OK)
        return(ERROR);
                                        /* Write Ground Fault alarm to Dmgr */
    return(writeDmItem(gndFltTestDm, &gndFltTestStatus, sizeof(gfTestStatus)));
} /* updateGndFltTestDm() */

/****************************************************************************/
/* Function    : microSetGnsFltEnableState                                  */
/* Purpose     : Send command to Enable/Disable Ground Fault monitoring     */
/* Inputs      : Sio32 Serial Channel, GF enable state                      */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
microSetGndFltEnableState( sio32Chan *sio32DataChan, MBool gfEnable )
{
    Word    status;                 /* Command Result from microcontroller  */

                                    /* Send command to microcontroller      */
    if ( sendMicroCommand( sio32DataChan, &status, sizeof(status),
        2, SIO32_APP | SET_GNDFLT_ENABLE, gfEnable) == ERROR )
             return(ERROR);

                                    /* Check command result                  */
    return (wordFromBuf(&status, 0) == CMD_OK ? OK : ERROR);
} /* microSetGndFltEnableState() */

/****************************************************************************/
/* Function    : updateGndFltEnableDm                                       */
/* Purpose     : Reads Ground Fault Enable status & updates dmgr item       */
/* Inputs      : Sio32 chan & Ground Fault Enable data manager item handle  */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateGndFltEnableDm( sio32Chan *sio32DataChan, DM_Item gfEnableDm )
{
    Word  gfEnable;                     /* Ground Fault Enable status       */
    MBool gfEnableState;

    if (microCommand(sio32DataChan, SIO32_APP | GET_GNDFLT_ENABLE, &gfEnable)
       != OK) return(ERROR);

    gfEnableState = (MBool) gfEnable;   /* Map to vxWorks MBool definition  */

                                        /* Write Ground Fault Enable to Dmgr*/
    return(writeDmItem(gfEnableDm, &gfEnableState, sizeof(gfEnableState)));
} /* updateGndFltEnableDm() */

/****************************************************************************/
/* Function    : microWriteGndFaultEnable                                   */
/* Purpose     : Send command to enable/disable ground fault monitoring     */
/* Inputs      : Sio32 channel, gf Enable DM Item                           */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    STATUS
microWriteGndFaultEnable( sio32Chan *sio32Channel, DM_Item gfEnableDm)
{
    Errno   status;                 /* Result of dm_read                    */
    Word    cmdStatus;              /* Command Result from microcontroller  */
    MBool   gfEnableState;          /* Ground Fault Enable State            */

                                    /* Read Desired State from dm           */
    if (dm_read( gfEnableDm, (char *) &gfEnableState, sizeof(gfEnableState),
        (DM_Time *) NULL) == SUCCESS)
                                    /* Send command to microcontroller      */
        if (microSetGndFltEnableState(sio32Channel, gfEnableState) == OK)
            return (OK);
    return(ERROR);
} /* microWriteGndFaultEnable() */

/****************************************************************************/
/* Function    : microInitGndFaultEnable                                    */
/* Purpose     : Send command to enable/disable ground fault monitoring     */
/* Inputs      : Sio32 channel, gf Enable DM Item                           */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    STATUS
microInitGndFaultEnable( sio32Chan *sio32Channel, DM_Item gfEnableDm,
   MBool gfEnableState)
{
    urgentWriteDmItem(gfEnableDm, &gfEnableState, sizeof(gfEnableState));

                                    /* Send command to microcontroller      */
    return (microSetGndFltEnableState(sio32Channel, gfEnableState));
} /* microInitGndFaultEnable() */

/****************************************************************************/
/* Function    : microGetGndFltCurrents                                     */
/* Purpose     : Returns Groud Fault current measurements from micro        */
/* Inputs      : Sio32 channel, pointer to local current                    */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    MLocal STATUS
microGetGndFltCurrent( sio32Chan *sio32DataChan, Int16 *localGfCurrent)
{
    Int16 cmdStatus;                /* Command Status                       */
    Word  reply[2];                 /* Command Result from microcontroller  */
    Word  localGf;

                                    /* Get Ground Fault Currents from micro */
                                    /* Send command to microcontroller      */
    if ( sendMicroCommand( sio32DataChan, &reply, sizeof(Word) * 2,
         1, MICRO_APP | GET_GNDFLT_VALUE ) == ERROR )
        return(ERROR);
                                    /* Check if command result is CMD OK    */
    if (wordFromBuf(&reply, 0) != CMD_OK)
        return(ERROR);              /* Command failed so return ERROR       */

                                    /* Command OK so update GF current      */
    wordsFromBuf(reply, 2, &cmdStatus, &localGf);
    *localGfCurrent = (Int16) localGf;

    return(OK);
} /* microGetGndFltCurrents() */

/****************************************************************************/
/* Function    : updateGndFltCurrentDm                                      */
/* Purpose     : Reads Ground Fault current & updates dmgr items            */
/* Inputs      : Sio32 chan & Ground Fault current item handle              */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateGndFltCurrentDm( sio32Chan *sio32DataChan, DM_Item localGfCurrentDm)
{
    Int16 localGfCurrent;               /* Local Ground Fault Current       */

    if (microGetGndFltCurrent(sio32DataChan, &localGfCurrent) != OK)
       return(ERROR);
                                        /* Write Ground Fault current to DM */
    writeDmItem(localGfCurrentDm, &localGfCurrent, sizeof(localGfCurrent));
    return (OK);
} /* updateGndFltCurrentDm() */

/****************************************************************************/
/* Function    : sio32SetRelayState                                         */
/* Purpose     : Send command to set state of SIO32 board relays            */
/* Inputs      : Telem Serial Channel, relay control word                   */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
sio32SetRelayState( sio32Chan *sio32DataChan, DWord relayCtrl )
{
    Word    status;                 /* Command Result from microcontroller  */

                                    /* Send command to microcontroller      */
    if ( sendMicroCommand( sio32DataChan, &status, sizeof(status),
        3, SIO32_APP | SET_RELAY_STATE,
        (relayCtrl >> 16) & 0xffff, relayCtrl & 0xffff) == ERROR )
             return(ERROR);

                                    /* Check command result                  */
    return (wordFromBuf(&status, 0) == CMD_OK ? OK : ERROR);
} /* sio32SetRelayControl() */

/****************************************************************************/
/* Function    : testSio32PowerSupply                                       */
/* Purpose     : Tests sio32 breakout board power supplies & updates dmgr   */
/* Inputs      : Sio32 micro Serial Channel                                 */
/* Outputs     : Returns SIO32 Board PSU Status Word                        */
/****************************************************************************/
    LOCAL Nat16
testSio32PowerSupply( sio32Chan *sio32DataChan )
{
    Nat16  psuStatus;               /* sio32 PSU Status Word                */

                                    /* Read PSU Status Word                 */
    if ( (psuStatus = (Nat16) getSio32PSStatus(GMS_BOARD))
        == (Nat16) ERROR) return(0);/* Assume all power supplies are bad    */


    if (psuStatus & (PS1_GOOD_BIT | PS2_GOOD_BIT) !=
        (PS1_GOOD_BIT | PS2_GOOD_BIT))
        return (psuStatus);         /* Power Supply 1 or 2 is bad           */

                                    /* Open all relays on breakout board    */
    if (sio32SetRelayState(sio32DataChan, 0xffffffff) != OK)
        return (psuStatus);         /* Relays failed to open                */

    taskDelay(1);                   /* Wait for relays to open              */

                                    /* Read PSU Status Word                 */
    if ( (psuStatus = (Nat16) getSio32PSStatus(GMS_BOARD))
        == (Nat16) ERROR) return(PS1_GOOD_BIT | PS2_GOOD_BIT);

                                    /* Close all relays on breakout board   */
    sio32SetRelayState(sio32DataChan, 0);

    if (~psuStatus & PS2_GOOD_BIT)  /* Relays opened so PS3 is good         */
        psuStatus |= PS3_GOOD_BIT;  /* Add PS2 & PS3 GOOD flag to bit mask  */

    psuStatus |= PS2_GOOD_BIT;      /* Add PS2 GOOD flag to bit mask        */

    return (psuStatus);
} /* testSio32PSUStatusDm() */

/****************************************************************************/
/* Function    : updateSio32PSUStatusDm                                     */
/* Purpose     : Reads SIO32 PSU Status & updates dmgr item                 */
/* Inputs      : Sio32 PSU status data manager item                         */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateSio32PSUStatusDm( DM_Item sio32PsuStatusDm )
{
    Nat16  psuStatus;               /* SIO32 PSU Status Word                */
    Nat16  oldStatus;               /* Previous PSU Status                  */
                                    /* Read PSU Status Word                 */
    if ( (psuStatus = (Nat16) getSio32PSStatus(GMS_BOARD))
        == (Nat16) ERROR) return(ERROR);
                                    /* Read previous status vaule           */
    if (dm_read(sio32PsuStatusDm, &oldStatus, sizeof(oldStatus),
                (DM_Time *)NULL) != SUCCESS )
        return (ERROR);
                                    /* Carry through PS3_GOOD_BIT           */
    psuStatus |= (oldStatus & PS3_GOOD_BIT);

    if (psuStatus == oldStatus)     /* Don't write Data Manager if no change*/
        return (OK);
                                    /* Write to Data Manager                */
    return (writeDmItem(sio32PsuStatusDm, &psuStatus, sizeof(psuStatus)));
} /* updateSio32PSUStatusDm() */

/****************************************************************************/
/* Function    : initSio32PSUStatusDm                                       */
/* Purpose     : Read SIO32 PSU Status and update data manager item         */
/* Inputs      : Sio32 serial channel, PSU status dm item handle            */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
initSio32PSUStatusDm ( sio32Chan *sio32DataChan, DM_Item sio32PsuStatusDm )
{
    Nat16  psuStatus;               /* SIO32 PSU Status Word                */

    if ( (psuStatus = (Nat16) getSio32PSStatus(GMS_BOARD)) == (Nat16) ERROR)
        return(ERROR);

                                    /* We MUST use urgent open here as      */
                                    /* another task is normal provider      */
    return (urgentWriteDmItem(sio32PsuStatusDm, &psuStatus, sizeof(psuStatus)));
} /* initSio32PSUStatusDm() */

/****************************************************************************/
/* Function    : updateSio32SerialStatsDm                                   */
/* Purpose     : Reads SIO32 Serial I/O Statistics & updates dmgr items     */
/* Inputs      : Channel number and Data Manager item handle                */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateSio32SerialStatsDm( Nat16 chan, DM_Item sio32SerialStatsDm )
{
    pktStat  serialStats;

    if ((getSio32Statistics(GMS_BOARD | chan, &serialStats)) == ERROR)
        return(ERROR);
                                    /* Write to Data Manager                */
    return (writeDmItem(sio32SerialStatsDm, &serialStats,
         sizeof(serialStats)));
} /* updateSio32SerialStatsDm() */

/****************************************************************************/
/* Function    : initSio32RelayStateDm                                      */
/* Purpose     : Read SIO32 Relay State and update data manager item        */
/* Inputs      : Sio32 channel, relay state dm item handle                  */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
initSio32RelayStateDm ( sio32Chan *sio32DataChan, DM_Item relayCtrlDm )
{
    DWord  relayCtrl;               /* Relay control word                   */
    Word   relayHigh, relayLow;     /* Relay Control Word High & Low        */
    Int16  cmdStatus;               /* Command Status                       */
    Word   reply[3];                /* Command Result from microcontroller  */

                                    /* Get Relay Ctrl Words from micro      */
    if ( sendMicroCommand( sio32DataChan, &reply, sizeof(Word) * 3,
         1, SIO32_APP | GET_RELAY_STATE ) == ERROR )
         return(ERROR);

                                    /* Check if command result is CMD OK    */
    if (wordFromBuf(&reply, 0) != CMD_OK)
        return(ERROR);              /* Command failed so return ERROR       */

                                    /* Command OK so extract relay words    */
    wordsFromBuf(reply, 3, &cmdStatus, &relayHigh,  &relayLow );

                                    /* Convert to a 32 bit wide word        */
    relayCtrl = ((DWord) relayHigh << 16) | relayLow;

                                    /* We MUST use urgent open here as      */
                                    /* another task is normal provider      */
    return (urgentWriteDmItem(relayCtrlDm, &relayCtrl, sizeof(relayCtrl)));
} /* initSio32RelayStateDm() */

/****************************************************************************/
/* Function    : sio32SetRelayControlCmd                                    */
/* Purpose     : Sets sio32 Relay Control bit vector                        */
/* Inputs      : Sio32 channel, relay control DM item handle                */
/* Outputs     : Return OK or ERROR                                         */
/****************************************************************************/
    LOCAL STATUS
sio32SetRelayControlCmd( Reg sio32Chan *sio32DataChan, DM_Item relayCtrlDm )
{
    Word    status;                 /* Command Result from microcontroller  */
    DWord   relayCtrl;              /* Relay control word                   */

    if (dm_read( relayCtrlDm, (char *) &relayCtrl,
             sizeof(relayCtrl), (DM_Time *) NULL) != SUCCESS )
        return (ERROR);

#if 0
    relayCtrl = relayCtrl << 1;     /* Temporary fix until sio32 micro is   */
                                    /* updated. 1st Feb 1996 pean/audo      */
#endif
                                    /* Send command to microcontroller      */
    return (sio32SetRelayState(sio32DataChan, relayCtrl));
} /* sio32SetRelayControlCmd() */

/*****************************************************************************/
/* Function    : sio32DmItemInit                                             */
/* Purpose     : Reads parameters from SIO32 & update Data Manager items     */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : None, but Data Manager Items change                         */
/*****************************************************************************/
    Void
sio32DiagDmItemInit( sio32DiagDmItems* dmItems, sio32Chan* sio32DataChan )
{
    Int16 trys;
    Int16 gfStatus;
                                /* Send Command Enable Command to SIO32 Micro*/
    for (trys = 0; ((microCmdEnable(sio32DataChan) == ERROR) &&
         trys < MICRO_ENABLE_TRYS); trys++)
         taskDelay(sysClkRateGet() / 5);

    if (trys == MICRO_ENABLE_TRYS)
        logMsg("SIO32 Diag: Error Enabling SIO32 Diag Microcontroller\n");

                                /* Set Micro Identification initial value    */
    if (updateMicroIdentDm(sio32DataChan, dmItems->microDm.idString) == ERROR)
        logMsg("SIO32 Diag: Error reading Identification String\n");

                                /* Set Micro Serial Number initial value     */
    if (updateSerialNoDm(sio32DataChan, dmItems->microDm.serialNo) == ERROR)
        logMsg("SIO32 Diag: Error reading Micro Serial Number\n");

                                /* Set Software Revision initial value       */
    if (updateSoftwareRevDm(sio32DataChan, dmItems->microDm.softwareRev)
        == ERROR) logMsg("SIO32 Diag: Error reading Software Revision\n");

                                /* Set Micro Ram Test Result value           */
    if (updateMicroRamTestDm(sio32DataChan, dmItems->microDm.ramTest) == ERROR)
        logMsg("SIO32 Diag: Error checking micro RAM Test\n");

                                /* Set Micro Temperature Alarm initial value */
    if (updateTempAlarmDm(sio32DataChan, dmItems->temperatureAlarm) == ERROR)
        logMsg("SIO32 Diag: Error checking temperature alarm status\n");

                                /* Set Micro Ground Fault Alarm initial value*/
    if (updateGndFltAlarmDm(sio32DataChan, dmItems->localGndFaultAlarm)
        == ERROR)
        logMsg("SIO32 Diag: Error checking Ground Fault alarm status\n");

    if (updateGndFltTestDm(sio32DataChan, dmItems->gndFaultTestStatus)
        == ERROR)
       logMsg("SIO32 Diag: Error checking Ground Fault Circuit Test status\n");

} /* sio32DiagDmItemInit() */

/*****************************************************************************/
/* Function    : sio32DiagWaitForSRQ                                         */
/* Purpose     : Waits for Service Rquest Packet from SIO32 microcontroller  */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/*               task Id's for SIO32 Diag Input and Output Tasks             */
/* Outputs     : Data Manager Items change & tasks states are modified       */
/*****************************************************************************/
    MLocal Void
sio32DiagWaitForSRQ( sio32DiagDmItems* dmItems, sio32Chan* sio32DataChan,
    Int32 sio32InputTask, Int32 sio32OutputTask )
{
    taskResume(sio32InputTask);     /* Resume SIO32 Diag input & output tasks*/
    taskResume(sio32OutputTask);

    while (!processSio32SRQ(dmItems, sio32DataChan));
                                    /* Repeat until a reset event occurs     */
                                    /* Wait for Service Requests from micro  */

                                    /* We recevied a reset SRQ from the micro*/
                                    /* Wait for In & Out tasks to complete   */
                                    /* any outstanding communications by     */
                                    /* taking the mutual exclusion semaphore */
    semTake(sio32DataChan->mutexSem, WAIT_FOREVER);

    taskSuspend(sio32InputTask);    /* It's now safe to suspend In/Out tasks */
    taskSuspend(sio32OutputTask);

                                    /* Post Reset Event Data Manager Item    */
    microResetEventDm(dmItems->microDm.resetEvent);

    taskDelay(sysClkRateGet() / 3); /* Wait 300 msec for traffic to stop     */
                                    /* Release serial chan mutual exclusion  */
    semGive(sio32DataChan->mutexSem);
} /* sio32DiagWaitForSRQ() */

/*****************************************************************************/
/* Function    : sio32DiagOutTask                                            */
/* Purpose     : Thruster Output Task. Read DM items and write them to SIO32 */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : Normally runs forever, but exits if error occurs            */
/*****************************************************************************/
    Void
sio32DiagOutTask(Reg sio32DiagDmItems *dmItems, Reg sio32Chan *sio32DataChan)
{
    DM_Group dmGroup;               /* SIO32 Diag Data Manager Group         */
    SEM_ID  dmUpdateSem;            /* Data Manager Item Change wakeup sem   */
    SEM_ID  powerReqSem;            /* Power Request Update Semaphore        */

    DWord   sio32GroupBits;         /* Holds dm_group_changes bit vector     */

    DWord   resetEventBit;          /* Microcontroller reset event  bit      */
    DWord   resetCmdBit;            /* Microcontroller reset item changed bit*/
    DWord   gndFltTestBit;          /* Ground Fault test item changed bit    */
    DWord   gndFltEnableBit;        /* Ground Fault Enable item changed bit  */
    DWord   tempWarnBit;            /* Temp warning threshold item change bit*/
    DWord   tempAlarmBit;           /* Temp alarm threshold item changed bit */
    DWord   relayControlBit;        /* Sio32 Relay Control item changed bit  */

    Word    sio32PsuStatus;         /* sio32 breakout board PSU Status       */

                                    /* Create switch & power sync semaphores */
    if ( ((dmUpdateSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL) ||
         ((powerReqSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL) )
    {
        logMsg("SIO32 Diag: Error initializing Input Task Resources\n");
        return;
    } /* if */
                                    /* Declare this task a consumer of items */
                                    /* which are written to the SIO32 micro  */
    dm_start_consumer(dmItems->microDm.resetEvent, DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->microDm.resetCmd,   DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->gndFaultTest,       DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->gndFaultEnable,     DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->tempWarnThresh,     DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->tempAlarmThresh,    DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->sio32RelayCtrl,     DM_STATIC, dmUpdateSem);

    dmGroup = dm_create_group();    /* Create Data Manager Group for items   */

    dm_group_add_item(dmGroup, dmItems->microDm.resetEvent, &resetEventBit);
    dm_group_add_item(dmGroup, dmItems->microDm.resetCmd,   &resetCmdBit);
    dm_group_add_item(dmGroup, dmItems->gndFaultTest,       &gndFltTestBit);
    dm_group_add_item(dmGroup, dmItems->gndFaultEnable,     &gndFltEnableBit);
    dm_group_add_item(dmGroup, dmItems->tempWarnThresh,     &tempWarnBit);
    dm_group_add_item(dmGroup, dmItems->tempAlarmThresh,    &tempAlarmBit);
    dm_group_add_item(dmGroup, dmItems->sio32RelayCtrl,     &relayControlBit);

    FOREVER
    {                               /* Reset received so set Data Manager to */
                                    /* reflect hardware state                */
        microInitGndFaultEnable(sio32DataChan, dmItems->gndFaultEnable, ON);
        microWriteGndFaultTest(sio32DataChan,   dmItems->gndFaultTest);

        initTempAlarmThreshDm( sio32DataChan, dmItems->tempWarnThresh,
                                  dmItems->tempAlarmThresh );

        initSio32RelayStateDm( sio32DataChan, dmItems->sio32RelayCtrl );

                                    /* Power up test of breakout board PSU's */
        sio32PsuStatus = testSio32PowerSupply(sio32DataChan);
        urgentWriteDmItem(dmItems->sio32PsuStatus, &sio32PsuStatus,
            sizeof(sio32PsuStatus));

                                    /* Clear data manager item changed bits  */
        sio32GroupBits = dm_get_group_changes(dmGroup);

        FOREVER                     /* Repeat until micro controller reset   */
        {                           /* Wait for any data items to change     */
            semTake(dmUpdateSem, WAIT_FOREVER);

                                    /* Ask Data Manager which items changed  */
            sio32GroupBits = dm_get_group_changes(dmGroup);

                                    /* Check if micro Reset Event occurred   */
            if (sio32GroupBits & resetEventBit)
                break;              /* Exit loop and re-initialize DM items  */

            taskSafe();             /* Prevent task from being deleted during*/
                                    /* serial IO and Data Manager updates    */

            if (sio32GroupBits & gndFltEnableBit)
               microWriteGndFaultEnable(sio32DataChan, dmItems->gndFaultEnable);

            if (sio32GroupBits & gndFltTestBit)
               microWriteGndFaultTest(sio32DataChan, dmItems->gndFaultTest);

                                    /* Send Set Temp Warn/Alarm Threshold Cmd*/
            if ( (sio32GroupBits & tempWarnBit) ||
                 (sio32GroupBits & tempAlarmBit))
                writeTempAlarmThresh(sio32DataChan, dmItems->tempWarnThresh,
                                     dmItems->tempAlarmThresh);

                                    /* Check if Relay Control item changed   */
            if (sio32GroupBits & relayControlBit)
                                    /* Send Relay Control Command to Micro   */
               sio32SetRelayControlCmd(sio32DataChan, dmItems->sio32RelayCtrl);

                                    /* Check for Reset Command request       */
            if (sio32GroupBits & resetCmdBit)
                                    /* Send Reset Command to Microcontroller */
                microResetCmd(sio32DataChan);

            taskUnsafe();           /* Task may now be safely deleted        */

        } /*  FOREVER */
    } /* FOREVER */

                       /* dm_stop_provider, dm_stop_consumer, dm_delete_group*/
                       /* etc are NOT required when the task exits as the    */
                       /* Data Manager does this automatically when the task */
                       /* is deleted via the taskDeleteHookAdd() and         */
                       /* dm_task_exit functions.                            */

                        /* That's all folks !                                 */

} /* sio32DiagOutTask() */

/*****************************************************************************/
/* Function    : sio32DiagInTask                                             */
/* Purpose     : SIO32 Diagnostic Input Task. Wakes up periodically, read    */
/*               data from the SIO32 Diag and write Data Manager Items       */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : Normally runs forever, but exits if error occurs            */
/*****************************************************************************/
    Void
sio32DiagInTask(Reg sio32DiagDmItems* dmItems, sio32Chan* sio32DataChan)
{
    SEM_ID  wakeupSem;              /* Used wake up this task periodically   */
    Int32   updates = 0;            /* Counts dm updates for rate calculation*/
    Int32   chan;
                                    /* Create wakeup semaphore and watch dog */
                                    /* timer for provider rate control       */
    if ( (wakeupSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL)
    {
        logMsg("SIO32 Diag: Error initializing Input Task Resources\n");
        return;
    } /* if */
                                    /* Provider Task for non-static items    */
    dm_start_provider(dmItems->microTemperature, TEMP_DM_PERIOD);
    dm_start_provider(dmItems->localGfCurrent,   PSU_DM_PERIOD);
    dm_start_provider(dmItems->sio32PsuStatus,   PSU_DM_PERIOD);
    dm_start_consumer(dmItems->sio32PsuStatus,   PSU_DM_PERIOD, SEM_NULL);

                                    /* Provider task for SIO32 Statistics    */
    for (chan = 0; chan < SIO32_PORTS; chan++)
        dm_start_provider(dmItems->serialStats[chan],
            PSU_DM_PERIOD * SIO32_PORTS);

                                    /* Update Rate is not guaranteed due to  */
                                    /* the possibility of task preemption    */

    chan = 0;                       /* Start gathering statistics for chan 0 */

    FOREVER
    {
        taskSafe();                 /* Prevent task from being deleted during*/
                                    /* serial IO and Data Manager updates    */

                                    /* update data manager items we provide  */
        if ((++updates % (TEMP_DM_PERIOD / PSU_DM_PERIOD)) == 0)
        {
            updates = 0;
            updateMicroTempDm(sio32DataChan, dmItems->microTemperature);
        } /* if */
                                    /* Update Ground Fault Current           */
        updateGndFltCurrentDm(sio32DataChan, dmItems->localGfCurrent);

                                    /* Check Power Supply Status             */
        updateSio32PSUStatusDm(dmItems->sio32PsuStatus);

                                    /* Update serial statistics for next chan*/
        updateSio32SerialStatsDm(chan, dmItems->serialStats[chan]);
        if (++chan >= SIO32_PORTS)
           chan = 0;

        taskUnsafe();               /* Task may now be deleted safely        */

                                    /* Pend until sem timeout wakes us up    */
        semTake(wakeupSem, sysClkRateGet() / (USECS_PER_SEC / PSU_DM_PERIOD));
    } /* FOREVER */

    semDelete(wakeupSem);           /* semaphore resources                   */


                       /* dm_stop_provider, dm_stop_consumer, dm_delete_group*/
                       /* etc are NOT required when the task exits as the    */
                       /* Data Manager does this automatically when the task */
                       /* is deleted via the taskDeleteHookAdd() and         */
                       /* dm_task_exit functions.                            */

                       /* That's all folks !                                 */
} /* sio32DiagInTask() */

/*****************************************************************************/
/* Function    : processSio32SRQ                                             */
/* Purpose     : Decode Service Request and take appropriate action          */
/* Inputs      : SRQ code, array of DM items, serial channel                 */
/* Outputs     : Returns Reset Status & many DM items are changed            */
/*****************************************************************************/
    LOCAL MBool
processSio32SRQ( Reg sio32DiagDmItems* dmItems, sio32Chan *sio32DataChan)
{
    Word srqRequest;                /* Service Request Value                 */
    Word tempAlarm;                 /* Sio32 Alarm Status Word               */
    Word alarmStatus;               /* Microcontroller Alarm Status Word     */
    gfStatus   gfAlarm;             /* Ground Fault Alarm Status             */
    gfTestStatus gfTest;            /* Ground Fault Test Status              */
    Byte buffer[SRQ_PACKET_LEN];    /* Buffer for micro communications data  */

                                    /* Block on Reading Service Request      */
    if (readSRQPacket(sio32DataChan, buffer, SRQ_PACKET_LEN,
            sio32DataChan->timeout) != ERROR)
    {                               /* Service Request received so process it*/
        srqRequest = wordFromBuf(buffer, 0);

        switch (srqRequest)         /* Decode Service Request from micro     */
        {
        case MICRO_RESET_SRQ:       /* Microcontroller Reset Occurred        */
            return(TRUE);           /* Return Reset Received Status          */
            break;

        case TEMP_ALARM_ON:         /* Temperature Alarm Status Change       */
            wordsFromBuf(buffer, 2, &srqRequest, &tempAlarm);

                                        /* Update Temperature & Alarm Status */
            updateTempAlarm(sio32DataChan, (microAlarm) tempAlarm,
                dmItems->temperatureAlarm, dmItems->microTemperature);
            break;

        case GF_TEST_STATUS_SRQ:
            wordsFromBuf(buffer, 2, &srqRequest, &alarmStatus);
            gfTest= (gfTestStatus) alarmStatus;
            writeDmItem(dmItems->gndFaultTestStatus, &gfTest, sizeof(gfTest));
            break;

        case LOCAL_GNDFLT_SRQ:
            wordsFromBuf(buffer, 2, &srqRequest, &alarmStatus);
            gfAlarm = (gfStatus) alarmStatus;
            writeDmItem(dmItems->localGndFaultAlarm, &gfAlarm,
                sizeof(gfAlarm));
            break;

        default:
            printf("SIO32 Diag: Unrecognized Service Request 0x%x\n",
                 srqRequest);
        } /* switch */

    } /* if */

    return(FALSE);                      /* Return Reset Received Status      */
} /* processSio32SRQ() */
