From 4e8be74dd98a31dea56e33b2651dad7d8fb861b5 Mon Sep 17 00:00:00 2001 From: Aiden <68633820+awils27@users.noreply.github.com> Date: Wed, 13 May 2026 16:36:43 +1000 Subject: [PATCH] run 8 --- ...cp-buttons-call-exact-echo-delay-120ms.txt | 19 +++++ ...rcp-buttons-call-exact-echo-delay-20ms.txt | 19 +++++ ...rcp-buttons-call-exact-echo-delay-50ms.txt | 23 ++++++ ...rcp-buttons-call-exact-echo-delay-80ms.txt | 22 +++++ docs/discovery-notes.md | 75 ++++++++++++++++++ ...erial_button_response_test.cpython-312.pyc | Bin 0 -> 18228 bytes scripts/serial_button_response_test.py | 24 +++++- 7 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 captures/rcp-buttons-call-exact-echo-delay-120ms.txt create mode 100644 captures/rcp-buttons-call-exact-echo-delay-20ms.txt create mode 100644 captures/rcp-buttons-call-exact-echo-delay-50ms.txt create mode 100644 captures/rcp-buttons-call-exact-echo-delay-80ms.txt create mode 100644 scripts/__pycache__/serial_button_response_test.cpython-312.pyc diff --git a/captures/rcp-buttons-call-exact-echo-delay-120ms.txt b/captures/rcp-buttons-call-exact-echo-delay-120ms.txt new file mode 100644 index 0000000..e66706b --- /dev/null +++ b/captures/rcp-buttons-call-exact-echo-delay-120ms.txt @@ -0,0 +1,19 @@ +Button test on COM5 at 38400 8N1 +Listening for 15.0s; respond_to_cam_power=False, respond_to_call=True, mirror_call=False +16:32:20.568 RX 006 bytes 00 00 00 00 80 DA +16:32:20.568 DETECT heartbeat x1 +16:32:21.270 RX 006 bytes 00 00 00 00 80 DA +16:32:21.270 DETECT heartbeat x1 +16:32:21.879 RX 006 bytes 00 00 15 80 00 CF +16:32:21.879 DETECT call-on x1 +16:32:21.999 TX button response frame 006 00 00 15 80 00 CF +16:32:22.000 TX button response frame 006 00 00 15 00 00 4F +16:32:23.980 RX 006 bytes 00 00 00 00 80 DA +16:32:23.980 DETECT heartbeat x1 +16:32:24.654 RX 006 bytes 00 00 15 00 00 4F +16:32:24.654 DETECT call-off x1 +16:32:25.264 RX 001 bytes 00 +16:32:25.294 RX 005 bytes 00 00 00 80 DA +16:32:25.966 RX 001 bytes 00 +16:32:25.996 RX 005 bytes 00 00 00 80 DA +Stopped. diff --git a/captures/rcp-buttons-call-exact-echo-delay-20ms.txt b/captures/rcp-buttons-call-exact-echo-delay-20ms.txt new file mode 100644 index 0000000..11dad36 --- /dev/null +++ b/captures/rcp-buttons-call-exact-echo-delay-20ms.txt @@ -0,0 +1,19 @@ +Button test on COM5 at 38400 8N1 +Listening for 15.0s; respond_to_cam_power=False, respond_to_call=True, mirror_call=False +16:31:27.712 RX 006 bytes 00 00 15 80 00 CF +16:31:27.712 DETECT call-on x1 +16:31:27.733 TX button response frame 006 00 00 15 80 00 CF +16:31:27.733 TX button response frame 006 00 00 15 00 00 4F +16:31:29.683 RX 001 bytes 00 +16:31:29.714 RX 005 bytes 00 00 00 80 DA +16:31:30.383 RX 001 bytes 00 +16:31:30.414 RX 005 bytes 00 00 00 80 DA +16:31:31.087 RX 006 bytes 00 00 00 00 80 DA +16:31:31.087 DETECT heartbeat x1 +16:31:31.788 RX 006 bytes 00 00 00 00 80 DA +16:31:31.788 DETECT heartbeat x1 +16:31:32.490 RX 006 bytes 00 00 00 00 80 DA +16:31:32.490 DETECT heartbeat x1 +16:31:33.193 RX 006 bytes 00 00 00 00 80 DA +16:31:33.193 DETECT heartbeat x1 +Stopped. diff --git a/captures/rcp-buttons-call-exact-echo-delay-50ms.txt b/captures/rcp-buttons-call-exact-echo-delay-50ms.txt new file mode 100644 index 0000000..05cb7ce --- /dev/null +++ b/captures/rcp-buttons-call-exact-echo-delay-50ms.txt @@ -0,0 +1,23 @@ +Button test on COM5 at 38400 8N1 +Listening for 15.0s; respond_to_cam_power=False, respond_to_call=True, mirror_call=False +16:31:45.587 RX 006 bytes 00 00 00 00 80 DA +16:31:45.587 DETECT heartbeat x1 +16:31:46.285 RX 006 bytes 00 00 00 00 80 DA +16:31:46.285 DETECT heartbeat x1 +16:31:46.895 RX 006 bytes 00 00 15 80 00 CF +16:31:46.895 DETECT call-on x1 +16:31:46.946 TX button response frame 006 00 00 15 80 00 CF +16:31:46.946 TX button response frame 006 00 00 15 00 00 4F +16:31:48.895 RX 006 bytes 00 00 00 00 80 DA +16:31:48.895 DETECT heartbeat x1 +16:31:49.049 RX 006 bytes 00 00 15 00 00 4F +16:31:49.049 DETECT call-off x1 +16:31:49.688 RX 006 bytes 00 00 00 00 80 DA +16:31:49.688 DETECT heartbeat x1 +16:31:50.389 RX 006 bytes 00 00 00 00 80 DA +16:31:50.389 DETECT heartbeat x1 +16:31:51.088 RX 006 bytes 00 00 00 00 80 DA +16:31:51.088 DETECT heartbeat x1 +16:31:51.788 RX 006 bytes 00 00 00 00 80 DA +16:31:51.788 DETECT heartbeat x1 +Stopped. diff --git a/captures/rcp-buttons-call-exact-echo-delay-80ms.txt b/captures/rcp-buttons-call-exact-echo-delay-80ms.txt new file mode 100644 index 0000000..0778738 --- /dev/null +++ b/captures/rcp-buttons-call-exact-echo-delay-80ms.txt @@ -0,0 +1,22 @@ +Button test on COM5 at 38400 8N1 +Listening for 15.0s; respond_to_cam_power=False, respond_to_call=True, mirror_call=False +16:32:03.872 RX 006 bytes 00 00 00 00 80 DA +16:32:03.872 DETECT heartbeat x1 +16:32:04.542 RX 001 bytes 00 +16:32:04.572 RX 005 bytes 00 00 00 80 DA +16:32:04.908 RX 006 bytes 00 00 15 80 00 CF +16:32:04.908 DETECT call-on x1 +16:32:04.990 TX button response frame 006 00 00 15 80 00 CF +16:32:04.990 TX button response frame 006 00 00 15 00 00 4F +16:32:05.021 RX 006 bytes 07 80 45 30 D0 78 +16:32:06.967 RX 006 bytes 00 00 00 00 80 DA +16:32:06.967 DETECT heartbeat x1 +16:32:07.457 RX 006 bytes 00 00 15 00 00 4F +16:32:07.457 DETECT call-off x1 +16:32:08.068 RX 006 bytes 00 00 00 00 80 DA +16:32:08.068 DETECT heartbeat x1 +16:32:08.769 RX 006 bytes 00 00 00 00 80 DA +16:32:08.769 DETECT heartbeat x1 +16:32:09.470 RX 006 bytes 00 00 00 00 80 DA +16:32:09.470 DETECT heartbeat x1 +Stopped. diff --git a/docs/discovery-notes.md b/docs/discovery-notes.md index 6db5641..7dec298 100644 --- a/docs/discovery-notes.md +++ b/docs/discovery-notes.md @@ -2959,3 +2959,78 @@ python scripts/serial_button_response_test.py --port COM5 --duration 15 --prompt For each run, power-cycle first, press and hold `CALL` for about 2 seconds, then release after either the watch frame appears or the next heartbeat appears. + +### 2026-05-13 CALL Timing-Bracket Result + +Captures: + +- `captures/rcp-buttons-call-exact-echo-delay-20ms.txt` +- `captures/rcp-buttons-call-exact-echo-delay-50ms.txt` +- `captures/rcp-buttons-call-exact-echo-delay-80ms.txt` +- `captures/rcp-buttons-call-exact-echo-delay-120ms.txt` + +User procedure: + +- Each run used the same two-frame exact CALL echo pair. +- Button hold timing was kept as accurate and consistent as possible. + +Observed result: + +| Delay | Result | +| --- | --- | +| 20 ms | heartbeat only; no `0x45` response | +| 50 ms | heartbeat/CALL traffic only; no `0x45` response | +| 80 ms | new response `07 80 45 30 D0 78` | +| 120 ms | heartbeat/CALL traffic only; no `0x45` response | + +Comparison of known CALL-response-family frames: + +```text +07 80 45 20 D0 68 +07 80 45 30 D0 78 +``` + +Both frames are checksum-valid under the current XOR-with-`0x5A` hypothesis. +They share prefix `07 80`, command/status byte `45`, and value byte `D0`. The +state/status byte changed from `20` to `30`, with the checksum changing from +`68` to `78` as expected. + +Interpretation: + +- The RCP appears to have a CALL-related `0x45` response family. +- The observed `0x45` response is timing-sensitive but not locked only to the + original 50 ms response delay. +- The `0x20` vs `0x30` byte may represent a CALL/button substate, link/session + substate, or timing/window state. +- This is stronger evidence that the panel is responding meaningfully to host + traffic, even though the LCD state still has not been driven active. + +Next CALL timing tests should watch both known `0x45` family frames: + +```powershell +python scripts/serial_button_response_test.py --port COM5 --duration 15 --prompt --respond-to-call --respond-once --response-delay 0.06 --response-frame "00 00 15 80 00 CF" --response-frame "00 00 15 00 00 4F" --watch-frame "07 80 45 20 D0 68" --watch-frame "07 80 45 30 D0 78" --log captures/rcp-buttons-call-exact-echo-delay-60ms.txt +python scripts/serial_button_response_test.py --port COM5 --duration 15 --prompt --respond-to-call --respond-once --response-delay 0.07 --response-frame "00 00 15 80 00 CF" --response-frame "00 00 15 00 00 4F" --watch-frame "07 80 45 20 D0 68" --watch-frame "07 80 45 30 D0 78" --log captures/rcp-buttons-call-exact-echo-delay-70ms.txt +python scripts/serial_button_response_test.py --port COM5 --duration 15 --prompt --respond-to-call --respond-once --response-delay 0.08 --response-frame "00 00 15 80 00 CF" --response-frame "00 00 15 00 00 4F" --watch-frame "07 80 45 20 D0 68" --watch-frame "07 80 45 30 D0 78" --log captures/rcp-buttons-call-exact-echo-delay-80ms-v2.txt +python scripts/serial_button_response_test.py --port COM5 --duration 15 --prompt --respond-to-call --respond-once --response-delay 0.09 --response-frame "00 00 15 80 00 CF" --response-frame "00 00 15 00 00 4F" --watch-frame "07 80 45 20 D0 68" --watch-frame "07 80 45 30 D0 78" --log captures/rcp-buttons-call-exact-echo-delay-90ms.txt +python scripts/serial_button_response_test.py --port COM5 --duration 15 --prompt --respond-to-call --respond-once --response-delay 0.10 --response-frame "00 00 15 80 00 CF" --response-frame "00 00 15 00 00 4F" --watch-frame "07 80 45 20 D0 68" --watch-frame "07 80 45 30 D0 78" --log captures/rcp-buttons-call-exact-echo-delay-100ms.txt +``` + +If the `0x45` family repeats in the 60-100 ms window, the next step is to test +whether the host can answer the RCP's `0x45` response with a checksum-valid +host-shaped frame using command byte `0x45`. + +Tooling note: + +- `scripts/serial_button_response_test.py` now supports + `--followup-on-watch-frame` with one or more `--followup-frame` values. This + lets the host answer a reproduced RCP response immediately in the same run. + +Possible follow-up test after reproducing a `0x45` response: + +```powershell +python scripts/serial_button_response_test.py --port COM5 --duration 15 --prompt --respond-to-call --respond-once --response-delay 0.08 --response-frame "00 00 15 80 00 CF" --response-frame "00 00 15 00 00 4F" --watch-frame "07 80 45 20 D0 68" --watch-frame "07 80 45 30 D0 78" --followup-on-watch-frame --followup-frame "00 00 45 00 80 9F" --log captures/rcp-buttons-call-45-followup-host-shaped.txt +``` + +This test is deliberately secondary. Run it only after the `0x45` family +repeats, so any change can be attributed to the follow-up rather than to the +initial CALL echo timing. diff --git a/scripts/__pycache__/serial_button_response_test.cpython-312.pyc b/scripts/__pycache__/serial_button_response_test.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dccf21ccca920e3e40685ff40ca91f2c117f3c60 GIT binary patch literal 18228 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 literal 0 HcmV?d00001 diff --git a/scripts/serial_button_response_test.py b/scripts/serial_button_response_test.py index 8edb7e8..fcc28cc 100644 --- a/scripts/serial_button_response_test.py +++ b/scripts/serial_button_response_test.py @@ -7,6 +7,7 @@ This helper can: 2. Listen for the button frames that are known to appear while disconnected. 3. Optionally transmit response frames when CAM POWER or CALL is observed. 4. Optionally mirror CALL high/low events with matching host responses. +5. Optionally transmit follow-up frames when a watched response frame appears. Known RCP-origin button frames: @@ -162,6 +163,18 @@ def parse_args() -> argparse.Namespace: action="append", help="hex frame to count when it appears in RX; can be repeated", ) + parser.add_argument( + "--followup-on-watch-frame", + action="store_true", + help="send follow-up frame(s) when any watched frame is observed", + ) + parser.add_argument( + "--followup-frame", + type=parse_hex_bytes, + action="append", + help="hex frame to send after a watched frame appears; can be repeated", + ) + parser.add_argument("--followup-delay", type=float, default=0.05) parser.add_argument("--response-delay", type=float, default=0.05) parser.add_argument("--response-repeat", type=int, default=1) parser.add_argument("--response-interval", type=float, default=0.2) @@ -176,7 +189,10 @@ def parse_args() -> argparse.Namespace: help="with --mirror-call, respond once to CALL high and once to CALL low", ) parser.add_argument("--prompt", action="store_true", help="pause before listen so you can prepare button presses") - return parser.parse_args() + args = parser.parse_args() + if args.followup_on_watch_frame and not args.followup_frame: + parser.error("--followup-on-watch-frame requires at least one --followup-frame") + return args def main() -> int: @@ -187,6 +203,7 @@ def main() -> int: primer = build_frame(0x00, 0x00, args.latch_primer_command, args.state, args.value) query = build_frame(0x00, 0x00, args.latch_query_command, args.state, args.value) responded = False + followup_sent = False mirrored_call_on = False mirrored_call_off = False totals = {name: 0 for name in KNOWN_PATTERNS} @@ -248,6 +265,11 @@ def main() -> int: key = hex_preview(frame) watch_totals[key] += count emit(f"{stamp} DETECT watch-frame {key} x{count}") + if args.followup_on_watch_frame and not followup_sent: + followup_sent = True + time.sleep(args.followup_delay) + for followup in args.followup_frame or []: + send_frame(ser, emit, "watch follow-up", followup) if args.mirror_call: mirrored = False