Corrected some issues related to controllers with small RAM and limited numbers support (i.e. BBC micro:bit and Calliope mini). eric7

Thu, 20 Mar 2025 11:54:57 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Thu, 20 Mar 2025 11:54:57 +0100
branch
eric7
changeset 11177
f511038a0061
parent 11176
1b0e4bf80f49
child 11178
52699bca6df9

Corrected some issues related to controllers with small RAM and limited numbers support (i.e. BBC micro:bit and Calliope mini).

src/eric7/APIs/Python3/eric7.api file | annotate | diff | comparison | revisions
src/eric7/Documentation/Help/source.qch file | annotate | diff | comparison | revisions
src/eric7/Documentation/Help/source.qhp file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.MicrobitDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.QScintilla.MiniEditor.html file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/DeviceBase.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/MicrobitDevices.py file | annotate | diff | comparison | revisions
src/eric7/QScintilla/MiniEditor.py file | annotate | diff | comparison | revisions
--- a/src/eric7/APIs/Python3/eric7.api	Tue Mar 18 18:32:29 2025 +0100
+++ b/src/eric7/APIs/Python3/eric7.api	Thu Mar 20 11:54:57 2025 +0100
@@ -3017,6 +3017,7 @@
 eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.deviceName?4()
 eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.forceInterrupt?4()
 eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getBluetoothStatus?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getBoardInformation?4()
 eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDeviceScan?4(timeout=10)
 eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDocumentationUrl?4()
 eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDownloadMenuEntries?4()
@@ -9613,6 +9614,9 @@
 eric7.QScintilla.MiniEditor.MiniEditor.getSearchSelectionHighlight?4()
 eric7.QScintilla.MiniEditor.MiniEditor.gotoLine?4(line, pos=1)
 eric7.QScintilla.MiniEditor.MiniEditor.highlightSearchSelection?4(startLine, startIndex, endLine, endIndex)
+eric7.QScintilla.MiniEditor.MiniEditor.isMicroPythonFile?4()
+eric7.QScintilla.MiniEditor.MiniEditor.isPy3File?4()
+eric7.QScintilla.MiniEditor.MiniEditor.isPyFile?7
 eric7.QScintilla.MiniEditor.MiniEditor.languageChanged?7
 eric7.QScintilla.MiniEditor.MiniEditor.refreshed?7
 eric7.QScintilla.MiniEditor.MiniEditor.setFileName?4(name)
Binary file src/eric7/Documentation/Help/source.qch has changed
--- a/src/eric7/Documentation/Help/source.qhp	Tue Mar 18 18:32:29 2025 +0100
+++ b/src/eric7/Documentation/Help/source.qhp	Thu Mar 20 11:54:57 2025 +0100
@@ -11875,6 +11875,7 @@
       <keyword name="MicrobitDevice.deviceName" id="MicrobitDevice.deviceName" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.deviceName" />
       <keyword name="MicrobitDevice.forceInterrupt" id="MicrobitDevice.forceInterrupt" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.forceInterrupt" />
       <keyword name="MicrobitDevice.getBluetoothStatus" id="MicrobitDevice.getBluetoothStatus" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getBluetoothStatus" />
+      <keyword name="MicrobitDevice.getBoardInformation" id="MicrobitDevice.getBoardInformation" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getBoardInformation" />
       <keyword name="MicrobitDevice.getDeviceScan" id="MicrobitDevice.getDeviceScan" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getDeviceScan" />
       <keyword name="MicrobitDevice.getDocumentationUrl" id="MicrobitDevice.getDocumentationUrl" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getDocumentationUrl" />
       <keyword name="MicrobitDevice.getDownloadMenuEntries" id="MicrobitDevice.getDownloadMenuEntries" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getDownloadMenuEntries" />
@@ -11996,6 +11997,8 @@
       <keyword name="MiniEditor.getSearchSelectionHighlight" id="MiniEditor.getSearchSelectionHighlight" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.getSearchSelectionHighlight" />
       <keyword name="MiniEditor.gotoLine" id="MiniEditor.gotoLine" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.gotoLine" />
       <keyword name="MiniEditor.highlightSearchSelection" id="MiniEditor.highlightSearchSelection" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.highlightSearchSelection" />
+      <keyword name="MiniEditor.isMicroPythonFile" id="MiniEditor.isMicroPythonFile" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.isMicroPythonFile" />
+      <keyword name="MiniEditor.isPy3File" id="MiniEditor.isPy3File" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.isPy3File" />
       <keyword name="MiniEditor.setFileName" id="MiniEditor.setFileName" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.setFileName" />
       <keyword name="MiniEditor.setLanguage" id="MiniEditor.setLanguage" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.setLanguage" />
       <keyword name="MiniEditor.setModified" id="MiniEditor.setModified" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.setModified" />
--- a/src/eric7/Documentation/Source/eric7.MicroPython.Devices.MicrobitDevices.html	Tue Mar 18 18:32:29 2025 +0100
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.MicrobitDevices.html	Thu Mar 20 11:54:57 2025 +0100
@@ -140,6 +140,10 @@
 <td>Public method to get Bluetooth status data of the connected board.</td>
 </tr>
 <tr>
+<td><a href="#MicrobitDevice.getBoardInformation">getBoardInformation</a></td>
+<td>Public method to get some information data of the connected board.</td>
+</tr>
+<tr>
 <td><a href="#MicrobitDevice.getDeviceScan">getDeviceScan</a></td>
 <td>Public method to perform a Bluetooth device scan.</td>
 </tr>
@@ -576,6 +580,25 @@
 raised to indicate an issue with the device
 </dd>
 </dl>
+<a NAME="MicrobitDevice.getBoardInformation" ID="MicrobitDevice.getBoardInformation"></a>
+<h4>MicrobitDevice.getBoardInformation</h4>
+<b>getBoardInformation</b>(<i></i>)
+<p>
+        Public method to get some information data of the connected board.
+</p>
+
+<dl>
+<dt>Return:</dt>
+<dd>
+dictionary containing the determined data
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+dict
+</dd>
+</dl>
 <a NAME="MicrobitDevice.getDeviceScan" ID="MicrobitDevice.getDeviceScan"></a>
 <h4>MicrobitDevice.getDeviceScan</h4>
 <b>getDeviceScan</b>(<i>timeout=10</i>)
--- a/src/eric7/Documentation/Source/eric7.QScintilla.MiniEditor.html	Tue Mar 18 18:32:29 2025 +0100
+++ b/src/eric7/Documentation/Source/eric7.QScintilla.MiniEditor.html	Thu Mar 20 11:54:57 2025 +0100
@@ -75,7 +75,7 @@
 EricMainWindow
 <h3>Class Attributes</h3>
 <table>
-<tr><td>None</td></tr>
+<tr><td>isPyFile</td></tr>
 </table>
 
 <h3>Class Methods</h3>
@@ -446,6 +446,14 @@
 <td>Public method to set a highlight for the selection at the start of a search.</td>
 </tr>
 <tr>
+<td><a href="#MiniEditor.isMicroPythonFile">isMicroPythonFile</a></td>
+<td>Public method to return a flag indicating a MicroPython file.</td>
+</tr>
+<tr>
+<td><a href="#MiniEditor.isPy3File">isPy3File</a></td>
+<td>Public method to return a flag indicating a Python3 file.</td>
+</tr>
+<tr>
 <td><a href="#MiniEditor.setFileName">setFileName</a></td>
 <td>Public method to set the file name of the file being displayed.</td>
 </tr>
@@ -1667,6 +1675,44 @@
 index of the selection end
 </dd>
 </dl>
+<a NAME="MiniEditor.isMicroPythonFile" ID="MiniEditor.isMicroPythonFile"></a>
+<h4>MiniEditor.isMicroPythonFile</h4>
+<b>isMicroPythonFile</b>(<i></i>)
+<p>
+        Public method to return a flag indicating a MicroPython file.
+</p>
+
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a MicroPython file
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="MiniEditor.isPy3File" ID="MiniEditor.isPy3File"></a>
+<h4>MiniEditor.isPy3File</h4>
+<b>isPy3File</b>(<i></i>)
+<p>
+        Public method to return a flag indicating a Python3 file.
+</p>
+
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a Python3 file
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
 <a NAME="MiniEditor.setFileName" ID="MiniEditor.setFileName"></a>
 <h4>MiniEditor.setFileName</h4>
 <b>setFileName</b>(<i>name</i>)
