use deku::prelude::*;
use serde::{Deserialize, Serialize};
use crate::decode::{AC13Field, ICAO};
#[derive(Debug, PartialEq, Serialize, Deserialize, DekuRead, Clone)]
#[serde(tag = "bds", rename = "30")]
pub struct ACASResolutionAdvisory {
#[deku(bits = "8", map = "fail_if_not30")]
#[serde(skip)]
pub bds: u8,
#[deku(bits = "1")]
pub issued_ra: bool,
#[deku(
bits = "1",
map = "|v: bool| -> Result<_, DekuError> {
if *issued_ra { Ok(Some(v)) } else { Ok(None) }
}"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub corrective: Option<bool>,
#[deku(
bits = "1",
map = "|v: bool| -> Result<_, DekuError> {
if *issued_ra { Ok(Some(v)) } else { Ok(None) }
}"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub downward_sense: Option<bool>,
#[deku(
bits = "1",
map = "|v: bool| -> Result<_, DekuError> {
if *issued_ra { Ok(Some(v)) } else { Ok(None) }
}"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub increased_rate: Option<bool>,
#[deku(
bits = "1",
map = "|v: bool| -> Result<_, DekuError> {
if *issued_ra { Ok(Some(v)) } else { Ok(None) }
}"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub sense_reversal: Option<bool>,
#[deku(
bits = "1",
map = "|v: bool| -> Result<_, DekuError> {
if *issued_ra { Ok(Some(v)) } else { Ok(None) }
}"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub altitude_crossing: Option<bool>,
#[deku(
bits = "1",
map = "|v: bool| -> Result<_, DekuError> {
if *issued_ra { Ok(Some(v)) } else { Ok(None) }
}"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub positive: Option<bool>,
#[deku(bits = "7")]
#[serde(skip)]
pub reserved_acas3: u16,
#[deku(
bits = "1",
map = "|v: bool| -> Result<_, DekuError> {
if *issued_ra { Ok(Some(v)) } else { Ok(None) }
}"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub no_below: Option<bool>,
#[deku(
bits = "1",
map = "|v: bool| -> Result<_, DekuError> {
if *issued_ra { Ok(Some(v)) } else { Ok(None) }
}"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub no_above: Option<bool>,
#[deku(
bits = "1",
map = "|v: bool| -> Result<_, DekuError> {
if *issued_ra { Ok(Some(v)) } else { Ok(None) }
}"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub no_left: Option<bool>,
#[deku(
bits = "1",
map = "|v: bool| -> Result<_, DekuError> {
if *issued_ra { Ok(Some(v)) } else { Ok(None) }
}"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub no_right: Option<bool>,
#[deku(bits = "1")]
pub terminated: bool,
#[deku(bits = "1")]
pub multiple: bool,
#[serde(flatten)]
pub threat_type: ThreatType,
}
#[derive(Debug, PartialEq, Serialize, Deserialize, DekuRead, Clone)]
#[deku(id_type = "u8", bits = "2")]
#[serde(untagged)]
pub enum ThreatType {
#[deku(id = "0")]
NoIdentity {
#[deku(bits = "26")]
#[serde(skip)]
unused: u32,
},
#[deku(id = "1")]
ThreatAddress(ThreadAddress),
#[deku(id = "2")]
ThreatOrientation(ThreatOrientation),
#[deku(id = "3")]
NotAssigned {
#[deku(bits = "26")]
#[serde(skip)]
unused: u32,
},
}
#[derive(Debug, PartialEq, Serialize, Deserialize, DekuRead, Clone)]
pub struct ThreadAddress {
pub threat_identity: ICAO,
#[deku(bits = "2")]
#[serde(skip)]
pub zeros: u8,
}
#[derive(Debug, PartialEq, Serialize, Deserialize, DekuRead, Clone)]
pub struct ThreatOrientation {
#[serde(rename = "threat_altitude")]
altitude: AC13Field,
#[deku(
bits = "7",
map = "|n: u8| -> Result<_, DekuError> {
if n == 0 { Ok(None) } else { Ok(Some((n as f32 - 1.) / 10.)) }
}"
)]
#[serde(rename = "threat_range")]
range: Option<f32>,
#[deku(
bits = "6",
map = "|n: u16| -> Result<_, DekuError> {
if n == 0 { Ok(None) } else { Ok(Some(6 * (n - 1) + 3)) }
}"
)]
#[serde(rename = "threat_bearing")]
bearing: Option<u16>,
}
fn fail_if_not30(value: u8) -> Result<u8, DekuError> {
if value == 0x30 {
Ok(value)
} else {
Err(DekuError::Assertion(
"First bits must be 0x30 in BDS 3,0".into(),
))
}
}