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
3 changes: 1 addition & 2 deletions src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

use crate::conversion::*;
use crate::types::*;
use crate::Result;
use anyhow::Context;
use anyhow::{Context, Result};
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufWriter, Write};
Expand Down
149 changes: 9 additions & 140 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};

// Import conversion functions from crate library to avoid code duplication
use bbl_parser::conversion::{
convert_gps_altitude, convert_gps_coordinate, convert_gps_course, convert_gps_speed,
format_failsafe_phase, format_flight_mode_flags, format_state_flags,
};

/// Maximum recursion depth to prevent stack overflow
const MAX_RECURSION_DEPTH: usize = 100;

Expand Down Expand Up @@ -2910,148 +2916,11 @@ fn parse_bbl_file_streaming(
Ok(processed_logs)
}

fn format_flight_mode_flags(flags: i32) -> String {
let mut modes = Vec::new();

// Based on Betaflight firmware runtime_config.h flightModeFlags_e enum
// This matches the blackbox-tools implementation exactly:
// https://github.com/betaflight/blackbox-tools/blob/master/src/blackbox_fielddefs.c

// FLIGHT_LOG_FLIGHT_MODE_NAME array from blackbox-tools
if (flags & (1 << 0)) != 0 {
modes.push("ANGLE_MODE"); // ANGLE_MODE = (1 << 0)
}
if (flags & (1 << 1)) != 0 {
modes.push("HORIZON_MODE"); // HORIZON_MODE = (1 << 1)
}
if (flags & (1 << 2)) != 0 {
modes.push("MAG"); // MAG_MODE = (1 << 2)
}
if (flags & (1 << 3)) != 0 {
modes.push("BARO"); // ALT_HOLD_MODE = (1 << 3) (old name BARO)
}
if (flags & (1 << 4)) != 0 {
modes.push("GPS_HOME"); // GPS_HOME_MODE (disabled in current firmware)
}
if (flags & (1 << 5)) != 0 {
modes.push("GPS_HOLD"); // POS_HOLD_MODE = (1 << 5) (old name GPS_HOLD)
}
if (flags & (1 << 6)) != 0 {
modes.push("HEADFREE"); // HEADFREE_MODE = (1 << 6)
}
if (flags & (1 << 7)) != 0 {
modes.push("UNUSED"); // CHIRP_MODE = (1 << 7) (old autotune, now unused)
}
if (flags & (1 << 8)) != 0 {
modes.push("PASSTHRU"); // PASSTHRU_MODE = (1 << 8)
}
if (flags & (1 << 9)) != 0 {
modes.push("RANGEFINDER_MODE"); // RANGEFINDER_MODE (disabled in current firmware)
}
if (flags & (1 << 10)) != 0 {
modes.push("FAILSAFE_MODE"); // FAILSAFE_MODE = (1 << 10)
}
if (flags & (1 << 11)) != 0 {
modes.push("GPS_RESCUE_MODE"); // GPS_RESCUE_MODE = (1 << 11) (new in current firmware)
}

if modes.is_empty() {
"0".to_string()
} else {
modes.join("|") // Use pipe separator to avoid breaking CSV format
}
}

fn format_state_flags(flags: i32) -> String {
let mut states = Vec::new();

// Based on Betaflight firmware runtime_config.h stateFlags_t enum
// This matches the blackbox-tools implementation exactly:
// https://github.com/betaflight/blackbox-tools/blob/master/src/blackbox_fielddefs.c

// FLIGHT_LOG_FLIGHT_STATE_NAME array from blackbox-tools
if (flags & (1 << 0)) != 0 {
states.push("GPS_FIX_HOME"); // GPS_FIX_HOME = (1 << 0)
}
if (flags & (1 << 1)) != 0 {
states.push("GPS_FIX"); // GPS_FIX = (1 << 1)
}
if (flags & (1 << 2)) != 0 {
states.push("CALIBRATE_MAG"); // GPS_FIX_EVER = (1 << 2) but old name CALIBRATE_MAG
}
if (flags & (1 << 3)) != 0 {
states.push("SMALL_ANGLE"); // Used in blackbox-tools for compatibility
}
if (flags & (1 << 4)) != 0 {
states.push("FIXED_WING"); // Used in blackbox-tools for compatibility
}

if states.is_empty() {
"0".to_string()
} else {
states.join("|") // Use pipe separator to avoid breaking CSV format
}
}

