Jpp  master_rocky-37-gf0c5bc59d
the software that should make you happy
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

◆ GET_IO_SERVICE

#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

◆ get_terminal_width()

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 }

◆ handle_signal()

void handle_signal ( boost::asio::signal_set &  set,
int &  terminal_width,
boost::system::error_code const &  error,
int  signum 
)

Definition at line 940 of file clb_swiss_knife.cpp.

946 {
947  if (!error) {
948  if (signum == SIGINT) {
949 
950  GET_IO_SERVICE(set).stop();
951 
952  if (isatty(1)) {
953  std::cout << "\033]2;thank you for flying with CLBSwissKnife!\007";
954  std::cout << "\rBye bye!\n";
955  }
956  return;
957  } else if (signum == SIGWINCH) {
959  }
960 
961  set.async_wait(
962  boost::bind(
964  boost::ref(set),
965  boost::ref(terminal_width),
966  boost::asio::placeholders::error,
967  boost::asio::placeholders::signal_number
968  )
969  );
970  }
971 }
int get_terminal_width()
void handle_signal(boost::asio::signal_set &set, int &terminal_width, boost::system::error_code const &error, int signum)
#define GET_IO_SERVICE(s)
Program name: CLBSwissKnife.
static int terminal_width
Definition: daq_parser.cpp:21

◆ make_endpoint()

boost::asio::ip::tcp::endpoint make_endpoint ( std::string const &  address)
inline
Author
cpellegrino

Definition at line 434 of file clb_swiss_knife.cpp.

436  {
437  boost::asio::io_service service;
438  boost::asio::ip::tcp::resolver resolver(service);
439 
440  std::string::size_type const pos = address.find(":");
441 
442  std::string const host = pos == std::string::npos ? address : address.substr(0, pos);
443  std::string const port = pos == std::string::npos ? "5553" : address.substr(pos + 1);
444 
445  boost::asio::ip::tcp::resolver::query query(
446  boost::asio::ip::tcp::v4()
447  , host
448  , port
449  );
450 
451  return *resolver.resolve(query);
452 }

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 454 of file clb_swiss_knife.cpp.

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

Variable Documentation

◆ buffer_size

const size_t buffer_size = 10000
static

Definition at line 175 of file clb_swiss_knife.cpp.

◆ default_opto_port

const unsigned int default_opto_port = 56015
static

Definition at line 177 of file clb_swiss_knife.cpp.

◆ default_acou_port

const unsigned int default_acou_port = 56016
static

Definition at line 178 of file clb_swiss_knife.cpp.

◆ default_moni_port

const unsigned int default_moni_port = 56017
static

Definition at line 179 of file clb_swiss_knife.cpp.