Repository navigation
Conversation
…ts publisher New self-contained subproject under p2plink/ (builds against the sibling devourer tree): a range-first 1:1 video + IP link with opportunistic hardware ACK. This commit carries the shared interfaces and the device-free io glue; the pure cores (FEC, N-ear merge, link controller, scheduler) and the radio glue follow. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dRefy4rsgbUwdnp6m6K3W
…rmonde) RsCodec(k,n) with precomputed repair rows, allocation-free encode/decode, submatrix inversion on erasure; block_symbol_len helper. Test sweeps every C(12,4) and C(11,3) erasure pattern plus the k=n / k=1 edges. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dRefy4rsgbUwdnp6m6K3W
…ck assembly) BlockMerger: per-(stream,block,idx) dedup across ears, emit-on-decodable with a separate retire cursor so trailing repair symbols are never counted lost, three gap rules, silent-ear exclusion, per-rung ok/lost accounting and the LinkReport builder; SeqDedup for the IP/probe/report classes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dRefy4rsgbUwdnp6m6K3W
Ladder table, LinkController (TRACK/BLIND/HOLD/FLOOR), DaMachine and the airtime scheduler headers as they stand mid-build; the final form and the budget test follow in the next commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dRefy4rsgbUwdnp6m6K3W
…tests LinkController TRACK/BLIND/HOLD/FLOOR with budget-leads-phy demotes and dwell-gated promotes; DaMachine ratio-based ACK mode; TxScheduler strict priority with interactive token bucket and airtime-bounded video queue. 186 checks across link_ctl_test and budget_test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dRefy4rsgbUwdnp6m6K3W
…, gaps) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dRefy4rsgbUwdnp6m6K3W
…DOVER greps) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dRefy4rsgbUwdnp6m6K3W
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dRefy4rsgbUwdnp6m6K3W
…lease build Adapter (per-adapter libusb context, RX fan-in off the event thread, TX mutex, tx.report tag join), p2p_tx (frame ring + tun -> scheduler -> FEC blocks; probes; LinkController/DaMachine; 20/40 tune follow), p2p_rx (N ears -> BlockMerger -> UDP/shm/tun; 10 Hz LinkReport on the uplink), p2p_feed (synthetic / Annex-B replay into the ring). Sentinels replace the optionals GCC -O3 flagged; tests labelled p2p; DESIGN.md implementation notes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dRefy4rsgbUwdnp6m6K3W
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dRefy4rsgbUwdnp6m6K3W
claim_interface_then_reset leaves the handle stale when the reset re-enumerates the adapter; the reopen variant waits for the same bus/port to come back and replaces the handle in place, which is what every demo that opens arbitrary dies uses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p starts StopRxLoop only sets a flag, and both Jaguar3 and MT7612U StartRxLoop clear that flag on entry (the loop is restartable). A stop that lands while an rx-only ear's Init is still in bring-up, or before the duplex worker thread reaches StartRxLoop, is wiped and the join waits forever. Re-assert the stop every 50 ms until the worker is seen to exit. The stopped flag becomes atomic: send/retune read it from the TX thread. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ery frame Only probes recorded their SW_DEFINE tag, and only after send_packet returned. The tag is 8 bits and advances on every frame (Jaguar3 stamps it whatever the sampling), so a probe whose report was lost left a valid slot that a unicast IP frame's report could claim 256 frames later, and a report consumed before the post-send write was dropped as not-a-probe. Adapter::send now takes a hook it calls under the TX mutex immediately before send_packet with the tag the frame will carry; the drone records every frame's kind there, so a slot always names the latest frame with that tag, and a send that fails clears its slot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… symbol First light (8812EU drone, MT7612U ground, R2, 30 fps synthetic feed with an IDR every second) lost exactly one block per second: every IDR. Rule (3) declared a block lost 20 ms after its FIRST symbol, but a block's own airtime is k + repair frames back to back, which exceeds 20 ms for every IDR at every rung and for most blocks at R0 (~1.8 ms per 1400 B frame). The block was declared while its symbols were still arriving. Blocks now carry last_ms (any copy, duplicates included) and rule (3) fires 20 ms after it; a gap in front of a block is still dated from that block's first symbol. New merge_test case (c3): symbols at 7 ms spacing complete the block, and a block that goes quiet is declared at last + 20 ms. Rerun: 760/760 blocks delivered (25 via FEC), 0 failed. DESIGN.md "RX merge" updated in the same commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HANDOVER told the bench to back power off with DEVOURER_TX_PWR, but the library reads no environment and p2plink builds its own DeviceConfig, so that variable never reached the chip and the apps had no power lever at all. RadioCfg gains txpwr_offset_qdb, applied with SetTxPowerOffsetQdb right after InitWrite on duplex adapters (the drone; the ground uplink), with the applied value logged. HANDOVER's near-field paragraph and CLI contract updated in the same commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With --tun and --uplink none the tun fd was polled but never read, so poll() returned at once forever and the ground spun at 100 % CPU. The tun is now polled only when there is an uplink to send it on. The ground's tx_timeouts was last_was_timeout as 0/1; it now accumulates the same way the drone's does (failures that landed while the last failure was a bulk-OUT timeout). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
First light at --fixed-rung 2 received 255 reports yet published report_age_ms = UINT32_MAX and walked TRACK -> BLIND -> HOLD -> FLOOR, because reports were only fed when the controller was adaptive. The DA machine needs TRACK, so a pinned drone could never reach Ucast — which is one of HANDOVER's first-light criteria. Rungs stay pinned (the controller's rung outputs are ignored in fixed mode); its state and ages now reflect the uplink. Rerun: report_age ~20 ms, TRACK throughout, Ucast at +1.5 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
devourer logs every successful bulk-OUT at info (UsbTransport "bulk_send EP n OK", one stderr line + flush per frame): ~11.4k lines in a 30 s R2 first-light run, and proportionally more at the top rungs, for no information. Everything p2plink itself reports at info is also carried by its NDJSON events (p2p.ready has the ack_target_mac). Upstream note: that line belongs at trace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Milestone: review + first light (hardware, 2026-10-29). Bench has one 8812EU, so every result is 8812EU drone (1-1, USB2) → MT7612U ground (8-1). C1 and C3's 8812EU ear are deferred until the second 8812EU is available. Review fixes (one commit each):
First light, ch 100 HT40+, R2, −10 dB power offset, near field (−37 dBm), run 2:
Upstream note (not changed here): |
Every per-sender counter (probe/IP seq, LinkReport epoch) begins again at 0 when a process restarts, but the receivers treated them as monotonic for the life of the link: after a ground restart the drone refused every report as stale until the new epoch overtook the old one (minutes into a session; C5(c) "restore -> TRACK" could not pass), and SeqDedup refused a restarted peer's probes and IP until its seq passed the old window. Found by the independent review of the glue. Header byte 11 (reserved, always 0 until now) now carries a session nonce Adapter::send stamps on every frame (random 1..255 per adapter open; 0 = none, so old senders still decode as one fixed session). SeqDedup restarts a window on a session change; p2p_tx calls LinkController::on_peer_restart on a LinkReport from a new session, which accepts the next report as the first. And a forward epoch whose cumulative uniq went backwards no longer underflows uniq_delta into a false acute floor. Tests: wire (byte 11 round trip), merge (g) restart, link_ctl restart + uniq-backwards. DESIGN.md implementation notes updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…by readback The TX thread picks a frame's rung (and so its width) before it blocks on the adapter's TX mutex, and the main loop published tune_bw = 20 only after the 40 -> 20 retune returned, so a frame picked while tune_bw still read 40 could air at 40 MHz on the freshly narrowed tune. tune_bw now drops to 20 before the retune (restored on failure); 20 -> 40 keeps publishing after, since a 20 MHz frame on a 40 MHz tune is fine. SetMonitorChannel is void, and the MT7612U logs and returns on a refused width; Adapter::retune now reads GetSelectedChannel back and fails the call instead of recording a width the radio does not hold. Both from the independent review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- p2p_rx: a spectator (no --tun) counted every received IP packet as a tun write failure and published it as dropped_ip_pkts. - parse_adapter_spec: an over-long @bus value reached std::stoi, which throws out of main instead of printing the usage error. - Adapter::stop: ClearAckResponder before Stop when the arm succeeded — the arm's documented mirror; Jaguar2's Stop() does not de-init the MAC, so the port identity would otherwise outlive the process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
C5(a) is "kill the uplink but keep the ACK". When one adapter is both the ACK target and the uplink (an MT7612U-only ground), restarting p2p_rx with --uplink none also removes the ACK for the whole bring-up, which is a different cell. SIGUSR1 toggles report transmission while the adapter keeps running; each toggle emits a p2p.uplink_mute event. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Milestone: C1–C4 (+ C5/C6 run, 2026-10-29). Pairing as before: 8812EU drone (1-1) → MT7612U ground (8-1), ch 100 HT40+, near field (−36 dBm, no attenuator). Details + log names: HANDOVER
Fixes since first light, from an independent review: afdb65c (peer restart = new session; byte 11 nonce), bdc3b56 (40 MHz frame on a 20 MHz tune race + retune readback), 14319ad (spectator IP drops, Open design questions (no code changed for these):
|
C5 on hardware: the drone never promoted — not R5 -> R6 in 20 s of clean TRACK, not off R0 after a restore — so any outage parked the link at the floor for good. LinkController::probe_evidence_ok vetoes unless the ground saw frames at r+1, and nothing ever aired at r+1 (the probe goes at the current rung). The unit tests passed on synthetic reports carrying r+1 counters the system never produces. Decided on PR #4: from 1 s before the promote dwell ends (TRACK, settled, r+1 unlocked and strictly faster) LinkController::sample_rung() opens and the drone airs each video block's REPAIR symbols at r+1 — a lost repair costs nothing while the sources arrive. Every symbol's flags now carry the repair rung (bits 4..6, valid 0x80; P2pHeader::rung stays the source rung), so the merger charges each lost symbol to the rung it aired at instead of to the block's rung, which would have read r+1 PER as zero. A step that is not faster on air (R3 -> R4, 26 = 26 Mb/s, 20 -> 40 MHz) needs no r+1 evidence. Tests: wire flag round trip, merge (g2) per-air-rung accounting, link_ctl (7b) sampling window + equal-PHY promote. DESIGN.md updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HANDOVER C5(a) expected one R-2 step before HOLD when reports stop but probes stay ACKed; the code and link_ctl_test hold at once, and the bench (c5-run1) did exactly that. Decided on PR #4: keep the code — ACKs prove the forward link, and stepping the drone's rate down does nothing for a lost reverse path. DESIGN.md's HOLD wording and HANDOVER C5(a) now say so (and name the SIGUSR1 report mute for a one-adapter ground). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HT40 carries 108 data subcarriers, not 2 x 52, so 40 MHz MCS1/3/5 run at 27/54/108 Mb/s (LGI). The ladder had 26/52/104, which made the airtime model overstate every 40 MHz frame (R6: 198 us, really 194). R4 is now faster than R3, which broke the promotion-evidence rule from 13db3fc ("a step that is not faster on air needs no r+1 evidence"): R3 -> R4 would have demanded R4 repairs, which cannot air on a 20 MHz tune, and the link would have stalled at R3. The rule now reads the ladder's own sensitivity column: a step needs evidence when the next rung has a higher rssi_floor_dbm (R3 -> R4: -84 -> -86 dBm, needs none). Tests and DESIGN updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
video_budget_kbps was PHY x duty x k/n x 0.97, which treats every us of the duty cap as payload. The scheduler charges each frame PLCP 36 us + data + IFS 50 us, so feeding exactly the budget overran the cap that the budget was derived from. C7 measured it: duty p50 707 permille at R5 against a 500 cap, 822 at R6 against 450, peaks above 1000. The budget is now the payload that duty x wall-clock airtime carries in full frames by frame_airtime_us(), x k/n x 0.97 - reserve, so the duty cap and the reported tx_duty_permille are one quantity. It moves to budget.h, next to the model. R0 2.0, R3 8.5, R4 8.1, R5 14.1, R6 19.6 Mb/s (was 2.2 / 10.7 / 10.2 / 20.6 / 37.4). est_capacity_kbps and ip_budget_kbps used the same PHY x share form and now use the model too (ip_budget at the PHY rung, which is where the interactive bucket charges). The cap stays the encoder's average, not a scheduler limit: bursts above it go to the existing 60 ms video queue bound. New test: feeding the budget in whole k_r-symbol blocks charges 0.95..1.0 x cap at every rung. DESIGN and HANDOVER updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
Each encoder frame is one FEC block whose repair count is the rung's ratio, ceil(k x (n_r - k_r) / k_r), floored at 1 until now. A small frame (k <= 4 at R5/R6, k <= 2 at R0-R4: the common P-frame on a static scene) then carried a single repair and died on a second lost symbol. waybeam-link floors repairs at min_r = 2 for the same reason; p2plink now does too. video_repair_count() in budget.h is the one rule: the TX encoder uses it and so does video_item_airtime_us(), so the scheduler still charges exactly what airs. Cost: one more frame of airtime per small frame, nothing on blocks large enough for the ratio to give >= 2 (the budget test's 8-symbol blocks are unchanged, 0.95..1.0 x cap). The video-bound test now derives its counts from the blocks that fit (10 one-symbol R0 blocks in 60 ms, was 16). DESIGN updated: one block per frame, k/n is a ratio, the floor and its cost. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
…l bring-up Outside p2plink/ on purpose: the stall is inside the MT7612U HAL's bring-up, before any caller gets the device back, so p2plink has no seam to work around it. To go upstream as its own PR. On a busy channel a fresh bring-up took ~31 s instead of ~1 s about half the time: 10-11 MCU commands in a row hit their 3 s reply budget, then all the replies appeared within 7 ms of the RX ring's first transfer. The command that starts it is CMD_CALIBRATION_OP / MCU_CAL_RXDCOC: the calibration opens the receive path with MAC RX still off, frames on the channel land in EP 4, and while data is parked there the chip does not deliver the EP 5 replies either. mcu_wait_resp() now drains EP 4 (mt_rx_flush, which returns the bytes it drained) on each 300 ms timeout whenever no RX ring owns EP 4, and logs what it drained with the command id. Nothing changes on a reply that arrives in time. RXDCOC runs on every channel set, so this also covers a ring-less channel set under traffic. Measured on one MT7612U restarted under an RTL8812EU airing ~1.7 k frames/s of HT40 MCS3 at 50 cm (p2plink bench, ch 100): before, 16 of 32 restarts took 31-34 s; after, 21 of 21 took 0.94-1.26 s, each slow-path case logging 7-19 kB drained at cmd 31 arg 3. A second flush at the end of mt_mac_stop() was tried first and did not help (7 of 10 still slow): the data comes from RXDCOC, not from the MAC stop window. src/mt7612u/CLAUDE.md's "bring this one up before the interferer" note is replaced with the mechanism. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
… floor, MT7612U restart Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
…ucer Outside p2plink/ for the same reason as 3d7c081: the stall is inside the MT7612U HAL's bring-up, before any caller gets the device back. This brings the branch to the revision going upstream as its own PR, after three independent reviews: - the drain's ownership test read d->a->rx_active without a lock from the PHY tick, which can overlap StopRxLoop's lock-free ring teardown (use-after-free window) and missed MT_RX_DRAIN_SYNC callers. Now mt7612u_dev::ep4_owner (NONE/RING/SYNC, compare-exchange transitions; the ring claims it under io_lock before its first RX submit and releases it once nothing is in flight); - drain once per command (bounded cost), mt_rx_flush counts partial reads; - docs: src/mt7612u/CLAUDE.md "MCU replies and EP 4" (current state, the mechanism worded as far as it is observed), docs/mt7612u.md "Bring-up on a busy channel" (A/B on upstream code via the new tests/mt7612u_busy_bringup.sh: master 6/6 + 6/6 stalled at 27.5 s, fixed 10/10 + 10/10 at 1.18 s); - 3d7c081's message miscounted the p2plink bench baseline: it is 22 of 32 slow restarts before (not 16) and 8 of 10 with the mt_mac_stop attempt (not 7); p2plink/docs/HANDOVER.md now carries the recount. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
…ordering) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
|
Milestone: C5–C9 (2026-10-29), same pairing: 8812EU drone (1-1) → MT7612U ground (8-1), ch 100 HT40+, near field (−36 dBm, 50 cm, no attenuator). Detail, logs and counterparts: HANDOVER
Fixed along the way:
8812EU HT40 TX (the libc0607/rtl88x2eu#7 stall):
Open:
|
…era drone R4 (40 MHz MCS1, 27 Mb/s) had a 0.55 cap against R3's 0.60, so the R3 -> R4 promote dropped the video budget 8529 -> 8111 kb/s (-4.9 %), under the actuator's 5 % threshold: the re-target was never sent (C9 partial) and the encoder ran ~5 % over R4's budget. The cap is demote headroom, and what a demote costs is the PHY-rate ratio to the rung below: R5 -> R4 doubles the airtime, R4 -> R3 adds ~4 %. R4 now takes R3's cap; its budget is 8.9 Mb/s, above R3's 8.5, so every promote raises it. HANDOVER: the ssc338q camera's 8812EU as a second drone unit (cross-built p2p_tx/p2p_feed from /tmp). C1 PASS (ack8 8 / coverage 1.00 ON, 203/203 pinned OFF), C3 PASS with both ears (8812EU 99.4-99.5 %, MT7612U 99.9 %, adapters 2 throughout), C4 edge 0 on the second unit too (21/21 starts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
|
Addendum — second 8812EU (the ssc338q camera as drone), 2026-10-29 evening. This closes cells the two milestone comments left NOT RUN or PARTIAL.
Also:
Still open:
|
…e (jaguar2-read-fail-survive) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
The drone keeps its own copy of the ladder with frame_bytes set from --frame-bytes (200..1400, default 1400, every rung), so block sizing, the airtime charge, the video budget and the oversize ceiling all follow from the one Rung field they already read. The tun MTU follows the frame. The ground needs no knob: rx_merge takes each block's symbol length from its frames; p2p_rx now reports what it receives as frame_bytes instead of a hard-coded 1400, and the drone's p2p.ready names its size. Short frames pay the per-frame PLCP + IFS more often, so the budget falls: R0 2018 -> 1786 kb/s at 600 B (-11 %), R6 19600 -> 11833 (-40 %). budget_test checks the duty-fill property at 1400, 600 and 200 B. HANDOVER's C8 spec said an MCS0 frame is 4.7 ms; the airtime model gives 1850 us at 1400 B and 866 us at 600 B (R0, HT20 MCS0) — corrected there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
send_video drops a frame above kMaxK x S whole, unsent, but the TX loop then charged its full block airtime to the scheduler anyway, so tx_duty_permille (and the interactive bucket's window) over-read whenever keyframes exceeded the block limit. send_video now says whether anything aired; a dropped item is not charged. Camera drone, R6 saturation, 100 Mb/s synthetic feed with a keyframe every 30 frames (472 oversize drops in 60 s): meter p50 1068 permille before, 551 after, against 554 for the frames actually aired (2853 frames/s x 194 us). The bench R5/R6 saturation readings carried ~1 such charge/s (116 in 115 s); HANDOVER's IFS-overcharge note now says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
BlockMerger treated a sender restart as such only when the block_id fell more than kResyncBlocks (1024) behind its cursor. A p2p_tx restarted under a running ground starts block_id at 0 again, so unless the old sender had aired more than 1024 blocks, every new block was discarded as late until the new count caught up — up to ~34 s of video at 30 fps. The C8 walk hit it on every leg: 18 drone restarts under one ground, ~560 blocks each, and the ground decoded only the first leg while both ears received ~120 000 frames. The header's session nonce (random per p2p_tx, already used by SeqDedup) now drives it: a new nonce flushes the pending set and rebases the cursors; a copy from the session just replaced is late, not a second restart. The id rule remains for senders without a nonce. A rebase now also forgets every ear's position — an old-session position made rule (1) close the new session's gaps before the slower ear had spoken (merge_test (f2) fails without it). Hardware: three drone restarts under one ground, each leg decoded from its first symbol, 0 failed blocks (walk-restartfix). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dReg1L6xtBhf95NpAeuge
|
p2plink development has moved to its own repository: What moved
What did not move: the devourer-side commits on this branch (3d7c081, f63d895). They go upstream through OpenIPC#510 instead. Last milestone on this branch (also in the new repo):
🤖 Generated with Claude Code |
What
A new self-contained subproject
p2plink/that builds against the sibling devourer tree: a standalone 1:1 radio layer (drone RTL8812EU → ground 8812EU and/or MT7612U ears) carrying an H.265 stream from the waybeam encoder frame ring plus an IP tunnel. Range and link robustness are the objective, not throughput.Nothing outside
p2plink/is touched. The branch sits on upstreamOpenIPC/devourermasterf46c28a(the fork was fast-forwarded first).Mechanism
Contents
include/p2p/wire.h,report.hwire_testfec.h,src/fec.cppfec_test(every C(12,4)/C(11,3) erasure pattern)rx_merge.hmerge_test(132 checks)link_ctl.h,budget.hlink_ctl_test,budget_test(186 checks)frame_shm.*,tun.*,stats_pub.*frame_shm_testradio.h,src/radio.cppsrc/p2p_tx.cpp,src/p2p_rx.cpp,src/p2p_feed.cpp--help/error paths onlydocs/DESIGN.md(spec as built),docs/HANDOVER.md(bench cells C1–C9),README.mdBuild:
cmake -S p2plink -B build-p2p -DCMAKE_BUILD_TYPE=Release -DP2P_WITH_MT7612U=ON && cmake --build build-p2p -j && ctest --test-dir build-p2p -L p2p— warning-free, 6/6 suites pass.Not yet verified (why this is a draft)
All of
radio.cppand both apps have never touched an adapter.docs/HANDOVER.mdlists the six design assumptions the bench must confirm first: 8812EU as the soliciting transmitter (only ever measured as responder), 8812EU→MT7612U ACK, 20 MHz frames into ears parked at 40 MHz on these dies, the per-unitwide_tx_igi_flooredge and its unmeasured uplink cost, MT7612U 40 MHz receive, frame-length PER at the floor. Review and hardware trials happen in a local session against this branch; fixes land as further commits here.Known gaps carried as follow-ups
Frame size fixed at 1400 B (not a rung); ground IP broadcast-only; no encryption; no channel migration; the "no probe ACK for 30 s → cap duty" rule; encoder floor (resolution/fps) co-design.
Generated by Claude Code