9915
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
1
|
# -*- coding: utf-8 -*- |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
2
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
3
|
# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
4
|
# |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
5
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
6
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
7
|
Module implementing a dialog to convert a .hex or .bin firmware file to .uf2. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
8
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
9
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
10
|
import json |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
11
|
import os |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
12
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
13
|
from PyQt6.QtCore import QProcess, QRegularExpression, pyqtSlot |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
14
|
from PyQt6.QtGui import QRegularExpressionValidator |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
15
|
from PyQt6.QtWidgets import QDialog |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
16
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
17
|
from eric7 import Preferences |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
18
|
from eric7.EricWidgets.EricPathPicker import EricPathPickerModes |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
19
|
from eric7.SystemUtilities.PythonUtilities import getPythonExecutable |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
20
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
21
|
from .Ui_ConvertToUF2Dialog import Ui_ConvertToUF2Dialog |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
22
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
23
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
24
|
class ConvertToUF2Dialog(QDialog, Ui_ConvertToUF2Dialog): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
25
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
26
|
Class implementing a dialog to convert a .hex or .bin firmware file to .uf2. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
27
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
28
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
29
|
FamiliesFile = os.path.join(os.path.dirname(__file__), "Tools", "uf2families.json") |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
30
|
ConvertScript = os.path.join(os.path.dirname(__file__), "Tools", "uf2conv.py") |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
31
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
32
|
def __init__(self, parent=None): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
33
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
34
|
Constructor |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
35
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
36
|
@param parent reference to the parent widget (defaults to None) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
37
|
@type QWidget (optional) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
38
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
39
|
super().__init__(parent) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
40
|
self.setupUi(self) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
41
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
42
|
self.firmwarePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
43
|
self.firmwarePicker.setFilters( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
44
|
self.tr("MicroPython Firmware Files (*.hex *.bin);;All Files (*)") |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
45
|
) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
46
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
47
|
self.__validator = QRegularExpressionValidator( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
48
|
QRegularExpression(r"[0-9a-fA-F]{0,7}") |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
49
|
) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
50
|
self.addressEdit.setValidator(self.__validator) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
51
|
self.addressEdit.setEnabled(False) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
52
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
53
|
self.__populateFamilyComboBox() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
54
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
55
|
self.__process = QProcess(self) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
56
|
self.__process.readyReadStandardOutput.connect(self.__readOutput) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
57
|
self.__process.readyReadStandardError.connect(self.__readError) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
58
|
self.__process.finished.connect(self.__conversionFinished) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
59
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
60
|
self.__updateConvertButton() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
61
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
62
|
def __populateFamilyComboBox(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
63
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
64
|
Private method to populate the chip family combo box with values read from |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
65
|
'uf2families.json' file. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
66
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
67
|
with open(ConvertToUF2Dialog.FamiliesFile, "r") as f: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
68
|
families = json.load(f) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
69
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
70
|
self.familiesComboBox.addItem("", "") |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
71
|
for family in families: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
72
|
self.familiesComboBox.addItem(family["description"], family["id"]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
73
|
self.familiesComboBox.model().sort(0) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
74
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
75
|
def __updateConvertButton(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
76
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
77
|
Private method to set the enabled status of the 'Convert' button. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
78
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
79
|
self.convertButton.setEnabled( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
80
|
bool(self.firmwarePicker.text()) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
81
|
and bool(self.familiesComboBox.currentText()) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
82
|
) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
83
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
84
|
@pyqtSlot(str) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
85
|
def on_firmwarePicker_textChanged(self, firmware): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
86
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
87
|
Private slot handling a change of the firmware file name. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
88
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
89
|
@param firmware name of the firmware file |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
90
|
@type str |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
91
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
92
|
self.addressEdit.setEnabled(firmware.lower().endswith(".bin")) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
93
|
self.__updateConvertButton() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
94
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
95
|
@pyqtSlot(str) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
96
|
def on_familiesComboBox_currentTextChanged(self, family): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
97
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
98
|
Private slot handling the selection of a chip family. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
99
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
100
|
@param family name of the selected chip family |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
101
|
@type str |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
102
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
103
|
self.__updateConvertButton() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
104
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
105
|
@pyqtSlot() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
106
|
def on_convertButton_clicked(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
107
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
108
|
Private slot activating the conversion process. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
109
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
110
|
self.outputEdit.clear() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
111
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
112
|
inputFile = self.firmwarePicker.text() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
113
|
outputFile = os.path.splitext(inputFile)[0] + ".uf2" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
114
|
args = [ |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
115
|
ConvertToUF2Dialog.ConvertScript, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
116
|
"--convert", |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
117
|
"--family", |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
118
|
self.familiesComboBox.currentData(), |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
119
|
"--output", |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
120
|
outputFile, |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
121
|
] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
122
|
if inputFile.lower().endswith(".bin"): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
123
|
address = self.addressEdit.text() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
124
|
if address: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
125
|
args.extend(["--base", "0x{0}".format(address)]) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
126
|
args.append(inputFile) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
127
|
python = getPythonExecutable() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
128
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
129
|
# output the generated command |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
130
|
self.outputEdit.insertPlainText( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
131
|
"{0} {1}\n{2}\n\n".format(python, " ".join(args), "=" * 40) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
132
|
) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
133
|
self.outputEdit.ensureCursorVisible() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
134
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
135
|
# start the conversion process |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
136
|
self.convertButton.setEnabled(False) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
137
|
self.__process.start(python, args) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
138
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
139
|
@pyqtSlot() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
140
|
def __readOutput(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
141
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
142
|
Private slot to read the standard output channel of the conversion process. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
143
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
144
|
out = str( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
145
|
self.__process.readAllStandardOutput(), |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
146
|
Preferences.getSystem("IOEncoding"), |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
147
|
"replace", |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
148
|
) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
149
|
self.outputEdit.insertPlainText(out) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
150
|
self.outputEdit.ensureCursorVisible() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
151
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
152
|
@pyqtSlot() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
153
|
def __readError(self): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
154
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
155
|
Private slot to read the standard error channel of the conversion process. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
156
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
157
|
out = str( |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
158
|
self.__process.readAllStandardError(), |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
159
|
Preferences.getSystem("IOEncoding"), |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
160
|
"replace", |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
161
|
) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
162
|
self.outputEdit.insertPlainText(self.tr("--- ERROR ---\n")) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
163
|
self.outputEdit.insertPlainText(out) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
164
|
self.outputEdit.ensureCursorVisible() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
165
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
166
|
def __conversionFinished(self, exitCode, exitStatus): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
167
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
168
|
Private slot handling the end of the conversion process. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
169
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
170
|
@param exitCode exit code of the process |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
171
|
@type int |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
172
|
@param exitStatus exit status of the process |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
173
|
@type QProcess.ExitStatus |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
174
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
175
|
self.convertButton.setEnabled(True) |