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-apps
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: a42ea1251436
Choose a base ref
...
head repository: ngscopeclient/scopehal-apps
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 224573fd61de
Choose a head ref
  • 1 commit
  • 4 files changed
  • 1 contributor

Commits on Jun 11, 2020

  1. Copy the full SHA
    224573f View commit details
Showing with 119 additions and 24 deletions.
  1. +15 −0 glscopeclient/OscilloscopeWindow.cpp
  2. +5 −1 glscopeclient/OscilloscopeWindow.h
  3. +88 −23 glscopeclient/ScopeSyncWizard.cpp
  4. +11 −0 glscopeclient/ScopeSyncWizard.h
15 changes: 15 additions & 0 deletions glscopeclient/OscilloscopeWindow.cpp
Original file line number Diff line number Diff line change
@@ -78,6 +78,7 @@ OscilloscopeWindow::OscilloscopeWindow(vector<Oscilloscope*> scopes, bool nodigi
m_tHistory = 0;
m_tPoll = 0;
m_totalWaveforms = 0;
m_syncComplete = false;

//Start a timer for polling for scope updates
//TODO: can we use signals of some sort to avoid busy polling until a trigger event?
@@ -387,6 +388,14 @@ void OscilloscopeWindow::CreateWidgets(bool nodigital)
bool OscilloscopeWindow::OnTimer(int /*timer*/)
{
PollScopes();

//Clean up the scope sync wizard if it's completed
if(m_syncComplete)
{
delete m_scopeSyncWizard;
m_scopeSyncWizard = NULL;
}

return true;
}

@@ -2152,5 +2161,11 @@ void OscilloscopeWindow::OnScopeSync()
m_scopeSyncWizard = new ScopeSyncWizard(this);

m_scopeSyncWizard->show();
m_syncComplete = false;
}
}

void OscilloscopeWindow::OnSyncComplete()
{
m_syncComplete = true;
}
6 changes: 5 additions & 1 deletion glscopeclient/OscilloscopeWindow.h
Original file line number Diff line number Diff line change
@@ -110,6 +110,10 @@ class OscilloscopeWindow : public Gtk::Window

//has to be public so ScopeSyncWizard can call it
void ArmTrigger(bool oneshot);
void OnStop();

//Clean up the sync wizard
void OnSyncComplete();

protected:
void SetTitle();
@@ -119,7 +123,6 @@ class OscilloscopeWindow : public Gtk::Window

//Menu/toolbar message handlers
void OnStartSingle();
void OnStop();
void OnQuit();
void OnHistory();
void OnAlphaChanged();
@@ -258,6 +261,7 @@ class OscilloscopeWindow : public Gtk::Window

//Instrument sync wizard
ScopeSyncWizard* m_scopeSyncWizard;
bool m_syncComplete;
};

#endif
111 changes: 88 additions & 23 deletions glscopeclient/ScopeSyncWizard.cpp
Original file line number Diff line number Diff line change
@@ -132,6 +132,8 @@ ScopeSyncWizard::ScopeSyncWizard(OscilloscopeWindow* parent)
, m_secondaryWaveform(0)
, m_delta(0)
, m_maxSkewSamples(0)
, m_numAverages(10)
, m_waitingForWaveform(false)
{
set_transient_for(*parent);

@@ -172,6 +174,17 @@ ScopeSyncWizard::ScopeSyncWizard(OscilloscopeWindow* parent)
set_page_title(progpage->m_grid, string("Deskew ") + m_parent->GetScope(i)->m_nickname);
}

//Last page
append_page(m_donePage);
set_page_type(m_donePage, Gtk::ASSISTANT_PAGE_CONFIRM);
m_donePage.attach(m_doneLabel, 0, 0, 1, 1);
set_page_title(m_donePage, "Complete");
m_doneLabel.set_markup(
string("Instrument synchronization successfully completed!\n") +
string("\n") +
string("The sync wizard may be re-run at any time to tune if necessary.\n")
);

