use crate::delta::Delta;
use crate::error::SpatialError;
use crate::types::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum FrameMode {
Absolute = 0x00,
Delta = 0x01,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct SpatialFrameHeader {
pub mode: FrameMode,
pub sequence_id: u32,
pub timestamp: u64, pub checksum: u32, }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SpatialFrame {
pub header: SpatialFrameHeader,
pub payload: SpatialValue,
}
#[derive(Debug, Clone)]
pub struct SpatialStreamerConfig {
pub abs_interval: u32,
pub enable_prediction: bool,
pub max_prediction_frames: u8,
}
impl Default for SpatialStreamerConfig {
fn default() -> Self {
Self {
abs_interval: 100,
enable_prediction: true,
max_prediction_frames: 3,
}
}
}
pub struct SpatialStreamer {
config: SpatialStreamerConfig,
sequence_counter: u32,
last_sent_state: Option<SpatialState>,
last_received_seq: Option<u32>,
current_state: Option<SpatialState>,
predicted_next: Option<Position3D>,
prediction_frame_count: u8,
}
impl SpatialStreamer {
pub fn new(abs_interval: u32) -> Self {
Self::with_config(SpatialStreamerConfig {
abs_interval,
..Default::default()
})
}
pub fn with_config(config: SpatialStreamerConfig) -> Self {
Self {
config,
sequence_counter: 0,
last_sent_state: None,
last_received_seq: None,
current_state: None,
predicted_next: None,
prediction_frame_count: 0,
}
}
pub fn next_frame(
&mut self,
new_state: &SpatialState,
timestamp: u64,
) -> Result<SpatialFrame, SpatialError> {
let seq = self.sequence_counter;
self.sequence_counter += 1;
let force_abs = seq.is_multiple_of(self.config.abs_interval);
let (mode, payload) = if force_abs || self.last_sent_state.is_none() {
(FrameMode::Absolute, SpatialValue::S10(new_state.clone()))
} else {
let delta =
SpatialState::compute_delta(self.last_sent_state.as_ref().unwrap(), new_state);
(FrameMode::Delta, SpatialValue::S13(delta))
};
self.last_sent_state = Some(new_state.clone());
if self.config.enable_prediction {
if let (Some(pos), Some(vel)) = (&new_state.position, &new_state.velocity) {
let dt = 0.001; self.predicted_next = Some(Position3D {
x: pos.x + vel.vx * dt,
y: pos.y + vel.vy * dt,
z: pos.z + vel.vz * dt,
});
}
}
let payload_bytes = bincode::serialize(&payload)
.map_err(|e| SpatialError::ValidationError(format!("Serialization error: {}", e)))?;
let checksum = crate::checksum::compute_checksum(&payload_bytes);
Ok(SpatialFrame {
header: SpatialFrameHeader {
mode,
sequence_id: seq,
timestamp,
checksum,
},
payload,
})
}
pub fn process_frame(&mut self, frame: &SpatialFrame) -> Result<&SpatialState, SpatialError> {
let payload_bytes = bincode::serialize(&frame.payload)
.map_err(|e| SpatialError::ValidationError(format!("Serialization error: {}", e)))?;
if !crate::checksum::verify_checksum(&payload_bytes, frame.header.checksum) {
return Err(SpatialError::ValidationError(
"Checksum mismatch! Frame corrupted.".into(),
));
}
if let Some(last_seq) = self.last_received_seq {
if frame.header.sequence_id <= last_seq {
} else if frame.header.sequence_id > last_seq + 1 {
if frame.header.mode == FrameMode::Delta {
if self.config.enable_prediction && self.predicted_next.is_some() {
self.prediction_frame_count += 1;
if self.prediction_frame_count > self.config.max_prediction_frames {
return Err(SpatialError::ValidationError(format!(
"Prediction limit exceeded ({} frames). Waiting for ABS frame.",
self.prediction_frame_count
)));
}
if let Some(predicted_pos) = self.predicted_next {
if let Some(mut state) = self.current_state.clone() {
state.position = Some(predicted_pos);
self.current_state = Some(state);
}
}
} else {
return Err(SpatialError::ValidationError(format!(
"Packet loss detected (gap {} -> {}). Waiting for ABS frame.",
last_seq, frame.header.sequence_id
)));
}
}
}
}
match frame.header.mode {
FrameMode::Absolute => {
if let SpatialValue::S10(state) = &frame.payload {
self.current_state = Some(state.clone());
self.prediction_frame_count = 0;
} else {
return Err(SpatialError::ValidationError(
"ABS frame must contain SpatialState".into(),
));
}
}
FrameMode::Delta => {
if let SpatialValue::S13(delta) = &frame.payload {
if let Some(current) = &self.current_state {
let new_state = SpatialState::apply_delta(current, delta);
self.current_state = Some(new_state);
} else {
return Err(SpatialError::ValidationError(
"Received DELTA frame without prior ABS state".into(),
));
}
} else {
return Err(SpatialError::ValidationError(
"DELTA frame must contain SpatialDelta".into(),
));
}
}
}
self.last_received_seq = Some(frame.header.sequence_id);
Ok(self.current_state.as_ref().unwrap())
}
}