1use bacnet_types::enums::{NetworkType, ObjectType, PropertyIdentifier, Reliability};
18use bacnet_types::error::Error;
19use bacnet_types::primitives::{ObjectIdentifier, PropertyValue, StatusFlags};
20use bacnet_types::MacAddr;
21use std::borrow::Cow;
22
23use crate::common::{self, read_common_properties};
24use crate::traits::BACnetObject;
25
26mod bip6_config;
27mod bip_config;
28mod bip_mode;
29mod ip_config;
30mod metadata;
31mod multicast;
32mod pending;
33mod registration;
34use bacnet_types::network_number::NetworkNumber;
35pub(crate) use bip6_config::Bip6Bind;
36pub use bip6_config::Bip6PortConfig;
37pub use bip_config::BipPortConfig;
38use ip_config::IpConfig;
39pub(crate) use ip_config::{PortAddress, PortBind};
40
41pub struct NetworkPortObject {
43 oid: ObjectIdentifier,
44 name: String,
45 description: String,
46 status_flags: StatusFlags,
47 out_of_service: bool,
48 reliability: Reliability,
49 network_type: NetworkType,
50 network_number: NetworkNumber,
51 mac_address: MacAddr,
52 apdu_length: u32,
53 ip: Option<IpConfig>,
55 mode: bip_mode::LiveMode,
59 pending: pending::Pending,
61 activation: bool,
64 multicast: multicast::Multicast,
66 binding: std::sync::Weak<()>,
67}
68
69impl NetworkPortObject {
70 pub fn new_bip(
74 instance: u32,
75 name: impl Into<String>,
76 config: BipPortConfig,
77 ) -> Result<Self, Error> {
78 Self::new_ip(instance, name.into(), IpConfig::V4(config))
79 }
80
81 pub fn new_bip6(
86 instance: u32,
87 name: impl Into<String>,
88 config: Bip6PortConfig,
89 ) -> Result<Self, Error> {
90 Self::new_ip(instance, name.into(), IpConfig::V6(config))
91 }
92
93 fn new_ip(instance: u32, name: String, config: IpConfig) -> Result<Self, Error> {
94 config.validate(instance)?;
95 Ok(Self {
96 oid: ObjectIdentifier::new(ObjectType::NETWORK_PORT, instance)?,
97 name,
98 description: String::new(),
99 status_flags: StatusFlags::empty(),
100 out_of_service: false,
101 reliability: Reliability::NO_FAULT_DETECTED,
102 network_type: config.network_type(),
103 network_number: NetworkNumber::configured(config.network_number())
104 .expect("validated Network Number"),
105 mac_address: config.mac(),
106 apdu_length: config.apdu_length(),
107 ip: Some(config),
108 mode: Default::default(),
109 pending: Default::default(),
110 activation: false,
111 multicast: Default::default(),
112 binding: std::sync::Weak::new(),
113 })
114 }
115
116 pub fn new_non_bip(
121 instance: u32,
122 name: impl Into<String>,
123 network_type: NetworkType,
124 network_number: u16,
125 mac_address: MacAddr,
126 apdu_length: u32,
127 ) -> Result<Self, Error> {
128 if !matches!(network_type, NetworkType::ETHERNET | NetworkType::VIRTUAL)
129 || network_number == u16::MAX
130 || apdu_length < 50
131 {
132 return Err(common::value_out_of_range_error());
133 }
134 Ok(Self {
135 oid: ObjectIdentifier::new(ObjectType::NETWORK_PORT, instance)?,
136 name: name.into(),
137 description: String::new(),
138 status_flags: StatusFlags::empty(),
139 out_of_service: false,
140 reliability: Reliability::NO_FAULT_DETECTED,
141 network_type,
142 network_number: NetworkNumber::configured(network_number)
143 .expect("validated Network Number"),
144 mac_address,
145 apdu_length,
146 ip: None,
147 mode: Default::default(),
148 pending: Default::default(),
149 activation: false,
150 multicast: Default::default(),
151 binding: std::sync::Weak::new(),
152 })
153 }
154
155 pub fn set_description(&mut self, desc: impl Into<String>) {
157 self.description = desc.into();
158 }
159}
160
161impl BACnetObject for NetworkPortObject {
162 fn object_identifier(&self) -> ObjectIdentifier {
163 self.oid
164 }
165 fn object_name(&self) -> &str {
166 &self.name
167 }
168
169 fn read_property(
170 &self,
171 property: PropertyIdentifier,
172 array_index: Option<u32>,
173 ) -> Result<PropertyValue, Error> {
174 use PropertyIdentifier as P;
175 if let Some(result) = read_common_properties!(self, property, array_index) {
176 return result;
177 }
178 match property {
179 P::OBJECT_TYPE => Ok(PropertyValue::Enumerated(ObjectType::NETWORK_PORT.to_raw())),
180 P::NETWORK_TYPE => Ok(PropertyValue::Enumerated(self.network_type.to_raw())),
181 P::PROTOCOL_LEVEL => Ok(PropertyValue::Enumerated(2)),
182 P::NETWORK_NUMBER => Ok(PropertyValue::Unsigned(
183 self.network_number.snapshot().0.into(),
184 )),
185 P::NETWORK_NUMBER_QUALITY => Ok(PropertyValue::Enumerated(
186 self.network_number.snapshot().1.into(),
187 )),
188 P::MAC_ADDRESS => Ok(PropertyValue::OctetString(self.mac_address.to_vec())),
189 P::APDU_LENGTH => Ok(PropertyValue::Unsigned(self.apdu_length.into())),
190 P::LINK_SPEED => Ok(PropertyValue::Real(0.0)),
192 P::CHANGES_PENDING => Ok(PropertyValue::Boolean(self.changes_pending())),
193 _ => {
194 let config = self
195 .ip
196 .as_ref()
197 .ok_or_else(common::unknown_property_error)?;
198 if property == config.mode_property() {
199 return Ok(PropertyValue::Enumerated(self.mode.ip_mode().to_raw()));
200 }
201 if pending::nat_row(property) && !self.serves_nat() {
202 return Err(common::unknown_property_error());
203 }
204 if let Some(result) = self.read_multicast(property) {
205 return result;
206 }
207 config
208 .read(property, array_index)
209 .or_else(|| self.pending_value(property))
210 .or_else(|| self.mode.read(property))
211 .unwrap_or_else(|| Err(common::unknown_property_error()))
212 }
213 }
214 }
215
216 fn write_property(
217 &mut self,
218 property: PropertyIdentifier,
219 array_index: Option<u32>,
220 value: PropertyValue,
221 _priority: Option<u8>,
222 ) -> Result<(), Error> {
223 if property == PropertyIdentifier::OUT_OF_SERVICE && self.is_bound() {
224 return Err(common::write_access_denied_error());
225 }
226 if let Some(result) =
227 common::write_out_of_service(&mut self.out_of_service, property, &value)
228 {
229 return result;
230 }
231 if let Some(result) = common::write_description(&mut self.description, property, &value) {
232 return result;
233 }
234 if let Some(result) = self.write_pending(property, array_index, &value) {
235 return result;
236 }
237 if let Some(result) = self.write_multicast(property, array_index, &value) {
238 return result;
239 }
240 if self
243 .property_metadata()
244 .iter()
245 .any(|row| row.property_identifier == property)
246 {
247 Err(common::write_access_denied_error())
248 } else {
249 Err(common::unknown_property_error())
250 }
251 }
252
253 fn property_metadata(&self) -> Cow<'_, [crate::property_metadata::PropertyMetadata]> {
254 metadata::for_object(self)
255 }
256 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
257 crate::property_metadata::property_list_from_metadata(self.property_metadata().as_ref())
258 }
259 fn is_createable(&self) -> bool {
260 false
261 }
262 fn is_deleteable(&self) -> bool {
263 false
264 }
265}
266
267#[cfg(test)]
268mod bip6_tests;
269#[cfg(test)]
270mod foreign_pending_tests;
271#[cfg(test)]
272mod mode_tests;
273#[cfg(test)]
274mod multicast_tests;
275#[cfg(test)]
276mod nat_pending_tests;
277#[cfg(test)]
278mod pending_tests;
279#[cfg(test)]
280mod tests;