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