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