xref: /btstack/test/mock/mock_gatt_client.c (revision 98f6d969a938c70e3dde105515d11fbd80f9f5db)
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <string.h>
4 
5 #include "btstack_debug.h"
6 #include "mock_gatt_client.h"
7 
8 #include "CppUTest/TestHarness.h"
9 #include "CppUTestExt/MockSupport.h"
10 
11 static enum {
12     MOCK_QUERY_IDLE = 0,
13     MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID16,
14     MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID16,
15     MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS,
16     MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION,
17     MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE
18 } mock_gatt_client_state;
19 
20 static uint16_t mock_gatt_client_att_handle_generator;
21 
22 static uint8_t mock_gatt_client_att_error;
23 static uint16_t mock_gatt_client_uuid;
24 static uint16_t mock_gatt_client_value_handle;
25 static uint16_t mock_gatt_client_start_handle;
26 static uint16_t mock_gatt_client_end_handle;
27 
28 static gatt_client_t gatt_client;
29 
30 static btstack_linked_list_t mock_gatt_client_services;
31 
32 static mock_gatt_client_service_t * mock_gatt_client_last_service;
33 static mock_gatt_client_characteristic_t * mock_gatt_client_last_characteristic;
34 
35 static uint8_t moc_att_error_code_discover_services;
36 static uint8_t moc_att_error_code_discover_characteristics;
37 static uint8_t moc_att_error_code_discover_characteristic_descriptors;
38 
39 static void mock_gatt_client_reset_att_errors(void){
40     moc_att_error_code_discover_services = ATT_ERROR_SUCCESS;
41     moc_att_error_code_discover_characteristics = ATT_ERROR_SUCCESS;
42     moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_SUCCESS;
43 }
44 
45 void mock_gatt_client_reset(void){
46     mock_gatt_client_att_error = 0;
47     mock_gatt_client_state = MOCK_QUERY_IDLE;
48     mock_gatt_client_att_handle_generator = 0;
49     mock_gatt_client_last_service = NULL;
50 
51     mock_gatt_client_reset_att_errors();
52 
53     btstack_linked_list_iterator_t service_it;
54     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
55     while (btstack_linked_list_iterator_has_next(&service_it)){
56         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
57         btstack_linked_list_remove(&mock_gatt_client_services, (btstack_linked_item_t *) service);
58 
59         btstack_linked_list_iterator_t characteristic_it;
60         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
61         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
62             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
63             btstack_linked_list_remove(&service->characteristics, (btstack_linked_item_t *) characteristic);
64 
65             btstack_linked_list_iterator_t desc_it;
66             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
67             while (btstack_linked_list_iterator_has_next(&desc_it)){
68                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
69                 btstack_linked_list_remove(&characteristic->descriptors, (btstack_linked_item_t *) desc);
70                 free(desc);
71             }
72             free(characteristic);
73         }
74         free(service);
75     }
76 }
77 
78 void mock_gatt_client_set_att_error_discover_primary_services(void){
79     moc_att_error_code_discover_services = ATT_ERROR_REQUEST_NOT_SUPPORTED;
80 }
81 void mock_gatt_client_set_att_error_discover_characteristics(void){
82     moc_att_error_code_discover_characteristics = ATT_ERROR_REQUEST_NOT_SUPPORTED;
83 }
84 void mock_gatt_client_set_att_error_discover_characteristic_descriptors(void){
85     moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_REQUEST_NOT_SUPPORTED;
86 }
87 
88 void mock_gatt_client_dump_services(void){
89     btstack_linked_list_iterator_t service_it;
90     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
91     while (btstack_linked_list_iterator_has_next(&service_it)){
92         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
93         printf("0x%02x: START SERVICE 0%02x\n", service->start_group_handle, service->uuid16);
94 
95         btstack_linked_list_iterator_t characteristic_it;
96         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
97         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
98             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
99             printf("0x%02x:   START CHR 0%02x\n", characteristic->start_handle, characteristic->uuid16);
100             printf("0x%02x:   VALUE HANDLE CHR 0%02x\n", characteristic->value_handle, characteristic->uuid16);
101 
102             btstack_linked_list_iterator_t desc_it;
103             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
104             while (btstack_linked_list_iterator_has_next(&desc_it)){
105                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
106                 printf("0x%02x:     DESC 0x%02x\n", desc->handle, desc->uuid16);
107             }
108 
109             printf("0x%02x:   END CHR 0%02x\n", characteristic->end_handle, characteristic->uuid16);
110 
111         }
112         printf("0x%02x: END SERVICE 0%02x\n", service->end_group_handle, service->uuid16);
113 
114     }
115 }
116 
117 mock_gatt_client_service_t * mock_gatt_client_add_primary_service_uuid16(uint16_t service_uuid){
118     // set lsat group handle
119     // create new service
120     mock_gatt_client_last_service = (mock_gatt_client_service_t * )malloc(sizeof(mock_gatt_client_service_t));
121     memset(mock_gatt_client_last_service, 0, sizeof(mock_gatt_client_service_t));
122     mock_gatt_client_last_service->uuid16 = service_uuid;
123     mock_gatt_client_last_service->start_group_handle = mock_gatt_client_att_handle_generator++;
124     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_last_service->start_group_handle;
125     btstack_linked_list_add_tail(&mock_gatt_client_services, (btstack_linked_item_t*)mock_gatt_client_last_service);
126     mock_gatt_client_last_characteristic = NULL;
127     return mock_gatt_client_last_service;
128 }
129 
130 mock_gatt_client_characteristic_t * mock_gatt_client_add_characteristic_uuid16(uint16_t characteristic_uuid, uint16_t properties){
131     btstack_assert(mock_gatt_client_last_service != NULL);
132     mock_gatt_client_last_characteristic = (mock_gatt_client_characteristic_t * )malloc(sizeof(mock_gatt_client_characteristic_t));
133     memset(mock_gatt_client_last_characteristic, 0, sizeof(mock_gatt_client_characteristic_t));
134     mock_gatt_client_last_characteristic->uuid16 = characteristic_uuid;
135     mock_gatt_client_last_characteristic->properties = properties;
136     mock_gatt_client_last_characteristic->start_handle = mock_gatt_client_att_handle_generator++;
137     mock_gatt_client_last_characteristic->value_handle = mock_gatt_client_att_handle_generator++;
138     mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_last_characteristic->value_handle;
139     btstack_linked_list_add_tail(&mock_gatt_client_last_service->characteristics, (btstack_linked_item_t*)mock_gatt_client_last_characteristic);
140     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1;
141     return mock_gatt_client_last_characteristic;
142 }
143 
144 mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor_uuid16(uint16_t descriptor_uuid){
145     btstack_assert(mock_gatt_client_last_characteristic != NULL);
146     mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t * )malloc(sizeof(mock_gatt_client_characteristic_descriptor_t));
147     memset(desc, 0, sizeof(mock_gatt_client_characteristic_descriptor_t));
148     desc->uuid16 = descriptor_uuid;
149     desc->handle = mock_gatt_client_att_handle_generator++;
150     btstack_linked_list_add_tail(&mock_gatt_client_last_characteristic->descriptors, (btstack_linked_item_t*)desc);
151     mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_att_handle_generator - 1;
152     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1;
153     return desc;
154 }
155 
156 static mock_gatt_client_characteristic_t * mock_gatt_client_get_characteristic_for_value_handle(uint16_t value_handle){
157     btstack_linked_list_iterator_t service_it;
158     btstack_linked_list_iterator_t characteristic_it;
159 
160     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
161     while (btstack_linked_list_iterator_has_next(&service_it)){
162         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
163 
164         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
165         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
166             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
167             if (characteristic->value_handle != value_handle) continue;
168             return characteristic;
169         }
170     }
171     return NULL;
172 }
173 
174 static mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_get_characteristic_descriptor_for_handle(uint16_t handle){
175     btstack_linked_list_iterator_t service_it;
176     btstack_linked_list_iterator_t characteristic_it;
177 
178     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
179     while (btstack_linked_list_iterator_has_next(&service_it)){
180         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
181 
182         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
183         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
184             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
185 
186             btstack_linked_list_iterator_t desc_it;
187             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
188             while (btstack_linked_list_iterator_has_next(&desc_it)){
189                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
190                 if (desc->handle != handle) continue;
191                 return desc;
192             }
193         }
194     }
195     return NULL;
196 }
197 
198 
199 void mock_gatt_client_set_characteristic_value(mock_gatt_client_characteristic_descriptor_t * descriptor, uint8_t * value_buffer, uint16_t value_len){
200     btstack_assert(descriptor != NULL);
201     descriptor->value_buffer = value_buffer;
202     descriptor->value_len = value_len;
203 }
204 
205 // simulate erro
206 void mock_gatt_client_simulate_att_error(uint8_t att_error){
207     mock_gatt_client_att_error = att_error;
208 }
209 
210 uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){
211     mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID16;
212     mock_gatt_client_uuid = uuid16;
213 
214     gatt_client.callback = callback;
215     gatt_client.con_handle = con_handle;
216     return ERROR_CODE_SUCCESS;
217 }
218 
219 uint8_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
220     mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID16;
221     mock_gatt_client_uuid = uuid16;
222     mock_gatt_client_start_handle = start_handle;
223     mock_gatt_client_end_handle = end_handle;
224 
225     gatt_client.callback = callback;
226     gatt_client.con_handle = con_handle;
227     return ERROR_CODE_SUCCESS;
228 }
229 
230 uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
231     mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS;
232     mock_gatt_client_value_handle = characteristic->value_handle;
233 
234     gatt_client.callback = callback;
235     gatt_client.con_handle = con_handle;
236     return ERROR_CODE_SUCCESS;
237 }
238 
239 uint8_t gatt_client_write_client_characteristic_configuration(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic, uint16_t configuration){
240     mock_gatt_client_state = MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
241     mock_gatt_client_uuid = characteristic->uuid16;
242 
243     gatt_client.callback = callback;
244     gatt_client.con_handle = con_handle;
245     return ERROR_CODE_SUCCESS;
246 }
247 
248 void gatt_client_listen_for_characteristic_value_updates(gatt_client_notification_t * notification, btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
249     notification->callback = callback;
250     notification->con_handle = con_handle;
251 
252     if (characteristic == NULL){
253         // 'all characteristics': not used yet
254         btstack_assert(false);
255     } else {
256         notification->attribute_handle = characteristic->value_handle;
257     }
258 
259     // finc our characteristic and set point to notification
260 }
261 
262 
263 uint8_t gatt_client_read_value_of_characteristic_using_value_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle){
264     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
265     mock_gatt_client_value_handle = value_handle;
266     return ERROR_CODE_SUCCESS;
267 }
268 
269 uint8_t gatt_client_read_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
270     btstack_assert(characteristic != NULL);
271     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
272     mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle);
273 
274     btstack_assert(mock_characteristic != NULL);
275 
276     mock_gatt_client_value_handle = mock_characteristic->value_handle;
277     return ERROR_CODE_SUCCESS;
278 }
279 
280 void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification){
281 }
282 
283 /**
284  * copied from gatt_client.c - START
285  */
286 void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t * service){
287     service->start_group_handle = little_endian_read_16(packet, offset);
288     service->end_group_handle = little_endian_read_16(packet, offset + 2);
289     reverse_128(&packet[offset + 4], service->uuid128);
290     if (uuid_has_bluetooth_prefix(service->uuid128)){
291         service->uuid16 = big_endian_read_32(service->uuid128, 0);
292     } else {
293         service->uuid16 = 0;
294     }
295 }
296 
297 void gatt_client_deserialize_characteristic(const uint8_t * packet, int offset, gatt_client_characteristic_t * characteristic){
298     characteristic->start_handle = little_endian_read_16(packet, offset);
299     characteristic->value_handle = little_endian_read_16(packet, offset + 2);
300     characteristic->end_handle = little_endian_read_16(packet, offset + 4);
301     characteristic->properties = little_endian_read_16(packet, offset + 6);
302     reverse_128(&packet[offset+8], characteristic->uuid128);
303     if (uuid_has_bluetooth_prefix(characteristic->uuid128)){
304         characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0);
305     } else {
306         characteristic->uuid16 = 0;
307     }
308 }
309 
310 void gatt_client_deserialize_characteristic_descriptor(const uint8_t * packet, int offset, gatt_client_characteristic_descriptor_t * descriptor){
311     descriptor->handle = little_endian_read_16(packet, offset);
312     reverse_128(&packet[offset+2], descriptor->uuid128);
313     if (uuid_has_bluetooth_prefix(descriptor->uuid128)){
314         descriptor->uuid16 = big_endian_read_32(descriptor->uuid128, 0);
315     } else {
316         descriptor->uuid16 = 0;
317     }
318 }
319 
320 static void emit_event_new(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){
321     if (!callback) return;
322     (*callback)(HCI_EVENT_PACKET, 0, packet, size);
323 }
324 
325 static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_status){
326     // @format H1
327     uint8_t packet[5];
328     packet[0] = GATT_EVENT_QUERY_COMPLETE;
329     packet[1] = 3;
330     little_endian_store_16(packet, 2, gatt_client->con_handle);
331     packet[4] = att_status;
332     emit_event_new(gatt_client->callback, packet, sizeof(packet));
333 }
334 
335 static void emit_gatt_service_query_result_event(gatt_client_t * gatt_client, uint16_t start_group_handle, uint16_t end_group_handle, const uint8_t * uuid128){
336     // @format HX
337     uint8_t packet[24];
338     packet[0] = GATT_EVENT_SERVICE_QUERY_RESULT;
339     packet[1] = sizeof(packet) - 2u;
340     little_endian_store_16(packet, 2, gatt_client->con_handle);
341     ///
342     little_endian_store_16(packet, 4, start_group_handle);
343     little_endian_store_16(packet, 6, end_group_handle);
344     reverse_128(uuid128, &packet[8]);
345     emit_event_new(gatt_client->callback, packet, sizeof(packet));
346 }
347 
348 static void emit_gatt_characteristic_query_result_event(gatt_client_t * gatt_client, uint16_t start_handle, uint16_t value_handle, uint16_t end_handle,
349                                                         uint16_t properties, const uint8_t * uuid128){
350     // @format HY
351     uint8_t packet[28];
352     packet[0] = GATT_EVENT_CHARACTERISTIC_QUERY_RESULT;
353     packet[1] = sizeof(packet) - 2u;
354     little_endian_store_16(packet, 2, gatt_client->con_handle);
355     ///
356     little_endian_store_16(packet, 4,  start_handle);
357     little_endian_store_16(packet, 6,  value_handle);
358     little_endian_store_16(packet, 8,  end_handle);
359     little_endian_store_16(packet, 10, properties);
360     reverse_128(uuid128, &packet[12]);
361     emit_event_new(gatt_client->callback, packet, sizeof(packet));
362 }
363 
364 static void emit_gatt_all_characteristic_descriptors_result_event(
365         gatt_client_t * gatt_client, uint16_t descriptor_handle, const uint8_t * uuid128){
366     // @format HZ
367     uint8_t packet[22];
368     packet[0] = GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT;
369     packet[1] = sizeof(packet) - 2u;
370     little_endian_store_16(packet, 2, gatt_client->con_handle);
371     ///
372     little_endian_store_16(packet, 4,  descriptor_handle);
373     reverse_128(uuid128, &packet[6]);
374     emit_event_new(gatt_client->callback, packet, sizeof(packet));
375 }
376 
377 
378 static const int characteristic_value_event_header_size = 8;
379 static uint8_t * setup_characteristic_value_packet(uint8_t type, hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t * value, uint16_t length){
380     // before the value inside the ATT PDU
381     uint8_t * packet = value - characteristic_value_event_header_size;
382     packet[0] = type;
383     packet[1] = characteristic_value_event_header_size - 2 + length;
384     little_endian_store_16(packet, 2, con_handle);
385     little_endian_store_16(packet, 4, attribute_handle);
386     little_endian_store_16(packet, 6, length);
387     return packet;
388 }
389 
390 // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
391 static void report_gatt_characteristic_value(gatt_client_t * gatt_client, uint16_t attribute_handle, uint8_t * value, uint16_t length){
392     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT, gatt_client->con_handle, attribute_handle, value, length);
393     emit_event_new(gatt_client->callback, packet, characteristic_value_event_header_size + length);
394 }
395 
396 /**
397  * copied from gatt_client.c - END
398  */
399 
400 static void mock_gatt_client_emit_complete(uint8_t status){
401     mock_gatt_client_state = MOCK_QUERY_IDLE;
402     emit_gatt_complete_event(&gatt_client, status);
403 }
404 
405 void mock_gatt_client_run(void){
406     btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE);
407     mock_gatt_client_characteristic_t * characteristic;
408     mock_gatt_client_characteristic_descriptor_t * descriptor;
409 
410     btstack_linked_list_iterator_t service_it;
411     btstack_linked_list_iterator_t characteristic_it;
412     btstack_linked_list_iterator_t descriptor_it;
413 
414     uint8_t uuid128[16];
415 
416     while (mock_gatt_client_state != MOCK_QUERY_IDLE){
417         switch (mock_gatt_client_state){
418             case MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID16:
419                 // emit GATT_EVENT_SERVICE_QUERY_RESULT for each matching service
420                 if (moc_att_error_code_discover_services != ATT_ERROR_SUCCESS){
421                     mock_gatt_client_emit_complete(moc_att_error_code_discover_services);
422                     return;
423                 }
424 
425                 btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
426                 while (btstack_linked_list_iterator_has_next(&service_it)){
427                     mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
428                     if (service->uuid16 != mock_gatt_client_uuid) continue;
429                     mock_gatt_client_last_service = service;
430                     uuid_add_bluetooth_prefix(uuid128, service->uuid16);
431                     emit_gatt_service_query_result_event(&gatt_client, service->start_group_handle, service->end_group_handle, uuid128);
432                 }
433                 // emit GATT_EVENT_QUERY_COMPLETE
434                 mock_gatt_client_emit_complete(ATT_ERROR_SUCCESS);
435                 break;
436 
437             case MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID16:
438                 // emit GATT_EVENT_CHARACTERISTIC_QUERY_RESULT for each matching characteristic
439                 if (moc_att_error_code_discover_characteristics != ATT_ERROR_SUCCESS){
440                     mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristics);
441                     return;
442                 }
443 
444                 btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
445                 while (btstack_linked_list_iterator_has_next(&service_it)){
446                     mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
447 
448                     btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
449                     while (btstack_linked_list_iterator_has_next(&characteristic_it)){
450                         mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
451                         if (characteristic->uuid16 != mock_gatt_client_uuid) continue;
452                         if (characteristic->start_handle < mock_gatt_client_start_handle) continue;
453                         if (characteristic->end_handle > mock_gatt_client_end_handle) continue;
454 
455                         uuid_add_bluetooth_prefix(uuid128, characteristic->uuid16);
456                         emit_gatt_characteristic_query_result_event(&gatt_client,
457                             characteristic->start_handle, characteristic->value_handle, characteristic->end_handle,
458                             characteristic->properties, uuid128);
459                     }
460                 }
461 
462                 // emit GATT_EVENT_QUERY_COMPLETE
463                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
464                 break;
465 
466             case MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS:
467                 characteristic = mock_gatt_client_get_characteristic_for_value_handle(mock_gatt_client_value_handle);
468                 btstack_assert(characteristic != NULL);
469 
470                 if (moc_att_error_code_discover_characteristic_descriptors != ATT_ERROR_SUCCESS){
471                     mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristic_descriptors);
472                     return;
473                 }
474 
475                 btstack_linked_list_iterator_init(&descriptor_it, &characteristic->descriptors);
476                 while (btstack_linked_list_iterator_has_next(&descriptor_it)){
477                     mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&descriptor_it);
478 
479                     uuid_add_bluetooth_prefix(uuid128, desc->uuid16);
480                     emit_gatt_all_characteristic_descriptors_result_event(&gatt_client, desc->handle, uuid128);
481                 }
482 
483                 // emit GATT_EVENT_QUERY_COMPLETE
484                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
485                 break;
486 
487             case MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION:
488                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
489                 break;
490 
491             case MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE:
492                 descriptor = mock_gatt_client_get_characteristic_descriptor_for_handle(mock_gatt_client_value_handle);
493                 btstack_assert(descriptor != NULL);
494                 btstack_assert(descriptor->value_buffer != NULL);
495 
496                 report_gatt_characteristic_value(&gatt_client, descriptor->handle, descriptor->value_buffer, descriptor->value_len);
497                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
498                 break;
499 
500             default:
501                 btstack_assert(false);
502                 break;
503         }
504     }
505     mock_gatt_client_att_error = ERROR_CODE_SUCCESS;
506     mock_gatt_client_state = MOCK_QUERY_IDLE;
507 }