diff --git a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp index 0f96708cd5..93e78d8a9e 100644 --- a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp +++ b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_discoverer.hpp @@ -86,6 +86,27 @@ class NodeDiscoverer : TimerBase typedef Map NodeMap; + class HighestUptimeSearcher : ::uavcan::Noncopyable + { + uint32_t highest_uptime_sec_; + NodeID node_id_; + + public: + HighestUptimeSearcher() : highest_uptime_sec_(0) { } + + bool operator()(const NodeID& key, const NodeData& value) + { + if (value.last_seen_uptime >= highest_uptime_sec_) + { + highest_uptime_sec_ = value.last_seen_uptime; + node_id_ = key; + } + return false; + } + + NodeID getNodeWithHighestUptime() const { return node_id_; } + }; + /** * When this number of attempts has been made, the discoverer will give up and assume that the node * does not implement this service. @@ -121,34 +142,13 @@ class NodeDiscoverer : TimerBase NodeID pickNextNodeToQuery() const { - const unsigned node_map_size = node_map_.getSize(); + HighestUptimeSearcher searcher; - // Searching the lowest number of attempts made - uint8_t lowest_number_of_attempts = static_cast(MaxAttemptsToGetNodeInfo + 1U); - for (unsigned i = 0; i < node_map_size; i++) - { - const NodeMap::KVPair* const kv = node_map_.getByIndex(i); - UAVCAN_ASSERT(kv != NULL); - lowest_number_of_attempts = min(lowest_number_of_attempts, kv->value.num_get_node_info_attempts); - } + const NodeID* const out = node_map_.findFirstKey(searcher); + (void)out; + UAVCAN_ASSERT(out == NULL); - // Now, among nodes with this number of attempts selecting the one with highest uptime. - NodeID output; - uint32_t largest_uptime = 0; - for (unsigned i = 0; i < node_map_size; i++) - { - const NodeMap::KVPair* const kv = node_map_.getByIndex(i); - UAVCAN_ASSERT(kv != NULL); - if ((kv->value.num_get_node_info_attempts == lowest_number_of_attempts) && - (kv->value.last_seen_uptime >= largest_uptime)) - { - largest_uptime = kv->value.last_seen_uptime; - output = kv->key; - } - } - - // An invalid node ID will be returned only if there's no nodes at all. - return output; + return searcher.getNodeWithHighestUptime(); } bool needToQuery(NodeID node_id) @@ -319,7 +319,7 @@ class NodeDiscoverer : TimerBase if (!isRunning()) { - startPeriodic(get_node_info_client_.getRequestTimeout() * 2); + startPeriodic(get_node_info_client_.getRequestTimeout()); trace(TraceDiscoveryTimerStart, getPeriod().toUSec()); } } diff --git a/libuavcan/test/protocol/dynamic_node_id_server/node_discoverer.cpp b/libuavcan/test/protocol/dynamic_node_id_server/node_discoverer.cpp index 427213bad1..4c28113ead 100644 --- a/libuavcan/test/protocol/dynamic_node_id_server/node_discoverer.cpp +++ b/libuavcan/test/protocol/dynamic_node_id_server/node_discoverer.cpp @@ -134,7 +134,7 @@ TEST(dynamic_node_id_server_NodeDiscoverer, Basic) */ handler.can_discover = true; - nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1900)); + nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1400)); ASSERT_EQ(1, tracer.countEvents(TraceDiscoveryNewNodeFound)); ASSERT_EQ(1, tracer.countEvents(TraceDiscoveryTimerStart)); @@ -149,7 +149,7 @@ TEST(dynamic_node_id_server_NodeDiscoverer, Basic) node_status.uptime_sec += 5U; ASSERT_LE(0, node_status_pub.broadcast(node_status)); - nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1900)); + nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1400)); ASSERT_EQ(1, tracer.countEvents(TraceDiscoveryNewNodeFound)); ASSERT_EQ(1, tracer.countEvents(TraceDiscoveryTimerStart)); @@ -167,7 +167,7 @@ TEST(dynamic_node_id_server_NodeDiscoverer, Basic) get_node_info_server.response.hardware_version.unique_id[14] = 52; ASSERT_LE(0, get_node_info_server.start()); - nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1900)); + nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1400)); ASSERT_EQ(1, tracer.countEvents(TraceDiscoveryNewNodeFound)); ASSERT_EQ(1, tracer.countEvents(TraceDiscoveryTimerStart));