mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-11-02 17:11:36 +08:00
ScalarCodec implementation; more tests to come
This commit is contained in:
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
#include <uavcan/internal/util.hpp>
|
||||||
|
#include <uavcan/internal/marshalling/bit_stream.hpp>
|
||||||
|
|
||||||
|
namespace uavcan
|
||||||
|
{
|
||||||
|
|
||||||
|
class ScalarCodec
|
||||||
|
{
|
||||||
|
BitStream& stream_;
|
||||||
|
|
||||||
|
template <int SIZE>
|
||||||
|
static void swapByteOrder(uint8_t (&bytes)[SIZE])
|
||||||
|
{
|
||||||
|
for (int i = 0, j = SIZE - 1; i < j; i++, j--)
|
||||||
|
{
|
||||||
|
const uint8_t c = bytes[i];
|
||||||
|
bytes[i] = bytes[j];
|
||||||
|
bytes[j] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int BITLEN, int SIZE>
|
||||||
|
static typename EnableIf<(BITLEN > 8)>::Type
|
||||||
|
convertByteOrder(uint8_t (&bytes)[SIZE])
|
||||||
|
{
|
||||||
|
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN)
|
||||||
|
static const bool big_endian = BYTE_ORDER == BIG_ENDIAN;
|
||||||
|
#else
|
||||||
|
union { long int l; char c[sizeof(long int)]; } u;
|
||||||
|
u.l = 1;
|
||||||
|
const bool big_endian = u.c[sizeof(long int) - 1] == 1;
|
||||||
|
#endif
|
||||||
|
if (big_endian)
|
||||||
|
swapByteOrder(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int BITLEN, int SIZE>
|
||||||
|
static typename EnableIf<(BITLEN <= 8)>::Type
|
||||||
|
convertByteOrder(uint8_t (&bytes)[SIZE])
|
||||||
|
{
|
||||||
|
(void)bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int BITLEN, typename T>
|
||||||
|
static typename EnableIf<std::numeric_limits<T>::is_signed && ((sizeof(T) * 8) > BITLEN)>::Type
|
||||||
|
fixTwosComplement(T& value)
|
||||||
|
{
|
||||||
|
StaticAssert<std::numeric_limits<T>::is_integer>::check(); // Not applicable to floating point types
|
||||||
|
|
||||||
|
if (value & (T(1) << (BITLEN - 1))) // The most significant bit is set --> negative
|
||||||
|
value |= 0xFFFFFFFFFFFFFFFF & ~((T(1) << BITLEN) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int BITLEN, typename T>
|
||||||
|
static typename EnableIf<!std::numeric_limits<T>::is_signed || ((sizeof(T) * 8) == BITLEN)>::Type
|
||||||
|
fixTwosComplement(T& value)
|
||||||
|
{
|
||||||
|
(void)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int BITLEN, typename T>
|
||||||
|
static typename EnableIf<((sizeof(T) * 8) > BITLEN)>::Type
|
||||||
|
clearExtraBits(T& value)
|
||||||
|
{
|
||||||
|
value &= (1 << BITLEN) - 1; // Signedness doesn't matter
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int BITLEN, typename T>
|
||||||
|
static typename EnableIf<((sizeof(T) * 8) == BITLEN)>::Type
|
||||||
|
clearExtraBits(T& value)
|
||||||
|
{
|
||||||
|
(void)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int BITLEN, typename T>
|
||||||
|
void validate()
|
||||||
|
{
|
||||||
|
StaticAssert<((sizeof(T) * 8) >= BITLEN)>::check();
|
||||||
|
StaticAssert<(BITLEN <= BitStream::MAX_BITS_PER_RW)>::check();
|
||||||
|
StaticAssert<std::numeric_limits<T>::is_signed ? (BITLEN > 1) : 1>::check();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScalarCodec(BitStream& stream)
|
||||||
|
: stream_(stream)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
template <int BITLEN, typename T>
|
||||||
|
int encode(const T value)
|
||||||
|
{
|
||||||
|
validate<BITLEN, T>();
|
||||||
|
union ByteUnion
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
uint8_t bytes[sizeof(T)];
|
||||||
|
} byte_union;
|
||||||
|
byte_union.value = value;
|
||||||
|
|
||||||
|
clearExtraBits<BITLEN>(byte_union.value);
|
||||||
|
convertByteOrder<BITLEN>(byte_union.bytes);
|
||||||
|
|
||||||
|
// Underlying stream class assumes that more significant bits have lower index, so we need to shift some.
|
||||||
|
byte_union.bytes[BITLEN / 8] <<= (8 - (BITLEN % 8)) & 7;
|
||||||
|
|
||||||
|
return stream_.write(byte_union.bytes, BITLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int BITLEN, typename T>
|
||||||
|
int decode(T& value)
|
||||||
|
{
|
||||||
|
validate<BITLEN, T>();
|
||||||
|
union ByteUnion
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
uint8_t bytes[sizeof(T)];
|
||||||
|
} byte_union;
|
||||||
|
std::fill(byte_union.bytes, byte_union.bytes + sizeof(T), 0);
|
||||||
|
|
||||||
|
const int read_res = stream_.read(byte_union.bytes, BITLEN);
|
||||||
|
if (read_res <= 0)
|
||||||
|
return read_res;
|
||||||
|
|
||||||
|
byte_union.bytes[BITLEN / 8] >>= (8 - (BITLEN % 8)) & 7; // As in encode(), vice versa
|
||||||
|
|
||||||
|
convertByteOrder<BITLEN>(byte_union.bytes);
|
||||||
|
fixTwosComplement<BITLEN>(byte_union.value);
|
||||||
|
|
||||||
|
value = byte_union.value;
|
||||||
|
return read_res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -36,4 +36,11 @@ protected:
|
|||||||
Noncopyable() { }
|
Noncopyable() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<bool B, typename T = void>
|
||||||
|
struct EnableIf { };
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct EnableIf<true, T> { typedef T Type; };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <uavcan/internal/marshalling/scalar_codec.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
TEST(ScalarCodec, Basic)
|
||||||
|
{
|
||||||
|
uavcan::StaticTransferBuffer<38> buf;
|
||||||
|
uavcan::BitStream bs_wr(buf);
|
||||||
|
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||||
|
|
||||||
|
{
|
||||||
|
uint64_t u64 = 0;
|
||||||
|
ASSERT_EQ(0, sc_wr.decode<64>(u64)); // Out of buffer space
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encoding some variables
|
||||||
|
*/
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<12>((uint16_t)0xbeda)); // --> 0xeda
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<1>((uint8_t)1));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<1>((uint16_t)0));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<4>((uint8_t)8));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<32>((uint32_t)0xdeadbeef));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<3>((int8_t)-1));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<4>((int8_t)-6));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<20>((int32_t)-123456));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<64>(std::numeric_limits<int64_t>::min()));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<64>(std::numeric_limits<int64_t>::max()));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<15>((int16_t)-1));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<2>((int16_t)-1));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<16>(std::numeric_limits<int16_t>::min()));
|
||||||
|
ASSERT_EQ(1, sc_wr.encode<64>(std::numeric_limits<uint64_t>::max())); // Total 302 bit (38 bytes)
|
||||||
|
|
||||||
|
ASSERT_EQ(0, sc_wr.encode<64>(std::numeric_limits<uint64_t>::min())); // Out of buffer space
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decoding back
|
||||||
|
*/
|
||||||
|
uavcan::BitStream bs_rd(buf);
|
||||||
|
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||||
|
|
||||||
|
uint8_t u8 = 0;
|
||||||
|
int8_t i8 = 0;
|
||||||
|
uint16_t u16 = 0;
|
||||||
|
int16_t i16 = 0;
|
||||||
|
uint32_t u32 = 0;
|
||||||
|
int32_t i32 = 0;
|
||||||
|
uint64_t u64 = 0;
|
||||||
|
int64_t i64 = 0;
|
||||||
|
|
||||||
|
#define CHECK(bitlen, variable, expected_value) \
|
||||||
|
do { \
|
||||||
|
ASSERT_EQ(1, sc_rd.decode<bitlen>(variable)); \
|
||||||
|
ASSERT_EQ(expected_value, variable); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
CHECK(12, u16, 0xeda);
|
||||||
|
CHECK(1, u8, 1);
|
||||||
|
CHECK(1, u16, 0);
|
||||||
|
CHECK(4, u8, 8);
|
||||||
|
CHECK(32, u32, 0xdeadbeef);
|
||||||
|
CHECK(3, i8, -1);
|
||||||
|
CHECK(4, i8, -6);
|
||||||
|
CHECK(20, i32, -123456);
|
||||||
|
CHECK(64, i64, std::numeric_limits<int64_t>::min());
|
||||||
|
CHECK(64, i64, std::numeric_limits<int64_t>::max());
|
||||||
|
CHECK(15, i16, -1);
|
||||||
|
CHECK(2, i8, -1);
|
||||||
|
CHECK(16, i16, std::numeric_limits<int16_t>::min());
|
||||||
|
CHECK(64, u64, std::numeric_limits<uint64_t>::max());
|
||||||
|
|
||||||
|
#undef CHECK
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ScalarCodec, RepresentationCorrectness)
|
||||||
|
{
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user