diff options
-rw-r--r-- | Makefile | 27 | ||||
-rw-r--r-- | examples/1_convolve_simple.cpp | 9 | ||||
-rw-r--r-- | examples/2_convolve_overlap_save.cpp | 8 | ||||
-rw-r--r-- | examples/3_fir.cpp | 8 | ||||
-rw-r--r-- | examples/4_fir_pro.cpp | 10 | ||||
-rw-r--r-- | examples/5_fir_differentiator.cpp | 8 | ||||
-rw-r--r-- | examples/6_iir_test.cpp | 18 | ||||
-rw-r--r-- | examples/7_iir_echo.cpp | 16 | ||||
-rw-r--r-- | source/circular.hpp | 7 | ||||
-rw-r--r-- | source/code.cpp | 19 | ||||
-rw-r--r-- | source/config.h | 8 | ||||
-rw-r--r-- | source/device.cpp | 73 | ||||
-rw-r--r-- | source/gui.cpp | 8 | ||||
-rw-r--r-- | source/gui_code.cpp | 6 | ||||
-rw-r--r-- | source/gui_device.cpp | 54 | ||||
-rw-r--r-- | source/main.cpp | 59 | ||||
-rw-r--r-- | source/stmdsp/stmdsp.cpp | 40 | ||||
-rw-r--r-- | source/stmdsp/stmdsp.hpp | 21 | ||||
-rw-r--r-- | source/stmdsp/stmdsp_code.hpp | 58 |
19 files changed, 254 insertions, 203 deletions
@@ -1,27 +1,30 @@ -#linux: CXXFILES += source/serial/src/impl/unix.cc source/serial/src/impl/list_ports/list_ports_unix.cc -#linux: LDFLAGS = -lSDL2 -lGL -lpthread - -#CROSS = x86_64-w64-mingw32- -#CXX = $(CROSS)g++ CXX = g++ CXXFILES := \ source/serial/src/serial.cc \ - source/serial/src/impl/win.cc \ - source/serial/src/impl/list_ports/list_ports_win.cc \ $(wildcard source/imgui/backends/*.cpp) \ $(wildcard source/imgui/*.cpp) \ $(wildcard source/stmdsp/*.cpp) \ $(wildcard source/*.cpp) -OFILES := $(patsubst %.cc, %.o, $(patsubst %.cpp, %.o, $(CXXFILES))) -OUTPUT := stmdspgui.exe - CXXFLAGS := -std=c++20 -O2 \ -Isource -Isource/imgui -Isource/stmdsp -Isource/serial/include \ - -Wall -Wextra -pedantic \ - -DSTMDSP_WIN32 -Wa,-mbig-obj -DSTMDSP_DISABLE_FORMULAS + -Wall -Wextra -pedantic #-DSTMDSP_DISABLE_FORMULAS + +ifeq ($(OS),Windows_NT) +CXXFILES += source/serial/src/impl/win.cc \ + source/serial/src/impl/list_ports/list_ports_win.cc +CXXFLAGS += -DSTMDSP_WIN32 -Wa,-mbig-obj LDFLAGS = -mwindows -lSDL2 -lopengl32 -lsetupapi -lole32 +OUTPUT := stmdspgui.exe +else +CXXFILES += source/serial/src/impl/unix.cc \ + source/serial/src/impl/list_ports/list_ports_unix.cc +LDFLAGS = -lSDL2 -lGL -lpthread +OUTPUT := stmdspgui +endif + +OFILES := $(patsubst %.cc, %.o, $(patsubst %.cpp, %.o, $(CXXFILES))) all: $(OUTPUT) diff --git a/examples/1_convolve_simple.cpp b/examples/1_convolve_simple.cpp index 8de05d3..95877f1 100644 --- a/examples/1_convolve_simple.cpp +++ b/examples/1_convolve_simple.cpp @@ -7,10 +7,10 @@ * transient response is not calculated. */ -Sample *process_data(Samples samples) +Sample* process_data(Samples samples) { - // Define our output buffer. SIZE is the largest size of the 'samples' buffer. - static Sample buffer[samples.size()]; + // Define our output buffer. + static Samples buffer; // Define our filter constexpr unsigned int filter_size = 3; @@ -19,7 +19,8 @@ Sample *process_data(Samples samples) }; // Begin convolving: - for (int n = 0; n < samples.size() - (filter_size - 1); n++) { + // SIZE is the size of the sample buffer. + for (int n = 0; n < SIZE - (filter_size - 1); n++) { buffer[n] = 0; for (int k = 0; k < filter_size; k++) buffer[n] += samples[n + k] * filter[k]; diff --git a/examples/2_convolve_overlap_save.cpp b/examples/2_convolve_overlap_save.cpp index 57c020a..5651f3e 100644 --- a/examples/2_convolve_overlap_save.cpp +++ b/examples/2_convolve_overlap_save.cpp @@ -11,9 +11,9 @@ * computation. */ -Sample *process_data(Samples samples) +Sample* process_data(Samples samples) { - static Sample buffer[samples.size()]; + static Samples buffer; constexpr unsigned int filter_size = 3; float filter[filter_size] = { @@ -23,7 +23,7 @@ Sample *process_data(Samples samples) // Keep a buffer of extra samples for overlap-save static Sample prev[filter_size]; - for (int n = 0; n < samples.size(); n++) { + for (int n = 0; n < SIZE; n++) { buffer[n] = 0; for (int k = 0; k < filter_size; k++) { @@ -40,7 +40,7 @@ Sample *process_data(Samples samples) // Save samples for the next convolution run for (int i = 0; i < filter_size; i++) - prev[i] = samples[samples.size() - filter_size + i]; + prev[i] = samples[SIZE - filter_size + i]; return buffer; } diff --git a/examples/3_fir.cpp b/examples/3_fir.cpp index 3a68500..b6d8751 100644 --- a/examples/3_fir.cpp +++ b/examples/3_fir.cpp @@ -7,9 +7,9 @@ * within the available execution time. Samples are also normalized so that they center around zero. */ -Sample *process_data(Samples samples) +Sample* process_data(Samples samples) { - static Sample buffer[samples.size()]; + static Samples buffer; // Define the filter: constexpr unsigned int filter_size = 3; @@ -21,7 +21,7 @@ Sample *process_data(Samples samples) // Do an overlap-save convolution static Sample prev[filter_size]; - for (int n = 0; n < samples.size(); n++) { + for (int n = 0; n < SIZE; n++) { // Using a float variable for accumulation allows for better code optimization float v = 0; @@ -40,7 +40,7 @@ Sample *process_data(Samples samples) // Save samples for next convolution for (int i = 0; i < filter_size; i++) - prev[i] = samples[samples.size() - filter_size + i]; + prev[i] = samples[SIZE - filter_size + i]; return buffer; } diff --git a/examples/4_fir_pro.cpp b/examples/4_fir_pro.cpp index b1a6832..1771cd5 100644 --- a/examples/4_fir_pro.cpp +++ b/examples/4_fir_pro.cpp @@ -10,7 +10,7 @@ typedef struct static void arm_fir_f32(const arm_fir_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize); -Sample *process_data(Samples samples) +Sample* process_data(Samples samples) { // 1. Define our array sizes (Be sure to set Run > Set buffer size... to below value!) constexpr unsigned int buffer_size = 500; @@ -34,18 +34,18 @@ Sample *process_data(Samples samples) static float working[buffer_size + filter_size]; // 3. Scale 0-4095 interger sample values to +/- 1.0 floats - for (unsigned int i = 0; i < samples.size(); i++) + for (unsigned int i = 0; i < SIZE; i++) input[i] = (samples[i] - 2048) / 2048.f; // 4. Compute the FIR arm_fir_instance_f32 fir { filter_size, working, filter }; - arm_fir_f32(&fir, input, output, samples.size()); + arm_fir_f32(&fir, input, output, SIZE); // 5. Convert float results back to 0-4095 range for output - for (unsigned int i = 0; i < samples.size(); i++) + for (unsigned int i = 0; i < SIZE; i++) samples[i] = output[i] * 2048.f + 2048; - return samples.data(); + return samples; } // Below taken from the CMSIS DSP Library (find it on GitHub) diff --git a/examples/5_fir_differentiator.cpp b/examples/5_fir_differentiator.cpp index 72415c6..1500dee 100644 --- a/examples/5_fir_differentiator.cpp +++ b/examples/5_fir_differentiator.cpp @@ -7,23 +7,23 @@ * A scaling factor is applied so that the output's form is more clearly visible. */ -Sample *process_data(Samples samples) +Sample* process_data(Samples samples) { constexpr int scaling_factor = 4; - static Sample output[samples.size()]; + static Samples output; static Sample prev = 2048; // Compute the first output value using the saved sample. output[0] = 2048 + ((samples[0] - prev) * scaling_factor); - for (unsigned int i = 1; i < samples.size(); i++) { + for (unsigned int i = 1; i < SIZE; i++) { // Take the rate of change and scale it. // 2048 is added as the output should be centered in the voltage range. output[i] = 2048 + ((samples[i] - samples[i - 1]) * scaling_factor); } // Save the last sample for the next iteration. - prev = samples[samples.size() - 1]; + prev = samples[SIZE - 1]; return output; } diff --git a/examples/6_iir_test.cpp b/examples/6_iir_test.cpp index 116a680..e0b266d 100644 --- a/examples/6_iir_test.cpp +++ b/examples/6_iir_test.cpp @@ -1,13 +1,23 @@ -Sample *process_data(Samples samples) +/** + * 6_iir_test.cpp + * Written by Clyne Sullivan. + * + * Implements a simple infinite impulse response (IIR) filter using an alpha + * parameter. + * To build upon this example, try setting `alpha` with a parameter knob: + * alpha = param1() / 4095.0 + */ + +Sample* process_data(Samples samples) { constexpr float alpha = 0.7; static Sample prev = 2048; samples[0] = (1 - alpha) * samples[0] + alpha * prev; - for (unsigned int i = 1; i < samples.size(); i++) + for (unsigned int i = 1; i < SIZE; i++) samples[i] = (1 - alpha) * samples[i] + alpha * samples[i - 1]; - prev = samples[samples.size() - 1]; + prev = samples[SIZE - 1]; - return samples.data(); + return samples; } diff --git a/examples/7_iir_echo.cpp b/examples/7_iir_echo.cpp index 57e5605..75bf56e 100644 --- a/examples/7_iir_echo.cpp +++ b/examples/7_iir_echo.cpp @@ -1,9 +1,17 @@ -Sample *process_data(Samples samples) +/** + * 7_iir_echo.cpp + * Written by Clyne Sullivan. + * + * This filter produces an echo of the given input. There are two parameters: + * alpha controls the feedback gain, and D controls the echo/delay length. + */ + +Sample* process_data(Samples samples) { constexpr float alpha = 0.75; constexpr unsigned int D = 100; - static Sample output[samples.size()]; + static Samples output; static Sample prev[D]; // prev[0] = output[0 - D] // Do calculations with previous output @@ -11,12 +19,12 @@ Sample *process_data(Samples samples) output[i] = samples[i] + alpha * (prev[i] - 2048); // Do calculations with current samples - for (unsigned int i = D; i < samples.size(); i++) + for (unsigned int i = D; i < SIZE; i++) output[i] = samples[i] + alpha * (output[i - D] - 2048); // Save outputs for next computation for (unsigned int i = 0; i < D; i++) - prev[i] = output[samples.size() - (D - i)]; + prev[i] = output[SIZE - (D - i)]; return output; } diff --git a/source/circular.hpp b/source/circular.hpp index 6b82068..4f49322 100644 --- a/source/circular.hpp +++ b/source/circular.hpp @@ -21,7 +21,7 @@ public: CircularBuffer(Container<T>& container) : m_begin(std::begin(container)), m_end(std::end(container)), - m_current(std::begin(container)) {} + m_current(m_begin) {} void put(const T& value) noexcept { *m_current = value; @@ -33,6 +33,11 @@ public: return std::distance(m_begin, m_end); } + void reset(const T& fill) noexcept { + std::fill(m_begin, m_end, fill); + m_current = m_begin; + } + private: Container<T>::iterator m_begin; Container<T>::iterator m_end; diff --git a/source/code.cpp b/source/code.cpp index 14f603c..8e3bd6c 100644 --- a/source/code.cpp +++ b/source/code.cpp @@ -134,18 +134,17 @@ std::string newTempFileName() bool codeExecuteCommand(const std::string& command, const std::string& file) { bool success = system(command.c_str()) == 0; - if (success) { - if (std::ifstream output (file); output.good()) { - std::ostringstream sstr; - sstr << output.rdbuf(); - log(sstr.str().c_str()); - } else { - log("Could not read command output!"); - } - - std::filesystem::remove(file); + + if (std::ifstream output (file); output.good()) { + std::ostringstream sstr; + sstr << output.rdbuf(); + log(sstr.str().c_str()); + } else { + log("Could not read command output!"); } + std::filesystem::remove(file); + return success; } diff --git a/source/config.h b/source/config.h deleted file mode 100644 index 879a0ea..0000000 --- a/source/config.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef STMDSP_CONFIG_H -#define STMDSP_CONFIG_H - -constexpr unsigned int WINDOW_WIDTH = 640; -constexpr unsigned int WINDOW_HEIGHT = 720; - -#endif - diff --git a/source/device.cpp b/source/device.cpp index edd950c..9c50a0d 100644 --- a/source/device.cpp +++ b/source/device.cpp @@ -33,6 +33,7 @@ extern void log(const std::string& str); extern std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string&); extern std::ifstream compileOpenBinaryFile(); +extern void deviceRenderDisconnect(); std::shared_ptr<stmdsp::device> m_device; @@ -45,9 +46,15 @@ static std::deque<stmdsp::dacsample_t> drawSamplesInputQueue; static bool drawSamplesInput = false; static unsigned int drawSamplesBufferSize = 1; +bool deviceConnect(); + void deviceSetInputDrawing(bool enabled) { drawSamplesInput = enabled; + if (enabled) { + drawSamplesQueue.clear(); + drawSamplesInputQueue.clear(); + } } static void measureCodeTask(std::shared_ptr<stmdsp::device> device) @@ -55,7 +62,7 @@ static void measureCodeTask(std::shared_ptr<stmdsp::device> device) std::this_thread::sleep_for(std::chrono::seconds(1)); if (device) { - const auto cycles = device->continuous_start_get_measurement(); + const auto cycles = device->measurement_read(); log(std::string("Execution time: ") + std::to_string(cycles) + " cycles."); } } @@ -111,11 +118,20 @@ static void drawSamplesTask(std::shared_ptr<stmdsp::device> device) const auto next = std::chrono::high_resolution_clock::now() + bufferTime; if (lockDevice.try_lock_until(next)) { - const auto chunk = tryReceiveChunk(device, + std::vector<stmdsp::dacsample_t> chunk, chunk2; + + chunk = tryReceiveChunk(device, std::mem_fn(&stmdsp::device::continuous_read)); + if (drawSamplesInput) { + chunk2 = tryReceiveChunk(device, + std::mem_fn(&stmdsp::device::continuous_read_input)); + } + lockDevice.unlock(); addToQueue(drawSamplesQueue, chunk); + if (drawSamplesInput) + addToQueue(drawSamplesInputQueue, chunk2); if (logSamplesFile.is_open()) { for (const auto& s : chunk) @@ -126,16 +142,6 @@ static void drawSamplesTask(std::shared_ptr<stmdsp::device> device) std::this_thread::sleep_for(std::chrono::milliseconds(50)); } - if (drawSamplesInput) { - if (lockDevice.try_lock_for(std::chrono::milliseconds(1))) { - const auto chunk2 = tryReceiveChunk(device, - std::mem_fn(&stmdsp::device::continuous_read_input)); - lockDevice.unlock(); - - addToQueue(drawSamplesInputQueue, chunk2); - } - } - std::this_thread::sleep_until(next); } } @@ -196,6 +202,12 @@ static void statusTask(std::shared_ptr<stmdsp::device> device) case stmdsp::Error::ConversionAborted: log("Error: Algorithm unloaded, a fault occurred!"); break; + case stmdsp::Error::GUIDisconnect: + // Do GUI events for disconnect if device was lost. + deviceConnect(); + deviceRenderDisconnect(); + return; + break; default: log("Error: Device had an issue..."); break; @@ -304,7 +316,7 @@ bool deviceConnect() return false; } -void deviceStart(bool measureCodeTime, bool logResults, bool drawSamples) +void deviceStart(bool logResults, bool drawSamples) { if (!m_device) { log("No device connected."); @@ -323,18 +335,22 @@ void deviceStart(bool measureCodeTime, bool logResults, bool drawSamples) } log("Ready."); } else { - if (measureCodeTime) { - m_device->continuous_start_measure(); - std::thread(measureCodeTask, m_device).detach(); - } else { - m_device->continuous_start(); - if (drawSamples || logResults || wavOutput.valid()) - std::thread(drawSamplesTask, m_device).detach(); - } + m_device->continuous_start(); + if (drawSamples || logResults || wavOutput.valid()) + std::thread(drawSamplesTask, m_device).detach(); + log("Running."); } } +void deviceStartMeasurement() +{ + if (m_device && m_device->is_running()) { + m_device->measurement_start(); + std::thread(measureCodeTask, m_device).detach(); + } +} + void deviceAlgorithmUpload() { if (!m_device) { @@ -390,7 +406,7 @@ void deviceGenLoadList(const std::string_view list) } } - it = itend; + it = std::find_if(itend, list.cend(), isdigit); } if (it == list.cend()) { @@ -417,8 +433,7 @@ void deviceGenLoadFormula(const std::string& formula) std::size_t pullFromQueue( std::deque<stmdsp::dacsample_t>& queue, - CircularBuffer<std::vector, stmdsp::dacsample_t>& circ, - double timeframe) + CircularBuffer<std::vector, stmdsp::dacsample_t>& circ) { // We know how big the circular buffer should be to hold enough samples to // fill the current draw samples view. @@ -453,16 +468,14 @@ std::size_t pullFromQueue( * the samples to the given buffer. */ std::size_t pullFromDrawQueue( - CircularBuffer<std::vector, stmdsp::dacsample_t>& circ, - double timeframe) + CircularBuffer<std::vector, stmdsp::dacsample_t>& circ) { - return pullFromQueue(drawSamplesQueue, circ, timeframe); + return pullFromQueue(drawSamplesQueue, circ); } std::size_t pullFromInputDrawQueue( - CircularBuffer<std::vector, stmdsp::dacsample_t>& circ, - double timeframe) + CircularBuffer<std::vector, stmdsp::dacsample_t>& circ) { - return pullFromQueue(drawSamplesInputQueue, circ, timeframe); + return pullFromQueue(drawSamplesInputQueue, circ); } diff --git a/source/gui.cpp b/source/gui.cpp index 80120c4..43c95df 100644 --- a/source/gui.cpp +++ b/source/gui.cpp @@ -14,8 +14,6 @@ #include "backends/imgui_impl_sdl.h" #include "backends/imgui_impl_opengl2.h" -#include "config.h" - #include <SDL2/SDL.h> #include <SDL2/SDL_opengl.h> @@ -42,14 +40,16 @@ bool guiInitialize() SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); window = SDL_CreateWindow("stmdsp gui", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - WINDOW_WIDTH, WINDOW_HEIGHT, - SDL_WINDOW_OPENGL /*| SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI*/); + 640, 700, + SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE /*| SDL_WINDOW_ALLOW_HIGHDPI*/); if (window == nullptr) { puts("Error: Could not create the window!"); return false; } + SDL_SetWindowMinimumSize(window, 320, 320); + gl_context = SDL_GL_CreateContext(window); SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync diff --git a/source/gui_code.cpp b/source/gui_code.cpp index 19fa572..50fd0c8 100644 --- a/source/gui_code.cpp +++ b/source/gui_code.cpp @@ -14,8 +14,6 @@ #include "backends/imgui_impl_opengl2.h" #include "TextEditor.h" -#include "config.h" - #include <string> extern void compileEditorCode(const std::string& code); @@ -52,9 +50,9 @@ void codeRenderToolbar() codeCompile(); } -void codeRenderWidgets() +void codeRenderWidgets(const ImVec2& size) { - editor.Render("code", {WINDOW_WIDTH - 15, 450}, true); + editor.Render("code", size, true); } static void codeCompile() diff --git a/source/gui_device.cpp b/source/gui_device.cpp index 43c0a58..689ef54 100644 --- a/source/gui_device.cpp +++ b/source/gui_device.cpp @@ -24,14 +24,13 @@ void deviceLoadAudioFile(const std::string& file); void deviceLoadLogFile(const std::string& file); void deviceSetSampleRate(unsigned int index); void deviceSetInputDrawing(bool enabled); -void deviceStart(bool measureCodeTime, bool logResults, bool drawSamples); +void deviceStart(bool logResults, bool drawSamples); +void deviceStartMeasurement(); void deviceUpdateDrawBufferSize(double timeframe); std::size_t pullFromDrawQueue( - CircularBuffer<std::vector, stmdsp::dacsample_t>& circ, - double timeframe); + CircularBuffer<std::vector, stmdsp::dacsample_t>& circ); std::size_t pullFromInputDrawQueue( - CircularBuffer<std::vector, stmdsp::dacsample_t>& circ, - double timeframe); + CircularBuffer<std::vector, stmdsp::dacsample_t>& circ); static std::string sampleRatePreview = "?"; static bool measureCodeTime = false; @@ -47,6 +46,15 @@ static std::string getSampleRatePreview(unsigned int rate) return std::to_string(rate / 1000) + " kHz"; } +static std::string connectLabel ("Connect"); +void deviceRenderDisconnect() +{ + connectLabel = "Connect"; + measureCodeTime = false; + logResults = false; + drawSamples = false; +} + void deviceRenderMenu() { auto addMenuItem = [](const std::string& label, bool enable, auto action) { @@ -56,7 +64,6 @@ void deviceRenderMenu() }; if (ImGui::BeginMenu("Device")) { - static std::string connectLabel ("Connect"); addMenuItem(connectLabel, !m_device || !m_device->is_running(), [&] { if (deviceConnect()) { connectLabel = "Disconnect"; @@ -64,10 +71,7 @@ void deviceRenderMenu() getSampleRatePreview(m_device->get_sample_rate()); deviceUpdateDrawBufferSize(drawSamplesTimeframe); } else { - connectLabel = "Connect"; - measureCodeTime = false; - logResults = false; - drawSamples = false; + deviceRenderDisconnect(); } }); @@ -79,7 +83,7 @@ void deviceRenderMenu() static std::string startLabel ("Start"); addMenuItem(startLabel, isConnected, [&] { startLabel = isRunning ? "Start" : "Stop"; - deviceStart(measureCodeTime, logResults, drawSamples); + deviceStart(logResults, drawSamples); if (logResults && isRunning) logResults = false; }); @@ -87,28 +91,25 @@ void deviceRenderMenu() deviceAlgorithmUpload); addMenuItem("Unload algorithm", isConnected && !isRunning, deviceAlgorithmUnload); + addMenuItem("Measure Code Time", isRunning, deviceStartMeasurement); ImGui::Separator(); if (!isConnected || isRunning) - ImGui::PushDisabled(); + ImGui::PushDisabled(); // Hey, pushing disabled! - ImGui::Checkbox("Measure Code Time", &measureCodeTime); ImGui::Checkbox("Draw samples", &drawSamples); if (ImGui::Checkbox("Log results...", &logResults)) { if (logResults) popupRequestLog = true; } + addMenuItem("Set buffer size...", true, [] { popupRequestBuffer = true; }); if (!isConnected || isRunning) ImGui::PopDisabled(); - - addMenuItem("Set buffer size...", isConnected && !isRunning, - [] { popupRequestBuffer = true; }); - ImGui::Separator(); addMenuItem("Load signal generator", - isConnected && !m_device->is_siggening(), + isConnected && !m_device->is_siggening() && !m_device->is_running(), [] { popupRequestSiggen = true; }); static std::string startSiggenLabel ("Start signal generator"); @@ -193,7 +194,7 @@ void deviceRenderWidgets() } } else { ImGui::Text(siggenOption == 0 ? "Enter a list of numbers:" - : "Enter a formula. f(x) = "); + : "Enter a formula. x = sample #, y = -1 to 1.\nf(x) = "); ImGui::PushStyleColor(ImGuiCol_FrameBg, {.8, .8, .8, 1}); ImGui::InputText("", siggenInput.data(), siggenInput.size()); ImGui::PopStyleColor(); @@ -286,8 +287,13 @@ void deviceRenderDraw() ImGui::Begin("draw", &drawSamples); ImGui::Text("Draw input "); ImGui::SameLine(); - if (ImGui::Checkbox("", &drawSamplesInput)) + if (ImGui::Checkbox("", &drawSamplesInput)) { deviceSetInputDrawing(drawSamplesInput); + if (drawSamplesInput) { + bufferCirc.reset(2048); + bufferInputCirc.reset(2048); + } + } ImGui::SameLine(); ImGui::Text("Time: %0.3f sec", drawSamplesTimeframe); ImGui::SameLine(); @@ -311,19 +317,19 @@ void deviceRenderDraw() yMinMax = std::min(4095u, (yMinMax << 1) | 1); } - auto newSize = pullFromDrawQueue(bufferCirc, drawSamplesTimeframe); + auto newSize = pullFromDrawQueue(bufferCirc); if (newSize > 0) { buffer.resize(newSize); bufferCirc = CircularBuffer(buffer); - pullFromDrawQueue(bufferCirc, drawSamplesTimeframe); + pullFromDrawQueue(bufferCirc); } if (drawSamplesInput) { - auto newSize = pullFromInputDrawQueue(bufferInputCirc, drawSamplesTimeframe); + auto newSize = pullFromInputDrawQueue(bufferInputCirc); if (newSize > 0) { bufferInput.resize(newSize); bufferInputCirc = CircularBuffer(bufferInput); - pullFromInputDrawQueue(bufferInputCirc, drawSamplesTimeframe); + pullFromInputDrawQueue(bufferInputCirc); } } diff --git a/source/main.cpp b/source/main.cpp index d6277b7..e0d893e 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -13,7 +13,6 @@ #include "backends/imgui_impl_sdl.h" #include "backends/imgui_impl_opengl2.h" -#include "config.h" #include "logview.h" #include "stmdsp.hpp" @@ -26,7 +25,7 @@ void codeEditorInit(); void codeRenderMenu(); void codeRenderToolbar(); -void codeRenderWidgets(); +void codeRenderWidgets(const ImVec2& size); void deviceRenderDraw(); void deviceRenderMenu(); void deviceRenderToolbar(); @@ -45,6 +44,7 @@ static LogView logView; static ImFont *fontSans = nullptr; static ImFont *fontMono = nullptr; +template<bool first = false> static void renderWindow(); int main(int argc, char *argv[]) @@ -63,6 +63,8 @@ int main(int argc, char *argv[]) codeEditorInit(); fileInit(); + renderWindow<true>(); + while (1) { constexpr std::chrono::duration<double> fpsDelay (1. / 60.); const auto endTime = std::chrono::steady_clock::now() + fpsDelay; @@ -85,6 +87,7 @@ void log(const std::string& str) logView.AddLog(str); } +template<bool first> void renderWindow() { // Start the new window frame and render the menu bar. @@ -99,35 +102,41 @@ void renderWindow() ImGui::EndMainMenuBar(); } - // Begin the main view which the controls will be drawn onto. - constexpr float LOGVIEW_HEIGHT = 200; - constexpr ImVec2 WINDOW_POS (0, 22); - constexpr ImVec2 WINDOW_SIZE (WINDOW_WIDTH, WINDOW_HEIGHT - 22 - LOGVIEW_HEIGHT); - ImGui::SetNextWindowPos(WINDOW_POS); - ImGui::SetNextWindowSize(WINDOW_SIZE); + if constexpr (first) { + ImGui::SetNextWindowSize({550, 440}); + } + + constexpr int MainTopMargin = 22; + const auto& displaySize = ImGui::GetIO().DisplaySize; + + ImGui::SetNextWindowPos({0, MainTopMargin}); + ImGui::SetNextWindowSizeConstraints({displaySize.x, 150}, {displaySize.x, displaySize.y - 150}); ImGui::Begin("main", nullptr, - ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBringToFrontOnFocus); - // Render main controls (order is important). - { - ImGui::PushFont(fontSans); - codeRenderToolbar(); - deviceRenderToolbar(); - fileRenderDialog(); - deviceRenderWidgets(); - ImGui::PopFont(); - - ImGui::PushFont(fontMono); - codeRenderWidgets(); - ImGui::SetNextWindowPos({0, WINDOW_HEIGHT - LOGVIEW_HEIGHT}); - ImGui::SetNextWindowSize({WINDOW_WIDTH, LOGVIEW_HEIGHT}); - logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus); - ImGui::PopFont(); - } + const float mainWindowHeight = ImGui::GetWindowHeight(); + + ImGui::PushFont(fontSans); + codeRenderToolbar(); + deviceRenderToolbar(); + fileRenderDialog(); + deviceRenderWidgets(); + ImGui::PopFont(); + + ImGui::PushFont(fontMono); + codeRenderWidgets({displaySize.x - 16, mainWindowHeight - MainTopMargin - 24}); + ImGui::PopFont(); ImGui::End(); + // The log window is kept separate from "main" to support panel resizing. + ImGui::PushFont(fontMono); + ImGui::SetNextWindowPos({0, mainWindowHeight + MainTopMargin}); + ImGui::SetNextWindowSize({displaySize.x, displaySize.y - mainWindowHeight - MainTopMargin}); + logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus); + ImGui::PopFont(); + deviceRenderDraw(); // Draw everything to the screen. diff --git a/source/stmdsp/stmdsp.cpp b/source/stmdsp/stmdsp.cpp index c835257..294e98f 100644 --- a/source/stmdsp/stmdsp.cpp +++ b/source/stmdsp/stmdsp.cpp @@ -92,8 +92,7 @@ namespace stmdsp m_serial->write(cmd.data(), cmd.size()); success = true; } catch (...) { - m_serial.release(); - log("Lost connection!"); + handle_disconnect(); } } @@ -110,8 +109,7 @@ namespace stmdsp m_serial->read(dest, dest_size); success = true; } catch (...) { - m_serial.release(); - log("Lost connection!"); + handle_disconnect(); } } @@ -160,12 +158,11 @@ namespace stmdsp m_is_running = true; } - void device::continuous_start_measure() { - if (try_command({'M'})) - m_is_running = true; + void device::measurement_start() { + try_command({'M'}); } - uint32_t device::continuous_start_get_measurement() { + uint32_t device::measurement_read() { uint32_t count = 0; try_read({'m'}, reinterpret_cast<uint8_t *>(&count), sizeof(uint32_t)); return count / 2; @@ -195,8 +192,7 @@ namespace stmdsp } } catch (...) { - m_serial.release(); - log("Lost connection!"); + handle_disconnect(); } } @@ -227,8 +223,7 @@ namespace stmdsp } } catch (...) { - m_serial.release(); - log("Lost connection!"); + handle_disconnect(); } } @@ -253,8 +248,7 @@ namespace stmdsp m_serial->write(request, 3); m_serial->write((uint8_t *)buffer, size * sizeof(dacsample_t)); } catch (...) { - m_serial.release(); - log("Lost connection!"); + handle_disconnect(); } } else { try { @@ -264,8 +258,7 @@ namespace stmdsp else m_serial->write((uint8_t *)buffer, size * sizeof(dacsample_t)); } catch (...) { - m_serial.release(); - log("Lost connection!"); + handle_disconnect(); } } @@ -297,8 +290,7 @@ namespace stmdsp m_serial->write(request, 3); m_serial->write(buffer, size); } catch (...) { - m_serial.release(); - log("Lost connection!"); + handle_disconnect(); } } } @@ -320,9 +312,19 @@ namespace stmdsp bool running = ret.first == RunStatus::Running; if (m_is_running != running) m_is_running = running; + } else if (m_disconnect_error_flag) { + m_disconnect_error_flag = false; + return {RunStatus::Idle, Error::GUIDisconnect}; } return ret; } -} + + void device::handle_disconnect() + { + m_disconnect_error_flag = true; + m_serial.release(); + log("Lost connection!"); + } +} // namespace stmdsp diff --git a/source/stmdsp/stmdsp.hpp b/source/stmdsp/stmdsp.hpp index e0fca90..efed8a3 100644 --- a/source/stmdsp/stmdsp.hpp +++ b/source/stmdsp/stmdsp.hpp @@ -63,12 +63,15 @@ namespace stmdsp */ enum class Error : char { None = 0, - BadParam, /* An invalid parameter was passed for a command. */ - BadParamSize, /* An invaild param. size was given for a command. */ - BadUserCodeLoad, /* Device failed to load the given algorithm. */ - BadUserCodeSize, /* The given algorithm is too large for the device. */ - NotIdle, /* An idle-only command was received while not Idle. */ - ConversionAborted /* A conversion was aborted due to a fault. */ + BadParam, /* An invalid parameter was passed for a command. */ + BadParamSize, /* An invaild param. size was given for a command. */ + BadUserCodeLoad, /* Device failed to load the given algorithm. */ + BadUserCodeSize, /* The given algorithm is too large for the device. */ + NotIdle, /* An idle-only command was received while not Idle. */ + ConversionAborted, /* A conversion was aborted due to a fault. */ + NotRunning, /* A running-only command was received while not Running. */ + + GUIDisconnect = 100 /* The GUI lost connection with the device. */ }; /** @@ -123,8 +126,8 @@ namespace stmdsp void continuous_start(); void continuous_stop(); - void continuous_start_measure(); - uint32_t continuous_start_get_measurement(); + void measurement_start(); + uint32_t measurement_read(); std::vector<adcsample_t> continuous_read(); std::vector<adcsample_t> continuous_read_input(); @@ -149,11 +152,13 @@ namespace stmdsp unsigned int m_sample_rate = 0; bool m_is_siggening = false; bool m_is_running = false; + bool m_disconnect_error_flag = false; std::mutex m_lock; bool try_command(std::basic_string<uint8_t> data); bool try_read(std::basic_string<uint8_t> cmd, uint8_t *dest, unsigned int dest_size); + void handle_disconnect(); }; } diff --git a/source/stmdsp/stmdsp_code.hpp b/source/stmdsp/stmdsp_code.hpp index 6850459..7ba0ed2 100644 --- a/source/stmdsp/stmdsp_code.hpp +++ b/source/stmdsp/stmdsp_code.hpp @@ -118,67 +118,67 @@ return s; )cpp"; static std::string file_header_l4 = R"cpp( #include <cstdint> -#include <span> using Sample = uint16_t; -using Samples = std::span<Sample, $0>; +using Samples = Sample[$0]; +constexpr unsigned int SIZE = $0; Sample *process_data(Samples samples); extern "C" void process_data_entry() { Sample *samples; asm("mov %0, r0" : "=r" (samples)); - process_data(Samples(samples, $0)); + process_data(samples); } -static float PI = 3.14159265358979L; +static inline float PI = 3.14159265358979L; __attribute__((naked)) -auto sin(float x) { -asm("vmov.f32 r1, s0;" +static inline auto sin(float x) { + asm("vmov.f32 r1, s0;" "eor r0, r0;" "svc 1;" "vmov.f32 s0, r1;" "bx lr"); -return 0; + return 0; } __attribute__((naked)) -auto cos(float x) { -asm("vmov.f32 r1, s0;" +static inline auto cos(float x) { + asm("vmov.f32 r1, s0;" "mov r0, #1;" "svc 1;" "vmov.f32 s0, r1;" "bx lr"); -return 0; + return 0; } __attribute__((naked)) -auto tan(float x) { -asm("vmov.f32 r1, s0;" +static inline auto tan(float x) { + asm("vmov.f32 r1, s0;" "mov r0, #2;" "svc 1;" "vmov.f32 s0, r1;" "bx lr"); -return 0; + return 0; } __attribute__((naked)) -auto sqrt(float) { -asm("vsqrt.f32 s0, s0; bx lr"); -return 0; +static inline auto sqrt(float) { + asm("vsqrt.f32 s0, s0; bx lr"); + return 0; } -auto readpot1() { -Sample s; -asm("push {r4-r11}; eor r0, r0; svc 3; mov %0, r0; pop {r4-r11}" : "=r"(s)); -return s; +static inline auto param1() { + Sample s; + asm("eor r0, r0; svc 3; mov %0, r0" : "=r" (s) :: "r0"); + return s; } -auto readpot2() { -Sample s; -asm("push {r4-r11}; mov r0, #1; svc 3; mov %0, r0; pop {r4-r11}" : "=r"(s)); -return s; +static inline auto param2() { + Sample s; + asm("mov r0, #1; svc 3; mov %0, r0" : "=r" (s) :: "r0"); + return s; } -//void puts(const char *s) { -// 's' will already be in r0. -//asm("push {r4-r6}; svc 4; pop {r4-r6}"); +//static inline void puts(const char *s) { +// // 's' will already be in r0. +// asm("push {r4-r6}; svc 4; pop {r4-r6}"); //} // End stmdspgui header code @@ -187,9 +187,9 @@ return s; static std::string file_content = -R"cpp(Sample *process_data(Samples samples) +R"cpp(Sample* process_data(Samples samples) { - return samples.data(); + return samples; } )cpp"; |