PageRenderTime 39ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Lib/Firmware/DynamixelGateway/Host/SerialDevice.cc

http://github.com/UPenn-RoboCup/UPennalizers
C++ | 931 lines | 693 code | 130 blank | 108 comment | 85 complexity | 341444a3a49d0f4adce7c512ac0cb37c MD5 | raw file
Possible License(s): GPL-3.0
  1. /* Driver for reading data from a serial port
  2. Aleksandr Kushleyev <akushley(at)seas(dot)upenn(dot)edu>
  3. University of Pennsylvania, 2008
  4. BSD license.
  5. --------------------------------------------------------------------
  6. Copyright (c) 2008 Aleksandr Kushleyev
  7. All rights reserved.
  8. Redistribution and use in source and binary forms, with or without
  9. modification, are permitted provided that the following conditions
  10. are met:
  11. 1. Redistributions of source code must retain the above copyright
  12. notice, this list of conditions and the following disclaimer.
  13. 2. Redistributions in binary form must reproduce the above copyright
  14. notice, this list of conditions and the following disclaimer in the
  15. documentation and/or other materials provided with the distribution.
  16. 3. The name of the author may not be used to endorse or promote products
  17. derived from this software without specific prior written permission.
  18. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  19. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #include "SerialDevice.hh"
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. //constructor
  33. SerialDevice::SerialDevice()
  34. {
  35. _fd=-1;
  36. _connected=false;
  37. _block=-1;
  38. _baud=B2400;
  39. _ioMode=IO_BLOCK_W_TIMEOUT;
  40. _delay_us=0;
  41. _numTermChars=0;
  42. _retTermSequence=false;
  43. }
  44. //destructor
  45. SerialDevice::~SerialDevice()
  46. {
  47. Disconnect();
  48. }
  49. //wrapper for ConnectSerial function
  50. int SerialDevice::Connect(const char * device, const int speed)
  51. {
  52. return ConnectSerial(device,speed);
  53. }
  54. int SerialDevice::Connect(const char * device, const char * speedStr)
  55. {
  56. int speed = strtol(speedStr,NULL,10);
  57. return ConnectSerial(device,speed);
  58. }
  59. //connect to the serial device
  60. int SerialDevice::ConnectSerial(const char * device, const int speed)
  61. {
  62. if (_connected)
  63. {
  64. std::cout << "SerialDevice::ConnectSerial: Warning: already connected" << std::endl;
  65. return 0;
  66. }
  67. //store the device name
  68. strncpy(_device,device,MAX_DEVICE_NAME_LENGTH);
  69. // Open the device
  70. if((_fd = open(_device, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
  71. //if((_fd = open(_device, O_RDWR | O_NOCTTY)) < 0)
  72. {
  73. #ifdef SERIAL_DEVICE_DEBUG
  74. std::cout << "SerialDevice::ConnectSerial: Error: Unable to open serial port" << std::endl;
  75. #endif
  76. return -1;
  77. }
  78. //update the connected flag
  79. _connected=true;
  80. //set the default IO mode
  81. if (Set_IO_BLOCK_W_TIMEOUT())
  82. {
  83. #ifdef SERIAL_DEVICE_DEBUG
  84. std::cout << "SerialDevice::ConnectSerial: Error: Unable to set the io mode" << std::endl;
  85. #endif
  86. close(_fd);
  87. _connected=false;
  88. return -1;
  89. }
  90. //set the device type
  91. _device_type = DEVICE_TYPE_SERIAL;
  92. if (speed==0)
  93. return 0;
  94. //save current attributes so they can be restored after use
  95. if( tcgetattr( _fd, &_oldterm ) < 0 )
  96. {
  97. #ifdef SERIAL_DEVICE_DEBUG
  98. std::cout<<"SerialDevice::ConnectSerial: Error: Unable to get old serial port attributes" << std::endl;
  99. #endif
  100. close(_fd);
  101. _connected=false;
  102. return -1;
  103. }
  104. //set up the terminal and set the baud rate
  105. if (SetBaudRate(speed))
  106. {
  107. #ifdef SERIAL_DEVICE_DEBUG
  108. std::cout << "SerialDevice::ConnectSerial: Error: Unable to set baud rate" << std::endl;
  109. #endif
  110. close(_fd);
  111. _connected=false;
  112. return -1;
  113. }
  114. return 0;
  115. }
  116. int SerialDevice::ConnectTCP(const char * device, const int port, const int buff_size)
  117. {
  118. //int buffSize, nonblock=1;
  119. struct sockaddr_in serv_addr;
  120. struct hostent *hostptr;
  121. //check the port
  122. if ( (port < 0) || (port > 65536) )
  123. {
  124. #ifdef SERIAL_DEVICE_DEBUG
  125. std::cout << "SerialDevice::ConnectTCP: Error: bad port number" << std::endl;
  126. #endif
  127. return -1;
  128. }
  129. //get the hostname
  130. if ((hostptr = gethostbyname(device)) == NULL)
  131. {
  132. #ifdef SERIAL_DEVICE_DEBUG
  133. std::cout << "SerialDevice::ConnectTCP: Error: could not get hostname" << std::endl;
  134. #endif
  135. return -1;
  136. }
  137. //Get host info
  138. bzero((char *) &serv_addr, sizeof(serv_addr));
  139. serv_addr.sin_family = AF_INET;
  140. bcopy(hostptr->h_addr, (char *) &serv_addr.sin_addr, hostptr->h_length);
  141. serv_addr.sin_port = htons(port);
  142. if ((_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  143. {
  144. #ifdef SERIAL_DEVICE_DEBUG
  145. std::cout << "SerialDevice::ConnectTCP: Error: could not open a socket" << std::endl;
  146. #endif
  147. return -1;
  148. }
  149. // Set read buffer size
  150. if (setsockopt(_fd, SOL_SOCKET, SO_RCVBUF, &buff_size, sizeof(int)) < 0)
  151. {
  152. #ifdef SERIAL_DEVICE_DEBUG
  153. std::cout << "SerialDevice::ConnectTCP: Error: could not set receive buffer size" << std::endl;
  154. #endif
  155. close(_fd);
  156. return -1;
  157. }
  158. //update the connected flag
  159. _connected=true;
  160. // Set nonblocking I/O so that we can attempt to connect
  161. if (Set_IO_NONBLOCK_WO_TIMEOUT())
  162. {
  163. #ifdef SERIAL_DEVICE_DEBUG
  164. std::cout << "SerialDevice::ConnectTCP: Error: could not set non-blocking io mode" << std::endl;
  165. #endif
  166. close(_fd);
  167. _connected=false;
  168. return -1;
  169. }
  170. struct timeval selTimeout = {0,DEFAULT_TCP_CONNECT_TIMEOUT_US};
  171. fd_set wrfds;
  172. FD_ZERO(&wrfds);
  173. FD_SET(_fd, &wrfds);
  174. connect(_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
  175. int selret = 0;
  176. selret = select(_fd+1,NULL,&wrfds,NULL,&selTimeout);
  177. //make sure that we actually connected by getting the status from getsocketopt
  178. int option_value;
  179. int option_length=4; //need to set this value to 4 to let getsockopt know that we are expecting an int (4 bytes)
  180. if (getsockopt(_fd,SOL_SOCKET,SO_ERROR,(char*)&option_value,(socklen_t*)&option_length) != 0)
  181. {
  182. #ifdef SERIAL_DEVICE_DEBUG
  183. std::cout << "SerialDevice::ConnectTCP: Error: could not get socket option" << std::endl;
  184. #endif
  185. close(_fd);
  186. _connected=false;
  187. return -1;
  188. }
  189. //std::cout <<"option length= "<<option_length<<" option value= " << *(int*)option_value<<std::endl;
  190. if (option_value != 0)
  191. {
  192. #ifdef SERIAL_DEVICE_DEBUG
  193. std::cout << "SerialDevice::ConnectTCP: Error: could not connect to the server:"<< std::endl;
  194. std::cout<<strerror(option_value)<<std::endl;
  195. #endif
  196. close(_fd);
  197. _connected=false;
  198. return -1;
  199. }
  200. if (selret <= 0)
  201. {
  202. #ifdef SERIAL_DEVICE_DEBUG
  203. std::cout << "SerialDevice::ConnectTCP: Error: could not connect to the server" << std::endl;
  204. #endif
  205. close(_fd);
  206. _connected=false;
  207. return -1;
  208. }
  209. //set the default IO mode
  210. if (Set_IO_BLOCK_W_TIMEOUT())
  211. {
  212. #ifdef SERIAL_DEVICE_DEBUG
  213. std::cout << "SerialDevice::ConnectSerial: Error: Unable to set the io mode" << std::endl;
  214. #endif
  215. close(_fd);
  216. _connected=false;
  217. return -1;
  218. }
  219. _device_type = DEVICE_TYPE_TCP;
  220. return 0;
  221. }
  222. //disconnect from the device
  223. int SerialDevice::Disconnect()
  224. {
  225. //check whether we are connected to the device
  226. if (!_connected)
  227. {
  228. return 0;
  229. }
  230. if (_device_type == DEVICE_TYPE_SERIAL)
  231. {
  232. // Restore old terminal settings
  233. if(tcsetattr(_fd,TCSANOW,&_oldterm) < 0)
  234. {
  235. #ifdef SERIAL_DEVICE_DEBUG
  236. std::cout << "SerialDevice::Disconnect: Failed to restore attributes!" << std::endl;
  237. #endif
  238. }
  239. }
  240. // Actually close the device
  241. if(close(_fd) != 0)
  242. {
  243. #ifdef SERIAL_DEVICE_DEBUG
  244. std::cout << "SerialDevice::Disconnect: Failed to close device!" << std::endl;
  245. #endif
  246. _connected=false;
  247. return -1;
  248. }
  249. _connected=false;
  250. return 0;
  251. }
  252. bool SerialDevice::IsConnected()
  253. {
  254. return _connected;
  255. }
  256. //convert speed (integer) to baud rate (speed_t)
  257. int SerialDevice::_SpeedToBaud(int speed, speed_t & baud)
  258. {
  259. switch (speed)
  260. {
  261. case 2400:
  262. baud=B2400;
  263. return 0;
  264. case 4800:
  265. baud=B4800;
  266. return 0;
  267. case 9600:
  268. baud=B9600;
  269. return 0;
  270. case 19200:
  271. baud=B19200;
  272. return 0;
  273. case 38400:
  274. baud=B38400;
  275. return 0;
  276. case 57600:
  277. baud=B57600;
  278. return 0;
  279. case 115200:
  280. baud=B115200;
  281. return 0;
  282. case 230400:
  283. baud=B230400;
  284. return 0;
  285. case 460800:
  286. #ifndef __APPLE__
  287. baud=B460800;
  288. return 0;
  289. #endif
  290. case 921600:
  291. #ifndef __APPLE__
  292. baud=B921600;
  293. return 0;
  294. #endif
  295. case 1000000:
  296. #ifndef __APPLE__
  297. baud=B1000000;
  298. return 0;
  299. #endif
  300. case 2000000:
  301. #ifndef __APPLE__
  302. baud=B2000000;
  303. return 0;
  304. #endif
  305. default:
  306. #ifdef SERIAL_DEVICE_DEBUG
  307. std::cout << "SerialDevice::speedToBaud: ERROR: unknown baud rate" <<std::endl;
  308. #endif
  309. return -1;
  310. }
  311. }
  312. //set the terminal baud rate. Argument can be either an integer (ex. 115200) or speed_t (ex. B115200)
  313. int SerialDevice::SetBaudRate(const int speed)
  314. {
  315. speed_t tempBaud;
  316. //check whether we are connected to the device
  317. if (!_connected)
  318. {
  319. #ifdef SERIAL_DEVICE_DEBUG
  320. std::cout << "SerialDevice::FlushInputBuffer: Error: not connected to the device" << std::endl;
  321. #endif
  322. return -1;
  323. }
  324. //convert the integer speed value to speed_t if needed
  325. if (_SpeedToBaud(speed,tempBaud))
  326. {
  327. #ifdef SERIAL_DEVICE_DEBUG
  328. std::cout<<"SerialDevice::SetBaudRate: Error: bad baud rate" << std::endl;
  329. #endif
  330. return -1;
  331. }
  332. //get current port settings
  333. if( tcgetattr( _fd, &_newterm ) < 0 )
  334. {
  335. #ifdef SERIAL_DEVICE_DEBUG
  336. std::cout<<"SerialDevice::SetBaudRate: Error: Unable to get serial port attributes" << std::endl;
  337. #endif
  338. return -1;
  339. }
  340. //cfmakeraw initializes the port to standard configuration. Use this!
  341. cfmakeraw( &_newterm );
  342. //set input baud rate
  343. if (cfsetispeed( &_newterm, tempBaud ) < 0 )
  344. {
  345. #ifdef SERIAL_DEVICE_DEBUG
  346. std::cout<<"SerialDevice::SetBaudRate: Error: Unable to set baud rate" <<std::endl;
  347. #endif
  348. return -1;
  349. }
  350. //set output baud rate
  351. if (cfsetospeed( &_newterm, tempBaud ) < 0 )
  352. {
  353. #ifdef SERIAL_DEVICE_DEBUG
  354. std::cout<<"SerialDevice::SetBaudRate: Error: Unable to set baud rate" <<std::endl;
  355. #endif
  356. return -1;
  357. }
  358. //set new attributes
  359. if( tcsetattr( _fd, TCSAFLUSH, &_newterm ) < 0 )
  360. {
  361. #ifdef SERIAL_DEVICE_DEBUG
  362. std::cout<<"SerialDevice::SetBaudRate: Error: Unable to set serial port attributes" <<std::endl;
  363. #endif
  364. return -1;
  365. }
  366. //make sure queue is empty
  367. tcflush(_fd, TCIOFLUSH);
  368. //save the baud rate value
  369. _baud=tempBaud;
  370. return 0;
  371. }
  372. int SerialDevice::Set_IO_BLOCK_W_TIMEOUT()
  373. {
  374. //check whether we are connected to the device
  375. if (!_connected)
  376. {
  377. #ifdef SERIAL_DEVICE_DEBUG
  378. std::cout << "SerialDevice::Set_IO_BLOCK_WO_TIMEOUT: Error: not connected to the device" << std::endl;
  379. #endif
  380. return -1;
  381. }
  382. if (_SetBlockingIO())
  383. {
  384. #ifdef SERIAL_DEVICE_DEBUG
  385. std::cout << "SerialDevice::Set_IO_BLOCK_WO_TIMEOUT: Error: could not set blocking io" << std::endl;
  386. #endif
  387. return -1;
  388. }
  389. _ioMode=IO_BLOCK_W_TIMEOUT;
  390. _delay_us=0;
  391. _numTermChars=0;
  392. _retTermSequence=false;
  393. return 0;
  394. }
  395. int SerialDevice::Set_IO_BLOCK_WO_TIMEOUT()
  396. {
  397. //check whether we are connected to the device
  398. if (!_connected)
  399. {
  400. #ifdef SERIAL_DEVICE_DEBUG
  401. std::cout << "SerialDevice::Set_IO_BLOCK_WO_TIMEOUT: Error: not connected to the device" << std::endl;
  402. #endif
  403. return -1;
  404. }
  405. if (_SetBlockingIO())
  406. {
  407. #ifdef SERIAL_DEVICE_DEBUG
  408. std::cout << "SerialDevice::Set_IO_BLOCK_WO_TIMEOUT: Error: could not set blocking io" << std::endl;
  409. #endif
  410. return -1;
  411. }
  412. _ioMode=IO_BLOCK_WO_TIMEOUT;
  413. _delay_us=0;
  414. _numTermChars=0;
  415. _retTermSequence=false;
  416. return 0;
  417. }
  418. int SerialDevice::Set_IO_BLOCK_W_TIMEOUT_W_TERM_SEQUENCE(const char * termSequence, int numTermChars, bool retTermSequence)
  419. {
  420. //check whether we are connected to the device
  421. if (!_connected)
  422. {
  423. #ifdef SERIAL_DEVICE_DEBUG
  424. std::cout << "SerialDevice::Set_IO_BLOCK_W_TIMEOUT_W_TERM_SEQUENCE: Error: not connected to the device" << std::endl;
  425. #endif
  426. return -1;
  427. }
  428. if (_SetBlockingIO())
  429. {
  430. #ifdef SERIAL_DEVICE_DEBUG
  431. std::cout << "SerialDevice::Set_IO_BLOCK_W_TIMEOUT_W_TERM_SEQUENCE: Error: could not set blocking io" << std::endl;
  432. #endif
  433. return -1;
  434. }
  435. if (numTermChars < 1 || numTermChars > MAX_NUM_TERM_CHARS)
  436. {
  437. std::cout<<" IOMode::Set_IO_BLOCK_W_TIMEOUT_W_TERM_SEQUENCE: ERROR: bad number of chars: " <<numTermChars<<std::endl;
  438. return -1;
  439. }
  440. _ioMode=IO_BLOCK_W_TIMEOUT_W_TERM_SEQUENCE;
  441. _numTermChars=numTermChars;
  442. _retTermSequence=retTermSequence;
  443. memcpy(_termSequence,termSequence, numTermChars*sizeof(char));
  444. _delay_us=0;
  445. return 0;
  446. }
  447. int SerialDevice::Set_IO_NONBLOCK_WO_TIMEOUT()
  448. {
  449. //check whether we are connected to the device
  450. if (!_connected)
  451. {
  452. #ifdef SERIAL_DEVICE_DEBUG
  453. std::cout << "SerialDevice::Set_IO_NONBLOCK_WO_TIMEOUT: Error: not connected to the device" << std::endl;
  454. #endif
  455. return -1;
  456. }
  457. if (_SetNonBlockingIO())
  458. {
  459. #ifdef SERIAL_DEVICE_DEBUG
  460. std::cout << "SerialDevice::Set_IO_NONBLOCK_WO_TIMEOUT: Error: could not set non-blocking io" << std::endl;
  461. #endif
  462. return -1;
  463. }
  464. _ioMode=IO_NONBLOCK_WO_TIMEOUT;
  465. _delay_us=0;
  466. _numTermChars=0;
  467. _retTermSequence=false;
  468. return 0;
  469. }
  470. int SerialDevice::Set_IO_NONBLOCK_POLL_W_DELAY_W_TIMEOUT(int delay_us)
  471. {
  472. //check whether we are connected to the device
  473. if (!_connected)
  474. {
  475. #ifdef SERIAL_DEVICE_DEBUG
  476. std::cout << "SerialDevice::Set_IO_NONBLOCK_POLL_W_DELAY_W_TIMEOUT: Error: not connected to the device" << std::endl;
  477. #endif
  478. return -1;
  479. }
  480. if (_SetNonBlockingIO())
  481. {
  482. #ifdef SERIAL_DEVICE_DEBUG
  483. std::cout << "SerialDevice::Set_IO_NONBLOCK_POLL_W_DELAY_W_TIMEOUT: Error: could not set non-blocking io" << std::endl;
  484. #endif
  485. return -1;
  486. }
  487. _ioMode=IO_NONBLOCK_POLL_W_DELAY_W_TIMEOUT;
  488. _delay_us=delay_us;
  489. _numTermChars=0;
  490. _retTermSequence=false;
  491. return 0;
  492. }
  493. //set blocking terminal mode
  494. int SerialDevice::_SetBlockingIO()
  495. {
  496. //check whether we are connected to the device
  497. if (!_connected)
  498. {
  499. #ifdef SERIAL_DEVICE_DEBUG
  500. std::cout << "SerialDevice::SetBlockingIO: Error: not connected to the device" << std::endl;
  501. #endif
  502. return -1;
  503. }
  504. //only set blocking if not already set
  505. if (_block != 1)
  506. {
  507. // Read the flags
  508. int flags;
  509. if((flags = fcntl(_fd,F_GETFL)) < 0)
  510. {
  511. #ifdef SERIAL_DEVICE_DEBUG
  512. std::cout << "SerialDevice::_setBlockingIO: unable to get device flags" << std::endl;
  513. #endif
  514. return -1;
  515. }
  516. // Set the new flags
  517. if(fcntl(_fd,F_SETFL,flags & (~O_NONBLOCK)) < 0)
  518. {
  519. #ifdef SERIAL_DEVICE_DEBUG
  520. std::cout << "SerialDevice::_setBlockingIO: unable to set device flags" << std::endl;
  521. #endif
  522. return -1;
  523. }
  524. _block=1;
  525. }
  526. return 0;
  527. }
  528. //set non-blocking terminal mode
  529. int SerialDevice::_SetNonBlockingIO()
  530. {
  531. //check whether we are connected to the device
  532. if (!_connected)
  533. {
  534. #ifdef SERIAL_DEVICE_DEBUG
  535. std::cout << "SerialDevice::SetNonBlockingIO: Error: not connected to the device" << std::endl;
  536. #endif
  537. return -1;
  538. }
  539. //only set non-blocking if not already set
  540. if (_block != 0)
  541. {
  542. // Read the flags
  543. int flags;
  544. if((flags = fcntl(_fd,F_GETFL)) < 0)
  545. {
  546. #ifdef SERIAL_DEVICE_DEBUG
  547. std::cout << "SerialDevice::_setNonBlockingIO failed! - unable to retrieve device flags" << std::endl;
  548. #endif
  549. return -1;
  550. }
  551. // Set the new flags
  552. if(fcntl(_fd,F_SETFL,flags | O_NONBLOCK) < 0)
  553. {
  554. #ifdef SERIAL_DEVICE_DEBUG
  555. std::cout << "SerialDevice::_setNonBlockingIO failed! - unable to set device flags" << std::endl;
  556. #endif
  557. return -1;
  558. }
  559. _block=0;
  560. }
  561. return 0;
  562. }
  563. //delete all the data in the input buffer
  564. int SerialDevice::FlushInputBuffer()
  565. {
  566. char c[1000];
  567. //check whether we are connected to the device
  568. if (!_connected)
  569. {
  570. #ifdef SERIAL_DEVICE_DEBUG
  571. std::cout << "SerialDevice::FlushInputBuffer: Error: not connected to the device" << std::endl;
  572. #endif
  573. return -1;
  574. }
  575. //TODO tcflush for some reason does not work..
  576. //tcflush(_fd, TCIFLUSH);
  577. int block=_block;
  578. _SetNonBlockingIO();
  579. //read off all the chars
  580. while (read(_fd,c,1000) > 0){}
  581. if (block==1)
  582. {
  583. _SetBlockingIO();
  584. }
  585. return 0;
  586. }
  587. //read characters from device
  588. int SerialDevice::ReadChars(char * data, int byte_count, int timeout_us)
  589. {
  590. //check whether we are connected to the device
  591. if (!_connected)
  592. {
  593. #ifdef SERIAL_DEVICE_DEBUG
  594. std::cout << "SerialDevice::ReadChars: Error: not connected to the device" << std::endl;
  595. #endif
  596. return -1;
  597. }
  598. //TODO: tcp behaves strangely when connection is closed. The check below does not work
  599. /*
  600. struct stat fd_info;
  601. if (fstat(_fd,&fd_info) != 0 )
  602. {
  603. #ifdef SERIAL_DEVICE_DEBUG
  604. std::cout << "SerialDevice::ReadChars: Error: file descriptor is not valid" << std::endl;
  605. #endif
  606. return -1;
  607. }
  608. */
  609. fd_set watched_fds;
  610. struct timeval timeout, start, end;
  611. int bytes_read_total = 0;
  612. int bytes_left = byte_count;
  613. int retval;
  614. int bytes_read;
  615. int charsMatched=0;
  616. switch (_ioMode)
  617. {
  618. case IO_BLOCK_W_TIMEOUT:
  619. //set up for the "select" call
  620. FD_ZERO(&watched_fds);
  621. FD_SET(_fd, &watched_fds);
  622. timeout.tv_sec = timeout_us / 1000000;
  623. timeout.tv_usec = timeout_us % 1000000;
  624. while (bytes_left)
  625. {
  626. if ((retval = select(_fd + 1, &watched_fds, NULL, NULL, &timeout)) < 1) //block until at least 1 char is available or timeout
  627. { //error reading chars
  628. if (retval < 0)
  629. {
  630. #ifdef SERIAL_DEVICE_DEBUG
  631. perror("SerialDevice::ReadChars");
  632. #endif
  633. }
  634. else //timeout
  635. {
  636. #ifdef SERIAL_DEVICE_DEBUG
  637. std::cout << "SerialDevice::ReadChars: Error: timeout. #chars read= "<<bytes_read_total <<", requested= "<< byte_count << std::endl;
  638. #endif
  639. }
  640. return bytes_read_total;
  641. }
  642. bytes_read = read(_fd, &(data[bytes_read_total]), bytes_left);
  643. if (bytes_read > 0)
  644. {
  645. bytes_read_total += bytes_read;
  646. bytes_left -= bytes_read;
  647. }
  648. }
  649. return bytes_read_total;
  650. case IO_NONBLOCK_POLL_W_DELAY_W_TIMEOUT:
  651. gettimeofday(&start,NULL);
  652. while (bytes_left)
  653. {
  654. bytes_read = read(_fd,&(data[bytes_read_total]),bytes_left);
  655. if ( bytes_read < 1)
  656. {
  657. // If a time out then return false
  658. gettimeofday(&end,NULL);
  659. if((end.tv_sec*1000000 + end.tv_usec) - (start.tv_sec*1000000 + start.tv_usec) > timeout_us)
  660. {
  661. #ifdef SERIAL_DEVICE_DEBUG
  662. std::cout << "SerialDevice::ReadChars: Error: timeout. #chars read= "<<bytes_read_total <<", requested= "<< byte_count << std::endl;
  663. #endif
  664. return bytes_read_total;
  665. }
  666. usleep(_delay_us);
  667. continue;
  668. }
  669. bytes_read_total += bytes_read;
  670. bytes_left -= bytes_read;
  671. }
  672. return bytes_read_total;
  673. case IO_BLOCK_WO_TIMEOUT:
  674. while (bytes_left)
  675. {
  676. bytes_read = read(_fd,&(data[bytes_read_total]),bytes_left);
  677. if (bytes_read < 1)
  678. {
  679. return -1;
  680. }
  681. bytes_read_total += bytes_read;
  682. bytes_left -= bytes_read;
  683. }
  684. return bytes_read_total;
  685. case IO_NONBLOCK_WO_TIMEOUT:
  686. bytes_read = read(_fd,&(data[0]),bytes_left);
  687. if (bytes_read < 0) bytes_read=0;
  688. return bytes_read;
  689. case IO_BLOCK_W_TIMEOUT_W_TERM_SEQUENCE:
  690. //set up for the "select" call
  691. FD_ZERO(&watched_fds);
  692. FD_SET(_fd, &watched_fds);
  693. timeout.tv_sec = timeout_us / 1000000;
  694. timeout.tv_usec = timeout_us % 1000000;
  695. while (bytes_left) {
  696. if ((retval = select(_fd + 1, &watched_fds, NULL, NULL, &timeout)) < 1) //block until at least 1 char is available or timeout
  697. { //error reading chars
  698. if (retval < 0)
  699. {
  700. #ifdef SERIAL_DEVICE_DEBUG
  701. perror("SerialDevice::ReadChars");
  702. #endif
  703. }
  704. else //timeout
  705. {
  706. #ifdef SERIAL_DEVICE_DEBUG
  707. std::cout << "SerialDevice::ReadChars: Error: timeout. The terminating sequence has not been read"<< std::endl;
  708. #endif
  709. }
  710. return -1;
  711. }
  712. bytes_read = read(_fd, &(data[bytes_read_total]), 1);
  713. if (bytes_read==1)
  714. {
  715. if (data[bytes_read_total]==_termSequence[charsMatched])
  716. {
  717. charsMatched++;
  718. }
  719. else
  720. {
  721. charsMatched=0;
  722. }
  723. //std::cout<<data[bytes_read_total];
  724. bytes_read_total += bytes_read;
  725. bytes_left -= bytes_read;
  726. if (charsMatched==_numTermChars)
  727. {
  728. if (_retTermSequence)
  729. {
  730. return bytes_read_total;
  731. }
  732. else
  733. {
  734. return bytes_read_total-_numTermChars;
  735. }
  736. }
  737. }
  738. }
  739. #ifdef SERIAL_DEVICE_DEBUG
  740. std::cout << "SerialDevice::ReadChars: Error: Read too much data. The terminating sequence has not been read"<< std::endl;
  741. #endif
  742. return -1;
  743. default:
  744. #ifdef SERIAL_DEVICE_DEBUG
  745. std::cout << "SerialDevice::ReadChars: Error: Bad io mode " << std::endl;
  746. #endif
  747. return -1;
  748. }
  749. }
  750. int SerialDevice::WriteChars(const char * data, int byte_count, int delay_us)
  751. {
  752. int bytes_written_total=0;
  753. int bytes_written;
  754. int bytes_left=byte_count;
  755. //check whether we are connected to the device
  756. if (!_connected)
  757. {
  758. #ifdef SERIAL_DEVICE_DEBUG
  759. std::cout << "SerialDevice::ReadChars: Error: not connected to the device" << std::endl;
  760. #endif
  761. return -1;
  762. }
  763. if (delay_us==0)
  764. {
  765. bytes_written_total=write(_fd,data,byte_count);
  766. }
  767. else
  768. {
  769. while (bytes_left)
  770. {
  771. bytes_written=write(_fd,&(data[bytes_written_total]),1);
  772. if (bytes_written < 0)
  773. {
  774. #ifdef SERIAL_DEVICE_DEBUG
  775. perror("SerialDevice::ReadChars");
  776. #endif
  777. }
  778. if (bytes_written < 1)
  779. {
  780. #ifdef SERIAL_DEVICE_DEBUG
  781. std::cout << "SerialDevice::WriteChars: Error: Could not write a char. #chars written= "<<bytes_written_total <<", requested= "<< byte_count << std::endl;
  782. #endif
  783. return bytes_written_total;
  784. }
  785. bytes_written_total += bytes_written;
  786. bytes_left -= bytes_written;
  787. usleep(delay_us);
  788. }
  789. }
  790. tcdrain(_fd); //wait till all the data written to the file descriptor is transmitted
  791. return bytes_written_total;
  792. }
  793. double SerialDevice::GetLastInputPacketTime()
  794. {
  795. return 0;
  796. }