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