nmea_parser/ais/vdm_t4.rs
1/*
2Copyright 2020 Timo Saarinen
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17use super::*;
18
19// -------------------------------------------------------------------------------------------------
20
21/// Type 4: Base Station Report
22#[derive(Default, Clone, Debug, PartialEq)]
23pub struct BaseStationReport {
24 /// True if the data is about own vessel, false if about other.
25 pub own_vessel: bool,
26
27 /// AIS station type.
28 pub station: Station,
29
30 /// User ID (30 bits)
31 pub mmsi: u32,
32
33 /// Timestamp
34 pub timestamp: Option<DateTime<Utc>>,
35
36 /// Position accuracy: true = high (<= 10 m), false = low (> 10 m)
37 pub high_position_accuracy: bool,
38
39 /// Latitude
40 pub latitude: Option<f64>,
41
42 /// Longitude
43 pub longitude: Option<f64>,
44
45 // Type of electronic position fixing device.
46 pub position_fix_type: Option<PositionFixType>,
47
48 /// Riverine And Inland Navigation systems blue sign:
49 /// RAIM (Receiver autonomous integrity monitoring) flag of electronic position
50 /// fixing device; false = RAIM not in use = default; true = RAIM in use
51 pub raim_flag: bool,
52
53 /// Communication state
54 /// Diagnostic information for the radio system.
55 /// <https://www.itu.int/dms_pubrec/itu-r/rec/m/R-REC-M.1371-1-200108-S!!PDF-E.pdf>
56 pub radio_status: u32,
57}
58
59impl LatLon for BaseStationReport {
60 fn latitude(&self) -> Option<f64> {
61 self.latitude
62 }
63
64 fn longitude(&self) -> Option<f64> {
65 self.longitude
66 }
67}
68
69// -------------------------------------------------------------------------------------------------
70
71/// AIS VDM/VDO type 4: Base Station Report
72pub(crate) fn handle(
73 bv: &BitVec,
74 station: Station,
75 own_vessel: bool,
76) -> Result<ParsedMessage, ParseError> {
77 Ok(ParsedMessage::BaseStationReport(BaseStationReport {
78 own_vessel: { own_vessel },
79 station: { station },
80 mmsi: { pick_u64(bv, 8, 30) as u32 },
81 timestamp: {
82 Some(parse_ymdhs(
83 pick_u64(bv, 38, 14) as i32,
84 pick_u64(bv, 52, 4) as u32,
85 pick_u64(bv, 56, 5) as u32,
86 pick_u64(bv, 61, 5) as u32,
87 pick_u64(bv, 66, 6) as u32,
88 pick_u64(bv, 72, 6) as u32,
89 )?)
90 },
91 high_position_accuracy: { pick_u64(bv, 78, 1) != 0 },
92 latitude: {
93 let lat_raw = pick_i64(bv, 107, 27) as i32;
94 if lat_raw != 0x3412140 {
95 Some((lat_raw as f64) / 600000.0)
96 } else {
97 None
98 }
99 },
100 longitude: {
101 let lon_raw = pick_i64(bv, 79, 28) as i32;
102 if lon_raw != 0x6791AC0 {
103 Some((lon_raw as f64) / 600000.0)
104 } else {
105 None
106 }
107 },
108 position_fix_type: {
109 let raw = pick_u64(bv, 134, 4) as u8;
110 match raw {
111 0 => None,
112 _ => Some(PositionFixType::new(raw)),
113 }
114 },
115 raim_flag: { pick_u64(bv, 148, 1) != 0 },
116 radio_status: { pick_u64(bv, 149, 19) as u32 },
117 }))
118}
119
120// -------------------------------------------------------------------------------------------------
121
122#[cfg(test)]
123mod test {
124 use super::*;
125
126 #[test]
127 fn test_parse_vdm_type4() {
128 let mut p = NmeaParser::new();
129 match p.parse_sentence("!AIVDM,1,1,,A,403OviQuMGCqWrRO9>E6fE700@GO,0*4D") {
130 Ok(ps) => {
131 match ps {
132 // The expected result
133 ParsedMessage::BaseStationReport(bsr) => {
134 assert_eq!(bsr.mmsi, 3669702);
135 assert_eq!(
136 bsr.timestamp,
137 Utc.with_ymd_and_hms(2007, 5, 14, 19, 57, 39).single()
138 );
139 assert!(bsr.high_position_accuracy);
140 assert::close(bsr.latitude.unwrap_or(0.0), 36.884, 0.001);
141 assert::close(bsr.longitude.unwrap_or(0.0), -76.352, 0.001);
142 assert_eq!(bsr.position_fix_type, Some(PositionFixType::Surveyed));
143 assert!(!bsr.raim_flag);
144 assert_eq!(bsr.radio_status, 67039);
145 }
146 ParsedMessage::Incomplete => {
147 assert!(false);
148 }
149 _ => {
150 assert!(false);
151 }
152 }
153 }
154 Err(e) => {
155 assert_eq!(e.to_string(), "OK");
156 }
157 }
158 }
159}