Exemplo n.º 1
0
    def __init__(self, parent):
        super(FlashDialog, self).__init__(parent, Qt.WindowCloseButtonHint)
        self.setupUi(self)
        self.setModal(True)

        self._connection_scanner = ConnectionScanner()
        self._port = None
        self._flash_output = None
        self._flash_output_mutex = Lock()
        self._flashing = False

        if Settings().python_flash_executable:
            self.pythonPathEdit.setText(Settings().python_flash_executable)

        self.pickPythonButton.clicked.connect(self._pick_python)
        self.pickFirmwareButton.clicked.connect(self._pick_firmware)
        self.refreshButton.clicked.connect(self._refresh_ports)
        self.wiringButton.clicked.connect(self._show_wiring)
        self.eraseButton.clicked.connect(lambda: self._start(False, True))
        self.flashButton.clicked.connect(lambda: self._start(True, False))

        self._flash_output_signal.connect(self._update_output)
        self._flash_finished_signal.connect(self._flash_finished)

        self._refresh_ports()
Exemplo n.º 2
0
    def remove_preset(self):
        idx = self.presetsListView.currentIndex()
        assert isinstance(idx, QModelIndex)
        if idx.row() < 0:
            return

        Settings().wifi_presets.remove(Settings().wifi_presets[idx.row()])
        self.update_preset_list()
Exemplo n.º 3
0
 def closeEvent(self, event):
     Settings.root_dir = self._root_dir
     Settings.save()
     if self._connection is not None and self._connection.is_connected():
         self.end_connection()
     if self._terminal_dialog:
         assert isinstance(self._terminal_dialog, QDialog)
         self._terminal_dialog.close()
     event.accept()
Exemplo n.º 4
0
    def __init__(self, parent):
        super(SettingsDialog, self).__init__(parent, Qt.WindowCloseButtonHint)
        self.setupUi(self)
        self.setModal(True)

        # Workaround because UI compiler doesn't recognize QKeySequenceEdit
        # Create new items
        new_line_key_edit = SettingsDialog.one_key_sequence_edit(self.terminalGroupBox, "newLineKeyEdit")
        send_key_edit = SettingsDialog.one_key_sequence_edit(self.terminalGroupBox, "sendKeyEdit")
        # Replace old items in layout
        self.terminalFormLayout.replaceWidget(self.newLineKeyEdit, new_line_key_edit)
        self.terminalFormLayout.replaceWidget(self.sendKeyEdit, send_key_edit)
        # Set parent to None effectively removing old items
        self.newLineKeyEdit.setParent(None)
        self.sendKeyEdit.setParent(None)
        # Replace references
        self.newLineKeyEdit = new_line_key_edit
        self.sendKeyEdit = send_key_edit

        if Settings().external_editor_path:
            self.externalPathLineEdit.setText(Settings().external_editor_path)
        if Settings().external_editor_args:
            self.externalCommandLineEdit.setText(Settings().external_editor_args)
        self.externalPathBrowseButton.clicked.connect(self.browse_external_editor)

        self.newLineKeyEdit.setKeySequence(Settings().new_line_key)
        self.sendKeyEdit.setKeySequence(Settings().send_key)
        self.tabSpacesSpinBox.setValue(Settings().terminal_tab_spaces)

        if Settings().mpy_cross_path:
            self.mpyCrossPathLineEdit.setText(Settings().mpy_cross_path)
        self.mpyPathBrowseButton.clicked.connect(self.browse_mpy_cross)
Exemplo n.º 5
0
    def open_external_editor(self, file_path):
        ext_path = Settings().external_editor_path
        ext_args = []
        if Settings().external_editor_args:
            def wildcard_replace(s):
                s = s.replace("%f", file_path)
                return s

            ext_args = [wildcard_replace(x.strip()) for x in Settings().external_editor_args.split(";")]

        subprocess.Popen([ext_path] + ext_args)
Exemplo n.º 6
0
    def _transfer_file_path(transfer_file_name):
        # External transfer scripts folder should be used (use case: files need to be edited)
        if Settings().external_transfer_scripts_folder:
            path = "".join([Settings().external_transfer_scripts_folder, "/", transfer_file_name])
            # Check if file exists. If not, ignore external folder path.
            if os.path.isfile(path):
                return path
            else:
                raise FileNotFoundError

        return PyInstallerHelper.resource_path("mcu/" + transfer_file_name)
