1beb20288SMatthias Ringwald /* 2beb20288SMatthias Ringwald * Copyright (C) 2018 BlueKitchen GmbH 3beb20288SMatthias Ringwald * 4beb20288SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5beb20288SMatthias Ringwald * modification, are permitted provided that the following conditions 6beb20288SMatthias Ringwald * are met: 7beb20288SMatthias Ringwald * 8beb20288SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9beb20288SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10beb20288SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11beb20288SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12beb20288SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13beb20288SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14beb20288SMatthias Ringwald * contributors may be used to endorse or promote products derived 15beb20288SMatthias Ringwald * from this software without specific prior written permission. 16beb20288SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17beb20288SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18beb20288SMatthias Ringwald * monetary gain. 19beb20288SMatthias Ringwald * 20beb20288SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21beb20288SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22beb20288SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23beb20288SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24beb20288SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25beb20288SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26beb20288SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27beb20288SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28beb20288SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29beb20288SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30beb20288SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31beb20288SMatthias Ringwald * SUCH DAMAGE. 32beb20288SMatthias Ringwald * 33beb20288SMatthias Ringwald * Please inquire about commercial licensing options at 34beb20288SMatthias Ringwald * [email protected] 35beb20288SMatthias Ringwald * 36beb20288SMatthias Ringwald */ 37beb20288SMatthias Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "att_delayed_response.c" 39beb20288SMatthias Ringwald 40beb20288SMatthias Ringwald // ***************************************************************************** 41beb20288SMatthias Ringwald /* EXAMPLE_START(att_delayed_response): LE Peripheral - Delayed Response 42beb20288SMatthias Ringwald * 43beb20288SMatthias Ringwald * @text If the value for a GATT Chararacteristic isn't availabl for read, 44beb20288SMatthias Ringwald * the value ATT_READ_RESPONSE_PENDING can be returned. When the value is available, 45beb20288SMatthias Ringwald * att_server_response_ready is then called to complete the ATT request. 46beb20288SMatthias Ringwald * 47beb20288SMatthias Ringwald * Similarly, the error code ATT_ERROR_WRITE_RESPONSE_PENING can be returned when 48beb20288SMatthias Ringwald * it is unclear if a write can be performed or not. When the decision was made, 49beb20288SMatthias Ringwald * att_server_response_ready is is then called to complete the ATT request. 50beb20288SMatthias Ringwald */ 51beb20288SMatthias Ringwald // ***************************************************************************** 52beb20288SMatthias Ringwald 53beb20288SMatthias Ringwald #include <stdint.h> 54beb20288SMatthias Ringwald #include <stdio.h> 55beb20288SMatthias Ringwald #include <stdlib.h> 56beb20288SMatthias Ringwald #include <string.h> 57beb20288SMatthias Ringwald 58beb20288SMatthias Ringwald #include "btstack.h" 59beb20288SMatthias Ringwald 60a63a688aSMatthias Ringwald // att_delayed_response.gatt contains the declaration of the provided GATT Services + Characteristics 61a63a688aSMatthias Ringwald // att_delayed_response.h contains the binary representation of att_delayed_response.gatt 62a63a688aSMatthias Ringwald // it is generated by the build system by calling: $BTSTACK_ROOT/tool/compile_gatt.py att_delayed_response.gatt att_delayed_response.h 63a63a688aSMatthias Ringwald // it needs to be regenerated when the GATT Database declared in att_delayed_response.gatt file is modified 64a63a688aSMatthias Ringwald #include "att_delayed_response.h" 65a63a688aSMatthias Ringwald 66beb20288SMatthias Ringwald #define ATT_VALUE_DELAY_MS 3000 67beb20288SMatthias Ringwald #define ATT_VALUE_INVALID_MS 5000 68beb20288SMatthias Ringwald 69beb20288SMatthias Ringwald /* @section Main Application Setup 70beb20288SMatthias Ringwald * 71beb20288SMatthias Ringwald * @text Listing MainConfiguration shows main application code. 72beb20288SMatthias Ringwald * It initializes L2CAP, the Security Manager and configures the ATT Server with the pre-compiled 73*bdc352b1SMatthias Ringwald * ATT Database generated from $att_delayed_response.gatt$. 74beb20288SMatthias Ringwald * Additionally, it enables the Battery Service Server with the current battery level. 75beb20288SMatthias Ringwald * Finally, it configures the advertisements and boots the Bluetooth stack. 76beb20288SMatthias Ringwald * In this example, the Advertisement contains the Flags attribute and the device name. 77beb20288SMatthias Ringwald * The flag 0x06 indicates: LE General Discoverable Mode and BR/EDR not supported. 78beb20288SMatthias Ringwald */ 79beb20288SMatthias Ringwald 80beb20288SMatthias Ringwald /* LISTING_START(MainConfiguration): Init L2CAP SM ATT Server */ 81beb20288SMatthias Ringwald #ifdef ENABLE_ATT_DELAYED_RESPONSE 82beb20288SMatthias Ringwald static btstack_timer_source_t att_timer; 83beb20288SMatthias Ringwald static hci_con_handle_t con_handle; 84beb20288SMatthias Ringwald static int value_ready; 85beb20288SMatthias Ringwald #endif 86beb20288SMatthias Ringwald 87beb20288SMatthias Ringwald 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); 88beb20288SMatthias Ringwald 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); 89beb20288SMatthias Ringwald 90beb20288SMatthias Ringwald const uint8_t adv_data[] = { 91beb20288SMatthias Ringwald // Flags general discoverable, BR/EDR not supported 92beb20288SMatthias Ringwald 0x02, 0x01, 0x06, 93beb20288SMatthias Ringwald // Name 94beb20288SMatthias Ringwald 0x08, 0x09, 'D', 'e', 'l', 'a', 'y', 'e', 'd', 95beb20288SMatthias Ringwald }; 96beb20288SMatthias Ringwald const uint8_t adv_data_len = sizeof(adv_data); 97beb20288SMatthias Ringwald 98beb20288SMatthias Ringwald const char * test_string = "Delayed response"; 99beb20288SMatthias Ringwald 100beb20288SMatthias Ringwald static void example_setup(void){ 101beb20288SMatthias Ringwald 102beb20288SMatthias Ringwald l2cap_init(); 103beb20288SMatthias Ringwald 104beb20288SMatthias Ringwald // setup le device db 105beb20288SMatthias Ringwald le_device_db_init(); 106beb20288SMatthias Ringwald 107beb20288SMatthias Ringwald // setup SM: Display only 108beb20288SMatthias Ringwald sm_init(); 109beb20288SMatthias Ringwald 110beb20288SMatthias Ringwald // setup ATT server 111beb20288SMatthias Ringwald att_server_init(profile_data, att_read_callback, att_write_callback); 112beb20288SMatthias Ringwald 113beb20288SMatthias Ringwald // setup advertisements 114beb20288SMatthias Ringwald uint16_t adv_int_min = 0x0030; 115beb20288SMatthias Ringwald uint16_t adv_int_max = 0x0030; 116beb20288SMatthias Ringwald uint8_t adv_type = 0; 117beb20288SMatthias Ringwald bd_addr_t null_addr; 118beb20288SMatthias Ringwald memset(null_addr, 0, 6); 119beb20288SMatthias Ringwald gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00); 120beb20288SMatthias Ringwald gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data); 121beb20288SMatthias Ringwald gap_advertisements_enable(1); 122beb20288SMatthias Ringwald } 123beb20288SMatthias Ringwald /* LISTING_END */ 124beb20288SMatthias Ringwald 125beb20288SMatthias Ringwald /* 126beb20288SMatthias Ringwald * @section att_invalidate_value Handler 127beb20288SMatthias Ringwald * 128beb20288SMatthias Ringwald * @text The att_invalidate_value handler 'invalidates' the value of the single Characteristic provided in this example 129beb20288SMatthias Ringwald */ 130beb20288SMatthias Ringwald #ifdef ENABLE_ATT_DELAYED_RESPONSE 131beb20288SMatthias Ringwald static void att_invalidate_value(struct btstack_timer_source *ts){ 132beb20288SMatthias Ringwald UNUSED(ts); 133beb20288SMatthias Ringwald printf("Value got stale\n"); 134beb20288SMatthias Ringwald value_ready = 0; 135beb20288SMatthias Ringwald } 136beb20288SMatthias Ringwald #endif 137beb20288SMatthias Ringwald 138beb20288SMatthias Ringwald /* 139beb20288SMatthias Ringwald * @section att_update_value Handler 140beb20288SMatthias Ringwald * 141beb20288SMatthias Ringwald * @text The att_update_value handler 'updates' the value of the single Characteristic provided in this example 142beb20288SMatthias Ringwald */ 143beb20288SMatthias Ringwald 144beb20288SMatthias Ringwald /* LISTING_START(att_read_delay): ATT Read Delay Handler */ 145beb20288SMatthias Ringwald #ifdef ENABLE_ATT_DELAYED_RESPONSE 146beb20288SMatthias Ringwald static void att_update_value(struct btstack_timer_source *ts){ 147beb20288SMatthias Ringwald UNUSED(ts); 148beb20288SMatthias Ringwald value_ready = 1; 149beb20288SMatthias Ringwald 150beb20288SMatthias Ringwald // trigger ATT Server to try request again 151beb20288SMatthias Ringwald int status = att_server_response_ready(con_handle); 152beb20288SMatthias Ringwald 153beb20288SMatthias Ringwald printf("Value updated -> complete ATT request - status %02x\n", status); 154beb20288SMatthias Ringwald 155beb20288SMatthias Ringwald // simulated value becoming stale again 156beb20288SMatthias Ringwald att_timer.process = &att_invalidate_value; 157beb20288SMatthias Ringwald btstack_run_loop_set_timer(&att_timer, ATT_VALUE_DELAY_MS); 158beb20288SMatthias Ringwald btstack_run_loop_add_timer(&att_timer); 159beb20288SMatthias Ringwald } 160beb20288SMatthias Ringwald #endif 161beb20288SMatthias Ringwald 162beb20288SMatthias Ringwald /* LISTING_END */ 163beb20288SMatthias Ringwald 164beb20288SMatthias Ringwald /* 165beb20288SMatthias Ringwald * @section ATT Read 166beb20288SMatthias Ringwald * 167beb20288SMatthias Ringwald * @text The ATT Server handles all reads to constant data. For dynamic data like the custom characteristic, the registered 168beb20288SMatthias Ringwald * att_read_callback is called. To handle long characteristics and long reads, the att_read_callback is first called 169beb20288SMatthias Ringwald * with buffer == NULL, to request the total value length. Then it will be called again requesting a chunk of the value. 170beb20288SMatthias Ringwald * See Listing attRead. 171beb20288SMatthias Ringwald */ 172beb20288SMatthias Ringwald 173beb20288SMatthias Ringwald /* LISTING_START(attRead): ATT Read */ 174beb20288SMatthias Ringwald 175beb20288SMatthias Ringwald // ATT Client Read Callback for Dynamic Data 176beb20288SMatthias Ringwald // - if buffer == NULL, don't copy data, just return size of value 177beb20288SMatthias Ringwald // - if buffer != NULL, copy data and return number bytes copied 178beb20288SMatthias Ringwald // @param offset defines start of attribute value 179beb20288SMatthias Ringwald 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){ 180beb20288SMatthias Ringwald 181beb20288SMatthias Ringwald #ifdef ENABLE_ATT_DELAYED_RESPONSE 182beb20288SMatthias Ringwald switch (att_handle){ 183beb20288SMatthias Ringwald case ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE: 184beb20288SMatthias Ringwald if (value_ready){ 185beb20288SMatthias Ringwald return att_read_callback_handle_blob((const uint8_t *)test_string, strlen(test_string), offset, buffer, buffer_size); 186beb20288SMatthias Ringwald } else { 187beb20288SMatthias Ringwald printf("Read callback for handle %02x, but value not ready -> report response pending\n", att_handle); 188beb20288SMatthias Ringwald con_handle = connection_handle; 189beb20288SMatthias Ringwald return ATT_READ_RESPONSE_PENDING; 190beb20288SMatthias Ringwald } 191beb20288SMatthias Ringwald break; 192beb20288SMatthias Ringwald case ATT_READ_RESPONSE_PENDING: 193beb20288SMatthias Ringwald // virtual handle indicating all attributes have been queried 194beb20288SMatthias Ringwald printf("Read callback for virtual handle %02x - all attributes have been queried (important for read multiple or read by type) -> start updating values\n", att_handle); 195beb20288SMatthias Ringwald // simulated delayed response for example 196beb20288SMatthias Ringwald att_timer.process = &att_update_value; 197beb20288SMatthias Ringwald btstack_run_loop_set_timer(&att_timer, ATT_VALUE_DELAY_MS); 198beb20288SMatthias Ringwald btstack_run_loop_add_timer(&att_timer); 199beb20288SMatthias Ringwald return 0; 200beb20288SMatthias Ringwald default: 201beb20288SMatthias Ringwald break; 202beb20288SMatthias Ringwald } 203beb20288SMatthias Ringwald #else 204beb20288SMatthias Ringwald UNUSED(connection_handle); 205beb20288SMatthias Ringwald // useless code when ENABLE_ATT_DELAYED_RESPONSE is not defined - but avoids built errors 206beb20288SMatthias Ringwald if (att_handle == ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE){ 207beb20288SMatthias Ringwald printf("ENABLE_ATT_DELAYED_RESPONSE not defined in btstack_config.h, responding right away"); 208beb20288SMatthias Ringwald return att_read_callback_handle_blob((const uint8_t *)test_string, strlen(test_string), offset, buffer, buffer_size); 209beb20288SMatthias Ringwald } 210beb20288SMatthias Ringwald #endif 211beb20288SMatthias Ringwald 212beb20288SMatthias Ringwald return 0; 213beb20288SMatthias Ringwald } 214beb20288SMatthias Ringwald 215beb20288SMatthias Ringwald /* 216beb20288SMatthias Ringwald * @section ATT Write 217beb20288SMatthias Ringwald * */ 218beb20288SMatthias Ringwald 219beb20288SMatthias Ringwald /* LISTING_START(attWrite): ATT Write */ 220beb20288SMatthias Ringwald 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){ 221beb20288SMatthias Ringwald UNUSED(transaction_mode); 222beb20288SMatthias Ringwald UNUSED(offset); 223beb20288SMatthias Ringwald UNUSED(buffer_size); 224beb20288SMatthias Ringwald UNUSED(connection_handle); 225beb20288SMatthias Ringwald 226beb20288SMatthias Ringwald if (att_handle == ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE) { 227beb20288SMatthias Ringwald printf("Write request, value: "); 228beb20288SMatthias Ringwald printf_hexdump(buffer, buffer_size); 229beb20288SMatthias Ringwald #ifdef ENABLE_ATT_DELAYED_RESPONSE 230beb20288SMatthias Ringwald if (value_ready){ 231beb20288SMatthias Ringwald printf("Write callback, value ready\n"); 232beb20288SMatthias Ringwald return 0; 233beb20288SMatthias Ringwald } else { 234beb20288SMatthias Ringwald printf("Write callback for handle %02x, but not ready -> return response pending\n", att_handle); 235beb20288SMatthias Ringwald } 236beb20288SMatthias Ringwald // simulated delayed response for example 237beb20288SMatthias Ringwald att_timer.process = &att_update_value; 238beb20288SMatthias Ringwald btstack_run_loop_set_timer(&att_timer, ATT_VALUE_DELAY_MS); 239beb20288SMatthias Ringwald btstack_run_loop_add_timer(&att_timer); 240beb20288SMatthias Ringwald return ATT_ERROR_WRITE_RESPONSE_PENDING; 241beb20288SMatthias Ringwald #else 242beb20288SMatthias Ringwald printf("ENABLE_ATT_DELAYED_RESPONSE not defined in btstack_config.h, responding right away"); 243beb20288SMatthias Ringwald return 0; 244beb20288SMatthias Ringwald #endif 245beb20288SMatthias Ringwald } 246beb20288SMatthias Ringwald return 0; 247beb20288SMatthias Ringwald } 248beb20288SMatthias Ringwald 249beb20288SMatthias Ringwald /* LISTING_END */ 250beb20288SMatthias Ringwald 251beb20288SMatthias Ringwald int btstack_main(void); 252beb20288SMatthias Ringwald int btstack_main(void) 253beb20288SMatthias Ringwald { 254beb20288SMatthias Ringwald example_setup(); 255beb20288SMatthias Ringwald 256beb20288SMatthias Ringwald // turn on! 257beb20288SMatthias Ringwald hci_power_control(HCI_POWER_ON); 258beb20288SMatthias Ringwald 259beb20288SMatthias Ringwald return 0; 260beb20288SMatthias Ringwald } 261beb20288SMatthias Ringwald /* EXAMPLE_END */ 262