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: 2de8e78b2fae
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: e01b5eafc589
Choose a head ref
  • 2 commits
  • 4 files changed
  • 1 contributor

Commits on Oct 31, 2020

  1. Updated scopehal

    azonenberg committed Oct 31, 2020
    Copy the full SHA
    a7a9bad View commit details
  2. Began work on CSV import.

    azonenberg committed Oct 31, 2020
    Copy the full SHA
    e01b5ea View commit details
Showing with 168 additions and 61 deletions.
  1. +1 −1 lib
  2. +149 −58 src/glscopeclient/OscilloscopeWindow.cpp
  3. +9 −1 src/glscopeclient/OscilloscopeWindow.h
  4. +9 −1 src/glscopeclient/ScopeApp.cpp
207 changes: 149 additions & 58 deletions src/glscopeclient/OscilloscopeWindow.cpp
Original file line number Diff line number Diff line change
@@ -136,6 +136,9 @@ OscilloscopeWindow::~OscilloscopeWindow()
*/
void OscilloscopeWindow::CreateWidgets(bool nodigital, bool nospectrum)
{
//Initialize filter colors from preferences
SyncFilterColors();

//Set up window hierarchy
add(m_vbox);
m_vbox.pack_start(m_menu, Gtk::PACK_SHRINK);
@@ -172,6 +175,10 @@ void OscilloscopeWindow::CreateWidgets(bool nodigital, bool nospectrum)
item->signal_activate().connect(
sigc::mem_fun(*this, &OscilloscopeWindow::OnFileOpen));
m_fileMenu.append(*item);
item = Gtk::manage(new Gtk::MenuItem("Import...", false));
item->signal_activate().connect(
sigc::mem_fun(*this, &OscilloscopeWindow::OnFileImport));
m_fileMenu.append(*item);
item = Gtk::manage(new Gtk::SeparatorMenuItem);
m_fileMenu.append(*item);
item = Gtk::manage(new Gtk::MenuItem("Quit", false));
@@ -326,9 +333,6 @@ void OscilloscopeWindow::CreateWidgets(bool nodigital, bool nospectrum)
auto split = new Gtk::VPaned;
m_vbox.pack_start(*split);
m_splitters.emplace(split);
auto group = new WaveformGroup(this);
m_waveformGroups.emplace(group);
split->pack1(group->m_frame);

m_vbox.pack_start(m_statusbar, Gtk::PACK_SHRINK);
m_statusbar.get_style_context()->add_class("status");
@@ -337,13 +341,44 @@ void OscilloscopeWindow::CreateWidgets(bool nodigital, bool nospectrum)
m_statusbar.pack_end(m_waveformRateLabel, Gtk::PACK_SHRINK);
m_waveformRateLabel.set_size_request(175, 1);

//Reconfigure menus
RefreshChannelsMenu();
RefreshMultimeterMenu();
RefreshTriggerMenu();

//History isn't shown by default
for(auto it : m_historyWindows)
it.second->hide();

//Create the waveform areas for all enabled channels
CreateDefaultWaveformAreas(split, nodigital, nospectrum);

//Don't show measurements or wizards by default
m_haltConditionsDialog.hide();

//Initialize the style sheets
m_css = Gtk::CssProvider::create();
m_css->load_from_path("styles/glscopeclient.css");
get_style_context()->add_provider_for_screen(
Gdk::Screen::get_default(), m_css, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}

/**
@brief Creates the waveform areas for a new scope.
*/
void OscilloscopeWindow::CreateDefaultWaveformAreas(Gtk::Paned* split, bool nodigital, bool nospectrum)
{
//Create top level waveform group
auto group = new WaveformGroup(this);
m_waveformGroups.emplace(group);
split->pack1(group->m_frame);

//Create history windows
for(auto scope : m_scopes)
m_historyWindows[scope] = new HistoryWindow(this, scope);

WaveformGroup* spectrumGroup = NULL;

//Process all of the channels
WaveformGroup* spectrumGroup = NULL;
for(auto scope : m_scopes)
{
for(size_t i=0; i<scope->GetChannelCount(); i++)
@@ -397,40 +432,11 @@ void OscilloscopeWindow::CreateWidgets(bool nodigital, bool nospectrum)
}
}

//Add trigger config menu items for each scope
for(auto scope : m_scopes)
{
item = Gtk::manage(new Gtk::MenuItem(scope->m_nickname, false));
item->signal_activate().connect(
sigc::bind<Oscilloscope*>(sigc::mem_fun(*this, &OscilloscopeWindow::OnTriggerProperties), scope));
m_setupTriggerMenu.append(*item);
}

//Reconfigure menus
RefreshChannelsMenu();
RefreshMultimeterMenu();

//History isn't shown by default
for(auto it : m_historyWindows)
it.second->hide();

//Done adding widgets
//Done
show_all();

//Don't show measurements or wizards by default
group->m_measurementView.hide();
if(spectrumGroup)
spectrumGroup->m_measurementView.hide();
m_haltConditionsDialog.hide();

//Initialize the style sheets
m_css = Gtk::CssProvider::create();
m_css->load_from_path("styles/glscopeclient.css");
get_style_context()->add_provider_for_screen(
Gdk::Screen::get_default(), m_css, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

//Initialize filter colors from preferences
SyncFilterColors();
group->m_measurementView.hide();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -581,14 +587,92 @@ void OscilloscopeWindow::CloseSession()
g_app->ShutDownSession();
}

/**
@brief Import waveform data not in the native glscopeclient format
*/
void OscilloscopeWindow::OnFileImport()
{
//TODO: prompt to save changes to the current session
Gtk::FileChooserDialog dlg(*this, "Import", Gtk::FILE_CHOOSER_ACTION_OPEN);

auto filter = Gtk::FileFilter::create();
filter->add_pattern("*.csv");
filter->set_name("Comma Separated Value (*.csv)");
dlg.add_filter(filter);
dlg.add_button("Open", Gtk::RESPONSE_OK);
dlg.add_button("Cancel", Gtk::RESPONSE_CANCEL);
auto response = dlg.run();

if(response != Gtk::RESPONSE_OK)
return;

DoImportCSV(dlg.get_filename());

//Done
OnLoadComplete();
}

/**
@brief Import a CSV file
*/
void OscilloscopeWindow::DoImportCSV(const string& filename)
{
LogDebug("Importing CSV file \"%s\"\n", filename.c_str());
LogIndenter li;

//Setup
CloseSession();
m_currentFileName = filename;
m_loadInProgress = true;

//Clear performance counters
m_totalWaveforms = 0;
m_lastWaveformTimes.clear();

FILE* fp = fopen(filename.c_str(), "r");
if(!fp)
return;

char line[1024];
bool first = true;
size_t ncols = 0;
while(!feof(fp))
{
if(!fgets(line, sizeof(line), fp))
break;

//If this is the first line, figure out how many columns we have.
//First column is always timestamp in seconds.
//TODO: support timestamp in abstract sample units instead
if(first)
{
for(size_t i=0; i<sizeof(line); i++)
{
if(line[i] == '\0')
break;
else if(line[i] == ',')
ncols ++;
}

LogDebug("Found %zu signal columns, no header row\n", ncols);

first = false;

//
}
}

fclose(fp);
}

/**
@brief Open a saved configuration
*/
void OscilloscopeWindow::OnFileOpen()
{
//TODO: prompt to save changes to the current session

Gtk::FileChooserDialog dlg(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);
Gtk::FileChooserDialog dlg(*this, "Open", Gtk::FILE_CHOOSER_ACTION_OPEN);

dlg.add_choice("layout", "Load UI Configuration");
dlg.add_choice("waveform", "Load Waveform Data");
@@ -689,6 +773,14 @@ void OscilloscopeWindow::DoFileOpen(const string& filename, bool loadLayout, boo
return;
}

OnLoadComplete();
}

/**
@brief Refresh everything in the UI when a new file has been loaded
*/
void OscilloscopeWindow::OnLoadComplete()
{
//TODO: refresh measurements and protocol decodes

//Create protocol analyzers
@@ -715,6 +807,7 @@ void OscilloscopeWindow::DoFileOpen(const string& filename, bool loadLayout, boo
RefreshChannelsMenu();
RefreshAnalyzerMenu();
RefreshMultimeterMenu();
RefreshTriggerMenu();

//Make sure all resize etc events have been handled before replaying history.
//Otherwise eye patterns don't refresh right.
@@ -1125,27 +1218,6 @@ void OscilloscopeWindow::LoadInstruments(const YAML::Node& node, bool reconnect,

//Configure the scope
scope->LoadConfiguration(inst, table);

//Add menu config for the scope (only if reconnecting)
if(reconnect)
{
for(size_t i=0; i<scope->GetChannelCount(); i++)
{
auto chan = scope->GetChannel(i);
if(chan->GetType() != OscilloscopeChannel::CHANNEL_TYPE_TRIGGER)
{
auto item = Gtk::manage(new Gtk::MenuItem(chan->GetDisplayName(), false));
item->signal_activate().connect(
sigc::bind<StreamDescriptor>(sigc::mem_fun(*this, &OscilloscopeWindow::OnAddChannel),
StreamDescriptor(chan, 0)));
m_channelsMenu.append(*item);
}
}
auto item = Gtk::manage(new Gtk::MenuItem(scope->m_nickname, false));
item->signal_activate().connect(
sigc::bind<Oscilloscope*>(sigc::mem_fun(*this, &OscilloscopeWindow::OnTriggerProperties), scope));
m_setupTriggerMenu.append(*item);
}
}
}

@@ -2704,6 +2776,25 @@ void OscilloscopeWindow::RefreshChannelsMenu()
m_channelsMenu.show_all();
}

/**
@brief Refresh the trigger menu when we connect to a new instrument
*/
void OscilloscopeWindow::RefreshTriggerMenu()
{
//Remove the old items
auto children = m_setupTriggerMenu.get_children();
for(auto c : children)
m_setupTriggerMenu.remove(*c);

for(auto scope : m_scopes)
{
auto item = Gtk::manage(new Gtk::MenuItem(scope->m_nickname, false));
item->signal_activate().connect(
sigc::bind<Oscilloscope*>(sigc::mem_fun(*this, &OscilloscopeWindow::OnTriggerProperties), scope));
m_setupTriggerMenu.append(*item);
}
}

/**
@brief Update the protocol analyzer menu when we create or destroy an analyzer
*/
10 changes: 9 additions & 1 deletion src/glscopeclient/OscilloscopeWindow.h
Original file line number Diff line number Diff line change
@@ -234,6 +234,8 @@ class OscilloscopeWindow : public Gtk::Window
void OnFileSave(bool saveToCurrentFile, bool saveLayout, bool saveWaveforms);
void OnFileOpen();
void DoFileOpen(const std::string& filename, bool loadLayout = true, bool loadWaveform = true, bool reconnect = true);
void OnFileImport();
void DoImportCSV(const std::string& filename);
void LoadInstruments(const YAML::Node& node, bool reconnect, IDTable& table);
void LoadDecodes(const YAML::Node& node, IDTable& table);
void LoadUIConfiguration(const YAML::Node& node, IDTable& table);
@@ -255,7 +257,6 @@ class OscilloscopeWindow : public Gtk::Window
volatile float* progress,
volatile int* done
);
void CloseSession();
void OnEyeColorChanged(EyeColor color, Gtk::RadioMenuItem* item);
void OnTriggerProperties(Oscilloscope* scope);
void OnFullscreen();
@@ -266,12 +267,19 @@ class OscilloscopeWindow : public Gtk::Window
void OnShowAnalyzer(ProtocolAnalyzerWindow* window);
void OnShowMultimeter(Multimeter* meter);

//Session handling
void CloseSession();
void OnLoadComplete();
void CreateDefaultWaveformAreas(Gtk::Paned* split, bool nodigital=false, bool nospectrum=false);

void OnPreferences();
void OnPreferenceDialogResponse(int response);

//Reconfigure menus
void RefreshChannelsMenu();
void RefreshAnalyzerMenu();
void RefreshMultimeterMenu();
void RefreshTriggerMenu();

//Protocol decoding etc
void RefreshAllFilters();
10 changes: 9 additions & 1 deletion src/glscopeclient/ScopeApp.cpp
Original file line number Diff line number Diff line change
@@ -52,7 +52,15 @@ void ScopeApp::run(string fileToLoad, bool reconnect, bool nodata, bool retrigge

//Handle file loads specified on the command line
if(!fileToLoad.empty())
m_window->DoFileOpen(fileToLoad, true, !nodata, reconnect);
{
//Guess CSV files by extension
if(fileToLoad.find(".csv") != string::npos)
m_window->DoImportCSV(fileToLoad);

//Assume anything else is a scopesession
else
m_window->DoFileOpen(fileToLoad, true, !nodata, reconnect);
}

m_window->present();