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/version.h>
10#include <goby/middleware/io/detail/serial_interface.h>
49template <
const goby::middleware::Group& line_in_group,
50 const goby::middleware::Group& line_out_group,
51 goby::middleware::io::PubSubLayer publish_layer =
52 goby::middleware::io::PubSubLayer::INTERPROCESS,
53 goby::middleware::io::PubSubLayer subscribe_layer =
54 goby::middleware::io::PubSubLayer::INTERTHREAD,
55#if GOBY_VERSION_MAJOR == 3 && GOBY_VERSION_MINOR < 4
56 template <
class>
class ThreadType = goby::middleware::SimpleThread,
58 template <
class>
class ThreadType = goby::zeromq::SimpleThread,
60 bool use_indexed_groups =
false>
62 :
public goby::middleware::io::detail::SerialThread<line_in_group, line_out_group,
63 publish_layer, subscribe_layer, ThreadType,
67 goby::middleware::io::detail::SerialThread<line_in_group, line_out_group, publish_layer,
68 subscribe_layer, ThreadType, use_indexed_groups>;
79 void async_read()
override;
81 void read_first_byte();
87 std::array<char, SERIAL_MAX_SIZE> buffer_;
88 char* buffer_write_ptr_{buffer_.data()};
89 std::uint16_t message_size_{0};
92template <
typename ProtobufMessage>
93ProtobufMessage
parse(
const goby::middleware::protobuf::IOData& io)
95 auto& data = io.data();
96 ProtobufMessage pb_msg;
107 pb_msg.ParseFromArray(&data[0] + prefix_size, data.size() - prefix_size);
111template <
typename ProtobufMessage>
112std::shared_ptr<goby::middleware::protobuf::IOData>
serialize(
const ProtobufMessage& pb_msg)
114 auto io = std::make_shared<goby::middleware::protobuf::IOData>();
116 std::string pb_encoded = pb_msg.SerializeAsString();
118 std::uint16_t size = pb_encoded.size();
120 static_cast<char>(size & 0xFF)};
126 std::string crc_data = std::string((
const char*)&
crc,
sizeof(
crc));
131 io->set_data(header_and_data + crc_data);
139template <
const goby::middleware::Group& line_in_group,
140 const goby::middleware::Group& line_out_group,
141 goby::middleware::io::PubSubLayer publish_layer,
142 goby::middleware::io::PubSubLayer subscribe_layer,
template <
class>
class ThreadType,
143 bool use_indexed_groups>
145 subscribe_layer, ThreadType,
146 use_indexed_groups>::async_read()
148 buffer_write_ptr_ = buffer_.data();
152template <
const goby::middleware::Group& line_in_group,
153 const goby::middleware::Group& line_out_group,
154 goby::middleware::io::PubSubLayer publish_layer,
155 goby::middleware::io::PubSubLayer subscribe_layer,
template <
class>
class ThreadType,
156 bool use_indexed_groups>
158 subscribe_layer, ThreadType,
159 use_indexed_groups>::read_first_byte()
161 boost::asio::async_read(
162 this->mutable_serial_port(),
163 boost::asio::buffer(buffer_write_ptr_,
164 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
165 boost::asio::transfer_exactly(1),
166 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
167 if (!ec && bytes_transferred > 0)
169 if (buffer_[0] != SERIAL_MAGIC[0])
171 goby::glog.is_warn() &&
172 goby::glog <<
"Invalid first byte, expected: " << SERIAL_MAGIC[0]
173 <<
", received: " << buffer_[0] << std::endl;
178 buffer_write_ptr_ += bytes_transferred;
184 this->handle_read_error(ec);
189template <
const goby::middleware::Group& line_in_group,
190 const goby::middleware::Group& line_out_group,
191 goby::middleware::io::PubSubLayer publish_layer,
192 goby::middleware::io::PubSubLayer subscribe_layer,
template <
class>
class ThreadType,
193 bool use_indexed_groups>
195 subscribe_layer, ThreadType,
196 use_indexed_groups>::read_magic()
198 boost::asio::async_read(
199 this->mutable_serial_port(),
200 boost::asio::buffer(buffer_write_ptr_,
201 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
202 boost::asio::transfer_exactly(SERIAL_MAGIC_BYTES - 1),
203 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
204 if (!ec && bytes_transferred > 0)
206 if (memcmp(buffer_.data(), SERIAL_MAGIC, SERIAL_MAGIC_BYTES) != 0)
208 goby::glog.is_warn() &&
210 <<
"Invalid magic word, expected: " << SERIAL_MAGIC <<
", received: "
211 << std::string(buffer_.data(), buffer_.data() + SERIAL_MAGIC_BYTES)
217 buffer_write_ptr_ += bytes_transferred;
223 this->handle_read_error(ec);
228template <
const goby::middleware::Group& line_in_group,
229 const goby::middleware::Group& line_out_group,
230 goby::middleware::io::PubSubLayer publish_layer,
231 goby::middleware::io::PubSubLayer subscribe_layer,
template <
class>
class ThreadType,
232 bool use_indexed_groups>
234 subscribe_layer, ThreadType,
235 use_indexed_groups>::read_size()
237 boost::asio::async_read(
238 this->mutable_serial_port(),
239 boost::asio::buffer(buffer_write_ptr_,
240 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
241 boost::asio::transfer_exactly(SIZE_BYTES),
242 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
243 if (!ec && bytes_transferred > 0)
246 message_size_ |= buffer_[SERIAL_MAGIC_BYTES];
247 message_size_ <<= BITS_IN_BYTE;
248 message_size_ |= buffer_[SERIAL_MAGIC_BYTES + 1];
249 if (message_size_ > jaiabot_protobuf_LoRaMessage_size)
251 goby::glog.is_warn() && goby::glog
252 <<
"Reported message size is larger than Protobuf "
253 "LoraMessage maximum size. Reported:"
254 << message_size_ <<
", expected max: "
255 << jaiabot_protobuf_LoRaMessage_size << std::endl;
261 buffer_write_ptr_ += bytes_transferred;
267 this->handle_read_error(ec);
272template <
const goby::middleware::Group& line_in_group,
273 const goby::middleware::Group& line_out_group,
274 goby::middleware::io::PubSubLayer publish_layer,
275 goby::middleware::io::PubSubLayer subscribe_layer,
template <
class>
class ThreadType,
276 bool use_indexed_groups>
278 subscribe_layer, ThreadType,
279 use_indexed_groups>::read_body()
281 boost::asio::async_read(
282 this->mutable_serial_port(),
283 boost::asio::buffer(buffer_write_ptr_,
284 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
285 boost::asio::transfer_exactly(message_size_),
286 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
287 if (!ec && bytes_transferred > 0)
291 buffer_write_ptr_ += bytes_transferred;
292 auto io_msg = std::make_shared<goby::middleware::protobuf::IOData>();
293 io_msg->set_data(std::string(buffer_.data(), buffer_write_ptr_));
294 this->handle_read_success(buffer_write_ptr_ - buffer_.data(), io_msg);
299 this->handle_read_error(ec);
Reads/Writes LoRa Adafruit feather message packages from/to serial port.
SerialThreadFletcher16(const goby::middleware::protobuf::SerialConfig &config, int index=-1)
~SerialThreadFletcher16()
uint16_t fletcher16(const void *input_str, size_t num_bytes)
Calculate the Fletcher-16 checksum of a block of data.
ProtobufMessage parse(const goby::middleware::protobuf::IOData &io)
constexpr int SERIAL_MAGIC_BYTES
constexpr const char * SERIAL_MAGIC
std::shared_ptr< goby::middleware::protobuf::IOData > serialize(const ProtobufMessage &pb_msg)
constexpr int BITS_IN_BYTE
constexpr auto SERIAL_MAX_SIZE