diff -r 189b7a23c3c6 -r 39daf45010c8 src/eric7/MicroPython/Devices/GenericMicroPythonDevices.py --- a/src/eric7/MicroPython/Devices/GenericMicroPythonDevices.py Thu Mar 16 09:20:00 2023 +0100 +++ b/src/eric7/MicroPython/Devices/GenericMicroPythonDevices.py Thu Mar 16 12:03:23 2023 +0100 @@ -10,12 +10,18 @@ import os -from eric7 import Preferences +from PyQt6.QtCore import QUrl, pyqtSlot +from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest +from PyQt6.QtWidgets import QMenu + +from eric7 import Globals, Preferences from eric7.EricWidgets import EricMessageBox +from eric7.EricWidgets.EricApplication import ericApp from eric7.SystemUtilities import FileSystemUtilities +from ..MicroPythonWidget import HAS_QTCHART +from . import FirmwareGithubUrls from .DeviceBase import BaseDevice -from .MicroPythonWidget import HAS_QTCHART class GenericMicroPythonDevice(BaseDevice): @@ -40,6 +46,8 @@ """ super().__init__(microPythonWidget, deviceType, parent) + self.__createGenericMenu() + self.__directAccess = False self.__deviceVolumeName = "" self.__workspace = "" @@ -123,6 +131,39 @@ """ return True, "" + def __createGenericMenu(self): + """ + Private method to create the Generic submenu. + """ + self.__genericMenu = QMenu(self.tr("Generic Device Functions")) + + self.__showMpyAct = self.__genericMenu.addAction( + self.tr("Show MicroPython Versions"), self.__showFirmwareVersions + ) + self.__genericMenu.addSeparator() + self.__bootloaderAct = self.__genericMenu.addAction( + self.tr("Activate Bootloader"), self.__activateBootloader + ) + self.__genericMenu.addSeparator() + self.__resetAct = self.__genericMenu.addAction( + self.tr("Reset Device"), self.__resetDevice + ) + + def addDeviceMenuEntries(self, menu): + """ + Public method to add device specific entries to the given menu. + + @param menu reference to the context menu + @type QMenu + """ + connected = self.microPython.isConnected() + + self.__showMpyAct.setEnabled(connected) + self.__bootloaderAct.setEnabled(connected) + self.__resetAct.setEnabled(connected) + + menu.addMenu(self.__genericMenu) + def supportsLocalFileAccess(self): """ Public method to indicate file access via a local directory. @@ -202,6 +243,156 @@ return super().getWorkspace() + @pyqtSlot() + def __activateBootloader(self): + """ + Private slot to switch the board into 'bootloader' mode. + """ + if self.microPython.isConnected(): + self.microPython.deviceInterface().execute( + "import machine\nmachine.bootloader()\n", mode=self._submitMode + ) + # simulate pressing the disconnect button + self.microPython.on_connectButton_clicked() + + @pyqtSlot() + def __showFirmwareVersions(self): + """ + Private slot to show the firmware version of the connected device and the + available firmware version. + """ + if self.microPython.isConnected(): + if self._deviceData["mpy_name"] != "micropython": + EricMessageBox.critical( + None, + self.tr("Show MicroPython Versions"), + self.tr( + """The firmware of the connected device cannot be""" + """ determined or the board does not run MicroPython.""" + """ Aborting...""" + ), + ) + else: + ui = ericApp().getObject("UserInterface") + request = QNetworkRequest(QUrl(FirmwareGithubUrls["micropython"])) + reply = ui.networkAccessManager().head(request) + reply.finished.connect(lambda: self.__firmwareVersionResponse(reply)) + + @pyqtSlot(QNetworkReply) + def __firmwareVersionResponse(self, reply): + """ + Private slot handling the response of the latest version request. + + @param reply reference to the reply object + @type QNetworkReply + """ + latestUrl = reply.url().toString() + tag = latestUrl.rsplit("/", 1)[-1] + while tag and not tag[0].isdecimal(): + # get rid of leading non-decimal characters + tag = tag[1:] + latestVersion = Globals.versionToTuple(tag) + + if self._deviceData["mpy_version"] == "unknown": + currentVersionStr = self.tr("unknown") + currentVersion = (0, 0, 0) + else: + currentVersionStr = ( + self._deviceData["mpy_variant_version"] + if bool(self._deviceData["mpy_variant_version"]) + else self._deviceData["mpy_version"] + ) + currentVersion = Globals.versionToTuple(currentVersionStr) + + msg = self.tr( + "<h4>MicroPython Version Information</h4>" + "<table>" + "<tr><td>Installed:</td><td>{0}</td></tr>" + "<tr><td>Available:</td><td>{1}</td></tr>" + "{2}" + "</table>" + ).format( + currentVersionStr, + tag, + self.tr("<tr><td>Variant:</td><td>{0}</td></tr>").format( + self._deviceData["mpy_variant"] + ) + if self._deviceData["mpy_variant"] + else "", + ) + if currentVersion < latestVersion: + msg += self.tr("<p><b>Update available!</b></p>") + + EricMessageBox.information( + None, + self.tr("MicroPython Version"), + msg, + ) + + @pyqtSlot() + def __resetDevice(self): + """ + Private slot to reset the connected device. + """ + self.microPython.deviceInterface().execute( + "import machine\nmachine.reset()\n", mode=self._submitMode + ) + # simulate pressing the disconnect button + self.microPython.on_connectButton_clicked() + + def getDocumentationUrl(self): + """ + Public method to get the device documentation URL. + + @return documentation URL of the device + @rtype str + """ + return Preferences.getMicroPython("MicroPythonDocuUrl") + + def getFirmwareUrl(self): + """ + Public method to get the device firmware download URL. + + @return firmware download URL of the device + @rtype str + """ + return Preferences.getMicroPython("MicroPythonFirmwareUrl") + + ################################################################## + ## time related methods below + ################################################################## + + def _getSetTimeCode(self): + """ + Protected method to get the device code to set the time. + + Note: This method must be implemented in the various device specific + subclasses. + + @return code to be executed on the connected device to set the time + @rtype str + """ + # rtc_time[0] - year 4 digit + # rtc_time[1] - month 1..12 + # rtc_time[2] - day 1..31 + # rtc_time[3] - weekday 1..7 1=Monday + # rtc_time[4] - hour 0..23 + # rtc_time[5] - minute 0..59 + # rtc_time[6] - second 0..59 + # rtc_time[7] - yearday 1..366 + # rtc_time[8] - isdst 0, 1, or -1 + # + # https://docs.micropython.org/en/latest/library/machine.RTC.html#machine-rtc + return """ +def set_time(rtc_time): + try: + import machine + rtc = machine.RTC() + rtc.datetime(rtc_time[:7] + (0,)) + except Exception: + pass +""" + def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber): """