blob: a29944d1836f84bf3c1c6f7f595411ca1ad400b4 [file] [log] [blame]
Brian Silvermanf6b68842013-12-20 12:34:58 -08001#include "bbb/uart_reader.h"
Brian Silverman1662a0e2013-12-19 17:50:01 -08002
Daniel Pettia4fe7bc2013-12-22 12:57:50 -08003#include <errno.h>
Daniel Pettib36f5b82013-12-15 08:55:04 -08004#include <fcntl.h>
5#include <linux/serial.h>
6#include <termio.h>
7#include <unistd.h>
Daniel Petti059be422013-12-14 19:47:42 -08008
Brian Silverman1662a0e2013-12-19 17:50:01 -08009#include "aos/common/logging/logging.h"
Brian Silverman53f29182013-12-21 15:16:27 -080010
Daniel Petti059be422013-12-14 19:47:42 -080011// This is the code for receiving data from the cape via UART.
Brian Silverman1662a0e2013-12-19 17:50:01 -080012// NOTE: In order for this to work, you MUST HAVE
13// "capemgr.enable_partno=BB_UART1"
Daniel Petti059be422013-12-14 19:47:42 -080014// in your BBB's /media/BEAGLEBONE/uEnv.txt file!
15
Daniel Pettib36f5b82013-12-15 08:55:04 -080016// Implementation for setting custom serial baud rates based on this code:
17// <http://jim.sh/ftx/files/linux-custom-baudrate.c>
18
Daniel Petti059be422013-12-14 19:47:42 -080019namespace bbb {
Brian Silverman1662a0e2013-12-19 17:50:01 -080020namespace {
21// TODO(brians): Determine this in some way that allows easy switching for
22// testing with /dev/ttyUSB0 for example.
Brian Silvermaned030062013-12-20 21:03:47 -080023// TODO(brians): Change back to /dev/ttyO1.
24const char *device = "/dev/ttyUSB0";
Brian Silverman1662a0e2013-12-19 17:50:01 -080025} // namespace
Daniel Petti059be422013-12-14 19:47:42 -080026
Brian Silvermanf6b68842013-12-20 12:34:58 -080027UartReader::UartReader(int32_t baud_rate)
Daniel Pettia4fe7bc2013-12-22 12:57:50 -080028 : fd_(open(device, O_RDWR | O_NOCTTY)) {
29
Brian Silverman1662a0e2013-12-19 17:50:01 -080030 if (fd_ < 0) {
31 LOG(FATAL, "open(%s, O_RDWR | O_NOCTTY) failed with %d: %s."
Brian Silvermanf6b68842013-12-20 12:34:58 -080032 " Did you read my note in bbb/uart_reader.cc?\n",
Brian Silverman1662a0e2013-12-19 17:50:01 -080033 device, errno, strerror(errno));
Daniel Petti059be422013-12-14 19:47:42 -080034 }
Brian Silvermaned030062013-12-20 21:03:47 -080035
36 {
37 termios options;
38 if (tcgetattr(fd_, &options) != 0) {
39 LOG(FATAL, "tcgetattr(%d, %p) failed with %d: %s\n",
40 fd_, &options, errno, strerror(errno));
41 }
42 if (cfsetispeed(&options, B38400) != 0) {
43 LOG(FATAL, "cfsetispeed(%p, B38400) failed with %d: %s\n",
44 &options, errno, strerror(errno));
45 }
46 if (cfsetospeed(&options, B38400) != 0) {
47 LOG(FATAL, "cfsetospeed(%p, B38400) failed with %d: %s\n",
48 &options, errno, strerror(errno));
49 }
50 cfmakeraw(&options);
51 options.c_cflag |= CLOCAL; // ignore modem flow control
52 options.c_cflag |= CREAD; // enable receiver
53 options.c_cflag &= ~CRTSCTS; // disable flow control
54 //options.c_cflag |= PARENB; // enable parity; defaults to even
55 options.c_cflag = (options.c_cflag & ~CSIZE) | CS8; // 8 bits
56 options.c_cflag &= ~CSTOPB; // 1 stop bit
57 options.c_iflag = 0;
58 // Replace any received characters with parity or framing errors with 0s.
59 options.c_iflag = (options.c_iflag & ~(IGNPAR | PARMRK)) | INPCK;
60 //options.c_iflag |= IGNCR | PARMRK;
61 options.c_oflag = 0;
62 options.c_lflag = 0;
Brian Silverman3e0a05b2013-12-22 11:33:42 -080063 options.c_cc[VMIN] = 20;
64 options.c_cc[VTIME] = 0;
Brian Silvermaned030062013-12-20 21:03:47 -080065 if (tcsetattr(fd_, TCSANOW, &options) != 0) {
66 LOG(FATAL, "tcsetattr(%d, TCSANOW, %p) failed with %d: %s\n",
67 fd_, &options, errno, strerror(errno));
68 }
69 }
Daniel Pettib36f5b82013-12-15 08:55:04 -080070
Brian Silvermaned030062013-12-20 21:03:47 -080071 {
72 serial_struct serinfo;
73 if (ioctl(fd_, TIOCGSERIAL, &serinfo) != 0) {
74 LOG(FATAL, "ioctl(%d, TIOCGSERIAL, %p) failed with %d: %s\n",
75 fd_, &serinfo, errno, strerror(errno));
76 }
77 serinfo.reserved_char[0] = 0;
78 serinfo.flags &= ~ASYNC_SPD_MASK;
79 serinfo.flags |= ASYNC_SPD_CUST;
80 //serinfo.flags |= ASYNC_LOW_LATENCY;
81 serinfo.custom_divisor = static_cast<int>(
Daniel Pettia4fe7bc2013-12-22 12:57:50 -080082 static_cast<double>(serinfo.baud_base) / baud_rate + 0.5);
Brian Silvermaned030062013-12-20 21:03:47 -080083 if (serinfo.custom_divisor < 1) serinfo.custom_divisor = 1;
84 if (ioctl(fd_, TIOCSSERIAL, &serinfo) < 0) {
85 LOG(FATAL, "ioctl(%d, TIOCSSERIAL, %p) failed with %d: %s\n",
86 fd_, &serinfo, errno, strerror(errno));
87 }
88 if (ioctl(fd_, TIOCGSERIAL, &serinfo) < 0) {
89 LOG(FATAL, "ioctl(%d, TIOCGSERIAL, %p) failed with %d: %s\n",
90 fd_, &serinfo, errno, strerror(errno));
91 }
92 if ((serinfo.flags & ASYNC_SPD_CUST) == 0) {
Daniel Pettia4fe7bc2013-12-22 12:57:50 -080093 LOG(FATAL, "Cannot set custom baud rate\n");
Brian Silvermaned030062013-12-20 21:03:47 -080094 }
Daniel Pettia4fe7bc2013-12-22 12:57:50 -080095 if (serinfo.custom_divisor * baud_rate != serinfo.baud_base) {
Brian Silvermaned030062013-12-20 21:03:47 -080096 LOG(WARNING, "actual baudrate is %d / %d = %f\n",
97 serinfo.baud_base, serinfo.custom_divisor,
98 static_cast<double>(serinfo.baud_base) / serinfo.custom_divisor);
99 }
Daniel Petti059be422013-12-14 19:47:42 -0800100 }
101
Brian Silverman1662a0e2013-12-19 17:50:01 -0800102 if (fcntl(fd_, F_SETFL, 0) != 0) {
103 LOG(FATAL, "fcntl(%d, F_SETFL, 0) failed with %d: %s\n",
104 fd_, errno, strerror(errno));
105 }
Daniel Petti059be422013-12-14 19:47:42 -0800106}
107
Brian Silvermanf6b68842013-12-20 12:34:58 -0800108UartReader::~UartReader() {
Brian Silverman1662a0e2013-12-19 17:50:01 -0800109 if (fd_ > 0) close(fd_);
110}
Daniel Petti059be422013-12-14 19:47:42 -0800111
Daniel Pettia4fe7bc2013-12-22 12:57:50 -0800112int UartReader::ReadBytes(AlignedChar *dest, size_t max_bytes) {
113 return read(fd_, dest, max_bytes);
Brian Silverman1662a0e2013-12-19 17:50:01 -0800114}
Daniel Petti059be422013-12-14 19:47:42 -0800115
Daniel Pettia4fe7bc2013-12-22 12:57:50 -0800116} // namespace bbb