Sun, 23 Mar 2025 14:55:14 +0100
Corrected some issues in the 'micro:bit' device class and enhanced the MPy file manager.
--- a/src/eric7/APIs/Python3/eric7.api Fri Mar 21 18:12:17 2025 +0100 +++ b/src/eric7/APIs/Python3/eric7.api Sun Mar 23 14:55:14 2025 +0100 @@ -2830,6 +2830,7 @@ eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog.getSelection?4() eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog.on_modulesList_itemChanged?4(item, column) eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog?1(devicePath, selectionMode=False, parent=None) +eric7.MicroPython.Devices.DeviceBase.BaseDevice._boardInformationCommands?5() eric7.MicroPython.Devices.DeviceBase.BaseDevice._getSetTimeCode?5() eric7.MicroPython.Devices.DeviceBase.BaseDevice._shortError?5(error) eric7.MicroPython.Devices.DeviceBase.BaseDevice.activateBluetoothInterface?4() @@ -2891,6 +2892,7 @@ eric7.MicroPython.Devices.DeviceBase.BaseDevice.hasWifi?4() eric7.MicroPython.Devices.DeviceBase.BaseDevice.hasWifiCountry?4() eric7.MicroPython.Devices.DeviceBase.BaseDevice.isLanConnected?4() +eric7.MicroPython.Devices.DeviceBase.BaseDevice.isMicrobit?4() eric7.MicroPython.Devices.DeviceBase.BaseDevice.isNetworkConnected?4() eric7.MicroPython.Devices.DeviceBase.BaseDevice.isWifiApConnected?4() eric7.MicroPython.Devices.DeviceBase.BaseDevice.isWifiClientConnected?4() @@ -2922,7 +2924,9 @@ eric7.MicroPython.Devices.DeviceBase.BaseDevice.stopAccessPoint?4() eric7.MicroPython.Devices.DeviceBase.BaseDevice.submitMode?4() eric7.MicroPython.Devices.DeviceBase.BaseDevice.supportsDeviceScan?4() +eric7.MicroPython.Devices.DeviceBase.BaseDevice.supportsDirectories?4() eric7.MicroPython.Devices.DeviceBase.BaseDevice.supportsLocalFileAccess?4() +eric7.MicroPython.Devices.DeviceBase.BaseDevice.supportsRenameFiles?4() eric7.MicroPython.Devices.DeviceBase.BaseDevice.syncTime?4(_deviceType, hasCPy=False) eric7.MicroPython.Devices.DeviceBase.BaseDevice.upipInstall?4(packages) eric7.MicroPython.Devices.DeviceBase.BaseDevice.writeCredentials?4(ssid, password, hostname, country) @@ -3006,6 +3010,7 @@ eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice?1(microPythonWidget, deviceType, vid, pid, parent=None) eric7.MicroPython.Devices.GenericMicroPythonDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, _boardName, _serialNumber) eric7.MicroPython.Devices.IgnoredBoards?7 +eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice._boardInformationCommands?5() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice._getSetTimeCode?5() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.activateBluetoothInterface?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.addDeviceMenuEntries?4(menu) @@ -3018,15 +3023,19 @@ 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.getData?4(deviceFileName) eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDeviceScan?4(timeout=10) eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDocumentationUrl?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDownloadMenuEntries?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.hasBluetooth?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.hasFlashMenuEntry?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.hasTimeCommands?4() +eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.isMicrobit?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.lls?4(dirname="", fullstat=False, showHidden=False) eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.ls?4(dirname="") +eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.putData?4(deviceFileName, content) eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.pwd?4() +eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.rm?4(filename) eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.runScript?4(script) eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.setButtons?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.setConnected?4(connected)
--- a/src/eric7/Documentation/Help/source.qhp Fri Mar 21 18:12:17 2025 +0100 +++ b/src/eric7/Documentation/Help/source.qhp Sun Mar 23 14:55:14 2025 +0100 @@ -2196,6 +2196,7 @@ <keyword name="BaseDevice" id="BaseDevice" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice" /> <keyword name="BaseDevice (Constructor)" id="BaseDevice (Constructor)" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.__init__" /> <keyword name="BaseDevice.__getDeviceData" id="BaseDevice.__getDeviceData" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.__getDeviceData" /> + <keyword name="BaseDevice._boardInformationCommands" id="BaseDevice._boardInformationCommands" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice._boardInformationCommands" /> <keyword name="BaseDevice._getSetTimeCode" id="BaseDevice._getSetTimeCode" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice._getSetTimeCode" /> <keyword name="BaseDevice._shortError" id="BaseDevice._shortError" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice._shortError" /> <keyword name="BaseDevice.activateBluetoothInterface" id="BaseDevice.activateBluetoothInterface" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.activateBluetoothInterface" /> @@ -2257,6 +2258,7 @@ <keyword name="BaseDevice.hasWifi" id="BaseDevice.hasWifi" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.hasWifi" /> <keyword name="BaseDevice.hasWifiCountry" id="BaseDevice.hasWifiCountry" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.hasWifiCountry" /> <keyword name="BaseDevice.isLanConnected" id="BaseDevice.isLanConnected" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.isLanConnected" /> + <keyword name="BaseDevice.isMicrobit" id="BaseDevice.isMicrobit" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.isMicrobit" /> <keyword name="BaseDevice.isNetworkConnected" id="BaseDevice.isNetworkConnected" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.isNetworkConnected" /> <keyword name="BaseDevice.isWifiApConnected" id="BaseDevice.isWifiApConnected" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.isWifiApConnected" /> <keyword name="BaseDevice.isWifiClientConnected" id="BaseDevice.isWifiClientConnected" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.isWifiClientConnected" /> @@ -2288,7 +2290,9 @@ <keyword name="BaseDevice.stopAccessPoint" id="BaseDevice.stopAccessPoint" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.stopAccessPoint" /> <keyword name="BaseDevice.submitMode" id="BaseDevice.submitMode" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.submitMode" /> <keyword name="BaseDevice.supportsDeviceScan" id="BaseDevice.supportsDeviceScan" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.supportsDeviceScan" /> + <keyword name="BaseDevice.supportsDirectories" id="BaseDevice.supportsDirectories" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.supportsDirectories" /> <keyword name="BaseDevice.supportsLocalFileAccess" id="BaseDevice.supportsLocalFileAccess" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.supportsLocalFileAccess" /> + <keyword name="BaseDevice.supportsRenameFiles" id="BaseDevice.supportsRenameFiles" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.supportsRenameFiles" /> <keyword name="BaseDevice.syncTime" id="BaseDevice.syncTime" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.syncTime" /> <keyword name="BaseDevice.upipInstall" id="BaseDevice.upipInstall" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.upipInstall" /> <keyword name="BaseDevice.writeCredentials" id="BaseDevice.writeCredentials" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.writeCredentials" /> @@ -11865,6 +11869,7 @@ <keyword name="MicrobitDevice.__resetDevice" id="MicrobitDevice.__resetDevice" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__resetDevice" /> <keyword name="MicrobitDevice.__saveMain" id="MicrobitDevice.__saveMain" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__saveMain" /> <keyword name="MicrobitDevice.__showFirmwareVersions" id="MicrobitDevice.__showFirmwareVersions" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__showFirmwareVersions" /> + <keyword name="MicrobitDevice._boardInformationCommands" id="MicrobitDevice._boardInformationCommands" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice._boardInformationCommands" /> <keyword name="MicrobitDevice._getSetTimeCode" id="MicrobitDevice._getSetTimeCode" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice._getSetTimeCode" /> <keyword name="MicrobitDevice.activateBluetoothInterface" id="MicrobitDevice.activateBluetoothInterface" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.activateBluetoothInterface" /> <keyword name="MicrobitDevice.addDeviceMenuEntries" id="MicrobitDevice.addDeviceMenuEntries" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.addDeviceMenuEntries" /> @@ -11877,15 +11882,19 @@ <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.getData" id="MicrobitDevice.getData" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getData" /> <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" /> <keyword name="MicrobitDevice.hasBluetooth" id="MicrobitDevice.hasBluetooth" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.hasBluetooth" /> <keyword name="MicrobitDevice.hasFlashMenuEntry" id="MicrobitDevice.hasFlashMenuEntry" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.hasFlashMenuEntry" /> <keyword name="MicrobitDevice.hasTimeCommands" id="MicrobitDevice.hasTimeCommands" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.hasTimeCommands" /> + <keyword name="MicrobitDevice.isMicrobit" id="MicrobitDevice.isMicrobit" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.isMicrobit" /> <keyword name="MicrobitDevice.lls" id="MicrobitDevice.lls" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.lls" /> <keyword name="MicrobitDevice.ls" id="MicrobitDevice.ls" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.ls" /> + <keyword name="MicrobitDevice.putData" id="MicrobitDevice.putData" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.putData" /> <keyword name="MicrobitDevice.pwd" id="MicrobitDevice.pwd" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.pwd" /> + <keyword name="MicrobitDevice.rm" id="MicrobitDevice.rm" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.rm" /> <keyword name="MicrobitDevice.runScript" id="MicrobitDevice.runScript" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.runScript" /> <keyword name="MicrobitDevice.setButtons" id="MicrobitDevice.setButtons" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.setButtons" /> <keyword name="MicrobitDevice.setConnected" id="MicrobitDevice.setConnected" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.setConnected" />
--- a/src/eric7/Documentation/Source/eric7.MicroPython.Devices.DeviceBase.html Fri Mar 21 18:12:17 2025 +0100 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.DeviceBase.html Sun Mar 23 14:55:14 2025 +0100 @@ -147,6 +147,10 @@ <td>Private method to get some essential data for the connected board.</td> </tr> <tr> +<td><a href="#BaseDevice._boardInformationCommands">_boardInformationCommands</a></td> +<td>Protected method defining the list of commands to be execute on the board for determining information about the board.</td> +</tr> +<tr> <td><a href="#BaseDevice._getSetTimeCode">_getSetTimeCode</a></td> <td>Protected method to get the device code to set the time.</td> </tr> @@ -391,6 +395,10 @@ <td>Public method to check the LAN connection status.</td> </tr> <tr> +<td><a href="#BaseDevice.isMicrobit">isMicrobit</a></td> +<td>Public method to check, if the device is a BBC micro:bit or Calliope mini.</td> +</tr> +<tr> <td><a href="#BaseDevice.isNetworkConnected">isNetworkConnected</a></td> <td>Public method to check, if the network interface (WiFi or Ethernet) is connected.</td> </tr> @@ -515,10 +523,18 @@ <td>Public method to indicate, that the Bluetooth implementation supports scanning for devices.</td> </tr> <tr> +<td><a href="#BaseDevice.supportsDirectories">supportsDirectories</a></td> +<td>Public method to check, if the device supports directory operations.</td> +</tr> +<tr> <td><a href="#BaseDevice.supportsLocalFileAccess">supportsLocalFileAccess</a></td> <td>Public method to indicate file access via a local directory.</td> </tr> <tr> +<td><a href="#BaseDevice.supportsRenameFiles">supportsRenameFiles</a></td> +<td>Public method to check, if the device supports renaming of files.</td> +</tr> +<tr> <td><a href="#BaseDevice.syncTime">syncTime</a></td> <td>Public method to set the time of the connected device to the local computer's time.</td> </tr> @@ -590,6 +606,26 @@ raised to indicate an issue with the device </dd> </dl> +<a NAME="BaseDevice._boardInformationCommands" ID="BaseDevice._boardInformationCommands"></a> +<h4>BaseDevice._boardInformationCommands</h4> +<b>_boardInformationCommands</b>(<i></i>) +<p> + Protected method defining the list of commands to be execute on the board + for determining information about the board. +</p> + +<dl> +<dt>Return:</dt> +<dd> +list of command strings to be executed +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of str +</dd> +</dl> <a NAME="BaseDevice._getSetTimeCode" ID="BaseDevice._getSetTimeCode"></a> <h4>BaseDevice._getSetTimeCode</h4> <b>_getSetTimeCode</b>(<i></i>) @@ -1917,6 +1953,25 @@ bool </dd> </dl> +<a NAME="BaseDevice.isMicrobit" ID="BaseDevice.isMicrobit"></a> +<h4>BaseDevice.isMicrobit</h4> +<b>isMicrobit</b>(<i></i>) +<p> + Public method to check, if the device is a BBC micro:bit or Calliope mini. +</p> + +<dl> +<dt>Return:</dt> +<dd> +flag indicating a micro:bit device +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> <a NAME="BaseDevice.isNetworkConnected" ID="BaseDevice.isNetworkConnected"></a> <h4>BaseDevice.isNetworkConnected</h4> <b>isNetworkConnected</b>(<i></i>) @@ -2659,6 +2714,25 @@ bool </dd> </dl> +<a NAME="BaseDevice.supportsDirectories" ID="BaseDevice.supportsDirectories"></a> +<h4>BaseDevice.supportsDirectories</h4> +<b>supportsDirectories</b>(<i></i>) +<p> + Public method to check, if the device supports directory operations. +</p> + +<dl> +<dt>Return:</dt> +<dd> +flag indicating directory operations are supported +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> <a NAME="BaseDevice.supportsLocalFileAccess" ID="BaseDevice.supportsLocalFileAccess"></a> <h4>BaseDevice.supportsLocalFileAccess</h4> <b>supportsLocalFileAccess</b>(<i></i>) @@ -2678,6 +2752,25 @@ bool </dd> </dl> +<a NAME="BaseDevice.supportsRenameFiles" ID="BaseDevice.supportsRenameFiles"></a> +<h4>BaseDevice.supportsRenameFiles</h4> +<b>supportsRenameFiles</b>(<i></i>) +<p> + Public method to check, if the device supports renaming of files. +</p> + +<dl> +<dt>Return:</dt> +<dd> +flag indicating renaming of files are supported +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> <a NAME="BaseDevice.syncTime" ID="BaseDevice.syncTime"></a> <h4>BaseDevice.syncTime</h4> <b>syncTime</b>(<i>_deviceType, hasCPy=False</i>)
--- a/src/eric7/Documentation/Source/eric7.MicroPython.Devices.MicrobitDevices.html Fri Mar 21 18:12:17 2025 +0100 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.MicrobitDevices.html Sun Mar 23 14:55:14 2025 +0100 @@ -96,6 +96,10 @@ <td>Private slot to show the firmware version of the connected device and the available firmware version.</td> </tr> <tr> +<td><a href="#MicrobitDevice._boardInformationCommands">_boardInformationCommands</a></td> +<td>Protected method defining the list of commands to be execute on the board for determining information about the board.</td> +</tr> +<tr> <td><a href="#MicrobitDevice._getSetTimeCode">_getSetTimeCode</a></td> <td>Protected method to get the device code to set the time.</td> </tr> @@ -144,6 +148,10 @@ <td>Public method to get some information data of the connected board.</td> </tr> <tr> +<td><a href="#MicrobitDevice.getData">getData</a></td> +<td>Public method to read data from the connected device.</td> +</tr> +<tr> <td><a href="#MicrobitDevice.getDeviceScan">getDeviceScan</a></td> <td>Public method to perform a Bluetooth device scan.</td> </tr> @@ -168,6 +176,10 @@ <td>Public method to check, if the device supports time commands.</td> </tr> <tr> +<td><a href="#MicrobitDevice.isMicrobit">isMicrobit</a></td> +<td>Public method to check, if the device is a BBC micro:bit or Calliope mini.</td> +</tr> +<tr> <td><a href="#MicrobitDevice.lls">lls</a></td> <td>Public method to get a long directory listing of the connected device including meta data.</td> </tr> @@ -176,10 +188,18 @@ <td>Public method to get a directory listing of the connected device.</td> </tr> <tr> +<td><a href="#MicrobitDevice.putData">putData</a></td> +<td>Public method to write the given data to the connected device.</td> +</tr> +<tr> <td><a href="#MicrobitDevice.pwd">pwd</a></td> <td>Public method to get the current directory of the connected device.</td> </tr> <tr> +<td><a href="#MicrobitDevice.rm">rm</a></td> +<td>Public method to remove a file from the connected device.</td> +</tr> +<tr> <td><a href="#MicrobitDevice.runScript">runScript</a></td> <td>Public method to run the given Python script.</td> </tr> @@ -345,6 +365,26 @@ available firmware version. </p> +<a NAME="MicrobitDevice._boardInformationCommands" ID="MicrobitDevice._boardInformationCommands"></a> +<h4>MicrobitDevice._boardInformationCommands</h4> +<b>_boardInformationCommands</b>(<i></i>) +<p> + Protected method defining the list of commands to be execute on the board + for determining information about the board. +</p> + +<dl> +<dt>Return:</dt> +<dd> +list of command strings to be executed +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of str +</dd> +</dl> <a NAME="MicrobitDevice._getSetTimeCode" ID="MicrobitDevice._getSetTimeCode"></a> <h4>MicrobitDevice._getSetTimeCode</h4> <b>_getSetTimeCode</b>(<i></i>) @@ -599,6 +639,32 @@ dict </dd> </dl> +<a NAME="MicrobitDevice.getData" ID="MicrobitDevice.getData"></a> +<h4>MicrobitDevice.getData</h4> +<b>getData</b>(<i>deviceFileName</i>) +<p> + Public method to read data from the connected device. +</p> + +<dl> + +<dt><i>deviceFileName</i> (str)</dt> +<dd> +name of the file to read from +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +data read from the device +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bytes +</dd> +</dl> <a NAME="MicrobitDevice.getDeviceScan" ID="MicrobitDevice.getDeviceScan"></a> <h4>MicrobitDevice.getDeviceScan</h4> <b>getDeviceScan</b>(<i>timeout=10</i>) @@ -733,6 +799,25 @@ bool </dd> </dl> +<a NAME="MicrobitDevice.isMicrobit" ID="MicrobitDevice.isMicrobit"></a> +<h4>MicrobitDevice.isMicrobit</h4> +<b>isMicrobit</b>(<i></i>) +<p> + Public method to check, if the device is a BBC micro:bit or Calliope mini. +</p> + +<dl> +<dt>Return:</dt> +<dd> +flag indicating a micro:bit device +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> <a NAME="MicrobitDevice.lls" ID="MicrobitDevice.lls"></a> <h4>MicrobitDevice.lls</h4> <b>lls</b>(<i>dirname="", fullstat=False, showHidden=False</i>) @@ -811,6 +896,36 @@ raised to indicate an issue with the device </dd> </dl> +<a NAME="MicrobitDevice.putData" ID="MicrobitDevice.putData"></a> +<h4>MicrobitDevice.putData</h4> +<b>putData</b>(<i>deviceFileName, content</i>) +<p> + Public method to write the given data to the connected device. +</p> + +<dl> + +<dt><i>deviceFileName</i> (str)</dt> +<dd> +name of the file to write to +</dd> +<dt><i>content</i> (bytes)</dt> +<dd> +data to write +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +flag indicating success +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> <a NAME="MicrobitDevice.pwd" ID="MicrobitDevice.pwd"></a> <h4>MicrobitDevice.pwd</h4> <b>pwd</b>(<i></i>) @@ -830,6 +945,20 @@ str </dd> </dl> +<a NAME="MicrobitDevice.rm" ID="MicrobitDevice.rm"></a> +<h4>MicrobitDevice.rm</h4> +<b>rm</b>(<i>filename</i>) +<p> + Public method to remove a file from the connected device. +</p> + +<dl> + +<dt><i>filename</i> (str)</dt> +<dd> +name of the file to be removed +</dd> +</dl> <a NAME="MicrobitDevice.runScript" ID="MicrobitDevice.runScript"></a> <h4>MicrobitDevice.runScript</h4> <b>runScript</b>(<i>script</i>)
--- a/src/eric7/Documentation/Source/eric7.MicroPython.MicroPythonFileManagerWidget.html Fri Mar 21 18:12:17 2025 +0100 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.MicroPythonFileManagerWidget.html Sun Mar 23 14:55:14 2025 +0100 @@ -542,13 +542,17 @@ </dl> <a NAME="MicroPythonFileManagerWidget.__handleLongListFiles" ID="MicroPythonFileManagerWidget.__handleLongListFiles"></a> <h4>MicroPythonFileManagerWidget.__handleLongListFiles</h4> -<b>__handleLongListFiles</b>(<i>filesList</i>) +<b>__handleLongListFiles</b>(<i>dirname, filesList</i>) <p> Private slot to receive a long directory listing. </p> <dl> +<dt><i>dirname</i> (str)</dt> +<dd> +name of the directory the list of files belongs to +</dd> <dt><i>filesList</i> (tuple of (str, str, str, str))</dt> <dd> tuple containing tuples with name, mode, size and time
--- a/src/eric7/MicroPython/Devices/DeviceBase.py Fri Mar 21 18:12:17 2025 +0100 +++ b/src/eric7/MicroPython/Devices/DeviceBase.py Sun Mar 23 14:55:14 2025 +0100 @@ -550,10 +550,55 @@ return self.tr("Detected an error without indications.") + 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 + """ + return False + ################################################################## ## Methods below implement the file system commands ################################################################## + def supportsDirectories(self): + """ + Public method to check, if the device supports directory operations. + + @return flag indicating directory operations are supported + @rtype bool + """ + command = """ +import os as __os_ +print('getcwd' in dir(__os_)) +del __os_ +""" + out, err = self.executeCommands(command, mode=self._submitMode) + if err: + return False + + return out.strip() == b"True" + + def supportsRenameFiles(self): + """ + Public method to check, if the device supports renaming of files. + + @return flag indicating renaming of files are supported + @rtype bool + """ + command = """ +import os as __os_ +print('getcwd' in dir(__os_)) +del __os_ +""" + out, err = self.executeCommands(command, mode=self._submitMode) + if err: + return False + + return out.strip() == b"True" + def exists(self, pathname): """ Public method to check the existence of a file or directory. @@ -879,6 +924,7 @@ @rtype bool @exception OSError raised to indicate an issue with the device """ + # TODO: micro:bit with old MPy does not support leading '/' if not deviceFileName: raise OSError("Missing device file name") @@ -941,6 +987,7 @@ @rtype bytes @exception OSError raised to indicate an issue with the device """ + # TODO: micro:bit with old MPy does not support leading '/' if not deviceFileName: raise OSError("Missing device file name") @@ -1164,7 +1211,7 @@ print(get_device_data()) del get_device_data -""" +""", ] res = {} for command in commands: @@ -1174,15 +1221,36 @@ res.update(ast.literal_eval(out.decode("utf-8"))) return res - def getBoardInformation(self): + def _boardInformationCommands(self): """ - Public method to get some information data of the connected board. + 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 + """ + return [ # needs to be splitted for boards with low memory + """def get_board_info(): + res = {} - @return dictionary containing the determined data - @rtype dict - @exception OSError raised to indicate an issue with the device - """ - commands = [ # needs to be splitted for boards with low memory + 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 = {} @@ -1246,6 +1314,53 @@ 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 + if isinstance(mc.freq(), tuple): + res['mc_frequency_mhz'] = mc.freq()[0] / 1000000.0 + else: + res['mc_frequency_mhz'] = mc.freq() / 1000000.0 + 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'] = None + res['mc_temp'] = 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: @@ -1258,123 +1373,22 @@ """, ] - 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 -""" + def getBoardInformation(self): + """ + Public method to get some information data of the connected board. - machine_command = """def get_board_info(): - res = {} + @return dictionary containing the determined data + @rtype dict + @exception OSError raised to indicate an issue with the device + """ + 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: + for command in self._boardInformationCommands(): 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 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
--- a/src/eric7/MicroPython/MicroPythonFileManager.py Fri Mar 21 18:12:17 2025 +0100 +++ b/src/eric7/MicroPython/MicroPythonFileManager.py Sun Mar 23 14:55:14 2025 +0100 @@ -53,7 +53,7 @@ during the most recent operation """ - longListFiles = pyqtSignal(tuple) + longListFiles = pyqtSignal(str, tuple) currentDir = pyqtSignal(str) currentDirChanged = pyqtSignal(str) getFileDone = pyqtSignal(str, str) @@ -126,7 +126,7 @@ ) for name, (mode, size, mtime) in filesList ] - self.longListFiles.emit(tuple(result)) + self.longListFiles.emit(dirname, tuple(result)) except Exception as exc: self.error.emit("lls", str(exc))
--- a/src/eric7/MicroPython/MicroPythonFileManagerWidget.py Fri Mar 21 18:12:17 2025 +0100 +++ b/src/eric7/MicroPython/MicroPythonFileManagerWidget.py Sun Mar 23 14:55:14 2025 +0100 @@ -181,9 +181,12 @@ self.__openDeviceFileAct = self.__deviceMenu.addAction( self.tr("Open File"), self.__openDeviceFile ) - self.__devRenameFileAct = self.__deviceMenu.addAction( - self.tr("Rename File"), self.__renameDeviceFile - ) + if not isMicrobitDeviceWithMPy: + self.__devRenameFileAct = self.__deviceMenu.addAction( + self.tr("Rename File"), self.__renameDeviceFile + ) + else: + self.__devRenameFileAct = None self.__devDelFileAct = self.__deviceMenu.addAction( self.tr("Delete File"), self.__deleteDeviceFile ) @@ -301,17 +304,19 @@ return None - @pyqtSlot(tuple) - def __handleLongListFiles(self, filesList): + @pyqtSlot(str, tuple) + def __handleLongListFiles(self, dirname, filesList): """ Private slot to receive a long directory listing. + @param dirname name of the directory the list of files belongs to + @type str @param filesList tuple containing tuples with name, mode, size and time for each directory entry @type tuple of (str, str, str, str) """ if filesList: - dirPath = os.path.dirname(filesList[0][-1]) + dirPath = dirname dirItem = ( self.__findDirectoryItem(dirPath, self.deviceFileTreeWidget) if dirPath != self.deviceCwd.text() @@ -336,7 +341,8 @@ QTreeWidgetItem.ChildIndicatorPolicy.ShowIndicator ) else: - self.deviceFileTreeWidget.clear() + if dirname == self.deviceCwd.text(): + self.deviceFileTreeWidget.clear() self.deviceFileTreeWidget.header().resizeSections( QHeaderView.ResizeMode.ResizeToContents @@ -1380,7 +1386,7 @@ if not self.__repl.isMicrobit(): self.__devDelDirAct.setEnabled(isDir) self.__devDelDirTreeAct.setEnabled(isDir) - self.__devRenameFileAct.setEnabled(isFile) + self.__devRenameFileAct.setEnabled(isFile) self.__devDelFileAct.setEnabled(isFile) self.__openDeviceFileAct.setEnabled(isFile)
--- a/src/eric7/MicroPython/MicroPythonWidget.py Fri Mar 21 18:12:17 2025 +0100 +++ b/src/eric7/MicroPython/MicroPythonWidget.py Sun Mar 23 14:55:14 2025 +0100 @@ -382,17 +382,7 @@ @return flag indicating a micro:bit device @rtype bool """ - if ( - self.__device - and ( - "micro:bit" in self.__device.deviceName() - or "Calliope" in self.__device.deviceName() - ) - and not self.__device.hasCircuitPython() - ): - return True - - return False + return self.__device and self.__device.isMicrobit() @pyqtSlot(int) def on_deviceTypeComboBox_activated(self, index):