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" 8*7aa69c24SMatthias Ringwald #include "hci_event_builder.h" 90f7fd6c1SMilanka Ringwald 1043bef108SMatthias Ringwald //#include "CppUTest/TestHarness.h" 1143bef108SMatthias Ringwald //#include "CppUTestExt/MockSupport.h" 120f7fd6c1SMilanka Ringwald 13af770404SMilanka Ringwald static enum { 14af770404SMilanka Ringwald MOCK_QUERY_IDLE = 0, 157dbac955SMatthias Ringwald MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID, 167dbac955SMatthias Ringwald MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID, 177dbac955SMatthias Ringwald MOCK_QUERY_DISCOVER_ALL_CHARACTERISTICS, 1876cdba3eSMilanka Ringwald MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS, 1976cdba3eSMilanka Ringwald MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION, 207e693ad3SMilanka Ringwald MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE, 217e693ad3SMilanka Ringwald MOCK_READ_VALUE_OF_CHARACTERISTIC_DESCRIPTOR_USING_VALUE_HANDLE 22af770404SMilanka Ringwald } mock_gatt_client_state; 23af770404SMilanka Ringwald 2476cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_att_handle_generator; 2576cdba3eSMilanka Ringwald 26af770404SMilanka Ringwald static uint8_t mock_gatt_client_att_error; 277dbac955SMatthias Ringwald static uint8_t mock_gatt_client_uuid128[16]; 2876cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_value_handle; 2976cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_start_handle; 3076cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_end_handle; 3176cdba3eSMilanka Ringwald 32af770404SMilanka Ringwald static gatt_client_t gatt_client; 330f7fd6c1SMilanka Ringwald 347da2c1baSMilanka Ringwald static btstack_linked_list_t mock_gatt_client_services; 357da2c1baSMilanka Ringwald 367da2c1baSMilanka Ringwald static mock_gatt_client_service_t * mock_gatt_client_last_service; 377da2c1baSMilanka Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_last_characteristic; 387da2c1baSMilanka Ringwald 39ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_services; 40ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_characteristics; 41ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_characteristic_descriptors; 42e92f7a17SMilanka Ringwald static uint8_t moc_att_error_code_read_value_characteristics; 4386d0910fSMilanka Ringwald 44500d8180SMilanka Ringwald static btstack_linked_list_t event_packet_handlers; 45500d8180SMilanka Ringwald 46500d8180SMilanka Ringwald void hci_add_event_handler(btstack_packet_callback_registration_t * callback_handler){ 47500d8180SMilanka Ringwald btstack_linked_list_add_tail(&event_packet_handlers, (btstack_linked_item_t*) callback_handler); 48500d8180SMilanka Ringwald } 49500d8180SMilanka Ringwald 50500d8180SMilanka Ringwald void mock_hci_emit_event(uint8_t * packet, uint16_t size){ 51500d8180SMilanka Ringwald // dispatch to all event handlers 52500d8180SMilanka Ringwald btstack_linked_list_iterator_t it; 53500d8180SMilanka Ringwald btstack_linked_list_iterator_init(&it, &event_packet_handlers); 54500d8180SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 55500d8180SMilanka Ringwald btstack_packet_callback_registration_t * entry = (btstack_packet_callback_registration_t*) btstack_linked_list_iterator_next(&it); 56500d8180SMilanka Ringwald entry->callback(HCI_EVENT_PACKET, 0, packet, size); 57500d8180SMilanka Ringwald } 58500d8180SMilanka Ringwald } 59500d8180SMilanka Ringwald 60500d8180SMilanka Ringwald static void hci_create_gap_connection_complete_event(const uint8_t * hci_event, uint8_t * gap_event) { 61500d8180SMilanka Ringwald gap_event[0] = HCI_EVENT_META_GAP; 62500d8180SMilanka Ringwald gap_event[1] = 36 - 2; 63500d8180SMilanka Ringwald gap_event[2] = GAP_SUBEVENT_LE_CONNECTION_COMPLETE; 64500d8180SMilanka Ringwald switch (hci_event[2]){ 65500d8180SMilanka Ringwald case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: 66500d8180SMilanka Ringwald memcpy(&gap_event[3], &hci_event[3], 11); 67500d8180SMilanka Ringwald memset(&gap_event[14], 0, 12); 68500d8180SMilanka Ringwald memcpy(&gap_event[26], &hci_event[14], 7); 69500d8180SMilanka Ringwald memset(&gap_event[33], 0xff, 3); 70500d8180SMilanka Ringwald break; 71500d8180SMilanka Ringwald case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE_V1: 72500d8180SMilanka Ringwald memcpy(&gap_event[3], &hci_event[3], 30); 73500d8180SMilanka Ringwald memset(&gap_event[33], 0xff, 3); 74500d8180SMilanka Ringwald break; 75500d8180SMilanka Ringwald case HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE_V2: 76500d8180SMilanka Ringwald memcpy(&gap_event[3], &hci_event[3], 33); 77500d8180SMilanka Ringwald break; 78500d8180SMilanka Ringwald default: 79500d8180SMilanka Ringwald btstack_unreachable(); 80500d8180SMilanka Ringwald break; 81500d8180SMilanka Ringwald } 82500d8180SMilanka Ringwald } 83500d8180SMilanka Ringwald 84500d8180SMilanka 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){ 85500d8180SMilanka Ringwald uint8_t hci_event[21]; 86500d8180SMilanka Ringwald hci_event[0] = HCI_EVENT_LE_META; 87500d8180SMilanka Ringwald hci_event[1] = sizeof(hci_event) - 2u; 88500d8180SMilanka Ringwald hci_event[2] = HCI_SUBEVENT_LE_CONNECTION_COMPLETE; 89500d8180SMilanka Ringwald hci_event[3] = status; 90500d8180SMilanka Ringwald little_endian_store_16(hci_event, 4, con_handle); 91500d8180SMilanka Ringwald hci_event[6] = 0; // TODO: role 92500d8180SMilanka Ringwald hci_event[7] = address_type; 93500d8180SMilanka Ringwald reverse_bd_addr(address, &hci_event[8]); 94500d8180SMilanka Ringwald little_endian_store_16(hci_event, 14, 0); // interval 95500d8180SMilanka Ringwald little_endian_store_16(hci_event, 16, 0); // latency 96500d8180SMilanka Ringwald little_endian_store_16(hci_event, 18, 0); // supervision timeout 97500d8180SMilanka Ringwald hci_event[20] = 0; // master clock accuracy 98500d8180SMilanka Ringwald // emit GAP event, too 99500d8180SMilanka Ringwald uint8_t gap_event[36]; 100500d8180SMilanka Ringwald hci_create_gap_connection_complete_event(hci_event, gap_event); 101500d8180SMilanka Ringwald mock_hci_emit_event(gap_event, sizeof(gap_event)); 102500d8180SMilanka Ringwald } 103500d8180SMilanka Ringwald 104500d8180SMilanka Ringwald void mock_hci_emit_connection_encrypted(hci_con_handle_t con_handle, uint8_t encrypted){ 105500d8180SMilanka Ringwald uint8_t encryption_complete_event[6] = { HCI_EVENT_ENCRYPTION_CHANGE, 4, 0, 0, 0, 0}; 106500d8180SMilanka Ringwald little_endian_store_16(encryption_complete_event, 3, con_handle); 107500d8180SMilanka Ringwald encryption_complete_event[5] = encrypted; 108500d8180SMilanka Ringwald mock_hci_emit_event(encryption_complete_event, sizeof(encryption_complete_event)); 109500d8180SMilanka Ringwald } 110500d8180SMilanka Ringwald 111500d8180SMilanka Ringwald void mock_hci_emit_disconnection_complete(hci_con_handle_t con_handle, uint8_t reason){ 112500d8180SMilanka Ringwald uint8_t event[6]; 113500d8180SMilanka Ringwald event[0] = HCI_EVENT_DISCONNECTION_COMPLETE; 114500d8180SMilanka Ringwald event[1] = sizeof(event) - 2u; 115500d8180SMilanka Ringwald event[2] = 0; // status = OK 116500d8180SMilanka Ringwald little_endian_store_16(event, 3, con_handle); 117500d8180SMilanka Ringwald event[5] = reason; 118500d8180SMilanka Ringwald mock_hci_emit_event(event, sizeof(event)); 119500d8180SMilanka Ringwald } 120500d8180SMilanka Ringwald 121500d8180SMilanka Ringwald 122af770404SMilanka Ringwald /** 123af770404SMilanka Ringwald * copied from gatt_client.c - START 124af770404SMilanka Ringwald */ 1250f7fd6c1SMilanka Ringwald void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t * service){ 1260f7fd6c1SMilanka Ringwald service->start_group_handle = little_endian_read_16(packet, offset); 1270f7fd6c1SMilanka Ringwald service->end_group_handle = little_endian_read_16(packet, offset + 2); 1280f7fd6c1SMilanka Ringwald reverse_128(&packet[offset + 4], service->uuid128); 1290f7fd6c1SMilanka Ringwald if (uuid_has_bluetooth_prefix(service->uuid128)){ 1300f7fd6c1SMilanka Ringwald service->uuid16 = big_endian_read_32(service->uuid128, 0); 1310f7fd6c1SMilanka Ringwald } else { 1320f7fd6c1SMilanka Ringwald service->uuid16 = 0; 1330f7fd6c1SMilanka Ringwald } 1340f7fd6c1SMilanka Ringwald } 1350f7fd6c1SMilanka Ringwald 1360f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic(const uint8_t * packet, int offset, gatt_client_characteristic_t * characteristic){ 1370f7fd6c1SMilanka Ringwald characteristic->start_handle = little_endian_read_16(packet, offset); 1380f7fd6c1SMilanka Ringwald characteristic->value_handle = little_endian_read_16(packet, offset + 2); 1390f7fd6c1SMilanka Ringwald characteristic->end_handle = little_endian_read_16(packet, offset + 4); 1400f7fd6c1SMilanka Ringwald characteristic->properties = little_endian_read_16(packet, offset + 6); 1410f7fd6c1SMilanka Ringwald reverse_128(&packet[offset+8], characteristic->uuid128); 1420f7fd6c1SMilanka Ringwald if (uuid_has_bluetooth_prefix(characteristic->uuid128)){ 1430f7fd6c1SMilanka Ringwald characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0); 1440f7fd6c1SMilanka Ringwald } else { 1450f7fd6c1SMilanka Ringwald characteristic->uuid16 = 0; 1460f7fd6c1SMilanka Ringwald } 1470f7fd6c1SMilanka Ringwald } 1480f7fd6c1SMilanka Ringwald 1490f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic_descriptor(const uint8_t * packet, int offset, gatt_client_characteristic_descriptor_t * descriptor){ 1500f7fd6c1SMilanka Ringwald descriptor->handle = little_endian_read_16(packet, offset); 1510f7fd6c1SMilanka Ringwald reverse_128(&packet[offset+2], descriptor->uuid128); 1520f7fd6c1SMilanka Ringwald if (uuid_has_bluetooth_prefix(descriptor->uuid128)){ 1530f7fd6c1SMilanka Ringwald descriptor->uuid16 = big_endian_read_32(descriptor->uuid128, 0); 1540f7fd6c1SMilanka Ringwald } else { 1550f7fd6c1SMilanka Ringwald descriptor->uuid16 = 0; 1560f7fd6c1SMilanka Ringwald } 1570f7fd6c1SMilanka Ringwald } 1580f7fd6c1SMilanka Ringwald 159*7aa69c24SMatthias Ringwald static void emit_event_new(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){ 160af770404SMilanka Ringwald if (!callback) return; 161af770404SMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, packet, size); 1620f7fd6c1SMilanka Ringwald } 1630f7fd6c1SMilanka Ringwald 164af770404SMilanka Ringwald static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_status){ 165*7aa69c24SMatthias Ringwald // @format H122 166*7aa69c24SMatthias Ringwald uint8_t packet[9]; 167*7aa69c24SMatthias Ringwald hci_event_builder_context_t context; 168*7aa69c24SMatthias Ringwald hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_QUERY_COMPLETE, 0); 169*7aa69c24SMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 170*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->service_id); 171*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->connection_id); 172*7aa69c24SMatthias Ringwald hci_event_builder_add_08(&context, att_status); 173*7aa69c24SMatthias Ringwald emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context)); 1740f7fd6c1SMilanka Ringwald } 1750f7fd6c1SMilanka Ringwald 1767da2c1baSMilanka 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){ 177*7aa69c24SMatthias Ringwald // @format H22X 178*7aa69c24SMatthias Ringwald uint8_t packet[28]; 179*7aa69c24SMatthias Ringwald hci_event_builder_context_t context; 180*7aa69c24SMatthias Ringwald hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_SERVICE_QUERY_RESULT, 0); 181*7aa69c24SMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 182*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->service_id); 183*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->connection_id); 184*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, start_group_handle); 185*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, end_group_handle); 186*7aa69c24SMatthias Ringwald hci_event_builder_add_128(&context, uuid128); 187*7aa69c24SMatthias Ringwald emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context)); 1887da2c1baSMilanka Ringwald } 1897da2c1baSMilanka Ringwald 1907da2c1baSMilanka 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, 1917da2c1baSMilanka Ringwald uint16_t properties, const uint8_t * uuid128){ 192*7aa69c24SMatthias Ringwald // @format H22Y 193*7aa69c24SMatthias Ringwald uint8_t packet[32]; 194*7aa69c24SMatthias Ringwald hci_event_builder_context_t context; 195*7aa69c24SMatthias Ringwald hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_CHARACTERISTIC_QUERY_RESULT, 0); 196*7aa69c24SMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 197*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->service_id); 198*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->connection_id); 199*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, start_handle); 200*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, value_handle); 201*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, end_handle); 202*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, properties); 203*7aa69c24SMatthias Ringwald hci_event_builder_add_128(&context, uuid128); 204*7aa69c24SMatthias Ringwald emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context)); 2057da2c1baSMilanka Ringwald } 2067da2c1baSMilanka Ringwald 20776cdba3eSMilanka Ringwald static void emit_gatt_all_characteristic_descriptors_result_event( 20876cdba3eSMilanka Ringwald gatt_client_t * gatt_client, uint16_t descriptor_handle, const uint8_t * uuid128){ 20976cdba3eSMilanka Ringwald // @format HZ 21076cdba3eSMilanka Ringwald uint8_t packet[22]; 211*7aa69c24SMatthias Ringwald hci_event_builder_context_t context; 212*7aa69c24SMatthias Ringwald hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT, 0); 213*7aa69c24SMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 214*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->service_id); 215*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->connection_id); 216*7aa69c24SMatthias Ringwald hci_event_builder_add_16(&context, descriptor_handle); 217*7aa69c24SMatthias Ringwald hci_event_builder_add_128(&context, uuid128); 218*7aa69c24SMatthias Ringwald emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context)); 21976cdba3eSMilanka Ringwald } 22076cdba3eSMilanka Ringwald 2217e693ad3SMilanka Ringwald static uint8_t event_packet[255]; 22276cdba3eSMilanka 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){ 22376cdba3eSMilanka Ringwald // before the value inside the ATT PDU 2247e693ad3SMilanka Ringwald event_packet[0] = type; 225*7aa69c24SMatthias Ringwald event_packet[1] = 10 + length; 2267e693ad3SMilanka Ringwald little_endian_store_16(event_packet, 2, con_handle); 227*7aa69c24SMatthias Ringwald little_endian_store_16(event_packet, 4, 0); 228*7aa69c24SMatthias Ringwald little_endian_store_16(event_packet, 6, 0); 229*7aa69c24SMatthias Ringwald little_endian_store_16(event_packet, 8, attribute_handle); 230*7aa69c24SMatthias Ringwald little_endian_store_16(event_packet, 10, length); 231*7aa69c24SMatthias Ringwald memcpy(&event_packet[12], value, length); 2327e693ad3SMilanka Ringwald return &event_packet[0]; 23376cdba3eSMilanka Ringwald } 23476cdba3eSMilanka Ringwald 2357dbac955SMatthias 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){ 2367e693ad3SMilanka Ringwald btstack_assert(characteristic != NULL); 2377e693ad3SMilanka Ringwald btstack_assert(characteristic->notification != NULL); 2387e693ad3SMilanka Ringwald btstack_assert(characteristic->notification->callback != NULL); 2397dbac955SMatthias Ringwald uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_NOTIFICATION, gatt_client.con_handle, value_handle, (uint8_t *) value_buffer, value_len); 240*7aa69c24SMatthias Ringwald emit_event_new(characteristic->notification->callback, packet, 2 + packet[1]); 2417e693ad3SMilanka Ringwald } 2427e693ad3SMilanka Ringwald 2437dbac955SMatthias Ringwald void mock_gatt_client_send_notification(mock_gatt_client_characteristic_t * characteristic, const uint8_t * value_buffer, uint16_t value_len){ 2447e693ad3SMilanka Ringwald mock_gatt_client_send_notification_with_handle(characteristic, characteristic->value_handle, value_buffer, value_len); 2457e693ad3SMilanka Ringwald } 2467e693ad3SMilanka Ringwald 2477dbac955SMatthias 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){ 2487dbac955SMatthias Ringwald btstack_assert(characteristic != NULL); 2497dbac955SMatthias Ringwald btstack_assert(characteristic->notification != NULL); 2507dbac955SMatthias Ringwald btstack_assert(characteristic->notification->callback != NULL); 2517dbac955SMatthias Ringwald uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_INDICATION, gatt_client.con_handle, value_handle, (uint8_t *) value_buffer, value_len); 252*7aa69c24SMatthias Ringwald emit_event_new(characteristic->notification->callback, packet, 2 + packet[1]); 2537dbac955SMatthias Ringwald } 2547dbac955SMatthias Ringwald 2557dbac955SMatthias Ringwald void mock_gatt_client_send_indication(mock_gatt_client_characteristic_t * characteristic, const uint8_t * value_buffer, uint16_t value_len){ 2567dbac955SMatthias Ringwald mock_gatt_client_send_indication_with_handle(characteristic, characteristic->value_handle, value_buffer, value_len); 2577dbac955SMatthias Ringwald } 2587dbac955SMatthias Ringwald 2597e693ad3SMilanka Ringwald static void mock_gatt_client_send_characteristic_value(gatt_client_t * gatt_client, mock_gatt_client_characteristic_t * characteristic){ 2607e693ad3SMilanka 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); 261*7aa69c24SMatthias Ringwald emit_event_new(gatt_client->callback, packet, 2 + packet[1]); 26276cdba3eSMilanka Ringwald } 26376cdba3eSMilanka Ringwald 264af770404SMilanka Ringwald /** 265af770404SMilanka Ringwald * copied from gatt_client.c - END 266af770404SMilanka Ringwald */ 2670f7fd6c1SMilanka Ringwald 2687dbac955SMatthias Ringwald 2697dbac955SMatthias Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_get_characteristic_for_value_handle(uint16_t value_handle){ 2707dbac955SMatthias Ringwald btstack_linked_list_iterator_t service_it; 2717dbac955SMatthias Ringwald btstack_linked_list_iterator_t characteristic_it; 2727dbac955SMatthias Ringwald 2737dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 2747dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 2757dbac955SMatthias Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 2767dbac955SMatthias Ringwald 2777dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 2787dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 2797dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 2807dbac955SMatthias Ringwald if (characteristic->value_handle != value_handle) continue; 2817dbac955SMatthias Ringwald return characteristic; 2827dbac955SMatthias Ringwald } 2837dbac955SMatthias Ringwald } 2847dbac955SMatthias Ringwald return NULL; 2857dbac955SMatthias Ringwald } 2867dbac955SMatthias Ringwald 287e92f7a17SMilanka Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_get_characteristic_for_uuid16(uint16_t uuid16){ 288e92f7a17SMilanka Ringwald btstack_linked_list_iterator_t service_it; 289e92f7a17SMilanka Ringwald btstack_linked_list_iterator_t characteristic_it; 290e92f7a17SMilanka Ringwald 291e92f7a17SMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 292e92f7a17SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 293e92f7a17SMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 294e92f7a17SMilanka Ringwald 295e92f7a17SMilanka Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 296e92f7a17SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 297e92f7a17SMilanka Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 298e92f7a17SMilanka Ringwald if (characteristic->uuid16 != uuid16) continue; 299e92f7a17SMilanka Ringwald return characteristic; 300e92f7a17SMilanka Ringwald } 301e92f7a17SMilanka Ringwald } 302e92f7a17SMilanka Ringwald return NULL; 303e92f7a17SMilanka Ringwald } 304e92f7a17SMilanka Ringwald 3057dbac955SMatthias Ringwald static mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_get_characteristic_descriptor_for_handle(uint16_t handle){ 3067dbac955SMatthias Ringwald btstack_linked_list_iterator_t service_it; 3077dbac955SMatthias Ringwald btstack_linked_list_iterator_t characteristic_it; 3087dbac955SMatthias Ringwald 3097dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 3107dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 3117dbac955SMatthias Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 3127dbac955SMatthias Ringwald 3137dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 3147dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 3157dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 3167dbac955SMatthias Ringwald 3177dbac955SMatthias Ringwald btstack_linked_list_iterator_t desc_it; 3187dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors); 3197dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&desc_it)){ 3207dbac955SMatthias Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it); 3217dbac955SMatthias Ringwald if (desc->handle != handle) continue; 3227dbac955SMatthias Ringwald return desc; 3237dbac955SMatthias Ringwald } 3247dbac955SMatthias Ringwald } 3257dbac955SMatthias Ringwald } 3267dbac955SMatthias Ringwald return NULL; 3277dbac955SMatthias Ringwald } 3287dbac955SMatthias Ringwald 3297dbac955SMatthias Ringwald uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){ 3307dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID; 3317dbac955SMatthias Ringwald uuid_add_bluetooth_prefix(mock_gatt_client_uuid128, uuid16); 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_primary_services_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, const uint8_t * uuid128){ 3387dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID; 3397dbac955SMatthias Ringwald memcpy(mock_gatt_client_uuid128, uuid128, 16); 3407dbac955SMatthias Ringwald gatt_client.callback = callback; 3417dbac955SMatthias Ringwald gatt_client.con_handle = con_handle; 3427dbac955SMatthias Ringwald return ERROR_CODE_SUCCESS; 3437dbac955SMatthias Ringwald } 3447dbac955SMatthias Ringwald 3457dbac955SMatthias 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){ 3467dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID; 3477dbac955SMatthias Ringwald uuid_add_bluetooth_prefix(mock_gatt_client_uuid128, uuid16); 3487dbac955SMatthias Ringwald mock_gatt_client_start_handle = start_handle; 3497dbac955SMatthias Ringwald mock_gatt_client_end_handle = end_handle; 3507dbac955SMatthias Ringwald 3517dbac955SMatthias Ringwald gatt_client.callback = callback; 3527dbac955SMatthias Ringwald gatt_client.con_handle = con_handle; 3537dbac955SMatthias Ringwald return ERROR_CODE_SUCCESS; 3547dbac955SMatthias Ringwald } 3557dbac955SMatthias Ringwald 3567dbac955SMatthias 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){ 3577dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_QUERY_DISCOVER_ALL_CHARACTERISTICS; 3587dbac955SMatthias Ringwald mock_gatt_client_start_handle = service->start_group_handle; 3597dbac955SMatthias Ringwald mock_gatt_client_end_handle = service->end_group_handle; 3607dbac955SMatthias Ringwald gatt_client.callback = callback; 3617dbac955SMatthias Ringwald gatt_client.con_handle = con_handle; 3627dbac955SMatthias Ringwald return ERROR_CODE_SUCCESS; 3637dbac955SMatthias Ringwald } 3647dbac955SMatthias Ringwald 3657dbac955SMatthias Ringwald uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){ 3667dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS; 3677dbac955SMatthias Ringwald mock_gatt_client_value_handle = characteristic->value_handle; 3687dbac955SMatthias Ringwald 3697dbac955SMatthias Ringwald gatt_client.callback = callback; 3707dbac955SMatthias Ringwald gatt_client.con_handle = con_handle; 3717dbac955SMatthias Ringwald return ERROR_CODE_SUCCESS; 3727dbac955SMatthias Ringwald } 3737dbac955SMatthias Ringwald 3747dbac955SMatthias 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){ 3757dbac955SMatthias Ringwald btstack_assert(notification != NULL); 3767dbac955SMatthias Ringwald btstack_assert(&callback != NULL); 3777dbac955SMatthias Ringwald 3787dbac955SMatthias Ringwald notification->callback = callback; 3797dbac955SMatthias Ringwald notification->con_handle = con_handle; 3807dbac955SMatthias Ringwald 3817dbac955SMatthias Ringwald 3827dbac955SMatthias Ringwald if (characteristic == NULL){ 3837dbac955SMatthias Ringwald // 'all characteristics': not used yet 3847dbac955SMatthias Ringwald btstack_assert(false); 3857dbac955SMatthias Ringwald } else { 3867dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle); 3877dbac955SMatthias Ringwald btstack_assert(mock_characteristic != NULL); 3887dbac955SMatthias Ringwald 3897dbac955SMatthias Ringwald notification->attribute_handle = characteristic->value_handle; 3907dbac955SMatthias Ringwald mock_characteristic->notification = notification; 3917dbac955SMatthias Ringwald } 3927dbac955SMatthias Ringwald } 3937dbac955SMatthias Ringwald 3947dbac955SMatthias 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){ 3957dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle); 3967dbac955SMatthias Ringwald btstack_assert(mock_characteristic != NULL); 3977dbac955SMatthias Ringwald 3987dbac955SMatthias Ringwald if (mock_characteristic->notification_status_code != ERROR_CODE_SUCCESS){ 3997dbac955SMatthias Ringwald return mock_characteristic->notification_status_code; 4007dbac955SMatthias Ringwald } 4017dbac955SMatthias Ringwald 4027dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION; 4037dbac955SMatthias Ringwald 4047dbac955SMatthias Ringwald gatt_client.callback = callback; 4057dbac955SMatthias Ringwald gatt_client.con_handle = con_handle; 4067dbac955SMatthias Ringwald return ERROR_CODE_SUCCESS; 4077dbac955SMatthias Ringwald } 4087dbac955SMatthias Ringwald 409e92f7a17SMilanka 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){ 410e92f7a17SMilanka Ringwald mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE; 411e92f7a17SMilanka Ringwald 412e92f7a17SMilanka Ringwald mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_uuid16(uuid16); 413e92f7a17SMilanka Ringwald if (mock_characteristic != NULL){ 414e92f7a17SMilanka Ringwald mock_gatt_client_value_handle = mock_characteristic->value_handle; 415e92f7a17SMilanka Ringwald gatt_client.callback = callback; 416e92f7a17SMilanka Ringwald gatt_client.con_handle = con_handle; 417e92f7a17SMilanka Ringwald } 418e92f7a17SMilanka Ringwald return ERROR_CODE_SUCCESS; 419e92f7a17SMilanka Ringwald } 420e92f7a17SMilanka Ringwald 4217dbac955SMatthias 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){ 4227dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE; 4237dbac955SMatthias Ringwald 4247dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(value_handle); 4257dbac955SMatthias Ringwald btstack_assert(mock_characteristic != NULL); 4267dbac955SMatthias Ringwald 4277dbac955SMatthias Ringwald mock_gatt_client_value_handle = mock_characteristic->value_handle; 4287dbac955SMatthias Ringwald gatt_client.callback = callback; 4297dbac955SMatthias Ringwald gatt_client.con_handle = con_handle; 4307dbac955SMatthias Ringwald return ERROR_CODE_SUCCESS; 4317dbac955SMatthias Ringwald } 4327dbac955SMatthias Ringwald 4337dbac955SMatthias 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){ 4347dbac955SMatthias Ringwald btstack_assert(characteristic != NULL); 4357dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE; 4367dbac955SMatthias Ringwald 4377dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle); 4387dbac955SMatthias Ringwald btstack_assert(mock_characteristic != NULL); 4397dbac955SMatthias Ringwald 4407dbac955SMatthias Ringwald gatt_client.callback = callback; 4417dbac955SMatthias Ringwald gatt_client.con_handle = con_handle; 4427dbac955SMatthias Ringwald mock_gatt_client_value_handle = mock_characteristic->value_handle; 4437dbac955SMatthias Ringwald return ERROR_CODE_SUCCESS; 4447dbac955SMatthias Ringwald } 4457dbac955SMatthias Ringwald 4467dbac955SMatthias 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){ 4477dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_DESCRIPTOR_USING_VALUE_HANDLE; 4487dbac955SMatthias Ringwald mock_gatt_client_value_handle = descriptor_handle; 4497dbac955SMatthias Ringwald return ERROR_CODE_SUCCESS; 4507dbac955SMatthias Ringwald } 4517dbac955SMatthias Ringwald 4527dbac955SMatthias Ringwald void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification){ 4537dbac955SMatthias Ringwald } 4547dbac955SMatthias Ringwald 4557dbac955SMatthias 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){ 4567dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(value_handle); 4577dbac955SMatthias Ringwald btstack_assert(mock_characteristic != NULL); 4587dbac955SMatthias Ringwald 4597dbac955SMatthias Ringwald if (mock_characteristic->notification_status_code != ERROR_CODE_SUCCESS){ 4607dbac955SMatthias Ringwald return mock_characteristic->notification_status_code; 4617dbac955SMatthias Ringwald } 4627dbac955SMatthias Ringwald 4637dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION; 4647dbac955SMatthias Ringwald 4657dbac955SMatthias Ringwald gatt_client.callback = callback; 4667dbac955SMatthias Ringwald gatt_client.con_handle = con_handle; 4677dbac955SMatthias Ringwald return ERROR_CODE_SUCCESS; 4687dbac955SMatthias Ringwald } 4697dbac955SMatthias Ringwald 4707e693ad3SMilanka Ringwald void mock_gatt_client_emit_complete(uint8_t status){ 4717da2c1baSMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_IDLE; 4727da2c1baSMilanka Ringwald emit_gatt_complete_event(&gatt_client, status); 4737da2c1baSMilanka Ringwald } 4740f7fd6c1SMilanka Ringwald 4757e693ad3SMilanka Ringwald void mock_gatt_client_run_once(void){ 476af770404SMilanka Ringwald btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE); 47776cdba3eSMilanka Ringwald mock_gatt_client_characteristic_t * characteristic; 47876cdba3eSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * descriptor; 47976cdba3eSMilanka Ringwald 4807da2c1baSMilanka Ringwald btstack_linked_list_iterator_t service_it; 4817da2c1baSMilanka Ringwald btstack_linked_list_iterator_t characteristic_it; 48276cdba3eSMilanka Ringwald btstack_linked_list_iterator_t descriptor_it; 48376cdba3eSMilanka Ringwald 484af770404SMilanka Ringwald switch (mock_gatt_client_state){ 4857dbac955SMatthias Ringwald case MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID: 486af770404SMilanka Ringwald // emit GATT_EVENT_SERVICE_QUERY_RESULT for each matching service 487ec1a0daeSMilanka Ringwald if (moc_att_error_code_discover_services != ATT_ERROR_SUCCESS){ 488ec1a0daeSMilanka Ringwald mock_gatt_client_emit_complete(moc_att_error_code_discover_services); 489ec1a0daeSMilanka Ringwald return; 490ec1a0daeSMilanka Ringwald } 491ec1a0daeSMilanka Ringwald 4927da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 4937da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 4947da2c1baSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 4957dbac955SMatthias Ringwald if (memcmp(service->uuid128, mock_gatt_client_uuid128, 16) != 0) continue; 4967da2c1baSMilanka Ringwald mock_gatt_client_last_service = service; 4977dbac955SMatthias Ringwald emit_gatt_service_query_result_event(&gatt_client, service->start_group_handle, service->end_group_handle, service->uuid128); 4987da2c1baSMilanka Ringwald } 4997da2c1baSMilanka Ringwald // emit GATT_EVENT_QUERY_COMPLETE 5007da2c1baSMilanka Ringwald mock_gatt_client_emit_complete(ATT_ERROR_SUCCESS); 5017da2c1baSMilanka Ringwald break; 5027da2c1baSMilanka Ringwald 5037dbac955SMatthias Ringwald case MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID: 5047dbac955SMatthias Ringwald case MOCK_QUERY_DISCOVER_ALL_CHARACTERISTICS: 5057da2c1baSMilanka Ringwald // emit GATT_EVENT_CHARACTERISTIC_QUERY_RESULT for each matching characteristic 506ec1a0daeSMilanka Ringwald if (moc_att_error_code_discover_characteristics != ATT_ERROR_SUCCESS){ 507ec1a0daeSMilanka Ringwald mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristics); 508ec1a0daeSMilanka Ringwald return; 509ec1a0daeSMilanka Ringwald } 510ec1a0daeSMilanka Ringwald 5117da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 5127da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 5137da2c1baSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 5147da2c1baSMilanka Ringwald 5157da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 5167da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 5177da2c1baSMilanka Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 51876cdba3eSMilanka Ringwald if (characteristic->start_handle < mock_gatt_client_start_handle) continue; 51976cdba3eSMilanka Ringwald if (characteristic->end_handle > mock_gatt_client_end_handle) continue; 5207dbac955SMatthias Ringwald if ((mock_gatt_client_state == MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID) && (memcmp(characteristic->uuid128, mock_gatt_client_uuid128, 16) != 0)) continue; 52176cdba3eSMilanka Ringwald 52276cdba3eSMilanka Ringwald emit_gatt_characteristic_query_result_event(&gatt_client, 52376cdba3eSMilanka Ringwald characteristic->start_handle, characteristic->value_handle, characteristic->end_handle, 5247dbac955SMatthias Ringwald characteristic->properties, characteristic->uuid128); 5257da2c1baSMilanka Ringwald } 5267da2c1baSMilanka Ringwald } 5277da2c1baSMilanka Ringwald 5287da2c1baSMilanka Ringwald // emit GATT_EVENT_QUERY_COMPLETE 5297da2c1baSMilanka Ringwald mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); 530af770404SMilanka Ringwald break; 53176cdba3eSMilanka Ringwald 53276cdba3eSMilanka Ringwald case MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS: 53376cdba3eSMilanka Ringwald characteristic = mock_gatt_client_get_characteristic_for_value_handle(mock_gatt_client_value_handle); 53476cdba3eSMilanka Ringwald btstack_assert(characteristic != NULL); 53576cdba3eSMilanka Ringwald 536ec1a0daeSMilanka Ringwald if (moc_att_error_code_discover_characteristic_descriptors != ATT_ERROR_SUCCESS){ 537ec1a0daeSMilanka Ringwald mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristic_descriptors); 538ec1a0daeSMilanka Ringwald return; 539ec1a0daeSMilanka Ringwald } 540ec1a0daeSMilanka Ringwald 54176cdba3eSMilanka Ringwald btstack_linked_list_iterator_init(&descriptor_it, &characteristic->descriptors); 54276cdba3eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&descriptor_it)){ 54376cdba3eSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&descriptor_it); 54476cdba3eSMilanka Ringwald 5457dbac955SMatthias Ringwald emit_gatt_all_characteristic_descriptors_result_event(&gatt_client, desc->handle, desc->uuid128); 54676cdba3eSMilanka Ringwald } 54776cdba3eSMilanka Ringwald 54876cdba3eSMilanka Ringwald // emit GATT_EVENT_QUERY_COMPLETE 54976cdba3eSMilanka Ringwald mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); 55076cdba3eSMilanka Ringwald break; 55176cdba3eSMilanka Ringwald 55276cdba3eSMilanka Ringwald case MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION: 55376cdba3eSMilanka Ringwald mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); 55476cdba3eSMilanka Ringwald break; 55576cdba3eSMilanka Ringwald 55676cdba3eSMilanka Ringwald case MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE: 5577e693ad3SMilanka Ringwald characteristic = mock_gatt_client_get_characteristic_for_value_handle(mock_gatt_client_value_handle); 558e92f7a17SMilanka Ringwald if (moc_att_error_code_read_value_characteristics != ATT_ERROR_SUCCESS){ 559e92f7a17SMilanka Ringwald mock_gatt_client_emit_complete(moc_att_error_code_read_value_characteristics); 560e92f7a17SMilanka Ringwald break; 561e92f7a17SMilanka Ringwald } 562e92f7a17SMilanka Ringwald if (characteristic != NULL){ 5637e693ad3SMilanka Ringwald mock_gatt_client_send_characteristic_value(&gatt_client, characteristic); 564e92f7a17SMilanka Ringwald } 5657e693ad3SMilanka Ringwald mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); 5667e693ad3SMilanka Ringwald break; 5677e693ad3SMilanka Ringwald 5687e693ad3SMilanka Ringwald case MOCK_READ_VALUE_OF_CHARACTERISTIC_DESCRIPTOR_USING_VALUE_HANDLE: 56976cdba3eSMilanka Ringwald descriptor = mock_gatt_client_get_characteristic_descriptor_for_handle(mock_gatt_client_value_handle); 57076cdba3eSMilanka Ringwald btstack_assert(descriptor != NULL); 57176cdba3eSMilanka Ringwald btstack_assert(descriptor->value_buffer != NULL); 57276cdba3eSMilanka Ringwald 57376cdba3eSMilanka Ringwald mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); 57476cdba3eSMilanka Ringwald break; 57576cdba3eSMilanka Ringwald 576af770404SMilanka Ringwald default: 577af770404SMilanka Ringwald btstack_assert(false); 578af770404SMilanka Ringwald break; 5790f7fd6c1SMilanka Ringwald } 5807da2c1baSMilanka Ringwald } 5817e693ad3SMilanka Ringwald 5827e693ad3SMilanka Ringwald void mock_gatt_client_run(void){ 5837e693ad3SMilanka Ringwald btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE); 5847e693ad3SMilanka Ringwald while (mock_gatt_client_state != MOCK_QUERY_IDLE){ 5857e693ad3SMilanka Ringwald mock_gatt_client_run_once(); 5867e693ad3SMilanka Ringwald } 5877da2c1baSMilanka Ringwald mock_gatt_client_att_error = ERROR_CODE_SUCCESS; 588af770404SMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_IDLE; 5890f7fd6c1SMilanka Ringwald } 5907e693ad3SMilanka Ringwald 5917e693ad3SMilanka Ringwald void mock_gatt_client_emit_dummy_event(void){ 5927e693ad3SMilanka Ringwald // @format H1 5937e693ad3SMilanka Ringwald uint8_t packet[2]; 5947e693ad3SMilanka Ringwald packet[0] = 0; 5957e693ad3SMilanka Ringwald packet[1] = 0; 596*7aa69c24SMatthias Ringwald emit_event_new(gatt_client.callback, packet, sizeof(packet)); 5977e693ad3SMilanka Ringwald } 5987dbac955SMatthias Ringwald 5997dbac955SMatthias Ringwald static void mock_gatt_client_reset_errors(void){ 6007dbac955SMatthias Ringwald moc_att_error_code_discover_services = ATT_ERROR_SUCCESS; 6017dbac955SMatthias Ringwald moc_att_error_code_discover_characteristics = ATT_ERROR_SUCCESS; 6027dbac955SMatthias Ringwald moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_SUCCESS; 603e92f7a17SMilanka Ringwald moc_att_error_code_read_value_characteristics = ATT_ERROR_SUCCESS; 6047dbac955SMatthias Ringwald } 6057dbac955SMatthias Ringwald 6067dbac955SMatthias Ringwald void mock_gatt_client_reset(void){ 6077dbac955SMatthias Ringwald mock_gatt_client_att_error = 0; 6087dbac955SMatthias Ringwald mock_gatt_client_state = MOCK_QUERY_IDLE; 6097dbac955SMatthias Ringwald mock_gatt_client_att_handle_generator = 0; 6107dbac955SMatthias Ringwald mock_gatt_client_last_service = NULL; 6117dbac955SMatthias Ringwald 6127dbac955SMatthias Ringwald mock_gatt_client_reset_errors(); 6137dbac955SMatthias Ringwald 6147dbac955SMatthias Ringwald btstack_linked_list_iterator_t service_it; 6157dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 6167dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 6177dbac955SMatthias Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 6187dbac955SMatthias Ringwald btstack_linked_list_remove(&mock_gatt_client_services, (btstack_linked_item_t *) service); 6197dbac955SMatthias Ringwald 6207dbac955SMatthias Ringwald btstack_linked_list_iterator_t characteristic_it; 6217dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 6227dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 6237dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 6247dbac955SMatthias Ringwald btstack_linked_list_remove(&service->characteristics, (btstack_linked_item_t *) characteristic); 6257dbac955SMatthias Ringwald 6267dbac955SMatthias Ringwald btstack_linked_list_iterator_t desc_it; 6277dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors); 6287dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&desc_it)){ 6297dbac955SMatthias Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it); 6307dbac955SMatthias Ringwald btstack_linked_list_remove(&characteristic->descriptors, (btstack_linked_item_t *) desc); 6317dbac955SMatthias Ringwald free(desc); 6327dbac955SMatthias Ringwald } 6337dbac955SMatthias Ringwald free(characteristic); 6347dbac955SMatthias Ringwald } 6357dbac955SMatthias Ringwald free(service); 6367dbac955SMatthias Ringwald } 6377dbac955SMatthias Ringwald } 6387dbac955SMatthias Ringwald 6397dbac955SMatthias Ringwald void mock_gatt_client_set_att_error_discover_primary_services(void){ 6407dbac955SMatthias Ringwald moc_att_error_code_discover_services = ATT_ERROR_REQUEST_NOT_SUPPORTED; 6417dbac955SMatthias Ringwald } 6427dbac955SMatthias Ringwald void mock_gatt_client_set_att_error_discover_characteristics(void){ 6437dbac955SMatthias Ringwald moc_att_error_code_discover_characteristics = ATT_ERROR_REQUEST_NOT_SUPPORTED; 6447dbac955SMatthias Ringwald } 6457dbac955SMatthias Ringwald void mock_gatt_client_set_att_error_discover_characteristic_descriptors(void){ 6467dbac955SMatthias Ringwald moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_REQUEST_NOT_SUPPORTED; 6477dbac955SMatthias Ringwald } 648e92f7a17SMilanka Ringwald void mock_gatt_client_set_att_error_read_value_characteristics(void){ 649e92f7a17SMilanka Ringwald moc_att_error_code_read_value_characteristics = ATT_ERROR_REQUEST_NOT_SUPPORTED; 6507dbac955SMatthias Ringwald } 6517dbac955SMatthias Ringwald 6527dbac955SMatthias Ringwald void mock_gatt_client_enable_notification(mock_gatt_client_characteristic_t * characteristic, bool command_allowed){ 6537dbac955SMatthias Ringwald if (command_allowed){ 6547dbac955SMatthias Ringwald characteristic->notification_status_code = ERROR_CODE_SUCCESS; 6557dbac955SMatthias Ringwald } else { 6567dbac955SMatthias Ringwald characteristic->notification_status_code = ERROR_CODE_COMMAND_DISALLOWED; 6577dbac955SMatthias Ringwald } 6587dbac955SMatthias Ringwald } 6597dbac955SMatthias Ringwald 6607dbac955SMatthias Ringwald void mock_gatt_client_dump_services(void){ 6617dbac955SMatthias Ringwald btstack_linked_list_iterator_t service_it; 6627dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 6637dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 6647dbac955SMatthias Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 6657dbac955SMatthias Ringwald printf("0x%02x: START SERVICE ", service->start_group_handle); 6667dbac955SMatthias Ringwald if (service->uuid16) { 6677dbac955SMatthias Ringwald printf("%04x\n", service->uuid16); 6687dbac955SMatthias Ringwald } else { 6697dbac955SMatthias Ringwald printf("%s\n", uuid128_to_str(service->uuid128)); 6707dbac955SMatthias Ringwald } 6717dbac955SMatthias Ringwald 6727dbac955SMatthias Ringwald btstack_linked_list_iterator_t characteristic_it; 6737dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 6747dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 6757dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 6767dbac955SMatthias Ringwald printf("0x%02x: START CHR ", characteristic->start_handle); 6777dbac955SMatthias Ringwald if (characteristic->uuid16) { 6787dbac955SMatthias Ringwald printf("%04x\n", characteristic->uuid16); 6797dbac955SMatthias Ringwald } else { 6807dbac955SMatthias Ringwald printf("%s\n", uuid128_to_str(characteristic->uuid128)); 6817dbac955SMatthias Ringwald } 6827dbac955SMatthias Ringwald printf("0x%02x: VALUE HANDLE CHR\n", characteristic->value_handle); 6837dbac955SMatthias Ringwald 6847dbac955SMatthias Ringwald btstack_linked_list_iterator_t desc_it; 6857dbac955SMatthias Ringwald btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors); 6867dbac955SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&desc_it)){ 6877dbac955SMatthias Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it); 6887dbac955SMatthias Ringwald printf("0x%02x: DESC 0x%02x\n", desc->handle, desc->uuid16); 6897dbac955SMatthias Ringwald } 6907dbac955SMatthias Ringwald 6917dbac955SMatthias Ringwald printf("0x%02x: END CHR 0%02x\n", characteristic->end_handle, characteristic->uuid16); 6927dbac955SMatthias Ringwald } 6937dbac955SMatthias Ringwald printf("0x%02x: END SERVICE 0%02x\n", service->end_group_handle, service->uuid16); 6947dbac955SMatthias Ringwald 6957dbac955SMatthias Ringwald } 6967dbac955SMatthias Ringwald } 6977dbac955SMatthias Ringwald 6987dbac955SMatthias Ringwald static void mock_gatt_client_add_primary_service(void){ 6997dbac955SMatthias Ringwald // set lsat group handle 7007dbac955SMatthias Ringwald // create new service 7017dbac955SMatthias Ringwald mock_gatt_client_last_service = (mock_gatt_client_service_t * )malloc(sizeof(mock_gatt_client_service_t)); 7027dbac955SMatthias Ringwald memset(mock_gatt_client_last_service, 0, sizeof(mock_gatt_client_service_t)); 7037dbac955SMatthias Ringwald mock_gatt_client_last_service->start_group_handle = mock_gatt_client_att_handle_generator++; 7047dbac955SMatthias Ringwald mock_gatt_client_last_service->end_group_handle = mock_gatt_client_last_service->start_group_handle; 7057dbac955SMatthias Ringwald btstack_linked_list_add_tail(&mock_gatt_client_services, (btstack_linked_item_t*)mock_gatt_client_last_service); 7067dbac955SMatthias Ringwald mock_gatt_client_last_characteristic = NULL; 7077dbac955SMatthias Ringwald } 7087dbac955SMatthias Ringwald 7097dbac955SMatthias Ringwald mock_gatt_client_service_t * mock_gatt_client_add_primary_service_uuid16(uint16_t service_uuid){ 7107dbac955SMatthias Ringwald mock_gatt_client_add_primary_service(); 7117dbac955SMatthias Ringwald mock_gatt_client_last_service->uuid16 = service_uuid; 7127dbac955SMatthias Ringwald uuid_add_bluetooth_prefix(mock_gatt_client_last_service->uuid128, service_uuid); 7137dbac955SMatthias Ringwald return mock_gatt_client_last_service; 7147dbac955SMatthias Ringwald } 7157dbac955SMatthias Ringwald mock_gatt_client_service_t * mock_gatt_client_add_primary_service_uuid128(const uint8_t * service_uuid){ 7167dbac955SMatthias Ringwald mock_gatt_client_add_primary_service(); 7177dbac955SMatthias Ringwald (void) memcpy(mock_gatt_client_last_service->uuid128, service_uuid, 16); 7187dbac955SMatthias Ringwald return mock_gatt_client_last_service; 7197dbac955SMatthias Ringwald } 7207dbac955SMatthias Ringwald 7217dbac955SMatthias Ringwald static void mock_gatt_client_add_characteristic(uint16_t properties){ 7227dbac955SMatthias Ringwald btstack_assert(mock_gatt_client_last_service != NULL); 7237dbac955SMatthias Ringwald mock_gatt_client_last_characteristic = (mock_gatt_client_characteristic_t * )malloc(sizeof(mock_gatt_client_characteristic_t)); 7247dbac955SMatthias Ringwald memset(mock_gatt_client_last_characteristic, 0, sizeof(mock_gatt_client_characteristic_t)); 7257dbac955SMatthias Ringwald mock_gatt_client_last_characteristic->properties = properties; 7267dbac955SMatthias Ringwald mock_gatt_client_last_characteristic->start_handle = mock_gatt_client_att_handle_generator++; 7277dbac955SMatthias Ringwald mock_gatt_client_last_characteristic->value_handle = mock_gatt_client_att_handle_generator++; 7287dbac955SMatthias Ringwald mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_last_characteristic->value_handle; 7297dbac955SMatthias Ringwald btstack_linked_list_add_tail(&mock_gatt_client_last_service->characteristics, (btstack_linked_item_t*)mock_gatt_client_last_characteristic); 7307dbac955SMatthias Ringwald mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1; 7317dbac955SMatthias Ringwald } 7327dbac955SMatthias Ringwald 7337dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * mock_gatt_client_add_characteristic_uuid16(uint16_t characteristic_uuid, uint16_t properties){ 7347dbac955SMatthias Ringwald mock_gatt_client_add_characteristic(properties); 7357dbac955SMatthias Ringwald mock_gatt_client_last_characteristic->uuid16 = characteristic_uuid; 7367dbac955SMatthias Ringwald uuid_add_bluetooth_prefix(mock_gatt_client_last_characteristic->uuid128, characteristic_uuid); 7377dbac955SMatthias Ringwald return mock_gatt_client_last_characteristic; 7387dbac955SMatthias Ringwald } 7397dbac955SMatthias Ringwald 7407dbac955SMatthias Ringwald mock_gatt_client_characteristic_t * mock_gatt_client_add_characteristic_uuid128(const uint8_t * characteristic_uuid, uint16_t properties){ 7417dbac955SMatthias Ringwald mock_gatt_client_add_characteristic(properties); 7427dbac955SMatthias Ringwald (void) memcpy(mock_gatt_client_last_characteristic->uuid128, characteristic_uuid, 16); 7437dbac955SMatthias Ringwald return mock_gatt_client_last_characteristic; 7447dbac955SMatthias Ringwald } 7457dbac955SMatthias Ringwald 7467dbac955SMatthias Ringwald static mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor(void){ 7477dbac955SMatthias Ringwald btstack_assert(mock_gatt_client_last_characteristic != NULL); 7487dbac955SMatthias Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t * )malloc(sizeof(mock_gatt_client_characteristic_descriptor_t)); 7497dbac955SMatthias Ringwald memset(desc, 0, sizeof(mock_gatt_client_characteristic_descriptor_t)); 7507dbac955SMatthias Ringwald desc->handle = mock_gatt_client_att_handle_generator++; 7517dbac955SMatthias Ringwald btstack_linked_list_add_tail(&mock_gatt_client_last_characteristic->descriptors, (btstack_linked_item_t*)desc); 7527dbac955SMatthias Ringwald mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_att_handle_generator - 1; 7537dbac955SMatthias Ringwald mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1; 7547dbac955SMatthias Ringwald return desc; 7557dbac955SMatthias Ringwald } 7567dbac955SMatthias Ringwald 7577dbac955SMatthias Ringwald mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor_uuid16(uint16_t descriptor_uuid){ 7587dbac955SMatthias Ringwald mock_gatt_client_characteristic_descriptor_t * desc = mock_gatt_client_add_characteristic_descriptor(); 7597dbac955SMatthias Ringwald desc->uuid16 = descriptor_uuid; 7607dbac955SMatthias Ringwald uuid_add_bluetooth_prefix(desc->uuid128, descriptor_uuid); 7617dbac955SMatthias Ringwald return desc; 7627dbac955SMatthias Ringwald } 7637dbac955SMatthias Ringwald 7647dbac955SMatthias Ringwald mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor_uuid128(const uint8_t * descriptor_uuid){ 7657dbac955SMatthias Ringwald mock_gatt_client_characteristic_descriptor_t * desc = mock_gatt_client_add_characteristic_descriptor(); 7667dbac955SMatthias Ringwald (void) memcpy(desc->uuid128, descriptor_uuid, 16); 7677dbac955SMatthias Ringwald return desc; 7687dbac955SMatthias Ringwald } 7697dbac955SMatthias Ringwald 7707dbac955SMatthias Ringwald void mock_gatt_client_set_descriptor_characteristic_value(mock_gatt_client_characteristic_descriptor_t * descriptor, uint8_t * value_buffer, uint16_t value_len){ 7717dbac955SMatthias Ringwald btstack_assert(descriptor != NULL); 7727dbac955SMatthias Ringwald descriptor->value_buffer = value_buffer; 7737dbac955SMatthias Ringwald descriptor->value_len = value_len; 7747dbac955SMatthias Ringwald } 7757dbac955SMatthias Ringwald 7767dbac955SMatthias Ringwald void mock_gatt_client_set_characteristic_value(mock_gatt_client_characteristic_t * characteristic, uint8_t * value_buffer, uint16_t value_len){ 7777dbac955SMatthias Ringwald btstack_assert(characteristic != NULL); 7787dbac955SMatthias Ringwald characteristic->value_buffer = value_buffer; 7797dbac955SMatthias Ringwald characteristic->value_len = value_len; 7807dbac955SMatthias Ringwald } 7817dbac955SMatthias Ringwald 7827dbac955SMatthias Ringwald // simulate error 7837dbac955SMatthias Ringwald void mock_gatt_client_simulate_att_error(uint8_t att_error){ 7847dbac955SMatthias Ringwald mock_gatt_client_att_error = att_error; 7857dbac955SMatthias Ringwald } 786