use super::*;
#[derive(Default, Clone, Debug, PartialEq)]
pub struct AidToNavigationReport {
pub own_vessel: bool,
pub station: Station,
pub mmsi: u32,
pub aid_type: NavAidType,
pub name: String,
high_position_accuracy: bool,
pub latitude: Option<f64>,
pub longitude: Option<f64>,
pub dimension_to_bow: Option<u16>,
pub dimension_to_stern: Option<u16>,
pub dimension_to_port: Option<u16>,
pub dimension_to_starboard: Option<u16>,
pub position_fix_type: Option<PositionFixType>,
pub timestamp_seconds: u8,
pub off_position_indicator: bool,
pub regional: u8,
pub raim_flag: bool,
pub virtual_aid_flag: bool,
pub assigned_mode_flag: bool,
}
impl LatLon for AidToNavigationReport {
fn latitude(&self) -> Option<f64> {
self.latitude
}
fn longitude(&self) -> Option<f64> {
self.longitude
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum NavAidType {
NotSpecified,
ReferencePoint,
Racon,
FixedStructure,
Reserved4,
LightWithoutSectors,
LightWithSectors,
LeadingLightFront,
LeadingLightRear,
BeaconCardinalNorth,
BeaconCardinalEast,
BeaconCardinalSouth,
BeaconCardinalWest,
BeaconLateralPort,
BeaconLateralStarboard,
BeaconLateralPreferredChannelPort,
BeaconLateralPreferredChannelStarboard,
BeaconIsolatedDanger,
BeaconSafeWater,
BeaconSpecialMark,
CardinalMarkNorth,
CardinalMarkEast,
CardinalMarkSouth,
CardinalMarkWest,
PortHandMark,
StarboardHandMark,
PreferredChannelPort,
PreferredChannelStarboard,
IsolatedDanger,
SafeWater,
SpecialMark,
LightVessel,
}
impl NavAidType {
fn new(raw: u8) -> Result<NavAidType, ParseError> {
match raw {
0 => Ok(NavAidType::NotSpecified),
1 => Ok(NavAidType::ReferencePoint),
2 => Ok(NavAidType::Racon),
3 => Ok(NavAidType::FixedStructure),
4 => Ok(NavAidType::Reserved4),
5 => Ok(NavAidType::LightWithoutSectors),
6 => Ok(NavAidType::LightWithSectors),
7 => Ok(NavAidType::LeadingLightFront),
8 => Ok(NavAidType::LeadingLightRear),
9 => Ok(NavAidType::BeaconCardinalNorth),
10 => Ok(NavAidType::BeaconCardinalEast),
11 => Ok(NavAidType::BeaconCardinalSouth),
12 => Ok(NavAidType::BeaconCardinalWest),
13 => Ok(NavAidType::BeaconLateralPort),
14 => Ok(NavAidType::BeaconLateralStarboard),
15 => Ok(NavAidType::BeaconLateralPreferredChannelPort),
16 => Ok(NavAidType::BeaconLateralPreferredChannelStarboard),
17 => Ok(NavAidType::BeaconIsolatedDanger),
18 => Ok(NavAidType::BeaconSafeWater),
19 => Ok(NavAidType::BeaconSpecialMark),
20 => Ok(NavAidType::CardinalMarkNorth),
21 => Ok(NavAidType::CardinalMarkEast),
22 => Ok(NavAidType::CardinalMarkSouth),
23 => Ok(NavAidType::CardinalMarkWest),
24 => Ok(NavAidType::PortHandMark),
25 => Ok(NavAidType::StarboardHandMark),
26 => Ok(NavAidType::PreferredChannelPort),
27 => Ok(NavAidType::PreferredChannelStarboard),
28 => Ok(NavAidType::IsolatedDanger),
29 => Ok(NavAidType::SafeWater),
30 => Ok(NavAidType::SpecialMark),
31 => Ok(NavAidType::LightVessel),
_ => Err(format!("Unrecognized Nav aid type code: {}", raw).into()),
}
}
}
impl Default for NavAidType {
fn default() -> NavAidType {
NavAidType::NotSpecified
}
}
impl std::fmt::Display for NavAidType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NavAidType::NotSpecified => { write!(f, "not specified") },
NavAidType::ReferencePoint => { write!(f, "reference point") },
NavAidType::Racon => { write!(f, "RACON") },
NavAidType::FixedStructure => { write!(f, "FixedStructure") },
NavAidType::Reserved4 => { write!(f, "(reserved)") },
NavAidType::LightWithoutSectors => { write!(f, "light without sectors") },
NavAidType::LightWithSectors => { write!(f, "light with sectors") },
NavAidType::LeadingLightFront => { write!(f, "leading light front") },
NavAidType::LeadingLightRear => { write!(f, "leading light rear") },
NavAidType::BeaconCardinalNorth => { write!(f, "cardinal beacon, north") },
NavAidType::BeaconCardinalEast => { write!(f, "cardinal beacon, east") },
NavAidType::BeaconCardinalSouth => { write!(f, "cardinal beacon, south") },
NavAidType::BeaconCardinalWest => { write!(f, "cardinal beacon, west") },
NavAidType::BeaconLateralPort => { write!(f, "lateral beacon, port side") },
NavAidType::BeaconLateralStarboard => { write!(f, "lateral beacon, starboard side") },
NavAidType::BeaconLateralPreferredChannelPort => {
write!(f, "lateral beacon, preferred channel, port side")
},
NavAidType::BeaconLateralPreferredChannelStarboard => {
write!(f, "lateral beacon, preferred channel, starboard side")
},
NavAidType::BeaconIsolatedDanger => { write!(f, "isolated danger beacon") },
NavAidType::BeaconSafeWater => { write!(f, "safe water") },
NavAidType::BeaconSpecialMark => { write!(f, "special mark") },
NavAidType::CardinalMarkNorth => { write!(f, "cardinal mark, north") },
NavAidType::CardinalMarkEast => { write!(f, "cardinal mark, east") },
NavAidType::CardinalMarkSouth => { write!(f, "cardinal mark, south") },
NavAidType::CardinalMarkWest => { write!(f, "cardinal mark, west") },
NavAidType::PortHandMark => { write!(f, "port hand mark") },
NavAidType::StarboardHandMark => { write!(f, "starboard hand mark") },
NavAidType::PreferredChannelPort => {
write!(f, "preferred channel, port side")
},
NavAidType::PreferredChannelStarboard => {
write!(f, "preferred channel, starboard side")
},
NavAidType::IsolatedDanger => { write!(f, "isolated danger") },
NavAidType::SafeWater => { write!(f, "safe water") },
NavAidType::SpecialMark => { write!(f, "special mark") },
NavAidType::LightVessel => { write!(f, "light vessel") },
}
}
}
#[doc(hidden)]
pub fn handle(bv: &BitVec, station: Station, own_vessel: bool) -> Result<ParsedSentence, ParseError> {
return Ok(ParsedSentence::AidToNavigationReport(AidToNavigationReport{
own_vessel: {
own_vessel
},
station: {
station
},
mmsi: {
pick_u64(&bv, 8, 30) as u32
},
aid_type: {
NavAidType::new(pick_u64(&bv, 38, 5) as u8).ok().unwrap_or(NavAidType::NotSpecified)
},
name: {
let mut s = pick_string(&bv, 43, 20);
s.push_str(&pick_string(&bv, 272, 14));
s
},
high_position_accuracy: {
pick_u64(&bv, 163, 1) != 0
},
latitude: {
let lat_raw = pick_i64(&bv, 192, 27) as i32;
if lat_raw != 0x3412140 {
Some((lat_raw as f64) / 600000.0)
} else {
None
}
},
longitude: {
let lon_raw = pick_i64(&bv, 164, 28) as i32;
if lon_raw != 0x6791AC0 {
Some((lon_raw as f64) / 600000.0)
} else {
None
}
},
dimension_to_bow: {
Some(pick_u64(&bv, 219, 9) as u16)
},
dimension_to_stern: {
Some(pick_u64(&bv, 228, 9) as u16)
},
dimension_to_port: {
Some(pick_u64(&bv, 237, 6) as u16)
},
dimension_to_starboard: {
Some(pick_u64(&bv, 243, 6) as u16)
},
position_fix_type: {
Some(PositionFixType::new(pick_u64(&bv, 249, 4) as u8))
},
timestamp_seconds: {
pick_u64(&bv, 253, 6) as u8
},
off_position_indicator: {
pick_u64(&bv, 243, 1) != 0
},
regional: {
pick_u64(&bv, 260, 8) as u8
},
raim_flag: {
pick_u64(&bv, 268, 1) != 0
},
virtual_aid_flag: {
pick_u64(&bv, 269, 1) != 0
},
assigned_mode_flag: {
pick_u64(&bv, 270, 1) != 0
},
}));
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_parse_vdm_type21() {
let mut p = NmeaParser::new();
match p.parse_sentence("!AIVDM,2,1,5,B,E1mg=5J1T4W0h97aRh6ba84<h2d;W:Te=eLvH50```q,0*46") {
Ok(ps) => {
match ps {
ParsedSentence::Incomplete => {
assert!(true);
},
_ => {
assert!(false);
}
}
},
Err(e) => {
assert_eq!(e.to_string(), "OK");
}
}
match p.parse_sentence("!AIVDM,2,2,5,B,:D44QDlp0C1DU00,2*36") {
Ok(ps) => {
match ps {
ParsedSentence::AidToNavigationReport(atnr) => {
assert_eq!(atnr.mmsi, 123456789);
assert_eq!(atnr.aid_type, NavAidType::CardinalMarkNorth);
assert_eq!(atnr.name, "CHINA ROSE MURPHY EXPRESS ALERT");
assert_eq!(atnr.high_position_accuracy, false);
assert::close(atnr.latitude.unwrap_or(0.0), 47.9206183333, 0.00000001);
assert::close(atnr.longitude.unwrap_or(0.0), -122.698591667, 0.00000001);
assert_eq!(atnr.dimension_to_bow, Some(5));
assert_eq!(atnr.dimension_to_stern, Some(5));
assert_eq!(atnr.dimension_to_port, Some(5));
assert_eq!(atnr.dimension_to_starboard, Some(5));
assert_eq!(atnr.position_fix_type, Some(PositionFixType::GPS));
assert_eq!(atnr.timestamp_seconds, 50);
assert_eq!(atnr.off_position_indicator, false);
assert_eq!(atnr.regional, 165);
assert_eq!(atnr.raim_flag, false);
assert_eq!(atnr.virtual_aid_flag, false);
assert_eq!(atnr.assigned_mode_flag, false);
},
ParsedSentence::Incomplete => {
assert!(false);
},
_ => {
assert!(false);
}
}
},
Err(e) => {
assert_eq!(e.to_string(), "OK");
}
}
}
}