Jpp  18.6.0-rc.1
the software that should make you happy
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Classes | Macros | 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 >
 

Macros

#define GET_IO_SERVICE(s)   ((s).get_io_service())
 Program name: CLBSwissKnife. More...
 

Functions

int get_terminal_width ()
 
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
 

Macro Definition Documentation

#define GET_IO_SERVICE (   s)    ((s).get_io_service())

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 147 of file clb_swiss_knife.cpp.

Function Documentation

int get_terminal_width ( )

Definition at line 157 of file clb_swiss_knife.cpp.

158 {
159  static bool const is_a_tty = isatty(1);
160 
161  if (!is_a_tty) {
162  return 80;
163  } else {
164  struct winsize sz;
165 
166  ioctl(1, TIOCGWINSZ, &sz);
167  return sz.ws_col;
168  }
169 }
void handle_signal ( boost::asio::signal_set &  set,
int &  terminal_width,
boost::system::error_code const &  error,
int  signum 
)

Definition at line 936 of file clb_swiss_knife.cpp.

942 {
943  if (!error) {
944  if (signum == SIGINT) {
945 
946  GET_IO_SERVICE(set).stop();
947 
948  if (isatty(1)) {
949  std::cout << "\033]2;thank you for flying with CLBSwissKnife!\007";
950  std::cout << "\rBye bye!\n";
951  }
952  return;
953  } else if (signum == SIGWINCH) {
955  }
956 
957  set.async_wait(
958  boost::bind(
960  boost::ref(set),
961  boost::ref(terminal_width),
962  boost::asio::placeholders::error,
963  boost::asio::placeholders::signal_number
964  )
965  );
966  }
967 }
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()
#define GET_IO_SERVICE(s)
Program name: CLBSwissKnife.
boost::asio::ip::tcp::endpoint make_endpoint ( std::string const &  address)
inline
Author
cpellegrino

Definition at line 430 of file clb_swiss_knife.cpp.

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

Definition at line 450 of file clb_swiss_knife.cpp.

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

const unsigned int default_opto_port = 56015
static

Definition at line 177 of file clb_swiss_knife.cpp.

const unsigned int default_acou_port = 56016
static

Definition at line 178 of file clb_swiss_knife.cpp.

const unsigned int default_moni_port = 56017
static

Definition at line 179 of file clb_swiss_knife.cpp.