]> code.bitgloo.com Git - clyne/stmdsp.git/commitdiff
signal monitoring support
authorClyne Sullivan <clyne@bitgloo.com>
Sun, 21 Feb 2021 13:59:15 +0000 (08:59 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Sun, 21 Feb 2021 13:59:15 +0000 (08:59 -0500)
Makefile
gui/Makefile
gui/stmdsp.cpp
gui/stmdsp.hpp
gui/wxmain.cpp
gui/wxmain.hpp
source/adc.hpp
source/main.cpp
source/samplebuffer.cpp
source/samplebuffer.hpp

index 53340e4fcad358be193f32b87088f1e2893325b3..7c36535472a557a4702f51695539f9078a94f01e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@ endif
 
 # C++ specific options here (added to USE_OPT).
 ifeq ($(USE_CPPOPT),)
-  USE_CPPOPT = -std=c++17 -fno-rtti
+  USE_CPPOPT = -std=c++2a -fno-rtti
 endif
 
 # Enable this if you want the linker to remove unused code and data.
@@ -25,7 +25,7 @@ endif
 
 # Linker extra options here.
 ifeq ($(USE_LDOPT),)
-  USE_LDOPT = 
+#  USE_LDOPT = -L.,-lzig
 endif
 
 # Enable this if you want link time optimizations (LTO).
index 679e1e4eb4a9cfded3bdd098375e0b65e81d2358..20dd4734c30bb8ea5b4afd6ce881cfd9e5b817ad 100644 (file)
@@ -1,18 +1,21 @@
 CXX = g++-10
-CXXFLAGS = --std=c++20 -ggdb -Og \
-                  -Wall -Wextra -pedantic \
-                  -Wno-deprecated-copy \
-                  -Iserial/include \
-                  $(shell wx-config --cxxflags)
+CXXFLAGS = --std=c++20 -ggdb -O0 \
+           -Wall -Wextra -pedantic \
+           -Wno-deprecated-copy \
+           -Iserial/include \
+           $(shell wx-config --cxxflags)
 
-CXXFILES = $(shell find serial/src -name "*.cc") $(wildcard *.cpp)
+CXXFILES = serial/src/serial.cc \
+           serial/src/impl/unix.cc \
+           serial/src/impl/list_ports/list_ports_linux.cc \
+           $(wildcard *.cpp)
 OFILES = $(patsubst %.cc, %.o, $(patsubst %.cpp, %.o, $(CXXFILES)))
 
 LIBS = $(shell wx-config --libs) -lwx_gtk3u_stc-3.1
 OUTELF = stmdspgui
 
 all: $(OUTELF)
-       
+
 $(OUTELF): $(OFILES)
        @echo "  CXX    " $(OUTELF)
        @$(CXX) $(CXXFLAGS) $(OFILES) $(LIBS) -o $(OUTELF)
index 1b4bba65c930a96dbf8e91aa042c291c33203e25..5ea18af3016c0ee59c0345816d2d1ad35c7f09f9 100644 (file)
@@ -120,6 +120,33 @@ namespace stmdsp
         return {};
     }
 
