att: support for delayed att read response

This commit is contained in:
Matthias Ringwald 2018-02-22 17:28:09 +01:00
parent 75130320d7
commit e404a68886
4 changed files with 77 additions and 6 deletions

View File

@ -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;i<num_handles;i++){
handle = little_endian_read_16(handles, i << 1);
@ -725,6 +753,13 @@ static uint16_t handle_read_multiple_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
// limit data
if (offset + it.value_len > response_buffer_size) {
it.value_len = response_buffer_size - 1;

View File

@ -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,

View File

@ -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;

View File

@ -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