esp_idf_svc/ble/gatt.rs
1//! NimBLE GATT: shared types and helpers.
2
3use core::ffi::c_int;
4
5#[cfg(esp_idf_bt_nimble_gatt_server)]
6use enumset::{EnumSet, EnumSetType};
7
8use crate::sys::*;
9
10use super::{BleError, ConnHandle};
11
12#[cfg(esp_idf_bt_nimble_gatt_client)]
13pub mod client;
14#[cfg(esp_idf_bt_nimble_gatt_server)]
15pub mod server;
16
17/// A GATT attribute handle (e.g. a characteristic's value handle).
18pub type AttrHandle = u16;
19
20/// Set the preferred ATT MTU. Safe to call before or after the host starts.
21pub fn set_preferred_mtu(mtu: u16) -> Result<(), BleError> {
22 BleError::from_raw(unsafe { ble_att_set_preferred_mtu(mtu) })
23}
24
25/// The negotiated ATT MTU for a connection
26pub fn att_mtu(conn_handle: ConnHandle) -> Result<u16, BleError> {
27 match unsafe { ble_att_mtu(conn_handle) } {
28 0 => Err(BleError::new(BLE_HS_ENOTCONN as c_int)),
29 mtu => Ok(mtu),
30 }
31}
32
33/// A GATT characteristic operation / permission flag (`BLE_GATT_CHR_F_*`).
34///
35/// The operation flags become the property bits of the characteristic declaration (and gate what
36/// the ATT server lets a peer do); the `*Enc` / `*Authen` / `*Author` flags additionally demand a
37/// security level before the access is dispatched to the
38/// [`gatts_subscribe`](crate::ble::BleDriver::gatts_subscribe) hook.
39#[cfg(esp_idf_bt_nimble_gatt_server)]
40#[derive(Debug, EnumSetType)]
41pub enum BleGattCharFlag {
42 /// The value may be broadcast (sets the Broadcast property bit).
43 Broadcast,
44 /// The peer may read the value.
45 Read,
46 /// The peer may write the value **without** a response (ATT Write Command). Independent of
47 /// [`Write`](Self::Write) — a peer cannot use write-without-response unless this flag is set —
48 /// but both kinds of write arrive as the same
49 /// [`GattsEvent::Write`](server::GattsEvent::Write), as NimBLE does not report which ATT
50 /// opcode carried them.
51 WriteNoRsp,
52 /// The peer may write the value **with** a response (ATT Write Request).
53 Write,
54 /// The value may be notified (unacknowledged). NimBLE adds the CCCD for you.
55 Notify,
56 /// The value may be indicated (acknowledged). NimBLE adds the CCCD for you.
57 Indicate,
58 /// The peer may write the value with a signature (ATT Signed Write Command).
59 AuthSignWrite,
60 /// Sets the "Reliable Write" extended property (prepare/execute writes). The queued writes are
61 /// coalesced by NimBLE and delivered as a single [`Write`](server::GattsEvent::Write).
62 ReliableWrite,
63 /// Sets the "Writable Auxiliaries" extended property (the Characteristic User Description
64 /// descriptor is writable).
65 AuxWrite,
66 /// Reads require an encrypted link.
67 ReadEnc,
68 /// Reads require an encrypted link from an authenticated (MITM-protected) pairing.
69 ReadAuthen,
70 /// Reads require authorization.
71 ///
72 /// **Not usable yet:** NimBLE asks the application to authorize the access through the
73 /// `BLE_GAP_EVENT_AUTHORIZE` GAP event, which this crate does not surface (it arrives as
74 /// [`GapEvent::Other`](crate::ble::gap::GapEvent::Other), whose response cannot be set), and
75 /// NimBLE rejects an unanswered request — so setting this flag currently fails every read with
76 /// "insufficient authorization".
77 ReadAuthor,
78 /// Writes require an encrypted link.
79 WriteEnc,
80 /// Writes require an encrypted link from an authenticated (MITM-protected) pairing.
81 WriteAuthen,
82 /// Writes require authorization. Carries the same caveat as [`ReadAuthor`](Self::ReadAuthor).
83 WriteAuthor,
84 /// Subscribing (writing the CCCD) requires an encrypted link.
85 #[cfg(esp_idf_version_at_least_5_5_0)]
86 NotifyIndicateEnc,
87 /// Subscribing (writing the CCCD) requires an encrypted link from an authenticated
88 /// (MITM-protected) pairing.
89 #[cfg(esp_idf_version_at_least_5_5_0)]
90 NotifyIndicateAuthen,
91 /// Subscribing (writing the CCCD) requires authorization. Carries the same caveat as
92 /// [`ReadAuthor`](Self::ReadAuthor).
93 #[cfg(esp_idf_version_at_least_5_5_0)]
94 NotifyIndicateAuthor,
95}
96
97#[cfg(esp_idf_bt_nimble_gatt_server)]
98impl BleGattCharFlag {
99 /// The raw NimBLE flag bit (`BLE_GATT_CHR_F_*`). `const`, so it can be used to build a static
100 /// service table (see the [`gatt_services!`](crate::gatt_services) macro).
101 pub const fn repr(self) -> ble_gatt_chr_flags {
102 match self {
103 Self::Broadcast => BLE_GATT_CHR_F_BROADCAST,
104 Self::Read => BLE_GATT_CHR_F_READ,
105 Self::WriteNoRsp => BLE_GATT_CHR_F_WRITE_NO_RSP,
106 Self::Write => BLE_GATT_CHR_F_WRITE,
107 Self::Notify => BLE_GATT_CHR_F_NOTIFY,
108 Self::Indicate => BLE_GATT_CHR_F_INDICATE,
109 Self::AuthSignWrite => BLE_GATT_CHR_F_AUTH_SIGN_WRITE,
110 Self::ReliableWrite => BLE_GATT_CHR_F_RELIABLE_WRITE,
111 Self::AuxWrite => BLE_GATT_CHR_F_AUX_WRITE,
112 Self::ReadEnc => BLE_GATT_CHR_F_READ_ENC,
113 Self::ReadAuthen => BLE_GATT_CHR_F_READ_AUTHEN,
114 Self::ReadAuthor => BLE_GATT_CHR_F_READ_AUTHOR,
115 Self::WriteEnc => BLE_GATT_CHR_F_WRITE_ENC,
116 Self::WriteAuthen => BLE_GATT_CHR_F_WRITE_AUTHEN,
117 Self::WriteAuthor => BLE_GATT_CHR_F_WRITE_AUTHOR,
118 // The CCCD-write permission flags only exist from ESP-IDF 5.5 on.
119 #[cfg(esp_idf_version_at_least_5_5_0)]
120 Self::NotifyIndicateEnc => BLE_GATT_CHR_F_NOTIFY_INDICATE_ENC,
121 #[cfg(esp_idf_version_at_least_5_5_0)]
122 Self::NotifyIndicateAuthen => BLE_GATT_CHR_F_NOTIFY_INDICATE_AUTHEN,
123 #[cfg(esp_idf_version_at_least_5_5_0)]
124 Self::NotifyIndicateAuthor => BLE_GATT_CHR_F_NOTIFY_INDICATE_AUTHOR,
125 }
126 }
127}
128
129#[cfg(esp_idf_bt_nimble_gatt_server)]
130impl From<BleGattCharFlag> for ble_gatt_chr_flags {
131 fn from(flag: BleGattCharFlag) -> Self {
132 flag.repr()
133 }
134}
135
136#[cfg(esp_idf_bt_nimble_gatt_server)]
137pub(crate) fn flags_to_repr(flags: EnumSet<BleGattCharFlag>) -> ble_gatt_chr_flags {
138 flags
139 .iter()
140 .fold(0, |acc, flag| acc | ble_gatt_chr_flags::from(flag))
141}