Skip to content

Commit 256f47e

Browse files
committed
extmod/btstack: Fix indicate/notify queuing.
This adds a mechanism to track a pending notify/indicate operation that is deferred due to the send buffer being full. This uses a tracked alloc that is passed as the content arg to the callback. This replaces the previous mechanism that did this via the global pending op queue, shared with client read/write ops. Signed-off-by: Jim Mussared <[email protected]>
1 parent bc9ec1c commit 256f47e

File tree

6 files changed

+73
-9
lines changed

6 files changed

+73
-9
lines changed

extmod/btstack/modbluetooth_btstack.c

+64-5
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ STATIC void btstack_remove_pending_operation(mp_btstack_pending_op_t *pending_op
166166

167167
// Register a pending background operation -- copies the buffer, and makes it known to the GC.
168168
STATIC mp_btstack_pending_op_t *btstack_enqueue_pending_operation(uint16_t op_type, uint16_t conn_handle, uint16_t value_handle, const uint8_t *buf, size_t len) {
169-
DEBUG_printf("btstack_enqueue_pending_operation op_type=%d conn_handle=%d value_handle=%d len=%zu\n", op_type, conn_handle, value_handle, len);
169+
DEBUG_printf("btstack_enqueue_pending_operation op_type=%d conn_handle=%d value_handle=%d len=%lu\n", op_type, conn_handle, value_handle, len);
170170
mp_btstack_pending_op_t *pending_op = m_new_obj_var(mp_btstack_pending_op_t, uint8_t, len);
171171
pending_op->op_type = op_type;
172172
pending_op->conn_handle = conn_handle;
@@ -1079,8 +1079,44 @@ int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t
10791079
return mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, value, value_len);
10801080
}
10811081

