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