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 }