Skip to content

Commit dc82bee

Browse files
committed
docs/library/bluetooth: Add initial BLE documentation.
1 parent 76f4741 commit dc82bee

File tree

2 files changed

+309
-0
lines changed

2 files changed

+309
-0
lines changed

docs/library/bluetooth.rst

+308
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
:mod:`bluetooth` --- low-level Bluetooth
2+
========================================
3+
4+
.. module:: bluetooth
5+
:synopsis: Low-level Bluetooth radio functionality
6+
7+
This module provides an interface to a Bluetooth controller on a board.
8+
Currently this supports Bluetooth Low Energy (BLE) in Central, Peripheral,
9+
Broadcaster, and Observer roles.
10+
11+
This API is intended to match the low-level Bluetooth protocol and provide
12+
building-blocks for higher-level abstractions such as specific device types.
13+
14+
class BLE
15+
---------
16+
17+
Constructor
18+
-----------
19+
20+
.. class:: BLE()
21+
22+
Returns the singleton BLE object.
23+
24+
Configuration
25+
-------------
26+
27+
.. method:: BLE.active([active])
28+
29+
Optionally changes the active state of the BLE radio, and returns the
30+
current state.
31+
32+
The radio must be made active before using any other methods on this class.
33+
34+
.. method:: BLE.config(name)
35+
36+
Queries a configuration value by *name*. Currently supported values are:
37+
38+
- ``'mac'``: Returns the device MAC address. If a device has a fixed address
39+
(e.g. PYBD) then it will be returned. Otherwise (e.g. ESP32) a random
40+
address will be generated when the BLE interface is made active.
41+
42+
Event Handling
43+
--------------
44+
45+
.. method:: BLE.irq(handler, trigger=0xffff)
46+
47+
Registers a callback for events from the BLE stack. The *handler* takes two
48+
arguments, ``event`` (which will be one of the codes below) and ``data``
49+
(which is an event-specific tuple of values).
50+
51+
The optional *trigger* parameter allows you to set a mask of events that
52+
your program is interested in. The default is all events.
53+
54+
An event handler showing all possible events::
55+
56+
def bt_irq(event, data):
57+
if event == _IRQ_CENTRAL_CONNECT:
58+
# A central has connected to this peripheral.
59+
conn_handle, addr_type, addr = data
60+
elif event == _IRQ_CENTRAL_DISCONNECT:
61+
# A central has disconnected from this peripheral.
62+
conn_handle, addr_type, addr = data
63+
elif event == _IRQ_GATTS_WRITE:
64+
# A central has written to this characteristic or descriptor.
65+
conn_handle, attr_handle = data
66+
elif event == _IRQ_GATTS_READ_REQUEST:
67+
# A central has issued a read. Note: this is a hard IRQ.
68+
# Return None to deny the read.
69+
conn_handle, attr_handle = data
70+
elif event == _IRQ_SCAN_RESULT:
71+
# A single scan result.
72+
addr_type, addr, connectable, rssi, adv_data = data
73+
elif event == _IRQ_SCAN_COMPLETE:
74+
# Scan duration finished or manually stopped.
75+
pass
76+
elif event == _IRQ_PERIPHERAL_CONNECT:
77+
# A successful gap_connect().
78+
conn_handle, addr_type, addr = data
79+
elif event == _IRQ_PERIPHERAL_DISCONNECT:
80+
# Connected peripheral has disconnected.
81+
conn_handle, addr_type, addr = data
82+
elif event == _IRQ_GATTC_SERVICE_RESULT:
83+
# Called for each service found by gattc_discover_services().
84+
conn_handle, start_handle, end_handle, uuid = data
85+
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
86+
# Called for each characteristic found by gattc_discover_services().
87+
conn_handle, def_handle, value_handle, properties, uuid = data
88+
elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:
89+
# Called for each descriptor found by gattc_discover_descriptors().
90+
conn_handle, dsc_handle, uuid = data
91+
elif event == _IRQ_GATTC_READ_RESULT:
92+
# A gattc_read() has completed.
93+
conn_handle, value_handle, char_data = data
94+
elif event == _IRQ_GATTC_WRITE_STATUS:
95+
# A gattc_write() has completed.
96+
conn_handle, value_handle, status = data
97+
elif event == _IRQ_GATTC_NOTIFY:
98+
# A peripheral has sent a notify request.
99+
conn_handle, value_handle, notify_data = data
100+
elif event == _IRQ_GATTC_INDICATE:
101+
# A peripheral has sent an indicate request.
102+
conn_handle, value_handle, notify_data = data
103+
104+
The event codes are::
105+
106+
from micropython import const
107+
_IRQ_CENTRAL_CONNECT = const(1 << 0)
108+
_IRQ_CENTRAL_DISCONNECT = const(1 << 1)
109+
_IRQ_GATTS_WRITE = const(1 << 2)
110+
_IRQ_GATTS_READ_REQUEST = const(1 << 3)
111+
_IRQ_SCAN_RESULT = const(1 << 4)
112+
_IRQ_SCAN_COMPLETE = const(1 << 5)
113+
_IRQ_PERIPHERAL_CONNECT = const(1 << 6)
114+
_IRQ_PERIPHERAL_DISCONNECT = const(1 << 7)
115+
_IRQ_GATTC_SERVICE_RESULT = const(1 << 8)
116+
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(1 << 9)
117+
_IRQ_GATTC_DESCRIPTOR_RESULT = const(1 << 10)
118+
_IRQ_GATTC_READ_RESULT = const(1 << 11)
119+
_IRQ_GATTC_WRITE_STATUS = const(1 << 12)
120+
_IRQ_GATTC_NOTIFY = const(1 << 13)
121+
_IRQ_GATTC_INDICATE = const(1 << 14)
122+
123+
In order to save space in the firmware, these constants are not included on the
124+
:mod:`bluetooth` module. Add the ones that you need from the list above to your
125+
program.
126+
127+
128+
Broadcaster Role (Advertiser)
129+
-----------------------------
130+
131+
.. method:: BLE.gap_advertise(interval_us, adv_data=None, resp_data=None, connectable=True)
132+
133+
Starts advertising at the specified interval (in **micro**\ seconds). This
134+
interval will be rounded down to the nearest 625us. To stop advertising, set
135+
*interval_us* to ``None``.
136+
137+
*adv_data* and *resp_data* can be any type that implements the buffer
138+
protocol (e.g. ``bytes``, ``bytearray``, ``str``). *adv_data* is included
139+
in all broadcasts, and *resp_data* is send in reply to an active scan.
140+
141+
142+
Observer Role (Scanner)
143+
-----------------------
144+
145+
.. method:: BLE.gap_scan(duration_ms, [interval_us], [window_us])
146+
147+
Run a scan operation lasting for the specified duration (in **milli**\ seconds).
148+
149+
To scan indefinitely, set *duration_ms* to ``0``.
150+
151+
To stop scanning, set *duration_ms* to ``None``.
152+
153+
Use *interval_us* and *window_us* to optionally configure the duty cycle.
154+
The scanner will run for *window_us* **micro**\ seconds every *interval_us*
155+
**micro**\ seconds for a total of *duration_ms* **milli**\ seconds. The default
156+
interval and window are 1.28 seconds and 11.25 milliseconds respectively
157+
(background scanning).
158+
159+
For each scan result, the ``_IRQ_SCAN_RESULT`` event will be raised.
160+
161+
When scanning is stopped (either due to the duration finishing or when
162+
explicitly stopped), the ``_IRQ_SCAN_COMPLETE`` event will be raised.
163+
164+
165+
Peripheral Role (GATT Server)
166+
-----------------------------
167+
168+
A BLE peripheral has a set of registered services. Each service may contain
169+
characteristics, which each have a value. Characteristics can also contain
170+
descriptors, which themselves have values.
171+
172+
These values are stored locally and can be read from or written to by a remote
173+
central device. Additionally, a peripheral can "notify" its value to a connected
174+
central via its connection handle.
175+
176+
.. method:: BLE.gatts_register_services(services_definition)
177+
178+
Configures the peripheral with the specified services, replacing any
179+
existing services.
180+
181+
*services_definition* is a list of **services**, where each **service** is a
182+
two-element tuple containing a UUID and a list of **characteristics**.
183+
184+
Each **characteristic** is a two-or-three-element tuple containing a UUID, a
185+
**flags** value, and optionally a list of *descriptors*.
186+
187+
Each **descriptor** is a two-element tuple containing a UUID and a **flags**
188+
value.
189+
190+
The **flags** are a bitwise-OR combination of the
191+
:data:`bluetooth.FLAGS_READ`, :data:`bluetooth.FLAGS_WRITE` and
192+
:data:`bluetooth.FLAGS_NOTIFY` values defined below.
193+
194+
The return value is a list (one element per service) of tuples (each element
195+
is a value handle). Characteristics and descriptor handles are flattened
196+
into the same tuple, in the order that they are defined.
197+
198+
The following example registers two services (Heart Rate, and Nordic UART)::
199+
200+
HR_UUID = bluetooth.UUID(0x180D)
201+
HR_CHAR = (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
202+
HR_SERVICE = (HR_SERVICE, (HR_CHAR,),)
203+
UART_UUID = bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')
204+
UART_TX = (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
205+
UART_RX = (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE,)
206+
UART_SERVICE = (UART_UUID, (UART_TX, UART_RX,),)
207+
SERVICES = (HR_SERVICE, UART_SERVICE,)
208+
( (hr,), (tx, rx,), ) = bt.gatts_register_services(SERVICES)
209+
210+
The three value handles (``hr``, ``tx``, ``rx``) can be used with
211+
:meth:`gatts_read <BLE.gatts_read>`, :meth:`gatts_write <BLE.gatts_write>`,
212+
and :meth:`gatts_notify <BLE.gatts_notify>`.
213+
214+
**Note:** Advertising must be stopped before registering services.
215+
216+
.. method:: BLE.gatts_read(value_handle)
217+
218+
Reads the local value for this handle (which has either been written by
219+
:meth:`gatts_write <BLE.gatts_write>` or by a remote central).
220+
221+
.. method:: BLE.gatts_write(value_handle, data)
222+
223+
Writes the local value for this handle, which can be read by a central.
224+
225+
.. method:: BLE.gatts_notify(conn_handle, value_handle, [data])
226+
227+
Notifies a connected central that this value has changed and that it should
228+
issue a read of the current value from this peripheral.
229+
230+
If *data* is specified, then the that value is sent to the central as part
231+
of the notification, avoiding the need for a separate read request. Note
232+
that this will not update the local value stored.
233+
234+
235+
Central Role (GATT Client)
236+
--------------------------
237+
238+
.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000)
239+
240+
Connect to a peripheral.
241+
242+
On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised.
243+
244+
.. method:: BLE.gap_disconnect(conn_handle)
245+
246+
Disconnect the specified connection handle.
247+
248+
On success, the ``_IRQ_PERIPHERAL_DISCONNECT`` event will be raised.
249+
250+
.. method:: BLE.gattc_discover_services(conn_handle)
251+
252+
Query a connected peripheral for its services.
253+
254+
For each service discovered, the ``_IRQ_GATTC_SERVICE_RESULT`` event will be
255+
raised.
256+
257+
.. method:: BLE.gattc_discover_characteristics(conn_handle, start_handle, end_handle)
258+
259+
Query a connected peripheral for characteristics in the specified range.
260+
261+
For each characteristic discovered, the ``_IRQ_GATTC_CHARACTERISTIC_RESULT``
262+
event will be raised.
263+
264+
.. method:: BLE.gattc_discover_descriptors(conn_handle, start_handle, end_handle)
265+
266+
Query a connected peripheral for descriptors in the specified range.
267+
268+
For each descriptor discovered, the ``_IRQ_GATTC_DESCRIPTOR_RESULT`` event
269+
will be raised.
270+
271+
.. method:: BLE.gattc_read(conn_handle, value_handle)
272+
273+
Issue a remote read to a connected peripheral for the specified
274+
characteristic or descriptor handle.
275+
276+
On success, the ``_IRQ_GATTC_READ_RESULT`` event will be raised.
277+
278+
.. method:: BLE.gattc_write(conn_handle, value_handle, data)
279+
280+
Issue a remote write to a connected peripheral for the specified
281+
characteristic or descriptor handle.
282+
283+
On success, the ``_IRQ_GATTC_WRITE_STATUS`` event will be raised.
284+
285+
286+
class UUID
287+
----------
288+
289+
290+
Constructor
291+
-----------
292+
293+
.. class:: UUID(value)
294+
295+
Creates a UUID instance with the specified **value**.
296+
297+
The **value** can be either:
298+
299+
- A 16-bit integer. e.g. ``0x2908``.
300+
- A 128-bit UUID string. e.g. ``'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'``.
301+
302+
303+
Constants
304+
---------
305+
306+
.. data:: bluetooth.FLAG_READ
307+
bluetooth.FLAG_WRITE
308+
bluetooth.FLAG_NOTIFY

docs/library/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ it will fallback to loading the built-in ``ujson`` module.
7575

7676
builtins.rst
7777
array.rst
78+
bluetooth.rst
7879
cmath.rst
7980
gc.rst
8081
math.rst

0 commit comments

Comments
 (0)