libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers global_data_type_registry.hpp Source File

global_data_type_registry.hpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #ifndef UAVCAN_NODE_GLOBAL_DATA_TYPE_REGISTRY_HPP_INCLUDED
00006 #define UAVCAN_NODE_GLOBAL_DATA_TYPE_REGISTRY_HPP_INCLUDED
00007 
00008 #include <cassert>
00009 #include <uavcan/error.hpp>
00010 #include <uavcan/std.hpp>
00011 #include <uavcan/data_type.hpp>
00012 #include <uavcan/util/templates.hpp>
00013 #include <uavcan/util/linked_list.hpp>
00014 #if UAVCAN_DEBUG
00015 # include <uavcan/debug.hpp>
00016 #endif
00017 
00018 namespace uavcan
00019 {
00020 /**
00021  * This singleton is shared among all existing node instances. It is instantiated automatically
00022  * when the C++ runtime executes contstructors before main().
00023  *
00024  * Its purpose is to keep the list of all UAVCAN data types known and used by this application.
00025  *
00026  * Also, the mapping between Data Type name and its Data Type ID is also stored in this singleton.
00027  * UAVCAN data types with default Data Type ID that are autogenerated by the libuavcan DSDL compiler
00028  * are registered automatically before main() (refer to the generated headers to see how exactly).
00029  * Data types that don't have a default Data Type ID must be registered manually using the methods
00030  * of this class (read the method documentation).
00031  *
00032  * Attempt to use a data type that was not registered with this singleton (e.g. publish, subscribe,
00033  * perform a service call etc.) will fail with an error code @ref ErrUnknownDataType.
00034  */
00035 class UAVCAN_EXPORT GlobalDataTypeRegistry : Noncopyable
00036 {
00037     struct Entry : public LinkedListNode<Entry>
00038     {
00039         DataTypeDescriptor descriptor;
00040 
00041         Entry() { }
00042 
00043         Entry(DataTypeKind kind, DataTypeID id, const DataTypeSignature& signature, const char* name)
00044             : descriptor(kind, id, signature, name)
00045         { }
00046     };
00047 
00048     struct EntryInsertionComparator
00049     {
00050         const DataTypeID id;
00051         explicit EntryInsertionComparator(const Entry* dtd)
00052             : id((dtd == UAVCAN_NULLPTR) ? DataTypeID() : dtd->descriptor.getID())
00053         {
00054             UAVCAN_ASSERT(dtd != UAVCAN_NULLPTR);
00055         }
00056         bool operator()(const Entry* entry) const
00057         {
00058             UAVCAN_ASSERT(entry != UAVCAN_NULLPTR);
00059             return entry->descriptor.getID() > id;
00060         }
00061     };
00062 
00063 public:
00064     /**
00065      * Result of data type registration
00066      */
00067     enum RegistrationResult
00068     {
00069         RegistrationResultOk,            ///< Success, data type is now registered and can be used.
00070         RegistrationResultCollision,     ///< Data type name or ID is not unique.
00071         RegistrationResultInvalidParams, ///< Invalid input parameters.
00072         RegistrationResultFrozen         ///< Data Type Registery has been frozen and can't be modified anymore.
00073     };
00074 
00075 private:
00076     typedef LinkedListRoot<Entry>  List;
00077     mutable List msgs_;
00078     mutable List srvs_;
00079     bool frozen_;
00080 
00081     GlobalDataTypeRegistry() : frozen_(false) { }
00082 
00083     List* selectList(DataTypeKind kind) const;
00084 
00085     RegistrationResult remove(Entry* dtd);
00086     RegistrationResult registImpl(Entry* dtd);
00087 
00088 public:
00089     /**
00090      * Returns the reference to the singleton.
00091      */
00092     static GlobalDataTypeRegistry& instance();
00093 
00094     /**
00095      * Register a data type 'Type' with ID 'id'.
00096      * If this data type was registered earlier, its old registration will be overridden.
00097      * This method will fail if the data type registry is frozen.
00098      *
00099      * @tparam Type     Autogenerated UAVCAN data type to register. Data types are generated by the
00100      *                  libuavcan DSDL compiler from DSDL definitions.
00101      *
00102      * @param id        Data Type ID for this data type.
00103      */
00104     template <typename Type>
00105     RegistrationResult registerDataType(DataTypeID id);
00106 
00107     /**
00108      * Data Type registry needs to be frozen before a node instance can use it in
00109      * order to prevent accidental change in data type configuration on a running
00110      * node.
00111      *
00112      * This method will be called automatically by the node during start up, so
00113      * the user does not need to call it from the application manually. Subsequent
00114      * calls will not have any effect.
00115      *
00116      * Once frozen, data type registry can't be unfrozen.
00117      */
00118     void freeze();
00119     bool isFrozen() const { return frozen_; }
00120 
00121     /**
00122      * Finds data type descriptor by full data type name, e.g. "uavcan.protocol.NodeStatus".
00123      * Messages are searched first, then services.
00124      * Returns null pointer if the data type with this name is not registered.
00125      * @param name  Full data type name
00126      * @return      Descriptor for this data type or null pointer if not found
00127      */
00128     const DataTypeDescriptor* find(const char* name) const;
00129 
00130     /**
00131      * Finds data type descriptor by full data type name, e.g. "uavcan.protocol.NodeStatus", and data type kind.
00132      * Returns null pointer if the data type with this name is not registered.
00133      * @param kind  Data Type Kind - message or service
00134      * @param name  Full data type name
00135      * @return      Descriptor for this data type or null pointer if not found
00136      */
00137     const DataTypeDescriptor* find(DataTypeKind kind, const char* name) const;
00138 
00139     /**
00140      * Finds data type descriptor by data type ID.
00141      * Returns null pointer if the data type with this ID is not registered.
00142      * @param kind  Data Type Kind - message or service
00143      * @param dtid  Data Type ID
00144      * @return      Descriptor for this data type or null pointer if not found
00145      */
00146     const DataTypeDescriptor* find(DataTypeKind kind, DataTypeID dtid) const;
00147 
00148     /**
00149      * Returns the number of registered message types.
00150      */
00151     unsigned getNumMessageTypes() const { return msgs_.getLength(); }
00152 
00153     /**
00154      * Returns the number of registered service types.
00155      */
00156     unsigned getNumServiceTypes() const { return srvs_.getLength(); }
00157 
00158 #if UAVCAN_DEBUG
00159     /// Required for unit testing
00160     void reset()
00161     {
00162         UAVCAN_TRACE("GlobalDataTypeRegistry", "Reset; was frozen: %i, num msgs: %u, num srvs: %u",
00163                      int(frozen_), getNumMessageTypes(), getNumServiceTypes());
00164         frozen_ = false;
00165         while (msgs_.get())
00166         {
00167             msgs_.remove(msgs_.get());
00168         }
00169         while (srvs_.get())
00170         {
00171             srvs_.remove(srvs_.get());
00172         }
00173     }
00174 #endif
00175 };
00176 
00177 /**
00178  * This class is used by autogenerated data types to register with the
00179  * data type registry automatically before main() is called. Note that
00180  * if a generated data type header file is not included by any translation
00181  * unit of the application, the data type will not be registered.
00182  *
00183  * Data type needs to have a default ID to be registrable by this class.
00184  */
00185 template <typename Type>
00186 struct UAVCAN_EXPORT DefaultDataTypeRegistrator
00187 {
00188     DefaultDataTypeRegistrator()
00189     {
00190 #if !UAVCAN_NO_GLOBAL_DATA_TYPE_REGISTRY
00191         const GlobalDataTypeRegistry::RegistrationResult res =
00192             GlobalDataTypeRegistry::instance().registerDataType<Type>(Type::DefaultDataTypeID);
00193 
00194         if (res != GlobalDataTypeRegistry::RegistrationResultOk)
00195         {
00196             handleFatalError("Type reg failed");
00197         }
00198 #endif
00199     }
00200 };
00201 
00202 // ----------------------------------------------------------------------------
00203 
00204 /*
00205  * GlobalDataTypeRegistry
00206  */
00207 template <typename Type>
00208 GlobalDataTypeRegistry::RegistrationResult GlobalDataTypeRegistry::registerDataType(DataTypeID id)
00209 {
00210     if (isFrozen())
00211     {
00212         return RegistrationResultFrozen;
00213     }
00214 
00215     static Entry entry;
00216 
00217     {
00218         const RegistrationResult remove_res = remove(&entry);
00219         if (remove_res != RegistrationResultOk)
00220         {
00221             return remove_res;
00222         }
00223     }
00224 
00225     // We can't just overwrite the entry itself because it's noncopyable
00226     entry.descriptor = DataTypeDescriptor(DataTypeKind(Type::DataTypeKind), id,
00227                                           Type::getDataTypeSignature(), Type::getDataTypeFullName());
00228 
00229     {
00230         const RegistrationResult remove_res = remove(&entry);
00231         if (remove_res != RegistrationResultOk)
00232         {
00233             return remove_res;
00234         }
00235     }
00236     return registImpl(&entry);
00237 }
00238 
00239 }
00240 
00241 #endif // UAVCAN_NODE_GLOBAL_DATA_TYPE_REGISTRY_HPP_INCLUDED