bacnet_objects/color/
mod.rs1use core::ops::RangeInclusive;
25use core::time::Duration;
26
27use bacnet_types::constructed::BACnetXyColor;
28use bacnet_types::enums::ColorTransition;
29use bacnet_types::error::Error;
30use bacnet_types::primitives::PropertyValue;
31
32use crate::audit::ObjectAuditPolicy;
33use crate::common;
34
35mod command;
36mod engine;
37mod metadata;
38mod persistence;
39mod saving;
40mod temperature;
41mod xy;
42
43#[cfg(feature = "std")]
44pub use persistence::FileColorOutputPersistence;
45pub use persistence::{ColorOutputPersistence, ColorOutputSnapshot, ColorOutputValue};
46pub use saving::ColorOutputSaveCounters;
47pub use temperature::ColorTemperatureObject;
48pub use xy::ColorObject;
49
50#[cfg(test)]
51mod command_tests;
52#[cfg(test)]
53mod engine_tests;
54#[cfg(test)]
55mod metadata_tests;
56#[cfg(all(test, feature = "std"))]
57mod persistence_tests;
58#[cfg(test)]
59mod rows_tests;
60#[cfg(test)]
61mod start_tests;
62#[cfg(test)]
63mod value_source_tests;
64
65fn xy_value(color: BACnetXyColor) -> PropertyValue {
68 PropertyValue::List(vec![
69 PropertyValue::Real(color.x),
70 PropertyValue::Real(color.y),
71 ])
72}
73
74fn written_xy(value: PropertyValue) -> Result<BACnetXyColor, Error> {
78 let PropertyValue::List(items) = value else {
79 return Err(common::invalid_data_type_error());
80 };
81 let [PropertyValue::Real(x), PropertyValue::Real(y)] = items.as_slice() else {
82 return Err(common::invalid_data_type_error());
83 };
84 let color = BACnetXyColor::new(*x, *y);
85 if command::xy_in_range(color) {
86 Ok(color)
87 } else {
88 Err(common::value_out_of_range_error())
89 }
90}
91
92fn written_unsigned(value: PropertyValue, range: RangeInclusive<u32>) -> Result<u32, Error> {
95 let PropertyValue::Unsigned(value) = value else {
96 return Err(common::invalid_data_type_error());
97 };
98 u32::try_from(value)
99 .ok()
100 .filter(|value| range.contains(value))
101 .ok_or_else(common::value_out_of_range_error)
102}
103
104fn written_transition(
108 value: PropertyValue,
109 last: ColorTransition,
110) -> Result<ColorTransition, Error> {
111 let PropertyValue::Enumerated(raw) = value else {
112 return Err(common::invalid_data_type_error());
113 };
114 if raw > last.to_raw() {
115 return Err(common::value_out_of_range_error());
116 }
117 Ok(ColorTransition::from_raw(raw))
118}
119
120fn noncommandable_audit_policy(policy: ObjectAuditPolicy) -> ObjectAuditPolicy {
123 ObjectAuditPolicy {
124 priority_filter: None,
125 ..policy
126 }
127}
128
129fn milliseconds(fade_time: u32) -> Duration {
131 Duration::from_millis(u64::from(fade_time))
132}