From e404a68886935ab5663e81c68e710063e21f5480 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Thu, 22 Feb 2018 17:28:09 +0100 Subject: [PATCH] att: support for delayed att read response --- src/ble/att_db.c | 35 +++++++++++++++++++++++++++++++++++ src/ble/att_db.h | 15 ++++++++++----- src/ble/att_server.c | 23 ++++++++++++++++++++++- src/ble/att_server.h | 10 ++++++++++ 4 files changed, 77 insertions(+), 6 deletions(-) diff --git a/src/ble/att_db.c b/src/ble/att_db.c index 7e4325b2f..7dbbedc2e 100644 --- a/src/ble/att_db.c +++ b/src/ble/att_db.c @@ -494,6 +494,10 @@ static uint16_t handle_read_by_type_request2(att_connection_t * att_connection, uint8_t error_code = 0; uint16_t first_matching_but_unreadable_handle = 0; +#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE + int read_request_pending = 0; +#endif + while (att_iterator_has_next(&it)){ att_iterator_fetch_next(&it); @@ -520,6 +524,13 @@ static uint16_t handle_read_by_type_request2(att_connection_t * att_connection, att_update_value_len(&it, att_connection->con_handle); +#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE + if (it.value_len == ATT_READ_RESPONSE_PENDING){ + read_request_pending = 1; + } + if (read_request_pending) continue; +#endif + // check if value has same len as last one uint16_t this_pair_len = 2 + it.value_len; if (offset > 1){ @@ -549,6 +560,10 @@ static uint16_t handle_read_by_type_request2(att_connection_t * att_connection, offset += bytes_copied; } +#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE + if (read_request_pending) return ATT_READ_RESPONSE_PENDING; +#endif + // at least one attribute could be read if (offset > 1){ response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE; @@ -609,6 +624,10 @@ static uint16_t handle_read_request2(att_connection_t * att_connection, uint8_t att_update_value_len(&it, att_connection->con_handle); +#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE + if (it.value_len == ATT_READ_RESPONSE_PENDING) return ATT_READ_RESPONSE_PENDING; +#endif + uint16_t offset = 1; // limit data if (offset + it.value_len > response_buffer_size) { @@ -657,6 +676,10 @@ static uint16_t handle_read_blob_request2(att_connection_t * att_connection, uin att_update_value_len(&it, att_connection->con_handle); +#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE + if (it.value_len == ATT_READ_RESPONSE_PENDING) return ATT_READ_RESPONSE_PENDING; +#endif + if (value_offset > it.value_len){ return setup_error_invalid_offset(response_buffer, request_type, handle); } @@ -698,6 +721,11 @@ static uint16_t handle_read_multiple_request2(att_connection_t * att_connection, int i; uint8_t error_code = 0; uint16_t handle = 0; + +#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE + int read_request_pending = 0; +#endif + for (i=0;icon_handle); +#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE + if (it.value_len == ATT_READ_RESPONSE_PENDING) { + read_request_pending = 1; + } + if (read_request_pending) continue; +#endif + // limit data if (offset + it.value_len > response_buffer_size) { it.value_len = response_buffer_size - 1; diff --git a/src/ble/att_db.h b/src/ble/att_db.h index 4f42b7687..330d09daa 100644 --- a/src/ble/att_db.h +++ b/src/ble/att_db.h @@ -48,12 +48,15 @@ extern "C" { #endif // custom BTstack error codes -#define ATT_ERROR_HCI_DISCONNECT_RECEIVED 0x1f +#define ATT_ERROR_HCI_DISCONNECT_RECEIVED 0x1f // custom BTstack ATT error codes -#define ATT_ERROR_DATA_MISMATCH 0x7e -#define ATT_ERROR_TIMEOUT 0x7F - +#define ATT_ERROR_DATA_MISMATCH 0x7e +#define ATT_ERROR_TIMEOUT 0x7F + +// custom BTstack ATT Response Pending +#define ATT_READ_RESPONSE_PENDING 0xffff + typedef struct att_connection { hci_con_handle_t con_handle; uint16_t mtu; // initialized to ATT_DEFAULT_MTU (23), negotiated during MTU exchange @@ -66,6 +69,7 @@ typedef struct att_connection { // ATT Client Read Callback for Dynamic Data // - if buffer == NULL, don't copy data, just return size of value // - if buffer != NULL, copy data and return number bytes copied +// If ENABLE_ATT_DELAYED_READ_RESPONSE is defined, you may return ATT_READ_RESPONSE_PENDING if data isn't available yet // @param con_handle of hci le connection // @param attribute_handle to be read // @param offset defines start of attribute value @@ -130,7 +134,8 @@ void att_dump_attributes(void); * @param att_connection used for mtu and security properties * @param request_buffer, request_len: ATT request from clinet * @param response_buffer for result - * @returns len of data in response buffer. 0 = no response + * @returns len of data in response buffer. 0 = no response, + * ATT_READ_RESPONSE_PENDING if it was returned at least once for dynamic data (requires ENABLE_ATT_DELAYED_READ_RESPONSE) */ uint16_t att_handle_request(att_connection_t * att_connection, uint8_t * request_buffer, diff --git a/src/ble/att_server.c b/src/ble/att_server.c index d1b910382..4c0a43eb8 100644 --- a/src/ble/att_server.c +++ b/src/ble/att_server.c @@ -340,6 +340,16 @@ static int att_server_process_validated_request(att_server_t * att_server){ uint8_t * att_response_buffer = l2cap_get_outgoing_buffer(); uint16_t att_response_size = att_handle_request(&att_server->connection, att_server->request_buffer, att_server->request_size, att_response_buffer); +#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE + if (att_response_size == ATT_READ_RESPONSE_PENDING){ + // update state + att_server->state = ATT_SERVER_READ_RESPONSE_PENDING; + + // callback with handle ATT_READ_RESPONSE_PENDING + att_server_client_read_callback(att_server->connection.con_handle, ATT_READ_RESPONSE_PENDING, 0, NULL, 0); + } +#endif + // intercept "insufficient authorization" for authenticated connections to allow for user authorization if ((att_response_size >= 4) && (att_response_buffer[0] == ATT_ERROR_RESPONSE) @@ -374,6 +384,18 @@ static int att_server_process_validated_request(att_server_t * att_server){ return 1; } +#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE +int att_server_read_response_ready(hci_con_handle_t con_handle){ + att_server_t * att_server = att_server_for_handle(con_handle); + if (!att_server) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + if (att_server->state != ATT_SERVER_READ_RESPONSE_PENDING) return ERROR_CODE_COMMAND_DISALLOWED; + + att_server->state = ATT_SERVER_REQUEST_RECEIVED_AND_VALIDATED; + att_dispatch_server_request_can_send_now_event(con_handle); + return ERROR_CODE_SUCCESS; +} +#endif + static void att_run_for_context(att_server_t * att_server){ switch (att_server->state){ case ATT_SERVER_REQUEST_RECEIVED: @@ -829,7 +851,6 @@ void att_server_register_can_send_now_callback(btstack_context_callback_registra att_dispatch_server_request_can_send_now_event(con_handle); } - int att_server_notify(hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t *value, uint16_t value_len){ att_server_t * att_server = att_server_for_handle(con_handle); if (!att_server) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; diff --git a/src/ble/att_server.h b/src/ble/att_server.h index 053ffa8e5..380f006e4 100644 --- a/src/ble/att_server.h +++ b/src/ble/att_server.h @@ -112,6 +112,16 @@ int att_server_notify(hci_con_handle_t con_handle, uint16_t attribute_handle, ui */ int att_server_indicate(hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t *value, uint16_t value_len); +#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE +/* + * @brief read response ready - called after returning ATT_READ_RESPONSE_PENDING in an att_read_callback before + * @nore The ATT Server will retry handling the current ATT request + * @param con_handle + * @return 0 if ok, error otherwise + */ +int att_server_read_response_ready(hci_con_handle_t con_handle); +#endif + /* API_END */ #if defined __cplusplus