diff --git a/dsdl/uavcan/protocol/552.GetDataTypeInfo.uavcan b/dsdl/uavcan/protocol/552.GetDataTypeInfo.uavcan index 8392045c26..c744ad707a 100644 --- a/dsdl/uavcan/protocol/552.GetDataTypeInfo.uavcan +++ b/dsdl/uavcan/protocol/552.GetDataTypeInfo.uavcan @@ -1,13 +1,23 @@ # # Get the implementation details of a given data type. # +# Request is interpreted as follows: +# - If the field 'name' is empty, the fields 'kind' and 'id' will be used to identify the data type. +# - If the field 'name' is non-empty, it will be used to identify the data type; the +# fields 'kind' and 'id' will be ignored. +# -uint16 id -DataTypeKind kind +uint16 id # Ignored if 'name' is non-empty +DataTypeKind kind # Ignored if 'name' is non-empty + +uint8[<=80] name # Full data type name, e.g. "uavcan.protocol.GetDataTypeInfo" --- -uint64 signature # Data type signature +uint64 signature # Data type signature; valid only if the data type is known (see MASK_KNOWN) + +uint16 id # Valid only if the data type is known (see MASK_KNOWN) +DataTypeKind kind # Ditto uint8 MASK_KNOWN = 1 # This data type is defined uint8 MASK_SUBSCRIBED = 2 # Subscribed to messages of this type @@ -15,4 +25,4 @@ uint8 MASK_PUBLISHING = 4 # Publishing messages of this type uint8 MASK_SERVING = 8 # Providing service of this type uint8 mask -uint8[<=80] name # Full data type name, e.g. "uavcan.protocol.GetDataTypeInfo" +uint8[<=80] name # Full data type name; valid only if the data type is known (see MASK_KNOWN) diff --git a/dsdl/uavcan/protocol/DataTypeKind.uavcan b/dsdl/uavcan/protocol/DataTypeKind.uavcan index 925a575e0c..58dd68b056 100644 --- a/dsdl/uavcan/protocol/DataTypeKind.uavcan +++ b/dsdl/uavcan/protocol/DataTypeKind.uavcan @@ -2,6 +2,6 @@ # Data type kind (message or service). # -uint2 SERVICE = 0 -uint2 MESSAGE = 1 -uint2 value +uint8 SERVICE = 0 +uint8 MESSAGE = 1 +uint8 value diff --git a/libuavcan/src/protocol/uc_data_type_info_provider.cpp b/libuavcan/src/protocol/uc_data_type_info_provider.cpp index 38a0a023b5..c736d06842 100644 --- a/libuavcan/src/protocol/uc_data_type_info_provider.cpp +++ b/libuavcan/src/protocol/uc_data_type_info_provider.cpp @@ -35,43 +35,67 @@ void DataTypeInfoProvider::handleComputeAggregateTypeSignatureRequest( void DataTypeInfoProvider::handleGetDataTypeInfoRequest(const protocol::GetDataTypeInfo::Request& request, protocol::GetDataTypeInfo::Response& response) { - const DataTypeKind kind = DataTypeKind(request.kind.value); - if (!isValidDataTypeKind(kind)) + /* + * Asking the Global Data Type Registry for the matching type descriptor, either by name or by ID + */ + const DataTypeDescriptor* desc = NULL; + + if (request.name.empty()) { - UAVCAN_TRACE("DataTypeInfoProvider", "GetDataTypeInfo request with invalid DataTypeKind %i", kind); - return; + response.id = request.id; // Pre-setting the fields so they have meaningful values even in + response.kind = request.kind; // ...case of failure. + + if (!isValidDataTypeKind(DataTypeKind(request.kind.value))) + { + UAVCAN_TRACE("DataTypeInfoProvider", "GetDataTypeInfo request with invalid DataTypeKind %i", + static_cast(request.kind.value)); + return; + } + + desc = GlobalDataTypeRegistry::instance().find(DataTypeKind(request.kind.value), request.id); + } + else + { + response.name = request.name; + + desc = GlobalDataTypeRegistry::instance().find(request.name.c_str()); } - const DataTypeDescriptor* const desc = GlobalDataTypeRegistry::instance().find(kind, request.id); - if (!desc) + if (desc == NULL) { - UAVCAN_TRACE("DataTypeInfoProvider", "Cannot process GetDataTypeInfo for nonexistent type dtid=%i dtk=%i", - int(request.id), int(request.kind.value)); + UAVCAN_TRACE("DataTypeInfoProvider", + "Cannot process GetDataTypeInfo for nonexistent type: dtid=%i dtk=%i name='%s'", + static_cast(request.id), static_cast(request.kind.value), request.name.c_str()); return; } UAVCAN_TRACE("DataTypeInfoProvider", "GetDataTypeInfo request for %s", desc->toString().c_str()); - response.signature = desc->getSignature().get(); - response.name = desc->getFullName(); - response.mask = protocol::GetDataTypeInfo::Response::MASK_KNOWN; + /* + * Filling the response struct + */ + response.signature = desc->getSignature().get(); + response.id = desc->getID().get(); + response.kind.value = desc->getKind(); + response.mask = protocol::GetDataTypeInfo::Response::MASK_KNOWN; + response.name = desc->getFullName(); const Dispatcher& dispatcher = getNode().getDispatcher(); - if (request.kind.value == protocol::DataTypeKind::SERVICE) + if (desc->getKind() == DataTypeKindService) { - if (dispatcher.hasServer(request.id)) + if (dispatcher.hasServer(desc->getID().get())) { response.mask |= protocol::GetDataTypeInfo::Response::MASK_SERVING; } } - else if (request.kind.value == protocol::DataTypeKind::MESSAGE) + else if (desc->getKind() == DataTypeKindMessage) { - if (dispatcher.hasSubscriber(request.id)) + if (dispatcher.hasSubscriber(desc->getID().get())) { response.mask |= protocol::GetDataTypeInfo::Response::MASK_SUBSCRIBED; } - if (dispatcher.hasPublisher(request.id)) + if (dispatcher.hasPublisher(desc->getID().get())) { response.mask |= protocol::GetDataTypeInfo::Response::MASK_PUBLISHING; } diff --git a/libuavcan/test/protocol/data_type_info_provider.cpp b/libuavcan/test/protocol/data_type_info_provider.cpp index 046d6074fa..add46c17ac 100644 --- a/libuavcan/test/protocol/data_type_info_provider.cpp +++ b/libuavcan/test/protocol/data_type_info_provider.cpp @@ -23,22 +23,39 @@ static bool validateDataTypeInfoResponse(const std::auto_ptrisSuccessful()) { + std::cout << "Request was not successful" << std::endl; return false; } if (resp->response.name != DataType::getDataTypeFullName()) { + std::cout << "Type name mismatch: '" + << resp->response.name.c_str() << "' '" + << DataType::getDataTypeFullName() << "'" << std::endl; return false; } if (DataType::getDataTypeSignature().get() != resp->response.signature) { + std::cout << "Signature mismatch" << std::endl; return false; } if (resp->response.mask != mask) { + std::cout << "Mask mismatch" << std::endl; + return false; + } + if (resp->response.kind.value != DataType::DataTypeKind) + { + std::cout << "Kind mismatch" << std::endl; + return false; + } + if (resp->response.id != DataType::DefaultDataTypeID) + { + std::cout << "DTID mismatch" << std::endl; return false; } return true; @@ -75,9 +92,25 @@ TEST(DataTypeInfoProvider, Basic) GetDataTypeInfo::Response::MASK_SERVING)); ASSERT_EQ(1, gdti_cln.collector.result->server_node_id.get()); + /* + * GetDataTypeInfo request for GetDataTypeInfo by name + */ + gdti_request = GetDataTypeInfo::Request(); + gdti_request.id = 999; // Intentionally wrong + gdti_request.kind.value = DataTypeKind::MESSAGE; // Intentionally wrong + gdti_request.name = "uavcan.protocol.GetDataTypeInfo"; + ASSERT_LE(0, gdti_cln.call(1, gdti_request)); + nodes.spinBoth(MonotonicDuration::fromMSec(10)); + + ASSERT_TRUE(validateDataTypeInfoResponse(gdti_cln.collector.result, + GetDataTypeInfo::Response::MASK_KNOWN | + GetDataTypeInfo::Response::MASK_SERVING)); + ASSERT_EQ(1, gdti_cln.collector.result->server_node_id.get()); + /* * GetDataTypeInfo request for NodeStatus - not used yet */ + gdti_request = GetDataTypeInfo::Request(); gdti_request.id = NodeStatus::DefaultDataTypeID; gdti_request.kind.value = DataTypeKind::MESSAGE; ASSERT_LE(0, gdti_cln.call(1, gdti_request)); @@ -107,15 +140,37 @@ TEST(DataTypeInfoProvider, Basic) /* * Requesting a non-existent type */ + gdti_request = GetDataTypeInfo::Request(); gdti_request.id = ComputeAggregateTypeSignature::DefaultDataTypeID; - gdti_request.kind.value = 0xFF; // INVALID VALUE + gdti_request.kind.value = 3; // INVALID VALUE ASSERT_LE(0, gdti_cln.call(1, gdti_request)); nodes.spinBoth(MonotonicDuration::fromMSec(10)); ASSERT_TRUE(gdti_cln.collector.result.get()); ASSERT_TRUE(gdti_cln.collector.result->isSuccessful()); ASSERT_EQ(1, gdti_cln.collector.result->server_node_id.get()); - ASSERT_TRUE(gdti_cln.collector.result->response == GetDataTypeInfo::Response()); // Empty response + ASSERT_EQ(0, gdti_cln.collector.result->response.mask); + ASSERT_TRUE(gdti_cln.collector.result->response.name.empty()); // Empty name + ASSERT_EQ(gdti_request.id, gdti_cln.collector.result->response.id); + ASSERT_EQ(gdti_request.kind.value, gdti_cln.collector.result->response.kind.value); + + /* + * Requesting a non-existent type by name + */ + gdti_request = GetDataTypeInfo::Request(); + gdti_request.id = 999; // Intentionally wrong + gdti_request.kind.value = 3; // Intentionally wrong + gdti_request.name = "uavcan.equipment.gnss.Fix"; + ASSERT_LE(0, gdti_cln.call(1, gdti_request)); + nodes.spinBoth(MonotonicDuration::fromMSec(10)); + + ASSERT_TRUE(gdti_cln.collector.result.get()); + ASSERT_TRUE(gdti_cln.collector.result->isSuccessful()); + ASSERT_EQ(1, gdti_cln.collector.result->server_node_id.get()); + ASSERT_EQ(0, gdti_cln.collector.result->response.mask); + ASSERT_EQ("uavcan.equipment.gnss.Fix", gdti_cln.collector.result->response.name); + ASSERT_EQ(0, gdti_cln.collector.result->response.id); + ASSERT_EQ(0, gdti_cln.collector.result->response.kind.value); /* * ComputeAggregateTypeSignature test