Skip to content
2 changes: 1 addition & 1 deletion lib
Submodule lib updated 39 files
+12 −2 scopehal/AgilentOscilloscope.cpp
+2 −0 scopehal/CMakeLists.txt
+5 −0 scopehal/Instrument.cpp
+8 −0 scopehal/Instrument.h
+128 −0 scopehal/MockInstrument.cpp
+92 −0 scopehal/MockInstrument.h
+4 −50 scopehal/MockOscilloscope.cpp
+3 −28 scopehal/MockOscilloscope.h
+219 −0 scopehal/MockPowerSupply.cpp
+112 −0 scopehal/MockPowerSupply.h
+0 −5 scopehal/Oscilloscope.cpp
+0 −8 scopehal/Oscilloscope.h
+39 −5 scopehal/PicoOscilloscope.cpp
+14 −1 scopehal/SCPIDevice.cpp
+1 −1 scopehal/SCPIDevice.h
+1 −0 scopehal/scopehal.h
+4 −0 scopeprotocols/ACCoupleFilter.cpp
+13 −2 scopeprotocols/CSVExportFilter.cpp
+13 −4 scopeprotocols/CSVImportFilter.cpp
+5 −1 scopeprotocols/CTLEFilter.cpp
+11 −2 scopeprotocols/ClockRecoveryFilter.cpp
+10 −7 scopeprotocols/ComplexImportFilter.cpp
+22 −2 scopeprotocols/ComplexSpectrogramFilter.cpp
+2 −1 scopeprotocols/ComplexSpectrogramFilter.h
+5 −3 scopeprotocols/ConstantFilter.cpp
+24 −1 scopeprotocols/ConstellationFilter.cpp
+2 −1 scopeprotocols/ConstellationFilter.h
+19 −2 scopeprotocols/CouplerDeEmbedFilter.cpp
+22 −4 scopeprotocols/CurrentShuntFilter.cpp
+3 −2 scopeprotocols/CurrentShuntFilter.h
+22 −4 scopeprotocols/DCDMeasurement.cpp
+3 −2 scopeprotocols/DCDMeasurement.h
+13 −0 scopeprotocols/DDJMeasurement.cpp
+3 −0 scopeprotocols/EyePattern.cpp
+187 −52 scopeprotocols/PAMEdgeDetectorFilter.cpp
+31 −3 scopeprotocols/PAMEdgeDetectorFilter.h
+2 −0 scopeprotocols/shaders/CMakeLists.txt
+132 −0 scopeprotocols/shaders/PAMEdgeDetector_LevelCrossings.glsl
+110 −0 scopeprotocols/shaders/PAMEdgeDetector_MergeCrossings.glsl
40 changes: 36 additions & 4 deletions src/ngscopeclient/AddInstrumentDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* *
* ngscopeclient *
* *
* Copyright (c) 2012-2024 Andrew D. Zonenberg *
* Copyright (c) 2012-2026 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
Expand Down Expand Up @@ -45,16 +45,49 @@ AddInstrumentDialog::AddInstrumentDialog(
const string& title,
const string& nickname,
Session& session,
const string& driverType)
const string& driverType,
const std::string& driver,
const std::string& transport,
const std::string& path)
: Dialog(title, string("AddInstrument") + to_string_hex(reinterpret_cast<uintptr_t>(this)), ImVec2(600, 150))
, m_session(session)
, m_nickname(nickname)
, m_selectedDriver(0)
, m_selectedTransport(0)
, m_path(path)
{
SCPITransport::EnumTransports(m_transports);

m_drivers = session.GetDriverNamesForType(driverType);

if(!driver.empty())
{
int i = 0;
for(auto driverName: m_drivers)
{
if(driverName == driver)
{
m_selectedDriver = i;
break;
}
i++;
}
}


if(!transport.empty())
{
int i = 0;
for(auto transportName: m_transports)
{
if(transportName == transport)
{
m_selectedTransport = i;
break;
}
i++;
}
}
}

AddInstrumentDialog::~AddInstrumentDialog()
Expand Down Expand Up @@ -170,6 +203,5 @@ SCPITransport* AddInstrumentDialog::MakeTransport()

