hideakitai / MsgPacketizer

msgpack based serializer / deserializer + packetize for Arduino, ROS, and more

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

C++ library?

stwirth opened this issue · comments

Thanks for this great work @hideakitai!
I find it really useful to use msgpack on Arduino. Now I'm looking on how to de-code the packets on the receiver end (which in my case is a Linux computer). When using MsgPacketizer on the Arduino, what do I need in my C++ program to do the unpacking? I am seeing an add-on for openFrameworks but I'm not using that.
When I try to compile a simple example program with g++ --std=c++14 that includes MsgPacketizer.h I'm running into a bunch of errors.

 g++ main.cpp --std=c++14
In file included from main.cpp:19:0:
MsgPacketizer.h: In member function ‘bool ht::serial::msgpacketizer::element::Base::next() const’:
MsgPacketizer.h:70:55: error: ‘ELAPSED_MICROS’ was not declared in this scope
             bool next() const { return ELAPSED_MICROS() >= (last_publish_us + interval_us); }
                                                       ^
MsgPacketizer.h: At global scope:
MsgPacketizer.h:169:9: error: ‘StreamType’ does not name a type
         StreamType* stream;
         ^
MsgPacketizer.h:176:27: error: ‘StreamType’ does not name a type
         Destination(const StreamType& stream, const uint8_t index)
                           ^

I'm trying to provide the corresponding #defines but still no luck:

$ cat main.cpp 

#include <iostream>

using StreamType = std::iostream;

// dummy
unsigned long micros()
{
  return 0;
}

#define ELAPSED_MICROS micros
#define PACKETIZER_ENABLE_STREAM
#define PACKETIZER_STREAM_WRITE(stream, data, size) stream.write(data, size);


#include "MsgPacketizer.h"

int main(int argc, char **argv)
{
  return 0;
}
$ g++ main.cpp --std=c++14
util/Packetizer/Packetizer.h: In instantiation of ‘void ht::serial::packetizer::send(StreamType&, uint8_t, const uint8_t*, size_t) [with Encoding = ht::serial::packetizer::encoding::COBS; StreamType = std::basic_iostream<char>; uint8_t = unsigned char; size_t = long unsigned int]’:
MsgPacketizer.h:251:86:   required from here
util/Packetizer/Packetizer.h:244:33: error: invalid conversion from ‘const unsigned char*’ to ‘const char*’ [-fpermissive]
         PACKETIZER_STREAM_WRITE(stream, packet.data.data(), packet.data.size());
                                 ^
main.cpp:14:53: note: in definition of macro ‘PACKETIZER_STREAM_WRITE’
 #define PACKETIZER_STREAM_WRITE(stream, data, size) stream.write(data, size);
                                                     ^
In file included from /usr/include/c++/5/ostream:638:0,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:2:
/usr/include/c++/5/bits/ostream.tcc:182:5: note:   initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::write(const _CharT*, std::streamsize) [with _CharT = char; _Traits = std::char_traits<char>; std::streamsize = long int]’
     basic_ostream<_CharT, _Traits>::
     ^
In file included from MsgPacketizer.h:12:0,
                 from main.cpp:17:
util/Packetizer/Packetizer.h: In instantiation of ‘void ht::serial::packetizer::DecodeManager<Encoding>::parse(bool) [with Encoding = ht::serial::packetizer::encoding::COBS]’:
util/Packetizer/Packetizer.h:497:9:   required from ‘void ht::serial::packetizer::parse(bool) [with Encoding = ht::serial::packetizer::encoding::COBS]’
MsgPacketizer.h:557:36:   required from here
util/Packetizer/Packetizer.h:317:45: error: ‘class std::basic_iostream<char>’ has no member named ‘available’
                 while (d.first->available() > 0)
                                             ^
util/Packetizer/Packetizer.h:319:57: error: ‘class std::basic_iostream<char>’ has no member named ‘available’
                     const int size = d.first->available();
                                                         ^
util/Packetizer/Packetizer.h:321:21: error: ‘class std::basic_iostream<char>’ has no member named ‘readBytes’
                     d.first->readBytes((char*)data, size);
                     ^

So do I need to implement my own stream class?

Without #define PACKETIZER_ENABLE_STREAM I get:

$ g++ main.cpp --std=c++14
In file included from main.cpp:17:0:
MsgPacketizer.h: In member function ‘void ht::serial::msgpacketizer::PackerManager::send(const ht::serial::msgpacketizer::Destination&, ht::serial::msgpacketizer::PublishElementRef)’:
MsgPacketizer.h:251:13: error: ‘send’ is not a member of ‘Packetizer’
             Packetizer::send(*dest.stream, dest.index, encoder.data(), encoder.size());
             ^
MsgPacketizer.h: In function ‘void ht::serial::msgpacketizer::send(StreamType&, uint8_t, Args&& ...)’:
MsgPacketizer.h:349:9: error: ‘send’ is not a member of ‘Packetizer’
         Packetizer::send(stream, index, packer.data(), packer.size());
         ^
MsgPacketizer.h:349:9: note: suggested alternative:
MsgPacketizer.h:344:17: note:   ‘ht::serial::msgpacketizer::send’
     inline void send(StreamType& stream, const uint8_t index, Args&&... args)
                 ^
MsgPacketizer.h: In function ‘void ht::serial::msgpacketizer::send(StreamType&, uint8_t, const uint8_t*, uint8_t)’:
MsgPacketizer.h:357:9: error: ‘send’ is not a member of ‘Packetizer’
         Packetizer::send(stream, index, packer.data(), packer.size());
         ^
MsgPacketizer.h:357:9: note: suggested alternative:
MsgPacketizer.h:352:17: note:   ‘ht::serial::msgpacketizer::send’
     inline void send(StreamType& stream, const uint8_t index, const uint8_t* data, const uint8_t size)
                 ^
MsgPacketizer.h: In function ‘void ht::serial::msgpacketizer::send(StreamType&, uint8_t)’:
MsgPacketizer.h:363:9: error: ‘send’ is not a member of ‘Packetizer’
         Packetizer::send(stream, index, packer.data(), packer.size());
         ^
MsgPacketizer.h:363:9: note: suggested alternative:
MsgPacketizer.h:360:17: note:   ‘ht::serial::msgpacketizer::send’
     inline void send(StreamType& stream, const uint8_t index)
                 ^
MsgPacketizer.h: In function ‘void ht::serial::msgpacketizer::send_arr(StreamType&, uint8_t, Args&& ...)’:
MsgPacketizer.h:372:9: error: ‘send’ is not a member of ‘Packetizer’
         Packetizer::send(stream, index, packer.data(), packer.size());
         ^
MsgPacketizer.h:372:9: note: suggested alternative:
MsgPacketizer.h:360:17: note:   ‘ht::serial::msgpacketizer::send’
     inline void send(StreamType& stream, const uint8_t index)
                 ^
MsgPacketizer.h: In function ‘void ht::serial::msgpacketizer::send_map(StreamType&, uint8_t, Args&& ...)’:
MsgPacketizer.h:383:13: error: ‘send’ is not a member of ‘Packetizer’
             Packetizer::send(stream, index, packer.data(), packer.size());
             ^
MsgPacketizer.h:383:13: note: suggested alternative:
MsgPacketizer.h:360:17: note:   ‘ht::serial::msgpacketizer::send’
     inline void send(StreamType& stream, const uint8_t index)
                 ^
MsgPacketizer.h: In function ‘void ht::serial::msgpacketizer::parse(bool)’:
MsgPacketizer.h:557:9: error: ‘parse’ is not a member of ‘Packetizer’
         Packetizer::parse(b_exec_cb);
         ^
MsgPacketizer.h:557:9: note: suggested alternative:
MsgPacketizer.h:555:17: note:   ‘ht::serial::msgpacketizer::parse’
     inline void parse(bool b_exec_cb = true)
                 ^
MsgPacketizer.h: In function ‘void ht::serial::msgpacketizer::update(bool)’:
MsgPacketizer.h:574:9: error: ‘parse’ is not a member of ‘Packetizer’
         Packetizer::parse(b_exec_cb);
         ^
MsgPacketizer.h:574:9: note: suggested alternative:
MsgPacketizer.h:555:17: note:   ‘ht::serial::msgpacketizer::parse’
     inline void parse(bool b_exec_cb = true)
                 ^

@stwirth Hi, currently this library supports only Arduino and openFramewroks because this library needs serial class. One easy and reliable solution is to import ofSerial to this library for other situation (without Arduino and openFrameworks). I will try it somewhere in this week.

I am currently using another library for the serial communication but what I'd like to use from this project is the packet format. Maybe using Packetizer directly would be a better fit?

@stwirth Sorry for late reply. You can encode/decode manually by using MsgPack and Packetizer.

// serialize
MsgPack::Packer packer;
packer.serialize(i, f, s, v, m);
const auto&  packet = Packetizer::encode(index, packer.data(), packer.size());
send(packet.data(), packet.size()); // use your serial object
// deserialize
const auto& packet = Packetizer::decode(data.data(), data.size()); // data: your data from serial
MsgPack::Unpacker unpacker;
unpacker.feed(packet.data(), packet.size()); 
unpacker.deserialize(i, f, s, v, m)

I haven't tested but you can do like above code.

Has this been tested? I am interested in using this but I need to make sure that it will work in my setup. I did some quick testing and got the code to compile with the Packetizer and MsgPack header files but when I run the program with this serial library the program does not seem to terminate correctly.

  serial::Serial con{"/dev/ttyACM0", 115200,
                     serial::Timeout::simpleTimeout(10),
                     serial::eightbits,
                     serial::parity_even,
                     serial::stopbits_one,
                     serial::flowcontrol_none};

// serialize
  MsgPack::Packer packer;
  packer.serialize(0, 1, 2, 3, 4);
  Packetizer::Packet  packet = Packetizer::encode(0x00, packer.data(), packer.size());
  auto data = packet.data.data();
  auto size = packet.data.size();
  con.write(packet.data.data(), packet.data.size()); // use your serial object
  std::cout << "Data sent" << std::endl;

Also, without MsgPacketizer what is the suggested way of robustly parsing the packets from the bytes returned from the serial library?

I haven't tested the above code and I don't know why your code fails because I can't see the your whole code.

PacketSerial is similar to this library which uses COBS/SLIP but without CRC error check. I've not tested but want to try PJON.

I'm going to close this issue. If someone can contribute to this issue, please feel free to send me a pull request.

@stwirth @Michael-Equi Hi, I've released the support for just serializing / deserializing function for various communication interfaces. If you are interested, please give it a try. Please see this example for the details https://github.com/hideakitai/MsgPacketizer/blob/master/examples/simple/arduino/simple_bind_lambda_manual/simple_bind_lambda_manual.ino