YARP  2.3.70.2
Yet Another Robot Platform
Module.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007 RobotCub Consortium
3  * Authors: Paul Fitzpatrick
4  * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
5  */
6 
7 #ifndef YARP_NO_DEPRECATED
8 
9 #include <yarp/os/Module.h>
10 
13 #include <yarp/os/BufferedPort.h>
14 #include <yarp/os/Property.h>
15 #include <yarp/os/Searchable.h>
16 #include <yarp/os/Network.h>
17 #include <yarp/os/Vocab.h>
18 
19 #include <yarp/os/impl/Logger.h>
21 
22 #include <cstdio>
23 #include <cstdlib>
24 
25 
26 using namespace yarp::os::impl;
27 using namespace yarp::os;
28 
29 
31  public yarp::os::TypedReaderCallback<yarp::os::Bottle>,
32  public Thread,
33  public SearchMonitor {
34 
35 private:
37 
38 public:
39  ModuleHelper(Module& owner) : owner(owner) {}
40 
47  virtual bool read(yarp::os::ConnectionReader& connection) override;
48 
56  virtual void onRead(yarp::os::Bottle& v) override {
57  yarp::os::Bottle reply;
58  owner.safeRespond(v, reply);
59  }
60 
67  bool handleStream) {
68  if (handleStream) {
69  source.useCallback(*this);
70  }
71  source.setReplier(*this);
72  return true;
73  }
74 
75 
76  bool attach(yarp::os::Port& source) {
77  source.setReader(*this);
78  return true;
79  }
80 
81  virtual void run() override {
82  printf("Listening to terminal (type \"quit\" to stop module)\n");
83  bool isEof = false;
84  while (!(isEof||isStopping()||owner.isStopping())) {
86  if (!isEof) {
87  Bottle cmd(str.c_str());
88  Bottle reply;
89  bool ok = owner.safeRespond(cmd, reply);
90  if (ok) {
91  //printf("ALL: %s\n", reply.toString().c_str());
92  //printf("ITEM 1: %s\n", reply.get(0).toString().c_str());
93  if (reply.get(0).toString()=="help") {
94  for (int i=0; i<reply.size(); i++) {
95  printf("%s\n",
96  reply.get(i).toString().c_str());
97  }
98  } else {
99  printf("%s\n", reply.toString().c_str());
100  }
101  } else {
102  printf("Command not understood -- %s\n", str.c_str());
103  }
104  }
105  }
106  //printf("terminal shutting down\n");
107  //owner.interruptModule();
108  }
109 
110 
111  // SearchMonitor role
112 
113 private:
114  Property comment, fallback, present, actual, reported;
116 public:
117  virtual void report(const SearchReport& report, const char *context) override {
118  ConstString ctx = context;
119  ConstString key = report.key.c_str();
120  ConstString prefix = "";
121 
122  prefix = ctx;
123  prefix += ".";
124 
125  key = prefix + key;
126  if (key.substr(0, 1)==".") {
127  key = key.substr(1, key.length());
128  }
129 
130  if (!present.check(key.c_str())) {
131  present.put(key.c_str(), "present");
132  order.addString(key.c_str());
133  }
134 
135  if (report.isFound) {
136  actual.put(key.c_str(), report.value);
137  }
138 
139  if (report.isComment==true) {
140  comment.put(key.c_str(), report.value);
141  return;
142  }
143 
144  if (report.isDefault==true) {
145  fallback.put(key.c_str(), report.value);
146  return;
147  }
148 
149  if (comment.check(key.c_str())) {
150  if (!reported.check(key.c_str())) {
151  if (report.isFound) {
152  ConstString hasValue = report.value.c_str();
153  if (hasValue.length()>35) {
154  hasValue = hasValue.substr(0, 30) + " ...";
155  }
156  printf("Checking \"%s\": = %s (%s)\n", key.c_str(),
157  hasValue.c_str(),
158  comment.check(key.c_str(),
159  Value("")).toString().c_str());
160  } else {
161  reported.put(key.c_str(), 1);
162  bool hasDefault = fallback.check(key.c_str());
163  ConstString defString = "";
164  if (hasDefault) {
165  defString += " ";
166  defString += "(default ";
167  ConstString theDefault =
168  fallback.find(key.c_str()).toString().c_str();
169  if (theDefault=="") {
170  defString += "is blank";
171  } else {
172  defString += theDefault;
173  }
174  defString += ")";
175  }
176  printf("Checking \"%s\": %s%s\n", key.c_str(),
177  comment.check(key.c_str(),
178  Value("")).toString().c_str(),
179  defString.c_str());
180  }
181  }
182  }
183  }
184 
186  return order;
187  }
188 
189  ConstString getComment(const char *option) {
190  ConstString desc = comment.find(option).toString();
191  return desc;
192  }
193 
194  Value getDefaultValue(const char *option) {
195  return fallback.find(option);
196  }
197 
198  Value getValue(const char *option) {
199  return actual.find(option);
200  }
201 
202 };
203 
204 
206  Bottle cmd, response;
207  if (!cmd.read(connection)) { return false; }
208  //printf("command received: %s\n", cmd.toString().c_str());
209  bool result = owner.safeRespond(cmd, response);
210  if (response.size()>=1) {
211  ConnectionWriter *writer = connection.getWriter();
212  if (writer!=YARP_NULLPTR) {
213  if (response.get(0).toString()=="many") {
214  for (int i=1; i<response.size(); i++) {
215  Value& v = response.get(i);
216  if (v.isList()) {
217  v.asList()->write(*writer);
218  } else {
219  Bottle b;
220  b.add(v);
221  b.write(*writer);
222  }
223  }
224  } else {
225  response.write(*writer);
226  }
227 
228  //printf("response sent: %s\n", response.toString().c_str());
229  }
230  }
231  return result;
232 }
233 
234 
235 
236 #define HELPER(x) (*((ModuleHelper*)(x)))
237 
238 Module::Module() {
239  stopFlag = false;
240  implementation = new ModuleHelper(*this);
241  yAssert(implementation!=YARP_NULLPTR);
242 }
243 
244 Module::~Module() {
245  if (implementation!=YARP_NULLPTR) {
246  HELPER(implementation).stop();
247  delete &HELPER(implementation);
248  implementation = YARP_NULLPTR;
249  }
250 }
251 
252 double Module::getPeriod() {
253  return 0.0;
254 }
255 
256 bool Module::updateModule() {
257  // insert a delay so, if user accidentally doesn't override this
258  // method, the thread won't kill the processor
260  return true;
261 }
262 
263 bool Module::interruptModule() {
264  return false;
265 }
266 
267 bool Module::respond(const Bottle& command, Bottle& reply) {
268  return basicRespond(command, reply);
269 }
270 
271 bool Module::isStopping() {
272  return stopFlag;
273 }
274 
275 void Module::setName(const char *name) {
276  this->name = name;
277 }
278 
279 bool Module::basicRespond(const Bottle& command, Bottle& reply) {
280  switch (command.get(0).asVocab()) {
281  case VOCAB3('s', 'e', 't'):
282  state.put(command.get(1).toString(), command.get(2));
283  reply.addVocab(Vocab::encode("ack"));
284  return true;
285  break;
286  case VOCAB3('g', 'e', 't'):
287  reply.add(state.check(command.get(1).toString(), Value(0)));
288  return true;
289  break;
290  case VOCAB4('q', 'u', 'i', 't'):
291  case VOCAB4('e', 'x', 'i', 't'):
292  case VOCAB3('b', 'y', 'e'):
293  reply.addVocab(Vocab::encode("bye"));
294  stopFlag = true;
295  interruptModule();
296  return true;
297  default:
298  reply.add("command not recognized");
299  return false;
300  }
301  return false;
302 }
303 
304 bool Module::safeRespond(const Bottle& command, Bottle& reply) {
305  bool ok = respond(command, reply);
306  if (!ok) {
307  // just in case derived classes don't correctly pass on messages
308  ok = basicRespond(command, reply);
309  }
310  return ok;
311 }
312 
313 
314 static Module *module = YARP_NULLPTR;
315 static bool terminated = false;
316 static void handler (int) {
317  static int ct = 0;
318  ct++;
319  if (ct>3) {
320  printf("Aborting...\n");
321  std::exit(1);
322  }
323  printf("[try %d of 3] Trying to shut down\n",
324  ct);
325  terminated = true;
326  if (module!=YARP_NULLPTR) {
327  Bottle cmd, reply;
328  cmd.fromString("quit");
329  module->safeRespond(cmd, reply);
330  //printf("sent %s, got %s\n", cmd.toString().c_str(),
331  // reply.toString().c_str());
332  }
333 }
334 
335 
336 bool Module::runModule() {
337  if (module==YARP_NULLPTR) {
338  module = this;
339  //module = &HELPER(implementation);
340  } else {
341  printf("Module::runModule() signal handling currently only good for one module\n");
342  }
345  while (updateModule()) {
346  if (terminated) break;
347  if (isStopping()) break;
349  if (isStopping()) break;
350  if (terminated) break;
351  }
352  printf("Module closing\n");
353  close();
354  printf("Module finished\n");
355  if (1) { //terminated) {
356  // only portable way to bring down a thread reading from
357  // the keyboard -- no good way to interrupt.
358  std::exit(1);
359  }
360  return true;
361 }
362 
363 
364 
365 bool Module::attach(Port& port) {
366  return HELPER(implementation).attach(port);
367 }
368 
369 bool Module::attach(TypedReader<Bottle>& port, bool handleStream) {
370  return HELPER(implementation).attach(port, handleStream);
371 }
372 
373 
374 
375 bool Module::attachTerminal() {
376  HELPER(implementation).start();
377  return true;
378 }
379 
380 int Module::runModule(int argc, char *argv[], bool skipFirst) {
381  if (!openFromCommand(argc, argv, skipFirst)) {
382  printf("Module failed to open\n");
383  return 1;
384  }
385  attachTerminal();
386  bool ok = runModule();
387  close();
388  return ok?0:1;
389 }
390 
391 bool Module::openFromCommand(int argc, char *argv[], bool skipFirst) {
392  Property options;
393  options.fromCommand(argc, argv, skipFirst);
394 
395  options.setMonitor(&HELPER(implementation));
396  // check if we're being asked to read the options from file
397  Value *val;
398  if (options.check("file", val, "configuration file to use, if any")) {
399  ConstString fname = val->toString();
400  options.unput("file");
401  printf("Working with config file %s\n", fname.c_str());
402  options.fromConfigFile(fname, false);
403 
404  // interpret command line options as a set of flags again
405  // (just in case we need to override something)
406  options.fromCommand(argc, argv, true, false);
407  }
408 
409  // probably folloing options will be removed, so don't advertise them
410  options.setMonitor(YARP_NULLPTR);
411  // check if we want to use nested options (less ambiguous)
412  if (options.check("nested", val)||options.check("lispy", val)) {
413  ConstString lispy = val->toString();
414  options.fromString(lispy);
415  }
416  options.setMonitor(&HELPER(implementation));
417 
418  name = options.check("name", Value(name), "name of module").asString();
419 
420  return open(options);
421 }
422 
423 
424 ConstString Module::getName(const char *subName) {
425  if (subName==YARP_NULLPTR) {
426  return name;
427  }
428  ConstString base = name.c_str();
429  if (subName[0]!='/') {
430  base += "/";
431  }
432  base += subName;
433  return base.c_str();
434 }
435 
436 #endif // YARP_NO_DEPRECATED
virtual bool updateModule()
Override this to do whatever your module needs to do.
virtual YARP_SSIZE_T read(const Bytes &b) override
virtual bool interruptModule()
Try to halt any ongoing operations by threads managed by the module.
ConstString substr(size_t start=0, size_t n=npos) const
Generate a substring.
dest b
Definition: ImageCopy.cpp:91
virtual void run() override
Main body of the new thread.
Definition: Module.cpp:81
Value getDefaultValue(const char *option)
Definition: Module.cpp:194
int size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:186
bool isStopping()
Check if the module is shutting down.
virtual bool read(yarp::os::ConnectionReader &connection) override
Handler for reading messages from the network, and passing them on to the respond() method...
Definition: Module.cpp:205
A class for storing options and configuration information.
Definition: Property.h:32
Property reported
Definition: Module.cpp:114
A callback for typed data from a port.
virtual bool runModule()
Calls updateModule() until that returns false.
static bool terminated
Definition: Module.cpp:315
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:105
virtual bool respond(const Bottle &command, Bottle &reply)
Respond to a message.
static NetInt32 encode(const ConstString &str)
Convert a string into a vocabulary identifier.
Definition: Vocab.cpp:12
Module()
Constructor.
A mini-server for network communication.
Definition: Port.h:45
static void handler(int)
Definition: Module.cpp:316
void add(const Value &value)
Add a Value to the bottle, at the end of the list.
Definition: Bottle.cpp:271
Bottle order
Definition: Module.cpp:115
Value getValue(const char *option)
Definition: Module.cpp:198
A string with almost the same api as std::string.
Definition: ConstString.h:44
virtual void report(const SearchReport &report, const char *context) override
Definition: Module.cpp:117
ConstString getComment(const char *option)
Definition: Module.cpp:189
void fromString(const ConstString &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:976
bool stopFlag
Definition: Module.h:220
void exit(int exit_code)
Portable wrapper for the exit() function.
Definition: Os.cpp:40
virtual void setReplier(PortReader &reader)=0
If a message is received that requires a reply, use this handler.
static void delay(double seconds)
Wait for a certain number of seconds.
Definition: Time.cpp:81
An interface for writing to a network connection.
Interface implemented by all objects that can read themselves from the network, such as Bottle object...
Definition: PortReader.h:25
virtual bool attachTerminal()
Make any input from standard input (usually the keyboard) go to the respond() method.
#define HELPER(x)
Definition: Module.cpp:236
virtual Bottle * asList() const
Get list value.
Definition: Value.cpp:202
Module & owner
Definition: Module.cpp:36
bool check(const ConstString &key) const YARP_OVERRIDE
Check if there exists a property of the given name.
Definition: Property.cpp:952
ConstString toString() const YARP_OVERRIDE
Return a standard text representation of the content of the object.
Definition: Value.cpp:303
A simple collection of objects that can be described and transmitted in a portable way...
Definition: Bottle.h:57
bool attach(yarp::os::TypedReader< yarp::os::Bottle > &source, bool handleStream)
Attach this object to a source of messages.
Definition: Module.cpp:66
void fromString(const ConstString &text)
Initializes bottle from a string.
Definition: Bottle.cpp:139
YarpSignalHandler signal(int signum, YarpSignalHandler sighandler)
Portable wrapper for the signal() function.
Definition: Os.cpp:26
void put(const ConstString &key, const ConstString &value)
Associate the given key with the given string.
Definition: Property.cpp:926
static Module * module
Definition: Module.cpp:314
#define VOCAB3(a, b, c)
Definition: Vocab.h:24
virtual bool basicRespond(const Bottle &command, Bottle &reply)
bool attach(yarp::os::Port &source)
Definition: Module.cpp:76
void addVocab(int x)
Places a vocabulary item in the bottle, at the end of the list.
Definition: Bottle.cpp:93
#define yAssert(x)
Definition: Log.h:118
virtual void useCallback(TypedReaderCallback< T > &callback)=0
Set an object whose onRead method will be called when data is available.
void unput(const ConstString &key)
Remove the association from the given key to a value, if present.
Definition: Property.cpp:958
void setReader(PortReader &reader) YARP_OVERRIDE
Set an external reader for port data.
Definition: Port.cpp:468
virtual bool openFromCommand(int argc, char *argv[], bool skipFirst=true)
Calls open() with the result of interpreting a list of command line arguments.
size_t length() const
bool read(ConnectionReader &reader) YARP_OVERRIDE
Set the bottle&#39;s value based on input from a network connection.
Definition: Bottle.cpp:175
An interface for reading from a network connection.
virtual void close() override
Definition: TcpRosStream.h:95
virtual void onRead(yarp::os::Bottle &v) override
Alternative handler for reading messages from the network, and passing them on to the respond() metho...
Definition: Module.cpp:56
Bottle getOptions()
Definition: Module.cpp:185
An abstraction for a thread of execution.
Definition: Thread.h:23
bool write(ConnectionWriter &writer) YARP_OVERRIDE
Output a representation of the bottle to a network connection.
Definition: Bottle.cpp:165
ConstString name
Definition: Module.h:221
ModuleHelper(Module &owner)
Definition: Module.cpp:39
A single value (typically within a Bottle).
Definition: Value.h:36
const char * c_str() const
Accesses the character sequence stored in this object.
Definition: ConstString.cpp:88
virtual double getPeriod()
You can override this to control the approximate periodicity at which updateModule() is called by run...
virtual ConnectionWriter * getWriter()=0
Gets a way to reply to the message, if possible.
virtual Value & find(const ConstString &key) const YARP_OVERRIDE
Gets a value corresponding to a given keyword.
Definition: Property.cpp:964
Property state
Definition: Module.h:219
An interface to the operating system, including Port based communication.
virtual int asVocab() const
Get vocabulary identifier as an integer.
Definition: Value.cpp:184
void * implementation
Definition: Module.h:218
dest v
Definition: ImageCopy.cpp:62
virtual bool isList() const
Checks if value is a list.
Definition: Value.cpp:142
static ConstString readString(bool *eof=YARP_NULLPTR)
Read a line of arbitrary length from standard input.
Definition: Network.cpp:755
std::string toString(const T &value)
convert an arbitary type to string.
The components from which ports and connections are built.
Definition: Bottle.h:30
#define VOCAB4(a, b, c, d)
Definition: Vocab.h:23
void fromCommand(int argc, char *argv[], bool skipFirst=true, bool wipe=true)
Interprets a list of command arguments as a list of properties.
Definition: Property.cpp:987
Value & get(int index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:181
bool fromConfigFile(const ConstString &fname, bool wipe=true)
Interprets a file as a list of properties.
Definition: Property.cpp:1012