From 4d890b2d0d5e5b5057ce3bbb5a4b8ff6a3af5b10 Mon Sep 17 00:00:00 2001 From: "mila@ringwald.ch" Date: Fri, 11 Apr 2014 08:50:07 +0000 Subject: [PATCH] ble client: unit test discover primary services --- test/gatt_client/Makefile | 7 +- test/gatt_client/gatt_client.c | 66 +++++++++++++++-- test/gatt_client/mock.c | 22 +++++- test/gatt_client/profile.gatt | 130 +++++++++++++++++++++++++++++++++ 4 files changed, 213 insertions(+), 12 deletions(-) create mode 100644 test/gatt_client/profile.gatt diff --git a/test/gatt_client/Makefile b/test/gatt_client/Makefile index 849ca1b10..04aae9ddd 100644 --- a/test/gatt_client/Makefile +++ b/test/gatt_client/Makefile @@ -19,13 +19,18 @@ COMMON = \ ${BTSTACK_ROOT}/src/run_loop_posix.c \ ${BTSTACK_ROOT}/src/hci_cmds.c \ ${BTSTACK_ROOT}/example/libusb/ble_client.c \ + ${BTSTACK_ROOT}/ble/att.c \ mock.c COMMON_OBJ = $(COMMON:.c=.o) all: gatt_client -gatt_client: ${CORE_OBJ} ${COMMON_OBJ} gatt_client.c +# compile .ble description +profile.h: profile.gatt + python ${BTSTACK_ROOT}/ble/compile-gatt.py $< $@ + +gatt_client: ${CORE_OBJ} ${COMMON_OBJ} gatt_client.c profile.h ${CC} ${CORE_OBJ} ${COMMON_OBJ} gatt_client.c ${CFLAGS} ${LDFLAGS} -o $@ clean: diff --git a/test/gatt_client/gatt_client.c b/test/gatt_client/gatt_client.c index e25177d2c..317557887 100644 --- a/test/gatt_client/gatt_client.c +++ b/test/gatt_client/gatt_client.c @@ -19,18 +19,26 @@ #include "btstack_memory.h" #include "hci.h" #include "ble_client.h" +#include "att.h" +#include "profile.h" static bd_addr_t test_device_addr = {0x34, 0xb1, 0xf7, 0xd1, 0x77, 0x9b}; static le_peripheral_t test_device; +static int result_index; +static le_service_t services[50]; + static uint8_t advertisement_received; static uint8_t connected; +static uint8_t primary_services_found; void mock_simulate_hci_state_working(); void mock_simulate_command_complete(const hci_cmd_t *cmd); void mock_simulate_scan_response(); void mock_simulate_connected(); void mock_simulate_exchange_mtu(); +void mock_simulate_discover_primary_services_response(); + void CHECK_EQUAL_ARRAY(uint8_t * expected, uint8_t * actual, int size){ int i; @@ -47,6 +55,24 @@ static void verify_advertisement(ad_event_t * e){ CHECK_EQUAL_ARRAY((uint8_t *)test_device_addr, (uint8_t *)e->address, 6); } +static void verify_primary_services(){ + CHECK_EQUAL(6, result_index); + + uint8_t uuids[6][16] = { + {0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}, + {0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}, + {0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}, + {0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}, + {0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}, + {0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb} + }; + + int i; + for (i=0; itype){ case GATT_ADVERTISEMENT: @@ -57,6 +83,13 @@ static void handle_le_central_event(le_central_event_t * event){ printf("GATT_CONNECTION_COMPLETE\n"); connected = 1; break; + case GATT_SERVICE_QUERY_RESULT: + services[result_index++] = ((le_service_event_t *) event)->service; + break; + case GATT_SERVICE_QUERY_COMPLETE: + verify_primary_services(); + primary_services_found = 1; + break; default: printf("handle_le_central_event"); break; @@ -64,32 +97,49 @@ static void handle_le_central_event(le_central_event_t * event){ } TEST_GROUP(GATTClient){ + int acl_buffer_size; + uint8_t acl_buffer[27]; + void setup(){ advertisement_received = 0; connected = 0; + primary_services_found = 0; + result_index = 0; le_central_init(); le_central_register_handler(handle_le_central_event); - // le_central_register_packet_handler(handle_hci_event); mock_simulate_hci_state_working(); + att_set_db(profile_data); } }; +// TEST(GATTClient, TestScanning){ +// le_central_start_scan(); +// mock_simulate_command_complete(&hci_le_set_scan_enable); +// mock_simulate_scan_response(); +// CHECK(advertisement_received); +// } -TEST(GATTClient, TestScanning){ - le_central_start_scan(); - mock_simulate_command_complete(&hci_le_set_scan_enable); - mock_simulate_scan_response(); - CHECK(advertisement_received); -} +// TEST(GATTClient, TestConnecting){ +// le_central_connect(&test_device, 1, test_device_addr); +// mock_simulate_connected(); +// mock_simulate_exchange_mtu(); +// CHECK(connected); +// } -TEST(GATTClient, TestConnecting){ +TEST(GATTClient, TestDiscoverPrimaryServices){ le_central_connect(&test_device, 1, test_device_addr); mock_simulate_connected(); mock_simulate_exchange_mtu(); CHECK(connected); + + le_central_discover_primary_services(&test_device); + CHECK(primary_services_found); } + + + int main (int argc, const char * argv[]){ return CommandLineTestRunner::RunAllTests(argc, argv); } diff --git a/test/gatt_client/mock.c b/test/gatt_client/mock.c index a0908891c..0ef5f0216 100644 --- a/test/gatt_client/mock.c +++ b/test/gatt_client/mock.c @@ -4,6 +4,7 @@ #include #include +#include "att.h" #include "hci.h" #include "hci_dump.h" #include "l2cap.h" @@ -37,9 +38,15 @@ void mock_simulate_scan_response(){ } void mock_simulate_exchange_mtu(){ - printf("mock_simulate_exchange_mtu\n"); - uint8_t packet[] = {0x03, 0x17, 0x00}; - att_packet_handler(ATT_DATA_PACKET, 0x40, (uint8_t *)&packet, sizeof(packet)); + // uint8_t packet[] = {0x03, 0x17, 0x00}; + // att_packet_handler(ATT_DATA_PACKET, 0x40, (uint8_t *)&packet, sizeof(packet)); +} + +static void att_init_connection(att_connection_t * att_connection){ + att_connection->mtu = 23; + att_connection->encryption_key_size = 0; + att_connection->authenticated = 0; + att_connection->authorized = 0; } int hci_can_send_packet_now_using_packet_buffer(uint8_t packet_type){ @@ -82,6 +89,15 @@ int l2cap_reserve_packet_buffer(void){ int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t len){ printf("l2cap_send_prepared_connectionless\n"); + // assert handle = current connection + // assert cid = att + + att_connection_t att_connection; + att_init_connection(&att_connection); + uint8_t response[max_mtu]; + uint16_t response_len = att_handle_request(&att_connection, l2cap_get_outgoing_buffer(), len, &response[0]); + att_packet_handler(ATT_DATA_PACKET, 0x40, &response[0], response_len); + return 0; } diff --git a/test/gatt_client/profile.gatt b/test/gatt_client/profile.gatt new file mode 100644 index 000000000..97c7d04c7 --- /dev/null +++ b/test/gatt_client/profile.gatt @@ -0,0 +1,130 @@ +PRIMARY_SERVICE, GAP_SERVICE +CHARACTERISTIC, GAP_DEVICE_NAME, READ | WRITE | DYNAMIC, +CHARACTERISTIC, GAP_APPEARANCE, READ | WRITE | DYNAMIC, +// GAP Peripheral Privacy Flag +CHARACTERISTIC, 2A02, READ | WRITE | DYNAMIC, 00 +// GAP Reconnection Address - 6 bytes +CHARACTERISTIC, 2A03, READ | WRITE | DYNAMIC, +// GAP Peripheral Preferred Connection Parameters +CHARACTERISTIC, 2A04, READ | WRITE | DYNAMIC, + +PRIMARY_SERVICE, GATT_SERVICE +CHARACTERISTIC, GATT_SERVICE_CHANGED, READ, + +SECONDARY_SERVICE, 0000FF10-0000-1000-8000-00805F9B34FB +CHARACTERISTIC, FF10, READ | WRITE | DYNAMIC, + +SECONDARY_SERVICE, 0000FF11-0000-1000-8000-00805F9B34FB +CHARACTERISTIC, FF11, READ | WRITE | DYNAMIC, + +// +PRIMARY_SERVICE, FFFF +CHARACTERISTIC, FFFD, READ | WRITE | DYNAMIC, +CHARACTERISTIC, FFFE, READ | WRITE | DYNAMIC, +// +PRIMARY_SERVICE, FFFF +CHARACTERISTIC, FFFD, READ | WRITE | DYNAMIC, +CHARACTERISTIC, FFFE, READ | WRITE | DYNAMIC, +// +// SECONDARY_SERVICE, FFFA +// CHARACTERISTIC, FFFB, READ | WRITE | DYNAMIC, +// +// SECONDARY_SERVICE, FFF9 +// INCLUDE_SERVICE, FFFA +// +// SECONDARY_SERVICE, FFF7 +// INCLUDE_SERVICE, FFF9 +// CHARACTERISTIC, FFF8, READ | WRITE | DYNAMIC, +// +SECONDARY_SERVICE, FFF4 +// INCLUDE_SERVICE, FFF7 +// INCLUDE_SERVICE, FFFC +// INCLUDE_SERVICE, FFFF +CHARACTERISTIC, FFF5, READ | WRITE | DYNAMIC, +CHARACTERISTIC, FFF6, READ | WRITE | DYNAMIC, +// +// PRIMARY_SERVICE, FFF0 +// INCLUDE_SERVICE, FFF4 +// CHARACTERISTIC, FFF1, READ | WRITE | DYNAMIC | AUTHORIZATION_REQUIRED | ENCRYPTION_KEY_SIZE_7 | AUTHENTICATION_REQUIRED, +// CHARACTERISTIC, FFF2, READ | WRITE | DYNAMIC, +// CHARACTERISTIC, FFF3, READ | INDICATE, +// CHARACTERISTIC, 00001234-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC, + +// Primary Service with 16-bit UUID, included service +PRIMARY_SERVICE, F000 +INCLUDE_SERVICE, FFF4 +// Characteristics 16 and 128 bit with different authoriztion/authentication/encryption requirements and read/write flags +// - no requirements +CHARACTERISTIC, F100, READ | WRITE | DYNAMIC | NOTIFY | INDICATE | RELIABLE_WRITE, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC, +CHARACTERISTIC, 0000F101-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC | NOTIFY | INDICATE | RELIABLE_WRITE, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC, +// - neither read nor writable +CHARACTERISTIC, F102, DYNAMIC, +CHARACTERISTIC_USER_DESCRIPTION, DYNAMIC, +CHARACTERISTIC, 0000F103-0000-1000-8000-00805F9B34FB, DYNAMIC, +CHARACTERISTIC_USER_DESCRIPTION, DYNAMIC, +// - authorization required +CHARACTERISTIC, F104, READ | WRITE | DYNAMIC | AUTHORIZATION_REQUIRED, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | AUTHORIZATION_REQUIRED, +CHARACTERISTIC, 0000F105-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC | AUTHORIZATION_REQUIRED, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | AUTHORIZATION_REQUIRED, +// - authenthication required +CHARACTERISTIC, F106, READ | WRITE | DYNAMIC | AUTHENTICATION_REQUIRED, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | AUTHENTICATION_REQUIRED, +CHARACTERISTIC, 0000F107-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC | AUTHENTICATION_REQUIRED, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | AUTHENTICATION_REQUIRED, +// - encryptiont with 128 bit key required +CHARACTERISTIC, F108, READ | WRITE | DYNAMIC | ENCRYPTION_KEY_SIZE_16, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | ENCRYPTION_KEY_SIZE_16, +CHARACTERISTIC, 0000F109-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC | ENCRYPTION_KEY_SIZE_16, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | ENCRYPTION_KEY_SIZE_16, +// - write only +CHARACTERISTIC, F10A, WRITE | DYNAMIC, + +// - read/write, incl. server characteristic configuration, characteristic format (uint8_t, exponent = 0, unitless, Bluetooth SIG, and characteristic aggregate format +CHARACTERISTIC, F10B, READ | WRITE | DYNAMIC, +SERVER_CHARACTERISTIC_CONFIGURATION, READ | WRITE | DYNAMIC, +CHARACTERISTIC_FORMAT, 1, 04, 0, 2700, 1, 0000 +CHARACTERISTIC_FORMAT, 2, 0c, 0, 2700, 1, 0000 +CHARACTERISTIC_AGGREGATE_FORMAT, 1, 2 + +// - read/write/write without response +CHARACTERISTIC, F10D, READ | WRITE | WRITE_WITHOUT_RESPONSE | DYNAMIC, +// - read/write without response +CHARACTERISTIC, F10C, READ | WRITE_WITHOUT_RESPONSE | DYNAMIC, +// - read/authenticated signed writes +CHARACTERISTIC, F10E, READ | WRITE | AUTHENTICATED_SIGNED_WRITE | DYNAMIC, + +// Primary Service with 128-bit UUID, included service +PRIMARY_SERVICE, 0000F001-0000-1000-8000-00805F9B34FB +INCLUDE_SERVICE, 0000FF10-0000-1000-8000-00805F9B34FB +INCLUDE_SERVICE, 0000FF11-0000-1000-8000-00805F9B34FB +// Characteristics 16 and 128 bit with different authoriztion/authentication/encryption requirements and read/write flags +// - no requirements +CHARACTERISTIC, F200, READ | WRITE | DYNAMIC | NOTIFY | INDICATE | RELIABLE_WRITE | WRITE_WITHOUT_RESPONSE, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC, +CHARACTERISTIC, 0000F201-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC | NOTIFY | INDICATE | RELIABLE_WRITE, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC, +// - neither read nor writable +CHARACTERISTIC, F202, DYNAMIC, +CHARACTERISTIC_USER_DESCRIPTION, DYNAMIC, +CHARACTERISTIC, 0000F203-0000-1000-8000-00805F9B34FB, DYNAMIC, +CHARACTERISTIC_USER_DESCRIPTION, DYNAMIC, +// - authorization required +CHARACTERISTIC, F204, READ | WRITE | DYNAMIC | AUTHORIZATION_REQUIRED, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | AUTHORIZATION_REQUIRED, +CHARACTERISTIC, 0000F205-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC | AUTHORIZATION_REQUIRED, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | AUTHORIZATION_REQUIRED, +// - authenthication required +CHARACTERISTIC, F206, READ | WRITE | DYNAMIC | AUTHENTICATION_REQUIRED, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | AUTHENTICATION_REQUIRED, +CHARACTERISTIC, 0000F207-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC | AUTHENTICATION_REQUIRED, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | AUTHENTICATION_REQUIRED, +// - encryptiont with 128 bit key required +CHARACTERISTIC, F208, READ | WRITE | DYNAMIC | ENCRYPTION_KEY_SIZE_16, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | ENCRYPTION_KEY_SIZE_16, +CHARACTERISTIC, 0000F209-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC | ENCRYPTION_KEY_SIZE_16, +CHARACTERISTIC_USER_DESCRIPTION, READ | WRITE | DYNAMIC | ENCRYPTION_KEY_SIZE_16, + +