src/eric7/MicroPython/MicrobitDevices.py

branch
eric7
changeset 9749
5d409223cf3f
parent 9738
4ae976ee5339
child 9750
4958dd72c937
equal deleted inserted replaced
9748:df9520c864f2 9749:5d409223cf3f
9 """ 9 """
10 10
11 import os 11 import os
12 import shutil 12 import shutil
13 13
14 from PyQt6.QtCore import QStandardPaths, pyqtSlot 14 from PyQt6.QtCore import QStandardPaths, QUrl, pyqtSlot
15 from PyQt6.QtNetwork import QNetworkRequest
15 from PyQt6.QtWidgets import QInputDialog, QLineEdit 16 from PyQt6.QtWidgets import QInputDialog, QLineEdit
16 17
17 from eric7 import Preferences 18 from eric7 import Globals, Preferences
18 from eric7.EricWidgets import EricFileDialog, EricMessageBox 19 from eric7.EricWidgets import EricFileDialog, EricMessageBox
19 from eric7.EricWidgets.EricApplication import ericApp 20 from eric7.EricWidgets.EricApplication import ericApp
20 from eric7.SystemUtilities import FileSystemUtilities 21 from eric7.SystemUtilities import FileSystemUtilities
21 22
22 from .MicroPythonDevices import MicroPythonDevice 23 from .MicroPythonDevices import FirmwareGithubUrls, MicroPythonDevice
23 from .MicroPythonWidget import HAS_QTCHART 24 from .MicroPythonWidget import HAS_QTCHART
24 25
25 26
26 class MicrobitDevice(MicroPythonDevice): 27 class MicrobitDevice(MicroPythonDevice):
27 """ 28 """
141 142
142 @param menu reference to the context menu 143 @param menu reference to the context menu
143 @type QMenu 144 @type QMenu
144 """ 145 """
145 connected = self.microPython.isConnected() 146 connected = self.microPython.isConnected()
146 147 linkConnected = self.microPython.isLinkConnected()
147 act = menu.addAction(self.tr("Flash MicroPython"), self.__flashMicroPython) 148
148 act.setEnabled(not connected) 149 menu.addAction(
149 act = menu.addAction( 150 self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
151 ).setEnabled(connected and self.getDeviceType() != "calliope")
152 menu.addAction(
153 self.tr("Flash MicroPython"), self.__flashMicroPython
154 ).setEnabled(not linkConnected)
155 menu.addAction(
150 self.tr("Flash Firmware"), lambda: self.__flashMicroPython(firmware=True) 156 self.tr("Flash Firmware"), lambda: self.__flashMicroPython(firmware=True)
151 ) 157 ).setEnabled(not linkConnected)
152 act.setEnabled(not connected)
153 menu.addSeparator() 158 menu.addSeparator()
154 act = menu.addAction(self.tr("Save Script"), self.__saveScriptToDevice) 159 act = menu.addAction(self.tr("Save Script"), self.__saveScriptToDevice)
155 act.setToolTip(self.tr("Save the current script to the selected device")) 160 act.setToolTip(self.tr("Save the current script to the selected device"))
156 act.setEnabled(connected) 161 act.setEnabled(connected)
157 act = menu.addAction(self.tr("Save Script as 'main.py'"), self.__saveMain) 162 act = menu.addAction(self.tr("Save Script as 'main.py'"), self.__saveMain)
158 act.setToolTip( 163 act.setToolTip(
159 self.tr("Save the current script as 'main.py' on the connected device") 164 self.tr("Save the current script as 'main.py' on the connected device")
160 ) 165 )
161 act.setEnabled(connected) 166 act.setEnabled(connected)
162 menu.addSeparator() 167 menu.addSeparator()
163 act = menu.addAction( 168 menu.addAction(
164 self.tr("Reset {0}").format(self.deviceName()), self.__resetDevice 169 self.tr("Reset {0}").format(self.deviceName()), self.__resetDevice
165 ) 170 ).setEnabled(connected)
166 act.setEnabled(connected)
167 171
168 def hasFlashMenuEntry(self): 172 def hasFlashMenuEntry(self):
169 """ 173 """
170 Public method to check, if the device has its own flash menu entry. 174 Public method to check, if the device has its own flash menu entry.
171 175
215 "<p>The BBC micro:bit is not ready for flashing" 219 "<p>The BBC micro:bit is not ready for flashing"
216 " the DAPLink firmware. Follow these" 220 " the DAPLink firmware. Follow these"
217 " instructions. </p>" 221 " instructions. </p>"
218 "<ul>" 222 "<ul>"
219 "<li>unplug USB cable and any batteries</li>" 223 "<li>unplug USB cable and any batteries</li>"
220 "<li>keep RESET button pressed an plug USB cable" 224 "<li>keep RESET button pressed and plug USB cable"
221 " back in</li>" 225 " back in</li>"
222 "<li>a drive called MAINTENANCE should be" 226 "<li>a drive called MAINTENANCE should be"
223 " available</li>" 227 " available</li>"
224 "</ul>" 228 "</ul>"
225 "<p>See the " 229 "<p>See the "
289 " Please make sure, that only one device is prepared." 293 " Please make sure, that only one device is prepared."
290 ), 294 ),
291 ) 295 )
292 296
293 @pyqtSlot() 297 @pyqtSlot()
298 def __showFirmwareVersions(self):
299 """
300 Private slot to show the firmware version of the connected device and the
301 available firmware version.
302 """
303 if self.microPython.isConnected():
304 interface = self.microPython.commandsInterface()
305 if interface is not None:
306 impInfo = interface.getImplementation()
307 versionInfo = interface.version()
308 if impInfo["name"] != "micropython":
309 EricMessageBox.critical(
310 None,
311 self.tr("Show MicroPython Versions"),
312 self.tr(
313 """The firmware of the connected device cannot be"""
314 """ determined or the board does not run MicroPython."""
315 """ Aborting..."""
316 ),
317 )
318 else:
319 impInfo["version"] = versionInfo["release"]
320 if self.getDeviceType() == "bbc_microbit":
321 if "nRF51822" in versionInfo["machine"]:
322 url = QUrl(FirmwareGithubUrls["microbit_v1"])
323 elif "nRF52833" in versionInfo["machine"]:
324 url = QUrl(FirmwareGithubUrls["microbit_v2"])
325 else:
326 EricMessageBox.critical(
327 None,
328 self.tr("Show MicroPython Versions"),
329 self.tr(
330 """<p>The BBC micro:bit generation cannot be"""
331 """ determined. Aborting...</p>"""
332 ),
333 )
334 return
335 else:
336 EricMessageBox.critical(
337 None,
338 self.tr("Show MicroPython Versions"),
339 self.tr(
340 """<p>The firmware URL for the device type <b>{0}</b>"""
341 """ is not known. Aborting...</p>"""
342 ).format(self.getDeviceType()),
343 )
344 return
345
346 ui = ericApp().getObject("UserInterface")
347 request = QNetworkRequest(url)
348 reply = ui.networkAccessManager().head(request)
349 reply.finished.connect(
350 lambda: self.__firmwareVersionResponse(reply, impInfo)
351 )
352
353 def __firmwareVersionResponse(self, reply, implementation):
354 """
355 Private method handling the response of the latest version request.
356
357 @param reply reference to the reply object
358 @type QNetworkReply
359 @param implementation dictionary containing the implementation data of the
360 connected device
361 @type dict
362 """
363 latestUrl = reply.url().toString()
364 tag = latestUrl.rsplit("/", 1)[-1]
365 while tag and not tag[0].isdecimal():
366 # get rid of leading non-decimal characters
367 tag = tag[1:]
368 latestVersion = Globals.versionToTuple(tag)
369
370 if implementation["version"] == "unknown":
371 currentVersionStr = self.tr("unknown")
372 currentVersion = (0, 0, 0)
373 else:
374 currentVersionStr = implementation["version"]
375 currentVersion = Globals.versionToTuple(currentVersionStr)
376
377 msg = self.tr(
378 "<h4>MicroPython Version Information<br/>"
379 "(BBC micro:bit v{2})</h4>"
380 "<table>"
381 "<tr><td>Installed:</td><td>{0}</td></tr>"
382 "<tr><td>Available:</td><td>{1}</td></tr>"
383 "</table>"
384 ).format(currentVersionStr, tag, currentVersionStr[0])
385 if currentVersion < latestVersion:
386 msg += self.tr("<p><b>Update available!</b></p>")
387
388 EricMessageBox.information(
389 None,
390 self.tr("MicroPython Version"),
391 msg,
392 )
393
394 @pyqtSlot()
294 def __saveMain(self): 395 def __saveMain(self):
295 """ 396 """
296 Private slot to copy the current script as 'main.py' onto the 397 Private slot to copy the current script as 'main.py' onto the
297 connected device. 398 connected device.
298 """ 399 """

eric ide

mercurial