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