-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
fix(fdr2csv): refactor to unify fdr2csv, fix conversion bug (#9324)
* feat(fdr2csv): refactor to unify fdr2csv, fix conversion bug * chore: don't downgrade crate versions * feat(fdr2csv): add option to get raw file version * fix(fdr): fixed wrong storage of parameters * feat(fdr2csv): -o no longer required when -r or -g are present * fix(fdr2csv): correct description of parameters --------- Co-authored-by: Andreas Guther <[email protected]>
1 parent
c9cfe3c
commit 2776100
Showing
23 changed files
with
426 additions
and
1,185 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#include "../../fbw-a32nx/src/wasm/fbw_a320/src/model/AutopilotLaws_types.h" | ||
#include "../../fbw-a32nx/src/wasm/fbw_a320/src/model/AutopilotStateMachine_types.h" | ||
#include "../../fbw-a32nx/src/wasm/fbw_a320/src/model/Autothrust_types.h" | ||
#include "../../fbw-a32nx/src/wasm/fbw_a320/src/model/ElacComputer_types.h" | ||
#include "../../fbw-a32nx/src/wasm/fbw_a320/src/model/FacComputer_types.h" | ||
#include "../../fbw-a32nx/src/wasm/fbw_a320/src/model/SecComputer_types.h" | ||
#include "../../fbw-a32nx/src/wasm/fbw_a320/src/recording/RecordingDataTypes.h" |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#include "../../fbw-a380x/src/wasm/fbw_a380/src/interface/FuelSystemData.h" | ||
#include "../../fbw-a380x/src/wasm/fbw_a380/src/model/A380PrimComputer_types.h" | ||
#include "../../fbw-a380x/src/wasm/fbw_a380/src/model/A380SecComputer_types.h" | ||
#include "../../fbw-a380x/src/wasm/fbw_a380/src/model/AutopilotLaws_types.h" | ||
#include "../../fbw-a380x/src/wasm/fbw_a380/src/model/AutopilotStateMachine_types.h" | ||
#include "../../fbw-a380x/src/wasm/fbw_a380/src/model/Autothrust_types.h" | ||
#include "../../fbw-a380x/src/wasm/fbw_a380/src/model/FacComputer_types.h" | ||
#include "../../fbw-a380x/src/wasm/fbw_a380/src/recording/RecordingDataTypes.h" |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
use crate::{ | ||
a320_headers::{ | ||
ap_laws_output, ap_sm_output, athr_out, base_elac_analog_outputs, | ||
base_elac_discrete_outputs, base_elac_out_bus, base_fac_analog_outputs, base_fac_bus, | ||
base_fac_discrete_outputs, base_sec_analog_outputs, base_sec_discrete_outputs, | ||
base_sec_out_bus, AircraftSpecificData, BaseData, | ||
}, | ||
read_bytes, | ||
}; | ||
use serde::Serialize; | ||
use std::io::{prelude::*, Error}; | ||
|
||
pub const INTERFACE_VERSION: u64 = 3200001; | ||
|
||
// A single FDR record | ||
#[derive(Serialize, Default)] | ||
pub struct FdrData { | ||
base: BaseData, | ||
specific: AircraftSpecificData, | ||
elac_1: ElacData, | ||
elac_2: ElacData, | ||
sec_1: SecData, | ||
sec_2: SecData, | ||
sec_3: SecData, | ||
fac_1: FacData, | ||
fac_2: FacData, | ||
ap_sm: ap_sm_output, | ||
ap_law: ap_laws_output, | ||
athr: athr_out, | ||
} | ||
|
||
#[derive(Serialize, Default)] | ||
struct ElacData { | ||
bus_outputs: base_elac_out_bus, | ||
discrete_outputs: base_elac_discrete_outputs, | ||
analog_outputs: base_elac_analog_outputs, | ||
} | ||
|
||
#[derive(Serialize, Default)] | ||
struct SecData { | ||
bus_outputs: base_sec_out_bus, | ||
discrete_outputs: base_sec_discrete_outputs, | ||
analog_outputs: base_sec_analog_outputs, | ||
} | ||
|
||
#[derive(Serialize, Default)] | ||
struct FacData { | ||
bus_outputs: base_fac_bus, | ||
discrete_outputs: base_fac_discrete_outputs, | ||
analog_outputs: base_fac_analog_outputs, | ||
} | ||
|
||
// These are helper functions to read in a whole FDR record. | ||
pub fn read_record(reader: &mut impl Read) -> Result<FdrData, Error> { | ||
Ok(FdrData { | ||
base: read_bytes::<BaseData>(reader)?, | ||
specific: read_bytes::<AircraftSpecificData>(reader)?, | ||
elac_1: read_elac(reader)?, | ||
elac_2: read_elac(reader)?, | ||
sec_1: read_sec(reader)?, | ||
sec_2: read_sec(reader)?, | ||
sec_3: read_sec(reader)?, | ||
fac_1: read_fac(reader)?, | ||
fac_2: read_fac(reader)?, | ||
ap_sm: read_bytes::<ap_sm_output>(reader)?, | ||
ap_law: read_bytes::<ap_laws_output>(reader)?, | ||
athr: read_bytes::<athr_out>(reader)?, | ||
}) | ||
} | ||
|
||
fn read_elac(reader: &mut impl Read) -> Result<ElacData, Error> { | ||
Ok(ElacData { | ||
bus_outputs: read_bytes::<base_elac_out_bus>(reader)?, | ||
discrete_outputs: read_bytes::<base_elac_discrete_outputs>(reader)?, | ||
analog_outputs: read_bytes::<base_elac_analog_outputs>(reader)?, | ||
}) | ||
} | ||
|
||
fn read_sec(reader: &mut impl Read) -> Result<SecData, Error> { | ||
Ok(SecData { | ||
bus_outputs: read_bytes::<base_sec_out_bus>(reader)?, | ||
discrete_outputs: read_bytes::<base_sec_discrete_outputs>(reader)?, | ||
analog_outputs: read_bytes::<base_sec_analog_outputs>(reader)?, | ||
}) | ||
} | ||
|
||
fn read_fac(reader: &mut impl Read) -> Result<FacData, Error> { | ||
Ok(FacData { | ||
bus_outputs: read_bytes::<base_fac_bus>(reader)?, | ||
discrete_outputs: read_bytes::<base_fac_discrete_outputs>(reader)?, | ||
analog_outputs: read_bytes::<base_fac_analog_outputs>(reader)?, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
use crate::{ | ||
a380_headers::{ | ||
ap_laws_output, ap_sm_output, athr_out, base_fac_analog_outputs, base_fac_bus, | ||
base_fac_discrete_outputs, base_prim_analog_outputs, base_prim_discrete_outputs, | ||
base_prim_out_bus, base_sec_analog_outputs, base_sec_discrete_outputs, base_sec_out_bus, | ||
AircraftSpecificData, BaseData, FuelSystemData, | ||
}, | ||
read_bytes, | ||
}; | ||
use serde::Serialize; | ||
use std::io::{prelude::*, Error}; | ||
|
||
pub const INTERFACE_VERSION: u64 = 3800001; | ||
pub const INTERFACE_MIN_VERSION: u64 = 3800000; | ||
|
||
// A single FDR record | ||
#[derive(Serialize, Default)] | ||
pub struct FdrData { | ||
base: BaseData, | ||
specific: AircraftSpecificData, | ||
prim_1: PrimData, | ||
prim_2: PrimData, | ||
prim_3: PrimData, | ||
sec_1: SecData, | ||
sec_2: SecData, | ||
sec_3: SecData, | ||
fac_1: FacData, | ||
fac_2: FacData, | ||
ap_sm: ap_sm_output, | ||
ap_law: ap_laws_output, | ||
athr: athr_out, | ||
fuel: FuelSystemData, | ||
} | ||
|
||
#[derive(Serialize, Default)] | ||
struct PrimData { | ||
bus_outputs: base_prim_out_bus, | ||
discrete_outputs: base_prim_discrete_outputs, | ||
analog_outputs: base_prim_analog_outputs, | ||
} | ||
|
||
#[derive(Serialize, Default)] | ||
struct SecData { | ||
bus_outputs: base_sec_out_bus, | ||
discrete_outputs: base_sec_discrete_outputs, | ||
analog_outputs: base_sec_analog_outputs, | ||
} | ||
|
||
#[derive(Serialize, Default)] | ||
struct FacData { | ||
bus_outputs: base_fac_bus, | ||
discrete_outputs: base_fac_discrete_outputs, | ||
analog_outputs: base_fac_analog_outputs, | ||
} | ||
|
||
// These are helper functions to read in a whole FDR record. | ||
pub fn read_record(reader: &mut impl Read) -> Result<FdrData, Error> { | ||
Ok(FdrData { | ||
base: read_bytes::<BaseData>(reader)?, | ||
specific: read_bytes::<AircraftSpecificData>(reader)?, | ||
prim_1: read_prim(reader)?, | ||
prim_2: read_prim(reader)?, | ||
prim_3: read_prim(reader)?, | ||
sec_1: read_sec(reader)?, | ||
sec_2: read_sec(reader)?, | ||
sec_3: read_sec(reader)?, | ||
fac_1: read_fac(reader)?, | ||
fac_2: read_fac(reader)?, | ||
ap_sm: read_bytes::<ap_sm_output>(reader)?, | ||
ap_law: read_bytes::<ap_laws_output>(reader)?, | ||
athr: read_bytes::<athr_out>(reader)?, | ||
fuel: read_bytes::<FuelSystemData>(reader)?, | ||
}) | ||
} | ||
|
||
fn read_prim(reader: &mut impl Read) -> Result<PrimData, Error> { | ||
Ok(PrimData { | ||
bus_outputs: read_bytes::<base_prim_out_bus>(reader)?, | ||
discrete_outputs: read_bytes::<base_prim_discrete_outputs>(reader)?, | ||
analog_outputs: read_bytes::<base_prim_analog_outputs>(reader)?, | ||
}) | ||
} | ||
|
||
fn read_sec(reader: &mut impl Read) -> Result<SecData, Error> { | ||
Ok(SecData { | ||
bus_outputs: read_bytes::<base_sec_out_bus>(reader)?, | ||
discrete_outputs: read_bytes::<base_sec_discrete_outputs>(reader)?, | ||
analog_outputs: read_bytes::<base_sec_analog_outputs>(reader)?, | ||
}) | ||
} | ||
|
||
fn read_fac(reader: &mut impl Read) -> Result<FacData, Error> { | ||
Ok(FacData { | ||
bus_outputs: read_bytes::<base_fac_bus>(reader)?, | ||
discrete_outputs: read_bytes::<base_fac_discrete_outputs>(reader)?, | ||
analog_outputs: read_bytes::<base_fac_analog_outputs>(reader)?, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
use bytemuck::AnyBitPattern; | ||
use clap::Parser; | ||
use csv::WriterBuilder; | ||
use flate2::bufread::GzDecoder; | ||
use std::{ | ||
fs::{File, OpenOptions}, | ||
io::{prelude::*, BufReader, BufWriter, Error, ErrorKind}, | ||
mem, | ||
}; | ||
|
||
mod a320; | ||
mod a320_headers; | ||
mod a380; | ||
mod a380_headers; | ||
mod csv_header_serializer; | ||
mod error; | ||
|
||
#[derive(Debug)] | ||
enum AircraftType { | ||
A320, | ||
A380, | ||
} | ||
|
||
#[derive(Parser, Debug)] | ||
#[command(version, about, long_about = None)] | ||
struct Args { | ||
/// Input file | ||
#[arg(short, long)] | ||
input: String, | ||
/// Output file | ||
#[arg(short, long, required_unless_present_any(["get_input_file_version", "get_raw_input_file_version"]))] | ||
output: Option<String>, | ||
/// Delimiter | ||
#[arg(short, long, default_value = ",")] | ||
delimiter: char, | ||
/// Input file is not compressed | ||
#[arg(short, long, default_value_t = false)] | ||
no_compression: bool, | ||
/// Print struct size | ||
#[arg(short, long, default_value_t = false)] | ||
print_struct_size: bool, | ||
/// Print interface version and aircraft type of input file | ||
#[arg(short, long, default_value_t = false)] | ||
get_input_file_version: bool, | ||
/// Print raw interface version of input file | ||
#[arg(short = 'r', long, default_value_t = false)] | ||
get_raw_input_file_version: bool, | ||
} | ||
|
||
// Read number of bytes specified by the size of T from the binary file | ||
pub fn read_bytes<T: AnyBitPattern>(reader: &mut impl Read) -> Result<T, Error> { | ||
let size = mem::size_of::<T>(); | ||
|
||
// allocate the buffer that will hold the value read from the binary | ||
let mut buf = vec![0u8; size]; | ||
|
||
// now read from the reader into the buffer | ||
reader.read_exact(&mut buf)?; | ||
|
||
// If the read was successful, reinterpret the bytes as the struct, and return | ||
let res = bytemuck::from_bytes::<T>(buf.as_slice()); | ||
|
||
Ok(*res) | ||
} | ||
|
||
fn main() -> Result<(), std::io::Error> { | ||
// Parse CLI arguments | ||
let args = Args::parse(); | ||
|
||
// Open the input file | ||
let in_file = File::open(args.input.trim()) | ||
.map_err(|e| std::io::Error::new(e.kind(), "Failed to open input file!"))?; | ||
|
||
// Create Gzip Reader | ||
let mut reader: Box<dyn Read> = if args.no_compression { | ||
Box::new(BufReader::new(in_file)) | ||
} else { | ||
Box::new(GzDecoder::new(BufReader::new(in_file))) | ||
}; | ||
|
||
// Read file version | ||
let file_format_version = read_bytes::<u64>(&mut reader)?; | ||
let aircraft_type = if file_format_version > a380::INTERFACE_MIN_VERSION { | ||
AircraftType::A380 | ||
} else { | ||
AircraftType::A320 | ||
}; | ||
|
||
let aircraft_interface_version = match aircraft_type { | ||
AircraftType::A320 => a320::INTERFACE_VERSION, | ||
AircraftType::A380 => a380::INTERFACE_VERSION, | ||
}; | ||
|
||
// Print or check file version | ||
if args.get_input_file_version { | ||
println!( | ||
"Aircraft Type is {:?}, Interface version is {}", | ||
aircraft_type, file_format_version | ||
); | ||
return Ok(()); | ||
} else if args.get_raw_input_file_version { | ||
println!("{}", file_format_version); | ||
return Ok(()); | ||
} else if aircraft_interface_version != file_format_version { | ||
return Err(std::io::Error::new( | ||
ErrorKind::InvalidInput, | ||
format!( | ||
"Mismatch between converter and file version (expected {aircraft_interface_version}, got {file_format_version})", | ||
), | ||
)); | ||
} | ||
|
||
// Print info on conversion start | ||
println!( | ||
"Converting from '{}' to '{}' for aircraft type '{:?}' with interface version '{}' and delimiter '{}'", | ||
args.input, args.output.clone().unwrap(), aircraft_type, file_format_version, args.delimiter | ||
); | ||
|
||
// Open or create output file in truncate mode | ||
let out_file = OpenOptions::new() | ||
.write(true) | ||
.truncate(true) | ||
.create(true) | ||
.open(args.output.clone().unwrap().trim()) | ||
.map_err(|e| std::io::Error::new(e.kind(), "Failed to open output file!"))?; | ||
|
||
let mut buf_writer = BufWriter::new(out_file); | ||
|
||
let mut counter = 0; | ||
|
||
// Generate and write the header | ||
let header = match aircraft_type { | ||
AircraftType::A320 => { | ||
csv_header_serializer::to_string(&a320::FdrData::default(), args.delimiter) | ||
} | ||
AircraftType::A380 => { | ||
csv_header_serializer::to_string(&a380::FdrData::default(), args.delimiter) | ||
} | ||
} | ||
.map_err(|_| std::io::Error::new(ErrorKind::Other, "Failed to generate header."))?; | ||
|
||
buf_writer.write(header.as_bytes())?; | ||
|
||
// Create the CSV writer, and serialize the file. | ||
let mut writer = WriterBuilder::new() | ||
.delimiter(args.delimiter as u8) | ||
.has_headers(false) | ||
.from_writer(buf_writer); | ||
|
||
match aircraft_type { | ||
AircraftType::A320 => { | ||
while let Ok(fdr_data) = a320::read_record(&mut reader) { | ||
writer.serialize(&fdr_data)?; | ||
|
||
counter += 1; | ||
|
||
if counter % 1000 == 0 { | ||
print!("Processed {counter} entries...\r"); | ||
std::io::stdout().flush()?; | ||
} | ||
} | ||
} | ||
AircraftType::A380 => { | ||
while let Ok(fdr_data) = a380::read_record(&mut reader) { | ||
writer.serialize(&fdr_data)?; | ||
|
||
counter += 1; | ||
|
||
if counter % 1000 == 0 { | ||
print!("Processed {counter} entries...\r"); | ||
std::io::stdout().flush()?; | ||
} | ||
} | ||
} | ||
} | ||
|
||
println!("Processed {counter} entries..."); | ||
|
||
Result::Ok(()) | ||
} |