head 4.4; access ; symbols ; locks oasisa:4.4; strict; comment @ * @; 4.4 date 2001.06.19.12.16.02; author oasisa; state Exp; branches ; next ; desc @New Repository; 6/19/2001 (klh) @ 4.4 log @New Repository; 6/19/2001 (klh) @ text @/****************************************************************************/ /* Copyright 1997 MBARI */ /****************************************************************************/ /* $Header: tinyshut.c,v 1.1 2001/06/19 11:45:05 oasisa Exp $ */ /* Summary : Minimal Driver Routines for type 2 Shutters for PRR Spectro */ /* Filename : shutter22.c */ /* Author : Kent Headley (klh) */ /* Project : OASIS Mooring */ /* $Revision: 1.1 $ */ /* Created : 8/2/00 from shut22.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: */ /****************************************************************************/ /* This module controls a "Shutter", which is a mechanical device designed to cover the optical windows of the Spectroradiometers when not actively sampling. This is to eliminate biofouling which degrades the data obtained by the Spectroradiometers. The shutter contains a DC motor to move the covers, and a potentiometer for determining the position of the covers. The covers are rotated into the dxesired open or closed position, and the design is such that they can make continuous revolutions in either direction. Drive electronics within the OASIS can consists of an H-Bridge reversible motor drive with overcurrent sensing, and conditioning for the potentiometer that presents position as A/D counts ranging from ~100 to ~800. The motor drive is controlled by two I/O bits known as "control" and "direction". Direction being hi results in increasing A/D counts when in motion, and we refer to this as the "clockwise" direction. Control is a bi-directional bit which when driven hi starts motor motion, and stops it when driven low. When the state of the control bit is read, hi indicates in motion and lo indicates stopped. Once started the motor will continue to run in the direction defined by the direction bit until stopped or an overcurrent event occurs. An overcurrent event is indicative of an obstruction to the mechanism, and the drive electronics will revert to the stopped state automaticly. In an attempt to deal with an obstructed condition, the code that follows implements an algorithm which reverses the direction of rotation when obstructed, taking the "long way around" to the open or closed position. Each invocation of the driver writes a record to the log with the results of the move attempted. In this way we hope to observe the occurance of an obstruction and successful recovery from it in the field. This module assumes the ownership of PIA_A, PORT_C. Sharing of unused bits on this port by other modules has not been implemented. (at some point we should deal with it, but not in this module, dkw.) Addendum 8/2/00 To create enough room for instrument drivers for the 2000M1 turn, an attempt is being made to cut the shutter driver to a bare-bones implementation with simple open|close functionality and little or no optimization for power and error checking. One strategy for reducing space has been to implement several 'one-liner' functions as macros reducing space while maintaining compatibility with shutcom and shutcal. Defining functions of several lines is basically a wash; the global byte portbits and the do/while structure takes up as much space as the function overhead. Tried defining PORT_CTL,PORT_DIR macros to use in functions (to eliminate Byte portbits, but they took up more space (why??) klh */ #include /* MBARI type definitions */ #include /* MBARI constants */ #include /* OASIS controller definitions */ #include /* OASIS I/O definitions */ #include /* Log record definitions */ #include <80C196.h> /* 80196 Register mapping */ #include /* OASIS Multitasking definitions */ #include /* ARGOS definition */ #include /* shutter definitions */ /* Use function version */ #undef stopMotor #undef startMotor #undef initMotor #undef sector /********************************/ /* External Functions */ /********************************/ Extern Nat16 io_atod( Nat16 channel ); Extern Void drvLog( Driver *dp, Byte *samplep, Int16 len ); Extern volatile Reg Nat16 tick; /* 10 ms ticker */ Extern Void drv_pwron( Driver *dp ); Extern Void drv_pwroff( Driver *dp ); #ifdef ARGOS_SHUTTER Extern Void argosShutter( Shutter_data *sdp ); #endif /********************************/ /* External Data */ /********************************/ Extern Reg Byte ioctrl; /* Copy of oasis_ctrl */ Extern Int16 ad_use_cnt; /* Number of people using A/D */ /********************************/ /* Module Local Data */ /********************************/ #ifdef SHUTTER #if (NUMBER_OF_SHUTTERS == 1) const shutter_const shutter_io[NUMBER_OF_SHUTTERS] = { { SHUTTER0_ANALOG_PORT, 0x01, 0x02 } /* Shutter0: A/D chan, control bitmask, direction bitmask */ }; #else /* For EqPac */ const shutter_const shutter_io[NUMBER_OF_SHUTTERS] = { { SHUTTER0_ANALOG_PORT, 0x01, 0x02 }, /* Shutter0: A/D chan, control bitmask, direction bitmask */ { SHUTTER1_ANALOG_PORT, 0x04, 0x08 } /* Shutter1: A/D chan, control bitmask, direction bitmask */ }; #endif /************************************************************************/ /* Function : initMotor */ /* Purpose : Set up motor drive port */ /* Inputs : Pointer to shutter structure */ /* Outputs : None */ /************************************************************************/ #ifndef initMotor Void initMotor( Shutter_data *sd ) { Byte portbits; portbits = shutter_io[sd->ShutterNumber].control_bit | shutter_io[sd->ShutterNumber].dir_bit; piaa_pdc &= ~portbits; piaa_ddrc |= portbits; } /* take control and direction bits low, set as output. */ #endif /************************************************************************/ /* Function : startMotor */ /* Purpose : Turn on motor drive */ /* Inputs : Pointer to shutter structure */ /* Outputs : None */ /************************************************************************/ #ifndef startMotor Void startMotor( Shutter_data *sd ) { Byte portbits; portbits = shutter_io[sd->ShutterNumber].control_bit; piaa_pdc |= portbits; piaa_ddrc |= portbits; task_delay(2); piaa_ddrc &= ~portbits; } /* take control bit high, set as output, delay for 20MS then set as input */ #endif /************************************************************************/ /* Function : stopMotor */ /* Purpose : Turn off motor drive */ /* Inputs : Pointer to shutter structure */ /* Outputs : None */ /************************************************************************/ #ifndef stopMotor Void stopMotor( Shutter_data *sd ) { Byte portbits; portbits = shutter_io[sd->ShutterNumber].control_bit; piaa_pdc &= ~portbits; piaa_ddrc |= portbits; task_delay(15); } /* take control bit low, set as output, delay 150MS to allow coast down */ #endif /************************************************************************/ /* Function : setDirMotor */ /* Purpose : Set direction of motor drive */ /* Inputs : Boolean, true=clockwise, pointer to shutter structure */ /* Outputs : None */ /************************************************************************/ Void setDirMotor( MBool clockwise, Shutter_data *sd ) { Byte portbits; portbits = shutter_io[sd->ShutterNumber].dir_bit; if (clockwise) piaa_pdc |= portbits; else piaa_pdc &= ~portbits; } /************************************************************************/ /* Function : readMotor */ /* Purpose : Return state of motor drive */ /* Inputs : Pointer to shutter structure */ /* Outputs : Boolean, true=running */ /************************************************************************/ #ifndef readMotor MBool readMotor( Shutter_data *sd ) { return(( piaa_pdc & shutter_io[sd->ShutterNumber].control_bit) ? TRUE : FALSE ); } #endif /************************************************************************/ /* Function : readDirMotor */ /* Purpose : Return direction of motor drive */ /* Inputs : None */ /* Outputs : Boolean, true=clockwise */ /************************************************************************/ #ifndef readDirMotor MBool readDirMotor( Shutter_data *sd ) { return(( piaa_pdc & shutter_io[sd->ShutterNumber].dir_bit) ? CW : CCW ); } #endif /************************************************************************/ /* Function : reverseMotor */ /* Purpose : Reverse direction of motor drive */ /* Inputs : Pointer to shutter structure */ /* Outputs : None */ /************************************************************************/ #ifndef reverseMotor Void reverseMotor(Shutter_data *sd) { setDirMotor(!readDirMotor(sd),sd); } #endif /************************************************************************/ /* Function : readShutter */ /* Purpose : Return position value */ /* Inputs : Pointer to shutter structure */ /* Outputs : Nat16, shutter position */ /************************************************************************/ #ifndef readShutter Nat16 readShutter(Shutter_data *sd) { return(io_atod(shutter_io[sd->ShutterNumber].ad_port)); } #endif /************************************************************************/ /* Function : sector */ /* Purpose : Determine if we are: Open, Closed, In between. */ /* Inputs : Pointer to shutter structure */ /* Outputs : State value OPEN, CLOSED, INTER */ /************************************************************************/ #ifndef sector State sector(Shutter_data *sd) { Nat16 shutterPosition; shutterPosition = readShutter(sd); /* insure A/D read only once */ if((sd->ClosePosition-SHUTTER_CLOSED_SECTOR/2 <= shutterPosition ) && ( shutterPosition <= sd->ClosePosition+SHUTTER_CLOSED_SECTOR/2)) return(CLOSED); if((sd->ClosePosition-SHUTTER_OPEN_SECTOR/2 >= shutterPosition ) || ( shutterPosition >= sd->ClosePosition+SHUTTER_OPEN_SECTOR/2)) return(OPEN); return(INTER); /* must be somewhere else... */ } #endif /************************************************************************/ /* Function : moveShutter dkw */ /* Purpose : Open or shut the shutter */ /* Inputs : Pointer to shutter structure */ /* Outputs : 0 if got there, else error code, TryCount is updated */ /************************************************************************/ Byte moveShutter(Shutter_data *sd) { Nat16 ref_tick; startMotor(sd); ref_tick = tick; --sd->TryCount; while(sector(sd) != (sd->Open ? OPEN : CLOSED)) { if (!readMotor(sd)) /* this handles collisions */ { stopMotor(sd); /* allow coast down */ if ( sd->TryCount <= 0 ) { return(2); /* too many tries error code */ } else { reverseMotor(sd); startMotor(sd); ref_tick = tick; --sd->TryCount; } } if ( (tick - ref_tick) > sd->MaxTicks ) /* taking too long..? */ { stopMotor(sd); return(1); /* timeout error code */ } task_delay(SHUTTER_POLL); /* be a good citizen */ } /* end while */ stopMotor(sd); return(0); /* success */ } /* moveShutter() */ /************************************************************************/ /* Function : RunShutter */ /* Purpose : Operate a shutter */ /* Inputs : Pointer to driver, operation type (open:close) */ /* : PARM0 is shutter number */ /* : PARM1 is closed position calibration */ /* : PARM2 is number of attempts to complete operation */ /* : TIMEOUT is seconds allowed for each attempt */ /* Outputs : Logs results of operation */ /************************************************************************/ Void runShutter(Driver *dp ) { Nat16 ShutterLogData[2]; Shutter_data sd; if( dp->drv_cnt >= MAX_SHUT_FAILURES ) /* drv_cnt used for failure count*/ { dp->drv_flags &= ~DO_SYNC; return; /* just skip it */ } sd.ShutterNumber = dp->drv_parms[PARM0]; sd.Open = dp->drv_usrparm; /* type of operation, */ if ( sd.ShutterNumber >= NUMBER_OF_SHUTTERS ) sd.ShutterNumber = 0; /* on which shutter, */ sd.ClosePosition = dp->drv_parms[PARM1]; /* whose calibration is.. */ sd.TryCount = dp->drv_parms[PARM2]; /* how many attempts allowed */ sd.MaxTicks = TICKS_PER_SECOND * dp->drv_parms[TIMEOUT]; initMotor(&sd); /* set up the I/O port */ ad_use_cnt++; /* Show we're using analog voltage */ ioctrl &= ~ANALOG_DSBL; /* Turn on analog power */ oasis_ctrl = ioctrl; task_delay( TICKS_PER_SECOND/2 ); /* Wait 500 ms for pwr to stabilize */ if(sector(&sd) != (sd.Open ? OPEN : CLOSED)) /* make sure we are not already there */ { drv_pwron(dp); task_delay(10); setDirMotor((readShutter(&sd) < sd.ClosePosition) ? (!sd.Open) : sd.Open, &sd); /* this determines shortest direction to desired condition and presets */ /* the motor control to that direction. clockwise is A/D++ */ if((sd.ErrCode = moveShutter(&sd)) != 0) dp->drv_cnt++; /* do move, accumulate result */ else dp->drv_cnt = 0; #if (NUMBER_OF_SHUTTERS < 2) drv_pwroff(dp); /* we're finished with the motor */ #endif } else { sd.ErrCode = 5; /* redundant operaton code, already there */ } ShutterLogData[0] = readShutter(&sd); /* record where we stopped */ if ( --ad_use_cnt <= 0) /* No longer using analog voltage */ { /* If no one else is, */ ioctrl |= ANALOG_DSBL; /* Turn off analog power */ oasis_ctrl = ioctrl; } dp->drv_flags &= ~DO_SYNC; /* pack shutter status into word as: MS open(bit) number(3bits) error(4bits) count(byte) LS */ sd.TryCount = (0x00FF & (dp->drv_parms[PARM2] - sd.TryCount)); /* TryCount was -- */ ShutterLogData[1] = sd.TryCount; ShutterLogData[1] |= ((sd.ErrCode << 8 ) & 0x0F00); /* pack in error bits, */ ShutterLogData[1] |= ((sd.ShutterNumber << 12) & 0x7000); /* and shutter number */ if (sd.Open) ShutterLogData[1] |= 0x8000; /* set direction bit if appropriate */ drvLog(dp,(Byte *)ShutterLogData,sizeof(ShutterLogData)); /* stash it away... */ #ifdef ARGOS_SHUTTER argosShutter( &sd ); /* Tell ARGOS module */ #endif return; /* da da da dat's all folks... */ } /* runShutter() */ #endif @