/****************************************************************************/
/* Copyright 1992 to 1998 MBARI                                             */
/****************************************************************************/
/* Summary  : Sensor Dcon Interface Module for VxWorks                      */
/* Filename : sensorDcon.c                                                  */
/* Author   : Andrew Pearce                                                 */
/* Project  : Tiburon                                                       */
/* Version  : Version 1.0                                                   */
/* Created  : 07/08/93                                                      */
/* Modified : 05/05/98                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: sensorDcon.c,v 1.1 94/06/14 14:15:48 pean Exp $
 * $Log:        sensorDcon.c,v $
 * Revision 1.1  94/06/14  14:15:48  14:15:48  pean (Andrew Pearce)
 * Initial revision
 * Revision 1.2  96/08/16  12:00:00  12:00:00  audo (Douglas Au)
 * Revision 1.2.1 02/02/11                     audo (Douglas Au)
 * Changed Scaling Factor of Transmissometer to 0-5V
 *
 */
/****************************************************************************/

#include <vxWorks.h>                /* vxWorks system declarations          */
#include <semLib.h>                 /* vxWorks semaphore functions          */
#include <taskLib.h>                /* vxWorks task library functions       */
#include <stdio.h>                  /* vxWorks standard I/O library         */
#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 "powerAlloc.h"             /* Device Power Requirements            */
#include "powerDM.h"                /* Power System Data Manager Items      */
#include "powerTypes.h"             /* Power management Data Types          */
#include "console.h"                /* Topside Console Data Manager Items   */

#include "sio32.h"                  /* Sio32 hardware and driver information*/
#include "sio32Server.h"            /* Sio32 server communication services  */
#include "sio32Client.h"            /* Sio32 client communication services  */
#include "sensorDcon.h"             /* Sensor Dcon Can Definitions          */
#include "sensorsDm.h"              /* Sensor Dm Prefix                     */
#include "medianFilter.h"           /* median filter data structers         */

#include "applic.h"                 /* Microcontroller applications         */
#include "microcmd.h"               /* Microcontroller commands             */
#include "microDm.h"                /* Micro Data Manager Items & Functions */

#define Boolean MBool               /* Map microcontroller Boolean to MBool */

#include "timer.h"                  /* IBC Micro Timer Definitions          */
#include "ibc_card.h"               /* IBC Card Types                       */
#include "ibc_cmd.h"                /* IBC Serial Commands                  */
#include "filter.h"                 /* IBC General IIR Filter Routines      */
#include "gf_board.h"               /* GF/5V Controller Board Definitions   */
#include "low_pwr.h"                /* Low Power Switch Board Definitions   */
#include "sensor.h"                 /* Sensor Dcon Micro definitions        */

#include "ibc.h"                    /* Function Prototypes for ibc.c        */
#include "switch.h"                 /* IBC Function Libarary Definitions    */
#include "ibcDm.h"                  /* IBC Data Manager Interface Functions */
#include "lpsDm.h"                  /* IBC LPS Board Interface Functions    */
#include "gf_5vDm.h"                /* IBC Ground Fault Board DMgr Functions*/
#include "gf_5v.h"                  /* IBC Ground Fault Board Definitions   */
#include "quadSerDm.h"              /* Quad Serial Board Data Manager Funcs */
#include "microTask.h"              /* Microcontroller Task IO definitions  */

#include "trimbleGps.h"		    /* for GPS_LATITUDE_DM 		    */
                                    /* Sensor Dcon Device Name              */
#include "math.h"		    /* for sin() and log()                  */
#include "trig.h"		    /* for M_PI definition		    */

MLocal char* const sensorDconName = "Sensor Dcon";
                                    /* Sensor Dcon Data Mgr Item Name Prefix*/
MLocal char* const sensorIbcDmPrefix  = SENSOR_IBC_DM_PREFIX;
MLocal char* const sensorDmPrefix  = SENSOR_DM_PREFIX;

#define GF5V_BOARD_ADDR     (Word) GROUND_FAULT_0_ADDR
#define ATOD_BOARD_ADDR     (Word) QUAD_A_TO_D_0_ADDR
#define SERIAL_BOARD_ADDR   (Word) QUAD_SERIAL_0_ADDR

#define LPS_BOARDS          2       /* Number of LPS Board in Sensor Dcon   */

MLocal Word lpsBoardAddr[LPS_BOARDS] =  /* LPS Board Assignments            */
{
    LOW_PWR_SWITCH_12V_0_ADDR,
    LOW_PWR_SWITCH_12V_1_ADDR
};

MLocal ibcCardConfig ibcCardSet =
{
    6,                              /* Number of IBC Cards Expected         */
    {
         CPU196,
         GF5V_BOARD_ADDR,
         LOW_PWR_SWITCH_12V_0_ADDR,
         LOW_PWR_SWITCH_12V_1_ADDR,
         ATOD_BOARD_ADDR,
         SERIAL_BOARD_ADDR
    }
};
                                      /* LPS 12V 0 Board Channel Assignments*/
#define CONDUCTIVITY_SWITCH_CHAN    1 /* Falmouth Conductivity Sensor Power */
#define TEMPERATURE_SWITCH_CHAN     2 /* Falmouth Pressure Sensor Power     */
#define PRESSURE_SWITCH_CHAN        3 /* Falmouth Pressure Sensor Power     */

                                      /* LPS 12V 1 Board Channel Assignments*/
#define SAMPLING_PUMP_SWITCH_CHAN   1 /* Oxygen Sensor Power                */
#define OXYGEN_SENSOR_SWITCH_CHAN   2 /* Oxygen Sensor Power                */
#define TRANSMISSOMETER_SWITCH_CHAN 3 /* Transmissometer Power              */

#define SENSOR_DM_PERIOD        100000 /* Sensor Data period 10 Hz          */
#define SENSOR_IBC_DM_PERIOD    500000 /* Sensor DCOn Data period 2 Hz      */
#define HUMIDITY_DM_PERIOD     2000000 /* Humidity sensor period .5Hz       */

#define SENSOR_IBC_IN_STACKSIZE   3000 /* Sensor Dcon Input Task size & TCB */
#define SENSOR_IBC_OUT_STACKSIZE  4000 /* Sensor Dcon Output Task size & TCB*/
#define SENSOR_TASK_STACKSIZE     4000 /* Sensor Dcon Sensor Task size & TCB*/

#define NUM_TASKS 4                    /* Number of co-operating tasks      */

                                       /* Build signed value from integer   */
                                       /* and fractional parts              */
#define FALMOUTH_VALUE(intPart, fractPart) (Flt64) ((((Flt64) abs(intPart)) + \
       (Flt64) fractPart / 10000.0) * (intPart < 0 ? -1.0 : 1.0))

#define OXYGEN_BITS_TO_VOLTS(bits) (( ((Flt32) bits) * 5.0) / 65536.0)

/* Tranmissometer range 0-5Volts */
#define TMISS_BITS_TO_VOLTS(bits)  (( ((Flt32) bits) * 5.0) / 65536.0)

#define STARTUP_COUNT    1000       /* startup period (100 secs at 10 Hz)   */
#define BLOCK_COUNT      250        /* blocking period (10 secs at 10 Hz)   */
#define DEPTH_THRESHOLD  0.6        /* depth delta threshold (metres)       */

typedef struct                      /* Sensor Dcon Data Manager Item Handles*/
{
    DM_Item powerSwitch;            /* Data Concentrator Power Switch       */
    DM_Item canWaterAlarm;          /* Housing Water Alarm Detected         */
    DM_Item jboxWaterAlarm;         /* J Box Water Alarm Detected           */
    DM_Item waterAlarmThresh;       /* Water Alarm Threshold                */

    ibcCpuDmItems  ibcDm;           /* IBC CPU Data Manager Items           */
    ibcGf5vDmItems gf5vDm;          /* GF/5V Board Data Manager Items       */
    ibcLpsDmItems  lpsDm[LPS_BOARDS];  /* LPS Board Data Manager Items      */
    ibcQuadSerDmItems quadSerDm;    /* Quad Serial Board Data Manager Items */
} sensorDconDmItems;

typedef struct                      /* Sensor Dcon Data Manager Item Handles*/
{
    DM_Item depth;
    DM_Item depthDataValid;

    DM_Item conductivity;
    DM_Item temperature;
    DM_Item pressure;
    DM_Item pressureOffset;

    DM_Item oxygenCurrent;
    DM_Item oxygenTemperature;
    DM_Item transmissometer;

    DM_Item pressureSwitchState;

    DM_Item latitude;
    DM_Item GPSlatitude;
    DM_Item depthValueValid;
    DM_Item depthAlgorithm;
    DM_Item useMedianFilter;

#if 0
    DM_Item setupCTDSensorsCmd;
#endif
} sensorDconSensorItems;


/****************************************************************************/

Void sensorDconInTask(Reg sensorDconDmItems *dmItems,
                      microIOControl *microIOCtrl);

Void sensorDconOutTask(Reg sensorDconDmItems* dmItems,
                       microIOControl *microIOCtrl);

Void sensorDconSensorInTask( microIOControl *microIOCtrl);

MLocal Word processSensorDconSRQ( Reg sensorDconDmItems* dmItems,
                                   microIOControl *microIOCtrl);

MLocal Void initSensorDconDmItems(sensorDconDmItems* dmItems,
    sio32Chan* sensorDconDataChan);

