ais/messages/
dgnss_broadcast_binary_message.rs1use super::parsers::*;
3use super::AisMessageType;
4use crate::errors::Result;
5use crate::lib;
6use nom::bits::{bits, complete::take as take_bits};
7use nom::combinator::map;
8use nom::IResult;
9
10#[cfg(all(not(feature = "std"), not(feature = "alloc")))]
11const MAX_DATA_SIZE_BYTES: usize = 119;
12
13#[cfg(any(feature = "std", feature = "alloc"))]
14pub type CorrectionData = lib::std::vec::Vec<u8>;
15#[cfg(all(not(feature = "std"), not(feature = "alloc")))]
16pub type CorrectionData = lib::std::vec::Vec<u8, MAX_DATA_SIZE_BYTES>;
17
18#[derive(Debug, PartialEq)]
19pub struct DgnssBroadcastBinaryMessage {
20 pub message_type: u8,
21 pub repeat_indicator: u8,
22 pub mmsi: u32,
23 pub longitude: Option<f32>,
24 pub latitude: Option<f32>,
25 pub payload: DifferentialCorrectionData,
26}
27
28#[derive(Debug, PartialEq, Eq)]
29pub struct DifferentialCorrectionData {
30 pub message_type: u8,
31 pub station_id: u16,
32 pub z_count: u16,
33 pub sequence_number: u8,
34 pub n: u8,
35 pub health: u8,
36 pub data: CorrectionData,
37}
38
39impl DifferentialCorrectionData {
40 fn parse(data: (&[u8], usize)) -> IResult<(&[u8], usize), Self> {
41 let (data, message_type) = take_bits(6u8)(data)?;
42 let (data, station_id) = take_bits(10u8)(data)?;
43 let (data, z_count) = take_bits(13u8)(data)?;
44 let (data, sequence_number) = take_bits(3u8)(data)?;
45 let (data, n) = take_bits(5u8)(data)?;
46 let (data, health) = take_bits(3u8)(data)?;
47 #[cfg(any(feature = "std", feature = "alloc"))]
48 let data_owned = data.0.into();
49 #[cfg(all(not(feature = "std"), not(feature = "alloc")))]
50 let data_owned = data.0.try_into().map_err(|_| {
51 nom::Err::Failure(nom::error::Error::new(
52 data,
53 nom::error::ErrorKind::TooLarge,
54 ))
55 })?;
56 Ok((
57 (<&[u8]>::default(), 0),
58 Self {
59 message_type,
60 station_id,
61 z_count,
62 sequence_number,
63 n,
64 health,
65 data: data_owned,
66 },
67 ))
68 }
69}
70
71impl<'a> AisMessageType<'a> for DgnssBroadcastBinaryMessage {
72 fn name(&self) -> &'static str {
73 "DGNSS Broadcast Binary Message"
74 }
75
76 fn parse(data: &'a [u8]) -> Result<Self> {
77 let (_, message) = parse_base(data)?;
78 Ok(message)
79 }
80}
81
82fn parse_longitude_min_10(data: i32) -> Option<f32> {
83 match data {
84 108_600 => None,
85 _ => Some(data as f32 / 600.0),
86 }
87}
88
89fn parse_latitude_min_10(data: i32) -> Option<f32> {
90 match data {
91 54_600 => None,
92 _ => Some(data as f32 / 600.0),
93 }
94}
95
96fn parse_base(data: &[u8]) -> IResult<&[u8], DgnssBroadcastBinaryMessage> {
97 bits(move |data| -> IResult<_, _> {
98 let (data, message_type) = take_bits(6u8)(data)?;
99 let (data, repeat_indicator) = take_bits(2u8)(data)?;
100 let (data, mmsi) = take_bits(30u32)(data)?;
101 let (data, _spare) = take_bits::<_, u8, _, _>(2u8)(data)?;
102 let (data, longitude) = map(|data| signed_i32(data, 18), parse_longitude_min_10)(data)?;
103 let (data, latitude) = map(|data| signed_i32(data, 17), parse_latitude_min_10)(data)?;
104 let (data, _spare) = take_bits::<_, u8, _, _>(5u8)(data)?;
105 let (data, payload) = DifferentialCorrectionData::parse(data)?;
106 Ok((
107 data,
108 DgnssBroadcastBinaryMessage {
109 message_type,
110 repeat_indicator,
111 mmsi,
112 longitude,
113 latitude,
114 payload,
115 },
116 ))
117 })(data)
118}
119
120#[cfg(test)]
121mod tests {
122 #![allow(clippy::unreadable_literal)]
123 use super::*;
124 use crate::test_helpers::*;
125
126 #[test]
127 fn test_message() {
128 let bytestream =
129 b"A02VqLPA4I6C07h5Ed1h<OrsuBTTwS?r:C?w`?la<gno1RTRwSP9:BcurA8a:Oko02TSwu8<:Jbb";
130 let bitstream = crate::messages::unarmor(bytestream, 0).unwrap();
131 let message = DgnssBroadcastBinaryMessage::parse(bitstream.as_ref()).unwrap();
132 assert_eq!(message.message_type, 17);
133 assert_eq!(message.repeat_indicator, 0);
134 assert_eq!(message.mmsi, 2734450);
135 f32_equal_naive(message.longitude.unwrap(), 29.13);
136 f32_equal_naive(message.latitude.unwrap(), 59.986668);
137 assert_eq!(message.payload.z_count, 2776);
138 assert_eq!(message.payload.data.len(), 42);
139 }
140}