aboutsummaryrefslogtreecommitdiffstats
path: root/host/utils/latency/include/Responder.hpp
blob: 7ee91050027772fbd4b90bb495de8886a5d3f816 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
//
// Copyright 2010-2013 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#ifndef RESPONDER_H
#define RESPONDER_H

#include <curses.h>
#include <map>
#include <ctime>
#include <stdint.h>

#include <uhd/usrp/multi_usrp.hpp>

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;
            bool invert;
            bool 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<uint64_t,STATS> 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<std::complex<float> > &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<std::map<std::string,std::string> > read_eth_info();
        uhd::device_addr_t get_usrp_info();
        std::map<std::string, std::string> get_hw_info();
        std::string get_ip_subnet_addr(std::string ip);
};

#endif // RESPONDER_H