Giter Club home page Giter Club logo

msgpacketizer's Introduction

MsgPacketizer

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

NOTE (>= v0.5.0) : DEPENDENT LIBRARIES REMOVED

If you have already installed this library, please follow:

  • Cloned from GitHub (manually): Please install dependent libraries manually
  • Installed from library manager: re-install this library from library manager
    • Dependent libraries will be installed automatically

Feature

  • one-line [serialize/deserialize] or [publish/subscribe] + packetize + robust [send/receive]
  • [serializer/deserializer] supports almost all standard type of C++ same as msgpack-c
  • support custom class [serialization/deserialization]
  • support one-line manual [serialization/deserialization] to work with any communication interface
  • support working with ArduinoJSON
  • [serializer/deserializer] based on MsgPack
  • packetize based on Packetizer
  • working also in ROS with serial and serial-ros2

Packet Protocol

index msgpack crc8
1 byte N bytes 1 byte
  • 1 byte index (packet index can be used to identify packet)
  • N byte serialized msgpack data
  • 1 byte crc8 (for received data check)
  • these bytes are encoded to COBS encoding based on Packetizer

Usage

Direct Data Receive + Data Publishing

#include <MsgPacketizer.h>

// input to msgpack
int i;
float f;
MsgPack::str_t s; // std::string or String
MsgPack::arr_t<int> v; // std::vector or arx::stdx::vector
MsgPack::map_t<String, float> m; // std::map or arx::stdx::map

uint8_t recv_index = 0x12;
uint8_t send_index = 0x34;

void setup() {
    Serial.begin(115200);

    // update received data directly
    MsgPacketizer::subscribe(Serial, recv_index, i, f, s, v, m);

    // publish varibales periodically (default 30[times/sec])
    MsgPacketizer::publish(Serial, send_index, i, f, s, v, m);
}

void loop() {
    // must be called to trigger callback and publish data
    MsgPacketizer::update();
}

Callback with Received Objects + One-Line Send

#include <MsgPacketizer.h>

uint8_t recv_index = 0x12;
uint8_t send_index = 0x34;

void setup() {
    Serial.begin(115200);

    // handle received data with lambda
    // which has incoming argument types/data

    MsgPacketizer::subscribe(Serial, recv_index,
        [](int i, float f, MsgPack::str_t s, MsgPack::arr_t<int> v, MsgPack::map_t<String, float> m)
        {
            // send received data back in one-line
            MsgPacketizer::send(Serial, send_index, i, f, s, v, m);
        }
    );
}

void loop() {
    // must be called to trigger callback
    MsgPacketizer::parse();
}

Nested Data with Custom Class

To serialize / deserialize nested data, defining custom class is recommended. For example, to make {"k1": v, "k2":[i, f, s]}:

struct ArrayData {
    int i; float f; MsgPack::str_t s;
    MSGPACK_DEFINE(i, f, s); // [i, f, s]
};
struct NestedData {
    MsgPack::str_t k1, k2; int v;
    ArrayData a;
    MSGPACK_DEFINE_MAP(k1, v, k2, a); // {"k1": v, "k2":[i, f, s]}
};

and you can serialize / deserialize your class completely same as other types.

NestedData n;
MsgPacketizer::publish(Serial, send_index, n);
MsgPacketizer::subscribe(Serial, recv_index, n);

Please see examples and MsgPack for more detail.

Manual Encode / Decode with Any Communication I/F

You can just encode / decode data manually to use it with any communication interface. Please note:

  • only one unsupoprted interface (serial, udp, tcp, etc.) is available for manual subscription because MsgPacketizer cannot indetify which data is from which device
  • publish is not available for unsupported data stream
#include <MsgPacketizer.h>

const uint8_t recv_index = 0x12;
const uint8_t send_index = 0x34;

void setup() {
    Serial.begin(115200);
    delay(2000);

    // subscribe the data for manual operation
    MsgPacketizer::subscribe(recv_index,
        [&](const int i, const float f, const String& s) {
            // just encode your data manually and get binary packet from MsgPacketizer
            const auto& packet = MsgPacketizer::encode(send_index, i, f, s);
            // send the packet data with your interface
            Serial.write(packet.data.data(), packet.data.size());
        }
    );
}

void loop() {
    // you should feed the received data manually to MsgPacketizer
    const size_t size = Serial.available();
    if (size) {
        uint8_t* data = new uint8_t[size];
        // you can get binary data from any communication interface
        Serial.readBytes(data, size);
        // feed your binary data to MsgPacketizer manually
        // if data has successfully received and decoded, callback will be called
        MsgPacketizer::feed(data, size);
        delete[] data;
    }
}

UDP and TCP Support

TCP Support

  • start client first
  • everything else can be used in the same way
#include <MsgPacketizer.h>
#include <WiFi.h>

const uint8_t index = 0x12;
int i; float f; String s;

// WiFi stuff
WiFiClient client;
const char* host = "192.168.0.10";
const int port = 54321;

void setup() {
    WiFi.begin("your-ssid", "your-password");

    // start client
    client.connect(host, port);

    // everything else can be used in the same way
    MsgPacketizer::publish(client, index, i, f, s)->setFrameRate(1);
    MsgPacketizer::subscribe(client, index,
        [&](const int i, const float f, const String& s) {
            // do something with received data
        }
    );
}

void loop() {
    // do something with your variables i, f, s

    // must be called to trigger callback and publish data
    MsgPacketizer::update();
}

UDP Support

  • start client first
  • set ip and port when you publish or send messages
  • everything else can be used in the same way
#include <MsgPacketizer.h>
#include <WiFi.h>

const uint8_t index = 0x12;
int i; float f; String s;

// WiFi stuff
WiFiUDP client;
const char* host = "192.168.0.10";
const int port = 54321;

void setup() {
    WiFi.begin("your-ssid", "your-password");

    // start client first
    client.begin(port);

    // set host and port when publishing or sending messages
    MsgPacketizer::publish(client, host, port, index, i, f, s)->setFrameRate(1);
    MsgPacketizer::subscribe(client, index,
        [&](const int i, const float f, const String& s) {
            // do something with received data
        }
    );
}

void loop() {
    // do something with your variables i, f, s

    // must be called to trigger callback and publish data
    MsgPacketizer::update();
}

ArduinoJson Support

  • supports only version > 6.x
  • supports StaticJsonDocument<N> and DynamicJsonDocument
  • supports only send, decode, and subscribe with callbacks
    • you can use publish and subscribe directly by reference, but not reccomended
    • please see this official document for the detail
#include <ArduinoJson.h>  // include before MsgPacketizer.h
#include <MsgPacketizer.h>
#include <WiFi.h>

const uint8_t msg_index = 0x12;
const char* host = "192.168.0.10";
const int port = 54321;
WiFiUDP client;

void setup() {
    WiFi.begin("your-ssid", "your-password");
    client.begin(port);

    MsgPacketizer::subscribe(client, msg_index,
        [&](const StaticJsonDocument<200>& doc) {
            // do something with your json
        }
    );
}

