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_configuration_client.c" 39 40 #include <string.h> 41 #include <stdio.h> 42 43 #include "mesh/mesh_configuration_client.h" 44 45 #include "bluetooth_company_id.h" 46 #include "btstack_debug.h" 47 #include "btstack_memory.h" 48 #include "btstack_util.h" 49 50 #include "mesh/mesh_access.h" 51 #include "mesh/mesh_foundation.h" 52 #include "mesh/mesh_generic_model.h" 53 #include "mesh/mesh_keys.h" 54 #include "mesh/mesh_network.h" 55 #include "mesh/mesh_upper_transport.h" 56 57 58 // Mesh Composition Data Element iterator 59 #define MESH_VENDOR_MODEL_SIZE 4 60 #define MESH_SIG_MODEL_SIZE 2 61 #define MESH_COMPOSITION_DATA_ELEMENT_DESCRIPTION_OFFSET 17 62 #define MESH_COMPOSITION_DATA_ELEMENT_LOCATION_DESCRIPTOR_LEN 2 63 #define MESH_COMPOSITION_DATA_ELEMENT_MODEL_SIZE_LEN 1 64 65 static inline uint16_t mesh_composition_data_iterator_sig_model_list_size(mesh_composite_data_iterator_t * it){ 66 return it->elements[it->offset + 2] * MESH_SIG_MODEL_SIZE; 67 } 68 69 static inline uint16_t mesh_composition_data_iterator_vendor_model_list_size(mesh_composite_data_iterator_t * it){ 70 return it->elements[it->offset + 3] * MESH_VENDOR_MODEL_SIZE; 71 } 72 73 static inline uint16_t mesh_composition_data_iterator_element_len(mesh_composite_data_iterator_t * it){ 74 uint16_t sig_model_list_size = mesh_composition_data_iterator_sig_model_list_size(it); 75 uint16_t vendor_model_list_size = mesh_composition_data_iterator_vendor_model_list_size(it); 76 uint16_t previous_fields_len = MESH_COMPOSITION_DATA_ELEMENT_LOCATION_DESCRIPTOR_LEN + 2 * MESH_COMPOSITION_DATA_ELEMENT_MODEL_SIZE_LEN; 77 78 return previous_fields_len + sig_model_list_size + vendor_model_list_size;; 79 } 80 81 uint16_t mesh_subevent_configuration_composition_data_get_num_elements(const uint8_t * event, uint16_t size){ 82 uint16_t pos = MESH_COMPOSITION_DATA_ELEMENT_DESCRIPTION_OFFSET; 83 uint16_t num_elements = 0; 84 85 while ((pos + 4) <= size){ 86 // location descriptor 87 pos += 2; 88 uint8_t num_sig_model_ids = event[pos++]; 89 uint8_t num_vendor_model_ids = event[pos++]; 90 pos += (num_sig_model_ids + num_vendor_model_ids) * 2; 91 num_elements++; 92 } 93 return num_elements; 94 } 95 96 void mesh_composition_data_iterator_init(mesh_composite_data_iterator_t * it, const uint8_t * elements, uint16_t size){ 97 it->elements = elements; 98 it->size = size; 99 it->offset = MESH_COMPOSITION_DATA_ELEMENT_DESCRIPTION_OFFSET; 100 } 101 102 bool mesh_composition_data_iterator_has_next_element(mesh_composite_data_iterator_t * it){ 103 return (it->offset + mesh_composition_data_iterator_element_len(it)) <= it->size; 104 } 105 106 void mesh_composition_data_iterator_next_element(mesh_composite_data_iterator_t * it){ 107 it->sig_model_iterator.models = &it->elements[it->offset + 4]; 108 it->sig_model_iterator.size = mesh_composition_data_iterator_sig_model_list_size(it); 109 it->sig_model_iterator.offset = 0; 110 111 it->vendor_model_iterator.models = &it->elements[it->offset + 4 + it->sig_model_iterator.size]; 112 it->vendor_model_iterator.size = mesh_composition_data_iterator_vendor_model_list_size(it); 113 it->vendor_model_iterator.offset = 0; 114 115 it->loc = little_endian_read_16(it->elements, it->offset); 116 it->offset += mesh_composition_data_iterator_element_len(it); 117 } 118 119 uint16_t mesh_composition_data_iterator_element_loc(mesh_composite_data_iterator_t * it){ 120 return it->loc; 121 } 122 123 bool mesh_composition_data_iterator_has_next_sig_model(mesh_composite_data_iterator_t * it){ 124 return (it->sig_model_iterator.offset + MESH_SIG_MODEL_SIZE) <= it->sig_model_iterator.size; 125 } 126 127 void mesh_composition_data_iterator_next_sig_model(mesh_composite_data_iterator_t * it){ 128 it->sig_model_iterator.id = little_endian_read_16(it->sig_model_iterator.models, it->sig_model_iterator.offset); 129 it->sig_model_iterator.offset += 2; 130 } 131 132 uint16_t mesh_composition_data_iterator_sig_model_id(mesh_composite_data_iterator_t * it){ 133 return (uint16_t)it->sig_model_iterator.id; 134 } 135 136 bool mesh_composition_data_iterator_has_next_vendor_model(mesh_composite_data_iterator_t * it){ 137 return (it->vendor_model_iterator.offset + MESH_VENDOR_MODEL_SIZE) <= it->vendor_model_iterator.size; 138 } 139 140 void mesh_composition_data_iterator_next_vendor_model(mesh_composite_data_iterator_t * it){ 141 uint16_t vendor_id = little_endian_read_16(it->vendor_model_iterator.models, it->vendor_model_iterator.offset); 142 it->vendor_model_iterator.offset += 2; 143 uint16_t model_id = little_endian_read_16(it->vendor_model_iterator.models, it->vendor_model_iterator.offset); 144 it->vendor_model_iterator.offset += 2; 145 it->vendor_model_iterator.id = mesh_model_get_model_identifier(vendor_id, model_id); 146 } 147 148 uint32_t mesh_composition_data_iterator_vendor_model_id(mesh_composite_data_iterator_t * it){ 149 return it->vendor_model_iterator.id; 150 } 151 152 // Configuration client messages 153 154 static const mesh_access_message_t mesh_configuration_client_beacon_get = { 155 MESH_FOUNDATION_OPERATION_BEACON_GET, "" 156 }; 157 static const mesh_access_message_t mesh_configuration_client_beacon_set = { 158 MESH_FOUNDATION_OPERATION_BEACON_SET, "1" 159 }; 160 161 162 static const mesh_access_message_t mesh_configuration_client_composition_data_get = { 163 MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_GET, "1" 164 }; 165 166 167 static const mesh_access_message_t mesh_configuration_client_default_ttl_get = { 168 MESH_FOUNDATION_OPERATION_DEFAULT_TTL_GET, "" 169 }; 170 static const mesh_access_message_t mesh_configuration_client_default_ttl_set = { 171 MESH_FOUNDATION_OPERATION_DEFAULT_TTL_SET, "1" 172 }; 173 174 175 static const mesh_access_message_t mesh_configuration_client_gatt_proxy_get = { 176 MESH_FOUNDATION_OPERATION_GATT_PROXY_GET, "" 177 }; 178 static const mesh_access_message_t mesh_configuration_client_gatt_proxy_set = { 179 MESH_FOUNDATION_OPERATION_GATT_PROXY_SET, "1" 180 }; 181 182 183 static const mesh_access_message_t mesh_configuration_client_relay_get = { 184 MESH_FOUNDATION_OPERATION_RELAY_GET, "" 185 }; 186 static const mesh_access_message_t mesh_configuration_client_relay_set = { 187 MESH_FOUNDATION_OPERATION_RELAY_SET, "11" 188 }; 189 190 static const mesh_access_message_t mesh_configuration_client_publication_get = { 191 MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_GET, "2m" 192 }; 193 static const mesh_access_message_t mesh_configuration_client_publication_set = { 194 MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_SET, "222111m" 195 }; 196 static const mesh_access_message_t mesh_configuration_client_publication_virtual_address_set = { 197 MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_VIRTUAL_ADDRESS_SET, "2P2111m" 198 }; 199 200 static void mesh_configuration_client_send_acknowledged(uint16_t src, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, mesh_pdu_t *pdu, uint32_t ack_opcode){ 201 uint8_t ttl = mesh_foundation_default_ttl_get(); 202 mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0); 203 mesh_access_send_acknowledged_pdu(pdu, mesh_access_acknowledged_message_retransmissions(), ack_opcode); 204 } 205 206 static uint8_t mesh_access_validate_envelop_params(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){ 207 btstack_assert(mesh_model != NULL); 208 // TODO: validate other params 209 UNUSED(mesh_model); 210 UNUSED(dest); 211 UNUSED(netkey_index); 212 UNUSED(appkey_index); 213 214 return ERROR_CODE_SUCCESS; 215 } 216 217 uint8_t mesh_configuration_client_send_beacon_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){ 218 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 219 if (status != ERROR_CODE_SUCCESS) return status; 220 221 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_beacon_get); 222 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 223 224 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_BEACON_STATUS); 225 return ERROR_CODE_SUCCESS; 226 } 227 228 uint8_t mesh_configuration_client_send_beacon_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t beacon){ 229 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 230 if (status != ERROR_CODE_SUCCESS) return status; 231 232 if (beacon > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 233 234 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_beacon_set, beacon); 235 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 236 237 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_BEACON_STATUS); 238 return ERROR_CODE_SUCCESS; 239 } 240 241 uint8_t mesh_configuration_client_send_composition_data_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t page){ 242 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 243 if (status != ERROR_CODE_SUCCESS) return status; 244 245 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_composition_data_get, page); 246 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 247 248 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_GET); 249 return ERROR_CODE_SUCCESS; 250 } 251 252 uint8_t mesh_configuration_client_send_default_ttl_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){ 253 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 254 if (status != ERROR_CODE_SUCCESS) return status; 255 256 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_default_ttl_get); 257 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 258 259 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_DEFAULT_TTL_GET); 260 return ERROR_CODE_SUCCESS; 261 } 262 263 uint8_t mesh_configuration_client_send_default_ttl_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t ttl){ 264 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 265 if (status != ERROR_CODE_SUCCESS) return status; 266 267 if (ttl == 0x01 || ttl >= 0x80) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 268 269 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_default_ttl_set, ttl); 270 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 271 272 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_DEFAULT_TTL_SET); 273 return ERROR_CODE_SUCCESS; 274 } 275 276 uint8_t mesh_configuration_client_send_gatt_proxy_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){ 277 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 278 if (status != ERROR_CODE_SUCCESS) return status; 279 280 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_gatt_proxy_get); 281 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 282 283 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_GATT_PROXY_GET); 284 return ERROR_CODE_SUCCESS; 285 } 286 287 uint8_t mesh_configuration_client_send_gatt_proxy_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t gatt_proxy_state){ 288 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 289 if (status != ERROR_CODE_SUCCESS) return status; 290 291 if (gatt_proxy_state > 2) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 292 293 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_gatt_proxy_set, gatt_proxy_state); 294 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 295 296 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_GATT_PROXY_SET); 297 return ERROR_CODE_SUCCESS; 298 } 299 300 uint8_t mesh_configuration_client_send_relay_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){ 301 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 302 if (status != ERROR_CODE_SUCCESS) return status; 303 304 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_relay_get); 305 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 306 307 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_RELAY_GET); 308 return ERROR_CODE_SUCCESS; 309 } 310 311 uint8_t mesh_configuration_client_send_relay_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t relay, uint8_t relay_retransmit_count, uint8_t relay_retransmit_interval_steps){ 312 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 313 if (status != ERROR_CODE_SUCCESS) return status; 314 315 if (relay_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 316 if (relay_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 317 318 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_relay_set, relay, (relay_retransmit_count << 5) | relay_retransmit_interval_steps); 319 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 320 321 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_RELAY_SET); 322 return ERROR_CODE_SUCCESS; 323 } 324 325 uint8_t mesh_configuration_client_send_model_publication_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint32_t model_id){ 326 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 327 if (status != ERROR_CODE_SUCCESS) return status; 328 329 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_publication_get, dest, model_id); 330 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 331 332 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_DEFAULT_TTL_GET); 333 return ERROR_CODE_SUCCESS; 334 } 335 336 uint8_t mesh_configuration_client_send_model_publication_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint32_t model_id, mesh_publication_model_config_t * publication_config){ 337 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 338 if (status != ERROR_CODE_SUCCESS) return status; 339 if (mesh_network_address_virtual(publication_config->publish_address_unicast)) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 340 341 if (!mesh_network_address_unicast(dest)) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 342 if (publication_config->appkey_index > 0xFFF) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 343 if (publication_config->credential_flag > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 344 if (publication_config->publish_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 345 if (publication_config->publish_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 346 347 mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_publication_set, 348 dest, 349 publication_config->publish_address_unicast, 350 (publication_config->credential_flag << 12) | publication_config->appkey_index, 351 publication_config->publish_ttl, 352 publication_config->publish_period, 353 (publication_config->publish_retransmit_interval_steps << 3) | publication_config->publish_retransmit_count, 354 model_id); 355 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 356 357 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_RELAY_SET); 358 return ERROR_CODE_SUCCESS; 359 360 } 361 362 uint8_t mesh_configuration_client_send_model_publication_virtual_address_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint32_t model_id, mesh_publication_model_config_t * publication_config){ 363 uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index); 364 if (status != ERROR_CODE_SUCCESS) return status; 365 366 if (!mesh_network_address_unicast(dest)) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 367 if (publication_config->appkey_index > 0xFFF) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 368 if (publication_config->credential_flag > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 369 if (publication_config->publish_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 370 if (publication_config->publish_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 371 372 mesh_transport_pdu_t * network_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_publication_virtual_address_set, 373 dest, 374 publication_config->publish_address_virtual, 375 (publication_config->credential_flag << 12) | publication_config->appkey_index, 376 publication_config->publish_ttl, 377 publication_config->publish_period, 378 (publication_config->publish_retransmit_interval_steps << 3) | publication_config->publish_retransmit_count, 379 model_id); 380 if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED; 381 382 mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_RELAY_SET); 383 return ERROR_CODE_SUCCESS; 384 } 385 386 387 388 // Model Operations 389 static void mesh_configuration_client_composition_data_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){ 390 // Composition Data has variable of element descriptions, with two lists of model lists 391 // Pass raw data to application but provide convenient setters instead of parsing pdu here 392 393 // reuse part of the mesh_network_t / mesh_transport_t struct to create event without memcpy or allocation 394 uint8_t * data = mesh_pdu_data(pdu); 395 uint8_t * event = &data[-6]; 396 397 int pos = 0; 398 event[pos++] = HCI_EVENT_MESH_META; 399 // Composite Data might be larger than 251 bytes - in this case only lower 8 bit are stored here. packet size is correct 400 event[pos++] = (uint8_t) (6 + mesh_pdu_len(pdu)); 401 event[pos++] = MESH_SUBEVENT_CONFIGURATION_COMPOSITION_DATA; 402 // dest 403 little_endian_store_16(event, pos, mesh_pdu_src(pdu)); 404 pos += 2; 405 event[pos++] = ERROR_CODE_SUCCESS; 406 407 (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 408 mesh_access_message_processed(pdu); 409 } 410 411 uint8_t mesh_subevent_configuration_composition_data_get_page(const uint8_t * event){ 412 return event[6]; 413 } 414 415 uint16_t mesh_subevent_configuration_composition_data_get_cid(const uint8_t * event){ 416 return little_endian_read_16(event, 7); 417 } 418 419 uint16_t mesh_subevent_configuration_composition_data_get_pid(const uint8_t * event){ 420 return little_endian_read_16(event, 9); 421 } 422 423 uint16_t mesh_subevent_configuration_composition_data_get_vid(const uint8_t * event){ 424 return little_endian_read_16(event, 11); 425 } 426 427 uint16_t mesh_subevent_configuration_composition_data_get_crpl(const uint8_t * event){ 428 return little_endian_read_16(event, 13); 429 } 430 431 uint16_t mesh_subevent_configuration_composition_data_get_features(const uint8_t * event){ 432 return little_endian_read_16(event, 15); 433 } 434 435 436 static inline void mesh_configuration_client_handle_uint8_value(mesh_model_t *mesh_model, mesh_pdu_t * pdu, uint8_t subevent_type){ 437 mesh_access_parser_state_t parser; 438 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu); 439 440 uint8_t value = mesh_access_parser_get_u8(&parser); 441 442 uint8_t event[7]; 443 int pos = 0; 444 445 event[pos++] = HCI_EVENT_MESH_META; 446 event[pos++] = sizeof(event) - 2; 447 event[pos++] = subevent_type; 448 // dest 449 little_endian_store_16(event, pos, mesh_pdu_src(pdu)); 450 pos += 2; 451 event[pos++] = ERROR_CODE_SUCCESS; 452 event[pos++] = value; 453 454 (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 455 mesh_access_message_processed(pdu); 456 } 457 458 static void mesh_configuration_client_beacon_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){ 459 mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_BEACON); 460 } 461 462 static void mesh_configuration_client_default_ttl_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){ 463 mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_DEFAULT_TTL); 464 } 465 466 static void mesh_configuration_client_gatt_proxy_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){ 467 mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_GATT_PROXY); 468 } 469 470 static void mesh_configuration_client_relay_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){ 471 mesh_access_parser_state_t parser; 472 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu); 473 474 uint8_t relay = mesh_access_parser_get_u8(&parser); 475 uint8_t retransmition = mesh_access_parser_get_u8(&parser); 476 477 uint8_t event[9]; 478 479 int pos = 0; 480 event[pos++] = HCI_EVENT_MESH_META; 481 event[pos++] = sizeof(event) - 2; 482 event[pos++] = MESH_SUBEVENT_CONFIGURATION_RELAY; 483 // dest 484 little_endian_store_16(event, pos, mesh_pdu_src(pdu)); 485 pos += 2; 486 event[pos++] = ERROR_CODE_SUCCESS; 487 event[pos++] = relay; 488 event[pos++] = (retransmition >> 5) + 1; 489 event[pos++] = ((retransmition & 0x07) + 1) * 10; 490 491 (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 492 mesh_access_message_processed(pdu); 493 } 494 495 static void mesh_configuration_client_model_publication_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){ 496 mesh_access_parser_state_t parser; 497 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu); 498 uint8_t status = mesh_access_parser_get_u8(&parser); 499 uint16_t publish_addres = mesh_access_parser_get_u16(&parser); 500 501 uint16_t value = mesh_access_parser_get_u16(&parser); 502 uint16_t appkey_index = value & 0xFFF; 503 uint8_t credential_flag = (value & 0x1000) >> 12; 504 505 uint8_t publish_ttl = mesh_access_parser_get_u8(&parser); 506 uint8_t publish_period = mesh_access_parser_get_u8(&parser); 507 508 uint8_t retransmit = mesh_access_parser_get_u8(&parser); 509 uint8_t publish_retransmit_count = retransmit & 0x111; 510 uint8_t publish_retransmit_interval_steps = retransmit >> 5; 511 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser); 512 513 uint8_t event[19]; 514 int pos = 0; 515 event[pos++] = HCI_EVENT_MESH_META; 516 event[pos++] = sizeof(event) - 2; 517 event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_PUBLICATION; 518 // dest 519 little_endian_store_16(event, pos, mesh_pdu_src(pdu)); 520 pos += 2; 521 event[pos++] = status; 522 523 little_endian_store_16(event, pos, publish_addres); 524 pos += 2; 525 526 little_endian_store_16(event, pos, appkey_index); 527 pos += 2; 528 529 event[pos++] = credential_flag; 530 event[pos++] = publish_ttl; 531 event[pos++] = publish_period; 532 event[pos++] = publish_retransmit_count; 533 event[pos++] = publish_retransmit_interval_steps; 534 535 little_endian_store_32(event, pos, model_identifier); 536 pos += 4; 537 538 (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 539 mesh_access_message_processed(pdu); 540 } 541 542 const static mesh_operation_t mesh_configuration_client_model_operations[] = { 543 { MESH_FOUNDATION_OPERATION_BEACON_STATUS, 1, mesh_configuration_client_beacon_status_handler }, 544 { MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_STATUS, 10, mesh_configuration_client_composition_data_status_handler }, 545 { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS, 1, mesh_configuration_client_default_ttl_handler }, 546 { MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS, 1, mesh_configuration_client_gatt_proxy_handler }, 547 { MESH_FOUNDATION_OPERATION_RELAY_STATUS, 2, mesh_configuration_client_relay_handler }, 548 { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS, 12, mesh_configuration_client_model_publication_handler }, 549 550 { 0, 0, NULL } 551 }; 552 553 const mesh_operation_t * mesh_configuration_client_get_operations(void){ 554 return mesh_configuration_client_model_operations; 555 } 556 557 void mesh_configuration_client_register_packet_handler(mesh_model_t *configuration_client_model, btstack_packet_handler_t events_packet_handler){ 558 btstack_assert(events_packet_handler != NULL); 559 btstack_assert(configuration_client_model != NULL); 560 561 configuration_client_model->model_packet_handler = events_packet_handler; 562 } 563 564