use deku::prelude::*;
use serde::{Deserialize, Serialize};
use super::converters::*;
fn read_optional_mmsi<R: std::io::Read + std::io::Seek>(
reader: &mut Reader<R>,
) -> Result<Option<u32>, DekuError> {
match u32::from_reader_with_ctx(reader, deku::ctx::BitSize(30)) {
Ok(raw_mmsi) => {
if raw_mmsi == 0 {
Ok(None)
} else {
Ok(Some(from_mmsi(raw_mmsi)))
}
}
Err(DekuError::Incomplete(_)) => Ok(None), Err(e) => Err(e), }
}
fn read_optional_u8<R: std::io::Read + std::io::Seek>(
bits: usize,
) -> impl Fn(&mut Reader<R>) -> Result<Option<u8>, DekuError> {
move |reader: &mut Reader<R>| match u8::from_reader_with_ctx(reader, deku::ctx::BitSize(bits)) {
Ok(value) => Ok(Some(value)),
Err(DekuError::Incomplete(_)) => Ok(None),
Err(e) => Err(e),
}
}
fn read_optional_u16<R: std::io::Read + std::io::Seek>(
bits: usize,
) -> impl Fn(&mut Reader<R>) -> Result<Option<u16>, DekuError> {
move |reader: &mut Reader<R>| match u16::from_reader_with_ctx(reader, deku::ctx::BitSize(bits))
{
Ok(value) => Ok(Some(value)),
Err(DekuError::Incomplete(_)) => Ok(None),
Err(e) => Err(e),
}
}
#[derive(Debug, Clone, PartialEq, DekuRead, Serialize, Deserialize)]
#[deku(endian = "big")]
pub struct Interrogation {
#[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 = "2")]
#[serde(skip)]
pub spare_1: u8,
#[deku(
bits = "30",
map = "|x: u32| -> Result<_, DekuError> { Ok(from_mmsi(x)) }"
)]
pub mmsi1: u32,
#[deku(bits = "6")]
pub type1_1: u8,
#[deku(bits = "12")]
pub offset1_1: u16,
#[deku(reader = "read_optional_u8(2)(deku::reader)")]
#[serde(skip)]
pub spare_2: Option<u8>,
#[deku(reader = "read_optional_u8(6)(deku::reader)")]
pub type1_2: Option<u8>,
#[deku(reader = "read_optional_u16(12)(deku::reader)")]
pub offset1_2: Option<u16>,
#[deku(reader = "read_optional_u8(2)(deku::reader)")]
#[serde(skip)]
pub spare_3: Option<u8>,
#[deku(reader = "read_optional_mmsi(deku::reader)")]
pub mmsi2: Option<u32>,
#[deku(reader = "read_optional_u8(6)(deku::reader)")]
pub type2_1: Option<u8>,
#[deku(reader = "read_optional_u16(12)(deku::reader)")]
pub offset2_1: Option<u16>,
#[deku(reader = "read_optional_u8(2)(deku::reader)")]
#[serde(skip)]
pub spare_4: Option<u8>,
}
impl Interrogation {
pub fn asdict(&self) -> serde_json::Value {
serde_json::json!({
"msg_type": self.msg_type,
"repeat": self.repeat,
"mmsi": self.mmsi,
"mmsi1": self.mmsi1,
"type1_1": self.type1_1,
"offset1_1": self.offset1_1,
"type1_2": self.type1_2,
"offset1_2": self.offset1_2,
"mmsi2": self.mmsi2,
"type2_1": self.type2_1,
"offset2_1": self.offset2_1,
})
}
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) -> Interrogation {
let nmea_msg = NmeaAisMessage::parse(sentence).unwrap();
let binary_data = nmea_msg.payload_to_binary().unwrap();
let (_, msg) = Interrogation::from_bytes((&binary_data, 0)).unwrap();
msg
}
#[test]
fn test_msg_type_15_a() {
let msg = decode("!AIVDM,1,1,,A,?5OP=l00052HD00,2*5B");
assert_eq!(msg.msg_type, 15);
assert_eq!(msg.repeat, 0);
assert_eq!(msg.mmsi, 368578000);
assert_eq!(msg.offset1_1, 0);
assert_eq!(msg.mmsi1, 5158);
assert_eq!(msg.offset1_2, None);
assert_eq!(msg.mmsi2, None);
}
#[test]
fn test_msg_type_15_b() {
let msg = decode("!AIVDM,1,1,,B,?h3Ovn1GP<K0<P@59a0,2*04");
assert_eq!(msg.msg_type, 15);
assert_eq!(msg.repeat, 3);
assert_eq!(msg.mmsi, 3669720);
assert_eq!(msg.mmsi1, 367014320);
assert_eq!(msg.mmsi2, None);
assert_eq!(msg.type1_1, 3);
assert_eq!(msg.type1_2, Some(5));
assert_eq!(msg.offset1_1, 516);
}
#[test]
fn test_message_serialization() {
let msg = decode("!AIVDM,1,1,,A,?5OP=l00052HD00,2*5B");
let json = msg.to_json().unwrap();
let deserialized: Interrogation = serde_json::from_str(&json).unwrap();
assert_eq!(msg, deserialized);
}
#[test]
fn test_asdict_compatibility() {
let msg = decode("!AIVDM,1,1,,A,?5OP=l00052HD00,2*5B");
let dict = msg.asdict();
assert_eq!(dict["msg_type"], 15);
assert_eq!(dict["repeat"], 0);
assert_eq!(dict["mmsi"], 368578000);
assert_eq!(dict["mmsi1"], 5158);
assert_eq!(dict["offset1_2"], serde_json::Value::Null);
assert_eq!(dict["mmsi2"], serde_json::Value::Null);
}
#[test]
fn test_msg_type_15_fields() {
let msg = decode("!AIVDM,1,1,,A,?5OP=l00052HD00,2*5B");
assert_eq!(msg.msg_type, 15);
assert_eq!(msg.repeat, 0);
assert!(msg.mmsi > 0);
assert!(msg.mmsi1 > 0);
assert!(msg.to_json().is_ok());
}
}