1
0

Compare commits

...

13 Commits

Author SHA1 Message Date
Aiden
0d099235c5 knee page discovery 2026-05-26 19:08:15 +10:00
Aiden
57547fb6ed knee 2026-05-26 18:38:08 +10:00
Aiden
a187214e06 knee auto tests 2026-05-26 18:35:13 +10:00
Aiden
c007f2180c otehr lamps 2026-05-26 18:25:03 +10:00
Aiden
566b4ab108 gated run 2026-05-26 17:44:16 +10:00
Aiden
8d98beb6aa more lamps 2026-05-26 17:18:05 +10:00
Aiden
fb282fea49 black lamp refining 2026-05-26 17:09:52 +10:00
Aiden
de992c6087 Black flare lamp 2026-05-26 17:06:43 +10:00
Aiden
99946170cf more lamp work 2026-05-26 17:03:49 +10:00
Aiden
fec48518c1 isolating lamp behaviour 2026-05-26 16:59:09 +10:00
Aiden
11b6a2dc3b Shutter display 2026-05-26 16:38:32 +10:00
Aiden
3e1d30527f Intresting 2026-05-26 16:17:24 +10:00
Aiden
d9a9dade41 copy in progress 2026-05-26 16:01:20 +10:00
71 changed files with 924795 additions and 22 deletions

View File

@@ -62,7 +62,7 @@ To start the current emulator harness:
The real-device bench helper uses `pyserial`; install repo dependencies with `.\.venv\Scripts\python.exe -m pip install -r requirements.txt` if needed. The real-device bench helper uses `pyserial`; install repo dependencies with `.\.venv\Scripts\python.exe -m pip install -r requirements.txt` if needed.
The current PT2/protocol reconstruction is documented in [docs/pt2-protocol.md](docs/pt2-protocol.md). The current PT2/protocol reconstruction is documented in [docs/pt2-protocol.md](docs/pt2-protocol.md), with focused mini-notes for [COPY state](docs/pt2-copy-state-machine.md) and [menu state](docs/pt2-menu-state-machine.md).
## Real Bench Serial Format ## Real Bench Serial Format
@@ -150,7 +150,7 @@ Current serial observations:
- Bench serial-format finding: real hardware talks `38400 8E1`. Earlier `8N1` captures primarily exercised SCI1 parity/error handling and retry echoes, not the normal command path. After switching bench scripts to even parity, the selector-zero CONNECT path can reach `CONNECT: OK`. - Bench serial-format finding: real hardware talks `38400 8E1`. Earlier `8N1` captures primarily exercised SCI1 parity/error handling and retry echoes, not the normal command path. After switching bench scripts to even parity, the selector-zero CONNECT path can reach `CONNECT: OK`.
- Bench CONNECT recovery finding: `CONNECT:NOT ACT` is recoverable without a power cycle. This makes it a normal no-active-session/cleared-state display rather than a terminal latch; tests can now probe from the idle NOT ACT state directly, then separately check whether OK is held or needs periodic CCU-like refresh traffic. - Bench CONNECT recovery finding: `CONNECT:NOT ACT` is recoverable without a power cycle. This makes it a normal no-active-session/cleared-state display rather than a terminal latch; tests can now probe from the idle NOT ACT state directly, then separately check whether OK is held or needs periodic CCU-like refresh traffic.
- Bench CONNECT cadence finding: the `40 -> 80 -> C0` sequence stayed at `CONNECT:NOT ACT` with 10 ms, 50 ms, and 150 ms gaps, but produced `CONNECT: OK` then returned to `CONNECT:NOT ACT` with 700 ms and 1.5 s gaps. At 700 ms, single `40`/`80`/`C0` frames did not work, but all tested two-frame pairs did. Repeated `80 -> 80` at about 700 ms also worked, so the values do not need to differ. The no-power-cycle NOT ACT recovery capture produced repeated `02 00 02 00 00 5A` OK-path responses before heartbeat traffic resumed. - Bench CONNECT cadence finding: the `40 -> 80 -> C0` sequence stayed at `CONNECT:NOT ACT` with 10 ms, 50 ms, and 150 ms gaps, but produced `CONNECT: OK` then returned to `CONNECT:NOT ACT` with 700 ms and 1.5 s gaps. At 700 ms, single `40`/`80`/`C0` frames did not work, but all tested two-frame pairs did. Repeated `80 -> 80` at about 700 ms also worked, so the values do not need to differ. The no-power-cycle NOT ACT recovery capture produced repeated `02 00 02 00 00 5A` OK-path responses before heartbeat traffic resumed.
- Bench special-selector finding: in the CONNECT OK advance sweep, command-5 selector `0x006C` (`05 00 6C 00 00 33`) produced `CONNECT OK` then a blank LCD with the CAM POWER lamp still on, while selector `0x006D` (`05 00 6D 00 00 32`) produced `CONNECT OK` then `COPY IN PROGRESS` then `CONNECT NOT ACT`. A later fresh isolated `ack-006d` run in `captures/connect-ok-advance-special-20260526-153339.txt` reproduced the copy path after a relay power-cycle. Forced ROM decoding confirms `0x006C -> H'2FAF` and `0x006D -> H'3015`; the `0x006D` path sets display selector `F732=H'1903`, a long `F798` countdown, and the ROM contains the `COPY IN PROGRESS` LCD string. LCD dispatch now traces through `493E[0x19] -> H'930A`, with local table entry `H'9F6A` building `COPY IN PROGRESS` and entry `H'9FDA` building `COPY COMPLETED`; `0x006C` appears to be the completion/exit sibling only after `0x006D` has set the `F795.6/F795.7` copy flags. The RCP-TX7 manual identifies `COPY IN PROGRESS` as the multi-camera `COPY TO SLAVES` transfer state over the RS232C command-link system, with controls locked until `COPY COMPLETED`. - Bench special-selector finding: in the CONNECT OK advance sweep, command-5 selector `0x006C` (`05 00 6C 00 00 33`) produced `CONNECT OK` then a blank LCD with the CAM POWER lamp still on, while selector `0x006D` (`05 00 6D 00 00 32`) produced `CONNECT OK` then `COPY IN PROGRESS` then `CONNECT NOT ACT`. A later fresh isolated `ack-006d` run in `captures/connect-ok-advance-special-20260526-153339.txt` reproduced the copy path after a relay power-cycle. Forced ROM decoding confirms `0x006C -> H'2FAF` and `0x006D -> H'3015`; the `0x006D` path sets display selector `F732=H'1903`, a long `F798` countdown, and the ROM contains the `COPY IN PROGRESS` LCD string. LCD dispatch now traces through `493E[0x19] -> H'930A`, with local table entry `H'9F6A` building `COPY IN PROGRESS` and entry `H'9FDA` building `COPY COMPLETED`; `0x006C` appears to be the completion/exit sibling only after `0x006D` has set the `F795.6/F795.7` copy flags. The RCP-side menu trace now also identifies page `0x01` table entry `H'6FF0` as `OTHERS / COPY TO SLAVES`; it is gated by `E400[0x0015]`, and its local copy-start branch also requires `F791.7` before setting `F76E.6`, `F795.7`, `F731.7`, `F798=H'C8`, `F711.7`, and `F726=H'64`. The RCP-TX7 manual identifies `COPY IN PROGRESS` as the multi-camera `COPY TO SLAVES` transfer state over the RS232C command-link system, with controls locked until `COPY COMPLETED`.
- ROM report-source finding: the active `02/01 ...` frames exposed during CONNECT OK attempts are autonomous `F870 -> BAF2 -> BA26` report-queue transmissions, not ordinary command-1 readbacks. The ROM sets `FAA2.3/FAA3.7` after sending them, so the CCU probably needs to answer in that continuation window with command `4`, `5`, or `6` to consume the report queue and keep the session alive. - ROM report-source finding: the active `02/01 ...` frames exposed during CONNECT OK attempts are autonomous `F870 -> BAF2 -> BA26` report-queue transmissions, not ordinary command-1 readbacks. The ROM sets `FAA2.3/FAA3.7` after sending them, so the CCU probably needs to answer in that continuation window with command `4`, `5`, or `6` to consume the report queue and keep the session alive.
- Board/P9 finding: traced MCU pin 62 `P91` reaches X24164 pin 6 `SCL`, and MCU pin 68 `P97` reaches the shared X24164 pin 5 `SDA` node. The emulator now treats the ROM's `C121/C08B/C0DB/C10C/C142` P9 routines as an X24164-style two-wire EEPROM bus, with ROM logical addresses `0x000-0x7FF` on the `H'A0/H'A1` control-byte family and `0x800-0xFFF` on `H'E0/H'E1`. - Board/P9 finding: traced MCU pin 62 `P91` reaches X24164 pin 6 `SCL`, and MCU pin 68 `P97` reaches the shared X24164 pin 5 `SDA` node. The emulator now treats the ROM's `C121/C08B/C0DB/C10C/C142` P9 routines as an X24164-style two-wire EEPROM bus, with ROM logical addresses `0x000-0x7FF` on the `H'A0/H'A1` control-byte family and `0x800-0xFFF` on `H'E0/H'E1`.
- EEPROM role finding: `loc_40BB` checks `P7DR.7` and the `F402 == H'6B6F` signature before defaulting EEPROM/shadow tables; `loc_4103` writes ROM default words through `BFE0`, `loc_41D2` reads sixteen 8-byte records into `F7B0-F82F`, and the command-4 path at `BD2B-BD5F` can persist serial table writes when `F76E.7` is set. - EEPROM role finding: `loc_40BB` checks `P7DR.7` and the `F402 == H'6B6F` signature before defaulting EEPROM/shadow tables; `loc_4103` writes ROM default words through `BFE0`, `loc_41D2` reads sixteen 8-byte records into `F7B0-F82F`, and the command-4 path at `BD2B-BD5F` can persist serial table writes when `F76E.7` is set.

4263
build/rom_others_menu.asm Normal file

File diff suppressed because it is too large Load Diff

219643
build/rom_others_menu.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

220100
build/rom_others_menu_deep.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

221410
build/rom_others_menu_gate.json Normal file

File diff suppressed because it is too large Load Diff

4642
build/rom_others_page1.asm Normal file

File diff suppressed because it is too large Load Diff

239015
build/rom_others_page1.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,125 @@
# PT2 Copy State Machine
This is a focused reference for the COPY behavior seen on the RCP LCD and traced in the ROM.
## Known Entry Points
### Serial Start / Progress
Frame:
```text
05 00 6D 00 00 32
```
ROM path:
- Command 5 accepts selector `0x006D` at `BD80-BDBF`.
- The selector is queued through `BE70`.
- Selector `0x006D` dispatches to `H'3015`.
Observed effects from forced decode:
- Sets `F731.7`.
- Sets `F795.6/F795.7`.
- Loads `F798=H'C8`.
- Sets display selector `F732=H'1903`.
- Sets `FB02=H'64`.
- Calls the display/report bridge at `48FA`.
- Sets `F76E.6`.
LCD dispatch:
- `F732` high byte `0x19` selects `493E[0x19] -> H'930A`.
- The local table at `H'931C` maps substate `0x03` to `H'9F6A`.
- `H'9F6A` builds `COPY` / `IN PROGRESS`.
### Serial Complete / Exit
Frame:
```text
05 00 6C 00 00 33
```
ROM path:
- Command 5 accepts selector `0x006C` at `BD80-BDBF`.
- The selector is queued through `BE70`.
- Selector `0x006C` dispatches to `H'2FAF`.
Observed effects from forced decode:
- Manipulates `F76E`, `F795`, `F797`, and `F799`.
- Can set display selector `F732=H'1904`.
- Sets `FB02=H'14`.
- Calls the display/report bridge at `48FA`.
LCD dispatch:
- `F732` high byte `0x19` selects `493E[0x19] -> H'930A`.
- The local table at `H'931C` maps substate `0x04` to `H'9FDA`.
- `H'9FDA` builds `COPY` / `COMPLETED`.
### RCP-Side Menu Start
ROM path:
- OTHERS menu page: `493E[0x01] -> H'631C`.
- Local page table: `H'632E`.
- `COPY TO SLAVES` entry handler: `H'6FF0`.
Required gates:
- The entry descriptor before `H'6FF0` requires `E400[0x0015] != 0`.
- The local COPY action branch requires `F770.2` and `F791.7`.
Local branch effects:
- Sets `F76E.6`.
- Sets `F795.7`.
- Sets `F731.7`.
- Loads `F798=H'C8`.
- Sets `F711.7`.
- Loads `F726=H'64`.
- Calls `loc_5500`.
- Displays `COPY TO SLAVES`.
If `F770.2` is set while `F791.7` is clear, the ROM diverts through `H'704C` to a `SET RCP` / `MASTER` display path instead of starting copy.
## Working State Model
| State | Likely indicators | Entry | Exit |
| --- | --- | --- | --- |
| Idle / no copy | `F731.7` clear | Boot, timeout, or completion cleanup | `0x006D` or local COPY branch |
| Copy in progress | `F731.7`, `F795.6/F795.7`, `F798` live, `F732=H'1903` | `05 00 6D 00 00 32` or local COPY branch | `0x006C` in the live window, or timer expiry |
| Copy completed | `F732=H'1904` | `05 00 6C 00 00 33` while copy flags are live | Display/session timeout or next state update |
| Timeout / not active | `F731.7` cleared by timer path | `F797` or `F798` reaches zero | Normal CONNECT recovery traffic |
## Bench Results
Observed on the real panel:
```text
006C alone -> CONNECT OK -> blank
006D alone -> CONNECT OK -> COPY IN PROGRESS -> CONNECT NOT ACT
006D -> 006C after 250 ms -> COPY IN PROGRESS -> COPY COMPLETED
006D -> 006C after 1.0-1.5 s -> COPY IN PROGRESS -> COPY COMPLETED
006D -> 006C after 2.0-2.5 s -> COPY IN PROGRESS -> CONNECT NOT ACT
006D repeated, then 006C -> COPY IN PROGRESS held longer -> COPY COMPLETED
006D repeated without 006C -> COPY IN PROGRESS -> CONNECT NOT ACT
```
Current interpretation:
- `0x006D` is a copy-start/progress-window refresh selector.
- `0x006C` is a completion/exit selector that only behaves cleanly while the copy window is live.
- The copy window is transient and timer-controlled.
- The panel does not treat `0x006C` as a stateless "show completed" command.
## Open Questions
- What sets `F791.7` during normal CCU/RCP operation?
- What exact official PT2 name belongs to selectors `0x006C`, `0x006D`, and `0x006E`?
- Whether `0x006E` is a copy cancel/error sibling or an unrelated special selector.
- Whether the CCU sends repeated progress refreshes during a real COPY TO SLAVES operation.

175
docs/pt2-knee-rom-trace.md Normal file
View File

