1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//! Sending WriteGroup requests (Clause 15.11).
//!
//! WriteGroup is unconfirmed, so it can go to one device or to many at once:
//! the local network, one remote network through its routers, or every
//! network. Each receiving device that has Channels in the request's control
//! group applies the change list to them itself; nothing comes back.
use super::*;
use bacnet_services::write_group::WriteGroupRequest;
/// Where [`BACnetClient::write_group`] sends a request.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WriteGroupDestination {
/// One device, by its address on the local network.
Device(MacAddr),
/// Every device on the local network.
LocalBroadcast,
/// Every device on one remote network (1 to 65534), through its router.
RemoteBroadcast(u16),
/// Every device on every network (DNET 65535).
GlobalBroadcast,
}
impl<T: TransportPort + 'static> BACnetClient<T> {
/// Send a WriteGroup request to `destination`.
///
/// The service is unconfirmed: this returns once the request is sent, and
/// no device answers it, so delivery isn't confirmed either. Fails before
/// anything is sent when `request` doesn't encode (see
/// [`WriteGroupRequest::encode`]) or a remote network number is 0 or
/// 65535; use [`WriteGroupDestination::GlobalBroadcast`] for every
/// network.
pub async fn write_group(
&self,
destination: &WriteGroupDestination,
request: &WriteGroupRequest,
) -> Result<(), Error> {
if let WriteGroupDestination::RemoteBroadcast(network) = destination
&& !(1..u16::MAX).contains(network)
{
return Err(Error::Encoding(format!(
"WriteGroup remote network {network} out of range 1-65534"
)));
}
let mut service = BytesMut::new();
request.encode(&mut service)?;
let choice = UnconfirmedServiceChoice::WRITE_GROUP;
match destination {
WriteGroupDestination::Device(mac) => {
self.unconfirmed_request(mac, choice, &service).await
}
WriteGroupDestination::LocalBroadcast => {
self.broadcast_unconfirmed(choice, &service).await
}
WriteGroupDestination::RemoteBroadcast(network) => {
self.broadcast_network_unconfirmed(choice, &service, *network)
.await
}
WriteGroupDestination::GlobalBroadcast => {
self.broadcast_global_unconfirmed(choice, &service).await
}
}
}
}
#[cfg(test)]
#[path = "write_group_tests.rs"]
mod tests;