/****************************************************************************/
/* Copyright 1995 to 1998 MBARI                                             */
/****************************************************************************/
/* Summary  : AC Can Microcontroller Interface Module for VxWorks           */
/* Filename : acMicro.c                                                     */
/* Author   : Andrew Pearce                                                 */
/* Project  : Tiburon                                                       */
/* Version  : Version 1.0                                                   */
/* Created  : 03/24/95                                                      */
/* Modified : 04/29/98                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: acMicro.c,v 1.1 95/03/27 16:14:21 pean Exp $
 * $Log:        acMicro.c,v $
 * Revision 1.1  95/03/27  16:14:21  16:14:21  pean (Andrew Pearce)
 * Initial revision
 *
 */
/****************************************************************************/

#include <vxWorks.h>                /* vxWorks system declarations          */
#include <stdio.h>                  /* vxWorks standard IO file functions   */
#include <semLib.h>                 /* vxWorks semaphore functions          */
#include <taskLib.h>                /* vxWorks task library functions       */
#include <lstLib.h>                 /* vxWorks linked list library          */
#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 constants              */

#include <rovPriority.h>            /* MBARI Rov Application Priorities     */
#include <usrTime.h>                /* MBARI time and date functions        */

#include <datamgr.h>                /* Data Manager declarations            */
#include <dm_errno.h>               /* Data Manager error declarations      */

#include "sio32.h"                  /* SIO32 hardware and driver information*/
#include "sio32Server.h"            /* Sio32 server communication services  */
#include "sio32Client.h"            /* Sio32 client communication services  */
#include "microCmd.h"               /* Microcontoller command functions     */
#include "acMicro.h"                /* AC Can Micro Definitions             */
#include "microDm.h"                /* Micro Data Manager Items & Functions */
#include "microdef.h"
#include "powerTypes.h"             /* Power management Data Types          */

#define Boolean MBool               /* Map microcontroller Boolean to MBool */

#include "applic.h"                 /* Microcontroller applications         */
#include "microcmd.h"               /* Microcontroller commands             */
#include "ac_micro.h"               /* AC Can Microcontroller defines       */
#include "microTask.h"              /* Microcontroller Task IO definitions  */

                                    /* AC Micro Device Name                 */
MLocal char* const acMicroName = "AC Can Micro";
                                    /* AC Micro Data Mgr Item Name Prefix   */
MLocal char* const acMicroAppPrefix  = AC_MICRO_DM_PREFIX;

#define AC_MICRO_DM_PERIOD   500000 /* AC Can Telemetery Updatep period 2 Hz*/
#define POWER_UP_DELAY          120 /* 2 Minute delay for AC Micro power up */
#define TANK_ALARM_DELAY         20 /* 20 second tank alarm delay           */

#define AC_MICRO_IN_STACKSIZE  2300 /* AC Can Micro Input Task size & TCB   */
#define AC_MICRO_OUT_STACKSIZE 2000 /* AC Can Micro Output Task size & TCB  */
#define AC_MICRO_MON_STACKSIZE 2000 /* AC Can Alarm Monitor Task size & TCB */
#define NUM_TASKS           3        /* Number of co-operating tasks        */

typedef struct                      /* AC Can Micro Data Manager Items      */
{
    microDmItems microDm;           /* Microcontroller Data Manager Items   */

    DM_Item acCanWaterAlarm;        /* Housing Water Alarm Detected         */
    DM_Item tetherCanWaterAlarm;    /* Tether Termination Can Water Alarm   */

    DM_Item microTemperature;       /* Temperature sensor value deg C       */
    DM_Item temperatureAlarm;       /* Temperature Alarm Status             */
    DM_Item tempWarnThresh;         /* Temperature Warn Threshold           */
    DM_Item tempAlarmThresh;        /* Temperature Alarm Threshold          */

    DM_Item microPressure;          /* Pressure sensor value PSIA           */
    DM_Item pressureAlarm;          /* Pressure Alarm Status                */
    DM_Item pressureWarnThresh;     /* Pressure Warn Threshold              */
    DM_Item pressureAlarmThresh;    /* Pressure Alarm Threshold             */

    DM_Item tankLevelAlarm;         /* Tank Coolant Level Alarm Status      */

    DM_Item outbdTankLevel;         /* Outboard Tank Coolant Level          */
    DM_Item outbdTankAlarmThresh;   /* Outboard Tank Alarm Level            */
    DM_Item outbdTankLevelAlarm;    /* Outbd Tank Coolant Level Alarm Status */

    DM_Item inbdTankLevel;          /* Inbd Tank Coolant Level              */
    DM_Item inbdTankAlarmThresh;    /* Inbd Tank Alarm Level                */
    DM_Item inbdTankLevelAlarm;     /* Inbd Tank Coolant Level Alarm Status */

    DM_Item outbdSumpLevel;         /* Outboard sump coolant Level          */
    DM_Item inbdSumpLevel;          /* Inbd sump coolant Level              */
} acMicroDmItems;

/****************************************************************************/

Void acMicroInTask(acMicroDmItems *dmItems,  microIOControl *microIOCtrl);
Void acMicroOutTask(acMicroDmItems* dmItems, microIOControl *microIOCtrl);
Void acMicroMonitorTask(Reg acMicroDmItems *dmItems);

MLocal Word processAcMicroSRQ( Reg acMicroDmItems* dmItems,
     microIOControl *microIOCtrl );

MLocal STATUS acMicroDmItemInit( acMicroDmItems* dmItems,
    sio32Chan* acMicroDataChan );

