MRPT  1.9.9
macOS/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/macOS/net_serial.h"
35 #include <sys/select.h>
36 #include <termios.h>
37 #include "arch/macOS/arch_macOS.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 
51 raw_serial::~raw_serial() { close(); }
52 bool raw_serial::open() { return open(_portName, _baudrate, _flags); }
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  */
111  if (tcsetattr(serial_fd, TCSANOW, &options))
112  {
113  close();
114  return false;
115  }
116 
117  _is_serial_opened = true;
118 
119  // Clear the DTR bit to let the motor spin
120  clearDTR();
121 
122  return true;
123 }
124 
125 void raw_serial::close()
126 {
127  if (serial_fd != -1) ::close(serial_fd);
128  serial_fd = -1;
129 
130  _is_serial_opened = false;
131 }
132 
133 int raw_serial::senddata(const unsigned char* data, _word_size_t size)
134 {
135  // FIXME: non-block io should be used
136  if (!isOpened()) return 0;
137 
138  if (data == nullptr || size == 0) return 0;
139 
140  size_t tx_len = 0;
141  required_tx_cnt = 0;
142  do
143  {
144  int ans = ::write(serial_fd, data + tx_len, size - tx_len);
145 
146  if (ans == -1) return tx_len;
147 
148  tx_len += ans;
149  required_tx_cnt = tx_len;
150  } while (tx_len < size);
151 
152  return tx_len;
153 }
154 
155 int raw_serial::recvdata(unsigned char* data, _word_size_t size)
156 {
157  if (!isOpened()) return 0;
158 
159  int ans = ::read(serial_fd, data, size);
160 
161  if (ans == -1) ans = 0;
162  required_rx_cnt = ans;
163  return ans;
164 }
165 
166 void raw_serial::flush(_u32 flags) { tcflush(serial_fd, TCIFLUSH); }
167 int raw_serial::waitforsent(_u32 timeout, _word_size_t* returned_size)
168 {
169  if (returned_size) *returned_size = required_tx_cnt;
170  return 0;
171 }
172 
173 int raw_serial::waitforrecv(_u32 timeout, _word_size_t* returned_size)
174 {
175  if (!isOpened()) return -1;
176 
177  if (returned_size) *returned_size = required_rx_cnt;
178  return 0;
179 }
180 
181 int raw_serial::waitfordata(
182  _word_size_t data_count, _u32 timeout, _word_size_t* returned_size)
183 {
184  _word_size_t length = 0;
185  if (returned_size == nullptr) returned_size = (_word_size_t*)&length;
186  *returned_size = 0;
187 
188  int max_fd;
189  fd_set input_set;
190  struct timeval timeout_val;
191 
192  /* Initialize the input set */
193  FD_ZERO(&input_set);
194  FD_SET(serial_fd, &input_set);
195  max_fd = serial_fd + 1;
196 
197  /* Initialize the timeout structure */
198  timeout_val.tv_sec = timeout / 1000;
199  timeout_val.tv_usec = (timeout % 1000) * 1000;
200 
201  if (isOpened())
202  {
203  if (ioctl(serial_fd, FIONREAD, returned_size) == -1) return ANS_DEV_ERR;
204  if (*returned_size >= data_count)
205  {
206  return 0;
207  }
208  }
209 
210  while (isOpened())
211  {
212  /* Do the select */
213  int n = ::select(max_fd, &input_set, nullptr, nullptr, &timeout_val);
214 
215  if (n < 0)
216  {
217  // select error
218  return ANS_DEV_ERR;
219  }
220  else if (n == 0)
221  {
222  // time out
223  return ANS_TIMEOUT;
224  }
225  else
226  {
227  // data avaliable
228  assert(FD_ISSET(serial_fd, &input_set));
229 
230  if (ioctl(serial_fd, FIONREAD, returned_size) == -1)
231  return ANS_DEV_ERR;
232  if (*returned_size >= data_count)
233  {
234  return 0;
235  }
236  else
237  {
238  int remain_timeout =
239  timeout_val.tv_sec * 1000000 + timeout_val.tv_usec;
240  int expect_remain_time =
241  (data_count - *returned_size) * 1000000 * 8 / _baudrate;
242  if (remain_timeout > expect_remain_time)
243  usleep(expect_remain_time);
244  }
245  }
246  }
247  return ANS_DEV_ERR;
248 }
249 
250 size_t raw_serial::rxqueue_count()
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 
259 void raw_serial::setDTR()
260 {
261  if (!isOpened()) return;
262 
263  uint32_t dtr_bit = TIOCM_DTR;
264  ioctl(serial_fd, TIOCMBIS, &dtr_bit);
265 }
266 
267 void raw_serial::clearDTR()
268 {
269  if (!isOpened()) return;
270 
271  uint32_t dtr_bit = TIOCM_DTR;
272  ioctl(serial_fd, TIOCMBIC, &dtr_bit);
273 }
274 
275 void raw_serial::_init()
276 {
277  serial_fd = 0;
278  _portName[0] = 0;
279  required_tx_cnt = required_rx_cnt = 0;
280 }
281 
282 _u32 raw_serial::getTermBaudBitmap(_u32 baud)
283 {
284 #define BAUD_CONV(_baud_) \
285  case _baud_: \
286  return _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  BAUD_CONV(2500000);
308  BAUD_CONV(3000000);
309  BAUD_CONV(3500000);
310  BAUD_CONV(4000000);
311  }
312  return -1;
313 }
314 } // namespace net
315 } // namespace arch
316 } // namespace rp
317 
318 // begin rp::hal
319 namespace rp
320 {
321 namespace hal
322 {
323 serial_rxtx* serial_rxtx::CreateRxTx()
324 {
325  return new rp::arch::net::raw_serial();
326 }
327 
328 void serial_rxtx::ReleaseRxTx(serial_rxtx* rxtx) { delete rxtx; }
329 } // namespace hal
330 } // namespace rp
GLenum GLsizei n
Definition: glext.h:5136
#define BAUD_CONV(_baud_)
static serial_rxtx * CreateRxTx()
static void ReleaseRxTx(serial_rxtx *)
GLuint GLsizei GLsizei * length
Definition: glext.h:4079
uint32_t _u32
Definition: rptypes.h:69
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



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