@@ -0,0 +1,175 @@
# PT2 KNEE ROM Trace
Date: 2026-05-26
## Short Version
KNEE is not a simple held selector bit. The ROM has a dedicated local panel-input handler at `loc_1795`, reached when the panel input word at `F104` changes. That handler uses CCU-side selector state as gates, then either shows a short timed KNEE page or reports a KNEE value change on selector `0x00BC`.
This explains the bench pattern where KNEE AUTO can light or flash and then clear even while serial traffic remains healthy: one ROM path is a timed display/page override, not a maintained lamp value.
## Input Path
The local panel path is:
```text
F104 changes -> F692 updated -> F6F0.1 set -> main dispatcher calls loc_1795
```
The important code anchors are:
```text
3B33 MOV:G.W @H'F104, R0
3B37 CMP:G.W @H'F692, R0
3B3D BSET.B #1, @H'F6F0
3B41 MOV:G.W R0, @H'F692
1630 BCLR.B #1, @H'F6F0
1636 JSR @loc_1795
```
So serial writes can prepare the state table, but the main KNEE control branch appears to require the panel-side input lane to change.
## Handler Decision Table
`loc_1795` reads two words from the primary selector table:
| ROM read | Selector meaning |
| --- | --- |
| `@H'E172` | `E000[0x00B9]` |
| `@H'E220` | `E000[0x0110]` |
The branch is:
```text
1795 if F731 > 2: skip
179C if E000[0x00B9].13 == 0: loc_2127()
17A7 else if E000[0x0110].15 == 1: loc_2127()
17B2 else:
delta = F692 - F6B2
report/update selector 0x00BC via loc_19A2
17C0 F6B2 = F692
```
Practical interpretation:
| Condition | ROM effect | Current meaning |
| --- | --- | --- |
| `0x00B9.13 = 0` | timed KNEE page via `loc_2127` | KNEE value reporting not enabled |
| `0x00B9.13 = 1`, `0x0110.15 = 1` | timed KNEE page via `loc_2127` | override/inhibit mode |
| `0x00B9.13 = 1`, `0x0110.15 = 0` | value delta reported as selector `0x00BC` | likely live KNEE control/report lane |
This downgrades the earlier bench label that treated `0x00B9.15` as the main KNEE gate. The ROM gate for the panel-input handler is `0x00B9.13`.
## Timed KNEE Page
`loc_2127` is the timed page path:
```text
2127 set FB03.7
212D save old F732 into F734, if this is a fresh override
2135 F732 = 0x1C03
213B FB02 = 0x14
2140 call loc_48FA
```
The timer path later decrements `FB02`; when it expires, `loc_48EF` restores `F732` from `F734` and redraws. That is the likely cause of "lights, then falls away" observations.
The LCD dispatcher confirms `F732=0x1C03` is a KNEE page:
```text
493E[0x1C] -> 0x92CC
0x92DE[3] -> 0x95CE
0x960B prints "KNEE"
```
On that KNEE page, the second line is selected like this:
```text
if E000[0x0110].15: "DL"
else if E000[0x00B9].15: "PRESET"
else: "AUTO"
```
So `0x00B9.15` still matters, but it appears to choose the KNEE page label (`PRESET` versus `AUTO`) rather than enabling the report path. `0x0110.15` selects the `DL` label and also forces the timed page path from `loc_1795`.
## Bench Implications
Useful frames to test this model:
| Purpose | Frame |
| --- | --- |
| clear `0x00B9` | `00 01 39 00 00 62` |
| set `0x00B9.13` gate | `00 01 39 20 00 42` |
| set `0x00B9.15` label bit | `00 01 39 80 00 E2` |
| set `0x00B9.15` and `.13` | `00 01 39 A0 00 C2` |
| clear `0x0110` | `00 01 90 00 00 CB` |
| set `0x0110.15` override | `00 01 90 80 00 4B` |
| read `0x00BC` | `01 01 3C 00 00 66` |
The most direct live-control test is:
1. Reach `CONNECT: OK`.
2. Send `00 01 39 20 00 42` to set `0x00B9.13`.
3. Send `00 01 90 00 00 CB` to clear `0x0110.15`.
4. Move or exercise the physical KNEE-related control, if available.
5. Watch for TX/report traffic around selector `0x00BC`.
If no physical KNEE input is moved, the ROM may not enter `loc_1795`, because the trigger is the `F104` panel input change path rather than the serial write itself.
## Bench Observation: DTL / KNEE
The first `knee-rom-gate-and-value-probe` bench run produced a new LCD state with `DTL` on the left and `KNEE` on the right. That is an important confirmation: page `0x1C` contains both a KNEE entry and a DETAIL entry.
Relevant ROM text and page entries:
```text
0x92DE[3] -> 0x95CE KNEE page entry
0x92DE[7] -> 0x97C8 DETAIL page entry
0x960B prints "KNEE"
0x9805 prints "DETAIL"
```
The bench display probably shows the page-0x1C menu neighborhood, with DETAIL abbreviated as `DTL` and KNEE as the selected/right-side item. The log does not encode LCD pixels, but the serial timing around the observation is consistent with the KNEE probe:
```text
00 01 39 20 00 42 ; set 0x00B9.13 gate
00 01 39 A0 00 C2 ; set 0x00B9.15 + 0x00B9.13
00 01 90 80 00 4B ; set 0x0110.15 timed KNEE/DL override
```
Next isolation target: determine whether `DTL/KNEE` appears from `0x00B9.13`, `0x00B9.A0`, `0x0110.15`, or only the combined sequence.
## Panel Correlation
The physical panel has both DETAIL and KNEE buttons near the LCD. That matches the ROM page-`0x1C` neighborhood and makes the observed `DTL/KNEE` state likely to be a local menu/button context rather than a generic lamp status.
Practical implication: once the CCU-side selector gates are prepared, pressing the physical DETAIL/KNEE buttons may be the missing `F104` panel-input transition that calls `loc_1795`. If so, the useful evidence should be:
- visible LCD movement between DETAIL and KNEE entries,
- possible KNEE timed page redraws,
- TX/report traffic for selector `0x00BC` when KNEE input movement is accepted,
- or other page-`0x1C` selector reports from neighboring DETAIL/KNEE controls.
## Follow-Up: Lamp Without LCD Movement
The follow-up run after discovering the DETAIL/KNEE buttons did not reproduce an LCD page change. The observed result was:
- only the later KNEE cases/windows illuminated the KNEE AUTO lamp,
- none of those cases changed the LCD.
Current interpretation:
- `0x0110.15` is still the strongest KNEE AUTO lamp/status source.
- Serial table writes can light KNEE AUTO without necessarily entering the LCD DETAIL/KNEE page.
- The LCD path probably needs an additional local-display/menu condition, not just the CCU-side selector bits.
- The physical DETAIL/KNEE buttons may be scanned by the local panel path, but in this test they did not create a visible LCD transition or new serial report evidence.
This separates two related but distinct paths:
```text
KNEE AUTO lamp/status: mostly selector/table driven, strongest source 0x0110.15
DETAIL/KNEE LCD page: local page/menu context, likely page 0x1C plus panel/menu state
```
Next ROM target: trace the DETAIL and KNEE button scan bits through the page-`0x1C` menu dispatcher, not just the `loc_1795` KNEE value handler.

View File

@@ -0,0 +1,166 @@
# 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` | CAM POWER lamp blink confirmed by isolated run |
| `0x0015 = 0x8000/0x0000` | CALL lamp blink confirmed; red tally also blinked in the same phase |
| `0x0012`, `0x0013`, `0x0016`, `0x0017`, `0x0018`, `0x001A` | ordered candidates for SLAVE, green tally, BARS, MASTER, and neighboring lamp states |
Follow-up `lamp-isolate-cam-call` result:
- First phase blinked CAM POWER.
- Second phase blinked CALL and red tally.
Follow-up `lamp-isolate-known-neighbors` result:
- Visible order was SLAVE, then green tally, then BARS.
- The pattern repeated, and at one point SLAVE and BARS were visible together.
- Treat the ordered mapping as likely but not final until a fresh-boot single-selector run separates latch/persistence effects from the selector under test.
Follow-up `lamp-isolate-neighbor-single-boot` result:
| Fresh-boot candidate | Visible result |
| --- | --- |
| `0x0012 = 0x8000/0x0000` | no visible change reported |
| `0x0013 = 0x8000/0x0000` | SLAVE lamp |
| `0x0016 = 0x8000/0x0000` | camera tally green |
| `0x0017 = 0x8000/0x0000` | BARS lamp |
| `0x0018 = 0x8000/0x0000` | no visible result reported yet |
| `0x001A = 0x8000/0x0000` | no visible result reported yet |
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.
- Follow-up isolation saw KNEE AUTO toward the end of the run, then blinking.
Candidate selectors in that run:
`0x0003`, `0x0040`, `0x0081`, `0x0092`, `0x00A7`, `0x00B7`, `0x00B9`, `0x0110`
Interpretation:
- KNEE AUTO is likely in this broader status cluster.
- Because the visible change happened toward the end, strongest next candidates are `0x00A7`, `0x00B7`, `0x00B9`, and `0x0110`, with `0x0092` kept as a guard candidate.
- Exact selector/value still needs isolation because the broad sweep changed several selectors in sequence.
Follow-up `lamp-isolate-knee-tail-single-boot` result:
| Fresh-boot candidate | Visible result |
| --- | --- |
| `0x0092` | iris AUTO/OFF behavior |
| `0x00A7` | no visible result reported |
| `0x00B7` | no visible result reported |
| `0x00B9` | KNEE AUTO |
| `0x0110` | KNEE AUTO |
Interpretation:
- `0x00B9` and `0x0110` are real KNEE-related selectors, but a ROM trace now shows they are not a simple OR-held lamp pair.
- `loc_1795` is the local KNEE/panel-input handler. It is reached from `F104 -> F692 -> F6F0.1`, then reads `E000[0x00B9]` and `E000[0x0110]`.
- The ROM gate for the live KNEE value/report branch is `0x00B9.13`, not `0x00B9.15`.
- `0x0110.15` forces a timed KNEE page/display override. That fits the observed "lights, then clears" behavior.
- `0x00B9.15` still matters on the timed KNEE LCD page: it selects the `PRESET` label when `0x0110.15` is clear. With both clear, the same page labels KNEE as `AUTO`.
- When `0x00B9.13` is set and `0x0110.15` is clear, the ROM computes `F692 - F6B2` and reports/updates selector `0x00BC`. That is now the strongest candidate for the KNEE control value lane.
Follow-up `lamp-knee-or-precedence` result:
- Case 1 (`0x00B9.15` set, then `0x0110.15` set, then `0x00B9` cleared) kept KNEE AUTO on until near the end, when `0x0110` was cleared.
- Case 2 (`0x0110.15` set, then `0x00B9.15` set, then `0x0110` cleared) turned KNEE AUTO off well before the end, even though `0x00B9` had been set.
- This argues against a simple OR model. Current best interpretation: `0x0110.15` is the stronger live display/control source for KNEE AUTO; `0x00B9.15` is related, but may be a transient, secondary status source, or only meaningful with another gate active.
Follow-up `lamp-knee-sustain-compare` result:
- Repeated `0x00B9.15` refresh never lit KNEE AUTO.
- Repeated `0x0110.15` refresh lit KNEE AUTO, but it turned off again around the middle of the repeated-refresh window.
- This makes `0x00B9.15` look like a context-sensitive or stale interpretation rather than a maintained lamp source.
- `0x0110.15` remains the best KNEE AUTO source, but it is not sufficient by itself to hold the lamp. It likely needs a surrounding CCU status refresh, or another selector periodically clears/rebuilds the visible lamp bank.
Follow-up `lamp-knee-context-hold` result:
- Pairing `0x00B9.15` with the known `0x0093=0x9020` active refresh did not light KNEE AUTO.
- Pairing `0x0110.15` with `0x0093=0x9020` did light KNEE AUTO, but it still turned off around the middle of the run.
- The serial log stayed clean: repeated table readbacks and `02 00 02 00 00 5A` active responses continued, with no resync or NOT ACT-style serial collapse.
- Current best hypothesis: `0x0110.15` behaves more like an edge/pulse or consumed display request than a pure level-held lamp bit. Repeating the same high value may not retrigger it after the display task has consumed the state.
ROM follow-up:
- Detailed notes: `docs/pt2-knee-rom-trace.md`.
- The timed path sets `F732=0x1C03`, `FB02=0x14`, calls `loc_48FA`, and later restores the previous page through `loc_48EF`.
- `F732=0x1C03` dispatches to a KNEE LCD page. Its second line is `DL` when `0x0110.15` is set, `PRESET` when `0x0110.15` is clear and `0x00B9.15` is set, otherwise `AUTO`.
- `knee-rom-gate-and-value-probe` produced a new bench LCD state with `DTL` on the left and `KNEE` on the right. This matches the ROM page-0x1C neighborhood: KNEE entry at `0x95CE`, DETAIL entry at `0x97C8`.
- The panel physically has DETAIL and KNEE buttons near the LCD, so this is likely a local menu/button context. Pressing those buttons during the prepared gate window may supply the `F104` transition that the ROM needs before it calls `loc_1795`.
- Follow-up isolation lit KNEE AUTO in the later KNEE cases/windows but did not change the LCD. Treat the KNEE AUTO lamp and the DETAIL/KNEE LCD page as related but separate paths: `0x0110.15` remains the strongest lamp/status source, while LCD movement likely needs an additional local menu/display gate.
- Next bench retest should include `0x00B9.13` (`00 01 39 20 00 42`) and the `0x00BC` report/read lane, not only the older `0x00B9.15` / `0x0110.15` pair.
## 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
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\lamp-isolate-neighbor-single-boot.json --parity E --log captures\lamp-isolate-neighbor-single-boot.txt --result-json captures\lamp-isolate-neighbor-single-boot-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\lamp-isolate-knee-tail-single-boot.json --parity E --log captures\lamp-isolate-knee-tail-single-boot.txt --result-json captures\lamp-isolate-knee-tail-single-boot-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\lamp-isolate-knee-bit-scan.json --parity E --log captures\lamp-isolate-knee-bit-scan.txt --result-json captures\lamp-isolate-knee-bit-scan-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\lamp-knee-or-precedence.json --parity E --log captures\lamp-knee-or-precedence.txt --result-json captures\lamp-knee-or-precedence-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\lamp-knee-sustain-compare.json --parity E --log captures\lamp-knee-sustain-compare.txt --result-json captures\lamp-knee-sustain-compare-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\lamp-knee-context-hold.json --parity E --log captures\lamp-knee-context-hold.txt --result-json captures\lamp-knee-context-hold-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\lamp-knee-edge-refresh.json --parity E --log captures\lamp-knee-edge-refresh.txt --result-json captures\lamp-knee-edge-refresh-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\knee-rom-gate-and-value-probe.json --parity E --log captures\knee-rom-gate-and-value-probe.txt --result-json captures\knee-rom-gate-and-value-probe-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\knee-rom-dtl-knee-isolation.json --parity E --log captures\knee-rom-dtl-knee-isolation.txt --result-json captures\knee-rom-dtl-knee-isolation-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\knee-detail-physical-button-watch.json --parity E --log captures\knee-detail-physical-button-watch.txt --result-json captures\knee-detail-physical-button-watch-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.
- For the single-boot follow-ups, each candidate gets a fresh power cycle. That is deliberate: it tests whether a lamp is truly driven by that selector rather than retained from a previous write.

View File

@@ -0,0 +1,193 @@
# PT2 Menu State Machine
This is a focused reference for the ROM menu/display selection machinery that drives LCD pages and panel soft-key activity.
## Page Dispatch
Primary display selector:
- `F732` holds the current display/page selector.
- The high byte of `F732` selects a page wrapper through `493E`.
- The low byte is used as a page-local substate/selection, commonly through `F733`.
Important dispatcher:
- `48FA` bridges table/report state into LCD page dispatch.
- `493E[page]` points at a wrapper.
- Wrappers pass a local table pointer to `5FD2`.
For COPY status:
- `F732=H'1903` selects page `0x19`, substate `0x03`, `COPY IN PROGRESS`.
- `F732=H'1904` selects page `0x19`, substate `0x04`, `COPY COMPLETED`.
For OTHERS:
- `493E[0x01] -> H'631C`.
- Local table `H'632E` includes the OTHERS pages.
## Local Entry Selection
`loc_5FD2` is the local menu chooser.
Important RAM:
| RAM | Role |
| --- | --- |
| `F72C` | visible/selectable entry bitmask |
| `F72E` | count of visible/selectable entries |
| `F72F` | cached page high byte |
| `F733` | selected local entry index |
| `FB03.7` | no-entry/error/display suppression flag |
| `FB02` | display/session timer or message timer |
Observed algorithm shape:
1. If the page changed, clear `F72C/F72E` and cache the new page in `F72F`.
2. Walk the page-local handler table from the last entry down.
3. For each handler, read descriptor words immediately before the handler.
4. Compare the entry state descriptor against `F731`.
5. If the entry has required selector descriptors, test `E400 + selector*2`.
6. If requirements pass, set the entry bit in `F72C` and increment `F72E`.
7. Clamp or reset `F733` so it points at a visible entry.
8. If no entries are visible, set `FB03.7`, set `FB02=H'14`, clear `F72F`, and return `R4=H'FFFE`.
Practical meaning:
- A page can exist in ROM but be invisible/inactive until the CCU seeds the right `E400` feature/status selector.
- Command 6 writes the `E400-E7FF` secondary table, but only on the continuation side of the protocol.
## OTHERS / COPY TO SLAVES Gates
OTHERS page map:
| Local entry | Handler | Visible text | Required secondary selector |
| --- | --- | --- | --- |
| 1 | `H'6FF0` | `OTHERS` / `COPY TO SLAVES` | `E400[0x0015] != 0` |
| 2 | `H'70F6` | `OTHERS` / `CAM ID SET` | `E400[0x0043] != 0` |
| 3 | `H'7188` | `OTHERS` / `CAM ID IND` | `E400[0x0037] != 0` |
| 4 | `H'7258` | `OTHERS` / `CAM BARS` | `E400[0x0038] != 0` |
| 5-6 | `H'7328/H'73D8` | marker/percentage pages | `E400[0x0027] != 0` |
COPY TO SLAVES local action gate:
- Handler `H'6FF0` watches `F770.2`.
- If `F770.2` is clear, it only displays the OTHERS/COPY page.
- If `F770.2` is set and `F791.7` is set, it enters the local copy-start branch.
- If `F770.2` is set and `F791.7` is clear, it diverts to `SET RCP` / `MASTER`.
Root OTHERS soft-key bits:
- Root handler `H'6EE4` tests `E000[0x008F]` at `H'E11E`.
- Bit 11 sets `F711.6`.
- Bit 12 sets `F711.4`.
These bits are not only OTHERS soft-key enables. Bench tests show `E000[0x008F]` directly changes the shutter seven-segment display and iris AUTO lamp, so treat it as a packed camera/display status selector that also feeds the OTHERS root handler.
## Button / Lamp Masks
Important RAM:
| RAM | Role |
| --- | --- |
| `F711-F718` | panel output masks used by external panel chips |
| `F711.4-F711.7` | soft-key/menu-related bits seen around OTHERS/COPY |
| `F726` | countdown that temporarily preserves some soft-key bits |
| `F770` | local panel action/change code |
Relevant ROM behavior:
- Init clears `F711-F717` and sets `F718=H'FF`.
- `5A7A` clears `F711.4-F711.7` if `F726 == 0`.
- The FRT timer path decrements `F726`; when it expires, it clears `F713.6` and `F711.4-F711.7`.
- The OTHERS/COPY branch sets `F711.7` and `F726=H'64` to keep the local key/display state alive briefly.
## Bench Implications
To make the local COPY path available from the panel, the fake CCU probably needs to:
1. Recover to a live `CONNECT: OK` style session.
2. Seed root OTHERS soft-key bits:
```text
00 01 0F 18 00 4C ; E000[0x008F] bits 11+12
```
3. During a live continuation/report window, seed the COPY page visibility bit:
```text
06 00 15 00 01 48 ; E400[0x0015] nonzero
```
4. Still satisfy the `F791.7` local copy-start gate.
The current hardest unknown is step 4: the ROM uses `F791.7` in several places, but the source that sets it has not yet been identified.
## Bench Observation: OTHERS Gate Probe
Run:
```text
00 00 00 80 00 DA ; recover/seed CONNECT OK
00 01 0F 18 00 4C ; E000[0x008F] = 0x1800
06 00 15 00 01 48 ; E400[0x0015] = 0x0001, sent in active window
```
Observed on the real panel without touching the controls:
- LCD stayed at `CONNECT: OK`.
- SHUTTER seven-segment display changed to something like `EUS`; manuals make this likely `EVS` rendered on a seven-segment display.
- Iris AUTO lamp illuminated.
- OTHERS menu did not appear by itself.
Interpretation:
- The sequence reached real UI state, not only serial parser state.
- `E000[0x008F]=0x1800` is now a candidate shutter/mode-status value as well as an OTHERS soft-key source. Treat the earlier "soft-key bits" interpretation as incomplete.
- `E400[0x0015]=0x0001` may be the OTHERS/COPY visibility bit, but it may also affect an iris/auto feature path. Isolate before assigning a final meaning.
Recommended isolation probes:
```text
00 01 0F 08 00 5C ; E000[0x008F] bit 11 only
00 01 0F 10 00 44 ; E000[0x008F] bit 12 only
00 01 0F 18 00 4C ; E000[0x008F] bits 11+12
06 00 15 00 00 49 ; E400[0x0015] clear/zero
06 00 15 00 01 48 ; E400[0x0015] low nonzero
06 00 15 80 00 C9 ; E400[0x0015] high nonzero
```
Scenario files:
- `scenarios/others-isolate-008f-bit11.json`
- `scenarios/others-isolate-008f-bit12.json`
- `scenarios/others-isolate-008f-bits11-12.json`
- `scenarios/others-isolate-e400-0015-low.json`
- `scenarios/others-isolate-e400-0015-high.json`
- `scenarios/others-isolate-008f-then-e400-clear.json`
Isolation results:
| Scenario | Visible panel result | Serial result |
| --- | --- | --- |
| `others-isolate-008f-bit11` | Iris AUTO lamp on, SHUTTER seven-segment shows observed `EUS`, likely manual `EVS` | `04 01 0F 08 00 58`, then repeated `02 00 02 00 00 5A` |
| `others-isolate-008f-bit12` | Iris AUTO lamp on, SHUTTER seven-segment shows literal letters `OFF` | `04 01 0F 10 00 40`, then repeated `02 00 02 00 00 5A` |
| `others-isolate-008f-bits11-12` | Iris AUTO lamp on, SHUTTER seven-segment shows observed `EUS`, likely manual `EVS` | `04 01 0F 18 00 48`, then repeated `02 00 02 00 00 5A` |
| `others-isolate-e400-0015-low` | LCD stays `CONNECT: OK` only | repeated `01 00 02 00 00 59` after command 6 |
| `others-isolate-e400-0015-high` | LCD stays `CONNECT: OK` only | repeated `01 00 02 00 00 59` after command 6 |
| `others-isolate-008f-then-e400-clear` | Iris AUTO lamp on, SHUTTER seven-segment shows observed `EUS`, likely manual `EVS` | repeated `01 00 02 00 00 59` after command 6 |
Updated interpretation:
- `E000[0x008F]` directly affects visible shutter/iris UI state.
- Bit 11 selects the observed `EUS` shutter display, probably manual `EVS`; bit 12 selects literal shutter-display text `OFF`; when both are present, the likely `EVS` display appears to win.
- The iris AUTO lamp turns on for either bit 11 or bit 12, so it may be tied to the same status selector or to the resulting display mode.
- `E400[0x0015]` does not visibly change the panel by itself, even though command 6 does alter the report stream from `02 00 02 00 00 5A` to `01 00 02 00 00 59`.
- Keep `E400[0x0015]` as a probable OTHERS/COPY visibility/report-gate candidate, but do not assign the shutter/iris effect to it.
Manual correlation:
- The RCP-TX7 operating instructions list `OTHERS (1/6: SHUTTER)` with an `EVS` button, and say to use the shutter block `C.SCAN` or `SHUTTER ON/OFF` buttons when not using EVS.
- The same RCP-TX7 manual lists `EVS/ECS` under OTHERS for DXC-D30/D30P normal settings.
- A later CCU/RCP manual states that when EVS is on, `EVS` is displayed; when the shutter switch is off, `OFF` is displayed.
- Therefore `E000[0x008F].11` is best labeled `shutter_evs_display_or_mode`, and `E000[0x008F].12` is best labeled `shutter_off_display_or_mode` until ROM traces split display-only status from actual camera setting.

