diff --git a/libuavcan/include/uavcan/internal/transport/transfer.hpp b/libuavcan/include/uavcan/internal/transport/transfer.hpp index e5609ed9e6..69f2b2af1d 100644 --- a/libuavcan/include/uavcan/internal/transport/transfer.hpp +++ b/libuavcan/include/uavcan/internal/transport/transfer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 + * Copyright (C) 2014 Pavel Kirienko */ #pragma once @@ -19,21 +19,60 @@ enum TransferType MESSAGE_UNICAST = 3 }; + +class TransferID +{ + uint_fast8_t value_; + +public: + enum { BITLEN = 4 }; + enum { MAX = (1 << BITLEN) - 1 }; + + TransferID() + : value_(0) + { } + + TransferID(uint_fast8_t value) // implicit + : value_(value) + { + value_ &= MAX; + assert(value == value_); + } + + bool operator!=(TransferID rhs) const { return !operator==(rhs); } + bool operator==(TransferID rhs) const { return get() == rhs.get(); } + + void increment() + { + value_ = (value_ + 1) & MAX; + } + + uint_fast8_t get() const + { + assert(value_ <= MAX); + return value_; + } + + /** + * Amount of increment() calls to reach rhs value. + */ + int forwardDistance(TransferID rhs) const; +}; + + struct Frame { - enum { MAX_TRANSFER_ID = 15 }; - uint8_t payload[8]; TransferType transfer_type; uint_fast16_t data_type_id; uint_fast8_t payload_len; uint_fast8_t source_node_id; uint_fast8_t frame_index; - uint_fast8_t transfer_id; + TransferID transfer_id; bool last_frame; Frame(const uint8_t* payload, uint_fast8_t payload_len, uint_fast16_t data_type_id, TransferType transfer_type, - uint_fast8_t source_node_id, uint_fast8_t frame_index, uint_fast8_t transfer_id, bool last_frame) + uint_fast8_t source_node_id, uint_fast8_t frame_index, TransferID transfer_id, bool last_frame) : transfer_type(transfer_type) , data_type_id(data_type_id) , payload_len(payload_len) @@ -48,11 +87,7 @@ struct Frame static Frame parse(const CanFrame& can_frame); - /** - * Difference computed from (this.transfer_id - rhs.transfer_id) with proper overflow handling. - */ - int subtractTransferID(const Frame& rhs) const { return subtractTransferID(rhs.transfer_id); } - int subtractTransferID(int rhs) const; + CanFrame compile() const; bool operator!=(const Frame& rhs) const { return !operator==(rhs); } bool operator==(const Frame& rhs) const @@ -69,6 +104,7 @@ struct Frame } }; + struct RxFrame { uint_fast64_t timestamp; diff --git a/libuavcan/src/transport/transfer.cpp b/libuavcan/src/transport/transfer.cpp index 21dd7b263f..cff09f30be 100644 --- a/libuavcan/src/transport/transfer.cpp +++ b/libuavcan/src/transport/transfer.cpp @@ -1,27 +1,20 @@ /* - * Copyright (C) 2014 + * Copyright (C) 2014 Pavel Kirienko */ +#include #include namespace uavcan { -//static Frame Frame::parse(const CanFrame& can_frame) -//{ -//} - -int Frame::subtractTransferID(int rhs) const +int TransferID::forwardDistance(TransferID rhs) const { - static const int RANGE = MAX_TRANSFER_ID + 1; // 16 256 - static const int NEGATIVE = -RANGE / 2; // -8 -128 (two's complement) - static const int POSITIVE = (-NEGATIVE) - 1; // 7 127 + int d = int(rhs.get()) - int(get()); + if (d < 0) + d += 1 << BITLEN; - const int d = int(this->transfer_id) - rhs; - if (d <= NEGATIVE) - return RANGE + d; - else if (d >= POSITIVE) - return d - RANGE; + assert(((get() + d) & MAX) == rhs.get()); return d; } diff --git a/libuavcan/test/transport/transfer.cpp b/libuavcan/test/transport/transfer.cpp new file mode 100644 index 0000000000..14bdc77ead --- /dev/null +++ b/libuavcan/test/transport/transfer.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 Pavel Kirienko + */ + +#include +#include +#include + + +TEST(Transfer, TransferID) +{ + using uavcan::TransferID; + + // Tests below are based on this assumption + ASSERT_EQ(16, 1 << TransferID::BITLEN); + + /* + * forwardDistance() + */ + EXPECT_EQ(0, TransferID(0).forwardDistance(0)); + EXPECT_EQ(1, TransferID(0).forwardDistance(1)); + EXPECT_EQ(15, TransferID(0).forwardDistance(15)); + + EXPECT_EQ(0, TransferID(7).forwardDistance(7)); + EXPECT_EQ(15, TransferID(7).forwardDistance(6)); + EXPECT_EQ(1, TransferID(7).forwardDistance(8)); + + EXPECT_EQ(9, TransferID(10).forwardDistance(3)); + EXPECT_EQ(7, TransferID(3).forwardDistance(10)); + + EXPECT_EQ(8, TransferID(6).forwardDistance(14)); + EXPECT_EQ(8, TransferID(14).forwardDistance(6)); + + EXPECT_EQ(1, TransferID(14).forwardDistance(15)); + EXPECT_EQ(2, TransferID(14).forwardDistance(0)); + EXPECT_EQ(4, TransferID(14).forwardDistance(2)); + + EXPECT_EQ(15, TransferID(15).forwardDistance(14)); + EXPECT_EQ(14, TransferID(0).forwardDistance(14)); + EXPECT_EQ(12, TransferID(2).forwardDistance(14)); + + /* + * Misc + */ + EXPECT_TRUE(TransferID(2) == TransferID(2)); + EXPECT_FALSE(TransferID(2) != TransferID(2)); + EXPECT_FALSE(TransferID(2) == TransferID(8)); + EXPECT_TRUE(TransferID(2) != TransferID(8)); + + TransferID tid; + for (int i = 0; i < 999; i++) + { + ASSERT_EQ(i & ((1 << TransferID::BITLEN) - 1), tid.get()); + const TransferID copy = tid; + tid.increment(); + ASSERT_EQ(1, copy.forwardDistance(tid)); + ASSERT_EQ(15, tid.forwardDistance(copy)); + ASSERT_EQ(0, tid.forwardDistance(tid)); + } +}