13deb3ec6SMatthias Ringwald /* 23deb3ec6SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 33deb3ec6SMatthias Ringwald * 43deb3ec6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 53deb3ec6SMatthias Ringwald * modification, are permitted provided that the following conditions 63deb3ec6SMatthias Ringwald * are met: 73deb3ec6SMatthias Ringwald * 83deb3ec6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 93deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 103deb3ec6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 113deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 123deb3ec6SMatthias Ringwald * documentation and/or other materials provided with the distribution. 133deb3ec6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 143deb3ec6SMatthias Ringwald * contributors may be used to endorse or promote products derived 153deb3ec6SMatthias Ringwald * from this software without specific prior written permission. 163deb3ec6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 173deb3ec6SMatthias Ringwald * personal benefit and not for any commercial purpose or for 183deb3ec6SMatthias Ringwald * monetary gain. 193deb3ec6SMatthias Ringwald * 203deb3ec6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 213deb3ec6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 223deb3ec6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 233deb3ec6SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 243deb3ec6SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 253deb3ec6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 263deb3ec6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 273deb3ec6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 283deb3ec6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 293deb3ec6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 303deb3ec6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 313deb3ec6SMatthias Ringwald * SUCH DAMAGE. 323deb3ec6SMatthias Ringwald * 333deb3ec6SMatthias Ringwald * Please inquire about commercial licensing options at 343deb3ec6SMatthias Ringwald * [email protected] 353deb3ec6SMatthias Ringwald * 363deb3ec6SMatthias Ringwald */ 373deb3ec6SMatthias Ringwald 383deb3ec6SMatthias Ringwald #include <stdlib.h> 393deb3ec6SMatthias Ringwald #include <string.h> 403deb3ec6SMatthias Ringwald 413deb3ec6SMatthias Ringwald #include "att_db_util.h" 423edc84c5SMatthias Ringwald #include "ble/att.h" 43eb886013SMatthias Ringwald #include "btstack_util.h" 4416ece135SMatthias Ringwald #include "btstack_debug.h" 45aa4dd815SMatthias Ringwald #include "bluetooth.h" 463deb3ec6SMatthias Ringwald 473deb3ec6SMatthias Ringwald // ATT DB Storage 483deb3ec6SMatthias Ringwald #ifndef HAVE_MALLOC 493deb3ec6SMatthias Ringwald #ifdef MAX_ATT_DB_SIZE 503deb3ec6SMatthias Ringwald static uint8_t att_db_storage[MAX_ATT_DB_SIZE]; 513deb3ec6SMatthias Ringwald #else 523deb3ec6SMatthias Ringwald #error Neither HAVE_MALLOC] nor MAX_ATT_DB_SIZE is defined. 533deb3ec6SMatthias Ringwald #endif 543deb3ec6SMatthias Ringwald #endif 553deb3ec6SMatthias Ringwald 563deb3ec6SMatthias Ringwald static uint8_t * att_db; 573deb3ec6SMatthias Ringwald static uint16_t att_db_size; 583deb3ec6SMatthias Ringwald static uint16_t att_db_max_size; 593deb3ec6SMatthias Ringwald static uint16_t att_db_next_handle; 603deb3ec6SMatthias Ringwald 613deb3ec6SMatthias Ringwald static void att_db_util_set_end_tag(void){ 623deb3ec6SMatthias Ringwald // end tag 633deb3ec6SMatthias Ringwald att_db[att_db_size] = 0; 643deb3ec6SMatthias Ringwald att_db[att_db_size+1] = 0; 653deb3ec6SMatthias Ringwald } 663deb3ec6SMatthias Ringwald 673deb3ec6SMatthias Ringwald void att_db_util_init(void){ 683deb3ec6SMatthias Ringwald #ifdef HAVE_MALLOC 693deb3ec6SMatthias Ringwald att_db = (uint8_t*) malloc(128); 703deb3ec6SMatthias Ringwald att_db_max_size = 128; 713deb3ec6SMatthias Ringwald #else 723deb3ec6SMatthias Ringwald att_db = att_db_storage; 733deb3ec6SMatthias Ringwald att_db_max_size = sizeof(att_db_storage); 743deb3ec6SMatthias Ringwald #endif 753deb3ec6SMatthias Ringwald att_db_size = 0; 763deb3ec6SMatthias Ringwald att_db_next_handle = 1; 773deb3ec6SMatthias Ringwald att_db_util_set_end_tag(); 783deb3ec6SMatthias Ringwald } 793deb3ec6SMatthias Ringwald 803deb3ec6SMatthias Ringwald /** 813deb3ec6SMatthias Ringwald * asserts that the requested amount of bytes can be stored in the att_db 823deb3ec6SMatthias Ringwald * @returns TRUE if space is available 833deb3ec6SMatthias Ringwald */ 843deb3ec6SMatthias Ringwald static int att_db_util_assert_space(uint16_t size){ 853deb3ec6SMatthias Ringwald size += 2; // for end tag 863deb3ec6SMatthias Ringwald if (att_db_size + size <= att_db_max_size) return 1; 873deb3ec6SMatthias Ringwald #ifdef HAVE_MALLOC 883deb3ec6SMatthias Ringwald int new_size = att_db_size + att_db_size / 2; 893deb3ec6SMatthias Ringwald att_db = (uint8_t*) realloc(att_db, new_size); 903deb3ec6SMatthias Ringwald if (!att_db) { 913deb3ec6SMatthias Ringwald log_error("att_db: realloc failed"); 923deb3ec6SMatthias Ringwald return 0; 933deb3ec6SMatthias Ringwald } 943deb3ec6SMatthias Ringwald att_db_max_size = new_size; 953deb3ec6SMatthias Ringwald return 1; 963deb3ec6SMatthias Ringwald #else 973deb3ec6SMatthias Ringwald log_error("att_db: out of memory"); 983deb3ec6SMatthias Ringwald return 0; 993deb3ec6SMatthias Ringwald #endif 1003deb3ec6SMatthias Ringwald } 1013deb3ec6SMatthias Ringwald 1023deb3ec6SMatthias Ringwald // attribute size in bytes (16), flags(16), handle (16), uuid (16/128), value(...) 1033deb3ec6SMatthias Ringwald 1043deb3ec6SMatthias Ringwald // db endds with 0x00 0x00 1053deb3ec6SMatthias Ringwald 1063deb3ec6SMatthias Ringwald static void att_db_util_add_attribute_uuid16(uint16_t uuid16, uint16_t flags, uint8_t * data, uint16_t data_len){ 1073deb3ec6SMatthias Ringwald int size = 2 + 2 + 2 + 2 + data_len; 1083deb3ec6SMatthias Ringwald if (!att_db_util_assert_space(size)) return; 109*f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, size); 1103deb3ec6SMatthias Ringwald att_db_size += 2; 111*f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, flags); 1123deb3ec6SMatthias Ringwald att_db_size += 2; 113*f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, att_db_next_handle); 1143deb3ec6SMatthias Ringwald att_db_size += 2; 1153deb3ec6SMatthias Ringwald att_db_next_handle++; 116*f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, uuid16); 1173deb3ec6SMatthias Ringwald att_db_size += 2; 1183deb3ec6SMatthias Ringwald memcpy(&att_db[att_db_size], data, data_len); 1193deb3ec6SMatthias Ringwald att_db_size += data_len; 1203deb3ec6SMatthias Ringwald att_db_util_set_end_tag(); 1213deb3ec6SMatthias Ringwald } 1223deb3ec6SMatthias Ringwald 1233deb3ec6SMatthias Ringwald static void att_db_util_add_attribute_uuid128(uint8_t * uuid128, uint16_t flags, uint8_t * data, uint16_t data_len){ 1243deb3ec6SMatthias Ringwald int size = 2 + 2 + 2 + 16 + data_len; 1253deb3ec6SMatthias Ringwald if (!att_db_util_assert_space(size)) return; 1263deb3ec6SMatthias Ringwald flags |= ATT_PROPERTY_UUID128; 127*f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, size); 1283deb3ec6SMatthias Ringwald att_db_size += 2; 129*f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, flags); 1303deb3ec6SMatthias Ringwald att_db_size += 2; 131*f8fbdce0SMatthias Ringwald little_endian_store_16(att_db, att_db_size, att_db_next_handle); 1323deb3ec6SMatthias Ringwald att_db_size += 2; 1333deb3ec6SMatthias Ringwald att_db_next_handle++; 1343deb3ec6SMatthias Ringwald swap128(uuid128, &att_db[att_db_size]); 1353deb3ec6SMatthias Ringwald att_db_size += 16; 1363deb3ec6SMatthias Ringwald memcpy(&att_db[att_db_size], data, data_len); 1373deb3ec6SMatthias Ringwald att_db_size += data_len; 1383deb3ec6SMatthias Ringwald att_db_util_set_end_tag(); 1393deb3ec6SMatthias Ringwald } 1403deb3ec6SMatthias Ringwald 1413deb3ec6SMatthias Ringwald void att_db_util_add_service_uuid16(uint16_t uuid16){ 1423deb3ec6SMatthias Ringwald uint8_t buffer[2]; 143*f8fbdce0SMatthias Ringwald little_endian_store_16(buffer, 0, uuid16); 1443deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_PRIMARY_SERVICE_UUID, ATT_PROPERTY_READ, buffer, 2); 1453deb3ec6SMatthias Ringwald } 1463deb3ec6SMatthias Ringwald 1473deb3ec6SMatthias Ringwald void att_db_util_add_service_uuid128(uint8_t * uuid128){ 1483deb3ec6SMatthias Ringwald uint8_t buffer[16]; 1493deb3ec6SMatthias Ringwald swap128(uuid128, buffer); 1503deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_PRIMARY_SERVICE_UUID, ATT_PROPERTY_READ, buffer, 16); 1513deb3ec6SMatthias Ringwald } 1523deb3ec6SMatthias Ringwald 1533deb3ec6SMatthias Ringwald uint16_t att_db_util_add_characteristic_uuid16(uint16_t uuid16, uint16_t properties, uint8_t * data, uint16_t data_len){ 1543deb3ec6SMatthias Ringwald uint8_t buffer[5]; 1553deb3ec6SMatthias Ringwald buffer[0] = properties; 156*f8fbdce0SMatthias Ringwald little_endian_store_16(buffer, 1, att_db_next_handle + 1); 157*f8fbdce0SMatthias Ringwald little_endian_store_16(buffer, 3, uuid16); 1583deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_CHARACTERISTICS_UUID, ATT_PROPERTY_READ, buffer, sizeof(buffer)); 1593deb3ec6SMatthias Ringwald uint16_t value_handle = att_db_next_handle; 1603deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(uuid16, properties, data, data_len); 1613deb3ec6SMatthias Ringwald if (properties & (ATT_PROPERTY_NOTIFY | ATT_PROPERTY_INDICATE)){ 1623deb3ec6SMatthias Ringwald uint16_t flags = ATT_PROPERTY_READ | ATT_PROPERTY_WRITE | ATT_PROPERTY_DYNAMIC; 163*f8fbdce0SMatthias Ringwald little_endian_store_16(buffer, 0, 0); 1643deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_CLIENT_CHARACTERISTICS_CONFIGURATION, flags, buffer, 2); 1653deb3ec6SMatthias Ringwald } 1663deb3ec6SMatthias Ringwald return value_handle; 1673deb3ec6SMatthias Ringwald } 1683deb3ec6SMatthias Ringwald 1693deb3ec6SMatthias Ringwald uint16_t att_db_util_add_characteristic_uuid128(uint8_t * uuid128, uint16_t properties, uint8_t * data, uint16_t data_len){ 1703deb3ec6SMatthias Ringwald uint8_t buffer[19]; 1713deb3ec6SMatthias Ringwald buffer[0] = properties; 172*f8fbdce0SMatthias Ringwald little_endian_store_16(buffer, 1, att_db_next_handle + 1); 1733deb3ec6SMatthias Ringwald swap128(uuid128, &buffer[3]); 1743deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_CHARACTERISTICS_UUID, ATT_PROPERTY_READ, buffer, sizeof(buffer)); 1753deb3ec6SMatthias Ringwald uint16_t value_handle = att_db_next_handle; 1763deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid128(uuid128, properties, data, data_len); 1773deb3ec6SMatthias Ringwald if (properties & (ATT_PROPERTY_NOTIFY | ATT_PROPERTY_INDICATE)){ 1783deb3ec6SMatthias Ringwald uint16_t flags = ATT_PROPERTY_READ | ATT_PROPERTY_WRITE | ATT_PROPERTY_DYNAMIC; 179*f8fbdce0SMatthias Ringwald little_endian_store_16(buffer, 0, 0); 1803deb3ec6SMatthias Ringwald att_db_util_add_attribute_uuid16(GATT_CLIENT_CHARACTERISTICS_CONFIGURATION, flags, buffer, 2); 1813deb3ec6SMatthias Ringwald } 1823deb3ec6SMatthias Ringwald return value_handle; 1833deb3ec6SMatthias Ringwald } 1843deb3ec6SMatthias Ringwald 1853deb3ec6SMatthias Ringwald uint8_t * att_db_util_get_address(void){ 1863deb3ec6SMatthias Ringwald return att_db; 1873deb3ec6SMatthias Ringwald } 1883deb3ec6SMatthias Ringwald 1893deb3ec6SMatthias Ringwald uint16_t att_db_util_get_size(void){ 1903deb3ec6SMatthias Ringwald return att_db_size + 2; // end tag 1913deb3ec6SMatthias Ringwald } 192