Skip to content

Commit 850fc27

Browse files
committed
fix: align crate parse_h_frame and 14-bit encoding with CLI behavior
- parser/gps.rs: parse_h_frame now uses graceful fallback for unknown encodings (read_signed_vb with unwrap_or(0)) matching CLI behavior - parser/stream.rs: read_neg_14bit now uses sign-magnitude encoding matching CLI's bbl_format::sign_extend_14bit + negation - Updated tests for sign-magnitude encoding - Removed unused two's complement sign extension function This ensures crate's H-frame parsing matches the working CLI logic. Addresses Issue #9: CLI logic takes precedence
1 parent 20a8f0a commit 850fc27

2 files changed

Lines changed: 63 additions & 63 deletions

File tree

src/parser/gps.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,15 @@ pub fn parse_h_frame(
4242
ENCODING_NEG_14BIT => stream.read_neg_14bit()?,
4343
ENCODING_NULL => 0,
4444
_ => {
45-
// Unsupported H-frame encoding - return error instead of silently continuing
46-
// This prevents stream desynchronization from being masked by default values
47-
return Err(anyhow::anyhow!(
48-
"Unsupported H-frame encoding {} for field '{}' - stream desynchronization possible",
49-
field.encoding, field.name
50-
));
45+
// Unsupported H-frame encoding - gracefully fall back to signed VB
46+
// This matches CLI behavior for maximum compatibility with various logs
47+
if debug {
48+
println!(
49+
"Unsupported H-frame encoding {} for field {}",
50+
field.encoding, field.name
51+
);
52+
}
53+
stream.read_signed_vb().unwrap_or(0)
5154
}
5255
};
5356

src/parser/stream.rs

Lines changed: 54 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -220,17 +220,23 @@ impl<'a> BBLDataStream<'a> {
220220
Ok(())
221221
}
222222

223-
/// Read negative 14-bit encoding
224-
/// Reads an unsigned variable byte and interprets it as a 14-bit two's complement signed value.
225-
/// The value is masked to 14 bits (0x3FFF), with bit 13 serving as the sign bit.
226-
/// Negative values (sign bit set) are sign-extended to i32.
223+
/// Read negative 14-bit encoding (sign-magnitude format)
224+
/// Reads an unsigned variable byte and interprets it as a 14-bit sign-magnitude value.
225+
/// Bit 13 is the sign bit, bits 0-12 are the magnitude.
226+
/// Returns the negated value to match blackbox_decode behavior.
227227
pub fn read_neg_14bit(&mut self) -> Result<i32> {
228-
let unsigned = self.read_unsigned_vb()?;
228+
let unsigned = self.read_unsigned_vb()? as u16;
229+
Ok(-sign_extend_14bit_sign_magnitude(unsigned))
230+
}
231+
}
229232

230-
// Mask to 14 bits and perform sign-extension
231-
// If bit 13 is set, the value is negative and needs sign-extension
232-
let masked = (unsigned & 0x3FFF) as u16;
233-
Ok(sign_extend_14bit_twos_complement(masked))
233+
/// Sign-magnitude 14-bit encoding (matches bbl_format::sign_extend_14bit and blackbox_decode)
234+
/// Bit 13 indicates sign, bits 0-12 are the magnitude
235+
fn sign_extend_14bit_sign_magnitude(value: u16) -> i32 {
236+
if (value & 0x2000) != 0 {
237+
-((value & 0x1fff) as i32)
238+
} else {
239+
(value & 0x1fff) as i32
234240
}
235241
}
236242

@@ -263,16 +269,6 @@ fn sign_extend_8bit(value: u8) -> i32 {
263269
value as i8 as i32
264270
}
265271

266-
// Two's complement sign extension for 14-bit values (distinct from bbl_format.rs::sign_extend_14bit
267-
// which uses sign-magnitude encoding)
268-
fn sign_extend_14bit_twos_complement(value: u16) -> i32 {
269-
if (value & 0x2000) != 0 {
270-
(value as i32) | !0x3fff
271-
} else {
272-
(value & 0x3fff) as i32
273-
}
274-
}
275-
276272
fn sign_extend_16bit(value: u16) -> i32 {
277273
value as i16 as i32
278274
}
@@ -290,70 +286,71 @@ mod tests {
290286
use super::*;
291287

292288
#[test]
293-
fn test_sign_extend_14bit_positive() {
294-
// Positive values have bit 13 = 0
295-
assert_eq!(sign_extend_14bit_twos_complement(0x0000), 0); // 0
296-
assert_eq!(sign_extend_14bit_twos_complement(0x0001), 1); // 1
297-
assert_eq!(sign_extend_14bit_twos_complement(0x1FFF), 0x1FFF); // 8191 (max positive)
289+
fn test_sign_extend_14bit_sign_magnitude_positive() {
290+
// Positive values have bit 13 = 0 (sign bit clear)
291+
assert_eq!(sign_extend_14bit_sign_magnitude(0x0000), 0); // 0
292+
assert_eq!(sign_extend_14bit_sign_magnitude(0x0001), 1); // 1
293+
assert_eq!(sign_extend_14bit_sign_magnitude(0x1FFF), 0x1FFF); // 8191 (max positive magnitude)
298294
}
299295

300296
#[test]
301-
fn test_sign_extend_14bit_negative() {
302-
// Negative values have bit 13 = 1, sign extended to all upper bits
303-
assert_eq!(sign_extend_14bit_twos_complement(0x2000), -8192); // -8192 (min negative)
304-
assert_eq!(sign_extend_14bit_twos_complement(0x3FFF), -1); // -1
305-
assert_eq!(sign_extend_14bit_twos_complement(0x2001), -8191); // -8191
297+
fn test_sign_extend_14bit_sign_magnitude_negative() {
298+
// Negative values have bit 13 = 1 (sign bit set), magnitude in bits 0-12
299+
// 0x2000 = bit 13 set, magnitude 0 -> returns -0 = 0 (actually negative zero)
300+
assert_eq!(sign_extend_14bit_sign_magnitude(0x2000), 0); // -0
301+
// 0x2001 = bit 13 set, magnitude 1 -> returns -1
302+
assert_eq!(sign_extend_14bit_sign_magnitude(0x2001), -1);
303+
// 0x3FFF = bit 13 set, magnitude 0x1FFF (8191) -> returns -8191
304+
assert_eq!(sign_extend_14bit_sign_magnitude(0x3FFF), -8191);
306305
}
307306

308307
#[test]
309308
fn test_read_neg_14bit_positive() {
310309
// Test reading positive 14-bit value from variable byte encoding
311310
// VB encoding of 100 is [100] (single byte since 100 < 128)
311+
// sign_extend_14bit_sign_magnitude(100) = 100 (bit 13 not set)
312+
// read_neg_14bit returns -100 (negation)
312313
let data = vec![100u8];
313314
let mut stream = BBLDataStream::new(&data);
314-
assert_eq!(stream.read_neg_14bit().unwrap(), 100);
315+
// The function returns the negation: -sign_extend_14bit_sign_magnitude(100) = -100
316+
assert_eq!(stream.read_neg_14bit().unwrap(), -100);
315317
}
316318

317319
#[test]
318320
fn test_read_neg_14bit_negative() {
319-
// Test reading negative 14-bit value
320-
// 14-bit value -1 (0x3FFF in two's complement)
321-
// VB encode 0x3FFF: 0x3FFF = 16383
322-
// 16383 in VB: 0xFF (127 + continuation), 0x7F (127, final) = 127 + 127*128 = 16383
323-
let data = vec![0xFF, 0x7Fu8];
321+
// Test reading value with sign bit set
322+
// VB encode 0x2001 = 8193: 0x81 (1 + continuation), 0x40 (64, final) = 1 + 64*128 = 8193
323+
let data = vec![0x81, 0x40u8];
324324
let mut stream = BBLDataStream::new(&data);
325-
assert_eq!(stream.read_neg_14bit().unwrap(), -1);
325+
// 0x2001: bit 13 set, magnitude = 1, sign_extend returns -1
326+
// read_neg_14bit returns -(-1) = 1
327+
assert_eq!(stream.read_neg_14bit().unwrap(), 1);
326328
}
327329

328330
#[test]
329331
fn test_read_neg_14bit_boundary() {
330332
// Test boundary values
331-
// Max positive: 0x1FFF (8191)
332-
// VB encode 0x1FFF: 0xFF (127 + continuation), 0x3F (63, final) = 127 + 63*128 = 8191
333-
let data = vec![0xFF, 0x3Fu8];
333+
// Value 0: VB = [0], sign_extend_14bit(0) = 0, read_neg_14bit returns -0 = 0
334+
let data = vec![0u8];
334335
let mut stream = BBLDataStream::new(&data);
335-
assert_eq!(stream.read_neg_14bit().unwrap(), 8191);
336-
337-
// Min negative: 0x2000 (-8192)
338-
// VB encode 0x2000: 0x80 (0 + continuation), 0x20 (32, final) = 0 + 32*128 = 4096
339-
// But 0x2000 & 0x3FFF = 0x2000, and bit 13 is set, so it's negative
340-
// Actually we need the full 14-bit value 0x2000 = 8192
341-
// In VB that's: 0x80, 0x40 = 0 + 64*128 = 8192
342-
let data = vec![0x80, 0x40u8];
336+
assert_eq!(stream.read_neg_14bit().unwrap(), 0);
337+
338+
// Max magnitude positive (no sign): 0x1FFF = 8191
339+
// VB encode 0x1FFF: 0xFF, 0x3F = 127 + 63*128 = 8191
340+
// sign_extend returns 8191, read_neg_14bit returns -8191
341+
let data = vec![0xFF, 0x3Fu8];
343342
let mut stream = BBLDataStream::new(&data);
344-
assert_eq!(stream.read_neg_14bit().unwrap(), -8192);
343+
assert_eq!(stream.read_neg_14bit().unwrap(), -8191);
345344
}
346345

347346
#[test]
348-
fn test_read_neg_14bit_masks_14_bits() {
349-
// Verify that only lower 14 bits are used even if VB encodes more
350-
// If VB reads a value > 0x3FFF, only lower 14 bits are used
351-
// Encode 0x1FFFFF (large value), which masks to 0x3FFF = -1
352-
// VB encode 0x1FFFFF: 0xFF, 0xFF, 0x7F = 127 + 127*128 + 127*128^2
353-
let data = vec![0xFF, 0xFF, 0x7Fu8];
347+
fn test_read_neg_14bit_with_sign_bit() {
348+
// When sign bit (bit 13) is set, sign_extend returns negative, then we negate again
349+
// 0x2001 encodes as VB: 0x81, 0x40 = 1 + 64*128 = 8193
350+
// sign_extend_14bit_sign_magnitude(0x2001) = -1 (sign bit set, magnitude 1)
351+
// read_neg_14bit returns -(-1) = 1
352+
let data = vec![0x81, 0x40u8];
354353
let mut stream = BBLDataStream::new(&data);
355-
let result = stream.read_neg_14bit().unwrap();
356-
// 0x1FFFFF & 0x3FFF = 0x3FFF, which is -1 in 14-bit two's complement
357-
assert_eq!(result, -1);
354+
assert_eq!(stream.read_neg_14bit().unwrap(), 1);
358355
}
359356
}

0 commit comments

Comments
 (0)