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(
79 &self,
80 timeout: Duration,
81 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
82 self.inner.lock().unwrap().transport.set_timeout(timeout)
83 }
84
85 pub fn execute_command<R: McuMgrCommand>(
87 &self,
88 request: &R,
89 ) -> Result<R::Response, ExecuteError> {
90 let mut lock_guard = self.inner.lock().unwrap();
91 let locked_self: &mut Inner = &mut lock_guard;
92
93 let mut cursor = Cursor::new(locked_self.transport_buffer.as_mut_slice());
94 ciborium::into_writer(request.data(), &mut cursor)
95 .into_diagnostic()
96 .map_err(Into::into)
97 .map_err(ExecuteError::EncodeFailed)?;
98 let data_size = cursor.position() as usize;
99 let data = &locked_self.transport_buffer[..data_size];
100
101 log::debug!("TX data: {}", hex::encode(data));
102
103 let sequence_num = locked_self.next_seqnum;
104 locked_self.next_seqnum = locked_self.next_seqnum.wrapping_add(1);
105
106 let write_operation = request.is_write_operation();
107 let group_id = request.group_id();
108 let command_id = request.command_id();
109
110 locked_self.transport.send_frame(
111 write_operation,
112 sequence_num,
113 group_id,
114 command_id,
115 data,
116 )?;
117
118 let response = locked_self.transport.receive_frame(
119 &mut locked_self.transport_buffer,
120 write_operation,
121 sequence_num,
122 group_id,
123 command_id,
124 )?;
125
126 log::debug!("RX data: {}", hex::encode(response));
127
128 let err: ErrResponse = ciborium::from_reader(Cursor::new(response))
129 .into_diagnostic()
130 .map_err(Into::into)
131 .map_err(ExecuteError::DecodeFailed)?;
132
133 if let Some(ErrResponseV2 { rc, group }) = err.err {
134 return Err(ExecuteError::ErrorResponse(DeviceError::V2 { group, rc }));
135 }
136
137 if let Some(rc) = err.rc {
138 if rc != MCUmgrErr::MGMT_ERR_EOK as i32 {
139 return Err(ExecuteError::ErrorResponse(DeviceError::V1 {
140 rc,
141 rsn: err.rsn,
142 }));
143 }
144 }
145
146 let decoded_response: R::Response = ciborium::from_reader(Cursor::new(response))
147 .into_diagnostic()
148 .map_err(Into::into)
149 .map_err(ExecuteError::DecodeFailed)?;
150
151 Ok(decoded_response)
152 }
153
154 pub fn execute_raw_command(
164 &self,
165 write_operation: bool,
166 group_id: u16,
167 command_id: u8,
168 data: &[u8],
169 ) -> Result<Box<[u8]>, ExecuteError> {
170 let mut lock_guard = self.inner.lock().unwrap();
171 let locked_self: &mut Inner = &mut lock_guard;
172
173 let sequence_num = locked_self.next_seqnum;
174 locked_self.next_seqnum = locked_self.next_seqnum.wrapping_add(1);
175
176 locked_self.transport.send_frame(
177 write_operation,
178 sequence_num,
179 group_id,
180 command_id,
181 data,
182 )?;
183
184 locked_self
185 .transport
186 .receive_frame(
187 &mut locked_self.transport_buffer,
188 write_operation,
189 sequence_num,
190 group_id,
191 command_id,
192 )
193 .map_err(Into::into)
194 .map(|val| val.into())
195 }
196}