Skip to content

Commit

Permalink
extmod/bluetooth: Allow registering multiple services.
Browse files Browse the repository at this point in the history
Now, Bluetooth().active(True) must only be called after all your services have been registered, this is what triggers the stack startup.
Bluetooth().handles() can be called to get a dict of all the service uuid's keyed to a tuple of char uuids with a buffer of the matching handles.
  • Loading branch information
pi-anl committed Sep 4, 2019
1 parent 422a66e commit 72b2d17
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 62 deletions.
67 changes: 59 additions & 8 deletions extmod/modbluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,35 @@ STATIC mp_obj_t bluetooth_handle_errno(int err) {
return mp_const_none;
}


// Allocate and store as root pointer.
// TODO: This is duplicated from mbedtls.
// Perhaps make this a generic feature?
void *m_malloc_bluetooth(size_t size) {
void **ptr = m_malloc0(size + 2 * sizeof(uintptr_t));
if (MP_STATE_PORT(bluetooth_nimble_memory) != NULL) {
MP_STATE_PORT(bluetooth_nimble_memory)[0] = ptr;
}
ptr[0] = NULL;
ptr[1] = MP_STATE_PORT(bluetooth_nimble_memory);
MP_STATE_PORT(bluetooth_nimble_memory) = ptr;
return &ptr[2];
}


// void m_free_bluetooth(void *ptr_in) {
// void **ptr = &((void**)ptr_in)[-2];
// if (ptr[1] != NULL) {
// ((void**)ptr[1])[0] = ptr[0];
// }
// if (ptr[0] != NULL) {
// ((void**)ptr[0])[1] = ptr[1];
// } else {
// MP_STATE_PORT(bluetooth_nimble_memory) = ptr[1];
// }
// m_free(ptr);
// }

// ----------------------------------------------------------------------------
// UUID object
// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -220,17 +249,26 @@ STATIC const mp_obj_type_t uuid_type = {
// ----------------------------------------------------------------------------

STATIC mp_obj_t bluetooth_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
mp_obj_t result;
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
if (MP_STATE_VM(bluetooth) == MP_OBJ_NULL) {
mp_obj_bluetooth_t *o = m_new_obj(mp_obj_bluetooth_t);
o->base.type = &bluetooth_type;
o->irq_handler = mp_const_none;
o->irq_trigger = 0;
ringbuf_alloc(&o->ringbuf, MICROPY_PY_BLUETOOTH_RINGBUF_SIZE);
mp_obj_dict_init(&o->char_handles, 1);
MP_STATE_VM(bluetooth) = MP_OBJ_FROM_PTR(o);
result = MP_STATE_VM(bluetooth);
MICROPY_END_ATOMIC_SECTION(atomic_state);

mp_bluetooth_init();
return result;
}
mp_obj_t result = MP_STATE_VM(bluetooth);

result = MP_STATE_VM(bluetooth);
MICROPY_END_ATOMIC_SECTION(atomic_state);

return result;
}

Expand Down Expand Up @@ -264,6 +302,12 @@ STATIC mp_obj_t bluetooth_config(mp_obj_t self_in, mp_obj_t param) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_config_obj, bluetooth_config);

STATIC mp_obj_t bluetooth_handles(mp_obj_t self_in) {
mp_obj_bluetooth_t *self = MP_OBJ_TO_PTR(self_in);
return MP_OBJ_FROM_PTR(&self->char_handles);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_handles_obj, bluetooth_handles);

