Jpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Classes | Functions | Variables
clb_swiss_knife.cpp File Reference
#include <iostream>
#include <stdint.h>
#include <stddef.h>
#include <string>
#include <stdexcept>
#include <fstream>
#include <ctime>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <boost/asio.hpp>
#include <boost/program_options.hpp>
#include <sys/ioctl.h>
#include "structs.hpp"
#include "datatypes.hpp"
#include "version.hpp"
#include "ligier_helper.hpp"
#include "consumers.hpp"
#include "dom_map.hpp"

Go to the source code of this file.

Classes

class  LigierDataHandler< Consumer >
 
class  UdpDataHandler< Consumer >
 

Functions

int get_terminal_width ()
 Program name: CLBSwissKnife. More...
 
void handle_signal (boost::asio::signal_set &set, int &terminal_width, boost::system::error_code const &error, int signum)
 
boost::asio::ip::tcp::endpoint make_endpoint (std::string const &address)
 
int main (int argc, char *argv[])
 

Variables

static const size_t buffer_size = 10000
 
static const unsigned int default_opto_port = 56015
 
static const unsigned int default_acou_port = 56016
 
static const unsigned int default_moni_port = 56017
 

Function Documentation

int get_terminal_width ( )

Program name: CLBSwissKnife.

General description: This program aims to provide a powerful debugging tool for all the kind of data sent by a KM3NeT DOM.

It listens to the specified UDP port and prints out to the screen some informations contained in the read CLB datagrams.

Since version 5.0, it operates in two main modes:

  • in UDP mode (available since the first release), the program reads data directly from a UDP port. In this mode it is allowed to perform several tasks, such as read all kind of data, dump data on file and send monitoring data to a RoyWeb server;
  • in Ligier mode, data are retrieved from a Ligier subscription. Only monitoring data are available and no secondary tasks are allowed.

General options: The program is configured via command line parameters. UDP mode is default and can be forced with the -u/–udp command line switch. Ligier mode can be activated with the -l/–ligier switch.

In the systems where the ncurses libraries are present, is possible to use the -g/–gui option to display multiple DOMs data via a text gui, in conjunction of the UDP-mode "-m/--monitoring" option or in the Ligier mode. Press the 'h' key to see the help for GUI mode. Arroy keys can be used to select a dom and to scroll the list.

With the "--map" option the user can specify a map file to be used to match the DOM IDs of incoming data. The DOM map file is an ASCII file reporting assignments of DOM IDs or MAC addresses with names. Each assignment must be separated by a semicolon. An example of map file follows:

08:00:30:BE:B7:A2 = CLB19; 817805038 = CLB13;

By default, CLBSwissKnife will try to load the file

~/.doms.csk

as a map file. The user can write the information about its setup to this file and let CLBSK use it without specifying any "--map" option.

Use: $ CLBSwissKnife -h for a detailed help and $ CLBSwissKnife -v for version information.

UDP-mode options: The user can specify the port to bind and/or the data type:

  • if the port is specified using the "-p" or "--port" options the type is automatically determined as data comes;
  • if the port is specified using one of the other options ("-o/--optical", "-a/--acoustic", "-m/--monitoring"), the program is forced to parse the incoming data with the specified data type; with these options it is not mandatory to specify a port number, since a default value is pre-defined.

With the "-f/--dump-file" option is also possible to specify a destination file in which the incoming data will be stored for offline analysis.

In the monitoring-mode, with the "-r/--royweb" option it is possible to send the hit rates to a ROyWeb server. This option accept 3 parameters separated by a colon character (":"), which are:

  • the format of the name of the ROy parameter; the format string allows the use of the following place-holders:
    • "%d": DOM ID
    • "%n": DOM name as in the map file (see below); if not present the DOM ID is used.
    • "%c": channel ID (0-30)
  • the ROyWeb server address
  • the ROyWeb server port

Es: CLBSwissKnife -m -r HitRates-DOMd-CHc:localhost:9999

A default HR_n.c:localhost:9999 is used, otherwise all three parameters must be set at once.

Moreover, the time difference between two consecutive monitoring packets is sent to the ROy server with the tag "Time_difference". This is useful in order to highlight possible packet losses when a single CLB is used.

Ligier-mode options: The Ligier mode allows the user to monitor CLB data using a Ligier connection. To be activated a "-l/--ligier" flag must be present in the command line.

Ligier endpoint can be set with "-s/--server", while the tag can be set with the "-t/--tag". Proper default values are available and are listed in the on-line help.

