rustbac_core/services/
read_property.rs1use crate::apdu::ConfirmedRequestHeader;
2use crate::encoding::{
3 primitives::{decode_unsigned, encode_ctx_object_id, encode_ctx_unsigned},
4 reader::Reader,
5 tag::Tag,
6 writer::Writer,
7};
8use crate::services::value_codec::decode_application_data_value;
9use crate::types::{DataValue, ObjectId, PropertyId};
10use crate::{DecodeError, EncodeError};
11
12pub const SERVICE_READ_PROPERTY: u8 = 0x0C;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct ReadPropertyRequest {
16 pub object_id: ObjectId,
17 pub property_id: PropertyId,
18 pub array_index: Option<u32>,
19 pub invoke_id: u8,
20}
21
22impl ReadPropertyRequest {
23 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
24 ConfirmedRequestHeader {
25 segmented: false,
26 more_follows: false,
27 segmented_response_accepted: true,
28 max_segments: 0,
29 max_apdu: 5,
30 invoke_id: self.invoke_id,
31 sequence_number: None,
32 proposed_window_size: None,
33 service_choice: SERVICE_READ_PROPERTY,
34 }
35 .encode(w)?;
36
37 encode_ctx_object_id(w, 0, self.object_id.raw())?;
38 encode_ctx_unsigned(w, 1, self.property_id.to_u32())?;
39 if let Some(idx) = self.array_index {
40 encode_ctx_unsigned(w, 2, idx)?;
41 }
42 Ok(())
43 }
44}
45
46#[derive(Debug, Clone, PartialEq)]
47pub struct ReadPropertyAck<'a> {
48 pub object_id: ObjectId,
49 pub property_id: PropertyId,
50 pub array_index: Option<u32>,
51 pub value: DataValue<'a>,
52}
53
54impl<'a> ReadPropertyAck<'a> {
55 pub fn decode_after_header(r: &mut Reader<'a>) -> Result<Self, DecodeError> {
56 let object_id = match Tag::decode(r)? {
57 Tag::Context { tag_num: 0, len } => {
58 ObjectId::from_raw(decode_unsigned(r, len as usize)?)
59 }
60 _ => return Err(DecodeError::InvalidTag),
61 };
62
63 let property_id = match Tag::decode(r)? {
64 Tag::Context { tag_num: 1, len } => {
65 PropertyId::from_u32(decode_unsigned(r, len as usize)?)
66 }
67 _ => return Err(DecodeError::InvalidTag),
68 };
69
70 let next = Tag::decode(r)?;
71 let (array_index, value_start_tag) = match next {
72 Tag::Context { tag_num: 2, len } => {
73 let idx = decode_unsigned(r, len as usize)?;
74 (Some(idx), Tag::decode(r)?)
75 }
76 other => (None, other),
77 };
78
79 if value_start_tag != (Tag::Opening { tag_num: 3 }) {
80 return Err(DecodeError::InvalidTag);
81 }
82
83 let value = decode_application_data_value(r)?;
84
85 match Tag::decode(r)? {
86 Tag::Closing { tag_num: 3 } => {}
87 _ => return Err(DecodeError::InvalidTag),
88 }
89
90 Ok(Self {
91 object_id,
92 property_id,
93 array_index,
94 value,
95 })
96 }
97}