xref: /btstack/test/mock/mock_gatt_client.c (revision 65e76442879710536c8282d7434f54986ceda717)
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <string.h>
4 
5 #include "btstack_debug.h"
6 #include "bluetooth_gatt.h"
7 #include "mock_gatt_client.h"
8 #include "hci_event_builder.h"
9 
10 //#include "CppUTest/TestHarness.h"
11 //#include "CppUTestExt/MockSupport.h"
12 
13 static enum {
14     MOCK_QUERY_IDLE = 0,
15     MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID,
16     MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID,
17     MOCK_QUERY_DISCOVER_ALL_CHARACTERISTICS,
18     MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS,
19     MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION,
20     MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE,
21     MOCK_READ_VALUE_OF_CHARACTERISTIC_DESCRIPTOR_USING_VALUE_HANDLE
22 } mock_gatt_client_state;
23 
24 static uint16_t mock_gatt_client_att_handle_generator;
25 
26 static uint8_t mock_gatt_client_att_error;
27 static uint8_t  mock_gatt_client_uuid128[16];
28 static uint16_t mock_gatt_client_value_handle;
29 static uint16_t mock_gatt_client_start_handle;
30 static uint16_t mock_gatt_client_end_handle;
31 
32 static gatt_client_t gatt_client;
33 
34 static btstack_linked_list_t mock_gatt_client_services;
35 
36 static mock_gatt_client_service_t * mock_gatt_client_last_service;
37 static mock_gatt_client_characteristic_t * mock_gatt_client_last_characteristic;
38 
39 static uint8_t moc_att_error_code_discover_services;
40 static uint8_t moc_att_error_code_discover_characteristics;
41 static uint8_t moc_att_error_code_discover_characteristic_descriptors;
42 static uint8_t moc_att_error_code_read_value_characteristics;
43 
44 static btstack_linked_list_t event_packet_handlers;
45 
46 void hci_add_event_handler(btstack_packet_callback_registration_t * callback_handler){
47     btstack_linked_list_add_tail(&event_packet_handlers, (btstack_linked_item_t*) callback_handler);
48 }
49 
50 void mock_hci_emit_event(uint8_t * packet, uint16_t size){
51     // dispatch to all event handlers
52     btstack_linked_list_iterator_t it;
53     btstack_linked_list_iterator_init(&it, &event_packet_handlers);
54     while (btstack_linked_list_iterator_has_next(&it)){
55         btstack_packet_callback_registration_t * entry = (btstack_packet_callback_registration_t*) btstack_linked_list_iterator_next(&it);
56         entry->callback(HCI_EVENT_PACKET, 0, packet, size);
57     }
58 }
59 
60 static void hci_create_gap_connection_complete_event(const uint8_t * hci_event, uint8_t * gap_event) {
61     gap_event[0] = HCI_EVENT_META_GAP;
62     gap_event[1] = 36 - 2;
63     gap_event[2] = GAP_SUBEVENT_LE_CONNECTION_COMPLETE;
64     switch (hci_event[2]){
65         case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
66             memcpy(&gap_event[3], &hci_event[3], 11);
67         memset(&gap_event[14], 0, 12);
68         memcpy(&gap_event[26], &hci_event[14], 7);
69         memset(&gap_event[33], 0xff, 3);
70         break;
71         case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE_V1:
72             memcpy(&gap_event[3], &hci_event[3], 30);
73         memset(&gap_event[33], 0xff, 3);
74         break;
75         case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE_V2:
76             memcpy(&gap_event[3], &hci_event[3], 33);
77         break;
78         default:
79             btstack_unreachable();
80         break;
81     }
82 }
83 
84 void mock_hci_emit_le_connection_complete(uint8_t address_type, const bd_addr_t address, hci_con_handle_t con_handle, uint8_t status){
85     uint8_t hci_event[21];
86     hci_event[0] = HCI_EVENT_LE_META;
87     hci_event[1] = sizeof(hci_event) - 2u;
88     hci_event[2] = HCI_SUBEVENT_LE_CONNECTION_COMPLETE;
89     hci_event[3] = status;
90     little_endian_store_16(hci_event, 4, con_handle);
91     hci_event[6] = 0; // TODO: role
92     hci_event[7] = address_type;
93     reverse_bd_addr(address, &hci_event[8]);
94     little_endian_store_16(hci_event, 14, 0); // interval
95     little_endian_store_16(hci_event, 16, 0); // latency
96     little_endian_store_16(hci_event, 18, 0); // supervision timeout
97     hci_event[20] = 0; // master clock accuracy
98     // emit GAP event, too
99     uint8_t gap_event[36];
100     hci_create_gap_connection_complete_event(hci_event, gap_event);
101     mock_hci_emit_event(gap_event, sizeof(gap_event));
102 }
103 
104 void mock_hci_emit_connection_encrypted(hci_con_handle_t con_handle, uint8_t encrypted){
105     uint8_t encryption_complete_event[6] = { HCI_EVENT_ENCRYPTION_CHANGE, 4, 0, 0, 0, 0};
106     little_endian_store_16(encryption_complete_event, 3, con_handle);
107     encryption_complete_event[5] = encrypted;
108     mock_hci_emit_event(encryption_complete_event, sizeof(encryption_complete_event));
109 }
110 
111 void mock_hci_emit_disconnection_complete(hci_con_handle_t con_handle, uint8_t reason){
112     uint8_t event[6];
113     event[0] = HCI_EVENT_DISCONNECTION_COMPLETE;
114     event[1] = sizeof(event) - 2u;
115     event[2] = 0; // status = OK
116     little_endian_store_16(event, 3, con_handle);
117     event[5] = reason;
118     mock_hci_emit_event(event, sizeof(event));
119 }
120 
121 
122 /**
123  * copied from gatt_client.c - START
124  */
125 void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t * service){
126     service->start_group_handle = little_endian_read_16(packet, offset);
127     service->end_group_handle = little_endian_read_16(packet, offset + 2);
128     reverse_128(&packet[offset + 4], service->uuid128);
129     if (uuid_has_bluetooth_prefix(service->uuid128)){
130         service->uuid16 = big_endian_read_32(service->uuid128, 0);
131     } else {
132         service->uuid16 = 0;
133     }
134 }
135 
136 void gatt_client_deserialize_characteristic(const uint8_t * packet, int offset, gatt_client_characteristic_t * characteristic){
137     characteristic->start_handle = little_endian_read_16(packet, offset);
138     characteristic->value_handle = little_endian_read_16(packet, offset + 2);
139     characteristic->end_handle = little_endian_read_16(packet, offset + 4);
140     characteristic->properties = little_endian_read_16(packet, offset + 6);
141     reverse_128(&packet[offset+8], characteristic->uuid128);
142     if (uuid_has_bluetooth_prefix(characteristic->uuid128)){
143         characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0);
144     } else {
145         characteristic->uuid16 = 0;
146     }
147 }
148 
149 void gatt_client_deserialize_characteristic_descriptor(const uint8_t * packet, int offset, gatt_client_characteristic_descriptor_t * descriptor){
150     descriptor->handle = little_endian_read_16(packet, offset);
151     reverse_128(&packet[offset+2], descriptor->uuid128);
152     if (uuid_has_bluetooth_prefix(descriptor->uuid128)){
153         descriptor->uuid16 = big_endian_read_32(descriptor->uuid128, 0);
154     } else {
155         descriptor->uuid16 = 0;
156     }
157 }
158 
159 static void emit_event_new(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){
160     if (!callback) return;
161     (*callback)(HCI_EVENT_PACKET, 0, packet, size);
162 }
163 
164 static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_status){
165     // @format H122
166     uint8_t packet[9];
167     hci_event_builder_context_t context;
168     hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_QUERY_COMPLETE, 0);
169     hci_event_builder_add_con_handle(&context, gatt_client->con_handle);
170     hci_event_builder_add_16(&context, gatt_client->service_id);
171     hci_event_builder_add_16(&context, gatt_client->connection_id);
172     hci_event_builder_add_08(&context, att_status);
173     emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context));
174 }
175 
176 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){
177     // @format H22X
178     uint8_t packet[28];
179     hci_event_builder_context_t context;
180     hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_SERVICE_QUERY_RESULT, 0);
181     hci_event_builder_add_con_handle(&context, gatt_client->con_handle);
182     hci_event_builder_add_16(&context, gatt_client->service_id);
183     hci_event_builder_add_16(&context, gatt_client->connection_id);
184     hci_event_builder_add_16(&context, start_group_handle);
185     hci_event_builder_add_16(&context, end_group_handle);
186     hci_event_builder_add_128(&context, uuid128);
187     emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context));
188 }
189 
190 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,
191                                                         uint16_t properties, const uint8_t * uuid128){
192     // @format H22Y
193     uint8_t packet[32];
194     hci_event_builder_context_t context;
195     hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_CHARACTERISTIC_QUERY_RESULT, 0);
196     hci_event_builder_add_con_handle(&context, gatt_client->con_handle);
197     hci_event_builder_add_16(&context, gatt_client->service_id);
198     hci_event_builder_add_16(&context, gatt_client->connection_id);
199     hci_event_builder_add_16(&context, start_handle);
200     hci_event_builder_add_16(&context, value_handle);
201     hci_event_builder_add_16(&context, end_handle);
202     hci_event_builder_add_16(&context, properties);
203     hci_event_builder_add_128(&context, uuid128);
204     emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context));
205 }
206 
207 static void emit_gatt_all_characteristic_descriptors_result_event(
208         gatt_client_t * gatt_client, uint16_t descriptor_handle, const uint8_t * uuid128){
209     // @format HZ
210     uint8_t packet[22];
211     hci_event_builder_context_t context;
212     hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT, 0);
213     hci_event_builder_add_con_handle(&context, gatt_client->con_handle);
214     hci_event_builder_add_16(&context, gatt_client->service_id);
215     hci_event_builder_add_16(&context, gatt_client->connection_id);
216     hci_event_builder_add_16(&context, descriptor_handle);
217     hci_event_builder_add_128(&context, uuid128);
218     emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context));
219 }
220 
221 static uint8_t event_packet[255];
222 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){
223     // before the value inside the ATT PDU
224     event_packet[0] = type;
225     event_packet[1] = 10 + length;
226     little_endian_store_16(event_packet, 2, con_handle);
227     little_endian_store_16(event_packet, 4, 0);
228     little_endian_store_16(event_packet, 6, 0);
229     little_endian_store_16(event_packet, 8, attribute_handle);
230     little_endian_store_16(event_packet, 10, length);
231     memcpy(&event_packet[12], value, length);
232     return &event_packet[0];
233 }
234 
235 void mock_gatt_client_send_notification_with_handle(mock_gatt_client_characteristic_t * characteristic, uint16_t value_handle, const uint8_t * value_buffer, uint16_t value_len){
236     btstack_assert(characteristic != NULL);
237     btstack_assert(characteristic->notification != NULL);
238     btstack_assert(characteristic->notification->callback != NULL);
239     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_NOTIFICATION, gatt_client.con_handle, value_handle, (uint8_t *) value_buffer, value_len);
240     emit_event_new(characteristic->notification->callback, packet, 2 + packet[1]);
241 }
242 
243 void mock_gatt_client_send_notification(mock_gatt_client_characteristic_t * characteristic, const uint8_t * value_buffer, uint16_t value_len){
244     mock_gatt_client_send_notification_with_handle(characteristic, characteristic->value_handle, value_buffer, value_len);
245 }
246 
247 void mock_gatt_client_send_indication_with_handle(mock_gatt_client_characteristic_t * characteristic, uint16_t value_handle, const uint8_t * value_buffer, uint16_t value_len){
248     btstack_assert(characteristic != NULL);
249     btstack_assert(characteristic->notification != NULL);
250     btstack_assert(characteristic->notification->callback != NULL);
251     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_INDICATION, gatt_client.con_handle, value_handle, (uint8_t *) value_buffer, value_len);
252     emit_event_new(characteristic->notification->callback, packet, 2 + packet[1]);
253 }
254 
255 void mock_gatt_client_send_indication(mock_gatt_client_characteristic_t * characteristic, const uint8_t * value_buffer, uint16_t value_len){
256     mock_gatt_client_send_indication_with_handle(characteristic, characteristic->value_handle, value_buffer, value_len);
257 }
258 
259 static void mock_gatt_client_send_characteristic_value(gatt_client_t * gatt_client, mock_gatt_client_characteristic_t * characteristic){
260     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT, gatt_client->con_handle, characteristic->value_handle, characteristic->value_buffer, characteristic->value_len);
261     emit_event_new(gatt_client->callback, packet, 2 + packet[1]);
262 }
263 
264 /**
265  * copied from gatt_client.c - END
266  */
267 
268 
269 static mock_gatt_client_characteristic_t * mock_gatt_client_get_characteristic_for_value_handle(uint16_t value_handle){
270     btstack_linked_list_iterator_t service_it;
271     btstack_linked_list_iterator_t characteristic_it;
272 
273     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
274     while (btstack_linked_list_iterator_has_next(&service_it)){
275         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
276 
277         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
278         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
279             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
280             if (characteristic->value_handle != value_handle) continue;
281             return characteristic;
282         }
283     }
284     return NULL;
285 }
286 
287 static mock_gatt_client_characteristic_t * mock_gatt_client_get_characteristic_for_uuid16(uint16_t uuid16){
288     btstack_linked_list_iterator_t service_it;
289     btstack_linked_list_iterator_t characteristic_it;
290 
291     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
292     while (btstack_linked_list_iterator_has_next(&service_it)){
293         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
294 
295         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
296         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
297             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
298             if (characteristic->uuid16 != uuid16) continue;
299             return characteristic;
300         }
301     }
302     return NULL;
303 }
304 
305 static mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_get_characteristic_descriptor_for_handle(uint16_t handle){
306     btstack_linked_list_iterator_t service_it;
307     btstack_linked_list_iterator_t characteristic_it;
308 
309     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
310     while (btstack_linked_list_iterator_has_next(&service_it)){
311         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
312 
313         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
314         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
315             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
316 
317             btstack_linked_list_iterator_t desc_it;
318             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
319             while (btstack_linked_list_iterator_has_next(&desc_it)){
320                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
321                 if (desc->handle != handle) continue;
322                 return desc;
323             }
324         }
325     }
326     return NULL;
327 }
328 
329 uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){
330     mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID;
331     uuid_add_bluetooth_prefix(mock_gatt_client_uuid128, uuid16);
332     gatt_client.callback = callback;
333     gatt_client.con_handle = con_handle;
334     return ERROR_CODE_SUCCESS;
335 }
336 
337 uint8_t gatt_client_discover_primary_services_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, const uint8_t * uuid128){
338     mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID;
339     memcpy(mock_gatt_client_uuid128, uuid128, 16);
340     gatt_client.callback = callback;
341     gatt_client.con_handle = con_handle;
342     return ERROR_CODE_SUCCESS;
343 }
344 
345 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){
346     mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID;
347     uuid_add_bluetooth_prefix(mock_gatt_client_uuid128, uuid16);
348     mock_gatt_client_start_handle = start_handle;
349     mock_gatt_client_end_handle = end_handle;
350 
351     gatt_client.callback = callback;
352     gatt_client.con_handle = con_handle;
353     return ERROR_CODE_SUCCESS;
354 }
355 
356 uint8_t gatt_client_discover_characteristics_for_service(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service){
357     mock_gatt_client_state = MOCK_QUERY_DISCOVER_ALL_CHARACTERISTICS;
358     mock_gatt_client_start_handle = service->start_group_handle;
359     mock_gatt_client_end_handle = service->end_group_handle;
360     gatt_client.callback = callback;
361     gatt_client.con_handle = con_handle;
362     return ERROR_CODE_SUCCESS;
363 }
364 
365 uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
366     mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS;
367     mock_gatt_client_value_handle = characteristic->value_handle;
368 
369     gatt_client.callback = callback;
370     gatt_client.con_handle = con_handle;
371     return ERROR_CODE_SUCCESS;
372 }
373 
374 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){
375     btstack_assert(notification != NULL);
376     btstack_assert(&callback != NULL);
377 
378     notification->callback = callback;
379     notification->con_handle = con_handle;
380 
381 
382     if (characteristic == NULL){
383         // 'all characteristics': not used yet
384         btstack_assert(false);
385     } else {
386         mock_gatt_client_characteristic_t * mock_characteristic  = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle);
387         btstack_assert(mock_characteristic != NULL);
388 
389         notification->attribute_handle = characteristic->value_handle;
390         mock_characteristic->notification = notification;
391     }
392 }
393 
394 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){
395     mock_gatt_client_characteristic_t * mock_characteristic  = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle);
396     btstack_assert(mock_characteristic != NULL);
397 
398     if (mock_characteristic->notification_status_code != ERROR_CODE_SUCCESS){
399         return mock_characteristic->notification_status_code;
400     }
401 
402     mock_gatt_client_state = MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
403 
404     gatt_client.callback = callback;
405     gatt_client.con_handle = con_handle;
406     return ERROR_CODE_SUCCESS;
407 }
408 
409 uint8_t gatt_client_read_value_of_characteristics_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
410     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
411 
412     mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_uuid16(uuid16);
413     if (mock_characteristic != NULL){
414         mock_gatt_client_value_handle = mock_characteristic->value_handle;
415         gatt_client.callback = callback;
416         gatt_client.con_handle = con_handle;
417     }
418     return ERROR_CODE_SUCCESS;
419 }
420 
421 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){
422     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
423 
424     mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(value_handle);
425     btstack_assert(mock_characteristic != NULL);
426 
427     mock_gatt_client_value_handle = mock_characteristic->value_handle;
428     gatt_client.callback = callback;
429     gatt_client.con_handle = con_handle;
430     return ERROR_CODE_SUCCESS;
431 }
432 
433 uint8_t gatt_client_read_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
434     btstack_assert(characteristic != NULL);
435     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
436 
437     mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle);
438     btstack_assert(mock_characteristic != NULL);
439 
440     gatt_client.callback = callback;
441     gatt_client.con_handle = con_handle;
442     mock_gatt_client_value_handle = mock_characteristic->value_handle;
443     return ERROR_CODE_SUCCESS;
444 }
445 
446 uint8_t gatt_client_read_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle){
447     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_DESCRIPTOR_USING_VALUE_HANDLE;
448     mock_gatt_client_value_handle = descriptor_handle;
449     return ERROR_CODE_SUCCESS;
450 }
451 
452 void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification){
453 }
454 
455 uint8_t gatt_client_request_to_send_gatt_query(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle){
456     // immediate callback, we don't have btstack runloop in most tests
457     (*callback_registration->callback)(callback_registration->context);
458     return ERROR_CODE_SUCCESS;
459 }
460 
461 uint8_t gatt_client_write_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
462     mock_gatt_client_characteristic_t * mock_characteristic  = mock_gatt_client_get_characteristic_for_value_handle(value_handle);
463     btstack_assert(mock_characteristic != NULL);
464 
465     if (mock_characteristic->notification_status_code != ERROR_CODE_SUCCESS){
466         return mock_characteristic->notification_status_code;
467     }
468 
469     mock_gatt_client_state = MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
470 
471     gatt_client.callback = callback;
472     gatt_client.con_handle = con_handle;
473     return ERROR_CODE_SUCCESS;
474 }
475 
476 void mock_gatt_client_emit_complete(uint8_t status){
477     mock_gatt_client_state = MOCK_QUERY_IDLE;
478     emit_gatt_complete_event(&gatt_client, status);
479 }
480 
481 void mock_gatt_client_run_once(void){
482     btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE);
483     mock_gatt_client_characteristic_t * characteristic;
484     mock_gatt_client_characteristic_descriptor_t * descriptor;
485 
486     btstack_linked_list_iterator_t service_it;
487     btstack_linked_list_iterator_t characteristic_it;
488     btstack_linked_list_iterator_t descriptor_it;
489 
490     switch (mock_gatt_client_state){
491         case MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID:
492             // emit GATT_EVENT_SERVICE_QUERY_RESULT for each matching service
493             if (moc_att_error_code_discover_services != ATT_ERROR_SUCCESS){
494                 mock_gatt_client_emit_complete(moc_att_error_code_discover_services);
495                 return;
496             }
497 
498             btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
499             while (btstack_linked_list_iterator_has_next(&service_it)){
500                 mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
501                 if (memcmp(service->uuid128, mock_gatt_client_uuid128, 16) != 0) continue;
502                 mock_gatt_client_last_service = service;
503                 emit_gatt_service_query_result_event(&gatt_client, service->start_group_handle, service->end_group_handle, service->uuid128);
504             }
505             // emit GATT_EVENT_QUERY_COMPLETE
506             mock_gatt_client_emit_complete(ATT_ERROR_SUCCESS);
507             break;
508 
509         case MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID:
510         case MOCK_QUERY_DISCOVER_ALL_CHARACTERISTICS:
511             // emit GATT_EVENT_CHARACTERISTIC_QUERY_RESULT for each matching characteristic
512             if (moc_att_error_code_discover_characteristics != ATT_ERROR_SUCCESS){
513                 mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristics);
514                 return;
515             }
516 
517             btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
518             while (btstack_linked_list_iterator_has_next(&service_it)){
519                 mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
520 
521                 btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
522                 while (btstack_linked_list_iterator_has_next(&characteristic_it)){
523                     mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
524                     if (characteristic->start_handle < mock_gatt_client_start_handle) continue;
525                     if (characteristic->end_handle > mock_gatt_client_end_handle) continue;
526                     if ((mock_gatt_client_state == MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID) && (memcmp(characteristic->uuid128, mock_gatt_client_uuid128, 16) != 0)) continue;
527 
528                     emit_gatt_characteristic_query_result_event(&gatt_client,
529                         characteristic->start_handle, characteristic->value_handle, characteristic->end_handle,
530                         characteristic->properties, characteristic->uuid128);
531                 }
532             }
533 
534             // emit GATT_EVENT_QUERY_COMPLETE
535             mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
536             break;
537 
538         case MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS:
539             characteristic = mock_gatt_client_get_characteristic_for_value_handle(mock_gatt_client_value_handle);
540             btstack_assert(characteristic != NULL);
541 
542             if (moc_att_error_code_discover_characteristic_descriptors != ATT_ERROR_SUCCESS){
543                 mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristic_descriptors);
544                 return;
545             }
546 
547             btstack_linked_list_iterator_init(&descriptor_it, &characteristic->descriptors);
548             while (btstack_linked_list_iterator_has_next(&descriptor_it)){
549                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&descriptor_it);
550 
551                 emit_gatt_all_characteristic_descriptors_result_event(&gatt_client, desc->handle, desc->uuid128);
552             }
553 
554             // emit GATT_EVENT_QUERY_COMPLETE
555             mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
556             break;
557 
558         case MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION:
559             mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
560             break;
561 
562         case MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE:
563             characteristic = mock_gatt_client_get_characteristic_for_value_handle(mock_gatt_client_value_handle);
564             if (moc_att_error_code_read_value_characteristics != ATT_ERROR_SUCCESS){
565                 mock_gatt_client_emit_complete(moc_att_error_code_read_value_characteristics);
566                 break;
567             }
568             if (characteristic != NULL){
569                 mock_gatt_client_send_characteristic_value(&gatt_client, characteristic);
570             }
571             mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
572             break;
573 
574         case MOCK_READ_VALUE_OF_CHARACTERISTIC_DESCRIPTOR_USING_VALUE_HANDLE:
575             descriptor = mock_gatt_client_get_characteristic_descriptor_for_handle(mock_gatt_client_value_handle);
576             btstack_assert(descriptor != NULL);
577             btstack_assert(descriptor->value_buffer != NULL);
578 
579             mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
580             break;
581 
582         default:
583             btstack_assert(false);
584             break;
585     }
586 }
587 
588 void mock_gatt_client_run(void){
589     btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE);
590     while (mock_gatt_client_state != MOCK_QUERY_IDLE){
591         mock_gatt_client_run_once();
592     }
593     mock_gatt_client_att_error = ERROR_CODE_SUCCESS;
594     mock_gatt_client_state = MOCK_QUERY_IDLE;
595 }
596 
597 void mock_gatt_client_emit_dummy_event(void){
598         // @format H1
599     uint8_t packet[2];
600     packet[0] = 0;
601     packet[1] = 0;
602     emit_event_new(gatt_client.callback, packet, sizeof(packet));
603 }
604 
605 static void mock_gatt_client_reset_errors(void){
606     moc_att_error_code_discover_services = ATT_ERROR_SUCCESS;
607     moc_att_error_code_discover_characteristics = ATT_ERROR_SUCCESS;
608     moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_SUCCESS;
609     moc_att_error_code_read_value_characteristics = ATT_ERROR_SUCCESS;
610 }
611 
612 void mock_gatt_client_reset(void){
613     mock_gatt_client_att_error = 0;
614     mock_gatt_client_state = MOCK_QUERY_IDLE;
615     mock_gatt_client_att_handle_generator = 0;
616     mock_gatt_client_last_service = NULL;
617 
618     mock_gatt_client_reset_errors();
619 
620     btstack_linked_list_iterator_t service_it;
621     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
622     while (btstack_linked_list_iterator_has_next(&service_it)){
623         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
624         btstack_linked_list_remove(&mock_gatt_client_services, (btstack_linked_item_t *) service);
625 
626         btstack_linked_list_iterator_t characteristic_it;
627         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
628         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
629             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
630             btstack_linked_list_remove(&service->characteristics, (btstack_linked_item_t *) characteristic);
631 
632             btstack_linked_list_iterator_t desc_it;
633             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
634             while (btstack_linked_list_iterator_has_next(&desc_it)){
635                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
636                 btstack_linked_list_remove(&characteristic->descriptors, (btstack_linked_item_t *) desc);
637                 free(desc);
638             }
639             free(characteristic);
640         }
641         free(service);
642     }
643 }
644 
645 void mock_gatt_client_set_att_error_discover_primary_services(void){
646     moc_att_error_code_discover_services = ATT_ERROR_REQUEST_NOT_SUPPORTED;
647 }
648 void mock_gatt_client_set_att_error_discover_characteristics(void){
649     moc_att_error_code_discover_characteristics = ATT_ERROR_REQUEST_NOT_SUPPORTED;
650 }
651 void mock_gatt_client_set_att_error_discover_characteristic_descriptors(void){
652     moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_REQUEST_NOT_SUPPORTED;
653 }
654 void mock_gatt_client_set_att_error_read_value_characteristics(void){
655     moc_att_error_code_read_value_characteristics = ATT_ERROR_REQUEST_NOT_SUPPORTED;
656 }
657 
658 void mock_gatt_client_enable_notification(mock_gatt_client_characteristic_t * characteristic, bool command_allowed){
659     if (command_allowed){
660         characteristic->notification_status_code = ERROR_CODE_SUCCESS;
661     } else {
662         characteristic->notification_status_code = ERROR_CODE_COMMAND_DISALLOWED;
663     }
664 }
665 
666 void mock_gatt_client_dump_services(void){
667     btstack_linked_list_iterator_t service_it;
668     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
669     while (btstack_linked_list_iterator_has_next(&service_it)){
670         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
671         printf("0x%02x: START SERVICE ", service->start_group_handle);
672         if (service->uuid16) {
673             printf("%04x\n", service->uuid16);
674         } else {
675             printf("%s\n", uuid128_to_str(service->uuid128));
676         }
677 
678         btstack_linked_list_iterator_t characteristic_it;
679         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
680         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
681             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
682             printf("0x%02x:   START CHR ", characteristic->start_handle);
683             if (characteristic->uuid16) {
684                 printf("%04x\n", characteristic->uuid16);
685             } else {
686                 printf("%s\n", uuid128_to_str(characteristic->uuid128));
687             }
688             printf("0x%02x:   VALUE HANDLE CHR\n", characteristic->value_handle);
689 
690             btstack_linked_list_iterator_t desc_it;
691             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
692             while (btstack_linked_list_iterator_has_next(&desc_it)){
693                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
694                 printf("0x%02x:     DESC 0x%02x\n", desc->handle, desc->uuid16);
695             }
696 
697             printf("0x%02x:   END CHR 0%02x\n", characteristic->end_handle, characteristic->uuid16);
698         }
699         printf("0x%02x: END SERVICE 0%02x\n", service->end_group_handle, service->uuid16);
700 
701     }
702 }
703 
704 static void mock_gatt_client_add_primary_service(void){
705     // set lsat group handle
706     // create new service
707     mock_gatt_client_last_service = (mock_gatt_client_service_t * )malloc(sizeof(mock_gatt_client_service_t));
708     memset(mock_gatt_client_last_service, 0, sizeof(mock_gatt_client_service_t));
709     mock_gatt_client_last_service->start_group_handle = mock_gatt_client_att_handle_generator++;
710     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_last_service->start_group_handle;
711     btstack_linked_list_add_tail(&mock_gatt_client_services, (btstack_linked_item_t*)mock_gatt_client_last_service);
712     mock_gatt_client_last_characteristic = NULL;
713 }
714 
715 mock_gatt_client_service_t * mock_gatt_client_add_primary_service_uuid16(uint16_t service_uuid){
716     mock_gatt_client_add_primary_service();
717     mock_gatt_client_last_service->uuid16 = service_uuid;
718     uuid_add_bluetooth_prefix(mock_gatt_client_last_service->uuid128, service_uuid);
719     return mock_gatt_client_last_service;
720 }
721 mock_gatt_client_service_t * mock_gatt_client_add_primary_service_uuid128(const uint8_t * service_uuid){
722     mock_gatt_client_add_primary_service();
723     (void) memcpy(mock_gatt_client_last_service->uuid128, service_uuid, 16);
724     return mock_gatt_client_last_service;
725 }
726 
727 static void mock_gatt_client_add_characteristic(uint16_t properties){
728     btstack_assert(mock_gatt_client_last_service != NULL);
729     mock_gatt_client_last_characteristic = (mock_gatt_client_characteristic_t * )malloc(sizeof(mock_gatt_client_characteristic_t));
730     memset(mock_gatt_client_last_characteristic, 0, sizeof(mock_gatt_client_characteristic_t));
731     mock_gatt_client_last_characteristic->properties = properties;
732     mock_gatt_client_last_characteristic->start_handle = mock_gatt_client_att_handle_generator++;
733     mock_gatt_client_last_characteristic->value_handle = mock_gatt_client_att_handle_generator++;
734     mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_last_characteristic->value_handle;
735     btstack_linked_list_add_tail(&mock_gatt_client_last_service->characteristics, (btstack_linked_item_t*)mock_gatt_client_last_characteristic);
736     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1;
737 }
738 
739 mock_gatt_client_characteristic_t * mock_gatt_client_add_characteristic_uuid16(uint16_t characteristic_uuid, uint16_t properties){
740     mock_gatt_client_add_characteristic(properties);
741     mock_gatt_client_last_characteristic->uuid16 = characteristic_uuid;
742     uuid_add_bluetooth_prefix(mock_gatt_client_last_characteristic->uuid128, characteristic_uuid);
743     return mock_gatt_client_last_characteristic;
744 }
745 
746 mock_gatt_client_characteristic_t * mock_gatt_client_add_characteristic_uuid128(const uint8_t * characteristic_uuid, uint16_t properties){
747     mock_gatt_client_add_characteristic(properties);
748     (void) memcpy(mock_gatt_client_last_characteristic->uuid128, characteristic_uuid, 16);
749     return mock_gatt_client_last_characteristic;
750 }
751 
752 static mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor(void){
753     btstack_assert(mock_gatt_client_last_characteristic != NULL);
754     mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t * )malloc(sizeof(mock_gatt_client_characteristic_descriptor_t));
755     memset(desc, 0, sizeof(mock_gatt_client_characteristic_descriptor_t));
756     desc->handle = mock_gatt_client_att_handle_generator++;
757     btstack_linked_list_add_tail(&mock_gatt_client_last_characteristic->descriptors, (btstack_linked_item_t*)desc);
758     mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_att_handle_generator - 1;
759     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1;
760     return desc;
761 }
762 
763 mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor_uuid16(uint16_t descriptor_uuid){
764     mock_gatt_client_characteristic_descriptor_t * desc = mock_gatt_client_add_characteristic_descriptor();
765     desc->uuid16 = descriptor_uuid;
766     uuid_add_bluetooth_prefix(desc->uuid128, descriptor_uuid);
767     return desc;
768 }
769 
770 mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor_uuid128(const uint8_t * descriptor_uuid){
771     mock_gatt_client_characteristic_descriptor_t * desc = mock_gatt_client_add_characteristic_descriptor();
772     (void) memcpy(desc->uuid128, descriptor_uuid, 16);
773     return desc;
774 }
775 
776 void mock_gatt_client_set_descriptor_characteristic_value(mock_gatt_client_characteristic_descriptor_t * descriptor, uint8_t * value_buffer, uint16_t value_len){
777     btstack_assert(descriptor != NULL);
778     descriptor->value_buffer = value_buffer;
779     descriptor->value_len = value_len;
780 }
781 
782 void mock_gatt_client_set_characteristic_value(mock_gatt_client_characteristic_t * characteristic, uint8_t * value_buffer, uint16_t value_len){
783     btstack_assert(characteristic != NULL);
784     characteristic->value_buffer = value_buffer;
785     characteristic->value_len = value_len;
786 }
787 
788 // simulate error
789 void mock_gatt_client_simulate_att_error(uint8_t att_error){
790     mock_gatt_client_att_error = att_error;
791 }
792