View File

@@ -4,6 +4,12 @@ This document is the current working model for the serial protocol spoken by the
A later RCP manual mentions a "PT2 compatibility mode" for controlling the same CCU family this panel was made for. We are using "PT2" here as a practical label for this six-byte SCI1 protocol model. It is not yet a claim that every field name matches Sony's official PT2 terminology. A later RCP manual mentions a "PT2 compatibility mode" for controlling the same CCU family this panel was made for. We are using "PT2" here as a practical label for this six-byte SCI1 protocol model. It is not yet a claim that every field name matches Sony's official PT2 terminology.
Focused companion notes:
- [PT2 Copy State Machine](pt2-copy-state-machine.md)
- [PT2 Menu State Machine](pt2-menu-state-machine.md)
- [PT2 Shutter Display Trace](pt2-shutter-display-trace.md)
## Current High-Confidence Facts ## Current High-Confidence Facts
- The real bench link is `38400 8E1`, not `38400 8N1`. - The real bench link is `38400 8E1`, not `38400 8N1`.
@@ -562,10 +568,27 @@ The `0x006D` copy path is now confirmed outside the earlier all-suite ordering c
- Selector `0x006D` dispatches to `H'3015`. Forced decoding shows it sets `F731.7`, loads `F798=H'C8`, sets `F795.6/F795.7`, sets display selector `F732=H'1903`, sets `FB02=H'64`, calls `48FA`, then sets `F76E.6`. - Selector `0x006D` dispatches to `H'3015`. Forced decoding shows it sets `F731.7`, loads `F798=H'C8`, sets `F795.6/F795.7`, sets display selector `F732=H'1903`, sets `FB02=H'64`, calls `48FA`, then sets `F76E.6`.
- The LCD dispatch for these states is now traced: `loc_48FA` reads the high byte at `F732`, so `F732=H'1903/H'1904` selects display page `0x19`, not direct page `0x03/0x04`. `493E[0x19] -> H'930A`; that page's local table at `H'931C` includes `H'9F6A` for `COPY` / `IN PROGRESS` and `H'9FDA` for `COPY` / `COMPLETED`. The low byte at `F733` is the substate selector: `0x03` is in-progress and `0x04` is completed. - The LCD dispatch for these states is now traced: `loc_48FA` reads the high byte at `F732`, so `F732=H'1903/H'1904` selects display page `0x19`, not direct page `0x03/0x04`. `493E[0x19] -> H'930A`; that page's local table at `H'931C` includes `H'9F6A` for `COPY` / `IN PROGRESS` and `H'9FDA` for `COPY` / `COMPLETED`. The low byte at `F733` is the substate selector: `0x03` is in-progress and `0x04` is completed.
- This makes the likely copy handshake: `0x006D` starts copy and sets the `F795.6/F795.7` in-progress flags; `0x006C` is the completion/exit sibling only when those flags are live. Sending `0x006C` alone can therefore blank or clear state instead of displaying `COPY COMPLETED`. - This makes the likely copy handshake: `0x006D` starts copy and sets the `F795.6/F795.7` in-progress flags; `0x006C` is the completion/exit sibling only when those flags are live. Sending `0x006C` alone can therefore blank or clear state instead of displaying `COPY COMPLETED`.
- Bench step-through confirmed the sequence model: `006C` alone produced `CONNECT OK -> blank`; `006D` alone produced `CONNECT OK -> COPY IN PROGRESS`; `006D` followed by `006C` after 250 ms produced a brief `COPY IN PROGRESS` then `COPY COMPLETED`; the same after 1.0 s and 1.5 s produced a longer `COPY IN PROGRESS` then `COPY COMPLETED`; after 2.0 s or 2.5 s it fell to `CONNECT:NOT ACT` instead of completing. Repeating `006D` before `006C` also completed successfully in the 2x and 3x repeat tests. A longer `006D` hold test kept `COPY IN PROGRESS` active for several seconds and then completed when `006C` arrived, while the same hold without `006C` timed out from `COPY IN PROGRESS` to `CONNECT:NOT ACT`. This points to `006D` as an in-progress/progress-window refresh selector and `006C` as the explicit completion/exit selector, not a stateless command pair.
- The FRT1 timer path decrements `F797` and `F798`; when either reaches zero, it clears `F731.7`. This matches the observed transient display modes falling back to `CONNECT:NOT ACT`. - The FRT1 timer path decrements `F797` and `F798`; when either reaches zero, it clears `F731.7`. This matches the observed transient display modes falling back to `CONNECT:NOT ACT`.
- The string `COPY IN PROGRESS` is present in the ROM LCD resources, so the `006D` result is not a generic serial artifact. - The string `COPY IN PROGRESS` is present in the ROM LCD resources, so the `006D` result is not a generic serial artifact.
- Manual interpretation: the RCP-TX7 operating manual describes `COPY IN PROGRESS` as the LCD state shown during the multi-camera `COPY TO SLAVES` data-transfer operation over the RS232C command-link system. During that state, all linked RCP units display the message and their buttons/knobs are locked until `COPY COMPLETED`. Therefore selector `0x006D` is best treated as entering a command-link copy/data-transfer state, not as a normal CCU connection ACK. - Manual interpretation: the RCP-TX7 operating manual describes `COPY IN PROGRESS` as the LCD state shown during the multi-camera `COPY TO SLAVES` data-transfer operation over the RS232C command-link system. During that state, all linked RCP units display the message and their buttons/knobs are locked until `COPY COMPLETED`. Therefore selector `0x006D` is best treated as entering a command-link copy/data-transfer state, not as a normal CCU connection ACK.
RCP-side OTHERS/COPY menu trace:
- The OTHERS menu is page `0x01`: `493E[0x01] -> H'631C`, local table `H'632E`.
- Local table entry 1 points to `H'6FF0`, the page that renders `OTHERS` / `COPY TO SLAVES`.
- The entry descriptor immediately before `H'6FF0` requires selector `0x0015` in the secondary table: `E400[0x0015] != 0`. Because command 6 writes `E400`, this is probably a CCU-provided feature/visibility bit, and command 6 must be sent in a live continuation/report window to have an effect.
- When the page sees `F770.2` set, it only follows the local copy-start branch if `F791.7` is already set. That branch sets `F76E.6`, `F795.7`, `F731.7`, `F798=H'C8`, `F711.7`, `F726=H'64`, calls `loc_5500`, then displays `COPY TO SLAVES`. This is the RCP-side equivalent of the serial `0x006D` copy-start effect.
- If `F770.2` is set while `F791.7` is clear, the ROM diverts through `H'704C` to a `SET RCP` / `MASTER` display path instead of starting copy. That makes `F791.7` a second, likely master/link/session gate for the physical COPY operation.
- The OTHERS root handler at `H'6EE4` also tests primary selector `E000[0x008F]` (`H'E11E`) bits 11 and 12, and uses them to set `F711.6` and `F711.4`. Bench isolation shows this selector is broader than an OTHERS gate: bit 11 makes the SHUTTER seven-segment display show observed `EUS`, probably the manual's `EVS` display, and bit 12 makes it show the literal letters `OFF`; either bit also illuminates the iris AUTO lamp.
- Candidate gate probes, not final protocol truth:
```text
00 01 0F 18 00 4C ; command 0, set E000[0x008F] bits 11+12
06 00 15 00 01 48 ; command 6, set E400[0x0015] nonzero; requires live continuation
06 00 15 80 00 C9 ; command 6, alternate nonzero visibility value; requires live continuation
```
Read table state: Read table state:
```powershell ```powershell
@@ -588,6 +611,87 @@ This fits the real panel behavior:
- Correct fake-CCU traffic can wake it to `CONNECT: OK`. - Correct fake-CCU traffic can wake it to `CONNECT: OK`.
- Without richer CCU state, readouts illuminate but show placeholders like `----`. - Without richer CCU state, readouts illuminate but show placeholders like `----`.
## Active-State Local-Control Watch
Bench evidence now suggests `CONNECT: OK` is maintained by an ongoing CCU refresh stream, not by one magic wake frame. This creates a useful local-control test: keep the RCP in the active state and press/turn physical controls while logging device TX.
Two JSON scenarios are set up for that:
```powershell
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\active-control-report-watch-quiet.json --parity E --log captures\active-control-report-watch-quiet.txt --result-json captures\active-control-report-watch-quiet-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\active-control-report-watch-broad.json --parity E --log captures\active-control-report-watch-broad.txt --result-json captures\active-control-report-watch-broad-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\active-control-report-watch-gated.json --parity E --log captures\active-control-report-watch-gated.txt --result-json captures\active-control-report-watch-gated-result.json
```
The quiet scenario sends the selector-zero OK seed, then refreshes `E000[0x0093]=0x9020` every 0.60 s. This is the lowest-noise active hold that has already kept `CONNECT: OK` alive.
The broad scenario streams `E000[0x008F]=0x1800` and `E000[0x0093]=0xFFFF` every cycle. This is noisier, but may open more local-control/status gates.
The gated scenario first seeds candidate secondary-table feature bits with command 6:
```text
06 00 15 80 00 C9 ; E400[0x0015] OTHERS/COPY visibility candidate
06 01 0F 18 00 4A ; E400[0x008F] shutter/OTHERS bits 11+12
06 01 13 FF FF 4E ; E400[0x0093] broad local-report/status gate candidate
```
Then it streams `E000[0x008F]=0x1800` and `E000[0x0093]=0x90FF`. This is the better next watch if quiet/broad E000-only refreshes do not produce local-control TX.
After a run, summarize unexpected device frames with:
```powershell
.\.venv\Scripts\python.exe scripts\serial_scenario_unexpected.py captures\active-control-report-watch-quiet.txt --show-all
.\.venv\Scripts\python.exe scripts\serial_scenario_unexpected.py captures\active-control-report-watch-broad.txt --show-all
.\.venv\Scripts\python.exe scripts\serial_scenario_unexpected.py captures\active-control-report-watch-gated.txt --show-all
```
Expected refresh responses are ignored by default: heartbeat, table readbacks, and `02 00 02 00 00 5A`. Any remaining checksum-valid frame is a candidate local-control report. This is where physical button/dial reports should appear if the RCP only talks while the CCU keeps the selector tables active.
The unexpected-frame summarizer also labels known autonomous button frames so they are not mistaken for newly unlocked controls:
```text
00 00 15 80 00 CF ; known CALL active report
00 00 15 00 00 4F ; known CALL inactive report
00 00 07 80 00 DD ; known CAM POWER report
```
First quiet/broad watch captures on 2026-05-26 showed no unexpected checksum-valid frames in the observed window:
```text
active-control-report-watch-quiet: 114 detected frames, all expected refresh/heartbeat/readback
active-control-report-watch-broad: 133 detected frames, all expected refresh/heartbeat/readback
```
Those runs stopped mid-scenario, so this is not a full negative proof. The practical interpretation is narrower: E000 active-state refresh alone did not make the pressed controls emit visible TX in the watched window. The gated command-6 version is the next ROM-supported test.
The first gated watch capture produced a new periodic active-state response:
```text
02 00 04 00 00 5C ; gated 0x0004 transition candidate, seen twice
01 00 04 00 00 5F ; gated 0x0004 active response candidate, seen 328 times
```
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` blinked CAM POWER in isolation.
- `0x0015 = 0x8000/0x0000` blinked CALL and red tally in isolation.
- Fresh-boot isolation maps `0x0013` to SLAVE, `0x0016` to green tally, and `0x0017` to BARS for the `0x8000/0x0000` value pair.
- Fresh-boot isolation maps `0x0092` to iris AUTO/OFF behavior, and maps both `0x00B9` and `0x0110` to KNEE-related behavior.
- A ROM trace now explains why the KNEE tests looked non-level-held. `loc_1795` is reached from the panel input lane (`F104 -> F692 -> F6F0.1`) and reads `E000[0x00B9]` plus `E000[0x0110]`.
- The live KNEE value/report gate is `0x00B9.13`, not the earlier bench-only `0x00B9.15` guess.
- `0x0110.15` forces a timed KNEE page/display override (`F732=0x1C03`, `FB02=0x14`), which matches the observed "lights, then clears" behavior.
- On that KNEE LCD page, `0x0110.15` selects `DL`, `0x00B9.15` selects `PRESET`, and both clear selects `AUTO`.
- When `0x00B9.13` is set and `0x0110.15` is clear, the ROM reports/updates selector `0x00BC` from the `F692 - F6B2` panel-input delta. See `docs/pt2-knee-rom-trace.md`.
- The first KNEE ROM probe produced a new bench LCD state with `DTL` on the left and `KNEE` on the right, matching the ROM page-0x1C DETAIL/KNEE neighborhood.
- A follow-up isolation lit the KNEE AUTO lamp in later KNEE windows but did not change the LCD. Current model: KNEE AUTO lamp/status is mostly selector driven, while the DETAIL/KNEE LCD page needs an additional local menu/display condition.
## What Is Still Unknown ## What Is Still Unknown
- The official PT2 names for commands and selectors. - The official PT2 names for commands and selectors.
@@ -612,7 +716,7 @@ This fits the real panel behavior:
5. Dump selector table state before and after CONNECT OK. 5. Dump selector table state before and after CONNECT OK.
6. Seed selectors `0x003`, `0x040`, and `0x0F6` after selector-zero OK and watch lamps/readouts. 6. Seed selectors `0x003`, `0x040`, and `0x0F6` after selector-zero OK and watch lamps/readouts.
7. Mine selector dispatch handlers for known UI text terms: `IRIS`, `GAIN`, `SHUTTER`, `BARS`, `BLACK`, `CALL`, `AUTO`, `DIAG`. 7. Mine selector dispatch handlers for known UI text terms: `IRIS`, `GAIN`, `SHUTTER`, `BARS`, `BLACK`, `CALL`, `AUTO`, `DIAG`.
8. Build a fake-CCU streamer that repeatedly writes a small selector set and logs which RCP reports appear. 8. Run the active-control watch scenarios and map any unexpected frames back to physical controls.
## Source Files And Reports ## Source Files And Reports

View File

@@ -0,0 +1,201 @@
# PT2 Shutter Display Trace
This note collects the current ROM evidence for the shutter seven-segment display and related selector traffic.
## Confirmed Bench Mapping
The real panel responds to primary selector `0x008F`:
| Command 0 write | Meaning candidate | Observed panel result |
| --- | --- | --- |
| `00 01 0F 08 00 5C` | `E000[0x008F].11` | SHUTTER shows observed `EUS`, likely manual `EVS`; iris AUTO lamp on |
| `00 01 0F 10 00 44` | `E000[0x008F].12` | SHUTTER shows literal `OFF`; iris AUTO lamp on |
| `00 01 0F 18 00 4C` | bits 11 and 12 | likely `EVS` wins over `OFF`; iris AUTO lamp on |
| `00 01 0F 00 00 54` | live default/clear | in the short clear-control run, SHUTTER swapped to `OFF`, then back to `EVS` when bit 11 was restored |
Manual correlation:
- The RCP-TX7 manual has `OTHERS (1/6: SHUTTER)` with an `EVS` button.
- The RCP-TX7 menu table lists `EVS/ECS` under OTHERS for DXC-D30/D30P.
- A later CCU/RCP manual says the shutter display shows `EVS` when EVS is on and `OFF` when the shutter switch is off.
So `0x008F.11` is currently best labeled `shutter_evs_display_or_mode`. `0x008F.12` and `0x008F=0` both have `OFF` display evidence, so treat `OFF` as the live default/fallback shutter display unless a later bit-isolation run splits forced OFF from default OFF.
## Selector 0x008F ROM Path
Primary table address:
```text
selector 0x008F -> E000 + 2 * 0x008F = H'E11E
```
The OTHERS/SHUTTER menu handler is `H'6EE4`.
Important instructions:
```text
6F6E: BTST.W #11, @H'E11E
6F74: BSET.B #6, R0
6F76: BTST.W #12, @H'E11E
6F7C: BSET.B #4, R0
6F7E: MOV:G.B R0, @H'F711
```
This is the direct consumer seen so far. The current decompile does not show another static read of `H'E11E` outside this handler.
`H'6EE4` also programs local descriptor RAM before this:
```text
6EFD: F73E = H'088F
6F09: F74E = H'0800
6F0F: F742 = H'088F
6F1B: F752 = H'1000
```
Those descriptors match selector `0x008F` plus the two observed masks `0x0800` and `0x1000`, so the generic panel-output updater also appears to know about the same selector.
## Local Panel Trigger Path
`H'6EE4` can also generate a selector `0x008F` report/update from local OTHERS/SHUTTER controls:
```text
6F26: read F770 local action byte
6F2E: keep low two action bits
6F37: if action bit path and E400[0x008F].11 is enabled, set E800[0x008F] = 0x0800
6F45: if alternate action path and E400[0x008F].12 is enabled, set E800[0x008F] = 0x1000
6F53: R3 = 0x008F
6F64: call 3E54 report/target-frame builder
```
Practical meaning:
- The CCU can force the display state by writing `E000[0x008F]`.
- The RCP can also try to report local EVS/OFF changes through selector `0x008F`, but only when the secondary-table feature bits `E400[0x008F].11/.12` allow it.
## Adjacent Shutter Value Family
The periodic/control-change scanner at `H'15E0` processes changed input words collected by IRQ3 from the external panel chips. Around the shutter path it calls `H'19A2`, which compares a local delta against the current primary table value and, if changed, writes the `E800` current table and calls `H'3E54`.
Candidate selectors:
| Handler | Source RAM | Gate | Selector sent | Meaning candidate |
| --- | --- | --- | --- | --- |
| `H'17C9` | `F6AE/F6CE` | `E000[0x0093].12` | `0x00A3` | clear-scan/shutter value lane |
| `H'17FB` | `F6AC/F6CC` | `E000[0x0093].12` | `0x00A4` | clear-scan/shutter value lane |
| `H'182D` | `F6AA/F6CA` | `E000[0x0093].5`, `F717.2` clear | `0x00A5` | shutter value lane |
| `H'182D` | `F6AA/F6CA` | `F717.2` set | `0x00D8` | alternate/DXC-637 shutter lane |
| `H'1891` | `F6A8/F6C8` | `E000[0x0093].5`, `F717.2` clear | `0x0080` | shutter value lane |
| `H'1891` | `F6A8/F6C8` | `F717.2` set | `0x00D9` | alternate/DXC-637 shutter lane |
| `H'18E7` | `F6A6/F6C6` | `E000[0x0093].5`, `F717.2` clear | `0x00A6` | shutter value lane |
| `H'18E7` | `F6A6/F6C6` | `F717.2` set | `0x00DA` | alternate/DXC-637 shutter lane |
| `H'194A` | `F6A4/F6C4` | `F731 <= 3` | `0x0080` | shared value lane |
| `H'1979` | `F6A2/F6C2` plus `F68C` scale | `F731 <= 3` | `0x0081` | scaled analog value lane |
This cluster is a strong candidate for the numeric shutter speed / clear-scan frequency side of the display. It is not yet bench-confirmed.
ROM refinement:
- `F6AE/F6AC` are sampled from the external panel bus in the IRQ3 `A8` branch (`H'3CCB`), from `F00C/F00A`.
- `F6AA/F6A8/F6A6/F6A4/F6A2` are sampled from the IRQ3 `A9` branch (`H'3C49`), from `F00C/F00A/F008/F006/F004`.
- Those IRQ3 branches set dirty bits in `F6F1`, then the `H'15E0` scanner fans changes into the selector reports above.
- Several lanes can OR bit 14 into the report selector when `F791` and `F404` feature bits are live. So emitted report traffic may carry a tagged variant of the base selector even though the table readback probes below use the base selector.
- This makes the adjacent selector family more likely to be live local-panel state than a simple CCU-write display latch.
## Candidate Probe Frames
Readback:
```text
01 01 0F 00 00 55 ; read 0x008F
01 01 13 00 00 49 ; read 0x0093 gate/status
01 01 23 00 00 79 ; read 0x00A3
01 01 24 00 00 7E ; read 0x00A4
01 01 25 00 00 7F ; read 0x00A5
01 01 58 00 00 02 ; read 0x00D8
01 01 00 00 00 5A ; read 0x0080
01 01 59 00 00 03 ; read 0x00D9
01 01 26 00 00 7C ; read 0x00A6
01 01 5A 00 00 00 ; read 0x00DA
01 01 01 00 00 5B ; read 0x0081
```
Potential display probes after `CONNECT: OK`:
```text
00 01 0F 00 00 54 ; clear selector 0x008F
00 01 13 80 00 C8 ; set 0x0093 high bit candidate
00 01 13 FF FF 48 ; enable all 0x0093 gates candidate
```
Use the value-lane selectors cautiously. They may represent shutter/clear-scan numeric values, but they are also part of the local control-report path, so bench probing should change one selector at a time and record LCD, shutter display, iris AUTO, and emitted report frames.
Important methodology caveat:
- `CONNECT:NOT ACT` globally clears volatile panel presentation. A blank LCD/segment result after a long wait is not evidence that a tested selector cleared the panel.
- For selector-display tests, record the visible state inside the short post-write window, before the session can fall back to `NOT ACT`.
- Use the timeout-control scenario below to measure the current bench's natural EVS-to-NOT-ACT cleanup time. Treat results after that point as timeout-contaminated.
- Re-seed `CONNECT: OK` immediately before gate writes when a prior readback sweep may have consumed enough time for the visible state to expire.
## Adjacent Selector Bench Scenarios
These JSON scenarios are set up for the current bench runner and default to `38400 8E1`:
```text
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-adjacent-readback.json --parity E --log captures\shutter-adjacent-readback.txt --result-json captures\shutter-adjacent-readback-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-008f-evs-timeout-control.json --parity E --log captures\shutter-008f-evs-timeout-control.txt --result-json captures\shutter-008f-evs-timeout-control-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-008f-evs-clear-control.json --parity E --log captures\shutter-008f-evs-clear-control.txt --result-json captures\shutter-008f-evs-clear-control-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-gate-8000.json --parity E --log captures\shutter-0093-gate-8000.txt --result-json captures\shutter-0093-gate-8000-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-gate-ffff.json --parity E --log captures\shutter-0093-gate-ffff.txt --result-json captures\shutter-0093-gate-ffff-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-bit-isolation.json --parity E --log captures\shutter-0093-bit-isolation.txt --result-json captures\shutter-0093-bit-isolation-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-auto-candidates.json --parity E --log captures\shutter-0093-blackflare-auto-candidates.txt --result-json captures\shutter-0093-blackflare-auto-candidates-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-slow-marked.json --parity E --log captures\shutter-0093-blackflare-slow-marked.txt --result-json captures\shutter-0093-blackflare-slow-marked-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-field-groups.json --parity E --log captures\shutter-0093-blackflare-field-groups.txt --result-json captures\shutter-0093-blackflare-field-groups-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-field-confirm.json --parity E --log captures\shutter-0093-blackflare-field-confirm.txt --result-json captures\shutter-0093-blackflare-field-confirm-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-field-stream-confirm.json --parity E --log captures\shutter-0093-blackflare-field-stream-confirm.txt --result-json captures\shutter-0093-blackflare-field-stream-confirm-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-confirm-f020.json --parity E --log captures\shutter-0093-blackflare-confirm-f020.txt --result-json captures\shutter-0093-blackflare-confirm-f020-result.json
-Manual-auto-manual
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-confirm-ff20.json --parity E --log captures\shutter-0093-blackflare-confirm-ff20.txt --result-json captures\shutter-0093-blackflare-confirm-ff20-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-confirm-9f20.json --parity E --log captures\shutter-0093-blackflare-confirm-9f20.txt --result-json captures\shutter-0093-blackflare-confirm-9f20-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-confirm-90ff.json --parity E --log captures\shutter-0093-blackflare-confirm-90ff.txt --result-json captures\shutter-0093-blackflare-confirm-90ff-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-confirm-9fff.json --parity E --log captures\shutter-0093-blackflare-confirm-9fff.txt --result-json captures\shutter-0093-blackflare-confirm-9fff-result.json
.\.venv\Scripts\python.exe scripts\serial_scenario.py scenarios\shutter-0093-blackflare-lowbyte-groups.json --parity E --log captures\shutter-0093-blackflare-lowbyte-groups.txt --result-json captures\shutter-0093-blackflare-lowbyte-groups-result.json
```
Run order:
1. `shutter-adjacent-readback.json`: read-only baseline for the adjacent shutter cluster after the selector-zero `CONNECT: OK` seed.
2. `shutter-008f-evs-timeout-control.json`: measures how long EVS survives before `CONNECT:NOT ACT` clears it with no explicit clear command.
3. `shutter-008f-evs-clear-control.json`: checks whether the EVS/OFF display selector can be cleared live inside the safe pre-timeout window.
4. `shutter-0093-gate-8000.json`: tests the ROM-observed `0x0093` high-bit gate without enabling every unknown bit.
5. `shutter-0093-gate-ffff.json`: broader gate test if the targeted high-bit run is uneventful.
6. `shutter-0093-bit-isolation.json`: isolates the `0x0093` bits after bench evidence showed this selector also controls white-balance and black/flare lamps.
7. `shutter-0093-blackflare-auto-candidates.json`: uses the known `0x9020` black/flare-manual context and adds each remaining bit to hunt for the `0xFFFF` black/flare-AUTO effect.
8. `shutter-0093-blackflare-slow-marked.json`: repeats the hunt without clear/OK resets between candidates, so white-balance should flicker less and black/flare AUTO transitions can be matched to candidate holds.
9. `shutter-0093-blackflare-field-groups.json`: tests multi-bit field groups after the slow-marked run suggested black/flare AUTO is not one single extra bit over `0x9020`.
10. `shutter-0093-blackflare-field-confirm.json`: shorter, longer-hold confirmation of the broad field groups after the first field-groups run produced three MANUAL->AUTO->MANUAL swaps.
11. `shutter-0093-blackflare-field-stream-confirm.json`: repeats each candidate every 0.60 s after the longer-hold confirmation fell into `CONNECT:NOT ACT`, testing the CCU-refresh model directly.
12. `shutter-0093-blackflare-confirm-*.json`: one-candidate streamed confirmations. Each run includes a known `0xFFFF` AUTO positive control, then brackets one candidate with `0x9020` manual context. After the positive-control section, the expected candidate pattern is MANUAL -> AUTO -> MANUAL -> AUTO -> MANUAL only if that candidate drives black/flare AUTO.
13. `shutter-0093-blackflare-lowbyte-groups.json`: keeps the high byte fixed at `0x90` and varies only the low byte, after `0x90FF` and `0x9FFF` both toggled black/flare AUTO.
## Bench Observations 2026-05-26
Observed visible effects from the first adjacent-selector run set:
| Scenario | Serial evidence | Observed panel result | Current interpretation |
| --- | --- | --- | --- |
| `shutter-adjacent-readback` | all read selectors returned value `0x0000` | no specific visible note | baseline cluster was clear |
| `shutter-0093-gate-8000` | `E000[0x0093]` read back as `0x8000` | white-balance PRESET lamp on, black/flare MANUAL lamp on | `0x0093.15` is a live panel-status/lamp bit, not just a shutter gate |
| `shutter-0093-gate-ffff` | `E000[0x0093]` read back as `0xFFFF` | white-balance PRESET lamp on, black/flare AUTO lamp on | another `0x0093` bit overrides/selects black/flare AUTO when all bits are set |
| `shutter-0093-bit-isolation` | stepped through `0x1000`, `0x0020`, `0x1020`, `0x8000`, `0x8020`, `0x9000`, `0x9020` | white-balance lamps swapped between MANUAL and PRESET; black/flare stayed MANUAL | bit 15 remains the prime white-balance PRESET candidate; black/flare AUTO is likely outside bits 15/12/5 |
| `shutter-0093-blackflare-auto-candidates` | stepped through `0x9020`, `0xFFFF`, then `0x9020` plus each remaining bit | black/flare swapped AUTO/MANUAL more slowly than white-balance MANUAL/PRESET | the clear/OK reset before each candidate likely caused extra white-balance flicker; use the slow-marked follow-up to map black/flare transitions to exact bits |
| `shutter-0093-blackflare-slow-marked` | held `0x9020`, `0xFFFF`, then alternated `0x9020` with each candidate | white-balance stayed stable, black/flare swapped twice with large pauses; panel stayed `CONNECT: OK` throughout | likely only the manual-reference to `0xFFFF` and `0xFFFF` back to `0x9020` changed black/flare, so AUTO is probably a multi-bit field rather than one added bit |
| `shutter-0093-blackflare-field-groups` | held broad grouped values such as `0xF020`, `0xFF20`, `0x9F20`, `0x90FF`, `0x9FFF` | black/flare made three MANUAL->AUTO->MANUAL swaps | broad field combinations can produce black/flare AUTO; use the shorter confirmation run to identify which grouped windows caused the swaps |
| `shutter-0093-blackflare-field-confirm` | held `0xFFFF` for 2.8 s, then candidate groups | one MANUAL->AUTO transition at the start, then `CONNECT:NOT ACT`; PRESET white-balance lamp briefly flashed a few times while inactive | a silent 2.8 s hold is too long; traffic must be refreshed, and some lamp latch/update paths can still flash during inactive display cleanup |
| `shutter-0093-blackflare-field-stream-confirm` | streamed every candidate at 0.60 s and saw 148 `02 00 02 00 00 5A` OK-path responses with no resync errors | manual/auto/manual groups were visible, then `CONNECT:NOT ACT` after the stream ended | the stream itself kept OK alive; the final inactive state is likely just the refresh stopping. Candidate isolation needs streamed, one-candidate tests |
| `shutter-0093-blackflare-confirm-f020`, `ff20`, `9f20` | each completed cleanly with 137 OK-path responses and no resync errors | MANUAL->AUTO->MANUAL only | only the built-in `0xFFFF` positive control produced AUTO; these candidates did not drive black/flare AUTO by themselves |
| `shutter-0093-blackflare-confirm-90ff`, `9fff` | each completed cleanly with 137 OK-path responses and no resync errors | black/flare went back and forth a couple of times | `0x90FF` is sufficient to drive the AUTO effect, so the black/flare field is likely in the low byte of `0x0093`; `0x9FFF` is a superset rather than a separate high-byte requirement |
| `shutter-008f-evs-clear-control` | `0x008F` writes acknowledged as `0x0800`, `0x0000`, `0x0800` | SHUTTER swapped between EVS and OFF while iris AUTO lamp stayed on | `0x008F` is a packed shutter/display status word; clearing it does not simply mean "blank" |
| `shutter-008f-evs-timeout-control` | only `0x008F=0x0800` was sent after OK seed | EVS/iris AUTO, then `CONNECT:NOT ACT` | later blanking is timeout cleanup, not selector-clear evidence |
This changes the local naming: the "adjacent shutter" group should be treated as a broader camera-status and panel-output word cluster. `0x008F` currently covers shutter EVS/OFF plus iris AUTO side effects; `0x0093` covers at least white-balance manual/preset and black/flare manual/auto side effects, and still gates some ROM-observed shutter/clear-scan report lanes. Current black/flare evidence points to `0x0093` high byte `0x90` as enough context, with the low byte selecting the black/flare MANUAL/AUTO state.

