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