Skip to content
Snippets Groups Projects
destination.rs 1.97 KiB
Newer Older
use core::str::FromStr;

use arrayvec::ArrayString;

#[derive(Debug, PartialEq, Eq)]
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,
        })
    }
}