xref: /btstack/example/att_delayed_response.c (revision ff3cc4a5378c2f681cc9b75cf54d154a12a3051e)
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 "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