// TODO: consider making trigger optional if handler=None
STATIC mp_obj_t bluetooth_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_handler, ARG_trigger };
Expand Down Expand Up @@ -353,18 +397,29 @@ STATIC mp_obj_t bluetooth_gatts_add_service(size_t n_args, const mp_obj_t *pos_a
uint8_t *characteristic_flags = m_new(uint8_t, len);
uint16_t *value_handles = m_new(uint16_t, len);

// Keep track of characteristics for each service in handles_db
// Along with the memory buffer used to hold the handle we get back from the stack
mp_obj_bluetooth_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_map_t * handles_db = mp_obj_dict_get_map(&self->char_handles);
mp_map_elem_t *elem = mp_map_lookup(handles_db, args[ARG_uuid].u_obj, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
mp_obj_tuple_t *char_details = mp_obj_new_tuple(2, NULL);
mp_obj_tuple_t *char_uuids_obj = mp_obj_new_tuple(len, NULL);
char_details->items[0] = char_uuids_obj;
char_details->items[1] = mp_obj_new_memoryview('H', len, value_handles);
elem->value = char_details;

// Extract out characteristic uuids & flags.
int i = 0;
while ((characteristic_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
mp_obj_tuple_t *characteristic = MP_OBJ_TO_PTR(characteristic_obj);

if (!mp_obj_is_type(characteristic_obj, &mp_type_tuple) || characteristic->len != 2) {
mp_raise_ValueError("invalid characteristic tuple");
}
mp_obj_t uuid_obj = characteristic->items[0];
if (!mp_obj_is_type(uuid_obj, &uuid_type)) {
mp_raise_ValueError("invalid characteristic uuid");
}
char_uuids_obj->items[i] = uuid_obj;
characteristic_uuids[i] = MP_OBJ_TO_PTR(uuid_obj);
characteristic_flags[i] = mp_obj_get_int(characteristic->items[1]);
value_handles[i] = 0xffff;
Expand All @@ -375,12 +430,7 @@ STATIC mp_obj_t bluetooth_gatts_add_service(size_t n_args, const mp_obj_t *pos_a
int err = mp_bluetooth_add_service(service_uuid, characteristic_uuids, characteristic_flags, value_handles, len);
bluetooth_handle_errno(err);

// Return tuple of value handles.
mp_obj_tuple_t *result = mp_obj_new_tuple(len, NULL);
for (int i = 0; i < len; i++) {
result->items[i] = MP_OBJ_NEW_SMALL_INT(value_handles[i]);
}
return MP_OBJ_FROM_PTR(result);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_gatts_add_service_obj, 1, bluetooth_gatts_add_service);

Expand Down Expand Up @@ -528,6 +578,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_gattc_write_obj, 4, 4, blue
STATIC const mp_rom_map_elem_t bluetooth_locals_dict_table[] = {
// General
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&bluetooth_active_obj) },
{ MP_ROM_QSTR(MP_QSTR_handles), MP_ROM_PTR(&bluetooth_handles_obj) },
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&bluetooth_config_obj) },
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&bluetooth_irq_obj) },
// GAP
Expand Down
9 changes: 9 additions & 0 deletions extmod/modbluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ typedef struct {
mp_obj_t irq_handler;
uint16_t irq_trigger;
ringbuf_t ringbuf;
mp_obj_dict_t char_handles;
} mp_obj_bluetooth_t;

// Common UUID type.
Expand All @@ -135,6 +136,11 @@ typedef struct {
} uuid;
} mp_obj_bluetooth_uuid_t;


// Memory allocation for bluetooth
void *m_malloc_bluetooth(size_t size);
#define m_new_bluetooth(type, num) ((type*)m_malloc_bluetooth(sizeof(type) * (num)))

//////////////////////////////////////////////////////////////
// API implemented by ports (i.e. called from modbluetooth.c):

Expand All @@ -144,6 +150,9 @@ typedef struct {

// Any method returning an int returns errno on failure, otherwise zero.

// Performs any initial setup for stack.
int mp_bluetooth_init(void);

// Enables the Bluetooth stack.
int mp_bluetooth_enable(void);

Expand Down
73 changes: 19 additions & 54 deletions extmod/modbluetooth_nimble.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,34 +87,6 @@ STATIC int ble_hs_err_to_errno(int err) {
}
}

// Allocate and store as root pointer.
// TODO: This is duplicated from mbedtls.
// Perhaps make this a generic feature?
void *m_malloc_bluetooth(size_t size) {
void **ptr = m_malloc0(size + 2 * sizeof(uintptr_t));
if (MP_STATE_PORT(bluetooth_nimble_memory) != NULL) {
MP_STATE_PORT(bluetooth_nimble_memory)[0] = ptr;
}
ptr[0] = NULL;
ptr[1] = MP_STATE_PORT(bluetooth_nimble_memory);
MP_STATE_PORT(bluetooth_nimble_memory) = ptr;
return &ptr[2];
}

