Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
316 changes: 2 additions & 314 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<u8>,
event_name: String,
}

#[derive(Debug)]
struct BBLLog {
log_number: usize,
Expand Down Expand Up @@ -2304,310 +2293,9 @@ fn parse_frames(
))
}

#[allow(dead_code)]
fn parse_i_frame(
stream: &mut BBLDataStream,
frame_def: &FrameDefinition,
debug: bool,
) -> Result<HashMap<String, i32>> {
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<HashMap<String, i32>> {
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<HashMap<String, i32>> {
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<EventFrame> {
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");
Expand Down
Loading