Skip to content

Commit bc9ec1c

Browse files
committed
extmod/modbluetooth: Merge gatts_notify/indicate implementation.
Makes gatts_notify and gatts_indicate work in the same way: by default they send the DB value, but you can manually override the payload. In other words, makes gatts_indicate work the same as gatts_notify. Note: This removes support for queuing notifications and indications on btstack when the ACL buffer is full. This functionality will be reimplemented in a future commit. Signed-off-by: Jim Mussared <[email protected]>
1 parent 9e6885a commit bc9ec1c

File tree

6 files changed

+88
-173
lines changed

6 files changed

+88
-173
lines changed

docs/library/bluetooth.rst

+12-7
Original file line numberDiff line numberDiff line change
@@ -514,19 +514,24 @@ writes from a client to a given characteristic, use
514514

515515
Sends a notification request to a connected client.
516516

517-
If *data* is not ``None``, then that value is sent to the client as part of
518-
the notification. The local value will not be modified.
517+
If *data* is ``None`` (the default), then the current local value (as set
518+
with :meth:`gatts_write <BLE.gatts_write>`) will be sent.
519519

520-
Otherwise, if *data* is ``None``, then the current local value (as
521-
set with :meth:`gatts_write <BLE.gatts_write>`) will be sent.
520+
Otherwise, if *data* is not ``None``, then that value is sent to the client
521+
as part of the notification. The local value will not be modified.
522522

523523
**Note:** The notification will be sent regardless of the subscription
524524
status of the client to this characteristic.
525525

526-
.. method:: BLE.gatts_indicate(conn_handle, value_handle, /)
526+
.. method:: BLE.gatts_indicate(conn_handle, value_handle, data=None, /)
527527

528-
Sends an indication request containing the characteristic's current value to
529-
a connected client.
528+
Sends a indication request to a connected client.
529+
530+
If *data* is ``None`` (the default), then the current local value (as set
531+
with :meth:`gatts_write <BLE.gatts_write>`) will be sent.
532+
533+
Otherwise, if *data* is not ``None``, then that value is sent to the client
534+
as part of the indication. The local value will not be modified.
530535

531536
On acknowledgment (or failure, e.g. timeout), the
532537
``_IRQ_GATTS_INDICATE_DONE`` event will be raised.

extmod/btstack/modbluetooth_btstack.c

