xref: /btstack/test/mock/mock_gatt_client.c (revision 500d8180fa32d9bb205d49465fb0f7fa20250313)
10f7fd6c1SMilanka Ringwald #include <stdint.h>
20f7fd6c1SMilanka Ringwald #include <stdio.h>
30f7fd6c1SMilanka Ringwald #include <string.h>
40f7fd6c1SMilanka Ringwald 
5af770404SMilanka Ringwald #include "btstack_debug.h"
67e693ad3SMilanka Ringwald #include "bluetooth_gatt.h"
70f7fd6c1SMilanka Ringwald #include "mock_gatt_client.h"
80f7fd6c1SMilanka Ringwald 
943bef108SMatthias Ringwald //#include "CppUTest/TestHarness.h"
1043bef108SMatthias Ringwald //#include "CppUTestExt/MockSupport.h"
110f7fd6c1SMilanka Ringwald 
12af770404SMilanka Ringwald static enum {
13af770404SMilanka Ringwald     MOCK_QUERY_IDLE = 0,
147dbac955SMatthias Ringwald     MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID,
157dbac955SMatthias Ringwald     MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID,
167dbac955SMatthias Ringwald     MOCK_QUERY_DISCOVER_ALL_CHARACTERISTICS,
1776cdba3eSMilanka Ringwald     MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS,
1876cdba3eSMilanka Ringwald     MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION,
197e693ad3SMilanka Ringwald     MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE,
207e693ad3SMilanka Ringwald     MOCK_READ_VALUE_OF_CHARACTERISTIC_DESCRIPTOR_USING_VALUE_HANDLE
21af770404SMilanka Ringwald } mock_gatt_client_state;
22af770404SMilanka Ringwald 
2376cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_att_handle_generator;
2476cdba3eSMilanka Ringwald 
25af770404SMilanka Ringwald static uint8_t mock_gatt_client_att_error;
267dbac955SMatthias Ringwald static uint8_t  mock_gatt_client_uuid128[16];
2776cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_value_handle;
2876cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_start_handle;
2976cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_end_handle;
3076cdba3eSMilanka Ringwald 
31af770404SMilanka Ringwald static gatt_client_t gatt_client;
320f7fd6c1SMilanka Ringwald 
337da2c1baSMilanka Ringwald static btstack_linked_list_t mock_gatt_client_services;
347da2c1baSMilanka Ringwald 
357da2c1baSMilanka Ringwald static mock_gatt_client_service_t * mock_gatt_client_last_service;
367da2c1baSMilanka Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_last_characteristic;
377da2c1baSMilanka Ringwald 
38ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_services;
39ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_characteristics;
40ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_characteristic_descriptors;
41e92f7a17SMilanka Ringwald static uint8_t moc_att_error_code_read_value_characteristics;
4286d0910fSMilanka Ringwald 
43*500d8180SMilanka Ringwald static btstack_linked_list_t event_packet_handlers;
44*500d8180SMilanka Ringwald 
45*500d8180SMilanka Ringwald void hci_add_event_handler(btstack_packet_callback_registration_t * callback_handler){
46*500d8180SMilanka Ringwald     btstack_linked_list_add_tail(&event_packet_handlers, (btstack_linked_item_t*) callback_handler);
47*500d8180SMilanka Ringwald }
48*500d8180SMilanka Ringwald 
49*500d8180SMilanka Ringwald void mock_hci_emit_event(uint8_t * packet, uint16_t size){
50*500d8180SMilanka Ringwald     // dispatch to all event handlers
51*500d8180SMilanka Ringwald     btstack_linked_list_iterator_t it;
52*500d8180SMilanka Ringwald     btstack_linked_list_iterator_init(&it, &event_packet_handlers);
53*500d8180SMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
54*500d8180SMilanka Ringwald         btstack_packet_callback_registration_t * entry = (btstack_packet_callback_registration_t*) btstack_linked_list_iterator_next(&it);
55*500d8180SMilanka Ringwald         entry->callback(HCI_EVENT_PACKET, 0, packet, size);
56*500d8180SMilanka Ringwald     }
57*500d8180SMilanka Ringwald }
58*500d8180SMilanka Ringwald 
59*500d8180SMilanka Ringwald static void hci_create_gap_connection_complete_event(const uint8_t * hci_event, uint8_t * gap_event) {
60*500d8180SMilanka Ringwald     gap_event[0] = HCI_EVENT_META_GAP;
61*500d8180SMilanka Ringwald     gap_event[1] = 36 - 2;
62*500d8180SMilanka Ringwald     gap_event[2] = GAP_SUBEVENT_LE_CONNECTION_COMPLETE;
63*500d8180SMilanka Ringwald     switch (hci_event[2]){
64*500d8180SMilanka Ringwald         case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
65*500d8180SMilanka Ringwald             memcpy(&gap_event[3], &hci_event[3], 11);
66*500d8180SMilanka Ringwald         memset(&gap_event[14], 0, 12);
67*500d8180SMilanka Ringwald         memcpy(&gap_event[26], &hci_event[14], 7);
68*500d8180SMilanka Ringwald         memset(&gap_event[33], 0xff, 3);
69*500d8180SMilanka Ringwald         break;
70*500d8180SMilanka Ringwald         case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE_V1:
71*500d8180SMilanka Ringwald             memcpy(&gap_event[3], &hci_event[3], 30);
72*500d8180SMilanka Ringwald         memset(&gap_event[33], 0xff, 3);
73*500d8180SMilanka Ringwald         break;
74*500d8180SMilanka Ringwald         case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE_V2:
75*500d8180SMilanka Ringwald             memcpy(&gap_event[3], &hci_event[3], 33);
76*500d8180SMilanka Ringwald         break;
77*500d8180SMilanka Ringwald         default:
78*500d8180SMilanka Ringwald             btstack_unreachable();
79*500d8180SMilanka Ringwald         break;
80*500d8180SMilanka Ringwald     }
81*500d8180SMilanka Ringwald }
82*500d8180SMilanka Ringwald 
83*500d8180SMilanka Ringwald 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){
84*500d8180SMilanka Ringwald     uint8_t hci_event[21];
85*500d8180SMilanka Ringwald     hci_event[0] = HCI_EVENT_LE_META;
86*500d8180SMilanka Ringwald     hci_event[1] = sizeof(hci_event) - 2u;
87*500d8180SMilanka Ringwald     hci_event[2] = HCI_SUBEVENT_LE_CONNECTION_COMPLETE;
88*500d8180SMilanka Ringwald     hci_event[3] = status;
89*500d8180SMilanka Ringwald     little_endian_store_16(hci_event, 4, con_handle);
90*500d8180SMilanka Ringwald     hci_event[6] = 0; // TODO: role
91*500d8180SMilanka Ringwald     hci_event[7] = address_type;
92*500d8180SMilanka Ringwald     reverse_bd_addr(address, &hci_event[8]);
93*500d8180SMilanka Ringwald     little_endian_store_16(hci_event, 14, 0); // interval
94*500d8180SMilanka Ringwald     little_endian_store_16(hci_event, 16, 0); // latency
95*500d8180SMilanka Ringwald     little_endian_store_16(hci_event, 18, 0); // supervision timeout
96*500d8180SMilanka Ringwald     hci_event[20] = 0; // master clock accuracy
97*500d8180SMilanka Ringwald     // emit GAP event, too
98*500d8180SMilanka Ringwald     uint8_t gap_event[36];
99*500d8180SMilanka Ringwald     hci_create_gap_connection_complete_event(hci_event, gap_event);
100*500d8180SMilanka Ringwald     mock_hci_emit_event(gap_event, sizeof(gap_event));
101*500d8180SMilanka Ringwald }
102*500d8180SMilanka Ringwald 
103*500d8180SMilanka Ringwald void mock_hci_emit_connection_encrypted(hci_con_handle_t con_handle, uint8_t encrypted){
104*500d8180SMilanka Ringwald     uint8_t encryption_complete_event[6] = { HCI_EVENT_ENCRYPTION_CHANGE, 4, 0, 0, 0, 0};
105*500d8180SMilanka Ringwald     little_endian_store_16(encryption_complete_event, 3, con_handle);
106*500d8180SMilanka Ringwald     encryption_complete_event[5] = encrypted;
107*500d8180SMilanka Ringwald     mock_hci_emit_event(encryption_complete_event, sizeof(encryption_complete_event));
108*500d8180SMilanka Ringwald }
109*500d8180SMilanka Ringwald 
110*500d8180SMilanka Ringwald void mock_hci_emit_disconnection_complete(hci_con_handle_t con_handle, uint8_t reason){
111*500d8180SMilanka Ringwald     uint8_t event[6];
112*500d8180SMilanka Ringwald     event[0] = HCI_EVENT_DISCONNECTION_COMPLETE;
113*500d8180SMilanka Ringwald     event[1] = sizeof(event) - 2u;
114*500d8180SMilanka Ringwald     event[2] = 0; // status = OK
115*500d8180SMilanka Ringwald     little_endian_store_16(event, 3, con_handle);
116*500d8180SMilanka Ringwald     event[5] = reason;
117*500d8180SMilanka Ringwald     mock_hci_emit_event(event, sizeof(event));
118*500d8180SMilanka Ringwald }
119*500d8180SMilanka Ringwald 
120*500d8180SMilanka Ringwald 
121af770404SMilanka Ringwald /**
122af770404SMilanka Ringwald  * copied from gatt_client.c - START
123af770404SMilanka Ringwald  */
1240f7fd6c1SMilanka Ringwald void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t * service){
1250f7fd6c1SMilanka Ringwald     service->start_group_handle = little_endian_read_16(packet, offset);
1260f7fd6c1SMilanka Ringwald     service->end_group_handle = little_endian_read_16(packet, offset + 2);
1270f7fd6c1SMilanka Ringwald     reverse_128(&packet[offset + 4], service->uuid128);
1280f7fd6c1SMilanka Ringwald     if (uuid_has_bluetooth_prefix(service->uuid128)){
1290f7fd6c1SMilanka Ringwald         service->uuid16 = big_endian_read_32(service->uuid128, 0);
1300f7fd6c1SMilanka Ringwald     } else {
1310f7fd6c1SMilanka Ringwald         service->uuid16 = 0;
1320f7fd6c1SMilanka Ringwald     }
1330f7fd6c1SMilanka Ringwald }
1340f7fd6c1SMilanka Ringwald 
1350f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic(const uint8_t * packet, int offset, gatt_client_characteristic_t * characteristic){
1360f7fd6c1SMilanka Ringwald     characteristic->start_handle = little_endian_read_16(packet, offset);
1370f7fd6c1SMilanka Ringwald     characteristic->value_handle = little_endian_read_16(packet, offset + 2);
1380f7fd6c1SMilanka Ringwald     characteristic->end_handle = little_endian_read_16(packet, offset + 4);
1390f7fd6c1SMilanka Ringwald     characteristic->properties = little_endian_read_16(packet, offset + 6);
1400f7fd6c1SMilanka Ringwald     reverse_128(&packet[offset+8], characteristic->uuid128);
1410f7fd6c1SMilanka Ringwald     if (uuid_has_bluetooth_prefix(characteristic->uuid128)){
1420f7fd6c1SMilanka Ringwald         characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0);
1430f7fd6c1SMilanka Ringwald     } else {
1440f7fd6c1SMilanka Ringwald         characteristic->uuid16 = 0;
1450f7fd6c1SMilanka Ringwald     }
1460f7fd6c1SMilanka Ringwald }
1470f7fd6c1SMilanka Ringwald 
1480f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic_descriptor(const uint8_t * packet, int offset, gatt_client_characteristic_descriptor_t * descriptor){
1490f7fd6c1SMilanka Ringwald     descriptor->handle = little_endian_read_16(packet, offset);
1500f7fd6c1SMilanka Ringwald     reverse_128(&packet[offset+2], descriptor->uuid128);
1510f7fd6c1SMilanka Ringwald     if (uuid_has_bluetooth_prefix(descriptor->uuid128)){
1520f7fd6c1SMilanka Ringwald         descriptor->uuid16 = big_endian_read_32(descriptor->uuid128, 0);
1530f7fd6c1SMilanka Ringwald     } else {
1540f7fd6c1SMilanka Ringwald         descriptor->uuid16 = 0;
1550f7fd6c1SMilanka Ringwald     }
1560f7fd6c1SMilanka Ringwald }
1570f7fd6c1SMilanka Ringwald 
1587e693ad3SMilanka Ringwald static void emit_event(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){
159af770404SMilanka Ringwald     if (!callback) return;
160af770404SMilanka Ringwald     (*callback)(HCI_EVENT_PACKET, 0, packet, size);
1610f7fd6c1SMilanka Ringwald }
1620f7fd6c1SMilanka Ringwald 
163af770404SMilanka Ringwald static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_status){
164af770404SMilanka Ringwald     // @format H1
165af770404SMilanka Ringwald     uint8_t packet[5];
166af770404SMilanka Ringwald     packet[0] = GATT_EVENT_QUERY_COMPLETE;
167af770404SMilanka Ringwald     packet[1] = 3;
168af770404SMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
169af770404SMilanka Ringwald     packet[4] = att_status;
1707e693ad3SMilanka Ringwald     emit_event(gatt_client->callback, packet, sizeof(packet));
1710f7fd6c1SMilanka Ringwald }
1720f7fd6c1SMilanka Ringwald 
1737da2c1baSMilanka 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){
1747da2c1baSMilanka Ringwald     // @format HX
1757da2c1baSMilanka Ringwald     uint8_t packet[24];
1767da2c1baSMilanka Ringwald     packet[0] = GATT_EVENT_SERVICE_QUERY_RESULT;
1777da2c1baSMilanka Ringwald     packet[1] = sizeof(packet) - 2u;
1787da2c1baSMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
1797da2c1baSMilanka Ringwald     ///
1807da2c1baSMilanka Ringwald     little_endian_store_16(packet, 4, start_group_handle);
1817da2c1baSMilanka Ringwald     little_endian_store_16(packet, 6, end_group_handle);
1827da2c1baSMilanka Ringwald     reverse_128(uuid128, &packet[8]);
1837e693ad3SMilanka Ringwald     emit_event(gatt_client->callback, packet, sizeof(packet));
1847da2c1baSMilanka Ringwald }
1857da2c1baSMilanka Ringwald 
1867da2c1baSMilanka 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,
1877da2c1baSMilanka Ringwald                                                         uint16_t properties, const uint8_t * uuid128){
1887da2c1baSMilanka Ringwald     // @format HY
1897da2c1baSMilanka Ringwald     uint8_t packet[28];
1907da2c1baSMilanka Ringwald     packet[0] = GATT_EVENT_CHARACTERISTIC_QUERY_RESULT;
1917da2c1baSMilanka Ringwald     packet[1] = sizeof(packet) - 2u;
1927da2c1baSMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
1937da2c1baSMilanka Ringwald     ///
1947da2c1baSMilanka Ringwald     little_endian_store_16(packet, 4,  start_handle);
1957da2c1baSMilanka Ringwald     little_endian_store_16(packet, 6,  value_handle);
1967da2c1baSMilanka Ringwald     little_endian_store_16(packet, 8,  end_handle);
1977da2c1baSMilanka Ringwald     little_endian_store_16(packet, 10, properties);
1987da2c1baSMilanka Ringwald     reverse_128(uuid128, &packet[12]);
1997e693ad3SMilanka Ringwald     emit_event(gatt_client->callback, packet, sizeof(packet));
2007da2c1baSMilanka Ringwald }
2017da2c1baSMilanka Ringwald 
20276cdba3eSMilanka Ringwald static void emit_gatt_all_characteristic_descriptors_result_event(
20376cdba3eSMilanka Ringwald         gatt_client_t * gatt_client, uint16_t descriptor_handle, const uint8_t * uuid128){
20476cdba3eSMilanka Ringwald     // @format HZ
20576cdba3eSMilanka Ringwald     uint8_t packet[22];
20676cdba3eSMilanka Ringwald     packet[0] = GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT;
20776cdba3eSMilanka Ringwald     packet[1] = sizeof(packet) - 2u;
20876cdba3eSMilanka Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
20976cdba3eSMilanka Ringwald     ///
21076cdba3eSMilanka Ringwald     little_endian_store_16(packet, 4,  descriptor_handle);
21176cdba3eSMilanka Ringwald     reverse_128(uuid128, &packet[6]);
2127e693ad3SMilanka Ringwald     emit_event(gatt_client->callback, packet, sizeof(packet));
21376cdba3eSMilanka Ringwald }
21476cdba3eSMilanka Ringwald 
2157e693ad3SMilanka Ringwald static uint8_t event_packet[255];
21676cdba3eSMilanka 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){
21776cdba3eSMilanka Ringwald     // before the value inside the ATT PDU
2187e693ad3SMilanka Ringwald     event_packet[0] = type;
2197e693ad3SMilanka Ringwald     event_packet[1] = 6 + length;
2207e693ad3SMilanka Ringwald     little_endian_store_16(event_packet, 2, con_handle);
2217e693ad3SMilanka Ringwald     little_endian_store_16(event_packet, 4, attribute_handle);
2227e693ad3SMilanka Ringwald     little_endian_store_16(event_packet, 6, length);
2237e693ad3SMilanka Ringwald     memcpy(&event_packet[8], value, length);
2247e693ad3SMilanka Ringwald     return &event_packet[0];
22576cdba3eSMilanka Ringwald }
22676cdba3eSMilanka Ringwald 
2277dbac955SMatthias Ringwald 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){
2287e693ad3SMilanka Ringwald     btstack_assert(characteristic != NULL);
2297e693ad3SMilanka Ringwald     btstack_assert(characteristic->notification != NULL);
2307e693ad3SMilanka Ringwald     btstack_assert(characteristic->notification->callback != NULL);
2317dbac955SMatthias Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_NOTIFICATION, gatt_client.con_handle, value_handle, (uint8_t *) value_buffer, value_len);
2327e693ad3SMilanka Ringwald     emit_event(characteristic->notification->callback, packet, 2 + packet[1]);
2337e693ad3SMilanka Ringwald }
2347e693ad3SMilanka Ringwald 
2357dbac955SMatthias Ringwald void mock_gatt_client_send_notification(mock_gatt_client_characteristic_t * characteristic, const uint8_t * value_buffer, uint16_t value_len){
2367e693ad3SMilanka Ringwald     mock_gatt_client_send_notification_with_handle(characteristic, characteristic->value_handle, value_buffer, value_len);
2377e693ad3SMilanka Ringwald }
2387e693ad3SMilanka Ringwald 
2397dbac955SMatthias Ringwald 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){
2407dbac955SMatthias Ringwald     btstack_assert(characteristic != NULL);
2417dbac955SMatthias Ringwald     btstack_assert(characteristic->notification != NULL);
2427dbac955SMatthias Ringwald     btstack_assert(characteristic->notification->callback != NULL);
2437dbac955SMatthias Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_INDICATION, gatt_client.con_handle, value_handle, (uint8_t *) value_buffer, value_len);
2447dbac955SMatthias Ringwald     emit_event(characteristic->notification->callback, packet, 2 + packet[1]);
2457dbac955SMatthias Ringwald }
2467dbac955SMatthias Ringwald 
2477dbac955SMatthias Ringwald void mock_gatt_client_send_indication(mock_gatt_client_characteristic_t * characteristic, const uint8_t * value_buffer, uint16_t value_len){
2487dbac955SMatthias Ringwald     mock_gatt_client_send_indication_with_handle(characteristic, characteristic->value_handle, value_buffer, value_len);
2497dbac955SMatthias Ringwald }
2507dbac955SMatthias Ringwald 
2517e693ad3SMilanka Ringwald static void mock_gatt_client_send_characteristic_value(gatt_client_t * gatt_client, mock_gatt_client_characteristic_t * characteristic){
2527e693ad3SMilanka Ringwald     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);
2537e693ad3SMilanka Ringwald     emit_event(gatt_client->callback, packet, 2 + packet[1]);
25476cdba3eSMilanka Ringwald }
25576cdba3eSMilanka Ringwald 
256af770404SMilanka Ringwald /**
257af770404SMilanka Ringwald  * copied from gatt_client.c - END
258af770404SMilanka Ringwald  */
2590f7fd6c1SMilanka Ringwald 
2607dbac955SMatthias Ringwald 
2617dbac955SMatthias Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_get_characteristic_for_value_handle(uint16_t value_handle){
2627dbac955SMatthias Ringwald     btstack_linked_list_iterator_t service_it;
2637dbac955SMatthias Ringwald     btstack_linked_list_iterator_t characteristic_it;
2647dbac955SMatthias Ringwald 
2657dbac955SMatthias Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
2667dbac955SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
2677dbac955SMatthias Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
2687dbac955SMatthias Ringwald 
2697dbac955SMatthias Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
2707dbac955SMatthias Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
2717dbac955SMatthias Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
2727dbac955SMatthias Ringwald             if (characteristic->value_handle != value_handle) continue;
2737dbac955SMatthias Ringwald             return characteristic;
2747dbac955SMatthias Ringwald         }
2757dbac955SMatthias Ringwald     }
2767dbac955SMatthias Ringwald     return NULL;
2777dbac955SMatthias Ringwald }
2787dbac955SMatthias Ringwald 
279e92f7a17SMilanka Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_get_characteristic_for_uuid16(uint16_t uuid16){
280e92f7a17SMilanka Ringwald     btstack_linked_list_iterator_t service_it;
281e92f7a17SMilanka Ringwald     btstack_linked_list_iterator_t characteristic_it;
282e92f7a17SMilanka Ringwald 
283e92f7a17SMilanka Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
284e92f7a17SMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
285e92f7a17SMilanka Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
286e92f7a17SMilanka Ringwald 
287e92f7a17SMilanka Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
288e92f7a17SMilanka Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
289e92f7a17SMilanka Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
290e92f7a17SMilanka Ringwald             if (characteristic->uuid16 != uuid16) continue;
291e92f7a17SMilanka Ringwald             return characteristic;
292e92f7a17SMilanka Ringwald         }
293e92f7a17SMilanka Ringwald     }
294e92f7a17SMilanka Ringwald     return NULL;
295e92f7a17SMilanka Ringwald }
296e92f7a17SMilanka Ringwald 
2977dbac955SMatthias Ringwald static mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_get_characteristic_descriptor_for_handle(uint16_t handle){
2987dbac955SMatthias Ringwald     btstack_linked_list_iterator_t service_it;
2997dbac955SMatthias Ringwald     btstack_linked_list_iterator_t characteristic_it;
3007dbac955SMatthias Ringwald 
3017dbac955SMatthias Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
3027dbac955SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
3037dbac955SMatthias Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
3047dbac955SMatthias Ringwald 
3057dbac955SMatthias Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
3067dbac955SMatthias Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
3077dbac955SMatthias Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
3087dbac955SMatthias Ringwald 
3097dbac955SMatthias Ringwald             btstack_linked_list_iterator_t desc_it;
3107dbac955SMatthias Ringwald             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
3117dbac955SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&desc_it)){
3127dbac955SMatthias Ringwald                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
3137dbac955SMatthias Ringwald                 if (desc->handle != handle) continue;
3147dbac955SMatthias Ringwald                 return desc;
3157dbac955SMatthias Ringwald             }
3167dbac955SMatthias Ringwald         }
3177dbac955SMatthias Ringwald     }
3187dbac955SMatthias Ringwald     return NULL;
3197dbac955SMatthias Ringwald }
3207dbac955SMatthias Ringwald 
3217dbac955SMatthias Ringwald uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){
3227dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID;
3237dbac955SMatthias Ringwald     uuid_add_bluetooth_prefix(mock_gatt_client_uuid128, uuid16);
3247dbac955SMatthias Ringwald     gatt_client.callback = callback;
3257dbac955SMatthias Ringwald     gatt_client.con_handle = con_handle;
3267dbac955SMatthias Ringwald     return ERROR_CODE_SUCCESS;
3277dbac955SMatthias Ringwald }
3287dbac955SMatthias Ringwald 
3297dbac955SMatthias Ringwald uint8_t gatt_client_discover_primary_services_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, const uint8_t * uuid128){
3307dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID;
3317dbac955SMatthias Ringwald     memcpy(mock_gatt_client_uuid128, uuid128, 16);
3327dbac955SMatthias Ringwald     gatt_client.callback = callback;
3337dbac955SMatthias Ringwald     gatt_client.con_handle = con_handle;
3347dbac955SMatthias Ringwald     return ERROR_CODE_SUCCESS;
3357dbac955SMatthias Ringwald }
3367dbac955SMatthias Ringwald 
3377dbac955SMatthias 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){
3387dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID;
3397dbac955SMatthias Ringwald     uuid_add_bluetooth_prefix(mock_gatt_client_uuid128, uuid16);
3407dbac955SMatthias Ringwald     mock_gatt_client_start_handle = start_handle;
3417dbac955SMatthias Ringwald     mock_gatt_client_end_handle = end_handle;
3427dbac955SMatthias Ringwald 
3437dbac955SMatthias Ringwald     gatt_client.callback = callback;
3447dbac955SMatthias Ringwald     gatt_client.con_handle = con_handle;
3457dbac955SMatthias Ringwald     return ERROR_CODE_SUCCESS;
3467dbac955SMatthias Ringwald }
3477dbac955SMatthias Ringwald 
3487dbac955SMatthias Ringwald uint8_t gatt_client_discover_characteristics_for_service(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service){
3497dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_ALL_CHARACTERISTICS;
3507dbac955SMatthias Ringwald     mock_gatt_client_start_handle = service->start_group_handle;
3517dbac955SMatthias Ringwald     mock_gatt_client_end_handle = service->end_group_handle;
3527dbac955SMatthias Ringwald     gatt_client.callback = callback;
3537dbac955SMatthias Ringwald     gatt_client.con_handle = con_handle;
3547dbac955SMatthias Ringwald     return ERROR_CODE_SUCCESS;
3557dbac955SMatthias Ringwald }
3567dbac955SMatthias Ringwald 
3577dbac955SMatthias Ringwald uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
3587dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS;
3597dbac955SMatthias Ringwald     mock_gatt_client_value_handle = characteristic->value_handle;
3607dbac955SMatthias Ringwald 
3617dbac955SMatthias Ringwald     gatt_client.callback = callback;
3627dbac955SMatthias Ringwald     gatt_client.con_handle = con_handle;
3637dbac955SMatthias Ringwald     return ERROR_CODE_SUCCESS;
3647dbac955SMatthias Ringwald }
3657dbac955SMatthias Ringwald 
3667dbac955SMatthias 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){
3677dbac955SMatthias Ringwald     btstack_assert(notification != NULL);
3687dbac955SMatthias Ringwald     btstack_assert(&callback != NULL);
3697dbac955SMatthias Ringwald 
3707dbac955SMatthias Ringwald     notification->callback = callback;
3717dbac955SMatthias Ringwald     notification->con_handle = con_handle;
3727dbac955SMatthias Ringwald 
3737dbac955SMatthias Ringwald 
3747dbac955SMatthias Ringwald     if (characteristic == NULL){
3757dbac955SMatthias Ringwald         // 'all characteristics': not used yet
3767dbac955SMatthias Ringwald         btstack_assert(false);
3777dbac955SMatthias Ringwald     } else {
3787dbac955SMatthias Ringwald         mock_gatt_client_characteristic_t * mock_characteristic  = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle);
3797dbac955SMatthias Ringwald         btstack_assert(mock_characteristic != NULL);
3807dbac955SMatthias Ringwald 
3817dbac955SMatthias Ringwald         notification->attribute_handle = characteristic->value_handle;
3827dbac955SMatthias Ringwald         mock_characteristic->notification = notification;
3837dbac955SMatthias Ringwald     }
3847dbac955SMatthias Ringwald }
3857dbac955SMatthias Ringwald 
3867dbac955SMatthias 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){
3877dbac955SMatthias Ringwald     mock_gatt_client_characteristic_t * mock_characteristic  = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle);
3887dbac955SMatthias Ringwald     btstack_assert(mock_characteristic != NULL);
3897dbac955SMatthias Ringwald 
3907dbac955SMatthias Ringwald     if (mock_characteristic->notification_status_code != ERROR_CODE_SUCCESS){
3917dbac955SMatthias Ringwald         return mock_characteristic->notification_status_code;
3927dbac955SMatthias Ringwald     }
3937dbac955SMatthias Ringwald 
3947dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
3957dbac955SMatthias Ringwald 
3967dbac955SMatthias Ringwald     gatt_client.callback = callback;
3977dbac955SMatthias Ringwald     gatt_client.con_handle = con_handle;
3987dbac955SMatthias Ringwald     return ERROR_CODE_SUCCESS;
3997dbac955SMatthias Ringwald }
4007dbac955SMatthias Ringwald 
401e92f7a17SMilanka Ringwald 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){
402e92f7a17SMilanka Ringwald     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
403e92f7a17SMilanka Ringwald 
404e92f7a17SMilanka Ringwald     mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_uuid16(uuid16);
405e92f7a17SMilanka Ringwald     if (mock_characteristic != NULL){
406e92f7a17SMilanka Ringwald         mock_gatt_client_value_handle = mock_characteristic->value_handle;
407e92f7a17SMilanka Ringwald         gatt_client.callback = callback;
408e92f7a17SMilanka Ringwald         gatt_client.con_handle = con_handle;
409e92f7a17SMilanka Ringwald     }
410e92f7a17SMilanka Ringwald     return ERROR_CODE_SUCCESS;
411e92f7a17SMilanka Ringwald }
412e92f7a17SMilanka Ringwald 
4137dbac955SMatthias 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){
4147dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
4157dbac955SMatthias Ringwald 
4167dbac955SMatthias Ringwald     mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(value_handle);
4177dbac955SMatthias Ringwald     btstack_assert(mock_characteristic != NULL);
4187dbac955SMatthias Ringwald 
4197dbac955SMatthias Ringwald     mock_gatt_client_value_handle = mock_characteristic->value_handle;
4207dbac955SMatthias Ringwald     gatt_client.callback = callback;
4217dbac955SMatthias Ringwald     gatt_client.con_handle = con_handle;
4227dbac955SMatthias Ringwald     return ERROR_CODE_SUCCESS;
4237dbac955SMatthias Ringwald }
4247dbac955SMatthias Ringwald 
4257dbac955SMatthias 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){
4267dbac955SMatthias Ringwald     btstack_assert(characteristic != NULL);
4277dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE;
4287dbac955SMatthias Ringwald 
4297dbac955SMatthias Ringwald     mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle);
4307dbac955SMatthias Ringwald     btstack_assert(mock_characteristic != NULL);
4317dbac955SMatthias Ringwald 
4327dbac955SMatthias Ringwald     gatt_client.callback = callback;
4337dbac955SMatthias Ringwald     gatt_client.con_handle = con_handle;
4347dbac955SMatthias Ringwald     mock_gatt_client_value_handle = mock_characteristic->value_handle;
4357dbac955SMatthias Ringwald     return ERROR_CODE_SUCCESS;
4367dbac955SMatthias Ringwald }
4377dbac955SMatthias Ringwald 
4387dbac955SMatthias Ringwald 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){
4397dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_DESCRIPTOR_USING_VALUE_HANDLE;
4407dbac955SMatthias Ringwald     mock_gatt_client_value_handle = descriptor_handle;
4417dbac955SMatthias Ringwald     return ERROR_CODE_SUCCESS;
4427dbac955SMatthias Ringwald }
4437dbac955SMatthias Ringwald 
4447dbac955SMatthias Ringwald void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification){
4457dbac955SMatthias Ringwald }
4467dbac955SMatthias Ringwald 
4477dbac955SMatthias Ringwald 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){
4487dbac955SMatthias Ringwald     mock_gatt_client_characteristic_t * mock_characteristic  = mock_gatt_client_get_characteristic_for_value_handle(value_handle);
4497dbac955SMatthias Ringwald     btstack_assert(mock_characteristic != NULL);
4507dbac955SMatthias Ringwald 
4517dbac955SMatthias Ringwald     if (mock_characteristic->notification_status_code != ERROR_CODE_SUCCESS){
4527dbac955SMatthias Ringwald         return mock_characteristic->notification_status_code;
4537dbac955SMatthias Ringwald     }
4547dbac955SMatthias Ringwald 
4557dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
4567dbac955SMatthias Ringwald 
4577dbac955SMatthias Ringwald     gatt_client.callback = callback;
4587dbac955SMatthias Ringwald     gatt_client.con_handle = con_handle;
4597dbac955SMatthias Ringwald     return ERROR_CODE_SUCCESS;
4607dbac955SMatthias Ringwald }
4617dbac955SMatthias Ringwald 
4627e693ad3SMilanka Ringwald void mock_gatt_client_emit_complete(uint8_t status){
4637da2c1baSMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_IDLE;
4647da2c1baSMilanka Ringwald     emit_gatt_complete_event(&gatt_client, status);
4657da2c1baSMilanka Ringwald }
4660f7fd6c1SMilanka Ringwald 
4677e693ad3SMilanka Ringwald void mock_gatt_client_run_once(void){
468af770404SMilanka Ringwald     btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE);
46976cdba3eSMilanka Ringwald     mock_gatt_client_characteristic_t * characteristic;
47076cdba3eSMilanka Ringwald     mock_gatt_client_characteristic_descriptor_t * descriptor;
47176cdba3eSMilanka Ringwald 
4727da2c1baSMilanka Ringwald     btstack_linked_list_iterator_t service_it;
4737da2c1baSMilanka Ringwald     btstack_linked_list_iterator_t characteristic_it;
47476cdba3eSMilanka Ringwald     btstack_linked_list_iterator_t descriptor_it;
47576cdba3eSMilanka Ringwald 
476af770404SMilanka Ringwald     switch (mock_gatt_client_state){
4777dbac955SMatthias Ringwald         case MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID:
478af770404SMilanka Ringwald             // emit GATT_EVENT_SERVICE_QUERY_RESULT for each matching service
479ec1a0daeSMilanka Ringwald             if (moc_att_error_code_discover_services != ATT_ERROR_SUCCESS){
480ec1a0daeSMilanka Ringwald                 mock_gatt_client_emit_complete(moc_att_error_code_discover_services);
481ec1a0daeSMilanka Ringwald                 return;
482ec1a0daeSMilanka Ringwald             }
483ec1a0daeSMilanka Ringwald 
4847da2c1baSMilanka Ringwald             btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
4857da2c1baSMilanka Ringwald             while (btstack_linked_list_iterator_has_next(&service_it)){
4867da2c1baSMilanka Ringwald                 mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
4877dbac955SMatthias Ringwald                 if (memcmp(service->uuid128, mock_gatt_client_uuid128, 16) != 0) continue;
4887da2c1baSMilanka Ringwald                 mock_gatt_client_last_service = service;
4897dbac955SMatthias Ringwald                 emit_gatt_service_query_result_event(&gatt_client, service->start_group_handle, service->end_group_handle, service->uuid128);
4907da2c1baSMilanka Ringwald             }
4917da2c1baSMilanka Ringwald             // emit GATT_EVENT_QUERY_COMPLETE
4927da2c1baSMilanka Ringwald             mock_gatt_client_emit_complete(ATT_ERROR_SUCCESS);
4937da2c1baSMilanka Ringwald             break;
4947da2c1baSMilanka Ringwald 
4957dbac955SMatthias Ringwald         case MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID:
4967dbac955SMatthias Ringwald         case MOCK_QUERY_DISCOVER_ALL_CHARACTERISTICS:
4977da2c1baSMilanka Ringwald             // emit GATT_EVENT_CHARACTERISTIC_QUERY_RESULT for each matching characteristic
498ec1a0daeSMilanka Ringwald             if (moc_att_error_code_discover_characteristics != ATT_ERROR_SUCCESS){
499ec1a0daeSMilanka Ringwald                 mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristics);
500ec1a0daeSMilanka Ringwald                 return;
501ec1a0daeSMilanka Ringwald             }
502ec1a0daeSMilanka Ringwald 
5037da2c1baSMilanka Ringwald             btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
5047da2c1baSMilanka Ringwald             while (btstack_linked_list_iterator_has_next(&service_it)){
5057da2c1baSMilanka Ringwald                 mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
5067da2c1baSMilanka Ringwald 
5077da2c1baSMilanka Ringwald                 btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
5087da2c1baSMilanka Ringwald                 while (btstack_linked_list_iterator_has_next(&characteristic_it)){
5097da2c1baSMilanka Ringwald                     mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
51076cdba3eSMilanka Ringwald                     if (characteristic->start_handle < mock_gatt_client_start_handle) continue;
51176cdba3eSMilanka Ringwald                     if (characteristic->end_handle > mock_gatt_client_end_handle) continue;
5127dbac955SMatthias Ringwald                     if ((mock_gatt_client_state == MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID) && (memcmp(characteristic->uuid128, mock_gatt_client_uuid128, 16) != 0)) continue;
51376cdba3eSMilanka Ringwald 
51476cdba3eSMilanka Ringwald                     emit_gatt_characteristic_query_result_event(&gatt_client,
51576cdba3eSMilanka Ringwald                         characteristic->start_handle, characteristic->value_handle, characteristic->end_handle,
5167dbac955SMatthias Ringwald                         characteristic->properties, characteristic->uuid128);
5177da2c1baSMilanka Ringwald                 }
5187da2c1baSMilanka Ringwald             }
5197da2c1baSMilanka Ringwald 
5207da2c1baSMilanka Ringwald             // emit GATT_EVENT_QUERY_COMPLETE
5217da2c1baSMilanka Ringwald             mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
522af770404SMilanka Ringwald             break;
52376cdba3eSMilanka Ringwald 
52476cdba3eSMilanka Ringwald         case MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS:
52576cdba3eSMilanka Ringwald             characteristic = mock_gatt_client_get_characteristic_for_value_handle(mock_gatt_client_value_handle);
52676cdba3eSMilanka Ringwald             btstack_assert(characteristic != NULL);
52776cdba3eSMilanka Ringwald 
528ec1a0daeSMilanka Ringwald             if (moc_att_error_code_discover_characteristic_descriptors != ATT_ERROR_SUCCESS){
529ec1a0daeSMilanka Ringwald                 mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristic_descriptors);
530ec1a0daeSMilanka Ringwald                 return;
531ec1a0daeSMilanka Ringwald             }
532ec1a0daeSMilanka Ringwald 
53376cdba3eSMilanka Ringwald             btstack_linked_list_iterator_init(&descriptor_it, &characteristic->descriptors);
53476cdba3eSMilanka Ringwald             while (btstack_linked_list_iterator_has_next(&descriptor_it)){
53576cdba3eSMilanka Ringwald                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&descriptor_it);
53676cdba3eSMilanka Ringwald 
5377dbac955SMatthias Ringwald                 emit_gatt_all_characteristic_descriptors_result_event(&gatt_client, desc->handle, desc->uuid128);
53876cdba3eSMilanka Ringwald             }
53976cdba3eSMilanka Ringwald 
54076cdba3eSMilanka Ringwald             // emit GATT_EVENT_QUERY_COMPLETE
54176cdba3eSMilanka Ringwald             mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
54276cdba3eSMilanka Ringwald             break;
54376cdba3eSMilanka Ringwald 
54476cdba3eSMilanka Ringwald         case MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION:
54576cdba3eSMilanka Ringwald             mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
54676cdba3eSMilanka Ringwald             break;
54776cdba3eSMilanka Ringwald 
54876cdba3eSMilanka Ringwald         case MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE:
5497e693ad3SMilanka Ringwald             characteristic = mock_gatt_client_get_characteristic_for_value_handle(mock_gatt_client_value_handle);
550e92f7a17SMilanka Ringwald             if (moc_att_error_code_read_value_characteristics != ATT_ERROR_SUCCESS){
551e92f7a17SMilanka Ringwald                 mock_gatt_client_emit_complete(moc_att_error_code_read_value_characteristics);
552e92f7a17SMilanka Ringwald                 break;
553e92f7a17SMilanka Ringwald             }
554e92f7a17SMilanka Ringwald             if (characteristic != NULL){
5557e693ad3SMilanka Ringwald                 mock_gatt_client_send_characteristic_value(&gatt_client, characteristic);
556e92f7a17SMilanka Ringwald             }
5577e693ad3SMilanka Ringwald             mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
5587e693ad3SMilanka Ringwald             break;
5597e693ad3SMilanka Ringwald 
5607e693ad3SMilanka Ringwald         case MOCK_READ_VALUE_OF_CHARACTERISTIC_DESCRIPTOR_USING_VALUE_HANDLE:
56176cdba3eSMilanka Ringwald             descriptor = mock_gatt_client_get_characteristic_descriptor_for_handle(mock_gatt_client_value_handle);
56276cdba3eSMilanka Ringwald             btstack_assert(descriptor != NULL);
56376cdba3eSMilanka Ringwald             btstack_assert(descriptor->value_buffer != NULL);
56476cdba3eSMilanka Ringwald 
56576cdba3eSMilanka Ringwald             mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
56676cdba3eSMilanka Ringwald             break;
56776cdba3eSMilanka Ringwald 
568af770404SMilanka Ringwald         default:
569af770404SMilanka Ringwald             btstack_assert(false);
570af770404SMilanka Ringwald             break;
5710f7fd6c1SMilanka Ringwald     }
5727da2c1baSMilanka Ringwald }
5737e693ad3SMilanka Ringwald 
5747e693ad3SMilanka Ringwald void mock_gatt_client_run(void){
5757e693ad3SMilanka Ringwald     btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE);
5767e693ad3SMilanka Ringwald     while (mock_gatt_client_state != MOCK_QUERY_IDLE){
5777e693ad3SMilanka Ringwald         mock_gatt_client_run_once();
5787e693ad3SMilanka Ringwald     }
5797da2c1baSMilanka Ringwald     mock_gatt_client_att_error = ERROR_CODE_SUCCESS;
580af770404SMilanka Ringwald     mock_gatt_client_state = MOCK_QUERY_IDLE;
5810f7fd6c1SMilanka Ringwald }
5827e693ad3SMilanka Ringwald 
5837e693ad3SMilanka Ringwald void mock_gatt_client_emit_dummy_event(void){
5847e693ad3SMilanka Ringwald         // @format H1
5857e693ad3SMilanka Ringwald     uint8_t packet[2];
5867e693ad3SMilanka Ringwald     packet[0] = 0;
5877e693ad3SMilanka Ringwald     packet[1] = 0;
5887e693ad3SMilanka Ringwald     emit_event(gatt_client.callback, packet, sizeof(packet));
5897e693ad3SMilanka Ringwald }
5907dbac955SMatthias Ringwald 
5917dbac955SMatthias Ringwald static void mock_gatt_client_reset_errors(void){
5927dbac955SMatthias Ringwald     moc_att_error_code_discover_services = ATT_ERROR_SUCCESS;
5937dbac955SMatthias Ringwald     moc_att_error_code_discover_characteristics = ATT_ERROR_SUCCESS;
5947dbac955SMatthias Ringwald     moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_SUCCESS;
595e92f7a17SMilanka Ringwald     moc_att_error_code_read_value_characteristics = ATT_ERROR_SUCCESS;
5967dbac955SMatthias Ringwald }
5977dbac955SMatthias Ringwald 
5987dbac955SMatthias Ringwald void mock_gatt_client_reset(void){
5997dbac955SMatthias Ringwald     mock_gatt_client_att_error = 0;
6007dbac955SMatthias Ringwald     mock_gatt_client_state = MOCK_QUERY_IDLE;
6017dbac955SMatthias Ringwald     mock_gatt_client_att_handle_generator = 0;
6027dbac955SMatthias Ringwald     mock_gatt_client_last_service = NULL;
6037dbac955SMatthias Ringwald 
6047dbac955SMatthias Ringwald     mock_gatt_client_reset_errors();
6057dbac955SMatthias Ringwald 
6067dbac955SMatthias Ringwald     btstack_linked_list_iterator_t service_it;
6077dbac955SMatthias Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
6087dbac955SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
6097dbac955SMatthias Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
6107dbac955SMatthias Ringwald         btstack_linked_list_remove(&mock_gatt_client_services, (btstack_linked_item_t *) service);
6117dbac955SMatthias Ringwald 
6127dbac955SMatthias Ringwald         btstack_linked_list_iterator_t characteristic_it;
6137dbac955SMatthias Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
6147dbac955SMatthias Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
6157dbac955SMatthias Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
6167dbac955SMatthias Ringwald             btstack_linked_list_remove(&service->characteristics, (btstack_linked_item_t *) characteristic);
6177dbac955SMatthias Ringwald 
6187dbac955SMatthias Ringwald             btstack_linked_list_iterator_t desc_it;
6197dbac955SMatthias Ringwald             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
6207dbac955SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&desc_it)){
6217dbac955SMatthias Ringwald                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
6227dbac955SMatthias Ringwald                 btstack_linked_list_remove(&characteristic->descriptors, (btstack_linked_item_t *) desc);
6237dbac955SMatthias Ringwald                 free(desc);
6247dbac955SMatthias Ringwald             }
6257dbac955SMatthias Ringwald             free(characteristic);
6267dbac955SMatthias Ringwald         }
6277dbac955SMatthias Ringwald         free(service);
6287dbac955SMatthias Ringwald     }
6297dbac955SMatthias Ringwald }
6307dbac955SMatthias Ringwald 
6317dbac955SMatthias Ringwald void mock_gatt_client_set_att_error_discover_primary_services(void){
6327dbac955SMatthias Ringwald     moc_att_error_code_discover_services = ATT_ERROR_REQUEST_NOT_SUPPORTED;
6337dbac955SMatthias Ringwald }
6347dbac955SMatthias Ringwald void mock_gatt_client_set_att_error_discover_characteristics(void){
6357dbac955SMatthias Ringwald     moc_att_error_code_discover_characteristics = ATT_ERROR_REQUEST_NOT_SUPPORTED;
6367dbac955SMatthias Ringwald }
6377dbac955SMatthias Ringwald void mock_gatt_client_set_att_error_discover_characteristic_descriptors(void){
6387dbac955SMatthias Ringwald     moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_REQUEST_NOT_SUPPORTED;
6397dbac955SMatthias Ringwald }
640e92f7a17SMilanka Ringwald void mock_gatt_client_set_att_error_read_value_characteristics(void){
641e92f7a17SMilanka Ringwald     moc_att_error_code_read_value_characteristics = ATT_ERROR_REQUEST_NOT_SUPPORTED;
6427dbac955SMatthias Ringwald }
6437dbac955SMatthias Ringwald 
6447dbac955SMatthias Ringwald void mock_gatt_client_enable_notification(mock_gatt_client_characteristic_t * characteristic, bool command_allowed){
6457dbac955SMatthias Ringwald     if (command_allowed){
6467dbac955SMatthias Ringwald         characteristic->notification_status_code = ERROR_CODE_SUCCESS;
6477dbac955SMatthias Ringwald     } else {
6487dbac955SMatthias Ringwald         characteristic->notification_status_code = ERROR_CODE_COMMAND_DISALLOWED;
6497dbac955SMatthias Ringwald     }
6507dbac955SMatthias Ringwald }
6517dbac955SMatthias Ringwald 
6527dbac955SMatthias Ringwald void mock_gatt_client_dump_services(void){
6537dbac955SMatthias Ringwald     btstack_linked_list_iterator_t service_it;
6547dbac955SMatthias Ringwald     btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services);
6557dbac955SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&service_it)){
6567dbac955SMatthias Ringwald         mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it);
6577dbac955SMatthias Ringwald         printf("0x%02x: START SERVICE ", service->start_group_handle);
6587dbac955SMatthias Ringwald         if (service->uuid16) {
6597dbac955SMatthias Ringwald             printf("%04x\n", service->uuid16);
6607dbac955SMatthias Ringwald         } else {
6617dbac955SMatthias Ringwald             printf("%s\n", uuid128_to_str(service->uuid128));
6627dbac955SMatthias Ringwald         }
6637dbac955SMatthias Ringwald 
6647dbac955SMatthias Ringwald         btstack_linked_list_iterator_t characteristic_it;
6657dbac955SMatthias Ringwald         btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics);
6667dbac955SMatthias Ringwald         while (btstack_linked_list_iterator_has_next(&characteristic_it)){
6677dbac955SMatthias Ringwald             mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it);
6687dbac955SMatthias Ringwald             printf("0x%02x:   START CHR ", characteristic->start_handle);
6697dbac955SMatthias Ringwald             if (characteristic->uuid16) {
6707dbac955SMatthias Ringwald                 printf("%04x\n", characteristic->uuid16);
6717dbac955SMatthias Ringwald             } else {
6727dbac955SMatthias Ringwald                 printf("%s\n", uuid128_to_str(characteristic->uuid128));
6737dbac955SMatthias Ringwald             }
6747dbac955SMatthias Ringwald             printf("0x%02x:   VALUE HANDLE CHR\n", characteristic->value_handle);
6757dbac955SMatthias Ringwald 
6767dbac955SMatthias Ringwald             btstack_linked_list_iterator_t desc_it;
6777dbac955SMatthias Ringwald             btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors);
6787dbac955SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&desc_it)){
6797dbac955SMatthias Ringwald                 mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it);
6807dbac955SMatthias Ringwald                 printf("0x%02x:     DESC 0x%02x\n", desc->handle, desc->uuid16);
6817dbac955SMatthias Ringwald             }
6827dbac955SMatthias Ringwald 
6837dbac955SMatthias Ringwald             printf("0x%02x:   END CHR 0%02x\n", characteristic->end_handle, characteristic->uuid16);
6847dbac955SMatthias Ringwald         }
6857dbac955SMatthias Ringwald         printf("0x%02x: END SERVICE 0%02x\n", service->end_group_handle, service->uuid16);
6867dbac955SMatthias Ringwald 
6877dbac955SMatthias Ringwald     }
6887dbac955SMatthias Ringwald }
6897dbac955SMatthias Ringwald 
6907dbac955SMatthias Ringwald static void mock_gatt_client_add_primary_service(void){
6917dbac955SMatthias Ringwald     // set lsat group handle
6927dbac955SMatthias Ringwald     // create new service
6937dbac955SMatthias Ringwald     mock_gatt_client_last_service = (mock_gatt_client_service_t * )malloc(sizeof(mock_gatt_client_service_t));
6947dbac955SMatthias Ringwald     memset(mock_gatt_client_last_service, 0, sizeof(mock_gatt_client_service_t));
6957dbac955SMatthias Ringwald     mock_gatt_client_last_service->start_group_handle = mock_gatt_client_att_handle_generator++;
6967dbac955SMatthias Ringwald     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_last_service->start_group_handle;
6977dbac955SMatthias Ringwald     btstack_linked_list_add_tail(&mock_gatt_client_services, (btstack_linked_item_t*)mock_gatt_client_last_service);
6987dbac955SMatthias Ringwald     mock_gatt_client_last_characteristic = NULL;
6997dbac955SMatthias Ringwald }
7007dbac955SMatthias Ringwald 
7017dbac955SMatthias Ringwald mock_gatt_client_service_t * mock_gatt_client_add_primary_service_uuid16(uint16_t service_uuid){
7027dbac955SMatthias Ringwald     mock_gatt_client_add_primary_service();
7037dbac955SMatthias Ringwald     mock_gatt_client_last_service->uuid16 = service_uuid;
7047dbac955SMatthias Ringwald     uuid_add_bluetooth_prefix(mock_gatt_client_last_service->uuid128, service_uuid);
7057dbac955SMatthias Ringwald     return mock_gatt_client_last_service;
7067dbac955SMatthias Ringwald }
7077dbac955SMatthias Ringwald mock_gatt_client_service_t * mock_gatt_client_add_primary_service_uuid128(const uint8_t * service_uuid){
7087dbac955SMatthias Ringwald     mock_gatt_client_add_primary_service();
7097dbac955SMatthias Ringwald     (void) memcpy(mock_gatt_client_last_service->uuid128, service_uuid, 16);
7107dbac955SMatthias Ringwald     return mock_gatt_client_last_service;
7117dbac955SMatthias Ringwald }
7127dbac955SMatthias Ringwald 
7137dbac955SMatthias Ringwald static void mock_gatt_client_add_characteristic(uint16_t properties){
7147dbac955SMatthias Ringwald     btstack_assert(mock_gatt_client_last_service != NULL);
7157dbac955SMatthias Ringwald     mock_gatt_client_last_characteristic = (mock_gatt_client_characteristic_t * )malloc(sizeof(mock_gatt_client_characteristic_t));
7167dbac955SMatthias Ringwald     memset(mock_gatt_client_last_characteristic, 0, sizeof(mock_gatt_client_characteristic_t));
7177dbac955SMatthias Ringwald     mock_gatt_client_last_characteristic->properties = properties;
7187dbac955SMatthias Ringwald     mock_gatt_client_last_characteristic->start_handle = mock_gatt_client_att_handle_generator++;
7197dbac955SMatthias Ringwald     mock_gatt_client_last_characteristic->value_handle = mock_gatt_client_att_handle_generator++;
7207dbac955SMatthias Ringwald     mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_last_characteristic->value_handle;
7217dbac955SMatthias Ringwald     btstack_linked_list_add_tail(&mock_gatt_client_last_service->characteristics, (btstack_linked_item_t*)mock_gatt_client_last_characteristic);
7227dbac955SMatthias Ringwald     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1;
7237dbac955SMatthias Ringwald }
7247dbac955SMatthias Ringwald 
7257dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * mock_gatt_client_add_characteristic_uuid16(uint16_t characteristic_uuid, uint16_t properties){
7267dbac955SMatthias Ringwald     mock_gatt_client_add_characteristic(properties);
7277dbac955SMatthias Ringwald     mock_gatt_client_last_characteristic->uuid16 = characteristic_uuid;
7287dbac955SMatthias Ringwald     uuid_add_bluetooth_prefix(mock_gatt_client_last_characteristic->uuid128, characteristic_uuid);
7297dbac955SMatthias Ringwald     return mock_gatt_client_last_characteristic;
7307dbac955SMatthias Ringwald }
7317dbac955SMatthias Ringwald 
7327dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * mock_gatt_client_add_characteristic_uuid128(const uint8_t * characteristic_uuid, uint16_t properties){
7337dbac955SMatthias Ringwald     mock_gatt_client_add_characteristic(properties);
7347dbac955SMatthias Ringwald     (void) memcpy(mock_gatt_client_last_characteristic->uuid128, characteristic_uuid, 16);
7357dbac955SMatthias Ringwald     return mock_gatt_client_last_characteristic;
7367dbac955SMatthias Ringwald }
7377dbac955SMatthias Ringwald 
7387dbac955SMatthias Ringwald static mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor(void){
7397dbac955SMatthias Ringwald     btstack_assert(mock_gatt_client_last_characteristic != NULL);
7407dbac955SMatthias Ringwald     mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t * )malloc(sizeof(mock_gatt_client_characteristic_descriptor_t));
7417dbac955SMatthias Ringwald     memset(desc, 0, sizeof(mock_gatt_client_characteristic_descriptor_t));
7427dbac955SMatthias Ringwald     desc->handle = mock_gatt_client_att_handle_generator++;
7437dbac955SMatthias Ringwald     btstack_linked_list_add_tail(&mock_gatt_client_last_characteristic->descriptors, (btstack_linked_item_t*)desc);
7447dbac955SMatthias Ringwald     mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_att_handle_generator - 1;
7457dbac955SMatthias Ringwald     mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1;
7467dbac955SMatthias Ringwald     return desc;
7477dbac955SMatthias Ringwald }
7487dbac955SMatthias Ringwald 
7497dbac955SMatthias Ringwald mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor_uuid16(uint16_t descriptor_uuid){
7507dbac955SMatthias Ringwald     mock_gatt_client_characteristic_descriptor_t * desc = mock_gatt_client_add_characteristic_descriptor();
7517dbac955SMatthias Ringwald     desc->uuid16 = descriptor_uuid;
7527dbac955SMatthias Ringwald     uuid_add_bluetooth_prefix(desc->uuid128, descriptor_uuid);
7537dbac955SMatthias Ringwald     return desc;
7547dbac955SMatthias Ringwald }
7557dbac955SMatthias Ringwald 
7567dbac955SMatthias Ringwald mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor_uuid128(const uint8_t * descriptor_uuid){
7577dbac955SMatthias Ringwald     mock_gatt_client_characteristic_descriptor_t * desc = mock_gatt_client_add_characteristic_descriptor();
7587dbac955SMatthias Ringwald     (void) memcpy(desc->uuid128, descriptor_uuid, 16);
7597dbac955SMatthias Ringwald     return desc;
7607dbac955SMatthias Ringwald }
7617dbac955SMatthias Ringwald 
7627dbac955SMatthias Ringwald void mock_gatt_client_set_descriptor_characteristic_value(mock_gatt_client_characteristic_descriptor_t * descriptor, uint8_t * value_buffer, uint16_t value_len){
7637dbac955SMatthias Ringwald     btstack_assert(descriptor != NULL);
7647dbac955SMatthias Ringwald     descriptor->value_buffer = value_buffer;
7657dbac955SMatthias Ringwald     descriptor->value_len = value_len;
7667dbac955SMatthias Ringwald }
7677dbac955SMatthias Ringwald 
7687dbac955SMatthias Ringwald void mock_gatt_client_set_characteristic_value(mock_gatt_client_characteristic_t * characteristic, uint8_t * value_buffer, uint16_t value_len){
7697dbac955SMatthias Ringwald     btstack_assert(characteristic != NULL);
7707dbac955SMatthias Ringwald     characteristic->value_buffer = value_buffer;
7717dbac955SMatthias Ringwald     characteristic->value_len = value_len;
7727dbac955SMatthias Ringwald }
7737dbac955SMatthias Ringwald 
7747dbac955SMatthias Ringwald // simulate error
7757dbac955SMatthias Ringwald void mock_gatt_client_simulate_att_error(uint8_t att_error){
7767dbac955SMatthias Ringwald     mock_gatt_client_att_error = att_error;
7777dbac955SMatthias Ringwald }
778