00001 /*!@file Devices/BeeSTEM.H Interface to Rand Voorhies' BeeSTEM controller.*/ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rand Voorhies <voorhies@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Devices/BeeSTEM.H $ 00035 00036 #ifndef BEESTEM_H_DEFINED 00037 #define BEESTEM_H_DEFINED 00038 00039 #include "Component/ModelComponent.H" 00040 #include "Component/ModelParam.H" 00041 #include "Devices/Serial.H" 00042 #include "Util/Types.H" 00043 #include "rutz/shared_ptr.h" 00044 00045 #include <pthread.h> 00046 #include <stdarg.h> 00047 00048 00049 // Recursive template metaprogramming is used here to allow us to 00050 // define binary constants in the code, as we use these a lot in this 00051 // BeeSTEM program. See http://www.flipcode.com/cgi-bin/msg.cgi? 00052 // showThread=Tip-CPPCompileTimeBinConst&forum=totd&id=-1 for 00053 // additional info. NOTE: we have to be very careful not to have 00054 // leading zeros in our constants, otherwise they will be interpreted 00055 // as octal numbers by the compiler. The macro BIN below fixes that by 00056 // first forcing the interpretation of our constant as a double (which 00057 // may have leading zeros) and then casting it back to int and doing 00058 // the recursion. See Carlo Pescio's "Binary Constants Using Template 00059 // Metaprogramming," C/C++ Users Journal, February 1997 for a version 00060 // of that (which we here bugfixed for syntax). 00061 template<unsigned long int N> class binary 00062 { public: enum { bit = N % 10, value = bit + (((binary<N/10>::value)<<1)) }; }; 00063 template <> class binary<0> { public: enum { bit = 0, value = 0 }; }; 00064 #define BIN(N) (((byte(binary<(unsigned long int)(N##.0)>::value)))) 00065 00066 //! BeeSTEM event types 00067 /*! 00068 This is the EventType that is passed to an external event handler on an event trigger. 00069 For simplicity, COMPASS_HEADING_EVENT through MOTOR_E_CURR_EVENT are used internally to 00070 address our data buffer. If any events need to be added later, please just make sure to 00071 pay attention to how the data buffer size is initialized in the private section of this 00072 class, and how it is addressed in the accessor functions as well as the run loop. 00073 */ 00074 enum BeeSTEMEventType { 00075 COMPASS_HEADING_EVENT = 0, 00076 COMPASS_PITCH_EVENT = 1, 00077 COMPASS_ROLL_EVENT = 2, 00078 ACCEL_X_EVENT = 3, 00079 ACCEL_Y_EVENT = 4, 00080 INT_PRESS_EVENT = 5, 00081 EXT_PRESS_EVENT = 6, 00082 TEMP1_EVENT = 7, 00083 TEMP2_EVENT = 8, 00084 TEMP3_EVENT = 9, 00085 DIG_IN_EVENT = 10, 00086 ADC_IN_EVENT = 11, 00087 MOTOR_A_CURR_EVENT = 12, 00088 MOTOR_B_CURR_EVENT = 13, 00089 MOTOR_C_CURR_EVENT = 14, 00090 MOTOR_D_CURR_EVENT = 15, 00091 MOTOR_E_CURR_EVENT = 16, 00092 ECHO_REPLY_EVENT = 17, 00093 RESET_EVENT = 18, 00094 SW_OVERFLOW_EVENT = 19, 00095 FRAMING_ERR_EVENT = 20, 00096 OVR_ERR_EVENT = 21, 00097 HMR3300_LOST_EVENT = 22, 00098 ACCEL_LOST_EVENT = 23, 00099 TEMP1_LOST_EVENT = 24, 00100 TEMP2_LOST_EVENT = 25, 00101 HMR_LEVELED_EVENT = 26, 00102 ESTOP_EVENT = 27, 00103 UNRECOGNIZED_EVENT = 28, 00104 BAD_IN_CMD_SEQ_EVENT = 29, 00105 BAD_OUT_CMD_SEQ_EVENT = 30, 00106 RESET_ACK_EVENT = 31, 00107 DATA_EVENT = 32, 00108 HMR3300_CAL_EVENT = 33, 00109 NO_EVENT = 34 00110 }; 00111 #define DATATOP MOTOR_E_CURR_EVENT 00112 00113 //! BeeSTEM Reporting Masks 00114 /*! Quick and dirty way to turn on reporting for a feature or the 00115 BeeSTEM. Simply pass one of these masks to setReporting with 00116 a bool to turn reporting for that feature on or off */ 00117 enum BeeSTEMReportingMask { 00118 HMR3300 = BIN(01100010), 00119 ACCELEROMETER = BIN(01100000), 00120 INT_PRESS = BIN(01101010), 00121 EXT_PRESS = BIN(01101100), 00122 TEMP1 = BIN(01100100), 00123 TEMP2 = BIN(01100110), 00124 TEMP3 = BIN(01101000), 00125 DIG_IN = BIN(01101110), 00126 ADC_IN = BIN(01110000), 00127 MOTOR_CURR = BIN(01110010) 00128 }; 00129 00130 00131 //! BeoChip event listener 00132 /*! The BeoChipListener gets called each time an event is received 00133 from the BeoChip. The BeoChipEventType is passed to the listener, 00134 allowing the user to determine the type of event received and to 00135 then interpret the event data also passed to the listener. By 00136 default, there is no listener, and users can just asynchronously 00137 query the BeoChip for its current internal state. If those queries 00138 come in too slowly, however, they may miss some events (e.g., a 00139 briefly pressed key). So, production code should define a derived 00140 class for BeoChipListener and register it with the BeoChip object, 00141 so that it will take action as soon as an event is received. */ 00142 class BeeSTEMListener { 00143 public: 00144 //! Destructor 00145 virtual ~BeeSTEMListener(); 00146 00147 //! An event was received 00148 /*! This function will be called by the BeeSTEM once you have 00149 registered your BeeSTEMListener derivative with the BeeSTEM using 00150 BeeSTEM::setListener(). Beware that the call to event() will be 00151 from a thread running in the BeeSTEM and thus will operate in 00152 parallel with your main thread and main loop. See test-BeeSTEM.C 00153 for an example of how to synchronize a main loop with these 00154 asynchronous event calls. The following data will be passed along 00155 with the event type: 00156 <PRE> 00157 _type______________________dat1__________________dat2_ 00158 COMPASS_HEADING heading 0 00159 COMPASS_PITCH pitch 0 00160 COMPASS_ROLL roll 0 00161 ACCEL_X x-acceleration 0 00162 ACCEL_Y y-acceleration 0 00163 INT_PRESS internal pressure 0 00164 EXT_PRESS external pressure 0 00165 TEMP1 temperature 1 0 00166 TEMP2 temperature 2 0 00167 TEMP3 temperature 3 0 00168 DIG_IN digital input byte 0 00169 ADC_IN spare adc value 0 00170 MOTOR_CURR current motor number 00171 All Others 0 0 00172 </PRE> 00173 */ 00174 virtual void event(const BeeSTEMEventType t, const unsigned char dat1, 00175 const unsigned char dat2) = 0; 00176 }; 00177 00178 //! BeeSTEM.H Interface to Rand Voorhies' BeeSTEM device 00179 /*! Hardware interface Class. Contains interfaces to display to an 00180 LCD, a 2D Accelerometer/Compass, and extra high speed accelerometer, 00181 3 temperature sensors, internal & external pressure sensors, 8 digital I/O pins 00182 an ADC pin, 5 PWM outputs, and motor current readings. */ 00183 class BeeSTEM : public ModelComponent 00184 { 00185 public: 00186 // ############################################################ 00187 /*! @name Constructors, destructors and debugging */ 00188 //@{ 00189 00190 //! Default constructor. See ModelComponent.H 00191 BeeSTEM(OptionManager& mgr, 00192 const std::string& descrName = "BeeSTEM", 00193 const std::string& tagName = "BeeSTEM", 00194 const char* dev = "/dev/ttyS0"); 00195 00196 //! Destructor 00197 ~BeeSTEM(); 00198 00199 //! Install a callback (listener) for BeeSTEM events 00200 /*! This callback will be called with the corresponding 00201 BeeSTEMEventType each time an event is received from the BeeSTEM. */ 00202 void setListener(rutz::shared_ptr<BeeSTEMListener>& listener); 00203 00204 //! Send an echo request 00205 /*! The BeeSTEM should reply with an Echo_Reply event if it is alive */ 00206 bool echoRequest(); 00207 00208 //! Turn debug mode on/off 00209 /*! When in debug mode, the BeeSTEM sends an EchoReply for each command 00210 it receives. */ 00211 bool debugMode(const bool on); 00212 00213 //! Reset the BeeSTEM 00214 bool resetChip(); 00215 00216 //! Toggle the calibration mode of the HMR3300 00217 bool toggleCalibrateHMR3300(); 00218 00219 //! Level the HMR3300 00220 bool levelHMR3300(); 00221 00222 //@} 00223 00224 // ############################################################ 00225 /*! @name LCD functions */ 00226 //@{ 00227 00228 //! Print some text 00229 /*! syntax is the same as printf(). Returns true on success. */ 00230 bool lcdPrintf(const char *fmt, ...) 00231 // NOTE: this __attribute__ tells gcc that it should issue 00232 // printf-style warnings when compiling calls to 00233 // BeeSTEM::lcdPrintf(), treating the 2nd argument (fmt) as the 00234 // format string, and the 3rd and subsequent arguments as the 00235 // printf-style parameters (SUBNOTE: because this is a member 00236 // function, there is a hidden 'this' parameter that counts as arg 00237 // 1, so the listed arguments are counted starting from 2) 00238 __attribute__((format(__printf__, 2, 3))); 00239 ; 00240 00241 //! Clear LCD screen 00242 bool lcdClear(); 00243 //@} 00244 00245 // ############################################################ 00246 /*! @name PWM control functions */ 00247 //@{ 00248 00249 //! Sets the speed of a motor. -100 is full reverse, and +100 is full forwards 00250 /*! Note that the [-100..+100] is only a percentage of the maximum possible 00251 PWM allowed by the BeeSTEM. See MotorControl.H of the BeeSTEM code for more. */ 00252 bool setMotor(const int motor, signed char speed); 00253 00254 //! Gets the current current consumption of a motor 00255 /*! Note that motor current monitoring must be explicitely turned on*/ 00256 float getMotorCurrent(const int motor) const; 00257 00258 //@} 00259 00260 // ############################################################ 00261 /*! @name Data aquisition and reporting functions */ 00262 //! Tell the BeeSTEM to start (or stop) sending a data type over the serial connection. 00263 /*! This function takes in a BeeSTEMReportingMask and a bool, and tells the BeeSTEM 00264 to start or stop monitoring and reporting a resource designated by the mask. 00265 Note that turning on too many reporting features may significantly slow down 00266 the device, so please only turn on what's needed.*/ 00267 bool setReporting(const BeeSTEMReportingMask t, const bool on); 00268 00269 00270 //@} 00271 00272 // ############################################################ 00273 /*! @name Data Acquisition Functions */ 00274 //@{ 00275 00276 //! Get Compass Heading 00277 byte getCompassHeading(); 00278 00279 //! Get Compass Pitch 00280 byte getCompassPitch(); 00281 00282 //! Get Compass Pitch 00283 byte getCompassRoll(); 00284 00285 //! Get High Speed Accelerometer X 00286 byte getAccelX(); 00287 00288 //! Get High Speed Accelerometer Y 00289 byte getAccelY(); 00290 00291 //! Get Internal Pressure 00292 byte getIntPress(); 00293 00294 //! Get External Pressure 00295 byte getExtPress(); 00296 00297 //! Get Temperature Zone 1 00298 byte getTemp1(); 00299 00300 //! Get Temperature Zone 2 00301 byte getTemp2(); 00302 00303 //! Get Temperature Zone 3 00304 byte getTemp3(); 00305 00306 //! Get current raw Analog value from the spare ADC pin 00307 byte getSpareADC(); 00308 00309 //! Get the current from a motor 00310 byte getMotorCurr(byte whichone); 00311 00312 //! Get the value of a single digital input pin 00313 bool getDigitalIn(const int whichone); 00314 00315 //! Get the value of all 8 digital input pins as a whole byte 00316 byte getDigitalIn(); 00317 00318 00319 // ############################################################ 00320 /*! @name Digital output function */ 00321 //@{ 00322 00323 //! Turn a given digital output on/off 00324 /*! Valid range for outnum is [0..7] */ 00325 bool setDigitalOut(const int outnum, const bool on); 00326 00327 //@} 00328 00329 //! This is our main running thread - don't call directly 00330 /*! Should have been protected, but is not because of pthread hack. */ 00331 void run(); 00332 00333 //! send a byte to the BeeSTEM 00334 /*! You should never have to use this, use the other functions 00335 instead. This function is made public just for testing the chip's 00336 robustness against a flood of random junk hitting it... See 00337 test-BeeSTEM.C */ 00338 bool writeByte(const byte val, const bool uselock = true); 00339 00340 protected: 00341 //! open the port and get started 00342 void start1(); 00343 00344 //! close the port and get stopped 00345 void stop2(); 00346 00347 private: 00348 00349 nub::soft_ref<Serial> itsSerial; 00350 bool itsKeepgoing; 00351 00352 rutz::shared_ptr<BeeSTEMListener> itsListener; 00353 00354 pthread_t runner; 00355 pthread_mutex_t lock, serlock; 00356 00357 //!Buffer for incoming data from the BeeSTEM 00358 byte* itsData; 00359 00360 int itsCurrentMotorValues[5]; 00361 00362 }; 00363 00364 #endif 00365 00366 // ###################################################################### 00367 /* So things look consistent in everyone's emacs... */ 00368 /* Local Variables: */ 00369 /* indent-tabs-mode: nil */ 00370 /* End: */