use std::convert::From;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
#[derive(Debug)]
pub struct ParserError(String);
impl fmt::Display for ParserError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for ParserError {}
impl<T> From<nom::Err<T>> for ParserError
where
nom::Err<T>: std::fmt::Debug,
{
fn from(error: nom::Err<T>) -> Self {
ParserError(format!("{:?}", error))
}
}
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
pub struct ICAOAddress(pub(crate) u8, pub(crate) u8, pub(crate) u8);
impl fmt::Display for ICAOAddress {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:02X}{:02X}{:02X}", self.0, self.1, self.2)
}
}
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
pub struct Squawk(pub(crate) u8, pub(crate) u8);
impl From<u16> for Squawk {
fn from(value: u16) -> Self {
Squawk(((value & 0xFF00) >> 8) as u8, (value & 0x00FF) as u8)
}
}
impl FromStr for Squawk {
type Err = std::num::ParseIntError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
Ok(u16::from_str_radix(value, 16)?.into())
}
}
impl fmt::Display for Squawk {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:02X}{:02X}", self.0, self.1)
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Position {
pub latitude: f64,
pub longitude: f64,
}
#[derive(Debug, PartialEq, Clone)]
pub struct CPRFrame {
pub position: Position,
pub parity: Parity,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Parity {
Even,
Odd,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum VerticalRateSource {
BarometricPressureAltitude,
GeometricAltitude,
}
#[derive(Debug, PartialEq)]
pub struct Message {
pub downlink_format: u8,
pub kind: MessageKind,
}
#[derive(Debug, PartialEq, Clone)]
pub enum MessageKind {
ADSBMessage {
capability: u8,
icao_address: ICAOAddress,
type_code: u8,
kind: ADSBMessageKind,
crc: bool,
},
ModeSMessage {
icao_address: ICAOAddress,
kind: ModeSMessageKind,
},
Unknown,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ModeSMessageKind {
SurveillanceIdentity {
squawk: Squawk,
},
}
#[derive(Debug, PartialEq, Clone)]
pub enum ADSBMessageKind {
AircraftIdentification {
emitter_category: u8,
callsign: String,
},
AirbornePosition {
altitude: u16,
cpr_frame: CPRFrame,
},
AirborneVelocity {
heading: f64,
ground_speed: f64,
vertical_rate: i16,
vertical_rate_source: VerticalRateSource,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn convert_squawk() {
assert_eq!(Squawk::from(22128), Squawk(86, 112));
assert_eq!(Squawk::from_str("5670").unwrap(), Squawk(86, 112));
assert_eq!(format!("{}", Squawk::from_str("5670").unwrap()), "5670");
assert_eq!(Squawk::from(4608), Squawk(18, 0));
assert_eq!(Squawk::from_str("1200").unwrap(), Squawk(18, 0));
assert_eq!(format!("{}", Squawk::from_str("1200").unwrap()), "1200");
}
}