1use crate::delta::Delta;
2use crate::error::SpatialError;
3use crate::types::*;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
7pub enum FrameMode {
8 Absolute = 0x00,
9 Delta = 0x01,
10}
11
12#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
13pub struct SpatialFrameHeader {
14 pub mode: FrameMode,
15 pub sequence_id: u32,
16 pub timestamp: u64, pub checksum: u32, }
19
20#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21pub struct SpatialFrame {
22 pub header: SpatialFrameHeader,
23 pub payload: SpatialValue,
24}
25
26#[derive(Debug, Clone)]
27pub struct SpatialStreamerConfig {
28 pub abs_interval: u32,
29 pub enable_prediction: bool,
30 pub max_prediction_frames: u8,
31}
32
33impl Default for SpatialStreamerConfig {
34 fn default() -> Self {
35 Self {
36 abs_interval: 100,
37 enable_prediction: true,
38 max_prediction_frames: 3,
39 }
40 }
41}
42
43pub struct SpatialStreamer {
44 config: SpatialStreamerConfig,
45 sequence_counter: u32,
46 last_sent_state: Option<SpatialState>,
47
48 last_received_seq: Option<u32>,
50 current_state: Option<SpatialState>,
51 predicted_next: Option<Position3D>,
52 prediction_frame_count: u8,
53}
54
55impl SpatialStreamer {
56 pub fn new(abs_interval: u32) -> Self {
57 Self::with_config(SpatialStreamerConfig {
58 abs_interval,
59 ..Default::default()
60 })
61 }
62
63 pub fn with_config(config: SpatialStreamerConfig) -> Self {
64 Self {
65 config,
66 sequence_counter: 0,
67 last_sent_state: None,
68 last_received_seq: None,
69 current_state: None,
70 predicted_next: None,
71 prediction_frame_count: 0,
72 }
73 }
74
75 pub fn next_frame(
78 &mut self,
79 new_state: &SpatialState,
80 timestamp: u64,
81 ) -> Result<SpatialFrame, SpatialError> {
82 let seq = self.sequence_counter;
83 self.sequence_counter += 1;
84
85 let force_abs = seq.is_multiple_of(self.config.abs_interval);
86
87 let (mode, payload) = if force_abs || self.last_sent_state.is_none() {
88 (FrameMode::Absolute, SpatialValue::S10(new_state.clone()))
89 } else {
90 let delta =
91 SpatialState::compute_delta(self.last_sent_state.as_ref().unwrap(), new_state);
92 (FrameMode::Delta, SpatialValue::S13(delta))
93 };
94
95 self.last_sent_state = Some(new_state.clone());
96
97 if self.config.enable_prediction {
99 if let (Some(pos), Some(vel)) = (&new_state.position, &new_state.velocity) {
100 let dt = 0.001; self.predicted_next = Some(Position3D {
104 x: pos.x + vel.vx * dt,
105 y: pos.y + vel.vy * dt,
106 z: pos.z + vel.vz * dt,
107 });
108 }
109 }
110
111 let payload_bytes = bincode::serialize(&payload)
113 .map_err(|e| SpatialError::ValidationError(format!("Serialization error: {}", e)))?;
114 let checksum = crate::checksum::compute_checksum(&payload_bytes);
115
116 Ok(SpatialFrame {
117 header: SpatialFrameHeader {
118 mode,
119 sequence_id: seq,
120 timestamp,
121 checksum,
122 },
123 payload,
124 })
125 }
126
127 pub fn process_frame(&mut self, frame: &SpatialFrame) -> Result<&SpatialState, SpatialError> {
130 let payload_bytes = bincode::serialize(&frame.payload)
132 .map_err(|e| SpatialError::ValidationError(format!("Serialization error: {}", e)))?;
133
134 if !crate::checksum::verify_checksum(&payload_bytes, frame.header.checksum) {
135 return Err(SpatialError::ValidationError(
136 "Checksum mismatch! Frame corrupted.".into(),
137 ));
138 }
139
140 if let Some(last_seq) = self.last_received_seq {
142 if frame.header.sequence_id <= last_seq {
143 } else if frame.header.sequence_id > last_seq + 1 {
147 if frame.header.mode == FrameMode::Delta {
151 if self.config.enable_prediction && self.predicted_next.is_some() {
153 self.prediction_frame_count += 1;
155
156 if self.prediction_frame_count > self.config.max_prediction_frames {
157 return Err(SpatialError::ValidationError(format!(
159 "Prediction limit exceeded ({} frames). Waiting for ABS frame.",
160 self.prediction_frame_count
161 )));
162 }
163
164 if let Some(predicted_pos) = self.predicted_next {
166 if let Some(mut state) = self.current_state.clone() {
167 state.position = Some(predicted_pos);
168 self.current_state = Some(state);
169 }
170 }
171 } else {
172 return Err(SpatialError::ValidationError(format!(
174 "Packet loss detected (gap {} -> {}). Waiting for ABS frame.",
175 last_seq, frame.header.sequence_id
176 )));
177 }
178 }
179 }
180 }
181
182 match frame.header.mode {
184 FrameMode::Absolute => {
185 if let SpatialValue::S10(state) = &frame.payload {
186 self.current_state = Some(state.clone());
187 self.prediction_frame_count = 0;
189 } else {
190 return Err(SpatialError::ValidationError(
191 "ABS frame must contain SpatialState".into(),
192 ));
193 }
194 }
195 FrameMode::Delta => {
196 if let SpatialValue::S13(delta) = &frame.payload {
197 if let Some(current) = &self.current_state {
198 let new_state = SpatialState::apply_delta(current, delta);
208 self.current_state = Some(new_state);
209 } else {
210 return Err(SpatialError::ValidationError(
211 "Received DELTA frame without prior ABS state".into(),
212 ));
213 }
214 } else {
215 return Err(SpatialError::ValidationError(
216 "DELTA frame must contain SpatialDelta".into(),
217 ));
218 }
219 }
220 }
221
222 self.last_received_seq = Some(frame.header.sequence_id);
223
224 Ok(self.current_state.as_ref().unwrap())
225 }
226}