bacnet_objects/channel/
arrays.rs1use bacnet_types::constructed::BACnetDeviceObjectPropertyReference;
33use bacnet_types::enums::{ErrorClass, ErrorCode, ObjectType};
34use bacnet_types::error::Error;
35use bacnet_types::primitives::PropertyValue;
36
37use super::ChannelObject;
38use crate::{common, device_reference};
39
40pub const MAX_CHANNEL_MEMBERS: usize = 1024;
43
44pub const MAX_CONTROL_GROUPS: usize = 64;
47
48pub(super) fn empty_reference() -> BACnetDeviceObjectPropertyReference {
51 device_reference::unset_reference(ObjectType::ANALOG_INPUT)
52}
53
54pub(super) fn is_empty(member: &BACnetDeviceObjectPropertyReference) -> bool {
58 member.is_unset()
59}
60
61fn no_space_error() -> Error {
62 common::protocol_error(ErrorClass::RESOURCES, ErrorCode::NO_SPACE_TO_WRITE_PROPERTY)
63}
64
65fn new_size(value: PropertyValue, cap: usize) -> Result<usize, Error> {
67 let PropertyValue::Unsigned(size) = value else {
68 return Err(common::invalid_data_type_error());
69 };
70 usize::try_from(size)
71 .ok()
72 .filter(|size| *size <= cap)
73 .ok_or_else(no_space_error)
74}
75
76fn slot(index: u32, len: usize) -> Result<usize, Error> {
78 usize::try_from(index - 1)
79 .ok()
80 .filter(|slot| *slot < len)
81 .ok_or_else(common::invalid_array_index_error)
82}
83
84fn decode_members(
87 value: &PropertyValue,
88) -> Result<Vec<BACnetDeviceObjectPropertyReference>, Error> {
89 let members = device_reference::decode_references(value)?;
90 if members.len() > MAX_CHANNEL_MEMBERS {
91 return Err(no_space_error());
92 }
93 device_reference::check_device_members(&members)?;
94 Ok(members)
95}
96
97fn unsigned_elements(value: PropertyValue) -> Result<Vec<u32>, Error> {
100 let elements = match value {
101 PropertyValue::List(elements) => elements,
102 single => vec![single],
103 };
104 elements.into_iter().map(unsigned_element).collect()
105}
106
107fn unsigned_element(value: PropertyValue) -> Result<u32, Error> {
111 let PropertyValue::Unsigned(raw) = value else {
112 return Err(common::invalid_data_type_error());
113 };
114 u32::try_from(raw).map_err(|_| common::value_out_of_range_error())
115}
116
117impl ChannelObject {
118 fn resize_members(&mut self, size: usize) {
122 self.members.resize_with(size, empty_reference);
123 self.learned.resize(size, None);
124 self.execution_delay.resize(size, 0);
125 }
126
127 pub(super) fn write_members(
130 &mut self,
131 array_index: Option<u32>,
132 value: PropertyValue,
133 ) -> Result<(), Error> {
134 match array_index {
135 None => {
136 let members = decode_members(&value)?;
137 let size = members.len();
138 self.members = members;
139 self.learned.clear();
140 self.resize_members(size);
141 }
142 Some(0) => {
143 let size = new_size(value, MAX_CHANNEL_MEMBERS)?;
144 self.resize_members(size);
145 }
146 Some(index) => {
147 let at = slot(index, self.members.len())?;
148 let member: BACnetDeviceObjectPropertyReference =
149 device_reference::decode_reference(&value)?;
150 device_reference::check_device_member(member.device_identifier)?;
151 self.members[at] = member;
152 self.learned[at] = None;
153 }
154 }
155 Ok(())
156 }
157
158 pub(super) fn write_execution_delay(
159 &mut self,
160 array_index: Option<u32>,
161 value: PropertyValue,
162 ) -> Result<(), Error> {
163 match array_index {
164 None => {
165 let delays = unsigned_elements(value)?;
166 if delays.len() != self.members.len() {
167 return Err(common::value_out_of_range_error());
168 }
169 self.execution_delay = delays;
170 }
171 Some(0) => {
172 let size = new_size(value, MAX_CHANNEL_MEMBERS)?;
173 self.resize_members(size);
174 }
175 Some(index) => {
176 let at = slot(index, self.execution_delay.len())?;
177 self.execution_delay[at] = unsigned_element(value)?;
178 }
179 }
180 Ok(())
181 }
182
183 pub(super) fn write_control_groups(
184 &mut self,
185 array_index: Option<u32>,
186 value: PropertyValue,
187 ) -> Result<(), Error> {
188 match array_index {
189 None => {
190 let groups = unsigned_elements(value)?;
191 check_group_count(groups.len())?;
192 self.control_groups = groups;
193 }
194 Some(0) => {
195 let size = new_size(value, MAX_CONTROL_GROUPS)?;
196 check_group_count(size)?;
197 self.control_groups.resize(size, 0);
198 }
199 Some(index) => {
200 let at = slot(index, self.control_groups.len())?;
201 self.control_groups[at] = unsigned_element(value)?;
202 }
203 }
204 Ok(())
205 }
206}
207
208pub(super) fn check_group_count(count: usize) -> Result<(), Error> {
211 match count {
212 0 => Err(common::value_out_of_range_error()),
213 count if count > MAX_CONTROL_GROUPS => Err(no_space_error()),
214 _ => Ok(()),
215 }
216}