View File

@@ -148,6 +148,11 @@ def label_frame(frame: bytes) -> str:
bytes.fromhex("0780C040A0FD"): "visible_40A0_family_C0", bytes.fromhex("0780C040A0FD"): "visible_40A0_family_C0",
bytes.fromhex("07804020902D"): "visible_retry_0040_2090_candidate", bytes.fromhex("07804020902D"): "visible_retry_0040_2090_candidate",
bytes.fromhex("0780C060205D"): "visible_C0_6020_family_candidate", bytes.fromhex("0780C060205D"): "visible_C0_6020_family_candidate",
bytes.fromhex("0000158000CF"): "known_call_button_active_report",
bytes.fromhex("00001500004F"): "known_call_button_inactive_report",
bytes.fromhex("0000078000DD"): "known_cam_power_button_report",
bytes.fromhex("01000400005F"): "gated_active_0004_response_candidate",
bytes.fromhex("02000400005C"): "gated_active_0004_transition_candidate",
} }
label = labels.get(frame, "") label = labels.get(frame, "")
if label: if label:

View 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",
]

View File

@@ -230,9 +230,13 @@ def _step_table_sweep(ctx: ScenarioContext, spec: dict[str, Any]) -> None:
selectors = _selector_list(spec) selectors = _selector_list(spec)
gap = float(spec.get("gap", 0.080)) gap = float(spec.get("gap", 0.080))
ack = _ack_config(spec.get("ack_on", {})) ack = _ack_config(spec.get("ack_on", {}))
ack_note = (
"ack=disabled"
if not ack["enabled"]
else f"ack_targets={len(ack['targets'])} ack_frame={format_frame(ack['frame'])}"
)
ctx.logger.event( ctx.logger.event(
f"TABLE_SWEEP selectors={len(selectors)} gap={gap:.3f}s " f"TABLE_SWEEP selectors={len(selectors)} gap={gap:.3f}s {ack_note}"
f"ack_targets={len(ack['targets'])} ack_frame={format_frame(ack['frame'])}"
) )
for selector in selectors: for selector in selectors:
if ctx.abort_requested: if ctx.abort_requested:
@@ -246,7 +250,10 @@ def _step_table_sweep(ctx: ScenarioContext, spec: dict[str, Any]) -> None:
def _ack_config(raw: Any) -> dict[str, Any]: def _ack_config(raw: Any) -> dict[str, Any]:
spec = raw if isinstance(raw, dict) else {} spec = raw if isinstance(raw, dict) else {}
enabled = bool(spec.get("enabled", True))
targets = _parse_frame_list(spec.get("frames", spec.get("frame", DEFAULT_ACK_TARGET))) targets = _parse_frame_list(spec.get("frames", spec.get("frame", DEFAULT_ACK_TARGET)))
if not enabled:
targets = set()
return { return {
"targets": set(targets), "targets": set(targets),
"frame": _parse_optional_frame(spec.get("ack_frame"), DEFAULT_ACK_FRAME), "frame": _parse_optional_frame(spec.get("ack_frame"), DEFAULT_ACK_FRAME),
@@ -254,7 +261,7 @@ def _ack_config(raw: Any) -> dict[str, Any]:
"poll_interval": float(spec.get("poll_interval", 0.005)), "poll_interval": float(spec.get("poll_interval", 0.005)),
"post_read": float(spec.get("post_ack_read", 0.250)), "post_read": float(spec.get("post_ack_read", 0.250)),
"once_per_selector": bool(spec.get("once_per_selector", True)), "once_per_selector": bool(spec.get("once_per_selector", True)),
"enabled": bool(spec.get("enabled", True)), "enabled": enabled,
"max_acks": _optional_int(spec.get("max_acks")), "max_acks": _optional_int(spec.get("max_acks")),
"max_target_hits": _optional_int(spec.get("max_target_hits")), "max_target_hits": _optional_int(spec.get("max_target_hits")),
"abort_on_limit": bool(spec.get("abort_on_limit", True)), "abort_on_limit": bool(spec.get("abort_on_limit", True)),
@@ -452,23 +459,52 @@ def _print_dry_run(args: argparse.Namespace, scenario: dict[str, Any], log_path:
for index, step in enumerate(_scenario_steps(scenario), start=1): for index, step in enumerate(_scenario_steps(scenario), start=1):
action, spec = _normalize_step(step) action, spec = _normalize_step(step)
print(f"step[{index}]={action}", file=stdout) print(f"step[{index}]={action}", file=stdout)
if action == "send": _print_step_dry_run(action, spec, stdout)
frame = _parse_required_frame(spec.get("frame"))
print(f" frame={format_frame(frame)} checksum_ok={int(frame_checksum_ok(frame))}", file=stdout)
elif action == "table_sweep": def _print_step_dry_run(action: str, spec: dict[str, Any], stdout: TextIO, *, indent: str = " ") -> None:
selectors = _selector_list(spec) if action == "send":
ack = _ack_config(spec.get("ack_on", {})) frame = _parse_required_frame(spec.get("frame"))
if selectors: print(f"{indent}frame={format_frame(frame)} checksum_ok={int(frame_checksum_ok(frame))}", file=stdout)
first = selectors[0] if float(spec.get("listen", 0.0)) > 0:
last = selectors[-1] print(f"{indent}listen={float(spec.get('listen', 0.0)):.3f}s", file=stdout)
print(f" selectors={len(selectors)} first=0x{first:03X} last=0x{last:03X}", file=stdout) elif action in {"drain", "listen", "wait"}:
else: print(f"{indent}seconds={float(spec.get('seconds', spec.get('value', 0.0))):.3f}", file=stdout)
print(" selectors=0", file=stdout) elif action == "wait_ready":
print(f" gap={float(spec.get('gap', 0.080)):.3f}", file=stdout) print(
f"{indent}heartbeats={int(spec.get('heartbeats', 2))} "
f"timeout={float(spec.get('timeout', 10.0)):.3f}s "
f"require={int(bool(spec.get('require', False)))}",
file=stdout,
)
elif action == "table_sweep":
selectors = _selector_list(spec)
ack = _ack_config(spec.get("ack_on", {}))
if selectors:
first = selectors[0]
last = selectors[-1]
print(f"{indent}selectors={len(selectors)} first=0x{first:03X} last=0x{last:03X}", file=stdout)
else:
print(f"{indent}selectors=0", file=stdout)
print(f"{indent}gap={float(spec.get('gap', 0.080)):.3f}", file=stdout)
if not ack["enabled"]:
print(f"{indent}ack=disabled", file=stdout)
else:
for target in sorted(ack["targets"]): for target in sorted(ack["targets"]):
print(f" ack_target={format_frame(target)}", file=stdout) print(f"{indent}ack_target={format_frame(target)}", file=stdout)
print(f" ack_frame={format_frame(ack['frame'])}", file=stdout) print(f"{indent}ack_frame={format_frame(ack['frame'])}", file=stdout)
print(f" max_acks={ack['max_acks']} max_target_hits={ack['max_target_hits']}", file=stdout) print(f"{indent}max_acks={ack['max_acks']} max_target_hits={ack['max_target_hits']}", file=stdout)
elif action == "repeat":
count = max(0, int(spec.get("count", 1)))
steps = spec.get("steps", [])
step_count = len(steps) if isinstance(steps, list) else 0
print(f"{indent}count={count} steps={step_count}", file=stdout)
if not isinstance(steps, list):
return
for child_index, child in enumerate(steps, start=1):
child_action, child_spec = _normalize_step(child)
print(f"{indent}child[{child_index}]={child_action}", file=stdout)
_print_step_dry_run(child_action, child_spec, stdout, indent=indent + " ")
def _emit_summary(ctx: ScenarioContext, logger: BenchLogger) -> None: def _emit_summary(ctx: ScenarioContext, logger: BenchLogger) -> None:

View File

@@ -0,0 +1,136 @@
from __future__ import annotations
import argparse
import re
import sys
from collections import Counter
from dataclasses import dataclass
from pathlib import Path
from typing import Iterable, TextIO
DETECT_RE = re.compile(
r"^(?P<time>\d\d:\d\d:\d\d\.\d{3})\s+DETECT\s+"
r"(?:(?P<label>\S+)\s+)?(?P<frame>(?:[0-9A-Fa-f]{2}\s*){6})\s*$"
)
DEFAULT_IGNORED_LABELS = {
"heartbeat",
"connect_ok_path_response_candidate",
"connect_c0_path_response_candidate",
"table_readback_candidate",
"gated_active_0004_response_candidate",
"gated_active_0004_transition_candidate",
}
KNOWN_FRAME_LABELS = {
"00 00 15 80 00 CF": "known_call_button_active_report",
"00 00 15 00 00 4F": "known_call_button_inactive_report",
"00 00 07 80 00 DD": "known_cam_power_button_report",
"01 00 04 00 00 5F": "gated_active_0004_response_candidate",
"02 00 04 00 00 5C": "gated_active_0004_transition_candidate",
}
@dataclass(frozen=True)
class DetectedFrame:
timestamp: str
label: str
frame: str
line_number: int
def build_arg_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="Show unexpected DETECT frames from a serial_scenario capture log."
)
parser.add_argument("log", type=Path, help="serial_scenario capture log")
parser.add_argument(
"--include-refresh",
action="store_true",
help="include heartbeat, table-readback, and CONNECT OK refresh frames",
)
parser.add_argument(
"--show-all",
action="store_true",
help="print every matching DETECT frame after the summary",
)
return parser
def main(argv: list[str] | None = None, *, stdout: TextIO = sys.stdout) -> int:
args = build_arg_parser().parse_args(argv)
text = args.log.read_text(encoding="utf-8")
frames = parse_detected_frames(text.splitlines())
interesting = frames if args.include_refresh else filter_expected_refresh(frames)
print(format_report(frames, interesting, include_refresh=args.include_refresh, show_all=args.show_all), file=stdout)
return 0
def parse_detected_frames(lines: Iterable[str]) -> list[DetectedFrame]:
frames: list[DetectedFrame] = []
for line_number, line in enumerate(lines, start=1):
match = DETECT_RE.match(line.strip())
if not match:
continue
frame = " ".join(match.group("frame").upper().split())
label = KNOWN_FRAME_LABELS.get(frame, match.group("label") or "checksum_ok_unlabeled")
frames.append(
DetectedFrame(
timestamp=match.group("time"),
label=label,
frame=frame,
line_number=line_number,
)
)
return frames
def filter_expected_refresh(frames: Iterable[DetectedFrame]) -> list[DetectedFrame]:
return [frame for frame in frames if frame.label not in DEFAULT_IGNORED_LABELS]
def format_report(
frames: list[DetectedFrame],
interesting: list[DetectedFrame],
*,
include_refresh: bool,
show_all: bool,
) -> str:
lines = [
"Serial scenario unexpected-frame summary",
f"detected_frames={len(frames)} mode={'all' if include_refresh else 'unexpected-only'}",
]
label_counts = Counter(frame.label for frame in frames)
if label_counts:
lines.append("labels:")
for label, count in sorted(label_counts.items()):
lines.append(f" {label}: {count}")
ignored = len(frames) - len(interesting)
if not include_refresh:
lines.append(f"ignored_expected_refresh={ignored}")
lines.append(f"interesting_frames={len(interesting)}")
frame_counts = Counter((frame.frame, frame.label) for frame in interesting)
if frame_counts:
lines.append("interesting frame counts:")
for (frame_text, label), count in sorted(frame_counts.items(), key=lambda item: (-item[1], item[0][0])):
first = next(frame for frame in interesting if frame.frame == frame_text and frame.label == label)
lines.append(f" {count:4d}x {frame_text} label={label} first={first.timestamp} line={first.line_number}")
else:
lines.append("no unexpected checksum-valid frames found")
if show_all and interesting:
lines.append("timeline:")
for frame in interesting:
lines.append(f" {frame.timestamp} line={frame.line_number} {frame.frame} label={frame.label}")
return "\n".join(lines)
__all__ = [
"DetectedFrame",
"filter_expected_refresh",
"format_report",
"main",
"parse_detected_frames",
]

View 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())

View File

@@ -0,0 +1,52 @@
{
"name": "active-control-report-watch-broad",
"notes": [
"Hold CONNECT OK while streaming broader camera/status words that may enable more local controls.",
"Press or turn one physical control at a time while this runs. Note the rough time and control name.",
"This is noisier than the quiet watch: each cycle writes 0x008F and 0x0093, so use the unexpected-frame summarizer after the run."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 80,
"steps": [
{
"action": "send",
"label": "broad_refresh_008f_1800",
"frame": "00 01 0F 18 00 4C",
"listen": 0.30
},
{
"action": "send",
"label": "broad_refresh_0093_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 0.30
}
]
},
{
"action": "listen",
"seconds": 1.50
}
]
}

