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