MRPT  1.9.9
linux/net_serial.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://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/net_serial.h"
35 #include <sys/select.h>
36 #include <termios.h>
37 #include "arch/linux/arch_linux.h"
38 
39 namespace rp
40 {
41 namespace arch
42 {
43 namespace net
44 {
45 raw_serial::raw_serial() : rp::hal::serial_rxtx() { _init(); }
48 bool raw_serial::bind(const char* portname, uint32_t baudrate, uint32_t flags)
49 {
50  strncpy(_portName, portname, sizeof(_portName));
51  _baudrate = baudrate;
52  _flags = flags;
53  return true;
54 }
55 
56 bool raw_serial::open(const char* portname, uint32_t baudrate, uint32_t flags)
57 {
58  if (isOpened()) close();
59 
60  serial_fd = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
61 
62  if (serial_fd == -1) return false;
63 
64  struct termios options, oldopt;
65  tcgetattr(serial_fd, &oldopt);
66  bzero(&options, sizeof(struct termios));
67 
68  _u32 termbaud = getTermBaudBitmap(baudrate);
69 
70  if (termbaud == (_u32)-1)
71  {
72  close();
73  return false;
74  }
75  cfsetispeed(&options, termbaud);
76  cfsetospeed(&options, termbaud);
77 
78  // enable rx and tx
79  options.c_cflag |= (CLOCAL | CREAD);
80 
81  options.c_cflag &= ~PARENB; // no checkbit
82  options.c_cflag &= ~CSTOPB; // 1bit stop bit
83 
84  options.c_cflag &= ~CSIZE;
85  options.c_cflag |= CS8; /* Select 8 data bits */
86 
87 #ifdef CNEW_RTSCTS
88  options.c_cflag &= ~CNEW_RTSCTS; // no hw flow control
89 #endif
90 
91  options.c_iflag &= ~(IXON | IXOFF | IXANY); // no sw flow control
92 
93  // raw input mode
94  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
95  // raw output mode
96  options.c_oflag &= ~OPOST;
97 
98  tcflush(serial_fd, TCIFLUSH);
99 
100  if (fcntl(serial_fd, F_SETFL, FNDELAY))
101  {
102  close();
103  return false;
104  }
105  if (tcsetattr(serial_fd, TCSANOW, &options))
106  {
107  close();
108  return false;
109  }
110 
111  _is_serial_opened = true;
112 
113  // Clear the DTR bit to let the motor spin
114  clearDTR();
115 
116  return true;
117 }
118 
120 {
121  if (serial_fd != -1) ::close(serial_fd);
122  serial_fd = -1;
123 
124  _is_serial_opened = false;
125 }
126 
127 int raw_serial::senddata(const unsigned char* data, size_t size)
128 {
129  // FIXME: non-block io should be used
130  if (!isOpened()) return 0;
131 
132  if (data == nullptr || size == 0) return 0;
133 
134  size_t tx_len = 0;
135  required_tx_cnt = 0;
136  do
137  {
138  int ans = ::write(serial_fd, data + tx_len, size - tx_len);
139 
140  if (ans == -1) return tx_len;
141 
142  tx_len += ans;
143  required_tx_cnt = tx_len;
144  } while (tx_len < size);
145 
146  return tx_len;
147 }
148 
149 int raw_serial::recvdata(unsigned char* data, size_t size)
150 {
151  if (!isOpened()) return 0;
152 
153  int ans = ::read(serial_fd, data, size);
154 
155  if (ans == -1) ans = 0;
156  required_rx_cnt = ans;
157  return ans;
158 }
159 
160 void raw_serial::flush(_u32 flags) { tcflush(serial_fd, TCIFLUSH); }
161 int raw_serial::waitforsent(_u32 timeout, size_t* returned_size)
162 {
163  if (returned_size) *returned_size = required_tx_cnt;
164  return 0;
165 }
166 
167 int raw_serial::waitforrecv(_u32 timeout, size_t* returned_size)
168 {
169  if (!isOpened()) return -1;
170 
171  if (returned_size) *returned_size = required_rx_cnt;
172  return 0;
173 }
174 
176  size_t data_count, _u32 timeout, size_t* returned_size)
177 {
178  size_t length = 0;
179  if (returned_size == nullptr) returned_size = (size_t*)&length;
180  *returned_size = 0;
181 
182  int max_fd;
183  fd_set input_set;
184  struct timeval timeout_val;
185 
186  /* Initialize the input set */
187  FD_ZERO(&input_set);
188  FD_SET(serial_fd, &input_set);
189  max_fd = serial_fd + 1;
190 
191  /* Initialize the timeout structure */
192  timeout_val.tv_sec = timeout / 1000;
193  timeout_val.tv_usec = (timeout % 1000) * 1000;
194 
195  if (isOpened())
196  {
197  if (ioctl(serial_fd, FIONREAD, returned_size) == -1) return ANS_DEV_ERR;
198  if (*returned_size >= data_count)
199  {
200  return 0;
201  }
202  }
203 
204  while (isOpened())
205  {
206  /* Do the select */
207  int n = ::select(max_fd, &input_set, nullptr, nullptr, &timeout_val);
208 
209  if (n < 0)
210  {
211  // select error
212  return ANS_DEV_ERR;
213  }
214  else if (n == 0)
215  {
216  // time out
217  return ANS_TIMEOUT;
218  }
219  else
220  {
221  // data avaliable
222  assert(FD_ISSET(serial_fd, &input_set));
223 
224  if (ioctl(serial_fd, FIONREAD, returned_size) == -1)
225  return ANS_DEV_ERR;
226  if (*returned_size >= data_count)
227  {
228  return 0;
229  }
230  else
231  {
232  int remain_timeout =
233  timeout_val.tv_sec * 1000000 + timeout_val.tv_usec;
234  int expect_remain_time =
235  (data_count - *returned_size) * 1000000 * 8 / _baudrate;
236  if (remain_timeout > expect_remain_time)
237  usleep(expect_remain_time);
238  }
239  }
240  }
241 
242  return ANS_DEV_ERR;
243 }
244 
246 {
247  if (!isOpened()) return 0;
248  size_t remaining;
249 
250  if (::ioctl(serial_fd, FIONREAD, &remaining) == -1) return 0;
251  return remaining;
252 }
253 
255 {
256  if (!isOpened()) return;
257 
258  uint32_t dtr_bit = TIOCM_DTR;
259  ioctl(serial_fd, TIOCMBIS, &dtr_bit);
260 }
261 
263 {
264  if (!isOpened()) return;
265 
266  uint32_t dtr_bit = TIOCM_DTR;
267  ioctl(serial_fd, TIOCMBIC, &dtr_bit);
268 }
269 
271 {
272  serial_fd = 0;
273  _portName[0] = 0;
275 }
276 
278 {
279 #define BAUD_CONV(_baud_) \
280  case _baud_: \
281  return B##_baud_
282  switch (baud)
283  {
284  BAUD_CONV(1200);
285  BAUD_CONV(1800);
286  BAUD_CONV(2400);
287  BAUD_CONV(4800);
288  BAUD_CONV(9600);
289  BAUD_CONV(19200);
290  BAUD_CONV(38400);
291  BAUD_CONV(57600);
292  BAUD_CONV(115200);
293  BAUD_CONV(230400);
294  BAUD_CONV(460800);
295  BAUD_CONV(500000);
296  BAUD_CONV(576000);
297  BAUD_CONV(921600);
298  BAUD_CONV(1000000);
299  BAUD_CONV(1152000);
300  BAUD_CONV(1500000);
301  BAUD_CONV(2000000);
302  }
303  return -1;
304 }
305 } // namespace net
306 } // namespace arch
307 } // namespace rp
308 
309 // begin rp::hal
310 namespace rp
311 {
312 namespace hal
313 {
315 {
316  return new rp::arch::net::raw_serial();
317 }
318 
319 void serial_rxtx::ReleaseRxTx(serial_rxtx* rxtx) { delete rxtx; }
320 } // namespace hal
321 } // namespace rp
size_t rxqueue_count() override
virtual bool isOpened()
Definition: abs_rxtx.h:78
GLenum GLsizei n
Definition: glext.h:5136
bool bind(const char *portname, uint32_t baudrate, uint32_t flags=0) override
#define BAUD_CONV(_baud_)
static serial_rxtx * CreateRxTx()
static void ReleaseRxTx(serial_rxtx *)
volatile bool _is_serial_opened
Definition: abs_rxtx.h:81
int waitforsent(_u32 timeout=-1, size_t *returned_size=nullptr) override
int waitfordata(size_t data_count, _u32 timeout=-1, size_t *returned_size=nullptr) override
int senddata(const unsigned char *data, size_t size) override
void flush(_u32 flags) override
GLuint GLsizei GLsizei * length
Definition: glext.h:4079
uint32_t _u32
Definition: rptypes.h:69
int waitforrecv(_u32 timeout=-1, size_t *returned_size=nullptr) override
GLsizeiptr size
Definition: glext.h:3934
unsigned __int32 uint32_t
Definition: rptypes.h:50
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3550
int recvdata(unsigned char *data, size_t size) override



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 8fe78517f Sun Jul 14 19:43:28 2019 +0200 at lun oct 28 02:10:00 CET 2019