オブジェクトのバイト列化、バイト列からオブジェクトへの復元を行います。主に通信クラス内部で使用されています。
使用例
flowchart LR
subgraph マイコン
まいこんおぶ[オブジェクト] --シリアライズ--> a[バイト列]
end
subgraph パソコン
a[バイト列] --> バイト列 --デシリアライズ--> ぱそこんおぶ[オブジェクト]
end
個別インクルード
シリアライズ可能な型
整数型 ( int
, uint8_t
, uint16_t
... )
浮動小数点型 ( double
, float
... )
列挙型 ( enum
, enum class
)
シリアライズ可能な型の配列 (メンバ変数のみ)
列挙可能なユーザー定義型
シリアライズ
シリアライズしたいオブジェクトのデータ構造を構造体、クラスを用いて定義します。UDON_ENUMERABLE
マクロにメンバ変数を登録することで、メンバ変数を走査できるようになり、シリアライズできるようになります。
Udon::Serialize(object)
の引数にオブジェクトを渡すことでバイト列 std::vector<uint8_t>
が返されます。
struct Vec2
{
double x;
double y;
};
void setup() {}
void loop()
{
Vec2 v{ 2.5, 3.4 };
}
#define UDON_ENUMERABLE(...)
メンバ変数の列挙を可能にする
Definition EnumerableMacro.hpp:11
bool Serialize(const T &object, ArrayView< uint8_t > buffer)
バッファにシリアル化する
Definition Serializer.hpp:35
デシリアライズ
バイト列をオブジェクトに復元するには Udon::Deserialize<T>(...)
を使用します。 Udon::Deserialize
はデシリアライズされたオブジェクトを Udon::Optional
でラップして返します。
Optional
型とは値とエラー値を持つ型で、Optional::operator bool()
を呼び出すことで次のように if 文でエラー判定可能です。
バイト列末端バイトに挿入されているチェックサムと、バイト列から求めたチェックサムが異なる場合、デシリアライズが失敗します。 チェックサムの整合が取れない場合、データが破損しています。
void loop()
{
{
Serial.print(unpacked->x); Serial.print('\t');
Serial.print(unpacked->y); Serial.print('\n');
}
else
{
Serial.println("Deserialize failed!");
}
}
オプショナル型
Definition Optional.hpp:62
Udon::Optional< T > Deserialize(ArrayView< const uint8_t > buffer)
バイト列からオブジェクトに逆シリアル化します
Definition Serializer.hpp:87
既に定義されている型のシリアライズ、デシリアライズ
作成中
詳細
バイト列末尾に CRC8 値を付与します。
bool 型は 1bit としてシリアライズします。
浮動小数点型はアーキテクチャによってサイズが異なるので、常に 32bit 浮動小数点型にキャストして扱います。
列挙型は基底型を基にシリアライズします。
エンディアン変換を自動的に行います。リトルエンディアン環境を順列として扱い、ビッグエンディアン環境の場合はエンディアン変換を行います。
API
Udon::Serialize(...)
オブジェクトをシリアライズします
Serialize 関数は次のオーバーロードが定義されています。buffer
を引数にとる関数はヒープ領域を使用しません。
std::vector<uint8_t> Serialize(const T& object);
bool Serialize(const T& object, ArrayView<uint8_t> buffer);
Udon::Deserialize<T>(...)
バイト列をオブジェクトにデシリアライズします
Udon::IsDeserializable(...)
デシリアライズできるかを確認します。(CRC 値の一致を確認)
bool IsDeserializable(ArrayView<const uint8_t> buffer);
Udon::SerializedSize<T>()
T 型オブジェクトシリアライズ後のバイト列のバイトサイズを取得します。
コンパイル時にサイズを取得可能なため、バッファの大きさを静的に指定するときに使用します。
constexpr size_t SerializedSize() noexcept
Tをシリアライズした際のバイト列の要素数を取得する
Definition Serializer.hpp:22
サンプル
整数型シリアライズ
#include <iostream>
int main()
{
{
std::cout << *unpacked << std::endl;
}
else
{
std::cout << "deserialize failed" << std::endl;
}
}
ヒープ領域を使用しないシリアライズ
Udon::Serialize(T) -> std::vector<uint8_t>
は std::vector
を用いており、バイト列をヒープ領域に割り当てて返します。パフォーマンスを気にする場合、ヒープ領域の使用はなるべく控えるべきです。Udon::Serialize(T, Udon::ArrayView<uint8_t>)
を用いることで、スタック領域(静的配列)をバッファーとしてシリアライズできます。
この時、バッファーのサイズと、シリアライズ後のサイズ(Udon::SerializedSize<T>()
)が異なる場合 Udon::Serialize
は失敗し false を返します。
#include <iostream>
int main()
{
{
std::cout << "serialize failed" << std::endl;
}
{
std::cout << *unpacked << std::endl;
}
else
{
std::cout << "deserialize failed" << std::endl;
}
}
列挙型シリアライズ
#include <iostream>
enum class Language : uint8_t
{
C,
Cpp,
CSharp,
Python,
};
int main()
{
const Language lang = Language::Cpp;
{
switch (*unpacked)
{
case Language::C : std::cout << "C" << std::endl; break;
case Language::Cpp : std::cout << "C++" << std::endl; break;
case Language::CSharp: std::cout << "C#" << std::endl; break;
case Language::Python: std::cout << "Python" << std::endl; break;
}
}
else
{
std::cout << "deserialize failed" << std::endl;
}
}
ユーザー定義型シリアライズ
#include <iostream>
struct Vec2
{
double x;
double y;
};
int main()
{
const Vec2 vector{ 1.0, 2.0 };
{
std::cout
<< unpacked->x << ", "
<< unpacked->y << std::endl;
}
else
{
std::cout << "deserialize failed" << std::endl;
}
}
メンバに配列を持つユーザー定義型
#include <iostream>
struct Array
{
int array[5];
};
int main()
{
Array array{ { 1, 2, 3, 4, 5 } };
{
for (const auto& e : unpacked->array)
{
std::cout << e << std::endl;
}
}
else
{
std::cout << "deserialize failed" << std::endl;
}
}
ユーザー定義型のネスト
#include <iostream>
struct Vec2
{
struct Double
{
double value;
};
Double x;
Double y;
};
int main()
{
const Vec2 vector{ { 1.0 }, { 2.0 } };
{
std::cout
<< unpacked->x.value << ", "
<< unpacked->y.value << std::endl;
}
else
{
std::cout << "deserialize failed" << std::endl;
}
}
デシリアライズ失敗
#include <iostream>
int main()
{
packed.at(1) = 0x00;
{
std::cout << *unpacked << std::endl;
}
else
{
std::cout << "deserialize failed" << std::endl;
}
}