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::types::{ObjectId, ObjectType};
9use crate::{DecodeError, EncodeError};
10
11pub const SERVICE_CREATE_OBJECT: u8 = 0x0A;
12pub const SERVICE_DELETE_OBJECT: u8 = 0x0B;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum CreateObjectSpecifier {
16 ObjectType(ObjectType),
17 ObjectId(ObjectId),
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct CreateObjectRequest {
22 pub specifier: CreateObjectSpecifier,
23 pub invoke_id: u8,
24}
25
26impl CreateObjectRequest {
27 pub fn by_type(object_type: ObjectType, invoke_id: u8) -> Self {
28 Self {
29 specifier: CreateObjectSpecifier::ObjectType(object_type),
30 invoke_id,
31 }
32 }
33
34 pub fn by_id(object_id: ObjectId, invoke_id: u8) -> Self {
35 Self {
36 specifier: CreateObjectSpecifier::ObjectId(object_id),
37 invoke_id,
38 }
39 }
40
41 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
42 ConfirmedRequestHeader {
43 segmented: false,
44 more_follows: false,
45 segmented_response_accepted: true,
46 max_segments: 0,
47 max_apdu: 5,
48 invoke_id: self.invoke_id,
49 sequence_number: None,
50 proposed_window_size: None,
51 service_choice: SERVICE_CREATE_OBJECT,
52 }
53 .encode(w)?;
54
55 match self.specifier {
56 CreateObjectSpecifier::ObjectType(object_type) => {
57 encode_ctx_unsigned(w, 0, object_type.to_u16() as u32)?
58 }
59 CreateObjectSpecifier::ObjectId(object_id) => {
60 encode_ctx_object_id(w, 1, object_id.raw())?
61 }
62 }
63 Ok(())
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub struct CreateObjectAck {
69 pub object_id: ObjectId,
70}
71
72impl CreateObjectAck {
73 pub fn decode_after_header(r: &mut Reader<'_>) -> Result<Self, DecodeError> {
74 let object_id = match Tag::decode(r)? {
75 Tag::Context { tag_num: 0, len } => {
76 if len != 4 {
77 return Err(DecodeError::InvalidLength);
78 }
79 ObjectId::from_raw(decode_unsigned(r, len as usize)?)
80 }
81 _ => return Err(DecodeError::InvalidTag),
82 };
83 Ok(Self { object_id })
84 }
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub struct DeleteObjectRequest {
89 pub object_id: ObjectId,
90 pub invoke_id: u8,
91}
92
93impl DeleteObjectRequest {
94 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
95 ConfirmedRequestHeader {
96 segmented: false,
97 more_follows: false,
98 segmented_response_accepted: false,
99 max_segments: 0,
100 max_apdu: 5,
101 invoke_id: self.invoke_id,
102 sequence_number: None,
103 proposed_window_size: None,
104 service_choice: SERVICE_DELETE_OBJECT,
105 }
106 .encode(w)?;
107 encode_ctx_object_id(w, 0, self.object_id.raw())
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::{
114 CreateObjectAck, CreateObjectRequest, DeleteObjectRequest, SERVICE_CREATE_OBJECT,
115 SERVICE_DELETE_OBJECT,
116 };
117 use crate::apdu::{ComplexAckHeader, ConfirmedRequestHeader};
118 use crate::encoding::primitives::encode_ctx_object_id;
119 use crate::encoding::{reader::Reader, writer::Writer};
120 use crate::types::{ObjectId, ObjectType};
121
122 #[test]
123 fn encode_create_object_request() {
124 let req = CreateObjectRequest::by_type(ObjectType::AnalogValue, 3);
125 let mut buf = [0u8; 64];
126 let mut w = Writer::new(&mut buf);
127 req.encode(&mut w).unwrap();
128 let mut r = Reader::new(w.as_written());
129 let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
130 assert_eq!(hdr.service_choice, SERVICE_CREATE_OBJECT);
131 }
132
133 #[test]
134 fn encode_delete_object_request() {
135 let req = DeleteObjectRequest {
136 object_id: ObjectId::new(ObjectType::AnalogValue, 9),
137 invoke_id: 5,
138 };
139 let mut buf = [0u8; 64];
140 let mut w = Writer::new(&mut buf);
141 req.encode(&mut w).unwrap();
142 let mut r = Reader::new(w.as_written());
143 let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
144 assert_eq!(hdr.service_choice, SERVICE_DELETE_OBJECT);
145 }
146
147 #[test]
148 fn decode_create_object_ack() {
149 let mut buf = [0u8; 64];
150 let mut w = Writer::new(&mut buf);
151 ComplexAckHeader {
152 segmented: false,
153 more_follows: false,
154 invoke_id: 3,
155 sequence_number: None,
156 proposed_window_size: None,
157 service_choice: SERVICE_CREATE_OBJECT,
158 }
159 .encode(&mut w)
160 .unwrap();
161 encode_ctx_object_id(&mut w, 0, ObjectId::new(ObjectType::AnalogValue, 9).raw()).unwrap();
162 let mut r = Reader::new(w.as_written());
163 let _ack_hdr = ComplexAckHeader::decode(&mut r).unwrap();
164 let ack = CreateObjectAck::decode_after_header(&mut r).unwrap();
165 assert_eq!(ack.object_id, ObjectId::new(ObjectType::AnalogValue, 9));
166 }
167}