-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
tools/mpr: Add new command-line utility to interact with remote device. #6375
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
Conversation
89ca246
to
5dde59b
Compare
This is sooo awesome! Thanks heaps for spending time getting this working. |
Cool! Looks like a worthy successor to mprepl.py. Everything I tried works. I’d appreciate a The preconfigured device shortcuts/autodetection are a bit Linux-centric, useful for me would be an additional Now I just need to fix that WebREPL protocol… |
This really rocks! This helps testing hardware even quicker! |
Looks very good. Just a little note: You are using assignment expressions at three places. That does not work with python3 < 3.8, which is on some systems (like my debian 10) still the default version. Considering about what to change, I changed the script. |
Ok, noted. I'll remove use of them. |
How's progress on this going @dpgeorge ? Is it really just waiting on choosing a name? or are there more outstanding issues to be worked on before this can get merged? |
Could be nice to be able to mount remote FS on ESP32 over socket. |
I agree, which is why I once worked on adding WebREPL support. The roadblock there was that the WebREPL protocol is flawed, it is incapable of transferring arbitrary binary data, which cannot be fixed compatibly in the current design, and I haven’t spent the effort to come up with a redesign proposal. |
I was thinking of a service that runs on the ESP32 side (started by boot.py), waits for Wifi and listens on some port for incoming connections. Once connected, it can automatically mount remote FS. |
Since this tool runs over the REPL, that would essentially be a Telnet service. Which seems supported already, so it might just work? |
Yes, it's really just picking a name. Maybe |
The idea is that this tool will work with any serial IO, eg USB, UART, I2C, CAN, telnet, etc. It just needs a way of getting bytes in and out. At the moment USB/UART/serial should work, along with telnet. |
I mad a small change to the Windows readchar function to a) support Home/End/PgUP&PgDown b) not stop with an unknown function key.
|
Please be careful with the syntax for having multiple commands in one invocation. Right now, there’s no delimiter between them. In my opinion, this looks strange (e.g. in your example Of course using
|
Have you considered using pyinvoke? mpr could use it as a library and thereby allow users to write pyinvoke tasks files in their projects that use the mpr functionality to do things, plus combine with other tasks as well. |
Thanks, that changed is pushed here.
This tool is intended to be optimised for ergonomics (fast typing) and I think not having a delimiter when not needed helps that aim. Once you get used to it it seems quite natural, IMO.
Copy is already supported. It consumes all its arguments.
Yes I think it would be good to support optional delimiters that can be used when needed to disambiguate chains of commands. Maybe something like |
I've never seen this library. Might be a good way to customise things, will look into it. |
Just before I forget it again: I played a little bit more with the Windows terminal window and extended the translation list for keys to all combinations of cursor + modifier that issued a key. No functions keys included:
I also added port shortcuts for a few 'COMx' devices as 'cx', like c3 for COM3, etc. |
For what it's worth, a tiny fix (for what seems to be unused code anyway :-): should be: Loving mpr. Thanks so much for this tool @dpgeorge. |
I am loving mpr - such a clever solution to the micropython dev workflow. I do find that on the ESP32, filesystem operations fail in an ugly way if I type a single key while they are in progress (eg. while reading a file from the /remote filesystem). I know, I could just be more careful - but I do have a proposed fix. Cause:
Fix (mostly):(Sorry - I can't post a PR against this PR ;-). In RemoteCommand.init() after:
insert (sys.stdio does support polling on the ESP32 - I don't know which boards don't have this capability):
In RemoteCommand.begin(): after
insert:
This make remote filesystem operations robust against most casual keystrokes, but not entirely. More Complete Fix:After RemoteCommand.begin() sends ctrl-X to the serial port there may be some characters still being sent from the computer that will be swallowed on the next data read. A suggested further fix:
The downside is a little extra handshaking latency. That could be alleviated with a more complex fix by looking for the ack just before the first read in each operation. With this fix, the clearing of chars before sending ctrl-X can be deleted. |
Now added, thanks!
Also added.
Fixed.
Thanks for that @glenn20 , I've applied the fix using the poller for all platforms (they should now all support stdin polling). Can fix properly using "ctrl-X" at a later date. |
This tool is now available for installation via pip:
Then it's installed as the executable |
This works really well. I had one confusing issue which I guess is my own fault. The following line produced an odd error message: from color_setup import ssd The cause proved to be that the directory on my PC contained a file I guess this is a real outlier. Renaming the directory has fixed the problem for me. |
So far I haven't managed to replicate the error message but I have uncovered this issue #7229 which may be the underlying cause. |
@peterhinch this is what confused me: it sounds like when the board is running from its own filesystem then the import works as expected, but when it runs via |
The application runs on the device under its own filesystem and has been tested on Pyboard, ESP32, ESP8266 and RP2. When run under mpremote it produces the above error message. However I have failed to produce a test case which produces a similar error message. Further, issue #7229 has me foxed as to how the application ever worked. In my attempts to produce a simple test case the error messages are a) consistent with #7229 and b) identical under mpremote and Unix. I'm puzzled that I can't produce a test case as very little code has run at the point where the exception occurs. |
I've looked at this again and figured out what was going on.
|
Ok, great! Thanks for testing/confirming that. Then it's just #7229 to deal with. |
Just a heads-up that the existing mpremote tool allows access to files and directories outside the mounted directory, eg For my own personal use I can't see this being a big security issue, but I can envision scenarios where it could be - especially for unwary users accessing boards with code from other sources. The following patch causes an And while I am here, I have also included below the very simple patch to make the FS handling completely robust against keystrokes. On the ESP32 without this patch, pressing a few key strokes during a read of a 30k file will cause it to fail most times. With the patch - never - (so far ;-). And finally, I am just noting some surprising behaviour with
To fix keystrokes crashing FS commands:
|
A small point re user friendliness. If the user pulls the plug on the device while the session is in progress a |
Thanks @glenn20 , both those improvements are now in.
@peterhinch I do not see a traceback. If I unplug a device I just see "device disconnected". |
Here is what I get: [adminpete@capybara]: ~
$ mpremote mount .
Local directory . is mounted at /remote
Connected to MicroPython at /dev/ttyACM0
Use Ctrl-] to exit this shell
>
MicroPython v1.14 on 2021-03-28; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>> device disconnected
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 537, in write
n = os.write(self.fd, d)
OSError: [Errno 5] Input/output error
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/adminpete/.local/bin/mpremote", line 8, in <module>
sys.exit(main())
File "/home/adminpete/.local/lib/python3.8/site-packages/mpremote/main.py", line 1042, in main
pyb.enter_raw_repl_without_soft_reset()
File "/home/adminpete/.local/lib/python3.8/site-packages/mpremote/main.py", line 593, in enter_raw_repl_without_soft_reset
self.serial.write(b"\r\x03\x03")
File "/home/adminpete/.local/lib/python3.8/site-packages/mpremote/main.py", line 582, in write
self.orig_serial.write(buf)
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 571, in write
raise SerialException('write failed: {}'.format(e))
serial.serialutil.SerialException: write failed: [Errno 5] Input/output error
[adminpete@capybara]: ~
$ CPython version:
|
Ok, I can reproduce now. There needs to be a |
Another minor observation: a with open('color_setup.py', 'r') as f:
print(dir(f))
while l := f.readline():
print(l, end='') Files $ mpremote mount .
Local directory . is mounted at /remote
Connected to MicroPython at /dev/ttyACM0
Use Ctrl-] to exit this shell
>
MicroPython v1.15 on 2021-05-13; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>> import rats
['__class__', '__enter__', '__exit__', '__init__', '__module__', '__qualname__', 'close', 'read', 'readinto', 'write', '__dict__', 'flush', 'ioctl', 'seek', 'cmd', 'fd', 'is_text']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "rats.py", line 4, in <module>
AttributeError: 'RemoteFile' object has no attribute 'readline'
>>> |
Thanks Damien - I like the new macros. I have one more patch to sanitise directory handling in the RemoteVFS. Without this patch you can "uos.chdir('/remote/mis-typed-directory-name')" and then things get confusing very quickly. Oh - and the strange use of "if self.path is not None:" below works around a problem that I haven't been able to resolve that causes a lock-up if you perform the stat() call on the first call to uos.chdir('/remote'). That is, I avoid performing the check on first use.
|
Another observation. If, while a program is running, I press |
Excuse my ignorance, but is there a way when my local filesystem is mounted that when I save whatever code I am actually running Right now if I make a code change, I have to cancel the execution and soft reset myself (if main.py) or re connect and run whatever other code I changed. I'm not sure if this is beyond the capabilities of what mpr can do, but it would give similar workflow to how in CiruitPython, saving code onto the board reloads and restarts it. Which is a very nice workflow for many projects. |
This is now fixed.
These are now added.
Good find! Now fixed. |
Thanks, now integrated, but slightly differently.
The first chdir call is |
This has been under development since April 2017. See micropython#3034 and micropython#6375. Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
This has been under development since April 2017. See micropython#3034 and micropython#6375. Signed-off-by: Damien George <damien@micropython.org>
That could be possible using |
Sorry for the late reply, sure thing, will add one soon! |
This has been under development since April 2017. See micropython#3034 and micropython#6375. Signed-off-by: Damien George <damien@micropython.org>
…n-main Translations update from Hosted Weblate
This PR builds on and supersedes #3034, adding a new tool called
mpr
(name subject to change).The new tool provides a set of utilities to interact with and automate a MicroPython device over a serial connection It's considered a more user-friendly version of
pyboard.py
(and uses that module to create the connection to the device). So far the commands supported are:Multiple commands can be specified and they will be run sequentially. The serial device will be automatically detected if not specified. If no actionis specified then the REPL will be entered.
Example usage:
The
mount
command is quite powerful and is the main thing inherited from #3034. For example the bootloader on an stm32 board can be updated by using (at the PC prompt):That will:
/dev/ttyACM0
)fwupdate.py
script which defines some functionsupdate_mboot(...)
function (defined infwupdate.py
) to update the bootloaderupdate_mboot(...)
is executing it reads in the firmware file from the local PC's filesystemTODO:
mpr
means "MicroPython remote"