90 self.__serial.waitForBytesWritten() |
93 self.__serial.waitForBytesWritten() |
91 QThread.msleep(10) |
94 QThread.msleep(10) |
92 self.__serial.readAll() # read all data and discard it |
95 self.__serial.readAll() # read all data and discard it |
93 self.__serial.write(b"\r\x01") # send CTRL-A to enter raw mode |
96 self.__serial.write(b"\r\x01") # send CTRL-A to enter raw mode |
94 self.__serial.readUntil(rawReplMessage) |
97 self.__serial.readUntil(rawReplMessage) |
|
98 if self.__serial.hasTimedOut(): |
|
99 return False |
95 self.__serial.write(b"\x04") # send CTRL-D to soft reset |
100 self.__serial.write(b"\x04") # send CTRL-D to soft reset |
96 self.__serial.readUntil(softRebootMessage) |
101 self.__serial.readUntil(softRebootMessage) |
|
102 if self.__serial.hasTimedOut(): |
|
103 return False |
97 |
104 |
98 # some MicroPython devices seem to need to be convinced in some |
105 # some MicroPython devices seem to need to be convinced in some |
99 # special way |
106 # special way |
100 data = self.__serial.readUntil(rawReplMessage) |
107 data = self.__serial.readUntil(rawReplMessage) |
|
108 if self.__serial.hasTimedOut(): |
|
109 return False |
101 if not data.endswith(rawReplMessage): |
110 if not data.endswith(rawReplMessage): |
102 self.__serial.write(b"\r\x01") # send CTRL-A again |
111 self.__serial.write(b"\r\x01") # send CTRL-A again |
103 self.__serial.readUntil(rawReplMessage) |
112 self.__serial.readUntil(rawReplMessage) |
|
113 if self.__serial.hasTimedOut(): |
|
114 return False |
104 self.__serial.readAll() # read all data and discard it |
115 self.__serial.readAll() # read all data and discard it |
|
116 return True |
105 |
117 |
106 def __rawOff(self): |
118 def __rawOff(self): |
107 """ |
119 """ |
108 Private method to switch 'raw' mode off. |
120 Private method to switch 'raw' mode off. |
109 """ |
121 """ |
126 return b"", b"" |
138 return b"", b"" |
127 |
139 |
128 result = bytearray() |
140 result = bytearray() |
129 err = b"" |
141 err = b"" |
130 |
142 |
131 self.__rawOn() |
143 ok = self.__rawOn() |
|
144 if not ok: |
|
145 return ( |
|
146 b"", |
|
147 b"Could not switch to raw mode. Is the device switched on?" |
|
148 ) |
|
149 |
132 QThread.msleep(10) |
150 QThread.msleep(10) |
133 for command in commands: |
151 for command in commands: |
134 if command: |
152 if command: |
135 commandBytes = command.encode("utf-8") |
153 commandBytes = command.encode("utf-8") |
136 self.__serial.write(commandBytes + b"\x04") |
154 self.__serial.write(commandBytes + b"\x04") |
137 # read until prompt |
155 # read until prompt |
138 response = self.__serial.readUntil(b"\x04>") |
156 response = self.__serial.readUntil(b"\x04>") |
139 # split stdout, stderr |
157 if self.__serial.hasTimedOut(): |
140 out, err = response[2:-2].split(b"\x04") |
158 return b"", b"Timeout while processing commands." |
141 result += out |
159 if b"\x04" in response[2:-2]: |
|
160 # split stdout, stderr |
|
161 out, err = response[2:-2].split(b"\x04") |
|
162 result += out |
|
163 else: |
|
164 err = b"invalid response received: " + response |
142 if err: |
165 if err: |
143 return b"", err |
166 return b"", err |
144 QThread.msleep(10) |
167 QThread.msleep(10) |
145 self.__rawOff() |
168 self.__rawOff() |
146 |
169 |
509 "def set_time(rtc_time):", |
532 "def set_time(rtc_time):", |
510 " rtc = None", |
533 " rtc = None", |
511 " try:", # Pyboard (it doesn't have machine.RTC()) |
534 " try:", # Pyboard (it doesn't have machine.RTC()) |
512 " import pyb", |
535 " import pyb", |
513 " rtc = pyb.RTC()", |
536 " rtc = pyb.RTC()", |
514 " rtc.datetime(rtc_time)", |
537 " clock_time = rtc_time[:6] + (rtc_time[6] + 1, 0)", |
|
538 " rtc.datetime(clock_time)", |
515 " except:", |
539 " except:", |
516 " try:", |
540 " try:", |
517 " import machine", |
541 " import machine", |
518 " rtc = machine.RTC()", |
542 " rtc = machine.RTC()", |
519 " try:", # ESP8266 uses rtc.datetime() |
543 " try:", # ESP8266 may use rtc.datetime() |
520 " rtc.datetime(rtc_time)", |
544 " clock_time = rtc_time[:6] +" |
|
545 " (rtc_time[6] + 1, 0)", |
|
546 " rtc.datetime(clock_time)", |
521 " except:", # ESP32 uses rtc.init() |
547 " except:", # ESP32 uses rtc.init() |
522 " rtc.init(rtc_time)", |
548 " rtc.init(rtc_time[:6])", |
523 " except:", |
549 " except:", |
524 " pass", |
550 " try:", |
|
551 " import rtc, time", |
|
552 " clock=rtc.RTC()", |
|
553 " clock.datetime = time.struct_time(rtc_time +" |
|
554 " (-1, -1))", |
|
555 " except:", |
|
556 " pass", |
525 ]), |
557 ]), |
526 "set_time({0})".format((now.tm_year, now.tm_mon, now.tm_mday, |
558 "set_time({0})".format((now.tm_year, now.tm_mon, now.tm_mday, |
527 now.tm_wday + 1, now.tm_hour, now.tm_min, |
559 now.tm_hour, now.tm_min, now.tm_sec, |
528 now.tm_sec, 0)) |
560 now.tm_wday)) |
529 ] |
561 ] |
530 out, err = self.__execute(commands) |
562 out, err = self.__execute(commands) |
531 if err: |
563 if err: |
532 raise IOError(self.__shortError(err)) |
564 raise IOError(self.__shortError(err)) |
533 |
565 |
568 @signal deleteFileDone(deviceFile) emitted after the file has been deleted |
600 @signal deleteFileDone(deviceFile) emitted after the file has been deleted |
569 on the connected device |
601 on the connected device |
570 @signal rsyncDone(localName, deviceName) emitted after the rsync operation |
602 @signal rsyncDone(localName, deviceName) emitted after the rsync operation |
571 has been completed |
603 has been completed |
572 @signal rsyncMessages(list) emitted with a list of messages |
604 @signal rsyncMessages(list) emitted with a list of messages |
573 |
605 @signal removeDirectoryDone() emitted after a directory has been deleted |
574 @signal longListFilesFailed(exc) emitted with a failure message to indicate |
606 @signal createDirectoryDone() emitted after a directory was created |
575 a failed long listing operation |
607 @signal synchTimeDone() emitted after the time was synchronizde to the |
576 @signal currentDirFailed(exc) emitted with a failure message to indicate |
608 device |
577 that the current directory is not available |
609 @signal showTimeDone(dateTime) emitted after the date and time was fetched |
578 @signal currentDirChangeFailed(exc) emitted with a failure message to |
610 from the connected device |
579 indicate that the current directory could not be changed |
611 @signal showVersionDone(versionInfo) emitted after the version information |
580 @signal getFileFailed(exc) emitted with a failure message to indicate that |
612 was fetched from the connected device |
581 the file could not be fetched |
613 |
582 @signal putFileFailed(exc) emitted with a failure message to indicate that |
614 @signal error(exc) emitted with a failure message to indicate a failure |
583 the file could not be copied |
615 during the most recent operation |
584 @signal deleteFileFailed(exc) emitted with a failure message to indicate |
|
585 that the file could not be deleted on the device |
|
586 @signal rsyncFailed(exc) emitted with a failure message to indicate that |
|
587 the rsync operation could not be completed |
|
588 """ |
616 """ |
589 longListFiles = pyqtSignal(tuple) |
617 longListFiles = pyqtSignal(tuple) |
590 currentDir = pyqtSignal(str) |
618 currentDir = pyqtSignal(str) |
591 currentDirChanged = pyqtSignal(str) |
619 currentDirChanged = pyqtSignal(str) |
592 getFileDone = pyqtSignal(str, str) |
620 getFileDone = pyqtSignal(str, str) |
593 putFileDone = pyqtSignal(str, str) |
621 putFileDone = pyqtSignal(str, str) |
594 deleteFileDone = pyqtSignal(str) |
622 deleteFileDone = pyqtSignal(str) |
595 rsyncDone = pyqtSignal(str, str) |
623 rsyncDone = pyqtSignal(str, str) |
596 rsyncMessages = pyqtSignal(list) |
624 rsyncMessages = pyqtSignal(list) |
597 |
625 removeDirectoryDone = pyqtSignal() |
598 longListFilesFailed = pyqtSignal(str) |
626 createDirectoryDone = pyqtSignal() |
599 currentDirFailed = pyqtSignal(str) |
627 synchTimeDone = pyqtSignal() |
600 currentDirChangeFailed = pyqtSignal(str) |
628 showTimeDone = pyqtSignal(str) |
601 getFileFailed = pyqtSignal(str) |
629 showVersionDone = pyqtSignal(dict) |
602 putFileFailed = pyqtSignal(str) |
630 |
603 deleteFileFailed = pyqtSignal(str) |
631 error = pyqtSignal(str, str) |
604 rsyncFailed = pyqtSignal(str) |
|
605 |
632 |
606 def __init__(self, port, parent=None): |
633 def __init__(self, port, parent=None): |
607 """ |
634 """ |
608 Constructor |
635 Constructor |
609 |
636 |
648 str(size), |
675 str(size), |
649 mtime2string(time)) for |
676 mtime2string(time)) for |
650 name, (mode, size, time) in filesList] |
677 name, (mode, size, time) in filesList] |
651 self.longListFiles.emit(tuple(result)) |
678 self.longListFiles.emit(tuple(result)) |
652 except Exception as exc: |
679 except Exception as exc: |
653 self.longListFilesFailed.emit(str(exc)) |
680 self.error.emit("lls", str(exc)) |
654 |
681 |
655 @pyqtSlot() |
682 @pyqtSlot() |
656 def pwd(self): |
683 def pwd(self): |
657 """ |
684 """ |
658 Public slot to get the current directory of the device. |
685 Public slot to get the current directory of the device. |
659 """ |
686 """ |
660 try: |
687 try: |
661 pwd = self.__fs.pwd() |
688 pwd = self.__fs.pwd() |
662 self.currentDir.emit(pwd) |
689 self.currentDir.emit(pwd) |
663 except Exception as exc: |
690 except Exception as exc: |
664 self.currentDirFailed.emit(str(exc)) |
691 self.error.emit("pwd", str(exc)) |
665 |
692 |
666 @pyqtSlot(str) |
693 @pyqtSlot(str) |
667 def cd(self, dirname): |
694 def cd(self, dirname): |
668 """ |
695 """ |
669 Public slot to change the current directory of the device. |
696 Public slot to change the current directory of the device. |
694 os.path.basename(deviceFileName)) |
721 os.path.basename(deviceFileName)) |
695 try: |
722 try: |
696 self.__fs.get(deviceFileName, hostFileName) |
723 self.__fs.get(deviceFileName, hostFileName) |
697 self.getFileDone.emit(deviceFileName, hostFileName) |
724 self.getFileDone.emit(deviceFileName, hostFileName) |
698 except Exception as exc: |
725 except Exception as exc: |
699 self.getFileFailed.emit(str(exc)) |
726 self.error.emit("get", str(exc)) |
700 |
727 |
701 @pyqtSlot(str) |
728 @pyqtSlot(str) |
702 @pyqtSlot(str, str) |
729 @pyqtSlot(str, str) |
703 def put(self, hostFileName, deviceFileName=""): |
730 def put(self, hostFileName, deviceFileName=""): |
704 """ |
731 """ |
711 """ |
738 """ |
712 try: |
739 try: |
713 self.__fs.put(hostFileName, deviceFileName) |
740 self.__fs.put(hostFileName, deviceFileName) |
714 self.putFileDone.emit(hostFileName, deviceFileName) |
741 self.putFileDone.emit(hostFileName, deviceFileName) |
715 except Exception as exc: |
742 except Exception as exc: |
716 self.putFileFailed.emit(str(exc)) |
743 self.error.emit("put", str(exc)) |
717 |
744 |
718 @pyqtSlot(str) |
745 @pyqtSlot(str) |
719 def delete(self, deviceFileName): |
746 def delete(self, deviceFileName): |
720 """ |
747 """ |
721 Public slot to delete a file on the device. |
748 Public slot to delete a file on the device. |
725 """ |
752 """ |
726 try: |
753 try: |
727 self.__fs.rm(deviceFileName) |
754 self.__fs.rm(deviceFileName) |
728 self.deleteFileDone.emit(deviceFileName) |
755 self.deleteFileDone.emit(deviceFileName) |
729 except Exception as exc: |
756 except Exception as exc: |
730 self.deleteFileFailed.emit(str(exc)) |
757 self.error.emit("delete", str(exc)) |
731 |
758 |
732 def __rsync(self, hostDirectory, deviceDirectory, mirror=True): |
759 def __rsync(self, hostDirectory, deviceDirectory, mirror=True): |
733 """ |
760 """ |
734 Private method to synchronize a local directory to the device. |
761 Private method to synchronize a local directory to the device. |
735 |
762 |
839 except Exception as exc: |
866 except Exception as exc: |
840 messages.append(str(exc)) |
867 messages.append(str(exc)) |
841 |
868 |
842 return messages, errors |
869 return messages, errors |
843 |
870 |
|
871 @pyqtSlot(str, str) |
|
872 @pyqtSlot(str, str, bool) |
844 def rsync(self, hostDirectory, deviceDirectory, mirror=True): |
873 def rsync(self, hostDirectory, deviceDirectory, mirror=True): |
845 """ |
874 """ |
846 Public method to synchronize a local directory to the device. |
875 Public slot to synchronize a local directory to the device. |
847 |
876 |
848 @param hostDirectory name of the local directory |
877 @param hostDirectory name of the local directory |
849 @type str |
878 @type str |
850 @param deviceDirectory name of the directory on the device |
879 @param deviceDirectory name of the directory on the device |
851 @type str |
880 @type str |
854 @type bool |
883 @type bool |
855 """ |
884 """ |
856 messages, errors = self.__rsync(hostDirectory, deviceDirectory, |
885 messages, errors = self.__rsync(hostDirectory, deviceDirectory, |
857 mirror=mirror) |
886 mirror=mirror) |
858 if errors: |
887 if errors: |
859 self.rsyncFailed.emit("\n".join(errors)) |
888 self.error.emit("rsync", "\n".join(errors)) |
860 |
889 |
861 if messages: |
890 if messages: |
862 self.rsyncMessages.emit(messages) |
891 self.rsyncMessages.emit(messages) |
863 |
892 |
864 self.rsyncDone.emit(hostDirectory, deviceDirectory) |
893 self.rsyncDone.emit(hostDirectory, deviceDirectory) |
|
894 |
|
895 @pyqtSlot(str) |
|
896 def mkdir(self, dirname): |
|
897 """ |
|
898 Public slot to create a new directory. |
|
899 |
|
900 @param dirname name of the directory to create |
|
901 @type str |
|
902 """ |
|
903 try: |
|
904 self.__fs.mkdir(dirname) |
|
905 self.createDirectoryDone.emit() |
|
906 except Exception as exc: |
|
907 self.error.emit("mkdir", str(exc)) |
|
908 |
|
909 @pyqtSlot(str) |
|
910 @pyqtSlot(str, bool) |
|
911 def rmdir(self, dirname, recursive=False): |
|
912 """ |
|
913 Public slot to (recursively) remove a directory. |
|
914 |
|
915 @param dirname name of the directory to be removed |
|
916 @type str |
|
917 @param recursive flag indicating a recursive removal |
|
918 @type bool |
|
919 """ |
|
920 try: |
|
921 if recursive: |
|
922 self.__fs.rmrf(dirname, recursive=True, force=True) |
|
923 else: |
|
924 self.__fs.rmdir(dirname) |
|
925 self.removeDirectoryDone.emit() |
|
926 except Exception as exc: |
|
927 self.error.emit("rmdir", str(exc)) |
|
928 |
|
929 ################################################################## |
|
930 ## some non-filesystem related methods below |
|
931 ################################################################## |
|
932 |
|
933 @pyqtSlot() |
|
934 def synchronizeTime(self): |
|
935 """ |
|
936 Public slot to set the time of the connected device to the local |
|
937 computer's time. |
|
938 """ |
|
939 try: |
|
940 self.__fs.syncTime() |
|
941 self.synchTimeDone.emit() |
|
942 except Exception as exc: |
|
943 self.error.emit("rmdir", str(exc)) |
|
944 |
|
945 @pyqtSlot() |
|
946 def showTime(self): |
|
947 """ |
|
948 Public slot to get the current date and time of the device. |
|
949 """ |
|
950 try: |
|
951 dt = self.__fs.showTime() |
|
952 self.showTimeDone.emit(dt) |
|
953 except Exception as exc: |
|
954 self.error.emit("showTime", str(exc)) |
|
955 |
|
956 @pyqtSlot() |
|
957 def showVersion(self): |
|
958 """ |
|
959 Public slot to get the version info for the MicroPython run by the |
|
960 connected device. |
|
961 """ |
|
962 try: |
|
963 versionInfo = self.__fs.version() |
|
964 self.showVersionDone.emit(versionInfo) |
|
965 except Exception as exc: |
|
966 self.error.emit("showVersion", str(exc)) |