att: ENABLE_ATT_DELAYED_READ_RESPONSE -> ENABLE_ATT_DELAYED_RESPONSE, example/att_delayed_read_response.c -> example/att_delayed_response.c

This commit is contained in:
Matthias Ringwald 2018-08-27 11:01:19 +02:00
parent 1cd21c0571
commit beb202884a
15 changed files with 96 additions and 57 deletions

View File

@ -85,7 +85,7 @@ ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS | Use [micro-ecc library](https://git
ENABLE_LE_DATA_CHANNELS | Enable LE Data Channels in credit-based flow control mode
ENABLE_LE_DATA_LENGTH_EXTENSION | Enable LE Data Length Extension support
ENABLE_LE_SIGNED_WRITE | Enable LE Signed Writes in ATT/GATT
ENABLE_ATT_DELAYED_READ_RESPONSE | Enable support for delayed ATT Read operations, see [GATT Server](profiles/#sec:GATTServerProfile)
ENABLE_ATT_DELAYED_RESPONSE | Enable support for delayed ATT operations, see [GATT Server](profiles/#sec:GATTServerProfile)
ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE | Enable L2CAP Enhanced Retransmission Mode. Mandatory for AVRCP Browsing
ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL | Enable HCI Controller to Host Flow Control, see below
ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND | Enable workaround for bug in CC256x Flow Control during baud rate change, see chipset docs.

View File

@ -469,7 +469,7 @@ To send a Notification, you can call *att_server_request_can_send_now*
to receive a ATT_EVENT_CAN_SEND_NOW event.
If your application cannot handle an ATT Read Request in the *att_read_callback*
in some situations, you can enable support for this by adding ENABLE_ATT_DELAYED_READ_RESPONSE
in some situations, you can enable support for this by adding ENABLE_ATT_DELAYED_RESPONSE
to *btstack_config.h*. Now, you can store the requested attribute handle and return
*ATT_READ_RESPONSE_PENDING* instead of the length of the provided data when you don't have the data ready.
For ATT operations that read more than one attribute, your *att_read_callback*
@ -477,7 +477,7 @@ might get called multiple times as well. To let you know that all necessary
attribute handles have been 'requested' by the *att_server*, you'll get a final
*att_read_callback* with the attribute handle of *ATT_READ_RESPONSE_PENDING*.
When you've got the data for all requested attributes ready, you can call
*att_server_read_response_ready*, which will trigger processing of the current request.
*att_server_response_ready*, which will trigger processing of the current request.
Please keep in mind that there is only one active ATT operation and that it has a 30 second
timeout after which the ATT server is considered defunct by the GATT Client.

View File

@ -108,7 +108,7 @@ HXCMOD_PLAYER = \
${BTSTACK_ROOT}/3rd-party/hxcmod-player/mods/nao-deceased_by_disease.c \
EXAMPLES = \
att_delayed_read_response \
att_delayed_response \
a2dp_sink_demo \
a2dp_source_demo \
ancs_client_demo \
@ -207,8 +207,8 @@ spp_counter: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} spp_counter.c
le_counter: le_counter.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_OBJ} battery_service_server.o le_counter.c
${CC} $(filter-out le_counter.h,$^) ${CFLAGS} ${LDFLAGS} -o $@
att_delayed_read_response: att_delayed_read_response.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_OBJ} att_delayed_read_response.c
${CC} $(filter-out att_delayed_read_response.h,$^) ${CFLAGS} ${LDFLAGS} -o $@
att_delayed_response: att_delayed_response.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_OBJ} att_delayed_response.c
${CC} $(filter-out att_delayed_response.h,$^) ${CFLAGS} ${LDFLAGS} -o $@
hog_keyboard_demo: hog_keyboard_demo.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_OBJ} battery_service_server.o device_information_service_server.o hids_device.o btstack_ring_buffer.o hog_keyboard_demo.c
${CC} $(filter-out hog_keyboard_demo.h,$^) ${CFLAGS} ${LDFLAGS} -o $@

View File

@ -1,10 +0,0 @@
PRIMARY_SERVICE, GAP_SERVICE
CHARACTERISTIC, GAP_DEVICE_NAME, READ, "LE Counter"
PRIMARY_SERVICE, GATT_SERVICE
CHARACTERISTIC, GATT_SERVICE_CHANGED, READ,
// Counter Service
PRIMARY_SERVICE, 0000FF10-0000-1000-8000-00805F9B34FB
// Counter Characteristic, with read and notify
CHARACTERISTIC, 0000FF11-0000-1000-8000-00805F9B34FB, READ | NOTIFY | DYNAMIC,

View File