E-mail: carme.nosp@m.lo.p.nosp@m.elleg.nosp@m.rino.nosp@m.@bo.i.nosp@m.nfn..nosp@m.it Date: 27 October 2014

Author
Carmelo Pellegrino

Definition at line 151 of file clb_swiss_knife.cpp.

152 {
153  static bool const is_a_tty = isatty(1);
154 
155  if (!is_a_tty) {
156  return 80;
157  } else {
158  struct winsize sz;
159 
160  ioctl(1, TIOCGWINSZ, &sz);
161  return sz.ws_col;
162  }
163 }
void handle_signal ( boost::asio::signal_set &  set,
int &  terminal_width,
boost::system::error_code const &  error,
int  signum 
)

Definition at line 930 of file clb_swiss_knife.cpp.

936 {
937  if (!error) {
938  if (signum == SIGINT) {
939  set.get_io_service().stop();
940  if (isatty(1)) {
941  std::cout << "\033]2;thank you for flying with CLBSwissKnife!\007";
942  std::cout << "\rBye bye!\n";
943  }
944  return;
945  } else if (signum == SIGWINCH) {
947  }
948 
949  set.async_wait(
950  boost::bind(
952  boost::ref(set),
953  boost::ref(terminal_width),
954  boost::asio::placeholders::error,
955  boost::asio::placeholders::signal_number
956  )
957  );
958  }
959 }
static int terminal_width
Definition: daq_parser.cpp:21
void handle_signal(boost::asio::signal_set &set, int &terminal_width, boost::system::error_code const &error, int signum)
int get_terminal_width()
Program name: CLBSwissKnife.
boost::asio::ip::tcp::endpoint make_endpoint ( std::string const &  address)
inline
Author
cpellegrino

Definition at line 424 of file clb_swiss_knife.cpp.

426  {
427  boost::asio::io_service service;
428  boost::asio::ip::tcp::resolver resolver(service);
429 
430  std::string::size_type const pos = address.find(":");
431 
432  std::string const host = pos == std::string::npos ? address : address.substr(0, pos);
433  std::string const port = pos == std::string::npos ? "5553" : address.substr(pos + 1);
434 
435  boost::asio::ip::tcp::resolver::query query(
436  boost::asio::ip::tcp::v4()
437  , host
438  , port
439  );
440 
441  return *resolver.resolve(query);
442 }
int main ( int  argc,
char *  argv[] 
)

Definition at line 444 of file clb_swiss_knife.cpp.