Exemplo n.º 7
0
 def closeEvent(self, event):
     Settings().root_dir = self._root_dir
     Settings().auto_transfer = self.autoTransferCheckBox.isChecked()
     Settings().update_geometry("main", self.saveGeometry())
     Settings().save()
     if self._connection is not None and self._connection.is_connected():
         self.end_connection()
     if self._terminal_dialog:
         self._terminal_dialog.close()
     if self._code_editor:
         self._code_editor.close()
     event.accept()
Exemplo n.º 8
0
    def _pick_firmware(self):
        firmware_dir = None
        if Settings().last_firmware_directory:
            firmware_dir = Settings().last_firmware_directory

        p = QFileDialog.getOpenFileName(parent=self,
                                        caption="Select python executable",
                                        directory=firmware_dir,
                                        filter="*.bin")
        path = p[0]
        if path:
            self.firmwarePathEdit.setText(path)
            Settings().last_firmware_directory = "/".join(
                path.split("/")[0:-1])
Exemplo n.º 9
0
 def save_settings(self):
     Settings().external_editor_path = self.externalPathLineEdit.text()
     Settings().external_editor_args = self.externalCommandLineEdit.text()
     Settings().new_line_key = self.newLineKeyEdit.keySequence()
     Settings().send_key = self.sendKeyEdit.keySequence()
     Settings().terminal_tab_spaces = self.tabSpacesSpinBox.value()
     Settings().mpy_cross_path = self.mpyCrossPathLineEdit.text()
     Settings().preferred_port = self.preferredPortLineEdit.text()
     Settings(
     ).external_transfer_scripts_folder = self.transferFilesPathLineEdit.text(
     )
     Settings().save()
Exemplo n.º 10
0
 def _pick_python(self):
     p = QFileDialog.getOpenFileName(parent=self,
                                     caption="Select python executable")
     path = p[0]
     if path:
         self.pythonPathEdit.setText(path)
         Settings().python_flash_executable = path
Exemplo n.º 11
0
    def compile_files(self):
        local_file_paths = self.get_local_file_selection()
        compiled_file_paths = []

        for local_path in local_file_paths:
            split = os.path.splitext(local_path)
            if split[1] == ".mpy":
                title = "COMPILE WARNING!! " + os.path.basename(local_path)
                QMessageBox.warning(self, title, "Can't compile .mpy files, already bytecode")
                continue
            mpy_path = split[0]+".mpy"

            try:
                os.remove(mpy_path)
                # Force view to update itself so that it sees file removed
                self.localFilesTreeView.repaint()
                QApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
            except OSError:
                pass

            try:
                with subprocess.Popen([Settings().mpy_cross_path, os.path.basename(local_path)],
                                      cwd=os.path.dirname(local_path),
                                      stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) as proc:
                    proc.wait()  # Wait for process to finish
                    out = proc.stderr.read()
                    if out:
                        QMessageBox.warning(self, "Compilation error", out.decode("utf-8"))

            except OSError:
                QMessageBox.warning(self, "Compilation error", "Failed to run mpy-cross")

            compiled_file_paths += [mpy_path]

        # Force view to update so that it sees compiled files added
        self.localFilesTreeView.repaint()
        QApplication.processEvents(QEventLoop.ExcludeUserInputEvents)

        # Force view to update last time so that it resorts the content
        # Without this, the new file will be placed at the bottom of the view no matter what
        header = self.localFilesTreeView.header()
        column = header.sortIndicatorSection()
        order = header.sortIndicatorOrder()
        # This is necessary so that view actually sorts anything again
        self.localFilesTreeView.sortByColumn(-1, Qt.AscendingOrder)
        QApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
        self.localFilesTreeView.sortByColumn(column, order)

        selection_model = self.localFilesTreeView.selectionModel()
        if compiled_file_paths:
            assert isinstance(selection_model, QItemSelectionModel)
            selection_model.clearSelection()

        for mpy_path in compiled_file_paths:
            idx = self.localFilesTreeView.model().index(mpy_path)
            selection_model.select(idx, QItemSelectionModel.Select | QItemSelectionModel.Rows)

        if self.autoTransferCheckBox.isChecked() and self._connection and self._connection.is_connected():
            self.transfer_to_mcu()
Exemplo n.º 12
0
 def update_preset_list(self):
     self.model.removeRows(0, self.model.rowCount())
     for preset in Settings().wifi_presets:
         idx = self.model.rowCount()
         self.model.insertRow(idx)
         name, ip, port, _ = preset
         text = "{}\nIP: {}    Port: {}".format(name, ip, port)
         self.model.setData(self.model.index(idx), text)
