1use crate::error::Error;
2use crate::types::{CommandType, MTExtendedHeaderStatus, MTSubsystem};
3use bytes::{Buf, BufMut};
4use num_traits::FromPrimitive;
5use std::io::{Cursor, Read};
6
7#[derive(Debug, Clone)]
8pub struct MTFrame {
9 pub header: MTHeader,
10 pub extended_header: Option<MTExtendedHeader>,
11 pub payload: Vec<u8>,
12}
13
14impl MTFrame {
15 pub fn try_decode(cursor: &mut Cursor<&[u8]>) -> Result<Self, Error> {
16 let header = MTHeader::try_decode(Read::by_ref(cursor))?;
17
18 let extended_header = if header.has_extension() {
19 Some(MTExtendedHeader::try_decode(Read::by_ref(cursor))?)
20 } else {
21 None
22 };
23
24 let mut payload = Vec::new();
25 cursor
26 .read_to_end(&mut payload)
27 .map_err(|_| Error::NotEnoughBytes)?;
28
29 Ok(MTFrame {
30 header,
31 extended_header,
32 payload,
33 })
34 }
35
36 pub fn encode_into(&self, buffer: &mut Vec<u8>) {
37 self.header.encode_into(buffer);
38
39 if let Some(ref extended_header) = self.extended_header {
40 extended_header.encode_into(buffer);
41 }
42
43 buffer.extend(self.payload.iter());
44 }
45
46 pub fn encode_to_uart_transport_frame(&self) -> Vec<u8> {
47 const START_OF_FRAME: u8 = 0xfe;
48 let mut buffer = Vec::new();
49 buffer.put_u8(START_OF_FRAME);
50 self.encode_into(&mut buffer);
51 let fcs = Self::compute_frame_check_sequence(&buffer[1..]);
52 buffer.put_u8(fcs);
53 buffer
54 }
55
56 pub fn compute_frame_check_sequence(mt_frame_bytes: &[u8]) -> u8 {
57 mt_frame_bytes.iter().fold(0, |acc, x| acc ^ x)
58 }
59}
60
61#[derive(Debug, Clone)]
62pub struct MTHeader {
63 pub length: u8,
64 pub command: CommandCode,
65}
66
67impl MTHeader {
68 pub fn size() -> usize {
69 return 3;
70 }
71
72 pub fn has_extension(&self) -> bool {
73 self.command.is_extended
74 }
75
76 pub fn try_decode(cursor: &mut Cursor<&[u8]>) -> Result<Self, Error> {
77 let length = cursor.get_u8();
78 let command = CommandCode::try_decode(cursor)?;
79 Ok(MTHeader { length, command })
80 }
81
82 pub fn encode_into(&self, buffer: &mut Vec<u8>) {
83 buffer.put_u8(self.length);
84 self.command.encode_into(buffer);
85 }
86}
87
88#[derive(Debug, PartialEq, Clone)]
89pub struct CommandCode {
90 pub is_extended: bool,
91 pub cmd_type: CommandType,
92 pub subsystem: MTSubsystem,
93 pub id: u8,
94}
95
96impl CommandCode {
97 pub fn try_decode(cursor: &mut Cursor<&[u8]>) -> Result<Self, Error> {
98 let type_and_subsystem = cursor.get_u8();
99 let id = cursor.get_u8();
100
101 let is_extended = (type_and_subsystem & 0x80) != 0;
102
103 let cmd_type = 0x03 & (type_and_subsystem >> 5);
104 let cmd_type =
105 FromPrimitive::from_u8(cmd_type).ok_or(Error::InvalidCommandType(cmd_type))?;
106
107 let subsystem = type_and_subsystem & 0x1F;
108 let subsystem =
109 FromPrimitive::from_u8(subsystem).ok_or(Error::InvalidSubsystem(subsystem))?;
110
111 Ok(CommandCode {
112 is_extended,
113 cmd_type,
114 subsystem,
115 id,
116 })
117 }
118
119 pub fn encode_into(&self, buffer: &mut Vec<u8>) {
120 let type_and_subsystem = {
121 let value = ((self.cmd_type as u8) << 5) | (self.subsystem as u8);
122 if self.is_extended {
123 0x80 | value
124 } else {
125 value
126 }
127 };
128 buffer.put_u8(type_and_subsystem);
129 buffer.put_u8(self.id);
130 }
131}
132
133#[derive(Debug, Clone)]
134pub enum MTExtendedHeader {
135 V1 {
136 stack_id: u8,
137 },
138 V2 {
139 stack_id: u8,
140 block: u8,
141 packet_length: u16,
142 },
143 V3 {
144 stack_id: u8,
145 block: u8,
146 status: MTExtendedHeaderStatus,
147 },
148 V4 {
149 stack_id: u8,
150 block: u8,
151 status: MTExtendedHeaderStatus,
152 },
153}
154
155impl MTExtendedHeader {
156 pub fn try_decode(cursor: &mut Cursor<&[u8]>) -> Result<Self, Error> {
157 let version_and_stack_id = cursor.get_u8();
158 let version = (version_and_stack_id & 0xf8) >> 3;
159 let stack_id = version_and_stack_id & 0x07;
160
161 if version == 1 {
162 return Ok(MTExtendedHeader::V1 { stack_id });
163 }
164
165 let block = cursor.get_u8();
166
167 if version == 2 {
168 let packet_length = cursor.get_u16_le();
169 return Ok(MTExtendedHeader::V2 {
170 stack_id,
171 block,
172 packet_length,
173 });
174 }
175
176 if version == 3 || version == 4 {
177 let status = MTExtendedHeaderStatus::try_decode(cursor)?;
178
179 if version == 3 {
180 return Ok(MTExtendedHeader::V3 {
181 stack_id,
182 block,
183 status,
184 });
185 } else {
186 return Ok(MTExtendedHeader::V4 {
187 stack_id,
188 block,
189 status,
190 });
191 }
192 }
193
194 Err(Error::NotImplemented)
195 }
196
197 pub fn encode_into(&self, buffer: &mut Vec<u8>) {
198 match self {
199 MTExtendedHeader::V1 { stack_id } => {
200 let version_and_stack_id = (1 << 3) | stack_id;
201 buffer.put_u8(version_and_stack_id);
202 }
203 MTExtendedHeader::V2 {
204 stack_id,
205 block,
206 packet_length,
207 } => {
208 let version_and_stack_id = (2 << 3) | stack_id;
209 buffer.put_u8(version_and_stack_id);
210 buffer.put_u8(*block);
211 buffer.put_u16_le(*packet_length);
212 }
213 MTExtendedHeader::V3 {
214 stack_id,
215 block,
216 status,
217 } => {
218 let version_and_stack_id = (3 << 3) | stack_id;
219 buffer.put_u8(version_and_stack_id);
220 buffer.put_u8(*block);
221 status.encode_into(buffer);
222 }
223 MTExtendedHeader::V4 {
224 stack_id,
225 block,
226 status,
227 } => {
228 let version_and_stack_id = (4 << 3) | stack_id;
229 buffer.put_u8(version_and_stack_id);
230 buffer.put_u8(*block);
231 status.encode_into(buffer);
232 }
233 }
234 }
235}