Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 7f3563b6885d
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ed4f684b8478
Choose a head ref
  • 5 commits
  • 6 files changed
  • 1 contributor

Commits on Oct 23, 2020

  1. Copy the full SHA
    d1ce0e1 View commit details
  2. Copy the full SHA
    a8b4944 View commit details
  3. Copy the full SHA
    437c00d View commit details
  4. Refactored SPIFlashDecoder to avoid compiler warning. There should ha…

    …ve been no "can't return" path but the control flow was too complex for the compiler to understand, so this leaves no doubt.
    azonenberg committed Oct 23, 2020
    Copy the full SHA
    95e293e View commit details
  5. Copy the full SHA
    ed4f684 View commit details
Showing with 131 additions and 74 deletions.
  1. +63 −3 scopehal/Filter.cpp
  2. +2 −0 scopehal/Filter.h
  3. +8 −1 scopehal/PulseWidthTrigger.cpp
  4. +47 −30 scopeprotocols/EyePattern.cpp
  5. +4 −5 scopeprotocols/SPIFlashDecoder.cpp
  6. +7 −35 scopeprotocols/UartClockRecoveryFilter.cpp
66 changes: 63 additions & 3 deletions scopehal/Filter.cpp
Original file line number Diff line number Diff line change
@@ -515,13 +515,13 @@ void Filter::FindZeroCrossings(AnalogWaveform* data, float threshold, std::vecto
}

/**
@brief Find zero crossings in a waveform, interpolating as necessary
@brief Find edges in a waveform, discarding repeated samples
*/
void Filter::FindZeroCrossings(DigitalWaveform* data, vector<int64_t>& edges)
{
//Find times of the zero crossings
bool first = true;
bool last = false;
bool last = data->m_samples[0];
int64_t phoff = data->m_timescale/2 + data->m_triggerPhase;
size_t len = data->m_samples.size();
for(size_t i=1; i<len; i++)
@@ -546,7 +546,67 @@ void Filter::FindZeroCrossings(DigitalWaveform* data, vector<int64_t>& edges)
}

/**
@brief Find zero crossings in a waveform, interpolating as necessary
@brief Find rising edges in a waveform
*/
void Filter::FindRisingEdges(DigitalWaveform* data, vector<int64_t>& edges)
{
//Find times of the zero crossings
bool first = true;
bool last = data->m_samples[0];
int64_t phoff = data->m_timescale/2 + data->m_triggerPhase;
size_t len = data->m_samples.size();
for(size_t i=1; i<len; i++)
{
bool value = data->m_samples[i];

//Save the last value
if(first)
{
last = value;
first = false;
continue;
}

//Save samples with an edge
if(value && !last)
edges.push_back(phoff + data->m_timescale * data->m_offsets[i]);

last = value;
}
}

/**
@brief Find falling edges in a waveform
*/
void Filter::FindFallingEdges(DigitalWaveform* data, vector<int64_t>& edges)
{
//Find times of the zero crossings
bool first = true;
bool last = data->m_samples[0];
int64_t phoff = data->m_timescale/2 + data->m_triggerPhase;
size_t len = data->m_samples.size();
for(size_t i=1; i<len; i++)
{
bool value = data->m_samples[i];

//Save the last value
if(first)
{
last = value;
first = false;
continue;
}

//Save samples with an edge
if(!value && last)
edges.push_back(phoff + data->m_timescale * data->m_offsets[i]);

last = value;
}
}

/**
@brief Find edges in a waveform, discarding repeated samples
No extra resolution vs the int64 version, just for interface compatibility with the analog interpolating version.
*/
2 changes: 2 additions & 0 deletions scopehal/Filter.h
Original file line number Diff line number Diff line change
@@ -205,6 +205,8 @@ class Filter : public OscilloscopeChannel

//Find edges in a signal (discarding repeated samples)
void FindZeroCrossings(DigitalWaveform* data, std::vector<int64_t>& edges);
void FindRisingEdges(DigitalWaveform* data, std::vector<int64_t>& edges);
void FindFallingEdges(DigitalWaveform* data, std::vector<int64_t>& edges);
void FindZeroCrossings(DigitalWaveform* data, std::vector<double>& edges);