Exemplo n.º 13
0
    def select_preset(self):
        idx = self.presetsListView.currentIndex()
        assert isinstance(idx, QModelIndex)
        if idx.row() < 0:
            return

        _, self.selected_ip, self.selected_port, self.selected_password = Settings(
        ).wifi_presets[idx.row()]
        self.accept()
Exemplo n.º 14
0
 def save_settings(self):
     Settings().external_editor_path = self.externalPathLineEdit.text()
     Settings().external_editor_args = self.externalCommandLineEdit.text()
     Settings().new_line_key = self.newLineKeyEdit.keySequence()
     Settings().send_key = self.sendKeyEdit.keySequence()
     Settings().terminal_tab_spaces = self.tabSpacesSpinBox.value()
     Settings().mpy_cross_path = self.mpyCrossPathLineEdit.text()
     Settings().save()
Exemplo n.º 15
0
    def _flash_job(self, python_path, firmware_file, erase_flash):
        try:
            params = [python_path, "flash.py", self._port]
            if firmware_file:
                params.append("--fw={}".format(firmware_file))
            if erase_flash:
                params.append("--erase")
            if Settings().debug_mode:
                params.append("--debug")
            with subprocess.Popen(params,
                                  stdout=subprocess.PIPE,
                                  stdin=subprocess.PIPE,
                                  stderr=subprocess.PIPE,
                                  bufsize=1) as sub:
                buf = bytearray()
                delete = 0
                Logger.log("Pipe receiving:\r\n")
                while True:
                    x = sub.stdout.read(1)
                    Logger.log(x)

                    # Flushing content only in large blocks helps with flickering
                    # Flush output if:
                    # - didn't receive any character (timeout?)
                    # - received first backspace (content is going to be deleted)
                    # - received whitespace or dot (used to signal progress)
                    if not x \
                            or (x[0] == 8 and delete == 0) \
                            or (x[0] in b"\r\n\t ."):
                        with self._flash_output_mutex:
                            if delete > 0:
                                self._flash_output = self._flash_output[:
                                                                        -delete]
                            self._flash_output.extend(buf)
                        self._flash_output_signal.emit()
                        buf = bytearray()
                        delete = 0

                    if not x:
                        break

                    if x[0] == 8:
                        delete += 1
                    else:
                        buf.append(x[0])

                Logger.log("\r\nPipe end.\r\n")
                sub.stdout.close()
                code = sub.wait()

                self._flash_finished_signal.emit(code)
        except (FileNotFoundError, OSError):
            self._flash_finished_signal.emit(-1)
            return
Exemplo n.º 16
0
    def log(x):
        if not Settings().debug_mode:
            return

        if not Logger._log_file:
            Logger._log_file = open("log.txt", "w+b", 0)

        if isinstance(x, str):
            x = x.encode('utf-8')

        Logger._log_file.write(x)
Exemplo n.º 17
0
 def _read_file_job(self, file_name, transfer):
     self._auto_reader_lock.acquire()
     self._auto_read_enabled = False
     if Settings().use_transfer_scripts:
         self.run_file("__download.py",
                       "file_name=\"{}\"".format(file_name))
     else:
         self.send_download_file(file_name)
     self.read_junk()
     self.recv_file(transfer)
     self._auto_read_enabled = True
     self._auto_reader_lock.release()
Exemplo n.º 18
0
    def _write_file_job(self, file_name, text, transfer):
        if isinstance(text, str):
            text = text.encode('utf-8')

        self._auto_reader_lock.acquire()
        self._auto_read_enabled = False
        if Settings().use_transfer_scripts:
            self.run_file("__upload.py", "file_name=\"{}\"".format(file_name))
        else:
            self.send_upload_file(file_name)
        self.read_junk()
        self.send_file(text, transfer)
        self._auto_read_enabled = True
        self._auto_reader_lock.release()