View File

@@ -0,0 +1,70 @@
{
"name": "active-control-report-watch-gated",
"notes": [
"Hold CONNECT OK and seed candidate secondary-table E400 gates before watching for local-control TX reports.",
"This follows the ROM clue that some local report paths require E400 feature bits, not only E000 display/status words.",
"Press or turn one physical control at a time while this runs. Note the rough time and control name."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "send",
"label": "secondary_gate_0015_other_copy_candidate",
"frame": "06 00 15 80 00 C9",
"listen": 0.30
},
{
"action": "send",
"label": "secondary_gate_008f_shutter_bits_11_12",
"frame": "06 01 0F 18 00 4A",
"listen": 0.30
},
{
"action": "send",
"label": "secondary_gate_0093_all_bits",
"frame": "06 01 13 FF FF 4E",
"listen": 0.30
},
{
"action": "repeat",
"count": 80,
"steps": [
{
"action": "send",
"label": "gated_refresh_008f_1800",
"frame": "00 01 0F 18 00 4C",
"listen": 0.30
},
{
"action": "send",
"label": "gated_refresh_0093_90ff",
"frame": "00 01 13 90 FF 27",
"listen": 0.30
}
]
},
{
"action": "listen",
"seconds": 1.50
}
]
}

View File

@@ -0,0 +1,46 @@
{
"name": "active-control-report-watch-quiet",
"notes": [
"Hold the panel in CONNECT OK with the least noisy proven refresh stream, then watch for local-control TX reports.",
"Press or turn one physical control at a time while this runs. Note the rough time and control name.",
"Expected refresh traffic is table readback for 0x0093 plus 02 00 02 00 00 5A OK-path responses; anything else is interesting."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 100,
"steps": [
{
"action": "send",
"label": "quiet_active_refresh_0093_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "listen",
"seconds": 1.50
}
]
}

View File

@@ -0,0 +1,53 @@
{
"name": "copy-hold-006d-5x-006c",
"notes": [
"Recover to CONNECT OK, send 006D every 1 second for five starts/progress ticks, then send 006C.",
"Tests whether repeated 006D can hold the copy-in-progress state for a longer transfer before completion."
],
"steps": [
{
"action": "power_cycle",
"off_seconds": 1.5
},
{
"action": "wait_ready",
"timeout": 10.0,
"heartbeats": 2,
"require": true
},
{
"action": "drain",
"seconds": 0.25
},
{
"action": "send",
"label": "ok_baseline_1",
"frame": "04 00 00 80 00 DE",
"listen": 0.7
},
{
"action": "send",
"label": "ok_baseline_2",
"frame": "04 00 00 80 00 DE",
"listen": 1.0
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "copy_progress_006d",
"frame": "05 00 6D 00 00 32",
"listen": 1.0
}
]
},
{
"action": "send",
"label": "copy_complete_candidate_006c",
"frame": "05 00 6C 00 00 33",
"listen": 10.0
}
]
}

View File

@@ -0,0 +1,51 @@
{
"name": "copy-hold-006d-5x-no-complete",
"notes": [
"Recover to CONNECT OK, send 006D every 1 second five times, then do not send 006C.",
"Tests whether the timeout/fallback is measured from the last 006D progress tick."
],
"steps": [
{
"action": "power_cycle",
"off_seconds": 1.5
},
{
"action": "wait_ready",
"timeout": 10.0,
"heartbeats": 2,
"require": true
},
{
"action": "drain",
"seconds": 0.25
},
{
"action": "send",
"label": "ok_baseline_1",
"frame": "04 00 00 80 00 DE",
"listen": 0.7
},
{
"action": "send",
"label": "ok_baseline_2",
"frame": "04 00 00 80 00 DE",
"listen": 1.0
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "copy_progress_006d",
"frame": "05 00 6D 00 00 32",
"listen": 1.0
}
]
},
{
"action": "listen",
"seconds": 10.0
}
]
}

View File

