head 4.4; access ; symbols ; locks oasisa:4.4; strict; comment @ * @; 4.4 date 2001.06.19.12.16.19; author oasisa; state Exp; branches ; next ; desc @New Repository; 6/19/2001 (klh) @ 4.4 log @New Repository; 6/19/2001 (klh) @ text @/****************************************************************************/ /* Copyright 1991 MBARI */ /****************************************************************************/ /* $Header: utils.c,v 1.1 2001/06/19 11:45:15 oasisa Exp $ */ /* Summary : Utility Routines for OASIS Mooring Controller */ /* Filename : utils.c */ /* Author : Robert Herlien (rah) */ /* Project : OASIS Mooring */ /* $Revision: 1.1 $ */ /* Created : 06/14/91 */ /* */ /* 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: */ /* 14jun91 rah - created */ /* $Log: utils.c,v $ * Revision 1.1 2001/06/19 11:45:15 11:45:15 oasisa (Oasis users) * Initial revision * * Revision 4.3 99/06/16 10:21:39 10:21:39 bobh (Bob Herlien) * Mar/May '99 Deployments of M3/M2 * * Revision 4.2 98/09/09 10:48:10 10:48:10 bobh (Bob Herlien) * Sept/Oct '98 deployments of M1, Eqpac 1 & 2 * * Revision 4.0 98/03/09 11:44:48 11:44:48 bobh (Bob Herlien) * M3 Deployment of March '98, new Sat-Pac driver * * Revision 3.7 97/07/23 11:18:24 11:18:24 bobh (Bob Herlien) * July '97 M1 deployment, new shutter code * * Revision 3.5 96/07/17 13:01:43 13:01:43 bobh (Bob Herlien) * July '96 deployment of M2 with ARGOS code * * Revision 3.4 96/06/18 15:24:39 15:24:39 bobh (Bob Herlien) * June '96 deployment of M1 * * Revision 3.3 95/04/13 13:47:07 13:47:07 hebo (Bob Herlien) * Drifter Deployment for Coop (flip) cruise * * Revision 3.2 95/04/11 14:03:36 14:03:36 hebo (Bob Herlien) * Drifter Deployment on IronEx * * Revision 3.1 95/03/09 19:31:07 19:31:07 hebo (Bob Herlien) * March '95 Deployment of M1A * * Revision 3.0 95/02/21 18:42:53 18:42:53 hebo (Bob Herlien) * February '95 Deployment * * Revision 2.4 93/10/29 11:12:52 11:12:52 hebo (Bob Herlien) * November 1993 Deployment * * Revision 2.0 92/08/21 14:46:21 14:46:21 hebo (Bob Herlien) * August 1992 deployment * * Revision 1.3 92/03/03 16:41:36 16:41:36 hebo (Bob Herlien 408-647-3748) * New defaults, restart check, perm power stuff, analog command * */ /****************************************************************************/ #include /* MBARI type definitions */ #include /* MBARI constants */ #include /* OASIS controller definitions */ #include /* OASIS I/O definitions */ #include /* OASIS Multitasking definitions */ #include /* Standard ctype.h defs */ #include /* vararg stuff */ #include /* String library functions */ #include /* For INT_MAX */ #define RANDOM_POLYNOMIAL 0x8e47 /* Generator polynomial for prn */ #define SER_POLL 2 /* Poll serial ports every 2 ticks */ #define MAX_FLUSH_TIME (30 * TICKS_PER_SECOND) /********************************/ /* External Functions */ /********************************/ Extern MBool ser_putc( Nat16 port, const Byte byte ); Extern Int16 ser_getc( Nat16 port ); Extern Int16 ser_getn( Nat16 port, char *p, Int16 nchars ); Extern Int16 ser_sndsts( Nat16 port ); Extern Void ser_flush( Nat16 port ); /********************************/ /* External Data */ /********************************/ Extern volatile Reg Nat16 tick; /* 10 ms ticker */ Extern Reg Nat16 port; /* Dflt ser port, saved by dispatch */ Extern Reg Word sermode; /* Serial mode (see ser_init()) */ /* Port and sermode are special variables: they get saved/restored */ /* during task swap, so they're always valid */ Extern Nat16 randSeed; /* Seed for random number generator */ /************************************************************************/ /* Function : doputc */ /* Purpose : Write one character to serial port, no '\n' conversion */ /* Inputs : Character to output */ /* Output : None */ /* Comments : Waits until character output */ /************************************************************************/ Void doputc( Int16 c ) { while( !ser_putc(port, c) ) task_delay(1); } /* doputc() */ /************************************************************************/ /* Function : newline */ /* Purpose : Write '\n' to serial port */ /* Inputs : None */ /* Outputs : None */ /* Comments : Will wait forever until it can output serial character */ /************************************************************************/ Void newline( Void ) { switch( sermode & NMODE ) { case NOLF: break; case NEWCR: if ( task_get()->td_serchar != '\r' ) doputc('\r'); break; case AUTOCR: doputc('\r'); /* NOTE fall through! */ default: doputc('\n'); } } /* newline() */ /************************************************************************/ /* Function : xputc */ /* Purpose : Write one character to serial port */ /* Inputs : Character to output */ /* Output : None */ /* Comments : Waits until character output */ /************************************************************************/ Void xputc( Int16 c ) { if ( c == '\n' ) newline(); else doputc( c ); task_get()->td_serchar = c; } /* xputc() */ /************************************************************************/ /* Function : xgetc_tmout */ /* Purpose : Read one character from serial port with timeout */ /* Inputs : Timeout in seconds */ /* Output : Character */ /* Comments : Returns ERROR if timed out */ /* Uses default serial port "port", which is saved by dispatch*/ /* If tmout == NO_TIMEOUT, will wait 18 hours */ /* If tmout == 0, get just what's currently in input buffer*/ /************************************************************************/ Int16 xgetc_tmout( Nat16 tmout ) { Reg Int16 c; Nat16 secs, st_tick; if ( tmout == 0 ) return( ser_getc(port) ); for ( secs = tmout; secs; secs-- ) for ( st_tick = tick; (tick - st_tick < TICKS_PER_SECOND); ) { if ( (c = ser_getc(port)) != ERROR ) return( c ); task_delay( 1 ); } return( c ); } /* xgetc_tmout() */ /************************************************************************/ /* Function : xgetc */ /* Purpose : Read one character from serial port */ /* Inputs : None */ /* Output : Character */ /* Comments : Waits until character available */ /************************************************************************/ Int16 xgetc( Void ) { return( xgetc_tmout(NO_TIMEOUT) ); } /* xgetc() */ /************************************************************************/ /* Function : xputs */ /* Purpose : Write string to serial out */ /* Inputs : String ptr */ /* Outputs : None */ /* Comments : Uses default serial port "port", which is saved by dispatch*/ /* Will wait forever until it can output serial characters*/ /************************************************************************/ Void xputs( const char *s ) { while (*s) xputc(*s++); } /* xputs() */ /************************************************************************/ /* Function : xputn */ /* Purpose : Write fixed length message to serial out, no CR/LF xlate*/ /* Inputs : Buffer ptr, buffer length */ /* Outputs : None */ /* Comments : Uses default serial port "port", which is saved by dispatch*/ /* Will wait forever until it can output serial characters*/ /************************************************************************/ Void xputn( const char *s, Int16 len ) { Int16 cnt; for ( cnt = 0; cnt < len; cnt++ ) doputc( s[cnt] ); } /* xputn() */ /************************************************************************/ /* Function : xgetn_tmout */ /* Purpose : Read n characters into buffer with timeout */ /* Inputs : Buffer ptr, buffer length, timeout in seconds */ /* Outputs : Number characters read (0 if no chars before timeout) */ /* Comments : Does no line editing, doesn't echo */ /* Uses default serial port, which is saved by dispatch() */ /* If tmout == NO_TIMEOUT, will wait 18 hours */ /* If tmout == 0, get just what's currently in input buffer*/ /************************************************************************/ Int16 xgetn_tmout( char *s, Int16 len, Nat16 tmout ) { Reg Int16 nchars; /* Number chars read each time */ Int16 totchars; /* Total chars read */ Nat16 ticks, secs,rtick; if ( tmout == 0 ) return( ser_getn(port, s, len ) ); totchars = 0; for ( secs = 0; secs < tmout; secs++ ) for ( ticks = 0; ticks < TICKS_PER_SECOND; ticks += SER_POLL ) { nchars = ser_getn(port, s + totchars, len - totchars); if ( (totchars += nchars) >= len ) /* If enough chars, return */ return( totchars ); task_delay( SER_POLL ); /* Else wait for more serial*/ } return( totchars ); /* Return # chars found */ } /* xgetn_tmout() */ /************************************************************************/ /* Function : xgets_tmout_flg */ /* Purpose : Read one line of user input into buffer with timeout */ /* Inputs : Buffer ptr, buffer length, timeout in seconds, flags */ /* Outputs : Number characters read, or ERROR if no chars before timeout*/ /* Comments : Gets input until newline, return, end of buffer, or tmout*/ /* Uses default serial port, which is saved by dispatch() */ /* If tmout == NO_TIMEOUT, will wait 18 hours */ /* If tmout == 0, get just what's currently in input buffer*/ /* See oasis.h for flags. Currently just INCLUDE_TERMCHAR*/ /************************************************************************/ Int16 xgets_tmout_flg( char *s, Int16 len, Nat16 tmout, Word flags ) { Nat16 nchars, ticks, secs; /* Num chars read, time counters*/ Reg Int16 c; /* Most recently read character */ nchars = 0; for ( secs = 0; secs < tmout; secs++ ) for ( ticks = 0; ticks < TICKS_PER_SECOND; ) { s[nchars] = '\0'; /* NULL terminate string*/ switch( c = ser_getc(port) ) { case '\n': case '\r': if ( sermode & ECHO ) newline(); if ( flags & INCLUDE_TERMCHAR ) { s[nchars++] = (Byte)c; s[nchars] = '\0'; } return(nchars); case '\b': if ( nchars > 0 ) { nchars--; if ( sermode & ECHO ) xputs("\b \b"); } break; case ERROR: task_delay( SER_POLL ); /* Wait for more serial */ ticks += SER_POLL; break; default: s[nchars++] = (Byte)c; /* Normal char, put in buffer*/ s[nchars] = '\0'; if ( sermode & ECHO ) xputc( c ); if ( nchars >= len-1 ) return( nchars ); break; } /* switch */ } /* for */ if ( nchars == 0 ) return( ERROR ); return( nchars ); } /* xgets_tmout_flg() */ /************************************************************************/ /* Function : xgets_tmout */ /* Purpose : Read one line of user input into buffer with timeout */ /* Inputs : Buffer ptr, buffer length, timeout in seconds */ /* Outputs : Number characters read, or ERROR if no chars before timeout*/ /* Comments : Gets input until newline, return, end of buffer, or tmout*/ /* Uses default serial port, which is saved by dispatch() */ /* If tmout == NO_TIMEOUT, will wait 18 hours */ /* If tmout == 0, get just what's currently in input buffer*/ /************************************************************************/ Int16 xgets_tmout( char *s, Int16 len, Nat16 tmout ) { return( xgets_tmout_flg(s, len, tmout, 0) ); } /* xgets_tmout() */ /************************************************************************/ /* Function : xgets */ /* Purpose : Read one line into buffer */ /* Inputs : Buffer pointer, buffer length */ /* Outputs : Number characters read */ /* Comments : Gets input until newline, return, or end of buffer */ /* Will wait forever for above conditions */ /************************************************************************/ Int16 xgets( char *s, Int16 len ) { return( xgets_tmout(s,len,NO_TIMEOUT) ); } /* xgets() */ /************************************************************************/ /* Function : xflush_ser */ /* Purpose : Discard serial input stream */ /* Inputs : Number of ticks to wait for input to flush */ /* Output : None */ /* Comments : If tmout == 0, just discard current input */ /************************************************************************/ Void xflush_ser( Nat16 timeout ) { Nat16 flushTick, startTick; ser_flush( port ); startTick = flushTick = tick; while ( (tick - flushTick < timeout) && (tick - startTick < MAX_FLUSH_TIME) ) { task_delay( 1 ); while ( ser_getc(port) != ERROR ) flushTick = tick; } } /* xflush_ser() */ /************************************************************************/ /* Function : xdrain_ser */ /* Purpose : Wait for serial output stream to finish sending */ /* Inputs : Number of ticks to wait for output to drain */ /* Output : None */ /************************************************************************/ Void xdrain_ser( Nat16 tmout ) { Nat16 i; for ( i = tmout; (ser_sndsts(port) > 0) && i; i-- ) task_delay( 1 ); } /* xdrain_ser() */ /************************************************************************/ /* Function : delimit */ /* Purpose : Determine if character is a delimiter */ /* Inputs : Character */ /* Outputs : TRUE if character is ',', NULL, or space */ /************************************************************************/ MBool delimit( Reg char c ) { return( isspace(c) || (c == '\0') || (c == ',') || (c == '.') ); } /* delimit() */ /************************************************************************/ /* Function : cmp_ulc */ /* Purpose : Compare strings, case insensitive */ /* Inputs : String ptr (mixed case, leading blanks), */ /* string ptr (mixed case, no blanks) */ /* Outputs : NULL if strings don't match, else ptr to remainder of */ /* user input string */ /************************************************************************/ char * cmp_ulc( char *s, char *cs ) { deblank(s); while( *cs ) { if ( _to_upper(*s) != _to_upper(*cs) ) return( NULL ); s++; cs++; } return( delimit(*s) ? s : NULL ); } /* cmp_ulc() */ /************************************************************************/ /* Function : skipField */ /* Purpose : Skip a given number of fields in input */ /* Inputs : Input ptr, number of fields to skip */ /* Outputs : Ptr to remaining string, or to NULL terminator if at end*/ /************************************************************************/ char * skipField( Reg char *p, Nat16 nfields ) { Reg Nat16 n; for ( n = nfields; *p && n; ) if ( delimit(*p++) ) { deblank( p ); n--; } return( p ); } /* skipField() */ /************************************************************************/ /* Function : find_str */ /* Purpose : Find target string embedded in source string, case insens*/ /* Inputs : Source string ptr, Target string ptr */ /* Outputs : NULL if strings don't match, else ptr to next char of source*/ /************************************************************************/ char * find_str( char *src, char *tgt ) { Reg char *p, *p1, *q; for ( p1 = src; *p1; p1++ ) { for( p = p1, q = tgt; ; p++, q++ ) { if ( *q == '\0' ) return( p ); if ( *p == '\0' ) return( NULL ); if ( _to_upper(*p) != _to_upper(*q) ) break; } } return( NULL ); } /* find_str() */ /************************************************************************/ /* Function : tohex */ /* Purpose : Convert an ASCII character to hex equivalent */ /* Inputs : ASCII character, radix */ /* Outputs : Hex number, or ERROR if not valid hex digit */ /************************************************************************/ Int16 tohex( Int16 c, Nat16 radix ) { Reg Int16 rtn; if ( isdigit(c) ) rtn = c - '0'; else if ( isxdigit(c) ) rtn = _toupper(c) - 'A' + 10; else return( ERROR ); return( (rtn < radix) ? rtn : ERROR ); } /* tohex() */ /************************************************************************/ /* Function : getByte */ /* Purpose : Get one byte from first two ASCII chars in buffer */ /* Inputs : Buffer pointer */ /* Outputs : Value of 0 - 255, or ERROR */ /************************************************************************/ Int16 getByte( char *p, Nat16 radix ) { Reg Nat16 low, high; if ( ((high = tohex(*p++, radix)) == ERROR) || ((low = tohex(*p, radix)) == ERROR) ) return( ERROR ); return( (high * radix) + low ); } /* getByte() */ #ifdef INCLUDE_GETNUM32 /************************************************************************/ /* Function : getnum32 */ /* Purpose : Get a number in a given base */ /* Inputs : Ptr to string pointer for input, ptr to converted number*/ /* Radix (number base) <= 16 */ /* Outputs : TRUE if found a number, else FALSE */ /************************************************************************/ MBool getnum32( char **s, Int32 *result, Nat16 radix ) { Reg Nat32 i, j; Reg Int16 neg; Reg char *p; p = *s; /* Temp save pointer */ deblank(p); /* Skip blanks */ neg = 1; if ( *p == '-' ) /* Check for leading sign*/ { neg = -1; p++; } else if ( *p == '+' ) p++; if ( (i = tohex(*p++, radix)) == ERROR ) /* Check for first digit*/ return( FALSE ); while ( (j = tohex(*p, radix)) != ERROR ) /* Loop to get all digits*/ { j += (i * radix); /* Calc new number */ if ( j < i ) /* If overflow, stop */ break; i = j; /* Else, keep new number*/ p++; /* and point to next char*/ } *s = p; /* Store buffer ptr */ *result = i * neg; /* Store result */ return( delimit(*p) ); /* If no space, bad conv*/ } /* getnum32 () */ /************************************************************************/ /* Function : getnum */ /* Purpose : Get a number in a given base */ /* Inputs : Ptr to string pointer for input, ptr to converted number*/ /* Radix (number base) <= 16 */ /* Outputs : TRUE if found a number, else FALSE */ /************************************************************************/ MBool getnum( char **s, Int16 *result, Nat16 radix ) { Int32 result32; MBool rtn; rtn = getnum32( s, &result32, radix ); *result = (Int16)result32; if ( (result32 > NAT16_MAX) || (result32 < -(NAT16_MAX)) ) return( FALSE ); return( rtn ); } /* getnum () */ #else /************************************************************************/ /* Function : getnum */ /* Purpose : Get a number in a given base */ /* Inputs : Ptr to string pointer for input, ptr to converted number*/ /* Radix (number base) <= 16 */ /* Outputs : TRUE if found a number, else FALSE */ /************************************************************************/ MBool getnum( char **s, Int16 *result, Nat16 radix ) { Reg Nat16 i, j; Reg Int16 neg; Reg char *p; p = *s; /* Temp save pointer */ deblank(p); /* Skip blanks */ neg = 1; if ( *p == '-' ) /* Check for leading sign*/ { neg = -1; p++; } else if ( *p == '+' ) p++; if ( (i = tohex(*p++, radix)) == ERROR ) /* Check for first digit*/ return( FALSE ); while ( (j = tohex(*p, radix)) != ERROR ) /* Loop to get all digits*/ { j += (i * radix); /* Calc new number */ if ( j < i ) /* If overflow, stop */ break; i = j; /* Else, keep new number*/ p++; /* and point to next char*/ } *s = p; /* Store buffer ptr */ *result = i * neg; /* Store result */ return( delimit(*p) ); /* If no space, bad conv*/ } /* getnum () */ #endif /************************************************************************/ /* Function : todec */ /* Purpose : Convert an ASCII character to decimal */ /* Inputs : ASCII character */ /* Outputs : Decimal number, or ERROR if not valid decimal digit */ /************************************************************************/ Int16 todec( Int16 c ) { if ( isdigit(c) ) return( c - '0' ); return( ERROR ); } /* todec() */ /************************************************************************/ /* Function : getFixedPt */ /* Purpose : Get a number in Fixed Point */ /* Inputs : Ptr to string pointer for input, ptr to converted number*/ /* Number of digits to right of decimal point */ /* Outputs : TRUE if found a number, else FALSE */ /* Comment : Result is * (10^decDigits) + */ /************************************************************************/ MBool getFixedPt( char **s, Int16 *resultPtr, Nat16 decDigits ) { Reg Int16 val, shftCnt; Reg char *p; if ( getnum(s, resultPtr, 10) ) val = *resultPtr; else { if ( **s == '.' ) val = 0; else return( FALSE ); } p = *s; shftCnt = decDigits; if ( *p == '.' ) for (p++; (shftCnt > 0) && (isdigit(*p)); shftCnt--, p++) { val *= 10; val += todec(*p); } while ( shftCnt-- > 0 ) /* Adjust if not enuf digits*/ val *= 10; while ( isdigit(*p) ) /* Discard add'l precision*/ p++; *s = p; *resultPtr = val; return( delimit(*p) ); } /* getFixedPt() */ /************************************************************************/ /* Function : printword */ /* Purpose : Print a word to default serial port */ /* Inputs : Word to print */ /* Outputs : None */ /* Comments : Largest size this can print is Nat16, which is at most */ /* 5 decimal digits. So buffer of 8 is large enough */ /************************************************************************/ Void printword( Nat16 num, Int16 digits, Int16 radix, Int16 fillchar, MBool dosigned) { #define BLEN 8 Byte buf[BLEN]; Int16 i, j; if ( dosigned ) if ( (Int16)num < 0 ) { if (digits) digits--; num = -num; } else /* If signed nmbr but postv*/ dosigned = FALSE; /* show not signed */ i = 0; do /* Fill buffer with digits*/ { /* LSB in buf[0] */ j = num % radix; buf[i] = (j > 9) ? (j + 'A' - 10) : (j + '0'); num /= radix; i++; } while ( (i < BLEN) && num ); if ( digits && (i > digits) ) i = digits; for( j = digits; j > i; j-- ) xputc( fillchar ); if ( dosigned ) /* TRUE iff signed & neg */ xputc('-'); while ( --i >= 0 ) /* Print buffer from */ xputc( buf[i] ); /* MSB (buf[7]) */ } /* printword() */ /************************************************************************/ /* Function : xprintf */ /* Purpose : Print formatted output to default serial port */ /* Inputs : Format string, parameters */ /* Outputs : None */ /* Comments : Implements %d, %i, %x, %u, %s, %c functions of printf */ /************************************************************************/ Void xprintf( const char *format, ... ) { va_list ap; const char *s, *p; Int16 fillchar, fmtlen, radix; MBool dosigned; va_start(ap, format); s = format; while (*s) { if ( *s != '%' ) xputc( *s++ ); else { fmtlen = 0; radix = 16; dosigned = FALSE; fillchar = (*++s == '0') ? '0' : ' '; while ( isdigit(*s) ) fmtlen = fmtlen * 10 + (*s++ - '0'); switch (*s++) { case 's': p = va_arg(ap, char *); if ( fmtlen == 0 ) xputs(p); else while ( fmtlen-- ) { if (*p) xputc( *p++ ); else xputc(' '); } break; case 'c': xputc( va_arg(ap, Nat16) ); break; case 'i': case 'd': dosigned = TRUE; case 'u': radix = 10; case 'x': printword( va_arg(ap, Nat16), fmtlen, radix, fillchar, dosigned ); break; } } } va_end(ap); } /* xprintf() */ /************************************************************************/ /* Function : bitsOn */ /* Purpose : Return how bits set in number */ /* Inputs : Number to check */ /* Outputs : Number of bits set */ /************************************************************************/ Nat16 bitsOn( Nat16 num ) { Reg Nat16 n, bits; for ( n = num, bits = 0; n; n >>= 1 ) if ( n & 1 ) bits++; return( bits ); } /* bitsOn() */ /************************************************************************/ /* Function : random */ /* Purpose : Pseudo-random number generator */ /* Inputs : None */ /* Outputs : Pseudo-random number */ /* Comment : Uses randSeed, seeded in io_term() at each power off */ /************************************************************************/ Nat16 random( Void ) { Reg Nat16 temp; temp = bitsOn(randSeed & RANDOM_POLYNOMIAL); randSeed >>= 1; if ( temp & 1 ) randSeed |= 0x8000; return( randSeed ); } /* random() */ @