diff --git a/.gitignore b/.gitignore index d7ed0eb..9c562a6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ stmdspgui stmdspgui.exe perf.data* *.o +*.dll .* diff --git a/Makefile b/Makefile index 81e580d..dc62d10 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,36 @@ +CXX = g++ + CXXFILES := \ source/serial/src/serial.cc \ - source/serial/src/impl/unix.cc \ - source/serial/src/impl/list_ports/list_ports_linux.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))) +CXXFLAGS := -std=c++20 -O2 \ + -Isource -Isource/imgui -Isource/stmdsp -Isource/serial/include \ + -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 -#CXXFLAGS := -std=c++20 -O2 \ -# -Isource -Isource/imgui -Isource/stmdsp -Isource/serial/include -CXXFLAGS := -std=c++20 -ggdb -O0 -g3 \ - -Isource -Isource/imgui -Isource/stmdsp -Isource/serial/include \ - -Wall -Wextra -pedantic +OFILES := $(patsubst %.cc, %.o, $(patsubst %.cpp, %.o, $(CXXFILES))) all: $(OUTPUT) $(OUTPUT): $(OFILES) @echo " LD " $(OUTPUT) - @g++ $(OFILES) -o $(OUTPUT) -lSDL2 -lGL -lpthread + @$(CXX) $(OFILES) -o $(OUTPUT) $(LDFLAGS) clean: @echo " CLEAN" @@ -28,9 +38,9 @@ clean: %.o: %.cpp @echo " CXX " $< - @g++ $(CXXFLAGS) -c $< -o $@ + @$(CXX) $(CXXFLAGS) -c $< -o $@ %.o: %.cc @echo " CXX " $< - @g++ $(CXXFLAGS) -c $< -o $@ + @$(CXX) $(CXXFLAGS) -c $< -o $@ diff --git a/source/device.cpp b/source/device.cpp index 60b1bc9..9c50a0d 100644 --- a/source/device.cpp +++ b/source/device.cpp @@ -103,8 +103,10 @@ static void drawSamplesTask(std::shared_ptr device) if (!device) return; - const auto bufferTime = getBufferPeriod(device); + // This is the amount of time to wait between device reads. + const auto bufferTime = getBufferPeriod(device, 1); + // Adds the given chunk of samples to the given queue. const auto addToQueue = [](auto& queue, const auto& chunk) { std::scoped_lock lock (mutexDrawSamples); std::copy(chunk.cbegin(), chunk.cend(), std::back_inserter(queue)); @@ -136,8 +138,8 @@ static void drawSamplesTask(std::shared_ptr device) logSamplesFile << s << '\n'; } } else { - // Device must be busy, cooldown. - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + // Device must be busy, back off for a bit. + std::this_thread::sleep_for(std::chrono::milliseconds(50)); } std::this_thread::sleep_until(next); @@ -431,15 +433,27 @@ void deviceGenLoadFormula(const std::string& formula) std::size_t pullFromQueue( std::deque& queue, - CircularBuffer& circ, - double timeframe) + CircularBuffer& circ) { + // We know how big the circular buffer should be to hold enough samples to + // fill the current draw samples view. + // If the given buffer does not match this size, notify the caller. + // TODO this could be done better... drawSamplesBufferSize should be a GUI- + // only thing. if (circ.size() != drawSamplesBufferSize) return drawSamplesBufferSize; std::scoped_lock lock (mutexDrawSamples); - const auto desiredCount = drawSamplesBufferSize / (60. * timeframe) * 1.025; + // The render code will draw all of the new samples we add to the buffer. + // So, we must provide a certain amount of samples at a time to make the + // render appear smooth. + // The 1.025 factor keeps us on top of the stream; don't want to fall + // behind. + const double FPS = ImGui::GetIO().Framerate; + const auto desiredCount = m_device->get_sample_rate() / FPS; + + // Transfer from the queue to the render buffer. auto count = std::min(queue.size(), static_cast(desiredCount)); while (count--) { circ.put(queue.front()); @@ -449,17 +463,19 @@ std::size_t pullFromQueue( return 0; } +/** + * Pulls a render frame's worth of samples from the draw samples queue, adding + * the samples to the given buffer. + */ std::size_t pullFromDrawQueue( - CircularBuffer& circ, - double timeframe) + CircularBuffer& circ) { - return pullFromQueue(drawSamplesQueue, circ, timeframe); + return pullFromQueue(drawSamplesQueue, circ); } std::size_t pullFromInputDrawQueue( - CircularBuffer& circ, - double timeframe) + CircularBuffer& circ) { - return pullFromQueue(drawSamplesInputQueue, circ, timeframe); + return pullFromQueue(drawSamplesInputQueue, circ); } diff --git a/source/device_formula.cpp b/source/device_formula.cpp index a70f465..e21d374 100644 --- a/source/device_formula.cpp +++ b/source/device_formula.cpp @@ -11,13 +11,26 @@ */ #include "stmdsp.hpp" -#include "exprtk.hpp" #include #include #include #include +#ifndef STMDSP_DISABLE_FORMULAS + +#define exprtk_disable_comments +#define exprtk_disable_break_continue +#define exprtk_disable_sc_andor +#define exprtk_disable_return_statement +#define exprtk_disable_enhanced_features +//#define exprtk_disable_string_capabilities +#define exprtk_disable_superscalar_unroll +#define exprtk_disable_rtl_io_file +#define exprtk_disable_rtl_vecops +//#define exprtk_disable_caseinsensitivity +#include "exprtk.hpp" + static std::random_device randomDevice; std::vector deviceGenLoadFormulaEval(const std::string& formulaString) @@ -62,3 +75,12 @@ std::vector deviceGenLoadFormulaEval(const std::string& for return samples; } +#else // no formula support + +std::vector deviceGenLoadFormulaEval(const std::string&) +{ + return {}; +} + +#endif // STMDSP_DISABLE_FORMULAS + diff --git a/source/file.cpp b/source/file.cpp index fe5dafb..b4332f4 100644 --- a/source/file.cpp +++ b/source/file.cpp @@ -104,7 +104,7 @@ void fileRenderMenu() if (ImGui::BeginMenu("Open Example")) { for (const auto& file : fileExampleList) { - if (ImGui::MenuItem(file.filename().c_str())) { + if (ImGui::MenuItem(file.filename().string().c_str())) { fileCurrentPath = file.string(); openCurrentFile(); diff --git a/source/gui.cpp b/source/gui.cpp index 0e67446..43c95df 100644 --- a/source/gui.cpp +++ b/source/gui.cpp @@ -40,7 +40,7 @@ bool guiInitialize() SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); window = SDL_CreateWindow("stmdsp gui", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - 550, 700, + 640, 700, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE /*| SDL_WINDOW_ALLOW_HIGHDPI*/); if (window == nullptr) { diff --git a/source/gui_device.cpp b/source/gui_device.cpp index f846414..689ef54 100644 --- a/source/gui_device.cpp +++ b/source/gui_device.cpp @@ -28,11 +28,9 @@ void deviceStart(bool logResults, bool drawSamples); void deviceStartMeasurement(); void deviceUpdateDrawBufferSize(double timeframe); std::size_t pullFromDrawQueue( - CircularBuffer& circ, - double timeframe); + CircularBuffer& circ); std::size_t pullFromInputDrawQueue( - CircularBuffer& circ, - double timeframe); + CircularBuffer& circ); static std::string sampleRatePreview = "?"; static bool measureCodeTime = false; @@ -319,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 f913cf1..e0d893e 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -47,7 +47,7 @@ static ImFont *fontMono = nullptr; template static void renderWindow(); -int main(int, char **) +int main(int argc, char *argv[]) { if (!guiInitialize()) return -1; diff --git a/source/stmdsp/stmdsp.cpp b/source/stmdsp/stmdsp.cpp index d7e977b..294e98f 100644 --- a/source/stmdsp/stmdsp.cpp +++ b/source/stmdsp/stmdsp.cpp @@ -45,7 +45,9 @@ namespace stmdsp device::device(const std::string& file) { // This could throw! - m_serial.reset(new serial::Serial(file, 8'000'000, serial::Timeout::simpleTimeout(50))); + // Note: Windows needs a not-simple, positive timeout like this to + // ensure that reads block. + m_serial.reset(new serial::Serial(file, 921'600 /*8'000'000*/, serial::Timeout(1000, 1000, 1, 1000, 1))); // Test the ID command. m_serial->flush();