# PT2 IRIS/M.BLACK LINK State Machine Date: 2026-05-27 This note records the bench-proven closed loop for the `IRIS/M.BLACK LINK` button/lamp path. ## Short Answer There is no current evidence that the CCU first sends a separate "this function exists" capability command for `IRIS/M.BLACK LINK`. The stronger model is: 1. The CCU/RCP session must be awake/active. 2. The CCU must service the RCP report queue. 3. The CCU is the authoritative owner of selector state. 4. When the RCP reports a local button intent, the CCU ACKs the report and mirrors the resulting selector value back to the RCP. For this control, selector `0x0013` bit `0x4000` is the `IRIS/M.BLACK LINK` state. ## Proven Frames Selector value frames: ```text 00 00 13 40 00 09 ; command 0, selector 0x0013, value 0x4000, active 00 00 13 00 00 49 ; command 0, selector 0x0013, value 0x0000, clear ``` Report ACK: ```text 05 00 13 00 00 4C ; command 5 ACK/continuation for selector 0x0013 ``` Readback request: ```text 01 00 13 00 00 48 ; command 1 read selector 0x0013 ``` Observed readback shapes: ```text 04 00 13 40 00 0D ; command-0 write response, selector 0x0013 active 04 00 13 00 00 4D ; command-0 write response, selector 0x0013 clear 04 13 00 40 00 0D ; command-1 readback response, selector 0x0013 active 04 13 00 00 00 4D ; command-1 readback response, selector 0x0013 clear ``` ## Successful Closed Loop Capture: ```text captures/iris-mblack-link-mirror-state-machine.txt captures/iris-mblack-link-mirror-state-machine-result.json ``` Scenario: ```text scenarios/iris-mblack-link-mirror-state-machine.json ``` The visible panel behavior was: ```text press 1: lamp on press 2: lamp off press 3: lamp on ``` The serial behavior matched that cycle. ### Baseline Clear ```text TX 00 00 13 00 00 49 RX 04 00 13 00 00 4D ``` ### Press 1: Active ```text RX 00 00 13 40 00 09 TX 05 00 13 00 00 4C ; ACK report TX 00 00 13 40 00 09 ; mirror active back RX 04 00 13 40 00 0D TX 01 00 13 00 00 48 ; readback RX 04 13 00 40 00 0D ``` ### Press 2: Clear ```text RX 00 00 13 00 00 49 TX 05 00 13 00 00 4C ; ACK report TX 00 00 13 00 00 49 ; mirror clear back RX 04 00 13 00 00 4D TX 01 00 13 00 00 48 ; readback RX 04 13 00 00 00 4D ``` ### Press 3: Active Again ```text RX 00 00 13 40 00 09 TX 05 00 13 00 00 4C TX 00 00 13 40 00 09 RX 04 00 13 40 00 0D TX 01 00 13 00 00 48 RX 04 13 00 40 00 0D ``` ## Interpretation The RCP does not appear to treat the local button press as final local state. It reports local intent to the CCU. The CCU then: 1. ACKs the selector report with command `5`. 2. Applies the chosen state back to the RCP with command `0`. The RCP uses the mirrored/current selector state to decide the next toggle direction. This explains the earlier failed/incomplete behavior: - Without mirroring `0x0013=0x4000` back, repeated presses could keep reporting active because the RCP still believed the selector was clear. - Once the CCU mirrored active back, the next press reported clear. - Once the CCU mirrored clear back, the next press reported active again. ## Wakeup Versus Capability The successful test also had active session traffic: ```text 00 00 00 80 80 5A ; active selector-zero keepalive/report 05 00 00 00 00 5F ; ACK for selector zero ``` That traffic looks like general session/connected behavior, not a per-function enable for `IRIS/M.BLACK LINK`. So the current working model is: - `CONNECT: OK` / active rhythm opens the report path and keeps the panel from falling back to `CONNECT: NOT ACT`. - Selector `0x0013` state tells the RCP the current value of this specific control/lamp. - There may still be feature-specific gates for other controls, but this test did not require a distinct `IRIS/M.BLACK LINK exists` command. ## ROM Correlation The ROM trace in `docs/pt2-iris-mblack-link-rom-trace.md` matches the bench behavior: ```text F006.7 / F6DB.7 -> H'200E -> H'E826 bit14 -> loc_3E54 queues selector 0x0013 ``` At `H'200E`, the ROM reads `F791.5` as the current `IRIS/M.BLACK LINK` state: - if `F791.5` is clear, the local press queues/set reports `0x0013=0x4000`; - if `F791.5` is set, the local press queues/clear reports `0x0013=0x0000`. The selector handler for `0x0013` updates `F791.5` from `E800[0x0013].14`. That is why mirroring command-0 selector state back to the RCP completes the toggle loop. ## Implications For a CCU emulator: - Maintain an authoritative selector table. - Treat RCP button reports as requested state changes, not just notifications. - ACK each report with command `5`. - Write the accepted selector value back with command `0`. - Keep the selector-zero/session rhythm alive separately. For other latched buttons: - The same pattern is likely: RCP emits a selector report, then expects the CCU to mirror the accepted state back. - A button that only reports "active" repeatedly may not be broken; it may be waiting for the CCU to update the selector state that controls its next toggle direction.