Jpp test-rotations-old
the software that should make you happy
Loading...
Searching...
No Matches
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)
 Program name: CLBSwissKnife.
 

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)
Value:
((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

◆ 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 \
515provided 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 \
521provided 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 \
527not 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 \
531data 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 \
540server. The syntax is format:server_ip:server_port. \
541The format parameter can contain the following placeholders: %d for \
542DOM ID, %n for DOM name (if available, otherwise the DOM ID is used) \
543and %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(
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
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
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(
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
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
932 , consumer_set
933 );
934
935 io_service.run();
936 }
937 }
938}
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
static const unsigned int taes
static const unsigned int ttdc
static const unsigned int tmch
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

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.