From 4c97f0aae9ad610f3fe3e4e8a3784b39a936ee6e Mon Sep 17 00:00:00 2001 From: Aiden <68633820+awils27@users.noreply.github.com> Date: Wed, 13 May 2026 16:54:41 +1000 Subject: [PATCH] run 12 --- ...-buttons-call-45-followup-discovery-b5.txt | 39 +++++++++ docs/discovery-notes.md | 80 ++++++++++++++++++ ...erial_button_response_test.cpython-312.pyc | Bin 18638 -> 19685 bytes scripts/serial_button_response_test.py | 26 +++++- 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 captures/rcp-buttons-call-45-followup-discovery-b5.txt diff --git a/captures/rcp-buttons-call-45-followup-discovery-b5.txt b/captures/rcp-buttons-call-45-followup-discovery-b5.txt new file mode 100644 index 0000000..873330b --- /dev/null +++ b/captures/rcp-buttons-call-45-followup-discovery-b5.txt @@ -0,0 +1,39 @@ +Button test on COM5 at 38400 8N1 +Listening for 15.0s; respond_to_cam_power=False, respond_to_call=True, mirror_call=False +16:48:44.407 RX 001 bytes 00 +16:48:44.439 RX 005 bytes 00 00 00 80 DA +16:48:45.016 RX 006 bytes 00 00 15 80 00 CF +16:48:45.016 DETECT call-on x1 +16:48:45.068 TX button response frame 006 00 00 15 80 00 CF +16:48:45.118 TX button response frame 006 00 00 15 00 00 4F +16:48:45.149 RX 006 bytes 07 80 45 20 D0 68 +16:48:45.149 DETECT watch-frame 07 80 45 20 D0 68 x1 +16:48:45.200 TX watch follow-up frame 006 00 00 00 00 80 DA +16:48:45.202 TX watch follow-up frame 006 00 00 B5 00 80 6F +16:48:47.216 RX 001 bytes 00 +16:48:47.246 RX 005 bytes 00 00 00 80 DA +16:48:47.916 RX 001 bytes 00 +16:48:47.946 RX 005 bytes 00 00 00 80 DA +16:48:48.619 RX 001 bytes 00 +16:48:48.650 RX 005 bytes 00 00 00 80 DA +16:48:49.323 RX 006 bytes 00 00 00 00 80 DA +16:48:49.323 DETECT heartbeat x1 +16:48:50.024 RX 006 bytes 00 00 00 00 80 DA +16:48:50.024 DETECT heartbeat x1 +16:48:50.725 RX 006 bytes 00 00 00 00 80 DA +16:48:50.725 DETECT heartbeat x1 +16:48:51.429 RX 006 bytes 00 00 00 00 80 DA +16:48:51.429 DETECT heartbeat x1 +16:48:52.130 RX 006 bytes 00 00 00 00 80 DA +16:48:52.130 DETECT heartbeat x1 +16:48:52.831 RX 006 bytes 00 00 00 00 80 DA +16:48:52.831 DETECT heartbeat x1 +16:48:53.530 RX 006 bytes 00 00 00 00 80 DA +16:48:53.530 DETECT heartbeat x1 +16:48:54.233 RX 006 bytes 00 00 00 00 80 DA +16:48:54.233 DETECT heartbeat x1 +16:48:54.935 RX 006 bytes 00 00 00 00 80 DA +16:48:54.935 DETECT heartbeat x1 +16:48:55.607 RX 001 bytes 00 +16:48:55.637 RX 005 bytes 00 00 00 80 DA +Stopped. diff --git a/docs/discovery-notes.md b/docs/discovery-notes.md index 9693109..b3d2565 100644 --- a/docs/discovery-notes.md +++ b/docs/discovery-notes.md @@ -3196,3 +3196,83 @@ python scripts/serial_button_response_test.py --port COM5 --duration 15 --prompt If this produces the known `B5` response `07 80 6D 20 D8 48`, then the CALL path does not consume the one-shot discovery response. If it returns heartbeat only, CALL/`0x45` may put the RCP into a similar one-shot consumed state. + +### 2026-05-13 CALL `0x45` Then Discovery Result + +Capture: + +- `captures/rcp-buttons-call-45-followup-discovery-b5.txt` + +Observed sequence: + +```text +RCP CALL high: 00 00 15 80 00 CF +Host CALL high echo: 00 00 15 80 00 CF +Host CALL low echo: 00 00 15 00 00 4F +RCP CALL response: 07 80 45 20 D0 68 +Host primer: 00 00 00 00 80 DA +Host B5 query: 00 00 B5 00 80 6F +``` + +Result: + +- After the follow-up `00 -> B5` query, the RCP returned heartbeat-compatible + traffic only. +- The known `B5` response `07 80 6D 20 D8 48` did not appear. + +Interpretation: + +- The CALL/`0x45` path does not unlock the known discovery query. +- It may consume or bypass the same cold one-shot discovery window, or the RCP + may simply ignore discovery-style queries once the CALL event path has been + exercised. +- This pushes the CALL path into the "useful diagnostic but probably not the + activation handshake" bucket. + +### Cold No-Button CALL Injection Tests + +Question: have we tried sending the CALL response frames without first pressing +the `CALL` button? + +Answer: partially, but not in the exact form that now matters. + +- Earlier command `0x15` matrix tests sent individual `0x15` frames from a cold + panel and saw `CONNECT NOT ACT`, but no non-heartbeat serial response. +- The newer reproducible `0x45` result depends on sending the CALL-high and + CALL-low frames as a pair with a gap. That exact cold/no-button pair has not + been tested yet. + +Tooling note: + +- `scripts/serial_button_response_test.py` now supports `--startup-frame`. These + frames are sent automatically after the listen window begins, without waiting + for a physical button event. + +Test C1: cold CALL pair, 50 ms gap, no physical button press. + +```powershell +python scripts/serial_button_response_test.py --port COM5 --duration 12 --prompt --startup-delay 1.0 --startup-frame-interval 0.05 --startup-frame "00 00 15 80 00 CF" --startup-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-cold-call-pair-gap-50ms.txt +``` + +Test C2: cold CALL pair, 80 ms gap, no physical button press. + +```powershell +python scripts/serial_button_response_test.py --port COM5 --duration 12 --prompt --startup-delay 1.0 --startup-frame-interval 0.08 --startup-frame "00 00 15 80 00 CF" --startup-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-cold-call-pair-gap-80ms.txt +``` + +Test C3: cold CALL high only, no physical button press. + +```powershell +python scripts/serial_button_response_test.py --port COM5 --duration 12 --prompt --startup-delay 1.0 --startup-frame "00 00 15 80 00 CF" --watch-frame "07 80 45 20 D0 68" --watch-frame "07 80 45 30 D0 78" --log captures/rcp-buttons-cold-call-high-only.txt +``` + +Test C4: cold CALL low only, no physical button press. + +```powershell +python scripts/serial_button_response_test.py --port COM5 --duration 12 --prompt --startup-delay 1.0 --startup-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-cold-call-low-only.txt +``` + +For each test, power-cycle first and do not press any panel buttons. If C1/C2 +produce `0x45`, the host can synthesize the CALL event path. If they do not, +the RCP's own physical CALL transition is required before the echo pair has +meaning. diff --git a/scripts/__pycache__/serial_button_response_test.cpython-312.pyc b/scripts/__pycache__/serial_button_response_test.cpython-312.pyc index 80bc6138b553bab01c9dcc103e535f59348abc5b..d3cb795e8ba19c51dcfce8282b0a34a0f35951fe 100644 GIT binary patch delta 2896 zcma)8X;2&29pAUR5+G@Htqvq~EEb0a7Kaen<`Bl=u(8K>oTP1niIKgFg8)HS3kbTZ zlhkdK2~%Ugc8bTzl=MT6;=1lAGi^WgOh5EUQj_38!FVR)NoV?jX|bE;m`pu=Phycw z+-cv;zWwX>Ki~h*+jlO2zg`0RKQoMmK#mJ}-=cb0Fr^Y5EZYnY)4aLrIgJU8W;Z99R(pZcWCWV-knxTF|f?%pj{V56d zLtoJf*qi#iXdQr_)Zesq033r3=237o6=NCzcohCne-b>BA`Ni>o`93aS@7i)WqKQc z)2Su1n*^h&e^_i3NJ4e-Js_o24hRs<2Umy8UB)o(@E+rLv7d)6V4NC$B1elZ{a)O z1w`#f)I%An6H#5z?Twqd7eUqnAY||e;qOVk?7cyqH3R~iX$@r3I&=6bA(726CyjA& zA;xo&K}is~k)gOG#BicB3h`b4M*(K?%=5xXWco}th7a0jiZhO_xS(0jfuR_3GZ`6~ zDThDy*}eBy+fRw#K)T{NygiFHIN?jA?)lVY0mkEFZSrG%%I1HMYHN^*Xfrao zZHYRmO@Vk_E}1cH9?rmzchv$ttO?rGyx}s<8{v~d8x#XBHE%|CJK;dU0>2Yrv^|Qg z=mEH3DuJ~@Yj_4>NuzW~VJ&VFNz;D`X;{jcISiK!7BYGS{ypes9#%|XMT9s#okV|# zAWo3TgE`5_X3_ga-Q!pn{;WaoW@ToP&e{OPY!gl731{MEjKj#(93>u<4bjK4uD^sG z?M$*V8wayZ(pQuiqE9GP?j7w%r*=ZA)`EIfNhVM5Rwt3Pkf=jt%VmPMNfAXwX1Ap5 zD6hqmBgcX3H4gZE9UBtuSe1A1P9#zy2{{o(`7-emrO;>)Owltab{4R3pwOI_ZL$rW%PH$*ZGudY*uQL>VF=q^;TseUVK29!%qE{0saHPES`xwk0tWYQst3L={(39$lMlHjTO%Erius=m^{BgeTRd{T7FVVxt|raIwh)Uu&%OKc^hIj1WB_GZXwSB?v$~PROKa zlF2AisD_ay_BfJjNqVI7iXI=3J!o!7X-+|+XkNCjD>aMg{|7H@lP8j%uX}Qq-R`pK zvMe|SricXfI57o$d9Gc$DMG>hweW7!uX_(37b5&LzVosdT@80k6ykBN3*SmD**h=) z+hb&eJ0;-zQQ{&K(%5K38af>r8JTY8;I-YCidG9Y@2}LsJzW6w!Sj3H0t4_w^I_1N zdc9c<^vtHf$;`bAueKcByQ+$h2*UX47AtdSt`-TgiBUm}NW!Y^KBbe&l?ngdatI!6 zeFolajR7z0ZM({>YBP3`2rneyr)>kY7i9}Z!VWkdR>PUFPIDUptLTZZ!@2OE$o(Wd z(S8^t;Op(@OVX@;g)M)VEnl-Zt~-Srmcb7(F|cfjz>a;>r_u&?#ZdaLp>)k?`M&0Y zWUMSK~GKf?Le z9vmGX6QwRu923P}48H?iJ$~&gnEVaieg}{Bw1C@iwx`mujsX1K7QctK4GI8ohc*KG hUuE#Eo_X}?3XK1Zk;h5EY((K#54cG|1LqEe{{zEN-0T1V delta 2149 zcmah~eQZ-z6u;-aw)<#b*YB>YOef zD6Y(T1W{#$I}^BsUg^!f&tty-8Eb`{uBM?bF(g)=sKS2#9HCk^OzD`m1}FUmLhUra zI#r`zBs#<}HuwtkimgOwV0RQWHxEH zO5R{Zd3UaXOH-xjT~0YxWaaQ^aSj$PxWio&6hrVQUhv3aW=<~Ags#$3y+BE1F@n#o zH;?JWEWA_d;>HN}l~&@(Qo-1!xkr{_pUo3y&YC90w=*$rkvlZa_+ue%m1o5ZmdzX? z2Y9K2W<@&jbkK>RGCS4>)91%+)E0$AwcM@2L{@52ibqznG;*=5+_6)%X|)lFXwM~a zJI887?PElA$m_Han(}h81G;4Q)0Q!EM6Y47I+Murnoo*L*($o2E#@#3x7>_xi+=GF-bUa!iJm;XcNWbQo;?$w#5qDB2D@QIhQDcmYacbJs zxm_S+6TgX5oABhcxzxzc?4izsAs^3RF~B$r$HtJm#6`{2^*;b!>Y4&TuA&e>3K_F} z@$_k}6V*n+OZZQfSI4UJ3N}_b@IcV8zLjjSu-0eG<=PQw7AumUW{>NpG(ZwI9Z4M0 zsby`}yi#0}L@u5qM>Gw!zD}fh%y$rnD~qb~QkE2==!<8tFO7XU^3Z=qI>VXKoLN}~ zQob{=GBqrkBiX1m@~V2n3_uQWi9Gc=;HoMgG~#fTJ2)fF7(~-qV`n4~1Ie1aK@zKx zlg$l6(@Z4prf%u1y3JEXm03}J!pM_DkVp&{26M5oI*rejM{#+zFX)MTsYeR3qEO8* z#ihL2nE0^DkGIRr&NJG=|RyHFb(LXyBcBnm0PwZm8j|))^WXL}4 zIa##}Di)|HlAc=G^DErLEg{p;lEVT&ud(Roit{47)cKNDw3|>%|3H5WRB2y9b>#QYvwTKjF zvEjH+-lu8AAoa0V&&h9NS)JE=V&OO&OX^YqMH2Vz@J)ve0NIwmEq}@|0wW~G_mB}N zn6bAR$O!vQnTkseF8T&q@$@1u7KKNZ@o*bJ3r;RR5AFE%k}g=L80!syfrf58-q2~# zM+XN6hHB>AEwVy+_cU$!RL;@sn>G+OvCX z{DtfqMlWVnGWw&AQ)$}LBF3(iHhCGlDl`QcyH=9UVy@ftJ)X4d*=efmxAt23>!r}^ zAQL(plP6sMUK2l2sbiWOCOy;Ku=1+xaP}7CiH=Kf8{^9l<)38-mek2CeaOg!v17~d zR!MG?q^**)TveaLP-n6616BM|C12soong3z$2yDLzcGdSPa1v1$UPnaCUse$`zs%R d={zhf1F-zDhHK|QxVIMH>hf_T8F;*_{$IWb+GGF# diff --git a/scripts/serial_button_response_test.py b/scripts/serial_button_response_test.py index 2484fa2..72b8446 100644 --- a/scripts/serial_button_response_test.py +++ b/scripts/serial_button_response_test.py @@ -8,6 +8,7 @@ This helper can: 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. +6. Optionally transmit startup frames without waiting for a button event. Known RCP-origin button frames: @@ -175,6 +176,19 @@ def parse_args() -> argparse.Namespace: 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( + "--startup-frame", + type=parse_hex_bytes, + action="append", + help="hex frame to send after listening starts, without waiting for a button event", + ) + parser.add_argument("--startup-delay", type=float, default=0.5) + parser.add_argument( + "--startup-frame-interval", + type=float, + default=0.05, + help="delay between multiple startup frames", + ) parser.add_argument("--response-delay", type=float, default=0.05) parser.add_argument( "--response-frame-interval", @@ -238,7 +252,10 @@ def main() -> int: emit_known_counts(emit, "LATCH QUERY", read_window(ser, args.after_latch)) if args.prompt: - input("Ready to listen. Press Enter, then press CAM POWER/CALL on the RCP: ") + if args.startup_frame: + input("Ready to listen. Press Enter; startup frames will be sent automatically: ") + else: + input("Ready to listen. Press Enter, then press CAM POWER/CALL on the RCP: ") ser.reset_input_buffer() emit( @@ -249,6 +266,13 @@ def main() -> int: ) stop_at = time.monotonic() + args.duration buffer = bytearray() + if args.startup_frame: + time.sleep(args.startup_delay) + for frame_index, frame in enumerate(args.startup_frame): + if frame_index: + time.sleep(args.startup_frame_interval) + send_frame(ser, emit, "startup", frame) + while time.monotonic() < stop_at: data = ser.read(args.chunk_size) if not data: