YARP
Yet Another Robot Platform
yarpros.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 
7 #include "RosSlave.h"
8 #include "RosLookup.h"
9 #include "TcpRosStream.h"
10 
11 #include <yarp/os/Vocab.h>
12 #include <yarp/os/LogComponent.h>
13 #include <yarp/os/LogStream.h>
14 
15 #include <cstdio>
16 #include <string>
17 
18 using namespace yarp::os;
19 
20 
21 namespace {
23  const char* msg,
24  const char* file,
25  const unsigned int line,
26  const char* func,
27  double systemtime,
28  double networktime,
29  double externaltime,
30  const char* comp_name)
31 {
32  YARP_UNUSED(type);
33  YARP_UNUSED(file);
34  YARP_UNUSED(line);
35  YARP_UNUSED(func);
36  YARP_UNUSED(systemtime);
37  YARP_UNUSED(networktime);
38  YARP_UNUSED(externaltime);
39  YARP_UNUSED(comp_name);
40  static const char* err_str = "[ERROR] ";
41  static const char* warn_str = "[WARNING] ";
42  static const char* no_str = "";
43  printf("%s%s\n",
44  ((type == yarp::os::Log::ErrorType) ? err_str : ((type == yarp::os::Log::WarningType) ? warn_str : no_str)),
45  msg);
46 }
47 
48 YARP_LOG_COMPONENT(YARPROS,
49  "yarp.carrier.tcpros.yarpros",
53  nullptr)
54 }
55 
56 
57 std::string addPart(std::string t, std::string name, int code, Value *val, std::string orig, std::string mode="") {
58  char buf[5000];
59  if (mode=="length") {
60  sprintf(buf,"%s %s # suggested length: %d", t.c_str(), name.c_str(), code);
61  } else if (mode=="string") {
62  sprintf(buf,"%s %s # value seen: \"%s\"", t.c_str(), name.c_str(), orig.c_str());
63  } else if (mode=="vocab") {
64  char char4 = (code>>24)%256;
65  char char3 = (code>>16)%256;
66  char char2 = (code>>8)%256;
67  char char1 = code%256;
68  std::string r;
69  if (char1!=0) {
70  r += '\''; r += char1; r += "\'*256^3";
71  }
72  if (char2!=0) {
73  if (r != "") {
74  r += "+";
75  }
76  r += '\''; r += char2; r += "\'*256^2";
77  }
78  if (char3!=0) {
79  if (r != "") {
80  r += "+";
81  }
82  r += '\''; r += char3; r += "\'*256";
83  }
84  if (char4!=0) {
85  if (r != "") {
86  r += "+";
87  }
88  r += '\''; r += char4; r += '\'';
89  }
90  if (r.length()==0) {
91  r = "0";
92  }
93  sprintf(buf,"%s %s # set to %d (=%s=%s)", t.c_str(), name.c_str(), code, r.c_str(), orig.c_str());
94  } else {
95  if (val) {
96  sprintf(buf,"%s %s # set to %s (%s)", t.c_str(), name.c_str(), val->toString().c_str(), orig.c_str());
97  } else {
98  sprintf(buf,"%s %s # set to %d (%s)", t.c_str(), name.c_str(), code, orig.c_str());
99  }
100  }
101  return buf;
102 }
103 
104 std::string showFormat(Bottle& b, std::string root) {
105  std::string r;
106  int code = b.getSpecialization();
107  r += addPart("int32",root + "_tag",BOTTLE_TAG_LIST+code,nullptr,"BOTTLE_TAG_LIST+code");
108  r += "\n";
109  bool specialized = (code>0);
110  if (code==BOTTLE_TAG_INT32) {
111  r += addPart("int32[]",root,b.size(),nullptr,"length","length");
112  r += "\n";
113  if (b.size()<50) {
114  r += " # integers seen: ";
115  for (size_t i=0; i<b.size(); i++) {
116  char buf[1000];
117  sprintf(buf," %d",b.get(i).asInt32());
118  r += buf;
119  }
120  r += "\n";
121  }
122  return r;
123  }
124  if (code==BOTTLE_TAG_FLOAT64) {
125  r += addPart("float64[]",root,b.size(),nullptr,"length","length");
126  r += "\n";
127  if (b.size()<50) {
128  r += " # floats seen: ";
129  for (size_t i=0; i<b.size(); i++) {
130  char buf[1000];
131  sprintf(buf," %g",b.get(i).asFloat64());
132  r += buf;
133  }
134  r += "\n";
135  }
136  return r;
137  }
138  r += addPart("int32",root + "_len",b.size(),nullptr,"elements in list");
139  r += "\n";
140  for (size_t i=0; i<b.size(); i++) {
141  Value& v = b.get(i);
142  char tag_name[1000];
143  char val_name[1000];
144  sprintf(tag_name,"%s%zu_tag", root.c_str(), i);
145  sprintf(val_name,"%s%zu", root.c_str(), i);
146  if (v.isVocab32()) {
147  if (!specialized) {
148  r += addPart("int32",tag_name,BOTTLE_TAG_VOCAB32,nullptr,
149  "BOTTLE_TAG_VOCAB32");
150  r += "\n";
151  }
152  r += addPart("int32",val_name,v.asInt32(),nullptr,v.toString(),"vocab");
153  r += "\n";
154  } else if (v.isInt32()) {
155  if (!specialized) {
156  r += addPart("int32",tag_name,BOTTLE_TAG_INT32,nullptr,
157  "BOTTLE_TAG_INT32");
158  r += "\n";
159  }
160  r += addPart("int32",val_name,v.asInt32(),&v,v.toString());
161  r += "\n";
162  } else if (v.isFloat64()) {
163  if (!specialized) {
164  r += addPart("int32",tag_name,BOTTLE_TAG_FLOAT64,nullptr,
165  "BOTTLE_TAG_FLOAT64");
166  r += "\n";
167  }
168  r += addPart("float64",val_name,v.asInt32(),&v,v.toString());
169  r += "\n";
170  } else if (v.isList()) {
171  r += showFormat(*v.asList(), val_name);
172  } else if (v.isBlob()) {
173  if (!specialized) {
174  r += addPart("int32",tag_name,BOTTLE_TAG_BLOB,nullptr,
175  "BOTTLE_TAG_BLOB");
176  r += "\n";
177  }
178  r += addPart("int8[]",val_name,v.asBlobLength(),nullptr,"length","length");
179  } else if (v.isString()) {
180  if (!specialized) {
181  r += addPart("int32",tag_name,BOTTLE_TAG_STRING,nullptr,
182  "BOTTLE_TAG_STRING");
183  r += "\n";
184  }
185  r += addPart("string",val_name,0,nullptr,v.asString(),"string");
186  r += "\n";
187  } else {
188  r += "IGNORED ";
189  r += v.toString();
190  r += "\n";
191  }
192  }
193  return r;
194 }
195 
196 void usage(const char *action,
197  const char *msg,
198  const char *example = nullptr,
199  const char *explanation = nullptr) {
200  yCInfo(YARPROS, "\n yarpros %s", action);
201  yCInfo(YARPROS, " %s\n", msg);
202  if (example!=nullptr) {
203  yCInfo(YARPROS, " $ yarpros %s", example);
204  }
205  if (explanation!=nullptr) {
206  yCInfo(YARPROS, " # %s", explanation);
207  }
208 }
209 
210 void show_usage() {
211  yCInfo(YARPROS, "Welcome to yarpros. Here are the most useful commands available:");
212  usage("sniff out <port>","suggest .msg for output from <port> ","sniff out /grabber");
213  usage("sniff in <port>","suggest .msg for input to <port> ","sniff in /grabber");
214  usage("type <name>","(MOVED to yarpidl_rosmsg) generate YARP header files from <name>.msg","type PointCloud2");
215  usage("help","show this help",nullptr);
216 
217  yCInfo(YARPROS);
218  yCInfo(YARPROS, "YARP clients can use the ROS name server. If you'd prefer to stick");
219  yCInfo(YARPROS, "with the native YARP name server, the following commands are useful:");
220  usage("roscore","register port /roscore to refer to ROS_MASTER_URI","roscore");
221  usage("roscore <hostname> <port number>","manually register port /roscore to point to the ros master","roscore 192.168.0.1 11311");
222  usage("pub[lisher] <node> <topic>","register a ROS publisher <node>/<topic> pair as a port called <node><topic>","publisher /talker /chatter","this registers a port called /talker/chatter");
223  usage("pub[lisher] <port> <node> <topic>","register a ROS publisher <node>/<topic> pair as a port called <port>","publisher /talker /talker /chatter");
224  usage("sub[scriber] <node> <topic>","register a ROS subscriber <node>/<topic> pair as a port called <node><topic>","subscriber /listener /chatter","this registers a port called /listener/chatter");
225  usage("sub[scriber] <yarp> <node> <topic>","register a ROS subscriber <node>/<topic> pair as a port called <port>","subscriber /listener /listener /chatter");
226  usage("service <yarp> <node> <service>","register a ROS service <node>/<service> pair as a port called <port>","service /adder /add_two_ints_server /add_two_ints");
227  usage("node <name>","register a ROS node name with YARP","node /talker");
228 }
229 
230 bool announce_port(const char *name,
231  PortReader& reply) {
232  Bottle req;
233  req.addString("announce");
234  req.addString(name);
236  req,
237  reply);
238 }
239 
240 bool register_port(const char *name,
241  const char *carrier,
242  const char *hostname,
243  int portnum,
244  PortReader& reply) {
245  std::string ip = Contact::convertHostToIp(hostname);
246  Bottle req;
247  req.addString("register");
248  req.addString(name);
249  req.addString(carrier);
250  req.addString(ip);
251  req.addInt32(portnum);
253  req,
254  reply);
255  if (ok) {
256  Bottle reply2;
257  announce_port(name,reply2);
258  }
259  return ok;
260 }
261 
262 
263 int main(int argc, char *argv[]) {
264  if (argc<=1) {
265  show_usage();
266  return 0;
267  }
268  if (std::string(argv[1])=="help" ||
269  std::string(argv[1])=="--help") {
270  show_usage();
271  return 0;
272  }
273 
274  Network yarp;
275 
276  // Read in the command sequence
277  Bottle cmd;
278  for (int i=1; i<argc; i++) {
279  Value v;
280  v.fromString(argv[i]);
281  if (argv[i][0]!='-') {
282  cmd.add(v);
283  }
284  }
285 
286  // Check for flags
287  Property options;
288  options.fromCommand(argc,argv);
289 
290  if (options.check("verbose")) {
291  yCWarning(YARPROS, "The 'verbose' option is deprecated");
292  }
293 
294  // Get the command tag
295  std::string tag = cmd.get(0).asString();
296 
297  // Process the command
298  if (tag=="roscore") {
299  if (cmd.size()>1) {
300  if (!(cmd.get(1).isString()&&cmd.get(2).isInt32())) {
301  yCError(YARPROS, "wrong syntax, run with no arguments for help");
302  return 1;
303  }
304  Bottle reply;
305  register_port("/roscore", "xmlrpc",
306  cmd.get(1).asString().c_str(), cmd.get(2).asInt32(),
307  reply);
308  yCInfo(YARPROS, "%s", reply.toString().c_str());
309  } else {
310  Bottle reply;
312  if (!c.isValid()) {
313  yCError(YARPROS, "cannot find roscore, is ROS_MASTER_URI set?");
314  return 1;
315  }
316  register_port("/roscore", "xmlrpc",
317  c.getHost().c_str(), c.getPort(),
318  reply);
319  yCInfo(YARPROS, "%s", reply.toString().c_str());
320  }
321  return 0;
322  } else if (tag=="node") {
323  Bottle req, reply;
324  if (cmd.size()!=2) {
325  yCError(YARPROS, "wrong syntax, run with no arguments for help");
326  return 1;
327  }
328  if (!cmd.get(1).isString()) {
329  yCError(YARPROS, "wrong syntax, run with no arguments for help");
330  return 1;
331  }
332  RosLookup lookup;
333  bool ok = lookup.lookupCore(cmd.get(1).asString());
334  if (ok) {
335  register_port(cmd.get(1).asString().c_str(),
336  "xmlrpc",
337  lookup.hostname.c_str(),
338  lookup.portnum,
339  reply);
340  yCInfo(YARPROS, "%s",reply.toString().c_str());
341  }
342  return ok?0:1;
343  } else if (tag=="publisher"||tag=="pub"||tag=="service"||tag=="srv") {
344  bool service = (tag=="service"||tag=="srv");
345  Bottle req, reply;
346  if (cmd.size()!=3 && cmd.size()!=4) {
347  yCError(YARPROS, "wrong syntax, run with no arguments for help");
348  return 1;
349  }
350  int offset = 0;
351  if (cmd.size()==3) {
352  offset = -1;
353  }
354  std::string yarp_port = cmd.get(1+offset).asString();
355  std::string ros_port = cmd.get(2+offset).asString();
356  std::string topic = cmd.get(3+offset).asString();
357  if (cmd.size()==3) {
358  yarp_port = ros_port + topic;
359  }
360  RosLookup lookup;
361  yCDebug(YARPROS, " * looking up ros node %s", ros_port.c_str());
362  bool ok = lookup.lookupCore(ros_port);
363  if (!ok) {
364  return 1;
365  }
366  yCDebug(YARPROS, " * found ros node %s", ros_port.c_str());
367  yCDebug(YARPROS, " * looking up topic %s", topic.c_str());
368  ok = lookup.lookupTopic(topic);
369  if (!ok) {
370  return 1;
371  }
372  yCDebug(YARPROS, " * found topic %s", topic.c_str());
373  std::string carrier = "tcpros+role.pub+topic.";
374  if (service) {
375  carrier = "rossrv+service.";
376  }
377  register_port(yarp_port.c_str(),
378  (carrier+topic).c_str(),
379  lookup.hostname.c_str(),
380  lookup.portnum,
381  reply);
382  yCInfo(YARPROS, "%s", reply.toString().c_str());
383  return 0;
384  } else if (tag=="subscriber"||tag=="sub") {
385  Bottle req, reply;
386  if (cmd.size()!=3 && cmd.size()!=4) {
387  yCError(YARPROS, "wrong syntax, run with no arguments for help");
388  return 1;
389  }
390  int offset = 0;
391  if (cmd.size()==3) {
392  offset = -1;
393  }
394  std::string yarp_port = cmd.get(1+offset).asString();
395  std::string ros_port = cmd.get(2+offset).asString();
396  std::string topic = cmd.get(3+offset).asString();
397  if (cmd.size()==3) {
398  yarp_port = ros_port + topic;
399  }
400  RosLookup lookup;
401  yCDebug(YARPROS, " * looking up ros node %s", ros_port.c_str());
402  bool ok = lookup.lookupCore(ros_port);
403  if (!ok) {
404  return 1;
405  }
406  yCDebug(YARPROS, " * found ros node %s", ros_port.c_str());
407  ok = register_port(yarp_port.c_str(),
408  (std::string("tcpros+role.sub+topic.")+topic).c_str(),
409  lookup.hostname.c_str(),
410  lookup.portnum,
411  reply);
412  yCInfo(YARPROS, "%s", reply.toString().c_str());
413  return ok?0:1;
414  } else if (tag=="type") {
415  yCError(YARPROS, "MOVED: 'yarpros type' is now 'yarpidl_rosmsg'");
416  return 1;
417  } else if (tag=="sniff") {
418  if (cmd.size()<2) {
419  yCError(YARPROS, "Show the format of a YARP bottle-compatible message in ROS syntax.");
420  return 1;
421  }
422  std::string dir = cmd.get(1).asString();
423  bool in = false;
424  if (dir == "in") {
425  in = true;
426  } else if (dir == "out") {
427  in = false;
428  } else {
429  yCError(YARPROS, "Please specify one of 'in' or 'out'.");
430  return 1;
431  }
432  std::string pname = cmd.get(2).asString();
433  Port p;
434  if (!p.open("...")) {
435  return 1;
436  }
437  if (in) {
438  if (!Network::connect(pname, p.getName(), "tcp+log.in")) {
439  return 1;
440  }
441  } else {
442  if (!Network::connect(pname, p.getName())) {
443  return 1;
444  }
445  }
446  Bottle b;
447  p.read(b);
448  std::string r;
449  if (in&&b.get(0).asVocab32()==yarp::os::createVocab32('r','p','c')&&b.get(1).isList()) {
450 
451  r = showFormat(*b.get(1).asList(),"v");
452  } else {
453  r = showFormat(b,"v");
454  }
455  yCInfo(YARPROS, "Got message: [%s]",r.c_str());
456  return 0;
457  } else {
458  yCError(YARPROS, "unknown command, run with no arguments for help");
459  return 1;
460  }
461  return 0;
462 }
#define BOTTLE_TAG_FLOAT64
Definition: Bottle.h:25
#define BOTTLE_TAG_INT32
Definition: Bottle.h:21
#define BOTTLE_TAG_STRING
Definition: Bottle.h:26
#define BOTTLE_TAG_BLOB
Definition: Bottle.h:27
#define BOTTLE_TAG_LIST
Definition: Bottle.h:28
#define BOTTLE_TAG_VOCAB32
Definition: Bottle.h:23
float t
bool lookupTopic(const std::string &name)
Definition: RosLookup.cpp:73
std::string hostname
Definition: RosLookup.h:15
bool lookupCore(const std::string &name)
Definition: RosLookup.cpp:36
int portnum
Definition: RosLookup.h:16
static yarp::os::Contact getRosCoreAddressFromEnv()
Definition: RosLookup.cpp:118
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:74
void add(const Value &value)
Add a Value to the bottle, at the end of the list.
Definition: Bottle.cpp:336
int getSpecialization()
Get numeric bottle code for this bottle.
Definition: Bottle.cpp:261
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
void addInt32(std::int32_t x)
Places a 32-bit integer in the bottle, at the end of the list.
Definition: Bottle.cpp:140
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:170
std::string toString() const override
Gives a human-readable textual representation of the bottle.
Definition: Bottle.cpp:211
Represents how to reach a part of a YARP network.
Definition: Contact.h:36
bool isValid() const
Checks if a Contact is tagged as valid.
Definition: Contact.cpp:298
static std::string convertHostToIp(const char *name)
If the host is a machine name, convert it to a plausible IP address.
Definition: Contact.cpp:331
int getPort() const
Get the port number associated with this Contact for socket communication.
Definition: Contact.cpp:239
std::string getHost() const
Get the host name associated with this Contact for socket communication.
Definition: Contact.cpp:228
virtual std::string getName() const
Get name of port.
Definition: Contactable.cpp:14
@ ErrorType
Definition: Log.h:78
@ LogTypeReserved
Definition: Log.h:80
@ InfoType
Definition: Log.h:76
@ WarningType
Definition: Log.h:77
static Contact getNameServerContact()
Get the contact information for the port associated with the nameserver (usually "/root",...
Definition: Network.cpp:1360
static bool connect(const std::string &src, const std::string &dest, const std::string &carrier="", bool quiet=true)
Request that an output port connect to an input port.
Definition: Network.cpp:682
static bool write(const Contact &contact, PortWriter &cmd, PortReader &reply, bool admin=false, bool quiet=false, double timeout=-1)
Send a single command to a port and await a single response.
Definition: Network.cpp:1226
Utilities for manipulating the YARP network, including initialization and shutdown.
Definition: Network.h:783
Interface implemented by all objects that can read themselves from the network, such as Bottle object...
Definition: PortReader.h:25
A mini-server for network communication.
Definition: Port.h:47
bool read(PortReader &reader, bool willReply=false) override
Read an object from the port.
Definition: Port.cpp:472
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
Definition: Port.cpp:79
A class for storing options and configuration information.
Definition: Property.h:34
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Property.cpp:1041
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:1074
A single value (typically within a Bottle).
Definition: Value.h:45
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition: Value.cpp:222
virtual bool isString() const
Checks if value is a string.
Definition: Value.cpp:156
virtual yarp::conf::vocab32_t asVocab32() const
Get vocabulary identifier as an integer.
Definition: Value.cpp:228
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:204
virtual size_t asBlobLength() const
Get binary data length.
Definition: Value.cpp:267
virtual bool isList() const
Checks if value is a list.
Definition: Value.cpp:162
virtual Bottle * asList() const
Get list value.
Definition: Value.cpp:240
virtual bool isBlob() const
Checks if value is a binary object.
Definition: Value.cpp:180
virtual bool isFloat64() const
Checks if value is a 64-bit floating point number.
Definition: Value.cpp:150
std::string toString() const override
Return a standard text representation of the content of the object.
Definition: Value.cpp:356
virtual bool isInt32() const
Checks if value is a 32-bit integer.
Definition: Value.cpp:132
virtual bool isVocab32() const
Checks if value is a vocabulary identifier.
Definition: Value.cpp:174
void fromString(const char *str)
Set value to correspond to a textual representation.
Definition: Value.cpp:351
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
#define yCInfo(component,...)
Definition: LogComponent.h:132
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCWarning(component,...)
Definition: LogComponent.h:143
#define yCDebug(component,...)
Definition: LogComponent.h:109
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:77
void print_callback(yarp::os::Log::LogType type, const char *msg, const char *file, const unsigned int line, const char *func, double systemtime, double networktime, double externaltime, const char *comp_name)
An interface to the operating system, including Port based communication.
constexpr yarp::conf::vocab32_t createVocab32(char a, char b=0, char c=0, char d=0)
Create a vocab from chars.
Definition: Vocab.h:28
The main, catch-all namespace for YARP.
Definition: dirs.h:16
#define YARP_UNUSED(var)
Definition: api.h:162
std::string showFormat(Bottle &b, std::string root)
Definition: yarpros.cpp:104
std::string addPart(std::string t, std::string name, int code, Value *val, std::string orig, std::string mode="")
Definition: yarpros.cpp:57
int main(int argc, char *argv[])
Definition: yarpros.cpp:263
bool register_port(const char *name, const char *carrier, const char *hostname, int portnum, PortReader &reply)
Definition: yarpros.cpp:240
void show_usage()
Definition: yarpros.cpp:210
bool announce_port(const char *name, PortReader &reply)
Definition: yarpros.cpp:230
void usage(const char *action, const char *msg, const char *example=nullptr, const char *explanation=nullptr)
Definition: yarpros.cpp:196