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
[email protected]
http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com