/****************************************************************************/
/* Function    : updateWaterAlarmsDm                                        */
/* Purpose     : Read AC Can & Tether Can Water Alarm status & updates DM   */
/* Inputs      : Sio32 chan & water alarm status data manager item handles  */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateWaterAlarmsDm( sio32Chan *acMicroDataChan, DM_Item acCanWaterAlarmDm,
    DM_Item tetherCanWaterAlarmDm )
{
    Word acCanWaterAlarm;           /* AC Can Water Alarm Status            */
    Word tetherCanWaterAlarm;       /* Tether Can Water Alarm Status        */

    Int16   cmdStatus;              /* Command Status                       */
    Word    reply[3];               /* Command Result from microcontroller  */

                                    /* Read Water Alarm Status              */
    if ( sendMicroCommand( acMicroDataChan, &reply, sizeof(Word) * 3,
         1, AC_MICRO_APP | GET_WATER_ALARM ) == 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 currents        */
    wordsFromBuf(reply, 3, &cmdStatus, &acCanWaterAlarm, &tetherCanWaterAlarm);

                                    /* Map from a word to a boolean         */
    acCanWaterAlarm     = (acCanWaterAlarm     ? TRUE : FALSE);
    tetherCanWaterAlarm = (tetherCanWaterAlarm ? TRUE : FALSE);

                                    /* Write water alarm status to Dmgr     */
    writeDmItem(acCanWaterAlarmDm, &acCanWaterAlarm,
             sizeof(acCanWaterAlarm));

    return (writeDmItem(tetherCanWaterAlarmDm, &tetherCanWaterAlarm,
             sizeof(tetherCanWaterAlarm)));
} /* updateWaterAlarmsDm() */

/****************************************************************************/
/* Function    : initTemperatureThreshDm                                    */
/* Purpose     : Read Temperature Thresholds and update data manager item   */
/* Inputs      : Sio32 channel, temperature alarm threshold dm item handles */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
initTemperatureThreshDm( sio32Chan *acMicroDataChan, DM_Item temperatureWarnDm,
    DM_Item temperatureAlarmDm )
{
    Int16   warnThresh;             /* Temperature warning threshold        */
    Int16   alarmThresh;            /* Temperature alarm Threshold          */

    Int16   cmdStatus;              /* Command Status                       */
    Word    reply[3];               /* Command Result from microcontroller  */

                                    /* Send command to microcontroller      */
    if ( sendMicroCommand( acMicroDataChan, &reply, sizeof(Word) * 3,
         1, AC_MICRO_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 currents        */
    wordsFromBuf(reply, 3, &cmdStatus, &warnThresh, &alarmThresh);

                                    /* We MUST use urgent open here as      */
                                    /* another task is normal provider      */

    urgentWriteDmItem( temperatureAlarmDm, &alarmThresh, sizeof(alarmThresh));
    return (urgentWriteDmItem(temperatureWarnDm, &warnThresh,
         sizeof(warnThresh)));
} /* initTemperatureThreshDm() */

/****************************************************************************/
/* Function    : writeTemperatureThresh                                     */
/* Purpose     : Get temperature alarm thresholds from dm and send to micro */
/* Inputs      : Sio32 channel, temperature threshold dm item handles       */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
writeTemperatureThresh( sio32Chan *acMicroDataChan, DM_Item temperatureWarnDm,
    DM_Item temperatureAlarmDm  )
{
    Errno   status;                 /* Result of dm_read                    */
    Word    cmdStatus;              /* Command Result from microcontroller  */

    Int16   warnThresh;             /* Temperature warning threshold        */
    Int16   alarmThresh;            /* Temperature alarm Threshold          */

                                    /* Read Temperature Thresholds from dm  */
    status = dm_read( temperatureWarnDm, (char *) &warnThresh,
         sizeof(warnThresh), (DM_Time *) NULL);

    status = dm_read( temperatureAlarmDm, (char *) &alarmThresh,
         sizeof(alarmThresh), (DM_Time *) NULL);

                                    /* Check for successful dm_read         */
    if ((status == SUCCESS) || (status == EDM_NOPROVIDER))
    {                               /* Send command to microcontroller      */
        if ( sendMicroCommand( acMicroDataChan, &cmdStatus, sizeof(cmdStatus),
            3,  AC_MICRO_APP | SET_TEMP_ALARM_THRESH, warnThresh, alarmThresh )
             == ERROR ) return(ERROR);

                                    /* Check command result                 */
        return (wordFromBuf(&cmdStatus, 0) == CMD_OK ? OK : ERROR);
    } /* if */

    return(ERROR);
} /* writeTemperatureThresh() */

/****************************************************************************/
/* Function    : updateTemperatureDm                                        */
/* 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
updateTemperatureDm( sio32Chan *acMicroDataChan, DM_Item microTempDm )
{
    Int16   temperature;            /* Micro Temperature Sensor Value       */
                                    /* Read temperature sensor value        */
    if (microCommand(acMicroDataChan, AC_MICRO_APP | GET_TEMPERATURE,
        &temperature) == ERROR)
        return (ERROR);
                                    /* Write temperature to Data Manager    */
    return (writeDmItem(microTempDm, &temperature, sizeof(temperature)));
} /* updateTemperatureDm() */

/****************************************************************************/
/* 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                                        */
/****************************************************************************/
    MLocal STATUS
updateTempAlarmDm( sio32Chan *acMicroDataChan, DM_Item tempAlarmDm )
{
    Word alarmStatus;               /* Microcontroller Alarm Status Word    */
    microAlarm tempAlarmStatus;     /* Micro temperature alarm status       */
                                    /* Get TempAlarm Status from micro      */
    if (microCommand(acMicroDataChan, AC_MICRO_APP | GET_TEMP_ALARM_STATUS,
         &alarmStatus) == ERROR) return(ERROR);

    tempAlarmStatus = (microAlarm) alarmStatus;

                                    /* Write temperature alarm to Dmgr      */
    return(writeDmItem(tempAlarmDm, &tempAlarmStatus,
        sizeof(tempAlarmStatus)));
} /* updateTempAlarmDm() */

/****************************************************************************/
/* Function    : initPressureThreshDm                                       */
/* Purpose     : Read Pressure Thresholds and update data manager item      */
/* Inputs      : Sio32 channel, pressure alarm threshold dm item handles    */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
initPressureThreshDm( sio32Chan *acMicroDataChan, DM_Item pressureWarnDm,
    DM_Item pressureAlarmDm )
{
    Int16   warnThresh;             /* Pressure warning threshold           */
    Int16   alarmThresh;            /* Pressure alarm Threshold             */
    Flt32   scaledWarnThresh;
    Flt32   scaledAlarmThresh;

    Int16   cmdStatus;              /* Command Status                       */
    Word    reply[3];               /* Command Result from microcontroller  */

                                    /* Send command to microcontroller      */
    if ( sendMicroCommand( acMicroDataChan, &reply, sizeof(Word) * 3,
         1, AC_MICRO_APP | GET_PRESSURE_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 currents        */
    wordsFromBuf(reply, 3, &cmdStatus, &warnThresh, &alarmThresh);

    scaledWarnThresh = warnThresh / 100;
    scaledAlarmThresh = alarmThresh / 100;

                                    /* We MUST use urgent open here as      */
                                    /* another task is normal provider      */
    urgentWriteDmItem( pressureAlarmDm, &scaledAlarmThresh,
                       sizeof(scaledAlarmThresh));
    return (urgentWriteDmItem(pressureWarnDm, &scaledWarnThresh,
                              sizeof(scaledWarnThresh)));
} /* initPressureThreshDm() */

/****************************************************************************/
/* Function    : writePressureThresh                                        */
/* Purpose     : Get pressure alarm thresholds from dm and send to micro    */
/* Inputs      : Sio32 channel, pressure threshold dm item handles          */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
writePressureThresh( sio32Chan *acMicroDataChan, DM_Item pressureWarnDm,
    DM_Item pressureAlarmDm  )
{
    Errno   status;                 /* Result of dm_read                    */
    Word    cmdStatus;              /* Command Result from microcontroller  */

    Flt32   warnThresh;             /* Pressure warning threshold           */
    Flt32   alarmThresh;            /* Pressure alarm Threshold             */
    Int16   scaledWarnThresh;
    Int16   scaledAlarmThresh;

                                    /* Read Pressure Thresholds from dm     */
    status = dm_read( pressureWarnDm, (char *) &warnThresh,
         sizeof(warnThresh), (DM_Time *) NULL);

    status = dm_read( pressureAlarmDm, (char *) &alarmThresh,
         sizeof(alarmThresh), (DM_Time *) NULL);

    scaledWarnThresh =  (Int16) warnThresh * 100;
    scaledAlarmThresh = (Int16) alarmThresh * 100;

                                    /* Check for successful dm_read         */
    if ((status == SUCCESS) || (status == EDM_NOPROVIDER))
    {                               /* Send command to microcontroller      */
        if ( sendMicroCommand( acMicroDataChan, &cmdStatus, sizeof(cmdStatus),
            3,  AC_MICRO_APP | SET_PRESSURE_ALARM_THRESH,
            scaledWarnThresh, scaledAlarmThresh ) == ERROR ) return(ERROR);

                                    /* Check command result                 */
        return (wordFromBuf(&cmdStatus, 0) == CMD_OK ? OK : ERROR);
    } /* if */

    return(ERROR);
} /* writePressureThresh() */

/****************************************************************************/
/* Function    : updatePressureDm                                           */
/* Purpose     : Reads micro pressure sensor value & updates dmgr item      */
/* Inputs      : Sio32 chan & pressure sensor data manager item handle      */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updatePressureDm( sio32Chan *acMicroDataChan, DM_Item pressureDm )
{
    Int16   pressure;               /* Micro Pressure Sensor Value       */
    Flt32   psia;
                                    /* Read pressure sensor value        */
    if (microCommand(acMicroDataChan, AC_MICRO_APP | GET_PRESSURE,
       &pressure) == ERROR)
        return (ERROR);

    psia = pressure / 100.0;        /* Convert to PSIA                   */
                                    /* Write pressure to Data Manager    */
    return (writeDmItem(pressureDm, &psia, sizeof(psia)));
} /* updatePressureDm() */

/****************************************************************************/
/* Function    : updatePressureAlarmDm                                      */
/* Purpose     : Reads micro pressure alarm status & updates dmgr item   */
/* Inputs      : Sio32 chan & pressure alarm data manager item handle    */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    MLocal STATUS
updatePressureAlarmDm( sio32Chan *acMicroDataChan, DM_Item pressureAlarmDm )
{
    Word alarmStatus;               /* Microcontroller Alarm Status Word    */
    microAlarm pressureAlarm;       /* Micro pressure alarm status          */
                                    /* Get PressureAlarm Status from micro  */
    if (microCommand(acMicroDataChan, AC_MICRO_APP | GET_PRESSURE_ALARM_STATUS,
         &alarmStatus) == ERROR) return(ERROR);

    pressureAlarm = (microAlarm) alarmStatus;

                                    /* Write pressure alarm to Dmgr         */
    return(writeDmItem(pressureAlarmDm, &pressureAlarm, sizeof(pressureAlarm)));
} /* updatePressureAlarmDm() */

/****************************************************************************/
/* Function    : readAcMicroCoolantLevelsDm                                 */
/* Purpose     : Read Coolant Levels and update data manager item           */
/* Inputs      : Sio32 channel, coolant level item handles                  */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
readAcMicroCoolantLevelsDm( sio32Chan *acMicroDataChan, DM_Item outbdTankDm,
    DM_Item inbdTankDm, DM_Item outbdSumpDm, DM_Item inbdSumpDm)
{
    Int16   outbdTank, inbdTank;    /* Tank Coolant Levels                  */
    Int16   outbdSump, inbdSump;    /* Sump Coolant Levels                  */

    Int16   cmdStatus;              /* Command Status                       */
    Word    reply[5];               /* Command Result from microcontroller  */

                                    /* Send command to microcontroller      */
    if ( sendMicroCommand( acMicroDataChan, &reply, sizeof(Word) * 5,
         1, AC_MICRO_APP | GET_COOLANT_LEVELS ) == 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 coolant levels  */
    wordsFromBuf(reply, 5, &cmdStatus, &outbdTank, &inbdTank,
                                       &outbdSump, &inbdSump);

    writeDmItem( outbdTankDm, &outbdTank, sizeof(outbdTank) );
    writeDmItem( inbdTankDm, &inbdTank, sizeof(inbdTank) );
    writeDmItem( outbdSumpDm, &outbdSump, sizeof(outbdSump) );
    writeDmItem( inbdSumpDm, &inbdSump, sizeof(inbdSump) );

    return(OK);
} /* readAcMicroCoolantLevelsDm() */

/****************************************************************************/
/* Function    : initCoolantAlarmThreshDm                                   */
/* Purpose     : Read Coolant Alarm Thresholds and update data manager items*/
/* Inputs      : Sio32 channel, coolant level alarm threshold dm handles    */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
initCoolantAlarmThreshDm( sio32Chan *acMicroDataChan, DM_Item outbdAlarmLevelDm,
    DM_Item inbdAlarmLevelDm )
{
    Int16   outbdAlarmThresh;       /* Outboard alarm level threshold       */
    Int16   inbdAlarmThresh;        /* Inboard alarm level threshold        */

    Int16   cmdStatus;              /* Command Status                       */
    Word    reply[3];               /* Command Result from microcontroller  */

                                    /* Send command to microcontroller      */
    if ( sendMicroCommand( acMicroDataChan, &reply, sizeof(Word) * 3,
         1, AC_MICRO_APP | GET_COOLANT_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 alarm thresholds*/
    wordsFromBuf(reply, 3, &cmdStatus, &outbdAlarmThresh, &inbdAlarmThresh);

                                    /* We MUST use urgent open here as      */
                                    /* another task is normal provider      */
    urgentWriteDmItem( outbdAlarmLevelDm, &outbdAlarmThresh,
        sizeof(outbdAlarmThresh));

    return (urgentWriteDmItem( inbdAlarmLevelDm, &inbdAlarmThresh,
        sizeof(inbdAlarmThresh)));
} /* initCoolantAlarmThreshDm() */

/****************************************************************************/
/* Function    : writeCoolantLevelThresh                                    */
/* Purpose     : Get coolant level alarm thresholds from dm & send to micro */
/* Inputs      : Sio32 channel, alarm level threshold dm item handles       */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
writeCoolantLevelThresh( sio32Chan *acMicroDataChan, DM_Item outbdTankThreshDm,
    DM_Item inbdTankThreshDm )
{
    Errno   status;                 /* Result of dm_read                    */
    Word    cmdStatus;              /* Command Result from microcontroller  */

    Int16   outbdTankThresh;        /* Outboard Tank Coolant Level Threshold*/
    Int16   inbdTankThresh;         /* Inboard Tank Coolant Level Threshold */

                                    /* Read Tank Level thresholds from dm   */
    status = dm_read( outbdTankThreshDm, (char *) &outbdTankThresh,
         sizeof(outbdTankThresh), (DM_Time *) NULL);

    status = dm_read( inbdTankThreshDm, (char *) &inbdTankThresh,
         sizeof(inbdTankThresh), (DM_Time *) NULL);

                                    /* Check for successful dm_read         */
    if ((status == SUCCESS) || (status == EDM_NOPROVIDER))
    {                               /* Send command to microcontroller      */
        if ( sendMicroCommand( acMicroDataChan, &cmdStatus, sizeof(cmdStatus),
            3,  AC_MICRO_APP | SET_COOLANT_ALARM_THRESH,
             outbdTankThresh,  inbdTankThresh ) == ERROR ) return(ERROR);

                                    /* Check command result                 */
        return (wordFromBuf(&cmdStatus, 0) == CMD_OK ? OK : ERROR);
    } /* if */

    return(ERROR);
} /* writeCoolantLevelThresh() */

/****************************************************************************/
/* Function    : updateCoolantLevelAlarmsDm                                 */
/* Purpose     : Read Coolant Level Alarm status & updates DM               */
/* Inputs      : Sio32 chan & coolant level alarm status dm item handles    */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateCoolantLevelAlarmsDm( sio32Chan *acMicroDataChan,
    DM_Item tankLevelAlarmDm, DM_Item outbdTankLevelAlarmDm,
    DM_Item inbdTankLevelAlarmDm )
{
    microAlarm tankAlarm;           /* Both tank level Alarms ored together */
    microAlarm outbdTankAlarm;      /* Outboard tank level alarm status     */
    microAlarm inbdTankAlarm;       /* Inboard tank level alarm status      */

    Word  outbdAlarmStatus;         /* Microcontroller Alarm Status Word    */
    Word  inbdAlarmStatus;          /* Microcontroller Alarm Status Word    */

    Int16 cmdStatus;                /* Command Status                       */
    Word  reply[3];                 /* Command Result from microcontroller  */

                                    /* Read Coolant level alarm status      */
    if ( sendMicroCommand( acMicroDataChan, &reply, sizeof(Word) * 3,
         1, AC_MICRO_APP | GET_COOLANT_ALARM_STATUS ) == 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 currents        */
    wordsFromBuf(reply, 3, &cmdStatus, &outbdAlarmStatus, &inbdAlarmStatus);

    outbdTankAlarm  = (microAlarm) outbdAlarmStatus;
    inbdTankAlarm   = (microAlarm) inbdAlarmStatus;

    tankAlarm = MICRO_ALARM_OK;
                                     /* Write coolant alarm status to dm     */
    urgentWriteDmItem(tankLevelAlarmDm,&tankAlarm,      sizeof(tankAlarm));
    writeDmItem(outbdTankLevelAlarmDm, &outbdTankAlarm, sizeof(outbdTankAlarm));
    writeDmItem(inbdTankLevelAlarmDm,  &inbdTankAlarm,  sizeof(inbdTankAlarm));

    return(OK);
} /* updateCoolantLevelAlarmsDm() */

/****************************************************************************/
/* Function    : createACMicroAppDmItems                                    */
/* Purpose     : Create Data Mgr Items specific to AC Micro Application     */
/* Inputs      : Pointer to structure of DM item handles, AC Micro DM       */
/*               prefix, AC Micro Microcontroller Name                      */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
createAcMicroAppDmItems( acMicroDmItems *dmItems,
    const char* acMicroAppPrefix, const char* acMicroName )
{
    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      */
    } acMicroDmInit[] =

      { { &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->temperatureAlarm,        "Temperature Alarm",
                TEMPERATURE_ALARM_DM,           DM_ENUM,  1 },

        { &dmItems->tempWarnThresh,          "Temperature Warn Threshold",
                TEMP_WARN_THRESH_DM,            DM_INT16, 1 },

        { &dmItems->tempAlarmThresh,         "Temperature Alarm Threshold",
                TEMP_ALARM_THRESH_DM,           DM_INT16, 1 },

        { &dmItems->microTemperature,        "Temperature",
                TEMPERATURE_DM,                 DM_INT16, 1 },

        { &dmItems->microPressure,           "Pressure",
                PRESSURE_DM,                    DM_FLT32, 1 },

        { &dmItems->pressureAlarm,           "Pressure Alarm",
                PRESSURE_ALARM_DM,              DM_ENUM,  1 },

        { &dmItems->pressureWarnThresh,      "Pressure Warn Threshold",
                PRESSURE_WARN_THRESH_DM,        DM_FLT32, 1 },

        { &dmItems->pressureAlarmThresh,     "Pressure Alarm Threshold",
                PRESSURE_ALARM_THRESH_DM,       DM_FLT32, 1 },

        { &dmItems->acCanWaterAlarm,         "AC Can Water Alarm",
                AC_CAN_WATER_ALARM_DM,          DM_MBOOL, 1 },

        { &dmItems->tetherCanWaterAlarm,     "Tether Can Water Alarm",
                TETHER_CAN_WATER_ALARM_DM,      DM_MBOOL, 1 },

        { &dmItems->tankLevelAlarm,          "Tank coolant level alarm",
                TANK_LEVEL_ALARM_DM,             DM_ENUM, 1 },

        { &dmItems->outbdTankLevel,          "Outboard tank coolant level",
                OUTBD_TANK_LEVEL_DM,             DM_INT16, 1 },

        { &dmItems->inbdTankLevel,           "Inboard tank coolant level",
                INBD_TANK_LEVEL_DM,             DM_INT16, 1 },

        { &dmItems->outbdSumpLevel,          "Outboard sump coolant level",
                OUTBD_SUMP_LEVEL_DM,             DM_INT16, 1 },

        { &dmItems->inbdSumpLevel,           "Inboard sump coolant level",
                INBD_SUMP_LEVEL_DM,             DM_INT16, 1 },

        { &dmItems->outbdTankLevelAlarm,     "Outbd tank coolant level alarm",
                OUTBD_TANK_LEVEL_ALARM_DM,       DM_ENUM, 1 },

        { &dmItems->inbdTankLevelAlarm,      "Inbd tank coolant level alarm",
                INBD_TANK_LEVEL_ALARM_DM,       DM_ENUM, 1 },

        { &dmItems->outbdTankAlarmThresh,    "Outbd tank coolant level thresh",
                OUTBD_TANK_ALARM_THRESH_DM,      DM_INT16, 1 },

        { &dmItems->inbdTankAlarmThresh,     "Inbd tank coolant level thresh",
                INBD_TANK_ALARM_THRESH_DM,      DM_INT16, 1 },

        { NO_ITEM, NULL, NULL, DM_ENDT, 0 } };

                                  /* Initialize AC Micro Data Manager Items*/
    for (item = 0; acMicroDmInit[item].dmItem != NO_ITEM; item++)
    {
        if ((*acMicroDmInit[item].dmItem =
             initMicroDmItem(acMicroAppPrefix, acMicroDmInit[item].name,
             acMicroDmInit[item].type, acMicroDmInit[item].len)) == ERROR)
        {                         /* Error occurred so print message & exit*/
            logMsg("%s: Error Initializing %s DM Item\n",
                acMicroName, acMicroDmInit[item].errorMsg);
            return(ERROR);
        } /* if */
    } /* for */

    return(OK);
} /* createAcMicroAppDmItems() */

/****************************************************************************/
/* Function    : acMicroDmItemInit                                          */
/* Purpose     : Read parameters from P/T microcontroller and update DMgr   */
/* Inputs      : Pointer to DM item handles, P/T micro serial channel       */
/* Outputs     : None, but data manager items change                        */
/****************************************************************************/
    LOCAL STATUS
acMicroDmItemInit(acMicroDmItems* dmItems, sio32Chan* acMicroDataChan)
{
    Int16 trys;
                                /* Send Command Enable Command to IBC Micro  */
    for (trys = 0; ((microCmdEnable(acMicroDataChan) == ERROR) &&
         trys < MICRO_ENABLE_TRYS); trys++)
         taskDelay(sysClkRateGet() / 5);

    if (trys == MICRO_ENABLE_TRYS)
    {
        logMsg("AC Micro: Error Enabling AC Micro Microcontroller\n");
        return(ERROR);
    }
                                /* Set Micro Identification initial value    */
    if (updateMicroIdentDm(acMicroDataChan, dmItems->microDm.idString)
        == ERROR)
        logMsg("AC Micro: Error reading Identification String\n");

                                /* Set Micro Serial Number initial value     */
    if (updateSerialNoDm(acMicroDataChan, dmItems->microDm.serialNo) == ERROR)
        logMsg("AC Micro: Error reading Micro Serial Number\n");

                                /* Set Software Revision initial value       */
    if (updateSoftwareRevDm(acMicroDataChan, dmItems->microDm.softwareRev)
        == ERROR)
        logMsg("AC Micro: Error reading Software Revision\n");

                                /* Set Micro Ram Test Result value           */
    if (updateMicroRamTestDm(acMicroDataChan, dmItems->microDm.ramTest)
        == ERROR)
        logMsg("AC Micro: Error checking micro RAM Test\n");

                                /* Set Micro Temperature Alarm initial value */
    if (updateTempAlarmDm(acMicroDataChan, dmItems->temperatureAlarm) == ERROR)
        logMsg("AC Micro: Error checking temperature alarm status\n");

                                /* Set Micro Pressure Alarm initial value   */
    if (updatePressureAlarmDm(acMicroDataChan, dmItems->pressureAlarm) == ERROR)
        logMsg("AC Micro: Error checking pressure alarm status\n");

                                /* Set Micro Water Alarm initial value       */
    if (updateWaterAlarmsDm(acMicroDataChan, dmItems->acCanWaterAlarm,
        dmItems->tetherCanWaterAlarm) == ERROR)
        logMsg("AC Micro: Error checking water alarm status\n");

                                /* Set Coolant Level Alarm initial values    */
    if (updateCoolantLevelAlarmsDm(acMicroDataChan, dmItems->tankLevelAlarm,
        dmItems->outbdTankLevelAlarm, dmItems->inbdTankLevelAlarm) == ERROR)
        logMsg("AC Micro: Error checking coolant level alarm status\n");

    return(OK);
} /* acMicroDmItemInit() */

/****************************************************************************/
/* Function    : acMicroTask                                                */
/* Purpose     : Initializes communication with AC Micro Microcontroller    */
/*               Provides interface between AC Micro and Data Manager       */
/* Inputs      : SIO32 serial channel number for AC Micro Microcontrller    */
/*               Physically maps the AC Micro to a serial channel           */
/* Outputs     : Normally runs forever, but returns ERROR on fatal error    */
/****************************************************************************/
    STATUS
acMicroTask( Nat16 acMicroSerialChan )
{
    acMicroDmItems dmItems;         /* AC Micro Application Data Mgr items  */
    microIOControl microIOCtrl;     /* Microcontroller IO Task control      */

                                    /* Initialize serial channel and task   */
                                    /* synchronization resources            */
    if (initMicroTaskIO( &microIOCtrl, NUM_TASKS, acMicroSerialChan,
        acMicroAppPrefix, "/sio32/acMicro", NO_ITEM ) == ERROR)
    {
        logMsg("Error initializing IO for AC Micro");
        return(ERROR);
    } /* if */
                                   /* Clear AC Micro Data Manager handles */
    bzero(&dmItems, sizeof(dmItems));

                                   /* Create AC Micro Application Items   */
    if (createAcMicroAppDmItems(&dmItems, acMicroAppPrefix, acMicroName)
         == ERROR)
    {                              /* Error occurred so print message & exit */
        sio32ChanDestroy( acMicroSerialChan, &microIOCtrl.sio32DataChan);
        return(ERROR);
    } /* if */

                                   /* Start Provider for Static Data & Alarms*/
    dm_start_provider(dmItems.microDm.resetEvent,  DM_STATIC);
    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.ramTest,     DM_STATIC);

    dm_start_provider(dmItems.acCanWaterAlarm,     DM_STATIC);
    dm_start_provider(dmItems.tetherCanWaterAlarm, DM_STATIC);
    dm_start_provider(dmItems.temperatureAlarm,    DM_STATIC);
    dm_start_provider(dmItems.pressureAlarm,       DM_STATIC);

    dm_start_provider(dmItems.inbdTankLevelAlarm,  DM_STATIC);
    dm_start_provider(dmItems.outbdTankLevelAlarm, DM_STATIC);

                                    /* Initialize AC Micro Data Out Task     */
    if ((microIOCtrl.childTasks[OUT_TASK].taskId =
         taskSpawn("acMicroOut", AC_MICRO_OUT_PRIORITY, VX_FP_TASK,
         AC_MICRO_OUT_STACKSIZE, (FUNCPTR) acMicroOutTask,
         (int) &dmItems, (int) &microIOCtrl,
         0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    {
                                    /* Close serial communication channel    */
        sio32ChanDestroy( acMicroSerialChan, &microIOCtrl.sio32DataChan );
        logMsg("AC Micro: Error spawning data output task\n");
        return(ERROR);
    } /* if */

                                    /* Initialize AC Micro Data In Task      */
    if (( microIOCtrl.childTasks[IN_TASK].taskId =
         taskSpawn( "acMicroIn", AC_MICRO_IN_PRIORITY, VX_FP_TASK,
         AC_MICRO_IN_STACKSIZE, (FUNCPTR) acMicroInTask,
         (int) &dmItems, (int) &microIOCtrl,
         0, 0, 0, 0, 0, 0, 0, 0) ) == ERROR)
    {                               /* Delete Sonar Dcon Out Task             */
        taskDelete(microIOCtrl.childTasks[OUT_TASK].taskId);
        sio32ChanDestroy( acMicroSerialChan, &microIOCtrl.sio32DataChan );
        logMsg("AC Micro: Error spawning data input task\n");
        return(ERROR);
    } /* if */
                                    /* Initialize AC Micro Alarm Monitor Task */
    taskSpawn("acMicroMon", AC_MICRO_MONITOR_PRIORITY, 0,
         AC_MICRO_MON_STACKSIZE, (FUNCPTR) acMicroMonitorTask,
         (int) &dmItems, 0, 0, 0, 0, 0, 0, 0, 0, 0);


    FOREVER
    {
        if (microIOCtrl.resetEventCount != 0)
                                    /* Process SRQ's from micro               */
        while(processAcMicroSRQ(&dmItems, &microIOCtrl) != MICRO_RESET_SRQ);

        microIOCtrl.resetEventCount++;   /* Count reset events ffrom micro    */

                                    /* Reset event received from Micro so     */
                                    /* Mark serial coms link as up            */
        setSerialLinkState(&microIOCtrl, LINK_UP);

                                    /* Initialize AC Micro DM Item values    */
        if (acMicroDmItemInit( &dmItems, &microIOCtrl.sio32DataChan) == OK)
                                    /* Wake up output task to configure micro*/
            semGive(microIOCtrl.childTasks[OUT_TASK].taskSyncSem);
        else
            setSerialLinkState(&microIOCtrl, LINK_DOWN);

    } /* FOREVER */
                                   /* Delete Child Tasks                     */
    taskDelete(microIOCtrl.childTasks[IN_TASK].taskId);
    taskDelete(microIOCtrl.childTasks[OUT_TASK].taskId);


                                    /* Close serial communication channel    */
    sio32ChanDestroy( acMicroSerialChan, &microIOCtrl.sio32DataChan );

                        /* dm_stop_provider, dm_stop_consumer, etc are NOT   */
                        /* required when the task exits as the Data Manager  */
                        /* does this automatically when the task is deleted  */
                        /* via taskDeleteHookAdd() and dm_task_exit functions*/

    return(OK);         /* That's all folks                                  */
} /* acMicroTask() */

/*****************************************************************************/
/* Function    : acMicroOutTask                                              */
/* Purpose     : AC Can Micro Out Task. Read DM items & write to AC Micro    */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : Normally runs forever, but exits if error occurs            */
/*****************************************************************************/
     Void
acMicroOutTask(Reg acMicroDmItems *dmItems, microIOControl *microIOCtrl )
{
    DM_Group dmGroup;               /* AC Micro Data Manager Group           */
    SEM_ID   dmUpdateSem;           /* Data Manager wakes up task when an    */

    DWord   changedBits;            /* Holds dm_group_changes bit vector     */
    DWord   resetEventBit;          /* Microcontroller reset event  bit      */
    DWord   resetCmdBit;            /* Microcontroller reset item changed bit*/
    DWord   tempWarnBit;            /* Temperature Warning item changed bit  */
    DWord   tempAlarmBit;           /* Temperature Alarm item changed bit    */
    DWord   pressureWarnBit;        /* Pressure Warning item changed bit     */
    DWord   pressureAlarmBit;       /* Presure Alarm item changed bit        */
    DWord   outbdTankAlarmBit;      /* Outbd Tank Alarm thres item chaned bit */
    DWord   inbdTankAlarmBit;       /* Inbd Tank Alarm thres item chaned bit */

                                    /* Create switch & power sync semaphores */
    if ((dmUpdateSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL)
    {
        logMsg("AC Micro: Error initializing Input Task Resources\n");
        return;
    } /* if */
                                    /* Declare this task a consumer of items */
                                    /* which are written to the AC Micro t   */
    dm_start_consumer(dmItems->microDm.resetEvent,  DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->microDm.resetCmd,    DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->tempWarnThresh,      DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->tempAlarmThresh,     DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->pressureWarnThresh,  DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->pressureAlarmThresh, DM_STATIC, dmUpdateSem);

    dm_start_consumer(dmItems->outbdTankAlarmThresh, DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->inbdTankAlarmThresh, 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->tempWarnThresh,      &tempWarnBit);
    dm_group_add_item(dmGroup, dmItems->tempAlarmThresh,     &tempAlarmBit);
    dm_group_add_item(dmGroup, dmItems->pressureWarnThresh,  &pressureWarnBit);
    dm_group_add_item(dmGroup, dmItems->pressureAlarmThresh, &pressureAlarmBit);

    dm_group_add_item(dmGroup, dmItems->outbdTankAlarmThresh,
                      &outbdTankAlarmBit);
    dm_group_add_item(dmGroup, dmItems->inbdTankAlarmThresh, &inbdTankAlarmBit);

    FOREVER
    {   microIOCtrl->microConfigured = FALSE;

                                    /* Wait for micro reset via SRQ Task      */
        semTake(microIOCtrl->childTasks[OUT_TASK].taskSyncSem, WAIT_FOREVER);

        /* We need to initialize default state of Data manager Items here    */

        initTemperatureThreshDm(SERIAL_CHAN, dmItems->tempWarnThresh,
                             dmItems->tempAlarmThresh);

        initPressureThreshDm(SERIAL_CHAN, dmItems->pressureWarnThresh,
                             dmItems->pressureAlarmThresh);

        initCoolantAlarmThreshDm(SERIAL_CHAN, dmItems->outbdTankAlarmThresh,
                             dmItems->inbdTankAlarmThresh);

                                    /* Ask Data Manager which items changed  */
        changedBits = dm_get_group_changes(dmGroup);


                                    /* Flag that micro has been configured    */
        microIOCtrl->microConfigured = TRUE;

                                    /* Wake up input task to read from micro  */
        semGive(microIOCtrl->childTasks[IN_TASK].taskSyncSem);

        while (microIOCtrl->serialLinkState == LINK_UP)
        {                           /* Wait for any data items to change     */
            semTake(dmUpdateSem, WAIT_FOREVER);

                                    /* Ask Data Manager which items changed  */
            changedBits = dm_get_group_changes(dmGroup);

                                    /* Check if micro Reset Event occurred   */
            if (changedBits & resetEventBit)
                break;              /* Exit loop and re-initialize DM items  */

            taskSafe();             /* Prevent task from being deleted during*/
                                    /* serial IO and Data Manager updates    */

            if ( (changedBits & tempWarnBit) ||
                 (changedBits & tempAlarmBit) )
                writeTemperatureThresh(SERIAL_CHAN,
                     dmItems->tempWarnThresh, dmItems->tempAlarmThresh);

            if ( (changedBits & pressureWarnBit) ||
                 (changedBits & pressureAlarmBit) )
                writePressureThresh(SERIAL_CHAN,
                     dmItems->pressureWarnThresh, dmItems->pressureAlarmThresh);

            if ( (changedBits & outbdTankAlarmBit) ||
                 (changedBits & inbdTankAlarmBit) )
                writeCoolantLevelThresh(SERIAL_CHAN,
                   dmItems->outbdTankAlarmThresh, dmItems->inbdTankAlarmThresh);

                                   /* Check if Reset Command request occurred*/
            if (changedBits & resetCmdBit)
            {                       /* Mark serial link as down               */
                setSerialLinkState(microIOCtrl, LINK_DOWN);
                                    /* Manual reset so announce it            */
                microIOCtrl->announceResets = TRUE;
                                    /* Send Reset Command to Microcontroller  */
                microResetCmd(SERIAL_CHAN);
                break;              /* Exit loop and wait for RESET           */
            } /* if */

            taskUnsafe();          /* Task may now be safely deleted         */

        } /* while (LINK_UP) */
    } /* FOREVER */

                       /* dm_stop_provider, dm_stop_consumer, dm_delete_group*/
                       /* etc are NOT required when the task exits as the    */
                       /* Data Manager does this automatically when the task */
                       /* is deleted via the taskDeleteHookAdd() and         */
                       /* dm_task_exit functions.                            */

                       /* That's all folks !                                 */
} /* acMicroOutTask() */


/*****************************************************************************/
/* Function    : acMicroInTask                                               */
/* Purpose     : AC Micro Input Task. Wakes up periodically, read data       */
/*               from the AC Micro 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
acMicroInTask(Reg acMicroDmItems* dmItems,  microIOControl *microIOCtrl)
{
    SEM_ID  wakeupSem;              /* Used by watch dog to wake up this task*/
    Word    atodValues[8];

                                    /* Create wakeup semaphore and watch dog */
                                    /* timer for provider rate control       */
    if ((wakeupSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL )
    {
        logMsg("AC Micro: Error initializing Input Task Resources\n");
        return;
    } /* if */
                                   /* Provider Task for non-static data items*/
    dm_start_provider(dmItems->microTemperature,  AC_MICRO_DM_PERIOD);
    dm_start_provider(dmItems->microPressure,     AC_MICRO_DM_PERIOD);
    dm_start_provider(dmItems->outbdTankLevel,    AC_MICRO_DM_PERIOD);
    dm_start_provider(dmItems->inbdTankLevel,     AC_MICRO_DM_PERIOD);
    dm_start_provider(dmItems->outbdSumpLevel,    AC_MICRO_DM_PERIOD);
    dm_start_provider(dmItems->inbdSumpLevel,     AC_MICRO_DM_PERIOD);

                                    /* Update Rate is not guaranteed due to  */
                                    /* the possibility of task preemption    */
    FOREVER
    {                               /* Wait for IBC Coms to be initialized   */
       semTake(microIOCtrl->childTasks[IN_TASK].taskSyncSem, WAIT_FOREVER);

       while (microIOCtrl->serialLinkState == LINK_UP)
       {
           taskSafe();              /* Prevent task from being deleted during*/
                                    /* serial IO and Data Manager updates    */

           updateTemperatureDm( SERIAL_CHAN, dmItems->microTemperature );
           updatePressureDm   ( SERIAL_CHAN, dmItems->microPressure );

           readAcMicroCoolantLevelsDm( SERIAL_CHAN,
                             dmItems->outbdTankLevel, dmItems->inbdTankLevel,
                             dmItems->outbdSumpLevel, dmItems->inbdSumpLevel);

           taskUnsafe();             /* task may now be deleted safely        */
                                     /* pend until sem timeout  wakes us up   */
           semTake(wakeupSem, sysClkRateGet() /
                   (USECS_PER_SEC / AC_MICRO_DM_PERIOD));
       }/* while */
    } /* FOREVER */

    semDelete(wakeupSem);           /* semaphore resources                   */

                       /* dm_stop_provider, dm_stop_consumer, dm_delete_group*/
                       /* etc are not required when the task exits as the    */
                       /* data manager does this automatically when the task */
                       /* is deleted via the taskDeleteHookAdd() and         */
                       /* dm_task_exit functions.                            */

                       /* that's all folks !                                 */
} /* acMicroInTask() */

/*****************************************************************************/
/* Function    : acMicroMonitorTask                                          */
/* Purpose     : AC Can Monitor Task. Monitors Tank Alarm Level DM items     */
/* Inputs      : Array of Data Manager Item handles                          */
/* Outputs     : Normally runs forever, but exits if error occurs            */
/*****************************************************************************/
     Void
acMicroMonitorTask(Reg acMicroDmItems *dmItems)
{
    SEM_ID   dmUpdateSem;           /* Data Manager wakes up task when an    */
    MBool    tankAlarmDelay;

    microAlarm tankAlarm,     lastTankAlarm;
    microAlarm inbdTankAlarm, outbdTankAlarm;
                                    /* Create switch & power sync semaphores */
    if ((dmUpdateSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL)
    {
        logMsg("AC Micro: Error initializing Monitor Task Resources\n");
        return;
    } /* if */

                                    /* Wait for power delay to expire        */
    semTake(dmUpdateSem, sysClkRateGet() * POWER_UP_DELAY);

    dm_start_provider(dmItems->tankLevelAlarm, DM_STATIC);

                                    /* Wait for power up delay to expire     */
    dm_start_consumer(dmItems->inbdTankLevelAlarm,  DM_STATIC, dmUpdateSem);
    dm_start_consumer(dmItems->outbdTankLevelAlarm, DM_STATIC, dmUpdateSem);

    tankAlarmDelay = FALSE;
    lastTankAlarm  = MICRO_ALARM_OK;
    FOREVER
    {
         if ((dm_read( dmItems->inbdTankLevelAlarm, (char *) &inbdTankAlarm,
             sizeof(inbdTankAlarm), (DM_Time *) NULL) == OK) &&

             (dm_read( dmItems->outbdTankLevelAlarm, (char *) &outbdTankAlarm,
             sizeof(outbdTankAlarm), (DM_Time *) NULL) == OK))
         {
             tankAlarm = (((outbdTankAlarm == MICRO_ALARM) &&
                (inbdTankAlarm == MICRO_ALARM)) ? MICRO_ALARM : MICRO_ALARM_OK);

             if (tankAlarm != lastTankAlarm)
             {
                 if (tankAlarmDelay)
                 {
                     tankAlarmDelay = FALSE;
                     lastTankAlarm = tankAlarm;
                     writeDmItem(dmItems->tankLevelAlarm, &tankAlarm,
                        sizeof(tankAlarm));
                 } /* if */
                 else
                     tankAlarmDelay = TRUE;
             } /* if */
             else
                 tankAlarmDelay = FALSE;
         } /* if */

         if (tankAlarmDelay)
             semTake(dmUpdateSem, sysClkRateGet() * TANK_ALARM_DELAY);
         else
                                    /* Wait for an alarm to be written       */
             semTake(dmUpdateSem, WAIT_FOREVER);
    } /* FOREVER */
} /* acMicroMonitorTask() */

/*****************************************************************************/
/* Function    : processAcMicroSRQ                                           */
/* 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 Word
processAcMicroSRQ( Reg acMicroDmItems* dmItems, microIOControl *microIOCtrl)
{
    Byte buffer[SRQ_PACKET_LEN];    /* Buffer for micro communications data  */
    Word srqRequest;                /* Service Request Value                 */
    Word alarmStatus;               /* Microcontroller Alarm Status Word     */
    microAlarm alarm;               /* Alarm Status                          */

                                    /* Block on Reading Service Request      */
    if (readSRQPacket(SERIAL_CHAN, buffer, SRQ_PACKET_LEN,
                         WAIT_FOREVER) != ERROR)
                                    /* Service Request received so process it*/
        srqRequest = wordFromBuf(buffer, 0);

        switch (srqRequest)         /* Decode Service Request from micro     */
        {
          case MICRO_RESET_SRQ:     /* Microcontroller Reset Occurred        */
                                    /* Post Reset Event DM Item              */
            if (microIOCtrl->announceResets)
                microResetEventDm(dmItems->microDm.resetEvent);

            break;

          case WATER_ALARM_ON_SRQ:    /* Housing Water Alarm Active        */
            writeBooleanDmItem(dmItems->acCanWaterAlarm, TRUE);
            break;

          case WATER_ALARM_OFF_SRQ:   /* Housing Water Alarm Inactive      */
            writeBooleanDmItem(dmItems->acCanWaterAlarm, FALSE);
            break;

          case TETHER_CAN_WATER_ALARM_ON_SRQ:
            writeBooleanDmItem(dmItems->tetherCanWaterAlarm, TRUE);
            break;

          case TETHER_CAN_WATER_ALARM_OFF_SRQ:
            writeBooleanDmItem(dmItems->tetherCanWaterAlarm, FALSE);
            break;

          case HUMIDITY_ALARM_SRQ:
            break;

          case TEMPERATURE_ALARM_SRQ:
            wordsFromBuf(buffer, 2, &srqRequest, &alarmStatus);
            alarm = (microAlarm) alarmStatus;
            writeDmItem(dmItems->temperatureAlarm, &alarm, sizeof(alarm));
            break;

          case PRESSURE_ALARM_SRQ:
            wordsFromBuf(buffer, 2, &srqRequest, &alarmStatus);
            alarm = (microAlarm) alarmStatus;
            writeDmItem(dmItems->pressureAlarm, &alarm, sizeof(alarm));
            break;

          case OUTBD_TANK_LEVEL_ALARM_SRQ:
            wordsFromBuf(buffer, 2, &srqRequest, &alarmStatus);
            alarm = (microAlarm) alarmStatus;

            writeDmItem(dmItems->outbdTankLevelAlarm, &alarm, sizeof(alarm));
            break;

          case INBD_TANK_LEVEL_ALARM_SRQ:
            wordsFromBuf(buffer, 2, &srqRequest, &alarmStatus);
            alarm = (microAlarm) alarmStatus;

            writeDmItem(dmItems->inbdTankLevelAlarm, &alarm, sizeof(alarm));
            break;

          default:
            printf("AC Micro: Unrecognized SRQ 0x%x\n", srqRequest);
        } /* switch */

    return (srqRequest);                    /* Return SRQ Received to Caller */
} /* processAcMicroSRQ() */