@ -35,14 +35,18 @@
*
*/
#define __BTSTACK_FILE__ "att_delayed_read_response.c"
#define __BTSTACK_FILE__ "att_delayed_response.c"
// *****************************************************************************
/* EXAMPLE_START(att_delayed_read_response): LE Peripheral - Delayed Read Response
/* EXAMPLE_START(att_delayed_response): LE Peripheral - Delayed Response
*
* @text If the value for a GATT Chararacteristic isn't available, the value
* ATT_READ_RESPONSE_PENDING can be returned. When the value is available,
* att_server_read_response_ready is then called to complete the ATT request.
* @text If the value for a GATT Chararacteristic isn't availabl for read,
* the value ATT_READ_RESPONSE_PENDING can be returned. When the value is available,
* att_server_response_ready is then called to complete the ATT request.
*
* Similarly, the error code ATT_ERROR_WRITE_RESPONSE_PENING can be returned when
* it is unclear if a write can be performed or not. When the decision was made,
* att_server_response_ready is is then called to complete the ATT request.
*/
// *****************************************************************************
@ -51,7 +55,7 @@
#include <stdlib.h>
#include <string.h>
#include "att_delayed_read_response.h"
#include "att_delayed_response.h"
#include "btstack.h"
#define ATT_VALUE_DELAY_MS 3000
@ -69,19 +73,20 @@
*/
/* LISTING_START(MainConfiguration): Init L2CAP SM ATT Server */
#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE
#ifdef ENABLE_ATT_DELAYED_RESPONSE
static btstack_timer_source_t att_timer;
static hci_con_handle_t con_handle;
static int value_ready;
#endif
static uint16_t att_read_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);
static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size);
const uint8_t adv_data[] = {
// Flags general discoverable, BR/EDR not supported
0x02, 0x01, 0x06,
// Name
0x0b, 0x09, 'L', 'E', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r',
0x08, 0x09, 'D', 'e', 'l', 'a', 'y', 'e', 'd',
};
const uint8_t adv_data_len = sizeof(adv_data);
@ -98,7 +103,7 @@ static void example_setup(void){
sm_init();
// setup ATT server
att_server_init(profile_data, att_read_callback, NULL);
att_server_init(profile_data, att_read_callback, att_write_callback);
// setup advertisements
uint16_t adv_int_min = 0x0030;
@ -117,7 +122,7 @@ static void example_setup(void){
*
* @text The att_invalidate_value handler 'invalidates' the value of the single Characteristic provided in this example
*/
#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE
#ifdef ENABLE_ATT_DELAYED_RESPONSE
static void att_invalidate_value(struct btstack_timer_source *ts){
UNUSED(ts);
printf("Value got stale\n");
@ -132,14 +137,13 @@ static void att_invalidate_value(struct btstack_timer_source *ts){
*/
/* LISTING_START(att_read_delay): ATT Read Delay Handler */
#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE
#ifdef ENABLE_ATT_DELAYED_RESPONSE
static void att_update_value(struct btstack_timer_source *ts){
UNUSED(ts);
value_ready = 1;
// trigger ATT Server to try request again
int status = att_server_read_response_ready(con_handle);
int status = att_server_response_ready(con_handle);
printf("Value updated -> complete ATT request - status %02x\n", status);
@ -169,7 +173,7 @@ static void att_update_value(struct btstack_timer_source *ts){
// @param offset defines start of attribute value
static uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
#ifdef ENABLE_ATT_DELAYED_READ_RESPONSE
#ifdef ENABLE_ATT_DELAYED_RESPONSE
switch (att_handle){
case ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE:
if (value_ready){
@ -193,15 +197,50 @@ static uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t a
}
#else
UNUSED(connection_handle);
// useless code when ENABLE_ATT_DELAYED_READ_RESPONSE is not defined - but avoids built errors
// useless code when ENABLE_ATT_DELAYED_RESPONSE is not defined - but avoids built errors
if (att_handle == ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE){
printf("ENABLE_ATT_DELAYED_READ_RESPONSE not defined in btstack_config.h, responding right away");
printf("ENABLE_ATT_DELAYED_RESPONSE not defined in btstack_config.h, responding right away");
return att_read_callback_handle_blob((const uint8_t *)test_string, strlen(test_string), offset, buffer, buffer_size);
}
#endif
return 0;
}
/*
* @section ATT Write
* */
/* LISTING_START(attWrite): ATT Write */
static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){
UNUSED(transaction_mode);
UNUSED(offset);
UNUSED(buffer_size);
UNUSED(connection_handle);
if (att_handle == ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE) {
printf("Write request, value: ");
printf_hexdump(buffer, buffer_size);
#ifdef ENABLE_ATT_DELAYED_RESPONSE
if (value_ready){
printf("Write callback, value ready\n");
return 0;
} else {
printf("Write callback for handle %02x, but not ready -> return response pending\n", att_handle);
}
// simulated delayed response for example
att_timer.process = &att_update_value;
btstack_run_loop_set_timer(&att_timer, ATT_VALUE_DELAY_MS);
btstack_run_loop_add_timer(&att_timer);
return ATT_ERROR_WRITE_RESPONSE_PENDING;
#else
printf("ENABLE_ATT_DELAYED_RESPONSE not defined in btstack_config.h, responding right away");
return 0;
#endif
}
return 0;
}
/* LISTING_END */
int btstack_main(void);

View File

@ -0,0 +1,10 @@
PRIMARY_SERVICE, GAP_SERVICE
CHARACTERISTIC, GAP_DEVICE_NAME, READ, "Delayed Response"
PRIMARY_SERVICE, GATT_SERVICE
CHARACTERISTIC, GATT_SERVICE_CHANGED, READ,
// Some Service
PRIMARY_SERVICE, 0000FF10-0000-1000-8000-00805F9B34FB
// Some Characteristic, with read and write
CHARACTERISTIC, 0000FF11-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC,

View File

@ -61,6 +61,5 @@ spp_and_le_streamer.h
spp_counter
spp_streamer
spp_streamer_client
spp_streamer_client
att_delayed_read_response
att_delayed_read_response.h
att_delayed_response
att_delayed_response.h

View File

@ -21,7 +21,7 @@
#define ENABLE_LE_DATA_CHANNELS
#define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS
#define ENABLE_LE_DATA_LENGTH_EXTENSION
#define ENABLE_ATT_DELAYED_READ_RESPONSE
#define ENABLE_ATT_DELAYED_RESPONSE
#define ENABLE_LOG_ERROR
#define ENABLE_LOG_INFO
#define ENABLE_SCO_OVER_HCI

View File

@ -47,5 +47,5 @@ le_streamer_client
pbap_client_demo
sm_pairing_central
sm_pairing_peripheral
att_delayed_read_response
att_delayed_read_response.h

View File

@ -1,5 +1,6 @@
ancs_client_demo
ancs_client_demo.h
att_delayed_response.h
ble_central_test
ble_peripheral
ble_peripheral_sm_minimal
@ -16,7 +17,9 @@ gap_inquiry
gap_inquiry_and_bond
gap_le_advertisements
gatt_battery_query
gatt_battery_query.h
gatt_browser
gatt_browser.h
hfp_ag_demo
hfp_hf_demo
hsp_ag_demo
@ -28,12 +31,16 @@ le_counter
le_counter.h
le_streamer
le_streamer.h
le_streamer_client
led_counter
pbap_client_demo
profile.h
sco_input.wav
sdp_bnep_query
sdp_general_query
sdp_rfcomm_query
sm_pairing_central
sm_pairing_peripheral
sm_pairing_peripheral.h
spp_and_le_counter
spp_and_le_counter.h
@ -41,11 +48,3 @@ spp_counter
spp_streamer
TIInit_12.10.28.c
TIInit_12.8.32.c
gatt_battery_query.h
gatt_browser.h
le_streamer_client
pbap_client_demo
sm_pairing_central
sm_pairing_peripheral
att_delayed_read_response.h

View File

@ -22,7 +22,7 @@
#define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS
#define ENABLE_LE_DATA_CHANNELS
#define ENABLE_LE_DATA_LENGTH_EXTENSION
#define ENABLE_ATT_DELAYED_READ_RESPONSE
#define ENABLE_ATT_DELAYED_RESPONSE
#define ENABLE_LOG_ERROR
#define ENABLE_LOG_INFO
#define ENABLE_SCO_OVER_HCI

View File

@ -54,8 +54,9 @@ extern "C" {
// custom BTstack ATT error codes
#define ATT_ERROR_DATA_MISMATCH 0x7e
#define ATT_ERROR_TIMEOUT 0x7F
#define ATT_ERROR_WRITE_RESPONSE_PENDING 0x100
// custom BTstack ATT Response Pending
// custom BTstack ATT Response Pending for att_read_callback
#define ATT_READ_RESPONSE_PENDING 0xffff
typedef struct att_connection {

View File

@ -386,10 +386,10 @@ 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
#ifdef ENABLE_ATT_DELAYED_RESPONSE
if (att_response_size == ATT_READ_RESPONSE_PENDING){
// update state
att_server->state = ATT_SERVER_READ_RESPONSE_PENDING;
att_server->state = ATT_SERVER_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);
@ -434,11 +434,11 @@ 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){
#ifdef ENABLE_ATT_DELAYED_RESPONSE
int att_server_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;
if (!att_server) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
if (att_server->state != ATT_SERVER_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);

View File

@ -135,14 +135,15 @@ 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
#ifdef ENABLE_ATT_DELAYED_RESPONSE
/*
* @brief read response ready - called after returning ATT_READ_RESPONSE_PENDING in an att_read_callback before
* @brief response ready - called after returning ATT_READ__RESPONSE_PENDING in an att_read_callback or
* ATT_ERROR_WRITE_REQUEST_PENDING IN att_write_callback before to trigger callback again and complete the transaction
* @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);
int att_server_response_ready(hci_con_handle_t con_handle);
#endif
/* API_END */

View File

@ -410,7 +410,7 @@ typedef enum {
ATT_SERVER_REQUEST_RECEIVED,
ATT_SERVER_W4_SIGNED_WRITE_VALIDATION,
ATT_SERVER_REQUEST_RECEIVED_AND_VALIDATED,
ATT_SERVER_READ_RESPONSE_PENDING,
ATT_SERVER_RESPONSE_PENDING,
} att_server_state_t;
typedef struct {