xref: /btstack/src/ble/gatt-service/scan_parameters_service_client.c (revision 7aa5195fa4e273d13737d85f8ad3e87aade1e700)
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
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH 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 
60*7aa5195fSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
61*7aa5195fSMatthias 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;
136d4ac06ebSMilanka Ringwald     (*client->client_handler)(HCI_EVENT_GATTSERVICE_META, 0, event, sizeof(event));
13778ae886bSMilanka Ringwald }
13878ae886bSMilanka Ringwald 
139*7aa5195fSMatthias Ringwald static void scan_parameters_service_emit_disconnected(btstack_packet_handler_t packet_handler, uint16_t cid){
140*7aa5195fSMatthias Ringwald     uint8_t event[5];
141*7aa5195fSMatthias Ringwald     int pos = 0;
142*7aa5195fSMatthias Ringwald     event[pos++] = HCI_EVENT_GATTSERVICE_META;
143*7aa5195fSMatthias Ringwald     event[pos++] = sizeof(event) - 2;
144*7aa5195fSMatthias Ringwald     event[pos++] = GATTSERVICE_SUBEVENT_SCAN_PARAMETERS_SERVICE_DISCONNECTED;
145*7aa5195fSMatthias Ringwald     little_endian_store_16(event, pos, cid);
146*7aa5195fSMatthias Ringwald     pos += 2;
147*7aa5195fSMatthias Ringwald     btstack_assert(pos == sizeof(event));
148*7aa5195fSMatthias Ringwald     (*packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
149*7aa5195fSMatthias Ringwald }
150*7aa5195fSMatthias Ringwald 
151b3f0de51SMilanka Ringwald static void handle_notification_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
152b3f0de51SMilanka Ringwald     UNUSED(packet_type);
153b3f0de51SMilanka Ringwald     UNUSED(channel);
154b3f0de51SMilanka Ringwald     UNUSED(size);
155b3f0de51SMilanka Ringwald 
156b3f0de51SMilanka Ringwald     if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) return;
157b3f0de51SMilanka Ringwald 
158b3f0de51SMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_con_handle(gatt_event_notification_get_handle(packet));
159b3f0de51SMilanka Ringwald     btstack_assert(client != NULL);
160b3f0de51SMilanka Ringwald     client->scan_interval_window_value_update = true;
161b3f0de51SMilanka Ringwald     scan_parameters_service_run_for_client(client);
162b3f0de51SMilanka Ringwald }
16378ae886bSMilanka Ringwald 
16478ae886bSMilanka Ringwald static void scan_parameters_service_run_for_client(scan_parameters_service_client_t * client){
16578ae886bSMilanka Ringwald     uint8_t att_status;
16678ae886bSMilanka Ringwald     gatt_client_service_t service;
16778ae886bSMilanka Ringwald 
168b3f0de51SMilanka Ringwald     gatt_client_characteristic_t characteristic;
169b3f0de51SMilanka Ringwald 
17078ae886bSMilanka Ringwald     switch (client->state){
17178ae886bSMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE:
172b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
173b3f0de51SMilanka Ringwald             printf("\n\nQuery Services:\n");
174b3f0de51SMilanka Ringwald #endif
17578ae886bSMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT;
17678ae886bSMilanka Ringwald             att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_SCAN_PARAMETERS);
17778ae886bSMilanka Ringwald             // TODO handle status
17878ae886bSMilanka Ringwald             UNUSED(att_status);
17978ae886bSMilanka Ringwald             break;
18078ae886bSMilanka Ringwald 
18178ae886bSMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC:
182b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
183b3f0de51SMilanka Ringwald             printf("\n\nQuery Characteristics of service\n");
184b3f0de51SMilanka Ringwald #endif
18578ae886bSMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
18678ae886bSMilanka Ringwald             service.start_group_handle = client->start_handle;
18778ae886bSMilanka Ringwald             service.end_group_handle = client->end_handle;
188b3f0de51SMilanka Ringwald             att_status = gatt_client_discover_characteristics_for_service(
189b3f0de51SMilanka Ringwald                 handle_gatt_client_event, client->con_handle, &service);
19078ae886bSMilanka Ringwald             // TODO handle status
19178ae886bSMilanka Ringwald             UNUSED(att_status);
19278ae886bSMilanka Ringwald             break;
19378ae886bSMilanka Ringwald 
19478ae886bSMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED:
19578ae886bSMilanka Ringwald             if (client->scan_interval_window_value_update){
196b3f0de51SMilanka Ringwald                 client->scan_interval_window_value_update = false;
197b3f0de51SMilanka Ringwald 
198b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
199b3f0de51SMilanka Ringwald                 printf("\n\nUpdate - interval %d, window %d:\n", scan_parameters_service_scan_interval, scan_parameters_service_scan_window);
200b3f0de51SMilanka Ringwald #endif
20178ae886bSMilanka Ringwald                 uint8_t value[4];
20278ae886bSMilanka Ringwald                 little_endian_store_16(value, 0, scan_parameters_service_scan_interval);
20378ae886bSMilanka Ringwald                 little_endian_store_16(value, 2, scan_parameters_service_scan_window);
20478ae886bSMilanka Ringwald 
20578ae886bSMilanka Ringwald                 att_status = gatt_client_write_value_of_characteristic_without_response(client->con_handle, client->scan_interval_window_value_handle, 4, value);
20678ae886bSMilanka Ringwald                 // TODO handle status
20778ae886bSMilanka Ringwald                 UNUSED(att_status);
20878ae886bSMilanka Ringwald             }
20978ae886bSMilanka Ringwald             break;
210b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
211b3f0de51SMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CCC:
212b3f0de51SMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CCC;
213b3f0de51SMilanka Ringwald 
214b3f0de51SMilanka Ringwald             characteristic.value_handle = client->scan_refresh_value_handle;
215b3f0de51SMilanka Ringwald             characteristic.end_handle   =  client->scan_refresh_end_handle;
216b3f0de51SMilanka Ringwald 
217b3f0de51SMilanka Ringwald             // result in GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT
218b3f0de51SMilanka Ringwald             att_status = gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, client->con_handle, &characteristic);
219b3f0de51SMilanka Ringwald             UNUSED(att_status);
220b3f0de51SMilanka Ringwald             break;
221b3f0de51SMilanka Ringwald #endif
222b3f0de51SMilanka Ringwald         case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_CONFIGURE_NOTIFICATIONS:
223b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
224b3f0de51SMilanka Ringwald             printf("    Notification configuration enable ");
225b3f0de51SMilanka Ringwald #endif
226b3f0de51SMilanka Ringwald 
227b3f0de51SMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_NOTIFICATIONS_CONFIGURED;
228b3f0de51SMilanka Ringwald 
229b3f0de51SMilanka Ringwald             characteristic.value_handle = client->scan_refresh_value_handle;
230b3f0de51SMilanka Ringwald             characteristic.end_handle = client->scan_refresh_end_handle;
231b3f0de51SMilanka Ringwald             characteristic.properties = client->scan_refresh_properties;
232b3f0de51SMilanka Ringwald 
233b3f0de51SMilanka Ringwald             // end of write marked in GATT_EVENT_QUERY_COMPLETE
234b3f0de51SMilanka Ringwald 
235b3f0de51SMilanka Ringwald             att_status = gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, client->con_handle, &characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
236b3f0de51SMilanka Ringwald 
237b3f0de51SMilanka Ringwald             if (att_status == ERROR_CODE_SUCCESS){
238b3f0de51SMilanka Ringwald                 gatt_client_listen_for_characteristic_value_updates(
239b3f0de51SMilanka Ringwald                             &client->notification_listener,
240b3f0de51SMilanka Ringwald                             &handle_notification_event, client->con_handle, &characteristic);
241b3f0de51SMilanka Ringwald             }
242b3f0de51SMilanka Ringwald             client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED;
243b3f0de51SMilanka Ringwald             break;
24478ae886bSMilanka Ringwald         default:
24578ae886bSMilanka Ringwald             break;
24678ae886bSMilanka Ringwald     }
24778ae886bSMilanka Ringwald }
24878ae886bSMilanka Ringwald 
24978ae886bSMilanka Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
25078ae886bSMilanka Ringwald     UNUSED(packet_type);
25178ae886bSMilanka Ringwald     UNUSED(channel);
25278ae886bSMilanka Ringwald     UNUSED(size);
25378ae886bSMilanka Ringwald 
25478ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = NULL;
25578ae886bSMilanka Ringwald     gatt_client_service_t service;
25678ae886bSMilanka Ringwald     gatt_client_characteristic_t characteristic;
25778ae886bSMilanka Ringwald     uint8_t att_status;
25878ae886bSMilanka Ringwald 
259b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
260b3f0de51SMilanka Ringwald     gatt_client_characteristic_descriptor_t characteristic_descriptor;
261b3f0de51SMilanka Ringwald #endif
262b3f0de51SMilanka Ringwald 
26378ae886bSMilanka Ringwald     switch(hci_event_packet_get_type(packet)){
26478ae886bSMilanka Ringwald         case GATT_EVENT_SERVICE_QUERY_RESULT:
26578ae886bSMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
26678ae886bSMilanka Ringwald             btstack_assert(client != NULL);
26778ae886bSMilanka Ringwald 
26878ae886bSMilanka Ringwald             if (client->state != SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT) {
26978ae886bSMilanka Ringwald                 scan_parameters_service_emit_connection_established(client, GATT_CLIENT_IN_WRONG_STATE);
27078ae886bSMilanka Ringwald                 scan_parameters_service_finalize_client(client);
2715fa2c39aSMilanka Ringwald                 return;
27278ae886bSMilanka Ringwald             }
27378ae886bSMilanka Ringwald 
27478ae886bSMilanka Ringwald             gatt_event_service_query_result_get_service(packet, &service);
27578ae886bSMilanka Ringwald             client->start_handle = service.start_group_handle;
27678ae886bSMilanka Ringwald             client->end_handle = service.end_group_handle;
277b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
278b3f0de51SMilanka Ringwald             printf("ScS Service: start handle 0x%04X, end handle 0x%04X\n", client->start_handle, client->end_handle);
279b3f0de51SMilanka Ringwald #endif
28078ae886bSMilanka Ringwald             break;
28178ae886bSMilanka Ringwald 
28278ae886bSMilanka Ringwald         case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
28378ae886bSMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet));
28478ae886bSMilanka Ringwald             btstack_assert(client != NULL);
28578ae886bSMilanka Ringwald 
28678ae886bSMilanka Ringwald             // found scan_interval_window_value_handle, check att_status
28778ae886bSMilanka Ringwald             gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
288b3f0de51SMilanka Ringwald             switch (characteristic.uuid16){
289b3f0de51SMilanka Ringwald                 case ORG_BLUETOOTH_CHARACTERISTIC_SCAN_INTERVAL_WINDOW:
29078ae886bSMilanka Ringwald                     client->scan_interval_window_value_handle = characteristic.value_handle;
291b3f0de51SMilanka Ringwald 
292b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
293b3f0de51SMilanka Ringwald                     printf("ScS Scan Interval Characteristic:  \n    Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n",
294b3f0de51SMilanka Ringwald                         characteristic.start_handle,
295b3f0de51SMilanka Ringwald                         characteristic.properties,
296b3f0de51SMilanka Ringwald                         characteristic.value_handle, characteristic.uuid16);
297b3f0de51SMilanka Ringwald #endif
29878ae886bSMilanka Ringwald                     break;
299b3f0de51SMilanka Ringwald                 case ORG_BLUETOOTH_CHARACTERISTIC_SCAN_REFRESH:
300b3f0de51SMilanka Ringwald                     client->scan_refresh_value_handle = characteristic.value_handle;
301b3f0de51SMilanka Ringwald                     client->scan_refresh_end_handle = characteristic.end_handle;
302b3f0de51SMilanka Ringwald                     client->scan_refresh_properties = characteristic.properties;
303b3f0de51SMilanka Ringwald 
304b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
305b3f0de51SMilanka Ringwald                     printf("ScS Scan Refresh Characteristic:  \n    Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n",
306b3f0de51SMilanka Ringwald                         characteristic.start_handle,
307b3f0de51SMilanka Ringwald                         characteristic.properties,
308b3f0de51SMilanka Ringwald                         characteristic.value_handle, characteristic.uuid16);
309b3f0de51SMilanka Ringwald #endif
310b3f0de51SMilanka Ringwald                     break;
311b3f0de51SMilanka Ringwald                 default:
312b3f0de51SMilanka Ringwald                     break;
313b3f0de51SMilanka Ringwald             }
314b3f0de51SMilanka Ringwald             break;
315b3f0de51SMilanka Ringwald 
316b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
317b3f0de51SMilanka Ringwald         case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
318b3f0de51SMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet));
319b3f0de51SMilanka Ringwald             btstack_assert(client != NULL);
320b3f0de51SMilanka Ringwald 
321b3f0de51SMilanka Ringwald             gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor);
322b3f0de51SMilanka Ringwald             if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION){
323b3f0de51SMilanka Ringwald                 printf("    Client Characteristic Configuration Descriptor: Handle 0x%04X, UUID 0x%04X\n",
324b3f0de51SMilanka Ringwald                     characteristic_descriptor.handle,
325b3f0de51SMilanka Ringwald                     characteristic_descriptor.uuid16);
326b3f0de51SMilanka Ringwald             }
327b3f0de51SMilanka Ringwald             break;
328b3f0de51SMilanka Ringwald 
329b3f0de51SMilanka Ringwald         case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
330b3f0de51SMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
331b3f0de51SMilanka Ringwald             btstack_assert(client != NULL);
332b3f0de51SMilanka Ringwald 
333b3f0de51SMilanka Ringwald             printf("    Received CCC value: ");
334b3f0de51SMilanka Ringwald             printf_hexdump(gatt_event_characteristic_value_query_result_get_value(packet),  gatt_event_characteristic_value_query_result_get_value_length(packet));
335b3f0de51SMilanka Ringwald             break;
336b3f0de51SMilanka Ringwald #endif
33778ae886bSMilanka Ringwald 
33878ae886bSMilanka Ringwald         case GATT_EVENT_QUERY_COMPLETE:
33978ae886bSMilanka Ringwald             client = scan_parameters_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
34078ae886bSMilanka Ringwald             btstack_assert(client != NULL);
34178ae886bSMilanka Ringwald 
34278ae886bSMilanka Ringwald             att_status = gatt_event_query_complete_get_att_status(packet);
34378ae886bSMilanka Ringwald 
34478ae886bSMilanka Ringwald             switch (client->state){
34578ae886bSMilanka Ringwald                 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT:
34678ae886bSMilanka Ringwald                     if (att_status != ATT_ERROR_SUCCESS){
34778ae886bSMilanka Ringwald                         scan_parameters_service_emit_connection_established(client, att_status);
34878ae886bSMilanka Ringwald                         scan_parameters_service_finalize_client(client);
3495fa2c39aSMilanka Ringwald                         return;
35078ae886bSMilanka Ringwald                     }
35178ae886bSMilanka Ringwald 
35278ae886bSMilanka Ringwald                     if (client->start_handle != 0){
353b3f0de51SMilanka Ringwald                         client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC;
35478ae886bSMilanka Ringwald                         break;
35578ae886bSMilanka Ringwald                     }
356b3f0de51SMilanka Ringwald 
357b3f0de51SMilanka Ringwald                     scan_parameters_service_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
358b3f0de51SMilanka Ringwald                     scan_parameters_service_finalize_client(client);
3595fa2c39aSMilanka Ringwald                     return;
36078ae886bSMilanka Ringwald 
36178ae886bSMilanka Ringwald                 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
36278ae886bSMilanka Ringwald                     if (att_status != ATT_ERROR_SUCCESS){
36378ae886bSMilanka Ringwald                         scan_parameters_service_emit_connection_established(client, att_status);
36478ae886bSMilanka Ringwald                         scan_parameters_service_finalize_client(client);
36578ae886bSMilanka Ringwald                         break;
36678ae886bSMilanka Ringwald                     }
36778ae886bSMilanka Ringwald                     if (client->scan_interval_window_value_handle == 0){
36878ae886bSMilanka Ringwald                         scan_parameters_service_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
36978ae886bSMilanka Ringwald                         scan_parameters_service_finalize_client(client);
3705fa2c39aSMilanka Ringwald                         return;
37178ae886bSMilanka Ringwald                     }
372b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
373b3f0de51SMilanka Ringwald                     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CCC;
374b3f0de51SMilanka Ringwald #else
37578ae886bSMilanka Ringwald                     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED;
37678ae886bSMilanka Ringwald                     client->scan_interval_window_value_update = true;
377b3f0de51SMilanka Ringwald                     scan_parameters_service_emit_connection_established(client, ERROR_CODE_SUCCESS);
378b3f0de51SMilanka Ringwald #endif
37978ae886bSMilanka Ringwald                     break;
38078ae886bSMilanka Ringwald 
381b3f0de51SMilanka Ringwald #ifdef ENABLE_TESTING_SUPPORT
382b3f0de51SMilanka Ringwald                 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CCC:
383b3f0de51SMilanka Ringwald                     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED;
384b3f0de51SMilanka Ringwald                     client->scan_interval_window_value_update = true;
385b3f0de51SMilanka Ringwald                     scan_parameters_service_emit_connection_established(client, ERROR_CODE_SUCCESS);
386b3f0de51SMilanka Ringwald                     break;
387b3f0de51SMilanka Ringwald #endif
38878ae886bSMilanka Ringwald                 default:
38978ae886bSMilanka Ringwald                     break;
39078ae886bSMilanka Ringwald             }
39178ae886bSMilanka Ringwald             break;
39278ae886bSMilanka Ringwald         default:
39378ae886bSMilanka Ringwald             break;
39478ae886bSMilanka Ringwald     }
39578ae886bSMilanka Ringwald 
39678ae886bSMilanka Ringwald     if (client != NULL){
39778ae886bSMilanka Ringwald         scan_parameters_service_run_for_client(client);
39878ae886bSMilanka Ringwald     }
39978ae886bSMilanka Ringwald }
40078ae886bSMilanka Ringwald 
401*7aa5195fSMatthias Ringwald static void handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
402*7aa5195fSMatthias Ringwald     UNUSED(packet_type); // ok: only hci events
403*7aa5195fSMatthias Ringwald     UNUSED(channel);     // ok: there is no channel
404*7aa5195fSMatthias Ringwald     UNUSED(size);        // ok: fixed format events read from HCI buffer
405*7aa5195fSMatthias Ringwald 
406*7aa5195fSMatthias Ringwald     hci_con_handle_t con_handle;
407*7aa5195fSMatthias Ringwald     scan_parameters_service_client_t * client;
408*7aa5195fSMatthias Ringwald 
409*7aa5195fSMatthias Ringwald     switch (hci_event_packet_get_type(packet)) {
410*7aa5195fSMatthias Ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
411*7aa5195fSMatthias Ringwald             con_handle = hci_event_disconnection_complete_get_connection_handle(packet);
412*7aa5195fSMatthias Ringwald             client = scan_parameters_service_get_client_for_con_handle(con_handle);
413*7aa5195fSMatthias Ringwald             if (client != NULL){
414*7aa5195fSMatthias Ringwald                 // emit disconnected
415*7aa5195fSMatthias Ringwald                 btstack_packet_handler_t packet_handler = client->client_handler;
416*7aa5195fSMatthias Ringwald                 uint16_t cid = client->cid;
417*7aa5195fSMatthias Ringwald                 scan_parameters_service_emit_disconnected(packet_handler, cid);
418*7aa5195fSMatthias Ringwald                 // finalize
419*7aa5195fSMatthias Ringwald                 scan_parameters_service_finalize_client(client);
420*7aa5195fSMatthias Ringwald             }
421*7aa5195fSMatthias Ringwald             break;
422*7aa5195fSMatthias Ringwald         default:
423*7aa5195fSMatthias Ringwald             break;
424*7aa5195fSMatthias Ringwald     }
425*7aa5195fSMatthias Ringwald }
426*7aa5195fSMatthias Ringwald 
42778ae886bSMilanka Ringwald void scan_parameters_service_client_set(uint16_t scan_interval, uint16_t scan_window){
42878ae886bSMilanka Ringwald     scan_parameters_service_scan_interval = scan_interval;
42978ae886bSMilanka Ringwald     scan_parameters_service_scan_window = scan_window;
43078ae886bSMilanka Ringwald 
43178ae886bSMilanka Ringwald     btstack_linked_list_iterator_t it;
43278ae886bSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &clients);
43378ae886bSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
43478ae886bSMilanka Ringwald         scan_parameters_service_client_t * client = (scan_parameters_service_client_t*) btstack_linked_list_iterator_next(&it);
43578ae886bSMilanka Ringwald         client->scan_interval_window_value_update = true;
43678ae886bSMilanka Ringwald         scan_parameters_service_run_for_client(client);
43778ae886bSMilanka Ringwald     }
43878ae886bSMilanka Ringwald }
43978ae886bSMilanka Ringwald 
440b3f0de51SMilanka Ringwald uint8_t scan_parameters_service_client_enable_notifications(uint16_t scan_parameters_service_cid){
441b3f0de51SMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_cid(scan_parameters_service_cid);
442b3f0de51SMilanka Ringwald 
443b3f0de51SMilanka Ringwald     if (client == NULL){
444b3f0de51SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
445b3f0de51SMilanka Ringwald     }
446b3f0de51SMilanka Ringwald 
447b3f0de51SMilanka Ringwald     if (client->state != SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED) {
448b3f0de51SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
449b3f0de51SMilanka Ringwald     }
450b3f0de51SMilanka Ringwald 
451b3f0de51SMilanka Ringwald     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_CONFIGURE_NOTIFICATIONS;
452b3f0de51SMilanka Ringwald     scan_parameters_service_run_for_client(client);
453b3f0de51SMilanka Ringwald     return ERROR_CODE_SUCCESS;
454b3f0de51SMilanka Ringwald }
455b3f0de51SMilanka Ringwald 
45678ae886bSMilanka 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){
45778ae886bSMilanka Ringwald     btstack_assert(packet_handler != NULL);
45878ae886bSMilanka Ringwald 
45978ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_con_handle(con_handle);
46078ae886bSMilanka Ringwald     if (client != NULL){
46178ae886bSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
46278ae886bSMilanka Ringwald     }
46378ae886bSMilanka Ringwald 
46478ae886bSMilanka Ringwald     uint16_t cid = scan_parameters_service_get_next_cid();
46578ae886bSMilanka Ringwald     if (scan_parameters_service_cid != NULL) {
46678ae886bSMilanka Ringwald         *scan_parameters_service_cid = cid;
46778ae886bSMilanka Ringwald     }
46878ae886bSMilanka Ringwald 
46978ae886bSMilanka Ringwald     client = scan_parameters_service_create_client(con_handle, cid);
47078ae886bSMilanka Ringwald     if (client == NULL) {
47178ae886bSMilanka Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
47278ae886bSMilanka Ringwald     }
47378ae886bSMilanka Ringwald 
47478ae886bSMilanka Ringwald     client->client_handler = packet_handler;
47578ae886bSMilanka Ringwald     client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE;
47678ae886bSMilanka Ringwald     scan_parameters_service_run_for_client(client);
47778ae886bSMilanka Ringwald     return ERROR_CODE_SUCCESS;
47878ae886bSMilanka Ringwald }
47978ae886bSMilanka Ringwald 
48078ae886bSMilanka Ringwald uint8_t scan_parameters_service_client_disconnect(uint16_t scan_parameters_service_cid){
48178ae886bSMilanka Ringwald     scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_cid(scan_parameters_service_cid);
48278ae886bSMilanka Ringwald     if (client == NULL){
48378ae886bSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
48478ae886bSMilanka Ringwald     }
48578ae886bSMilanka Ringwald     // finalize connections
48678ae886bSMilanka Ringwald     scan_parameters_service_finalize_client(client);
48778ae886bSMilanka Ringwald     return ERROR_CODE_SUCCESS;
48878ae886bSMilanka Ringwald }
48978ae886bSMilanka Ringwald 
490*7aa5195fSMatthias Ringwald void scan_parameters_service_client_init(void){
491*7aa5195fSMatthias Ringwald     hci_event_callback_registration.callback = &handle_hci_event;
492*7aa5195fSMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
493*7aa5195fSMatthias Ringwald }
49478ae886bSMilanka Ringwald 
495*7aa5195fSMatthias Ringwald void scan_parameters_service_client_deinit(void){
496*7aa5195fSMatthias Ringwald }
49778ae886bSMilanka Ringwald 
498