# PT2 Fake CCU This folder contains a small modular fake-CCU runner for the Sony RCP PT2-style serial link. The first goal is simple: 1. Open the RCP serial link at `38400 8E1`. 2. Optionally wait for heartbeat. 3. Seed active selector-zero state. 4. Listen for complete RCP report frames. 5. Immediately answer report-looking frames with the neutral command-5 ACK: ```text 05 00 40 00 00 1F ``` ROM and emulator evidence says this consumes the outstanding report cursor without triggering COPY or lamp/display side effects. ## Run Dry-run configuration: ```powershell .\.venv\Scripts\python.exe scripts\ccu_emulator.py --dry-run ``` Run against the bench RCP on COM5: ```powershell .\.venv\Scripts\python.exe scripts\ccu_emulator.py --port COM5 --duration 30 --log captures\ccu-keepalive.txt ``` Power-cycle first through the COM6 relay: ```powershell .\.venv\Scripts\python.exe scripts\ccu_emulator.py --port COM5 --power-cycle --relay-port COM6 --duration 30 --log captures\ccu-keepalive-powercycle.txt ``` Try the older three-frame CONNECT cadence seed instead of the command-0 active seed: ```powershell .\.venv\Scripts\python.exe scripts\ccu_emulator.py --seed connect-sequence --seed-gap 0.700 --duration 30 ``` Optionally add periodic state refresh traffic: ```powershell .\.venv\Scripts\python.exe scripts\ccu_emulator.py --refresh-active --refresh-interval 0.600 --duration 30 ``` Enable the bench-proven IRIS/M.BLACK LINK closed-loop module: ```powershell .\.venv\Scripts\python.exe scripts\ccu_emulator.py --iris-mblack-link --duration 60 --log captures\ccu-iris-mblack-link.txt ``` When the RCP reports selector `0x0013` as `0x4000` or `0x0000`, this module sends: ```text 05 00 13 00 00 4C ; ACK selector 0x0013 00 00 13 40 00 09 ; mirror active, or 00 00 13 00 00 49 for clear ``` That matches the bench-proven IRIS/M.BLACK LINK state machine: the RCP reports local intent, the CCU acknowledges the selector, then the CCU mirrors the accepted state back so the next physical press toggles the other way. ## Layout - `frames.py`: checksums, built-in frames, and simple host-frame builders. - `iris_mblack_link.py`: selector `0x0013` ACK-and-mirror state-machine module. - `modules.py`: small protocol-module interface for feature-specific CCU behavior. - `policy.py`: decides whether an RCP frame should be ACKed. - `refresh.py`: optional periodic state-refresh scheduling. - `serial_link.py`: serial read/write plus checksum-resync frame detection. - `controller.py`: event loop and stats. - `cli.py`: command-line entry point. ## Why Periodic Lamp/Value Writes Help Repeated button/lamp/status writes probably do play into the normal CCU flow. The ROM reloads the broad `F9C5` session watchdog on every complete six-byte RX frame, and command-0/command-4/command-6 table writes refresh the selector tables that drive lamps, readouts, and menus. So a real CCU likely does both: - reactively ACK RCP reports so the report queue advances, and - stream or refresh panel state so the visible UI remains current. The first version keeps those concerns separate: reactive ACKs are always available, while periodic refresh frames are opt-in with `--refresh-frame` or `--refresh-active`.