@@ -0,0 +1,53 @@
{
"name": "copy-repeat-006d-2x-006c",
"notes": [
"Recover to CONNECT OK, send 006D twice one second apart, then send 006C.",
"Tests whether repeating the in-progress selector extends/resets the completion window or interferes with completion."
],
"steps": [
{
"action": "power_cycle",
"off_seconds": 1.5
},
{
"action": "wait_ready",
"timeout": 10.0,
"heartbeats": 2,
"require": true
},
{
"action": "drain",
"seconds": 0.25
},
{
"action": "send",
"label": "ok_baseline_1",
"frame": "04 00 00 80 00 DE",
"listen": 0.7
},
{
"action": "send",
"label": "ok_baseline_2",
"frame": "04 00 00 80 00 DE",
"listen": 1.0
},
{
"action": "send",
"label": "copy_start_006d_1",
"frame": "05 00 6D 00 00 32",
"listen": 1.0
},
{
"action": "send",
"label": "copy_start_006d_2",
"frame": "05 00 6D 00 00 32",
"listen": 1.0
},
{
"action": "send",
"label": "copy_complete_candidate_006c",
"frame": "05 00 6C 00 00 33",
"listen": 10.0
}
]
}

View File

@@ -0,0 +1,59 @@
{
"name": "copy-repeat-006d-3x-006c",
"notes": [
"Recover to CONNECT OK, send 006D three times one second apart, then send 006C.",
"Tests whether repeated in-progress selectors can keep the copy state alive longer than the single-start window."
],
"steps": [
{
"action": "power_cycle",
"off_seconds": 1.5
},
{
"action": "wait_ready",
"timeout": 10.0,
"heartbeats": 2,
"require": true
},
{
"action": "drain",
"seconds": 0.25
},
{
"action": "send",
"label": "ok_baseline_1",
"frame": "04 00 00 80 00 DE",
"listen": 0.7
},
{
"action": "send",
"label": "ok_baseline_2",
"frame": "04 00 00 80 00 DE",
"listen": 1.0
},
{
"action": "send",
"label": "copy_start_006d_1",
"frame": "05 00 6D 00 00 32",
"listen": 1.0
},
{
"action": "send",
"label": "copy_start_006d_2",
"frame": "05 00 6D 00 00 32",
"listen": 1.0
},
{
"action": "send",
"label": "copy_start_006d_3",
"frame": "05 00 6D 00 00 32",
"listen": 1.0
},
{
"action": "send",
"label": "copy_complete_candidate_006c",
"frame": "05 00 6C 00 00 33",
"listen": 10.0
}
]
}

View File

@@ -0,0 +1,47 @@
{
"name": "copy-step-006d-006c-1500ms",
"notes": [
"Recover to CONNECT OK, send 006D, then send 006C 1.5 seconds later.",
"Narrows the working copy-complete window between the known 1.0s success and 2.5s failure."
],
"steps": [
{
"action": "power_cycle",
"off_seconds": 1.5
},
{
"action": "wait_ready",
"timeout": 10.0,
"heartbeats": 2,
"require": true
},
{
"action": "drain",
"seconds": 0.25
},
{
"action": "send",
"label": "ok_baseline_1",
"frame": "04 00 00 80 00 DE",
"listen": 0.7
},
{
"action": "send",
"label": "ok_baseline_2",
"frame": "04 00 00 80 00 DE",
"listen": 1.0
},
{
"action": "send",
"label": "copy_start_006d",
"frame": "05 00 6D 00 00 32",
"listen": 1.5
},
{
"action": "send",
"label": "copy_complete_candidate_006c",
"frame": "05 00 6C 00 00 33",
"listen": 10.0
}
]
}

View File

@@ -0,0 +1,47 @@
{
"name": "copy-step-006d-006c-2000ms",
"notes": [
"Recover to CONNECT OK, send 006D, then send 006C 2.0 seconds later.",
"Narrows the copy-complete acceptance window before the known 2.5s failure."
],
"steps": [
{
"action": "power_cycle",
"off_seconds": 1.5
},
{
"action": "wait_ready",
"timeout": 10.0,
"heartbeats": 2,
"require": true
},
{
"action": "drain",
"seconds": 0.25
},
{
"action": "send",
"label": "ok_baseline_1",
"frame": "04 00 00 80 00 DE",
"listen": 0.7
},
{
"action": "send",
"label": "ok_baseline_2",
"frame": "04 00 00 80 00 DE",
"listen": 1.0
},
{
"action": "send",
"label": "copy_start_006d",
"frame": "05 00 6D 00 00 32",
"listen": 2.0
},
{
"action": "send",
"label": "copy_complete_candidate_006c",
"frame": "05 00 6C 00 00 33",
"listen": 10.0
}
]
}

View File

@@ -0,0 +1,100 @@
{
"name": "knee-detail-physical-button-watch",
"notes": [
"Create clean watch windows for the physical DETAIL and KNEE buttons near the LCD.",
"The ROM trace suggests these buttons may be the missing F104 panel-input transition into loc_1795.",
"Watch the console labels and LCD. During the labeled windows, press DETAIL, KNEE, then DETAIL/KNEE alternately."
],
"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": "ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "prepare_clear_0110",
"frame": "00 01 90 00 00 CB",
"listen": 0.30
},
{
"action": "send",
"label": "prepare_00b9_bit13_gate",
"frame": "00 01 39 20 00 42",
"listen": 0.80
},
{
"action": "listen",
"seconds": 5.0
},
{
"action": "send",
"label": "read_00bc_after_detail_press_window",
"frame": "01 01 3C 00 00 66",
"listen": 0.80
},
{
"action": "send",
"label": "refresh_00b9_bit13_gate_for_knee_press",
"frame": "00 01 39 20 00 42",
"listen": 0.50
},
{
"action": "listen",
"seconds": 5.0
},
{
"action": "send",
"label": "read_00bc_after_knee_press_window",
"frame": "01 01 3C 00 00 66",
"listen": 0.80
},
{
"action": "send",
"label": "prepare_00b9_a0_for_page_label_watch",
"frame": "00 01 39 A0 00 C2",
"listen": 0.80
},
{
"action": "listen",
"seconds": 6.0
},
{
"action": "send",
"label": "prepare_0110_dl_override_then_press_buttons",
"frame": "00 01 90 80 00 4B",
"listen": 0.80
},
{
"action": "listen",
"seconds": 6.0
},
{
"action": "send",
"label": "final_read_00bc",
"frame": "01 01 3C 00 00 66",
"listen": 0.80
}
]
}

View File

@@ -0,0 +1,206 @@
{
"name": "knee-rom-dtl-knee-isolation",
"notes": [
"Isolate which ROM-derived KNEE selector sequence creates the bench DTL/KNEE LCD state.",
"Record the exact case label visible in the console when DTL/KNEE appears or disappears.",
"Cases separate 0x00B9.13 gate, 0x00B9.15 label bit, and 0x0110.15 timed override."
],
"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": "case_a_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_a_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_a_clear_00b9",
"frame": "00 01 39 00 00 62",
"listen": 0.30
},
{
"action": "send",
"label": "case_a_clear_0110",
"frame": "00 01 90 00 00 CB",
"listen": 0.30
},
{
"action": "send",
"label": "case_a_set_00b9_bit13_only_watch_dtl_knee",
"frame": "00 01 39 20 00 42",
"listen": 3.00
},
{
"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": "case_b_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_b_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_b_clear_0110",
"frame": "00 01 90 00 00 CB",
"listen": 0.30
},
{
"action": "send",
"label": "case_b_set_00b9_bits15_and_13_watch_dtl_knee",
"frame": "00 01 39 A0 00 C2",
"listen": 3.00
},
{
"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": "case_c_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_c_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_c_clear_00b9",
"frame": "00 01 39 00 00 62",
"listen": 0.30
},
{
"action": "send",
"label": "case_c_set_0110_bit15_only_watch_dtl_knee",
"frame": "00 01 90 80 00 4B",
"listen": 3.00
},
{
"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": "case_d_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_d_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_d_set_00b9_bit13_then_0110_override_part1",
"frame": "00 01 39 20 00 42",
"listen": 0.80
},
{
"action": "send",
"label": "case_d_set_0110_bit15_after_00b9_bit13_watch_dtl_knee",
"frame": "00 01 90 80 00 4B",
"listen": 3.00
},
{
"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": "case_e_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_e_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_e_set_00b9_a0_then_0110_override_part1",
"frame": "00 01 39 A0 00 C2",
"listen": 0.80
},
{
"action": "send",
"label": "case_e_set_0110_bit15_after_00b9_a0_watch_dtl_knee",
"frame": "00 01 90 80 00 4B",
"listen": 3.00
}
]
}

View File

@@ -0,0 +1,132 @@
{
"name": "knee-rom-gate-and-value-probe",
"notes": [
"Probe the ROM-derived KNEE model from docs/pt2-knee-rom-trace.md.",
"The key correction is that 0x00B9.13 gates the live KNEE value/report branch, while 0x0110.15 forces the timed KNEE page.",
"Serial writes may only prepare the state. If the panel has a KNEE-related control, move it during the long gate windows and watch for selector 0x00BC reports or visible KNEE changes."
],
"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": "ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "clear_00b9",
"frame": "00 01 39 00 00 62",
"listen": 0.30
},
{
"action": "send",
"label": "clear_0110",
"frame": "00 01 90 00 00 CB",
"listen": 0.80
},
{
"action": "send",
"label": "read_00bc_baseline",
"frame": "01 01 3C 00 00 66",
"listen": 0.60
},
{
"action": "send",
"label": "set_00b9_bit13_gate_move_knee_control_if_possible",
"frame": "00 01 39 20 00 42",
"listen": 4.00
},
{
"action": "send",
"label": "read_00bc_after_gate_window",
"frame": "01 01 3C 00 00 66",
"listen": 0.80
},
{
"action": "send",
"label": "set_00b9_bits15_and_13_preset_label_plus_gate",
"frame": "00 01 39 A0 00 C2",
"listen": 1.50
},
{
"action": "send",
"label": "set_0110_bit15_dl_timed_page_override",
"frame": "00 01 90 80 00 4B",
"listen": 2.50
},
{
"action": "send",
"label": "clear_0110_return_to_value_path",
"frame": "00 01 90 00 00 CB",
"listen": 1.00
},
{
"action": "send",
"label": "read_00bc_after_override_clear",
"frame": "01 01 3C 00 00 66",
"listen": 0.80
},
{
"action": "repeat",
"count": 2,
"steps": [
{
"action": "send",
"label": "00bc_direct_low_probe",
"frame": "00 01 3C 00 00 67",
"listen": 0.35
},
{
"action": "send",
"label": "00bc_direct_mid_probe",
"frame": "00 01 3C 40 00 27",
"listen": 0.35
},
{
"action": "send",
"label": "00bc_direct_high_probe",
"frame": "00 01 3C 80 00 E7",
"listen": 0.35
},
{
"action": "send",
"label": "read_00bc_direct_probe",
"frame": "01 01 3C 00 00 66",
"listen": 0.50
}
]
},
{
"action": "send",
"label": "final_clear_00b9",
"frame": "00 01 39 00 00 62",
"listen": 0.50
},
{
"action": "send",
"label": "final_clear_0110",
"frame": "00 01 90 00 00 CB",
"listen": 1.50
}
]
}

View 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
}
]
}

View 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
}
]
}

View 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
}
]
}

View File

@@ -0,0 +1,206 @@
{
"name": "lamp-isolate-knee-bit-scan",
"notes": [
"Bit-scan the two fresh-boot KNEE AUTO candidates, 0x00B9 and 0x0110.",
"Each selector gets its own fresh CONNECT OK seed, then high-byte bits are tested one at a time with clears between writes.",
"Record whether KNEE AUTO, KNEE manual, or any neighboring paint/detail lamp changes during each label."
],
"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_for_00b9",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_00b9",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_00b9_bit15_watch",
"frame": "00 01 39 80 00 E2",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_00b9_clear_after_bit15",
"frame": "00 01 39 00 00 62",
"listen": 0.70
},
{
"action": "send",
"label": "candidate_00b9_bit14_watch",
"frame": "00 01 39 40 00 22",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_00b9_clear_after_bit14",
"frame": "00 01 39 00 00 62",
"listen": 0.70
},
{
"action": "send",
"label": "candidate_00b9_bit13_watch",
"frame": "00 01 39 20 00 42",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_00b9_clear_after_bit13",
"frame": "00 01 39 00 00 62",
"listen": 0.70
},
{
"action": "send",
"label": "candidate_00b9_bit12_watch",
"frame": "00 01 39 10 00 72",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_00b9_clear_after_bit12",
"frame": "00 01 39 00 00 62",
"listen": 0.70
},
{
"action": "send",
"label": "candidate_00b9_bit11_watch",
"frame": "00 01 39 08 00 6A",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_00b9_clear_after_bit11",
"frame": "00 01 39 00 00 62",
"listen": 0.70
},
{
"action": "send",
"label": "candidate_00b9_lowff_watch",
"frame": "00 01 39 00 FF 9D",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_00b9_clear_after_lowff",
"frame": "00 01 39 00 00 62",
"listen": 0.70
},
{
"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_for_0110",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_0110",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_0110_bit15_watch",
"frame": "00 01 90 80 00 4B",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_0110_clear_after_bit15",
"frame": "00 01 90 00 00 CB",
"listen": 0.70
},
{
"action": "send",
"label": "candidate_0110_bit14_watch",
"frame": "00 01 90 40 00 8B",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_0110_clear_after_bit14",
"frame": "00 01 90 00 00 CB",
"listen": 0.70
},
{
"action": "send",
"label": "candidate_0110_bit13_watch",
"frame": "00 01 90 20 00 EB",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_0110_clear_after_bit13",
"frame": "00 01 90 00 00 CB",
"listen": 0.70
},
{
"action": "send",
"label": "candidate_0110_bit12_watch",
"frame": "00 01 90 10 00 DB",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_0110_clear_after_bit12",
"frame": "00 01 90 00 00 CB",
"listen": 0.70
},
{
"action": "send",
"label": "candidate_0110_bit11_watch",
"frame": "00 01 90 08 00 C3",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_0110_clear_after_bit11",
"frame": "00 01 90 00 00 CB",
"listen": 0.70
},
{
"action": "send",
"label": "candidate_0110_lowff_watch",
"frame": "00 01 90 00 FF 34",
"listen": 1.30
},
{
"action": "send",
"label": "candidate_0110_clear_after_lowff",
"frame": "00 01 90 00 00 CB",
"listen": 0.70
}
]
}

View 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
}
]
}

View File

@@ -0,0 +1,260 @@
{
"name": "lamp-isolate-knee-tail-single-boot",
"notes": [
"Fresh-boot isolation for the late broad-status candidates after KNEE AUTO appeared toward the end of the previous run.",
"Selector 0x0092 is included as a guard before the stronger tail candidates 0x00A7, 0x00B7, 0x00B9, and 0x0110.",
"Each candidate tests high, clear, all bits, clear."
],
"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_for_0092",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_0092",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_0092_high_watch",
"frame": "00 01 12 80 00 C9",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_0092_clear_after_high",
"frame": "00 01 12 00 00 49",
"listen": 0.90
},
{
"action": "send",
"label": "candidate_0092_all_bits_watch",
"frame": "00 01 12 FF FF 49",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_0092_clear_after_all",
"frame": "00 01 12 00 00 49",
"listen": 0.90
},
{
"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_for_00a7",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_00a7",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_00a7_high_watch",
"frame": "00 01 27 80 00 FC",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_00a7_clear_after_high",
"frame": "00 01 27 00 00 7C",
"listen": 0.90
},
{
"action": "send",
"label": "candidate_00a7_all_bits_watch",
"frame": "00 01 27 FF FF 7C",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_00a7_clear_after_all",
"frame": "00 01 27 00 00 7C",
"listen": 0.90
},
{
"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_for_00b7",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_00b7",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_00b7_high_watch",
"frame": "00 01 37 80 00 EC",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_00b7_clear_after_high",
"frame": "00 01 37 00 00 6C",
"listen": 0.90
},
{
"action": "send",
"label": "candidate_00b7_all_bits_watch",
"frame": "00 01 37 FF FF 6C",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_00b7_clear_after_all",
"frame": "00 01 37 00 00 6C",
"listen": 0.90
},
{
"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_for_00b9",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_00b9",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_00b9_high_watch",
"frame": "00 01 39 80 00 E2",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_00b9_clear_after_high",
"frame": "00 01 39 00 00 62",
"listen": 0.90
},
{
"action": "send",
"label": "candidate_00b9_all_bits_watch",
"frame": "00 01 39 FF FF 62",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_00b9_clear_after_all",
"frame": "00 01 39 00 00 62",
"listen": 0.90
},
{
"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_for_0110",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_0110",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_0110_high_watch",
"frame": "00 01 90 80 00 4B",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_0110_clear_after_high",
"frame": "00 01 90 00 00 CB",
"listen": 0.90
},
{
"action": "send",
"label": "candidate_0110_all_bits_watch",
"frame": "00 01 90 FF FF CB",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_0110_clear_after_all",
"frame": "00 01 90 00 00 CB",
"listen": 0.90
}
]
}

View 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
}
]
}

View File

