blackbox_log/
lib.rs

1#![no_std]
2#![warn(clippy::std_instead_of_alloc, clippy::std_instead_of_core)]
3#![warn(unreachable_pub, clippy::missing_panics_doc)]
4
5//! Ergonomic parser for Betaflight blackbox logs.
6//!
7//! For details about the format of blackbox logs, see the *Blackbox Internals*
8//! development documentation from [INAV][inav-doc], [Betaflight][bf-doc]
9//!
10//! # Examples
11//!
12//! The simplest way to extract a few fields of interest:
13//!
14//! ```
15//! use blackbox_log::frame::FieldDef;
16//! use blackbox_log::prelude::*;
17//! use blackbox_log::Filter;
18//!
19//! let filters = blackbox_log::FilterSet {
20//!     // This restricts the included fields to `rcCommand[0]` through `rcCommand[3]`
21//!     main: Filter::OnlyFields(["rcCommand"].into()),
22//!     // ... only `flightModeFlags` for slow frames
23//!     slow: Filter::OnlyFields(["flightModeFlags"].into()),
24//!     // ... and no filter for gps frames -- include all fields
25//!     gps: Filter::Unfiltered,
26//! };
27//!
28//! let file = b"...";
29//! for headers in blackbox_log::File::new(file).iter() {
30//!     let headers = headers.expect("valid log headers");
31//!
32//!     let mut parser = headers.data_parser_with_filters(&filters);
33//!     while let Some(event) = parser.next() {
34//!         match event {
35//!             ParserEvent::Main(main) => {
36//!                 for (value, FieldDef { name, .. }) in
37//!                     main.iter().zip(headers.main_frame_def().iter())
38//!                 {
39//!                     println!("{name}: {value:?}");
40//!                 }
41//!             }
42//!             ParserEvent::Slow(slow) => {
43//!                 for (value, FieldDef { name, .. }) in
44//!                     slow.iter().zip(headers.slow_frame_def().iter())
45//!                 {
46//!                     println!("{name}: {value:?}");
47//!                 }
48//!             }
49//!             ParserEvent::Event(_) | ParserEvent::Gps(_) => {}
50//!         }
51//!     }
52//! }
53//! ```
54//!
55//! Get only the GPS data without parsing logs that cannot contain GPS frames:
56//!
57//! ```
58//! use blackbox_log::frame::FieldDef;
59//! use blackbox_log::prelude::*;
60//!
61//! let file = b"...";
62//! for headers in blackbox_log::File::new(file).iter() {
63//!     let headers = headers.expect("valid log headers");
64//!
65//!     if let Some(gps_def) = &headers.gps_frame_def() {
66//!         let mut parser = headers.data_parser();
67//!
68//!         while let Some(event) = parser.next() {
69//!             if let ParserEvent::Gps(gps) = event {
70//!                 for (value, FieldDef { name, .. }) in gps.iter().zip(gps_def.iter()) {
71//!                     println!("{name}: {value:?}");
72//!                 }
73//!             }
74//!         }
75//!     }
76//! }
77//! ```
78//!
79//! # Features
80//!
81//! - `std`: **Enabled** by default. Currently, this only implements
82//!   [`std::error::Error`] for [`headers::ParseError`].
83//!
84//! [bf-doc]: https://betaflight.com/docs/development/Blackbox-Internals
85//! [inav-doc]: https://github.com/iNavFlight/inav/blob/master/docs/development/Blackbox%20Internals.md
86
87extern crate alloc;
88#[cfg(feature = "std")]
89extern crate std;
90
91#[macro_use]
92mod utils;
93
94pub mod data;
95pub mod event;
96mod file;
97mod filter;
98pub mod frame;
99pub mod headers;
100mod parser;
101mod predictor;
102pub mod prelude;
103mod reader;
104pub mod units;
105
106use core::ops::Range;
107
108pub use self::data::{DataParser, ParserEvent};
109pub use self::event::Event;
110pub use self::file::File;
111pub use self::filter::{FieldFilter, Filter, FilterSet};
112pub use self::frame::{Unit, Value};
113use self::headers::FirmwareVersion;
114pub use self::headers::Headers;
115use self::reader::Reader;
116
117/// The first line of any blackbox log.
118const MARKER: &[u8] = b"H Product:Blackbox flight data recorder by Nicholas Sherlock\n";
119
120const BETAFLIGHT_SUPPORT: Range<FirmwareVersion> =
121    FirmwareVersion::new(4, 2, 0)..FirmwareVersion::new(4, 6, 0);
122const INAV_SUPPORT: Range<FirmwareVersion> =
123    FirmwareVersion::new(5, 0, 0)..FirmwareVersion::new(8, 0, 0);