1use super::*;
2use bacnet_services::cov::{SubscribeCOVPropertyRequest, SubscribeCOVRequest};
3use bacnet_types::enums::PropertyIdentifier;
4use bacnet_types::primitives::ObjectIdentifier;
5use std::num::NonZeroU32;
6
7#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct CovPropertySubscription {
10 pub subscriber_process_identifier: u32,
12 pub monitored_object_identifier: ObjectIdentifier,
14 pub monitored_property_identifier: PropertyIdentifier,
16 pub monitored_property_array_index: Option<u32>,
18 pub confirmed: bool,
20 pub lifetime: NonZeroU32,
22 pub cov_increment: Option<f32>,
24}
25
26impl CovPropertySubscription {
27 pub(super) fn into_request(self) -> SubscribeCOVPropertyRequest {
28 SubscribeCOVPropertyRequest {
29 subscriber_process_identifier: self.subscriber_process_identifier,
30 monitored_object_identifier: self.monitored_object_identifier,
31 issue_confirmed_notifications: Some(self.confirmed),
32 lifetime: Some(self.lifetime.get()),
33 monitored_property_identifier: self.monitored_property_identifier,
34 monitored_property_array_index: self.monitored_property_array_index,
35 cov_increment: self.cov_increment,
36 }
37 }
38}
39
40impl<T: TransportPort + 'static> BACnetClient<T> {
41 pub(super) fn subscribe_cov_request(
42 subscriber_process_identifier: u32,
43 monitored_object_identifier: ObjectIdentifier,
44 confirmed: Option<bool>,
45 lifetime: Option<u32>,
46 ) -> SubscribeCOVRequest {
47 SubscribeCOVRequest {
48 subscriber_process_identifier,
49 monitored_object_identifier,
50 issue_confirmed_notifications: confirmed,
51 lifetime,
52 }
53 }
54
55 pub(super) async fn send_subscribe_cov_request(
56 &self,
57 target: ConfirmedTarget<'_>,
58 request: SubscribeCOVRequest,
59 ) -> Result<(), Error> {
60 let mut buf = BytesMut::new();
61 request.encode(&mut buf)?;
62
63 let _ = self
64 .confirmed_request_inner(target, ConfirmedServiceChoice::SUBSCRIBE_COV, &buf)
65 .await?;
66
67 Ok(())
68 }
69
70 fn subscribe_cov_property_request(
71 subscriber_process_identifier: u32,
72 monitored_object_identifier: ObjectIdentifier,
73 confirmed: Option<bool>,
74 lifetime: Option<u32>,
75 monitored_property_identifier: PropertyIdentifier,
76 monitored_property_array_index: Option<u32>,
77 cov_increment: Option<f32>,
78 ) -> SubscribeCOVPropertyRequest {
79 SubscribeCOVPropertyRequest {
80 subscriber_process_identifier,
81 monitored_object_identifier,
82 issue_confirmed_notifications: confirmed,
83 lifetime,
84 monitored_property_identifier,
85 monitored_property_array_index,
86 cov_increment,
87 }
88 }
89
90 pub(super) async fn send_subscribe_cov_property_request(
91 &self,
92 target: ConfirmedTarget<'_>,
93 request: SubscribeCOVPropertyRequest,
94 ) -> Result<(), Error> {
95 let mut buf = BytesMut::new();
96 request.encode(&mut buf)?;
97
98 let _ = self
99 .confirmed_request_inner(target, ConfirmedServiceChoice::SUBSCRIBE_COV_PROPERTY, &buf)
100 .await?;
101
102 Ok(())
103 }
104
105 pub async fn subscribe_cov(
107 &self,
108 destination_mac: &[u8],
109 subscriber_process_identifier: u32,
110 monitored_object_identifier: ObjectIdentifier,
111 confirmed: bool,
112 lifetime: Option<u32>,
113 ) -> Result<(), Error> {
114 let request = Self::subscribe_cov_request(
115 subscriber_process_identifier,
116 monitored_object_identifier,
117 Some(confirmed),
118 lifetime,
119 );
120
121 self.send_subscribe_cov_request(
122 ConfirmedTarget::Local {
123 mac: destination_mac,
124 },
125 request,
126 )
127 .await
128 }
129
130 pub async fn subscribe_cov_to_device(
132 &self,
133 device_instance: u32,
134 subscriber_process_identifier: u32,
135 monitored_object_identifier: ObjectIdentifier,
136 confirmed: bool,
137 lifetime: Option<u32>,
138 ) -> Result<(), Error> {
139 let request = Self::subscribe_cov_request(
140 subscriber_process_identifier,
141 monitored_object_identifier,
142 Some(confirmed),
143 lifetime,
144 );
145
146 request.validate()?;
147 let (mac, routing) = self.resolve_device(device_instance).await?;
148
149 if let Some((dnet, dadr)) = routing {
150 self.send_subscribe_cov_request(
151 ConfirmedTarget::Routed {
152 router_mac: &mac,
153 dest_network: dnet,
154 dest_mac: &dadr,
155 },
156 request,
157 )
158 .await
159 } else {
160 self.send_subscribe_cov_request(ConfirmedTarget::Local { mac: &mac }, request)
161 .await
162 }
163 }
164
165 pub async fn unsubscribe_cov(
167 &self,
168 destination_mac: &[u8],
169 subscriber_process_identifier: u32,
170 monitored_object_identifier: ObjectIdentifier,
171 ) -> Result<(), Error> {
172 let request = Self::subscribe_cov_request(
173 subscriber_process_identifier,
174 monitored_object_identifier,
175 None,
176 None,
177 );
178
179 self.send_subscribe_cov_request(
180 ConfirmedTarget::Local {
181 mac: destination_mac,
182 },
183 request,
184 )
185 .await
186 }
187
188 pub async fn unsubscribe_cov_to_device(
190 &self,
191 device_instance: u32,
192 subscriber_process_identifier: u32,
193 monitored_object_identifier: ObjectIdentifier,
194 ) -> Result<(), Error> {
195 let request = Self::subscribe_cov_request(
196 subscriber_process_identifier,
197 monitored_object_identifier,
198 None,
199 None,
200 );
201
202 request.validate()?;
203 let (mac, routing) = self.resolve_device(device_instance).await?;
204
205 if let Some((dnet, dadr)) = routing {
206 self.send_subscribe_cov_request(
207 ConfirmedTarget::Routed {
208 router_mac: &mac,
209 dest_network: dnet,
210 dest_mac: &dadr,
211 },
212 request,
213 )
214 .await
215 } else {
216 self.send_subscribe_cov_request(ConfirmedTarget::Local { mac: &mac }, request)
217 .await
218 }
219 }
220
221 pub async fn subscribe_cov_property(
224 &self,
225 destination_mac: &[u8],
226 subscription: CovPropertySubscription,
227 ) -> Result<(), Error> {
228 let request = subscription.into_request();
229
230 self.send_subscribe_cov_property_request(
231 ConfirmedTarget::Local {
232 mac: destination_mac,
233 },
234 request,
235 )
236 .await
237 }
238
239 pub async fn subscribe_cov_property_to_device(
242 &self,
243 device_instance: u32,
244 subscription: CovPropertySubscription,
245 ) -> Result<(), Error> {
246 let request = subscription.into_request();
247
248 request.validate()?;
249 let (mac, routing) = self.resolve_device(device_instance).await?;
250 if let Some((dnet, dadr)) = routing {
251 self.send_subscribe_cov_property_request(
252 ConfirmedTarget::Routed {
253 router_mac: &mac,
254 dest_network: dnet,
255 dest_mac: &dadr,
256 },
257 request,
258 )
259 .await
260 } else {
261 self.send_subscribe_cov_property_request(ConfirmedTarget::Local { mac: &mac }, request)
262 .await
263 }
264 }
265
266 pub async fn unsubscribe_cov_property(
268 &self,
269 destination_mac: &[u8],
270 subscriber_process_identifier: u32,
271 monitored_object_identifier: ObjectIdentifier,
272 monitored_property_identifier: PropertyIdentifier,
273 monitored_property_array_index: Option<u32>,
274 ) -> Result<(), Error> {
275 let request = Self::subscribe_cov_property_request(
276 subscriber_process_identifier,
277 monitored_object_identifier,
278 None,
279 None,
280 monitored_property_identifier,
281 monitored_property_array_index,
282 None,
283 );
284
285 self.send_subscribe_cov_property_request(
286 ConfirmedTarget::Local {
287 mac: destination_mac,
288 },
289 request,
290 )
291 .await
292 }
293
294 pub async fn unsubscribe_cov_property_to_device(
297 &self,
298 device_instance: u32,
299 subscriber_process_identifier: u32,
300 monitored_object_identifier: ObjectIdentifier,
301 monitored_property_identifier: PropertyIdentifier,
302 monitored_property_array_index: Option<u32>,
303 ) -> Result<(), Error> {
304 let request = Self::subscribe_cov_property_request(
305 subscriber_process_identifier,
306 monitored_object_identifier,
307 None,
308 None,
309 monitored_property_identifier,
310 monitored_property_array_index,
311 None,
312 );
313
314 request.validate()?;
315 let (mac, routing) = self.resolve_device(device_instance).await?;
316
317 if let Some((dnet, dadr)) = routing {
318 self.send_subscribe_cov_property_request(
319 ConfirmedTarget::Routed {
320 router_mac: &mac,
321 dest_network: dnet,
322 dest_mac: &dadr,
323 },
324 request,
325 )
326 .await
327 } else {
328 self.send_subscribe_cov_property_request(ConfirmedTarget::Local { mac: &mac }, request)
329 .await
330 }
331 }
332
333 pub async fn unsubscribe_cov_target(
339 &self,
340 target: &CovTarget,
341 subscriber_process_identifier: u32,
342 monitored_object_identifier: ObjectIdentifier,
343 ) -> Result<(), Error> {
344 let request = Self::subscribe_cov_request(
345 subscriber_process_identifier,
346 monitored_object_identifier,
347 None,
348 None,
349 );
350 self.send_subscribe_cov_request(target.confirmed(), request)
351 .await
352 }
353
354 pub async fn unsubscribe_cov_property_target(
358 &self,
359 target: &CovTarget,
360 subscriber_process_identifier: u32,
361 monitored_object_identifier: ObjectIdentifier,
362 monitored_property_identifier: PropertyIdentifier,
363 monitored_property_array_index: Option<u32>,
364 ) -> Result<(), Error> {
365 let request = Self::subscribe_cov_property_request(
366 subscriber_process_identifier,
367 monitored_object_identifier,
368 None,
369 None,
370 monitored_property_identifier,
371 monitored_property_array_index,
372 None,
373 );
374 self.send_subscribe_cov_property_request(target.confirmed(), request)
375 .await
376 }
377
378 pub fn cov_notifications(&self) -> broadcast::Receiver<ReceivedCOVNotification> {
381 self.cov_tx.subscribe()
382 }
383}
384
385#[cfg(test)]
386#[path = "cov_property_validation_tests.rs"]
387mod property_validation_tests;
388
389#[cfg(test)]
390#[path = "cov_request_validation_tests.rs"]
391mod request_validation_tests;