00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <fvutils/net/fuse.h>
00024 #include <fvutils/net/fuse_client.h>
00025 #include <fvutils/net/fuse_client_handler.h>
00026 #include <fvutils/net/fuse_message.h>
00027 #include <fvutils/net/fuse_image_content.h>
00028 #include <fvutils/net/fuse_lut_content.h>
00029 #include <fvutils/net/fuse_imagelist_content.h>
00030 #include <fvutils/net/fuse_lutlist_content.h>
00031 #include <fvutils/writers/fvraw.h>
00032 #include <fvutils/color/colorspaces.h>
00033 #include <fvutils/colormap/yuvcm.h>
00034 #include <fvutils/colormap/cmfile.h>
00035
00036 #include <core/threading/mutex.h>
00037 #include <core/threading/wait_condition.h>
00038 #include <core/exceptions/software.h>
00039 #include <utils/system/argparser.h>
00040 #include <utils/system/console_colors.h>
00041
00042 #include <netcomm/service_discovery/browse_handler.h>
00043 #ifdef HAVE_AVAHI
00044 #include <netcomm/dns-sd/avahi_thread.h>
00045 #endif
00046
00047
00048 #include <arpa/inet.h>
00049 #include <netinet/in.h>
00050 #include <cstring>
00051 #include <cstdlib>
00052 #include <cstdio>
00053
00054 using namespace fawkes;
00055
00056
00057 class FireVisionNetworkTool
00058 : public FuseClientHandler,
00059 public ServiceBrowseHandler
00060 {
00061 public:
00062
00063
00064
00065 FireVisionNetworkTool(ArgumentParser *argp)
00066 {
00067 __argp = argp;
00068 __exploring = false;
00069 __explore_waitcond = NULL;
00070 }
00071
00072 void
00073 fuse_invalid_server_version(uint32_t local_version,
00074 uint32_t remote_version) throw()
00075 {
00076 printf("Invalid version received (local: %u, remote: %u)\n",
00077 local_version, remote_version);
00078 }
00079
00080 virtual void
00081 fuse_connection_established() throw()
00082 {
00083 }
00084
00085 virtual void
00086 fuse_connection_died() throw()
00087 {
00088 }
00089
00090 virtual void
00091 fuse_inbound_received(FuseNetworkMessage *m) throw()
00092 {
00093
00094
00095 switch (m->type() ) {
00096 case FUSE_MT_IMAGE:
00097
00098 try {
00099 FuseImageContent *ic = m->msgc<FuseImageContent>();
00100 if ( ic->format() == FUSE_IF_RAW ) {
00101 FvRawWriter *w = new FvRawWriter(__file, ic->pixel_width(), ic->pixel_height(),
00102 (colorspace_t)ic->colorspace(), ic->buffer());
00103 w->write();
00104 delete w;
00105 } else if ( ic->format() == FUSE_IF_JPEG ) {
00106 FILE *f = fopen(__file, "w");
00107 if (fwrite(ic->buffer(), ic->buffer_size(), 1, f) == 0) {
00108 printf("Failed to write data to file");
00109 }
00110 fclose(f);
00111 } else {
00112 printf("Image of unknown format (%u) received.\n", ic->format());
00113 }
00114 delete ic;
00115 } catch (Exception &e) {
00116 printf("Received message cannot be casted to FuseImageMessage\n");
00117 e.print_trace();
00118 }
00119 __client->cancel();
00120 break;
00121 case FUSE_MT_IMAGE_LIST:
00122 try {
00123 FuseImageListContent *ilc = m->msgc<FuseImageListContent>();
00124 if ( ilc->has_next() ) {
00125 printf("Available images:\n");
00126 while ( ilc->has_next() ) {
00127 FUSE_imageinfo_t *ii = ilc->next();
00128 char tmp[IMAGE_ID_MAX_LENGTH + 1];
00129 tmp[IMAGE_ID_MAX_LENGTH] = 0;
00130 strncpy(tmp, ii->image_id, IMAGE_ID_MAX_LENGTH);
00131 printf(" %s (%u x %u, %s)\n", tmp, ntohl(ii->width), ntohl(ii->height),
00132 colorspace_to_string((colorspace_t)ntohs(ii->colorspace)));
00133 }
00134 } else {
00135 printf("No images available\n");
00136 }
00137 delete ilc;
00138 } catch (Exception &e) {
00139 printf("Received message cannot be casted to FuseImageListMessage\n");
00140 e.print_trace();
00141 }
00142 break;
00143 case FUSE_MT_LUT_LIST:
00144 try {
00145 FuseLutListContent *llc = m->msgc<FuseLutListContent>();
00146 if ( llc->has_next() ) {
00147 printf("Available lookup tables:\n");
00148 while ( llc->has_next() ) {
00149 FUSE_lutinfo_t *li = llc->next();
00150 char tmp[LUT_ID_MAX_LENGTH + 1];
00151 tmp[LUT_ID_MAX_LENGTH] = 0;
00152 strncpy(tmp, li->lut_id, LUT_ID_MAX_LENGTH);
00153 printf(" %s (%u x %u x %u, %u bpc)\n", tmp,
00154 ntohl(li->width), ntohl(li->height),
00155 ntohl(li->depth), ntohl(li->bytes_per_cell));
00156 }
00157 } else {
00158 printf("No lookup tables available\n");
00159 }
00160 delete llc;
00161 } catch (Exception &e) {
00162 printf("Received message cannot be casted to FuseImageListMessage\n");
00163 e.print_trace();
00164 }
00165 __client->cancel();
00166 break;
00167
00168 case FUSE_MT_LUT:
00169
00170 try {
00171 FuseLutContent *lc = m->msgc<FuseLutContent>();
00172
00173 if ( lc->width() != 256 ) {
00174 printf("Invalid dimensions for LUT received, colormap width %u != 256", lc->width());
00175 } else if ( lc->height() != 256 ) {
00176 printf("Invalid dimensions for LUT received, colormap height %u != 256", lc->height());
00177 } else if ( lc->depth() > 256 ) {
00178 printf("Invalid dimensions for LUT received, colormap depth %u > 256", lc->depth());
00179 } else {
00180 try {
00181 YuvColormap yuvcm(lc->depth());
00182 yuvcm.set(lc->buffer());
00183 ColormapFile cmf;
00184 cmf.add_colormap(&yuvcm);
00185 cmf.write(__file);
00186 } catch (Exception &e) {
00187 e.append("Failed to save colormap");
00188 e.print_trace();
00189 }
00190 }
00191 delete lc;
00192 } catch (Exception &e) {
00193 printf("Received message cannot be casted to FuseLutMessage\n");
00194 e.print_trace();
00195 }
00196 __client->cancel();
00197 break;
00198
00199 case FUSE_MT_SET_LUT_SUCCEEDED:
00200 {
00201 FUSE_lutdesc_message_t *lutdesc = m->msg<FUSE_lutdesc_message_t>();
00202 char lut_id[LUT_ID_MAX_LENGTH + 1];
00203 lut_id[LUT_ID_MAX_LENGTH] = 0;
00204 strncpy(lut_id, lutdesc->lut_id, LUT_ID_MAX_LENGTH);
00205 printf("LUT %s has been uploaded successfully.\n", lut_id);
00206 __client->cancel();
00207 }
00208 break;
00209
00210 case FUSE_MT_SET_LUT_FAILED:
00211 {
00212 FUSE_lutdesc_message_t *lutdesc = m->msg<FUSE_lutdesc_message_t>();
00213 char lut_id[LUT_ID_MAX_LENGTH + 1];
00214 lut_id[LUT_ID_MAX_LENGTH] = 0;
00215 strncpy(lut_id, lutdesc->lut_id, LUT_ID_MAX_LENGTH);
00216 printf("LUT upload of %s has failed.\n", lut_id);
00217 __client->cancel();
00218 }
00219 break;
00220
00221 default:
00222 printf("Unhandled message of type %u received\n", m->type());
00223 __client->cancel();
00224 break;
00225 }
00226 }
00227
00228
00229 virtual void all_for_now()
00230 {
00231 printf("All for now\n");
00232 __explore_mutex->lock();
00233 __explore_waitcond->wake_all();
00234 __explore_mutex->unlock();
00235 }
00236
00237 virtual void cache_exhausted()
00238 {
00239 }
00240
00241 virtual void browse_failed(const char *name,
00242 const char *type,
00243 const char *domain)
00244 {
00245 printf("Browsing for %s failed\n", type);
00246 }
00247
00248 virtual void service_added(const char *name,
00249 const char *type,
00250 const char *domain,
00251 const char *host_name,
00252 const struct sockaddr *addr,
00253 const socklen_t addr_size,
00254 uint16_t port,
00255 std::list<std::string> &txt,
00256 int flags
00257 )
00258 {
00259 struct sockaddr_in *s;
00260 if ( addr_size == sizeof(struct sockaddr_in) ) {
00261 s = (struct sockaddr_in *)addr;
00262 } else {
00263 printf("%s socket data not IPv4, ignoring\n", name);
00264 return;
00265 }
00266
00267 char addrp[INET_ADDRSTRLEN];
00268 inet_ntop(AF_INET, &(s->sin_addr), addrp, sizeof(addrp));
00269 printf("Found %s%s%s (%s/%s on %hu), querying\n",
00270 c_blue, name, c_normal, host_name, addrp, port);
00271
00272 __client = new FuseClient(host_name, port, this);
00273 __client->connect();
00274 __client->start();
00275 __client->wait_greeting();
00276 show_all();
00277 __client->join();
00278 delete __client;
00279
00280 printf("\n");
00281 }
00282
00283 virtual void service_removed(const char *name,
00284 const char *type,
00285 const char *domain)
00286 {
00287 }
00288
00289
00290 void
00291 print_usage()
00292 {
00293 printf("Usage: %s -i/-l/-L/-s -n host[:port]/id file\n"
00294 " -i Get image\n"
00295 " -j Get JPEG-compressed image\n"
00296 " -c Get colormap\n"
00297 " -C Set colormap from file\n"
00298 " -s Show available images and LUTs\n"
00299 " -e Explore network. Will query all instances of Fountain\n"
00300 " found on the network for all available images and LUTs.\n"
00301 " -n net_string Open network camera, the camera string is of the form\n"
00302 " host[:port]/id. You have to specify at least the host\n"
00303 " and the id, the port is optional and defaults to 5000\n"
00304 " Depending on the operation id is the image or the LUT ID\n"
00305 " file File to write incoming data to or to read data to send from\n",
00306 __argp->program_name());
00307 }
00308
00309
00310
00311
00312
00313
00314 void
00315 get_image(const char *image_id, bool jpeg)
00316 {
00317 FUSE_imagereq_message_t *idm = (FUSE_imagereq_message_t *)malloc(sizeof(FUSE_imagereq_message_t));
00318 memset(idm, 0, sizeof(FUSE_imagereq_message_t));
00319 strncpy(idm->image_id, image_id, IMAGE_ID_MAX_LENGTH);
00320 idm->format = (jpeg ? FUSE_IF_JPEG : FUSE_IF_RAW);
00321 __client->enqueue(FUSE_MT_GET_IMAGE, idm, sizeof(FUSE_imagereq_message_t));
00322 }
00323
00324
00325
00326
00327 void
00328 get_colormap(const char *lut_id)
00329 {
00330 FUSE_lutdesc_message_t *ldm = (FUSE_lutdesc_message_t *)malloc(sizeof(FUSE_lutdesc_message_t));
00331 memset(ldm, 0, sizeof(FUSE_lutdesc_message_t));
00332 strncpy(ldm->lut_id, lut_id, LUT_ID_MAX_LENGTH);
00333 __client->enqueue(FUSE_MT_GET_LUT, ldm, sizeof(FUSE_lutdesc_message_t));
00334 }
00335
00336
00337
00338
00339 void
00340 set_colormap(const char *lut_id)
00341 {
00342 ColormapFile cmf;
00343 cmf.read(__file);
00344 Colormap *cm = cmf.get_colormap();
00345 FuseLutContent *lc = new FuseLutContent(lut_id, cm->get_buffer(),
00346 cm->width(), cm->height(), cm->depth(),
00347 1);
00348 delete cm;
00349
00350 __client->enqueue(new FuseNetworkMessage(FUSE_MT_SET_LUT, lc));
00351 }
00352
00353
00354 void
00355 show_all()
00356 {
00357 __client->enqueue(FUSE_MT_GET_IMAGE_LIST);
00358 __client->enqueue(FUSE_MT_GET_LUT_LIST);
00359 }
00360
00361
00362
00363
00364
00365
00366 void
00367 explore_network()
00368 {
00369 #ifdef HAVE_AVAHI
00370 __exploring = true;
00371 __explore_mutex = new Mutex();
00372 __explore_waitcond = new WaitCondition(__explore_mutex);
00373
00374 __explore_mutex->lock();
00375
00376 __avahi_thread = new AvahiThread();
00377 __avahi_thread->start();
00378
00379 __avahi_thread->watch_service("_fountain._tcp", this);
00380
00381 __explore_waitcond->wait();
00382 delete __explore_waitcond;
00383 __explore_mutex->unlock();
00384 delete __explore_mutex;
00385 __avahi_thread->cancel();
00386 __avahi_thread->join();
00387 delete __avahi_thread;
00388 #else
00389 printf("\nExploration is not available because Avahi support is missing. "
00390 "Install avahi-devel and recompile.\n\n");
00391 #endif
00392 }
00393
00394
00395 void
00396 run()
00397 {
00398 if ( __argp->has_arg("h") ) {
00399 print_usage();
00400 exit(0);
00401 } else {
00402 char *net_string;
00403 if ( __argp->has_arg("n") ) {
00404 net_string = strdup(__argp->arg("n"));
00405 } else {
00406 net_string = strdup("localhost");
00407 }
00408 char *id = NULL, *host = NULL, *port = NULL, *save_ptr = NULL;
00409 int port_num = 2208;
00410 char *hostport;
00411
00412 hostport = strtok_r(net_string, "/", &save_ptr);
00413 id = strtok_r(NULL, "", &save_ptr);
00414
00415 if ( strchr(hostport, ':') != NULL ) {
00416 host = strtok_r(hostport, ":", &save_ptr);
00417 port = strtok_r(NULL, "", &save_ptr);
00418 } else {
00419 host = hostport;
00420 }
00421
00422 if ( port != NULL ) {
00423 port_num = atoi(port);
00424 if ( (port_num < 0) || (port_num > 0xFFFF) ) {
00425 throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
00426 }
00427 }
00428
00429 if (__argp->has_arg("i") || __argp->has_arg("j") ||
00430 __argp->has_arg("c") || __argp->has_arg("C")) {
00431 if ( __argp->num_items() == 0 ) {
00432 print_usage();
00433 printf("\nFile name missing\n\n");
00434 exit(1);
00435 } else {
00436 __file = __argp->items()[0];
00437 }
00438
00439 if (id == NULL) {
00440 print_usage();
00441 printf("\nNo Image/LUT ID given, needed for -i/-c/-C\n\n");
00442 exit(2);
00443 }
00444 }
00445
00446 if ( ! __argp->has_arg("e") ) {
00447 __client = new FuseClient(host, port_num, this);
00448 __client->connect();
00449 __client->start();
00450 __client->wait_greeting();
00451 }
00452
00453 if ( __argp->has_arg("i") ) {
00454 get_image(id, false);
00455 } else if ( __argp->has_arg("j") ) {
00456 get_image(id, true);
00457 } else if ( __argp->has_arg("c") ) {
00458 get_colormap(id);
00459 } else if ( __argp->has_arg("C") ) {
00460 set_colormap(id);
00461 } else if ( __argp->has_arg("s") ) {
00462 show_all();
00463 } else if ( __argp->has_arg("e") ) {
00464 explore_network();
00465 } else {
00466 print_usage();
00467 __client->cancel();
00468 }
00469
00470 if ( ! __argp->has_arg("e") ) {
00471 __client->join();
00472 delete __client;
00473 }
00474
00475 free(net_string);
00476 }
00477 }
00478
00479 private:
00480 ArgumentParser *__argp;
00481 FuseClient *__client;
00482
00483 const char *__file;
00484
00485 bool __exploring;
00486 Mutex *__explore_mutex;
00487 WaitCondition *__explore_waitcond;
00488
00489 #ifdef HAVE_AVAHI
00490 AvahiThread *__avahi_thread;
00491 #endif
00492 };
00493
00494
00495 int
00496 main(int argc, char **argv)
00497 {
00498 ArgumentParser argp(argc, argv, "hn:icCsej");
00499
00500 FireVisionNetworkTool *nettool = new FireVisionNetworkTool(&argp);
00501 nettool->run();
00502 delete nettool;
00503
00504 return 0;
00505 }