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