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) |