libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers server.hpp Source File

server.hpp

00001 /*
00002  * Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #ifndef UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_CENTRALIZED_SERVER_HPP_INCLUDED
00006 #define UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_CENTRALIZED_SERVER_HPP_INCLUDED
00007 
00008 #include <uavcan/build_config.hpp>
00009 #include <uavcan/debug.hpp>
00010 #include <uavcan/protocol/dynamic_node_id_server/abstract_server.hpp>
00011 #include <uavcan/protocol/dynamic_node_id_server/node_id_selector.hpp>
00012 #include <uavcan/protocol/dynamic_node_id_server/storage_marshaller.hpp>
00013 #include <uavcan/protocol/dynamic_node_id_server/centralized/storage.hpp>
00014 
00015 namespace uavcan
00016 {
00017 namespace dynamic_node_id_server
00018 {
00019 namespace centralized
00020 {
00021 /**
00022  * This server is an alternative to @ref DistributedServer with the following differences:
00023  *  - It is not distributed, so using it means introducing a single point of failure into the system.
00024  *  - It takes less code space and requires less RAM, which makes it suitable for resource-constrained applications.
00025  *
00026  * This version is suitable only for simple non-critical systems.
00027  */
00028 class Server : public AbstractServer
00029 {
00030     Storage storage_;
00031 
00032     /*
00033      * Private methods
00034      */
00035     bool isNodeIDTaken(const NodeID node_id) const
00036     {
00037         return storage_.isNodeIDOccupied(node_id);
00038     }
00039 
00040     void tryPublishAllocationResult(const NodeID node_id, const UniqueID& unique_id)
00041     {
00042         const int res = allocation_request_manager_.broadcastAllocationResponse(unique_id, node_id);
00043         if (res < 0)
00044         {
00045             tracer_.onEvent(TraceError, res);
00046             node_.registerInternalFailure("Dynamic allocation response");
00047         }
00048     }
00049 
00050     /*
00051      * Methods of IAllocationRequestHandler
00052      */
00053     virtual bool canPublishFollowupAllocationResponse() const
00054     {
00055         return true;    // Because there's only one Centralized server in the system
00056     }
00057 
00058     virtual void handleAllocationRequest(const UniqueID& unique_id, const NodeID preferred_node_id)
00059     {
00060         const NodeID existing_node_id = storage_.getNodeIDForUniqueID(unique_id);
00061         if (existing_node_id.isValid())
00062         {
00063             tryPublishAllocationResult(existing_node_id, unique_id);
00064         }
00065         else
00066         {
00067             const NodeID allocated_node_id =
00068                 NodeIDSelector<Server>(this, &Server::isNodeIDTaken).findFreeNodeID(preferred_node_id);
00069 
00070             if (allocated_node_id.isUnicast())
00071             {
00072                 const int res = storage_.add(allocated_node_id, unique_id);
00073                 if (res >= 0)
00074                 {
00075                     tryPublishAllocationResult(allocated_node_id, unique_id);
00076                 }
00077                 else
00078                 {
00079                     tracer_.onEvent(TraceError, res);
00080                     node_.registerInternalFailure("CentralizedServer storage add");
00081                 }
00082             }
00083             else
00084             {
00085                 UAVCAN_TRACE("dynamic_node_id_server::distributed::Server", "Request ignored - no free node ID left");
00086             }
00087         }
00088     }
00089 
00090     /*
00091      * Methods of INodeDiscoveryHandler
00092      */
00093     virtual bool canDiscoverNewNodes() const
00094     {
00095         return true;    // Because there's only one Centralized server in the system
00096     }
00097 
00098     virtual NodeAwareness checkNodeAwareness(NodeID node_id) const
00099     {
00100         return storage_.isNodeIDOccupied(node_id) ? NodeAwarenessKnownAndCommitted : NodeAwarenessUnknown;
00101     }
00102 
00103     virtual void handleNewNodeDiscovery(const UniqueID* unique_id_or_null, NodeID node_id)
00104     {
00105         if (storage_.isNodeIDOccupied(node_id))
00106         {
00107             UAVCAN_ASSERT(0);   // Such node is already known, the class that called this method should have known that
00108             return;
00109         }
00110 
00111         const int res = storage_.add(node_id, (unique_id_or_null == UAVCAN_NULLPTR) ? UniqueID() : *unique_id_or_null);
00112         if (res < 0)
00113         {
00114             tracer_.onEvent(TraceError, res);
00115             node_.registerInternalFailure("CentralizedServer storage add");
00116         }
00117     }
00118 
00119 public:
00120     Server(INode& node,
00121            IStorageBackend& storage,
00122            IEventTracer& tracer)
00123         : AbstractServer(node, tracer)
00124         , storage_(storage)
00125     { }
00126 
00127     int init(const UniqueID& own_unique_id,
00128              const TransferPriority priority = TransferPriority::OneHigherThanLowest)
00129     {
00130         /*
00131          * Initializing storage first, because the next step requires it to be loaded
00132          */
00133         int res = storage_.init();
00134         if (res < 0)
00135         {
00136             return res;
00137         }
00138 
00139         /*
00140          * Common logic
00141          */
00142         res = AbstractServer::init(own_unique_id, priority);
00143         if (res < 0)
00144         {
00145             return res;
00146         }
00147 
00148         /*
00149          * Making sure that the server is started with the same node ID
00150          */
00151         {
00152             const NodeID stored_own_node_id = storage_.getNodeIDForUniqueID(getOwnUniqueID());
00153             if (stored_own_node_id.isValid())
00154             {
00155                 if (stored_own_node_id != node_.getNodeID())
00156                 {
00157                     return -ErrInvalidConfiguration;
00158                 }
00159             }
00160             else
00161             {
00162                 res = storage_.add(node_.getNodeID(), getOwnUniqueID());
00163                 if (res < 0)
00164                 {
00165                     return res;
00166                 }
00167             }
00168         }
00169 
00170         return 0;
00171     }
00172 
00173     uint8_t getNumAllocations() const { return storage_.getSize(); }
00174 };
00175 
00176 }
00177 }
00178 }
00179 
00180 #endif // UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_CENTRALIZED_SERVER_HPP_INCLUDED