YARP
Yet Another Robot Platform
DeviceGroup.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "DeviceGroup.h"
8
9#include <cstdio>
10#include <yarp/os/Time.h>
12#include <yarp/dev/Drivers.h>
14
16
17#include <mutex>
18#include <vector>
19
20using namespace yarp::os;
21using namespace yarp::sig;
22using namespace yarp::dev;
23
24namespace {
25YARP_LOG_COMPONENT(DEVICEGROUP, "yarp.devices.DeviceGroup")
26}
27
28#define HELPER(x) (*((DeviceGroupHelper*)(x)))
29
30
32{
33private:
34 std::vector<PolyDriver *> drivers;
35 std::vector<std::string> names;
36 std::vector<bool> needDrive;
37 std::mutex mutex;
38public:
39 bool needDriveSummary{false};
40
41 void clear()
42 {
43 mutex.lock();
44 std::vector<PolyDriver *>& lst = drivers;
45 for (unsigned int i=0; i<lst.size(); i++) {
46 yCInfo(DEVICEGROUP, "*** Removing %s",names[i].c_str());
47 Drivers::factory().remove(names[i].c_str());
48 yCTrace(DEVICEGROUP, "*** removed %s",names[i].c_str());
49 delete lst[i];
50 yCTrace(DEVICEGROUP, "*** deleted %s",names[i].c_str());
51 }
52 lst.clear();
53 names.clear();
54 mutex.unlock();
55 }
56
57 void update()
58 {
59 mutex.lock();
60 std::vector<PolyDriver *>& lst = drivers;
61 for (unsigned int i=0; i<lst.size(); i++) {
62 if (needDrive[i]) {
63 IService *service;
64 lst[i]->view(service);
65 if (service!=nullptr) {
66 service->updateService();
67 }
68 }
69 }
70 mutex.unlock();
71 }
72
73 bool close()
74 {
75 yCTrace(DEVICEGROUP, "*** Device group closing");
76 clear();
77 yCTrace(DEVICEGROUP, "*** Device group closed");
78 return true;
79 }
80
82 {
83 clear();
84 }
85
86 bool add(const std::string& name, yarp::os::Searchable& config)
87 {
88 yCTrace(DEVICEGROUP, "ADDING %s", config.toString().c_str());
89 auto* pd = new PolyDriver();
90 yCAssert(DEVICEGROUP, pd!=nullptr);
91 bool result = pd->open(config);
92 if (!result) {
93 delete pd;
94 return false;
95 }
96 drivers.push_back(pd);
97 names.push_back(name);
98 IService *service = nullptr;
99 pd->view(service);
100 bool backgrounded = true;
101 if (service!=nullptr) {
102 backgrounded = service->startService();
103 if (backgrounded) {
104 // we don't need to poll this, so forget about the
105 // service interface
106 yCInfo(DEVICEGROUP, "group: service backgrounded");
107 service = nullptr;
108 }
109 }
110 needDrive.push_back(!backgrounded);
111 needDriveSummary = needDriveSummary || (!backgrounded);
112 Drivers::factory().add(new DriverLinkCreator(name,*pd));
113 return true;
114 }
115
116};
117
118
119
120
122{
123 if (implementation==nullptr) {
124 implementation = new DeviceGroupHelper;
125 }
126 if (implementation==nullptr) {
127 yCError(DEVICEGROUP, "Out of memory");
128 return false;
129 }
130
131 if (config.check("part","a list of section names, with each section containing a device")) {
132 Bottle bot = config.findGroup("part").tail();
133 yCInfo(DEVICEGROUP, "Assembly of: %s", bot.toString().c_str());
134 for (size_t i=0; i<bot.size(); i++) {
135 std::string name = bot.get(i).asString();
136 yCInfo(DEVICEGROUP, " %s -> %s", name.c_str(),
137 config.findGroup(name).toString().c_str());
138 bool result = HELPER(implementation).add(name,
139 config.findGroup(name));
140 if (!result) {
141 HELPER(implementation).close();
142 return false;
143 }
144 }
145 return true;
146 }
147 return false;
148}
149
150
151bool DeviceGroup::open(const char *key, PolyDriver& poly,
152 yarp::os::Searchable& config, const char *comment)
153{
154 Value *name;
155 if (config.check(key,name,comment)) {
156 if (name->isString()) {
157 // maybe user isn't doing nested configuration
159 p.setMonitor(config.getMonitor(),
160 name->toString().c_str()); // pass on any monitoring
161 p.fromString(config.toString());
162 p.put("device",name->toString());
163 p.unput("subdevice");
164 p.unput("wrapped");
165 poly.open(p);
166 } else {
167 Bottle subdevice = config.findGroup(key).tail();
168 poly.open(subdevice);
169 }
170 if (!poly.isValid()) {
171 yCError(DEVICEGROUP, "cannot make <%s>", name->toString().c_str());
172 return false;
173 }
174 } else {
175 yCError(DEVICEGROUP, "\"--%s <name>\" not set", key);
176 return false;
177 }
178 return true;
179}
180
181
182bool DeviceGroup::closeMain()
183{
184 yCInfo(DEVICEGROUP, "Devices closing");
185 HELPER(implementation).close();
186 source.close();
187 sink.close();
188 return true;
189}
190
192{
193 return !HELPER(implementation).needDriveSummary;
194}
195
196
198{
199 HELPER(implementation).update();
200 return true;
201}
202
203
205{
206 if (implementation!=nullptr) {
207 delete &HELPER(implementation);
208 implementation = nullptr;
209 }
210}
#define HELPER(x)
Definition: DeviceGroup.cpp:28
bool add(const std::string &name, yarp::os::Searchable &config)
Definition: DeviceGroup.cpp:86
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
bool updateService() override
Give the service the chance to run for a while.
bool startService() override
Initiate the service, whatever it is.
~DeviceGroup() override
A factory for creating links to a driver that has already been created.
Common interface for devices that act like services (by which we mean they do something for remote us...
virtual bool startService()
Initiate the service, whatever it is.
virtual bool updateService()
Give the service the chance to run for a while.
A container for a device driver.
Definition: PolyDriver.h:23
bool close() override
Close the DeviceDriver.
Definition: PolyDriver.cpp:173
bool isValid() const
Check if device is valid.
Definition: PolyDriver.cpp:196
bool open(const std::string &txt)
Construct and configure a device by its common name.
Definition: PolyDriver.cpp:140
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:64
size_type size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:251
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:246
Bottle tail() const
Get all but the first element of a bottle.
Definition: Bottle.cpp:388
std::string toString() const override
Gives a human-readable textual representation of the bottle.
Definition: Bottle.cpp:211
A class for storing options and configuration information.
Definition: Property.h:33
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1063
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:1015
void unput(const std::string &key)
Remove the association from the given key to a value, if present.
Definition: Property.cpp:1046
A base class for nested structures that can be searched.
Definition: Searchable.h:63
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
A single value (typically within a Bottle).
Definition: Value.h:43
virtual bool isString() const
Checks if value is a string.
Definition: Value.cpp:156
std::string toString() const override
Return a standard text representation of the content of the object.
Definition: Value.cpp:356
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
#define yCInfo(component,...)
Definition: LogComponent.h:171
#define yCError(component,...)
Definition: LogComponent.h:213
#define yCAssert(component, x)
Definition: LogComponent.h:240
#define yCTrace(component,...)
Definition: LogComponent.h:84
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:76
For streams capable of holding different kinds of content, check what they actually have.
An interface to the operating system, including Port based communication.