Exemplo n.º 19
0
    def start_connection(self):
        self.set_status("Connecting...")

        connection = self._connection_scanner.port_list[self.connectionComboBox.currentIndex()]

        if connection == "wifi":
            ip_address = self.ipLineEdit.text()
            port = self.portSpinBox.value()
            if not IpHelper.is_valid_ipv4(ip_address):
                QMessageBox().warning(self, "Invalid IP", "The IP address has invalid format", QMessageBox.Ok)
                return

            try:
                self._connection = WifiConnection(ip_address, port, self._terminal, self.ask_for_password)
            except PasswordException:
                self.set_status("Password")
                return
            except NewPasswordException:
                QMessageBox().information(self, "Password set",
                                          "WebREPL password was not previously configured, so it was set to "
                                          "\"passw\" (without quotes). "
                                          "You can change it in port_config.py (will require reboot to take effect). "
                                          "Caution: Passwords longer than 9 characters will be truncated.\n\n"
                                          "Continue by connecting again.", QMessageBox.Ok)
                return
        else:
            baud_rate = BaudOptions.speeds[self.baudComboBox.currentIndex()]
            self._connection = SerialConnection(connection, baud_rate, self._terminal,
                                                self.serialResetCheckBox.isChecked())
            if self._connection.is_connected():
               if not self.serial_mcu_connection_valid():
                  self._connection.disconnect()
                  self._connection = None
            else:
               # serial connection didn't work, so likely the unplugged the serial device and COM value is stale
               self.refresh_ports()

        if self._connection is not None and self._connection.is_connected():
            self.connected()
            if isinstance(self._connection, SerialConnection):
                if Settings().use_transfer_scripts and not self._connection.check_transfer_scripts_version():
                    QMessageBox.warning(self,
                                        "Transfer scripts problem",
                                        "Transfer scripts for UART are either"
                                        " missing or have wrong version.\nPlease use 'File->Init transfer files' to"
                                        " fix this issue.")
        else:
            self._connection = None
            self.set_status("Error")
            self.refresh_ports()
Exemplo n.º 20
0
 def _read_file_job(self, file_name, transfer):
     self._auto_reader_lock.acquire()
     self._auto_read_enabled = False
     transfer_ready = True
     if Settings().use_transfer_scripts:
         self.run_file("__download.py", "file_name=\"{}\"".format(file_name))
     else:
         try:
             self.send_download_file(file_name)
         except FileNotFoundError:
             transfer_ready = False
             transfer.mark_error()
     if transfer_ready:
         self.read_junk()
         self.recv_file(transfer)
     self._auto_read_enabled = True
     self._auto_reader_lock.release()
Exemplo n.º 21
0
    def refresh_ports(self):
        self._connection_scanner.scan_connections(with_wifi=True)
        # Populate port combo box and select default
        self.connectionComboBox.clear()

        if self._connection_scanner.port_list:
            for port in self._connection_scanner.port_list:
                self.connectionComboBox.addItem(port)
            prefPort = str(Settings().preferred_port)
            prefPort = prefPort.upper()
            prefPort = prefPort.join(prefPort.split())
            if self.connectionComboBox.findText(prefPort) >= 0:
                self.connectionComboBox.setCurrentIndex(self.connectionComboBox.findText(prefPort))
            else:
                self.connectionComboBox.setCurrentIndex(0)
            self.connectButton.setEnabled(True)
        else:
            self.connectButton.setEnabled(False)
Exemplo n.º 22
0
    def open_local_file(self, idx):
        assert isinstance(idx, QModelIndex)
        model = self.localFilesTreeView.model()
        assert isinstance(model, QFileSystemModel)

        if model.isDir(idx):
            return

        local_path = model.filePath(idx)
        remote_path = local_path.rsplit("/", 1)[1]
        if local_path.endswith(".py"):
            if Settings().external_editor_path:
                self.open_external_editor(local_path)
            else:
                with open(local_path) as f:
                    text = "".join(f.readlines())
                    self.open_code_editor()
                    self._code_editor.set_code(local_path, remote_path, text)
        else:
            QMessageBox.information(self, "Unknown file", "Files without .py ending won't open"
                                                          " in editor, but can still be transferred.")
Exemplo n.º 23
0
    def __init__(self, parent, connection):
        super(CodeEditDialog, self).__init__(None, Qt.WindowCloseButtonHint)
        self.setupUi(self)

        geometry = Settings().retrieve_geometry("editor")
        if geometry:
            self.restoreGeometry(geometry)

        self._connection = connection

        self.saveLocalButton.clicked.connect(self._save_local)
        self.saveMcuButton.clicked.connect(self._save_to_mcu)
        #self.runButton.clicked.connect(self._run_file)
        self.runButton.hide()

        fixed_font = QFontDatabase.systemFont(QFontDatabase.FixedFont)
        self.codeEdit.setFont(fixed_font)

        if connection and connection.is_connected():
            self.connected(connection)
        else:
            self.disconnected()
