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