extmod/modbluetooth: Combine gattc-data-available callbacks into one.
Instead of having the stack indicate a "start", "data"..., "end", pass through the data in one callback as an array of chunks of data. This is because the upcoming non-ringbuffer modbluetooth implementation cannot buffer the data in the ringbuffer and requires instead a single callback with all the data, to pass to the Python callback. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This commit is contained in:
parent
4559bcb467
commit
c398e46b29
@ -414,30 +414,21 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t
|
|||||||
uint16_t value_handle = gatt_event_characteristic_value_query_result_get_value_handle(packet);
|
uint16_t value_handle = gatt_event_characteristic_value_query_result_get_value_handle(packet);
|
||||||
uint16_t len = gatt_event_characteristic_value_query_result_get_value_length(packet);
|
uint16_t len = gatt_event_characteristic_value_query_result_get_value_length(packet);
|
||||||
const uint8_t *data = gatt_event_characteristic_value_query_result_get_value(packet);
|
const uint8_t *data = gatt_event_characteristic_value_query_result_get_value(packet);
|
||||||
mp_uint_t atomic_state;
|
mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_READ_RESULT, conn_handle, value_handle, &data, &len, 1);
|
||||||
len = mp_bluetooth_gattc_on_data_available_start(MP_BLUETOOTH_IRQ_GATTC_READ_RESULT, conn_handle, value_handle, len, &atomic_state);
|
|
||||||
mp_bluetooth_gattc_on_data_available_chunk(data, len);
|
|
||||||
mp_bluetooth_gattc_on_data_available_end(atomic_state);
|
|
||||||
} else if (event_type == GATT_EVENT_NOTIFICATION) {
|
} else if (event_type == GATT_EVENT_NOTIFICATION) {
|
||||||
DEBUG_printf(" --> gatt notification\n");
|
DEBUG_printf(" --> gatt notification\n");
|
||||||
uint16_t conn_handle = gatt_event_notification_get_handle(packet);
|
uint16_t conn_handle = gatt_event_notification_get_handle(packet);
|
||||||
uint16_t value_handle = gatt_event_notification_get_value_handle(packet);
|
uint16_t value_handle = gatt_event_notification_get_value_handle(packet);
|
||||||
uint16_t len = gatt_event_notification_get_value_length(packet);
|
uint16_t len = gatt_event_notification_get_value_length(packet);
|
||||||
const uint8_t *data = gatt_event_notification_get_value(packet);
|
const uint8_t *data = gatt_event_notification_get_value(packet);
|
||||||
mp_uint_t atomic_state;
|
mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_NOTIFY, conn_handle, value_handle, &data, &len, 1);
|
||||||
len = mp_bluetooth_gattc_on_data_available_start(MP_BLUETOOTH_IRQ_GATTC_NOTIFY, conn_handle, value_handle, len, &atomic_state);
|
|
||||||
mp_bluetooth_gattc_on_data_available_chunk(data, len);
|
|
||||||
mp_bluetooth_gattc_on_data_available_end(atomic_state);
|
|
||||||
} else if (event_type == GATT_EVENT_INDICATION) {
|
} else if (event_type == GATT_EVENT_INDICATION) {
|
||||||
DEBUG_printf(" --> gatt indication\n");
|
DEBUG_printf(" --> gatt indication\n");
|
||||||
uint16_t conn_handle = gatt_event_indication_get_handle(packet);
|
uint16_t conn_handle = gatt_event_indication_get_handle(packet);
|
||||||
uint16_t value_handle = gatt_event_indication_get_value_handle(packet);
|
uint16_t value_handle = gatt_event_indication_get_value_handle(packet);
|
||||||
uint16_t len = gatt_event_indication_get_value_length(packet);
|
uint16_t len = gatt_event_indication_get_value_length(packet);
|
||||||
const uint8_t *data = gatt_event_indication_get_value(packet);
|
const uint8_t *data = gatt_event_indication_get_value(packet);
|
||||||
mp_uint_t atomic_state;
|
mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_INDICATE, conn_handle, value_handle, &data, &len, 1);
|
||||||
len = mp_bluetooth_gattc_on_data_available_start(MP_BLUETOOTH_IRQ_GATTC_INDICATE, conn_handle, value_handle, len, &atomic_state);
|
|
||||||
mp_bluetooth_gattc_on_data_available_chunk(data, len);
|
|
||||||
mp_bluetooth_gattc_on_data_available_end(atomic_state);
|
|
||||||
} else if (event_type == GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE) {
|
} else if (event_type == GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE) {
|
||||||
uint16_t conn_handle = gatt_event_can_write_without_response_get_handle(packet);
|
uint16_t conn_handle = gatt_event_can_write_without_response_get_handle(packet);
|
||||||
DEBUG_printf(" --> gatt can write without response %d\n", conn_handle);
|
DEBUG_printf(" --> gatt can write without response %d\n", conn_handle);
|
||||||
|
@ -1125,31 +1125,34 @@ void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle
|
|||||||
schedule_ringbuf(atomic_state);
|
schedule_ringbuf(atomic_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mp_bluetooth_gattc_on_data_available_start(uint8_t event, uint16_t conn_handle, uint16_t value_handle, size_t data_len, mp_uint_t *atomic_state_out) {
|
void mp_bluetooth_gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t **data, uint16_t *data_len, size_t num) {
|
||||||
MICROPY_PY_BLUETOOTH_ENTER
|
MICROPY_PY_BLUETOOTH_ENTER
|
||||||
*atomic_state_out = atomic_state;
|
|
||||||
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
|
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
|
||||||
data_len = MIN(o->irq_data_data_alloc, data_len);
|
|
||||||
if (enqueue_irq(o, 2 + 2 + 2 + data_len, event)) {
|
// Get the total length of the fragmented buffers.
|
||||||
|
uint16_t total_len = 0;
|
||||||
|
for (size_t i = 0; i < num; ++i) {
|
||||||
|
total_len += data_len[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate the data at what we'll be able to pass to Python.
|
||||||
|
total_len = MIN(o->irq_data_data_alloc, total_len);
|
||||||
|
|
||||||
|
if (enqueue_irq(o, 2 + 2 + 2 + total_len, event)) {
|
||||||
ringbuf_put16(&o->ringbuf, conn_handle);
|
ringbuf_put16(&o->ringbuf, conn_handle);
|
||||||
ringbuf_put16(&o->ringbuf, value_handle);
|
ringbuf_put16(&o->ringbuf, value_handle);
|
||||||
// Length field is 16-bit.
|
|
||||||
data_len = MIN(UINT16_MAX, data_len);
|
|
||||||
ringbuf_put16(&o->ringbuf, data_len);
|
|
||||||
return data_len;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mp_bluetooth_gattc_on_data_available_chunk(const uint8_t *data, size_t data_len) {
|
ringbuf_put16(&o->ringbuf, total_len);
|
||||||
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
|
|
||||||
for (size_t i = 0; i < data_len; ++i) {
|
|
||||||
ringbuf_put(&o->ringbuf, data[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mp_bluetooth_gattc_on_data_available_end(mp_uint_t atomic_state) {
|
// Copy total_len from the fragments to the ringbuffer.
|
||||||
|
uint16_t copied_bytes = 0;
|
||||||
|
for (size_t i = 0; i < num; ++i) {
|
||||||
|
for (size_t j = 0; i < data_len[i] && copied_bytes < total_len; ++j) {
|
||||||
|
ringbuf_put(&o->ringbuf, data[i][j]);
|
||||||
|
++copied_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
schedule_ringbuf(atomic_state);
|
schedule_ringbuf(atomic_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,11 +289,7 @@ void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t hand
|
|||||||
void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle, uint16_t status);
|
void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle, uint16_t status);
|
||||||
|
|
||||||
// Notify modbluetooth that a read has completed with data (or notify/indicate data available, use `event` to disambiguate).
|
// Notify modbluetooth that a read has completed with data (or notify/indicate data available, use `event` to disambiguate).
|
||||||
// Note: these functions are to be called in a group protected by MICROPY_PY_BLUETOOTH_ENTER/EXIT.
|
void mp_bluetooth_gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t **data, uint16_t *data_len, size_t num);
|
||||||
// _start returns the number of bytes to submit to the calls to _chunk, followed by a call to _end.
|
|
||||||
size_t mp_bluetooth_gattc_on_data_available_start(uint8_t event, uint16_t conn_handle, uint16_t value_handle, size_t data_len, mp_uint_t *atomic_state_out);
|
|
||||||
void mp_bluetooth_gattc_on_data_available_chunk(const uint8_t *data, size_t data_len);
|
|
||||||
void mp_bluetooth_gattc_on_data_available_end(mp_uint_t atomic_state);
|
|
||||||
|
|
||||||
// Notify modbluetooth that a read or write operation has completed.
|
// Notify modbluetooth that a read or write operation has completed.
|
||||||
void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status);
|
void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status);
|
||||||
|
@ -798,16 +798,35 @@ int mp_bluetooth_set_preferred_mtu(uint16_t mtu) {
|
|||||||
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||||
|
|
||||||
STATIC void gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const struct os_mbuf *om) {
|
STATIC void gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const struct os_mbuf *om) {
|
||||||
size_t len = OS_MBUF_PKTLEN(om);
|
// When the HCI data for an ATT payload arrives, the L2CAP channel will
|
||||||
mp_uint_t atomic_state;
|
// buffer it into its receive buffer. We set BLE_L2CAP_JOIN_RX_FRAGS=1 in
|
||||||
len = mp_bluetooth_gattc_on_data_available_start(event, conn_handle, value_handle, len, &atomic_state);
|
// syscfg.h so it should be rare that the mbuf is fragmented, but we do need
|
||||||
while (len > 0 && om != NULL) {
|
// to be able to handle it. We pass all the fragments up to modbluetooth.c
|
||||||
size_t n = MIN(om->om_len, len);
|
// which will create a temporary buffer on the MicroPython heap if necessary
|
||||||
mp_bluetooth_gattc_on_data_available_chunk(OS_MBUF_DATA(om, const uint8_t *), n);
|
// to re-assemble them.
|
||||||
len -= n;
|
|
||||||
|
// Count how many links are in the mbuf chain.
|
||||||
|
size_t n = 0;
|
||||||
|
const struct os_mbuf *elem = om;
|
||||||
|
while (elem) {
|
||||||
|
n += 1;
|
||||||
|
elem = SLIST_NEXT(elem, om_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab data pointers and lengths for each of the links.
|
||||||
|
const uint8_t **data = mp_local_alloc(sizeof(uint8_t *) * n);
|
||||||
|
uint16_t *data_len = mp_local_alloc(sizeof(uint16_t) * n);
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
data[i] = OS_MBUF_DATA(om, const uint8_t *);
|
||||||
|
data_len[i] = om->om_len;
|
||||||
om = SLIST_NEXT(om, om_next);
|
om = SLIST_NEXT(om, om_next);
|
||||||
}
|
}
|
||||||
mp_bluetooth_gattc_on_data_available_end(atomic_state);
|
|
||||||
|
// Pass all the fragments together.
|
||||||
|
mp_bluetooth_gattc_on_data_available(event, conn_handle, value_handle, data, data_len, n);
|
||||||
|
|
||||||
|
mp_local_free(data_len);
|
||||||
|
mp_local_free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) {
|
STATIC int gap_scan_cb(struct ble_gap_event *event, void *arg) {
|
||||||
|
Loading…
Reference in New Issue
Block a user