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