use core::str::FromStr; use arrayvec::ArrayString; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Destination { ack: u8, callsign: ArrayString<253>, ssid: u8, } impl Destination { /// Returns none if the ack number is > 127 /// Returns none if the dest callsign is too long /// Returns none is is_ack is true and ack_num is 0 pub fn new(is_ack: bool, ack_num: u8, dest_callsign: &str, dest_ssid: u8) -> Option<Self> { if ack_num > 127 { return None; } if is_ack && ack_num == 0 { return None; } let ack = if is_ack { (1 << 7) | ack_num } else { ack_num }; let callsign = ArrayString::from_str(dest_callsign).ok()?; let ssid = dest_ssid; Some(Self { ack, callsign, ssid, }) } pub fn is_ack(&self) -> bool { self.ack & (1 << 7) > 0 } pub fn ack_num(&self) -> u8 { self.ack } pub fn callsign(&self) -> &str { self.callsign.as_str() } pub fn ssid(&self) -> u8 { self.ssid } pub fn encode<'a>(&self, buf: &'a mut [u8]) -> Option<&'a [u8]> { let n = self.callsign.len() + 2; *buf.get_mut(0)? = n.try_into().unwrap(); *buf.get_mut(1)? = self.ack; buf.get_mut(2..n)?.copy_from_slice(self.callsign.as_bytes()); *buf.get_mut(n)? = self.ssid; Some(&buf[0..(n + 1)]) } pub fn decode(data: &[u8]) -> Option<Self> { let n = data.first()?; let call_length: usize = n.checked_sub(2)?.into(); let ack = *data.get(1)?; if ack == 0b10000000 { // is_ack is true and # is 0 return None; } let callsign = core::str::from_utf8(data.get(2..(call_length + 2))?).ok()?; let callsign = ArrayString::from_str(callsign).ok()?; let ssid = *data.get(call_length + 2)?; Some(Self { ack, callsign, ssid, }) } }