Files
Sony-rcp/docs/discovery-notes.md
2026-05-13 15:19:58 +10:00

2394 lines
94 KiB
Markdown

# Discovery Notes
This file records hands-on observations separately from manual-derived facts.
Treat these as bench notes: useful and current, but still worth rechecking with
photos, continuity tests, and instrument captures.
## 2026-05-13 - RCP-TX7 10-Pin Power and Cable
Observed on the RCP-TX7 10-pin remote connector/cable during restoration work:
- Pin 9 confirmed as ground / DC return.
- Pin 10 confirmed as power input.
- Cable color for pin 9 / ground: brown.
- Cable color for pin 10 / +12 V power: brown-white.
- Cable colors for pins 1-8 have been continuity-mapped; see the working cable
map below.
- Yellow and yellow-white conductors are present in the cable but did not map to
connector pins during continuity testing.
- Multimeter reading from pin 9 ground to pin 4 serial data: about -9 V.
- Multimeter reading from pin 9 ground to pin 7 serial data: about +0.037 V.
- Pins 4 and 7 were the only serial-related combinations that produced a
meaningful multimeter result during this check.
- With power present on pins 9 and 10, the panel shows a green `PANEL ACTIVE`
light.
- The inside of the 10-pin cable contains 12 wires total.
- Three of those wire groups are twisted pairs.
Immediate implications:
- The bench result agrees with the RCP-TX7 and CCU-TX7 manual pinout for pins 9
and 10.
- The 12-conductor cable construction suggests not every conductor maps
one-to-one to the 10 connector pins; shielding/drain, duplicated grounds, or
paired signal returns may be present.
- The three twisted pairs are likely important candidates for serial data,
composite video, and/or power/ground pairing, but this should be confirmed by
continuity testing rather than color or twist assumptions.
- Pin 4 measuring around -9 V relative to pin 9 strongly suggests true RS-232
level idle on at least the RCP-to-CCU/camera data line.
- Pin 7 near 0 V may be inactive/floating until a CCU or camera drives the
return data line.
### Working Cable Map
This table combines the manual-derived pin purpose with hands-on color mapping.
Rows marked `confirmed` have been checked on the current cable/panel under test.
| Pin | Purpose | Cable color | Status | Notes |
| ---: | --- | --- | --- | --- |
| 1 | Spare / unused | red | confirmed | No function shown in service manual. |
| 2 | VBS / composite video X | black | confirmed | 1.0 Vp-p composite video input to RCP. |
| 3 | VBS / composite video ground | green | confirmed | Video reference/ground. |
| 4 | Serial data, RCP to CCU/camera | orange | confirmed | RS-232C-based data direction. |
| 5 | Serial/data ground | blue | confirmed | One of two serial/data grounds. |
| 6 | Serial/data ground | grey | confirmed | One of two serial/data grounds. |
| 7 | Serial data, CCU/camera to RCP | purple | confirmed | RS-232C-based data direction. |
| 8 | Spare / unused | purple-white | confirmed | No function shown in service manual. |
| 9 | DC return / ground | brown | confirmed | Confirmed as ground on current cable. |
| 10 | +12 V remote power input | brown-white | confirmed | Confirmed as power input on current cable. |
### Unmapped Cable Conductors
The cable contains two additional conductors that did not show continuity to
the 10 connector pins during the current test:
| Conductor color | Current status | Notes |
| --- | --- | --- |
| yellow | unmapped | May be shield/drain-related, spare, broken, or connected only at one end. |
| yellow-white | unmapped | May be shield/drain-related, spare, broken, or connected only at one end. |
Recheck these against connector shells, shield braid/drain, cable strain relief
hardware, and both ends of the cable if accessible.
Suggested next observations to capture:
1. Connector orientation photo showing pin numbering reference.
2. Wire color list, including which colors form each twisted pair.
3. Confirm whether yellow and yellow-white connect to shield, shell, or one end
only.
4. Resistance between pins 5, 6, and 9 with the cable disconnected.
5. Scope idle voltage and activity on pins 4 and 7 relative to pins 5/6 and
pin 9 while pressing panel controls and, later, while connected to a CCU or
camera.
## Serial Capture Setup
Initial USB serial adapter wiring for passive listening:
| Adapter terminal | RCP-TX7 cable pin | Cable color | Purpose |
| --- | ---: | --- | --- |
| `GND` | 9 | brown | Shared reference / DC return |
| `RXD` | 4 | orange | Listen to RCP-to-CCU/camera serial data |
Do not connect adapter `TXD` during the first capture pass. Pin 4 measured about
-9 V relative to pin 9, so use the adapter's RS-232 side, not TTL UART mode.
Capture helper:
```powershell
python -m pip install pyserial
python scripts/serial_sniff.py --list
python scripts/serial_sniff.py --port COM3 --baud 38400 --ascii
python scripts/serial_sniff.py --port COM3 --baud 38400 --frame-size 6 --log captures/rcp-pin4.txt
```
Replace `COM3` with the adapter port shown by `--list` or Windows Device
Manager. While the script is running, press simple RCP controls and watch for
new hex bytes.
### 2026-05-13 Initial Pin 4 Capture
With the adapter in RS-232 mode, adapter `RXD` connected to RCP pin 4, and
adapter `GND` connected to pin 9, the stream produced repeating 6-byte patterns:
```text
00 00 00 00 80 DA
00 00 07 80 00 DD
```
Observed behavior:
- Frames repeat roughly every 200 ms during the sample.
- The stream sometimes appeared split as `00` followed by five bytes, which is
likely a read-timeout/chunking artifact rather than a protocol feature.
- Button presses did not obviously correlate with a visible byte change in the
first capture.
Current interpretation:
- This looks like a regular RCP-origin heartbeat/status transmission on pin 4,
not random noise.
- Because only pin 4 is connected, this may be the panel repeatedly trying to
announce itself or poll a missing CCU/camera.
- Pin 7 measured near 0 V and is probably quiet until a CCU/camera drives the
return channel.
Next capture passes:
1. Use `--frame-size 6` to avoid misleading `1 + 5` packet splits.
2. Capture a quiet baseline for 30 seconds.
3. Capture separate files while pressing one control repeatedly, naming the
action in the filename.
4. Later, capture pin 7 when connected to a real CCU/camera or a controlled
test transmitter.
### 2026-05-13 Baseline vs CAM POWER Capture
Capture files:
- `captures/rcp-pin4-baseline.txt`
- `captures/rcp-pin4-cam-power.txt`
- `captures/rcp-pin4-call.txt`
Frame counts from the available logs:
| Capture | Frame | Count | Current label |
| --- | --- | ---: | --- |
| baseline | `00 00 00 00 80 DA` | 67 | idle heartbeat |
| CAM POWER | `00 00 00 00 80 DA` | 23 | idle heartbeat |
| CAM POWER | `00 00 07 80 00 DD` | 4 | CAM POWER candidate |
| CALL | `00 00 00 00 80 DA` | 17 | idle heartbeat |
| CALL | `00 00 15 80 00 CF` | 4 | CALL candidate, state/high bit set |
| CALL | `00 00 15 00 00 4F` | 4 | CALL candidate, state/high bit clear |
Current interpretation:
- The baseline capture contains only `00 00 00 00 80 DA`.
- Pressing `CAM POWER` introduces `00 00 07 80 00 DD`.
- Pressing `CALL` introduces `00 00 15 80 00 CF` and `00 00 15 00 00 4F`.
- Other tested buttons did not obviously produce unique frames while the panel
was not connected to a CCU/camera.
- `CAM POWER` and `CALL` may be among the few controls the panel transmits even
without a completed host/CCU session.
- The CALL frames differ by byte 4 (`80` vs `00`) and final byte (`CF` vs `4F`),
suggesting a state bit plus checksum or complement-style trailing byte.
- Current checksum hypothesis: byte 6 is XOR checksum with seed `0x5A` over the
first five bytes. Examples:
- `5A xor 00 xor 00 xor 00 xor 00 xor 80 = DA`
- `5A xor 00 xor 00 xor 07 xor 80 xor 00 = DD`
- `5A xor 00 xor 00 xor 15 xor 80 xor 00 = CF`
- `5A xor 00 xor 00 xor 15 xor 00 xor 00 = 4F`
Helper for future captures:
```powershell
python scripts/analyze_capture.py captures/rcp-pin4-baseline.txt captures/rcp-pin4-cam-power.txt captures/rcp-pin4-call.txt
```
## Host Response Experiments
The RCP currently appears to be in an offline heartbeat state. With no CCU/camera
response present, only `CAM POWER` and `CALL` have been observed to send unique
frames beyond the heartbeat. The next protocol step is to learn what the RCP
expects on pin 7 (`CCU/camera -> RCP`).
Important wiring for host-response tests:
| Adapter terminal | RCP-TX7 cable pin | Cable color | Purpose |
| --- | ---: | --- | --- |
| `GND` | 9 | brown | Shared reference / DC return |
| `TXD` | 7 | purple | Candidate host-to-RCP transmit line |
Suggested safety precautions:
- Use the adapter's RS-232 side, not TTL UART.
- Keep adapter `RXD` on pin 4 if possible so the RCP output is still logged.
- Add a series resistor, for example 1 k to 4.7 k, between adapter `TXD` and pin
7 for early experiments.
- Send one candidate frame at a time or repeat at a slow cadence. Avoid brute
forcing unknown byte ranges.
- Watch for changes in heartbeat, LCD state, panel lock state, or new frames on
pin 4.
Frame sender:
```powershell
python scripts/serial_send_frame.py --port COM3 --dry-run
python scripts/serial_send_frame.py --port COM3 --frame "00 00 00 00 80 DA" --repeat 5 --interval 0.2
```
On Windows, a COM port is usually exclusive, so the sniffer and sender cannot
open the same adapter at the same time. Use the combined probe script when RXD
is connected to pin 4 and TXD is connected to pin 7:
```powershell
python scripts/serial_probe_response.py --port COM3 --tx-frame "00 00 00 00 80 DA" --repeat 5 --interval 0.2 --log captures/rcp-response-test.txt
```
This listens first, sends the candidate response from the same serial session,
then keeps listening for changes on pin 4.
Candidate first response:
- `00 00 00 00 80 DA` - mirror the observed heartbeat as a possible no-op/ack.
If mirroring the heartbeat changes nothing, the next low-risk approach is to
capture a real CCU/camera response rather than guessing. If no host is available,
try only checksum-valid, documented-frame-shape candidates and record every
attempt in a separate capture log.
### 2026-05-13 Heartbeat Mirror Response Result
Experiment:
- Adapter `TXD` connected to RCP pin 7.
- Sent `00 00 00 00 80 DA` on the host-to-RCP line as a mirrored heartbeat /
possible no-op acknowledgement.
- Capture file: `captures/rcp-response-heartbeat-mirror.txt`.
Observed result:
- The RCP screen changed to `CONNECT: NOT ACT`.
- During this capture, pin 4 still transmitted only `00 00 00 00 80 DA`.
- Frame count: 59 received heartbeat frames, 10 transmitted mirrored heartbeat
frames.
- Pin 4 heartbeat timing became more frequent during the response window, then
returned to the slower baseline cadence afterward.
Current interpretation:
- The RCP is detecting return-channel traffic on pin 7.
- Mirroring the heartbeat is enough to move the panel out of the simple offline
state, but it does not complete active host/CCU negotiation.
- `NOT ACT` likely means connected/not active, connected/not activated, or a
similar state where the link is electrically/protocol-visible but no valid
control session has been established.
- The RCP did not emit a new command/status frame on pin 4 in response to the
mirrored heartbeat, so the next handshake step is probably not simply an echo
of its heartbeat.
Additional checksum-valid response tests:
| Capture | TX frame | RX result on pin 4 | Screen result |
| --- | --- | --- | --- |
| `captures/rcp-response-zero-state.txt` | `00 00 00 00 00 5A` | heartbeat only | `CONNECT: NOT ACT` |
| `captures/rcp-response-state-byte4.txt` | `00 00 00 80 00 DA` | heartbeat only | `CONNECT: NOT ACT` |
| `captures/rcp-response-invalid-checksum.txt` | `00 00 00 00 80 00` | heartbeat only | `CONNECT: NOT ACT` |
| TXD connected, no transmitted bytes | RS-232 idle only | heartbeat only | no `CONNECT: NOT ACT` |
| Single-byte test | `00` | heartbeat only | no `CONNECT: NOT ACT` |
| Single-byte test | `FF` | heartbeat only | no `CONNECT: NOT ACT` |
| Short-frame test | `00 00 00` | heartbeat only | no `CONNECT: NOT ACT` |
| Frame-length test | `00 00 00 00` | heartbeat only | no `CONNECT: NOT ACT` |
| Frame-length test | `00 00 00 00 80` | heartbeat only | no `CONNECT: NOT ACT` |
| Frame-length test | `00 00 00 00 80 DA 00` | heartbeat only | `CONNECT: NOT ACT` |
Updated interpretation:
- `CONNECT: NOT ACT` is probably a link-present state, not proof of a correct
CCU handshake.
- The RCP reacts to several checksum-valid 6-byte frames on pin 7, but continues
sending only the pin 4 heartbeat.
- An intentionally invalid checksum frame also produced `CONNECT: NOT ACT`, so
that display state does not prove checksum acceptance.
- The response needed to enter an active control session likely needs a specific
status/identity/activation frame, not just a valid no-op frame shape.
- TXD connected at idle without transmitted bytes did not produce
`CONNECT: NOT ACT`, so the display state appears to require received byte
activity on pin 7, not merely a driven RS-232 idle level.
- Single-byte and three-byte transmissions did not produce `CONNECT: NOT ACT`,
so the RCP is likely recognizing a minimum frame length or parser shape rather
than arbitrary serial bytes.
- Four-byte and five-byte transmissions did not produce `CONNECT: NOT ACT`, but
a seven-byte transmission beginning with the known six-byte heartbeat did.
This suggests the first six bytes are enough to trigger the parser/link state,
and the seventh byte may be ignored, buffered for a later frame, or treated as
extra data after the recognized packet.
- None of the tested host frames have caused the RCP to emit anything on pin 4
except the heartbeat.
Command-field response tests, using frame shape `00 00 CMD 00 80 CHECKSUM`:
| Capture | TX frame | Checksum | Screen result | Notes |
| --- | --- | --- | --- | --- |
| `captures/rcp-response-cmd01.txt` | `00 00 01 00 80 DB` | valid | `CONNECT: NOT ACT` | 6-byte command-shaped frame accepted enough to change display. |
| `captures/rcp-response-cmd02.txt` | `00 00 02 00 80 DB` | invalid | `CONNECT: NOT ACT` | Bad checksum still changed display. |
| `captures/rcp-response-cmd02.txt` | `00 00 02 00 80 D8` | valid | `CONNECT: NOT ACT` | Valid checksum also changed display. |
| `captures/rcp-response-cmd03.txt` | `00 00 03 00 80 D9` | valid | `CONNECT: NOT ACT` | 6-byte command-shaped frame accepted enough to change display. |
| `captures/rcp-response-cmd04.txt` | `00 00 7F 00 80 A5` | valid | no screen change | First observed checksum-valid 6-byte frame that does not trigger `CONNECT: NOT ACT`. |
| `captures/rcp-response-cmd05.txt` | `00 00 80 00 80 5A` | valid | `CONNECT: NOT ACT` | 6-byte command-shaped frame accepted enough to change display. |
Implications from command-field tests:
- Screen change is not simply based on frame length or checksum validity.
- The command/status byte matters: `0x7F` appears ignored or treated as
non-link-establishing, despite a valid checksum.
- Tested commands `0x00`, `0x01`, `0x02`, `0x03`, and `0x80` can trigger
`CONNECT: NOT ACT`; `0x7F` did not.
- The RCP operating manual notes that `CAM POWER`, `MASTER`/`SLAVE`, and some
monitor functions are available only when connected to a CCU, so active state
may depend on CCU identity/status bits.
Next low-risk response experiments:
1. Repeat the same test with logging enabled so the pin 4 output before, during,
and after `CONNECT: NOT ACT` is captured.
2. Try sending the mirrored heartbeat continuously at a cadence close to the RCP
heartbeat, for example every 0.6 seconds, and watch whether the display state
changes.
3. Probe semantic fields within the six-byte frame shape, changing one byte at
a time and logging both screen state and pin 4 output. Prioritize small
command values and avoid broad brute-force sweeps.
4. Prefer capturing a real CCU/camera pin 7 response before broad guessing.
### Command Sweep Helper
A cautious command-byte sweep helper is available at
`scripts/serial_sweep_commands.py`. It sends only checksum-valid six-byte frames
using the current frame/checksum hypothesis and marks any RCP output that is not
the known heartbeat.
Recommended first sweep:
```powershell
python scripts/serial_sweep_commands.py --port COM5 --start 0x00 --end 0x20 --after-each 1.0 --log captures/rcp-sweep-cmd-00-20.txt
```
Optional dry run:
```powershell
python scripts/serial_sweep_commands.py --port COM5 --start 0x00 --end 0x20 --dry-run
```
Use small ranges and keep watching the RCP screen while the sweep runs. The log
captures TX/RX bytes, but it cannot record screen messages unless they are noted
manually afterward.
The `0x00-0x20` sweep produced `CONNECT: NOT ACT` roughly halfway through the
run, but the exact command was not recorded in the log. Rerun a narrower range
with manual screen prompts:
```powershell
python scripts/serial_sweep_commands.py --port COM5 --start 0x0C --end 0x14 --after-each 1.2 --prompt-screen --log captures/rcp-sweep-cmd-0c-14-screen.txt
```
At each prompt, press Enter for no screen change, type `CONNECT: NOT ACT` when
that appears, or type `q` to stop.
Prompted sweep result:
- Capture: `captures/rcp-sweep-cmd-0c-14-screen.txt`.
- The RCP was reset after each screen trigger to clear its state, so recorded
triggers should be treated as independent fresh observations.
- First recorded screen marker: after command `0x0C`, frame
`00 00 0C 00 80 D6`, screen `CONNECT: NOT ACT`.
- Later manual screen markers were recorded after `0x0D`, `0x10`, `0x11`,
`0x12`, `0x13`, and `0x14`.
- No manual screen markers were recorded after `0x0E` or `0x0F`.
- Pin 4 output remained the heartbeat `00 00 00 00 80 DA` throughout.
Interpretation:
- Commands `0x0C`, `0x0D`, `0x10`, `0x11`, `0x12`, `0x13`, and `0x14` have
independent evidence of triggering `CONNECT: NOT ACT` in this sweep.
- Commands `0x0E` and `0x0F` did not have a screen marker recorded in this
sweep and are current non-trigger candidates.
- Because pin 4 stayed heartbeat-only, this state change is visible on the LCD
but does not yet produce a new RCP-to-host serial response.
Second prompted sweep result:
- Capture: `captures/rcp-sweep-cmd-15-30-screen.txt`.
- The log includes one partial/restarted pass at the beginning, then a fuller
prompted sweep through `0x30`.
- Pin 4 output remained the heartbeat `00 00 00 00 80 DA` throughout.
Commands with recorded `CONNECT: NOT ACT` screen markers:
| Command | TX frame |
| ---: | --- |
| `0x15` | `00 00 15 00 80 CF` |
| `0x16` | `00 00 16 00 80 CC` |
| `0x17` | `00 00 17 00 80 CD` |
| `0x18` | `00 00 18 00 80 C2` |
| `0x19` | `00 00 19 00 80 C3` |
| `0x1A` | `00 00 1A 00 80 C0` |
| `0x1B` | `00 00 1B 00 80 C1` |
| `0x1C` | `00 00 1C 00 80 C6` |
| `0x1D` | `00 00 1D 00 80 C7` |
| `0x28` | `00 00 28 00 80 F2` |
| `0x29` | `00 00 29 00 80 F3` |
| `0x2C` | `00 00 2C 00 80 F6` |
| `0x2D` | `00 00 2D 00 80 F7` |
| `0x30` | `00 00 30 00 80 EA` |
Commands with no recorded screen marker in this sweep:
```text
0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25
0x26 0x27 0x2A 0x2B 0x2E 0x2F
```
Emerging pattern:
- Some command byte ranges trigger `CONNECT: NOT ACT` while nearby checksum-valid
commands do not.
- Triggering still does not make the RCP transmit anything except the heartbeat.
- `CONNECT: NOT ACT` appears to be a parser-recognized but not session-active
state. It may indicate the RCP recognizes the command class as CCU-like, but
the remaining status/identity/activation fields are wrong or incomplete.
### Targeted Field Matrix Probe
After the `0x15-0x30` sweep, the best next experiment is not a broader command
sweep. The command byte is clearly relevant, but active-session behavior may
depend on the state/value fields or the prefix bytes. Use
`scripts/serial_probe_matrix.py` to hold one promising command constant and vary
only a small set of fields.
Start with command `0x15` because it is already associated with the RCP's own
`CALL` output frames:
```powershell
python scripts/serial_probe_matrix.py --port COM5 --commands 0x15 --states "0x00 0x80" --values "0x00 0x80" --after-each 1.2 --prompt-screen --log captures/rcp-matrix-cmd15-state-value.txt
```
Dry-run frames:
```text
00 00 15 00 00 4F
00 00 15 00 80 CF
00 00 15 80 00 CF
00 00 15 80 80 4F
```
Why this is useful:
- `00 00 15 00 00 4F` and `00 00 15 80 00 CF` match the RCP's observed
`CALL` frames.
- `00 00 15 00 80 CF` matches the command-sweep shape that triggered
`CONNECT: NOT ACT`.
- `00 00 15 80 80 4F` checks whether both high/state bits together change the
parser state.
If all four still produce only `CONNECT: NOT ACT` or no change, the next matrix
should keep `cmd=0x15`, `state=0x00`, `value=0x80`, and vary only prefix bytes:
```powershell
python scripts/serial_probe_matrix.py --port COM5 --prefix2s "0x00-0x0F" --commands 0x15 --states 0x00 --values 0x80 --after-each 1.2 --prompt-screen --log captures/rcp-matrix-cmd15-prefix2-00-0f.txt
```
Treat any result other than heartbeat-only pin 4 output as high-priority. In
particular, look for a new RCP frame, a different LCD message, or any transition
from `CONNECT: NOT ACT` to an active/connected state.
### 2026-05-13 Command `0x15` State/Value Matrix Result
Capture:
- `captures/rcp-matrix-cmd15-state-value.txt`
Frames tested:
| Command | State | Value | TX frame | Screen result |
| ---: | ---: | ---: | --- | --- |
| `0x15` | `0x00` | `0x00` | `00 00 15 00 00 4F` | `CONNECT NOT ACT` |
| `0x15` | `0x00` | `0x80` | `00 00 15 00 80 CF` | `CONNECT NOT ACT` |
| `0x15` | `0x80` | `0x00` | `00 00 15 80 00 CF` | `CONNECT NOT ACT` |
| `0x15` | `0x80` | `0x80` | `00 00 15 80 80 4F` | `CONNECT NOT ACT` |
Analyzer result:
- Pin 4 RX stayed at heartbeat only: `00 00 00 00 80 DA`.
- No non-heartbeat RCP-to-host frames were observed.
- The RCP was sensitive to all four command `0x15` variants, including both
frames that match the panel's own `CALL` output, but none advanced the panel
beyond `CONNECT NOT ACT`.
Interpretation:
- For command `0x15`, the tested state/value high bits are not enough to produce
an active session.
- The missing host response is likely in another field, a required repeated
cadence, a multi-frame exchange, or a CCU/camera identity/status frame.
- Since command `0x15` is parser-visible across all tested state/value variants,
it is a good anchor for prefix-byte testing.
Recommended next matrix:
```powershell
python scripts/serial_probe_matrix.py --port COM5 --prefix2s "0x00-0x0F" --commands 0x15 --states 0x00 --values 0x80 --after-each 1.2 --prompt-screen --log captures/rcp-matrix-cmd15-prefix2-00-0f.txt
```
If all `prefix2` values behave the same, repeat with `prefix1s "0x00-0x0F"` and
`prefix2s 0x00`. Prefix bytes may encode device address, CCU identity, panel
number, or bus direction.
### 2026-05-13 Command `0x15` Prefix2 Matrix Result
Capture:
- `captures/rcp-matrix-cmd15-prefix2-00-0f.txt`
Test shape:
- `p1=0x00`
- `p2=0x00-0x0F`
- `cmd=0x15`
- `state=0x00`
- `value=0x80`
Analyzer result:
- Pin 4 RX stayed at heartbeat only: `00 00 00 00 80 DA`.
- No non-heartbeat RCP-to-host frames were observed.
- The log contains 263 heartbeat RX frames and 16 transmitted prefix2 variants.
Screen observations:
- `CONNECT NOT ACT` was recorded after prefix2 values `0x00`, `0x01`, `0x02`,
`0x03`, `0x04`, `0x05`, `0x06`, `0x08`, `0x09`, `0x0A`, `0x0B`, `0x0C`,
`0x0D`, and `0x0E`.
- No screen marker was recorded after prefix2 `0x07` or `0x0F`.
- One marker was typed as `CONNECT NTO ACT`; treat this as the same
observation unless later testing proves otherwise.
Interpretation:
- Prefix2 did not produce an active session in the tested low-nibble range.
- The missing response is still not visible on pin 4.
- The missing markers at `0x07` and `0x0F` may be real parser behavior, because
both have low three bits set, but this needs a focused confirmation run before
treating it as a rule.
Recommended confirmation:
```powershell
python scripts/serial_probe_matrix.py --port COM5 --prefix2s "0x06 0x07 0x08 0x0E 0x0F" --commands 0x15 --states 0x00 --values 0x80 --after-each 1.2 --prompt-screen --log captures/rcp-matrix-cmd15-prefix2-confirm.txt
```
Reset the RCP after any screen-triggering result. This keeps the comparison
between trigger and non-trigger prefix2 values clean.
### 2026-05-13 Prefix2 Confirmation Result
Capture:
- `captures/rcp-matrix-cmd15-prefix2-confirm.txt`
Test shape:
- `p1=0x00`
- `p2=0x06`, `0x07`, `0x08`, `0x0E`, `0x0F`
- `cmd=0x15`
- `state=0x00`
- `value=0x80`
Screen observations:
| Prefix2 | TX frame | Screen marker |
| ---: | --- | --- |
| `0x06` | `00 06 15 00 80 C9` | `CONNECT NOT ACT` |
| `0x07` | `00 07 15 00 80 C8` | none recorded |
| `0x08` | `00 08 15 00 80 C7` | `CONNECT NOT ACT` |
| `0x0E` | `00 0E 15 00 80 C1` | `CONNECT NOT ACT` |
| `0x0F` | `00 0F 15 00 80 C0` | none recorded |
Analyzer result:
- 65 heartbeat RX frames: `00 00 00 00 80 DA`.
- 14 apparent non-heartbeat RX frames after `p2=0x0F`:
`00 00 00 80 DA 00`.
- No other RCP-to-host frame shape was observed.
Interpretation:
- `p2=0x07` and `p2=0x0F` again failed to produce a recorded screen marker,
while neighboring values did.
- The apparent `00 00 00 80 DA 00` response after `p2=0x0F` is probably a
one-byte framing slip of the normal heartbeat stream, because it is exactly
the heartbeat sequence viewed from byte offset 1:
`00 00 00 00 80 DA 00 00 ...`.
- Because the shifted heartbeat also satisfies the current XOR checksum
hypothesis, checksum validity alone is not enough to prove frame alignment.
Recommended raw confirmation for `p2=0x0F`:
```powershell
python scripts/serial_probe_response.py --port COM5 --tx-frame "00 0F 15 00 80 C0" --repeat 1 --delay 1.5 --after 5 --frame-size 0 --log captures/rcp-prefix2-0f-raw.txt
```
Then repeat for `p2=0x07`:
```powershell
python scripts/serial_probe_response.py --port COM5 --tx-frame "00 07 15 00 80 C8" --repeat 1 --delay 1.5 --after 5 --frame-size 0 --log captures/rcp-prefix2-07-raw.txt
```
Raw capture avoids imposing 6-byte alignment on the received stream, so it
should show whether the apparent non-heartbeat is a real frame or just a shifted
view of the heartbeat.
### Series Resistor Note
Current host-to-RCP tests use a series resistor between adapter `TXD` and RCP
pin 7 as a protection measure. A 4.7 kOhm series resistor should normally still
work with a high-impedance RS-232 receiver input, so it is unlikely to explain a
selective pattern where nearby checksum-valid frames behave differently.
Possible resistor-related failure modes:
- If the RCP input is much lower impedance than expected, 4.7 kOhm could reduce
the voltage swing at pin 7.
- If the input is clamped internally, the resistor may limit current enough to
make the received waveform marginal.
- Marginal signaling would more likely produce random missed/garbled frames
than a repeatable distinction between specific prefix values.
Low-risk check:
- Measure pin 7 relative to pin 9 on the RCP side of the resistor while the
adapter is idle; it should show a strong RS-232 idle level, not near 0 V.
- If testing without the resistor, first try a smaller protection resistor such
as 1 kOhm rather than going straight to a direct connection.
- Compare one known-trigger frame, such as `00 06 15 00 80 C9`, and one
suspected non-trigger frame, such as `00 07 15 00 80 C8`, using the same reset
procedure.
### Direct Response Sweep Without Screen Logging
For response hunting, use `scripts/serial_direct_response_sweep.py` rather than
the older fixed-frame sweep. It sends checksum-valid 6-byte host frames, but
reads pin 4 as raw bytes and checks whether the received data can be explained
as the repeated heartbeat:
```text
00 00 00 00 80 DA
```
This avoids treating shifted heartbeat bytes such as `00 00 00 80 DA 00` as a
new response frame.
Recommended first direct sweep:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00-0xFF" --states 0x00 --values 0x80 --after-each 0.6 --stop-on-anomaly --log captures/rcp-direct-cmd-00-ff.txt
```
For a long sweep where every anomaly should be logged but the panel needs a
fresh power cycle before continuing, use `--pause-on-anomaly` instead of
`--stop-on-anomaly`. After the prompt, power-cycle the RCP, wait for the normal
heartbeat, then press Enter.
What to watch for:
- If the script reports `Anomalies: 0`, the panel never sent raw bytes that
differed from the heartbeat stream during this sweep.
- If it stops on an anomaly, preserve the log and rerun only the reported frame
with raw capture before assuming it is a real response.
- Keep the same resistor/wiring setup for this run so the result remains
comparable to the earlier observations.
If the command-only direct sweep finds nothing, the next direct grid should be
split into two chunks to stay within the default safety limit:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --prefix2s "0x00-0x0F" --commands "0x00-0x1F" --states 0x00 --values 0x80 --after-each 0.4 --stop-on-anomaly --log captures/rcp-direct-p2-00-0f-cmd-00-1f.txt
python scripts/serial_direct_response_sweep.py --port COM5 --prefix2s "0x00-0x0F" --commands "0x20-0x3F" --states 0x00 --values 0x80 --after-each 0.4 --stop-on-anomaly --log captures/rcp-direct-p2-00-0f-cmd-20-3f.txt
```
### 2026-05-13 Direct Command Sweep Response Hit
Capture:
- `captures/rcp-direct-cmd-00-ff.txt`
Sweep shape:
- `p1=0x00`
- `p2=0x00`
- `cmd=0x00-0xFF`
- `state=0x00`
- `value=0x80`
- Stop on first raw RX anomaly.
Important result:
- The sweep stopped immediately after transmitting command `0xB5`:
`00 00 B5 00 80 6F`.
- The previous transmitted command was `0xB4`: `00 00 B4 00 80 6E`, about
0.6 seconds earlier.
- The RCP produced repeated non-heartbeat frames:
`07 80 6D 20 D8 48`.
- Final raw capture showed the same frame repeated, then the panel returned to
the normal heartbeat `00 00 00 00 80 DA`.
Observed response:
```text
07 80 6D 20 D8 48
07 80 6D 20 D8 48
07 80 6D 20 D8 48
...
00 00 00 00 80 DA
```
Checksum check:
- `5A xor 07 xor 80 xor 6D xor 20 xor D8 = 48`.
- This means `07 80 6D 20 D8 48` is a real checksum-valid 6-byte frame under the
current checksum hypothesis, not a shifted heartbeat artifact.
Interpretation:
- This is the first confirmed non-heartbeat RCP-to-host serial response on pin
4 during host-frame probing.
- `cmd=0xB5` is the most likely trigger, but `cmd=0xB4` should be retested
because it was sent one read window earlier and delayed responses are possible.
- The response frame shape suggests the RCP may be reporting a status or
identity-like frame with `p1=0x07`, `p2=0x80`, `cmd=0x6D`, `state=0x20`,
`value=0xD8`.
Recommended confirmation tests:
```powershell
python scripts/serial_probe_response.py --port COM5 --tx-frame "00 00 B4 00 80 6E" --repeat 1 --delay 1.5 --after 5 --frame-size 0 --log captures/rcp-confirm-cmd-b4-raw.txt
python scripts/serial_probe_response.py --port COM5 --tx-frame "00 00 B5 00 80 6F" --repeat 1 --delay 1.5 --after 5 --frame-size 0 --log captures/rcp-confirm-cmd-b5-raw.txt
python scripts/serial_probe_response.py --port COM5 --tx-frame "00 00 B6 00 80 6C" --repeat 1 --delay 1.5 --after 5 --frame-size 0 --log captures/rcp-confirm-cmd-b6-raw.txt
```
If `cmd=0xB5` reliably triggers the `07 80 6D 20 D8 48` response, test whether
the response depends on the state/value fields:
```powershell
python scripts/serial_probe_matrix.py --port COM5 --commands 0xB5 --states "0x00 0x80" --values "0x00 0x80" --after-each 1.2 --prompt-screen --log captures/rcp-matrix-cmd-b5-state-value.txt
```
### 2026-05-13 B4/B5/B6 Single-Frame Confirmation
Captures:
- `captures/rcp-confirm-cmd-b4-raw.txt`
- `captures/rcp-confirm-cmd-b5-raw.txt`
- `captures/rcp-confirm-cmd-b6-raw.txt`
Single frames tested:
| Command | TX frame | Pin 4 result |
| ---: | --- | --- |
| `0xB4` | `00 00 B4 00 80 6E` | heartbeat only |
| `0xB5` | `00 00 B5 00 80 6F` | heartbeat only |
| `0xB6` | `00 00 B6 00 80 6C` | heartbeat only |
Interpretation:
- The earlier `07 80 6D 20 D8 48` response did not reproduce from isolated
single-frame `B4`, `B5`, or `B6` tests.
- The response may require prior sweep history, a command sequence, repeated
cadence, or a temporary parser/session state produced by many earlier frames.
- The `B5` frame is still the best suspect because the direct sweep reported the
anomaly in the read window immediately after transmitting `B5`, but it is not
sufficient by itself in a fresh single-frame test.
Recommended focused replay:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB8" --states 0x00 --values 0x80 --after-each 0.6 --stop-on-anomaly --log captures/rcp-direct-cmd-b0-b8-replay.txt
```
If that does not reproduce the response, try the same range with a shorter
cadence to better mimic the long sweep:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB8" --states 0x00 --values 0x80 --after-each 0.25 --stop-on-anomaly --log captures/rcp-direct-cmd-b0-b8-fast.txt
```
If the focused range still does not reproduce it, rerun the longer sweep from
`0xA0-0xB8` rather than the full `0x00-0xFF` range:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xA0-0xB8" --states 0x00 --values 0x80 --after-each 0.6 --stop-on-anomaly --log captures/rcp-direct-cmd-a0-b8-replay.txt
```
### 2026-05-13 B0-B8 Focused Replay Hit
Capture:
- `captures/rcp-direct-cmd-b0-b8-replay.txt`
Replay shape:
- `p1=0x00`
- `p2=0x00`
- `cmd=0xB0-0xB8`
- `state=0x00`
- `value=0x80`
- `after-each=0.6`
- Stop on first raw RX anomaly.
Important result:
- The sweep sent `cmd=0xB0`, then `cmd=0xB1`.
- The anomaly was captured in the read window immediately after transmitting
`cmd=0xB1`: `00 00 B1 00 80 6B`.
- The RCP emitted one checksum-valid non-heartbeat frame:
`07 80 6C 20 D8 49`.
- The final read window returned to heartbeat-only traffic.
Checksum check:
- `5A xor 07 xor 80 xor 6C xor 20 xor D8 = 49`.
Comparison with the earlier full sweep hit:
| Trigger window | RCP response |
| --- | --- |
| After `cmd=0xB1` in focused `B0-B8` replay | `07 80 6C 20 D8 49` |
| After `cmd=0xB5` in full `00-FF` sweep | `07 80 6D 20 D8 48` |
Interpretation:
- The non-heartbeat response is reproducible with a short local sequence, so it
does not require the entire `0x00-0xFF` sweep history.
- The response may be sequence-dependent: `B1` alone is not yet proven as the
trigger because `B0` was sent one window earlier.
- The response command byte changed from `0x6D` to `0x6C`, which suggests the
RCP may be returning a status/identity code related to the host command or to
internal state.
Recommended tight confirmations:
```powershell
python scripts/serial_probe_response.py --port COM5 --tx-frame "00 00 B0 00 80 6A" --repeat 1 --delay 1.5 --after 5 --frame-size 0 --log captures/rcp-confirm-cmd-b0-raw.txt
python scripts/serial_probe_response.py --port COM5 --tx-frame "00 00 B1 00 80 6B" --repeat 1 --delay 1.5 --after 5 --frame-size 0 --log captures/rcp-confirm-cmd-b1-raw.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB1" --states 0x00 --values 0x80 --after-each 0.6 --stop-on-anomaly --log captures/rcp-direct-cmd-b0-b1-replay.txt
```
If `B1` alone is heartbeat-only but `B0-B1` reproduces the response, treat
`B0 -> B1` as a required two-frame sequence.
### 2026-05-13 B0/B1 Tight Confirmation Result
Captures:
- `captures/rcp-confirm-cmd-b0-raw.txt`
- `captures/rcp-confirm-cmd-b1-raw.txt`
- `captures/rcp-direct-cmd-b0-b1-replay.txt`
Results:
| Test | Pin 4 result |
| --- | --- |
| Single `B0`: `00 00 B0 00 80 6A` | heartbeat only |
| Single `B1`: `00 00 B1 00 80 6B` | heartbeat only |
| Sequence `B0 -> B1` | heartbeat only, `Anomalies: 0` |
Interpretation:
- The `07 80 6C 20 D8 49` response from the `B0-B8` replay did not reproduce
with the minimal `B0 -> B1` sequence.
- The response may be intermittent, cadence-sensitive, dependent on a longer
sequence such as `B0-B8`, or affected by panel state that was not identical
between runs.
- The next priority is measuring reproducibility of the same short range rather
than expanding the search space.
Recommended reproducibility test:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB8" --states 0x00 --values 0x80 --after-each 0.6 --cycles 5 --cycle-pause 2 --log captures/rcp-direct-cmd-b0-b8-cycles.txt
```
Run this without `--stop-on-anomaly` so all five cycles complete and the log can
show whether the response happens consistently, intermittently, or only once.
### Power-Cycle Isolation Test Plan
Use this plan when intentionally power-cycling the RCP between tests. The goal
is to distinguish a cold-boot reproducible protocol response from a response
that only appears after accumulated parser/session state.
Before each test:
1. Stop any serial script.
2. Power off the RCP.
3. Wait at least 5 seconds.
4. Power on the RCP.
5. Wait until the panel is stable and heartbeat traffic has resumed.
6. Run exactly one test command.
Keep the wiring and series resistor the same between tests unless the test name
explicitly says otherwise.
#### Set A: Cold-Boot Reproducibility
Run these first. They test whether the `B0-B8` response is repeatable from a
fresh power cycle.
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB8" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-a1-b0-b8.txt
```
Power-cycle, then:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB8" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-a2-b0-b8.txt
```
Power-cycle, then:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB8" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-a3-b0-b8.txt
```
Expected useful outcomes:
- If all three produce the same response, the sequence is cold-boot
reproducible.
- If only some produce a response, the behavior may be timing-sensitive or
intermittent.
- If none produce a response, the earlier hit likely depended on prior panel
state.
#### Set B: Minimum Sequence Length
Run this set only if Set A produces at least one response. Power-cycle between
each command. These tests find the shortest command prefix that can trigger a
non-heartbeat response.
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB1" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-b1-b0-b1.txt
```
Power-cycle, then:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB2" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-b2-b0-b2.txt
```
Power-cycle, then:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB3" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-b3-b0-b3.txt
```
Power-cycle, then:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB4" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-b4-b0-b4.txt
```
#### Set C: Cadence Sensitivity
Run this set if Set A is inconsistent or if Set B does not identify a clean
minimum sequence. Power-cycle between each command.
Slow cadence:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB8" --states 0x00 --values 0x80 --settle 3 --after-each 1.2 --stop-on-anomaly --log captures/rcp-powercycle-c1-b0-b8-slow.txt
```
Fast cadence:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB8" --states 0x00 --values 0x80 --settle 3 --after-each 0.25 --stop-on-anomaly --log captures/rcp-powercycle-c2-b0-b8-fast.txt
```
Very fast cadence:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB8" --states 0x00 --values 0x80 --settle 3 --after-each 0.1 --stop-on-anomaly --log captures/rcp-powercycle-c3-b0-b8-very-fast.txt
```
#### Set D: Control Tests
Run these if the `B0-B8` range is producing responses. Power-cycle between
each command. These confirm the response is specific to the `B0` range.
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xA8-0xAF" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-d1-a8-af-control.txt
```
Power-cycle, then:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB8-0xBF" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-d2-b8-bf-control.txt
```
If a response appears in control ranges too, the trigger may be a broader
command class rather than a specific `B0-B8` sequence.
### 2026-05-13 Power-Cycle Set A Result
Captures:
- `captures/rcp-powercycle-a1-b0-b8.txt`
- `captures/rcp-powercycle-a2-b0-b8.txt`
- `captures/rcp-powercycle-a3-b0-b8.txt`
Each run was performed after a panel power cycle. All three runs produced the
same non-heartbeat response.
| Run | Trigger window | RCP response | Result |
| --- | --- | --- | --- |
| A1 | after `B1`: `00 00 B1 00 80 6B` | `07 80 6C 20 D8 49` repeated | anomaly |
| A2 | after `B1`: `00 00 B1 00 80 6B` | `07 80 6C 20 D8 49` repeated | anomaly |
| A3 | after `B1`: `00 00 B1 00 80 6B` | `07 80 6C 20 D8 49` repeated | anomaly |
Observed raw pattern in each run:
```text
07 80 6C 20 D8 49
07 80 6C 20 D8 49
07 80 6C 20 D8 49
...
00 00 00 00 80 DA
```
Interpretation:
- The `B0-B8` response is cold-boot reproducible.
- The response appears immediately after the `B1` transmit window when the test
starts from a fresh power cycle.
- The earlier `B0 -> B1` heartbeat-only result was likely affected by panel
state from previous experiments, timing, or not starting from an equivalent
cold condition.
- The next test should determine whether `B0 -> B1` is sufficient from a fresh
power cycle, or whether the script/test context of the `B0-B8` run matters.
Recommended next power-cycle tests:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB1" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-b1-b0-b1.txt
```
Power-cycle, then:
```powershell
python scripts/serial_probe_response.py --port COM5 --tx-frame "00 00 B1 00 80 6B" --repeat 1 --delay 3 --after 5 --frame-size 0 --log captures/rcp-powercycle-b1-alone-raw.txt
```
If `B0-B1` reproduces but `B1` alone does not, treat `B0 -> B1` as the minimum
cold-boot sequence.
### 2026-05-13 Minimum Cold-Boot Sequence Result
Captures:
- `captures/rcp-powercycle-b0.txt`
- `captures/rcp-powercycle-b1-b0-b1.txt`
- `captures/rcp-powercycle-b1-alone-raw.txt`
Each test was run after a panel power cycle.
| Test | TX frame(s) | Pin 4 result |
| --- | --- | --- |
| `B0` alone | `00 00 B0 00 80 6A` | heartbeat only, `Anomalies: 0` |
| `B1` alone | `00 00 B1 00 80 6B` | heartbeat only |
| `B0 -> B1` | `00 00 B0 00 80 6A`, then `00 00 B1 00 80 6B` | `07 80 6C 20 D8 49` repeated |
Conclusion:
- The minimum confirmed cold-boot trigger is the two-frame sequence:
```text
Host -> RCP: 00 00 B0 00 80 6A
Host -> RCP: 00 00 B1 00 80 6B
RCP -> Host: 07 80 6C 20 D8 49
```
- Neither `B0` nor `B1` is sufficient alone from a cold panel.
- `B0` appears to prime the panel, and `B1` completes the query/trigger.
- The response repeats for a short period, then the panel returns to the normal
heartbeat `00 00 00 00 80 DA`.
Recommended next tests:
1. Timing sensitivity between `B0` and `B1`.
2. State/value sensitivity of the `B0 -> B1` pair.
3. Whether the response changes when sending nearby pairs such as `B1 -> B2`,
`B2 -> B3`, etc.
Suggested timing tests, with power cycle between each:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB1" --states 0x00 --values 0x80 --settle 3 --after-each 0.1 --stop-on-anomaly --log captures/rcp-powercycle-timing-b0-b1-100ms.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0-0xB1" --states 0x00 --values 0x80 --settle 3 --after-each 1.2 --stop-on-anomaly --log captures/rcp-powercycle-timing-b0-b1-1200ms.txt
```
Suggested nearby-pair tests, with power cycle between each:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB1-0xB2" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-b1-b2.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB2-0xB3" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-b2-b3.txt
```
### 2026-05-13 B0-B1 Timing Result
Captures:
- `captures/rcp-powercycle-timing-b0-b1-100ms.txt`
- `captures/rcp-powercycle-timing-b0-b1-1200ms.txt`
Each test was run after a panel power cycle.
| B0-to-B1 spacing | RCP response |
| ---: | --- |
| about 100 ms | `07 80 6C 20 D8 49` |
| about 1200 ms | `07 80 6C 20 D8 49` repeated |
Interpretation:
- The `B0 -> B1` trigger is not tightly timing-sensitive across the tested
range.
- `B0` appears to prime a state that remains valid for at least about 1.2
seconds.
- The sequence order is more important than exact short timing.
Recommended next tests:
Power-cycle between each test. Check whether the trigger is specific to the
`B0 -> B1` pair or whether nearby ordered pairs also trigger related responses:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB1-0xB2" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-b1-b2.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB2-0xB3" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-b2-b3.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xAF-0xB0" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-af-b0.txt
```
### 2026-05-13 Nearby Pair Results
Captures:
- `captures/rcp-powercycle-pair-af-b0.txt`
- `captures/rcp-powercycle-pair-b1-b2.txt`
- `captures/rcp-powercycle-pair-b2-b3.txt`
Each test was run after a panel power cycle.
| Host pair | Second frame window | RCP response |
| --- | --- | --- |
| `AF -> B0` | `00 00 B0 00 80 6A` | `07 80 6C 60 30 E1` repeated |
| `B1 -> B2` | `00 00 B2 00 80 68` | `07 80 36 10 0C F7` repeated |
| `B2 -> B3` | `00 00 B3 00 80 69` | `07 80 36 10 2C D7` repeated |
Previously confirmed:
| Host pair | Second frame window | RCP response |
| --- | --- | --- |
| `B0 -> B1` | `00 00 B1 00 80 6B` | `07 80 6C 20 D8 49` repeated |
Checksum checks:
- `07 80 6C 60 30 E1`: checksum valid.
- `07 80 36 10 0C F7`: checksum valid.
- `07 80 36 10 2C D7`: checksum valid.
Interpretation:
- The RCP responds to multiple adjacent two-frame host sequences in the
`AF-B3` region, not only `B0 -> B1`.
- The response appears in the read window after the second frame of each pair.
- The response payload changes by pair, which suggests these are real command
queries or status reads rather than a generic link-present acknowledgement.
- The repeated response pattern still returns to the normal heartbeat afterward.
Emerging map:
| Host sequence | RCP response fields |
| --- | --- |
| `AF -> B0` | `p1=07 p2=80 cmd=6C state=60 value=30 checksum=E1` |
| `B0 -> B1` | `p1=07 p2=80 cmd=6C state=20 value=D8 checksum=49` |
| `B1 -> B2` | `p1=07 p2=80 cmd=36 state=10 value=0C checksum=F7` |
| `B2 -> B3` | `p1=07 p2=80 cmd=36 state=10 value=2C checksum=D7` |
Recommended next tests:
Power-cycle between each. First continue the adjacent-pair map:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB3-0xB4" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-b3-b4.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB4-0xB5" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-b4-b5.txt
```
Then test whether adjacency and order matter:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB0 0xB2" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-b0-b2-skip.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB1 0xB0" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-b1-b0-reverse.txt
```
### 2026-05-13 Additional Pair/Control Results
User observation:
- All tests still showed `CONNECT NOT ACT` on the RCP/CCU screen, with no other
visible state change.
Serial captures:
- `captures/rcp-powercycle-pair-b3-b4.txt`
- `captures/rcp-powercycle-pair-b4-b5.txt`
- `captures/rcp-powercycle-pair-b0-b2-skip.txt`
- `captures/rcp-powercycle-pair-b1-b0-reverse.txt`
Each test was run after a panel power cycle.
| Host pair | Second frame window | RCP response |
| --- | --- | --- |
| `B3 -> B4` | `00 00 B4 00 80 6E` | `07 80 6D 40 30 C0` repeated |
| `B4 -> B5` | `00 00 B5 00 80 6F` | `07 80 6D 20 D8 48` repeated |
| `B0 -> B2` | `00 00 B2 00 80 68` | `07 80 36 10 0C F7` repeated |
| `B1 -> B0` | `00 00 B0 00 80 6A` | `07 80 6C 40 30 C1` repeated |
Interpretation:
- The screen state remains `CONNECT NOT ACT`, but pin 4 responses are changing
in a structured, checksum-valid way.
- The skip test `B0 -> B2` produced the same response as `B1 -> B2`, so the
second command may be the main selector once any valid priming frame is sent.
- The reverse test `B1 -> B0` also produced a valid response, so strict
ascending adjacency is not required.
- Current model: a first host frame primes/enters a response mode, and the
second host frame selects a status/query response.
Expanded observed response map:
| Second host command | Observed response(s) |
| ---: | --- |
| `B0` | `07 80 6C 60 30 E1` after `AF -> B0`; `07 80 6C 40 30 C1` after `B1 -> B0` |
| `B1` | `07 80 6C 20 D8 49` after `B0 -> B1` |
| `B2` | `07 80 36 10 0C F7` after `B1 -> B2` and `B0 -> B2` |
| `B3` | `07 80 36 10 2C D7` after `B2 -> B3` |
| `B4` | `07 80 6D 40 30 C0` after `B3 -> B4` |
| `B5` | `07 80 6D 20 D8 48` after `B4 -> B5` |
Recommended next tests:
Power-cycle between each. Test whether a generic primer plus selected second
command is enough:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB0" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-primer-00-b0.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB2" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-primer-00-b2.txt
```
Then map the next selected second commands:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB5-0xB6" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-b5-b6.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0xB6-0xB7" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-pair-b6-b7.txt
```
### 2026-05-13 Generic Primer and B6-B7 Results
Captures:
- `captures/rcp-powercycle-primer-00-b0.txt`
- `captures/rcp-powercycle-primer-00-b2.txt`
- `captures/rcp-powercycle-pair-b5-b6.txt`
- `captures/rcp-powercycle-pair-b6-b7.txt`
Each test was run after a panel power cycle.
| Host pair | Second frame window | RCP response |
| --- | --- | --- |
| `00 -> B0` | `00 00 B0 00 80 6A` | `07 80 6C 40 30 C1` repeated |
| `00 -> B2` | `00 00 B2 00 80 68` | `07 80 36 10 0C F7` repeated |
| `B5 -> B6` | `00 00 B6 00 80 6C` | `07 80 1B 08 C6 08` repeated |
| `B6 -> B7` | `00 00 B7 00 80 6D` | `07 80 1B 08 D6 18` repeated |
Checksum checks:
- `07 80 6C 40 30 C1`: checksum valid.
- `07 80 36 10 0C F7`: checksum valid.
- `07 80 1B 08 C6 08`: checksum valid.
- `07 80 1B 08 D6 18`: checksum valid.
Interpretation:
- `00 -> B0` produced the same response as `B1 -> B0`.
- `00 -> B2` produced the same response as `B0 -> B2` and `B1 -> B2`.
- This supports the model that the first frame can be a generic valid primer,
and the second frame selects the response.
- The `B6` and `B7` selected responses introduce another response command class
(`cmd=0x1B`) with changing value bytes.
Updated selected-command map:
| Selected second command | Observed response |
| ---: | --- |
| `B0` | `07 80 6C 40 30 C1` after `00 -> B0` and `B1 -> B0`; `07 80 6C 60 30 E1` after `AF -> B0` |
| `B1` | `07 80 6C 20 D8 49` after `B0 -> B1` |
| `B2` | `07 80 36 10 0C F7` after `00 -> B2`, `B0 -> B2`, and `B1 -> B2` |
| `B3` | `07 80 36 10 2C D7` after `B2 -> B3` |
| `B4` | `07 80 6D 40 30 C0` after `B3 -> B4` |
| `B5` | `07 80 6D 20 D8 48` after `B4 -> B5` |
| `B6` | `07 80 1B 08 C6 08` after `B5 -> B6` |
| `B7` | `07 80 1B 08 D6 18` after `B6 -> B7` |
Recommended next controls:
Power-cycle between each. First prove whether `B2`, `B6`, and `B7` need a
primer, or whether they can respond as single frames from cold boot:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands 0xB2 --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-single-b2.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands 0xB6 --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-single-b6.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands 0xB7 --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-single-b7.txt
```
Then continue the selected-command map using `00` as the primer:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB3" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-primer-00-b3.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB4" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-primer-00-b4.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB5" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-primer-00-b5.txt
```
### 2026-05-13 Single-Frame and One-Shot Primer Results
Captures:
- `captures/rcp-powercycle-single-b2.txt`
- `captures/rcp-powercycle-single-b6.txt`
- `captures/rcp-powercycle-single-b7.txt`
- `captures/rcp-powercycle-primer-00-b3.txt`
- `captures/rcp-powercycle-primer-00-b4.txt`
- `captures/rcp-powercycle-primer-00-b5.txt`
Single-frame controls, each after a panel power cycle:
| Test | Pin 4 result |
| --- | --- |
| `B2` alone | heartbeat only, `Anomalies: 0` |
| `B6` alone | heartbeat only, `Anomalies: 0` |
| `B7` alone | heartbeat only, `Anomalies: 0` |
Generic-primer map, each first run after a panel power cycle:
| Host pair | Second frame window | RCP response |
| --- | --- | --- |
| `00 -> B3` | `00 00 B3 00 80 69` | `07 80 36 10 2C D7` repeated |
| `00 -> B4` | `00 00 B4 00 80 6E` | `07 80 6D 40 30 C0` |
| `00 -> B5` | `00 00 B5 00 80 6F` | `07 80 6D 20 D8 48` repeated |
Repeated `00 -> B5` without power-cycling:
| Attempt | Power cycle before attempt? | Result |
| ---: | --- | --- |
| 1 | yes | `07 80 6D 20 D8 48` repeated |
| 2 | no | heartbeat only, `Anomalies: 0` |
| 3 | no | heartbeat only, `Anomalies: 0` |
Interpretation:
- A single selected command is not enough; the panel requires a preceding valid
primer frame.
- `00` works as a primer for `B0`, `B2`, `B3`, `B4`, and `B5`.
- The same primed query may be one-shot after power-up. After `00 -> B5`
returns its response, repeating `00 -> B5` without power-cycling does not
produce another non-heartbeat response.
- Future mapping should power-cycle before each selected-command test unless
intentionally studying latch/repeat behavior.
Current generic-primer selected-command map:
| Host query | RCP response |
| --- | --- |
| `00 -> B0` | `07 80 6C 40 30 C1` |
| `00 -> B2` | `07 80 36 10 0C F7` |
| `00 -> B3` | `07 80 36 10 2C D7` |
| `00 -> B4` | `07 80 6D 40 30 C0` |
| `00 -> B5` | `07 80 6D 20 D8 48` |
Recommended next tests:
Power-cycle before each query. Fill the missing `00 -> B1` entry and continue
the `00 -> selected` map:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB1" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-primer-00-b1.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB6" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-primer-00-b6.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB7" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --stop-on-anomaly --log captures/rcp-powercycle-primer-00-b7.txt
```
Optional latch test, without power-cycling after the first run:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB5" --states 0x00 --values 0x80 --settle 3 --after-each 0.6 --cycles 3 --cycle-pause 2 --log captures/rcp-latch-primer-00-b5-cycles.txt
```
## Current Inferred Behavior
The current evidence suggests the RCP is entering a discovery/query/status-read
phase, not a completed active-control handshake.
Working model:
```text
Host/CCU -> RCP: valid primer frame
Host/CCU -> RCP: selected query/status command
RCP -> Host/CCU: checksum-valid response frame repeated briefly
RCP -> Host/CCU: returns to heartbeat
```
Important details:
- Single selected commands such as `B2`, `B6`, and `B7` do not respond from a
cold panel.
- A preceding valid frame is required. `00 00 00 00 80 DA` works as a generic
primer for several selected commands.
- The second command selects the response payload.
- The LCD can remain `CONNECT NOT ACT` while serial responses vary in a
structured way. Serial response does not yet mean the active control session
is accepted.
- At least some primed queries appear one-shot after power-up. Repeating the
same primed query without power-cycling can produce only heartbeat traffic.
Likely protocol role:
- These `B0`-range commands may be a CCU discovery or capability/status query
phase.
- The CCU may query RCP model/capability/state blocks before sending a later
activation/session command.
- The next unknown is the command or command sequence that follows these
discovery responses and moves the panel from `CONNECT NOT ACT` to active.
## Primer-Candidate Broad Sweep
Use `scripts/serial_primer_candidate_sweep.py` for broader searches based on
the current primer/query model. It sends:
```text
primer frame -> candidate frame -> raw RX classification
```
For clean mapping, use `--prompt-power-cycle` and power-cycle before each
candidate. This avoids the one-shot/latch behavior contaminating later
candidates.
Example dry run:
```powershell
python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0xB0-0xB7" --dry-run
```
Continue the known `B` range first:
```powershell
python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0xB1 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF" --prompt-power-cycle --stop-on-anomaly --log captures/rcp-primer-sweep-b1-bf.txt
```
Because `--stop-on-anomaly` stops at the first response, after each hit:
1. Save the reported candidate and response frame.
2. Power-cycle the panel.
3. Restart the sweep from the next unmapped candidate.
For non-stop mapping, omit `--stop-on-anomaly`, but still power-cycle at each
prompt:
```powershell
python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0xB8-0xBF" --prompt-power-cycle --log captures/rcp-primer-sweep-b8-bf.txt
```
Suggested broad ranges after `B0-BF`:
```powershell
python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0xA0-0xAF" --prompt-power-cycle --log captures/rcp-primer-sweep-a0-af.txt
python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0xC0-0xCF" --prompt-power-cycle --log captures/rcp-primer-sweep-c0-cf.txt
python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0x00-0x1F" --prompt-power-cycle --log captures/rcp-primer-sweep-00-1f.txt
```
Recommended first run:
```powershell
python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0xB1 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF" --prompt-power-cycle --log captures/rcp-primer-sweep-b1-bf.txt
```
## Primer Reuse and Sequential Query Tests
Two open questions:
1. After a cold boot, does the RCP only answer one selected query before it
latches/suppresses further responses?
2. Is a fresh primer required before every selected query, or can one primer
unlock several selected commands in sequence?
Use `scripts/serial_direct_response_sweep.py` for these tests because it can
send arbitrary command sequences without stopping between commands. For each
test below, power-cycle once before starting the script, then do not power-cycle
again until the script exits.
### Test S1: One Primer, Multiple Different Queries
Purpose: test whether one primer can unlock several different selected commands.
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB2 0xB3 0xB4 0xB5" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --log captures/rcp-seq-one-primer-b2-b5.txt
```
Interpretation:
- If only `B2` responds, the panel likely allows one selected response per
cold-boot/primer state.
- If `B2`, `B3`, `B4`, and `B5` all respond, one primer can unlock multiple
sequential queries.
- If some respond and some do not, there may be command-group or latch behavior.
### Test S2: Primer Before Every Query, No Power Cycle
Purpose: test whether a new primer can re-arm another selected query without
power-cycling.
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB2 0x00 0xB3 0x00 0xB4 0x00 0xB5" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --log captures/rcp-seq-reprimer-b2-b5.txt
```
Interpretation:
- If every selected command responds, a primer is required before each query but
power-cycling is not.
- If only the first selected command responds, power-cycle or another reset-like
command may be required to clear the latch.
### Test S3: Repeat Same Query With and Without Reprimer
Purpose: test whether the same selected query can be repeated in one powered
session.
Without re-primer:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB5 0xB5 0xB5" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --log captures/rcp-seq-repeat-b5-no-reprimer.txt
```
Power-cycle, then with re-primer:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB5 0x00 0xB5 0x00 0xB5" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --log captures/rcp-seq-repeat-b5-reprimer.txt
```
Interpretation:
- If only the first `B5` responds in both tests, the response is one-shot until
power cycle or a yet-unknown reset/ack command.
- If the re-primer version responds repeatedly, the primer re-arms the selected
query.
### 2026-05-13 Sequential Query Test Result
Captures:
- `captures/rcp-seq-one-primer-b2-b5.txt`
- `captures/rcp-seq-reprimer-b2-b5.txt`
- `captures/rcp-seq-repeat-b5-no-reprimer.txt`
- `captures/rcp-seq-repeat-b5-reprimer.txt`
Valid result:
| Test | Intended sequence | Actual sequence sent | Result |
| --- | --- | --- | --- |
| S1 | `00 -> B2 -> B3 -> B4 -> B5` | `00 -> B2 -> B3 -> B4 -> B5` | only `B2` responded: `07 80 36 10 0C F7` |
Tooling caveat:
- The original `serial_direct_response_sweep.py` de-duplicated command lists.
- Because of that, sequences containing repeated commands did not run as
intended.
- `S2`, `S3 no re-primer`, and `S3 re-primer` need to be rerun after the
script fix.
- The script has been updated to preserve repeated command values in explicit
command lists.
Interpretation from S1:
- One primer did not unlock a whole list of feature/status queries.
- After `00 -> B2` returned `07 80 36 10 0C F7`, later `B3`, `B4`, and `B5`
in the same powered session did not produce additional non-heartbeat frames.
- This supports a one-response latch model unless the re-primer test proves that
the primer can re-arm another query.
Rerun these tests after the script fix:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB2 0x00 0xB3 0x00 0xB4 0x00 0xB5" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --log captures/rcp-seq-reprimer-b2-b5-v2.txt
```
Power-cycle, then:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB5 0xB5 0xB5" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --log captures/rcp-seq-repeat-b5-no-reprimer-v2.txt
```
Power-cycle, then:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0xB5 0x00 0xB5 0x00 0xB5" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --log captures/rcp-seq-repeat-b5-reprimer-v2.txt
```
### 2026-05-13 Sequential Query Rerun Result
Captures:
- `captures/rcp-seq-reprimer-b2-b5-v2.txt`
- `captures/rcp-seq-repeat-b5-no-reprimer-v2.txt`
- `captures/rcp-seq-repeat-b5-reprimer-v2.txt`
These reruns used the fixed `serial_direct_response_sweep.py`, which preserves
repeated command values in explicit sequences.
Results:
| Test | Sequence | Non-heartbeat response(s) |
| --- | --- | --- |
| Re-primer between different queries | `00 -> B2 -> 00 -> B3 -> 00 -> B4 -> 00 -> B5` | only `B2`: `07 80 36 10 0C F7` |
| Repeat `B5`, no re-primer | `00 -> B5 -> B5 -> B5` | only first `B5`: `07 80 6D 20 D8 48` |
| Repeat `B5`, re-primer each time | `00 -> B5 -> 00 -> B5 -> 00 -> B5` | only first `B5`: `07 80 6D 20 D8 48` |
Interpretation:
- The RCP appears to allow only one selected query response per powered session
in the current `CONNECT NOT ACT` state.
- Sending another primer (`00 00 00 00 80 DA`) after the first response does not
re-arm the query responder.
- Repeating the same selected query does not produce another response.
- This strongly suggests a one-shot discovery/status response followed by a
required next-stage command, acknowledgement, reset, or activation step.
Implication for CCU behavior:
- The CCU may not scan a list of feature queries in the current state. It may
send one discovery/status query, receive one response, then decide what
activation/session command to send next.
- Alternatively, additional feature reads may require an acknowledgement or
state-advance command that has not yet been identified.
Recommended next direction:
- Stop broad feature scanning for the moment.
- Search for the post-discovery acknowledgement/activation command that follows
one known response such as `00 -> B5 => 07 80 6D 20 D8 48`.
- Use a three-step pattern:
```text
primer -> selected query -> candidate activation/ack command
```
Known reproducible setup:
```text
Host -> RCP: 00 00 00 00 80 DA
Host -> RCP: 00 00 B5 00 80 6F
RCP -> Host: 07 80 6D 20 D8 48
Host -> RCP: candidate next-stage command
```
## Post-Discovery Candidate Sweep
Use `scripts/serial_post_discovery_sweep.py` to search for the command that
comes after one known discovery/status response. This is the likely next stage
after the one-shot response behavior.
Default setup:
```text
primer: 00 00 00 00 80 DA
query: 00 00 B5 00 80 6F
RCP: 07 80 6D 20 D8 48
then: candidate next-stage command
```
Recommended first post-discovery sweep:
```powershell
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0x00-0x1F" --prompt-power-cycle --prompt-screen --log captures/rcp-post-discovery-b5-candidates-00-1f.txt
```
For each candidate:
1. Power-cycle the RCP.
2. Wait for heartbeat/panel stable.
3. Press Enter at the prompt.
4. Watch for any screen change after the candidate frame.
5. Type the screen state if it changes, or press Enter for no visible change.
Why this range first:
- Earlier frame-length tests showed small command values can change screen state
to `CONNECT NOT ACT`.
- If a simple ACK/activation command exists, it may be in the low command range.
Next ranges if `00-1F` does not change state:
```powershell
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0x20-0x3F" --prompt-power-cycle --prompt-screen --log captures/rcp-post-discovery-b5-candidates-20-3f.txt
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0x80-0x9F" --prompt-power-cycle --prompt-screen --log captures/rcp-post-discovery-b5-candidates-80-9f.txt
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0xB0-0xBF" --prompt-power-cycle --prompt-screen --log captures/rcp-post-discovery-b5-candidates-b0-bf.txt
```
If any candidate changes the screen away from `CONNECT NOT ACT`, or produces a
new RCP response after the candidate stage, retest that candidate alone with
three fresh power cycles.
### 2026-05-13 Post-Discovery Sweep `00-1F` Result
Capture:
- `captures/rcp-post-discovery-b5-candidates-00-1f.txt`
Sweep setup:
```text
primer: 00 00 00 00 80 DA
query: 00 00 B5 00 80 6F
expected: 07 80 6D 20 D8 48
candidate: 00-1F
```
Screen result:
- Every candidate remained at `CONNECT NOT ACT` / `CONNECTION NOT ACT`.
- No candidate in `0x00-0x1F` moved the panel into an active state.
Serial result:
- Most candidates produced only heartbeat-compatible traffic after the candidate
frame.
- Candidate windows for `0x00`, `0x0E`, `0x0F`, `0x1A`, `0x1E`, and `0x1F`
included additional bytes matching the known discovery response
`07 80 6D 20 D8 48`.
- Those candidate-window anomalies are likely trailing/repeated discovery
response frames from the `B5` query, not new candidate-specific responses.
Notable outlier:
- During candidate `0x03`, the primer read window contained
`07 80 40 40 30 ED`, followed by heartbeat.
- This is checksum-valid, but it occurred before the `B5` query in that test
window. Treat it as an outlier until reproduced. Possible explanations include
incomplete power-cycle reset, a previous state/latch edge, or an accidental
timing artifact.
Interpretation:
- Low command range `0x00-0x1F` does not appear to contain the simple
post-discovery activation command when tested after the `B5` discovery query.
- The script's candidate read window can still catch residual discovery
response frames; candidate anomalies must be checked against the known query
response before treating them as new behavior.
Recommended next sweep:
Use a slightly longer query read window so the known discovery response has more
time to finish before the candidate frame:
```powershell
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0x20-0x3F" --after-query 2.0 --prompt-power-cycle --prompt-screen --log captures/rcp-post-discovery-b5-candidates-20-3f.txt
```
If `20-3F` also keeps the screen at `CONNECT NOT ACT`, continue:
```powershell
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0x80-0x9F" --after-query 2.0 --prompt-power-cycle --prompt-screen --log captures/rcp-post-discovery-b5-candidates-80-9f.txt
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0xB0-0xBF" --after-query 2.0 --prompt-power-cycle --prompt-screen --log captures/rcp-post-discovery-b5-candidates-b0-bf.txt
```
## Post-Discovery Test Ladder
Before manually sweeping every command byte, sample representative patterns from
several command regions. The goal is to identify which command families are
worth expanding.
Use the same known discovery setup for each sample:
```text
primer: 00 00 00 00 80 DA
query: 00 00 B5 00 80 6F
RCP: 07 80 6D 20 D8 48
then: sampled candidate command
```
Power-cycle before each candidate prompt. Type any screen change, otherwise
press Enter.
### Ladder 1: Low-Range Sanity Sample
The full `00-1F` sweep did not activate the panel, but one outlier appeared
during the `0x03` test. Retest only representative low bytes plus the outlier:
```powershell
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0x00 0x01 0x03 0x07 0x0F 0x10 0x1B 0x1F" --after-query 2.0 --prompt-power-cycle --prompt-screen --log captures/rcp-post-ladder-low-sample.txt
```
What this checks:
- `0x00`, `0x01`: no-op / ACK-like small commands.
- `0x03`: the outlier run produced `07 80 40 40 30 ED`.
- `0x07`, `0x0F`, `0x1F`: bit-mask/boundary values.
- `0x10`, `0x1B`: response command-family values observed in RCP frames.
### Ladder 2: Response-Command Echo Sample
Test host commands that match command bytes seen in RCP responses. If the CCU
acknowledges or advances using related command IDs, these are good candidates.
Observed RCP response command bytes so far:
```text
1B 36 40 6C 6D
```
Run:
```powershell
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0x1B 0x36 0x40 0x6C 0x6D" --after-query 2.0 --prompt-power-cycle --prompt-screen --log captures/rcp-post-ladder-response-cmds.txt
```
Expand only if one of these changes screen state or produces a new
candidate-stage response.
### Ladder 3: Boundary and Bit-Pattern Sample
This tests command bytes that often mark command classes, flags, or boundaries:
```powershell
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0x20 0x2F 0x30 0x3F 0x40 0x4F 0x50 0x5F 0x7F 0x80 0x8F 0x90 0x9F 0xA0 0xAF 0xB0 0xBF 0xC0 0xCF 0xE0 0xEF 0xF0 0xFF" --after-query 2.0 --prompt-power-cycle --prompt-screen --log captures/rcp-post-ladder-boundaries.txt
```
What this checks:
- Nibble/region boundaries.
- The high-bit transition at `0x80`.
- Known discovery query region around `0xB0`.
- High command space around `0xE0-0xFF`.
### Ladder 4: Known Query Region Sample
The `B0` range is known to produce discovery/status responses when used as the
selected query. It may also contain a next-stage command.
```powershell
python scripts/serial_post_discovery_sweep.py --port COM5 --candidates "0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7 0xB8 0xBF" --after-query 2.0 --prompt-power-cycle --prompt-screen --log captures/rcp-post-ladder-b-region.txt
```
If any `B` candidate changes behavior, expand locally around it rather than
sweeping the full byte space.
### Ladder 5: Alternate Discovery Response Bases
If all candidate ladders after `00 -> B5` leave the screen at `CONNECT NOT ACT`,
try the same sampled candidates after a different discovery query. Different RCP
responses may expect different follow-up ACKs.
Use `B2` discovery:
```powershell
python scripts/serial_post_discovery_sweep.py --port COM5 --query-command 0xB2 --candidates "0x00 0x01 0x1B 0x36 0x40 0x6C 0x6D 0x80 0xB0 0xB5 0xFF" --after-query 2.0 --prompt-power-cycle --prompt-screen --log captures/rcp-post-ladder-after-b2.txt
```
Use `B0` discovery:
```powershell
python scripts/serial_post_discovery_sweep.py --port COM5 --query-command 0xB0 --candidates "0x00 0x01 0x1B 0x36 0x40 0x6C 0x6D 0x80 0xB0 0xB5 0xFF" --after-query 2.0 --prompt-power-cycle --prompt-screen --log captures/rcp-post-ladder-after-b0.txt
```
Interpretation:
- If a candidate only works after one discovery response, the next-stage command
may depend on the returned block.
- If the same candidate works after multiple discovery responses, it is a
stronger activation/ACK candidate.
### When to Expand
Expand a region only when one of these occurs:
- Screen changes away from `CONNECT NOT ACT`.
- RCP sends a new candidate-stage frame that is not the known discovery response
trailing into the candidate window.
- The panel begins sending different heartbeat/status frames after the
candidate.
If none of the ladder samples produce a new behavior, stop command-byte guessing
and test other frame fields for the candidate stage: state byte, value byte, or
prefix bytes.
### 2026-05-13 Ladder 1 Result and Keepalive Hypothesis
Capture:
- `captures/rcp-post-ladder-low-sample.txt`
Ladder 1 candidates:
```text
00 01 03 07 0F 10 1B 1F
```
Result:
- Every sampled candidate left the screen at `CONNECT NOT ACT`.
- Candidate-stage RX was heartbeat-compatible for all candidates.
- The earlier `0x03` outlier did not reproduce.
- Query-stage response `07 80 6D 20 D8 48` reproduced reliably before each
candidate.
Interpretation:
- The low/outlier sample did not find a post-discovery activation/ACK command.
- `CONNECT NOT ACT` may be unrelated to a one-shot ACK. It may mean the RCP sees
host traffic but is not receiving the correct ongoing CCU heartbeat/session
cadence.
Alternative working model:
```text
Host sends discovery/status query
RCP answers once
Host must then send a sustained keepalive/session heartbeat
RCP remains CONNECT NOT ACT until that heartbeat/cadence is correct
```
### Keepalive After Discovery Tests
Use `scripts/serial_keepalive_after_query.py` to test whether a sustained host
heartbeat changes the RCP state after a known discovery response.
Default setup:
```text
primer: 00 00 00 00 80 DA
query: 00 00 B5 00 80 6F
RCP reply: 07 80 6D 20 D8 48
keepalive: repeated candidate frame
```
Test K1: repeat the known primer/heartbeat shape:
```powershell
python scripts/serial_keepalive_after_query.py --port COM5 --keepalive-command 0x00 --duration 15 --interval 0.6 --prompt-screen --log captures/rcp-keepalive-after-b5-cmd00-600ms.txt
```
Test K2: repeat the zero-state frame:
```powershell
python scripts/serial_keepalive_after_query.py --port COM5 --keepalive-frame "00 00 00 00 00 5A" --duration 15 --interval 0.6 --prompt-screen --log captures/rcp-keepalive-after-b5-zero-state-600ms.txt
```
Test K3: repeat the alternate state frame:
```powershell
python scripts/serial_keepalive_after_query.py --port COM5 --keepalive-frame "00 00 00 80 00 DA" --duration 15 --interval 0.6 --prompt-screen --log captures/rcp-keepalive-after-b5-state80-600ms.txt
```
Test K4: faster primer/heartbeat cadence:
```powershell
python scripts/serial_keepalive_after_query.py --port COM5 --keepalive-command 0x00 --duration 15 --interval 0.2 --prompt-screen --log captures/rcp-keepalive-after-b5-cmd00-200ms.txt
```
Power-cycle before each keepalive test. Watch for:
- Screen changing away from `CONNECT NOT ACT`.
- Pin 4 changing from heartbeat to another recurring status frame.
- RCP controls beginning to transmit additional button/status data.
### 2026-05-13 Keepalive After Discovery Result
Captures:
- `captures/rcp-keepalive-after-b5-cmd00-600ms.txt`
- `captures/rcp-keepalive-after-b5-zero-state-600ms.txt`
- `captures/rcp-keepalive-after-b5-state80-600ms.txt`
- `captures/rcp-keepalive-after-b5-cmd00-200ms.txt`
Result:
| Test | Keepalive frame | Cadence | Screen result | Pin 4 RX |
| --- | --- | --- | --- | --- |
| K1 | `00 00 00 00 80 DA` | 0.6 s | `CONNECT NOT ACT` | heartbeat-compatible |
| K2 | `00 00 00 00 00 5A` | 0.6 s | `CONNECT NOT ACT` | heartbeat-compatible |
| K3 | `00 00 00 80 00 DA` | 0.6 s | `CONNECT NOT ACT` | heartbeat-compatible |
| K4 | `00 00 00 00 80 DA` | 0.2 s | `CONNECT NOT ACT` | heartbeat-compatible |
Interpretation:
- A simple sustained host heartbeat after `00 -> B5` does not activate the RCP.
- The RCP continues emitting only the known heartbeat-compatible stream on pin
4 during these keepalive attempts.
- The correct next stage is probably not just "repeat the primer" or "hold a
no-op frame at CCU cadence".
- The better next branch is to map additional `primer -> request` commands that
cause one-shot RCP responses. Those response blocks may reveal the command
families, status bits, or identity data needed for the later activation step.
Recommended next request sweep:
```powershell
python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0xB1 0xB6 0xB7 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF" --prompt-power-cycle --log captures/rcp-primer-sweep-b1-bf.txt
```
Power-cycle before each candidate prompt. This fills the gaps around the known
`B0-B5` discovery/status region and checks whether `B8-BF` contain additional
one-shot readable blocks.
If this range is quiet, continue with neighboring command regions:
```powershell
python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0xA0-0xAF" --prompt-power-cycle --log captures/rcp-primer-sweep-a0-af.txt
python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0xC0-0xCF" --prompt-power-cycle --log captures/rcp-primer-sweep-c0-cf.txt
```
### 2026-05-13 Primer Sweep A/B/C Region Result
Captures:
- `captures/rcp-primer-sweep-a0-af.txt`
- `captures/rcp-primer-sweep-b1-bf.tx`
- `captures/rcp-primer-sweep-c0-cf.txt`
These sweeps used a fresh power cycle before each candidate, with the standard
primer shape before the selected request:
```text
primer: 00 00 00 00 80 DA
candidate: 00 00 CMD 00 80 CHECKSUM
```
New selected-command response map:
| Selected command | Observed RCP response |
| ---: | --- |
| `A0` | `07 80 68 40 30 C5` |
| `A1` | `07 80 68 20 D8 4D` |
| `A2` | `07 80 34 10 0C F5` |
| `A3` | `07 80 34 10 2C D5` |
| `A4` | `07 80 69 40 30 C4` |
| `A5` | `07 80 69 20 D8 4C` |
| `A6` | `07 80 1A 08 C6 09` |
| `A7` | `07 80 1A 08 D6 19` |
| `A8` | `07 80 6A 40 30 C7` |
| `A9` | `07 80 6A 20 D8 4F` |
| `AA` | `07 80 35 10 0C F4` |
| `AB` | `07 80 35 10 2C D4` |
| `AC` | `07 80 6B 40 30 C6` |
| `AD` | `07 80 6B 20 D8 4E` |
| `AE` | `07 80 0D 04 A3 77` |
| `AF` | `07 80 0D 04 AB 7F` |
| `B1` | `07 80 6C 20 D8 49` |
| `B6` | `07 80 1B 08 C6 08` |
| `B7` | `07 80 1B 08 F6 38` |
| `B8` | `07 80 EE 40 30 43` |
| `B9` | `07 80 6E 20 D8 4B` |
| `BA` | `07 80 37 10 0C F6` |
| `BB` | `07 80 37 10 2C D6` |
| `BC` | `07 80 EF 40 30 42` |
| `BD` | `07 80 6F 20 D8 4A` |
| `BE` | heartbeat only |
| `BF` | heartbeat only |
| `C0` | heartbeat only |
| `C1` | `07 80 70 20 D8 55` |
| `C2` | `07 80 38 10 0C F9` |
| `C3` | `07 80 38 10 2C D9` |
| `C4` | `07 80 71 40 30 DC` |
| `C5` | `07 80 71 20 D8 54` |
| `C6` | `07 80 1C 08 C6 0F` |
| `C7` | `07 80 1C 08 D6 1F` |
| `C8` | `07 80 72 40 30 DF` |
| `C9` | `07 80 72 20 D8 57` |
| `CA` | `07 80 39 10 0C F8` |
| `CB` | `07 80 39 10 2C D8` |
| `CC` | `07 80 F3 40 30 5E` |
| `CD` | `07 80 73 20 D8 56` |
| `CE` | `07 80 0E 04 A3 74` |
| `CF` | `07 80 0E 04 AB 7C` |
Interpretation:
- The RCP has a much larger one-shot readable status/query surface than first
assumed.
- The `A0-CF` region looks highly structured. Most commands return stable
six-byte responses with the same `07 80` prefix and valid XOR checksum.
- Pairs often share a response command byte and differ in state/value fields:
`A0/A1`, `A2/A3`, `A4/A5`, `A6/A7`, and similar patterns continue through
the `B` and `C` regions.
- `BE`, `BF`, and `C0` are current no-response candidates in this mapping.
- This strongly supports a discovery/status table model: the CCU may read a
specific set of one-shot blocks, then choose a later activation/session
command based on the returned table values.
### 2026-05-13 Paused Direct Sweep Result
Capture:
- `captures/rcp-direct-remaining-after-b5-pause.txt`
The paused direct sweep logged anomalies and then allowed a manual power cycle
before continuing. Because the script continues with the next command after the
pause, this run is useful for finding response-producing commands, but it is
not a clean `00 -> B5 -> candidate` post-discovery sweep.
Response hits observed in this run:
| Command at anomaly | Observed RCP response | Caution |
| ---: | --- | --- |
| `B5` | `07 80 6D 20 D8 48` | expected known query response |
| `40` | `07 80 50 40 30 FD` | repeated twice in this run |
| `6D` | `07 80 5B 20 D8 7E` | may depend on prior `6C` |
| `4F` | `07 80 0A 04 AB 78` | needs clean one-per-boot confirmation |
| `8F` | `07 80 0C 04 AB 7E` | may depend on prior sequence |
| `A0` | `07 80 E8 40 30 45` | differs from primer-sweep `A0` response |
| `B0` | `07 80 6C 40 30 C1` | known response |
| `CF` | `07 80 0E 04 AB 7C` | matches primer-sweep `CF` response |
| `EF` | `07 80 0F 04 EB 3D` | needs clean one-per-boot confirmation |
| `B1` | `07 80 6C 20 D8 49` | known response |
| `B3` | `07 80 36 10 2C D7` | known response |
| `B6` | `07 80 1B 08 C6 08` | known response |
| `B8` | `07 80 6E 40 30 C3` | differs from primer-sweep `B8` response |
| `BA` | `07 80 37 10 0C F6` | matches primer-sweep `BA` response |
| `BC` | `07 80 6F 40 30 C2` | differs from primer-sweep `BC` response |
Next confirmations:
- Retest `40`, `4F`, `8F`, `EF`, and the differing `A0/B8/BC` cases as clean
one-per-boot primer pairs.
- If a response differs between a plain/direct command and a primer-pair query,
treat the first host frame as a mode/context selector rather than only a
generic wake-up primer.
## Context Selector Confirmation Tests
Goal: confirm whether the first host frame is only a generic primer, or whether
it selects a response page/context for the next command.
The test method is to hold the second/query command constant and change only
the first frame:
```text
selector/primer -> selected query
```
Strong confirmation:
- Same selected query, different first frame, different RCP response.
- Example pattern: `00 -> B8` returns one block while `B7 -> B8` returns a
different block.
Weak or negative result:
- Same selected query always returns the same block regardless of the first
frame.
- The differing blocks from the paused direct sweep were caused by longer
sequence/timing effects rather than a two-frame selector.
### Test CS1: Known Generic `00` Page
This rechecks the current generic-primer page for the commands that had
different-looking responses in the paused direct sweep.
```powershell
python scripts/serial_primer_candidate_sweep.py --port COM5 --primer-command 0x00 --candidates "0xA0 0xB8 0xBC" --prompt-power-cycle --log captures/rcp-context-selector-00-a0-b8-bc.txt
```
Expected from prior primer sweeps:
| Pair | Expected response |
| --- | --- |
| `00 -> A0` | `07 80 68 40 30 C5` |
| `00 -> B8` | `07 80 EE 40 30 43` |
| `00 -> BC` | `07 80 EF 40 30 42` |
### Test CS2: Suspected Alternate Selectors
These test the pairings implied by the paused direct sweep. Power-cycle before
each prompt.
```powershell
python scripts/serial_primer_candidate_sweep.py --port COM5 --primer-command 0x9F --candidates 0xA0 --prompt-power-cycle --log captures/rcp-context-selector-9f-a0.txt
python scripts/serial_primer_candidate_sweep.py --port COM5 --primer-command 0xB7 --candidates 0xB8 --prompt-power-cycle --log captures/rcp-context-selector-b7-b8.txt
python scripts/serial_primer_candidate_sweep.py --port COM5 --primer-command 0xBB --candidates 0xBC --prompt-power-cycle --log captures/rcp-context-selector-bb-bc.txt
python scripts/serial_primer_candidate_sweep.py --port COM5 --primer-command 0xAF --candidates 0xB0 --prompt-power-cycle --log captures/rcp-context-selector-af-b0.txt
```
Compare against these paused/direct observations:
| Pair under test | Context hypothesis if reproduced |
| --- | --- |
| `9F -> A0` | `A0` may return `07 80 E8 40 30 45` after selector `9F`. |
| `B7 -> B8` | `B8` may return `07 80 6E 40 30 C3` after selector `B7`. |
| `BB -> BC` | `BC` may return `07 80 6F 40 30 C2` after selector `BB`. |
| `AF -> B0` | `B0` may return `07 80 6C 60 30 E1` after selector `AF`. |
### Test CS3: Check for Three-Frame Context
The paused sweep's `A0` response happened after `90` and `9F` had both been
sent in the same powered session. If `9F -> A0` does not reproduce the alternate
`A0` block, try the full three-frame setup:
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x90 0x9F 0xA0" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --after 3 --log captures/rcp-context-seq-90-9f-a0.txt
```
Power-cycle once before this test and do not power-cycle until the script
exits.
Interpretation:
- If `9F -> A0` reproduces `07 80 E8 40 30 45`, a two-frame selector is likely.
- If only `90 -> 9F -> A0` reproduces it, the context/page setup may require
multiple host frames.
- If neither reproduces it, treat the paused direct `A0` response as a
sequence/timing artifact until another capture confirms it.
### Optional Single-Frame Controls
These check whether the candidate can respond as the first frame after boot.
```powershell
python scripts/serial_direct_response_sweep.py --port COM5 --commands 0xA0 --states 0x00 --values 0x80 --settle 3 --after-each 1.5 --after 2 --log captures/rcp-context-single-a0.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands 0xB8 --states 0x00 --values 0x80 --settle 3 --after-each 1.5 --after 2 --log captures/rcp-context-single-b8.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands 0xBC --states 0x00 --values 0x80 --settle 3 --after-each 1.5 --after 2 --log captures/rcp-context-single-bc.txt
```
Power-cycle before each single-frame control.
### 2026-05-13 Context Selector Dataset Results
New captures:
- `captures/rcp-context-selector-00-a0-b8-bc.txt`
- `captures/rcp-context-selector-9f-a0.txt`
- `captures/rcp-context-selector-b7-b8.txt`
- `captures/rcp-context-selector-bb-bc.txt`
- `captures/rcp-context-selector-af-b0.txt`
- `captures/rcp-context-seq-90-9f-a0.txt`
- `captures/rcp-context-single-a0.txt`
- `captures/rcp-context-single-b8.txt`
- `captures/rcp-context-single-bc.txt`
Observed results:
| Test | Sequence | Observed response |
| --- | --- | --- |
| CS1 | `00 -> A0` | `07 80 E8 40 30 45` |
| CS1 | `00 -> B8` | `07 80 6E 40 30 C3` |
| CS1 | `00 -> BC` | `07 80 6F 40 30 C2` |
| CS2 | `9F -> A0` | heartbeat only |
| CS2 | `B7 -> B8` | `07 80 6E 40 30 C3` |
| CS2 | `BB -> BC` | `07 80 6F 40 30 C2` |
| CS2 | `AF -> B0` | `07 80 6C 40 30 C1` |
| CS3 | `90 -> 9F -> A0` | `07 80 68 40 30 C5` |
| Single-frame control | `A0` | heartbeat only |
| Single-frame control | `B8` | heartbeat only |
| Single-frame control | `BC` | heartbeat only |
Important comparison against earlier sweeps:
| Selected query | Earlier primer sweep response | New `00 -> query` response |
| ---: | --- | --- |
| `A0` | `07 80 68 40 30 C5` | `07 80 E8 40 30 45` |
| `B8` | `07 80 EE 40 30 43` | `07 80 6E 40 30 C3` |
| `BC` | `07 80 EF 40 30 42` | `07 80 6F 40 30 C2` |
Interpretation:
- Single `A0`, `B8`, and `BC` frames after boot produced heartbeat only, so
these responses require prior host traffic.
- The response is not determined only by the selected query command. The same
selected query can produce different response blocks in different setup
contexts.
- `B7 -> B8` and `BB -> BC` reproduced the alternate `B8`/`BC` responses seen
in the paused direct sweep.
- `90 -> 9F -> A0` reproduced the earlier `A0` response
`07 80 68 40 30 C5`, while `9F -> A0` alone produced no response.
- `00 -> A0` now produced the alternate `A0` response
`07 80 E8 40 30 45`, so the `00` first frame is not always a simple
deterministic "generic primer" in the current bench state.
- The evidence now favors a stateful/page-sensitive discovery model rather than
a single fixed primer model.
Working model after these datasets:
```text
Host sends one or more setup/selector frames.
RCP arms one readable response.
The next selected query returns a block from the currently selected page/state.
After that response, the RCP latches until power cycle or an unknown reset/state
advance command.
```
Recommended next confirmation:
1. Repeat `00 -> A0`, `00 -> B8`, and `00 -> BC` once more after clean power
cycles to see whether the alternate page is now stable.
2. Repeat `90 -> 9F -> A0` once more to confirm the earlier page can be selected
reliably.
3. Test whether `90 -> A0` alone selects the earlier page, or whether `9F` is
also required.
4. Test whether `00 -> 9F -> A0` behaves like `90 -> 9F -> A0`, which would
suggest `9F` is the real selector and `90` is only a setup/arming frame.
Suggested commands:
```powershell
python scripts/serial_primer_candidate_sweep.py --port COM5 --primer-command 0x00 --candidates "0xA0 0xB8 0xBC" --prompt-power-cycle --log captures/rcp-context-repeat-00-a0-b8-bc.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x90 0x9F 0xA0" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --after 3 --log captures/rcp-context-repeat-90-9f-a0.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x90 0xA0" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --after 3 --log captures/rcp-context-seq-90-a0.txt
python scripts/serial_direct_response_sweep.py --port COM5 --commands "0x00 0x9F 0xA0" --states 0x00 --values 0x80 --settle 3 --after-each 0.8 --after 3 --log captures/rcp-context-seq-00-9f-a0.txt
```
### 2026-05-13 Context Confirmation Result
New captures:
- `captures/rcp-context-repeat-00-a0-b8-bc.txt`
- `captures/rcp-context-repeat-90-9f-a0.txt`
- `captures/rcp-context-seq-90-a0.txt`
- `captures/rcp-context-seq-00-9f-a0.txt`
Observed results:
| Test | Sequence | Observed response |
| --- | --- | --- |
| Repeat `00` page | `00 -> A0` | `07 80 68 40 30 C5` |
| Repeat `00` page | `00 -> B8` | `07 80 6E 40 30 C3` |
| Repeat `00` page | `00 -> BC` | `07 80 6F 40 30 C2` |
| Repeat three-frame A0 | `90 -> 9F -> A0` | `07 80 68 40 30 C5` |
| A0 with `90` only | `90 -> A0` | `07 80 68 40 30 C5` |
| A0 with `00` then `9F` | `00 -> 9F -> A0` | `07 80 68 40 30 C5` |
Updated interpretation:
- `90 -> A0` is enough to produce the `A0` response
`07 80 68 40 30 C5`; `9F` is not required for that page.
- `00 -> 9F -> A0` also produces `07 80 68 40 30 C5`, so a frame before `9F`
can arm the response, but `9F` does not appear to select the alternate `A0`
response by itself.
- The repeat `00 -> A0` result returned to `07 80 68 40 30 C5`, while the
previous `00 -> A0` context dataset returned `07 80 E8 40 30 45`. Treat the
`E8` response as real but not yet deterministic from the current two-frame
model.
- `00 -> B8` and `00 -> BC` remained stable as `07 80 6E 40 30 C3` and
`07 80 6F 40 30 C2`, matching the earlier alternate-page observations.
Current best model:
```text
The RCP requires at least one setup frame before many query commands respond.
Some setup/query pairs are stable, for example 90 -> A0 and 00 -> B8.
Some response differences are still not explained by only the immediately
preceding frame, so a hidden boot/session/state bit or timing-sensitive page
selection may also be involved.
```
Next useful tests:
1. Retest `00 -> A0` several times in a row with a power cycle before each run
to measure whether `68` or `E8` is the dominant response.
2. Try direct pairs for the observed alternate `B8/BC` family:
`B8 -> B9`, `BC -> BD`, and `BD -> BE`.
3. Sweep the `D0-DF` region with the same primer-pair method to see whether the
structured discovery table continues after `CF`.