void loop() {
    StaticJsonDocument<200> doc;
    // make your json here
    MsgPacketizer::send(client, host, port, msg_index, doc);

    delay(1000);

    // must be called to trigger callback and publish data
    MsgPacketizer::update();
}

Buffer Size Adjustment when Subscribing DynamicJsonDocument

Currently we cannot calculate the json size from msgpack format before deserialization. Please adjust buffer size by defining following macro before including MsgPacketizer.h. Default is size_of_msgpack_bytes * 3.

#define MSGPACKETIZER_ARDUINOJSON_DESERIALIZE_BUFFER_SCALE 3  // default
#include <MsgPacketizer.h>

APIs

Subscriber

namespace MsgPacketizer {

    // ----- for unsupported communication interface with manual operation -----

    // bind variables directly to specified index packet
    template <typename... Args>
    inline void subscribe_manual(const uint8_t index, Args&&... args);
    // bind variables directly to specified index packet with array format
    template <typename... Args>
    inline void subscribe_manual_arr(const uint8_t index, Args&&... args);
    // bind variables directly to specified index packet with map format
    template <typename... Args>
    inline void subscribe_manual_map(const uint8_t index, Args&&... args);
    // bind callback to specified index packet
    template <typename F>
    inline void subscribe_manual(const uint8_t index, F&& callback);
    // bind callback which is always called regardless of index
    template <typename F>
    inline void subscribe_manual(F&& callback);
    // unsubscribe
    inline void unsubscribe_manual(const uint8_t index);

    // feed packet manually: must be called to manual decoding
    inline void feed(const uint8_t* data, const size_t size);


    // ----- for supported communication interface (Arduino, oF, ROS) -----

    template <typename S, typename... Args>
    inline void subscribe(S& stream, const uint8_t index, Args&&... args);
    template <typename S, typename... Args>
    inline void subscribe_arr(S& stream, const uint8_t index, Args&&... args);
    template <typename S, typename... Args>
    inline void subscribe_map(S& stream, const uint8_t index, Args&&... args);
    template <typename S, typename F>
    inline void subscribe(S& stream, const uint8_t index, F&& callback);
    template <typename S, typename F>
    inline void subscribe(S& stream, F&& callback);
    template <typename S>
    inline void unsubscribe(const S& stream, const uint8_t index);
    template <typename S>
    inline void unsubscribe(const S& stream);
    template <typename S>

    // get UnpackerRef = std::shared_ptr<MsgPack::Unpacker> of stream and handle it manually
    inline UnpackerRef getUnpackerRef(const S& stream);
    // get map of unpackers and handle it manually
    inline UnpackerMap& getUnpackerMap();

    // must be called to receive packets
    inline void parse(bool b_exec_cb = true);
    inline void update(bool b_exec_cb = true);
}

Publisher

namespace MsgPacketizer {

    // ----- for unsupported communication interface with manual operation -----

    // encode arguments directly with variable types
    template <typename... Args>
    inline const Packetizer::Packet& encode(const uint8_t index, Args&&... args);
    // encode binary data
    inline const Packetizer::Packet& encode(const uint8_t index, const uint8_t* data, const uint8_t size);
    // encode manually packed data
    inline const Packetizer::Packet& encode(const uint8_t index);
    // encode args as array format
    template <typename... Args>
    inline const Packetizer::Packet& encode_arr(const uint8_t index, Args&&... args);
    // encode args as map format
    template <typename... Args>
    inline const Packetizer::Packet& encode_map(const uint8_t index, Args&&... args);


    // ----- for supported communication interface (Arduino, oF, ROS) -----

    // send arguments dilectly with variable types
    template <typename S, typename... Args>
    inline void send(S& stream, const uint8_t index, Args&&... args);
    // send binary data
    template <typename S>
    inline void send(S& stream, const uint8_t index, const uint8_t* data, const uint8_t size);
    // send manually packed data
    template <typename S>
    inline void send(S& stream, const uint8_t index);
    // send args as array format
    template <typename S, typename... Args>
    inline void send_arr(S& stream, const uint8_t index, Args&&... args);
    // send args as map format
    template <typename S, typename... Args>
    inline void send_map(S& stream, const uint8_t index, Args&&... args);

    // UDP version of send
    template <typename... Args>
    inline void send(UDP& stream, const str_t& ip, const uint16_t port, const uint8_t index, Args&&... args);
    inline void send(UDP& stream, const str_t& ip, const uint16_t port, const uint8_t index, const uint8_t* data, const uint8_t size);
    inline void send(UDP& stream, const str_t& ip, const uint16_t port, const uint8_t index);
    template <typename... Args>
    inline void send_arr(UDP& stream, const str_t& ip, const uint16_t port, const uint8_t index, Args&&... args);
    template <typename... Args>
    inline void send_map(UDP& stream, const str_t& ip, const uint16_t port, const uint8_t index, Args&&... args);

    // publish arguments periodically
    template <typename S, typename... Args>
    inline PublishElementRef publish(const S& stream, const uint8_t index, Args&&... args);
    // publish arguments periodically as array format
    template <typename S, typename... Args>
    inline PublishElementRef publish_arr(const S& stream, const uint8_t index, Args&&... args);
    // publish arguments periodically as map format
    template <typename S, typename... Args>
    inline PublishElementRef publish_map(const S& stream, const uint8_t index, Args&&... args);
    // unpublish
    template <typename S>
    inline void unpublish(const S& stream, const uint8_t index);
    // get registerd publish element class
    template <typename S>
    inline PublishElementRef getPublishElementRef(const S& stream, const uint8_t index);

    // UDP version of publish
    template <typename... Args>
    inline PublishElementRef publish(const UDP& stream, const str_t& ip, const uint16_t port, const uint8_t index, Args&&... args);
    template <typename... Args>
    inline PublishElementRef publish_arr(const UDP& stream, const str_t& ip, const uint16_t port, const uint8_t index, Args&&... args);
    template <typename... Args>
    inline PublishElementRef publish_map(const UDP& stream, const str_t& ip, const uint16_t port, const uint8_t index, Args&&... args);
    inline void unpublish(const UDP& stream, const str_t& ip, const uint16_t port, const uint8_t index);
    inline PublishElementRef getPublishElementRef(const UDP& stream, const uint8_t index);

    // must be called to publish data
    inline void post();
    // get MsgPack::Packer and handle it manually
    inline const MsgPack::Packer& getPacker();
}

Other Options

#define MSGPACKETIZER_DEBUGLOG_ENABLE

For NO-STL Boards

For following archtectures, several storage size for packets are limited.

  • AVR
  • megaAVR

Memory Management (only for NO-STL Boards)

As mentioned above, for such boards like Arduino Uno, the storage sizes are limited. And of course you can manage them by defining following macros. But these default values are optimized for such boards, please be careful not to excess your boards storage/memory. These macros have no effect for STL enabled boards.

MsgPacketizer

// max publishing elemtnt size in one destination
#define MSGPACKETIZER_MAX_PUBLISH_ELEMENT_SIZE 5
// max destinations to publish
#define MSGPACKETIZER_MAX_PUBLISH_DESTINATION_SIZE 1

MsgPack

