use std::fmt::Debug;
use chrono::{DateTime, Utc};
use nom::{
Parser,
branch::alt,
bytes::complete::tag,
combinator::map,
multi::length_data,
number::complete::{be_u16, u8 as nom_u8},
};
use super::{Config, Model};
use crate::common::MessageParseError;
use crate::rf_explorer::{SetupInfo, parsers::*};
#[derive(Debug, Clone, PartialEq, Default)]
pub(crate) struct Sweep {
pub(crate) amplitudes_dbm: Vec<f32>,
pub(crate) timestamp: DateTime<Utc>,
}
impl Sweep {
pub(crate) const STANDARD_PREFIX: &'static [u8] = b"$S";
pub(crate) const EXT_PREFIX: &'static [u8] = b"$s";
pub(crate) const LARGE_PREFIX: &'static [u8] = b"$z";
const EEOT_BYTES: [u8; 5] = [255, 254, 255, 254, 0];
}
impl<'a> TryFrom<&'a [u8]> for Sweep {
type Error = MessageParseError<'a>;
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
let (bytes, prefix) = alt((
tag(Self::STANDARD_PREFIX),
tag(Self::EXT_PREFIX),
tag(Self::LARGE_PREFIX),
))
.parse(bytes)?;
if let Some(index) = bytes.windows(5).enumerate().find_map(|(i, window)| {
if Self::EEOT_BYTES.starts_with(window) {
Some(i + Self::EEOT_BYTES.len())
} else if Config::PREFIX.starts_with(window)
|| SetupInfo::<Model>::PREFIX.starts_with(window)
{
Some(i)
} else {
None
}
}) {
return Err(MessageParseError::Truncated {
remainder: bytes.get(index..),
});
}
let (bytes, amps) = match prefix {
Self::STANDARD_PREFIX => length_data(nom_u8).parse(bytes)?,
Self::EXT_PREFIX => {
length_data(map(nom_u8, |len| (usize::from(len) + 1) * 16)).parse(bytes)?
}
Self::LARGE_PREFIX => length_data(be_u16).parse(bytes)?,
_ => length_data(nom_u8).parse(bytes)?,
};
let amplitudes_dbm = amps.iter().map(|&byte| f32::from(byte) / -2.).collect();
let _ = parse_opt_line_ending(bytes)?;
Ok(Sweep {
amplitudes_dbm,
timestamp: Utc::now(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_sweep() {
let length = 112;
let bytes = [
b'$', b'S', length, 15, 136, 218, 52, 155, 233, 246, 235, 135, 113, 130, 74, 70, 251,
124, 186, 231, 115, 199, 203, 64, 112, 146, 24, 170, 197, 77, 105, 121, 139, 134, 91,
157, 44, 19, 167, 140, 65, 188, 86, 28, 244, 191, 26, 164, 55, 241, 16, 5, 154, 57,
109, 253, 211, 62, 47, 111, 152, 196, 73, 119, 178, 147, 88, 41, 250, 238, 247, 40, 97,
230, 102, 169, 151, 249, 116, 66, 4, 80, 234, 3, 183, 71, 107, 237, 198, 175, 179, 36,
21, 195, 243, 30, 90, 176, 37, 81, 153, 117, 51, 122, 83, 7, 189, 227, 20, 92, 6, 229,
120, 125, 239,
];
let sweep = Sweep::try_from(&bytes[..]).unwrap();
assert_eq!(
sweep.amplitudes_dbm,
&[
-7.5, -68.0, -109.0, -26.0, -77.5, -116.5, -123.0, -117.5, -67.5, -56.5, -65.0,
-37.0, -35.0, -125.5, -62.0, -93.0, -115.5, -57.5, -99.5, -101.5, -32.0, -56.0,
-73.0, -12.0, -85.0, -98.5, -38.5, -52.5, -60.5, -69.5, -67.0, -45.5, -78.5, -22.0,
-9.5, -83.5, -70.0, -32.5, -94.0, -43.0, -14.0, -122.0, -95.5, -13.0, -82.0, -27.5,
-120.5, -8.0, -2.5, -77.0, -28.5, -54.5, -126.5, -105.5, -31.0, -23.5, -55.5,
-76.0, -98.0, -36.5, -59.5, -89.0, -73.5, -44.0, -20.5, -125.0, -119.0, -123.5,
-20.0, -48.5, -115.0, -51.0, -84.5, -75.5, -124.5, -58.0, -33.0, -2.0, -40.0,
-117.0, -1.5, -91.5, -35.5, -53.5, -118.5, -99.0, -87.5, -89.5, -18.0, -10.5,
-97.5, -121.5, -15.0, -45.0, -88.0, -18.5, -40.5, -76.5, -58.5, -25.5, -61.0,
-41.5, -3.5, -94.5, -113.5, -10.0, -46.0, -3.0, -114.5, -60.0, -62.5, -119.5
]
);
}
#[test]
fn parse_sweep_ext() {
let length = (112 / 16) - 1;
let bytes = [
b'$', b's', length, 15, 136, 218, 52, 155, 233, 246, 235, 135, 113, 130, 74, 70, 251,
124, 186, 231, 115, 199, 203, 64, 112, 146, 24, 170, 197, 77, 105, 121, 139, 134, 91,
157, 44, 19, 167, 140, 65, 188, 86, 28, 244, 191, 26, 164, 55, 241, 16, 5, 154, 57,
109, 253, 211, 62, 47, 111, 152, 196, 73, 119, 178, 147, 88, 41, 250, 238, 247, 40, 97,
230, 102, 169, 151, 249, 116, 66, 4, 80, 234, 3, 183, 71, 107, 237, 198, 175, 179, 36,
21, 195, 243, 30, 90, 176, 37, 81, 153, 117, 51, 122, 83, 7, 189, 227, 20, 92, 6, 229,
120, 125, 239,
];
let sweep = Sweep::try_from(&bytes[..]).unwrap();
assert_eq!(
sweep.amplitudes_dbm,
&[
-7.5, -68.0, -109.0, -26.0, -77.5, -116.5, -123.0, -117.5, -67.5, -56.5, -65.0,
-37.0, -35.0, -125.5, -62.0, -93.0, -115.5, -57.5, -99.5, -101.5, -32.0, -56.0,
-73.0, -12.0, -85.0, -98.5, -38.5, -52.5, -60.5, -69.5, -67.0, -45.5, -78.5, -22.0,
-9.5, -83.5, -70.0, -32.5, -94.0, -43.0, -14.0, -122.0, -95.5, -13.0, -82.0, -27.5,
-120.5, -8.0, -2.5, -77.0, -28.5, -54.5, -126.5, -105.5, -31.0, -23.5, -55.5,
-76.0, -98.0, -36.5, -59.5, -89.0, -73.5, -44.0, -20.5, -125.0, -119.0, -123.5,
-20.0, -48.5, -115.0, -51.0, -84.5, -75.5, -124.5, -58.0, -33.0, -2.0, -40.0,
-117.0, -1.5, -91.5, -35.5, -53.5, -118.5, -99.0, -87.5, -89.5, -18.0, -10.5,
-97.5, -121.5, -15.0, -45.0, -88.0, -18.5, -40.5, -76.5, -58.5, -25.5, -61.0,
-41.5, -3.5, -94.5, -113.5, -10.0, -46.0, -3.0, -114.5, -60.0, -62.5, -119.5
]
);
}
#[test]
fn parse_sweep_large() {
let length = 112u16.to_be_bytes();
let bytes = [
b'$', b'z', length[0], length[1], 15, 136, 218, 52, 155, 233, 246, 235, 135, 113, 130,
74, 70, 251, 124, 186, 231, 115, 199, 203, 64, 112, 146, 24, 170, 197, 77, 105, 121,
139, 134, 91, 157, 44, 19, 167, 140, 65, 188, 86, 28, 244, 191, 26, 164, 55, 241, 16,
5, 154, 57, 109, 253, 211, 62, 47, 111, 152, 196, 73, 119, 178, 147, 88, 41, 250, 238,
247, 40, 97, 230, 102, 169, 151, 249, 116, 66, 4, 80, 234, 3, 183, 71, 107, 237, 198,
175, 179, 36, 21, 195, 243, 30, 90, 176, 37, 81, 153, 117, 51, 122, 83, 7, 189, 227,
20, 92, 6, 229, 120, 125, 239,
];
let sweep = Sweep::try_from(&bytes[..]).unwrap();
assert_eq!(
sweep.amplitudes_dbm,
&[
-7.5, -68.0, -109.0, -26.0, -77.5, -116.5, -123.0, -117.5, -67.5, -56.5, -65.0,
-37.0, -35.0, -125.5, -62.0, -93.0, -115.5, -57.5, -99.5, -101.5, -32.0, -56.0,
-73.0, -12.0, -85.0, -98.5, -38.5, -52.5, -60.5, -69.5, -67.0, -45.5, -78.5, -22.0,
-9.5, -83.5, -70.0, -32.5, -94.0, -43.0, -14.0, -122.0, -95.5, -13.0, -82.0, -27.5,
-120.5, -8.0, -2.5, -77.0, -28.5, -54.5, -126.5, -105.5, -31.0, -23.5, -55.5,
-76.0, -98.0, -36.5, -59.5, -89.0, -73.5, -44.0, -20.5, -125.0, -119.0, -123.5,
-20.0, -48.5, -115.0, -51.0, -84.5, -75.5, -124.5, -58.0, -33.0, -2.0, -40.0,
-117.0, -1.5, -91.5, -35.5, -53.5, -118.5, -99.0, -87.5, -89.5, -18.0, -10.5,
-97.5, -121.5, -15.0, -45.0, -88.0, -18.5, -40.5, -76.5, -58.5, -25.5, -61.0,
-41.5, -3.5, -94.5, -113.5, -10.0, -46.0, -3.0, -114.5, -60.0, -62.5, -119.5
]
);
}
#[test]
fn reject_sweep_with_too_many_amplitudes() {
let length = 112;
let bytes = [
b'$', b'S', length, 15, 136, 218, 52, 155, 233, 246, 235, 135, 113, 130, 74, 70, 251,
124, 186, 231, 115, 199, 203, 64, 112, 146, 24, 170, 197, 77, 105, 121, 139, 134, 91,
157, 44, 19, 167, 140, 65, 188, 86, 28, 244, 191, 26, 164, 55, 241, 16, 5, 154, 57,
109, 253, 211, 62, 47, 111, 152, 196, 73, 119, 178, 147, 88, 41, 250, 238, 247, 40, 97,
230, 102, 169, 151, 249, 116, 66, 4, 80, 234, 3, 183, 71, 107, 237, 198, 175, 179, 36,
21, 195, 243, 30, 90, 176, 37, 81, 153, 117, 51, 122, 83, 7, 189, 227, 20, 92, 6, 229,
120, 125, 239, 100,
];
let sweep_error = Sweep::try_from(&bytes[..]).unwrap_err();
assert_eq!(sweep_error, MessageParseError::Invalid);
}
#[test]
fn reject_sweep_with_too_few_amplitudes() {
let length = 112;
let bytes = [
b'$', b'S', length, 15, 136, 218, 52, 155, 233, 246, 235, 135, 113, 130, 74, 70, 251,
124, 186, 231, 115, 199, 203, 64, 112, 146, 24, 170, 197, 77, 105, 121, 139, 134, 91,
157, 44, 19, 167, 140, 65, 188, 86, 28, 244, 191, 26, 164, 55, 241, 16, 5, 154, 57,
109, 253, 211, 62, 47, 111, 152, 196, 73, 119, 178, 147, 88, 41, 250, 238, 247, 40, 97,
230, 102, 169, 151, 249, 116, 66, 4, 80, 234, 3, 183, 71, 107, 237, 198, 175, 179, 36,
21, 195, 243, 30, 90, 176, 37, 81, 153, 117, 51, 122, 83, 7, 189, 227, 20, 92, 6, 229,
120, 125,
];
let sweep_error = Sweep::try_from(&bytes[..]).unwrap_err();
assert_eq!(sweep_error, MessageParseError::Incomplete);
}
#[test]
fn reject_sweep_with_eeot_bytes() {
let length = 112;
let bytes = [
b'$', b'S', length, 255, 254, 255, 254, 0, 233, 246, 235, 135, 113, 130, 74, 70, 251,
124, 186, 231, 115, 199, 203, 64, 112, 146, 24, 170, 197, 77, 105, 121, 139, 134, 91,
157, 44, 19, 167, 140, 65, 188, 86, 28, 244, 191, 26, 164, 55, 241, 16, 5, 154, 57,
109, 253, 211, 62, 47, 111, 152, 196, 73, 119, 178, 147, 88, 41, 250, 238, 247, 40, 97,
230, 102, 169, 151, 249, 116, 66, 4, 80, 234, 3, 183, 71, 107, 237, 198, 175, 179, 36,
21, 195, 243, 30, 90, 176, 37, 81, 153, 117, 51, 122, 83, 7, 189, 227, 20, 92, 6, 229,
120, 125, 239,
];
let sweep_error = Sweep::try_from(bytes.as_slice()).unwrap_err();
assert_eq!(
sweep_error,
MessageParseError::Truncated {
remainder: Some(&bytes[8..])
}
);
}
#[test]
fn reject_sweep_with_config_at_the_end() {
let bytes = [
36, 83, 112, 215, 210, 214, 212, 212, 216, 212, 210, 214, 213, 212, 215, 212, 212, 212,
212, 220, 211, 215, 212, 212, 217, 213, 208, 214, 216, 210, 210, 213, 215, 216, 213,
213, 217, 209, 216, 214, 217, 206, 210, 13, 10, 35, 67, 50, 45, 77, 58, 48, 48, 54, 44,
48, 48, 52, 44, 48, 49, 46, 49, 50, 66, 50, 48, 13, 10,
];
assert_eq!(
Sweep::try_from(bytes.as_slice()).unwrap_err(),
MessageParseError::Truncated {
remainder: Some(&bytes[45..])
}
);
}
}