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/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_system_id}, 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_string_value}, 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 } 192 193 static void device_information_service_emit_query_done(device_information_service_client_t * client, uint8_t att_status){ 194 uint8_t event[6]; 195 int pos = 0; 196 event[pos++] = HCI_EVENT_GATTSERVICE_META; 197 event[pos++] = sizeof(event) - 2; 198 event[pos++] = GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE; 199 little_endian_store_16(event, pos, client->con_handle); 200 pos += 2; 201 event[pos++] = att_status; 202 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 203 } 204 205 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){ 206 uint8_t event[6 + DEVICE_INFORMATION_MAX_STRING_LEN + 1]; 207 int pos = 0; 208 209 event[pos++] = HCI_EVENT_GATTSERVICE_META; 210 pos++; 211 event[pos++] = subevent; 212 little_endian_store_16(event, pos, client->con_handle); 213 pos += 2; 214 event[pos++] = att_status; 215 216 uint16_t bytes_to_copy = btstack_min(value_len, DEVICE_INFORMATION_MAX_STRING_LEN); 217 memcpy((char*)&event[pos], value, bytes_to_copy); 218 pos += bytes_to_copy; 219 event[pos++] = 0; 220 221 event[1] = pos - 2; 222 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 223 } 224 225 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){ 226 if (value_len != 8) return; 227 228 uint8_t event[14]; 229 uint16_t pos = 0; 230 event[pos++] = HCI_EVENT_GATTSERVICE_META; 231 event[pos++] = sizeof(event) - 2; 232 event[pos++] = subevent; 233 little_endian_store_16(event, pos, client->con_handle); 234 pos += 2; 235 event[pos++] = att_status; 236 memcpy(event+pos, value, 8); 237 pos += 8; 238 239 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 240 } 241 242 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){ 243 if (value_len != 4) return; 244 245 uint8_t event[10]; 246 int pos = 0; 247 event[pos++] = HCI_EVENT_GATTSERVICE_META; 248 event[pos++] = sizeof(event) - 2; 249 event[pos++] = subevent; 250 little_endian_store_16(event, pos, client->con_handle); 251 pos += 2; 252 event[pos++] = att_status; 253 memcpy(event + pos, value, 4); 254 pos += 4; 255 256 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 257 } 258 259 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){ 260 if (value_len != 7) return; 261 262 uint8_t event[13]; 263 uint16_t pos = 0; 264 event[pos++] = HCI_EVENT_GATTSERVICE_META; 265 event[pos++] = sizeof(event) - 2; 266 event[pos++] = subevent; 267 little_endian_store_16(event, pos, client->con_handle); 268 pos += 2; 269 event[pos++] = att_status; 270 memcpy(event + pos, value, 7); 271 pos += 7; 272 273 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 274 } 275 276 277 static void device_information_service_run_for_client(device_information_service_client_t * client){ 278 uint8_t att_status; 279 280 switch (client->state){ 281 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE: 282 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT; 283 att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_DEVICE_INFORMATION); 284 // TODO handle status 285 UNUSED(att_status); 286 break; 287 #ifdef ENABLE_TESTING_SUPPORT 288 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS: 289 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT; 290 gatt_client_discover_characteristics_for_handle_range_by_uuid16( 291 &handle_gatt_client_event, 292 client->con_handle, client->start_handle, client->end_handle, 293 device_information_characteristics[client->characteristic_index].uuid); 294 break; 295 #endif 296 297 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC: 298 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE; 299 300 #ifdef ENABLE_TESTING_SUPPORT 301 att_status = gatt_client_read_value_of_characteristic_using_value_handle( 302 handle_gatt_client_event, 303 client->con_handle, 304 device_information_characteristic_handles[client->characteristic_index].value_handle); 305 #else 306 att_status = gatt_client_read_value_of_characteristics_by_uuid16( 307 handle_gatt_client_event, 308 client->con_handle, client->start_handle, client->end_handle, 309 device_information_characteristics[client->characteristic_index].uuid); 310 #endif 311 // TODO handle status 312 UNUSED(att_status); 313 break; 314 315 default: 316 break; 317 } 318 } 319 320 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 321 UNUSED(packet_type); 322 UNUSED(channel); 323 UNUSED(size); 324 325 uint8_t att_status; 326 device_information_service_client_t * client = NULL; 327 gatt_client_service_t service; 328 329 #ifdef ENABLE_TESTING_SUPPORT 330 gatt_client_characteristic_t characteristic; 331 #endif 332 333 switch(hci_event_packet_get_type(packet)){ 334 335 case GATT_EVENT_SERVICE_QUERY_RESULT: 336 client = device_information_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet)); 337 btstack_assert(client != NULL); 338 339 if (client->state != DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT) { 340 device_information_service_emit_query_done(client, GATT_CLIENT_IN_WRONG_STATE); 341 device_information_service_finalize_client(client); 342 return; 343 } 344 345 gatt_event_service_query_result_get_service(packet, &service); 346 client->start_handle = service.start_group_handle; 347 client->end_handle = service.end_group_handle; 348 #ifdef ENABLE_TESTING_SUPPORT 349 printf("Device Information Service: start handle 0x%04X, end handle 0x%04X\n", client->start_handle, client->end_handle); 350 #endif 351 client->num_instances++; 352 client->characteristic_index = 0; 353 break; 354 355 #ifdef ENABLE_TESTING_SUPPORT 356 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 357 client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet)); 358 btstack_assert(client != NULL); 359 gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 360 361 device_information_service_update_handle_for_uuid(characteristic.uuid16, characteristic.value_handle); 362 printf("Device Information Characteristic %s: \n Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n", 363 device_information_characteristic_name(characteristic.uuid16), 364 characteristic.start_handle, 365 characteristic.properties, 366 characteristic.value_handle, characteristic.uuid16); 367 break; 368 #endif 369 case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: 370 client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet)); 371 btstack_assert(client != NULL); 372 373 374 (device_information_characteristics[client->characteristic_index].handle_value( 375 client, device_information_characteristics[client->characteristic_index].subevent, 376 ATT_ERROR_SUCCESS, 377 gatt_event_characteristic_value_query_result_get_value(packet), 378 gatt_event_characteristic_value_query_result_get_value_length(packet))); 379 break; 380 381 case GATT_EVENT_QUERY_COMPLETE: 382 client = device_information_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet)); 383 btstack_assert(client != NULL); 384 385 att_status = gatt_event_query_complete_get_att_status(packet); 386 switch (client->state){ 387 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT: 388 if (att_status != ATT_ERROR_SUCCESS){ 389 device_information_service_emit_query_done(client, att_status); 390 device_information_service_finalize_client(client); 391 return; 392 } 393 394 if (client->num_instances != 1){ 395 device_information_service_emit_query_done(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 396 device_information_service_finalize_client(client); 397 return; 398 } 399 client->characteristic_index = 0; 400 #ifdef ENABLE_TESTING_SUPPORT 401 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS; 402 #else 403 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC; 404 #endif 405 break; 406 407 #ifdef ENABLE_TESTING_SUPPORT 408 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT: 409 // check if there is another characteristic to query 410 if ((client->characteristic_index + 1) < num_information_fields){ 411 client->characteristic_index++; 412 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS; 413 break; 414 } 415 client->characteristic_index = 0; 416 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC; 417 break; 418 #endif 419 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE: 420 if (att_status != ATT_ERROR_SUCCESS){ 421 (device_information_characteristics[client->characteristic_index].handle_value( 422 client, device_information_characteristics[client->characteristic_index].subevent, 423 att_status, 424 gatt_event_characteristic_value_query_result_get_value(packet), 425 gatt_event_characteristic_value_query_result_get_value_length(packet))); 426 } 427 428 // check if there is another characteristic to query 429 if ((client->characteristic_index + 1) < num_information_fields){ 430 client->characteristic_index++; 431 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC; 432 break; 433 } 434 // we are done with quering all characteristics 435 device_information_service_emit_query_done(client, ERROR_CODE_SUCCESS); 436 device_information_service_finalize_client(client); 437 return; 438 439 default: 440 break; 441 } 442 break; 443 default: 444 break; 445 } 446 447 if (client != NULL){ 448 device_information_service_run_for_client(client); 449 } 450 451 } 452 453 uint8_t device_information_service_client_query(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler){ 454 btstack_assert(packet_handler != NULL); 455 device_information_service_client_t * client = device_information_service_client_get_client(); 456 457 if (client->state != DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE){ 458 return GATT_CLIENT_IN_WRONG_STATE; 459 } 460 461 client->con_handle = con_handle; 462 client->client_handler = packet_handler; 463 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE; 464 device_information_service_run_for_client(client); 465 return ERROR_CODE_SUCCESS; 466 } 467 468 469 void device_information_service_client_init(void){} 470 471 void device_information_service_client_deinit(void){} 472 473