diff --git a/ble/att.c b/ble/att.c index d511fe406..2405301d5 100644 --- a/ble/att.c +++ b/ble/att.c @@ -92,6 +92,8 @@ static uint16_t uuid16_from_uuid(uint16_t uuid_len, uint8_t * uuid){ static uint8_t const * att_db = NULL; static att_read_callback_t att_read_callback = NULL; static att_write_callback_t att_write_callback = NULL; +static att_prepare_write_error_code = 0; +static att_prepare_write_error_handle = 0x0000; // new java-style iterator typedef struct att_iterator { @@ -230,6 +232,26 @@ void att_dump_attributes(void){ } } +static void att_prepare_write_reset(){ + att_prepare_write_error_code = 0; + att_prepare_write_error_handle = 0x0000; +} + +static void att_prepare_write_update_errors(uint8_t error_code, uint16_t handle){ + // first ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH has highest priority + if (error_code == ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH && error_code != att_prepare_write_error_code){ + att_prepare_write_error_code = error_code; + att_prepare_write_error_handle = handle; + return; + } + // first ATT_ERROR_INVALID_OFFSET is next + if (error_code == ATT_ERROR_INVALID_OFFSET && att_prepare_write_error_code == 0){ + att_prepare_write_error_code = error_code; + att_prepare_write_error_handle = handle; + return; + } +} + static uint16_t setup_error(uint8_t * response_buffer, uint16_t request, uint16_t handle, uint8_t error_code){ response_buffer[0] = ATT_ERROR_RESPONSE; response_buffer[1] = request; @@ -887,9 +909,17 @@ static uint16_t handle_prepare_write_request(att_connection_t * att_connection, return setup_error(response_buffer, request_type, handle, error_code); } - int result = (*att_write_callback)(handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5, NULL); - if (result){ - return setup_error(response_buffer, request_type, handle, result); + error_code = (*att_write_callback)(handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5, NULL); + switch (error_code){ + case 0: + break; + case ATT_ERROR_INVALID_OFFSET: + case ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH: + // postpone to execute write request + att_prepare_write_update_errors(error_code, handle); + break; + default: + return setup_error(response_buffer, request_type, handle, error_code); } // response: echo request @@ -909,6 +939,14 @@ static uint16_t handle_execute_write_request(att_connection_t * att_connection, return setup_error_write_not_permitted(response_buffer, request_type, 0); } if (request_buffer[1]) { + // deliver queued errors + if (att_prepare_write_error_code){ + (*att_write_callback)(0, ATT_TRANSACTION_MODE_CANCEL, 0, request_buffer + 3, request_len - 3, NULL); + uint8_t error_code = att_prepare_write_error_code; + uint16_t handle = att_prepare_write_error_handle; + att_prepare_write_reset(); + return setup_error(response_buffer, request_type, handle, error_code); + } (*att_write_callback)(0, ATT_TRANSACTION_MODE_EXECUTE, 0, request_buffer + 3, request_len - 3, NULL); } else { (*att_write_callback)(0, ATT_TRANSACTION_MODE_CANCEL, 0, request_buffer + 3, request_len - 3, NULL);