Optimised failed test

This commit is contained in:
Martino Ferrari
2026-02-25 21:07:27 +01:00
parent dfb399bbba
commit f8f04856ed
17 changed files with 1842 additions and 557 deletions

View File

@@ -342,7 +342,7 @@ fn tcp_command_worker(shared_config: Arc<Mutex<ConnectionConfig>>, rx_cmd: Recei
let trimmed = line.trim();
if trimmed.is_empty() { line.clear(); continue; }
if !in_json && trimmed.starts_with("{") { in_json = true; json_acc.clear(); }
if !in_json && (trimmed.starts_with("{") || trimmed.starts_with("[")) { in_json = true; json_acc.clear(); }
if in_json {
json_acc.push_str(trimmed);
@@ -439,6 +439,7 @@ fn udp_worker(shared_config: Arc<Mutex<ConnectionConfig>>, id_to_meta: Arc<Mutex
let mut socket: Option<UdpSocket> = None;
let mut last_seq: Option<u32> = None;
let mut last_warning_time = std::time::Instant::now();
let mut first_packet = true;
loop {
let (ver, port) = { let config = shared_config.lock().unwrap(); (config.version, config.udp_port.clone()) };
@@ -460,6 +461,7 @@ fn udp_worker(shared_config: Arc<Mutex<ConnectionConfig>>, id_to_meta: Arc<Mutex
if !bound { thread::sleep(std::time::Duration::from_secs(5)); continue; }
let _ = socket.as_ref().unwrap().set_read_timeout(Some(std::time::Duration::from_millis(500)));
last_seq = None;
first_packet = true;
}
let s = if let Some(sock) = socket.as_ref() { sock } else { thread::sleep(std::time::Duration::from_secs(1)); continue; };
let mut buf = [0u8; 4096];
@@ -468,9 +470,14 @@ fn udp_worker(shared_config: Arc<Mutex<ConnectionConfig>>, id_to_meta: Arc<Mutex
if shared_config.lock().unwrap().version != current_version { break; }
if let Ok(n) = s.recv(&mut buf) {
total_packets += 1;
if (total_packets % 500) == 0 { let _ = tx_events.send(InternalEvent::UdpStats(total_packets)); }
if (total_packets % 10) == 0 { let _ = tx_events.send(InternalEvent::UdpStats(total_packets)); }
if first_packet {
let _ = tx_events.send(InternalEvent::InternalLog("First UDP packet received!".to_string()));
first_packet = false;
}
if n < 20 { continue; }
if u32::from_le_bytes(buf[0..4].try_into().unwrap()) != 0xDA7A57AD { continue; }
let magic = u32::from_le_bytes(buf[0..4].try_into().unwrap());
if magic != 0xDA7A57AD { continue; }
let seq = u32::from_le_bytes(buf[4..8].try_into().unwrap());
if let Some(last) = last_seq { if seq != last + 1 && seq > last { let _ = tx_events.send(InternalEvent::UdpDropped(seq - last - 1)); } }
last_seq = Some(seq);
@@ -482,7 +489,7 @@ fn udp_worker(shared_config: Arc<Mutex<ConnectionConfig>>, id_to_meta: Arc<Mutex
let metas = id_to_meta.lock().unwrap();
if metas.is_empty() && count > 0 && last_warning_time.elapsed().as_secs() > 5 {
let _ = tx_events.send(InternalEvent::InternalLog("UDP received but Metadata empty. Still discovering?".to_string()));
let _ = tx_events.send(InternalEvent::InternalLog(format!("UDP received but Metadata empty ({} known). Still discovering?", metas.len())));
last_warning_time = std::time::Instant::now();
}
@@ -497,24 +504,43 @@ fn udp_worker(shared_config: Arc<Mutex<ConnectionConfig>>, id_to_meta: Arc<Mutex
let data_slice = &buf[offset..offset + size as usize];
let mut base_ts_guard = BASE_TELEM_TS.lock().unwrap();
if let Some(base) = *base_ts_guard {
let diff = if ts_raw > base { ts_raw - base } else { base - ts_raw };
if diff > 100_000_000 {
*base_ts_guard = Some(ts_raw);
let _ = tx_events.send(InternalEvent::InternalLog("Clock reset detected. Syncing base.".to_string()));
}
}
if base_ts_guard.is_none() { *base_ts_guard = Some(ts_raw); }
let base = base_ts_guard.unwrap();
let ts_s = if ts_raw >= base {
(ts_raw - base) as f64 / 1000000.0
} else {
0.0 // Avoid huge jitter wrap-around
0.0
};
drop(base_ts_guard);
if let Some(meta) = metas.get(&id) {
let _ = tx_events.send(InternalEvent::TelemMatched(id));
let t = meta.sig_type.as_str();
let t = meta.sig_type.to_lowercase();
let val = match size {
1 => { if t.contains('u') { data_slice[0] as f64 } else { (data_slice[0] as i8) as f64 } },
2 => { let b = data_slice[0..2].try_into().unwrap(); if t.contains('u') { u16::from_le_bytes(b) as f64 } else { i16::from_le_bytes(b) as f64 } },
4 => { let b = data_slice[0..4].try_into().unwrap(); if t.contains("float") { f32::from_le_bytes(b) as f64 } else if t.contains('u') { u32::from_le_bytes(b) as f64 } else { i32::from_le_bytes(b) as f64 } },
8 => { let b = data_slice[0..8].try_into().unwrap(); if t.contains("float") { f64::from_le_bytes(b) } else if t.contains('u') { u64::from_le_bytes(b) as f64 } else { i64::from_le_bytes(b) as f64 } },
4 => {
let b = data_slice[0..4].try_into().unwrap();
if t.contains("float") || (t.contains("32") && (t.contains('f') || t.contains("real"))) { f32::from_le_bytes(b) as f64 }
else if t.contains('u') { u32::from_le_bytes(b) as f64 }
else { i32::from_le_bytes(b) as f64 }
},
8 => {
let b = data_slice[0..8].try_into().unwrap();
if t.contains("float") || t.contains("double") || (t.contains("64") && (t.contains('f') || t.contains("real"))) { f64::from_le_bytes(b) }
else if t.contains('u') { u64::from_le_bytes(b) as f64 }
else { i64::from_le_bytes(b) as f64 }
},
_ => 0.0,
};
for name in &meta.names {
@@ -702,6 +728,16 @@ impl eframe::App for MarteDebugApp {
}
});
ui.separator();
ui.heading("Telemetry Stats");
let mut ids: Vec<_> = self.telem_match_count.keys().cloned().collect();
ids.sort();
if ids.is_empty() { ui.label("No IDs matched yet."); }
for id in ids {
if let Some(count) = self.telem_match_count.get(&id) {
ui.label(format!("ID {}: {} samples", id, count));
}
}
ui.separator();
ui.heading("Forced Signals");
for (path, val) in &self.forced_signals { ui.horizontal(|ui| { ui.label(format!("{}: {}", path, val)); if ui.button("").clicked() { let _ = self.tx_cmd.send(format!("UNFORCE {}", path)); } }); }
});

431
Tools/pipeline_validator/Cargo.lock generated Normal file
View File

@@ -0,0 +1,431 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bumpalo"
version = "3.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
[[package]]
name = "cc"
version = "1.2.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chrono"
version = "0.4.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "iana-time-zone"
version = "0.1.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "js-sys"
version = "0.3.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dc6f6450b3f6d4ed5b16327f38fed626d375a886159ca555bd7822c0c3a5a6"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.182"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "memchr"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "pipeline_validator"
version = "0.1.0"
dependencies = [
"chrono",
"serde",
"serde_json",
"socket2",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "socket2"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "wasm-bindgen"
version = "0.2.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60722a937f594b7fde9adb894d7c092fc1bb6612897c46368d18e7a20208eff2"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac8c6395094b6b91c4af293f4c79371c163f9a6f56184d2c9a85f5a95f3950"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab3fabce6159dc20728033842636887e4877688ae94382766e00b180abac9d60"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0e091bdb824da87dc01d967388880d017a0a9bc4f3bdc0d86ee9f9336e3bb5"
dependencies = [
"unicode-ident",
]
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"

View File

@@ -0,0 +1,10 @@
[package]
name = "pipeline_validator"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
socket2 = "0.5"
chrono = "0.4"

View File

@@ -0,0 +1,135 @@
use std::io::{Read, Write};
use std::net::{TcpStream, UdpSocket};
use std::time::{Duration, Instant};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct Signal {
name: String,
id: u32,
#[serde(rename = "type")]
sig_type: String,
ready: bool,
}
#[derive(Deserialize, Debug)]
struct DiscoverResponse {
#[serde(rename = "Signals")]
signals: Vec<Signal>,
}
fn main() {
println!("--- MARTe2 Debug Pipeline Validator ---");
// 1. Connect to TCP Control Port
let mut stream = match TcpStream::connect("127.0.0.1:8080") {
Ok(s) => {
println!("[TCP] Connected to DebugService on 8080");
s
}
Err(e) => {
println!("[TCP] FAILED to connect: {}", e);
println!("Check if 'run_debug_app.sh' is running.");
return;
}
};
stream.set_read_timeout(Some(Duration::from_secs(2))).unwrap();
// 2. DISCOVER signals
println!("[TCP] Sending DISCOVER...");
stream.write_all(b"DISCOVER\n").unwrap();
let mut buf = [0u8; 8192];
let n = stream.read(&mut buf).unwrap();
let resp = String::from_utf8_lossy(&buf[..n]);
// Split JSON from OK DISCOVER terminator
let json_part = resp.split("OK DISCOVER").next().unwrap_or("").trim();
let discovery: DiscoverResponse = match serde_json::from_str(json_part) {
Ok(d) => d,
Err(e) => {
println!("[TCP] Discovery Parse Error: {}", e);
println!("Raw Response: {}", resp);
return;
}
};
println!("[TCP] Found {} signals.", discovery.signals.len());
let mut counter_id = None;
for s in &discovery.signals {
println!("[TCP] Signal: {} (ID={}, Ready={})", s.name, s.id, s.ready);
if s.name.contains("Timer.Counter") {
println!("[TCP] Target found: {} (ID={})", s.name, s.id);
counter_id = Some(s.id);
// 3. Enable TRACE
println!("[TCP] Enabling TRACE for {}...", s.name);
stream.write_all(format!("TRACE {} 1\n", s.name).as_bytes()).unwrap();
let mut t_buf = [0u8; 1024];
let tn = stream.read(&mut t_buf).unwrap();
println!("[TCP] TRACE Response: {}", String::from_utf8_lossy(&t_buf[..tn]).trim());
}
}
if counter_id.is_none() {
println!("[TCP] ERROR: Counter signal not found in discovery.");
return;
}
// 4. Listen for UDP Telemetry
let socket = UdpSocket::bind("0.0.0.0:8081").expect("Could not bind UDP socket");
socket.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
println!("[UDP] Listening for telemetry on 8081...");
let mut samples_received = 0;
let mut last_val: Option<u32> = None;
let mut last_ts: Option<u64> = None;
let start_wait = Instant::now();
while samples_received < 20 && start_wait.elapsed().as_secs() < 10 {
let mut u_buf = [0u8; 4096];
if let Ok(n) = socket.recv(&mut u_buf) {
if n < 20 { continue; }
// Validate Header
let magic = u32::from_le_bytes(u_buf[0..4].try_into().unwrap());
if magic != 0xDA7A57AD { continue; }
let count = u32::from_le_bytes(u_buf[16..20].try_into().unwrap());
let mut offset = 20;
for _ in 0..count {
if offset + 16 > n { break; }
let id = u32::from_le_bytes(u_buf[offset..offset+4].try_into().unwrap());
let ts = u64::from_le_bytes(u_buf[offset+4..offset+12].try_into().unwrap());
let size = u32::from_le_bytes(u_buf[offset+12..offset+16].try_into().unwrap());
offset += 16;
if offset + size as usize > n { break; }
if id == counter_id.unwrap() && size == 4 {
let val = u32::from_le_bytes(u_buf[offset..offset+4].try_into().unwrap());
println!("[UDP] Match! ID={} TS={} VAL={}", id, ts, val);
if let Some(lt) = last_ts {
if ts <= lt { println!("[UDP] WARNING: Non-monotonic timestamp!"); }
}
if let Some(lv) = last_val {
if val == lv { println!("[UDP] WARNING: Stale value detected."); }
}
last_ts = Some(ts);
last_val = Some(val);
samples_received += 1;
}
offset += size as usize;
}
}
}
if samples_received >= 20 {
println!("\n[RESULT] SUCCESS: Telemetry pipeline is fully functional!");
} else {
println!("\n[RESULT] FAILURE: Received only {} samples.", samples_received);
}
}