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