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
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00045 #include <stdio.h>
00046 #include <string.h>
00047 #include <errno.h>
00048 #include <termios.h>
00049 #include <math.h>
00050 #include <poll.h>
00051 #include <signal.h>
00052 #include <fcntl.h>
00053 #include <iostream>
00054 #include <fstream>
00055
00056 #include "serialcom/SerialCom.h"
00057
00059 #define SERIAL_EXCEPT(except, msg, ...) \
00060 { \
00061 char buf[1000]; \
00062 snprintf(buf, 1000, msg " (in serialcom::SerialCom::%s)" , ##__VA_ARGS__, __FUNCTION__); \
00063 throw except(buf); \
00064 }
00065
00066 serialcom::SerialCom::SerialCom() : fd_(-1)
00067 {
00068 stream_thread_ = NULL;
00069 }
00070
00071 serialcom::SerialCom::~SerialCom()
00072 {
00073 if(portOpen()) close();
00074 }
00075
00076
00077 tcflag_t serialcom::SerialCom:: selectbaud(int baudrate_)
00078 {
00079
00080 switch(baudrate_)
00081 {
00082 case(0): return(B0);
00083 case(50): return(B50);
00084 case(75): return(B75);
00085 case(110): return(B110);
00086 case(134): return(B134);
00087 case(150): return(B150);
00088 case(200): return(B200);
00089 case(300): return(B300);
00090 case(600): return(B600);
00091 case(1200): return(B1200);
00092 case(1800): return(B1800);
00093 case(2400): return(B2400);
00094 case(4800): return(B4800);
00095 case(9600): return(B9600);
00096 case(19200): return(B19200);
00097 case(38400): return(B38400);
00098 case(57600): return(B57600);
00099 case(115200): return(B115200);
00100 case(230400): return(B230400);
00101 case(460800): return(B460800);
00102 case(500000): return(B500000);
00103 case(576000): return(B576000);
00104 default:
00105 return(B9600);
00106
00107 }
00108 };
00109
00110 bool serialcom::SerialCom:: config(int baudrate_, int databits_, int startbits_, int stopbits_, int parity_, int NLchar_)
00111 {
00112
00113 tcflag_t DATABITS;
00114 tcflag_t PARITY;
00115 tcflag_t confipar;
00116 tcflag_t MAPCRNL;
00117 tcflag_t STOPBITS;
00118
00119 int attribset, attribget;
00120
00121 switch (databits_)
00122 {
00123 case(5): DATABITS = CS5; break;
00124 case(6): DATABITS = CS6; break;
00125 case(7): DATABITS = CS7; break;
00126 case(8): DATABITS = CS8; break;
00127 default:
00128 DATABITS = CS8;
00129 };
00130
00131 switch (parity_)
00132 {
00133 case(EVEN):
00134 PARITY = PARENB;
00135 PARITY &= ~PARODD;
00136 confipar = INPCK | ISTRIP;
00137 break;
00138
00139 case(ODD):
00140 PARITY = PARENB;
00141 PARITY |= PARODD;
00142 confipar = INPCK | ISTRIP;
00143 break;
00144
00145 default:
00146 PARITY = 0;
00147 confipar = IGNPAR;
00148
00149 };
00150
00151 switch (stopbits_)
00152 {
00153 case(1):
00154 default:
00155 STOPBITS = 0;
00156 break;
00157 case(2):
00158 STOPBITS = CSTOPB;
00159 break;
00160 };
00161
00162 if (NLchar_ == 1)
00163 {
00164 MAPCRNL = ICRNL;
00165 newParams.c_lflag = (ICANON & (~(ECHO)));
00166 }
00167 else
00168 {
00169 MAPCRNL = 0;
00170 newParams.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
00171 };
00172
00173
00174 attribget = tcgetattr(fd_, &ComParams);
00175
00176 newParams.c_iflag = confipar | MAPCRNL;
00177
00178
00179 newParams.c_oflag = 0;
00180
00181
00182 newParams.c_cflag = selectbaud(baudrate_) |
00183 DATABITS |
00184 STOPBITS |
00185 PARITY |
00186 CLOCAL |
00187 CREAD;
00188
00189
00190
00191 newParams.c_cc[VTIME] = 0;
00192 newParams.c_cc[VMIN] = 0;
00193
00194 tcflush(fd_, TCIFLUSH);
00195
00196 attribset = tcsetattr(fd_, TCSANOW, &newParams );
00197
00198 if(attribset == 0)
00199 {
00200 baud_ = baudrate_;
00201 databits = databits_;
00202 startbits = startbits_;
00203 stopbits = stopbits_;
00204 parity = parity_;
00205 return true;
00206 }
00207 else
00208 {
00209 SERIAL_EXCEPT(serialcom::Exception,"Set serial communication parameters failed:");
00210 return false;
00211 }
00212
00213 };
00214
00215 bool serialcom::SerialCom:: changebaudrate(int baudrate_)
00216 {
00217 int outset;
00218 int inset;
00219 int attribset;
00220
00221 attribset = 0;
00222
00223 outset = cfsetospeed(&newParams,(speed_t) selectbaud(baudrate_));
00224 inset = cfsetispeed(&newParams, (speed_t) selectbaud(baudrate_));
00225
00226 if((inset<0) || (outset<0))
00227 {
00228 SERIAL_EXCEPT(serialcom::Exception,"Setting baudrate failed");
00229 }
00230
00231 tcflush(fd_, TCIFLUSH);
00232 attribset = tcsetattr(fd_,TCSANOW,&newParams);
00233
00234 if(attribset<0)
00235 {
00236 SERIAL_EXCEPT(serialcom::Exception,"Set serial communication parameters failed:");
00237 return false;
00238 }
00239
00240 return true;
00241 };
00242
00243
00244 void serialcom::SerialCom::open(const char * port_name, int baud_rate)
00245 {
00246 tcflag_t MAPCRNL;
00247
00248 if(portOpen()) close();
00249
00250
00251
00252
00253
00254 fd_ = ::open(port_name, O_RDWR | O_NONBLOCK | O_NOCTTY);
00255
00256 if(fd_ == -1)
00257 {
00258 const char *extra_msg = "";
00259 switch(errno)
00260 {
00261 case EACCES:
00262 extra_msg = "You probably don't have premission to open the port for reading and writing.";
00263 break;
00264
00265 case ENOENT:
00266 extra_msg = "The requested port does not exist. Was the port name misspelled?";
00267 break;
00268 }
00269 SERIAL_EXCEPT(serialcom::Exception, "Failed to open port: %s. %s (errno = %d). %s", port_name, strerror(errno), errno, extra_msg);
00270 }
00271
00272 try
00273 {
00274 struct flock fl;
00275 fl.l_type = F_WRLCK;
00276 fl.l_whence = SEEK_SET;
00277 fl.l_start = 0;
00278 fl.l_len = 0;
00279 fl.l_pid = getpid();
00280
00281 if(fcntl(fd_, F_SETLK, &fl) != 0)
00282 SERIAL_EXCEPT(serialcom::Exception, "Device %s is already locked. Try 'lsof | grep %s' to find other processes that currently have the port open.", port_name, port_name);
00283
00284
00285 struct termios newtio;
00286 tcgetattr(fd_, &newtio);
00287 memset (&newtio.c_cc, 0, sizeof (newtio.c_cc));
00288 newtio.c_cflag = CS8 | CLOCAL | CREAD;
00289
00290
00291
00292
00293 MAPCRNL = ICRNL;
00294 newtio.c_iflag = IGNPAR | MAPCRNL;
00295
00296
00297 newtio.c_oflag = 0;
00298
00299
00300
00301
00302 newtio.c_lflag = ICANON;
00303
00304
00305 cfsetspeed(&newtio, selectbaud(baud_rate));
00306 baud_ = baud_rate;
00307
00308
00309 tcflush(fd_, TCIFLUSH);
00310 if(tcsetattr(fd_, TCSANOW, &newtio) < 0)
00311 SERIAL_EXCEPT(serialcom::Exception, "Unable to set serial port attributes. The port you specified (%s) may not be a serial port.", port_name);
00312 usleep (200000);
00313 }
00314 catch(serialcom::Exception& e)
00315 {
00316
00317 if(fd_ != -1) ::close(fd_);
00318 fd_ = -1;
00319 throw e;
00320 }
00321 }
00322
00323 void serialcom::SerialCom::close()
00324 {
00325 int retval = 0;
00326
00327 retval = ::close(fd_);
00328
00329 fd_ = -1;
00330
00331 if(retval != 0)
00332 SERIAL_EXCEPT(serialcom::Exception, "Failed to close port properly -- error = %d: %s\n", errno, strerror(errno));
00333 }
00334
00335 int serialcom::SerialCom::write(const char * data, int length)
00336 {
00337 int len = length==-1 ? strlen(data) : length;
00338
00339
00340 int origflags = fcntl(fd_, F_GETFL, 0);
00341 fcntl(fd_, F_SETFL, origflags & ~O_NONBLOCK);
00342 int retval = ::write(fd_, data, len);
00343 fcntl(fd_, F_SETFL, origflags | O_NONBLOCK);
00344
00345 if(retval == len) return retval;
00346 else SERIAL_EXCEPT(serialcom::Exception, "write failed");
00347 }
00348
00349
00350 bool serialcom::SerialCom::writebyte(uint8_t byte)
00351 {
00352 int written = 0;
00353 while (written != 1)
00354 {
00355 written = ::write(fd_, &byte, 1);
00356 if (written < 0)
00357 {
00358 return false;
00359 }
00360
00361 usleep(1000);
00362 }
00363 return true;
00364 }
00365
00366
00367 int serialcom :: SerialCom:: readbyte(uint8_t *read_byte)
00368 {
00369
00370
00371 char read_result;
00372 int ret;
00373 ret = ::read(fd_, &read_result, 1);
00374 *read_byte = (uint8_t) read_result;
00375
00376
00377
00378
00379
00380
00381 if (read_result == EOF) return false;
00382 return ret;
00383 }
00384
00385
00386 int serialcom::SerialCom::read(char * buffer, int max_length, int timeout)
00387 {
00388 int ret;
00389
00390 struct pollfd ufd[1];
00391 int retval;
00392 ufd[0].fd = fd_;
00393 ufd[0].events = POLLIN;
00394
00395 if(timeout == 0) timeout = -1;
00396
00397 if((retval = poll(ufd, 1, timeout)) < 0) SERIAL_EXCEPT(serialcom::Exception, "poll failed -- error = %d: %s", errno, strerror(errno));
00398
00399 if(retval == 0) SERIAL_EXCEPT(serialcom::TimeoutException, "timeout reached");
00400
00401 if(ufd[0].revents & POLLERR) SERIAL_EXCEPT(serialcom::Exception, "error on socket, possibly unplugged");
00402
00403 ret = ::read(fd_, buffer, max_length);
00404
00405 if(ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK) SERIAL_EXCEPT(serialcom::Exception, "read failed");
00406
00407 return ret;
00408 }
00409
00410 int serialcom::SerialCom::readBytes(char * buffer, int length, int timeout)
00411 {
00412 int ret;
00413 int current = 0;
00414
00415 struct pollfd ufd[1];
00416 int retval;
00417 ufd[0].fd = fd_;
00418 ufd[0].events = POLLIN;
00419
00420 if(timeout == 0) timeout = -1;
00421
00422 while(current < length)
00423 {
00424 if((retval = poll(ufd, 1, timeout)) < 0) SERIAL_EXCEPT(serialcom::Exception, "poll failed -- error = %d: %s", errno, strerror(errno));
00425
00426 if(retval == 0) SERIAL_EXCEPT(serialcom::TimeoutException, "timeout reached");
00427
00428 if(ufd[0].revents & POLLERR) SERIAL_EXCEPT(serialcom::Exception, "error on socket, possibly unplugged");
00429
00430 ret = ::read(fd_, &buffer[current], length-current);
00431
00432 if(ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK) SERIAL_EXCEPT(serialcom::Exception, "read failed");
00433
00434 current += ret;
00435 }
00436 return current;
00437 }
00438
00439 int serialcom::SerialCom::readLine(char * buffer, int length, int timeout)
00440 {
00441 int ret;
00442 int current = 0;
00443
00444 struct pollfd ufd[1];
00445 int retval;
00446 ufd[0].fd = fd_;
00447 ufd[0].events = POLLIN;
00448
00449 if(timeout == 0) timeout = -1;
00450
00451 while(current < length-1)
00452 {
00453 if(current > 0)
00454 if(buffer[current-1] == '\n')
00455 return current;
00456
00457 if((retval = poll(ufd, 1, timeout)) < 0) SERIAL_EXCEPT(serialcom::Exception, "poll failed -- error = %d: %s", errno, strerror(errno));
00458
00459 if(retval == 0) SERIAL_EXCEPT(serialcom::TimeoutException, "timeout reached");
00460
00461 if(ufd[0].revents & POLLERR) SERIAL_EXCEPT(serialcom::Exception, "error on socket, possibly unplugged");
00462
00463 ret = ::read(fd_, &buffer[current], length-current);
00464
00465 if(ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK) SERIAL_EXCEPT(serialcom::Exception, "read failed");
00466
00467 current += ret;
00468 }
00469 SERIAL_EXCEPT(serialcom::Exception, "buffer filled without end of line being found");
00470 }
00471 using namespace std;
00472 bool serialcom::SerialCom::readLine(std::string& buffer)
00473 {
00474 int ret;
00475 struct pollfd ufd[1];
00476 int retval;
00477 ufd[0].fd = fd_;
00478 ufd[0].events = POLLIN;
00479
00480 buffer.clear();
00481
00482 int timeout=1;
00483 int c=0;
00484
00485 while(1)
00486 {
00487 char ch;
00488
00489 ret = readbyte((uint8_t*)&ch);
00490
00491 if(ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
00492 {
00493 continue;
00494 }else if(ret==-1)
00495 {
00496
00497 break;
00498 }
00499
00500 if(ch=='\n')
00501 break;
00502
00503 buffer.append(1,ch);
00504 }
00505
00506 return true;
00507 }
00508
00509 bool serialcom::SerialCom::readLine(std::string * buffer, int timeout)
00510 {
00511 int ret;
00512
00513 struct pollfd ufd[1];
00514 int retval;
00515 ufd[0].fd = fd_;
00516 ufd[0].events = POLLIN;
00517
00518 if(timeout == 0) timeout = -1;
00519
00520 buffer->clear();
00521 while(buffer->size() < buffer->max_size()/2)
00522 {
00523
00524 ret = buffer->find_first_of("\n");
00525
00526
00527 if(ret == 0)
00528 {
00529 buffer->erase(0,1);
00530 ret = buffer->find_first_of("\n");
00531 }
00532
00533 if(ret > 0)
00534 {
00535
00536 buffer->erase(ret);
00537
00538
00539
00540
00541 return true;
00542 }
00543
00544 if((retval = poll(ufd, 1, timeout)) < 0) SERIAL_EXCEPT(serialcom::Exception, "poll failed -- error = %d: %s", errno, strerror(errno));
00545
00546 if(retval == 0) SERIAL_EXCEPT(serialcom::TimeoutException, "timeout reached");
00547
00548 if(ufd[0].revents & POLLERR) SERIAL_EXCEPT(serialcom::Exception, "error on socket, possibly unplugged");
00549
00550 char temp_buffer[128];
00551
00552 ret = ::read(fd_, temp_buffer, 128);
00553
00554
00555
00556
00557
00558 if(ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK) SERIAL_EXCEPT(serialcom::Exception, "read failed");
00559
00560
00561 buffer->append(temp_buffer, ret);
00562
00563
00564
00565
00566 }
00567
00568 SERIAL_EXCEPT(serialcom::Exception, "buffer filled without end of line being found");
00569 }
00570
00571 bool serialcom::SerialCom::readBetween(std::string * buffer, char start, char end, int timeout)
00572 {
00573 int ret;
00574
00575 struct pollfd ufd[1];
00576 int retval;
00577 ufd[0].fd = fd_;
00578 ufd[0].events = POLLIN;
00579
00580 if(timeout == 0) timeout = -1;
00581
00582
00583 buffer->clear();
00584 while(buffer->size() < buffer->max_size()/2)
00585 {
00586 if((retval = poll(ufd, 1, timeout)) < 0) SERIAL_EXCEPT(serialcom::Exception, "poll failed -- error = %d: %s", errno, strerror(errno));
00587
00588 if(retval == 0) SERIAL_EXCEPT(serialcom::TimeoutException, "timeout reached");
00589
00590 if(ufd[0].revents & POLLERR) SERIAL_EXCEPT(serialcom::Exception, "error on socket, possibly unplugged");
00591
00592 char temp_buffer[128];
00593 ret = ::read(fd_, temp_buffer, 128);
00594
00595 if(ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK) SERIAL_EXCEPT(serialcom::Exception, "read failed");
00596
00597
00598 buffer->append(temp_buffer, ret);
00599
00600
00601 ret = buffer->find_first_of(start);
00602
00603 if(ret == -1) buffer->clear();
00604
00605 else if(ret > 0) buffer->erase(0, ret);
00606
00607
00608 ret = buffer->find_first_of(end);
00609 if(ret > 0)
00610 {
00611
00612 buffer->erase(ret+1, buffer->size()-ret-1);
00613 return true;
00614 }
00615 }
00616 SERIAL_EXCEPT(serialcom::Exception, "buffer filled without reaching end of data stream");
00617 }
00618
00619 int serialcom::SerialCom::flush()
00620 {
00621 int retval = tcflush(fd_, TCIOFLUSH);
00622 if(retval != 0) SERIAL_EXCEPT(serialcom::Exception, "tcflush failed");
00623
00624 return retval;
00625 }
00626
00627 bool serialcom::SerialCom::startReadStream(boost::function<void(char*, int)> f)
00628 {
00629 if(stream_thread_ != NULL) return false;
00630
00631 stream_stopped_ = false;
00632 stream_paused_ = false;
00633
00634 readCallback = f;
00635
00636 stream_thread_ = new boost::thread(boost::bind(&serialcom::SerialCom::readThread, this));
00637 return true;
00638 }
00639
00640 void serialcom::SerialCom::readThread()
00641 {
00642 char data[MAX_LENGTH];
00643 int ret;
00644
00645 struct pollfd ufd[1];
00646 ufd[0].fd = fd_;
00647 ufd[0].events = POLLIN;
00648
00649 while(!stream_stopped_)
00650 {
00651 if(!stream_paused_)
00652 {
00653 if(poll(ufd, 1, 10) > 0)
00654 {
00655 if(!(ufd[0].revents & POLLERR))
00656 {
00657 ret = ::read(fd_, data, MAX_LENGTH);
00658 if(ret>0)
00659 {
00660 readCallback(data, ret);
00661 }
00662 }
00663 }
00664 }
00665 }
00666 }
00667
00668 bool serialcom::SerialCom::startReadLineStream(boost::function<void(std::string*)> f)
00669 {
00670 if(stream_thread_ != NULL) return false;
00671
00672 stream_stopped_ = false;
00673 stream_paused_ = false;
00674
00675 readLineCallback = f;
00676
00677 stream_thread_ = new boost::thread(boost::bind(&serialcom::SerialCom::readLineThread, this));
00678 return true;
00679 }
00680
00681 void serialcom::SerialCom::readLineThread()
00682 {
00683 std::string data;
00684 bool error = false;
00685
00686 while(!stream_stopped_)
00687 {
00688
00689 if(!stream_paused_)
00690 {
00691 error = false;
00692 try{readLine(&data, 100); }
00693 catch(serialcom::Exception& e)
00694 {
00695 error = true;
00696 }
00697
00698
00699
00700 if(!error && data.size()>0) {readLineCallback(&data);};
00701 }
00702 }
00703 }
00704
00705 bool serialcom::SerialCom::startReadBetweenStream(boost::function<void(std::string*)> f, char start, char end)
00706 {
00707 if(stream_thread_ != NULL) return false;
00708
00709 stream_stopped_ = false;
00710 stream_paused_ = false;
00711
00712 readBetweenCallback = f;
00713
00714 stream_thread_ = new boost::thread(boost::bind(&serialcom::SerialCom::readBetweenThread, this, start, end));
00715 return true;
00716 }
00717
00718 void serialcom::SerialCom::readBetweenThread(char start, char end)
00719 {
00720 std::string data;
00721 bool error = false;
00722
00723 while(!stream_stopped_)
00724 {
00725 if(!stream_paused_)
00726 {
00727 error = false;
00728 try{ readBetween(&data, start, end, 100); }
00729 catch(serialcom::Exception& e)
00730 {
00731 error = true;
00732 }
00733
00734 if(!error && data.size()>0) readBetweenCallback(&data);
00735 }
00736 }
00737 }
00738
00739 void serialcom::SerialCom::stopStream()
00740 {
00741 stream_stopped_ = true;
00742 stream_thread_->join();
00743
00744 delete stream_thread_;
00745 stream_thread_ = NULL;
00746 }
00747
00748 void serialcom::SerialCom::pauseStream()
00749 {
00750 stream_paused_ = true;
00751 }
00752
00753 void serialcom::SerialCom::resumeStream()
00754 {
00755 stream_paused_ = false;
00756 }
00757
00758