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 le device db 105 le_device_db_init(); 106 107 // setup SM: Display only 108 sm_init(); 109 110 // setup ATT server 111 att_server_init(profile_data, att_read_callback, att_write_callback); 112 113 // setup advertisements 114 uint16_t adv_int_min = 0x0030; 115 uint16_t adv_int_max = 0x0030; 116 uint8_t adv_type = 0; 117 bd_addr_t null_addr; 118 memset(null_addr, 0, 6); 119 gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00); 120 gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data); 121 gap_advertisements_enable(1); 122 } 123 /* LISTING_END */ 124 125 /* 126 * @section att_invalidate_value Handler 127 * 128 * @text The att_invalidate_value handler 'invalidates' the value of the single Characteristic provided in this example 129 */ 130 #ifdef ENABLE_ATT_DELAYED_RESPONSE 131 static void att_invalidate_value(struct btstack_timer_source *ts){ 132 UNUSED(ts); 133 printf("Value got stale\n"); 134 value_ready = 0; 135 } 136 #endif 137 138 /* 139 * @section att_update_value Handler 140 * 141 * @text The att_update_value handler 'updates' the value of the single Characteristic provided in this example 142 */ 143 144 /* LISTING_START(att_read_delay): ATT Read Delay Handler */ 145 #ifdef ENABLE_ATT_DELAYED_RESPONSE 146 static void att_update_value(struct btstack_timer_source *ts){ 147 UNUSED(ts); 148 value_ready = 1; 149 150 // trigger ATT Server to try request again 151 int status = att_server_response_ready(con_handle); 152 153 printf("Value updated -> complete ATT request - status %02x\n", status); 154 155 // simulated value becoming stale again 156 att_timer.process = &att_invalidate_value; 157 btstack_run_loop_set_timer(&att_timer, ATT_VALUE_DELAY_MS); 158 btstack_run_loop_add_timer(&att_timer); 159 } 160 #endif 161 162 /* LISTING_END */ 163 164 /* 165 * @section ATT Read 166 * 167 * @text The ATT Server handles all reads to constant data. For dynamic data like the custom characteristic, the registered 168 * att_read_callback is called. To handle long characteristics and long reads, the att_read_callback is first called 169 * with buffer == NULL, to request the total value length. Then it will be called again requesting a chunk of the value. 170 * See Listing attRead. 171 */ 172 173 /* LISTING_START(attRead): ATT Read */ 174 175 // ATT Client Read Callback for Dynamic Data 176 // - if buffer == NULL, don't copy data, just return size of value 177 // - if buffer != NULL, copy data and return number bytes copied 178 // @param offset defines start of attribute value 179 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){ 180 181 #ifdef ENABLE_ATT_DELAYED_RESPONSE 182 switch (att_handle){ 183 case ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE: 184 if (value_ready){ 185 return att_read_callback_handle_blob((const uint8_t *)test_string, strlen(test_string), offset, buffer, buffer_size); 186 } else { 187 printf("Read callback for handle %02x, but value not ready -> report response pending\n", att_handle); 188 con_handle = connection_handle; 189 return ATT_READ_RESPONSE_PENDING; 190 } 191 break; 192 case ATT_READ_RESPONSE_PENDING: 193 // virtual handle indicating all attributes have been queried 194 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); 195 // simulated delayed response for example 196 att_timer.process = &att_update_value; 197 btstack_run_loop_set_timer(&att_timer, ATT_VALUE_DELAY_MS); 198 btstack_run_loop_add_timer(&att_timer); 199 return 0; 200 default: 201 break; 202 } 203 #else 204 UNUSED(connection_handle); 205 // useless code when ENABLE_ATT_DELAYED_RESPONSE is not defined - but avoids built errors 206 if (att_handle == ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE){ 207 printf("ENABLE_ATT_DELAYED_RESPONSE not defined in btstack_config.h, responding right away"); 208 return att_read_callback_handle_blob((const uint8_t *)test_string, strlen(test_string), offset, buffer, buffer_size); 209 } 210 #endif 211 212 return 0; 213 } 214 215 /* 216 * @section ATT Write 217 * */ 218 219 /* LISTING_START(attWrite): ATT Write */ 220 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){ 221 UNUSED(transaction_mode); 222 UNUSED(offset); 223 UNUSED(buffer_size); 224 UNUSED(connection_handle); 225 226 if (att_handle == ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE) { 227 printf("Write request, value: "); 228 printf_hexdump(buffer, buffer_size); 229 #ifdef ENABLE_ATT_DELAYED_RESPONSE 230 if (value_ready){ 231 printf("Write callback, value ready\n"); 232 return 0; 233 } else { 234 printf("Write callback for handle %02x, but not ready -> return response pending\n", att_handle); 235 } 236 // simulated delayed response for example 237 att_timer.process = &att_update_value; 238 btstack_run_loop_set_timer(&att_timer, ATT_VALUE_DELAY_MS); 239 btstack_run_loop_add_timer(&att_timer); 240 return ATT_ERROR_WRITE_RESPONSE_PENDING; 241 #else 242 printf("ENABLE_ATT_DELAYED_RESPONSE not defined in btstack_config.h, responding right away"); 243 return 0; 244 #endif 245 } 246 return 0; 247 } 248 249 /* LISTING_END */ 250 251 int btstack_main(void); 252 int btstack_main(void) 253 { 254 example_setup(); 255 256 // turn on! 257 hci_power_control(HCI_POWER_ON); 258 259 return 0; 260 } 261 /* EXAMPLE_END */ 262