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: */