1082+
#if !MICROPY_TRACKED_ALLOC
1083+
#error "btstack requires MICROPY_TRACKED_ALLOC"
1084+
#endif
1085+
1086+
typedef struct {
1087+
btstack_context_callback_registration_t btstack_registration;
1088+
int gatts_op;
1089+
uint16_t conn_handle;
1090+
uint16_t value_handle;
1091+
size_t value_len;
1092+
uint8_t value[];
1093+
} notify_indicate_pending_op_t;
1094+
1095+
// Called in response to a gatts_notify/indicate being unable to complete, which then calls
1096+
// att_server_request_to_send_notification.
1097+
STATIC void btstack_notify_indicate_ready_handler(void *context) {
1098+
MICROPY_PY_BLUETOOTH_ENTER
1099+
notify_indicate_pending_op_t *pending_op = (notify_indicate_pending_op_t *)context;
1100+
DEBUG_printf("btstack_notify_indicate_ready_handler gatts_op=%d conn_handle=%d value_handle=%d len=%lu\n", pending_op->gatts_op, pending_op->conn_handle, pending_op->value_handle, pending_op->value_len);
1101+
int err = ERROR_CODE_SUCCESS;
1102+
switch (pending_op->gatts_op) {
1103+
case MP_BLUETOOTH_GATTS_OP_NOTIFY:
1104+
err = att_server_notify(pending_op->conn_handle, pending_op->value_handle, pending_op->value, pending_op->value_len);
1105+
DEBUG_printf("btstack_notify_indicate_ready_handler: sending notification err=%d\n", err);
1106+
break;
1107+
case MP_BLUETOOTH_GATTS_OP_INDICATE:
1108+
err = att_server_indicate(pending_op->conn_handle, pending_op->value_handle, pending_op->value, pending_op->value_len);
1109+
DEBUG_printf("btstack_notify_indicate_ready_handler: sending indication err=%d\n", err);
1110+
break;
1111+
}
1112+
assert(err == ERROR_CODE_SUCCESS);
1113+
(void)err;
1114+
MICROPY_PY_BLUETOOTH_EXIT
1115+
m_tracked_free(pending_op);
1116+
}
1117+
10821118
int mp_bluetooth_gatts_notify_indicate(uint16_t conn_handle, uint16_t value_handle, int gatts_op, const uint8_t *value, size_t value_len) {
1083-
DEBUG_printf("mp_bluetooth_gatts_notify_indicate\n");
1119+
DEBUG_printf("mp_bluetooth_gatts_notify_indicate: gatts_op=%d\n", gatts_op);
10841120

10851121
if (!mp_bluetooth_is_active()) {
10861122
return ERRNO_BLUETOOTH_NOT_ACTIVE;
@@ -1107,10 +1143,33 @@ int mp_bluetooth_gatts_notify_indicate(uint16_t conn_handle, uint16_t value_hand
11071143
}
11081144
MICROPY_PY_BLUETOOTH_EXIT
11091145

1110-
if (err == BTSTACK_ACL_BUFFERS_FULL) {
1111-
DEBUG_printf("mp_bluetooth_gatts_notify_indicate: ACL buffer full, scheduling callback\n");
1146+
if (err == BTSTACK_ACL_BUFFERS_FULL || err == ATT_HANDLE_VALUE_INDICATION_IN_PROGRESS) {
1147+
DEBUG_printf("mp_bluetooth_gatts_notify_indicate: ACL buffer full / indication in progress, scheduling callback\n");
1148+
1149+
// Copy the value and ask btstack to let us know when it can be sent.
1150+
notify_indicate_pending_op_t *pending_op = m_tracked_calloc(1, sizeof(notify_indicate_pending_op_t) + value_len);
1151+
pending_op->btstack_registration.context = pending_op;
1152+
pending_op->btstack_registration.callback = &btstack_notify_indicate_ready_handler;
1153+
pending_op->gatts_op = gatts_op;
1154+
pending_op->conn_handle = conn_handle;
1155+
pending_op->value_handle = value_handle;
1156+
pending_op->value_len = value_len;
1157+
memcpy(pending_op->value, value, value_len);
1158+
1159+
MICROPY_PY_BLUETOOTH_ENTER
1160+
switch (gatts_op) {
1161+
case MP_BLUETOOTH_GATTS_OP_NOTIFY:
1162+
err = att_server_request_to_send_notification(&pending_op->btstack_registration, conn_handle);
1163+
break;
1164+
case MP_BLUETOOTH_GATTS_OP_INDICATE:
1165+
err = att_server_request_to_send_indication(&pending_op->btstack_registration, conn_handle);
1166+
break;
1167+
}
1168+
MICROPY_PY_BLUETOOTH_EXIT
11121169

1113-
// TODO: re-implement the handling for this.
1170+
if (err != ERROR_CODE_SUCCESS) {
1171+
m_tracked_free(pending_op);
1172+
}
11141173
}
11151174

11161175
return btstack_error_to_errno(err);

ports/rp2/mpconfigport.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
#define MICROPY_OPT_COMPUTED_GOTO (1)
7575

7676
// Python internal features
77-
#define MICROPY_TRACKED_ALLOC (MICROPY_SSL_MBEDTLS)
77+
#define MICROPY_TRACKED_ALLOC (MICROPY_SSL_MBEDTLS || MICROPY_BLUETOOTH_BTSTACK)
7878
#define MICROPY_READER_VFS (1)
7979
#define MICROPY_ENABLE_GC (1)
8080
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)

ports/stm32/mpconfigport.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
#endif
6666

6767
// Python internal features
68-
#define MICROPY_TRACKED_ALLOC (MICROPY_SSL_MBEDTLS)
68+
#define MICROPY_TRACKED_ALLOC (MICROPY_SSL_MBEDTLS || MICROPY_BLUETOOTH_BTSTACK)
6969
#define MICROPY_READER_VFS (1)
7070
#define MICROPY_ENABLE_GC (1)
7171
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)

ports/unix/mpconfigport.h

+3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ typedef long mp_off_t;
117117
#define MICROPY_HELPER_LEXER_UNIX (1)
118118
#define MICROPY_VFS_POSIX (1)
119119
#define MICROPY_READER_POSIX (1)
120+
#ifndef MICROPY_TRACKED_ALLOC
121+
#define MICROPY_TRACKED_ALLOC (MICROPY_BLUETOOTH_BTSTACK)
122+
#endif
120123

121124
// VFS stat functions should return time values relative to 1970/1/1
122125
#define MICROPY_EPOCH_IS_1970 (1)

ports/unix/variants/coverage/mpconfigvariant.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@
3939

4040
// Enable additional features.
4141
#define MICROPY_DEBUG_PARSE_RULE_NAME (1)
42-
#define MICROPY_TRACKED_ALLOC (1)
42+
#define MICROPY_TRACKED_ALLOC (1)
4343
#define MICROPY_WARNINGS_CATEGORY (1)
4444
#define MICROPY_PY_UCRYPTOLIB_CTR (1)

py/gc.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,9 @@ void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
746746
// TODO: freeing here does not call finaliser
747747
void gc_free(void *ptr) {
748748
if (MP_STATE_THREAD(gc_lock_depth) > 0) {
749-
// TODO how to deal with this error?
749+
// Cannot free while the GC is locked. However free is an optimisation
750+
// to reclaim the memory immediately, this means it will now be left
751+
// until the next collection.
750752
return;
751753
}
752754

0 commit comments

Comments
 (0)