Skip to content

Commit 0646ea3

Browse files
kantooonadrian
andauthored
Dynamically set tx_streamer buffer size based on sample rate (#74)
The original hardcoded buffer size of 4096 is too small for a full duplex RX and TX stream at higher sample rates, leading to dropped samples during transmit. Change tested with a duplex stream at 2 Msps. Co-authored-by: adrian <adrian@qradiolink.org>
1 parent cdce239 commit 0646ea3

3 files changed

Lines changed: 77 additions & 13 deletions

File tree

PlutoSDR_Settings.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,8 @@ void SoapyPlutoSDR::setSampleRate( const int direction, const size_t channel, co
590590

591591
iio_channel_attr_write_longlong(iio_device_find_channel(dev, "voltage0", true),"sampling_frequency", samplerate);
592592
iio_channel_attr_write_longlong(iio_device_find_channel(tx_dev, "voltage0", true), "sampling_frequency", interpolation?samplerate / 8:samplerate);
593+
if(tx_stream)
594+
tx_stream->set_buffer_size_by_samplerate(interpolation ? samplerate / 8 : samplerate);
593595

594596
}
595597

PlutoSDR_Streaming.cpp

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ size_t SoapyPlutoSDR::getStreamMTU( SoapySDR::Stream *handle) const
173173
}
174174

175175
if (IsValidTxStreamHandle(handle)) {
176-
return 4096;
176+
return this->tx_stream->get_mtu_size();
177177
}
178178

179179
return 0;
@@ -605,14 +605,11 @@ tx_streamer::tx_streamer(const iio_device *_dev, const plutosdrStreamFormat _for
605605
iio_channel_enable(chn);
606606
channel_list.push_back(chn);
607607
}
608+
long long samplerate;
608609

609-
buf_size = 4096;
610-
items_in_buf = 0;
611-
buf = iio_device_create_buffer(dev, buf_size, false);
612-
if (!buf) {
613-
SoapySDR_logf(SOAPY_SDR_ERROR, "Unable to create buffer!");
614-
throw std::runtime_error("Unable to create buffer!");
615-
}
610+
iio_channel_attr_read_longlong(iio_device_find_channel(dev, "voltage0", true),"sampling_frequency",&samplerate);
611+
612+
this->set_buffer_size_by_samplerate(samplerate);
616613

617614
direct_copy = has_direct_copy();
618615

@@ -629,6 +626,66 @@ tx_streamer::~tx_streamer(){
629626

630627
}
631628

629+
void tx_streamer::set_buffer_size_by_samplerate(const size_t samplerate) {
630+
631+
// The original buffer size of 4096 is not enough for a full duplex stream at sample rates above 1 Msps
632+
// Avoid samples getting dropped in the TX stream by setting a high enough buffer size.
633+
// Apply the same logic as for the rx_streamer buffer. Keep it a power of 2 which seems to be better.
634+
int rounded_nb_samples_per_call = (int)::round(samplerate / 60.0);
635+
636+
int power_of_2_nb_samples = 0;
637+
638+
while (rounded_nb_samples_per_call > (1 << power_of_2_nb_samples)) {
639+
power_of_2_nb_samples++;
640+
}
641+
642+
this->set_buffer_size(1 << power_of_2_nb_samples);
643+
644+
SoapySDR_logf(SOAPY_SDR_INFO, "Auto setting TX Buffer Size: %lu", (unsigned long)buffer_size);
645+
646+
//Recompute transmit MTU from buffer size change.
647+
//We always set MTU size = Buffer Size.
648+
//On buffer size adjustment to sample rate,
649+
//MTU can be changed accordingly safely here.
650+
set_mtu_size(this->buffer_size);
651+
}
652+
653+
void tx_streamer::set_mtu_size(const size_t mtu_size) {
654+
655+
this->mtu_size = mtu_size;
656+
657+
SoapySDR_logf(SOAPY_SDR_INFO, "Set TX MTU Size: %lu", (unsigned long)mtu_size);
658+
}
659+
660+
void tx_streamer::set_buffer_size(const size_t _buffer_size){
661+
662+
if (!buf || this->buffer_size != _buffer_size) {
663+
//cancel first
664+
if (buf) {
665+
iio_buffer_cancel(buf);
666+
}
667+
//then destroy
668+
if (buf) {
669+
iio_buffer_destroy(buf);
670+
}
671+
672+
items_in_buf = 0;
673+
674+
buf = iio_device_create_buffer(dev, _buffer_size, false);
675+
if (!buf) {
676+
SoapySDR_logf(SOAPY_SDR_ERROR, "Unable to create TX buffer!");
677+
throw std::runtime_error("Unable to create TX buffer!\n");
678+
}
679+
680+
}
681+
682+
this->buffer_size=_buffer_size;
683+
}
684+
685+
size_t tx_streamer::get_mtu_size() {
686+
return this->mtu_size;
687+
}
688+
632689
int tx_streamer::send( const void * const *buffs,
633690
const size_t numElems,
634691
int &flags,
@@ -640,7 +697,7 @@ int tx_streamer::send( const void * const *buffs,
640697
return 0;
641698
}
642699

643-
size_t items = std::min(buf_size - items_in_buf, numElems);
700+
size_t items = std::min(this->buffer_size - items_in_buf, numElems);
644701

645702
int16_t src = 0;
646703
int16_t const *src_ptr = &src;
@@ -729,14 +786,14 @@ int tx_streamer::send( const void * const *buffs,
729786

730787
items_in_buf += items;
731788

732-
if (items_in_buf == buf_size || (flags & SOAPY_SDR_END_BURST && numElems == items)) {
789+
if (items_in_buf == this->buffer_size || (flags & SOAPY_SDR_END_BURST && numElems == items)) {
733790
int ret = send_buf();
734791

735792
if (ret < 0) {
736793
return SOAPY_SDR_ERROR;
737794
}
738795

739-
if ((size_t)ret != buf_size) {
796+
if ((size_t)ret != this->buffer_size) {
740797
return SOAPY_SDR_ERROR;
741798
}
742799
}
@@ -757,7 +814,7 @@ int tx_streamer::send_buf()
757814
}
758815

759816
if (items_in_buf > 0) {
760-
if (items_in_buf < buf_size) {
817+
if (items_in_buf < this->buffer_size) {
761818
ptrdiff_t buf_step = iio_buffer_step(buf);
762819
uint8_t *buf_ptr = (uint8_t *)iio_buffer_start(buf) + items_in_buf * buf_step;
763820
uint8_t *buf_end = (uint8_t *)iio_buffer_end(buf);

SoapyPlutoSDR.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,12 @@ class tx_streamer {
6363
~tx_streamer();
6464
int send(const void * const *buffs,const size_t numElems,int &flags,const long long timeNs,const long timeoutUs );
6565
int flush();
66+
void set_buffer_size_by_samplerate(const size_t _samplerate);
67+
size_t get_mtu_size();
6668

6769
private:
70+
void set_buffer_size(const size_t _buffer_size);
71+
void set_mtu_size(const size_t mtu_size);
6872
int send_buf();
6973
bool has_direct_copy();
7074

@@ -73,9 +77,10 @@ class tx_streamer {
7377
const plutosdrStreamFormat format;
7478

7579
iio_buffer *buf;
76-
size_t buf_size;
7780
size_t items_in_buf;
7881
bool direct_copy;
82+
size_t buffer_size;
83+
size_t mtu_size;
7984

8085
};
8186

0 commit comments

Comments
 (0)