Sat, 04 Mar 2023 18:09:08 +0100
Corrected flashing of ESP 8266 devices.
9755 | 1 | # -*- coding: utf-8 -*- |
2 | ||
3 | # Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> | |
4 | # | |
5 | ||
6 | """ | |
7 | Module implementing the device interface class for Teensy boards with MicroPython. | |
8 | """ | |
9 | ||
9820 | 10 | from PyQt6.QtCore import QCoreApplication, QProcess, QUrl, pyqtSlot |
11 | from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest | |
9755 | 12 | from PyQt6.QtWidgets import QMenu |
13 | ||
14 | from eric7 import Globals, Preferences | |
15 | from eric7.EricWidgets import EricMessageBox | |
16 | from eric7.EricWidgets.EricApplication import ericApp | |
17 | ||
9765
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
18 | from ..MicroPythonWidget import HAS_QTCHART |
9756
9854647c8c5c
Reorganized the MicroPython package.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9755
diff
changeset
|
19 | from . import FirmwareGithubUrls |
9854647c8c5c
Reorganized the MicroPython package.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9755
diff
changeset
|
20 | from .DeviceBase import BaseDevice |
9755 | 21 | |
22 | ||
9756
9854647c8c5c
Reorganized the MicroPython package.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9755
diff
changeset
|
23 | class TeensyDevice(BaseDevice): |
9755 | 24 | """ |
25 | Class implementing the device for Teensy boards with MicroPython. | |
26 | """ | |
27 | ||
28 | def __init__(self, microPythonWidget, deviceType, parent=None): | |
29 | """ | |
30 | Constructor | |
31 | ||
32 | @param microPythonWidget reference to the main MicroPython widget | |
33 | @type MicroPythonWidget | |
34 | @param deviceType device type assigned to this device interface | |
35 | @type str | |
36 | @param parent reference to the parent object | |
37 | @type QObject | |
38 | """ | |
39 | super().__init__(microPythonWidget, deviceType, parent) | |
40 | ||
41 | self.__createTeensyMenu() | |
42 | ||
43 | def setButtons(self): | |
44 | """ | |
45 | Public method to enable the supported action buttons. | |
46 | """ | |
47 | super().setButtons() | |
9763
52f982c08301
Removed the 'Open' and 'Save' buttons from the MicroPython widget and made the repl and file manager start automatically upon connecting to the selected device.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9756
diff
changeset
|
48 | |
9755 | 49 | self.microPython.setActionButtons( |
50 | run=True, repl=True, files=True, chart=HAS_QTCHART | |
51 | ) | |
52 | ||
53 | def forceInterrupt(self): | |
54 | """ | |
55 | Public method to determine the need for an interrupt when opening the | |
56 | serial connection. | |
57 | ||
58 | @return flag indicating an interrupt is needed | |
59 | @rtype bool | |
60 | """ | |
61 | return False | |
62 | ||
63 | def deviceName(self): | |
64 | """ | |
65 | Public method to get the name of the device. | |
66 | ||
67 | @return name of the device | |
68 | @rtype str | |
69 | """ | |
70 | return self.tr("Teensy") | |
71 | ||
72 | def canStartRepl(self): | |
73 | """ | |
74 | Public method to determine, if a REPL can be started. | |
75 | ||
76 | @return tuple containing a flag indicating it is safe to start a REPL | |
77 | and a reason why it cannot. | |
78 | @rtype tuple of (bool, str) | |
79 | """ | |
80 | return True, "" | |
81 | ||
82 | def canStartPlotter(self): | |
83 | """ | |
84 | Public method to determine, if a Plotter can be started. | |
85 | ||
86 | @return tuple containing a flag indicating it is safe to start a | |
87 | Plotter and a reason why it cannot. | |
88 | @rtype tuple of (bool, str) | |
89 | """ | |
90 | return True, "" | |
91 | ||
92 | def canRunScript(self): | |
93 | """ | |
94 | Public method to determine, if a script can be executed. | |
95 | ||
96 | @return tuple containing a flag indicating it is safe to start a | |
97 | Plotter and a reason why it cannot. | |
98 | @rtype tuple of (bool, str) | |
99 | """ | |
100 | return True, "" | |
101 | ||
102 | def runScript(self, script): | |
103 | """ | |
104 | Public method to run the given Python script. | |
105 | ||
106 | @param script script to be executed | |
107 | @type str | |
108 | """ | |
109 | pythonScript = script.split("\n") | |
110 | self.sendCommands(pythonScript) | |
111 | ||
112 | def canStartFileManager(self): | |
113 | """ | |
114 | Public method to determine, if a File Manager can be started. | |
115 | ||
116 | @return tuple containing a flag indicating it is safe to start a | |
117 | File Manager and a reason why it cannot. | |
118 | @rtype tuple of (bool, str) | |
119 | """ | |
120 | return True, "" | |
121 | ||
122 | def getDocumentationUrl(self): | |
123 | """ | |
124 | Public method to get the device documentation URL. | |
125 | ||
126 | @return documentation URL of the device | |
127 | @rtype str | |
128 | """ | |
129 | return Preferences.getMicroPython("MicroPythonDocuUrl") | |
130 | ||
131 | def getFirmwareUrl(self): | |
132 | """ | |
133 | Public method to get the device firmware download URL. | |
134 | ||
135 | @return firmware download URL of the device | |
136 | @rtype str | |
137 | """ | |
138 | return Preferences.getMicroPython("MicroPythonFirmwareUrl") | |
139 | ||
140 | def __createTeensyMenu(self): | |
141 | """ | |
142 | Private method to create the microbit submenu. | |
143 | """ | |
144 | self.__teensyMenu = QMenu(self.tr("Teensy Functions")) | |
145 | ||
146 | self.__showMpyAct = self.__teensyMenu.addAction( | |
147 | self.tr("Show MicroPython Versions"), self.__showFirmwareVersions | |
148 | ) | |
149 | self.__teensyMenu.addSeparator() | |
150 | self.__teensyMenu.addAction( | |
9820 | 151 | self.tr("MicroPython Flash Instructions"), showTeensyFlashInstructions |
9755 | 152 | ) |
153 | self.__flashMpyAct = self.__teensyMenu.addAction( | |
9820 | 154 | self.tr("Flash MicroPython Firmware"), startTeensyLoader |
9755 | 155 | ) |
156 | self.__flashMpyAct.setToolTip( | |
157 | self.tr("Start the 'Teensy Loader' application to flash the Teensy device.") | |
158 | ) | |
159 | ||
160 | def addDeviceMenuEntries(self, menu): | |
161 | """ | |
162 | Public method to add device specific entries to the given menu. | |
163 | ||
164 | @param menu reference to the context menu | |
165 | @type QMenu | |
166 | """ | |
167 | connected = self.microPython.isConnected() | |
168 | linkConnected = self.microPython.isLinkConnected() | |
169 | ||
170 | self.__showMpyAct.setEnabled(connected) | |
171 | self.__flashMpyAct.setEnabled(not linkConnected) | |
172 | ||
173 | menu.addMenu(self.__teensyMenu) | |
174 | ||
175 | @pyqtSlot() | |
176 | def __showFirmwareVersions(self): | |
177 | """ | |
178 | Private slot to show the firmware version of the connected device and the | |
179 | available firmware version. | |
180 | """ | |
181 | if self.microPython.isConnected(): | |
182 | if self._deviceData["mpy_name"] != "micropython": | |
183 | EricMessageBox.critical( | |
184 | None, | |
185 | self.tr("Show MicroPython Versions"), | |
186 | self.tr( | |
187 | """The firmware of the connected device cannot be""" | |
188 | """ determined or the board does not run MicroPython.""" | |
189 | """ Aborting...""" | |
190 | ), | |
191 | ) | |
192 | else: | |
193 | ui = ericApp().getObject("UserInterface") | |
194 | request = QNetworkRequest(QUrl(FirmwareGithubUrls["micropython"])) | |
195 | reply = ui.networkAccessManager().head(request) | |
196 | reply.finished.connect(lambda: self.__firmwareVersionResponse(reply)) | |
197 | ||
9820 | 198 | @pyqtSlot(QNetworkReply) |
9755 | 199 | def __firmwareVersionResponse(self, reply): |
200 | """ | |
9820 | 201 | Private slot handling the response of the latest version request. |
9755 | 202 | |
203 | @param reply reference to the reply object | |
204 | @type QNetworkReply | |
205 | """ | |
206 | latestUrl = reply.url().toString() | |
207 | tag = latestUrl.rsplit("/", 1)[-1] | |
208 | while tag and not tag[0].isdecimal(): | |
209 | # get rid of leading non-decimal characters | |
210 | tag = tag[1:] | |
211 | latestVersion = Globals.versionToTuple(tag) | |
212 | ||
213 | if self._deviceData["mpy_version"] == "unknown": | |
214 | currentVersionStr = self.tr("unknown") | |
215 | currentVersion = (0, 0, 0) | |
216 | else: | |
217 | currentVersionStr = self._deviceData["mpy_version"] | |
218 | currentVersion = Globals.versionToTuple(currentVersionStr) | |
219 | ||
220 | msg = self.tr( | |
221 | "<h4>MicroPython Version Information</h4>" | |
222 | "<table>" | |
223 | "<tr><td>Installed:</td><td>{0}</td></tr>" | |
224 | "<tr><td>Available:</td><td>{1}</td></tr>" | |
225 | "</table>" | |
226 | ).format(currentVersionStr, tag) | |
227 | if currentVersion < latestVersion: | |
228 | msg += self.tr("<p><b>Update available!</b></p>") | |
229 | ||
230 | EricMessageBox.information( | |
231 | None, | |
232 | self.tr("MicroPython Version"), | |
233 | msg, | |
234 | ) | |
235 | ||
9765
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
236 | ################################################################## |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
237 | ## time related methods below |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
238 | ################################################################## |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
239 | |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
240 | def _getSetTimeCode(self): |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
241 | """ |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
242 | Protected method to get the device code to set the time. |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
243 | |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
244 | Note: This method must be implemented in the various device specific |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
245 | subclasses. |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
246 | |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
247 | @return code to be executed on the connected device to set the time |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
248 | @rtype str |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
249 | """ |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
250 | # rtc_time[0] - year 4 digit |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
251 | # rtc_time[1] - month 1..12 |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
252 | # rtc_time[2] - day 1..31 |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
253 | # rtc_time[3] - weekday 1..7 1=Monday |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
254 | # rtc_time[4] - hour 0..23 |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
255 | # rtc_time[5] - minute 0..59 |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
256 | # rtc_time[6] - second 0..59 |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
257 | # rtc_time[7] - yearday 1..366 |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
258 | # rtc_time[8] - isdst 0, 1, or -1 |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
259 | |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
260 | # The machine.RTC.init() function takes the arguments in the |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
261 | # order: (year, month, day, weekday, hour, minute, second, |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
262 | # subseconds) |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
263 | # https://docs.micropython.org/en/latest/library/machine.RTC.html#machine-rtc |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
264 | return """ |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
265 | def set_time(rtc_time): |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
266 | import machine |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
267 | rtc = machine.RTC() |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
268 | rtc.init(rtc_time[:7] + (0,)) |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
269 | """ |
6378da868bb0
Reorganized the MicroPython code even more.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9763
diff
changeset
|
270 | |
9755 | 271 | |
272 | def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber): | |
273 | """ | |
274 | Function to instantiate a MicroPython device object. | |
275 | ||
276 | @param microPythonWidget reference to the main MicroPython widget | |
277 | @type MicroPythonWidget | |
278 | @param deviceType device type assigned to this device interface | |
279 | @type str | |
280 | @param vid vendor ID | |
281 | @type int | |
282 | @param pid product ID | |
283 | @type int | |
284 | @param boardName name of the board | |
285 | @type str | |
286 | @param serialNumber serial number of the board | |
287 | @type str | |
288 | @return reference to the instantiated device object | |
289 | @rtype PyBoardDevice | |
290 | """ | |
291 | return TeensyDevice(microPythonWidget, deviceType) | |
9820 | 292 | |
293 | ||
294 | @pyqtSlot() | |
295 | def showTeensyFlashInstructions(): | |
296 | """ | |
297 | Slot to show a message box with instruction to flash the Teensy. | |
298 | """ | |
299 | EricMessageBox.information( | |
300 | None, | |
301 | QCoreApplication.translate("TeensyDevice", "Flash MicroPython Firmware"), | |
302 | QCoreApplication.translate( | |
303 | "TeensyDevice", | |
304 | """<p>Teensy 4.0 and Teensy 4.1 are flashed using the 'Teensy Loader'""" | |
305 | """ application. Make sure you downloaded the MicroPython or""" | |
306 | """ CircuitPython .hex file.</p>""" | |
307 | """<p>See <a href="{0}">the PJRC Teensy web site</a>""" | |
308 | """ for details.</p>""", | |
309 | ).format("https://www.pjrc.com/teensy/loader.html"), | |
310 | ) | |
311 | ||
312 | ||
313 | @pyqtSlot() | |
314 | def startTeensyLoader(): | |
315 | """ | |
316 | Slot to start the 'Teensy Loader' application. | |
317 | ||
318 | Note: The application must be accessible via the application search path. | |
319 | """ | |
320 | ok, _ = QProcess.startDetached("teensy") | |
321 | if not ok: | |
322 | EricMessageBox.warning( | |
323 | None, | |
324 | QCoreApplication.translate("TeensyDevice", "Start 'Teensy Loader'"), | |
325 | QCoreApplication.translate( | |
326 | "TeensyDevice", | |
327 | """<p>The 'Teensy Loader' application <b>teensy</b> could not""" | |
328 | """ be started. Ensure it is in the application search path or""" | |
329 | """ start it manually.</p>""", | |
330 | ), | |
331 | ) |