rustbac_core/services/
list_element.rs1use crate::apdu::ConfirmedRequestHeader;
2use crate::encoding::{
3 primitives::{encode_ctx_object_id, encode_ctx_unsigned},
4 tag::Tag,
5 writer::Writer,
6};
7use crate::services::value_codec::encode_application_data_value;
8use crate::types::{DataValue, ObjectId, PropertyId};
9use crate::EncodeError;
10
11pub const SERVICE_ADD_LIST_ELEMENT: u8 = 0x08;
12pub const SERVICE_REMOVE_LIST_ELEMENT: u8 = 0x09;
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct AddListElementRequest<'a> {
16 pub object_id: ObjectId,
17 pub property_id: PropertyId,
18 pub array_index: Option<u32>,
19 pub elements: &'a [DataValue<'a>],
20 pub invoke_id: u8,
21}
22
23impl<'a> AddListElementRequest<'a> {
24 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
25 encode_list_element_request(w, self, SERVICE_ADD_LIST_ELEMENT)
26 }
27}
28
29#[derive(Debug, Clone, PartialEq)]
30pub struct RemoveListElementRequest<'a> {
31 pub object_id: ObjectId,
32 pub property_id: PropertyId,
33 pub array_index: Option<u32>,
34 pub elements: &'a [DataValue<'a>],
35 pub invoke_id: u8,
36}
37
38impl<'a> RemoveListElementRequest<'a> {
39 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
40 encode_list_element_request(
41 w,
42 &AddListElementRequest {
43 object_id: self.object_id,
44 property_id: self.property_id,
45 array_index: self.array_index,
46 elements: self.elements,
47 invoke_id: self.invoke_id,
48 },
49 SERVICE_REMOVE_LIST_ELEMENT,
50 )
51 }
52}
53
54fn encode_list_element_request(
55 w: &mut Writer<'_>,
56 req: &AddListElementRequest<'_>,
57 service_choice: u8,
58) -> Result<(), EncodeError> {
59 ConfirmedRequestHeader {
60 segmented: false,
61 more_follows: false,
62 segmented_response_accepted: false,
63 max_segments: 0,
64 max_apdu: 5,
65 invoke_id: req.invoke_id,
66 sequence_number: None,
67 proposed_window_size: None,
68 service_choice,
69 }
70 .encode(w)?;
71 encode_ctx_object_id(w, 0, req.object_id.raw())?;
72 encode_ctx_unsigned(w, 1, req.property_id.to_u32())?;
73 if let Some(array_index) = req.array_index {
74 encode_ctx_unsigned(w, 2, array_index)?;
75 }
76 Tag::Opening { tag_num: 3 }.encode(w)?;
77 for value in req.elements {
78 encode_application_data_value(w, value)?;
79 }
80 Tag::Closing { tag_num: 3 }.encode(w)?;
81 Ok(())
82}
83
84#[cfg(test)]
85mod tests {
86 use super::{
87 AddListElementRequest, RemoveListElementRequest, SERVICE_ADD_LIST_ELEMENT,
88 SERVICE_REMOVE_LIST_ELEMENT,
89 };
90 use crate::apdu::ConfirmedRequestHeader;
91 use crate::encoding::{reader::Reader, writer::Writer};
92 use crate::types::{DataValue, ObjectId, ObjectType, PropertyId};
93
94 #[test]
95 fn encode_add_list_element_request() {
96 let values = [DataValue::Unsigned(1), DataValue::Unsigned(2)];
97 let req = AddListElementRequest {
98 object_id: ObjectId::new(ObjectType::AnalogValue, 1),
99 property_id: PropertyId::Proprietary(512),
100 array_index: None,
101 elements: &values,
102 invoke_id: 7,
103 };
104 let mut buf = [0u8; 128];
105 let mut w = Writer::new(&mut buf);
106 req.encode(&mut w).unwrap();
107 let mut r = Reader::new(w.as_written());
108 let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
109 assert_eq!(hdr.service_choice, SERVICE_ADD_LIST_ELEMENT);
110 }
111
112 #[test]
113 fn encode_remove_list_element_request() {
114 let values = [DataValue::Enumerated(3)];
115 let req = RemoveListElementRequest {
116 object_id: ObjectId::new(ObjectType::TrendLog, 1),
117 property_id: PropertyId::Proprietary(513),
118 array_index: None,
119 elements: &values,
120 invoke_id: 8,
121 };
122 let mut buf = [0u8; 128];
123 let mut w = Writer::new(&mut buf);
124 req.encode(&mut w).unwrap();
125 let mut r = Reader::new(w.as_written());
126 let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
127 assert_eq!(hdr.service_choice, SERVICE_REMOVE_LIST_ELEMENT);
128 }
129}