Commit 81200c2a authored by schneider's avatar schneider
Browse files

Merge branch 'schneider/mp-ble-gatts-queue' into 'master'

feat(ble): Add a queue for indications and notifications

See merge request !491
parents cf092b1e a9a4051b
Pipeline #5314 passed with stages
in 2 minutes and 31 seconds
......@@ -6,13 +6,6 @@
#include <stdio.h>
#include <string.h>
enum notification_status {
NOTIFICATION_STATUS_UNKNOWN,
NOTIFICATION_STATUS_PENDING,
NOTIFICATION_STATUS_SUCCESS,
NOTIFICATION_STATUS_OVERFLOW
};
typedef struct _pendig_gattc_operation_obj_t {
mp_obj_base_t base;
uint16_t conn_handle;
......@@ -24,22 +17,29 @@ typedef struct _pendig_gattc_operation_obj_t {
STATIC const mp_obj_type_t pending_gattc_operation_type;
typedef struct _pendig_gatts_operation_obj_t {
mp_obj_base_t base;
uint16_t conn_handle;
uint16_t value_handle;
bool indication;
uint16_t value_len;
uint8_t value[];
} pending_gatts_operation_obj_t;
STATIC const mp_obj_type_t pending_gatts_operation_type;
typedef struct _mp_bluetooth_card10_root_pointers_t {
// Characteristic (and descriptor) value storage.
mp_gatts_db_t gatts_db;
mp_gatts_db_t gatts_status;
mp_obj_t attc_pending;
mp_obj_t atts_pending;
} mp_bluetooth_card10_root_pointers_t;
#define GATTS_DB (MP_STATE_PORT(bluetooth_card10_root_pointers)->gatts_db)
#define GATTS_STATUS \
(MP_STATE_PORT(bluetooth_card10_root_pointers)->gatts_status)
#define ATTC_PENDING \
(MP_STATE_PORT(bluetooth_card10_root_pointers)->attc_pending)
typedef struct {
enum notification_status notification_status;
} gatts_status_entry_t;
#define ATTS_PENDING \
(MP_STATE_PORT(bluetooth_card10_root_pointers)->atts_pending)
static bool active = false;
static mp_obj_bluetooth_uuid_t uuid_filter;
......@@ -52,29 +52,6 @@ static void raise(void)
mp_raise_NotImplementedError(not_implemented_message);
}
static void gatts_status_create_entry(mp_gatts_db_t db, uint16_t handle)
{
mp_map_elem_t *elem = mp_map_lookup(
db,
MP_OBJ_NEW_SMALL_INT(handle),
MP_MAP_LOOKUP_ADD_IF_NOT_FOUND
);
gatts_status_entry_t *entry = m_new(gatts_status_entry_t, 1);
entry->notification_status = NOTIFICATION_STATUS_UNKNOWN;
elem->value = MP_OBJ_FROM_PTR(entry);
}
static gatts_status_entry_t *
gatts_status_lookup(mp_gatts_db_t db, uint16_t handle)
{
mp_map_elem_t *elem =
mp_map_lookup(db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP);
if (!elem) {
mp_raise_OSError(-EACCES);
}
return MP_OBJ_TO_PTR(elem->value);
}
static void clear_events(void)
{
struct epic_ble_event ble_event;
......@@ -91,12 +68,62 @@ static void clear_events(void)
static void handle_att_event(struct epic_att_event *att_event)
{
if (att_event->hdr.event == ATTS_HANDLE_VALUE_CNF) {
gatts_status_entry_t *e =
gatts_status_lookup(GATTS_STATUS, att_event->handle);
size_t len;
mp_obj_t *items;
if (att_event->hdr.status == ATT_SUCCESS) {
e->notification_status = NOTIFICATION_STATUS_SUCCESS;
} else if (att_event->hdr.status == ATT_ERR_OVERFLOW) {
e->notification_status = NOTIFICATION_STATUS_OVERFLOW;
} else if (att_event->hdr.status == ATT_ERR_MTU_EXCEEDED) {
} else {
}
mp_obj_list_get(ATTS_PENDING, &len, &items);
for (size_t i = 0; i < len; i++) {
pending_gatts_operation_obj_t *op =
MP_OBJ_TO_PTR(items[i]);
//TODO: Can we diff between ntf/ind?
//TODO: get conn_handle from event
if (op->conn_handle == 1 &&
op->value_handle == att_event->handle) {
if (op->indication) {
mp_bluetooth_gatts_on_indicate_complete(
op->conn_handle,
op->value_handle,
att_event->hdr.status
);
}
mp_obj_subscr(
ATTS_PENDING,
MP_OBJ_NEW_SMALL_INT(i),
MP_OBJ_NULL
);
break;
}
}
/* Prepare next item to be sent */
mp_obj_list_get(ATTS_PENDING, &len, &items);
if (len > 0) {
pending_gatts_operation_obj_t *op =
MP_OBJ_TO_PTR(items[0]);
if (op->indication == false) {
epic_ble_atts_handle_value_ntf(
op->conn_handle,
op->value_handle,
op->value_len,
op->value
);
} else {
epic_ble_atts_handle_value_ind(
op->conn_handle,
op->value_handle,
op->value_len,
op->value
);
}
}
}
......@@ -371,6 +398,16 @@ static void handle_dm_event(struct epic_dm_event *dm_event)
0xFF,
addr
);
size_t len;
mp_obj_t *items;
mp_obj_list_get(ATTS_PENDING, &len, &items);
for (size_t i = 0; i < len; i++) {
mp_obj_subscr(
ATTS_PENDING,
MP_OBJ_NEW_SMALL_INT(i),
MP_OBJ_NULL
);
}
}
}
......@@ -430,8 +467,8 @@ int mp_bluetooth_init(void)
m_new0(mp_bluetooth_card10_root_pointers_t, 1);
mp_bluetooth_gatts_db_create(&GATTS_DB);
mp_bluetooth_gatts_db_create(&GATTS_STATUS);
ATTC_PENDING = mp_obj_new_list(0, NULL);
ATTS_PENDING = mp_obj_new_list(0, NULL);
mp_interrupt_set_callback(
MP_ROM_INT(EPIC_INT_BLE), (mp_obj_t *)&ble_event_obj
......@@ -582,7 +619,6 @@ int mp_bluetooth_gatts_register_service(
mp_bluetooth_gatts_db_create_entry(
GATTS_DB, value_handle, MP_BLUETOOTH_DEFAULT_ATTR_LEN
);
gatts_status_create_entry(GATTS_STATUS, value_handle);
if ((flags & MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY) ||
flags & (MP_BLUETOOTH_CHARACTERISTIC_FLAG_INDICATE)) {
......@@ -711,59 +747,68 @@ int mp_bluetooth_gatts_notify_send(
const uint8_t *value,
size_t value_len
) {
// TODO: We could make use of a list similar to GATTC operations to
// avoid polling for the return value in this function
gatts_status_entry_t *e =
gatts_status_lookup(GATTS_STATUS, value_handle);
e->notification_status = NOTIFICATION_STATUS_PENDING;
int ret = epic_ble_atts_handle_value_ntf(
conn_handle, value_handle, value_len, (uint8_t *)value
pending_gatts_operation_obj_t *op = m_new_obj_var(
pending_gatts_operation_obj_t, uint8_t, value_len
);
op->base.type = &pending_gatts_operation_type;
op->conn_handle = conn_handle;
op->value_handle = value_handle;
op->indication = false;
op->value_len = value_len;
memcpy(op->value, value, value_len);
mp_obj_list_append(ATTS_PENDING, MP_OBJ_FROM_PTR(op));
if (ret < 0) {
return ret;
}
size_t len;
mp_obj_t *items;
mp_obj_list_get(ATTS_PENDING, &len, &items);
while (e->notification_status == NOTIFICATION_STATUS_PENDING) {
mp_ble_poll_events(0);
int ret = 0;
if (len == 1) {
ret = epic_ble_atts_handle_value_ntf(
conn_handle, value_handle, value_len, (uint8_t *)value
);
}
if (e->notification_status != NOTIFICATION_STATUS_SUCCESS) {
if (ret < 0) {
// TODO: better error mapping
return -EIO;
return ret;
}
return 0;
}
// Indicate the central.
int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle)
{
// TODO: We could make use of a list similar to GATTC operations to
// avoid polling for the return value in this function
gatts_status_entry_t *e =
gatts_status_lookup(GATTS_STATUS, value_handle);
e->notification_status = NOTIFICATION_STATUS_PENDING;
// Note: cordio doesn't appear to support sending a notification without a value, so include the stored value.
uint8_t *value = NULL;
size_t value_len = 0;
mp_bluetooth_gatts_read(value_handle, &value, &value_len);
int ret = epic_ble_atts_handle_value_ind(
conn_handle, value_handle, value_len, (uint8_t *)value
pending_gatts_operation_obj_t *op = m_new_obj_var(
pending_gatts_operation_obj_t, uint8_t, value_len
);
op->base.type = &pending_gatts_operation_type;
op->conn_handle = conn_handle;
op->value_handle = value_handle;
op->indication = true;
op->value_len = value_len;
memcpy(op->value, value, value_len);
mp_obj_list_append(ATTS_PENDING, MP_OBJ_FROM_PTR(op));
if (ret < 0) {
return ret;
}
size_t len;
mp_obj_t *items;
mp_obj_list_get(ATTS_PENDING, &len, &items);
while (e->notification_status == NOTIFICATION_STATUS_PENDING) {
mp_ble_poll_events(0);
int ret = 0;
if (len == 1) {
ret = epic_ble_atts_handle_value_ind(
conn_handle, value_handle, value_len, (uint8_t *)value
);
}
if (e->notification_status != NOTIFICATION_STATUS_SUCCESS) {
if (ret < 0) {
// TODO: better error mapping
return -EIO;
return ret;
}
// TODO: How does the cordio stack signal that the indication was acked?
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment