diff --git a/libuavcan/include/uavcan/data_type.hpp b/libuavcan/include/uavcan/data_type.hpp index dbc371fdaa..345bbafa7a 100644 --- a/libuavcan/include/uavcan/data_type.hpp +++ b/libuavcan/include/uavcan/data_type.hpp @@ -69,11 +69,8 @@ class DataTypeSignature void mixin64(uint64_t x); - DataTypeSignature() : value_(0) { } - public: - static DataTypeSignature zero() { return DataTypeSignature(); } - + DataTypeSignature() : value_(0) { } explicit DataTypeSignature(uint64_t value) : value_(value) { } void extend(DataTypeSignature dts); @@ -100,7 +97,6 @@ public: DataTypeDescriptor() : kind_(DataTypeKind(0)) , id_(0) - , signature_(DataTypeSignature::zero()) , name_("") { } @@ -121,6 +117,7 @@ public: const char* getName() const { return name_; } bool match(DataTypeKind kind, const char* name) const; + bool match(DataTypeKind kind, uint16_t id) const; std::string toString() const; diff --git a/libuavcan/include/uavcan/global_data_type_registry.hpp b/libuavcan/include/uavcan/global_data_type_registry.hpp index 0b8ece466c..56d9afa790 100644 --- a/libuavcan/include/uavcan/global_data_type_registry.hpp +++ b/libuavcan/include/uavcan/global_data_type_registry.hpp @@ -64,7 +64,7 @@ public: const DataTypeDescriptor* find(DataTypeKind kind, const char* name) const; - DataTypeSignature computeAggregateSignature(const DataTypeIDMask& msgs, const DataTypeIDMask& srvs) const; + DataTypeSignature computeAggregateSignature(DataTypeKind kind, DataTypeIDMask& inout_id_mask) const; void getDataTypeIDMask(DataTypeKind kind, DataTypeIDMask& mask) const; diff --git a/libuavcan/src/data_type.cpp b/libuavcan/src/data_type.cpp index afb6e062db..92d32b3d28 100644 --- a/libuavcan/src/data_type.cpp +++ b/libuavcan/src/data_type.cpp @@ -44,6 +44,11 @@ bool DataTypeDescriptor::match(DataTypeKind kind, const char* name) const return (kind_ == kind) && !std::strcmp(name_, name); } +bool DataTypeDescriptor::match(DataTypeKind kind, uint16_t id) const +{ + return (kind_ == kind) && (id_ == id); +} + std::string DataTypeDescriptor::toString() const { char kindch = '?'; diff --git a/libuavcan/src/global_data_type_registry.cpp b/libuavcan/src/global_data_type_registry.cpp index fd804f1c21..69bf8ba1bf 100644 --- a/libuavcan/src/global_data_type_registry.cpp +++ b/libuavcan/src/global_data_type_registry.cpp @@ -91,12 +91,55 @@ const DataTypeDescriptor* GlobalDataTypeRegistry::find(DataTypeKind kind, const return NULL; } -DataTypeSignature GlobalDataTypeRegistry::computeAggregateSignature(const DataTypeIDMask& msgs, - const DataTypeIDMask& srvs) const +DataTypeSignature GlobalDataTypeRegistry::computeAggregateSignature(DataTypeKind kind, + DataTypeIDMask& inout_id_mask) const { - (void)msgs; - (void)srvs; - return DataTypeSignature::zero(); // TODO: implementation + const List* list = selectList(kind); + if (list == NULL) + { + assert(0); + return DataTypeSignature(); + } + + DataTypeSignature signature; + bool signature_initialized = false; + + for (int id = 0; id <= DataTypeDescriptor::MaxDataTypeID; id++) + { + if (!inout_id_mask[id]) + continue; + + // TODO: do it faster - no need to traverse the list on each iteration + const DataTypeDescriptor* desc = NULL; + { + Entry* p = list->get(); + while (p) + { + if (p->decriptor.match(kind, id)) + { + desc = &p->decriptor; + break; + } + p = p->getNextListNode(); + } + } + + if (desc) + { + if (signature_initialized) + { + signature.extend(desc->getSignature()); + } + else + { + signature_initialized = true; + signature = DataTypeSignature(desc->getSignature()); + } + } + else + inout_id_mask[id] = false; + } + return signature; } void GlobalDataTypeRegistry::getDataTypeIDMask(DataTypeKind kind, DataTypeIDMask& mask) const diff --git a/libuavcan/test/data_type.cpp b/libuavcan/test/data_type.cpp index ccd2e5aff4..15fd79d203 100644 --- a/libuavcan/test/data_type.cpp +++ b/libuavcan/test/data_type.cpp @@ -42,7 +42,7 @@ TEST(DataTypeSignature, Correctness) using uavcan::DataTypeSignature; using uavcan::DataTypeSignatureCRC; - DataTypeSignature signature = DataTypeSignature::zero(); + DataTypeSignature signature; ASSERT_EQ(0, signature.get()); /* @@ -87,9 +87,9 @@ TEST(DataTypeSignature, Correctness) * Comparison */ ASSERT_TRUE(signature == DataTypeSignature(signature.get())); - ASSERT_FALSE(signature == DataTypeSignature::zero()); + ASSERT_FALSE(signature == DataTypeSignature()); ASSERT_FALSE(signature != DataTypeSignature(signature.get())); - ASSERT_TRUE(signature != DataTypeSignature::zero()); + ASSERT_TRUE(signature != DataTypeSignature()); } diff --git a/libuavcan/test/global_data_type_registry.cpp b/libuavcan/test/global_data_type_registry.cpp index f0cc73bb0a..305f17f1dd 100644 --- a/libuavcan/test/global_data_type_registry.cpp +++ b/libuavcan/test/global_data_type_registry.cpp @@ -31,6 +31,22 @@ namespace static const char* getDataTypeName() { return "my_namespace.DataTypeB"; } }; + struct DataTypeC + { + enum { DefaultDataTypeID = 43 }; + enum { DataTypeKind = uavcan::DataTypeKindMessage }; + static uavcan::DataTypeSignature getDataTypeSignature() { return uavcan::DataTypeSignature(654); } + static const char* getDataTypeName() { return "foo.DataTypeC"; } + }; + + struct DataTypeD + { + enum { DefaultDataTypeID = 43 }; + enum { DataTypeKind = uavcan::DataTypeKindService }; + static uavcan::DataTypeSignature getDataTypeSignature() { return uavcan::DataTypeSignature(987); } + static const char* getDataTypeName() { return "foo.DataTypeD"; } + }; + template uavcan::DataTypeDescriptor extractDescriptor(uint16_t dtid = Type::DefaultDataTypeID) @@ -44,13 +60,15 @@ namespace TEST(GlobalDataTypeRegistry, Basic) { using uavcan::GlobalDataTypeRegistry; + using uavcan::DataTypeIDMask; + using uavcan::DataTypeSignature; GlobalDataTypeRegistry::instance().reset(); ASSERT_FALSE(GlobalDataTypeRegistry::instance().isFrozen()); ASSERT_EQ(0, GlobalDataTypeRegistry::instance().getNumMessageTypes()); ASSERT_EQ(0, GlobalDataTypeRegistry::instance().getNumServiceTypes()); - uavcan::DataTypeIDMask dtmask; + DataTypeIDMask dtmask; dtmask.set(); GlobalDataTypeRegistry::instance().getDataTypeIDMask(uavcan::DataTypeKindMessage, dtmask); ASSERT_FALSE(dtmask.any()); @@ -106,6 +124,25 @@ TEST(GlobalDataTypeRegistry, Basic) dtmask[147] = false; ASSERT_FALSE(dtmask.any()); + /* + * These types will be necessary for the aggregate signature test + */ + ASSERT_TRUE(GlobalDataTypeRegistry::instance().assign(DataTypeC::DefaultDataTypeID)); + uavcan::DefaultDataTypeRegistrator reg_DataTypeD; + + GlobalDataTypeRegistry::instance().getDataTypeIDMask(uavcan::DataTypeKindMessage, dtmask); + ASSERT_TRUE(dtmask[0]); + ASSERT_TRUE(dtmask[741]); + ASSERT_TRUE(dtmask[43]); + dtmask[0] = dtmask[43] = dtmask[741] = false; + ASSERT_FALSE(dtmask.any()); + + GlobalDataTypeRegistry::instance().getDataTypeIDMask(uavcan::DataTypeKindService, dtmask); + ASSERT_TRUE(dtmask[147]); + ASSERT_TRUE(dtmask[43]); + dtmask[43] = dtmask[147] = false; + ASSERT_FALSE(dtmask.any()); + /* * Frozen state */ @@ -131,14 +168,76 @@ TEST(GlobalDataTypeRegistry, Basic) ASSERT_TRUE((pdtd = GlobalDataTypeRegistry::instance().find(uavcan::DataTypeKindService, "my_namespace.DataTypeA"))); ASSERT_EQ(extractDescriptor(147), *pdtd); +} - /* - * Aggregate signature computation - */ - // TODO: test + +TEST(GlobalDataTypeRegistry, AggregateSignature) +{ + using uavcan::GlobalDataTypeRegistry; + using uavcan::DataTypeIDMask; + using uavcan::DataTypeSignature; + + ASSERT_TRUE(GlobalDataTypeRegistry::instance().isFrozen()); + + DataTypeIDMask mask; + DataTypeSignature sign; + + // Zero - empty mask + sign = GlobalDataTypeRegistry::instance().computeAggregateSignature(uavcan::DataTypeKindMessage, mask); + + ASSERT_EQ(DataTypeSignature(), sign); + ASSERT_FALSE(mask.any()); + + // All set + mask.set(); + sign = GlobalDataTypeRegistry::instance().computeAggregateSignature(uavcan::DataTypeKindMessage, mask); + ASSERT_TRUE(mask[0]); // DataTypeAMessage + ASSERT_TRUE(mask[43]); // DataTypeC + ASSERT_TRUE(mask[741]); // DataTypeB + mask[0] = mask[43] = mask[741] = false; + ASSERT_FALSE(mask.any()); + { + DataTypeSignature check_signature(DataTypeAMessage::getDataTypeSignature()); // Order matters - low --> high + check_signature.extend(DataTypeC::getDataTypeSignature()); + check_signature.extend(DataTypeB::getDataTypeSignature()); + ASSERT_EQ(check_signature, sign); + } + + mask.set(); + sign = GlobalDataTypeRegistry::instance().computeAggregateSignature(uavcan::DataTypeKindService, mask); + ASSERT_TRUE(mask[43]); // DataTypeD + ASSERT_TRUE(mask[147]); // DataTypeAService + mask[43] = mask[147] = false; + ASSERT_FALSE(mask.any()); + { + DataTypeSignature check_signature(DataTypeD::getDataTypeSignature()); + check_signature.extend(DataTypeAService::getDataTypeSignature()); + ASSERT_EQ(check_signature, sign); + } + + // Random + mask[0] = mask[99] = mask[147] = mask[741] = mask[999] = true; + sign = GlobalDataTypeRegistry::instance().computeAggregateSignature(uavcan::DataTypeKindMessage, mask); + ASSERT_TRUE(mask[0]); // DataTypeAMessage + ASSERT_TRUE(mask[741]); // DataTypeB + mask[0] = mask[741] = false; + ASSERT_FALSE(mask.any()); + { + DataTypeSignature check_signature(DataTypeAMessage::getDataTypeSignature()); // Order matters - low --> high + check_signature.extend(DataTypeB::getDataTypeSignature()); + ASSERT_EQ(check_signature, sign); + } +} + + +TEST(GlobalDataTypeRegistry, Reset) +{ + using uavcan::GlobalDataTypeRegistry; /* * Since we're dealing with singleton, we need to reset it for other tests to use */ + ASSERT_TRUE(GlobalDataTypeRegistry::instance().isFrozen()); GlobalDataTypeRegistry::instance().reset(); + ASSERT_FALSE(GlobalDataTypeRegistry::instance().isFrozen()); }