mirror of
https://github.com/google/pebble.git
synced 2025-03-24 04:29:07 +00:00
319 lines
13 KiB
C
319 lines
13 KiB
C
/*
|
|
* Copyright 2024 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <bluetooth/gatt.h>
|
|
|
|
#include "comm/ble/gatt_client_accessors.h"
|
|
#include "comm/ble/gatt_client_discovery.h"
|
|
#include "comm/ble/gatt_service_changed.h"
|
|
#include "comm/ble/gap_le_connection.h"
|
|
|
|
#include "kernel/events.h"
|
|
|
|
#include "clar.h"
|
|
|
|
#include <btutil/bt_device.h>
|
|
#include <btutil/bt_uuid.h>
|
|
|
|
// Fakes
|
|
///////////////////////////////////////////////////////////
|
|
|
|
#include "fake_GAPAPI.h"
|
|
#include "fake_GATTAPI.h"
|
|
#include "fake_GATTAPI_test_vectors.h"
|
|
#include "fake_events.h"
|
|
#include "fake_new_timer.h"
|
|
#include "fake_system_task.h"
|
|
#include "fake_pbl_malloc.h"
|
|
|
|
// Stubs
|
|
///////////////////////////////////////////////////////////
|
|
|
|
#include "stubs_bluetopia_interface.h"
|
|
#include "stubs_bt_driver_gatt.h"
|
|
#include "stubs_bt_lock.h"
|
|
#include "stubs_gatt_client_subscriptions.h"
|
|
#include "stubs_logging.h"
|
|
#include "stubs_mutex.h"
|
|
#include "stubs_passert.h"
|
|
#include "stubs_prompt.h"
|
|
#include "stubs_rand_ptr.h"
|
|
#include "stubs_regular_timer.h"
|
|
|
|
void core_dump_reset(bool is_forced) {
|
|
}
|
|
|
|
void launcher_task_add_callback(void (*callback)(void *data), void *data) {
|
|
callback(data);
|
|
}
|
|
|
|
uint16_t gaps_get_starting_att_handle(void) {
|
|
return 4;
|
|
}
|
|
|
|
// Helpers
|
|
///////////////////////////////////////////////////////////
|
|
|
|
#define TEST_GATT_CONNECTION_ID (1234)
|
|
|
|
static BTDeviceInternal prv_dummy_device(uint8_t octet) {
|
|
BTDeviceAddress address = {
|
|
.octets = {
|
|
[0] = octet,
|
|
[1] = octet,
|
|
[2] = octet,
|
|
[3] = octet,
|
|
[4] = octet,
|
|
[5] = octet,
|
|
},
|
|
};
|
|
BTDevice device = bt_device_init_with_address(address, true /* is_random */);
|
|
return *(BTDeviceInternal *)(&device);
|
|
}
|
|
|
|
static BTDeviceInternal prv_connected_dummy_device(uint8_t octet) {
|
|
BTDeviceInternal device = prv_dummy_device(octet);
|
|
gap_le_connection_add(&device, NULL, true /* local_is_master */);
|
|
GAPLEConnection *connection = gap_le_connection_by_device(&device);
|
|
connection->gatt_connection_id = TEST_GATT_CONNECTION_ID;
|
|
return device;
|
|
}
|
|
|
|
static void prv_mock_put_service_discovery_events(void) {
|
|
// Simulate discovery of Blood Pressure service:
|
|
fake_gatt_put_discovery_indication_blood_pressure_service(TEST_GATT_CONNECTION_ID);
|
|
fake_gatt_put_discovery_indication_health_thermometer_service(TEST_GATT_CONNECTION_ID);
|
|
fake_gatt_put_discovery_indication_random_128bit_uuid_service(TEST_GATT_CONNECTION_ID);
|
|
fake_gatt_put_discovery_complete_event(GATT_SERVICE_DISCOVERY_STATUS_SUCCESS,
|
|
TEST_GATT_CONNECTION_ID);
|
|
}
|
|
|
|
// Tests
|
|
///////////////////////////////////////////////////////////
|
|
|
|
void test_gatt_client_accessors__initialize(void) {
|
|
fake_gatt_init();
|
|
fake_event_init();
|
|
gap_le_connection_init();
|
|
}
|
|
|
|
void test_gatt_client_accessors__cleanup(void) {
|
|
gap_le_connection_deinit();
|
|
}
|
|
|
|
void test_gatt_client_accessors__copy_service_refs(void) {
|
|
BTDeviceInternal device = prv_connected_dummy_device(1);
|
|
|
|
// Start discovery:
|
|
cl_assert_equal_i(gatt_client_discovery_discover_all(&device), BTErrnoOK);
|
|
prv_mock_put_service_discovery_events();
|
|
|
|
const Service *bp_service = fake_gatt_get_blood_pressure_service();
|
|
const Service *thermo_service = fake_gatt_get_health_thermometer_service();
|
|
const Service *random_128bit_service = fake_gatt_get_random_128bit_uuid_service();
|
|
const Service *services[] = {
|
|
bp_service,
|
|
thermo_service,
|
|
random_128bit_service,
|
|
};
|
|
const uint8_t num_services = 3;
|
|
|
|
// Test gatt_client_copy_service_refs():
|
|
BLEService service_refs[num_services];
|
|
uint8_t num_found_services = gatt_client_copy_service_refs(&device, service_refs, num_services);
|
|
cl_assert_equal_i(num_found_services, num_services);
|
|
|
|
for (uint8_t s = 0; s < num_found_services; ++s) {
|
|
BLEService service_ref = service_refs[s];
|
|
const Service *expected_service = services[s];
|
|
|
|
// Test gatt_client_service_get_uuid():
|
|
const Uuid uuid = gatt_client_service_get_uuid(service_ref);
|
|
cl_assert(uuid_equal(&uuid, &expected_service->uuid));
|
|
|
|
// Test gatt_client_service_get_device():
|
|
BTDeviceInternal returned_device = gatt_client_service_get_device(service_ref);
|
|
cl_assert(bt_device_equal(&returned_device.opaque, &device.opaque));
|
|
|
|
// Check Characteristics:
|
|
const uint8_t num_characteristics = expected_service->num_characteristics;
|
|
BLECharacteristic characteristic_refs[num_characteristics];
|
|
// Test gatt_client_service_get_characteristics():
|
|
const uint8_t num_found_characteristics =
|
|
gatt_client_service_get_characteristics(service_ref, characteristic_refs, num_characteristics);
|
|
cl_assert_equal_i(num_characteristics, num_found_characteristics);
|
|
|
|
for (uint8_t c = 0; c < num_found_characteristics; ++c) {
|
|
BLECharacteristic characteristic_ref = characteristic_refs[c];
|
|
const Characteristic *expected_characteristic = &expected_service->characteristics[c];
|
|
|
|
// Test gatt_client_characteristic_get_uuid():
|
|
const Uuid uuid = gatt_client_characteristic_get_uuid(characteristic_ref);
|
|
cl_assert(uuid_equal(&uuid, &expected_characteristic->uuid));
|
|
|
|
// Test gatt_client_characteristic_get_properties():
|
|
cl_assert_equal_i(gatt_client_characteristic_get_properties(characteristic_ref),
|
|
expected_characteristic->properties);
|
|
|
|
// Test gatt_client_characteristic_get_service():
|
|
cl_assert_equal_i(gatt_client_characteristic_get_service(characteristic_ref), service_ref);
|
|
|
|
// Test gatt_client_characteristic_get_device():
|
|
BTDeviceInternal returned_device = gatt_client_characteristic_get_device(characteristic_ref);
|
|
cl_assert(bt_device_equal(&returned_device.opaque, &device.opaque));
|
|
|
|
// Test gatt_client_characteristic_get_descriptors():
|
|
const uint8_t num_descriptors = expected_characteristic->num_descriptors;
|
|
BLEDescriptor descriptor_refs[num_descriptors];
|
|
const uint8_t num_found_descriptors =
|
|
gatt_client_characteristic_get_descriptors(characteristic_ref, descriptor_refs, num_descriptors);
|
|
cl_assert_equal_i(num_descriptors, num_found_descriptors);
|
|
|
|
for (uint8_t d = 0; d < num_descriptors; ++d) {
|
|
const Descriptor *expected_descriptor = &expected_characteristic->descriptors[d];
|
|
const BLEDescriptor descriptor_ref = descriptor_refs[d];
|
|
|
|
// Test gatt_client_descriptor_get_uuid():
|
|
const Uuid uuid = gatt_client_descriptor_get_uuid(descriptor_ref);
|
|
cl_assert(uuid_equal(&uuid, &expected_descriptor->uuid));
|
|
|
|
// Test gatt_client_descriptor_get_characteristic():
|
|
cl_assert_equal_i(gatt_client_descriptor_get_characteristic(descriptor_ref), characteristic_ref);
|
|
}
|
|
}
|
|
|
|
// Test gatt_client_service_get_included_services():
|
|
const uint8_t num_inc_services = expected_service->num_included_services;
|
|
BLEService inc_service_refs[num_inc_services];
|
|
const uint8_t num_found_included_services =
|
|
gatt_client_service_get_included_services(service_ref, inc_service_refs, num_inc_services);
|
|
cl_assert_equal_i(num_inc_services, num_found_included_services);
|
|
|
|
for (uint8_t i = 0; i < num_inc_services; ++i) {
|
|
const Service *expected_inc_service = expected_service->included_services[i];
|
|
BLEService inc_service = inc_service_refs[i];
|
|
|
|
// Only check the Service UUID:
|
|
const Uuid uuid = gatt_client_service_get_uuid(inc_service);
|
|
cl_assert(uuid_equal(&uuid, &expected_inc_service->uuid));
|
|
}
|
|
}
|
|
}
|
|
|
|
void test_gatt_client_accessors__copy_service_refs_matching(void) {
|
|
BTDeviceInternal device = prv_connected_dummy_device(1);
|
|
|
|
// Start discovery:
|
|
cl_assert_equal_i(gatt_client_discovery_discover_all(&device), BTErrnoOK);
|
|
prv_mock_put_service_discovery_events();
|
|
|
|
const uint8_t num_services = 1;
|
|
|
|
// Test gatt_client_copy_service_refs():
|
|
BLEService service_refs[num_services];
|
|
const Service *bp_service = fake_gatt_get_blood_pressure_service();
|
|
uint8_t num_found_services = gatt_client_copy_service_refs_matching_uuid(&device, service_refs,
|
|
num_services,
|
|
&bp_service->uuid);
|
|
cl_assert_equal_i(num_found_services, num_services);
|
|
|
|
// Test that the UUID matches the Blood Pressure UUID:
|
|
const Uuid uuid = gatt_client_service_get_uuid(service_refs[0]);
|
|
cl_assert(uuid_equal(&uuid, &bp_service->uuid));
|
|
}
|
|
|
|
void test_gatt_client_accessors__get_characteristics_matching_uuids(void) {
|
|
BTDeviceInternal device = prv_connected_dummy_device(1);
|
|
|
|
// Start discovery:
|
|
cl_assert_equal_i(gatt_client_discovery_discover_all(&device), BTErrnoOK);
|
|
prv_mock_put_service_discovery_events();
|
|
|
|
const Service *bp_service = fake_gatt_get_blood_pressure_service();
|
|
|
|
// Get the reference to the Blood Pressure service:
|
|
const uint8_t num_services = 1;
|
|
BLEService service_refs[num_services];
|
|
gatt_client_copy_service_refs_matching_uuid(&device, service_refs,
|
|
num_services, &bp_service->uuid);
|
|
|
|
Uuid matching_uuids[3];
|
|
matching_uuids[0] = bp_service->characteristics[1].uuid;
|
|
matching_uuids[1] = bt_uuid_expand_16bit(0xffff); // not expected to match
|
|
matching_uuids[2] = bp_service->characteristics[0].uuid;
|
|
|
|
BLECharacteristic characteristics[3];
|
|
const uint8_t found =
|
|
gatt_client_service_get_characteristics_matching_uuids(service_refs[0], characteristics,
|
|
matching_uuids, 3);
|
|
cl_assert_equal_i(found, 2);
|
|
|
|
// Expect the order of the matching_uuids array is preserved:
|
|
cl_assert(uuid_equal(&matching_uuids[0], &bp_service->characteristics[1].uuid));
|
|
cl_assert(uuid_equal(&matching_uuids[2], &bp_service->characteristics[0].uuid));
|
|
|
|
// Expect the 0xffff UUID to return "no match":
|
|
cl_assert_equal_i(characteristics[1], BLE_CHARACTERISTIC_INVALID);
|
|
}
|
|
|
|
extern uint8_t gatt_client_copy_service_refs_by_discovery_generation(
|
|
const BTDeviceInternal *device, BLEService services_out[],
|
|
uint8_t num_services, uint8_t discovery_gen);
|
|
extern void gatt_client_discovery_discover_range(GAPLEConnection *connection,
|
|
ATTHandleRange *hdl_range);
|
|
|
|
void test_gatt_client_accessors__get_service_refs_by_discovery_gen(void) {
|
|
BTDeviceInternal device = prv_connected_dummy_device(1);
|
|
|
|
cl_assert_equal_i(gatt_client_discovery_discover_all(&device), BTErrnoOK);
|
|
fake_gatt_put_discovery_indication_blood_pressure_service(TEST_GATT_CONNECTION_ID);
|
|
fake_gatt_put_discovery_complete_event(GATT_SERVICE_DISCOVERY_STATUS_SUCCESS, TEST_GATT_CONNECTION_ID);
|
|
|
|
ATTHandleRange range = {
|
|
.start = 0x1,
|
|
.end = 0xC000,
|
|
};
|
|
|
|
gatt_client_discovery_discover_range(gap_le_connection_by_device(&device), &range);
|
|
fake_gatt_put_discovery_indication_health_thermometer_service(TEST_GATT_CONNECTION_ID);
|
|
fake_gatt_put_discovery_indication_random_128bit_uuid_service(TEST_GATT_CONNECTION_ID);
|
|
fake_gatt_put_discovery_complete_event(GATT_SERVICE_DISCOVERY_STATUS_SUCCESS, TEST_GATT_CONNECTION_ID);
|
|
|
|
|
|
const Service *bp_service = fake_gatt_get_blood_pressure_service();
|
|
const Service *thermo_service = fake_gatt_get_health_thermometer_service();
|
|
const Service *random_128bit_service = fake_gatt_get_random_128bit_uuid_service();
|
|
|
|
BLEService service_refs_out[3];
|
|
|
|
// Only the BP service should be part of the first generation
|
|
uint8_t refs_out = gatt_client_copy_service_refs_by_discovery_generation(
|
|
&device, service_refs_out, 3, 0);
|
|
cl_assert_equal_i(1, refs_out);
|
|
const Uuid uuid = gatt_client_service_get_uuid(service_refs_out[0]);
|
|
cl_assert(uuid_equal(&uuid, &bp_service->uuid));
|
|
|
|
// Thermo & Random 128 bit service should be part of the second gen
|
|
refs_out = gatt_client_copy_service_refs_by_discovery_generation(
|
|
&device, service_refs_out, 3, 1);
|
|
cl_assert_equal_i(2, refs_out);
|
|
const Uuid uuid1 = gatt_client_service_get_uuid(service_refs_out[0]);
|
|
const Uuid uuid2 = gatt_client_service_get_uuid(service_refs_out[0]);
|
|
cl_assert(uuid_equal(&uuid1, &thermo_service->uuid) ||
|
|
uuid_equal(&uuid1, &random_128bit_service->uuid));
|
|
cl_assert(uuid_equal(&uuid2, &thermo_service->uuid) ||
|
|
uuid_equal(&uuid2, &random_128bit_service->uuid));
|
|
}
|