libuav original
Dependents: UAVCAN UAVCAN_Subscriber
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
Generated on Tue Jul 12 2022 17:17:32 by 1.7.2