fn format_failsafe_phase(phase: i32) -> String {
// Based on Betaflight firmware failsafe.h failsafePhase_e enum
// This matches the blackbox-tools implementation exactly:
// https://github.com/betaflight/blackbox-tools/blob/master/src/blackbox_fielddefs.c

// FLIGHT_LOG_FAILSAFE_PHASE_NAME array from blackbox-tools
match phase {
0 => "IDLE".to_string(), // FAILSAFE_IDLE = 0
1 => "RX_LOSS_DETECTED".to_string(), // FAILSAFE_RX_LOSS_DETECTED
2 => "LANDING".to_string(), // FAILSAFE_LANDING
3 => "LANDED".to_string(), // FAILSAFE_LANDED
4 => "RX_LOSS_MONITORING".to_string(), // FAILSAFE_RX_LOSS_MONITORING (new in current firmware)
5 => "RX_LOSS_RECOVERED".to_string(), // FAILSAFE_RX_LOSS_RECOVERED (new in current firmware)
6 => "GPS_RESCUE".to_string(), // FAILSAFE_GPS_RESCUE (new in current firmware)
_ => phase.to_string(),
}
}
// Note: Flag formatting functions now imported from bbl_parser::conversion module
// (format_flight_mode_flags, format_state_flags, format_failsafe_phase)

// GPS/GPX export functions
fn extract_major_firmware_version(firmware_revision: &str) -> u8 {
// Extract major version from firmware string like "Betaflight 4.5.1 (77d01ba3b) AT32F435M"
if let Some(start) = firmware_revision.find(' ') {
let version_part = &firmware_revision[start + 1..];
if let Some(end) = version_part.find('.') {
if let Ok(major) = version_part[..end].parse::<u8>() {
return major;
}
}
}
// Default to 4 if parsing fails (assume modern firmware)
4
}

fn convert_gps_coordinate(raw_value: i32) -> f64 {
// GPS coordinates are stored as degrees * 10000000
raw_value as f64 / 10000000.0
}

fn convert_gps_altitude(raw_value: i32, firmware_revision: &str) -> f64 {
// Altitude units changed between firmware versions:
// Before Betaflight 4: centimeters (factor 0.01)
// Betaflight 4+: decimeters (factor 0.1)
let major_version = extract_major_firmware_version(firmware_revision);
if major_version >= 4 {
raw_value as f64 / 10.0 // decimeters to meters
} else {
raw_value as f64 / 100.0 // centimeters to meters
}
}

fn convert_gps_speed(raw_value: i32) -> f64 {
// Speed is stored as cm/s * 100, convert to m/s
raw_value as f64 / 100.0
}

fn convert_gps_course(raw_value: i32) -> f64 {
// Course is stored as degrees * 10
raw_value as f64 / 10.0
}
// Note: GPS conversion functions now imported from bbl_parser::conversion module

