use super::*;
use bacnet_services::cov::{SubscribeCOVPropertyRequest, SubscribeCOVRequest};
use bacnet_types::enums::PropertyIdentifier;
use bacnet_types::primitives::ObjectIdentifier;
use std::num::NonZeroU32;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CovPropertySubscription {
pub subscriber_process_identifier: u32,
pub monitored_object_identifier: ObjectIdentifier,
pub monitored_property_identifier: PropertyIdentifier,
pub monitored_property_array_index: Option<u32>,
pub confirmed: bool,
pub lifetime: NonZeroU32,
pub cov_increment: Option<f32>,
}
impl CovPropertySubscription {
pub(super) fn into_request(self) -> SubscribeCOVPropertyRequest {
SubscribeCOVPropertyRequest {
subscriber_process_identifier: self.subscriber_process_identifier,
monitored_object_identifier: self.monitored_object_identifier,
issue_confirmed_notifications: Some(self.confirmed),
lifetime: Some(self.lifetime.get()),
monitored_property_identifier: self.monitored_property_identifier,
monitored_property_array_index: self.monitored_property_array_index,
cov_increment: self.cov_increment,
}
}
}
impl<T: TransportPort + 'static> BACnetClient<T> {
pub(super) fn subscribe_cov_request(
subscriber_process_identifier: u32,
monitored_object_identifier: ObjectIdentifier,
confirmed: Option<bool>,
lifetime: Option<u32>,
) -> SubscribeCOVRequest {
SubscribeCOVRequest {
subscriber_process_identifier,
monitored_object_identifier,
issue_confirmed_notifications: confirmed,
lifetime,
}
}
pub(super) async fn send_subscribe_cov_request(
&self,
target: ConfirmedTarget<'_>,
request: SubscribeCOVRequest,
) -> Result<(), Error> {
let mut buf = BytesMut::new();
request.encode(&mut buf)?;
let _ = self
.confirmed_request_inner(target, ConfirmedServiceChoice::SUBSCRIBE_COV, &buf)
.await?;
Ok(())
}
fn subscribe_cov_property_request(
subscriber_process_identifier: u32,
monitored_object_identifier: ObjectIdentifier,
confirmed: Option<bool>,
lifetime: Option<u32>,
monitored_property_identifier: PropertyIdentifier,
monitored_property_array_index: Option<u32>,
cov_increment: Option<f32>,
) -> SubscribeCOVPropertyRequest {
SubscribeCOVPropertyRequest {
subscriber_process_identifier,
monitored_object_identifier,
issue_confirmed_notifications: confirmed,
lifetime,
monitored_property_identifier,
monitored_property_array_index,
cov_increment,
}
}
pub(super) async fn send_subscribe_cov_property_request(
&self,
target: ConfirmedTarget<'_>,
request: SubscribeCOVPropertyRequest,
) -> Result<(), Error> {
let mut buf = BytesMut::new();
request.encode(&mut buf)?;
let _ = self
.confirmed_request_inner(target, ConfirmedServiceChoice::SUBSCRIBE_COV_PROPERTY, &buf)
.await?;
Ok(())
}
pub async fn subscribe_cov(
&self,
destination_mac: &[u8],
subscriber_process_identifier: u32,
monitored_object_identifier: ObjectIdentifier,
confirmed: bool,
lifetime: Option<u32>,
) -> Result<(), Error> {
let request = Self::subscribe_cov_request(
subscriber_process_identifier,
monitored_object_identifier,
Some(confirmed),
lifetime,
);
self.send_subscribe_cov_request(
ConfirmedTarget::Local {
mac: destination_mac,
},
request,
)
.await
}
pub async fn subscribe_cov_to_device(
&self,
device_instance: u32,
subscriber_process_identifier: u32,
monitored_object_identifier: ObjectIdentifier,
confirmed: bool,
lifetime: Option<u32>,
) -> Result<(), Error> {
let request = Self::subscribe_cov_request(
subscriber_process_identifier,
monitored_object_identifier,
Some(confirmed),
lifetime,
);
request.validate()?;
let (mac, routing) = self.resolve_device(device_instance).await?;
if let Some((dnet, dadr)) = routing {
self.send_subscribe_cov_request(
ConfirmedTarget::Routed {
router_mac: &mac,
dest_network: dnet,
dest_mac: &dadr,
},
request,
)
.await
} else {
self.send_subscribe_cov_request(ConfirmedTarget::Local { mac: &mac }, request)
.await
}
}
pub async fn unsubscribe_cov(
&self,
destination_mac: &[u8],
subscriber_process_identifier: u32,
monitored_object_identifier: ObjectIdentifier,
) -> Result<(), Error> {
let request = Self::subscribe_cov_request(
subscriber_process_identifier,
monitored_object_identifier,
None,
None,
);
self.send_subscribe_cov_request(
ConfirmedTarget::Local {
mac: destination_mac,
},
request,
)
.await
}
pub async fn unsubscribe_cov_to_device(
&self,
device_instance: u32,
subscriber_process_identifier: u32,
monitored_object_identifier: ObjectIdentifier,
) -> Result<(), Error> {
let request = Self::subscribe_cov_request(
subscriber_process_identifier,
monitored_object_identifier,
None,
None,
);
request.validate()?;
let (mac, routing) = self.resolve_device(device_instance).await?;
if let Some((dnet, dadr)) = routing {
self.send_subscribe_cov_request(
ConfirmedTarget::Routed {
router_mac: &mac,
dest_network: dnet,
dest_mac: &dadr,
},
request,
)
.await
} else {
self.send_subscribe_cov_request(ConfirmedTarget::Local { mac: &mac }, request)
.await
}
}
pub async fn subscribe_cov_property(
&self,
destination_mac: &[u8],
subscription: CovPropertySubscription,
) -> Result<(), Error> {
let request = subscription.into_request();
self.send_subscribe_cov_property_request(
ConfirmedTarget::Local {
mac: destination_mac,
},
request,
)
.await
}
pub async fn subscribe_cov_property_to_device(
&self,
device_instance: u32,
subscription: CovPropertySubscription,
) -> Result<(), Error> {
let request = subscription.into_request();
request.validate()?;
let (mac, routing) = self.resolve_device(device_instance).await?;
if let Some((dnet, dadr)) = routing {
self.send_subscribe_cov_property_request(
ConfirmedTarget::Routed {
router_mac: &mac,
dest_network: dnet,
dest_mac: &dadr,
},
request,
)
.await
} else {
self.send_subscribe_cov_property_request(ConfirmedTarget::Local { mac: &mac }, request)
.await
}
}
pub async fn unsubscribe_cov_property(
&self,
destination_mac: &[u8],
subscriber_process_identifier: u32,
monitored_object_identifier: ObjectIdentifier,
monitored_property_identifier: PropertyIdentifier,
monitored_property_array_index: Option<u32>,
) -> Result<(), Error> {
let request = Self::subscribe_cov_property_request(
subscriber_process_identifier,
monitored_object_identifier,
None,
None,
monitored_property_identifier,
monitored_property_array_index,
None,
);
self.send_subscribe_cov_property_request(
ConfirmedTarget::Local {
mac: destination_mac,
},
request,
)
.await
}
pub async fn unsubscribe_cov_property_to_device(
&self,
device_instance: u32,
subscriber_process_identifier: u32,
monitored_object_identifier: ObjectIdentifier,
monitored_property_identifier: PropertyIdentifier,
monitored_property_array_index: Option<u32>,
) -> Result<(), Error> {
let request = Self::subscribe_cov_property_request(
subscriber_process_identifier,
monitored_object_identifier,
None,
None,
monitored_property_identifier,
monitored_property_array_index,
None,
);
request.validate()?;
let (mac, routing) = self.resolve_device(device_instance).await?;
if let Some((dnet, dadr)) = routing {
self.send_subscribe_cov_property_request(
ConfirmedTarget::Routed {
router_mac: &mac,
dest_network: dnet,
dest_mac: &dadr,
},
request,
)
.await
} else {
self.send_subscribe_cov_property_request(ConfirmedTarget::Local { mac: &mac }, request)
.await
}
}
pub async fn unsubscribe_cov_target(
&self,
target: &CovTarget,
subscriber_process_identifier: u32,
monitored_object_identifier: ObjectIdentifier,
) -> Result<(), Error> {
let request = Self::subscribe_cov_request(
subscriber_process_identifier,
monitored_object_identifier,
None,
None,
);
self.send_subscribe_cov_request(target.confirmed(), request)
.await
}
pub async fn unsubscribe_cov_property_target(
&self,
target: &CovTarget,
subscriber_process_identifier: u32,
monitored_object_identifier: ObjectIdentifier,
monitored_property_identifier: PropertyIdentifier,
monitored_property_array_index: Option<u32>,
) -> Result<(), Error> {
let request = Self::subscribe_cov_property_request(
subscriber_process_identifier,
monitored_object_identifier,
None,
None,
monitored_property_identifier,
monitored_property_array_index,
None,
);
self.send_subscribe_cov_property_request(target.confirmed(), request)
.await
}
pub fn cov_notifications(&self) -> broadcast::Receiver<ReceivedCOVNotification> {
self.cov_tx.subscribe()
}
}
#[cfg(test)]
#[path = "cov_property_validation_tests.rs"]
mod property_validation_tests;
#[cfg(test)]
#[path = "cov_request_validation_tests.rs"]
mod request_validation_tests;