1use frame::event;
2use itertools::Itertools;
3use nom::FindSubstring;
4use stream::{
5 data::parse_next_frame,
6 header::{parse_headers, Header},
7 predictor::{LogProcessor, LogRecord},
8};
9use thiserror::Error;
10
11extern crate itertools;
12
13pub mod frame;
14pub(crate) mod stream;
15
16pub enum BlackboxRecord<'a> {
17 Main(&'a [i64]),
18 GNSS(&'a [i64]),
19 Slow(Vec<i64>),
20 Event(event::Frame),
21 Garbage(usize),
22}
23
24#[derive(Copy, Clone)]
25pub enum Strictness {
26 Strict,
27 Lenient,
28}
29
30pub struct BlackboxReader<'a> {
31 strictness: Strictness,
32 last_values: Vec<i64>,
33 remaining_bytes: &'a [u8],
34 original_length: usize,
35 pub header: Header,
36 processor: LogProcessor,
37 pub last_loop_iteration: i64,
38 pub last_time: i64,
39 loop_iteration_field_ix: usize,
40 time_field_ix: usize,
41}
42
43#[derive(Error, Debug)]
44#[cfg_attr(test, derive(serde::Serialize))]
45pub enum BlackboxReaderError {
46 #[error("couldn't parse header")]
47 ParseHeader,
48 #[error("loopIteration or time I/P fields have not been found")]
49 NoLoopIterationAndTime,
50 #[error("log is truncated")]
51 Incomplete,
52}
53
54impl<'a> BlackboxReader<'a> {
55 pub fn new(bytes: &'a [u8], strictness: Strictness) -> Result<BlackboxReader<'a>, BlackboxReaderError> {
56 let original_length = bytes.len();
57 let (remaining_bytes, header) = parse_headers(bytes).map_err(|e| match e {
58 nom::Err::Error(_e) => BlackboxReaderError::ParseHeader,
59 nom::Err::Failure(_e) => BlackboxReaderError::ParseHeader,
60 nom::Err::Incomplete(_) => BlackboxReaderError::Incomplete,
61 })?;
62
63 let loop_iteration_field_ix = header
64 .ip_fields_in_order
65 .iter()
66 .find_position(|f| f.name == "loopIteration")
67 .ok_or(BlackboxReaderError::NoLoopIterationAndTime)?
68 .0;
69
70 let time_field_ix = header
71 .ip_fields_in_order
72 .iter()
73 .find_position(|f| f.name == "time")
74 .ok_or(BlackboxReaderError::NoLoopIterationAndTime)?
75 .0;
76
77 let last_values = Vec::with_capacity(
78 header
79 .ip_fields_in_order
80 .len()
81 .max(header.s_fields_in_order.len())
82 .max(header.g_fields_in_order.len()),
83 );
84
85 Ok(BlackboxReader {
86 remaining_bytes,
87 original_length,
88 processor: LogProcessor::new(&header),
89 last_values,
90 loop_iteration_field_ix,
91 time_field_ix,
92 header,
93 last_loop_iteration: 0,
94 last_time: 0,
95 strictness,
96 })
97 }
98
99 pub fn from_bytes(bytes: &'a [u8]) -> Result<BlackboxReader<'a>, BlackboxReaderError> {
100 Self::new(bytes, Strictness::Lenient)
101 }
102
103 pub fn next(&mut self) -> Option<BlackboxRecord> {
104 loop {
105 match parse_next_frame(&self.header, self.remaining_bytes) {
106 Ok((remaining_bytes, frame)) => {
107 self.remaining_bytes = remaining_bytes;
108 if let Some(record) = self.processor.process_frame(frame) {
109 return Some(match record {
110 LogRecord::Main(values) => {
111 self.last_loop_iteration = values[self.loop_iteration_field_ix];
112 self.last_time = values[self.time_field_ix];
113 self.last_values.clear();
114 self.last_values.extend_from_slice(values);
115 BlackboxRecord::Main(&self.last_values)
116 }
117 LogRecord::GNSS(values) => {
118 self.last_values.clear();
119 self.last_values.extend_from_slice(values);
120 BlackboxRecord::GNSS(&self.last_values)
121 }
122 LogRecord::Slow(values) => BlackboxRecord::Slow(values),
123 LogRecord::Event(event) => BlackboxRecord::Event(event),
124 });
125 }
126 }
127 Err(e) => match e {
128 nom::Err::Error(e) => {
129 match self.strictness {
130 Strictness::Strict => return None,
131 Strictness::Lenient => if e.input.len() > 0 {
132 self.remaining_bytes = &e.input[1..];
133 }
134 }
135 }
136 nom::Err::Failure(_) => {
137 return None;
138 }
139 nom::Err::Incomplete(_) => {
140 return None;
141 }
142 },
143 }
144 }
145 }
146
147 pub fn bytes_read(&self) -> usize {
148 self.original_length - self.remaining_bytes.len()
149 }
150}
151
152pub struct MultiSegmentBlackboxReader<'a> {
153 remaining_bytes: &'a [u8],
154 strictness: Strictness,
155}
156
157impl<'a> MultiSegmentBlackboxReader<'a> {
158 pub fn new(bytes: &'a [u8], strictness: Strictness) -> Self {
159 Self {
160 remaining_bytes: bytes,
161 strictness,
162 }
163 }
164
165 pub fn from_bytes(bytes: &'a [u8]) -> Self {
166 Self::new(bytes, Strictness::Lenient)
167 }
168
169 pub fn successful_only(self) -> impl Iterator<Item = BlackboxReader<'a>> {
170 self.filter_map(|r| {
171 r.ok()
172 })
173 }
174}
175
176impl<'a> Iterator for MultiSegmentBlackboxReader<'a> {
177 type Item = Result<BlackboxReader<'a>, BlackboxReaderError>;
178
179 fn next(&mut self) -> Option<Self::Item> {
180 let pos = self.remaining_bytes.find_substring(&b"H Product:Blackbox"[..])?;
181 self.remaining_bytes = &self.remaining_bytes[pos..];
182 let reader = BlackboxReader::new(self.remaining_bytes, self.strictness);
183 if let Ok(reader) = &reader {
184 self.remaining_bytes = &self.remaining_bytes[reader.bytes_read()..];
185 } else {
186 self.remaining_bytes = &self.remaining_bytes[1..];
187 }
188 Some(reader)
189 }
190}
191
192#[cfg(test)]
193mod tests;