From 559b43331a4c8c28dcb1397a122975c6f3cc1ffa Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Sun, 9 Aug 2026 17:55:54 +0200 Subject: [PATCH 1/6] SPIDecoder: Add CPHA and LSB/MSB option --- scopeprotocols/SPIDecoder.cpp | 115 +++++++++++++++++++++------------- scopeprotocols/SPIDecoder.h | 5 ++ 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/scopeprotocols/SPIDecoder.cpp b/scopeprotocols/SPIDecoder.cpp index 36b82c70..2e965fe6 100644 --- a/scopeprotocols/SPIDecoder.cpp +++ b/scopeprotocols/SPIDecoder.cpp @@ -45,6 +45,8 @@ using namespace std; SPIDecoder::SPIDecoder(const string& color) : Filter(color, CAT_BUS) , m_cpol(m_parameters["Clock Polarity"]) + , m_cpha(m_parameters["Clock Phase Alignment"]) + , m_bendian(m_parameters["Byte Endianness"]) { AddProtocolStream("data"); CreateInput("clk", Stream::STREAM_TYPE_DIGITAL); @@ -55,6 +57,16 @@ SPIDecoder::SPIDecoder(const string& color) m_cpol.AddEnumValue("Idle low", 0); m_cpol.AddEnumValue("Idle high", 1); m_cpol.SetIntVal(0); + + m_cpha = FilterParameter(FilterParameter::TYPE_ENUM, Unit(Unit::UNIT_COUNTS)); + m_cpha.AddEnumValue("Sample Rising CLK", 0); + m_cpha.AddEnumValue("Sample Falling CLK", 1); + m_cpha.SetIntVal(0); + + m_bendian = FilterParameter(FilterParameter::TYPE_ENUM, Unit(Unit::UNIT_COUNTS)); + m_bendian.AddEnumValue("LSB First", 0); + m_bendian.AddEnumValue("MSB First", 1); + m_bendian.SetIntVal(1); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -66,8 +78,57 @@ string SPIDecoder::GetProtocolName() } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Actual decoder logic +// Sample the current data-bit. +void SPIDecoder::sampleBit(SPIWaveform* cap, size_t timestamp, int endian, uint8_t& current_byte, uint8_t& bitcount, int64_t& bytestart, + bool cur_data, bool first) +{ + if(bitcount == 0) + { + //Add a "chip selected" event + if(first) + { + cap->m_offsets.push_back(bytestart); + cap->m_durations.push_back(timestamp - bytestart); + cap->m_samples.push_back(SPISymbol(SPISymbol::TYPE_SELECT, 0)); + first = false; + } + + //Extend the last byte until this edge + else if(!cap->m_samples.empty()) + { + size_t ilast = cap->m_samples.size()-1; + if(cap->m_samples[ilast].m_stype == SPISymbol::TYPE_DATA) + cap->m_durations[ilast] = timestamp- cap->m_offsets[ilast]; + } + + bytestart = timestamp; + } + + if(endian == 0) { // LSB + if(cur_data) + current_byte = (1 << bitcount) | current_byte; + } else { // MSB + if(cur_data) + current_byte = 1 | (current_byte << 1); + else + current_byte = (current_byte << 1); + } + bitcount ++; + + if(bitcount == 8) + { + cap->m_offsets.push_back(bytestart); + cap->m_durations.push_back(timestamp - bytestart); + cap->m_samples.push_back(SPISymbol(SPISymbol::TYPE_DATA, current_byte)); + + bitcount = 0; + current_byte = 0; + bytestart = timestamp; + } +} + +// Actual decoder logic void SPIDecoder::Refresh( [[maybe_unused]] vk::raii::CommandBuffer& cmdBuf, [[maybe_unused]] shared_ptr queue @@ -107,8 +168,6 @@ void SPIDecoder::Refresh( cap->m_triggerPhase = 0; cap->PrepareForCpuAccess(); - //TODO: different cpha/cpol modes - //TODO: packets based on CS# pulses? //Loop over the data and look for transactions @@ -137,6 +196,9 @@ void SPIDecoder::Refresh( //Get SPI clock polarity auto cpol = m_cpol.GetIntVal(); + auto cpha = m_cpha.GetIntVal(); + // LSB/MSB for data + auto endian = m_bendian.GetIntVal(); bool active_clk; if(cpol == 0) @@ -175,47 +237,9 @@ void SPIDecoder::Refresh( case STATE_SELECTED_CLK_INACTIVE: if(cur_clk == active_clk) { - if(bitcount == 0) - { - //Add a "chip selected" event - if(first) - { - cap->m_offsets.push_back(bytestart); - cap->m_durations.push_back(timestamp - bytestart); - cap->m_samples.push_back(SPISymbol(SPISymbol::TYPE_SELECT, 0)); - first = false; - } - - //Extend the last byte until this edge - else if(!cap->m_samples.empty()) - { - size_t ilast = cap->m_samples.size()-1; - if(cap->m_samples[ilast].m_stype == SPISymbol::TYPE_DATA) - cap->m_durations[ilast] = timestamp - cap->m_offsets[ilast]; - } - - bytestart = timestamp; - } - + if(cpha == 0) + sampleBit(cap, timestamp, endian, current_byte, bitcount, bytestart, cur_data, first); state = STATE_SELECTED_CLK_ACTIVE; - - //TODO: selectable msb/lsb first direction - bitcount ++; - if(cur_data) - current_byte = 1 | (current_byte << 1); - else - current_byte = (current_byte << 1); - - if(bitcount == 8) - { - cap->m_offsets.push_back(bytestart); - cap->m_durations.push_back(timestamp - bytestart); - cap->m_samples.push_back(SPISymbol(SPISymbol::TYPE_DATA, current_byte)); - - bitcount = 0; - current_byte = 0; - bytestart = timestamp; - } } //end of packet @@ -233,8 +257,11 @@ void SPIDecoder::Refresh( //wait for falling edge of clk case STATE_SELECTED_CLK_ACTIVE: - if(cur_clk != active_clk) + if(cur_clk != active_clk) { + if(cpha == 1) + sampleBit(cap, timestamp, endian, current_byte, bitcount, bytestart, cur_data, first); state = STATE_SELECTED_CLK_INACTIVE; + } //end of packet //TODO: error if a byte is truncated diff --git a/scopeprotocols/SPIDecoder.h b/scopeprotocols/SPIDecoder.h index 5e612bc4..25a804f7 100644 --- a/scopeprotocols/SPIDecoder.h +++ b/scopeprotocols/SPIDecoder.h @@ -85,6 +85,11 @@ class SPIDecoder : public Filter protected: FilterParameter& m_cpol; + FilterParameter& m_cpha; + // Bit endianess + FilterParameter& m_bendian; + void sampleBit(SPIWaveform*, size_t timestamp, int endian, uint8_t& current_byte, uint8_t& bitcount, int64_t& bytestart, + bool cur_data, bool first); }; #endif From f533342f6a2c497bde9d528bea4841299de44611 Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Tue, 11 Aug 2026 21:57:36 +0200 Subject: [PATCH 2/6] Add Decoder for the DAC8552 SPI protocol. DAC8552 is a 16-bit dual-channel SPI-controlled DAC. It's message consists of 24 bit. The first byte is a control-header specifying what register to update and what register contents to push out to the DAC. The second and third byte are the 16-bit value to be loaded into either register. The implementation of the Decoder is basically identical to the `ADL5205Decoder`. I am thinking of merging the 2 into children of a general CPUSPIByteDecoder class as it seems to me that more decoders that just decode SPI-Traffic are to come. The only things, which are fundamentally different is the state machine, that loops over all `SPISymbol` and `GetText()`-Method. --- scopeprotocols/CMakeLists.txt | 1 + scopeprotocols/DAC8552Decoder.cpp | 145 ++++++++++++++++++++++++++++++ scopeprotocols/DAC8552Decoder.h | 85 ++++++++++++++++++ scopeprotocols/scopeprotocols.cpp | 1 + scopeprotocols/scopeprotocols.h | 1 + 5 files changed, 233 insertions(+) create mode 100644 scopeprotocols/DAC8552Decoder.cpp create mode 100644 scopeprotocols/DAC8552Decoder.h diff --git a/scopeprotocols/CMakeLists.txt b/scopeprotocols/CMakeLists.txt index 58758578..37dce387 100644 --- a/scopeprotocols/CMakeLists.txt +++ b/scopeprotocols/CMakeLists.txt @@ -28,6 +28,7 @@ set(SCOPEPROTOCOLS_SOURCES CSVImportFilter.cpp CTLEFilter.cpp CurrentShuntFilter.cpp + DAC8552Decoder.cpp DCDMeasurement.cpp DDJMeasurement.cpp DDR1Decoder.cpp diff --git a/scopeprotocols/DAC8552Decoder.cpp b/scopeprotocols/DAC8552Decoder.cpp new file mode 100644 index 00000000..b08ca089 --- /dev/null +++ b/scopeprotocols/DAC8552Decoder.cpp @@ -0,0 +1,145 @@ + +/*********************************************************************************************************************** +* * +* libscopeprotocols * +* * +* Copyright (c) 2012-2026 Andrew D. Zonenberg and contributors * +* All rights reserved. * +* * +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the * +* following conditions are met: * +* * +* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other materials provided with the distribution. * +* * +* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products * +* derived from this software without specific prior written permission. * +* * +* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * +* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * +* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * +* POSSIBILITY OF SUCH DAMAGE. * +* * +***********************************************************************************************************************/ + +#include "../scopehal/scopehal.h" +#include "DAC8552Decoder.h" +#include "SPIDecoder.h" + +using namespace std; + +DAC8552Decoder::DAC8552Decoder(const string& color) + : Filter(color, CAT_MISC) +{ + AddProtocolStream("data"); + CreateInput>("spi"); +} + +string DAC8552Waveform::GetColor(size_t) +{ + return m_color; +} + +string DAC8552Waveform::GetText(size_t i) +{ + const DAC8552Symbol& s = m_samples[i]; + + char tmp[128]; + snprintf(tmp, sizeof(tmp), "Load %s %s, Bfr=%c, Value=%d", + s.loadA() ? "A" : "", s.loadB() ? "B" : "", s.bfrSelect() ? 'A' : 'B', s.m_value); + return string(tmp); +} + +string DAC8552Decoder::GetProtocolName() +{ + return "DAC8552"; +} + +void DAC8552Decoder::Refresh( + [[maybe_unused]] vk::raii::CommandBuffer& cmdBuf, + [[maybe_unused]] shared_ptr queue) +{ + ClearMessages(); + + if(!VerifyAllInputsOK()) + { + if(!GetInput(0)) + AddErrorMessage("Missing inputs", "No signal input connected"); + else if(!GetInputWaveform(0)) + AddErrorMessage("Missing inputs", "No waveform available at input"); + SetData(nullptr, 0); + return; + } + + auto din = dynamic_cast(GetInputWaveform(0)); + if(!din) + { + AddErrorMessage("Missing inputs", "Invalid input connected"); + SetData(nullptr, 0); + return; + } + size_t len = din->m_samples.size(); + + auto cap = new DAC8552Waveform(m_displaycolor); + cap->m_timescale = din->m_timescale; + cap->m_startTimestamp = din->m_startTimestamp; + cap->m_startFemtoseconds = din->m_startFemtoseconds; + cap->PrepareForCpuAccess(); + din->PrepareForCpuAccess(); + DAC8552Symbol samp; + int state = 0; + int64_t offset = 0; + + for(size_t i=0; im_samples[i]; + + switch(state) + { + case 0: + if(s.m_stype == SPISymbol::TYPE_SELECT) + state = 1; + break; + case 1: + if(s.m_stype == SPISymbol::TYPE_DATA) + { + offset = din->m_offsets[i]; + samp.m_flags = s.m_data & (DAC8552Symbol::MASK_LOAD_A | DAC8552Symbol::MASK_LOAD_B | DAC8552Symbol::MASK_BFR_SEL); + state = 2; + } else + state = 0; + break; + case 2: + if(s.m_stype == SPISymbol::TYPE_DATA) + { + samp.m_value = static_cast(s.m_data) << 8; + state = 3; + } else + state = 0; + break; + case 3: + if(s.m_stype == SPISymbol::TYPE_DATA) + { + samp.m_value |= s.m_data; + cap->m_offsets.push_back(offset); + cap->m_durations.push_back(din->m_offsets[i] + din->m_durations[i] - offset); + cap->m_samples.push_back(samp); + state = 4; + } else + state = 0; + break; + case 4: + if(s.m_stype == SPISymbol::TYPE_DESELECT) + state = 0; + break; + } + } + cap->MarkSamplesModifiedFromCpu(); + cap->MarkTimestampsModifiedFromCpu(); + SetData(cap, 0); +} diff --git a/scopeprotocols/DAC8552Decoder.h b/scopeprotocols/DAC8552Decoder.h new file mode 100644 index 00000000..4ca07423 --- /dev/null +++ b/scopeprotocols/DAC8552Decoder.h @@ -0,0 +1,85 @@ + +/*********************************************************************************************************************** +* * +* libscopeprotocols * +* * +* Copyright (c) 2012-2026 Andrew D. Zonenberg and contributors * +* All rights reserved. * +* * +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the * +* following conditions are met: * +* * +* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other materials provided with the distribution. * +* * +* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products * +* derived from this software without specific prior written permission. * +* * +* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * +* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * +* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * +* POSSIBILITY OF SUCH DAMAGE. * +* * +***********************************************************************************************************************/ + +/** + @file + @author Daniel Bauer + @brief Declaration of DAC8552Decoder +*/ +#ifndef DAC8522Decoder_h +#define DAC8522Decoder_h + +class DAC8552Symbol +{ +public: + DAC8552Symbol(uint8_t flags = 0, uint16_t value=0xDEAD) + : m_flags(flags) + , m_value(value) + {} + // Rather store all the flags in 1 byte instead of making the struct 5 bytes large and then get funky padding + // This will most likely get padded to a nice handy integer + static constexpr uint8_t MASK_LOAD_A = 0x10; + static constexpr uint8_t MASK_LOAD_B = 0x20; + static constexpr uint8_t MASK_BFR_SEL = 0x04; + uint8_t m_flags; + uint16_t m_value; + + bool operator==(const DAC8552Symbol& s) const + { + return (m_flags == s.m_flags) && (m_value == s.m_value); + } + bool loadA() const { return m_flags & MASK_LOAD_A ? true : false; } + bool loadB() const { return m_flags & MASK_LOAD_B ? true : false; } + bool bfrSelect() const { return m_flags & MASK_BFR_SEL ? true : false; } +}; + +class DAC8552Waveform : public SparseWaveform +{ +public: + DAC8552Waveform (const std::string& color) : SparseWaveform(), m_color(color) {}; + virtual std::string GetText(size_t override); + virtual std::string GetColor(size_t override); + +private: + const std::string& m_color; +}; + +class DAC8552Decoder : public Filter +{ +public: + DAC8552Decoder(const std::string& color); + + virtual void Refresh(vk::raii::CommandBuffer& cmdBuf, std::shared_ptr queue) override; + static std::string GetProtocolName(); + + PROTOCOL_DECODER_INITPROC(DAC8552Decoder) +}; + +#endif diff --git a/scopeprotocols/scopeprotocols.cpp b/scopeprotocols/scopeprotocols.cpp index 6d2ebeb9..644a8701 100644 --- a/scopeprotocols/scopeprotocols.cpp +++ b/scopeprotocols/scopeprotocols.cpp @@ -69,6 +69,7 @@ void ScopeProtocolStaticInit() AddDecoderClass(CSVImportFilter); AddDecoderClass(CTLEFilter); AddDecoderClass(CurrentShuntFilter); + AddDecoderClass(DAC8552Decoder); AddDecoderClass(DCDMeasurement); AddDecoderClass(DDJMeasurement); AddDecoderClass(DDR1Decoder); diff --git a/scopeprotocols/scopeprotocols.h b/scopeprotocols/scopeprotocols.h index 3daee910..fa9f1da8 100644 --- a/scopeprotocols/scopeprotocols.h +++ b/scopeprotocols/scopeprotocols.h @@ -68,6 +68,7 @@ #include "CSVImportFilter.h" #include "CTLEFilter.h" #include "CurrentShuntFilter.h" +#include "DAC8552Decoder.h" #include "DCDMeasurement.h" #include "DDJMeasurement.h" #include "DDR1Decoder.h" From f51f192cd62ca039fbc3d0a24518cf0c2656c765 Mon Sep 17 00:00:00 2001 From: "Andrew D. Zonenberg" Date: Wed, 12 Aug 2026 00:32:40 -0700 Subject: [PATCH 3/6] JitterSpectrumFilter: we are FFTFilter derived so need to advertise ourselves as not tail call capable until we fix our input handling. Fixes #1107. --- scopeprotocols/JitterSpectrumFilter.cpp | 19 +++++++++++++++++++ scopeprotocols/JitterSpectrumFilter.h | 1 + 2 files changed, 20 insertions(+) diff --git a/scopeprotocols/JitterSpectrumFilter.cpp b/scopeprotocols/JitterSpectrumFilter.cpp index 4c77a850..f5551efa 100644 --- a/scopeprotocols/JitterSpectrumFilter.cpp +++ b/scopeprotocols/JitterSpectrumFilter.cpp @@ -158,6 +158,12 @@ size_t JitterSpectrumFilter::EstimateUIWidth(SparseAnalogWaveform* din) return ui_width; } +uint32_t JitterSpectrumFilter::GetExecutionCapabilitiesMask() +{ + //for now, not tail call capable since we do CPU side input preprocessing + return 0; +} + void JitterSpectrumFilter::Refresh(vk::raii::CommandBuffer& cmdBuf, shared_ptr queue) { #ifdef HAVE_NVTX @@ -165,6 +171,7 @@ void JitterSpectrumFilter::Refresh(vk::raii::CommandBuffer& cmdBuf, shared_ptr(GetInput(0).GetData()); if(!din) { @@ -218,5 +225,17 @@ void JitterSpectrumFilter::Refresh(vk::raii::CommandBuffer& cmdBuf, shared_ptrSubmitAndBlock(cmdBuf); + } } diff --git a/scopeprotocols/JitterSpectrumFilter.h b/scopeprotocols/JitterSpectrumFilter.h index 8427c053..88592866 100644 --- a/scopeprotocols/JitterSpectrumFilter.h +++ b/scopeprotocols/JitterSpectrumFilter.h @@ -44,6 +44,7 @@ class JitterSpectrumFilter : public FFTFilter virtual ~JitterSpectrumFilter(); virtual void Refresh(vk::raii::CommandBuffer& cmdBuf, std::shared_ptr queue) override; + virtual uint32_t GetExecutionCapabilitiesMask() override; //This is intentionally not virtual since it's a static method used by enumeration //cppcheck-suppress duplInheritedMember From 8f6c960be6ac800d459eff0323962c1352fb30b4 Mon Sep 17 00:00:00 2001 From: "Andrew D. Zonenberg" Date: Wed, 12 Aug 2026 01:11:49 -0700 Subject: [PATCH 4/6] Fixed more bugs in JitterSpectrumFilter --- scopeprotocols/JitterSpectrumFilter.cpp | 50 +++++++++++++++---------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/scopeprotocols/JitterSpectrumFilter.cpp b/scopeprotocols/JitterSpectrumFilter.cpp index f5551efa..363df482 100644 --- a/scopeprotocols/JitterSpectrumFilter.cpp +++ b/scopeprotocols/JitterSpectrumFilter.cpp @@ -41,7 +41,7 @@ using namespace std; JitterSpectrumFilter::JitterSpectrumFilter(const string& color) : FFTFilter(color) { - m_xAxisUnit = Unit(Unit::UNIT_HZ); + m_xAxisUnit = Unit(Unit::UNIT_MICROHZ); SetYAxisUnits(Unit(Unit::UNIT_FS), 0); m_category = CAT_ANALYSIS; @@ -160,7 +160,20 @@ size_t JitterSpectrumFilter::EstimateUIWidth(SparseAnalogWaveform* din) uint32_t JitterSpectrumFilter::GetExecutionCapabilitiesMask() { - //for now, not tail call capable since we do CPU side input preprocessing + //for now, not append capable since we do CPU side input preprocessing + /*if(m_numpeaks.GetIntVal() > 0) + { + return + //(uint32_t)ExecutionCapabilities::CommandBufferAppend | + (uint32_t)ExecutionCapabilities::VulkanOnly; + } + else + { + return + //(uint32_t)ExecutionCapabilities::CommandBufferAppend | + (uint32_t)ExecutionCapabilities::CommandBufferTailCall | + (uint32_t)ExecutionCapabilities::VulkanOnly; + }*/ return 0; } @@ -196,45 +209,44 @@ void JitterSpectrumFilter::Refresh(vk::raii::CommandBuffer& cmdBuf, shared_ptr extended_samples; - extended_samples.reserve(inlen); + ScratchBuffer_float32_t extended_samples(ScratchBufferManager::F32_GPU_WAVEFORM); + extended_samples->PrepareForCpuAccess(); + extended_samples->resize(0); + extended_samples->reserve(inlen); for(size_t i=0; im_durations[i] / ui_width); for(int64_t j=0; jm_samples[i]); + extended_samples->push_back(din->m_samples[i]); } + extended_samples->MarkModifiedFromCpu(); //Refine our estimate of the final UI width. //This needs to be fairly precise as the timebase for converting FFT bins to frequency is derived from it. size_t capture_duration = din->m_offsets[inlen-1] + din->m_durations[inlen-1]; - size_t num_uis = extended_samples.size(); + size_t num_uis = extended_samples->size(); double ui_width_final = static_cast(capture_duration) / num_uis; LogTrace("Capture is %zu UIs, %s\n", num_uis, Unit(Unit::UNIT_FS).PrettyPrint(capture_duration).c_str()); LogTrace("Final UI width estimate: %s\n", Unit(Unit::UNIT_FS).PrettyPrint(ui_width_final).c_str()); - //Round size up to next power of two - const size_t npoints_raw = extended_samples.size(); - const size_t npoints = next_pow2(npoints_raw); - LogTrace("JitterSpectrumFilter: processing %zu raw points\n", npoints_raw); - LogTrace("Rounded to %zu\n", npoints); - //Reallocate buffers if size has changed - const size_t nouts = npoints/2 + 1; - if(m_cachedNumPoints != npoints_raw) - ReallocateBuffers(npoints_raw, npoints, nouts); + const size_t nouts = num_uis/2 + 1; + if(m_cachedNumPoints != num_uis) + ReallocateBuffers(num_uis, num_uis, nouts); //and do the actual FFT processing - //FIXME: CPU side processing + //FIXME: CPU side processing, so we need to open the command buffer ourself after doing the setup cmdBuf.begin({}); - DoRefresh(din, extended_samples, ui_width_final, npoints, nouts, false, cmdBuf, queue); + DoRefresh(din, *extended_samples, ui_width_final, num_uis, nouts, false, cmdBuf, queue); - //FIXME: DoRefresh will leave cmdbuf open if not doing peak detection - //since we are hacky with CPU side input processing, run the submit here until we fix trhings + //force a submit if not doing peak detection if(m_numpeaks.GetIntVal() == 0) { + //Mark the scratch buffer as in use until the command buffer finishes + queue->MarkScratchBufferUsed(extended_samples); + cmdBuf.end(); queue->SubmitAndBlock(cmdBuf); } From 48753fb8a788d78232f3096bb67690a08d4b4804 Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Wed, 12 Aug 2026 13:07:41 +0200 Subject: [PATCH 5/6] SPIdecoder: fix incorrectly using pass by value The previous refactor pulling out parseBit had the cur_data & first boolean flags passed as value. This lead to select symbols being inserted between every SPI symbol. I have no clue how this didn't show up in my testing, but only later when testing it in combination with my other decoder... --- scopeprotocols/SPIDecoder.cpp | 2 +- scopeprotocols/SPIDecoder.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scopeprotocols/SPIDecoder.cpp b/scopeprotocols/SPIDecoder.cpp index 2e965fe6..601ff033 100644 --- a/scopeprotocols/SPIDecoder.cpp +++ b/scopeprotocols/SPIDecoder.cpp @@ -81,7 +81,7 @@ string SPIDecoder::GetProtocolName() // Sample the current data-bit. void SPIDecoder::sampleBit(SPIWaveform* cap, size_t timestamp, int endian, uint8_t& current_byte, uint8_t& bitcount, int64_t& bytestart, - bool cur_data, bool first) + bool& cur_data, bool& first) { if(bitcount == 0) { diff --git a/scopeprotocols/SPIDecoder.h b/scopeprotocols/SPIDecoder.h index 25a804f7..b7e5360a 100644 --- a/scopeprotocols/SPIDecoder.h +++ b/scopeprotocols/SPIDecoder.h @@ -89,7 +89,7 @@ class SPIDecoder : public Filter // Bit endianess FilterParameter& m_bendian; void sampleBit(SPIWaveform*, size_t timestamp, int endian, uint8_t& current_byte, uint8_t& bitcount, int64_t& bytestart, - bool cur_data, bool first); + bool& cur_data, bool& first); }; #endif From 920f8e80e344c42c1d1b0a7ba69add0bf5a41987 Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Wed, 12 Aug 2026 22:41:39 +0200 Subject: [PATCH 6/6] DAC8552Decoder: Improve decoded message format The decoded package is now more intuitively readable. The Format was changed to ` Bufr=[A|B] ` --- scopeprotocols/DAC8552Decoder.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scopeprotocols/DAC8552Decoder.cpp b/scopeprotocols/DAC8552Decoder.cpp index b08ca089..8511c704 100644 --- a/scopeprotocols/DAC8552Decoder.cpp +++ b/scopeprotocols/DAC8552Decoder.cpp @@ -51,8 +51,10 @@ string DAC8552Waveform::GetText(size_t i) const DAC8552Symbol& s = m_samples[i]; char tmp[128]; - snprintf(tmp, sizeof(tmp), "Load %s %s, Bfr=%c, Value=%d", - s.loadA() ? "A" : "", s.loadB() ? "B" : "", s.bfrSelect() ? 'A' : 'B', s.m_value); + static const char* load_strs[] = {"No Load", "Load A", "Load B", "Load A&B"}; + const char* load_str = load_strs[s.loadA() ? (s.loadB() ? 3 : 1) : (s.loadB() ? 2 : 0)]; + snprintf(tmp, sizeof(tmp), "%s, Bfr=%c, Value=0x%04X", + load_str, s.bfrSelect() ? 'B' : 'A', s.m_value); return string(tmp); }