Skip to main content

bacnet_client/client/
device_mgmt.rs

1use super::*;
2
3impl<T: TransportPort + 'static> BACnetClient<T> {
4    /// Send DeviceCommunicationControl to a remote device.
5    pub async fn device_communication_control(
6        &self,
7        destination_mac: &[u8],
8        enable_disable: bacnet_types::enums::EnableDisable,
9        time_duration: Option<u16>,
10        password: Option<String>,
11    ) -> Result<(), Error> {
12        use bacnet_services::device_mgmt::DeviceCommunicationControlRequest;
13
14        let request = DeviceCommunicationControlRequest {
15            time_duration,
16            enable_disable,
17            password,
18        };
19        let mut buf = BytesMut::new();
20        request.encode(&mut buf)?;
21
22        let _ = self
23            .confirmed_request(
24                destination_mac,
25                ConfirmedServiceChoice::DEVICE_COMMUNICATION_CONTROL,
26                &buf,
27            )
28            .await?;
29
30        Ok(())
31    }
32
33    /// Send ReinitializeDevice to a remote device.
34    pub async fn reinitialize_device(
35        &self,
36        destination_mac: &[u8],
37        reinitialized_state: bacnet_types::enums::ReinitializedState,
38        password: Option<String>,
39    ) -> Result<(), Error> {
40        use bacnet_services::device_mgmt::ReinitializeDeviceRequest;
41
42        let request = ReinitializeDeviceRequest {
43            reinitialized_state,
44            password,
45        };
46        let mut buf = BytesMut::new();
47        request.encode(&mut buf)?;
48
49        let _ = self
50            .confirmed_request(
51                destination_mac,
52                ConfirmedServiceChoice::REINITIALIZE_DEVICE,
53                &buf,
54            )
55            .await?;
56
57        Ok(())
58    }
59    /// Send a TimeSynchronization request (unconfirmed, no response expected).
60    pub async fn time_synchronization(
61        &self,
62        destination_mac: &[u8],
63        date: bacnet_types::primitives::Date,
64        time: bacnet_types::primitives::Time,
65    ) -> Result<(), Error> {
66        use bacnet_services::device_mgmt::TimeSynchronizationRequest;
67
68        let request = TimeSynchronizationRequest { date, time };
69        let mut buf = BytesMut::new();
70        request.encode(&mut buf);
71
72        self.unconfirmed_request(
73            destination_mac,
74            UnconfirmedServiceChoice::TIME_SYNCHRONIZATION,
75            &buf,
76        )
77        .await
78    }
79
80    /// Send a UTCTimeSynchronization request (unconfirmed, no response expected).
81    pub async fn utc_time_synchronization(
82        &self,
83        destination_mac: &[u8],
84        date: bacnet_types::primitives::Date,
85        time: bacnet_types::primitives::Time,
86    ) -> Result<(), Error> {
87        use bacnet_services::device_mgmt::TimeSynchronizationRequest;
88
89        let request = TimeSynchronizationRequest { date, time };
90        let mut buf = BytesMut::new();
91        request.encode(&mut buf);
92
93        self.unconfirmed_request(
94            destination_mac,
95            UnconfirmedServiceChoice::UTC_TIME_SYNCHRONIZATION,
96            &buf,
97        )
98        .await
99    }
100    /// Send DeviceCommunicationControl to a discovered device, routing when needed.
101    ///
102    /// Preserves the request fields and confirmation semantics of [`Self::device_communication_control`].
103    /// A missing device fails before sending.
104    pub async fn device_communication_control_from_device(
105        &self,
106        device_instance: u32,
107        enable_disable: bacnet_types::enums::EnableDisable,
108        time_duration: Option<u16>,
109        password: Option<String>,
110    ) -> Result<(), Error> {
111        let (mac, routing) = self.resolve_device(device_instance).await?;
112        if let Some((network, address)) = routing {
113            let request = bacnet_services::device_mgmt::DeviceCommunicationControlRequest {
114                time_duration,
115                enable_disable,
116                password,
117            };
118            let mut buf = BytesMut::new();
119            request.encode(&mut buf)?;
120            self.confirmed_request_routed(
121                &mac,
122                network,
123                &address,
124                ConfirmedServiceChoice::DEVICE_COMMUNICATION_CONTROL,
125                &buf,
126            )
127            .await?;
128            Ok(())
129        } else {
130            self.device_communication_control(&mac, enable_disable, time_duration, password)
131                .await
132        }
133    }
134
135    /// Send ReinitializeDevice to a discovered device, routing when needed.
136    ///
137    /// Preserves the request fields and confirmation semantics of [`Self::reinitialize_device`].
138    /// A missing device fails before sending.
139    pub async fn reinitialize_device_from_device(
140        &self,
141        device_instance: u32,
142        reinitialized_state: bacnet_types::enums::ReinitializedState,
143        password: Option<String>,
144    ) -> Result<(), Error> {
145        let (mac, routing) = self.resolve_device(device_instance).await?;
146        if let Some((network, address)) = routing {
147            let request = bacnet_services::device_mgmt::ReinitializeDeviceRequest {
148                reinitialized_state,
149                password,
150            };
151            let mut buf = BytesMut::new();
152            request.encode(&mut buf)?;
153            self.confirmed_request_routed(
154                &mac,
155                network,
156                &address,
157                ConfirmedServiceChoice::REINITIALIZE_DEVICE,
158                &buf,
159            )
160            .await?;
161            Ok(())
162        } else {
163            self.reinitialize_device(&mac, reinitialized_state, password)
164                .await
165        }
166    }
167
168    /// Send local time synchronization to a discovered device, routing when needed.
169    ///
170    /// This unconfirmed service sends once without waiting for a response.
171    /// Success means local send completion, not acceptance by the remote clock.
172    pub async fn time_synchronization_from_device(
173        &self,
174        device_instance: u32,
175        date: bacnet_types::primitives::Date,
176        time: bacnet_types::primitives::Time,
177    ) -> Result<(), Error> {
178        self.time_synchronization_to_device(
179            device_instance,
180            date,
181            time,
182            UnconfirmedServiceChoice::TIME_SYNCHRONIZATION,
183        )
184        .await
185    }
186
187    /// Send UTC time synchronization to a discovered device, routing when needed.
188    ///
189    /// This unconfirmed service sends once without waiting for a response.
190    /// Success means local send completion, not acceptance by the remote clock.
191    pub async fn utc_time_synchronization_from_device(
192        &self,
193        device_instance: u32,
194        date: bacnet_types::primitives::Date,
195        time: bacnet_types::primitives::Time,
196    ) -> Result<(), Error> {
197        self.time_synchronization_to_device(
198            device_instance,
199            date,
200            time,
201            UnconfirmedServiceChoice::UTC_TIME_SYNCHRONIZATION,
202        )
203        .await
204    }
205
206    async fn time_synchronization_to_device(
207        &self,
208        device_instance: u32,
209        date: bacnet_types::primitives::Date,
210        time: bacnet_types::primitives::Time,
211        service_choice: UnconfirmedServiceChoice,
212    ) -> Result<(), Error> {
213        let (mac, routing) = self.resolve_device(device_instance).await?;
214        let request = bacnet_services::device_mgmt::TimeSynchronizationRequest { date, time };
215        let mut data = BytesMut::new();
216        request.encode(&mut data);
217        let Some((network, address)) = routing else {
218            return self.unconfirmed_request(&mac, service_choice, &data).await;
219        };
220        check_routed_unicast(network, address.len())?;
221        if self.network.local_network_number().get() == Some(network) {
222            if self.network.transport().is_group_destination(&address) {
223                return Err(Error::Encoding(
224                    "routed time synchronization requires a unicast station".into(),
225                ));
226            }
227            return self
228                .unconfirmed_request(&address, service_choice, &data)
229                .await;
230        }
231        let apdu = Apdu::UnconfirmedRequest(bacnet_encoding::apdu::UnconfirmedRequest {
232            service_choice,
233            service_request: data.freeze(),
234        });
235        let mut buf = BytesMut::new();
236        encode_apdu(&mut buf, &apdu)?;
237        self.network
238            .send_apdu_routed(
239                &buf,
240                network,
241                &address,
242                &mac,
243                false,
244                NetworkPriority::Normal,
245            )
246            .await
247    }
248}
249
250#[cfg(test)]
251#[path = "device_mgmt_tests.rs"]
252mod tests;