src/eric7/MicroPython/MicrobitDevices.py

branch
eric7
changeset 9749
5d409223cf3f
parent 9738
4ae976ee5339
child 9750
4958dd72c937
diff -r df9520c864f2 -r 5d409223cf3f src/eric7/MicroPython/MicrobitDevices.py
--- a/src/eric7/MicroPython/MicrobitDevices.py	Wed Feb 08 11:54:36 2023 +0100
+++ b/src/eric7/MicroPython/MicrobitDevices.py	Wed Feb 08 18:09:19 2023 +0100
@@ -11,15 +11,16 @@
 import os
 import shutil
 
-from PyQt6.QtCore import QStandardPaths, pyqtSlot
+from PyQt6.QtCore import QStandardPaths, QUrl, pyqtSlot
+from PyQt6.QtNetwork import QNetworkRequest
 from PyQt6.QtWidgets import QInputDialog, QLineEdit
 
-from eric7 import Preferences
+from eric7 import Globals, Preferences
 from eric7.EricWidgets import EricFileDialog, EricMessageBox
 from eric7.EricWidgets.EricApplication import ericApp
 from eric7.SystemUtilities import FileSystemUtilities
 
-from .MicroPythonDevices import MicroPythonDevice
+from .MicroPythonDevices import FirmwareGithubUrls, MicroPythonDevice
 from .MicroPythonWidget import HAS_QTCHART
 
 
@@ -143,13 +144,17 @@
         @type QMenu
         """
         connected = self.microPython.isConnected()
+        linkConnected = self.microPython.isLinkConnected()
 
-        act = menu.addAction(self.tr("Flash MicroPython"), self.__flashMicroPython)
-        act.setEnabled(not connected)
-        act = menu.addAction(
+        menu.addAction(
+            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
+        ).setEnabled(connected and self.getDeviceType() != "calliope")
+        menu.addAction(
+            self.tr("Flash MicroPython"), self.__flashMicroPython
+        ).setEnabled(not linkConnected)
+        menu.addAction(
             self.tr("Flash Firmware"), lambda: self.__flashMicroPython(firmware=True)
-        )
-        act.setEnabled(not connected)
+        ).setEnabled(not linkConnected)
         menu.addSeparator()
         act = menu.addAction(self.tr("Save Script"), self.__saveScriptToDevice)
         act.setToolTip(self.tr("Save the current script to the selected device"))
@@ -160,10 +165,9 @@
         )
         act.setEnabled(connected)
         menu.addSeparator()
-        act = menu.addAction(
+        menu.addAction(
             self.tr("Reset {0}").format(self.deviceName()), self.__resetDevice
-        )
-        act.setEnabled(connected)
+        ).setEnabled(connected)
 
     def hasFlashMenuEntry(self):
         """
@@ -217,7 +221,7 @@
                             " instructions. </p>"
                             "<ul>"
                             "<li>unplug USB cable and any batteries</li>"
-                            "<li>keep RESET button pressed an plug USB cable"
+                            "<li>keep RESET button pressed and plug USB cable"
                             " back in</li>"
                             "<li>a drive called MAINTENANCE should be"
                             " available</li>"
@@ -291,6 +295,103 @@
             )
 
     @pyqtSlot()
+    def __showFirmwareVersions(self):
+        """
+        Private slot to show the firmware version of the connected device and the
+        available firmware version.
+        """
+        if self.microPython.isConnected():
+            interface = self.microPython.commandsInterface()
+            if interface is not None:
+                impInfo = interface.getImplementation()
+                versionInfo = interface.version()
+                if impInfo["name"] != "micropython":
+                    EricMessageBox.critical(
+                        None,
+                        self.tr("Show MicroPython Versions"),
+                        self.tr(
+                            """The firmware of the connected device cannot be"""
+                            """ determined or the board does not run MicroPython."""
+                            """ Aborting..."""
+                        ),
+                    )
+                else:
+                    impInfo["version"] = versionInfo["release"]
+                    if self.getDeviceType() == "bbc_microbit":
+                        if "nRF51822" in versionInfo["machine"]:
+                            url = QUrl(FirmwareGithubUrls["microbit_v1"])
+                        elif "nRF52833" in versionInfo["machine"]:
+                            url = QUrl(FirmwareGithubUrls["microbit_v2"])
+                        else:
+                            EricMessageBox.critical(
+                                None,
+                                self.tr("Show MicroPython Versions"),
+                                self.tr(
+                                    """<p>The BBC micro:bit generation cannot be"""
+                                    """ determined. Aborting...</p>"""
+                                ),
+                            )
+                            return
+                    else:
+                        EricMessageBox.critical(
+                            None,
+                            self.tr("Show MicroPython Versions"),
+                            self.tr(
+                                """<p>The firmware URL for the device type <b>{0}</b>"""
+                                """ is not known. Aborting...</p>"""
+                            ).format(self.getDeviceType()),
+                        )
+                        return
+
+                    ui = ericApp().getObject("UserInterface")
+                    request = QNetworkRequest(url)
+                    reply = ui.networkAccessManager().head(request)
+                    reply.finished.connect(
+                        lambda: self.__firmwareVersionResponse(reply, impInfo)
+                    )
+
+    def __firmwareVersionResponse(self, reply, implementation):
+        """
+        Private method handling the response of the latest version request.
+
+        @param reply reference to the reply object
+        @type QNetworkReply
+        @param implementation dictionary containing the implementation data of the
+            connected device
+        @type dict
+        """
+        latestUrl = reply.url().toString()
+        tag = latestUrl.rsplit("/", 1)[-1]
+        while tag and not tag[0].isdecimal():
+            # get rid of leading non-decimal characters
+            tag = tag[1:]
+        latestVersion = Globals.versionToTuple(tag)
+
+        if implementation["version"] == "unknown":
+            currentVersionStr = self.tr("unknown")
+            currentVersion = (0, 0, 0)
+        else:
+            currentVersionStr = implementation["version"]
+            currentVersion = Globals.versionToTuple(currentVersionStr)
+
+        msg = self.tr(
+            "<h4>MicroPython Version Information<br/>"
+            "(BBC micro:bit v{2})</h4>"
+            "<table>"
+            "<tr><td>Installed:</td><td>{0}</td></tr>"
+            "<tr><td>Available:</td><td>{1}</td></tr>"
+            "</table>"
+        ).format(currentVersionStr, tag, currentVersionStr[0])
+        if currentVersion < latestVersion:
+            msg += self.tr("<p><b>Update available!</b></p>")
+
+        EricMessageBox.information(
+            None,
+            self.tr("MicroPython Version"),
+            msg,
+        )
+
+    @pyqtSlot()
     def __saveMain(self):
         """
         Private slot to copy the current script as 'main.py' onto the

eric ide

mercurial