Repository navigation
Releases
diaggrok 2026.11.8.post1
diaggrok 2026.11.8.post1: a README-only post-release of v2026.11.8.
README only: the Installation section now says pip install diaggrok. The
v2026.11.8 README still said diaggrok was not on PyPI, and PyPI never lets a
published version's description change, so this post-release carries the fix.
The code is identical to v2026.11.8.
On PyPI: pip install diaggrok==2026.11.8.post1, the same code as this tag.
diaggrok 2026.11.8
diaggrok 2026.11.8, the first release on PyPI. The same notes are the v2026.11.8 section of CHANGELOG.md.
On PyPI: diaggrok 2026.11.8 is the same code as this tag. Its PyPI page shows the README this tag shipped, which still said diaggrok was not on PyPI; v2026.11.8.post1 fixes that.
First release published to PyPI (pip install diaggrok). 197 log codes: the
196 of v2026.10.31 plus one new parser, 0xB9A6. No parser was removed.
Three record shapes change in ways that can break code reading them (below);
every other shape change adds fields.
New log code
| code | name | record type |
|---|---|---|
0xB9A6 |
NR cell acquisition timeline (per-stage frame and USTMR stamps, RF config id, target cell's SSB and UL-centre NR-ARFCN) | Diag0xB9A6 |
It is grounded on the firmware's own F3 text for both versions it decodes
(v0x01, v0x02). Its shared time-word decode ships as
parsers/_nr_acq_b9be_b9bf.py, which registers no parser of its own.
Breaking: removed, renamed or re-typed fields
| record | change |
|---|---|
DplRecord (0x11EB and the other DPL codes) |
counter is removed. The old 24-bit "counter" is two fields: packet_seq and segment, plus last_segment (bool). |
Diag0xB8DD |
slot is removed: it was mis-modelled. The bits it read are sfn_word_hi6. |
Diag0x1476 |
num_gps_svs, num_glo_svs, num_bds_svs, total_gps_svs, total_glo_svs and total_bds_svs are int | None: None on the v21 form, which does not carry them, instead of a misread number. |
Diag0xB825 |
cells is always a list (list[dict[str, Any]]), never None; each cell also carries its raw wire words. |
Diag0x1886 |
svs items may also be the new Sdx55GalSv. |
Decode changes in existing parsers
0x1886(GNSS Galileo measurement) decodes the SDX55 variable-length
variant (Sdx55GalSv).0x197Fdecodes its 9,244 B capture form (Diag0x197FCapture).0xB180decodes thev0x048 + N×32form, picking the stride from the
record size.0xB063frames records whose RLC extension the strict layout rejected, and
marks themframing_relaxed.0xB064decodes subpacket 8 versions 5, 7 and 8.0x18AEand0x4177fix lossy reads: values that were truncated or skipped
are now exposed (see Fields added).0x1476: thev24/v26SV-block tails and thev21tail are kept raw.
A cut MDM9600 record is rejected instead of half-decoded.0x506A:to_dict()'stail_rawis JSON-safe.- Every record these parsers now drop logs a warning saying why.
codes:0x4801isLOG_WCDMA_RRC_ACQ_SUMMARY_INFORMATION(it is a WCDMA
code).LOG_LTE_CELL_SEARCH_RESULTSremains as a deprecated alias.
Fields added
| record | added fields |
|---|---|
Diag0x1476 |
sv_block_568_raw, sv_block_602_raw, sv_block_612_raw, sv_pad_566, sv_pad_600, v21_tail_raw |
Diag0x18AE |
full_hdr_raw, full_trailer_raw, gts_raw_25, gts_raw_2_6, gts_raw_34, gts_raw_43, gts_raw_52_75, gts_raw_u32_48, timer_19m2 |
Diag0x4177 |
hdr_count, hdr_s16, hdr_u16_at23, hdr_u16_at34, hdr_u16_at8, hdr_var_raw, hdr_word |
Diag0xB063 |
framing_relaxed |
Diag0xB0CD |
tail_bytes |
Diag0xB0EE |
guti_plmn_raw |
Diag0xB823 |
tac, nr_band, rel_major, word_22 |
Diag0xB825 |
bands, blocks |
Diag0xB8DD |
sfn_word_hi6 |
HdlcStats |
qsh_trace_sub_stream_frames |
diaggrok 2026.10.31
diaggrok 2026.10.31. The same notes are the v2026.10.31 section of CHANGELOG.md.
196 log codes: the 191 of v2026.10.26 plus five new parsers, 0x1377,
0x1383, 0x13C4, 0x1756 and 0xB181. No parser was removed, and no
record field was removed, renamed or re-typed: every shape change below adds
fields. One module is new outside the parsers: ts64_cal.py (see below).
New log codes
| code | name | record type |
|---|---|---|
0x1377 |
CGPS report event log packet (GNSS session events) | Diag0x1377 |
0x1383 |
CGPS PDSM extended-status position report (each final, intermediate or seed fix) | Diag0x1383 |
0x13C4 |
CGPS measurement-engine time-estimate put (GPS week / ms clock, bias, uncertainty) | Diag0x13C4 |
0x1756 |
GNSS BeiDou B1I measurement report (per-SV) | Diag0x1756 |
0xB181 |
LTE ML1 intra-frequency cell reselection (serving EARFCN / PCI, per-frequency reselection lists) | Diag0xB181 |
All five are grounded on the firmware's own F3 text for every version they
decode. 0xB181's subpackets must tile the record exactly; a record that does
not is rejected (None, with a warning), which no corpus record does.
ts64_cal — capture-clock calibration
diaggrok.ts64_cal now ships whenever 0x1476 does. It maps the DIAG ts64
counter to UTC from the capture's own 0x1476 GNSS fixes, fitting the tick rate
rather than assuming it, and applies the GPS-UTC leap-second offset. It is what
diagmunge-dlf-to-pcap uses for calibrated pcap timestamps; without it that
tool falls back to a synthetic clock.
Decode changes in existing parsers
0xB18F(LTE ML1 AdvRx IC cell list) decodesv0x18(512 B, MDM9240), which
was previously rejected: the 34 B head ofv0x20with 28 B cell slots that
carry nodl_bw_rb/num_rx_ant_candidate(bothNoneonv0x18).0xB18B(LTE ML1 sleep) decodes the 64 Bv0x01form (MDM9625) as the 60 B
form's 16-bit EARFCN + PCI; it previously fell back to an out-of-range 32-bit
EARFCN. A record one byte short of 64 B is now rejected.0xB0C0v0x1e: connected-mode channels 8..11 decode (thev26/v27layout).0xB193: thev48/v59family uses constant strides.0x1476: the GLONASS time triplet is decoded on the v13+ and MDM9600 paths too.0x1807: every f32 site keeps its raw u32 word, so an sNaN lane survives a
rebuild of the record.0xB823: bytes [9:17] are a 60-bit NCGI: PLMN (ncgi_mcc,ncgi_mnc) and
36-bitncgi_nci, pluscell_global_id.
Fields added
| record | added fields |
|---|---|
Diag0x1476 |
clock_block_raw, ellipse_sensor_raw, failure_code, fake_align, fix_events, hdr_gap_raw, pos_count, pos_vel_flag, pos_vel_flag2, post_dop_raw, reserved1; to_dict() key struct_raw |
Diag0x14FD |
aux1_lat_raw, aux1_lon_raw, aux2_lat_raw, aux2_lon_raw, cell_lat_raw, cell_lon_raw, raw |
Diag0x1526V01 |
aux_b8_27_raw |
Diag0x1807 |
fmt_b30, gps_ms_of_week, gps_week, hb_trailer_word, hdr_tail_raw, medium_b27_raw, medium_body_words, medium_fmt_b31, medium_fmt_b32, medium_word_23 |
Diag0x1807FineCell / Diag0x1807MeasRow |
meas_a_word, meas_b_word / lane_words |
Diag0x1874V0c |
flag_6, flag_11 |
Diag0x1C7Cv2Sub* (8 types) |
entries (dataclass); tags (to_dict()) |
Diag0xB0C0 |
aux_b3_raw, bearer_word_lo |
Diag0xB17F |
aux_b1_raw, aux_word_raw, rsrp_avg_word, rsrp_word, rsrq_word, rssi_word, squal_word, srxlev_word |
Diag0xB18F cells (v0x18) |
raw_10 in place of raw_14 (the 28 B slot's trailing bytes) |
Diag0xB192 |
num_subpackets, request_earfcn, request_num_cells_flag, request_sp_version; LteMl1NeighborCellEntry.timing1; LteMl1NeighborRequestCell.pci_raw |
Diag0xB193 |
body_raw, num_subpackets, subpacket_id, subpacket_size; LteMl1ServingCellMeasEntry.cell_index, .pci_word |
Diag0xB195 |
counter, request_cells, request_header, request_sp_version, request_trailing, response_trailing; new LteMl1ConnectedNeighborRequestCell |
Diag0xB821 |
reserved_raw, trailing_raw |
Diag0xB823 |
cell_global_id, ncgi_mcc, ncgi_mnc, ncgi_nci |
Diag0xB97F |
trailing_raw |
Install: pip install "diaggrok @ git+https://github.com/lukejenkins/diaggrok@v2026.10.31"