Skip to content

Commit f8fd4de

Browse files
src/oscilloscope.cpp: Fix crash in streaming mode.
After 200ms/div, the tool enters streaming mode, which makes use of kernel buffers to acquire data in smaller chunks. There are 2 scenarios: -the trigger is inside the visible buffer and the buffer size is restricted by the trigger value; -the trigger is 0, which means we get to manipulate the best values for buffersize and number of kernel buffers. Also, the time position handle needs some limits when the time base is over the timebase threshold. Signed-off-by: Alexandra Trifan <Alexandra.Trifan@analog.com>
1 parent 604c993 commit f8fd4de

File tree

1 file changed

+60
-16
lines changed

1 file changed

+60
-16
lines changed

src/oscilloscope.cpp

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ using namespace libm2k;
9898
using namespace libm2k::context;
9999
using namespace std::placeholders;
100100

101+
constexpr int MAX_BUFFER_SIZE_STREAM = 1024 * 1024;
102+
constexpr int MAX_KERNEL_BUFFERS = 64;
103+
101104
Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt,
102105
ToolMenuItem *toolMenuItem,
103106
QJSEngine *engine, ToolLauncher *parent) :
@@ -159,7 +162,7 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt,
159162
if (m_m2k_analogin) {
160163
symmBufferMode = make_shared<SymmetricBufferMode>();
161164
symmBufferMode->setSampleRates(m_m2k_analogin->getAvailableSampleRates());
162-
symmBufferMode->setEntireBufferMaxSize(64000);
165+
symmBufferMode->setEntireBufferMaxSize(MAX_BUFFER_SIZE_STREAM);
163166
symmBufferMode->setTriggerBufferMaxSize(8192); // 8192 is what hardware supports
164167
symmBufferMode->setTimeDivisionCount(plot.xAxisNumDiv());
165168
}
@@ -547,7 +550,7 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt,
547550
{"h", 36E2}
548551
}, tr("Position"),
549552
-timeBase->maxValue() * 5,
550-
36E2,
553+
36E3,
551554
true, false, this);
552555
voltsPerDiv = new ScaleSpinButton({
553556
// {"μVolts", 1E-6},
@@ -563,8 +566,8 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt,
563566
-25, 25, true, false, this);
564567

565568
plot.setOffsetInterval(-DBL_MAX, DBL_MAX);
566-
plot.setTimeTriggerInterval(-timeBase->maxValue() * 5,
567-
timeBase->maxValue() * 5);
569+
plot.setTimeTriggerInterval(-36E2,
570+
timeBase->maxValue() * 5);
568571

569572
ch_ui = new Ui::ChannelSettings();
570573
ch_ui->setupUi(ui->channelSettings);
@@ -3594,7 +3597,7 @@ void Oscilloscope::onCmbMemoryDepthChanged(QString value)
35943597
power = ceil(log2(active_plot_sample_count));
35953598
}
35963599
fft_plot_size = pow(2, power);
3597-
fft_size = active_sample_count;
3600+
fft_size = active_plot_sample_count;
35983601
onFFT_view_toggled(fft_is_visible);
35993602

36003603
updateBufferPreviewer();
@@ -3603,6 +3606,8 @@ void Oscilloscope::onCmbMemoryDepthChanged(QString value)
36033606
toggle_blockchain_flow(true);
36043607
}
36053608
resetStreamingFlag(true);
3609+
double maxT = (1 << 13) * (1.0 / active_sample_rate) - 1.0 / active_sample_rate * active_plot_sample_count / 2.0;
3610+
plot.setTimeTriggerInterval(-36E2, maxT);
36063611
}
36073612

36083613
void Oscilloscope::setSinksDisplayOneBuffer(bool val)
@@ -3654,14 +3659,52 @@ void adiscope::Oscilloscope::onHorizScaleValueChanged(double value)
36543659

