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