ParamServer - automatic case conversion for parameter names

This commit is contained in:
Pavel Kirienko 2015-03-21 00:12:06 +03:00
parent 241ae8a538
commit 80c2c175aa
3 changed files with 111 additions and 2 deletions

View File

@ -79,22 +79,48 @@ class UAVCAN_EXPORT ParamServer
void (ParamServer::*)(const protocol::param::ExecuteOpcode::Request&,
protocol::param::ExecuteOpcode::Response&)> ExecuteOpcodeCallback;
public:
/**
* This class can automatically enforce that parameter names are not case-sensitive, by means of
* automatic conversion to either upper or lower case whenever a parameter name is received.
* For instance, if the lower-case conversion is enabled, then a UAVCAN request for a parameter
* named "Foo" will be passed to the application as "foo". Similarly, when the application reports
* that it has a parameter named "FOO", the class will convert the name to "foo".
*/
enum ParamNameCaseConversion
{
ParamNameCaseConversionDisabled, ///< Do not convert parameter names. The case will remain intact.
ParamNameCaseConversionToLower, ///< Convert parameter names to lower case.
ParamNameCaseConversionToUpper ///< Convert parameter names to upper case.
};
private:
ServiceServer<protocol::param::GetSet, GetSetCallback> get_set_srv_;
ServiceServer<protocol::param::ExecuteOpcode, ExecuteOpcodeCallback> save_erase_srv_;
IParamManager* manager_;
const ParamNameCaseConversion param_name_case_conversion_mode_;
static bool isValueNonEmpty(const protocol::param::Value& value);
void convertParamNameCase(IParamManager::ParamName& name) const;
void handleGetSet(const protocol::param::GetSet::Request& request, protocol::param::GetSet::Response& response);
void handleExecuteOpcode(const protocol::param::ExecuteOpcode::Request& request,
protocol::param::ExecuteOpcode::Response& response);
public:
explicit ParamServer(INode& node)
/**
* @param param_name_case_conversion Specifies the parameter name conversion mode. Lower case is default,
* which means that an external request for a parameter named "Foo" will
* be relayed to the application as "foo".
*/
explicit ParamServer(INode& node,
ParamNameCaseConversion param_name_case_conversion = ParamNameCaseConversionToLower)
: get_set_srv_(node)
, save_erase_srv_(node)
, manager_(NULL)
, param_name_case_conversion_mode_(param_name_case_conversion)
{ }
/**

View File

@ -18,6 +18,22 @@ bool ParamServer::isValueNonEmpty(const protocol::param::Value& value)
!value.value_string.empty();
}
void ParamServer::convertParamNameCase(IParamManager::ParamName& name) const
{
if (param_name_case_conversion_mode_ == ParamNameCaseConversionToLower)
{
name.convertToLowerCaseASCII();
}
else if (param_name_case_conversion_mode_ == ParamNameCaseConversionToUpper)
{
name.convertToUpperCaseASCII();
}
else
{
; // Conversion is not needed
}
}
void ParamServer::handleGetSet(const protocol::param::GetSet::Request& in, protocol::param::GetSet::Response& out)
{
UAVCAN_ASSERT(manager_ != NULL);
@ -33,6 +49,8 @@ void ParamServer::handleGetSet(const protocol::param::GetSet::Request& in, proto
out.name = in.name;
}
convertParamNameCase(out.name);
// Assign if needed, read back
if (isValueNonEmpty(in.value))
{

View File

@ -145,7 +145,7 @@ TEST(ParamServer, Basic)
// Get by name
get_set_rq = uavcan::protocol::param::GetSet::Request();
get_set_rq.name = "foobar";
get_set_rq.name = "FOOBAR"; // Requesting in upper case
doCall(get_set_cln, get_set_rq, nodes);
ASSERT_STREQ("foobar", get_set_cln.collector.result->response.name.c_str());
ASSERT_TRUE(get_set_cln.collector.result->response.value.value_bool.empty());
@ -171,3 +171,68 @@ TEST(ParamServer, Basic)
ASSERT_STREQ("foobar", get_set_cln.collector.result->response.name.c_str());
ASSERT_FLOAT_EQ(424242, get_set_cln.collector.result->response.value.value_float[0]);
}
TEST(ParamServer, UpperCaseConversion)
{
InterlinkedTestNodesWithSysClock nodes;
uavcan::ParamServer server(nodes.a, uavcan::ParamServer::ParamNameCaseConversionToUpper);
ParamServerTestManager mgr;
uavcan::GlobalDataTypeRegistry::instance().reset();
uavcan::DefaultDataTypeRegistrator<uavcan::protocol::param::GetSet> _reg1;
uavcan::DefaultDataTypeRegistrator<uavcan::protocol::param::ExecuteOpcode> _reg2;
ASSERT_LE(0, server.start(&mgr));
ServiceClientWithCollector<uavcan::protocol::param::GetSet> get_set_cln(nodes.b);
mgr.kv["foobar"] = 0.0; // Will be ignored because not upper case
mgr.kv["FOOBAR"] = 123.456;
/*
* Get/set
*/
uavcan::protocol::param::GetSet::Request get_set_rq;
get_set_rq = uavcan::protocol::param::GetSet::Request();
get_set_rq.name = "foobar"; // Requesting in upper case
doCall(get_set_cln, get_set_rq, nodes);
ASSERT_STREQ("FOOBAR", get_set_cln.collector.result->response.name.c_str());
ASSERT_TRUE(get_set_cln.collector.result->response.value.value_bool.empty());
ASSERT_TRUE(get_set_cln.collector.result->response.value.value_int.empty());
ASSERT_FLOAT_EQ(123.456F, get_set_cln.collector.result->response.value.value_float[0]);
}
TEST(ParamServer, NoCaseConversion)
{
InterlinkedTestNodesWithSysClock nodes;
uavcan::ParamServer server(nodes.a, uavcan::ParamServer::ParamNameCaseConversionDisabled);
ParamServerTestManager mgr;
uavcan::GlobalDataTypeRegistry::instance().reset();
uavcan::DefaultDataTypeRegistrator<uavcan::protocol::param::GetSet> _reg1;
uavcan::DefaultDataTypeRegistrator<uavcan::protocol::param::ExecuteOpcode> _reg2;
ASSERT_LE(0, server.start(&mgr));
ServiceClientWithCollector<uavcan::protocol::param::GetSet> get_set_cln(nodes.b);
mgr.kv["foobar"] = 0.0;
mgr.kv["FooBar"] = 123.456;
mgr.kv["FOOBAR"] = 0.0;
/*
* Get/set
*/
uavcan::protocol::param::GetSet::Request get_set_rq;
get_set_rq = uavcan::protocol::param::GetSet::Request();
get_set_rq.name = "FooBar";
doCall(get_set_cln, get_set_rq, nodes);
ASSERT_STREQ("FooBar", get_set_cln.collector.result->response.name.c_str());
ASSERT_TRUE(get_set_cln.collector.result->response.value.value_bool.empty());
ASSERT_TRUE(get_set_cln.collector.result->response.value.value_int.empty());
ASSERT_FLOAT_EQ(123.456F, get_set_cln.collector.result->response.value.value_float[0]);
}