Skip to content

Machine-readable LTE/5G-NR cell measurements (--cell-kv, --meas-gsmtap) - #153

Open
shark-fi wants to merge 6 commits into
fgsect:masterfrom
shark-fi:feat/cell-measurements
Open

Machine-readable LTE/5G-NR cell measurements (--cell-kv, --meas-gsmtap)#153
shark-fi wants to merge 6 commits into
fgsect:masterfrom
shark-fi:feat/cell-measurements

Conversation

@shark-fi

@shark-fi shark-fi commented Sep 4, 2026

Copy link
Copy Markdown

Summary

Consolidated PR for machine-readable LTE/5G-NR cell measurements. Supersedes the stacked PRs #150, #1, and #2 — same work, one reviewable branch off master.

--cell-kv — key=value measurement output

LTE and 5G-NR serving + neighbor cell measurements as single-line key=value records to stdout:

pci=..,earfcn=..,earfcn_ul=..,frequency=..,protocol=lte|nr,cell=scell|ncell,plmn=..,mcc=..,mnc=..,tac=..,cid=..,band=..,bwmhzdl=..,bwmhzul=.. rssi=..,rsrp=..,rsrq=..
  • Frequency in Hz (3GPP TS 36.101 / 38.104 tables), real LTE UL-EARFCN.
  • Stateful RRC↔ML1 identity join: a per-radio serving-cell cache from RRC SCell Info is merged onto ML1 measurements, guarded on (earfcn, pci) so no stale identity; neighbors stay 0.
  • Order-independent CellID: the RRC SCell Info parser emits its own identity-bearing serving line (CellID/TAC/PLMN) joined to the last ML1 serving signal, so CellID is captured even when the RRC packet precedes the next measurement.

--meas-gsmtap — measurements into the PCAP

Writes the measurements as GSMTAPv3 SIGNAL_STATUS_REPORT packets so RSRP/RSRQ/RSSI/SINR show in Wireshark (NR uses the SS_* tags). Also fixes a latent bug in create_gsmtap_header's v3 metadata packing (float tags only worked for integer values).

Compatibility

Default output (no flags) is unchanged. New util helpers: dl_earfcn_to_frequency_hz, nrarfcn_to_frequency_hz, format_cell_kv, format_plmn, serving_identity_fields, build_signal_status_report. Full suite: 107 passing (new tests/test_cell_kv.py, tests/test_meas_gsmtap.py).

Requires GSMTAPv3-capable Wireshark (or the repo's wireshark/scat.lua) to dissect the signal reports.

🤖 Generated with Claude Code

shark-fi and others added 6 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>
feat: --cell-kv machine-readable cell output + NR serving-cell fixes
…-gsmtap)

Consolidates the cell-measurement work (supersedes the stacked PRs fgsect#150, #1, #2).

--cell-kv: emit LTE and 5G-NR serving and neighbor cell measurements as key=value
lines to stdout for machine parsing. Frequency in Hz (3GPP TS 36.101 / 38.104
tables), real LTE UL-EARFCN, and a stateful RRC<->ML1 identity join (per-radio
serving-cell cache from RRC SCell Info merged onto ML1 measurements, guarded on
(earfcn, pci) so no stale identity; neighbors stay 0).

--meas-gsmtap: also write the measurements into the capture as GSMTAPv3
SIGNAL_STATUS_REPORT packets, so RSRP/RSRQ/RSSI/SINR are visible in Wireshark
(NR uses the SS_* tags). Fixes a latent float-packing bug in create_gsmtap_header's
v3 metadata (float tags only worked for int values).

CellID capture is order-independent: cache the latest ML1 serving signal so the RRC
SCell Info parser emits its own identity-bearing serving-cell line (CellID/TAC/PLMN)
joined to that signal, even when the RRC packet arrives before the next measurement.

Default (no flags) output is unchanged. util helpers: dl_earfcn_to_frequency_hz,
nrarfcn_to_frequency_hz, format_cell_kv, format_plmn, serving_identity_fields,
build_signal_status_report. Full suite: 107 pass.

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

peremen commented Sep 8, 2026

Copy link
Copy Markdown
Member

I see that the feature would be useful, but I want to digest the content first. Keep in mind that Samsung baseband also supports similar LTE measurement (5G equivalent is coming soon), and there is a generic lack of 2G/3G measurement. Yes, most countries are shutting down them but they are still alive.

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.

2 participants