nmea_parser/ais/vdm_t25.rs
1/*
2Copyright 2020-2021 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 25: Single Slot Binary Message
22#[derive(Default, Clone, Debug, PartialEq)]
23pub struct SingleSlotBinaryMessage {
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 /// When 'addressed' flag is on this field contains the parsed destination MMSI.
34 pub dest_mmsi: Option<u32>,
35
36 /// When 'addressed' flag is off and 'structured' flag on this field contains
37 /// application ID which consists of 10-bit DAC and 6-bit FID as in message types 6 and 8.
38 pub app_id: Option<u16>,
39
40 /// Data field of length 0-128 bits.
41 pub data: BitVec,
42}
43
44// -------------------------------------------------------------------------------------------------
45
46/// AIS VDM/VDO type 25: Single Slot Binary Message
47#[allow(clippy::collapsible_if)]
48pub(crate) fn handle(
49 bv: &BitVec,
50 station: Station,
51 own_vessel: bool,
52) -> Result<ParsedMessage, ParseError> {
53 let addressed = pick_u64(bv, 38, 1) != 0;
54 let structured = pick_u64(bv, 39, 1) != 0;
55
56 Ok(ParsedMessage::SingleSlotBinaryMessage(
57 SingleSlotBinaryMessage {
58 own_vessel: { own_vessel },
59 station: { station },
60 mmsi: { pick_u64(bv, 8, 30) as u32 },
61 dest_mmsi: {
62 if addressed {
63 Some(pick_u64(bv, 40, 30) as u32)
64 } else {
65 None
66 }
67 },
68 app_id: {
69 if addressed {
70 None
71 } else if structured {
72 Some(pick_u64(bv, 70, 16) as u16)
73 } else {
74 None
75 }
76 },
77 data: {
78 if addressed {
79 BitVec::from_bitslice(&bv[70..max(70, bv.len())])
80 } else if structured {
81 BitVec::from_bitslice(&bv[86..max(86, bv.len())])
82 } else {
83 BitVec::from_bitslice(&bv[40..max(40, bv.len())])
84 }
85 },
86 },
87 ))
88}
89
90// -------------------------------------------------------------------------------------------------
91
92#[cfg(test)]
93mod test {
94 use super::*;
95
96 #[test]
97 fn test_parse_vdm_type25() {
98 let mut p = NmeaParser::new();
99
100 // Test 1
101 match p.parse_sentence("!AIVDM,1,1,,A,I6SWo?8P00a3PKpEKEVj0?vNP<65,0*73") {
102 Ok(ps) => {
103 match ps {
104 // The expected result
105 ParsedMessage::SingleSlotBinaryMessage(ssbm) => {
106 assert_eq!(ssbm.mmsi, 440006460);
107 assert_eq!(ssbm.dest_mmsi, Some(134218384));
108 assert_eq!(ssbm.app_id, None);
109 }
110 ParsedMessage::Incomplete => {
111 assert!(false);
112 }
113 _ => {
114 assert!(false);
115 }
116 }
117 }
118 Err(e) => {
119 assert_eq!(e.to_string(), "OK");
120 }
121 }
122
123 // Test 2
124 match p.parse_sentence("!AIVDM,1,1,,A,I8IRGB40QPPa0:<HP::V=gwv0l48,0*0E") {
125 Ok(ps) => {
126 match ps {
127 // The expected result
128 ParsedMessage::SingleSlotBinaryMessage(ssbm) => {
129 assert_eq!(ssbm.mmsi, 563648328);
130 assert_eq!(ssbm.dest_mmsi, None);
131 assert_eq!(ssbm.app_id, Some(16424));
132 }
133 ParsedMessage::Incomplete => {
134 assert!(false);
135 }
136 _ => {
137 assert!(false);
138 }
139 }
140 }
141 Err(e) => {
142 assert_eq!(e.to_string(), "OK");
143 }
144 }
145
146 // Test 3
147 match p.parse_sentence("!AIVDM,1,1,,A,I6SWVNP001a3P8FEKNf=Qb0@00S8,0*6B") {
148 Ok(ps) => {
149 match ps {
150 // The expected result
151 ParsedMessage::SingleSlotBinaryMessage(ssbm) => {
152 assert_eq!(ssbm.mmsi, 440002170);
153 assert_eq!(ssbm.dest_mmsi, None);
154 assert_eq!(ssbm.app_id, None);
155 }
156 ParsedMessage::Incomplete => {
157 assert!(false);
158 }
159 _ => {
160 assert!(false);
161 }
162 }
163 }
164 Err(e) => {
165 assert_eq!(e.to_string(), "OK");
166 }
167 }
168 }
169}