Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Param parser for fake devices #3084

Merged
merged 17 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions cmake/YarpDeviceParamsParserGenerator.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# SPDX-License-Identifier: BSD-3-Clause

# Here is an example of how the YarpDeviceParamParserGenerator should be invoked:
# YarpDeviceParamParserGenerator --class_name className --input_filename_md filename.md [--input_extra_comments comments.md] [--generate_md] [--generate_ini] [--generate_yarpdev] [--generate_yarprobotinterface] [--generate_all] [--output_dir output_path]
# YarpDeviceParamParserGenerator --class_name className --input_filename_ini filename.ini [--input_extra_comments comments.md] [--generate_md] [--generate_ini] [--generate_yarpdev] [--generate_yarprobotinterface] [--generate_all] [--output_dir output_path]
# YarpDeviceParamParserGenerator --class_name className --module_name deviceName --input_filename_md filename.md [--input_extra_comments comments.md] [--generate_md] [--generate_ini] [--generate_yarpdev] [--generate_yarprobotinterface] [--generate_all] [--output_dir output_path]
# YarpDeviceParamParserGenerator --class_name className --module_name deviceName --input_filename_ini filename.ini [--input_extra_comments comments.md] [--generate_md] [--generate_ini] [--generate_yarpdev] [--generate_yarprobotinterface] [--generate_all] [--output_dir output_path]

function(generateDeviceParamsParser_commandline COMMANDLINE)
option(ALLOW_DEVICE_PARAM_PARSER_GENERATION "Allow YARP to (re)build device param parsers" OFF)
Expand Down Expand Up @@ -37,33 +37,33 @@ function(generateDeviceParamsParser_commandline COMMANDLINE)
endfunction()


function(generateDeviceParamsParser_fromMdFile CLASSNAME FILEMD EXTRACOMMENTS)
function(generateDeviceParamsParser_fromMdFile CLASSNAME DEVICENAME FILEMD EXTRACOMMENTS)
if (EXTRACOMMENTS)
set (COMMAND "--class_name ${CLASSNAME} --input_filename_md ${FILEMD} --input_extra_comments ${EXTRACOMMENTS}")
set (COMMAND "--class_name ${CLASSNAME} --module_name ${DEVICENAME} --input_filename_md ${FILEMD} --input_extra_comments ${EXTRACOMMENTS}")
else()
set (COMMAND "--class_name ${CLASSNAME} --input_filename_md ${FILEMD}")
set (COMMAND "--class_name ${CLASSNAME} --module_name ${DEVICENAME} --input_filename_md ${FILEMD}")
endif()
generateDeviceParamsParser_commandline (${COMMAND})
endfunction()

function(generateDeviceParamsParser_fromIniFile CLASSNAME FILEINI EXTRACOMMENTS)
function(generateDeviceParamsParser_fromIniFile CLASSNAME DEVICENAME FILEINI EXTRACOMMENTS)
if (EXTRACOMMENTS)
set (COMMAND "--class_name ${CLASSNAME} --input_filename_ini ${FILEINI} --input_extra_comments ${EXTRACOMMENTS}")
set (COMMAND "--class_name ${CLASSNAME} --module_name ${DEVICENAME} --input_filename_ini ${FILEINI} --input_extra_comments ${EXTRACOMMENTS}")
else()
set (COMMAND "--class_name ${CLASSNAME} --input_filename_ini ${FILEINI}")
set (COMMAND "--class_name ${CLASSNAME} --module_name ${DEVICENAME} --input_filename_ini ${FILEINI}")
endif()
generateDeviceParamsParser_commandline (${COMMAND})
endfunction()