@@ -0,0 +1,238 @@
{
"name": "lamp-isolate-neighbor-single-boot",
"notes": [
"Fresh-boot isolation for the selector cluster that produced SLAVE, green tally, BARS, MASTER, and related lamps.",
"Each candidate starts from a fresh power cycle and CONNECT OK seed so latched lamps from the previous selector cannot contaminate the result.",
"Record the visible lamp during the high hold and whether the low write clears it."
],
"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_for_0012",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_0012",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_0012_high_watch",
"frame": "00 00 12 80 00 C8",
"listen": 2.00
},
{
"action": "send",
"label": "candidate_0012_low_clear_watch",
"frame": "00 00 12 00 00 48",
"listen": 1.20
},
{
"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_for_0013",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_0013",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_0013_high_watch",
"frame": "00 00 13 80 00 C9",
"listen": 2.00
},
{
"action": "send",
"label": "candidate_0013_low_clear_watch",
"frame": "00 00 13 00 00 49",
"listen": 1.20
},
{
"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_for_0016",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_0016",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_0016_high_watch",
"frame": "00 00 16 80 00 CC",
"listen": 2.00
},
{
"action": "send",
"label": "candidate_0016_low_clear_watch",
"frame": "00 00 16 00 00 4C",
"listen": 1.20
},
{
"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_for_0017",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_0017",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_0017_high_watch",
"frame": "00 00 17 80 00 CD",
"listen": 2.00
},
{
"action": "send",
"label": "candidate_0017_low_clear_watch",
"frame": "00 00 17 00 00 4D",
"listen": 1.20
},
{
"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_for_0018",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_0018",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_0018_high_watch",
"frame": "00 00 18 80 00 C2",
"listen": 2.00
},
{
"action": "send",
"label": "candidate_0018_low_clear_watch",
"frame": "00 00 18 00 00 42",
"listen": 1.20
},
{
"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_for_001a",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "selector_zero_ok_seed_2_for_001a",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "candidate_001a_high_watch",
"frame": "00 00 1A 80 00 C0",
"listen": 2.00
},
{
"action": "send",
"label": "candidate_001a_low_clear_watch",
"frame": "00 00 1A 00 00 40",
"listen": 1.20
}
]
}

View File

@@ -0,0 +1,110 @@
{
"name": "lamp-knee-context-hold",
"notes": [
"Test whether the known quiet active refresh context lets KNEE AUTO stay on.",
"The prior sustain test showed repeated 0x00B9.15 never lit KNEE AUTO, while repeated 0x0110.15 lit it then cleared around mid-window.",
"This pairs each KNEE candidate with the proven 0x0093=0x9020 active refresh stream."
],
"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": "case_00b9_context_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_00b9_context_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "repeat",
"count": 10,
"steps": [
{
"action": "send",
"label": "context_0093_9020_refresh_for_00b9",
"frame": "00 01 13 90 20 F8",
"listen": 0.25
},
{
"action": "send",
"label": "context_00b9_bit15_knee_test",
"frame": "00 01 39 80 00 E2",
"listen": 0.35
}
]
},
{
"action": "send",
"label": "clear_00b9_with_context_watch",
"frame": "00 01 39 00 00 62",
"listen": 1.00
},
{
"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": "case_0110_context_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_0110_context_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "repeat",
"count": 10,
"steps": [
{
"action": "send",
"label": "context_0093_9020_refresh_for_0110",
"frame": "00 01 13 90 20 F8",
"listen": 0.25
},
{
"action": "send",
"label": "context_0110_bit15_knee_test",
"frame": "00 01 90 80 00 4B",
"listen": 0.35
}
]
},
{
"action": "send",
"label": "clear_0110_with_context_watch",
"frame": "00 01 90 00 00 CB",
"listen": 1.00
}
]
}

View File

@@ -0,0 +1,116 @@
{
"name": "lamp-knee-edge-refresh",
"notes": [
"Test whether KNEE AUTO needs a low-to-high edge on 0x0110.15 rather than repeated high writes.",
"The context-hold test kept active serial responses alive, but KNEE AUTO still turned off mid-run.",
"This alternates clear/set for 0x0110.15, first by itself and then with 0x0093=0x9020 context refresh."
],
"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": "edge_only_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "edge_only_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "repeat",
"count": 10,
"steps": [
{
"action": "send",
"label": "edge_only_clear_0110",
"frame": "00 01 90 00 00 CB",
"listen": 0.18
},
{
"action": "send",
"label": "edge_only_set_0110_bit15_watch",
"frame": "00 01 90 80 00 4B",
"listen": 0.42
}
]
},
{
"action": "send",
"label": "edge_only_final_clear_0110",
"frame": "00 01 90 00 00 CB",
"listen": 1.00
},
{
"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": "edge_context_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "edge_context_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "repeat",
"count": 10,
"steps": [
{
"action": "send",
"label": "edge_context_0093_9020_refresh",
"frame": "00 01 13 90 20 F8",
"listen": 0.20
},
{
"action": "send",
"label": "edge_context_clear_0110",
"frame": "00 01 90 00 00 CB",
"listen": 0.16
},
{
"action": "send",
"label": "edge_context_set_0110_bit15_watch",
"frame": "00 01 90 80 00 4B",
"listen": 0.34
}
]
},
{
"action": "send",
"label": "edge_context_final_clear_0110",
"frame": "00 01 90 00 00 CB",
"listen": 1.00
}
]
}

View File

@@ -0,0 +1,110 @@
{
"name": "lamp-knee-or-precedence",
"notes": [
"Test whether KNEE AUTO is an OR of 0x00B9.15 and 0x0110.15, or whether latest-write/hidden precedence matters.",
"Case 1 sets 0x00B9.15, then 0x0110.15, then clears 0x00B9 while 0x0110 remains set.",
"Case 2 sets 0x0110.15, then 0x00B9.15, then clears 0x0110 while 0x00B9 remains set."
],
"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": "case1_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case1_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case1_set_00b9_bit15_watch_knee_auto",
"frame": "00 01 39 80 00 E2",
"listen": 1.50
},
{
"action": "send",
"label": "case1_set_0110_bit15_while_00b9_still_set",
"frame": "00 01 90 80 00 4B",
"listen": 1.50
},
{
"action": "send",
"label": "case1_clear_00b9_watch_if_knee_stays_on",
"frame": "00 01 39 00 00 62",
"listen": 1.50
},
{
"action": "send",
"label": "case1_clear_0110_watch_knee_off",
"frame": "00 01 90 00 00 CB",
"listen": 1.20
},
{
"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": "case2_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case2_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case2_set_0110_bit15_watch_knee_auto",
"frame": "00 01 90 80 00 4B",
"listen": 1.50
},
{
"action": "send",
"label": "case2_set_00b9_bit15_while_0110_still_set",
"frame": "00 01 39 80 00 E2",
"listen": 1.50
},
{
"action": "send",
"label": "case2_clear_0110_watch_if_knee_stays_on",
"frame": "00 01 90 00 00 CB",
"listen": 1.50
},
{
"action": "send",
"label": "case2_clear_00b9_watch_knee_off",
"frame": "00 01 39 00 00 62",
"listen": 1.20
}
]
}

View File

@@ -0,0 +1,98 @@
{
"name": "lamp-knee-sustain-compare",
"notes": [
"Compare how long KNEE AUTO stays lit from repeated 0x00B9.15 versus repeated 0x0110.15 refreshes.",
"This follows the precedence result where clearing 0x0110 turned KNEE AUTO off even after 0x00B9 had been set.",
"Record whether each repeated-refresh phase holds KNEE AUTO continuously or only flashes it."
],
"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": "case_00b9_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_00b9_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "refresh_00b9_bit15_hold_test",
"frame": "00 01 39 80 00 E2",
"listen": 0.55
}
]
},
{
"action": "send",
"label": "clear_00b9_watch_knee_off",
"frame": "00 01 39 00 00 62",
"listen": 1.50
},
{
"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": "case_0110_ok_seed_1",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "send",
"label": "case_0110_ok_seed_2",
"frame": "00 00 00 80 00 DA",
"listen": 0.60
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "refresh_0110_bit15_hold_test",
"frame": "00 01 90 80 00 4B",
"listen": 0.55
}
]
},
{
"action": "send",
"label": "clear_0110_watch_knee_off",
"frame": "00 01 90 00 00 CB",
"listen": 1.50
}
]
}

View 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
}
]
}

View File

@@ -0,0 +1,49 @@
{
"name": "others-copy-gate-probe",
"notes": [
"Recover toward CONNECT OK, seed the OTHERS root soft-key bits, then try to set the page-1 COPY TO SLAVES visibility gate.",
"Press the panel OTHER/COPY controls during the final listen window and record the LCD/lamp result.",
"The command-6 E400 write only works if the ROM is in a live continuation/report window.",
"ROM trace also shows a second local COPY-start gate at F791.7; if that is clear, the panel can divert to SET RCP / MASTER instead of COPY."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "others_root_e000_008f_bits11_12",
"frame": "00 01 0F 18 00 4C",
"listen": 0.15
},
{
"action": "wait_for",
"frame": "02 00 02 00 00 5A",
"timeout": 1.5,
"require": false
},
{
"action": "send",
"label": "others_copy_e400_0015_gate",
"frame": "06 00 15 00 01 48",
"listen": 8.0
}
]
}

View File

@@ -0,0 +1,35 @@
{
"name": "others-isolate-008f-bit11",
"notes": [
"Recover to CONNECT OK, then write only E000[0x008F].11.",
"Use this to isolate whether bit 11 alone changes the shutter display, iris AUTO lamp, or OTHERS soft-key state."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.20
},
{
"action": "send",
"label": "e000_008f_bit11_only",
"frame": "00 01 0F 08 00 5C",
"listen": 8.0
}
]
}

View File

@@ -0,0 +1,35 @@
{
"name": "others-isolate-008f-bit12",
"notes": [
"Recover to CONNECT OK, then write only E000[0x008F].12.",
"Use this to isolate whether bit 12 alone changes the shutter display, iris AUTO lamp, or OTHERS soft-key state."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.20
},
{
"action": "send",
"label": "e000_008f_bit12_only",
"frame": "00 01 0F 10 00 44",
"listen": 8.0
}
]
}

View File

@@ -0,0 +1,35 @@
{
"name": "others-isolate-008f-bits11-12",
"notes": [
"Recover to CONNECT OK, then write E000[0x008F].11 and .12 together.",
"This repeats the first half of others-copy-gate-probe without the E400[0x0015] write."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.20
},
{
"action": "send",
"label": "e000_008f_bits11_12",
"frame": "00 01 0F 18 00 4C",
"listen": 8.0
}
]
}

View File

@@ -0,0 +1,47 @@
{
"name": "others-isolate-008f-then-e400-clear",
"notes": [
"Recover to CONNECT OK, write E000[0x008F]=0x1800, then write E400[0x0015]=0x0000 in the live window.",
"This is the control case for others-copy-gate-probe: same root bits, but COPY visibility cleared instead of set."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.15
},
{
"action": "send",
"label": "e000_008f_bits11_12",
"frame": "00 01 0F 18 00 4C",
"listen": 0.15
},
{
"action": "wait_for",
"frame": "02 00 02 00 00 5A",
"timeout": 1.5,
"require": false
},
{
"action": "send",
"label": "e400_0015_clear",
"frame": "06 00 15 00 00 49",
"listen": 8.0
}
]
}

View File

@@ -0,0 +1,41 @@
{
"name": "others-isolate-e400-0015-high",
"notes": [
"Recover to CONNECT OK, wait for the live 02 report window, then write E400[0x0015]=0x8000.",
"This tests whether the high bit of the same secondary selector behaves differently from 0x0001."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.15
},
{
"action": "wait_for",
"frame": "02 00 02 00 00 5A",
"timeout": 1.5,
"require": false
},
{
"action": "send",
"label": "e400_0015_high_nonzero",
"frame": "06 00 15 80 00 C9",
"listen": 8.0
}
]
}

View File

@@ -0,0 +1,41 @@
{
"name": "others-isolate-e400-0015-low",
"notes": [
"Recover to CONNECT OK, wait for the live 02 report window, then write E400[0x0015]=0x0001.",
"This isolates the command-6 secondary-table write from the E000[0x008F] write."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.15
},
{
"action": "wait_for",
"frame": "02 00 02 00 00 5A",
"timeout": 1.5,
"require": false
},
{
"action": "send",
"label": "e400_0015_low_nonzero",
"frame": "06 00 15 00 01 48",
"listen": 8.0
}
]
}

View File

@@ -0,0 +1,48 @@
{
"name": "shutter-008f-evs-clear-control",
"notes": [
"Recover to CONNECT OK, force the likely EVS display via selector 0x008F, then clear selector 0x008F.",
"CONNECT NOT ACT globally clears the panel, so this scenario uses short observation windows to avoid mistaking timeout cleanup for selector clearing.",
"Record the panel within about one second of each write: EVS set, clear, and EVS set again."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "send",
"label": "e000_008f_likely_evs",
"frame": "00 01 0F 08 00 5C",
"listen": 0.85
},
{
"action": "send",
"label": "e000_008f_clear",
"frame": "00 01 0F 00 00 54",
"listen": 0.85
},
{
"action": "send",
"label": "e000_008f_likely_evs_again",
"frame": "00 01 0F 08 00 5C",
"listen": 0.85
}
]
}

View File

@@ -0,0 +1,36 @@
{
"name": "shutter-008f-evs-timeout-control",
"notes": [
"Recover to CONNECT OK, force likely EVS via selector 0x008F, then deliberately do not clear it.",
"This is the negative control for the adjacent-selector methodology: if the panel later blanks or falls to CONNECT NOT ACT, that is timeout cleanup, not proof that 0x008F clear worked.",
"Record the time from EVS visibility to blank/CONNECT NOT ACT."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "send",
"label": "e000_008f_likely_evs",
"frame": "00 01 0F 08 00 5C",
"listen": 4.0
}
]
}

View File

@@ -0,0 +1,236 @@
{
"name": "shutter-0093-bit-isolation",
"notes": [
"Recover to CONNECT OK, then isolate likely selector 0x0093 lamp/display bits with a clear and OK seed before each candidate.",
"Record white-balance PRESET, black/flare MANUAL, black/flare AUTO, shutter display, iris AUTO, and LCD state during each candidate window.",
"This follows the 0x0093=0x8000 and 0x0093=0xFFFF bench observations that affected lamps beyond the shutter cluster."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 1,
"steps": [
{
"action": "send",
"label": "e000_0093_clear_before_bit12",
"frame": "00 01 13 00 00 48",
"listen": 0.20
},
{
"action": "send",
"label": "selector_zero_ok_before_bit12",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_bit12_rom_gate",
"frame": "00 01 13 10 00 58",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.20,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit5",
"frame": "00 01 13 00 00 48",
"listen": 0.20
},
{
"action": "send",
"label": "selector_zero_ok_before_bit5",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_bit5_rom_gate",
"frame": "00 01 13 00 20 68",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.20,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bits12_5",
"frame": "00 01 13 00 00 48",
"listen": 0.20
},
{
"action": "send",
"label": "selector_zero_ok_before_bits12_5",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_bits12_5",
"frame": "00 01 13 10 20 78",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.20,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit15",
"frame": "00 01 13 00 00 48",
"listen": 0.20
},
{
"action": "send",
"label": "selector_zero_ok_before_bit15",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_bit15_seen_wb_preset_blackflare_manual",
"frame": "00 01 13 80 00 C8",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.20,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bits15_5",
"frame": "00 01 13 00 00 48",
"listen": 0.20
},
{
"action": "send",
"label": "selector_zero_ok_before_bits15_5",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_bits15_5",
"frame": "00 01 13 80 20 E8",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.20,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bits15_12",
"frame": "00 01 13 00 00 48",
"listen": 0.20
},
{
"action": "send",
"label": "selector_zero_ok_before_bits15_12",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_bits15_12",
"frame": "00 01 13 90 00 D8",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.20,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bits15_12_5",
"frame": "00 01 13 00 00 48",
"listen": 0.20
},
{
"action": "send",
"label": "selector_zero_ok_before_bits15_12_5",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_bits15_12_5",
"frame": "00 01 13 90 20 F8",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.20,
"ack_on": {
"enabled": false
}
}
]
},
{
"action": "listen",
"seconds": 0.75
}
]
}

View File

@@ -0,0 +1,436 @@
{
"name": "shutter-0093-blackflare-auto-candidates",
"notes": [
"Recover to CONNECT OK, then use known 0x0093=0x9020 black/flare-manual context and add one remaining bit at a time.",
"Earlier 0xFFFF made black/flare AUTO, while 0x9020 kept black/flare MANUAL, so the missing AUTO bit should be outside bits 15, 12, and 5.",
"Record white-balance MANUAL/PRESET, black/flare MANUAL/AUTO, shutter display, iris AUTO, and LCD state during each candidate window."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 1,
"steps": [
{
"action": "send",
"label": "e000_0093_known_manual_context_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_known_auto_reference_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit14",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit14",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit14",
"frame": "00 01 13 D0 20 B8",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit13",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit13",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit13",
"frame": "00 01 13 B0 20 D8",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit11",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit11",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit11",
"frame": "00 01 13 98 20 F0",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit10",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit10",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit10",
"frame": "00 01 13 94 20 FC",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit9",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit9",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit9",
"frame": "00 01 13 92 20 FA",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit8",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit8",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit8",
"frame": "00 01 13 91 20 F9",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit7",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit7",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit7",
"frame": "00 01 13 90 A0 78",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit6",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit6",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit6",
"frame": "00 01 13 90 60 B8",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit4",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit4",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit4",
"frame": "00 01 13 90 30 E8",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit3",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit3",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit3",
"frame": "00 01 13 90 28 F0",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit2",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit2",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit2",
"frame": "00 01 13 90 24 FC",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit1",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit1",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit1",
"frame": "00 01 13 90 22 FA",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "e000_0093_clear_before_bit0",
"frame": "00 01 13 00 00 48",
"listen": 0.18
},
{
"action": "send",
"label": "selector_zero_ok_before_bit0",
"frame": "00 00 00 80 00 DA",
"listen": 0.10
},
{
"action": "send",
"label": "e000_0093_9020_plus_bit0",
"frame": "00 01 13 90 21 F9",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x093"
],
"gap": 0.16,
"ack_on": {
"enabled": false
}
}
]
},
{
"action": "listen",
"seconds": 0.75
}
]
}

