binary data packetization encoder / decoder based on COBS / SLIP encoding
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
- encode / decode binary arrays to COBS / SLIP packet protocol
- one-line packetizing and sending with Serial, UDP and TCP
- callback registration with lambda and automatic execution
- optionally following features are available
- packet verification using crc8
- send / subscribe data with index to indentify packet type
- this library is embeded and used inside of my other libraries
- MsgPacketizer : recommend to use this to serialize any value type
- default encoding of this library
- refer here for more detail
- this library follows encoding described above, note difference pointed out in this discussion
- optional encoding of this library
- refer here for more detail
You can optionally add index byte to idetify packet type, and crc8 byte to verify packet structure. These options are disabled by default. If you use them, original data array is modified like:
| index | data | crc8 |
|---|---|---|
| 1 byte | N bytes | 1 byte |
CRC8 will be calcurated from data bytes (excluding index).
After that, these byte arrays will be coverted to COBS / SLIP encoding.
#include<Packetizer.h>voidsetup() {
Serial.begin(115200);
// register callback called if packet has comePacketizer::subscribe(Serial,
[](constuint8_t* data, constsize_t size) {
// one-line send data arrayPacketizer::send(Serial, data, size);
}
);
}
voidloop() {
Packetizer::parse(); // decode incoming packets and invoke callbacks automatically
}To use SLIP encoding by default, just define this macro before you #include <Packetizer.h>.
#definePACKETIZER_SET_DEFAULT_ENCODING_SLIPTo enable indexing and verifying packet by crc8, define following macros each.
// define these macros before include, to enable indexing and verifying
#definePACKETIZER_USE_INDEX_AS_DEFAULT
#definePACKETIZER_USE_CRC_AS_DEFAULT
#include<Packetizer.h>uint8_t recv_index = 0x12;
uint8_t send_index = 0x34;
voidsetup() {
Serial.begin(115200);
// you can add callback depending on index valuePacketizer::subscribe(Serial, recv_index,
[&](constuint8_t* data, constsize_t size) {
Packetizer::send(Serial, send_index, data, size); // send back packet
}
);
// you can also add callback called every time packet comesPacketizer::subscribe(Serial,
[&](constuint8_t index, constuint8_t* data, constsize_t size) {
// send back to same indexPacketizer::send(Serial, index, data, size);
}
);
}
voidloop() {
Packetizer::parse(); // automatically incoming packets are verified by crc
}To use with TCP, connect to host first. Everything else can be used in the same way.
#include<Packetizer.h>
#include<WiFi.h>
WiFiClient client;
uint8_t index = 0x12;
constchar* host = "192.168.0.10";
constuint16_t port = 3000;
voidsetup() {
Serial.begin(115200);
WiFi.begin("your-ssid", "your-password");
// start clientif (!client.connect(host, port)) {
Serial.println("client connection failed");
} else {
Serial.println("client connection success");
}
// you can add callback depending on index valuePacketizer::subscribe(client, recv_index,
[&](constuint8_t* data, constsize_t size) {
for (size_t i = 0; i < size; ++i)
Serial.println(data[i]);
}
);
}
voidloop() {
Packetizer::send(client, index, data, size); // send packetdelay(1000);
Packetizer::parse(); // decode incoming packets and invoke callbacks automatically
}To use with UDP, start client first. And also you should set the host and port when sending packet. Everything else can be used in the same way.
#include<Packetizer.h>
#include<WiFi.h>
WiFiUDP client;
uint8_t index = 0x12;
constchar* host = "192.168.0.10";
constuint16_t port = 3000;
voidsetup() {
Serial.begin(115200);
WiFi.begin("your-ssid", "your-password");
// start client
client.begin(3000);
// you can add callback depending on index valuePacketizer::subscribe(client, recv_index,
[&](constuint8_t* data, constsize_t size) {
for (size_t i = 0; i < size; ++i)
Serial.println(data[i]);
}
);
}
voidloop() {
// you should set host and port when sending packetPacketizer::send(client, host, port, index, data, size);
delay(1000);
Packetizer::parse(); // decode incoming packets and invoke callbacks automatically
}Just to encode / decode packets, you can use global mathod like:
Packetizer::Packet p_in {0xAB, {0x11, 0x22, 0x00, 0x33}}; // {index, {data}}constauto& p_buff = Packetizer::encode(p_in.index, p_in.data.data(), p_in.data.size());
constauto& p_out = Packetizer::decode(p_buff.data.data(), p_buff.data.size());Packetizer::Packet is alias for struct { uint8_t index; std::vector<uint8_t> data };.
STL is used to handle packet data by default, but for following boards/architectures, ArxContainer is used to store the packet data because STL can not be used for such boards. The storage size of such boards for packets, queue of packets, max packet binary size, and callbacks are limited.
- AVR
- megaAVR
- SAMD
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.
// max number of decoded packet queues
#definePACKETIZER_MAX_PACKET_QUEUE_SIZE1// max data bytes in packet
#definePACKETIZER_MAX_PACKET_BINARY_SIZE128// max number of callback for one stream
#definePACKETIZER_MAX_CALLBACK_QUEUE_SIZE4// max number of streams
#definePACKETIZER_MAX_STREAM_MAP_SIZE2For other STL enabled boards, only max packet queue size can be changed. Default value is 0 and not limited.
#definePACKETIZER_MAX_PACKET_QUEUE_SIZE3// default: 0- Please follow this instruction (TeensyDirtySTLErrorSolution) to enable STL
None
template <typename Encoding = DefaultEncoding>
inlineconst Packet& encode(constuint8_t index, constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlineconst Packet& encode(constuint8_t index, constuint8_t* data, constsize_t size);
template <typename Encoding = DefaultEncoding>
inlineconst Packet& encode(constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlineconst Packet& encode(constuint8_t* data, constsize_t size);
template <typename Encoding = DefaultEncoding>
inlinevoidencode_option(constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(StreamType& stream, constuint8_t index, constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(StreamType& stream, constuint8_t index, constuint8_t* data, constsize_t size);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(StreamType& stream, constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(StreamType& stream, constuint8_t* data, constsize_t size);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(UDP& stream, const String& ip, constuint16_t port, constuint8_t index, constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(UDP& stream, const String& ip, constuint16_t port, constuint8_t index, constuint8_t* data, constsize_t size);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(UDP& stream, const String& ip, constuint16_t port, constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(UDP& stream, const String& ip, constuint16_t port, constuint8_t* data, constsize_t size);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(UDP& stream, const IPAddress& ip, constuint16_t port, constuint8_t index, constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(UDP& stream, const IPAddress& ip, constuint16_t port, constuint8_t index, constuint8_t* data, constsize_t size);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(UDP& stream, const IPAddress& ip, constuint16_t port, constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(UDP& stream, const IPAddress& ip, constuint16_t port, constuint8_t* data, constsize_t size);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(Client& stream, constuint8_t index, constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(Client& stream, constuint8_t index, constuint8_t* data, constsize_t size);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(Client& stream, constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlinevoidsend(Client& stream, constuint8_t* data, constsize_t size);template <typename Encoding = DefaultEncoding>
inlineconst Packet& decode(constuint8_t* data, constsize_t size);
template <typename Encoding = DefaultEncoding>
inlineconst Packet& decode(constuint8_t* data, constsize_t size, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inlineconst Packet& decode(constuint8_t* data, constsize_t size, constbool b_index, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inline DecoderRef<Encoding> decode_option(constbool b_index, constbool b_crc);
template <typename Encoding = DefaultEncoding>
inline DecoderRef<Encoding> subscribe(const CallbackType& func);
template <typename Encoding = DefaultEncoding>
inline DecoderRef<Encoding> subscribe(const CallbackAlwaysType& func);
template <typename Encoding = DefaultEncoding>
inline DecoderRef<Encoding> subscribe(constuint8_t index, const CallbackType& func);
template <typename Encoding = DefaultEncoding>
inline DecoderRef<Encoding> unsubscribe();
template <typename Encoding = DefaultEncoding>
inline DecoderRef<Encoding> unsubscribe(constuint8_t index);
template <typename Encoding = DefaultEncoding>
inline DecoderRef<Encoding> feed(constuint8_t* data, constsize_t size, bool b_exec_cb = true);
template <typename Encoding = DefaultEncoding>
inline DecoderRef<Encoding> reset();
template <typename Encoding = DefaultEncoding>
inline DecoderRef<Encoding> getDecoderRef();
template <typename S, typename Encoding = DefaultEncoding>
inlineautooptions(const S& stream, constbool b_index, constbool b_crc);
template <typename S, typename Encoding = DefaultEncoding>
inlineautosubscribe(const S& stream, const CallbackType& func);
template <typename S, typename Encoding = DefaultEncoding>
inlineautosubscribe(const S& stream, const CallbackAlwaysType& func);
template <typename S, typename Encoding = DefaultEncoding>
inlineautosubscribe(const S& stream, constuint8_t index, const CallbackType& func);
template <typename S, typename Encoding = DefaultEncoding>
inlineautounsubscribe(const S& stream);
template <typename S, typename Encoding = DefaultEncoding>
inlineautounsubscribe(const S& stream, constuint8_t index);
template <typename S, typename Encoding = DefaultEncoding>
inlineautogetDecoderRef(const S& stream);
template <typename Encoding = DefaultEncoding>
inlinevoidparse(bool b_exec_cb = true);MIT