Skip to main content

nmea_kit/ais/messages/
assignment_mode.rs

1//! AIS Type 16 — Assigned mode command.
2
3use crate::ais::armor::extract_u32;
4
5/// A Type 16 assignment for one destination station.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct Assignment {
8    pub destination_mmsi: u32,
9    pub offset: u16,
10    pub increment: u16,
11}
12
13/// AIS Type 16 assigned mode command.
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct AssignmentModeCommand {
16    pub repeat_indicator: u8,
17    pub mmsi: u32,
18    /// One or two assigned stations.
19    pub assignments: Vec<Assignment>,
20}
21
22impl AssignmentModeCommand {
23    pub(crate) fn decode(bits: &[u8]) -> Option<Self> {
24        if bits.len() < 96 {
25            return None;
26        }
27        let mut assignments = vec![decode_assignment(bits, 40)?];
28        if bits.len() >= 144 {
29            assignments.push(decode_assignment(bits, 92)?);
30        }
31        Some(Self {
32            repeat_indicator: extract_u32(bits, 6, 2)? as u8,
33            mmsi: extract_u32(bits, 8, 30)?,
34            assignments,
35        })
36    }
37}
38
39fn decode_assignment(bits: &[u8], offset: usize) -> Option<Assignment> {
40    Some(Assignment {
41        destination_mmsi: extract_u32(bits, offset, 30)?,
42        offset: extract_u32(bits, offset + 30, 12)? as u16,
43        increment: extract_u32(bits, offset + 42, 10)? as u16,
44    })
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50    use crate::ais::messages::test_helpers::set_bits;
51
52    #[test]
53    fn decodes_two_assignments() {
54        let mut bits = vec![0; 144];
55        set_bits(&mut bits, 0, 6, 16);
56        set_bits(&mut bits, 6, 2, 1);
57        set_bits(&mut bits, 8, 30, 123_456_789);
58        set_bits(&mut bits, 40, 30, 111_111_111);
59        set_bits(&mut bits, 70, 12, 100);
60        set_bits(&mut bits, 82, 10, 25);
61        set_bits(&mut bits, 92, 30, 222_222_222);
62        set_bits(&mut bits, 122, 12, 200);
63        set_bits(&mut bits, 134, 10, 50);
64
65        let message = AssignmentModeCommand::decode(&bits).expect("decode");
66        assert_eq!(message.repeat_indicator, 1);
67        assert_eq!(message.mmsi, 123_456_789);
68        assert_eq!(
69            message.assignments,
70            vec![
71                Assignment {
72                    destination_mmsi: 111_111_111,
73                    offset: 100,
74                    increment: 25,
75                },
76                Assignment {
77                    destination_mmsi: 222_222_222,
78                    offset: 200,
79                    increment: 50,
80                },
81            ]
82        );
83    }
84}