mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-11 05:03:34 +08:00
YAML streaming for generated types
This commit is contained in:
@@ -198,8 +198,6 @@ ${define_out_of_line_constants(t.cpp_type_name, t.constants)}
|
||||
UAVCAN_PACKED_END
|
||||
#endif
|
||||
|
||||
// TODO Stream operator
|
||||
|
||||
% if t.has_default_dtid:
|
||||
const ::uavcan::DefaultDataTypeRegistrator< ${t.cpp_type_name} > _uavcan_gdtr_registrator_${t.cpp_type_name};
|
||||
% else:
|
||||
@@ -213,3 +211,56 @@ typedef ${t.cpp_type_name} ${t.short_name};
|
||||
} // Namespace ${nsc}
|
||||
% endfor
|
||||
|
||||
namespace uavcan
|
||||
{
|
||||
|
||||
<%def name="define_yaml_streamer(type_name, fields)">
|
||||
template <>
|
||||
struct YamlStreamer< ${type_name} >
|
||||
{
|
||||
template <typename Stream>
|
||||
static void stream(Stream& s, ${type_name}::ParameterType obj, const int level)
|
||||
{
|
||||
% for idx,a in enumerate(fields):
|
||||
% if idx == 0:
|
||||
if (level > 0)
|
||||
{
|
||||
s << '\n';
|
||||
for (int pos = 0; pos < level; pos++)
|
||||
s << " ";
|
||||
}
|
||||
% else:
|
||||
s << '\n';
|
||||
for (int pos = 0; pos < level; pos++)
|
||||
s << " ";
|
||||
% endif
|
||||
s << "${a.name}: ";
|
||||
YamlStreamer< ${type_name}::FieldTypes::${a.name} >::stream(s, obj.${a.name}, level + 1);
|
||||
% endfor
|
||||
}
|
||||
};
|
||||
</%def>
|
||||
% if t.kind == t.KIND_SERVICE:
|
||||
${define_yaml_streamer(t.cpp_full_type_name + '::Request', t.request_fields)}
|
||||
${define_yaml_streamer(t.cpp_full_type_name + '::Response', t.response_fields)}
|
||||
% else:
|
||||
${define_yaml_streamer(t.cpp_full_type_name, t.fields)}
|
||||
% endif
|
||||
|
||||
}
|
||||
|
||||
<%def name="define_streaming_operator(type_name)">
|
||||
template <typename Stream>
|
||||
inline Stream& operator<<(Stream& s, ${type_name}::ParameterType obj)
|
||||
{
|
||||
::uavcan::YamlStreamer< ${type_name} >::stream(s, obj, 0);
|
||||
return s;
|
||||
}
|
||||
</%def>
|
||||
% if t.kind == t.KIND_SERVICE:
|
||||
${define_streaming_operator(t.cpp_full_type_name + '::Request')}
|
||||
${define_streaming_operator(t.cpp_full_type_name + '::Response')}
|
||||
% else:
|
||||
${define_streaming_operator(t.cpp_full_type_name)}
|
||||
% endif
|
||||
|
||||
|
||||
@@ -115,7 +115,11 @@ class ArrayImpl : public StaticIf<ArrayMode == ArrayModeDynamic,
|
||||
StaticArrayBase<MaxSize> >::Result Base;
|
||||
|
||||
public:
|
||||
enum { IsStringLike = IsIntegerSpec<T>::Result && (T::MaxBitLen == 8 || T::MaxBitLen == 7) };
|
||||
enum
|
||||
{
|
||||
IsStringLike = IsIntegerSpec<T>::Result && (T::MaxBitLen == 8 || T::MaxBitLen == 7)
|
||||
&& (ArrayMode == ArrayModeDynamic)
|
||||
};
|
||||
|
||||
private:
|
||||
typedef typename StorageType<T>::Type BufferType[MaxSize + (IsStringLike ? 1 : 0)];
|
||||
@@ -410,4 +414,114 @@ inline bool operator!=(const R& rhs, const Array<T, ArrayMode, MaxSize>& lhs)
|
||||
return lhs.operator!=(rhs);
|
||||
}
|
||||
|
||||
|
||||
template <typename T, ArrayMode ArrayMode, unsigned int MaxSize>
|
||||
class YamlStreamer<Array<T, ArrayMode, MaxSize> >
|
||||
{
|
||||
typedef Array<T, ArrayMode, MaxSize> ArrayType;
|
||||
|
||||
template <typename Stream>
|
||||
static void streamPrimitives(Stream& s, const ArrayType& array)
|
||||
{
|
||||
s << '[';
|
||||
for (std::size_t i = 0; i < array.size(); i++)
|
||||
{
|
||||
YamlStreamer<T>::stream(s, array.at(i), 0);
|
||||
if ((i + 1) < array.size())
|
||||
s << ", ";
|
||||
}
|
||||
s << ']';
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
static void streamCharacters(Stream& s, const ArrayType& array)
|
||||
{
|
||||
s << '"';
|
||||
for (std::size_t i = 0; i < array.size(); i++)
|
||||
{
|
||||
const unsigned int c = array.at(i);
|
||||
if (c < 32 || c > 126) // Non-printable characters
|
||||
{
|
||||
char nibbles[2] = {(c >> 4) & 0xF, c & 0xF};
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
nibbles[i] += '0';
|
||||
if (nibbles[i] > '9')
|
||||
nibbles[i] += 'A' - '9' - 1;
|
||||
}
|
||||
s << "\\x" << nibbles[0] << nibbles[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c == '"' || c == '\\') // YAML requires to escape these two
|
||||
s << '\\';
|
||||
s << char(c);
|
||||
}
|
||||
}
|
||||
s << '"';
|
||||
}
|
||||
|
||||
struct SelectorStringLike { };
|
||||
struct SelectorPrimitives { };
|
||||
struct SelectorObjects { };
|
||||
|
||||
template <typename Stream>
|
||||
static void genericStreamImpl(Stream& s, const ArrayType& array, int, SelectorStringLike)
|
||||
{
|
||||
bool printable_only = true;
|
||||
for (int i = 0; i < array.size(); i++)
|
||||
{
|
||||
if (array[i] < 32 || array[i] > 126)
|
||||
{
|
||||
printable_only = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (printable_only)
|
||||
{
|
||||
streamCharacters(s, array);
|
||||
}
|
||||
else
|
||||
{
|
||||
streamPrimitives(s, array);
|
||||
s << " # ";
|
||||
streamCharacters(s, array);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
static void genericStreamImpl(Stream& s, const ArrayType& array, int, SelectorPrimitives)
|
||||
{
|
||||
streamPrimitives(s, array);
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
static void genericStreamImpl(Stream& s, const ArrayType& array, int level, SelectorObjects)
|
||||
{
|
||||
if (array.empty())
|
||||
{
|
||||
s << "[]";
|
||||
return;
|
||||
}
|
||||
for (std::size_t i = 0; i < array.size(); i++)
|
||||
{
|
||||
s << '\n';
|
||||
for (int pos = 0; pos < level; pos++)
|
||||
s << " ";
|
||||
s << "- ";
|
||||
YamlStreamer<T>::stream(s, array.at(i), level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename Stream>
|
||||
static void stream(Stream& s, const ArrayType& array, int level)
|
||||
{
|
||||
typedef typename StaticIf<ArrayType::IsStringLike, SelectorStringLike,
|
||||
typename StaticIf<IsPrimitiveType<typename ArrayType::RawValueType>::Result, SelectorPrimitives,
|
||||
SelectorObjects>::Result >::Result Type;
|
||||
genericStreamImpl(s, array, level, Type());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ public:
|
||||
enum { BitLen = BitLen_ };
|
||||
enum { MinBitLen = BitLen };
|
||||
enum { MaxBitLen = BitLen };
|
||||
enum { IsPrimitive = 1 };
|
||||
|
||||
typedef typename NativeFloatSelector<BitLen>::Type StorageType;
|
||||
|
||||
@@ -157,4 +158,17 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <unsigned int BitLen, CastMode CastMode>
|
||||
struct YamlStreamer<FloatSpec<BitLen, CastMode> >
|
||||
{
|
||||
typedef typename FloatSpec<BitLen, CastMode>::StorageType StorageType;
|
||||
|
||||
template <typename Stream>
|
||||
static void stream(Stream& s, const StorageType value, int)
|
||||
{
|
||||
s << value;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ enum Signedness { SignednessUnsigned, SignednessSigned };
|
||||
template <unsigned int BitLen_, Signedness Signedness, CastMode CastMode>
|
||||
class IntegerSpec
|
||||
{
|
||||
enum { IsSigned = Signedness == SignednessSigned };
|
||||
|
||||
struct ErrorNoSuchInteger;
|
||||
|
||||
public:
|
||||
enum { IsSigned = Signedness == SignednessSigned };
|
||||
enum { BitLen = BitLen_ };
|
||||
enum { MinBitLen = BitLen };
|
||||
enum { MaxBitLen = BitLen };
|
||||
enum { IsPrimitive = 1 };
|
||||
|
||||
typedef typename StaticIf<(BitLen <= 8), typename StaticIf<IsSigned, int8_t, uint8_t>::Result,
|
||||
typename StaticIf<(BitLen <= 16), typename StaticIf<IsSigned, int16_t, uint16_t>::Result,
|
||||
@@ -116,4 +116,21 @@ struct IsIntegerSpec { enum { Result = 0 }; };
|
||||
template <unsigned int BitLen, Signedness Signedness, CastMode CastMode>
|
||||
struct IsIntegerSpec<IntegerSpec<BitLen, Signedness, CastMode> > { enum { Result = 1 }; };
|
||||
|
||||
|
||||
template <unsigned int BitLen, Signedness Signedness, CastMode CastMode>
|
||||
struct YamlStreamer<IntegerSpec<BitLen, Signedness, CastMode> >
|
||||
{
|
||||
typedef IntegerSpec<BitLen, Signedness, CastMode> RawType;
|
||||
typedef typename RawType::StorageType StorageType;
|
||||
|
||||
template <typename Stream>
|
||||
static void stream(Stream& s, const StorageType value, int)
|
||||
{
|
||||
// Get rid of character types - we want its integer representation, not ASCII code
|
||||
typedef typename StaticIf<(sizeof(StorageType) >= sizeof(int)), StorageType,
|
||||
typename StaticIf<RawType::IsSigned, int, unsigned int>::Result >::Result TempType;
|
||||
s << TempType(value);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -29,4 +29,25 @@ struct StorageType<T, typename EnableIfType<typename T::StorageType>::Type>
|
||||
typedef typename T::StorageType Type;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class IsPrimitiveType
|
||||
{
|
||||
typedef char Yes;
|
||||
struct No { Yes dummy[8]; };
|
||||
|
||||
template <typename U>
|
||||
static typename EnableIf<U::IsPrimitive, Yes>::Type test(int);
|
||||
|
||||
template <typename>
|
||||
static No test(...);
|
||||
|
||||
public:
|
||||
enum { Result = sizeof(test<T>(0)) == sizeof(Yes) };
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct YamlStreamer;
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <uavcan/Timestamp.hpp>
|
||||
#include <uavcan/FigureOfMerit.hpp>
|
||||
#include <uavcan/mavlink/Message.hpp>
|
||||
@@ -29,3 +30,92 @@
|
||||
#include <uavcan/protocol/file/BeginTransfer.hpp>
|
||||
#include <uavcan/protocol/file/Crc.hpp>
|
||||
#include <uavcan/protocol/file/GetInfo.hpp>
|
||||
|
||||
#include <root_ns_a/Deep.hpp>
|
||||
|
||||
|
||||
TEST(Dsdl, Streaming)
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
uavcan::mavlink::Message mavlink;
|
||||
os << mavlink << std::endl << "==========" << std::endl;
|
||||
|
||||
mavlink.compid = 12;
|
||||
mavlink.seq = 42;
|
||||
mavlink.payload = "Here goes payload";
|
||||
os << mavlink << std::endl << "==========" << std::endl;
|
||||
|
||||
uavcan::protocol::GetNodeInfo::Response get_node_info_rsp;
|
||||
os << get_node_info_rsp << std::endl << "==========" << std::endl;
|
||||
|
||||
root_ns_a::Deep ps;
|
||||
ps.a.resize(2);
|
||||
os << ps << std::endl << "==========" << std::endl;
|
||||
|
||||
static const std::string Reference = "seq: 0\n"
|
||||
"sysid: 0\n"
|
||||
"compid: 0\n"
|
||||
"msgid: 0\n"
|
||||
"payload: \"\"\n"
|
||||
"==========\n"
|
||||
"seq: 42\n"
|
||||
"sysid: 0\n"
|
||||
"compid: 12\n"
|
||||
"msgid: 0\n"
|
||||
"payload: \"Here goes payload\"\n"
|
||||
"==========\n"
|
||||
"software_version: \n"
|
||||
" major: 0\n"
|
||||
" minor: 0\n"
|
||||
"hardware_version: \n"
|
||||
" major: 0\n"
|
||||
" minor: 0\n"
|
||||
"uavcan_version: \n"
|
||||
" major: 0\n"
|
||||
" minor: 0\n"
|
||||
"status: \n"
|
||||
" uptime_sec: 0\n"
|
||||
" status_code: 0\n"
|
||||
"name: \"\"\n"
|
||||
"==========\n"
|
||||
"c: 0\n"
|
||||
"str: \"\"\n"
|
||||
"a: \n"
|
||||
" - \n"
|
||||
" scalar: 0\n"
|
||||
" vector: \n"
|
||||
" - \n"
|
||||
" vector: [0, 0, 0, 0]\n"
|
||||
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
|
||||
" - \n"
|
||||
" vector: [0, 0, 0, 0]\n"
|
||||
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
|
||||
" - \n"
|
||||
" vector: [0, 0, 0, 0]\n"
|
||||
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
|
||||
" - \n"
|
||||
" scalar: 0\n"
|
||||
" vector: \n"
|
||||
" - \n"
|
||||
" vector: [0, 0, 0, 0]\n"
|
||||
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
|
||||
" - \n"
|
||||
" vector: [0, 0, 0, 0]\n"
|
||||
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
|
||||
" - \n"
|
||||
" vector: [0, 0, 0, 0]\n"
|
||||
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
|
||||
"b: \n"
|
||||
" - \n"
|
||||
" vector: [0, 0, 0, 0]\n"
|
||||
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
|
||||
" - \n"
|
||||
" vector: [0, 0, 0, 0]\n"
|
||||
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
|
||||
" - \n"
|
||||
" vector: [0, 0, 0, 0]\n"
|
||||
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
|
||||
"==========\n";
|
||||
ASSERT_EQ(Reference, os.str());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Nested type.
|
||||
# Energy and capacity are expressed in watt hours (Joules are infeasible because of range limitations).
|
||||
# Unknown values should be represented as NAN.
|
||||
#
|
||||
|
||||
float32 scalar
|
||||
B[3] vector
|
||||
@@ -0,0 +1,2 @@
|
||||
float64[4] vector
|
||||
bool[16] bools
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Info for all battery packs of the primary power supply.
|
||||
#
|
||||
|
||||
bool c
|
||||
uint8[<64] str
|
||||
A[<3] a
|
||||
B[3] b
|
||||
@@ -710,3 +710,59 @@ TEST(Array, Strings)
|
||||
ASSERT_STREQ("Our sun is dying. 123456-789", a8.c_str());
|
||||
ASSERT_STREQ("456", a7.c_str());
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, FlatStreaming)
|
||||
{
|
||||
typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 32> A8D;
|
||||
typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 16> AF16D;
|
||||
typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeStatic, 3> AF16S;
|
||||
|
||||
A8D a1;
|
||||
a1 = "12\n3\x44\xa5\xde\xad\x79";
|
||||
uavcan::YamlStreamer<A8D>::stream(std::cout, a1, 0);
|
||||
std::cout << std::endl;
|
||||
|
||||
A8D a2;
|
||||
a2 = "Hello";
|
||||
uavcan::YamlStreamer<A8D>::stream(std::cout, a2, 0);
|
||||
std::cout << std::endl;
|
||||
|
||||
AF16D af16d1;
|
||||
af16d1.push_back(1.23);
|
||||
af16d1.push_back(4.56);
|
||||
uavcan::YamlStreamer<AF16D>::stream(std::cout, af16d1, 0);
|
||||
std::cout << std::endl;
|
||||
|
||||
AF16D af16d2;
|
||||
uavcan::YamlStreamer<AF16D>::stream(std::cout, af16d2, 0);
|
||||
std::cout << std::endl;
|
||||
|
||||
AF16S af16s;
|
||||
uavcan::YamlStreamer<AF16S>::stream(std::cout, af16s, 0);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, MultidimensionalStreaming)
|
||||
{
|
||||
typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 16> Float16Array;
|
||||
typedef Array<Float16Array, ArrayModeDynamic, 8> TwoDimensional;
|
||||
typedef Array<TwoDimensional, ArrayModeDynamic, 4> ThreeDimensional;
|
||||
|
||||
ThreeDimensional threedee;
|
||||
threedee.resize(3);
|
||||
for (int x = 0; x < threedee.size(); x++)
|
||||
{
|
||||
threedee[x].resize(3);
|
||||
for (int y = 0; y < threedee[x].size(); y++)
|
||||
{
|
||||
threedee[x][y].resize(3);
|
||||
for (int z = 0; z < threedee[x][y].size(); z++)
|
||||
threedee[x][y][z] = 1.0 / (x + y + z + 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
uavcan::YamlStreamer<ThreeDimensional>::stream(std::cout, threedee, 0);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user