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 BLUEKITCHEN
24 * GMBH 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
88 static btstack_context_callback_registration_t device_information_service_handle_can_send_now;
89
90 static device_information_service_client_t device_information_service_client;
91
92 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
93 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);
94 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);
95 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);
96 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);
97 static void device_information_service_emit_udi_for_medical_devices(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 const 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_string_value},
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_system_id},
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 {ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES, GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_UDI_FOR_MEDICAL_DEVICES, device_information_service_emit_udi_for_medical_devices}
116 };
117
device_informatiom_client_request_send_gatt_query(device_information_service_client_t * client)118 static uint8_t device_informatiom_client_request_send_gatt_query(device_information_service_client_t * client){
119 uint8_t status = gatt_client_request_to_send_gatt_query(&device_information_service_handle_can_send_now, client->con_handle);
120 if (status != ERROR_CODE_SUCCESS){
121 if (client->state >= DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE){
122 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE;
123 }
124
125 }
126 return status;
127 }
128
129 #ifdef ENABLE_TESTING_SUPPORT
130 static struct device_information_characteristic_handles{
131 uint16_t uuid;
132 uint16_t value_handle;
133 } device_information_characteristic_handles[] = {
134 {ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, 0},
135 {ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, 0},
136 {ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, 0},
137 {ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING, 0},
138 {ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING, 0},
139 {ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING, 0},
140 {ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID, 0},
141 {ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST, 0},
142 {ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID, 0},
143 {ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES, 0}
144 };
145
device_information_service_update_handle_for_uuid(uint16_t uuid,uint16_t value_handle)146 static void device_information_service_update_handle_for_uuid(uint16_t uuid, uint16_t value_handle){
147 uint8_t i;
148 for (i = 0; i < 9; i++){
149 if (device_information_characteristic_handles[i].uuid == uuid){
150 device_information_characteristic_handles[i].value_handle = value_handle;
151 return;
152 }
153 }
154 }
155 #endif
156
157
158 static const uint8_t num_information_fields = sizeof(device_information_characteristics)/sizeof(struct device_information_characteristic);
159
160 #ifdef ENABLE_TESTING_SUPPORT
device_information_characteristic_name(uint16_t uuid)161 static char * device_information_characteristic_name(uint16_t uuid){
162 switch (uuid){
163 case ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING:
164 return "MANUFACTURER_NAME_STRING";
165
166 case ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING:
167 return "MODEL_NUMBER_STRING";
168
169 case ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING:
170 return "SERIAL_NUMBER_STRING";
171
172 case ORG_BLUETOOTH_CHARACTERISTIC_HARDWARE_REVISION_STRING:
173 return "HARDWARE_REVISION_STRING";
174
175 case ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING:
176 return "FIRMWARE_REVISION_STRING";
177
178 case ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING:
179 return "SOFTWARE_REVISION_STRING";
180
181 case ORG_BLUETOOTH_CHARACTERISTIC_SYSTEM_ID:
182 return "SYSTEM_ID";
183
184 case ORG_BLUETOOTH_CHARACTERISTIC_IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST:
185 return "IEEE_11073_20601_REGULATORY_CERTIFICATION_DATA_LIST";
186
187 case ORG_BLUETOOTH_CHARACTERISTIC_PNP_ID:
188 return "PNP_ID";
189
190 case ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES:
191 return "ORG_BLUETOOTH_CHARACTERISTIC_UDI_FOR_MEDICAL_DEVICES";
192
193 default:
194 return "UKNOWN";
195 }
196 }
197 #endif
device_information_service_client_get_client(void)198 static device_information_service_client_t * device_information_service_client_get_client(void){
199 return &device_information_service_client;
200 }
201
device_information_service_get_client_for_con_handle(hci_con_handle_t con_handle)202 static device_information_service_client_t * device_information_service_get_client_for_con_handle(hci_con_handle_t con_handle){
203 if (device_information_service_client.con_handle == con_handle){
204 return &device_information_service_client;
205 }
206 return NULL;
207 }
208
device_information_service_finalize_client(device_information_service_client_t * client)209 static void device_information_service_finalize_client(device_information_service_client_t * client){
210 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE;
211 client->con_handle = HCI_CON_HANDLE_INVALID;
212 client->client_handler = NULL;
213 client->num_instances = 0;
214 client->start_handle = 0;
215 client->end_handle = 0;
216 }
217
device_information_service_emit_query_done_and_finalize_client(device_information_service_client_t * client,uint8_t status)218 static void device_information_service_emit_query_done_and_finalize_client(device_information_service_client_t * client, uint8_t status){
219 hci_con_handle_t con_handle = client->con_handle;
220 btstack_packet_handler_t callback = client->client_handler;
221
222 device_information_service_finalize_client(client);
223
224 uint8_t event[6];
225 int pos = 0;
226 event[pos++] = HCI_EVENT_GATTSERVICE_META;
227 event[pos++] = sizeof(event) - 2;
228 event[pos++] = GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE;
229 little_endian_store_16(event, pos, con_handle);
230 pos += 2;
231 event[pos++] = status;
232 (*callback)(HCI_EVENT_PACKET, 0, event, pos);
233 }
234
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)235 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){
236 uint8_t event[6 + DEVICE_INFORMATION_MAX_STRING_LEN + 1];
237 int pos = 0;
238
239 event[pos++] = HCI_EVENT_GATTSERVICE_META;
240 pos++;
241 event[pos++] = subevent;
242 little_endian_store_16(event, pos, client->con_handle);
243 pos += 2;
244 event[pos++] = att_status;
245
246 uint16_t bytes_to_copy = btstack_min(value_len, DEVICE_INFORMATION_MAX_STRING_LEN);
247 memcpy((char*)&event[pos], value, bytes_to_copy);
248 pos += bytes_to_copy;
249 event[pos++] = 0;
250
251 event[1] = pos - 2;
252 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
253 }
254
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)255 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){
256 if (value_len != 8) return;
257
258 uint8_t event[14];
259 uint16_t pos = 0;
260 event[pos++] = HCI_EVENT_GATTSERVICE_META;
261 event[pos++] = sizeof(event) - 2;
262 event[pos++] = subevent;
263 little_endian_store_16(event, pos, client->con_handle);
264 pos += 2;
265 event[pos++] = att_status;
266 memcpy(event+pos, value, 8);
267 pos += 8;
268
269 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
270 }
271
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)272 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){
273 if (value_len != 4) return;
274
275 uint8_t event[10];
276 int pos = 0;
277 event[pos++] = HCI_EVENT_GATTSERVICE_META;
278 event[pos++] = sizeof(event) - 2;
279 event[pos++] = subevent;
280 little_endian_store_16(event, pos, client->con_handle);
281 pos += 2;
282 event[pos++] = att_status;
283 memcpy(event + pos, value, 4);
284 pos += 4;
285
286 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
287 }
288
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)289 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){
290 if (value_len != 7) return;
291
292 uint8_t event[13];
293 uint16_t pos = 0;
294 event[pos++] = HCI_EVENT_GATTSERVICE_META;
295 event[pos++] = sizeof(event) - 2;
296 event[pos++] = subevent;
297 little_endian_store_16(event, pos, client->con_handle);
298 pos += 2;
299 event[pos++] = att_status;
300 memcpy(event + pos, value, 7);
301 pos += 7;
302
303 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
304 }
305
device_information_service_emit_udi_for_medical_devices(device_information_service_client_t * client,uint8_t subevent,uint8_t att_status,const uint8_t * value,uint16_t value_len)306 static void device_information_service_emit_udi_for_medical_devices(device_information_service_client_t * client, uint8_t subevent, uint8_t att_status, const uint8_t * value, uint16_t value_len){
307 uint16_t max_udi_length = 1 + 4 * DEVICE_INFORMATION_MAX_STRING_LEN;
308
309 if (value_len > max_udi_length) return;
310
311 uint8_t event[6 + 1 + 4 * DEVICE_INFORMATION_MAX_STRING_LEN];
312 uint16_t pos = 0;
313 event[pos++] = HCI_EVENT_GATTSERVICE_META;
314 event[pos++] = sizeof(event) - 2;
315 event[pos++] = subevent;
316 little_endian_store_16(event, pos, client->con_handle);
317 pos += 2;
318 event[pos++] = att_status;
319 memcpy(event + pos, value, value_len);
320 pos += value_len;
321
322 (*client->client_handler)(HCI_EVENT_PACKET, 0, event, pos);
323 }
324
325
device_information_service_send_next_query(void * context)326 static void device_information_service_send_next_query(void * context){
327 UNUSED(context);
328 device_information_service_client_t * client = device_information_service_client_get_client();
329
330 if (client == NULL){
331 return;
332 }
333
334 uint8_t att_status;
335
336 switch (client->state){
337 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE:
338 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT;
339 att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_DEVICE_INFORMATION);
340 // TODO handle status
341 UNUSED(att_status);
342 break;
343 #ifdef ENABLE_TESTING_SUPPORT
344 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS:
345 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
346 gatt_client_discover_characteristics_for_handle_range_by_uuid16(
347 &handle_gatt_client_event,
348 client->con_handle, client->start_handle, client->end_handle,
349 device_information_characteristics[client->characteristic_index].uuid);
350 break;
351 #endif
352
353 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC:
354 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE;
355
356 #ifdef ENABLE_TESTING_SUPPORT
357 att_status = gatt_client_read_value_of_characteristic_using_value_handle(
358 handle_gatt_client_event,
359 client->con_handle,
360 device_information_characteristic_handles[client->characteristic_index].value_handle);
361 #else
362 att_status = gatt_client_read_value_of_characteristics_by_uuid16(
363 handle_gatt_client_event,
364 client->con_handle, client->start_handle, client->end_handle,
365 device_information_characteristics[client->characteristic_index].uuid);
366 #endif
367 // TODO handle status
368 UNUSED(att_status);
369 break;
370
371 default:
372 break;
373 }
374 }
375
handle_gatt_client_event(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)376 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
377 UNUSED(packet_type);
378 UNUSED(channel);
379 UNUSED(size);
380
381 uint8_t att_status;
382 device_information_service_client_t * client = NULL;
383 gatt_client_service_t service;
384 bool trigger_next_query = false;
385 #ifdef ENABLE_TESTING_SUPPORT
386 gatt_client_characteristic_t characteristic;
387 #endif
388
389 switch(hci_event_packet_get_type(packet)){
390
391 case GATT_EVENT_SERVICE_QUERY_RESULT:
392 client = device_information_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
393 btstack_assert(client != NULL);
394
395 gatt_event_service_query_result_get_service(packet, &service);
396 client->start_handle = service.start_group_handle;
397 client->end_handle = service.end_group_handle;
398
399 client->characteristic_index = 0;
400 if (client->start_handle < client->end_handle){
401 client->num_instances++;
402 }
403 #ifdef ENABLE_TESTING_SUPPORT
404 printf("Device Information Service: start handle 0x%04X, end handle 0x%04X, num_instances %d\n", client->start_handle, client->end_handle, client->num_instances);
405 #endif
406 break;
407
408 #ifdef ENABLE_TESTING_SUPPORT
409 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
410 client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet));
411 btstack_assert(client != NULL);
412 gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
413
414 device_information_service_update_handle_for_uuid(characteristic.uuid16, characteristic.value_handle);
415 printf("Device Information Characteristic %s: \n Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X\n",
416 device_information_characteristic_name(characteristic.uuid16),
417 characteristic.start_handle,
418 characteristic.properties,
419 characteristic.value_handle, characteristic.uuid16);
420 break;
421 #endif
422 case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
423 client = device_information_service_get_client_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
424 btstack_assert(client != NULL);
425
426
427 (device_information_characteristics[client->characteristic_index].handle_value(
428 client, device_information_characteristics[client->characteristic_index].subevent,
429 ATT_ERROR_SUCCESS,
430 gatt_event_characteristic_value_query_result_get_value(packet),
431 gatt_event_characteristic_value_query_result_get_value_length(packet)));
432 break;
433
434 case GATT_EVENT_QUERY_COMPLETE:
435 client = device_information_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
436 btstack_assert(client != NULL);
437
438 att_status = gatt_event_query_complete_get_att_status(packet);
439 switch (client->state){
440 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT:
441 if (att_status != ATT_ERROR_SUCCESS){
442 device_information_service_emit_query_done_and_finalize_client(client, att_status);
443 return;
444 }
445
446 if (client->num_instances != 1){
447 device_information_service_emit_query_done_and_finalize_client(client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
448 return;
449 }
450 client->characteristic_index = 0;
451
452 #ifdef ENABLE_TESTING_SUPPORT
453 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS;
454 #else
455 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC;
456 #endif
457 trigger_next_query = true;
458 break;
459
460 #ifdef ENABLE_TESTING_SUPPORT
461 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
462 // check if there is another characteristic to query
463 if ((client->characteristic_index + 1) < num_information_fields){
464 client->characteristic_index++;
465 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS;
466 trigger_next_query = true;
467 break;
468 }
469 client->characteristic_index = 0;
470 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC;
471 trigger_next_query = true;
472 break;
473 #endif
474 case DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE:
475 // check if there is another characteristic to query
476 if ((client->characteristic_index + 1) < num_information_fields){
477 client->characteristic_index++;
478 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_READ_VALUE_OF_CHARACTERISTIC;
479 trigger_next_query = true;
480 break;
481 }
482 // we are done with quering all characteristics
483 device_information_service_emit_query_done_and_finalize_client(client, ERROR_CODE_SUCCESS);
484 return;
485
486 default:
487 break;
488 }
489 break;
490 default:
491 break;
492 }
493
494 if (trigger_next_query){
495 device_informatiom_client_request_send_gatt_query(client);
496 }
497 }
498
device_information_service_client_query(hci_con_handle_t con_handle,btstack_packet_handler_t packet_handler)499 uint8_t device_information_service_client_query(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler){
500 btstack_assert(packet_handler != NULL);
501 device_information_service_client_t * client = device_information_service_get_client_for_con_handle(con_handle);
502
503 if (client != NULL){
504 return ERROR_CODE_COMMAND_DISALLOWED;
505 }
506
507 client = device_information_service_client_get_client();
508
509 if (client->con_handle != HCI_CON_HANDLE_INVALID) {
510 return ERROR_CODE_COMMAND_DISALLOWED;
511 }
512
513 client->con_handle = con_handle;
514 client->client_handler = packet_handler;
515 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE;
516
517 device_informatiom_client_request_send_gatt_query(client);
518 return ERROR_CODE_SUCCESS;
519 }
520
521
device_information_service_client_init(void)522 void device_information_service_client_init(void){
523 device_information_service_client_t * client = device_information_service_client_get_client();
524 device_information_service_finalize_client(client);
525 device_information_service_handle_can_send_now.callback = &device_information_service_send_next_query;
526 }
527
device_information_service_client_deinit(void)528 void device_information_service_client_deinit(void){}
529
530 // unit test only
531 #if defined __cplusplus
532 extern "C"
533 #endif
534 void device_information_service_client_set_invalid_state(void);
device_information_service_client_set_invalid_state(void)535 void device_information_service_client_set_invalid_state(void){
536 device_information_service_client_t * client = device_information_service_client_get_client();
537 client->state = DEVICE_INFORMATION_SERVICE_CLIENT_STATE_IDLE;
538 }
539