diff --git a/test/gatt-service-client/battery_service_client_test.c b/test/gatt-service-client/battery_service_client_test.c index 71a2fccc1..2e1563be9 100644 --- a/test/gatt-service-client/battery_service_client_test.c +++ b/test/gatt-service-client/battery_service_client_test.c @@ -73,12 +73,23 @@ TEST_GROUP(BATTERY_SERVICE_CLIENT){ battery_service_cid = 1; connected = false; poll_interval_ms = 2000; + + mock_gatt_client_reset(); battery_service_client_init(); } - void teardown(){ + void setup_service(bool add_characteristics, bool add_descriptors){ + mock_gatt_client_add_primary_service_uuid16(ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE); + if (!add_characteristics) return; + + mock_gatt_client_add_characteristic_uuid16(ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL); + + if (!add_descriptors) return; + mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION); + } + + void teardown(void){ battery_service_client_deinit(); - // mock().clear(); } }; @@ -86,11 +97,22 @@ TEST(BATTERY_SERVICE_CLIENT, connect_no_service){ uint8_t status = battery_service_client_connect(con_handle, &gatt_client_event_handler, poll_interval_ms, &battery_service_cid); CHECK_EQUAL(ERROR_CODE_SUCCESS, status); + mock_gatt_client_run(); + CHECK_EQUAL(false, connected); +} + + +TEST(BATTERY_SERVICE_CLIENT, connect_with_service){ + setup_service(true, true); + + uint8_t status = battery_service_client_connect(con_handle, &gatt_client_event_handler, poll_interval_ms, &battery_service_cid); + CHECK_EQUAL(ERROR_CODE_SUCCESS, status); mock_gatt_client_run(); CHECK_EQUAL(false, connected); } + #if 0 TEST(BATTERY_SERVICE_CLIENT, disconnect){ uint8_t status; diff --git a/test/mock/mock_gatt_client.c b/test/mock/mock_gatt_client.c index 3af21d547..29875cd7e 100644 --- a/test/mock/mock_gatt_client.c +++ b/test/mock/mock_gatt_client.c @@ -11,34 +11,78 @@ static enum { MOCK_QUERY_IDLE = 0, MOCK_QUERY_DISCOVER_PRIMARY_SERVICES, + MOCK_QUERY_DISCOVER_CHARACTERISTICS, } mock_gatt_client_state; static uint8_t mock_gatt_client_att_error; static uint16_t mock_gatt_client_uuid; static gatt_client_t gatt_client; +static btstack_linked_list_t mock_gatt_client_services; + +static mock_gatt_client_service_t * mock_gatt_client_last_service; +static mock_gatt_client_characteristic_t * mock_gatt_client_last_characteristic; + void mock_gatt_client_reset(void){ mock_gatt_client_att_error = 0; mock_gatt_client_state = MOCK_QUERY_IDLE; + + + btstack_linked_list_iterator_t service_it; + btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); + while (btstack_linked_list_iterator_has_next(&service_it)){ + mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); + btstack_linked_list_remove(&mock_gatt_client_services, (btstack_linked_item_t *) service); + + btstack_linked_list_iterator_t characteristic_it; + btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); + while (btstack_linked_list_iterator_has_next(&characteristic_it)){ + mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); + btstack_linked_list_remove(&service->characteristics, (btstack_linked_item_t *) characteristic); + + btstack_linked_list_iterator_t desc_it; + btstack_linked_list_iterator_init(&desc_it, &characteristic->descriptors); + while (btstack_linked_list_iterator_has_next(&desc_it)){ + mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t *) btstack_linked_list_iterator_next(&desc_it); + btstack_linked_list_remove(&characteristic->descriptors, (btstack_linked_item_t *) desc); + free(desc); + } + free(characteristic); + } + free(service); + } } -void mock_gatt_client_add_primary_service(uint16_t service_uuid){ +void mock_gatt_client_add_primary_service_uuid16(uint16_t service_uuid){ + mock_gatt_client_last_service = (mock_gatt_client_service_t * )malloc(sizeof(mock_gatt_client_service_t)); + memset(mock_gatt_client_last_service, 0, sizeof(mock_gatt_client_service_t)); + mock_gatt_client_last_service->uuid16 = service_uuid; + + btstack_linked_list_add(&mock_gatt_client_services, (btstack_linked_item_t*)mock_gatt_client_last_service); } -void mock_gatt_client_add_characteristic(uint16_t characteristic_uuid){ +void mock_gatt_client_add_characteristic_uuid16(uint16_t characteristic_uuid){ + btstack_assert(mock_gatt_client_last_service != NULL); + mock_gatt_client_last_characteristic = (mock_gatt_client_characteristic_t * )malloc(sizeof(mock_gatt_client_characteristic_t)); + memset(mock_gatt_client_last_characteristic, 0, sizeof(mock_gatt_client_characteristic_t)); + mock_gatt_client_last_characteristic->uuid16 = characteristic_uuid; + btstack_linked_list_add(&mock_gatt_client_last_service->characteristics, (btstack_linked_item_t*)mock_gatt_client_last_characteristic); } -void mock_gatt_client_add_characteristic_descriptor(uint16_t descriptor_uuid){ +void mock_gatt_client_add_characteristic_descriptor_uuid16(uint16_t descriptor_uuid){ + mock_gatt_client_characteristic_descriptor_t * desc = (mock_gatt_client_characteristic_descriptor_t * )malloc(sizeof(mock_gatt_client_characteristic_descriptor_t)); + memset(desc, 0, sizeof(mock_gatt_client_characteristic_descriptor_t)); + desc->uuid16 = descriptor_uuid; + btstack_linked_list_add(&mock_gatt_client_last_characteristic->descriptors, (btstack_linked_item_t*)desc); } + // simulate erro void mock_gatt_client_simulate_att_error(uint8_t att_error){ mock_gatt_client_att_error = att_error; } uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){ - printf("gatt_client_discover_primary_services_by_uuid16 callback %p\n", callback); - mock_gatt_client_state = MOCK_QUERY_DISCOVER_PRIMARY_SERVICES; mock_gatt_client_uuid = uuid16; @@ -48,7 +92,11 @@ uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t } 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){ - btstack_assert(false); + mock_gatt_client_state = MOCK_QUERY_DISCOVER_CHARACTERISTICS; + mock_gatt_client_uuid = uuid16; + + gatt_client.callback = callback; + gatt_client.con_handle = con_handle; return ERROR_CODE_SUCCESS; } @@ -132,26 +180,90 @@ static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_st emit_event_new(gatt_client->callback, packet, sizeof(packet)); } +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){ + // @format HX + uint8_t packet[24]; + packet[0] = GATT_EVENT_SERVICE_QUERY_RESULT; + packet[1] = sizeof(packet) - 2u; + little_endian_store_16(packet, 2, gatt_client->con_handle); + /// + little_endian_store_16(packet, 4, start_group_handle); + little_endian_store_16(packet, 6, end_group_handle); + reverse_128(uuid128, &packet[8]); + emit_event_new(gatt_client->callback, packet, sizeof(packet)); +} + +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, + uint16_t properties, const uint8_t * uuid128){ + // @format HY + uint8_t packet[28]; + packet[0] = GATT_EVENT_CHARACTERISTIC_QUERY_RESULT; + packet[1] = sizeof(packet) - 2u; + little_endian_store_16(packet, 2, gatt_client->con_handle); + /// + little_endian_store_16(packet, 4, start_handle); + little_endian_store_16(packet, 6, value_handle); + little_endian_store_16(packet, 8, end_handle); + little_endian_store_16(packet, 10, properties); + reverse_128(uuid128, &packet[12]); + emit_event_new(gatt_client->callback, packet, sizeof(packet)); +} + /** * copied from gatt_client.c - END */ -// magic +static void mock_gatt_client_emit_complete(uint8_t status){ + mock_gatt_client_state = MOCK_QUERY_IDLE; + emit_gatt_complete_event(&gatt_client, status); +} void mock_gatt_client_run(void){ btstack_assert(mock_gatt_client_state != MOCK_QUERY_IDLE); - switch (mock_gatt_client_state){ - case MOCK_QUERY_DISCOVER_PRIMARY_SERVICES: - // emit GATT_EVENT_SERVICE_QUERY_RESULT for each matching service - // TODO: - // emit GATT_EVENT_QUERY_COMPLETE with status mock_gatt_client_att_error - emit_gatt_complete_event(&gatt_client, ERROR_CODE_SUCCESS); - // reset status - mock_gatt_client_att_error = ERROR_CODE_SUCCESS; - break; - default: - btstack_assert(false); - break; - } + btstack_linked_list_iterator_t service_it; + btstack_linked_list_iterator_t characteristic_it; + uint8_t uuid128[16]; + + while (mock_gatt_client_state != MOCK_QUERY_IDLE){ + switch (mock_gatt_client_state){ + case MOCK_QUERY_DISCOVER_PRIMARY_SERVICES: + // emit GATT_EVENT_SERVICE_QUERY_RESULT for each matching service + btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); + while (btstack_linked_list_iterator_has_next(&service_it)){ + mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); + if (service->uuid16 != mock_gatt_client_uuid) continue; + mock_gatt_client_last_service = service; + uuid_add_bluetooth_prefix(uuid128, service->uuid16); + emit_gatt_service_query_result_event(&gatt_client, 0x01, 0xFFFF, uuid128); + } + // emit GATT_EVENT_QUERY_COMPLETE + mock_gatt_client_emit_complete(ATT_ERROR_SUCCESS); + break; + + case MOCK_QUERY_DISCOVER_CHARACTERISTICS: + // emit GATT_EVENT_CHARACTERISTIC_QUERY_RESULT for each matching characteristic + btstack_linked_list_iterator_init(&service_it, &mock_gatt_client_services); + while (btstack_linked_list_iterator_has_next(&service_it)){ + mock_gatt_client_service_t * service = (mock_gatt_client_service_t *) btstack_linked_list_iterator_next(&service_it); + + btstack_linked_list_iterator_init(&characteristic_it, &service->characteristics); + while (btstack_linked_list_iterator_has_next(&characteristic_it)){ + mock_gatt_client_characteristic_t * characteristic = (mock_gatt_client_characteristic_t *) btstack_linked_list_iterator_next(&characteristic_it); + if (characteristic->uuid16 != mock_gatt_client_uuid) continue; + // TODO validate handle range + uuid_add_bluetooth_prefix(uuid128, characteristic->uuid16); + emit_gatt_characteristic_query_result_event(&gatt_client, 0x01, 0x02, 0xFFFF, 0, uuid128); + } + } + + // emit GATT_EVENT_QUERY_COMPLETE + mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS); + break; + default: + btstack_assert(false); + break; + } + } + mock_gatt_client_att_error = ERROR_CODE_SUCCESS; mock_gatt_client_state = MOCK_QUERY_IDLE; } \ No newline at end of file diff --git a/test/mock/mock_gatt_client.h b/test/mock/mock_gatt_client.h index e75199207..7cd70af98 100644 --- a/test/mock/mock_gatt_client.h +++ b/test/mock/mock_gatt_client.h @@ -45,11 +45,40 @@ extern "C" { #include "ble/gatt_client.h" +typedef struct { + btstack_linked_item_t item; + // uint16_t start_group_handle; + // uint16_t end_group_handle; + uint16_t uuid16; + // uint8_t uuid128[16]; + btstack_linked_list_t characteristics; +} mock_gatt_client_service_t; + +typedef struct { + btstack_linked_item_t item; + // uint16_t start_handle; + uint16_t value_handle; + // uint16_t end_handle; + // uint16_t properties; + uint16_t uuid16; + // uint8_t uuid128[16]; + btstack_linked_list_t descriptors; +} mock_gatt_client_characteristic_t; + +typedef struct { + btstack_linked_item_t item; + // uint16_t handle; + uint16_t uuid16; + // uint8_t uuid128[16]; +} mock_gatt_client_characteristic_descriptor_t; + + void mock_gatt_client_reset(void); -void mock_gatt_client_add_primary_service(uint16_t service_uuid); -void mock_gatt_client_add_characteristic(uint16_t characteristic_uuid); -void mock_gatt_client_add_characteristic_descriptor(uint16_t descriptor_uuid); +void mock_gatt_client_add_primary_service_uuid16(uint16_t service_uuid); +void mock_gatt_client_add_characteristic_uuid16(uint16_t characteristic_uuid); +void mock_gatt_client_add_characteristic_descriptor_uuid16(uint16_t descriptor_uuid); + void mock_gatt_client_run(void); #if defined __cplusplus