src/eric7/MicroPython/Devices/MicrobitDevices.py

branch
eric7
changeset 11186
c2d18aefef6b
parent 11177
f511038a0061
child 11189
289c7150ec4b
--- a/src/eric7/MicroPython/Devices/MicrobitDevices.py	Fri Mar 21 18:12:17 2025 +0100
+++ b/src/eric7/MicroPython/Devices/MicrobitDevices.py	Sun Mar 23 14:55:14 2025 +0100
@@ -654,12 +654,12 @@
         @rtype tuple of (str, tuple)
         @exception OSError raised to indicate an issue with the device
         """
-        if self.hasCircuitPython():
+        if self.hasCircuitPython() or self.supportsDirectories():
             return super().lls(
                 dirname=dirname, fullstat=fullstat, showHidden=showHidden
             )
         else:
-            # BBC micro:bit with MicroPython does not support directories
+            # BBC micro:bit with old MicroPython does not support directories
             command = """
 import os as __os_
 
@@ -667,8 +667,11 @@
     return showHidden or (filename[0] != '.' and filename[-1] != '~')
 
 def stat(filename):
-    size = __os_.size(filename)
-    return (0, 0, 0, 0, 0, 0, size, 0, 0, 0)
+    try:
+        return __os_.stat(filename)
+    except AttributeError:
+        size = __os_.size(filename)
+        return (0, 0, 0, 0, 0, 0, size, 0, 0, 0)
 
 def listdir_stat(showHidden):
     files = __os_.listdir()
@@ -701,8 +704,50 @@
         if self.hasCircuitPython():
             return super().pwd()
         else:
-            # BBC micro:bit with MicroPython does not support directories
-            return ""
+            try:
+                return super().pwd()
+            except OSError:
+                # BBC micro:bit with old MicroPython does not support directories
+                return ""
+
+    def rm(self, filename):
+        """
+        Public method to remove a file from the connected device.
+
+        @param filename name of the file to be removed
+        @type str
+        """
+        if filename.startswith("/") and not self.supportsDirectories():
+            filename = filename[1:]
+        super().rm(filename)
+
+    def putData(self, deviceFileName, content):
+        """
+        Public method to write the given data to the connected device.
+
+        @param deviceFileName name of the file to write to
+        @type str
+        @param content data to write
+        @type bytes
+        @return flag indicating success
+        @rtype bool
+        """
+        if deviceFileName.startswith("/") and not self.supportsDirectories():
+            deviceFileName = deviceFileName[1:]
+        return super().putData(deviceFileName, content)
+
+    def getData(self, deviceFileName):
+        """
+        Public method to read data from the connected device.
+
+        @param deviceFileName name of the file to read from
+        @type str
+        @return data read from the device
+        @rtype bytes
+        """
+        if deviceFileName.startswith("/") and not self.supportsDirectories():
+            deviceFileName = deviceFileName[1:]
+        return super().getData(deviceFileName)
 
     ##################################################################
     ## time related methods below
@@ -970,6 +1015,157 @@
         """
         return True
 
+    def _boardInformationCommands(self):
+        """
+        Protected method defining the list of commands to be execute on the board
+        for determining information about the board.
+
+        @return list of command strings to be executed
+        @rtype list of str
+        """
+        # These are a subset of the generic ones.
+        return [  # needs to be splitted for boards with low memory
+            """def get_board_info():
+    res = {}
+
+    try:
+        import os
+        uname = os.uname()
+        res['sysname'] = uname.sysname
+        res['nodename'] = uname.nodename
+        res['release'] = uname.release
+        res['version'] = uname.version
+        res['machine'] = uname.machine
+    except AttributeError:
+        import sys
+        res['sysname'] = sys.platform
+        res['nodename'] = sys.platform
+        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_board_info())
+del get_board_info
+""",
+            """def get_board_info():
+    res = {}
+
+    import sys
+    res['py_platform'] = sys.platform
+    res['py_version'] = sys.version
+
+    try:
+        res['mpy_name'] = sys.implementation.name
+    except AttributeError:
+        res['mpy_name'] = 'unknown'
+    try:
+        res['mpy_version'] = '.'.join((str(i) for i in sys.implementation.version))
+    except AttributeError:
+        res['mpy_version'] = 'unknown'
+    try:
+        import pimoroni
+        res['mpy_variant'] = 'Pimoroni Pico'
+        try:
+            import version
+            res['mpy_variant_info'] = version.BUILD
+            res['mpy_variant_version'] = version.BUILD.split('-')[2][1:]
+        except ImportError:
+            res['mpy_variant_info'] = ''
+            res['mpy_variant_version'] = ''
+    except ImportError:
+        res['mpy_variant'] = ''
+        res['mpy_variant_info'] = ''
+        res['mpy_variant_version'] = ''
+
+    return res
+
+print(get_board_info())
+del get_board_info
+""",
+            """def get_board_info():
+    res = {}
+
+    try:
+        import ulab
+        res['ulab'] = ulab.__version__
+    except ImportError:
+        res['ulab'] = None
+
+    return res
+
+print(get_board_info())
+del get_board_info
+""",
+            # micro:bit specific variants due to missing float support
+            """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
+""",
+            """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
+""",
+            """def get_board_info():
+    res = {}
+
+    import machine as mc
+    import microbit as mb
+    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:
+        try:
+            res['mc_temp_c'] = mb.temperature() * 100
+        except AttributeError:
+            res['mc_temp_c'] = None
+    res['mc_id'] = mc.unique_id()
+    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
+""",
+        ]
 
     def getBoardInformation(self):
         """
@@ -979,12 +1175,50 @@
         @rtype dict
         """
         res = super().getBoardInformation()
+
+        # post-process the results to determine the right float entries
+
+        # 1. memory
+        res["mem_total_kb"] = res["mem_total"] / 1024.0
+        res["mem_used_kb"] = res["mem_used"] / 1024.0
+        res["mem_used_pc"] = res["mem_used"] / res["mem_total"] * 100.0
+        res["mem_free_kb"] = res["mem_free"] / 1024.0
+        res["mem_free_pc"] = res["mem_free"] / res["mem_total"] * 100.0
+
+        # 2. flash
+        if res["flash_info_available"]:
+            res["flash_total_kb"] = res["flash_total"] / 1024.0
+            res["flash_free_kb"] = 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
+
+        # 3. machine
+        res["mc_frequency_mhz"] = (
+            res["mc_frequency"] / 1000000.0 if res["mc_frequency"] is not None else None
+        )
         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 isMicrobit(self):
+        """
+        Public method to check, if the device is a BBC micro:bit or Calliope mini.
+
+        @return flag indicating a micro:bit device
+        @rtype bool
+        """
+        if (
+            ("micro:bit" in self.deviceName() or "Calliope" in self.deviceName())
+            and not self.hasCircuitPython()
+            and not self.supportsDirectories()
+        ):
+            return True
+
+        return False
+
 
 def createDevice(microPythonWidget, deviceType, _vid, _pid, _boardName, serialNumber):
     """
@@ -1006,3 +1240,7 @@
     @rtype MicrobitDevice
     """
     return MicrobitDevice(microPythonWidget, deviceType, serialNumber)
+
+
+#
+# eflag: noqa = M-613

eric ide

mercurial