+23-102
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,6 @@ STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(uint16_t uuid16, const uint8_t *uu
130130
// Pending operation types.
131131
enum {
132132
// Queued for sending when possible.
133-
MP_BLUETOOTH_BTSTACK_PENDING_NOTIFY, // Waiting for context callback
134-
MP_BLUETOOTH_BTSTACK_PENDING_INDICATE, // Waiting for context callback
135133
MP_BLUETOOTH_BTSTACK_PENDING_WRITE_NO_RESPONSE, // Waiting for conn handle
136134
// Hold buffer pointer until complete.
137135
MP_BLUETOOTH_BTSTACK_PENDING_WRITE, // Waiting for write done event
@@ -150,11 +148,7 @@ struct _mp_btstack_pending_op_t {
150148
uint16_t conn_handle;
151149
uint16_t value_handle;
152150

153-
// For notify/indicate only.
154-
// context_registration.context will point back to this struct.
155-
btstack_context_callback_registration_t context_registration;
156-
157-
// For notify/indicate/write-without-response, this is the actual buffer to send.
151+
// For write-without-response, this is the actual buffer to send.
158152
// For write-with-response, just holding onto the buffer for GC ref.
159153
size_t len;
160154
uint8_t buf[];
@@ -170,30 +164,6 @@ STATIC void btstack_remove_pending_operation(mp_btstack_pending_op_t *pending_op
170164
}
171165
}
172166

173-
// Called in response to a gatts_notify/indicate being unable to complete, which then calls
174-
// att_server_request_to_send_notification.
175-
// We now have an opportunity to re-try the operation with an empty ACL buffer.
176-
STATIC void btstack_notify_indicate_ready_handler(void *context) {
177-
MICROPY_PY_BLUETOOTH_ENTER
178-
mp_btstack_pending_op_t *pending_op = (mp_btstack_pending_op_t *)context;
179-
DEBUG_printf("btstack_notify_indicate_ready_handler op_type=%d conn_handle=%d value_handle=%d len=%zu\n", pending_op->op_type, pending_op->conn_handle, pending_op->value_handle, pending_op->len);
180-
if (pending_op->op_type == MP_BLUETOOTH_BTSTACK_PENDING_NOTIFY) {
181-
int err = att_server_notify(pending_op->conn_handle, pending_op->value_handle, pending_op->buf, pending_op->len);
182-
DEBUG_printf("btstack_notify_indicate_ready_handler: sending notification err=%d\n", err);
183-
assert(err == ERROR_CODE_SUCCESS);
184-
(void)err;
185-
} else {
186-
assert(pending_op->op_type == MP_BLUETOOTH_BTSTACK_PENDING_INDICATE);
187-
int err = att_server_indicate(pending_op->conn_handle, pending_op->value_handle, NULL, 0);
188-
DEBUG_printf("btstack_notify_indicate_ready_handler: sending indication err=%d\n", err);
189-
assert(err == ERROR_CODE_SUCCESS);
190-
(void)err;
191-
}
192-
// Can't free the pending op as we're in IRQ context. Leave it for the GC.
193-
btstack_remove_pending_operation(pending_op, false /* del */);
194-
MICROPY_PY_BLUETOOTH_EXIT
195-
}
196-
197167
// Register a pending background operation -- copies the buffer, and makes it known to the GC.
198168
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) {
199169
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);
@@ -204,11 +174,6 @@ STATIC mp_btstack_pending_op_t *btstack_enqueue_pending_operation(uint16_t op_ty
204174
pending_op->len = len;
205175
memcpy(pending_op->buf, buf, len);
206176

207-
if (op_type == MP_BLUETOOTH_BTSTACK_PENDING_NOTIFY || op_type == MP_BLUETOOTH_BTSTACK_PENDING_INDICATE) {
208-
pending_op->context_registration.callback = &btstack_notify_indicate_ready_handler;
209-
pending_op->context_registration.context = pending_op;
210-
}
211-
212177
MICROPY_PY_BLUETOOTH_ENTER
213178
bool added = btstack_linked_list_add(&MP_STATE_PORT(bluetooth_btstack_root_pointers)->pending_ops, (btstack_linked_item_t *)pending_op);
214179
assert(added);
@@ -854,7 +819,7 @@ void mp_bluetooth_set_io_capability(uint8_t capability) {
854819
#endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
855820

856821
size_t mp_bluetooth_gap_get_device_name(const uint8_t **buf) {
857-
uint8_t *value = NULL;
822+
const uint8_t *value = NULL;
858823
size_t value_len = 0;
859824
mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, BTSTACK_GAP_DEVICE_NAME_HANDLE, &value, &value_len);
860825
*buf = value;
@@ -1095,7 +1060,7 @@ int mp_bluetooth_gatts_register_service_end(void) {
10951060
return 0;
10961061
}
10971062

1098-
int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len) {
1063+
int mp_bluetooth_gatts_read(uint16_t value_handle, const uint8_t **value, size_t *value_len) {
10991064
DEBUG_printf("mp_bluetooth_gatts_read\n");
11001065
if (!mp_bluetooth_is_active()) {
11011066
return ERRNO_BLUETOOTH_NOT_ACTIVE;
@@ -1114,85 +1079,41 @@ int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t
11141079
return mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, value, value_len);
11151080
}
11161081

1117-
int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle) {
1118-
DEBUG_printf("mp_bluetooth_gatts_notify\n");
1082+
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");
11191084

11201085
if (!mp_bluetooth_is_active()) {
11211086
return ERRNO_BLUETOOTH_NOT_ACTIVE;
11221087
}
11231088

1124-
// Note: btstack doesn't appear to support sending a notification without a value, so include the stored value.
1125-
uint8_t *data = NULL;
1126-
size_t len = 0;
1127-
mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, &data, &len);
1128-
return mp_bluetooth_gatts_notify_send(conn_handle, value_handle, data, len);
1129-
}
1130-
1131-
int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len) {
1132-
DEBUG_printf("mp_bluetooth_gatts_notify_send\n");
1133-
1134-
if (!mp_bluetooth_is_active()) {
1135-
return ERRNO_BLUETOOTH_NOT_ACTIVE;
1089+
if (!value) {
1090+
// NULL value means "use DB value".
1091+
mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, &value, &value_len);
11361092
}
11371093

1094+
int err = ERROR_CODE_UNKNOWN_HCI_COMMAND;
1095+
11381096
// Attempt to send immediately. If it succeeds, btstack will copy the buffer.
11391097
MICROPY_PY_BLUETOOTH_ENTER
1140-
int err = att_server_notify(conn_handle, value_handle, value, value_len);
1141-
MICROPY_PY_BLUETOOTH_EXIT
1142-
1143-
if (err == BTSTACK_ACL_BUFFERS_FULL) {
1144-
DEBUG_printf("mp_bluetooth_gatts_notify_send: ACL buffer full, scheduling callback\n");
1145-
// Schedule callback, making a copy of the buffer.
1146-
mp_btstack_pending_op_t *pending_op = btstack_enqueue_pending_operation(MP_BLUETOOTH_BTSTACK_PENDING_NOTIFY, conn_handle, value_handle, value, value_len);
1147-
1148-
err = att_server_request_to_send_notification(&pending_op->context_registration, conn_handle);
1149-
1150-
if (err != ERROR_CODE_SUCCESS) {
1151-
// Failure. Unref and free the pending operation.
1152-
btstack_remove_pending_operation(pending_op, true /* del */);
1153-
}
1154-
1155-
return 0;
1156-
} else {
1157-
return btstack_error_to_errno(err);
1158-
}
1159-
}
1160-
1161-
int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) {
1162-
DEBUG_printf("mp_bluetooth_gatts_indicate\n");
1163-
1164-
if (!mp_bluetooth_is_active()) {
1165-
return ERRNO_BLUETOOTH_NOT_ACTIVE;
1098+
switch (gatts_op) {
1099+
case MP_BLUETOOTH_GATTS_OP_NOTIFY:
1100+
err = att_server_notify(conn_handle, value_handle, value, value_len);
1101+
break;
1102+
case MP_BLUETOOTH_GATTS_OP_INDICATE:
1103+
// Indicate will raise ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE when
1104+
// acknowledged (or timeout/error).
1105+
err = att_server_indicate(conn_handle, value_handle, value, value_len);
1106+
break;
11661107
}
1167-
1168-
uint8_t *data = NULL;
1169-
size_t len = 0;
1170-
mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, &data, &len);
1171-
1172-
// Indicate will raise ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE when
1173-
// acknowledged (or timeout/error).
1174-
1175-
// Attempt to send immediately, will copy buffer.
1176-
MICROPY_PY_BLUETOOTH_ENTER
1177-
int err = att_server_indicate(conn_handle, value_handle, data, len);
11781108
MICROPY_PY_BLUETOOTH_EXIT
11791109

11801110
if (err == BTSTACK_ACL_BUFFERS_FULL) {
1181-
DEBUG_printf("mp_bluetooth_gatts_indicate: ACL buffer full, scheduling callback\n");
1182-
// Schedule callback, making a copy of the buffer.
1183-
mp_btstack_pending_op_t *pending_op = btstack_enqueue_pending_operation(MP_BLUETOOTH_BTSTACK_PENDING_INDICATE, conn_handle, value_handle, data, len);
1184-
1185-
err = att_server_request_to_send_indication(&pending_op->context_registration, conn_handle);
1186-
1187-
if (err != ERROR_CODE_SUCCESS) {
1188-
// Failure. Unref and free the pending operation.
1189-
btstack_remove_pending_operation(pending_op, true /* del */);
1190-
}
1111+
DEBUG_printf("mp_bluetooth_gatts_notify_indicate: ACL buffer full, scheduling callback\n");
11911112

1192-
return 0;
1193-
} else {
1194-
return btstack_error_to_errno(err);
1113+
// TODO: re-implement the handling for this.
11951114
}
1115+
1116+
return btstack_error_to_errno(err);
11961117
}
11971118

