MicroPython:

Sat, 02 Nov 2019 18:21:01 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 02 Nov 2019 18:21:01 +0100
changeset 7327
71883ddcb762
parent 7326
eab46b63ed91
child 7328
e2d85ef3fadb

MicroPython:
- added an entry to configure the 'dfu-util' executable path
- added menu entries to flash the PyBoard firmware

docs/changelog file | annotate | diff | comparison | revisions
eric6/MicroPython/PyBoardDevices.py file | annotate | diff | comparison | revisions
eric6/Preferences/ConfigurationPages/MicroPythonPage.py file | annotate | diff | comparison | revisions
eric6/Preferences/ConfigurationPages/MicroPythonPage.ui file | annotate | diff | comparison | revisions
eric6/Preferences/__init__.py file | annotate | diff | comparison | revisions
--- a/docs/changelog	Sat Nov 02 18:19:24 2019 +0100
+++ b/docs/changelog	Sat Nov 02 18:21:01 2019 +0100
@@ -4,6 +4,7 @@
 - bug fixes
 - MicroPython
   -- added a menu entry to show the local and device time side-by-side
+  -- added a PyBoard menu entry to flash a new firmware
 
 Version 19.11:
 - bug fixes
--- 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()
--- a/eric6/Preferences/ConfigurationPages/MicroPythonPage.py	Sat Nov 02 18:19:24 2019 +0100
+++ b/eric6/Preferences/ConfigurationPages/MicroPythonPage.py	Sat Nov 02 18:21:01 2019 +0100
@@ -38,6 +38,9 @@
         self.mpyCrossPicker.setMode(E5PathPickerModes.OpenFileMode)
         self.mpyCrossPicker.setFilters(self.tr("All Files (*)"))
         
+        self.dfuUtilPathPicker.setMode(E5PathPickerModes.OpenFileMode)
+        self.dfuUtilPathPicker.setFilters(self.tr("All Files (*)"))
+        
         # set initial values
         self.timeoutSpinBox.setValue(
             Preferences.getMicroPython("SerialTimeout") / 1000)
@@ -51,6 +54,8 @@
             Preferences.getMicroPython("ReplLineWrap"))
         self.mpyCrossPicker.setText(
             Preferences.getMicroPython("MpyCrossCompiler"))
+        self.dfuUtilPathPicker.setText(
+            Preferences.getMicroPython("DfuUtilPath"))
         self.micropythonDocuUrlLineEdit.setText(
             Preferences.getMicroPython("MicroPythonDocuUrl"))
         self.circuitpythonDocuUrlLineEdit.setText(
@@ -74,6 +79,8 @@
         Preferences.setMicroPython(
             "MpyCrossCompiler", self.mpyCrossPicker.text())
         Preferences.setMicroPython(
+            "DfuUtilPath", self.dfuUtilPathPicker.text())
+        Preferences.setMicroPython(
             "MicroPythonDocuUrl", self.micropythonDocuUrlLineEdit.text())
         Preferences.setMicroPython(
             "CircuitPythonDocuUrl", self.circuitpythonDocuUrlLineEdit.text())
--- a/eric6/Preferences/ConfigurationPages/MicroPythonPage.ui	Sat Nov 02 18:19:24 2019 +0100
+++ b/eric6/Preferences/ConfigurationPages/MicroPythonPage.ui	Sat Nov 02 18:21:01 2019 +0100
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>476</width>
-    <height>550</height>
+    <height>691</height>
    </rect>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
@@ -167,6 +167,38 @@
     </widget>
    </item>
    <item>
+    <widget class="QGroupBox" name="groupBox_5">
+     <property name="title">
+      <string>PyBoard</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <item>
+       <widget class="QLabel" name="label_7">
+        <property name="text">
+         <string>dfu-util Path:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="E5PathPicker" name="dfuUtilPathPicker" native="true">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="focusPolicy">
+         <enum>Qt::WheelFocus</enum>
+        </property>
+        <property name="toolTip">
+         <string>Enter the path of the dfu-util flashing executable</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
     <widget class="QGroupBox" name="groupBox_4">
      <property name="title">
       <string>Documentation</string>
@@ -251,6 +283,7 @@
   <tabstop>colorSchemeComboBox</tabstop>
   <tabstop>replWrapCheckBox</tabstop>
   <tabstop>mpyCrossPicker</tabstop>
+  <tabstop>dfuUtilPathPicker</tabstop>
   <tabstop>micropythonDocuUrlLineEdit</tabstop>
   <tabstop>circuitpythonDocuUrlLineEdit</tabstop>
   <tabstop>microbitDocuUrlLineEdit</tabstop>
--- a/eric6/Preferences/__init__.py	Sat Nov 02 18:19:24 2019 +0100
+++ b/eric6/Preferences/__init__.py	Sat Nov 02 18:21:01 2019 +0100
@@ -1451,6 +1451,7 @@
         "ShowHiddenLocal": True,
         "ShowHiddenDevice": True,
         "MpyCrossCompiler": "",         # path of the mpy-cross compiler
+        "DfuUtilPath": "",              # path of the dfu-util flashing tool
         "MicroPythonDocuUrl":
             "https://docs.micropython.org/en/latest/",
         "CircuitPythonDocuUrl":
@@ -1458,6 +1459,7 @@
         "MicrobitDocuUrl":
             "https://microbit-micropython.readthedocs.io/en/latest/",
     }
+    # TODO: add URLs for getting the firmware
     if Globals.isWindowsPlatform():
         microPythonDefaults["ColorScheme"] = "Windows 10"
     elif Globals.isMacPlatform():

eric ide

mercurial