Thu, 11 Feb 2021 11:44:07 +0100
CircuitPython: extended the list of known UF2 boards.
# -*- coding: utf-8 -*- # Copyright (c) 2019 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a dialog to enter the firmware flashing data. """ import os from PyQt5.QtCore import pyqtSlot, QCoreApplication from PyQt5.QtWidgets import QDialog, QDialogButtonBox from E5Gui.E5PathPicker import E5PathPickerModes from E5Gui import E5MessageBox from .Ui_CircuitPythonFirmwareSelectionDialog import ( Ui_CircuitPythonFirmwareSelectionDialog ) import Utilities import UI.PixmapCache import Preferences class CircuitPythonFirmwareSelectionDialog( QDialog, Ui_CircuitPythonFirmwareSelectionDialog): """ Class implementing a dialog to enter the firmware flashing data. """ # # The Boards list is built with data extracted from: # - https://github.com/microsoft/uf2-samdx1 # - https://github.com/adafruit/Adafruit_nRF52_Bootloader # Boards = ( # Adafruit boards ("--- Adafruit ---", ""), ("BLM Badge", "BADGEBOOT"), ("BadgeLC", "BADGELCBOOT"), ("CLUE nRF52840", "CLUEBOOT"), ("Circuit Playground Express", "CPLAYBOOT"), ("Circuit Playground nRF52840", "CPLAYBTBOOT"), ("Feather Arcade D51", "ARCADE-D5"), ("Feather M0", "FEATHERBOOT"), ("Feather M0 Express", "FEATHERBOOT"), ("Feather M4 CAN Express", "FTHRCANBOOT"), ("Feather M4 Express", "FEATHERBOOT"), ("Feather nRF52840 Express", "FTHR840BOOT"), ("Feather nRF52840 Sense", "FTHR840BOOT"), ("Gemma M0", "GEMMABOOT"), ("Grand Central M4 Express", "GCM4BOOT"), ("Hallowing M0", "HALLOWBOOT"), ("Hallowing M4", "HALLOM4BOOT"), ("Hallowing Mask M4", "MASKM4BOOT"), ("Itsy Arcade D51", "ARCADE-D5"), ("ItsyBitsy M0 Express", "ITSYBOOT"), ("ItsyBitsy M4 Express", "ITSYM4BOOT"), ("ItsyBitsy nRF52840 Express", " ITSY840BOOT"), ("Metro M0", "METROBOOT"), ("Metro M4 AirLift", "METROM4BOOT"), ("Metro M4 Express", "METROM4BOOT"), ("Metro nRF52840 Express", "METR840BOOT"), ("NeoPixel Trinkey M0", "TRINKEYBOOT"), ("NeoTrelis M4 Express", "TRELM4BOOT"), ("PyBadge", "BADGEBOOT"), ("PyGamer", "PYGAMERBOOT"), ("PyPortal", "PORTALBOOT"), ("PyPortal M4 Express", "PORTALBOOT"), ("PyPortal Pynt", "PORTALBOOT"), ("PyPortal Titano", "PORTALBOOT"), ("PyRuler", "TRINKETBOOT"), ("QT Py M0", "QTPY_BOOT"), ("Radiofruit M0", "RADIOBOOT"), ("Trellis M4 Express", "TRELM4BOOT"), ("Trinket M0", "TRINKETBOOT"), ("crickit", "CRICKITBOOT"), ("pIRKey M0", "PIRKEYBOOT"), # Arduino boards ("--- Arduino ---", ""), ("MKR1000", "MKR1000"), ("MKR1300", "MKR1300"), ("MKRZero", "MKRZEROBOOT"), ("Nano 33 BLE", "NANO33BOOT"), ("Zero", "ZEROBOOT"), # Particle boards ("--- Particle ---", ""), ("Argon", "ARGONBOOT "), ("Boron", "BORONBOOT "), ("Xenon", "XENONBOOT "), # Seed boards ("--- Seeed Studio ---", ""), ("Grove Zero", "Grove Zero"), ("Seeduino XIAO", "Arduino"), # SparkFun boards ("--- SparkFun ---", ""), ("Qwiic Micro", "QwiicMicro"), ("SAMD21 Dev Breakout", "SPARKFUN"), ("SAMD21 Mini Breakout", "SPARKFUN"), ("SAMD51 Thing Plus", "51THINGBOOT"), ("RedBoard Turbo", "TURBOBOOT"), ("Pro nRF52840 Mini", "NRF52BOOT"), # other boards we know about ("--- {0} ---".format( QCoreApplication.translate("CircuitPythonFirmwareSelectionDialog", "Others") ), ""), ("ARAMCON Badge 2019", "ARAMBOOT"), ("AtelierDuMaker NRF52840 Breakout", "ADM840BOOT"), ("BlueMicro", "BLUEMICRO"), ("Capable Robot Programmable USB Hub", "USBHUBBOOT"), ("CircuitBrains Basic", "BOOT"), ("CircuitBrains Deluxe", "BOOT"), ("Eitech Robotics", "ROBOTICS"), ("ElectronicCats Bast BLE", "BASTBLE"), ("Fluff M0", "FLUFFBOOT"), ("Generic Corp. SAMD21 Board", "SAMD21"), ("Generic Corp. SAME54 Board", "SAME54"), ("IkigaiSense Vita nRF52840", "ISVITABoot"), ("Itaca uChip CircuitPython", "UCHIPYBOOT"), ("MakerDiary MDK nRF52840 USB Dongle", "MDK840DONGL"), ("MakerDiary nRF52840 M.2 Module", "nRF52840M2"), ("MakerDiary Pitaya Go", "PITAYAGO"), ("Microchip SAME54 Xplained", "E54XBOOT"), ("Mini SAM M0", "MINISAMBOOT"), ("Mini SAM M4", "MINISAMBOOT"), ("Nice Keyboards nice!nano", "NICENANO"), ("OHS2020 Badge", "BADGEBOOT"), ("PewPew", "PEWBOOT"), ("Raytac MDBT50Q-RX", "MDBT50QBOOT"), ("Robotics Masters Robo HAT MM1", "ROBOM0BOOT"), ("Robotics Masters Robo HAT MM1 M4", "ROBOM4BOOT"), ("Serpente", "SERPENTBOOT"), ("The Open Book Feather", "BOOKBOOT"), ("Watterott Wattuino RC", "RCBOOT"), ("Waveshare nRF52840 Eval", "WS52840EVK"), ("Winterbloom Big Honking Button", "HONKBOOT"), ("Winterbloom Binary Star", "STARBOOT"), ("Winterbloom Gemini", "GEMINIBOOT"), ("Winterbloom Sol", "SOLBOOT"), ("XinaBox CC03", "CC03"), ("XinaBox CS11", "CS11"), ("dadamachines automat", "AUTOMAT"), ("eduSense senseBox MCU", "SENSEBOX"), ("maholli PyCubedv04", "PYCUBEDBOOT"), ("maholli SAM32", "SAM32BOOT"), ("ndGarage ndBit6", "ND6BOOT"), ("ndGarage ndBit7", "ND7BOOT"), ) def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget @type QWidget """ super(CircuitPythonFirmwareSelectionDialog, self).__init__(parent) self.setupUi(self) self.retestButton.setIcon(UI.PixmapCache.getIcon("rescan")) self.firmwarePicker.setMode(E5PathPickerModes.OpenFileMode) self.firmwarePicker.setFilters( self.tr("CircuitPython Firmware Files (*.uf2);;" "All Files (*)")) self.bootPicker.setMode(E5PathPickerModes.DirectoryShowFilesMode) self.__manualMarker = "<manual>" self.boardComboBox.addItem("", ""), # indicator for no selection for boardName, bootVolume in self.Boards: self.boardComboBox.addItem(boardName, bootVolume) manualDevices = Preferences.getMicroPython("ManualDevices") if manualDevices: self.boardComboBox.addItem(self.tr("--- Local Devices ---"), "") for device in manualDevices: self.boardComboBox.addItem(device["description"], device["volume"]) self.boardComboBox.addItem(self.tr("Manual Select"), self.__manualMarker), msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) def __updateOkButton(self): """ Private method to update the state of the OK button and the retest button. """ firmwareFile = self.firmwarePicker.text() self.retestButton.setEnabled(bool(firmwareFile) and os.path.exists(firmwareFile)) if not bool(firmwareFile) or not os.path.exists(firmwareFile): enable = False else: volumeName = self.boardComboBox.currentData() if volumeName and volumeName != self.__manualMarker: # check if the user selected a board and the board is in # bootloader mode deviceDirectories = Utilities.findVolume(volumeName, findAll=True) if len(deviceDirectories) > 1: enable = False E5MessageBox.warning( self, self.tr("Select Path to Device"), self.tr("There are multiple devices in 'bootloader'" " mode and mounted. Please make sure, that" " only one device is prepared for flashing.") ) elif len(deviceDirectories) == 1: self.bootPicker.setText(deviceDirectories[0]) enable = True else: enable = False E5MessageBox.warning( self, self.tr("Select Path to Device"), self.tr("""<p>The device volume <b>{0}</b> could not""" """ be found. Is the device in 'bootloader'""" """ mode and mounted?</p> <p>Alternatively""" """ select the "Manual Select" entry and""" """ enter the path to the device below.</p>""") .format(volumeName) ) elif volumeName == self.__manualMarker: # select the device path manually deviceDirectory = self.bootPicker.text() enable = (bool(deviceDirectory) and os.path.exists(deviceDirectory)) else: # illegal entry enable = False self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable) @pyqtSlot(str) def on_firmwarePicker_textChanged(self, firmware): """ Private slot handling a change of the firmware path. @param firmware path to the firmware @type str """ self.__updateOkButton() @pyqtSlot(int) def on_boardComboBox_currentIndexChanged(self, index): """ Private slot to handle the selection of a board type. @param index index of the selected board type @type int """ if self.boardComboBox.itemData(index) == self.__manualMarker: self.bootPicker.clear() self.bootPicker.setEnabled(True) else: self.bootPicker.setEnabled(False) self.__updateOkButton() @pyqtSlot() def on_retestButton_clicked(self): """ Private slot to research for the selected volume. """ self.__updateOkButton() @pyqtSlot(str) def on_bootPicker_textChanged(self, devicePath): """ Private slot handling a change of the device path. @param devicePath path to the device @type str """ self.__updateOkButton() def getData(self): """ Public method to obtain the entered data. @return tuple containing the path to the CircuitPython firmware file and the path to the device @rtype tuple of (str, str) """ return self.firmwarePicker.text(), self.bootPicker.text()