11981119
int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append) {

extmod/modbluetooth.c

+15-17
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_passkey_obj, 4, 4,
733733
STATIC mp_obj_t bluetooth_ble_gatts_read(mp_obj_t self_in, mp_obj_t value_handle_in) {
734734
(void)self_in;
735735
size_t len = 0;
736-
uint8_t *buf;
736+
const uint8_t *buf;
737737
mp_bluetooth_gatts_read(mp_obj_get_int(value_handle_in), &buf, &len);
738738
return mp_obj_new_bytes(buf, len);
739739
}
@@ -751,32 +751,30 @@ STATIC mp_obj_t bluetooth_ble_gatts_write(size_t n_args, const mp_obj_t *args) {
751751
}
752752
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_write_obj, 3, 4, bluetooth_ble_gatts_write);
753753

754-
STATIC mp_obj_t bluetooth_ble_gatts_notify(size_t n_args, const mp_obj_t *args) {
754+
STATIC mp_obj_t bluetooth_ble_gatts_notify_indicate(size_t n_args, const mp_obj_t *args, int gatts_op) {
755755
mp_int_t conn_handle = mp_obj_get_int(args[1]);
756756
mp_int_t value_handle = mp_obj_get_int(args[2]);
757757

758+
const uint8_t *value = NULL;
759+
size_t value_len = 0;
758760
if (n_args == 4 && args[3] != mp_const_none) {
759761
mp_buffer_info_t bufinfo = {0};
760762
mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
761-
int err = mp_bluetooth_gatts_notify_send(conn_handle, value_handle, bufinfo.buf, bufinfo.len);
762-
bluetooth_handle_errno(err);
763-
return mp_const_none;
764-
} else {
765-
int err = mp_bluetooth_gatts_notify(conn_handle, value_handle);
766-
return bluetooth_handle_errno(err);
763+
value = bufinfo.buf;
764+
value_len = bufinfo.len;
767765
}
766+
return bluetooth_handle_errno(mp_bluetooth_gatts_notify_indicate(conn_handle, value_handle, gatts_op, value, value_len));
768767
}
769-
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_notify_obj, 3, 4, bluetooth_ble_gatts_notify);
770768

