Skip to content

Add --cell-kv machine-readable LTE/5G-NR cell measurement output - #150

Closed
shark-fi wants to merge 4 commits into
fgsect:masterfrom
shark-fi:feat/cell-kv-output
Closed

shark-fi wants to merge 4 commits into
fgsect:masterfrom
shark-fi:feat/cell-kv-output

Conversation

@shark-fi

@shark-fi shark-fi commented Jul 1, 2026

Copy link
Copy Markdown

Summary

Adds a --cell-kv flag (Qualcomm) that emits LTE and 5G-NR serving and neighbor cell measurements as single-line key=value records to stdout, for machine parsing / ingestion into external tooling. Without the flag, output is unchanged.

Record format:

pci=..,earfcn=..,earfcn_ul=..,frequency=..,protocol=lte|nr,cell=scell|ncell,plmn=..,mcc=..,mnc=..,tac=..,cid=..,band=..,bwmhzdl=..,bwmhzul=.. rssi=..,rsrp=..,rsrq=..

Example (LTE serving cell, with RRC identity joined in):

pci=214,earfcn=6300,earfcn_ul=24300,frequency=806000000,protocol=lte,cell=scell,plmn=310260,mcc=310,mnc=260,tac=7,cid=123456,band=20,bwmhzdl=10,bwmhzul=10 rssi=-66.625,rsrp=-101.25,rsrq=-14.0625

What's included

  • util: dl_earfcn_to_frequency_hz() (3GPP TS 36.101 DL band table) and nrarfcn_to_frequency_hz() (TS 38.104 global raster) return center frequency in Hz; format_cell_kv() / format_plmn() build the record; LTE UL-EARFCN via the existing calculate_ul_earfcn().
  • LTE (diagltelogparser) and NR (diagnrlogparser): serving and neighbor cell measurements emit the record. NR beam parsing is preserved (byte offsets still advance) but beams are not emitted as records.
  • Stateful RRC↔ML1 join: RRC SCell Info packets populate a per-radio serving-cell identity cache (plmn/mcc/mnc/tac/cid/band/bandwidth), merged onto the matching ML1 serving-cell measurement. The join is guarded on (earfcn, pci) so stale identity is never attached to a different cell; neighbor cells remain identity-zeroed.

Compatibility / tests

  • Default (no --cell-kv) output is byte-identical; the full existing test suite passes (81 tests).
  • Scope is the Qualcomm parser; Samsung/HiSilicon are unaffected.

Notes

  • Identity enrichment requires an RRC SCell Info packet to have been seen before the measurement (as in a live diag stream on cell change); measurements before it stay identity-zeroed.
  • frequency is in Hz; bwmhzdl/ul in MHz.

🤖 Generated with Claude Code

shark-fi and others added 2 commits July 1, 2026 15:08
Add a --cell-kv flag (Qualcomm) that emits LTE and 5G-NR serving and
neighbor cell measurements as single-line key=value records for machine
parsing, instead of the human-readable stdout.

Each record has the form:

  pci=..,earfcn=..,earfcn_ul=..,frequency=..,protocol=lte|nr,cell=scell|ncell,
  plmn=..,mcc=..,mnc=..,tac=..,cid=..,band=..,bwmhzdl=..,bwmhzul=.. rssi=..,rsrp=..,rsrq=..

Details:
- util: dl_earfcn_to_frequency_hz() (3GPP TS 36.101 DL band table) and
  nrarfcn_to_frequency_hz() (TS 38.104 global raster) give center frequency
  in Hz; format_cell_kv()/format_plmn() build the record; real LTE UL-EARFCN
  via calculate_ul_earfcn().
- LTE (diagltelogparser) and NR (diagnrlogparser) serving and neighbor cell
  measurements emit the record; NR beam parsing is preserved (offsets still
  advance) but beams are not emitted as records.
- Stateful join: RRC SCell Info packets populate a per-radio serving-cell
  identity cache (plmn/mcc/mnc/tac/cid/band/bandwidth) that is merged onto the
  matching ML1 serving-cell measurement, guarded on (earfcn, pci) so stale
  identity is never attached to a different cell.

Default (no --cell-kv) output is unchanged; existing tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cover the util helpers (dl_earfcn_to_frequency_hz, nrarfcn_to_frequency_hz,
format_plmn, serving_identity_fields match-guard), LTE/NR serving and neighbor
cell key=value records, the RRC SCell Info -> serving-cell cache population,
and the stateful identity join (hit, mismatch-guard, and neighbor-not-enriched)
using existing real capture vectors. Also asserts default (no --cell-kv) output
is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
parse_nr_rrc_scell_info handled versions 0.04 / 3.00 / 3.02 / 3.03, but a
rel_maj==0x03 packet with any other rel_min fell through the inner if/elif
with `item` never assigned and then crashed with NameError at the
nr_serving_cell assignment. Flatten the dispatch and add a single
`item is None` guard that logs the version + body and returns cleanly.

This unblocks NR serving-cell identity (TAC/CID/PLMN) for modems whose SCell
Info version isn't listed yet (e.g. the Quectel RG650 in the GL-E5800): the
warning now prints the exact version + raw bytes needed to add its struct,
instead of silently yielding empty NR identity in --cell-kv output.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… 0xffff)

On SA 5G the NR ML1 measurement reports one entry per measured carrier; a
carrier the UE isn't camped on reports serv_cell_pci == 0xffff. SCAT was
emitting an all-zero `protocol=nr,cell=scell` row for each of those
(pci=65535, tac=0, cid=0, rsrp=0), which drowned the real serving cell and
made NR captures look like they had no TAC/CID. The real serving cell's
identity join already works (verified live: n25 PCI 796 -> tac/cid populated
from RRC SCell Info).

Guard the scell kv-row on serv_cell_pci != 0xffff so only actual serving
cells are emitted; neighbors are unaffected. Adds a regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shark-fi

shark-fi commented Sep 4, 2026

Copy link
Copy Markdown
Author

Superseded by #153, which consolidates this (--cell-kv + the RRC↔ML1 identity join), --meas-gsmtap, and the order-independent CellID emission into one branch off master. Closing in favor of #153.

@shark-fi shark-fi closed this Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant