head 4.4; access ; symbols ; locks oasisa:4.4; strict; comment @ * @; 4.4 date 2001.06.19.12.14.46; author oasisa; state Exp; branches ; next ; desc @New Repository; 6/19/2001 (klh) @ 4.4 log @New Repository; 6/19/2001 (klh) @ text @/****************************************************************************/ /* Copyright 1995 MBARI */ /****************************************************************************/ /* $Header: no3.c,v 1.1 2001/06/19 11:44:17 oasisa Exp $ */ /* Summary : Driver Routines for Nitrate Anaylyzer on OASIS mooring */ /* Filename : no3.c */ /* Author : Robert Herlien (rah) */ /* Project : OASIS Mooring */ /* $Revision: 1.1 $ */ /* Created : 02/15/95 from sensors.c */ /* */ /* MBARI provides this documentation and code "as is", with no warranty, */ /* express or implied, of its quality or consistency. It is provided without*/ /* support and without obligation on the part of the Monterey Bay Aquarium */ /* Research Institute to assist in its use, correction, modification, or */ /* enhancement. This information should not be published or distributed to */ /* third parties without specific written permission from MBARI. */ /* */ /****************************************************************************/ /* Modification History: */ /* 15feb95 rah - created from sensors.c */ /* $Log: no3.c,v $ * Revision 1.1 2001/06/19 11:44:17 11:44:17 oasisa (Oasis users) * Initial revision * * Revision 4.3 99/06/16 10:21:34 10:21:34 bobh (Bob Herlien) * Mar/May '99 Deployments of M3/M2 * * Revision 4.2 98/09/09 10:48:04 10:48:04 bobh (Bob Herlien) * Sept/Oct '98 deployments of M1, Eqpac 1 & 2 * * Revision 4.0 98/03/09 11:44:40 11:44:40 bobh (Bob Herlien) * M3 Deployment of March '98, new Sat-Pac driver * * Revision 3.7 97/07/23 11:18:11 11:18:11 bobh (Bob Herlien) * July '97 M1 deployment, new shutter code * * Revision 3.6 96/10/30 14:00:15 14:00:15 bobh (Bob Herlien) * Release for EqPac, M2 Test Replacement * * Revision 3.5 96/07/19 09:53:38 09:53:38 bobh (Bob Herlien) * July '96 Deployment of M2 with ARGOS code * * Revision 3.1 95/03/09 19:31:00 19:31:00 hebo (Bob Herlien) * March '95 Deployment of M1A * * Revision 3.0 95/02/21 18:42:45 18:42:45 hebo (Bob Herlien) * February '95 Deployment * */ /****************************************************************************/ #include /* MBARI type definitions */ #include /* MBARI constants */ #include /* OASIS controller definitions */ #include /* OASIS I/O definitions */ #include /* Log record definitions */ #include /* Deployment-specific definitions */ #include /* OASIS Multitasking definitions */ #include /* ARGOS definitions */ #include /* Standard I/O functions */ #include /* Standard ctype.h defs */ #define NO3_BUFSIZE 512 /* Size of buffer for nitrate */ #define NO3_LINE_MAX 60 #define SAMPLES_PER_PERIOD 18 /* Three hours per period */ #define SAMPLES_TO_AVG 6 /* Average one hour for normal samples*/ #define SAMPLES_PER_STD 12 /* Examine 2 hrs of data for std/blk*/ typedef enum /************************************/ { /* State of NO3 sampling */ ST_NO_AVG, /* Normal data past averaging time */ ST_NORMAL, /* Averaging normal data */ ST_STANDARD, /* Standard insertion period */ ST_BLANK /* Blank insertion period */ } NO3State; /************************************/ typedef enum /************************************/ { /* Type of NO3 data point */ DT_BAD_DATA, /* Bad Data point */ DT_NORMAL, /* Normal data */ DT_STANDARD, /* Start of std insertion period */ DT_BLANK /* Start of blank insertion period */ } NO3DataType; /************************************/ typedef struct /************************************/ { /* Result of one NO3 sample */ Nat16 no3; /* Nitrate value */ Nat16 temp; /* Temperature, centidegrees C */ } NO3Sample; /************************************/ /********************************/ /* External Functions */ /********************************/ Extern Void drvLog( Driver *dp, Byte *samplep, Int16 len ); Extern char *drvSerPortAndMalloc( Driver *dp, Nat16 size ); Extern Void drvSerReleaseAndFree( Driver *dp, char *buffer ); Extern Void xputs( const char *s ); Extern Void xflush_ser( Nat16 tmout ); Extern Int16 xgets_tmout( char *s, Int16 len, Nat16 tmout ); Extern char *find_str( char *src, char *tgt ); Extern Void tmpFree( char *ptr ); #ifdef ARGOS_NO3 Extern MBool delimit( Reg char c ); Extern Int16 getByte( char *p, Nat16 radix ); Extern MBool getnum( char **s, Int16 *result, Nat16 radix ); Extern MBool getFixedPt( char **s, Int16 *resultPtr, Nat16 decDigits ); Extern Void bzero( void *s, int n ); Extern char *skipField( Reg char *p, Nat16 nfields ); Extern Void argosNo3Sample( Driver *dp, Nat16 numSamples, NO3Sample *data ); #endif /********************************/ /* External Data */ /********************************/ Extern Semaphore no3_sem; /* Mutex sems for no3 driver */ /********************************/ /* Module Local Data */ /********************************/ #ifdef ARGOS_NO3 MLocal NO3State state; /* What are we doing? */ MLocal Nat16 no3Accum; /* Accum buffer for no3 */ MLocal Nat16 tempAccum; /* Accum buffers for no3, temp */ MLocal Nat16 curSamples; /* Num samples accum for cur period */ MLocal Nat16 totSamples; /* Total number samples gotten */ MLocal Nat16 blkStdVal[3]; /* Blank/Standard values */ MLocal Nat16 argosSamples; /* Number of samples in argos buf */ MLocal NO3Sample argosData[2 * CHEM_SAMPLES]; /* Samples for ARGOS */ #endif /************************************************************************/ /* Function : wakeup_nitrate */ /* Purpose : Wake up the NO3 analyzer, pass wakeup string */ /* Inputs : Driver ptr, wakeup string, buffer to use */ /* Outputs : TRUE if woke up nitrate, else FALSE */ /************************************************************************/ MBool wakeup_nitrate( Driver *dp, char *wakestr, char *buffer ) { Nat16 i; for ( i = dp->drv_parms[PARM0]; i; i-- ) { xputs("UUU"); /* Wake up nitrate sensor */ while ( xgets_tmout(buffer, 30, dp->drv_parms[TIMEOUT]) >= 0 ) if ( find_str(buffer, "Enter") != NULL ) { /* Look for signon message*/ xflush_ser( TICKS_PER_SECOND ); /* Flush serial buffer */ xputs( wakestr ); /* Send wakeup string */ return( TRUE ); /* Got it, return TRUE */ } } return( FALSE ); } /* wakeup_nitrate() */ /************************************************************************/ /* Function : nitrate_wake */ /* Purpose : Nitrate serial wakeup function */ /* Inputs : Driver ptr, Boolean (TRUE for on, FALSE for off) */ /* Outputs : TRUE */ /************************************************************************/ MBool nitrate_wake( Driver *dp, MBool on, char *buffer ) { if ( on ) wakeup_nitrate( dp, "PASS", buffer ); return( TRUE ); } /* nitrate_wake() */ #ifdef ARGOS_NO3 /************************************************************************/ /* Function : parseNo3Sample */ /* Purpose : Parse one nitrate sample */ /* Inputs : Buffer ptr, ptr to sample struct */ /* Outputs : Data Type of sample */ /************************************************************************/ NO3DataType parseNo3Sample( char *bufp, Reg NO3Sample *samplep ) { Reg char *p; char *q; p = bufp; deblank( p ); if ( (*p == 'A') && (p[2] == 'S') ) return( DT_STANDARD ); else if ( *p == 'B' ) return( DT_BLANK ); else if ( *p != 'S' ) return( DT_BAD_DATA ); q = skipField(p, 4); if ( !getnum(&q, (Int16 *)&samplep->no3, 10) ) return( DT_BAD_DATA ); q = skipField( q, 2 ); if ( getFixedPt(&q, (Int16 *)&samplep->temp, 2) ) return( DT_NORMAL ); return( DT_BAD_DATA ); } /* parseNo3Sample() */ /************************************************************************/ /* Function : storeNo3Sample */ /* Purpose : store No3 sample in ARGOS buffer */ /* Inputs : None */ /* Outputs : None */ /************************************************************************/ Void storeNo3Sample( Void ) { Reg Nat16 no3Val, sampleNum; if ( curSamples > 0 ) { if (state == ST_NORMAL) no3Val = ((no3Accum/curSamples) + 1) & ~1; else { no3Val = blkStdVal[0] + blkStdVal[1] + blkStdVal[2]; if ( state == ST_STANDARD ) no3Val = -no3Val; no3Val = (no3Val / 3) | 1; } sampleNum = totSamples / SAMPLES_PER_PERIOD; if ( sampleNum < (2 * CHEM_SAMPLES) ) { argosData[sampleNum].no3 = no3Val; argosData[sampleNum].temp = tempAccum / curSamples; argosSamples = sampleNum + 1; } } curSamples = no3Accum = tempAccum = 0; } /* storeNo3Sample() */ #endif /* ARGOS_NO3 */ /************************************************************************/ /* Function : getNo3Sample */ /* Purpose : Get one nitrate data sample */ /* Inputs : Driver Pointer, buffer ptr */ /* Outputs : Number of bytes gotten, 0 for end of record */ /************************************************************************/ Int16 getNo3Sample( Driver *dp, char *bufp ) { Reg Int16 curLen; Reg Nat16 val; Reg NO3DataType sampleType; NO3Sample sample; do { curLen = xgets_tmout(bufp, NO3_LINE_MAX, dp->drv_parms[TIMEOUT]); if ( curLen < 0 ) return( 0 ); } while ( curLen == 0 ); #ifdef ARGOS_NO3 sampleType = parseNo3Sample( bufp, &sample ); switch ( sampleType ) { case DT_NORMAL: break; case DT_STANDARD: /* Standard and blank records denote start */ case DT_BLANK: /* of std/blank, but don't contain data */ storeNo3Sample(); bzero( (void *)blkStdVal, sizeof(blkStdVal) ); state = (sampleType == DT_STANDARD) ? ST_STANDARD : ST_BLANK; curSamples = 0; /* Note fallthrough */ default: return( curLen ); } totSamples++; if ( state != ST_NO_AVG ) { curSamples++; tempAccum += sample.temp; val = sample.no3; no3Accum += val; } switch( state ) /* Switch on previously recorded state */ { case ST_STANDARD: val = -val; /* Note trick of recording the _inverse_ of sample*/ /* value for a standard, so then we can look for */ /* the maximum 3 of -values, as in blank */ /* Fall through to BLANK case */ case ST_BLANK: if ( val > blkStdVal[0] ) { blkStdVal[2] = blkStdVal[1]; blkStdVal[1] = blkStdVal[0]; blkStdVal[0] = val; } else if ( val > blkStdVal[1] ) { blkStdVal[2] = blkStdVal[1]; blkStdVal[1] = val; } else if ( val > blkStdVal[2] ) blkStdVal[2] = val; if ( curSamples >= SAMPLES_PER_STD ) { storeNo3Sample(); state = ST_NO_AVG; } break; case ST_NORMAL: if ( curSamples >= SAMPLES_TO_AVG ) { storeNo3Sample(); state = ST_NO_AVG; } break; case ST_NO_AVG: if ( totSamples/SAMPLES_PER_PERIOD >= argosSamples ) state = ST_NORMAL; break; } #endif /* ARGOS_NO3 */ return( curLen ); } /* getNo3Sample() */ /************************************************************************/ /* Function : nitrate_drv */ /* Purpose : Nitrate Sensor driver */ /* Inputs : Driver Pointer */ /* Outputs : None */ /************************************************************************/ Void nitrate_drv( Driver *dp ) { Nat16 bufLen; char *nitrate_buf; /* Buffer for nitrate data */ Reg Nat16 curLen; #ifdef SYNC_AT_MIDNIGHT if ( dp->drv_flags & DO_ARGOS ) { dp->drv_cnt = dp->drv_parms[PARM1]; if ( --dp->drv_cnt > 0 ) return; } #endif sem_take( &no3_sem ); /* Mutual exclusion due to common data*/ if ( (nitrate_buf = drvSerPortAndMalloc(dp, NO3_BUFSIZE)) == NULL ) return; if ( wakeup_nitrate(dp, "DATA", nitrate_buf) ) { /* Wake up NO3, ask for data */ #ifdef ARGOS_NO3 bufLen = totSamples = curSamples = 0; no3Accum = tempAccum = argosSamples = 0; state = ST_NORMAL; bzero( (void *)argosData, sizeof(argosData) ); #endif while( (curLen = getNo3Sample(dp, nitrate_buf + bufLen)) > 0 ) { bufLen += curLen; nitrate_buf[bufLen++] = '\n'; if ( bufLen >= (NO3_BUFSIZE - NO3_LINE_MAX) ) { drvLog( dp, (Byte *)nitrate_buf, bufLen ); bufLen = 0; } } #ifdef ARGOS_NO3 if ( state != ST_NO_AVG ) storeNo3Sample(); argosNo3Sample( dp, argosSamples, argosData ); #endif if ( bufLen > 0 ) drvLog( dp, (Byte *)nitrate_buf, bufLen ); } drvSerReleaseAndFree( dp, nitrate_buf ); /* Release serial port & buf*/ sem_give( &no3_sem ); /* Release mutex sem */ } /* nitrate_drv() */ @