Skip to main content

rustbac_core/services/
read_property.rs

1use 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}