37 <li>rm: remove a file from the connected device</li> |
42 <li>rm: remove a file from the connected device</li> |
38 <li>rmrf: remove a file/directory recursively (like 'rm -rf' in bash) |
43 <li>rmrf: remove a file/directory recursively (like 'rm -rf' in bash) |
39 <li>mkdir: create a new directory</li> |
44 <li>mkdir: create a new directory</li> |
40 <li>rmdir: remove an empty directory</li> |
45 <li>rmdir: remove an empty directory</li> |
41 </ul> |
46 </ul> |
42 |
47 |
43 There are additional commands related to time and version. |
48 There are additional commands related to time and version. |
44 <ul> |
49 <ul> |
45 <li>version: get version info about MicroPython</li> |
50 <li>version: get version info about MicroPython</li> |
46 <li>getImplementation: get some implementation information</li> |
51 <li>getImplementation: get some implementation information</li> |
47 <li>syncTime: synchronize the time of the connected device</li> |
52 <li>syncTime: synchronize the time of the connected device</li> |
48 <li>showTime: show the current time of the connected device</li> |
53 <li>showTime: show the current time of the connected device</li> |
49 </ul> |
54 </ul> |
50 |
55 |
51 @signal executeAsyncFinished() emitted to indicate the end of an |
56 @signal executeAsyncFinished() emitted to indicate the end of an |
52 asynchronously executed list of commands (e.g. a script) |
57 asynchronously executed list of commands (e.g. a script) |
53 @signal dataReceived(data) emitted to send data received via the serial |
58 @signal dataReceived(data) emitted to send data received via the serial |
54 connection for further processing |
59 connection for further processing |
55 """ |
60 """ |
|
61 |
56 executeAsyncFinished = pyqtSignal() |
62 executeAsyncFinished = pyqtSignal() |
57 dataReceived = pyqtSignal(bytes) |
63 dataReceived = pyqtSignal(bytes) |
58 |
64 |
59 def __init__(self, parent=None): |
65 def __init__(self, parent=None): |
60 """ |
66 """ |
61 Constructor |
67 Constructor |
62 |
68 |
63 @param parent reference to the parent object |
69 @param parent reference to the parent object |
64 @type QObject |
70 @type QObject |
65 """ |
71 """ |
66 super().__init__(parent) |
72 super().__init__(parent) |
67 |
73 |
68 self.__repl = parent |
74 self.__repl = parent |
69 |
75 |
70 self.__blockReadyRead = False |
76 self.__blockReadyRead = False |
71 |
77 |
72 self.__serial = MicroPythonSerialPort( |
78 self.__serial = MicroPythonSerialPort( |
73 timeout=Preferences.getMicroPython("SerialTimeout"), |
79 timeout=Preferences.getMicroPython("SerialTimeout"), parent=self |
74 parent=self) |
80 ) |
75 self.__serial.readyRead.connect(self.__readSerial) |
81 self.__serial.readyRead.connect(self.__readSerial) |
76 |
82 |
77 @pyqtSlot() |
83 @pyqtSlot() |
78 def __readSerial(self): |
84 def __readSerial(self): |
79 """ |
85 """ |
80 Private slot to read all available serial data and emit it with the |
86 Private slot to read all available serial data and emit it with the |
81 "dataReceived" signal for further processing. |
87 "dataReceived" signal for further processing. |
82 """ |
88 """ |
83 if not self.__blockReadyRead: |
89 if not self.__blockReadyRead: |
84 data = bytes(self.__serial.readAll()) |
90 data = bytes(self.__serial.readAll()) |
85 self.dataReceived.emit(data) |
91 self.dataReceived.emit(data) |
86 |
92 |
87 @pyqtSlot() |
93 @pyqtSlot() |
88 def connectToDevice(self, port): |
94 def connectToDevice(self, port): |
89 """ |
95 """ |
90 Public slot to start the manager. |
96 Public slot to start the manager. |
91 |
97 |
92 @param port name of the port to be used |
98 @param port name of the port to be used |
93 @type str |
99 @type str |
94 @return flag indicating success |
100 @return flag indicating success |
95 @rtype bool |
101 @rtype bool |
96 """ |
102 """ |
97 return self.__serial.openSerialLink(port) |
103 return self.__serial.openSerialLink(port) |
98 |
104 |
99 @pyqtSlot() |
105 @pyqtSlot() |
100 def disconnectFromDevice(self): |
106 def disconnectFromDevice(self): |
101 """ |
107 """ |
102 Public slot to stop the thread. |
108 Public slot to stop the thread. |
103 """ |
109 """ |
104 self.__serial.closeSerialLink() |
110 self.__serial.closeSerialLink() |
105 |
111 |
106 def isConnected(self): |
112 def isConnected(self): |
107 """ |
113 """ |
108 Public method to get the connection status. |
114 Public method to get the connection status. |
109 |
115 |
110 @return flag indicating the connection status |
116 @return flag indicating the connection status |
111 @rtype bool |
117 @rtype bool |
112 """ |
118 """ |
113 return self.__serial.isConnected() |
119 return self.__serial.isConnected() |
114 |
120 |
115 @pyqtSlot() |
121 @pyqtSlot() |
116 def handlePreferencesChanged(self): |
122 def handlePreferencesChanged(self): |
117 """ |
123 """ |
118 Public slot to handle a change of the preferences. |
124 Public slot to handle a change of the preferences. |
119 """ |
125 """ |
120 self.__serial.setTimeout(Preferences.getMicroPython("SerialTimeout")) |
126 self.__serial.setTimeout(Preferences.getMicroPython("SerialTimeout")) |
121 |
127 |
122 def write(self, data): |
128 def write(self, data): |
123 """ |
129 """ |
124 Public method to write data to the connected device. |
130 Public method to write data to the connected device. |
125 |
131 |
126 @param data data to be written |
132 @param data data to be written |
127 @type bytes or bytearray |
133 @type bytes or bytearray |
128 """ |
134 """ |
129 self.__serial.isConnected() and self.__serial.write(data) |
135 self.__serial.isConnected() and self.__serial.write(data) |
130 |
136 |
131 def __rawOn(self): |
137 def __rawOn(self): |
132 """ |
138 """ |
133 Private method to switch the connected device to 'raw' mode. |
139 Private method to switch the connected device to 'raw' mode. |
134 |
140 |
135 Note: switching to raw mode is done with synchronous writes. |
141 Note: switching to raw mode is done with synchronous writes. |
136 |
142 |
137 @return flag indicating success |
143 @return flag indicating success |
138 @@rtype bool |
144 @@rtype bool |
139 """ |
145 """ |
140 if not self.__serial: |
146 if not self.__serial: |
141 return False |
147 return False |
142 |
148 |
143 rawReplMessage = b"raw REPL; CTRL-B to exit\r\n>" |
149 rawReplMessage = b"raw REPL; CTRL-B to exit\r\n>" |
144 |
150 |
145 self.__serial.write(b"\x02") # end raw mode if required |
151 self.__serial.write(b"\x02") # end raw mode if required |
146 written = self.__serial.waitForBytesWritten(500) |
152 written = self.__serial.waitForBytesWritten(500) |
147 # time out after 500ms if device is not responding |
153 # time out after 500ms if device is not responding |
148 if not written: |
154 if not written: |
149 return False |
155 return False |
150 for _i in range(3): |
156 for _i in range(3): |
153 written = self.__serial.waitForBytesWritten(500) |
159 written = self.__serial.waitForBytesWritten(500) |
154 # time out after 500ms if device is not responding |
160 # time out after 500ms if device is not responding |
155 if not written: |
161 if not written: |
156 return False |
162 return False |
157 QThread.msleep(10) |
163 QThread.msleep(10) |
158 self.__serial.readAll() # read all data and discard it |
164 self.__serial.readAll() # read all data and discard it |
159 self.__serial.write(b"\r\x01") # send CTRL-A to enter raw mode |
165 self.__serial.write(b"\r\x01") # send CTRL-A to enter raw mode |
160 self.__serial.readUntil(rawReplMessage) |
166 self.__serial.readUntil(rawReplMessage) |
161 if self.__serial.hasTimedOut(): |
167 if self.__serial.hasTimedOut(): |
162 # it timed out; try it again and than fail |
168 # it timed out; try it again and than fail |
163 self.__serial.write(b"\r\x01") # send CTRL-A again |
169 self.__serial.write(b"\r\x01") # send CTRL-A again |
164 self.__serial.readUntil(rawReplMessage) |
170 self.__serial.readUntil(rawReplMessage) |
165 if self.__serial.hasTimedOut(): |
171 if self.__serial.hasTimedOut(): |
166 return False |
172 return False |
167 |
173 |
168 QCoreApplication.processEvents( |
174 QCoreApplication.processEvents( |
169 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) |
175 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents |
170 self.__serial.readAll() # read all data and discard it |
176 ) |
|
177 self.__serial.readAll() # read all data and discard it |
171 return True |
178 return True |
172 |
179 |
173 def __rawOff(self): |
180 def __rawOff(self): |
174 """ |
181 """ |
175 Private method to switch 'raw' mode off. |
182 Private method to switch 'raw' mode off. |
176 """ |
183 """ |
177 if self.__serial: |
184 if self.__serial: |
178 self.__serial.write(b"\x02") # send CTRL-B to cancel raw mode |
185 self.__serial.write(b"\x02") # send CTRL-B to cancel raw mode |
179 self.__serial.readUntil(b">>> ") # read until Python prompt |
186 self.__serial.readUntil(b">>> ") # read until Python prompt |
180 self.__serial.readAll() # read all data and discard it |
187 self.__serial.readAll() # read all data and discard it |
181 |
188 |
182 def execute(self, commands): |
189 def execute(self, commands): |
183 """ |
190 """ |
184 Public method to send commands to the connected device and return the |
191 Public method to send commands to the connected device and return the |
185 result. |
192 result. |
186 |
193 |
187 If no serial connection is available, empty results will be returned. |
194 If no serial connection is available, empty results will be returned. |
188 |
195 |
189 @param commands list of commands to be executed |
196 @param commands list of commands to be executed |
190 @type str |
197 @type str |
191 @return tuple containing stdout and stderr output of the device |
198 @return tuple containing stdout and stderr output of the device |
192 @rtype tuple of (bytes, bytes) |
199 @rtype tuple of (bytes, bytes) |
193 """ |
200 """ |
194 if not self.__serial: |
201 if not self.__serial: |
195 return b"", b"" |
202 return b"", b"" |
196 |
203 |
197 if not self.__serial.isConnected(): |
204 if not self.__serial.isConnected(): |
198 return b"", b"Device not connected or not switched on." |
205 return b"", b"Device not connected or not switched on." |
199 |
206 |
200 result = bytearray() |
207 result = bytearray() |
201 err = b"" |
208 err = b"" |
202 |
209 |
203 # switch on raw mode |
210 # switch on raw mode |
204 self.__blockReadyRead = True |
211 self.__blockReadyRead = True |
205 ok = self.__rawOn() |
212 ok = self.__rawOn() |
206 if not ok: |
213 if not ok: |
207 self.__blockReadyRead = False |
214 self.__blockReadyRead = False |
208 return ( |
215 return (b"", b"Could not switch to raw mode. Is the device switched on?") |
209 b"", |
216 |
210 b"Could not switch to raw mode. Is the device switched on?" |
|
211 ) |
|
212 |
|
213 # send commands |
217 # send commands |
214 QThread.msleep(10) |
218 QThread.msleep(10) |
215 for command in commands: |
219 for command in commands: |
216 if command: |
220 if command: |
217 commandBytes = command.encode("utf-8") |
221 commandBytes = command.encode("utf-8") |
218 self.__serial.write(commandBytes + b"\x04") |
222 self.__serial.write(commandBytes + b"\x04") |
219 QCoreApplication.processEvents( |
223 QCoreApplication.processEvents( |
220 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) |
224 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents |
|
225 ) |
221 ok = self.__serial.readUntil(b"OK") |
226 ok = self.__serial.readUntil(b"OK") |
222 if ok != b"OK": |
227 if ok != b"OK": |
223 return ( |
228 return ( |
224 b"", |
229 b"", |
225 "Expected 'OK', got '{0}', followed by '{1}'".format( |
230 "Expected 'OK', got '{0}', followed by '{1}'".format( |
226 ok, self.__serial.readAll()).encode("utf-8") |
231 ok, self.__serial.readAll() |
|
232 ).encode("utf-8"), |
227 ) |
233 ) |
228 |
234 |
229 # read until prompt |
235 # read until prompt |
230 response = self.__serial.readUntil(b"\x04>") |
236 response = self.__serial.readUntil(b"\x04>") |
231 if self.__serial.hasTimedOut(): |
237 if self.__serial.hasTimedOut(): |
232 self.__blockReadyRead = False |
238 self.__blockReadyRead = False |
233 return b"", b"Timeout while processing commands." |
239 return b"", b"Timeout while processing commands." |
238 else: |
244 else: |
239 err = b"invalid response received: " + response |
245 err = b"invalid response received: " + response |
240 if err: |
246 if err: |
241 self.__blockReadyRead = False |
247 self.__blockReadyRead = False |
242 return b"", err |
248 return b"", err |
243 |
249 |
244 # switch off raw mode |
250 # switch off raw mode |
245 QThread.msleep(10) |
251 QThread.msleep(10) |
246 self.__rawOff() |
252 self.__rawOff() |
247 self.__blockReadyRead = False |
253 self.__blockReadyRead = False |
248 |
254 |
249 return bytes(result), err |
255 return bytes(result), err |
250 |
256 |
251 def executeAsync(self, commandsList): |
257 def executeAsync(self, commandsList): |
252 """ |
258 """ |
253 Public method to execute a series of commands over a period of time |
259 Public method to execute a series of commands over a period of time |
254 without returning any result (asynchronous execution). |
260 without returning any result (asynchronous execution). |
255 |
261 |
256 @param commandsList list of commands to be execute on the device |
262 @param commandsList list of commands to be execute on the device |
257 @type list of bytes |
263 @type list of bytes |
258 """ |
264 """ |
|
265 |
259 def remainingTask(commands): |
266 def remainingTask(commands): |
260 self.executeAsync(commands) |
267 self.executeAsync(commands) |
261 |
268 |
262 if commandsList: |
269 if commandsList: |
263 command = commandsList[0] |
270 command = commandsList[0] |
264 self.__serial.write(command) |
271 self.__serial.write(command) |
265 remainder = commandsList[1:] |
272 remainder = commandsList[1:] |
266 QTimer.singleShot(2, lambda: remainingTask(remainder)) |
273 QTimer.singleShot(2, lambda: remainingTask(remainder)) |
267 else: |
274 else: |
268 self.executeAsyncFinished.emit() |
275 self.executeAsyncFinished.emit() |
269 |
276 |
270 def __shortError(self, error): |
277 def __shortError(self, error): |
271 """ |
278 """ |
272 Private method to create a shortened error message. |
279 Private method to create a shortened error message. |
273 |
280 |
274 @param error verbose error message |
281 @param error verbose error message |
275 @type bytes |
282 @type bytes |
276 @return shortened error message |
283 @return shortened error message |
277 @rtype str |
284 @rtype str |
278 """ |
285 """ |
337 """ |
344 """ |
338 commands = ( |
345 commands = ( |
339 # BBC micro:bit does not support directories |
346 # BBC micro:bit does not support directories |
340 [ |
347 [ |
341 "import os as __os_", |
348 "import os as __os_", |
342 "\n".join([ |
349 "\n".join( |
343 "def is_visible(filename, showHidden):", |
350 [ |
344 " return showHidden or " |
351 "def is_visible(filename, showHidden):", |
345 "(filename[0] != '.' and filename[-1] != '~')", |
352 " return showHidden or " |
346 ]), |
353 "(filename[0] != '.' and filename[-1] != '~')", |
347 "\n".join([ |
354 ] |
348 "def stat(filename):", |
355 ), |
349 " size = __os_.size(filename)", |
356 "\n".join( |
350 " return (0, 0, 0, 0, 0, 0, size, 0, 0, 0)" |
357 [ |
351 ]), |
358 "def stat(filename):", |
352 "\n".join([ |
359 " size = __os_.size(filename)", |
353 "def listdir_stat(showHidden):", |
360 " return (0, 0, 0, 0, 0, 0, size, 0, 0, 0)", |
354 " files = __os_.listdir()", |
361 ] |
355 " return list((f, stat(f)) for f in files if" |
362 ), |
356 " is_visible(f,showHidden))", |
363 "\n".join( |
357 ]), |
364 [ |
|
365 "def listdir_stat(showHidden):", |
|
366 " files = __os_.listdir()", |
|
367 " return list((f, stat(f)) for f in files if" |
|
368 " is_visible(f,showHidden))", |
|
369 ] |
|
370 ), |
358 "print(listdir_stat({0}))".format(showHidden), |
371 "print(listdir_stat({0}))".format(showHidden), |
359 "del __os_, stat, listdir_stat, is_visible", |
372 "del __os_, stat, listdir_stat, is_visible", |
360 ] |
373 ] |
361 if self.__repl.isMicrobit() else |
374 if self.__repl.isMicrobit() |
362 [ |
375 else [ |
363 "import os as __os_", |
376 "import os as __os_", |
364 "\n".join([ |
377 "\n".join( |
365 "def is_visible(filename, showHidden):", |
378 [ |
366 " return showHidden or " |
379 "def is_visible(filename, showHidden):", |
367 "(filename[0] != '.' and filename[-1] != '~')", |
380 " return showHidden or " |
368 ]), |
381 "(filename[0] != '.' and filename[-1] != '~')", |
369 "\n".join([ |
382 ] |
370 "def stat(filename):", |
383 ), |
371 " try:", |
384 "\n".join( |
372 " rstat = __os_.lstat(filename)", |
385 [ |
373 " except:", |
386 "def stat(filename):", |
374 " rstat = __os_.stat(filename)", |
387 " try:", |
375 " return tuple(rstat)", |
388 " rstat = __os_.lstat(filename)", |
376 ]), |
389 " except:", |
377 "\n".join([ |
390 " rstat = __os_.stat(filename)", |
378 "def listdir_stat(dirname, showHidden):", |
391 " return tuple(rstat)", |
379 " try:", |
392 ] |
380 " files = __os_.listdir(dirname)", |
393 ), |
381 " except OSError:", |
394 "\n".join( |
382 " return []", |
395 [ |
383 " if dirname in ('', '/'):", |
396 "def listdir_stat(dirname, showHidden):", |
384 " return list((f, stat(f)) for f in files if" |
397 " try:", |
385 " is_visible(f, showHidden))", |
398 " files = __os_.listdir(dirname)", |
386 " return list((f, stat(dirname + '/' + f))" |
399 " except OSError:", |
387 " for f in files if is_visible(f, showHidden))", |
400 " return []", |
388 ]), |
401 " if dirname in ('', '/'):", |
|
402 " return list((f, stat(f)) for f in files if" |
|
403 " is_visible(f, showHidden))", |
|
404 " return list((f, stat(dirname + '/' + f))" |
|
405 " for f in files if is_visible(f, showHidden))", |
|
406 ] |
|
407 ), |
389 "print(listdir_stat('{0}', {1}))".format(dirname, showHidden), |
408 "print(listdir_stat('{0}', {1}))".format(dirname, showHidden), |
390 "del __os_, stat, listdir_stat, is_visible", |
409 "del __os_, stat, listdir_stat, is_visible", |
391 ] |
410 ] |
392 ) |
411 ) |
393 out, err = self.execute(commands) |
412 out, err = self.execute(commands) |
475 @exception OSError raised to indicate an issue with the device |
494 @exception OSError raised to indicate an issue with the device |
476 """ |
495 """ |
477 if name: |
496 if name: |
478 commands = [ |
497 commands = [ |
479 "import os as __os_", |
498 "import os as __os_", |
480 "\n".join([ |
499 "\n".join( |
481 "def remove_file(name, recursive=False, force=False):", |
500 [ |
482 " try:", |
501 "def remove_file(name, recursive=False, force=False):", |
483 " mode = __os_.stat(name)[0]", |
502 " try:", |
484 " if mode & 0x4000 != 0:", |
503 " mode = __os_.stat(name)[0]", |
485 " if recursive:", |
504 " if mode & 0x4000 != 0:", |
486 " for file in __os_.listdir(name):", |
505 " if recursive:", |
487 " success = remove_file(" |
506 " for file in __os_.listdir(name):", |
488 "name + '/' + file, recursive, force)", |
507 " success = remove_file(" |
489 " if not success and not force:", |
508 "name + '/' + file, recursive, force)", |
490 " return False", |
509 " if not success and not force:", |
491 " __os_.rmdir(name)", |
510 " return False", |
492 " else:", |
511 " __os_.rmdir(name)", |
493 " if not force:", |
512 " else:", |
494 " return False", |
513 " if not force:", |
495 " else:", |
514 " return False", |
496 " __os_.remove(name)", |
515 " else:", |
497 " except:", |
516 " __os_.remove(name)", |
498 " if not force:", |
517 " except:", |
499 " return False", |
518 " if not force:", |
500 " return True", |
519 " return False", |
501 ]), |
520 " return True", |
502 "print(remove_file('{0}', {1}, {2}))".format(name, recursive, |
521 ] |
503 force), |
522 ), |
|
523 "print(remove_file('{0}', {1}, {2}))".format(name, recursive, force), |
504 "del __os_, remove_file", |
524 "del __os_, remove_file", |
505 ] |
525 ] |
506 out, err = self.execute(commands) |
526 out, err = self.execute(commands) |
507 if err: |
527 if err: |
508 raise OSError(self.__shortError(err)) |
528 raise OSError(self.__shortError(err)) |
509 return ast.literal_eval(out.decode("utf-8")) |
529 return ast.literal_eval(out.decode("utf-8")) |
510 |
530 |
511 return False |
531 return False |
512 |
532 |
513 def mkdir(self, dirname): |
533 def mkdir(self, dirname): |
514 """ |
534 """ |
515 Public method to create a new directory. |
535 Public method to create a new directory. |
516 |
536 |
517 @param dirname name of the directory to create |
537 @param dirname name of the directory to create |
518 @type str |
538 @type str |
519 @exception OSError raised to indicate an issue with the device |
539 @exception OSError raised to indicate an issue with the device |
520 """ |
540 """ |
521 if dirname: |
541 if dirname: |
543 "del __os_", |
563 "del __os_", |
544 ] |
564 ] |
545 out, err = self.execute(commands) |
565 out, err = self.execute(commands) |
546 if err: |
566 if err: |
547 raise OSError(self.__shortError(err)) |
567 raise OSError(self.__shortError(err)) |
548 |
568 |
549 def put(self, hostFileName, deviceFileName=None): |
569 def put(self, hostFileName, deviceFileName=None): |
550 """ |
570 """ |
551 Public method to copy a local file to the connected device. |
571 Public method to copy a local file to the connected device. |
552 |
572 |
553 @param hostFileName name of the file to be copied |
573 @param hostFileName name of the file to be copied |
554 @type str |
574 @type str |
555 @param deviceFileName name of the file to copy to |
575 @param deviceFileName name of the file to copy to |
556 @type str |
576 @type str |
557 @return flag indicating success |
577 @return flag indicating success |
558 @rtype bool |
578 @rtype bool |
559 @exception OSError raised to indicate an issue with the device |
579 @exception OSError raised to indicate an issue with the device |
560 """ |
580 """ |
561 if not os.path.isfile(hostFileName): |
581 if not os.path.isfile(hostFileName): |
562 raise OSError("No such file: {0}".format(hostFileName)) |
582 raise OSError("No such file: {0}".format(hostFileName)) |
563 |
583 |
564 with open(hostFileName, "rb") as hostFile: |
584 with open(hostFileName, "rb") as hostFile: |
565 content = hostFile.read() |
585 content = hostFile.read() |
566 # convert eol '\r' |
586 # convert eol '\r' |
567 content = content.replace(b"\r\n", b"\r") |
587 content = content.replace(b"\r\n", b"\r") |
568 content = content.replace(b"\n", b"\r") |
588 content = content.replace(b"\n", b"\r") |
569 |
589 |
570 if not deviceFileName: |
590 if not deviceFileName: |
571 deviceFileName = os.path.basename(hostFileName) |
591 deviceFileName = os.path.basename(hostFileName) |
572 |
592 |
573 commands = [ |
593 commands = [ |
574 "fd = open('{0}', 'wb')".format(deviceFileName), |
594 "fd = open('{0}', 'wb')".format(deviceFileName), |
575 "f = fd.write", |
595 "f = fd.write", |
576 ] |
596 ] |
577 while content: |
597 while content: |
578 chunk = content[:64] |
598 chunk = content[:64] |
579 commands.append("f(" + repr(chunk) + ")") |
599 commands.append("f(" + repr(chunk) + ")") |
580 content = content[64:] |
600 content = content[64:] |
581 commands.extend([ |
601 commands.extend( |
582 "fd.close()", |
602 [ |
583 "del f, fd", |
603 "fd.close()", |
584 ]) |
604 "del f, fd", |
585 |
605 ] |
|
606 ) |
|
607 |
586 out, err = self.execute(commands) |
608 out, err = self.execute(commands) |
587 if err: |
609 if err: |
588 raise OSError(self.__shortError(err)) |
610 raise OSError(self.__shortError(err)) |
589 return True |
611 return True |
590 |
612 |
591 def get(self, deviceFileName, hostFileName=None): |
613 def get(self, deviceFileName, hostFileName=None): |
592 """ |
614 """ |
593 Public method to copy a file from the connected device. |
615 Public method to copy a file from the connected device. |
594 |
616 |
595 @param deviceFileName name of the file to copy |
617 @param deviceFileName name of the file to copy |
596 @type str |
618 @type str |
597 @param hostFileName name of the file to copy to |
619 @param hostFileName name of the file to copy to |
598 @type str |
620 @type str |
599 @return flag indicating success |
621 @return flag indicating success |
600 @rtype bool |
622 @rtype bool |
601 @exception OSError raised to indicate an issue with the device |
623 @exception OSError raised to indicate an issue with the device |
602 """ |
624 """ |
603 if not hostFileName: |
625 if not hostFileName: |
604 hostFileName = deviceFileName |
626 hostFileName = deviceFileName |
605 |
627 |
606 commands = [ |
628 commands = [ |
607 "\n".join([ |
629 "\n".join( |
608 "def send_data():", |
630 [ |
609 " try:", |
631 "def send_data():", |
610 " from microbit import uart as u", |
632 " try:", |
611 " except ImportError:", |
633 " from microbit import uart as u", |
612 " try:", |
634 " except ImportError:", |
613 " from machine import UART", |
635 " try:", |
614 " u = UART(0, {0})".format(115200), |
636 " from machine import UART", |
615 " except Exception:", |
637 " u = UART(0, {0})".format(115200), |
616 " try:", |
638 " except Exception:", |
617 " from sys import stdout as u", |
639 " try:", |
618 " except Exception:", |
640 " from sys import stdout as u", |
619 " raise Exception('Could not find UART module" |
641 " except Exception:", |
620 " in device.')", |
642 " raise Exception('Could not find UART module" |
621 " f = open('{0}', 'rb')".format(deviceFileName), |
643 " in device.')", |
622 " r = f.read", |
644 " f = open('{0}', 'rb')".format(deviceFileName), |
623 " result = True", |
645 " r = f.read", |
624 " while result:", |
646 " result = True", |
625 " result = r(32)", |
647 " while result:", |
626 " if result:", |
648 " result = r(32)", |
627 " u.write(result)", |
649 " if result:", |
628 " f.close()", |
650 " u.write(result)", |
629 ]), |
651 " f.close()", |
|
652 ] |
|
653 ), |
630 "send_data()", |
654 "send_data()", |
631 ] |
655 ] |
632 out, err = self.execute(commands) |
656 out, err = self.execute(commands) |
633 if err: |
657 if err: |
634 raise OSError(self.__shortError(err)) |
658 raise OSError(self.__shortError(err)) |
635 |
659 |
636 # write the received bytes to the local file |
660 # write the received bytes to the local file |
637 # convert eol to "\n" |
661 # convert eol to "\n" |
638 out = out.replace(b"\r\n", b"\n") |
662 out = out.replace(b"\r\n", b"\n") |
639 out = out.replace(b"\r", b"\n") |
663 out = out.replace(b"\r", b"\n") |
640 with open(hostFileName, "wb") as hostFile: |
664 with open(hostFileName, "wb") as hostFile: |
641 hostFile.write(out) |
665 hostFile.write(out) |
642 return True |
666 return True |
643 |
667 |
644 def fileSystemInfo(self): |
668 def fileSystemInfo(self): |
645 """ |
669 """ |
646 Public method to obtain information about the currently mounted file |
670 Public method to obtain information about the currently mounted file |
647 systems. |
671 systems. |
648 |
672 |
649 @return tuple of tuples containing the file system name, the total |
673 @return tuple of tuples containing the file system name, the total |
650 size, the used size and the free size |
674 size, the used size and the free size |
651 @rtype tuple of tuples of (str, int, int, int) |
675 @rtype tuple of tuples of (str, int, int, int) |
652 @exception OSError raised to indicate an issue with the device |
676 @exception OSError raised to indicate an issue with the device |
653 """ |
677 """ |
654 commands = [ |
678 commands = [ |
655 "import os as __os_", |
679 "import os as __os_", |
656 "\n".join([ |
680 "\n".join( |
657 "def fsinfo():", |
681 [ |
658 " infolist = []", |
682 "def fsinfo():", |
659 " info = __os_.statvfs('/')", |
683 " infolist = []", |
660 " if info[0] == 0:", |
684 " info = __os_.statvfs('/')", |
661 # assume it is just mount points |
685 " if info[0] == 0:", |
662 " fsnames = __os_.listdir('/')", |
686 # assume it is just mount points |
663 " for fs in fsnames:", |
687 " fsnames = __os_.listdir('/')", |
664 " fs = '/' + fs", |
688 " for fs in fsnames:", |
665 " infolist.append((fs, __os_.statvfs(fs)))", |
689 " fs = '/' + fs", |
666 " else:", |
690 " infolist.append((fs, __os_.statvfs(fs)))", |
667 " infolist.append(('/', info))", |
691 " else:", |
668 " return infolist", |
692 " infolist.append(('/', info))", |
669 ]), |
693 " return infolist", |
|
694 ] |
|
695 ), |
670 "print(fsinfo())", |
696 "print(fsinfo())", |
671 "del __os_, fsinfo", |
697 "del __os_, fsinfo", |
672 ] |
698 ] |
673 out, err = self.execute(commands) |
699 out, err = self.execute(commands) |
674 if err: |
700 if err: |
705 "del __os_", |
731 "del __os_", |
706 ] |
732 ] |
707 out, err = self.execute(commands) |
733 out, err = self.execute(commands) |
708 if err: |
734 if err: |
709 raise OSError(self.__shortError(err)) |
735 raise OSError(self.__shortError(err)) |
710 |
736 |
711 rawOutput = out.decode("utf-8").strip() |
737 rawOutput = out.decode("utf-8").strip() |
712 rawOutput = rawOutput[1:-1] |
738 rawOutput = rawOutput[1:-1] |
713 items = rawOutput.split(",") |
739 items = rawOutput.split(",") |
714 result = {} |
740 result = {} |
715 for item in items: |
741 for item in items: |
716 key, value = item.strip().split("=") |
742 key, value = item.strip().split("=") |
717 result[key.strip()] = value.strip()[1:-1] |
743 result[key.strip()] = value.strip()[1:-1] |
718 return result |
744 return result |
719 |
745 |
720 def getImplementation(self): |
746 def getImplementation(self): |
721 """ |
747 """ |
722 Public method to get some implementation information of the connected |
748 Public method to get some implementation information of the connected |
723 device. |
749 device. |
724 |
750 |
725 @return dictionary containing the implementation information |
751 @return dictionary containing the implementation information |
726 @rtype dict |
752 @rtype dict |
727 @exception OSError raised to indicate an issue with the device |
753 @exception OSError raised to indicate an issue with the device |
728 """ |
754 """ |
729 commands = [ |
755 commands = [ |
730 "import sys as __sys_", |
756 "import sys as __sys_", |
731 "res = {}", # __IGNORE_WARNING_M613__ |
757 "res = {}", # __IGNORE_WARNING_M613__ |
732 "\n".join([ |
758 "\n".join( |
733 "try:", |
759 [ |
734 " res['name'] = __sys_.implementation.name", |
760 "try:", |
735 "except AttributeError:", |
761 " res['name'] = __sys_.implementation.name", |
736 " res['name'] = 'unknown'", |
762 "except AttributeError:", |
737 ]), |
763 " res['name'] = 'unknown'", |
738 "\n".join([ |
764 ] |
739 "try:", |
765 ), |
740 " res['version'] = '.'.join((str(i) for i in" |
766 "\n".join( |
741 " __sys_.implementation.version))", |
767 [ |
742 "except AttributeError:", |
768 "try:", |
743 " res['version'] = 'unknown'", |
769 " res['version'] = '.'.join((str(i) for i in" |
744 ]), |
770 " __sys_.implementation.version))", |
|
771 "except AttributeError:", |
|
772 " res['version'] = 'unknown'", |
|
773 ] |
|
774 ), |
745 "print(res)", |
775 "print(res)", |
746 "del res, __sys_", |
776 "del res, __sys_", |
747 ] |
777 ] |
748 out, err = self.execute(commands) |
778 out, err = self.execute(commands) |
749 if err: |
779 if err: |
750 raise OSError(self.__shortError(err)) |
780 raise OSError(self.__shortError(err)) |
751 return ast.literal_eval(out.decode("utf-8")) |
781 return ast.literal_eval(out.decode("utf-8")) |
752 |
782 |
753 def getBoardInformation(self): |
783 def getBoardInformation(self): |
754 """ |
784 """ |
755 Public method to get some information data of the connected board. |
785 Public method to get some information data of the connected board. |
756 |
786 |
757 @return dictionary containing the determined data |
787 @return dictionary containing the determined data |
758 @rtype dict |
788 @rtype dict |
759 @exception OSError raised to indicate an issue with the device |
789 @exception OSError raised to indicate an issue with the device |
760 """ |
790 """ |
761 commands = [ |
791 commands = [ |
762 "res = {}", # __IGNORE_WARNING_M613__ |
792 "res = {}", # __IGNORE_WARNING_M613__ |
763 |
|
764 "import gc as __gc_", |
793 "import gc as __gc_", |
765 "__gc_.enable()", |
794 "__gc_.enable()", |
766 "__gc_.collect()", |
795 "__gc_.collect()", |
767 "mem_alloc = __gc_.mem_alloc()", |
796 "mem_alloc = __gc_.mem_alloc()", |
768 "mem_free = __gc_.mem_free()", |
797 "mem_free = __gc_.mem_free()", |
771 "res['mem_used_kb'] = mem_alloc / 1024.0", |
800 "res['mem_used_kb'] = mem_alloc / 1024.0", |
772 "res['mem_used_pc'] = mem_alloc / mem_total * 100.0", |
801 "res['mem_used_pc'] = mem_alloc / mem_total * 100.0", |
773 "res['mem_free_kb'] = mem_free / 1024.0", |
802 "res['mem_free_kb'] = mem_free / 1024.0", |
774 "res['mem_free_pc'] = mem_free / mem_total * 100.0", |
803 "res['mem_free_pc'] = mem_free / mem_total * 100.0", |
775 "del __gc_, mem_alloc, mem_free, mem_total", |
804 "del __gc_, mem_alloc, mem_free, mem_total", |
776 |
|
777 "import os as __os_", |
805 "import os as __os_", |
778 "uname = __os_.uname()", |
806 "uname = __os_.uname()", |
779 "res['sysname'] = uname.sysname", |
807 "res['sysname'] = uname.sysname", |
780 "res['nodename'] = uname.nodename", |
808 "res['nodename'] = uname.nodename", |
781 "res['release'] = uname.release", |
809 "res['release'] = uname.release", |
782 "res['version'] = uname.version", |
810 "res['version'] = uname.version", |
783 "res['machine'] = uname.machine", |
811 "res['machine'] = uname.machine", |
784 |
|
785 "import sys as __sys_", |
812 "import sys as __sys_", |
786 "res['py_platform'] = __sys_.platform", |
813 "res['py_platform'] = __sys_.platform", |
787 "res['py_version'] = __sys_.version", |
814 "res['py_version'] = __sys_.version", |
788 "\n".join([ |
815 "\n".join( |
789 "try:", |
816 [ |
790 " res['mpy_name'] = __sys_.implementation.name", |
817 "try:", |
791 "except AttributeError:", |
818 " res['mpy_name'] = __sys_.implementation.name", |
792 " res['mpy_name'] = 'unknown'", |
819 "except AttributeError:", |
793 ]), |
820 " res['mpy_name'] = 'unknown'", |
794 "\n".join([ |
821 ] |
795 "try:", |
822 ), |
796 " res['mpy_version'] = '.'.join((str(i) for i in" |
823 "\n".join( |
797 " __sys_.implementation.version))", |
824 [ |
798 "except AttributeError:", |
825 "try:", |
799 " res['mpy_version'] = 'unknown'", |
826 " res['mpy_version'] = '.'.join((str(i) for i in" |
800 ]), |
827 " __sys_.implementation.version))", |
801 |
828 "except AttributeError:", |
|
829 " res['mpy_version'] = 'unknown'", |
|
830 ] |
|
831 ), |
802 "stat_ = __os_.statvfs('/flash')", |
832 "stat_ = __os_.statvfs('/flash')", |
803 "res['flash_total_kb'] = stat_[2] * stat_[0] / 1024.0", |
833 "res['flash_total_kb'] = stat_[2] * stat_[0] / 1024.0", |
804 "res['flash_free_kb'] = stat_[3] * stat_[0] / 1024.0", |
834 "res['flash_free_kb'] = stat_[3] * stat_[0] / 1024.0", |
805 "res['flash_used_kb'] = res['flash_total_kb'] -" |
835 "res['flash_used_kb'] = res['flash_total_kb'] -" " res['flash_free_kb']", |
806 " res['flash_free_kb']", |
|
807 "res['flash_free_pc'] = res['flash_free_kb'] /" |
836 "res['flash_free_pc'] = res['flash_free_kb'] /" |
808 " res['flash_total_kb'] * 100.0", |
837 " res['flash_total_kb'] * 100.0", |
809 "res['flash_used_pc'] = res['flash_used_kb'] /" |
838 "res['flash_used_pc'] = res['flash_used_kb'] /" |
810 " res['flash_total_kb'] * 100.0", |
839 " res['flash_total_kb'] * 100.0", |
811 |
840 "\n".join( |
812 "\n".join([ |
841 [ |
813 "try:", |
842 "try:", |
814 " import machine as __mc_", |
843 " import machine as __mc_", |
815 " res['mc_frequency_mhz'] = __mc_.freq() / 1000000.0", |
844 " res['mc_frequency_mhz'] = __mc_.freq() / 1000000.0", |
816 " res['mc_id'] = ':'.join(['{0:X}'.format(x)" |
845 " res['mc_id'] = ':'.join(['{0:X}'.format(x)" |
817 " for x in __mc_.unique_id()])", |
846 " for x in __mc_.unique_id()])", |
818 " del __mc_", |
847 " del __mc_", |
819 "except ImportError:", |
848 "except ImportError:", |
820 "\n".join([ |
849 "\n".join( |
821 " try:", |
850 [ |
822 " import microcontroller as __mc_", |
851 " try:", |
823 " res['mc_frequency_mhz'] = __mc_.cpu.frequency" |
852 " import microcontroller as __mc_", |
824 " / 1000000.0", |
853 " res['mc_frequency_mhz'] = __mc_.cpu.frequency" |
825 " res['mc_temp_c'] = __mc_.cpu.temperature", |
854 " / 1000000.0", |
826 " res['mc_id'] = ':'.join(['{0:X}'.format(x)" |
855 " res['mc_temp_c'] = __mc_.cpu.temperature", |
827 " for x in __mc_.cpu.uid])", |
856 " res['mc_id'] = ':'.join(['{0:X}'.format(x)" |
828 " del __mc_", |
857 " for x in __mc_.cpu.uid])", |
829 " except ImportError:", |
858 " del __mc_", |
830 " res['mc_frequency'] = None", |
859 " except ImportError:", |
831 " res['mc_temp'] = None", |
860 " res['mc_frequency'] = None", |
832 ]), |
861 " res['mc_temp'] = None", |
833 ]), |
862 ] |
834 |
863 ), |
835 "\n".join([ |
864 ] |
836 "try:", |
865 ), |
837 " import ulab as __ulab_", |
866 "\n".join( |
838 " res['ulab'] = __ulab_.__version__", |
867 [ |
839 " del __ulab_", |
868 "try:", |
840 "except ImportError:", |
869 " import ulab as __ulab_", |
841 " res['ulab'] = None", |
870 " res['ulab'] = __ulab_.__version__", |
842 ]), |
871 " del __ulab_", |
843 |
872 "except ImportError:", |
|
873 " res['ulab'] = None", |
|
874 ] |
|
875 ), |
844 "print(res)", |
876 "print(res)", |
845 "del res, stat_, __os_, __sys_", |
877 "del res, stat_, __os_, __sys_", |
846 ] |
878 ] |
847 out, err = self.execute(commands) |
879 out, err = self.execute(commands) |
848 if err: |
880 if err: |
849 raise OSError(self.__shortError(err)) |
881 raise OSError(self.__shortError(err)) |
850 return ast.literal_eval(out.decode("utf-8")) |
882 return ast.literal_eval(out.decode("utf-8")) |
851 |
883 |
852 def syncTime(self, deviceType): |
884 def syncTime(self, deviceType): |
853 """ |
885 """ |
854 Public method to set the time of the connected device to the local |
886 Public method to set the time of the connected device to the local |
855 computer's time. |
887 computer's time. |
856 |
888 |
857 @param deviceType type of board to sync time to |
889 @param deviceType type of board to sync time to |
858 @type str |
890 @type str |
859 @exception OSError raised to indicate an issue with the device |
891 @exception OSError raised to indicate an issue with the device |
860 """ |
892 """ |
861 # rtc_time[0] - year 4 digit |
893 # rtc_time[0] - year 4 digit |
872 # The pyb.RTC.datetime function takes the arguments in the |
904 # The pyb.RTC.datetime function takes the arguments in the |
873 # order: (year, month, day, weekday, hour, minute, second, |
905 # order: (year, month, day, weekday, hour, minute, second, |
874 # subseconds) |
906 # subseconds) |
875 # http://docs.micropython.org/en/latest/library/pyb.RTC.html |
907 # http://docs.micropython.org/en/latest/library/pyb.RTC.html |
876 # #pyb.RTC.datetime |
908 # #pyb.RTC.datetime |
877 set_time = "\n".join([ |
909 set_time = "\n".join( |
878 "def set_time(rtc_time):", |
910 [ |
879 " import pyb", |
911 "def set_time(rtc_time):", |
880 " rtc = pyb.RTC()", |
912 " import pyb", |
881 " rtc.datetime(rtc_time[:7] + (0,))", |
913 " rtc = pyb.RTC()", |
882 ]) |
914 " rtc.datetime(rtc_time[:7] + (0,))", |
|
915 ] |
|
916 ) |
883 elif deviceType == "esp": |
917 elif deviceType == "esp": |
884 # The machine.RTC documentation was incorrect and doesn't agree |
918 # The machine.RTC documentation was incorrect and doesn't agree |
885 # with the code, so no link is presented here. The order of the |
919 # with the code, so no link is presented here. The order of the |
886 # arguments is the same as the pyboard except for LoBo MPy. |
920 # arguments is the same as the pyboard except for LoBo MPy. |
887 set_time = "\n".join([ |
921 set_time = "\n".join( |
888 "def set_time(rtc_time):", |
922 [ |
889 " import machine", |
923 "def set_time(rtc_time):", |
890 " rtc = machine.RTC()", |
924 " import machine", |
891 " try:", # ESP8266 may use rtc.datetime() |
925 " rtc = machine.RTC()", |
892 " rtc.datetime(rtc_time[:7] + (0,))", |
926 " try:", # ESP8266 may use rtc.datetime() |
893 " except Exception:", # ESP32 uses rtc.init() |
927 " rtc.datetime(rtc_time[:7] + (0,))", |
894 " import os", |
928 " except Exception:", # ESP32 uses rtc.init() |
895 " if 'LoBo' in os.uname()[0]:", # LoBo MPy |
929 " import os", |
896 " clock_time = rtc_time[:3] +" |
930 " if 'LoBo' in os.uname()[0]:", # LoBo MPy |
897 " rtc_time[4:7] + (rtc_time[3], rtc_time[7])", |
931 " clock_time = rtc_time[:3] +" |
898 " else:", |
932 " rtc_time[4:7] + (rtc_time[3], rtc_time[7])", |
899 " clock_time = rtc_time[:7] + (0,)", |
933 " else:", |
900 " rtc.init(clock_time)", |
934 " clock_time = rtc_time[:7] + (0,)", |
901 ]) |
935 " rtc.init(clock_time)", |
|
936 ] |
|
937 ) |
902 elif deviceType == "circuitpython": |
938 elif deviceType == "circuitpython": |
903 set_time = "\n".join([ |
939 set_time = "\n".join( |
904 "def set_time(rtc_time):", |
940 [ |
905 " import rtc", |
941 "def set_time(rtc_time):", |
906 " import time", |
942 " import rtc", |
907 " clock = rtc.RTC()", |
943 " import time", |
908 " clock_time = rtc_time[:3] + rtc_time[4:7] + (rtc_time[3]," |
944 " clock = rtc.RTC()", |
909 " rtc_time[7], rtc_time[8])", |
945 " clock_time = rtc_time[:3] + rtc_time[4:7] + (rtc_time[3]," |
910 " clock.datetime = time.struct_time(clock_time)", |
946 " rtc_time[7], rtc_time[8])", |
911 ]) |
947 " clock.datetime = time.struct_time(clock_time)", |
|
948 ] |
|
949 ) |
912 elif deviceType in ("bbc_microbit", "calliope"): |
950 elif deviceType in ("bbc_microbit", "calliope"): |
913 # BBC micro:bit and Calliope mini don't support time commands |
951 # BBC micro:bit and Calliope mini don't support time commands |
914 return |
952 return |
915 elif deviceType == "rp2040": |
953 elif deviceType == "rp2040": |
916 # Raspberry Pi Pico (RP2040) - machine.RTC doesn't exist |
954 # Raspberry Pi Pico (RP2040) - machine.RTC doesn't exist |
917 set_time = "\n".join([ |
955 set_time = "\n".join( |
918 "def set_time(rtc_time):", |
956 [ |
919 " setup_0 = rtc_time[0] << 12 | rtc_time[1] << 8 |" |
957 "def set_time(rtc_time):", |
920 " rtc_time[2]", |
958 " setup_0 = rtc_time[0] << 12 | rtc_time[1] << 8 |" |
921 " setup_1 = (rtc_time[3] % 7) << 24 | rtc_time[4] << 16 |" |
959 " rtc_time[2]", |
922 " rtc_time[5] << 8 | rtc_time[6]", |
960 " setup_1 = (rtc_time[3] % 7) << 24 | rtc_time[4] << 16 |" |
923 " machine.mem32[0x4005c004] = setup_0", |
961 " rtc_time[5] << 8 | rtc_time[6]", |
924 " machine.mem32[0x4005c008] = setup_1", |
962 " machine.mem32[0x4005c004] = setup_0", |
925 " machine.mem32[0x4005c00c] |= 0x10", |
963 " machine.mem32[0x4005c008] = setup_1", |
926 ]) |
964 " machine.mem32[0x4005c00c] |= 0x10", |
|
965 ] |
|
966 ) |
927 elif deviceType == "pycom": |
967 elif deviceType == "pycom": |
928 # PyCom's machine.RTC takes its arguments in a slightly |
968 # PyCom's machine.RTC takes its arguments in a slightly |
929 # different order than the official machine.RTC. |
969 # different order than the official machine.RTC. |
930 # (year, month, day, hour, minute, second[, microsecond[, |
970 # (year, month, day, hour, minute, second[, microsecond[, |
931 # tzinfo]]) |
971 # tzinfo]]) |
932 # https://docs.pycom.io/firmwareapi/pycom/machine/rtc/ |
972 # https://docs.pycom.io/firmwareapi/pycom/machine/rtc/ |
933 # #rtc-init-datetime-none-source-rtc-internal-rc |
973 # #rtc-init-datetime-none-source-rtc-internal-rc |
934 set_time = "\n".join([ |
974 set_time = "\n".join( |
935 "def set_time(rtc_time):", |
975 [ |
936 " import pycom", |
976 "def set_time(rtc_time):", |
937 " rtc_time2 = rtc_time[:3] + rtc_time[4:7]", |
977 " import pycom", |
938 " import machine", |
978 " rtc_time2 = rtc_time[:3] + rtc_time[4:7]", |
939 " rtc = machine.RTC()", |
979 " import machine", |
940 " rtc.init(rtc_time2)", |
980 " rtc = machine.RTC()", |
941 ]) |
981 " rtc.init(rtc_time2)", |
|
982 ] |
|
983 ) |
942 else: |
984 else: |
943 # no set_time() support for generic boards |
985 # no set_time() support for generic boards |
944 return |
986 return |
945 |
987 |
946 now = time.localtime(time.time()) |
988 now = time.localtime(time.time()) |
947 commands = [ |
989 commands = [ |
948 set_time, |
990 set_time, |
949 "set_time({0})".format(( |
991 "set_time({0})".format( |
950 now.tm_year, now.tm_mon, now.tm_mday, now.tm_wday + 1, |
992 ( |
951 now.tm_hour, now.tm_min, now.tm_sec, now.tm_yday, now.tm_isdst |
993 now.tm_year, |
952 )), |
994 now.tm_mon, |
|
995 now.tm_mday, |
|
996 now.tm_wday + 1, |
|
997 now.tm_hour, |
|
998 now.tm_min, |
|
999 now.tm_sec, |
|
1000 now.tm_yday, |
|
1001 now.tm_isdst, |
|
1002 ) |
|
1003 ), |
953 "del set_time", |
1004 "del set_time", |
954 ] |
1005 ] |
955 out, err = self.execute(commands) |
1006 out, err = self.execute(commands) |
956 if err: |
1007 if err: |
957 raise OSError(self.__shortError(err)) |
1008 raise OSError(self.__shortError(err)) |
958 |
1009 |
959 def getTime(self): |
1010 def getTime(self): |
960 """ |
1011 """ |
961 Public method to get the current time of the device. |
1012 Public method to get the current time of the device. |
962 |
1013 |
963 @return time of the device |
1014 @return time of the device |
964 @rtype str |
1015 @rtype str |
965 @exception OSError raised to indicate an issue with the device |
1016 @exception OSError raised to indicate an issue with the device |
966 """ |
1017 """ |
967 commands = [ |
1018 commands = [ |
968 "\n".join([ |
1019 "\n".join( |
969 "try:", |
1020 [ |
970 " import rtc as __rtc_", |
1021 "try:", |
971 " print('{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}'" |
1022 " import rtc as __rtc_", |
972 ".format(*__rtc_.RTC().datetime[:6]))", |
1023 " print('{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}'" |
973 " del __rtc_", |
1024 ".format(*__rtc_.RTC().datetime[:6]))", |
974 "except:", |
1025 " del __rtc_", |
975 " import time as __time_", |
1026 "except:", |
976 " try:", |
1027 " import time as __time_", |
977 " print(__time_.strftime('%Y-%m-%d %H:%M:%S'," |
1028 " try:", |
978 # __IGNORE_WARNING_M601__ |
1029 " print(__time_.strftime('%Y-%m-%d %H:%M:%S'," |
979 " __time_.localtime()))", |
1030 # __IGNORE_WARNING_M601__ |
980 " except AttributeError:", |
1031 " __time_.localtime()))", |
981 " tm = __time_.localtime()", |
1032 " except AttributeError:", |
982 " print('{0:04d}-{1:02d}-{2:02d}" |
1033 " tm = __time_.localtime()", |
983 " {3:02d}:{4:02d}:{5:02d}'" |
1034 " print('{0:04d}-{1:02d}-{2:02d}" |
984 ".format(tm[0], tm[1], tm[2], tm[3], tm[4], tm[5]))", |
1035 " {3:02d}:{4:02d}:{5:02d}'" |
985 " del tm", |
1036 ".format(tm[0], tm[1], tm[2], tm[3], tm[4], tm[5]))", |
986 " del __time_" |
1037 " del tm", |
987 ]), |
1038 " del __time_", |
|
1039 ] |
|
1040 ), |
988 ] |
1041 ] |
989 out, err = self.execute(commands) |
1042 out, err = self.execute(commands) |
990 if err: |
1043 if err: |
991 if b"NotImplementedError" in err: |
1044 if b"NotImplementedError" in err: |
992 return "<unsupported> <unsupported>" |
1045 return "<unsupported> <unsupported>" |