diff --git a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/server.hpp b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/server.hpp index 24b4b99cff..b15dc9df39 100644 --- a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/server.hpp +++ b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/distributed/server.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace uavcan { @@ -69,39 +70,10 @@ class Server : private IAllocationRequestHandler return raft_core_.traverseLogFromEndUntil(NodeIDLogPredicate(node_id)); } - NodeID findFreeNodeID(const NodeID preferred_node_id) const - { - uint8_t candidate = preferred_node_id.isUnicast() ? preferred_node_id.get() : NodeID::Max; - - // Up - while (candidate <= NodeID::Max) - { - if (!isNodeIDTaken(candidate)) - { - return candidate; - } - candidate++; - } - - candidate = preferred_node_id.isUnicast() ? preferred_node_id.get() : NodeID::Max; - candidate--; // This has been tested already - - // Down - while (candidate > 0) - { - if (!isNodeIDTaken(candidate)) - { - return candidate; - } - candidate--; - } - - return NodeID(); - } - void allocateNewNode(const UniqueID& unique_id, const NodeID preferred_node_id) { - const NodeID allocated_node_id = findFreeNodeID(preferred_node_id); + const NodeID allocated_node_id = + NodeIDSelector(this, &Server::isNodeIDTaken).findFreeNodeID(preferred_node_id); if (!allocated_node_id.isUnicast()) { UAVCAN_TRACE("DynamicNodeIDServer", "Request ignored - no free node ID left"); diff --git a/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_id_selector.hpp b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_id_selector.hpp new file mode 100644 index 0000000000..2af730a67e --- /dev/null +++ b/libuavcan/include/uavcan/protocol/dynamic_node_id_server/node_id_selector.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Pavel Kirienko + */ + +#ifndef UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_NODE_ID_SELECTOR_HPP_INCLUDED +#define UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_NODE_ID_SELECTOR_HPP_INCLUDED + +#include +#include + +namespace uavcan +{ +namespace dynamic_node_id_server +{ +/** + * Node ID allocation logic + */ +template +class NodeIDSelector +{ + typedef bool (Owner::*IsNodeIDTakenMethod)(const NodeID node_id) const; + + const Owner* const owner_; + const IsNodeIDTakenMethod is_node_id_taken_; + +public: + NodeIDSelector(const Owner* owner, IsNodeIDTakenMethod is_node_id_taken) + : owner_(owner) + , is_node_id_taken_(is_node_id_taken) + { + UAVCAN_ASSERT(owner_ != NULL); + UAVCAN_ASSERT(is_node_id_taken_ != NULL); + } + + /** + * Reutrns a default-constructed (invalid) node ID if a free one could not be found. + */ + NodeID findFreeNodeID(const NodeID preferred_node_id) const + { + uint8_t candidate = preferred_node_id.isUnicast() ? preferred_node_id.get() : NodeID::Max; + + // Up + while (candidate <= NodeID::Max) + { + if (!(owner_->*is_node_id_taken_)(candidate)) + { + return candidate; + } + candidate++; + } + + candidate = preferred_node_id.isUnicast() ? preferred_node_id.get() : NodeID::Max; + candidate--; // This has been tested already + + // Down + while (candidate > 0) + { + if (!(owner_->*is_node_id_taken_)(candidate)) + { + return candidate; + } + candidate--; + } + + return NodeID(); + } +}; + +} +} + +#endif // Include guard