src/eric7/MicroPython/MicroPythonWidget.py

branch
eric7
changeset 9751
606ac0e26533
parent 9749
5d409223cf3f
child 9752
2b9546c0cbd9
equal deleted inserted replaced
9750:4958dd72c937 9751:606ac0e26533
200 DeviceTypeRole = Qt.ItemDataRole.UserRole 200 DeviceTypeRole = Qt.ItemDataRole.UserRole
201 DeviceBoardRole = Qt.ItemDataRole.UserRole + 1 201 DeviceBoardRole = Qt.ItemDataRole.UserRole + 1
202 DevicePortRole = Qt.ItemDataRole.UserRole + 2 202 DevicePortRole = Qt.ItemDataRole.UserRole + 2
203 DeviceVidRole = Qt.ItemDataRole.UserRole + 3 203 DeviceVidRole = Qt.ItemDataRole.UserRole + 3
204 DevicePidRole = Qt.ItemDataRole.UserRole + 4 204 DevicePidRole = Qt.ItemDataRole.UserRole + 4
205 DeviceSerNoRole = Qt.ItemDataRole.UserRole + 5
205 206
206 dataReceived = pyqtSignal(bytes) 207 dataReceived = pyqtSignal(bytes)
207 208
208 ManualMarker = "<manual>" 209 ManualMarker = "<manual>"
209 210
280 self.__device = None 281 self.__device = None
281 self.__connected = False 282 self.__connected = False
282 self.__linkConnected = False 283 self.__linkConnected = False
283 self.__setConnected(False) 284 self.__setConnected(False)
284 285
286 self.__replBuffer = b""
287
285 if not HAS_QTSERIALPORT: 288 if not HAS_QTSERIALPORT:
286 self.replEdit.setHtml( 289 self.replEdit.setHtml(
287 self.tr( 290 self.tr(
288 "<h3>The QtSerialPort package is not available.<br/>" 291 "<h3>The QtSerialPort package is not available.<br/>"
289 "MicroPython support is deactivated.</h3>" 292 "MicroPython support is deactivated.</h3>"
334 boardName, 337 boardName,
335 description, 338 description,
336 portName, 339 portName,
337 vid, 340 vid,
338 pid, 341 pid,
342 serialNumber,
339 ) in enumerate(sorted(devices), 1): 343 ) in enumerate(sorted(devices), 1):
340 self.deviceTypeComboBox.addItem( 344 self.deviceTypeComboBox.addItem(
341 self.tr( 345 self.tr(
342 "{0} - {1} ({2})", "board name, description, port name" 346 "{0} - {1} ({2})", "board name, description, port name"
343 ).format(boardName, description, portName) 347 ).format(boardName, description, portName)
351 self.deviceTypeComboBox.setItemData( 355 self.deviceTypeComboBox.setItemData(
352 index, portName, self.DevicePortRole 356 index, portName, self.DevicePortRole
353 ) 357 )
354 self.deviceTypeComboBox.setItemData(index, vid, self.DeviceVidRole) 358 self.deviceTypeComboBox.setItemData(index, vid, self.DeviceVidRole)
355 self.deviceTypeComboBox.setItemData(index, pid, self.DevicePidRole) 359 self.deviceTypeComboBox.setItemData(index, pid, self.DevicePidRole)
360 self.deviceTypeComboBox.setItemData(
361 index, serialNumber, self.DeviceSerNoRole
362 )
356 363
357 else: 364 else:
358 supportedMessage = self.tr("No supported devices detected.") 365 supportedMessage = self.tr("No supported devices detected.")
359 366
360 self.__unknownPorts = unknownPorts 367 self.__unknownPorts = unknownPorts
384 # entry is no longer present 391 # entry is no longer present
385 index = 0 392 index = 0
386 if self.__linkConnected: 393 if self.__linkConnected:
387 # we are still connected, so disconnect 394 # we are still connected, so disconnect
388 self.on_connectButton_clicked() 395 self.on_connectButton_clicked()
396 self.__device = None
389 397
390 self.on_deviceTypeComboBox_activated(index) 398 self.on_deviceTypeComboBox_activated(index)
391 self.deviceTypeComboBox.setCurrentIndex(index) 399 self.deviceTypeComboBox.setCurrentIndex(index)
392 400
393 if unknownDevices: 401 if unknownDevices:
498 ) 506 )
499 507
500 boardName = self.deviceTypeComboBox.itemData(index, self.DeviceBoardRole) 508 boardName = self.deviceTypeComboBox.itemData(index, self.DeviceBoardRole)
501 vid = self.deviceTypeComboBox.itemData(index, self.DeviceVidRole) 509 vid = self.deviceTypeComboBox.itemData(index, self.DeviceVidRole)
502 pid = self.deviceTypeComboBox.itemData(index, self.DevicePidRole) 510 pid = self.deviceTypeComboBox.itemData(index, self.DevicePidRole)
511 serNo = self.deviceTypeComboBox.itemData(index, self.DeviceSerNoRole)
503 512
504 if deviceType or (pid is not None and pid is not None): 513 if deviceType or (pid is not None and pid is not None):
505 self.__device = MicroPythonDevices.getDevice( 514 self.__device = MicroPythonDevices.getDevice(
506 deviceType, self, vid, pid, boardName 515 deviceType, self, vid, pid, boardName=boardName, serialNumber=serNo
507 ) 516 )
508 self.__device.setButtons() 517 self.__device.setButtons()
509 518
510 self.connectButton.setEnabled(bool(deviceType)) 519 self.connectButton.setEnabled(bool(deviceType))
520 else:
521 self.__device = None
511 522
512 @pyqtSlot() 523 @pyqtSlot()
513 def on_checkButton_clicked(self): 524 def on_checkButton_clicked(self):
514 """ 525 """
515 Private slot to check for connected devices. 526 Private slot to check for connected devices.
842 charFormat = tc.charFormat() 853 charFormat = tc.charFormat()
843 charFormat.setFontFamilies([self.__font.family()]) 854 charFormat.setFontFamilies([self.__font.family()])
844 charFormat.setFontPointSize(self.__font.pointSize()) 855 charFormat.setFontPointSize(self.__font.pointSize())
845 tc.setCharFormat(charFormat) 856 tc.setCharFormat(charFormat)
846 857
858 # add received data to the buffered one
859 data = self.__replBuffer + data
860
847 index = 0 861 index = 0
848 while index < len(data): 862 while index < len(data):
849 if data[index] == 8: # \b 863 if data[index] == 8: # \b
850 tc.movePosition(QTextCursor.MoveOperation.Left) 864 tc.movePosition(QTextCursor.MoveOperation.Left)
851 self.replEdit.setTextCursor(tc) 865 self.replEdit.setTextCursor(tc)
889 mode=QTextCursor.MoveMode.KeepAnchor, 903 mode=QTextCursor.MoveMode.KeepAnchor,
890 ) 904 )
891 tc.removeSelectedText() 905 tc.removeSelectedText()
892 self.replEdit.setTextCursor(tc) 906 self.replEdit.setTextCursor(tc)
893 elif match.group("count") == "1": 907 elif match.group("count") == "1":
894 # delete to beinning of line 908 # delete to beginning of line
895 tc.movePosition( 909 tc.movePosition(
896 QTextCursor.MoveOperation.StartOfLine, 910 QTextCursor.MoveOperation.StartOfLine,
897 mode=QTextCursor.MoveMode.KeepAnchor, 911 mode=QTextCursor.MoveMode.KeepAnchor,
898 ) 912 )
899 tc.removeSelectedText() 913 tc.removeSelectedText()
907 ) 921 )
908 tc.removeSelectedText() 922 tc.removeSelectedText()
909 self.replEdit.setTextCursor(tc) 923 self.replEdit.setTextCursor(tc)
910 elif action == "m": 924 elif action == "m":
911 self.__setCharFormat(match.group(0)[:-1].split(";"), tc) 925 self.__setCharFormat(match.group(0)[:-1].split(";"), tc)
926 elif (
927 len(data) > index + 1
928 and data[index] == 27
929 and data[index + 1 : index + 4] == b"]0;"
930 ):
931 if b"\x1b\\" in data[index + 4 :]:
932 # 'set window title' command detected: <Esc>]0;...<Esc>\
933 # __IGNORE_WARNING_M891__
934 titleData = data[index + 4 :].split(b"\x1b\\")[0]
935 title = titleData.decode()
936 index += len(titleData) + 5 # one more is done at the end
937 tc.deleteChar()
938 self.replEdit.setTextCursor(tc)
939 self.replEdit.insertPlainText(title)
940 else:
941 # data is incomplete; buffer and stop processing
942 self.__replBuffer = data[index:]
943 return
912 else: 944 else:
913 tc.deleteChar() 945 tc.deleteChar()
914 self.replEdit.setTextCursor(tc) 946 self.replEdit.setTextCursor(tc)
915 self.replEdit.insertPlainText(chr(data[index])) 947 self.replEdit.insertPlainText(chr(data[index]))
916 948
917 index += 1 949 index += 1
918 950
919 self.replEdit.ensureCursorVisible() 951 self.replEdit.ensureCursorVisible()
952 self.__replBuffer = b""
920 953
921 def __setCharFormat(self, formatCodes, textCursor): 954 def __setCharFormat(self, formatCodes, textCursor):
922 """ 955 """
923 Private method setting the current text format of the REPL pane based 956 Private method setting the current text format of the REPL pane based
924 on the passed ANSI codes. 957 on the passed ANSI codes.
1125 return 1158 return
1126 1159
1127 if self.__interface.connectToDevice(port): 1160 if self.__interface.connectToDevice(port):
1128 deviceResponding = self.__interface.probeDevice() 1161 deviceResponding = self.__interface.probeDevice()
1129 self.__setConnected(deviceResponding) 1162 self.__setConnected(deviceResponding)
1163 self.__device.setConnected(deviceResponding)
1130 if deviceResponding: 1164 if deviceResponding:
1131 if ( 1165 if (
1132 Preferences.getMicroPython("SyncTimeAfterConnect") 1166 Preferences.getMicroPython("SyncTimeAfterConnect")
1133 and self.__device.hasTimeCommands() 1167 and self.__device.hasTimeCommands()
1134 ): 1168 ):
1159 1193
1160 def __disconnectFromDevice(self): 1194 def __disconnectFromDevice(self):
1161 """ 1195 """
1162 Private method to disconnect from the device. 1196 Private method to disconnect from the device.
1163 """ 1197 """
1198 self.__device.setConnected(False)
1164 self.__interface.disconnectFromDevice() 1199 self.__interface.disconnectFromDevice()
1165 self.__setConnected(False) 1200 self.__setConnected(False)
1166 1201
1167 @pyqtSlot() 1202 @pyqtSlot()
1168 def on_runButton_clicked(self): 1203 def on_runButton_clicked(self):
1421 downloadMenu = None 1456 downloadMenu = None
1422 1457
1423 # populate the super menu 1458 # populate the super menu
1424 hasTime = self.__device.hasTimeCommands() if self.__device else False 1459 hasTime = self.__device.hasTimeCommands() if self.__device else False
1425 1460
1426 act = self.__superMenu.addAction( 1461 self.__superMenu.addAction(
1427 self.tr("Show Version"), self.__showDeviceVersion 1462 self.tr("Show Version"), self.__showDeviceVersion
1428 ) 1463 ).setEnabled(self.__connected)
1429 act.setEnabled(self.__connected) 1464 self.__superMenu.addAction(
1430 act = self.__superMenu.addAction(
1431 self.tr("Show Implementation"), self.__showImplementation 1465 self.tr("Show Implementation"), self.__showImplementation
1432 ) 1466 ).setEnabled(self.__connected)
1433 act.setEnabled(self.__connected) 1467 self.__superMenu.addAction(
1434 act = self.__superMenu.addAction(
1435 self.tr("Show Board Data"), self.__showBoardInformation 1468 self.tr("Show Board Data"), self.__showBoardInformation
1436 ) 1469 ).setEnabled(self.__connected)
1437 act.setEnabled(self.__connected)
1438 self.__superMenu.addSeparator() 1470 self.__superMenu.addSeparator()
1439 if hasTime: 1471 if hasTime:
1440 act = self.__superMenu.addAction( 1472 self.__superMenu.addAction(
1441 self.tr("Synchronize Time"), self.__synchronizeTime 1473 self.tr("Synchronize Time"), self.__synchronizeTime
1442 ) 1474 ).setEnabled(self.__connected)
1443 act.setEnabled(self.__connected) 1475 self.__superMenu.addAction(
1444 act = self.__superMenu.addAction(
1445 self.tr("Show Device Time"), self.__showDeviceTime 1476 self.tr("Show Device Time"), self.__showDeviceTime
1446 ) 1477 ).setEnabled(self.__connected)
1447 act.setEnabled(self.__connected)
1448 self.__superMenu.addAction(self.tr("Show Local Time"), self.__showLocalTime) 1478 self.__superMenu.addAction(self.tr("Show Local Time"), self.__showLocalTime)
1449 if hasTime: 1479 if hasTime:
1450 act = self.__superMenu.addAction( 1480 self.__superMenu.addAction(
1451 self.tr("Show Time"), self.__showLocalAndDeviceTime 1481 self.tr("Show Time"), self.__showLocalAndDeviceTime
1452 ) 1482 ).setEnabled(self.__connected)
1453 act.setEnabled(self.__connected)
1454 self.__superMenu.addSeparator() 1483 self.__superMenu.addSeparator()
1455 self.__superMenu.addAction( 1484 self.__superMenu.addAction(
1456 self.tr("Show Builtin Modules"), self.__showBuiltinModules 1485 self.tr("Show Builtin Modules"), self.__showBuiltinModules
1457 ).setEnabled(self.__connected) 1486 ).setEnabled(self.__connected)
1458 self.__superMenu.addSeparator() 1487 self.__superMenu.addSeparator()
1459 if not OSUtilities.isWindowsPlatform(): 1488 if not OSUtilities.isWindowsPlatform():
1460 available = self.__mpyCrossAvailable() 1489 available = self.__mpyCrossAvailable()
1461 act = self.__superMenu.addAction( 1490 self.__superMenu.addAction(
1462 self.tr("Compile Python File"), self.__compileFile2Mpy 1491 self.tr("Compile Python File"), self.__compileFile2Mpy
1463 ) 1492 ).setEnabled(available)
1464 act.setEnabled(available) 1493 aw = ericApp().getObject("ViewManager").activeWindow()
1465 act = self.__superMenu.addAction( 1494 self.__superMenu.addAction(
1466 self.tr("Compile Current Editor"), self.__compileEditor2Mpy 1495 self.tr("Compile Current Editor"), self.__compileEditor2Mpy
1467 ) 1496 ).setEnabled(available and bool(aw))
1468 aw = ericApp().getObject("ViewManager").activeWindow()
1469 act.setEnabled(available and bool(aw))
1470 self.__superMenu.addSeparator() 1497 self.__superMenu.addSeparator()
1471 if self.__device: 1498 if self.__device:
1472 self.__device.addDeviceMenuEntries(self.__superMenu) 1499 self.__device.addDeviceMenuEntries(self.__superMenu)
1473 self.__superMenu.addSeparator() 1500 self.__superMenu.addSeparator()
1474 if downloadMenu is None: 1501 if downloadMenu is None:
1475 # generic download action 1502 # generic download action
1476 act = self.__superMenu.addAction( 1503 self.__superMenu.addAction(
1477 self.tr("Download Firmware"), self.__downloadFirmware 1504 self.tr("Download Firmware"), self.__downloadFirmware
1478 ) 1505 ).setEnabled(self.__device.hasFirmwareUrl())
1479 act.setEnabled(self.__device.hasFirmwareUrl())
1480 else: 1506 else:
1481 # download sub-menu 1507 # download sub-menu
1482 self.__superMenu.addMenu(downloadMenu) 1508 self.__superMenu.addMenu(downloadMenu)
1483 self.__superMenu.addSeparator() 1509 self.__superMenu.addSeparator()
1484 act = self.__superMenu.addAction( 1510 self.__superMenu.addAction(
1485 self.tr("Show Documentation"), self.__showDocumentation 1511 self.tr("Show Documentation"), self.__showDocumentation
1486 ) 1512 ).setEnabled(self.__device.hasDocumentationUrl())
1487 act.setEnabled(self.__device.hasDocumentationUrl())
1488 self.__superMenu.addSeparator() 1513 self.__superMenu.addSeparator()
1489 if self.__device is not None and not self.__device.hasFlashMenuEntry(): 1514 ##if self.__device is not None and not self.__device.hasFlashMenuEntry():
1515 if bool(UF2FlashDialog.getFoundDevices()):
1490 self.__superMenu.addAction(self.tr("Flash UF2 Device"), self.__flashUF2) 1516 self.__superMenu.addAction(self.tr("Flash UF2 Device"), self.__flashUF2)
1491 self.__superMenu.addSeparator() 1517 self.__superMenu.addSeparator()
1492 self.__superMenu.addAction( 1518 self.__superMenu.addAction(
1493 self.tr("Manage Unknown Devices"), self.__manageUnknownDevices 1519 self.tr("Manage Unknown Devices"), self.__manageUnknownDevices
1494 ) 1520 )
1501 @pyqtSlot() 1527 @pyqtSlot()
1502 def __showDeviceVersion(self): 1528 def __showDeviceVersion(self):
1503 """ 1529 """
1504 Private slot to show some version info about MicroPython of the device. 1530 Private slot to show some version info about MicroPython of the device.
1505 """ 1531 """
1506 try: 1532 data = self.__device.getDeviceData()
1507 versionInfo = self.__interface.version() 1533 if data:
1508 if versionInfo: 1534 msg = self.tr("<h3>Device Version Information</h3>")
1509 msg = self.tr("<h3>Device Version Information</h3>") 1535 msg += "<table>"
1510 msg += "<table>" 1536 for key in ("sysname", "nodename", "release", "version", "machine"):
1511 for key, value in versionInfo.items(): 1537 msg += "<tr><td><b>{0}</b></td><td>{1}</td></tr>".format(
1512 msg += "<tr><td><b>{0}</b></td><td>{1}</td></tr>".format( 1538 key.capitalize(), data[key]
1513 key.capitalize(), value 1539 )
1514 ) 1540 msg += "</table>"
1515 msg += "</table>"
1516 else:
1517 msg = self.tr("No version information available.")
1518
1519 EricMessageBox.information(self, self.tr("Device Version Information"), msg) 1541 EricMessageBox.information(self, self.tr("Device Version Information"), msg)
1520 except Exception as exc: 1542 else:
1521 self.__showError("version()", str(exc)) 1543 EricMessageBox.critical(
1544 self,
1545 self.tr("Device Version Information"),
1546 self.tr("No version information available."),
1547 )
1522 1548
1523 @pyqtSlot() 1549 @pyqtSlot()
1524 def __showImplementation(self): 1550 def __showImplementation(self):
1525 """ 1551 """
1526 Private slot to show some implementation related information. 1552 Private slot to show some implementation related information.
1527 """ 1553 """
1528 try: 1554 data = self.__device.getDeviceData()
1529 impInfo = self.__interface.getImplementation() 1555 if data:
1530 if impInfo["name"] == "micropython": 1556 if data["mpy_name"] == "micropython":
1531 name = "MicroPython" 1557 name = "MicroPython"
1532 elif impInfo["name"] == "circuitpython": 1558 elif data["mpy_name"] == "circuitpython":
1533 name = "CircuitPython" 1559 name = "CircuitPython"
1534 elif impInfo["name"] == "unknown": 1560 elif data["mpy_name"] == "unknown":
1535 name = self.tr("unknown") 1561 name = self.tr("unknown")
1536 else: 1562 else:
1537 name = impInfo["name"] 1563 name = data["mpy_name"]
1538 version = ( 1564 version = (
1539 self.tr("unknown") 1565 self.tr("unknown")
1540 if impInfo["version"] == "unknown" 1566 if data["mpy_version"] == "unknown"
1541 else impInfo["version"] 1567 else data["mpy_version"]
1542 ) 1568 )
1543 variant = ( 1569 variant = (
1544 self.tr(" ({0})").format(impInfo["variant"]) 1570 self.tr(" ({0})").format(data["mpy_variant"])
1545 if impInfo["variant"] 1571 if data["mpy_variant"]
1546 else "" 1572 else ""
1547 ) 1573 )
1548 1574
1549 EricMessageBox.information( 1575 EricMessageBox.information(
1550 self, 1576 self,
1552 self.tr( 1578 self.tr(
1553 "<h3>Device Implementation Information</h3>" 1579 "<h3>Device Implementation Information</h3>"
1554 "<p>This device contains <b>{0} {1}{2}</b>.</p>" 1580 "<p>This device contains <b>{0} {1}{2}</b>.</p>"
1555 ).format(name, version, variant), 1581 ).format(name, version, variant),
1556 ) 1582 )
1557 except Exception as exc: 1583 else:
1558 self.__showError("getImplementation()", str(exc)) 1584 EricMessageBox.critical(
1585 self,
1586 self.tr("Device Implementation Information"),
1587 self.tr("No device implementation information available."),
1588 )
1559 1589
1560 @pyqtSlot() 1590 @pyqtSlot()
1561 def __showBoardInformation(self): 1591 def __showBoardInformation(self):
1562 """ 1592 """
1563 Private slot to show all available information about a board. 1593 Private slot to show all available information about a board.
1580 1610
1581 @param quiet flag indicating to not show a message 1611 @param quiet flag indicating to not show a message
1582 @type bool 1612 @type bool
1583 """ 1613 """
1584 if self.__device and self.__device.hasTimeCommands(): 1614 if self.__device and self.__device.hasTimeCommands():
1615 hasCPy = (
1616 self.__device.checkDeviceData()
1617 and self.__device.getDeviceData()["mpy_name"] == "circuitpython"
1618 )
1585 try: 1619 try:
1586 self.__interface.syncTime(self.__device.getDeviceType()) 1620 self.__interface.syncTime(self.__device.getDeviceType(), hasCPy=hasCPy)
1587 1621
1588 if not quiet: 1622 if not quiet:
1589 with EricOverridenCursor(): 1623 with EricOverridenCursor():
1590 EricMessageBox.information( 1624 EricMessageBox.information(
1591 self, 1625 self,

eric ide

mercurial