1683cf298SMatthias Ringwald /* 2683cf298SMatthias Ringwald * Copyright (C) 2019 BlueKitchen GmbH 3683cf298SMatthias Ringwald * 4683cf298SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5683cf298SMatthias Ringwald * modification, are permitted provided that the following conditions 6683cf298SMatthias Ringwald * are met: 7683cf298SMatthias Ringwald * 8683cf298SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9683cf298SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10683cf298SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11683cf298SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12683cf298SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13683cf298SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14683cf298SMatthias Ringwald * contributors may be used to endorse or promote products derived 15683cf298SMatthias Ringwald * from this software without specific prior written permission. 16683cf298SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17683cf298SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18683cf298SMatthias Ringwald * monetary gain. 19683cf298SMatthias Ringwald * 20683cf298SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21683cf298SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22683cf298SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23683cf298SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24683cf298SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25683cf298SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26683cf298SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27683cf298SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28683cf298SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29683cf298SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30683cf298SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31683cf298SMatthias Ringwald * SUCH DAMAGE. 32683cf298SMatthias Ringwald * 33683cf298SMatthias Ringwald * Please inquire about commercial licensing options at 34683cf298SMatthias Ringwald * [email protected] 35683cf298SMatthias Ringwald * 36683cf298SMatthias Ringwald */ 37683cf298SMatthias Ringwald 382d4000d1SMatthias Ringwald #define BTSTACK_FILE__ "mesh_node.c" 39683cf298SMatthias Ringwald 400d42a059SMatthias Ringwald #include "bluetooth_company_id.h" 410d42a059SMatthias Ringwald #include "mesh/mesh_foundation.h" 420d42a059SMatthias Ringwald 43f4854a5eSMatthias Ringwald #include "mesh/mesh_node.h" 44f4854a5eSMatthias Ringwald 45e8625ff1SMatthias Ringwald #include <stddef.h> 46d0e44c14SMatthias Ringwald #include <string.h> 47e8625ff1SMatthias Ringwald 48683cf298SMatthias Ringwald static uint16_t primary_element_address; 49683cf298SMatthias Ringwald 50e8625ff1SMatthias Ringwald static mesh_element_t primary_element; 51e8625ff1SMatthias Ringwald 52e8625ff1SMatthias Ringwald static uint16_t mesh_element_index_next; 53e8625ff1SMatthias Ringwald 54e8625ff1SMatthias Ringwald static btstack_linked_list_t mesh_elements; 55e8625ff1SMatthias Ringwald 560d42a059SMatthias Ringwald static uint16_t mid_counter; 570d42a059SMatthias Ringwald 58d0e44c14SMatthias Ringwald static uint8_t mesh_node_device_uuid[16]; 5939cd8755SMatthias Ringwald static int mesh_node_have_device_uuid; 60d0e44c14SMatthias Ringwald 615d71beb8SMatthias Ringwald static uint16_t mesh_node_company_id; 625d71beb8SMatthias Ringwald static uint16_t mesh_node_product_id; 635d71beb8SMatthias Ringwald static uint16_t mesh_node_product_version_id; 645d71beb8SMatthias Ringwald 65683cf298SMatthias Ringwald void mesh_node_primary_element_address_set(uint16_t unicast_address){ 66683cf298SMatthias Ringwald primary_element_address = unicast_address; 67683cf298SMatthias Ringwald } 68683cf298SMatthias Ringwald 69001c65e0SMatthias Ringwald uint16_t mesh_node_get_primary_element_address(void){ 70683cf298SMatthias Ringwald return primary_element_address; 71683cf298SMatthias Ringwald } 72e8625ff1SMatthias Ringwald 73e8625ff1SMatthias Ringwald void mesh_node_init(void){ 74e8625ff1SMatthias Ringwald // dd Primary Element to list of elements 75001c65e0SMatthias Ringwald mesh_node_add_element(&primary_element); 76e8625ff1SMatthias Ringwald } 77e8625ff1SMatthias Ringwald 785d71beb8SMatthias Ringwald void mesh_node_set_info(uint16_t company_id, uint16_t product_id, uint16_t product_version_id){ 795d71beb8SMatthias Ringwald mesh_node_company_id = company_id; 805d71beb8SMatthias Ringwald mesh_node_product_id = product_id; 815d71beb8SMatthias Ringwald mesh_node_product_version_id = product_version_id; 825d71beb8SMatthias Ringwald } 835d71beb8SMatthias Ringwald 845d71beb8SMatthias Ringwald uint16_t mesh_node_get_company_id(void){ 855d71beb8SMatthias Ringwald return mesh_node_company_id; 865d71beb8SMatthias Ringwald } 875d71beb8SMatthias Ringwald 885d71beb8SMatthias Ringwald uint16_t mesh_node_get_product_id(void){ 895d71beb8SMatthias Ringwald return mesh_node_product_id; 905d71beb8SMatthias Ringwald } 915d71beb8SMatthias Ringwald 925d71beb8SMatthias Ringwald uint16_t mesh_node_get_product_version_id(void){ 935d71beb8SMatthias Ringwald return mesh_node_product_version_id; 945d71beb8SMatthias Ringwald } 955d71beb8SMatthias Ringwald 96001c65e0SMatthias Ringwald void mesh_node_add_element(mesh_element_t * element){ 97e8625ff1SMatthias Ringwald element->element_index = mesh_element_index_next++; 98e8625ff1SMatthias Ringwald btstack_linked_list_add_tail(&mesh_elements, (void*) element); 99e8625ff1SMatthias Ringwald } 100e8625ff1SMatthias Ringwald 101001c65e0SMatthias Ringwald uint16_t mesh_node_element_count(void){ 102e4058622SMatthias Ringwald return (uint16_t) btstack_linked_list_count(&mesh_elements); 103e4058622SMatthias Ringwald } 104e4058622SMatthias Ringwald 105001c65e0SMatthias Ringwald mesh_element_t * mesh_node_get_primary_element(void){ 106e8625ff1SMatthias Ringwald return &primary_element; 107e8625ff1SMatthias Ringwald } 108e8625ff1SMatthias Ringwald 1096f175e03SMatthias Ringwald 1106f175e03SMatthias Ringwald void mesh_node_set_element_location(mesh_element_t * element, uint16_t location){ 1116f175e03SMatthias Ringwald element->loc = location; 1126f175e03SMatthias Ringwald } 1136f175e03SMatthias Ringwald 114001c65e0SMatthias Ringwald void mesh_node_set_primary_element_location(uint16_t location){ 1156f175e03SMatthias Ringwald mesh_node_set_element_location(&primary_element, location); 116e8625ff1SMatthias Ringwald } 117e8625ff1SMatthias Ringwald 118001c65e0SMatthias Ringwald mesh_element_t * mesh_node_element_for_index(uint16_t element_index){ 119e8625ff1SMatthias Ringwald btstack_linked_list_iterator_t it; 120e8625ff1SMatthias Ringwald btstack_linked_list_iterator_init(&it, &mesh_elements); 121e8625ff1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 122e8625ff1SMatthias Ringwald mesh_element_t * element = (mesh_element_t *) btstack_linked_list_iterator_next(&it); 123e8625ff1SMatthias Ringwald if (element->element_index != element_index) continue; 124e8625ff1SMatthias Ringwald return element; 125e8625ff1SMatthias Ringwald } 126e8625ff1SMatthias Ringwald return NULL; 127e8625ff1SMatthias Ringwald } 128e8625ff1SMatthias Ringwald 129001c65e0SMatthias Ringwald mesh_element_t * mesh_node_element_for_unicast_address(uint16_t unicast_address){ 130001c65e0SMatthias Ringwald uint16_t element_index = unicast_address - mesh_node_get_primary_element_address(); 131001c65e0SMatthias Ringwald return mesh_node_element_for_index(element_index); 132e8625ff1SMatthias Ringwald } 133e8625ff1SMatthias Ringwald 134e8625ff1SMatthias Ringwald void mesh_element_iterator_init(mesh_element_iterator_t * iterator){ 135e8625ff1SMatthias Ringwald btstack_linked_list_iterator_init(&iterator->it, &mesh_elements); 136e8625ff1SMatthias Ringwald } 137e8625ff1SMatthias Ringwald 138e8625ff1SMatthias Ringwald int mesh_element_iterator_has_next(mesh_element_iterator_t * iterator){ 139e8625ff1SMatthias Ringwald return btstack_linked_list_iterator_has_next(&iterator->it); 140e8625ff1SMatthias Ringwald } 141e8625ff1SMatthias Ringwald 142e8625ff1SMatthias Ringwald mesh_element_t * mesh_element_iterator_next(mesh_element_iterator_t * iterator){ 143e8625ff1SMatthias Ringwald return (mesh_element_t *) btstack_linked_list_iterator_next(&iterator->it); 144e8625ff1SMatthias Ringwald } 145d0e44c14SMatthias Ringwald 1460d42a059SMatthias Ringwald // Mesh Node Element functions 1470d42a059SMatthias Ringwald uint8_t mesh_access_get_element_index(mesh_model_t * mesh_model){ 1480d42a059SMatthias Ringwald return mesh_model->element->element_index; 1490d42a059SMatthias Ringwald } 1500d42a059SMatthias Ringwald 1510d42a059SMatthias Ringwald uint16_t mesh_access_get_element_address(mesh_model_t * mesh_model){ 1520d42a059SMatthias Ringwald return mesh_node_get_primary_element_address() + mesh_model->element->element_index; 1530d42a059SMatthias Ringwald } 1540d42a059SMatthias Ringwald 1550d42a059SMatthias Ringwald // Model Identifier utilities 1560d42a059SMatthias Ringwald 1570d42a059SMatthias Ringwald uint32_t mesh_model_get_model_identifier(uint16_t vendor_id, uint16_t model_id){ 158*df71a9a4SMatthias Ringwald return (((uint32_t) vendor_id << 16)) | model_id; 1590d42a059SMatthias Ringwald } 1600d42a059SMatthias Ringwald 1610d42a059SMatthias Ringwald uint32_t mesh_model_get_model_identifier_bluetooth_sig(uint16_t model_id){ 162*df71a9a4SMatthias Ringwald return ((uint32_t) BLUETOOTH_COMPANY_ID_BLUETOOTH_SIG_INC << 16) | model_id; 1630d42a059SMatthias Ringwald } 1640d42a059SMatthias Ringwald 1650d42a059SMatthias Ringwald uint16_t mesh_model_get_model_id(uint32_t model_identifier){ 1660d42a059SMatthias Ringwald return model_identifier & 0xFFFFu; 1670d42a059SMatthias Ringwald } 1680d42a059SMatthias Ringwald 1690d42a059SMatthias Ringwald uint16_t mesh_model_get_vendor_id(uint32_t model_identifier){ 1700d42a059SMatthias Ringwald return model_identifier >> 16; 1710d42a059SMatthias Ringwald } 1720d42a059SMatthias Ringwald 1730d42a059SMatthias Ringwald int mesh_model_is_bluetooth_sig(uint32_t model_identifier){ 1740d42a059SMatthias Ringwald return mesh_model_get_vendor_id(model_identifier) == BLUETOOTH_COMPANY_ID_BLUETOOTH_SIG_INC; 1750d42a059SMatthias Ringwald } 1760d42a059SMatthias Ringwald 1776f8febaeSMatthias Ringwald mesh_model_t * mesh_node_get_configuration_server(void){ 1780d42a059SMatthias Ringwald return mesh_model_get_by_identifier(mesh_node_get_primary_element(), mesh_model_get_model_identifier_bluetooth_sig(MESH_SIG_MODEL_ID_CONFIGURATION_SERVER)); 1790d42a059SMatthias Ringwald } 1800d42a059SMatthias Ringwald 1816f8febaeSMatthias Ringwald mesh_model_t * mesh_node_get_health_server(void){ 1826f8febaeSMatthias Ringwald return mesh_model_get_by_identifier(mesh_node_get_primary_element(), mesh_model_get_model_identifier_bluetooth_sig(MESH_SIG_MODEL_ID_HEALTH_SERVER)); 1836f8febaeSMatthias Ringwald } 1846f8febaeSMatthias Ringwald 1850d42a059SMatthias Ringwald void mesh_model_reset_appkeys(mesh_model_t * mesh_model){ 1860d42a059SMatthias Ringwald uint16_t i; 1870d42a059SMatthias Ringwald for (i=0;i<MAX_NR_MESH_APPKEYS_PER_MODEL;i++){ 1880d42a059SMatthias Ringwald mesh_model->appkey_indices[i] = MESH_APPKEY_INVALID; 1890d42a059SMatthias Ringwald } 1900d42a059SMatthias Ringwald } 1910d42a059SMatthias Ringwald 1920d42a059SMatthias Ringwald void mesh_element_add_model(mesh_element_t * element, mesh_model_t * mesh_model){ 1930d42a059SMatthias Ringwald // reset app keys 1940d42a059SMatthias Ringwald mesh_model_reset_appkeys(mesh_model); 1950d42a059SMatthias Ringwald 1960d42a059SMatthias Ringwald if (mesh_model_is_bluetooth_sig(mesh_model->model_identifier)){ 1970d42a059SMatthias Ringwald element->models_count_sig++; 1980d42a059SMatthias Ringwald } else { 1990d42a059SMatthias Ringwald element->models_count_vendor++; 2000d42a059SMatthias Ringwald } 2010d42a059SMatthias Ringwald mesh_model->mid = mid_counter++; 2020d42a059SMatthias Ringwald mesh_model->element = element; 2030d42a059SMatthias Ringwald btstack_linked_list_add_tail(&element->models, (btstack_linked_item_t *) mesh_model); 2040d42a059SMatthias Ringwald } 2050d42a059SMatthias Ringwald 2060d42a059SMatthias Ringwald void mesh_model_iterator_init(mesh_model_iterator_t * iterator, mesh_element_t * element){ 2070d42a059SMatthias Ringwald btstack_linked_list_iterator_init(&iterator->it, &element->models); 2080d42a059SMatthias Ringwald } 2090d42a059SMatthias Ringwald 2100d42a059SMatthias Ringwald int mesh_model_iterator_has_next(mesh_model_iterator_t * iterator){ 2110d42a059SMatthias Ringwald return btstack_linked_list_iterator_has_next(&iterator->it); 2120d42a059SMatthias Ringwald } 2130d42a059SMatthias Ringwald 2140d42a059SMatthias Ringwald mesh_model_t * mesh_model_iterator_next(mesh_model_iterator_t * iterator){ 2150d42a059SMatthias Ringwald return (mesh_model_t *) btstack_linked_list_iterator_next(&iterator->it); 2160d42a059SMatthias Ringwald } 2170d42a059SMatthias Ringwald 2180d42a059SMatthias Ringwald mesh_model_t * mesh_model_get_by_identifier(mesh_element_t * element, uint32_t model_identifier){ 2190d42a059SMatthias Ringwald mesh_model_iterator_t it; 2200d42a059SMatthias Ringwald mesh_model_iterator_init(&it, element); 2210d42a059SMatthias Ringwald while (mesh_model_iterator_has_next(&it)){ 2220d42a059SMatthias Ringwald mesh_model_t * model = mesh_model_iterator_next(&it); 2230d42a059SMatthias Ringwald if (model->model_identifier != model_identifier) continue; 2240d42a059SMatthias Ringwald return model; 2250d42a059SMatthias Ringwald } 2260d42a059SMatthias Ringwald return NULL; 2270d42a059SMatthias Ringwald } 2280d42a059SMatthias Ringwald 2290d42a059SMatthias Ringwald mesh_model_t * mesh_access_model_for_address_and_model_identifier(uint16_t element_address, uint32_t model_identifier, uint8_t * status){ 2300d42a059SMatthias Ringwald mesh_element_t * element = mesh_node_element_for_unicast_address(element_address); 2310d42a059SMatthias Ringwald if (element == NULL){ 2320d42a059SMatthias Ringwald *status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS; 2330d42a059SMatthias Ringwald return NULL; 2340d42a059SMatthias Ringwald } 2350d42a059SMatthias Ringwald mesh_model_t * model = mesh_model_get_by_identifier(element, model_identifier); 2360d42a059SMatthias Ringwald if (model == NULL) { 2370d42a059SMatthias Ringwald *status = MESH_FOUNDATION_STATUS_INVALID_MODEL; 2380d42a059SMatthias Ringwald } else { 2390d42a059SMatthias Ringwald *status = MESH_FOUNDATION_STATUS_SUCCESS; 2400d42a059SMatthias Ringwald } 2410d42a059SMatthias Ringwald return model; 2420d42a059SMatthias Ringwald } 2430d42a059SMatthias Ringwald // Mesh Model Subscription 2440d42a059SMatthias Ringwald int mesh_model_contains_subscription(mesh_model_t * mesh_model, uint16_t address){ 2450d42a059SMatthias Ringwald uint16_t i; 2460d42a059SMatthias Ringwald for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){ 2470d42a059SMatthias Ringwald if (mesh_model->subscriptions[i] == address) return 1; 2480d42a059SMatthias Ringwald } 2490d42a059SMatthias Ringwald return 0; 2500d42a059SMatthias Ringwald } 2510d42a059SMatthias Ringwald 252d0e44c14SMatthias Ringwald void mesh_node_set_device_uuid(const uint8_t * device_uuid){ 2536535961aSMatthias Ringwald (void)memcpy(mesh_node_device_uuid, device_uuid, 16); 25439cd8755SMatthias Ringwald mesh_node_have_device_uuid = 1; 255d0e44c14SMatthias Ringwald } 256d0e44c14SMatthias Ringwald 257d0e44c14SMatthias Ringwald /** 258d0e44c14SMatthias Ringwald * @brief Get Device UUID 259d0e44c14SMatthias Ringwald */ 260d0e44c14SMatthias Ringwald const uint8_t * mesh_node_get_device_uuid(void){ 26139cd8755SMatthias Ringwald if (mesh_node_have_device_uuid == 0) return NULL; 26254274a76SMatthias Ringwald return mesh_node_device_uuid; 263d0e44c14SMatthias Ringwald } 264d0e44c14SMatthias Ringwald 26512d66e05SMilanka Ringwald 26612d66e05SMilanka Ringwald // Heartbeat (helper) 26712d66e05SMilanka Ringwald uint16_t mesh_heartbeat_pwr2(uint8_t value){ 26812d66e05SMilanka Ringwald if (value == 0 ) return 0x0000; 26912d66e05SMilanka Ringwald if (value == 0xff || value == 0x11) return 0xffff; 27012d66e05SMilanka Ringwald return 1 << (value-1); 27112d66e05SMilanka Ringwald } 27212d66e05SMilanka Ringwald 27312d66e05SMilanka Ringwald uint8_t mesh_heartbeat_count_log(uint16_t value){ 27412d66e05SMilanka Ringwald if (value == 0) return 0x00; 27512d66e05SMilanka Ringwald if (value == 0xffff) return 0xff; 27612d66e05SMilanka Ringwald // count leading zeros, supported by clang and gcc 27712d66e05SMilanka Ringwald // note: CountLog(8) == CountLog(7) = 3 27812d66e05SMilanka Ringwald return 33 - __builtin_clz(value - 1); 27912d66e05SMilanka Ringwald } 28012d66e05SMilanka Ringwald 28112d66e05SMilanka Ringwald uint8_t mesh_heartbeat_period_log(uint16_t value){ 28212d66e05SMilanka Ringwald if (value == 0) return 0x00; 28312d66e05SMilanka Ringwald // count leading zeros, supported by clang and gcc 28412d66e05SMilanka Ringwald // note: PeriodLog(8) == PeriodLog(7) = 3 28512d66e05SMilanka Ringwald return 33 - __builtin_clz(value - 1); 28612d66e05SMilanka Ringwald } 287