xref: /btstack/src/ble/gatt-service/scan_parameters_service_client.c (revision 5fa2c39a4946eac81a0cc04c0d4688b33dbcd039)
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/core.h"
5378ae886bSMilanka Ringwald #include "ble/gatt_client.h"
5478ae886bSMilanka Ringwald #include "bluetooth_gatt.h"
5578ae886bSMilanka Ringwald #include "btstack_debug.h"
5678ae886bSMilanka Ringwald #include "btstack_event.h"
5778ae886bSMilanka Ringwald #include "btstack_run_loop.h"
5878ae886bSMilanka Ringwald #include "gap.h"
5978ae886bSMilanka Ringwald 
6078ae886bSMilanka Ringwald static btstack_linked_list_t clients;
6178ae886bSMilanka Ringwald static uint16_t scan_parameters_service_cid_counter = 0;
6278ae886bSMilanka Ringwald static uint16_t scan_parameters_service_scan_window = 0;
6378ae886bSMilanka Ringwald static uint16_t scan_parameters_service_scan_interval = 0;
6478ae886bSMilanka Ringwald 
6578ae886bSMilanka Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
66b3f0de51SMilanka Ringwald static void scan_parameters_service_run_for_client(scan_parameters_service_client_t * client);
6778ae886bSMilanka Ringwald 
6878ae886bSMilanka Ringwald static uint16_t scan_parameters_service_get_next_cid(void){
6978ae886bSMilanka Ringwald     if (scan_parameters_service_cid_counter == 0xffff) {
7078ae886bSMilanka Ringwald         scan_parameters_service_cid_counter = 1;
7178ae886bSMilanka Ringwald     } else {
7278ae886bSMilanka Ringwald         scan_parameters_service_cid_counter++;
7378ae886bSMilanka Ringwald     }
7478ae886bSMilanka Ringwald     return scan_parameters_service_cid_counter;
7578ae886bSMilanka Ringwald }
7678ae886bSMilanka Ringwald 
7778ae886bSMilanka Ringwald static scan_parameters_service_client_t * scan_parameters_service_create_client(hci_con_handle_t con_handle, uint16_t cid){
7878ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = btstack_memory_scan_parameters_service_client_get();
7978ae886bSMilanka Ringwald     if (!client){
8078ae886bSMilanka Ringwald         log_error("Not enough memory to create client");
8178ae886bSMilanka Ringwald         return NULL;
8278ae886bSMilanka Ringwald     }
8378ae886bSMilanka Ringwald 
8478ae886bSMilanka Ringwald     client->cid = cid;
8578ae886bSMilanka Ringwald     client->con_handle = con_handle;
8678ae886bSMilanka Ringwald     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_IDLE;
8778ae886bSMilanka Ringwald 
8878ae886bSMilanka Ringwald     client->start_handle = 0;
8978ae886bSMilanka Ringwald     client->end_handle = 0;
9078ae886bSMilanka Ringwald 
9178ae886bSMilanka Ringwald     client->scan_interval_window_value_handle = 0;
9278ae886bSMilanka Ringwald     client->scan_interval_window_value_update = false;
9378ae886bSMilanka Ringwald     btstack_linked_list_add(&clients, (btstack_linked_item_t *) client);
9478ae886bSMilanka Ringwald     return client;
9578ae886bSMilanka Ringwald }
9678ae886bSMilanka Ringwald 
9778ae886bSMilanka Ringwald static void scan_parameters_service_finalize_client(scan_parameters_service_client_t * client){
98b3f0de51SMilanka Ringwald     gatt_client_stop_listening_for_characteristic_value_updates(&client->notification_listener);
9978ae886bSMilanka Ringwald     btstack_linked_list_remove(&clients, (btstack_linked_item_t *) client);
10078ae886bSMilanka Ringwald     btstack_memory_scan_parameters_service_client_free(client);
10178ae886bSMilanka Ringwald }
10278ae886bSMilanka Ringwald 
10378ae886bSMilanka Ringwald static scan_parameters_service_client_t * scan_parameters_service_get_client_for_con_handle(hci_con_handle_t con_handle){
10478ae886bSMilanka Ringwald     btstack_linked_list_iterator_t it;
10578ae886bSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &clients);
10678ae886bSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
10778ae886bSMilanka Ringwald         scan_parameters_service_client_t * client = (scan_parameters_service_client_t *)btstack_linked_list_iterator_next(&it);
10878ae886bSMilanka Ringwald         if (client->con_handle != con_handle) continue;
10978ae886bSMilanka Ringwald         return client;
11078ae886bSMilanka Ringwald     }
11178ae886bSMilanka Ringwald     return NULL;
11278ae886bSMilanka Ringwald }
11378ae886bSMilanka Ringwald 
114b3f0de51SMilanka Ringwald static scan_parameters_service_client_t * scan_parameters_service_get_client_for_cid(uint16_t scan_parameters_service_cid){
11578ae886bSMilanka Ringwald     btstack_linked_list_iterator_t it;
11678ae886bSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &clients);
11778ae886bSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
11878ae886bSMilanka Ringwald         scan_parameters_service_client_t * client = (scan_parameters_service_client_t *)btstack_linked_list_iterator_next(&it);
119b3f0de51SMilanka Ringwald         if (client->cid != scan_parameters_service_cid) continue;
12078ae886bSMilanka Ringwald         return client;
12178ae886bSMilanka Ringwald     }
12278ae886bSMilanka Ringwald     return NULL;
12378ae886bSMilanka Ringwald }
12478ae886bSMilanka Ringwald 
12578ae886bSMilanka Ringwald static void scan_parameters_service_emit_connection_established(scan_parameters_service_client_t * client, uint8_t status){
12678ae886bSMilanka Ringwald     uint8_t event[6];
12778ae886bSMilanka Ringwald     int pos = 0;
12878ae886bSMilanka Ringwald     event[pos++] = HCI_EVENT_GATTSERVICE_META;
12978ae886bSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
13078ae886bSMilanka Ringwald     event[pos++] = GATTSERVICE_SUBEVENT_SCAN_PARAMETERS_SERVICE_CONNECTED;
13178ae886bSMilanka Ringwald     little_endian_store_16(event, pos, client->cid);
13278ae886bSMilanka Ringwald     pos += 2;
13378ae886bSMilanka Ringwald     event[pos++] = status;
134d4ac06ebSMilanka Ringwald     (*client->client_handler)(HCI_EVENT_GATTSERVICE_META, 0, event, sizeof(event));
13578ae886bSMilanka Ringwald }
13678ae886bSMilanka Ringwald 
137b3f0de51SMilanka Ringwald static void handle_notification_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
138b3f0de51SMilanka Ringwald     UNUSED(packet_type);
139b3f0de51SMilanka Ringwald     UNUSED(channel);
140b3f0de51SMilanka Ringwald     UNUSED(size);
141b3f0de51SMilanka Ringwald 
142b3f0de51SMilanka Ringwald     if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) return;
143b3f0de51SMilanka Ringwald 
144b3f0de51SMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_con_handle(gatt_event_notification_get_handle(packet));
145b3f0de51SMilanka Ringwald     btstack_assert(client != NULL);
146b3f0de51SMilanka Ringwald     client->scan_interval_window_value_update = true;
147b3f0de51SMilanka Ringwald     scan_parameters_service_run_for_client(client);
148b3f0de51SMilanka Ringwald }
14978ae886bSMilanka Ringwald 
15078ae886bSMilanka Ringwald static void scan_parameters_service_run_for_client(scan_parameters_service_client_t * client){
15178ae886bSMilanka Ringwald     uint8_t att_status;
15278ae886bSMilanka Ringwald     gatt_client_service_t service;
15378ae886bSMilanka Ringwald 
154b3f0de51SMilanka Ringwald     gatt_client_characteristic_t characteristic;
155b3f0de51SMilanka Ringwald 
15678ae886bSMilanka Ringwald     switch (client->state){
15778ae886bSMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE:
158b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
159b3f0de51SMilanka Ringwald             printf("\n\nQuery Services:\n");
160b3f0de51SMilanka Ringwald #endif
16178ae886bSMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT;
16278ae886bSMilanka Ringwald             att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_SCAN_PARAMETERS);
16378ae886bSMilanka Ringwald             // TODO handle status
16478ae886bSMilanka Ringwald             UNUSED(att_status);
16578ae886bSMilanka Ringwald             break;
16678ae886bSMilanka Ringwald 
16778ae886bSMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC:
168b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
169b3f0de51SMilanka Ringwald             printf("\n\nQuery Characteristics of service\n");
170b3f0de51SMilanka Ringwald #endif
17178ae886bSMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
17278ae886bSMilanka Ringwald             service.start_group_handle = client->start_handle;
17378ae886bSMilanka Ringwald             service.end_group_handle = client->end_handle;
174b3f0de51SMilanka Ringwald             att_status = gatt_client_discover_characteristics_for_service(
175b3f0de51SMilanka Ringwald                 handle_gatt_client_event, client->con_handle, &service);
17678ae886bSMilanka Ringwald             // TODO handle status
17778ae886bSMilanka Ringwald             UNUSED(att_status);
17878ae886bSMilanka Ringwald             break;
17978ae886bSMilanka Ringwald 
18078ae886bSMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED:
18178ae886bSMilanka Ringwald             if (client->scan_interval_window_value_update){
182b3f0de51SMilanka Ringwald                 client->scan_interval_window_value_update = false;
183b3f0de51SMilanka Ringwald 
184b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
185b3f0de51SMilanka Ringwald                 printf("\n\nUpdate - interval %d, window %d:\n", scan_parameters_service_scan_interval, scan_parameters_service_scan_window);
186b3f0de51SMilanka Ringwald #endif
18778ae886bSMilanka Ringwald                 uint8_t value[4];
18878ae886bSMilanka Ringwald                 little_endian_store_16(value, 0, scan_parameters_service_scan_interval);
18978ae886bSMilanka Ringwald                 little_endian_store_16(value, 2, scan_parameters_service_scan_window);
19078ae886bSMilanka Ringwald 
19178ae886bSMilanka Ringwald                 att_status = gatt_client_write_value_of_characteristic_without_response(client->con_handle, client->scan_interval_window_value_handle, 4, value);
19278ae886bSMilanka Ringwald                 // TODO handle status
19378ae886bSMilanka Ringwald                 UNUSED(att_status);
19478ae886bSMilanka Ringwald             }
19578ae886bSMilanka Ringwald             break;
196b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
197b3f0de51SMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CCC:
198b3f0de51SMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CCC;
199b3f0de51SMilanka Ringwald 
200b3f0de51SMilanka Ringwald             characteristic.value_handle = client->scan_refresh_value_handle;
201b3f0de51SMilanka Ringwald             characteristic.end_handle   =  client->scan_refresh_end_handle;
202b3f0de51SMilanka Ringwald 
203b3f0de51SMilanka Ringwald             // result in GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT
204b3f0de51SMilanka Ringwald             att_status = gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, client->con_handle, &characteristic);
205b3f0de51SMilanka Ringwald             UNUSED(att_status);
206b3f0de51SMilanka Ringwald             break;
207b3f0de51SMilanka Ringwald #endif
208b3f0de51SMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_CONFIGURE_NOTIFICATIONS:
209b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
210b3f0de51SMilanka Ringwald             printf("    Notification configuration enable ");
211b3f0de51SMilanka Ringwald #endif
212b3f0de51SMilanka Ringwald 
213b3f0de51SMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_NOTIFICATIONS_CONFIGURED;
214b3f0de51SMilanka Ringwald 
215b3f0de51SMilanka Ringwald             characteristic.value_handle = client->scan_refresh_value_handle;
216b3f0de51SMilanka Ringwald             characteristic.end_handle = client->scan_refresh_end_handle;
217b3f0de51SMilanka Ringwald             characteristic.properties = client->scan_refresh_properties;
218b3f0de51SMilanka Ringwald 
219b3f0de51SMilanka Ringwald             // end of write marked in GATT_EVENT_QUERY_COMPLETE
220b3f0de51SMilanka Ringwald 
221b3f0de51SMilanka Ringwald             att_status = gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, client->con_handle, &characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
222b3f0de51SMilanka Ringwald 
223b3f0de51SMilanka Ringwald             if (att_status == ERROR_CODE_SUCCESS){
224b3f0de51SMilanka Ringwald                 gatt_client_listen_for_characteristic_value_updates(
225b3f0de51SMilanka Ringwald                             &client->notification_listener,
226b3f0de51SMilanka Ringwald                             &handle_notification_event, client->con_handle, &characteristic);
227b3f0de51SMilanka Ringwald             }
228b3f0de51SMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED;
229b3f0de51SMilanka Ringwald             break;
23078ae886bSMilanka Ringwald         default:
23178ae886bSMilanka Ringwald             break;
23278ae886bSMilanka Ringwald     }
23378ae886bSMilanka Ringwald }
23478ae886bSMilanka Ringwald 
23578ae886bSMilanka Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
23678ae886bSMilanka Ringwald     UNUSED(packet_type);
23778ae886bSMilanka Ringwald     UNUSED(channel);
23878ae886bSMilanka Ringwald     UNUSED(size);
23978ae886bSMilanka Ringwald 
24078ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = NULL;
24178ae886bSMilanka Ringwald     gatt_client_service_t service;
24278ae886bSMilanka Ringwald     gatt_client_characteristic_t characteristic;
24378ae886bSMilanka Ringwald     uint8_t att_status;
24478ae886bSMilanka Ringwald 
245b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
246b3f0de51SMilanka Ringwald     gatt_client_characteristic_descriptor_t characteristic_descriptor;
247b3f0de51SMilanka Ringwald #endif
248b3f0de51SMilanka Ringwald 
24978ae886bSMilanka Ringwald     switch(hci_event_packet_get_type(packet)){
25078ae886bSMilanka Ringwald         case GATT_EVENT_SERVICE_QUERY_RESULT:
25178ae886bSMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
25278ae886bSMilanka Ringwald             btstack_assert(client != NULL);
25378ae886bSMilanka Ringwald 
25478ae886bSMilanka Ringwald             if (client->state != SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT) {
25578ae886bSMilanka Ringwald                 scan_parameters_service_emit_connection_established(client, GATT_CLIENT_IN_WRONG_STATE);
25678ae886bSMilanka Ringwald                 scan_parameters_service_finalize_client(client);
257*5fa2c39aSMilanka Ringwald                 return;
25878ae886bSMilanka Ringwald             }
25978ae886bSMilanka Ringwald 
26078ae886bSMilanka Ringwald             gatt_event_service_query_result_get_service(packet, &service);
26178ae886bSMilanka Ringwald             client->start_handle = service.start_group_handle;
26278ae886bSMilanka Ringwald             client->end_handle = service.end_group_handle;
263b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
264b3f0de51SMilanka Ringwald             printf("ScS Service: start handle 0x%04X, end handle 0x%04X\n", client->start_handle, client->end_handle);
265b3f0de51SMilanka Ringwald #endif
26678ae886bSMilanka Ringwald             break;
26778ae886bSMilanka Ringwald 
26878ae886bSMilanka Ringwald         case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
26978ae886bSMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet));
27078ae886bSMilanka Ringwald             btstack_assert(client != NULL);
27178ae886bSMilanka Ringwald 
27278ae886bSMilanka Ringwald             // found scan_interval_window_value_handle, check att_status
27378ae886bSMilanka Ringwald             gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
274b3f0de51SMilanka Ringwald             switch (characteristic.uuid16){
275b3f0de51SMilanka Ringwald                 case ORG_BLUETOOTH_CHARACTERISTIC_SCAN_INTERVAL_WINDOW:
27678ae886bSMilanka Ringwald                     client->scan_interval_window_value_handle = characteristic.value_handle;
277b3f0de51SMilanka Ringwald 
278b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
279b3f0de51SMilanka Ringwald                     printf("ScS Scan Interval Characteristic:  \n    Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n",
280b3f0de51SMilanka Ringwald                         characteristic.start_handle,
281b3f0de51SMilanka Ringwald                         characteristic.properties,
282b3f0de51SMilanka Ringwald                         characteristic.value_handle, characteristic.uuid16);
283b3f0de51SMilanka Ringwald #endif
28478ae886bSMilanka Ringwald                     break;
285b3f0de51SMilanka Ringwald                 case ORG_BLUETOOTH_CHARACTERISTIC_SCAN_REFRESH:
286b3f0de51SMilanka Ringwald                     client->scan_refresh_value_handle = characteristic.value_handle;
287b3f0de51SMilanka Ringwald                     client->scan_refresh_end_handle = characteristic.end_handle;
288b3f0de51SMilanka Ringwald                     client->scan_refresh_properties = characteristic.properties;
289b3f0de51SMilanka Ringwald 
290b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
291b3f0de51SMilanka Ringwald                     printf("ScS Scan Refresh Characteristic:  \n    Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n",
292b3f0de51SMilanka Ringwald                         characteristic.start_handle,
293b3f0de51SMilanka Ringwald                         characteristic.properties,
294b3f0de51SMilanka Ringwald                         characteristic.value_handle, characteristic.uuid16);
295b3f0de51SMilanka Ringwald #endif
296b3f0de51SMilanka Ringwald                     break;
297b3f0de51SMilanka Ringwald                 default:
298b3f0de51SMilanka Ringwald                     break;
299b3f0de51SMilanka Ringwald             }
300b3f0de51SMilanka Ringwald             break;
301b3f0de51SMilanka Ringwald 
302b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
303b3f0de51SMilanka Ringwald         case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
304b3f0de51SMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet));
305b3f0de51SMilanka Ringwald             btstack_assert(client != NULL);
306b3f0de51SMilanka Ringwald 
307b3f0de51SMilanka Ringwald             gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor);
308b3f0de51SMilanka Ringwald             if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION){
309b3f0de51SMilanka Ringwald                 printf("    Client Characteristic Configuration Descriptor: Handle 0x%04X, UUID 0x%04X\n",
310b3f0de51SMilanka Ringwald                     characteristic_descriptor.handle,
311b3f0de51SMilanka Ringwald                     characteristic_descriptor.uuid16);
312b3f0de51SMilanka Ringwald             }
313b3f0de51SMilanka Ringwald             break;
314b3f0de51SMilanka Ringwald 
315b3f0de51SMilanka Ringwald         case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
316b3f0de51SMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
317b3f0de51SMilanka Ringwald             btstack_assert(client != NULL);
318b3f0de51SMilanka Ringwald 
319b3f0de51SMilanka Ringwald             printf("    Received CCC value: ");
320b3f0de51SMilanka Ringwald             printf_hexdump(gatt_event_characteristic_value_query_result_get_value(packet),  gatt_event_characteristic_value_query_result_get_value_length(packet));
321b3f0de51SMilanka Ringwald             break;
322b3f0de51SMilanka Ringwald #endif
32378ae886bSMilanka Ringwald 
32478ae886bSMilanka Ringwald         case GATT_EVENT_QUERY_COMPLETE:
32578ae886bSMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
32678ae886bSMilanka Ringwald             btstack_assert(client != NULL);
32778ae886bSMilanka Ringwald 
32878ae886bSMilanka Ringwald             att_status = gatt_event_query_complete_get_att_status(packet);
32978ae886bSMilanka Ringwald 
33078ae886bSMilanka Ringwald             switch (client->state){
33178ae886bSMilanka Ringwald                 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT:
33278ae886bSMilanka Ringwald                     if (att_status != ATT_ERROR_SUCCESS){
33378ae886bSMilanka Ringwald                         scan_parameters_service_emit_connection_established(client, att_status);
33478ae886bSMilanka Ringwald                         scan_parameters_service_finalize_client(client);
335*5fa2c39aSMilanka Ringwald                         return;
33678ae886bSMilanka Ringwald                     }
33778ae886bSMilanka Ringwald 
33878ae886bSMilanka Ringwald                     if (client->start_handle != 0){
339b3f0de51SMilanka Ringwald                         client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC;
34078ae886bSMilanka Ringwald                         break;
34178ae886bSMilanka Ringwald                     }
342b3f0de51SMilanka Ringwald 
343b3f0de51SMilanka Ringwald                     scan_parameters_service_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
344b3f0de51SMilanka Ringwald                     scan_parameters_service_finalize_client(client);
345*5fa2c39aSMilanka Ringwald                     return;
34678ae886bSMilanka Ringwald 
34778ae886bSMilanka Ringwald                 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
34878ae886bSMilanka Ringwald                     if (att_status != ATT_ERROR_SUCCESS){
34978ae886bSMilanka Ringwald                         scan_parameters_service_emit_connection_established(client, att_status);
35078ae886bSMilanka Ringwald                         scan_parameters_service_finalize_client(client);
35178ae886bSMilanka Ringwald                         break;
35278ae886bSMilanka Ringwald                     }
35378ae886bSMilanka Ringwald                     if (client->scan_interval_window_value_handle == 0){
35478ae886bSMilanka Ringwald                         scan_parameters_service_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
35578ae886bSMilanka Ringwald                         scan_parameters_service_finalize_client(client);
356*5fa2c39aSMilanka Ringwald                         return;
35778ae886bSMilanka Ringwald                     }
358b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
359b3f0de51SMilanka Ringwald                     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CCC;
360b3f0de51SMilanka Ringwald #else
36178ae886bSMilanka Ringwald                     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED;
36278ae886bSMilanka Ringwald                     client->scan_interval_window_value_update = true;
363b3f0de51SMilanka Ringwald                     scan_parameters_service_emit_connection_established(client, ERROR_CODE_SUCCESS);
364b3f0de51SMilanka Ringwald #endif
36578ae886bSMilanka Ringwald                     break;
36678ae886bSMilanka Ringwald 
367b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
368b3f0de51SMilanka Ringwald                 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CCC:
369b3f0de51SMilanka Ringwald                     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED;
370b3f0de51SMilanka Ringwald                     client->scan_interval_window_value_update = true;
371b3f0de51SMilanka Ringwald                     scan_parameters_service_emit_connection_established(client, ERROR_CODE_SUCCESS);
372b3f0de51SMilanka Ringwald                     break;
373b3f0de51SMilanka Ringwald #endif
37478ae886bSMilanka Ringwald                 default:
37578ae886bSMilanka Ringwald                     break;
37678ae886bSMilanka Ringwald             }
37778ae886bSMilanka Ringwald             break;
37878ae886bSMilanka Ringwald         default:
37978ae886bSMilanka Ringwald             break;
38078ae886bSMilanka Ringwald     }
38178ae886bSMilanka Ringwald 
38278ae886bSMilanka Ringwald     if (client != NULL){
38378ae886bSMilanka Ringwald         scan_parameters_service_run_for_client(client);
38478ae886bSMilanka Ringwald     }
38578ae886bSMilanka Ringwald }
38678ae886bSMilanka Ringwald 
38778ae886bSMilanka Ringwald void scan_parameters_service_client_set(uint16_t scan_interval, uint16_t scan_window){
38878ae886bSMilanka Ringwald     scan_parameters_service_scan_interval = scan_interval;
38978ae886bSMilanka Ringwald     scan_parameters_service_scan_window = scan_window;
39078ae886bSMilanka Ringwald 
39178ae886bSMilanka Ringwald     btstack_linked_list_iterator_t it;
39278ae886bSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &clients);
39378ae886bSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
39478ae886bSMilanka Ringwald         scan_parameters_service_client_t * client = (scan_parameters_service_client_t*) btstack_linked_list_iterator_next(&it);
39578ae886bSMilanka Ringwald         client->scan_interval_window_value_update = true;
39678ae886bSMilanka Ringwald         scan_parameters_service_run_for_client(client);
39778ae886bSMilanka Ringwald     }
39878ae886bSMilanka Ringwald }
39978ae886bSMilanka Ringwald 
400b3f0de51SMilanka Ringwald uint8_t scan_parameters_service_client_enable_notifications(uint16_t scan_parameters_service_cid){
401b3f0de51SMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_cid(scan_parameters_service_cid);
402b3f0de51SMilanka Ringwald 
403b3f0de51SMilanka Ringwald     if (client == NULL){
404b3f0de51SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
405b3f0de51SMilanka Ringwald     }
406b3f0de51SMilanka Ringwald 
407b3f0de51SMilanka Ringwald     if (client->state != SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED) {
408b3f0de51SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
409b3f0de51SMilanka Ringwald     }
410b3f0de51SMilanka Ringwald 
411b3f0de51SMilanka Ringwald     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_CONFIGURE_NOTIFICATIONS;
412b3f0de51SMilanka Ringwald     scan_parameters_service_run_for_client(client);
413b3f0de51SMilanka Ringwald     return ERROR_CODE_SUCCESS;
414b3f0de51SMilanka Ringwald }
415b3f0de51SMilanka Ringwald 
41678ae886bSMilanka 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){
41778ae886bSMilanka Ringwald     btstack_assert(packet_handler != NULL);
41878ae886bSMilanka Ringwald 
41978ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_con_handle(con_handle);
42078ae886bSMilanka Ringwald     if (client != NULL){
42178ae886bSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
42278ae886bSMilanka Ringwald     }
42378ae886bSMilanka Ringwald 
42478ae886bSMilanka Ringwald     uint16_t cid = scan_parameters_service_get_next_cid();
42578ae886bSMilanka Ringwald     if (scan_parameters_service_cid != NULL) {
42678ae886bSMilanka Ringwald         *scan_parameters_service_cid = cid;
42778ae886bSMilanka Ringwald     }
42878ae886bSMilanka Ringwald 
42978ae886bSMilanka Ringwald     client = scan_parameters_service_create_client(con_handle, cid);
43078ae886bSMilanka Ringwald     if (client == NULL) {
43178ae886bSMilanka Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
43278ae886bSMilanka Ringwald     }
43378ae886bSMilanka Ringwald 
43478ae886bSMilanka Ringwald     client->client_handler = packet_handler;
43578ae886bSMilanka Ringwald     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE;
43678ae886bSMilanka Ringwald     scan_parameters_service_run_for_client(client);
43778ae886bSMilanka Ringwald     return ERROR_CODE_SUCCESS;
43878ae886bSMilanka Ringwald }
43978ae886bSMilanka Ringwald 
44078ae886bSMilanka Ringwald uint8_t scan_parameters_service_client_disconnect(uint16_t scan_parameters_service_cid){
44178ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_cid(scan_parameters_service_cid);
44278ae886bSMilanka Ringwald     if (client == NULL){
44378ae886bSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
44478ae886bSMilanka Ringwald     }
44578ae886bSMilanka Ringwald     // finalize connections
44678ae886bSMilanka Ringwald     scan_parameters_service_finalize_client(client);
44778ae886bSMilanka Ringwald     return ERROR_CODE_SUCCESS;
44878ae886bSMilanka Ringwald }
44978ae886bSMilanka Ringwald 
45078ae886bSMilanka Ringwald void scan_parameters_service_client_init(void){}
45178ae886bSMilanka Ringwald 
45278ae886bSMilanka Ringwald void scan_parameters_service_client_deinit(void){}
45378ae886bSMilanka Ringwald 
454