1use crate::prelude::*;
40use alloc::borrow::Cow;
41use alloc::sync::Arc;
42
43use bacnet_encoding::constructed::constructed_channel_value;
44use bacnet_types::constructed::BACnetDeviceObjectPropertyReference;
45use bacnet_types::enums::{
46 ErrorClass, ErrorCode, EventState, ObjectType, PropertyIdentifier, Reliability, WriteStatus,
47};
48use bacnet_types::error::Error;
49use bacnet_types::primitives::{ObjectIdentifier, PropertyValue, StatusFlags};
50
51use crate::command::{CommandRun, RunPlan, WriteFailure, next_generation};
52use crate::common::{self, read_identity_properties};
53use crate::property_metadata::{PropertyMetadata, property_list_from_metadata};
54use crate::traits::BACnetObject;
55
56mod arrays;
57mod coercion;
58mod metadata;
59
60pub use arrays::{MAX_CHANNEL_MEMBERS, MAX_CONTROL_GROUPS};
61pub use coercion::{CoercionFailure, MemberDatatype, coerce_channel_value};
62
63const DEFAULT_PRIORITY: u8 = 16;
66
67#[doc(hidden)]
69#[derive(Debug, Clone, PartialEq)]
70pub struct ChannelMember {
71 pub reference: BACnetDeviceObjectPropertyReference,
74 pub delay_ms: u32,
77 pub slot: usize,
79 pub learned: Option<MemberDatatype>,
82}
83
84#[doc(hidden)]
86#[derive(Debug, Clone, PartialEq)]
87pub struct ChannelDistribution {
88 pub value: PropertyValue,
90 pub priority: Option<u8>,
92 pub members: Vec<ChannelMember>,
94}
95
96pub struct ChannelObject {
99 oid: ObjectIdentifier,
100 name: String,
101 description: String,
102 present_value: PropertyValue,
103 last_priority: u8,
104 write_status: WriteStatus,
105 reliability: Reliability,
108 simulated_reliability: Option<Reliability>,
112 out_of_service: bool,
113 members: Vec<BACnetDeviceObjectPropertyReference>,
114 learned: Vec<Option<MemberDatatype>>,
118 execution_delay: Vec<u32>,
119 channel_number: u16,
120 control_groups: Vec<u32>,
121 allow_group_delay_inhibit: bool,
122 generation: u64,
125 pending_run: Option<CommandRun>,
126}
127
128impl ChannelObject {
129 pub fn new(instance: u32, name: impl Into<String>, channel_number: u16) -> Result<Self, Error> {
133 let oid = ObjectIdentifier::new(ObjectType::CHANNEL, instance)?;
134 Ok(Self {
135 oid,
136 name: name.into(),
137 description: String::new(),
138 present_value: PropertyValue::Null,
139 last_priority: DEFAULT_PRIORITY,
140 write_status: WriteStatus::IDLE,
141 reliability: Reliability::NO_FAULT_DETECTED,
142 simulated_reliability: None,
143 out_of_service: false,
144 members: Vec::new(),
145 learned: Vec::new(),
146 execution_delay: Vec::new(),
147 channel_number,
148 control_groups: vec![0],
149 allow_group_delay_inhibit: false,
150 generation: next_generation(),
151 pending_run: None,
152 })
153 }
154
155 pub fn set_members(
164 &mut self,
165 members: Vec<BACnetDeviceObjectPropertyReference>,
166 ) -> Result<(), Error> {
167 if members.len() > MAX_CHANNEL_MEMBERS {
168 return Err(common::protocol_error(
169 ErrorClass::RESOURCES,
170 ErrorCode::NO_SPACE_TO_WRITE_PROPERTY,
171 ));
172 }
173 crate::device_reference::check_device_members(&members)?;
174 self.execution_delay.resize(members.len(), 0);
175 self.learned = vec![None; members.len()];
176 self.members = members;
177 Ok(())
178 }
179
180 pub fn set_execution_delay(&mut self, delays: Vec<u32>) -> Result<(), Error> {
185 if delays.len() != self.members.len() {
186 return Err(common::value_out_of_range_error());
187 }
188 self.execution_delay = delays;
189 Ok(())
190 }
191
192 pub fn set_control_groups(&mut self, groups: Vec<u32>) -> Result<(), Error> {
199 arrays::check_group_count(groups.len())?;
200 self.control_groups = groups;
201 Ok(())
202 }
203
204 pub fn set_allow_group_delay_inhibit(&mut self, allow: bool) {
209 self.allow_group_delay_inhibit = allow;
210 }
211
212 fn write_present_value(
214 &mut self,
215 value: PropertyValue,
216 priority: Option<u8>,
217 ) -> Result<(), Error> {
218 if self.write_status == WriteStatus::IN_PROGRESS {
219 return Err(common::protocol_error(ErrorClass::OBJECT, ErrorCode::BUSY));
220 }
221 check_channel_value(&value)?;
222 let last_priority = match priority {
223 None => DEFAULT_PRIORITY,
224 Some(priority @ 1..=16) => priority,
225 Some(_) => return Err(common::value_out_of_range_error()),
226 };
227 self.present_value = value;
228 self.last_priority = last_priority;
229 if self.out_of_service {
231 return Ok(());
232 }
233 if self.members.is_empty() {
234 self.write_status = WriteStatus::IDLE;
235 self.reliability = Reliability::NO_FAULT_DETECTED;
236 return Ok(());
237 }
238 self.generation = next_generation();
239 let members: Vec<ChannelMember> = self
240 .members
241 .iter()
242 .zip(&self.execution_delay)
243 .zip(&self.learned)
244 .enumerate()
245 .filter(|(_, ((member, _), _))| !arrays::is_empty(member))
246 .map(|(slot, ((member, delay), learned))| ChannelMember {
247 reference: member.clone(),
248 delay_ms: *delay,
249 slot,
250 learned: *learned,
251 })
252 .collect();
253 if members.is_empty() {
254 self.write_status = WriteStatus::SUCCESSFUL;
257 self.reliability = Reliability::NO_FAULT_DETECTED;
258 return Ok(());
259 }
260 self.write_status = WriteStatus::IN_PROGRESS;
261 self.pending_run = Some(CommandRun {
262 source: self.oid,
263 generation: self.generation,
264 plan: RunPlan::Channel(ChannelDistribution {
265 value: self.present_value.clone(),
266 priority,
267 members,
268 }),
269 chain: Arc::from([]),
270 });
271 Ok(())
272 }
273
274 fn served_reliability(&self) -> Reliability {
277 self.simulated_reliability.unwrap_or(self.reliability)
278 }
279
280 fn write_out_of_service(&mut self, value: PropertyValue) -> Result<(), Error> {
281 let PropertyValue::Boolean(value) = value else {
282 return Err(common::invalid_data_type_error());
283 };
284 if value != self.out_of_service {
285 self.simulated_reliability = value.then_some(self.reliability);
288 }
289 self.out_of_service = value;
290 Ok(())
291 }
292
293 fn write_reliability(&mut self, value: PropertyValue) -> Result<(), Error> {
296 if !self.out_of_service {
297 return Err(common::write_access_denied_error());
298 }
299 let PropertyValue::Enumerated(raw) = value else {
300 return Err(common::invalid_data_type_error());
301 };
302 let reliability = Reliability::from_raw(raw);
303 if !common::is_reliability_value_valid(reliability) {
304 return Err(common::value_out_of_range_error());
305 }
306 self.simulated_reliability = Some(reliability);
307 Ok(())
308 }
309}
310
311fn check_channel_value(value: &PropertyValue) -> Result<(), Error> {
317 match value {
318 value if value.is_primitive() => Ok(()),
319 PropertyValue::ApplicationData(octets)
320 if matches!(octets.first(), Some(0x0E | 0x1E | 0x2E)) =>
321 {
322 if constructed_channel_value(octets).is_some() {
323 Ok(())
324 } else {
325 Err(common::invalid_data_encoding_error())
326 }
327 }
328 _ => Err(common::invalid_data_type_error()),
329 }
330}
331
332impl BACnetObject for ChannelObject {
333 fn object_identifier(&self) -> ObjectIdentifier {
334 self.oid
335 }
336
337 fn object_name(&self) -> &str {
338 &self.name
339 }
340
341 fn read_property(
342 &self,
343 property: PropertyIdentifier,
344 array_index: Option<u32>,
345 ) -> Result<PropertyValue, Error> {
346 if let Some(result) = read_identity_properties!(self, property, array_index) {
347 return result;
348 }
349 match property {
350 PropertyIdentifier::OBJECT_TYPE => {
351 Ok(PropertyValue::Enumerated(ObjectType::CHANNEL.to_raw()))
352 }
353 PropertyIdentifier::PRESENT_VALUE => Ok(self.present_value.clone()),
354 PropertyIdentifier::LAST_PRIORITY => {
355 Ok(PropertyValue::Unsigned(self.last_priority.into()))
356 }
357 PropertyIdentifier::WRITE_STATUS => {
358 Ok(PropertyValue::Enumerated(self.write_status.to_raw()))
359 }
360 PropertyIdentifier::STATUS_FLAGS => Ok(common::compute_status_flags(
364 StatusFlags::empty(),
365 self.served_reliability(),
366 self.out_of_service,
367 EventState::NORMAL,
368 )),
369 PropertyIdentifier::RELIABILITY => Ok(PropertyValue::Enumerated(
370 self.served_reliability().to_raw(),
371 )),
372 PropertyIdentifier::OUT_OF_SERVICE => Ok(PropertyValue::Boolean(self.out_of_service)),
373 PropertyIdentifier::LIST_OF_OBJECT_PROPERTY_REFERENCES => common::read_array(
374 crate::device_reference::reference_elements(&self.members),
375 array_index,
376 ),
377 PropertyIdentifier::EXECUTION_DELAY => common::read_array(
378 self.execution_delay
379 .iter()
380 .map(|delay| PropertyValue::Unsigned((*delay).into()))
381 .collect(),
382 array_index,
383 ),
384 PropertyIdentifier::ALLOW_GROUP_DELAY_INHIBIT => {
385 Ok(PropertyValue::Boolean(self.allow_group_delay_inhibit))
386 }
387 PropertyIdentifier::CHANNEL_NUMBER => {
388 Ok(PropertyValue::Unsigned(self.channel_number.into()))
389 }
390 PropertyIdentifier::CONTROL_GROUPS => common::read_array(
391 self.control_groups
392 .iter()
393 .map(|group| PropertyValue::Unsigned((*group).into()))
394 .collect(),
395 array_index,
396 ),
397 _ => Err(common::unknown_property_error()),
398 }
399 }
400
401 fn write_property(
402 &mut self,
403 property: PropertyIdentifier,
404 array_index: Option<u32>,
405 value: PropertyValue,
406 priority: Option<u8>,
407 ) -> Result<(), Error> {
408 if array_index.is_some() && !self.is_array_property(property) {
409 return Err(common::property_is_not_an_array_error());
410 }
411 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
412 return result;
413 }
414 if let Some(result) = common::write_description(&mut self.description, property, &value) {
415 return result;
416 }
417 match property {
418 PropertyIdentifier::PRESENT_VALUE => self.write_present_value(value, priority),
419 PropertyIdentifier::OUT_OF_SERVICE => self.write_out_of_service(value),
420 PropertyIdentifier::RELIABILITY => self.write_reliability(value),
421 PropertyIdentifier::LIST_OF_OBJECT_PROPERTY_REFERENCES => {
422 self.write_members(array_index, value)
423 }
424 PropertyIdentifier::EXECUTION_DELAY => self.write_execution_delay(array_index, value),
425 PropertyIdentifier::ALLOW_GROUP_DELAY_INHIBIT => {
426 let PropertyValue::Boolean(allow) = value else {
427 return Err(common::invalid_data_type_error());
428 };
429 self.allow_group_delay_inhibit = allow;
430 Ok(())
431 }
432 PropertyIdentifier::CHANNEL_NUMBER => {
433 let PropertyValue::Unsigned(raw) = value else {
434 return Err(common::invalid_data_type_error());
435 };
436 self.channel_number =
437 u16::try_from(raw).map_err(|_| common::value_out_of_range_error())?;
438 Ok(())
439 }
440 PropertyIdentifier::CONTROL_GROUPS => self.write_control_groups(array_index, value),
441 _ => Err(common::unhandled_write_error(
442 self.property_metadata().as_ref(),
443 property,
444 array_index,
445 )),
446 }
447 }
448
449 fn property_metadata(&self) -> Cow<'_, [PropertyMetadata]> {
450 Cow::Borrowed(metadata::CHANNEL_PROPERTY_METADATA)
451 }
452
453 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
454 property_list_from_metadata(metadata::CHANNEL_PROPERTY_METADATA)
455 }
456
457 fn take_command_run_internal(&mut self) -> Option<CommandRun> {
458 self.pending_run.take()
459 }
460
461 fn command_generation_internal(&self) -> Option<u64> {
462 Some(self.generation)
463 }
464
465 fn remember_member_datatype_internal(
466 &mut self,
467 slot: usize,
468 reference: &BACnetDeviceObjectPropertyReference,
469 datatype: Option<MemberDatatype>,
470 ) {
471 if self.members.get(slot) == Some(reference) {
472 self.learned[slot] = datatype;
473 }
474 }
475
476 fn complete_command_run_internal(
477 &mut self,
478 generation: u64,
479 outcome: Result<(), WriteFailure>,
480 ) -> bool {
481 if generation != self.generation || self.write_status != WriteStatus::IN_PROGRESS {
482 return false;
483 }
484 (self.write_status, self.reliability) = match outcome {
485 Ok(()) => (WriteStatus::SUCCESSFUL, Reliability::NO_FAULT_DETECTED),
486 Err(failure) => (WriteStatus::FAILED, failure.reliability()),
487 };
488 true
489 }
490}
491
492#[cfg(test)]
493mod tests;
494
495#[cfg(test)]
496mod array_tests;
497
498#[cfg(test)]
499mod coercion_tests;
500
501#[cfg(test)]
502mod reliability_tests;
503
504#[cfg(test)]
505mod learned_tests;