Skip to content

Commit 31d52b0

Browse files
committed
tests/multi_bluetooth: Add multitests for BLE pairing and bonding.
Signed-off-by: Damien George <damien@micropython.org>
1 parent c66bc68 commit 31d52b0

File tree

4 files changed

+297
-0
lines changed

4 files changed

+297
-0
lines changed

tests/multi_bluetooth/ble_gap_pair.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Test BLE GAP connect/disconnect with pairing, and read an encrypted characteristic
2+
# TODO: add gap_passkey testing
3+
4+
from micropython import const
5+
import time, machine, bluetooth
6+
7+
TIMEOUT_MS = 4000
8+
9+
_IRQ_CENTRAL_CONNECT = const(1)
10+
_IRQ_CENTRAL_DISCONNECT = const(2)
11+
_IRQ_GATTS_READ_REQUEST = const(4)
12+
_IRQ_PERIPHERAL_CONNECT = const(7)
13+
_IRQ_PERIPHERAL_DISCONNECT = const(8)
14+
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
15+
_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
16+
_IRQ_GATTC_READ_RESULT = const(15)
17+
_IRQ_ENCRYPTION_UPDATE = const(28)
18+
19+
_FLAG_READ = const(0x0002)
20+
_FLAG_READ_ENCRYPTED = const(0x0200)
21+
22+
SERVICE_UUID = bluetooth.UUID("A5A5A5A5-FFFF-9999-1111-5A5A5A5A5A5A")
23+
CHAR_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444")
24+
CHAR = (CHAR_UUID, _FLAG_READ | _FLAG_READ_ENCRYPTED)
25+
SERVICE = (SERVICE_UUID, (CHAR,))
26+
27+
waiting_events = {}
28+
29+
30+
def irq(event, data):
31+
if event == _IRQ_CENTRAL_CONNECT:
32+
print("_IRQ_CENTRAL_CONNECT")
33+
waiting_events[event] = data[0]
34+
elif event == _IRQ_CENTRAL_DISCONNECT:
35+
print("_IRQ_CENTRAL_DISCONNECT")
36+
elif event == _IRQ_GATTS_READ_REQUEST:
37+
print("_IRQ_GATTS_READ_REQUEST")
38+
elif event == _IRQ_PERIPHERAL_CONNECT:
39+
print("_IRQ_PERIPHERAL_CONNECT")
40+
waiting_events[event] = data[0]
41+
elif event == _IRQ_PERIPHERAL_DISCONNECT:
42+
print("_IRQ_PERIPHERAL_DISCONNECT")
43+
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
44+
if data[-1] == CHAR_UUID:
45+
print("_IRQ_GATTC_CHARACTERISTIC_RESULT", data[-1])
46+
waiting_events[event] = data[2]
47+
else:
48+
return
49+
elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
50+
print("_IRQ_GATTC_CHARACTERISTIC_DONE")
51+
elif event == _IRQ_GATTC_READ_RESULT:
52+
print("_IRQ_GATTC_READ_RESULT", bytes(data[-1]))
53+
elif event == _IRQ_ENCRYPTION_UPDATE:
54+
print("_IRQ_ENCRYPTION_UPDATE", data[1], data[2], data[3])
55+
56+
if event not in waiting_events:
57+
waiting_events[event] = None
58+
59+
60+
def wait_for_event(event, timeout_ms):
61+
t0 = time.ticks_ms()
62+
while time.ticks_diff(time.ticks_ms(), t0) < timeout_ms:
63+
if event in waiting_events:
64+
return waiting_events.pop(event)
65+
machine.idle()
66+
raise ValueError("Timeout waiting for {}".format(event))
67+
68+
69+
# Acting in peripheral role.
70+
def instance0():
71+
multitest.globals(BDADDR=ble.config("mac"))
72+
((char_handle,),) = ble.gatts_register_services((SERVICE,))
73+
ble.gatts_write(char_handle, "encrypted")
74+
print("gap_advertise")
75+
ble.gap_advertise(20_000, b"\x02\x01\x06\x04\xffMPY")
76+
multitest.next()
77+
try:
78+
# Wait for central to connect.
79+
wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS)
80+
81+
# Wait for pairing event.
82+
wait_for_event(_IRQ_ENCRYPTION_UPDATE, TIMEOUT_MS)
83+
84+
# Wait for GATTS read request.
85+
wait_for_event(_IRQ_GATTS_READ_REQUEST, TIMEOUT_MS)
86+
87+
# Wait for central to disconnect.
88+
wait_for_event(_IRQ_CENTRAL_DISCONNECT, TIMEOUT_MS)
89+
finally:
90+
ble.active(0)
91+
92+
93+
# Acting in central role.
94+
def instance1():
95+
multitest.next()
96+
try:
97+
# Connect to peripheral.
98+
print("gap_connect")
99+
ble.gap_connect(*BDADDR)
100+
conn_handle = wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS)
101+
102+
# Discover characteristics (before pairing, doesn't need to be encrypted).
103+
ble.gattc_discover_characteristics(conn_handle, 1, 65535)
104+
value_handle = wait_for_event(_IRQ_GATTC_CHARACTERISTIC_RESULT, TIMEOUT_MS)
105+
wait_for_event(_IRQ_GATTC_CHARACTERISTIC_DONE, TIMEOUT_MS)
106+
107+
# Pair with the peripheral.
108+
print("gap_pair")
109+
ble.gap_pair(conn_handle)
110+
111+
# Wait for the pairing event.
112+
wait_for_event(_IRQ_ENCRYPTION_UPDATE, TIMEOUT_MS)
113+
114+
# Read the peripheral's characteristic, should be encrypted.
115+
print("gattc_read")
116+
ble.gattc_read(conn_handle, value_handle)
117+
wait_for_event(_IRQ_GATTC_READ_RESULT, TIMEOUT_MS)
118+
119+
# Disconnect from the peripheral.
120+
print("gap_disconnect:", ble.gap_disconnect(conn_handle))
121+
wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, TIMEOUT_MS)
122+
finally:
123+
ble.active(0)
124+
125+
126+
ble = bluetooth.BLE()
127+
ble.config(mitm=True, le_secure=True, bond=False)
128+
ble.active(1)
129+
ble.irq(irq)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--- instance0 ---
2+
gap_advertise
3+
_IRQ_CENTRAL_CONNECT
4+
_IRQ_ENCRYPTION_UPDATE 1 0 0
5+
_IRQ_GATTS_READ_REQUEST
6+
_IRQ_CENTRAL_DISCONNECT
7+
--- instance1 ---
8+
gap_connect
9+
_IRQ_PERIPHERAL_CONNECT
10+
_IRQ_GATTC_CHARACTERISTIC_RESULT UUID('00000000-1111-2222-3333-444444444444')
11+
_IRQ_GATTC_CHARACTERISTIC_DONE
12+
gap_pair
13+
_IRQ_ENCRYPTION_UPDATE 1 0 0
14+
gattc_read
15+
_IRQ_GATTC_READ_RESULT b'encrypted'
16+
gap_disconnect: True
17+
_IRQ_PERIPHERAL_DISCONNECT
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Test BLE GAP connect/disconnect with pairing and bonding, and read an encrypted
2+
# characteristic
3+
# TODO: reconnect after bonding to test that the secrets persist
4+
5+
from micropython import const
6+
import time, machine, bluetooth
7+
8+
TIMEOUT_MS = 4000
9+
10+
_IRQ_CENTRAL_CONNECT = const(1)
11+
_IRQ_CENTRAL_DISCONNECT = const(2)
12+
_IRQ_GATTS_READ_REQUEST = const(4)
13+
_IRQ_PERIPHERAL_CONNECT = const(7)
14+
_IRQ_PERIPHERAL_DISCONNECT = const(8)
15+
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
16+
_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
17+
_IRQ_GATTC_READ_RESULT = const(15)
18+
_IRQ_ENCRYPTION_UPDATE = const(28)
19+
_IRQ_SET_SECRET = const(30)
20+
21+
_FLAG_READ = const(0x0002)
22+
_FLAG_READ_ENCRYPTED = const(0x0200)
23+
24+
SERVICE_UUID = bluetooth.UUID("A5A5A5A5-FFFF-9999-1111-5A5A5A5A5A5A")
25+
CHAR_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444")
26+
CHAR = (CHAR_UUID, _FLAG_READ | _FLAG_READ_ENCRYPTED)
27+
SERVICE = (SERVICE_UUID, (CHAR,))
28+
29+
waiting_events = {}
30+
secrets = {}
31+
32+
33+
def irq(event, data):
34+
if event == _IRQ_CENTRAL_CONNECT:
35+
print("_IRQ_CENTRAL_CONNECT")
36+
waiting_events[event] = data[0]
37+
elif event == _IRQ_CENTRAL_DISCONNECT:
38+
print("_IRQ_CENTRAL_DISCONNECT")
39+
elif event == _IRQ_GATTS_READ_REQUEST:
40+
print("_IRQ_GATTS_READ_REQUEST")
41+
elif event == _IRQ_PERIPHERAL_CONNECT:
42+
print("_IRQ_PERIPHERAL_CONNECT")
43+
waiting_events[event] = data[0]
44+
elif event == _IRQ_PERIPHERAL_DISCONNECT:
45+
print("_IRQ_PERIPHERAL_DISCONNECT")
46+
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
47+
if data[-1] == CHAR_UUID:
48+
print("_IRQ_GATTC_CHARACTERISTIC_RESULT", data[-1])
49+
waiting_events[event] = data[2]
50+
else:
51+
return
52+
elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
53+
print("_IRQ_GATTC_CHARACTERISTIC_DONE")
54+
elif event == _IRQ_GATTC_READ_RESULT:
55+
print("_IRQ_GATTC_READ_RESULT", bytes(data[-1]))
56+
elif event == _IRQ_ENCRYPTION_UPDATE:
57+
print("_IRQ_ENCRYPTION_UPDATE", data[1], data[2], data[3])
58+
elif event == _IRQ_SET_SECRET:
59+
return True
60+
61+
if event not in waiting_events:
62+
waiting_events[event] = None
63+
64+
65+
def wait_for_event(event, timeout_ms):
66+
t0 = time.ticks_ms()
67+
while time.ticks_diff(time.ticks_ms(), t0) < timeout_ms:
68+
if event in waiting_events:
69+
return waiting_events.pop(event)
70+
machine.idle()
71+
raise ValueError("Timeout waiting for {}".format(event))
72+
73+
74+
# Acting in peripheral role.
75+
def instance0():
76+
multitest.globals(BDADDR=ble.config("mac"))
77+
((char_handle,),) = ble.gatts_register_services((SERVICE,))
78+
ble.gatts_write(char_handle, "encrypted")
79+
print("gap_advertise")
80+
ble.gap_advertise(20_000, b"\x02\x01\x06\x04\xffMPY")
81+
multitest.next()
82+
try:
83+
# Wait for central to connect.
84+
wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS)
85+
86+
# Wait for pairing event.
87+
wait_for_event(_IRQ_ENCRYPTION_UPDATE, TIMEOUT_MS)
88+
89+
# Wait for GATTS read request.
90+
wait_for_event(_IRQ_GATTS_READ_REQUEST, TIMEOUT_MS)
91+
92+
# Wait for central to disconnect.
93+
wait_for_event(_IRQ_CENTRAL_DISCONNECT, TIMEOUT_MS)
94+
finally:
95+
ble.active(0)
96+
97+
98+
# Acting in central role.
99+
def instance1():
100+
multitest.next()
101+
try:
102+
# Connect to peripheral.
103+
print("gap_connect")
104+
ble.gap_connect(*BDADDR)
105+
conn_handle = wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS)
106+
107+
# Discover characteristics (before pairing, doesn't need to be encrypted).
108+
ble.gattc_discover_characteristics(conn_handle, 1, 65535)
109+
value_handle = wait_for_event(_IRQ_GATTC_CHARACTERISTIC_RESULT, TIMEOUT_MS)
110+
wait_for_event(_IRQ_GATTC_CHARACTERISTIC_DONE, TIMEOUT_MS)
111+
112+
# Pair with the peripheral.
113+
print("gap_pair")
114+
ble.gap_pair(conn_handle)
115+
116+
# Wait for the pairing event.
117+
wait_for_event(_IRQ_ENCRYPTION_UPDATE, TIMEOUT_MS)
118+
119+
# Read the peripheral's characteristic, should be encrypted.
120+
print("gattc_read")
121+
ble.gattc_read(conn_handle, value_handle)
122+
wait_for_event(_IRQ_GATTC_READ_RESULT, TIMEOUT_MS)
123+
124+
# Disconnect from the peripheral.
125+
print("gap_disconnect:", ble.gap_disconnect(conn_handle))
126+
wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, TIMEOUT_MS)
127+
finally:
128+
ble.active(0)
129+
130+
131+
ble = bluetooth.BLE()
132+
ble.config(mitm=True, le_secure=True, bond=True)
133+
ble.active(1)
134+
ble.irq(irq)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--- instance0 ---
2+
gap_advertise
3+
_IRQ_CENTRAL_CONNECT
4+
_IRQ_ENCRYPTION_UPDATE 1 0 1
5+
_IRQ_GATTS_READ_REQUEST
6+
_IRQ_CENTRAL_DISCONNECT
7+
--- instance1 ---
8+
gap_connect
9+
_IRQ_PERIPHERAL_CONNECT
10+
_IRQ_GATTC_CHARACTERISTIC_RESULT UUID('00000000-1111-2222-3333-444444444444')
11+
_IRQ_GATTC_CHARACTERISTIC_DONE
12+
gap_pair
13+
_IRQ_ENCRYPTION_UPDATE 1 0 1
14+
gattc_read
15+
_IRQ_GATTC_READ_RESULT b'encrypted'
16+
gap_disconnect: True
17+
_IRQ_PERIPHERAL_DISCONNECT

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy