host: allow multiple repeats for play command of replay block

Add a new play command that accepts a size_t for iterations. This
allows arbritrary iteration on the signal as well as continous
play (max value of iteration). Use the CONTINOUS_PLAY command for
that.

The old play command (using bool) is deprecated but stays in
for backward capabilities.
This commit is contained in:
Lars Amsel 2025-07-10 09:53:09 +02:00 committed by Jörg Hofrichter
parent bf8c552e34
commit 4708d01d9e
3 changed files with 88 additions and 5 deletions

View File

@ -149,6 +149,12 @@ public:
static const uint32_t PLAY_CMD_FINITE;
static const uint32_t PLAY_CMD_CONTINUOUS;
/*!
* This constant can be used in the play command to trigger continous
* play of the signal.
*/
static constexpr auto PLAY_CONTINUOUS{std::numeric_limits<size_t>::max()};
/**************************************************************************
* Replay Control API calls
*************************************************************************/
@ -198,6 +204,9 @@ public:
* the same time spec, and either continuous streaming (if \p repeat is true)
* or STREAM_MODE_START_NUM_SAMPS_AND_DONE if it is not.
*
* \deprecated{ This play command is deprecated, please use play command with
* repeat as size_t where 0 is repeat=true and 1 is repeat=false}
*
* \param offset Memory offset of the data to be played. This value must be
* aligned to the size of the word in memory. Use get_word_size()
* to get the memory word size.
@ -219,11 +228,58 @@ public:
* \throws uhd::value_error if offset+size exceeds the available memory.
* \throws uhd::op_failed Too many play commands are queued.
*/
virtual void play(const uint64_t offset,
const uint64_t size,
const size_t port,
const uhd::time_spec_t time_spec,
const bool repeat) = 0;
/*! Play back data.
*
* The offset and size define what data is played back on an output port.
* It will stream out \p size bytes of data, starting at memory offset
* \p offset.
*
* The data can be played once or repeated continuously until a stop
* command is issued. If a time_spec is supplied, it will be placed in the
* header of the first packet. Typically, this is used to tell a downstream
* Radio block when to start transmitting the data.
*
* If the data type on the output port is not defined, this function will
* throw an error.
*
* This is equivalent to calling config_play() with the same arguments for
* \p offset, \p size, and \p port, and then calling issue_stream_cmd() with
* the same time spec, and either continuous streaming (if \p repeat is true)
* or STREAM_MODE_START_NUM_SAMPS_AND_DONE if it is not.
*
* \param offset Memory offset of the data to be played. This value must be
* aligned to the size of the word in memory. Use get_word_size()
* to get the memory word size.
* \param size Size of data to play back. This value must be aligned to the
* size of the memory word and item size. Use get_word_size() to
* get the memory word size and get_output_item_size() to get
* the item size. This value will be used for the num_samps
* component of the underlying stream command.
* \param port Which output port of the replay block to use
* \param time_spec Set the time for the first item. Any non-zero value is
* used to set the time in the header of the first packet.
* Most commonly, this is used to set the start time of a
* transmission. Note that this block will not wait for a
* time to occur, rather, it will tag the first outgoing
* packet with this time stamp.
* \param iterations Determines whether the data should be played continous
* (PLAY_CONTINUOUS) or num_repeat times. If set to
* PLAY_CONTINUOUS stop() must be called to stop the
* play back.
* \throws uhd::value_error if offset+size exceeds the available memory.
* \throws uhd::op_failed Too many play commands are queued.
*/
virtual void play(const uint64_t offset,
const uint64_t size,
const size_t port = 0,
const uhd::time_spec_t time_spec = uhd::time_spec_t(0.0),
const bool repeat = false) = 0;
const size_t iterations = 1) = 0;
/*! Stops playback
*

View File

@ -238,12 +238,28 @@ public:
const size_t port,
const uhd::time_spec_t time_spec,
const bool repeat) override
{
play(offset,
size,
port,
time_spec,
static_cast<size_t>(repeat ? PLAY_CONTINUOUS : 1));
}
void play(const uint64_t offset,
const uint64_t size,
const size_t port,
const uhd::time_spec_t time_spec,
const size_t iterations) override
{
config_play(offset, size, port);
uhd::stream_cmd_t play_cmd =
repeat ? uhd::stream_cmd_t(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS)
: uhd::stream_cmd_t(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
play_cmd.num_samps = size / get_play_item_size(port);
iterations == PLAY_CONTINUOUS
? uhd::stream_cmd_t(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS)
: uhd::stream_cmd_t(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
play_cmd.num_samps = iterations == PLAY_CONTINUOUS
? 0
: iterations * size / get_play_item_size(port);
play_cmd.time_spec = time_spec;
play_cmd.stream_now = (time_spec == 0.0);
issue_stream_cmd(play_cmd, port);

View File

@ -18,7 +18,18 @@ void export_replay_block_control(py::module& m)
.def(py::init(&block_controller_factory<replay_block_control>::make_from))
.def("record", &replay_block_control::record)
.def("record_restart", &replay_block_control::record_restart)
.def("play", &replay_block_control::play)
.def("play",
py::overload_cast<const uint64_t,
const uint64_t,
const size_t,
const uhd::time_spec_t,
const bool>(&replay_block_control::play))
.def("play",
py::overload_cast<const uint64_t,
const uint64_t,
const size_t,
const uhd::time_spec_t,
const size_t>(&replay_block_control::play))
.def("stop", &replay_block_control::stop)
.def("get_mem_size", &replay_block_control::get_mem_size)
.def("get_word_size", &replay_block_control::get_word_size)