From 33bb1be4a17f1cd899c07b069c690c3bdbf78b4d Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Wed, 9 Apr 2014 17:19:31 +0400 Subject: [PATCH] Space optimized GenericSubscriber --- .../uavcan/node/generic_subscriber.hpp | 180 ++++++++++-------- libuavcan/src/node/uc_generic_subscriber.cpp | 37 ++++ 2 files changed, 136 insertions(+), 81 deletions(-) create mode 100644 libuavcan/src/node/uc_generic_subscriber.cpp diff --git a/libuavcan/include/uavcan/node/generic_subscriber.hpp b/libuavcan/include/uavcan/node/generic_subscriber.hpp index b086965f64..b0f1f9e387 100644 --- a/libuavcan/include/uavcan/node/generic_subscriber.hpp +++ b/libuavcan/include/uavcan/node/generic_subscriber.hpp @@ -68,6 +68,28 @@ static Stream& operator<<(Stream& s, const ReceivedDataStructure& rds) } +class GenericSubscriberBase : Noncopyable +{ +protected: + INode& node_; + uint32_t failure_count_; + + GenericSubscriberBase(INode& node) + : node_(node) + , failure_count_(0) + { } + + ~GenericSubscriberBase() { } + + int genericStart(TransferListenerBase* listener, bool (Dispatcher::*registration_method)(TransferListenerBase*)); + + void stop(TransferListenerBase* listener); + +public: + INode& getNode() const { return node_; } +}; + + template class UAVCAN_EXPORT TransferListenerInstantiationHelper { @@ -83,7 +105,7 @@ public: template -class UAVCAN_EXPORT GenericSubscriber : Noncopyable +class UAVCAN_EXPORT GenericSubscriber : public GenericSubscriberBase { typedef GenericSubscriber SelfType; @@ -109,86 +131,20 @@ class UAVCAN_EXPORT GenericSubscriber : Noncopyable using ReceivedDataStructure::setTransfer; }; - INode& node_; LazyConstructor forwarder_; ReceivedDataStructureSpec message_; - uint32_t failure_count_; - int checkInit() - { - if (forwarder_) - { - return 0; - } + int checkInit(); - GlobalDataTypeRegistry::instance().freeze(); + bool decodeTransfer(IncomingTransfer& transfer); - const DataTypeDescriptor* const descr = - GlobalDataTypeRegistry::instance().find(DataTypeKind(DataSpec::DataTypeKind), - DataSpec::getDataTypeFullName()); - if (!descr) - { - UAVCAN_TRACE("GenericSubscriber", "Type [%s] is not registered", DataSpec::getDataTypeFullName()); - return -ErrUnknownDataType; - } - forwarder_.template construct - (*this, *descr, node_.getAllocator()); - return 0; - } + void handleIncomingTransfer(IncomingTransfer& transfer); - bool decodeTransfer(IncomingTransfer& transfer) - { - BitStream bitstream(transfer); - ScalarCodec codec(bitstream); - - message_.setTransfer(&transfer); - - const int decode_res = DataStruct::decode(message_, codec); - // We don't need the data anymore, the memory can be reused from the callback: - transfer.release(); - if (decode_res <= 0) - { - UAVCAN_TRACE("GenericSubscriber", "Unable to decode the message [%i] [%s]", - decode_res, DataSpec::getDataTypeFullName()); - failure_count_++; - node_.getDispatcher().getTransferPerfCounter().addError(); - return false; - } - return true; - } - - void handleIncomingTransfer(IncomingTransfer& transfer) - { - if (decodeTransfer(transfer)) - { - handleReceivedDataStruct(message_); - } - } - - int genericStart(bool (Dispatcher::*registration_method)(TransferListenerBase* listener)) - { - stop(); - - const int res = checkInit(); - if (res < 0) - { - UAVCAN_TRACE("GenericSubscriber", "Initialization failure [%s]", DataSpec::getDataTypeFullName()); - return res; - } - - if (!(node_.getDispatcher().*registration_method)(forwarder_)) - { - UAVCAN_TRACE("GenericSubscriber", "Failed to register transfer listener [%s]", - DataSpec::getDataTypeFullName()); - return -ErrInvalidTransferListener; - } - return 0; - } + int genericStart(bool (Dispatcher::*registration_method)(TransferListenerBase*)); protected: explicit GenericSubscriber(INode& node) - : node_(node) - , failure_count_(0) + : GenericSubscriberBase(node) { } virtual ~GenericSubscriber() { stop(); } @@ -212,12 +168,7 @@ protected: void stop() { - if (forwarder_) - { - node_.getDispatcher().unregisterMessageListener(forwarder_); - node_.getDispatcher().unregisterServiceRequestListener(forwarder_); - node_.getDispatcher().unregisterServiceResponseListener(forwarder_); - } + GenericSubscriberBase::stop(forwarder_); } uint32_t getFailureCount() const { return failure_count_; } @@ -225,9 +176,76 @@ protected: TransferListenerType* getTransferListener() { return forwarder_; } ReceivedDataStructure& getReceivedStructStorage() { return message_; } - -public: - INode& getNode() const { return node_; } }; +// ---------------------------------------------------------------------------- + +/* + * GenericSubscriber + */ +template +int GenericSubscriber::checkInit() +{ + if (forwarder_) + { + return 0; + } + GlobalDataTypeRegistry::instance().freeze(); + const DataTypeDescriptor* const descr = + GlobalDataTypeRegistry::instance().find(DataTypeKind(DataSpec::DataTypeKind), DataSpec::getDataTypeFullName()); + if (!descr) + { + UAVCAN_TRACE("GenericSubscriber", "Type [%s] is not registered", DataSpec::getDataTypeFullName()); + return -ErrUnknownDataType; + } + forwarder_.template construct + (*this, *descr, node_.getAllocator()); + return 0; +} + +template +bool GenericSubscriber::decodeTransfer(IncomingTransfer& transfer) +{ + BitStream bitstream(transfer); + ScalarCodec codec(bitstream); + + message_.setTransfer(&transfer); + + const int decode_res = DataStruct::decode(message_, codec); + // We don't need the data anymore, the memory can be reused from the callback: + transfer.release(); + if (decode_res <= 0) + { + UAVCAN_TRACE("GenericSubscriber", "Unable to decode the message [%i] [%s]", + decode_res, DataSpec::getDataTypeFullName()); + failure_count_++; + node_.getDispatcher().getTransferPerfCounter().addError(); + return false; + } + return true; +} + +template +void GenericSubscriber::handleIncomingTransfer(IncomingTransfer& transfer) +{ + if (decodeTransfer(transfer)) + { + handleReceivedDataStruct(message_); + } +} + +template +int GenericSubscriber:: +genericStart(bool (Dispatcher::*registration_method)(TransferListenerBase*)) +{ + const int res = checkInit(); + if (res < 0) + { + UAVCAN_TRACE("GenericSubscriber", "Initialization failure [%s]", DataSpec::getDataTypeFullName()); + return res; + } + return GenericSubscriberBase::genericStart(forwarder_, registration_method); +} + + } diff --git a/libuavcan/src/node/uc_generic_subscriber.cpp b/libuavcan/src/node/uc_generic_subscriber.cpp new file mode 100644 index 0000000000..2abd40c01b --- /dev/null +++ b/libuavcan/src/node/uc_generic_subscriber.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 Pavel Kirienko + */ + +#include + +namespace uavcan +{ + +int GenericSubscriberBase::genericStart(TransferListenerBase* listener, + bool (Dispatcher::*registration_method)(TransferListenerBase*)) +{ + if (listener == NULL) + { + assert(0); + return -ErrLogic; + } + stop(listener); + if (!(node_.getDispatcher().*registration_method)(listener)) + { + UAVCAN_TRACE("GenericSubscriber", "Failed to register transfer listener"); + return -ErrInvalidTransferListener; + } + return 0; +} + +void GenericSubscriberBase::stop(TransferListenerBase* listener) +{ + if (listener != NULL) + { + node_.getDispatcher().unregisterMessageListener(listener); + node_.getDispatcher().unregisterServiceRequestListener(listener); + node_.getDispatcher().unregisterServiceResponseListener(listener); + } +} + +}