diff --git a/doc/release/master.md b/doc/release/master.md index afcea33a9a0..313785d252a 100644 --- a/doc/release/master.md +++ b/doc/release/master.md @@ -29,6 +29,7 @@ Fixes * Configuration files installed by the `yarp_configure_plugins_installation` CMake macro are now relocatable (https://github.com/robotology/yarp/issues/2445, ). * Improved `ffmpeg` port monitor to allow using different couples of coders/decodes +* Improved `yarpdev` closing behavior for devices implementing the `iService` interface New Features ------------ diff --git a/src/devices/deviceBundler/DeviceBundler.cpp b/src/devices/deviceBundler/DeviceBundler.cpp index 7900a4930b4..eea5fcfb283 100644 --- a/src/devices/deviceBundler/DeviceBundler.cpp +++ b/src/devices/deviceBundler/DeviceBundler.cpp @@ -76,6 +76,12 @@ bool DeviceBundler::open(yarp::os::Searchable& config) return false; } + ret = m_pdev_wrapper.view(m_iService); + if (ret) + { + yCInfo(DEVICEBUNDLER, "The device implements the IService iterface"); + } + ret = m_iWrapper->attach(&m_pdev_subdevice); if (!ret) { @@ -93,6 +99,7 @@ bool DeviceBundler::close() { m_iWrapper->detach(); m_iWrapper = nullptr; + m_iService = nullptr; } if (m_pdev_wrapper.isValid()) @@ -107,3 +114,30 @@ bool DeviceBundler::close() return true; } + +bool DeviceBundler::startService() +{ + if (m_iService) + { + return m_iService->startService(); + } + return true; //If not implemented, emulate running in background +} + +bool DeviceBundler::updateService() +{ + if (m_iService) + { + return m_iService->updateService(); + } + return false; +} + +bool DeviceBundler::stopService() +{ + if (m_iService) + { + return m_iService->stopService(); + } + return false; +} diff --git a/src/devices/deviceBundler/DeviceBundler.h b/src/devices/deviceBundler/DeviceBundler.h index 35a2a832fff..9132fa15561 100644 --- a/src/devices/deviceBundler/DeviceBundler.h +++ b/src/devices/deviceBundler/DeviceBundler.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "DeviceBundler_ParamsParser.h" /** @@ -25,6 +26,7 @@ */ class DeviceBundler : public yarp::dev::DeviceDriver, + public yarp::dev::IService, public DeviceBundler_ParamsParser { public: @@ -39,10 +41,16 @@ class DeviceBundler : public yarp::dev::DeviceDriver, bool open(yarp::os::Searchable& config) override; bool close() override; + // yarp::dev::IService methods + virtual bool startService() override; + virtual bool updateService() override; + virtual bool stopService() override; + private: yarp::dev::PolyDriver m_pdev_wrapper; yarp::dev::PolyDriver m_pdev_subdevice; yarp::dev::IWrapper* m_iWrapper=nullptr; + yarp::dev::IService* m_iService=nullptr; }; #endif // YARP_DEVICEBUNDLER_H diff --git a/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer.cpp b/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer.cpp index 8ecd82cb30b..ac2531fe60b 100644 --- a/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer.cpp +++ b/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer.cpp @@ -239,6 +239,8 @@ bool JoypadControlServer::open(yarp::os::Searchable& config) return false; } + m_lastRunTime = yarp::os::Time::now(); + m_rpcPortName = m_name + "/rpc:i"; m_portButtons.name = m_name + "/buttons:o"; m_portAxis.name = m_name + "/axis:o"; @@ -262,10 +264,11 @@ bool JoypadControlServer::attach(PolyDriver* poly) yCError(JOYPADCONTROLSERVER) << "Attached device has no valid IJoypadController interface."; return false; } - - PeriodicThread::setPeriod(m_period); - if (!PeriodicThread::start()) { - return false; + if (!m_use_single_thread) { + PeriodicThread::setPeriod(m_period); + if (!PeriodicThread::start()) { + return false; + } } openPorts(); @@ -549,6 +552,10 @@ void JoypadControlServer::profile() void JoypadControlServer::run() { + if (m_use_single_thread && yarp::os::Time::now() - m_lastRunTime < m_period) { + return; + } + if(m_use_separate_ports) { if (m_portButtons.valid) @@ -696,6 +703,25 @@ void JoypadControlServer::run() { profile(); } + + m_lastRunTime = yarp::os::Time::now(); +} + +bool JoypadControlServer::startService() +{ + return !m_use_single_thread; +} + +bool JoypadControlServer::updateService() +{ + if (m_use_single_thread) + run(); + return true; +} + +bool JoypadControlServer::stopService() +{ + return close(); } bool JoypadControlServer::close() diff --git a/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer.h b/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer.h index b78fe1b7297..83ec7d5be51 100644 --- a/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer.h +++ b/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ class JoypadControlServer : public yarp::dev::DeviceDriver, public yarp::dev::WrapperSingle, public yarp::os::PeriodicThread, + public yarp::dev::IService, public JoypadControlServer_ParamsParser { typedef yarp::dev::IJoypadController::JoypadCtrl_coordinateMode coordsMode; @@ -68,6 +70,7 @@ class JoypadControlServer : JoyPort m_portTrackball; yarp::os::BufferedPort m_godPort; //TODO: single port purpose coordsMode m_coordsMode = yarp::dev::IJoypadController::JypCtrlcoord_CARTESIAN; + double m_lastRunTime = 0.0; bool openAndAttachSubDevice(yarp::os::Searchable& prop); @@ -89,6 +92,9 @@ class JoypadControlServer : bool threadInit() override; void threadRelease() override; void run() override; + bool startService() override; + bool updateService() override; + bool stopService() override; }; #endif diff --git a/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_ParamsParser.cpp b/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_ParamsParser.cpp index 9290c14b84f..d779d2ac5ca 100644 --- a/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_ParamsParser.cpp +++ b/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_ParamsParser.cpp @@ -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: Thu Mar 7 17:59:50 2024 +// Generated on: Mon Apr 8 10:24:20 2024 #include "JoypadControlServer_ParamsParser.h" @@ -32,6 +32,7 @@ std::vector JoypadControlServer_ParamsParser::getListOfParams() con params.push_back("name"); params.push_back("use_separate_ports"); params.push_back("profile"); + params.push_back("use_single_thread"); return params; } @@ -104,6 +105,20 @@ bool JoypadControlServer_ParamsParser::parseParams(const yarp::os::Searchab prop_check.unput("profile"); } + //Parser of parameter use_single_thread + { + if (config.check("use_single_thread")) + { + m_use_single_thread = config.find("use_single_thread").asBool(); + yCInfo(JoypadControlServerParamsCOMPONENT) << "Parameter 'use_single_thread' using value:" << m_use_single_thread; + } + else + { + yCInfo(JoypadControlServerParamsCOMPONENT) << "Parameter 'use_single_thread' using DEFAULT value:" << m_use_single_thread; + } + prop_check.unput("use_single_thread"); + } + /* //This code check if the user set some parameter which are not check by the parser //If the parser is set in strict mode, this will generate an error @@ -144,9 +159,10 @@ std::string JoypadControlServer_ParamsParser::getDocumentationOfDeviceParam doc = doc + std::string("'name': Prefix name of the ports opened by the JoypadControlServer\n"); doc = doc + std::string("'use_separate_ports': set it to 1 to use separate ports (buttons, axes, trackballs, hats) and 0 to stream all in one single port\n"); doc = doc + std::string("'profile': print the joypad data for debugging purpose\n"); + doc = doc + std::string("'use_single_thread': If true, the device is updated when calling updateService rather than using a separate thread.\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 JoypadControlServer --period 0.01 --name /robotName/joypad --use_separate_ports true --profile false\n"; + doc = doc + " yarpdev --device JoypadControlServer --period 0.01 --name /robotName/joypad --use_separate_ports true --profile false --use_single_thread false\n"; doc = doc + std::string("Using only mandatory params:\n"); doc = doc + " yarpdev --device JoypadControlServer --name /robotName/joypad\n"; doc = doc + std::string("=============================================\n\n"); return doc; diff --git a/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_ParamsParser.h b/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_ParamsParser.h index e0e6b7ff67d..0195526322a 100644 --- a/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_ParamsParser.h +++ b/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_ParamsParser.h @@ -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: Thu Mar 7 17:59:50 2024 +// Generated on: Mon Apr 8 10:24:20 2024 #ifndef JOYPADCONTROLSERVER_PARAMSPARSER_H @@ -29,10 +29,11 @@ * | - | name | string | - | /robotName/joypad | 1 | Prefix name of the ports opened by the JoypadControlServer | - | * | - | use_separate_ports | bool | - | true | 0 | set it to 1 to use separate ports (buttons, axes, trackballs, hats) and 0 to stream all in one single port | - | * | - | profile | bool | - | false | 0 | print the joypad data for debugging purpose | - | +* | - | use_single_thread | bool | - | false | 0 | If true, the device is updated when calling updateService rather than using a separate thread. | - | * * The device can be launched by yarpdev using one of the following examples (with and without all optional parameters): * \code{.unparsed} -* yarpdev --device JoypadControlServer --period 0.01 --name /robotName/joypad --use_separate_ports true --profile false +* yarpdev --device JoypadControlServer --period 0.01 --name /robotName/joypad --use_separate_ports true --profile false --use_single_thread false * \endcode * * \code{.unparsed} @@ -62,11 +63,13 @@ class JoypadControlServer_ParamsParser : public yarp::dev::IDeviceDriverParams const std::string m_name_defaultValue = {"/robotName/joypad"}; const std::string m_use_separate_ports_defaultValue = {"true"}; const std::string m_profile_defaultValue = {"false"}; + const std::string m_use_single_thread_defaultValue = {"false"}; double m_period = {0.01}; std::string m_name = {"/robotName/joypad"}; bool m_use_separate_ports = {true}; bool m_profile = {false}; + bool m_use_single_thread = {false}; bool parseParams(const yarp::os::Searchable & config) override; std::string getDeviceClassName() const override { return m_device_classname; } diff --git a/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_params.md b/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_params.md index 705cc42ca6c..cc8fff6222c 100644 --- a/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_params.md +++ b/src/devices/networkWrappers/JoypadControlServer/JoypadControlServer_params.md @@ -2,3 +2,4 @@ * | | name | string | - | /robotName/joypad | Yes | Prefix name of the ports opened by the JoypadControlServer | - | * | | use_separate_ports | bool | - | true | No | set it to 1 to use separate ports (buttons, axes, trackballs, hats) and 0 to stream all in one single port | - | * | | profile | bool | - | false | No | print the joypad data for debugging purpose | - | + * | | use_single_thread | bool | - | false | No | If true, the device is updated when calling updateService rather than using a separate thread. | - | diff --git a/src/libYARP_dev/src/yarp/dev/Drivers.cpp b/src/libYARP_dev/src/yarp/dev/Drivers.cpp index 88d60503548..b4ea95f1b68 100644 --- a/src/libYARP_dev/src/yarp/dev/Drivers.cpp +++ b/src/libYARP_dev/src/yarp/dev/Drivers.cpp @@ -325,7 +325,6 @@ DriverCreator* Drivers::Private::load(const char *name) { } static std::string terminatorKey; -static bool terminated = false; static void handler (int) { Time::useSystemClock(); @@ -343,7 +342,6 @@ static void handler (int) } if (!terminatorKey.empty()) { yCInfo(DRIVERS, "[try %d of 3] Trying to shut down %s", ct, terminatorKey.c_str()); - terminated = true; Terminator::terminateByName(terminatorKey.c_str()); } else { yCInfo(DRIVERS, "Aborting..."); @@ -529,6 +527,7 @@ int Drivers::yarpdev(int argc, char *argv[]) { service = nullptr; } } + bool terminated = false; while (dd.isValid() && !(terminated||(terminee&&terminee->mustQuit()))) { if (service!=nullptr) { double now = Time::now();