Skip to content

Commit dd9b783

Browse files
committed
aioble/multitests: Add test for subscription and notification.
This replicates the failure described in micropython#453 (which is fixed by micropython#459. Also adds a test for subscription. Signed-off-by: Jim Mussared <[email protected]>
1 parent 9169ca6 commit dd9b783

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Test notification-specific behavior.
2+
3+
import sys
4+
5+
sys.path.append("")
6+
7+
from micropython import const
8+
import time, machine
9+
10+
import uasyncio as asyncio
11+
import aioble
12+
import bluetooth
13+
14+
TIMEOUT_MS = 5000
15+
16+
SERVICE_UUID = bluetooth.UUID("A5A5A5A5-FFFF-9999-1111-5A5A5A5A5A5A")
17+
CHAR_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444")
18+
19+
20+
# Acting in peripheral role.
21+
async def instance0_task():
22+
service = aioble.Service(SERVICE_UUID)
23+
characteristic = aioble.Characteristic(service, CHAR_UUID, read=True, notify=True)
24+
aioble.register_services(service)
25+
26+
multitest.globals(BDADDR=aioble.config("mac"))
27+
multitest.next()
28+
29+
# Wait for central to connect to us.
30+
print("advertise")
31+
connection = await aioble.advertise(
32+
20_000, adv_data=b"\x02\x01\x06\x04\xffMPY", timeout_ms=TIMEOUT_MS
33+
)
34+
print("connected")
35+
36+
# Send a subscribed-write (but client isn't subscribed, won't send anything).
37+
multitest.wait("discovery")
38+
await asyncio.sleep_ms(100)
39+
characteristic.write("before-subscribe", send_update=True)
40+
41+
# Send a subscribed-write (now client is subscribed, client should get notified).
42+
multitest.wait("subscribed")
43+
await asyncio.sleep_ms(100)
44+
characteristic.write("after-subscribe", send_update=True)
45+
46+
# Send a subscribed-write (now client is unsubscribed, won't send anything).
47+
multitest.wait("unsubscribed")
48+
await asyncio.sleep_ms(100)
49+
characteristic.write("after-unsubscribe", send_update=True)
50+
51+
# Send 5 direct notifications.
52+
multitest.wait("start-direct")
53+
for i in range(5):
54+
# Send 1 notification each time, except for 3 quick notifications the third time.
55+
# The client should only see the last one.
56+
for j in range(3 if i == 2 else 1):
57+
if j > 0:
58+
await asyncio.sleep_ms(100)
59+
msg = "direct-{}-{}".format(i, j)
60+
print("notify", msg)
61+
characteristic.notify(connection, msg)
62+
63+
# Tell client to wait for notification.
64+
multitest.broadcast("notified")
65+
# Wait until client is ready for next notification.
66+
multitest.wait("next")
67+
68+
# Wait for the central to disconnect.
69+
await connection.disconnected(timeout_ms=TIMEOUT_MS)
70+
print("disconnected")
71+
72+
73+
def instance0():
74+
try:
75+
asyncio.run(instance0_task())
76+
finally:
77+
aioble.stop()
78+
79+
80+
# Acting in central role.
81+
async def instance1_task():
82+
multitest.next()
83+
84+
# Connect to peripheral and then disconnect.
85+
print("connect")
86+
device = aioble.Device(*BDADDR)
87+
connection = await device.connect(timeout_ms=TIMEOUT_MS)
88+
89+
# Discover characteristics.
90+
service = await connection.service(SERVICE_UUID)
91+
print("service", service.uuid)
92+
characteristic = await service.characteristic(CHAR_UUID)
93+
print("characteristic", characteristic.uuid)
94+
95+
# Expect to not receive a notification (not subscribed).
96+
multitest.broadcast("discovery")
97+
try:
98+
await characteristic.notified(timeout_ms=500)
99+
print("fail")
100+
return
101+
except asyncio.TimeoutError:
102+
print("no notification")
103+
104+
# Subscribe and expect a notification.
105+
await characteristic.subscribe(notify=True)
106+
multitest.broadcast("subscribed")
107+
value = await characteristic.notified()
108+
print("notified", value)
109+
110+
# Unsubscribe, and expect not to receive a notification.
111+
await characteristic.subscribe(notify=False)
112+
multitest.broadcast("unsubscribed")
113+
try:
114+
await characteristic.notified(timeout_ms=500)
115+
print("fail")
116+
return
117+
except asyncio.TimeoutError:
118+
print("no notification")
119+
120+
# Receive 5 notifications.
121+
multitest.broadcast("start-direct")
122+
for i in range(5):
123+
multitest.wait("notified")
124+
await asyncio.sleep_ms(200)
125+
value = await characteristic.notified()
126+
print("notified", value)
127+
128+
# Expect that after receiving a notification we don't get another one
129+
# until we broadcast to the server.
130+
try:
131+
value = await characteristic.notified(timeout_ms=100)
132+
print("unexpected notify", value)
133+
except asyncio.TimeoutError:
134+
pass
135+
136+
multitest.broadcast("next")
137+
138+
# Disconnect from peripheral.
139+
print("disconnect")
140+
await connection.disconnect(timeout_ms=TIMEOUT_MS)
141+
print("disconnected")
142+
143+
144+
def instance1():
145+
try:
146+
asyncio.run(instance1_task())
147+
finally:
148+
aioble.stop()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--- instance0 ---
2+
advertise
3+
connected
4+
notify direct-0-0
5+
notify direct-1-0
6+
notify direct-2-0
7+
notify direct-2-1
8+
notify direct-2-2
9+
notify direct-3-0
10+
notify direct-4-0
11+
disconnected
12+
--- instance1 ---
13+
connect
14+
service UUID('a5a5a5a5-ffff-9999-1111-5a5a5a5a5a5a')
15+
characteristic UUID('00000000-1111-2222-3333-444444444444')
16+
no notification
17+
notified b'after-subscribe'
18+
no notification
19+
notified b'direct-0-0'
20+
notified b'direct-1-0'
21+
notified b'direct-2-2'
22+
notified b'direct-3-0'
23+
notified b'direct-4-0'
24+
disconnect
25+
disconnected

0 commit comments

Comments
 (0)