/****************************************************************************/
/* Function    : sensorCanReadCTDSensors                                    */
/* Purpose     : Reads CTD sensor values from Sensor Can IBC                */
/* Inputs      : Sio32 channel, pointers to C, T, & P                       */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
sensorCanReadCTDSensors( sio32Chan *IBC_SerialChan, Flt64 *conductivity,
    Flt64 *temperature, Flt64 *pressure )
{
    struct
    {
        Int16  integer;
        Int16  fraction;
    } cond, temp, pres;

    Int16   cmdStatus;              /* Command Status                       */
    Word    reply[7];               /* Command Result from microcontroller  */

                                    /* Send command to VME IBC micro        */
    if ( sendMicroCommand( IBC_SerialChan, &reply, sizeof(Word) * 7,
         1, SENSOR_IBC_APP | GET_CTD_SENSOR_DATA) == 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, 7, &cmdStatus,  &cond.integer, &cond.fraction,
         &temp.integer, &temp.fraction, &pres.integer, &pres.fraction);


    *conductivity = FALMOUTH_VALUE(cond.integer, cond.fraction);
    *temperature  = FALMOUTH_VALUE(temp.integer, temp.fraction);
    *pressure     = FALMOUTH_VALUE(pres.integer, pres.fraction);

    return (OK);
} /* sensorCanReadCTDSensors() */


/****************************************************************************/
/* Function    : calcDepthFM                                                */
/* Purpose     : Calculates depth from pressure using Fofonoff & Millard    */
/* From paper; w/o geopotential anomaly                                     */
/* Inputs      : pressure, depth (pointer)                       	    */
/* Outputs     : Returns OK or ERROR on range error                         */
/****************************************************************************/
LOCAL STATUS
calcDepthFM(Flt64 P, Flt64 L, Flt64 *depth, MBool doGACorrection)
{
  static const Flt64 a0 = 5.2788E-3;
  static const Flt64 a1 = 2.36E-5;
  static const Flt64 c4 = -1.82e-15;
  static const Flt64 c3 = 2.279e-10;
  static const Flt64 c2 = -2.2512e-5;
  static const Flt64 c1 = 9.72659;
  static const Flt64 gv = 2.184E-6;
  static const Flt64 K  = 21582.27;
  static const Flt64 A  = 3.35941;
  static const Flt64 B  = 5.032E-5;
  static const Flt64 V  = 9.72662E-4;

  Flt64 phi;
  Flt64 sinPhi,X;
  Flt64 g0;
  Flt64 dd,T1,T2,R;  

  /* Calculate coefficients using latitude */
  phi = L*M_PI/180.0;
  sinPhi  = sin(phi);
  X = sinPhi*sinPhi;

  g0 = 9.780318*(1.0 + (a0 + a1*X)*X)+gv*P/2;

  /* do range checking */
  if( g0==0 )
    return(ERROR);

  /* do the depth calculation */
   *depth = (((c4*P+c3)*P+c2)*P+c1)*P/g0;

  if(doGACorrection == FALSE)
    return OK;

  R =  sqrt(A*A-4*B*K);
  T1 = log(1+A*P/K+B*P*P/K);
  T2 = log(((2*B*P+A-R)/(A-R))/((2*B*P+A+R)/(A+R)));
  dd = V*(P-(T1+A*T2/R)/(2*B));
  
  *depth+=(dd/9.8);

  return(OK);
}/* calcDepthFM() */


/****************************************************************************/
/* Function    : calcDepthSF                                                */
/* Purpose     : Calculates depth from pressure using Saunders & Fofonoff   */
/* from MBARI memo                                                          */
/* Inputs      : pressure, depth (pointer)                       	    */
/* Outputs     : Returns OK or ERROR on range error                         */
/****************************************************************************/
LOCAL STATUS
calcDepthSF(Flt64 P, Flt64 L, Flt64 *depth)
{
  static const Flt64 a0 = 5.3024e-3;
  static const Flt64 a1 = -5.9e-6;
  static const Flt64 c1 = 0.712953;
  static const Flt64 c2 = 1.113e-7;
  static const Flt64 c3 = -3.434e-12;
  static const Flt64 c4 = 14190.7;
  static const Flt64 c5 = 1.83e-5;
  static const Flt64 gv = 0.5*2.226e-4;
  Flt64 phi;
  Flt64 sinPhi;
  Flt64 sin2Phi;
  Flt64 g0;
  Flt64 T1,T2;  

  /* Calculate coefficients using latitude */
  phi = L*M_PI/180.0;  /* Convert degrees to radians */
  sinPhi  = sin(phi);
  sin2Phi = sin(2*phi);
  g0 = 978.0318*(1 + a0*sinPhi*sinPhi + a1*sin2Phi*sin2Phi);

  /* do range checking */
  T1 = (1 + c5*P);
  T2 = (g0 + gv*P);
  if( (T1 <= 0) || (T2 == 0) )
    return(ERROR);

  /* do the depth calculation */

  *depth = (Flt64)(1000*((c1 + (c2 + c3*P)*P)*P + c4*log(T1))/(T2));

  return(OK);

}/* calcDepthSF() */

    MLocal Void
sensorCanUpdateCTDSensors( sio32Chan *sensorDconSerialChan,
    sensorDconSensorItems *dmItems, MedianFilter *depthFilter)
{
						/* previous switch state    */
    static switchStatus prevPressureSwitchState = SWITCH_OFF;
    static MBool        startUp = FALSE;        /* startup sensor flag      */
    static MBool        blockUpdate = FALSE;    /* block data update flag   */
    static MBool        depthDataValid = FALSE; /* depth data valid flag    */
    static Int16        startupCount = 9999;    /* startup counter          */
    static Int16        count = 0;              /* counter                  */
    static Flt64        prevDepth = 0.0;        /* previous depth value     */
    switchStatus        pressureSwitchState;    /* pressure switch state    */
    Flt64               conductivity;           /* Sensor values            */
    Flt64               temperature;
    Flt64               pressure, depth;        /* values from Sensor IBC   */
    Flt64               pressureOffset;         /* Surface pressure offset  */
    Flt64		latitude;               /* Used for depth calc      */
    Errno               status;                 /* Generic return test      */
    static MBool        depthValueValid = FALSE; /* depth value valid flag  */
    MBool		useMedianFilter = TRUE;	/* Enable Median Filter     */
    Nat16               depthAlgorithm=2;       /*  */
    static MBool        prevDepthValueValid = FALSE; /* depth value valid flag    */


    if (startupCount == 9999)           /* initialize depth data valid      */
    {
        writeBooleanDmItem(dmItems->depthDataValid, FALSE);
        writeBooleanDmItem(dmItems->useMedianFilter, useMedianFilter);
        writeDmItem(dmItems->depthAlgorithm, &depthAlgorithm,sizeof(depthAlgorithm));
	
        startupCount = 0;
    }

    /* Default calculation result */
    depthValueValid = FALSE;

    if (sensorCanReadCTDSensors(sensorDconSerialChan, &conductivity,
          &temperature, &pressure) == OK)
    {
	status = dm_read(dmItems->pressureOffset, &pressureOffset,sizeof(pressureOffset), (DM_Time *) NULL);

        if( status  == SUCCESS){
	   pressure -= pressureOffset; /* Subtract surface pressure offset     */

	  /* Get latitude */
	  status = dm_read (dmItems->GPSlatitude, &latitude, sizeof(latitude),(DM_Time *) NULL);
	  writeDmItem(dmItems->latitude, &latitude,sizeof(latitude));


	  if ( status == SUCCESS){
  	     /* Convert pressure to meters          */
	     dm_read (dmItems->depthAlgorithm,&depthAlgorithm, sizeof(depthAlgorithm),(DM_Time *) NULL);

	     switch(depthAlgorithm){
	     case 0:
	       depth = pressure * DECIBARS_TO_METERS;
	       depthValueValid = TRUE;
	       break;
	     case 1:
	     if( calcDepthSF(pressure, latitude, &depth) == OK )
		depthValueValid = TRUE;
	       break;
	     case 2:
	     if( calcDepthFM(pressure, latitude, &depth, FALSE) == OK )
		depthValueValid = TRUE;
	       break;
	     case 3:
	     if( calcDepthFM(pressure, latitude, &depth,TRUE) == OK )
		depthValueValid = TRUE;
	       break;
	     default:
	       depth = pressure * DECIBARS_TO_METERS;
	       depthValueValid = TRUE;
	       break;
	     }
	   }
         }


        /* Check calculation result */
	if(depthValueValid == TRUE){
	  prevDepth = depth;
	}else{
	  depth = prevDepth;
	}

	/* if depthValueValid has changed, write the dmItem */
	if(depthValueValid!=prevDepthValueValid)
	  writeDmItem(dmItems->depthValueValid, &depthValueValid,
                            sizeof(depthValueValid));

	prevDepthValueValid=depthValueValid;

                                    /* Filter to remove spikes in depth data*/
                                    /* removes outliers of duration less than*/
                                    /* half the median filter sample number */
 
	dm_read (dmItems->useMedianFilter, &useMedianFilter, sizeof(useMedianFilter),(DM_Time *) NULL);
        if(useMedianFilter == TRUE)
        depth = (Flt64) medianFilter( depthFilter, (Flt32) depth );


                                        /* read the pressure switch status  */
        dm_read(dmItems->pressureSwitchState, &pressureSwitchState,
                sizeof(pressureSwitchState), (DM_Time *) NULL);

                                        /* on power up of sensor, wait      */
                                        /* startup period for depth data to */
                                        /* be valid                         */
        if (pressureSwitchState != prevPressureSwitchState)
        {
            if (pressureSwitchState == SWITCH_ON)
                startUp = TRUE;

            else if (depthDataValid)
            {
                depthDataValid = FALSE;
                writeDmItem(dmItems->depthDataValid, &depthDataValid,
                            sizeof(depthDataValid));
                if (startUp)
                {
                    startUp = FALSE;
                    startupCount = 0;
                }
                if (blockUpdate)
                {
                    blockUpdate = FALSE;
                    count = 0;
                }
            }
        }
        prevPressureSwitchState = pressureSwitchState;
        if (startUp)
        {
            startupCount++;
            if (startupCount > STARTUP_COUNT)
            {
                startupCount = 0;
                startUp = FALSE;
                depthDataValid = TRUE;
                writeDmItem(dmItems->depthDataValid, &depthDataValid,
                            sizeof(depthDataValid));
            }
        }

                                    /* block depth data update of outliers  */
                                    /* that decay with a time constant      */
        if ( (!startUp) && (!blockUpdate) )
        {
            if (fabs(depth - prevDepth) > DEPTH_THRESHOLD)
            {
                blockUpdate = TRUE;
                depthDataValid = FALSE;
/*              writeDmItem(dmItems->depthDataValid, &depthDataValid,
                            sizeof(depthDataValid)); */
            }
        }
        if (blockUpdate)
        {
            count++;
/*          depth = prevDepth; */
            if (count > BLOCK_COUNT)/* unblock depth update after set period*/
            {
                count = 0;
                blockUpdate = FALSE;
                if (pressureSwitchState == SWITCH_ON)
                {
                    depthDataValid = TRUE;
                    writeDmItem(dmItems->depthDataValid, &depthDataValid,
                                sizeof(depthDataValid));
                }
            }
        }
        else
            prevDepth = depth;


        writeDmItem(dmItems->conductivity, &conductivity, sizeof(conductivity));
        writeDmItem(dmItems->temperature,  &temperature,  sizeof(temperature));
        writeDmItem(dmItems->pressure,     &pressure,     sizeof(pressure));
        writeDmItem(dmItems->depth,        &depth,        sizeof(depth));

    } /* if sensorCanReadCTDSensors == OK*/
    else
    {
        if (depthDataValid)             /* reset data valid flag to FALSE */
        {
            depthDataValid = FALSE;
            writeDmItem(dmItems->depthDataValid, &depthDataValid,
                        sizeof(depthDataValid));
        }
    }

} /* sensorCanUpdateCTDSensors() */

#if 0
/****************************************************************************/
/* Function    : sensorCanSetupCTDSensors                                   */
/* Purpose     : Setup CTD sensors from Sensor Can IBC                      */
/* Inputs      : Sio32 channel                                              */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
sensorCanSetupCTDSensors( sio32Chan *IBC_SerialChan )
{

    Word    reply[1];               /* Command Result from microcontroller  */

                                    /* Send command to VME IBC micro        */
    if ( sendMicroCommand( IBC_SerialChan, &reply, sizeof(Word),
         1, SENSOR_IBC_APP | SETUP_CTD_SENSORS) == ERROR )
     return(ERROR);

                                    /* Check if command result is CMD OK    */
    if (wordFromBuf(&reply, 0) != CMD_OK)
        return(ERROR);              /* Command failed so return ERROR       */

    return (OK);
} /* sensorCanSetupCTDSensors() */
#endif

    MLocal STATUS
sensorCanUpdateOxygenXmiss( sio32Chan *sensorDconSerialChan,
    sensorDconSensorItems *dmItems)
{
    Nat16 transmissometer;
    Nat16 oxygenCurrent, oxygenTemperature;

    Int16   cmdStatus;              /* Command Status                       */
    Word    reply[4];               /* Command Result from microcontroller  */
    Flt32   fltValue;

                                    /* Send command to VME IBC micro        */
    if ( sendMicroCommand( sensorDconSerialChan, &reply, sizeof(Word) * 4,
         1, SENSOR_IBC_APP | GET_SENSOR_DATA) == 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, 4, &cmdStatus,  &oxygenCurrent, &oxygenTemperature,
         &transmissometer);

    fltValue = TMISS_BITS_TO_VOLTS(transmissometer);
    writeDmItem(dmItems->transmissometer, &fltValue, sizeof(fltValue));

    fltValue = OXYGEN_BITS_TO_VOLTS(oxygenCurrent);
    writeDmItem(dmItems->oxygenCurrent, &fltValue, sizeof(fltValue));

    fltValue = OXYGEN_BITS_TO_VOLTS(oxygenTemperature);
    writeDmItem(dmItems->oxygenTemperature, &fltValue, sizeof(fltValue));

    return(OK);
} /* sensorCanOxygenXmiss() */

/****************************************************************************/
/* Function    : sensorCanGetWaterAlarm                                     */
/* Purpose     : Read water alarm status from Sensor Dcon microcontroller   */
/* Inputs      : Sio32 socket and pointer to water alarm status             */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
sensorCanGetWaterAlarm( sio32Chan *IBC_SerialChan, Word *waterAlarmStatus )
{
                                    /* Send command to microcontroller      */
    return( microCommand(IBC_SerialChan, SENSOR_IBC_APP | GET_WATER_ALARM,
                        waterAlarmStatus) );
} /* sensorCanGetWaterAlarm() */

/****************************************************************************/
/* Function    : sensorGetWaterAlarmThresh                                  */
/* Purpose     : Reads water alarm threshold value from IBC CPU             */
/* Inputs      : Sio32 channel, pointer to water alarm threshold            */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
sensorGetWaterAlarmThresh( sio32Chan *IBC_SerialChan, Int16 *waterAlarmThresh )
{
                                    /* Send command to microcontroller      */
    return (microCommand( IBC_SerialChan,
          SENSOR_IBC_APP | GET_WATER_ALARM_THRESH, waterAlarmThresh) );
} /* sensorGetWaterAlarmThresh() */

/****************************************************************************/
/* Function    : initWaterAlarmThreshDm                                     */
/* Purpose     : Read Water Alarm Threshold and update data manager item    */
/* Inputs      : Sio32 channel, water alarm threshold dm item handle        */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
initWaterAlarmThreshDm( sio32Chan *IBC_SerialChan, DM_Item waterAlarmThreshDm )
{
    Int16   waterAlarmThresh;           /* Water Alarm Threshold from IBC   */

                                        /* Get Water Alarm Threshold        */
    if (sensorGetWaterAlarmThresh( IBC_SerialChan, &waterAlarmThresh ) != OK)
        return (ERROR);
                                        /* We MUST use urgent open here as  */
                                        /* another task is normal provider  */
    return (urgentWriteDmItem(waterAlarmThreshDm, &waterAlarmThresh,
                      sizeof(waterAlarmThresh)) );
} /* initWaterAlarmThreshDm() */

/****************************************************************************/
/* Function    : writeWaterAlarmThresh                                      */
/* Purpose     : Get water alarm threshold value from dm and send to IBC    */
/* Inputs      : Sio32 channel, water threshold dm item handle              */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
writeWaterAlarmThresh( sio32Chan *sio32DataChan, DM_Item waterAlarmThreshDm )
{
    Errno   status;                     /* Result of dm_read                */
    Int16   waterAlarmThresh;           /* Water Alarm Threshold            */

                                        /* Read Water Alarm Thresh from dmgr*/
    status = dm_read( waterAlarmThreshDm, (char *) &waterAlarmThresh,
         sizeof(waterAlarmThresh), (DM_Time *) NULL);
                                        /* Check for successful dm_read     */
    if ((status == SUCCESS) || (status == EDM_NOPROVIDER))

                                        /* Send command to microcontroller  */
        if ( sendMicroCommand( sio32DataChan, &status, sizeof(status), 2,
             SENSOR_IBC_APP | SET_WATER_ALARM_THRESH, waterAlarmThresh )
             != ERROR )
                                       /* Check command result              */
            return (wordFromBuf(&status, 0) == CMD_OK ? OK : ERROR);

    return(ERROR);
} /* writeWaterAlarmThresh() */

/****************************************************************************/
/* Function    : updateWaterAlarmDm                                         */
/* Purpose     : Reads micro Water Alarm status & updates dmgr items        */
/* Inputs      : Sio32 chan & water alarm status data manager item handles  */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
updateWaterAlarmDm( sio32Chan *sio32DataChan,
    DM_Item canWaterAlarmDm, DM_Item jboxWaterAlarmDm )
{
    Word waterAlarmStatus;          /* Microcontroller Water Alarm Status   */
    MBool status;                   /* Boolean state of Water Alarm         */
                                    /* Read Water Alarm Status              */
    if (sensorCanGetWaterAlarm(sio32DataChan, &waterAlarmStatus) != OK)
        return(ERROR);

    status = ( (waterAlarmStatus & HOUSING_WATER_ALARM_BIT) ? TRUE : FALSE);
    writeDmItem(canWaterAlarmDm, &status, sizeof(status));

    status = ( (waterAlarmStatus & JBOX_WATER_ALARM_BIT) ? TRUE : FALSE);

                                    /* Write water alarm status to Dmgr     */
    return ( writeDmItem(jboxWaterAlarmDm, &status, sizeof(status)) );
} /* updateWaterAlarmDm() */

