eric6/MicroPython/MicrobitDevices.py

branch
micropython
changeset 7123
94948e2aa0a5
parent 7114
f416440c8be1
child 7126
376deb7fefe7
equal deleted inserted replaced
7122:8e67ef7975de 7123:94948e2aa0a5
7 Module implementing the device interface class for BBC micro:bit boards. 7 Module implementing the device interface class for BBC micro:bit boards.
8 """ 8 """
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 11
12 import sys
13 import os
14
15 from PyQt5.QtCore import pyqtSlot, QStandardPaths
16
12 from .MicroPythonDevices import MicroPythonDevice 17 from .MicroPythonDevices import MicroPythonDevice
13 from .MicroPythonReplWidget import HAS_QTCHART 18 from .MicroPythonReplWidget import HAS_QTCHART
19
20 from E5Gui import E5MessageBox, E5FileDialog
21 from E5Gui.E5Application import e5App
22 from E5Gui.E5ProcessDialog import E5ProcessDialog
23
24 import Utilities
14 25
15 26
16 class MicrobitDevice(MicroPythonDevice): 27 class MicrobitDevice(MicroPythonDevice):
17 """ 28 """
18 Class implementing the device for BBC micro:bit boards. 29 Class implementing the device for BBC micro:bit boards.
32 """ 43 """
33 Public method to enable the supported action buttons. 44 Public method to enable the supported action buttons.
34 """ 45 """
35 super(MicrobitDevice, self).setButtons() 46 super(MicrobitDevice, self).setButtons()
36 self.microPython.setActionButtons( 47 self.microPython.setActionButtons(
37 repl=True, files=True, chart=HAS_QTCHART) 48 repl=True, chart=HAS_QTCHART)
38 49
39 def forceInterrupt(self): 50 def forceInterrupt(self):
40 """ 51 """
41 Public method to determine the need for an interrupt when opening the 52 Public method to determine the need for an interrupt when opening the
42 serial connection. 53 serial connection.
72 83
73 @return tuple containing a flag indicating it is safe to start a 84 @return tuple containing a flag indicating it is safe to start a
74 File Manager and a reason why it cannot. 85 File Manager and a reason why it cannot.
75 @rtype tuple of (bool, str) 86 @rtype tuple of (bool, str)
76 """ 87 """
77 return True, "" 88 return False, ""
89
90 def getWorkspace(self):
91 """
92 Public method to get the workspace directory.
93
94 @return workspace directory used for saving files
95 @rtype str
96 """
97 # Attempts to find the path on the filesystem that represents the
98 # plugged in MICROBIT board.
99 deviceDirectory = Utilities.findVolume("MICROBIT")
100
101 if deviceDirectory:
102 return deviceDirectory
103 else:
104 # return the default workspace and give the user a warning
105 E5MessageBox.warning(
106 self.microPython,
107 self.tr("Workspace Directory"),
108 self.tr("Could not find an attached BBC micro:bit.\n\n"
109 "Please make sure the device is plugged "
110 "into this computer."))
111
112 return super(MicrobitDevice, self).getWorkspace()
113
114 def hasTimeCommands(self):
115 """
116 Public method to check, if the device supports time commands.
117
118 The default returns True.
119
120 @return flag indicating support for time commands
121 @rtype bool
122 """
123 return False
124
125 def addDeviceMenuEntries(self, menu):
126 """
127 Public method to add device specific entries to the given menu.
128
129 @param menu reference to the context menu
130 @type QMenu
131 """
132 connected = self.microPython.isConnected()
133
134 act = menu.addAction(self.tr("Flash Default MicroPython Firmware"),
135 self.__flashMicroPython)
136 act.setEnabled(not connected)
137 act = menu.addAction(self.tr("Flash Custom MicroPython Firmware"),
138 self.__flashCustomMicroPython)
139 act.setEnabled(not connected)
140 menu.addSeparator()
141 act = menu.addAction(self.tr("Flash Script"), self.__flashScript)
142 act.setToolTip(self.tr(
143 "Flash the current script to the selected device."))
144 act.setEnabled(not connected)
145 act = menu.addAction(self.tr("Save Script as 'main.py'"),
146 self.__saveMain)
147 act.setToolTip(self.tr(
148 "Save the current script as 'main.py' on the connected device"))
149 act.setEnabled(connected)
150 menu.addSeparator()
151 act = menu.addAction(self.tr("Reset micro:bit"), self.__resetDevice)
152 act.setEnabled(connected)
153 menu.addSeparator()
154 menu.addAction(self.tr("Install 'uflash'"), self.__installUflashTool)
155
156 @pyqtSlot()
157 def __flashMicroPython(self):
158 """
159 Private slot to flash the default MicroPython firmware to the device.
160 """
161 flashArgs = [
162 "-u",
163 "-m", "uflash",
164 ]
165 dlg = E5ProcessDialog(self.tr("'uflash' Output"),
166 self.tr("Flash Default MicroPython Firmware"))
167 res = dlg.startProcess(sys.executable, flashArgs)
168 if res:
169 dlg.exec_()
170
171 @pyqtSlot()
172 def __flashCustomMicroPython(self):
173 """
174 Private slot to flash a custom MicroPython firmware to the device.
175 """
176 downloadsPath = QStandardPaths.standardLocations(
177 QStandardPaths.DownloadLocation)[0]
178 firmware = E5FileDialog.getOpenFileName(
179 None,
180 self.tr("Flash Custom MicroPython Firmware"),
181 downloadsPath,
182 self.tr("MicroPython Firmware Files (*.hex);;All Files (*)"))
183 if firmware and os.path.exists(firmware):
184 flashArgs = [
185 "-u",
186 "-m", "uflash",
187 "--runtime", firmware,
188 ]
189 dlg = E5ProcessDialog(
190 self.tr("'uflash' Output"),
191 self.tr("Flash Default MicroPython Firmware"))
192 res = dlg.startProcess(sys.executable, flashArgs)
193 if res:
194 dlg.exec_()
195
196 @pyqtSlot()
197 def __flashScript(self):
198 """
199 Private slot to flash the current script onto the selected device.
200 """
201 aw = e5App().getObject("ViewManager").activeWindow()
202 if not aw:
203 return
204
205 if not (aw.isPy3File() or aw.isPy2File()):
206 yes = E5MessageBox.yesNo(
207 None,
208 self.tr("Flash Script"),
209 self.tr("""The current editor does not contain a Python"""
210 """ script. Flash it anyway?"""))
211 if not yes:
212 return
213
214 script = aw.text().strip()
215 if not script:
216 E5MessageBox.warning(
217 self,
218 self.tr("Flash Script"),
219 self.tr("""The script is empty. Aborting."""))
220 return
221
222 if aw.checkDirty():
223 filename = aw.getFileName()
224 flashArgs = [
225 "-u",
226 "-m", "uflash",
227 filename,
228 ]
229 dlg = E5ProcessDialog(self.tr("'uflash' Output"),
230 self.tr("Flash Script"))
231 res = dlg.startProcess(sys.executable, flashArgs)
232 if res:
233 dlg.exec_()
234
235 @pyqtSlot()
236 def __saveMain(self):
237 """
238 Private slot to copy the current script as 'main.py' onto the
239 connected device.
240 """
241 aw = e5App().getObject("ViewManager").activeWindow()
242 if not aw:
243 return
244
245 if not (aw.isPy3File() or aw.isPy2File()):
246 yes = E5MessageBox.yesNo(
247 None,
248 self.tr("Save Script as 'main.py'"),
249 self.tr("""The current editor does not contain a Python"""
250 """ script. Write it anyway?"""))
251 if not yes:
252 return
253
254 script = aw.text().strip()
255 if not script:
256 E5MessageBox.warning(
257 self,
258 self.tr("Save Script as 'main.py'"),
259 self.tr("""The script is empty. Aborting."""))
260 return
261
262 commands = [
263 "fd = open('main.py', 'wb')",
264 "f = fd.write",
265 ]
266 for line in script.splitlines():
267 commands.append("f(" + repr(line + "\n") + ")")
268 commands.append("fd.close()")
269 out, err = self.microPython.commandsInterface().execute(commands)
270 if err:
271 E5MessageBox.critical(
272 self,
273 self.tr("Save Script as 'main.py'"),
274 self.tr("""<p>The script could not be saved to the"""
275 """ device.</p><p>Reason: {0}</p>""")
276 .format(err.decode("utf-8")))
277
278 # reset the device
279 self.microPython.commandsInterface().execute([
280 "import microbit",
281 "microbit.reset()",
282 ])
283
284 @pyqtSlot()
285 def __resetDevice(self):
286 """
287 Private slot to reset the connected device.
288 """
289 self.microPython.commandsInterface().execute([
290 "import microbit",
291 "microbit.reset()",
292 ])
293
294 @pyqtSlot()
295 def __installUflashTool(self):
296 """
297 Private slot to install the uflash package via pip.
298 """
299 pip = e5App().getObject("Pip")
300 pip.installPackages(["uflash"], interpreter=sys.executable)

eric ide

mercurial