771-
STATIC mp_obj_t bluetooth_ble_gatts_indicate(mp_obj_t self_in, mp_obj_t conn_handle_in, mp_obj_t value_handle_in) {
772-
(void)self_in;
773-
mp_int_t conn_handle = mp_obj_get_int(conn_handle_in);
774-
mp_int_t value_handle = mp_obj_get_int(value_handle_in);
769+
STATIC mp_obj_t bluetooth_ble_gatts_notify(size_t n_args, const mp_obj_t *args) {
770+
return bluetooth_ble_gatts_notify_indicate(n_args, args, MP_BLUETOOTH_GATTS_OP_NOTIFY);
771+
}
772+
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_notify_obj, 3, 4, bluetooth_ble_gatts_notify);
775773

776-
int err = mp_bluetooth_gatts_indicate(conn_handle, value_handle);
777-
return bluetooth_handle_errno(err);
774+
STATIC mp_obj_t bluetooth_ble_gatts_indicate(size_t n_args, const mp_obj_t *args) {
775+
return bluetooth_ble_gatts_notify_indicate(n_args, args, MP_BLUETOOTH_GATTS_OP_INDICATE);
778776
}
779-
STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_gatts_indicate_obj, bluetooth_ble_gatts_indicate);
777+
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_indicate_obj, 3, 4, bluetooth_ble_gatts_indicate);
780778