View File

@@ -0,0 +1,115 @@
{
"name": "shutter-0093-blackflare-confirm-90ff",
"notes": [
"Single-candidate streaming confirmation for selector 0x0093 value 0x90FF.",
"The known 0xFFFF AUTO reference is included first as a positive control.",
"Expected observation pattern if this candidate drives black/flare AUTO: MANUAL -> AUTO -> MANUAL -> AUTO -> MANUAL.",
"All holds refresh every 0.60s so CONNECT OK should stay alive during the visual test."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 6,
"steps": [
{
"action": "send",
"label": "positive_auto_reference_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_after_positive_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "candidate_90ff",
"frame": "00 01 13 90 FF 27",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_return_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "candidate_90ff_repeat",
"frame": "00 01 13 90 FF 27",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "manual_tail_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
}
]
}

View File

@@ -0,0 +1,115 @@
{
"name": "shutter-0093-blackflare-confirm-9f20",
"notes": [
"Single-candidate streaming confirmation for selector 0x0093 value 0x9F20.",
"The known 0xFFFF AUTO reference is included first as a positive control.",
"Expected observation pattern if this candidate drives black/flare AUTO: MANUAL -> AUTO -> MANUAL -> AUTO -> MANUAL.",
"All holds refresh every 0.60s so CONNECT OK should stay alive during the visual test."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 6,
"steps": [
{
"action": "send",
"label": "positive_auto_reference_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_after_positive_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "candidate_9f20",
"frame": "00 01 13 9F 20 F7",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_return_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "candidate_9f20_repeat",
"frame": "00 01 13 9F 20 F7",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "manual_tail_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
}
]
}

View File

@@ -0,0 +1,115 @@
{
"name": "shutter-0093-blackflare-confirm-9fff",
"notes": [
"Single-candidate streaming confirmation for selector 0x0093 value 0x9FFF.",
"The known 0xFFFF AUTO reference is included first as a positive control.",
"Expected observation pattern if this candidate drives black/flare AUTO: MANUAL -> AUTO -> MANUAL -> AUTO -> MANUAL.",
"All holds refresh every 0.60s so CONNECT OK should stay alive during the visual test."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 6,
"steps": [
{
"action": "send",
"label": "positive_auto_reference_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_after_positive_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "candidate_9fff",
"frame": "00 01 13 9F FF 28",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_return_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "candidate_9fff_repeat",
"frame": "00 01 13 9F FF 28",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "manual_tail_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
}
]
}

View File

@@ -0,0 +1,115 @@
{
"name": "shutter-0093-blackflare-confirm-f020",
"notes": [
"Single-candidate streaming confirmation for selector 0x0093 value 0xF020.",
"The known 0xFFFF AUTO reference is included first as a positive control.",
"Expected observation pattern if this candidate drives black/flare AUTO: MANUAL -> AUTO -> MANUAL -> AUTO -> MANUAL.",
"All holds refresh every 0.60s so CONNECT OK should stay alive during the visual test."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 6,
"steps": [
{
"action": "send",
"label": "positive_auto_reference_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_after_positive_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "candidate_f020",
"frame": "00 01 13 F0 20 98",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_return_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "candidate_f020_repeat",
"frame": "00 01 13 F0 20 98",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "manual_tail_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
}
]
}

View File

@@ -0,0 +1,115 @@
{
"name": "shutter-0093-blackflare-confirm-ff20",
"notes": [
"Single-candidate streaming confirmation for selector 0x0093 value 0xFF20.",
"The known 0xFFFF AUTO reference is included first as a positive control.",
"Expected observation pattern if this candidate drives black/flare AUTO: MANUAL -> AUTO -> MANUAL -> AUTO -> MANUAL.",
"All holds refresh every 0.60s so CONNECT OK should stay alive during the visual test."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 6,
"steps": [
{
"action": "send",
"label": "positive_auto_reference_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_after_positive_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "candidate_ff20",
"frame": "00 01 13 FF 20 97",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_return_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "candidate_ff20_repeat",
"frame": "00 01 13 FF 20 97",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "manual_tail_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
}
]
}

View File

@@ -0,0 +1,106 @@
{
"name": "shutter-0093-blackflare-field-confirm",
"notes": [
"Shorter black/flare field confirmation after the field-groups run produced three MANUAL->AUTO->MANUAL swaps.",
"This keeps only the broad candidates most likely to explain those swaps, with longer holds for easier visual correlation.",
"Each candidate is preceded by 0x9020 manual context. Count which candidate windows produce black/flare AUTO."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "send",
"label": "manual_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 1.80
},
{
"action": "send",
"label": "auto_reference_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 2.80
},
{
"action": "send",
"label": "manual_before_candidate_f020",
"frame": "00 01 13 90 20 F8",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_f020_high_upper_nibble",
"frame": "00 01 13 F0 20 98",
"listen": 2.80
},
{
"action": "send",
"label": "manual_before_candidate_ff20",
"frame": "00 01 13 90 20 F8",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_ff20_all_high_byte",
"frame": "00 01 13 FF 20 97",
"listen": 2.80
},
{
"action": "send",
"label": "manual_before_candidate_9f20",
"frame": "00 01 13 90 20 F8",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_9f20_high_low_nibble",
"frame": "00 01 13 9F 20 F7",
"listen": 2.80
},
{
"action": "send",
"label": "manual_before_candidate_90ff",
"frame": "00 01 13 90 20 F8",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_90ff_low_byte",
"frame": "00 01 13 90 FF 27",
"listen": 2.80
},
{
"action": "send",
"label": "manual_before_candidate_9fff",
"frame": "00 01 13 90 20 F8",
"listen": 1.80
},
{
"action": "send",
"label": "candidate_9fff_high_low_nibble_plus_low_byte",
"frame": "00 01 13 9F FF 28",
"listen": 2.80
},
{
"action": "listen",
"seconds": 0.75
}
]
}

View File

@@ -0,0 +1,154 @@
{
"name": "shutter-0093-blackflare-field-groups",
"notes": [
"Follow-up after the slow-marked run: black/flare swapped only twice, likely on 0x9020 -> 0xFFFF and back to 0x9020.",
"That suggests black/flare AUTO is not one single extra bit over 0x9020, but a multi-bit mode field.",
"Each candidate is preceded by 0x9020 manual context. Record whether black/flare changes during the candidate hold."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "send",
"label": "known_manual_context_9020",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "known_auto_reference_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 1.80
},
{
"action": "send",
"label": "manual_before_high_upper_nibble_f020",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_high_upper_nibble_f020",
"frame": "00 01 13 F0 20 98",
"listen": 1.80
},
{
"action": "send",
"label": "manual_before_all_high_byte_ff20",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_all_high_byte_ff20",
"frame": "00 01 13 FF 20 97",
"listen": 1.80
},
{
"action": "send",
"label": "manual_before_high_low_nibble_9f20",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_high_low_nibble_9f20",
"frame": "00 01 13 9F 20 F7",
"listen": 1.80
},
{
"action": "send",
"label": "manual_before_low_byte_90ff",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_low_byte_90ff",
"frame": "00 01 13 90 FF 27",
"listen": 1.80
},
{
"action": "send",
"label": "manual_before_high_low_nibble_plus_low_byte_9fff",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_high_low_nibble_plus_low_byte_9fff",
"frame": "00 01 13 9F FF 28",
"listen": 1.80
},
{
"action": "send",
"label": "manual_before_low_bits0_5_903f",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_low_bits0_5_903f",
"frame": "00 01 13 90 3F E7",
"listen": 1.80
},
{
"action": "send",
"label": "manual_before_high_low_nibble_combo_9b20",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_high_low_nibble_combo_9b20",
"frame": "00 01 13 9B 20 F3",
"listen": 1.80
},
{
"action": "send",
"label": "manual_before_high_low_nibble_combo_9d20",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_high_low_nibble_combo_9d20",
"frame": "00 01 13 9D 20 F5",
"listen": 1.80
},
{
"action": "send",
"label": "manual_before_high_low_nibble_combo_9e20",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_high_low_nibble_combo_9e20",
"frame": "00 01 13 9E 20 F6",
"listen": 1.80
},
{
"action": "listen",
"seconds": 0.75
}
]
}

View File

@@ -0,0 +1,178 @@
{
"name": "shutter-0093-blackflare-field-stream-confirm",
"notes": [
"Streaming confirmation for selector 0x0093 black/flare fields.",
"The prior field-confirm run held candidates too long and fell into CONNECT NOT ACT during the 0xFFFF hold.",
"This repeats each candidate every 0.60s so the candidate value itself acts like a CCU refresh stream."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_manual_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_auto_reference_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_manual_9020_before_f020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_candidate_f020",
"frame": "00 01 13 F0 20 98",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_manual_9020_before_ff20",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_candidate_ff20",
"frame": "00 01 13 FF 20 97",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_manual_9020_before_9f20",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_candidate_9f20",
"frame": "00 01 13 9F 20 F7",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_manual_9020_before_90ff",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_candidate_90ff",
"frame": "00 01 13 90 FF 27",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_manual_9020_before_9fff",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 4,
"steps": [
{
"action": "send",
"label": "stream_candidate_9fff",
"frame": "00 01 13 9F FF 28",
"listen": 0.60
}
]
},
{
"action": "listen",
"seconds": 0.75
}
]
}

View File

@@ -0,0 +1,210 @@
{
"name": "shutter-0093-blackflare-lowbyte-groups",
"notes": [
"Narrow black/flare AUTO now that 0x90FF and 0x9FFF both toggled AUTO but 0xF020/0xFF20/0x9F20 did not.",
"This keeps the high byte fixed at 0x90 and varies only the low byte.",
"Use 0x9020 as the manual reference and 0x90FF as the low-byte AUTO positive control."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_reference_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 6,
"steps": [
{
"action": "send",
"label": "positive_lowbyte_auto_90ff",
"frame": "00 01 13 90 FF 27",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_before_9000",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "candidate_9000_lowbyte_none",
"frame": "00 01 13 90 00 D8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_before_901f",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "candidate_901f_low_bits_0_to_4",
"frame": "00 01 13 90 1F C7",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_before_903f",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "candidate_903f_low_bits_0_to_5",
"frame": "00 01 13 90 3F E7",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_before_90c0",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "candidate_90c0_low_bits_6_to_7",
"frame": "00 01 13 90 C0 18",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_before_90e0",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "candidate_90e0_low_bits_5_to_7",
"frame": "00 01 13 90 E0 38",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "manual_before_90df",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 5,
"steps": [
{
"action": "send",
"label": "candidate_90df_all_except_bit5",
"frame": "00 01 13 90 DF 07",
"listen": 0.60
}
]
},
{
"action": "repeat",
"count": 8,
"steps": [
{
"action": "send",
"label": "manual_tail_9020",
"frame": "00 01 13 90 20 F8",
"listen": 0.60
}
]
}
]
}

View File

@@ -0,0 +1,202 @@
{
"name": "shutter-0093-blackflare-slow-marked",
"notes": [
"Slow marked follow-up for selector 0x0093 black/flare AUTO hunting.",
"Each candidate is preceded by known 0x9020 context, which previously kept black/flare MANUAL. This avoids the clear/OK reset flicker that made white-balance swap quickly.",
"Record whether black/flare changes during the candidate hold. White-balance should be steadier because all candidates keep the 0x9020 base bits."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "send",
"label": "known_manual_context_9020",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "known_auto_reference_ffff",
"frame": "00 01 13 FF FF 48",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit14",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit14_d020",
"frame": "00 01 13 D0 20 B8",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit13",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit13_b020",
"frame": "00 01 13 B0 20 D8",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit11",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit11_9820",
"frame": "00 01 13 98 20 F0",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit10",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit10_9420",
"frame": "00 01 13 94 20 FC",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit9",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit9_9220",
"frame": "00 01 13 92 20 FA",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit8",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit8_9120",
"frame": "00 01 13 91 20 F9",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit7",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit7_90a0",
"frame": "00 01 13 90 A0 78",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit6",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit6_9060",
"frame": "00 01 13 90 60 B8",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit4",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit4_9030",
"frame": "00 01 13 90 30 E8",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit3",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit3_9028",
"frame": "00 01 13 90 28 F0",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit2",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit2_9024",
"frame": "00 01 13 90 24 FC",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit1",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit1_9022",
"frame": "00 01 13 90 22 FA",
"listen": 1.80
},
{
"action": "send",
"label": "known_manual_context_9020_before_bit0",
"frame": "00 01 13 90 20 F8",
"listen": 1.20
},
{
"action": "send",
"label": "candidate_bit0_9021",
"frame": "00 01 13 90 21 F9",
"listen": 1.80
},
{
"action": "listen",
"seconds": 0.75
}
]
}

View File

@@ -0,0 +1,87 @@
{
"name": "shutter-0093-gate-8000",
"notes": [
"Recover to CONNECT OK, read the shutter cluster, set primary selector 0x0093 to 0x8000, then read the cluster again.",
"ROM trace shows E000[0x0093] gates adjacent shutter/clear-scan value lanes, but the exact bit meaning is not bench-confirmed.",
"CONNECT NOT ACT can clear the panel, so a fresh selector-zero OK seed is sent immediately before the 0x0093 write.",
"Record visual changes during the short post-write window, then use the second sweep for table evidence."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "table_sweep",
"selectors": [
"0x08F",
"0x093",
"0x0A3",
"0x0A4",
"0x0A5",
"0x0D8",
"0x080",
"0x0D9",
"0x0A6",
"0x0DA",
"0x081"
],
"gap": 0.10,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "selector_zero_connect_ok_seed_before_gate",
"frame": "00 00 00 80 00 DA",
"listen": 0.15
},
{
"action": "send",
"label": "e000_0093_gate_high_bit",
"frame": "00 01 13 80 00 C8",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x08F",
"0x093",
"0x0A3",
"0x0A4",
"0x0A5",
"0x0D8",
"0x080",
"0x0D9",
"0x0A6",
"0x0DA",
"0x081"
],
"gap": 0.12,
"ack_on": {
"enabled": false
}
},
{
"action": "listen",
"seconds": 0.75
}
]
}

View File

@@ -0,0 +1,87 @@
{
"name": "shutter-0093-gate-ffff",
"notes": [
"Recover to CONNECT OK, read the shutter cluster, set primary selector 0x0093 to 0xFFFF, then read the cluster again.",
"This enables both ROM-observed gate bits 12 and 5, plus unknown bits, so run after shutter-0093-gate-8000.",
"CONNECT NOT ACT can clear the panel, so a fresh selector-zero OK seed is sent immediately before the 0x0093 write.",
"Record visual changes during the short post-write window, then use the second sweep for table evidence."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "table_sweep",
"selectors": [
"0x08F",
"0x093",
"0x0A3",
"0x0A4",
"0x0A5",
"0x0D8",
"0x080",
"0x0D9",
"0x0A6",
"0x0DA",
"0x081"
],
"gap": 0.10,
"ack_on": {
"enabled": false
}
},
{
"action": "send",
"label": "selector_zero_connect_ok_seed_before_gate",
"frame": "00 00 00 80 00 DA",
"listen": 0.15
},
{
"action": "send",
"label": "e000_0093_all_bits",
"frame": "00 01 13 FF FF 48",
"listen": 0.85
},
{
"action": "table_sweep",
"selectors": [
"0x08F",
"0x093",
"0x0A3",
"0x0A4",
"0x0A5",
"0x0D8",
"0x080",
"0x0D9",
"0x0A6",
"0x0DA",
"0x081"
],
"gap": 0.12,
"ack_on": {
"enabled": false
}
},
{
"action": "listen",
"seconds": 0.75
}
]
}

View File

@@ -0,0 +1,55 @@
{
"name": "shutter-adjacent-readback",
"notes": [
"Recover to CONNECT OK, then read the currently known shutter/clear-scan selector cluster.",
"This is read-only after the selector-zero CONNECT seed and should be the first adjacent-selector bench run.",
"CONNECT NOT ACT can clear the panel during/after the sweep, so treat visual state at the end as timeout-contaminated.",
"Use this primarily for table readback rows and non-heartbeat frames, not for proving display clearing."
],
"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_connect_ok_seed",
"frame": "00 00 00 80 00 DA",
"listen": 0.25
},
{
"action": "table_sweep",
"selectors": [
"0x08F",
"0x093",
"0x0A3",
"0x0A4",
"0x0A5",
"0x0D8",
"0x080",
"0x0D9",
"0x0A6",
"0x0DA",
"0x081"
],
"gap": 0.12,
"ack_on": {
"enabled": false
}
},
{
"action": "listen",
"seconds": 0.75
}
]
}

View File

@@ -0,0 +1,16 @@
#!/usr/bin/env python3
"""Summarize unexpected device frames from a serial_scenario log."""
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from h8536.serial_scenario_unexpected import main
if __name__ == "__main__":
raise SystemExit(main())

View 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()