Exemplo n.º 24
0
def run_game():
    all_setting = Settings()
    pygame.init()
    screen = pygame.display.set_mode((all_setting.width, all_setting.height))
    ship = Ship(screen, all_setting)
    pygame.display.set_caption('my first bullshit')

    bulls = Group()
    monsters = Group()

    while (True):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                gf.check_event_keydown(ship, bulls, all_setting, screen, event)
            elif event.type == pygame.KEYUP:
                gf.check_event_keyup(ship, bulls, all_setting, screen, event)

        ship.move()
        bulls.update()
        gf.update_screen(screen, ship, all_setting, bulls)
Exemplo n.º 25
0
    def add_preset(self):
        name = self.nameLineEdit.text()
        ip = self.ipLineEdit.text()
        port = self.portSpinBox.value()
        password = self.passwordLineEdit.text()
        # Make sure password is non if empty
        if not password:
            password = None

        if not name:
            QMessageBox().warning(self, "Missing name",
                                  "Fill the name of preset", QMessageBox.Ok)
            return

        if not IpHelper.is_valid_ipv4(ip):
            QMessageBox().warning(self, "Invalid IP",
                                  "The IP address has invalid format",
                                  QMessageBox.Ok)
            return

        Settings().wifi_presets.append((name, ip, port, password))
        self.update_preset_list()
Exemplo n.º 26
0
 def send_bytes(self, binary):
     self._serial.write(binary)
     time.sleep(Settings().send_sleep)
Exemplo n.º 27
0
    def send_character(self, char):
        assert isinstance(char, str)

        self._serial.write(char.encode('utf-8'))
        time.sleep(Settings().send_sleep)
Exemplo n.º 28
0
    def send_line(self, line_text, ending="\r\n"):
        assert isinstance(line_text, str)
        assert isinstance(ending, str)

        self._serial.write((line_text + ending).encode('utf-8'))
        time.sleep(Settings().send_sleep)
Exemplo n.º 29
0
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)
        self.setAttribute(Qt.WA_QuitOnClose)

        geometry = Settings().retrieve_geometry("main")
        if geometry:
            self.restoreGeometry(geometry)

        self._connection_scanner = ConnectionScanner()
        self._connection = None
        self._root_dir = Settings().root_dir
        self._mcu_files_model = None
        self._terminal = Terminal()
        self._terminal_dialog = None
        self._code_editor = None
        self._flash_dialog = None
        self._settings_dialog = None
        self._preset_password = None

        self.actionNavigate.triggered.connect(self.navigate_directory)
        self.actionTerminal.triggered.connect(self.open_terminal)
        self.actionCode_Editor.triggered.connect(self.open_code_editor)
        self.actionUpload.triggered.connect(self.upload_transfer_scripts)
        self.actionFlash.triggered.connect(self.open_flash_dialog)
        self.actionSettings.triggered.connect(self.open_settings_dialog)

        self.connectionComboBox.currentIndexChanged.connect(self.connection_changed)
        self.refreshButton.clicked.connect(self.refresh_ports)

        # Populate baud speed combo box and select default
        self.baudComboBox.clear()
        for speed in BaudOptions.speeds:
            self.baudComboBox.addItem(str(speed))
        self.baudComboBox.setCurrentIndex(BaudOptions.speeds.index(115200))

        self.presetButton.clicked.connect(self.show_presets)
        self.connectButton.clicked.connect(self.connect_pressed)

        self.update_file_tree()

        self.listButton.clicked.connect(self.list_mcu_files)
        self.mcuFilesListView.clicked.connect(self.mcu_file_selection_changed)
        self.mcuFilesListView.doubleClicked.connect(self.read_mcu_file)
        self.executeButton.clicked.connect(self.execute_mcu_code)
        self.removeButton.clicked.connect(self.remove_file)
        self.localPathEdit.setText(self._root_dir)

        local_selection_model = self.localFilesTreeView.selectionModel()
        local_selection_model.selectionChanged.connect(self.local_file_selection_changed)
        self.localFilesTreeView.doubleClicked.connect(self.open_local_file)

        # Set the "Name" column to always fit the content
        self.localFilesTreeView.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)

        self.compileButton.clicked.connect(self.compile_files)
        self.update_compile_button()
        self.autoTransferCheckBox.setChecked(Settings().auto_transfer)

        self.transferToMcuButton.clicked.connect(self.transfer_to_mcu)
        self.transferToPcButton.clicked.connect(self.transfer_to_pc)

        self.disconnected()
Exemplo n.º 30
0
 def update_compile_button(self):
     self.compileButton.setEnabled(bool(Settings().mpy_cross_path) and
                                   len(self.get_local_file_selection()) > 0)