/****************************************************************************/
/* Function    : createSensorDconAppDmItems                                 */
/* Purpose     : Create Data Mgr Items specific to Sensor Dcon Application  */
/* Inputs      : Pointer to structure of DM item handles, Dcon DM prefix,   */
/*               Sensor DM prefix, Sensor Data Concentrator Name            */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
createSensorDconAppDmItems( sensorDconDmItems *sensorDmItems,
     const char* sensorDconDmPrefix, const char* sensorIbcDmPrefix,
     const char* sensorDconName )
{
    dmItemList sensorDconDmInit[] =

     {  { &sensorDmItems->canWaterAlarm,     "Housing Water Alarm",
                HOUSING_WATER_ALARM_DM,           DM_MBOOL, 1 },

        { &sensorDmItems->jboxWaterAlarm,    "J Box Water Alarm",
                JBOX_WATER_ALARM_DM,              DM_MBOOL, 1 },

        { &sensorDmItems->waterAlarmThresh,  "Water Alarm Threshold",
                WATER_ALARM_THRESH_DM,            DM_NAT16, 1 },

        { NO_ITEM, NULL, NULL, DM_ENDT, 0 } };

                                 /* Initialize Data Manager Items from table*/
    if (initMicroDmItemList( sensorDconDmInit, sensorIbcDmPrefix,
        "Sensor Dcon I/F" ) != OK)
        return(ERROR);

    if ( (sensorDmItems->powerSwitch = initMicroDmItem(
         "", SENSOR_DCON_SWITCH_STATUS_DM, DM_ENUM, 1)) == ERROR)
    {
        logMsg("Sensor Dcon I/F: Error initializing Dcon Power Switch Item\n");
        return (ERROR);
    } /* if */

                                     /* Declare this task an item provider  */
    dm_start_provider(sensorDmItems->canWaterAlarm,  DM_STATIC);
    dm_start_provider(sensorDmItems->jboxWaterAlarm, DM_STATIC);

    dm_start_consumer(sensorDmItems->powerSwitch, DM_STATIC, SEM_NULL);

    return(OK);
} /* createSensorDconAppDmItems() */

/****************************************************************************/
/* Function    : createSensorDconSensorDmItems                              */
/* Purpose     : Create Data Mgr Items specific to Sensor Dcon Application  */
/* Inputs      : Pointer to structure of DM item handles, Dcon DM prefix,   */
/*               Sensor DM prefix, Sensor Data Concentrator Name            */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    LOCAL STATUS
createSensorDconSensorDmItems( sensorDconSensorItems *sensorDmItems,
     const char* sensorDconDmPrefix, const char* sensorIbcDmPrefix,
     const char* sensorDconName )
{
    dmItemList sensorDconDmInit[] =

     {  { &sensorDmItems->conductivity,      "Conductivity Sensor Reading",
                CONDUCTIVITY_SENSOR_DM,           DM_FLT64, 1 },

        { &sensorDmItems->temperature,       "Temperature Sensor Reading",
                TEMPERATURE_SENSOR_DM,            DM_FLT64, 1 },

        { &sensorDmItems->pressure,          "Pressure Sensor Reading",
                PRESSURE_SENSOR_DM,               DM_FLT64, 1 },

        { &sensorDmItems->pressureOffset,    "Pressure Sensor Offset",
                PRESSURE_SENSOR_OFFSET_DM,        DM_FLT64, 1 },

        { &sensorDmItems->oxygenCurrent,     "Oxygen Sensor Current",
                OXYGEN_SENSOR_RAW_CURRENT_VOLTS_DM, DM_FLT32, 1 },

        { &sensorDmItems->oxygenTemperature, "Oxygen Sensor Temperature",
                OXYGEN_SENSOR_RAW_TEMP_VOLTS_DM,    DM_FLT32, 1 },

        { &sensorDmItems->transmissometer,   "Transmissometer Reading",
                TRANSMISSOMETER_SENSOR_DM,        DM_FLT32, 1 },
#if 0
        { &sensorDmItems->setupCTDSensorsCmd,"Setup CTD Sensors Command",
                SETUP_CTD_SENSORS_CMD_DM,         DM_EMPTY, 1 },
#endif
        { NO_ITEM, NULL, NULL, DM_ENDT, 0 } };


    dmItemList sensorDmInit[] =

     {  { &sensorDmItems->depth,            "Vehicle Depth",
                DEPTH_METERS_DM,                  DM_FLT64, 1 },
        { &sensorDmItems->depthDataValid,   "Vehicle Depth Data Valid",
                DEPTH_DATA_VALID_DM,              DM_MBOOL, 1 },
        { &sensorDmItems->depthValueValid,   "Vehicle Depth Value Valid",
                DEPTH_VALUE_VALID_DM,             DM_MBOOL, 1 },
        { &sensorDmItems->useMedianFilter,   "Use Median Filter",
                USE_MEDIAN_FILTER_DM,             DM_MBOOL, 1 },
        { &sensorDmItems->latitude,         "Sensor Latitude",
                LATITUDE_DM,                      DM_FLT64, 1 },
        { &sensorDmItems->depthAlgorithm,   "Depth Algorithm",
                DEPTH_ALGORITHM_DM,               DM_NAT16, 1 },
        { NO_ITEM, NULL, NULL, DM_ENDT, 0 } };


                                 /* Initialize Data Manager Items from table*/
    if (initMicroDmItemList( sensorDconDmInit, sensorIbcDmPrefix,
        "Sensor Dcon I/F" ) != OK)
        return(ERROR);

                                 /* Initialize Data Manager Items from table*/
    if (initMicroDmItemList( sensorDmInit, sensorDmPrefix,
        "Sensor Dcon I/F" ) != OK)
        return(ERROR);

                                 /* Initialize GPS DM Item*/
    if ( (sensorDmItems->GPSlatitude =
          initMicroDmItem("", WF_GPS_LATITUDE_DM, DM_FLT64, 1))
          == ERROR)
    {
        logMsg("Sensor Dcon I/F: Error initializing GPS Item\n");
        return (ERROR);
    } /* if */

                                 /* Initialize pressure switch status DM Item*/
    if ( (sensorDmItems->pressureSwitchState =
          initMicroDmItem("", PRESSURE_SENSOR_SWITCH_STATUS_DM, DM_ENUM, 1))
          == ERROR)
    {
        logMsg("Sensor Dcon I/F: Error initializing GPS Item\n");
        return (ERROR);
    } /* if */

                                 /* Declare this task an item provider      */
    dm_start_provider(sensorDmItems->conductivity,      SENSOR_DM_PERIOD);
    dm_start_provider(sensorDmItems->temperature,       SENSOR_DM_PERIOD);
    dm_start_provider(sensorDmItems->pressure,          SENSOR_DM_PERIOD);

    dm_start_provider(sensorDmItems->depth,             SENSOR_DM_PERIOD);
    dm_start_provider(sensorDmItems->oxygenCurrent,     SENSOR_DM_PERIOD);
    dm_start_provider(sensorDmItems->oxygenTemperature, SENSOR_DM_PERIOD);
    dm_start_provider(sensorDmItems->transmissometer,   SENSOR_DM_PERIOD);

    dm_start_provider(sensorDmItems->depthDataValid,     DM_STATIC);
    dm_start_provider(sensorDmItems->depthValueValid,    DM_STATIC);

    dm_start_consumer(sensorDmItems->pressureOffset,     DM_STATIC, SEM_NULL);
    dm_start_consumer(sensorDmItems->pressureSwitchState,DM_ASYNC,  SEM_NULL);

    dm_start_provider(sensorDmItems->latitude,           SENSOR_DM_PERIOD);
    dm_start_consumer(sensorDmItems->GPSlatitude,        DM_ASYNC,  SEM_NULL);

    dm_start_provider(sensorDmItems->depthAlgorithm,     DM_STATIC);
    dm_start_provider(sensorDmItems->useMedianFilter,     DM_STATIC);
    dm_start_consumer(sensorDmItems->depthAlgorithm,     DM_STATIC, SEM_NULL);
    dm_start_consumer(sensorDmItems->useMedianFilter,    DM_STATIC, SEM_NULL);


    return(OK);
} /* createSensorDconSensorDmItems() */

/****************************************************************************/
/* Function    : sensorDconTask                                             */
/* Purpose     : Initializes communication with Sensor Data Concentrator.   */
/*               Provides interface between Sensor Data Concentrator and    */
/*               Data Manager items.                                        */
/* Inputs      : SIO32 serial channel number for Sensor Data Concentrator   */
/*               Physically maps the Data Concentrators to a serial channel */
/* Outputs     : Normally runs forever, but returns ERROR on fatal error    */
/****************************************************************************/
    STATUS
