Files
SDR-Rover/docs/handoff/NEXT_RX_TASK.md
2026-09-22 17:43:58 +03:00

7.8 KiB

TASK_ID = RF001A_OTA_CAPTURE_004 TASK_TITLE = Start hardened RF-001A common-clock OTA capture SOURCE_BRANCH = video-development EXPECTED_HEAD = 168e03d9e7 REQUIRES_APPROVAL = YES HARDWARE_ACCESS = YES RF_RX = YES RF_TX = NO ALLOW_COMMIT = NO ALLOW_PUSH = RX_RESULT_ONLY RISK_LEVEL = YELLOW


RF-001A RX capture 004

This file is the authoritative current task for the RX laptop. Read RX_NODE_STATE.md first. If chat history conflicts with these files or the current Git HEAD, stop and report the conflict.

This task is prepared only. A previous approval does not apply to this new TASK_ID. Do not access HackRF until the user approves this exact YELLOW task.

1. Software and Git gates

  1. Run git pull --ff-only origin video-development.

  2. Require branch video-development and a clean tracked worktree.

  3. Require local HEAD to equal origin/video-development; EXPECTED_HEAD must be its ancestor.

  4. Confirm the historical channel-test READY and COMPLETE acknowledgements from origin/tx-node through the RX watcher.

  5. Before opening HackRF, run the authenticated no-change publication check:

    python -B tools/rx_agent_watcher.py --check-result-write --result-branch rx-node
    

    Require RX-NODE WRITE PREFLIGHT = PASS. This command fetches the branch, performs git push --dry-run of its existing HEAD to the same ref, and confirms that the remote HEAD did not change. It creates no commit and no production READY event.

  6. Run the targeted tests, Ruff, Pyright and git diff --check according to the tracked project instructions.

  7. Validate configs/rf/rf001a_truth_metadata.json: waveform SHA256, seed, PHY settings, 100 sequence numbers and 100 packet hashes must agree with configs/rf/rf001a_common_clock.json.

If any gate fails, do not open HackRF and stop. In particular, a failed Git write preflight blocks the hardware task.

2. Optional offline check of capture 003

If the existing RF001A_OTA_CAPTURE_003 file is present locally, analyze it read-only with the streaming cs8 decoder before starting new hardware work:

python -B -X utf8 tools/qpsk_rf_rx.py --iq-file <capture-003-path>\rf001a_ota_capture.cs8 --iq-format cs8 --truth-metadata configs/rf/rf001a_truth_metadata.json --report <new-path-outside-git>\capture003_streaming_report.json

No RF-001A transmission occurred during capture 003. The expected exact packet count is 0. CRC-valid background candidates must not be reported as exact unless their complete packet SHA256 matches the tracked truth metadata. The analysis must use memmap/chunks and must not materialize the full 1.92 GB capture as complex64.

If capture 003 is unavailable, report CAPTURE_003 ANALYSIS = NOT_RUN and continue only after all mandatory gates pass.

3. Hardware preflight after YELLOW approval

  1. Run hackrf_info and require RX serial 000000000000000097c063dc2e5327d3.

  2. With MASTER CLKOUT -> SLAVE CLKIN connected, run:

    hackrf_clock.exe -d 000000000000000097c063dc2e5327d3 -i
    
  3. Require CLKIN status: clock signal detected.

  4. Repeat the Git write preflight immediately before the finite RX command.

  5. Require antennas connected, approximately 2 m distance, clear LOS, and video disabled.

  6. Require at least 1500000000 free bytes on the capture volume and record the measured value.

Do not reconfigure clocks. If CLKIN or the second Git preflight fails, stop before capture.

4. Finite RX capture

Use a unique directory outside Git. Never overwrite an earlier capture.

RX serial = 000000000000000097c063dc2e5327d3
center frequency = 1400000000 Hz
sample rate = 8000000 samples/s
RX LNA = 24 dB
RX VGA = 24 dB
RF amp = OFF
antenna bias = OFF
duration = 60 s
sample count = 480000000 complex samples
hardware format = cs8
expected file size = 960000000 bytes

