From 892c833344960355376bc03ad7dabdc24bae8250 Mon Sep 17 00:00:00 2001 From: Will Greenberg Date: Fri, 26 Jun 2026 11:19:33 -0700 Subject: [PATCH] Add LL1 Serving Cell Timing messages This log should provide constant feedback about the serving cell's LTE timing advance value. --- lib/src/analysis/analyzer.rs | 9 ++--- lib/src/diag/diaglog/ll1.rs | 33 +++++++++++++++++++ lib/src/diag/diaglog/mac.rs | 3 +- .../diag/diaglog/{measurement.rs => ml1.rs} | 0 lib/src/diag/diaglog/mod.rs | 16 +++++++-- lib/src/diag/mod.rs | 3 +- lib/src/diag_device.rs | 33 ++++++++++--------- lib/src/log_codes.rs | 2 ++ 8 files changed, 73 insertions(+), 26 deletions(-) create mode 100644 lib/src/diag/diaglog/ll1.rs rename lib/src/diag/diaglog/{measurement.rs => ml1.rs} (100%) diff --git a/lib/src/analysis/analyzer.rs b/lib/src/analysis/analyzer.rs index f088b58..ebb6823 100644 --- a/lib/src/analysis/analyzer.rs +++ b/lib/src/analysis/analyzer.rs @@ -430,17 +430,14 @@ impl Harness { return row; } }; - let gsmtap_message = match gsmtap_parser::parse(qmdl_message) { - Ok(msg) => msg, + let (timestamp, gsmtap_msg) = match gsmtap_parser::parse(qmdl_message) { + Ok(Some(msg)) => msg, + Ok(None) => return row, Err(err) => { row.skipped_message_reason = Some(format!("{err:?}")); return row; } }; - - let Some((timestamp, gsmtap_msg)) = gsmtap_message else { - return row; - }; row.packet_timestamp = Some(timestamp.to_datetime()); let element = match InformationElement::try_from(&gsmtap_msg) { diff --git a/lib/src/diag/diaglog/ll1.rs b/lib/src/diag/diaglog/ll1.rs new file mode 100644 index 0000000..0022767 --- /dev/null +++ b/lib/src/diag/diaglog/ll1.rs @@ -0,0 +1,33 @@ +use deku::prelude::*; + +#[derive(Debug, Clone, PartialEq, DekuRead, DekuWrite)] +#[deku(bit_order = "lsb", ctx = "_: deku::ctx::Order")] +pub struct ServingCellTiming { + #[deku(assert_eq = "1")] + pub version: u8, + #[deku(bits = 5, assert = "*num_records <= 20")] + pub num_records: u8, + #[deku(bits = 4, assert = "*starting_sub_fn <= 9")] + pub starting_sub_fn: u8, + #[deku(bits = 10, pad_bits_after = "5", assert = "*starting_system_fn <= 1023")] + pub starting_system_fn: u16, + #[deku(bits = 19, pad_bits_after = "13", assert = "*starting_dl_frame_timing_offs <= 307200")] + pub starting_dl_frame_timing_offs: u32, // in Ts units + #[deku(bits = 19, assert = "*starting_ul_frame_timing_offs <= 307200")] + pub starting_ul_frame_timing_offs: u32, // in Ts units + #[deku(bits = 11, pad_bits_after = "2")] + pub starting_ul_timing_advance: u16, // in 16 Ts units + #[deku(count = "*num_records")] + pub timing_adjustment: Vec, +} + +#[derive(Debug, Clone, PartialEq, DekuRead, DekuWrite)] +#[deku(bit_order = "lsb", ctx = "_: deku::ctx::Order")] +pub struct TimingAdjustment { + #[deku(bits = 11, assert = "(-512..=511).contains(dl_frame_timing_adjustment)")] + pub dl_frame_timing_adjustment: i16, // in Ts units + #[deku(bits = 5, assert = "(-16..=15).contains(ul_frame_timing_adjustment)")] + pub ul_frame_timing_adjustment: i8, // in Ts units + #[deku(bits = 8, assert = "(-128..=127).contains(timing_advance)")] + pub timing_advance: i8, // in 16 Ts units +} diff --git a/lib/src/diag/diaglog/mac.rs b/lib/src/diag/diaglog/mac.rs index a1ed45f..5dddb1e 100644 --- a/lib/src/diag/diaglog/mac.rs +++ b/lib/src/diag/diaglog/mac.rs @@ -18,7 +18,8 @@ pub struct Subpacket { pub id: u8, pub version: u8, pub size: u16, - #[deku(ctx = "*id, *version, *size")] + // size includes the header length, so subtract that + #[deku(ctx = "*id, *version, *size - 4")] pub body: SubpacketBody, } diff --git a/lib/src/diag/diaglog/measurement.rs b/lib/src/diag/diaglog/ml1.rs similarity index 100% rename from lib/src/diag/diaglog/measurement.rs rename to lib/src/diag/diaglog/ml1.rs diff --git a/lib/src/diag/diaglog/mod.rs b/lib/src/diag/diaglog/mod.rs index da3af34..77b322b 100644 --- a/lib/src/diag/diaglog/mod.rs +++ b/lib/src/diag/diaglog/mod.rs @@ -3,8 +3,9 @@ use chrono::{DateTime, FixedOffset}; use deku::prelude::*; +pub mod ll1; pub mod mac; -pub mod measurement; +pub mod ml1; pub mod rrc; #[derive(Debug, Clone, PartialEq, DekuRead, DekuWrite)] @@ -79,14 +80,23 @@ pub enum LogBody { }, #[deku(id = "0xb17f")] LteMl1ServingCellMeasurementAndEvaluation { - data: measurement::serving_cell::MeasurementAndEvaluation, + data: ml1::serving_cell::MeasurementAndEvaluation, }, #[deku(id = "0xb180")] LteMl1NeighborCellsMeasurements { - data: measurement::neighbor_cells::Measurements, + data: ml1::neighbor_cells::Measurements, }, #[deku(id = "0xb062")] LteMacRachResponse { packet: mac::Packet }, + #[deku(id = "0xb063")] + LteMacDl { packet: mac::Packet }, + #[deku(id = "0xb064")] + LteMacUl { packet: mac::Packet }, + #[deku(id = "0xb114")] + LteLl1ServingCellTiming { + #[deku(ctx = "deku::ctx::Order::Lsb0")] + data: ll1::ServingCellTiming, + } } #[derive(Debug, Clone, PartialEq, DekuRead, DekuWrite)] diff --git a/lib/src/diag/mod.rs b/lib/src/diag/mod.rs index 3b58c7e..130acd3 100644 --- a/lib/src/diag/mod.rs +++ b/lib/src/diag/mod.rs @@ -166,8 +166,9 @@ impl Message { match body { LogBody::LteRrcOtaMessage { .. } => true, LogBody::LteMacRachResponse { .. } => true, + LogBody::LteMl1NeighborCellsMeasurements { .. } => true, LogBody::Nas4GMessage { .. } => true, - _ => false, + _ => false } } } diff --git a/lib/src/diag_device.rs b/lib/src/diag_device.rs index 2cd4900..ef291d7 100644 --- a/lib/src/diag_device.rs +++ b/lib/src/diag_device.rs @@ -40,27 +40,30 @@ pub enum DiagDeviceError { ParseMessagesContainerError(deku::DekuError), } -pub const LOG_CODES_FOR_RAW_PACKET_LOGGING: [u32; 14] = [ +pub const LOG_CODES_FOR_RAW_PACKET_LOGGING: [u32; 17] = [ // Layer 2: - log_codes::LOG_GPRS_MAC_SIGNALLING_MESSAGE_C, // 0x5226 + log_codes::LOG_GPRS_MAC_SIGNALLING_MESSAGE_C, // Layer 3: - log_codes::LOG_GSM_RR_SIGNALING_MESSAGE_C, // 0x512f - log_codes::WCDMA_SIGNALLING_MESSAGE, // 0x412f - log_codes::LOG_LTE_RRC_OTA_MSG_LOG_C, // 0xb0c0 - log_codes::LOG_NR_RRC_OTA_MSG_LOG_C, // 0xb821 + log_codes::LOG_GSM_RR_SIGNALING_MESSAGE_C, + log_codes::WCDMA_SIGNALLING_MESSAGE, + log_codes::LOG_LTE_RRC_OTA_MSG_LOG_C, + log_codes::LOG_NR_RRC_OTA_MSG_LOG_C, // NAS: - log_codes::LOG_UMTS_NAS_OTA_MESSAGE_LOG_PACKET_C, // 0x713a - log_codes::LOG_LTE_NAS_ESM_OTA_IN_MSG_LOG_C, // 0xb0e2 - log_codes::LOG_LTE_NAS_ESM_OTA_OUT_MSG_LOG_C, // 0xb0e3 - log_codes::LOG_LTE_NAS_EMM_OTA_IN_MSG_LOG_C, // 0xb0ec - log_codes::LOG_LTE_NAS_EMM_OTA_OUT_MSG_LOG_C, // 0xb0ed + log_codes::LOG_UMTS_NAS_OTA_MESSAGE_LOG_PACKET_C, + log_codes::LOG_LTE_NAS_ESM_OTA_IN_MSG_LOG_C, + log_codes::LOG_LTE_NAS_ESM_OTA_OUT_MSG_LOG_C, + log_codes::LOG_LTE_NAS_EMM_OTA_IN_MSG_LOG_C, + log_codes::LOG_LTE_NAS_EMM_OTA_OUT_MSG_LOG_C, // User IP traffic: - log_codes::LOG_DATA_PROTOCOL_LOGGING_C, // 0x11eb + log_codes::LOG_DATA_PROTOCOL_LOGGING_C, // LTE physical layer serving cell measurements: RSRP, RSRQ, RSSI - log_codes::LOG_LTE_ML1_SERVING_CELL_MEAS_AND_EVAL_C, // 0xb17f - log_codes::LOG_LTE_ML1_NEIGHBOR_MEAS, // 0xb180 + log_codes::LOG_LTE_ML1_SERVING_CELL_MEAS_AND_EVAL_C, + log_codes::LOG_LTE_ML1_NEIGHBOR_MEAS, // LTE MAC Random Access Channel response: contains Timing Advance - log_codes::LOG_LTE_MAC_RACH_RESPONSE_C, // 0xb062 + log_codes::LOG_LTE_MAC_RACH_RESPONSE_C, + log_codes::LOG_LTE_MAC_DL, + log_codes::LOG_LTE_MAC_UL, + 0xb114, // maybe timing advance related? ]; const BUFFER_LEN: usize = 1024 * 1024 * 10; diff --git a/lib/src/log_codes.rs b/lib/src/log_codes.rs index e0bcc34..b22170e 100644 --- a/lib/src/log_codes.rs +++ b/lib/src/log_codes.rs @@ -35,6 +35,8 @@ pub const LOG_LTE_RRC_OTA_MSG_LOG_C: u32 = 0xb0c0; pub const LOG_LTE_ML1_SERVING_CELL_MEAS_AND_EVAL_C: u32 = 0xb17f; pub const LOG_LTE_ML1_SERVING_CELL_MEAS_RESPONSE: u32 = 0xb193; pub const LOG_LTE_ML1_NEIGHBOR_MEAS: u32 = 0xb180; +pub const LOG_LTE_ML1_MAC_RAR_MSG1_REPORT: u32 = 0xb167; +pub const LOG_LTE_ML1_MAC_RAR_MSG2_REPORT: u32 = 0xb168; // Qualcomm MAC layer RACH response log: contains Timing Advance from Random Access Response pub const LOG_LTE_MAC_RACH_RESPONSE_C: u32 = 0xb062; pub const LOG_LTE_MAC_DL: u32 = 0xb063;