eric6/MicroPython/PyBoardDevices.py

changeset 7327
71883ddcb762
parent 7321
3642cc5df144
child 7328
e2d85ef3fadb
--- a/eric6/MicroPython/PyBoardDevices.py	Sat Nov 02 18:19:24 2019 +0100
+++ b/eric6/MicroPython/PyBoardDevices.py	Sat Nov 02 18:21:01 2019 +0100
@@ -7,8 +7,13 @@
 Module implementing the device interface class for PyBoard boards.
 """
 
-from E5Gui import E5MessageBox
+import os
+
+from PyQt5.QtCore import pyqtSlot, QStandardPaths
+
+from E5Gui import E5MessageBox, E5FileDialog
 from E5Gui.E5Application import e5App
+from E5Gui.E5ProcessDialog import E5ProcessDialog
 
 from .MicroPythonDevices import MicroPythonDevice
 from .MicroPythonWidget import HAS_QTCHART
@@ -183,15 +188,167 @@
         @param menu reference to the context menu
         @type QMenu
         """
-        menu.addAction(
-            self.tr("MicroPython Install Instructions"),
-            self.__showInstallInstructions)
-        # TODO: add entry to flash a new firmware using dfu-util
+        connected = self.microPython.isConnected()
+        
+        act = menu.addAction(self.tr("List DFU-capable Devices"),
+                             self.__listDfuCapableDevices)
+        act.setEnabled(not connected)
+        act = menu.addAction(self.tr("Flash MicroPython Firmware"),
+                             self.__flashMicroPython)
+        act.setEnabled(not connected)
+        menu.addSeparator()
+        menu.addAction(self.tr("MicroPython Flash Instructions"),
+                       self.__showFlashInstructions)
     
-    def __showInstallInstructions(self):
+    @pyqtSlot()
+    def __showFlashInstructions(self):
         """
         Private slot to open the URL containing instructions for installing
         MicroPython on the pyboard.
         """
         e5App().getObject("UserInterface").launchHelpViewer(
             PyBoardDevice.FlashInstructionsURL)
+    
+    def __dfuUtilAvailable(self):
+        """
+        Private method to check the availability of dfu-util.
+        
+        @return flag indicating the availability of dfu-util
+        @rtype bool
+        """
+        available = False
+        program = Preferences.getMicroPython("DfuUtilPath")
+        if not program:
+            program = "dfu-util"
+            if Utilities.isinpath(program):
+                available = True
+        else:
+            if Utilities.isExecutable(program):
+                available = True
+        
+        if not available:
+            E5MessageBox.critical(
+                self.microPython,
+                self.tr("dfu-util not available"),
+                self.tr("""The dfu-util firmware flashing tool"""
+                        """ <b>dfu-util</b> cannot be found or is not"""
+                        """ executable. Ensure it is in the search path"""
+                        """ or configure it on the MicroPython"""
+                        """ configuration page.""")
+            )
+        
+        return available
+    
+    def __showDfuEnableInstructions(self, flash=True):
+        """
+        Private method to show some instructions to enable the DFU mode.
+        
+        @param flash flag indicating to show a warning message for flashing
+        @type bool
+        @return flag indicating OK to continue or abort
+        @rtype bool
+        """
+        msg = self.tr(
+            "<h3>Enable DFU Mode</h3>"
+            "<p>1. Disconnect everything from your board</p>"
+            "<p>2. Disconnect your board</p>"
+            "<p>3. Connect the DFU/BOOT0 pin with a 3.3V pin</p>"
+            "<p>4. Re-connect your board</p>"
+            "<hr />"
+        )
+        
+        if flash:
+            msg += self.tr(
+                "<p><b>Warning:</b> Make sure that all other DFU capable"
+                " devices except your PyBoard are disconnected."
+                "<hr />"
+            )
+        
+        msg += self.tr(
+            "<p>Press <b>OK</b> to continue...</p>"
+        )
+        res = E5MessageBox.information(
+            self.microPython,
+            self.tr("Enable DFU mode"),
+            msg,
+            E5MessageBox.StandardButtons(
+                E5MessageBox.Abort |
+                E5MessageBox.Ok))
+        
+        return res == E5MessageBox.Ok
+    
+    def __showDfuDisableInstructions(self):
+        """
+        Private method to show some instructions to disable the DFU mode.
+        """
+        msg = self.tr(
+            "<h3>Disable DFU Mode</h3>"
+            "<p>1. Disconnect your board</p>"
+            "<p>2. Remove the DFU jumper</p>"
+            "<p>3. Re-connect your board</p>"
+            "<hr />"
+            "<p>Press <b>OK</b> to continue...</p>"
+        )
+        E5MessageBox.information(
+            self.microPython,
+            self.tr("Disable DFU mode"),
+            msg
+        )
+    
+    @pyqtSlot()
+    def __listDfuCapableDevices(self):
+        """
+        Private slot to list all DFU-capable devices.
+        """
+        if self.__dfuUtilAvailable():
+            ok2continue = self.__showDfuEnableInstructions(flash=False)
+            if ok2continue:
+                program = Preferences.getMicroPython("DfuUtilPath")
+                if not program:
+                    program = "dfu-util"
+                
+                args = [
+                    "--list",
+                ]
+                dlg = E5ProcessDialog(
+                    self.tr("'dfu-util' Output"),
+                    self.tr("List DFU capable Devices")
+                )
+                res = dlg.startProcess(program, args)
+                if res:
+                    dlg.exec_()
+    
+    @pyqtSlot()
+    def __flashMicroPython(self):
+        """
+        Private slot to flash a MicroPython firmware.
+        """
+        if self.__dfuUtilAvailable():
+            ok2continue = self.__showDfuEnableInstructions()
+            if ok2continue:
+                program = Preferences.getMicroPython("DfuUtilPath")
+                if not program:
+                    program = "dfu-util"
+                
+                downloadsPath = QStandardPaths.standardLocations(
+                    QStandardPaths.DownloadLocation)[0]
+                firmware = E5FileDialog.getOpenFileName(
+                    self.microPython,
+                    self.tr("Flash MicroPython Firmware"),
+                    downloadsPath,
+                    self.tr(
+                        "MicroPython Firmware Files (*.dfu);;All Files (*)")
+                )
+                if firmware and os.path.exists(firmware):
+                    args = [
+                        "--alt", "0",
+                        "--download", firmware,
+                    ]
+                    dlg = E5ProcessDialog(
+                        self.tr("'dfu-util' Output"),
+                        self.tr("Flash MicroPython Firmware")
+                    )
+                    res = dlg.startProcess(program, args)
+                    if res:
+                        dlg.exec_()
+                        self.__showDfuDisableInstructions()

eric ide

mercurial