Skip to content

Commit

Permalink
Add a feature to show a progress bar when copying a file btw local an…
Browse files Browse the repository at this point in the history
…d PI
  • Loading branch information
JeongJun-Lee committed Aug 10, 2024
1 parent ab24e39 commit 3b47cc9
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 17 deletions.
30 changes: 16 additions & 14 deletions mu/contrib/microfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def get_serial():
return Serial(port, SERIAL_BAUD_RATE, timeout=1, parity="N")


def execute(commands, serial=None):
def execute(commands, serial=None, show_progress=False, callback=None):
"""
Sends the command to the connected micro:bit via serial and returns the
result. If no serial connection is provided, attempts to autodetect the
Expand All @@ -139,17 +139,22 @@ def execute(commands, serial=None):
raw_on(serial)
time.sleep(0.1)
# Write the actual command and send CTRL-D to evaluate.
for command in commands:
total_size = len(commands)
for cnt, command in enumerate(commands):
command_bytes = command.encode("utf-8")
# Up to 32 bytes can be stored separately in both transmit and receive modes of the UART
for i in range(0, len(command_bytes), 32):
serial.write(command_bytes[i : min(i + 32, len(command_bytes))])
time.sleep(0.01)
serial.write(b"\x04")
serial.write(b"\x04") # Soft Reset with CTRL-D
response = serial.read_until(b"\x04>") # Read until prompt.
out, err = response[2:-2].split(b"\x04", 1) # Split stdout, stderr
result += out
if err:
return b"", err
if len(response) > 3: # Check if the split is possible
out, err = response[2:-2].split(b"\x04", 1) # Split stdout, stderr
result += out
if err:
return b"", err
if show_progress:
callback.emit(round(cnt / total_size * 100))
time.sleep(0.1)
raw_off(serial)
if close_serial:
Expand Down Expand Up @@ -204,7 +209,7 @@ def rm(filename, serial=None):
return True


def put(filename, target=None, serial=None):
def put(self, filename, target=None, serial=None):
"""
Puts a referenced file on the LOCAL file system onto the
file system on the BBC micro:bit.
Expand All @@ -230,13 +235,13 @@ def put(filename, target=None, serial=None):
commands.append("f(" + repr(line) + ")")
content = content[64:]
commands.append("fd.close()")
out, err = execute(commands, serial)
out, err = execute(commands, serial, True, self.on_put_update_file)
if err:
raise IOError(clean_error(err))
return True


def get(filename, target=None, serial=None):
def get(self, filename, target=None, serial=None):
"""
Gets a referenced file on the device's file system and copies it to the
target (or current working directory if unspecified).
Expand Down Expand Up @@ -270,12 +275,9 @@ def get(filename, target=None, serial=None):
"while result:\n result = r(32)\n if result:\n u.write(result)\n",
"f.close()",
]
out, err = execute(commands, serial)
out, err = execute(commands, serial, True, self.on_put_update_file)
if err:
raise IOError(clean_error(err))
# Recombine the bytes while removing "b'" from start and "'" from end.
with open(target, "wb") as f:
f.write(out)
return True


Expand Down
13 changes: 13 additions & 0 deletions mu/interface/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
QPushButton,
QHBoxLayout,
QProgressDialog,
QProgressBar,
)
from PyQt5.QtGui import QKeySequence, QStandardItemModel, QCursor
from mu import __version__
Expand Down Expand Up @@ -627,8 +628,10 @@ def on_open_file(file):
self.fs_pane.microbit_fs.list_files.connect(file_manager.ls)
self.fs_pane.local_fs.get.connect(file_manager.get)
self.fs_pane.local_fs.put.connect(file_manager.put)
self.fs_pane.local_fs.pbar_update.connect(self.fs_pane.microbit_fs.on_put_update)
self.fs_pane.local_fs.list_files.connect(file_manager.ls)
file_manager.on_put_file.connect(self.fs_pane.microbit_fs.on_put)
file_manager.on_put_update_file.connect(self.fs_pane.microbit_fs.on_put_update)
file_manager.on_delete_file.connect(self.fs_pane.microbit_fs.on_delete)
file_manager.on_get_file.connect(self.fs_pane.local_fs.on_get)
file_manager.on_list_fail.connect(self.fs_pane.on_ls_fail)
Expand Down Expand Up @@ -1463,6 +1466,10 @@ def __init__(self, parent=None, mode="python"):
self.mode = mode
self.msg_duration = 5

# Progress bar
self.progress_bar = QProgressBar()
self.addPermanentWidget(self.progress_bar)

# Mode selector.
self.mode_label = QLabel()
self.mode_label.setToolTip(_("Mu's current mode of behaviour."))
Expand Down Expand Up @@ -1527,3 +1534,9 @@ def device_connected(self, device):
msg = _("Detected new {} device.").format(device.long_mode_name)

self.set_message(msg, self.msg_duration * 1000)

def set_pbar_value(self, amount):
self.progress_bar.setVisible(True)
self.progress_bar.setValue(amount)
if amount >= 100 or amount < 0:
self.progress_bar.setVisible(False)
14 changes: 14 additions & 0 deletions mu/interface/panes.py
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,7 @@ class MuFileList(QListWidget):
disable = pyqtSignal()
list_files = pyqtSignal()
set_message = pyqtSignal(str)
pbar_update = pyqtSignal(int)

def show_confirm_overwrite_dialog(self):
"""
Expand Down Expand Up @@ -737,6 +738,10 @@ def on_put(self, microbit_file):
msg = _("'{}' successfully copied to device.").format(microbit_file)
self.set_message.emit(msg)
self.list_files.emit()
self.pbar_update.emit(-1) # To remove the pbar UI

