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 DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT 70 } device_information_service_client_state_t; 71 72 typedef struct { 73 hci_con_handle_t con_handle; 74 device_information_service_client_state_t state; 75 btstack_packet_handler_t client_handler; 76 77 // service 78 uint16_t start_handle; 79 uint16_t end_handle; 80 uint8_t num_instances; 81 82 // index of next characteristic to query 83 uint8_t characteristic_index; 84 } device_information_service_client_t; 85 86 static device_information_service_client_t device_information_service_client; 87 88 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 89 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); 90 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); 91 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); 92 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); 93 94 // list of uuids and how they are reported as events 95 static struct device_information_characteristic { 96 uint16_t uuid; 97 uint8_t subevent; 98 void (*handle_value)(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len); 99 } device_information_characteristics[] = { 100 {ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MANUFACTURER_NAME, device_information_service_emit_string_value}, 101 {ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_MODEL_NUMBER, device_information_service_emit_string_value}, 102 {ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SERIAL_NUMBER, device_information_service_emit_string_value}, 103 {ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_HARDWARE_REVISION, device_information_service_emit_system_id}, 104 {ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_FIRMWARE_REVISION, device_information_service_emit_string_value}, 105 {ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SOFTWARE_REVISION, device_information_service_emit_string_value}, 106 107 {ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_SYSTEM_ID, device_information_service_emit_string_value}, 108 {ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_IEEE_REGULATORY_CERTIFICATION, device_information_service_emit_certification_data_list}, 109 {ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_PNP_ID, device_information_service_emit_pnp_id} 110 }; 111 112 static const uint8_t num_information_fields = sizeof(device_information_characteristics)/sizeof(struct device_information_characteristic); 113 114 static device_information_service_client_t * device_information_service_client_get_client(void){ 115 return &device_information_service_client; 116 } 117 118 static device_information_service_client_t * device_information_service_get_client_for_con_handle(hci_con_handle_t con_handle){ 119 if (device_information_service_client.con_handle == con_handle){ 120 return &device_information_service_client; 121 } 122 return NULL; 123 } 124 125 static void device_information_service_finalize_client(device_information_service_client_t * client){ 126 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE; 127 client->con_handle = HCI_CON_HANDLE_INVALID; 128 } 129 130 static void device_information_service_emit_query_done(device_information_service_client_t * client, uint8_t att_status){ 131 uint8_t event[6]; 132 int pos = 0; 133 event[pos++] = HCI_EVENT_GATTSERVICE_META; 134 event[pos++] = sizeof(event) - 2; 135 event[pos++] = GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE; 136 little_endian_store_16(event, pos, client->con_handle); 137 pos += 2; 138 event[pos++] = att_status; 139 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 140 } 141 142 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){ 143 uint8_t event[6 + DEVICE_INFORMATION_MAX_STRING_LEN + 1]; 144 int pos = 0; 145 146 event[pos++] = HCI_EVENT_GATTSERVICE_META; 147 pos++; 148 event[pos++] = subevent; 149 little_endian_store_16(event, pos, client->con_handle); 150 pos += 2; 151 event[pos++] = att_status; 152 153 uint16_t bytes_to_copy = btstack_min(value_len, DEVICE_INFORMATION_MAX_STRING_LEN); 154 memcpy((char*)&event[pos], value, bytes_to_copy); 155 pos += bytes_to_copy; 156 event[pos++] = 0; 157 158 event[2] = pos - 2; 159 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 160 } 161 162 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){ 163 if (value_len != 8) return; 164 165 uint8_t event[14]; 166 uint16_t pos = 0; 167 event[pos++] = HCI_EVENT_GATTSERVICE_META; 168 event[pos++] = sizeof(event) - 2; 169 event[pos++] = subevent; 170 little_endian_store_16(event, pos, client->con_handle); 171 pos += 2; 172 event[pos++] = att_status; 173 memcpy(event+pos, value, 8); 174 pos += 8; 175 176 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 177 } 178 179 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){ 180 if (value_len != 4) return; 181 182 uint8_t event[10]; 183 int pos = 0; 184 event[pos++] = HCI_EVENT_GATTSERVICE_META; 185 event[pos++] = sizeof(event) - 2; 186 event[pos++] = subevent; 187 little_endian_store_16(event, pos, client->con_handle); 188 pos += 2; 189 event[pos++] = att_status; 190 memcpy(event + pos, value, 4); 191 pos += 4; 192 193 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 194 } 195 196 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){ 197 if (value_len != 7) return; 198 199 uint8_t event[13]; 200 uint16_t pos = 0; 201 event[pos++] = HCI_EVENT_GATTSERVICE_META; 202 event[pos++] = sizeof(event) - 2; 203 event[pos++] = subevent; 204 little_endian_store_16(event, pos, client->con_handle); 205 pos += 2; 206 event[pos++] = att_status; 207 memcpy(event + pos, value, 7); 208 pos += 7; 209 210 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos); 211 } 212 213 214 static void device_information_service_run_for_client(device_information_service_client_t * client){ 215 uint8_t att_status; 216 217 switch (client->state){ 218 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE: 219 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT; 220 att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_DEVICE_INFORMATION); 221 // TODO handle status 222 UNUSED(att_status); 223 break; 224 225 case DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT: 226 if (client->characteristic_index < num_information_fields){ 227 att_status = gatt_client_read_value_of_characteristics_by_uuid16( 228 handle_gatt_client_event, 229 client->con_handle, client->start_handle, client->end_handle, 230 device_information_characteristics[client->characteristic_index].uuid); 231 // TODO handle status 232 UNUSED(att_status); 233 } 234 break; 235 236 default: 237 break; 238 } 239 } 240 241 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 242 UNUSED(packet_type); 243 UNUSED(channel); 244 UNUSED(size); 245 246 uint8_t att_status; 247 device_information_service_client_t * client; 248 gatt_client_service_t service; 249 250 switch(hci_event_packet_get_type(packet)){ 251 252 case GATT_EVENT_SERVICE_QUERY_RESULT: 253 client = device_information_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet)); 254 btstack_assert(client != NULL); 255 256 if (client->state != DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT) { 257 device_information_service_emit_query_done(client, GATT_CLIENT_IN_WRONG_STATE); 258 device_information_service_finalize_client(client); 259 break; 260 } 261 262 gatt_event_service_query_result_get_service(packet, &service); 263 client->start_handle = service.start_group_handle; 264 client->end_handle = service.end_group_handle; 265 #ifdef ENABLE_TESTING_SUPPORT 266 printf("Device Information Service: start handle 0x%04X, end handle 0x%04X\n", client->start_handle, client->end_handle); 267 #endif 268 client->num_instances++; 269 client->characteristic_index = 0; 270 break; 271 272 case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: 273 client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet)); 274 btstack_assert(client != NULL); 275 276 (device_information_characteristics[client->characteristic_index].handle_value( 277 client, device_information_characteristics[client->characteristic_index].subevent, 278 ATT_ERROR_SUCCESS, 279 gatt_event_characteristic_value_query_result_get_value(packet), 280 gatt_event_characteristic_value_query_result_get_value_length(packet))); 281 break; 282 283 case GATT_EVENT_QUERY_COMPLETE: 284 client = device_information_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet)); 285 btstack_assert(client != NULL); 286 287 att_status = gatt_event_query_complete_get_att_status(packet); 288 switch (client->state){ 289 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT: 290 if (att_status != ATT_ERROR_SUCCESS){ 291 device_information_service_emit_query_done(client, att_status); 292 device_information_service_finalize_client(client); 293 break; 294 } 295 296 if (client->num_instances != 1){ 297 device_information_service_emit_query_done(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 298 device_information_service_finalize_client(client); 299 break; 300 } 301 302 client->state = DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT; 303 device_information_service_run_for_client(client); 304 break; 305 306 case DEVICE_INFORMATION_CLIENT_STATE_W4_CHARACTERISTIC_RESULT: 307 if (att_status != ATT_ERROR_SUCCESS){ 308 (device_information_characteristics[client->characteristic_index].handle_value( 309 client, device_information_characteristics[client->characteristic_index].subevent, 310 att_status, 311 gatt_event_characteristic_value_query_result_get_value(packet), 312 gatt_event_characteristic_value_query_result_get_value_length(packet))); 313 } 314 315 // check if there is another characteristic to query 316 if (client->characteristic_index < num_information_fields){ 317 client->characteristic_index++; 318 device_information_service_run_for_client(client); 319 break; 320 } 321 // we are done with quering all characteristics 322 device_information_service_emit_query_done(client, ERROR_CODE_SUCCESS); 323 device_information_service_finalize_client(client); 324 break; 325 326 default: 327 break; 328 } 329 break; 330 default: 331 break; 332 } 333 334 } 335 336 uint8_t device_information_service_client_query(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler){ 337 btstack_assert(packet_handler != NULL); 338 device_information_service_client_t * client = device_information_service_client_get_client(); 339 340 if (client->state != DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE){ 341 return GATT_CLIENT_IN_WRONG_STATE; 342 } 343 344 client->con_handle = con_handle; 345 client->client_handler = packet_handler; 346 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE; 347 device_information_service_run_for_client(client); 348 return ERROR_CODE_SUCCESS; 349 } 350 351 352 void device_information_service_client_init(void){} 353 354 void device_information_service_client_deinit(void){} 355 356