from __future__ import annotations from copy import deepcopy from typing import Any JsonObject = dict[str, Any] CURRENT_TABLE_BASE = 0xE800 PRIMARY_TABLE_BASE = 0xE000 SECONDARY_TABLE_BASE = 0xE400 PANEL_SELECTOR_SEMANTICS: tuple[JsonObject, ...] = ( { "selector": 0x0013, "selector_hex": "0x0013", "name": "slave_and_iris_mblack_link_lamps", "summary": ( "Selector 0x0013 is a two-bit lamp/status word. ROM dispatch H'2E06 " "reads current table word H'E826 and fans bit 15 and bit 14 into panel latch RAM." ), "state_machine": { "name_candidate": "iris_mblack_link_closed_loop_state_candidate", "summary": ( "Bench-proven closed loop: the RCP reports local IRIS/M.BLACK LINK intent, " "the CCU ACKs selector 0x0013, then the CCU mirrors the accepted selector " "state back with command 0. The mirrored state controls the next toggle direction." ), "active_report_frame": "00 00 13 40 00 09", "clear_report_frame": "00 00 13 00 00 49", "ack_frame": "05 00 13 00 00 4C", "active_mirror_frame": "00 00 13 40 00 09", "clear_mirror_frame": "00 00 13 00 00 49", "confidence": "bench-high", }, "primary_word_address": PRIMARY_TABLE_BASE + 0x0013 * 2, "primary_word_address_hex": "H'E026", "current_word_address": CURRENT_TABLE_BASE + 0x0013 * 2, "current_word_address_hex": "H'E826", "dispatch_handler": "H'2E06", "confidence": "high", "evidence": [ "bench: 00 00 13 80 00 C9 lights far-right SLAVE lamp", "bench: 00 00 13 40 00 09 lights IRIS/M.BLACK LINK lamp", "ROM: H'2E06-H'2E32 tests H'E826 bits 15/14 and sets/clears F791/F713/F716 latch bits", ], "effects": [ { "bit": 15, "mask": 0x8000, "mask_hex": "0x8000", "name": "SLAVE lamp", "when_set": "sets F791.6 and F713.4", "when_clear": "clears F791.6 and F713.4", "ram_bits": ["F791.6", "F713.4"], "handler_range": "H'2E06-H'2E1A", "confidence": "high", }, { "bit": 14, "mask": 0x4000, "mask_hex": "0x4000", "name": "IRIS/M.BLACK LINK lamp", "when_set": "sets F791.5 and F716.7", "when_clear": "clears F791.5 and F716.7", "ram_bits": ["F791.5", "F716.7"], "handler_range": "H'2E1E-H'2E32", "confidence": "high", }, ], "local_triggers": [ { "kind": "panel_input_toggle", "source": "F006.7 / F6DB.7", "handler": "H'200E", "name_candidate": "provisional_iris_mblack_link_button_toggle_report", "summary": ( "When F6DB.7 is asserted and F731 <= 3, the ROM toggles current-table " "bit 14 at H'E826 based on F791.5, then queues selector 0x0013 through loc_3E54." ), "gate": "F731 <= 3", "current_state_bit": "F791.5", "active_value": 0x4000, "active_value_hex": "0x4000", "clear_value": 0x0000, "clear_value_hex": "0x0000", "writes": ["H'E826 bit14"], "queue_call": "loc_3E54", "confidence": "medium-high", }, { "kind": "local_helper_set_clear", "source": "H'1FE8/H'1FFB", "handler": "H'1FE8-H'200D", "summary": "Adjacent local helpers set or clear current-table bit 15 at H'E826 and queue selector 0x0013.", "writes": ["H'E826 bit15"], "queue_call": "loc_3E54", "confidence": "medium", }, ], "value_meanings": [ {"value": 0x8000, "value_hex": "0x8000", "meaning": "SLAVE lamp on", "confidence": "high"}, {"value": 0x4000, "value_hex": "0x4000", "meaning": "IRIS/M.BLACK LINK lamp on", "confidence": "high"}, {"value": 0x0000, "value_hex": "0x0000", "meaning": "SLAVE and IRIS/M.BLACK LINK latch bits clear through H'2E06", "confidence": "high"}, ], }, { "selector": 0x0024, "selector_hex": "0x0024", "name": "lcd_selector_button_lamp", "summary": "Bench-visible LCD selector-button lamp lane.", "primary_word_address": PRIMARY_TABLE_BASE + 0x0024 * 2, "primary_word_address_hex": "H'E048", "current_word_address": CURRENT_TABLE_BASE + 0x0024 * 2, "current_word_address_hex": "H'E848", "confidence": "bench-medium", "value_meanings": [ {"value": 0x8000, "value_hex": "0x8000", "meaning": "LCD selector-button lamp visible", "confidence": "bench-medium"}, {"value": 0x0000, "value_hex": "0x0000", "meaning": "lamp remained visible at 0.5 s in isolation run", "confidence": "bench-low"}, ], }, { "selector": 0x0082, "selector_hex": "0x0082", "name": "iris_readout_lane", "summary": "Bench-visible IRIS seven-segment/display lane.", "primary_word_address": PRIMARY_TABLE_BASE + 0x0082 * 2, "primary_word_address_hex": "H'E104", "current_word_address": CURRENT_TABLE_BASE + 0x0082 * 2, "current_word_address_hex": "H'E904", "confidence": "bench-high", "value_meanings": [ {"value": 0x8000, "value_hex": "0x8000", "meaning": "IRIS display OP", "confidence": "bench-high"}, {"value": 0x4000, "value_hex": "0x4000", "meaning": "IRIS display 1.4", "confidence": "bench-high"}, {"value": 0x0000, "value_hex": "0x0000", "meaning": "IRIS display blank", "confidence": "bench-high"}, ], }, { "selector": 0x0083, "selector_hex": "0x0083", "name": "combined_iris_shutter_master_gain_status_lane", "summary": "Bench-visible combined status/readout lane; clear behavior appears latched or copied elsewhere.", "primary_word_address": PRIMARY_TABLE_BASE + 0x0083 * 2, "primary_word_address_hex": "H'E106", "current_word_address": CURRENT_TABLE_BASE + 0x0083 * 2, "current_word_address_hex": "H'E906", "confidence": "bench-medium-high", "value_meanings": [ {"value": 0x8000, "value_hex": "0x8000", "meaning": "IRIS AUTO, SHUTTER OFF, MASTER GAIN -3", "confidence": "bench-medium-high"}, {"value": 0x0000, "value_hex": "0x0000", "meaning": "same visible state remained at 0.5 s", "confidence": "bench-low"}, ], }, { "selector": 0x0093, "selector_hex": "0x0093", "name": "white_balance_black_flare_mode_lane", "summary": "Bench-visible white-balance and black/flare lamp lane.", "primary_word_address": PRIMARY_TABLE_BASE + 0x0093 * 2, "primary_word_address_hex": "H'E126", "current_word_address": CURRENT_TABLE_BASE + 0x0093 * 2, "current_word_address_hex": "H'E926", "confidence": "bench-high", "value_meanings": [ {"value": 0x8000, "value_hex": "0x8000", "meaning": "BLACK/FLARE MANUAL plus white-balance PRESET", "confidence": "bench-high"}, {"value": 0x4000, "value_hex": "0x4000", "meaning": "BLACK/FLARE MANUAL plus white-balance AUTO", "confidence": "bench-high"}, {"value": 0x2000, "value_hex": "0x2000", "meaning": "BLACK/FLARE MANUAL plus white-balance MANUAL", "confidence": "bench-high"}, {"value": 0x0000, "value_hex": "0x0000", "meaning": "BLACK/FLARE MANUAL plus white-balance MANUAL", "confidence": "bench-high"}, ], }, ) def panel_selector_semantics_payload() -> list[JsonObject]: return deepcopy(list(PANEL_SELECTOR_SEMANTICS)) def known_panel_selector(selector: int) -> JsonObject | None: normalized = selector & 0x01FF for item in PANEL_SELECTOR_SEMANTICS: if int(item["selector"]) == normalized: return deepcopy(item) return None def selector_word_address(table_base: int, selector: int) -> int: return (table_base + ((selector & 0x01FF) * 2)) & 0xFFFF def describe_selector_value(selector: int, value: int) -> list[str]: item = known_panel_selector(selector) if item is None: return [] normalized_value = value & 0xFFFF lines: list[str] = [] for meaning in item.get("value_meanings", []): if not isinstance(meaning, dict) or meaning.get("value") != normalized_value: continue lines.append(str(meaning.get("meaning") or "known panel selector value")) for effect in item.get("effects", []): if not isinstance(effect, dict) or not isinstance(effect.get("mask"), int): continue mask = int(effect["mask"]) & 0xFFFF state = "set" if normalized_value & mask else "clear" action = effect.get("when_set") if state == "set" else effect.get("when_clear") name = str(effect.get("name") or f"bit {effect.get('bit', '?')}") if action: lines.append(f"{name}: bit {effect.get('bit', '?')} {state}; {action}") else: lines.append(f"{name}: bit {effect.get('bit', '?')} {state}") return lines