Skip to main content

bacnet_objects/access_control/
credential_data_input.rs

1use super::*;
2
3// CredentialDataInputObject (type 37)
4// ---------------------------------------------------------------------------
5
6/// BACnet Credential Data Input object (type 37).
7///
8/// Represents a credential reader device (card reader, biometric scanner, etc.).
9/// Present value indicates the authentication status.
10pub struct CredentialDataInputObject {
11    oid: ObjectIdentifier,
12    name: String,
13    description: String,
14    present_value: u32,              // AuthenticationStatus: 0=notReady, 1=waiting
15    update_time: ([u8; 4], [u8; 4]), // (Date, Time) as raw bytes
16    supported_formats: Vec<u64>,
17    supported_format_classes: Vec<u64>,
18    status_flags: StatusFlags,
19    out_of_service: bool,
20    reliability: u32,
21}
22
23impl CredentialDataInputObject {
24    /// Create a new Credential Data Input object.
25    pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
26        let oid = ObjectIdentifier::new(ObjectType::CREDENTIAL_DATA_INPUT, instance)?;
27        Ok(Self {
28            oid,
29            name: name.into(),
30            description: String::new(),
31            present_value: 0, // notReady
32            update_time: ([0xFF, 0xFF, 0xFF, 0xFF], [0xFF, 0xFF, 0xFF, 0xFF]),
33            supported_formats: Vec::new(),
34            supported_format_classes: Vec::new(),
35            status_flags: StatusFlags::empty(),
36            out_of_service: false,
37            reliability: 0,
38        })
39    }
40}
41
42impl BACnetObject for CredentialDataInputObject {
43    fn object_identifier(&self) -> ObjectIdentifier {
44        self.oid
45    }
46
47    fn object_name(&self) -> &str {
48        &self.name
49    }
50
51    fn read_property(
52        &self,
53        property: PropertyIdentifier,
54        array_index: Option<u32>,
55    ) -> Result<PropertyValue, Error> {
56        if let Some(result) = read_common_properties!(self, property, array_index) {
57            return result;
58        }
59        match property {
60            p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
61                ObjectType::CREDENTIAL_DATA_INPUT.to_raw(),
62            )),
63            p if p == PropertyIdentifier::PRESENT_VALUE => {
64                Ok(PropertyValue::Enumerated(self.present_value))
65            }
66            p if p == PropertyIdentifier::UPDATE_TIME => {
67                let (d, t) = &self.update_time;
68                Ok(PropertyValue::List(vec![
69                    PropertyValue::Date(Date {
70                        year: d[0],
71                        month: d[1],
72                        day: d[2],
73                        day_of_week: d[3],
74                    }),
75                    PropertyValue::Time(Time {
76                        hour: t[0],
77                        minute: t[1],
78                        second: t[2],
79                        hundredths: t[3],
80                    }),
81                ]))
82            }
83            p if p == PropertyIdentifier::SUPPORTED_FORMATS => Ok(PropertyValue::List(
84                self.supported_formats
85                    .iter()
86                    .map(|v| PropertyValue::Unsigned(*v))
87                    .collect(),
88            )),
89            p if p == PropertyIdentifier::SUPPORTED_FORMAT_CLASSES => Ok(PropertyValue::List(
90                self.supported_format_classes
91                    .iter()
92                    .map(|v| PropertyValue::Unsigned(*v))
93                    .collect(),
94            )),
95            _ => Err(common::unknown_property_error()),
96        }
97    }
98
99    fn write_property(
100        &mut self,
101        property: PropertyIdentifier,
102        _array_index: Option<u32>,
103        value: PropertyValue,
104        _priority: Option<u8>,
105    ) -> Result<(), Error> {
106        if let Some(result) =
107            common::write_out_of_service(&mut self.out_of_service, property, &value)
108        {
109            return result;
110        }
111        if let Some(result) = common::write_description(&mut self.description, property, &value) {
112            return result;
113        }
114        // CredentialDataInput is primarily read-only (driven by hardware)
115        Err(common::write_access_denied_error())
116    }
117
118    fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
119        static PROPS: &[PropertyIdentifier] = &[
120            PropertyIdentifier::OBJECT_IDENTIFIER,
121            PropertyIdentifier::OBJECT_NAME,
122            PropertyIdentifier::DESCRIPTION,
123            PropertyIdentifier::OBJECT_TYPE,
124            PropertyIdentifier::PRESENT_VALUE,
125            PropertyIdentifier::UPDATE_TIME,
126            PropertyIdentifier::SUPPORTED_FORMATS,
127            PropertyIdentifier::SUPPORTED_FORMAT_CLASSES,
128            PropertyIdentifier::STATUS_FLAGS,
129            PropertyIdentifier::OUT_OF_SERVICE,
130            PropertyIdentifier::RELIABILITY,
131        ];
132        Cow::Borrowed(PROPS)
133    }
134}
135
136// ---------------------------------------------------------------------------
137// Tests
138// ---------------------------------------------------------------------------