aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile27
-rw-r--r--examples/1_convolve_simple.cpp9
-rw-r--r--examples/2_convolve_overlap_save.cpp8
-rw-r--r--examples/3_fir.cpp8
-rw-r--r--examples/4_fir_pro.cpp10
-rw-r--r--examples/5_fir_differentiator.cpp8
-rw-r--r--examples/6_iir_test.cpp18
-rw-r--r--examples/7_iir_echo.cpp16
-rw-r--r--source/circular.hpp7
-rw-r--r--source/code.cpp19
-rw-r--r--source/config.h8
-rw-r--r--source/device.cpp73
-rw-r--r--source/gui.cpp8
-rw-r--r--source/gui_code.cpp6
-rw-r--r--source/gui_device.cpp54
-rw-r--r--source/main.cpp59
-rw-r--r--source/stmdsp/stmdsp.cpp40
-rw-r--r--source/stmdsp/stmdsp.hpp21
-rw-r--r--source/stmdsp/stmdsp_code.hpp58
19 files changed, 254 insertions, 203 deletions
diff --git a/Makefile b/Makefile
index 6b85111..dc62d10 100644
--- a/Makefile
+++ b/Makefile
@@ -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";