fn export_gpx_file(
file_path: &Path,
Expand Down
6 changes: 3 additions & 3 deletions src/parser/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::{BBLError, Result};
use crate::parser::stream::BBLDataStream;
use anyhow::Result;

// BBL Encoding constants - directly from JavaScript reference
pub const ENCODING_SIGNED_VB: u8 = 0;
Expand Down Expand Up @@ -46,7 +46,7 @@ pub fn decode_field_value(
values[index] = 0;
}
_ => {
return Err(BBLError::InvalidEncoding(encoding));
return Err(anyhow::anyhow!("Invalid encoding type: {}", encoding));
}
}
Ok(())
Expand Down Expand Up @@ -127,6 +127,6 @@ pub fn apply_predictor(
let motor_output_min = sysconfig.get("motorOutput[0]").copied().unwrap_or(48);
Ok(value + motor_output_min) // Force signed 32-bit like Betaflight
}
_ => Err(BBLError::InvalidPredictor(predictor)),
_ => Err(anyhow::anyhow!("Invalid predictor type: {}", predictor)),
}
}
2 changes: 1 addition & 1 deletion src/parser/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use crate::parser::stream::BBLDataStream;
use crate::types::EventFrame;
use crate::Result;
use anyhow::Result;

/// Helper function to parse inflight adjustment events (types 4 and 13)
/// Returns the event description string
Expand Down
2 changes: 1 addition & 1 deletion src/parser/frame.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::error::Result;
use crate::parser::{decoder::*, event::parse_e_frame, gps::*, stream::BBLDataStream};
use crate::types::{
DecodedFrame, EventFrame, FrameDefinition, FrameHistory, FrameStats, GpsCoordinate,
GpsHomeCoordinate,
};
use anyhow::Result;
use std::collections::HashMap;

/// Parse frames from binary data
Expand Down
17 changes: 10 additions & 7 deletions src/parser/gps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::parser::decoder::{
use crate::parser::frame::parse_frame_data;
use crate::parser::stream::BBLDataStream;
use crate::types::{FrameDefinition, GpsCoordinate, GpsHomeCoordinate};
use crate::Result;
use anyhow::Result;
use std::collections::HashMap;

/// Parse H-frame (GPS home position) data from the stream
Expand Down Expand Up @@ -42,12 +42,15 @@ pub fn parse_h_frame(
ENCODING_NEG_14BIT => stream.read_neg_14bit()?,
ENCODING_NULL => 0,
_ => {
// Unsupported H-frame encoding - return error instead of silently continuing
// This prevents stream desynchronization from being masked by default values
return Err(anyhow::anyhow!(
"Unsupported H-frame encoding {} for field '{}' - stream desynchronization possible",
field.encoding, field.name
));
// Unsupported H-frame encoding - gracefully fall back to signed VB
// This matches CLI behavior for maximum compatibility with various logs
if debug {
println!(
"Unsupported H-frame encoding {} for field {}",
field.encoding, field.name
);
}
stream.read_signed_vb().unwrap_or(0)
}
};

Expand Down
10 changes: 3 additions & 7 deletions src/parser/header.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::{BBLError, Result};
use crate::types::{BBLHeader, FrameDefinition};
use anyhow::Result;
use std::collections::HashMap;

/// Parse BBL headers from text
Expand Down Expand Up @@ -157,9 +157,7 @@ fn parse_predictor_info(line: &str, frame_def: &mut FrameDefinition) -> Result<(
frame_def.update_predictors(&predictors);
Ok(())
}
Err(_) => Err(BBLError::InvalidHeader(
"Invalid predictor values".to_string(),
)),
Err(_) => Err(anyhow::anyhow!("Invalid header: Invalid predictor values")),
}
}

Expand All @@ -178,9 +176,7 @@ fn parse_encoding_info(line: &str, frame_def: &mut FrameDefinition) -> Result<()
frame_def.update_encoding(&encodings);
Ok(())
}
Err(_) => Err(BBLError::InvalidHeader(
"Invalid encoding values".to_string(),
)),
Err(_) => Err(anyhow::anyhow!("Invalid header: Invalid encoding values")),
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/parser/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::types::*;
use crate::Result;
use anyhow::{anyhow, Context};
use anyhow::{anyhow, Context, Result};
use std::path::Path;

/// Parse BBL file and return all logs (for CLI and multi-log processing)
Expand Down
Loading