1#[cfg(not(feature = "std"))]
18use alloc::{string::String, vec::Vec};
19
20use crate::object::{ObjectIdentifier, ObjectType, PropertyIdentifier, PropertyValue, Result};
21
22#[derive(Clone)]
27pub struct ObjectFunctions {
28 pub object_type: ObjectType,
30
31 pub count: fn() -> usize,
33
34 pub index_to_instance: fn(usize) -> Option<u32>,
36
37 pub valid_instance: fn(u32) -> bool,
39
40 pub object_name: fn(u32) -> Option<String>,
42
43 pub read_property: fn(u32, PropertyIdentifier) -> Result<PropertyValue>,
45
46 pub write_property: fn(u32, PropertyIdentifier, PropertyValue) -> Result<()>,
48
49 pub is_property_writable: fn(u32, PropertyIdentifier) -> bool,
51
52 pub property_list: fn(u32) -> Vec<PropertyIdentifier>,
54}
55
56impl core::fmt::Debug for ObjectFunctions {
57 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
58 f.debug_struct("ObjectFunctions")
59 .field("object_type", &self.object_type)
60 .field("count", &"fn()")
61 .field("index_to_instance", &"fn(usize) -> Option<u32>")
62 .field("valid_instance", &"fn(u32) -> bool")
63 .field("object_name", &"fn(u32) -> Option<String>")
64 .field(
65 "read_property",
66 &"fn(u32, PropertyIdentifier) -> Result<PropertyValue>",
67 )
68 .field(
69 "write_property",
70 &"fn(u32, PropertyIdentifier, PropertyValue) -> Result<()>",
71 )
72 .field(
73 "is_property_writable",
74 &"fn(u32, PropertyIdentifier) -> bool",
75 )
76 .field("property_list", &"fn(u32) -> Vec<PropertyIdentifier>")
77 .finish()
78 }
79}
80
81#[derive(Debug, Clone)]
86pub struct DeviceObject {
87 object_table: Vec<ObjectFunctions>,
89
90 device_instance: u32,
92
93 device_identifier: String,
95
96 device_name: String,
98
99 device_description: String,
101
102 vendor_identifier: u16,
104
105 vendor_name: String,
107
108 model_name: String,
110
111 firmware_revision: String,
113
114 application_software_version: String,
116
117 protocol_version: u8,
119
120 protocol_revision: u8,
122}
123
124impl DeviceObject {
125 pub fn new(device_instance: u32, device_name: String) -> Self {
138 Self {
139 object_table: Vec::new(),
140 device_instance,
141 device_identifier: format!("Device-{}", device_instance),
142 device_name,
143 device_description: String::new(),
144 vendor_identifier: 0,
145 vendor_name: String::from("Unknown"),
146 model_name: String::from("BACnet-RS Device"),
147 firmware_revision: String::from("1.0"),
148 application_software_version: String::from("1.0"),
149 protocol_version: 1,
150 protocol_revision: 30, }
152 }
153
154 pub fn find_object_functions(&self, object_type: ObjectType) -> Option<&ObjectFunctions> {
170 self.object_table
171 .iter()
172 .find(|f| f.object_type == object_type)
173 }
174
175 pub fn object_functions(&self) -> &[ObjectFunctions] {
190 &self.object_table
191 }
192
193 pub fn register_object_functions(&mut self, functions: ObjectFunctions) {
219 self.object_table
221 .retain(|f| f.object_type != functions.object_type);
222 self.object_table.push(functions);
224 }
225
226 pub fn device_instance(&self) -> u32 {
228 self.device_instance
229 }
230
231 pub fn device_name(&self) -> &str {
233 &self.device_name
234 }
235
236 pub fn device_identifier(&self) -> &str {
238 &self.device_identifier
239 }
240
241 pub fn application_software_version(&self) -> &str {
243 &self.application_software_version
244 }
245
246 pub fn protocol_version(&self) -> u8 {
248 self.protocol_version
249 }
250
251 pub fn protocol_revision(&self) -> u8 {
253 self.protocol_revision
254 }
255
256 pub fn set_device_description(&mut self, description: String) {
258 self.device_description = description;
259 }
260
261 pub fn set_vendor_info(&mut self, vendor_id: u16, vendor_name: String) {
263 self.vendor_identifier = vendor_id;
264 self.vendor_name = vendor_name;
265 }
266
267 pub fn set_model_info(&mut self, model_name: String, firmware_revision: String) {
269 self.model_name = model_name;
270 self.firmware_revision = firmware_revision;
271 }
272
273 pub fn read_object_property(
284 &self,
285 object_id: ObjectIdentifier,
286 property: PropertyIdentifier,
287 ) -> Result<PropertyValue> {
288 if let Some(funcs) = self.find_object_functions(object_id.object_type) {
290 if !(funcs.valid_instance)(object_id.instance) {
292 return Err(crate::object::ObjectError::InstanceNotFound);
293 }
294 (funcs.read_property)(object_id.instance, property)
296 } else {
297 Err(crate::object::ObjectError::TypeNotSupported)
298 }
299 }
300
301 pub fn write_object_property(
313 &self,
314 object_id: ObjectIdentifier,
315 property: PropertyIdentifier,
316 value: PropertyValue,
317 ) -> Result<()> {
318 if let Some(funcs) = self.find_object_functions(object_id.object_type) {
320 if !(funcs.valid_instance)(object_id.instance) {
322 return Err(crate::object::ObjectError::InstanceNotFound);
323 }
324 if !(funcs.is_property_writable)(object_id.instance, property) {
326 return Err(crate::object::ObjectError::PropertyNotWritable);
327 }
328 (funcs.write_property)(object_id.instance, property, value)
330 } else {
331 Err(crate::object::ObjectError::TypeNotSupported)
332 }
333 }
334
335 pub fn total_object_count(&self) -> usize {
337 self.object_table.iter().map(|funcs| (funcs.count)()).sum()
338 }
339}
340
341#[cfg(test)]
342mod tests {
343 use super::*;
344
345 fn mock_count() -> usize {
347 2
348 }
349
350 fn mock_index_to_instance(index: usize) -> Option<u32> {
351 match index {
352 0 => Some(1),
353 1 => Some(2),
354 _ => None,
355 }
356 }
357
358 fn mock_valid_instance(instance: u32) -> bool {
359 instance == 1 || instance == 2
360 }
361
362 fn mock_object_name(instance: u32) -> Option<String> {
363 if mock_valid_instance(instance) {
364 Some(format!("Test Object {}", instance))
365 } else {
366 None
367 }
368 }
369
370 fn mock_read_property(_instance: u32, property: PropertyIdentifier) -> Result<PropertyValue> {
371 match property {
372 PropertyIdentifier::PresentValue => Ok(PropertyValue::Real(42.0)),
373 _ => Err(crate::object::ObjectError::UnknownProperty),
374 }
375 }
376
377 fn mock_write_property(
378 _instance: u32,
379 _property: PropertyIdentifier,
380 _value: PropertyValue,
381 ) -> Result<()> {
382 Ok(())
383 }
384
385 fn mock_is_writable(_instance: u32, property: PropertyIdentifier) -> bool {
386 property == PropertyIdentifier::PresentValue
387 }
388
389 fn mock_property_list(_instance: u32) -> Vec<PropertyIdentifier> {
390 vec![PropertyIdentifier::PresentValue]
391 }
392
393 #[test]
394 fn test_device_object_creation() {
395 let device = DeviceObject::new(123, "Test Device".to_string());
396 assert_eq!(device.device_instance(), 123);
397 assert_eq!(device.device_name(), "Test Device");
398 assert_eq!(device.total_object_count(), 0);
399 }
400
401 #[test]
402 fn test_register_object_functions() {
403 let mut device = DeviceObject::new(123, "Test Device".to_string());
404
405 let functions = ObjectFunctions {
406 object_type: ObjectType::AnalogInput,
407 count: mock_count,
408 index_to_instance: mock_index_to_instance,
409 valid_instance: mock_valid_instance,
410 object_name: mock_object_name,
411 read_property: mock_read_property,
412 write_property: mock_write_property,
413 is_property_writable: mock_is_writable,
414 property_list: mock_property_list,
415 };
416
417 device.register_object_functions(functions);
418
419 assert_eq!(device.total_object_count(), 2);
420 assert!(device
421 .find_object_functions(ObjectType::AnalogInput)
422 .is_some());
423 }
424
425 #[test]
426 fn test_find_object_functions() {
427 let mut device = DeviceObject::new(123, "Test Device".to_string());
428
429 let functions = ObjectFunctions {
430 object_type: ObjectType::AnalogInput,
431 count: mock_count,
432 index_to_instance: mock_index_to_instance,
433 valid_instance: mock_valid_instance,
434 object_name: mock_object_name,
435 read_property: mock_read_property,
436 write_property: mock_write_property,
437 is_property_writable: mock_is_writable,
438 property_list: mock_property_list,
439 };
440
441 device.register_object_functions(functions);
442
443 assert!(device
445 .find_object_functions(ObjectType::AnalogInput)
446 .is_some());
447
448 assert!(device
450 .find_object_functions(ObjectType::AnalogOutput)
451 .is_none());
452 }
453
454 #[test]
455 fn test_read_object_property() {
456 let mut device = DeviceObject::new(123, "Test Device".to_string());
457
458 let functions = ObjectFunctions {
459 object_type: ObjectType::AnalogInput,
460 count: mock_count,
461 index_to_instance: mock_index_to_instance,
462 valid_instance: mock_valid_instance,
463 object_name: mock_object_name,
464 read_property: mock_read_property,
465 write_property: mock_write_property,
466 is_property_writable: mock_is_writable,
467 property_list: mock_property_list,
468 };
469
470 device.register_object_functions(functions);
471
472 let object_id = ObjectIdentifier::new(ObjectType::AnalogInput, 1);
473 let result = device.read_object_property(object_id, PropertyIdentifier::PresentValue);
474
475 assert!(result.is_ok());
476 if let Ok(PropertyValue::Real(val)) = result {
477 assert_eq!(val, 42.0);
478 } else {
479 panic!("Expected Real property value");
480 }
481 }
482}