use deku::prelude::*;
use serde::{Deserialize, Serialize};
use super::common::NavigationStatus;
use super::converters::*;
#[derive(Debug, Clone, PartialEq, DekuRead, Serialize, Deserialize)]
#[deku(endian = "big")]
pub struct LongRangeAisBroadcastMessage {
#[deku(bits = "6")]
pub msg_type: u8,
#[deku(bits = "2")]
pub repeat: u8,
#[deku(
bits = "30",
map = "|x: u32| -> Result<_, DekuError> { Ok(from_mmsi(x)) }"
)]
pub mmsi: u32,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub accuracy: bool,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub raim: bool,
#[deku(
bits = "4",
map = "|x: u8| -> Result<_, DekuError> { Ok(NavigationStatus::from_bits(x)) }"
)]
pub status: NavigationStatus,
#[deku(
bits = "18",
map = "|x: u32| -> Result<_, DekuError> { Ok(from_longitude_600(x)) }"
)]
pub longitude: Option<f64>,
#[deku(
bits = "17",
map = "|x: u32| -> Result<_, DekuError> { Ok(from_latitude_600(x)) }"
)]
pub latitude: Option<f64>,
#[deku(
bits = "6",
map = "|x: u8| -> Result<_, DekuError> { Ok(from_speed_longrange(x)) }"
)]
pub speed: Option<u8>,
#[deku(
bits = "9",
map = "|x: u16| -> Result<_, DekuError> { Ok(from_course_longrange(x)) }"
)]
pub course: Option<u16>,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub gnss: bool,
#[deku(bits = "1")]
#[serde(skip)]
pub spare_1: u8,
}
impl LongRangeAisBroadcastMessage {
pub fn asdict(&self) -> serde_json::Value {
serde_json::json!({
"msg_type": self.msg_type,
"repeat": self.repeat,
"mmsi": self.mmsi,
"accuracy": self.accuracy,
"raim": self.raim,
"status": self.status as u8,
"longitude": self.longitude,
"latitude": self.latitude,
"speed": self.speed,
"course": self.course,
"gnss": self.gnss,
})
}
pub fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::decode::nmea::NmeaAisMessage;
fn decode(sentence: &str) -> LongRangeAisBroadcastMessage {
let nmea_msg = NmeaAisMessage::parse(sentence).unwrap();
let binary_data = nmea_msg.payload_to_binary().unwrap();
let (_, msg) = LongRangeAisBroadcastMessage::from_bytes((&binary_data, 0)).unwrap();
msg
}
#[test]
fn test_msg_type_27_signed() {
let msg = decode("!AIVDO,1,1,,A,K01;FQh?PbtE3P00,0*75");
assert_eq!(msg.mmsi, 1234567);
assert!((msg.longitude.unwrap() - (-13.368333)).abs() < 0.000001);
assert!((msg.latitude.unwrap() - (-50.121667)).abs() < 0.000001);
}
#[test]
fn test_message_serialization() {
let msg = decode("!AIVDO,1,1,,A,K01;FQh?PbtE3P00,0*75");
let json = msg.to_json().unwrap();
let deserialized: LongRangeAisBroadcastMessage = serde_json::from_str(&json).unwrap();
assert_eq!(msg, deserialized);
}
}