Fawkes API Fawkes Development Version
net.cpp
1
2/***************************************************************************
3 * net.cpp - Generic network tool
4 *
5 * Created: Fri Nov 16 10:27:57 2007
6 * Copyright 2005-2009 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * Read the full text in the LICENSE.GPL file in the doc directory.
21 */
22
23#include <core/exceptions/software.h>
24#include <core/threading/mutex.h>
25#include <core/threading/wait_condition.h>
26#include <fvutils/color/colorspaces.h>
27#include <fvutils/colormap/cmfile.h>
28#include <fvutils/colormap/yuvcm.h>
29#include <fvutils/net/fuse.h>
30#include <fvutils/net/fuse_client.h>
31#include <fvutils/net/fuse_client_handler.h>
32#include <fvutils/net/fuse_image_content.h>
33#include <fvutils/net/fuse_imagelist_content.h>
34#include <fvutils/net/fuse_lut_content.h>
35#include <fvutils/net/fuse_lutlist_content.h>
36#include <fvutils/net/fuse_message.h>
37#include <fvutils/writers/fvraw.h>
38#include <netcomm/service_discovery/browse_handler.h>
39#include <utils/system/argparser.h>
40#include <utils/system/console_colors.h>
41#ifdef HAVE_AVAHI
42# include <netcomm/dns-sd/avahi_thread.h>
43#endif
44
45// for inet_ntop
46#include <arpa/inet.h>
47#include <netinet/in.h>
48
49#include <cstdio>
50#include <cstdlib>
51#include <cstring>
52
53using namespace fawkes;
54using namespace firevision;
55
56/** FireVision Network Tool */
58{
59public:
60 /** Constructor.
61 * @param argp argument parser
62 */
64 {
65 argp_ = argp;
66 exploring_ = false;
67 explore_waitcond_ = NULL;
68 }
69
70 void
71 fuse_invalid_server_version(uint32_t local_version, uint32_t remote_version) noexcept
72 {
73 printf("Invalid version received (local: %u, remote: %u)\n", local_version, remote_version);
74 }
75
76 virtual void
78 {
79 }
80
81 virtual void
83 {
84 }
85
86 virtual void
88 {
89 // printf("Received message of type %u\n", m->type());
90
91 switch (m->type()) {
92 case FUSE_MT_IMAGE:
93 // we got an image, save it to the given file
94 try {
95 FuseImageContent *ic = m->msgc<FuseImageContent>();
96 if (ic->format() == FUSE_IF_RAW) {
97 FvRawWriter *w = new FvRawWriter(file_,
98 ic->pixel_width(),
99 ic->pixel_height(),
100 (colorspace_t)ic->colorspace(),
101 ic->buffer());
102 w->write();
103 delete w;
104 } else if (ic->format() == FUSE_IF_JPEG) {
105 FILE *f = fopen(file_, "w");
106 if (fwrite(ic->buffer(), ic->buffer_size(), 1, f) == 0) {
107 printf("Failed to write data to file");
108 }
109 fclose(f);
110 } else {
111 printf("Image of unknown format (%u) received.\n", ic->format());
112 }
113 delete ic;
114 } catch (Exception &e) {
115 printf("Received message cannot be casted to FuseImageMessage\n");
116 e.print_trace();
117 }
118 client_->cancel();
119 break;
120 case FUSE_MT_IMAGE_LIST:
121 try {
123 if (ilc->has_next()) {
124 printf("Available images:\n");
125 while (ilc->has_next()) {
126 FUSE_imageinfo_t *ii = ilc->next();
127 char tmp[IMAGE_ID_MAX_LENGTH + 1];
128 tmp[IMAGE_ID_MAX_LENGTH] = 0;
129 strncpy(tmp, ii->image_id, IMAGE_ID_MAX_LENGTH);
130 printf(" %s (%u x %u, %s)\n",
131 tmp,
132 ntohl(ii->width),
133 ntohl(ii->height),
134 colorspace_to_string((colorspace_t)ntohs(ii->colorspace)));
135 }
136 } else {
137 printf("No images available\n");
138 }
139 delete ilc;
140 } catch (Exception &e) {
141 printf("Received message cannot be casted to FuseImageListMessage\n");
142 e.print_trace();
143 }
144 break;
145 case FUSE_MT_LUT_LIST:
146 try {
147 FuseLutListContent *llc = m->msgc<FuseLutListContent>();
148 if (llc->has_next()) {
149 printf("Available lookup tables:\n");
150 while (llc->has_next()) {
151 FUSE_lutinfo_t *li = llc->next();
152 char tmp[LUT_ID_MAX_LENGTH + 1];
153 tmp[LUT_ID_MAX_LENGTH] = 0;
154 strncpy(tmp, li->lut_id, LUT_ID_MAX_LENGTH);
155 printf(" %s (%u x %u x %u, %u bpc)\n",
156 tmp,
157 ntohl(li->width),
158 ntohl(li->height),
159 ntohl(li->depth),
160 ntohl(li->bytes_per_cell));
161 }
162 } else {
163 printf("No lookup tables available\n");
164 }
165 delete llc;
166 } catch (Exception &e) {
167 printf("Received message cannot be casted to FuseImageListMessage\n");
168 e.print_trace();
169 }
170 client_->cancel();
171 break;
172
173 case FUSE_MT_LUT:
174 // we got a LUT, save it to the given file
175 try {
176 FuseLutContent *lc = m->msgc<FuseLutContent>();
177 // Currently we expect colormaps, so make sure we get sensible dimensions
178 if (lc->width() != 256) {
179 printf("Invalid dimensions for LUT received, colormap width %u != 256", lc->width());
180 } else if (lc->height() != 256) {
181 printf("Invalid dimensions for LUT received, colormap height %u != 256", lc->height());
182 } else if (lc->depth() > 256) {
183 printf("Invalid dimensions for LUT received, colormap depth %u > 256", lc->depth());
184 } else {
185 try {
186 YuvColormap yuvcm(lc->depth());
187 yuvcm.set(lc->buffer());
188 ColormapFile cmf;
189 cmf.add_colormap(&yuvcm);
190 cmf.write(file_);
191 } catch (Exception &e) {
192 e.append("Failed to save colormap");
193 e.print_trace();
194 }
195 }
196 delete lc;
197 } catch (Exception &e) {
198 printf("Received message cannot be casted to FuseLutMessage\n");
199 e.print_trace();
200 }
201 client_->cancel();
202 break;
203
204 case FUSE_MT_SET_LUT_SUCCEEDED: {
206 char lut_id[LUT_ID_MAX_LENGTH + 1];
207 lut_id[LUT_ID_MAX_LENGTH] = 0;
208 strncpy(lut_id, lutdesc->lut_id, LUT_ID_MAX_LENGTH);
209 printf("LUT %s has been uploaded successfully.\n", lut_id);
210 client_->cancel();
211 } break;
212
213 case FUSE_MT_SET_LUT_FAILED: {
215 char lut_id[LUT_ID_MAX_LENGTH + 1];
216 lut_id[LUT_ID_MAX_LENGTH] = 0;
217 strncpy(lut_id, lutdesc->lut_id, LUT_ID_MAX_LENGTH);
218 printf("LUT upload of %s has failed.\n", lut_id);
219 client_->cancel();
220 } break;
221
222 default:
223 printf("Unhandled message of type %u received\n", m->type());
224 client_->cancel();
225 break;
226 }
227 }
228
229 virtual void
231 {
232 printf("All for now\n");
233 explore_mutex_->lock();
234 explore_waitcond_->wake_all();
235 explore_mutex_->unlock();
236 }
237
238 virtual void
240 {
241 }
242
243 virtual void
244 browse_failed(const char *name, const char *type, const char *domain)
245 {
246 printf("Browsing for %s failed\n", type);
247 }
248
249 virtual void
250 service_added(const char * name,
251 const char * type,
252 const char * domain,
253 const char * host_name,
254 const char * interface,
255 const struct sockaddr * addr,
256 const socklen_t addr_size,
257 uint16_t port,
258 std::list<std::string> &txt,
259 int flags)
260 {
261 struct sockaddr_in *s;
262 if (addr_size == sizeof(struct sockaddr_in)) {
263 s = (struct sockaddr_in *)addr;
264 } else {
265 printf("%s socket data not IPv4, ignoring\n", name);
266 return;
267 }
268
269 char addrp[INET_ADDRSTRLEN];
270 inet_ntop(AF_INET, &(s->sin_addr), addrp, sizeof(addrp));
271 printf(
272 "Found %s%s%s (%s/%s on %hu), querying\n", c_blue, name, c_normal, host_name, addrp, port);
273
274 client_ = new FuseClient(host_name, port, this);
275 client_->connect();
276 client_->start();
277 client_->wait_greeting();
278 show_all();
279 client_->join();
280 delete client_;
281
282 printf("\n");
283 }
284
285 virtual void
286 service_removed(const char *name, const char *type, const char *domain)
287 {
288 }
289
290 /** Print usage message. */
291 void
293 {
294 printf("Usage: %s -i/-c/-C/-s/-e [-n host[:port]/id file]\n"
295 " -i Get image\n"
296 " -j Get JPEG-compressed image\n"
297 " -c Get colormap\n"
298 " -C Set colormap from file\n"
299 " -s Show available images and LUTs\n"
300 " -e Explore network. Will query all instances of Fountain\n"
301 " found on the network for all available images and LUTs.\n"
302 " -n net_string Open network camera, the camera string is of the form\n"
303 " host[:port]/id. You have to specify at least the host\n"
304 " and the id, the port is optional and defaults to 5000\n"
305 " Depending on the operation id is the image or the LUT ID\n"
306 " file File to write incoming data to or to read data to send from\n",
307 argp_->program_name());
308 }
309
310 /** Request image.
311 * @param image_id Image ID.
312 * @param jpeg if true JPEG images are requested, raw images otherwise
313 */
314 void
315 get_image(const char *image_id, bool jpeg)
316 {
319 memset(idm, 0, sizeof(FUSE_imagereq_message_t));
320 strncpy(idm->image_id, image_id, IMAGE_ID_MAX_LENGTH - 1);
321 idm->format = (jpeg ? FUSE_IF_JPEG : FUSE_IF_RAW);
322 client_->enqueue(FUSE_MT_GET_IMAGE, idm, sizeof(FUSE_imagereq_message_t));
323 }
324
325 /** Request LUT.
326 * @param lut_id LUT ID.
327 */
328 void
329 get_colormap(const char *lut_id)
330 {
332 memset(ldm, 0, sizeof(FUSE_lutdesc_message_t));
333 strncpy(ldm->lut_id, lut_id, LUT_ID_MAX_LENGTH - 1);
334 client_->enqueue(FUSE_MT_GET_LUT, ldm, sizeof(FUSE_lutdesc_message_t));
335 }
336
337 /** Upload LUT.
338 * @param lut_id LUT ID.
339 */
340 void
341 set_colormap(const char *lut_id)
342 {
343 ColormapFile cmf;
344 cmf.read(file_);
345 Colormap * cm = cmf.get_colormap();
346 FuseLutContent *lc = new FuseLutContent(lut_id,
347 cm->get_buffer(),
348 cm->width(),
349 cm->height(),
350 cm->depth(),
351 /* bytes per cell */ 1);
352 delete cm;
353
354 client_->enqueue(new FuseNetworkMessage(FUSE_MT_SET_LUT, lc));
355 }
356
357 /** Show all images and LUTs. */
358 void
360 {
361 client_->enqueue(FUSE_MT_GET_IMAGE_LIST);
362 client_->enqueue(FUSE_MT_GET_LUT_LIST);
363 }
364
365 /** Explore network.
366 * This will query via service discovery for all Fountain instances on the local
367 * network. It will then connect to each of these and query them for existing images
368 * and lookup tables.
369 */
370 void
372 {
373#ifdef HAVE_AVAHI
374 exploring_ = true;
375 explore_mutex_ = new Mutex();
376 explore_waitcond_ = new WaitCondition(explore_mutex_);
377
378 explore_mutex_->lock();
379
380 avahi_thread_ = new AvahiThread();
381 avahi_thread_->start();
382
383 avahi_thread_->watch_service("_fountain._tcp", this);
384
385 explore_waitcond_->wait();
386 delete explore_waitcond_;
387 explore_mutex_->unlock();
388 delete explore_mutex_;
389 avahi_thread_->cancel();
390 avahi_thread_->join();
391 delete avahi_thread_;
392#else
393 printf("\nExploration is not available because Avahi support is missing. "
394 "Install avahi-devel and recompile.\n\n");
395#endif
396 }
397
398 /** Run. */
399 void
401 {
402 if (argp_->has_arg("h")) {
403 print_usage();
404 exit(0);
405 } else {
406 char *net_string;
407 if (argp_->has_arg("n")) {
408 net_string = strdup(argp_->arg("n"));
409 } else {
410 net_string = strdup("localhost");
411 }
412 char *id;
413 char *host = NULL;
414 char *port = NULL;
415 char *save_ptr = NULL;
416 int port_num = 2208;
417 char *hostport;
418
419 hostport = strtok_r(net_string, "/", &save_ptr);
420 id = strtok_r(NULL, "", &save_ptr);
421
422 if (strchr(hostport, ':') != NULL) {
423 host = strtok_r(hostport, ":", &save_ptr);
424 port = strtok_r(NULL, "", &save_ptr);
425 } else {
426 host = hostport;
427 }
428
429 if (port != NULL) {
430 port_num = atoi(port);
431 if ((port_num < 0) || (port_num > 0xFFFF)) {
432 throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
433 }
434 }
435
436 if (argp_->has_arg("i") || argp_->has_arg("j") || argp_->has_arg("c")
437 || argp_->has_arg("C")) {
438 if (argp_->num_items() == 0) {
439 print_usage();
440 printf("\nFile name missing\n\n");
441 exit(1);
442 } else {
443 file_ = argp_->items()[0];
444 }
445
446 if (id == NULL) {
447 print_usage();
448 printf("\nNo Image/LUT ID given, needed for -i/-c/-C\n\n");
449 exit(2);
450 }
451 }
452
453 if (!argp_->has_arg("e")) {
454 client_ = new FuseClient(host, port_num, this);
455 client_->connect();
456 client_->start();
457 client_->wait_greeting();
458 }
459
460 if (argp_->has_arg("i")) {
461 get_image(id, /* JPEG? */ false);
462 } else if (argp_->has_arg("j")) {
463 get_image(id, /* JPEG? */ true);
464 } else if (argp_->has_arg("c")) {
465 get_colormap(id);
466 } else if (argp_->has_arg("C")) {
467 set_colormap(id);
468 } else if (argp_->has_arg("s")) {
469 show_all();
470 } else if (argp_->has_arg("e")) {
472 } else {
473 print_usage();
474 client_->cancel();
475 }
476
477 if (!argp_->has_arg("e")) {
478 client_->join();
479 delete client_;
480 }
481
482 free(net_string);
483 }
484 }
485
486private:
487 ArgumentParser *argp_;
488 FuseClient * client_;
489
490 const char *file_;
491
492 bool exploring_;
493 Mutex * explore_mutex_;
494 WaitCondition *explore_waitcond_;
495
496#ifdef HAVE_AVAHI
497 AvahiThread *avahi_thread_;
498#endif
499};
500
501int
502main(int argc, char **argv)
503{
504 ArgumentParser argp(argc, argv, "hn:icCsej");
505
506 FireVisionNetworkTool *nettool = new FireVisionNetworkTool(&argp);
507 nettool->run();
508 delete nettool;
509
510 return 0;
511}
FireVision Network Tool.
Definition: net.cpp:58
virtual void all_for_now()
All results have been retrieved.
Definition: net.cpp:230
virtual void fuse_connection_died() noexcept
Connection died.
Definition: net.cpp:82
void get_colormap(const char *lut_id)
Request LUT.
Definition: net.cpp:329
void explore_network()
Explore network.
Definition: net.cpp:371
void run()
Run.
Definition: net.cpp:400
virtual void fuse_inbound_received(FuseNetworkMessage *m) noexcept
Message received.
Definition: net.cpp:87
virtual void service_added(const char *name, const char *type, const char *domain, const char *host_name, const char *interface, const struct sockaddr *addr, const socklen_t addr_size, uint16_t port, std::list< std::string > &txt, int flags)
A service has been announced on the network.
Definition: net.cpp:250
virtual void service_removed(const char *name, const char *type, const char *domain)
A service has been removed from the network.
Definition: net.cpp:286
FireVisionNetworkTool(ArgumentParser *argp)
Constructor.
Definition: net.cpp:63
virtual void fuse_connection_established() noexcept
Connection has been established.
Definition: net.cpp:77
void print_usage()
Print usage message.
Definition: net.cpp:292
void get_image(const char *image_id, bool jpeg)
Request image.
Definition: net.cpp:315
void show_all()
Show all images and LUTs.
Definition: net.cpp:359
void set_colormap(const char *lut_id)
Upload LUT.
Definition: net.cpp:341
virtual void cache_exhausted()
Cache exhausted.
Definition: net.cpp:239
virtual void browse_failed(const char *name, const char *type, const char *domain)
Failed to browse for a given service.
Definition: net.cpp:244
void fuse_invalid_server_version(uint32_t local_version, uint32_t remote_version) noexcept
Invalid version string received.
Definition: net.cpp:71
Parse command line arguments.
Definition: argparser.h:64
const char * program_name() const
Get name of program.
Definition: argparser.cpp:483
const std::vector< const char * > & items() const
Get non-option items.
Definition: argparser.cpp:447
const char * arg(const char *argn)
Get argument value.
Definition: argparser.cpp:177
std::vector< constchar * >::size_type num_items() const
Get number of non-option items.
Definition: argparser.cpp:456
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:165
Avahi main thread.
Definition: avahi_thread.h:55
Base class for exceptions in Fawkes.
Definition: exception.h:36
void print_trace() noexcept
Prints trace to stderr.
Definition: exception.cpp:601
void append(const char *format,...) noexcept
Append messages to the message list.
Definition: exception.cpp:333
Mutex mutual exclusion lock.
Definition: mutex.h:33
void lock()
Lock this mutex.
Definition: mutex.cpp:87
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
Index out of bounds.
Definition: software.h:86
Interface for class that process browse results.
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:499
void join()
Join the thread.
Definition: thread.cpp:597
void cancel()
Cancel a thread.
Definition: thread.cpp:646
Wait until a given condition holds.
void wait()
Wait for the condition forever.
void wake_all()
Wake up all waiting threads.
Colormap file.
Definition: cmfile.h:55
Colormap * get_colormap()
Get a freshly generated colormap based on current file content.
Definition: cmfile.cpp:164
void add_colormap(Colormap *colormap)
Add colormap.
Definition: cmfile.cpp:89
Colormap interface.
Definition: colormap.h:37
virtual unsigned int depth() const =0
Get depth of colormap.
virtual unsigned char * get_buffer() const =0
Get the raw buffer of this colormap.
virtual unsigned int height() const =0
Get height of colormap.
virtual unsigned int width() const =0
Get width of colormap.
virtual void read(const char *file_name)
Read file.
Definition: fvfile.cpp:290
virtual void write(const char *file_name)
Write file.
Definition: fvfile.cpp:243
void wait_greeting()
Wait for greeting message.
void enqueue(FuseNetworkMessage *m)
Enqueue message.
void connect()
Connect.
unsigned int format() const
Get image format.
size_t buffer_size() const
Get size of buffer.
unsigned int colorspace() const
Get colorspace.
unsigned char * buffer() const
Image buffer.
unsigned int pixel_height() const
Get image height.
unsigned int pixel_width() const
Get image width.
bool has_next()
Check if another image info is available.
FUSE_imageinfo_t * next()
Get next image info.
FUSE lookup table content.
unsigned char * buffer() const
Get buffer.
unsigned int height() const
Height of LUT.
unsigned int depth() const
Depth of LUT.
unsigned int width() const
Width of LUT.
FUSE lookup table list content.
bool has_next()
Check if another LUT info is available.
FUSE_lutinfo_t * next()
Get next LUT info.
FUSE Network Message.
Definition: fuse_message.h:40
FvRaw Writer implementation.
Definition: fvraw.h:32
virtual void write()
Write to file.
Definition: fvraw.cpp:118
YUV Colormap.
Definition: yuvcm.h:36
virtual void set(unsigned int y, unsigned int u, unsigned int v, color_t c)
Set color class for given YUV value.
Definition: yuvcm.cpp:194
Fawkes library namespace.
Image info message.
Definition: fuse.h:168
uint32_t colorspace
color space
Definition: fuse.h:170
uint32_t height
height in pixels
Definition: fuse.h:173
uint32_t width
width in pixels
Definition: fuse.h:172
char image_id[IMAGE_ID_MAX_LENGTH]
image ID
Definition: fuse.h:169
Image request message.
Definition: fuse.h:148
char image_id[IMAGE_ID_MAX_LENGTH]
image ID
Definition: fuse.h:149
uint32_t format
requested image format, see FUSE_image_format_t
Definition: fuse.h:150
LUT description message.
Definition: fuse.h:162
char lut_id[LUT_ID_MAX_LENGTH]
LUT ID.
Definition: fuse.h:163
LUT info message.
Definition: fuse.h:179
uint32_t height
height of LUT
Definition: fuse.h:182
uint32_t bytes_per_cell
bytes per cell
Definition: fuse.h:184
uint32_t width
width of LUT
Definition: fuse.h:181
uint32_t depth
depth of LUT
Definition: fuse.h:183
char lut_id[LUT_ID_MAX_LENGTH]
LUT ID.
Definition: fuse.h:180