From 0bc62a74c95de808475f87e7db2b9d4c7e4ea083 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 11 Feb 2014 21:55:36 +0400 Subject: [PATCH] TransferListener partially implemented --- .../internal/transport/transfer_listener.hpp | 78 ++++++++++++++----- libuavcan/src/transport/transfer_listener.cpp | 39 +++++++--- .../test/transport/transfer_listener.cpp | 3 +- 3 files changed, 89 insertions(+), 31 deletions(-) diff --git a/libuavcan/include/uavcan/internal/transport/transfer_listener.hpp b/libuavcan/include/uavcan/internal/transport/transfer_listener.hpp index 2892998a00..f2116d13c7 100644 --- a/libuavcan/include/uavcan/internal/transport/transfer_listener.hpp +++ b/libuavcan/include/uavcan/internal/transport/transfer_listener.hpp @@ -74,18 +74,16 @@ public: */ class MultiFrameIncomingTransfer : public IncomingTransfer, Noncopyable { - ITransferBufferManager* const bufmgr_; - const TransferBufferManagerKey bufmgr_key_; + TransferBufferAccessor& buf_acc_; const uint8_t buffer_offset_; ///< Number of bytes to skip from the beginning of the buffer space public: - MultiFrameIncomingTransfer(const RxFrame& last_frame, uint8_t buffer_offset, ITransferBufferManager* bufmgr, - const TransferBufferManagerKey& bufmgr_key); + MultiFrameIncomingTransfer(const RxFrame& last_frame, uint8_t buffer_offset, TransferBufferAccessor& tba); int read(unsigned int offset, uint8_t* data, unsigned int len) const; - void release() { bufmgr_->remove(bufmgr_key_); } + void release() { buf_acc_.remove(); } }; /** - * Transport internal, for dispatcher. + * Internal, refer to transport dispatcher. */ class TransferListenerBase : public LinkedListNode { @@ -100,7 +98,7 @@ protected: virtual ~TransferListenerBase() { } - void handleReception(TransferReceiver& receiver, const RxFrame& frame); + void handleReception(TransferReceiver& receiver, const RxFrame& frame, TransferBufferAccessor& tba); virtual void handleIncomingTransfer(IncomingTransfer& transfer) = 0; @@ -112,36 +110,80 @@ public: /** * This class should be derived by transfer receivers (subscribers, servers, callers). */ -template +template class TransferListener : protected TransferListenerBase, Noncopyable { - TransferBufferManager bufmgr_; - Map receivers_; + typedef TransferBufferManager BufferManager; + BufferManager bufmgr_; + Map receivers_; void handleFrame(const RxFrame& frame) { - // TODO + const TransferBufferManagerKey key(frame.source_node_id, frame.transfer_type); + + TransferReceiver* recv = receivers_.access(key); + if (recv == NULL) + { + if (frame.frame_index != 0) // We don't want to add registrations mid-transfer, that's pointless + return; + + TransferReceiver new_recv; + recv = receivers_.insert(key, new_recv); + if (recv == NULL) + { + UAVCAN_TRACE("TransferListener", "Receiver registration failed; frame %s", frame.toString().c_str()); + return; + } + } + TransferBufferAccessor tba(&bufmgr_, key); + handleReception(*recv, frame, tba); } - struct TimedOutReceiverPredicate + class TimedOutReceiverPredicate { - const uint64_t ts_monotonic; - TimedOutReceiverPredicate(uint64_t ts_monotonic) : ts_monotonic(ts_monotonic) { } + const uint64_t ts_monotonic_; + BufferManager& bufmgr_; + + public: + TimedOutReceiverPredicate(uint64_t ts_monotonic, BufferManager& bufmgr) + : ts_monotonic_(ts_monotonic) + , bufmgr_(bufmgr) + { } + bool operator()(const TransferBufferManagerKey& key, const TransferReceiver& value) const { - (void)key; - return value.isTimedOut(ts_monotonic); + if (value.isTimedOut(ts_monotonic_)) + { + /* + * TransferReceivers do not own their buffers - this helps the Map<> container to copy them + * around quickly and safely (using default operator==()). Downside is that we need to destroy + * the buffers manually. + * Maybe it is not good that the predicate is being using as mapping functor, but I ran out + * of better ideas. + */ + bufmgr_.remove(key); + return true; + } + return false; } }; void cleanup(uint64_t ts_monotonic) { - receivers_.removeWhere(TimedOutReceiverPredicate(ts_monotonic)); + receivers_.removeWhere(TimedOutReceiverPredicate(ts_monotonic, bufmgr_)); +#if UAVCAN_DEBUG + if (receivers_.isEmpty()) + { + assert(bufmgr_.isEmpty()); + } +#endif } public: - TransferListener(const DataTypeDescriptor* data_type) + TransferListener(const DataTypeDescriptor* data_type, IAllocator* allocator) : TransferListenerBase(data_type) + , bufmgr_(allocator) + , receivers_(allocator) { } ~TransferListener() diff --git a/libuavcan/src/transport/transfer_listener.cpp b/libuavcan/src/transport/transfer_listener.cpp index b48c99f367..66d1f33bae 100644 --- a/libuavcan/src/transport/transfer_listener.cpp +++ b/libuavcan/src/transport/transfer_listener.cpp @@ -41,26 +41,21 @@ int SingleFrameIncomingTransfer::read(unsigned int offset, uint8_t* data, unsign * MultiFrameIncomingTransfer */ MultiFrameIncomingTransfer::MultiFrameIncomingTransfer(const RxFrame& last_frame, uint8_t buffer_offset, - ITransferBufferManager* bufmgr, - const TransferBufferManagerKey& bufmgr_key) + TransferBufferAccessor& tba) : IncomingTransfer(last_frame.ts_monotonic, last_frame.ts_utc, last_frame.transfer_type, last_frame.transfer_id, last_frame.source_node_id) -, bufmgr_(bufmgr) -, bufmgr_key_(bufmgr_key) +, buf_acc_(tba) , buffer_offset_(buffer_offset) { - assert(bufmgr); - assert(!bufmgr_key.isEmpty()); assert(last_frame.last_frame); } int MultiFrameIncomingTransfer::read(unsigned int offset, uint8_t* data, unsigned int len) const { - const TransferBufferBase* const tbb = const_cast(bufmgr_)->access(bufmgr_key_); + const TransferBufferBase* const tbb = const_cast(buf_acc_).access(); if (tbb == NULL) { - UAVCAN_TRACE("MultiFrameIncomingTransfer", "Read failed: no such buffer %s", - bufmgr_key_.toString().c_str()); + UAVCAN_TRACE("MultiFrameIncomingTransfer", "Read failed: no such buffer"); return -1; } return tbb->read(offset + buffer_offset_, data, len); @@ -70,10 +65,30 @@ int MultiFrameIncomingTransfer::read(unsigned int offset, uint8_t* data, unsigne * TransferListenerBase */ void TransferListenerBase::handleReception(TransferReceiver& receiver, const RxFrame& frame, - const TransferBufferManagerKey& bufmgr_key) + TransferBufferAccessor& tba) { - const TransferReceiver::ResultCode result = receiver.addFrame(frame, bufmgr_key); - (void)result; + const TransferReceiver::ResultCode result = receiver.addFrame(frame, tba); + switch (result) + { + case TransferReceiver::RESULT_NOT_COMPLETE: + break; + + case TransferReceiver::RESULT_SINGLE_FRAME: + { + SingleFrameIncomingTransfer it(frame); + handleIncomingTransfer(it); + break; + } + case TransferReceiver::RESULT_COMPLETE: + { + // TODO: check CRC + // TODO: select the buffer offset + const int buffer_offset = 123; + MultiFrameIncomingTransfer it(frame, buffer_offset, tba); + handleIncomingTransfer(it); + break; + } + } } } diff --git a/libuavcan/test/transport/transfer_listener.cpp b/libuavcan/test/transport/transfer_listener.cpp index ba2148c9c8..009cd43688 100644 --- a/libuavcan/test/transport/transfer_listener.cpp +++ b/libuavcan/test/transport/transfer_listener.cpp @@ -76,8 +76,9 @@ TEST(MultiFrameIncomingTransfer, Basic) const RxFrame frame = makeFrame(); uavcan::TransferBufferManagerKey bufmgr_key(frame.source_node_id, frame.transfer_type); + uavcan::TransferBufferAccessor tba(&bufmgr, bufmgr_key); - MultiFrameIncomingTransfer it(frame, 3, &bufmgr, bufmgr_key); + MultiFrameIncomingTransfer it(frame, 3, tba); /* * Empty read must fail