rustbac-core 0.4.0

Core BACnet protocol types, encoders, and service codecs for rustbac.
Documentation
use crate::apdu::ConfirmedRequestHeader;
use crate::encoding::{
    primitives::{encode_ctx_object_id, encode_ctx_unsigned},
    tag::Tag,
    writer::Writer,
};
use crate::types::ObjectId;
use crate::EncodeError;

pub const SERVICE_SUBSCRIBE_COV: u8 = 0x05;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SubscribeCovRequest {
    pub subscriber_process_id: u32,
    pub monitored_object_id: ObjectId,
    pub issue_confirmed_notifications: Option<bool>,
    pub lifetime_seconds: Option<u32>,
    pub invoke_id: u8,
}

impl SubscribeCovRequest {
    pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
        ConfirmedRequestHeader {
            segmented: false,
            more_follows: false,
            segmented_response_accepted: false,
            max_segments: 0,
            max_apdu: 5,
            invoke_id: self.invoke_id,
            sequence_number: None,
            proposed_window_size: None,
            service_choice: SERVICE_SUBSCRIBE_COV,
        }
        .encode(w)?;

        encode_ctx_unsigned(w, 0, self.subscriber_process_id)?;
        encode_ctx_object_id(w, 1, self.monitored_object_id.raw())?;
        if let Some(issue_confirmed) = self.issue_confirmed_notifications {
            Tag::Context { tag_num: 2, len: 1 }.encode(w)?;
            w.write_u8(if issue_confirmed { 1 } else { 0 })?;
        }
        if let Some(lifetime_seconds) = self.lifetime_seconds {
            encode_ctx_unsigned(w, 3, lifetime_seconds)?;
        }
        Ok(())
    }

    pub fn cancel(
        subscriber_process_id: u32,
        monitored_object_id: ObjectId,
        invoke_id: u8,
    ) -> Self {
        Self {
            subscriber_process_id,
            monitored_object_id,
            issue_confirmed_notifications: None,
            lifetime_seconds: None,
            invoke_id,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{SubscribeCovRequest, SERVICE_SUBSCRIBE_COV};
    use crate::apdu::ConfirmedRequestHeader;
    use crate::encoding::{reader::Reader, writer::Writer};
    use crate::types::{ObjectId, ObjectType};

    #[test]
    fn encode_subscribe_cov_request() {
        let req = SubscribeCovRequest {
            subscriber_process_id: 7,
            monitored_object_id: ObjectId::new(ObjectType::AnalogInput, 2),
            issue_confirmed_notifications: Some(false),
            lifetime_seconds: Some(600),
            invoke_id: 3,
        };

        let mut buf = [0u8; 64];
        let mut w = Writer::new(&mut buf);
        req.encode(&mut w).unwrap();

        let mut r = Reader::new(w.as_written());
        let header = ConfirmedRequestHeader::decode(&mut r).unwrap();
        assert_eq!(header.invoke_id, 3);
        assert_eq!(header.service_choice, SERVICE_SUBSCRIBE_COV);
        assert!(!r.is_empty());
    }
}