26 |
26 |
27 class MicrobitDevice(MicroPythonDevice): |
27 class MicrobitDevice(MicroPythonDevice): |
28 """ |
28 """ |
29 Class implementing the device for BBC micro:bit and Calliope mini boards. |
29 Class implementing the device for BBC micro:bit and Calliope mini boards. |
30 """ |
30 """ |
|
31 |
31 def __init__(self, microPythonWidget, deviceType, parent=None): |
32 def __init__(self, microPythonWidget, deviceType, parent=None): |
32 """ |
33 """ |
33 Constructor |
34 Constructor |
34 |
35 |
35 @param microPythonWidget reference to the main MicroPython widget |
36 @param microPythonWidget reference to the main MicroPython widget |
36 @type MicroPythonWidget |
37 @type MicroPythonWidget |
37 @param deviceType type of the device |
38 @param deviceType type of the device |
38 @type str |
39 @type str |
39 @param parent reference to the parent object |
40 @param parent reference to the parent object |
40 @type QObject |
41 @type QObject |
41 """ |
42 """ |
42 super().__init__( |
43 super().__init__(microPythonWidget, deviceType, parent) |
43 microPythonWidget, deviceType, parent) |
44 |
44 |
|
45 def setButtons(self): |
45 def setButtons(self): |
46 """ |
46 """ |
47 Public method to enable the supported action buttons. |
47 Public method to enable the supported action buttons. |
48 """ |
48 """ |
49 super().setButtons() |
49 super().setButtons() |
50 self.microPython.setActionButtons( |
50 self.microPython.setActionButtons( |
51 run=True, repl=True, files=True, chart=HAS_QTCHART) |
51 run=True, repl=True, files=True, chart=HAS_QTCHART |
52 |
52 ) |
|
53 |
53 def forceInterrupt(self): |
54 def forceInterrupt(self): |
54 """ |
55 """ |
55 Public method to determine the need for an interrupt when opening the |
56 Public method to determine the need for an interrupt when opening the |
56 serial connection. |
57 serial connection. |
57 |
58 |
58 @return flag indicating an interrupt is needed |
59 @return flag indicating an interrupt is needed |
59 @rtype bool |
60 @rtype bool |
60 """ |
61 """ |
61 return True |
62 return True |
62 |
63 |
63 def deviceName(self): |
64 def deviceName(self): |
64 """ |
65 """ |
65 Public method to get the name of the device. |
66 Public method to get the name of the device. |
66 |
67 |
67 @return name of the device |
68 @return name of the device |
68 @rtype str |
69 @rtype str |
69 """ |
70 """ |
70 if self.getDeviceType() == "bbc_microbit": |
71 if self.getDeviceType() == "bbc_microbit": |
71 # BBC micro:bit |
72 # BBC micro:bit |
72 return self.tr("BBC micro:bit") |
73 return self.tr("BBC micro:bit") |
73 else: |
74 else: |
74 # Calliope mini |
75 # Calliope mini |
75 return self.tr("Calliope mini") |
76 return self.tr("Calliope mini") |
76 |
77 |
77 def canStartRepl(self): |
78 def canStartRepl(self): |
78 """ |
79 """ |
79 Public method to determine, if a REPL can be started. |
80 Public method to determine, if a REPL can be started. |
80 |
81 |
81 @return tuple containing a flag indicating it is safe to start a REPL |
82 @return tuple containing a flag indicating it is safe to start a REPL |
82 and a reason why it cannot. |
83 and a reason why it cannot. |
83 @rtype tuple of (bool, str) |
84 @rtype tuple of (bool, str) |
84 """ |
85 """ |
85 return True, "" |
86 return True, "" |
86 |
87 |
87 def canStartPlotter(self): |
88 def canStartPlotter(self): |
88 """ |
89 """ |
89 Public method to determine, if a Plotter can be started. |
90 Public method to determine, if a Plotter can be started. |
90 |
91 |
91 @return tuple containing a flag indicating it is safe to start a |
92 @return tuple containing a flag indicating it is safe to start a |
92 Plotter and a reason why it cannot. |
93 Plotter and a reason why it cannot. |
93 @rtype tuple of (bool, str) |
94 @rtype tuple of (bool, str) |
94 """ |
95 """ |
95 return True, "" |
96 return True, "" |
96 |
97 |
97 def canRunScript(self): |
98 def canRunScript(self): |
98 """ |
99 """ |
99 Public method to determine, if a script can be executed. |
100 Public method to determine, if a script can be executed. |
100 |
101 |
101 @return tuple containing a flag indicating it is safe to start a |
102 @return tuple containing a flag indicating it is safe to start a |
102 Plotter and a reason why it cannot. |
103 Plotter and a reason why it cannot. |
103 @rtype tuple of (bool, str) |
104 @rtype tuple of (bool, str) |
104 """ |
105 """ |
105 return True, "" |
106 return True, "" |
106 |
107 |
107 def runScript(self, script): |
108 def runScript(self, script): |
108 """ |
109 """ |
109 Public method to run the given Python script. |
110 Public method to run the given Python script. |
110 |
111 |
111 @param script script to be executed |
112 @param script script to be executed |
112 @type str |
113 @type str |
113 """ |
114 """ |
114 pythonScript = script.split("\n") |
115 pythonScript = script.split("\n") |
115 self.sendCommands(pythonScript) |
116 self.sendCommands(pythonScript) |
116 |
117 |
117 def canStartFileManager(self): |
118 def canStartFileManager(self): |
118 """ |
119 """ |
119 Public method to determine, if a File Manager can be started. |
120 Public method to determine, if a File Manager can be started. |
120 |
121 |
121 @return tuple containing a flag indicating it is safe to start a |
122 @return tuple containing a flag indicating it is safe to start a |
122 File Manager and a reason why it cannot. |
123 File Manager and a reason why it cannot. |
123 @rtype tuple of (bool, str) |
124 @rtype tuple of (bool, str) |
124 """ |
125 """ |
125 return True, "" |
126 return True, "" |
126 |
127 |
127 def hasTimeCommands(self): |
128 def hasTimeCommands(self): |
128 """ |
129 """ |
129 Public method to check, if the device supports time commands. |
130 Public method to check, if the device supports time commands. |
130 |
131 |
131 The default returns True. |
132 The default returns True. |
132 |
133 |
133 @return flag indicating support for time commands |
134 @return flag indicating support for time commands |
134 @rtype bool |
135 @rtype bool |
135 """ |
136 """ |
136 return False |
137 return False |
137 |
138 |
138 def addDeviceMenuEntries(self, menu): |
139 def addDeviceMenuEntries(self, menu): |
139 """ |
140 """ |
140 Public method to add device specific entries to the given menu. |
141 Public method to add device specific entries to the given menu. |
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 |
147 act = menu.addAction(self.tr("Flash MicroPython"), |
148 act = menu.addAction(self.tr("Flash MicroPython"), self.__flashMicroPython) |
148 self.__flashMicroPython) |
|
149 act.setEnabled(not connected) |
149 act.setEnabled(not connected) |
150 act = menu.addAction(self.tr("Flash Firmware"), |
150 act = menu.addAction( |
151 lambda: self.__flashMicroPython(firmware=True)) |
151 self.tr("Flash Firmware"), lambda: self.__flashMicroPython(firmware=True) |
|
152 ) |
152 act.setEnabled(not connected) |
153 act.setEnabled(not connected) |
153 menu.addSeparator() |
154 menu.addSeparator() |
154 act = menu.addAction(self.tr("Save Script"), self.__saveScriptToDevice) |
155 act = menu.addAction(self.tr("Save Script"), self.__saveScriptToDevice) |
155 act.setToolTip(self.tr( |
156 act.setToolTip(self.tr("Save the current script to the selected device")) |
156 "Save the current script to the selected device")) |
|
157 act.setEnabled(connected) |
157 act.setEnabled(connected) |
158 act = menu.addAction(self.tr("Save Script as 'main.py'"), |
158 act = menu.addAction(self.tr("Save Script as 'main.py'"), self.__saveMain) |
159 self.__saveMain) |
159 act.setToolTip( |
160 act.setToolTip(self.tr( |
160 self.tr("Save the current script as 'main.py' on the connected device") |
161 "Save the current script as 'main.py' on the connected device")) |
161 ) |
162 act.setEnabled(connected) |
162 act.setEnabled(connected) |
163 menu.addSeparator() |
163 menu.addSeparator() |
164 act = menu.addAction(self.tr("Reset {0}").format(self.deviceName()), |
164 act = menu.addAction( |
165 self.__resetDevice) |
165 self.tr("Reset {0}").format(self.deviceName()), self.__resetDevice |
|
166 ) |
166 act.setEnabled(connected) |
167 act.setEnabled(connected) |
167 |
168 |
168 def hasFlashMenuEntry(self): |
169 def hasFlashMenuEntry(self): |
169 """ |
170 """ |
170 Public method to check, if the device has its own flash menu entry. |
171 Public method to check, if the device has its own flash menu entry. |
171 |
172 |
172 @return flag indicating a specific flash menu entry |
173 @return flag indicating a specific flash menu entry |
173 @rtype bool |
174 @rtype bool |
174 """ |
175 """ |
175 return True |
176 return True |
176 |
177 |
177 @pyqtSlot() |
178 @pyqtSlot() |
178 def __flashMicroPython(self, firmware=False): |
179 def __flashMicroPython(self, firmware=False): |
179 """ |
180 """ |
180 Private slot to flash MicroPython or the DAPLink firmware to the |
181 Private slot to flash MicroPython or the DAPLink firmware to the |
181 device. |
182 device. |
182 |
183 |
183 @param firmware flag indicating to flash the DAPLink firmware |
184 @param firmware flag indicating to flash the DAPLink firmware |
184 @type bool |
185 @type bool |
185 """ |
186 """ |
186 # Attempts to find the path on the file system that represents the |
187 # Attempts to find the path on the file system that represents the |
187 # plugged in micro:bit board. To flash the DAPLink firmware, it must be |
188 # plugged in micro:bit board. To flash the DAPLink firmware, it must be |
188 # in maintenance mode, for MicroPython in standard mode. |
189 # in maintenance mode, for MicroPython in standard mode. |
189 if self.getDeviceType() == "bbc_microbit": |
190 if self.getDeviceType() == "bbc_microbit": |
190 # BBC micro:bit |
191 # BBC micro:bit |
191 if firmware: |
192 if firmware: |
192 deviceDirectories = Utilities.findVolume("MAINTENANCE", |
193 deviceDirectories = Utilities.findVolume("MAINTENANCE", findAll=True) |
193 findAll=True) |
|
194 else: |
194 else: |
195 deviceDirectories = Utilities.findVolume("MICROBIT", |
195 deviceDirectories = Utilities.findVolume("MICROBIT", findAll=True) |
196 findAll=True) |
|
197 else: |
196 else: |
198 # Calliope mini |
197 # Calliope mini |
199 if firmware: |
198 if firmware: |
200 deviceDirectories = Utilities.findVolume("MAINTENANCE", |
199 deviceDirectories = Utilities.findVolume("MAINTENANCE", findAll=True) |
201 findAll=True) |
|
202 else: |
200 else: |
203 deviceDirectories = Utilities.findVolume("MINI", |
201 deviceDirectories = Utilities.findVolume("MINI", findAll=True) |
204 findAll=True) |
|
205 if len(deviceDirectories) == 0: |
202 if len(deviceDirectories) == 0: |
206 if self.getDeviceType() == "bbc_microbit": |
203 if self.getDeviceType() == "bbc_microbit": |
207 # BBC micro:bit is not ready or not mounted |
204 # BBC micro:bit is not ready or not mounted |
208 if firmware: |
205 if firmware: |
209 EricMessageBox.critical( |
206 EricMessageBox.critical( |
210 self.microPython, |
207 self.microPython, |
211 self.tr("Flash MicroPython/Firmware"), |
208 self.tr("Flash MicroPython/Firmware"), |
212 self.tr( |
209 self.tr( |
213 '<p>The BBC micro:bit is not ready for flashing' |
210 "<p>The BBC micro:bit is not ready for flashing" |
214 ' the DAPLink firmware. Follow these' |
211 " the DAPLink firmware. Follow these" |
215 ' instructions. </p>' |
212 " instructions. </p>" |
216 '<ul>' |
213 "<ul>" |
217 '<li>unplug USB cable and any batteries</li>' |
214 "<li>unplug USB cable and any batteries</li>" |
218 '<li>keep RESET button pressed an plug USB cable' |
215 "<li>keep RESET button pressed an plug USB cable" |
219 ' back in</li>' |
216 " back in</li>" |
220 '<li>a drive called MAINTENANCE should be' |
217 "<li>a drive called MAINTENANCE should be" |
221 ' available</li>' |
218 " available</li>" |
222 '</ul>' |
219 "</ul>" |
223 '<p>See the ' |
220 "<p>See the " |
224 '<a href="https://microbit.org/guide/firmware/">' |
221 '<a href="https://microbit.org/guide/firmware/">' |
225 'micro:bit web site</a> for details.</p>' |
222 "micro:bit web site</a> for details.</p>" |
226 ) |
223 ), |
227 ) |
224 ) |
228 else: |
225 else: |
229 EricMessageBox.critical( |
226 EricMessageBox.critical( |
230 self.microPython, |
227 self.microPython, |
231 self.tr("Flash MicroPython/Firmware"), |
228 self.tr("Flash MicroPython/Firmware"), |
232 self.tr( |
229 self.tr( |
233 '<p>The BBC micro:bit is not ready for flashing' |
230 "<p>The BBC micro:bit is not ready for flashing" |
234 ' the MicroPython firmware. Please make sure,' |
231 " the MicroPython firmware. Please make sure," |
235 ' that a drive called MICROBIT is available.' |
232 " that a drive called MICROBIT is available." |
236 '</p>' |
233 "</p>" |
237 ) |
234 ), |
238 ) |
235 ) |
239 else: |
236 else: |
240 # Calliope mini is not ready or not mounted |
237 # Calliope mini is not ready or not mounted |
241 if firmware: |
238 if firmware: |
242 EricMessageBox.critical( |
239 EricMessageBox.critical( |
243 self.microPython, |
240 self.microPython, |
244 self.tr("Flash MicroPython/Firmware"), |
241 self.tr("Flash MicroPython/Firmware"), |
245 self.tr( |
242 self.tr( |
246 '<p>The "Calliope mini" is not ready for flashing' |
243 '<p>The "Calliope mini" is not ready for flashing' |
247 ' the DAPLink firmware. Follow these' |
244 " the DAPLink firmware. Follow these" |
248 ' instructions. </p>' |
245 " instructions. </p>" |
249 '<ul>' |
246 "<ul>" |
250 '<li>unplug USB cable and any batteries</li>' |
247 "<li>unplug USB cable and any batteries</li>" |
251 '<li>keep RESET button pressed an plug USB cable' |
248 "<li>keep RESET button pressed an plug USB cable" |
252 ' back in</li>' |
249 " back in</li>" |
253 '<li>a drive called MAINTENANCE should be' |
250 "<li>a drive called MAINTENANCE should be" |
254 ' available</li>' |
251 " available</li>" |
255 '</ul>' |
252 "</ul>" |
256 ) |
253 ), |
257 ) |
254 ) |
258 else: |
255 else: |
259 EricMessageBox.critical( |
256 EricMessageBox.critical( |
260 self.microPython, |
257 self.microPython, |
261 self.tr("Flash MicroPython/Firmware"), |
258 self.tr("Flash MicroPython/Firmware"), |
262 self.tr( |
259 self.tr( |
263 '<p>The "Calliope mini" is not ready for flashing' |
260 '<p>The "Calliope mini" is not ready for flashing' |
264 ' the MicroPython firmware. Please make sure,' |
261 " the MicroPython firmware. Please make sure," |
265 ' that a drive called MINI is available.' |
262 " that a drive called MINI is available." |
266 '</p>' |
263 "</p>" |
267 ) |
264 ), |
268 ) |
265 ) |
269 elif len(deviceDirectories) == 1: |
266 elif len(deviceDirectories) == 1: |
270 downloadsPath = QStandardPaths.standardLocations( |
267 downloadsPath = QStandardPaths.standardLocations( |
271 QStandardPaths.StandardLocation.DownloadLocation)[0] |
268 QStandardPaths.StandardLocation.DownloadLocation |
|
269 )[0] |
272 firmware = EricFileDialog.getOpenFileName( |
270 firmware = EricFileDialog.getOpenFileName( |
273 self.microPython, |
271 self.microPython, |
274 self.tr("Flash MicroPython/Firmware"), |
272 self.tr("Flash MicroPython/Firmware"), |
275 downloadsPath, |
273 downloadsPath, |
276 self.tr("MicroPython/Firmware Files (*.hex *.bin);;" |
274 self.tr("MicroPython/Firmware Files (*.hex *.bin);;" "All Files (*)"), |
277 "All Files (*)")) |
275 ) |
278 if firmware and os.path.exists(firmware): |
276 if firmware and os.path.exists(firmware): |
279 shutil.copy2(firmware, deviceDirectories[0]) |
277 shutil.copy2(firmware, deviceDirectories[0]) |
280 else: |
278 else: |
281 EricMessageBox.warning( |
279 EricMessageBox.warning( |
282 self, |
280 self, |
283 self.tr("Flash MicroPython/Firmware"), |
281 self.tr("Flash MicroPython/Firmware"), |
284 self.tr("There are multiple devices ready for flashing." |
282 self.tr( |
285 " Please make sure, that only one device is prepared.") |
283 "There are multiple devices ready for flashing." |
286 ) |
284 " Please make sure, that only one device is prepared." |
287 |
285 ), |
|
286 ) |
|
287 |
288 @pyqtSlot() |
288 @pyqtSlot() |
289 def __saveMain(self): |
289 def __saveMain(self): |
290 """ |
290 """ |
291 Private slot to copy the current script as 'main.py' onto the |
291 Private slot to copy the current script as 'main.py' onto the |
292 connected device. |
292 connected device. |
293 """ |
293 """ |
294 self.__saveScriptToDevice("main.py") |
294 self.__saveScriptToDevice("main.py") |
295 |
295 |
296 @pyqtSlot() |
296 @pyqtSlot() |
297 def __saveScriptToDevice(self, scriptName=""): |
297 def __saveScriptToDevice(self, scriptName=""): |
298 """ |
298 """ |
299 Private method to save the current script onto the connected |
299 Private method to save the current script onto the connected |
300 device. |
300 device. |
301 |
301 |
302 @param scriptName name of the file on the device |
302 @param scriptName name of the file on the device |
303 @type str |
303 @type str |
304 """ |
304 """ |
305 aw = ericApp().getObject("ViewManager").activeWindow() |
305 aw = ericApp().getObject("ViewManager").activeWindow() |
306 if not aw: |
306 if not aw: |
307 return |
307 return |
308 |
308 |
309 title = ( |
309 title = ( |
310 self.tr("Save Script as '{0}'").format(scriptName) |
310 self.tr("Save Script as '{0}'").format(scriptName) |
311 if scriptName else |
311 if scriptName |
312 self.tr("Save Script") |
312 else self.tr("Save Script") |
313 ) |
313 ) |
314 |
314 |
315 if not (aw.isPyFile() or aw.isMicroPythonFile()): |
315 if not (aw.isPyFile() or aw.isMicroPythonFile()): |
316 yes = EricMessageBox.yesNo( |
316 yes = EricMessageBox.yesNo( |
317 self.microPython, |
317 self.microPython, |
318 title, |
318 title, |
319 self.tr("""The current editor does not contain a Python""" |
319 self.tr( |
320 """ script. Write it anyway?""")) |
320 """The current editor does not contain a Python""" |
|
321 """ script. Write it anyway?""" |
|
322 ), |
|
323 ) |
321 if not yes: |
324 if not yes: |
322 return |
325 return |
323 |
326 |
324 script = aw.text().strip() |
327 script = aw.text().strip() |
325 if not script: |
328 if not script: |
326 EricMessageBox.warning( |
329 EricMessageBox.warning( |
327 self.microPython, |
330 self.microPython, title, self.tr("""The script is empty. Aborting.""") |
328 title, |
331 ) |
329 self.tr("""The script is empty. Aborting.""")) |
|
330 return |
332 return |
331 |
333 |
332 if not scriptName: |
334 if not scriptName: |
333 scriptName = os.path.basename(aw.getFileName()) |
335 scriptName = os.path.basename(aw.getFileName()) |
334 scriptName, ok = QInputDialog.getText( |
336 scriptName, ok = QInputDialog.getText( |
335 self.microPython, |
337 self.microPython, |
336 title, |
338 title, |
337 self.tr("Enter a file name on the device:"), |
339 self.tr("Enter a file name on the device:"), |
338 QLineEdit.EchoMode.Normal, |
340 QLineEdit.EchoMode.Normal, |
339 scriptName) |
341 scriptName, |
|
342 ) |
340 if not ok or not bool(scriptName): |
343 if not ok or not bool(scriptName): |
341 return |
344 return |
342 |
345 |
343 title = self.tr("Save Script as '{0}'").format(scriptName) |
346 title = self.tr("Save Script as '{0}'").format(scriptName) |
344 |
347 |
345 commands = [ |
348 commands = [ |
346 "fd = open('{0}', 'wb')".format(scriptName), |
349 "fd = open('{0}', 'wb')".format(scriptName), |
347 "f = fd.write", |
350 "f = fd.write", |
348 ] |
351 ] |
349 for line in script.splitlines(): |
352 for line in script.splitlines(): |
352 out, err = self.microPython.commandsInterface().execute(commands) |
355 out, err = self.microPython.commandsInterface().execute(commands) |
353 if err: |
356 if err: |
354 EricMessageBox.critical( |
357 EricMessageBox.critical( |
355 self.microPython, |
358 self.microPython, |
356 title, |
359 title, |
357 self.tr("""<p>The script could not be saved to the""" |
360 self.tr( |
358 """ device.</p><p>Reason: {0}</p>""") |
361 """<p>The script could not be saved to the""" |
359 .format(err.decode("utf-8"))) |
362 """ device.</p><p>Reason: {0}</p>""" |
360 |
363 ).format(err.decode("utf-8")), |
|
364 ) |
|
365 |
361 # reset the device |
366 # reset the device |
362 self.__resetDevice() |
367 self.__resetDevice() |
363 |
368 |
364 @pyqtSlot() |
369 @pyqtSlot() |
365 def __resetDevice(self): |
370 def __resetDevice(self): |
366 """ |
371 """ |
367 Private slot to reset the connected device. |
372 Private slot to reset the connected device. |
368 """ |
373 """ |
369 if self.getDeviceType() == "bbc_microbit": |
374 if self.getDeviceType() == "bbc_microbit": |
370 # BBC micro:bit |
375 # BBC micro:bit |
371 self.microPython.commandsInterface().execute([ |
376 self.microPython.commandsInterface().execute( |
372 "import microbit", |
377 [ |
373 "microbit.reset()", |
378 "import microbit", |
374 ]) |
379 "microbit.reset()", |
|
380 ] |
|
381 ) |
375 else: |
382 else: |
376 # Calliope mini |
383 # Calliope mini |
377 self.microPython.commandsInterface().execute([ |
384 self.microPython.commandsInterface().execute( |
378 "import calliope_mini", |
385 [ |
379 "calliope_mini.reset()", |
386 "import calliope_mini", |
380 ]) |
387 "calliope_mini.reset()", |
381 |
388 ] |
|
389 ) |
|
390 |
382 def getDocumentationUrl(self): |
391 def getDocumentationUrl(self): |
383 """ |
392 """ |
384 Public method to get the device documentation URL. |
393 Public method to get the device documentation URL. |
385 |
394 |
386 @return documentation URL of the device |
395 @return documentation URL of the device |
387 @rtype str |
396 @rtype str |
388 """ |
397 """ |
389 if self.getDeviceType() == "bbc_microbit": |
398 if self.getDeviceType() == "bbc_microbit": |
390 # BBC micro:bit |
399 # BBC micro:bit |
391 return Preferences.getMicroPython("MicrobitDocuUrl") |
400 return Preferences.getMicroPython("MicrobitDocuUrl") |
392 else: |
401 else: |
393 # Calliope mini |
402 # Calliope mini |
394 return Preferences.getMicroPython("CalliopeDocuUrl") |
403 return Preferences.getMicroPython("CalliopeDocuUrl") |
395 |
404 |
396 def getDownloadMenuEntries(self): |
405 def getDownloadMenuEntries(self): |
397 """ |
406 """ |
398 Public method to retrieve the entries for the downloads menu. |
407 Public method to retrieve the entries for the downloads menu. |
399 |
408 |
400 @return list of tuples with menu text and URL to be opened for each |
409 @return list of tuples with menu text and URL to be opened for each |
401 entry |
410 entry |
402 @rtype list of tuple of (str, str) |
411 @rtype list of tuple of (str, str) |
403 """ |
412 """ |
404 if self.getDeviceType() == "bbc_microbit": |
413 if self.getDeviceType() == "bbc_microbit": |
405 return [ |
414 return [ |
406 (self.tr("MicroPython Firmware for BBC micro:bit V1"), |
415 ( |
407 Preferences.getMicroPython("MicrobitMicroPythonUrl")), |
416 self.tr("MicroPython Firmware for BBC micro:bit V1"), |
408 (self.tr("MicroPython Firmware for BBC micro:bit V2"), |
417 Preferences.getMicroPython("MicrobitMicroPythonUrl"), |
409 Preferences.getMicroPython("MicrobitV2MicroPythonUrl")), |
418 ), |
410 (self.tr("DAPLink Firmware"), |
419 ( |
411 Preferences.getMicroPython("MicrobitFirmwareUrl")) |
420 self.tr("MicroPython Firmware for BBC micro:bit V2"), |
|
421 Preferences.getMicroPython("MicrobitV2MicroPythonUrl"), |
|
422 ), |
|
423 ( |
|
424 self.tr("DAPLink Firmware"), |
|
425 Preferences.getMicroPython("MicrobitFirmwareUrl"), |
|
426 ), |
412 ] |
427 ] |
413 else: |
428 else: |
414 return [ |
429 return [ |
415 (self.tr("MicroPython Firmware"), |
430 ( |
416 Preferences.getMicroPython("CalliopeMicroPythonUrl")), |
431 self.tr("MicroPython Firmware"), |
417 (self.tr("DAPLink Firmware"), |
432 Preferences.getMicroPython("CalliopeMicroPythonUrl"), |
418 Preferences.getMicroPython("CalliopeDAPLinkUrl")) |
433 ), |
|
434 ( |
|
435 self.tr("DAPLink Firmware"), |
|
436 Preferences.getMicroPython("CalliopeDAPLinkUrl"), |
|
437 ), |
419 ] |
438 ] |