// // Copyright 2010-2013 Ettus Research LLC // Copyright 2018 Ettus Research, a National Instruments Company // // SPDX-License-Identifier: GPL-3.0-or-later // #ifndef RESPONDER_H #define RESPONDER_H #include #include #include #include #include using namespace std; class Responder { public: enum ReturnCodes { RETCODE_OK = 0, RETCODE_BAD_ARGS = -1, RETCODE_RUNTIME_ERROR = -2, RETCODE_UNKNOWN_EXCEPTION = -3, RETCODE_RECEIVE_TIMEOUT = -4, RETCODE_RECEIVE_FAILED = -5, RETCODE_MANUAL_ABORT = -6, RETCODE_BAD_PACKET = -7, RETCODE_OVERFLOW = -8 }; struct Options { string device_args; double delay; double sample_rate; double trigger_level; float output_scale; double response_duration; double dc_offset_delay; double init_delay; double timeout; size_t samps_per_buff; size_t samps_per_packet; double level_calibration_duration; std::string test_title; std::string stats_filename; std::string stats_filename_prefix; std::string stats_filename_suffix; double delay_min; double delay_max; double delay_step; double pulse_detection_threshold; uint64_t test_iterations; size_t end_test_after_success_count; size_t skip_iterations; double simulate_frequency; double time_mul; size_t flush_count; size_t optimize_padding; double rt_priority; bool ignore_simulation_check; bool test_iterations_is_sample_count; bool skip_eob; bool adjust_simulation_rate; bool optimize_simulation_rate; bool no_stats_file; bool log_file; bool batch_mode; bool skip_if_results_exist; bool skip_send; bool combine_eob; bool pause; bool realtime; float invert; float output_value; bool no_delay; bool allow_late_bursts; uint64_t level_calibration_count() const { return (uint64_t)(sample_rate * level_calibration_duration); } uint64_t response_length() const { return (uint64_t)(sample_rate * response_duration); } uint64_t highest_delay_samples(const double delay) const { return (uint64_t)(delay * (double)sample_rate); } uint64_t simulate_duration(const double simulate_frequency) const { if (simulate_frequency > 0.0) { return (uint64_t)((double)sample_rate / simulate_frequency); } return 0; } }; typedef struct Stats { double delay; uint64_t detected; uint64_t missed; uint64_t skipped; } STATS; typedef std::map StatsMap; struct DebugInfo { time_t start_time; time_t end_time; time_t start_time_test; time_t end_time_test; time_t first_send_timeout; }; Responder(Options& opt); virtual ~Responder(); // Main entry point after constructor. int run(); int get_return_code() { return _return_code; } protected: private: // These 2 variables are used for ncurses output. WINDOW* _window; std::stringstream _ss; std::stringstream _ss_cerr; // struct which holds all arguments as constants settable from outside the class const Options _opt; string _stats_filename; // Specify name of statistics file string _stats_log_filename; // Specify name for log file. double _delay; // may be altered in all modes. size_t _samps_per_packet; // This is one of the options of interest. Find out how well // it performs. double _delay_step; // may be altered in interactive mode double _simulate_frequency; // updated during automatic test iterations // additional attributes bool _allow_late_bursts; // may be altered in interactive mode bool _no_delay; // may be altered in interactive mode // dependent variables uint64_t _response_length; int64_t _init_delay_count; int64_t _dc_offset_countdown; int64_t _level_calibration_countdown; uint64_t _simulate_duration; uint64_t _original_simulate_duration; // these variables store test conditions uint64_t _num_total_samps; // printed on exit size_t _overruns; // printed on exit StatsMap _mapStats; // store results uint64_t _max_success; // < 0 --> write results to file int _return_code; // Hold USRP, streams and commands uhd::usrp::multi_usrp::sptr _usrp; uhd::tx_streamer::sptr _tx_stream; uhd::rx_streamer::sptr _rx_stream; uhd::stream_cmd_t _stream_cmd; // Keep track of number of timeouts. uint64_t _timeout_burst_count; uint64_t _timeout_eob_count; // Transmit attributes float* _pResponse; // Control print parameters. int _y_delay_pos; int _x_delay_pos; // Remember the cursor position of delay line uint64_t _last_overrun_count; // Hold debug info during test. Will be included in log file. DebugInfo _dbginfo; /* * Here are the class's member methods. */ // These methods are used for ncurses output void create_ncurses_window(); void FLUSH_SCREEN(); void FLUSH_SCREEN_NL(); // Variable calculation helpers inline uint64_t get_response_length(double sample_rate, double response_duration) { return (uint64_t)(sample_rate * response_duration); } int calculate_dependent_values(); // make sure existing results are not overwritten accidently bool set_stats_filename(string test_id); bool check_for_existing_results(); // Functions that may cause Responder to finish void register_stop_signal_handler(); bool test_finished(size_t success_count); int test_step_finished(uint64_t trigger_count, uint64_t num_total_samps_test, STATS statsCurrent, size_t success_count); // Check if sent burst could be transmitted. bool tx_burst_is_late(); // Handle receiver errors such as overflows. bool handle_rx_errors(uhd::rx_metadata_t::error_code_t err, size_t num_rx_samps); // In interactive mode, handle Responder control and output. bool handle_interactive_control(); void print_interactive_msg(std::string msg); // calibration important for interactive mode with 2nd USRP connected. float calibrate_usrp_for_test_run(); // Run actual test void run_test(float threshold = 0.0f); // Detect falling edge bool get_new_state( uint64_t total_samps, uint64_t simulate_duration, float val, float threshold); uint64_t detect_respond_pulse_count(STATS& statsCurrent, std::vector>& buff, uint64_t trigger_count, size_t num_rx_samps, float threshold, uhd::time_spec_t rx_time); // Hold test results till they are printed to a file void add_stats_to_results(STATS statsCurrent, double delay); // Control USRP and necessary streamers uhd::usrp::multi_usrp::sptr create_usrp_device(); void set_usrp_rx_dc_offset(uhd::usrp::multi_usrp::sptr usrp, bool ena); void stop_usrp_stream(); uhd::tx_streamer::sptr create_tx_streamer(uhd::usrp::multi_usrp::sptr usrp); uhd::rx_streamer::sptr create_rx_streamer(uhd::usrp::multi_usrp::sptr usrp); // Send burst and handle results. bool send_tx_burst(uhd::time_spec_t rx_time, size_t n); void handle_tx_timeout(int burst, int eob); float* alloc_response_buffer_with_data(uint64_t response_length); uhd::tx_metadata_t get_tx_metadata(uhd::time_spec_t rx_time, size_t n); // Control test parameters void update_and_print_parameters(const STATS& statsPrev, const double delay); double get_simulate_frequency( double delay, uint64_t response_length, uint64_t original_simulate_duration); double get_max_possible_frequency( uint64_t highest_delay_samples, uint64_t response_length); // Helper methods to print status during test. void print_init_test_status(); void print_test_title(); void print_usrp_status(); void print_create_usrp_msg(); void print_tx_stream_status(); void print_rx_stream_status(); void print_test_parameters(); void print_formatted_delay_line(const uint64_t simulate_duration, const uint64_t old_simulate_duration, const STATS& statsPrev, const double delay, const double simulate_frequency); void print_overrun_msg(); void print_error_msg(std::string msg); void print_timeout_msg(); void print_final_statistics(); void print_msg_and_wait(std::string msg); void print_msg(std::string msg); // Safe results of test to file. void write_statistics_to_file(StatsMap mapStats); void safe_write_statistics_to_file( StatsMap mapStats, uint64_t max_success, int return_code); void write_log_file(); // Write debug info to log file if requested. void write_debug_info(ofstream& logs); std::string get_gmtime_string(time_t time); std::string enum2str(int return_code); std::vector> read_eth_info(); uhd::device_addr_t get_usrp_info(); std::map get_hw_info(); std::string get_ip_subnet_addr(std::string ip); }; #endif // RESPONDER_H