#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use crate::error::Error;
const EXTENDED_VALUE_FACTOR: u32 = 100_000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BACnetExtendedPropertyState {
tag: u32,
value: u32,
}
impl BACnetExtendedPropertyState {
pub fn new(tag: u32, value: u32) -> Result<Self, Error> {
if tag <= 254 {
return Err(Error::decoding(
0,
"extended property-state tag must exceed 254",
));
}
if value >= EXTENDED_VALUE_FACTOR {
return Err(Error::decoding(
0,
"extended property-state value must be below 100000",
));
}
tag.checked_mul(EXTENDED_VALUE_FACTOR)
.and_then(|base| base.checked_add(value))
.ok_or_else(|| Error::decoding(0, "extended property-state value exceeds u32"))?;
Ok(Self { tag, value })
}
pub fn from_encoded(encoded: u32) -> Result<Self, Error> {
Self::new(
encoded / EXTENDED_VALUE_FACTOR,
encoded % EXTENDED_VALUE_FACTOR,
)
}
pub const fn tag(self) -> u32 {
self.tag
}
pub const fn value(self) -> u32 {
self.value
}
pub fn encoded(self) -> u32 {
self.tag * EXTENDED_VALUE_FACTOR + self.value
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BACnetProprietaryPropertyState {
tag: u8,
data: Vec<u8>,
constructed: bool,
}
impl BACnetProprietaryPropertyState {
fn new(tag: u8, data: Vec<u8>, constructed: bool) -> Result<Self, Error> {
if !(64..=254).contains(&tag) {
return Err(Error::decoding(
0,
"proprietary property-state tag must be in 64..=254",
));
}
Ok(Self {
tag,
data,
constructed,
})
}
pub fn primitive(tag: u8, data: Vec<u8>) -> Result<Self, Error> {
Self::new(tag, data, false)
}
pub fn constructed(tag: u8, data: Vec<u8>) -> Result<Self, Error> {
Self::new(tag, data, true)
}
pub const fn tag(&self) -> u8 {
self.tag
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub const fn is_constructed(&self) -> bool {
self.constructed
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BACnetPropertyStates {
BooleanValue(bool),
BinaryValue(u32),
EventType(u32),
Polarity(u32),
ProgramChange(u32),
ProgramState(u32),
ReasonForHalt(u32),
Reliability(u32),
State(u32),
SystemStatus(u32),
Units(u32),
UnsignedValue(u32),
LifeSafetyMode(u32),
LifeSafetyState(u32),
RestartReason(u32),
DoorAlarmState(u32),
Action(u32),
DoorSecuredStatus(u32),
DoorStatus(u32),
DoorValue(u32),
FileAccessMethod(u32),
LockStatus(u32),
LifeSafetyOperation(u32),
Maintenance(u32),
NodeType(u32),
NotifyType(u32),
ShedState(u32),
SilencedState(u32),
AccessEvent(u32),
ZoneOccupancyState(u32),
AccessCredentialDisableReason(u32),
AccessCredentialDisable(u32),
AuthenticationStatus(u32),
BackupState(u32),
WriteStatus(u32),
LightingInProgress(u32),
LightingOperation(u32),
LightingTransition(u32),
IntegerValue(i32),
BinaryLightingValue(u32),
TimerState(u32),
TimerTransition(u32),
BacnetIpMode(u32),
NetworkPortCommand(u32),
NetworkType(u32),
NetworkNumberQuality(u32),
EscalatorOperationDirection(u32),
EscalatorFault(u32),
EscalatorMode(u32),
LiftCarDirection(u32),
LiftCarDoorCommand(u32),
LiftCarDriveStatus(u32),
LiftCarMode(u32),
LiftGroupMode(u32),
LiftFault(u32),
ProtocolLevel(u32),
AuditLevel(u32),
AuditOperation(u32),
ExtendedValue(BACnetExtendedPropertyState),
Other(BACnetProprietaryPropertyState),
}
impl BACnetPropertyStates {
pub fn as_u32(&self) -> Option<u32> {
use BACnetPropertyStates as S;
match self {
S::BooleanValue(value) => Some(u32::from(*value)),
S::BinaryValue(value)
| S::EventType(value)
| S::Polarity(value)
| S::ProgramChange(value)
| S::ProgramState(value)
| S::ReasonForHalt(value)
| S::Reliability(value)
| S::State(value)
| S::SystemStatus(value)
| S::Units(value)
| S::UnsignedValue(value)
| S::LifeSafetyMode(value)
| S::LifeSafetyState(value)
| S::RestartReason(value)
| S::DoorAlarmState(value)
| S::Action(value)
| S::DoorSecuredStatus(value)
| S::DoorStatus(value)
| S::DoorValue(value)
| S::FileAccessMethod(value)
| S::LockStatus(value)
| S::LifeSafetyOperation(value)
| S::Maintenance(value)
| S::NodeType(value)
| S::NotifyType(value)
| S::ShedState(value)
| S::SilencedState(value)
| S::AccessEvent(value)
| S::ZoneOccupancyState(value)
| S::AccessCredentialDisableReason(value)
| S::AccessCredentialDisable(value)
| S::AuthenticationStatus(value)
| S::BackupState(value)
| S::WriteStatus(value)
| S::LightingInProgress(value)
| S::LightingOperation(value)
| S::LightingTransition(value)
| S::BinaryLightingValue(value)
| S::TimerState(value)
| S::TimerTransition(value)
| S::BacnetIpMode(value)
| S::NetworkPortCommand(value)
| S::NetworkType(value)
| S::NetworkNumberQuality(value)
| S::EscalatorOperationDirection(value)
| S::EscalatorFault(value)
| S::EscalatorMode(value)
| S::LiftCarDirection(value)
| S::LiftCarDoorCommand(value)
| S::LiftCarDriveStatus(value)
| S::LiftCarMode(value)
| S::LiftGroupMode(value)
| S::LiftFault(value)
| S::ProtocolLevel(value)
| S::AuditLevel(value)
| S::AuditOperation(value) => Some(*value),
S::ExtendedValue(value) => Some(value.value()),
S::IntegerValue(value) => u32::try_from(*value).ok(),
S::Other(value) if !value.is_constructed() && !value.data().is_empty() => {
value.data().iter().try_fold(0u32, |acc, byte| {
acc.checked_mul(256)?.checked_add(*byte as u32)
})
}
S::Other(_) => None,
}
}
}