function(generateDeviceParamsParser CLASSNAME)
function(generateDeviceParamsParser CLASSNAME DEVICENAME)
set (INPUTFILENAME_INI "${CMAKE_CURRENT_SOURCE_DIR}/${CLASSNAME}_params.ini")
set (INPUTFILENAME_MD "${CMAKE_CURRENT_SOURCE_DIR}/${CLASSNAME}_params.md")
set (INPUTFILENAME_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/${CLASSNAME}_params_extracomments.md")

if (EXISTS ${INPUTFILENAME_INI})
set (COMMAND "--class_name ${CLASSNAME} --input_filename_ini ${INPUTFILENAME_INI}")
set (COMMAND "--class_name ${CLASSNAME} --module_name ${DEVICENAME} --input_filename_ini ${INPUTFILENAME_INI}")
elseif (EXISTS ${INPUTFILENAME_MD})
set (COMMAND "--class_name ${CLASSNAME} --input_filename_md ${INPUTFILENAME_MD}")
set (COMMAND "--class_name ${CLASSNAME} --module_name ${DEVICENAME} --input_filename_md ${INPUTFILENAME_MD}")
else()
message(FATAL_ERROR "Cannot find input file ${INPUTFILENAME_INI} or ${INPUTFILENAME_MD}")
endif()
Expand Down
12 changes: 11 additions & 1 deletion cmake/YarpPlugin.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ include(CMakeParseArguments)
include(CMakeDependentOption)
include(${CMAKE_CURRENT_LIST_DIR}/YarpInstallationHelpers.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/YarpPrintFeature.cmake)

include(${CMAKE_CURRENT_LIST_DIR}/YarpDeviceParamsParserGenerator.cmake)

################################################################################
#.rst:
Expand Down Expand Up @@ -169,6 +169,7 @@ endmacro()
# [DOC "<plugin documentation>"]
# [ADVANCED]
# [INTERNAL]
# [GENERATE_PARSER]
# [DEPENDS <condition>]
# [TEMPLATE <file_name|path_to_a_file>]
# [TEMPLATE_DIR <dir>]
Expand Down Expand Up @@ -218,6 +219,8 @@ endmacro()
# The ``DOC`` argument can be used to set a description for this option.
# If the``ADVANCED`` option is enabled, this option is marked as advanced in
# CMake.
# If the ``GENERATE_PARSER`` option is enabled, a parameter parser will be generated
# for the plugin. See documentation of: generateDeviceParamsParser()
# If the ``INTERNAL`` option is enabled, this option is marked as internal in
# CMake, and therefore not displayed in CMake gui. This also implies
# `DEFAULT=ON` unless explicitly specified.
Expand Down Expand Up @@ -250,6 +253,7 @@ macro(YARP_PREPARE_PLUGIN _plugin_name)
ADVANCED
INTERNAL
QUIET
GENERATE_PARSER
)
set(_oneValueArgs
TYPE
Expand Down Expand Up @@ -567,6 +571,12 @@ YARP_DEFINE_SHARED_SUBCLASS(\@YARPPLUG_NAME\@, \@YARPPLUG_TYPE\@, \@YARPPLUG_PAR
add_feature_info(${_plugin_fullname} ${_YPP_OPTION} "${_feature_doc}.")
endif()

if (NOT SKIP_${_plugin_name})
if(_YPP_GENERATE_PARSER)
message ("Invoking generateDeviceParamsParser (${_YPP_TYPE} ${_plugin_name})")
generateDeviceParamsParser(${_YPP_TYPE} ${_plugin_name})
endif()
endif()
endmacro()


Expand Down
85 changes: 74 additions & 11 deletions doc/module_executables/cmd_yarpDeviceParamParserGenerator.dox
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,67 @@ depending on the meaning of specific parameters (e.g. when a real hardware is in

\section yarpDeviceParamParserGenerator_cmake CMake Usage
yarpDeviceParamParserGenerator usage can be integrated in the CMakeLists.txt of a device.
The usage is very simple: user has to add the generateDeviceParamsParser() command, whose input parameter must match the name of the class
of the device, in this case ChatBot_nws_yarp. yarpDeviceParamParserGenerator will generate the two files ChatBot_nws_yarp_ParamsParser.cpp,

\subsection yarpDeviceParamParserGenerator_cmake_basic Basic cmake

The usage is very simple: user has to add the `GENERATE_PARSER` option to the `yarp_prepare_plugin` macro. yarpDeviceParamParserGenerator will generate the two files ChatBot_nws_yarp_ParamsParser.cpp,
ChatBot_nws_yarp_ParamsParser.h which must be added to target_sources.
The name of the generated files depends on the `TYPE` keyword, to which the `_ParamsParser` suffix is added.

\code{.cmake}
include(YarpDeviceParamsParserGenerator)

yarp_prepare_plugin(chatBot_nws_yarp
CATEGORY device
TYPE ChatBot_nws_yarp
INCLUDE ChatBot_nws_yarp.h
DEFAULT ON
GENERATE_PARSER
)

if(NOT SKIP_chatBot_nws_yarp)
yarp_add_plugin(yarp_chatBot_nws_yarp)

target_sources(yarp_chatBot_nws_yarp
PRIVATE
ChatBot_nws_yarp.cpp
ChatBot_nws_yarp.h
ChatBot_nws_yarp_ParamsParser.cpp
ChatBot_nws_yarp_ParamsParser.h
)

target_link_libraries(yarp_chatBot_nws_yarp
PRIVATE
YARP::YARP_os
YARP::YARP_sig
YARP::YARP_dev
)

list(APPEND YARP_${YARP_PLUGIN_MASTER}_PRIVATE_DEPS
YARP_os
YARP_sig
YARP_dev
)

yarp_install(
TARGETS yarp_chatBot_nws_yarp
EXPORT YARP_${YARP_PLUGIN_MASTER}
COMPONENT ${YARP_PLUGIN_MASTER}
LIBRARY DESTINATION ${YARP_DYNAMIC_PLUGINS_INSTALL_DIR}
ARCHIVE DESTINATION ${YARP_STATIC_PLUGINS_INSTALL_DIR}
YARP_INI DESTINATION ${YARP_PLUGIN_MANIFESTS_INSTALL_DIR}
)

set(YARP_${YARP_PLUGIN_MASTER}_PRIVATE_DEPS ${YARP_${YARP_PLUGIN_MASTER}_PRIVATE_DEPS} PARENT_SCOPE)
endif()
\endcode

\subsection yarpDeviceParamParserGenerator_cmake_advanced Advanced cmake

It is also possible to provide a customized control command by using the `generateDeviceParamsParser()` function (see documentation
in file YarpDeviceParamsParserGenerator.cmake). The minimum number of accepted parameters is two:
the name of the device class and the name of the plugin. It is not mandatory, but in Yarp the convention typically followed is to have
the class name upper camel case and the plugin name lower camel case.

\code{.cmake}
include(YarpDeviceParamsParserGenerator)
Expand All @@ -114,7 +172,7 @@ yarp_prepare_plugin(chatBot_nws_yarp

if(NOT SKIP_chatBot_nws_yarp)
yarp_add_plugin(yarp_chatBot_nws_yarp)
generateDeviceParamsParser(ChatBot_nws_yarp)
generateDeviceParamsParser(ChatBot_nws_yarp chatBot_nws_yarp)

target_sources(yarp_chatBot_nws_yarp
PRIVATE
Expand Down Expand Up @@ -160,15 +218,20 @@ file YarpDeviceParamsParserGenerator.cmake
- nested groups can be specified using the :: operator. For example: myGroup::mySubGroup1::mySubGroup2::myVariable
- only the following values are supported for the Type field in the input files:
\code{.unparsed}
| Parameter type | c++ type | yarp::os::Value call |
|:--------------:|:--------------:|:--------------------:|
| "bool" | bool | .asBool() |
| "string" | std::string | .asString() |
| "int" | int | .asInt64() |
| "size_t" | size_t | .asInt64() |
| "float" | float | .asFloat32() |
| "double" | double | .asFloat64() |
| Parameter type | c++ type | yarp::os::Value call | .md file example |
|:--------------:|:--------------------:|:--------------------:|:----------------:|
| "bool" | bool | .asBool() | true |
| "string" | std::string | .asString() | "hello" |
| "int" | int | .asInt64() | 10 |
| "size_t" | size_t | .asInt64() | 10 |
| "float" | float | .asFloat32() | 10.0 |
| "double" | double | .asFloat64() | 10.0 |
| "char" | char | .asInt8() | 'c' |
| vector<int> | std::vector<int> | - | 10 10 |
| vector<double> | std::vector<double> | - | 10.0 10.0 |
| vector<string> | std::vector<string> | - | "hello" "hello" |
\endcode
- Be careful with the vector type: invoking the device from the command line requires additional escape quotes (e.g. "10 10", "\"hello\" \"hello\"")
- The generated .cpp file also include a function ::getDocumentationOfDeviceParams() which will output a documentation string which
will be displayed on user request (for example invoking the --help option)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// This is an automatically generated file. Please do not edit it.
// It will be re-generated if the cmake flag ALLOW_DEVICE_PARAM_PARSER_GERNERATION is ON.

// Generated on: Fri Feb 9 16:59:13 2024
// Generated on: Mon Feb 19 16:28:03 2024


#include "AudioToFileDevice_ParamsParser.h"
Expand All @@ -20,6 +20,11 @@ namespace {
}


AudioToFileDevice_ParamsParser::AudioToFileDevice_ParamsParser()
{
}


std::vector<std::string> AudioToFileDevice_ParamsParser::getListOfParams() const
{
std::vector<std::string> params;
Expand Down Expand Up @@ -123,8 +128,8 @@ std::string AudioToFileDevice_ParamsParser::getDocumentationOfDeviceParams(
doc = doc + std::string("'add_marker': If set, it will add a marker at the beginning and at the ending of each received waveform.\n");
doc = doc + std::string("\n");
doc = doc + std::string("Here are some examples of invocation command with yarpdev, with all params:\n");
doc = doc + " yarpdev --device AudioToFileDevice --file_name audio_out.wav --save_mode overwrite_file --add_marker false\n";
doc = doc + " yarpdev --device audioToFileDevice --file_name audio_out.wav --save_mode overwrite_file --add_marker false\n";
doc = doc + std::string("Using only mandatory params:\n");
doc = doc + " yarpdev --device AudioToFileDevice\n";
doc = doc + " yarpdev --device audioToFileDevice\n";
doc = doc + std::string("=============================================\n\n"); return doc;
}
19 changes: 13 additions & 6 deletions src/devices/audioToFileDevice/AudioToFileDevice_ParamsParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// This is an automatically generated file. Please do not edit it.
// It will be re-generated if the cmake flag ALLOW_DEVICE_PARAM_PARSER_GERNERATION is ON.

// Generated on: Sun Feb 11 01:26:28 2024
// Generated on: Mon Feb 19 16:28:03 2024


#ifndef AUDIOTOFILEDEVICE_PARAMSPARSER_H
Expand All @@ -31,36 +31,43 @@
*
* The device can be launched by yarpdev using one of the following examples:
* \code{.unparsed}
* yarpdev --device AudioToFileDevice --file_name audio_out.wav --save_mode overwrite_file --add_marker false
* yarpdev --device audioToFileDevice --file_name audio_out.wav --save_mode overwrite_file --add_marker false
* \endcode
*
* \code{.unparsed}
* yarpdev --device AudioToFileDevice
* yarpdev --device audioToFileDevice
* \endcode
*
*/

class AudioToFileDevice_ParamsParser : public yarp::dev::IDeviceDriverParams
{
public:
AudioToFileDevice_ParamsParser() = default;
AudioToFileDevice_ParamsParser();
~AudioToFileDevice_ParamsParser() override = default;

public:
const std::string m_device_type = {"AudioToFileDevice"};
const std::string m_device_classname = {"AudioToFileDevice"};
const std::string m_device_name = {"audioToFileDevice"};
bool m_parser_is_strict = false;
struct parser_version_type
{
int major = 1;
int minor = 0;
};
const parser_version_type m_parser_version = {};

const std::string m_file_name_defaultValue = {"audio_out.wav"};
const std::string m_save_mode_defaultValue = {"overwrite_file"};
const std::string m_add_marker_defaultValue = {"false"};

std::string m_file_name = {"audio_out.wav"};
std::string m_save_mode = {"overwrite_file"};
bool m_add_marker = {false};

bool parseParams(const yarp::os::Searchable & config) override;
std::string getDeviceType() const override { return m_device_type; }
std::string getDeviceClassName() const override { return m_device_classname; }
std::string getDeviceName() const override { return m_device_name; }
std::string getDocumentationOfDeviceParams() const override;
std::vector<std::string> getListOfParams() const override;
};
Expand Down
2 changes: 1 addition & 1 deletion src/devices/audioToFileDevice/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ yarp_prepare_plugin(audioToFileDevice
CATEGORY device
TYPE AudioToFileDevice
INCLUDE AudioToFileDevice.h
GENERATE_PARSER
EXTRA_CONFIG
WRAPPER=AudioPlayerWrapper
DEFAULT ON
)

if(NOT SKIP_audioToFileDevice)
yarp_add_plugin(yarp_audioToFileDevice)
generateDeviceParamsParser(AudioToFileDevice)

target_sources(yarp_audioToFileDevice
PRIVATE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,40 +22,31 @@ const char *fmcA_file_content = "device fakeMotionControl\n"
"[GENERAL]\n"
"Joints 2\n"
"\n"
"AxisName \"axisA1\" \"axisA2\" \n";
"AxisName (\"axisA1\" \"axisA2\") \n";

const char *fmcB_file_content = "device fakeMotionControl\n"
"[GENERAL]\n"
"Joints 3\n"
"\n"
"AxisName \"axisB1\" \"axisB2\" \"axisB3\"\n";
"AxisName (\"axisB1\" \"axisB2\" \"axisB3\") \n";

const char *fmcC_file_content = "device fakeMotionControl\n"
"[GENERAL]\n"
"Joints 4\n"
"\n"
"AxisName \"axisC1\" \"axisC2\" \"axisC3\" \"axisC4\" \n";
"AxisName (\"axisC1\" \"axisC2\" \"axisC3\" \"axisC4\") \n";

const char *wrapperA_file_content = "device controlBoard_nws_yarp\n"
"name /testRemapperRobot/a\n"
"period 0.01\n"
"networks (net_a)\n"
"joints 2\n"
"net_a 0 1 0 1\n";
"period 0.01\n";

const char *wrapperB_file_content = "device controlBoard_nws_yarp\n"
"name /testRemapperRobot/b\n"
"period 0.01\n"
"networks (net_b)\n"
"joints 3\n"
"net_b 0 2 0 2\n";
"period 0.01\n";

const char *wrapperC_file_content = "device controlBoard_nws_yarp\n"
"name /testRemapperRobot/c\n"
"period 0.01\n"
"networks (net_c)\n"
"joints 4\n"
"net_c 0 3 0 3\n";
"period 0.01\n";


static void checkRemapper(yarp::dev::PolyDriver & ddRemapper, int rand, size_t nrOfRemappedAxes)
Expand Down Expand Up @@ -220,7 +211,7 @@ TEST_CASE("dev::ControlBoardRemapperTest", "[yarp::dev]")
PolyDriverList pdList;
pdList.push(fmcbs[i],wrapperNetworks[i].c_str());

CHECK(iwrap->attachAll(pdList)); // controlBoard_nws_yarp attached successfully to the device
REQUIRE(iwrap->attachAll(pdList)); // controlBoard_nws_yarp attached successfully to the device
}

// Create a list containing all the fake controlboards
Expand Down Expand Up @@ -252,7 +243,7 @@ TEST_CASE("dev::ControlBoardRemapperTest", "[yarp::dev]")
REQUIRE(ddRemapperWN.view(imultwrapWN)); // interface for multiple wrapper with wrong names correctly opened
REQUIRE(imultwrapWN);

CHECK_FALSE(imultwrapWN->attachAll(fmcList)); // attachAll for controlboardremapper with wrong names successful
REQUIRE_FALSE(imultwrapWN->attachAll(fmcList)); // attachAll for controlboardremapper with wrong names successful

// Make sure that a controlboard in which attachAll is not successfull
// closes correctly
Expand All @@ -278,7 +269,7 @@ TEST_CASE("dev::ControlBoardRemapperTest", "[yarp::dev]")
REQUIRE(ddRemapper.view(imultwrap)); // interface for multiple wrapper correctly opened
REQUIRE(imultwrap);

CHECK(imultwrap->attachAll(fmcList)); // attachAll for controlboardremapper successful
REQUIRE(imultwrap->attachAll(fmcList)); // attachAll for controlboardremapper successful


// Test the controlboardremapper
Expand Down
Loading
Loading