Skip to main content

rustbac_core/services/
event_information.rs

1use crate::apdu::ConfirmedRequestHeader;
2use crate::encoding::{primitives::encode_ctx_object_id, writer::Writer};
3use crate::types::ObjectId;
4use crate::EncodeError;
5
6#[cfg(feature = "alloc")]
7use crate::encoding::{
8    primitives::decode_unsigned,
9    reader::Reader,
10    tag::{AppTag, Tag},
11};
12#[cfg(feature = "alloc")]
13use crate::types::BitString;
14#[cfg(feature = "alloc")]
15use crate::DecodeError;
16#[cfg(feature = "alloc")]
17use alloc::vec::Vec;
18
19pub const SERVICE_GET_EVENT_INFORMATION: u8 = 0x1D;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct GetEventInformationRequest {
23    pub last_received_object_id: Option<ObjectId>,
24    pub invoke_id: u8,
25}
26
27impl GetEventInformationRequest {
28    pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
29        ConfirmedRequestHeader {
30            segmented: false,
31            more_follows: false,
32            segmented_response_accepted: true,
33            max_segments: 0,
34            max_apdu: 5,
35            invoke_id: self.invoke_id,
36            sequence_number: None,
37            proposed_window_size: None,
38            service_choice: SERVICE_GET_EVENT_INFORMATION,
39        }
40        .encode(w)?;
41
42        if let Some(object_id) = self.last_received_object_id {
43            encode_ctx_object_id(w, 0, object_id.raw())?;
44        }
45        Ok(())
46    }
47}
48
49#[cfg(feature = "alloc")]
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub struct EventSummaryItem<'a> {
52    pub object_id: ObjectId,
53    pub event_state: u32,
54    pub acknowledged_transitions: BitString<'a>,
55    pub notify_type: u32,
56    pub event_enable: BitString<'a>,
57    pub event_priorities: [u32; 3],
58}
59
60#[cfg(feature = "alloc")]
61#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct GetEventInformationAck<'a> {
63    pub summaries: Vec<EventSummaryItem<'a>>,
64    pub more_events: bool,
65}
66
67#[cfg(feature = "alloc")]
68impl<'a> GetEventInformationAck<'a> {
69    pub fn decode_after_header(r: &mut Reader<'a>) -> Result<Self, DecodeError> {
70        if Tag::decode(r)? != (Tag::Opening { tag_num: 0 }) {
71            return Err(DecodeError::InvalidTag);
72        }
73
74        let mut summaries = Vec::new();
75        loop {
76            let tag = Tag::decode(r)?;
77            if tag == (Tag::Closing { tag_num: 0 }) {
78                break;
79            }
80            let object_id = decode_object_id_from_tag(r, tag)?;
81            let event_state = decode_expected_context_unsigned(r, 1)?;
82            let acknowledged_transitions = decode_expected_context_bit_string(r, 2)?;
83
84            match Tag::decode(r)? {
85                Tag::Opening { tag_num: 3 } => skip_constructed(r, 3)?,
86                _ => return Err(DecodeError::InvalidTag),
87            }
88
89            let notify_type = decode_expected_context_unsigned(r, 4)?;
90            let event_enable = decode_expected_context_bit_string(r, 5)?;
91
92            match Tag::decode(r)? {
93                Tag::Opening { tag_num: 6 } => {}
94                _ => return Err(DecodeError::InvalidTag),
95            }
96            let mut priorities = [0u32; 3];
97            for slot in &mut priorities {
98                let priority_tag = Tag::decode(r)?;
99                *slot = decode_unsigned_from_tag(r, priority_tag)?;
100            }
101            if Tag::decode(r)? != (Tag::Closing { tag_num: 6 }) {
102                return Err(DecodeError::InvalidTag);
103            }
104
105            summaries.push(EventSummaryItem {
106                object_id,
107                event_state,
108                acknowledged_transitions,
109                notify_type,
110                event_enable,
111                event_priorities: priorities,
112            });
113        }
114
115        let more_events = match Tag::decode(r)? {
116            Tag::Context { tag_num: 1, len: 0 } => true,
117            Tag::Context { tag_num: 1, len } => decode_unsigned(r, len as usize)? != 0,
118            _ => return Err(DecodeError::InvalidTag),
119        };
120
121        Ok(Self {
122            summaries,
123            more_events,
124        })
125    }
126}
127
128#[cfg(feature = "alloc")]
129fn decode_object_id_from_tag(r: &mut Reader<'_>, tag: Tag) -> Result<ObjectId, DecodeError> {
130    match tag {
131        Tag::Context { tag_num: 0, len } => {
132            if len != 4 {
133                return Err(DecodeError::InvalidLength);
134            }
135            Ok(ObjectId::from_raw(decode_unsigned(r, len as usize)?))
136        }
137        _ => Err(DecodeError::InvalidTag),
138    }
139}
140
141#[cfg(feature = "alloc")]
142fn decode_expected_context_unsigned(r: &mut Reader<'_>, tag_num: u8) -> Result<u32, DecodeError> {
143    match Tag::decode(r)? {
144        Tag::Context {
145            tag_num: found,
146            len,
147        } if found == tag_num => decode_unsigned(r, len as usize),
148        _ => Err(DecodeError::InvalidTag),
149    }
150}
151
152#[cfg(feature = "alloc")]
153fn decode_unsigned_from_tag(r: &mut Reader<'_>, tag: Tag) -> Result<u32, DecodeError> {
154    match tag {
155        Tag::Application {
156            tag: AppTag::UnsignedInt,
157            len,
158        } => decode_unsigned(r, len as usize),
159        Tag::Context { len, .. } => decode_unsigned(r, len as usize),
160        _ => Err(DecodeError::InvalidTag),
161    }
162}
163
164#[cfg(feature = "alloc")]
165fn decode_expected_context_bit_string<'a>(
166    r: &mut Reader<'a>,
167    tag_num: u8,
168) -> Result<BitString<'a>, DecodeError> {
169    match Tag::decode(r)? {
170        Tag::Context {
171            tag_num: found,
172            len,
173        } if found == tag_num => {
174            if len == 0 {
175                return Err(DecodeError::InvalidLength);
176            }
177            let raw = r.read_exact(len as usize)?;
178            if raw[0] > 7 {
179                return Err(DecodeError::InvalidValue);
180            }
181            Ok(BitString {
182                unused_bits: raw[0],
183                data: &raw[1..],
184            })
185        }
186        _ => Err(DecodeError::InvalidTag),
187    }
188}
189
190#[cfg(feature = "alloc")]
191fn skip_constructed(r: &mut Reader<'_>, tag_num: u8) -> Result<(), DecodeError> {
192    loop {
193        let tag = Tag::decode(r)?;
194        match tag {
195            Tag::Closing { tag_num: closing } if closing == tag_num => return Ok(()),
196            Tag::Opening { tag_num: nested } => skip_constructed(r, nested)?,
197            Tag::Application { len, .. } | Tag::Context { len, .. } => {
198                r.read_exact(len as usize)?;
199            }
200            Tag::Closing { .. } => return Err(DecodeError::InvalidTag),
201        }
202    }
203}
204
205#[cfg(test)]
206mod tests {
207    #[cfg(feature = "alloc")]
208    use super::GetEventInformationAck;
209    use super::{GetEventInformationRequest, SERVICE_GET_EVENT_INFORMATION};
210    #[cfg(feature = "alloc")]
211    use crate::apdu::ComplexAckHeader;
212    use crate::apdu::ConfirmedRequestHeader;
213    #[cfg(feature = "alloc")]
214    use crate::encoding::primitives::{encode_ctx_object_id, encode_ctx_unsigned};
215    #[cfg(feature = "alloc")]
216    use crate::encoding::tag::Tag;
217    use crate::encoding::{reader::Reader, writer::Writer};
218    #[cfg(feature = "alloc")]
219    use crate::types::{ObjectId, ObjectType};
220
221    #[test]
222    fn encode_get_event_information_request() {
223        let req = GetEventInformationRequest {
224            last_received_object_id: None,
225            invoke_id: 9,
226        };
227        let mut buf = [0u8; 32];
228        let mut w = Writer::new(&mut buf);
229        req.encode(&mut w).unwrap();
230
231        let mut r = Reader::new(w.as_written());
232        let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
233        assert_eq!(hdr.service_choice, SERVICE_GET_EVENT_INFORMATION);
234    }
235
236    #[cfg(feature = "alloc")]
237    #[test]
238    fn decode_get_event_information_ack() {
239        let mut buf = [0u8; 256];
240        let mut w = Writer::new(&mut buf);
241        ComplexAckHeader {
242            segmented: false,
243            more_follows: false,
244            invoke_id: 9,
245            sequence_number: None,
246            proposed_window_size: None,
247            service_choice: SERVICE_GET_EVENT_INFORMATION,
248        }
249        .encode(&mut w)
250        .unwrap();
251        Tag::Opening { tag_num: 0 }.encode(&mut w).unwrap();
252        encode_ctx_object_id(&mut w, 0, ObjectId::new(ObjectType::AnalogInput, 1).raw()).unwrap();
253        encode_ctx_unsigned(&mut w, 1, 2).unwrap();
254        Tag::Context { tag_num: 2, len: 2 }.encode(&mut w).unwrap();
255        w.write_u8(5).unwrap();
256        w.write_u8(0b1110_0000).unwrap();
257        Tag::Opening { tag_num: 3 }.encode(&mut w).unwrap();
258        Tag::Opening { tag_num: 0 }.encode(&mut w).unwrap();
259        encode_ctx_unsigned(&mut w, 1, 42).unwrap();
260        Tag::Closing { tag_num: 0 }.encode(&mut w).unwrap();
261        Tag::Closing { tag_num: 3 }.encode(&mut w).unwrap();
262        encode_ctx_unsigned(&mut w, 4, 0).unwrap();
263        Tag::Context { tag_num: 5, len: 2 }.encode(&mut w).unwrap();
264        w.write_u8(5).unwrap();
265        w.write_u8(0b1110_0000).unwrap();
266        Tag::Opening { tag_num: 6 }.encode(&mut w).unwrap();
267        encode_ctx_unsigned(&mut w, 0, 1).unwrap();
268        encode_ctx_unsigned(&mut w, 1, 2).unwrap();
269        encode_ctx_unsigned(&mut w, 2, 3).unwrap();
270        Tag::Closing { tag_num: 6 }.encode(&mut w).unwrap();
271        Tag::Closing { tag_num: 0 }.encode(&mut w).unwrap();
272        Tag::Context { tag_num: 1, len: 1 }.encode(&mut w).unwrap();
273        w.write_u8(0).unwrap();
274
275        let mut r = Reader::new(w.as_written());
276        let _ack_hdr = ComplexAckHeader::decode(&mut r).unwrap();
277        let ack = GetEventInformationAck::decode_after_header(&mut r).unwrap();
278        assert_eq!(ack.summaries.len(), 1);
279        assert!(!ack.more_events);
280    }
281}