+    std::vector<adcsample_t> device::continuous_read_input() {
+        if (connected()) {
+            m_serial.write("t");
+            unsigned char sizebytes[2];
+            m_serial.read(sizebytes, 2);
+            unsigned int size = sizebytes[0] | (sizebytes[1] << 8);
+            if (size > 0) {
+                std::vector<adcsample_t> data (size);
+                unsigned int total = size * sizeof(adcsample_t);
+                unsigned int offset = 0;
+
+                while (total > 512) {
+                    m_serial.read(reinterpret_cast<uint8_t *>(&data[0]) + offset, 512);
+                    m_serial.write("n");
+                    offset += 512;
+                    total -= 512;
+                }
+                m_serial.read(reinterpret_cast<uint8_t *>(&data[0]) + offset, total);
+                m_serial.write("n");
+                return data;
+
+            }
+        }
+
+        return {};
+    }
+
     void device::continuous_stop() {
         if (connected())
             m_serial.write("S");
index f805ab3436c6bff8b9777bf9b9ccf7c896aa5821..a22a55da16a52f5b783bf4e2927cb5d38c691e96 100644 (file)
@@ -19,7 +19,7 @@
 
 namespace stmdsp
 {
-    constexpr unsigned int SAMPLES_MAX = 4000;
+    constexpr unsigned int SAMPLES_MAX = 4096;
 
     class scanner
     {
@@ -62,6 +62,7 @@ namespace stmdsp
         void continuous_start_measure();
         uint32_t continuous_start_get_measurement();
         std::vector<adcsample_t> continuous_read();
+        std::vector<adcsample_t> continuous_read_input();
         void continuous_stop();
 
         void siggen_upload(dacsample_t *buffer, unsigned int size);
index c7acddf5c217ef2acacea0ece788936c68e4c5c9..e5f0d4d3cfed17c8e377ba2de0bea2ac5bbd3dfd 100644 (file)
@@ -12,6 +12,7 @@
 #include "wxmain.hpp"
 
 #include <wx/combobox.h>
+#include <wx/dcclient.h>
 #include <wx/dir.h>
 #include <wx/filename.h>
 #include <wx/filedlg.h>
@@ -25,6 +26,7 @@
 #include <wx/textdlg.h>
 
 #include <array>
+#include <sys/mman.h>
 #include <vector>
 
 static const std::array<wxString, 6> srateValues {
@@ -133,6 +135,7 @@ enum Id {
     MRunConnect,
     MRunStart,
     MRunMeasure,
+    MRunDrawSamples,
     MRunLogResults,
     MRunUpload,
     MRunUnload,
@@ -177,6 +180,12 @@ MainFrame::MainFrame() : wxFrame(nullptr, wxID_ANY, "stmdspgui", wxPoint(50, 50)
                                       wxDefaultPosition, wxDefaultSize,
                                       srateValues.size(), srateValues.data(),
                                       wxCB_READONLY);
+    m_device_samples = reinterpret_cast<stmdsp::adcsample_t *>(::mmap(
+        nullptr, stmdsp::SAMPLES_MAX * sizeof(stmdsp::adcsample_t),
+        PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
+    m_device_samples_input = reinterpret_cast<stmdsp::adcsample_t *>(::mmap(
+        nullptr, stmdsp::SAMPLES_MAX * sizeof(stmdsp::adcsample_t),
+        PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
 
     m_menu_bar->Append(menuFile, "&File");
     m_menu_bar->Append(menuRun, "&Run");
@@ -217,6 +226,7 @@ MainFrame::MainFrame() : wxFrame(nullptr, wxID_ANY, "stmdspgui", wxPoint(50, 50)
     // General
     Bind(wxEVT_TIMER,        &MainFrame::onMeasureTimer, this, Id::MeasureTimer);
     Bind(wxEVT_CLOSE_WINDOW, &MainFrame::onCloseEvent,   this, wxID_ANY);
+    Bind(wxEVT_PAINT,        &MainFrame::onPaint,        this, wxID_ANY);
 
     // Toolbar actions
     Bind(wxEVT_BUTTON,   &MainFrame::onRunCompile,        this, Id::MCodeCompile, wxID_ANY, comp);
@@ -237,6 +247,7 @@ MainFrame::MainFrame() : wxFrame(nullptr, wxID_ANY, "stmdspgui", wxPoint(50, 50)
     menuRun->AppendSeparator();
     Bind(wxEVT_MENU, &MainFrame::onRunStart,      this, Id::MRunStart,      wxID_ANY, menuRun->Append(MRunStart, "&Start"));
     m_run_measure = menuRun->AppendCheckItem(MRunMeasure, "&Measure code time");
+    m_run_draw_samples = menuRun->AppendCheckItem(MRunDrawSamples, "&Draw samples");
     Bind(wxEVT_MENU, &MainFrame::onRunLogResults, this, Id::MRunLogResults, wxID_ANY, menuRun->AppendCheckItem(MRunLogResults, "&Log results..."));
     menuRun->AppendSeparator();
     Bind(wxEVT_MENU, &MainFrame::onRunUpload,     this, Id::MRunUpload,     wxID_ANY, menuRun->Append(MRunUpload, "&Upload code"));
@@ -276,12 +287,21 @@ void MainFrame::onCloseEvent(wxCloseEvent& event)
 // Only called while connected and running.
 void MainFrame::onMeasureTimer(wxTimerEvent&)
 {
-    if (m_conv_result_log) {
-        // We're meant to log
-        if (auto samples = m_device->continuous_read(); samples.size() > 0) {
-            for (auto& s : samples) {
-                auto str = std::to_string(s);
-                m_conv_result_log->Write(str.c_str(), str.size());
+    if (m_conv_result_log || m_run_draw_samples->IsChecked()) {
+        auto samples = m_device->continuous_read();
+        if (samples.size() > 0) {
+            std::copy(samples.cbegin(), samples.cend(), m_device_samples);
+
+            if (m_conv_result_log) {
+                for (auto& s : samples) {
+                    auto str = std::to_string(s);
+                    m_conv_result_log->Write(str.c_str(), str.size());
+                }
+            }
+            if (m_run_draw_samples->IsChecked()) {
+                samples = m_device->continuous_read_input();
+                std::copy(samples.cbegin(), samples.cend(), m_device_samples_input);
+                this->Refresh();
             }
         }
     }
@@ -304,6 +324,54 @@ void MainFrame::onMeasureTimer(wxTimerEvent&)
     }
 }
 
+void MainFrame::onPaint(wxPaintEvent&)
+{
+    if (!m_is_running || !m_run_draw_samples->IsChecked()) {
+        if (!m_compile_output->IsShown())
+            m_compile_output->Show();
+        return;
+    } else if (m_compile_output->IsShown()) {
+        m_compile_output->Hide();
+    }
+
+    auto py = m_compile_output->GetScreenPosition().y - this->GetScreenPosition().y - 28;
+    wxRect rect {
+        0, py,
+        this->GetSize().GetWidth(),
+        this->GetSize().GetHeight() - py - 60
+    };
+
+    auto *dc = new wxPaintDC(this);
+    dc->SetBrush(*wxBLACK_BRUSH);
+    dc->SetPen(*wxBLACK_PEN);
+    dc->DrawRectangle(rect);
+    dc->SetBrush(*wxRED_BRUSH);
+    dc->SetPen(*wxRED_PEN);
+    auto stoy = [&](stmdsp::adcsample_t s) {
+        return static_cast<float>(py) + rect.GetHeight() -
+            (static_cast<float>(rect.GetHeight()) * s / 4095.f);
+    };
+    auto scount = m_device->get_buffer_size();
+    float dx = static_cast<float>(rect.GetWidth()) / scount;
+    float x = 0;
+    float lasty = stoy(2048);
+    for (decltype(scount) i = 0; i < scount; i++) {
+        auto y = stoy(m_device_samples[i]);
+        dc->DrawLine(x, lasty, x + dx, y);
+        x += dx, lasty = y;
+    }
+    dc->SetBrush(*wxBLUE_BRUSH);
+    dc->SetPen(*wxBLUE_PEN);
+    x = 0;
+    lasty = stoy(2048);
+    for (decltype(scount) i = 0; i < scount; i++) {
+        auto y = stoy(m_device_samples_input[i]);
+        dc->DrawLine(x, lasty, x + dx, y);
+        x += dx, lasty = y;
+    }
+    delete dc;
+}
+
 void MainFrame::prepareEditor()
 {
     m_text_editor->SetLexer(wxSTC_LEX_CPP);
@@ -536,11 +604,14 @@ void MainFrame::onRunStart(wxCommandEvent& ce)
                                        srateNums[m_rate_select->GetSelection()]);
             } else if (m_conv_result_log) {
                 m_measure_timer->Start(15);
+            } else if (m_run_draw_samples->IsChecked()) {
+                m_measure_timer->Start(300);
             }
 
             m_device->continuous_start();
         }
 
+        m_rate_select->Enable(false);
         menuItem->SetItemLabel("&Stop");
         m_status_bar->SetStatusText("Running.");
         m_is_running = true;
@@ -548,9 +619,13 @@ void MainFrame::onRunStart(wxCommandEvent& ce)
         m_device->continuous_stop();
         m_measure_timer->Stop();
 
+        m_rate_select->Enable(true);
         menuItem->SetItemLabel("&Start");
         m_status_bar->SetStatusText("Ready.");
         m_is_running = false;
+
+        if (m_run_draw_samples->IsChecked())
+            m_compile_output->Refresh();
     }
 }
 
@@ -581,7 +656,7 @@ void MainFrame::onRunLogResults(wxCommandEvent& ce)
 
 void MainFrame::onRunEditBSize(wxCommandEvent&)
 {
-    wxTextEntryDialog dialog (this, "Enter new buffer size (100-4000)", "Set Buffer Size");
+    wxTextEntryDialog dialog (this, "Enter new buffer size (100-4096)", "Set Buffer Size");
     if (dialog.ShowModal() == wxID_OK) {
         if (wxString value = dialog.GetValue(); !value.IsEmpty()) {
             if (unsigned long n; value.ToULong(&n)) {
@@ -667,9 +742,11 @@ void MainFrame::onRunGenStart(wxCommandEvent& ce)
     if (menuItem->IsChecked()) {
         m_device->siggen_start();
         menuItem->SetItemLabel("Stop &generator");
+        m_status_bar->SetStatusText("Generator running.");
     } else {
         m_device->siggen_stop();
         menuItem->SetItemLabel("Start &generator");
+        m_status_bar->SetStatusText("Ready.");
     }
 }
 
index e96f51d3b5cb8319cb3d644eadbc128bd72b0e6b..9b3db1e070b06d6af429941b52db7f84eb11d55f 100644 (file)
@@ -58,7 +58,8 @@ public:
     void onRunCompile(wxCommandEvent&);
     void onCodeDisassemble(wxCommandEvent&);
 
-    void onMeasureTimer(wxTimerEvent& te);
+    void onPaint(wxPaintEvent&);
+    void onMeasureTimer(wxTimerEvent&);
 
 private:
     // Set to true if connected and running
@@ -69,6 +70,7 @@ private:
     wxTextCtrl *m_compile_output = nullptr;
     wxControl *m_signal_area = nullptr;
     wxMenuItem *m_run_measure = nullptr;
+    wxMenuItem *m_run_draw_samples = nullptr;
     wxTimer *m_measure_timer = nullptr;
     wxStatusBar *m_status_bar = nullptr;
     wxMenuBar *m_menu_bar = nullptr;
@@ -87,6 +89,8 @@ private:
     // Device interface
     // Not null if connected
     stmdsp::device *m_device = nullptr;
+    stmdsp::adcsample_t *m_device_samples = nullptr;
+    stmdsp::adcsample_t *m_device_samples_input = nullptr;
     // WAV data for signal generator
     // Not null when a WAV is loaded
     wav::clip *m_wav_clip = nullptr;
index 488501c825b0de22186db0fc4dfa32e624f135f6..d9a435a717a8edef4971e8061eb92f48e5a3fecc 100644 (file)
@@ -42,6 +42,7 @@ private:
     static size_t m_current_buffer_size;
     static Operation m_operation;
 
+public:
     static void conversionCallback(ADCDriver *);
 };
 
index 0dfc0e76bcd25f1907ba8ca8c06c99ff81615488..6e5851051a3435b453bb82b5b2d4f21fce00a0d9 100644 (file)
@@ -52,7 +52,7 @@ static MAILBOX_DECL(conversionMB, conversionMBBuffer, 2);
 // Thread for LED status and wakeup hold
 __attribute__((section(".stacks")))
 static THD_WORKING_AREA(monitorThreadWA, 4096);
-static THD_FUNCTION(monitorThread, arg);
+/*extern "C"*/static THD_FUNCTION(monitorThread, arg);
 
 // Thread for managing the conversion task
 __attribute__((section(".stacks")))
@@ -161,6 +161,7 @@ THD_FUNCTION(communicationThread, arg)
                 // 'r' - Read or write sample rate.
                 // 'S' - Stop conversion.
                 // 's' - Get latest block of conversion results.
+                // 't' - Get latest block of conversion input.
                 // 'W' - Start signal generator (siggen).
                 // 'w' - Stop siggen.
 
@@ -308,6 +309,28 @@ THD_FUNCTION(communicationThread, arg)
                         USBSerial::write(reinterpret_cast<const uint8_t *>("\0\0"), 2);
                     }
                     break;
+                case 't':
+                    if (auto samps = samplesIn.modified(); samps != nullptr) {
+                        unsigned char buf[2] = {
+                            static_cast<unsigned char>(samplesIn.size() / 2 & 0xFF),
+                            static_cast<unsigned char>(((samplesIn.size() / 2) >> 8) & 0xFF)
+                        };
+                        USBSerial::write(buf, 2);
+                        unsigned int total = samplesIn.bytesize() / 2;
+                        unsigned int offset = 0;
+                        unsigned char unused;
+                        while (total > 512) {
+                            USBSerial::write(reinterpret_cast<uint8_t *>(samps) + offset, 512);
+                            while (USBSerial::read(&unused, 1) == 0);
+                            offset += 512;
+                            total -= 512;
+                        }
+                        USBSerial::write(reinterpret_cast<uint8_t *>(samps) + offset, total);
+                        while (USBSerial::read(&unused, 1) == 0);
+                    } else {
+                        USBSerial::write(reinterpret_cast<const uint8_t *>("\0\0"), 2);
+                    }
+                    break;
 
                 case 'W':
                     DAC::start(1, samplesSigGen.data(), samplesSigGen.size());
@@ -455,7 +478,13 @@ void signal_operate(adcsample_t *buffer, size_t)
         chSysUnlockFromISR();
         conversion_abort();
     } else {
-        chMBPostI(&conversionMB, buffer == samplesIn.data() ? MSG_CONVFIRST : MSG_CONVSECOND);
+        if (buffer == samplesIn.data()) {
+            samplesIn.setModified();
+            chMBPostI(&conversionMB, MSG_CONVFIRST);
+        } else {
+            samplesIn.setMidmodified();
+            chMBPostI(&conversionMB, MSG_CONVSECOND);
+        }
         chSysUnlockFromISR();
     }
 }
@@ -463,8 +492,13 @@ void signal_operate(adcsample_t *buffer, size_t)
 void signal_operate_measure(adcsample_t *buffer, [[maybe_unused]] size_t count)
 {
     chSysLockFromISR();
-    chMBPostI(&conversionMB, buffer == samplesIn.data() ? MSG_CONVFIRST_MEASURE
-                                                        : MSG_CONVSECOND_MEASURE);
+    if (buffer == samplesIn.data()) {
+        samplesIn.setModified();
+        chMBPostI(&conversionMB, MSG_CONVFIRST_MEASURE);
+    } else {
+        samplesIn.setMidmodified();
+        chMBPostI(&conversionMB, MSG_CONVSECOND_MEASURE);
+    }
     chSysUnlockFromISR();
 
     ADC::setOperation(signal_operate);
index 55ebc8156c5aad28eca093d4590433a35c153215..24cc42423fe3f975a8ead1bd11367a8bf68b5e79 100644 (file)
@@ -9,15 +9,23 @@ void SampleBuffer::clear() {
 __attribute__((section(".convcode")))
 void SampleBuffer::modify(Sample *data, unsigned int srcsize) {
     auto size = srcsize < m_size ? srcsize : m_size;
-    for (Sample *d = data, *s = m_buffer; d != data + size;)
-        *d++ = *s++;
     m_modified = m_buffer;
+    for (Sample *d = m_buffer, *s = data; s != data + size;)
+        *d++ = *s++;
 }
 __attribute__((section(".convcode")))
 void SampleBuffer::midmodify(Sample *data, unsigned int srcsize) {
     auto size = srcsize < m_size / 2 ? srcsize : m_size / 2;
-    for (Sample *d = data, *s = middata(); d != data + size;)
+    m_modified = middata();
+    for (Sample *d = middata(), *s = data; s != data + size;)
         *d++ = *s++;
+}
+
+void SampleBuffer::setModified() {
+    m_modified = m_buffer;
+}
+
+void SampleBuffer::setMidmodified() {
     m_modified = middata();
 }
 
index 334c0484f2b88cc46b5e2d22b635e8c79acdbab9..bed52bf40c8a7cfc5f18b959e750c8d6ad6c1431 100644 (file)
@@ -6,7 +6,7 @@
 
 using Sample = uint16_t;
 
-// gives 8000 (8192)
+// Gives 8000 (8192) samples total (algorithm works with max 4096).
 constexpr unsigned int MAX_SAMPLE_BUFFER_BYTESIZE = 16384;
 constexpr unsigned int MAX_SAMPLE_BUFFER_SIZE = MAX_SAMPLE_BUFFER_BYTESIZE / sizeof(Sample);
 
@@ -19,6 +19,8 @@ public:
 
     void modify(Sample *data, unsigned int srcsize);
     void midmodify(Sample *data, unsigned int srcsize);
+    void setModified();
+    void setMidmodified();
     Sample *modified();
 
     Sample *data();