781779
STATIC mp_obj_t bluetooth_ble_gatts_set_buffer(size_t n_args, const mp_obj_t *args) {
782780
mp_int_t value_handle = mp_obj_get_int(args[1]);
@@ -1718,7 +1716,7 @@ mp_bluetooth_gatts_db_entry_t *mp_bluetooth_gatts_db_lookup(mp_gatts_db_t db, ui
17181716
return MP_OBJ_TO_PTR(elem->value);
17191717
}
17201718

1721-
int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, uint8_t **value, size_t *value_len) {
1719+
int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, const uint8_t **value, size_t *value_len) {
17221720
MICROPY_PY_BLUETOOTH_ENTER
17231721
mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle);
17241722
if (entry) {

extmod/modbluetooth.h

+8-8
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@
186186
#define MP_BLUETOOTH_PASSKEY_ACTION_DISPLAY (3)
187187
#define MP_BLUETOOTH_PASSKEY_ACTION_NUMERIC_COMPARISON (4)
188188

189+
// These are the ops for mp_bluetooth_gatts_notify_indicate.
190+
#define MP_BLUETOOTH_GATTS_OP_NOTIFY (1)
191+
#define MP_BLUETOOTH_GATTS_OP_INDICATE (2)
192+
189193
/*
190194
These aren't included in the module for space reasons, but can be used
191195
in your Python code if necessary.
@@ -333,15 +337,11 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m
333337
int mp_bluetooth_gatts_register_service_end(void);
334338

335339
// Read the value from the local gatts db (likely this has been written by a central).
336-
int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len);
340+
int mp_bluetooth_gatts_read(uint16_t value_handle, const uint8_t **value, size_t *value_len);
337341
// Write a value to the local gatts db (ready to be queried by a central). Optionally send notifications/indications.
338342
int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len, bool send_update);
339-
// Notify the central that it should do a read.
340-
int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle);
341-
// Notify the central, including a data payload. (Note: does not set the gatts db value).
342-
int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len);
343-
// Indicate the central.
344-
int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle);
343+
// Send a notification/indication to the central, optionally with custom payload (otherwise the DB value is used).
344+
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);
345345

346346
// Resize and enable/disable append-mode on a value.
347347
// Append-mode means that remote writes will append and local reads will clear after reading.
@@ -508,7 +508,7 @@ STATIC inline void mp_bluetooth_gatts_db_reset(mp_gatts_db_t db) {
508508

509509
void mp_bluetooth_gatts_db_create_entry(mp_gatts_db_t db, uint16_t handle, size_t len);
510510
mp_bluetooth_gatts_db_entry_t *mp_bluetooth_gatts_db_lookup(mp_gatts_db_t db, uint16_t handle);
511-
int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, uint8_t **value, size_t *value_len);
511+
int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, const uint8_t **value, size_t *value_len);
512512
int mp_bluetooth_gatts_db_write(mp_gatts_db_t db, uint16_t handle, const uint8_t *value, size_t value_len);
513513
int mp_bluetooth_gatts_db_resize(mp_gatts_db_t db, uint16_t handle, size_t len, bool append);
514514

extmod/nimble/modbluetooth_nimble.c

+28-23
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,7 @@ int mp_bluetooth_gap_disconnect(uint16_t conn_handle) {
10081008
return ble_hs_err_to_errno(ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM));
10091009
}
10101010

1011-
int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len) {
1011+
int mp_bluetooth_gatts_read(uint16_t value_handle, const uint8_t **value, size_t *value_len) {
10121012
if (!mp_bluetooth_is_active()) {
10131013
return ERRNO_BLUETOOTH_NOT_ACTIVE;
10141014
}
@@ -1026,35 +1026,40 @@ int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t
10261026
return err;
10271027
}
10281028

1029-
// TODO: Could use ble_gatts_chr_updated to send to all subscribed centrals.
1030-
1031-
int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle) {
1029+
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) {
10321030
if (!mp_bluetooth_is_active()) {
10331031
return ERRNO_BLUETOOTH_NOT_ACTIVE;
10341032
}
1035-
// Confusingly, notify/notify_custom/indicate are "gattc" function (even though they're used by peripherals (i.e. gatt servers)).
1036-
// See https://www.mail-archive.com/[email protected]/msg01293.html
1037-
return ble_hs_err_to_errno(ble_gattc_notify(conn_handle, value_handle));
1038-
}
10391033

1040-
int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len) {
1041-
if (!mp_bluetooth_is_active()) {
1042-
return ERRNO_BLUETOOTH_NOT_ACTIVE;
1043-
}
1044-
struct os_mbuf *om = ble_hs_mbuf_from_flat(value, value_len);
1045-
if (om == NULL) {
1046-
return MP_ENOMEM;
1034+
int err = BLE_HS_EINVAL;
1035+
1036+
// NULL om in the _custom methods means "use DB value" (NimBLE will call
1037+
// back into mp_bluetooth_gatts_read for us).
1038+
struct os_mbuf *om = NULL;
1039+
1040+
if (value) {
1041+
om = ble_hs_mbuf_from_flat(value, value_len);
1042+
if (om == NULL) {
1043+
return MP_ENOMEM;
1044+
}
10471045
}
1048-
return ble_hs_err_to_errno(ble_gattc_notify_custom(conn_handle, value_handle, om));
1049-
}
10501046

1051-
int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) {
1052-
if (!mp_bluetooth_is_active()) {
1053-
return ERRNO_BLUETOOTH_NOT_ACTIVE;
1047+
// Note: Confusingly, Nimble's notify/notify_custom and indicate/indicate_custom
1048+
// are "gattc" functions (even though they're used by peripherals, i.e. gatt servers).
1049+
// See https://www.mail-archive.com/[email protected]/msg01293.html
1050+
1051+
switch (gatts_op) {
1052+
case MP_BLUETOOTH_GATTS_OP_NOTIFY:
1053+
err = ble_gattc_notify_custom(conn_handle, value_handle, om);
1054+
break;
1055+
case MP_BLUETOOTH_GATTS_OP_INDICATE:
1056+
// This will raise BLE_GAP_EVENT_NOTIFY_TX with a status when it is
1057+
// acknowledged (or timeout/error).
1058+
err = ble_gattc_indicate_custom(conn_handle, value_handle, om);
1059+
break;
10541060
}
1055-
// This will raise BLE_GAP_EVENT_NOTIFY_TX with a status when it is
1056-
// acknowledged (or timeout/error).
1057-
return ble_hs_err_to_errno(ble_gattc_indicate(conn_handle, value_handle));
1061+
1062+
return ble_hs_err_to_errno(err);
10581063
}
10591064

10601065
int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append) {

0 commit comments

Comments
 (0)