445 {
446  bool dump = false;
447  uint32_t type = unkn;
448  bool uses_roy = false;
449  bool use_gui = false;
450  bool lm_mode = false;
451 
452  std::string dom_names = std::getenv("HOME") + std::string("/.doms.csk");
453  dom_map_type dom_names_map;
454 
455  std::ofstream output_file;
456 
457  unsigned int port = 0;
458 
459  std::string filename;
460  std::string roy_setup;
461 
462  std::string lserver = "localhost:5553";
463  std::string tag;
464  boost::asio::ip::tcp::endpoint endpoint;
465 
466  po::options_description desc("Generic options");
467  desc.add_options()
468  ("help,h", "Print this help and exit.")
469  ("version,v", "Print the version and exit.")
470  (
471  "map"
472  , po::value<std::string>(&dom_names)->value_name("filename")
473  , "File that specifies a conversion from DOM IDs to a human readable name."
474  )
475 #ifdef CURSES_FOUND
476  ("gui,g", "Use GUI (avalilable in UDP-monitoring and Ligier modes only).")
477 #endif
478  ("ligier,l", "Set Ligier mode.")
479  ("udp,u", "Force UDP mode (default).");
480 
481  po::options_description lmdesc("Ligier-mode options");
482  lmdesc.add_options()
483  (
484  "server,s"
485  , po::value<std::string>(&lserver)
486  ->default_value("localhost:5553")
487  ->value_name("server:[port]")
488  , "Set the Ligier server endpoint to read data from."
489  )
490  (
491  "tag,t"
492  , po::value<std::string>(&tag)
493  ->default_value("IO_MONIT")
494  ->value_name("tag")
495  , "Set the Ligier tag to read data from."
496  );
497 
498  po::options_description umdesc("UDP-mode options");
499  umdesc.add_options()
500  ("optical,o",
501  po::value<unsigned int>(&port)
502  ->implicit_value(default_opto_port)
503  ->value_name("port"),
504  "Set the expected data type to optical. If a port is not \
505 provided the default one is used (56015).")
506  ("acoustic,a",
507  po::value<unsigned int>(&port)
508  ->implicit_value(default_acou_port)
509  ->value_name("port"),
510  "Set the expected data type to acoustic. If a port is not \
511 provided the default one is used (56016).")
512  ("monitoring,m",
513  po::value<unsigned int>(&port)
514  ->implicit_value(default_moni_port)
515  ->value_name("port"),
516  "Set the expected data type to monitoring. If a port is \
517 not provided the default one is used (56017).")
518  ("port,p",
519  po::value<unsigned int>(&port)->value_name("port"),
520  "Listen on the specified port, automatically determining the \
521 data type.")
522  ("dumpfile,f",
523  po::value<std::string>(&filename)->value_name("filename"),
524  "Dumps the acquired data to a file.")
525  ("royweb,r",
526  po::value<std::string>(&roy_setup)
527  ->implicit_value("HR_%n.%c:localhost:9999")
528  ->value_name("format:host:port"),
529  "Send the monitoring hit rates to the specified ROyWeb \
530 server. The syntax is format:server_ip:server_port. \
531 The format parameter can contain the following placeholders: %d for \
532 DOM ID, %n for DOM name (if available, otherwise the DOM ID is used) \
533 and %c for channel ID.");
534 
535  std::string templ;
536  std::string roy_server;
537  int roy_port = 0;
538 
539  try {
540  po::options_description global;
541  global.add(desc).add(lmdesc).add(umdesc);
542 
543  po::variables_map vm;
544  po::store(
545  po::command_line_parser(argc, argv).options(global).run()
546  , vm
547  );
548 
549  if (vm.count("help")) {
550  std::cout
551  << desc << '\n'
552  << umdesc << '\n'
553  << lmdesc << '\n';
554  return EXIT_SUCCESS;
555  }
556 
557  if (vm.count("version")) {
558  std::cout << clbsk::version::v() << std::endl;
559  return EXIT_SUCCESS;
560  }
561 
562  po::notify(vm);
563 
564 #ifdef CURSES_FOUND
565  use_gui = vm.count("gui");
566 #endif
567 
568  lm_mode = vm.count("ligier");
569 
570  if (lm_mode && vm.count("udp")) {
571  throw std::runtime_error("You can specify only one mode. Both provided.");
572  }
573 
574  if (vm.count("map")) {
575  std::ifstream map(dom_names.c_str());
576 
577  if (! map) {
578  throw std::runtime_error(
579  std::string("Error reading map file: ")
580  + std::strerror(errno)
581  );
582  }
583 
584  dom_names_map = load_dom_map(map);
585  } else {
586  std::ifstream map(dom_names.c_str());
587 
588  dom_names_map = load_dom_map(map);
589  }
590 
591  if (lm_mode) {
592  po::variables_map vm;
593  po::options_description options;
594  options.add(lmdesc).add(desc);
595 
596  po::store(
597  po::command_line_parser(argc, argv).options(options).run()
598  , vm
599  );
600 
601  po::notify(vm);
602 
603  endpoint = make_endpoint(lserver);
604 
605  type = tmch;
606  } else {
607  po::variables_map vm;
608  po::options_description options;
609  options.add(desc).add(umdesc);
610 
611  po::store(
612  po::command_line_parser(argc, argv).options(options).run()
613  , vm
614  );
615 
616  po::notify(vm);
617 
618  unsigned int counter = 0;
619  if (vm.count("port")) {
620  type = unkn;
621  ++counter;
622  }
623  if (vm.count("optical")) {
624  type = ttdc;
625  ++counter;
626  }
627  if (vm.count("acoustic")) {
628  type = taes;
629  ++counter;
630  }
631  if (vm.count("monitoring")) {
632  type = tmch;
633  ++counter;
634  }
635 
636  if (counter != 1) {
637  if (counter) {
638  throw std::runtime_error("More than one port provided.");
639  } else {
640  throw std::runtime_error("You must specify at least one port.");
641  }
642  }
643 
644  if (use_gui && type != tmch) {
645  throw std::runtime_error("GUI is only available in monitoring mode");
646  }
647 
648  if (vm.count("royweb")) {
649  if (type != tmch) {
650  throw std::runtime_error("you can use ROyWeb only with the"
651  " monitoring channel");
652  }
653 
654  uses_roy = true;
655  std::replace(roy_setup.begin(), roy_setup.end(), ':', ' ');
656  std::istringstream ss(roy_setup);
657  int param_count = 0;
658  if (ss >> templ) {
659  ++param_count;
660  }
661  if (ss >> roy_server) {
662  ++param_count;
663  }
664  if (ss >> roy_port) {
665  ++param_count;
666  }
667 
668  if (param_count != 3) {
669  throw std::runtime_error("you must specify all the parameters"
670  " or accept all the default one to use with ROyWeb.");
671  }
672  }
673 
674  if (vm.count("dumpfile")) {
675  output_file.open(filename.c_str(), std::ios::binary);
676  if (! output_file) {
677  throw std::runtime_error(
678  "Unable to open file "
679  + filename
680  + " for writing: "
681  + strerror(errno)
682  );
683  }
684  dump = true;
685  }
686  }
687  } catch (const po::error& e) {
688  std::cerr
689  << "CLBSwissKnife: Error: " << e.what() << '\n'
690  << desc << '\n'
691  << umdesc << '\n'
692  << lmdesc << '\n';
693 
694  return EXIT_FAILURE;
695  } catch (const std::runtime_error& e) {
696  std::cerr << "CLBSwissKnife: Error: " << e.what() << std::endl;
697  return EXIT_FAILURE;
698  }
699 
700  boost::asio::io_service io_service;
701  char buffer[buffer_size] __attribute__((aligned(8)));
702 
703  // Initialise the terminal width
705 
706  if (lm_mode) { // Ligier
707  if (use_gui) { // Ligier-GUI
708  #ifdef CURSES_FOUND
709  ChList stats;
710 
711  boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(1));
712 
713  boost::asio::posix::stream_descriptor keyb(io_service, ::dup(STDIN_FILENO));
714 
715  boost::asio::signal_set window_resize(io_service, SIGWINCH);
716 
717  char key = 0;
718  gui::ScreenInitialiser init;
719 
720  gui::Screen screen(io_service, lserver, stats);
721 
722  keyb.async_read_some(
723  boost::asio::buffer(&key, sizeof(key)),
724  boost::bind(
725  async_cin,
726  boost::ref(keyb),
727  boost::ref(key),
728  boost::ref(screen),
729  boost::asio::placeholders::error,
730  boost::asio::placeholders::bytes_transferred
731  )
732  );
733 
734  timer.async_wait(
735  boost::bind(
736  async_commit,
737  boost::ref(timer),
738  boost::ref(screen),
739  boost::asio::placeholders::error
740  )
741  );
742 
744  io_service
745  , tag
746  , endpoint
747  , buffer
748  , buffer_size
749  , clbsk::consumer::Gui(terminal_width, dom_names_map, stats, screen)
750  );
751 
752  window_resize.async_wait(
753  boost::bind(
755  boost::ref(window_resize),
756  boost::ref(screen),
757  boost::asio::placeholders::error,
758  boost::asio::placeholders::signal_number
759  )
760  );
761 
762  io_service.run();
763  #endif
764  } else { // Ligier-Scrollback
765  std::cout << "Listening from: " << endpoint << ':' << tag << '\n';
766  boost::asio::signal_set signals_handler(io_service, SIGWINCH, SIGINT);
767 
768  signals_handler.async_wait(
769  boost::bind(
771  boost::ref(signals_handler),
772  boost::ref(terminal_width),
773  boost::asio::placeholders::error,
774  boost::asio::placeholders::signal_number
775  )
776  );
777 
779  io_service
780  , tag
781  , endpoint
782  , buffer
783  , buffer_size
784  , clbsk::consumer::Scrollback(terminal_width, tmch, dom_names_map)
785  );
786 
787  io_service.run();
788  }
789  } else { // UDP
790  std::cout << "Listening port: " << port << '\n' << "Data type: ";
791 
792  if (type == taes) {
793  std::cout << "Acoustic\n";
794  } else if (type == ttdc) {
795  std::cout << "Optical\n";
796  } else if (type == tmch) {
797  std::cout << "Monitoring\n";
798  } else {
799  std::cout << "Automatically determined\n";
800  }
801 
802  clbsk::consumer::ConsumerSet consumer_set;
803 
804  trm::MonStreamer ms(roy_server, roy_port);
805 
806  if (uses_roy) {
807  std::cout
808  << "Using ROyWeb ("
809  << roy_server
810  << ", "
811  << roy_port
812  << ") with tag format "
813  << templ << std::endl;
814 
815  consumer_set.add(
816  clbsk::consumer::Roy(
817  dom_names_map
818  , templ
819  , ms
820  )
821  );
822  }
823 
824  if (dump) {
825  consumer_set.add(clbsk::consumer::File(output_file));
826  }
827 
828  if (use_gui) { // UDP-GUI
829  #ifdef CURSES_FOUND
830  ChList stats;
831 
832  boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(1));
833 
834  boost::asio::posix::stream_descriptor keyb(io_service, ::dup(STDIN_FILENO));
835 
836  boost::asio::signal_set window_resize(io_service, SIGWINCH);
837 
838  char key = 0;
839  gui::ScreenInitialiser init;
840 
841  std::string const heading
842  = "UDP " + boost::lexical_cast<std::string>(port);
843 
844  gui::Screen screen(io_service, heading, stats);
845 
846  keyb.async_read_some(
847  boost::asio::buffer(&key, sizeof(key)),
848  boost::bind(
849  async_cin,
850  boost::ref(keyb),
851  boost::ref(key),
852  boost::ref(screen),
853  boost::asio::placeholders::error,
854  boost::asio::placeholders::bytes_transferred
855  )
856  );
857 
858  timer.async_wait(
859  boost::bind(
860  async_commit,
861  boost::ref(timer),
862  boost::ref(screen),
863  boost::asio::placeholders::error
864  )
865  );
866 
867  window_resize.async_wait(
868  boost::bind(
870  boost::ref(window_resize),
871  boost::ref(screen),
872  boost::asio::placeholders::error,
873  boost::asio::placeholders::signal_number
874  )
875  );
876 
877  consumer_set.add(
878  clbsk::consumer::Gui(
879  terminal_width
880  , dom_names_map
881  , stats
882  , screen
883  )
884  );
885 
887  io_service
888  , port
889  , buffer
890  , buffer_size
891  , consumer_set
892  );
893 
894  io_service.run();
895  #endif
896  } else { // UDP-Scrollback
897  consumer_set.add(
898  clbsk::consumer::Scrollback(
899  terminal_width
900  , type
901  , dom_names_map
902  )
903  );
904 
905  boost::asio::signal_set signals_handler(io_service, SIGWINCH, SIGINT);
906 
907  signals_handler.async_wait(
908  boost::bind(
910  , boost::ref(signals_handler)
911  , boost::ref(terminal_width)
912  , boost::asio::placeholders::error
913  , boost::asio::placeholders::signal_number
914  )
915  );
916 
918  io_service
919  , port
920  , buffer
921  , buffer_size
922  , consumer_set
923  );
924 
925  io_service.run();
926  }
927  }
928 }
static int terminal_width
Definition: daq_parser.cpp:21
void handle_signal(boost::asio::signal_set &set, int &terminal_width, boost::system::error_code const &error, int signum)
struct __attribute__((__packed__)) InfoWord
Definition: infoword.hh:18
void async_win_resize(boost::asio::signal_set &window_resize, gui::Screen &screen, boost::system::error_code const &error, int signum)
Definition: gui.cpp:106
TString replace(const TString &target, const TRegexp &regexp, const T &replacement)
Replace regular expression in input by given replacement.
Definition: JPrintResult.cc:63
unsigned int const tmch
Definition: datatypes.cpp:9
then print u2 $script< option > print u2 Possible options
static const size_t buffer_size
unsigned int const ttdc
Definition: datatypes.cpp:7
static const unsigned int default_opto_port
int get_terminal_width()
Program name: CLBSwissKnife.
boost::asio::ip::tcp::endpoint make_endpoint(const std::string &address)
unsigned int const taes
Definition: datatypes.cpp:8
void store(const JString &file_name, const JDetector &detector)
Store detector to output file.
void async_cin(boost::asio::posix::stream_descriptor &keyb, char &key, gui::Screen &screen, const boost::system::error_code &error, std::size_t bytes_transferred)
Definition: gui.cpp:68
unsigned int const unkn
Definition: datatypes.cpp:10
void async_commit(boost::asio::deadline_timer &timer, gui::Screen &screen, boost::system::error_code const &error)
Definition: gui.cpp:50
dom_map_type load_dom_map(std::istream &map)
Definition: dom_map.cpp:49
const char * map
Definition: elog.cc:87
data_type v[N+1][M+1]
Definition: JPolint.hh:707
static const unsigned int default_acou_port
static const unsigned int default_moni_port

Variable Documentation

const size_t buffer_size = 10000
static

Definition at line 169 of file clb_swiss_knife.cpp.

const unsigned int default_opto_port = 56015
static

Definition at line 171 of file clb_swiss_knife.cpp.

const unsigned int default_acou_port = 56016
static

Definition at line 172 of file clb_swiss_knife.cpp.

const unsigned int default_moni_port = 56017
static

Definition at line 173 of file clb_swiss_knife.cpp.