serial.cpp
Go to the documentation of this file.
1 #include <chrono>
2 #include <functional>
3 #include <iostream>
4 
5 #include "create/serial.h"
6 #include "create/types.h"
7 
8 namespace create {
9 
10  Serial::Serial(std::shared_ptr<Data> d, bool install_signal_handler) :
11  signals(io),
12  port(io),
13  dataReady(false),
14  isReading(false),
15  data(d),
16  corruptPackets(0),
17  totalPackets(0)
18  {
19  if (install_signal_handler) {
20  signals.add(SIGINT);
21  signals.add(SIGTERM);
22  }
23  }
24 
26  disconnect();
27  }
28 
29  void Serial::signalHandler(const boost::system::error_code& error, int signal_number) {
30  if (!error) {
31  if (connected()) {
32  // Ensure not in Safe/Full modes
34  // Stop OI
36  exit(signal_number);
37  }
38  }
39  }
40 
41  bool Serial::connect(const std::string& portName, const int& baud, std::function<void()> cb) {
42  using namespace boost::asio;
43  port.open(portName);
44  port.set_option(serial_port::baud_rate(baud));
45  port.set_option(serial_port::character_size(8));
46  port.set_option(serial_port::parity(serial_port::parity::none));
47  port.set_option(serial_port::stop_bits(serial_port::stop_bits::one));
48  port.set_option(serial_port::flow_control(serial_port::flow_control::none));
49 
50  signals.async_wait(std::bind(&Serial::signalHandler, this, std::placeholders::_1, std::placeholders::_2));
51 
52  usleep(1000000);
53 
54  if (port.is_open()) {
55  callback = cb;
56  bool startReadSuccess = startReading();
57  if (!startReadSuccess) {
58  port.close();
59  }
60  return startReadSuccess;
61  }
62  return false;
63  }
64 
66  if (isReading) {
67  stopReading();
68  }
69 
70  if (connected()) {
71  // Ensure not in Safe/Full modes
73  // Stop OI
75  port.close();
76  }
77  }
78 
80  if (!connected()) return false;
81 
82  if (!data) {
83  CERR("[create::Serial] ", "data pointer not initialized.");
84  return false;
85  }
86 
87  // Only allow once
88  if (isReading) return true;
89 
90  // Start OI
92 
93  if (!startSensorStream()) return false;
94 
95  io.reset();
96 
97  // Start continuously reading one byte at a time
98  boost::asio::async_read(port,
99  boost::asio::buffer(&byteRead, 1),
100  std::bind(&Serial::onData,
101  shared_from_this(),
102  std::placeholders::_1,
103  std::placeholders::_2));
104 
105  ioThread = std::thread(std::bind(
106  static_cast<std::size_t(boost::asio::io_service::*)(void)>(
107  &boost::asio::io_service::run), &io));
108 
109  // Wait for first complete read to finish
110  std::unique_lock<std::mutex> lock(dataReadyMut);
111 
112  int attempts = 1;
113  int maxAttempts = 10;
114  while (!dataReady) {
115  if (dataReadyCond.wait_for(lock, std::chrono::milliseconds(500)) == std::cv_status::timeout) {
116  if (attempts >= maxAttempts) {
117  CERR("[create::Serial] ", "failed to receive data from Create. Check if robot is powered!");
118  io.stop();
119  ioThread.join();
120  return false;
121  }
122  attempts++;
123 
124  // Request data again
127  }
128  }
129 
130  isReading = true;
131  return true;
132  }
133 
135  if (isReading) {
136  io.stop();
137  ioThread.join();
138  isReading = false;
139  {
140  std::lock_guard<std::mutex> lock(dataReadyMut);
141  dataReady = false;
142  }
143  }
144  }
145 
146 
148  // Validate all packets
149  data->validateAll();
150 
151  // Notify first data packets ready
152  {
153  std::lock_guard<std::mutex> lock(dataReadyMut);
154  if (!dataReady) {
155  dataReady = true;
156  dataReadyCond.notify_one();
157  }
158  }
159  // Callback to notify data is ready
160  if (callback)
161  callback();
162  }
163 
164  void Serial::onData(const boost::system::error_code& e, const std::size_t& size) {
165  if (e) {
166  CERR("[create::Serial] ", "serial error - " << e.message());
167  return;
168  }
169 
170  // Should have read exactly one byte
171  if (size == 1) {
173  } // end if (size == 1)
174 
175  // Read the next byte
176  boost::asio::async_read(port,
177  boost::asio::buffer(&byteRead, 1),
178  std::bind(&Serial::onData,
179  shared_from_this(),
180  std::placeholders::_1,
181  std::placeholders::_2));
182  }
183 
184  bool Serial::send(const uint8_t* bytes, unsigned int numBytes) {
185  if (!connected()) {
186  CERR("[create::Serial] ", "send failed, not connected.");
187  return false;
188  }
189  // TODO: catch boost exceptions
190  boost::asio::write(port, boost::asio::buffer(bytes, numBytes));
191  return true;
192  }
193 
194  bool Serial::sendOpcode(const Opcode& code) {
195  uint8_t oc = (uint8_t) code;
196  return send(&oc, 1);
197  }
198 
199  uint64_t Serial::getNumCorruptPackets() const {
200  return corruptPackets;
201  }
202 
203  uint64_t Serial::getTotalPackets() const {
204  return totalPackets;
205  }
206 } // namespace create
std::function< void()> callback
Definition: serial.h:70
uint8_t byteRead
Definition: serial.h:65
uint64_t getTotalPackets() const
Definition: serial.cpp:203
boost::asio::serial_port port
Definition: serial.h:56
bool connected() const
Definition: serial.h:93
virtual void processByte(uint8_t byteRead)=0
bool sendOpcode(const Opcode &code)
Definition: serial.cpp:194
void notifyDataReady()
Definition: serial.cpp:147
std::condition_variable dataReadyCond
Definition: serial.h:60
Opcode
Definition: types.h:154
Definition: create.h:48
uint64_t totalPackets
Definition: serial.h:79
#define CERR(prefix, msg)
Definition: util.h:38
bool startReading()
Definition: serial.cpp:79
void stopReading()
Definition: serial.cpp:134
std::shared_ptr< Data > data
Definition: serial.h:76
boost::asio::signal_set signals
Definition: serial.h:55
Serial(std::shared_ptr< Data > data, bool install_signal_handler)
Definition: serial.cpp:10
void disconnect()
Definition: serial.cpp:65
bool send(const uint8_t *bytes, const uint32_t numBytes)
Definition: serial.cpp:184
virtual bool startSensorStream()=0
void signalHandler(const boost::system::error_code &error, int signal_number)
Definition: serial.cpp:29
bool dataReady
Definition: serial.h:62
bool connect(const std::string &port, const int &baud=115200, std::function< void()> cb=0)
Definition: serial.cpp:41
std::thread ioThread
Definition: serial.h:59
void onData(const boost::system::error_code &e, const std::size_t &size)
Definition: serial.cpp:164
std::mutex dataReadyMut
Definition: serial.h:61
boost::asio::io_service io
Definition: serial.h:54
bool isReading
Definition: serial.h:63
uint64_t getNumCorruptPackets() const
Definition: serial.cpp:199
uint64_t corruptPackets
Definition: serial.h:78


libcreate
Author(s): Jacob Perron
autogenerated on Sat May 8 2021 03:02:37