00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 
00067 
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 #include <pressure_cells/AsyncSerial.h>
00084 
00085 #include <string>
00086 #include <algorithm>
00087 #include <iostream>
00088 #include <boost/bind.hpp>
00089 
00090 using namespace std;
00091 
00092 using namespace boost;
00093 
00094 
00095 
00096 
00097 
00098 #ifndef __APPLE__
00099 
00100 class AsyncSerialImpl:private
00101    boost::noncopyable {
00102  public:
00103    AsyncSerialImpl (  ):
00104    io (  ),
00105    port ( io ),
00106    backgroundThread (  ),
00107    open ( false ),
00108    error ( false ) {
00109    }
00110    boost::asio::io_service
00111       io;                       
00112 
00113    boost::asio::serial_port port;   
00114    boost::thread backgroundThread;  
00115    bool open;                   
00116 
00117    bool error;                  
00118 
00119    mutable boost::mutex errorMutex; 
00120 
00122    std::vector < char >
00123       writeQueue;
00124 
00125    boost::shared_array < char >
00126       writeBuffer;              
00127 
00128    size_t writeBufferSize;      
00129 
00130    boost::mutex writeQueueMutex;    
00131    char
00132      readBuffer[AsyncSerial::readBufferSize];   
00133 
00135    boost::function < void ( const char *, size_t ) >
00136       callback;
00137 };
00138 
00139 AsyncSerial::AsyncSerial (  ):pimpl ( new AsyncSerialImpl )
00140 {
00141 
00142 }
00143 
00144 AsyncSerial::AsyncSerial ( const std::string & devname, unsigned int baud_rate,
00145                            asio::serial_port_base::parity opt_parity,
00146                            asio::serial_port_base::character_size opt_csize,
00147                            asio::serial_port_base::flow_control opt_flow,
00148                            asio::serial_port_base::stop_bits opt_stop ):
00149 pimpl ( new AsyncSerialImpl )
00150 {
00151    open ( devname, baud_rate, opt_parity, opt_csize, opt_flow, opt_stop );
00152 }
00153 
00154 void
00155 
00156 
00157 
00158 
00159 
00160 
00161 
00162 
00163  
00164    AsyncSerial::open ( const std::string & devname, unsigned int baud_rate,
00165                        asio::serial_port_base::parity opt_parity,
00166                        asio::serial_port_base::character_size opt_csize,
00167                        asio::serial_port_base::flow_control opt_flow,
00168                        asio::serial_port_base::stop_bits opt_stop )
00169 {
00170    if ( isOpen (  ) )
00171       close (  );
00172 
00173    setErrorStatus ( true );     
00174    pimpl->port.open ( devname );
00175    pimpl->port.set_option ( asio::serial_port_base::baud_rate ( baud_rate ) );
00176    pimpl->port.set_option ( opt_parity );
00177    pimpl->port.set_option ( opt_csize );
00178    pimpl->port.set_option ( opt_flow );
00179    pimpl->port.set_option ( opt_stop );
00180 
00181    
00182    pimpl->io.post ( boost::bind ( &AsyncSerial::doRead, this ) );
00183 
00184    thread t ( boost::bind ( &asio::io_service::run, &pimpl->io ) );
00185 
00186    pimpl->backgroundThread.swap ( t );
00187    setErrorStatus ( false );    
00188    pimpl->open = true;          
00189 }
00190 
00191 bool AsyncSerial::isOpen (  ) const
00192 {
00193    return pimpl->open;
00194 }
00195 
00196 bool AsyncSerial::errorStatus (  ) const
00197 {
00198    lock_guard < mutex > l ( pimpl->errorMutex );
00199    return pimpl->error;
00200 }
00201 
00202 void
00203   AsyncSerial::close (  )
00204 {
00205    if ( !isOpen (  ) )
00206       return;
00207 
00208    pimpl->open = false;
00209    pimpl->io.post ( boost::bind ( &AsyncSerial::doClose, this ) );
00210    pimpl->backgroundThread.join (  );
00211    pimpl->io.reset (  );
00212    if ( errorStatus (  ) )
00213      {
00214         throw ( boost::system::system_error ( boost::system::error_code (  ),
00215                                               "Error while closing the device" ) );
00216      }
00217 }
00218 
00219 void
00220   AsyncSerial::write ( const char *data, size_t size )
00221 {
00222    {
00223       lock_guard < mutex > l ( pimpl->writeQueueMutex );
00224       pimpl->writeQueue.insert ( pimpl->writeQueue.end (  ), data, data + size );
00225    }
00226    pimpl->io.post ( boost::bind ( &AsyncSerial::doWrite, this ) );
00227 }
00228 
00229 void
00230   AsyncSerial::write ( const std::vector < char >&data )
00231 {
00232    {
00233       lock_guard < mutex > l ( pimpl->writeQueueMutex );
00234       pimpl->writeQueue.insert ( pimpl->writeQueue.end (  ), data.begin (  ),
00235                                  data.end (  ) );
00236    }
00237    pimpl->io.post ( boost::bind ( &AsyncSerial::doWrite, this ) );
00238 }
00239 
00240 void
00241   AsyncSerial::writeString ( const std::string & s )
00242 {
00243    {
00244       lock_guard < mutex > l ( pimpl->writeQueueMutex );
00245       pimpl->writeQueue.insert ( pimpl->writeQueue.end (  ), s.begin (  ), s.end (  ) );
00246    }
00247    pimpl->io.post ( boost::bind ( &AsyncSerial::doWrite, this ) );
00248 }
00249 
00250 AsyncSerial::~AsyncSerial (  )
00251 {
00252    if ( isOpen (  ) )
00253      {
00254         try
00255         {
00256            close (  );
00257         }
00258         catch ( ... )
00259         {
00260            
00261         }
00262      }
00263 }
00264 
00265 void
00266   AsyncSerial::doRead (  )
00267 {
00268    pimpl->port.async_read_some ( asio::buffer ( pimpl->readBuffer, readBufferSize ),
00269                                  boost::bind ( &AsyncSerial::readEnd,
00270                                                this,
00271                                                asio::placeholders::error,
00272                                                asio::placeholders::bytes_transferred ) );
00273 }
00274 
00275 void
00276   AsyncSerial::readEnd ( const boost::system::error_code & error,
00277                           size_t bytes_transferred )
00278 {
00279    if ( error )
00280      {
00281 #ifdef __APPLE__
00282         if ( error.value (  ) == 45 )
00283           {
00284              
00285              
00286              doRead (  );
00287              return;
00288           }
00289 #endif //__APPLE__
00290         
00291         
00292         if ( isOpen (  ) )
00293           {
00294              doClose (  );
00295              setErrorStatus ( true );
00296           }
00297    } else
00298      {
00299         if ( pimpl->callback )
00300            pimpl->callback ( pimpl->readBuffer, bytes_transferred );
00301         doRead (  );
00302      }
00303 }
00304 
00305 void
00306   AsyncSerial::doWrite (  )
00307 {
00308    
00309    if ( pimpl->writeBuffer == 0 )
00310      {
00311         lock_guard < mutex > l ( pimpl->writeQueueMutex );
00312         pimpl->writeBufferSize = pimpl->writeQueue.size (  );
00313         pimpl->writeBuffer.reset ( new char[pimpl->writeQueue.size (  )] );
00314 
00315         copy ( pimpl->writeQueue.begin (  ), pimpl->writeQueue.end (  ),
00316                pimpl->writeBuffer.get (  ) );
00317         pimpl->writeQueue.clear (  );
00318         async_write ( pimpl->port, asio::buffer ( pimpl->writeBuffer.get (  ),
00319                                                   pimpl->writeBufferSize ),
00320                       boost::bind ( &AsyncSerial::writeEnd, this,
00321                                     asio::placeholders::error ) );
00322      }
00323 }
00324 
00325 void
00326   AsyncSerial::writeEnd ( const boost::system::error_code & error )
00327 {
00328    if ( !error )
00329      {
00330         lock_guard < mutex > l ( pimpl->writeQueueMutex );
00331         if ( pimpl->writeQueue.empty (  ) )
00332           {
00333              pimpl->writeBuffer.reset (  );
00334              pimpl->writeBufferSize = 0;
00335 
00336              return;
00337           }
00338         pimpl->writeBufferSize = pimpl->writeQueue.size (  );
00339         pimpl->writeBuffer.reset ( new char[pimpl->writeQueue.size (  )] );
00340         copy ( pimpl->writeQueue.begin (  ), pimpl->writeQueue.end (  ),
00341                pimpl->writeBuffer.get (  ) );
00342         pimpl->writeQueue.clear (  );
00343         async_write ( pimpl->port, asio::buffer ( pimpl->writeBuffer.get (  ),
00344                                                   pimpl->writeBufferSize ),
00345                       boost::bind ( &AsyncSerial::writeEnd, this,
00346                                     asio::placeholders::error ) );
00347    } else
00348      {
00349         setErrorStatus ( true );
00350         doClose (  );
00351      }
00352 }
00353 
00354 void
00355   AsyncSerial::doClose (  )
00356 {
00357    boost::system::error_code ec;
00358    pimpl->port.cancel ( ec );
00359    if ( ec )
00360       setErrorStatus ( true );
00361    pimpl->port.close ( ec );
00362    if ( ec )
00363       setErrorStatus ( true );
00364 }
00365 
00366 void
00367   AsyncSerial::setErrorStatus ( bool e )
00368 {
00369    lock_guard < mutex > l ( pimpl->errorMutex );
00370    pimpl->error = e;
00371 }
00372 
00373 void
00374    AsyncSerial::setReadCallback ( const boost::function < void ( const char *, size_t ) >
00375                                   &callback )
00376 {
00377    pimpl->callback = callback;
00378 }
00379 
00380 void
00381   AsyncSerial::clearReadCallback (  )
00382 {
00383    pimpl->callback.clear (  );
00384 }
00385 
00386 #else //__APPLE__
00387 
00388 #include <sys/types.h>
00389 #include <sys/stat.h>
00390 #include <fcntl.h>
00391 #include <termios.h>
00392 #include <unistd.h>
00393 
00394 class AsyncSerialImpl:private
00395    boost::noncopyable {
00396  public:
00397    AsyncSerialImpl (  ):
00398    backgroundThread (  ),
00399    open ( false ),
00400    error ( false ) {
00401    }
00402    boost::thread
00403       backgroundThread;         
00404 
00405    bool open;                   
00406 
00407    bool error;                  
00408 
00409    mutable boost::mutex errorMutex; 
00410 
00411    int
00412      fd;                        
00413 
00414    char
00415      readBuffer[AsyncSerial::readBufferSize];   
00416 
00418    boost::function < void ( const char *, size_t ) >
00419       callback;
00420 };
00421 
00422 AsyncSerial::AsyncSerial (  ):pimpl ( new AsyncSerialImpl )
00423 {
00424 
00425 }
00426 
00427 AsyncSerial::AsyncSerial ( const std::string & devname, unsigned int baud_rate,
00428                            asio::serial_port_base::parity opt_parity,
00429                            asio::serial_port_base::character_size opt_csize,
00430                            asio::serial_port_base::flow_control opt_flow,
00431                            asio::serial_port_base::stop_bits opt_stop ):
00432 pimpl ( new AsyncSerialImpl )
00433 {
00434    open ( devname, baud_rate, opt_parity, opt_csize, opt_flow, opt_stop );
00435 }
00436 
00437 void
00438   AsyncSerial::open ( const std::string & devname, unsigned int baud_rate,
00439                        asio::serial_port_base::parity opt_parity,
00440                        asio::serial_port_base::character_size opt_csize,
00441                        asio::serial_port_base::flow_control opt_flow,
00442                        asio::serial_port_base::stop_bits opt_stop )
00443 {
00444    if ( isOpen (  ) )
00445       close (  );
00446 
00447    setErrorStatus ( true );     
00448 
00449    struct termios new_attributes;
00450 
00451    speed_t speed;
00452 
00453    int status;
00454 
00455    
00456    pimpl->fd =::open ( devname.c_str (  ), O_RDWR | O_NOCTTY | O_NONBLOCK );
00457    if ( pimpl->fd < 0 )
00458       throw ( boost::system::system_error ( boost::system::error_code (  ),
00459                                             "Failed to open port" ) );
00460 
00461    
00462    status = tcgetattr ( pimpl->fd, &new_attributes );
00463    if ( status < 0 || !isatty ( pimpl->fd ) )
00464      {
00465         ::close ( pimpl->fd );
00466         throw ( boost::system::system_error ( boost::system::error_code (  ),
00467                                               "Device is not a tty" ) );
00468      }
00469    new_attributes.c_iflag = IGNBRK;
00470    new_attributes.c_oflag = 0;
00471    new_attributes.c_lflag = 0;
00472    new_attributes.c_cflag = ( CS8 | CREAD | CLOCAL );   
00473    
00474 
00475 
00476 
00477 
00478    new_attributes.c_cc[VMIN] = 1;   
00479    new_attributes.c_cc[VTIME] = 1;  
00480 
00481    
00482    switch ( baud_rate )
00483      {
00484      case 50:
00485         speed = B50;
00486         break;
00487      case 75:
00488         speed = B75;
00489         break;
00490      case 110:
00491         speed = B110;
00492         break;
00493      case 134:
00494         speed = B134;
00495         break;
00496      case 150:
00497         speed = B150;
00498         break;
00499      case 200:
00500         speed = B200;
00501         break;
00502      case 300:
00503         speed = B300;
00504         break;
00505      case 600:
00506         speed = B600;
00507         break;
00508      case 1200:
00509         speed = B1200;
00510         break;
00511      case 1800:
00512         speed = B1800;
00513         break;
00514      case 2400:
00515         speed = B2400;
00516         break;
00517      case 4800:
00518         speed = B4800;
00519         break;
00520      case 9600:
00521         speed = B9600;
00522         break;
00523      case 19200:
00524         speed = B19200;
00525         break;
00526      case 38400:
00527         speed = B38400;
00528         break;
00529      case 57600:
00530         speed = B57600;
00531         break;
00532      case 115200:
00533         speed = B115200;
00534         break;
00535      case 230400:
00536         speed = B230400;
00537         break;
00538      default:
00539         {
00540            ::close ( pimpl->fd );
00541            throw ( boost::system::system_error ( boost::system::error_code (  ),
00542                                                  "Unsupported baud rate" ) );
00543         }
00544      }
00545 
00546    cfsetospeed ( &new_attributes, speed );
00547    cfsetispeed ( &new_attributes, speed );
00548 
00549    
00550    status = tcsetattr ( pimpl->fd, TCSANOW, &new_attributes );
00551    if ( status < 0 )
00552      {
00553         ::close ( pimpl->fd );
00554         throw ( boost::system::system_error ( boost::system::error_code (  ),
00555                                               "Can't set port attributes" ) );
00556      }
00557    
00558    status = fcntl ( pimpl->fd, F_GETFL, 0 );
00559    if ( status != -1 )
00560       fcntl ( pimpl->fd, F_SETFL, status & ~O_NONBLOCK );
00561 
00562    setErrorStatus ( false );    
00563    pimpl->open = true;          
00564 
00565    thread t ( bind ( &AsyncSerial::doRead, this ) );
00566 
00567    pimpl->backgroundThread.swap ( t );
00568 }
00569 
00570      bool AsyncSerial::isOpen (  ) const {
00571         return
00572            pimpl->
00573            open;
00574      }
00575      bool
00576      AsyncSerial::errorStatus (  )  const {
00577         lock_guard <
00578            mutex >
00579         l ( pimpl->errorMutex );
00580         return
00581            pimpl->
00582            error;
00583      }
00584      void
00585      AsyncSerial::close (  )
00586 {
00587    if ( !isOpen (  ) )
00588       return;
00589 
00590    pimpl->open = false;
00591 
00592    ::close ( pimpl->fd );       
00593 
00594    pimpl->backgroundThread.join (  );
00595    if ( errorStatus (  ) )
00596      {
00597         throw ( boost::system::system_error ( boost::system::error_code (  ),
00598                                               "Error while closing the device" ) );
00599      }
00600 }
00601 
00602 void
00603   AsyncSerial::write ( const char *data, size_t size )
00604 {
00605    if ( ::write ( pimpl->fd, data, size ) != size )
00606       setErrorStatus ( true );
00607 }
00608 
00609 void
00610   AsyncSerial::write ( const std::vector < char >&data )
00611 {
00612    if ( ::write ( pimpl->fd, &data[0], data.size (  ) ) != data.size (  ) )
00613       setErrorStatus ( true );
00614 }
00615 
00616 void
00617   AsyncSerial::writeString ( const std::string & s )
00618 {
00619    if ( ::write ( pimpl->fd, &s[0], s.size (  ) ) != s.size (  ) )
00620       setErrorStatus ( true );
00621 }
00622 
00623 AsyncSerial::~AsyncSerial (  )
00624 {
00625    if ( isOpen (  ) )
00626      {
00627         try
00628         {
00629            close (  );
00630         }
00631         catch ( ... )
00632         {
00633            
00634         }
00635      }
00636 }
00637 
00638 void
00639   AsyncSerial::doRead (  )
00640 {
00641    
00642    for ( ;; )
00643      {
00644         int
00645           received =::read ( pimpl->fd, pimpl->readBuffer, readBufferSize );
00646 
00647         if ( received < 0 )
00648           {
00649              if ( isOpen (  ) == false )
00650                 return;         
00651              else
00652                {
00653                   setErrorStatus ( true );
00654                   continue;
00655                }
00656           }
00657         if ( pimpl->callback )
00658            pimpl->callback ( pimpl->readBuffer, received );
00659      }
00660 }
00661 
00662 void
00663 AsyncSerial::readEnd ( const boost::system::error_code & error,
00664                           size_t bytes_transferred )
00665 {
00666    
00667 }
00668 
00669 void
00670   AsyncSerial::doWrite (  )
00671 {
00672    
00673 }
00674 
00675 void
00676   AsyncSerial::writeEnd ( const boost::system::error_code & error )
00677 {
00678    
00679 }
00680 
00681 void
00682   AsyncSerial::doClose (  )
00683 {
00684    
00685 }
00686 
00687 void
00688   AsyncSerial::setErrorStatus ( bool e )
00689 {
00690    lock_guard < mutex > l ( pimpl->errorMutex );
00691    pimpl->error = e;
00692 }
00693 
00694 void
00695   AsyncSerial::setReadCallback ( const
00696                                  function < void ( const char *, size_t ) > &callback )
00697 {
00698    pimpl->callback = callback;
00699 }
00700 
00701 void
00702   AsyncSerial::clearReadCallback (  )
00703 {
00704    pimpl->callback.clear (  );
00705 }
00706 
00707 #endif //__APPLE__
00708 
00709 
00710 
00711 
00712 
00713 CallbackAsyncSerial::CallbackAsyncSerial (  ):AsyncSerial (  )
00714 {
00715 
00716 }
00717 
00718 CallbackAsyncSerial::CallbackAsyncSerial ( const std::string & devname,
00719                                            unsigned int baud_rate,
00720                                            asio::serial_port_base::parity opt_parity,
00721                                            asio::
00722                                            serial_port_base::character_size opt_csize,
00723                                            asio::serial_port_base::flow_control opt_flow,
00724                                            asio::serial_port_base::stop_bits opt_stop ):
00725 AsyncSerial ( devname, baud_rate, opt_parity, opt_csize, opt_flow, opt_stop )
00726 {
00727 
00728 }
00729 
00730 void
00731   CallbackAsyncSerial::setCallback ( const
00732                                      boost::function < void ( const char *,
00733                                                               size_t ) > &callback )
00734 {
00735    setReadCallback ( callback );
00736 }
00737 
00738 void
00739   CallbackAsyncSerial::clearCallback (  )
00740 {
00741    clearReadCallback (  );
00742 }
00743 
00744 CallbackAsyncSerial::~CallbackAsyncSerial (  )
00745 {
00746    clearReadCallback (  );
00747 }