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 0000000..dccf21c Binary files /dev/null and b/scripts/__pycache__/serial_button_response_test.cpython-312.pyc differ 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