status monitoring; improve connection safety

pull/1/head
Clyne 3 years ago
parent 12440b673f
commit 79032a73d5

@ -24,7 +24,7 @@
#include <iostream>
#include <string>
extern stmdsp::device *m_device;
extern std::shared_ptr<stmdsp::device> m_device;
extern void log(const std::string& str);
@ -75,7 +75,7 @@ void compileEditorCode()
}
stmdsp::platform platform;
if (m_device != nullptr) {
if (m_device) {
platform = m_device->get_platform();
} else {
// Assume a default.

@ -26,15 +26,17 @@
#include <deque>
#include <fstream>
#include <iostream>
#include <memory>
#include <mutex>
#include <thread>
extern std::string tempFileName;
extern stmdsp::device *m_device;
extern void log(const std::string& str);
extern std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string_view);
std::shared_ptr<stmdsp::device> m_device;
static const std::array<const char *, 6> sampleRateList {{
"8 kHz",
"16 kHz",
@ -75,18 +77,18 @@ static std::deque<stmdsp::dacsample_t> drawSamplesInputQueue;
static double drawSamplesTimeframe = 1.0; // seconds
static unsigned int drawSamplesBufferSize = 1;
static void measureCodeTask(stmdsp::device *device)
static void measureCodeTask(std::shared_ptr<stmdsp::device> device)
{
if (device == nullptr)
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.");
}
static void drawSamplesTask(stmdsp::device *device)
static void drawSamplesTask(std::shared_ptr<stmdsp::device> device)
{
if (device == nullptr)
if (!device)
return;
const bool doLogger = logResults && logSamplesFile.good();
@ -159,9 +161,9 @@ static void drawSamplesTask(stmdsp::device *device)
}
}
static void feedSigGenTask(stmdsp::device *device)
static void feedSigGenTask(std::shared_ptr<stmdsp::device> device)
{
if (device == nullptr)
if (!device)
return;
const auto bufferSize = m_device->get_buffer_size();
@ -197,6 +199,31 @@ static void feedSigGenTask(stmdsp::device *device)
}
}
static void statusTask(std::shared_ptr<stmdsp::device> device)
{
if (!device)
return;
while (device->connected()) {
std::unique_lock<std::timed_mutex> lockDevice (mutexDeviceLoad, std::defer_lock);
lockDevice.lock();
auto [status, error] = device->get_status();
lockDevice.unlock();
if (error != stmdsp::Error::None) {
if (error == stmdsp::Error::NotIdle) {
log("Error: Device already running...");
} else if (error == stmdsp::Error::ConversionAborted) {
log("Error: Algorithm unloaded, a fault occurred!");
} else {
log("Error: Device had an issue...");
}
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
static void deviceConnect();
static void deviceStart();
static void deviceAlgorithmUpload();
@ -286,7 +313,7 @@ void deviceRenderWidgets()
ImGui::InputText("", bufferSizeStr, sizeof(bufferSizeStr), ImGuiInputTextFlags_CharsDecimal);
ImGui::PopStyleColor();
if (ImGui::Button("Save")) {
if (m_device != nullptr) {
if (m_device) {
int n = std::clamp(std::stoi(bufferSizeStr), 100, 4096);
m_device->continuous_set_buffer_size(n);
}
@ -437,13 +464,14 @@ void deviceRenderDraw()
void deviceRenderMenu()
{
if (ImGui::BeginMenu("Run")) {
bool isConnected = m_device != nullptr;
bool isConnected = m_device ? true : false;
bool isRunning = isConnected && m_device->is_running();
static const char *connectLabel = "Connect";
if (ImGui::MenuItem(connectLabel)) {
if (ImGui::MenuItem(connectLabel, nullptr, false, !isConnected || (isConnected && !isRunning))) {
deviceConnect();
connectLabel = m_device == nullptr ? "Connect" : "Disconnect";
isConnected = m_device ? true : false;
connectLabel = isConnected ? "Disconnect" : "Connect";
}
ImGui::Separator();
@ -453,9 +481,9 @@ void deviceRenderMenu()
deviceStart();
}
if (ImGui::MenuItem("Upload algorithm", nullptr, false, isConnected))
if (ImGui::MenuItem("Upload algorithm", nullptr, false, isConnected && !isRunning))
deviceAlgorithmUpload();
if (ImGui::MenuItem("Unload algorithm", nullptr, false, isConnected))
if (ImGui::MenuItem("Unload algorithm", nullptr, false, isConnected && !isRunning))
deviceAlgorithmUnload();
ImGui::Separator();
if (ImGui::Checkbox("Measure Code Time", &measureCodeTime)) {
@ -480,16 +508,16 @@ void deviceRenderMenu()
logResults = false;
}
}
if (ImGui::MenuItem("Set buffer size...", nullptr, false, isConnected)) {
if (ImGui::MenuItem("Set buffer size...", nullptr, false, isConnected && !isRunning)) {
popupRequestBuffer = true;
}
ImGui::Separator();
if (ImGui::MenuItem("Load signal generator", nullptr, false, isConnected)) {
if (ImGui::MenuItem("Load signal generator", nullptr, false, isConnected && !isRunning)) {
popupRequestSiggen = true;
}
static const char *startSiggenLabel = "Start signal generator";
if (ImGui::MenuItem(startSiggenLabel, nullptr, false, isConnected)) {
if (m_device != nullptr) {
if (m_device) {
if (!genRunning) {
genRunning = true;
if (wavOutput.valid())
@ -522,7 +550,7 @@ void deviceRenderToolbar()
for (unsigned int i = 0; i < sampleRateList.size(); ++i) {
if (ImGui::Selectable(sampleRateList[i])) {
sampleRatePreview = sampleRateList[i];
if (m_device != nullptr && !m_device->is_running()) {
if (m_device && !m_device->is_running()) {
do {
m_device->set_sample_rate(i);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
@ -538,24 +566,28 @@ void deviceRenderToolbar()
void deviceConnect()
{
if (m_device == nullptr) {
static std::thread statusThread;
if (!m_device) {
stmdsp::scanner scanner;
if (auto devices = scanner.scan(); devices.size() > 0) {
try {
m_device = new stmdsp::device(devices.front());
m_device.reset(new stmdsp::device(devices.front()));
} catch (...) {
log("Failed to connect (check permissions?).");
m_device = nullptr;
m_device.reset();
}
if (m_device != nullptr) {
if (m_device) {
if (m_device->connected()) {
auto sri = m_device->get_sample_rate();
sampleRatePreview = sampleRateList[sri];
drawSamplesBufferSize = std::round(sampleRateInts[sri] * drawSamplesTimeframe);
log("Connected!");
statusThread = std::thread(statusTask, m_device);
statusThread.detach();
} else {
delete m_device;
m_device = nullptr;
m_device.reset();
log("Failed to connect.");
}
}
@ -563,15 +595,17 @@ void deviceConnect()
log("No devices found.");
}
} else {
delete m_device;
m_device = nullptr;
m_device->disconnect();
if (statusThread.joinable())
statusThread.join();
m_device.reset();
log("Disconnected.");
}
}
void deviceStart()
{
if (m_device == nullptr) {
if (!m_device) {
log("No device connected.");
return;
}
@ -579,6 +613,7 @@ void deviceStart()
if (m_device->is_running()) {
{
std::scoped_lock lock (mutexDrawSamples);
std::scoped_lock lock2 (mutexDeviceLoad);
std::this_thread::sleep_for(std::chrono::microseconds(150));
m_device->continuous_stop();
}
@ -603,7 +638,7 @@ void deviceStart()
void deviceAlgorithmUpload()
{
if (m_device == nullptr) {
if (!m_device) {
log("No device connected.");
return;
}
@ -625,7 +660,7 @@ void deviceAlgorithmUpload()
void deviceAlgorithmUnload()
{
if (m_device == nullptr) {
if (!m_device) {
log("No device connected.");
return;
}
@ -660,7 +695,7 @@ void deviceGenLoadList(std::string_view listStr)
if ((samples.size() & 1) == 1)
samples.push_back(samples.back());
if (m_device != nullptr)
if (m_device)
m_device->siggen_upload(&samples[0], samples.size());
log("Generator ready.");
} else {
@ -673,7 +708,7 @@ void deviceGenLoadFormula(std::string_view formula)
auto samples = deviceGenLoadFormulaEval(formula);
if (samples.size() > 0) {
if (m_device != nullptr)
if (m_device)
m_device->siggen_upload(&samples[0], samples.size());
log("Generator ready.");

@ -47,7 +47,6 @@ extern void deviceRenderWidgets();
// Globals that live here
bool done = false;
stmdsp::device *m_device = nullptr;
static LogView logView;

@ -13,6 +13,8 @@
#include <serial/serial.h>
extern void log(const std::string& str);
namespace stmdsp
{
std::list<std::string>& scanner::scan()
@ -26,25 +28,44 @@ namespace stmdsp
return m_available_devices;
}
device::device(const std::string& file) :
m_serial(file, 8'000'000, serial::Timeout::simpleTimeout(50))
device::device(const std::string& file)
{
if (m_serial.isOpen()) {
m_serial.flush();
m_serial.write("i");
if (auto id = m_serial.read(7); id.starts_with("stmdsp")) {
if (id.back() == 'h')
m_platform = platform::H7;
else if (id.back() == 'l')
m_platform = platform::L4;
else
m_serial.close();
} else {
m_serial.close();
}
// This could throw!
m_serial.reset(new serial::Serial(file, 8'000'000, serial::Timeout::simpleTimeout(50)));
m_serial->flush();
m_serial->write("i");
auto id = m_serial->read(7);
if (id.starts_with("stmdsp")) {
if (id.back() == 'h')
m_platform = platform::H7;
else if (id.back() == 'l')
m_platform = platform::L4;
else
m_serial.release();
} else {
m_serial.release();
}
}
device::~device()
{
disconnect();
}
bool device::connected() {
if (m_serial && !m_serial->isOpen())
m_serial.release();
return m_serial ? true : false;
}
void device::disconnect() {
if (m_serial)
m_serial.release();
}
void device::continuous_set_buffer_size(unsigned int size) {
if (connected()) {
m_buffer_size = size;
@ -54,7 +75,13 @@ namespace stmdsp
static_cast<uint8_t>(size),
static_cast<uint8_t>(size >> 8)
};
m_serial.write(request, 3);
try {
m_serial->write(request, 3);
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
}
@ -64,7 +91,13 @@ namespace stmdsp
'r',
static_cast<uint8_t>(id)
};
m_serial.write(request, 2);
try {
m_serial->write(request, 2);
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
}
@ -73,10 +106,16 @@ namespace stmdsp
uint8_t request[2] = {
'r', 0xFF
};
m_serial.write(request, 2);
unsigned char result = 0xFF;
m_serial.read(&result, 1);
try {
m_serial->write(request, 2);
m_serial->read(&result, 1);
} catch (...) {
m_serial.release();
log("Lost connection!");
}
m_sample_rate = result;
}
@ -85,23 +124,38 @@ namespace stmdsp
void device::continuous_start() {
if (connected()) {
m_serial.write("R");
m_is_running = true;
try {
m_serial->write("R");
m_is_running = true;
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
}
void device::continuous_start_measure() {
if (connected()) {
m_serial.write("M");
m_is_running = true;
try {
m_serial->write("M");
m_is_running = true;
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
}
uint32_t device::continuous_start_get_measurement() {
uint32_t count = 0;
if (connected()) {
m_serial.write("m");
m_serial.read(reinterpret_cast<uint8_t *>(&count), sizeof(uint32_t));
try {
m_serial->write("m");
m_serial->read(reinterpret_cast<uint8_t *>(&count), sizeof(uint32_t));
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
return count / 2;
@ -109,25 +163,30 @@ namespace stmdsp
std::vector<adcsample_t> device::continuous_read() {
if (connected()) {
m_serial.write("s");
unsigned char sizebytes[2];
m_serial.read(sizebytes, 2);
unsigned int size = sizebytes[0] | (sizebytes[1] << 8);
if (size > 0) {
std::vector<adcsample_t> data (size);
unsigned int total = size * sizeof(adcsample_t);
unsigned int offset = 0;
while (total > 512) {
m_serial.read(reinterpret_cast<uint8_t *>(&data[0]) + offset, 512);
m_serial.write("n");
offset += 512;
total -= 512;
}
m_serial.read(reinterpret_cast<uint8_t *>(&data[0]) + offset, total);
m_serial.write("n");
return data;
try {
m_serial->write("s");
unsigned char sizebytes[2];
m_serial->read(sizebytes, 2);
unsigned int size = sizebytes[0] | (sizebytes[1] << 8);
if (size > 0) {
std::vector<adcsample_t> data (size);
unsigned int total = size * sizeof(adcsample_t);
unsigned int offset = 0;
while (total > 512) {
m_serial->read(reinterpret_cast<uint8_t *>(&data[0]) + offset, 512);
m_serial->write("n");
offset += 512;
total -= 512;
}
m_serial->read(reinterpret_cast<uint8_t *>(&data[0]) + offset, total);
m_serial->write("n");
return data;
}
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
@ -136,25 +195,30 @@ namespace stmdsp
std::vector<adcsample_t> device::continuous_read_input() {
if (connected()) {
m_serial.write("t");
unsigned char sizebytes[2];
m_serial.read(sizebytes, 2);
unsigned int size = sizebytes[0] | (sizebytes[1] << 8);
if (size > 0) {
std::vector<adcsample_t> data (size);
unsigned int total = size * sizeof(adcsample_t);
unsigned int offset = 0;
while (total > 512) {
m_serial.read(reinterpret_cast<uint8_t *>(&data[0]) + offset, 512);
m_serial.write("n");
offset += 512;
total -= 512;
}
m_serial.read(reinterpret_cast<uint8_t *>(&data[0]) + offset, total);
m_serial.write("n");
return data;
try {
m_serial->write("t");
unsigned char sizebytes[2];
m_serial->read(sizebytes, 2);
unsigned int size = sizebytes[0] | (sizebytes[1] << 8);
if (size > 0) {
std::vector<adcsample_t> data (size);
unsigned int total = size * sizeof(adcsample_t);
unsigned int offset = 0;
while (total > 512) {
m_serial->read(reinterpret_cast<uint8_t *>(&data[0]) + offset, 512);
m_serial->write("n");
offset += 512;
total -= 512;
}
m_serial->read(reinterpret_cast<uint8_t *>(&data[0]) + offset, total);
m_serial->write("n");
return data;
}
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
@ -163,8 +227,13 @@ namespace stmdsp
void device::continuous_stop() {
if (connected()) {
m_serial.write("S");
m_is_running = false;
try {
m_serial->write("S");
m_is_running = false;
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
}
@ -175,26 +244,39 @@ namespace stmdsp
static_cast<uint8_t>(size),
static_cast<uint8_t>(size >> 8)
};
m_serial.write(request, 3);
m_serial.write((uint8_t *)buffer, size * sizeof(dacsample_t));
// TODO
if (!m_is_running)
m_serial.write((uint8_t *)buffer, size * sizeof(dacsample_t));
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!");
}
}
}
void device::siggen_start() {
if (connected()) {
m_is_siggening = true;
m_serial.write("W");
try {
m_serial->write("W");
m_is_siggening = true;
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
}
void device::siggen_stop() {
if (connected()) {
m_is_siggening = false;
m_serial.write("w");
try {
m_serial->write("w");
m_is_siggening = false;
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
}
@ -205,14 +287,48 @@ namespace stmdsp
static_cast<uint8_t>(size),
static_cast<uint8_t>(size >> 8)
};
m_serial.write(request, 3);
m_serial.write(buffer, size);
try {
m_serial->write(request, 3);
m_serial->write(buffer, size);
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
}
void device::unload_filter() {
if (connected())
m_serial.write("e");
if (connected()) {
try {
m_serial->write("e");
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
}
std::pair<RunStatus, Error> device::get_status() {
std::pair<RunStatus, Error> ret;
if (connected()) {
try {
m_serial->write("I");
auto result = m_serial->read(2);
ret = {static_cast<RunStatus>(result[0]),
static_cast<Error>(result[1])};
bool running = ret.first == RunStatus::Running;
if (m_is_running != running)
m_is_running = running;
} catch (...) {
m_serial.release();
log("Lost connection!");
}
}
return ret;
}
}

@ -12,15 +12,34 @@
#ifndef STMDSP_HPP_
#define STMDSP_HPP_
#include <serial/serial.h>
#include <cstdint>
#include <list>
#include <serial/serial.h>
#include <memory>
#include <string>
#include <tuple>
namespace stmdsp
{
constexpr unsigned int SAMPLES_MAX = 4096;
enum class RunStatus : char {
Idle = '1',
Running,
Recovering
};
enum class Error : char {
None = 0,
BadParam,
BadParamSize,
BadUserCodeLoad,
BadUserCodeSize,
NotIdle,
ConversionAborted
};
class scanner
{
private:
@ -46,39 +65,41 @@ namespace stmdsp
enum class platform {
Unknown,
H7,
L4,
G4
H7, /* Behind in feature support */
L4, /* Complete feature support */
G4 /* Currently unsupported */
};
class device
{
public:
device(const std::string& file);
~device();
~device() {
m_serial.close();
}
bool connected() {
return m_serial.isOpen();
}
bool connected();
void disconnect();
auto get_platform() const { return m_platform; }
void continuous_set_buffer_size(unsigned int size);
unsigned int get_buffer_size() const { return m_buffer_size; }
void set_sample_rate(unsigned int id);
unsigned int get_sample_rate();
void continuous_start();
void continuous_stop();
void continuous_start_measure();
uint32_t continuous_start_get_measurement();
std::vector<adcsample_t> continuous_read();
std::vector<adcsample_t> continuous_read_input();
void continuous_stop();
void siggen_upload(dacsample_t *buffer, unsigned int size);
void siggen_start();
void siggen_stop();
bool is_siggening() const { return m_is_siggening; }
bool is_running() const { return m_is_running; }
@ -86,8 +107,10 @@ namespace stmdsp
void upload_filter(unsigned char *buffer, size_t size);
void unload_filter();
std::pair<RunStatus, Error> get_status();
private:
serial::Serial m_serial;
std::unique_ptr<serial::Serial> m_serial;
platform m_platform = platform::Unknown;
unsigned int m_buffer_size = SAMPLES_MAX;
unsigned int m_sample_rate = 0;

Loading…
Cancel
Save