TransferBufferManager: using TransferBufferManagerKey instead of plain Node ID, this allows to distinguish transfers of different type from the same Node ID, which is necessary for message broadcasting/unicasting

This commit is contained in:
Pavel Kirienko
2014-02-11 12:21:25 +04:00
parent 149ac87a54
commit 78ff31f9ad
6 changed files with 150 additions and 90 deletions
@@ -30,24 +30,63 @@ public:
/** /**
* Internal for TransferBufferManager * Internal for TransferBufferManager
*/ */
class TransferBufferManagerEntry : public TransferBufferBase, Noncopyable class TransferBufferManagerKey
{ {
uint8_t node_id_; uint8_t node_id_;
uint8_t transfer_type_;
public:
TransferBufferManagerKey()
: node_id_(NODE_ID_INVALID)
, transfer_type_(TransferType(0))
{
assert(isEmpty());
}
TransferBufferManagerKey(uint8_t node_id, TransferType ttype)
: node_id_(node_id)
, transfer_type_(ttype)
{
assert(node_id <= NODE_ID_MAX && node_id != NODE_ID_INVALID);
assert(!isEmpty());
}
bool operator==(const TransferBufferManagerKey& rhs) const
{
return node_id_ == rhs.node_id_ && transfer_type_ == rhs.transfer_type_;
}
bool isEmpty() const { return node_id_ == NODE_ID_INVALID; }
uint8_t getNodeID() const { return node_id_; }
TransferType getTransferType() const { return TransferType(transfer_type_); }
std::string toString() const;
};
/**
* Internal for TransferBufferManager
*/
class TransferBufferManagerEntry : public TransferBufferBase, Noncopyable
{
TransferBufferManagerKey key_;
protected: protected:
virtual void resetImpl() = 0; virtual void resetImpl() = 0;
public: public:
TransferBufferManagerEntry(uint8_t node_id = NODE_ID_INVALID) TransferBufferManagerEntry() { }
: node_id_(node_id)
TransferBufferManagerEntry(const TransferBufferManagerKey& key)
: key_(key)
{ } { }
uint8_t getNodeID() const { return node_id_; } const TransferBufferManagerKey& getKey() const { return key_; }
bool isEmpty() const { return node_id_ == NODE_ID_INVALID; } bool isEmpty() const { return key_.isEmpty(); }
void reset(uint8_t node_id = NODE_ID_INVALID) void reset(const TransferBufferManagerKey& key = TransferBufferManagerKey())
{ {
node_id_ = node_id; key_ = key;
resetImpl(); resetImpl();
} }
}; };
@@ -169,7 +208,7 @@ public:
} }
// Resetting self and moving all data from the source // Resetting self and moving all data from the source
reset(tbme->getNodeID()); reset(tbme->getKey());
const int res = tbme->read(0, data_, SIZE); const int res = tbme->read(0, data_, SIZE);
if (res < 0) if (res < 0)
{ {
@@ -198,9 +237,9 @@ class ITransferBufferManager
{ {
public: public:
virtual ~ITransferBufferManager() { } virtual ~ITransferBufferManager() { }
virtual TransferBufferBase* access(uint8_t node_id) = 0; virtual TransferBufferBase* access(const TransferBufferManagerKey& key) = 0;
virtual TransferBufferBase* create(uint8_t node_id) = 0; virtual TransferBufferBase* create(const TransferBufferManagerKey& key) = 0;
virtual void remove(uint8_t node_id) = 0; virtual void remove(const TransferBufferManagerKey& key) = 0;
}; };
/** /**
@@ -215,24 +254,23 @@ class TransferBufferManager : public ITransferBufferManager, Noncopyable
LinkedListRoot<DynamicTransferBuffer> dynamic_buffers_; LinkedListRoot<DynamicTransferBuffer> dynamic_buffers_;
IAllocator* const allocator_; IAllocator* const allocator_;
StaticBufferType* findFirstStatic(uint8_t node_id) StaticBufferType* findFirstStatic(const TransferBufferManagerKey& key)
{ {
assert((node_id == NODE_ID_INVALID) || (node_id <= NODE_ID_MAX));
for (unsigned int i = 0; i < NUM_STATIC_BUFS; i++) for (unsigned int i = 0; i < NUM_STATIC_BUFS; i++)
{ {
if (static_buffers_[i].getNodeID() == node_id) if (static_buffers_[i].getKey() == key)
return static_buffers_ + i; return static_buffers_ + i;
} }
return NULL; return NULL;
} }
DynamicTransferBuffer* findFirstDynamic(uint8_t node_id) DynamicTransferBuffer* findFirstDynamic(const TransferBufferManagerKey& key)
{ {
DynamicTransferBuffer* dyn = dynamic_buffers_.get(); DynamicTransferBuffer* dyn = dynamic_buffers_.get();
while (dyn) while (dyn)
{ {
assert(!dyn->isEmpty()); assert(!dyn->isEmpty());
if (dyn->getNodeID() == node_id) if (dyn->getKey() == key)
return dyn; return dyn;
dyn = dyn->getNextListNode(); dyn = dyn->getNextListNode();
} }
@@ -243,7 +281,7 @@ class TransferBufferManager : public ITransferBufferManager, Noncopyable
{ {
while (!dynamic_buffers_.isEmpty()) while (!dynamic_buffers_.isEmpty())
{ {
StaticBufferType* const sb = findFirstStatic(NODE_ID_INVALID); StaticBufferType* const sb = findFirstStatic(TransferBufferManagerKey());
if (sb == NULL) if (sb == NULL)
break; break;
DynamicTransferBuffer* dyn = dynamic_buffers_.get(); DynamicTransferBuffer* dyn = dynamic_buffers_.get();
@@ -252,7 +290,8 @@ class TransferBufferManager : public ITransferBufferManager, Noncopyable
if (sb->migrateFrom(dyn)) if (sb->migrateFrom(dyn))
{ {
assert(!dyn->isEmpty()); assert(!dyn->isEmpty());
UAVCAN_TRACE("TransferBufferManager", "Storage optimization: Migrated NID %i", int(dyn->getNodeID())); UAVCAN_TRACE("TransferBufferManager", "Storage optimization: Migrated %s",
dyn->getKey().toString().c_str());
dynamic_buffers_.remove(dyn); dynamic_buffers_.remove(dyn);
DynamicTransferBuffer::destroy(dyn, allocator_); DynamicTransferBuffer::destroy(dyn, allocator_);
} }
@@ -262,8 +301,8 @@ class TransferBufferManager : public ITransferBufferManager, Noncopyable
* than STATIC_BUF_SIZE). This means that there is probably something wrong with the network. Logic * than STATIC_BUF_SIZE). This means that there is probably something wrong with the network. Logic
* that uses this class should explicitly ensure the proper maximum data size. * that uses this class should explicitly ensure the proper maximum data size.
*/ */
UAVCAN_TRACE("TransferBufferManager", "Storage optimization: MIGRATION FAILURE NID %i BUFSIZE %u", UAVCAN_TRACE("TransferBufferManager", "Storage optimization: MIGRATION FAILURE %s BUFSIZE %u",
int(dyn->getNodeID()), STATIC_BUF_SIZE); dyn->getKey().toString().c_str(), STATIC_BUF_SIZE);
sb->reset(); sb->reset();
break; // Probably we should try to migrate the rest? break; // Probably we should try to migrate the rest?
} }
@@ -300,29 +339,29 @@ public:
return res; return res;
} }
TransferBufferBase* access(uint8_t node_id) TransferBufferBase* access(const TransferBufferManagerKey& key)
{ {
if (node_id > NODE_ID_MAX || node_id == NODE_ID_INVALID) if (key.isEmpty())
{ {
assert(0); assert(0);
return NULL; return NULL;
} }
TransferBufferManagerEntry* tbme = findFirstStatic(node_id); TransferBufferManagerEntry* tbme = findFirstStatic(key);
if (tbme) if (tbme)
return tbme; return tbme;
return findFirstDynamic(node_id); return findFirstDynamic(key);
} }
TransferBufferBase* create(uint8_t node_id) TransferBufferBase* create(const TransferBufferManagerKey& key)
{ {
if (node_id > NODE_ID_MAX || node_id == NODE_ID_INVALID) if (key.isEmpty())
{ {
assert(0); assert(0);
return NULL; return NULL;
} }
remove(node_id); remove(key);
TransferBufferManagerEntry* tbme = findFirstStatic(NODE_ID_INVALID); TransferBufferManagerEntry* tbme = findFirstStatic(TransferBufferManagerKey());
if (tbme == NULL) if (tbme == NULL)
{ {
DynamicTransferBuffer* dyn = DynamicTransferBuffer::instantiate(allocator_); DynamicTransferBuffer* dyn = DynamicTransferBuffer::instantiate(allocator_);
@@ -335,16 +374,16 @@ public:
if (tbme) if (tbme)
{ {
assert(tbme->isEmpty()); assert(tbme->isEmpty());
tbme->reset(node_id); tbme->reset(key);
} }
return tbme; return tbme;
} }
void remove(uint8_t node_id) void remove(const TransferBufferManagerKey& key)
{ {
assert((node_id <= NODE_ID_MAX) && (node_id != NODE_ID_INVALID)); assert(!key.isEmpty());
TransferBufferManagerEntry* const tbme = findFirstStatic(node_id); TransferBufferManagerEntry* const tbme = findFirstStatic(key);
if (tbme) if (tbme)
{ {
tbme->reset(); tbme->reset();
@@ -352,7 +391,7 @@ public:
return; return;
} }
DynamicTransferBuffer* dyn = findFirstDynamic(node_id); DynamicTransferBuffer* dyn = findFirstDynamic(key);
if (dyn) if (dyn)
{ {
dynamic_buffers_.remove(dyn); dynamic_buffers_.remove(dyn);
@@ -27,8 +27,8 @@ private:
uint64_t this_transfer_timestamp_; uint64_t this_transfer_timestamp_;
uint64_t transfer_interval_; uint64_t transfer_interval_;
ITransferBufferManager* bufmgr_; ITransferBufferManager* bufmgr_;
TransferBufferManagerKey bufmgr_key_;
TransferID tid_; TransferID tid_;
uint8_t node_id_;
uint8_t iface_index_; uint8_t iface_index_;
uint8_t next_frame_index_; uint8_t next_frame_index_;
@@ -52,24 +52,21 @@ public:
, this_transfer_timestamp_(0) , this_transfer_timestamp_(0)
, transfer_interval_(DEFAULT_TRANSFER_INTERVAL) , transfer_interval_(DEFAULT_TRANSFER_INTERVAL)
, bufmgr_(NULL) , bufmgr_(NULL)
, node_id_(NODE_ID_INVALID)
, iface_index_(IFACE_INDEX_NOTSET) , iface_index_(IFACE_INDEX_NOTSET)
, next_frame_index_(0) , next_frame_index_(0)
{ } { }
TransferReceiver(ITransferBufferManager* bufmgr, uint8_t node_id) TransferReceiver(ITransferBufferManager* bufmgr, const TransferBufferManagerKey& bufmgr_key)
: prev_transfer_timestamp_(0) : prev_transfer_timestamp_(0)
, this_transfer_timestamp_(0) , this_transfer_timestamp_(0)
, transfer_interval_(DEFAULT_TRANSFER_INTERVAL) , transfer_interval_(DEFAULT_TRANSFER_INTERVAL)
, bufmgr_(bufmgr) , bufmgr_(bufmgr)
, node_id_(node_id) , bufmgr_key_(bufmgr_key)
, iface_index_(IFACE_INDEX_NOTSET) , iface_index_(IFACE_INDEX_NOTSET)
, next_frame_index_(0) , next_frame_index_(0)
{ {
assert(bufmgr); assert(bufmgr);
assert(node_id <= NODE_ID_MAX); assert(bufmgr_key.getNodeID() != NODE_ID_BROADCAST);
assert(node_id != NODE_ID_INVALID);
assert(node_id != NODE_ID_BROADCAST);
} }
~TransferReceiver() { cleanup(); } ~TransferReceiver() { cleanup(); }
@@ -82,7 +79,7 @@ public:
transfer_interval_ = rhs.transfer_interval_; transfer_interval_ = rhs.transfer_interval_;
bufmgr_ = rhs.bufmgr_; bufmgr_ = rhs.bufmgr_;
tid_ = rhs.tid_; tid_ = rhs.tid_;
node_id_ = rhs.node_id_; bufmgr_key_ = rhs.bufmgr_key_;
iface_index_ = rhs.iface_index_; iface_index_ = rhs.iface_index_;
next_frame_index_ = rhs.next_frame_index_; next_frame_index_ = rhs.next_frame_index_;
return *this; return *this;
@@ -4,10 +4,22 @@
#include <cassert> #include <cassert>
#include <cstdlib> #include <cstdlib>
#include <cstdio>
#include <string>
#include <uavcan/internal/transport/transfer_buffer.hpp> #include <uavcan/internal/transport/transfer_buffer.hpp>
namespace uavcan namespace uavcan
{ {
/*
* TransferBufferManagerKey
*/
std::string TransferBufferManagerKey::toString() const
{
char buf[24];
std::snprintf(buf, sizeof(buf), "nid:%i tt:%i", int(node_id_), int(transfer_type_));
return std::string(buf);
}
/* /*
* DynamicTransferBuffer::Block * DynamicTransferBuffer::Block
*/ */
@@ -18,8 +18,8 @@ const uint64_t TransferReceiver::MAX_TRANSFER_INTERVAL;
void TransferReceiver::cleanup() void TransferReceiver::cleanup()
{ {
if (bufmgr_ != NULL && node_id_ != NODE_ID_INVALID) if (bufmgr_ != NULL && !bufmgr_key_.isEmpty())
bufmgr_->remove(node_id_); bufmgr_->remove(bufmgr_key_);
} }
TransferReceiver::TidRelation TransferReceiver::getTidRelation(const RxFrame& frame) const TransferReceiver::TidRelation TransferReceiver::getTidRelation(const RxFrame& frame) const
@@ -99,15 +99,15 @@ TransferReceiver::ResultCode TransferReceiver::receive(const RxFrame& frame)
if ((frame.frame_index == 0) && frame.last_frame) // Single-frame transfer if ((frame.frame_index == 0) && frame.last_frame) // Single-frame transfer
{ {
bufmgr_->remove(node_id_); bufmgr_->remove(bufmgr_key_);
updateTransferTimings(); updateTransferTimings();
prepareForNextTransfer(); prepareForNextTransfer();
return RESULT_SINGLE_FRAME; return RESULT_SINGLE_FRAME;
} }
TransferBufferBase* buf = bufmgr_->access(node_id_); TransferBufferBase* buf = bufmgr_->access(bufmgr_key_);
if (buf == NULL) if (buf == NULL)
buf = bufmgr_->create(node_id_); buf = bufmgr_->create(bufmgr_key_);
if (buf == NULL) if (buf == NULL)
{ {
UAVCAN_TRACE("TransferReceiver", "Failed to access the buffer, %s", frame.toString().c_str()); UAVCAN_TRACE("TransferReceiver", "Failed to access the buffer, %s", frame.toString().c_str());
@@ -119,7 +119,7 @@ TransferReceiver::ResultCode TransferReceiver::receive(const RxFrame& frame)
if (res != frame.payload_len) if (res != frame.payload_len)
{ {
UAVCAN_TRACE("TransferReceiver", "Buffer write failure [%i], %s", res, frame.toString().c_str()); UAVCAN_TRACE("TransferReceiver", "Buffer write failure [%i], %s", res, frame.toString().c_str());
bufmgr_->remove(node_id_); bufmgr_->remove(bufmgr_key_);
prepareForNextTransfer(); prepareForNextTransfer();
return RESULT_NOT_COMPLETE; return RESULT_NOT_COMPLETE;
} }
@@ -146,7 +146,8 @@ bool TransferReceiver::isTimedOut(uint64_t timestamp) const
TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame) TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame)
{ {
assert(bufmgr_); assert(bufmgr_);
assert(node_id_ == frame.source_node_id); assert(bufmgr_key_.getNodeID() == frame.source_node_id);
assert(bufmgr_key_.getTransferType() == frame.transfer_type);
if ((frame.timestamp == 0) || if ((frame.timestamp == 0) ||
(frame.timestamp < prev_transfer_timestamp_) || (frame.timestamp < prev_transfer_timestamp_) ||
@@ -174,7 +175,7 @@ TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame)
"Restart [not_inited=%i, iface_timeout=%i, recv_timeout=%i, same_iface=%i, first_frame=%i, tid_rel=%i], %s", "Restart [not_inited=%i, iface_timeout=%i, recv_timeout=%i, same_iface=%i, first_frame=%i, tid_rel=%i], %s",
int(not_initialized), int(iface_timed_out), int(receiver_timed_out), int(same_iface), int(first_fame), int(not_initialized), int(iface_timed_out), int(receiver_timed_out), int(same_iface), int(first_fame),
int(tid_rel), frame.toString().c_str()); int(tid_rel), frame.toString().c_str());
bufmgr_->remove(node_id_); bufmgr_->remove(bufmgr_key_);
iface_index_ = frame.iface_index; iface_index_ = frame.iface_index;
tid_ = frame.transfer_id; tid_ = frame.transfer_id;
next_frame_index_ = 0; next_frame_index_ = 0;
+29 -19
View File
@@ -232,6 +232,7 @@ static int fillTestData(const std::string& data, uavcan::TransferBufferBase* tbb
TEST(TransferBufferManager, Basic) TEST(TransferBufferManager, Basic)
{ {
using uavcan::TransferBufferManager; using uavcan::TransferBufferManager;
using uavcan::TransferBufferManagerKey;
using uavcan::TransferBufferBase; using uavcan::TransferBufferBase;
static const int POOL_BLOCKS = 8; static const int POOL_BLOCKS = 8;
@@ -243,25 +244,34 @@ TEST(TransferBufferManager, Basic)
std::auto_ptr<TransferBufferManagerType> mgr(new TransferBufferManagerType(&poolmgr)); std::auto_ptr<TransferBufferManagerType> mgr(new TransferBufferManagerType(&poolmgr));
// Empty // Empty
ASSERT_FALSE(mgr->access(0)); ASSERT_FALSE(mgr->access(TransferBufferManagerKey(0, uavcan::TRANSFER_TYPE_MESSAGE_UNICAST)));
ASSERT_FALSE(mgr->access(uavcan::NODE_ID_MAX)); ASSERT_FALSE(mgr->access(TransferBufferManagerKey(uavcan::NODE_ID_MAX, uavcan::TRANSFER_TYPE_MESSAGE_UNICAST)));
TransferBufferBase* tbb = NULL; TransferBufferBase* tbb = NULL;
const TransferBufferManagerKey keys[5] =
{
TransferBufferManagerKey(0, uavcan::TRANSFER_TYPE_MESSAGE_UNICAST),
TransferBufferManagerKey(1, uavcan::TRANSFER_TYPE_MESSAGE_BROADCAST),
TransferBufferManagerKey(2, uavcan::TRANSFER_TYPE_SERVICE_REQUEST),
TransferBufferManagerKey(127, uavcan::TRANSFER_TYPE_SERVICE_RESPONSE),
TransferBufferManagerKey(64, uavcan::TRANSFER_TYPE_MESSAGE_BROADCAST)
};
// Static 0 // Static 0
ASSERT_TRUE((tbb = mgr->create(0))); ASSERT_TRUE((tbb = mgr->create(keys[0])));
ASSERT_EQ(MGR_STATIC_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[0], tbb)); ASSERT_EQ(MGR_STATIC_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[0], tbb));
ASSERT_EQ(1, mgr->getNumStaticBuffers()); ASSERT_EQ(1, mgr->getNumStaticBuffers());
// Static 1 // Static 1
ASSERT_TRUE((tbb = mgr->create(1))); ASSERT_TRUE((tbb = mgr->create(keys[1])));
ASSERT_EQ(MGR_STATIC_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[1], tbb)); ASSERT_EQ(MGR_STATIC_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[1], tbb));
ASSERT_EQ(2, mgr->getNumStaticBuffers()); ASSERT_EQ(2, mgr->getNumStaticBuffers());
ASSERT_EQ(0, mgr->getNumDynamicBuffers()); ASSERT_EQ(0, mgr->getNumDynamicBuffers());
ASSERT_EQ(0, pool.getNumUsedBlocks()); ASSERT_EQ(0, pool.getNumUsedBlocks());
// Dynamic 0 // Dynamic 0
ASSERT_TRUE((tbb = mgr->create(2))); ASSERT_TRUE((tbb = mgr->create(keys[2])));
ASSERT_EQ(1, pool.getNumUsedBlocks()); // Empty dynamic buffer occupies one block ASSERT_EQ(1, pool.getNumUsedBlocks()); // Empty dynamic buffer occupies one block
ASSERT_EQ(MGR_TEST_DATA[2].length(), fillTestData(MGR_TEST_DATA[2], tbb)); ASSERT_EQ(MGR_TEST_DATA[2].length(), fillTestData(MGR_TEST_DATA[2], tbb));
ASSERT_EQ(2, mgr->getNumStaticBuffers()); ASSERT_EQ(2, mgr->getNumStaticBuffers());
@@ -271,7 +281,7 @@ TEST(TransferBufferManager, Basic)
std::cout << "TransferBufferManager - Basic: Pool usage: " << pool.getNumUsedBlocks() << std::endl; std::cout << "TransferBufferManager - Basic: Pool usage: " << pool.getNumUsedBlocks() << std::endl;
// Dynamic 2 // Dynamic 2
ASSERT_TRUE((tbb = mgr->create(127))); ASSERT_TRUE((tbb = mgr->create(keys[3])));
ASSERT_EQ(0, pool.getNumFreeBlocks()); // The test assumes that the memory must be exhausted now ASSERT_EQ(0, pool.getNumFreeBlocks()); // The test assumes that the memory must be exhausted now
ASSERT_EQ(0, fillTestData(MGR_TEST_DATA[3], tbb)); ASSERT_EQ(0, fillTestData(MGR_TEST_DATA[3], tbb));
@@ -279,46 +289,46 @@ TEST(TransferBufferManager, Basic)
ASSERT_EQ(2, mgr->getNumDynamicBuffers()); ASSERT_EQ(2, mgr->getNumDynamicBuffers());
// Dynamic 3 - will fail due to OOM // Dynamic 3 - will fail due to OOM
ASSERT_FALSE((tbb = mgr->create(64))); ASSERT_FALSE((tbb = mgr->create(keys[4])));
ASSERT_EQ(2, mgr->getNumStaticBuffers()); ASSERT_EQ(2, mgr->getNumStaticBuffers());
ASSERT_EQ(2, mgr->getNumDynamicBuffers()); ASSERT_EQ(2, mgr->getNumDynamicBuffers());
// Making sure all buffers contain proper data // Making sure all buffers contain proper data
ASSERT_TRUE((tbb = mgr->access(0))); ASSERT_TRUE((tbb = mgr->access(keys[0])));
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[0], *tbb)); ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[0], *tbb));
ASSERT_TRUE((tbb = mgr->access(1))); ASSERT_TRUE((tbb = mgr->access(keys[1])));
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[1], *tbb)); ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[1], *tbb));
ASSERT_TRUE((tbb = mgr->access(2))); ASSERT_TRUE((tbb = mgr->access(keys[2])));
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[2], *tbb)); ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[2], *tbb));
ASSERT_TRUE((tbb = mgr->access(127))); ASSERT_TRUE((tbb = mgr->access(keys[3])));
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb)); ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
// Freeing one static buffer; one dynamic must migrate // Freeing one static buffer; one dynamic must migrate
mgr->remove(1); mgr->remove(keys[1]);
ASSERT_FALSE(mgr->access(1)); ASSERT_FALSE(mgr->access(keys[1]));
ASSERT_EQ(2, mgr->getNumStaticBuffers()); ASSERT_EQ(2, mgr->getNumStaticBuffers());
ASSERT_EQ(1, mgr->getNumDynamicBuffers()); // One migrated to the static ASSERT_EQ(1, mgr->getNumDynamicBuffers()); // One migrated to the static
ASSERT_LT(0, pool.getNumFreeBlocks()); ASSERT_LT(0, pool.getNumFreeBlocks());
// Removing NodeID 0; migration should fail due to oversized data // Removing NodeID 0; migration should fail due to oversized data
mgr->remove(0); mgr->remove(keys[0]);
ASSERT_FALSE(mgr->access(0)); ASSERT_FALSE(mgr->access(keys[0]));
ASSERT_EQ(1, mgr->getNumStaticBuffers()); ASSERT_EQ(1, mgr->getNumStaticBuffers());
ASSERT_EQ(1, mgr->getNumDynamicBuffers()); // Migration failed ASSERT_EQ(1, mgr->getNumDynamicBuffers()); // Migration failed
// At this time we have the following NodeID: 2, 127 // At this time we have the following NodeID: 2, 127
ASSERT_TRUE((tbb = mgr->access(2))); ASSERT_TRUE((tbb = mgr->access(keys[2])));
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[2], *tbb)); ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[2], *tbb));
ASSERT_TRUE((tbb = mgr->access(127))); ASSERT_TRUE((tbb = mgr->access(keys[3])));
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb)); ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
// These were deleted: 0, 1 // These were deleted: 0, 1
ASSERT_FALSE(mgr->access(1)); ASSERT_FALSE(mgr->access(keys[1]));
ASSERT_FALSE(mgr->access(0)); ASSERT_FALSE(mgr->access(keys[0]));
// Deleting the object; all memory must be freed // Deleting the object; all memory must be freed
ASSERT_NE(0, pool.getNumUsedBlocks()); ASSERT_NE(0, pool.getNumUsedBlocks());
+23 -22
View File
@@ -11,16 +11,15 @@
struct RxFrameGenerator struct RxFrameGenerator
{ {
static const uint8_t DEFAULT_NODE_ID = 42; static const uavcan::TransferBufferManagerKey DEFAULT_KEY;
uint16_t data_type_id; uint16_t data_type_id;
uavcan::TransferType ttype; uavcan::TransferBufferManagerKey bufmgr_key;
uint8_t source_node_id;
RxFrameGenerator(uint16_t data_type_id, uavcan::TransferType ttype, uint8_t source_node_id = DEFAULT_NODE_ID) RxFrameGenerator(uint16_t data_type_id, uavcan::TransferType ttype,
const uavcan::TransferBufferManagerKey& bufmgr_key = DEFAULT_KEY)
: data_type_id(data_type_id) : data_type_id(data_type_id)
, ttype(ttype) , bufmgr_key(bufmgr_key)
, source_node_id(source_node_id)
{ } { }
uavcan::RxFrame operator()(int iface_index, const std::string& data, uint8_t frame_index, bool last, uavcan::RxFrame operator()(int iface_index, const std::string& data, uint8_t frame_index, bool last,
@@ -42,14 +41,16 @@ struct RxFrameGenerator
frm.last_frame = last; frm.last_frame = last;
std::copy(data.begin(), data.end(), frm.payload); std::copy(data.begin(), data.end(), frm.payload);
frm.payload_len = data.length(); frm.payload_len = data.length();
frm.source_node_id = source_node_id; frm.source_node_id = bufmgr_key.getNodeID();
frm.transfer_id = uavcan::TransferID(transfer_id); frm.transfer_id = uavcan::TransferID(transfer_id);
frm.transfer_type = ttype; frm.transfer_type = bufmgr_key.getTransferType();
return frm; return frm;
} }
}; };
const uavcan::TransferBufferManagerKey RxFrameGenerator::DEFAULT_KEY(42, uavcan::TRANSFER_TYPE_MESSAGE_UNICAST);
template <unsigned int BUFSIZE> template <unsigned int BUFSIZE>
struct Context struct Context
@@ -62,7 +63,7 @@ struct Context
: bufmgr(&poolmgr) : bufmgr(&poolmgr)
{ {
assert(poolmgr.allocate(1) == NULL); assert(poolmgr.allocate(1) == NULL);
receiver = uavcan::TransferReceiver(&bufmgr, RxFrameGenerator::DEFAULT_NODE_ID); receiver = uavcan::TransferReceiver(&bufmgr, RxFrameGenerator::DEFAULT_KEY);
} }
~Context() ~Context()
@@ -125,7 +126,7 @@ TEST(TransferReceiver, Basic)
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "12345678", 0, false, 0, 100))); CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "12345678", 0, false, 0, 100)));
CHECK_COMPLETE(rcv.addFrame(gen(0, "foo", 1, true, 0, 200))); CHECK_COMPLETE(rcv.addFrame(gen(0, "foo", 1, true, 0, 200)));
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.source_node_id), "12345678foo")); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "12345678foo"));
ASSERT_EQ(TransferReceiver::DEFAULT_TRANSFER_INTERVAL, rcv.getInterval()); // Not initialized yet ASSERT_EQ(TransferReceiver::DEFAULT_TRANSFER_INTERVAL, rcv.getInterval()); // Not initialized yet
ASSERT_EQ(100, rcv.getLastTransferTimestamp()); ASSERT_EQ(100, rcv.getLastTransferTimestamp());
@@ -142,7 +143,7 @@ TEST(TransferReceiver, Basic)
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "", 31,true, 1, 1300))); // Unexpected FI CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "", 31,true, 1, 1300))); // Unexpected FI
CHECK_COMPLETE( rcv.addFrame(gen(0, "", 2, true, 1, 1300))); CHECK_COMPLETE( rcv.addFrame(gen(0, "", 2, true, 1, 1300)));
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.source_node_id), "12345678abcdefgh")); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "12345678abcdefgh"));
ASSERT_GT(TransferReceiver::DEFAULT_TRANSFER_INTERVAL, rcv.getInterval()); ASSERT_GT(TransferReceiver::DEFAULT_TRANSFER_INTERVAL, rcv.getInterval());
ASSERT_LT(TransferReceiver::MIN_TRANSFER_INTERVAL, rcv.getInterval()); ASSERT_LT(TransferReceiver::MIN_TRANSFER_INTERVAL, rcv.getInterval());
ASSERT_EQ(1000, rcv.getLastTransferTimestamp()); ASSERT_EQ(1000, rcv.getLastTransferTimestamp());
@@ -157,7 +158,7 @@ TEST(TransferReceiver, Basic)
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 2, 2100))); // Wrong iface CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 2, 2100))); // Wrong iface
CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "qwe", 0, true, 2, 2200))); CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "qwe", 0, true, 2, 2200)));
ASSERT_FALSE(bufmgr.access(RxFrameGenerator::DEFAULT_NODE_ID)); // Buffer must be removed ASSERT_FALSE(bufmgr.access(gen.bufmgr_key)); // Buffer must be removed
ASSERT_GT(TransferReceiver::DEFAULT_TRANSFER_INTERVAL, rcv.getInterval()); ASSERT_GT(TransferReceiver::DEFAULT_TRANSFER_INTERVAL, rcv.getInterval());
ASSERT_EQ(2200, rcv.getLastTransferTimestamp()); ASSERT_EQ(2200, rcv.getLastTransferTimestamp());
@@ -203,14 +204,14 @@ TEST(TransferReceiver, Basic)
ASSERT_LT(TransferReceiver::DEFAULT_TRANSFER_INTERVAL, rcv.getInterval()); ASSERT_LT(TransferReceiver::DEFAULT_TRANSFER_INTERVAL, rcv.getInterval());
ASSERT_LE(TransferReceiver::MIN_TRANSFER_INTERVAL, rcv.getInterval()); ASSERT_LE(TransferReceiver::MIN_TRANSFER_INTERVAL, rcv.getInterval());
ASSERT_GE(TransferReceiver::MAX_TRANSFER_INTERVAL, rcv.getInterval()); ASSERT_GE(TransferReceiver::MAX_TRANSFER_INTERVAL, rcv.getInterval());
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.source_node_id), "12345678qwe")); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "12345678qwe"));
/* /*
* Buffer cleanup * Buffer cleanup
*/ */
ASSERT_TRUE(bufmgr.access(gen.source_node_id)); ASSERT_TRUE(bufmgr.access(gen.bufmgr_key));
context.receiver = TransferReceiver(); context.receiver = TransferReceiver();
ASSERT_FALSE(bufmgr.access(gen.source_node_id)); ASSERT_FALSE(bufmgr.access(gen.bufmgr_key));
} }
@@ -231,7 +232,7 @@ TEST(TransferReceiver, OutOfBufferSpace_32bytes)
CHECK_COMPLETE( rcv.addFrame(gen(1, "", 4, true, 10, 100000400))); // 32 CHECK_COMPLETE( rcv.addFrame(gen(1, "", 4, true, 10, 100000400))); // 32
ASSERT_EQ(100000000, rcv.getLastTransferTimestamp()); ASSERT_EQ(100000000, rcv.getLastTransferTimestamp());
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.source_node_id), "12345678123456781234567812345678")); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "12345678123456781234567812345678"));
/* /*
* Transfer longer than available buffer space * Transfer longer than available buffer space
@@ -243,7 +244,7 @@ TEST(TransferReceiver, OutOfBufferSpace_32bytes)
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "12345678", 4, true, 11, 100001300))); // 40 // EOT, ignored - lost sync CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "12345678", 4, true, 11, 100001300))); // 40 // EOT, ignored - lost sync
ASSERT_EQ(100000000, rcv.getLastTransferTimestamp()); ASSERT_EQ(100000000, rcv.getLastTransferTimestamp());
ASSERT_FALSE(bufmgr.access(gen.source_node_id)); // Buffer should be removed ASSERT_FALSE(bufmgr.access(gen.bufmgr_key)); // Buffer should be removed
} }
@@ -262,7 +263,7 @@ TEST(TransferReceiver, UnterminatedTransfer)
} }
CHECK_COMPLETE(rcv.addFrame(gen(1, "12345678", uavcan::Frame::FRAME_INDEX_MAX, true, 0, 1100))); CHECK_COMPLETE(rcv.addFrame(gen(1, "12345678", uavcan::Frame::FRAME_INDEX_MAX, true, 0, 1100)));
ASSERT_EQ(1000, rcv.getLastTransferTimestamp()); ASSERT_EQ(1000, rcv.getLastTransferTimestamp());
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.source_node_id), content)); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), content));
} }
@@ -281,7 +282,7 @@ TEST(TransferReceiver, OutOfOrderFrames)
CHECK_COMPLETE( rcv.addFrame(gen(1, "abcd", 2, true, 10, 100000400))); CHECK_COMPLETE( rcv.addFrame(gen(1, "abcd", 2, true, 10, 100000400)));
ASSERT_EQ(100000000, rcv.getLastTransferTimestamp()); ASSERT_EQ(100000000, rcv.getLastTransferTimestamp());
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.source_node_id), "12345678qwertyuiabcd")); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "12345678qwertyuiabcd"));
} }
@@ -302,7 +303,7 @@ TEST(TransferReceiver, IntervalMeasurement)
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwertyui", 1, false, tid.get(), timestamp))); CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwertyui", 1, false, tid.get(), timestamp)));
CHECK_COMPLETE( rcv.addFrame(gen(1, "abcd", 2, true, tid.get(), timestamp))); CHECK_COMPLETE( rcv.addFrame(gen(1, "abcd", 2, true, tid.get(), timestamp)));
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.source_node_id), "12345678qwertyuiabcd")); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "12345678qwertyuiabcd"));
ASSERT_EQ(timestamp, rcv.getLastTransferTimestamp()); ASSERT_EQ(timestamp, rcv.getLastTransferTimestamp());
timestamp += INTERVAL; timestamp += INTERVAL;
@@ -334,7 +335,7 @@ TEST(TransferReceiver, Restart)
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "12345678", 1, false, 0, 13000300))); // Continue 3 sec later, iface timeout CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "12345678", 1, false, 0, 13000300))); // Continue 3 sec later, iface timeout
CHECK_COMPLETE( rcv.addFrame(gen(1, "12345678", 2, true, 0, 13000400))); // OK nevertheless CHECK_COMPLETE( rcv.addFrame(gen(1, "12345678", 2, true, 0, 13000400))); // OK nevertheless
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.source_node_id), "123456781234567812345678")); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "123456781234567812345678"));
/* /*
* Begins OK, gets an iface timeout, switches to another iface * Begins OK, gets an iface timeout, switches to another iface
@@ -348,5 +349,5 @@ TEST(TransferReceiver, Restart)
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "12345678", 1, false, 2, 16000900))); // Continuing CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "12345678", 1, false, 2, 16000900))); // Continuing
CHECK_COMPLETE( rcv.addFrame(gen(0, "12345678", 2, true, 2, 16000910))); // Done CHECK_COMPLETE( rcv.addFrame(gen(0, "12345678", 2, true, 2, 16000910))); // Done
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.source_node_id), "123456781234567812345678")); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "123456781234567812345678"));
} }