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