Skip to content

Commit 5fcddf2

Browse files
committed
- Modified pycboard file transfer code to improve reliability and give more informative error messages on transfer failure.
- Removed pycboard functions not used by GUI.
1 parent 3494e07 commit 5fcddf2

File tree

1 file changed

+51
-58
lines changed

1 file changed

+51
-58
lines changed

com/pycboard.py

Lines changed: 51 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -22,41 +22,34 @@ def _djb2_file(file_path):
2222
h = ((h << 5) + h + int.from_bytes(c,'little')) & 0xFFFFFFFF
2323
return h
2424

25-
# Used on pyboard to remove directories or files.
26-
def _rm_dir_or_file(i):
27-
try:
28-
os.remove(i)
29-
except OSError:
30-
os.chdir(i)
31-
for j in os.listdir():
32-
_rm_dir_or_file(j)
33-
os.chdir('..')
34-
os.rmdir(i)
35-
36-
# Used on pyboard to clear filesystem.
37-
def _reset_pyb_filesystem():
38-
os.chdir('/flash')
39-
for i in os.listdir():
40-
if i not in ['System Volume Information', 'boot.py']:
41-
_rm_dir_or_file(i)
25+
# Used on pyboard to measure free space on filesystem.
26+
def _fs_free_space(drive='/flash'):
27+
fs_stat = os.statvfs(drive)
28+
return fs_stat[0] * fs_stat[3]
4229

4330
# Used on pyboard for file transfer.
4431
def _receive_file(file_path, file_size):
45-
gc.collect()
4632
usb = pyb.USB_VCP()
4733
usb.setinterrupt(-1)
34+
if file_size > _fs_free_space():
35+
usb.write(b'NS')
36+
return
37+
else:
38+
usb.write(b'OK')
4839
buf_size = 512
4940
buf = bytearray(buf_size)
5041
buf_mv = memoryview(buf)
5142
bytes_remaining = file_size
52-
with open(file_path, 'wb') as f:
53-
while bytes_remaining > 0:
54-
bytes_read = usb.recv(buf, timeout=5)
55-
usb.write(b'0')
56-
if bytes_read:
57-
bytes_remaining -= bytes_read
58-
f.write(buf_mv[:bytes_read])
59-
gc.collect()
43+
try:
44+
with open(file_path, 'wb') as f:
45+
while bytes_remaining > 0:
46+
bytes_read = usb.recv(buf, timeout=5)
47+
usb.write(b'OK')
48+
if bytes_read:
49+
bytes_remaining -= bytes_read
50+
f.write(buf_mv[:bytes_read])
51+
except:
52+
usb.write(b'ER')
6053

6154
# ----------------------------------------------------------------------------------------
6255
# Pycboard class.
@@ -101,8 +94,9 @@ def __init__(self, serial_port, baudrate=115200, verbose=True, print_func=print
10194
def reset(self):
10295
'''Enter raw repl (soft reboots pyboard), import modules.'''
10396
self.enter_raw_repl() # Soft resets pyboard.
104-
self.exec(inspect.getsource(_djb2_file)) # define djb2 hashing function.
97+
self.exec(inspect.getsource(_djb2_file)) # define djb2 hashing function.
10598
self.exec(inspect.getsource(_receive_file)) # define recieve file function.
99+
self.exec(inspect.getsource(_fs_free_space)) # define file system free space function.
106100
self.exec('import os; import gc; import sys; import pyb')
107101
self.framework_running = False
108102
error_message = None
@@ -191,27 +185,35 @@ def transfer_file(self, file_path, target_path=None):
191185
target_path = os.path.split(file_path)[-1]
192186
file_size = os.path.getsize(file_path)
193187
file_hash = _djb2_file(file_path)
194-
try:
195-
for i in range(10):
196-
if file_hash == self.get_file_hash(target_path):
197-
return
198-
try:
199-
self.remove_file(file_path)
200-
except PyboardError:
201-
pass
202-
self.exec_raw_no_follow("_receive_file('{}',{})"
203-
.format(target_path, file_size))
204-
with open(file_path, 'rb') as f:
205-
while True:
206-
chunk = f.read(512)
207-
if not chunk:
208-
break
209-
self.serial.write(chunk)
210-
self.serial.read(1)
211-
self.follow(5)
212-
except PyboardError:
213-
self.print('\n\nError: Unable to transfer file.')
214-
raise PyboardError
188+
for i in range(3):
189+
if file_hash == self.get_file_hash(target_path):
190+
return
191+
try:
192+
self.remove_file(file_path)
193+
time.sleep(0.01)
194+
except PyboardError:
195+
pass
196+
self.exec_raw_no_follow("_receive_file('{}',{})"
197+
.format(target_path, file_size))
198+
if not self.serial.read(2) == b'OK':
199+
self.print('\n\nInsufficient space on pyboard filesystem to transfer file.')
200+
raise PyboardError
201+
with open(file_path, 'rb') as f:
202+
while True:
203+
chunk = f.read(512)
204+
if not chunk:
205+
break
206+
self.serial.write(chunk)
207+
response_bytes = self.serial.read(2)
208+
if response_bytes != b'OK':
209+
self.print('\n\nError: Unable to transfer file. See the troubleshooting docs:\n'
210+
'https://pycontrol.readthedocs.io/en/latest/user-guide/troubleshooting/')
211+
212+
time.sleep(0.01)
213+
self.serial.reset_input_buffer()
214+
raise PyboardError
215+
self.follow(3)
216+
215217

216218
def transfer_folder(self, folder_path, target_folder=None, file_type='all',
217219
show_progress=False):
@@ -238,16 +240,7 @@ def transfer_folder(self, folder_path, target_folder=None, file_type='all',
238240
def remove_file(self, file_path):
239241
'''Remove a file from the pyboard.'''
240242
self.exec('os.remove({})'.format(repr(file_path)))
241-
242-
def reset_filesystem(self):
243-
'''Delete all files in the flash drive apart from boot.py'''
244-
self.print('Resetting filesystem.')
245-
self.reset()
246-
self.exec(inspect.getsource(_rm_dir_or_file))
247-
self.exec(inspect.getsource(_reset_pyb_filesystem))
248-
self.exec_raw('_reset_pyb_filesystem()', timeout=60)
249-
self.hard_reset()
250-
243+
251244
# ------------------------------------------------------------------------------------
252245
# pyControl operations.
253246
# ------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)