diff --git a/src/main.rs b/src/main.rs index 106d45b..4105a99 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,12 +15,11 @@ use bbl_parser::conversion::{ // Import parser types from crate library use bbl_parser::parser::{ - parse_frame_data, BBLDataStream, ENCODING_NEG_14BIT, ENCODING_NULL, ENCODING_SIGNED_VB, - ENCODING_TAG2_3S32, ENCODING_UNSIGNED_VB, + parse_e_frame, parse_frame_data, parse_h_frame, parse_s_frame, BBLDataStream, }; // Import types from crate library -use bbl_parser::types::FrameDefinition; +use bbl_parser::types::{EventFrame, FrameDefinition}; /// Maximum recursion depth to prevent stack overflow const MAX_RECURSION_DEPTH: usize = 100; @@ -300,16 +299,6 @@ struct GpsHomeCoordinate { timestamp_us: u64, } -// Event structure for JSON export -#[derive(Debug, Clone)] -struct EventFrame { - timestamp_us: u64, - event_type: u8, - #[allow(dead_code)] - event_data: Vec, - event_name: String, -} - #[derive(Debug)] struct BBLLog { log_number: usize, @@ -2304,310 +2293,9 @@ fn parse_frames( )) } -#[allow(dead_code)] -fn parse_i_frame( - stream: &mut BBLDataStream, - frame_def: &FrameDefinition, - debug: bool, -) -> Result> { - let mut data = HashMap::new(); - - // Parse each field according to the frame definition - for field in &frame_def.fields { - let value = match field.encoding { - ENCODING_SIGNED_VB => stream.read_signed_vb()?, - ENCODING_UNSIGNED_VB => stream.read_unsigned_vb()? as i32, - ENCODING_NEG_14BIT => stream.read_neg_14bit()?, - ENCODING_NULL => 0, - _ => { - if debug { - println!( - "Unsupported I-frame encoding {} for field {}", - field.encoding, field.name - ); - } - 0 - } - }; - - data.insert(field.name.clone(), value); - } - - Ok(data) -} - -fn parse_s_frame( - stream: &mut BBLDataStream, - frame_def: &FrameDefinition, - debug: bool, -) -> Result> { - let mut data = HashMap::new(); - let mut field_index = 0; - - while field_index < frame_def.fields.len() { - let field = &frame_def.fields[field_index]; - - match field.encoding { - ENCODING_SIGNED_VB => { - let value = stream.read_signed_vb()?; - data.insert(field.name.clone(), value); - field_index += 1; - } - ENCODING_UNSIGNED_VB => { - let value = stream.read_unsigned_vb()? as i32; - data.insert(field.name.clone(), value); - field_index += 1; - } - ENCODING_NEG_14BIT => { - let value = stream.read_neg_14bit()?; - data.insert(field.name.clone(), value); - field_index += 1; - } - ENCODING_TAG2_3S32 => { - // This encoding handles 3 fields at once - let mut values = [0i32; 8]; - stream.read_tag2_3s32(&mut values)?; - - #[allow(clippy::needless_range_loop)] - for j in 0..3 { - if field_index + j < frame_def.fields.len() { - let current_field = &frame_def.fields[field_index + j]; - data.insert(current_field.name.clone(), values[j]); - } - } - field_index += 3; - } - ENCODING_NULL => { - data.insert(field.name.clone(), 0); - field_index += 1; - } - _ => { - if debug { - println!( - "Unsupported S-frame encoding {} for field {}", - field.encoding, field.name - ); - } - // For unsupported encodings, try to read as signed VB - let value = stream.read_signed_vb().unwrap_or(0); - data.insert(field.name.clone(), value); - field_index += 1; - } - } - } - - Ok(data) -} - -fn parse_h_frame( - stream: &mut BBLDataStream, - frame_def: &FrameDefinition, - debug: bool, -) -> Result> { - let mut data = HashMap::new(); - - if debug { - println!("Parsing H frame with {} fields", frame_def.count); - } - - // H frames contain GPS home position data - for (i, field) in frame_def.fields.iter().enumerate() { - if i >= frame_def.count { - break; - } - - let value = match field.encoding { - ENCODING_SIGNED_VB => stream.read_signed_vb()?, - ENCODING_UNSIGNED_VB => stream.read_unsigned_vb()? as i32, - ENCODING_NEG_14BIT => stream.read_neg_14bit()?, - ENCODING_NULL => 0, - _ => { - if debug { - println!( - "Unsupported H-frame encoding {} for field {}", - field.encoding, field.name - ); - } - stream.read_signed_vb().unwrap_or(0) - } - }; - - data.insert(field.name.clone(), value); - } - - Ok(data) -} - // Note: parse_g_frame is no longer used - G frames now use differential encoding // like P frames in the main parsing loop for correct GPS coordinate calculation -// Parse E frames (Event frames) - based on C reference implementation -fn parse_e_frame(stream: &mut BBLDataStream, debug: bool) -> Result { - if debug { - println!("Parsing E frame (Event frame)"); - } - - // Read event type (1 byte) - let event_type = stream.read_byte()?; - - // Read event data - the length depends on the event type - let mut event_data = Vec::new(); - let event_name = match event_type { - 0 => { - // FLIGHT_LOG_EVENT_SYNC_BEEP - "Sync beep".to_string() - } - 1 => { - // FLIGHT_LOG_EVENT_AUTOTUNE_CYCLE_START - "Autotune cycle start".to_string() - } - 2 => { - // FLIGHT_LOG_EVENT_AUTOTUNE_CYCLE_RESULT - let axis = stream.read_byte()?; - let p_gain = stream.read_signed_vb()? as f32 / 1000.0; - let i_gain = stream.read_signed_vb()? as f32 / 1000.0; - let d_gain = stream.read_signed_vb()? as f32 / 1000.0; - event_data.extend_from_slice(&[axis]); - format!( - "Autotune cycle result - Axis: {}, P: {:.3}, I: {:.3}, D: {:.3}", - axis, p_gain, i_gain, d_gain - ) - } - 3 => { - // FLIGHT_LOG_EVENT_AUTOTUNE_TARGETS - let current_angle = stream.read_signed_vb()?; - let target_angle = stream.read_signed_vb()?; - let target_angle_at_peak = stream.read_signed_vb()?; - let first_peak_angle = stream.read_signed_vb()?; - let second_peak_angle = stream.read_signed_vb()?; - format!("Autotune targets - Current: {}, Target: {}, Peak target: {}, First peak: {}, Second peak: {}", - current_angle, target_angle, target_angle_at_peak, first_peak_angle, second_peak_angle) - } - 4 => { - // FLIGHT_LOG_EVENT_INFLIGHT_ADJUSTMENT - let adjustment_function = stream.read_byte()?; - if adjustment_function > 127 { - // Float value - let new_value = stream.read_unsigned_vb()? as f32; - event_data.extend_from_slice(&[adjustment_function]); - format!( - "Inflight adjustment - Function: {}, New value: {:.3}", - adjustment_function, new_value - ) - } else { - // Integer value - let new_value = stream.read_signed_vb()?; - event_data.extend_from_slice(&[adjustment_function]); - format!( - "Inflight adjustment - Function: {}, New value: {}", - adjustment_function, new_value - ) - } - } - 5 => { - // FLIGHT_LOG_EVENT_LOGGING_RESUME - let log_iteration = stream.read_unsigned_vb()?; - let current_time = stream.read_unsigned_vb()?; - format!( - "Logging resume - Iteration: {}, Time: {}", - log_iteration, current_time - ) - } - 6 => { - // FLIGHT_LOG_EVENT_LOG_END (old numbering) - // Read end message bytes - for _ in 0..4 { - if !stream.eof { - event_data.push(stream.read_byte()?); - } - } - "Log end".to_string() - } - 10 => { - // FLIGHT_LOG_EVENT_AUTOTUNE_CYCLE_START (UNUSED) - "Autotune cycle start (unused)".to_string() - } - 11 => { - // FLIGHT_LOG_EVENT_AUTOTUNE_CYCLE_RESULT (UNUSED) - "Autotune cycle result (unused)".to_string() - } - 12 => { - // FLIGHT_LOG_EVENT_AUTOTUNE_TARGETS (UNUSED) - "Autotune targets (unused)".to_string() - } - 13 => { - // FLIGHT_LOG_EVENT_INFLIGHT_ADJUSTMENT - let adjustment_function = stream.read_byte()?; - if adjustment_function > 127 { - let new_value = stream.read_unsigned_vb()? as f32; - event_data.extend_from_slice(&[adjustment_function]); - format!( - "Inflight adjustment - Function: {}, New value: {:.3}", - adjustment_function, new_value - ) - } else { - let new_value = stream.read_signed_vb()?; - event_data.extend_from_slice(&[adjustment_function]); - format!( - "Inflight adjustment - Function: {}, New value: {}", - adjustment_function, new_value - ) - } - } - 14 => { - // FLIGHT_LOG_EVENT_LOGGING_RESUME - let log_iteration = stream.read_unsigned_vb()?; - let current_time = stream.read_unsigned_vb()?; - format!( - "Logging resume - Iteration: {}, Time: {}", - log_iteration, current_time - ) - } - 15 => { - // FLIGHT_LOG_EVENT_DISARM - "Disarm".to_string() - } - 30 => { - // FLIGHT_LOG_EVENT_FLIGHTMODE - flight mode status event - // Read flight mode data - for _ in 0..4 { - if !stream.eof { - event_data.push(stream.read_byte()?); - } - } - "Flight mode change".to_string() - } - 255 => { - // FLIGHT_LOG_EVENT_LOG_END - "Log end".to_string() - } - _ => { - // Unknown event type - read a few bytes as data - for _ in 0..8 { - if stream.eof { - break; - } - event_data.push(stream.read_byte()?); - } - format!("Unknown event type: {}", event_type) - } - }; - - if debug { - println!( - "DEBUG: Event - Type: {}, Description: {}", - event_type, event_name - ); - } - - Ok(EventFrame { - timestamp_us: 0, // Will be set later from context - event_type, - event_data, - event_name, - }) -} - fn skip_frame(stream: &mut BBLDataStream, frame_type: char, debug: bool) -> Result<()> { if debug { println!("Skipping {frame_type} frame"); diff --git a/src/parser/frame.rs b/src/parser/frame.rs index 2b75b72..6ece294 100644 --- a/src/parser/frame.rs +++ b/src/parser/frame.rs @@ -597,21 +597,56 @@ pub fn parse_frame_data( Ok(()) } -fn parse_s_frame( +/// Parse S-frame (Slow/periodic data) from the stream +/// +/// S-frames contain slowly-changing data that is logged less frequently. +/// This function handles all standard encodings including TAG2_3S32 which +/// reads 3 values at once. +pub fn parse_s_frame( stream: &mut BBLDataStream, frame_def: &FrameDefinition, debug: bool, ) -> Result> { let mut data = HashMap::new(); + let mut field_index = 0; - // Parse each field according to the frame definition - for field in &frame_def.fields { - let _values = [0i32; 1]; - let value = match field.encoding { - ENCODING_SIGNED_VB => stream.read_signed_vb()?, - ENCODING_UNSIGNED_VB => stream.read_unsigned_vb()? as i32, - ENCODING_NEG_14BIT => stream.read_neg_14bit()?, - ENCODING_NULL => 0, + while field_index < frame_def.fields.len() { + let field = &frame_def.fields[field_index]; + + match field.encoding { + ENCODING_SIGNED_VB => { + let value = stream.read_signed_vb()?; + data.insert(field.name.clone(), value); + field_index += 1; + } + ENCODING_UNSIGNED_VB => { + let value = stream.read_unsigned_vb()? as i32; + data.insert(field.name.clone(), value); + field_index += 1; + } + ENCODING_NEG_14BIT => { + let value = stream.read_neg_14bit()?; + data.insert(field.name.clone(), value); + field_index += 1; + } + ENCODING_TAG2_3S32 => { + // This encoding handles 3 fields at once + let mut values = [0i32; 8]; + stream.read_tag2_3s32(&mut values)?; + + #[allow(clippy::needless_range_loop)] + for j in 0..3 { + if field_index + j < frame_def.fields.len() { + let current_field = &frame_def.fields[field_index + j]; + data.insert(current_field.name.clone(), values[j]); + } + } + field_index += 3; + } + ENCODING_NULL => { + data.insert(field.name.clone(), 0); + field_index += 1; + } _ => { if debug { println!( @@ -620,11 +655,11 @@ fn parse_s_frame( ); } // For unsupported encodings, try to read as signed VB - stream.read_signed_vb().unwrap_or(0) + let value = stream.read_signed_vb().unwrap_or(0); + data.insert(field.name.clone(), value); + field_index += 1; } - }; - - data.insert(field.name.clone(), value); + } } Ok(data)