esp32_nimble/
ble_error.rs

1use core::num::NonZeroI32;
2use esp_idf_svc::sys;
3
4#[derive(Copy, Clone, Eq, PartialEq, Hash)]
5pub struct BLEError(NonZeroI32);
6
7impl BLEError {
8    pub fn fail() -> Result<(), Self> {
9        Self::convert(0xFFFF)
10    }
11
12    pub const fn from_non_zero(error: NonZeroI32) -> Self {
13        Self(error)
14    }
15
16    pub fn check_and_return<T>(error: u32, value: T) -> Result<T, Self> {
17        match error {
18            0 | sys::BLE_HS_EALREADY | sys::BLE_HS_EDONE => Ok(value),
19            error => Err(Self(unsafe { NonZeroI32::new_unchecked(error as _) })),
20        }
21    }
22
23    pub const fn convert(error: u32) -> Result<(), Self> {
24        match error {
25            0 | sys::BLE_HS_EALREADY | sys::BLE_HS_EDONE => Ok(()),
26            error => Err(Self(unsafe { NonZeroI32::new_unchecked(error as _) })),
27        }
28    }
29
30    pub fn code(&self) -> u32 {
31        self.0.get() as _
32    }
33}
34
35impl core::fmt::Display for BLEError {
36    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37        match return_code_to_string(self.0.get()) {
38            Some(text) => write!(f, "{text}")?,
39            None => write!(f, "0x{:X}", self.0)?,
40        };
41
42        Ok(())
43    }
44}
45
46impl core::fmt::Debug for BLEError {
47    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48        match return_code_to_string(self.0.get()) {
49            Some(text) => write!(f, "{text}")?,
50            None => write!(f, "0x{:X}", self.0)?,
51        };
52
53        Ok(())
54    }
55}
56
57#[cfg(feature = "std")]
58impl std::error::Error for BLEError {}
59
60pub fn return_code_to_string(rc: i32) -> Option<&'static str> {
61    let rc = rc as u32;
62
63    if rc < 0x100 {
64        match rc {
65            sys::BLE_HS_EALREADY => Some("Operation already in progress or completed."),
66            sys::BLE_HS_EINVAL => Some("One or more arguments are invalid."),
67            sys::BLE_HS_EMSGSIZE => Some("The provided buffer is too small."),
68            sys::BLE_HS_ENOENT => Some("No entry matching the specified criteria."),
69            sys::BLE_HS_ENOMEM => Some("Operation failed due to resource exhaustion."),
70            sys::BLE_HS_ENOTCONN => Some("No open connection with the specified handle."),
71            sys::BLE_HS_ENOTSUP => Some("Operation disabled at compile time."),
72            sys::BLE_HS_EAPP => Some("Application callback behaved unexpectedly."),
73            sys::BLE_HS_EBADDATA => Some("Command from peer is invalid."),
74            sys::BLE_HS_EOS => Some("Mynewt OS error."),
75            sys::BLE_HS_ECONTROLLER => Some("Event from controller is invalid."),
76            sys::BLE_HS_ETIMEOUT => Some("Operation timed out."),
77            sys::BLE_HS_EDONE => Some("Operation completed successfully."),
78            sys::BLE_HS_EBUSY => Some("Operation cannot be performed until procedure completes."),
79            sys::BLE_HS_EREJECT => Some("Peer rejected a connection parameter update request."),
80            sys::BLE_HS_EUNKNOWN => Some("Unexpected failure; catch all."),
81            sys::BLE_HS_EROLE => {
82                Some("Operation requires different role (e.g., central vs. peripheral).")
83            }
84            sys::BLE_HS_ETIMEOUT_HCI => Some("HCI request timed out; controller unresponsive."),
85            sys::BLE_HS_ENOMEM_EVT => Some(
86                "Controller failed to send event due to memory exhaustion (combined host-controller only).",
87            ),
88            sys::BLE_HS_ENOADDR => {
89                Some("Operation requires an identity address but none configured.")
90            }
91            sys::BLE_HS_ENOTSYNCED => {
92                Some("Attempt to use the host before it is synced with controller.")
93            }
94            sys::BLE_HS_EAUTHEN => Some("Insufficient authentication."),
95            sys::BLE_HS_EAUTHOR => Some("Insufficient authorization."),
96            sys::BLE_HS_EENCRYPT => Some("Insufficient encryption level."),
97            sys::BLE_HS_EENCRYPT_KEY_SZ => Some("Insufficient key size"),
98            sys::BLE_HS_ESTORE_CAP => Some("Storage at capacity."),
99            sys::BLE_HS_ESTORE_FAIL => Some("Storage IO error."),
100            _ => None,
101        }
102    }
103    // ATT errors (BLE_HS_ERR_ATT_BASE : 0x100)
104    else if rc < sys::BLE_HS_ERR_ATT_BASE + 0x100 {
105        match rc - sys::BLE_HS_ERR_ATT_BASE {
106            sys::BLE_ATT_ERR_INVALID_HANDLE => {
107                Some("The attribute handle given was not valid on this server.")
108            }
109            sys::BLE_ATT_ERR_READ_NOT_PERMITTED => Some("The attribute cannot be read."),
110            sys::BLE_ATT_ERR_WRITE_NOT_PERMITTED => Some("The attribute cannot be written."),
111            sys::BLE_ATT_ERR_INVALID_PDU => Some("The attribute PDU was invalid."),
112            sys::BLE_ATT_ERR_INSUFFICIENT_AUTHEN => {
113                Some("The attribute requires authentication before it can be read or written.")
114            }
115            sys::BLE_ATT_ERR_REQ_NOT_SUPPORTED => {
116                Some("Attribute server does not support the request received from the client.")
117            }
118            sys::BLE_ATT_ERR_INVALID_OFFSET => {
119                Some("Offset specified was past the end of the attribute.")
120            }
121            sys::BLE_ATT_ERR_INSUFFICIENT_AUTHOR => {
122                Some("The attribute requires authorization before it can be read or written.")
123            }
124            sys::BLE_ATT_ERR_PREPARE_QUEUE_FULL => {
125                Some("Too many prepare writes have been queued.")
126            }
127            sys::BLE_ATT_ERR_ATTR_NOT_FOUND => {
128                Some("No attribute found within the given attribute handle range.")
129            }
130            sys::BLE_ATT_ERR_ATTR_NOT_LONG => {
131                Some("The attribute cannot be read or written using the Read Blob Request.")
132            }
133            sys::BLE_ATT_ERR_INSUFFICIENT_KEY_SZ => {
134                Some("The Encryption Key Size used for encrypting this link is insufficient.")
135            }
136            sys::BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN => {
137                Some("The attribute value length is invalid for the operation.")
138            }
139            sys::BLE_ATT_ERR_UNLIKELY => Some(
140                "The attribute request has encountered an error that was unlikely, could not be completed as requested.",
141            ),
142            sys::BLE_ATT_ERR_INSUFFICIENT_ENC => {
143                Some("The attribute requires encryption before it can be read or written.")
144            }
145            sys::BLE_ATT_ERR_UNSUPPORTED_GROUP => Some(
146                "The attribute type is not a supported grouping attribute as defined by a higher layer specification.",
147            ),
148            sys::BLE_ATT_ERR_INSUFFICIENT_RES => {
149                Some("Insufficient Resources to complete the request.")
150            }
151            _ => None,
152        }
153    }
154    // HCI errors (BLE_HS_ERR_HCI_BASE : 0x200)
155    else if rc < sys::BLE_HS_ERR_HCI_BASE + 0x100 {
156        match rc - sys::BLE_HS_ERR_HCI_BASE {
157            sys::ble_error_codes_BLE_ERR_UNKNOWN_HCI_CMD => Some("Unknown HCI Command"),
158            sys::ble_error_codes_BLE_ERR_UNK_CONN_ID => Some("Unknown Connection Identifier"),
159            sys::ble_error_codes_BLE_ERR_HW_FAIL => Some("Hardware Failure"),
160            sys::ble_error_codes_BLE_ERR_PAGE_TMO => Some("Page Timeout"),
161            sys::ble_error_codes_BLE_ERR_AUTH_FAIL => Some("Authentication Failure"),
162            sys::ble_error_codes_BLE_ERR_PINKEY_MISSING => Some("PIN or Key Missing"),
163            sys::ble_error_codes_BLE_ERR_MEM_CAPACITY => Some("Memory Capacity Exceeded"),
164            sys::ble_error_codes_BLE_ERR_CONN_SPVN_TMO => Some("Connection Timeout"),
165            sys::ble_error_codes_BLE_ERR_CONN_LIMIT => Some("Connection Limit Exceeded"),
166            sys::ble_error_codes_BLE_ERR_SYNCH_CONN_LIMIT => {
167                Some("Synchronous Connection Limit To A Device Exceeded")
168            }
169            sys::ble_error_codes_BLE_ERR_ACL_CONN_EXISTS => Some("ACL Connection Already Exists"),
170            sys::ble_error_codes_BLE_ERR_CMD_DISALLOWED => Some("Command Disallowed"),
171            sys::ble_error_codes_BLE_ERR_CONN_REJ_RESOURCES => {
172                Some("Connection Rejected due to Limited Resources")
173            }
174            sys::ble_error_codes_BLE_ERR_INV_HCI_CMD_PARMS => {
175                Some("Invalid HCI Command Parameters")
176            }
177            sys::ble_error_codes_BLE_ERR_REM_USER_CONN_TERM => {
178                Some("Remote User Terminated Connection")
179            }
180            sys::ble_error_codes_BLE_ERR_CONN_TERM_LOCAL => {
181                Some("Connection Terminated By Local Host")
182            }
183            sys::ble_error_codes_BLE_ERR_CONN_TERM_MIC => {
184                Some("Connection Terminated; MIC Failure")
185            }
186            sys::ble_error_codes_BLE_ERR_CONN_ESTABLISHMENT => {
187                Some("Connection Failed to be Established.")
188            }
189            _ => None,
190        }
191    }
192    // L2CAP errors (BLE_HS_ERR_L2C_BASE : 0x300)
193    else if rc < sys::BLE_HS_ERR_L2C_BASE + 0x100 {
194        match rc - sys::BLE_HS_ERR_L2C_BASE {
195            sys::BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD => {
196                Some("Invalid or unsupported incoming L2CAP sig command.")
197            }
198            sys::BLE_L2CAP_SIG_ERR_MTU_EXCEEDED => Some("Incoming packet too large."),
199            sys::BLE_L2CAP_SIG_ERR_INVALID_CID => Some("No channel with specified ID."),
200            _ => None,
201        }
202    }
203    // local Security Manager errors (BLE_HS_ERR_SM_US_BASE : 0x400)
204    else if rc < sys::BLE_HS_ERR_SM_US_BASE + 0x100 {
205        match rc - sys::BLE_HS_ERR_SM_US_BASE {
206            sys::BLE_SM_ERR_PASSKEY => Some(
207                "The user input of passkey failed, for example, the user cancelled the operation.",
208            ),
209            sys::BLE_SM_ERR_OOB => Some("The OOB data is not available."),
210            sys::BLE_SM_ERR_AUTHREQ => Some(
211                "The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices.",
212            ),
213            sys::BLE_SM_ERR_CONFIRM_MISMATCH => {
214                Some("The confirm value does not match the calculated compare value.")
215            }
216            sys::BLE_SM_ERR_PAIR_NOT_SUPP => Some("Pairing is not supported by the device."),
217            sys::BLE_SM_ERR_ENC_KEY_SZ => Some(
218                "The resultant encryption key size is insufficient for the security requirements of this device.",
219            ),
220            sys::BLE_SM_ERR_CMD_NOT_SUPP => {
221                Some("The SMP command received is not supported on this device.")
222            }
223            sys::BLE_SM_ERR_UNSPECIFIED => Some("Pairing failed due to an unspecified reason."),
224            sys::BLE_SM_ERR_REPEATED => Some(
225                "Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request.",
226            ),
227            sys::BLE_SM_ERR_INVAL => Some(
228                "The Invalid Parameters error code indicates that the command length is invalid or that a parameter is outside of the specified range.",
229            ),
230            sys::BLE_SM_ERR_DHKEY => Some(
231                "Indicates to the remote device that the DHKey Check value received doesn’t match the one calculated by the local device.",
232            ),
233            sys::BLE_SM_ERR_NUMCMP => Some(
234                "Indicates that the confirm values in the numeric comparison protocol do not match.",
235            ),
236            sys::BLE_SM_ERR_ALREADY => Some(
237                "Indicates that the pairing over the LE transport failed due to a Pairing Request sent over the BR/EDR transport in process.",
238            ),
239            sys::BLE_SM_ERR_CROSS_TRANS => Some(
240                "Indicates that the BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport.",
241            ),
242            _ => None,
243        }
244    } else {
245        None
246    }
247}
248
249#[cfg(not(feature = "debug"))]
250macro_rules! ble {
251    ($err:expr) => {{ $crate::BLEError::convert($err as _) }};
252}
253#[cfg(feature = "debug")]
254macro_rules! ble {
255  ($err:expr) => {{
256    let rc = $crate::BLEError::convert($err as _);
257    if let Err(err) = rc {
258      ::log::warn!(target: "esp32_nimble", "{}[{}]: {:?}", file!(), line!(), err);
259    }
260    rc
261  }};
262}
263
264pub(crate) use ble;