BeoChip.C

Go to the documentation of this file.
00001 /*!@file Devices/BeoChip.C 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.C $
00035 // $Id: BeoChip.C 13708 2010-07-28 16:55:36Z itti $
00036 //
00037 
00038 #include "Devices/BeoChip.H"
00039 
00040 #include "Component/OptionManager.H"
00041 #include "Util/Assert.H"
00042 #include "rutz/compat_snprintf.h"
00043 
00044 #define NUMSERVO 8
00045 #define NUMPWM 2
00046 #define NUMADC 2
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 // BeoChip 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 // ######################################################################
00067 BeoChipListener::~BeoChipListener()
00068 { }
00069 
00070 // ######################################################################
00071 void *BeoChip_run(void *c)
00072 {
00073   BeoChip *d = (BeoChip *)c;
00074   d->run();
00075   return NULL;
00076 }
00077 
00078 // ######################################################################
00079 BeoChip::BeoChip(OptionManager& mgr, const std::string& descrName,
00080                  const std::string& tagName) :
00081   ModelComponent(mgr, descrName, tagName),
00082   itsDevName("BeoChipDeviceName", this, "/dev/ttyS0"),
00083   itsLCDrows("BeoChipLCDrows", this, 4),
00084   itsLCDcols("BeoChipLCDcols", this, 20),
00085   itsUseRTSCTS("BeoChipUseRTSCTS", this, true)
00086 {
00087   // Initialize our internals:
00088   zeroS = new rutz::shared_ptr<NModelParam<int> >[NUMSERVO];
00089   minS = new rutz::shared_ptr<NModelParam<int> >[NUMSERVO];
00090   maxS = new rutz::shared_ptr<NModelParam<int> >[NUMSERVO];
00091   servopos = new byte[NUMSERVO];
00092   for (uint i = 0; i < NUMSERVO; i ++)
00093     {
00094       servopos[i] = 127; char buf[20];
00095       sprintf(buf, "ZeroS%d", i);
00096       zeroS[i] = NModelParam<int>::make(buf, this, 127);
00097       sprintf(buf, "MinS%d", i);
00098       minS[i] = NModelParam<int>::make(buf, this, 0);
00099       sprintf(buf, "MaxS%d", i);
00100       maxS[i] = NModelParam<int>::make(buf, this, 255);
00101     }
00102 
00103   zeroP = new rutz::shared_ptr<NModelParam<int> >[NUMPWM];
00104   minP = new rutz::shared_ptr<NModelParam<int> >[NUMPWM];
00105   maxP = new rutz::shared_ptr<NModelParam<int> >[NUMPWM];
00106   pulseval = new short int[NUMPWM];
00107   for (uint i = 0; i < NUMPWM; i ++)
00108     {
00109       pulseval[i] = 1023; char buf[20];
00110       sprintf(buf, "ZeroP%d", i);
00111       zeroP[i] = NModelParam<int>::make(buf, this, 1023);
00112       sprintf(buf, "MinP%d", i);
00113       minP[i] = NModelParam<int>::make(buf, this, 0);
00114       sprintf(buf, "MaxP%d", i);
00115       maxP[i] = NModelParam<int>::make(buf, this, 2047);
00116     }
00117 
00118   zeroA = new rutz::shared_ptr<NModelParam<int> >[NUMADC];
00119   minA = new rutz::shared_ptr<NModelParam<int> >[NUMADC];
00120   maxA = new rutz::shared_ptr<NModelParam<int> >[NUMADC];
00121   adcval = new byte[NUMADC];
00122   for (uint i = 0; i < NUMADC; i ++)
00123     {
00124       adcval[i] = 127; char buf[20];
00125       sprintf(buf, "ZeroA%d", i);
00126       zeroA[i] = NModelParam<int>::make(buf, this, 127);
00127       sprintf(buf, "MinA%d", i);
00128       minA[i] = NModelParam<int>::make(buf, this, 0);
00129       sprintf(buf, "MaxA%d", i);
00130       maxA[i] = NModelParam<int>::make(buf, this, 255);
00131     }
00132 
00133   itsFd = -1;
00134   itsListener.reset(NULL);
00135   keyboard = 0;
00136   pthread_mutex_init(&lock, NULL);
00137   pthread_mutex_init(&serlock, NULL);
00138 }
00139 
00140 // ######################################################################
00141 void BeoChip::start1()
00142 {
00143   CLDEBUG("Opening port %s", itsDevName.getVal().c_str());
00144   itsFd = open(itsDevName.getVal().c_str(), O_RDWR | O_NOCTTY | O_SYNC);
00145   if (itsFd < 0)
00146     PLFATAL("Error opening serial port '%s'", itsDevName.getVal().c_str());
00147   CLDEBUG("Opened port %s", itsDevName.getVal().c_str());
00148 
00149   // save current port settings:
00150   if (tcgetattr(itsFd, &itsOldtio) == -1) PLFATAL("tcgetattr() failed");
00151 
00152   // set input mode (non-canonical, no echo, ...):
00153   struct termios newtio;
00154   bzero(&newtio, sizeof(newtio));
00155   newtio.c_cflag = CS8 | CREAD;
00156   if (itsUseRTSCTS.getVal())
00157     newtio.c_cflag |= CRTSCTS;
00158   else
00159     {
00160       newtio.c_cflag |= CLOCAL;
00161       CLDEBUG("WARNING: RTS/CTS flow and modem control lines not used");
00162     }
00163   newtio.c_iflag = IGNBRK | IGNPAR;
00164   newtio.c_oflag = 0;
00165   newtio.c_lflag = 0;
00166   newtio.c_cc[VTIME] = 0;   /* inter-character timer unused */
00167   newtio.c_cc[VMIN] = 1;   /* blocking read until 1 char received */
00168 
00169   // Clear everything out:
00170   if (tcflush(itsFd, TCIFLUSH) == -1) PLFATAL("tcflush() failed");
00171 
00172   // Set our new termio device settings:
00173   if (cfsetispeed(&newtio, B19200) == -1)
00174     PLFATAL("Cannot set serial in speed");
00175   if (cfsetospeed(&newtio, B19200) == -1)
00176     PLFATAL("Cannot set serial out speed");
00177   if (tcsetattr(itsFd, TCSANOW, &newtio) == -1)
00178     PLFATAL("tcsetattr() failed");
00179 
00180   // start our thread:
00181   keepgoing = true;
00182   pthread_create(&runner, NULL, &BeoChip_run, (void *)this);
00183 }
00184 
00185 // ######################################################################
00186 void BeoChip::stop2()
00187 {
00188   keepgoing = false;
00189   usleep(300000); // make sure thread has exited
00190 
00191   // restore old port settings:
00192   if (tcsetattr(itsFd, TCSANOW, &itsOldtio) == -1)
00193     PLERROR("tcsetaddr() failed");
00194   close(itsFd);
00195   itsFd = -1;
00196 }
00197 
00198 // ######################################################################
00199 BeoChip::~BeoChip()
00200 {
00201   delete [] zeroS;
00202   delete [] minS;
00203   delete [] maxS;
00204   delete [] servopos;
00205 
00206   delete [] zeroP;
00207   delete [] minP;
00208   delete [] maxP;
00209   delete [] pulseval;
00210 
00211   delete [] zeroA;
00212   delete [] minA;
00213   delete [] maxA;
00214   delete [] adcval;
00215 
00216   pthread_mutex_destroy(&lock);
00217   pthread_mutex_destroy(&serlock);
00218 }
00219 
00220 // ######################################################################
00221 void BeoChip::setListener(rutz::shared_ptr<BeoChipListener>& listener)
00222 { itsListener = listener; }
00223 
00224 // ######################################################################
00225 bool BeoChip::echoRequest()
00226 {
00227   // 11111000: Echo request (will send back an echo reply)
00228   return writeByte(BIN(11111000));
00229 }
00230 
00231 // ######################################################################
00232 bool BeoChip::debugMode(const bool on)
00233 {
00234   // 1111110x: Turn debug mode on/off (x)
00235   return writeByte(BIN(11111100) | (on?1:0));
00236 }
00237 
00238 // ######################################################################
00239 bool BeoChip::resetChip()
00240 {
00241   // 11111001: Reset the BeoChip
00242   return writeByte(BIN(11111001));
00243 }
00244 
00245 // ######################################################################
00246 bool BeoChip::lcdGotoXY(const int x, const int y)
00247 {
00248   if (itsLCDrows.getVal() != 4)
00249     LFATAL("FIXME: need some code to support various numbers of rows!");
00250 
00251   // figure out our starting offset:
00252   int offset = x;
00253   switch(y)
00254     {
00255     case 0: break;
00256     case 1: offset += 64; break;
00257     case 2: offset += itsLCDcols.getVal(); break;
00258     case 3: offset += 64 + itsLCDcols.getVal(); break;
00259     default:
00260       LERROR("Row number %d out of range 0..3 -- IGNORING", y);
00261       return false;
00262     }
00263 
00264   return lcdGoto(offset);
00265 }
00266 
00267 // ######################################################################
00268 bool BeoChip::lcdGoto(const int i)
00269 {
00270   if (i < 0 || i >= 128)
00271     { LERROR("Offset %d out of range 0..127 -- IGNORING", i); return false; }
00272 
00273   // set DDRAM address:
00274   return lcdSendRaw(BIN(10000000) | i, false);
00275 }
00276 
00277 // ######################################################################
00278 bool BeoChip::lcdPrintf(const char *fmt, ...)
00279 {
00280   // format and write out our message, truncating at our number of columns:
00281   char txt[itsLCDcols.getVal() + 1];
00282   va_list a; va_start(a, fmt);
00283   vsnprintf(txt, itsLCDcols.getVal()+1, fmt, a);
00284   va_end(a);
00285 
00286   // send it off to the LCD, char by char:
00287   bool ret = true;
00288   pthread_mutex_lock(&serlock);
00289   for (unsigned int i = 0; i < strlen(txt); i ++)
00290     ret &= lcdSendRaw(txt[i], true, false);
00291   pthread_mutex_unlock(&serlock);
00292 
00293   return ret;
00294 }
00295 
00296 // ######################################################################
00297 bool BeoChip::lcdPrintf(const int x, const int y, const char *fmt, ...)
00298 {
00299   // first do a goto:
00300   if (lcdGotoXY(x, y) == false) return false;
00301 
00302   // format and write out our message, truncating at our number of columns:
00303   char txt[itsLCDcols.getVal() + 1];
00304   va_list a; va_start(a, fmt);
00305   vsnprintf(txt, itsLCDcols.getVal()+1, fmt, a);
00306   va_end(a);
00307 
00308   return lcdPrintf("%s", txt);
00309 }
00310 
00311 // ######################################################################
00312 bool BeoChip::lcdClear()
00313 {
00314   return lcdSendRaw(BIN(00000001), false);
00315 }
00316 
00317 // ######################################################################
00318 bool BeoChip::lcdScrollLeft(const int i)
00319 {
00320   bool ret = true;
00321 
00322   pthread_mutex_lock(&serlock);
00323   for (int j = 0; j < i; j ++)
00324     ret &= lcdSendRaw(BIN(00011000), false, false);
00325   pthread_mutex_unlock(&serlock);
00326 
00327   return ret;
00328 }
00329 
00330 // ######################################################################
00331 bool BeoChip::lcdScrollRight(const int i)
00332 {
00333   bool ret = true;
00334 
00335   pthread_mutex_lock(&serlock);
00336   for (int j = 0; j < i; j ++)
00337     ret &= lcdSendRaw(BIN(00011100), false, false);
00338   pthread_mutex_unlock(&serlock);
00339 
00340   return ret;
00341 }
00342 
00343 // ######################################################################
00344 bool BeoChip::lcdMoveCursorLeft(const int i)
00345 {
00346   bool ret = true;
00347 
00348   pthread_mutex_lock(&serlock);
00349   for (int j = 0; j < i; j ++)
00350     ret &= lcdSendRaw(BIN(00010000), false, false);
00351   pthread_mutex_unlock(&serlock);
00352 
00353   return ret;
00354 }
00355 
00356 // ######################################################################
00357 bool BeoChip::lcdMoveCursorRight(const int i)
00358 {
00359   bool ret = true;
00360 
00361   pthread_mutex_lock(&serlock);
00362   for (int j = 0; j < i; j ++)
00363     ret &= lcdSendRaw(BIN(00010100), false, false);
00364   pthread_mutex_unlock(&serlock);
00365 
00366   return ret;
00367 }
00368 
00369 // ######################################################################
00370 bool BeoChip::lcdCursorBlock()
00371 { return lcdSendRaw(BIN(00001101), false); }
00372 
00373 // ######################################################################
00374 bool BeoChip::lcdCursorUnderline()
00375 { return lcdSendRaw(BIN(00001110), false); }
00376 
00377 // ######################################################################
00378 bool BeoChip::lcdCursorInvisible()
00379 { return lcdSendRaw(BIN(00001100), false); }
00380 
00381 // ######################################################################
00382 bool BeoChip::lcdLoadFont(const int font)
00383 {
00384   if (font < 0 || font > 7)
00385     {
00386       LERROR("font value %d out of range [0..7] - IGNORED", font);
00387       return false;
00388     }
00389 
00390   // 11100ccc: Load LCD graphics charset ccc
00391   return writeByte(BIN(11100000) | byte(font));
00392 }
00393 
00394 // ######################################################################
00395 bool BeoChip::lcdLoadFont(const byte data[64])
00396 {
00397   pthread_mutex_lock(&serlock);
00398 
00399   // get to start of CGRAM:
00400   if (lcdSendRaw(BIN(01000000), false, false) == false) return false;
00401 
00402   // load up the values:
00403   bool ret = true;
00404   for (int i = 0; i < 64; i ++) ret &= lcdSendRaw(data[i], true, false);
00405 
00406   pthread_mutex_unlock(&serlock);
00407 
00408   return ret;
00409 }
00410 
00411 // ######################################################################
00412 bool BeoChip::lcdSetAnimation(const int anim)
00413 {
00414   if (anim < 0 || anim > 7)
00415     {
00416       LERROR("anim value %d out of range [0..7] - IGNORED", anim);
00417       return false;
00418     }
00419 
00420   // 11101ttt: Set LCD animation type to ttt
00421   return writeByte((BIN(11101000)) | (byte(anim)));
00422 }
00423 
00424 // ######################################################################
00425 bool BeoChip::lcdSendRaw(const byte val, const bool RS, const bool uselock)
00426 {
00427   // we use the most efficient of either:
00428   //
00429   // 00xxxxxx: Send (6-bit) char xxxxxx to LCD, 32 will be added to value
00430   //
00431   // or:
00432   //
00433   // 101rxxxx: Memorize R/S r and 4 LSB xxxx for later send to LCD
00434   // 1100xxxx: Combine 4 MSB xxxx to memorized and send to the LCD
00435 
00436   if (RS == true && val >= 32 && val < 96)
00437     return writeByte(byte(val - 32), uselock); //32 will be re-added by BeoChip
00438   else
00439     {
00440       if (uselock) pthread_mutex_lock(&serlock);
00441       bool ret = writeByte((BIN(10100000)) |
00442                            (RS == true ? (BIN(00010000)):0) |
00443                            (byte(val) & (BIN(00001111))), false);
00444       ret &= writeByte((BIN(11000000)) | byte(val >> 4), false);
00445       if (uselock) pthread_mutex_unlock(&serlock);
00446       return ret;
00447     }
00448 }
00449 
00450 // ######################################################################
00451 bool BeoChip::shimServos(const byte shim)
00452 {
00453   if (shim > 7)
00454     {
00455       LERROR("shim value %d out of range [0..7] - IGNORED", shim);
00456       return false;
00457     }
00458 
00459   // 11011ddd: Set servos' delay loop shim to ddd
00460   return writeByte(BIN(11011000) | shim);
00461 }
00462 
00463 // ######################################################################
00464 void BeoChip::calibrateServo(const int servo, const byte neutralval,
00465                              const byte minval, const byte maxval)
00466 {
00467   ASSERT(servo >= 0 && servo < NUMSERVO);
00468   zeroS[servo]->setVal(neutralval);
00469   minS[servo]->setVal(minval);
00470   maxS[servo]->setVal(maxval);
00471 }
00472 
00473 // ######################################################################
00474 bool BeoChip::setServo(const int servo, const float position)
00475 {
00476   ASSERT(servo >= 0 && servo < NUMSERVO);
00477   byte raw = calibToRaw(position, zeroS[servo]->getVal(),
00478                         minS[servo]->getVal(), maxS[servo]->getVal());
00479   return setServoRaw(servo, raw);
00480 }
00481 
00482 // ######################################################################
00483 float BeoChip::getServo(const int servo) const
00484 {
00485   ASSERT(servo >= 0 && servo < NUMSERVO);
00486 
00487   byte raw = getServoRaw(servo);
00488   return rawToCalib(raw, zeroS[servo]->getVal(),
00489                     minS[servo]->getVal(), maxS[servo]->getVal());
00490 }
00491 
00492 // ######################################################################
00493 bool BeoChip::setServoRaw(const int servo, const byte val)
00494 {
00495   ASSERT(servo >= 0 && servo < NUMSERVO);
00496 
00497   // attempt to set it:
00498   // 01xxxxxx: Memorize 6 LSB xxxxxx to later send to a servo
00499   // 100sssxx: Combine 2 MSB xx to memorized and send to servo sss
00500   pthread_mutex_lock(&serlock);
00501   bool ret = writeByte(BIN(01000000) | (val & BIN(00111111)), false);
00502   if (ret) ret = writeByte(BIN(10000000) | (servo << 2) | (val >> 6), false);
00503   pthread_mutex_unlock(&serlock);
00504 
00505   if (ret == false) { LERROR("Set servo failed - keeping old"); return false; }
00506   servopos[servo] = val;
00507 
00508   return true;
00509 }
00510 
00511 // ######################################################################
00512 byte BeoChip::getServoRaw(const int servo) const
00513 {
00514   ASSERT(servo >= 0 && servo < NUMSERVO);
00515   return servopos[servo];
00516 }
00517 
00518 // ######################################################################
00519 bool BeoChip::capturePulse(const int whichone, const bool on)
00520 {
00521   ASSERT(whichone >= 0 && whichone <= 1);
00522 
00523   // 110100px: Turn PWM capture p on/off (x)
00524   return writeByte(BIN(11010000) | (whichone?2:0) | (on?1:0));
00525 }
00526 
00527 // ######################################################################
00528 void BeoChip::calibratePulse(const int whichone, const int neutralval,
00529                              const int minval, const int maxval)
00530 {
00531   ASSERT(whichone >= 0 && whichone <= 1);
00532   zeroP[whichone]->setVal(neutralval);
00533   minP[whichone]->setVal(minval);
00534   maxP[whichone]->setVal(maxval);
00535 }
00536 
00537 // ######################################################################
00538 float BeoChip::getPulse(const int whichone)
00539 {
00540   ASSERT(whichone >= 0 && whichone <= 1);
00541   short int raw = getPulseRaw(whichone);
00542   return rawToCalib(raw, zeroP[whichone]->getVal(),
00543                     minP[whichone]->getVal(), maxP[whichone]->getVal());
00544 }
00545 
00546 // ######################################################################
00547 short int BeoChip::getPulseRaw(const int whichone)
00548 {
00549   ASSERT(whichone >= 0 && whichone <= 1);
00550   pthread_mutex_lock(&lock);
00551   short int val = pulseval[whichone];
00552   pthread_mutex_unlock(&lock);
00553   return val;
00554 }
00555 
00556 // ######################################################################
00557 bool BeoChip::captureAnalog(const int whichone, const bool on)
00558 {
00559   ASSERT(whichone >= 0 && whichone <= 1);
00560 
00561   // 110101ax: Turn A/D capture a on/off (x)
00562   return writeByte(BIN(11010100) | (whichone?2:0) | (on?1:0));
00563 }
00564 
00565 // ######################################################################
00566 void BeoChip::calibrateAnalog(const int whichone, const int neutralval,
00567                               const int minval, const int maxval)
00568 {
00569   ASSERT(whichone >= 0 && whichone <= 1);
00570   zeroA[whichone]->setVal(neutralval);
00571   minA[whichone]->setVal(minval);
00572   maxA[whichone]->setVal(maxval);
00573 }
00574 
00575 // ######################################################################
00576 float BeoChip::getAnalog(const int whichone)
00577 {
00578   ASSERT(whichone >= 0 && whichone <= 1);
00579   byte raw = getAnalogRaw(whichone);
00580   return rawToCalib(raw, zeroS[whichone]->getVal(),
00581                     minS[whichone]->getVal(), maxS[whichone]->getVal());
00582 }
00583 
00584 // ######################################################################
00585 byte BeoChip::getAnalogRaw(const int whichone)
00586 {
00587   ASSERT(whichone >= 0 && whichone <= 1);
00588   pthread_mutex_lock(&lock);
00589   byte val = adcval[whichone];
00590   pthread_mutex_unlock(&lock);
00591   return val;
00592 }
00593 
00594 // ######################################################################
00595 bool BeoChip::captureKeyboard(const bool on)
00596 {
00597   // 1111101x: Turn Keyboard capture on/off (x)
00598   return writeByte(BIN(11111010) | (on?1:0));
00599 }
00600 
00601 // ######################################################################
00602 bool BeoChip::debounceKeyboard(const bool on)
00603 {
00604   // 1111111x: Turn keyboard debounce on/off (x)
00605   return writeByte(BIN(11111110) | (on?1:0));
00606 }
00607 
00608 // ######################################################################
00609 int BeoChip::getKeyboard()
00610 {
00611   pthread_mutex_lock(&lock);
00612   int val = keyboard;
00613   pthread_mutex_unlock(&lock);
00614   return val;
00615 }
00616 
00617 // ######################################################################
00618 bool BeoChip::setDigitalOut(const int outnum, const bool on)
00619 {
00620   ASSERT(outnum >= 0 && outnum < 4);
00621   // 11110oox: Set digital output oo to value x
00622   return writeByte(BIN(11110000) | (outnum << 1) | (on?1:0));
00623 }
00624 
00625 // ######################################################################
00626 bool BeoChip::writeByte(const byte val, const bool uselock)
00627 {
00628   if (MYLOGVERB >= LOG_DEBUG)
00629     {
00630       char txt[9];   txt[8] = '\0';
00631       for (int i = 0; i < 8; i ++) txt[i] = (val >> (7-i)) & 1 ? '1':'0';
00632       LDEBUG("Sending: %s", txt);
00633     }
00634 
00635   if (uselock) pthread_mutex_lock(&serlock);
00636   bool ret = (write(itsFd, &val, 1) == 1);
00637   if (uselock) pthread_mutex_unlock(&serlock);
00638 
00639   if (ret == false) PLERROR("Write to BeoChip failed");
00640   return ret;
00641 }
00642 
00643 // ######################################################################
00644 void BeoChip::run()
00645 {
00646   int pwm[2], adc[2], pwmidx = 0, adcidx = 0;
00647   while(keepgoing)
00648     {
00649       byte c;
00650       if (read(itsFd, &c, 1) != 1)  // blocking read
00651         PLERROR("Error reading from BeoChip -- IGNORED");
00652       else
00653         {
00654           if (MYLOGVERB >= LOG_DEBUG)
00655             {
00656               char txt[9]; txt[8] = '\0';
00657               for (int i = 0; i < 8; i ++) txt[i] = (c >> (7-i)) & 1 ? '1':'0';
00658               LDEBUG("Received: %s", txt);
00659             }
00660 
00661           // 00pxxxxx: PWM value p ready, 5 LSB attached in xxxxx
00662           // 01xxxxxx: 6 MSB attached in xxxxxx for last-sent PWM value LSB
00663           // 100kkkkk: Keyboard changed, current status in kkkkk
00664           // 101axxxx: A/D value a ready, 4 LSB attached in xxxx
00665           // 1100xxxx: 4 MSB for last-sent A/D value LSB
00666           // 11010000: Reset occurred, data may have been lost
00667           // 11010001: Echo reply (in reply to an echo request)
00668           // 11010010: Input command serial buffer overflow, data was lost
00669           // 11010011: Framing/overrun error on serial input, data was lost
00670           // 11010100: Return value buffer overflow, data was lost (panic mode)
00671 
00672           switch(c >> 6)
00673             {
00674             case BIN(00):
00675               pwmidx = ((c & BIN(00100000)) >> 5);
00676               pwm[pwmidx] = (c & BIN(00011111));
00677               break;
00678             case BIN(01):
00679               pwm[pwmidx] |= ((c & BIN(00111111)) << 5);
00680               pthread_mutex_lock(&lock);
00681               pulseval[pwmidx] = pwm[pwmidx];
00682               pthread_mutex_unlock(&lock);
00683               if (itsListener.get())
00684                 itsListener->event((pwmidx == 0 ? PWM0:PWM1),
00685                                    pwm[pwmidx],
00686                                    rawToCalib(pwm[pwmidx],
00687                                               zeroP[pwmidx]->getVal(),
00688                                               minP[pwmidx]->getVal(),
00689                                               maxP[pwmidx]->getVal()));
00690               break;
00691             case BIN(10):
00692               if ((c & BIN(11100000)) == BIN(10000000))
00693                 {
00694                   int kbd = (c & BIN(00011111));
00695                   pthread_mutex_lock(&lock);
00696                   keyboard = kbd;
00697                   pthread_mutex_unlock(&lock);
00698                   if (itsListener.get())
00699                     itsListener->event(KBD, kbd, 0.0F);
00700                 }
00701               else
00702                 {
00703                   adcidx = ((c & BIN(00010000)) >> 4);
00704                   adc[adcidx] = (c & BIN(00001111));
00705                 }
00706               break;
00707             case BIN(11):
00708               if ( (c & BIN(11110000)) == BIN(11000000) )
00709                 {
00710                   adc[adcidx] |= ((c & BIN(00001111)) << 4);
00711                   pthread_mutex_lock(&lock);
00712                   adcval[adcidx] = adc[adcidx];
00713                   pthread_mutex_unlock(&lock);
00714                   if (itsListener.get())
00715                     itsListener->event((adcidx == 0 ? ADC0:ADC1),
00716                                        adc[adcidx],
00717                                        rawToCalib(adc[adcidx],
00718                                                   zeroA[adcidx]->getVal(),
00719                                                   minA[adcidx]->getVal(),
00720                                                   maxA[adcidx]->getVal()));
00721                 }
00722               else
00723                 switch(c)
00724                   {
00725                   case BIN(11010000):
00726                     if (itsListener.get())
00727                       itsListener->event(RESET, 0, 0.0F);
00728                     break;
00729                   case BIN(11010001):
00730                     if (itsListener.get())
00731                       itsListener->event(ECHOREP, 0, 0.0F);
00732                     break;
00733                   case BIN(11010010):
00734                     if (itsListener.get())
00735                       itsListener->event(INOVERFLOW, 0, 0.0F);
00736                     break;
00737                   case BIN(11010011):
00738                     if (itsListener.get())
00739                       itsListener->event(SERIALERROR, 0, 0.0F);
00740                     break;
00741                   case BIN(11010100):
00742                     if (itsListener.get())
00743                       itsListener->event(OUTOVERFLOW, 0, 0.0F);
00744                     break;
00745                   default:
00746                     LERROR("Unknown message 0x%x from BeoChip -- IGNORED", c);
00747                   }
00748             }
00749         }
00750     }
00751   pthread_exit(0);
00752 }
00753 
00754 // ######################################################################
00755 float BeoChip::rawToCalib(const int raw, const int zero, const int mini,
00756                           const int maxi) const
00757 {
00758   if (raw < mini || raw > maxi)
00759     LERROR("Raw value %d out of range [%d..%d]", raw, mini, maxi);
00760 
00761   if (raw < zero)
00762     return float(zero - raw) / float(mini - zero);
00763   else
00764     return float(raw - zero) / float(maxi - zero);
00765 }
00766 
00767 // ######################################################################
00768 int BeoChip::calibToRaw(const float calibrated, const int zero, const int mini,
00769                         const int maxi, const int bits) const
00770 {
00771   if (calibrated < -1.0F || calibrated > 1.0F)
00772     LERROR("Calibrated value %f out of range [-1..1]", calibrated);
00773 
00774   if (calibrated < 0.0F)
00775     return zero + int(calibrated * float(zero - mini) + 0.4999F);
00776   else
00777     return zero + int(calibrated * float(maxi - zero) + 0.4999F);
00778 }
00779 
00780 // ######################################################################
00781 /* So things look consistent in everyone's emacs... */
00782 /* Local Variables: */
00783 /* indent-tabs-mode: nil */
00784 /* End: */
Generated on Sun May 8 08:04:44 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3