mcumgr_toolkit/transport/
mod.rs1use std::{io, time::Duration};
2
3use miette::Diagnostic;
4use thiserror::Error;
5
6pub mod serial;
8
9pub mod udp;
11
12#[derive(Debug, PartialEq, Clone, Copy)]
13struct SmpHeader {
14 ver: u8,
15 op: u8,
16 flags: u8,
17 data_length: u16,
18 group_id: u16,
19 sequence_num: u8,
20 command_id: u8,
21}
22
23impl SmpHeader {
24 fn from_bytes(data: [u8; SMP_HEADER_SIZE]) -> Self {
25 Self {
26 ver: (data[0] >> 3) & 0b11,
27 op: data[0] & 0b111,
28 flags: data[1],
29 data_length: u16::from_be_bytes([data[2], data[3]]),
30 group_id: u16::from_be_bytes([data[4], data[5]]),
31 sequence_num: data[6],
32 command_id: data[7],
33 }
34 }
35 fn to_bytes(self) -> [u8; SMP_HEADER_SIZE] {
36 let [length_0, length_1] = self.data_length.to_be_bytes();
37 let [group_id_0, group_id_1] = self.group_id.to_be_bytes();
38 [
39 ((self.ver & 0b11) << 3) | (self.op & 0b111),
40 self.flags,
41 length_0,
42 length_1,
43 group_id_0,
44 group_id_1,
45 self.sequence_num,
46 self.command_id,
47 ]
48 }
49}
50
51const SMP_HEADER_SIZE: usize = 8;
52const SMP_TRANSFER_BUFFER_SIZE: usize = u16::MAX as usize;
53
54mod smp_op {
55 pub(super) const READ: u8 = 0;
56 pub(super) const READ_RSP: u8 = 1;
57 pub(super) const WRITE: u8 = 2;
58 pub(super) const WRITE_RSP: u8 = 3;
59}
60
61#[derive(Error, Debug, Diagnostic)]
63pub enum SendError {
64 #[error("Transport error")]
66 #[diagnostic(code(mcumgr_toolkit::transport::send::transport))]
67 TransportError(#[from] io::Error),
68 #[error("Given data slice was too big")]
70 #[diagnostic(code(mcumgr_toolkit::transport::send::too_big))]
71 DataTooBig,
72}
73
74#[derive(Error, Debug, Diagnostic)]
76pub enum ReceiveError {
77 #[error("Transport error")]
79 #[diagnostic(code(mcumgr_toolkit::transport::recv::transport))]
80 TransportError(#[from] io::Error),
81 #[error("Received unexpected response")]
83 #[diagnostic(code(mcumgr_toolkit::transport::recv::unexpected))]
84 UnexpectedResponse,
85 #[error("Received frame that exceeds configured MTU")]
87 #[diagnostic(code(mcumgr_toolkit::transport::recv::too_big))]
88 FrameTooBig,
89 #[error("Failed to decode base64 data")]
91 #[diagnostic(code(mcumgr_toolkit::transport::recv::base64_decode))]
92 Base64DecodeError(#[from] base64::DecodeSliceError),
93}
94
95pub trait Transport {
97 fn send_raw_frame(
102 &mut self,
103 header: [u8; SMP_HEADER_SIZE],
104 data: &[u8],
105 ) -> Result<(), SendError>;
106
107 fn recv_raw_frame<'a>(
112 &mut self,
113 buffer: &'a mut [u8; SMP_TRANSFER_BUFFER_SIZE],
114 ) -> Result<&'a [u8], ReceiveError>;
115
116 fn send_frame(
129 &mut self,
130 write_operation: bool,
131 sequence_num: u8,
132 group_id: u16,
133 command_id: u8,
134 data: &[u8],
135 ) -> Result<(), SendError> {
136 let header = SmpHeader {
137 ver: 0b01,
138 op: if write_operation {
139 smp_op::WRITE
140 } else {
141 smp_op::READ
142 },
143 flags: 0,
144 data_length: data.len().try_into().map_err(|_| SendError::DataTooBig)?,
145 group_id,
146 sequence_num,
147 command_id,
148 };
149
150 let header_data = header.to_bytes();
151
152 self.send_raw_frame(header_data, data)
153 }
154
155 fn receive_frame<'a>(
170 &mut self,
171 buffer: &'a mut [u8; SMP_TRANSFER_BUFFER_SIZE],
172 write_operation: bool,
173 sequence_num: u8,
174 group_id: u16,
175 command_id: u8,
176 ) -> Result<&'a [u8], ReceiveError> {
177 let data_size = loop {
178 let frame = self.recv_raw_frame(buffer)?;
179
180 let (header_data, data) = frame
181 .split_first_chunk::<SMP_HEADER_SIZE>()
182 .ok_or(ReceiveError::UnexpectedResponse)?;
183
184 let header = SmpHeader::from_bytes(*header_data);
185
186 let expected_op = if write_operation {
187 smp_op::WRITE_RSP
188 } else {
189 smp_op::READ_RSP
190 };
191
192 if header.sequence_num != sequence_num {
195 continue;
196 }
197
198 if (header.group_id != group_id)
199 || (header.command_id != command_id)
200 || (header.op != expected_op)
201 || (usize::from(header.data_length) != data.len())
202 {
203 return Err(ReceiveError::UnexpectedResponse);
204 }
205
206 break data.len();
207 };
208
209 Ok(&buffer[SMP_HEADER_SIZE..SMP_HEADER_SIZE + data_size])
210 }
211
212 fn set_timeout(
217 &mut self,
218 timeout: Duration,
219 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
220
221 fn max_smp_frame_size(&self) -> usize {
230 usize::MAX
231 }
232}