From 6cbee2070fd6ec547d442e60ba9350b8fccf8a9b Mon Sep 17 00:00:00 2001
From: f4exb <f4exb06@gmail.com>
Date: Thu, 14 Mar 2019 23:02:51 +0100
Subject: [PATCH] Perseus: corrected startup sequence to restart full
 enumeration sequence if firmware is missing initially. Fixes cold start
 flawed init sequence

---
 devices/perseus/deviceperseus.cpp     | 18 ++++++++++++
 devices/perseus/deviceperseus.h       |  3 +-
 devices/perseus/deviceperseusscan.cpp | 41 +++++++++++++++++++++------
 devices/perseus/deviceperseusscan.h   |  3 +-
 4 files changed, 54 insertions(+), 11 deletions(-)

diff --git a/devices/perseus/deviceperseus.cpp b/devices/perseus/deviceperseus.cpp
index 0b3bbec2e..bc4b553dc 100644
--- a/devices/perseus/deviceperseus.cpp
+++ b/devices/perseus/deviceperseus.cpp
@@ -33,3 +33,21 @@ DevicePerseus& DevicePerseus::instance()
     return inst;
 }
 
+void DevicePerseus::scan()
+{
+    // If some firmware was not downloaded at time of enumeration interface will break later
+    // so in this case we re initialize the library, clear the scan results and scan again
+    if (!internal_scan())
+    {
+        qDebug("DevicePerseus::scan: re-init library and scan again");
+        m_scan.clear();
+        perseus_exit();
+        m_nbDevices = perseus_init();
+        internal_scan();
+    }
+}
+
+bool DevicePerseus::internal_scan()
+{
+    return m_scan.scan(m_nbDevices);
+}
diff --git a/devices/perseus/deviceperseus.h b/devices/perseus/deviceperseus.h
index 47d8a38c5..277e47953 100644
--- a/devices/perseus/deviceperseus.h
+++ b/devices/perseus/deviceperseus.h
@@ -25,7 +25,7 @@ class DEVICES_API DevicePerseus
 {
 public:
     static DevicePerseus& instance();
-    void scan() { m_scan.scan(m_nbDevices); }
+    void scan();
     void getSerials(std::vector<std::string>& serials) const { m_scan.getSerials(serials); }
     int getSequenceFromSerial(const std::string& serial) const { return m_scan.getSequenceFromSerial(serial); }
 
@@ -36,6 +36,7 @@ protected:
     ~DevicePerseus();
 
 private:
+    bool internal_scan();
     int m_nbDevices;
     DevicePerseusScan m_scan;
 };
diff --git a/devices/perseus/deviceperseusscan.cpp b/devices/perseus/deviceperseusscan.cpp
index 4fac6625e..3774aad5f 100644
--- a/devices/perseus/deviceperseusscan.cpp
+++ b/devices/perseus/deviceperseusscan.cpp
@@ -20,26 +20,40 @@
 #include <QtGlobal>
 
 
-void DevicePerseusScan::scan(int nbDevices)
+bool DevicePerseusScan::scan(int nbDevices)
 {
-	if (nbDevices == 0) {
+	if (nbDevices == 0)
+    {
 		qInfo("DevicePerseusScan::scan: no Perseus devices");
-		return;
+		return true;
 	}
 
+    bool done = true;
 	perseus_descr *descr;
 	eeprom_prodid prodid;
 
 	for (int deviceIndex = 0; deviceIndex < nbDevices; deviceIndex++)
 	{
-		if ((descr = perseus_open(deviceIndex)) == 0) {
-			qCritical("DevicePerseusScan::scan: open error: %s", perseus_errorstr());
+		if ((descr = perseus_open(deviceIndex)) == 0)
+        {
+			qCritical("DevicePerseusScan::scan: device #%d open error: %s", deviceIndex, perseus_errorstr());
 			perseus_close(descr);
 			continue;
 		}
 
-        if (perseus_firmware_download(descr, 0) < 0) {
-            qCritical("DevicePerseusScan::scan: firmware download error: %s", perseus_errorstr());
+        if (descr->firmware_downloaded)
+        {
+            qDebug("DevicePerseusScan::scan: device #%d firmware is already downloaded", deviceIndex);
+        }
+        else
+        {
+            qDebug("DevicePerseusScan::scan: device #%d firmware is not yet downloaded", deviceIndex);
+            done = false;
+        }
+
+        if (perseus_firmware_download(descr, 0) < 0)
+        {
+            qCritical("DevicePerseusScan::scan: device #%d firmware download error: %s", deviceIndex, perseus_errorstr());
             perseus_close(descr);
             continue;
         }
@@ -48,8 +62,9 @@ void DevicePerseusScan::scan(int nbDevices)
             qInfo("DevicePerseusScan::scan: device #%d firmware downloaded", deviceIndex);
         }
 
-		if (perseus_get_product_id(descr,&prodid) < 0) {
-			qCritical("DevicePerseusScan::scan: get product id error: %s", perseus_errorstr());
+		if (perseus_get_product_id(descr,&prodid) < 0)
+        {
+			qCritical("DevicePerseusScan::scan: device #%d get product id error: %s", deviceIndex, perseus_errorstr());
 			perseus_close(descr);
 			continue;
 		}
@@ -65,6 +80,14 @@ void DevicePerseusScan::scan(int nbDevices)
 			perseus_close(descr);
 		}
 	}
+
+    return done;
+}
+
+void DevicePerseusScan::clear()
+{
+    m_scans.clear();
+    m_serialMap.clear();
 }
 
 const std::string* DevicePerseusScan::getSerialAt(unsigned int index) const
diff --git a/devices/perseus/deviceperseusscan.h b/devices/perseus/deviceperseusscan.h
index 17bc8aca3..dcd8f0b00 100644
--- a/devices/perseus/deviceperseusscan.h
+++ b/devices/perseus/deviceperseusscan.h
@@ -35,7 +35,8 @@ public:
         int         m_sequence;
     };
 
-    void scan(int nbDevices);
+    bool scan(int nbDevices); //!< false if one device had its firmware not yet downloaded
+    void clear();
     int getNbActiveDevices() const { return m_scans.size(); }
     const std::string* getSerialAt(unsigned int index) const;
     uint16_t getSerialNumberAt(unsigned int index) const ;