nmea_parser/ais/
vdm_t22.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 22: Channel Management
22#[derive(Default, Clone, Debug, PartialEq)]
23pub struct ChannelManagement {
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    /// Channel A number (12 bits).
34    pub channel_a: u16,
35
36    /// Channel B number (12 bits).
37    pub channel_b: u16,
38
39    /// TxRx mode:
40    /// 0 = TxA/TxB, RxA/RxB (default)
41    /// 1 = TxA, RxA/RxB
42    /// 2 = TxB, RxA/RxB
43    /// 3 = Reserved for future use
44    pub txrx: u8,
45
46    /// Power level to be used:
47    /// 0 = low,
48    /// 1 = high
49    pub power: bool,
50
51    /// Northeast latitude to 0.1 minutes.
52    pub ne_lat: Option<f64>,
53
54    /// Northeast longitude to 0.1 minutes.
55    pub ne_lon: Option<f64>,
56
57    /// Southwest latitude to 0.1 minutes.
58    pub sw_lat: Option<f64>,
59
60    /// Southwest longitude to 0.1 minutes.
61    pub sw_lon: Option<f64>,
62
63    /// MMSI of destination 1 (30 bits).
64    pub dest1_mmsi: Option<u32>,
65
66    /// MMSI of destination 2 (30 bits).
67    pub dest2_mmsi: Option<u32>,
68
69    /// Addressed:
70    /// false = broadcast,
71    /// true = addressed
72    pub addressed: bool,
73
74    /// Channel A band:
75    /// false = default,
76    /// true = 12.5 kHz
77    pub channel_a_band: bool,
78
79    /// Channel B band:
80    /// false = default,
81    /// true = 12.5 kHz
82    pub channel_b_band: bool,
83
84    /// Size of transitional zone (3 bits).
85    pub zonesize: u8,
86}
87
88// -------------------------------------------------------------------------------------------------
89
90/// AIS VDM/VDO type 22: Channel Management
91pub(crate) fn handle(
92    bv: &BitVec,
93    station: Station,
94    own_vessel: bool,
95) -> Result<ParsedMessage, ParseError> {
96    let addressed = pick_u64(bv, 139, 1) != 0;
97    Ok(ParsedMessage::ChannelManagement(ChannelManagement {
98        own_vessel: { own_vessel },
99        station: { station },
100        mmsi: { pick_u64(bv, 8, 30) as u32 },
101        channel_a: { pick_u64(bv, 40, 12) as u16 },
102        channel_b: { pick_u64(bv, 52, 12) as u16 },
103        txrx: { pick_u64(bv, 64, 4) as u8 },
104        power: { pick_u64(bv, 68, 1) != 0 },
105        ne_lat: {
106            if !addressed {
107                Some(pick_i64(bv, 87, 17) as f64 / 600.0)
108            } else {
109                None
110            }
111        },
112        ne_lon: {
113            if !addressed {
114                Some(pick_i64(bv, 69, 18) as f64 / 600.0)
115            } else {
116                None
117            }
118        },
119        sw_lat: {
120            if !addressed {
121                Some(pick_i64(bv, 122, 17) as f64 / 600.0)
122            } else {
123                None
124            }
125        },
126        sw_lon: {
127            if !addressed {
128                Some(pick_i64(bv, 104, 18) as f64 / 600.0)
129            } else {
130                None
131            }
132        },
133        dest1_mmsi: {
134            if addressed {
135                Some(pick_u64(bv, 69, 30) as u32)
136            } else {
137                None
138            }
139        },
140        dest2_mmsi: {
141            if addressed {
142                Some(pick_u64(bv, 104, 30) as u32)
143            } else {
144                None
145            }
146        },
147        addressed: { pick_u64(bv, 139, 1) != 0 },
148        channel_a_band: { pick_u64(bv, 140, 1) != 0 },
149        channel_b_band: { pick_u64(bv, 141, 1) != 0 },
150        zonesize: { pick_u64(bv, 142, 3) as u8 },
151    }))
152}
153
154// -------------------------------------------------------------------------------------------------
155
156#[cfg(test)]
157mod test {
158    use super::*;
159
160    #[test]
161    fn test_parse_vdm_type22() {
162        let mut p = NmeaParser::new();
163        match p.parse_sentence("!AIVDM,1,1,,A,F030ot22N2P6aoQbhe4736L20000,0*1A") {
164            Ok(ps) => {
165                match ps {
166                    // The expected result
167                    ParsedMessage::ChannelManagement(cm) => {
168                        assert_eq!(cm.mmsi, 3160048);
169                        assert_eq!(cm.channel_a, 2087);
170                        assert_eq!(cm.channel_b, 2088);
171                        assert_eq!(cm.txrx, 0);
172                        assert!(!cm.power);
173                        assert::close(cm.ne_lat.unwrap_or(0.0), 45.55, 0.01);
174                        assert::close(cm.ne_lon.unwrap_or(0.0), -73.50, 0.01);
175                        assert::close(cm.sw_lat.unwrap_or(0.0), 42.33, 0.01);
176                        assert::close(cm.sw_lon.unwrap_or(0.0), -80.17, 0.01);
177                        assert!(!cm.addressed);
178                        assert!(!cm.channel_a_band);
179                        assert!(!cm.channel_b_band);
180                        assert_eq!(cm.zonesize, 4);
181                    }
182                    ParsedMessage::Incomplete => {
183                        assert!(false);
184                    }
185                    _ => {
186                        assert!(false);
187                    }
188                }
189            }
190            Err(e) => {
191                assert_eq!(e.to_string(), "OK");
192            }
193        }
194    }
195}