kopia lustrzana https://github.com/micropython/micropython
extmod/btstack: Reset pending_value_handle before calling write-done cb.
The pending_value_handle needs to be freed and reset before calling mp_bluetooth_gattc_on_read_write_status(), which will call the Python IRQ handler, which may in turn call back into BTstack to perform an action like a write. In that case the pending_value_handle will need to be available for the write/read/etc to proceed. Fixes issue #13611. Signed-off-by: Damien George <damien@micropython.org>pull/13618/head
rodzic
8cbae12d0d
commit
b4f59984f7
|
@ -490,11 +490,12 @@ STATIC void btstack_packet_handler_write_with_response(uint8_t packet_type, uint
|
|||
if (!conn) {
|
||||
return;
|
||||
}
|
||||
mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE, conn_handle, conn->pending_value_handle, status);
|
||||
uint16_t value_handle = conn->pending_value_handle;
|
||||
conn->pending_value_handle = 0xffff;
|
||||
m_del(uint8_t, conn->pending_write_value, conn->pending_write_value_len);
|
||||
conn->pending_write_value = NULL;
|
||||
conn->pending_write_value_len = 0;
|
||||
mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE, conn_handle, value_handle, status);
|
||||
}
|
||||
}
|
||||
#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
# Test calling BLE methods from within the BLE.irq event handler.
|
||||
|
||||
from micropython import const
|
||||
import struct
|
||||
import time
|
||||
import bluetooth
|
||||
|
||||
_IRQ_CENTRAL_CONNECT = const(1)
|
||||
_IRQ_CENTRAL_DISCONNECT = const(2)
|
||||
_IRQ_PERIPHERAL_CONNECT = const(7)
|
||||
_IRQ_PERIPHERAL_DISCONNECT = const(8)
|
||||
_IRQ_GATTC_SERVICE_RESULT = const(9)
|
||||
_IRQ_GATTC_SERVICE_DONE = const(10)
|
||||
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
|
||||
_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
|
||||
_IRQ_GATTC_DESCRIPTOR_RESULT = const(13)
|
||||
_IRQ_GATTC_DESCRIPTOR_DONE = const(14)
|
||||
_IRQ_GATTC_READ_RESULT = const(15)
|
||||
_IRQ_GATTC_READ_DONE = const(16)
|
||||
_IRQ_GATTC_WRITE_DONE = const(17)
|
||||
_IRQ_MTU_EXCHANGED = const(21)
|
||||
_IRQ_GET_SECRET = const(29)
|
||||
_IRQ_SET_SECRET = const(30)
|
||||
|
||||
EVENT_NAMES = {
|
||||
1: "_IRQ_CENTRAL_CONNECT",
|
||||
2: "_IRQ_CENTRAL_DISCONNECT",
|
||||
3: "_IRQ_GATTS_WRITE",
|
||||
4: "_IRQ_GATTS_READ_REQUEST",
|
||||
7: "_IRQ_PERIPHERAL_CONNECT",
|
||||
8: "_IRQ_PERIPHERAL_DISCONNECT",
|
||||
9: "_IRQ_GATTC_SERVICE_RESULT",
|
||||
10: "_IRQ_GATTC_SERVICE_DONE",
|
||||
11: "_IRQ_GATTC_CHARACTERISTIC_RESULT",
|
||||
12: "_IRQ_GATTC_CHARACTERISTIC_DONE",
|
||||
13: "_IRQ_GATTC_DESCRIPTOR_RESULT",
|
||||
14: "_IRQ_GATTC_DESCRIPTOR_DONE",
|
||||
15: "_IRQ_GATTC_READ_RESULT",
|
||||
16: "_IRQ_GATTC_READ_DONE",
|
||||
17: "_IRQ_GATTC_WRITE_DONE",
|
||||
18: "_IRQ_GATTC_NOTIFY",
|
||||
21: "_IRQ_MTU_EXCHANGED",
|
||||
}
|
||||
|
||||
_ADV_TYPE_FLAGS = const(0x01)
|
||||
_ADV_TYPE_NAME = const(0x09)
|
||||
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
|
||||
|
||||
_NOTIFY_ENABLE = const(1)
|
||||
|
||||
ACCESSORY_UUID = bluetooth.UUID("a5a5a5a5-ffff-9999-1111-5a5a5a5a5a5a")
|
||||
STATE_UUID = bluetooth.UUID("a5a5a5a5-eeee-9999-1111-5a5a5a5a5a5a")
|
||||
CCC_UUID = bluetooth.UUID(0x2902)
|
||||
|
||||
STATE_CHARACTERISTIC = (
|
||||
STATE_UUID,
|
||||
bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,
|
||||
)
|
||||
|
||||
ACCESSORY_SERVICE = (ACCESSORY_UUID, (STATE_CHARACTERISTIC,))
|
||||
|
||||
|
||||
class Central:
|
||||
def __init__(self):
|
||||
self.done = False
|
||||
self._conn_handle = None
|
||||
self._service = None
|
||||
self._characteristic = None
|
||||
self._cccd_handle = None
|
||||
ble.active(1)
|
||||
ble.irq(self._ble_event_handler)
|
||||
ble.gap_connect(*BDADDR)
|
||||
|
||||
def _ble_event_handler(self, event, data):
|
||||
print(EVENT_NAMES[event])
|
||||
|
||||
if event == _IRQ_PERIPHERAL_CONNECT:
|
||||
conn_handle, _, _ = data
|
||||
self._conn_handle = conn_handle
|
||||
ble.gattc_discover_services(self._conn_handle, ACCESSORY_UUID)
|
||||
|
||||
elif event == _IRQ_PERIPHERAL_DISCONNECT:
|
||||
conn_handle, _, addr = data
|
||||
assert self._conn_handle == conn_handle
|
||||
self._conn_handle = None
|
||||
print("connection closed")
|
||||
|
||||
elif event == _IRQ_GATTC_SERVICE_RESULT:
|
||||
_, first_handle, last_handle, uuid = data
|
||||
print("service found:", last_handle - first_handle, uuid)
|
||||
if uuid == ACCESSORY_UUID:
|
||||
assert self._service is None
|
||||
self._service = (first_handle, last_handle)
|
||||
|
||||
elif event == _IRQ_GATTC_SERVICE_DONE:
|
||||
print("service handle range:", self._service[1] - self._service[0])
|
||||
start_handle, end_handle = self._service
|
||||
ble.gattc_discover_characteristics(self._conn_handle, start_handle, end_handle)
|
||||
|
||||
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
|
||||
_, end_handle, value_handle, properties, uuid = data
|
||||
assert uuid == STATE_UUID
|
||||
print("characteristic found:", uuid)
|
||||
self._characteristic = (end_handle, value_handle, properties)
|
||||
|
||||
elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
|
||||
start_handle, end_handle = self._service
|
||||
ble.gattc_discover_descriptors(self._conn_handle, start_handle, end_handle)
|
||||
|
||||
elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:
|
||||
_, dsc_handle, uuid = data
|
||||
if uuid == CCC_UUID:
|
||||
print("CCCD found:", uuid)
|
||||
assert self._cccd_handle is None
|
||||
self._cccd_handle = dsc_handle
|
||||
|
||||
elif event == _IRQ_GATTC_DESCRIPTOR_DONE:
|
||||
# Discovery complete, proceed to MTU exchange.
|
||||
ble.gattc_exchange_mtu(self._conn_handle)
|
||||
|
||||
elif event == _IRQ_MTU_EXCHANGED:
|
||||
# MTU exchanged, proceed to enable CCCD.
|
||||
print("CCCD write")
|
||||
ble.gattc_write(
|
||||
self._conn_handle, self._cccd_handle, struct.pack("<h", _NOTIFY_ENABLE), 1
|
||||
)
|
||||
|
||||
elif event == _IRQ_GATTC_WRITE_DONE:
|
||||
conn_handle, _, result = data
|
||||
print("CCCD write result:", result)
|
||||
_, state_handle, _ = self._characteristic
|
||||
print("issue gattc_read")
|
||||
ble.gattc_read(self._conn_handle, state_handle)
|
||||
|
||||
elif event == _IRQ_GATTC_READ_RESULT:
|
||||
_, _, char_data = data
|
||||
print("gattc_read result:", bytes(char_data))
|
||||
|
||||
elif event == _IRQ_GATTC_READ_DONE:
|
||||
self.done = True
|
||||
ble.gap_disconnect(self._conn_handle)
|
||||
|
||||
|
||||
class Peripheral:
|
||||
def __init__(self):
|
||||
self.done = False
|
||||
ble.active(1)
|
||||
ble.irq(self._ble_event_handler)
|
||||
ble.gatts_register_services((ACCESSORY_SERVICE,))
|
||||
add_payload = self.advertising_payload("acc", (ACCESSORY_UUID,))
|
||||
ble.gap_advertise(500000, add_payload)
|
||||
|
||||
def advertising_payload(self, name, services):
|
||||
payload = bytearray()
|
||||
|
||||
def _append(adv_type, value):
|
||||
nonlocal payload
|
||||
payload.extend(struct.pack("BB", len(value) + 1, adv_type) + value)
|
||||
|
||||
_append(_ADV_TYPE_FLAGS, struct.pack("B", 0x02 + 0x04))
|
||||
_append(_ADV_TYPE_NAME, name)
|
||||
|
||||
for uuid in services:
|
||||
b = bytes(uuid)
|
||||
assert len(b) == 16
|
||||
_append(_ADV_TYPE_UUID128_COMPLETE, b)
|
||||
|
||||
return payload
|
||||
|
||||
def _ble_event_handler(self, event, data):
|
||||
if event not in (_IRQ_GET_SECRET, _IRQ_SET_SECRET):
|
||||
print(EVENT_NAMES[event])
|
||||
if event == _IRQ_CENTRAL_DISCONNECT:
|
||||
self.done = True
|
||||
|
||||
|
||||
# Acting in peripheral role.
|
||||
def instance0():
|
||||
print("peripheral start")
|
||||
peripheral = Peripheral()
|
||||
multitest.globals(BDADDR=ble.config("mac"))
|
||||
multitest.next()
|
||||
while not peripheral.done:
|
||||
time.sleep_ms(100)
|
||||
multitest.broadcast("finished")
|
||||
ble.active(0)
|
||||
|
||||
|
||||
# Acting in central role.
|
||||
def instance1():
|
||||
print("central start")
|
||||
multitest.next()
|
||||
central = Central()
|
||||
while not central.done:
|
||||
time.sleep_ms(100)
|
||||
multitest.wait("finished")
|
||||
ble.active(0)
|
||||
|
||||
|
||||
ble = bluetooth.BLE()
|
|
@ -0,0 +1,31 @@
|
|||
--- instance0 ---
|
||||
peripheral start
|
||||
_IRQ_CENTRAL_CONNECT
|
||||
_IRQ_MTU_EXCHANGED
|
||||
_IRQ_GATTS_READ_REQUEST
|
||||
_IRQ_CENTRAL_DISCONNECT
|
||||
--- instance1 ---
|
||||
central start
|
||||
_IRQ_PERIPHERAL_CONNECT
|
||||
_IRQ_GATTC_SERVICE_RESULT
|
||||
service found: 3 UUID('a5a5a5a5-ffff-9999-1111-5a5a5a5a5a5a')
|
||||
_IRQ_GATTC_SERVICE_DONE
|
||||
service handle range: 3
|
||||
_IRQ_GATTC_CHARACTERISTIC_RESULT
|
||||
characteristic found: UUID('a5a5a5a5-eeee-9999-1111-5a5a5a5a5a5a')
|
||||
_IRQ_GATTC_CHARACTERISTIC_DONE
|
||||
_IRQ_GATTC_DESCRIPTOR_RESULT
|
||||
_IRQ_GATTC_DESCRIPTOR_RESULT
|
||||
_IRQ_GATTC_DESCRIPTOR_RESULT
|
||||
CCCD found: UUID(0x2902)
|
||||
_IRQ_GATTC_DESCRIPTOR_DONE
|
||||
_IRQ_MTU_EXCHANGED
|
||||
CCCD write
|
||||
_IRQ_GATTC_WRITE_DONE
|
||||
CCCD write result: 0
|
||||
issue gattc_read
|
||||
_IRQ_GATTC_READ_RESULT
|
||||
gattc_read result: b''
|
||||
_IRQ_GATTC_READ_DONE
|
||||
_IRQ_PERIPHERAL_DISCONNECT
|
||||
connection closed
|
Ładowanie…
Reference in New Issue