-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Add new raw REPL paste mode that has flow control, and compiles as it receives data #6527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -253,6 +253,7 @@ def inWaiting(self): | |
|
||
class Pyboard: | ||
def __init__(self, device, baudrate=115200, user="micro", password="python", wait=0): | ||
self.use_raw_paste = True | ||
if device.startswith("exec:"): | ||
self.serial = ProcessToSerial(device[len("exec:") :]) | ||
elif device.startswith("execpty:"): | ||
|
@@ -359,6 +360,41 @@ def follow(self, timeout, data_consumer=None): | |
# return normal and error output | ||
return data, data_err | ||
|
||
def raw_paste_write(self, command_bytes): | ||
# Read initial header, with window size. | ||
data = self.serial.read(2) | ||
window_size = data[0] | data[1] << 8 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be "more pythonic" to use something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I try not to depend on entire modules if it's just for a very simple thing like this... too much micro, not enough Python :) |
||
window_remain = window_size | ||
|
||
# Write out the command_bytes data. | ||
i = 0 | ||
while i < len(command_bytes): | ||
while window_remain == 0 or self.serial.inWaiting(): | ||
data = self.serial.read(1) | ||
if data == b"\x01": | ||
# Device indicated that a new window of data can be sent. | ||
window_remain += window_size | ||
elif data == b"\x04": | ||
# Device indicated abrupt end. Acknowledge it and finish. | ||
self.serial.write(b"\x04") | ||
return | ||
else: | ||
# Unexpected data from device. | ||
raise PyboardError("unexpected read during raw paste: {}".format(data)) | ||
# Send out as much data as possible that fits within the allowed window. | ||
b = command_bytes[i : min(i + window_remain, len(command_bytes))] | ||
self.serial.write(b) | ||
window_remain -= len(b) | ||
i += len(b) | ||
|
||
# Indicate end of data. | ||
self.serial.write(b"\x04") | ||
|
||
# Wait for device to acknowledge end of data. | ||
data = self.read_until(1, b"\x04") | ||
if not data.endswith(b"\x04"): | ||
raise PyboardError("could not complete raw paste: {}".format(data)) | ||
|
||
def exec_raw_no_follow(self, command): | ||
if isinstance(command, bytes): | ||
command_bytes = command | ||
|
@@ -370,7 +406,26 @@ def exec_raw_no_follow(self, command): | |
if not data.endswith(b">"): | ||
raise PyboardError("could not enter raw repl") | ||
|
||
# write command | ||
if self.use_raw_paste: | ||
# Try to enter raw-paste mode. | ||
self.serial.write(b"\x05A\x01") | ||
data = self.serial.read(2) | ||
if data == b"R\x00": | ||
# Device understood raw-paste command but doesn't support it. | ||
pass | ||
elif data == b"R\x01": | ||
# Device supports raw-paste mode, write out the command using this mode. | ||
return self.raw_paste_write(command_bytes) | ||
else: | ||
# Device doesn't support raw-paste, fall back to normal raw REPL. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this then set There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah that's probably a good idea, so it doesn't keep trying the failing raw-paste each time. And it's not like the device can suddenly support it, you'd have to at least disconnect/reconnect to get support for raw-paste, which means resetting this variable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
data = self.read_until(1, b"w REPL; CTRL-B to exit\r\n>") | ||
if not data.endswith(b"w REPL; CTRL-B to exit\r\n>"): | ||
print(data) | ||
raise PyboardError("could not enter raw repl") | ||
# Don't try to use raw-paste mode again for this connection. | ||
self.use_raw_paste = False | ||
|
||
# Write command using standard raw REPL, 256 bytes every 10ms. | ||
for i in range(0, len(command_bytes), 256): | ||
self.serial.write(command_bytes[i : min(i + 256, len(command_bytes))]) | ||
time.sleep(0.01) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry if this is a stupid question, but given that
window
is transmitted as a 16-bit value, should this function be checking thatbuf_max
is less than 0x20000 ?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, yes, that should be constrained. I've now changed the type of the arg to a
uint16_t
so that the compiler enforces the size to a maximum of 65535 (which should be plenty).