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

68 KiB

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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

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:

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:

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:

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:

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:

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:

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:

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:

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:

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.

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:

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:

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.

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:

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:

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:

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:

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:

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:

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.

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:

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:

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:

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:

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:
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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

python scripts/serial_primer_candidate_sweep.py --port COM5 --candidates "0xB0-0xB7" --dry-run

Continue the known B range first:

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:

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:

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:

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.

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.

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:

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:

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:

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:

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:

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:
primer -> selected query -> candidate activation/ack command

Known reproducible setup:

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:

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:

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:

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.