bool AddInstrumentDialog::DoConnect(SCPITransport* transport)
{
m_session.CreateAndAddInstrument(m_drivers[m_selectedDriver], transport, m_nickname);
return true;
return m_session.CreateAndAddInstrument(m_drivers[m_selectedDriver], transport, m_nickname);
}
7 changes: 5 additions & 2 deletions src/ngscopeclient/AddInstrumentDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* *
* ngscopeclient *
* *
* Copyright (c) 2012-2024 Andrew D. Zonenberg *
* Copyright (c) 2012-2026 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
Expand Down Expand Up @@ -45,7 +45,10 @@ class AddInstrumentDialog : public Dialog
const std::string& title,
const std::string& nickname,
Session& session,
const std::string& driverType);
const std::string& driverType,
const std::string& driver = "",
const std::string& transport = "",
const std::string& path = "");
virtual ~AddInstrumentDialog();

virtual bool DoRender();
Expand Down
33 changes: 32 additions & 1 deletion src/ngscopeclient/Dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,11 @@ bool Dialog::TextInputWithImplicitApply(const string& label, string& currentValu
return false;
}

bool Dialog::TextInputWithExplicitApply(const string& label, string& currentValue, string& committedValue)
{
return renderEditablePropertyWithExplicitApply(-1,label,currentValue,committedValue,Unit()/*not used for string*/);
}