// msgpack serialized binary size
#define MSGPACK_MAX_PACKET_BYTE_SIZE 96
// max size of MsgPack::arr_t
#define MSGPACK_MAX_ARRAY_SIZE 3
// max size of MsgPack::map_t
#define MSGPACK_MAX_MAP_SIZE 3
// msgpack objects size in one packet
#define MSGPACK_MAX_OBJECT_SIZE 16

Packetizer

// max number of decoded packet queues
#define PACKETIZER_MAX_PACKET_QUEUE_SIZE 1
// max data bytes in packet
#define PACKETIZER_MAX_PACKET_BINARY_SIZE 96
// max number of callback for one stream
#define PACKETIZER_MAX_CALLBACK_QUEUE_SIZE 3
// max number of streams
#define PACKETIZER_MAX_STREAM_MAP_SIZE 1

Dependent Libraries

License

MIT

msgpacketizer's People

Contributors

dependabot[bot] avatar hideakitai avatar wshgl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

msgpacketizer's Issues

Subscribe to binary data (MsgPack::bin_t<uint8_t>)

I'm trying to subscribe to an array of uint_8t on an arduino by changing one line in the example:

#include <MsgPacketizer.h>

// input to msgpack
int i;
float f;
MsgPack::str_t s; // std::string or String
// MsgPack::arr_t<int> v; // std::vector or arx::vector
MsgPack::bin_t<uint8_t> v; // <-- array of bytes
MsgPack::map_t<String, float> m; // std::map or arx::map

uint8_t recv_index = 0x12;
uint8_t send_index = 0x34;

void setup()
{
    Serial.begin(115200);

    // update received data directly
    MsgPacketizer::subscribe(Serial, recv_index, i, f, s, v, m);

    // publish varibales periodically (default 30[times/sec])
    MsgPacketizer::publish(Serial, send_index, i, f, s, v, m);
}

void loop()
{
    // must be called to trigger callback and publish data
    MsgPacketizer::update();
}

I get the following error during compilation:

Compiling sketch...
/home/stwirth/src/arduino-1.8.13/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10813 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 "-DUSB_MANUFACTURER=\"Unknown\"" "-DUSB_PRODUCT=\"Arduino Leonardo\"" -I/home/stwirth/src/arduino-1.8.13/hardware/arduino/avr/cores/arduino -I/home/stwirth/src/arduino-1.8.13/hardware/arduino/avr/variants/leonardo -I/home/stwirth/Arduino/libraries/MsgPacketizer /tmp/arduino_build_12483/sketch/msgpack_test.ino.cpp -o /tmp/arduino_build_12483/sketch/msgpack_test.ino.cpp.o
In file included from /home/stwirth/Arduino/libraries/MsgPacketizer/util/MsgPack/MsgPack.h:11:0,
                 from /home/stwirth/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:13,
                 from /home/stwirth/Arduino/msgpack_test/msgpack_test.ino:1:
/home/stwirth/Arduino/libraries/MsgPacketizer/util/MsgPack/MsgPack/Unpacker.h: In instantiation of 'void ht::serial::msgpack::Unpacker::deserialize(First&, Rest&& ...) [with First = arx::vector<char, 128>; Rest = {arx::map<String, float, 8>&}]':
/home/stwirth/Arduino/libraries/MsgPacketizer/util/MsgPack/MsgPack/Unpacker.h:71:13:   recursively required from 'void ht::serial::msgpack::Unpacker::deserialize(First&, Rest&& ...) [with First = float; Rest = {String&, arx::vector<char, 128>&, arx::map<String, float, 8>&}]'
/home/stwirth/Arduino/libraries/MsgPacketizer/util/MsgPack/MsgPack/Unpacker.h:71:13:   required from 'void ht::serial::msgpack::Unpacker::deserialize(First&, Rest&& ...) [with First = int; Rest = {float&, String&, arx::vector<char, 128>&, arx::map<String, float, 8>&}]'
/home/stwirth/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:469:13:   required from 'ht::serial::msgpacketizer::subscribe(ht::serial::msgpacketizer::StreamType&, uint8_t, Args&& ...)::<lambda(const uint8_t*, uint8_t)> [with Args = {int&, float&, String&, arx::vector<char, 128>&, arx::map<String, float, 8>&}; uint8_t = unsigned char]'
/home/stwirth/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:469:54:   required from 'struct ht::serial::msgpacketizer::subscribe(ht::serial::msgpacketizer::StreamType&, uint8_t, Args&& ...) [with Args = {int&, float&, String&, arx::vector<char, 128>&, arx::map<String, float, 8>&}; ht::serial::msgpacketizer::StreamType = Stream; uint8_t = unsigned char]::<lambda(const uint8_t*, uint8_t)>'
/home/stwirth/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:464:30:   required from 'void ht::serial::msgpacketizer::subscribe(ht::serial::msgpacketizer::StreamType&, uint8_t, Args&& ...) [with Args = {int&, float&, String&, arx::vector<char, 128>&, arx::map<String, float, 8>&}; ht::serial::msgpacketizer::StreamType = Stream; uint8_t = unsigned char]'
/home/stwirth/Arduino/msgpack_test/msgpack_test.ino:18:63:   required from here
/home/stwirth/Arduino/libraries/MsgPacketizer/util/MsgPack/MsgPack/Unpacker.h:70:13: error: no matching function for call to 'ht::serial::msgpack::Unpacker::unpack(arx::vector<char, 128>&)'
             unpack(first);
             ^~~~~~
/home/stwirth/Arduino/libraries/MsgPacketizer/util/MsgPack/MsgPack/Unpacker.h:134:14: note: candidate: template<class T> typename arx::stdx::enable_if<arx::stdx::is_same<T, ht::serial::msgpack::object::nil_t>::value>::type ht::serial::msgpack::Unpacker::unpack(T&)
         auto unpack(T& value)
              ^~~~~~

I'm using MsgPacketizer 0.2.20.

What am I doing wrong?

V0.5.0; breaks compatibility with Grand Central M4 / SAMD21 / SAMD51

Seems that all SAMD21 and SAMD51 boards cannot build latest V0.5.0. I only have a Adafruit Grand Central M4, but can confirm V0.5.0 breaks compatibility when I target other SAMD51/SAMD21 boards as well such as the Feather M0 (SAMD21) and Feather M4 (SAMD21). Downgrading to V0.4.7 fixes the compilation issues.

Sketch I used to confirm:

// #define MSGPACKETIZER_DEBUGLOG_ENABLE
#include <MsgPacketizer.h>

const uint8_t recv_index = 0x12;
const uint8_t send_index = 0x34;

void setup() {
    Serial.begin(115200);
    delay(2000);

    // - only one interface (serial, udp, tcp, etc.) is available for manual subscription
    //   because MsgPacketizer cannot indetify which data is from which device
    // - publisher is not available for unsupported data stream (manual operation)
    MsgPacketizer::subscribe_manual(recv_index,
        [&](const MsgPack::arr_size_t& sz, const int i, const float f, const String& s) {
            if (sz.size() == 3)  // if array size is correct
            {
                // modify input and send back as array format
                static int count = 0;
                String str = s + " " + sz.size() + " " + count++;

                // encode your data manually and get binary packet from MsgPacketizer
                const auto& packet = MsgPacketizer::encode_arr(send_index, i * 2, f * 2, str);

                // send the packet data with your interface
                Serial.write(packet.data.data(), packet.data.size());
            }
        });
}

void loop() {
    // you should feed the received data manually to MsgPacketizer
    const size_t size = Serial.available();
    if (size) {
        uint8_t* data = new uint8_t[size];
        Serial.readBytes((char*)data, size);

        // feed your binary data to MsgPacketizer manually
        // if data has successfully received and decoded,
        // subscribed callback will be called
        MsgPacketizer::feed(data, size);

        delete[] data;
    }
}

In file included from /home/ken/Arduino/libraries/DebugLog/DebugLogRestoreState.h:4,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog.h:53,
                 from /home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:64,
                 from /tmp/.arduinoIDE-unsaved202415-27510-1ei8fpl.3ab7/simple_bind_lambda_manual/simple_bind_lambda_manual.ino:2:
/home/ken/Arduino/libraries/DebugLog/DebugLogEnable.h:50:4: warning: #warning "Defaulting to a log level of: DEBUGLOG_DEFAULT_LOG_LEVEL_TRACE" [-Wcpp]
   50 |   #warning "Defaulting to a log level of: DEBUGLOG_DEFAULT_LOG_LEVEL_TRACE"
      |    ^~~~~~~
In file included from /home/ken/Arduino/libraries/DebugLog/DebugLogRestoreState.h:4,
                 from /home/ken/Arduino/libraries/MsgPack/MsgPack.h:19,
                 from /home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:73,
                 from /tmp/.arduinoIDE-unsaved202415-27510-1ei8fpl.3ab7/simple_bind_lambda_manual/simple_bind_lambda_manual.ino:2:
/home/ken/Arduino/libraries/DebugLog/DebugLogEnable.h:50:4: warning: #warning "Defaulting to a log level of: DEBUGLOG_DEFAULT_LOG_LEVEL_TRACE" [-Wcpp]
   50 |   #warning "Defaulting to a log level of: DEBUGLOG_DEFAULT_LOG_LEVEL_TRACE"
      |    ^~~~~~~
In file included from /home/ken/Arduino/libraries/DebugLog/DebugLogRestoreState.h:4,
                 from /home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:126,
                 from /tmp/.arduinoIDE-unsaved202415-27510-1ei8fpl.3ab7/simple_bind_lambda_manual/simple_bind_lambda_manual.ino:2:
/home/ken/Arduino/libraries/DebugLog/DebugLogEnable.h:50:4: warning: #warning "Defaulting to a log level of: DEBUGLOG_DEFAULT_LOG_LEVEL_TRACE" [-Wcpp]
   50 |   #warning "Defaulting to a log level of: DEBUGLOG_DEFAULT_LOG_LEVEL_TRACE"
      |    ^~~~~~~
In file included from /home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/arm-none-eabi/thumb/v7e-m+fp/hard/bits/c++allocator.h:33,
                 from /home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/bits/allocator.h:46,
                 from /home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/string:41,
                 from /home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/stdexcept:39,
                 from /home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/array:39,
                 from /home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/tuple:39,
                 from /home/ken/Arduino/libraries/ArxTypeTraits/ArxTypeTraits/tuple.h:8,
                 from /home/ken/Arduino/libraries/ArxTypeTraits/ArxTypeTraits/type_traits.h:593,
                 from /home/ken/Arduino/libraries/ArxTypeTraits/ArxTypeTraits.h:36,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog.h:14,
                 from /home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:64,
                 from /tmp/.arduinoIDE-unsaved202415-27510-1ei8fpl.3ab7/simple_bind_lambda_manual/simple_bind_lambda_manual.ino:2:
/home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> >; _Args = {arx::stdx::pair<unsigned char, std::function<void(const unsigned char*, unsigned int)> >}; _Tp = std::_Rb_tree_node<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >]':
/home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/bits/alloc_traits.h:482:2:   required from 'static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> >; _Args = {arx::stdx::pair<unsigned char, std::function<void(const unsigned char*, unsigned int)> >}; _Tp = std::_Rb_tree_node<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::_Rb_tree_node<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > > >]'
/home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/bits/stl_tree.h:614:32:   required from 'void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_construct_node(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type, _Args&& ...) [with _Args = {arx::stdx::pair<unsigned char, std::function<void(const unsigned char*, unsigned int)> >}; _Key = unsigned char; _Val = std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> >; _KeyOfValue = std::_Select1st<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >; _Compare = std::less<unsigned char>; _Alloc = std::allocator<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >*]'
/home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/bits/stl_tree.h:631:4:   required from 'std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {arx::stdx::pair<unsigned char, std::function<void(const unsigned char*, unsigned int)> >}; _Key = unsigned char; _Val = std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> >; _KeyOfValue = std::_Select1st<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >; _Compare = std::less<unsigned char>; _Alloc = std::allocator<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >*]'
/home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/bits/stl_tree.h:2408:13:   required from 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_unique(_Args&& ...) [with _Args = {arx::stdx::pair<unsigned char, std::function<void(const unsigned char*, unsigned int)> >}; _Key = unsigned char; _Val = std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> >; _KeyOfValue = std::_Select1st<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >; _Compare = std::less<unsigned char>; _Alloc = std::allocator<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >]'
/home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/bits/stl_map.h:575:64:   required from 'std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename __gnu_cxx::__alloc_traits<_Allocator>::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::emplace(_Args&& ...) [with _Args = {arx::stdx::pair<unsigned char, std::function<void(const unsigned char*, unsigned int)> >}; _Key = unsigned char; _Tp = std::function<void(const unsigned char*, unsigned int)>; _Compare = std::less<unsigned char>; _Alloc = std::allocator<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >; typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename __gnu_cxx::__alloc_traits<_Allocator>::rebind<std::pair<const _Key, _Tp> >::other>::iterator = std::_Rb_tree_iterator<std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> > >]'
/home/ken/Arduino/libraries/Packetizer/Packetizer/Decoder.h:24:34:   required from 'void arduino::packetizer::Decoder<Encoding>::subscribe(uint8_t, const CallbackType&) [with Encoding = arduino::packetizer::encoding::COBS; uint8_t = unsigned char; arduino::packetizer::CallbackType = std::function<void(const unsigned char*, unsigned int)>]'
/home/ken/Arduino/libraries/Packetizer/Packetizer/Decoder.h:348:13:   required from 'arduino::packetizer::DecoderRef<Encoding> arduino::packetizer::subscribe(uint8_t, const CallbackType&) [with Encoding = arduino::packetizer::encoding::COBS; arduino::packetizer::DecoderRef<Encoding> = std::shared_ptr<arduino::packetizer::Decoder<arduino::packetizer::encoding::COBS> >; uint8_t = unsigned char; arduino::packetizer::CallbackType = std::function<void(const unsigned char*, unsigned int)>]'
/home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer/Subscriber.h:227:38:   required from 'void arduino::msgpack::msgpacketizer::detail::subscribe_manual(uint8_t, std::function<_Res(_ArgTypes ...)>&&) [with R = void; Args = {const arduino::msgpack::type::ArraySize&, int, float, const String&}; uint8_t = unsigned char]'
/home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer/Subscriber.h:282:37:   required from 'arx::stdx::enable_if_t<arx::is_callable<T>::value> arduino::msgpack::msgpacketizer::subscribe_manual(uint8_t, F&&) [with F = setup()::<lambda(const arr_size_t&, int, float, const String&)>; arx::stdx::enable_if_t<arx::is_callable<T>::value> = void; uint8_t = unsigned char]'
/tmp/.arduinoIDE-unsaved202415-27510-1ei8fpl.3ab7/simple_bind_lambda_manual/simple_bind_lambda_manual.ino:28:10:   required from here
/home/ken/.arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/arm-none-eabi/include/c++/9.2.1/ext/new_allocator.h:145:20: error: no matching function for call to 'std::pair<const unsigned char, std::function<void(const unsigned char*, unsigned int)> >::pair(arx::stdx::pair<unsigned char, std::function<void(const unsigned char*, unsigned int)> >)'
  145 |  noexcept(noexcept(::new((void *)__p)
      |                    ^~~~~~~~~~~~~~~~~~
  146 |        _Up(std::forward<_Args>(__args)...)))
      |        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<<< TRUNCATED FOR BREVITY >>>

exit status 1

Compilation error: exit status 1

How to not use the Network

#if defined(ARDUINO) || defined(OF_VERSION_MAJOR) || defined(SERIAL_H)
#define MSGPACKETIZER_ENABLE_STREAM
#ifdef ARDUINO  // TODO: support more platforms
#if defined(ESP_PLATFORM) || defined(ESP8266) || defined(ARDUINO_AVR_UNO_WIFI_REV2)                             \
    || defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(ARDUINO_SAMD_MKR1000) \
    || defined(ARDUINO_SAMD_NANO_33_IOT)
#define MSGPACKETIZER_ENABLE_WIFI
#endif
#if defined(ESP_PLATFORM) || defined(ESP8266) || !defined(MSGPACKETIZER_ENABLE_WIFI)
#define MSGPACKETIZER_ENABLE_ETHER
#endif
#endif
#endif

#if defined(MSGPACKETIZER_ENABLE_ETHER) || defined(MSGPACKETIZER_ENABLE_WIFI)
#define MSGPACKETIZER_ENABLE_NETWORK
#include <Udp.h>
#include <Client.h>
#endif

If I read it correctly, MSGPACKETIZER_ENABLE_ETHER is defined when MSGPACKETIZER_ENABLE_WIFI is not defined.

Does this mean that MSGPACKETIZER_ENABLE_NETWORK must be defined? But #include <Udp.h> will report an error on some development boards, such as ch32v307

How to write Unit tests

I would like to write unit tests. The idea is that I inject a buffer containing packetized and encoded data setup by the test. Then I call the "parse" method and test if my callback functions correctly:

