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_closing_tag, encode_ctx_object_id, encode_ctx_unsigned, encode_opening_tag,
    },
    writer::Writer,
};
use crate::services::value_codec::encode_application_data_value;
use crate::types::{DataValue, ObjectId, PropertyId};
use crate::EncodeError;

pub const SERVICE_WRITE_PROPERTY: u8 = 0x0F;

#[derive(Debug, Clone, PartialEq)]
pub struct WritePropertyRequest<'a> {
    pub object_id: ObjectId,
    pub property_id: PropertyId,
    pub value: DataValue<'a>,
    pub array_index: Option<u32>,
    pub priority: Option<u8>,
    pub invoke_id: u8,
}

impl<'a> Default for WritePropertyRequest<'a> {
    fn default() -> Self {
        Self {
            object_id: ObjectId::new(crate::types::ObjectType::AnalogValue, 0),
            property_id: PropertyId::PresentValue,
            value: DataValue::Null,
            array_index: None,
            priority: None,
            invoke_id: 1,
        }
    }
}

impl<'a> WritePropertyRequest<'a> {
    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_WRITE_PROPERTY,
        }
        .encode(w)?;

        encode_ctx_object_id(w, 0, self.object_id.raw())?;
        encode_ctx_unsigned(w, 1, self.property_id.to_u32())?;
        if let Some(idx) = self.array_index {
            encode_ctx_unsigned(w, 2, idx)?;
        }

        encode_opening_tag(w, 3)?;
        encode_application_data_value(w, &self.value)?;
        encode_closing_tag(w, 3)?;

        if let Some(priority) = self.priority {
            encode_ctx_unsigned(w, 4, priority as u32)?;
        }
        Ok(())
    }
}

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

    #[test]
    fn encode_write_property_with_character_string() {
        let req = WritePropertyRequest {
            object_id: ObjectId::new(ObjectType::AnalogValue, 3),
            property_id: PropertyId::Description,
            value: DataValue::CharacterString("loop tuning pending"),
            priority: None,
            ..Default::default()
        };

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

        let mut r = Reader::new(w.as_written());
        let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
        assert_eq!(hdr.service_choice, SERVICE_WRITE_PROPERTY);
    }
}