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 
53 using namespace fawkes;
54 using namespace firevision;
55 
56 /** FireVision Network Tool */
58 {
59 public:
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) throw()
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 {
122  FuseImageListContent *ilc = m->msgc<FuseImageListContent>();
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: {
205  FUSE_lutdesc_message_t *lutdesc = m->msg<FUSE_lutdesc_message_t>();
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: {
214  FUSE_lutdesc_message_t *lutdesc = m->msg<FUSE_lutdesc_message_t>();
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
400  run()
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")) {
471  explore_network();
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 
486 private:
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 
501 int
502 main(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()
Connection died.
Definition: net.cpp:82
virtual void fuse_inbound_received(FuseNetworkMessage *m)
Message received.
Definition: net.cpp:87
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_connection_established()
Connection has been established.
Definition: net.cpp:77
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
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
void fuse_invalid_server_version(uint32_t local_version, uint32_t remote_version)
Invalid version string received.
Definition: net.cpp:71
virtual void browse_failed(const char *name, const char *type, const char *domain)
Failed to browse for a given service.
Definition: net.cpp:244
Parse command line arguments.
Definition: argparser.h:64
Avahi main thread.
Definition: avahi_thread.h:55
Base class for exceptions in Fawkes.
Definition: exception.h:36
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:601
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:333
Mutex mutual exclusion lock.
Definition: mutex.h:33
Index out of bounds.
Definition: software.h:86
Interface for class that process browse results.
Wait until a given condition holds.
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
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.
static const char * c_normal
Print normal on console, without colors, depends on console settings.
static const char * c_blue
Print blue on console.
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