Harden RF handoff and stream OTA decode
This commit is contained in:
@@ -1,142 +1,96 @@
|
||||
TASK_ID = RF001A_OTA_TX_003
|
||||
TASK_TITLE = Transmit one coordinated RF-001A QPSK burst
|
||||
TASK_ID = RF001A_OTA_TX_004
|
||||
TASK_TITLE = Send one finite RF-001A burst into RX capture 004
|
||||
SOURCE_BRANCH = video-development
|
||||
EXPECTED_HEAD = bc55d0516dc1ee36cefa1ff096e7d86f60645303
|
||||
EXPECTED_HEAD = 168e03d9e778ab2ec63502552d385ec7be3ef677
|
||||
REQUIRES_APPROVAL = YES
|
||||
HARDWARE_ACCESS = YES
|
||||
RF_RX = NO
|
||||
RF_TX = YES
|
||||
ALLOW_COMMIT = NO
|
||||
ALLOW_PUSH = NO
|
||||
ALLOW_PUSH = TX_RESULT_ONLY
|
||||
RISK_LEVEL = RED
|
||||
|
||||
This file is the authoritative current task for the MAIN PC TX node.
|
||||
Read TX_NODE_STATE.md first. If chat history, this file, the shared RF-001A spec or current Git HEAD conflicts, stop and report the conflict.
|
||||
---
|
||||
|
||||
# Current TX task
|
||||
# RF-001A TX 004
|
||||
|
||||
TASK =
|
||||
TRANSMIT ONE COORDINATED RF-001A QPSK BURST
|
||||
This task is prepared only. Do not execute it now. Old approval for any earlier
|
||||
TASK_ID is invalid. The MAIN watcher waits for a fresh
|
||||
`RF001A_OTA_CAPTURE_004` READY event from `origin/rx-node`.
|
||||
|
||||
This is a new RED task. Publication of this file is not permission to transmit. It does not inherit any approval from RF001A_OTA_TX_001, RF001A_OTA_TX_002, the RX task, a previous watcher prompt or a previous RF run.
|
||||
## 1. Watcher gate
|
||||
|
||||
## 1. Coordination gate
|
||||
The watcher must require all of the following:
|
||||
|
||||
Start the local model-free watcher before the RX task begins:
|
||||
- RX TASK_ID = `RF001A_OTA_CAPTURE_004`;
|
||||
- state = `RX_READY_FOR_TX`;
|
||||
- source HEAD is the current `video-development` HEAD;
|
||||
- COMMON_CLOCK_VERIFIED = YES;
|
||||
- live child and growing capture are both true;
|
||||
- planned RX duration is 59–61 seconds;
|
||||
- READY is no more than 30 seconds old;
|
||||
- at least 10 seconds remain in the capture window;
|
||||
- the observed commit is the current valid `origin/rx-node` HEAD.
|
||||
|
||||
tools\start_tx_watcher.cmd
|
||||
The watcher then requests exactly:
|
||||
|
||||
The watcher polls origin/rx-node every 5 seconds. It processes every new result-branch commit from `last_processed_rx_node_commit` to the current `origin/rx-node` tip in chronological order. It accepts only a strict result for:
|
||||
|
||||
RX TASK_ID = RF001A_OTA_CAPTURE_003
|
||||
STATE = RX_READY_FOR_TX
|
||||
RX_READY_FOR_TX = YES
|
||||
PROCESS_ALIVE = YES
|
||||
FILE_GROWING = YES
|
||||
COMMON_CLOCK_VERIFIED = YES
|
||||
RF_TX = 0
|
||||
|
||||
The watcher records RF_HANDOFF_CHANNEL_TEST_001 READY and COMPLETE states without prompting for RED approval and never treats them as production readiness. A production READY publication must be no more than 30 seconds old. Its planned capture window must be 120 seconds. At least 10 seconds must remain. COMMON_CLOCK_VERIFIED must be YES, source_head must equal the expected video-development HEAD, and the result commit must be the current valid origin/rx-node HEAD.
|
||||
|
||||
When a valid new READY result appears, the watcher prints:
|
||||
|
||||
RX IS READY
|
||||
|
||||
TASK ID =
|
||||
CAPTURE STARTED =
|
||||
CAPTURE END EXPECTED =
|
||||
|
||||
TX TASK =
|
||||
RF001A_OTA_TX_003
|
||||
|
||||
RF TX REQUIRES RED APPROVAL
|
||||
|
||||
Enter:
|
||||
AUTHORIZE RF TX
|
||||
|
||||
Without the exact phrase AUTHORIZE RF TX, do not transmit.
|
||||
Any other response blocks TX. After the exact phrase, fetch `origin/rx-node`
|
||||
again and repeat every commit, digest, task, source HEAD, freshness, common
|
||||
clock and remaining-time check. A changed or stale result requires a new RX
|
||||
capture and a new exact RED approval.
|
||||
|
||||
After the phrase, the watcher fetches rx-node again and repeats the result commit, digest, task ID, source HEAD, READY, freshness, common-clock and capture-window checks. If the result changed or less than 10 seconds remain, it refuses authorization and requires a new RX capture.
|
||||
On success publish a schema-version-2 `TX_AUTHORIZED` event to `origin/tx-node`
|
||||
with the exact source RX commit and digest, TX TASK_ID `RF001A_OTA_TX_004`,
|
||||
`RF_TX_AUTHORIZED = YES`, `RF_TX_STARTED = NO` and `RF_TX = 0`. Also write the
|
||||
local authorization record. This event is permission evidence, not proof of a
|
||||
transmission.
|
||||
|
||||
The watcher never opens HackRF hardware. On success it writes one local authorization record under:
|
||||
## 2. Read-only TX preflight
|
||||
|
||||
.local\tx_authorizations\
|
||||
Before opening TX hardware:
|
||||
|
||||
The record has rf_tx_started = false and rf_tx = 0. It is the handoff to the separately controlled TX executor. It is not evidence that transmission occurred.
|
||||
1. Run `git pull --ff-only origin video-development`.
|
||||
2. Require branch `video-development`, a clean tracked worktree and local HEAD
|
||||
equal to `origin/video-development`; `EXPECTED_HEAD` must be its ancestor.
|
||||
3. Run `hackrf_info`; require TX serial
|
||||
`000000000000000097c063dc323b97d3`.
|
||||
4. Require the recorded MASTER CLKOUT command = PASS, both antennas connected,
|
||||
approximately 2 m distance, clear LOS, and video disabled.
|
||||
5. Verify the waveform without radio access:
|
||||
|
||||
## 2. Fixed RF-001A parameters
|
||||
python -B -X utf8 tools/rf001a_prepare.py --verify-dir data/raw/rf001/rf001a_common_clock_001
|
||||
|
||||
center frequency = 1400000000 Hz
|
||||
sample rate = 8000000 samples/s
|
||||
modulation = QPSK
|
||||
symbol rate = 500000 symbols/s
|
||||
inner FEC = 2/3
|
||||
payload = 256 bytes
|
||||
packet count = 100
|
||||
inter-packet gap = 5 ms
|
||||
digital carrier offset = +125000 Hz
|
||||
TX VGA = 20 dB
|
||||
RF amp = OFF
|
||||
antenna bias = OFF
|
||||
common 10 MHz reference = VERIFIED
|
||||
distance = approximately 2 m
|
||||
LOS = YES
|
||||
video = OFF
|
||||
6. Require:
|
||||
|
||||
The waveform is one finite burst. Never add repeat mode.
|
||||
|
||||
## 3. Read-only preflight
|
||||
|
||||
Before the watcher can request RED approval:
|
||||
|
||||
1. Run git pull --ff-only origin video-development.
|
||||
2. Require branch video-development.
|
||||
3. Require git status --short --untracked-files=no to produce no output.
|
||||
4. Require local HEAD to equal origin/video-development and EXPECTED_HEAD to be its ancestor.
|
||||
5. Run hackrf_info and preserve complete stdout.
|
||||
6. Require TX serial 000000000000000097c063dc323b97d3.
|
||||
7. Require the recorded MASTER CLKOUT command result = PASS.
|
||||
8. Require confirmation that both antennas are connected, the nodes are approximately 2 m apart, and LOS is clear.
|
||||
9. Verify the prepared waveform without radio access:
|
||||
|
||||
python -B -X utf8 tools/rf001a_prepare.py --verify-dir data/raw/rf001/rf001a_common_clock_001
|
||||
|
||||
10. Verify the actual cs8 bytes through the existing offline receiver:
|
||||
|
||||
python -B -X utf8 tools/qpsk_rf_rx.py --iq-file data/raw/rf001/rf001a_common_clock_001/tx_waveform.cs8 --iq-format cs8 --truth-metadata configs/rf/rf001a_truth_metadata.json --report <new-path-outside-git>\rf001a_tx_offline_verify.json
|
||||
|
||||
Require:
|
||||
|
||||
canonical waveform = PASS
|
||||
hardware-format cs8 = PASS
|
||||
offline hardware-format roundtrip = 100/100 exact
|
||||
TX waveform path = data/raw/rf001/rf001a_common_clock_001/tx_waveform.cs8
|
||||
TX waveform size = 17667656 bytes
|
||||
TX waveform SHA256 = 75f3fa39bfa4ee419f0676c54e4b9c486d7ff64bd0fe2fc06343b20c9d117ecd
|
||||
sample count = 8833828 complex samples
|
||||
expected duration = 1.1042285 s
|
||||
waveform path = data/raw/rf001/rf001a_common_clock_001/tx_waveform.cs8
|
||||
waveform size = 17667656 bytes
|
||||
waveform SHA256 = 75f3fa39bfa4ee419f0676c54e4b9c486d7ff64bd0fe2fc06343b20c9d117ecd
|
||||
sample count = 8833828 complex samples
|
||||
duration = 1.1042285 s
|
||||
offline exact packets = 100/100
|
||||
|
||||
If any value differs, do not transmit.
|
||||
|
||||
## 4. Final check before opening TX hardware
|
||||
## 3. Final executor gate
|
||||
|
||||
The controlled TX executor must read the authorization record immediately before TX and require:
|
||||
Immediately before hardware access, the controlled executor must read the
|
||||
local authorization and re-fetch `origin/rx-node`. Require:
|
||||
|
||||
- task_id = RF001A_OTA_TX_003;
|
||||
- authorization = AUTHORIZE RF TX;
|
||||
- rx_task_id = RF001A_OTA_CAPTURE_003;
|
||||
- dry_run = false;
|
||||
- action = MANUAL_EXECUTOR_GATE_OPEN;
|
||||
- rf_tx_started = false;
|
||||
- rf_tx = 0;
|
||||
- the authorization references the latest fetched rx-node result commit and digest;
|
||||
- current time is still inside the READY capture window with at least 10 seconds remaining.
|
||||
- TX TASK_ID = `RF001A_OTA_TX_004`;
|
||||
- RX TASK_ID = `RF001A_OTA_CAPTURE_004`;
|
||||
- authorization phrase = `AUTHORIZE RF TX`;
|
||||
- authorization binds the current READY commit and digest;
|
||||
- `rf_tx_started = false` and `rf_tx = 0` in the authorization record;
|
||||
- at least 10 seconds remain in the same READY window.
|
||||
|
||||
Fetch origin/rx-node once more and compare its current result digest and commit with the authorization record. Re-run the READY and time checks. If anything differs, if the result is stale, or if fewer than 10 seconds remain, do not transmit and require a new RX capture and a new exact RED approval.
|
||||
If any check fails, do not open HackRF.
|
||||
|
||||
## 5. One authorized TX execution
|
||||
## 4. One finite TX burst
|
||||
|
||||
Only after every preceding condition passes may the executor create a new unique evidence directory outside Git and run exactly one finite command:
|
||||
Only after all gates pass may the executor create a unique evidence directory
|
||||
outside Git and run exactly one finite command:
|
||||
|
||||
hackrf_transfer.exe
|
||||
-d 000000000000000097c063dc323b97d3
|
||||
@@ -149,71 +103,48 @@ Only after every preceding condition passes may the executor create a new unique
|
||||
-p 0
|
||||
-B
|
||||
|
||||
Run it once, synchronously, and preserve:
|
||||
Never add repeat mode and never retry automatically.
|
||||
|
||||
- exact process PID;
|
||||
- start and end UTC timestamps;
|
||||
- exact exit code;
|
||||
- complete stdout and stderr;
|
||||
- every TX underrun line;
|
||||
- every USB error;
|
||||
- waveform path, size and SHA256;
|
||||
- command parameters.
|
||||
At the exact process start, publish `TX_STARTED` to `origin/tx-node`, preserving
|
||||
the authorization binding and recording `TX_STARTED_AT` as accurately as the
|
||||
host permits. Set `RF_TX_STARTED = YES` and `RF_TX = 1` because this event is
|
||||
evidence of an actual started process.
|
||||
|
||||
Set RF TX STOPPED = YES only after the finite process exits. Never retry automatically. Never start a second burst.
|
||||
Write the strict schema-version-2 event JSON outside Git and publish it with:
|
||||
|
||||
## 6. Final TX report
|
||||
python -B tools/tx_agent_watcher.py --publish-tx-event <started-json> --acknowledgement-branch tx-node
|
||||
|
||||
TASK_ID =
|
||||
RF001A_OTA_TX_003
|
||||
After that exact process exits, publish `TX_COMPLETE` with `TX_FINISHED_AT`,
|
||||
the integer process exit code, underrun count and error count. Preserve the
|
||||
complete stdout and stderr outside Git. The event reports what happened; it
|
||||
does not by itself prove that packets were received. Captured IQ remains the
|
||||
source for exact packet verification.
|
||||
|
||||
RED AUTHORIZATION =
|
||||
AUTHORIZE RF TX / MISSING
|
||||
Publish the completion JSON with the same `--publish-tx-event` command. The
|
||||
publisher requires the matching `TX_AUTHORIZED` and `TX_STARTED` history.
|
||||
|
||||
RX READY FOR TX =
|
||||
YES / NO
|
||||
The only files permitted on `tx-node` are:
|
||||
|
||||
docs/handoff/results/TX_RESULT.json
|
||||
docs/handoff/results/TX_RESULT.md
|
||||
|
||||
Do not publish waveform, IQ, video, source code, local state or large logs.
|
||||
|
||||
## 5. Final report
|
||||
|
||||
TASK_ID = RF001A_OTA_TX_004
|
||||
RX READY FOR TX = YES / NO
|
||||
RX RESULT HEAD =
|
||||
|
||||
RX RESULT DIGEST =
|
||||
|
||||
TX SERIAL =
|
||||
|
||||
TX WAVEFORM SHA256 =
|
||||
|
||||
TX START TIME =
|
||||
|
||||
TX END TIME =
|
||||
|
||||
TX EXIT CODE =
|
||||
|
||||
TX AUTHORIZED EVENT = PASS / FAIL
|
||||
TX STARTED AT =
|
||||
TX FINISHED AT =
|
||||
TX PROCESS EXIT CODE =
|
||||
TX UNDERRUNS =
|
||||
TX ERRORS =
|
||||
TX COMPLETE EVENT = PASS / FAIL
|
||||
RF TX STOPPED = YES / NO
|
||||
|
||||
USB ERRORS =
|
||||
|
||||
RF TX STOPPED =
|
||||
YES / NO
|
||||
|
||||
BURSTS TRANSMITTED =
|
||||
0 / 1
|
||||
|
||||
RF TX =
|
||||
0
|
||||
|
||||
At report time, RF TX = 0 means no transmission process remains active.
|
||||
|
||||
## 7. Prohibited actions
|
||||
|
||||
Do not:
|
||||
|
||||
- transmit without the fresh READY state and exact RED phrase;
|
||||
- reuse an earlier authorization record;
|
||||
- use repeat mode;
|
||||
- transmit a second burst;
|
||||
- retry automatically;
|
||||
- change frequency, gains, clock configuration or waveform;
|
||||
- update firmware or CPLD;
|
||||
- use Zadig or change USB drivers;
|
||||
- commit or push from this task.
|
||||
|
||||
STOP after the single finite burst or any failed gate.
|
||||
STOP after the one finite burst and event publication. Firmware, CPLD, Zadig,
|
||||
USB driver changes, clock reconfiguration, a second burst, commit or push to
|
||||
`video-development` are forbidden.
|
||||
|
||||
Reference in New Issue
Block a user