com2tty 0.1.3__tar.gz → 0.2.0__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.
- {com2tty-0.1.3/src/com2tty.egg-info → com2tty-0.2.0}/PKG-INFO +251 -50
- {com2tty-0.1.3 → com2tty-0.2.0}/README.md +250 -49
- {com2tty-0.1.3 → com2tty-0.2.0}/pyproject.toml +14 -1
- com2tty-0.2.0/src/com2tty/__init__.py +1 -0
- com2tty-0.2.0/src/com2tty/banner.py +38 -0
- com2tty-0.2.0/src/com2tty/boards.py +172 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty/bridge.py +174 -29
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty/cli.py +84 -21
- com2tty-0.2.0/src/com2tty/discovery.py +72 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty/host.py +405 -258
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty/pad_bridge.py +158 -5
- com2tty-0.2.0/src/com2tty/profiles.py +93 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty/rfc2217_server.py +0 -1
- com2tty-0.2.0/src/com2tty/uf2.py +189 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty/xinput.py +66 -1
- {com2tty-0.1.3 → com2tty-0.2.0/src/com2tty.egg-info}/PKG-INFO +251 -50
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty.egg-info/SOURCES.txt +8 -0
- com2tty-0.2.0/tests/test_boards.py +141 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/tests/test_bridge_script.py +506 -4
- {com2tty-0.1.3 → com2tty-0.2.0}/tests/test_cli.py +71 -0
- com2tty-0.2.0/tests/test_discovery.py +136 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/tests/test_host.py +1070 -46
- {com2tty-0.1.3 → com2tty-0.2.0}/tests/test_pad_bridge.py +210 -0
- com2tty-0.2.0/tests/test_profiles.py +160 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/tests/test_rfc2217_server.py +30 -1
- {com2tty-0.1.3 → com2tty-0.2.0}/tests/test_xinput.py +78 -1
- com2tty-0.1.3/src/com2tty/__init__.py +0 -1
- {com2tty-0.1.3 → com2tty-0.2.0}/LICENSE +0 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/setup.cfg +0 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/setup.py +0 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty/__main__.py +0 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty.egg-info/dependency_links.txt +0 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty.egg-info/entry_points.txt +0 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty.egg-info/requires.txt +0 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/src/com2tty.egg-info/top_level.txt +0 -0
- {com2tty-0.1.3 → com2tty-0.2.0}/tests/test_main.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: com2tty
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A Windows COM port to WSL ttyUSB forwarder
|
|
5
5
|
Author-email: yichengs <yichengs.tw+com2tty@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/Yi-Cheng-Wang/com2tty
|
|
@@ -37,7 +37,11 @@ to Linux tools running in WSL.
|
|
|
37
37
|
- [Installation](#installation)
|
|
38
38
|
- [Configuration](#configuration)
|
|
39
39
|
- [Usage](#usage)
|
|
40
|
+
- [Listing available ports](#listing-available-ports)
|
|
40
41
|
- [Bridging a serial port](#bridging-a-serial-port)
|
|
42
|
+
- [Hot-plug auto-reconnect](#hot-plug-auto-reconnect)
|
|
43
|
+
- [Bridging multiple ports](#bridging-multiple-ports)
|
|
44
|
+
- [Argument profiles](#argument-profiles)
|
|
41
45
|
- [Automatic baud-rate detection](#automatic-baud-rate-detection)
|
|
42
46
|
- [Configuring /dev/ttyUSB0 in WSL](#configuring-devttyusb0-in-wsl)
|
|
43
47
|
- [Firmware upload through the bridge](#firmware-upload-through-the-bridge)
|
|
@@ -53,8 +57,11 @@ to Linux tools running in WSL.
|
|
|
53
57
|
The Windows host requires Python 3.8 or later. The `pyserial` package, version
|
|
54
58
|
3.5 or later, is the only runtime dependency and is installed automatically with
|
|
55
59
|
the package. A working WSL installation is required, and the WSL distribution
|
|
56
|
-
must provide `python3` on its `PATH`.
|
|
57
|
-
|
|
60
|
+
must provide `python3` on its `PATH`. By default the WSL default distribution
|
|
61
|
+
is used; a specific one can be selected with `--distro`. The WSL helper uses
|
|
62
|
+
only the Python standard library and therefore needs no additional packages
|
|
63
|
+
inside WSL. These prerequisites are verified at startup and a specific,
|
|
64
|
+
actionable error is reported when one is missing.
|
|
58
65
|
|
|
59
66
|
Serial forwarding requires a COM port that Windows can open. Gamepad forwarding
|
|
60
67
|
requires a controller that the Windows XInput driver recognises, which is the
|
|
@@ -89,41 +96,59 @@ is not on your `PATH`, the package can also be invoked as a module with
|
|
|
89
96
|
|
|
90
97
|
## Configuration
|
|
91
98
|
|
|
92
|
-
`com2tty` is configured
|
|
93
|
-
|
|
94
|
-
Note that in serial mode the WSL
|
|
95
|
-
WSL user's
|
|
99
|
+
`com2tty` is configured through command-line arguments, optionally saved as
|
|
100
|
+
named profiles in an INI file (see
|
|
101
|
+
[Argument profiles](#argument-profiles)). Note that in serial mode the WSL
|
|
102
|
+
helper writes environment variables into the WSL user's shell configuration;
|
|
103
|
+
this behaviour is described in
|
|
96
104
|
[Firmware upload through the bridge](#firmware-upload-through-the-bridge).
|
|
97
105
|
|
|
98
|
-
The
|
|
99
|
-
|
|
106
|
+
The positional arguments are the COM ports. At least one is required in
|
|
107
|
+
serial mode; several may be given to bridge them concurrently. The port is
|
|
108
|
+
omitted in gamepad mode, which is selected with `--gamepad`, and in the
|
|
109
|
+
`--list` and `--version` modes.
|
|
100
110
|
|
|
101
111
|
### Options common to both modes
|
|
102
112
|
|
|
103
|
-
The following
|
|
113
|
+
The following options apply to both modes.
|
|
104
114
|
|
|
105
115
|
```text
|
|
116
|
+
--version Print the com2tty version and exit.
|
|
117
|
+
-l, --list List the serial ports Windows can see (device name,
|
|
118
|
+
VID:PID, USB bus id, serial number, detected board,
|
|
119
|
+
description) and exit.
|
|
106
120
|
-d, --debug Enable verbose debug logging on standard error.
|
|
121
|
+
--distro NAME WSL distribution to use (default: the WSL default
|
|
122
|
+
distribution). Useful when the default distribution
|
|
123
|
+
lacks python3, for example docker-desktop.
|
|
107
124
|
```
|
|
108
125
|
|
|
109
126
|
### Serial-mode options
|
|
110
127
|
|
|
111
128
|
```text
|
|
112
|
-
port
|
|
113
|
-
|
|
129
|
+
port [port ...] Windows COM port(s) to bridge, for example COM3, or
|
|
130
|
+
COM3 COM5 to bridge two ports at once. Required
|
|
131
|
+
unless --gamepad or --list is given.
|
|
114
132
|
-b, --baud BAUD Baud rate, or the literal value "auto" to detect the
|
|
115
133
|
rate Windows has configured for the port
|
|
116
134
|
(default: auto; falls back to 9600 if detection fails).
|
|
117
135
|
-w, --wsl-tty PATH Target symlink path created inside WSL
|
|
118
|
-
(default: /tmp/ttyUSB0).
|
|
136
|
+
(default: /tmp/ttyUSB0). With multiple ports, each
|
|
137
|
+
additional port increments the trailing number.
|
|
119
138
|
--rfc2217-port PORT TCP port for the in-WSL RFC 2217 forwarder
|
|
120
|
-
(default: 4000). The UF2 relay uses PORT + 1
|
|
139
|
+
(default: 4000). The UF2 relay uses PORT + 1; with
|
|
140
|
+
multiple ports, each additional port uses PORT + 2i.
|
|
121
141
|
--bytesize {5,6,7,8} Serial byte size (default: 8).
|
|
122
142
|
--parity {N,E,O,S,M} Parity: none, even, odd, space, or mark (default: N).
|
|
123
143
|
--stopbits {1,1.5,2} Stop bits (default: 1).
|
|
124
144
|
--xonxoff Enable software flow control (XON/XOFF).
|
|
125
145
|
--rtscts Enable hardware flow control (RTS/CTS).
|
|
126
146
|
--dsrdtr Enable hardware flow control (DSR/DTR).
|
|
147
|
+
--board {auto,esp32,pico,nrf52,samd,stm32,none}
|
|
148
|
+
Override USB VID board detection for reset and upload
|
|
149
|
+
handling (default: auto). Use this when a board uses a
|
|
150
|
+
USB-UART chip that com2tty does not recognise; "none"
|
|
151
|
+
disables board-specific reset sequences entirely.
|
|
127
152
|
```
|
|
128
153
|
|
|
129
154
|
### Gamepad-mode options
|
|
@@ -146,6 +171,24 @@ port Windows COM port to bridge, for example COM3. Required
|
|
|
146
171
|
Run `com2tty` from any Windows terminal, either PowerShell or Command Prompt. The
|
|
147
172
|
process runs in the foreground and is stopped with Ctrl+C.
|
|
148
173
|
|
|
174
|
+
### Listing available ports
|
|
175
|
+
|
|
176
|
+
`com2tty --list` (or `-l`) enumerates every serial port Windows can see,
|
|
177
|
+
without requiring usbipd or administrator rights.
|
|
178
|
+
|
|
179
|
+
```text
|
|
180
|
+
> com2tty --list
|
|
181
|
+
Device VID:PID Bus ID Serial number Board Description
|
|
182
|
+
------ --------- ------ ---------------- ------- -----------------------
|
|
183
|
+
COM3 - - - unknown Bluetooth serial (COM3)
|
|
184
|
+
COM17 2E8A:F00F 1-6 98C4FFA253A63FB7 pico USB serial device (COM17)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The `Bus ID` column is the USB bus location (for example `1-6` or `2-6`), read
|
|
188
|
+
directly from the device descriptor. The `Board` column shows the family that
|
|
189
|
+
VID-based detection would assign, which is the same detection the bridge uses
|
|
190
|
+
for reset and upload handling.
|
|
191
|
+
|
|
149
192
|
### Bridging a serial port
|
|
150
193
|
|
|
151
194
|
Bridge `COM3` to the default WSL path `/tmp/ttyUSB0` at 115200 baud.
|
|
@@ -166,6 +209,63 @@ relayed in both directions between the Windows COM port and the WSL pseudo
|
|
|
166
209
|
terminal. Dynamic changes that a WSL program makes to the line settings, such as
|
|
167
210
|
the baud rate, are detected and applied to the underlying Windows COM port.
|
|
168
211
|
|
|
212
|
+
### Hot-plug auto-reconnect
|
|
213
|
+
|
|
214
|
+
When the bridged device is unplugged, resets, or re-enumerates, the bridge
|
|
215
|
+
does not need to be restarted. After a short grace period for transient
|
|
216
|
+
errors (such as a board rebooting into its bootloader), com2tty closes the
|
|
217
|
+
stale Windows handle and waits for the device to come back, first under its
|
|
218
|
+
original COM name and then by scanning for its USB serial number, because
|
|
219
|
+
Windows may assign a different COM number after a replug. Once the device
|
|
220
|
+
reappears the bridge resumes automatically; the WSL endpoint stays in place
|
|
221
|
+
the whole time.
|
|
222
|
+
|
|
223
|
+
### Bridging multiple ports
|
|
224
|
+
|
|
225
|
+
Passing several ports bridges them all from one invocation.
|
|
226
|
+
|
|
227
|
+
```cmd
|
|
228
|
+
com2tty COM3 COM5
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Each port gets its own WSL helper and endpoint: the symlink path is derived
|
|
232
|
+
from `--wsl-tty` by incrementing its trailing number (`/tmp/ttyUSB0`,
|
|
233
|
+
`/tmp/ttyUSB1`, ...), and the RFC 2217 port is the base value plus two per
|
|
234
|
+
additional port (each bridge also reserves its port plus one for the UF2
|
|
235
|
+
relay). Only the first port writes the PlatformIO environment variables and
|
|
236
|
+
intercepts `picotool`, so concurrent bridges do not overwrite each other's
|
|
237
|
+
shell configuration; tools targeting a secondary port can use its RFC 2217
|
|
238
|
+
port directly.
|
|
239
|
+
|
|
240
|
+
### Argument profiles
|
|
241
|
+
|
|
242
|
+
Frequently used argument sets can be saved as named profiles in an INI file,
|
|
243
|
+
either `com2tty.ini` in the current directory or `.com2tty.ini` in the user
|
|
244
|
+
profile directory. Keys are the long option names (dashes and underscores are
|
|
245
|
+
both accepted), `port` supplies the positional argument, and boolean keys
|
|
246
|
+
take `true` or `false`.
|
|
247
|
+
|
|
248
|
+
```ini
|
|
249
|
+
[myboard]
|
|
250
|
+
port = COM5
|
|
251
|
+
baud = 115200
|
|
252
|
+
wsl-tty = /tmp/my_device
|
|
253
|
+
board = pico
|
|
254
|
+
|
|
255
|
+
[pad]
|
|
256
|
+
gamepad = true
|
|
257
|
+
uinput = true
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
A profile is invoked with an `@` prefix, and arguments given after the token
|
|
261
|
+
override the profile's values.
|
|
262
|
+
|
|
263
|
+
```cmd
|
|
264
|
+
com2tty @myboard
|
|
265
|
+
com2tty @myboard --baud 9600
|
|
266
|
+
com2tty @pad
|
|
267
|
+
```
|
|
268
|
+
|
|
169
269
|
### Automatic baud-rate detection
|
|
170
270
|
|
|
171
271
|
When the baud rate is left at its default value of `auto`, com2tty queries the
|
|
@@ -209,29 +309,57 @@ involves three mechanisms.
|
|
|
209
309
|
First, the WSL helper starts an RFC 2217 forwarder that listens on
|
|
210
310
|
`127.0.0.1:<rfc2217-port>` inside WSL, where the port defaults to 4000. To make
|
|
211
311
|
PlatformIO use it, the helper appends environment variables to the WSL user's
|
|
212
|
-
|
|
312
|
+
shell startup file: `PLATFORMIO_UPLOAD_PORT` is set to
|
|
213
313
|
`rfc2217://127.0.0.1:<rfc2217-port>` and `PLATFORMIO_MONITOR_PORT` is set to the
|
|
214
|
-
serial symlink path.
|
|
215
|
-
|
|
216
|
-
|
|
314
|
+
serial symlink path. The variables are written to `~/.bashrc`, to `~/.zshrc`
|
|
315
|
+
when zsh is in use or that file exists, and to
|
|
316
|
+
`~/.config/fish/conf.d/com2tty.fish` when fish is in use or its configuration
|
|
317
|
+
directory exists. Open a new WSL shell or run `source ~/.bashrc` (or
|
|
318
|
+
`source ~/.zshrc`; fish picks the snippet up automatically) after starting
|
|
319
|
+
com2tty for them to take effect. The variables are removed when com2tty exits;
|
|
320
|
+
if a session is killed before it can clean up, the next run removes the stale
|
|
321
|
+
block on startup.
|
|
217
322
|
|
|
218
323
|
Second, com2tty detects the connected board type from its USB vendor identifier
|
|
219
324
|
and performs the appropriate hardware reset on the Windows side. For ESP32-class
|
|
220
325
|
boards it performs the DTR and RTS auto-reset sequence to enter the download
|
|
221
|
-
mode. For RP2040 and RP2350 boards
|
|
222
|
-
the
|
|
223
|
-
|
|
224
|
-
|
|
326
|
+
mode. For RP2040 and RP2350 boards, and for Adafruit nRF52 boards with the UF2
|
|
327
|
+
bootloader, it performs the 1200-baud touch that triggers the mass-storage
|
|
328
|
+
bootloader mode. For Arduino Leonardo- and SAMD-class boards it performs the
|
|
329
|
+
same 1200-baud touch; because their bootloader re-enumerates as a separate
|
|
330
|
+
serial port (often with a different USB identity than the application port),
|
|
331
|
+
com2tty snapshots the port list before the touch, waits for the new bootloader
|
|
332
|
+
port to appear, opens it, and runs the upload against it over RFC 2217. When the
|
|
333
|
+
upload finishes and the board reboots into the application, com2tty restores and
|
|
334
|
+
reopens the original application port. For STM32-class boards it pulses
|
|
335
|
+
DTR and RTS in the conventional BOOT0/NRST wiring so the board resets around
|
|
336
|
+
an upload; boards flashed through ST-LINK or DFU are unaffected by the pulse.
|
|
337
|
+
|
|
338
|
+
Third, for UF2-bootloader boards (RP2040, RP2350, and nRF52), com2tty
|
|
339
|
+
intercepts the `picotool` invocation
|
|
225
340
|
inside WSL. When PlatformIO calls `picotool` to flash a `.uf2` image, a wrapper
|
|
226
341
|
transfers the image back to the Windows host over a relay that listens on
|
|
227
342
|
`127.0.0.1:<rfc2217-port + 1>`. The host then triggers BOOTSEL mode, locates the
|
|
228
343
|
board's mass-storage drive, verifies the transferred image against an MD5
|
|
229
344
|
checksum, and writes the image to the drive. The original `picotool` is restored
|
|
230
|
-
when com2tty exits
|
|
345
|
+
when com2tty exits; if a session is killed before it can restore it, the next run
|
|
346
|
+
detects and reverses the leftover interception on startup, so PlatformIO uploads
|
|
347
|
+
are not left broken.
|
|
231
348
|
|
|
232
349
|
These mechanisms operate without any additional flags. The startup banner reports
|
|
233
350
|
the detected board type, the RFC 2217 port, the UF2 relay port, and the board's
|
|
234
|
-
USB serial number.
|
|
351
|
+
USB serial number. If the detected board type is wrong (for example a board whose
|
|
352
|
+
USB-UART chip is not recognised), override it with `--board`.
|
|
353
|
+
|
|
354
|
+
The RFC 2217 forwarder and the UF2 relay listen on the loopback interface
|
|
355
|
+
(`127.0.0.1`) inside the WSL distribution and perform no authentication. On a
|
|
356
|
+
single-user machine this is not exposed to the network, but on a shared or
|
|
357
|
+
multi-user WSL host any local user in the same distribution could connect to
|
|
358
|
+
these ports during an upload. Run com2tty only on hosts you trust, and choose a
|
|
359
|
+
non-default `--rfc2217-port` if another local service needs the default port. To
|
|
360
|
+
reclaim a port left open by a previous com2tty session, the helper only
|
|
361
|
+
terminates processes whose command line identifies them as a com2tty bridge; an
|
|
362
|
+
unrelated service occupying the port is never killed.
|
|
235
363
|
|
|
236
364
|
### Gamepad mode
|
|
237
365
|
|
|
@@ -330,7 +458,8 @@ on Windows and observe the events appear in WSL.
|
|
|
330
458
|
|
|
331
459
|
Both tiers emit the same evdev codes. Buttons are reported as `BTN_A`, `BTN_B`,
|
|
332
460
|
`BTN_X`, `BTN_Y`, `BTN_TL`, `BTN_TR`, `BTN_SELECT`, `BTN_START`, `BTN_THUMBL`,
|
|
333
|
-
|
|
461
|
+
`BTN_THUMBR`, and `BTN_MODE` for the Guide (Xbox logo) button. The sticks are
|
|
462
|
+
reported as `ABS_X` and `ABS_Y` for the left
|
|
334
463
|
stick and `ABS_RX` and `ABS_RY` for the right stick, each spanning the signed
|
|
335
464
|
16-bit range. The triggers are reported as `ABS_Z` for the left trigger and
|
|
336
465
|
`ABS_RZ` for the right trigger, each spanning 0 to 255. The directional pad is
|
|
@@ -338,23 +467,33 @@ reported as `ABS_HAT0X` and `ABS_HAT0Y` with values of -1, 0, or 1. The stick Y
|
|
|
338
467
|
axes are inverted to follow the Linux convention in which pushing up produces a
|
|
339
468
|
negative value.
|
|
340
469
|
|
|
470
|
+
In the uinput tier the virtual pad also advertises `FF_RUMBLE` force
|
|
471
|
+
feedback. When a game or emulator inside WSL plays a rumble effect, the
|
|
472
|
+
effect's magnitudes travel back through the bridge to the Windows host, which
|
|
473
|
+
drives the physical controller's motors through `XInputSetState`. The strong
|
|
474
|
+
(left, low-frequency) and weak (right, high-frequency) motors map directly to
|
|
475
|
+
their XInput counterparts. The `/tmp` stream tier has no reverse channel and
|
|
476
|
+
therefore no force feedback.
|
|
477
|
+
|
|
341
478
|
The forwarded signal matches a real controller at the level of these event codes,
|
|
342
479
|
ranges, and resolutions, but it is not bit-for-bit identical to a controller
|
|
343
480
|
driven by the kernel `xpad` driver. The timing and latency differ because the
|
|
344
481
|
path is polled and piped rather than delivered by a fixed USB interrupt interval.
|
|
345
|
-
The Guide button is
|
|
346
|
-
|
|
347
|
-
the approach.
|
|
482
|
+
The Guide button is read through the undocumented `XInputGetStateEx` call and is
|
|
483
|
+
reported as zero on systems where only the legacy `xinput9_1_0` DLL is
|
|
484
|
+
available. These differences are inherent to the approach.
|
|
348
485
|
|
|
349
486
|
## Architecture overview
|
|
350
487
|
|
|
351
488
|
The package is organised around a host process on Windows and a helper process
|
|
352
489
|
inside WSL connected by the standard input and output streams of the helper.
|
|
353
490
|
|
|
354
|
-
`cli.py` parses the command line
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
`
|
|
491
|
+
`cli.py` parses the command line (after `profiles.py` expands any `@profile`
|
|
492
|
+
tokens) and dispatches to an entry function in `host.py`: `run_bridge` in
|
|
493
|
+
serial mode, `run_multi_bridge` when several ports are given, and
|
|
494
|
+
`run_gamepad_bridge` in gamepad mode. `discovery.py` implements `--list`.
|
|
495
|
+
`__main__.py` and the console entry point both call `cli.main`, and
|
|
496
|
+
`__init__.py` holds the package version.
|
|
358
497
|
|
|
359
498
|
`host.py` is the Windows side. In serial mode `run_bridge` opens the COM port with
|
|
360
499
|
`pyserial`, spawns the WSL helper with `wsl python3 -u bridge.py`, and runs three
|
|
@@ -363,8 +502,11 @@ relays bytes from the helper's standard output to the COM port, and one reads th
|
|
|
363
502
|
helper's standard error. The standard error stream carries a line-oriented control
|
|
364
503
|
protocol whose messages are prefixed with `[CONTROL]`; these messages drive
|
|
365
504
|
dynamic serial-setting changes, the RFC 2217 session lifecycle, and the UF2 upload
|
|
366
|
-
sequence. `host.py` also contains the
|
|
367
|
-
|
|
505
|
+
sequence. `host.py` also contains the hot-plug reconnect logic and the routine
|
|
506
|
+
that writes a transferred UF2 image to the correct Windows drive. The board
|
|
507
|
+
detection and reset sequences live in `boards.py`, the UF2 drive lookup and
|
|
508
|
+
AutoPlay suppression in `uf2.py`, and the console colour handling in
|
|
509
|
+
`banner.py`; `host.py` re-exports these names for backwards compatibility.
|
|
368
510
|
|
|
369
511
|
`bridge.py` is the WSL side for serial forwarding. It creates a pseudo terminal
|
|
370
512
|
with `openpty`, symlinks the requested path to the pseudo-terminal slave, falling
|
|
@@ -376,13 +518,21 @@ installs the `picotool` interceptor. `rfc2217_server.py` provides the redirector
|
|
|
376
518
|
that implements the RFC 2217 protocol for the forwarder.
|
|
377
519
|
|
|
378
520
|
The gamepad path reuses the same spawn-and-pipe transport. `xinput.py` is the
|
|
379
|
-
Windows side: it polls an XInput controller slot through `ctypes`
|
|
521
|
+
Windows side: it polls an XInput controller slot through `ctypes` (preferring
|
|
522
|
+
the `XInputGetStateEx` export so the Guide button is visible) and packs each
|
|
380
523
|
state snapshot into a fixed 16-byte frame, sending a frame only when the state
|
|
381
524
|
changes. `pad_bridge.py` is the WSL side: it parses the frames, translates them
|
|
382
525
|
into evdev events, and writes them to one of two sinks. The default sink writes to
|
|
383
526
|
a `/tmp` FIFO, and the opt-in sink creates a real device through `/dev/uinput`
|
|
384
527
|
using raw `ioctl` calls. Both sinks share the same event-encoding code, so the
|
|
385
|
-
byte stream they produce is identical.
|
|
528
|
+
byte stream they produce is identical. In the uinput sink the helper also
|
|
529
|
+
services the kernel's force-feedback upload handshake and streams played
|
|
530
|
+
rumble effects back over its stdout, where the host applies them to the
|
|
531
|
+
physical controller with `XInputSetState`.
|
|
532
|
+
|
|
533
|
+
For a detailed account of the control protocol, the board reset sequences, the
|
|
534
|
+
reconnection model, the binary frame formats, and the known hardware-unverified
|
|
535
|
+
behaviour, see the [architecture document](ARCHITECTURE.md).
|
|
386
536
|
|
|
387
537
|
## Development setup
|
|
388
538
|
|
|
@@ -390,13 +540,14 @@ Install the package in editable mode together with the test tools.
|
|
|
390
540
|
|
|
391
541
|
```bash
|
|
392
542
|
pip install -e .
|
|
393
|
-
pip install pytest pytest-cov
|
|
543
|
+
pip install pytest pytest-cov ruff
|
|
394
544
|
```
|
|
395
545
|
|
|
396
|
-
Run the test suite with coverage.
|
|
546
|
+
Run the test suite with coverage, and the linter.
|
|
397
547
|
|
|
398
548
|
```bash
|
|
399
549
|
pytest --cov=src/com2tty --cov-report=term-missing tests/
|
|
550
|
+
ruff check src tests scripts
|
|
400
551
|
```
|
|
401
552
|
|
|
402
553
|
A passing run reports all tests passing and full line coverage for the package.
|
|
@@ -405,24 +556,74 @@ The test suite is cross-platform. The `tests/conftest.py` file substitutes a moc
|
|
|
405
556
|
the platform-specific system calls used by the gamepad sinks are mocked so that
|
|
406
557
|
the suite runs on both Windows and Linux.
|
|
407
558
|
|
|
408
|
-
Continuous integration is defined in `.github/workflows/ci.yml`. It runs
|
|
409
|
-
suite on `windows-latest` and `ubuntu-latest` against
|
|
410
|
-
3.
|
|
411
|
-
`--cov-fail-under=100`. A separate job publishes the package to PyPI
|
|
412
|
-
the `main` branch.
|
|
559
|
+
Continuous integration is defined in `.github/workflows/ci.yml`. It runs a ruff
|
|
560
|
+
lint job and the test suite on `windows-latest` and `ubuntu-latest` against
|
|
561
|
+
Python 3.8 through 3.13, and it enforces 100 percent line coverage by running
|
|
562
|
+
pytest with `--cov-fail-under=100`. A separate job publishes the package to PyPI
|
|
563
|
+
on pushes to the `main` branch.
|
|
564
|
+
|
|
565
|
+
Because CI has no WSL or serial hardware, a manual end-to-end smoke test lives
|
|
566
|
+
at `scripts/e2e_smoke.py`. Run it on a real Windows host with a device attached
|
|
567
|
+
before a release: it checks `--list`, starts a bridge, verifies the symlink and
|
|
568
|
+
the RFC 2217 forwarder inside WSL, and optionally verifies an echo round-trip
|
|
569
|
+
when the device has TX wired to RX (`--loopback`).
|
|
570
|
+
|
|
571
|
+
```cmd
|
|
572
|
+
python scripts/e2e_smoke.py --port COM17
|
|
573
|
+
```
|
|
413
574
|
|
|
414
575
|
## Contributing
|
|
415
576
|
|
|
416
|
-
Base feature branches on the `develop` branch
|
|
417
|
-
Conventional Commits format, for example
|
|
418
|
-
`test(host): ...`, as established in the project history.
|
|
419
|
-
the test suite passing with 100 percent line coverage on
|
|
420
|
-
across the supported Python versions,
|
|
421
|
-
|
|
422
|
-
|
|
577
|
+
Base feature branches on the `develop` branch and open pull requests against it.
|
|
578
|
+
Commit messages follow the Conventional Commits format, for example
|
|
579
|
+
`feat(gamepad): ...` or `test(host): ...`, as established in the project history.
|
|
580
|
+
Every change must keep the test suite passing with 100 percent line coverage on
|
|
581
|
+
both Windows and Ubuntu across the supported Python versions, and must pass the
|
|
582
|
+
ruff linter, because continuous integration enforces both. Add or update tests
|
|
583
|
+
for any behavioural change.
|
|
584
|
+
|
|
585
|
+
The full contribution process, including how to report bugs, the commit
|
|
586
|
+
convention, the linting requirements, and the manual end-to-end verification
|
|
587
|
+
step, is documented in [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
423
588
|
|
|
424
589
|
## Troubleshooting
|
|
425
590
|
|
|
591
|
+
At startup com2tty verifies the WSL environment and reports a specific error if
|
|
592
|
+
a prerequisite is missing. The checks and their remedies are:
|
|
593
|
+
|
|
594
|
+
- `wsl.exe` is not on `PATH`: install WSL with `wsl --install` from an elevated
|
|
595
|
+
prompt and reboot if requested.
|
|
596
|
+
- `python3` is not available in the selected distribution: the WSL default
|
|
597
|
+
distribution may not be a regular Linux distribution (for example
|
|
598
|
+
`docker-desktop`). List distributions with `wsl -l -v` and either select a
|
|
599
|
+
suitable one with `--distro`, or install Python inside WSL with
|
|
600
|
+
`sudo apt install python3`.
|
|
601
|
+
- The bridge script is not readable from WSL: Windows drive automounting is
|
|
602
|
+
disabled. Ensure `/etc/wsl.conf` does not disable the `[automount]` section,
|
|
603
|
+
then restart WSL with `wsl --shutdown`.
|
|
604
|
+
|
|
605
|
+
If the helper reports that the RFC 2217 or UF2 relay port could not be bound,
|
|
606
|
+
another process inside WSL is holding the TCP port. com2tty attempts to clean up
|
|
607
|
+
leftover listeners automatically using `fuser`, which ships in the `psmisc`
|
|
608
|
+
package; on minimal distributions install it with `sudo apt install psmisc`, or
|
|
609
|
+
select a different port with `--rfc2217-port` (the UF2 relay always uses that
|
|
610
|
+
port plus one).
|
|
611
|
+
|
|
612
|
+
The serial-mode environment variables are written to `~/.bashrc`, to `~/.zshrc`
|
|
613
|
+
when zsh is detected or a `~/.zshrc` file exists, and to
|
|
614
|
+
`~/.config/fish/conf.d/com2tty.fish` when fish is detected. Users of other
|
|
615
|
+
shells must export `PLATFORMIO_UPLOAD_PORT` and `PLATFORMIO_MONITOR_PORT`
|
|
616
|
+
manually.
|
|
617
|
+
|
|
618
|
+
The startup banner uses ANSI colours only when standard output is an
|
|
619
|
+
interactive terminal that supports them; set the `NO_COLOR` environment
|
|
620
|
+
variable to suppress colours entirely.
|
|
621
|
+
|
|
622
|
+
If a board is not detected (the banner shows `Unknown`), its USB-UART chip is
|
|
623
|
+
not in the VID whitelist. Check what detection sees with `com2tty --list`, then
|
|
624
|
+
force the board family with `--board` (`esp32`, `pico`, `nrf52`, `samd`, or
|
|
625
|
+
`stm32`) so that reset and upload handling still work.
|
|
626
|
+
|
|
426
627
|
If the WSL helper reports a permission error while creating the serial symlink,
|
|
427
628
|
the requested path under `/dev` is not writable; the helper falls back to `/tmp`
|
|
428
629
|
and prints the one-time command to link the `/dev` path to it.
|