diff --git a/ble/att_db_util.c b/ble/att_db_util.c new file mode 100644 index 000000000..a73fd018e --- /dev/null +++ b/ble/att_db_util.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2014 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +#include +#include + +#include "att_db_util.h" +#include "att.h" +#include +#include "debug.h" + +// ATT DB Storage +#ifndef HAVE_MALLOC +#ifdef MAX_ATT_DB_SIZE +static uint8_t att_db_storage[MAX_ATT_DB_SIZE]; +#else +#error Neither HAVE_MALLOC] nor MAX_ATT_DB_SIZE is defined. +#endif +#endif + +static uint8_t * att_db; +static uint16_t att_db_size; +static uint16_t att_db_max_size; +static uint16_t att_db_next_handle; + +static void att_db_util_set_end_tag(void){ + // end tag + att_db[att_db_size] = 0; + att_db[att_db_size+1] = 0; +} + +void att_db_util_init(void){ +#ifdef HAVE_MALLOC + att_db = (uint8_t*) malloc(128); + att_db_max_size = 128; +#else + att_db = att_db_storage; + att_db_max_size = sizeof(att_db_storage); +#endif + att_db_size = 0; + att_db_next_handle = 1; + att_db_util_set_end_tag(); +} + +/** + * asserts that the requested amount of bytes can be stored in the att_db + * @returns TRUE if space is available + */ +static int att_db_util_assert_space(uint16_t size){ + size += 2; // for end tag + if (att_db_size + size <= att_db_max_size) return true; +#ifdef HAVE_MALLOC + int new_size = att_db_size + att_db_size / 2; + att_db = (uint8_t*) realloc(att_db, new_size); + if (!att_db) { + log_error("att_db: realloc failed"); + return false; + } + att_db_max_size = new_size; + return true; +#else + log_error("att_db: out of memory"); + return false; +#endif +} + +// attribute size in bytes (16), flags(16), handle (16), uuid (16/128), value(...) + +// db endds with 0x00 0x00 + +static void att_db_util_add_attribute_uuid16(uint16_t uuid16, uint16_t flags, uint8_t * data, uint16_t data_len){ + int size = 2 + 2 + 2 + 2 + data_len; + if (!att_db_util_assert_space(size)) return; + bt_store_16(att_db, att_db_size, size); + att_db_size += 2; + bt_store_16(att_db, att_db_size, flags); + att_db_size += 2; + bt_store_16(att_db, att_db_size, att_db_next_handle); + att_db_size += 2; + att_db_next_handle++; + bt_store_16(att_db, att_db_size, uuid16); + att_db_size += 2; + memcpy(&att_db[att_db_size], data, data_len); + att_db_size += data_len; + att_db_util_set_end_tag(); +} + +static void att_db_util_add_attribute_uuid128(uint8_t * uuid128, uint16_t flags, uint8_t * data, uint16_t data_len){ + int size = 2 + 2 + 2 + 16 + data_len; + if (!att_db_util_assert_space(size)) return; + flags |= ATT_PROPERTY_UUID128; + bt_store_16(att_db, att_db_size, size); + att_db_size += 2; + bt_store_16(att_db, att_db_size, flags); + att_db_size += 2; + bt_store_16(att_db, att_db_size, att_db_next_handle); + att_db_size += 2; + att_db_next_handle++; + swap128(uuid128, &att_db[att_db_size]); + att_db_size += 16; + memcpy(&att_db[att_db_size], data, data_len); + att_db_size += data_len; + att_db_util_set_end_tag(); +} + +void att_db_util_add_service_uuid16(uint16_t uuid16){ + uint8_t buffer[2]; + bt_store_16(buffer, 0, uuid16); + att_db_util_add_attribute_uuid16(GATT_PRIMARY_SERVICE_UUID, ATT_PROPERTY_READ, buffer, 2); +} + +void att_db_util_add_service_uuid128(uint8_t * uuid128){ + uint8_t buffer[16]; + swap128(uuid128, buffer); + att_db_util_add_attribute_uuid16(GATT_PRIMARY_SERVICE_UUID, ATT_PROPERTY_READ, buffer, 16); +} + +uint16_t att_db_util_add_characteristic_uuid16(uint16_t uuid16, uint16_t properties, uint8_t * data, uint16_t data_len){ + uint8_t buffer[5]; + buffer[0] = properties; + bt_store_16(buffer, 1, att_db_next_handle + 1); + bt_store_16(buffer, 3, uuid16); + att_db_util_add_attribute_uuid16(GATT_CHARACTERISTICS_UUID, ATT_PROPERTY_READ, buffer, sizeof(buffer)); + uint16_t value_handle = att_db_next_handle; + att_db_util_add_attribute_uuid16(uuid16, properties, data, data_len); + if (properties & (ATT_PROPERTY_NOTIFY | ATT_PROPERTY_INDICATE)){ + uint16_t flags = ATT_PROPERTY_READ | ATT_PROPERTY_WRITE | ATT_PROPERTY_DYNAMIC; + bt_store_16(buffer, 0, 0); + att_db_util_add_attribute_uuid16(GATT_CLIENT_CHARACTERISTICS_CONFIGURATION, flags, buffer, 2); + } + return value_handle; +} + +uint16_t att_db_util_add_characteristic_uuid128(uint8_t * uuid128, uint16_t properties, uint8_t * data, uint16_t data_len){ + uint8_t buffer[19]; + buffer[0] = properties; + bt_store_16(buffer, 1, att_db_next_handle + 1); + swap128(uuid128, &buffer[3]); + att_db_util_add_attribute_uuid16(GATT_CHARACTERISTICS_UUID, ATT_PROPERTY_READ, buffer, sizeof(buffer)); + uint16_t value_handle = att_db_next_handle; + att_db_util_add_attribute_uuid128(uuid128, properties, data, data_len); + if (properties & (ATT_PROPERTY_NOTIFY | ATT_PROPERTY_INDICATE)){ + uint16_t flags = ATT_PROPERTY_READ | ATT_PROPERTY_WRITE | ATT_PROPERTY_DYNAMIC; + bt_store_16(buffer, 0, 0); + att_db_util_add_attribute_uuid16(GATT_CLIENT_CHARACTERISTICS_CONFIGURATION, flags, buffer, 2); + } + return value_handle; +} + +uint8_t * att_db_util_get_address(void){ + return att_db; +} + +uint16_t att_db_util_get_size(void){ + return att_db_size + 2; // end tag +} diff --git a/ble/att_db_util.h b/ble/att_db_util.h new file mode 100644 index 000000000..9f08bbb2c --- /dev/null +++ b/ble/att_db_util.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +/** + * Helper to construct ATT DB at runtime + * (BTstack GATT Compiler is not used) + */ + +#ifndef __ATT_DB_UTIL +#define __ATT_DB_UTIL + +#include "btstack-config.h" +# +#ifdef HAVE_MALLOC +#else +#endif + +#include + +#if defined __cplusplus +extern "C" { +#endif + +/** + * @brief Init ATT DB storage + */ +void att_db_util_init(void); + +/** + * @brief Add primary service for 16-bit UUID + */ +void att_db_util_add_service_uuid16(uint16_t udid16); + +/** + * @brief Add primary service for 128-bit UUID + */ +void att_db_util_add_service_uuid128(uint8_t * udid128); + +/** + * @brief Add Characteristic with 16-bit UUID, properties, and data + * @returns attribute value handle + * @see ATT_PROPERTY_* in ble/att.h + */ +uint16_t att_db_util_add_characteristic_uuid16(uint16_t udid16, uint16_t properties, uint8_t * data, uint16_t data_len); + +/** + * @brief Add Characteristic with 128-bit UUID, properties, and data + * @returns attribute value handle + * @see ATT_PROPERTY_* in ble/att.h + */ +uint16_t att_db_util_add_characteristic_uuid128(uint8_t * udid128, uint16_t properties, uint8_t * data, uint16_t data_len); + +/** + * @brief Get address of constructed ATT DB + */ +uint8_t * att_db_util_get_address(void); + +/** + * @brief Get size of constructed ATT DB + */ +uint16_t att_db_util_get_size(void); + +#if defined __cplusplus +} +#endif +#endif diff --git a/test/Makefile b/test/Makefile index 89b12a9a9..a61e68303 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,6 +2,7 @@ # Makefile to build and run all tests SUBDIRS = \ + att_db_util \ ble_client \ des_iterator \ gatt_client \ diff --git a/test/att_db/Makefile b/test/att_db/Makefile new file mode 100644 index 000000000..9a61f5f26 --- /dev/null +++ b/test/att_db/Makefile @@ -0,0 +1,34 @@ +CC = g++ + +# Requirements: http://www.cpputest.org/ should be placed in btstack/test + +BTSTACK_ROOT = ../.. +CPPUTEST_HOME = ${BTSTACK_ROOT}/test/cpputest + +CFLAGS = -g -Wall -I.. -I${BTSTACK_ROOT}/example/libusb -I${BTSTACK_ROOT}/src -I${BTSTACK_ROOT}/ble -I${BTSTACK_ROOT}/include -I$(CPPUTEST_HOME)/include +# -L$(CPPUTEST_HOME)/lib +LDFLAGS += -lCppUTest -lCppUTestExt + +VPATH += ${BTSTACK_ROOT}/ble +VPATH += ${BTSTACK_ROOT}/src +VPATH += ${BTSTACK_ROOT}/platforms/posix/src + +COMMON = \ + utils.c \ + att_db_util.c \ + +COMMON_OBJ = $(COMMON:.c=.o) + +all: att_db_util_test + +att_db_util_test: ${COMMON_OBJ} att_db_util_test.c + ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ + +test: + ./att_db_util_test + +clean: + rm -f att_db_util_test + rm -f *.o + rm -rf *.dSYM + \ No newline at end of file diff --git a/test/att_db/att_db_util_test.c b/test/att_db/att_db_util_test.c new file mode 100644 index 000000000..a389ecfce --- /dev/null +++ b/test/att_db/att_db_util_test.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2014 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +// ***************************************************************************** +// +// test rfcomm query tests +// +// ***************************************************************************** + + +#include +#include +#include +#include + +#include "CppUTest/TestHarness.h" +#include "CppUTest/CommandLineTestRunner.h" + +#include "att.h" +#include "att_db_util.h" +#include "le_counter.h" +#include + +#if 0 +PRIMARY_SERVICE, GAP_SERVICE +CHARACTERISTIC, GAP_DEVICE_NAME, READ, "SPP+LE Counter" + +PRIMARY_SERVICE, GATT_SERVICE +CHARACTERISTIC, GATT_SERVICE_CHANGED, READ, + +// Counter Service +PRIMARY_SERVICE, 0000FF10-0000-1000-8000-00805F9B34FB +// Counter Characteristic, with read and notify +CHARACTERISTIC, 0000FF11-0000-1000-8000-00805F9B34FB, READ | NOTIFY | DYNAMIC, +#endif + +// 0000FF10-0000-1000-8000-00805F9B34FB +uint8_t counter_service_uuid[] = { 0x00, 0x00, 0xFF, 0x10, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}; +// 0000FF11-0000-1000-8000-00805F9B34FB +uint8_t counter_characteristic_uuid[] = { 0x00, 0x00, 0xFF, 0x11, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}; + +void CHECK_EQUAL_ARRAY(const uint8_t * expected, uint8_t * actual, int size){ + for (int i=0; i + +const uint8_t profile_data[] = +{ + // 0x0001 PRIMARY_SERVICE-GAP_SERVICE + 0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x18, + // 0x0002 CHARACTERISTIC-GAP_DEVICE_NAME-READ + 0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x02, 0x03, 0x00, 0x00, 0x2a, + // 0x0003 VALUE-GAP_DEVICE_NAME-READ-'SPP+LE Counter' + 0x16, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x2a, 0x53, 0x50, 0x50, 0x2b, 0x4c, 0x45, 0x20, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, + + // 0x0004 PRIMARY_SERVICE-GATT_SERVICE + 0x0a, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x28, 0x01, 0x18, + // 0x0005 CHARACTERISTIC-GATT_SERVICE_CHANGED-READ + 0x0d, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x28, 0x02, 0x06, 0x00, 0x05, 0x2a, + // 0x0006 VALUE-GATT_SERVICE_CHANGED-READ-'' + 0x08, 0x00, 0x02, 0x00, 0x06, 0x00, 0x05, 0x2a, +// Counter Service + + // 0x0007 PRIMARY_SERVICE-0000FF10-0000-1000-8000-00805F9B34FB + 0x18, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x28, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x10, 0xff, 0x00, 0x00, +// Counter Characteristic, with read and notify + // 0x0008 CHARACTERISTIC-0000FF11-0000-1000-8000-00805F9B34FB-READ | NOTIFY | DYNAMIC + 0x1b, 0x00, 0x02, 0x00, 0x08, 0x00, 0x03, 0x28, 0x12, 0x09, 0x00, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x11, 0xff, 0x00, 0x00, + // 0x0009 VALUE-0000FF11-0000-1000-8000-00805F9B34FB-READ | NOTIFY | DYNAMIC-'' + 0x16, 0x00, 0x12, 0x03, 0x09, 0x00, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x11, 0xff, 0x00, 0x00, + // 0x000a CLIENT_CHARACTERISTIC_CONFIGURATION + 0x0a, 0x00, 0x0a, 0x01, 0x0a, 0x00, 0x02, 0x29, 0x00, 0x00, + // END + 0x00, 0x00, +}; // total size 99 bytes + + +// +// list mapping between characteristics and handles +// +#define ATT_CHARACTERISTIC_GAP_DEVICE_NAME_01_VALUE_HANDLE 0x0003 +#define ATT_CHARACTERISTIC_GATT_SERVICE_CHANGED_01_VALUE_HANDLE 0x0006 +#define ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE 0x0009 +#define ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_CLIENT_CONFIGURATION_HANDLE 0x000a