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, 13d41a8f51SMilanka Ringwald MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID16, 14d41a8f51SMilanka Ringwald MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID16, 1576cdba3eSMilanka Ringwald MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS, 1676cdba3eSMilanka Ringwald MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION, 1776cdba3eSMilanka Ringwald MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE 18af770404SMilanka Ringwald } mock_gatt_client_state; 19af770404SMilanka Ringwald 2076cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_att_handle_generator; 2176cdba3eSMilanka Ringwald 22af770404SMilanka Ringwald static uint8_t mock_gatt_client_att_error; 23af770404SMilanka Ringwald static uint16_t mock_gatt_client_uuid; 2476cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_value_handle; 2576cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_start_handle; 2676cdba3eSMilanka Ringwald static uint16_t mock_gatt_client_end_handle; 2776cdba3eSMilanka 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 35*ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_services; 36*ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_characteristics; 37*ec1a0daeSMilanka Ringwald static uint8_t moc_att_error_code_discover_characteristic_descriptors; 38*ec1a0daeSMilanka Ringwald 39*ec1a0daeSMilanka Ringwald static void mock_gatt_client_reset_att_errors(void){ 40*ec1a0daeSMilanka Ringwald moc_att_error_code_discover_services = ATT_ERROR_SUCCESS; 41*ec1a0daeSMilanka Ringwald moc_att_error_code_discover_characteristics = ATT_ERROR_SUCCESS; 42*ec1a0daeSMilanka Ringwald moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_SUCCESS; 43*ec1a0daeSMilanka Ringwald } 44*ec1a0daeSMilanka Ringwald 450f7fd6c1SMilanka Ringwald void mock_gatt_client_reset(void){ 46af770404SMilanka Ringwald mock_gatt_client_att_error = 0; 47af770404SMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_IDLE; 4876cdba3eSMilanka Ringwald mock_gatt_client_att_handle_generator = 0; 4976cdba3eSMilanka Ringwald mock_gatt_client_last_service = NULL; 507da2c1baSMilanka Ringwald 51*ec1a0daeSMilanka Ringwald mock_gatt_client_reset_att_errors(); 52*ec1a0daeSMilanka Ringwald 537da2c1baSMilanka Ringwald btstack_linked_list_iterator_t service_it; 547da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 557da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 567da2c1baSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 577da2c1baSMilanka Ringwald btstack_linked_list_remove(&mock_gatt_client_services, (btstack_linked_item_t *) service); 587da2c1baSMilanka Ringwald 597da2c1baSMilanka Ringwald btstack_linked_list_iterator_t characteristic_it; 607da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 617da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 627da2c1baSMilanka Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 637da2c1baSMilanka Ringwald btstack_linked_list_remove(&service->characteristics, (btstack_linked_item_t *) characteristic); 647da2c1baSMilanka Ringwald 657da2c1baSMilanka Ringwald btstack_linked_list_iterator_t desc_it; 667da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors); 677da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&desc_it)){ 687da2c1baSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it); 697da2c1baSMilanka Ringwald btstack_linked_list_remove(&characteristic->descriptors, (btstack_linked_item_t *) desc); 707da2c1baSMilanka Ringwald free(desc); 717da2c1baSMilanka Ringwald } 727da2c1baSMilanka Ringwald free(characteristic); 737da2c1baSMilanka Ringwald } 747da2c1baSMilanka Ringwald free(service); 757da2c1baSMilanka Ringwald } 760f7fd6c1SMilanka Ringwald } 77af770404SMilanka Ringwald 78*ec1a0daeSMilanka Ringwald void mock_gatt_client_set_att_error_discover_primary_services(void){ 79*ec1a0daeSMilanka Ringwald moc_att_error_code_discover_services = ATT_ERROR_REQUEST_NOT_SUPPORTED; 80*ec1a0daeSMilanka Ringwald } 81*ec1a0daeSMilanka Ringwald void mock_gatt_client_set_att_error_discover_characteristics(void){ 82*ec1a0daeSMilanka Ringwald moc_att_error_code_discover_characteristics = ATT_ERROR_REQUEST_NOT_SUPPORTED; 83*ec1a0daeSMilanka Ringwald } 84*ec1a0daeSMilanka Ringwald void mock_gatt_client_set_att_error_discover_characteristic_descriptors(void){ 85*ec1a0daeSMilanka Ringwald moc_att_error_code_discover_characteristic_descriptors = ATT_ERROR_REQUEST_NOT_SUPPORTED; 86*ec1a0daeSMilanka Ringwald } 87*ec1a0daeSMilanka Ringwald 8876cdba3eSMilanka Ringwald void mock_gatt_client_dump_services(void){ 8976cdba3eSMilanka Ringwald btstack_linked_list_iterator_t service_it; 9076cdba3eSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 9176cdba3eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 9276cdba3eSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 9376cdba3eSMilanka Ringwald printf("0x%02x: START SERVICE 0%02x\n", service->start_group_handle, service->uuid16); 9476cdba3eSMilanka Ringwald 9576cdba3eSMilanka Ringwald btstack_linked_list_iterator_t characteristic_it; 9676cdba3eSMilanka Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 9776cdba3eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 9876cdba3eSMilanka Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 9976cdba3eSMilanka Ringwald printf("0x%02x: START CHR 0%02x\n", characteristic->start_handle, characteristic->uuid16); 10076cdba3eSMilanka Ringwald printf("0x%02x: VALUE HANDLE CHR 0%02x\n", characteristic->value_handle, characteristic->uuid16); 10176cdba3eSMilanka Ringwald 10276cdba3eSMilanka Ringwald btstack_linked_list_iterator_t desc_it; 10376cdba3eSMilanka Ringwald btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors); 10476cdba3eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&desc_it)){ 10576cdba3eSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it); 10676cdba3eSMilanka Ringwald printf("0x%02x: DESC 0x%02x\n", desc->handle, desc->uuid16); 10776cdba3eSMilanka Ringwald } 10876cdba3eSMilanka Ringwald 10976cdba3eSMilanka Ringwald printf("0x%02x: END CHR 0%02x\n", characteristic->end_handle, characteristic->uuid16); 11076cdba3eSMilanka Ringwald 11176cdba3eSMilanka Ringwald } 11276cdba3eSMilanka Ringwald printf("0x%02x: END SERVICE 0%02x\n", service->end_group_handle, service->uuid16); 11376cdba3eSMilanka Ringwald 11476cdba3eSMilanka Ringwald } 11576cdba3eSMilanka Ringwald } 11676cdba3eSMilanka Ringwald 11776cdba3eSMilanka Ringwald mock_gatt_client_service_t * mock_gatt_client_add_primary_service_uuid16(uint16_t service_uuid){ 11876cdba3eSMilanka Ringwald // set lsat group handle 11976cdba3eSMilanka Ringwald // create new service 1207da2c1baSMilanka Ringwald mock_gatt_client_last_service = (mock_gatt_client_service_t * )malloc(sizeof(mock_gatt_client_service_t)); 1217da2c1baSMilanka Ringwald memset(mock_gatt_client_last_service, 0, sizeof(mock_gatt_client_service_t)); 1227da2c1baSMilanka Ringwald mock_gatt_client_last_service->uuid16 = service_uuid; 12376cdba3eSMilanka Ringwald mock_gatt_client_last_service->start_group_handle = mock_gatt_client_att_handle_generator++; 1246ad61799SMilanka Ringwald mock_gatt_client_last_service->end_group_handle = mock_gatt_client_last_service->start_group_handle; 1255b92fca9SMilanka Ringwald btstack_linked_list_add_tail(&mock_gatt_client_services, (btstack_linked_item_t*)mock_gatt_client_last_service); 12676cdba3eSMilanka Ringwald mock_gatt_client_last_characteristic = NULL; 12776cdba3eSMilanka Ringwald return mock_gatt_client_last_service; 1280f7fd6c1SMilanka Ringwald } 129af770404SMilanka Ringwald 13076cdba3eSMilanka Ringwald mock_gatt_client_characteristic_t * mock_gatt_client_add_characteristic_uuid16(uint16_t characteristic_uuid, uint16_t properties){ 1317da2c1baSMilanka Ringwald btstack_assert(mock_gatt_client_last_service != NULL); 1327da2c1baSMilanka Ringwald mock_gatt_client_last_characteristic = (mock_gatt_client_characteristic_t * )malloc(sizeof(mock_gatt_client_characteristic_t)); 1337da2c1baSMilanka Ringwald memset(mock_gatt_client_last_characteristic, 0, sizeof(mock_gatt_client_characteristic_t)); 1347da2c1baSMilanka Ringwald mock_gatt_client_last_characteristic->uuid16 = characteristic_uuid; 13576cdba3eSMilanka Ringwald mock_gatt_client_last_characteristic->properties = properties; 13676cdba3eSMilanka Ringwald mock_gatt_client_last_characteristic->start_handle = mock_gatt_client_att_handle_generator++; 13776cdba3eSMilanka Ringwald mock_gatt_client_last_characteristic->value_handle = mock_gatt_client_att_handle_generator++; 13876cdba3eSMilanka Ringwald mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_last_characteristic->value_handle; 1395b92fca9SMilanka Ringwald btstack_linked_list_add_tail(&mock_gatt_client_last_service->characteristics, (btstack_linked_item_t*)mock_gatt_client_last_characteristic); 14076cdba3eSMilanka Ringwald mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1; 14176cdba3eSMilanka Ringwald return mock_gatt_client_last_characteristic; 1420f7fd6c1SMilanka Ringwald } 143af770404SMilanka Ringwald 14476cdba3eSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_add_characteristic_descriptor_uuid16(uint16_t descriptor_uuid){ 14576cdba3eSMilanka Ringwald btstack_assert(mock_gatt_client_last_characteristic != NULL); 1467da2c1baSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t * )malloc(sizeof(mock_gatt_client_characteristic_descriptor_t)); 1477da2c1baSMilanka Ringwald memset(desc, 0, sizeof(mock_gatt_client_characteristic_descriptor_t)); 1487da2c1baSMilanka Ringwald desc->uuid16 = descriptor_uuid; 14976cdba3eSMilanka Ringwald desc->handle = mock_gatt_client_att_handle_generator++; 1505b92fca9SMilanka Ringwald btstack_linked_list_add_tail(&mock_gatt_client_last_characteristic->descriptors, (btstack_linked_item_t*)desc); 15176cdba3eSMilanka Ringwald mock_gatt_client_last_characteristic->end_handle = mock_gatt_client_att_handle_generator - 1; 15276cdba3eSMilanka Ringwald mock_gatt_client_last_service->end_group_handle = mock_gatt_client_att_handle_generator - 1; 15376cdba3eSMilanka Ringwald return desc; 1540f7fd6c1SMilanka Ringwald } 1550f7fd6c1SMilanka Ringwald 15676cdba3eSMilanka Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_get_characteristic_for_value_handle(uint16_t value_handle){ 15776cdba3eSMilanka Ringwald btstack_linked_list_iterator_t service_it; 15876cdba3eSMilanka Ringwald btstack_linked_list_iterator_t characteristic_it; 15976cdba3eSMilanka Ringwald 16076cdba3eSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 16176cdba3eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 16276cdba3eSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 16376cdba3eSMilanka Ringwald 16476cdba3eSMilanka Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 16576cdba3eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 16676cdba3eSMilanka Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 16776cdba3eSMilanka Ringwald if (characteristic->value_handle != value_handle) continue; 16876cdba3eSMilanka Ringwald return characteristic; 16976cdba3eSMilanka Ringwald } 17076cdba3eSMilanka Ringwald } 17176cdba3eSMilanka Ringwald return NULL; 17276cdba3eSMilanka Ringwald } 17376cdba3eSMilanka Ringwald 17476cdba3eSMilanka Ringwald static mock_gatt_client_characteristic_descriptor_t * mock_gatt_client_get_characteristic_descriptor_for_handle(uint16_t handle){ 17576cdba3eSMilanka Ringwald btstack_linked_list_iterator_t service_it; 17676cdba3eSMilanka Ringwald btstack_linked_list_iterator_t characteristic_it; 17776cdba3eSMilanka Ringwald 17876cdba3eSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 17976cdba3eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 18076cdba3eSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 18176cdba3eSMilanka Ringwald 18276cdba3eSMilanka Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 18376cdba3eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 18476cdba3eSMilanka Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 18576cdba3eSMilanka Ringwald 18676cdba3eSMilanka Ringwald btstack_linked_list_iterator_t desc_it; 18776cdba3eSMilanka Ringwald btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors); 18876cdba3eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&desc_it)){ 18976cdba3eSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it); 19076cdba3eSMilanka Ringwald if (desc->handle != handle) continue; 19176cdba3eSMilanka Ringwald return desc; 19276cdba3eSMilanka Ringwald } 19376cdba3eSMilanka Ringwald } 19476cdba3eSMilanka Ringwald } 19576cdba3eSMilanka Ringwald return NULL; 19676cdba3eSMilanka Ringwald } 19776cdba3eSMilanka Ringwald 19876cdba3eSMilanka Ringwald 19976cdba3eSMilanka Ringwald void mock_gatt_client_set_characteristic_value(mock_gatt_client_characteristic_descriptor_t * descriptor, uint8_t * value_buffer, uint16_t value_len){ 20076cdba3eSMilanka Ringwald btstack_assert(descriptor != NULL); 20176cdba3eSMilanka Ringwald descriptor->value_buffer = value_buffer; 20276cdba3eSMilanka Ringwald descriptor->value_len = value_len; 20376cdba3eSMilanka Ringwald } 2047da2c1baSMilanka Ringwald 205af770404SMilanka Ringwald // simulate erro 206af770404SMilanka Ringwald void mock_gatt_client_simulate_att_error(uint8_t att_error){ 207af770404SMilanka Ringwald mock_gatt_client_att_error = att_error; 2080f7fd6c1SMilanka Ringwald } 2090f7fd6c1SMilanka Ringwald 2100f7fd6c1SMilanka Ringwald uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){ 211d41a8f51SMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID16; 212af770404SMilanka Ringwald mock_gatt_client_uuid = uuid16; 213af770404SMilanka Ringwald 214af770404SMilanka Ringwald gatt_client.callback = callback; 215af770404SMilanka Ringwald gatt_client.con_handle = con_handle; 2160f7fd6c1SMilanka Ringwald return ERROR_CODE_SUCCESS; 2170f7fd6c1SMilanka Ringwald } 2180f7fd6c1SMilanka Ringwald 2190f7fd6c1SMilanka 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){ 220d41a8f51SMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID16; 2217da2c1baSMilanka Ringwald mock_gatt_client_uuid = uuid16; 22276cdba3eSMilanka Ringwald mock_gatt_client_start_handle = start_handle; 22376cdba3eSMilanka Ringwald mock_gatt_client_end_handle = end_handle; 2247da2c1baSMilanka Ringwald 2257da2c1baSMilanka Ringwald gatt_client.callback = callback; 2267da2c1baSMilanka Ringwald gatt_client.con_handle = con_handle; 2270f7fd6c1SMilanka Ringwald return ERROR_CODE_SUCCESS; 2280f7fd6c1SMilanka Ringwald } 2290f7fd6c1SMilanka Ringwald 2300f7fd6c1SMilanka Ringwald uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){ 23176cdba3eSMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS; 23276cdba3eSMilanka Ringwald mock_gatt_client_value_handle = characteristic->value_handle; 23376cdba3eSMilanka Ringwald 23476cdba3eSMilanka Ringwald gatt_client.callback = callback; 23576cdba3eSMilanka Ringwald gatt_client.con_handle = con_handle; 23676cdba3eSMilanka Ringwald return ERROR_CODE_SUCCESS; 23776cdba3eSMilanka Ringwald } 23876cdba3eSMilanka Ringwald 23976cdba3eSMilanka 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){ 24076cdba3eSMilanka Ringwald mock_gatt_client_state = MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION; 24176cdba3eSMilanka Ringwald mock_gatt_client_uuid = characteristic->uuid16; 24276cdba3eSMilanka Ringwald 24376cdba3eSMilanka Ringwald gatt_client.callback = callback; 24476cdba3eSMilanka Ringwald gatt_client.con_handle = con_handle; 24576cdba3eSMilanka Ringwald return ERROR_CODE_SUCCESS; 24676cdba3eSMilanka Ringwald } 24776cdba3eSMilanka Ringwald 24876cdba3eSMilanka 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){ 24976cdba3eSMilanka Ringwald notification->callback = callback; 25076cdba3eSMilanka Ringwald notification->con_handle = con_handle; 25176cdba3eSMilanka Ringwald 25276cdba3eSMilanka Ringwald if (characteristic == NULL){ 25376cdba3eSMilanka Ringwald // 'all characteristics': not used yet 254af770404SMilanka Ringwald btstack_assert(false); 25576cdba3eSMilanka Ringwald } else { 25676cdba3eSMilanka Ringwald notification->attribute_handle = characteristic->value_handle; 25776cdba3eSMilanka Ringwald } 25876cdba3eSMilanka Ringwald 25976cdba3eSMilanka Ringwald // finc our characteristic and set point to notification 26076cdba3eSMilanka Ringwald } 26176cdba3eSMilanka Ringwald 26276cdba3eSMilanka Ringwald 26376cdba3eSMilanka 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){ 26476cdba3eSMilanka Ringwald mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE; 26576cdba3eSMilanka Ringwald mock_gatt_client_value_handle = value_handle; 266af770404SMilanka Ringwald return ERROR_CODE_SUCCESS; 267af770404SMilanka Ringwald } 268af770404SMilanka Ringwald 269af770404SMilanka 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){ 27024152f08SMilanka Ringwald btstack_assert(characteristic != NULL); 27124152f08SMilanka Ringwald mock_gatt_client_state = MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE; 27224152f08SMilanka Ringwald mock_gatt_client_characteristic_t * mock_characteristic = mock_gatt_client_get_characteristic_for_value_handle(characteristic->value_handle); 27324152f08SMilanka Ringwald 27424152f08SMilanka Ringwald btstack_assert(mock_characteristic != NULL); 27524152f08SMilanka Ringwald 27624152f08SMilanka Ringwald mock_gatt_client_value_handle = mock_characteristic->value_handle; 2770f7fd6c1SMilanka Ringwald return ERROR_CODE_SUCCESS; 2780f7fd6c1SMilanka Ringwald } 2790f7fd6c1SMilanka Ringwald 280af770404SMilanka Ringwald void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification){ 281af770404SMilanka Ringwald } 282af770404SMilanka Ringwald 283af770404SMilanka Ringwald /** 284af770404SMilanka Ringwald * copied from gatt_client.c - START 285af770404SMilanka Ringwald */ 2860f7fd6c1SMilanka Ringwald void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t * service){ 2870f7fd6c1SMilanka Ringwald service->start_group_handle = little_endian_read_16(packet, offset); 2880f7fd6c1SMilanka Ringwald service->end_group_handle = little_endian_read_16(packet, offset + 2); 2890f7fd6c1SMilanka Ringwald reverse_128(&packet[offset + 4], service->uuid128); 2900f7fd6c1SMilanka Ringwald if (uuid_has_bluetooth_prefix(service->uuid128)){ 2910f7fd6c1SMilanka Ringwald service->uuid16 = big_endian_read_32(service->uuid128, 0); 2920f7fd6c1SMilanka Ringwald } else { 2930f7fd6c1SMilanka Ringwald service->uuid16 = 0; 2940f7fd6c1SMilanka Ringwald } 2950f7fd6c1SMilanka Ringwald } 2960f7fd6c1SMilanka Ringwald 2970f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic(const uint8_t * packet, int offset, gatt_client_characteristic_t * characteristic){ 2980f7fd6c1SMilanka Ringwald characteristic->start_handle = little_endian_read_16(packet, offset); 2990f7fd6c1SMilanka Ringwald characteristic->value_handle = little_endian_read_16(packet, offset + 2); 3000f7fd6c1SMilanka Ringwald characteristic->end_handle = little_endian_read_16(packet, offset + 4); 3010f7fd6c1SMilanka Ringwald characteristic->properties = little_endian_read_16(packet, offset + 6); 3020f7fd6c1SMilanka Ringwald reverse_128(&packet[offset+8], characteristic->uuid128); 3030f7fd6c1SMilanka Ringwald if (uuid_has_bluetooth_prefix(characteristic->uuid128)){ 3040f7fd6c1SMilanka Ringwald characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0); 3050f7fd6c1SMilanka Ringwald } else { 3060f7fd6c1SMilanka Ringwald characteristic->uuid16 = 0; 3070f7fd6c1SMilanka Ringwald } 3080f7fd6c1SMilanka Ringwald } 3090f7fd6c1SMilanka Ringwald 3100f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic_descriptor(const uint8_t * packet, int offset, gatt_client_characteristic_descriptor_t * descriptor){ 3110f7fd6c1SMilanka Ringwald descriptor->handle = little_endian_read_16(packet, offset); 3120f7fd6c1SMilanka Ringwald reverse_128(&packet[offset+2], descriptor->uuid128); 3130f7fd6c1SMilanka Ringwald if (uuid_has_bluetooth_prefix(descriptor->uuid128)){ 3140f7fd6c1SMilanka Ringwald descriptor->uuid16 = big_endian_read_32(descriptor->uuid128, 0); 3150f7fd6c1SMilanka Ringwald } else { 3160f7fd6c1SMilanka Ringwald descriptor->uuid16 = 0; 3170f7fd6c1SMilanka Ringwald } 3180f7fd6c1SMilanka Ringwald } 3190f7fd6c1SMilanka Ringwald 320af770404SMilanka Ringwald static void emit_event_new(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){ 321af770404SMilanka Ringwald if (!callback) return; 322af770404SMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, packet, size); 3230f7fd6c1SMilanka Ringwald } 3240f7fd6c1SMilanka Ringwald 325af770404SMilanka Ringwald static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_status){ 326af770404SMilanka Ringwald // @format H1 327af770404SMilanka Ringwald uint8_t packet[5]; 328af770404SMilanka Ringwald packet[0] = GATT_EVENT_QUERY_COMPLETE; 329af770404SMilanka Ringwald packet[1] = 3; 330af770404SMilanka Ringwald little_endian_store_16(packet, 2, gatt_client->con_handle); 331af770404SMilanka Ringwald packet[4] = att_status; 332af770404SMilanka Ringwald emit_event_new(gatt_client->callback, packet, sizeof(packet)); 3330f7fd6c1SMilanka Ringwald } 3340f7fd6c1SMilanka Ringwald 3357da2c1baSMilanka 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){ 3367da2c1baSMilanka Ringwald // @format HX 3377da2c1baSMilanka Ringwald uint8_t packet[24]; 3387da2c1baSMilanka Ringwald packet[0] = GATT_EVENT_SERVICE_QUERY_RESULT; 3397da2c1baSMilanka Ringwald packet[1] = sizeof(packet) - 2u; 3407da2c1baSMilanka Ringwald little_endian_store_16(packet, 2, gatt_client->con_handle); 3417da2c1baSMilanka Ringwald /// 3427da2c1baSMilanka Ringwald little_endian_store_16(packet, 4, start_group_handle); 3437da2c1baSMilanka Ringwald little_endian_store_16(packet, 6, end_group_handle); 3447da2c1baSMilanka Ringwald reverse_128(uuid128, &packet[8]); 3457da2c1baSMilanka Ringwald emit_event_new(gatt_client->callback, packet, sizeof(packet)); 3467da2c1baSMilanka Ringwald } 3477da2c1baSMilanka Ringwald 3487da2c1baSMilanka 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, 3497da2c1baSMilanka Ringwald uint16_t properties, const uint8_t * uuid128){ 3507da2c1baSMilanka Ringwald // @format HY 3517da2c1baSMilanka Ringwald uint8_t packet[28]; 3527da2c1baSMilanka Ringwald packet[0] = GATT_EVENT_CHARACTERISTIC_QUERY_RESULT; 3537da2c1baSMilanka Ringwald packet[1] = sizeof(packet) - 2u; 3547da2c1baSMilanka Ringwald little_endian_store_16(packet, 2, gatt_client->con_handle); 3557da2c1baSMilanka Ringwald /// 3567da2c1baSMilanka Ringwald little_endian_store_16(packet, 4, start_handle); 3577da2c1baSMilanka Ringwald little_endian_store_16(packet, 6, value_handle); 3587da2c1baSMilanka Ringwald little_endian_store_16(packet, 8, end_handle); 3597da2c1baSMilanka Ringwald little_endian_store_16(packet, 10, properties); 3607da2c1baSMilanka Ringwald reverse_128(uuid128, &packet[12]); 3617da2c1baSMilanka Ringwald emit_event_new(gatt_client->callback, packet, sizeof(packet)); 3627da2c1baSMilanka Ringwald } 3637da2c1baSMilanka Ringwald 36476cdba3eSMilanka Ringwald static void emit_gatt_all_characteristic_descriptors_result_event( 36576cdba3eSMilanka Ringwald gatt_client_t * gatt_client, uint16_t descriptor_handle, const uint8_t * uuid128){ 36676cdba3eSMilanka Ringwald // @format HZ 36776cdba3eSMilanka Ringwald uint8_t packet[22]; 36876cdba3eSMilanka Ringwald packet[0] = GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT; 36976cdba3eSMilanka Ringwald packet[1] = sizeof(packet) - 2u; 37076cdba3eSMilanka Ringwald little_endian_store_16(packet, 2, gatt_client->con_handle); 37176cdba3eSMilanka Ringwald /// 37276cdba3eSMilanka Ringwald little_endian_store_16(packet, 4, descriptor_handle); 37376cdba3eSMilanka Ringwald reverse_128(uuid128, &packet[6]); 37476cdba3eSMilanka Ringwald emit_event_new(gatt_client->callback, packet, sizeof(packet)); 37576cdba3eSMilanka Ringwald } 37676cdba3eSMilanka Ringwald 37776cdba3eSMilanka Ringwald 37876cdba3eSMilanka Ringwald static const int characteristic_value_event_header_size = 8; 37976cdba3eSMilanka 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){ 38076cdba3eSMilanka Ringwald // before the value inside the ATT PDU 38176cdba3eSMilanka Ringwald uint8_t * packet = value - characteristic_value_event_header_size; 38276cdba3eSMilanka Ringwald packet[0] = type; 38376cdba3eSMilanka Ringwald packet[1] = characteristic_value_event_header_size - 2 + length; 38476cdba3eSMilanka Ringwald little_endian_store_16(packet, 2, con_handle); 38576cdba3eSMilanka Ringwald little_endian_store_16(packet, 4, attribute_handle); 38676cdba3eSMilanka Ringwald little_endian_store_16(packet, 6, length); 38776cdba3eSMilanka Ringwald return packet; 38876cdba3eSMilanka Ringwald } 38976cdba3eSMilanka Ringwald 39076cdba3eSMilanka Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes 39176cdba3eSMilanka Ringwald static void report_gatt_characteristic_value(gatt_client_t * gatt_client, uint16_t attribute_handle, uint8_t * value, uint16_t length){ 39276cdba3eSMilanka Ringwald uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT, gatt_client->con_handle, attribute_handle, value, length); 39376cdba3eSMilanka Ringwald emit_event_new(gatt_client->callback, packet, characteristic_value_event_header_size + length); 39476cdba3eSMilanka Ringwald } 39576cdba3eSMilanka Ringwald 396af770404SMilanka Ringwald /** 397af770404SMilanka Ringwald * copied from gatt_client.c - END 398af770404SMilanka Ringwald */ 3990f7fd6c1SMilanka Ringwald 4007da2c1baSMilanka Ringwald static void mock_gatt_client_emit_complete(uint8_t status){ 4017da2c1baSMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_IDLE; 4027da2c1baSMilanka Ringwald emit_gatt_complete_event(&gatt_client, status); 4037da2c1baSMilanka Ringwald } 4040f7fd6c1SMilanka Ringwald 405af770404SMilanka Ringwald void mock_gatt_client_run(void){ 406af770404SMilanka Ringwald btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE); 40776cdba3eSMilanka Ringwald mock_gatt_client_characteristic_t * characteristic; 40876cdba3eSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * descriptor; 40976cdba3eSMilanka Ringwald 4107da2c1baSMilanka Ringwald btstack_linked_list_iterator_t service_it; 4117da2c1baSMilanka Ringwald btstack_linked_list_iterator_t characteristic_it; 41276cdba3eSMilanka Ringwald btstack_linked_list_iterator_t descriptor_it; 41376cdba3eSMilanka Ringwald 4147da2c1baSMilanka Ringwald uint8_t uuid128[16]; 4157da2c1baSMilanka Ringwald 4167da2c1baSMilanka Ringwald while (mock_gatt_client_state != MOCK_QUERY_IDLE){ 417af770404SMilanka Ringwald switch (mock_gatt_client_state){ 418d41a8f51SMilanka Ringwald case MOCK_QUERY_DISCOVER_PRIMARY_SERVICES_BY_UUID16: 419af770404SMilanka Ringwald // emit GATT_EVENT_SERVICE_QUERY_RESULT for each matching service 420*ec1a0daeSMilanka Ringwald if (moc_att_error_code_discover_services != ATT_ERROR_SUCCESS){ 421*ec1a0daeSMilanka Ringwald mock_gatt_client_emit_complete(moc_att_error_code_discover_services); 422*ec1a0daeSMilanka Ringwald return; 423*ec1a0daeSMilanka Ringwald } 424*ec1a0daeSMilanka Ringwald 4257da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 4267da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 4277da2c1baSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 4287da2c1baSMilanka Ringwald if (service->uuid16 != mock_gatt_client_uuid) continue; 4297da2c1baSMilanka Ringwald mock_gatt_client_last_service = service; 4307da2c1baSMilanka Ringwald uuid_add_bluetooth_prefix(uuid128, service->uuid16); 43176cdba3eSMilanka Ringwald emit_gatt_service_query_result_event(&gatt_client, service->start_group_handle, service->end_group_handle, uuid128); 4327da2c1baSMilanka Ringwald } 4337da2c1baSMilanka Ringwald // emit GATT_EVENT_QUERY_COMPLETE 4347da2c1baSMilanka Ringwald mock_gatt_client_emit_complete(ATT_ERROR_SUCCESS); 4357da2c1baSMilanka Ringwald break; 4367da2c1baSMilanka Ringwald 437d41a8f51SMilanka Ringwald case MOCK_QUERY_DISCOVER_CHARACTERISTICS_BY_UUID16: 4387da2c1baSMilanka Ringwald // emit GATT_EVENT_CHARACTERISTIC_QUERY_RESULT for each matching characteristic 439*ec1a0daeSMilanka Ringwald if (moc_att_error_code_discover_characteristics != ATT_ERROR_SUCCESS){ 440*ec1a0daeSMilanka Ringwald mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristics); 441*ec1a0daeSMilanka Ringwald return; 442*ec1a0daeSMilanka Ringwald } 443*ec1a0daeSMilanka Ringwald 4447da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 4457da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 4467da2c1baSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 4477da2c1baSMilanka Ringwald 4487da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 4497da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 4507da2c1baSMilanka Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 4517da2c1baSMilanka Ringwald if (characteristic->uuid16 != mock_gatt_client_uuid) continue; 45276cdba3eSMilanka Ringwald if (characteristic->start_handle < mock_gatt_client_start_handle) continue; 45376cdba3eSMilanka Ringwald if (characteristic->end_handle > mock_gatt_client_end_handle) continue; 45476cdba3eSMilanka Ringwald 4557da2c1baSMilanka Ringwald uuid_add_bluetooth_prefix(uuid128, characteristic->uuid16); 45676cdba3eSMilanka Ringwald emit_gatt_characteristic_query_result_event(&gatt_client, 45776cdba3eSMilanka Ringwald characteristic->start_handle, characteristic->value_handle, characteristic->end_handle, 45876cdba3eSMilanka Ringwald characteristic->properties, uuid128); 4597da2c1baSMilanka Ringwald } 4607da2c1baSMilanka Ringwald } 4617da2c1baSMilanka Ringwald 4627da2c1baSMilanka Ringwald // emit GATT_EVENT_QUERY_COMPLETE 4637da2c1baSMilanka Ringwald mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); 464af770404SMilanka Ringwald break; 46576cdba3eSMilanka Ringwald 46676cdba3eSMilanka Ringwald case MOCK_QUERY_DISCOVER_CHARACTERISTIC_DESCRIPTORS: 46776cdba3eSMilanka Ringwald characteristic = mock_gatt_client_get_characteristic_for_value_handle(mock_gatt_client_value_handle); 46876cdba3eSMilanka Ringwald btstack_assert(characteristic != NULL); 46976cdba3eSMilanka Ringwald 470*ec1a0daeSMilanka Ringwald if (moc_att_error_code_discover_characteristic_descriptors != ATT_ERROR_SUCCESS){ 471*ec1a0daeSMilanka Ringwald mock_gatt_client_emit_complete(moc_att_error_code_discover_characteristic_descriptors); 472*ec1a0daeSMilanka Ringwald return; 473*ec1a0daeSMilanka Ringwald } 474*ec1a0daeSMilanka Ringwald 47576cdba3eSMilanka Ringwald btstack_linked_list_iterator_init(&descriptor_it, &characteristic->descriptors); 47676cdba3eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&descriptor_it)){ 47776cdba3eSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&descriptor_it); 47876cdba3eSMilanka Ringwald 47976cdba3eSMilanka Ringwald uuid_add_bluetooth_prefix(uuid128, desc->uuid16); 48076cdba3eSMilanka Ringwald emit_gatt_all_characteristic_descriptors_result_event(&gatt_client, desc->handle, uuid128); 48176cdba3eSMilanka Ringwald } 48276cdba3eSMilanka Ringwald 48376cdba3eSMilanka Ringwald // emit GATT_EVENT_QUERY_COMPLETE 48476cdba3eSMilanka Ringwald mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); 48576cdba3eSMilanka Ringwald break; 48676cdba3eSMilanka Ringwald 48776cdba3eSMilanka Ringwald case MOCK_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION: 48876cdba3eSMilanka Ringwald mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); 48976cdba3eSMilanka Ringwald break; 49076cdba3eSMilanka Ringwald 49176cdba3eSMilanka Ringwald case MOCK_READ_VALUE_OF_CHARACTERISTIC_USING_VALUE_HANDLE: 49276cdba3eSMilanka Ringwald descriptor = mock_gatt_client_get_characteristic_descriptor_for_handle(mock_gatt_client_value_handle); 49376cdba3eSMilanka Ringwald btstack_assert(descriptor != NULL); 49476cdba3eSMilanka Ringwald btstack_assert(descriptor->value_buffer != NULL); 49576cdba3eSMilanka Ringwald 49676cdba3eSMilanka Ringwald report_gatt_characteristic_value(&gatt_client, descriptor->handle, descriptor->value_buffer, descriptor->value_len); 49776cdba3eSMilanka Ringwald mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); 49876cdba3eSMilanka Ringwald break; 49976cdba3eSMilanka Ringwald 500af770404SMilanka Ringwald default: 501af770404SMilanka Ringwald btstack_assert(false); 502af770404SMilanka Ringwald break; 5030f7fd6c1SMilanka Ringwald } 5047da2c1baSMilanka Ringwald } 5057da2c1baSMilanka Ringwald mock_gatt_client_att_error = ERROR_CODE_SUCCESS; 506af770404SMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_IDLE; 5070f7fd6c1SMilanka Ringwald }