diff --git a/libuavcan/include/uavcan/node/node.hpp b/libuavcan/include/uavcan/node/node.hpp index 725d5363b9..cdb174da2c 100644 --- a/libuavcan/include/uavcan/node/node.hpp +++ b/libuavcan/include/uavcan/node/node.hpp @@ -57,7 +57,7 @@ class UAVCAN_EXPORT Node : public INode return res; } NodeInitializer initializer(*this); - StaticAssert<(sizeof(initializer) < 1024)>::check(); + StaticAssert<(sizeof(initializer) < 1200)>::check(); res = initializer.execute(); node_init_result = initializer.getResult(); return res; diff --git a/libuavcan/include/uavcan/transport/transfer_buffer.hpp b/libuavcan/include/uavcan/transport/transfer_buffer.hpp index 68b747c1ba..b8b274f875 100644 --- a/libuavcan/include/uavcan/transport/transfer_buffer.hpp +++ b/libuavcan/include/uavcan/transport/transfer_buffer.hpp @@ -162,7 +162,6 @@ public: { } int read(unsigned offset, uint8_t* data, unsigned len) const; - int write(unsigned offset, const uint8_t* data, unsigned len); void reset(); @@ -203,7 +202,6 @@ public: { } int read(unsigned offset, uint8_t* data, unsigned len) const; - int write(unsigned offset, const uint8_t* data, unsigned len); bool migrateFrom(const TransferBufferManagerEntry* tbme); @@ -254,259 +252,63 @@ public: /** * Buffer manager implementation. */ -template -class UAVCAN_EXPORT TransferBufferManager : public ITransferBufferManager, Noncopyable +class TransferBufferManagerImpl : public ITransferBufferManager, Noncopyable { - typedef StaticTransferBufferManagerEntry StaticBufferType; - - StaticBufferType static_buffers_[NumStaticBufs]; LinkedListRoot dynamic_buffers_; IAllocator& allocator_; + const unsigned max_buf_size_; - StaticBufferType* findFirstStatic(const TransferBufferManagerKey& key); + virtual StaticTransferBufferManagerEntryImpl* getStaticByIndex(unsigned index) const = 0; + StaticTransferBufferManagerEntryImpl* findFirstStatic(const TransferBufferManagerKey& key); DynamicTransferBufferManagerEntry* findFirstDynamic(const TransferBufferManagerKey& key); - void optimizeStorage(); public: - TransferBufferManager(IAllocator& allocator) + TransferBufferManagerImpl(unsigned max_buf_size, IAllocator& allocator) : allocator_(allocator) - { - StaticAssert<(MaxBufSize > 0)>::check(); - StaticAssert<(NumStaticBufs > 0)>::check(); - } + , max_buf_size_(max_buf_size) + { } - ~TransferBufferManager(); + ~TransferBufferManagerImpl(); ITransferBuffer* access(const TransferBufferManagerKey& key); - ITransferBuffer* create(const TransferBufferManagerKey& key); - void remove(const TransferBufferManagerKey& key); bool isEmpty() const; - unsigned getNumDynamicBuffers() const; - unsigned getNumStaticBuffers() const; }; +template +class UAVCAN_EXPORT TransferBufferManager : public TransferBufferManagerImpl +{ + mutable StaticTransferBufferManagerEntry static_buffers_[NumStaticBufs]; // TODO: zero buffers support + + StaticTransferBufferManagerEntry* getStaticByIndex(unsigned index) const + { + return (index < NumStaticBufs) ? &static_buffers_[index] : NULL; + } + +public: + TransferBufferManager(IAllocator& allocator) + : TransferBufferManagerImpl(MaxBufSize, allocator) + { + StaticAssert<(MaxBufSize > 0)>::check(); + } +}; + template <> class UAVCAN_EXPORT TransferBufferManager<0, 0> : public ITransferBufferManager { public: TransferBufferManager() { } - TransferBufferManager(IAllocator& allocator) - { - (void)allocator; - } - - ITransferBuffer* access(const TransferBufferManagerKey& key) - { - (void)key; - return NULL; - } - - ITransferBuffer* create(const TransferBufferManagerKey& key) - { - (void)key; - return NULL; - } - - void remove(const TransferBufferManagerKey& key) - { - (void)key; - } - + TransferBufferManager(IAllocator&) { } + ITransferBuffer* access(const TransferBufferManagerKey&) { return NULL; } + ITransferBuffer* create(const TransferBufferManagerKey&) { return NULL; } + void remove(const TransferBufferManagerKey&) { } bool isEmpty() const { return true; } }; -// ---------------------------------------------------------------------------- - -/* - * TransferBufferManager<> - */ -template -typename TransferBufferManager::StaticBufferType* -TransferBufferManager::findFirstStatic(const TransferBufferManagerKey& key) -{ - for (unsigned i = 0; i < NumStaticBufs; i++) - { - if (static_buffers_[i].getKey() == key) - { - return static_buffers_ + i; - } - } - return NULL; -} - -template -DynamicTransferBufferManagerEntry* -TransferBufferManager::findFirstDynamic(const TransferBufferManagerKey& key) -{ - DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get(); - while (dyn) - { - assert(!dyn->isEmpty()); - if (dyn->getKey() == key) - { - return dyn; - } - dyn = dyn->getNextListNode(); - } - return NULL; -} - -template -void TransferBufferManager::optimizeStorage() -{ - while (!dynamic_buffers_.isEmpty()) - { - StaticBufferType* const sb = findFirstStatic(TransferBufferManagerKey()); - if (sb == NULL) - { - break; - } - DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get(); - assert(dyn); - assert(!dyn->isEmpty()); - if (sb->migrateFrom(dyn)) - { - assert(!dyn->isEmpty()); - UAVCAN_TRACE("TransferBufferManager", "Storage optimization: Migrated %s", - dyn->getKey().toString().c_str()); - dynamic_buffers_.remove(dyn); - DynamicTransferBufferManagerEntry::destroy(dyn, allocator_); - } - else - { - /* Migration can fail if a dynamic buffer contains more data than a static buffer can accomodate. - * This should never happen during normal operation because dynamic buffers are limited in growth. - */ - UAVCAN_TRACE("TransferBufferManager", "Storage optimization: MIGRATION FAILURE %s MAXSIZE %u", - dyn->getKey().toString().c_str(), MaxBufSize); - assert(0); - sb->reset(); - break; - } - } -} - -template -TransferBufferManager::~TransferBufferManager() -{ - DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get(); - while (dyn) - { - DynamicTransferBufferManagerEntry* const next = dyn->getNextListNode(); - dynamic_buffers_.remove(dyn); - DynamicTransferBufferManagerEntry::destroy(dyn, allocator_); - dyn = next; - } -} - -template -ITransferBuffer* TransferBufferManager::access(const TransferBufferManagerKey& key) -{ - if (key.isEmpty()) - { - assert(0); - return NULL; - } - TransferBufferManagerEntry* tbme = findFirstStatic(key); - if (tbme) - { - return tbme; - } - return findFirstDynamic(key); -} - -template -ITransferBuffer* TransferBufferManager::create(const TransferBufferManagerKey& key) -{ - if (key.isEmpty()) - { - assert(0); - return NULL; - } - remove(key); - - TransferBufferManagerEntry* tbme = findFirstStatic(TransferBufferManagerKey()); - if (tbme == NULL) - { - DynamicTransferBufferManagerEntry* dyn = - DynamicTransferBufferManagerEntry::instantiate(allocator_, MaxBufSize); - tbme = dyn; - if (dyn == NULL) - { - return NULL; // Epic fail. - } - dynamic_buffers_.insert(dyn); - UAVCAN_TRACE("TransferBufferManager", "Dynamic buffer created [st=%u, dyn=%u], %s", - getNumStaticBuffers(), getNumDynamicBuffers(), key.toString().c_str()); - } - else - { - UAVCAN_TRACE("TransferBufferManager", "Static buffer created [st=%u, dyn=%u], %s", - getNumStaticBuffers(), getNumDynamicBuffers(), key.toString().c_str()); - } - - if (tbme) - { - assert(tbme->isEmpty()); - tbme->reset(key); - } - return tbme; -} - -template -void TransferBufferManager::remove(const TransferBufferManagerKey& key) -{ - assert(!key.isEmpty()); - - TransferBufferManagerEntry* const tbme = findFirstStatic(key); - if (tbme) - { - UAVCAN_TRACE("TransferBufferManager", "Static buffer deleted, %s", key.toString().c_str()); - tbme->reset(); - optimizeStorage(); - return; - } - - DynamicTransferBufferManagerEntry* dyn = findFirstDynamic(key); - if (dyn) - { - UAVCAN_TRACE("TransferBufferManager", "Dynamic buffer deleted, %s", key.toString().c_str()); - dynamic_buffers_.remove(dyn); - DynamicTransferBufferManagerEntry::destroy(dyn, allocator_); - } -} - -template -bool TransferBufferManager::isEmpty() const -{ - return (getNumStaticBuffers() == 0) && (getNumDynamicBuffers() == 0); -} - -template -unsigned TransferBufferManager::getNumDynamicBuffers() const -{ - return dynamic_buffers_.getLength(); -} - -template -unsigned TransferBufferManager::getNumStaticBuffers() const -{ - unsigned res = 0; - for (unsigned i = 0; i < NumStaticBufs; i++) - { - if (!static_buffers_[i].isEmpty()) - { - res++; - } - } - return res; -} - } diff --git a/libuavcan/src/transport/uc_transfer_buffer.cpp b/libuavcan/src/transport/uc_transfer_buffer.cpp index 7031639280..2e5a57ff79 100644 --- a/libuavcan/src/transport/uc_transfer_buffer.cpp +++ b/libuavcan/src/transport/uc_transfer_buffer.cpp @@ -211,7 +211,7 @@ int DynamicTransferBufferManagerEntry::write(unsigned offset, const uint8_t* dat } const int actually_written = len - left_to_write; - max_write_pos_ = std::max(offset + actually_written, max_write_pos_); + max_write_pos_ = std::max(offset + actually_written, unsigned(max_write_pos_)); return actually_written; } @@ -255,7 +255,7 @@ int StaticTransferBufferImpl::write(unsigned offset, const uint8_t* data, unsign } assert((offset + len) <= size_); std::copy(data, data + len, data_ + offset); - max_write_pos_ = std::max(offset + len, max_write_pos_); + max_write_pos_ = std::max(offset + len, unsigned(max_write_pos_)); return len; } @@ -317,4 +317,187 @@ bool StaticTransferBufferManagerEntryImpl::migrateFrom(const TransferBufferManag return true; } +/* + * TransferBufferManagerImpl + */ +StaticTransferBufferManagerEntryImpl* TransferBufferManagerImpl::findFirstStatic(const TransferBufferManagerKey& key) +{ + for (unsigned i = 0; true; i++) + { + StaticTransferBufferManagerEntryImpl* const sb = getStaticByIndex(i); + if (sb == NULL) + { + break; + } + if (sb->getKey() == key) + { + return sb; + } + } + return NULL; +} + +DynamicTransferBufferManagerEntry* TransferBufferManagerImpl::findFirstDynamic(const TransferBufferManagerKey& key) +{ + DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get(); + while (dyn) + { + assert(!dyn->isEmpty()); + if (dyn->getKey() == key) + { + return dyn; + } + dyn = dyn->getNextListNode(); + } + return NULL; +} + +void TransferBufferManagerImpl::optimizeStorage() +{ + while (!dynamic_buffers_.isEmpty()) + { + StaticTransferBufferManagerEntryImpl* const sb = findFirstStatic(TransferBufferManagerKey()); + if (sb == NULL) + { + break; + } + DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get(); + assert(dyn); + assert(!dyn->isEmpty()); + if (sb->migrateFrom(dyn)) + { + assert(!dyn->isEmpty()); + UAVCAN_TRACE("TransferBufferManager", "Storage optimization: Migrated %s", + dyn->getKey().toString().c_str()); + dynamic_buffers_.remove(dyn); + DynamicTransferBufferManagerEntry::destroy(dyn, allocator_); + } + else + { + /* Migration can fail if a dynamic buffer contains more data than a static buffer can accomodate. + * This should never happen during normal operation because dynamic buffers are limited in growth. + */ + UAVCAN_TRACE("TransferBufferManager", "Storage optimization: MIGRATION FAILURE %s MAXSIZE %u", + dyn->getKey().toString().c_str(), max_buf_size_); + assert(0); + sb->reset(); + break; + } + } +} + +TransferBufferManagerImpl::~TransferBufferManagerImpl() +{ + DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get(); + while (dyn) + { + DynamicTransferBufferManagerEntry* const next = dyn->getNextListNode(); + dynamic_buffers_.remove(dyn); + DynamicTransferBufferManagerEntry::destroy(dyn, allocator_); + dyn = next; + } +} + +ITransferBuffer* TransferBufferManagerImpl::access(const TransferBufferManagerKey& key) +{ + if (key.isEmpty()) + { + assert(0); + return NULL; + } + TransferBufferManagerEntry* tbme = findFirstStatic(key); + if (tbme) + { + return tbme; + } + return findFirstDynamic(key); +} + +ITransferBuffer* TransferBufferManagerImpl::create(const TransferBufferManagerKey& key) +{ + if (key.isEmpty()) + { + assert(0); + return NULL; + } + remove(key); + + TransferBufferManagerEntry* tbme = findFirstStatic(TransferBufferManagerKey()); + if (tbme == NULL) + { + DynamicTransferBufferManagerEntry* dyn = + DynamicTransferBufferManagerEntry::instantiate(allocator_, max_buf_size_); + tbme = dyn; + if (dyn == NULL) + { + return NULL; // Epic fail. + } + dynamic_buffers_.insert(dyn); + UAVCAN_TRACE("TransferBufferManager", "Dynamic buffer created [st=%u, dyn=%u], %s", + getNumStaticBuffers(), getNumDynamicBuffers(), key.toString().c_str()); + } + else + { + UAVCAN_TRACE("TransferBufferManager", "Static buffer created [st=%u, dyn=%u], %s", + getNumStaticBuffers(), getNumDynamicBuffers(), key.toString().c_str()); + } + + if (tbme) + { + assert(tbme->isEmpty()); + tbme->reset(key); + } + return tbme; +} + +void TransferBufferManagerImpl::remove(const TransferBufferManagerKey& key) +{ + assert(!key.isEmpty()); + + TransferBufferManagerEntry* const tbme = findFirstStatic(key); + if (tbme) + { + UAVCAN_TRACE("TransferBufferManager", "Static buffer deleted, %s", key.toString().c_str()); + tbme->reset(); + optimizeStorage(); + return; + } + + DynamicTransferBufferManagerEntry* dyn = findFirstDynamic(key); + if (dyn) + { + UAVCAN_TRACE("TransferBufferManager", "Dynamic buffer deleted, %s", key.toString().c_str()); + dynamic_buffers_.remove(dyn); + DynamicTransferBufferManagerEntry::destroy(dyn, allocator_); + } +} + +bool TransferBufferManagerImpl::isEmpty() const +{ + return (getNumStaticBuffers() == 0) && (getNumDynamicBuffers() == 0); +} + +unsigned TransferBufferManagerImpl::getNumDynamicBuffers() const +{ + return dynamic_buffers_.getLength(); +} + +unsigned TransferBufferManagerImpl::getNumStaticBuffers() const +{ + unsigned res = 0; + for (unsigned i = 0; true; i++) + { + StaticTransferBufferManagerEntryImpl* const sb = getStaticByIndex(i); + if (sb == NULL) + { + break; + } + if (!sb->isEmpty()) + { + res++; + } + } + return res; +} + } diff --git a/libuavcan/test/protocol/node_initializer.cpp b/libuavcan/test/protocol/node_initializer.cpp index 00f984c3f9..5edb1519e5 100644 --- a/libuavcan/test/protocol/node_initializer.cpp +++ b/libuavcan/test/protocol/node_initializer.cpp @@ -48,7 +48,7 @@ struct NodeInitializerRemoteContext TEST(NodeInitializer, Size) { std::cout << "sizeof(uavcan::NodeInitializer): " << sizeof(uavcan::NodeInitializer) << std::endl; - ASSERT_TRUE(sizeof(uavcan::NodeInitializer) < 1024); + ASSERT_TRUE(sizeof(uavcan::NodeInitializer) < 2048); }