bool Dialog::IntInputWithImplicitApply(const string& label, int& currentValue, int& committedValue)
{
bool dirty = currentValue != committedValue;
Expand Down Expand Up @@ -488,7 +493,7 @@ template<typename T>
*/
bool Dialog::renderEditableProperty(float width, const std::string& label, std::string& currentValue, T& committedValue, Unit unit, const char* tooltip, std::optional<ImVec4> optcolor, bool allow7SegmentDisplay, bool explicitApply)
{
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, int64_t>,"renderEditableProperty only supports int64_t, float or double");
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, int64_t> || std::is_same_v<T, std::string>,"renderEditableProperty only supports string, int64_t, float or double");
bool use7Segment = false;
bool changeFont = false;
int64_t displayType = NumericValueDisplay::NUMERIC_DISPLAY_DEFAULT_FONT;
Expand Down Expand Up @@ -528,6 +533,8 @@ bool Dialog::renderEditableProperty(float width, const std::string& label, std::
}
if constexpr (std::is_same_v<T, int64_t>)
dirty = unit.PrettyPrintInt64(committedValue) != currentValue;
else if constexpr (std::is_same_v<T, std::string>)
dirty = committedValue != currentValue;
else
dirty = unit.PrettyPrint(committedValue) != currentValue;
string editLabel = label+"##Edit";
Expand Down Expand Up @@ -674,6 +681,10 @@ bool Dialog::renderEditableProperty(float width, const std::string& label, std::

currentValue = unit.PrettyPrintInt64(committedValue);
}
else if constexpr (std::is_same_v<T, std::string>)
{
committedValue = currentValue;
}
else
{
committedValue = static_cast<T>(unit.ParseString(currentValue));
Expand All @@ -689,6 +700,8 @@ bool Dialog::renderEditableProperty(float width, const std::string& label, std::
{ // Restore value
if constexpr (std::is_same_v<T, int64_t>)
currentValue = unit.PrettyPrintInt64(committedValue);
else if constexpr (std::is_same_v<T, std::string>)
currentValue = committedValue;
else
currentValue = unit.PrettyPrint(committedValue);
if(m_editedItemId == editId)
Expand All @@ -707,6 +720,7 @@ bool Dialog::renderEditableProperty(float width, const std::string& label, std::
template bool Dialog::renderEditableProperty<float>(float width, const std::string& label, std::string& currentValue, float& committedValue, Unit unit, const char* tooltip, std::optional<ImVec4> optcolor, bool allow7SegmentDisplay, bool explicitApply);
template bool Dialog::renderEditableProperty<double>(float width, const std::string& label, std::string& currentValue, double& committedValue, Unit unit, const char* tooltip, std::optional<ImVec4> optcolor, bool allow7SegmentDisplay, bool explicitApply);
template bool Dialog::renderEditableProperty<int64_t>(float width, const std::string& label, std::string& currentValue, int64_t& committedValue, Unit unit, const char* tooltip, std::optional<ImVec4> optcolor, bool allow7SegmentDisplay, bool explicitApply);
template bool Dialog::renderEditableProperty<std::string>(float width, const std::string& label, std::string& currentValue, std::string& committedValue, Unit unit, const char* tooltip, std::optional<ImVec4> optcolor, bool allow7SegmentDisplay, bool explicitApply);

template<typename T>
/**
Expand All @@ -731,7 +745,24 @@ bool Dialog::renderEditablePropertyWithExplicitApply(float width, const std::str
template bool Dialog::renderEditablePropertyWithExplicitApply<float>(float width, const std::string& label, std::string& currentValue, float& committedValue, Unit unit, const char* tooltip, std::optional<ImVec4> optcolor, bool allow7SegmentDisplay);
template bool Dialog::renderEditablePropertyWithExplicitApply<double>(float width, const std::string& label, std::string& currentValue, double& committedValue, Unit unit, const char* tooltip, std::optional<ImVec4> optcolor, bool allow7SegmentDisplay);
template bool Dialog::renderEditablePropertyWithExplicitApply<int64_t>(float width, const std::string& label, std::string& currentValue, int64_t& committedValue, Unit unit, const char* tooltip, std::optional<ImVec4> optcolor, bool allow7SegmentDisplay);
template bool Dialog::renderEditablePropertyWithExplicitApply<std::string>(float width, const std::string& label, std::string& currentValue, std::string& committedValue, Unit unit, const char* tooltip, std::optional<ImVec4> optcolor, bool allow7SegmentDisplay);

/**
@brief Render a badge with text inside
@param width the width of the badge
@param color the badge color
@param label the text of the badge
*/
void Dialog::renderBadge(float width, ImVec4 color, const string& label)
{
float fontSize = ImGui::GetFontSize();
if(width <= 0) width = 6*fontSize;
ImGui::PushStyleColor(ImGuiCol_ChildBg, color);
ImGui::BeginChild("##badge", ImVec2(width, ImGui::GetFontSize()),false,ImGuiWindowFlags_None);
ImGui::TextUnformatted(label.c_str());
ImGui::EndChild();
ImGui::PopStyleColor();
}

/**
@brief Segment on/off state for each of the 10 digits + "L" (needed for OL / Overload)
Expand Down
2 changes: 2 additions & 0 deletions src/ngscopeclient/Dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class Dialog
std::string& committedValue);

protected:
bool TextInputWithExplicitApply(const std::string& label,std::string& currentValue,std::string& committedValue);
bool IntInputWithImplicitApply(const std::string& label, int& currentValue, int& committedValue);
bool UnitInputWithExplicitApply(
const std::string& label,
Expand All @@ -93,6 +94,7 @@ class Dialog
bool renderEditableProperty(float width, const std::string& label, std::string& currentValue, T& committedValue, Unit unit, const char* tooltip = nullptr, std::optional<ImVec4> optcolor = std::nullopt, bool allow7SegmentDisplay = false, bool explicitApply = false);
template<typename T>
bool renderEditablePropertyWithExplicitApply(float width, const std::string& label, std::string& currentValue, T& committedValue, Unit unit, const char* tooltip = nullptr, std::optional<ImVec4> optcolor = std::nullopt, bool allow7SegmentDisplay = false);
void renderBadge(float width, ImVec4 color, const std::string& label);

public:
static void Tooltip(const std::string& str, bool allowDisabled = false);
Expand Down
73 changes: 69 additions & 4 deletions src/ngscopeclient/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1567,10 +1567,14 @@ void MainWindow::SaveRecentInstrumentList()
continue;

//Make a node for the instrument
YAML::Node inode;
inode["path"] = it.first;
inode["timestamp"] = static_cast<int64_t>(it.second);
node[nick] = inode;
int64_t timestamp = static_cast<int64_t>(it.second);
if(!node[nick] || (node[nick]["timestamp"].as<int64_t>() < timestamp))
{ // Only add node if not already present or if other timestamp is older
YAML::Node inode;
inode["path"] = it.first;
inode["timestamp"] = timestamp;
node[nick] = inode;
}
}

//Write the generated YAML to disk
Expand Down Expand Up @@ -1631,6 +1635,64 @@ void MainWindow::AddToRecentInstrumentList(shared_ptr<SCPIInstrument> inst)
SaveRecentInstrumentList();
}

void MainWindow::RenameRecentInstrument(std::shared_ptr<SCPIInstrument> inst, const std::string& oldName)
{
if(inst == nullptr)
return;

LogTrace("Renaming instrument \"%s\" with name \"%s\" in recent instrument list (had %zu)\n",
oldName.c_str(), inst->m_nickname.c_str(), m_recentInstruments.size());

auto oldConnectionString =
oldName + ":" +
inst->GetDriverName() + ":" +
inst->GetTransportName() + ":" +
inst->GetTransportConnectionString();
auto it = m_recentInstruments.find(oldConnectionString);
if (it != m_recentInstruments.end())
{
auto now = time(NULL);
auto newConnectionString =
inst->m_nickname + ":" +
inst->GetDriverName() + ":" +
inst->GetTransportName() + ":" +
inst->GetTransportConnectionString();
LogTrace("Replaced connection string %s by %s\n", oldConnectionString.c_str(),newConnectionString.c_str());
m_recentInstruments.erase(it);
m_recentInstruments.emplace(newConnectionString, now);
SaveRecentInstrumentList();
}
}

void MainWindow::RepathRecentInstrument(std::shared_ptr<SCPIInstrument> inst, const std::string& oldPath)
{
if(inst == nullptr)
return;

LogTrace("Changing path for instrument \"%s\" with path \"%s\" in recent instrument list (had %zu)\n",
oldPath.c_str(), inst->GetTransportConnectionString().c_str(), m_recentInstruments.size());

auto oldConnectionString =
inst->m_nickname + ":" +
inst->GetDriverName() + ":" +
inst->GetTransportName() + ":" +
oldPath;
auto it = m_recentInstruments.find(oldConnectionString);
if (it != m_recentInstruments.end())
{
auto now = time(NULL);
auto newConnectionString =
inst->m_nickname + ":" +
inst->GetDriverName() + ":" +
inst->GetTransportName() + ":" +
inst->GetTransportConnectionString();
LogTrace("Replaced connection string %s by %s\n", oldConnectionString.c_str(),newConnectionString.c_str());
m_recentInstruments.erase(it);
m_recentInstruments.emplace(newConnectionString, now);
SaveRecentInstrumentList();
}
}

/**
@brief Helper function for creating a transport and printing an error if the connection is unsuccessful
*/
Expand Down Expand Up @@ -1777,6 +1839,9 @@ ImGui::MarkdownConfig MainWindow::GetMarkdownConfig()
*/
void MainWindow::RenderLoadWarningPopup()
{
if(!m_errorPopupTitle.empty())
return; // Already showing Error popup, skip Warning for now

static ImGuiTableFlags flags =
ImGuiTableFlags_Resizable |
ImGuiTableFlags_BordersOuter |
Expand Down
2 changes: 2 additions & 0 deletions src/ngscopeclient/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,8 @@ class MainWindow : public VulkanWindow

public:
void AddToRecentInstrumentList(std::shared_ptr<SCPIInstrument> inst);
void RenameRecentInstrument(std::shared_ptr<SCPIInstrument> inst, const std::string& oldName);
void RepathRecentInstrument(std::shared_ptr<SCPIInstrument> inst, const std::string& oldPath);

protected:

Expand Down
25 changes: 23 additions & 2 deletions src/ngscopeclient/MainWindow_Menus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* *
* ngscopeclient *
* *
* Copyright (c) 2012-2025 Andrew D. Zonenberg and contributors *
* 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 *
Expand Down Expand Up @@ -340,9 +340,30 @@ void MainWindow::DoAddSubMenu(
path = path + ":" + fields[j];
}

bool success = true;
auto transport = MakeTransport(transname, path);
if(transport != nullptr)
m_session.CreateAndAddInstrument(drivername, transport, nick);
{
if(!m_session.CreateAndAddInstrument(drivername, transport, nick))
{
success = false;
}
}
else
{
success = false;
}
if(!success)
{ // Spawn an AddInstrument dialog here, prefilled with intrument informations, to allow changing connection path
m_dialogs.emplace(make_shared<AddInstrumentDialog>(
string("Update ") + typePretty,
nick,
m_session,
typeInternal,
drivername,
transname,
path));
}
}
}
}
Expand Down
Loading