]> code.bitgloo.com Git - clyne/stmdspgui.git/commitdiff
status monitoring; improve connection safety
authorClyne Sullivan <clyne@bitgloo.com>
Sat, 30 Oct 2021 20:50:03 +0000 (16:50 -0400)
committerClyne Sullivan <clyne@bitgloo.com>
Sat, 30 Oct 2021 20:50:03 +0000 (16:50 -0400)
source/code.cpp
source/device.cpp
source/main.cpp
source/stmdsp/stmdsp.cpp
source/stmdsp/stmdsp.hpp

index 2f10b90495b74bb81cde08a452ce7600fff94000..e29044013aec6966f223a3e63df1bae7015e4044 100644 (file)
@@ -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.
index 6f052d78636300251c7c2ff56aaa135a83d0c9e7..cfadd6eca56319503dad4849c47255931e4abe83 100644 (file)
 #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.");
index e11211890aab7b1af8998d60467e69134aaaaf94..b98ec2b0c1649f6c9b346db0b45c60492d63d328 100644 (file)
@@ -47,7 +47,6 @@ extern void deviceRenderWidgets();
 
 // Globals that live here
 bool done = false;
-stmdsp::device *m_device = nullptr;
 
 static LogView logView;
 
index d219d38fd03b265cd3a873c699d8fb36a1a32f56..650dbc41f78e621d719989406ffb1b57bbbae35a 100644 (file)
@@ -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;
     }
 }
+
index 0b9398e59479f803f7d30e5685d648d96198321d..76ca94e09b08653d4947425e2e4d3242cfdf9166 100644 (file)
 #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;