1use crate::apdu::ConfirmedRequestHeader;
2use crate::encoding::{
3 primitives::{encode_ctx_character_string, encode_ctx_unsigned},
4 writer::Writer,
5};
6use crate::EncodeError;
7
8pub const SERVICE_DEVICE_COMMUNICATION_CONTROL: u8 = 0x11;
9pub const SERVICE_REINITIALIZE_DEVICE: u8 = 0x14;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[repr(u32)]
13pub enum DeviceCommunicationState {
14 Enable = 0,
15 Disable = 1,
16 DisableInitiation = 2,
17}
18
19impl DeviceCommunicationState {
20 pub const fn to_u32(self) -> u32 {
21 self as u32
22 }
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26#[repr(u32)]
27pub enum ReinitializeState {
28 Coldstart = 0,
29 Warmstart = 1,
30 StartBackup = 2,
31 EndBackup = 3,
32 StartRestore = 4,
33 EndRestore = 5,
34 AbortRestore = 6,
35 ActivateChanges = 7,
36}
37
38impl ReinitializeState {
39 pub const fn to_u32(self) -> u32 {
40 self as u32
41 }
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub struct DeviceCommunicationControlRequest<'a> {
46 pub time_duration_seconds: Option<u16>,
47 pub enable_disable: DeviceCommunicationState,
48 pub password: Option<&'a str>,
49 pub invoke_id: u8,
50}
51
52impl<'a> DeviceCommunicationControlRequest<'a> {
53 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
54 ConfirmedRequestHeader {
55 segmented: false,
56 more_follows: false,
57 segmented_response_accepted: false,
58 max_segments: 0,
59 max_apdu: 5,
60 invoke_id: self.invoke_id,
61 sequence_number: None,
62 proposed_window_size: None,
63 service_choice: SERVICE_DEVICE_COMMUNICATION_CONTROL,
64 }
65 .encode(w)?;
66 if let Some(duration) = self.time_duration_seconds {
67 encode_ctx_unsigned(w, 0, duration as u32)?;
68 }
69 encode_ctx_unsigned(w, 1, self.enable_disable.to_u32())?;
70 if let Some(password) = self.password {
71 encode_ctx_character_string(w, 2, password)?;
72 }
73 Ok(())
74 }
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct ReinitializeDeviceRequest<'a> {
79 pub state: ReinitializeState,
80 pub password: Option<&'a str>,
81 pub invoke_id: u8,
82}
83
84impl<'a> ReinitializeDeviceRequest<'a> {
85 pub fn encode(&self, w: &mut Writer<'_>) -> Result<(), EncodeError> {
86 ConfirmedRequestHeader {
87 segmented: false,
88 more_follows: false,
89 segmented_response_accepted: false,
90 max_segments: 0,
91 max_apdu: 5,
92 invoke_id: self.invoke_id,
93 sequence_number: None,
94 proposed_window_size: None,
95 service_choice: SERVICE_REINITIALIZE_DEVICE,
96 }
97 .encode(w)?;
98 encode_ctx_unsigned(w, 0, self.state.to_u32())?;
99 if let Some(password) = self.password {
100 encode_ctx_character_string(w, 1, password)?;
101 }
102 Ok(())
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::{
109 DeviceCommunicationControlRequest, DeviceCommunicationState, ReinitializeDeviceRequest,
110 ReinitializeState, SERVICE_DEVICE_COMMUNICATION_CONTROL, SERVICE_REINITIALIZE_DEVICE,
111 };
112 use crate::apdu::ConfirmedRequestHeader;
113 use crate::encoding::{reader::Reader, writer::Writer};
114
115 #[test]
116 fn encode_device_communication_control_request() {
117 let req = DeviceCommunicationControlRequest {
118 time_duration_seconds: Some(120),
119 enable_disable: DeviceCommunicationState::Disable,
120 password: Some("secret"),
121 invoke_id: 7,
122 };
123 let mut buf = [0u8; 96];
124 let mut w = Writer::new(&mut buf);
125 req.encode(&mut w).unwrap();
126
127 let mut r = Reader::new(w.as_written());
128 let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
129 assert_eq!(hdr.service_choice, SERVICE_DEVICE_COMMUNICATION_CONTROL);
130 assert_eq!(hdr.invoke_id, 7);
131 }
132
133 #[test]
134 fn encode_reinitialize_device_request() {
135 let req = ReinitializeDeviceRequest {
136 state: ReinitializeState::ActivateChanges,
137 password: None,
138 invoke_id: 11,
139 };
140 let mut buf = [0u8; 64];
141 let mut w = Writer::new(&mut buf);
142 req.encode(&mut w).unwrap();
143
144 let mut r = Reader::new(w.as_written());
145 let hdr = ConfirmedRequestHeader::decode(&mut r).unwrap();
146 assert_eq!(hdr.service_choice, SERVICE_REINITIALIZE_DEVICE);
147 assert_eq!(hdr.invoke_id, 11);
148 }
149}