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 BLUEKITCHEN 24 * GMBH 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__ "device_information_service_client.c" 39 40 #include "btstack_config.h" 41 42 #include <stdint.h> 43 #include <string.h> 44 45 #ifdef ENABLE_TESTING_SUPPORT 46 #include <stdio.h> 47 #endif 48 49 #include "ble/gatt-service/device_information_service_client.h" 50 51 #include "ble/core.h" 52 #include "ble/gatt_client.h" 53 #include "bluetooth_gatt.h" 54 #include "btstack_debug.h" 55 #include "btstack_event.h" 56 #include "gap.h" 57 58 #define DEVICE_INFORMATION_MAX_STRING_LEN 32 59 60 61 typedef enum { 62 DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE, 63 DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE, 64 DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT, 65 #ifdef ENABLE_TESTING_SUPPORT 66 DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS, 67 DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT, 68 #endif 69 DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC, 70 DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE 71 } device_information_service_client_state_t; 72 73 typedef struct { 74 hci_con_handle_t con_handle; 75 device_information_service_client_state_t state; 76 btstack_packet_handler_t client_handler; 77 78 // service 79 uint16_t start_handle; 80 uint16_t end_handle; 81 uint8_t num_instances; 82 83 // index of next characteristic to query 84 uint8_t characteristic_index; 85 } device_information_service_client_t; 86 87 88 static btstack_context_callback_registration_t device_information_service_handle_can_send_now; 89 90 static device_information_service_client_t device_information_service_client; 91 92 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 93 static void device_information_service_emit_string_value(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len); 94 static void device_information_service_emit_system_id(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len); 95 static void device_information_service_emit_certification_data_list(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len); 96 static void device_information_service_emit_pnp_id(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len); 97 static void device_information_service_emit_udi_for_medical_devices(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len); 98 99 // list of uuids and how they are reported as events 100 static const struct device_information_characteristic { 101 uint16_t uuid; 102 uint8_t subevent; 103 void (*handle_value)(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len); 104 } device_information_characteristics[] = { 105 {ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MANUFACTURER_NAME, device_information_service_emit_string_value}, 106 {ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MODEL_NUMBER, device_information_service_emit_string_value}, 107 {ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SERIAL_NUMBER, device_information_service_emit_string_value}, 108 {ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_HARDWARE_REVISION, device_information_service_emit_string_value}, 109 {ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_FIRMWARE_REVISION, device_information_service_emit_string_value}, 110 {ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SOFTWARE_REVISION, device_information_service_emit_string_value}, 111 112 {ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SYSTEM_ID, device_information_service_emit_system_id}, 113 {ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_IEEE_REGULATORY_CERTIFICATION, device_information_service_emit_certification_data_list}, 114 {ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_PNP_ID, device_information_service_emit_pnp_id}, 115 {ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_UDI_FOR_MEDICAL_DEVICES, device_information_service_emit_udi_for_medical_devices} 116 }; 117 118 static uint8_t device_informatiom_client_request_send_gatt_query(device_information_service_client_t * client){ 119 uint8_t status = gatt_client_request_to_send_gatt_query(&device_information_service_handle_can_send_now, client->con_handle); 120 if (status != ERROR_CODE_SUCCESS){ 121 if (client->state >= DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE){ 122 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE; 123 } 124 125 } 126 return status; 127 } 128 129 #ifdef ENABLE_TESTING_SUPPORT 130 static struct device_information_characteristic_handles{ 131 uint16_t uuid; 132 uint16_t value_handle; 133 } device_information_characteristic_handles[] = { 134 {ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, 0}, 135 {ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, 0}, 136 {ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, 0}, 137 {ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING, 0}, 138 {ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING, 0}, 139 {ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING, 0}, 140 {ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID, 0}, 141 {ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, 0}, 142 {ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID, 0}, 143 {ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES, 0} 144 }; 145 146 static void device_information_service_update_handle_for_uuid(uint16_t uuid, uint16_t value_handle){ 147 uint8_t i; 148 for (i = 0; i < 9; i++){ 149 if (device_information_characteristic_handles[i].uuid == uuid){ 150 device_information_characteristic_handles[i].value_handle = value_handle; 151 return; 152 } 153 } 154 } 155 #endif 156 157 158 static const uint8_t num_information_fields = sizeof(device_information_characteristics)/sizeof(struct device_information_characteristic); 159 160 #ifdef ENABLE_TESTING_SUPPORT 161 static char * device_information_characteristic_name(uint16_t uuid){ 162 switch (uuid){ 163 case ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING: 164 return "MANUFACTURER_NAME_STRING"; 165 166 case ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING: 167 return "MODEL_NUMBER_STRING"; 168 169 case ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING: 170 return "SERIAL_NUMBER_STRING"; 171 172 case ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING: 173 return "HARDWARE_REVISION_STRING"; 174 175 case ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING: 176 return "FIRMWARE_REVISION_STRING"; 177 178 case ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING: 179 return "SOFTWARE_REVISION_STRING"; 180 181 case ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID: 182 return "SYSTEM_ID"; 183 184 case ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST: 185 return "IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST"; 186 187 case ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID: 188 return "PNP_ID"; 189 190 case ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES: 191 return "ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES"; 192 193 default: 194 return "UKNOWN"; 195 } 196 } 197 #endif 198 static device_information_service_client_t * device_information_service_client_get_client(void){ 199 return &device_information_service_client; 200 } 201 202 static device_information_service_client_t * device_information_service_get_client_for_con_handle(hci_con_handle_t con_handle){ 203 if (device_information_service_client.con_handle == con_handle){ 204 return &device_information_service_client; 205 } 206 return NULL; 207 } 208 209 static void device_information_service_finalize_client(device_information_service_client_t * client){ 210 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE; 211 client->con_handle = HCI_CON_HANDLE_INVALID; 212 client->client_handler = NULL; 213 client->num_instances = 0; 214 client->start_handle = 0; 215 client->end_handle = 0; 216 } 217 218 static void device_information_service_emit_query_done_and_finalize_client(device_information_service_client_t * client, uint8_t status){ 219 hci_con_handle_t con_handle = client->con_handle; 220 btstack_packet_handler_t callback = client->client_handler; 221 222 device_information_service_finalize_client(client); 223 224 uint8_t event[6]; 225 int pos = 0; 226 event[pos++] = HCI_EVENT_GATTSERVICE_META; 227 event[pos++] = sizeof(event) - 2; 228 event[pos++] = GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE; 229 little_endian_store_16(event, pos, con_handle); 230 pos += 2; 231 event[pos++] = status; 232 (*callback)(HCI_EVENT_PACKET, 0, event, pos); 233 } 234 235 static void device_information_service_emit_string_value(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){ 236 uint8_t event[6 + DEVICE_INFORMATION_MAX_STRING_LEN + 1]; 237 int pos = 0; 238 239 event[pos++] = HCI_EVENT_GATTSERVICE_META; 240 pos++; 241 event[pos++] = subevent; 242 little_endian_store_16(event, pos, client->con_handle); 243 pos += 2; 244 event[pos++] = att_status; 245 246 uint16_t bytes_to_copy = btstack_min(value_len, DEVICE_INFORMATION_MAX_STRING_LEN); 247 memcpy((char*)&event[pos], value, bytes_to_copy); 248 pos += bytes_to_copy; 249 event[pos++] = 0; 250 251 event[1] = pos - 2; 252 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 253 } 254 255 static void device_information_service_emit_system_id(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){ 256 if (value_len != 8) return; 257 258 uint8_t event[14]; 259 uint16_t pos = 0; 260 event[pos++] = HCI_EVENT_GATTSERVICE_META; 261 event[pos++] = sizeof(event) - 2; 262 event[pos++] = subevent; 263 little_endian_store_16(event, pos, client->con_handle); 264 pos += 2; 265 event[pos++] = att_status; 266 memcpy(event+pos, value, 8); 267 pos += 8; 268 269 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 270 } 271 272 static void device_information_service_emit_certification_data_list(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){ 273 if (value_len != 4) return; 274 275 uint8_t event[10]; 276 int pos = 0; 277 event[pos++] = HCI_EVENT_GATTSERVICE_META; 278 event[pos++] = sizeof(event) - 2; 279 event[pos++] = subevent; 280 little_endian_store_16(event, pos, client->con_handle); 281 pos += 2; 282 event[pos++] = att_status; 283 memcpy(event + pos, value, 4); 284 pos += 4; 285 286 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 287 } 288 289 static void device_information_service_emit_pnp_id(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){ 290 if (value_len != 7) return; 291 292 uint8_t event[13]; 293 uint16_t pos = 0; 294 event[pos++] = HCI_EVENT_GATTSERVICE_META; 295 event[pos++] = sizeof(event) - 2; 296 event[pos++] = subevent; 297 little_endian_store_16(event, pos, client->con_handle); 298 pos += 2; 299 event[pos++] = att_status; 300 memcpy(event + pos, value, 7); 301 pos += 7; 302 303 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 304 } 305 306 static void device_information_service_emit_udi_for_medical_devices(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){ 307 uint16_t max_udi_length = 1 + 4 * DEVICE_INFORMATION_MAX_STRING_LEN; 308 309 if (value_len > max_udi_length) return; 310 311 uint8_t event[6 + 1 + 4 * DEVICE_INFORMATION_MAX_STRING_LEN]; 312 uint16_t pos = 0; 313 event[pos++] = HCI_EVENT_GATTSERVICE_META; 314 event[pos++] = sizeof(event) - 2; 315 event[pos++] = subevent; 316 little_endian_store_16(event, pos, client->con_handle); 317 pos += 2; 318 event[pos++] = att_status; 319 memcpy(event + pos, value, value_len); 320 pos += value_len; 321 322 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 323 } 324 325 326 static void device_information_service_send_next_query(void * context){ 327 UNUSED(context); 328 device_information_service_client_t * client = device_information_service_client_get_client(); 329 330 if (client == NULL){ 331 return; 332 } 333 334 uint8_t att_status; 335 336 switch (client->state){ 337 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE: 338 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT; 339 att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_DEVICE_INFORMATION); 340 // TODO handle status 341 UNUSED(att_status); 342 break; 343 #ifdef ENABLE_TESTING_SUPPORT 344 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS: 345 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT; 346 gatt_client_discover_characteristics_for_handle_range_by_uuid16( 347 &handle_gatt_client_event, 348 client->con_handle, client->start_handle, client->end_handle, 349 device_information_characteristics[client->characteristic_index].uuid); 350 break; 351 #endif 352 353 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC: 354 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE; 355 356 #ifdef ENABLE_TESTING_SUPPORT 357 att_status = gatt_client_read_value_of_characteristic_using_value_handle( 358 handle_gatt_client_event, 359 client->con_handle, 360 device_information_characteristic_handles[client->characteristic_index].value_handle); 361 #else 362 att_status = gatt_client_read_value_of_characteristics_by_uuid16( 363 handle_gatt_client_event, 364 client->con_handle, client->start_handle, client->end_handle, 365 device_information_characteristics[client->characteristic_index].uuid); 366 #endif 367 // TODO handle status 368 UNUSED(att_status); 369 break; 370 371 default: 372 break; 373 } 374 } 375 376 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 377 UNUSED(packet_type); 378 UNUSED(channel); 379 UNUSED(size); 380 381 uint8_t att_status; 382 device_information_service_client_t * client = NULL; 383 gatt_client_service_t service; 384 bool trigger_next_query = false; 385 #ifdef ENABLE_TESTING_SUPPORT 386 gatt_client_characteristic_t characteristic; 387 #endif 388 389 switch(hci_event_packet_get_type(packet)){ 390 391 case GATT_EVENT_SERVICE_QUERY_RESULT: 392 client = device_information_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet)); 393 btstack_assert(client != NULL); 394 395 gatt_event_service_query_result_get_service(packet, &service); 396 client->start_handle = service.start_group_handle; 397 client->end_handle = service.end_group_handle; 398 399 client->characteristic_index = 0; 400 if (client->start_handle < client->end_handle){ 401 client->num_instances++; 402 } 403 #ifdef ENABLE_TESTING_SUPPORT 404 printf("Device Information Service: start handle 0x%04X, end handle 0x%04X, num_instances %d\n", client->start_handle, client->end_handle, client->num_instances); 405 #endif 406 break; 407 408 #ifdef ENABLE_TESTING_SUPPORT 409 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 410 client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet)); 411 btstack_assert(client != NULL); 412 gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 413 414 device_information_service_update_handle_for_uuid(characteristic.uuid16, characteristic.value_handle); 415 printf("Device Information Characteristic %s: \n Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n", 416 device_information_characteristic_name(characteristic.uuid16), 417 characteristic.start_handle, 418 characteristic.properties, 419 characteristic.value_handle, characteristic.uuid16); 420 break; 421 #endif 422 case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: 423 client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet)); 424 btstack_assert(client != NULL); 425 426 427 (device_information_characteristics[client->characteristic_index].handle_value( 428 client, device_information_characteristics[client->characteristic_index].subevent, 429 ATT_ERROR_SUCCESS, 430 gatt_event_characteristic_value_query_result_get_value(packet), 431 gatt_event_characteristic_value_query_result_get_value_length(packet))); 432 break; 433 434 case GATT_EVENT_QUERY_COMPLETE: 435 client = device_information_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet)); 436 btstack_assert(client != NULL); 437 438 att_status = gatt_event_query_complete_get_att_status(packet); 439 switch (client->state){ 440 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT: 441 if (att_status != ATT_ERROR_SUCCESS){ 442 device_information_service_emit_query_done_and_finalize_client(client, att_status); 443 return; 444 } 445 446 if (client->num_instances != 1){ 447 device_information_service_emit_query_done_and_finalize_client(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 448 return; 449 } 450 client->characteristic_index = 0; 451 452 #ifdef ENABLE_TESTING_SUPPORT 453 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS; 454 #else 455 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC; 456 #endif 457 trigger_next_query = true; 458 break; 459 460 #ifdef ENABLE_TESTING_SUPPORT 461 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT: 462 // check if there is another characteristic to query 463 if ((client->characteristic_index + 1) < num_information_fields){ 464 client->characteristic_index++; 465 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS; 466 trigger_next_query = true; 467 break; 468 } 469 client->characteristic_index = 0; 470 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC; 471 trigger_next_query = true; 472 break; 473 #endif 474 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE: 475 // check if there is another characteristic to query 476 if ((client->characteristic_index + 1) < num_information_fields){ 477 client->characteristic_index++; 478 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC; 479 trigger_next_query = true; 480 break; 481 } 482 // we are done with quering all characteristics 483 device_information_service_emit_query_done_and_finalize_client(client, ERROR_CODE_SUCCESS); 484 return; 485 486 default: 487 break; 488 } 489 break; 490 default: 491 break; 492 } 493 494 if (trigger_next_query){ 495 device_informatiom_client_request_send_gatt_query(client); 496 } 497 } 498 499 uint8_t device_information_service_client_query(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler){ 500 btstack_assert(packet_handler != NULL); 501 device_information_service_client_t * client = device_information_service_get_client_for_con_handle(con_handle); 502 503 if (client != NULL){ 504 return ERROR_CODE_COMMAND_DISALLOWED; 505 } 506 507 client = device_information_service_client_get_client(); 508 509 if (client->con_handle != HCI_CON_HANDLE_INVALID) { 510 return ERROR_CODE_COMMAND_DISALLOWED; 511 } 512 513 client->con_handle = con_handle; 514 client->client_handler = packet_handler; 515 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE; 516 517 device_informatiom_client_request_send_gatt_query(client); 518 return ERROR_CODE_SUCCESS; 519 } 520 521 522 void device_information_service_client_init(void){ 523 device_information_service_client_t * client = device_information_service_client_get_client(); 524 device_information_service_finalize_client(client); 525 device_information_service_handle_can_send_now.callback = &device_information_service_send_next_query; 526 } 527 528 void device_information_service_client_deinit(void){} 529 530 // unit test only 531 #if defined __cplusplus 532 extern "C" 533 #endif 534 void device_information_service_client_set_invalid_state(void); 535 void device_information_service_client_set_invalid_state(void){ 536 device_information_service_client_t * client = device_information_service_client_get_client(); 537 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE; 538 } 539