--- a/src/eric7/MicroPython/Devices/DeviceBase.py	Tue Mar 18 18:32:29 2025 +0100
+++ b/src/eric7/MicroPython/Devices/DeviceBase.py	Thu Mar 20 11:54:57 2025 +0100
@@ -1065,8 +1065,8 @@
         @rtype dict
         @exception OSError raised to indicate an issue with the device
         """
-        command = """
-def get_device_data():
+        commands = [  # needs to be splitted for boards with low memory
+            """def get_device_data():
     res = {}
 
     try:
@@ -1084,6 +1084,13 @@
         res['release'] = '.'.join(str(v) for v in sys.implementation.version)
         res['version'] = sys.version.split(';', 1)[-1].strip()
         res['machine'] = sys.implementation._machine
+    return res
+
+print(get_device_data())
+del get_device_data
+""",
+            """def get_device_data():
+    res = {}
 
     import sys
     res['py_platform'] = sys.platform
@@ -1105,6 +1112,13 @@
         res['mpy_file_version'] = sys.implementation.mpy & 0xff
     else:
         res['mpy_file_version'] = 0
+    return res
+
+print(get_device_data())
+del get_device_data
+""",
+            """def get_device_data():
+    res = {}
 
     try:
         import pimoroni
@@ -1120,6 +1134,13 @@
         res['mpy_variant'] = ''
         res['mpy_variant_info'] = ''
         res['mpy_variant_version'] = ''
+    return res
+
+print(get_device_data())
+del get_device_data
+""",
+            """def get_device_data():
+    res = {}
 
     res['mip'] = False
     res['upip'] = False
@@ -1144,10 +1165,14 @@
 print(get_device_data())
 del get_device_data
 """
-        out, err = self.executeCommands(command, mode=self._submitMode)
-        if err:
-            raise OSError(self._shortError(err))
-        return ast.literal_eval(out.decode("utf-8"))
+        ]
+        res = {}
+        for command in commands:
+            out, err = self.executeCommands(command, mode=self._submitMode)
+            if err:
+                raise OSError(self._shortError(err))
+            res.update(ast.literal_eval(out.decode("utf-8")))
+        return res
 
     def getBoardInformation(self):
         """
@@ -1161,27 +1186,6 @@
             """def get_board_info():
     res = {}
 
-    import gc
-    gc.enable()
-    gc.collect()
-    mem_alloc = gc.mem_alloc()
-    mem_free = gc.mem_free()
-    mem_total = mem_alloc + mem_free
-    res['mem_total_kb'] = mem_total / 1024.0
-    res['mem_used_kb'] = mem_alloc / 1024.0
-    res['mem_used_pc'] = mem_alloc / mem_total * 100.0
-    res['mem_free_kb'] = mem_free / 1024.0
-    res['mem_free_pc'] = mem_free / mem_total * 100.0
-    del gc, mem_alloc, mem_free, mem_total
-
-    return res
-
-print(get_board_info())
-del get_board_info
-""",
-            """def get_board_info():
-    res = {}
-
     try:
         import os
         uname = os.uname()
@@ -1242,60 +1246,6 @@
     res = {}
 
     try:
-        import os
-        stat_ = os.statvfs('/flash')
-        res['flash_info_available'] = True
-        res['flash_total_kb'] = stat_[2] * stat_[0] / 1024.0
-        res['flash_free_kb'] = stat_[3] * stat_[0] / 1024.0
-        res['flash_used_kb'] = res['flash_total_kb'] - res['flash_free_kb']
-        res['flash_free_pc'] = res['flash_free_kb'] / res['flash_total_kb'] * 100.0
-        res['flash_used_pc'] = res['flash_used_kb'] / res['flash_total_kb'] * 100.0
-    except (AttributeError, OSError):
-        res['flash_info_available'] = False
-
-    return res
-
-print(get_board_info())
-del get_board_info
-""",
-            """def get_board_info():
-    res = {}
-
-    try:
-        import machine as mc
-        try:
-            if isinstance(mc.freq(), tuple):
-                res['mc_frequency_mhz'] = mc.freq()[0] / 1000000.0
-            else:
-               res['mc_frequency_mhz'] = mc.freq() / 1000000.0
-        except NotImplementedError:
-            res['mc_frequency_mhz'] = None
-        try:
-            res['mc_temp_c'] = mc.Temp().read()
-        except AttributeError:
-            pass
-        res['mc_id'] = mc.unique_id()
-    except ImportError:
-        try:
-            import microcontroller as mc
-            res['mc_frequency_mhz'] = mc.cpu.frequency / 1000000.0
-            res['mc_temp_c'] = mc.cpu.temperature
-            res['mc_id'] = mc.cpu.uid
-        except ImportError:
-            res['mc_frequency_mhz'] = None
-            res['mc_temp_c'] = None
-    if 'mc_id' in res:
-        res['mc_id'] = ':'.join('{0:02X}'.format(x) for x in res['mc_id'])
-
-    return res
-
-print(get_board_info())
-del get_board_info
-""",
-            """def get_board_info():
-    res = {}
-
-    try:
         import ulab
         res['ulab'] = ulab.__version__
     except ImportError:
@@ -1307,12 +1257,124 @@
 del get_board_info
 """,
         ]
+
+        gc_command = """def get_board_info():
+    res = {}
+
+    import gc
+    gc.enable()
+    gc.collect()
+    mem_alloc = gc.mem_alloc()
+    mem_free = gc.mem_free()
+    mem_total = mem_alloc + mem_free
+    res['mem_total'] = mem_total
+    res['mem_used'] = mem_alloc
+    res['mem_free'] = mem_free
+    del gc, mem_alloc, mem_free, mem_total
+
+    return res
+
+print(get_board_info())
+del get_board_info
+"""
+
+        flash_command = """def get_board_info():
+    res = {}
+
+    try:
+        import os
+        stat_ = os.statvfs('/flash')
+        res['flash_info_available'] = True
+        res['flash_total'] = stat_[2] * stat_[0]
+        res['flash_free'] = stat_[3] * stat_[0]
+    except (AttributeError, OSError):
+        res['flash_info_available'] = False
+
+    return res
+
+print(get_board_info())
+del get_board_info
+"""
+
+        machine_command = """def get_board_info():
+    res = {}
+
+    try:
+        import machine as mc
+        try:
+            if isinstance(mc.freq(), tuple):
+                res['mc_frequency'] = mc.freq()[0]
+            else:
+               res['mc_frequency'] = mc.freq()
+        except NotImplementedError:
+            res['mc_frequency'] = None
+        try:
+            res['mc_temp_c'] = mc.Temp().read()
+        except AttributeError:
+            res['mc_temp_c'] = None
+        res['mc_id'] = mc.unique_id()
+    except ImportError:
+        try:
+            import microcontroller as mc
+            res['mc_frequency'] = mc.cpu.frequency
+            res['mc_temp_c'] = mc.cpu.temperature
+            res['mc_id'] = mc.cpu.uid
+        except ImportError:
+            res['mc_frequency'] = None
+            res['mc_temp_c'] = None
+    if 'mc_id' in res:
+        res['mc_id'] = ':'.join('{0:02X}'.format(x) for x in res['mc_id'])
+    else:
+        res['mc_id'] = None
+
+    return res
+
+print(get_board_info())
+del get_board_info
+"""
         res = {}
         for command in commands:
             out, err = self.executeCommands(command, mode=self._submitMode)
             if err:
                 raise OSError(self._shortError(err))
             res.update(ast.literal_eval(out.decode("utf-8")))
+
+        # Execute the commands needing some special postprocessing due to some
+        # boards supporting integer only.
+        out, err = self.executeCommands(gc_command, mode=self._submitMode)
+        if err:
+            raise OSError(self._shortError(err))
+        gc_res = ast.literal_eval(out.decode("utf-8"))
+        res['mem_total_kb'] = gc_res["mem_total"] / 1024.0
+        res['mem_used_kb'] = gc_res["mem_used"] / 1024.0
+        res['mem_used_pc'] = gc_res["mem_used"] / gc_res["mem_total"] * 100.0
+        res['mem_free_kb'] = gc_res["mem_free"] / 1024.0
+        res['mem_free_pc'] = gc_res["mem_free"] / gc_res["mem_total"] * 100.0
+
+        out, err = self.executeCommands(flash_command, mode=self._submitMode)
+        if err:
+            raise OSError(self._shortError(err))
+        flash_res = ast.literal_eval(out.decode("utf-8"))
+        res['flash_info_available'] = flash_res["flash_info_available"]
+        if flash_res["flash_info_available"]:
+            res['flash_total_kb'] = flash_res["flash_total"] / 1024.0
+            res['flash_free_kb'] = flash_res["flash_free"] / 1024.0
+            res['flash_used_kb'] = res['flash_total_kb'] - res['flash_free_kb']
+            res['flash_free_pc'] = res['flash_free_kb'] / res['flash_total_kb'] * 100.0
+            res['flash_used_pc'] = res['flash_used_kb'] / res['flash_total_kb'] * 100.0
+
+        out, err = self.executeCommands(machine_command, mode=self._submitMode)
+        if err:
+            raise OSError(self._shortError(err))
+        machine_res = ast.literal_eval(out.decode("utf-8"))
+        res['mc_frequency_mhz'] = (
+            machine_res["mc_frequency"] / 1000000.0
+            if machine_res["mc_frequency"] is not None
+            else None
+        )
+        res["mc_temp_c"] = machine_res["mc_temp_c"]
+        res["mc_id"] = machine_res["mc_id"]
+
         return res
 
     def getModules(self):
--- a/src/eric7/MicroPython/Devices/MicrobitDevices.py	Tue Mar 18 18:32:29 2025 +0100
+++ b/src/eric7/MicroPython/Devices/MicrobitDevices.py	Thu Mar 20 11:54:57 2025 +0100
@@ -73,7 +73,8 @@
         """
         super().setConnected(connected)
 
