xref: /btstack/example/att_delayed_response.c (revision beb202884a9012f104bdfb14768f08f9f089cd1b)
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 MATTHIAS
24  * RINGWALD 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 "att_delayed_response.h"
59 #include "btstack.h"
60 
61 #define ATT_VALUE_DELAY_MS   3000
62 #define ATT_VALUE_INVALID_MS 5000
63 
64 /* @section Main Application Setup
65  *
66  * @text Listing MainConfiguration shows main application code.
67  * It initializes L2CAP, the Security Manager and configures the ATT Server with the pre-compiled
68  * ATT Database generated from $le_counter.gatt$.
69  * Additionally, it enables the Battery Service Server with the current battery level.
70  * Finally, it configures the advertisements and boots the Bluetooth stack.
71  * In this example, the Advertisement contains the Flags attribute and the device name.
72  * The flag 0x06 indicates: LE General Discoverable Mode and BR/EDR not supported.
73  */
74 
75 /* LISTING_START(MainConfiguration): Init L2CAP SM ATT Server */
76 #ifdef ENABLE_ATT_DELAYED_RESPONSE
77 static btstack_timer_source_t att_timer;
78 static hci_con_handle_t con_handle;
79 static int value_ready;
80 #endif
81 
82 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 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 
85 const uint8_t adv_data[] = {
86     // Flags general discoverable, BR/EDR not supported
87     0x02, 0x01, 0x06,
88     // Name
89     0x08, 0x09, 'D', 'e', 'l', 'a', 'y', 'e', 'd',
90 };
91 const uint8_t adv_data_len = sizeof(adv_data);
92 
93 const char * test_string = "Delayed response";
94 
95 static void example_setup(void){
96 
97     l2cap_init();
98 
99     // setup le device db
100     le_device_db_init();
101 
102     // setup SM: Display only
103     sm_init();
104 
105     // setup ATT server
106     att_server_init(profile_data, att_read_callback, att_write_callback);
107 
108     // setup advertisements
109     uint16_t adv_int_min = 0x0030;
110     uint16_t adv_int_max = 0x0030;
111     uint8_t adv_type = 0;
112     bd_addr_t null_addr;
113     memset(null_addr, 0, 6);
114     gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
115     gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data);
116     gap_advertisements_enable(1);
117 }
118 /* LISTING_END */
119 
120 /*
121  * @section att_invalidate_value Handler
122  *
123  * @text The att_invalidate_value handler 'invalidates' the value of the single Characteristic provided in this example
124  */
125 #ifdef ENABLE_ATT_DELAYED_RESPONSE
126 static void att_invalidate_value(struct btstack_timer_source *ts){
127     UNUSED(ts);
128     printf("Value got stale\n");
129     value_ready = 0;
130 }
131 #endif
132 
133 /*
134  * @section att_update_value Handler
135  *
136  * @text The att_update_value handler 'updates' the value of the single Characteristic provided in this example
137  */
138 
139  /* LISTING_START(att_read_delay): ATT Read Delay Handler */
140 #ifdef ENABLE_ATT_DELAYED_RESPONSE
141 static void att_update_value(struct btstack_timer_source *ts){
142     UNUSED(ts);
143     value_ready = 1;
144 
145     // trigger ATT Server to try request again
146     int status = att_server_response_ready(con_handle);
147 
148     printf("Value updated -> complete ATT request - status %02x\n", status);
149 
150     // simulated value becoming stale again
151     att_timer.process = &att_invalidate_value;
152     btstack_run_loop_set_timer(&att_timer, ATT_VALUE_DELAY_MS);
153     btstack_run_loop_add_timer(&att_timer);
154 }
155 #endif
156 
157 /* LISTING_END */
158 
159 /*
160  * @section ATT Read
161  *
162  * @text The ATT Server handles all reads to constant data. For dynamic data like the custom characteristic, the registered
163  * att_read_callback is called. To handle long characteristics and long reads, the att_read_callback is first called
164  * with buffer == NULL, to request the total value length. Then it will be called again requesting a chunk of the value.
165  * See Listing attRead.
166  */
167 
168 /* LISTING_START(attRead): ATT Read */
169 
170 // ATT Client Read Callback for Dynamic Data
171 // - if buffer == NULL, don't copy data, just return size of value
172 // - if buffer != NULL, copy data and return number bytes copied
173 // @param offset defines start of attribute value
174 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 
176 #ifdef ENABLE_ATT_DELAYED_RESPONSE
177     switch (att_handle){
178         case ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE:
179             if (value_ready){
180                 return att_read_callback_handle_blob((const uint8_t *)test_string, strlen(test_string), offset, buffer, buffer_size);
181             } else {
182                 printf("Read callback for handle %02x, but value not ready -> report response pending\n", att_handle);
183                 con_handle = connection_handle;
184                 return ATT_READ_RESPONSE_PENDING;
185             }
186             break;
187         case ATT_READ_RESPONSE_PENDING:
188             // virtual handle indicating all attributes have been queried
189             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             // simulated delayed response for example
191             att_timer.process = &att_update_value;
192             btstack_run_loop_set_timer(&att_timer, ATT_VALUE_DELAY_MS);
193             btstack_run_loop_add_timer(&att_timer);
194             return 0;
195         default:
196             break;
197     }
198 #else
199     UNUSED(connection_handle);
200     // useless code when ENABLE_ATT_DELAYED_RESPONSE is not defined - but avoids built errors
201     if (att_handle == ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE){
202         printf("ENABLE_ATT_DELAYED_RESPONSE not defined in btstack_config.h, responding right away");
203         return att_read_callback_handle_blob((const uint8_t *)test_string, strlen(test_string), offset, buffer, buffer_size);
204     }
205 #endif
206 
207     return 0;
208 }
209 
210 /*
211  * @section ATT Write
212  * */
213 
214 /* LISTING_START(attWrite): ATT Write */
215 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     UNUSED(transaction_mode);
217     UNUSED(offset);
218     UNUSED(buffer_size);
219     UNUSED(connection_handle);
220 
221     if (att_handle == ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE) {
222         printf("Write request, value: ");
223         printf_hexdump(buffer, buffer_size);
224 #ifdef ENABLE_ATT_DELAYED_RESPONSE
225         if (value_ready){
226             printf("Write callback, value ready\n");
227             return 0;
228         } else {
229             printf("Write callback for handle %02x, but not ready -> return response pending\n", att_handle);
230         }
231         // simulated delayed response for example
232         att_timer.process = &att_update_value;
233         btstack_run_loop_set_timer(&att_timer, ATT_VALUE_DELAY_MS);
234         btstack_run_loop_add_timer(&att_timer);
235         return ATT_ERROR_WRITE_RESPONSE_PENDING;
236 #else
237         printf("ENABLE_ATT_DELAYED_RESPONSE not defined in btstack_config.h, responding right away");
238         return 0;
239 #endif
240     }
241     return 0;
242 }
243 
244 /* LISTING_END */
245 
246 int btstack_main(void);
247 int btstack_main(void)
248 {
249     example_setup();
250 
251     // turn on!
252 	hci_power_control(HCI_POWER_ON);
253 
254     return 0;
255 }
256 /* EXAMPLE_END */
257