use super::*;
use bacnet_services::read_range::{
RangeSpec, ReadRangeAck, ReadRangeReply, ReadRangeRequest, ReadRangeValidation,
};
use bacnet_types::enums::PropertyIdentifier;
use bacnet_types::primitives::ObjectIdentifier;
use crate::log_reader::{LogCursor, LogPage, LogRequester};
impl<T: TransportPort + 'static> BACnetClient<T> {
pub async fn read_range(
&self,
destination_mac: &[u8],
object_identifier: ObjectIdentifier,
property_identifier: PropertyIdentifier,
property_array_index: Option<u32>,
range: Option<RangeSpec>,
) -> Result<ReadRangeAck, Error> {
let request = ReadRangeRequest {
object_identifier,
property_identifier,
property_array_index,
range,
};
self.read_range_with(destination_mac, &request, ReadRangeValidation::Strict)
.await
.map(|reply| reply.ack)
}
pub async fn read_range_with(
&self,
destination_mac: &[u8],
request: &ReadRangeRequest,
validation: ReadRangeValidation,
) -> Result<ReadRangeReply, Error> {
let mut buf = BytesMut::new();
request.encode(&mut buf)?;
let response = self
.confirmed_request(destination_mac, ConfirmedServiceChoice::READ_RANGE, &buf)
.await?;
ReadRangeReply::check(request, ReadRangeAck::decode(&response)?, validation)
}
pub async fn read_range_from_device(
&self,
device_instance: u32,
object_identifier: ObjectIdentifier,
property_identifier: PropertyIdentifier,
property_array_index: Option<u32>,
range: Option<RangeSpec>,
) -> Result<ReadRangeAck, Error> {
let request = ReadRangeRequest {
object_identifier,
property_identifier,
property_array_index,
range,
};
self.read_range_from_device_with(device_instance, &request, ReadRangeValidation::Strict)
.await
.map(|reply| reply.ack)
}
pub async fn read_range_from_device_with(
&self,
device_instance: u32,
request: &ReadRangeRequest,
validation: ReadRangeValidation,
) -> Result<ReadRangeReply, Error> {
let (mac, routing) = self.resolve_device(device_instance).await?;
if let Some((network, address)) = routing {
self.read_range_routed(&mac, network, &address, request, validation)
.await
} else {
self.read_range_with(&mac, request, validation).await
}
}
pub async fn read_log_page_from_device(
&self,
device_instance: u32,
log: ObjectIdentifier,
cursor: LogCursor,
page_size: u16,
) -> Result<LogPage, Error> {
let (mac, routing) = self.resolve_device(device_instance).await?;
if let Some((network, address)) = routing {
let requester = RoutedLogRequester {
client: self,
network,
address: &address,
};
crate::log_reader::read_log_page(&requester, &mac, log, cursor, page_size).await
} else {
self.read_log_page(&mac, log, cursor, page_size).await
}
}
async fn read_range_routed(
&self,
router_mac: &[u8],
network: u16,
address: &[u8],
request: &ReadRangeRequest,
validation: ReadRangeValidation,
) -> Result<ReadRangeReply, Error> {
let mut buf = BytesMut::new();
request.encode(&mut buf)?;
let response = self
.confirmed_request_routed(
router_mac,
network,
address,
ConfirmedServiceChoice::READ_RANGE,
&buf,
)
.await?;
ReadRangeReply::check(request, ReadRangeAck::decode(&response)?, validation)
}
}
struct RoutedLogRequester<'a, T: TransportPort> {
client: &'a BACnetClient<T>,
network: u16,
address: &'a [u8],
}
impl<T: TransportPort + 'static> LogRequester for RoutedLogRequester<'_, T> {
async fn read_unsigned(
&self,
router_mac: &[u8],
log: ObjectIdentifier,
property: PropertyIdentifier,
) -> Result<u64, Error> {
let ack = self
.client
.read_property_routed(router_mac, self.network, self.address, log, property, None)
.await?;
crate::log_reader::unsigned_value(&ack.property_value)
}
async fn read_range_lenient(
&self,
router_mac: &[u8],
request: &ReadRangeRequest,
) -> Result<ReadRangeReply, Error> {
self.client
.read_range_routed(
router_mac,
self.network,
self.address,
request,
ReadRangeValidation::Lenient,
)
.await
}
}
#[cfg(test)]
#[path = "routed_read_services_tests.rs"]
mod tests;