Skip to main content

bacnet_objects/elevator/
escalator.rs

1//! The Escalator object (type 58, Clause 12.60).
2
3use bacnet_types::constructed::BACnetDeviceObjectReference;
4use bacnet_types::enums::{
5    EscalatorFault, EscalatorMode, EscalatorOperationDirection, ObjectType, PropertyIdentifier,
6    Reliability,
7};
8use bacnet_types::error::Error;
9use bacnet_types::primitives::{ObjectIdentifier, PropertyValue, StatusFlags};
10use std::borrow::Cow;
11
12use super::energy_meter::{energy_meter_accessors, EnergyMeter};
13use super::membership::{group_membership_accessors, GroupMembership};
14use super::{decode_fault_signals, metadata, named_or_proprietary};
15use crate::common::{self, read_common_properties};
16use crate::traits::BACnetObject;
17
18/// BACnet Escalator object — represents an escalator.
19///
20/// The object serves the rows of its table (Clause 12.60, Table 12-78) that
21/// it implements, each with its table datatype.
22pub struct EscalatorObject {
23    oid: ObjectIdentifier,
24    name: String,
25    description: String,
26    /// Elevator_Group, Group_ID and Installation_ID.
27    membership: GroupMembership,
28    /// Escalator mode (BACnetEscalatorMode, Clause 21); proprietary extensions
29    /// (Clause 23.1) are preserved as raw values.
30    pub(super) escalator_mode: EscalatorMode,
31    /// Fault signal set (BACnetEscalatorFault, Clause 21).
32    pub(super) fault_signals: Vec<EscalatorFault>,
33    /// Energy_Meter and Energy_Meter_Ref.
34    energy_meter: EnergyMeter,
35    /// Power mode (Boolean).
36    power_mode: bool,
37    /// Operation direction (BACnetEscalatorOperationDirection, Clause 21);
38    /// proprietary extensions (Clause 23.1) are preserved as raw values.
39    pub(super) operation_direction: EscalatorOperationDirection,
40    /// Passenger alarm state (Boolean).
41    passenger_alarm: bool,
42    status_flags: StatusFlags,
43    out_of_service: bool,
44    reliability: Reliability,
45}
46
47impl EscalatorObject {
48    /// Create a new Escalator object with default values.
49    pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
50        let oid = ObjectIdentifier::new(ObjectType::ESCALATOR, instance)?;
51        Ok(Self {
52            oid,
53            name: name.into(),
54            description: String::new(),
55            membership: GroupMembership::new()?,
56            escalator_mode: EscalatorMode::UNKNOWN,
57            fault_signals: Vec::new(),
58            energy_meter: EnergyMeter::new()?,
59            power_mode: false,
60            operation_direction: EscalatorOperationDirection::UNKNOWN,
61            passenger_alarm: false,
62            status_flags: StatusFlags::empty(),
63            out_of_service: false,
64            reliability: Reliability::NO_FAULT_DETECTED,
65        })
66    }
67
68    group_membership_accessors!("escalator");
69    energy_meter_accessors!("escalator");
70}
71
72impl BACnetObject for EscalatorObject {
73    fn object_identifier(&self) -> ObjectIdentifier {
74        self.oid
75    }
76
77    fn object_name(&self) -> &str {
78        &self.name
79    }
80
81    fn read_property(
82        &self,
83        property: PropertyIdentifier,
84        array_index: Option<u32>,
85    ) -> Result<PropertyValue, Error> {
86        if let Some(result) = read_common_properties!(self, property, array_index) {
87            return result;
88        }
89        if let Some(value) = self.membership.read(property) {
90            return Ok(value);
91        }
92        if let Some(value) = self.energy_meter.read(property) {
93            return Ok(value);
94        }
95        match property {
96            p if p == PropertyIdentifier::OBJECT_TYPE => {
97                Ok(PropertyValue::Enumerated(ObjectType::ESCALATOR.to_raw()))
98            }
99            p if p == PropertyIdentifier::ESCALATOR_MODE => {
100                Ok(PropertyValue::Enumerated(self.escalator_mode.to_raw()))
101            }
102            p if p == PropertyIdentifier::FAULT_SIGNALS => {
103                let items: Vec<PropertyValue> = self
104                    .fault_signals
105                    .iter()
106                    .map(|v| PropertyValue::Enumerated(v.to_raw()))
107                    .collect();
108                Ok(PropertyValue::List(items))
109            }
110            p if p == PropertyIdentifier::POWER_MODE => Ok(PropertyValue::Boolean(self.power_mode)),
111            p if p == PropertyIdentifier::OPERATION_DIRECTION => {
112                Ok(PropertyValue::Enumerated(self.operation_direction.to_raw()))
113            }
114            p if p == PropertyIdentifier::PASSENGER_ALARM => {
115                Ok(PropertyValue::Boolean(self.passenger_alarm))
116            }
117            _ => Err(common::unknown_property_error()),
118        }
119    }
120
121    fn write_property(
122        &mut self,
123        property: PropertyIdentifier,
124        _array_index: Option<u32>,
125        value: PropertyValue,
126        _priority: Option<u8>,
127    ) -> Result<(), Error> {
128        if let Some(result) =
129            common::write_out_of_service(&mut self.out_of_service, property, &value)
130        {
131            return result;
132        }
133        if let Some(result) = common::write_description(&mut self.description, property, &value) {
134            return result;
135        }
136        if let Some(result) = self.energy_meter.write(property, &value) {
137            return result;
138        }
139        match property {
140            p if p == PropertyIdentifier::POWER_MODE => {
141                if let PropertyValue::Boolean(v) = value {
142                    self.power_mode = v;
143                    Ok(())
144                } else {
145                    Err(common::invalid_data_type_error())
146                }
147            }
148            p if p == PropertyIdentifier::ESCALATOR_MODE => {
149                if let PropertyValue::Enumerated(v) = value {
150                    let mode = EscalatorMode::from_raw(v);
151                    if !named_or_proprietary(EscalatorMode::ALL_NAMED, mode, v) {
152                        return Err(common::value_out_of_range_error());
153                    }
154                    self.escalator_mode = mode;
155                    Ok(())
156                } else {
157                    Err(common::invalid_data_type_error())
158                }
159            }
160            p if p == PropertyIdentifier::OPERATION_DIRECTION => {
161                if let PropertyValue::Enumerated(v) = value {
162                    // Validate before mutating so a refused write leaves the
163                    // prior value intact.
164                    let direction = EscalatorOperationDirection::from_raw(v);
165                    if !named_or_proprietary(EscalatorOperationDirection::ALL_NAMED, direction, v) {
166                        return Err(common::value_out_of_range_error());
167                    }
168                    self.operation_direction = direction;
169                    Ok(())
170                } else {
171                    Err(common::invalid_data_type_error())
172                }
173            }
174            p if p == PropertyIdentifier::FAULT_SIGNALS => {
175                self.fault_signals = decode_fault_signals(
176                    value,
177                    EscalatorFault::ALL_NAMED,
178                    EscalatorFault::from_raw,
179                )?;
180                Ok(())
181            }
182            p if p == PropertyIdentifier::PASSENGER_ALARM => {
183                if let PropertyValue::Boolean(v) = value {
184                    self.passenger_alarm = v;
185                    Ok(())
186                } else {
187                    Err(common::invalid_data_type_error())
188                }
189            }
190            _ => Err(crate::common::unhandled_write_error(
191                self.property_metadata().as_ref(),
192                property,
193                _array_index,
194            )),
195        }
196    }
197
198    fn property_metadata(&self) -> Cow<'_, [crate::property_metadata::PropertyMetadata]> {
199        metadata::for_escalator_object(self)
200    }
201
202    fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
203        crate::property_metadata::property_list_from_metadata(self.property_metadata().as_ref())
204    }
205}