otehr lamps
This commit is contained in:
82
docs/pt2-lamp-selector-map.md
Normal file
82
docs/pt2-lamp-selector-map.md
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# PT2 Lamp And Panel Output Selector Map
|
||||||
|
|
||||||
|
This note tracks bench-visible lamp/readout effects from CCU-to-RCP selector writes.
|
||||||
|
|
||||||
|
## Current Model
|
||||||
|
|
||||||
|
The panel lamps and seven-segment displays are driven by selector-table state, not by one monolithic "connected" flag. Command 0 writes into the primary/current tables, and several selectors immediately affect visible panel outputs while `CONNECT: OK` is alive.
|
||||||
|
|
||||||
|
Known active-state foundation:
|
||||||
|
|
||||||
|
- `E000[0x0000] = 0x8080` wakes/holds `CONNECT: OK`.
|
||||||
|
- `E000[0x008F]` drives shutter `EVS`/`OFF` style display state and iris AUTO side effects.
|
||||||
|
- `E000[0x0093]` drives at least white-balance and black/flare lamp state.
|
||||||
|
|
||||||
|
## Bench Observations 2026-05-26
|
||||||
|
|
||||||
|
### `lamp-0093-lowbyte-sweep`
|
||||||
|
|
||||||
|
Result: no new visible behavior beyond the already-known `0x0093` family.
|
||||||
|
|
||||||
|
Interpretation:
|
||||||
|
|
||||||
|
- The earlier `0x0093` mapping still stands.
|
||||||
|
- Individual low-byte probes inside a streamed `0x90xx` context did not reveal a new lamp in this run.
|
||||||
|
- Keep `0x9020` as a useful manual/baseline context and `0x90FF` / `0xFFFF` as black/flare AUTO positive controls.
|
||||||
|
|
||||||
|
### `lamp-known-button-selector-probe`
|
||||||
|
|
||||||
|
Visible result:
|
||||||
|
|
||||||
|
- CAM button/lamp flashed on/off.
|
||||||
|
- CALL lamp flashed on/off.
|
||||||
|
- BARS and MASTER lamps flashed on/off.
|
||||||
|
- Camera tally changed red, then later green.
|
||||||
|
- Each visible output illuminated by itself, not as a broad all-lamps blast.
|
||||||
|
|
||||||
|
Serial result:
|
||||||
|
|
||||||
|
- The run stayed in normal `CONNECT: OK` response cadence.
|
||||||
|
- Each command-0 write produced an immediate `04 ...` readback-style frame and repeated `02 00 02 00 00 5A` active responses.
|
||||||
|
|
||||||
|
Candidate mapping:
|
||||||
|
|
||||||
|
| Selector/value pair | Current meaning |
|
||||||
|
| --- | --- |
|
||||||
|
| `0x0007 = 0x8000/0x0000` | strongest CAM POWER lamp candidate |
|
||||||
|
| `0x0015 = 0x8000/0x0000` | strongest CALL lamp candidate |
|
||||||
|
| `0x0012`, `0x0013`, `0x0016`, `0x0017`, `0x0018`, `0x001A` | BARS, MASTER, tally red/green candidates; exact assignment still needs isolation |
|
||||||
|
|
||||||
|
This confirms that the host/CCU can directly drive panel lamps through selector-table writes. It also validates using the ROM dispatch-neighbor list around `0x0007` and `0x0015` as a high-value lamp map.
|
||||||
|
|
||||||
|
### `lamp-broad-status-selector-sweep`
|
||||||
|
|
||||||
|
Visible result:
|
||||||
|
|
||||||
|
- KNEE AUTO lamp flashed a few times.
|
||||||
|
- No other new visible result was reported.
|
||||||
|
|
||||||
|
Candidate selectors in that run:
|
||||||
|
|
||||||
|
`0x0003`, `0x0040`, `0x0081`, `0x0092`, `0x00A7`, `0x00B7`, `0x00B9`, `0x0110`
|
||||||
|
|
||||||
|
Interpretation:
|
||||||
|
|
||||||
|
- KNEE AUTO is likely in this broader status cluster.
|
||||||
|
- Exact selector/value still needs isolation because the broad sweep changed several selectors in sequence.
|
||||||
|
|
||||||
|
## Follow-Up Isolation Scenarios
|
||||||
|
|
||||||
|
Run these with the console visible and record the exact label shown when each lamp changes:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\lamp-isolate-cam-call.json --parity E --log captures\lamp-isolate-cam-call.txt --result-json captures\lamp-isolate-cam-call-result.json
|
||||||
|
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\lamp-isolate-known-neighbors.json --parity E --log captures\lamp-isolate-known-neighbors.txt --result-json captures\lamp-isolate-known-neighbors-result.json
|
||||||
|
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\lamp-isolate-knee-status-selectors.json --parity E --log captures\lamp-isolate-knee-status-selectors.txt --result-json captures\lamp-isolate-knee-status-selectors-result.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Method notes:
|
||||||
|
|
||||||
|
- Record visible changes immediately during each labeled hold. Later `CONNECT: NOT ACT` cleanup is not selector evidence.
|
||||||
|
- If a selector causes a latch or unexpected mode, stop and keep the log instead of continuing the whole sweep.
|
||||||
|
- Prefer exact notes like `selector_0018_high -> tally red`, because the logs already preserve send timestamps and readback frames.
|
||||||
@@ -673,6 +673,18 @@ The first gated watch capture produced a new periodic active-state response:
|
|||||||
|
|
||||||
After treating those as expected gated refresh traffic, the capture had zero novel frames. A direct search found no known CALL/CAM POWER frames in that log. So the gated setup changed the session/status response shape, but it did not yet prove that physical controls beyond the already-known autonomous buttons are reporting.
|
After treating those as expected gated refresh traffic, the capture had zero novel frames. A direct search found no known CALL/CAM POWER frames in that log. So the gated setup changed the session/status response shape, but it did not yet prove that physical controls beyond the already-known autonomous buttons are reporting.
|
||||||
|
|
||||||
|
## Lamp Selector Mapping
|
||||||
|
|
||||||
|
Bench lamp sweeps now prove that several panel outputs are directly driven by command-0 selector writes while `CONNECT: OK` is alive. The current detailed map lives in `docs/pt2-lamp-selector-map.md`.
|
||||||
|
|
||||||
|
Newest confirmed behavior:
|
||||||
|
|
||||||
|
- `lamp-known-button-selector-probe` made CAM, CALL, BARS, MASTER, and camera tally outputs flash individually.
|
||||||
|
- `0x0007 = 0x8000/0x0000` is the strongest CAM POWER lamp candidate.
|
||||||
|
- `0x0015 = 0x8000/0x0000` is the strongest CALL lamp candidate.
|
||||||
|
- Neighbor selectors `0x0012`, `0x0013`, `0x0016`, `0x0017`, `0x0018`, and `0x001A` likely contain BARS/MASTER/tally red/green assignments, pending isolation.
|
||||||
|
- A broader status sweep made KNEE AUTO flash; candidate selectors are `0x0003`, `0x0040`, `0x0081`, `0x0092`, `0x00A7`, `0x00B7`, `0x00B9`, and `0x0110`.
|
||||||
|
|
||||||
## What Is Still Unknown
|
## What Is Still Unknown
|
||||||
|
|
||||||
- The official PT2 names for commands and selectors.
|
- The official PT2 names for commands and selectors.
|
||||||
|
|||||||
336
h8536/emulator/report_queue_probe.py
Normal file
336
h8536/emulator/report_queue_probe.py
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from ..formatting import h16, parse_int
|
||||||
|
from .cli import load_rom
|
||||||
|
from .eeprom_image import write_eeprom_snapshot
|
||||||
|
from .runner import H8536Emulator
|
||||||
|
from .rx_probe import RunContext, _run_until, _rx_ready, format_frame
|
||||||
|
from .uart import UartTiming
|
||||||
|
|
||||||
|
|
||||||
|
CHECKSUM_SEED = 0x5A
|
||||||
|
REPORT_QUEUE_START = 0xF870
|
||||||
|
REPORT_QUEUE_HEAD = 0xF9B0
|
||||||
|
REPORT_QUEUE_TAIL = 0xF9B5
|
||||||
|
TX_STAGING_START = 0xF850
|
||||||
|
TX_FRAME_START = 0xF858
|
||||||
|
TX_FRAME_LENGTH = 6
|
||||||
|
CURRENT_TABLE_START = 0xE800
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class ReportQueueProbeResult:
|
||||||
|
rom_path: Path
|
||||||
|
report_word: int
|
||||||
|
payload_selector: int
|
||||||
|
payload: int
|
||||||
|
expected_frame: bytes
|
||||||
|
boot_summary: str
|
||||||
|
steps: int
|
||||||
|
stopped_reason: str
|
||||||
|
tx_frames: tuple[bytes, ...]
|
||||||
|
staging_bytes: bytes
|
||||||
|
finalized_bytes: bytes
|
||||||
|
state: dict[str, int]
|
||||||
|
eeprom_writes: tuple[str, ...]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def emitted_expected_frame(self) -> bool:
|
||||||
|
return self.expected_frame in self.tx_frames
|
||||||
|
|
||||||
|
def as_dict(self) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"kind": "h8536_report_queue_probe",
|
||||||
|
"rom_path": str(self.rom_path),
|
||||||
|
"report_word": f"0x{self.report_word:04X}",
|
||||||
|
"payload_selector": f"0x{self.payload_selector:04X}",
|
||||||
|
"payload": f"0x{self.payload:04X}",
|
||||||
|
"expected_frame": format_frame(self.expected_frame),
|
||||||
|
"emitted_expected_frame": self.emitted_expected_frame,
|
||||||
|
"boot_summary": self.boot_summary,
|
||||||
|
"steps": self.steps,
|
||||||
|
"stopped_reason": self.stopped_reason,
|
||||||
|
"tx_frames": [format_frame(frame) for frame in self.tx_frames],
|
||||||
|
"staging_bytes_f850_f855": format_frame(self.staging_bytes),
|
||||||
|
"finalized_bytes_f858_f85d": format_frame(self.finalized_bytes),
|
||||||
|
"state": {name: _format_state_value(name, value) for name, value in self.state.items()},
|
||||||
|
"eeprom_writes": list(self.eeprom_writes),
|
||||||
|
}
|
||||||
|
|
||||||
|
def lines(self) -> list[str]:
|
||||||
|
lines = [
|
||||||
|
f"rom={self.rom_path}",
|
||||||
|
self.boot_summary,
|
||||||
|
f"report_word={h16(self.report_word)} payload_selector={h16(self.payload_selector)} payload={h16(self.payload)}",
|
||||||
|
f"expected_frame={format_frame(self.expected_frame)}",
|
||||||
|
f"emitted_expected_frame={int(self.emitted_expected_frame)}",
|
||||||
|
f"stopped={self.stopped_reason} steps={self.steps}",
|
||||||
|
"tx_frames=" + (" | ".join(format_frame(frame) for frame in self.tx_frames) or "none"),
|
||||||
|
f"staging_F850_F855={format_frame(self.staging_bytes)}",
|
||||||
|
f"finalized_F858_F85D={format_frame(self.finalized_bytes)}",
|
||||||
|
"state:",
|
||||||
|
]
|
||||||
|
for name, value in self.state.items():
|
||||||
|
width = 4 if name in {"queue_word", "current_table_word"} else 2
|
||||||
|
lines.append(f" {name}=0x{value:0{width}X}")
|
||||||
|
if self.eeprom_writes:
|
||||||
|
lines.append("eeprom_writes:")
|
||||||
|
lines.extend(f" {line}" for line in self.eeprom_writes)
|
||||||
|
else:
|
||||||
|
lines.append("eeprom_writes=none")
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def build_expected_report_frame(report_word: int, payload: int) -> bytes:
|
||||||
|
first, second, third = encode_report_header(report_word)
|
||||||
|
frame = bytes(
|
||||||
|
[
|
||||||
|
first,
|
||||||
|
second,
|
||||||
|
third,
|
||||||
|
(payload >> 8) & 0xFF,
|
||||||
|
payload & 0xFF,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return frame + bytes([frame_checksum(frame)])
|
||||||
|
|
||||||
|
|
||||||
|
def encode_report_header(report_word: int) -> tuple[int, int, int]:
|
||||||
|
raw = report_word & 0xFFFF
|
||||||
|
encoded_selector = _loc_6206_selector_encode(raw)
|
||||||
|
|
||||||
|
r1 = _swap_bytes(raw)
|
||||||
|
r1 = (r1 & 0xFF00) | ((r1 & 0xFF) >> 1)
|
||||||
|
r2 = r1 & 0xFF
|
||||||
|
|
||||||
|
first = r1 & 0x07
|
||||||
|
third = encoded_selector & 0xFF
|
||||||
|
swapped_encoded = _swap_bytes(encoded_selector)
|
||||||
|
second = (swapped_encoded & 0xFF) | (r2 & 0x78)
|
||||||
|
return first & 0xFF, second & 0xFF, third & 0xFF
|
||||||
|
|
||||||
|
|
||||||
|
def report_payload_selector(report_word: int) -> int:
|
||||||
|
return report_word & 0x01FF
|
||||||
|
|
||||||
|
|
||||||
|
def frame_checksum(frame_without_checksum: bytes) -> int:
|
||||||
|
checksum = CHECKSUM_SEED
|
||||||
|
for value in frame_without_checksum[: TX_FRAME_LENGTH - 1]:
|
||||||
|
checksum ^= value
|
||||||
|
return checksum & 0xFF
|
||||||
|
|
||||||
|
|
||||||
|
def run_report_queue_probe(
|
||||||
|
*,
|
||||||
|
report_word: int = 0x0204,
|
||||||
|
payload: int = 0x0000,
|
||||||
|
queue_index: int = 0,
|
||||||
|
rom_path: Path | None = None,
|
||||||
|
boot_steps: int = 250_000,
|
||||||
|
max_steps: int = 200_000,
|
||||||
|
eeprom_seed: str = "blank",
|
||||||
|
eeprom_image: bytes | None = None,
|
||||||
|
tx_wire_timing: bool = False,
|
||||||
|
uart_baud: int = 38_400,
|
||||||
|
uart_format: str = "8E1",
|
||||||
|
p9_fast_path: bool = True,
|
||||||
|
p9_fast_input: int = 0xFF,
|
||||||
|
p7_input: int = 0xFF,
|
||||||
|
) -> tuple[H8536Emulator, ReportQueueProbeResult]:
|
||||||
|
rom_bytes, discovered_rom_path = load_rom(rom_path)
|
||||||
|
emulator = H8536Emulator(
|
||||||
|
rom_bytes,
|
||||||
|
p9_fast_path_enabled=p9_fast_path,
|
||||||
|
p9_fast_default_input_byte=p9_fast_input,
|
||||||
|
p7_input=p7_input,
|
||||||
|
eeprom_seed=eeprom_seed,
|
||||||
|
sci1_tx_timing=UartTiming.from_format(uart_format, baud=uart_baud) if tx_wire_timing else None,
|
||||||
|
)
|
||||||
|
if eeprom_image is not None:
|
||||||
|
emulator.memory.load_eeprom_image(eeprom_image)
|
||||||
|
|
||||||
|
boot_context = RunContext()
|
||||||
|
boot_used, boot_reason = _run_until(emulator, boot_steps, _rx_ready, boot_context)
|
||||||
|
boot_summary = (
|
||||||
|
f"boot={boot_reason} steps={boot_used} pc={h16(emulator.cpu.pc)} "
|
||||||
|
f"rx_serviceable={int(_rx_ready(emulator))} lcd_display={emulator.memory.lcd.display_text(lines=4)!r}"
|
||||||
|
)
|
||||||
|
|
||||||
|
payload_selector = report_payload_selector(report_word)
|
||||||
|
expected_frame = build_expected_report_frame(report_word, payload)
|
||||||
|
_seed_report_queue(emulator, report_word=report_word, payload=payload, queue_index=queue_index)
|
||||||
|
emulator.memory.clear_eeprom_write_log()
|
||||||
|
|
||||||
|
start_frame_count = len(emulator.sci1.tx_frames)
|
||||||
|
|
||||||
|
def emitted_expected(inner: H8536Emulator) -> bool:
|
||||||
|
return expected_frame in inner.sci1.tx_frames[start_frame_count:]
|
||||||
|
|
||||||
|
run_context = RunContext()
|
||||||
|
steps, reason = _run_until(emulator, max_steps, emitted_expected, run_context)
|
||||||
|
stopped_reason = "expected_frame" if reason == "predicate" else reason
|
||||||
|
|
||||||
|
state = _state_snapshot(emulator, queue_index=queue_index, payload_selector=payload_selector)
|
||||||
|
staging = bytes(emulator.memory.read8(address) for address in range(TX_STAGING_START, TX_STAGING_START + TX_FRAME_LENGTH))
|
||||||
|
finalized = bytes(emulator.memory.read8(address) for address in range(TX_FRAME_START, TX_FRAME_START + TX_FRAME_LENGTH))
|
||||||
|
result = ReportQueueProbeResult(
|
||||||
|
rom_path=discovered_rom_path,
|
||||||
|
report_word=report_word & 0xFFFF,
|
||||||
|
payload_selector=payload_selector,
|
||||||
|
payload=payload & 0xFFFF,
|
||||||
|
expected_frame=expected_frame,
|
||||||
|
boot_summary=boot_summary,
|
||||||
|
steps=steps,
|
||||||
|
stopped_reason=stopped_reason,
|
||||||
|
tx_frames=tuple(emulator.sci1.tx_frames[start_frame_count:]),
|
||||||
|
staging_bytes=staging,
|
||||||
|
finalized_bytes=finalized,
|
||||||
|
state=state,
|
||||||
|
eeprom_writes=tuple(emulator.memory.p9_bus.x24164_bus.write_log_lines(limit=80)),
|
||||||
|
)
|
||||||
|
return emulator, result
|
||||||
|
|
||||||
|
|
||||||
|
def build_arg_parser() -> argparse.ArgumentParser:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Seed the ROM report queue and let the H8/536 ROM build the matching SCI1 TX frame."
|
||||||
|
)
|
||||||
|
parser.add_argument("--rom", type=Path, help="ROM image path; defaults to ROM/M27C512@DIP28_1.BIN")
|
||||||
|
parser.add_argument("--report-word", type=parse_int, default=0x0204, help="word to place in F870 report queue")
|
||||||
|
parser.add_argument("--payload", type=parse_int, default=0x0000, help="word to place in E800[current selector]")
|
||||||
|
parser.add_argument("--queue-index", type=parse_int, default=0, help="F870 queue slot to seed")
|
||||||
|
parser.add_argument("--boot-steps", type=int, default=250_000, help="maximum boot steps before queue seeding")
|
||||||
|
parser.add_argument("--max-steps", type=int, default=200_000, help="maximum steps after queue seeding")
|
||||||
|
parser.add_argument("--tx-wire-timing", action="store_true", help="model UART TX character time between TXI bytes")
|
||||||
|
parser.add_argument("--uart-baud", type=parse_int, default=38_400, help="baud rate used with --tx-wire-timing")
|
||||||
|
parser.add_argument("--uart-format", default="8E1", help="UART format used with --tx-wire-timing")
|
||||||
|
parser.add_argument("--no-p9-fast-path", action="store_true", help="disable shortcut handling for known P9 routines")
|
||||||
|
parser.add_argument("--p9-fast-input", type=parse_int, default=0xFF, help="default byte returned by P9 fast-path reads")
|
||||||
|
parser.add_argument("--p7-input", type=parse_int, default=0xFF, help="external P7 pin state; DIP-off default is 0xFF")
|
||||||
|
parser.add_argument("--eeprom-seed", choices=("blank", "factory"), default="blank", help="initial X24164/shadow state")
|
||||||
|
parser.add_argument("--eeprom-load", type=Path, help="load a 0x1000-byte logical EEPROM image before booting")
|
||||||
|
parser.add_argument("--eeprom-save", type=Path, help="save the final EEPROM image")
|
||||||
|
parser.add_argument("--eeprom-report", type=Path, help="write a readable EEPROM snapshot")
|
||||||
|
parser.add_argument("--eeprom-report-json", type=Path, help="write a structured EEPROM snapshot")
|
||||||
|
parser.add_argument("--eeprom-report-include-image", action="store_true", help="include full EEPROM image in JSON")
|
||||||
|
parser.add_argument("--json", action="store_true", help="print JSON instead of text")
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
args = build_arg_parser().parse_args(argv)
|
||||||
|
emulator, result = run_report_queue_probe(
|
||||||
|
report_word=args.report_word,
|
||||||
|
payload=args.payload,
|
||||||
|
queue_index=args.queue_index,
|
||||||
|
rom_path=args.rom,
|
||||||
|
boot_steps=args.boot_steps,
|
||||||
|
max_steps=args.max_steps,
|
||||||
|
eeprom_seed=args.eeprom_seed,
|
||||||
|
eeprom_image=args.eeprom_load.read_bytes() if args.eeprom_load else None,
|
||||||
|
tx_wire_timing=args.tx_wire_timing,
|
||||||
|
uart_baud=args.uart_baud,
|
||||||
|
uart_format=args.uart_format,
|
||||||
|
p9_fast_path=not args.no_p9_fast_path,
|
||||||
|
p9_fast_input=args.p9_fast_input,
|
||||||
|
p7_input=args.p7_input,
|
||||||
|
)
|
||||||
|
|
||||||
|
if args.json:
|
||||||
|
print(json.dumps(result.as_dict(), indent=2, sort_keys=True))
|
||||||
|
else:
|
||||||
|
for line in result.lines():
|
||||||
|
print(line)
|
||||||
|
|
||||||
|
if args.eeprom_save:
|
||||||
|
args.eeprom_save.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
args.eeprom_save.write_bytes(emulator.memory.dump_eeprom_image())
|
||||||
|
print(f"eeprom_saved={args.eeprom_save}")
|
||||||
|
if args.eeprom_report:
|
||||||
|
write_eeprom_snapshot(emulator.memory, args.eeprom_report, rom_bytes=emulator.memory.rom.data)
|
||||||
|
print(f"eeprom_report={args.eeprom_report}")
|
||||||
|
if args.eeprom_report_json:
|
||||||
|
write_eeprom_snapshot(
|
||||||
|
emulator.memory,
|
||||||
|
args.eeprom_report_json,
|
||||||
|
rom_bytes=emulator.memory.rom.data,
|
||||||
|
as_json=True,
|
||||||
|
include_image_hex=args.eeprom_report_include_image,
|
||||||
|
)
|
||||||
|
print(f"eeprom_report_json={args.eeprom_report_json}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def _seed_report_queue(
|
||||||
|
emulator: H8536Emulator,
|
||||||
|
*,
|
||||||
|
report_word: int,
|
||||||
|
payload: int,
|
||||||
|
queue_index: int,
|
||||||
|
) -> None:
|
||||||
|
queue_index &= 0x7F
|
||||||
|
queue_address = REPORT_QUEUE_START + (queue_index * 2)
|
||||||
|
payload_address = CURRENT_TABLE_START + (report_payload_selector(report_word) * 2)
|
||||||
|
memory = emulator.memory
|
||||||
|
memory.write16(queue_address, report_word)
|
||||||
|
memory.write16(payload_address, payload)
|
||||||
|
memory.write8(REPORT_QUEUE_TAIL, queue_index)
|
||||||
|
memory.write8(REPORT_QUEUE_HEAD, (queue_index + 1) & 0x7F)
|
||||||
|
memory.write8(0xF9C0, 0x00)
|
||||||
|
memory.write8(0xF9C3, 0x00)
|
||||||
|
memory.write8(0xFAA2, 0x00)
|
||||||
|
memory.write8(0xFAA3, 0x00)
|
||||||
|
|
||||||
|
|
||||||
|
def _state_snapshot(emulator: H8536Emulator, *, queue_index: int, payload_selector: int) -> dict[str, int]:
|
||||||
|
memory = emulator.memory
|
||||||
|
queue_address = REPORT_QUEUE_START + ((queue_index & 0x7F) * 2)
|
||||||
|
payload_address = CURRENT_TABLE_START + ((payload_selector & 0x01FF) * 2)
|
||||||
|
return {
|
||||||
|
"queue_head_F9B0": memory.read8(REPORT_QUEUE_HEAD),
|
||||||
|
"queue_tail_F9B5": memory.read8(REPORT_QUEUE_TAIL),
|
||||||
|
"queue_word": memory.read16(queue_address),
|
||||||
|
"current_table_word": memory.read16(payload_address),
|
||||||
|
"tx_gate_F9C0": memory.read8(0xF9C0),
|
||||||
|
"rx_index_F9C3": memory.read8(0xF9C3),
|
||||||
|
"heartbeat_gate_F9C4": memory.read8(0xF9C4),
|
||||||
|
"session_flags_FAA2": memory.read8(0xFAA2),
|
||||||
|
"pending_mask_FAA3": memory.read8(0xFAA3),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _loc_6206_selector_encode(value: int) -> int:
|
||||||
|
value &= 0x01FF
|
||||||
|
if value <= 0x007F:
|
||||||
|
return value
|
||||||
|
if value <= 0x017F:
|
||||||
|
return ((value - 0x0080) + 0x0100) & 0xFFFF
|
||||||
|
return ((value - 0x0180) + 0x0200) & 0xFFFF
|
||||||
|
|
||||||
|
|
||||||
|
def _swap_bytes(value: int) -> int:
|
||||||
|
value &= 0xFFFF
|
||||||
|
return ((value & 0x00FF) << 8) | ((value >> 8) & 0x00FF)
|
||||||
|
|
||||||
|
|
||||||
|
def _format_state_value(name: str, value: int) -> str:
|
||||||
|
width = 4 if name in {"queue_word", "current_table_word"} else 2
|
||||||
|
return f"0x{value:0{width}X}"
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"ReportQueueProbeResult",
|
||||||
|
"build_expected_report_frame",
|
||||||
|
"encode_report_header",
|
||||||
|
"frame_checksum",
|
||||||
|
"main",
|
||||||
|
"report_payload_selector",
|
||||||
|
"run_report_queue_probe",
|
||||||
|
]
|
||||||
8
h8536_emulator_report_queue_probe.py
Normal file
8
h8536_emulator_report_queue_probe.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Compatibility wrapper for the H8/536 report-queue emulator probe."""
|
||||||
|
|
||||||
|
from h8536.emulator.report_queue_probe import main
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
160
scenarios/lamp-0093-lowbyte-sweep.json
Normal file
160
scenarios/lamp-0093-lowbyte-sweep.json
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
{
|
||||||
|
"name": "lamp-0093-lowbyte-sweep",
|
||||||
|
"notes": [
|
||||||
|
"Hold CONNECT OK and vary only the low byte of E000[0x0093] while keeping high byte 0x90.",
|
||||||
|
"Record white-balance AUTO/PRESET/MANUAL, black/flare AUTO/MANUAL/FLARE, iris AUTO, shutter display, and LCD.",
|
||||||
|
"Known references: 0x9020 has behaved like a black/flare manual context; 0x90FF has produced black/flare auto toggles."
|
||||||
|
],
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"action": "power_cycle",
|
||||||
|
"off_seconds": 1.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "wait_ready",
|
||||||
|
"heartbeats": 2,
|
||||||
|
"timeout": 10.0,
|
||||||
|
"require": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "drain",
|
||||||
|
"seconds": 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_1",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_2",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "baseline_0093_9020",
|
||||||
|
"frame": "00 01 13 90 20 F8",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "repeat",
|
||||||
|
"count": 2,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "candidate_0093_9000",
|
||||||
|
"frame": "00 01 13 90 00 D8",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "baseline_0093_9020_after_9000",
|
||||||
|
"frame": "00 01 13 90 20 F8",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "candidate_0093_9001",
|
||||||
|
"frame": "00 01 13 90 01 D9",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "baseline_0093_9020_after_9001",
|
||||||
|
"frame": "00 01 13 90 20 F8",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "candidate_0093_9002",
|
||||||
|
"frame": "00 01 13 90 02 DA",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "baseline_0093_9020_after_9002",
|
||||||
|
"frame": "00 01 13 90 20 F8",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "candidate_0093_9004",
|
||||||
|
"frame": "00 01 13 90 04 DC",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "baseline_0093_9020_after_9004",
|
||||||
|
"frame": "00 01 13 90 20 F8",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "candidate_0093_9008",
|
||||||
|
"frame": "00 01 13 90 08 D0",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "baseline_0093_9020_after_9008",
|
||||||
|
"frame": "00 01 13 90 20 F8",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "candidate_0093_9010",
|
||||||
|
"frame": "00 01 13 90 10 C8",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "baseline_0093_9020_after_9010",
|
||||||
|
"frame": "00 01 13 90 20 F8",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "candidate_0093_9040",
|
||||||
|
"frame": "00 01 13 90 40 98",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "baseline_0093_9020_after_9040",
|
||||||
|
"frame": "00 01 13 90 20 F8",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "candidate_0093_9080",
|
||||||
|
"frame": "00 01 13 90 80 58",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "baseline_0093_9020_after_9080",
|
||||||
|
"frame": "00 01 13 90 20 F8",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "positive_0093_90ff",
|
||||||
|
"frame": "00 01 13 90 FF 27",
|
||||||
|
"listen": 0.55
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "baseline_0093_9020_after_90ff",
|
||||||
|
"frame": "00 01 13 90 20 F8",
|
||||||
|
"listen": 0.55
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "listen",
|
||||||
|
"seconds": 0.80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
184
scenarios/lamp-broad-status-selector-sweep.json
Normal file
184
scenarios/lamp-broad-status-selector-sweep.json
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
{
|
||||||
|
"name": "lamp-broad-status-selector-sweep",
|
||||||
|
"notes": [
|
||||||
|
"Cautious broader primary-table sweep for ROM-mined status selectors that may drive lamps/readouts.",
|
||||||
|
"Each selector is tested with 0x8000 then 0xFFFF, followed by 0x0000 clear. Record visible lamp/readout changes inside each short window.",
|
||||||
|
"If the panel enters CONNECT NOT ACT, stop the run and note the selector label immediately before the transition."
|
||||||
|
],
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"action": "power_cycle",
|
||||||
|
"off_seconds": 1.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "wait_ready",
|
||||||
|
"heartbeats": 2,
|
||||||
|
"timeout": 10.0,
|
||||||
|
"require": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "drain",
|
||||||
|
"seconds": 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_1",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_2",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0003_default_high",
|
||||||
|
"frame": "00 00 03 80 00 D9",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0003_all_bits",
|
||||||
|
"frame": "00 00 03 FF FF 59",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0003_clear",
|
||||||
|
"frame": "00 00 03 00 00 59",
|
||||||
|
"listen": 0.40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0040_high",
|
||||||
|
"frame": "00 00 40 80 00 9A",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0040_all_bits",
|
||||||
|
"frame": "00 00 40 FF FF 1A",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0040_clear",
|
||||||
|
"frame": "00 00 40 00 00 1A",
|
||||||
|
"listen": 0.40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0081_high",
|
||||||
|
"frame": "00 01 01 80 00 DA",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0081_all_bits",
|
||||||
|
"frame": "00 01 01 FF FF 5A",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0081_clear",
|
||||||
|
"frame": "00 01 01 00 00 5A",
|
||||||
|
"listen": 0.40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0092_high",
|
||||||
|
"frame": "00 01 12 80 00 C9",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0092_all_bits",
|
||||||
|
"frame": "00 01 12 FF FF 49",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0092_clear",
|
||||||
|
"frame": "00 01 12 00 00 49",
|
||||||
|
"listen": 0.40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00a7_high",
|
||||||
|
"frame": "00 01 27 80 00 FC",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00a7_all_bits",
|
||||||
|
"frame": "00 01 27 FF FF 7C",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00a7_clear",
|
||||||
|
"frame": "00 01 27 00 00 7C",
|
||||||
|
"listen": 0.40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b7_high",
|
||||||
|
"frame": "00 01 37 80 00 EC",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b7_all_bits",
|
||||||
|
"frame": "00 01 37 FF FF 6C",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b7_clear",
|
||||||
|
"frame": "00 01 37 00 00 6C",
|
||||||
|
"listen": 0.40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b9_high",
|
||||||
|
"frame": "00 01 39 80 00 E2",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b9_all_bits",
|
||||||
|
"frame": "00 01 39 FF FF 62",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b9_clear",
|
||||||
|
"frame": "00 01 39 00 00 62",
|
||||||
|
"listen": 0.40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0110_high",
|
||||||
|
"frame": "00 01 90 80 00 4B",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0110_all_bits",
|
||||||
|
"frame": "00 01 90 FF FF CB",
|
||||||
|
"listen": 0.80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0110_clear",
|
||||||
|
"frame": "00 01 90 00 00 CB",
|
||||||
|
"listen": 0.40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "listen",
|
||||||
|
"seconds": 0.80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
82
scenarios/lamp-isolate-cam-call.json
Normal file
82
scenarios/lamp-isolate-cam-call.json
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
{
|
||||||
|
"name": "lamp-isolate-cam-call",
|
||||||
|
"notes": [
|
||||||
|
"Isolate the two strongest known button/lamp selectors from the previous probe.",
|
||||||
|
"Record whether 0x0007 high/low maps to CAM POWER and whether 0x0015 high/low maps to CALL.",
|
||||||
|
"Each state is held long enough to see a visible lamp transition while staying below the usual inactive timeout."
|
||||||
|
],
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"action": "power_cycle",
|
||||||
|
"off_seconds": 1.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "wait_ready",
|
||||||
|
"heartbeats": 2,
|
||||||
|
"timeout": 10.0,
|
||||||
|
"require": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "drain",
|
||||||
|
"seconds": 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_1",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_2",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "repeat",
|
||||||
|
"count": 3,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "cam_candidate_0007_high",
|
||||||
|
"frame": "00 00 07 80 00 DD",
|
||||||
|
"listen": 1.15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "cam_candidate_0007_low",
|
||||||
|
"frame": "00 00 07 00 00 5D",
|
||||||
|
"listen": 0.85
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_refresh_before_call",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "repeat",
|
||||||
|
"count": 3,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "call_candidate_0015_high",
|
||||||
|
"frame": "00 00 15 80 00 CF",
|
||||||
|
"listen": 1.15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "call_candidate_0015_low",
|
||||||
|
"frame": "00 00 15 00 00 4F",
|
||||||
|
"listen": 0.85
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "listen",
|
||||||
|
"seconds": 0.80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
232
scenarios/lamp-isolate-knee-status-selectors.json
Normal file
232
scenarios/lamp-isolate-knee-status-selectors.json
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
{
|
||||||
|
"name": "lamp-isolate-knee-status-selectors",
|
||||||
|
"notes": [
|
||||||
|
"Isolate broad status selectors after the prior sweep made the KNEE AUTO lamp flash.",
|
||||||
|
"Each candidate is tested high, clear, all-bits, clear. Record the exact console label when KNEE AUTO changes.",
|
||||||
|
"Stop early if the panel latches or falls out of CONNECT OK."
|
||||||
|
],
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"action": "power_cycle",
|
||||||
|
"off_seconds": 1.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "wait_ready",
|
||||||
|
"heartbeats": 2,
|
||||||
|
"timeout": 10.0,
|
||||||
|
"require": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "drain",
|
||||||
|
"seconds": 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_1",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_2",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0003_high",
|
||||||
|
"frame": "00 00 03 80 00 D9",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0003_clear_after_high",
|
||||||
|
"frame": "00 00 03 00 00 59",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0003_all_bits",
|
||||||
|
"frame": "00 00 03 FF FF 59",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0003_clear_after_all",
|
||||||
|
"frame": "00 00 03 00 00 59",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0040_high",
|
||||||
|
"frame": "00 00 40 80 00 9A",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0040_clear_after_high",
|
||||||
|
"frame": "00 00 40 00 00 1A",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0040_all_bits",
|
||||||
|
"frame": "00 00 40 FF FF 1A",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0040_clear_after_all",
|
||||||
|
"frame": "00 00 40 00 00 1A",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0081_high",
|
||||||
|
"frame": "00 01 01 80 00 DA",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0081_clear_after_high",
|
||||||
|
"frame": "00 01 01 00 00 5A",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0081_all_bits",
|
||||||
|
"frame": "00 01 01 FF FF 5A",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0081_clear_after_all",
|
||||||
|
"frame": "00 01 01 00 00 5A",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0092_high",
|
||||||
|
"frame": "00 01 12 80 00 C9",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0092_clear_after_high",
|
||||||
|
"frame": "00 01 12 00 00 49",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0092_all_bits",
|
||||||
|
"frame": "00 01 12 FF FF 49",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0092_clear_after_all",
|
||||||
|
"frame": "00 01 12 00 00 49",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00a7_high",
|
||||||
|
"frame": "00 01 27 80 00 FC",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00a7_clear_after_high",
|
||||||
|
"frame": "00 01 27 00 00 7C",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00a7_all_bits",
|
||||||
|
"frame": "00 01 27 FF FF 7C",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00a7_clear_after_all",
|
||||||
|
"frame": "00 01 27 00 00 7C",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b7_high",
|
||||||
|
"frame": "00 01 37 80 00 EC",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b7_clear_after_high",
|
||||||
|
"frame": "00 01 37 00 00 6C",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b7_all_bits",
|
||||||
|
"frame": "00 01 37 FF FF 6C",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b7_clear_after_all",
|
||||||
|
"frame": "00 01 37 00 00 6C",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b9_high",
|
||||||
|
"frame": "00 01 39 80 00 E2",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b9_clear_after_high",
|
||||||
|
"frame": "00 01 39 00 00 62",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b9_all_bits",
|
||||||
|
"frame": "00 01 39 FF FF 62",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_00b9_clear_after_all",
|
||||||
|
"frame": "00 01 39 00 00 62",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0110_high",
|
||||||
|
"frame": "00 01 90 80 00 4B",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0110_clear_after_high",
|
||||||
|
"frame": "00 01 90 00 00 CB",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0110_all_bits",
|
||||||
|
"frame": "00 01 90 FF FF CB",
|
||||||
|
"listen": 1.20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0110_clear_after_all",
|
||||||
|
"frame": "00 01 90 00 00 CB",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "listen",
|
||||||
|
"seconds": 0.80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
118
scenarios/lamp-isolate-known-neighbors.json
Normal file
118
scenarios/lamp-isolate-known-neighbors.json
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
{
|
||||||
|
"name": "lamp-isolate-known-neighbors",
|
||||||
|
"notes": [
|
||||||
|
"Isolate ROM dispatch neighbors that caused BARS, MASTER, and camera tally changes in the prior run.",
|
||||||
|
"Watch the console label and record exact mappings such as selector_0018_high -> tally red.",
|
||||||
|
"Each selector is tested high then low twice."
|
||||||
|
],
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"action": "power_cycle",
|
||||||
|
"off_seconds": 1.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "wait_ready",
|
||||||
|
"heartbeats": 2,
|
||||||
|
"timeout": 10.0,
|
||||||
|
"require": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "drain",
|
||||||
|
"seconds": 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_1",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_2",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "repeat",
|
||||||
|
"count": 2,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0012_high",
|
||||||
|
"frame": "00 00 12 80 00 C8",
|
||||||
|
"listen": 1.10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0012_low",
|
||||||
|
"frame": "00 00 12 00 00 48",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0013_high",
|
||||||
|
"frame": "00 00 13 80 00 C9",
|
||||||
|
"listen": 1.10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0013_low",
|
||||||
|
"frame": "00 00 13 00 00 49",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0016_high",
|
||||||
|
"frame": "00 00 16 80 00 CC",
|
||||||
|
"listen": 1.10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0016_low",
|
||||||
|
"frame": "00 00 16 00 00 4C",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0017_high",
|
||||||
|
"frame": "00 00 17 80 00 CD",
|
||||||
|
"listen": 1.10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0017_low",
|
||||||
|
"frame": "00 00 17 00 00 4D",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0018_high",
|
||||||
|
"frame": "00 00 18 80 00 C2",
|
||||||
|
"listen": 1.10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_0018_low",
|
||||||
|
"frame": "00 00 18 00 00 42",
|
||||||
|
"listen": 0.70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_001a_high",
|
||||||
|
"frame": "00 00 1A 80 00 C0",
|
||||||
|
"listen": 1.10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_001a_low",
|
||||||
|
"frame": "00 00 1A 00 00 40",
|
||||||
|
"listen": 0.70
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "listen",
|
||||||
|
"seconds": 0.80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
136
scenarios/lamp-known-button-selector-probe.json
Normal file
136
scenarios/lamp-known-button-selector-probe.json
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
{
|
||||||
|
"name": "lamp-known-button-selector-probe",
|
||||||
|
"notes": [
|
||||||
|
"Probe host writes to selector families already tied to autonomous CAM POWER and CALL reports, plus nearby ROM dispatch entries.",
|
||||||
|
"Record CAM POWER, CALL, BARS, AUTO buttons, and any lamp/display movement immediately during each hold.",
|
||||||
|
"This script avoids command 5 copy/latch selectors; it only writes command-0 primary table values."
|
||||||
|
],
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"action": "power_cycle",
|
||||||
|
"off_seconds": 1.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "wait_ready",
|
||||||
|
"heartbeats": 2,
|
||||||
|
"timeout": 10.0,
|
||||||
|
"require": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "drain",
|
||||||
|
"seconds": 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_1",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "selector_zero_ok_seed_2",
|
||||||
|
"frame": "00 00 00 80 00 DA",
|
||||||
|
"listen": 0.60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "cam_power_candidate_0007_high",
|
||||||
|
"frame": "00 00 07 80 00 DD",
|
||||||
|
"listen": 1.00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "cam_power_candidate_0007_low",
|
||||||
|
"frame": "00 00 07 00 00 5D",
|
||||||
|
"listen": 1.00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "call_candidate_0015_high",
|
||||||
|
"frame": "00 00 15 80 00 CF",
|
||||||
|
"listen": 1.00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "call_candidate_0015_low",
|
||||||
|
"frame": "00 00 15 00 00 4F",
|
||||||
|
"listen": 1.00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_0012_high",
|
||||||
|
"frame": "00 00 12 80 00 C8",
|
||||||
|
"listen": 0.90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_0012_low",
|
||||||
|
"frame": "00 00 12 00 00 48",
|
||||||
|
"listen": 0.50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_0013_high",
|
||||||
|
"frame": "00 00 13 80 00 C9",
|
||||||
|
"listen": 0.90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_0013_low",
|
||||||
|
"frame": "00 00 13 00 00 49",
|
||||||
|
"listen": 0.50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_0016_high",
|
||||||
|
"frame": "00 00 16 80 00 CC",
|
||||||
|
"listen": 0.90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_0016_low",
|
||||||
|
"frame": "00 00 16 00 00 4C",
|
||||||
|
"listen": 0.50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_0017_high",
|
||||||
|
"frame": "00 00 17 80 00 CD",
|
||||||
|
"listen": 0.90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_0017_low",
|
||||||
|
"frame": "00 00 17 00 00 4D",
|
||||||
|
"listen": 0.50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_0018_high",
|
||||||
|
"frame": "00 00 18 80 00 C2",
|
||||||
|
"listen": 0.90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_0018_low",
|
||||||
|
"frame": "00 00 18 00 00 42",
|
||||||
|
"listen": 0.50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_001a_high",
|
||||||
|
"frame": "00 00 1A 80 00 C0",
|
||||||
|
"listen": 0.90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "send",
|
||||||
|
"label": "neighbor_001a_low",
|
||||||
|
"frame": "00 00 1A 00 00 40",
|
||||||
|
"listen": 0.50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"action": "listen",
|
||||||
|
"seconds": 0.80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
26
tests/test_emulator_report_queue_probe.py
Normal file
26
tests/test_emulator_report_queue_probe.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from h8536.emulator.report_queue_probe import (
|
||||||
|
build_expected_report_frame,
|
||||||
|
encode_report_header,
|
||||||
|
report_payload_selector,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class EmulatorReportQueueProbeTest(unittest.TestCase):
|
||||||
|
def test_report_word_0204_builds_observed_gated_active_frame(self):
|
||||||
|
self.assertEqual(encode_report_header(0x0204), (0x01, 0x00, 0x04))
|
||||||
|
self.assertEqual(report_payload_selector(0x0204), 0x0004)
|
||||||
|
self.assertEqual(build_expected_report_frame(0x0204, 0x0000), bytes.fromhex("01 00 04 00 00 5F"))
|
||||||
|
|
||||||
|
def test_report_word_0404_builds_observed_transition_frame(self):
|
||||||
|
self.assertEqual(encode_report_header(0x0404), (0x02, 0x00, 0x04))
|
||||||
|
self.assertEqual(report_payload_selector(0x0404), 0x0004)
|
||||||
|
self.assertEqual(build_expected_report_frame(0x0404, 0x0000), bytes.fromhex("02 00 04 00 00 5C"))
|
||||||
|
|
||||||
|
def test_payload_bytes_feed_frame_value_and_checksum(self):
|
||||||
|
self.assertEqual(build_expected_report_frame(0x0204, 0x1234), bytes.fromhex("01 00 04 12 34 79"))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user