xref: /btstack/src/mesh/mesh_node.c (revision 8613e0eb5b9621b90c6c50e3d739bfa544af1c63)
1 /*
2  * Copyright (C) 2019 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "mesh_node.c"
39 
40 #include "bluetooth_company_id.h"
41 #include "mesh/mesh_foundation.h"
42 
43 #include "mesh/mesh_node.h"
44 
45 #include <stddef.h>
46 #include <string.h>
47 
48 static uint16_t primary_element_address;
49 
50 static mesh_element_t primary_element;
51 
52 static uint16_t mesh_element_index_next;
53 
54 static btstack_linked_list_t mesh_elements;
55 
56 static uint16_t mid_counter;
57 
58 static uint8_t mesh_node_device_uuid[16];
59 static int     mesh_node_have_device_uuid;
60 
61 static uint16_t mesh_node_company_id;
62 static uint16_t mesh_node_product_id;
63 static uint16_t mesh_node_product_version_id;
64 
65 void mesh_node_primary_element_address_set(uint16_t unicast_address){
66     primary_element_address = unicast_address;
67 }
68 
69 uint16_t mesh_node_get_primary_element_address(void){
70     return primary_element_address;
71 }
72 
73 void mesh_node_init(void){
74     // dd Primary Element to list of elements
75     mesh_node_add_element(&primary_element);
76 }
77 
78 void mesh_node_set_info(uint16_t company_id, uint16_t product_id, uint16_t product_version_id){
79     mesh_node_company_id = company_id;
80     mesh_node_product_id = product_id;
81     mesh_node_product_version_id = product_version_id;
82 }
83 
84 uint16_t mesh_node_get_company_id(void){
85     return mesh_node_company_id;
86 }
87 
88 uint16_t mesh_node_get_product_id(void){
89     return mesh_node_product_id;
90 }
91 
92 uint16_t mesh_node_get_product_version_id(void){
93     return mesh_node_product_version_id;
94 }
95 
96 void mesh_node_add_element(mesh_element_t * element){
97     element->element_index = mesh_element_index_next++;
98     btstack_linked_list_add_tail(&mesh_elements, (void*) element);
99 }
100 
101 uint16_t mesh_node_element_count(void){
102 	return (uint16_t) btstack_linked_list_count(&mesh_elements);
103 }
104 
105 mesh_element_t * mesh_node_get_primary_element(void){
106     return &primary_element;
107 }
108 
109 
110 void mesh_node_set_element_location(mesh_element_t * element, uint16_t location){
111     element->loc = location;
112 }
113 
114 void mesh_node_set_primary_element_location(uint16_t location){
115     mesh_node_set_element_location(&primary_element, location);
116 }
117 
118 mesh_element_t * mesh_node_element_for_index(uint16_t element_index){
119     btstack_linked_list_iterator_t it;
120     btstack_linked_list_iterator_init(&it, &mesh_elements);
121     while (btstack_linked_list_iterator_has_next(&it)){
122         mesh_element_t * element = (mesh_element_t *) btstack_linked_list_iterator_next(&it);
123         if (element->element_index != element_index) continue;
124         return element;
125     }
126     return NULL;
127 }
128 
129 mesh_element_t * mesh_node_element_for_unicast_address(uint16_t unicast_address){
130     uint16_t element_index = unicast_address - mesh_node_get_primary_element_address();
131     return mesh_node_element_for_index(element_index);
132 }
133 
134 void mesh_element_iterator_init(mesh_element_iterator_t * iterator){
135     btstack_linked_list_iterator_init(&iterator->it, &mesh_elements);
136 }
137 
138 int mesh_element_iterator_has_next(mesh_element_iterator_t * iterator){
139     return btstack_linked_list_iterator_has_next(&iterator->it);
140 }
141 
142 mesh_element_t * mesh_element_iterator_next(mesh_element_iterator_t * iterator){
143     return (mesh_element_t *) btstack_linked_list_iterator_next(&iterator->it);
144 }
145 
146 // Mesh Node Element functions
147 uint8_t mesh_access_get_element_index(mesh_model_t * mesh_model){
148     return mesh_model->element->element_index;
149 }
150 
151 uint16_t mesh_access_get_element_address(mesh_model_t * mesh_model){
152     return mesh_node_get_primary_element_address() + mesh_model->element->element_index;
153 }
154 
155 // Model Identifier utilities
156 
157 uint32_t mesh_model_get_model_identifier(uint16_t vendor_id, uint16_t model_id){
158     return (((uint32_t) vendor_id << 16)) | model_id;
159 }
160 
161 uint32_t mesh_model_get_model_identifier_bluetooth_sig(uint16_t model_id){
162     return ((uint32_t) BLUETOOTH_COMPANY_ID_BLUETOOTH_SIG_INC << 16) | model_id;
163 }
164 
165 uint16_t mesh_model_get_model_id(uint32_t model_identifier){
166     return model_identifier & 0xFFFFu;
167 }
168 
169 uint16_t mesh_model_get_vendor_id(uint32_t model_identifier){
170     return model_identifier >> 16;
171 }
172 
173 int mesh_model_is_bluetooth_sig(uint32_t model_identifier){
174     return mesh_model_get_vendor_id(model_identifier) == BLUETOOTH_COMPANY_ID_BLUETOOTH_SIG_INC;
175 }
176 
177 mesh_model_t * mesh_node_get_configuration_server(void){
178     return mesh_model_get_by_identifier(mesh_node_get_primary_element(), mesh_model_get_model_identifier_bluetooth_sig(MESH_SIG_MODEL_ID_CONFIGURATION_SERVER));
179 }
180 
181 mesh_model_t * mesh_node_get_health_server(void){
182     return mesh_model_get_by_identifier(mesh_node_get_primary_element(), mesh_model_get_model_identifier_bluetooth_sig(MESH_SIG_MODEL_ID_HEALTH_SERVER));
183 }
184 
185 void mesh_model_reset_appkeys(mesh_model_t * mesh_model){
186     uint16_t i;
187     for (i=0;i<MAX_NR_MESH_APPKEYS_PER_MODEL;i++){
188         mesh_model->appkey_indices[i] = MESH_APPKEY_INVALID;
189     }
190 }
191 
192 void mesh_element_add_model(mesh_element_t * element, mesh_model_t * mesh_model){
193     // reset app keys
194     mesh_model_reset_appkeys(mesh_model);
195 
196     if (mesh_model_is_bluetooth_sig(mesh_model->model_identifier)){
197         element->models_count_sig++;
198     } else {
199         element->models_count_vendor++;
200     }
201     mesh_model->mid = mid_counter++;
202     mesh_model->element = element;
203     btstack_linked_list_add_tail(&element->models, (btstack_linked_item_t *) mesh_model);
204 }
205 
206 void mesh_model_iterator_init(mesh_model_iterator_t * iterator, mesh_element_t * element){
207     btstack_linked_list_iterator_init(&iterator->it, &element->models);
208 }
209 
210 int mesh_model_iterator_has_next(mesh_model_iterator_t * iterator){
211     return btstack_linked_list_iterator_has_next(&iterator->it);
212 }
213 
214 mesh_model_t * mesh_model_iterator_next(mesh_model_iterator_t * iterator){
215     return (mesh_model_t *) btstack_linked_list_iterator_next(&iterator->it);
216 }
217 
218 mesh_model_t * mesh_model_get_by_identifier(mesh_element_t * element, uint32_t model_identifier){
219     mesh_model_iterator_t it;
220     mesh_model_iterator_init(&it, element);
221     while (mesh_model_iterator_has_next(&it)){
222         mesh_model_t * model = mesh_model_iterator_next(&it);
223         if (model->model_identifier != model_identifier) continue;
224         return model;
225     }
226     return NULL;
227 }
228 
229 mesh_model_t * mesh_access_model_for_address_and_model_identifier(uint16_t element_address, uint32_t model_identifier, uint8_t * status){
230     mesh_element_t * element = mesh_node_element_for_unicast_address(element_address);
231     if (element == NULL){
232         *status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
233         return NULL;
234     }
235     mesh_model_t * model = mesh_model_get_by_identifier(element, model_identifier);
236     if (model == NULL) {
237         *status = MESH_FOUNDATION_STATUS_INVALID_MODEL;
238     } else {
239         *status = MESH_FOUNDATION_STATUS_SUCCESS;
240     }
241     return model;
242 }
243 // Mesh Model Subscription
244 int mesh_model_contains_subscription(mesh_model_t * mesh_model, uint16_t address){
245     uint16_t i;
246     for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){
247         if (mesh_model->subscriptions[i] == address) return 1;
248     }
249     return 0;
250 }
251 
252 void mesh_node_set_device_uuid(const uint8_t * device_uuid){
253     (void)memcpy(mesh_node_device_uuid, device_uuid, 16);
254     mesh_node_have_device_uuid = 1;
255 }
256 
257 /**
258  * @brief Get Device UUID
259  */
260 const uint8_t * mesh_node_get_device_uuid(void){
261     if (mesh_node_have_device_uuid == 0) return NULL;
262     return mesh_node_device_uuid;
263 }
264 
265 
266 // Heartbeat (helper)
267 uint16_t mesh_heartbeat_pwr2(uint8_t value){
268     if (value == 0 )                    return 0x0000;
269     if (value == 0xff || value == 0x11) return 0xffff;
270     return 1 << (value-1);
271 }
272 
273 uint8_t mesh_heartbeat_count_log(uint16_t value){
274     if (value == 0)      return 0x00;
275     if (value == 0xffff) return 0xff;
276     // count leading zeros, supported by clang and gcc
277     // note: CountLog(8) == CountLog(7) = 3
278     return 33 - __builtin_clz(value - 1);
279 }
280 
281 uint8_t mesh_heartbeat_period_log(uint16_t value){
282     if (value == 0)      return 0x00;
283     // count leading zeros, supported by clang and gcc
284     // note: PeriodLog(8) == PeriodLog(7) = 3
285     return 33 - __builtin_clz(value - 1);
286 }
287