def on_put_update(self, amount):
self.pbar_update.emit(amount)

def contextMenuEvent(self, event):
menu_current_item = self.currentItem()
Expand Down Expand Up @@ -807,6 +812,7 @@ def on_get(self, microbit_file):
).format(microbit_file)
self.set_message.emit(msg)
self.list_files.emit()
self.pbar_update.emit(-1) # To remove the pbar UI

def contextMenuEvent(self, event):
menu_current_item = self.currentItem()
Expand Down Expand Up @@ -858,6 +864,7 @@ class FileSystemPane(QFrame):
set_warning = pyqtSignal(str)
list_files = pyqtSignal()
open_file = pyqtSignal(str)
set_pbar_update = pyqtSignal(int)

def __init__(self, home):
super().__init__()
Expand Down Expand Up @@ -888,6 +895,7 @@ def on_open_file(file):
layout.addWidget(local_fs, 1, 1)
self.microbit_fs.disable.connect(self.disable)
self.microbit_fs.set_message.connect(self.show_message)
self.microbit_fs.pbar_update.connect(self.show_progressbar_update)
self.local_fs.disable.connect(self.disable)
self.local_fs.set_message.connect(self.show_message)

Expand Down Expand Up @@ -921,6 +929,12 @@ def show_warning(self, message):
"""
self.set_warning.emit(message)

def show_progressbar_update(self, amount):
"""
Emits the set_pbar_update signal.
"""
self.set_pbar_update.emit(amount)

def on_ls(self, microbit_files):
"""
Displays a list of the files on the micro:bit.
Expand Down
6 changes: 6 additions & 0 deletions mu/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1837,6 +1837,12 @@ def show_status_message(self, message, duration=5):
"""
self._view.status_bar.set_message(message, duration * 1000)

def show_progressbar_update(self, amount):
"""
Displays the referenced amount on the progress bar.
"""
self._view.status_bar.set_pbar_value(amount)

def debug_toggle_breakpoint(self, margin, line, modifiers):
"""
How to handle the toggling of a breakpoint.
Expand Down
8 changes: 6 additions & 2 deletions mu/modes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,8 @@ class FileManager(QObject):
on_get_file = pyqtSignal(str)
# Emitted when the file with referenced filename is put onto the device.
on_put_file = pyqtSignal(str)
# Emitted while the file with referenced filename is put onto the device.
on_put_update_file = pyqtSignal(int)
# Emitted when the file with referenced filename is deleted from the
# device.
on_delete_file = pyqtSignal(str)
Expand Down Expand Up @@ -714,11 +716,12 @@ def get(self, device_filename, local_filename):
failure signal.
"""
try:
microfs.get(device_filename, local_filename, serial=self.serial)
microfs.get(self, device_filename, local_filename, serial=self.serial)
self.on_get_file.emit(device_filename)
except Exception as ex:
logger.error(ex)
self.on_get_fail.emit(device_filename)
self.on_put_update_file.emit(-1) # To remove the pbar UI

def put(self, local_filename, target=None):
"""
Expand All @@ -727,11 +730,12 @@ def put(self, local_filename, target=None):
a failure signal.
"""
try:
microfs.put(local_filename, target=target, serial=self.serial)
microfs.put(self, local_filename, target=target, serial=self.serial)
self.on_put_file.emit(os.path.basename(local_filename))
except Exception as ex:
logger.error(ex)
self.on_put_fail.emit(local_filename)
self.on_put_update_file.emit(-1) # To remove the pbar UI

def delete(self, device_filename):
"""
Expand Down
2 changes: 1 addition & 1 deletion mu/modes/esp.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from PyQt5.QtCore import QThread
import os
from mu.resources import load_icon
import time


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -285,6 +284,7 @@ def add_fs(self):
)
self.fs.set_message.connect(self.editor.show_status_message)
self.fs.set_warning.connect(self.view.show_message)
self.fs.set_pbar_update.connect(self.editor.show_progressbar_update)
self.file_manager_thread.start()

def remove_fs(self):
Expand Down

0 comments on commit 3b47cc9

Please sign in to comment.