diff options
-rw-r--r-- | tools/kitchen_sink/kitchen_sink.cpp | 161 |
1 files changed, 139 insertions, 22 deletions
diff --git a/tools/kitchen_sink/kitchen_sink.cpp b/tools/kitchen_sink/kitchen_sink.cpp index c7265bea4..62bf89375 100644 --- a/tools/kitchen_sink/kitchen_sink.cpp +++ b/tools/kitchen_sink/kitchen_sink.cpp @@ -278,12 +278,16 @@ typedef struct RxParams { bool single_packets; bool size_map; size_t rx_sample_limit; - std::ofstream* capture_file; + std::vector<std::ofstream*> capture_files; bool set_rx_freq; double rx_freq; double rx_freq_delay; double rx_lo_offset; bool interleave_rx_file_samples; + bool ignore_late_start; + bool ignore_bad_packets; + bool ignore_timeout; + bool ignore_unexpected_error; } RX_PARAMS; static uint64_t recv_samp_count_progress = 0; @@ -465,25 +469,37 @@ void benchmark_rx_rate( recv_done.notify_one(); } - if (params.capture_file != NULL) + if (params.capture_files.empty() == false) { - if (params.interleave_rx_file_samples) + size_t channel_count = rx_stream->get_num_channels(); + + if ((channel_count == 1) || ((channel_count > 1) && (params.capture_files.size() == 1))) { - for (size_t i = 0; i < recv_samps; ++i) + if (params.interleave_rx_file_samples) + { + for (size_t i = 0; i < recv_samps; ++i) + { + for (size_t j = 0; j < channel_count; ++j) + { + params.capture_files[0]->write((const char*)buffs[j] + (bytes_per_samp * i), bytes_per_samp); + } + } + } + else { - size_t channel_count = rx_stream->get_num_channels(); - for (size_t j = 0; j < channel_count; ++j) + for (size_t i = 0; i < channel_count; ++i) { - params.capture_file->write((const char*)buffs[j] + (bytes_per_samp * i), bytes_per_samp); + size_t num_bytes = recv_samps * bytes_per_samp; + params.capture_files[0]->write((const char*)buffs[i], num_bytes); } } } else { - for (size_t i = 0; i < rx_stream->get_num_channels(); ++i) + for (size_t n = 0; n < channel_count; ++n) { size_t num_bytes = recv_samps * bytes_per_samp; - params.capture_file->write((const char*)buffs[i], num_bytes); + params.capture_files[n]->write((const char*)buffs[n], num_bytes); } } } @@ -498,13 +514,17 @@ void benchmark_rx_rate( //} //handle the error codes - switch(md.error_code) { + switch(md.error_code) + { case uhd::rx_metadata_t::ERROR_CODE_NONE: - if (had_an_overflow) { + { + if (had_an_overflow) + { had_an_overflow = false; num_dropped_samps += (md.time_spec - last_time).to_ticks(rate); // FIXME: Check this as 'num_dropped_samps' has come out -ve } break; + } // ERROR_CODE_OVERFLOW can indicate overflow or sequence error case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW: // 'recv_samps' should be 0 @@ -523,13 +543,43 @@ void benchmark_rx_rate( ss << HEADER_RX"(" << get_stringified_time() << ") "; ss << boost::format("Timeout") << std::endl; std::cout << ss.str(); + if (params.ignore_timeout == false) + sig_int_handler(-1); + break; + } + + case uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND: + { + std::stringstream ss; + ss << HEADER_RX"(" << get_stringified_time() << ") "; + ss << boost::format("Late command") << std::endl; + std::cout << ss.str(); + if (params.ignore_late_start == false) + sig_int_handler(-1); + break; + } + + case uhd::rx_metadata_t::ERROR_CODE_BAD_PACKET: + { + std::stringstream ss; + ss << HEADER_RX"(" << get_stringified_time() << ") "; + ss << boost::format("Bad packet") << std::endl; + std::cout << ss.str(); + if (params.ignore_bad_packets == false) + sig_int_handler(-1); break; } default: - std::cerr << HEADER_RX"Error code: " << md.error_code << std::endl; - std::cerr << HEADER_RX"Unexpected error on recv, continuing..." << std::endl; + { + std::stringstream ss; + ss << HEADER_RX"(" << get_stringified_time() << ") "; + ss << (boost::format("Unexpected error (code: %d)") % md.error_code) << std::endl; + std::cout << ss.str(); + if (params.ignore_unexpected_error == false) + sig_int_handler(-1); break; + } } print_msgs(); @@ -550,11 +600,14 @@ void benchmark_rx_rate( rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); } - if (params.capture_file != NULL) + if (params.capture_files.empty() == false) { - std::cout << HEADER_RX"Closing capture file..." << std::endl; - delete params.capture_file; - params.capture_file = NULL; + std::cout << HEADER_RX"Closing capture files..." << std::endl; + + for (size_t n = 0; n < params.capture_files.size(); ++n) + delete params.capture_files[n]; + + params.capture_files.clear(); } l.lock(); @@ -628,7 +681,7 @@ void benchmark_tx_rate( size_t total_packet_count = (total_length / max_samps_per_packet) + ((total_length % max_samps_per_packet) ? 1 : 0); if ((params.use_tx_eob) && (params.tx_time_between_bursts > 0)) packet_time += uhd::time_spec_t(params.tx_time_between_bursts); - size_t max_late_count = (size_t)(rate / (double)packet_time.to_ticks(rate)) * total_packet_count; + size_t max_late_count = (size_t)(rate / (double)packet_time.to_ticks(rate)) * total_packet_count * tx_stream->get_num_channels(); // Also need to take into account number of radios // Will be much higher L values (e.g. 31K) on e.g. B200 when entire TX pipeline is full of late packets (large size due to total TX buffering throughout transport & DSP) @@ -1139,7 +1192,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("progress-interval", po::value<double>(&progress_interval)->default_value(progress_interval), "seconds between bandwidth updates (0 disables)") ("rx-progress-interval", po::value<double>(&rx_progress_interval), "seconds between RX bandwidth updates (0 disables)") ("tx-progress-interval", po::value<double>(&tx_progress_interval), "seconds between TX bandwidth updates (0 disables)") - ("tx-offset", po::value<double>(&tx_time_offset), "seconds that TX should be in front of RX when following") + ("tx-offset", po::value<double>(&tx_time_offset)->default_value(0.0), "seconds that TX should be in front of RX when following") ("tx-length", po::value<size_t>(&tx_burst_length)->default_value(0), "TX burst length in samples (0: maximum packet size)") ("tx-flush", po::value<size_t>(&tx_flush_length)->default_value(0), "samples to flush TX with after burst") ("tx-burst-separation", po::value<double>(&tx_time_between_bursts), "seconds between TX bursts") @@ -1177,6 +1230,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("recover-late", "recover from excessive late TX packets") ("disable-async", "disable the async message thread") ("interleave-rx-file-samples", "interleave individual samples (default is interleaving buffers)") + ("ignore-late-start", "continue receiving even if stream command was late") + ("ignore-bad-packets", "continue receiving after a bad packet") + ("ignore-timeout", "continue receiving after timeout") + ("ignore-unexpected", "continue receiving after unexpected error") // record TX/RX times // Optional interruption // simulate u / o at random / pulses @@ -1234,6 +1291,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ bool recover_late = (vm.count("recover-late") > 0); bool enable_async = (vm.count("disable-async") == 0); bool interleave_rx_file_samples = (vm.count("interleave-rx-file-samples") > 0); + bool ignore_late_start = (vm.count("ignore-late-start") > 0); + bool ignore_bad_packets = (vm.count("ignore-bad-packets") > 0); + bool ignore_timeout = (vm.count("ignore-timeout") > 0); + bool ignore_unexpected_error = (vm.count("ignore-unexpected") > 0); boost::posix_time::time_duration interrupt_timeout_duration(boost::posix_time::seconds(long(interrupt_timeout)) + boost::posix_time::microseconds(long((interrupt_timeout - floor(interrupt_timeout))*1e6))); @@ -1273,6 +1334,36 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ return ~0; } + bool rx_filename_has_format = false; + if (rx_channel_nums.size() > 0) + { + std::string str0; + try + { + str0 = boost::str(boost::format(rx_file) % 0); + rx_filename_has_format = true; + } + catch (...) + { + } + + bool format_different = false; + try + { + std::string str1(boost::str(boost::format(rx_file) % 1)); + format_different = (str0 != str1); + } + catch (...) + { + } + + if ((rx_filename_has_format) && (format_different == false)) + { + std::cout << HEADER_ERROR "Multi-channel RX capture filename format did not produce unique names" << std::endl; + return ~0; + } + } + if ((tx_rx_sync) || (tx_follows_rx)) { if (tx_channel_nums.size() == 0) @@ -1462,11 +1553,33 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } } - rx_params.capture_file = NULL; if (rx_file.empty() == false) { - std::cout << boost::format(HEADER_RX"Capturing to \"%s\"") % rx_file << std::endl; - rx_params.capture_file = new std::ofstream(rx_file.c_str(), std::ios::out); + if (rx_filename_has_format == false) + { + if (rx_stream->get_num_channels() == 1) + { + std::cout << boost::format(HEADER_RX"Capturing single channel to \"%s\"") % rx_file << std::endl; + } + else + { + if (interleave_rx_file_samples) + std::cout << boost::format(HEADER_RX"Capturing all %d channels as interleaved samples to \"%s\"") % rx_stream->get_num_channels() % rx_file << std::endl; + else + std::cout << boost::format(HEADER_RX"Capturing all %d channels as interleaved buffers to \"%s\"") % rx_stream->get_num_channels() % rx_file << std::endl; + } + + rx_params.capture_files.push_back(new std::ofstream(rx_file.c_str(), std::ios::out)); + } + else + { + for (size_t n = 0; n < rx_stream->get_num_channels(); ++n) + { + std::cout << boost::format(HEADER_RX"Capturing channel %d to \"%s\"") % n % (boost::str(boost::format(rx_file) % n)) << std::endl; + std::string rx_file_name(boost::str(boost::format(rx_file) % n)); + rx_params.capture_files.push_back(new std::ofstream(rx_file_name.c_str(), std::ios::out)); + } + } } std::cout << boost::format( @@ -1488,6 +1601,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ rx_params.rx_freq_delay = rx_freq_delay; rx_params.rx_lo_offset = rx_lo_offset; rx_params.interleave_rx_file_samples = interleave_rx_file_samples; + rx_params.ignore_late_start = ignore_late_start; + rx_params.ignore_bad_packets = ignore_bad_packets; + rx_params.ignore_timeout = ignore_timeout; + rx_params.ignore_unexpected_error = ignore_unexpected_error; thread_group.create_thread(boost::bind( &benchmark_rx_rate, |