-        self._deviceData["local_mip"] = False
+        if self._deviceData:
+            self._deviceData["local_mip"] = False
 
         if self.hasCircuitPython():
             self._submitMode = "paste"
@@ -281,20 +282,22 @@
             # BBC micro:bit
             if firmware:
                 deviceDirectories = FileSystemUtilities.findVolume(
-                    "MAINTENANCE", findAll=True
+                    "MAINTENANCE", findAll=True, markerFile="DETAILS.TXT"
                 )
             else:
                 deviceDirectories = FileSystemUtilities.findVolume(
-                    "MICROBIT", findAll=True
+                    "MICROBIT", findAll=True, markerFile="DETAILS.TXT"
                 )
         else:
             # Calliope mini
             if firmware:
                 deviceDirectories = FileSystemUtilities.findVolume(
-                    "MAINTENANCE", findAll=True
+                    "MAINTENANCE", findAll=True, markerFile="DETAILS.TXT"
                 )
             else:
-                deviceDirectories = FileSystemUtilities.findVolume("MINI", findAll=True)
+                deviceDirectories = FileSystemUtilities.findVolume(
+                    "MINI", findAll=True, markerFile="DETAILS.TXT"
+                )
         if len(deviceDirectories) == 0:
             if self.getDeviceType() == "bbc_microbit":
                 # BBC micro:bit is not ready or not mounted
@@ -968,6 +971,21 @@
         return True
 
 
+    def getBoardInformation(self):
+        """
+        Public method to get some information data of the connected board.
+
+        @return dictionary containing the determined data
+        @rtype dict
+        """
+        res = super().getBoardInformation()
+        with contextlib.suppress(KeyError):
+            if res["mc_temp_c"] is not None:
+                res["mc_temp_c"] = res["mc_temp_c"] / 100  # due to integer support only
+
+        return res
+
+
 def createDevice(microPythonWidget, deviceType, _vid, _pid, _boardName, serialNumber):
     """
     Function to instantiate a MicroPython device object.
--- a/src/eric7/QScintilla/MiniEditor.py	Tue Mar 18 18:32:29 2025 +0100
+++ b/src/eric7/QScintilla/MiniEditor.py	Thu Mar 20 11:54:57 2025 +0100
@@ -54,7 +54,7 @@
 from eric7.EricWidgets.EricClickableLabel import EricClickableLabel
 from eric7.EricWidgets.EricMainWindow import EricMainWindow
 from eric7.EricWidgets.EricZoomWidget import EricZoomWidget
-from eric7.SystemUtilities import FileSystemUtilities, OSUtilities
+from eric7.SystemUtilities import FileSystemUtilities, OSUtilities, PythonUtilities
 
 from . import Lexers
 from .EditorOutline import EditorOutlineView
@@ -3421,6 +3421,26 @@
         """
         return pathlib.Path(fullFileName).name
 
+    def isPy3File(self):
+        """
+        Public method to return a flag indicating a Python3 file.
+
+        @return flag indicating a Python3 file
+        @rtype bool
+        """
+        return self.filetype in ("Python", "Python3")
+
+    isPyFile = isPy3File
+
+    def isMicroPythonFile(self):
+        """
+        Public method to return a flag indicating a MicroPython file.
+
+        @return flag indicating a MicroPython file
+        @rtype bool
+        """
+        return self.filetype == "MicroPython"
+
     def __modificationChanged(self, m):
         """
         Private slot to handle the modificationChanged signal.

eric ide

mercurial