xref: /btstack/src/ble/gatt-service/scan_parameters_service_client.c (revision d4ac06eb78d2abcd175f896382d4c15e93f0af92)
178ae886bSMilanka Ringwald /*
278ae886bSMilanka Ringwald  * Copyright (C) 2021 BlueKitchen GmbH
378ae886bSMilanka Ringwald  *
478ae886bSMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
578ae886bSMilanka Ringwald  * modification, are permitted provided that the following conditions
678ae886bSMilanka Ringwald  * are met:
778ae886bSMilanka Ringwald  *
878ae886bSMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
978ae886bSMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
1078ae886bSMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
1178ae886bSMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
1278ae886bSMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
1378ae886bSMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
1478ae886bSMilanka Ringwald  *    contributors may be used to endorse or promote products derived
1578ae886bSMilanka Ringwald  *    from this software without specific prior written permission.
1678ae886bSMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
1778ae886bSMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
1878ae886bSMilanka Ringwald  *    monetary gain.
1978ae886bSMilanka Ringwald  *
2078ae886bSMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
2178ae886bSMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2278ae886bSMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2378ae886bSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
2478ae886bSMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2578ae886bSMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2678ae886bSMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
2778ae886bSMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2878ae886bSMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2978ae886bSMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
3078ae886bSMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3178ae886bSMilanka Ringwald  * SUCH DAMAGE.
3278ae886bSMilanka Ringwald  *
3378ae886bSMilanka Ringwald  * Please inquire about commercial licensing options at
3478ae886bSMilanka Ringwald  * [email protected]
3578ae886bSMilanka Ringwald  *
3678ae886bSMilanka Ringwald  */
3778ae886bSMilanka Ringwald 
3878ae886bSMilanka Ringwald #define BTSTACK_FILE__ "scan_parameters_service_client.c"
3978ae886bSMilanka Ringwald 
4078ae886bSMilanka Ringwald #include "btstack_config.h"
4178ae886bSMilanka Ringwald 
4278ae886bSMilanka Ringwald #include <stdint.h>
4378ae886bSMilanka Ringwald #include <string.h>
4478ae886bSMilanka Ringwald 
45b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
46b3f0de51SMilanka Ringwald #include <stdio.h>
47b3f0de51SMilanka Ringwald #endif
4878ae886bSMilanka Ringwald 
4978ae886bSMilanka Ringwald #include "scan_parameters_service_client.h"
5078ae886bSMilanka Ringwald 
5178ae886bSMilanka Ringwald #include "btstack_memory.h"
5278ae886bSMilanka Ringwald #include "ble/att_db.h"
5378ae886bSMilanka Ringwald #include "ble/core.h"
5478ae886bSMilanka Ringwald #include "ble/gatt_client.h"
5578ae886bSMilanka Ringwald #include "ble/sm.h"
5678ae886bSMilanka Ringwald #include "bluetooth_gatt.h"
5778ae886bSMilanka Ringwald #include "btstack_debug.h"
5878ae886bSMilanka Ringwald #include "btstack_event.h"
5978ae886bSMilanka Ringwald #include "btstack_run_loop.h"
6078ae886bSMilanka Ringwald #include "gap.h"
6178ae886bSMilanka Ringwald 
6278ae886bSMilanka Ringwald static btstack_linked_list_t clients;
6378ae886bSMilanka Ringwald static uint16_t scan_parameters_service_cid_counter = 0;
6478ae886bSMilanka Ringwald static uint16_t scan_parameters_service_scan_window = 0;
6578ae886bSMilanka Ringwald static uint16_t scan_parameters_service_scan_interval = 0;
6678ae886bSMilanka Ringwald 
6778ae886bSMilanka Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
68b3f0de51SMilanka Ringwald static void scan_parameters_service_run_for_client(scan_parameters_service_client_t * client);
6978ae886bSMilanka Ringwald 
7078ae886bSMilanka Ringwald static uint16_t scan_parameters_service_get_next_cid(void){
7178ae886bSMilanka Ringwald     if (scan_parameters_service_cid_counter == 0xffff) {
7278ae886bSMilanka Ringwald         scan_parameters_service_cid_counter = 1;
7378ae886bSMilanka Ringwald     } else {
7478ae886bSMilanka Ringwald         scan_parameters_service_cid_counter++;
7578ae886bSMilanka Ringwald     }
7678ae886bSMilanka Ringwald     return scan_parameters_service_cid_counter;
7778ae886bSMilanka Ringwald }
7878ae886bSMilanka Ringwald 
7978ae886bSMilanka Ringwald static scan_parameters_service_client_t * scan_parameters_service_create_client(hci_con_handle_t con_handle, uint16_t cid){
8078ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = btstack_memory_scan_parameters_service_client_get();
8178ae886bSMilanka Ringwald     if (!client){
8278ae886bSMilanka Ringwald         log_error("Not enough memory to create client");
8378ae886bSMilanka Ringwald         return NULL;
8478ae886bSMilanka Ringwald     }
8578ae886bSMilanka Ringwald 
8678ae886bSMilanka Ringwald     client->cid = cid;
8778ae886bSMilanka Ringwald     client->con_handle = con_handle;
8878ae886bSMilanka Ringwald     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_IDLE;
8978ae886bSMilanka Ringwald 
9078ae886bSMilanka Ringwald     client->start_handle = 0;
9178ae886bSMilanka Ringwald     client->end_handle = 0;
9278ae886bSMilanka Ringwald 
9378ae886bSMilanka Ringwald     client->scan_interval_window_value_handle = 0;
9478ae886bSMilanka Ringwald     client->scan_interval_window_value_update = false;
9578ae886bSMilanka Ringwald     btstack_linked_list_add(&clients, (btstack_linked_item_t *) client);
9678ae886bSMilanka Ringwald     return client;
9778ae886bSMilanka Ringwald }
9878ae886bSMilanka Ringwald 
9978ae886bSMilanka Ringwald static void scan_parameters_service_finalize_client(scan_parameters_service_client_t * client){
100b3f0de51SMilanka Ringwald     gatt_client_stop_listening_for_characteristic_value_updates(&client->notification_listener);
10178ae886bSMilanka Ringwald     btstack_linked_list_remove(&clients, (btstack_linked_item_t *) client);
10278ae886bSMilanka Ringwald     btstack_memory_scan_parameters_service_client_free(client);
10378ae886bSMilanka Ringwald }
10478ae886bSMilanka Ringwald 
10578ae886bSMilanka Ringwald static scan_parameters_service_client_t * scan_parameters_service_get_client_for_con_handle(hci_con_handle_t con_handle){
10678ae886bSMilanka Ringwald     btstack_linked_list_iterator_t it;
10778ae886bSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &clients);
10878ae886bSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
10978ae886bSMilanka Ringwald         scan_parameters_service_client_t * client = (scan_parameters_service_client_t *)btstack_linked_list_iterator_next(&it);
11078ae886bSMilanka Ringwald         if (client->con_handle != con_handle) continue;
11178ae886bSMilanka Ringwald         return client;
11278ae886bSMilanka Ringwald     }
11378ae886bSMilanka Ringwald     return NULL;
11478ae886bSMilanka Ringwald }
11578ae886bSMilanka Ringwald 
116b3f0de51SMilanka Ringwald static scan_parameters_service_client_t * scan_parameters_service_get_client_for_cid(uint16_t scan_parameters_service_cid){
11778ae886bSMilanka Ringwald     btstack_linked_list_iterator_t it;
11878ae886bSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &clients);
11978ae886bSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
12078ae886bSMilanka Ringwald         scan_parameters_service_client_t * client = (scan_parameters_service_client_t *)btstack_linked_list_iterator_next(&it);
121b3f0de51SMilanka Ringwald         if (client->cid != scan_parameters_service_cid) continue;
12278ae886bSMilanka Ringwald         return client;
12378ae886bSMilanka Ringwald     }
12478ae886bSMilanka Ringwald     return NULL;
12578ae886bSMilanka Ringwald }
12678ae886bSMilanka Ringwald 
12778ae886bSMilanka Ringwald static void scan_parameters_service_emit_connection_established(scan_parameters_service_client_t * client, uint8_t status){
12878ae886bSMilanka Ringwald     uint8_t event[6];
12978ae886bSMilanka Ringwald     int pos = 0;
13078ae886bSMilanka Ringwald     event[pos++] = HCI_EVENT_GATTSERVICE_META;
13178ae886bSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
13278ae886bSMilanka Ringwald     event[pos++] = GATTSERVICE_SUBEVENT_SCAN_PARAMETERS_SERVICE_CONNECTED;
13378ae886bSMilanka Ringwald     little_endian_store_16(event, pos, client->cid);
13478ae886bSMilanka Ringwald     pos += 2;
13578ae886bSMilanka Ringwald     event[pos++] = status;
136*d4ac06ebSMilanka Ringwald     (*client->client_handler)(HCI_EVENT_GATTSERVICE_META, 0, event, sizeof(event));
13778ae886bSMilanka Ringwald }
13878ae886bSMilanka Ringwald 
139b3f0de51SMilanka Ringwald static void handle_notification_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
140b3f0de51SMilanka Ringwald     UNUSED(packet_type);
141b3f0de51SMilanka Ringwald     UNUSED(channel);
142b3f0de51SMilanka Ringwald     UNUSED(size);
143b3f0de51SMilanka Ringwald 
144b3f0de51SMilanka Ringwald     if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) return;
145b3f0de51SMilanka Ringwald 
146b3f0de51SMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_con_handle(gatt_event_notification_get_handle(packet));
147b3f0de51SMilanka Ringwald     btstack_assert(client != NULL);
148b3f0de51SMilanka Ringwald     client->scan_interval_window_value_update = true;
149b3f0de51SMilanka Ringwald     scan_parameters_service_run_for_client(client);
150b3f0de51SMilanka Ringwald }
15178ae886bSMilanka Ringwald 
15278ae886bSMilanka Ringwald static void scan_parameters_service_run_for_client(scan_parameters_service_client_t * client){
15378ae886bSMilanka Ringwald     uint8_t att_status;
15478ae886bSMilanka Ringwald     gatt_client_service_t service;
15578ae886bSMilanka Ringwald 
156b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
157b3f0de51SMilanka Ringwald     gatt_client_characteristic_t characteristic;
158b3f0de51SMilanka Ringwald #endif
159b3f0de51SMilanka Ringwald 
16078ae886bSMilanka Ringwald     switch (client->state){
16178ae886bSMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE:
162b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
163b3f0de51SMilanka Ringwald             printf("\n\nQuery Services:\n");
164b3f0de51SMilanka Ringwald #endif
16578ae886bSMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT;
16678ae886bSMilanka Ringwald             att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_SCAN_PARAMETERS);
16778ae886bSMilanka Ringwald             // TODO handle status
16878ae886bSMilanka Ringwald             UNUSED(att_status);
16978ae886bSMilanka Ringwald             break;
17078ae886bSMilanka Ringwald 
17178ae886bSMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC:
172b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
173b3f0de51SMilanka Ringwald             printf("\n\nQuery Characteristics of service\n");
174b3f0de51SMilanka Ringwald #endif
17578ae886bSMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
17678ae886bSMilanka Ringwald             service.start_group_handle = client->start_handle;
17778ae886bSMilanka Ringwald             service.end_group_handle = client->end_handle;
178b3f0de51SMilanka Ringwald             att_status = gatt_client_discover_characteristics_for_service(
179b3f0de51SMilanka Ringwald                 handle_gatt_client_event, client->con_handle, &service);
18078ae886bSMilanka Ringwald             // TODO handle status
18178ae886bSMilanka Ringwald             UNUSED(att_status);
18278ae886bSMilanka Ringwald             break;
18378ae886bSMilanka Ringwald 
18478ae886bSMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED:
18578ae886bSMilanka Ringwald             if (client->scan_interval_window_value_update){
186b3f0de51SMilanka Ringwald                 client->scan_interval_window_value_update = false;
187b3f0de51SMilanka Ringwald 
188b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
189b3f0de51SMilanka Ringwald                 printf("\n\nUpdate - interval %d, window %d:\n", scan_parameters_service_scan_interval, scan_parameters_service_scan_window);
190b3f0de51SMilanka Ringwald #endif
19178ae886bSMilanka Ringwald                 uint8_t value[4];
19278ae886bSMilanka Ringwald                 little_endian_store_16(value, 0, scan_parameters_service_scan_interval);
19378ae886bSMilanka Ringwald                 little_endian_store_16(value, 2, scan_parameters_service_scan_window);
19478ae886bSMilanka Ringwald 
19578ae886bSMilanka Ringwald                 att_status = gatt_client_write_value_of_characteristic_without_response(client->con_handle, client->scan_interval_window_value_handle, 4, value);
19678ae886bSMilanka Ringwald                 // TODO handle status
19778ae886bSMilanka Ringwald                 UNUSED(att_status);
19878ae886bSMilanka Ringwald             }
19978ae886bSMilanka Ringwald             break;
200b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
201b3f0de51SMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CCC:
202b3f0de51SMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CCC;
203b3f0de51SMilanka Ringwald 
204b3f0de51SMilanka Ringwald             characteristic.value_handle = client->scan_refresh_value_handle;
205b3f0de51SMilanka Ringwald             characteristic.end_handle   =  client->scan_refresh_end_handle;
206b3f0de51SMilanka Ringwald 
207b3f0de51SMilanka Ringwald             // result in GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT
208b3f0de51SMilanka Ringwald             att_status = gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, client->con_handle, &characteristic);
209b3f0de51SMilanka Ringwald             UNUSED(att_status);
210b3f0de51SMilanka Ringwald             break;
211b3f0de51SMilanka Ringwald #endif
212b3f0de51SMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_CONFIGURE_NOTIFICATIONS:
213b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
214b3f0de51SMilanka Ringwald             printf("    Notification configuration enable ");
215b3f0de51SMilanka Ringwald #endif
216b3f0de51SMilanka Ringwald 
217b3f0de51SMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_NOTIFICATIONS_CONFIGURED;
218b3f0de51SMilanka Ringwald 
219b3f0de51SMilanka Ringwald             characteristic.value_handle = client->scan_refresh_value_handle;
220b3f0de51SMilanka Ringwald             characteristic.end_handle = client->scan_refresh_end_handle;
221b3f0de51SMilanka Ringwald             characteristic.properties = client->scan_refresh_properties;
222b3f0de51SMilanka Ringwald 
223b3f0de51SMilanka Ringwald             // end of write marked in GATT_EVENT_QUERY_COMPLETE
224b3f0de51SMilanka Ringwald 
225b3f0de51SMilanka Ringwald             att_status = gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, client->con_handle, &characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
226b3f0de51SMilanka Ringwald 
227b3f0de51SMilanka Ringwald             if (att_status == ERROR_CODE_SUCCESS){
228b3f0de51SMilanka Ringwald                 gatt_client_listen_for_characteristic_value_updates(
229b3f0de51SMilanka Ringwald                             &client->notification_listener,
230b3f0de51SMilanka Ringwald                             &handle_notification_event, client->con_handle, &characteristic);
231b3f0de51SMilanka Ringwald             }
232b3f0de51SMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED;
233b3f0de51SMilanka Ringwald             break;
23478ae886bSMilanka Ringwald         default:
23578ae886bSMilanka Ringwald             break;
23678ae886bSMilanka Ringwald     }
23778ae886bSMilanka Ringwald }
23878ae886bSMilanka Ringwald 
23978ae886bSMilanka Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
24078ae886bSMilanka Ringwald     UNUSED(packet_type);
24178ae886bSMilanka Ringwald     UNUSED(channel);
24278ae886bSMilanka Ringwald     UNUSED(size);
24378ae886bSMilanka Ringwald 
24478ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = NULL;
24578ae886bSMilanka Ringwald     gatt_client_service_t service;
24678ae886bSMilanka Ringwald     gatt_client_characteristic_t characteristic;
24778ae886bSMilanka Ringwald     uint8_t att_status;
24878ae886bSMilanka Ringwald 
249b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
250b3f0de51SMilanka Ringwald     gatt_client_characteristic_descriptor_t characteristic_descriptor;
251b3f0de51SMilanka Ringwald #endif
252b3f0de51SMilanka Ringwald 
25378ae886bSMilanka Ringwald     switch(hci_event_packet_get_type(packet)){
25478ae886bSMilanka Ringwald         case GATT_EVENT_SERVICE_QUERY_RESULT:
25578ae886bSMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
25678ae886bSMilanka Ringwald             btstack_assert(client != NULL);
25778ae886bSMilanka Ringwald 
25878ae886bSMilanka Ringwald             if (client->state != SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT) {
25978ae886bSMilanka Ringwald                 scan_parameters_service_emit_connection_established(client, GATT_CLIENT_IN_WRONG_STATE);
26078ae886bSMilanka Ringwald                 scan_parameters_service_finalize_client(client);
26178ae886bSMilanka Ringwald                 break;
26278ae886bSMilanka Ringwald             }
26378ae886bSMilanka Ringwald 
26478ae886bSMilanka Ringwald             gatt_event_service_query_result_get_service(packet, &service);
26578ae886bSMilanka Ringwald             client->start_handle = service.start_group_handle;
26678ae886bSMilanka Ringwald             client->end_handle = service.end_group_handle;
267b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
268b3f0de51SMilanka Ringwald             printf("ScS Service: start handle 0x%04X, end handle 0x%04X\n", client->start_handle, client->end_handle);
269b3f0de51SMilanka Ringwald #endif
27078ae886bSMilanka Ringwald             break;
27178ae886bSMilanka Ringwald 
27278ae886bSMilanka Ringwald         case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
27378ae886bSMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet));
27478ae886bSMilanka Ringwald             btstack_assert(client != NULL);
27578ae886bSMilanka Ringwald 
27678ae886bSMilanka Ringwald             // found scan_interval_window_value_handle, check att_status
27778ae886bSMilanka Ringwald             gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
278b3f0de51SMilanka Ringwald             switch (characteristic.uuid16){
279b3f0de51SMilanka Ringwald                 case ORG_BLUETOOTH_CHARACTERISTIC_SCAN_INTERVAL_WINDOW:
28078ae886bSMilanka Ringwald                     client->scan_interval_window_value_handle = characteristic.value_handle;
281b3f0de51SMilanka Ringwald 
282b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
283b3f0de51SMilanka Ringwald                     printf("ScS Scan Interval Characteristic:  \n    Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n",
284b3f0de51SMilanka Ringwald                         characteristic.start_handle,
285b3f0de51SMilanka Ringwald                         characteristic.properties,
286b3f0de51SMilanka Ringwald                         characteristic.value_handle, characteristic.uuid16);
287b3f0de51SMilanka Ringwald #endif
28878ae886bSMilanka Ringwald                     break;
289b3f0de51SMilanka Ringwald                 case ORG_BLUETOOTH_CHARACTERISTIC_SCAN_REFRESH:
290b3f0de51SMilanka Ringwald                     client->scan_refresh_value_handle = characteristic.value_handle;
291b3f0de51SMilanka Ringwald                     client->scan_refresh_end_handle = characteristic.end_handle;
292b3f0de51SMilanka Ringwald                     client->scan_refresh_properties = characteristic.properties;
293b3f0de51SMilanka Ringwald 
294b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
295b3f0de51SMilanka Ringwald                     printf("ScS Scan Refresh Characteristic:  \n    Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n",
296b3f0de51SMilanka Ringwald                         characteristic.start_handle,
297b3f0de51SMilanka Ringwald                         characteristic.properties,
298b3f0de51SMilanka Ringwald                         characteristic.value_handle, characteristic.uuid16);
299b3f0de51SMilanka Ringwald #endif
300b3f0de51SMilanka Ringwald                     break;
301b3f0de51SMilanka Ringwald                 default:
302b3f0de51SMilanka Ringwald                     break;
303b3f0de51SMilanka Ringwald             }
304b3f0de51SMilanka Ringwald             break;
305b3f0de51SMilanka Ringwald 
306b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
307b3f0de51SMilanka Ringwald         case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
308b3f0de51SMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet));
309b3f0de51SMilanka Ringwald             btstack_assert(client != NULL);
310b3f0de51SMilanka Ringwald 
311b3f0de51SMilanka Ringwald             gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor);
312b3f0de51SMilanka Ringwald             if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION){
313b3f0de51SMilanka Ringwald                 printf("    Client Characteristic Configuration Descriptor: Handle 0x%04X, UUID 0x%04X\n",
314b3f0de51SMilanka Ringwald                     characteristic_descriptor.handle,
315b3f0de51SMilanka Ringwald                     characteristic_descriptor.uuid16);
316b3f0de51SMilanka Ringwald             }
317b3f0de51SMilanka Ringwald             break;
318b3f0de51SMilanka Ringwald 
319b3f0de51SMilanka Ringwald         case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
320b3f0de51SMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
321b3f0de51SMilanka Ringwald             btstack_assert(client != NULL);
322b3f0de51SMilanka Ringwald 
323b3f0de51SMilanka Ringwald             printf("    Received CCC value: ");
324b3f0de51SMilanka Ringwald             printf_hexdump(gatt_event_characteristic_value_query_result_get_value(packet),  gatt_event_characteristic_value_query_result_get_value_length(packet));
325b3f0de51SMilanka Ringwald             break;
326b3f0de51SMilanka Ringwald #endif
32778ae886bSMilanka Ringwald 
32878ae886bSMilanka Ringwald         case GATT_EVENT_QUERY_COMPLETE:
32978ae886bSMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
33078ae886bSMilanka Ringwald             btstack_assert(client != NULL);
33178ae886bSMilanka Ringwald 
33278ae886bSMilanka Ringwald             att_status = gatt_event_query_complete_get_att_status(packet);
33378ae886bSMilanka Ringwald 
33478ae886bSMilanka Ringwald             switch (client->state){
33578ae886bSMilanka Ringwald                 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT:
33678ae886bSMilanka Ringwald                     if (att_status != ATT_ERROR_SUCCESS){
33778ae886bSMilanka Ringwald                         scan_parameters_service_emit_connection_established(client, att_status);
33878ae886bSMilanka Ringwald                         scan_parameters_service_finalize_client(client);
33978ae886bSMilanka Ringwald                         break;
34078ae886bSMilanka Ringwald                     }
34178ae886bSMilanka Ringwald 
34278ae886bSMilanka Ringwald                     if (client->start_handle != 0){
343b3f0de51SMilanka Ringwald                         client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC;
34478ae886bSMilanka Ringwald                         break;
34578ae886bSMilanka Ringwald                     }
346b3f0de51SMilanka Ringwald 
347b3f0de51SMilanka Ringwald                     scan_parameters_service_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
348b3f0de51SMilanka Ringwald                     scan_parameters_service_finalize_client(client);
34978ae886bSMilanka Ringwald                     break;
35078ae886bSMilanka Ringwald 
35178ae886bSMilanka Ringwald                 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
35278ae886bSMilanka Ringwald                     if (att_status != ATT_ERROR_SUCCESS){
35378ae886bSMilanka Ringwald                         scan_parameters_service_emit_connection_established(client, att_status);
35478ae886bSMilanka Ringwald                         scan_parameters_service_finalize_client(client);
35578ae886bSMilanka Ringwald                         break;
35678ae886bSMilanka Ringwald                     }
35778ae886bSMilanka Ringwald                     if (client->scan_interval_window_value_handle == 0){
35878ae886bSMilanka Ringwald                         scan_parameters_service_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
35978ae886bSMilanka Ringwald                         scan_parameters_service_finalize_client(client);
36078ae886bSMilanka Ringwald                         break;
36178ae886bSMilanka Ringwald                     }
362b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
363b3f0de51SMilanka Ringwald                     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CCC;
364b3f0de51SMilanka Ringwald #else
36578ae886bSMilanka Ringwald                     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED;
36678ae886bSMilanka Ringwald                     client->scan_interval_window_value_update = true;
367b3f0de51SMilanka Ringwald                     scan_parameters_service_emit_connection_established(client, ERROR_CODE_SUCCESS);
368b3f0de51SMilanka Ringwald #endif
36978ae886bSMilanka Ringwald                     break;
37078ae886bSMilanka Ringwald 
371b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
372b3f0de51SMilanka Ringwald                 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CCC:
373b3f0de51SMilanka Ringwald                     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED;
374b3f0de51SMilanka Ringwald                     client->scan_interval_window_value_update = true;
375b3f0de51SMilanka Ringwald                     scan_parameters_service_emit_connection_established(client, ERROR_CODE_SUCCESS);
376b3f0de51SMilanka Ringwald                     break;
377b3f0de51SMilanka Ringwald #endif
37878ae886bSMilanka Ringwald                 default:
37978ae886bSMilanka Ringwald                     break;
38078ae886bSMilanka Ringwald             }
38178ae886bSMilanka Ringwald             break;
38278ae886bSMilanka Ringwald         default:
38378ae886bSMilanka Ringwald             break;
38478ae886bSMilanka Ringwald     }
38578ae886bSMilanka Ringwald 
38678ae886bSMilanka Ringwald     if (client != NULL){
38778ae886bSMilanka Ringwald         scan_parameters_service_run_for_client(client);
38878ae886bSMilanka Ringwald     }
38978ae886bSMilanka Ringwald }
39078ae886bSMilanka Ringwald 
39178ae886bSMilanka Ringwald void scan_parameters_service_client_set(uint16_t scan_interval, uint16_t scan_window){
39278ae886bSMilanka Ringwald     scan_parameters_service_scan_interval = scan_interval;
39378ae886bSMilanka Ringwald     scan_parameters_service_scan_window = scan_window;
39478ae886bSMilanka Ringwald 
39578ae886bSMilanka Ringwald     btstack_linked_list_iterator_t it;
39678ae886bSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &clients);
39778ae886bSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
39878ae886bSMilanka Ringwald         scan_parameters_service_client_t * client = (scan_parameters_service_client_t*) btstack_linked_list_iterator_next(&it);
39978ae886bSMilanka Ringwald         client->scan_interval_window_value_update = true;
40078ae886bSMilanka Ringwald         scan_parameters_service_run_for_client(client);
40178ae886bSMilanka Ringwald     }
40278ae886bSMilanka Ringwald }
40378ae886bSMilanka Ringwald 
404b3f0de51SMilanka Ringwald uint8_t scan_parameters_service_client_enable_notifications(uint16_t scan_parameters_service_cid){
405b3f0de51SMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_cid(scan_parameters_service_cid);
406b3f0de51SMilanka Ringwald 
407b3f0de51SMilanka Ringwald     if (client == NULL){
408b3f0de51SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
409b3f0de51SMilanka Ringwald     }
410b3f0de51SMilanka Ringwald 
411b3f0de51SMilanka Ringwald     if (client->state != SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED) {
412b3f0de51SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
413b3f0de51SMilanka Ringwald     }
414b3f0de51SMilanka Ringwald 
415b3f0de51SMilanka Ringwald     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_CONFIGURE_NOTIFICATIONS;
416b3f0de51SMilanka Ringwald     scan_parameters_service_run_for_client(client);
417b3f0de51SMilanka Ringwald     return ERROR_CODE_SUCCESS;
418b3f0de51SMilanka Ringwald }
419b3f0de51SMilanka Ringwald 
42078ae886bSMilanka Ringwald uint8_t scan_parameters_service_client_connect(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler, uint16_t * scan_parameters_service_cid){
42178ae886bSMilanka Ringwald     btstack_assert(packet_handler != NULL);
42278ae886bSMilanka Ringwald 
42378ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_con_handle(con_handle);
42478ae886bSMilanka Ringwald     if (client != NULL){
42578ae886bSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
42678ae886bSMilanka Ringwald     }
42778ae886bSMilanka Ringwald 
42878ae886bSMilanka Ringwald     uint16_t cid = scan_parameters_service_get_next_cid();
42978ae886bSMilanka Ringwald     if (scan_parameters_service_cid != NULL) {
43078ae886bSMilanka Ringwald         *scan_parameters_service_cid = cid;
43178ae886bSMilanka Ringwald     }
43278ae886bSMilanka Ringwald 
43378ae886bSMilanka Ringwald     client = scan_parameters_service_create_client(con_handle, cid);
43478ae886bSMilanka Ringwald     if (client == NULL) {
43578ae886bSMilanka Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
43678ae886bSMilanka Ringwald     }
43778ae886bSMilanka Ringwald 
43878ae886bSMilanka Ringwald     client->client_handler = packet_handler;
43978ae886bSMilanka Ringwald     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE;
44078ae886bSMilanka Ringwald     scan_parameters_service_run_for_client(client);
44178ae886bSMilanka Ringwald     return ERROR_CODE_SUCCESS;
44278ae886bSMilanka Ringwald }
44378ae886bSMilanka Ringwald 
44478ae886bSMilanka Ringwald uint8_t scan_parameters_service_client_disconnect(uint16_t scan_parameters_service_cid){
44578ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_cid(scan_parameters_service_cid);
44678ae886bSMilanka Ringwald     if (client == NULL){
44778ae886bSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
44878ae886bSMilanka Ringwald     }
44978ae886bSMilanka Ringwald     // finalize connections
45078ae886bSMilanka Ringwald     scan_parameters_service_finalize_client(client);
45178ae886bSMilanka Ringwald     return ERROR_CODE_SUCCESS;
45278ae886bSMilanka Ringwald }
45378ae886bSMilanka Ringwald 
45478ae886bSMilanka Ringwald void scan_parameters_service_client_init(void){}
45578ae886bSMilanka Ringwald 
45678ae886bSMilanka Ringwald void scan_parameters_service_client_deinit(void){}
45778ae886bSMilanka Ringwald 
458