replx 1.6.7__tar.gz → 1.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- replx-1.8/PKG-INFO +110 -0
- replx-1.8/README.md +84 -0
- {replx-1.6.7 → replx-1.8}/pyproject.toml +1 -1
- {replx-1.6.7 → replx-1.8}/replx/__init__.py +1 -1
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/handlers/repl.py +1 -2
- {replx-1.6.7 → replx-1.8}/replx/cli/app.py +4 -1
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/adc.py +11 -1
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/exec.py +123 -35
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/gpio.py +12 -8
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/i2c.py +158 -20
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/pwm.py +1019 -1008
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/spi.py +36 -31
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/uart.py +30 -17
- {replx-1.6.7 → replx-1.8}/replx/protocol/repl.py +2 -5
- {replx-1.6.7 → replx-1.8}/replx/transport/__init__.py +1 -3
- {replx-1.6.7 → replx-1.8}/replx/transport/serial.py +2 -6
- replx-1.8/replx/typehints/comm_separate/EFR32MG/digi/__init__.pyi +11 -0
- replx-1.8/replx/typehints/comm_separate/EFR32MG/digi/ble.pyi +1078 -0
- replx-1.8/replx/typehints/comm_separate/EFR32MG/xbee/__init__.pyi +394 -0
- replx-1.8/replx/typehints/comm_separate/EFR32MG/xbee/modem_status.pyi +116 -0
- replx-1.8/replx/typehints/comm_separate/EFR32MG/xbee/relay.pyi +156 -0
- replx-1.8/replx.egg-info/PKG-INFO +110 -0
- {replx-1.6.7 → replx-1.8}/replx.egg-info/SOURCES.txt +6 -1
- replx-1.6.7/PKG-INFO +0 -25
- replx-1.6.7/replx/transport/base.py +0 -43
- replx-1.6.7/replx.egg-info/PKG-INFO +0 -25
- {replx-1.6.7 → replx-1.8}/LICENSE +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/__init__.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/__init__.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/client/__init__.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/client/core.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/client/session.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/protocol.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/__init__.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/__main__.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/command_dispatcher.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/connection_manager.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/core.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/handlers/__init__.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/handlers/exec.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/handlers/filesystem.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/handlers/i2c.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/handlers/session.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/handlers/spi.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/handlers/transfer.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/handlers/uart.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/agent/server/session_manager.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/__init__.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/device.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/file.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/firmware.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/package.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/commands/utility.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/config.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/connection.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/helpers/__init__.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/helpers/compiler.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/helpers/environment.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/helpers/output.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/helpers/registry.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/helpers/scanner.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/helpers/store.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/cli/helpers/updater.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/commands.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/protocol/__init__.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/protocol/storage.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/terminal.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/_thread.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/aioble/__init__.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/array.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/asyncio/__init__.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/binascii.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/bluetooth.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/builtins.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/cmath.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/collections.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/cryptolib.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/deflate.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/errno.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/framebuf.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/gc.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/hashlib.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/heapq.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/io.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/json.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/lwip.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/machine.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/math.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/micropython.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/mip/__init__.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/network.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/ntptime.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/os.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/platform.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/random.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/re.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/requests/__init__.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/select.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/socket.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/ssl.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/struct.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/sys.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/time.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/tls.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/uasyncio.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/uctypes.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/urequests.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm/vfs.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/binascii.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/errno.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/hashlib.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/io.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/json.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/machine.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/math.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/micropython.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/network.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/os.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/select.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/socket.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/ssl.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/struct.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/sys.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/time.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/ubinascii.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/ucryptolib.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/uerrno.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/uhashlib.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/uio.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/ujson.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/umachine.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/uos.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/uselect.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/usocket.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/ussl.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/ustruct.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/comm_separate/EFR32MG/utime.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/core/ESP32/aioespnow.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/core/ESP32/esp.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/core/ESP32/esp32.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/core/ESP32/espnow.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/core/MIMXRT1062DVJ6A/mimxrt.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/typehints/core/RP2350/rp2.pyi +0 -0
- {replx-1.6.7 → replx-1.8}/replx/utils/__init__.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/utils/constants.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/utils/device_info.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx/utils/exceptions.py +0 -0
- {replx-1.6.7 → replx-1.8}/replx.egg-info/dependency_links.txt +0 -0
- {replx-1.6.7 → replx-1.8}/replx.egg-info/entry_points.txt +0 -0
- {replx-1.6.7 → replx-1.8}/replx.egg-info/requires.txt +0 -0
- {replx-1.6.7 → replx-1.8}/replx.egg-info/top_level.txt +0 -0
- {replx-1.6.7 → replx-1.8}/setup.cfg +0 -0
replx-1.8/PKG-INFO
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: replx
|
|
3
|
+
Version: 1.8
|
|
4
|
+
Summary: replx is a fast, modern MicroPython CLI: turbo REPL, robust file sync (put/get), project install, mpy-cross integration, and smart port discovery.
|
|
5
|
+
Author-email: "chanmin.park" <devcamp@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/PlanXLab/replx
|
|
8
|
+
Project-URL: Repository, https://github.com/PlanXLab/replx
|
|
9
|
+
Project-URL: Issues, https://github.com/PlanXLab/replx/issues
|
|
10
|
+
Keywords: micropython,repl,serial,pyserial,typer,mpy-cross,deploy,gpio,i2c,spi,uart,pwm,adc
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Topic :: Software Development :: Embedded Systems
|
|
16
|
+
Classifier: Topic :: System :: Hardware :: Universal Serial Bus (USB)
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: typer>=0.12
|
|
21
|
+
Requires-Dist: rich>=13.0
|
|
22
|
+
Requires-Dist: pyserial>=3.5
|
|
23
|
+
Requires-Dist: mpy-cross>=1.26
|
|
24
|
+
Requires-Dist: psutil>=5.9.0
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# replx
|
|
28
|
+
|
|
29
|
+
[](https://badge.fury.io/py/replx)
|
|
30
|
+
[](https://www.python.org/downloads/)
|
|
31
|
+
[](https://opensource.org/licenses/MIT)
|
|
32
|
+
|
|
33
|
+
`replx` is a CLI tool for MicroPython development. It uses an agent-based architecture to manage multiple CLI sessions and multiple boards in a consistent workflow.
|
|
34
|
+
|
|
35
|
+
## What replx provides
|
|
36
|
+
|
|
37
|
+
- Shared connection management across terminal sessions
|
|
38
|
+
- Foreground and background board handling per session
|
|
39
|
+
- Workspace-level default device configuration
|
|
40
|
+
- File operations on device storage
|
|
41
|
+
- Script execution, REPL access, and utility commands
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
pip install replx
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Command summary
|
|
50
|
+
|
|
51
|
+
### Connection and session
|
|
52
|
+
|
|
53
|
+
- `setup`: Initialize workspace settings and register a default device.
|
|
54
|
+
- `scan`: List available serial devices.
|
|
55
|
+
- `status`: Show session and connection state.
|
|
56
|
+
- `fg`: Change the foreground device for the current session.
|
|
57
|
+
- `whoami`: Show the current foreground device.
|
|
58
|
+
- `disconnect`: Close a device connection.
|
|
59
|
+
- `shutdown`: Stop the agent and clear active sessions.
|
|
60
|
+
|
|
61
|
+
### Execution and interaction
|
|
62
|
+
|
|
63
|
+
- `exec` (`-c`): Execute inline Python code on the device.
|
|
64
|
+
- `run`: Run a local or device-side script.
|
|
65
|
+
- `repl`: Open an interactive REPL session.
|
|
66
|
+
- `shell`: Open a device file-system shell.
|
|
67
|
+
|
|
68
|
+
### File operations
|
|
69
|
+
|
|
70
|
+
- `ls`: List files and directories.
|
|
71
|
+
- `cat`: Print file content.
|
|
72
|
+
- `get`: Download files from device to local.
|
|
73
|
+
- `put`: Upload files from local to device.
|
|
74
|
+
- `cp`: Copy files or directories on device.
|
|
75
|
+
- `mv`: Move or rename files or directories on device.
|
|
76
|
+
- `rm`: Remove files or directories on device.
|
|
77
|
+
- `mkdir`: Create directories on device.
|
|
78
|
+
- `touch`: Create an empty file or update timestamps.
|
|
79
|
+
|
|
80
|
+
### Device management
|
|
81
|
+
|
|
82
|
+
- `usage`: Show device storage usage.
|
|
83
|
+
- `reset`: Perform a soft reset.
|
|
84
|
+
- `format`: Format the device file system.
|
|
85
|
+
- `init`: Run initialization scripts on device.
|
|
86
|
+
- `wifi`: Manage Wi-Fi configuration and status.
|
|
87
|
+
- `firmware`: Check, download, or update firmware.
|
|
88
|
+
|
|
89
|
+
### Package and build
|
|
90
|
+
|
|
91
|
+
- `pkg`: Search, download, and update packages.
|
|
92
|
+
- `mpy`: Compile `.py` files to `.mpy`.
|
|
93
|
+
|
|
94
|
+
### Hardware
|
|
95
|
+
|
|
96
|
+
- `gpio`: Read, write, and run GPIO sequences.
|
|
97
|
+
- `pwm`: Generate and monitor PWM signals.
|
|
98
|
+
- `adc`: Read ADC pins and run a board-side scope UI.
|
|
99
|
+
- `uart`: Open, write, read, and monitor UART.
|
|
100
|
+
- `spi`: Open, write, read, and transfer SPI data.
|
|
101
|
+
- `i2c`: Scan, read, write, and dump I2C devices.
|
|
102
|
+
|
|
103
|
+
## Notes
|
|
104
|
+
|
|
105
|
+
- `scan`, `status`, `whoami`, and `shutdown` are special commands and do not accept `--port`.
|
|
106
|
+
- Most device commands can omit the port when a foreground or workspace default device is available.
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT
|
replx-1.8/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# replx
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/replx)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
`replx` is a CLI tool for MicroPython development. It uses an agent-based architecture to manage multiple CLI sessions and multiple boards in a consistent workflow.
|
|
8
|
+
|
|
9
|
+
## What replx provides
|
|
10
|
+
|
|
11
|
+
- Shared connection management across terminal sessions
|
|
12
|
+
- Foreground and background board handling per session
|
|
13
|
+
- Workspace-level default device configuration
|
|
14
|
+
- File operations on device storage
|
|
15
|
+
- Script execution, REPL access, and utility commands
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
pip install replx
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Command summary
|
|
24
|
+
|
|
25
|
+
### Connection and session
|
|
26
|
+
|
|
27
|
+
- `setup`: Initialize workspace settings and register a default device.
|
|
28
|
+
- `scan`: List available serial devices.
|
|
29
|
+
- `status`: Show session and connection state.
|
|
30
|
+
- `fg`: Change the foreground device for the current session.
|
|
31
|
+
- `whoami`: Show the current foreground device.
|
|
32
|
+
- `disconnect`: Close a device connection.
|
|
33
|
+
- `shutdown`: Stop the agent and clear active sessions.
|
|
34
|
+
|
|
35
|
+
### Execution and interaction
|
|
36
|
+
|
|
37
|
+
- `exec` (`-c`): Execute inline Python code on the device.
|
|
38
|
+
- `run`: Run a local or device-side script.
|
|
39
|
+
- `repl`: Open an interactive REPL session.
|
|
40
|
+
- `shell`: Open a device file-system shell.
|
|
41
|
+
|
|
42
|
+
### File operations
|
|
43
|
+
|
|
44
|
+
- `ls`: List files and directories.
|
|
45
|
+
- `cat`: Print file content.
|
|
46
|
+
- `get`: Download files from device to local.
|
|
47
|
+
- `put`: Upload files from local to device.
|
|
48
|
+
- `cp`: Copy files or directories on device.
|
|
49
|
+
- `mv`: Move or rename files or directories on device.
|
|
50
|
+
- `rm`: Remove files or directories on device.
|
|
51
|
+
- `mkdir`: Create directories on device.
|
|
52
|
+
- `touch`: Create an empty file or update timestamps.
|
|
53
|
+
|
|
54
|
+
### Device management
|
|
55
|
+
|
|
56
|
+
- `usage`: Show device storage usage.
|
|
57
|
+
- `reset`: Perform a soft reset.
|
|
58
|
+
- `format`: Format the device file system.
|
|
59
|
+
- `init`: Run initialization scripts on device.
|
|
60
|
+
- `wifi`: Manage Wi-Fi configuration and status.
|
|
61
|
+
- `firmware`: Check, download, or update firmware.
|
|
62
|
+
|
|
63
|
+
### Package and build
|
|
64
|
+
|
|
65
|
+
- `pkg`: Search, download, and update packages.
|
|
66
|
+
- `mpy`: Compile `.py` files to `.mpy`.
|
|
67
|
+
|
|
68
|
+
### Hardware
|
|
69
|
+
|
|
70
|
+
- `gpio`: Read, write, and run GPIO sequences.
|
|
71
|
+
- `pwm`: Generate and monitor PWM signals.
|
|
72
|
+
- `adc`: Read ADC pins and run a board-side scope UI.
|
|
73
|
+
- `uart`: Open, write, read, and monitor UART.
|
|
74
|
+
- `spi`: Open, write, read, and transfer SPI data.
|
|
75
|
+
- `i2c`: Scan, read, write, and dump I2C devices.
|
|
76
|
+
|
|
77
|
+
## Notes
|
|
78
|
+
|
|
79
|
+
- `scan`, `status`, `whoami`, and `shutdown` are special commands and do not accept `--port`.
|
|
80
|
+
- Most device commands can omit the port when a foreground or workspace default device is available.
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
MIT
|
|
@@ -9,7 +9,7 @@ description = "replx is a fast, modern MicroPython CLI: turbo REPL, robust file
|
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "chanmin.park", email = "devcamp@gmail.com" }]
|
|
11
11
|
requires-python = ">=3.10"
|
|
12
|
-
keywords = ["micropython", "repl", "serial", "pyserial", "typer", "mpy-cross", "deploy"]
|
|
12
|
+
keywords = ["micropython", "repl", "serial", "pyserial", "typer", "mpy-cross", "deploy", "gpio", "i2c", "spi", "uart", "pwm", "adc"]
|
|
13
13
|
license = "MIT"
|
|
14
14
|
license-files = ["LICENSE"]
|
|
15
15
|
|
|
@@ -35,8 +35,7 @@ class ReplCommandsMixin:
|
|
|
35
35
|
while conn.repl.active and conn.repl_protocol:
|
|
36
36
|
try:
|
|
37
37
|
data = await loop.run_in_executor(
|
|
38
|
-
self._slow_executor,
|
|
39
|
-
self._read_repl_chunk, repl
|
|
38
|
+
self._slow_executor, self._read_repl_chunk, repl
|
|
40
39
|
)
|
|
41
40
|
if data:
|
|
42
41
|
conn.repl.append_output(data)
|
|
@@ -353,9 +353,12 @@ def _print_main_help():
|
|
|
353
353
|
("mpy", "Compile Python files to .mpy bytecode"),
|
|
354
354
|
]),
|
|
355
355
|
("Hardware", [
|
|
356
|
-
("i2c", "Scan, read, write, dump I2C devices on the connected board"),
|
|
357
356
|
("gpio", "Read, write, and run GPIO sequences on the connected board"),
|
|
357
|
+
("pwm", "Generate and monitor PWM signals on the connected board"),
|
|
358
358
|
("adc", "Read ADC pins and run the board-side ADC scope UI"),
|
|
359
|
+
("uart", "Open, write, read, monitor UART on the connected board"),
|
|
360
|
+
("spi", "Open, write, read, xfer SPI devices on the connected board"),
|
|
361
|
+
("i2c", "Scan, read, write, dump I2C devices on the connected board"),
|
|
359
362
|
]),
|
|
360
363
|
]
|
|
361
364
|
|
|
@@ -1145,9 +1145,19 @@ def adc_cmd(
|
|
|
1145
1145
|
sample: int = typer.Option(10, "--sample", metavar="MS", help="Initial scope render rate"),
|
|
1146
1146
|
show_help: bool = typer.Option(False, "--help", "-h", is_eager=True, hidden=True),
|
|
1147
1147
|
):
|
|
1148
|
-
if show_help
|
|
1148
|
+
if show_help:
|
|
1149
1149
|
_print_adc_help()
|
|
1150
1150
|
raise typer.Exit()
|
|
1151
|
+
if not args:
|
|
1152
|
+
OutputHelper.print_panel(
|
|
1153
|
+
"Subcommands: [bright_blue]read[/bright_blue] [bright_blue]scope[/bright_blue]\n\n"
|
|
1154
|
+
" [bright_green]replx PORT adc read GP26[/bright_green]\n"
|
|
1155
|
+
" [bright_green]replx PORT adc scope GP26 GP27 GP28[/bright_green]\n\n"
|
|
1156
|
+
"Use [bright_blue]replx adc --help[/bright_blue] for details.",
|
|
1157
|
+
title="ADC",
|
|
1158
|
+
border_style="yellow",
|
|
1159
|
+
)
|
|
1160
|
+
raise typer.Exit(1)
|
|
1151
1161
|
|
|
1152
1162
|
subcmd = args[0].lower()
|
|
1153
1163
|
pos_args = args[1:]
|
|
@@ -10,6 +10,7 @@ import shlex
|
|
|
10
10
|
import hashlib
|
|
11
11
|
import subprocess
|
|
12
12
|
import shutil
|
|
13
|
+
from collections import deque
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
|
|
15
16
|
import typer
|
|
@@ -73,6 +74,29 @@ def _wrap_trailing_expression_for_print(code: str) -> str:
|
|
|
73
74
|
return code
|
|
74
75
|
|
|
75
76
|
|
|
77
|
+
def _is_repl_enter_key(ch: bytes) -> bool:
|
|
78
|
+
return ch in (b"\r", b"\n", b"\r\n", b"\n\r")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _setup_readline_for_repl():
|
|
82
|
+
try:
|
|
83
|
+
import readline
|
|
84
|
+
except ImportError:
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
readline.parse_and_bind("set editing-mode emacs")
|
|
89
|
+
except Exception:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
readline.set_auto_history(False)
|
|
94
|
+
except Exception:
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
return readline
|
|
98
|
+
|
|
99
|
+
|
|
76
100
|
def _resolve_vscode_command() -> list[str] | None:
|
|
77
101
|
candidates = ["code", "code-insiders", "codium"]
|
|
78
102
|
comspec = os.environ.get("COMSPEC", "cmd.exe")
|
|
@@ -1355,6 +1379,45 @@ Start a live MicroPython session where you can type code line by line.
|
|
|
1355
1379
|
|
|
1356
1380
|
repl_running = [True]
|
|
1357
1381
|
reader_client = [None]
|
|
1382
|
+
pending_echoes = deque()
|
|
1383
|
+
pending_echo_lock = threading.Lock()
|
|
1384
|
+
pending_output_fragment = [""]
|
|
1385
|
+
|
|
1386
|
+
def _queue_pending_echo(line: str) -> None:
|
|
1387
|
+
with pending_echo_lock:
|
|
1388
|
+
pending_echoes.append(line + "\r\n")
|
|
1389
|
+
|
|
1390
|
+
def _strip_pending_echo(output: str) -> str:
|
|
1391
|
+
if not output:
|
|
1392
|
+
return output
|
|
1393
|
+
|
|
1394
|
+
with pending_echo_lock:
|
|
1395
|
+
text = pending_output_fragment[0] + output
|
|
1396
|
+
normalized = text.replace("\r\n", "\n")
|
|
1397
|
+
pending_output_fragment[0] = ""
|
|
1398
|
+
|
|
1399
|
+
if not normalized:
|
|
1400
|
+
return ""
|
|
1401
|
+
|
|
1402
|
+
trailing_fragment = "" if normalized.endswith("\n") else normalized.split("\n")[-1]
|
|
1403
|
+
lines = normalized.splitlines(keepends=True)
|
|
1404
|
+
if trailing_fragment and lines:
|
|
1405
|
+
lines = lines[:-1]
|
|
1406
|
+
|
|
1407
|
+
kept: list[str] = []
|
|
1408
|
+
for line in lines:
|
|
1409
|
+
if pending_echoes and line == pending_echoes[0].replace("\r\n", "\n"):
|
|
1410
|
+
pending_echoes.popleft()
|
|
1411
|
+
continue
|
|
1412
|
+
kept.append(line)
|
|
1413
|
+
|
|
1414
|
+
if trailing_fragment:
|
|
1415
|
+
if pending_echoes and pending_echoes[0].replace("\r\n", "\n").startswith(trailing_fragment):
|
|
1416
|
+
pending_output_fragment[0] = trailing_fragment
|
|
1417
|
+
else:
|
|
1418
|
+
kept.append(trailing_fragment)
|
|
1419
|
+
|
|
1420
|
+
return "".join(kept)
|
|
1358
1421
|
|
|
1359
1422
|
def reader_thread_func():
|
|
1360
1423
|
try:
|
|
@@ -1366,6 +1429,10 @@ Start a live MicroPython session where you can type code line by line.
|
|
|
1366
1429
|
output = result.get('output', '')
|
|
1367
1430
|
if output:
|
|
1368
1431
|
sleep_time = 0.005
|
|
1432
|
+
if sys.platform == 'darwin':
|
|
1433
|
+
output = _strip_pending_echo(output)
|
|
1434
|
+
if not output:
|
|
1435
|
+
continue
|
|
1369
1436
|
output = colorize_prompt(output)
|
|
1370
1437
|
if IS_WINDOWS:
|
|
1371
1438
|
sys.stdout.buffer.write(output.encode('utf-8').replace(b'\r', b''))
|
|
@@ -1390,6 +1457,7 @@ Start a live MicroPython session where you can type code line by line.
|
|
|
1390
1457
|
reader.start()
|
|
1391
1458
|
|
|
1392
1459
|
writer_client = _create_agent_client()
|
|
1460
|
+
repl_enter_data = '\r'
|
|
1393
1461
|
|
|
1394
1462
|
_old_console_mode = disable_quick_edit_mode()
|
|
1395
1463
|
|
|
@@ -1430,53 +1498,73 @@ Start a live MicroPython session where you can type code line by line.
|
|
|
1430
1498
|
_atexit.register(_restore_console)
|
|
1431
1499
|
|
|
1432
1500
|
input_buffer = ""
|
|
1433
|
-
|
|
1501
|
+
|
|
1434
1502
|
try:
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
if char == b'\x00' or not char:
|
|
1439
|
-
continue
|
|
1440
|
-
|
|
1441
|
-
if char == CTRL_D:
|
|
1442
|
-
input_buffer = ""
|
|
1503
|
+
if sys.platform == 'darwin':
|
|
1504
|
+
readline_mod = _setup_readline_for_repl()
|
|
1505
|
+
while True:
|
|
1443
1506
|
try:
|
|
1444
|
-
|
|
1445
|
-
except
|
|
1507
|
+
line = input()
|
|
1508
|
+
except EOFError:
|
|
1446
1509
|
break
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
if char in (b'\r', b'\n'):
|
|
1450
|
-
if input_buffer.strip() == 'exit()':
|
|
1451
|
-
repl_running[0] = False
|
|
1452
|
-
reader.join(timeout=0.3)
|
|
1510
|
+
except KeyboardInterrupt:
|
|
1453
1511
|
try:
|
|
1454
1512
|
writer_client.send_command('repl_write', data='\x03', timeout=1.5, max_retries=1)
|
|
1455
1513
|
except Exception:
|
|
1456
|
-
|
|
1514
|
+
break
|
|
1515
|
+
continue
|
|
1516
|
+
|
|
1517
|
+
if line.strip() == 'exit()':
|
|
1457
1518
|
break
|
|
1458
|
-
|
|
1519
|
+
|
|
1459
1520
|
try:
|
|
1460
|
-
|
|
1521
|
+
if readline_mod and line and (readline_mod.get_current_history_length() == 0 or readline_mod.get_history_item(readline_mod.get_current_history_length()) != line):
|
|
1522
|
+
readline_mod.add_history(line)
|
|
1523
|
+
_queue_pending_echo(line)
|
|
1524
|
+
writer_client.send_command('repl_write', data=line + repl_enter_data, timeout=1.5, max_retries=1)
|
|
1461
1525
|
except Exception:
|
|
1462
1526
|
break
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1527
|
+
else:
|
|
1528
|
+
while True:
|
|
1529
|
+
char = getch()
|
|
1530
|
+
|
|
1531
|
+
if char == b'\x00' or not char:
|
|
1532
|
+
continue
|
|
1533
|
+
|
|
1534
|
+
if char == CTRL_D:
|
|
1469
1535
|
break
|
|
1470
|
-
|
|
1471
|
-
if char
|
|
1536
|
+
|
|
1537
|
+
if _is_repl_enter_key(char):
|
|
1538
|
+
if input_buffer.strip() == 'exit()':
|
|
1539
|
+
repl_running[0] = False
|
|
1540
|
+
reader.join(timeout=0.3)
|
|
1541
|
+
try:
|
|
1542
|
+
writer_client.send_command('repl_write', data='\x03', timeout=1.5, max_retries=1)
|
|
1543
|
+
except Exception:
|
|
1544
|
+
pass
|
|
1545
|
+
break
|
|
1546
|
+
input_buffer = ""
|
|
1472
1547
|
try:
|
|
1473
|
-
|
|
1474
|
-
except
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1548
|
+
writer_client.send_command('repl_write', data=repl_enter_data, timeout=1.5, max_retries=1)
|
|
1549
|
+
except Exception:
|
|
1550
|
+
break
|
|
1551
|
+
elif char == b'\x7f' or char == b'\x08':
|
|
1552
|
+
if input_buffer:
|
|
1553
|
+
input_buffer = input_buffer[:-1]
|
|
1554
|
+
try:
|
|
1555
|
+
writer_client.send_command('repl_write', data=char.decode('utf-8', errors='replace'), timeout=1.5, max_retries=1)
|
|
1556
|
+
except Exception:
|
|
1557
|
+
break
|
|
1558
|
+
else:
|
|
1559
|
+
if char >= b' ':
|
|
1560
|
+
try:
|
|
1561
|
+
input_buffer += char.decode('utf-8', errors='ignore')
|
|
1562
|
+
except UnicodeDecodeError:
|
|
1563
|
+
pass
|
|
1564
|
+
try:
|
|
1565
|
+
writer_client.send_command('repl_write', data=char.decode('utf-8', errors='replace'), timeout=1.5, max_retries=1)
|
|
1566
|
+
except Exception:
|
|
1567
|
+
break
|
|
1480
1568
|
|
|
1481
1569
|
except KeyboardInterrupt:
|
|
1482
1570
|
pass
|
|
@@ -263,7 +263,6 @@ _next_level = bytearray(1)
|
|
|
263
263
|
|
|
264
264
|
|
|
265
265
|
def _isr(pin):
|
|
266
|
-
"""Hard-IRQ handler: zero heap allocation."""
|
|
267
266
|
global _wr, _overflow
|
|
268
267
|
nxt = (_wr + 1) % _BUF_SIZE
|
|
269
268
|
if nxt == _rd:
|
|
@@ -276,7 +275,6 @@ def _isr(pin):
|
|
|
276
275
|
|
|
277
276
|
|
|
278
277
|
def _flush_buf():
|
|
279
|
-
"""Drain all pending edges into a plain list (called from main loop only)."""
|
|
280
278
|
global _rd, _overflow
|
|
281
279
|
edges = []
|
|
282
280
|
while _rd != _wr:
|
|
@@ -307,7 +305,6 @@ def _make_plot():
|
|
|
307
305
|
|
|
308
306
|
|
|
309
307
|
def _poll_key():
|
|
310
|
-
"""Return the first pending character, or None. Raises KeyboardInterrupt on Ctrl+C."""
|
|
311
308
|
r, _, _ = _sel.select([sys.stdin], [], [], 0)
|
|
312
309
|
if not r:
|
|
313
310
|
return None
|
|
@@ -318,7 +315,6 @@ def _poll_key():
|
|
|
318
315
|
|
|
319
316
|
|
|
320
317
|
def _draw_log(w, log_buf, log_pos):
|
|
321
|
-
"""Redraw all 8 edge-log rows (oldest at top, newest at bottom)."""
|
|
322
318
|
for i in range(_LOG_N):
|
|
323
319
|
idx = (log_pos - _LOG_N + i) % _LOG_N
|
|
324
320
|
entry = log_buf[idx]
|
|
@@ -394,10 +390,8 @@ def main():
|
|
|
394
390
|
|
|
395
391
|
t_now = time.ticks_us()
|
|
396
392
|
held = time.ticks_diff(t_now, last_change_t)
|
|
397
|
-
# Update last known level from IRQ edge history (avoids pin.value() race)
|
|
398
393
|
if edges:
|
|
399
394
|
last_irq_level = edges[-1][1]
|
|
400
|
-
# Advance scope exactly one tick per render loop with correct level
|
|
401
395
|
_pt = sc._t
|
|
402
396
|
sc.tick([float(last_irq_level)])
|
|
403
397
|
if sc._t <= _pt:
|
|
@@ -468,7 +462,6 @@ def _make_write_code(pin_no: int, pin_name: str, value: int) -> str:
|
|
|
468
462
|
|
|
469
463
|
|
|
470
464
|
def _mk_timeout_exit(action: str, read_pin_name: str, indent: int = 12) -> str:
|
|
471
|
-
"""Generate the MicroPython timeout-exit snippet (used inside while loops)."""
|
|
472
465
|
pad = " " * indent
|
|
473
466
|
return (
|
|
474
467
|
f"{pad}res['read_action']={action!r}\n"
|
|
@@ -1178,9 +1171,20 @@ def gpio_cmd(
|
|
|
1178
1171
|
repeat: int = typer.Option(1, "--repeat", metavar="N", help="Repeat gpio read N times (0=infinite until Ctrl+C, default 1)"),
|
|
1179
1172
|
show_help: bool = typer.Option(False, "--help", "-h", is_eager=True, hidden=True),
|
|
1180
1173
|
):
|
|
1181
|
-
if show_help
|
|
1174
|
+
if show_help:
|
|
1182
1175
|
_print_gpio_help()
|
|
1183
1176
|
raise typer.Exit()
|
|
1177
|
+
if not args:
|
|
1178
|
+
OutputHelper.print_panel(
|
|
1179
|
+
"Subcommands: [bright_blue]monitor[/bright_blue] [bright_blue]read[/bright_blue] [bright_blue]write[/bright_blue] [bright_blue]seq[/bright_blue]\n\n"
|
|
1180
|
+
" [bright_green]replx PORT gpio read GP1[/bright_green]\n"
|
|
1181
|
+
" [bright_green]replx PORT gpio write GP25 1[/bright_green]\n"
|
|
1182
|
+
" [bright_green]replx PORT gpio monitor GP1[/bright_green]\n\n"
|
|
1183
|
+
"Use [bright_blue]replx gpio --help[/bright_blue] for details.",
|
|
1184
|
+
title="GPIO",
|
|
1185
|
+
border_style="yellow",
|
|
1186
|
+
)
|
|
1187
|
+
raise typer.Exit(1)
|
|
1184
1188
|
|
|
1185
1189
|
subcmd = args[0].lower()
|
|
1186
1190
|
pos_args = args[1:]
|