1 /* 2 * Copyright (C) 2021 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "scan_parameters_service_client.c" 39 40 #include "btstack_config.h" 41 42 #include <stdint.h> 43 #include <string.h> 44 45 46 #include "scan_parameters_service_client.h" 47 48 #include "btstack_memory.h" 49 #include "ble/att_db.h" 50 #include "ble/core.h" 51 #include "ble/gatt_client.h" 52 #include "ble/sm.h" 53 #include "bluetooth_gatt.h" 54 #include "btstack_debug.h" 55 #include "btstack_event.h" 56 #include "btstack_run_loop.h" 57 #include "gap.h" 58 59 static btstack_linked_list_t clients; 60 static uint16_t scan_parameters_service_cid_counter = 0; 61 static uint16_t scan_parameters_service_scan_window = 0; 62 static uint16_t scan_parameters_service_scan_interval = 0; 63 64 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 65 66 static uint16_t scan_parameters_service_get_next_cid(void){ 67 if (scan_parameters_service_cid_counter == 0xffff) { 68 scan_parameters_service_cid_counter = 1; 69 } else { 70 scan_parameters_service_cid_counter++; 71 } 72 return scan_parameters_service_cid_counter; 73 } 74 75 static scan_parameters_service_client_t * scan_parameters_service_create_client(hci_con_handle_t con_handle, uint16_t cid){ 76 scan_parameters_service_client_t * client = btstack_memory_scan_parameters_service_client_get(); 77 if (!client){ 78 log_error("Not enough memory to create client"); 79 return NULL; 80 } 81 82 client->cid = cid; 83 client->con_handle = con_handle; 84 client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_IDLE; 85 86 client->start_handle = 0; 87 client->end_handle = 0; 88 89 client->scan_interval_window_value_handle = 0; 90 client->scan_interval_window_value_update = false; 91 btstack_linked_list_add(&clients, (btstack_linked_item_t *) client); 92 return client; 93 } 94 95 static void scan_parameters_service_finalize_client(scan_parameters_service_client_t * client){ 96 btstack_linked_list_remove(&clients, (btstack_linked_item_t *) client); 97 btstack_memory_scan_parameters_service_client_free(client); 98 } 99 100 static scan_parameters_service_client_t * scan_parameters_service_get_client_for_con_handle(hci_con_handle_t con_handle){ 101 btstack_linked_list_iterator_t it; 102 btstack_linked_list_iterator_init(&it, &clients); 103 while (btstack_linked_list_iterator_has_next(&it)){ 104 scan_parameters_service_client_t * client = (scan_parameters_service_client_t *)btstack_linked_list_iterator_next(&it); 105 if (client->con_handle != con_handle) continue; 106 return client; 107 } 108 return NULL; 109 } 110 111 static scan_parameters_service_client_t * scan_parameters_service_get_client_for_cid(uint16_t scann_parameters_service_cid){ 112 btstack_linked_list_iterator_t it; 113 btstack_linked_list_iterator_init(&it, &clients); 114 while (btstack_linked_list_iterator_has_next(&it)){ 115 scan_parameters_service_client_t * client = (scan_parameters_service_client_t *)btstack_linked_list_iterator_next(&it); 116 if (client->cid != scann_parameters_service_cid) continue; 117 return client; 118 } 119 return NULL; 120 } 121 122 static void scan_parameters_service_emit_connection_established(scan_parameters_service_client_t * client, uint8_t status){ 123 uint8_t event[6]; 124 int pos = 0; 125 event[pos++] = HCI_EVENT_GATTSERVICE_META; 126 event[pos++] = sizeof(event) - 2; 127 event[pos++] = GATTSERVICE_SUBEVENT_SCAN_PARAMETERS_SERVICE_CONNECTED; 128 little_endian_store_16(event, pos, client->cid); 129 pos += 2; 130 event[pos++] = status; 131 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 132 } 133 134 135 static void scan_parameters_service_run_for_client(scan_parameters_service_client_t * client){ 136 uint8_t att_status; 137 gatt_client_service_t service; 138 139 switch (client->state){ 140 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE: 141 client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT; 142 att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_SCAN_PARAMETERS); 143 // TODO handle status 144 UNUSED(att_status); 145 break; 146 147 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC: 148 client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT; 149 150 service.start_group_handle = client->start_handle; 151 service.end_group_handle = client->end_handle; 152 att_status = gatt_client_discover_characteristics_for_service_by_uuid16( 153 handle_gatt_client_event, client->con_handle, &service, ORG_BLUETOOTH_CHARACTERISTIC_SCAN_INTERVAL_WINDOW); 154 // TODO handle status 155 UNUSED(att_status); 156 break; 157 158 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED: 159 if (client->scan_interval_window_value_update){ 160 uint8_t value[4]; 161 little_endian_store_16(value, 0, scan_parameters_service_scan_interval); 162 little_endian_store_16(value, 2, scan_parameters_service_scan_window); 163 164 att_status = gatt_client_write_value_of_characteristic_without_response(client->con_handle, client->scan_interval_window_value_handle, 4, value); 165 client->scan_interval_window_value_update = false; 166 // TODO handle status 167 UNUSED(att_status); 168 } 169 break; 170 default: 171 break; 172 } 173 } 174 175 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 176 UNUSED(packet_type); 177 UNUSED(channel); 178 UNUSED(size); 179 180 scan_parameters_service_client_t * client = NULL; 181 gatt_client_service_t service; 182 gatt_client_characteristic_t characteristic; 183 uint8_t att_status; 184 185 switch(hci_event_packet_get_type(packet)){ 186 case GATT_EVENT_SERVICE_QUERY_RESULT: 187 client = scan_parameters_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet)); 188 btstack_assert(client != NULL); 189 190 if (client->state != SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT) { 191 scan_parameters_service_emit_connection_established(client, GATT_CLIENT_IN_WRONG_STATE); 192 scan_parameters_service_finalize_client(client); 193 break; 194 } 195 196 gatt_event_service_query_result_get_service(packet, &service); 197 client->start_handle = service.start_group_handle; 198 client->end_handle = service.end_group_handle; 199 break; 200 201 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 202 client = scan_parameters_service_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet)); 203 btstack_assert(client != NULL); 204 205 // found scan_interval_window_value_handle, check att_status 206 gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 207 client->scan_interval_window_value_handle = characteristic.value_handle; 208 break; 209 210 case GATT_EVENT_QUERY_COMPLETE: 211 client = scan_parameters_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet)); 212 btstack_assert(client != NULL); 213 214 att_status = gatt_event_query_complete_get_att_status(packet); 215 216 switch (client->state){ 217 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT: 218 if (att_status != ATT_ERROR_SUCCESS){ 219 scan_parameters_service_emit_connection_established(client, att_status); 220 scan_parameters_service_finalize_client(client); 221 break; 222 } 223 224 if (client->start_handle != 0){ 225 scan_parameters_service_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 226 scan_parameters_service_finalize_client(client); 227 break; 228 } 229 client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC; 230 break; 231 232 case SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT: 233 if (att_status != ATT_ERROR_SUCCESS){ 234 scan_parameters_service_emit_connection_established(client, att_status); 235 scan_parameters_service_finalize_client(client); 236 break; 237 } 238 239 if (client->scan_interval_window_value_handle == 0){ 240 scan_parameters_service_emit_connection_established(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 241 scan_parameters_service_finalize_client(client); 242 break; 243 } 244 client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_CONNECTED; 245 client->scan_interval_window_value_update = true; 246 break; 247 248 default: 249 break; 250 } 251 break; 252 default: 253 break; 254 } 255 256 if (client != NULL){ 257 scan_parameters_service_run_for_client(client); 258 } 259 } 260 261 void scan_parameters_service_client_set(uint16_t scan_interval, uint16_t scan_window){ 262 scan_parameters_service_scan_interval = scan_interval; 263 scan_parameters_service_scan_window = scan_window; 264 265 btstack_linked_list_iterator_t it; 266 btstack_linked_list_iterator_init(&it, &clients); 267 while (btstack_linked_list_iterator_has_next(&it)){ 268 scan_parameters_service_client_t * client = (scan_parameters_service_client_t*) btstack_linked_list_iterator_next(&it); 269 client->scan_interval_window_value_update = true; 270 scan_parameters_service_run_for_client(client); 271 } 272 } 273 274 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){ 275 btstack_assert(packet_handler != NULL); 276 277 scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_con_handle(con_handle); 278 if (client != NULL){ 279 return ERROR_CODE_COMMAND_DISALLOWED; 280 } 281 282 uint16_t cid = scan_parameters_service_get_next_cid(); 283 if (scan_parameters_service_cid != NULL) { 284 *scan_parameters_service_cid = cid; 285 } 286 287 client = scan_parameters_service_create_client(con_handle, cid); 288 if (client == NULL) { 289 return BTSTACK_MEMORY_ALLOC_FAILED; 290 } 291 292 client->client_handler = packet_handler; 293 client->state = SCAN_PARAMETERS_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE; 294 scan_parameters_service_run_for_client(client); 295 return ERROR_CODE_SUCCESS; 296 } 297 298 uint8_t scan_parameters_service_client_disconnect(uint16_t scan_parameters_service_cid){ 299 scan_parameters_service_client_t * client = scan_parameters_service_get_client_for_cid(scan_parameters_service_cid); 300 if (client == NULL){ 301 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 302 } 303 // finalize connections 304 scan_parameters_service_finalize_client(client); 305 return ERROR_CODE_SUCCESS; 306 } 307 308 void scan_parameters_service_client_init(void){} 309 310 void scan_parameters_service_client_deinit(void){} 311 312