GetDataTypeInfo now can be requested either by dtid/id, or by name

This commit is contained in:
Pavel Kirienko
2015-03-16 23:35:37 +03:00
parent 14c176015a
commit f2cfed70cb
4 changed files with 114 additions and 25 deletions
@@ -1,13 +1,23 @@
# #
# Get the implementation details of a given data type. # 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 uint16 id # Ignored if 'name' is non-empty
DataTypeKind kind 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_KNOWN = 1 # This data type is defined
uint8 MASK_SUBSCRIBED = 2 # Subscribed to messages of this type 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_SERVING = 8 # Providing service of this type
uint8 mask 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)
+3 -3
View File
@@ -2,6 +2,6 @@
# Data type kind (message or service). # Data type kind (message or service).
# #
uint2 SERVICE = 0 uint8 SERVICE = 0
uint2 MESSAGE = 1 uint8 MESSAGE = 1
uint2 value uint8 value
@@ -35,43 +35,67 @@ void DataTypeInfoProvider::handleComputeAggregateTypeSignatureRequest(
void DataTypeInfoProvider::handleGetDataTypeInfoRequest(const protocol::GetDataTypeInfo::Request& request, void DataTypeInfoProvider::handleGetDataTypeInfoRequest(const protocol::GetDataTypeInfo::Request& request,
protocol::GetDataTypeInfo::Response& response) 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); response.id = request.id; // Pre-setting the fields so they have meaningful values even in
return; response.kind = request.kind; // ...case of failure.
if (!isValidDataTypeKind(DataTypeKind(request.kind.value)))
{
UAVCAN_TRACE("DataTypeInfoProvider", "GetDataTypeInfo request with invalid DataTypeKind %i",
static_cast<int>(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 == NULL)
if (!desc)
{ {
UAVCAN_TRACE("DataTypeInfoProvider", "Cannot process GetDataTypeInfo for nonexistent type dtid=%i dtk=%i", UAVCAN_TRACE("DataTypeInfoProvider",
int(request.id), int(request.kind.value)); "Cannot process GetDataTypeInfo for nonexistent type: dtid=%i dtk=%i name='%s'",
static_cast<int>(request.id), static_cast<int>(request.kind.value), request.name.c_str());
return; return;
} }
UAVCAN_TRACE("DataTypeInfoProvider", "GetDataTypeInfo request for %s", desc->toString().c_str()); UAVCAN_TRACE("DataTypeInfoProvider", "GetDataTypeInfo request for %s", desc->toString().c_str());
response.signature = desc->getSignature().get(); /*
response.name = desc->getFullName(); * Filling the response struct
response.mask = protocol::GetDataTypeInfo::Response::MASK_KNOWN; */
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(); 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; 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; 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; response.mask |= protocol::GetDataTypeInfo::Response::MASK_PUBLISHING;
} }
@@ -23,22 +23,39 @@ static bool validateDataTypeInfoResponse(const std::auto_ptr<ServiceCallResult<G
{ {
if (!resp.get()) if (!resp.get())
{ {
std::cout << "Null response" << std::endl;
return false; return false;
} }
if (!resp->isSuccessful()) if (!resp->isSuccessful())
{ {
std::cout << "Request was not successful" << std::endl;
return false; return false;
} }
if (resp->response.name != DataType::getDataTypeFullName()) if (resp->response.name != DataType::getDataTypeFullName())
{ {
std::cout << "Type name mismatch: '"
<< resp->response.name.c_str() << "' '"
<< DataType::getDataTypeFullName() << "'" << std::endl;
return false; return false;
} }
if (DataType::getDataTypeSignature().get() != resp->response.signature) if (DataType::getDataTypeSignature().get() != resp->response.signature)
{ {
std::cout << "Signature mismatch" << std::endl;
return false; return false;
} }
if (resp->response.mask != mask) 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 false;
} }
return true; return true;
@@ -75,9 +92,25 @@ TEST(DataTypeInfoProvider, Basic)
GetDataTypeInfo::Response::MASK_SERVING)); GetDataTypeInfo::Response::MASK_SERVING));
ASSERT_EQ(1, gdti_cln.collector.result->server_node_id.get()); 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<GetDataTypeInfo>(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 * GetDataTypeInfo request for NodeStatus - not used yet
*/ */
gdti_request = GetDataTypeInfo::Request();
gdti_request.id = NodeStatus::DefaultDataTypeID; gdti_request.id = NodeStatus::DefaultDataTypeID;
gdti_request.kind.value = DataTypeKind::MESSAGE; gdti_request.kind.value = DataTypeKind::MESSAGE;
ASSERT_LE(0, gdti_cln.call(1, gdti_request)); ASSERT_LE(0, gdti_cln.call(1, gdti_request));
@@ -107,15 +140,37 @@ TEST(DataTypeInfoProvider, Basic)
/* /*
* Requesting a non-existent type * Requesting a non-existent type
*/ */
gdti_request = GetDataTypeInfo::Request();
gdti_request.id = ComputeAggregateTypeSignature::DefaultDataTypeID; 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)); ASSERT_LE(0, gdti_cln.call(1, gdti_request));
nodes.spinBoth(MonotonicDuration::fromMSec(10)); nodes.spinBoth(MonotonicDuration::fromMSec(10));
ASSERT_TRUE(gdti_cln.collector.result.get()); ASSERT_TRUE(gdti_cln.collector.result.get());
ASSERT_TRUE(gdti_cln.collector.result->isSuccessful()); ASSERT_TRUE(gdti_cln.collector.result->isSuccessful());
ASSERT_EQ(1, gdti_cln.collector.result->server_node_id.get()); 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 * ComputeAggregateTypeSignature test