1use super::*;
2use crate::object_profile::{ObjectProfile, ProfileState, TagsPersistence};
3use crate::prelude::*;
4use crate::property_metadata::{
5 PropertyConformance, PropertyMetadata, PropertyPresenceCondition, PropertyWriteCapability,
6};
7use alloc::sync::Arc;
8
9const BINARY_INPUT_PROPERTY_METADATA: &[PropertyMetadata] = &[
10 PropertyMetadata::new(
11 PropertyIdentifier::OBJECT_IDENTIFIER,
12 PropertyConformance::RequiredRead,
13 None,
14 PropertyWriteCapability::ReadOnly,
15 ),
16 PropertyMetadata::new(
17 PropertyIdentifier::OBJECT_NAME,
18 PropertyConformance::RequiredRead,
19 None,
20 PropertyWriteCapability::Always,
21 ),
22 PropertyMetadata::new(
23 PropertyIdentifier::DESCRIPTION,
24 PropertyConformance::Optional,
25 None,
26 PropertyWriteCapability::Always,
27 ),
28 PropertyMetadata::new(
29 PropertyIdentifier::OBJECT_TYPE,
30 PropertyConformance::RequiredRead,
31 None,
32 PropertyWriteCapability::ReadOnly,
33 ),
34 PropertyMetadata::new(
35 PropertyIdentifier::PRESENT_VALUE,
36 PropertyConformance::RequiredRead,
37 None,
38 PropertyWriteCapability::WhenOutOfService,
39 ),
40 PropertyMetadata::new(
41 PropertyIdentifier::STATUS_FLAGS,
42 PropertyConformance::RequiredRead,
43 None,
44 PropertyWriteCapability::ReadOnly,
45 ),
46 PropertyMetadata::new(
47 PropertyIdentifier::EVENT_STATE,
48 PropertyConformance::RequiredRead,
49 None,
50 PropertyWriteCapability::ReadOnly,
51 ),
52 PropertyMetadata::new(
53 PropertyIdentifier::EVENT_DETECTION_ENABLE,
54 PropertyConformance::Optional,
55 Some(PropertyPresenceCondition::IntrinsicReportingRequired),
56 PropertyWriteCapability::Always,
57 ),
58 PropertyMetadata::new(
59 PropertyIdentifier::EVENT_ENABLE,
60 PropertyConformance::Optional,
61 Some(PropertyPresenceCondition::IntrinsicReportingRequired),
62 PropertyWriteCapability::Always,
63 ),
64 PropertyMetadata::new(
65 PropertyIdentifier::TIME_DELAY,
66 PropertyConformance::Optional,
67 Some(PropertyPresenceCondition::IntrinsicReportingRequired),
68 PropertyWriteCapability::Always,
69 ),
70 PropertyMetadata::new(
71 PropertyIdentifier::TIME_DELAY_NORMAL,
72 PropertyConformance::Optional,
73 Some(PropertyPresenceCondition::IntrinsicReportingOptional),
74 PropertyWriteCapability::Always,
75 ),
76 PropertyMetadata::new(
77 PropertyIdentifier::NOTIFY_TYPE,
78 PropertyConformance::Optional,
79 Some(PropertyPresenceCondition::IntrinsicReportingRequired),
80 PropertyWriteCapability::Always,
81 ),
82 PropertyMetadata::new(
83 PropertyIdentifier::NOTIFICATION_CLASS,
84 PropertyConformance::Optional,
85 Some(PropertyPresenceCondition::IntrinsicReportingRequired),
86 PropertyWriteCapability::Always,
87 ),
88 PropertyMetadata::new(
89 PropertyIdentifier::ACKED_TRANSITIONS,
90 PropertyConformance::Optional,
91 Some(PropertyPresenceCondition::IntrinsicReportingRequired),
92 PropertyWriteCapability::ReadOnly,
93 ),
94 PropertyMetadata::new(
95 PropertyIdentifier::EVENT_TIME_STAMPS,
96 PropertyConformance::Optional,
97 Some(PropertyPresenceCondition::IntrinsicReportingRequired),
98 PropertyWriteCapability::ReadOnly,
99 ),
100 PropertyMetadata::new(
101 PropertyIdentifier::EVENT_MESSAGE_TEXTS,
102 PropertyConformance::Optional,
103 Some(PropertyPresenceCondition::IntrinsicReportingOptional),
104 PropertyWriteCapability::ReadOnly,
105 ),
106 crate::event::options::REPORTING_OPTION_METADATA[0],
108 crate::event::options::REPORTING_OPTION_METADATA[1],
109 crate::event::options::REPORTING_OPTION_METADATA[2],
110 PropertyMetadata::new(
111 PropertyIdentifier::OUT_OF_SERVICE,
112 PropertyConformance::RequiredRead,
113 None,
114 PropertyWriteCapability::Always,
115 ),
116 PropertyMetadata::new(
117 PropertyIdentifier::POLARITY,
118 PropertyConformance::RequiredRead,
119 None,
120 PropertyWriteCapability::ReadOnly,
121 ),
122 PropertyMetadata::new(
123 PropertyIdentifier::RELIABILITY,
124 PropertyConformance::Optional,
125 None,
126 PropertyWriteCapability::WhenOutOfService,
127 ),
128 PropertyMetadata::new(
129 PropertyIdentifier::RELIABILITY_EVALUATION_INHIBIT,
130 PropertyConformance::Optional,
131 None,
132 PropertyWriteCapability::Always,
133 ),
134 PropertyMetadata::new(
135 PropertyIdentifier::ACTIVE_TEXT,
136 PropertyConformance::Optional,
137 Some(PropertyPresenceCondition::PairedText),
138 PropertyWriteCapability::Always,
139 ),
140 PropertyMetadata::new(
141 PropertyIdentifier::INACTIVE_TEXT,
142 PropertyConformance::Optional,
143 Some(PropertyPresenceCondition::PairedText),
144 PropertyWriteCapability::Always,
145 ),
146 PropertyMetadata::new(
147 PropertyIdentifier::ALARM_VALUE,
148 PropertyConformance::Optional,
149 Some(PropertyPresenceCondition::IntrinsicReportingRequired),
150 PropertyWriteCapability::Always,
151 ),
152 PropertyMetadata::new(
153 PropertyIdentifier::PROPERTY_LIST,
154 PropertyConformance::RequiredRead,
155 None,
156 PropertyWriteCapability::ReadOnly,
157 ),
158];
159
160pub struct BinaryInputObject {
169 profile: ProfileState,
170 oid: ObjectIdentifier,
171 name: String,
172 description: String,
173 present_value: u32,
174 out_of_service: bool,
175 status_flags: StatusFlags,
176 polarity: u32,
178 reliability: Reliability,
180 reliability_before_out_of_service: Option<Reliability>,
181 reliability_inhibit: common::ReliabilityInhibitState,
182 active_text: String,
183 inactive_text: String,
184 event_detector: ChangeOfStateDetector,
186 event_detection_enable: bool,
189 pub(crate) event_history: EventHistory,
190}
191
192impl BinaryInputObject {
193 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
195 let oid = ObjectIdentifier::new(ObjectType::BINARY_INPUT, instance)?;
196 Ok(Self {
197 profile: ProfileState::default(),
198 oid,
199 name: name.into(),
200 description: String::new(),
201 present_value: 0,
202 out_of_service: false,
203 status_flags: StatusFlags::empty(),
204 polarity: 0,
205 reliability: Reliability::NO_FAULT_DETECTED,
206 reliability_before_out_of_service: None,
207 reliability_inhibit: common::ReliabilityInhibitState::default(),
208 active_text: "Active".into(),
209 inactive_text: "Inactive".into(),
210 event_detector: ChangeOfStateDetector {
211 alarm_values: vec![1],
212 ..Default::default()
213 },
214 event_detection_enable: true,
215 event_history: EventHistory::default(),
216 })
217 }
218
219 pub fn with_tags_persistence(
223 instance: u32,
224 name: impl Into<String>,
225 persistence: Arc<dyn TagsPersistence>,
226 ) -> Result<Self, Error> {
227 let mut object = Self::new(instance, name)?;
228 object.profile = ProfileState::persistent(object.oid, persistence)?;
229 Ok(object)
230 }
231
232 pub fn set_profile(&mut self, profile: ObjectProfile) -> Result<(), Error> {
237 self.profile.provision(profile)
238 }
239
240 pub fn wait_for_tag_saves(&self) {
243 self.profile.wait_for_saves();
244 }
245
246 pub fn set_present_value(&mut self, value: u32) {
254 self.present_value = value;
255 }
256
257 fn apply_present_value(&mut self, value: PropertyValue) -> Result<(), Error> {
262 let PropertyValue::Enumerated(v) = value else {
263 return Err(common::invalid_data_type_error());
264 };
265 if v > 1 {
266 return Err(common::value_out_of_range_error());
267 }
268 self.present_value = v;
269 Ok(())
270 }
271
272 pub fn set_description(&mut self, desc: impl Into<String>) {
274 self.description = desc.into();
275 }
276}
277
278impl BACnetObject for BinaryInputObject {
279 fn object_identifier(&self) -> ObjectIdentifier {
280 self.oid
281 }
282
283 fn object_name(&self) -> &str {
284 &self.name
285 }
286
287 fn durable_writes_internal(&mut self) -> Option<&mut dyn crate::durable::DurableWrites> {
288 self.profile.capability()
289 }
290
291 fn advance_monotonic_time_internal(&mut self, now: core::time::Duration) -> bool {
292 self.profile.expire(now);
293 false
294 }
295
296 fn property_metadata(&self) -> Cow<'_, [PropertyMetadata]> {
297 let mut rows = Cow::Borrowed(BINARY_INPUT_PROPERTY_METADATA);
298 if self.profile.metadata().next().is_some() {
299 rows.to_mut().extend(self.profile.metadata());
300 }
301 rows
302 }
303
304 fn supports_cov(&self) -> bool {
305 true
306 }
307
308 crate::event::impl_builtin_intrinsic_reporting!(
309 event_detector,
310 event_history,
311 [present_value],
312 reliability,
313 event_detection_enable,
314 ChangeOfStateDetector::ALGORITHM
315 );
316
317 fn acknowledge_alarm_correlated_internal(
318 &mut self,
319 event_state: EventState,
320 timestamp: &BACnetTimeStamp,
321 ) -> Result<(), Error> {
322 if !self.event_detection_enable {
323 return Err(Error::protocol(
324 ErrorClass::OBJECT,
325 ErrorCode::NO_ALARM_CONFIGURED,
326 ));
327 }
328 self.event_history.acknowledge_correlated(
329 &mut self.event_detector.acked_transitions,
330 event_state,
331 timestamp,
332 )
333 }
334
335 fn read_property(
336 &self,
337 property: PropertyIdentifier,
338 array_index: Option<u32>,
339 ) -> Result<PropertyValue, Error> {
340 if property == PropertyIdentifier::STATUS_FLAGS {
341 return Ok(common::compute_status_flags(
342 self.status_flags,
343 self.reliability,
344 self.out_of_service,
345 self.event_detector.event_state,
346 ));
347 }
348 if let Some(value) = self.reliability_inhibit.read(property) {
349 return Ok(value);
350 }
351 if let Some(result) = read_common_properties!(self, property, array_index) {
352 return result;
353 }
354 if property == PropertyIdentifier::EVENT_DETECTION_ENABLE {
355 return Ok(PropertyValue::Boolean(self.event_detection_enable));
356 }
357 if let Some(result) = read_generic_event_properties!(self, property) {
358 return result;
359 }
360 if let Some(result) = self.event_history.read(property, array_index) {
361 return result;
362 }
363 if let Some(result) = self.profile.read(property, array_index) {
364 return result;
365 }
366 match property {
367 p if p == PropertyIdentifier::OBJECT_TYPE => {
368 Ok(PropertyValue::Enumerated(ObjectType::BINARY_INPUT.to_raw()))
369 }
370 p if p == PropertyIdentifier::PRESENT_VALUE => {
371 Ok(PropertyValue::Enumerated(self.present_value))
372 }
373 p if p == PropertyIdentifier::POLARITY => Ok(PropertyValue::Enumerated(self.polarity)),
374 p if p == PropertyIdentifier::ACTIVE_TEXT => {
375 Ok(PropertyValue::CharacterString(self.active_text.clone()))
376 }
377 p if p == PropertyIdentifier::INACTIVE_TEXT => {
378 Ok(PropertyValue::CharacterString(self.inactive_text.clone()))
379 }
380 p if p == PropertyIdentifier::ALARM_VALUE => {
381 Ok(PropertyValue::Enumerated(
384 self.event_detector
385 .alarm_values
386 .first()
387 .copied()
388 .unwrap_or(1),
389 ))
390 }
391 _ => Err(common::unknown_property_error()),
392 }
393 }
394
395 fn write_property(
396 &mut self,
397 property: PropertyIdentifier,
398 array_index: Option<u32>,
399 value: PropertyValue,
400 _priority: Option<u8>,
401 ) -> Result<(), Error> {
402 if property == PropertyIdentifier::PRESENT_VALUE {
403 if !self.out_of_service {
404 return Err(common::write_access_denied_error());
405 }
406 return self.apply_present_value(value);
407 }
408 if let Some(result) = self.profile.write(property, array_index, &value) {
409 return result;
410 }
411 if property == PropertyIdentifier::ACTIVE_TEXT {
412 if let PropertyValue::CharacterString(s) = value {
413 self.active_text = s;
414 return Ok(());
415 }
416 return Err(common::invalid_data_type_error());
417 }
418 if property == PropertyIdentifier::INACTIVE_TEXT {
419 if let PropertyValue::CharacterString(s) = value {
420 self.inactive_text = s;
421 return Ok(());
422 }
423 return Err(common::invalid_data_type_error());
424 }
425 if property == PropertyIdentifier::ALARM_VALUE {
426 if let PropertyValue::Enumerated(v) = value {
427 if v > 1 {
428 return Err(common::value_out_of_range_error());
429 }
430 self.event_detector.alarm_values = vec![v];
431 return Ok(());
432 }
433 return Err(common::invalid_data_type_error());
434 }
435 if property == PropertyIdentifier::EVENT_DETECTION_ENABLE {
436 if let PropertyValue::Boolean(v) = value {
437 self.event_detection_enable = v;
438 if !v {
439 self.event_detector.event_state = bacnet_types::enums::EventState::NORMAL;
440 self.event_detector.acked_transitions =
441 bacnet_types::bitstring::EventTransitionBits::all();
442 self.event_detector.pending = None;
443 self.event_detector.fault_reliability = None;
444 self.event_history.reset();
445 }
446 return Ok(());
447 }
448 return Err(common::invalid_data_type_error());
449 }
450 if let Some(result) =
452 self.event_history
453 .write(property, array_index, &value, self.event_detection_enable)
454 {
455 return result;
456 }
457 if let Some(result) = write_generic_event_properties!(self, property, value) {
458 return result;
459 }
460 if let Some(result) = self.reliability_inhibit.write_inhibit(
461 &mut self.reliability,
462 self.out_of_service,
463 property,
464 &value,
465 ) {
466 return result;
467 }
468 if let Some(result) = self.reliability_inhibit.write_out_of_service(
469 &mut self.out_of_service,
470 &mut self.reliability,
471 &mut self.reliability_before_out_of_service,
472 property,
473 &value,
474 ) {
475 return result.map(|_| ());
476 }
477 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
478 return result;
479 }
480 if let Some(result) = common::write_description(&mut self.description, property, &value) {
481 return result;
482 }
483 if let Some(result) = self.reliability_inhibit.write_client_reliability(
484 self.out_of_service,
485 &mut self.reliability,
486 property,
487 &value,
488 ) {
489 return result;
490 }
491 Err(crate::common::unhandled_write_error(
492 self.property_metadata().as_ref(),
493 property,
494 array_index,
495 ))
496 }
497
498 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
499 let metadata = self.property_metadata();
500 crate::property_metadata::property_list_from_metadata(metadata.as_ref())
501 }
502
503 fn is_createable(&self) -> bool {
504 true
505 }
506
507 fn set_reliability_internal(&mut self, reliability: Reliability) -> Result<(), Error> {
508 if self.out_of_service || self.reliability_inhibit.enabled() {
509 return Err(common::write_access_denied_error());
510 }
511 if !common::is_reliability_value_valid(reliability) {
512 return Err(common::value_out_of_range_error());
513 }
514 self.reliability = reliability;
515 Ok(())
516 }
517
518 fn set_present_value_internal(&mut self, value: PropertyValue) -> Result<(), Error> {
519 if self.out_of_service {
521 return Err(common::write_access_denied_error());
522 }
523 self.apply_present_value(value)
524 }
525
526 fn reliability_evaluation_inhibited_internal(&self) -> bool {
527 self.reliability_inhibit.enabled()
528 }
529}
530
531#[cfg(test)]
532#[path = "tests/input_output.rs"]
533mod input_output_tests;