use deku::prelude::*;
use serde::{Deserialize, Deserializer, Serialize};
use super::converters::*;
#[derive(Debug, Clone, PartialEq, DekuRead, Serialize, Deserialize)]
#[deku(endian = "big")]
pub struct ChannelManagementAddressed {
#[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 = "12")]
pub channel_a: u16,
#[deku(bits = "12")]
pub channel_b: u16,
#[deku(bits = "4")]
pub txrx: u8,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub power: bool,
#[deku(
bits = "30",
map = "|x: u32| -> Result<_, DekuError> { Ok(from_mmsi(x)) }"
)]
pub dest1: u32,
#[deku(bits = "5")]
pub empty_1: u8,
#[deku(
bits = "30",
map = "|x: u32| -> Result<_, DekuError> { Ok(from_mmsi(x)) }"
)]
pub dest2: u32,
#[deku(bits = "5")]
pub empty_2: u8,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub addressed: bool,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub band_a: bool,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub band_b: bool,
#[deku(bits = "3")]
pub zonesize: u8,
#[deku(bits = "23", assert_eq = "0")]
#[serde(skip)]
pub spare_2: u32,
}
#[derive(Debug, Clone, PartialEq, DekuRead, Serialize, Deserialize)]
#[deku(endian = "big")]
pub struct ChannelManagementBroadcast {
#[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", assert_eq = "0")]
#[serde(skip)]
pub spare_1: u8,
#[deku(bits = "12")]
pub channel_a: u16,
#[deku(bits = "12")]
pub channel_b: u16,
#[deku(bits = "4")]
pub txrx: u8,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub power: bool,
#[deku(
bits = "18",
map = "|x: u32| -> Result<_, DekuError> { Ok(from_10th_minutes(x, 18)) }"
)]
pub ne_lon: f64,
#[deku(
bits = "17",
map = "|x: u32| -> Result<_, DekuError> { Ok(from_10th_minutes(x, 17)) }"
)]
pub ne_lat: f64,
#[deku(
bits = "18",
map = "|x: u32| -> Result<_, DekuError> { Ok(from_10th_minutes(x, 18)) }"
)]
pub sw_lon: f64,
#[deku(
bits = "17",
map = "|x: u32| -> Result<_, DekuError> { Ok(from_10th_minutes(x, 17)) }"
)]
pub sw_lat: f64,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub addressed: bool,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub band_a: bool,
#[deku(bits = "1", map = "|x: u8| -> Result<_, DekuError> { Ok(x != 0) }")]
pub band_b: bool,
#[deku(bits = "3")]
pub zonesize: u8,
#[deku(bits = "23", assert_eq = "0")]
#[serde(skip)]
pub spare_2: u32,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(untagged)]
pub enum ChannelManagement {
Broadcast(ChannelManagementBroadcast),
Addressed(ChannelManagementAddressed),
}
impl<'de> Deserialize<'de> for ChannelManagement {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de;
let value = serde_json::Value::deserialize(deserializer)?;
let addressed = value
.get("addressed")
.and_then(|v| v.as_bool())
.unwrap_or(false);
if addressed {
serde_json::from_value(value)
.map(ChannelManagement::Addressed)
.map_err(de::Error::custom)
} else {
serde_json::from_value(value)
.map(ChannelManagement::Broadcast)
.map_err(de::Error::custom)
}
}
}
impl ChannelManagement {
pub fn from_bytes(data: (&[u8], usize)) -> Result<((&[u8], usize), Self), DekuError> {
let (bytes, _bit_offset) = data;
if bytes.len() < 18 {
return Err(DekuError::Incomplete(deku::error::NeedSize::new(18 * 8)));
}
let addressed_bit = (bytes[17] & 0x02) != 0;
if addressed_bit {
let (remaining, addressed_msg) = ChannelManagementAddressed::from_bytes(data)?;
Ok((remaining, ChannelManagement::Addressed(addressed_msg)))
} else {
let (remaining, broadcast_msg) = ChannelManagementBroadcast::from_bytes(data)?;
Ok((remaining, ChannelManagement::Broadcast(broadcast_msg)))
}
}
pub fn asdict(&self) -> serde_json::Value {
match self {
ChannelManagement::Broadcast(msg) => {
serde_json::json!({
"msg_type": msg.msg_type,
"repeat": msg.repeat,
"mmsi": msg.mmsi,
"channel_a": msg.channel_a,
"channel_b": msg.channel_b,
"txrx": msg.txrx,
"power": msg.power,
"ne_lon": msg.ne_lon,
"ne_lat": msg.ne_lat,
"sw_lon": msg.sw_lon,
"sw_lat": msg.sw_lat,
"addressed": msg.addressed,
"band_a": msg.band_a,
"band_b": msg.band_b,
"zonesize": msg.zonesize,
})
}
ChannelManagement::Addressed(msg) => {
serde_json::json!({
"msg_type": msg.msg_type,
"repeat": msg.repeat,
"mmsi": msg.mmsi,
"channel_a": msg.channel_a,
"channel_b": msg.channel_b,
"txrx": msg.txrx,
"power": msg.power,
"dest1": msg.dest1,
"dest2": msg.dest2,
"addressed": msg.addressed,
"band_a": msg.band_a,
"band_b": msg.band_b,
"zonesize": msg.zonesize,
})
}
}
}
pub fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(self)
}
pub fn msg_type(&self) -> u8 {
match self {
ChannelManagement::Broadcast(msg) => msg.msg_type,
ChannelManagement::Addressed(msg) => msg.msg_type,
}
}
pub fn mmsi(&self) -> u32 {
match self {
ChannelManagement::Broadcast(msg) => msg.mmsi,
ChannelManagement::Addressed(msg) => msg.mmsi,
}
}
}
impl DekuReader<'_, ()> for ChannelManagement {
fn from_reader_with_ctx<R: std::io::Read + std::io::Seek>(
reader: &mut Reader<R>,
_ctx: (),
) -> Result<Self, DekuError> {
let mut data = Vec::new();
while let Ok(byte) = u8::from_reader_with_ctx(reader, ()) {
data.push(byte);
}
let (_, msg) = Self::from_bytes((&data, 0))?;
Ok(msg)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::decode::nmea::NmeaAisMessage;
fn decode(sentence: &str) -> ChannelManagement {
let nmea_msg = NmeaAisMessage::parse(sentence).unwrap();
let binary_data = nmea_msg.payload_to_binary().unwrap();
let (_, msg) = ChannelManagement::from_bytes((&binary_data, 0)).unwrap();
msg
}
#[test]
fn test_msg_type_22_broadcast() {
let msg = decode("!AIVDM,1,1,,B,F030p:j2N2P5aJR0r;6f3rj10000,0*11");
if let ChannelManagement::Broadcast(msg) = msg {
assert_eq!(msg.msg_type, 22);
assert_eq!(msg.mmsi, 3160107);
assert_eq!(msg.channel_a, 2087);
assert_eq!(msg.channel_b, 2088);
assert_eq!(msg.txrx, 0);
assert!(!msg.power);
assert_eq!(msg.ne_lon, -7710.0);
assert_eq!(msg.ne_lat, 3300.0);
assert_eq!(msg.sw_lon, -8020.0);
assert_eq!(msg.sw_lat, 3210.0);
assert!(!msg.addressed);
assert!(!msg.band_a);
assert!(!msg.band_b);
assert_eq!(msg.zonesize, 2);
} else {
panic!("Expected broadcast variant");
}
}
#[test]
fn test_message_serialization() {
let msg = decode("!AIVDM,1,1,,B,F030p:j2N2P5aJR0r;6f3rj10000,0*11");
let json = msg.to_json().unwrap();
let deserialized: ChannelManagement = serde_json::from_str(&json).unwrap();
assert_eq!(msg.msg_type(), deserialized.msg_type());
assert_eq!(msg.mmsi(), deserialized.mmsi());
}
}