serialization.h
Go to the documentation of this file.
1 //==============================================================================
2 // Copyright (c) 2012, Johannes Meyer, TU Darmstadt
3 // All rights reserved.
4 
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // * Neither the name of the Flight Systems and Automatic Control group,
13 // TU Darmstadt, nor the names of its contributors may be used to
14 // endorse or promote products derived from this software without
15 // specific prior written permission.
16 
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //==============================================================================
28 
29 #ifndef UBLOX_SERIALIZATION_H
30 #define UBLOX_SERIALIZATION_H
31 
32 #include <ros/console.h>
33 #include <stdint.h>
34 #include <boost/call_traits.hpp>
35 #include <vector>
36 #include <algorithm>
37 
38 #include "checksum.h"
39 
48 
49 
54 namespace ublox {
55 
57 static const uint8_t DEFAULT_SYNC_A = 0xB5;
59 static const uint8_t DEFAULT_SYNC_B = 0x62;
61 static const uint32_t kMaxPayloadLength = 8184; // == (buffer size - header length - checksum length)
63 static const uint8_t kHeaderLength = 6;
65 static const uint8_t kChecksumLength = 2;
66 
70 template <typename T>
71 struct Serializer {
78  static void read(const uint8_t *data, uint32_t count,
79  typename boost::call_traits<T>::reference message);
87  static uint32_t serializedLength(
88  typename boost::call_traits<T>::param_type message);
89 
96  static void write(uint8_t *data, uint32_t size,
97  typename boost::call_traits<T>::param_type message);
98 };
99 
104 template <typename T>
105 class Message {
106  public:
113  static bool canDecode(uint8_t class_id, uint8_t message_id) {
114  return std::find(keys_.begin(), keys_.end(),
115  std::make_pair(class_id, message_id)) != keys_.end();
116  }
117 
124  static void addKey(uint8_t class_id, uint8_t message_id) {
125  keys_.push_back(std::make_pair(class_id, message_id));
126  }
127 
129  {
130  StaticKeyInitializer(uint8_t class_id, uint8_t message_id) {
131  Message<T>::addKey(class_id, message_id);
132  }
133  };
134 
135  private:
136  static std::vector<std::pair<uint8_t,uint8_t> > keys_;
137 };
138 
142 struct Options {
150  uint8_t sync_a;
152  uint8_t sync_b;
156  uint8_t header_length;
158  uint8_t checksum_length;
159 
165  return header_length + checksum_length;
166  }
167 };
168 
172 class Reader {
173  public:
180  Reader(const uint8_t *data, uint32_t count,
181  const Options &options = Options()) :
182  data_(data), count_(count), found_(false), options_(options)
183  {
184  unused_data_.reserve(1024);
185  }
186 
187  typedef const uint8_t *iterator;
188 
194  {
195  if (found_) next();
196  // Search for a message header
197  for( ; count_ > 0; --count_, ++data_) {
198  if (data_[0] == options_.sync_a &&
199  (count_ == 1 || data_[1] == options_.sync_b)) {
200  // Ignore messages which exceed the maximum payload length
202  // Message exceeds maximum payload length
203  ROS_ERROR("U-Blox message exceeds maximum payload length %u: "
204  "0x%02x / 0x%02x", options_.max_payload_length,
205  classId(), messageId());
206  continue;
207  }
208  break;
209  }
210  else {
211  unused_data_.push_back(data_[0]);
212  }
213  }
214 
215  return data_;
216  }
217 
222  bool found()
223  {
224  if (found_) return true;
225  // Verify message is long enough to have sync chars, id, length & checksum
226  if (count_ < options_.wrapper_length()) return false;
227  // Verify the header bits
228  if (data_[0] != options_.sync_a || data_[1] != options_.sync_b)
229  return false;
230  // Verify that the buffer length is long enough based on the received
231  // message length
232  if (count_ < length() + options_.wrapper_length()) return false;
233 
234  found_ = true;
235  return true;
236  }
237 
246  if (found()) {
247  uint32_t size = length() + options_.wrapper_length();
248  data_ += size; count_ -= size;
249  }
250  found_ = false;
251  return data_;
252  }
253 
259  return data_;
260  }
261 
263  return data_ + count_;
264  }
265 
266  uint8_t classId() { return data_[2]; }
267  uint8_t messageId() { return data_[3]; }
268 
276  uint32_t length() {
277  if (count_ < 6) return 0u;
278  return (data_[5] << 8) + data_[4];
279  }
280  const uint8_t *data() { return data_ + options_.header_length; }
281 
287  uint16_t checksum() {
288  return *reinterpret_cast<const uint16_t *>(data_ + options_.header_length +
289  length());
290  }
291 
297  template <typename T>
298  bool read(typename boost::call_traits<T>::reference message,
299  bool search = false) {
300  if (search) this->search();
301  if (!found()) return false;
302  if (!Message<T>::canDecode(classId(), messageId())) return false;
303 
304  uint16_t chk;
305  if (calculateChecksum(data_ + 2, length() + 4, chk) != this->checksum()) {
306  // checksum error
307  ROS_DEBUG("U-Blox read checksum error: 0x%02x / 0x%02x", classId(),
308  messageId());
309  return false;
310  }
311 
313  return true;
314  }
315 
321  template <typename T>
322  bool hasType() {
323  if (!found()) return false;
325  }
326 
332  bool isMessage(uint8_t class_id, uint8_t message_id) {
333  if (!found()) return false;
334  return (classId() == class_id && messageId() == message_id);
335  }
336 
337  const std::string& getUnusedData() const { return unused_data_; }
338 
339  private:
341  const uint8_t *data_;
343  std::string unused_data_;
345  uint32_t count_;
347  bool found_;
350 };
351 
355 class Writer {
356  public:
357  typedef uint8_t *iterator;
358 
365  Writer(uint8_t *data, uint32_t size, const Options &options = Options()) :
366  data_(data), size_(size), options_(options) {}
367 
375  template <typename T> bool write(const T& message,
376  uint8_t class_id = T::CLASS_ID,
377  uint8_t message_id = T::MESSAGE_ID) {
378  // Check for buffer overflow
379  uint32_t length = Serializer<T>::serializedLength(message);
380  if (size_ < length + options_.wrapper_length()) {
381  ROS_ERROR("u-blox write buffer overflow. Message %u / %u not written",
382  class_id, message_id);
383  return false;
384  }
385  // Encode the message and add it to the buffer
387  size_ - options_.header_length, message);
388  return write(0, length, class_id, message_id);
389  }
390 
400  bool write(const uint8_t* message, uint32_t length, uint8_t class_id,
401  uint8_t message_id) {
402  if (size_ < length + options_.wrapper_length()) {
403  ROS_ERROR("u-blox write buffer overflow. Message %u / %u not written",
404  class_id, message_id);
405  return false;
406  }
407  iterator start = data_;
408 
409  // write header
410  *data_++ = options_.sync_a;
411  *data_++ = options_.sync_b;
412  *data_++ = class_id;
413  *data_++ = message_id;
414  *data_++ = length & 0xFF;
415  *data_++ = (length >> 8) & 0xFF;
417 
418  // write message
419  if (message) std::copy(message, message + length, data_);
420  data_ += length;
421  size_ -= length;
422 
423  // write checksum
424  uint8_t ck_a, ck_b;
425  calculateChecksum(start + 2, length + 4, ck_a, ck_b);
426  *data_++ = ck_a;
427  *data_++ = ck_b;
429 
430  return true;
431  }
432 
434  return data_;
435  }
436 
437  private:
441 
442  uint32_t size_;
445 };
446 
447 } // namespace ublox
448 
449 // Use to declare u-blox messages and message serializers
450 #define DECLARE_UBLOX_MESSAGE(class_id, message_id, package, message) \
451  template class ublox::Serializer<package::message>; \
452  template class ublox::Message<package::message>; \
453  namespace package { namespace { \
454  static const ublox::Message<message>::StaticKeyInitializer static_key_initializer_##message(class_id, message_id); \
455  } } \
456 
457 // Use for messages which have the same structure but different IDs, e.g. INF
458 // Call DECLARE_UBLOX_MESSAGE for the first message and DECLARE_UBLOX_MESSAGE_ID
459 // for following declarations
460 #define DECLARE_UBLOX_MESSAGE_ID(class_id, message_id, package, message, name) \
461  namespace package { namespace { \
462  static const ublox::Message<message>::StaticKeyInitializer static_key_initializer_##name(class_id, message_id); \
463  } } \
464 
465 
466 // use implementation of class Serializer in "serialization_ros.h"
467 #include "serialization_ros.h"
468 
469 #endif // UBLOX_SERIALIZATION_H
ublox::Writer::write
bool write(const uint8_t *message, uint32_t length, uint8_t class_id, uint8_t message_id)
Wrap the encoded message payload with a header and checksum and add it to the buffer.
Definition: serialization.h:400
ublox::Reader::end
iterator end()
Definition: serialization.h:262
ublox::Serializer::serializedLength
static uint32_t serializedLength(typename boost::call_traits< T >::param_type message)
Get the length of the message payload in bytes.
Definition: serialization_ros.h:47
ublox::Reader::Reader
Reader(const uint8_t *data, uint32_t count, const Options &options=Options())
Definition: serialization.h:180
ublox::Options
Options for the Reader and Writer for encoding and decoding messages.
Definition: serialization.h:142
ublox::Reader::found_
bool found_
Whether or not a message has been found.
Definition: serialization.h:347
ublox::Writer::iterator
uint8_t * iterator
Definition: serialization.h:357
ublox
Definition: checksum.h:34
ublox::Reader::length
uint32_t length()
Get the length of the u-blox message payload.
Definition: serialization.h:276
ublox::Options::header_length
uint8_t header_length
The length of the message header in bytes (everything before the payload)
Definition: serialization.h:156
ublox::Options::sync_a
uint8_t sync_a
The sync_a byte value identifying the start of a message.
Definition: serialization.h:150
ublox::Writer::Writer
Writer(uint8_t *data, uint32_t size, const Options &options=Options())
Construct a Writer with the given buffer.
Definition: serialization.h:365
ublox::Options::checksum_length
uint8_t checksum_length
The length of the checksum in bytes.
Definition: serialization.h:158
ublox::Options::Options
Options()
Definition: serialization.h:146
ublox::Reader::pos
iterator pos()
Get the current position in the read buffer.
Definition: serialization.h:258
serialization_ros.h
ublox::Serializer
Encodes and decodes messages.
Definition: serialization.h:71
ublox::DEFAULT_SYNC_B
static const uint8_t DEFAULT_SYNC_B
u-blox message Sync B char
Definition: serialization.h:59
ublox::Message::keys_
static std::vector< std::pair< uint8_t, uint8_t > > keys_
Definition: serialization.h:136
ublox::kHeaderLength
static const uint8_t kHeaderLength
Number of bytes in a message header (Sync chars + class ID + message ID)
Definition: serialization.h:63
ublox::Reader::isMessage
bool isMessage(uint8_t class_id, uint8_t message_id)
Does the u-blox message have the given class and message ID?
Definition: serialization.h:332
ublox::calculateChecksum
static void calculateChecksum(const uint8_t *data, uint32_t size, uint8_t &ck_a, uint8_t &ck_b)
calculate the checksum of a u-blox_message
Definition: checksum.h:43
ublox::Options::sync_b
uint8_t sync_b
The sync_b byte value identifying the start of a message.
Definition: serialization.h:152
ublox::Reader::next
iterator next()
Go to the start of the next message based on the received message length.
Definition: serialization.h:245
ublox::Message::canDecode
static bool canDecode(uint8_t class_id, uint8_t message_id)
Can this message type decode a u-blox message with the given ID?
Definition: serialization.h:113
ublox::Reader::options_
Options options_
Options representing the sync char values, etc.
Definition: serialization.h:349
console.h
ublox::Message::StaticKeyInitializer
Definition: serialization.h:128
ublox::DEFAULT_SYNC_A
static const uint8_t DEFAULT_SYNC_A
u-blox message Sync A char
Definition: serialization.h:57
ublox::Reader::hasType
bool hasType()
Can the given message type decode the current message in the buffer?
Definition: serialization.h:322
ROS_DEBUG
#define ROS_DEBUG(...)
ublox::Message::addKey
static void addKey(uint8_t class_id, uint8_t message_id)
Indicate that this message type can decode u-blox messages with the given ID.
Definition: serialization.h:124
ublox::Writer
Encodes a u-blox ROS message as a byte array.
Definition: serialization.h:355
ublox::Reader::search
iterator search()
Search the buffer for the beginning of the next u-blox message.
Definition: serialization.h:193
ublox::Reader::messageId
uint8_t messageId()
Definition: serialization.h:267
checksum.h
ublox::Writer::options_
Options options_
Options representing the sync char values, etc.
Definition: serialization.h:444
ublox::Reader
Decodes byte messages into u-blox ROS messages.
Definition: serialization.h:172
ublox::Writer::write
bool write(const T &message, uint8_t class_id=T::CLASS_ID, uint8_t message_id=T::MESSAGE_ID)
Encode the u-blox message.
Definition: serialization.h:375
ublox::Reader::data
const uint8_t * data()
Definition: serialization.h:280
ublox::Reader::data_
const uint8_t * data_
The buffer of message bytes.
Definition: serialization.h:341
start
ROSCPP_DECL void start()
ublox::Writer::end
iterator end()
Definition: serialization.h:433
ublox::Writer::data_
iterator data_
The buffer of message bytes.
Definition: serialization.h:439
ublox::Serializer::write
static void write(uint8_t *data, uint32_t size, typename boost::call_traits< T >::param_type message)
Encode the message payload as a byte array.
Definition: serialization_ros.h:53
ublox::Reader::classId
uint8_t classId()
Definition: serialization.h:266
ublox::Reader::found
bool found()
Has a u-blox message been found in the buffer?
Definition: serialization.h:222
ublox::Reader::count_
uint32_t count_
the number of bytes in the buffer, //! decrement as the buffer is read
Definition: serialization.h:345
ublox::Reader::read
bool read(typename boost::call_traits< T >::reference message, bool search=false)
Decode the given message.
Definition: serialization.h:298
ublox::Reader::checksum
uint16_t checksum()
Get the checksum of the u-blox message.
Definition: serialization.h:287
ublox::kMaxPayloadLength
static const uint32_t kMaxPayloadLength
Maximum payload length.
Definition: serialization.h:61
ROS_ERROR
#define ROS_ERROR(...)
ublox::Writer::size_
uint32_t size_
The number of remaining bytes in the buffer.
Definition: serialization.h:442
ublox::Reader::getUnusedData
const std::string & getUnusedData() const
Definition: serialization.h:337
ublox::kChecksumLength
static const uint8_t kChecksumLength
Number of checksum bytes in the u-blox message.
Definition: serialization.h:65
ublox::Reader::unused_data_
std::string unused_data_
Unused data from the read buffer, contains nmea messages.
Definition: serialization.h:343
ublox::Message
Keeps track of which class and message IDs can be decoded by a given message type.
Definition: serialization.h:105
ublox::Options::wrapper_length
int wrapper_length()
Get the number of bytes in the header and footer.
Definition: serialization.h:164
ublox::Options::max_payload_length
uint32_t max_payload_length
The maximum payload length.
Definition: serialization.h:154
ublox::Reader::iterator
const typedef uint8_t * iterator
Definition: serialization.h:187
ublox::Serializer::read
static void read(const uint8_t *data, uint32_t count, typename boost::call_traits< T >::reference message)
Decode the message payload from the data buffer.
Definition: serialization_ros.h:40
ublox::Message::StaticKeyInitializer::StaticKeyInitializer
StaticKeyInitializer(uint8_t class_id, uint8_t message_id)
Definition: serialization.h:130


ublox_serialization
Author(s): Johannes Meyer
autogenerated on Wed Dec 7 2022 03:47:50