1use super::*;
2use crate::object_profile::{ObjectProfile, ProfileState, TagsPersistence};
3use crate::prelude::*;
4use crate::present_value_access::PresentValueAccess;
5use crate::property_metadata::PropertyMetadata;
6use alloc::sync::Arc;
7
8#[path = "value/metadata.rs"]
9mod metadata;
10
11pub struct BinaryValueObject {
19 profile: ProfileState,
20 audit_policy: crate::audit::ObjectAuditPolicy,
21 oid: ObjectIdentifier,
22 name: String,
23 description: String,
24 present_value: u32, out_of_service: bool,
26 status_flags: StatusFlags,
27 access: PresentValueAccess,
28 priority_array: [Option<u32>; 16],
29 relinquish_default: u32,
30 reliability: Reliability,
32 reliability_before_out_of_service: Option<Reliability>,
33 reliability_inhibit: common::ReliabilityInhibitState,
34 active_text: String,
35 inactive_text: String,
36 event_detector: ChangeOfStateDetector,
38 event_detection_enable: bool,
41 pub(crate) event_history: EventHistory,
42 value_source: crate::command_source::ValueSourceTracking,
44 write_source: crate::command_source::SingleValueSource,
46}
47
48impl BinaryValueObject {
49 pub fn set_audit_policy(&mut self, policy: crate::audit::ObjectAuditPolicy) {
53 self.audit_policy = policy;
54 }
55
56 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
58 Self::with_access(instance, name, PresentValueAccess::Commandable)
59 }
60
61 pub fn with_access(
63 instance: u32,
64 name: impl Into<String>,
65 access: PresentValueAccess,
66 ) -> Result<Self, Error> {
67 let oid = ObjectIdentifier::new(ObjectType::BINARY_VALUE, instance)?;
68 Ok(Self {
69 profile: ProfileState::default(),
70 audit_policy: crate::audit::ObjectAuditPolicy::default(),
71 oid,
72 name: name.into(),
73 description: String::new(),
74 present_value: 0, out_of_service: false,
76 status_flags: StatusFlags::empty(),
77 access,
78 priority_array: [None; 16],
79 relinquish_default: 0,
80 reliability: Reliability::NO_FAULT_DETECTED,
81 reliability_before_out_of_service: None,
82 reliability_inhibit: common::ReliabilityInhibitState::default(),
83 active_text: "Active".into(),
84 inactive_text: "Inactive".into(),
85 event_detector: ChangeOfStateDetector {
86 alarm_values: vec![1],
87 ..Default::default()
88 },
89 event_detection_enable: true,
90 event_history: EventHistory::default(),
91 value_source: crate::command_source::ValueSourceTracking::default(),
92 write_source: crate::command_source::SingleValueSource::default(),
93 })
94 }
95
96 pub fn with_tags_persistence(
101 instance: u32,
102 name: impl Into<String>,
103 access: PresentValueAccess,
104 persistence: Arc<dyn TagsPersistence>,
105 ) -> Result<Self, Error> {
106 let mut object = Self::with_access(instance, name, access)?;
107 object.profile = ProfileState::persistent(object.oid, persistence)?;
108 Ok(object)
109 }
110
111 pub fn set_profile(&mut self, profile: ObjectProfile) -> Result<(), Error> {
116 self.profile.provision(profile)
117 }
118
119 pub fn wait_for_tag_saves(&self) {
122 self.profile.wait_for_saves();
123 }
124
125 pub fn set_value_source_tracking(&mut self, enabled: bool) {
130 self.write_source.set_enabled(enabled);
131 }
132
133 pub fn set_description(&mut self, desc: impl Into<String>) {
135 self.description = desc.into();
136 }
137
138 fn recalculate_present_value(&mut self) {
139 self.present_value =
140 common::recalculate_from_priority_array(&self.priority_array, self.relinquish_default);
141 }
142
143 pub fn set_relinquish_default(&mut self, value: u32) -> Result<(), Error> {
149 if self.access != PresentValueAccess::Commandable {
150 return Err(common::unknown_property_error());
151 }
152 if value > 1 {
153 return Err(common::value_out_of_range_error());
154 }
155 self.relinquish_default = value;
156 self.recalculate_present_value();
157 Ok(())
158 }
159
160 fn write_direct_present_value(
162 &mut self,
163 array_index: Option<u32>,
164 value: PropertyValue,
165 ) -> Result<(), Error> {
166 if array_index.is_some() {
167 return Err(common::property_is_not_an_array_error());
168 }
169 if self.access == PresentValueAccess::ReadOnly && !self.out_of_service {
170 return Err(common::write_access_denied_error());
171 }
172 if value == PropertyValue::Null {
174 return Ok(());
175 }
176 self.present_value = Self::checked_present_value(value)?;
177 Ok(())
178 }
179
180 fn checked_present_value(value: PropertyValue) -> Result<u32, Error> {
181 let PropertyValue::Enumerated(e) = value else {
182 return Err(common::invalid_data_type_error());
183 };
184 if e > 1 {
185 return Err(common::value_out_of_range_error());
186 }
187 Ok(e)
188 }
189}
190
191impl BACnetObject for BinaryValueObject {
192 fn audit_policy_authority_internal(
193 &mut self,
194 ) -> Option<crate::audit::AuditPolicyAuthority<'_>> {
195 Some(crate::audit::AuditPolicyAuthority::new(
196 &mut self.audit_policy,
197 ))
198 }
199
200 fn audit_object_policy_internal(&self) -> crate::audit::ObjectAuditPolicy {
201 self.audit_policy
202 }
203
204 fn object_identifier(&self) -> ObjectIdentifier {
205 self.oid
206 }
207
208 fn object_name(&self) -> &str {
209 &self.name
210 }
211
212 fn supports_cov(&self) -> bool {
213 true
214 }
215
216 crate::event::impl_builtin_intrinsic_reporting!(
217 event_detector,
218 event_history,
219 [present_value],
220 reliability,
221 event_detection_enable,
222 ChangeOfStateDetector::ALGORITHM
223 );
224
225 fn acknowledge_alarm_correlated_internal(
226 &mut self,
227 event_state: EventState,
228 timestamp: &BACnetTimeStamp,
229 ) -> Result<(), Error> {
230 if !self.event_detection_enable {
231 return Err(Error::protocol(
232 ErrorClass::OBJECT,
233 ErrorCode::NO_ALARM_CONFIGURED,
234 ));
235 }
236 self.event_history.acknowledge_correlated(
237 &mut self.event_detector.acked_transitions,
238 event_state,
239 timestamp,
240 )
241 }
242
243 fn read_property(
244 &self,
245 property: PropertyIdentifier,
246 array_index: Option<u32>,
247 ) -> Result<PropertyValue, Error> {
248 if metadata::excludes(self, property) {
249 return Err(common::unknown_property_error());
250 }
251 let source = match self.access {
252 PresentValueAccess::Commandable => {
253 self.value_source
254 .read(property, array_index, &self.priority_array)
255 }
256 _ => self.write_source.read(property, array_index),
257 };
258 if let Some(result) = source {
259 return result;
260 }
261 if let Some(result) = self.profile.read(property, array_index) {
262 return result;
263 }
264
265 if let Some(result) = self.audit_policy.read(property, array_index) {
266 return result;
267 }
268 if property == PropertyIdentifier::STATUS_FLAGS {
269 return Ok(common::compute_status_flags(
270 self.status_flags,
271 self.reliability,
272 self.out_of_service,
273 self.event_detector.event_state,
274 ));
275 }
276 if let Some(value) = self.reliability_inhibit.read(property) {
277 return Ok(value);
278 }
279 if let Some(result) = read_common_properties!(self, property, array_index) {
280 return result;
281 }
282 if property == PropertyIdentifier::EVENT_DETECTION_ENABLE {
283 return Ok(PropertyValue::Boolean(self.event_detection_enable));
284 }
285 if let Some(result) = read_generic_event_properties!(self, property) {
286 return result;
287 }
288 if let Some(result) = self.event_history.read(property, array_index) {
289 return result;
290 }
291 match property {
292 p if p == PropertyIdentifier::OBJECT_TYPE => {
293 Ok(PropertyValue::Enumerated(ObjectType::BINARY_VALUE.to_raw()))
294 }
295 p if p == PropertyIdentifier::PRESENT_VALUE => {
296 Ok(PropertyValue::Enumerated(self.present_value))
297 }
298 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
299 common::read_priority_array!(self, array_index, PropertyValue::Enumerated)
300 }
301 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
302 Ok(PropertyValue::Enumerated(self.relinquish_default))
303 }
304 p if p == PropertyIdentifier::CURRENT_COMMAND_PRIORITY => {
305 Ok(common::current_command_priority(&self.priority_array))
306 }
307 p if p == PropertyIdentifier::ACTIVE_TEXT => {
308 Ok(PropertyValue::CharacterString(self.active_text.clone()))
309 }
310 p if p == PropertyIdentifier::INACTIVE_TEXT => {
311 Ok(PropertyValue::CharacterString(self.inactive_text.clone()))
312 }
313 p if p == PropertyIdentifier::ALARM_VALUE => {
314 Ok(PropertyValue::Enumerated(
317 self.event_detector
318 .alarm_values
319 .first()
320 .copied()
321 .unwrap_or(1),
322 ))
323 }
324 _ => Err(common::unknown_property_error()),
325 }
326 }
327
328 fn write_property_from(
329 &mut self,
330 property: PropertyIdentifier,
331 array_index: Option<u32>,
332 value: PropertyValue,
333 priority: Option<u8>,
334 origin: &crate::command_source::CommandOrigin,
335 ) -> Result<(), Error> {
336 if matches!(
337 property,
338 PropertyIdentifier::PRESENT_VALUE | PropertyIdentifier::VALUE_SOURCE
339 ) && array_index.is_some()
340 {
341 return Err(common::property_is_not_an_array_error());
342 }
343 if property == PropertyIdentifier::VALUE_SOURCE {
344 return match self.access {
345 PresentValueAccess::Commandable => {
346 self.value_source.correct(value, priority, origin)
347 }
348 _ => self.write_source.correct(array_index, value, origin),
349 };
350 }
351 if property == PropertyIdentifier::PRESENT_VALUE {
352 return match self.access {
353 PresentValueAccess::Commandable => {
354 crate::command_source::write_sourced_priority!(
355 self,
356 value,
357 priority,
358 origin,
359 Self::checked_present_value
360 )
361 }
362 PresentValueAccess::ReadOnly | PresentValueAccess::Writable => {
363 self.write_source.admit(origin)?;
364 let null = value == PropertyValue::Null;
366 self.write_direct_present_value(array_index, value)?;
367 if !null {
368 self.write_source.record(origin);
369 }
370 Ok(())
371 }
372 };
373 }
374 self.write_property(property, array_index, value, priority)
375 }
376
377 fn write_property(
378 &mut self,
379 property: PropertyIdentifier,
380 array_index: Option<u32>,
381 value: PropertyValue,
382 priority: Option<u8>,
383 ) -> Result<(), Error> {
384 if metadata::excludes(self, property) {
385 return Err(common::unknown_property_error());
386 }
387 if let Some(result) = self.profile.write(property, array_index, &value) {
388 return result;
389 }
390 if let Some(result) = self
391 .audit_policy
392 .write(property, array_index, &value, priority)
393 {
394 return result;
395 }
396
397 if property == PropertyIdentifier::PRESENT_VALUE {
398 if self.access == PresentValueAccess::Commandable {
399 return Err(common::write_access_denied_error());
400 }
401 self.write_source.unsourced()?;
403 return self.write_direct_present_value(array_index, value);
404 }
405 if property == PropertyIdentifier::VALUE_SOURCE {
406 return Err(common::write_access_denied_error());
407 }
408 if property == PropertyIdentifier::ACTIVE_TEXT {
409 if let PropertyValue::CharacterString(s) = value {
410 self.active_text = s;
411 return Ok(());
412 }
413 return Err(common::invalid_data_type_error());
414 }
415 if property == PropertyIdentifier::INACTIVE_TEXT {
416 if let PropertyValue::CharacterString(s) = value {
417 self.inactive_text = s;
418 return Ok(());
419 }
420 return Err(common::invalid_data_type_error());
421 }
422 if property == PropertyIdentifier::ALARM_VALUE {
423 if let PropertyValue::Enumerated(v) = value {
424 if v > 1 {
425 return Err(common::value_out_of_range_error());
426 }
427 self.event_detector.alarm_values = vec![v];
428 return Ok(());
429 }
430 return Err(common::invalid_data_type_error());
431 }
432 if property == PropertyIdentifier::EVENT_DETECTION_ENABLE {
433 if let PropertyValue::Boolean(v) = value {
434 self.event_detection_enable = v;
435 if !v {
436 self.event_detector.event_state = bacnet_types::enums::EventState::NORMAL;
437 self.event_detector.acked_transitions =
438 bacnet_types::bitstring::EventTransitionBits::all();
439 self.event_detector.pending = None;
440 self.event_detector.fault_reliability = None;
441 self.event_history.reset();
442 }
443 return Ok(());
444 }
445 return Err(common::invalid_data_type_error());
446 }
447 if property == PropertyIdentifier::RELINQUISH_DEFAULT {
448 if let PropertyValue::Enumerated(e) = value {
449 return self.set_relinquish_default(e);
450 }
451 return Err(common::invalid_data_type_error());
452 }
453 if let Some(result) =
455 self.event_history
456 .write(property, array_index, &value, self.event_detection_enable)
457 {
458 return result;
459 }
460 if let Some(result) = write_generic_event_properties!(self, property, value) {
461 return result;
462 }
463 if let Some(result) = self.reliability_inhibit.write_inhibit(
464 &mut self.reliability,
465 self.out_of_service,
466 property,
467 &value,
468 ) {
469 return result;
470 }
471 if let Some(result) = self.reliability_inhibit.write_out_of_service(
472 &mut self.out_of_service,
473 &mut self.reliability,
474 &mut self.reliability_before_out_of_service,
475 property,
476 &value,
477 ) {
478 return result.map(|_| ());
479 }
480 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
481 return result;
482 }
483 if let Some(result) = common::write_description(&mut self.description, property, &value) {
484 return result;
485 }
486 if let Some(result) = self.reliability_inhibit.write_client_reliability(
491 self.out_of_service,
492 &mut self.reliability,
493 property,
494 &value,
495 ) {
496 return result;
497 }
498 Err(crate::common::unhandled_write_error(
499 self.property_metadata().as_ref(),
500 property,
501 array_index,
502 ))
503 }
504
505 fn durable_writes_internal(&mut self) -> Option<&mut dyn crate::durable::DurableWrites> {
506 self.profile.capability()
507 }
508
509 fn advance_monotonic_time_internal(&mut self, now: core::time::Duration) -> bool {
510 self.profile.expire(now);
511 false
512 }
513
514 fn property_metadata(&self) -> Cow<'_, [PropertyMetadata]> {
515 metadata::for_object(self)
516 }
517
518 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
519 crate::property_metadata::property_list_from_metadata(self.property_metadata().as_ref())
520 }
521
522 fn is_createable(&self) -> bool {
523 true
524 }
525
526 fn set_reliability_internal(&mut self, reliability: Reliability) -> Result<(), Error> {
527 if self.out_of_service || self.reliability_inhibit.enabled() {
528 return Err(common::write_access_denied_error());
529 }
530 if !common::is_reliability_value_valid(reliability) {
531 return Err(common::value_out_of_range_error());
532 }
533 self.reliability = reliability;
534 Ok(())
535 }
536
537 fn set_present_value_internal(&mut self, value: PropertyValue) -> Result<(), Error> {
538 match self.access {
539 PresentValueAccess::Commandable => {
540 Err(common::optional_functionality_not_supported_error())
541 }
542 _ if self.out_of_service => Err(common::write_access_denied_error()),
543 PresentValueAccess::ReadOnly | PresentValueAccess::Writable => {
544 self.present_value = Self::checked_present_value(value)?;
545 self.write_source.forget();
546 Ok(())
547 }
548 }
549 }
550
551 fn set_present_value_from_internal(
552 &mut self,
553 value: PropertyValue,
554 origin: &crate::command_source::CommandOrigin,
555 ) -> Result<(), Error> {
556 self.write_source.admit(origin)?;
557 self.set_present_value_internal(value)?;
558 self.write_source.record(origin);
559 Ok(())
560 }
561
562 fn reliability_evaluation_inhibited_internal(&self) -> bool {
563 self.reliability_inhibit.enabled()
564 }
565}
566
567#[cfg(test)]
568#[path = "tests/value.rs"]
569mod value_tests;