MRPT  1.9.9
linux/net_serial.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 /*
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright notice,
14  * this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright notice,
17  * this list of conditions and the following disclaimer in the documentation
18  * and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
33 
34 #include "arch/linux/arch_linux.h"
35 #include "arch/linux/net_serial.h"
36 #include <termios.h>
37 #include <sys/select.h>
38 
39 namespace rp
40 {
41 namespace arch
42 {
43 namespace net
44 {
46  : rp::hal::serial_rxtx(), _baudrate(0), _flags(0), serial_fd(-1)
47 {
48  _init();
49 }
50 
53 bool raw_serial::bind(const char* portname, uint32_t baudrate, uint32_t flags)
54 {
55  strncpy(_portName, portname, sizeof(_portName));
56  _baudrate = baudrate;
57  _flags = flags;
58  return true;
59 }
60 
61 bool raw_serial::open(const char* portname, uint32_t baudrate, uint32_t flags)
62 {
63  if (isOpened()) close();
64 
65  serial_fd = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
66 
67  if (serial_fd == -1) return false;
68 
69  struct termios options, oldopt;
70  tcgetattr(serial_fd, &oldopt);
71  bzero(&options, sizeof(struct termios));
72 
73  _u32 termbaud = getTermBaudBitmap(baudrate);
74 
75  if (termbaud == (_u32)-1)
76  {
77  close();
78  return false;
79  }
80  cfsetispeed(&options, termbaud);
81  cfsetospeed(&options, termbaud);
82 
83  // enable rx and tx
84  options.c_cflag |= (CLOCAL | CREAD);
85 
86  options.c_cflag &= ~PARENB; // no checkbit
87  options.c_cflag &= ~CSTOPB; // 1bit stop bit
88 
89  options.c_cflag &= ~CSIZE;
90  options.c_cflag |= CS8; /* Select 8 data bits */
91 
92 #ifdef CNEW_RTSCTS
93  options.c_cflag &= ~CNEW_RTSCTS; // no hw flow control
94 #endif
95 
96  options.c_iflag &= ~(IXON | IXOFF | IXANY); // no sw flow control
97 
98  // raw input mode
99  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
100  // raw output mode
101  options.c_oflag &= ~OPOST;
102 
103  tcflush(serial_fd, TCIFLUSH);
104 
105  if (fcntl(serial_fd, F_SETFL, FNDELAY))
106  {
107  close();
108  return false;
109  }
110  if (tcsetattr(serial_fd, TCSANOW, &options))
111  {
112  close();
113  return false;
114  }
115 
116  _is_serial_opened = true;
117 
118  // Clear the DTR bit to let the motor spin
119  clearDTR();
120 
121  return true;
122 }
123 
125 {
126  if (serial_fd != -1) ::close(serial_fd);
127  serial_fd = -1;
128 
129  _is_serial_opened = false;
130 }
131 
132 int raw_serial::senddata(const unsigned char* data, size_t size)
133 {
134  // FIXME: non-block io should be used
135  if (!isOpened()) return 0;
136 
137  if (data == nullptr || size == 0) return 0;
138 
139  size_t tx_len = 0;
140  required_tx_cnt = 0;
141  do
142  {
143  int ans = ::write(serial_fd, data + tx_len, size - tx_len);
144 
145  if (ans == -1) return tx_len;
146 
147  tx_len += ans;
148  required_tx_cnt = tx_len;
149  } while (tx_len < size);
150 
151  return tx_len;
152 }
153 
154 int raw_serial::recvdata(unsigned char* data, size_t size)
155 {
156  if (!isOpened()) return 0;
157 
158  int ans = ::read(serial_fd, data, size);
159 
160  if (ans == -1) ans = 0;
161  required_rx_cnt = ans;
162  return ans;
163 }
164 
165 void raw_serial::flush(_u32 flags) { tcflush(serial_fd, TCIFLUSH); }
166 int raw_serial::waitforsent(_u32 timeout, size_t* returned_size)
167 {
168  if (returned_size) *returned_size = required_tx_cnt;
169  return 0;
170 }
171 
172 int raw_serial::waitforrecv(_u32 timeout, size_t* returned_size)
173 {
174  if (!isOpened()) return -1;
175 
176  if (returned_size) *returned_size = required_rx_cnt;
177  return 0;
178 }
179 
181  size_t data_count, _u32 timeout, size_t* returned_size)
182 {
183  size_t length = 0;
184  if (returned_size == nullptr) returned_size = (size_t*)&length;
185  *returned_size = 0;
186 
187  int max_fd;
188  fd_set input_set;
189  struct timeval timeout_val;
190 
191  /* Initialize the input set */
192  FD_ZERO(&input_set);
193  FD_SET(serial_fd, &input_set);
194  max_fd = serial_fd + 1;
195 
196  /* Initialize the timeout structure */
197  timeout_val.tv_sec = timeout / 1000;
198  timeout_val.tv_usec = (timeout % 1000) * 1000;
199 
200  if (isOpened())
201  {
202  if (ioctl(serial_fd, FIONREAD, returned_size) == -1) return ANS_DEV_ERR;
203  if (*returned_size >= data_count)
204  {
205  return 0;
206  }
207  }
208 
209  while (isOpened())
210  {
211  /* Do the select */
212  int n = ::select(max_fd, &input_set, nullptr, nullptr, &timeout_val);
213 
214  if (n < 0)
215  {
216  // select error
217  return ANS_DEV_ERR;
218  }
219  else if (n == 0)
220  {
221  // time out
222  return ANS_TIMEOUT;
223  }
224  else
225  {
226  // data avaliable
227  assert(FD_ISSET(serial_fd, &input_set));
228 
229  if (ioctl(serial_fd, FIONREAD, returned_size) == -1)
230  return ANS_DEV_ERR;
231  if (*returned_size >= data_count)
232  {
233  return 0;
234  }
235  else
236  {
237  int remain_timeout =
238  timeout_val.tv_sec * 1000000 + timeout_val.tv_usec;
239  int expect_remain_time =
240  (data_count - *returned_size) * 1000000 * 8 / _baudrate;
241  if (remain_timeout > expect_remain_time)
242  usleep(expect_remain_time);
243  }
244  }
245  }
246 
247  return ANS_DEV_ERR;
248 }
249 
251 {
252  if (!isOpened()) return 0;
253  size_t remaining;
254 
255  if (::ioctl(serial_fd, FIONREAD, &remaining) == -1) return 0;
256  return remaining;
257 }
258 
260 {
261  if (!isOpened()) return;
262 
263  uint32_t dtr_bit = TIOCM_DTR;
264  ioctl(serial_fd, TIOCMBIS, &dtr_bit);
265 }
266 
268 {
269  if (!isOpened()) return;
270 
271  uint32_t dtr_bit = TIOCM_DTR;
272  ioctl(serial_fd, TIOCMBIC, &dtr_bit);
273 }
274 
276 {
277  serial_fd = 0;
278  _portName[0] = 0;
280 }
281 
283 {
284 #define BAUD_CONV(_baud_) \
285  case _baud_: \
286  return B##_baud_
287  switch (baud)
288  {
289  BAUD_CONV(1200);
290  BAUD_CONV(1800);
291  BAUD_CONV(2400);
292  BAUD_CONV(4800);
293  BAUD_CONV(9600);
294  BAUD_CONV(19200);
295  BAUD_CONV(38400);
296  BAUD_CONV(57600);
297  BAUD_CONV(115200);
298  BAUD_CONV(230400);
299  BAUD_CONV(460800);
300  BAUD_CONV(500000);
301  BAUD_CONV(576000);
302  BAUD_CONV(921600);
303  BAUD_CONV(1000000);
304  BAUD_CONV(1152000);
305  BAUD_CONV(1500000);
306  BAUD_CONV(2000000);
307  }
308  return -1;
309 }
310 }
311 }
312 } // end rp::arch::net
313 
314 // begin rp::hal
315 namespace rp
316 {
317 namespace hal
318 {
320 {
321  return new rp::arch::net::raw_serial();
322 }
323 
324 void serial_rxtx::ReleaseRxTx(serial_rxtx* rxtx) { delete rxtx; }
325 }
326 } // end rp::hal
virtual void flush(_u32 flags)
virtual bool isOpened()
Definition: abs_rxtx.h:78
GLenum GLsizei n
Definition: glext.h:5074
#define BAUD_CONV(_baud_)
static serial_rxtx * CreateRxTx()
static void ReleaseRxTx(serial_rxtx *)
volatile bool _is_serial_opened
Definition: abs_rxtx.h:80
virtual bool bind(const char *portname, uint32_t baudrate, uint32_t flags=0)
virtual int senddata(const unsigned char *data, size_t size)
virtual int waitfordata(size_t data_count, _u32 timeout=-1, size_t *returned_size=nullptr)
virtual int recvdata(unsigned char *data, size_t size)
virtual int waitforsent(_u32 timeout=-1, size_t *returned_size=nullptr)
GLuint GLsizei GLsizei * length
Definition: glext.h:4064
uint32_t _u32
Definition: rptypes.h:66
virtual int waitforrecv(_u32 timeout=-1, size_t *returned_size=nullptr)
GLsizeiptr size
Definition: glext.h:3923
unsigned __int32 uint32_t
Definition: rptypes.h:47
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3546



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 7d5e6d718 Fri Aug 24 01:51:28 2018 +0200 at lun nov 2 08:35:50 CET 2020