Hi, I am using the Replay block and I ran into an issue where I have gotten the Replay block into a bad state which I can't seem to fix short of rebooting the N310. The way I know it is in a bad state is that the data playing out is corrupted. Although the playout is similar to what it should be, there are numerous gaps & drops that indicate the corruption. If I reboot the N310, the corruption disappears. I would like to be able to "reset" things without requiring an N310 reboot.
My custom software controls the Replay block with 3 functions: replay_store() and replay_play() and replay_stop(), all provided below. I don't do anything tricky like trying to store and play simultaneously. The replay_store() function is very similar to the rfnoc_replay_samples_from_file() example with the exception that it doesn't actually start or stop the playout. This occurs in my other 2 functions. The way that I get the replay block into a bad state is by failing to call replay_store() prior to replay_play(). This was a bug in my software that could occur in some situations (which I have since fixed). After this happens, I can't produce uncorrupted playouts without rebooting the N310. Let me know if you have any ideas how I can "reset" the Replay block to obtain uncorrupted output. Rob /*******************************************************/ int nd::replay_store( uhd::rfnoc::replay_block_control::sptr replay_ptr, size_t port, uhd::tx_streamer::sptr tx_stream, std::vector<char>& samp_vec, uint32_t addr ){ const std::string ID = replay_ptr->get_block_id().to_string() + ":" + std::to_string(port); // Constants related to the Replay block const size_t bytes_per_sample = 4; // Complex signed 16-bit is 32 bits per sample const size_t samples_per_word = 2; // Number of sc16 samples per 64-bit word const size_t bytes_per_word = bytes_per_sample*samples_per_word; size_t num_bytes = samp_vec.size(); // Calculate the number of 64-bit words and samples to replay size_t words_to_replay = num_bytes / bytes_per_word; size_t samples_to_replay = words_to_replay * samples_per_word; uint32_t bytes_to_replay = words_to_replay * bytes_per_word; if (bytes_to_replay != num_bytes) { UHD_LOGGER_WARNING(__CLASS_AND_FUNC__) << ID << "Replay block requires an even number of samples. Truncating extra bytes"; } // Configure a buffer in the on-board memory at address 0 that's equal in // size to the file we want to play back (rounded down to a multiple of // 64-bit words). Note that it is allowed to playback a different size or // location from what was recorded. UHD_LOGGER_DEBUG(__CLASS_AND_FUNC__) << ID << ": Configuring memory at addr 0x" << std::hex << addr << std::dec << " for " << bytes_to_replay << " bytes"; replay_ptr->stop(port); // just in case it is presently playing replay_ptr->record(addr, bytes_to_replay, port); // Restart record buffer repeatedly until no new data appears on the Replay // block's input. This will flush any data that was buffered on the input. UHD_LOGGER_DEBUG(__CLASS_AND_FUNC__) << ID << ": Restarting record buffer"; auto start_time = std::chrono::steady_clock::now(); while (true) { replay_ptr->record_restart(port); std::this_thread::sleep_for(std::chrono::milliseconds(20)); uint32_t fullness = replay_ptr->get_record_fullness(port); if (fullness==0) break; std::chrono::duration<double> time_diff_s = std::chrono::steady_clock::now() - start_time; UHD_LOGGER_DEBUG(__CLASS_AND_FUNC__) << ID << ": Time: " << time_diff_s.count() << ": Fullness " << fullness; if (time_diff_s.count() > 2.0) { UHD_LOGGER_ERROR(__CLASS_AND_FUNC__) << ID << ": Timeout waiting to flush record buffer"; return -1; } } /////////////////////////////////////////////////////////////////////////// // Send data to replay (record the data) UHD_LOGGER_INFO(__CLASS_AND_FUNC__) << ID << ": Sending " << samples_to_replay << " samples"; uhd::tx_metadata_t tx_md; tx_md.start_of_burst = true; tx_md.end_of_burst = true; size_t num_tx_samps = tx_stream->send(&samp_vec[0], samples_to_replay, tx_md); if (num_tx_samps != samples_to_replay) { UHD_LOGGER_ERROR(__CLASS_AND_FUNC__) << ID << ": Error sending samples: " << num_tx_samps << "/" << samples_to_replay; return -1; } /////////////////////////////////////////////////////////////////////////// // Wait for data to be stored in on-board memory UHD_LOGGER_DEBUG(__CLASS_AND_FUNC__) << ID << ": Waiting for recording to complete"; start_time = std::chrono::steady_clock::now(); while (true) { uint32_t fullness = replay_ptr->get_record_fullness(port); if (fullness>=bytes_to_replay) break; std::chrono::duration<double> time_diff_s = std::chrono::steady_clock::now() - start_time; UHD_LOGGER_DEBUG(__CLASS_AND_FUNC__) << ID << ": Time: (s): " << time_diff_s.count() << ": Fullness: " << fullness << " / " << bytes_to_replay; if (time_diff_s.count() > 2.0) { UHD_LOGGER_ERROR(__CLASS_AND_FUNC__) << ID << ": Timeout waiting for recording to complete"; return -1; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } UHD_LOGGER_INFO(__CLASS_AND_FUNC__) << ID << ": Successfully sent " << samples_to_replay << " samples"; return samples_to_replay; } /*******************************************************/ /*******************************************************/ void nd::replay_play( uhd::rfnoc::replay_block_control::sptr replay_ptr, size_t port, const uhd::time_spec_t start_time ){ const std::string ID = replay_ptr->get_block_id().to_string() + ":" + std::to_string(port); uint64_t rec_addr = replay_ptr->get_record_offset(port); uint64_t rec_size = replay_ptr->get_record_size(port); UHD_LOGGER_DEBUG(ID) << "Replay Started. Samples: " << (rec_size/4); replay_ptr->play(rec_addr, rec_size, port, start_time, true); } /*******************************************************/ /*******************************************************/ void nd::replay_stop( uhd::rfnoc::replay_block_control::sptr replay_ptr, size_t port ){ const std::string ID = replay_ptr->get_block_id().to_string() + ":" + std::to_string(port); UHD_LOGGER_DEBUG(ID) << "Replay Stopped"; replay_ptr->stop(port); }
_______________________________________________ USRP-users mailing list USRP-users@lists.ettus.com http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com