45 std::string name,
int baud = 115200)
47 return std::shared_ptr<SV2SerialConnection>(
51 boost::asio::serial_port&
socket() {
return socket_; }
55 void close() { socket_.close(); }
59 std::fill(message_.begin(), message_.end(), 0);
62 boost::asio::async_read(
63 socket_, buffer_, boost::asio::transfer_exactly(1),
64 boost::bind(&SV2SerialConnection::handle_read,
this, boost::placeholders::_1, boost::placeholders::_2, PART_MAGIC));
70 boost::asio::async_write(socket_, boost::asio::buffer(data),
71 boost::bind(&SV2SerialConnection::handle_write,
this, boost::placeholders::_1, boost::placeholders::_2));
87 : socket_(io_context),
88 message_(SV2_MAX_SIZE * 2)
96 catch (std::exception& e)
98 glog.
is(DIE) &&
glog <<
"Failed to open serial port: " << name << std::endl;
101 socket_.set_option(boost::asio::serial_port_base::baud_rate(baud));
104 socket_.set_option(boost::asio::serial_port_base::flow_control(
105 boost::asio::serial_port_base::flow_control::none));
108 socket_.set_option(boost::asio::serial_port_base::character_size(8));
110 boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none));
111 socket_.set_option(boost::asio::serial_port_base::stop_bits(
112 boost::asio::serial_port_base::stop_bits::one));
115 void handle_write(
const boost::system::error_code& error,
size_t )
121 glog.
is(WARN) &&
glog <<
"Error writing to serial connection: " << error << std::endl;
125 void handle_read(
const boost::system::error_code& error,
size_t bytes_transferred,
135 std::istream istrm(&buffer_);
141 if ((istrm.peek() & 0xFF) != SV2_MAGIC_BYTE)
143 glog.
is(DEBUG2) &&
glog << std::hex << istrm.peek() << std::dec
144 <<
": Not magic byte, continuing to read."
147 buffer_.consume(bytes_transferred);
151 glog.
is(DEBUG2) &&
glog <<
"Received magic byte. Starting read of "
152 << SV2_HEADER_SIZE <<
" bytes" << std::endl;
153 message_insert_ = &message_[0];
154 istrm.read(message_insert_, bytes_transferred);
155 message_insert_ += bytes_transferred;
158 boost::asio::async_read(socket_, buffer_,
159 boost::asio::transfer_exactly(SV2_HEADER_SIZE),
160 boost::bind(&SV2SerialConnection::handle_read,
this,
161 boost::placeholders::_1, boost::placeholders::_2, PART_HEADER));
168 istrm.read(message_insert_, bytes_transferred);
169 message_insert_ += bytes_transferred;
171 if (!check_escapes(part))
175 message_size_ = message_[1] & 0xFF;
176 message_size_ |= (message_[2] & 0xFF) << 8;
179 glog <<
"Received header: "
180 << dccl::hex_encode(std::string(
181 message_.begin(), message_.begin() + SV2_HEADER_SIZE + 1))
182 <<
", size of " << message_size_ << std::endl;
185 boost::asio::async_read(
187 boost::asio::transfer_exactly(message_size_ - SV2_HEADER_SIZE),
188 boost::bind(&SV2SerialConnection::handle_read,
this, boost::placeholders::_1, boost::placeholders::_2,
195 istrm.read(message_insert_, bytes_transferred);
196 message_insert_ += bytes_transferred;
198 if (!check_escapes(part))
203 glog <<
"Read message: "
204 << dccl::hex_encode(std::string(message_.begin(),
205 message_.begin() + message_size_ + 1))
208 std::string(message_.begin(), message_.begin() + message_size_ + 1));
217 if (error == boost::asio::error::eof)
219 glog.
is(DEBUG1) &&
glog <<
"Connection reached EOF" << std::endl;
221 else if (error == boost::asio::error::operation_aborted)
223 glog.
is(DEBUG1) &&
glog <<
"Read operation aborted (socket closed)" << std::endl;
227 glog.
is(WARN) &&
glog <<
"Error reading from serial connection: " <<
error
233 bool check_escapes(MessagePart part)
238 int escape = std::count(message_.begin(), message_.end(), SV2_ESCAPE);
239 if (escape != last_escape_)
241 boost::asio::async_read(
242 socket_, buffer_, boost::asio::transfer_exactly(escape - last_escape_),
243 boost::bind(&SV2SerialConnection::handle_read,
this, boost::placeholders::_1, boost::placeholders::_2, part));
245 <<
" more bytes because of escape characters." << std::endl;
256 void remove_escapes()
258 if (last_escape_ == 0)
262 int before_size = message_.size();
263 boost::replace_all(message_, std::string(1, SV2_ESCAPE) + std::string(1, 0x5E),
264 std::string(1, SV2_MAGIC_BYTE));
265 boost::replace_all(message_, std::string(1, SV2_ESCAPE) + std::string(1, 0x5D),
266 std::string(1, SV2_ESCAPE));
267 int after_size = message_.size();
269 message_insert_ -= (before_size - after_size);
270 message_.resize(before_size);
271 last_escape_ = std::count(message_.begin(), message_.end(), SV2_ESCAPE);
274 void add_escapes(std::string* message)
277 boost::replace_all(*message, std::string(1, SV2_ESCAPE),
278 std::string(1, SV2_ESCAPE) + std::string(1, 0x5D));
279 boost::replace_all(*message, std::string(1, SV2_MAGIC_BYTE),
280 std::string(1, SV2_ESCAPE) + std::string(1, 0x5E));
282 boost::replace_first(*message, std::string(1, SV2_ESCAPE) + std::string(1, 0x5E),
283 std::string(1, SV2_MAGIC_BYTE));
287 boost::asio::serial_port socket_;
288 boost::asio::streambuf buffer_;
289 std::vector<char> message_;
290 char* message_insert_;
296 SV2_MAGIC_BYTE = 0x7e,