36553660
ch_ui->cmbMemoryDepth->setCurrentIndex(0);
36563661
if (timeBase->value() >= TIMEBASE_THRESHOLD) {
3657-
plot_samples_sequentially = true;
3658-
if (active_sample_count != -active_trig_sample_count) {
3659-
active_sample_count = ((-active_trig_sample_count + 3) / 4) * 4;
3660-
setSinksDisplayOneBuffer(false);
3661-
plot.setXAxisNumPoints(active_plot_sample_count);
3662-
resetStreamingFlag(true);
3662+
plot_samples_sequentially = true; // streaming
3663+
const int minKernelBuffers = 4;
3664+
const int oneBufferMaxSize = 2 * 1024 * 1024; // 2M
3665+
int m_currentKernelBuffers = minKernelBuffers;
3666+
if (active_trig_sample_count < 0) {
3667+
active_sample_count = -active_trig_sample_count;
3668+
m_currentKernelBuffers = (active_plot_sample_count / active_sample_count) + 1;
3669+
active_sample_count = (( active_sample_count + 3) / 4) * 4;
3670+
m_currentKernelBuffers = (m_currentKernelBuffers > MAX_KERNEL_BUFFERS) ? MAX_KERNEL_BUFFERS : m_currentKernelBuffers;
3671+
m_currentKernelBuffers = (m_currentKernelBuffers < minKernelBuffers) ? minKernelBuffers : m_currentKernelBuffers;
3672+
} else { // still streaming but without trigger contraints
3673+
/* ensure we have the minimum amount of kernel buffers to fit the buffer */
3674+
while (active_plot_sample_count > (m_currentKernelBuffers * oneBufferMaxSize)
3675+
&& m_currentKernelBuffers < MAX_KERNEL_BUFFERS) {
3676+
m_currentKernelBuffers++;
3677+
}
3678+
3679+
/* ensure we don't spend more than 100ms on a acquiring a buffer if we can
3680+
* further divide it into smaller buffers */
3681+
const double maxCaptureDuration = 0.1;
3682+
while (((static_cast<double>(active_plot_sample_count) / active_sample_rate)
3683+
/ static_cast<double>(m_currentKernelBuffers)) > maxCaptureDuration
3684+
&& m_currentKernelBuffers < MAX_KERNEL_BUFFERS) {
3685+
m_currentKernelBuffers++;
3686+
}
3687+
uint64_t chunk_size = active_plot_sample_count / m_currentKernelBuffers;
3688+
uint64_t chunkSizeBeforeAdjust = chunk_size;
3689+
chunk_size = 4 * (chunk_size / 4);
3690+
3691+
/* If the chunk_size was not divisible by 4 in the first place we would get a smaller value for it. */
3692+
if (chunk_size + 4 <= oneBufferMaxSize && chunkSizeBeforeAdjust != chunk_size) {
3693+
chunk_size += 4;
3694+
}
3695+
3696+
// If the buffer size is > 64 * 4M we need to cap the chunk_size to 4M
3697+
if (chunk_size > oneBufferMaxSize) {
3698+
chunk_size = oneBufferMaxSize;
3699+
}
3700+
active_sample_count = chunk_size;
36633701
}
3702+
setSinksDisplayOneBuffer(false);
3703+
plot.setXAxisNumPoints(active_plot_sample_count);
3704+
resetStreamingFlag(true);
3705+
iio->set_kernel_buffer_count(m_currentKernelBuffers);
36643706
} else {
3707+
iio->set_kernel_buffer_count();
36653708
plot_samples_sequentially = false;
36663709
setSinksDisplayOneBuffer(true);
36673710
plot.setXAxisNumPoints(0);
@@ -3698,6 +3741,8 @@ void adiscope::Oscilloscope::onHorizScaleValueChanged(double value)
36983741
timePosition->setValue(-params.timePos);
36993742
}
37003743

3744+
iio->set_device_timeout((active_sample_count / active_sample_rate) * 1000 + 100);
3745+
37013746
for (unsigned int i = 0; i < nb_channels; i++) {
37023747
iio->set_buffer_size(ids[i], active_sample_count);
37033748
dc_cancel.at(i)->set_buffer_size(active_sample_count);
@@ -3708,10 +3753,6 @@ void adiscope::Oscilloscope::onHorizScaleValueChanged(double value)
37083753
setDigitalPlotCurvesParams();
37093754
}
37103755

3711-
3712-
iio->set_device_timeout((active_sample_count / active_sample_rate) * 1000 + 100);
3713-
3714-
37153756
if (started) {
37163757
iio->unlock();
37173758
}
@@ -3729,13 +3770,16 @@ void adiscope::Oscilloscope::onHorizScaleValueChanged(double value)
37293770
power = ceil(log2(active_plot_sample_count));
37303771
}
37313772
fft_plot_size = pow(2, power);
3732-
fft_size = active_sample_count;
3773+
fft_size = active_plot_sample_count;
37333774
onFFT_view_toggled(fft_is_visible);
37343775

37353776
// Change the sensitivity of time position control
37363777
timePosition->setStep(value / 10);
37373778

37383779
updateBufferPreviewer();
3780+
3781+
double maxT = (1 << 13) * (1.0 / active_sample_rate) - 1.0 / active_sample_rate * active_plot_sample_count / 2.0;
3782+
plot.setTimeTriggerInterval(-36E2, maxT);
37393783
}
37403784

37413785
bool adiscope::Oscilloscope::gainUpdateNeeded()

0 commit comments

Comments
 (0)