2 #ifndef JAIABOT_LORA_SERIAL_H
3 #define JAIABOT_LORA_SERIAL_H
5 #include <boost/asio.hpp>
8 #include "goby/middleware/io/detail/io_interface.h"
9 #include "goby/middleware/io/detail/serial_interface.h"
47 template <
const goby::middleware::Group& line_in_group,
48 const goby::middleware::Group& line_out_group,
49 goby::middleware::io::PubSubLayer publish_layer =
50 goby::middleware::io::PubSubLayer::INTERPROCESS,
51 goby::middleware::io::PubSubLayer subscribe_layer =
52 goby::middleware::io::PubSubLayer::INTERTHREAD,
53 template <
class>
class ThreadType = goby::middleware::SimpleThread,
54 bool use_indexed_groups =
false>
56 :
public goby::middleware::io::detail::SerialThread<line_in_group, line_out_group,
57 publish_layer, subscribe_layer, ThreadType,
61 goby::middleware::io::detail::SerialThread<line_in_group, line_out_group, publish_layer,
62 subscribe_layer, ThreadType, use_indexed_groups>;
73 void async_read()
override;
75 void read_first_byte();
81 std::array<char, SERIAL_MAX_SIZE> buffer_;
82 char* buffer_write_ptr_{buffer_.data()};
83 std::uint16_t message_size_{0};
86 template <
typename ProtobufMessage>
87 ProtobufMessage
parse(
const goby::middleware::protobuf::IOData& io)
89 auto& data = io.data();
90 ProtobufMessage pb_msg;
101 pb_msg.ParseFromArray(&data[0] + prefix_size, data.size() - prefix_size);
105 template <
typename ProtobufMessage>
106 std::shared_ptr<goby::middleware::protobuf::IOData>
serialize(
const ProtobufMessage& pb_msg)
108 auto io = std::make_shared<goby::middleware::protobuf::IOData>();
110 std::string pb_encoded = pb_msg.SerializeAsString();
112 std::uint16_t size = pb_encoded.size();
114 static_cast<char>(size & 0xFF)};
119 auto crc =
fletcher16(&pb_encoded[0], pb_encoded.size());
120 std::string crc_data = std::string((
const char*)&crc,
sizeof(crc));
125 io->set_data(header_and_data + crc_data);
133 template <
const goby::middleware::Group& line_in_group,
134 const goby::middleware::Group& line_out_group,
135 goby::middleware::io::PubSubLayer publish_layer,
136 goby::middleware::io::PubSubLayer subscribe_layer,
template <
class>
class ThreadType,
137 bool use_indexed_groups>
139 subscribe_layer, ThreadType,
140 use_indexed_groups>::async_read()
142 buffer_write_ptr_ = buffer_.data();
146 template <
const goby::middleware::Group& line_in_group,
147 const goby::middleware::Group& line_out_group,
148 goby::middleware::io::PubSubLayer publish_layer,
149 goby::middleware::io::PubSubLayer subscribe_layer,
template <
class>
class ThreadType,
150 bool use_indexed_groups>
152 subscribe_layer, ThreadType,
153 use_indexed_groups>::read_first_byte()
155 boost::asio::async_read(
156 this->mutable_serial_port(),
157 boost::asio::buffer(buffer_write_ptr_,
158 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
159 boost::asio::transfer_exactly(1),
160 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
161 if (!ec && bytes_transferred > 0)
163 if (buffer_[0] != SERIAL_MAGIC[0])
165 goby::glog.is_warn() &&
166 goby::glog <<
"Invalid first byte, expected: " << SERIAL_MAGIC[0]
167 <<
", received: " << buffer_[0] << std::endl;
172 buffer_write_ptr_ += bytes_transferred;
178 this->handle_read_error(ec);
183 template <
const goby::middleware::Group& line_in_group,
184 const goby::middleware::Group& line_out_group,
185 goby::middleware::io::PubSubLayer publish_layer,
186 goby::middleware::io::PubSubLayer subscribe_layer,
template <
class>
class ThreadType,
187 bool use_indexed_groups>
189 subscribe_layer, ThreadType,
190 use_indexed_groups>::read_magic()
192 boost::asio::async_read(
193 this->mutable_serial_port(),
194 boost::asio::buffer(buffer_write_ptr_,
195 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
197 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
198 if (!ec && bytes_transferred > 0)
200 if (memcmp(buffer_.data(), SERIAL_MAGIC, SERIAL_MAGIC_BYTES) != 0)
202 goby::glog.is_warn() &&
204 <<
"Invalid magic word, expected: " << SERIAL_MAGIC <<
", received: "
205 << std::string(buffer_.data(), buffer_.data() + SERIAL_MAGIC_BYTES)
211 buffer_write_ptr_ += bytes_transferred;
217 this->handle_read_error(ec);
222 template <
const goby::middleware::Group& line_in_group,
223 const goby::middleware::Group& line_out_group,
224 goby::middleware::io::PubSubLayer publish_layer,
225 goby::middleware::io::PubSubLayer subscribe_layer,
template <
class>
class ThreadType,
226 bool use_indexed_groups>
228 subscribe_layer, ThreadType,
229 use_indexed_groups>::read_size()
231 boost::asio::async_read(
232 this->mutable_serial_port(),
233 boost::asio::buffer(buffer_write_ptr_,
234 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
236 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
237 if (!ec && bytes_transferred > 0)
240 message_size_ |= buffer_[SERIAL_MAGIC_BYTES];
241 message_size_ <<= BITS_IN_BYTE;
242 message_size_ |= buffer_[SERIAL_MAGIC_BYTES + 1];
243 if (message_size_ > jaiabot_protobuf_LoRaMessage_size)
245 goby::glog.is_warn() && goby::glog
246 <<
"Reported message size is larger than Protobuf "
247 "LoraMessage maximum size. Reported:"
248 << message_size_ <<
", expected max: "
249 << jaiabot_protobuf_LoRaMessage_size << std::endl;
255 buffer_write_ptr_ += bytes_transferred;
261 this->handle_read_error(ec);
266 template <
const goby::middleware::Group& line_in_group,
267 const goby::middleware::Group& line_out_group,
268 goby::middleware::io::PubSubLayer publish_layer,
269 goby::middleware::io::PubSubLayer subscribe_layer,
template <
class>
class ThreadType,
270 bool use_indexed_groups>
272 subscribe_layer, ThreadType,
273 use_indexed_groups>::read_body()
275 boost::asio::async_read(
276 this->mutable_serial_port(),
277 boost::asio::buffer(buffer_write_ptr_,
278 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
279 boost::asio::transfer_exactly(message_size_),
280 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
281 if (!ec && bytes_transferred > 0)
283 buffer_write_ptr_ += bytes_transferred;
284 auto io_msg = std::make_shared<goby::middleware::protobuf::IOData>();
285 io_msg->set_data(std::string(buffer_.data(), buffer_write_ptr_));
286 this->handle_read_success(buffer_write_ptr_ - buffer_.data(), io_msg);
291 this->handle_read_error(ec);