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

Reply via email to