//Mark the first page as complete, so we can move on
set_page_complete(m_welcomePage);

@@ -192,11 +205,20 @@ void ScopeSyncWizard::on_cancel()
hide();
}

void ScopeSyncWizard::on_apply()
{
hide();
m_parent->OnSyncComplete();
}

void ScopeSyncWizard::on_prepare(Gtk::Widget* page)
{
if(page == &m_primaryProgressPage)
ConfigurePrimaryScope(m_parent->GetScope(0));

if(page == &m_donePage)
set_page_complete(*page);

//Mark setup pages complete immediately
for(auto p : m_deskewSetupPages)
{
@@ -251,22 +273,18 @@ void ScopeSyncWizard::ConfigureSecondaryScope(ScopeSyncDeskewProgressPage* page,

//Set trigger to external
page->m_progressBar.set_text("Configure trigger source");
page->m_progressBar.set_fraction(0.025);
scope->SetTriggerChannelIndex(scope->GetExternalTrigger()->GetIndex());

//Set reference clock to external
page->m_progressBar.set_text("Configure reference clock");
page->m_progressBar.set_fraction(0.05);
scope->SetUseExternalRefclk(true);

//Set the trigger offset to the same as the primary
page->m_progressBar.set_text("Configure trigger offset");
page->m_progressBar.set_fraction(0.075);
scope->SetTriggerOffset(m_parent->GetScope(0)->GetTriggerOffset());

//Set all channels to zero skew
page->m_progressBar.set_text("Configure channel deskew");
page->m_progressBar.set_fraction(0.1);
for(size_t i=0; i<scope->GetChannelCount(); i++)
{
auto chan = scope->GetChannel(i);
@@ -277,22 +295,17 @@ void ScopeSyncWizard::ConfigureSecondaryScope(ScopeSyncDeskewProgressPage* page,
}

//Arm trigger and acquire a waveform
page->m_progressBar.set_text("Acquire skew reference waveform");
page->m_progressBar.set_fraction(0.15);
m_parent->ArmTrigger(true);
RequestWaveform();

//TODO: set timeout, in case it doesn't trigger stop and re-arm the trigger
//Clean out stats
m_averageSkews.clear();
}

void ScopeSyncWizard::OnWaveformDataReady()
{
if(!m_activeSecondaryPage)
return;

//Progress update
m_activeSecondaryPage->m_progressBar.set_text("Cross-correlate skew reference waveform");
m_activeSecondaryPage->m_progressBar.set_fraction(0.25);

//We must have active pages (sanity check)
if(!m_activeSecondaryPage || !m_activeSetupPage)
return;
@@ -309,6 +322,9 @@ void ScopeSyncWizard::OnWaveformDataReady()
if(!pw || !sw)
return;

//Good, not waiting
m_waitingForWaveform = false;

//Set up state
m_bestCorrelation = -999999;
m_bestCorrelationOffset = 0;
@@ -336,9 +352,13 @@ bool ScopeSyncWizard::OnTimer()
blockEnd = min(blockEnd, m_maxSkewSamples);

//Update the progress bar
float blockfrac = m_averageSkews.size() * 1.0f / m_numAverages;
int64_t blockpos = m_delta + m_maxSkewSamples;
float frac = blockpos * 1.0f / m_maxSkewSamples;
m_activeSecondaryPage->m_progressBar.set_fraction((frac * 0.75) + 0.25);
float infrac = blockpos * 1.0f / (2*m_maxSkewSamples);
float frac = blockfrac + infrac/m_numAverages;
float progress = (frac * 0.9) + 0.1;
m_activeSecondaryPage->m_progressBar.set_text("Cross-correlate skew reference waveform");
m_activeSecondaryPage->m_progressBar.set_fraction(progress);

for(; m_delta < blockEnd; m_delta ++)
{
@@ -393,21 +413,47 @@ bool ScopeSyncWizard::OnTimer()
}
}

//Need more data to go on
if(m_delta < len/2)
return true;

//Done
else
//Collect the skew from this round
auto scope = m_activeSecondaryPage->GetScope();
int64_t skew = m_bestCorrelationOffset * m_primaryWaveform->m_timescale;
LogTrace("Best correlation = %f (delta = %ld / %ld ps)\n",
m_bestCorrelation, m_bestCorrelationOffset, skew);
m_averageSkews.push_back(skew);

//Do we have additional averages to collect?
if(m_averageSkews.size() < m_numAverages)
{
auto scope = m_activeSecondaryPage->GetScope();
int64_t skew = m_bestCorrelationOffset * m_primaryWaveform->m_timescale;
LogTrace("Done deskewing %s. Best correlation = %f (delta = %ld / %ld ps)\n",
scope->m_nickname.c_str(), m_bestCorrelation, m_bestCorrelationOffset, skew);
char tmp[128];
snprintf(
tmp,
sizeof(tmp),
"Acquire skew reference waveform (%zu/%zu)",
m_averageSkews.size()+1,
m_numAverages);
m_activeSecondaryPage->m_progressBar.set_text(tmp);

RequestWaveform();
return false;
}

//Last iteration
else
{
set_page_complete(m_activeSecondaryPage->m_grid);
m_activeSecondaryPage->m_progressBar.set_fraction(1);
m_activeSecondaryPage->m_progressBar.set_text("Done");

//Average skew
double sum = 0;
for(auto f : m_averageSkews)
sum += f;
skew = static_cast<int64_t>(round(sum / m_numAverages));
LogTrace("Average skew = %ld ps\n", skew);

//Figure out where we want the secondary to go
int64_t targetOffset = scope->GetTriggerOffset() - skew;
LogTrace("Target trigger offset %ld\n", targetOffset);
@@ -428,11 +474,30 @@ bool ScopeSyncWizard::OnTimer()
if(chan->GetType() != OscilloscopeChannel::CHANNEL_TYPE_ANALOG)
continue;

LogDebug("Deskew start = %ld\n", chan->GetDeskew());
chan->SetDeskew(remainingSkew);
LogDebug("Deskew end = %ld\n", chan->GetDeskew());
}
}

return false;
}

bool ScopeSyncWizard::OnWaveformTimeout()
{
if(!m_waitingForWaveform)
return false;
}

LogWarning("Timed out waiting for waveform, retriggering...\n");
m_parent->OnStop();
RequestWaveform();
return false;
}

