Skip to content

Commit 1d95282

Browse files
committed
tests/multi_bluetooth: Add performance test for gatt char writes.
Signed-off-by: Damien George <[email protected]>
1 parent 76dab3b commit 1d95282

File tree

2 files changed

+175
-0
lines changed

2 files changed

+175
-0
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Write characteristic from central to peripheral and time data rate.
2+
3+
from micropython import const
4+
import time, machine, bluetooth
5+
6+
TIMEOUT_MS = 2000
7+
8+
_IRQ_CENTRAL_CONNECT = const(1)
9+
_IRQ_CENTRAL_DISCONNECT = const(2)
10+
_IRQ_GATTS_WRITE = const(3)
11+
_IRQ_PERIPHERAL_CONNECT = const(7)
12+
_IRQ_PERIPHERAL_DISCONNECT = const(8)
13+
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
14+
_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
15+
_IRQ_GATTC_WRITE_DONE = const(17)
16+
_IRQ_MTU_EXCHANGED = const(21)
17+
18+
# How long to run the test for.
19+
_NUM_NOTIFICATIONS = const(40)
20+
_MTU_SIZE = const(131)
21+
_CHAR_SIZE = const(_MTU_SIZE - 3)
22+
23+
SERVICE_UUID = bluetooth.UUID("A5A5A5A5-FFFF-9999-1111-5A5A5A5A5A5A")
24+
CHAR_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444")
25+
CHAR = (CHAR_UUID, bluetooth.FLAG_WRITE | bluetooth.FLAG_WRITE_NO_RESPONSE)
26+
SERVICE = (SERVICE_UUID, (CHAR,))
27+
SERVICES = (SERVICE,)
28+
29+
packet_sequence = 0
30+
waiting_events = {}
31+
32+
33+
def irq(event, data):
34+
if event == _IRQ_CENTRAL_CONNECT:
35+
waiting_events[event] = data[0]
36+
elif event == _IRQ_PERIPHERAL_CONNECT:
37+
waiting_events[event] = data[0]
38+
elif event == _IRQ_GATTS_WRITE:
39+
global packet_sequence
40+
conn_handle, attr_handle = data
41+
data = ble.gatts_read(attr_handle)
42+
if not (data[0] == packet_sequence and data[-1] == (256 - packet_sequence) & 0xFF):
43+
print("_IRQ_GATTS_WRITE data invalid:", packet_sequence, data)
44+
elif packet_sequence % 10 == 0:
45+
print("_IRQ_GATTS_WRITE", packet_sequence)
46+
packet_sequence += 1
47+
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
48+
# conn_handle, def_handle, value_handle, properties, uuid = data
49+
if data[-1] == CHAR_UUID:
50+
waiting_events[event] = data[2]
51+
else:
52+
return
53+
elif event == _IRQ_MTU_EXCHANGED:
54+
# ATT MTU exchange complete (either initiated by us or the remote device).
55+
conn_handle, mtu = data
56+
print("_IRQ_MTU_EXCHANGED:", mtu)
57+
58+
if event not in waiting_events:
59+
waiting_events[event] = None
60+
61+
62+
def wait_for_event(event, timeout_ms):
63+
t0 = time.ticks_ms()
64+
while time.ticks_diff(time.ticks_ms(), t0) < timeout_ms:
65+
if event in waiting_events:
66+
return waiting_events.pop(event)
67+
machine.idle()
68+
raise ValueError("Timeout waiting for {}".format(event))
69+
70+
71+
# Acting in peripheral role.
72+
def instance0():
73+
multitest.globals(BDADDR=ble.config("mac"))
74+
((char_handle,),) = ble.gatts_register_services(SERVICES)
75+
ble.gatts_set_buffer(char_handle, _CHAR_SIZE)
76+
print("gap_advertise")
77+
ble.gap_advertise(20_000, b"\x02\x01\x06\x04\xffMPY")
78+
multitest.next()
79+
try:
80+
# Wait for central to connect to us.
81+
conn_handle = wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS)
82+
# Wait for central to disconnect us.
83+
wait_for_event(_IRQ_CENTRAL_DISCONNECT, 30000)
84+
print("final packet_sequence:", packet_sequence)
85+
finally:
86+
ble.active(0)
87+
88+
89+
# Acting in central role.
90+
def instance1():
91+
global packet_sequence
92+
((char_handle,),) = ble.gatts_register_services(SERVICES)
93+
multitest.next()
94+
try:
95+
# Connect to peripheral and then disconnect.
96+
print("gap_connect")
97+
ble.config(mtu=_MTU_SIZE)
98+
ble.gap_connect(*BDADDR)
99+
conn_handle = wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS)
100+
ble.gattc_exchange_mtu(conn_handle)
101+
102+
# Discover characteristics.
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+
# Send data!
108+
data = bytearray(ord("A") + (i % 64) for i in range(_CHAR_SIZE))
109+
for mode in (0, 1):
110+
ticks_start = time.ticks_ms()
111+
for i in range(_NUM_NOTIFICATIONS):
112+
data[0] = packet_sequence
113+
data[-1] = 256 - packet_sequence
114+
if packet_sequence % 10 == 0:
115+
print("gattc_write", packet_sequence)
116+
if mode == 0:
117+
while True:
118+
try:
119+
ble.gattc_write(conn_handle, value_handle, data, mode)
120+
break
121+
except OSError:
122+
pass
123+
else:
124+
ble.gattc_write(conn_handle, value_handle, data, mode)
125+
wait_for_event(_IRQ_GATTC_WRITE_DONE, TIMEOUT_MS)
126+
packet_sequence += 1
127+
128+
ticks_end = time.ticks_ms()
129+
ticks_total = time.ticks_diff(ticks_end, ticks_start)
130+
131+
print(
132+
"Did {} writes in {} ms. {} ms/write, {} bytes/sec".format(
133+
_NUM_NOTIFICATIONS,
134+
ticks_total,
135+
ticks_total / _NUM_NOTIFICATIONS,
136+
_NUM_NOTIFICATIONS * len(data) * 1000 // ticks_total,
137+
)
138+
)
139+
140+
time.sleep_ms(100)
141+
142+
# DIsconnect the peripheral.
143+
print("gap_disconnect:", ble.gap_disconnect(conn_handle))
144+
wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, 20000)
145+
finally:
146+
ble.active(0)
147+
148+
149+
ble = bluetooth.BLE()
150+
ble.active(1)
151+
ble.irq(irq)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--- instance0 ---
2+
gap_advertise
3+
_IRQ_MTU_EXCHANGED: 131
4+
_IRQ_GATTS_WRITE 0
5+
_IRQ_GATTS_WRITE 10
6+
_IRQ_GATTS_WRITE 20
7+
_IRQ_GATTS_WRITE 30
8+
_IRQ_GATTS_WRITE 40
9+
_IRQ_GATTS_WRITE 50
10+
_IRQ_GATTS_WRITE 60
11+
_IRQ_GATTS_WRITE 70
12+
final packet_sequence: 80
13+
--- instance1 ---
14+
gap_connect
15+
_IRQ_MTU_EXCHANGED: 131
16+
gattc_write 0
17+
gattc_write 10
18+
gattc_write 20
19+
gattc_write 30
20+
gattc_write 40
21+
gattc_write 50
22+
gattc_write 60
23+
gattc_write 70
24+
gap_disconnect: True

0 commit comments

Comments
 (0)