23 #include <boost/asio.hpp> 24 #include <dccl/binary.h> 33 static boost::shared_ptr<SV2SerialConnection> create(boost::asio::io_service& io_service,
34 std::string name,
int baud = 115200)
36 return boost::shared_ptr<SV2SerialConnection>(
40 boost::asio::serial_port& socket() {
return socket_; }
42 void start() { read_start(); }
44 void close() { socket_.close(); }
48 std::fill(message_.begin(), message_.end(), 0);
51 boost::asio::async_read(
52 socket_, buffer_, boost::asio::transfer_exactly(1),
53 boost::bind(&SV2SerialConnection::handle_read,
this, _1, _2, PART_MAGIC));
56 void write_start(std::string data)
59 boost::asio::async_write(socket_, boost::asio::buffer(data),
60 boost::bind(&SV2SerialConnection::handle_write,
this, _1, _2));
65 boost::signals2::signal<void(const std::string& message)> message_signal;
76 : socket_(io_service),
77 message_(SV2_MAX_SIZE * 2)
80 using goby::common::logger::DIE;
85 catch (std::exception& e)
87 glog.is(DIE) &&
glog <<
"Failed to open serial port: " << name << std::endl;
90 socket_.set_option(boost::asio::serial_port_base::baud_rate(baud));
93 socket_.set_option(boost::asio::serial_port_base::flow_control(
94 boost::asio::serial_port_base::flow_control::none));
97 socket_.set_option(boost::asio::serial_port_base::character_size(8));
99 boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none));
100 socket_.set_option(boost::asio::serial_port_base::stop_bits(
101 boost::asio::serial_port_base::stop_bits::one));
104 void handle_write(
const boost::system::error_code& error,
size_t bytes_transferred)
109 using goby::common::logger::WARN;
110 glog.is(WARN) &&
glog <<
"Error writing to serial connection: " << error << std::endl;
114 void handle_read(
const boost::system::error_code& error,
size_t bytes_transferred,
118 using goby::common::logger::DEBUG1;
119 using goby::common::logger::DEBUG2;
120 using goby::common::logger::WARN;
124 std::istream istrm(&buffer_);
130 if ((istrm.peek() & 0xFF) != SV2_MAGIC_BYTE)
132 glog.is(DEBUG2) &&
glog << std::hex << istrm.peek() << std::dec
133 <<
": Not magic byte, continuing to read." 136 buffer_.consume(bytes_transferred);
140 glog.is(DEBUG2) &&
glog <<
"Received magic byte. Starting read of " 141 << SV2_HEADER_SIZE <<
" bytes" << std::endl;
142 message_insert_ = &message_[0];
143 istrm.read(message_insert_, bytes_transferred);
144 message_insert_ += bytes_transferred;
147 boost::asio::async_read(socket_, buffer_,
148 boost::asio::transfer_exactly(SV2_HEADER_SIZE),
149 boost::bind(&SV2SerialConnection::handle_read,
this,
150 _1, _2, PART_HEADER));
157 istrm.read(message_insert_, bytes_transferred);
158 message_insert_ += bytes_transferred;
160 if (!check_escapes(part))
164 message_size_ = message_[1] & 0xFF;
165 message_size_ |= (message_[2] & 0xFF) << 8;
168 glog <<
"Received header: " 169 << dccl::hex_encode(std::string(
170 message_.begin(), message_.begin() + SV2_HEADER_SIZE + 1))
171 <<
", size of " << message_size_ << std::endl;
174 boost::asio::async_read(
176 boost::asio::transfer_exactly(message_size_ - SV2_HEADER_SIZE),
177 boost::bind(&SV2SerialConnection::handle_read,
this, _1, _2,
184 istrm.read(message_insert_, bytes_transferred);
185 message_insert_ += bytes_transferred;
187 if (!check_escapes(part))
192 glog <<
"Read message: " 193 << dccl::hex_encode(std::string(message_.begin(),
194 message_.begin() + message_size_ + 1))
197 std::string(message_.begin(), message_.begin() + message_size_ + 1));
206 if (error == boost::asio::error::eof)
208 glog.is(DEBUG1) &&
glog <<
"Connection reached EOF" << std::endl;
210 else if (error == boost::asio::error::operation_aborted)
212 glog.is(DEBUG1) &&
glog <<
"Read operation aborted (socket closed)" << std::endl;
216 glog.is(WARN) &&
glog <<
"Error reading from serial connection: " << error
222 bool check_escapes(MessagePart part)
225 using goby::common::logger::DEBUG1;
226 using goby::common::logger::WARN;
227 int escape = std::count(message_.begin(), message_.end(), SV2_ESCAPE);
228 if (escape != last_escape_)
230 boost::asio::async_read(
231 socket_, buffer_, boost::asio::transfer_exactly(escape - last_escape_),
232 boost::bind(&SV2SerialConnection::handle_read,
this, _1, _2, part));
233 glog.is(DEBUG1) &&
glog <<
"Reading " << escape - last_escape_
234 <<
" more bytes because of escape characters." << std::endl;
236 last_escape_ = escape;
245 void remove_escapes()
247 if (last_escape_ == 0)
251 int before_size = message_.size();
252 boost::replace_all(message_, std::string(1, SV2_ESCAPE) + std::string(1, 0x5E),
253 std::string(1, SV2_MAGIC_BYTE));
254 boost::replace_all(message_, std::string(1, SV2_ESCAPE) + std::string(1, 0x5D),
255 std::string(1, SV2_ESCAPE));
256 int after_size = message_.size();
258 message_insert_ -= (before_size - after_size);
259 message_.resize(before_size);
260 last_escape_ = std::count(message_.begin(), message_.end(), SV2_ESCAPE);
263 void add_escapes(std::string* message)
266 boost::replace_all(*message, std::string(1, SV2_ESCAPE),
267 std::string(1, SV2_ESCAPE) + std::string(1, 0x5D));
268 boost::replace_all(*message, std::string(1, SV2_MAGIC_BYTE),
269 std::string(1, SV2_ESCAPE) + std::string(1, 0x5E));
271 boost::replace_first(*message, std::string(1, SV2_ESCAPE) + std::string(1, 0x5E),
272 std::string(1, SV2_MAGIC_BYTE));
276 boost::asio::serial_port socket_;
277 boost::asio::streambuf buffer_;
278 std::vector<char> message_;
279 char* message_insert_;
285 SV2_MAGIC_BYTE = 0x7e,
common::FlexOstream glog
Access the Goby logger through this object.
The global namespace for the Goby project.