1 | /* |
2 | * This file is part of the MicroPython project, http://micropython.org/ |
3 | * |
4 | * The MIT License (MIT) |
5 | * |
6 | * Copyright (c) 2018 Ayke van Laethem |
7 | * Copyright (c) 2019-2020 Jim Mussared |
8 | * |
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | * of this software and associated documentation files (the "Software"), to deal |
11 | * in the Software without restriction, including without limitation the rights |
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | * copies of the Software, and to permit persons to whom the Software is |
14 | * furnished to do so, subject to the following conditions: |
15 | * |
16 | * The above copyright notice and this permission notice shall be included in |
17 | * all copies or substantial portions of the Software. |
18 | * |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | * THE SOFTWARE. |
26 | */ |
27 | |
28 | #ifndef MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_H |
29 | #define MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_H |
30 | |
31 | #include <stdbool.h> |
32 | |
33 | #include "py/obj.h" |
34 | #include "py/objlist.h" |
35 | #include "py/ringbuf.h" |
36 | |
37 | // Port specific configuration. |
38 | #ifndef MICROPY_PY_BLUETOOTH_RINGBUF_SIZE |
39 | #define MICROPY_PY_BLUETOOTH_RINGBUF_SIZE (128) |
40 | #endif |
41 | |
42 | #ifndef MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE |
43 | #define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (0) |
44 | #endif |
45 | |
46 | #ifndef MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT |
47 | // Enable the client by default if we're enabling central mode. It's possible |
48 | // to enable client without central though. |
49 | #define MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT (MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE) |
50 | #endif |
51 | |
52 | #ifndef MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS |
53 | // This can be enabled if the BLE stack runs entirely in scheduler context |
54 | // and therefore is able to call directly into the VM to run Python callbacks. |
55 | #define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS (0) |
56 | #endif |
57 | |
58 | // A port can optionally enable support for L2CAP "Connection Oriented Channels". |
59 | #ifndef MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS |
60 | #define MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS (0) |
61 | #endif |
62 | |
63 | // A port can optionally enable support for pairing and bonding. |
64 | // Requires MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS. |
65 | #ifndef MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING |
66 | #define MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING (0) |
67 | #endif |
68 | |
69 | // Optionally enable support for the `hci_cmd` function allowing |
70 | // Python to directly low-level HCI commands. |
71 | #ifndef MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD |
72 | #define MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD (0) |
73 | #endif |
74 | |
75 | // This is used to protect the ringbuffer. |
76 | // A port may no-op this if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS is enabled. |
77 | #ifndef MICROPY_PY_BLUETOOTH_ENTER |
78 | #define MICROPY_PY_BLUETOOTH_ENTER mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); |
79 | #define MICROPY_PY_BLUETOOTH_EXIT MICROPY_END_ATOMIC_SECTION(atomic_state); |
80 | #endif |
81 | |
82 | // Common constants. |
83 | #ifndef MP_BLUETOOTH_DEFAULT_ATTR_LEN |
84 | #define MP_BLUETOOTH_DEFAULT_ATTR_LEN (20) |
85 | #endif |
86 | |
87 | #define MP_BLUETOOTH_CCCB_LEN (2) |
88 | |
89 | // Advertisement packet lengths |
90 | #define MP_BLUETOOTH_GAP_ADV_MAX_LEN (32) |
91 | |
92 | // Basic characteristic/descriptor flags. |
93 | // These match the spec values for these flags so can be passed directly to the stack. |
94 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_BROADCAST (0x0001) |
95 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ (0x0002) |
96 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_NO_RESPONSE (0x0004) |
97 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE (0x0008) |
98 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY (0x0010) |
99 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_INDICATE (0x0020) |
100 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_AUTHENTICATED_SIGNED_WRITE (0x0040) |
101 | |
102 | // TODO: NimBLE and BlueKitchen disagree on this one. |
103 | // #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_RELIABLE_WRITE (0x0080) |
104 | |
105 | // Extended flags for security and privacy. |
106 | // These match NimBLE but might require mapping in the bindings for other stacks. |
107 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_AUX_WRITE (0x0100) |
108 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ_ENCRYPTED (0x0200) |
109 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ_AUTHENTICATED (0x0400) |
110 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ_AUTHORIZED (0x0800) |
111 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_ENCRYPTED (0x1000) |
112 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_AUTHENTICATED (0x2000) |
113 | #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_AUTHORIZED (0x4000) |
114 | |
115 | // Return values from _IRQ_GATTS_READ_REQUEST. |
116 | #define MP_BLUETOOTH_GATTS_NO_ERROR (0x00) |
117 | #define MP_BLUETOOTH_GATTS_ERROR_READ_NOT_PERMITTED (0x02) |
118 | #define MP_BLUETOOTH_GATTS_ERROR_WRITE_NOT_PERMITTED (0x03) |
119 | #define MP_BLUETOOTH_GATTS_ERROR_INSUFFICIENT_AUTHENTICATION (0x05) |
120 | #define MP_BLUETOOTH_GATTS_ERROR_INSUFFICIENT_AUTHORIZATION (0x08) |
121 | #define MP_BLUETOOTH_GATTS_ERROR_INSUFFICIENT_ENCRYPTION (0x0f) |
122 | |
123 | // For mp_bluetooth_gattc_write, the mode parameter |
124 | #define MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE (0) |
125 | #define MP_BLUETOOTH_WRITE_MODE_WITH_RESPONSE (1) |
126 | |
127 | // Type value also doubles as length. |
128 | #define MP_BLUETOOTH_UUID_TYPE_16 (2) |
129 | #define MP_BLUETOOTH_UUID_TYPE_32 (4) |
130 | #define MP_BLUETOOTH_UUID_TYPE_128 (16) |
131 | |
132 | // Event codes for the IRQ handler. |
133 | #define MP_BLUETOOTH_IRQ_CENTRAL_CONNECT (1) |
134 | #define MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT (2) |
135 | #define MP_BLUETOOTH_IRQ_GATTS_WRITE (3) |
136 | #define MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST (4) |
137 | #define MP_BLUETOOTH_IRQ_SCAN_RESULT (5) |
138 | #define MP_BLUETOOTH_IRQ_SCAN_DONE (6) |
139 | #define MP_BLUETOOTH_IRQ_PERIPHERAL_CONNECT (7) |
140 | #define MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT (8) |
141 | #define MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT (9) |
142 | #define MP_BLUETOOTH_IRQ_GATTC_SERVICE_DONE (10) |
143 | #define MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT (11) |
144 | #define MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_DONE (12) |
145 | #define MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT (13) |
146 | #define MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_DONE (14) |
147 | #define MP_BLUETOOTH_IRQ_GATTC_READ_RESULT (15) |
148 | #define MP_BLUETOOTH_IRQ_GATTC_READ_DONE (16) |
149 | #define MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE (17) |
150 | #define MP_BLUETOOTH_IRQ_GATTC_NOTIFY (18) |
151 | #define MP_BLUETOOTH_IRQ_GATTC_INDICATE (19) |
152 | #define MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE (20) |
153 | #define MP_BLUETOOTH_IRQ_MTU_EXCHANGED (21) |
154 | #define MP_BLUETOOTH_IRQ_L2CAP_ACCEPT (22) |
155 | #define MP_BLUETOOTH_IRQ_L2CAP_CONNECT (23) |
156 | #define MP_BLUETOOTH_IRQ_L2CAP_DISCONNECT (24) |
157 | #define MP_BLUETOOTH_IRQ_L2CAP_RECV (25) |
158 | #define MP_BLUETOOTH_IRQ_L2CAP_SEND_READY (26) |
159 | #define MP_BLUETOOTH_IRQ_CONNECTION_UPDATE (27) |
160 | #define MP_BLUETOOTH_IRQ_ENCRYPTION_UPDATE (28) |
161 | #define MP_BLUETOOTH_IRQ_GET_SECRET (29) |
162 | #define MP_BLUETOOTH_IRQ_SET_SECRET (30) |
163 | #define MP_BLUETOOTH_IRQ_PASSKEY_ACTION (31) |
164 | |
165 | #define MP_BLUETOOTH_ADDRESS_MODE_PUBLIC (0) |
166 | #define MP_BLUETOOTH_ADDRESS_MODE_RANDOM (1) |
167 | #define MP_BLUETOOTH_ADDRESS_MODE_RPA (2) |
168 | #define MP_BLUETOOTH_ADDRESS_MODE_NRPA (3) |
169 | |
170 | // These match the spec values, can be used directly by the stack. |
171 | #define MP_BLUETOOTH_IO_CAPABILITY_DISPLAY_ONLY (0) |
172 | #define MP_BLUETOOTH_IO_CAPABILITY_DISPLAY_YESNO (1) |
173 | #define MP_BLUETOOTH_IO_CAPABILITY_KEYBOARD_ONLY (2) |
174 | #define MP_BLUETOOTH_IO_CAPABILITY_NO_INPUT_OUTPUT (3) |
175 | #define MP_BLUETOOTH_IO_CAPABILITY_KEYBOARD_DISPLAY (4) |
176 | |
177 | // These match NimBLE BLE_SM_IOACT_. |
178 | #define MP_BLUETOOTH_PASSKEY_ACTION_NONE (0) |
179 | #define MP_BLUETOOTH_PASSKEY_ACTION_INPUT (2) |
180 | #define MP_BLUETOOTH_PASSKEY_ACTION_DISPLAY (3) |
181 | #define MP_BLUETOOTH_PASSKEY_ACTION_NUMERIC_COMPARISON (4) |
182 | |
183 | // These match NimBLE BLE_SM_IOACT_. |
184 | #define MP_BLUETOOTH_PASSKEY_ACTION_NONE (0) |
185 | #define MP_BLUETOOTH_PASSKEY_ACTION_INPUT (2) |
186 | #define MP_BLUETOOTH_PASSKEY_ACTION_DISPLAY (3) |
187 | #define MP_BLUETOOTH_PASSKEY_ACTION_NUMERIC_COMPARISON (4) |
188 | |
189 | /* |
190 | These aren't included in the module for space reasons, but can be used |
191 | in your Python code if necessary. |
192 | |
193 | from micropython import const |
194 | _IRQ_CENTRAL_CONNECT = const(1) |
195 | _IRQ_CENTRAL_DISCONNECT = const(2) |
196 | _IRQ_GATTS_WRITE = const(3) |
197 | _IRQ_GATTS_READ_REQUEST = const(4) |
198 | _IRQ_SCAN_RESULT = const(5) |
199 | _IRQ_SCAN_DONE = const(6) |
200 | _IRQ_PERIPHERAL_CONNECT = const(7) |
201 | _IRQ_PERIPHERAL_DISCONNECT = const(8) |
202 | _IRQ_GATTC_SERVICE_RESULT = const(9) |
203 | _IRQ_GATTC_SERVICE_DONE = const(10) |
204 | _IRQ_GATTC_CHARACTERISTIC_RESULT = const(11) |
205 | _IRQ_GATTC_CHARACTERISTIC_DONE = const(12) |
206 | _IRQ_GATTC_DESCRIPTOR_RESULT = const(13) |
207 | _IRQ_GATTC_DESCRIPTOR_DONE = const(14) |
208 | _IRQ_GATTC_READ_RESULT = const(15) |
209 | _IRQ_GATTC_READ_DONE = const(16) |
210 | _IRQ_GATTC_WRITE_DONE = const(17) |
211 | _IRQ_GATTC_NOTIFY = const(18) |
212 | _IRQ_GATTC_INDICATE = const(19) |
213 | _IRQ_GATTS_INDICATE_DONE = const(20) |
214 | _IRQ_MTU_EXCHANGED = const(21) |
215 | _IRQ_L2CAP_ACCEPT = const(22) |
216 | _IRQ_L2CAP_CONNECT = const(23) |
217 | _IRQ_L2CAP_DISCONNECT = const(24) |
218 | _IRQ_L2CAP_RECV = const(25) |
219 | _IRQ_L2CAP_SEND_READY = const(26) |
220 | _IRQ_CONNECTION_UPDATE = const(27) |
221 | _IRQ_ENCRYPTION_UPDATE = const(28) |
222 | _IRQ_GET_SECRET = const(29) |
223 | _IRQ_SET_SECRET = const(30) |
224 | _IRQ_PASSKEY_ACTION = const(31) |
225 | |
226 | _FLAG_BROADCAST = const(0x0001) |
227 | _FLAG_READ = const(0x0002) |
228 | _FLAG_WRITE_NO_RESPONSE = const(0x0004) |
229 | _FLAG_WRITE = const(0x0008) |
230 | _FLAG_NOTIFY = const(0x0010) |
231 | _FLAG_INDICATE = const(0x0020) |
232 | _FLAG_AUTHENTICATED_SIGNED_WRITE = const(0x0040) |
233 | |
234 | _FLAG_AUX_WRITE = const(0x0100) |
235 | _FLAG_READ_ENCRYPTED = const(0x0200) |
236 | _FLAG_READ_AUTHENTICATED = const(0x0400) |
237 | _FLAG_READ_AUTHORIZED = const(0x0800) |
238 | _FLAG_WRITE_ENCRYPTED = const(0x1000) |
239 | _FLAG_WRITE_AUTHENTICATED = const(0x2000) |
240 | _FLAG_WRITE_AUTHORIZED = const(0x4000) |
241 | |
242 | _GATTS_NO_ERROR = const(0x00) |
243 | _GATTS_ERROR_READ_NOT_PERMITTED = const(0x02) |
244 | _GATTS_ERROR_WRITE_NOT_PERMITTED = const(0x03) |
245 | _GATTS_ERROR_INSUFFICIENT_AUTHENTICATION = const(0x05) |
246 | _GATTS_ERROR_INSUFFICIENT_AUTHORIZATION = const(0x08) |
247 | _GATTS_ERROR_INSUFFICIENT_ENCRYPTION = const(0x0f) |
248 | |
249 | _IO_CAPABILITY_DISPLAY_ONLY = const(0) |
250 | _IO_CAPABILITY_DISPLAY_YESNO = const(1) |
251 | _IO_CAPABILITY_KEYBOARD_ONLY = const(2) |
252 | _IO_CAPABILITY_NO_INPUT_OUTPUT = const(3) |
253 | _IO_CAPABILITY_KEYBOARD_DISPLAY = const(4) |
254 | |
255 | _PASSKEY_ACTION_NONE = const(0) |
256 | _PASSKEY_ACTION_INPUT = const(2) |
257 | _PASSKEY_ACTION_DISPLAY = const(3) |
258 | _PASSKEY_ACTION_NUMERIC_COMPARISON = const(4) |
259 | */ |
260 | |
261 | // bluetooth.UUID type. |
262 | // Ports are expected to map this to their own internal UUID types. |
263 | // Internally the UUID data is little-endian, but the user should only |
264 | // ever see this if they use the buffer protocol, e.g. in order to |
265 | // construct an advertising payload (which needs to be in LE). |
266 | // Both the constructor and the print function work in BE. |
267 | typedef struct { |
268 | mp_obj_base_t base; |
269 | uint8_t type; |
270 | uint8_t data[16]; |
271 | } mp_obj_bluetooth_uuid_t; |
272 | |
273 | extern const mp_obj_type_t mp_type_bluetooth_uuid; |
274 | |
275 | ////////////////////////////////////////////////////////////// |
276 | // API implemented by ports (i.e. called from modbluetooth.c): |
277 | |
278 | // TODO: At the moment this only allows for a single `Bluetooth` instance to be created. |
279 | // Ideally in the future we'd be able to have multiple instances or to select a specific BT driver or HCI UART. |
280 | // So these global methods should be replaced with a struct of function pointers (like the machine.I2C implementations). |
281 | |
282 | // Any method returning an int returns errno on failure, otherwise zero. |
283 | |
284 | // Note: All methods dealing with addresses (as 6-byte uint8 pointers) are in big-endian format. |
285 | // (i.e. the same way they would be printed on a device sticker or in a UI), so the user sees |
286 | // addresses in a way that looks like what they'd expect. |
287 | // This means that the lower level implementation will likely need to reorder them (e.g. Nimble |
288 | // works in little-endian, as does BLE itself). |
289 | |
290 | // Enables the Bluetooth stack. |
291 | int mp_bluetooth_init(void); |
292 | |
293 | // Disables the Bluetooth stack. Is a no-op when not enabled. |
294 | void mp_bluetooth_deinit(void); |
295 | |
296 | // Returns true when the Bluetooth stack is active. |
297 | bool mp_bluetooth_is_active(void); |
298 | |
299 | // Gets the current address of this device in big-endian format. |
300 | void mp_bluetooth_get_current_address(uint8_t *addr_type, uint8_t *addr); |
301 | |
302 | // Sets the addressing mode to use. |
303 | void mp_bluetooth_set_address_mode(uint8_t addr_mode); |
304 | |
305 | #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING |
306 | // Set bonding flag in pairing requests (i.e. persist security keys). |
307 | void mp_bluetooth_set_bonding(bool enabled); |
308 | // Require MITM protection. |
309 | void mp_bluetooth_set_mitm_protection(bool enabled); |
310 | // Require LE Secure pairing (rather than Legacy Pairing) |
311 | void mp_bluetooth_set_le_secure(bool enabled); |
312 | // I/O capabilities for authentication (see MP_BLUETOOTH_IO_CAPABILITY_*). |
313 | void mp_bluetooth_set_io_capability(uint8_t capability); |
314 | #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING |
315 | |
316 | // Get or set the GAP device name that will be used by service 0x1800, characteristic 0x2a00. |
317 | size_t mp_bluetooth_gap_get_device_name(const uint8_t **buf); |
318 | int mp_bluetooth_gap_set_device_name(const uint8_t *buf, size_t len); |
319 | |
320 | // Start advertisement. Will re-start advertisement when already enabled. |
321 | // Returns errno on failure. |
322 | int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len); |
323 | |
324 | // Stop advertisement. No-op when already stopped. |
325 | void mp_bluetooth_gap_advertise_stop(void); |
326 | |
327 | // Start adding services. Must be called before mp_bluetooth_register_service. |
328 | int mp_bluetooth_gatts_register_service_begin(bool append); |
329 | // Add a service with the given list of characteristics to the queue to be registered. |
330 | // The value_handles won't be valid until after mp_bluetooth_register_service_end is called. |
331 | int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint16_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint16_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics); |
332 | // Register any queued services. |
333 | int mp_bluetooth_gatts_register_service_end(void); |
334 | |
335 | // Read the value from the local gatts db (likely this has been written by a central). |
336 | int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len); |
337 | // Write a value to the local gatts db (ready to be queried by a central). |
338 | int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len); |
339 | // Notify the central that it should do a read. |
340 | int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle); |
341 | // Notify the central, including a data payload. (Note: does not set the gatts db value). |
342 | int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len); |
343 | // Indicate the central. |
344 | int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle); |
345 | |
346 | // Resize and enable/disable append-mode on a value. |
347 | // Append-mode means that remote writes will append and local reads will clear after reading. |
348 | int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append); |
349 | |
350 | // Disconnect from a central or peripheral. |
351 | int mp_bluetooth_gap_disconnect(uint16_t conn_handle); |
352 | |
353 | // Set/get the MTU that we will respond to a MTU exchange with. |
354 | int mp_bluetooth_get_preferred_mtu(void); |
355 | int mp_bluetooth_set_preferred_mtu(uint16_t mtu); |
356 | |
357 | #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING |
358 | // Initiate pairing on the specified connection. |
359 | int mp_bluetooth_gap_pair(uint16_t conn_handle); |
360 | |
361 | // Respond to a pairing request. |
362 | int mp_bluetooth_gap_passkey(uint16_t conn_handle, uint8_t action, mp_int_t passkey); |
363 | #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING |
364 | |
365 | #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE |
366 | // Start a discovery (scan). Set duration to zero to run continuously. |
367 | int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_t window_us, bool active_scan); |
368 | |
369 | // Stop discovery (if currently active). |
370 | int mp_bluetooth_gap_scan_stop(void); |
371 | |
372 | // Connect to a found peripheral. |
373 | int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms); |
374 | #endif |
375 | |
376 | #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT |
377 | // Find all primary services on the connected peripheral. |
378 | int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid); |
379 | |
380 | // Find all characteristics on the specified service on a connected peripheral. |
381 | int mp_bluetooth_gattc_discover_characteristics(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, const mp_obj_bluetooth_uuid_t *uuid); |
382 | |
383 | // Find all descriptors on the specified characteristic on a connected peripheral. |
384 | int mp_bluetooth_gattc_discover_descriptors(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle); |
385 | |
386 | // Initiate read of a value from the remote peripheral. |
387 | int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle); |
388 | |
389 | // Write the value to the remote peripheral. |
390 | int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len, unsigned int mode); |
391 | |
392 | // Initiate MTU exchange for a specific connection using the preferred MTU. |
393 | int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle); |
394 | #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT |
395 | |
396 | #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS |
397 | int mp_bluetooth_l2cap_listen(uint16_t psm, uint16_t mtu); |
398 | int mp_bluetooth_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu); |
399 | int mp_bluetooth_l2cap_disconnect(uint16_t conn_handle, uint16_t cid); |
400 | int mp_bluetooth_l2cap_send(uint16_t conn_handle, uint16_t cid, const uint8_t *buf, size_t len, bool *stalled); |
401 | int mp_bluetooth_l2cap_recvinto(uint16_t conn_handle, uint16_t cid, uint8_t *buf, size_t *len); |
402 | #endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS |
403 | |
404 | #if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD |
405 | int mp_bluetooth_hci_cmd(uint16_t ogf, uint16_t ocf, const uint8_t *req, size_t req_len, uint8_t *resp, size_t resp_len, uint8_t *status); |
406 | #endif // MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD |
407 | |
408 | ///////////////////////////////////////////////////////////////////////////// |
409 | // API implemented by modbluetooth (called by port-specific implementations): |
410 | |
411 | // Notify modbluetooth that a connection/disconnection event has occurred. |
412 | void mp_bluetooth_gap_on_connected_disconnected(uint8_t event, uint16_t conn_handle, uint8_t addr_type, const uint8_t *addr); |
413 | |
414 | // Call this when any connection parameters have been changed. |
415 | void mp_bluetooth_gap_on_connection_update(uint16_t conn_handle, uint16_t conn_interval, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t status); |
416 | |
417 | #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING |
418 | // Call this when any connection encryption has been changed (e.g. during pairing). |
419 | void mp_bluetooth_gatts_on_encryption_update(uint16_t conn_handle, bool encrypted, bool authenticated, bool bonded, uint8_t key_size); |
420 | |
421 | // Call this when you need the application to manage persistent key data. |
422 | // For get, if key is NULL, then the implementation must return the index'th matching key. Otherwise it should return a specific key. |
423 | // For set, if value is NULL, then delete. |
424 | // The "type" is stack-specific, but could also be used to implement versioning. |
425 | bool mp_bluetooth_gap_on_get_secret(uint8_t type, uint8_t index, const uint8_t *key, size_t key_len, const uint8_t **value, size_t *value_len); |
426 | bool mp_bluetooth_gap_on_set_secret(uint8_t type, const uint8_t *key, size_t key_len, const uint8_t *value, size_t value_len); |
427 | |
428 | // Call this when a passkey verification needs to be processed. |
429 | void mp_bluetooth_gap_on_passkey_action(uint16_t conn_handle, uint8_t action, mp_int_t passkey); |
430 | #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING |
431 | |
432 | // Call this when a characteristic is written to. |
433 | void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle); |
434 | |
435 | // Call this when an acknowledgment is received for an indication. |
436 | void mp_bluetooth_gatts_on_indicate_complete(uint16_t conn_handle, uint16_t value_handle, uint8_t status); |
437 | |
438 | // Call this when a characteristic is read from (giving the handler a chance to update the stored value). |
439 | // Return 0 to allow the read, otherwise a non-zero rejection reason (see MP_BLUETOOTH_GATTS_ERROR_*). |
440 | mp_int_t mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle); |
441 | |
442 | // Call this when an MTU exchange completes. |
443 | void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value); |
444 | |
445 | #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE |
446 | // Notify modbluetooth that scan has finished, either timeout, manually, or by some other action (e.g. connecting). |
447 | void mp_bluetooth_gap_on_scan_complete(void); |
448 | |
449 | // Notify modbluetooth of a scan result. |
450 | void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uint8_t adv_type, const int8_t rssi, const uint8_t *data, size_t data_len); |
451 | #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE |
452 | |
453 | #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT |
454 | // Notify modbluetooth that a service was found (either by discover-all, or discover-by-uuid). |
455 | void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid); |
456 | |
457 | // Notify modbluetooth that a characteristic was found (either by discover-all-on-service, or discover-by-uuid-on-service). |
458 | void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t def_handle, uint16_t value_handle, uint8_t properties, mp_obj_bluetooth_uuid_t *characteristic_uuid); |
459 | |
460 | // Notify modbluetooth that a descriptor was found. |
461 | void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid); |
462 | |
463 | // Notify modbluetooth that service, characteristic or descriptor discovery has finished. |
464 | void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle, uint16_t status); |
465 | |
466 | // Notify modbluetooth that a read has completed with data (or notify/indicate data available, use `event` to disambiguate). |
467 | void mp_bluetooth_gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t **data, uint16_t *data_len, size_t num); |
468 | |
469 | // Notify modbluetooth that a read or write operation has completed. |
470 | void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status); |
471 | #endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT |
472 | |
473 | #if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS |
474 | mp_int_t mp_bluetooth_on_l2cap_accept(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu); |
475 | void mp_bluetooth_on_l2cap_connect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu); |
476 | void mp_bluetooth_on_l2cap_disconnect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t status); |
477 | void mp_bluetooth_on_l2cap_send_ready(uint16_t conn_handle, uint16_t cid, uint8_t status); |
478 | void mp_bluetooth_on_l2cap_recv(uint16_t conn_handle, uint16_t cid); |
479 | #endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS |
480 | |
481 | // For stacks that don't manage attribute value data (currently all of them), helpers |
482 | // to store this in a map, keyed by value handle. |
483 | |
484 | typedef struct { |
485 | // Pointer to heap-allocated data. |
486 | uint8_t *data; |
487 | // Allocated size of data. |
488 | size_t data_alloc; |
489 | // Current bytes in use. |
490 | size_t data_len; |
491 | // Whether new writes append or replace existing data (default false). |
492 | bool append; |
493 | } mp_bluetooth_gatts_db_entry_t; |
494 | |
495 | typedef mp_map_t *mp_gatts_db_t; |
496 | |
497 | STATIC inline void mp_bluetooth_gatts_db_create(mp_gatts_db_t *db) { |
498 | *db = m_new(mp_map_t, 1); |
499 | } |
500 | |
501 | STATIC inline void mp_bluetooth_gatts_db_reset(mp_gatts_db_t db) { |
502 | mp_map_init(db, 0); |
503 | } |
504 | |
505 | void mp_bluetooth_gatts_db_create_entry(mp_gatts_db_t db, uint16_t handle, size_t len); |
506 | mp_bluetooth_gatts_db_entry_t *mp_bluetooth_gatts_db_lookup(mp_gatts_db_t db, uint16_t handle); |
507 | int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, uint8_t **value, size_t *value_len); |
508 | int mp_bluetooth_gatts_db_write(mp_gatts_db_t db, uint16_t handle, const uint8_t *value, size_t value_len); |
509 | int mp_bluetooth_gatts_db_resize(mp_gatts_db_t db, uint16_t handle, size_t len, bool append); |
510 | |
511 | #endif // MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_H |
512 | |