2 #ifndef JAIABOT_SERIAL_CRC32_H
3 #define JAIABOT_SERIAL_CRC32_H
5 #include <boost/asio.hpp>
8 #include "goby/middleware/io/detail/io_interface.h"
9 #include "goby/middleware/io/detail/serial_interface.h"
44 static const std::shared_ptr<goby::middleware::protobuf::IOData>
47 std::uint16_t size = data.length();
49 static_cast<char>(size & 0xFF)};
53 for (
int i = 0; i < 4; i++) { crc_data[i] = ((
char*)&
crc)[3 - i]; }
55 auto io_data = std::make_shared<goby::middleware::protobuf::IOData>();
57 string(crc_data, 4) + data);
62 static const std::string
decode_frame(
const std::string& frame_data)
65 auto size = frame_data.length() - HEADER_LENGTH;
69 return frame_data.substr(HEADER_LENGTH, size);
80 template <
const goby::middleware::Group& line_in_group,
81 const goby::middleware::Group& line_out_group,
82 goby::middleware::io::PubSubLayer publish_layer =
83 goby::middleware::io::PubSubLayer::INTERPROCESS,
84 goby::middleware::io::PubSubLayer subscribe_layer =
85 goby::middleware::io::PubSubLayer::INTERTHREAD,
86 template <
class>
class ThreadType = goby::middleware::SimpleThread,
87 bool use_indexed_groups =
false>
89 :
public goby::middleware::io::detail::SerialThread<line_in_group, line_out_group,
90 publish_layer, subscribe_layer, ThreadType,
94 goby::middleware::io::detail::SerialThread<line_in_group, line_out_group, publish_layer,
95 subscribe_layer, ThreadType, use_indexed_groups>;
106 void async_read()
override
108 buffer_write_ptr_ = buffer_.data();
112 void read_first_byte()
114 boost::asio::async_read(
115 this->mutable_serial_port(),
116 boost::asio::buffer(buffer_write_ptr_,
117 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
118 boost::asio::transfer_exactly(1),
119 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
120 if (!ec && bytes_transferred > 0)
122 if (buffer_[0] != SERIAL_MAGIC[0])
124 goby::glog.is_warn() &&
125 goby::glog <<
"Invalid first byte, expected: " << SERIAL_MAGIC[0]
126 <<
", received: " << buffer_[0] << std::endl;
131 buffer_write_ptr_ += bytes_transferred;
137 this->handle_read_error(ec);
144 boost::asio::async_read(
145 this->mutable_serial_port(),
146 boost::asio::buffer(buffer_write_ptr_,
147 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
149 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
150 if (!ec && bytes_transferred > 0)
152 if (memcmp(buffer_.data(), SERIAL_MAGIC, SERIAL_MAGIC_BYTES) != 0)
154 goby::glog.is_warn() &&
156 <<
"Invalid magic word, expected: " << SERIAL_MAGIC
158 << std::string(buffer_.data(), buffer_.data() + SERIAL_MAGIC_BYTES)
164 buffer_write_ptr_ += bytes_transferred;
170 this->handle_read_error(ec);
177 boost::asio::async_read(
178 this->mutable_serial_port(),
179 boost::asio::buffer(buffer_write_ptr_,
180 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
182 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
183 if (!ec && bytes_transferred > 0)
186 message_size_ |= buffer_[SERIAL_MAGIC_BYTES];
187 message_size_ <<= BITS_IN_BYTE;
188 message_size_ |= buffer_[SERIAL_MAGIC_BYTES + 1];
189 if (message_size_ > SERIAL_MAX_SIZE)
191 goby::glog.is_warn() &&
193 <<
"Reported message size is larger than SERIAL_MAX_SIZE. Reported:"
194 << message_size_ <<
", expected max: " << SERIAL_MAX_SIZE
201 buffer_write_ptr_ += bytes_transferred;
207 this->handle_read_error(ec);
214 boost::asio::async_read(
215 this->mutable_serial_port(),
216 boost::asio::buffer(buffer_write_ptr_,
217 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
218 boost::asio::transfer_exactly(
CRC_SIZE),
219 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
220 if (!ec && bytes_transferred > 0)
223 char* ptr = reinterpret_cast<char*>(&crc32_);
226 for (int i = 0; i < 4; i++) { ptr[3 - i] = buffer_write_ptr_[i]; }
228 buffer_write_ptr_ += bytes_transferred;
233 this->handle_read_error(ec);
240 boost::asio::async_read(
241 this->mutable_serial_port(),
242 boost::asio::buffer(buffer_write_ptr_,
243 buffer_.size() - (buffer_write_ptr_ - buffer_.data())),
244 boost::asio::transfer_exactly(message_size_),
245 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred) {
246 if (!ec && bytes_transferred > 0)
248 auto actual_crc32 = calculate_crc32(buffer_write_ptr_, bytes_transferred);
250 if (crc32_ != actual_crc32)
252 goby::glog.is_warn() &&
253 goby::glog <<
"message_size_: " << message_size_
254 <<
", bytes_transferred: " << bytes_transferred
255 <<
", expected crc32: " << crc32_
256 <<
", actual_crc32: " << actual_crc32 << std::endl;
258 goby::glog.is_warn() && goby::glog <<
"CRC32 failure. Expected: " << crc32_
259 <<
", actual: " << actual_crc32
265 buffer_write_ptr_ += bytes_transferred;
267 auto io_msg = std::make_shared<goby::middleware::protobuf::IOData>();
268 io_msg->set_data(std::string(buffer_.data(), buffer_write_ptr_));
269 this->handle_read_success(buffer_write_ptr_ - buffer_.data(), io_msg);
274 this->handle_read_error(ec);
280 std::array<char, SERIAL_MAX_SIZE> buffer_;
281 char* buffer_write_ptr_{buffer_.data()};
282 std::uint16_t message_size_{0};
283 std::uint32_t crc32_{0};
Reads/Writes message packages from/to serial port.
SerialThreadCRC32(const goby::middleware::protobuf::SerialConfig &config, int index=-1)
uint32_t calculate_crc32(const void *buf, size_t len, uint32_t initial=0)
constexpr int SERIAL_MAGIC_BYTES
static const std::string decode_frame(const std::string &frame_data)
constexpr const char * SERIAL_MAGIC
constexpr int BITS_IN_BYTE
static const std::shared_ptr< goby::middleware::protobuf::IOData > encode_frame(const std::string &data)
constexpr auto SERIAL_MAX_SIZE
extern ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< ::goby::acomms::protobuf::DriverConfig, ::PROTOBUF_NAMESPACE_ID::internal::MessageTypeTraits< ::jaiabot::udp::protobuf::Config >, 11, false > config