Apollo 10.0
自动驾驶开放平台
serial_stream.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2017 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
17#include <fcntl.h>
18#include <linux/netlink.h>
19#include <linux/serial.h>
20#include <sys/ioctl.h>
21#include <sys/select.h>
22#include <sys/socket.h>
23#include <sys/time.h>
24#include <termios.h>
25#include <unistd.h>
26#include <cerrno>
27#include <cstring>
28#include <ctime>
29#include <thread>
30
31#include "cyber/cyber.h"
32
34
35namespace apollo {
36namespace drivers {
37namespace gnss {
38
39speed_t get_serial_baudrate(uint32_t rate) {
40 switch (rate) {
41 case 9600:
42 return B9600;
43 case 19200:
44 return B19200;
45 case 38400:
46 return B38400;
47 case 57600:
48 return B57600;
49 case 115200:
50 return B115200;
51 case 230400:
52 return B230400;
53 case 460800:
54 return B460800;
55 case 921600:
56 return B921600;
57 default:
58 return 0;
59 }
60}
61
62class SerialStream : public Stream {
63 public:
64 SerialStream(const char* device_name, speed_t baud_rate,
65 uint32_t timeout_usec);
67
68 virtual bool Connect();
69 virtual bool Disconnect();
70 virtual size_t read(uint8_t* buffer, size_t max_length);
71 virtual size_t write(const uint8_t* data, size_t length);
72
73 private:
74 SerialStream() {}
75 void open();
76 void close();
77 bool configure_port(int fd);
78 bool wait_readable(uint32_t timeout_us);
79 bool wait_writable(uint32_t timeout_us);
80 void check_remove();
81
82 std::string device_name_;
83 speed_t baud_rate_;
84 uint32_t bytesize_;
85 uint32_t parity_;
86 uint32_t stopbits_;
87 uint32_t flowcontrol_;
88 uint32_t byte_time_us_;
89
90 uint32_t timeout_usec_;
91 int fd_;
92 int errno_;
93 bool is_open_;
94};
95
96SerialStream::SerialStream(const char* device_name, speed_t baud_rate,
97 uint32_t timeout_usec)
98 : device_name_(device_name),
99 baud_rate_(baud_rate),
100 bytesize_(8),
101 parity_(0),
102 stopbits_(1),
103 flowcontrol_(0),
104 timeout_usec_(timeout_usec),
105 fd_(-1),
106 errno_(0),
107 is_open_(false) {
108 if (device_name_.empty()) {
110 }
111}
112
113SerialStream::~SerialStream() { this->close(); }
114
115void SerialStream::open(void) {
116 int fd = 0;
117 fd = ::open(device_name_.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
118 if (fd == -1) {
119 switch (errno) {
120 case EINTR:
121 // Recurse because this is a recoverable error.
122 return open();
123
124 case ENFILE:
125 case EMFILE:
126 default:
127 AERROR << "Open device " << device_name_
128 << " failed, error: " << strerror(errno);
129 return;
130 }
131 }
132
133 if (!configure_port(fd)) {
134 ::close(fd);
135 return;
136 }
137
138 fd_ = fd;
139 is_open_ = true;
140}
141
142bool SerialStream::configure_port(int fd) {
143 if (fd < 0) {
144 return false;
145 }
146
147 struct termios options; // The options for the file descriptor
148 if (tcgetattr(fd, &options) == -1) {
149 AERROR << "tcgetattr failed.";
150 return false;
151 }
152
153 // set up raw mode / no echo / binary
154 options.c_cflag |= (tcflag_t)(CLOCAL | CREAD);
155 options.c_lflag &= (tcflag_t) ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL |
156 ISIG | IEXTEN); // |ECHOPRT
157
158 options.c_oflag &= (tcflag_t) ~(OPOST);
159 options.c_iflag &= (tcflag_t) ~(INLCR | IGNCR | ICRNL | IGNBRK);
160
161#ifdef IUCLC
162 options.c_iflag &= (tcflag_t)~IUCLC;
163#endif
164
165#ifdef PARMRK
166 options.c_iflag &= (tcflag_t)~PARMRK;
167#endif
168
169#ifdef BSD_SOURCE_ // depend glibc
170 ::cfsetspeed(&options, baud_rate_);
171#else
172 ::cfsetispeed(&options, baud_rate_);
173 ::cfsetospeed(&options, baud_rate_);
174#endif
175
176 // setup char len
177 options.c_cflag &= (tcflag_t)~CSIZE;
178
179 // eight bits
180 options.c_cflag |= CS8;
181
182 // setup stopbits:stopbits_one
183 options.c_cflag &= (tcflag_t) ~(CSTOPB);
184
185 // setup parity: parity_none
186 options.c_iflag &= (tcflag_t) ~(INPCK | ISTRIP);
187 options.c_cflag &= (tcflag_t) ~(PARENB | PARODD);
188
189// setup flow control : flowcontrol_none
190// xonxoff
191#ifdef IXANY
192 options.c_iflag &= (tcflag_t) ~(IXON | IXOFF | IXANY);
193#else
194 options.c_iflag &= (tcflag_t) ~(IXON | IXOFF);
195#endif
196
197// rtscts
198#ifdef CRTSCTS
199 options.c_cflag &= static_cast<uint64_t>(~(CRTSCTS));
200#elif defined CNEW_RTSCTS
201 options.c_cflag &= static_cast<uint64_t>(~(CNEW_RTSCTS));
202#else
203#error "OS Support seems wrong."
204#endif
205
206 // http://www.unixwiz.net/techtips/termios-vmin-vtime.html
207 // this basically sets the read call up to be a polling read,
208 // but we are using select to ensure there is data available
209 // to read before each call, so we should never needlessly poll
210 options.c_cc[VMIN] = 0;
211 options.c_cc[VTIME] = 0;
212
213 // activate settings
214 ::tcsetattr(fd, TCSANOW, &options);
215
216 // Update byte_time_ based on the new settings.
217 uint32_t bit_time_us = static_cast<uint32_t>(1e6 / 115200);
218 byte_time_us_ = bit_time_us * (1 + bytesize_ + parity_ + stopbits_);
219 return true;
220}
221
223 if (!is_open_) {
224 this->open();
225 if (!is_open_) {
227 errno_ = errno;
228 return false;
229 }
230 }
231
233 return true;
234 }
235
237 Login();
238 return true;
239}
240
241void SerialStream::close(void) {
242 if (is_open_) {
243 ::close(fd_);
244 fd_ = -1;
245 is_open_ = false;
247 }
248}
249
251 if (!is_open_) {
252 // not open
253 return false;
254 }
255
256 this->close();
257 return true;
258}
259
260void SerialStream::check_remove() {
261 char data = 0;
262 ssize_t nsent = ::write(fd_, &data, 0);
263 if (nsent < 0) {
264 AERROR << "Serial stream detect write failed, error: " << strerror(errno);
265 switch (errno) {
266 case EBADF:
267 case EIO:
269 AERROR << "Device " << device_name_ << " removed.";
270 Disconnect();
271 break;
272 }
273 }
274}
275
276size_t SerialStream::read(uint8_t* buffer, size_t max_length) {
277 if (!is_open_) {
278 if (!Connect()) {
279 return 0;
280 }
281 AINFO << "Connect " << device_name_ << " success.";
282 }
283
284 ssize_t bytes_read = 0;
285 ssize_t bytes_current_read = 0;
286
287 wait_readable(10000); // wait 10ms
288
289 while (max_length > 0) {
290 bytes_current_read = ::read(fd_, buffer, max_length);
291 if (bytes_current_read < 0) {
292 switch (errno) {
293 case EAGAIN:
294 case EINVAL:
295 bytes_current_read = 0;
296 break;
297
298 case EBADF:
299 case EIO:
300 AERROR << "Serial stream read data failed, error: "
301 << strerror(errno);
302 Disconnect();
303 if (Connect()) {
304 AINFO << "Reconnect " << device_name_ << " success.";
305 bytes_current_read = 0;
306 break; // has recoverable
307 }
308
309 default:
310 AERROR << "Serial stream read data failed, error: " << strerror(errno)
311 << ", errno: " << errno;
313 errno_ = errno;
314 return bytes_read;
315 }
316 }
317
318 if (bytes_current_read == 0) {
319 if (!bytes_read) {
320 check_remove();
321 return 0;
322 }
323 return bytes_read;
324 }
325 max_length -= bytes_current_read;
326 buffer += bytes_current_read;
327 bytes_read += bytes_current_read;
328 }
329
330 return bytes_read;
331}
332
333size_t SerialStream::write(const uint8_t* data, size_t length) {
334 if (!is_open_) {
335 if (!Connect()) {
336 return 0;
337 }
338 AINFO << "Connect " << device_name_ << " success.";
339 }
340
341 size_t total_nsent = 0;
342 size_t delay_times = 0;
343
344 while ((length > 0) && (delay_times < 5)) {
345 ssize_t nsent = ::write(fd_, data, length);
346 if (nsent < 0) {
347 AERROR << "Serial stream write data failed, error: " << strerror(errno);
348 switch (errno) {
349 case EAGAIN:
350 case EINVAL:
351 nsent = 0;
352 break;
353
354 case EBADF:
355 case EIO:
356 Disconnect();
357 if (Connect()) {
358 AINFO << "Reconnect " << device_name_ << "success.";
359 nsent = 0;
360 break; // has recoverable
361 }
362
363 default:
365 errno_ = errno;
366 return total_nsent;
367 }
368 }
369
370 if (nsent == 0) {
371 if (!wait_writable(byte_time_us_)) {
372 break;
373 }
374 ++delay_times;
375 continue;
376 }
377
378 total_nsent += nsent;
379 length -= nsent;
380 data += nsent;
381 }
382
383 return total_nsent;
384}
385
386bool SerialStream::wait_readable(uint32_t timeout_us) {
387 // Setup a select call to block for serial data or a timeout
388 timespec timeout_ts;
389 fd_set readfds;
390 FD_ZERO(&readfds);
391 FD_SET(fd_, &readfds);
392
393 timeout_ts.tv_sec = timeout_us / 1000000;
394 timeout_ts.tv_nsec = (timeout_us % 1000000) * 1000;
395 int r = pselect(fd_ + 1, &readfds, NULL, NULL, &timeout_ts, NULL);
396 if (r <= 0) {
397 return false;
398 }
399
400 // This shouldn't happen, if r > 0 our fd has to be in the list!
401 if (!FD_ISSET(fd_, &readfds)) {
402 return false;
403 }
404 // Data available to read.
405 return true;
406}
407
408bool SerialStream::wait_writable(uint32_t timeout_us) {
409 // Setup a select call to block for serial data or a timeout
410 timespec timeout_ts;
411 fd_set writefds;
412 FD_ZERO(&writefds);
413 FD_SET(fd_, &writefds);
414
415 timeout_ts.tv_sec = timeout_us / 1000000;
416 timeout_ts.tv_nsec = (timeout_us % 1000000) * 1000;
417 int r = pselect(fd_ + 1, NULL, &writefds, NULL, &timeout_ts, NULL);
418 if (r <= 0) {
419 return false;
420 }
421
422 // This shouldn't happen, if r > 0 our fd has to be in the list!
423 if (!FD_ISSET(fd_, &writefds)) {
424 return false;
425 }
426 // Data available to write.
427 return true;
428}
429
430Stream* Stream::create_serial(const char* device_name, uint32_t baud_rate,
431 uint32_t timeout_usec) {
432 speed_t baud = get_serial_baudrate(baud_rate);
433 return baud == 0 ? nullptr
434 : new SerialStream(device_name, baud, timeout_usec);
435}
436
437} // namespace gnss
438} // namespace drivers
439} // namespace apollo
virtual size_t write(const uint8_t *data, size_t length)
virtual size_t read(uint8_t *buffer, size_t max_length)
static Stream * create_serial(const char *device_name, uint32_t baud_rate, uint32_t timeout_usec=0)
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
speed_t get_serial_baudrate(uint32_t rate)
class register implement
Definition arena_queue.h:37