bacnet_parse 0.2.0

no_std BACnet parser
Documentation
use super::npdu::*;
use super::Error;
use arrayref::array_ref;

pub fn parse_bvlc(slice: &[u8]) -> Result<BVLC, Error> {
    if slice.len() < 4 {
        return Err(Error::Length("insufficient size for bvlc"));
    }
    if slice[0] != 0x81 {
        return Err(Error::InvalidValue("invalid bvlc type"));
    }

    let len = u16::from_be_bytes(*array_ref!(slice, 2, 2));
    let len = len as usize;
    if len > slice.len() {
        return Err(Error::Length("bvlc length too largu"));
    }

    let mut bvlc = BVLC::default();
    bvlc.bfn = slice[1].into();
    let npdu_start_idx: usize = if bvlc.has_ip_port() {
        if slice.len() < 6 {
            return Err(Error::Length("insufficient size for bvlc ip/port"));
        }
        bvlc.ip_port = Some(array_ref!(slice, 4, 6).into());
        10
    } else {
        4
    };
    if bvlc.has_npdu() {
        if slice.len() < npdu_start_idx || len < npdu_start_idx {
            return Err(Error::Length("insufficient size for npdu"));
        }
        if let Ok(npdu) = parse_npdu(&slice[npdu_start_idx..len]) {
            bvlc.npdu = Some(npdu);
        }
    }
    Ok(bvlc)
}

#[derive(Default)]
pub struct BVLC<'a> {
    bfn: BVLCFunction,
    ip_port: Option<IpPort>,
    npdu: Option<NPDU<'a>>,
}

impl<'a> BVLC<'a> {
    pub fn bvlc_function(&self) -> BVLCFunction {
        self.bfn
    }
    pub fn ip_port(&self) -> &Option<IpPort> {
        &self.ip_port
    }
    pub fn npdu(&self) -> &Option<NPDU<'a>> {
        &self.npdu
    }
    pub fn has_npdu(&self) -> bool {
        match &self.bfn {
            BVLCFunction::ForwardedNPDU
            | BVLCFunction::UnicastNPDU
            | BVLCFunction::BroadcastNPDU => true,
            _ => false,
        }
    }
    pub fn has_ip_port(&self) -> bool {
        match &self.bfn {
            BVLCFunction::ForwardedNPDU => true,
            _ => false,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BVLCFunction {
    BVLCResult,
    WBDT,
    RBDT,
    RBDTAck,
    ForwardedNPDU,
    RegisterForeignDevice,
    UnicastNPDU,
    BroadcastNPDU,
    SecureBVLL,
    Unknown,
}

impl Default for BVLCFunction {
    fn default() -> BVLCFunction {
        Self::Unknown
    }
}

impl From<u8> for BVLCFunction {
    fn from(b: u8) -> Self {
        match b {
            0x00 => Self::BVLCResult,
            0x01 => Self::WBDT,
            0x02 => Self::RBDT,
            0x03 => Self::RBDTAck,
            0x04 => Self::ForwardedNPDU,
            0x05 => Self::RegisterForeignDevice,
            0x0a => Self::UnicastNPDU,
            0x0b => Self::BroadcastNPDU,
            0x0c => Self::SecureBVLL,
            _ => Self::Unknown,
        }
    }
}

pub struct IpPort {
    pub ip: u32,
    pub port: u16,
}

impl From<&[u8; 6]> for IpPort {
    fn from(b: &[u8; 6]) -> IpPort {
        IpPort {
            ip: u32::from_be_bytes(*array_ref!(b, 0, 4)),
            port: u16::from_be_bytes(*array_ref!(b, 4, 2)),
        }
    }
}