Use these fixed hackrf_transfer.exe arguments:

-d 000000000000000097c063dc2e5327d3
-r <unique_capture_path>\rf001a_ota_capture.cs8
-f 1400000000
-s 8000000
-n 480000000
-l 24
-g 24
-a 0
-p 0
-B

Use tools/capture_process_runner.ps1 as a controlled background process. Preserve its complete stdout, stderr, start JSON and result JSON outside Git. The runner must start exactly one finite child, record the actual child PID and UTC start time, set the expected end to start plus 60 seconds, wait for that exact process, record its integer exit code, size and duration, and calculate SHA256 after the output file closes. Never retry the capture automatically.

Within five seconds require the runner and child to be alive and the file to exist and grow. Otherwise publish no READY and stop.

5. READY publication

Create the strict schema-version-1 READY JSON outside Git for TASK_ID RF001A_OTA_CAPTURE_004. Use the actual child PID and UTC timestamps, expected_capture_end = capture_started_at + 60 s, current source HEAD, common_clock_verified = true, rf_tx = 0, and null final result fields.

Publish it once with:

python -B tools/rx_agent_watcher.py --publish-result <ready-json> --result-branch rx-node

The publisher creates one immutable READY commit. On a recognized transient network or authentication failure it checks the remote branch and may retry the exact same commit once. It never creates a second READY commit or changes the payload between attempts. If the remote already contains that commit, the publication is successful. A second failure means:

READY publication = FAIL
RX READY FOR TX = NO
RF TX = 0

Do not publish READY after the capture window has ended. After the process exits, publish only a CAPTURE_COMPLETE result with the actual exit code, size, duration and error counters, including nonzero failure values.

After the remote HEAD confirms the READY commit, immediately print:

TASK_ID = RF001A_OTA_CAPTURE_004
RX CAPTURE STARTED = YES
RX READY FOR TX = YES
CAPTURE PID =
CAPTURE PATH =
CAPTURE START TIME =
EXPECTED CAPTURE END =
RX RESULT HEAD =
RF TX = 0

Return control without waiting for capture completion.

6. Completion and offline decode

After the child exits, record exact exit code, actual size, duration, overruns, USB errors, file-write errors and SHA256. A complete capture is exactly 960000000 bytes; a smaller file is incomplete. Run the CLKIN check again and require detected status.

Publish an honest schema-version-1 COMPLETE result with final values. Keep IQ, stdout, stderr and large logs outside Git.

After origin/tx-node contains TX_STARTED and TX_COMPLETE for RF001A_OTA_TX_004, run the streaming decoder with RX/TX timestamps:

python -B -X utf8 tools/qpsk_rf_rx.py --iq-file <capture-path>\rf001a_ota_capture.cs8 --iq-format cs8 --truth-metadata configs/rf/rf001a_truth_metadata.json --capture-started-at <CAPTURE_STARTED_AT> --tx-started-at <TX_STARTED_AT> --tx-finished-at <TX_FINISHED_AT> --report <new-path-outside-git>\rf001a_streaming_report.json

The decoder uses a two-second margin before and after the timestamped burst. Without complete timestamps it uses the streaming power locator. Chunk overlap is derived from the real 256-byte RF-001 waveform and duplicate detections from overlap are suppressed.

7. Prohibited actions

RF TX, firmware update, CPLD update, Zadig, USB driver changes, clock reconfiguration, commit or push to video-development, repeated capture, raw IQ/video/waveform publication and large-log publication are forbidden.

Final report:

TASK_ID = RF001A_OTA_CAPTURE_004
RX-NODE WRITE PREFLIGHT = PASS / FAIL
COMMON CLOCK = VERIFIED / NOT_VERIFIED
RX CAPTURE COMPLETE = YES / NO
CAPTURE SIZE =
CAPTURE DURATION =
RX OVERRUNS =
USB ERRORS =
FILE WRITE ERRORS =
RAW IQ SHA256 =
STREAMING DECODE = PASS / FAIL / NOT_RUN
EXACT RF001A PACKETS =
PEAK ANALYSIS MEMORY =
RF TX = 0

STOP.