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, 14*7da2c1baSMilanka Ringwald MOCK_QUERY_DISCOVER_CHARACTERISTICS, 15af770404SMilanka Ringwald } mock_gatt_client_state; 16af770404SMilanka Ringwald 17af770404SMilanka Ringwald static uint8_t mock_gatt_client_att_error; 18af770404SMilanka Ringwald static uint16_t mock_gatt_client_uuid; 19af770404SMilanka Ringwald static gatt_client_t gatt_client; 200f7fd6c1SMilanka Ringwald 21*7da2c1baSMilanka Ringwald static btstack_linked_list_t mock_gatt_client_services; 22*7da2c1baSMilanka Ringwald 23*7da2c1baSMilanka Ringwald static mock_gatt_client_service_t * mock_gatt_client_last_service; 24*7da2c1baSMilanka Ringwald static mock_gatt_client_characteristic_t * mock_gatt_client_last_characteristic; 25*7da2c1baSMilanka Ringwald 260f7fd6c1SMilanka Ringwald void mock_gatt_client_reset(void){ 27af770404SMilanka Ringwald mock_gatt_client_att_error = 0; 28af770404SMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_IDLE; 29*7da2c1baSMilanka Ringwald 30*7da2c1baSMilanka Ringwald 31*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_t service_it; 32*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 33*7da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 34*7da2c1baSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 35*7da2c1baSMilanka Ringwald btstack_linked_list_remove(&mock_gatt_client_services, (btstack_linked_item_t *) service); 36*7da2c1baSMilanka Ringwald 37*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_t characteristic_it; 38*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 39*7da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 40*7da2c1baSMilanka Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 41*7da2c1baSMilanka Ringwald btstack_linked_list_remove(&service->characteristics, (btstack_linked_item_t *) characteristic); 42*7da2c1baSMilanka Ringwald 43*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_t desc_it; 44*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors); 45*7da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&desc_it)){ 46*7da2c1baSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it); 47*7da2c1baSMilanka Ringwald btstack_linked_list_remove(&characteristic->descriptors, (btstack_linked_item_t *) desc); 48*7da2c1baSMilanka Ringwald free(desc); 49*7da2c1baSMilanka Ringwald } 50*7da2c1baSMilanka Ringwald free(characteristic); 51*7da2c1baSMilanka Ringwald } 52*7da2c1baSMilanka Ringwald free(service); 53*7da2c1baSMilanka Ringwald } 540f7fd6c1SMilanka Ringwald } 55af770404SMilanka Ringwald 56*7da2c1baSMilanka Ringwald void mock_gatt_client_add_primary_service_uuid16(uint16_t service_uuid){ 57*7da2c1baSMilanka Ringwald mock_gatt_client_last_service = (mock_gatt_client_service_t * )malloc(sizeof(mock_gatt_client_service_t)); 58*7da2c1baSMilanka Ringwald memset(mock_gatt_client_last_service, 0, sizeof(mock_gatt_client_service_t)); 59*7da2c1baSMilanka Ringwald mock_gatt_client_last_service->uuid16 = service_uuid; 60*7da2c1baSMilanka Ringwald 61*7da2c1baSMilanka Ringwald btstack_linked_list_add(&mock_gatt_client_services, (btstack_linked_item_t*)mock_gatt_client_last_service); 620f7fd6c1SMilanka Ringwald } 63af770404SMilanka Ringwald 64*7da2c1baSMilanka Ringwald void mock_gatt_client_add_characteristic_uuid16(uint16_t characteristic_uuid){ 65*7da2c1baSMilanka Ringwald btstack_assert(mock_gatt_client_last_service != NULL); 66*7da2c1baSMilanka Ringwald mock_gatt_client_last_characteristic = (mock_gatt_client_characteristic_t * )malloc(sizeof(mock_gatt_client_characteristic_t)); 67*7da2c1baSMilanka Ringwald memset(mock_gatt_client_last_characteristic, 0, sizeof(mock_gatt_client_characteristic_t)); 68*7da2c1baSMilanka Ringwald mock_gatt_client_last_characteristic->uuid16 = characteristic_uuid; 69*7da2c1baSMilanka Ringwald btstack_linked_list_add(&mock_gatt_client_last_service->characteristics, (btstack_linked_item_t*)mock_gatt_client_last_characteristic); 700f7fd6c1SMilanka Ringwald } 71af770404SMilanka Ringwald 72*7da2c1baSMilanka Ringwald void mock_gatt_client_add_characteristic_descriptor_uuid16(uint16_t descriptor_uuid){ 73*7da2c1baSMilanka Ringwald mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t * )malloc(sizeof(mock_gatt_client_characteristic_descriptor_t)); 74*7da2c1baSMilanka Ringwald memset(desc, 0, sizeof(mock_gatt_client_characteristic_descriptor_t)); 75*7da2c1baSMilanka Ringwald desc->uuid16 = descriptor_uuid; 76*7da2c1baSMilanka Ringwald btstack_linked_list_add(&mock_gatt_client_last_characteristic->descriptors, (btstack_linked_item_t*)desc); 770f7fd6c1SMilanka Ringwald } 780f7fd6c1SMilanka Ringwald 79*7da2c1baSMilanka Ringwald 80af770404SMilanka Ringwald // simulate erro 81af770404SMilanka Ringwald void mock_gatt_client_simulate_att_error(uint8_t att_error){ 82af770404SMilanka Ringwald mock_gatt_client_att_error = att_error; 830f7fd6c1SMilanka Ringwald } 840f7fd6c1SMilanka Ringwald 850f7fd6c1SMilanka Ringwald uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){ 86af770404SMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES; 87af770404SMilanka Ringwald mock_gatt_client_uuid = uuid16; 88af770404SMilanka Ringwald 89af770404SMilanka Ringwald gatt_client.callback = callback; 90af770404SMilanka Ringwald gatt_client.con_handle = con_handle; 910f7fd6c1SMilanka Ringwald return ERROR_CODE_SUCCESS; 920f7fd6c1SMilanka Ringwald } 930f7fd6c1SMilanka Ringwald 940f7fd6c1SMilanka 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){ 95*7da2c1baSMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTICS; 96*7da2c1baSMilanka Ringwald mock_gatt_client_uuid = uuid16; 97*7da2c1baSMilanka Ringwald 98*7da2c1baSMilanka Ringwald gatt_client.callback = callback; 99*7da2c1baSMilanka Ringwald gatt_client.con_handle = con_handle; 1000f7fd6c1SMilanka Ringwald return ERROR_CODE_SUCCESS; 1010f7fd6c1SMilanka Ringwald } 1020f7fd6c1SMilanka Ringwald 1030f7fd6c1SMilanka Ringwald uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){ 104af770404SMilanka Ringwald btstack_assert(false); 105af770404SMilanka Ringwald return ERROR_CODE_SUCCESS; 106af770404SMilanka Ringwald } 107af770404SMilanka Ringwald 108af770404SMilanka 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){ 109af770404SMilanka Ringwald btstack_assert(false); 1100f7fd6c1SMilanka Ringwald return ERROR_CODE_SUCCESS; 1110f7fd6c1SMilanka Ringwald } 1120f7fd6c1SMilanka Ringwald 1130f7fd6c1SMilanka 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){ 114af770404SMilanka Ringwald btstack_assert(false); 1150f7fd6c1SMilanka Ringwald return ERROR_CODE_SUCCESS; 1160f7fd6c1SMilanka Ringwald } 1170f7fd6c1SMilanka Ringwald 1180f7fd6c1SMilanka 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){ 119af770404SMilanka Ringwald btstack_assert(false); 1200f7fd6c1SMilanka Ringwald return ERROR_CODE_SUCCESS; 1210f7fd6c1SMilanka Ringwald } 1220f7fd6c1SMilanka Ringwald 1230f7fd6c1SMilanka 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){ 124af770404SMilanka Ringwald btstack_assert(false); 1250f7fd6c1SMilanka Ringwald } 1260f7fd6c1SMilanka Ringwald 127af770404SMilanka Ringwald void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification){ 128af770404SMilanka Ringwald btstack_assert(false); 129af770404SMilanka Ringwald } 130af770404SMilanka Ringwald 131af770404SMilanka Ringwald /** 132af770404SMilanka Ringwald * copied from gatt_client.c - START 133af770404SMilanka Ringwald */ 1340f7fd6c1SMilanka Ringwald void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t * service){ 1350f7fd6c1SMilanka Ringwald service->start_group_handle = little_endian_read_16(packet, offset); 1360f7fd6c1SMilanka Ringwald service->end_group_handle = little_endian_read_16(packet, offset + 2); 1370f7fd6c1SMilanka Ringwald reverse_128(&packet[offset + 4], service->uuid128); 1380f7fd6c1SMilanka Ringwald if (uuid_has_bluetooth_prefix(service->uuid128)){ 1390f7fd6c1SMilanka Ringwald service->uuid16 = big_endian_read_32(service->uuid128, 0); 1400f7fd6c1SMilanka Ringwald } else { 1410f7fd6c1SMilanka Ringwald service->uuid16 = 0; 1420f7fd6c1SMilanka Ringwald } 1430f7fd6c1SMilanka Ringwald } 1440f7fd6c1SMilanka Ringwald 1450f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic(const uint8_t * packet, int offset, gatt_client_characteristic_t * characteristic){ 1460f7fd6c1SMilanka Ringwald characteristic->start_handle = little_endian_read_16(packet, offset); 1470f7fd6c1SMilanka Ringwald characteristic->value_handle = little_endian_read_16(packet, offset + 2); 1480f7fd6c1SMilanka Ringwald characteristic->end_handle = little_endian_read_16(packet, offset + 4); 1490f7fd6c1SMilanka Ringwald characteristic->properties = little_endian_read_16(packet, offset + 6); 1500f7fd6c1SMilanka Ringwald reverse_128(&packet[offset+8], characteristic->uuid128); 1510f7fd6c1SMilanka Ringwald if (uuid_has_bluetooth_prefix(characteristic->uuid128)){ 1520f7fd6c1SMilanka Ringwald characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0); 1530f7fd6c1SMilanka Ringwald } else { 1540f7fd6c1SMilanka Ringwald characteristic->uuid16 = 0; 1550f7fd6c1SMilanka Ringwald } 1560f7fd6c1SMilanka Ringwald } 1570f7fd6c1SMilanka Ringwald 1580f7fd6c1SMilanka Ringwald void gatt_client_deserialize_characteristic_descriptor(const uint8_t * packet, int offset, gatt_client_characteristic_descriptor_t * descriptor){ 1590f7fd6c1SMilanka Ringwald descriptor->handle = little_endian_read_16(packet, offset); 1600f7fd6c1SMilanka Ringwald reverse_128(&packet[offset+2], descriptor->uuid128); 1610f7fd6c1SMilanka Ringwald if (uuid_has_bluetooth_prefix(descriptor->uuid128)){ 1620f7fd6c1SMilanka Ringwald descriptor->uuid16 = big_endian_read_32(descriptor->uuid128, 0); 1630f7fd6c1SMilanka Ringwald } else { 1640f7fd6c1SMilanka Ringwald descriptor->uuid16 = 0; 1650f7fd6c1SMilanka Ringwald } 1660f7fd6c1SMilanka Ringwald } 1670f7fd6c1SMilanka Ringwald 168af770404SMilanka Ringwald static void emit_event_new(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){ 169af770404SMilanka Ringwald if (!callback) return; 170af770404SMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, packet, size); 1710f7fd6c1SMilanka Ringwald } 1720f7fd6c1SMilanka Ringwald 173af770404SMilanka Ringwald static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_status){ 174af770404SMilanka Ringwald // @format H1 175af770404SMilanka Ringwald uint8_t packet[5]; 176af770404SMilanka Ringwald packet[0] = GATT_EVENT_QUERY_COMPLETE; 177af770404SMilanka Ringwald packet[1] = 3; 178af770404SMilanka Ringwald little_endian_store_16(packet, 2, gatt_client->con_handle); 179af770404SMilanka Ringwald packet[4] = att_status; 180af770404SMilanka Ringwald emit_event_new(gatt_client->callback, packet, sizeof(packet)); 1810f7fd6c1SMilanka Ringwald } 1820f7fd6c1SMilanka Ringwald 183*7da2c1baSMilanka 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){ 184*7da2c1baSMilanka Ringwald // @format HX 185*7da2c1baSMilanka Ringwald uint8_t packet[24]; 186*7da2c1baSMilanka Ringwald packet[0] = GATT_EVENT_SERVICE_QUERY_RESULT; 187*7da2c1baSMilanka Ringwald packet[1] = sizeof(packet) - 2u; 188*7da2c1baSMilanka Ringwald little_endian_store_16(packet, 2, gatt_client->con_handle); 189*7da2c1baSMilanka Ringwald /// 190*7da2c1baSMilanka Ringwald little_endian_store_16(packet, 4, start_group_handle); 191*7da2c1baSMilanka Ringwald little_endian_store_16(packet, 6, end_group_handle); 192*7da2c1baSMilanka Ringwald reverse_128(uuid128, &packet[8]); 193*7da2c1baSMilanka Ringwald emit_event_new(gatt_client->callback, packet, sizeof(packet)); 194*7da2c1baSMilanka Ringwald } 195*7da2c1baSMilanka Ringwald 196*7da2c1baSMilanka 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, 197*7da2c1baSMilanka Ringwald uint16_t properties, const uint8_t * uuid128){ 198*7da2c1baSMilanka Ringwald // @format HY 199*7da2c1baSMilanka Ringwald uint8_t packet[28]; 200*7da2c1baSMilanka Ringwald packet[0] = GATT_EVENT_CHARACTERISTIC_QUERY_RESULT; 201*7da2c1baSMilanka Ringwald packet[1] = sizeof(packet) - 2u; 202*7da2c1baSMilanka Ringwald little_endian_store_16(packet, 2, gatt_client->con_handle); 203*7da2c1baSMilanka Ringwald /// 204*7da2c1baSMilanka Ringwald little_endian_store_16(packet, 4, start_handle); 205*7da2c1baSMilanka Ringwald little_endian_store_16(packet, 6, value_handle); 206*7da2c1baSMilanka Ringwald little_endian_store_16(packet, 8, end_handle); 207*7da2c1baSMilanka Ringwald little_endian_store_16(packet, 10, properties); 208*7da2c1baSMilanka Ringwald reverse_128(uuid128, &packet[12]); 209*7da2c1baSMilanka Ringwald emit_event_new(gatt_client->callback, packet, sizeof(packet)); 210*7da2c1baSMilanka Ringwald } 211*7da2c1baSMilanka Ringwald 212af770404SMilanka Ringwald /** 213af770404SMilanka Ringwald * copied from gatt_client.c - END 214af770404SMilanka Ringwald */ 2150f7fd6c1SMilanka Ringwald 216*7da2c1baSMilanka Ringwald static void mock_gatt_client_emit_complete(uint8_t status){ 217*7da2c1baSMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_IDLE; 218*7da2c1baSMilanka Ringwald emit_gatt_complete_event(&gatt_client, status); 219*7da2c1baSMilanka Ringwald } 2200f7fd6c1SMilanka Ringwald 221af770404SMilanka Ringwald void mock_gatt_client_run(void){ 222af770404SMilanka Ringwald btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE); 223*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_t service_it; 224*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_t characteristic_it; 225*7da2c1baSMilanka Ringwald uint8_t uuid128[16]; 226*7da2c1baSMilanka Ringwald 227*7da2c1baSMilanka Ringwald while (mock_gatt_client_state != MOCK_QUERY_IDLE){ 228af770404SMilanka Ringwald switch (mock_gatt_client_state){ 229af770404SMilanka Ringwald case MOCK_QUERY_DISCOVER_PRIMARY_SERVICES: 230af770404SMilanka Ringwald // emit GATT_EVENT_SERVICE_QUERY_RESULT for each matching service 231*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 232*7da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 233*7da2c1baSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 234*7da2c1baSMilanka Ringwald if (service->uuid16 != mock_gatt_client_uuid) continue; 235*7da2c1baSMilanka Ringwald mock_gatt_client_last_service = service; 236*7da2c1baSMilanka Ringwald uuid_add_bluetooth_prefix(uuid128, service->uuid16); 237*7da2c1baSMilanka Ringwald emit_gatt_service_query_result_event(&gatt_client, 0x01, 0xFFFF, uuid128); 238*7da2c1baSMilanka Ringwald } 239*7da2c1baSMilanka Ringwald // emit GATT_EVENT_QUERY_COMPLETE 240*7da2c1baSMilanka Ringwald mock_gatt_client_emit_complete(ATT_ERROR_SUCCESS); 241*7da2c1baSMilanka Ringwald break; 242*7da2c1baSMilanka Ringwald 243*7da2c1baSMilanka Ringwald case MOCK_QUERY_DISCOVER_CHARACTERISTICS: 244*7da2c1baSMilanka Ringwald // emit GATT_EVENT_CHARACTERISTIC_QUERY_RESULT for each matching characteristic 245*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); 246*7da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&service_it)){ 247*7da2c1baSMilanka Ringwald mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); 248*7da2c1baSMilanka Ringwald 249*7da2c1baSMilanka Ringwald btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); 250*7da2c1baSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&characteristic_it)){ 251*7da2c1baSMilanka Ringwald mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); 252*7da2c1baSMilanka Ringwald if (characteristic->uuid16 != mock_gatt_client_uuid) continue; 253*7da2c1baSMilanka Ringwald // TODO validate handle range 254*7da2c1baSMilanka Ringwald uuid_add_bluetooth_prefix(uuid128, characteristic->uuid16); 255*7da2c1baSMilanka Ringwald emit_gatt_characteristic_query_result_event(&gatt_client, 0x01, 0x02, 0xFFFF, 0, uuid128); 256*7da2c1baSMilanka Ringwald } 257*7da2c1baSMilanka Ringwald } 258*7da2c1baSMilanka Ringwald 259*7da2c1baSMilanka Ringwald // emit GATT_EVENT_QUERY_COMPLETE 260*7da2c1baSMilanka Ringwald mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); 261af770404SMilanka Ringwald break; 262af770404SMilanka Ringwald default: 263af770404SMilanka Ringwald btstack_assert(false); 264af770404SMilanka Ringwald break; 2650f7fd6c1SMilanka Ringwald } 266*7da2c1baSMilanka Ringwald } 267*7da2c1baSMilanka Ringwald mock_gatt_client_att_error = ERROR_CODE_SUCCESS; 268af770404SMilanka Ringwald mock_gatt_client_state = MOCK_QUERY_IDLE; 2690f7fd6c1SMilanka Ringwald }