blob: aabedd3d15a3a273af27ef686b654851520fe8b0 [file] [log] [blame]
Daniel Pettib36f5b82013-12-15 08:55:04 -08001#include <fcntl.h>
2#include <linux/serial.h>
3#include <termio.h>
4#include <unistd.h>
5
Daniel Petti059be422013-12-14 19:47:42 -08006#include <cmath>
7#include <cstring>
Daniel Petti059be422013-12-14 19:47:42 -08008
9#include "aos/common/logging/logging_impl.h"
10#include "bbb_cape/src/cape/cows.h"
11#include "crc.h"
12#include "uart_receiver.h"
13
14// This is the code for receiving data from the cape via UART.
15// NOTE: In order for this to work, you MUST HAVE "capemgr.enable_partno=BB_UART1"
16// in your BBB's /media/BEAGLEBONE/uEnv.txt file!
17
Daniel Pettib36f5b82013-12-15 08:55:04 -080018// Implementation for setting custom serial baud rates based on this code:
19// <http://jim.sh/ftx/files/linux-custom-baudrate.c>
20
Daniel Petti059be422013-12-14 19:47:42 -080021namespace bbb {
22
Daniel Petti23dcf6c2013-12-19 08:56:41 -080023UartReceiver::UartReceiver(uint32_t baud_rate) :
24 baud_rate_(baud_rate) {
25 packet_size_ = DATA_STRUCT_SEND_SIZE;
Daniel Petti059be422013-12-14 19:47:42 -080026 //packet_size_ should be a multiple of four.
27 int toadd = packet_size_ % 4;
28 LOG(DEBUG, "Increasing packet size by %d bytes.\n", toadd);
29 packet_size_ += toadd;
30
31 // See cows.h for where this comes from.
32 stuffed_size_ = ((packet_size_ - 1) / (pow(2, 32) - 1) + 1) * 4 + packet_size_;
33
34 buf_ = static_cast<char *>(malloc(stuffed_size_));
35}
36
37UartReceiver::~UartReceiver() {
38 free(buf_);
39}
40
41int UartReceiver::SetUp() {
Daniel Pettib36f5b82013-12-15 08:55:04 -080042 termios options;
43 serial_struct serinfo;
Daniel Petti059be422013-12-14 19:47:42 -080044
45 if ((fd_ = open("/dev/ttyO1", O_RDWR | O_NOCTTY)) < 0) {
46 LOG(FATAL, "Open() failed with error %d.\
47 (Did you read my note in uart_receiver.cc?)\n", fd_);
48 }
Daniel Pettib36f5b82013-12-15 08:55:04 -080049
50 // Must implement an ugly custom divisor.
51 serinfo.reserved_char[0] = 0;
52 if (ioctl(fd_, TIOCGSERIAL, &serinfo) < 0)
Daniel Petti059be422013-12-14 19:47:42 -080053 return -1;
Daniel Pettib36f5b82013-12-15 08:55:04 -080054 serinfo.flags &= ~ASYNC_SPD_MASK;
55 serinfo.flags |= ASYNC_SPD_CUST;
56 serinfo.custom_divisor = (serinfo.baud_base + (baud_rate_ / 2)) / baud_rate_;
57 if (serinfo.custom_divisor < 1)
58 serinfo.custom_divisor = 1;
59 if (ioctl(fd_, TIOCSSERIAL, &serinfo) < 0)
60 LOG(ERROR, "First ioctl failed.\n");
Daniel Petti059be422013-12-14 19:47:42 -080061 return -1;
Daniel Pettib36f5b82013-12-15 08:55:04 -080062 if (ioctl(fd_, TIOCGSERIAL, &serinfo) < 0)
63 LOG(ERROR, "Second ioctl failed.\n");
64 return -1;
65 if (serinfo.custom_divisor * static_cast<int>(baud_rate_)
66 != serinfo.baud_base) {
67 LOG(WARNING, "actual baudrate is %d / %d = %f",
68 serinfo.baud_base, serinfo.custom_divisor,
69 (float)serinfo.baud_base / serinfo.custom_divisor);
Daniel Petti059be422013-12-14 19:47:42 -080070 }
71
Daniel Pettib36f5b82013-12-15 08:55:04 -080072 fcntl(fd_, F_SETFL, 0);
73 tcgetattr(fd_, &options);
74 cfsetispeed(&options, B38400);
75 cfsetospeed(&options, B38400);
76 cfmakeraw(&options);
77 options.c_cflag |= (CLOCAL | CREAD);
78 options.c_cflag &= ~CRTSCTS;
79 options.c_iflag = 0;
80 options.c_oflag = 0;
81 options.c_lflag = 0;
Daniel Petti067e0612013-12-19 09:09:09 -080082 options.c_cc[VMIN] = 0;
Daniel Petti23dcf6c2013-12-19 08:56:41 -080083 options.c_cc[VTIME] = 1;
Daniel Pettib36f5b82013-12-15 08:55:04 -080084 if (tcsetattr(fd_, TCSANOW, &options) != 0)
85 LOG(ERROR, "Tcsetattr failed.\n");
86 return -1;
Daniel Petti059be422013-12-14 19:47:42 -080087
88 return 0;
89}
90
91int UartReceiver::GetPacket(DataStruct *packet) {
92 int pstarti = 0, bread, cons_zeros = 0;
93 uint32_t readi = 0;
94 bool done = false, has_packet = false;
95 uint32_t ptemp [(stuffed_size_ - 1) / 4 + 1];
96
97 while (!done && buf_used_ < stuffed_size_) {
98 if ((bread = read(fd_, buf_ + buf_used_, stuffed_size_ - buf_used_)) < 0) {
99 LOG(WARNING, "Read() failed with error %d.\n", bread);
100 return -1;
101 }
102 buf_used_ += bread;
103
104 // Find the beginning of the packet.
105 // Look for four bytes of zeros.
106 while (readi < buf_used_) {
107 if (buf_[readi] == 0) {
108 if (cons_zeros == 4) {
109 if (has_packet) {
110 // We got to the end of a packet.
111 done = true;
112 break;
113 } else {
114 // We got to the start of a packet.
115 has_packet = true;
116 pstarti = readi - 3;
117 }
118 } else {
119 ++cons_zeros;
120 }
121 } else {
122 cons_zeros = 0;
123 }
Daniel Petti3d9e2f52013-12-19 12:24:03 -0800124 readi++
Daniel Petti059be422013-12-14 19:47:42 -0800125 }
Daniel Petti059be422013-12-14 19:47:42 -0800126 }
127
128 // Copy packet data to output.
129 int filled = 0;
Daniel Petti23dcf6c2013-12-19 08:56:41 -0800130 readi -= 3; // We read a little into the next packet.
Daniel Petti059be422013-12-14 19:47:42 -0800131 for (uint32_t i = pstarti; i < readi - 3; ++i) {
132 ptemp[i] = buf_[i];
133 ++filled;
134 }
135 // Move everything we didn't use to the beginning of the buffer for next time.
136 uint32_t puti = 0;
137 for (uint32_t i = readi; i < stuffed_size_; ++i) {
138 buf_[puti++] = buf_[i];
139 }
140 buf_used_ = stuffed_size_ - readi;
Daniel Petti23dcf6c2013-12-19 08:56:41 -0800141 readi = 0;
Daniel Petti059be422013-12-14 19:47:42 -0800142
143 // Cows algorithm always outputs something 4-byte aligned.
144 if (filled % 4) {
145 LOG(WARNING, "Rejecting packet due to it not being possible\
146 for cows to have created it.\n");
147 return -1;
148 }
149
150 // Unstuff our packet.
151 uint32_t ptemp_unstuffed [packet_size_];
152 uint32_t bunstuffed;
153 if ((bunstuffed = cows_unstuff(ptemp, sizeof(ptemp), ptemp_unstuffed)) == 0) {
154 LOG(WARNING, "Rejecting packet due to failure to unstuff it.\n");
155 return -1;
156 }
157 if (bunstuffed != packet_size_) {
158 LOG(WARNING, "Rejecting packet of wrong size.\
159 Expected packet of size %d, got packet of size %d.\n",
160 packet_size_, bunstuffed);
161 return -1;
162 }
163
164 // Make sure the checksum checks out.
165 uint32_t checksum = static_cast<uint32_t>(ptemp_unstuffed[packet_size_ - 4]);
Daniel Petti23dcf6c2013-12-19 08:56:41 -0800166 // Checksum only gets done on the actual datastruct part of the packet,
167 // so we'll discard everything after it.
Daniel Petti059be422013-12-14 19:47:42 -0800168 memcpy(packet, ptemp_unstuffed, sizeof(DataStruct));
169 if (cape::CalculateChecksum((uint8_t *)packet, sizeof(DataStruct)) != checksum) {
170 LOG(WARNING, "Rejecting packet due to checksum failure.\n");
171 return -1;
172 }
173
174 return 0;
175}
176
Daniel Petti23dcf6c2013-12-19 08:56:41 -0800177} // bbb
Daniel Petti059be422013-12-14 19:47:42 -0800178