nmea_kit/ais/messages/
position_a.rs1use crate::ais::armor::{extract_i32, extract_u32};
4
5use super::common::{AisClass, NavigationStatus};
6use super::utils::{
7 decode_cog, decode_heading, decode_latitude, decode_longitude, decode_rot, decode_sog,
8};
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct PositionReport {
13 pub msg_type: u8,
14 pub mmsi: u32,
15 pub nav_status: Option<NavigationStatus>,
16 pub rate_of_turn: Option<f32>,
17 pub sog: Option<f32>,
18 pub position_accuracy: bool,
19 pub longitude: Option<f64>,
20 pub latitude: Option<f64>,
21 pub cog: Option<f32>,
22 pub heading: Option<u16>,
24 pub timestamp: Option<u8>,
25 pub ais_class: AisClass,
26}
27
28impl PositionReport {
29 pub fn decode_class_a(bits: &[u8]) -> Option<Self> {
31 if bits.len() < 168 {
32 return None;
33 }
34
35 let msg_type = extract_u32(bits, 0, 6)? as u8;
36 let mmsi = extract_u32(bits, 8, 30)?;
37 let nav_status_raw = extract_u32(bits, 38, 4)? as u8;
38 let rot_raw = extract_i32(bits, 42, 8)?;
39 let sog_raw = extract_u32(bits, 50, 10)?;
40 let accuracy = extract_u32(bits, 60, 1)? == 1;
41 let lon_raw = extract_i32(bits, 61, 28)?;
42 let lat_raw = extract_i32(bits, 89, 27)?;
43 let cog_raw = extract_u32(bits, 116, 12)?;
44 let hdg_raw = extract_u32(bits, 128, 9)?;
45 let ts_raw = extract_u32(bits, 137, 6)? as u8;
46
47 Some(Self {
48 msg_type,
49 mmsi,
50 nav_status: Some(NavigationStatus::from(nav_status_raw)),
51 rate_of_turn: decode_rot(rot_raw),
52 sog: decode_sog(sog_raw),
53 position_accuracy: accuracy,
54 longitude: decode_longitude(lon_raw),
55 latitude: decode_latitude(lat_raw),
56 cog: decode_cog(cog_raw),
57 heading: decode_heading(hdg_raw),
58 timestamp: if ts_raw < 60 { Some(ts_raw) } else { None },
59 ais_class: AisClass::A,
60 })
61 }
62}