xref: /btstack/test/mock/mock_gatt_client.c (revision 76cdba3e40653998428b9e590094c54620ca56b2)
10f7fd6c1SMilanka Ringwald #include <stdint.h>
20f7fd6c1SMilanka Ringwald #include <stdio.h>
30f7fd6c1SMilanka Ringwald #include <string.h>
40f7fd6c1SMilanka Ringwald 
5af770404SMilanka Ringwald #include "btstack_debug.h"
60f7fd6c1SMilanka Ringwald #include "mock_gatt_client.h"
70f7fd6c1SMilanka Ringwald 
80f7fd6c1SMilanka Ringwald #include "CppUTest/TestHarness.h"
90f7fd6c1SMilanka Ringwald #include "CppUTestExt/MockSupport.h"
100f7fd6c1SMilanka Ringwald 
11af770404SMilanka Ringwald static enum {
12af770404SMilanka Ringwald     MOCK_QUERY_IDLE = 0,
13af770404SMilanka Ringwald     MOCK_QUERY_DISCOVER_PRIMARY_SERVICES,
147da2c1baSMilanka Ringwald     MOCK_QUERY_DISCOVER_CHARACTERISTICS,
15*76cdba3eSMilanka Ringwald     MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS,
16*76cdba3eSMilanka Ringwald     MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION,
17*76cdba3eSMilanka Ringwald     MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE
18af770404SMilanka Ringwald } mock_gatt_client_state;
19af770404SMilanka Ringwald 
20*76cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_att_handle_generator;
21*76cdba3eSMilanka Ringwald 
22af770404SMilanka Ringwald static uint8_t mock_gatt_client_att_error;
23af770404SMilanka Ringwald static uint16_t mock_gatt_client_uuid;
24*76cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_value_handle;
25*76cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_start_handle;
26*76cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_end_handle;
27*76cdba3eSMilanka Ringwald 
28af770404SMilanka Ringwald static gatt_client_t gatt_client;
290f7fd6c1SMilanka Ringwald 
307da2c1baSMilanka Ringwald static btstack_linked_list_t mock_gatt_client_services;
317da2c1baSMilanka Ringwald 
327da2c1baSMilanka Ringwald static mock_gatt_client_service_t * mock_gatt_client_last_service;
337da2c1baSMilanka Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_last_characteristic;
347da2c1baSMilanka Ringwald 
350f7fd6c1SMilanka Ringwald void mock_gatt_client_reset(void){
36af770404SMilanka Ringwald     mock_gatt_client_att_error = 0;
37af770404SMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_IDLE;
38*76cdba3eSMilanka Ringwald     mock_gatt_client_att_handle_generator = 0;
39*76cdba3eSMilanka Ringwald     mock_gatt_client_last_service = NULL;
407da2c1baSMilanka Ringwald 
417da2c1baSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
427da2c1baSMilanka Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
437da2c1baSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
447da2c1baSMilanka Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
457da2c1baSMilanka Ringwald         btstack_linked_list_remove(&mock_gatt_client_services, (btstack_linked_item_t *) service);
467da2c1baSMilanka Ringwald 
477da2c1baSMilanka Ringwald         btstack_linked_list_iterator_t characteristic_it;
487da2c1baSMilanka Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
497da2c1baSMilanka Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
507da2c1baSMilanka Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
517da2c1baSMilanka Ringwald             btstack_linked_list_remove(&service->characteristics, (btstack_linked_item_t *) characteristic);
527da2c1baSMilanka Ringwald 
537da2c1baSMilanka Ringwald             btstack_linked_list_iterator_t desc_it;
547da2c1baSMilanka Ringwald             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
557da2c1baSMilanka Ringwald             while (btstack_linked_list_iterator_has_next(&desc_it)){
567da2c1baSMilanka Ringwald                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
577da2c1baSMilanka Ringwald                 btstack_linked_list_remove(&characteristic->descriptors, (btstack_linked_item_t *) desc);
587da2c1baSMilanka Ringwald                 free(desc);
597da2c1baSMilanka Ringwald             }
607da2c1baSMilanka Ringwald             free(characteristic);
617da2c1baSMilanka Ringwald         }
627da2c1baSMilanka Ringwald         free(service);
637da2c1baSMilanka Ringwald     }
640f7fd6c1SMilanka Ringwald }
65af770404SMilanka Ringwald 
66*76cdba3eSMilanka Ringwald void mock_gatt_client_dump_services(void){
67*76cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
68*76cdba3eSMilanka Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
69*76cdba3eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
70*76cdba3eSMilanka Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
71*76cdba3eSMilanka Ringwald         printf("0x%02x: START SERVICE 0%02x\n", service->start_group_handle, service->uuid16);
72*76cdba3eSMilanka Ringwald 
73*76cdba3eSMilanka Ringwald         btstack_linked_list_iterator_t characteristic_it;
74*76cdba3eSMilanka Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
75*76cdba3eSMilanka Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
76*76cdba3eSMilanka Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
77*76cdba3eSMilanka Ringwald             printf("0x%02x:   START CHR 0%02x\n", characteristic->start_handle, characteristic->uuid16);
78*76cdba3eSMilanka Ringwald             printf("0x%02x:   VALUE HANDLE CHR 0%02x\n", characteristic->value_handle, characteristic->uuid16);
79*76cdba3eSMilanka Ringwald 
80*76cdba3eSMilanka Ringwald             btstack_linked_list_iterator_t desc_it;
81*76cdba3eSMilanka Ringwald             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
82*76cdba3eSMilanka Ringwald             while (btstack_linked_list_iterator_has_next(&desc_it)){
83*76cdba3eSMilanka Ringwald                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
84*76cdba3eSMilanka Ringwald                 printf("0x%02x:     DESC 0x%02x\n", desc->handle, desc->uuid16);
85*76cdba3eSMilanka Ringwald             }
86*76cdba3eSMilanka Ringwald 
87*76cdba3eSMilanka Ringwald             printf("0x%02x:   END CHR 0%02x\n", characteristic->end_handle, characteristic->uuid16);
88*76cdba3eSMilanka Ringwald 
89*76cdba3eSMilanka Ringwald         }
90*76cdba3eSMilanka Ringwald         printf("0x%02x: END SERVICE 0%02x\n", service->end_group_handle, service->uuid16);
91*76cdba3eSMilanka Ringwald 
92*76cdba3eSMilanka Ringwald     }
93*76cdba3eSMilanka Ringwald }
94*76cdba3eSMilanka Ringwald 
95*76cdba3eSMilanka Ringwald mock_gatt_client_service_t * mock_gatt_client_add_primary_service_uuid16(uint16_t service_uuid){
96*76cdba3eSMilanka Ringwald     // set lsat group handle
97*76cdba3eSMilanka Ringwald     // create new service
987da2c1baSMilanka Ringwald     mock_gatt_client_last_service = (mock_gatt_client_service_t * )malloc(sizeof(mock_gatt_client_service_t));
997da2c1baSMilanka Ringwald     memset(mock_gatt_client_last_service, 0, sizeof(mock_gatt_client_service_t));
1007da2c1baSMilanka Ringwald     mock_gatt_client_last_service->uuid16 = service_uuid;
101*76cdba3eSMilanka Ringwald     mock_gatt_client_last_service->start_group_handle = mock_gatt_client_att_handle_generator++;
102*76cdba3eSMilanka Ringwald     mock_gatt_client_last_service->end_group_handle = 0xffff;
1037da2c1baSMilanka Ringwald     btstack_linked_list_add(&mock_gatt_client_services, (btstack_linked_item_t*)mock_gatt_client_last_service);
104*76cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic = NULL;
105*76cdba3eSMilanka Ringwald     return mock_gatt_client_last_service;
1060f7fd6c1SMilanka Ringwald }
107af770404SMilanka Ringwald 
108*76cdba3eSMilanka Ringwald mock_gatt_client_characteristic_t * mock_gatt_client_add_characteristic_uuid16(uint16_t characteristic_uuid, uint16_t properties){
1097da2c1baSMilanka Ringwald     btstack_assert(mock_gatt_client_last_service != NULL);
1107da2c1baSMilanka Ringwald     mock_gatt_client_last_characteristic = (mock_gatt_client_characteristic_t * )malloc(sizeof(mock_gatt_client_characteristic_t));
1117da2c1baSMilanka Ringwald     memset(mock_gatt_client_last_characteristic, 0, sizeof(mock_gatt_client_characteristic_t));
1127da2c1baSMilanka Ringwald     mock_gatt_client_last_characteristic->uuid16 = characteristic_uuid;
113*76cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic->properties = properties;
114*76cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic->start_handle = mock_gatt_client_att_handle_generator++;
115*76cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic->value_handle = mock_gatt_client_att_handle_generator++;
116*76cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_last_characteristic->value_handle;
1177da2c1baSMilanka Ringwald     btstack_linked_list_add(&mock_gatt_client_last_service->characteristics, (btstack_linked_item_t*)mock_gatt_client_last_characteristic);
118*76cdba3eSMilanka Ringwald     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1;
119*76cdba3eSMilanka Ringwald     return mock_gatt_client_last_characteristic;
1200f7fd6c1SMilanka Ringwald }
121af770404SMilanka Ringwald 
122*76cdba3eSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor_uuid16(uint16_t descriptor_uuid){
123*76cdba3eSMilanka Ringwald     btstack_assert(mock_gatt_client_last_characteristic != NULL);
1247da2c1baSMilanka Ringwald     mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t * )malloc(sizeof(mock_gatt_client_characteristic_descriptor_t));
1257da2c1baSMilanka Ringwald     memset(desc, 0, sizeof(mock_gatt_client_characteristic_descriptor_t));
1267da2c1baSMilanka Ringwald     desc->uuid16 = descriptor_uuid;
127*76cdba3eSMilanka Ringwald     desc->handle = mock_gatt_client_att_handle_generator++;
1287da2c1baSMilanka Ringwald     btstack_linked_list_add(&mock_gatt_client_last_characteristic->descriptors, (btstack_linked_item_t*)desc);
129*76cdba3eSMilanka Ringwald     mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_att_handle_generator - 1;
130*76cdba3eSMilanka Ringwald     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1;
131*76cdba3eSMilanka Ringwald     return desc;
1320f7fd6c1SMilanka Ringwald }
1330f7fd6c1SMilanka Ringwald 
134*76cdba3eSMilanka Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_get_characteristic_for_value_handle(uint16_t value_handle){
135*76cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
136*76cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t characteristic_it;
137*76cdba3eSMilanka Ringwald 
138*76cdba3eSMilanka Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
139*76cdba3eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
140*76cdba3eSMilanka Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
141*76cdba3eSMilanka Ringwald 
142*76cdba3eSMilanka Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
143*76cdba3eSMilanka Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
144*76cdba3eSMilanka Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
145*76cdba3eSMilanka Ringwald             if (characteristic->value_handle != value_handle) continue;
146*76cdba3eSMilanka Ringwald             return characteristic;
147*76cdba3eSMilanka Ringwald         }
148*76cdba3eSMilanka Ringwald     }
149*76cdba3eSMilanka Ringwald     return NULL;
150*76cdba3eSMilanka Ringwald }
151*76cdba3eSMilanka Ringwald 
152*76cdba3eSMilanka Ringwald static mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_get_characteristic_descriptor_for_handle(uint16_t handle){
153*76cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
154*76cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t characteristic_it;
155*76cdba3eSMilanka Ringwald 
156*76cdba3eSMilanka Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
157*76cdba3eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
158*76cdba3eSMilanka Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
159*76cdba3eSMilanka Ringwald 
160*76cdba3eSMilanka Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
161*76cdba3eSMilanka Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
162*76cdba3eSMilanka Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
163*76cdba3eSMilanka Ringwald 
164*76cdba3eSMilanka Ringwald             btstack_linked_list_iterator_t desc_it;
165*76cdba3eSMilanka Ringwald             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
166*76cdba3eSMilanka Ringwald             while (btstack_linked_list_iterator_has_next(&desc_it)){
167*76cdba3eSMilanka Ringwald                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
168*76cdba3eSMilanka Ringwald                 if (desc->handle != handle) continue;
169*76cdba3eSMilanka Ringwald                 return desc;
170*76cdba3eSMilanka Ringwald             }
171*76cdba3eSMilanka Ringwald         }
172*76cdba3eSMilanka Ringwald     }
173*76cdba3eSMilanka Ringwald     return NULL;
174*76cdba3eSMilanka Ringwald }
175*76cdba3eSMilanka Ringwald 
176*76cdba3eSMilanka Ringwald 
177*76cdba3eSMilanka Ringwald void mock_gatt_client_set_characteristic_value(mock_gatt_client_characteristic_descriptor_t * descriptor, uint8_t * value_buffer, uint16_t value_len){
178*76cdba3eSMilanka Ringwald     btstack_assert(descriptor != NULL);
179*76cdba3eSMilanka Ringwald     descriptor->value_buffer = value_buffer;
180*76cdba3eSMilanka Ringwald     descriptor->value_len = value_len;
181*76cdba3eSMilanka Ringwald }
1827da2c1baSMilanka Ringwald 
183af770404SMilanka Ringwald // simulate erro
184af770404SMilanka Ringwald void mock_gatt_client_simulate_att_error(uint8_t att_error){
185af770404SMilanka Ringwald     mock_gatt_client_att_error = att_error;
1860f7fd6c1SMilanka Ringwald }
1870f7fd6c1SMilanka Ringwald 
1880f7fd6c1SMilanka Ringwald uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){
189af770404SMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES;
190af770404SMilanka Ringwald     mock_gatt_client_uuid = uuid16;
191af770404SMilanka Ringwald 
192af770404SMilanka Ringwald     gatt_client.callback = callback;
193af770404SMilanka Ringwald     gatt_client.con_handle = con_handle;
1940f7fd6c1SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1950f7fd6c1SMilanka Ringwald }
1960f7fd6c1SMilanka Ringwald 
1970f7fd6c1SMilanka Ringwald 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){
1987da2c1baSMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTICS;
1997da2c1baSMilanka Ringwald     mock_gatt_client_uuid = uuid16;
200*76cdba3eSMilanka Ringwald     mock_gatt_client_start_handle = start_handle;
201*76cdba3eSMilanka Ringwald     mock_gatt_client_end_handle = end_handle;
2027da2c1baSMilanka Ringwald 
2037da2c1baSMilanka Ringwald     gatt_client.callback = callback;
2047da2c1baSMilanka Ringwald     gatt_client.con_handle = con_handle;
2050f7fd6c1SMilanka Ringwald     return ERROR_CODE_SUCCESS;
2060f7fd6c1SMilanka Ringwald }
2070f7fd6c1SMilanka Ringwald 
2080f7fd6c1SMilanka Ringwald uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
209*76cdba3eSMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS;
210*76cdba3eSMilanka Ringwald     mock_gatt_client_value_handle = characteristic->value_handle;
211*76cdba3eSMilanka Ringwald 
212*76cdba3eSMilanka Ringwald     gatt_client.callback = callback;
213*76cdba3eSMilanka Ringwald     gatt_client.con_handle = con_handle;
214*76cdba3eSMilanka Ringwald     return ERROR_CODE_SUCCESS;
215*76cdba3eSMilanka Ringwald }
216*76cdba3eSMilanka Ringwald 
217*76cdba3eSMilanka Ringwald 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){
218*76cdba3eSMilanka Ringwald     mock_gatt_client_state = MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
219*76cdba3eSMilanka Ringwald     mock_gatt_client_uuid = characteristic->uuid16;
220*76cdba3eSMilanka Ringwald 
221*76cdba3eSMilanka Ringwald     gatt_client.callback = callback;
222*76cdba3eSMilanka Ringwald     gatt_client.con_handle = con_handle;
223*76cdba3eSMilanka Ringwald     return ERROR_CODE_SUCCESS;
224*76cdba3eSMilanka Ringwald }
225*76cdba3eSMilanka Ringwald 
226*76cdba3eSMilanka Ringwald 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){
227*76cdba3eSMilanka Ringwald     notification->callback = callback;
228*76cdba3eSMilanka Ringwald     notification->con_handle = con_handle;
229*76cdba3eSMilanka Ringwald 
230*76cdba3eSMilanka Ringwald     if (characteristic == NULL){
231*76cdba3eSMilanka Ringwald         // 'all characteristics': not used yet
232af770404SMilanka Ringwald         btstack_assert(false);
233*76cdba3eSMilanka Ringwald     } else {
234*76cdba3eSMilanka Ringwald         notification->attribute_handle = characteristic->value_handle;
235*76cdba3eSMilanka Ringwald     }
236*76cdba3eSMilanka Ringwald 
237*76cdba3eSMilanka Ringwald     // finc our characteristic and set point to notification
238*76cdba3eSMilanka Ringwald }
239*76cdba3eSMilanka Ringwald 
240*76cdba3eSMilanka Ringwald 
241*76cdba3eSMilanka Ringwald 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){
242*76cdba3eSMilanka Ringwald     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
243*76cdba3eSMilanka Ringwald     mock_gatt_client_value_handle = value_handle;
244af770404SMilanka Ringwald     return ERROR_CODE_SUCCESS;
245af770404SMilanka Ringwald }
246af770404SMilanka Ringwald 
247af770404SMilanka Ringwald uint8_t gatt_client_read_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
248af770404SMilanka Ringwald     btstack_assert(false);
2490f7fd6c1SMilanka Ringwald     return ERROR_CODE_SUCCESS;
2500f7fd6c1SMilanka Ringwald }
2510f7fd6c1SMilanka Ringwald 
252af770404SMilanka Ringwald void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification){
253af770404SMilanka Ringwald     btstack_assert(false);
254af770404SMilanka Ringwald }
255af770404SMilanka Ringwald 
256af770404SMilanka Ringwald /**
257af770404SMilanka Ringwald  * copied from gatt_client.c - START
258af770404SMilanka Ringwald  */
2590f7fd6c1SMilanka Ringwald void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t * service){
2600f7fd6c1SMilanka Ringwald     service->start_group_handle = little_endian_read_16(packet, offset);
2610f7fd6c1SMilanka Ringwald     service->end_group_handle = little_endian_read_16(packet, offset + 2);
2620f7fd6c1SMilanka Ringwald     reverse_128(&packet[offset + 4], service->uuid128);
2630f7fd6c1SMilanka Ringwald     if (uuid_has_bluetooth_prefix(service->uuid128)){
2640f7fd6c1SMilanka Ringwald         service->uuid16 = big_endian_read_32(service->uuid128, 0);
2650f7fd6c1SMilanka Ringwald     } else {
2660f7fd6c1SMilanka Ringwald         service->uuid16 = 0;
2670f7fd6c1SMilanka Ringwald     }
2680f7fd6c1SMilanka Ringwald }
2690f7fd6c1SMilanka Ringwald 
2700f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic(const uint8_t * packet, int offset, gatt_client_characteristic_t * characteristic){
2710f7fd6c1SMilanka Ringwald     characteristic->start_handle = little_endian_read_16(packet, offset);
2720f7fd6c1SMilanka Ringwald     characteristic->value_handle = little_endian_read_16(packet, offset + 2);
2730f7fd6c1SMilanka Ringwald     characteristic->end_handle = little_endian_read_16(packet, offset + 4);
2740f7fd6c1SMilanka Ringwald     characteristic->properties = little_endian_read_16(packet, offset + 6);
2750f7fd6c1SMilanka Ringwald     reverse_128(&packet[offset+8], characteristic->uuid128);
2760f7fd6c1SMilanka Ringwald     if (uuid_has_bluetooth_prefix(characteristic->uuid128)){
2770f7fd6c1SMilanka Ringwald         characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0);
2780f7fd6c1SMilanka Ringwald     } else {
2790f7fd6c1SMilanka Ringwald         characteristic->uuid16 = 0;
2800f7fd6c1SMilanka Ringwald     }
2810f7fd6c1SMilanka Ringwald }
2820f7fd6c1SMilanka Ringwald 
2830f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic_descriptor(const uint8_t * packet, int offset, gatt_client_characteristic_descriptor_t * descriptor){
2840f7fd6c1SMilanka Ringwald     descriptor->handle = little_endian_read_16(packet, offset);
2850f7fd6c1SMilanka Ringwald     reverse_128(&packet[offset+2], descriptor->uuid128);
2860f7fd6c1SMilanka Ringwald     if (uuid_has_bluetooth_prefix(descriptor->uuid128)){
2870f7fd6c1SMilanka Ringwald         descriptor->uuid16 = big_endian_read_32(descriptor->uuid128, 0);
2880f7fd6c1SMilanka Ringwald     } else {
2890f7fd6c1SMilanka Ringwald         descriptor->uuid16 = 0;
2900f7fd6c1SMilanka Ringwald     }
2910f7fd6c1SMilanka Ringwald }
2920f7fd6c1SMilanka Ringwald 
293af770404SMilanka Ringwald static void emit_event_new(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){
294af770404SMilanka Ringwald     if (!callback) return;
295af770404SMilanka Ringwald     (*callback)(HCI_EVENT_PACKET, 0, packet, size);
2960f7fd6c1SMilanka Ringwald }
2970f7fd6c1SMilanka Ringwald 
298af770404SMilanka Ringwald static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_status){
299af770404SMilanka Ringwald     // @format H1
300af770404SMilanka Ringwald     uint8_t packet[5];
301af770404SMilanka Ringwald     packet[0] = GATT_EVENT_QUERY_COMPLETE;
302af770404SMilanka Ringwald     packet[1] = 3;
303af770404SMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
304af770404SMilanka Ringwald     packet[4] = att_status;
305af770404SMilanka Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
3060f7fd6c1SMilanka Ringwald }
3070f7fd6c1SMilanka Ringwald 
3087da2c1baSMilanka Ringwald 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){
3097da2c1baSMilanka Ringwald     // @format HX
3107da2c1baSMilanka Ringwald     uint8_t packet[24];
3117da2c1baSMilanka Ringwald     packet[0] = GATT_EVENT_SERVICE_QUERY_RESULT;
3127da2c1baSMilanka Ringwald     packet[1] = sizeof(packet) - 2u;
3137da2c1baSMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
3147da2c1baSMilanka Ringwald     ///
3157da2c1baSMilanka Ringwald     little_endian_store_16(packet, 4, start_group_handle);
3167da2c1baSMilanka Ringwald     little_endian_store_16(packet, 6, end_group_handle);
3177da2c1baSMilanka Ringwald     reverse_128(uuid128, &packet[8]);
3187da2c1baSMilanka Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
3197da2c1baSMilanka Ringwald }
3207da2c1baSMilanka Ringwald 
3217da2c1baSMilanka Ringwald 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,
3227da2c1baSMilanka Ringwald                                                         uint16_t properties, const uint8_t * uuid128){
3237da2c1baSMilanka Ringwald     // @format HY
3247da2c1baSMilanka Ringwald     uint8_t packet[28];
3257da2c1baSMilanka Ringwald     packet[0] = GATT_EVENT_CHARACTERISTIC_QUERY_RESULT;
3267da2c1baSMilanka Ringwald     packet[1] = sizeof(packet) - 2u;
3277da2c1baSMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
3287da2c1baSMilanka Ringwald     ///
3297da2c1baSMilanka Ringwald     little_endian_store_16(packet, 4,  start_handle);
3307da2c1baSMilanka Ringwald     little_endian_store_16(packet, 6,  value_handle);
3317da2c1baSMilanka Ringwald     little_endian_store_16(packet, 8,  end_handle);
3327da2c1baSMilanka Ringwald     little_endian_store_16(packet, 10, properties);
3337da2c1baSMilanka Ringwald     reverse_128(uuid128, &packet[12]);
3347da2c1baSMilanka Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
3357da2c1baSMilanka Ringwald }
3367da2c1baSMilanka Ringwald 
337*76cdba3eSMilanka Ringwald static void emit_gatt_all_characteristic_descriptors_result_event(
338*76cdba3eSMilanka Ringwald         gatt_client_t * gatt_client, uint16_t descriptor_handle, const uint8_t * uuid128){
339*76cdba3eSMilanka Ringwald     // @format HZ
340*76cdba3eSMilanka Ringwald     uint8_t packet[22];
341*76cdba3eSMilanka Ringwald     packet[0] = GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT;
342*76cdba3eSMilanka Ringwald     packet[1] = sizeof(packet) - 2u;
343*76cdba3eSMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
344*76cdba3eSMilanka Ringwald     ///
345*76cdba3eSMilanka Ringwald     little_endian_store_16(packet, 4,  descriptor_handle);
346*76cdba3eSMilanka Ringwald     reverse_128(uuid128, &packet[6]);
347*76cdba3eSMilanka Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
348*76cdba3eSMilanka Ringwald }
349*76cdba3eSMilanka Ringwald 
350*76cdba3eSMilanka Ringwald 
351*76cdba3eSMilanka Ringwald static const int characteristic_value_event_header_size = 8;
352*76cdba3eSMilanka Ringwald 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){
353*76cdba3eSMilanka Ringwald     // before the value inside the ATT PDU
354*76cdba3eSMilanka Ringwald     uint8_t * packet = value - characteristic_value_event_header_size;
355*76cdba3eSMilanka Ringwald     packet[0] = type;
356*76cdba3eSMilanka Ringwald     packet[1] = characteristic_value_event_header_size - 2 + length;
357*76cdba3eSMilanka Ringwald     little_endian_store_16(packet, 2, con_handle);
358*76cdba3eSMilanka Ringwald     little_endian_store_16(packet, 4, attribute_handle);
359*76cdba3eSMilanka Ringwald     little_endian_store_16(packet, 6, length);
360*76cdba3eSMilanka Ringwald     return packet;
361*76cdba3eSMilanka Ringwald }
362*76cdba3eSMilanka Ringwald 
363*76cdba3eSMilanka Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
364*76cdba3eSMilanka Ringwald static void report_gatt_characteristic_value(gatt_client_t * gatt_client, uint16_t attribute_handle, uint8_t * value, uint16_t length){
365*76cdba3eSMilanka Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT, gatt_client->con_handle, attribute_handle, value, length);
366*76cdba3eSMilanka Ringwald     emit_event_new(gatt_client->callback, packet, characteristic_value_event_header_size + length);
367*76cdba3eSMilanka Ringwald }
368*76cdba3eSMilanka Ringwald 
369af770404SMilanka Ringwald /**
370af770404SMilanka Ringwald  * copied from gatt_client.c - END
371af770404SMilanka Ringwald  */
3720f7fd6c1SMilanka Ringwald 
3737da2c1baSMilanka Ringwald static void mock_gatt_client_emit_complete(uint8_t status){
3747da2c1baSMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_IDLE;
3757da2c1baSMilanka Ringwald     emit_gatt_complete_event(&gatt_client, status);
3767da2c1baSMilanka Ringwald }
3770f7fd6c1SMilanka Ringwald 
378af770404SMilanka Ringwald void mock_gatt_client_run(void){
379af770404SMilanka Ringwald     btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE);
380*76cdba3eSMilanka Ringwald     mock_gatt_client_characteristic_t * characteristic;
381*76cdba3eSMilanka Ringwald     mock_gatt_client_characteristic_descriptor_t * descriptor;
382*76cdba3eSMilanka Ringwald 
3837da2c1baSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
3847da2c1baSMilanka Ringwald     btstack_linked_list_iterator_t characteristic_it;
385*76cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t descriptor_it;
386*76cdba3eSMilanka Ringwald 
3877da2c1baSMilanka Ringwald     uint8_t uuid128[16];
3887da2c1baSMilanka Ringwald 
3897da2c1baSMilanka Ringwald     while (mock_gatt_client_state != MOCK_QUERY_IDLE){
390af770404SMilanka Ringwald         switch (mock_gatt_client_state){
391af770404SMilanka Ringwald             case MOCK_QUERY_DISCOVER_PRIMARY_SERVICES:
392af770404SMilanka Ringwald                 // emit GATT_EVENT_SERVICE_QUERY_RESULT for each matching service
3937da2c1baSMilanka Ringwald                 btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
3947da2c1baSMilanka Ringwald                 while (btstack_linked_list_iterator_has_next(&service_it)){
3957da2c1baSMilanka Ringwald                     mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
3967da2c1baSMilanka Ringwald                     if (service->uuid16 != mock_gatt_client_uuid) continue;
3977da2c1baSMilanka Ringwald                     mock_gatt_client_last_service = service;
3987da2c1baSMilanka Ringwald                     uuid_add_bluetooth_prefix(uuid128, service->uuid16);
399*76cdba3eSMilanka Ringwald                     emit_gatt_service_query_result_event(&gatt_client, service->start_group_handle, service->end_group_handle, uuid128);
4007da2c1baSMilanka Ringwald                 }
4017da2c1baSMilanka Ringwald                 // emit GATT_EVENT_QUERY_COMPLETE
4027da2c1baSMilanka Ringwald                 mock_gatt_client_emit_complete(ATT_ERROR_SUCCESS);
4037da2c1baSMilanka Ringwald                 break;
4047da2c1baSMilanka Ringwald 
4057da2c1baSMilanka Ringwald             case MOCK_QUERY_DISCOVER_CHARACTERISTICS:
4067da2c1baSMilanka Ringwald                 // emit GATT_EVENT_CHARACTERISTIC_QUERY_RESULT for each matching characteristic
4077da2c1baSMilanka Ringwald                 btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
4087da2c1baSMilanka Ringwald                 while (btstack_linked_list_iterator_has_next(&service_it)){
4097da2c1baSMilanka Ringwald                     mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
4107da2c1baSMilanka Ringwald 
4117da2c1baSMilanka Ringwald                     btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
4127da2c1baSMilanka Ringwald                     while (btstack_linked_list_iterator_has_next(&characteristic_it)){
4137da2c1baSMilanka Ringwald                         mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
4147da2c1baSMilanka Ringwald                         if (characteristic->uuid16 != mock_gatt_client_uuid) continue;
415*76cdba3eSMilanka Ringwald                         if (characteristic->start_handle < mock_gatt_client_start_handle) continue;
416*76cdba3eSMilanka Ringwald                         if (characteristic->end_handle > mock_gatt_client_end_handle) continue;
417*76cdba3eSMilanka Ringwald 
4187da2c1baSMilanka Ringwald                         uuid_add_bluetooth_prefix(uuid128, characteristic->uuid16);
419*76cdba3eSMilanka Ringwald                         emit_gatt_characteristic_query_result_event(&gatt_client,
420*76cdba3eSMilanka Ringwald                             characteristic->start_handle, characteristic->value_handle, characteristic->end_handle,
421*76cdba3eSMilanka Ringwald                             characteristic->properties, uuid128);
4227da2c1baSMilanka Ringwald                     }
4237da2c1baSMilanka Ringwald                 }
4247da2c1baSMilanka Ringwald 
4257da2c1baSMilanka Ringwald                 // emit GATT_EVENT_QUERY_COMPLETE
4267da2c1baSMilanka Ringwald                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
427af770404SMilanka Ringwald                 break;
428*76cdba3eSMilanka Ringwald 
429*76cdba3eSMilanka Ringwald             case MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS:
430*76cdba3eSMilanka Ringwald                 characteristic = mock_gatt_client_get_characteristic_for_value_handle(mock_gatt_client_value_handle);
431*76cdba3eSMilanka Ringwald                 btstack_assert(characteristic != NULL);
432*76cdba3eSMilanka Ringwald 
433*76cdba3eSMilanka Ringwald                 btstack_linked_list_iterator_init(&descriptor_it, &characteristic->descriptors);
434*76cdba3eSMilanka Ringwald                 while (btstack_linked_list_iterator_has_next(&descriptor_it)){
435*76cdba3eSMilanka Ringwald                     mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&descriptor_it);
436*76cdba3eSMilanka Ringwald 
437*76cdba3eSMilanka Ringwald                     uuid_add_bluetooth_prefix(uuid128, desc->uuid16);
438*76cdba3eSMilanka Ringwald                     emit_gatt_all_characteristic_descriptors_result_event(&gatt_client, desc->handle, uuid128);
439*76cdba3eSMilanka Ringwald                 }
440*76cdba3eSMilanka Ringwald 
441*76cdba3eSMilanka Ringwald 
442*76cdba3eSMilanka Ringwald                 // emit GATT_EVENT_QUERY_COMPLETE
443*76cdba3eSMilanka Ringwald                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
444*76cdba3eSMilanka Ringwald                 break;
445*76cdba3eSMilanka Ringwald 
446*76cdba3eSMilanka Ringwald             case MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION:
447*76cdba3eSMilanka Ringwald                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
448*76cdba3eSMilanka Ringwald                 break;
449*76cdba3eSMilanka Ringwald 
450*76cdba3eSMilanka Ringwald             case MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE:
451*76cdba3eSMilanka Ringwald                 descriptor = mock_gatt_client_get_characteristic_descriptor_for_handle(mock_gatt_client_value_handle);
452*76cdba3eSMilanka Ringwald                 btstack_assert(descriptor != NULL);
453*76cdba3eSMilanka Ringwald                 btstack_assert(descriptor->value_buffer != NULL);
454*76cdba3eSMilanka Ringwald 
455*76cdba3eSMilanka Ringwald                 report_gatt_characteristic_value(&gatt_client, descriptor->handle, descriptor->value_buffer, descriptor->value_len);
456*76cdba3eSMilanka Ringwald                 mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
457*76cdba3eSMilanka Ringwald                 break;
458*76cdba3eSMilanka Ringwald 
459af770404SMilanka Ringwald             default:
460af770404SMilanka Ringwald                 btstack_assert(false);
461af770404SMilanka Ringwald                 break;
4620f7fd6c1SMilanka Ringwald         }
4637da2c1baSMilanka Ringwald     }
4647da2c1baSMilanka Ringwald     mock_gatt_client_att_error = ERROR_CODE_SUCCESS;
465af770404SMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_IDLE;
4660f7fd6c1SMilanka Ringwald }