src/eric7/MicroPython/Devices/GenericMicroPythonDevices.py

branch
eric7
changeset 9906
39daf45010c8
parent 9763
52f982c08301
child 9989
286c2a21f36f
equal deleted inserted replaced
9905:189b7a23c3c6 9906:39daf45010c8
8 (i.e. those devices not specifically supported yet). 8 (i.e. those devices not specifically supported yet).
9 """ 9 """
10 10
11 import os 11 import os
12 12
13 from eric7 import Preferences 13 from PyQt6.QtCore import QUrl, pyqtSlot
14 from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest
15 from PyQt6.QtWidgets import QMenu
16
17 from eric7 import Globals, Preferences
14 from eric7.EricWidgets import EricMessageBox 18 from eric7.EricWidgets import EricMessageBox
19 from eric7.EricWidgets.EricApplication import ericApp
15 from eric7.SystemUtilities import FileSystemUtilities 20 from eric7.SystemUtilities import FileSystemUtilities
16 21
22 from ..MicroPythonWidget import HAS_QTCHART
23 from . import FirmwareGithubUrls
17 from .DeviceBase import BaseDevice 24 from .DeviceBase import BaseDevice
18 from .MicroPythonWidget import HAS_QTCHART
19 25
20 26
21 class GenericMicroPythonDevice(BaseDevice): 27 class GenericMicroPythonDevice(BaseDevice):
22 """ 28 """
23 Class implementing the device interface for generic MicroPython boards. 29 Class implementing the device interface for generic MicroPython boards.
38 @param parent reference to the parent object 44 @param parent reference to the parent object
39 @type QObject 45 @type QObject
40 """ 46 """
41 super().__init__(microPythonWidget, deviceType, parent) 47 super().__init__(microPythonWidget, deviceType, parent)
42 48
49 self.__createGenericMenu()
50
43 self.__directAccess = False 51 self.__directAccess = False
44 self.__deviceVolumeName = "" 52 self.__deviceVolumeName = ""
45 self.__workspace = "" 53 self.__workspace = ""
46 self.__deviceName = "" 54 self.__deviceName = ""
47 55
120 @return tuple containing a flag indicating it is safe to start a 128 @return tuple containing a flag indicating it is safe to start a
121 File Manager and a reason why it cannot. 129 File Manager and a reason why it cannot.
122 @rtype tuple of (bool, str) 130 @rtype tuple of (bool, str)
123 """ 131 """
124 return True, "" 132 return True, ""
133
134 def __createGenericMenu(self):
135 """
136 Private method to create the Generic submenu.
137 """
138 self.__genericMenu = QMenu(self.tr("Generic Device Functions"))
139
140 self.__showMpyAct = self.__genericMenu.addAction(
141 self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
142 )
143 self.__genericMenu.addSeparator()
144 self.__bootloaderAct = self.__genericMenu.addAction(
145 self.tr("Activate Bootloader"), self.__activateBootloader
146 )
147 self.__genericMenu.addSeparator()
148 self.__resetAct = self.__genericMenu.addAction(
149 self.tr("Reset Device"), self.__resetDevice
150 )
151
152 def addDeviceMenuEntries(self, menu):
153 """
154 Public method to add device specific entries to the given menu.
155
156 @param menu reference to the context menu
157 @type QMenu
158 """
159 connected = self.microPython.isConnected()
160
161 self.__showMpyAct.setEnabled(connected)
162 self.__bootloaderAct.setEnabled(connected)
163 self.__resetAct.setEnabled(connected)
164
165 menu.addMenu(self.__genericMenu)
125 166
126 def supportsLocalFileAccess(self): 167 def supportsLocalFileAccess(self):
127 """ 168 """
128 Public method to indicate file access via a local directory. 169 Public method to indicate file access via a local directory.
129 170
200 ).format(self.__deviceVolumeName), 241 ).format(self.__deviceVolumeName),
201 ) 242 )
202 243
203 return super().getWorkspace() 244 return super().getWorkspace()
204 245
246 @pyqtSlot()
247 def __activateBootloader(self):
248 """
249 Private slot to switch the board into 'bootloader' mode.
250 """
251 if self.microPython.isConnected():
252 self.microPython.deviceInterface().execute(
253 "import machine\nmachine.bootloader()\n", mode=self._submitMode
254 )
255 # simulate pressing the disconnect button
256 self.microPython.on_connectButton_clicked()
257
258 @pyqtSlot()
259 def __showFirmwareVersions(self):
260 """
261 Private slot to show the firmware version of the connected device and the
262 available firmware version.
263 """
264 if self.microPython.isConnected():
265 if self._deviceData["mpy_name"] != "micropython":
266 EricMessageBox.critical(
267 None,
268 self.tr("Show MicroPython Versions"),
269 self.tr(
270 """The firmware of the connected device cannot be"""
271 """ determined or the board does not run MicroPython."""
272 """ Aborting..."""
273 ),
274 )
275 else:
276 ui = ericApp().getObject("UserInterface")
277 request = QNetworkRequest(QUrl(FirmwareGithubUrls["micropython"]))
278 reply = ui.networkAccessManager().head(request)
279 reply.finished.connect(lambda: self.__firmwareVersionResponse(reply))
280
281 @pyqtSlot(QNetworkReply)
282 def __firmwareVersionResponse(self, reply):
283 """
284 Private slot handling the response of the latest version request.
285
286 @param reply reference to the reply object
287 @type QNetworkReply
288 """
289 latestUrl = reply.url().toString()
290 tag = latestUrl.rsplit("/", 1)[-1]
291 while tag and not tag[0].isdecimal():
292 # get rid of leading non-decimal characters
293 tag = tag[1:]
294 latestVersion = Globals.versionToTuple(tag)
295
296 if self._deviceData["mpy_version"] == "unknown":
297 currentVersionStr = self.tr("unknown")
298 currentVersion = (0, 0, 0)
299 else:
300 currentVersionStr = (
301 self._deviceData["mpy_variant_version"]
302 if bool(self._deviceData["mpy_variant_version"])
303 else self._deviceData["mpy_version"]
304 )
305 currentVersion = Globals.versionToTuple(currentVersionStr)
306
307 msg = self.tr(
308 "<h4>MicroPython Version Information</h4>"
309 "<table>"
310 "<tr><td>Installed:</td><td>{0}</td></tr>"
311 "<tr><td>Available:</td><td>{1}</td></tr>"
312 "{2}"
313 "</table>"
314 ).format(
315 currentVersionStr,
316 tag,
317 self.tr("<tr><td>Variant:</td><td>{0}</td></tr>").format(
318 self._deviceData["mpy_variant"]
319 )
320 if self._deviceData["mpy_variant"]
321 else "",
322 )
323 if currentVersion < latestVersion:
324 msg += self.tr("<p><b>Update available!</b></p>")
325
326 EricMessageBox.information(
327 None,
328 self.tr("MicroPython Version"),
329 msg,
330 )
331
332 @pyqtSlot()
333 def __resetDevice(self):
334 """
335 Private slot to reset the connected device.
336 """
337 self.microPython.deviceInterface().execute(
338 "import machine\nmachine.reset()\n", mode=self._submitMode
339 )
340 # simulate pressing the disconnect button
341 self.microPython.on_connectButton_clicked()
342
343 def getDocumentationUrl(self):
344 """
345 Public method to get the device documentation URL.
346
347 @return documentation URL of the device
348 @rtype str
349 """
350 return Preferences.getMicroPython("MicroPythonDocuUrl")
351
352 def getFirmwareUrl(self):
353 """
354 Public method to get the device firmware download URL.
355
356 @return firmware download URL of the device
357 @rtype str
358 """
359 return Preferences.getMicroPython("MicroPythonFirmwareUrl")
360
361 ##################################################################
362 ## time related methods below
363 ##################################################################
364
365 def _getSetTimeCode(self):
366 """
367 Protected method to get the device code to set the time.
368
369 Note: This method must be implemented in the various device specific
370 subclasses.
371
372 @return code to be executed on the connected device to set the time
373 @rtype str
374 """
375 # rtc_time[0] - year 4 digit
376 # rtc_time[1] - month 1..12
377 # rtc_time[2] - day 1..31
378 # rtc_time[3] - weekday 1..7 1=Monday
379 # rtc_time[4] - hour 0..23
380 # rtc_time[5] - minute 0..59
381 # rtc_time[6] - second 0..59
382 # rtc_time[7] - yearday 1..366
383 # rtc_time[8] - isdst 0, 1, or -1
384 #
385 # https://docs.micropython.org/en/latest/library/machine.RTC.html#machine-rtc
386 return """
387 def set_time(rtc_time):
388 try:
389 import machine
390 rtc = machine.RTC()
391 rtc.datetime(rtc_time[:7] + (0,))
392 except Exception:
393 pass
394 """
395
205 396
206 def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber): 397 def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
207 """ 398 """
208 Function to instantiate a MicroPython device object. 399 Function to instantiate a MicroPython device object.
209 400

eric ide

mercurial