From da34eae9c48cd658f1f163538e90091c734c8868 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 2 Jan 2018 11:32:35 +0200 Subject: [PATCH] Added IAdHocNodeStatusUpdater --- .../uavcan/protocol/node_status_provider.hpp | 35 +++++++++++++++++++ .../src/protocol/uc_node_status_provider.cpp | 10 ++++++ .../test/protocol/node_status_provider.cpp | 34 ++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/libuavcan/include/uavcan/protocol/node_status_provider.hpp b/libuavcan/include/uavcan/protocol/node_status_provider.hpp index 6a5bb1faaf..6206e76687 100644 --- a/libuavcan/include/uavcan/protocol/node_status_provider.hpp +++ b/libuavcan/include/uavcan/protocol/node_status_provider.hpp @@ -16,6 +16,29 @@ namespace uavcan { +/** + * This optional interface can be implemented by the user in order to update the node status as necessary, + * immediately before the next NodeStatus message is emitted by @ref NodeStatusProvider. + */ +class IAdHocNodeStatusUpdater +{ +public: + /** + * This method is invoked by the library from @ref NodeStatusProvider from the library's thread immediately + * before the next NodeStatus message is transmitted. The application can implement this method to perform + * node status updates only as necessary. + * The application is expected to invoke the methods of @ref NodeStatusProvider to update the status + * from this method. + * Note that this method is only invoked when publication is happening by the timer event. + * It will NOT be invoked if the following methods are used to trigger node status publication: + * - @ref NodeStatusProvider::startAndPublish() + * - @ref NodeStatusProvider::forcePublish() + */ + virtual void updateNodeStatus() = 0; + + virtual ~IAdHocNodeStatusUpdater() { } +}; + /** * Provides the status and basic information about this node to other network participants. * @@ -38,6 +61,8 @@ class UAVCAN_EXPORT NodeStatusProvider : private TimerBase protocol::GetNodeInfo::Response node_info_; + IAdHocNodeStatusUpdater* ad_hoc_status_updater_; + INode& getNode() { return node_status_pub_.getNode(); } bool isNodeInfoInitialized() const; @@ -58,6 +83,7 @@ public: , creation_timestamp_(node.getMonotonicTime()) , node_status_pub_(node) , gni_srv_(node) + , ad_hoc_status_updater_(UAVCAN_NULLPTR) { UAVCAN_ASSERT(!creation_timestamp_.isZero()); @@ -86,6 +112,15 @@ public: void setStatusPublicationPeriod(uavcan::MonotonicDuration period); uavcan::MonotonicDuration getStatusPublicationPeriod() const; + /** + * Configure the optional handler that is invoked before every node status message is emitted. + * By default no handler is installed. + * It is allowed to pass a null pointer, that will disable the ad-hoc update feature. + * @ref IAdHocNodeStatusUpdater + */ + void setAdHocNodeStatusUpdater(IAdHocNodeStatusUpdater* updater); + IAdHocNodeStatusUpdater* getAdHocNodeStatusUpdater() const { return ad_hoc_status_updater_; } + /** * Local node health code control. */ diff --git a/libuavcan/src/protocol/uc_node_status_provider.cpp b/libuavcan/src/protocol/uc_node_status_provider.cpp index 7f4b188939..a24034716c 100644 --- a/libuavcan/src/protocol/uc_node_status_provider.cpp +++ b/libuavcan/src/protocol/uc_node_status_provider.cpp @@ -34,6 +34,11 @@ void NodeStatusProvider::handleTimerEvent(const TimerEvent&) } else { + if (ad_hoc_status_updater_ != UAVCAN_NULLPTR) + { + ad_hoc_status_updater_->updateNodeStatus(); + } + const int res = publish(); if (res < 0) { @@ -109,6 +114,11 @@ uavcan::MonotonicDuration NodeStatusProvider::getStatusPublicationPeriod() const return TimerBase::getPeriod(); } +void NodeStatusProvider::setAdHocNodeStatusUpdater(IAdHocNodeStatusUpdater* updater) +{ + ad_hoc_status_updater_ = updater; // Can be nullptr, that's okay +} + void NodeStatusProvider::setHealth(uint8_t code) { node_info_.status.health = code; diff --git a/libuavcan/test/protocol/node_status_provider.cpp b/libuavcan/test/protocol/node_status_provider.cpp index 51c455a97b..2d57db3959 100644 --- a/libuavcan/test/protocol/node_status_provider.cpp +++ b/libuavcan/test/protocol/node_status_provider.cpp @@ -7,6 +7,19 @@ #include "helpers.hpp" +struct AdHocNodeStatusUpdater : public uavcan::IAdHocNodeStatusUpdater +{ + uavcan::uint64_t invokations; + + AdHocNodeStatusUpdater() : invokations(0) { } + + virtual void updateNodeStatus() + { + invokations++; + } +}; + + TEST(NodeStatusProvider, Basic) { InterlinkedTestNodesWithSysClock nodes; @@ -60,6 +73,11 @@ TEST(NodeStatusProvider, Basic) ASSERT_EQ(uavcan::MonotonicDuration::fromMSec(uavcan::protocol::NodeStatus::MAX_BROADCASTING_PERIOD_MS), nsp.getStatusPublicationPeriod()); + AdHocNodeStatusUpdater ad_hoc; + ASSERT_EQ(UAVCAN_NULLPTR, nsp.getAdHocNodeStatusUpdater()); + nsp.setAdHocNodeStatusUpdater(&ad_hoc); + ASSERT_EQ(&ad_hoc, nsp.getAdHocNodeStatusUpdater()); + /* * Initial status publication */ @@ -75,6 +93,8 @@ TEST(NodeStatusProvider, Basic) ASSERT_EQ(0, status_sub.collector.msg->vendor_specific_status_code); ASSERT_GE(1, status_sub.collector.msg->uptime_sec); + ASSERT_EQ(0, ad_hoc.invokations); // Not invoked from startAndPublish() + /* * Altering the vendor-specific status code, forcePublish()-ing it and checking the result */ @@ -90,6 +110,8 @@ TEST(NodeStatusProvider, Basic) ASSERT_EQ(1234, status_sub.collector.msg->vendor_specific_status_code); ASSERT_GE(1, status_sub.collector.msg->uptime_sec); + ASSERT_EQ(0, ad_hoc.invokations); // Not invoked from forcePublish() + /* * Explicit node info request */ @@ -113,4 +135,16 @@ TEST(NodeStatusProvider, Basic) ASSERT_TRUE(swver == gni_cln.collector.result->getResponse().software_version); ASSERT_EQ("superluminal_communication_unit", gni_cln.collector.result->getResponse().name); + + ASSERT_EQ(0, ad_hoc.invokations); // No timer-triggered publications happened yet + + /* + * Timer triggered publication + */ + EXPECT_EQ(3, nodes.a.getDispatcher().getTransferPerfCounter().getTxTransferCount()); + + nodes.spinBoth(nsp.getStatusPublicationPeriod()); + + EXPECT_EQ(1, ad_hoc.invokations); // No timer-triggered publications happened yet + EXPECT_EQ(4, nodes.a.getDispatcher().getTransferPerfCounter().getTxTransferCount()); }