Repository navigation
cell M5: move a running cell to another channel (runtime channel separation) - #567
Conversation
PR Summary by QodoApply coordinated channel moves to running cells
AI Description
Diagram
High-Level Assessment
Files changed (6)
|
Code Review by Qodo
1. A failed beacon restart looks like a move
|
…n-announced, DU and UEs retune together The coordination planner's spare-channel proposals were only logged. With RAN_RETUNE_APPLY=1 the CU now applies one: F1 v15 ChannelSwitch to that DU, RAN_CS_LEAD_SF (20) ahead; the DU stages it (refusing too little lead, its own channel, a handover in progress, or a retune that would not fit the idle window), announces it in its beacon (src/cell/ChannelSwitch.h: CsIe, tagged with the cell key, CRC; CsReceiver rejects replays and spent instants), and in the idle part of the superframe before the instant it and each UE stop the beacon, FastRetune and restart it - no TSF change, so the grid and slots keep their phase. A UE not hearing its cell there within 10 superframes goes back. The CU fences moves against handovers, times one out 50 sf after its instant and backs a refusing DU off RAN_CS_BACKOFF_S (30 s). Rig (testrig m5_retune.sh, cell 2's DL on UE1's uplink): the move done in both apply runs, 0/1 uplinks and 0 DL frames lost across it, uplinks in slot from the first superframe on 157, on-air cross-cell overlaps stop; a DU that can't fit the retune refuses and is not asked every round. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
aeac6d2 to
f34ef69
Compare
|
Review fixes pushed. All eight were real:
Rig on the fixed build (
The M6 suites that need a handover margin fail on master and here alike since the rig's RF levels changed; a separate PR makes them placement-independent. |
|
Qodo's re-review marks #7 resolved. It lists #1–#6 and #8 with their original descriptions, but the pushed head (f34ef69) has each fix:
Adding skip-qodo-gate. |
…LEVEL) (#568) Part of #254 (M6 regression). **Why.** On 2026-11-12, between 11:20 and 16:00, the rig's RF levels changed with no code change in between. UE1 now hears cell 1 at −50 dBm (−63 before) and cell 2 at −51 (−53); UE2's levels moved by 2–5 dB. The cause is not established. The M6 suites that hand over on a standing difference lost their margin (+10 to +13 dB): handover, measgap, three_ho, daps, daps_dl and daps_xch failed, identically on master (A/B on the rig). With those levels the A3 correctly has nothing to fire on. **What.** `CELL_UE_MEAS_LEVEL="cell:dBm,..."` (`MeasLevelPin`, `examples/cell/cell.h`). For each listed cell, the UE takes the median of its first 8 beacon measurements as where the bench put it, and shifts every later measurement by (target − median). The offset is logged (`cell.ue.meas_pin`); the cell is held out of the measurement table while it calibrates. - Fluctuations and TX ramps still come through; only the standing level is the suite's. - The radio links themselves are untouched: the bench still carries the frames. - It's a test-bench emulation in the example node, like `CELL_ATTEN_*` and `CELL_DU_TX_RAMP`; not library behaviour. - Selftest in `cell_node`. **testrig** (committed there): `m5_ran_coord.sh` takes `M5_MEAS_LEVELS` ("UE=cell:dBm,...;UE=..."). Each standing-difference M6 suite defaults it to the medians of its passing runs: two cells UE1 −63/−52, UE2 −53/−38; three cells per UE. The ramp-driven crossings are not pinned, and `M5_MEAS_LEVELS=""` runs on the bench's own levels. **Rig, on the changed levels:** all 8 M6 suites pass (handover, measgap, three_ho, daps, daps_dl, daps_xch, crossing3, crossing). On this exact build (master with #567, plus this), handover and measgap passed again. The calibrated offsets show the change: UE1's cell 1 is pulled −13 dB, the others by −2 to +6. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Closes the last open item of #259 (M5), epic #254: the coordination planner's channel separation, until now only logged (
ran.retune), is applied at runtime.How (
src/cell/ChannelSwitch.h, F1 v15ChannelSwitch)RAN_RETUNE_APPLY=1): tells the proposed DU to serve on the spare channel from a network superframeRAN_CS_LEAD_SF(20) ahead (ran.cs_cmd), and resends until it is staged.ran.cs_done); timed out 50 sf after its instant.RAN_CS_BACKOFF_S(30 s).no_window).CsIe: id, cell, channel, first superframe on the new channel; cell-key tag, CRC), and the DU refuses handover commands meanwhile.FastRetunes and restarts it. The TSF doesn't move, so the grid and slots keep their phase.CsReceiver: a newer id, instant ahead, so a replayed beacon can't move it).cell_m5): IE round trip, wrong key/cell, tamper, replay and spent instants, the window, F1 message and ack.Rig (testrig
m5_retune.sh: two cells on 149, capacity 1, cell 2's DL frames land on UE1's uplink; the planner proposes 157 for DU1)no_window), never announced, the UE never moved; 3 commands in 90 s (backoff)At this rig's levels the overlap costs UE1 only a few uplinks (1–3 of ~440 without the move, 0 with it), so the gain shown is the conflict removed, not a large delivery loss recovered. A first scenario (phase 3000) had a planner conflict with no frame overlap on air; the planner reasons on whole slots. The docs record both. The UE's fall-back path ran on the rig only before the staging check (it fell back every time and was heard on the old channel 1 sf later); a DU now refuses a move it can't make.
Regression. Coordination (
m5_ran_coord), crossing3 and crossing pass on this branch. handover, measgap, three_ho, daps, daps_dl and daps_xch fail, identically on master (A/B run on the rig). The rig's RF levels changed between 11:20 and 16:00 today, with no code change in between. UE1 now hears cell 1 at −50 dBm (was −63) and cell 2 at −51 (was −53), so those suites' standing A3 margins (+10–13 dB) are gone and no handover is the correct outcome. The cause isn't established.🤖 Generated with Claude Code