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