diff --git a/source/code.cpp b/source/code.cpp
index e290440..163d6e5 100644
--- a/source/code.cpp
+++ b/source/code.cpp
@@ -33,6 +33,8 @@ std::string tempFileName; // device.cpp
static std::string editorCompiled;
static std::string newTempFileName();
+static bool codeExecuteCommand(const std::string& command, const std::string& file);
+static void stringReplaceAll(std::string& str, const std::string& what, const std::string& with);
static void compileEditorCode();
static void disassembleCode();
@@ -64,6 +66,39 @@ void codeRenderWidgets()
editor.Render("code", {WINDOW_WIDTH - 15, 450}, true);
}
+std::string newTempFileName()
+{
+ const auto path = std::filesystem::temp_directory_path() / "stmdspgui_build";
+ return path.string();
+}
+
+bool codeExecuteCommand(const std::string& command, const std::string& file)
+{
+ if (system(command.c_str()) == 0) {
+ 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 true;
+ } else {
+ return false;
+ }
+}
+
+void stringReplaceAll(std::string& str, const std::string& what, const std::string& with)
+{
+ std::size_t i;
+ while ((i = str.find(what)) != std::string::npos) {
+ str.replace(i, what.size(), with);
+ i += what.size();
+ }
+};
+
void compileEditorCode()
{
log("Compiling...");
@@ -74,35 +109,28 @@ void compileEditorCode()
std::filesystem::remove(tempFileName + ".orig.o");
}
- stmdsp::platform platform;
- if (m_device) {
- platform = m_device->get_platform();
- } else {
- // Assume a default.
- platform = stmdsp::platform::L4;
- }
+ const auto platform = m_device ? m_device->get_platform()
+ : stmdsp::platform::L4;
- if (tempFileName.size() == 0)
+ if (tempFileName.empty())
tempFileName = newTempFileName();
+
{
std::ofstream file (tempFileName, std::ios::trunc | std::ios::binary);
- auto file_text = platform == stmdsp::platform::L4 ? stmdsp::file_header_l4
- : stmdsp::file_header_h7;
- auto samples_text = std::to_string(m_device ? m_device->get_buffer_size()
- : stmdsp::SAMPLES_MAX);
- for (std::size_t i = 0; (i = file_text.find("$0", i)) != std::string::npos;) {
- file_text.replace(i, 2, samples_text);
- i += 2;
- }
+ auto file_text =
+ platform == stmdsp::platform::L4 ? stmdsp::file_header_l4
+ : stmdsp::file_header_h7;
+ const auto buffer_size = m_device ? m_device->get_buffer_size()
+ : stmdsp::SAMPLES_MAX;
+
+ stringReplaceAll(file_text, "$0", std::to_string(buffer_size));
- file << file_text;
- file << "\n";
- file << editor.GetText();
+ file << file_text << '\n' << editor.GetText();
}
- constexpr const char *script_ext =
+ const auto scriptFile = tempFileName +
#ifndef STMDSP_WIN32
".sh";
#else
@@ -110,44 +138,33 @@ void compileEditorCode()
#endif
{
- std::ofstream makefile (tempFileName + script_ext, std::ios::binary);
- auto make_text = platform == stmdsp::platform::L4 ? stmdsp::makefile_text_l4
- : stmdsp::makefile_text_h7;
- auto cwd = std::filesystem::current_path().string();
- for (std::size_t i = 0; (i = make_text.find("$0", i)) != std::string::npos;) {
- make_text.replace(i, 2, tempFileName);
- i += 2;
- }
- for (std::size_t i = 0; (i = make_text.find("$1", i)) != std::string::npos;) {
- make_text.replace(i, 2, cwd);
- i += 2;
- }
+ std::ofstream makefile (scriptFile, std::ios::binary);
+ auto make_text =
+ platform == stmdsp::platform::L4 ? stmdsp::makefile_text_l4
+ : stmdsp::makefile_text_h7;
+
+ stringReplaceAll(make_text, "$0", tempFileName);
+ stringReplaceAll(make_text, "$1",
+ std::filesystem::current_path().string());
makefile << make_text;
}
- auto makeOutput = tempFileName + script_ext + ".log";
- auto makeCommand = tempFileName + script_ext + " > " + makeOutput + " 2>&1";
-
#ifndef STMDSP_WIN32
- system((std::string("chmod +x ") + tempFileName + script_ext).c_str());
+ system((std::string("chmod +x ") + scriptFile).c_str());
#endif
- int result = system(makeCommand.c_str());
- std::ifstream result_file (makeOutput);
- std::ostringstream sstr;
- sstr << result_file.rdbuf();
- log(sstr.str().c_str());
-
- std::filesystem::remove(tempFileName);
- std::filesystem::remove(tempFileName + script_ext);
- std::filesystem::remove(makeOutput);
- if (result == 0) {
+ const auto makeOutput = scriptFile + ".log";
+ const auto makeCommand = scriptFile + " > " + makeOutput + " 2>&1";
+ if (codeExecuteCommand(makeCommand, makeOutput)) {
editorCompiled = editor.GetText();
log("Compilation succeeded.");
} else {
log("Compilation failed.");
}
+
+ std::filesystem::remove(tempFileName);
+ std::filesystem::remove(scriptFile);
}
void disassembleCode()
@@ -158,31 +175,15 @@ void disassembleCode()
compileEditorCode();
}
- auto output = tempFileName + ".asm.log";
- auto command = std::string("arm-none-eabi-objdump -d --no-show-raw-insn ") +
+ const auto output = tempFileName + ".asm.log";
+ const auto command =
+ std::string("arm-none-eabi-objdump -d --no-show-raw-insn ") +
tempFileName + ".orig.o > " + output + " 2>&1";
-
- if (system(command.c_str()) == 0) {
- {
- std::ifstream result_file (output);
- std::ostringstream sstr;
- sstr << result_file.rdbuf();
- log(sstr.str().c_str());
- }
-
- ImGui::OpenPopup("compile");
- std::filesystem::remove(output);
+ if (codeExecuteCommand(command, output)) {
log("Ready.");
} else {
log("Failed to load disassembly.");
}
}
-std::string newTempFileName()
-{
- auto tempPath = std::filesystem::temp_directory_path();
- tempPath /= "stmdspgui_build";
- return tempPath.string();
-}
-
diff --git a/source/device.cpp b/source/device.cpp
index 399bf7d..39bc746 100644
--- a/source/device.cpp
+++ b/source/device.cpp
@@ -9,11 +9,6 @@
* If not, see .
*/
-/**
- * TODO list:
- * - Improve signal generator audio streaming.
- */
-
#include "stmdsp.hpp"
#include "imgui.h"
@@ -80,11 +75,41 @@ static unsigned int drawSamplesBufferSize = 1;
static void measureCodeTask(std::shared_ptr device)
{
- if (!device)
- return;
- std::this_thread::sleep_for(std::chrono::milliseconds(1000));
- auto cycles = device->continuous_start_get_measurement();
- log(std::string("Execution time: ") + std::to_string(cycles) + " cycles.");
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ if (device) {
+ const auto cycles = device->continuous_start_get_measurement();
+ log(std::string("Execution time: ") + std::to_string(cycles) + " cycles.");
+ }
+}
+
+static std::vector tryReceiveChunk(
+ std::shared_ptr device,
+ auto readFunc)
+{
+ int tries = -1;
+ do {
+ const auto chunk = readFunc(device.get());
+ if (!chunk.empty())
+ return chunk;
+ else
+ std::this_thread::sleep_for(std::chrono::microseconds(20));
+ } while (++tries < 100 && device->is_running());
+
+ return {};
+}
+
+static std::chrono::duration getBufferPeriod(
+ std::shared_ptr device,
+ const double factor = 0.975)
+{
+ if (device) {
+ const double bufferSize = device->get_buffer_size();
+ const double sampleRate = sampleRateInts[device->get_sample_rate()];
+ return std::chrono::duration(bufferSize / sampleRate * factor);
+ } else {
+ return {};
+ }
}
static void drawSamplesTask(std::shared_ptr device)
@@ -93,71 +118,45 @@ static void drawSamplesTask(std::shared_ptr device)
return;
const bool doLogger = logResults && logSamplesFile.good();
-
- const double bufferSize = m_device->get_buffer_size();
- const double sampleRate = sampleRateInts[m_device->get_sample_rate()];
- unsigned long bufferTime = bufferSize / sampleRate * 0.975 * 1e6;
+ const auto bufferTime = getBufferPeriod(device);
std::unique_lock lockDraw (mutexDrawSamples, std::defer_lock);
std::unique_lock lockDevice (mutexDeviceLoad, std::defer_lock);
- while (m_device && m_device->is_running()) {
- auto next = std::chrono::high_resolution_clock::now() +
- std::chrono::microseconds(bufferTime);
+ auto addToQueue = [&lockDraw](auto& queue, const auto& chunk) {
+ lockDraw.lock();
+ std::copy(chunk.cbegin(), chunk.cend(), std::back_inserter(queue));
+ lockDraw.unlock();
+ };
- std::vector chunk;
+ while (device && device->is_running()) {
+ const auto next = std::chrono::high_resolution_clock::now() + bufferTime;
if (lockDevice.try_lock_until(next)) {
- chunk = m_device->continuous_read();
- int tries = -1;
- while (chunk.empty() && m_device->is_running()) {
- if (++tries == 100)
- break;
- std::this_thread::sleep_for(std::chrono::microseconds(20));
- chunk = m_device->continuous_read();
- }
+ const auto chunk = tryReceiveChunk(device,
+ std::mem_fn(&stmdsp::device::continuous_read));
lockDevice.unlock();
+
+ addToQueue(drawSamplesQueue, chunk);
+ if (doLogger) {
+ for (const auto& s : chunk)
+ logSamplesFile << s << '\n';
+ }
} else {
- // Cooldown.
+ // Device must be busy, cooldown.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
if (drawSamplesInput && popupRequestDraw) {
- std::vector chunk2;
-
if (lockDevice.try_lock_for(std::chrono::milliseconds(1))) {
- chunk2 = m_device->continuous_read_input();
- int tries = -1;
- while (chunk2.empty() && m_device->is_running()) {
- if (++tries == 100)
- break;
- std::this_thread::sleep_for(std::chrono::microseconds(20));
- chunk2 = m_device->continuous_read_input();
- }
+ const auto chunk2 = tryReceiveChunk(device,
+ std::mem_fn(&stmdsp::device::continuous_read_input));
lockDevice.unlock();
- }
- lockDraw.lock();
- auto i = chunk2.cbegin();
- for (const auto& s : chunk) {
- drawSamplesQueue.push_back(s);
- drawSamplesInputQueue.push_back(*i++);
- }
- lockDraw.unlock();
- } else if (!doLogger) {
- lockDraw.lock();
- for (const auto& s : chunk)
- drawSamplesQueue.push_back(s);
- lockDraw.unlock();
- } else {
- lockDraw.lock();
- for (const auto& s : chunk) {
- drawSamplesQueue.push_back(s);
- logSamplesFile << s << '\n';
+ addToQueue(drawSamplesInputQueue, chunk2);
}
- lockDraw.unlock();
}
-
+
std::this_thread::sleep_until(next);
}
}
@@ -167,36 +166,36 @@ static void feedSigGenTask(std::shared_ptr device)
if (!device)
return;
- const auto bufferSize = m_device->get_buffer_size();
- const double sampleRate = sampleRateInts[m_device->get_sample_rate()];
- const unsigned long delay = bufferSize / sampleRate * 0.975 * 1e6;
+ const auto delay = getBufferPeriod(device);
+ const auto uploadDelay = getBufferPeriod(device, 0.001);
- std::vector wavBuf (bufferSize, 2048);
+ std::vector wavBuf (device->get_buffer_size() * 2, 2048);
std::unique_lock lockDevice (mutexDeviceLoad, std::defer_lock);
lockDevice.lock();
- // One (or both) of these freezes the device...
- m_device->siggen_upload(wavBuf.data(), wavBuf.size());
- //m_device->siggen_start();
+ device->siggen_upload(wavBuf.data(), wavBuf.size());
+ wavBuf.resize(wavBuf.size() / 2);
+ device->siggen_start();
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
lockDevice.unlock();
- std::this_thread::sleep_for(std::chrono::microseconds(delay));
+ std::vector wavIntBuf (wavBuf.size());
- return;
while (genRunning) {
- auto next = std::chrono::high_resolution_clock::now() +
- std::chrono::microseconds(delay);
+ const auto next = std::chrono::high_resolution_clock::now() + delay;
- auto src = reinterpret_cast(wavOutput.next(bufferSize));
- for (auto& w : wavBuf)
- w = *src++ / 16 + 2048;
+ wavOutput.next(wavIntBuf.data(), wavIntBuf.size());
+ auto src = wavIntBuf.cbegin();
+ std::generate(wavBuf.begin(), wavBuf.end(),
+ [&src] { return static_cast(*src++ / 16 + 2048); });
- if (lockDevice.try_lock_until(next)) {
- m_device->siggen_upload(wavBuf.data(), wavBuf.size());
- lockDevice.unlock();
- std::this_thread::sleep_until(next);
- }
+ lockDevice.lock();
+ while (!device->siggen_upload(wavBuf.data(), wavBuf.size()))
+ std::this_thread::sleep_for(uploadDelay);
+ lockDevice.unlock();
+
+ std::this_thread::sleep_until(next);
}
}
@@ -208,16 +207,20 @@ static void statusTask(std::shared_ptr device)
while (device->connected()) {
std::unique_lock lockDevice (mutexDeviceLoad, std::defer_lock);
lockDevice.lock();
- auto [status, error] = device->get_status();
+ const auto [status, error] = device->get_status();
lockDevice.unlock();
if (error != stmdsp::Error::None) {
- if (error == stmdsp::Error::NotIdle) {
+ switch (error) {
+ case stmdsp::Error::NotIdle:
log("Error: Device already running...");
- } else if (error == stmdsp::Error::ConversionAborted) {
+ break;
+ case stmdsp::Error::ConversionAborted:
log("Error: Algorithm unloaded, a fault occurred!");
- } else {
+ break;
+ default:
log("Error: Device had an issue...");
+ break;
}
}
@@ -383,13 +386,13 @@ void deviceRenderDraw()
drawSamplesBufferSize = std::round(sr * tf);
}
ImGui::SameLine();
- ImGui::Text("Y-minmax: %u", yMinMax);
+ ImGui::Text("Y: +/-%1.2fV", 3.3f * (static_cast(yMinMax) / 4095.f));
ImGui::SameLine();
- if (ImGui::Button("--", {30, 0})) {
+ if (ImGui::Button(" - ", {30, 0})) {
yMinMax = std::max(63u, yMinMax >> 1);
}
ImGui::SameLine();
- if (ImGui::Button("++", {30, 0})) {
+ if (ImGui::Button(" + ", {30, 0})) {
yMinMax = std::min(4095u, (yMinMax << 1) | 1);
}
@@ -508,7 +511,7 @@ void deviceRenderMenu()
popupRequestBuffer = true;
}
ImGui::Separator();
- if (ImGui::MenuItem("Load signal generator", nullptr, false, isConnected && !isRunning)) {
+ if (ImGui::MenuItem("Load signal generator", nullptr, false, isConnected && !m_device->is_siggening())) {
popupRequestSiggen = true;
}
static const char *startSiggenLabel = "Start signal generator";
@@ -542,22 +545,26 @@ void deviceRenderToolbar()
deviceAlgorithmUpload();
ImGui::SameLine();
ImGui::SetNextItemWidth(100);
+
+ const bool enable = m_device && !m_device->is_running() && !m_device->is_siggening();
+ if (!enable)
+ ImGui::PushDisabled();
if (ImGui::BeginCombo("", sampleRatePreview)) {
for (unsigned int i = 0; i < sampleRateList.size(); ++i) {
if (ImGui::Selectable(sampleRateList[i])) {
sampleRatePreview = sampleRateList[i];
- if (m_device && !m_device->is_running()) {
- do {
- m_device->set_sample_rate(i);
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- } while (m_device->get_sample_rate() != i);
+ do {
+ m_device->set_sample_rate(i);
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ } while (m_device->get_sample_rate() != i);
- drawSamplesBufferSize = std::round(sampleRateInts[i] * drawSamplesTimeframe);
- }
+ drawSamplesBufferSize = std::round(sampleRateInts[i] * drawSamplesTimeframe);
}
}
ImGui::EndCombo();
}
+ if (!enable)
+ ImGui::PopDisabled();
}
void deviceConnect()
@@ -566,7 +573,7 @@ void deviceConnect()
if (!m_device) {
stmdsp::scanner scanner;
- if (auto devices = scanner.scan(); devices.size() > 0) {
+ if (auto devices = scanner.scan(); !devices.empty()) {
try {
m_device.reset(new stmdsp::device(devices.front()));
} catch (...) {
@@ -608,8 +615,7 @@ void deviceStart()
if (m_device->is_running()) {
{
- std::scoped_lock lock (mutexDrawSamples);
- std::scoped_lock lock2 (mutexDeviceLoad);
+ std::scoped_lock lock (mutexDrawSamples, mutexDeviceLoad);
std::this_thread::sleep_for(std::chrono::microseconds(150));
m_device->continuous_stop();
}
@@ -637,10 +643,9 @@ void deviceAlgorithmUpload()
if (!m_device) {
log("No device connected.");
return;
- }
-
- if (m_device->is_running())
+ } else if (m_device->is_running()) {
return;
+ }
if (std::ifstream algo (tempFileName + ".o"); algo.good()) {
std::ostringstream sstr;
@@ -658,41 +663,38 @@ void deviceAlgorithmUnload()
{
if (!m_device) {
log("No device connected.");
- return;
- }
-
- if (!m_device->is_running()) {
+ } else if (!m_device->is_running()) {
m_device->unload_filter();
log("Algorithm unloaded.");
}
}
-void deviceGenLoadList(std::string_view listStr)
+void deviceGenLoadList(const std::string_view list)
{
std::vector samples;
- while (listStr.size() > 0 && samples.size() <= stmdsp::SAMPLES_MAX * 2) {
- auto numberEnd = listStr.find_first_not_of("0123456789");
-
+ auto it = list.cbegin();
+ while (it != list.cend() && samples.size() < stmdsp::SAMPLES_MAX * 2) {
+ const auto end = list.find_first_not_of("0123456789",
+ std::distance(list.cbegin(), it));
+ const auto itend = end != std::string_view::npos ? list.cbegin() + end
+ : list.cend();
unsigned long n;
- auto end = numberEnd != std::string_view::npos ? listStr.begin() + numberEnd : listStr.end();
- auto [ptr, ec] = std::from_chars(listStr.begin(), end, n);
+ const auto [ptr, ec] = std::from_chars(it, itend, n);
if (ec != std::errc())
break;
samples.push_back(n & 4095);
- if (end == listStr.end())
- break;
- listStr = listStr.substr(numberEnd + 1);
+ it = itend;
}
if (samples.size() <= stmdsp::SAMPLES_MAX * 2) {
// DAC buffer must be of even size
- if ((samples.size() & 1) == 1)
+ if (samples.size() % 2 != 0)
samples.push_back(samples.back());
if (m_device)
- m_device->siggen_upload(&samples[0], samples.size());
+ m_device->siggen_upload(samples.data(), samples.size());
log("Generator ready.");
} else {
log("Error: Too many samples for signal generator.");
@@ -703,9 +705,9 @@ void deviceGenLoadFormula(std::string_view formula)
{
auto samples = deviceGenLoadFormulaEval(formula);
- if (samples.size() > 0) {
+ if (!samples.empty()) {
if (m_device)
- m_device->siggen_upload(&samples[0], samples.size());
+ m_device->siggen_upload(samples.data(), samples.size());
log("Generator ready.");
} else {
diff --git a/source/file.cpp b/source/file.cpp
index 0f0015c..dfd9148 100644
--- a/source/file.cpp
+++ b/source/file.cpp
@@ -17,6 +17,7 @@
#include "stmdsp_code.hpp"
+#include
#include
#include
#include
@@ -34,6 +35,7 @@ enum class FileAction {
Save,
SaveAs
};
+
static FileAction fileAction = FileAction::None;
static std::string fileCurrentPath;
static std::vector fileTemplateList;
@@ -56,17 +58,31 @@ static void openCurrentFile()
}
}
-void openNewFile()
+static void openNewFile()
{
fileCurrentPath.clear();
editor.SetText(stmdsp::file_content);
}
-void fileScanTemplates()
+static std::vector fileScanTemplates()
+{
+ const auto path = std::filesystem::current_path() / "templates";
+ const std::filesystem::recursive_directory_iterator rdi (path);
+
+ std::vector list;
+ std::transform(
+ std::filesystem::begin(rdi),
+ std::filesystem::end(rdi),
+ std::back_inserter(list),
+ [](const auto& file) { return file.path(); });
+ std::sort(list.begin(), list.end());
+ return list;
+}
+
+void fileInit()
{
- auto path = std::filesystem::current_path() / "templates";
- for (const auto& file : std::filesystem::recursive_directory_iterator{path})
- fileTemplateList.push_back(file.path());
+ fileTemplateList = fileScanTemplates();
+ openNewFile();
}
void fileRenderMenu()
diff --git a/source/main.cpp b/source/main.cpp
index b98ec2b..20c8ea1 100644
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -32,8 +32,7 @@ extern void guiRender(void (*func)());
extern void fileRenderMenu();
extern void fileRenderDialog();
-extern void fileScanTemplates();
-extern void openNewFile();
+extern void fileInit();
extern void codeEditorInit();
extern void codeRenderMenu();
@@ -60,9 +59,8 @@ int main(int, char **)
if (!guiInitialize())
return -1;
- fileScanTemplates();
codeEditorInit();
- openNewFile();
+ fileInit();
while (!done) {
auto endTime = std::chrono::steady_clock::now() +
@@ -90,21 +88,22 @@ int main(int, char **)
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 - 200});
- ImGui::SetNextWindowSize({WINDOW_WIDTH, 200});
- logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus);
- ImGui::PopFont();
-
- // Finish main view rendering.
+ {
+ ImGui::PushFont(fontSans);
+ codeRenderToolbar();
+ deviceRenderToolbar();
+ fileRenderDialog();
+ deviceRenderWidgets();
+ ImGui::PopFont();
+
+ ImGui::PushFont(fontMono);
+ codeRenderWidgets();
+ ImGui::SetNextWindowPos({0, WINDOW_HEIGHT - 200});
+ ImGui::SetNextWindowSize({WINDOW_WIDTH, 200});
+ logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus);
+ ImGui::PopFont();
+ }
+
ImGui::End();
deviceRenderDraw();
diff --git a/source/stmdsp/stmdsp.cpp b/source/stmdsp/stmdsp.cpp
index 650dbc4..2bbb92b 100644
--- a/source/stmdsp/stmdsp.cpp
+++ b/source/stmdsp/stmdsp.cpp
@@ -13,18 +13,23 @@
#include
+#include
+
extern void log(const std::string& str);
namespace stmdsp
{
- std::list& scanner::scan()
+ const std::forward_list& scanner::scan()
{
auto devices = serial::list_ports();
- for (auto& device : devices) {
- if (device.hardware_id.find(STMDSP_USB_ID) != std::string::npos)
- m_available_devices.emplace_front(device.port);
- }
-
+ auto foundDevicesEnd = std::remove_if(
+ devices.begin(), devices.end(),
+ [](const auto& dev) {
+ return dev.hardware_id.find(STMDSP_USB_ID) == std::string::npos;
+ });
+ std::transform(devices.begin(), foundDevicesEnd,
+ std::front_inserter(m_available_devices),
+ [](const auto& dev) { return dev.port; });
return m_available_devices;
}
@@ -33,6 +38,7 @@ namespace stmdsp
// This could throw!
m_serial.reset(new serial::Serial(file, 8'000'000, serial::Timeout::simpleTimeout(50)));
+ // Test the ID command.
m_serial->flush();
m_serial->write("i");
auto id = m_serial->read(7);
@@ -66,98 +72,80 @@ namespace stmdsp
m_serial.release();
}
- void device::continuous_set_buffer_size(unsigned int size) {
- if (connected()) {
- m_buffer_size = size;
-
- uint8_t request[3] = {
- 'B',
- static_cast(size),
- static_cast(size >> 8)
- };
+ bool device::try_command(std::basic_string cmd) {
+ bool success = false;
+ if (connected()) {
try {
- m_serial->write(request, 3);
+ std::scoped_lock lock (m_lock);
+ m_serial->write(cmd.data(), cmd.size());
+ success = true;
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
+
+ return success;
}
- void device::set_sample_rate(unsigned int id) {
- if (connected()) {
- uint8_t request[2] = {
- 'r',
- static_cast(id)
- };
+ bool device::try_read(std::basic_string cmd, uint8_t *dest, unsigned int dest_size) {
+ bool success = false;
+ if (connected() && dest && dest_size > 0) {
try {
- m_serial->write(request, 2);
+ std::scoped_lock lock (m_lock);
+ m_serial->write(cmd.data(), cmd.size());
+ m_serial->read(dest, dest_size);
+ success = true;
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
+
+ return success;
}
- unsigned int device::get_sample_rate() {
- if (connected() && !is_running()) {
- uint8_t request[2] = {
- 'r', 0xFF
- };
+ void device::continuous_set_buffer_size(unsigned int size) {
+ if (try_command({
+ 'B',
+ static_cast(size),
+ static_cast(size >> 8)}))
+ {
+ m_buffer_size = size;
+ }
+ }
- unsigned char result = 0xFF;
- try {
- m_serial->write(request, 2);
- m_serial->read(&result, 1);
- } catch (...) {
- m_serial.release();
- log("Lost connection!");
- }
+ void device::set_sample_rate(unsigned int id) {
+ try_command({
+ 'r',
+ static_cast(id)
+ });
+ }
- m_sample_rate = result;
+ unsigned int device::get_sample_rate() {
+ if (!is_running()) {
+ uint8_t result = 0xFF;
+ if (try_read({'r', 0xFF}, &result, 1))
+ m_sample_rate = result;
}
-
return m_sample_rate;
}
void device::continuous_start() {
- if (connected()) {
- try {
- m_serial->write("R");
- m_is_running = true;
- } catch (...) {
- m_serial.release();
- log("Lost connection!");
- }
- }
+ if (try_command({'R'}))
+ m_is_running = true;
}
void device::continuous_start_measure() {
- if (connected()) {
- try {
- m_serial->write("M");
- m_is_running = true;
- } catch (...) {
- m_serial.release();
- log("Lost connection!");
- }
- }
+ if (try_command({'M'}))
+ m_is_running = true;
}
uint32_t device::continuous_start_get_measurement() {
uint32_t count = 0;
- if (connected()) {
- try {
- m_serial->write("m");
- m_serial->read(reinterpret_cast(&count), sizeof(uint32_t));
- } catch (...) {
- m_serial.release();
- log("Lost connection!");
- }
- }
-
+ try_read({'m'}, reinterpret_cast(&count), sizeof(uint32_t));
return count / 2;
}
@@ -226,18 +214,11 @@ namespace stmdsp
}
void device::continuous_stop() {
- if (connected()) {
- try {
- m_serial->write("S");
- m_is_running = false;
- } catch (...) {
- m_serial.release();
- log("Lost connection!");
- }
- }
+ if (try_command({'S'}))
+ m_is_running = false;
}
- void device::siggen_upload(dacsample_t *buffer, unsigned int size) {
+ bool device::siggen_upload(dacsample_t *buffer, unsigned int size) {
if (connected()) {
uint8_t request[3] = {
'D',
@@ -245,39 +226,41 @@ namespace stmdsp
static_cast(size >> 8)
};
- try {
- m_serial->write(request, 3);
- // TODO different write size if feeding audio?
- m_serial->write((uint8_t *)buffer, size * sizeof(dacsample_t));
- } catch (...) {
- m_serial.release();
- log("Lost connection!");
+ if (!m_is_siggening) {
+ try {
+ m_serial->write(request, 3);
+ m_serial->write((uint8_t *)buffer, size * sizeof(dacsample_t));
+ } catch (...) {
+ m_serial.release();
+ log("Lost connection!");
+ }
+ } else {
+ try {
+ m_serial->write(request, 3);
+ if (m_serial->read(1)[0] == 0)
+ return false;
+ else
+ m_serial->write((uint8_t *)buffer, size * sizeof(dacsample_t));
+ } catch (...) {
+ m_serial.release();
+ log("Lost connection!");
+ }
}
+
+ return true;
+ } else {
+ return false;
}
}
void device::siggen_start() {
- if (connected()) {
- try {
- m_serial->write("W");
- m_is_siggening = true;
- } catch (...) {
- m_serial.release();
- log("Lost connection!");
- }
- }
+ if (try_command({'W'}))
+ m_is_siggening = true;
}
void device::siggen_stop() {
- if (connected()) {
- try {
- m_serial->write("w");
- m_is_siggening = false;
- } catch (...) {
- m_serial.release();
- log("Lost connection!");
- }
- }
+ if (try_command({'w'}))
+ m_is_siggening = false;
}
void device::upload_filter(unsigned char *buffer, size_t size) {
@@ -299,33 +282,22 @@ namespace stmdsp
}
void device::unload_filter() {
- if (connected()) {
- try {
- m_serial->write("e");
- } catch (...) {
- m_serial.release();
- log("Lost connection!");
- }
- }
+ try_command({'e'});
}
std::pair device::get_status() {
std::pair ret;
- if (connected()) {
- try {
- m_serial->write("I");
- auto result = m_serial->read(2);
- ret = {static_cast(result[0]),
- static_cast(result[1])};
-
- bool running = ret.first == RunStatus::Running;
- if (m_is_running != running)
- m_is_running = running;
- } catch (...) {
- m_serial.release();
- log("Lost connection!");
- }
+ unsigned char buf[2];
+ if (try_read({'I'}, buf, 2)) {
+ ret = {
+ static_cast(buf[0]),
+ static_cast(buf[1])
+ };
+
+ bool running = ret.first == RunStatus::Running;
+ if (m_is_running != running)
+ m_is_running = running;
}
return ret;
diff --git a/source/stmdsp/stmdsp.hpp b/source/stmdsp/stmdsp.hpp
index 76ca94e..64f5aff 100644
--- a/source/stmdsp/stmdsp.hpp
+++ b/source/stmdsp/stmdsp.hpp
@@ -15,33 +15,83 @@
#include
#include
-#include
+#include
#include
+#include
#include
#include
namespace stmdsp
{
+ /**
+ * The largest possible size of an ADC or DAC sample buffer, as a sample count.
+ * Maximum byte size would be `SAMPLES_MAX * sizeof(XXXsample_t)`.
+ */
constexpr unsigned int SAMPLES_MAX = 4096;
+ /**
+ * ADC samples on all platforms are stored as 16-bit unsigned integers.
+ */
+ using adcsample_t = uint16_t;
+ /**
+ * DAC samples on all platforms are stored as 16-bit unsigned integers.
+ */
+ using dacsample_t = uint16_t;
+
+ /**
+ * List of all available platforms.
+ * Note that some platforms in this list may not have complete support.
+ */
+ enum class platform {
+ Unknown,
+ H7, /* Some feature support */
+ L4, /* Complete feature support */
+ G4 /* Unsupported, but planned */
+ };
+
+ /**
+ * Run status states, valued to match what the stmdsp firmware reports.
+ */
enum class RunStatus : char {
- Idle = '1',
- Running,
- Recovering
+ Idle = '1', /* Device ready for commands or execution. */
+ Running, /* Device currently executing its algorithm. */
+ Recovering /* Device recovering from fault caused by algorithm. */
};
+ /**
+ * Error messages that are reported by the firmware.
+ */
enum class Error : char {
None = 0,
- BadParam,
- BadParamSize,
- BadUserCodeLoad,
- BadUserCodeSize,
- NotIdle,
- ConversionAborted
+ 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. */
};
+ /**
+ * Provides functionality to scan the system for stmdsp devices.
+ * A list of devices is returned, though the GUI only interacts with one
+ * device at a time.
+ */
class scanner
{
+ public:
+ /**
+ * Scans for connected devices, returning a list of ports with
+ * connected stmdsp devices.
+ */
+ const std::forward_list& scan();
+
+ /**
+ * Retrieves the results of the last scan().
+ */
+ const std::forward_list& devices() const noexcept {
+ return m_available_devices;
+ }
+
private:
constexpr static const char *STMDSP_USB_ID =
#ifndef STMDSP_WIN32
@@ -50,24 +100,7 @@ namespace stmdsp
"USB\\VID_0483&PID_5740";
#endif
- public:
- std::list& scan();
- auto& devices() {
- return m_available_devices;
- }
-
- private:
- std::list m_available_devices;
- };
-
- using adcsample_t = uint16_t;
- using dacsample_t = uint16_t;
-
- enum class platform {
- Unknown,
- H7, /* Behind in feature support */
- L4, /* Complete feature support */
- G4 /* Currently unsupported */
+ std::forward_list m_available_devices;
};
class device
@@ -96,7 +129,7 @@ namespace stmdsp
std::vector continuous_read();
std::vector continuous_read_input();
- void siggen_upload(dacsample_t *buffer, unsigned int size);
+ bool siggen_upload(dacsample_t *buffer, unsigned int size);
void siggen_start();
void siggen_stop();
@@ -116,6 +149,11 @@ namespace stmdsp
unsigned int m_sample_rate = 0;
bool m_is_siggening = false;
bool m_is_running = false;
+
+ std::mutex m_lock;
+
+ bool try_command(std::basic_string data);
+ bool try_read(std::basic_string cmd, uint8_t *dest, unsigned int dest_size);
};
}
diff --git a/source/wav.hpp b/source/wav.hpp
index 9ff06e5..71842bd 100644
--- a/source/wav.hpp
+++ b/source/wav.hpp
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
namespace wav
{
@@ -64,31 +65,30 @@ namespace wav
file.read(reinterpret_cast(&d), sizeof(wav::data));
if (!d.valid())
return;
- m_data = new char[d.size + 4096 - (d.size % 4096)];
- m_size = d.size;
- file.read(m_data, d.size);
+ m_data.resize(d.size / sizeof(int16_t));
+ m_next = m_data.begin();
+ file.read(reinterpret_cast(m_data.data()), d.size);
}
}
clip() = default;
bool valid() const {
- return m_data != nullptr && m_size > 0;
+ return !m_data.empty();
}
- auto data() const {
- return m_data;
+ const int16_t *data() const {
+ return m_data.data();
}
- auto next(unsigned int chunksize = 3000) {
- if (m_pos == m_size) {
- m_pos = 0;
+ void next(int16_t *buf, unsigned int size) {
+ for (unsigned int i = 0; i < size; ++i) {
+ if (m_next == m_data.end())
+ m_next = m_data.begin();
+ else
+ *buf++ = *m_next++;
}
- auto ret = m_data + m_pos;
- m_pos = std::min(m_pos + chunksize, m_size);
- return ret;
}
private:
- char *m_data = nullptr;
- uint32_t m_size = 0;
- uint32_t m_pos = 0;
+ std::vector m_data;
+ decltype(m_data.begin()) m_next;
};
}