Skip to content
Snippets Groups Projects
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 card10/firmware!491
parents cf092b1e a9a4051b
Branches
No related tags found
No related merge requests found
...@@ -6,13 +6,6 @@ ...@@ -6,13 +6,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.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 { typedef struct _pendig_gattc_operation_obj_t {
mp_obj_base_t base; mp_obj_base_t base;
uint16_t conn_handle; uint16_t conn_handle;
...@@ -24,22 +17,29 @@ typedef struct _pendig_gattc_operation_obj_t { ...@@ -24,22 +17,29 @@ typedef struct _pendig_gattc_operation_obj_t {
STATIC const mp_obj_type_t pending_gattc_operation_type; 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 { typedef struct _mp_bluetooth_card10_root_pointers_t {
// Characteristic (and descriptor) value storage. // Characteristic (and descriptor) value storage.
mp_gatts_db_t gatts_db; mp_gatts_db_t gatts_db;
mp_gatts_db_t gatts_status;
mp_obj_t attc_pending; mp_obj_t attc_pending;
mp_obj_t atts_pending;
} mp_bluetooth_card10_root_pointers_t; } mp_bluetooth_card10_root_pointers_t;
#define GATTS_DB (MP_STATE_PORT(bluetooth_card10_root_pointers)->gatts_db) #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 \ #define ATTC_PENDING \
(MP_STATE_PORT(bluetooth_card10_root_pointers)->attc_pending) (MP_STATE_PORT(bluetooth_card10_root_pointers)->attc_pending)
#define ATTS_PENDING \
typedef struct { (MP_STATE_PORT(bluetooth_card10_root_pointers)->atts_pending)
enum notification_status notification_status;
} gatts_status_entry_t;
static bool active = false; static bool active = false;
static mp_obj_bluetooth_uuid_t uuid_filter; static mp_obj_bluetooth_uuid_t uuid_filter;
...@@ -52,29 +52,6 @@ static void raise(void) ...@@ -52,29 +52,6 @@ static void raise(void)
mp_raise_NotImplementedError(not_implemented_message); 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) static void clear_events(void)
{ {
struct epic_ble_event ble_event; struct epic_ble_event ble_event;
...@@ -91,12 +68,62 @@ static void clear_events(void) ...@@ -91,12 +68,62 @@ static void clear_events(void)
static void handle_att_event(struct epic_att_event *att_event) static void handle_att_event(struct epic_att_event *att_event)
{ {
if (att_event->hdr.event == ATTS_HANDLE_VALUE_CNF) { if (att_event->hdr.event == ATTS_HANDLE_VALUE_CNF) {
gatts_status_entry_t *e = size_t len;
gatts_status_lookup(GATTS_STATUS, att_event->handle); mp_obj_t *items;
if (att_event->hdr.status == ATT_SUCCESS) { if (att_event->hdr.status == ATT_SUCCESS) {
e->notification_status = NOTIFICATION_STATUS_SUCCESS;
} else if (att_event->hdr.status == ATT_ERR_OVERFLOW) { } 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) ...@@ -371,6 +398,16 @@ static void handle_dm_event(struct epic_dm_event *dm_event)
0xFF, 0xFF,
addr 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) ...@@ -430,8 +467,8 @@ int mp_bluetooth_init(void)
m_new0(mp_bluetooth_card10_root_pointers_t, 1); m_new0(mp_bluetooth_card10_root_pointers_t, 1);
mp_bluetooth_gatts_db_create(&GATTS_DB); mp_bluetooth_gatts_db_create(&GATTS_DB);
mp_bluetooth_gatts_db_create(&GATTS_STATUS);
ATTC_PENDING = mp_obj_new_list(0, NULL); ATTC_PENDING = mp_obj_new_list(0, NULL);
ATTS_PENDING = mp_obj_new_list(0, NULL);
mp_interrupt_set_callback( mp_interrupt_set_callback(
MP_ROM_INT(EPIC_INT_BLE), (mp_obj_t *)&ble_event_obj MP_ROM_INT(EPIC_INT_BLE), (mp_obj_t *)&ble_event_obj
...@@ -582,7 +619,6 @@ int mp_bluetooth_gatts_register_service( ...@@ -582,7 +619,6 @@ int mp_bluetooth_gatts_register_service(
mp_bluetooth_gatts_db_create_entry( mp_bluetooth_gatts_db_create_entry(
GATTS_DB, value_handle, MP_BLUETOOTH_DEFAULT_ATTR_LEN GATTS_DB, value_handle, MP_BLUETOOTH_DEFAULT_ATTR_LEN
); );
gatts_status_create_entry(GATTS_STATUS, value_handle);
if ((flags & MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY) || if ((flags & MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY) ||
flags & (MP_BLUETOOTH_CHARACTERISTIC_FLAG_INDICATE)) { flags & (MP_BLUETOOTH_CHARACTERISTIC_FLAG_INDICATE)) {
...@@ -711,59 +747,68 @@ int mp_bluetooth_gatts_notify_send( ...@@ -711,59 +747,68 @@ int mp_bluetooth_gatts_notify_send(
const uint8_t *value, const uint8_t *value,
size_t value_len size_t value_len
) { ) {
// TODO: We could make use of a list similar to GATTC operations to pending_gatts_operation_obj_t *op = m_new_obj_var(
// avoid polling for the return value in this function pending_gatts_operation_obj_t, uint8_t, value_len
gatts_status_entry_t *e = );
gatts_status_lookup(GATTS_STATUS, value_handle); op->base.type = &pending_gatts_operation_type;
e->notification_status = NOTIFICATION_STATUS_PENDING; 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));
size_t len;
mp_obj_t *items;
mp_obj_list_get(ATTS_PENDING, &len, &items);
int ret = epic_ble_atts_handle_value_ntf( int ret = 0;
if (len == 1) {
ret = epic_ble_atts_handle_value_ntf(
conn_handle, value_handle, value_len, (uint8_t *)value conn_handle, value_handle, value_len, (uint8_t *)value
); );
}
if (ret < 0) { if (ret < 0) {
// TODO: better error mapping
return ret; return ret;
} }
while (e->notification_status == NOTIFICATION_STATUS_PENDING) {
mp_ble_poll_events(0);
}
if (e->notification_status != NOTIFICATION_STATUS_SUCCESS) {
// TODO: better error mapping
return -EIO;
}
return 0; return 0;
} }
// Indicate the central. // Indicate the central.
int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) 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. // Note: cordio doesn't appear to support sending a notification without a value, so include the stored value.
uint8_t *value = NULL; uint8_t *value = NULL;
size_t value_len = 0; size_t value_len = 0;
mp_bluetooth_gatts_read(value_handle, &value, &value_len); mp_bluetooth_gatts_read(value_handle, &value, &value_len);
int ret = epic_ble_atts_handle_value_ind( pending_gatts_operation_obj_t *op = m_new_obj_var(
conn_handle, value_handle, value_len, (uint8_t *)value 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) { size_t len;
return ret; mp_obj_t *items;
} mp_obj_list_get(ATTS_PENDING, &len, &items);
while (e->notification_status == NOTIFICATION_STATUS_PENDING) { int ret = 0;
mp_ble_poll_events(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 // TODO: better error mapping
return -EIO; return ret;
} }
// TODO: How does the cordio stack signal that the indication was acked? // TODO: How does the cordio stack signal that the indication was acked?
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment