Commit 3f7f3b1
agent+transport: 5.6× flash throughput over rack pod via baud switching (#89)
## Summary
Three coordinated changes that make the flash agent's high-speed-UART
mode (`DEFAULT_FAST_BAUD = 921600`) actually work over rack-pod
WiFi-bridged links. Previously the host-side baud switch path
(`port.baudrate = baud` — pyserial) silently failed on
`SocketTransport`, so `defib agent {read,write,scan}` over
`tcp://<pod>:9000` fell back to `FALLBACK_BAUD = 115200` and ran at ~10
KB/s.
## Live result on the prototype
256 KB sustained flash read at 0x14000000 through the agent over
`rack://10.216.128.69`:
| Path | Rate | Speedup |
|---|---|---|
| 115200 (fallback) | 11.1 KB/s | 1.0× |
| 921600 (rack baud switch) | **61.9 KB/s** | **5.57×** |
~70 % of the theoretical 8× ceiling — the rest is COBS + windowed-ACK
protocol overhead, which is the same as the on-serial path.
## What changed
### 1. `Transport.set_baudrate(baud)` abstraction
New method on `defib.transport.base.Transport`. Default raises
`NotImplementedError`. Overrides:
- **`SerialTransport`** — sets `self._port.baudrate` (was inlined in
`FlashAgentClient.set_baud`).
- **`Rfc2217Transport`** — already had `set_baudrate` from PR #64
(Vectis); just exposed through the ABC.
- **New `RackTransport(SocketTransport)`** — captures the pod's HTTP
base URL at construction; `set_baudrate` POSTs `{"rate": baud}` to
`/uart/baud`. New `rack://host[:bridge_port][?api=http_port]` URL scheme
in `serial_platform.create_transport` (defaults 9000 / 8080).
`FlashAgentClient.set_baud` now `await transport.set_baudrate(baud)` —
works across all four transport flavours; cleanly returns `False` when
the transport refuses (was: raw `AttributeError`).
### 2. Agent: stop auto-reverting on the post-switch verification window
`handle_set_baud` used to switch UART, then `proto_recv(timeout=3000)`
for a verification packet from the host, reverting to 115200 if nothing
arrived. The "3000 ms" budget is a **CPU-speed-dependent busy-wait** —
`for (volatile int d=25; d>0; d--) {}` × `timeout_ms*100` iterations —
and on a fast Cortex-A7 the actual window collapses to **~300 ms**.
Over a rack pod the host's `POST /uart/baud` itself takes ~1 s (WiFi RTT
+ httpd dispatch), so the agent reverted to 115200 long before any
verification packet could land. Result: agent at 115200, bridge at
921600, host reading 35 bytes of misclocked `0x80 0x00 …` garbage
forever.
Fix: drop the verification window. The agent stays at whatever baud the
last `CMD_SET_BAUD` selected. If the new rate doesn't work the agent is
unreachable until the next power-cycle / fastboot — both of which the
rack pod and RouterOS trivially provide.
(This also matches the local-UART experience: defib has been using the
same `set_baud` against MikroTik+pyserial-attached cameras successfully
because pyserial's `port.baudrate=` is microsecond-fast, easily landing
within the agent's collapsed ~300 ms window. The bug only surfaces when
the host-side switch is on the wrong side of a high-RTT control plane.)
### 3. Pod firmware (rack repo, local-only —
`uart-bridge-flush-rx-on-accept` branch)
Defensive UART hygiene around `/uart/baud`: drain the TX FIFO at the old
rate before `uart_set_baudrate`, and read back the actual divisor via
`uart_get_baudrate`. Belt + braces — even with the agent fix, leaving
in-flight bytes from the old rate gets clocked out at the new rate and
corrupts the agent's RX window.
## Tests
7 new `tests/test_transport_rack.py`:
- `set_baudrate` POSTs correct URL + body
- HTTP / URL errors surface as `TransportError`
- `rack://` URL parsing with default + custom + `?api=` query
- Reject missing host
Suite: **468 passed / 2 skipped**; ruff + mypy clean.
## Test plan
- [ ] `uv run pytest tests/ -x -v --ignore=tests/fuzz`
- [ ] `uv run ruff check src/defib/ tests/`
- [ ] `uv run mypy src/defib/ --ignore-missing-imports`
- [ ] Regression: agent baud switch on local serial (pyserial path) —
same protocol changes, just no `RackTransport`. Confirm reading 256 KB
at 921600 still works on a USB-serial-attached camera.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Dmitry Ilyin <widgetii@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent deabdc2 commit 3f7f3b1
7 files changed
Lines changed: 355 additions & 34 deletions
File tree
- agent
- src/defib
- agent
- transport
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
969 | 969 | | |
970 | 970 | | |
971 | 971 | | |
972 | | - | |
973 | | - | |
974 | | - | |
975 | | - | |
976 | | - | |
977 | | - | |
978 | | - | |
979 | | - | |
980 | | - | |
981 | | - | |
982 | | - | |
983 | | - | |
984 | | - | |
985 | | - | |
986 | | - | |
987 | | - | |
988 | | - | |
989 | | - | |
990 | | - | |
991 | | - | |
992 | | - | |
993 | | - | |
994 | | - | |
995 | | - | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
996 | 986 | | |
997 | 987 | | |
998 | 988 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
753 | 753 | | |
754 | 754 | | |
755 | 755 | | |
756 | | - | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
757 | 764 | | |
758 | 765 | | |
759 | 766 | | |
760 | 767 | | |
761 | 768 | | |
762 | | - | |
763 | | - | |
764 | | - | |
765 | | - | |
766 | | - | |
767 | | - | |
| 769 | + | |
768 | 770 | | |
769 | 771 | | |
770 | 772 | | |
| |||
775 | 777 | | |
776 | 778 | | |
777 | 779 | | |
778 | | - | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
779 | 796 | | |
780 | | - | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
781 | 811 | | |
782 | 812 | | |
783 | 813 | | |
784 | 814 | | |
785 | 815 | | |
786 | 816 | | |
| 817 | + | |
787 | 818 | | |
788 | 819 | | |
789 | 820 | | |
790 | 821 | | |
791 | 822 | | |
792 | 823 | | |
793 | | - | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
794 | 828 | | |
795 | 829 | | |
796 | 830 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
133 | 133 | | |
134 | 134 | | |
135 | 135 | | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
136 | 150 | | |
137 | 151 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
111 | 114 | | |
112 | 115 | | |
113 | 116 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
167 | 205 | | |
168 | 206 | | |
169 | 207 | | |
| |||
0 commit comments