00001 /*!@file Devices/BeoChip.H Interface to Brian Hudson's BeoChip interface device.*/ 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: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Devices/BeoChip.H $ 00035 // $Id: BeoChip.H 6990 2006-08-11 18:13:51Z rjpeters $ 00036 // 00037 00038 #ifndef BEOCHIP_H_DEFINED 00039 #define BEOCHIP_H_DEFINED 00040 00041 #include "Component/ModelComponent.H" 00042 #include "Component/ModelParam.H" 00043 #include "Devices/Serial.H" 00044 #include "Util/Types.H" 00045 #include "rutz/shared_ptr.h" 00046 00047 #include <pthread.h> 00048 #include <stdarg.h> 00049 00050 //! BeoChip event types 00051 enum BeoChipEventType { 00052 NONE = 0, PWM0 = 1, PWM1 = 2, KBD = 3, ADC0 = 4, ADC1 = 5, 00053 RESET = 6, ECHOREP = 7, 00054 INOVERFLOW = 8, SERIALERROR = 9, OUTOVERFLOW = 10 }; 00055 00056 //! BeoChip event listener 00057 /*! The BeoChipListener gets called each time an event is received 00058 from the BeoChip. The BeoChipEventType is passed to the listener, 00059 allowing the user to determine the type of event received and to 00060 then interpret the event data also passed to the listener. By 00061 default, there is no listener, and users can just asynchronously 00062 query the BeoChip for its current internal state. If those queries 00063 come in too slowly, however, they may miss some events (e.g., a 00064 briefly pressed key). So, production code should define a derived 00065 class for BeoChipListener and register it with the BeoChip object, 00066 so that it will take action as soon as an event is received. */ 00067 class BeoChipListener { 00068 public: 00069 //! Destructor 00070 virtual ~BeoChipListener(); 00071 00072 //! An event was received 00073 /*! This function will be called by the BeoChip once you have 00074 registered your BeoChipListener derivative with the BeoChip using 00075 BeoChip::setListener(). Beware that the call to event() will ve 00076 from a thread running in the BeoChip and thus will operate in 00077 parallel with your main thread and main loop. See test-BeoChip.C 00078 for an example of how to synchronize a main loop with these 00079 asynchronous event calls. The following data will be passed along 00080 with the event type: 00081 <PRE> 00082 00083 Type valint valfloat 00084 ---------------------------------------------------------------------- 00085 NONE 0 0.0F 00086 PWM0 pulse 0 width, 1.6us units calibrated width in [-1..1] 00087 PWM1 pulse 1 width, 1.6us units calibrated width in [-1..1] 00088 KBD 5 LSB show the 5 keys 0.0F 00089 ADC0 A/D 0 value calibrated value in [-1..1] 00090 ADC1 A/D 0 value calibrated value in [-1..1] 00091 all others 0 0.0F 00092 00093 </PRE> 00094 */ 00095 virtual void event(const BeoChipEventType t, const int valint, 00096 const float valfloat) = 0; 00097 }; 00098 00099 //! BeoChip.H Interface to Brian Hudson's BeoChip device 00100 /*! Hardware interface Class. Contains interfaces to display to an 00101 LCD, read servo pulse values (2), set servo positions (8), get 00102 A/D conversion values (2), manipulate four digital outs, 00103 and finally, get some intput from 5 pushbuttons. */ 00104 class BeoChip : public ModelComponent 00105 { 00106 public: 00107 // ############################################################ 00108 /*! @name Constructors, destructors and debugging */ 00109 //@{ 00110 00111 //! Default constructor. See ModelComponent.H 00112 BeoChip(OptionManager& mgr, 00113 const std::string& descrName = "BeoChip", 00114 const std::string& tagName = "BeoChip"); 00115 00116 //! Destructor 00117 ~BeoChip(); 00118 00119 //! Install a callback (listener) for BeoChip events 00120 /*! This callback will be called with the corresponding 00121 BeoChipEvenType each time an event is received from the BeoChip. */ 00122 void setListener(rutz::shared_ptr<BeoChipListener>& listener); 00123 00124 //! Send an echo request 00125 /*! The BeoChip should reply with an EchoReply event if it is alive */ 00126 bool echoRequest(); 00127 00128 //! Turn debug mode on/off 00129 /*! When in debug mode, the BeoChip sends an EchoReply for each command 00130 it receives. */ 00131 bool debugMode(const bool on); 00132 00133 //! Reset the BeoChip 00134 bool resetChip(); 00135 00136 //@} 00137 00138 // ############################################################ 00139 /*! @name LCD functions */ 00140 //@{ 00141 00142 //! Go to given cursor position 00143 bool lcdGotoXY(const int x = 0, const int y = 0); 00144 00145 //! Go to given cursor position 00146 bool lcdGoto(const int i = 0); 00147 00148 //! Print some text 00149 /*! syntax is the same as printf(). Returns true on success. */ 00150 bool lcdPrintf(const char *fmt, ...) 00151 // NOTE: this __attribute__ tells gcc that it should issue 00152 // printf-style warnings when compiling calls to 00153 // BeoChip::lcdPrintf(), treating the 2nd argument (fmt) as the 00154 // format string, and the 3rd and subsequent arguments as the 00155 // printf-style parameters (SUBNOTE: because this is a member 00156 // function, there is a hidden 'this' parameter that counts as arg 00157 // 1, so the listed arguments are counted starting from 2) 00158 __attribute__((format(__printf__, 2, 3))); 00159 ; 00160 00161 //! Print some text starting at given cursor position 00162 /*! syntax is the same as printf(), plus the x, y 00163 coordinates. Returns true on success. */ 00164 bool lcdPrintf(const int x, const int y, const char *fmt, ...) 00165 // NOTE: this __attribute__ tells gcc that it should issue 00166 // printf-style warnings when compiling calls to 00167 // BeoChip::lcdPrintf(), treating the 3rd argument (fmt) as the 00168 // format string, and the 4th and subsequent arguments as the 00169 // printf-style parameters (SUBNOTE: because this is a member 00170 // function, there is a hidden 'this' parameter that counts as arg 00171 // 1, so the listed arguments are counted starting from 2) 00172 __attribute__((format(__printf__, 4, 5))); 00173 ; 00174 00175 //! Clear LCD screen 00176 bool lcdClear(); 00177 00178 //! Scroll display left by i positions 00179 bool lcdScrollLeft(const int i = 1); 00180 00181 //! Scroll display right by i positions 00182 bool lcdScrollRight(const int i = 1); 00183 00184 //! Move cursor left by i positions 00185 bool lcdMoveCursorLeft(const int i = 1); 00186 00187 //! Move cursor right by i positions 00188 bool lcdMoveCursorRight(const int i = 1); 00189 00190 //! Make cursor a blinking block 00191 bool lcdCursorBlock(); 00192 00193 //! Make cursor a blinking underline 00194 bool lcdCursorUnderline(); 00195 00196 //! Make cursor invisible (not recommended) 00197 bool lcdCursorInvisible(); 00198 00199 //! Load one of the pre-programmed custom fonts 00200 /*! Valid font values are [0..7]. Font 0 is an all-blank font. */ 00201 bool lcdLoadFont(const int font); 00202 00203 //! Load a new font from an array of 64 bytes 00204 bool lcdLoadFont(const byte data[64]); 00205 00206 //! Select an LCD animation and start it 00207 /*! Valid anim values are [0..7]. Anim 0 is no animation. */ 00208 bool lcdSetAnimation(const int anim = 0); 00209 00210 //! Send a raw byte to the LCD 00211 bool lcdSendRaw(const byte val, const bool RS, const bool uselock = true); 00212 00213 //@} 00214 00215 // ############################################################ 00216 /*! @name Servo control functions */ 00217 //@{ 00218 00219 //! Shim the BeoChip's servo pulses 00220 /*! Valid shim values are [0..7]. The default at bootup of the 00221 BeoChip is 4. Higher values will increase pulse length and lower 00222 values will decrease them. This may allow you to shim the pulses 00223 so as to maximally exploit the range of your servos. */ 00224 bool shimServos(const byte shim); 00225 00226 //! Calibrate a servo 00227 /*! Calibration will be made so that setServo(servo, 0.0F) will send the 00228 value 'neutralval' to the servo, setServo(servo, -1.0F) will send 00229 minval and setServo(servo, 1.0F) will send maxval. */ 00230 void calibrateServo(const int servo, const byte neutralval, 00231 const byte minval, const byte maxval); 00232 00233 //! Moves servo # to given position in [-1.0 .. 1.0] 00234 /*! Returns true on success, false if some serial error occurred. */ 00235 bool setServo(const int servo, const float position); 00236 00237 //! Gets the current position of given servo 00238 float getServo(const int servo) const; 00239 00240 //! Sets servo number servo to value val 00241 bool setServoRaw(const int servo, const byte val); 00242 00243 //! Gets the current raw position of given servo 00244 byte getServoRaw(const int servo) const; 00245 00246 //@} 00247 00248 // ############################################################ 00249 /*! @name Pulse acquisition functions */ 00250 //@{ 00251 00252 //! Turn pulse captures on/off 00253 bool capturePulse(const int whichone, const bool on); 00254 00255 //! Calibrate a pulse 00256 /*! Calibration will be made so that getPulse() returns 0.0F when 00257 raw pulse width is 'neutralval', returns -1.0F when the raw pulse 00258 value is minval and returns 1.0F when the raw pulse value is 00259 maxval. */ 00260 void calibratePulse(const int whichone, const int neutralval, 00261 const int minval, const int maxval); 00262 00263 //! Get current pulse value, between [-1.0..1.0] 00264 float getPulse(const int whichone); 00265 00266 //! Get current pulse value, raw uncalibrated 00267 short int getPulseRaw(const int whichone); 00268 00269 //@} 00270 00271 // ############################################################ 00272 /*! @name Analog acquisition functions */ 00273 //@{ 00274 00275 //! Turn A/D captures on/off 00276 bool captureAnalog(const int whichone, const bool on); 00277 00278 //! Calibrate an A/D converter 00279 /*! Calibration will be made so that getAnalog() returns 0.0F when 00280 raw value width is 'neutralval', returns -1.0F when the raw value 00281 is minval and returns 1.0F when the raw value is maxval. */ 00282 void calibrateAnalog(const int whichone, const int neutralval, 00283 const int minval, const int maxval); 00284 00285 //! Get current calibrated Analog value 00286 float getAnalog(const int whichone); 00287 00288 //! Get current raw Analog value 00289 byte getAnalogRaw(const int whichone); 00290 00291 //@} 00292 00293 // ############################################################ 00294 /*! @name Keyboard acquisition functions */ 00295 //@{ 00296 00297 //! Turn keyboard capture on/off 00298 bool captureKeyboard(const bool on); 00299 00300 //! Turn keyboard debouncing on/off 00301 bool debounceKeyboard(const bool on); 00302 00303 //! Get current Keyboard value 00304 int getKeyboard(); 00305 00306 //@} 00307 00308 // ############################################################ 00309 /*! @name Digital output function */ 00310 //@{ 00311 00312 //! Turn a given digital output on/off 00313 /*! Valid range for outnum is [0..3] */ 00314 bool setDigitalOut(const int outnum, const bool on); 00315 00316 //@} 00317 00318 //! This is our main running thread - don't call directly 00319 /*! Should have been protected, but is not because of pthread hack. */ 00320 void run(); 00321 00322 //! send a byte to the BeoChip 00323 /*! You should never have to use this, use the other functions 00324 instead. This function is made public just for testing the chip's 00325 robustness against a flood of random junk hitting it... See 00326 test-BeoChip.C */ 00327 bool writeByte(const byte val, const bool uselock = true); 00328 00329 protected: 00330 NModelParam<std::string> itsDevName; //!< name of our serial device 00331 NModelParam<int> itsLCDrows; //!< number of rows of LCD screen (lines of text) 00332 NModelParam<int> itsLCDcols; //!< number of columns of LCD screen 00333 00334 rutz::shared_ptr<NModelParam<int> >* zeroS; //!< zero calibration value, for 0.0F (servo) 00335 rutz::shared_ptr<NModelParam<int> >* minS; //!< minimum raw value, for -1.0F (servo) 00336 rutz::shared_ptr<NModelParam<int> >* maxS; //!< maximum raw value, for 1.0F (servo) 00337 byte *servopos; //!< raw servo positions [0..255] 00338 00339 rutz::shared_ptr<NModelParam<int> >* zeroP; //!< zero calibration value, for 0.0F (pulse) 00340 rutz::shared_ptr<NModelParam<int> >* minP; //!< minimum raw value, for -1.0F (pulse) 00341 rutz::shared_ptr<NModelParam<int> >* maxP; //!< maximum raw value, for 1.0F (pulse) 00342 short int *pulseval; //!< raw pulse values (11bit int) 00343 00344 rutz::shared_ptr<NModelParam<int> >* zeroA; //!< zero calibration value, for 0.0F (pulse) 00345 rutz::shared_ptr<NModelParam<int> >* minA; //!< minimum raw value, for -1.0F (servo) 00346 rutz::shared_ptr<NModelParam<int> >* maxA; //!< maximum raw value, for 1.0F (servo) 00347 00348 NModelParam<bool> itsUseRTSCTS; //!< Use RTS/CTS flow control 00349 00350 byte *adcval; //!< raw adc values [0..255] 00351 00352 byte keyboard; //!< our current keyboard state 00353 00354 //! Convert from raw (int) to calibrated (-1.0..1.0) position 00355 float rawToCalib(const int raw, const int zero, const int mini, 00356 const int maxi) const; 00357 00358 //! Convert from calibrated (-1.0..1.0) to raw (int) position 00359 int calibToRaw(const float calibrated, const int zero, const int mini, 00360 const int maxi, const int bits = 8) const; 00361 00362 //! open the port and get started 00363 void start1(); 00364 00365 //! close the port and get stopped 00366 void stop2(); 00367 00368 private: 00369 struct termios itsOldtio; //!< our old terminal io settings 00370 int itsFd; //!< our serial port file descriptor 00371 rutz::shared_ptr<BeoChipListener> itsListener; 00372 00373 pthread_t runner; 00374 pthread_mutex_t lock, serlock; 00375 bool keepgoing; 00376 }; 00377 00378 #endif 00379 00380 // ###################################################################### 00381 /* So things look consistent in everyone's emacs... */ 00382 /* Local Variables: */ 00383 /* indent-tabs-mode: nil */ 00384 /* End: */