00001 /** 00002 \file Robots/LoBot/io/LoSerial.C 00003 \brief This file defines the non-inline member functions of the 00004 lobot::Serial class. 00005 */ 00006 00007 // //////////////////////////////////////////////////////////////////// // 00008 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00009 // University of Southern California (USC) and the iLab at USC. // 00010 // See http://iLab.usc.edu for information about this project. // 00011 // //////////////////////////////////////////////////////////////////// // 00012 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00013 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00014 // in Visual Environments, and Applications'' by Christof Koch and // 00015 // Laurent Itti, California Institute of Technology, 2001 (patent // 00016 // pending; application number 09/912,225 filed July 23, 2001; see // 00017 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00018 // //////////////////////////////////////////////////////////////////// // 00019 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00020 // // 00021 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00022 // redistribute it and/or modify it under the terms of the GNU General // 00023 // Public License as published by the Free Software Foundation; either // 00024 // version 2 of the License, or (at your option) any later version. // 00025 // // 00026 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00027 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00028 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00029 // PURPOSE. See the GNU General Public License for more details. // 00030 // // 00031 // You should have received a copy of the GNU General Public License // 00032 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00033 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00034 // Boston, MA 02111-1307 USA. // 00035 // //////////////////////////////////////////////////////////////////// // 00036 // 00037 // Primary maintainer for this file: mviswana usc edu 00038 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/io/LoSerial.C $ 00039 // $Id: LoSerial.C 12858 2010-02-17 20:35:10Z mviswana $ 00040 // 00041 00042 //------------------------------ HEADERS -------------------------------- 00043 00044 // lobot headers 00045 #include "Robots/LoBot/io/LoSerial.H" 00046 #include "Robots/LoBot/misc/LoExcept.H" 00047 00048 // Standard C headers 00049 #include <errno.h> 00050 00051 //------------------------------ MACROS --------------------------------- 00052 00053 // Sometimes, during development, it may not be convenient to have 00054 // something actually connected to the serial port. We may simply want to 00055 // fake the Propeller being attached. For these situations, we can 00056 // uncomment the following line. 00057 //#define LOBOT_SERIAL_DEVMODE 1 00058 00059 //----------------------------- NAMESPACE ------------------------------- 00060 00061 namespace lobot { 00062 00063 //------------------------- LIBSERIAL VERSION --------------------------- 00064 00065 #ifdef HAVE_LIBSERIAL 00066 00067 // Quick helper to convert integral baud rates to the correct enum 00068 // expected by libserial 00069 static SerialPort::BaudRate baud_rate_enum(int baud_rate) 00070 { 00071 if (baud_rate < 63) // halfway between 50 and 75 00072 return SerialPort::BAUD_50 ; 00073 if (baud_rate < 93) // halfway between 75 and 110 00074 return SerialPort::BAUD_75 ; 00075 if (baud_rate < 122) // halfway between 110 and 134 00076 return SerialPort::BAUD_110 ; 00077 if (baud_rate < 142) // halfway between 134 and 150 00078 return SerialPort::BAUD_134 ; 00079 if (baud_rate < 175) // halfway between 150 and 200 00080 return SerialPort::BAUD_150 ; 00081 if (baud_rate < 250) // halfway between 200 and 300 00082 return SerialPort::BAUD_200 ; 00083 if (baud_rate < 450) // halfway between 300 and 600 00084 return SerialPort::BAUD_300 ; 00085 if (baud_rate < 900) // halfway between 600 and 1200 00086 return SerialPort::BAUD_600 ; 00087 if (baud_rate < 1500) // halfway between 1200 and 1800 00088 return SerialPort::BAUD_1200 ; 00089 if (baud_rate < 2100) // halfway between 1800 and 2400 00090 return SerialPort::BAUD_1800 ; 00091 if (baud_rate < 3600) // halfway between 2400 and 4800 00092 return SerialPort::BAUD_2400 ; 00093 if (baud_rate < 7200) // halfway between 4800 and 9600 00094 return SerialPort::BAUD_4800 ; 00095 if (baud_rate < 14400) // halfway between 9600 and 19200 00096 return SerialPort::BAUD_9600 ; 00097 if (baud_rate < 28800) // halfway between 19200 and 38400 00098 return SerialPort::BAUD_19200 ; 00099 if (baud_rate < 48000) // halfway between 38400 and 57600 00100 return SerialPort::BAUD_38400 ; 00101 if (baud_rate < 86400) // halfway between 57600 and 115200 00102 return SerialPort::BAUD_57600 ; 00103 if (baud_rate < 172800) // halfway between 115200 and 230400 00104 return SerialPort::BAUD_115200 ; 00105 return SerialPort::BAUD_230400 ; 00106 } 00107 00108 // Constructor 00109 Serial::Serial(const ModelManager&, const std::string& device, int baud_rate) 00110 : m_serial(device) 00111 { 00112 #ifdef LOBOT_SERIAL_DEVMODE 00113 ; // don't init serial port when working with development mode dummy 00114 #else 00115 try 00116 { 00117 m_serial.Open(baud_rate_enum(baud_rate)) ; 00118 } 00119 catch (std::exception&) 00120 { 00121 throw io_error(SERIAL_PORT_INIT_ERROR) ; 00122 } 00123 #endif 00124 } 00125 00126 // See if the serial port has input data pending 00127 bool Serial::ready() 00128 { 00129 return m_serial.IsDataAvailable() ; 00130 } 00131 00132 // Receive data from serial port 00133 int Serial::read(char buf[], int n) 00134 { 00135 int i = 0 ; 00136 try 00137 { 00138 for (; i < n; ++i) 00139 buf[i] = m_serial.ReadByte() ; 00140 } 00141 catch (std::exception&) 00142 { 00143 } 00144 return i ; 00145 } 00146 00147 // Send data via serial port 00148 void Serial::write(char buf[], int n) 00149 { 00150 try 00151 { 00152 for (int i = 0; i < n; ++i) 00153 m_serial.WriteByte(buf[i]) ; 00154 } 00155 catch (std::exception&) 00156 { 00157 throw io_error(SERIAL_PORT_WRITE_ERROR) ; 00158 } 00159 } 00160 00161 #else // don't HAVE_LIBSERIAL ==> fall back to INVT serial port support 00162 00163 //--------------------------- INVT VERSION ------------------------------ 00164 00165 // Constructor 00166 // 00167 // DEVNOTE: INVT's Serial class expects a non-const ModelManager 00168 // reference in its constructor. However, since the lobot::factory 00169 // mechanism only works with const references to constructor parameters, 00170 // the lobot::MotorBase constructor will pass a const ModelManager& to 00171 // this function here. To ensure that INVT's Serial class construction 00172 // works properly, we have to cast away the constness of the ModelManager 00173 // passed in. 00174 Serial:: 00175 Serial(const ModelManager& mgr, const std::string& device, int baud_rate) 00176 : m_serial(new ::Serial(const_cast<ModelManager&>(mgr), 00177 "LobotSerialPort", "LobotSerialPort")), 00178 m_peek_flag(false), m_peek_char(0) 00179 { 00180 #ifdef LOBOT_SERIAL_DEVMODE 00181 ; // don't init serial port when working with development mode dummy 00182 #else 00183 ModelManager& M = const_cast<ModelManager&>(mgr) ; 00184 00185 bool i_stopped_the_model_manager = false ; 00186 if (M.started()) { 00187 M.stop() ; 00188 i_stopped_the_model_manager = true ; 00189 } 00190 00191 M.addSubComponent(m_serial) ; 00192 m_serial->configure(device.c_str(), baud_rate, "8N1", false, false, 0) ; 00193 00194 M.exportOptions(MC_RECURSE) ; 00195 if (i_stopped_the_model_manager) 00196 M.start() ; 00197 #endif 00198 } 00199 00200 // Check if the serial port has pending data that can be read 00201 bool Serial::ready() 00202 { 00203 if (m_peek_flag) 00204 return true ; 00205 00206 m_serial->setBlocking(false) ; 00207 00208 bool is_ready = false ; 00209 switch (m_serial->read(& m_peek_char, 1)) 00210 { 00211 case -1: 00212 if (errno == EAGAIN) 00213 is_ready = false ; 00214 else 00215 throw io_error(SERIAL_PORT_READ_ERROR) ; 00216 break ; 00217 00218 case 0: // EOF 00219 //is_ready = true ; 00220 is_ready = false ; 00221 break ; 00222 00223 case 1: 00224 if (m_peek_char != '\0') { // often get bogus null chars; ignore 'em 00225 is_ready = true ; 00226 m_peek_flag = true ; 00227 } 00228 break ; 00229 00230 default: // hunh!?! this should never happen; but if it does, then 00231 errno = 0 ; 00232 throw io_error(SERIAL_PORT_READ_ERROR) ; 00233 break ; 00234 } 00235 00236 m_serial->setBlocking(true) ; 00237 return is_ready ; 00238 } 00239 00240 // Receive data from serial port 00241 int Serial::read(char buf[], int n) 00242 { 00243 if (n <= 0) 00244 throw io_error(SERIAL_PORT_BAD_ARG) ; 00245 00246 if (m_peek_flag) { 00247 buf[0] = m_peek_char ; 00248 m_peek_flag = false ; 00249 m_peek_char = 0 ; 00250 return 1 + m_serial->read(buf + 1, n - 1) ; 00251 } 00252 return m_serial->read(buf, n) ; 00253 } 00254 00255 // Send data via serial port 00256 void Serial::write(char buf[], int n) 00257 { 00258 if (n <= 0) 00259 throw io_error(SERIAL_PORT_BAD_ARG) ; 00260 m_serial->write(buf, n) ; 00261 } 00262 00263 #endif // HAVE_LIBSERIAL 00264 00265 //------------- FUNCTIONS COMMON IN BOTH IMPLEMENTATIONS ---------------- 00266 00267 // Read the specified number of bytes and don't return until they've all 00268 // been received. 00269 void Serial::read_full(char buf[], int n) 00270 { 00271 for (int m = n; m > 0;) 00272 m -= read(buf + n - m, m) ; 00273 } 00274 00275 // Read and discard specified number of bytes 00276 void Serial::eat(int n) 00277 { 00278 char buf[n] ; 00279 read_full(buf, n) ; 00280 } 00281 00282 // Clean-up 00283 Serial::~Serial(){} 00284 00285 //----------------------------------------------------------------------- 00286 00287 } // end of namespace encapsulating this file's definitions 00288 00289 /* So things look consistent in everyone's emacs... */ 00290 /* Local Variables: */ 00291 /* indent-tabs-mode: nil */ 00292 /* End: */