use super::field::{encode_char, encode_u8, encode_u32, read_char, read_string, read_u8, read_u32};
#[derive(Debug, Clone, PartialEq)]
pub struct Abm {
pub num_frags: Option<u8>,
pub frag_num: Option<u8>,
pub msg_id: Option<u8>,
pub mmsi: Option<u32>,
pub channel: Option<char>,
pub vdl_msg_num: Option<u8>,
pub payload: Option<String>,
pub fill_bits: Option<u8>,
}
impl Abm {
pub const SENTENCE_TYPE: &'static str = "ABM";
pub fn parse(fields: &[&str]) -> Option<Self> {
let mut idx = 0;
let num_frags = read_u8(fields, &mut idx);
let frag_num = read_u8(fields, &mut idx);
let msg_id = read_u8(fields, &mut idx);
let mmsi = read_u32(fields, &mut idx);
let channel = read_char(fields, &mut idx);
let vdl_msg_num = read_u8(fields, &mut idx);
let payload = read_string(fields, &mut idx);
let fill_bits = read_u8(fields, &mut idx);
Some(Self {
num_frags,
frag_num,
msg_id,
mmsi,
channel,
vdl_msg_num,
payload,
fill_bits,
})
}
pub fn encode(&self) -> Vec<String> {
vec![
encode_u8(self.num_frags),
encode_u8(self.frag_num),
encode_u8(self.msg_id),
encode_u32(self.mmsi),
encode_char(self.channel),
encode_u8(self.vdl_msg_num),
self.payload.clone().unwrap_or_default(),
encode_u8(self.fill_bits),
]
}
pub fn to_sentence(&self, talker: &str) -> String {
let fields = self.encode();
let field_refs: Vec<&str> = fields.iter().map(|s| s.as_str()).collect();
crate::encode_frame('!', talker, Self::SENTENCE_TYPE, &field_refs)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse_frame;
#[test]
fn abm_empty() {
let s = Abm {
num_frags: None,
frag_num: None,
msg_id: None,
mmsi: None,
channel: None,
vdl_msg_num: None,
payload: None,
fill_bits: None,
}
.to_sentence("AI");
let f = parse_frame(s.trim()).expect("valid");
let a = Abm::parse(&f.fields).expect("parse");
assert!(a.num_frags.is_none());
assert!(a.mmsi.is_none());
assert!(a.payload.is_none());
}
#[test]
fn abm_encode_roundtrip() {
let original = Abm {
num_frags: Some(1),
frag_num: Some(1),
msg_id: Some(0),
mmsi: Some(123456789),
channel: Some('1'),
vdl_msg_num: Some(6),
payload: Some("test".to_string()),
fill_bits: Some(0),
};
let sentence = original.to_sentence("AI");
let frame = parse_frame(sentence.trim()).expect("re-parse");
let parsed = Abm::parse(&frame.fields).expect("parse");
assert_eq!(original, parsed);
}
#[test]
fn abm_aiabm_gonmea() {
let frame = parse_frame("!AIABM,26,2,1,3381581370,3,8,177KQJ5000G?tO`K>RA1wUbN0TKH,0*02")
.expect("valid");
let a = Abm::parse(&frame.fields).expect("parse ABM");
assert_eq!(a.num_frags, Some(26));
assert_eq!(a.frag_num, Some(2));
assert_eq!(a.msg_id, Some(1));
assert_eq!(a.mmsi, Some(3381581370));
assert_eq!(a.channel, Some('3'));
assert_eq!(a.vdl_msg_num, Some(8));
assert_eq!(a.payload.as_deref(), Some("177KQJ5000G?tO`K>RA1wUbN0TKH"));
assert_eq!(a.fill_bits, Some(0));
}
}