/**
@brief Request a new waveform and set a timeout in case the scope doesn't trigger in time
*/
void ScopeSyncWizard::RequestWaveform()
{
m_parent->ArmTrigger(true);
m_waitingForWaveform = true;
Glib::signal_timeout().connect(sigc::mem_fun(*this, &ScopeSyncWizard::OnWaveformTimeout), 500);
}
11 changes: 11 additions & 0 deletions glscopeclient/ScopeSyncWizard.h
Original file line number Diff line number Diff line change
@@ -97,7 +97,10 @@ class ScopeSyncWizard : public Gtk::Assistant
Gtk::ProgressBar m_primaryProgressBar;
std::vector<ScopeSyncDeskewSetupPage*> m_deskewSetupPages;
std::vector<ScopeSyncDeskewProgressPage*> m_deskewProgressPages;
Gtk::Grid m_donePage;
Gtk::Label m_doneLabel;

virtual void on_apply();
virtual void on_cancel();
virtual void on_prepare(Gtk::Widget* page);

@@ -117,6 +120,14 @@ class ScopeSyncWizard : public Gtk::Assistant
AnalogWaveform* m_secondaryWaveform;
int64_t m_delta;
int64_t m_maxSkewSamples;
std::vector<int64_t> m_averageSkews;
size_t m_numAverages;

//Trigger checks
bool m_waitingForWaveform;
bool OnWaveformTimeout();

void RequestWaveform();
};

#endif