Skip to content

Commit 46748d2

Browse files
committed
aioble/server.py: Allow BufferedCharacteristic to support all ops.
Previously a BufferedCharacteristic could only be read by the client, where it should have been writeable. This makes it support all ops (read / write / write-with-response, etc). Adds a test to check the max_len and append functionality of BufferedCharacteristic. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
1 parent e5ba864 commit 46748d2

File tree

5 files changed

+164
-4
lines changed

5 files changed

+164
-4
lines changed

micropython/bluetooth/aioble-server/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
metadata(version="0.4.0")
1+
metadata(version="0.4.1")
22

33
require("aioble-core")
44

micropython/bluetooth/aioble/aioble/server.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,8 @@ def _indicate_done(conn_handle, value_handle, status):
290290

291291

292292
class BufferedCharacteristic(Characteristic):
293-
def __init__(self, service, uuid, max_len=20, append=False):
294-
super().__init__(service, uuid, read=True)
293+
def __init__(self, *args, max_len=20, append=False, **kwargs):
294+
super().__init__(*args, **kwargs)
295295
self._max_len = max_len
296296
self._append = append
297297

micropython/bluetooth/aioble/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# code. This allows (for development purposes) all the files to live in the
44
# one directory.
55

6-
metadata(version="0.4.0")
6+
metadata(version="0.4.1")
77

88
# Default installation gives you everything. Install the individual
99
# components (or a combination of them) if you want a more minimal install.
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Test characteristic read/write/notify from both GATTS and GATTC.
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+
CHAR1_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444")
18+
CHAR2_UUID = bluetooth.UUID("00000000-1111-2222-3333-555555555555")
19+
CHAR3_UUID = bluetooth.UUID("00000000-1111-2222-3333-666666666666")
20+
21+
22+
# Acting in peripheral role.
23+
async def instance0_task():
24+
service = aioble.Service(SERVICE_UUID)
25+
characteristic1 = aioble.BufferedCharacteristic(service, CHAR1_UUID, write=True)
26+
characteristic2 = aioble.BufferedCharacteristic(service, CHAR2_UUID, write=True, max_len=40)
27+
characteristic3 = aioble.BufferedCharacteristic(
28+
service, CHAR3_UUID, write=True, max_len=80, append=True
29+
)
30+
aioble.register_services(service)
31+
32+
multitest.globals(BDADDR=aioble.config("mac"))
33+
multitest.next()
34+
35+
# Wait for central to connect to us.
36+
print("advertise")
37+
connection = await aioble.advertise(
38+
20_000, adv_data=b"\x02\x01\x06\x04\xffMPY", timeout_ms=TIMEOUT_MS
39+
)
40+
print("connected")
41+
42+
# The first will just see the second write (truncated).
43+
await characteristic1.written(timeout_ms=TIMEOUT_MS)
44+
await characteristic1.written(timeout_ms=TIMEOUT_MS)
45+
print("written", characteristic1.read())
46+
47+
# The second will just see the second write (still truncated because MTU
48+
# exchange hasn't happened).
49+
await characteristic2.written(timeout_ms=TIMEOUT_MS)
50+
await characteristic2.written(timeout_ms=TIMEOUT_MS)
51+
print("written", characteristic2.read())
52+
53+
# MTU exchange should happen here.
54+
55+
# The second will now see the full second write.
56+
await characteristic2.written(timeout_ms=TIMEOUT_MS)
57+
await characteristic2.written(timeout_ms=TIMEOUT_MS)
58+
print("written", characteristic2.read())
59+
60+
# The third will see the two full writes concatenated.
61+
await characteristic3.written(timeout_ms=TIMEOUT_MS)
62+
await characteristic3.written(timeout_ms=TIMEOUT_MS)
63+
print("written", characteristic3.read())
64+
65+
# Wait for the central to disconnect.
66+
await connection.disconnected(timeout_ms=TIMEOUT_MS)
67+
print("disconnected")
68+
69+
70+
def instance0():
71+
try:
72+
asyncio.run(instance0_task())
73+
finally:
74+
aioble.stop()
75+
76+
77+
# Acting in central role.
78+
async def instance1_task():
79+
multitest.next()
80+
81+
# Connect to peripheral and then disconnect.
82+
print("connect")
83+
device = aioble.Device(*BDADDR)
84+
connection = await device.connect(timeout_ms=TIMEOUT_MS)
85+
86+
# Discover characteristics.
87+
service = await connection.service(SERVICE_UUID)
88+
print("service", service.uuid)
89+
characteristic1 = await service.characteristic(CHAR1_UUID)
90+
print("characteristic1", characteristic1.uuid)
91+
characteristic2 = await service.characteristic(CHAR2_UUID)
92+
print("characteristic2", characteristic2.uuid)
93+
characteristic3 = await service.characteristic(CHAR3_UUID)
94+
print("characteristic3", characteristic3.uuid)
95+
96+
# Write to each characteristic twice, with a long enough value to trigger
97+
# truncation.
98+
print("write1")
99+
await characteristic1.write(
100+
"central1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", response=True, timeout_ms=TIMEOUT_MS
101+
)
102+
await characteristic1.write(
103+
"central1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbb", response=True, timeout_ms=TIMEOUT_MS
104+
)
105+
print("write2a")
106+
await characteristic2.write(
107+
"central2a-aaaaaaaaaaaaaaaaaaaaaaaaaaaa", response=True, timeout_ms=TIMEOUT_MS
108+
)
109+
await characteristic2.write(
110+
"central2a-bbbbbbbbbbbbbbbbbbbbbbbbbbbb", response=True, timeout_ms=TIMEOUT_MS
111+
)
112+
print("exchange mtu")
113+
await connection.exchange_mtu(100)
114+
print("write2b")
115+
await characteristic2.write(
116+
"central2b-aaaaaaaaaaaaaaaaaaaaaaaaaaaa", response=True, timeout_ms=TIMEOUT_MS
117+
)
118+
await characteristic2.write(
119+
"central2b-bbbbbbbbbbbbbbbbbbbbbbbbbbbb", response=True, timeout_ms=TIMEOUT_MS
120+
)
121+
print("write3")
122+
await characteristic3.write(
123+
"central3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", response=True, timeout_ms=TIMEOUT_MS
124+
)
125+
await characteristic3.write(
126+
"central3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbb", response=True, timeout_ms=TIMEOUT_MS
127+
)
128+
129+
# Disconnect from peripheral.
130+
print("disconnect")
131+
await connection.disconnect(timeout_ms=TIMEOUT_MS)
132+
print("disconnected")
133+
134+
135+
def instance1():
136+
try:
137+
asyncio.run(instance1_task())
138+
finally:
139+
aioble.stop()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--- instance0 ---
2+
advertise
3+
connected
4+
written b'central1-bbbbbbbbbbb'
5+
written b'central2a-bbbbbbbbbb'
6+
written b'central2b-bbbbbbbbbbbbbbbbbbbbbbbbbbbb'
7+
written b'central3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaacentral3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
8+
disconnected
9+
--- instance1 ---
10+
connect
11+
service UUID('a5a5a5a5-ffff-9999-1111-5a5a5a5a5a5a')
12+
characteristic1 UUID('00000000-1111-2222-3333-444444444444')
13+
characteristic2 UUID('00000000-1111-2222-3333-555555555555')
14+
characteristic3 UUID('00000000-1111-2222-3333-666666666666')
15+
write1
16+
write2a
17+
exchange mtu
18+
write2b
19+
write3
20+
disconnect
21+
disconnected

0 commit comments

Comments
 (0)