use crate::{
application_protocol::primitives::data_value::ApplicationDataValueWrite,
common::{
error::Error,
helper::{
decode_context_object_id, decode_context_property_id, decode_unsigned,
encode_closing_tag, encode_context_enumerated, encode_context_object_id,
encode_context_unsigned, encode_opening_tag, get_tagged_body_for_tag,
},
io::{Reader, Writer},
object_id::ObjectId,
property_id::PropertyId,
spec::BACNET_ARRAY_ALL,
tag::{Tag, TagNumber},
},
};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct WritePropertyRequest<'a> {
pub property_id: PropertyId,
pub array_index: Option<u32>,
pub value: ApplicationDataValueWrite<'a>,
pub priority: Option<u8>,
}
impl<'a> WritePropertyRequest<'a> {
const TAG_PROPERTY_ID: u8 = 0;
const TAG_ARRAY_INDEX: u8 = 1;
const TAG_VALUE: u8 = 2;
const TAG_PRIORITY: u8 = 3;
const LOWEST_PRIORITY: u8 = 16;
pub fn new(
property_id: PropertyId,
array_index: Option<u32>,
value: ApplicationDataValueWrite<'a>,
priority: Option<u8>,
) -> Self {
Self {
property_id,
array_index,
value,
priority,
}
}
pub fn encode(&self, writer: &mut Writer, _object_id: &ObjectId) {
encode_context_enumerated(writer, Self::TAG_PROPERTY_ID, &self.property_id);
if let Some(array_index) = self.array_index {
encode_context_unsigned(writer, Self::TAG_ARRAY_INDEX, array_index);
}
encode_opening_tag(writer, Self::TAG_VALUE);
self.value.encode(writer);
encode_closing_tag(writer, Self::TAG_VALUE);
if let Some(priority) = self.priority {
let priority = priority.min(Self::LOWEST_PRIORITY) as u32;
encode_context_unsigned(writer, Self::TAG_PRIORITY, priority);
}
}
#[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
pub fn decode(
reader: &mut Reader,
buf: &'a [u8],
object_id: &ObjectId,
) -> Result<Self, Error> {
let property_id = decode_context_property_id(
reader,
buf,
Self::TAG_PROPERTY_ID,
"WritePropertyRequest decode property_id",
)?;
let mut tag = Tag::decode(reader, buf)?;
let mut array_index = None;
if let TagNumber::ContextSpecific(Self::TAG_ARRAY_INDEX) = tag.number {
let array_index_tmp = decode_unsigned(tag.value, reader, buf)? as u32;
if array_index_tmp != BACNET_ARRAY_ALL {
array_index = Some(array_index_tmp);
}
tag = Tag::decode(reader, buf)?;
}
tag.expect_number(
"WritePropertyRequest decode value",
TagNumber::ContextSpecificOpening(Self::TAG_VALUE),
)?;
let value = ApplicationDataValueWrite::decode(object_id, &property_id, reader, buf)?;
Tag::decode_expected(
reader,
buf,
TagNumber::ContextSpecificClosing(Self::TAG_VALUE),
"WritePropertyRequest decode value",
)?;
let mut priority = None;
if !reader.eof() {
let tag_result = Tag::decode(reader, buf);
if let Ok(tag) = tag_result {
if let TagNumber::ContextSpecific(Self::TAG_PRIORITY) = tag.number {
let priority_val = decode_unsigned(tag.value, reader, buf)? as u8;
priority = if priority_val == Self::LOWEST_PRIORITY {
None
} else {
Some(priority_val)
};
}
}
}
Ok(Self {
property_id,
array_index,
value,
priority,
})
}
}
#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct WritePropertyMultipleObject<'a> {
pub object_id: ObjectId,
pub writes: &'a [WritePropertyRequest<'a>],
buf: &'a [u8],
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct WritePropertyMultipleObject<'a> {
pub object_id: ObjectId,
pub writes: Vec<WritePropertyRequest<'a>>,
}
impl<'a> WritePropertyMultipleObject<'a> {
#[cfg(not(feature = "alloc"))]
pub fn new(object_id: ObjectId, writes: &'a [WritePropertyRequest<'a>]) -> Self {
Self {
object_id,
writes,
buf: &[],
}
}
#[cfg(feature = "alloc")]
pub fn new(object_id: ObjectId, writes: Vec<WritePropertyRequest<'a>>) -> Self {
Self { object_id, writes }
}
pub fn encode(&self, writer: &mut Writer) {
encode_context_object_id(writer, 0, &self.object_id);
encode_opening_tag(writer, 1);
for write in self.writes.iter() {
write.encode(writer, &self.object_id);
}
encode_closing_tag(writer, 1);
}
#[cfg(not(feature = "alloc"))]
#[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
let object_id = decode_context_object_id(
reader,
buf,
0,
"WritePropertyMultipleObject decode object_id",
)?;
let buf = get_tagged_body_for_tag(
reader,
buf,
1,
"WritePropertyMultipleObject decode list of writes",
)?;
Ok(WritePropertyMultipleObject {
object_id,
writes: &[],
buf,
})
}
#[cfg(feature = "alloc")]
pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
let object_id = decode_context_object_id(
reader,
buf,
0,
"WritePropertyMultipleObject decode object_id",
)?;
let inner_buf = get_tagged_body_for_tag(
reader,
buf,
1,
"WritePropertyMultipleObject decode list of writes",
)?;
let mut inner_reader = Reader::new_with_len(inner_buf.len());
let mut writes = Vec::new();
while !inner_reader.eof() {
let write_request =
WritePropertyRequest::decode(&mut inner_reader, inner_buf, &object_id)?;
writes.push(write_request);
}
Ok(Self::new(object_id, writes))
}
}
#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct WritePropertyMultiple<'a> {
pub objects: &'a [WritePropertyMultipleObject<'a>],
buf: &'a [u8],
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct WritePropertyMultiple<'a> {
pub objects: Vec<WritePropertyMultipleObject<'a>>,
}
impl<'a> WritePropertyMultiple<'a> {
#[cfg(not(feature = "alloc"))]
pub fn new(objects: &'a [WritePropertyMultipleObject<'a>]) -> Self {
Self {
objects,
buf: &[],
}
}
#[cfg(feature = "alloc")]
pub fn new(objects: Vec<WritePropertyMultipleObject<'a>>) -> Self {
Self { objects }
}
pub fn encode(&self, writer: &mut Writer) {
for object in self.objects.iter() {
object.encode(writer);
}
}
#[cfg(not(feature = "alloc"))]
#[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
let buf = &buf[reader.index..reader.end];
Ok(Self {
buf,
objects: &[],
})
}
#[cfg(feature = "alloc")]
pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
let inner_buf = &buf[reader.index..reader.end];
let mut inner_reader = Reader::new_with_len(inner_buf.len());
let mut objects = Vec::new();
while !inner_reader.eof() {
let object = WritePropertyMultipleObject::decode(&mut inner_reader, inner_buf)?;
objects.push(object);
}
Ok(Self::new(objects))
}
}
#[cfg(not(feature = "alloc"))]
pub struct WritePropertyRequestIter<'a> {
object_id: ObjectId,
reader: Reader,
buf: &'a [u8],
}
#[cfg(not(feature = "alloc"))]
impl<'a> Iterator for WritePropertyRequestIter<'a> {
type Item = Result<WritePropertyRequest<'a>, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.reader.eof() {
return None;
}
Some(WritePropertyRequest::decode(
&mut self.reader,
self.buf,
&self.object_id,
))
}
}
#[cfg(not(feature = "alloc"))]
pub struct WritePropertyMultipleObjectIter<'a> {
buf: &'a [u8],
reader: Reader,
}
#[cfg(not(feature = "alloc"))]
impl<'a> Iterator for WritePropertyMultipleObjectIter<'a> {
type Item = Result<WritePropertyMultipleObject<'a>, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.reader.eof() {
return None;
}
let object_with_writes = WritePropertyMultipleObject::decode(&mut self.reader, self.buf);
Some(object_with_writes)
}
}
#[cfg(not(feature = "alloc"))]
impl<'a> IntoIterator for &'_ WritePropertyMultiple<'a> {
type Item = Result<WritePropertyMultipleObject<'a>, Error>;
type IntoIter = WritePropertyMultipleObjectIter<'a>;
fn into_iter(self) -> Self::IntoIter {
WritePropertyMultipleObjectIter {
buf: self.buf,
reader: Reader::new_with_len(self.buf.len()),
}
}
}