Skip to main content

bacnet_objects/elevator/
escalator.rs

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