diff --git a/src/gui/build.mk b/src/gui/build.mk
index f949f017..125eada9 100644
--- a/src/gui/build.mk
+++ b/src/gui/build.mk
@@ -8,6 +8,7 @@ FLUXENGINE_GUI_SRCS = \
src/gui/fileviewerwindow.cc \
src/gui/fluxviewercontrol.cc \
src/gui/fluxviewerwindow.cc \
+ src/gui/histogramviewer.cc \
src/gui/iconbutton.cc \
src/gui/idlepanel.cc \
src/gui/imagerpanel.cc \
diff --git a/src/gui/explorerpanel.cc b/src/gui/explorerpanel.cc
index 148390af..d9229cd4 100644
--- a/src/gui/explorerpanel.cc
+++ b/src/gui/explorerpanel.cc
@@ -109,7 +109,13 @@ private:
UpdateExplorerData();
}
-private:
+ void OnGuessClockButton(wxCommandEvent& event) override
+ {
+ nanoseconds_t clock = histogram->GetMedian();
+ explorerClockSpinCtrl->SetValue(clock / 1e3);
+ UpdateExplorerData();
+ }
+
void OnQueueEmpty() override
{
SetState(STATE_IDLE);
@@ -159,9 +165,9 @@ private:
FluxmapReader fmr(*_explorerFluxmap);
fmr.seek(explorerStartTimeSpinCtrl->GetValue() * 1e6);
- FluxDecoder fluxDecoder(&fmr,
- explorerClockSpinCtrl->GetValue() * 1e3,
- DecoderProto());
+ nanoseconds_t clock =
+ explorerClockSpinCtrl->GetValue() * 1e3;
+ FluxDecoder fluxDecoder(&fmr, clock, DecoderProto());
fluxDecoder.readBits(
explorerBitOffsetSpinCtrl->GetValue());
auto bits = fluxDecoder.readBits();
@@ -183,9 +189,10 @@ private:
std::stringstream s;
hexdump(s, bytes);
-
explorerText->SetValue(s.str());
+ histogram->Redraw(*_explorerFluxmap, clock);
+
if (_explorerUpdatePending)
UpdateExplorerData();
});
diff --git a/src/gui/histogramviewer.cc b/src/gui/histogramviewer.cc
new file mode 100644
index 00000000..0e142126
--- /dev/null
+++ b/src/gui/histogramviewer.cc
@@ -0,0 +1,83 @@
+#include "lib/globals.h"
+#include "gui.h"
+#include "lib/fluxmap.h"
+#include "histogramviewer.h"
+
+static constexpr int BORDER = 10;
+static constexpr int WIDTH = 256;
+static constexpr int HEIGHT = 100;
+
+// clang-format off
+wxBEGIN_EVENT_TABLE(HistogramViewer, wxWindow)
+ EVT_PAINT(HistogramViewer::OnPaint)
+wxEND_EVENT_TABLE();
+// clang-format on
+
+HistogramViewer::HistogramViewer(wxWindow* parent,
+ wxWindowID winid,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style):
+ wxWindow(parent,
+ winid,
+ pos,
+ wxSize(WIDTH + 2 * BORDER, HEIGHT + 2 * BORDER),
+ style)
+{
+ _font = GetFont().MakeSmaller().MakeSmaller().MakeSmaller();
+}
+
+void HistogramViewer::Redraw(const Fluxmap& fluxmap, nanoseconds_t clock)
+{
+ _data = fluxmap.guessClock();
+ _clock = clock;
+ Refresh();
+}
+
+void HistogramViewer::OnPaint(wxPaintEvent&)
+{
+ wxPaintDC dc(this);
+ dc.SetBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK));
+ dc.Clear();
+
+ uint32_t max =
+ *std::max_element(std::begin(_data.buckets), std::end(_data.buckets));
+ dc.SetPen(*wxGREY_PEN);
+ for (int x = 0; x < 256; x++)
+ {
+ double v = (double)_data.buckets[x] / (double)max;
+ dc.DrawLine({BORDER + x, BORDER + HEIGHT},
+ {BORDER + x, BORDER + HEIGHT - (int)(v * HEIGHT)});
+ }
+
+ dc.SetPen(*wxBLACK_PEN);
+ dc.DrawLine({BORDER, BORDER + HEIGHT}, {BORDER + WIDTH, BORDER + HEIGHT});
+ dc.DrawLine({BORDER, BORDER + HEIGHT}, {BORDER, BORDER});
+
+ dc.SetPen(*wxRED_PEN);
+ {
+ int y = ((double)_data.signalLevel / (double)max) * HEIGHT;
+ dc.DrawLine({0, BORDER + HEIGHT - y},
+ {2 * BORDER + WIDTH, BORDER + HEIGHT - y});
+ }
+
+ {
+ int x = _clock / NS_PER_TICK;
+ dc.DrawLine({BORDER + x, 2 * BORDER + HEIGHT}, {BORDER + x, 0});
+ }
+
+ {
+ wxString text = "Clock interval";
+ dc.SetFont(_font);
+ auto size = dc.GetTextExtent(text);
+ dc.DrawText(text, {BORDER + WIDTH - size.GetWidth(), BORDER + HEIGHT});
+ }
+
+ {
+ wxString text = "Frequency";
+ dc.SetFont(_font);
+ auto size = dc.GetTextExtent(text);
+ dc.DrawRotatedText(
+ text, BORDER - size.GetHeight(), BORDER + size.GetWidth(), 90);
+ }
+}
diff --git a/src/gui/histogramviewer.h b/src/gui/histogramviewer.h
new file mode 100644
index 00000000..3dcdf8c2
--- /dev/null
+++ b/src/gui/histogramviewer.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "lib/globals.h"
+#include "lib/fluxmap.h"
+
+class HistogramViewer : public wxWindow
+{
+public:
+ HistogramViewer(wxWindow* parent,
+ wxWindowID winid,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0);
+ virtual ~HistogramViewer() {}
+
+public:
+ void Redraw(const Fluxmap& fluxmap, nanoseconds_t clock);
+ nanoseconds_t GetMedian() const { return _data.median; }
+
+private:
+ void OnPaint(wxPaintEvent&);
+
+private:
+ Fluxmap::ClockData _data;
+ wxFont _font;
+ nanoseconds_t _clock;
+ wxDECLARE_EVENT_TABLE();
+};
+
diff --git a/src/gui/layout.cpp b/src/gui/layout.cpp
index 016ef8e6..bce4a5d3 100644
--- a/src/gui/layout.cpp
+++ b/src/gui/layout.cpp
@@ -891,6 +891,13 @@ ExplorerPanelGen::ExplorerPanelGen( wxWindow* parent, wxWindowID id, const wxPoi
fgSizer12->SetFlexibleDirection( wxBOTH );
fgSizer12->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
+ wxFlexGridSizer* fgSizer13;
+ fgSizer13 = new wxFlexGridSizer( 0, 1, 0, 0 );
+ fgSizer13->AddGrowableCol( 0 );
+ fgSizer13->AddGrowableRow( 1 );
+ fgSizer13->SetFlexibleDirection( wxBOTH );
+ fgSizer13->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
+
wxFlexGridSizer* fgSizer10;
fgSizer10 = new wxFlexGridSizer( 0, 2, 0, 0 );
fgSizer10->AddGrowableCol( 1 );
@@ -919,9 +926,22 @@ ExplorerPanelGen::ExplorerPanelGen( wxWindow* parent, wxWindowID id, const wxPoi
explorerStartTimeSpinCtrl->SetDigits( 3 );
fgSizer10->Add( explorerStartTimeSpinCtrl, 0, wxALL|wxEXPAND, 5 );
+ wxFlexGridSizer* fgSizer121;
+ fgSizer121 = new wxFlexGridSizer( 0, 2, 0, 0 );
+ fgSizer121->AddGrowableCol( 0 );
+ fgSizer121->AddGrowableRow( 0 );
+ fgSizer121->SetFlexibleDirection( wxBOTH );
+ fgSizer121->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
+
m_staticText24 = new wxStaticText( this, wxID_ANY, wxT("Clock (us)"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText24->Wrap( -1 );
- fgSizer10->Add( m_staticText24, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+ fgSizer121->Add( m_staticText24, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+
+ guessButton = new wxButton( this, wxID_ANY, wxT("Guess"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
+ fgSizer121->Add( guessButton, 0, wxALIGN_BOTTOM|wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALIGN_TOP, 5 );
+
+
+ fgSizer10->Add( fgSizer121, 1, wxEXPAND, 5 );
explorerClockSpinCtrl = new wxSpinCtrlDouble( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 100, 4, 1 );
explorerClockSpinCtrl->SetDigits( 1 );
@@ -952,7 +972,13 @@ ExplorerPanelGen::ExplorerPanelGen( wxWindow* parent, wxWindowID id, const wxPoi
fgSizer10->Add( explorerReverseCheckBox, 0, wxALL, 5 );
- fgSizer12->Add( fgSizer10, 1, wxEXPAND, 5 );
+ fgSizer13->Add( fgSizer10, 1, wxEXPAND, 5 );
+
+ histogram = new HistogramViewer( this, wxID_ANY, wxDefaultPosition, wxSize( 256,100 ), 0 );
+ fgSizer13->Add( histogram, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_TOP|wxALL, 5 );
+
+
+ fgSizer12->Add( fgSizer13, 1, wxEXPAND, 5 );
explorerText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxTE_DONTWRAP|wxTE_MULTILINE|wxTE_READONLY );
explorerText->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
@@ -972,6 +998,7 @@ ExplorerPanelGen::ExplorerPanelGen( wxWindow* parent, wxWindowID id, const wxPoi
explorerTrackSpinCtrl->Connect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
explorerSideSpinCtrl->Connect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
explorerStartTimeSpinCtrl->Connect( wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, wxSpinDoubleEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
+ guessButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ExplorerPanelGen::OnGuessClockButton ), NULL, this );
explorerClockSpinCtrl->Connect( wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, wxSpinDoubleEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
explorerBitOffsetSpinCtrl->Connect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
explorerDecodeChoice->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
@@ -986,6 +1013,7 @@ ExplorerPanelGen::~ExplorerPanelGen()
explorerTrackSpinCtrl->Disconnect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
explorerSideSpinCtrl->Disconnect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
explorerStartTimeSpinCtrl->Disconnect( wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, wxSpinDoubleEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
+ guessButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ExplorerPanelGen::OnGuessClockButton ), NULL, this );
explorerClockSpinCtrl->Disconnect( wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, wxSpinDoubleEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
explorerBitOffsetSpinCtrl->Disconnect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
explorerDecodeChoice->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( ExplorerPanelGen::OnExplorerSettingChange ), NULL, this );
diff --git a/src/gui/layout.fbp b/src/gui/layout.fbp
index cf7315af..413ddb4a 100644
--- a/src/gui/layout.fbp
+++ b/src/gui/layout.fbp
@@ -4897,89 +4897,1028 @@
none
0
0
-