#define m_new_bluetooth(type, num) ((type*)m_malloc_bluetooth(sizeof(type) * (num)))

// void m_free_bluetooth(void *ptr_in) {
// void **ptr = &((void**)ptr_in)[-2];
// if (ptr[1] != NULL) {
// ((void**)ptr[1])[0] = ptr[0];
// }
// if (ptr[0] != NULL) {
// ((void**)ptr[0])[1] = ptr[1];
// } else {
// MP_STATE_PORT(bluetooth_nimble_memory) = ptr[1];
// }
// m_free(ptr);
// }

STATIC ble_uuid_t* create_nimble_uuid(const mp_obj_bluetooth_uuid_t *uuid) {
if (uuid->type == MP_BLUETOOTH_UUID_TYPE_16) {
Expand Down Expand Up @@ -224,7 +196,7 @@ STATIC void sync_cb(void) {
rc = ble_hs_util_ensure_addr(0); // prefer public address
if (rc != 0) {
// https://mynewt.apache.org/latest/tutorials/ble/eddystone.html#configure-the-nimble-stack-with-an-address
#if MICROPY_PY_BLUETOOTH_RANDOM_ADDR
#if MICROPY_PY_BLUETOOTH_RANDOM_ADDR
rc = ble_hs_id_gen_rnd(1, &addr);
assert(rc == 0);
rc = ble_hs_id_set_rnd(addr.val);
Expand All @@ -235,7 +207,7 @@ STATIC void sync_cb(void) {
rc = ble_hs_id_set_rnd(addr.val);
assert(rc == 0);
#endif

rc = ble_hs_util_ensure_addr(0); // prefer public address
assert(rc == 0);
}
Expand All @@ -258,6 +230,8 @@ STATIC void gatts_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) {

case BLE_GATT_REGISTER_OP_CHR:
printf("gatts_register_cb: chr uuid=%p def_handle=%d val_handle=%d\n", &ctxt->chr.chr_def->uuid, ctxt->chr.def_handle, ctxt->chr.val_handle);
mp_map_elem_t *elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(ctxt->chr.val_handle), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
elem->value = MP_OBJ_FROM_PTR(m_new0(gatts_db_entry_t, 1));
break;

case BLE_GATT_REGISTER_OP_DSC:
Expand Down Expand Up @@ -297,20 +271,28 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) {
return 0;
}

int mp_bluetooth_enable(void) {
if (ble_state != BLE_STATE_OFF) {
return 0;
}

ble_state = BLE_STATE_STARTING;

int mp_bluetooth_init(void) {
ble_hs_cfg.reset_cb = reset_cb;
ble_hs_cfg.sync_cb = sync_cb;
ble_hs_cfg.gatts_register_cb = gatts_register_cb;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;

ble_hci_uart_init();
nimble_port_init();

// Register the default gap service
ble_svc_gap_init();

return 0;
}

int mp_bluetooth_enable(void) {
if (ble_state != BLE_STATE_OFF) {
return 0;
}

ble_state = BLE_STATE_STARTING;

ble_hs_sched_start();

// Wait for sync callback
Expand Down Expand Up @@ -484,12 +466,6 @@ int mp_bluetooth_add_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluet

int ret;

ret = ble_gatts_reset();
if (ret != 0) {
//printf("ble_gatts_reset: fail with %d\n", ret);
return ble_hs_err_to_errno(ret);
}

ret = ble_gatts_count_cfg(service);
if (ret != 0) {
//printf("ble_gatts_count_cfg: fail with %d\n", ret);
Expand All @@ -502,17 +478,6 @@ int mp_bluetooth_add_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluet
return ble_hs_err_to_errno(ret);
}

ret = ble_gatts_start();
if (ret != 0) {
//printf("ble_gatts_start: fail with %d\n", ret);
return ble_hs_err_to_errno(ret);
}

for (size_t i = 0; i < characteristic_len; ++i) {
mp_map_elem_t *elem = mp_map_lookup(gatts_db, MP_OBJ_NEW_SMALL_INT(value_handles[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
elem->value = MP_OBJ_FROM_PTR(m_new0(gatts_db_entry_t, 1));
}

return 0;
}

Expand Down

0 comments on commit 72b2d17

Please sign in to comment.