1use crate::EncodeError;
2use crate::ais::encode::{
3 BitWriter, encode_cog, encode_epfd, encode_heading, encode_latitude, encode_longitude,
4 encode_position_timestamp, encode_sog, encode_timestamp,
5};
6
7use super::{AisEncodable, AisTransmitOptions, PositionTimestamp, encode_payload};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum ClassBCommunicationState {
12 Sotdma(u32),
13 Itdma(u32),
14}
15
16impl ClassBCommunicationState {
17 fn selector(self) -> bool {
18 matches!(self, Self::Itdma(_))
19 }
20
21 fn value(self) -> u32 {
22 match self {
23 Self::Sotdma(value) | Self::Itdma(value) => value,
24 }
25 }
26}
27
28#[derive(Debug, Clone, PartialEq)]
30pub struct ClassBPosition {
31 pub repeat_indicator: u8,
32 pub mmsi: u32,
33 pub sog: Option<f32>,
34 pub position_accuracy: bool,
35 pub longitude: Option<f64>,
36 pub latitude: Option<f64>,
37 pub cog: Option<f32>,
38 pub heading: Option<u16>,
39 pub timestamp: Option<u8>,
40 pub transmit_power_low: bool,
41 pub class_b_cs: bool,
42 pub display_available: bool,
43 pub dsc_capable: bool,
44 pub full_band_capable: bool,
45 pub message_22_capable: bool,
46 pub assigned_mode: bool,
47 pub raim: bool,
48 pub communication_state: ClassBCommunicationState,
49}
50
51#[derive(Debug, Clone, PartialEq)]
53pub struct ClassBExtendedPosition {
54 pub repeat_indicator: u8,
55 pub mmsi: u32,
56 pub sog: Option<f32>,
57 pub position_accuracy: bool,
58 pub longitude: Option<f64>,
59 pub latitude: Option<f64>,
60 pub cog: Option<f32>,
61 pub heading: Option<u16>,
62 pub timestamp: PositionTimestamp,
63 pub vessel_name: String,
64 pub ship_type: u8,
65 pub dimension_to_bow: u16,
66 pub dimension_to_stern: u16,
67 pub dimension_to_port: u8,
68 pub dimension_to_starboard: u8,
69 pub position_fixing_device: u8,
70 pub dte: bool,
72 pub assigned_mode: bool,
73 pub raim: bool,
74}
75
76#[derive(Debug, Clone, PartialEq)]
78pub struct ClassBStaticPartA {
79 pub repeat_indicator: u8,
80 pub mmsi: u32,
81 pub vessel_name: String,
82}
83
84#[derive(Debug, Clone, PartialEq)]
86pub struct ClassBStaticPartB {
87 pub repeat_indicator: u8,
88 pub mmsi: u32,
89 pub ship_type: u8,
90 pub manufacturer_id: String,
92 pub model_code: u8,
93 pub serial_number: u32,
94 pub callsign: String,
95 pub dimension_to_bow: u16,
96 pub dimension_to_stern: u16,
97 pub dimension_to_port: u8,
98 pub dimension_to_starboard: u8,
99 pub position_fixing_device: u8,
100 pub vdes_capabilities: u8,
102}
103
104impl AisEncodable for ClassBPosition {
105 fn to_sentences(&self, options: AisTransmitOptions) -> Result<Vec<String>, EncodeError> {
106 let mut writer = BitWriter::new();
107 writer.push_u32(18, 6, "message_type")?;
108 writer.push_u32(u32::from(self.repeat_indicator), 2, "repeat_indicator")?;
109 writer.push_u32(self.mmsi, 30, "mmsi")?;
110 writer.push_spare(8);
111 writer.push_u32(encode_sog(self.sog)?, 10, "sog")?;
112 writer.push_bool(self.position_accuracy);
113 writer.push_i32(encode_longitude(self.longitude)?, 28, "longitude")?;
114 writer.push_i32(encode_latitude(self.latitude)?, 27, "latitude")?;
115 writer.push_u32(encode_cog(self.cog)?, 12, "cog")?;
116 writer.push_u32(encode_heading(self.heading)?, 9, "heading")?;
117 writer.push_u32(encode_timestamp(self.timestamp)?, 6, "timestamp")?;
118 writer.push_bool(self.transmit_power_low);
119 writer.push_spare(1);
120 writer.push_bool(self.class_b_cs);
121 writer.push_bool(self.display_available);
122 writer.push_bool(self.dsc_capable);
123 writer.push_bool(self.full_band_capable);
124 writer.push_bool(self.message_22_capable);
125 writer.push_bool(self.assigned_mode);
126 writer.push_bool(self.raim);
127 writer.push_bool(self.communication_state.selector());
128 writer.push_u32(self.communication_state.value(), 19, "communication_state")?;
129 encode_payload(&writer.finish(), options)
130 }
131}
132
133impl AisEncodable for ClassBExtendedPosition {
134 fn to_sentences(&self, options: AisTransmitOptions) -> Result<Vec<String>, EncodeError> {
135 let mut writer = BitWriter::new();
136 writer.push_u32(19, 6, "message_type")?;
137 writer.push_u32(u32::from(self.repeat_indicator), 2, "repeat_indicator")?;
138 writer.push_u32(self.mmsi, 30, "mmsi")?;
139 writer.push_spare(8);
140 writer.push_u32(encode_sog(self.sog)?, 10, "sog")?;
141 writer.push_bool(self.position_accuracy);
142 writer.push_i32(encode_longitude(self.longitude)?, 28, "longitude")?;
143 writer.push_i32(encode_latitude(self.latitude)?, 27, "latitude")?;
144 writer.push_u32(encode_cog(self.cog)?, 12, "cog")?;
145 writer.push_u32(encode_heading(self.heading)?, 9, "heading")?;
146 writer.push_u32(encode_position_timestamp(self.timestamp)?, 6, "timestamp")?;
147 writer.push_spare(4);
148 writer.push_text(&self.vessel_name, 20, "vessel_name")?;
149 writer.push_u32(u32::from(self.ship_type), 8, "ship_type")?;
150 writer.push_u32(u32::from(self.dimension_to_bow), 9, "dimension_to_bow")?;
151 writer.push_u32(u32::from(self.dimension_to_stern), 9, "dimension_to_stern")?;
152 writer.push_u32(u32::from(self.dimension_to_port), 6, "dimension_to_port")?;
153 writer.push_u32(
154 u32::from(self.dimension_to_starboard),
155 6,
156 "dimension_to_starboard",
157 )?;
158 writer.push_u32(
159 encode_epfd(self.position_fixing_device)?,
160 4,
161 "position_fixing_device",
162 )?;
163 writer.push_bool(self.raim);
164 writer.push_bool(self.dte);
165 writer.push_bool(self.assigned_mode);
166 writer.push_spare(4);
167 encode_payload(&writer.finish(), options)
168 }
169}
170
171impl AisEncodable for ClassBStaticPartA {
172 fn to_sentences(&self, options: AisTransmitOptions) -> Result<Vec<String>, EncodeError> {
173 let mut writer = BitWriter::new();
174 writer.push_u32(24, 6, "message_type")?;
175 writer.push_u32(u32::from(self.repeat_indicator), 2, "repeat_indicator")?;
176 writer.push_u32(self.mmsi, 30, "mmsi")?;
177 writer.push_u32(0, 2, "part_number")?;
178 writer.push_text(&self.vessel_name, 20, "vessel_name")?;
179 encode_payload(&writer.finish(), options)
180 }
181}
182
183impl AisEncodable for ClassBStaticPartB {
184 fn to_sentences(&self, options: AisTransmitOptions) -> Result<Vec<String>, EncodeError> {
185 let mut writer = BitWriter::new();
186 writer.push_u32(24, 6, "message_type")?;
187 writer.push_u32(u32::from(self.repeat_indicator), 2, "repeat_indicator")?;
188 writer.push_u32(self.mmsi, 30, "mmsi")?;
189 writer.push_u32(1, 2, "part_number")?;
190 writer.push_u32(u32::from(self.ship_type), 8, "ship_type")?;
191 writer.push_text(&self.manufacturer_id, 3, "manufacturer_id")?;
192 writer.push_u32(u32::from(self.model_code), 4, "model_code")?;
193 writer.push_u32(self.serial_number, 20, "serial_number")?;
194 writer.push_text(&self.callsign, 7, "callsign")?;
195 writer.push_u32(u32::from(self.dimension_to_bow), 9, "dimension_to_bow")?;
196 writer.push_u32(u32::from(self.dimension_to_stern), 9, "dimension_to_stern")?;
197 writer.push_u32(u32::from(self.dimension_to_port), 6, "dimension_to_port")?;
198 writer.push_u32(
199 u32::from(self.dimension_to_starboard),
200 6,
201 "dimension_to_starboard",
202 )?;
203 writer.push_u32(
204 encode_epfd(self.position_fixing_device)?,
205 4,
206 "position_fixing_device",
207 )?;
208 writer.push_u32(u32::from(self.vdes_capabilities), 2, "vdes_capabilities")?;
209 encode_payload(&writer.finish(), options)
210 }
211}