static int8_t global_received_val = 0;
// setup a callback
MsgPacketizer::subscribe(Serial, [&](const uint8_t index, MsgPack::Unpacker& unpacker)
{
// store the received value in a place accessible to the test
unpacker.unpackInt8(global_received_val);
}
auto &pm = MsgPacketizer::PackerManager::getInstance();
auto &packer = pm.getPacker();
packer.clear();
int8_t expected = 100;
packer.serialize(expected); // serialize some data
// simulate reception via Serial by injecting the packed and encoded buffer
auto unpacker = MsgPacketizer::UnpackerManager::getInstance().getUnpackerRef(Serial);
unpacker->clear();
unpacker->feed(packer.data(), packer.size());
MsgPacketizer::parse();
// test if the callback fired and correctly handled the message
assertEqual(global_received_val, expected);

This code doesn't work however.

  1. The parse function checks the stream if data is available and as there is no data available (it is already stored in the unpacker) the parse function returns.
  2. I think my use of Packer - Unpacker skips the Encoder/Decoder. I would like to take these into account also during the test.

Can you show how to perform the test?

Error Compiling for STM32

When I try to build this library and MsgPack for the STM32 I get the following output

In file included from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer/util/ArxTypeTraits/ArxTypeTraits.h:10:0,
                 from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer.h:14,
                 from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:12,
                 from /var/folders/b1/q_skhhzd7_d_g916bdqprzph0000gn/T/arduino_modified_sketch_214801/nested_custom.ino:1:
/Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer/util/ArxTypeTraits/ArxTypeTraits/has_include.h:24:14: error: #error "Compiler does not support __has_include, please report a bug against the ArxTypeTraits library about this."
             #error "Compiler does not support __has_include, please report a bug against the ArxTypeTraits library about this."
              ^
In file included from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer/util/ArxTypeTraits/ArxTypeTraits.h:11:0,
                 from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer.h:14,
                 from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:12,
                 from /var/folders/b1/q_skhhzd7_d_g916bdqprzph0000gn/T/arduino_modified_sketch_214801/nested_custom.ino:1:
/Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer/util/ArxTypeTraits/ArxTypeTraits/has_libstdcplusplus.h:7:31: error: missing binary operator before token "("
     #if ARX_SYSTEM_HAS_INCLUDE(<cstdlib>)
                               ^
In file included from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer/util/ArxTypeTraits/ArxTypeTraits/type_traits.h:405:0,
                 from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer/util/ArxTypeTraits/ArxTypeTraits.h:40,
                 from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer.h:14,
                 from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:12,
                 from /var/folders/b1/q_skhhzd7_d_g916bdqprzph0000gn/T/arduino_modified_sketch_214801/nested_custom.ino:1:
/Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer/util/ArxTypeTraits/ArxTypeTraits/initializer_list.h:10:27: error: missing binary operator before token "("
 #if ARX_SYSTEM_HAS_INCLUDE(<initializer_list>)
                           ^
In file included from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer/util/ArxTypeTraits/ArxTypeTraits/type_traits.h:407:0,
                 from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer/util/ArxTypeTraits/ArxTypeTraits.h:40,
                 from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer.h:14,
                 from /Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:12,
                 from /var/folders/b1/q_skhhzd7_d_g916bdqprzph0000gn/T/arduino_modified_sketch_214801/nested_custom.ino:1:
/Users/michaelequi/Documents/Arduino/libraries/MsgPacketizer/util/Packetizer/Packetizer/util/ArxTypeTraits/ArxTypeTraits/functional.h:17:27: error: missing binary operator before token "("
 #if ARX_SYSTEM_HAS_INCLUDE(<new>)
                           ^
exit status 1
Error compiling for board Generic STM32F103C6/fake STM32F103C8.

Re: Odd bug with string encoding; MsgPacketizer randomly outputting messages without length indicator..

I've been using your library in an Arduino project and its awesome- thank you!

However, I encountered a bug that is recreated below. When sending the 'Works' structure, the bytes output via the serial port are as follows (Note, I am omitting the 0x00 byte at the end):
[0xb][0x4][0x92][0xa5][0x49][0x33][0x3a][0x30][0x30][0x1][0xe5]

This is as expected.

However, second structure ('Fails') is similar, but changes the string to "I3:0", and the bytes over the serial are as follows:
[0x4][0x92][0xa4][0x49][0x33][0x3a][0x30][0x1][0x2b]

As you can see, the 'Fails' structure gets output to the Serial port without the length byte prefixing the data.

What is very strange is if I change "I3:0" to just "I3:", the output is then correct and includes the length byte.

The appears to be some bug with the string encoding portion as the expected behavior is an array of bytes including a length, index, payload, and finally CRC.

Steps to recreate:

  1. Flash sketch below to Arduino
  2. Monitor received bytes, or use your library calls to dump the bytes which would be written to the wire
  3. Observe that the 'Fails' structure is causing unexpected behavior.

Thanks again!

// #define MSGPACKETIZER_DEBUGLOG_ENABLE
#include <MsgPacketizer.h>

struct Works {
    String s = "I3:00";
    int i = 1;
    MSGPACK_DEFINE(s, i);
}w;

struct Fails {
    String s = "I3:0";
    int i = 1;
    MSGPACK_DEFINE(s, i);
}f;



const uint8_t some_index = 0x4;

void setup() {
    Serial.begin(115200);
    delay(2000);
}

void loop() {
    // must be called to trigger callback and publish data
    MsgPacketizer::send(Serial, some_index, w);
    delay(1000);
    MsgPacketizer::send(Serial, some_index, f);
    delay(1000);
    MsgPacketizer::update();
}

#include <MsgPacketizer.h> in multiple source files

I have 2 cpp files both contain a line #include<MsgPacketizer.h>

The code is compiled for Arduino

I have enabled logging:
#define MSGPACKETIZER_ENABLE_DEBUG_LOG

(but even with DEBUG_LOG disabled some multiple definitions still exist)

During linking I get an error:

tmp/arduino-sketch-CBB01DD9DE742798D756B54022239E3C/sketch/plg_rtd.cpp.o (symbol from plugin): In function arx::debug::log_level': (.text+0x0): multiple definition of arx::debug::log_level'
/tmp/arduino-sketch-CBB01DD9DE742798D756B54022239E3C/sketch/iMaxi2Sensor.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here
/tmp/arduino-sketch-CBB01DD9DE742798D756B54022239E3C/sketch/plg_rtd.cpp.o (symbol from plugin): In function arx::debug::log_level': (.text+0x0): multiple definition of arx::debug::b_only_sd'
/tmp/arduino-sketch-CBB01DD9DE742798D756B54022239E3C/sketch/iMaxi2Sensor.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here
/tmp/arduino-sketch-CBB01DD9DE742798D756B54022239E3C/sketch/plg_rtd.cpp.o (symbol from plugin): In function arx::debug::log_level': (.text+0x0): multiple definition of arx::debug::b_auto_save'
/tmp/arduino-sketch-CBB01DD9DE742798D756B54022239E3C/sketch/iMaxi2Sensor.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here
/tmp/arduino-sketch-CBB01DD9DE742798D756B54022239E3C/sketch/plg_rtd.cpp.o (symbol from plugin): In function arx::debug::log_level': (.text+0x0): multiple definition of arx::debug::logger'
/tmp/arduino-sketch-CBB01DD9DE742798D756B54022239E3C/sketch/iMaxi2Sensor.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here
/tmp/arduino-sketch-CBB01DD9DE742798D756B54022239E3C/sketch/plg_rtd.cpp.o (symbol from plugin): In function arx::debug::log_level': (.text+0x0): multiple definition of arx::debug::stream'
/tmp/arduino-sketch-CBB01DD9DE742798D756B54022239E3C/sketch/iMaxi2Sensor.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

Cannot compile library on Mega 2560

Attempting to compile some examples on a 2560 produces numerous compile errors. This is a problem my code is facing, but the example below reproduces the issue.

Try the following code with 2560 set as a target:


#include <ArduinoJson.h>  // include before MsgPacketizer.h

#define MSGPACKETIZER_DEBUGLOG_ENABLE
#include <MsgPacketizer.h>
#include <Ethernet.h>

const uint8_t msg_index = 0x12;

// Ethernet stuff
uint8_t mac[] = {0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45};
const IPAddress ip(192, 168, 0, 201);
// Ethernet with useful options
// const IPAddress dns (192, 168, 0, 1);
// const IPAddress gateway (192, 168, 0, 1);
// const IPAddress subnet (255, 255, 255, 0);

const char* host = "192.168.0.201";  // loop back
const int port = 54321;

EthernetUDP client;

void setup() {
    Serial.begin(115200);
    delay(2000);

    // Ethernet stuff
    Ethernet.begin(mac, ip);
    // Ethernet with useful options
    // Ethernet.begin(mac, ip, dns, gateway, subnet); // full
    // Ethernet.setRetransmissionCount(4); // default: 8[times]
    // Ethernet.setRetransmissionTimeout(50); // default: 200[ms]

    // start client
    client.begin(port);

    // only subscribing ArduinoJson with lambda is allowed
    // because subscribing JsonDocument as global object is not reccomended
    // see https://arduinojson.org/v6/how-to/reuse-a-json-document/
    MsgPacketizer::subscribe(client, msg_index,
        [&](const StaticJsonDocument<200>& doc) {
            Serial.print(doc["us"].as<uint32_t>());
            Serial.print(" ");
            Serial.print(doc["usstr"].as<String>());
            Serial.print(" [");
            Serial.print(doc["now"][0].as<double>());
            Serial.print(" ");
            Serial.print(doc["now"][1].as<double>());
            Serial.println("]");
        });

    // you can also use DynamicJsonDocument if you want
    // MsgPacketizer::subscribe(client, msg_index,
    //     [&](const DynamicJsonDocument& doc) {
    //         Serial.print(doc["us"].as<uint32_t>());
    //         Serial.print(" ");
    //         Serial.print(doc["usstr"].as<String>());
    //         Serial.print(" [");
    //         Serial.print(doc["now"][0].as<double>());
    //         Serial.print(" ");
    //         Serial.print(doc["now"][1].as<double>());
    //         Serial.println("]");
    //     });

    // or of course you can bind to variables directly
    // MsgPacketizer::subscribe(client, msg_index,
    //     [&](const MsgPack::map_size_t,
    //         const String& k_us, const uint32_t v_us,
    //         const String& k_usstr, const String& v_usstr,
    //         const String& k_now, const MsgPack::arr_size_t, const double now0, const double now1) {
    //         Serial.print(v_us);
    //         Serial.print(" ");
    //         Serial.print(v_usstr);
    //         Serial.print(" [");
    //         Serial.print(now0);
    //         Serial.print(" ");
    //         Serial.print(now1);
    //         Serial.println("]");
    //     });
}

void loop() {
    static uint32_t prev_ms = millis();
    if (millis() > prev_ms + 1000) {
        prev_ms = millis();

        uint32_t now = micros();

        StaticJsonDocument<200> doc;
        // you can also use DynamicJsonDocument if you want
        // DynamicJsonDocument doc(200);
        doc["us"] = now;
        doc["usstr"] = String(now) + "[us]";
        JsonArray data = doc.createNestedArray("now");
        data.add(now * 0.001);
        data.add(now * 0.001 * 0.001);

        // only `send` ArduinoJson is supported (you can `publish` but not recommended)
        // because ArduinoJson is designed to be throw-away objects
        // please use standard `publish` without ArduinoJson
        // see https://arduinojson.org/v6/how-to/reuse-a-json-document/ for the detail
        MsgPacketizer::send(client, host, port, msg_index, doc);

        // or you can send them directly
        // MsgPacketizer::send(client, host, port, msg_index,
        //     MsgPack::map_size_t(3),
        //     "us", now,
        //     "usstr", String(now) + "[us]",
        //     "now", MsgPack::arr_size_t(2), now * 0.001, now * 0.001 * 0.001);
    }

    // must be called to trigger callback and publish data
    MsgPacketizer::update();
}

Observe these compile errors:

In file included from /home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/type_traits.h:411:0,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits.h:36,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog.h:14,
                 from /home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:64,
                 from /tmp/.arduinoIDE-unsaved202413-2067-80ztgm.3pekm/sketch_feb3a/sketch_feb3a.ino:4:
/home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/functional.h: In instantiation of 'R arx::stdx::function<R(Args ...)>::operator()(Args ...) const [with R = void; Args = {const ArduinoJson::V702L1::DynamicJsonDocument&}]':
/home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer/Subscriber.h:150:33:   required from here
/home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/functional.h:133:53: error: call of overloaded 'forward<const ArduinoJson::V702L1::DynamicJsonDocument&>(const ArduinoJson::V702L1::DynamicJsonDocument&)' is ambiguous
             return table->invoke(data, forward<Args>(args)...);
                                        ~~~~~~~~~~~~~^~~~~~
In file included from /home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits.h:36:0,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog.h:14,
                 from /home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:64,
                 from /tmp/.arduinoIDE-unsaved202413-2067-80ztgm.3pekm/sketch_feb3a/sketch_feb3a.ino:4:
/home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/type_traits.h:153:19: note: candidate: constexpr T&& arx::stdx::forward(typename arx::stdx::remove_reference<T>::type&) [with T = const ArduinoJson::V702L1::DynamicJsonDocument&; typename arx::stdx::remove_reference<T>::type = const ArduinoJson::V702L1::DynamicJsonDocument]
     constexpr T&& forward(typename remove_reference<T>::type& t) noexcept
                   ^~~~~~~
In file included from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Memory/StringPool.hpp:10:0,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Memory/ResourceManager.hpp:8,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariantConst.hpp:10,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantRefBase.hpp:9,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp:7,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp:7,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson.hpp:29,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson.h:9,
                 from /tmp/.arduinoIDE-unsaved202413-2067-80ztgm.3pekm/sketch_feb3a/sketch_feb3a.ino:1:
/home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Polyfills/utility.hpp:14:5: note: candidate: T&& ArduinoJson::V702L1::detail::forward(typename ArduinoJson::V702L1::detail::remove_reference<T>::type&) [with T = const ArduinoJson::V702L1::DynamicJsonDocument&; typename ArduinoJson::V702L1::detail::remove_reference<T>::type = const ArduinoJson::V702L1::DynamicJsonDocument]
 T&& forward(typename remove_reference<T>::type& t) noexcept {
     ^~~~~~~
In file included from /home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/type_traits.h:411:0,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits.h:36,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog.h:14,
                 from /home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:64,
                 from /tmp/.arduinoIDE-unsaved202413-2067-80ztgm.3pekm/sketch_feb3a/sketch_feb3a.ino:4:
/home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/functional.h: In instantiation of 'R arx::stdx::function<R(Args ...)>::operator()(Args ...) const [with R = void; Args = {unsigned char, const ArduinoJson::V702L1::DynamicJsonDocument&}]':
/home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer/Subscriber.h:176:40:   required from here
/home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/functional.h:133:53: error: call of overloaded 'forward<const ArduinoJson::V702L1::DynamicJsonDocument&>(const ArduinoJson::V702L1::DynamicJsonDocument&)' is ambiguous
             return table->invoke(data, forward<Args>(args)...);
                                        ~~~~~~~~~~~~~^~~~~~
In file included from /home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits.h:36:0,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog.h:14,
                 from /home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:64,
                 from /tmp/.arduinoIDE-unsaved202413-2067-80ztgm.3pekm/sketch_feb3a/sketch_feb3a.ino:4:
/home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/type_traits.h:153:19: note: candidate: constexpr T&& arx::stdx::forward(typename arx::stdx::remove_reference<T>::type&) [with T = const ArduinoJson::V702L1::DynamicJsonDocument&; typename arx::stdx::remove_reference<T>::type = const ArduinoJson::V702L1::DynamicJsonDocument]
     constexpr T&& forward(typename remove_reference<T>::type& t) noexcept
                   ^~~~~~~
In file included from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Memory/StringPool.hpp:10:0,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Memory/ResourceManager.hpp:8,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariantConst.hpp:10,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantRefBase.hpp:9,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp:7,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp:7,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson.hpp:29,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson.h:9,
                 from /tmp/.arduinoIDE-unsaved202413-2067-80ztgm.3pekm/sketch_feb3a/sketch_feb3a.ino:1:
/home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Polyfills/utility.hpp:14:5: note: candidate: T&& ArduinoJson::V702L1::detail::forward(typename ArduinoJson::V702L1::detail::remove_reference<T>::type&) [with T = const ArduinoJson::V702L1::DynamicJsonDocument&; typename ArduinoJson::V702L1::detail::remove_reference<T>::type = const ArduinoJson::V702L1::DynamicJsonDocument]
 T&& forward(typename remove_reference<T>::type& t) noexcept {
     ^~~~~~~
In file included from /home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/type_traits.h:411:0,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits.h:36,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog.h:14,
                 from /home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:64,
                 from /tmp/.arduinoIDE-unsaved202413-2067-80ztgm.3pekm/sketch_feb3a/sketch_feb3a.ino:4:
/home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/functional.h: In instantiation of 'R arx::stdx::function<R(Args ...)>::operator()(Args ...) const [with R = void; Args = {const ArduinoJson::V702L1::StaticJsonDocument<200>&}]':
/home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer/Subscriber.h:138:29:   required from 'void arduino::msgpack::msgpacketizer::detail::subscribe_staticjson(const uint8_t*, const arx::stdx::function<void(const ArduinoJson::V702L1::StaticJsonDocument<N>&)>&) [with unsigned int N = 200; uint8_t = unsigned char]'
/home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer/Subscriber.h:371:41:   required from 'arduino::msgpack::msgpacketizer::detail::subscribe(S&, uint8_t, arx::stdx::function<void(const ArduinoJson::V702L1::StaticJsonDocument<N>&)>&&)::<lambda(const uint8_t*, size_t)> [with S = EthernetUDP; unsigned int N = 200; uint8_t = unsigned char; size_t = unsigned int]'
/home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer/Subscriber.h:370:58:   required from 'struct arduino::msgpack::msgpacketizer::detail::subscribe(S&, uint8_t, arx::stdx::function<void(const ArduinoJson::V702L1::StaticJsonDocument<N>&)>&&) [with S = EthernetUDP; unsigned int N = 200; uint8_t = unsigned char]::<lambda(const uint8_t*, size_t)>'
/home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer/Subscriber.h:370:38:   required from 'void arduino::msgpack::msgpacketizer::detail::subscribe(S&, uint8_t, arx::stdx::function<void(const ArduinoJson::V702L1::StaticJsonDocument<N>&)>&&) [with S = EthernetUDP; unsigned int N = 200; uint8_t = unsigned char]'
/home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer/Subscriber.h:405:30:   required from 'arx::stdx::enable_if_t<arx::is_callable<T>::value> arduino::msgpack::msgpacketizer::subscribe(S&, uint8_t, F&&) [with S = EthernetUDP; F = setup()::<lambda(const ArduinoJson::V702L1::StaticJsonDocument<200>&)>; arx::stdx::enable_if_t<arx::is_callable<T>::value> = void; uint8_t = unsigned char]'
/tmp/.arduinoIDE-unsaved202413-2067-80ztgm.3pekm/sketch_feb3a/sketch_feb3a.ino:49:10:   required from here
/home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/functional.h:133:53: error: call of overloaded 'forward<const ArduinoJson::V702L1::StaticJsonDocument<200>&>(const ArduinoJson::V702L1::StaticJsonDocument<200>&)' is ambiguous
             return table->invoke(data, forward<Args>(args)...);
                                        ~~~~~~~~~~~~~^~~~~~
In file included from /home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits.h:36:0,
                 from /home/ken/Arduino/libraries/DebugLog/DebugLog.h:14,
                 from /home/ken/Arduino/libraries/MsgPacketizer/MsgPacketizer.h:64,
                 from /tmp/.arduinoIDE-unsaved202413-2067-80ztgm.3pekm/sketch_feb3a/sketch_feb3a.ino:4:
/home/ken/Arduino/libraries/DebugLog/DebugLog/util/ArxTypeTraits/ArxTypeTraits/type_traits.h:153:19: note: candidate: constexpr T&& arx::stdx::forward(typename arx::stdx::remove_reference<T>::type&) [with T = const ArduinoJson::V702L1::StaticJsonDocument<200>&; typename arx::stdx::remove_reference<T>::type = const ArduinoJson::V702L1::StaticJsonDocument<200>]
     constexpr T&& forward(typename remove_reference<T>::type& t) noexcept
                   ^~~~~~~
In file included from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Memory/StringPool.hpp:10:0,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Memory/ResourceManager.hpp:8,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariantConst.hpp:10,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantRefBase.hpp:9,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp:7,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp:7,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson.hpp:29,
                 from /home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson.h:9,
                 from /tmp/.arduinoIDE-unsaved202413-2067-80ztgm.3pekm/sketch_feb3a/sketch_feb3a.ino:1:
/home/ken/Arduino/libraries/ArduinoJson/src/ArduinoJson/Polyfills/utility.hpp:14:5: note: candidate: T&& ArduinoJson::V702L1::detail::forward(typename ArduinoJson::V702L1::detail::remove_reference<T>::type&) [with T = const ArduinoJson::V702L1::StaticJsonDocument<200>&; typename ArduinoJson::V702L1::detail::remove_reference<T>::type = const ArduinoJson::V702L1::StaticJsonDocument<200>]
 T&& forward(typename remove_reference<T>::type& t) noexcept {
     ^~~~~~~

exit status 1

Compilation error: exit status 1

Compile errors for nrF52 boards

I'm trying to port some MsgPacketizer based code over for a Adafruit Feather type board based using the nrF52 chips, and I am getting quite a few compile errors. If I #define ARDUINO_ARCH_SAMD, I get past the pgmspace errors, but I end up with a whole load of errors along the lines of undefined reference to `std::_Rb_tree_decrement(std::_Rb_tree_node_base*)'

This looks like a standard library issue. Wondering if you could shed any light on this and save me a bit of time reworking things. This library is so incredibly useful, I'd be willing to put a little elbow grease in to make it compatible.

Thanks!
Drew Hamilton

C++ library?

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?

Re: Additional bug related to encoding of uint64_t value

This bug was detected when implementing UDP communication, however, it likely impacts Serial as well.

The code below includes sending two structures with the same layout. However, the fails structure includes the featureMap set to 0x10003.

When receiving the 'Fails' structure via udp, the receiver gets the following bytes:
[0x5] [0x4] [0x94] [0x1] [0xce] [0x2] [0x1] [0x7] [0x3] [0xcd] [0x13] [0x88] [0x1] [0x9b] [0x0]

The "Works" structure is received via UDP as:
[0xc] [0x4] [0x94] [0x1] [0xcd] [0x10] [0x1] [0xcd] [0x13] [0x88] [0x1] [0x60] [0x0]

So as you can see, the 'Fails' bytes appear corrupt as the length of 0x5 is incorrect. 'Works' shows a proper length value.

I am not sure why changing featureMap from 0x1001 to 0x10003 causes the output bytes to be corrupted/incorrect.

Perhaps I am making a mistake or misunderstanding what can be encoded via MsgPack?

Looking forward to your advice/confirmation.

Thanks very much!

// #define MSGPACKETIZER_DEBUGLOG_ENABLE
#include <MsgPacketizer.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 88);

unsigned int localPort = 54321;      // local port to listen on

// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged";        // a string to send back

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

  struct Fails {
      uint8_t protocolVersion = 1;
      uint64_t featureMap = 0x10003;
      uint32_t timeout = 5000;
      uint8_t boardIndex = 1;
      MSGPACK_DEFINE(protocolVersion, featureMap, timeout, boardIndex); 
  }f;

  struct Works {
      uint8_t protocolVersion = 1;
      uint64_t featureMap = 0x1001;
      uint32_t timeout = 5000;
      uint8_t boardIndex = 1;
      MSGPACK_DEFINE(protocolVersion, featureMap, timeout, boardIndex); 
  }w;





const uint8_t some_index = 0x4;

void setup() {
    Serial.begin(115200);
    delay(2000);
      // You can use Ethernet.init(pin) to configure the CS pin
  //Ethernet.init(10);  // Most Arduino shields
  //Ethernet.init(5);   // MKR ETH shield
  //Ethernet.init(0);   // Teensy 2.0
  //Ethernet.init(20);  // Teensy++ 2.0
  //Ethernet.init(15);  // ESP8266 with Adafruit Featherwing Ethernet
  //Ethernet.init(33);  // ESP32 with Adafruit Featherwing Ethernet

  // start the Ethernet
  Ethernet.begin(mac, ip);


  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start UDP
  Udp.begin(localPort);
}

void loop() {
    // must be called to trigger callback and publish data
    MsgPacketizer::send(Udp, "192.168.1.2", 54321, some_index, w);
    //delay(1000);
    MsgPacketizer::send(Udp, "192.168.1.2", 54321, some_index, f);
    //delay(1000);
    MsgPacketizer::update();
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.