public:
9 changes: 8 additions & 1 deletion scopehal/PulseWidthTrigger.cpp
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@
#include "scopehal.h"
#include "PulseWidthTrigger.h"
#include "LeCroyOscilloscope.h"
#include "TektronixOscilloscope.h"

using namespace std;

@@ -51,9 +52,15 @@ PulseWidthTrigger::PulseWidthTrigger(Oscilloscope* scope)
m_parameters[m_conditionname].AddEnumValue("Greater than", CONDITION_GREATER);
m_parameters[m_conditionname].AddEnumValue("Between", CONDITION_BETWEEN);

//So far only LeCroy is known to support this
//Some modes are only supported by certain vendors
if(dynamic_cast<LeCroyOscilloscope*>(scope) != NULL)
m_parameters[m_conditionname].AddEnumValue("Not between", CONDITION_NOT_BETWEEN);
if(dynamic_cast<TektronixOscilloscope*>(scope) != NULL)
{
m_parameters[m_conditionname].AddEnumValue("Equal", CONDITION_EQUAL);
m_parameters[m_conditionname].AddEnumValue("Not equal", CONDITION_NOT_EQUAL);
m_parameters[m_conditionname].AddEnumValue("Not between", CONDITION_NOT_BETWEEN);
}
}

PulseWidthTrigger::~PulseWidthTrigger()
77 changes: 47 additions & 30 deletions scopeprotocols/EyePattern.cpp
Original file line number Diff line number Diff line change
@@ -348,7 +348,6 @@ void EyePattern::Refresh()
//Get the input data
auto waveform = GetAnalogInputWaveform(0);
auto clock = GetDigitalInputWaveform(1);
size_t cend = clock->m_samples.size();
double start = GetTime();

//If center of the eye was changed, reset existing eye data
@@ -376,24 +375,56 @@ void EyePattern::Refresh()
cap->m_timescale = 1;
int64_t* data = cap->GetAccumData();

//Calculate average period of the clock
//TODO: All of this code assumes a fully RLE'd clock with one sample per toggle.
//We probably need a preprocessing filter to handle analog etc clock sources.
//Find all toggles in the clock
vector<int64_t> clock_edges;
switch(m_parameters[m_polarityName].GetIntVal())
{
case CLOCK_RISING:
FindRisingEdges(clock, clock_edges);
break;

case CLOCK_FALLING:
FindFallingEdges(clock, clock_edges);
break;

case CLOCK_BOTH:
FindZeroCrossings(clock, clock_edges);
break;
}

//Calculate the nominal UI width
if(cap->m_uiWidth < FLT_EPSILON)
{
double tlastclk = clock->m_offsets[cend-1] + clock->m_durations[cend-1];
cap->m_uiWidth = tlastclk / cend;
//Find width of each UI
vector<int64_t> ui_widths;
for(size_t i=0; i<clock_edges.size()-1; i++)
ui_widths.push_back(clock_edges[i+1] - clock_edges[i]);

//Need to average at least ten UIs to get meaningful data
size_t nuis = ui_widths.size();
if(nuis > 10)
{
//Sort, discard the top and bottom 10%, and average the rest to calculate nominal width
sort(ui_widths.begin(), ui_widths.end());
size_t navg = 0;
int64_t total = 0;
for(size_t i = nuis/10; i <= nuis*9/10; i++)
{
total += ui_widths[i];
navg ++;
}

cap->m_uiWidth = (1.0 * total) / navg;
}
}

//Process the eye
size_t cend = clock_edges.size();
float yscale = m_height / m_inputs[0].m_channel->GetVoltageRange();
float ymid = m_height / 2;
float yoff = -center*yscale + ymid;
int clkpol = m_parameters[m_polarityName].GetIntVal();
size_t iclock = 0;
bool last_clock = clock->m_samples[0];
size_t wend = waveform->m_samples.size()-1;
size_t num_uis = 0;
for(size_t i=0; i<wend; i++)
{
//If scale isn't defined yet, early out
@@ -406,35 +437,21 @@ void EyePattern::Refresh()

//Find time of this sample.
//If it's past the end of the current UI, move to the next clock edge
int64_t twidth = clock->m_durations[iclock];
int64_t tnext = clock_edges[iclock + 1];
int64_t twidth = tnext - clock_edges[iclock];
int64_t tstart = waveform->m_offsets[i] * waveform->m_timescale + waveform->m_triggerPhase;
int64_t offset = tstart - clock->m_offsets[iclock] * clock->m_timescale;
int64_t offset = tstart - clock_edges[iclock];
if(offset < -10)
continue;
if( (offset > twidth) || (iclock == 0) )
if(offset > twidth)
{
//Move to the next clock edge
while(iclock < cend)
{
bool b = clock->m_samples[iclock];
if(b != last_clock)
{
last_clock = b;
if(b && (clkpol & CLOCK_RISING))
break;
if(!b && (clkpol & CLOCK_FALLING))
break;
}

iclock ++;
}
num_uis ++;

iclock ++;
if(iclock + 1 >= cend)
break;

//Figure out the offset to the next edge
offset = tstart - clock->m_offsets[iclock+1] * clock->m_timescale;
offset = tstart - tnext;
}

//LogDebug("%zu, %zd\n", i, offset);
@@ -486,7 +503,7 @@ void EyePattern::Refresh()
fflush(stdout);

//Count total number of UIs we've integrated
cap->IntegrateUIs(num_uis);
cap->IntegrateUIs(clock_edges.size());
cap->Normalize();
SetData(cap, 0);

9 changes: 4 additions & 5 deletions scopeprotocols/SPIFlashDecoder.cpp
Original file line number Diff line number Diff line change
@@ -1097,12 +1097,11 @@ string SPIFlashDecoder::GetPartID(SPIFlashWaveform* cap, const SPIFlashSymbol& s
return tmp;
}
break;

//Unknown vendor, print part number as hex
default:
snprintf(tmp, sizeof(tmp), "%x", s.m_data);
return tmp;
}

//Unknown vendor, print part number as hex
snprintf(tmp, sizeof(tmp), "%x", s.m_data);
return tmp;
}

bool SPIFlashDecoder::CanMerge(Packet* first, Packet* /*cur*/, Packet* next)
42 changes: 7 additions & 35 deletions scopeprotocols/UartClockRecoveryFilter.cpp
Original file line number Diff line number Diff line change
@@ -128,43 +128,12 @@ void UartClockRecoveryFilter::Refresh()
vector<int64_t> edges;

//Find times of the zero crossings
bool first = true;
bool last = false;
const float threshold = m_parameters[m_threshname].GetFloatVal();
size_t len = din->m_samples.size();
for(size_t i=1; i<len; i++)
{
bool value = din->m_samples[i] > threshold;

//Start time of the sample, in picoseconds
int64_t t = din->m_triggerPhase + din->m_timescale * din->m_offsets[i];

//Move to the middle of the sample
t += din->m_timescale/2;

//Save the last value
if(first)
{
last = value;
first = false;
continue;
}

//Skip samples with no transition
if(last == value)
continue;

//Interpolate the time
t += din->m_timescale * InterpolateTime(din, i-1, threshold);
edges.push_back(t);
last = value;
}
FindZeroCrossings(din, threshold, edges);

//Actual DLL logic
//TODO: recover from glitches better?
size_t nedge = 0;
int64_t bcenter = 0;
bool value = false;
size_t elen = edges.size();
for(; nedge < elen;)
{
@@ -187,9 +156,12 @@ void UartClockRecoveryFilter::Refresh()

//Emit a sample for this data bit
cap->m_offsets.push_back(bcenter);
cap->m_durations.push_back(ps);
cap->m_samples.push_back(value);
value = !value;
cap->m_durations.push_back(ps/2);
cap->m_samples.push_back(1);

cap->m_offsets.push_back(bcenter + ps/2);
cap->m_durations.push_back(ps/2);
cap->m_samples.push_back(0);

//Next bit starts one baud period later
bcenter += ps;