mcumgr_toolkit/
connection.rs1use std::{io::Cursor, sync::Mutex, time::Duration};
2
3use crate::{
4 commands::{ErrResponse, ErrResponseV2, McuMgrCommand},
5 smp_errors::{DeviceError, MCUmgrErr},
6 transport::{ReceiveError, SendError, Transport},
7};
8
9use miette::{Diagnostic, IntoDiagnostic};
10use thiserror::Error;
11
12struct Inner {
13 transport: Box<dyn Transport + Send>,
14 next_seqnum: u8,
15 transport_buffer: Box<[u8; u16::MAX as usize]>,
16}
17
18pub struct Connection {
23 inner: Mutex<Inner>,
24}
25
26#[derive(Error, Debug, Diagnostic)]
28pub enum ExecuteError {
29 #[error("Sending failed")]
31 #[diagnostic(code(mcumgr_toolkit::connection::execute::send))]
32 SendFailed(#[from] SendError),
33 #[error("Receiving failed")]
35 #[diagnostic(code(mcumgr_toolkit::connection::execute::receive))]
36 ReceiveFailed(#[from] ReceiveError),
37 #[error("CBOR encoding failed")]
39 #[diagnostic(code(mcumgr_toolkit::connection::execute::encode))]
40 EncodeFailed(#[source] Box<dyn miette::Diagnostic + Send + Sync>),
41 #[error("CBOR decoding failed")]
43 #[diagnostic(code(mcumgr_toolkit::connection::execute::decode))]
44 DecodeFailed(#[source] Box<dyn miette::Diagnostic + Send + Sync>),
45 #[error("Device returned error code: {0}")]
47 #[diagnostic(code(mcumgr_toolkit::connection::execute::device_error))]
48 ErrorResponse(DeviceError),
49}
50
51impl ExecuteError {
52 pub fn command_not_supported(&self) -> bool {
54 if let Self::ErrorResponse(DeviceError::V1 { rc, .. }) = self {
55 *rc == MCUmgrErr::MGMT_ERR_ENOTSUP as i32
56 } else {
57 false
58 }
59 }
60}
61
62impl Connection {
63 pub fn new<T: Transport + Send + 'static>(transport: T) -> Self {
65 Self {
66 inner: Mutex::new(Inner {
67 transport: Box::new(transport),
68 next_seqnum: rand::random(),
69 transport_buffer: Box::new([0; u16::MAX as usize]),
70 }),
71 }
72 }
73
74 pub fn set_timeout(&self, timeout: Duration) -> Result<(), miette::Report> {
79 self.inner.lock().unwrap().transport.set_timeout(timeout)
80 }
81
82 pub fn execute_command<R: McuMgrCommand>(
84 &self,
85 request: &R,
86 ) -> Result<R::Response, ExecuteError> {
87 let mut lock_guard = self.inner.lock().unwrap();
88 let locked_self: &mut Inner = &mut lock_guard;
89
90 let mut cursor = Cursor::new(locked_self.transport_buffer.as_mut_slice());
91 ciborium::into_writer(request.data(), &mut cursor)
92 .into_diagnostic()
93 .map_err(Into::into)
94 .map_err(ExecuteError::EncodeFailed)?;
95 let data_size = cursor.position() as usize;
96 let data = &locked_self.transport_buffer[..data_size];
97
98 log::debug!("TX data: {}", hex::encode(data));
99
100 let sequence_num = locked_self.next_seqnum;
101 locked_self.next_seqnum = locked_self.next_seqnum.wrapping_add(1);
102
103 let write_operation = request.is_write_operation();
104 let group_id = request.group_id();
105 let command_id = request.command_id();
106
107 locked_self.transport.send_frame(
108 write_operation,
109 sequence_num,
110 group_id,
111 command_id,
112 data,
113 )?;
114
115 let response = locked_self.transport.receive_frame(
116 &mut locked_self.transport_buffer,
117 write_operation,
118 sequence_num,
119 group_id,
120 command_id,
121 )?;
122
123 log::debug!("RX data: {}", hex::encode(response));
124
125 let err: ErrResponse = ciborium::from_reader(Cursor::new(response))
126 .into_diagnostic()
127 .map_err(Into::into)
128 .map_err(ExecuteError::DecodeFailed)?;
129
130 if let Some(ErrResponseV2 { rc, group }) = err.err {
131 return Err(ExecuteError::ErrorResponse(DeviceError::V2 { group, rc }));
132 }
133
134 if let Some(rc) = err.rc {
135 if rc != MCUmgrErr::MGMT_ERR_EOK as i32 {
136 return Err(ExecuteError::ErrorResponse(DeviceError::V1 {
137 rc,
138 rsn: err.rsn,
139 }));
140 }
141 }
142
143 let decoded_response: R::Response = ciborium::from_reader(Cursor::new(response))
144 .into_diagnostic()
145 .map_err(Into::into)
146 .map_err(ExecuteError::DecodeFailed)?;
147
148 Ok(decoded_response)
149 }
150
151 pub fn execute_raw_command(
161 &self,
162 write_operation: bool,
163 group_id: u16,
164 command_id: u8,
165 data: &[u8],
166 ) -> Result<Box<[u8]>, ExecuteError> {
167 let mut lock_guard = self.inner.lock().unwrap();
168 let locked_self: &mut Inner = &mut lock_guard;
169
170 let sequence_num = locked_self.next_seqnum;
171 locked_self.next_seqnum = locked_self.next_seqnum.wrapping_add(1);
172
173 locked_self.transport.send_frame(
174 write_operation,
175 sequence_num,
176 group_id,
177 command_id,
178 data,
179 )?;
180
181 locked_self
182 .transport
183 .receive_frame(
184 &mut locked_self.transport_buffer,
185 write_operation,
186 sequence_num,
187 group_id,
188 command_id,
189 )
190 .map_err(Into::into)
191 .map(|val| val.into())
192 }
193}