LoSerial.C

Go to the documentation of this file.
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: */
Generated on Sun May 8 08:05:54 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3