sensorDconTask( Nat16 sensorDconSerialChan )
{
    sensorDconDmItems sensorDmItems; /* Sensor Application Data Mgr handles */
    microIOControl microIOCtrl;      /* Microcontroller IO Task control     */
    Int16   lps;                     /* Low Power Switch Board Index        */

                                    /* Initialize serial channel and task     */
                                    /* synchronization resources              */
    if (initMicroTaskIO( &microIOCtrl, NUM_TASKS, sensorDconSerialChan,
        sensorIbcDmPrefix, "/sio32/sensorDcon",
        SENSOR_DCON_SWITCH_STATUS_DM ) == ERROR)
    {
        logMsg("Error initializing IO for Sensor DCon");
        return(ERROR);
    } /* if */

                                    /* Clear Sensor DCon Data Manager handles*/
    bzero(&sensorDmItems, sizeof(sensorDmItems));

                                   /* Create IBC CPU Data Manager Items     */
    if (createIbcCpuDmItems(&(sensorDmItems.ibcDm), sensorIbcDmPrefix,
            sensorDconName)     == ERROR)
    {                              /* Error occurred so print message & exit*/
        sio32ChanDestroy( sensorDconSerialChan, &microIOCtrl.sio32DataChan );
        return(ERROR);
    } /* if */

                                   /* Create Sensor Dcon Application Items  */
    if (createSensorDconAppDmItems(&sensorDmItems, sensorIbcDmPrefix,
           sensorIbcDmPrefix, sensorDconName) == ERROR)
    {                              /* Error occurred so print message & exit*/
        sio32ChanDestroy( sensorDconSerialChan, &microIOCtrl.sio32DataChan );
        return(ERROR);
    } /* if */

                                    /* Create GF/5V Board Data Manager Items*/
    createIbcGf5vDmItems( &sensorDmItems.gf5vDm, sensorIbcDmPrefix,
         sensorDconName );

    initIbcGf5vAlarmProvider( &sensorDmItems.gf5vDm );

    for (lps = 0; lps < LPS_BOARDS; lps++)
    {                               /* Create IBC LPS Data Manager Items    */
        createIbcLpsDmItems( &sensorDmItems.lpsDm[lps], sensorIbcDmPrefix,
                sensorDconName, lps );
        initIbcLpsAlarmProvider( &sensorDmItems.lpsDm[lps] );
    } /* for */

                                    /* Create Quad Serial Data Mgr Items    */
    createIbcQuadSerDmItems( &sensorDmItems.quadSerDm, sensorIbcDmPrefix,
        sensorDconName, 0);
    initIbcQuadSerAlarmProvider( &sensorDmItems.quadSerDm );

                                    /* Initialize Sensor Dcon Data Out Task   */
    if ((microIOCtrl.childTasks[OUT_TASK].taskId =
         taskSpawn("sensorDconOut", SENSOR_IBC_OUT_PRIORITY, 0,
         SENSOR_IBC_OUT_STACKSIZE, (FUNCPTR) sensorDconOutTask,
         (int) &sensorDmItems, (int) &microIOCtrl,
         0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    {
                                    /* Close serial communication channel     */
        sio32ChanDestroy( sensorDconSerialChan, &microIOCtrl.sio32DataChan );
        logMsg("Sensor Dcon: Error spawning data output task\n");
        return(ERROR);
    } /* if */

                                    /* Initialize Sensor Dcon Data In Task    */
    if (( microIOCtrl.childTasks[IN_TASK].taskId =
         taskSpawn( "sensorDconIn", SENSOR_IBC_IN_PRIORITY, 0,
         SENSOR_IBC_IN_STACKSIZE, (FUNCPTR) sensorDconInTask,
         (int) &sensorDmItems, (int) &microIOCtrl,
         0, 0, 0, 0, 0, 0, 0, 0) ) == ERROR)
    {                               /* Delete Sensor Dcon Out Task            */
        taskDelete(microIOCtrl.childTasks[OUT_TASK].taskId);
        sio32ChanDestroy( sensorDconSerialChan, &microIOCtrl.sio32DataChan );
        logMsg("Sensor Dcon: Error spawning data input task\n");
        return(ERROR);
    } /* if */

                                    /* Initialize Sensor Dcon Sensor In Task  */
    if (( microIOCtrl.childTasks[AUX_IN_TASK].taskId =
         taskSpawn("sensorDconSensorIn", SENSOR_IBC_SENSOR_PRIORITY, VX_FP_TASK,
         SENSOR_TASK_STACKSIZE, (FUNCPTR) sensorDconSensorInTask,
         (int) &microIOCtrl,  0, 0, 0, 0, 0, 0, 0, 0, 0) ) == ERROR)
    {                               /* Delete Sensor Dcon Out and IN Tasks    */
        taskDelete(microIOCtrl.childTasks[OUT_TASK].taskId);
        taskDelete(microIOCtrl.childTasks[IN_TASK].taskId);
        sio32ChanDestroy( sensorDconSerialChan, &microIOCtrl.sio32DataChan );
        logMsg("Sensor Dcon: Error spawning sensor input task\n");
        return(ERROR);
    } /* if */

    FOREVER
    {                               /* Check if Dcon is switched on           */
        if ((microDevPowerSwitchState(&microIOCtrl) != SWITCH_ON) ||
           ((microDevPowerSwitchState(&microIOCtrl) == SWITCH_ON) &&
            (microIOCtrl.resetEventCount != 0)))

                                    /* Process SRQ's from micro               */
           while(processSensorDconSRQ(&sensorDmItems, &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);

        /******* Re-initialize Data Manager items after reset received ***** */

        if (initIbcCpuDmItems( &sensorDmItems.ibcDm, &microIOCtrl.sio32DataChan,
            sensorDconName, ibcCardSet ) == OK)
        {
            initSensorDconDmItems( &sensorDmItems, &microIOCtrl.sio32DataChan );

            updateIbcGf5vAlarmsDm( &microIOCtrl.sio32DataChan, GF5V_BOARD_ADDR,
                     &sensorDmItems.gf5vDm );

            for (lps = 0; lps < LPS_BOARDS; lps++)
                 updateIbcLpsAlarmsDm(&microIOCtrl.sio32DataChan,
                     lpsBoardAddr[lps], &sensorDmItems.lpsDm[lps] );

            updateIbcQuadSerAlarmsDm( &microIOCtrl.sio32DataChan,
                     SERIAL_BOARD_ADDR, &sensorDmItems.quadSerDm );

                                    /* Wake up output task to configure micro*/
            semGive(microIOCtrl.childTasks[OUT_TASK].taskSyncSem);
        } /* if */
        else
            setSerialLinkState(&microIOCtrl, LINK_DOWN);

    } /* FOREVER */

                                    /* Delete Child Tasks                     */
    taskDelete(microIOCtrl.childTasks[IN_TASK].taskId);
    taskDelete(microIOCtrl.childTasks[OUT_TASK].taskId);
    taskDelete(microIOCtrl.childTasks[AUX_IN_TASK].taskId);


                                    /* Close serial communication channel    */
    sio32ChanDestroy( sensorDconSerialChan, &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                                  */
} /* sensorDconTask() */

/*****************************************************************************/
/* Function    : initSensorDconDmItems                                       */
/* Purpose     : Reads parameters from Sensor Dcon & update Data Mgr items   */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : None, but Data Manager Items change                         */
/*****************************************************************************/
    LOCAL Void
initSensorDconDmItems( sensorDconDmItems* dmItems, sio32Chan*
    sensorDconDataChan )
{
                                /* Set Micro Water Alarms initial value      */
    if (updateWaterAlarmDm(sensorDconDataChan,
             dmItems->canWaterAlarm, dmItems->jboxWaterAlarm) == ERROR)
          logMsg("Sensor Dcon: Error checking water alarm status\n");

} /* initSensorDconDmItems() */

/*****************************************************************************/
/* Function    : sensorDconOutTask                                           */
/* Purpose     : Sensor Dcon Out Task. Read DM items & write to Sensor Dcon  */
/* Inputs      : Array of Data Manager Item handles & serial chan structure  */
/* Outputs     : Normally runs forever, but exits if error occurs            */
/*****************************************************************************/
    Void
sensorDconOutTask(Reg sensorDconDmItems *dmItems, microIOControl *microIOCtrl)
{
    DM_Group cpuGroup;              /* CPU & Misc Item Data Manager Group    */
    DM_Group gf5vGroup;             /* GF/5V Board Data Manager Group        */
    DM_Group lpsGroup[LPS_BOARDS];  /* LPS Board Data Manager Group          */

    SEM_ID  dmUpdateSem;            /* Data Manager Item Change wakeup sem   */
    SEM_ID  powerReqSem;            /* Power Request Update Semaphore        */

    Int16 board;                    /* LPS Board Index                       */

    cpuUpdateBits   ibcCpuBits;     /* CPU Board Parameter Update Bits       */
    gf5vUpdateBits  gf5vBits;       /* GF/5V Board Paramater Update Bits     */
    lpsUpdateBits   lpsBits[LPS_BOARDS];  /* LPS Board Paramater Update Bits */

    DWord   sensorDconGroupBits;    /* Holds dm_group_changes bit vector     */
    DWord   waterAlarmThreshBit;    /* Water alarm threshold item change bit */

    DWord   lpsEnableBit[LPS_BOARDS]; /* LPS Enable Request change bit       */
    DWord   sensorDconSwitchBit;    /* Sensor Dcon Switch Request changed bit*/

    DWord   conductivitySwitchBit;  /* Pressure Switch Request changed bit   */
    DWord   temperatureSwitchBit;   /* Pressure Switch Request changed bit   */
    DWord   pressureSwitchBit;      /* Pressure Switch Request changed bit   */

    DWord   samplingPumpSwitchBit;  /* Sampling Pump Switch Request bit      */
    DWord   oxygenSensorSwitchBit;  /* Oxygen Sensor Switch Request bit      */
    DWord   transmissometerSwitchBit;  /* Transmissometer Switch Request bit */

                                    /* Sensor Dcon LPS Output Enable switches*/
    switchEntry sensorLpsEnableSwitch[LPS_BOARDS];

    switchEntry sensorDconSwitch;         /* Sensor DCon Power Switch        */
    switchEntry conductivitySensorSwitch; /* Conductivity Sensor Power Switch*/
    switchEntry temperatureSensorSwitch;  /* Temperature Sensor Power Switch */
    switchEntry pressureSensorSwitch;     /* Pressure Sensor Power Switch    */
    switchEntry samplingPumpSwitch;       /* Sampling Pump Power Switch      */
    switchEntry oxygenSensorSwitch;       /* Oxygen Sensor Power Switch      */
    switchEntry transmissometerSwitch;    /* Transmissometer Power Switch    */

/*****************************************************************************/
/* The code is this task implements the following interconnected switches for
   the sensor data concentrator, altimeter and pressure sensor

             Sensor Dcon     12V LPS 0 Enable  LPS 0-4
   48V Bus _____ \_____________ \______________ \_____ spare 12V LPS  ______|
                      |                      |                              |
                      |                      |_ \_____ Conductivity   ______|
                      |                      |                              |
                      |                      |_ \_____ Temperature    ______|
                      |                      |                              |
                      |                      |_ \_____ Pressure       ______|
                      |                                                     |
                      |      12V LPS 1 Enable LPS 0-4                       |
                      |________ \______________ \_____ spare 12V LPS  ______|
                                             |                              |
                                             |_ \_____ Sampling Pump  ______|
                                             |                              |
                                             |_ \_____ Oxygen Sensor  ______|
                                             |                              |
                                             |_ \_____ Transmissometer _____|

                                                                             */
/*****************************************************************************/

                                    /* Create switch & power sync semaphores */
    if ( ((dmUpdateSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL) ||
         ((powerReqSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL) )
    {
        logMsg("Sensor Dcon: Error initializing Input Task Resources\n");
        return;
    } /* if */

    duplicateIbcSwitchEntry( &sensorDconSwitch,
        SENSOR_DCON_SWITCH_REQ_DM,  SENSOR_DCON_SWITCH_STATUS_DM,
        dmUpdateSem, sensorDconName, "Sensor DCon Switch");

    initIbcSwitchEntry( &sensorLpsEnableSwitch[0], SERIAL_CHAN,
        VICOR_STANDBY_POWER,        B48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],      LPS_VICOR_ENABLE,
        SENSOR_LPS0_12V_ENABLE_SWITCH_REQ_DM, SENSOR_LPS0_12V_ENABLE_STATUS_DM,
        dmUpdateSem,
        SENSOR_LPS0_12V_ENABLE_PWR_REQ_DM,    SENSOR_LPS0_12V_ENABLE_PWR_OK_DM,
        powerReqSem,                sensorDconName,      "LPS 0 12V Enable");

    initIbcSwitchEntry( &sensorLpsEnableSwitch[1], SERIAL_CHAN,
        VICOR_STANDBY_POWER,        B48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[1],      LPS_VICOR_ENABLE,
        SENSOR_LPS1_12V_ENABLE_SWITCH_REQ_DM, SENSOR_LPS1_12V_ENABLE_STATUS_DM,
        dmUpdateSem,
        SENSOR_LPS1_12V_ENABLE_PWR_REQ_DM,    SENSOR_LPS1_12V_ENABLE_PWR_OK_DM,
        powerReqSem,                sensorDconName,      "LPS 1 12V Enable");


    initIbcSwitchEntry( &conductivitySensorSwitch, SERIAL_CHAN,
        CONDUCTIVITY_SENSOR_POWER,  B48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],  CONDUCTIVITY_SWITCH_CHAN,
        CONDUCTIVITY_SENSOR_SWITCH_REQ_DM, CONDUCTIVITY_SENSOR_SWITCH_STATUS_DM,
        dmUpdateSem,
        CONDUCTIVITY_SENSOR_PWR_REQ_DM,    CONDUCTIVITY_SENSOR_PWR_OK_DM,
        powerReqSem,              sensorDconName, "Conductivity Sensor Switch");

    initIbcSwitchEntry( &temperatureSensorSwitch, SERIAL_CHAN,
        TEMPERATURE_SENSOR_POWER,   B48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],   TEMPERATURE_SWITCH_CHAN,
        TEMPERATURE_SENSOR_SWITCH_REQ_DM, TEMPERATURE_SENSOR_SWITCH_STATUS_DM,
        dmUpdateSem,
        TEMPERATURE_SENSOR_PWR_REQ_DM,    TEMPERATURE_SENSOR_PWR_OK_DM,
        powerReqSem,              sensorDconName, "Temperature Sensor Switch");

    initIbcSwitchEntry( &pressureSensorSwitch, SERIAL_CHAN,
        PRESSURE_SENSOR_POWER,      B48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[0],      PRESSURE_SWITCH_CHAN,
        PRESSURE_SENSOR_SWITCH_REQ_DM, PRESSURE_SENSOR_SWITCH_STATUS_DM,
        dmUpdateSem,
        PRESSURE_SENSOR_PWR_REQ_DM,    PRESSURE_SENSOR_PWR_OK_DM,
        powerReqSem,                sensorDconName,  "Pressure Sensor Switch");

    initIbcSwitchEntry( &samplingPumpSwitch, SERIAL_CHAN,
        SAMPLING_PUMP_POWER,        B48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[1], SAMPLING_PUMP_SWITCH_CHAN,
        SAMPLING_PUMP_SWITCH_REQ_DM, SAMPLING_PUMP_SWITCH_STATUS_DM,
        dmUpdateSem,
        SAMPLING_PUMP_PWR_REQ_DM,    SAMPLING_PUMP_PWR_OK_DM,
        powerReqSem,                sensorDconName,   "Sampling Pump Switch");

    initIbcSwitchEntry( &oxygenSensorSwitch, SERIAL_CHAN,
        OXYGEN_SENSOR_POWER,        B48,                      HOTEL,
        LOW_POWER_SWITCH,           lpsBoardAddr[1], OXYGEN_SENSOR_SWITCH_CHAN,
        OXYGEN_SENSOR_SWITCH_REQ_DM, OXYGEN_SENSOR_SWITCH_STATUS_DM,
        dmUpdateSem,
        OXYGEN_SENSOR_PWR_REQ_DM,    OXYGEN_SENSOR_PWR_OK_DM,
        powerReqSem,                sensorDconName,   "Oxygen Sensor Switch");

    initIbcSwitchEntry( &transmissometerSwitch, SERIAL_CHAN,
        TRANSMISSOMETER_POWER,      B48,                      HOTEL,
        LOW_POWER_SWITCH,       lpsBoardAddr[1],   TRANSMISSOMETER_SWITCH_CHAN,
        TRANSMISSOMETER_SWITCH_REQ_DM,  TRANSMISSOMETER_SWITCH_STATUS_DM,
        dmUpdateSem,
        TRANSMISSOMETER_PWR_REQ_DM,     TRANSMISSOMETER_PWR_OK_DM,
        powerReqSem,                sensorDconName,  "Transmissometer Switch");


    ibcAddSwitchInSeries( &sensorDconSwitch, &sensorLpsEnableSwitch[0] );
    ibcAddSwitchInSeries( &sensorDconSwitch, &sensorLpsEnableSwitch[1] );

                                  /* Devices on Sensor Can Low Power Switches*/
    ibcAddSwitchInSeries( &sensorLpsEnableSwitch[0], &conductivitySensorSwitch);
    ibcAddSwitchInSeries( &sensorLpsEnableSwitch[0], &temperatureSensorSwitch);
    ibcAddSwitchInSeries( &sensorLpsEnableSwitch[0], &pressureSensorSwitch );

    ibcAddSwitchInSeries( &sensorLpsEnableSwitch[1], &samplingPumpSwitch );
    ibcAddSwitchInSeries( &sensorLpsEnableSwitch[1], &oxygenSensorSwitch );
    ibcAddSwitchInSeries( &sensorLpsEnableSwitch[1], &transmissometerSwitch );

    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &conductivitySensorSwitch,
         sensorDconName, "Conductivity Sensor", CONDUCTIVITY_SWITCH_CHAN,
         CONDUCTIVITY_SENSOR_CURRENT_DM,  CONDUCTIVITY_SENSOR_CURRENT_ALARM_DM,
         CONDUCTIVITY_SENSOR_CURRENT_WARN_THRESH_DM,
         CONDUCTIVITY_SENSOR_CURRENT_ALARM_THRESH_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &temperatureSensorSwitch,
         sensorDconName, "Temperature Sensor", TEMPERATURE_SWITCH_CHAN,
         TEMPERATURE_SENSOR_CURRENT_DM,  TEMPERATURE_SENSOR_CURRENT_ALARM_DM,
         TEMPERATURE_SENSOR_CURRENT_WARN_THRESH_DM,
         TEMPERATURE_SENSOR_CURRENT_ALARM_THRESH_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[0], &pressureSensorSwitch,
         sensorDconName, "Pressure Sensor",   PRESSURE_SWITCH_CHAN,
         PRESSURE_SENSOR_CURRENT_DM,          PRESSURE_SENSOR_CURRENT_ALARM_DM,
         PRESSURE_SENSOR_CURRENT_WARN_THRESH_DM,
         PRESSURE_SENSOR_CURRENT_ALARM_THRESH_DM);


    ibcConnectLpsDmItems( &dmItems->lpsDm[1], &samplingPumpSwitch,
         sensorDconName, "Sampling Pump", SAMPLING_PUMP_SWITCH_CHAN,
         SAMPLING_PUMP_CURRENT_DM,        SAMPLING_PUMP_CURRENT_ALARM_DM,
         SAMPLING_PUMP_CURRENT_WARN_THRESH_DM,
         SAMPLING_PUMP_CURRENT_ALARM_THRESH_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[1], &oxygenSensorSwitch,
         sensorDconName, "Oxygen Sensor", OXYGEN_SENSOR_SWITCH_CHAN,
         OXYGEN_SENSOR_CURRENT_DM,        OXYGEN_SENSOR_CURRENT_ALARM_DM,
         OXYGEN_SENSOR_CURRENT_WARN_THRESH_DM,
         OXYGEN_SENSOR_CURRENT_ALARM_THRESH_DM);

    ibcConnectLpsDmItems( &dmItems->lpsDm[1], &transmissometerSwitch,
         sensorDconName, "Transmissometer Sensor", TRANSMISSOMETER_SWITCH_CHAN,
         TRANSMISSOMETER_CURRENT_DM,        TRANSMISSOMETER_CURRENT_ALARM_DM,
         TRANSMISSOMETER_CURRENT_WARN_THRESH_DM,
         TRANSMISSOMETER_CURRENT_ALARM_THRESH_DM);

                                     /* Create Data Manager Group for items  */
    cpuGroup = initIbcCpuConsumer(&dmItems->ibcDm, &ibcCpuBits, dmUpdateSem);

                                    /* Use CPU Group for misc parameters     */
    dm_start_consumer(dmItems->waterAlarmThresh, DM_STATIC, dmUpdateSem);

    dm_group_add_item(cpuGroup, dmItems->waterAlarmThresh,
                      &waterAlarmThreshBit);

                                      /* Create GF/5V Data Manager Group     */
    gf5vGroup = initIbcGf5vConsumer( &dmItems->gf5vDm, &gf5vBits, dmUpdateSem);

    for (board = 0; board < LPS_BOARDS; board++)
    {                                 /* Create LPS Data Manager Group       */
        lpsGroup[board] =
            initIbcLpsConsumer( &dmItems->lpsDm[board], &lpsBits[board],
               dmUpdateSem );
                                      /* Add Switch Requests to DM Group     */
        dm_group_add_item(cpuGroup,
           sensorLpsEnableSwitch[board].switchRequestDm, &lpsEnableBit[board]);
    } /* for */

    dm_group_add_item(cpuGroup, sensorDconSwitch.switchStatusDm,
                      &sensorDconSwitchBit);

    dm_group_add_item(cpuGroup, conductivitySensorSwitch.switchRequestDm,
                      &conductivitySwitchBit);

    dm_group_add_item(cpuGroup, temperatureSensorSwitch.switchRequestDm,
                      &temperatureSwitchBit);

    dm_group_add_item(cpuGroup, pressureSensorSwitch.switchRequestDm,
                      &pressureSwitchBit);


    dm_group_add_item(cpuGroup, samplingPumpSwitch.switchRequestDm,
                      &samplingPumpSwitchBit);

    dm_group_add_item(cpuGroup, oxygenSensorSwitch.switchRequestDm,
                      &oxygenSensorSwitchBit);

    dm_group_add_item(cpuGroup, transmissometerSwitch.switchRequestDm,
                      &transmissometerSwitchBit);

                                    /* Clear changed bits before we start    */
    sensorDconGroupBits = dm_get_group_changes(cpuGroup);

    FOREVER
    {                              /* Mark micro configuration as invalid    */
        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    */

        ibcSetSwitchState (&pressureSensorSwitch,     SWITCH_ON);
        ibcSetSwitchState (&conductivitySensorSwitch, SWITCH_OFF);
        ibcSetSwitchState (&temperatureSensorSwitch,  SWITCH_OFF);

        ibcSetSwitchState (&samplingPumpSwitch,       SWITCH_OFF);
        ibcSetSwitchState (&oxygenSensorSwitch,       SWITCH_OFF);
        ibcSetSwitchState (&transmissometerSwitch,    SWITCH_OFF);

        for (board = 0; board < LPS_BOARDS; board++)
            ibcSetSwitchState (&sensorLpsEnableSwitch[board], SWITCH_ON );

        initIbcHumidityThreshDm(SERIAL_CHAN,
            dmItems->ibcDm.humidityWarnThresh,
            dmItems->ibcDm.humidityAlarmThresh );

        initWaterAlarmThreshDm(SERIAL_CHAN, dmItems->waterAlarmThresh);

        updateIbcGf5vDmItems( SERIAL_CHAN, GF5V_BOARD_ADDR,
                             &dmItems->gf5vDm, sensorDconName );

        setGf5vChargeTimes( &dmItems->gf5vDm,
            LOW_VOLTAGE_GF_CHARGE_TIME, LOW_VOLTAGE_GF_CHARGE_TIME,
            LOW_VOLTAGE_GF_CHARGE_TIME, LOW_VOLTAGE_GF_CHARGE_TIME );

        enableGf5vMonitoring( SERIAL_CHAN, GF5V_BOARD_ADDR,
           &dmItems->gf5vDm, TRUE );

        runGf5vBoardSelftest( SERIAL_CHAN, GF5V_BOARD_ADDR, &dmItems->gf5vDm );

        updateIbcLpsDmItems( SERIAL_CHAN, lpsBoardAddr[0],
                            &dmItems->lpsDm[0], sensorDconName );

        updateIbcLpsDmItems( SERIAL_CHAN, lpsBoardAddr[1],
                            &dmItems->lpsDm[1], sensorDconName );

                                    /* Clear changed bits before we start    */
        sensorDconGroupBits = dm_get_group_changes(cpuGroup);
                                    /* Flag that micro has been configured   */
        microIOCtrl->microConfigured = TRUE;

                                    /* Wake up input task to read from micro */
        semGive(microIOCtrl->childTasks[IN_TASK].taskSyncSem);
                                    /* Wake up task to check Aux In status   */
        semGive(microIOCtrl->childTasks[AUX_IN_TASK].taskSyncSem);

                                    /* Clear changed item bits in DM         */
        sensorDconGroupBits = dm_get_group_changes(cpuGroup);

        while (microIOCtrl->serialLinkState == LINK_UP)
        {                           /* Wait for any data items to change     */
            semTake(dmUpdateSem, WAIT_FOREVER);

                                   /* Ask Data Manager which items changed   */
            sensorDconGroupBits = dm_get_group_changes(cpuGroup);

                                    /* Check if micro Reset Event occurred   */
            if (sensorDconGroupBits & ibcCpuBits.resetEventBit)
                break;              /* Exit loop and re-initialize DM items  */

            taskSafe();             /* Prevent task from being deleted during*/
                                    /* serial IO and Data Manager updates    */

                                    /* Sensor Dcon Power Switch Request      */
            if (sensorDconGroupBits & sensorDconSwitchBit)
            {
                ibcProcessDupSwitchRequest( &sensorDconSwitch );
                if (microDevPowerSwitchState(microIOCtrl) != SWITCH_ON)
                {                   /* DCon is switched off so link is down  */
                    setSerialLinkState(microIOCtrl, LINK_DOWN);
                    taskSafe();
                    break;
                } /* if */
            } /* if */

                                    /* Sensor Can LPS Output Enable Request  */
            if (sensorDconGroupBits & lpsEnableBit[0])
                ibcProcessSwitchRequest( &sensorLpsEnableSwitch[0] );

            if (sensorDconGroupBits & lpsEnableBit[1])
                ibcProcessSwitchRequest( &sensorLpsEnableSwitch[1] );

                                    /* Conductivity Sensor Switch Request    */
            if (sensorDconGroupBits & conductivitySwitchBit)
                ibcProcessSwitchRequest( &conductivitySensorSwitch );

                                    /* Temperature Sensor Switch Request     */
            if (sensorDconGroupBits & temperatureSwitchBit)
                ibcProcessSwitchRequest( &temperatureSensorSwitch );

                                    /* Pressure Sensor Power Switch Request  */
            if (sensorDconGroupBits & pressureSwitchBit)
                ibcProcessSwitchRequest( &pressureSensorSwitch );

                                    /* Sampling Pump Power Switch Request    */
            if (sensorDconGroupBits & samplingPumpSwitchBit)
                ibcProcessSwitchRequest( &samplingPumpSwitch );

                                    /* Oxygen Sensor Power Switch Request    */
            if (sensorDconGroupBits & oxygenSensorSwitchBit)
                ibcProcessSwitchRequest( & oxygenSensorSwitch );

                                    /* Transmissometer Power Switch Request  */
            if (sensorDconGroupBits & transmissometerSwitchBit)
                ibcProcessSwitchRequest( &transmissometerSwitch );

                                    /* Check for GF/5V Board Parameter Update*/
            ibcGf5vUpdateCheck( SERIAL_CHAN, GF5V_BOARD_ADDR,
                              &dmItems->gf5vDm, &gf5vBits, gf5vGroup );

                                    /* Check for LPS Board Parameter Update  */
            ibcLpsUpdateCheck( SERIAL_CHAN, lpsBoardAddr[0],
                              &dmItems->lpsDm[0], &lpsBits[0], lpsGroup[0] );

                                    /* Check for LPS Board Parameter Update  */
            ibcLpsUpdateCheck( SERIAL_CHAN, lpsBoardAddr[1],
                              &dmItems->lpsDm[1], &lpsBits[1], lpsGroup[1] );

                                     /* Send Set Humidity Alarm Threshold cmd*/
            if ((sensorDconGroupBits & ibcCpuBits.humidityWarnThreshBit) ||
                (sensorDconGroupBits & ibcCpuBits.humidityAlarmThreshBit))
                writeIbcHumidityThresh(SERIAL_CHAN,
                    dmItems->ibcDm.humidityWarnThresh,
                    dmItems->ibcDm.humidityAlarmThresh);

                                    /* Send Set Water Alarm Threshold cmd    */
            if (sensorDconGroupBits & waterAlarmThreshBit)
                writeWaterAlarmThresh(SERIAL_CHAN, dmItems->waterAlarmThresh);

#if 0
                                    /* If Setup Command request occurred     */
            if (sensorDconGroupBits & ibcCpuBits.setupCmdBit)
                                    /* Send Setup Command to Microcontroller */
                sensorCanSetupCTDSensors(SERIAL_CHAN);
#endif
                                    /* If Reset Command request occurred     */
            if (sensorDconGroupBits & ibcCpuBits.resetCmdBit)
            {                       /* Mark serial link as down               */
                setSerialLinkState(microIOCtrl, LINK_DOWN);
                                    /* Manual reset so ammounce 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, 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*/

                        /* That's all folks !                                */
} /* sensorDconOutTask() */


/*****************************************************************************/
/* Function    : sensorDconInTask                                            */
/* Purpose     : Sensor Dcon Input Task. Wakes up periodically, read data    */
/*               from the Sensor Dcon 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
sensorDconInTask(Reg sensorDconDmItems* dmItems, microIOControl *microIOCtrl)
{
    SEM_ID  wakeupSem;              /* Used by watch dog to wake up this task*/
    Int32   updates = 0;            /* Counts dm updates for rate calculation*/

                                    /* Create wakeup semaphore for provider  */
                                    /* rate control                          */
    if ((wakeupSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL)
    {
        logMsg("Sensor Dcon: Error initializing Input Task Resources\n");
        return;
    } /* if */
                                   /* Provider Task for non-static data items*/
    initIbcCpuProvider  (&dmItems->ibcDm,    HUMIDITY_DM_PERIOD);
    initIbcGf5vProvider (&dmItems->gf5vDm,   SENSOR_IBC_DM_PERIOD);
    initIbcLpsProvider  (&dmItems->lpsDm[0], SENSOR_IBC_DM_PERIOD);
    initIbcLpsProvider  (&dmItems->lpsDm[1], SENSOR_IBC_DM_PERIOD);

    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    */

            if ((updates % (HUMIDITY_DM_PERIOD / SENSOR_IBC_DM_PERIOD)) == 0)
                updateIbcHumidityDm(SERIAL_CHAN, dmItems->ibcDm.microHumidity);

            updateNewIbcGf5vDm(SERIAL_CHAN, GF5V_BOARD_ADDR,
                             &dmItems->gf5vDm );

            updateIbcLpsDm(SERIAL_CHAN, lpsBoardAddr[0],
                             &dmItems->lpsDm[0] );

            updateIbcLpsDm(SERIAL_CHAN, lpsBoardAddr[1],
                             &dmItems->lpsDm[1] );

            taskUnsafe();           /* task may now be deleted safely        */
                                    /* increment & range check update counter*/
            if (++updates == 10000) updates = 0;

            semTake(wakeupSem,      /* pend until sem timeout wakes us up    */
                sysClkRateGet() / ( USECS_PER_SEC / SENSOR_IBC_DM_PERIOD));

        } /* while */
    } /* FOREVER */

    semDelete(wakeupSem);           /* reclaim semaphore resource            */

                        /* 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*/

                        /* That's all folks !                                */
} /* sensorDConInTask() */

/*****************************************************************************/
/* Function    : sensorDconSensorInTask                                      */
/* Purpose     : Sensor Dcon Sensor Task. Wakes up periodically, read data   */
/*               from the Sensor Dcon 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
sensorDconSensorInTask(microIOControl *microIOCtrl)
{
    SEM_ID  wakeupSem;              /* Used wake up this task periodically   */
    Nat32 ticks;                    /* For subtacting loop time from timer   */
    Int32 delay;                    /* Calculated loop delay                 */

    sensorDconSensorItems dmItems;  /* Sensor Application Data Mgr handles   */
    MedianFilter depthFilter;       /* Filter for depth sensor spikes        */

                                    /* Clear Sensor DCon Data Manager handles*/
    bzero(&dmItems, sizeof(dmItems));

                                    /* Create Sensor Dcon Application Items  */
    if (createSensorDconSensorDmItems(&dmItems, sensorIbcDmPrefix,
           sensorIbcDmPrefix, sensorDconName) == ERROR)
    {                               /* Error occurred so print message & exit*/
        logMsg("Sensor Dcon: Error initializing Sensor Data Manager Items\n");
        return;
    } /* if */
                                    /* Create wakeup semaphore               */
                                    /* timer for provider rate control       */
    if ((wakeupSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL)
    {
        logMsg("Sensor Dcon: Error initializing Input Task Resources\n");
        return;
    } /* if */

                                    /* Initialize median filter for samples  */
    initMedianFilter( &depthFilter, DEPTH_FILTER_SAMPLES );

    FOREVER
    {                               /* Wait for Dcon Coms to be initialized   */
       semTake(microIOCtrl->childTasks[AUX_IN_TASK].taskSyncSem, WAIT_FOREVER);

       ticks = tickGet();           /* Update Rate is not guaranteed due to   */

       while (microIOCtrl->serialLinkState == LINK_UP)
       {
            delay =
                sysClkRateGet() / (USECS_PER_SEC / SENSOR_DM_PERIOD )
                - min(tickGet() - ticks,
                sysClkRateGet() / (USECS_PER_SEC / SENSOR_DM_PERIOD ));

            if (delay > 0)          /* Pend until sem timeout wakes us up     */
                semTake(wakeupSem, delay);

            ticks = tickGet();

            taskSafe();             /* Prevent task from being deleted during*/
                                    /* serial IO and Data Manager updates    */


            sensorCanUpdateCTDSensors(SERIAL_CHAN, &dmItems, &depthFilter);
            sensorCanUpdateOxygenXmiss(SERIAL_CHAN, &dmItems);

            taskUnsafe();           /* Task may now be deleted safely        */
                                    /* Pend until timer wakes us up           */
        } /* while */
    } /* FOREVER */

    semDelete(wakeupSem);           /* semaphore resources                   */

                        /* 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*/

                        /* That's all folks !                                */
} /* sensorDconSensorInTask() */

/*****************************************************************************/
/* Function    : processSensorDconSRQ                                        */
/* Purpose     : Decode Service Request and take appropriate action          */
/* Inputs      : SRQ code, array of DM items, serial channel                 */
/* Outputs     : Returns SRQ Received & many DM items are changed            */
/*****************************************************************************/
    LOCAL Word
processSensorDconSRQ( Reg sensorDconDmItems* dmItems,
    microIOControl *microIOCtrl)
{
    Word srqRequest;                /* Service Request Value                 */
    Byte buffer[SRQ_PACKET_LEN];    /* Buffer for micro communications data  */


                                    /* Wait for Service Requests              */
    if (readSRQPacket(SERIAL_CHAN, buffer, SRQ_PACKET_LEN, WAIT_FOREVER)
        == ERROR) return (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->ibcDm.microDm.resetEvent);
        break;

      case CAN_WATER_ALARM_ON_SRQ:    /* Housing Water Alarm Active    */
        writeBooleanDmItem(dmItems->canWaterAlarm, TRUE);
        break;

      case CAN_WATER_ALARM_OFF_SRQ:   /* Housing Water Alarm Inactive  */
        writeBooleanDmItem(dmItems->canWaterAlarm, FALSE);
        break;

      case JBOX_WATER_ALARM_ON_SRQ:   /* J Box Water Alarm Active      */
        writeBooleanDmItem(dmItems->jboxWaterAlarm, TRUE);
        break;

      case JBOX_WATER_ALARM_OFF_SRQ:  /* J Box Water Alarm Inactive    */
        writeBooleanDmItem(dmItems->jboxWaterAlarm, FALSE);
        break;

      default:
        if (processIbcCpuSRQ(srqRequest,  buffer, &dmItems->ibcDm ) != TRUE)

        if (processIbcLpsSRQ(srqRequest,  buffer, lpsBoardAddr[0],
                    &dmItems->lpsDm[0]) != TRUE)

        if (processIbcLpsSRQ(srqRequest,  buffer, lpsBoardAddr[1],
                    &dmItems->lpsDm[1]) != TRUE)

        if (processIbcGf5vSRQ(srqRequest, buffer, GF5V_BOARD_ADDR,
                    &dmItems->gf5vDm) != TRUE)

        if (processIbcQuadSerSRQ(srqRequest, buffer,
                    SERIAL_BOARD_ADDR, &dmItems->quadSerDm) != TRUE)

        printf("Sensor Dcon: Unrecognized SRQ 0x%x\n", srqRequest);

        break;

    } /* switch */

    return(srqRequest);                 /* Return SRQ received to caller      */
} /* processSensorDconSRQ() */



