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