- Fix KSUDP clutch field reading fuel at offset 59 (KSUDP has no clutch input) - Replace Notify with watch::channel for reliable shutdown (no missed wakeups) - Deduplicate read_u16 from parser_pcars into shared binary_utils - Remove dead Display impl for FeedSource - Remove unused read_i8 helper from binary_utils - Change Vec<Instant> to [Instant; 50] in FeedState (eliminate heap alloc) - Cache rarely-changing strings by driver_id in Telemetry Tool parser
107 lines
3.9 KiB
Rust
107 lines
3.9 KiB
Rust
//! Shared binary reading helpers for UDP packet parsers.
|
|
//!
|
|
//! All helpers use `get()` for safe bounds checking — they return a zero/empty
|
|
//! fallback instead of panicking when the offset is out of bounds.
|
|
|
|
use crate::telemetry_frame::NUM_WHEELS;
|
|
|
|
/// Read a `bool` (1 byte) from the data at the given offset.
|
|
/// Returns `false` if the offset is out of bounds.
|
|
pub fn read_bool(data: &[u8], offset: usize) -> bool {
|
|
data.get(offset).map(|&b| b != 0).unwrap_or(false)
|
|
}
|
|
|
|
/// Read a little-endian `u32` from the data at the given offset.
|
|
/// Returns 0 if the offset is out of bounds (safe fallback for malformed packets).
|
|
pub fn read_u32(data: &[u8], offset: usize) -> u32 {
|
|
let buf: [u8; 4] = data
|
|
.get(offset..offset + 4)
|
|
.and_then(|s| s.try_into().ok())
|
|
.unwrap_or([0u8; 4]);
|
|
u32::from_le_bytes(buf)
|
|
}
|
|
|
|
/// Read a little-endian `i32` from the data at the given offset.
|
|
/// Returns 0 if the offset is out of bounds (safe fallback for malformed packets).
|
|
pub fn read_i32(data: &[u8], offset: usize) -> i32 {
|
|
let buf: [u8; 4] = data
|
|
.get(offset..offset + 4)
|
|
.and_then(|s| s.try_into().ok())
|
|
.unwrap_or([0u8; 4]);
|
|
i32::from_le_bytes(buf)
|
|
}
|
|
|
|
/// Read a little-endian `i16` from the data at the given offset.
|
|
/// Returns 0 if the offset is out of bounds (safe fallback for malformed packets).
|
|
pub fn read_i16(data: &[u8], offset: usize) -> i16 {
|
|
let buf: [u8; 2] = data
|
|
.get(offset..offset + 2)
|
|
.and_then(|s| s.try_into().ok())
|
|
.unwrap_or([0u8; 2]);
|
|
i16::from_le_bytes(buf)
|
|
}
|
|
|
|
/// Read a little-endian `u16` from the data at the given offset.
|
|
/// Returns 0 if the offset is out of bounds (safe fallback for malformed packets).
|
|
pub fn read_u16(data: &[u8], offset: usize) -> u16 {
|
|
let buf: [u8; 2] = data
|
|
.get(offset..offset + 2)
|
|
.and_then(|s| s.try_into().ok())
|
|
.unwrap_or([0u8; 2]);
|
|
u16::from_le_bytes(buf)
|
|
}
|
|
|
|
/// Read a little-endian `f32` from the data at the given offset.
|
|
/// Returns 0.0 if the offset is out of bounds (safe fallback for malformed packets).
|
|
pub fn read_f32(data: &[u8], offset: usize) -> f32 {
|
|
let buf: [u8; 4] = data
|
|
.get(offset..offset + 4)
|
|
.and_then(|s| s.try_into().ok())
|
|
.unwrap_or([0u8; 4]);
|
|
f32::from_le_bytes(buf)
|
|
}
|
|
|
|
/// Read a little-endian `f64` from the data at the given offset.
|
|
/// Returns 0.0 if the offset is out of bounds (safe fallback for malformed packets).
|
|
pub fn read_f64(data: &[u8], offset: usize) -> f64 {
|
|
let buf: [u8; 8] = data
|
|
.get(offset..offset + 8)
|
|
.and_then(|s| s.try_into().ok())
|
|
.unwrap_or([0u8; 8]);
|
|
f64::from_le_bytes(buf)
|
|
}
|
|
|
|
/// Read an array of 4 little-endian `f32` from the data at the given offset.
|
|
pub fn read_f32_4(data: &[u8], offset: usize) -> [f32; NUM_WHEELS] {
|
|
let mut arr = [0.0f32; NUM_WHEELS];
|
|
for i in 0..NUM_WHEELS {
|
|
arr[i] = read_f32(data, offset + i * 4);
|
|
}
|
|
arr
|
|
}
|
|
|
|
/// Read an array of 2 little-endian `f32` from the data at the given offset.
|
|
pub fn read_f32_2(data: &[u8], offset: usize) -> [f32; 2] {
|
|
[read_f32(data, offset), read_f32(data, offset + 4)]
|
|
}
|
|
|
|
/// Read an array of 3 little-endian `f32` from the data at the given offset.
|
|
pub fn read_f32_3(data: &[u8], offset: usize) -> [f32; 3] {
|
|
[read_f32(data, offset), read_f32(data, offset + 4), read_f32(data, offset + 8)]
|
|
}
|
|
|
|
/// Read an array of 3 little-endian `i32` from the data at the given offset.
|
|
pub fn read_i32_3(data: &[u8], offset: usize) -> [i32; 3] {
|
|
[read_i32(data, offset), read_i32(data, offset + 4), read_i32(data, offset + 8)]
|
|
}
|
|
|
|
/// Read a null-terminated/padded ASCII string.
|
|
/// Returns an empty string if the offset is out of bounds.
|
|
pub fn read_string(data: &[u8], offset: usize, len: usize) -> String {
|
|
let slice = match data.get(offset..offset + len) {
|
|
Some(s) => s,
|
|
None => return String::new(),
|
|
};
|
|
let end = slice.iter().position(|&b| b == 0).unwrap_or(len);
|
|
String::from_utf8_lossy(&slice[..end]).to_string()
|
|
}
|