From 4f59610a00da78639c1909acb09c7dfde4519a28 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Wed, 27 Jan 2021 11:18:33 -0500 Subject: sandboxed user algorithm --- source/samplebuffer.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 source/samplebuffer.cpp (limited to 'source/samplebuffer.cpp') diff --git a/source/samplebuffer.cpp b/source/samplebuffer.cpp new file mode 100644 index 0000000..6932392 --- /dev/null +++ b/source/samplebuffer.cpp @@ -0,0 +1,52 @@ +#include "common.hpp" + +SampleBuffer::SampleBuffer(Sample *buffer) : + m_buffer(buffer) {} + +void SampleBuffer::clear() { + std::fill(m_buffer, m_buffer + m_size, 2048); +} +__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; +} +__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;) + *d++ = *s++; + m_modified = middata(); +} + +void SampleBuffer::setSize(unsigned int size) { + m_size = size < MAX_SAMPLE_BUFFER_SIZE ? size : MAX_SAMPLE_BUFFER_SIZE; +} + +__attribute__((section(".convcode"))) +Sample *SampleBuffer::data() { + return m_buffer; +} +__attribute__((section(".convcode"))) +Sample *SampleBuffer::middata() { + return m_buffer + m_size / 2; +} +uint8_t *SampleBuffer::bytedata() { + return reinterpret_cast(m_buffer); +} + +Sample *SampleBuffer::modified() { + auto m = m_modified; + m_modified = nullptr; + return m; +} +__attribute__((section(".convcode"))) +unsigned int SampleBuffer::size() const { + return m_size; +} +unsigned int SampleBuffer::bytesize() const { + return m_size * sizeof(Sample); +} + -- cgit v1.2.3 From 87851f4e6c4aebd65e28ef16823ada7b197e2edc Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Wed, 3 Feb 2021 20:39:15 -0500 Subject: more stack space; expose trig to algorithms --- Makefile | 8 +++---- STM32H723xG.ld | 16 +++++++++----- gui/wxmain.cpp | 49 ++++++++++++++++++++++++++++++++++++------ source/main.cpp | 57 ++++++++++++++++++++++++++++++++++--------------- source/samplebuffer.cpp | 2 +- 5 files changed, 99 insertions(+), 33 deletions(-) (limited to 'source/samplebuffer.cpp') diff --git a/Makefile b/Makefile index 178b026..53340e4 100644 --- a/Makefile +++ b/Makefile @@ -55,13 +55,13 @@ endif # Stack size to be allocated to the Cortex-M process stack. This stack is # the stack used by the main() thread. ifeq ($(USE_PROCESS_STACKSIZE),) - USE_PROCESS_STACKSIZE = 0x400 + USE_PROCESS_STACKSIZE = 0x1000 endif # Stack size to the allocated to the Cortex-M main/exceptions stack. This # stack is used for processing interrupts and exceptions. ifeq ($(USE_EXCEPTIONS_STACKSIZE),) - USE_EXCEPTIONS_STACKSIZE = 0x400 + USE_EXCEPTIONS_STACKSIZE = 0x1000 endif # Enables the use of FPU (no, softfp, hard). @@ -134,10 +134,10 @@ ASMXSRC = $(ALLXASMSRC) INCDIR = $(CONFDIR) $(ALLINC) $(TESTINC) # Define C warning options here. -CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes +CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes -pedantic # Define C++ warning options here. -CPPWARN = -Wall -Wextra -Wundef +CPPWARN = -Wall -Wextra -Wundef -pedantic # # Project, target, sources and paths diff --git a/STM32H723xG.ld b/STM32H723xG.ld index e59c900..7d5bafb 100644 --- a/STM32H723xG.ld +++ b/STM32H723xG.ld @@ -19,15 +19,15 @@ * SRAM1 - SIGGEN. * SRAM2 - DAC. * SRAM4 - ADC. - * DTCM-RAM - Unprivileged Stack, Main Stack, Process Stack. + * DTCM-RAM - Process stacks. * ITCM-RAM - STMDSP Algorithm. * BCKP SRAM - None. */ MEMORY { flash0 (rx) : org = 0x08000000, len = 1M /* Flash bank1 + bank2 */ - flashc (rx) : org = 0x0807F000, len = 4K /* Unprivileged firmware */ - flash1 (rx) : org = 0x08000000, len = 512K /* Flash bank 1 */ + flash1 (rx) : org = 0x08000000, len = 510K /* Flash bank 1 */ + flashc (rx) : org = 0x0807F800, len = 2K /* Unprivileged firmware */ flash2 (rx) : org = 0x08080000, len = 512K /* Flash bank 2 */ flash3 (rx) : org = 0x00000000, len = 0 flash4 (rx) : org = 0x00000000, len = 0 @@ -39,8 +39,8 @@ MEMORY ram2 (wx) : org = 0x30004000, len = 16K /* AHB SRAM2 */ ram3 (wx) : org = 0x38000000, len = 16K /* AHB SRAM4 */ ram4 (wx) : org = 0x00000000, len = 0 - ramc (wx) : org = 0x20000000, len = 4K /* Unprivileged data */ - ram5 (wx) : org = 0x20001000, len = 124K /* DTCM-RAM */ + ramc (wx) : org = 0x20000000, len = 64K /* Unprivileged data */ + ram5 (wx) : org = 0x20010000, len = 64K /* DTCM-RAM */ ram6 (wx) : org = 0x00000000, len = 64K /* ITCM-RAM */ ram7 (wx) : org = 0x38800000, len = 4K /* BCKP SRAM */ } @@ -100,6 +100,12 @@ SECTIONS . = ALIGN(4); } > ramc + .stacks : ALIGN(4) + { + *(.stacks) + . = ALIGN(4); + } > ram5 + .convcode : ALIGN(4) { *(.convcode) diff --git a/gui/wxmain.cpp b/gui/wxmain.cpp index 86807ab..10e5d7a 100644 --- a/gui/wxmain.cpp +++ b/gui/wxmain.cpp @@ -65,14 +65,50 @@ static const char *file_header = R"cpp( using adcsample_t = uint16_t; constexpr unsigned int SIZE = $0; - adcsample_t *process_data(adcsample_t *samples, unsigned int size); - extern "C" void process_data_entry() { ((void (*)())process_data)(); } +constexpr double PI = 3.14159265358979323846L; +__attribute__((naked)) +auto sin(double x) { +asm("vmov.f64 r1, r2, d0;" + "eor r0, r0;" + "svc 1;" + "vmov.f64 d0, r1, r2;" + "bx lr"); +return 0; +} +__attribute__((naked)) +auto cos(double x) { +asm("vmov.f64 r1, r2, d0;" + "mov r0, #1;" + "svc 1;" + "vmov.f64 d0, r1, r2;" + "bx lr"); +return 0; +} +__attribute__((naked)) +auto tan(double x) { +asm("vmov.f64 r1, r2, d0;" + "mov r0, #2;" + "svc 1;" + "vmov.f64 d0, r1, r2;" + "bx lr"); +return 0; +} +__attribute__((naked)) +auto sqrt(double x) { +asm("vmov.f64 r1, r2, d0;" + "mov r0, #3;" + "svc 1;" + "vmov.f64 d0, r1, r2;" + "bx lr"); +return 0; +} + // End stmdspgui header code )cpp"; @@ -223,11 +259,12 @@ MainFrame::MainFrame() : wxFrame(nullptr, wxID_ANY, "stmdspgui", wxPoint(50, 50) void MainFrame::onCloseEvent(wxCloseEvent& event) { SetMenuBar(nullptr); - delete m_menu_bar->Remove(2); - delete m_menu_bar->Remove(1); - delete m_menu_bar->Remove(0); - delete m_menu_bar; + //delete m_menu_bar->Remove(2); + //delete m_menu_bar->Remove(1); + //delete m_menu_bar->Remove(0); + //delete m_menu_bar; delete m_measure_timer; + delete m_device; Unbind(wxEVT_COMBOBOX, &MainFrame::onToolbarSampleRate, this, wxID_ANY, wxID_ANY); Unbind(wxEVT_BUTTON, &MainFrame::onRunCompile, this, Id::MCodeCompile, wxID_ANY); diff --git a/source/main.cpp b/source/main.cpp index 1a89c93..d94f694 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -50,16 +50,19 @@ static msg_t conversionMBBuffer[2]; static MAILBOX_DECL(conversionMB, conversionMBBuffer, 2); // Thread for LED status and wakeup hold -static THD_WORKING_AREA(monitorThreadWA, 128); +__attribute__((section(".stacks"))) +static THD_WORKING_AREA(monitorThreadWA, 1024); static THD_FUNCTION(monitorThread, arg); // Thread for managing the conversion task -static THD_WORKING_AREA(conversionThreadMonitorWA, 128); +__attribute__((section(".stacks"))) +static THD_WORKING_AREA(conversionThreadMonitorWA, 1024); static THD_FUNCTION(conversionThreadMonitor, arg); // Thread for unprivileged algorithm execution -static THD_WORKING_AREA(conversionThreadWA, 128); +__attribute__((section(".stacks"))) +static THD_WORKING_AREA(conversionThreadWA, 1024); static THD_FUNCTION(conversionThread, arg); __attribute__((section(".convdata"))) -static THD_WORKING_AREA(conversionThreadUPWA, 256); +static THD_WORKING_AREA(conversionThreadUPWA, 62 * 1024); static thread_t *conversionThreadHandle = nullptr; __attribute__((section(".convdata"))) @@ -98,13 +101,13 @@ int main() mpuConfigureRegion(MPU_REGION_2, 0x20000000, MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | - MPU_RASR_SIZE_4K | + MPU_RASR_SIZE_64K | MPU_RASR_ENABLE); // Region 3: Code for algorithm manager thread mpuConfigureRegion(MPU_REGION_3, - 0x08080000, + 0x0807F800, MPU_RASR_ATTR_AP_RO_RO | MPU_RASR_ATTR_NON_CACHEABLE | - MPU_RASR_SIZE_4K | + MPU_RASR_SIZE_2K | MPU_RASR_ENABLE); // Region 4: Algorithm code mpuConfigureRegion(MPU_REGION_4, @@ -408,10 +411,12 @@ THD_FUNCTION(monitorThread, arg) if (run_status == RunStatus::Idle && palReadLine(LINE_BUTTON)) { palSetLine(LINE_LED_RED); palSetLine(LINE_LED_YELLOW); - asm("cpsid i"); + chSysLock(); + while (palReadLine(LINE_BUTTON)) + asm("nop"); while (!palReadLine(LINE_BUTTON)) asm("nop"); - asm("cpsie i"); + chSysUnlock(); palClearLine(LINE_LED_RED); palClearLine(LINE_LED_YELLOW); chThdSleepMilliseconds(500); @@ -433,15 +438,33 @@ __attribute__((naked)) void port_syscall(struct port_extctx *ctxp, uint32_t n) { switch (n) { - case 0: { - chSysLock(); - chMsgWaitS(); - auto msg = chMsgGet(conversionThreadMonitorHandle); - chMsgReleaseS(conversionThreadMonitorHandle, MSG_OK); - //chSchDoYieldS(); - chSysUnlock(); - ctxp->r0 = msg; + case 0: + { + chSysLock(); + chMsgWaitS(); + auto msg = chMsgGet(conversionThreadMonitorHandle); + chMsgReleaseS(conversionThreadMonitorHandle, MSG_OK); + chSysUnlock(); + ctxp->r0 = msg; + } + break; + case 1: + { + using mathcall = void (*)(); + static mathcall funcs[4] = { + reinterpret_cast(math::sin), + reinterpret_cast(math::cos), + reinterpret_cast(math::tan), + reinterpret_cast(math::sqrt), + }; + asm("vmov.f64 d0, %0, %1" :: "r" (ctxp->r1), "r" (ctxp->r2)); + if (ctxp->r0 < 4) { + funcs[ctxp->r0](); + asm("vmov.f64 %0, %1, d0" : "=r" (ctxp->r1), "=r" (ctxp->r2)); + } else { + asm("eor r0, r0; vmov.f64 d0, r0, r0"); } + } break; default: while (1); diff --git a/source/samplebuffer.cpp b/source/samplebuffer.cpp index 6932392..55ebc81 100644 --- a/source/samplebuffer.cpp +++ b/source/samplebuffer.cpp @@ -1,4 +1,4 @@ -#include "common.hpp" +#include "samplebuffer.hpp" SampleBuffer::SampleBuffer(Sample *buffer) : m_buffer(buffer) {} -- cgit v1.2.3 From 5f6181bb3c6ab4274a8068aaf14b278fa65e443e Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sun, 21 Feb 2021 08:59:15 -0500 Subject: signal monitoring support --- Makefile | 4 +-- gui/Makefile | 17 +++++---- gui/stmdsp.cpp | 27 +++++++++++++++ gui/stmdsp.hpp | 3 +- gui/wxmain.cpp | 91 +++++++++++++++++++++++++++++++++++++++++++++---- gui/wxmain.hpp | 6 +++- source/adc.hpp | 1 + source/main.cpp | 42 ++++++++++++++++++++--- source/samplebuffer.cpp | 14 ++++++-- source/samplebuffer.hpp | 4 ++- 10 files changed, 183 insertions(+), 26 deletions(-) (limited to 'source/samplebuffer.cpp') diff --git a/Makefile b/Makefile index 53340e4..7c36535 100644 --- 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). diff --git a/gui/Makefile b/gui/Makefile index 679e1e4..20dd473 100644 --- a/gui/Makefile +++ b/gui/Makefile @@ -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) diff --git a/gui/stmdsp.cpp b/gui/stmdsp.cpp index 1b4bba6..5ea18af 100644 --- a/gui/stmdsp.cpp +++ b/gui/stmdsp.cpp @@ -120,6 +120,33 @@ namespace stmdsp return {}; } + std::vector 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 data (size); + unsigned int total = size * sizeof(adcsample_t); + unsigned int offset = 0; + + while (total > 512) { + m_serial.read(reinterpret_cast(&data[0]) + offset, 512); + m_serial.write("n"); + offset += 512; + total -= 512; + } + m_serial.read(reinterpret_cast(&data[0]) + offset, total); + m_serial.write("n"); + return data; + + } + } + + return {}; + } + void device::continuous_stop() { if (connected()) m_serial.write("S"); diff --git a/gui/stmdsp.hpp b/gui/stmdsp.hpp index f805ab3..a22a55d 100644 --- a/gui/stmdsp.hpp +++ b/gui/stmdsp.hpp @@ -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 continuous_read(); + std::vector continuous_read_input(); void continuous_stop(); void siggen_upload(dacsample_t *buffer, unsigned int size); diff --git a/gui/wxmain.cpp b/gui/wxmain.cpp index c7acddf..e5f0d4d 100644 --- a/gui/wxmain.cpp +++ b/gui/wxmain.cpp @@ -12,6 +12,7 @@ #include "wxmain.hpp" #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include +#include #include static const std::array 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(::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(::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(py) + rect.GetHeight() - + (static_cast(rect.GetHeight()) * s / 4095.f); + }; + auto scount = m_device->get_buffer_size(); + float dx = static_cast(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."); } } diff --git a/gui/wxmain.hpp b/gui/wxmain.hpp index e96f51d..9b3db1e 100644 --- a/gui/wxmain.hpp +++ b/gui/wxmain.hpp @@ -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; diff --git a/source/adc.hpp b/source/adc.hpp index 488501c..d9a435a 100644 --- a/source/adc.hpp +++ b/source/adc.hpp @@ -42,6 +42,7 @@ private: static size_t m_current_buffer_size; static Operation m_operation; +public: static void conversionCallback(ADCDriver *); }; diff --git a/source/main.cpp b/source/main.cpp index 0dfc0e7..6e58510 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -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("\0\0"), 2); } break; + case 't': + if (auto samps = samplesIn.modified(); samps != nullptr) { + unsigned char buf[2] = { + static_cast(samplesIn.size() / 2 & 0xFF), + static_cast(((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(samps) + offset, 512); + while (USBSerial::read(&unused, 1) == 0); + offset += 512; + total -= 512; + } + USBSerial::write(reinterpret_cast(samps) + offset, total); + while (USBSerial::read(&unused, 1) == 0); + } else { + USBSerial::write(reinterpret_cast("\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); diff --git a/source/samplebuffer.cpp b/source/samplebuffer.cpp index 55ebc81..24cc424 100644 --- a/source/samplebuffer.cpp +++ b/source/samplebuffer.cpp @@ -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(); } diff --git a/source/samplebuffer.hpp b/source/samplebuffer.hpp index 334c048..bed52bf 100644 --- a/source/samplebuffer.hpp +++ b/source/samplebuffer.hpp @@ -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(); -- cgit v1.2.3