xref: /btstack/src/mesh/mesh_access.c (revision f77356ee3ff5b24d6580a05b873881bec1ac341d)
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_access.c"
39 
40 #include <string.h>
41 #include <stdio.h>
42 #include <stdarg.h>
43 
44 #include "mesh/mesh_access.h"
45 
46 #include "btstack_debug.h"
47 #include "btstack_memory.h"
48 #include "btstack_tlv.h"
49 
50 #include "mesh/beacon.h"
51 #include "mesh/mesh_foundation.h"
52 #include "mesh/mesh_iv_index_seq_number.h"
53 #include "mesh/mesh_node.h"
54 #include "mesh/mesh_proxy.h"
55 #include "mesh/mesh_upper_transport.h"
56 #include "mesh/mesh.h"
57 
58 #define MEST_TRANSACTION_TIMEOUT_MS  6000
59 
60 static void mesh_access_message_process_handler(mesh_pdu_t * pdu);
61 static void mesh_access_upper_transport_handler(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu);
62 static const mesh_operation_t * mesh_model_lookup_operation_by_opcode(mesh_model_t * model, uint32_t opcode);
63 
64 // receive
65 static uint16_t mesh_access_received_pdu_refcount;
66 
67 // acknowledged messages
68 static btstack_linked_list_t  mesh_access_acknowledged_messages;
69 static btstack_timer_source_t mesh_access_acknowledged_timer;
70 static int                    mesh_access_acknowledged_timer_active;
71 
72 // Transitions
73 static uint8_t mesh_transaction_id_counter = 0;
74 
75 void mesh_access_init(void){
76     // register with upper transport
77     mesh_upper_transport_register_access_message_handler(&mesh_access_message_process_handler);
78     mesh_upper_transport_set_higher_layer_handler(&mesh_access_upper_transport_handler);
79 }
80 
81 void mesh_access_emit_state_update_bool(btstack_packet_handler_t event_handler, uint8_t element_index, uint32_t model_identifier,
82     model_state_id_t state_identifier, model_state_update_reason_t reason, uint8_t value){
83     if (event_handler == NULL) return;
84     uint8_t event[14] = {HCI_EVENT_MESH_META, 12, MESH_SUBEVENT_STATE_UPDATE_BOOL};
85     int pos = 3;
86     event[pos++] = element_index;
87     little_endian_store_32(event, pos, model_identifier);
88     pos += 4;
89     little_endian_store_32(event, pos, (uint32_t)state_identifier);
90     pos += 4;
91     event[pos++] = (uint8_t)reason;
92     event[pos++] = value;
93     (*event_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
94 }
95 
96 void mesh_access_emit_state_update_int16(btstack_packet_handler_t event_handler, uint8_t element_index, uint32_t model_identifier,
97     model_state_id_t state_identifier, model_state_update_reason_t reason, int16_t value){
98     if (event_handler == NULL) return;
99     uint8_t event[15] = {HCI_EVENT_MESH_META, 13, MESH_SUBEVENT_STATE_UPDATE_BOOL};
100     int pos = 3;
101     event[pos++] = element_index;
102     little_endian_store_32(event, pos, model_identifier);
103     pos += 4;
104     little_endian_store_32(event, pos, (uint32_t)state_identifier);
105     pos += 4;
106     event[pos++] = (uint8_t)reason;
107     little_endian_store_16(event, pos, (uint16_t) value);
108     pos += 2;
109     (*event_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
110 }
111 
112 uint8_t mesh_access_acknowledged_message_retransmissions(void){
113     return 3;
114 }
115 
116 uint32_t mesh_access_acknowledged_message_timeout_ms(void){
117     return 30000;
118 }
119 
120 #define MESH_ACCESS_OPCODE_INVALID 0xFFFFFFFFu
121 #define MESH_ACCESS_OPCODE_NOT_SET 0xFFFFFFFEu
122 
123 static uint32_t mesh_access_message_ack_opcode(mesh_pdu_t * pdu){
124     switch (pdu->pdu_type){
125         case MESH_PDU_TYPE_TRANSPORT:
126             return ((mesh_transport_pdu_t *)pdu)->ack_opcode;
127         case MESH_PDU_TYPE_SEGMENTED:
128             return ((mesh_segmented_pdu_t *)pdu)->ack_opcode;
129         default:
130             btstack_assert(0);
131             return MESH_ACCESS_OPCODE_INVALID;
132     }
133 }
134 
135 static void mesh_access_message_set_ack_opcode(mesh_pdu_t * pdu, uint32_t ack_opcode){
136     switch (pdu->pdu_type){
137         case MESH_PDU_TYPE_TRANSPORT:
138             ((mesh_transport_pdu_t *)pdu)->ack_opcode = ack_opcode;
139             break;
140         case MESH_PDU_TYPE_SEGMENTED:
141             ((mesh_segmented_pdu_t *)pdu)->ack_opcode = ack_opcode;
142             break;
143         default:
144             btstack_assert(0);
145             break;
146     }
147 }
148 
149 static uint8_t mesh_access_message_retransmit_count(mesh_pdu_t * pdu){
150     switch (pdu->pdu_type){
151         case MESH_PDU_TYPE_TRANSPORT:
152             return ((mesh_transport_pdu_t *)pdu)->retransmit_count;
153         case MESH_PDU_TYPE_SEGMENTED:
154             return ((mesh_segmented_pdu_t *)pdu)->retransmit_count;
155         default:
156             btstack_assert(0);
157             return 0;
158     }
159 }
160 
161 static void mesh_access_message_set_retransmit_count(mesh_pdu_t * pdu, uint8_t retransmit_count){
162     switch (pdu->pdu_type){
163         case MESH_PDU_TYPE_TRANSPORT:
164             ((mesh_transport_pdu_t *)pdu)->retransmit_count = retransmit_count;
165             break;
166         case MESH_PDU_TYPE_SEGMENTED:
167             ((mesh_segmented_pdu_t *)pdu)->retransmit_count = retransmit_count;
168             break;
169         default:
170             btstack_assert(0);
171             break;
172     }
173 }
174 
175 static uint32_t mesh_access_message_retransmit_timeout_ms(mesh_pdu_t * pdu){
176     switch (pdu->pdu_type){
177         case MESH_PDU_TYPE_TRANSPORT:
178             return ((mesh_transport_pdu_t *)pdu)->retransmit_timeout_ms;
179         case MESH_PDU_TYPE_SEGMENTED:
180             return ((mesh_segmented_pdu_t *)pdu)->retransmit_timeout_ms;
181         default:
182             btstack_assert(0);
183             return 0;
184     }
185 }
186 
187 static void mesh_access_message_set_retransmit_timeout_ms(mesh_pdu_t * pdu, uint32_t retransmit_timeout_ms){
188     switch (pdu->pdu_type){
189         case MESH_PDU_TYPE_TRANSPORT:
190             ((mesh_transport_pdu_t *)pdu)->retransmit_timeout_ms = retransmit_timeout_ms;
191             break;
192         case MESH_PDU_TYPE_SEGMENTED:
193             ((mesh_segmented_pdu_t *)pdu)->retransmit_timeout_ms = retransmit_timeout_ms;
194             break;
195         default:
196             btstack_assert(0);
197             break;
198     }
199 }
200 
201 void mesh_access_send_unacknowledged_pdu(mesh_pdu_t * pdu){
202     mesh_access_message_set_ack_opcode(pdu, MESH_ACCESS_OPCODE_INVALID);
203     mesh_upper_transport_send_access_pdu(pdu);
204 }
205 
206 void mesh_access_send_acknowledged_pdu(mesh_pdu_t * pdu, uint8_t retransmissions, uint32_t ack_opcode){
207     mesh_access_message_set_retransmit_count(pdu, retransmissions);
208     mesh_access_message_set_ack_opcode(pdu, ack_opcode);
209 
210     mesh_upper_transport_send_access_pdu(pdu);
211 }
212 
213 #define MESH_SUBEVENT_MESSAGE_NOT_ACKNOWLEDGED                                        0x30
214 
215 static void mesh_access_acknowledged_run(btstack_timer_source_t * ts){
216     UNUSED(ts);
217 
218     uint32_t now = btstack_run_loop_get_time_ms();
219 
220     // handle timeouts
221     btstack_linked_list_iterator_t ack_it;
222     btstack_linked_list_iterator_init(&ack_it, &mesh_access_acknowledged_messages);
223     while (btstack_linked_list_iterator_has_next(&ack_it)){
224         mesh_pdu_t * pdu = (mesh_pdu_t *) btstack_linked_list_iterator_next(&ack_it);
225         uint32_t retransmit_timeout_ms = mesh_access_message_retransmit_timeout_ms(pdu);
226         if (btstack_time_delta(now, retransmit_timeout_ms) >= 0) {
227             // remove from list
228             btstack_linked_list_remove(&mesh_access_acknowledged_messages, (btstack_linked_item_t*) pdu);
229             // retransmit or report failure
230             uint8_t retransmit_count = mesh_access_message_retransmit_count(pdu);
231             if (retransmit_count){
232                 mesh_access_message_set_retransmit_count(pdu, retransmit_count - 1);
233                 mesh_upper_transport_send_access_pdu(pdu);
234             } else {
235                 // find correct model and emit error
236                 uint16_t src = mesh_pdu_src(pdu);
237                 uint16_t dst = mesh_pdu_dst(pdu);
238                 mesh_element_t * element = mesh_node_element_for_unicast_address(src);
239                 if (element){
240                     // find
241                     mesh_model_iterator_t model_it;
242                     mesh_model_iterator_init(&model_it, element);
243                     while (mesh_model_iterator_has_next(&model_it)){
244                         mesh_model_t * model = mesh_model_iterator_next(&model_it);
245                         // find opcode in table
246                         uint32_t ack_opcode = mesh_access_message_ack_opcode(pdu);
247                         const mesh_operation_t * operation = mesh_model_lookup_operation_by_opcode(model, ack_opcode);
248                         if (operation == NULL) continue;
249                         if (model->model_packet_handler == NULL) continue;
250                         // emit event
251                         uint8_t event[13];
252                         event[0] = HCI_EVENT_MESH_META;
253                         event[1] = sizeof(event) - 2;
254                         event[2] = element->element_index;
255                         little_endian_store_32(event, 3, model->model_identifier);
256                         little_endian_store_32(event, 7, ack_opcode);
257                         little_endian_store_16(event, 11, dst);
258                         (*model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
259                     }
260                 }
261 
262                 // free
263                 mesh_upper_transport_pdu_free(pdu);
264             }
265         }
266     }
267 
268     if (mesh_access_acknowledged_timer_active) return;
269 
270     // find earliest timeout and set timer
271     btstack_linked_list_iterator_init(&ack_it, &mesh_access_acknowledged_messages);
272     int32_t next_timeout_ms = 0;
273     while (btstack_linked_list_iterator_has_next(&ack_it)){
274         mesh_pdu_t * pdu = (mesh_pdu_t *) btstack_linked_list_iterator_next(&ack_it);
275         uint32_t retransmit_timeout_ms = mesh_access_message_retransmit_timeout_ms(pdu);
276         int32_t timeout_delta_ms = btstack_time_delta(retransmit_timeout_ms, now);
277         if (next_timeout_ms == 0 || timeout_delta_ms < next_timeout_ms){
278             next_timeout_ms = timeout_delta_ms;
279         }
280     }
281 
282     // set timer
283     if (next_timeout_ms == 0) return;
284 
285     btstack_run_loop_set_timer(&mesh_access_acknowledged_timer, next_timeout_ms);
286     btstack_run_loop_set_timer_handler(&mesh_access_acknowledged_timer, mesh_access_acknowledged_run);
287     btstack_run_loop_add_timer(&mesh_access_acknowledged_timer);
288     mesh_access_acknowledged_timer_active = 1;
289 }
290 
291 static void mesh_access_acknowledged_received(uint16_t rx_src, uint32_t opcode){
292     // check if received src matches our dest
293     // free acknowledged messages if we were waiting for this message
294 
295     btstack_linked_list_iterator_t ack_it;
296     btstack_linked_list_iterator_init(&ack_it, &mesh_access_acknowledged_messages);
297     while (btstack_linked_list_iterator_has_next(&ack_it)){
298         mesh_pdu_t * tx_pdu = (mesh_pdu_t *) btstack_linked_list_iterator_next(&ack_it);
299         uint16_t tx_dest = mesh_pdu_dst(tx_pdu);
300         if (tx_dest != rx_src) continue;
301         if (mesh_access_message_ack_opcode(tx_pdu) != opcode) continue;
302         // got expected response from dest, remove from outgoing messages
303         mesh_upper_transport_pdu_free(tx_pdu);
304         return;
305     }
306 }
307 
308 static void mesh_access_upper_transport_handler(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu){
309     UNUSED(status);
310     switch (callback_type){
311         case MESH_TRANSPORT_PDU_SENT:
312             // unacknowledged -> free
313             if (mesh_access_message_ack_opcode(pdu) == MESH_ACCESS_OPCODE_INVALID){
314                 mesh_upper_transport_pdu_free(pdu);
315                 break;
316             }
317             // setup timeout
318             mesh_access_message_set_retransmit_timeout_ms(pdu, btstack_run_loop_get_time_ms() + mesh_access_acknowledged_message_timeout_ms());
319             // add to mesh_access_acknowledged_messages
320             btstack_linked_list_add(&mesh_access_acknowledged_messages, (btstack_linked_item_t *) pdu);
321             // update timer
322             mesh_access_acknowledged_run(NULL);
323             break;
324         default:
325             break;
326     }
327 }
328 
329 // Mesh Model Transitions
330 
331 uint32_t mesh_access_time_gdtt2ms(uint8_t time_gdtt){
332     uint8_t num_steps  = mesh_access_transitions_num_steps_from_gdtt(time_gdtt);
333     if (num_steps > 0x3E) return 0;
334 
335     return mesh_access_transitions_step_ms_from_gdtt(time_gdtt) * num_steps;
336 }
337 
338 uint8_t mesh_access_transitions_num_steps_from_gdtt(uint8_t time_gdtt){
339     return time_gdtt & 0x3fu;
340 }
341 
342 uint32_t mesh_access_transitions_step_ms_from_gdtt(uint8_t time_gdtt){
343     mesh_default_transition_step_resolution_t step_resolution = (mesh_default_transition_step_resolution_t) (time_gdtt >> 6);
344     switch (step_resolution){
345         case MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_100ms:
346             return 100;
347         case MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_1s:
348             return 1000;
349         case MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_10s:
350             return 10000;
351         case MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_10min:
352             return 600000;
353         default:
354             return 0;
355     }
356 }
357 
358 uint8_t mesh_access_transactions_get_next_transaction_id(void){
359     mesh_transaction_id_counter++;
360     if (mesh_transaction_id_counter == 0){
361         mesh_transaction_id_counter = 1;
362     }
363     return mesh_transaction_id_counter;
364 }
365 
366 static int mesh_access_transitions_transaction_is_expired(mesh_transition_t * transition){
367     return (btstack_run_loop_get_time_ms() - transition->transaction_timestamp_ms) > MEST_TRANSACTION_TIMEOUT_MS;
368 }
369 
370 mesh_transaction_status_t mesh_access_transitions_transaction_status(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address){
371     if (transition->src_address != src_address || transition->dst_address != dst_address) return MESH_TRANSACTION_STATUS_DIFFERENT_DST_OR_SRC;
372 
373     if (transition->transaction_identifier == transaction_identifier && !mesh_access_transitions_transaction_is_expired(transition)){
374             return MESH_TRANSACTION_STATUS_RETRANSMISSION;
375     }
376     return MESH_TRANSACTION_STATUS_NEW;
377 }
378 
379 void mesh_access_transitions_init_transaction(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address){
380     transition->transaction_timestamp_ms = btstack_run_loop_get_time_ms();
381     transition->transaction_identifier = transaction_identifier;
382     transition->src_address = src_address;
383     transition->dst_address = dst_address;
384 }
385 
386 static void mesh_server_transition_timeout(btstack_timer_source_t * ts){
387     mesh_transition_t * base_transition = (mesh_transition_t*) btstack_run_loop_get_timer_context(ts);
388     switch (base_transition->state){
389         case MESH_TRANSITION_STATE_DELAYED:
390             base_transition->state = MESH_TRANSITION_STATE_ACTIVE;
391             (*base_transition->transition_callback)(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_START);
392             if (base_transition->num_steps > 0){
393                 btstack_run_loop_set_timer(&base_transition->timer, base_transition->step_duration_ms);
394                 btstack_run_loop_add_timer(&base_transition->timer);
395                 return;
396             }
397             base_transition->state = MESH_TRANSITION_STATE_IDLE;
398             (*base_transition->transition_callback)(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
399             break;
400         case MESH_TRANSITION_STATE_ACTIVE:
401             if (base_transition->num_steps < MESH_TRANSITION_NUM_STEPS_INFINITE){
402                 base_transition->num_steps--;
403             }
404             (*base_transition->transition_callback)(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_ACTIVE);
405             if (base_transition->num_steps > 0){
406                 btstack_run_loop_set_timer(&base_transition->timer, base_transition->step_duration_ms);
407                 btstack_run_loop_add_timer(&base_transition->timer);
408                 return;
409             }
410             base_transition->state = MESH_TRANSITION_STATE_IDLE;
411             (*base_transition->transition_callback)(base_transition, MODEL_STATE_UPDATE_REASON_TRANSITION_END);
412             break;
413         default:
414             break;
415     }
416 }
417 
418 void mesh_access_transition_setup(mesh_model_t *mesh_model, mesh_transition_t * base_transition, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, void (*transition_callback)(mesh_transition_t * base_transition, model_state_update_reason_t event)){
419 
420     base_transition->mesh_model          = mesh_model;
421     base_transition->num_steps           = mesh_access_transitions_num_steps_from_gdtt(transition_time_gdtt);
422     base_transition->step_resolution     = (mesh_default_transition_step_resolution_t) (transition_time_gdtt >> 6);
423     base_transition->step_duration_ms    = mesh_access_transitions_step_ms_from_gdtt(transition_time_gdtt);
424     base_transition->transition_callback = transition_callback;
425 
426     btstack_run_loop_set_timer_context(&base_transition->timer, base_transition);
427     btstack_run_loop_set_timer_handler(&base_transition->timer, &mesh_server_transition_timeout);
428 
429     // delayed
430     if (delay_time_gdtt > 0){
431         base_transition->state = MESH_TRANSITION_STATE_DELAYED;
432         btstack_run_loop_set_timer(&base_transition->timer, delay_time_gdtt * 5);
433         btstack_run_loop_add_timer(&base_transition->timer);
434         return;
435     }
436 
437     // started
438     if (base_transition->num_steps > 0){
439         base_transition->state = MESH_TRANSITION_STATE_ACTIVE;
440         btstack_run_loop_set_timer(&base_transition->timer, base_transition->step_duration_ms);
441         btstack_run_loop_add_timer(&base_transition->timer);
442         return;
443     }
444 
445     // instanteneous update
446     base_transition->state = MESH_TRANSITION_STATE_IDLE;
447     (*transition_callback)(base_transition, MODEL_STATE_UPDATE_REASON_SET);
448     return;
449 }
450 
451 void mesh_access_transitions_abort_transaction(mesh_transition_t * base_transition){
452     btstack_run_loop_add_timer(&base_transition->timer);
453 }
454 
455 static uint16_t mesh_access_src(mesh_access_pdu_t * access_pdu){
456     return big_endian_read_16(access_pdu->network_header, 5);
457 }
458 
459 static uint16_t mesh_access_dst(mesh_access_pdu_t * access_pdu){
460     return big_endian_read_16(access_pdu->network_header, 7);
461 }
462 
463 uint16_t mesh_pdu_ctl(mesh_pdu_t * pdu){
464     switch (pdu->pdu_type){
465         case MESH_PDU_TYPE_TRANSPORT:
466             return mesh_transport_ctl((mesh_transport_pdu_t*) pdu);
467         case MESH_PDU_TYPE_NETWORK:
468             return mesh_network_control((mesh_network_pdu_t *) pdu);
469         default:
470             btstack_assert(false);
471             return 0;
472     }
473 }
474 
475 uint16_t mesh_pdu_ttl(mesh_pdu_t * pdu){
476     switch (pdu->pdu_type){
477         case MESH_PDU_TYPE_TRANSPORT:
478             return mesh_transport_ttl((mesh_transport_pdu_t*) pdu);
479         case MESH_PDU_TYPE_NETWORK:
480             return mesh_network_ttl((mesh_network_pdu_t *) pdu);
481         default:
482             btstack_assert(false);
483             return 0;
484     }
485 }
486 
487 uint16_t mesh_pdu_src(mesh_pdu_t * pdu){
488     switch (pdu->pdu_type){
489         case MESH_PDU_TYPE_ACCESS:
490             return mesh_access_src((mesh_access_pdu_t *) pdu);
491         case MESH_PDU_TYPE_TRANSPORT:
492             return mesh_transport_src((mesh_transport_pdu_t*) pdu);
493         case MESH_PDU_TYPE_NETWORK:
494             return mesh_network_src((mesh_network_pdu_t *) pdu);
495         default:
496             btstack_assert(false);
497             return MESH_ADDRESS_UNSASSIGNED;
498     }
499 }
500 
501 uint16_t mesh_pdu_dst(mesh_pdu_t * pdu){
502     switch (pdu->pdu_type){
503         case MESH_PDU_TYPE_ACCESS:
504             return mesh_access_dst((mesh_access_pdu_t *) pdu);
505         case MESH_PDU_TYPE_TRANSPORT:
506             return mesh_transport_dst((mesh_transport_pdu_t*) pdu);
507         case MESH_PDU_TYPE_NETWORK:
508             return mesh_network_dst((mesh_network_pdu_t *) pdu);
509         default:
510             btstack_assert(false);
511             return MESH_ADDRESS_UNSASSIGNED;
512     }
513 }
514 
515 uint16_t mesh_pdu_netkey_index(mesh_pdu_t * pdu){
516     switch (pdu->pdu_type){
517         case MESH_PDU_TYPE_ACCESS:
518             return ((mesh_access_pdu_t*) pdu)->netkey_index;
519         case MESH_PDU_TYPE_TRANSPORT:
520             return ((mesh_transport_pdu_t*) pdu)->netkey_index;
521         case MESH_PDU_TYPE_NETWORK:
522             return ((mesh_network_pdu_t *) pdu)->netkey_index;
523         default:
524             btstack_assert(false);
525             return 0;
526     }
527 }
528 
529 uint16_t mesh_pdu_appkey_index(mesh_pdu_t * pdu){
530     switch (pdu->pdu_type){
531         case MESH_PDU_TYPE_ACCESS:
532             return ((mesh_access_pdu_t*) pdu)->appkey_index;
533         case MESH_PDU_TYPE_TRANSPORT:
534             return ((mesh_transport_pdu_t*) pdu)->appkey_index;
535         default:
536             btstack_assert(false);
537             return 0;
538     }
539 }
540 
541 uint16_t mesh_pdu_len(mesh_pdu_t * pdu){
542     switch (pdu->pdu_type){
543         case MESH_PDU_TYPE_ACCESS:
544             return ((mesh_access_pdu_t*) pdu)->len;
545         case MESH_PDU_TYPE_TRANSPORT:
546             return ((mesh_transport_pdu_t*) pdu)->len;
547         case MESH_PDU_TYPE_NETWORK:
548             return ((mesh_network_pdu_t *) pdu)->len - 10;
549         default:
550             btstack_assert(false);
551             return 0;
552     }
553 }
554 
555 uint8_t * mesh_pdu_data(mesh_pdu_t * pdu){
556     switch (pdu->pdu_type){
557         case MESH_PDU_TYPE_ACCESS:
558             return ((mesh_access_pdu_t*) pdu)->data;
559         case MESH_PDU_TYPE_TRANSPORT:
560             return ((mesh_transport_pdu_t*) pdu)->data;
561         case MESH_PDU_TYPE_NETWORK:
562             return &((mesh_network_pdu_t *) pdu)->data[10];
563         default:
564             btstack_assert(false);
565             return NULL;
566     }
567 }
568 
569 uint8_t mesh_pdu_control_opcode(mesh_pdu_t * pdu){
570     switch (pdu->pdu_type){
571         case MESH_PDU_TYPE_TRANSPORT:
572             return mesh_transport_control_opcode((mesh_transport_pdu_t*) pdu);
573         case MESH_PDU_TYPE_NETWORK:
574             return mesh_network_control_opcode((mesh_network_pdu_t *) pdu);
575         default:
576             btstack_assert(false);
577             return 0xff;
578     }
579 }
580 
581 // message parser
582 
583 static int mesh_access_get_opcode(uint8_t * buffer, uint16_t buffer_size, uint32_t * opcode, uint16_t * opcode_size){
584     switch (buffer[0] >> 6){
585         case 0:
586         case 1:
587             if (buffer[0] == 0x7f) return 0;
588             *opcode = buffer[0];
589             *opcode_size = 1;
590             return 1;
591         case 2:
592             if (buffer_size < 2) return 0;
593             *opcode = big_endian_read_16(buffer, 0);
594             *opcode_size = 2;
595             return 1;
596         case 3:
597             if (buffer_size < 3) return 0;
598             *opcode = (buffer[0] << 16) | little_endian_read_16(buffer, 1);
599             *opcode_size = 3;
600             return 1;
601         default:
602             return 0;
603     }
604 }
605 
606 int mesh_access_pdu_get_opcode(mesh_pdu_t * pdu, uint32_t * opcode, uint16_t * opcode_size){
607     btstack_assert(pdu->pdu_type == MESH_PDU_TYPE_ACCESS);
608     return mesh_access_get_opcode(((mesh_access_pdu_t *) pdu)->data, ((mesh_access_pdu_t *) pdu)->len, opcode,
609                                   opcode_size);
610 }
611 
612 void mesh_access_parser_skip(mesh_access_parser_state_t * state, uint16_t bytes_to_skip){
613     state->data += bytes_to_skip;
614     state->len  -= bytes_to_skip;
615 }
616 
617 int mesh_access_parser_init(mesh_access_parser_state_t * state, mesh_pdu_t * pdu){
618     btstack_assert(pdu->pdu_type == MESH_PDU_TYPE_ACCESS);
619     state->data = mesh_pdu_data(pdu);
620     state->len  = mesh_pdu_len(pdu);
621 
622     uint16_t opcode_size = 0;
623     int ok = mesh_access_get_opcode(state->data, state->len, &state->opcode, &opcode_size);
624     if (ok){
625         mesh_access_parser_skip(state, opcode_size);
626     }
627     return ok;
628 }
629 
630 uint16_t mesh_access_parser_available(mesh_access_parser_state_t * state){
631     return state->len;
632 }
633 
634 uint8_t mesh_access_parser_get_u8(mesh_access_parser_state_t * state){
635     uint8_t value = *state->data;
636     mesh_access_parser_skip(state, 1);
637     return value;
638 }
639 
640 uint16_t mesh_access_parser_get_u16(mesh_access_parser_state_t * state){
641     uint16_t value = little_endian_read_16(state->data, 0);
642     mesh_access_parser_skip(state, 2);
643     return value;
644 }
645 
646 uint32_t mesh_access_parser_get_u24(mesh_access_parser_state_t * state){
647     uint32_t value = little_endian_read_24(state->data, 0);
648     mesh_access_parser_skip(state, 3);
649     return value;
650 }
651 
652 uint32_t mesh_access_parser_get_u32(mesh_access_parser_state_t * state){
653     uint32_t value = little_endian_read_32(state->data, 0);
654     mesh_access_parser_skip(state, 4);
655     return value;
656 }
657 
658 void mesh_access_parser_get_u128(mesh_access_parser_state_t * state, uint8_t * dest){
659     reverse_128( state->data, dest);
660     mesh_access_parser_skip(state, 16);
661 }
662 
663 void mesh_access_parser_get_label_uuid(mesh_access_parser_state_t * state, uint8_t * dest){
664     (void)memcpy(dest, state->data, 16);
665     mesh_access_parser_skip(state, 16);
666 }
667 
668 void mesh_access_parser_get_key(mesh_access_parser_state_t * state, uint8_t * dest){
669     (void)memcpy(dest, state->data, 16);
670     mesh_access_parser_skip(state, 16);
671 }
672 
673 uint32_t mesh_access_parser_get_model_identifier(mesh_access_parser_state_t * parser){
674     uint16_t vendor_id = BLUETOOTH_COMPANY_ID_BLUETOOTH_SIG_INC;
675     if (mesh_access_parser_available(parser) == 4){
676         vendor_id = mesh_access_parser_get_u16(parser);
677     }
678     uint16_t model_id = mesh_access_parser_get_u16(parser);
679     return mesh_model_get_model_identifier(vendor_id, model_id);
680 }
681 
682 uint32_t mesh_access_parser_get_sig_model_identifier(mesh_access_parser_state_t * parser){
683     uint16_t model_id = mesh_access_parser_get_u16(parser);
684     return mesh_model_get_model_identifier(BLUETOOTH_COMPANY_ID_BLUETOOTH_SIG_INC, model_id);
685 }
686 
687 uint32_t mesh_access_parser_get_vendor_model_identifier(mesh_access_parser_state_t * parser){
688     uint16_t vendor_id = mesh_access_parser_get_u16(parser);
689     uint16_t model_id  = mesh_access_parser_get_u16(parser);
690     return mesh_model_get_model_identifier(vendor_id, model_id);
691 }
692 
693 // Mesh Access Message Builder
694 
695 // message builder
696 
697 static int mesh_access_setup_opcode(uint8_t * buffer, uint32_t opcode){
698     if (opcode < 0x100){
699         buffer[0] = opcode;
700         return 1;
701     }
702     if (opcode < 0x10000){
703         big_endian_store_16(buffer, 0, opcode);
704         return 2;
705     }
706     buffer[0] = opcode >> 16;
707     little_endian_store_16(buffer, 1, opcode & 0xffff);
708     return 3;
709 }
710 
711 mesh_transport_pdu_t * mesh_access_transport_init(uint32_t opcode){
712     mesh_transport_pdu_t * pdu = mesh_transport_pdu_get();
713     if (!pdu) return NULL;
714 
715     pdu->len  = mesh_access_setup_opcode(pdu->data, opcode);
716     pdu->ack_opcode = MESH_ACCESS_OPCODE_NOT_SET;
717     return pdu;
718 }
719 
720 void mesh_access_transport_add_uint8(mesh_transport_pdu_t * pdu, uint8_t value){
721     pdu->data[pdu->len++] = value;
722 }
723 
724 void mesh_access_transport_add_uint16(mesh_transport_pdu_t * pdu, uint16_t value){
725     little_endian_store_16(pdu->data, pdu->len, value);
726     pdu->len += 2;
727 }
728 
729 void mesh_access_transport_add_uint24(mesh_transport_pdu_t * pdu, uint32_t value){
730     little_endian_store_24(pdu->data, pdu->len, value);
731     pdu->len += 3;
732 }
733 
734 void mesh_access_transport_add_uint32(mesh_transport_pdu_t * pdu, uint32_t value){
735     little_endian_store_32(pdu->data, pdu->len, value);
736     pdu->len += 4;
737 }
738 
739 void mesh_access_transport_add_label_uuid(mesh_transport_pdu_t * pdu, uint8_t * value){
740     (void)memcpy(value, pdu->data, 16);
741     pdu->len += 16;
742 }
743 
744 void mesh_access_transport_add_model_identifier(mesh_transport_pdu_t * pdu, uint32_t model_identifier){
745     if (!mesh_model_is_bluetooth_sig(model_identifier)){
746         mesh_access_transport_add_uint16( pdu, mesh_model_get_vendor_id(model_identifier) );
747     }
748     mesh_access_transport_add_uint16( pdu, mesh_model_get_model_id(model_identifier) );
749 }
750 
751 // mesh_message_t builder
752 mesh_segmented_pdu_t * mesh_access_message_init(uint32_t opcode, bool segmented, uint8_t num_segments){
753     btstack_assert(num_segments > 0);
754     btstack_assert(segmented || (num_segments == 1));
755 
756     mesh_segmented_pdu_t * pdu = mesh_message_pdu_get();
757     if (!pdu) return NULL;
758 
759     // TODO: handle segmented messages
760     btstack_assert(segmented == false);
761 
762     // use mesh_network_t as before
763     mesh_network_pdu_t * segment = mesh_network_pdu_get();
764     if (segment == NULL){
765         mesh_message_pdu_free(pdu);
766         return NULL;
767     }
768     btstack_linked_list_add(&pdu->segments, (btstack_linked_item_t *) segment);
769 
770     pdu->len = mesh_access_setup_opcode(&segment->data[10], opcode) + 10;
771     pdu->ack_opcode = MESH_ACCESS_OPCODE_NOT_SET;
772     return pdu;
773 }
774 
775 void mesh_access_message_add_uint8(mesh_segmented_pdu_t * pdu, uint8_t value){
776     // TODO: handle segmented messages
777     mesh_network_pdu_t * segment = (mesh_network_pdu_t *) btstack_linked_list_get_first_item(&pdu->segments);
778     segment->data[pdu->len++] = value;
779 }
780 
781 void mesh_access_message_add_uint16(mesh_segmented_pdu_t * pdu, uint16_t value){
782     // TODO: handle segmented messages
783     mesh_network_pdu_t * segment = (mesh_network_pdu_t *) btstack_linked_list_get_first_item(&pdu->segments);
784     little_endian_store_16(segment->data, pdu->len, value);
785     pdu->len += 2;
786 }
787 
788 void mesh_access_message_add_uint24(mesh_segmented_pdu_t * pdu, uint16_t value){
789     // TODO: handle segmented messages
790     mesh_network_pdu_t * segment = (mesh_network_pdu_t *) btstack_linked_list_get_first_item(&pdu->segments);
791     little_endian_store_24(segment->data, pdu->len, value);
792     pdu->len += 3;
793 }
794 
795 void mesh_access_message_add_uint32(mesh_segmented_pdu_t * pdu, uint16_t value){
796     // TODO: handle segmented messages
797     mesh_network_pdu_t * segment = (mesh_network_pdu_t *) btstack_linked_list_get_first_item(&pdu->segments);
798     little_endian_store_32(segment->data, pdu->len, value);
799     pdu->len += 4;
800 }
801 
802 void mesh_access_message_add_model_identifier(mesh_segmented_pdu_t * pdu, uint32_t model_identifier){
803     if (mesh_model_is_bluetooth_sig(model_identifier)){
804         mesh_access_message_add_uint16( pdu, mesh_model_get_model_id(model_identifier) );
805     } else {
806         mesh_access_message_add_uint32( pdu, model_identifier );
807     }
808 }
809 
810 // access message template
811 mesh_segmented_pdu_t * mesh_access_setup_message(bool segmented, const mesh_access_message_t *message_template, ...){
812     btstack_assert(segmented == false);
813 
814     // TODO: handle segmented messages
815     mesh_segmented_pdu_t * message_pdu = mesh_access_message_init(message_template->opcode, segmented, 1);
816     if (!message_pdu) return NULL;
817 
818     va_list argptr;
819     va_start(argptr, message_template);
820 
821     // add params
822     const char * format = message_template->format;
823     uint16_t word;
824     uint32_t longword;
825     while (*format){
826         switch (*format){
827             case '1':
828                 word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
829                 mesh_access_message_add_uint8( message_pdu, word);
830                 break;
831             case '2':
832                 word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
833                 mesh_access_message_add_uint16( message_pdu, word);
834                 break;
835             case '3':
836                 longword = va_arg(argptr, uint32_t);
837                 mesh_access_message_add_uint24( message_pdu, longword);
838                 break;
839             case '4':
840                 longword = va_arg(argptr, uint32_t);
841                 mesh_access_message_add_uint32( message_pdu, longword);
842                 mesh_access_message_add_uint32( message_pdu, longword);
843                 break;
844             case 'm':
845                 longword = va_arg(argptr, uint32_t);
846                 mesh_access_message_add_model_identifier( message_pdu, longword);
847                 break;
848             default:
849                 log_error("Unsupported mesh message format specifier '%c", *format);
850                 break;
851         }
852         format++;
853     }
854 
855     va_end(argptr);
856 
857     return message_pdu;
858 }
859 
860 mesh_transport_pdu_t * mesh_access_setup_segmented_message(const mesh_access_message_t *message_template, ...){
861     mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init(message_template->opcode);
862     if (!transport_pdu) return NULL;
863 
864     va_list argptr;
865     va_start(argptr, message_template);
866 
867     // add params
868     const char * format = message_template->format;
869     uint16_t word;
870     uint32_t longword;
871     uint8_t * ptr;
872     while (*format){
873         switch (*format++){
874             case '1':
875                 word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
876                 mesh_access_transport_add_uint8( transport_pdu, word);
877                 break;
878             case '2':
879                 word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
880                 mesh_access_transport_add_uint16( transport_pdu, word);
881                 break;
882             case '3':
883                 longword = va_arg(argptr, uint32_t);
884                 mesh_access_transport_add_uint24( transport_pdu, longword);
885                 break;
886             case '4':
887                 longword = va_arg(argptr, uint32_t);
888                 mesh_access_transport_add_uint32( transport_pdu, longword);
889                 break;
890             case 'P': // 16 byte, eg LabelUUID, in network endianess
891                 ptr = va_arg(argptr, uint8_t *);
892                 mesh_access_transport_add_label_uuid( transport_pdu, ptr);
893                 break;
894             case 'm':
895                 longword = va_arg(argptr, uint32_t);
896                 mesh_access_transport_add_model_identifier( transport_pdu, longword);
897                 break;
898             default:
899                 break;
900         }
901     }
902 
903     va_end(argptr);
904 
905     return transport_pdu;
906 }
907 
908 
909 static const mesh_operation_t * mesh_model_lookup_operation_by_opcode(mesh_model_t * model, uint32_t opcode){
910     // find opcode in table
911     const mesh_operation_t * operation = model->operations;
912     if (operation == NULL) return NULL;
913     for ( ; operation->handler != NULL ; operation++){
914         if (operation->opcode != opcode) continue;
915         return operation;
916     }
917     return NULL;
918 }
919 
920 static const mesh_operation_t * mesh_model_lookup_operation(mesh_model_t * model, mesh_pdu_t * pdu){
921 
922     uint32_t opcode = 0;
923     uint16_t opcode_size = 0;
924     int ok = mesh_access_pdu_get_opcode( pdu, &opcode, &opcode_size);
925     if (!ok) return NULL;
926 
927     uint16_t len = mesh_pdu_len(pdu);
928 
929     // find opcode in table
930     const mesh_operation_t * operation = model->operations;
931     if (operation == NULL) return NULL;
932     for ( ; operation->handler != NULL ; operation++){
933         if (operation->opcode != opcode) continue;
934         if ((opcode_size + operation->minimum_length) > len) continue;
935         return operation;
936     }
937     return NULL;
938 }
939 
940 static int mesh_access_validate_appkey_index(mesh_model_t * model, uint16_t appkey_index){
941     // DeviceKey is valid for all models
942     if (appkey_index == MESH_DEVICE_KEY_INDEX) return 1;
943     // check if AppKey that is bound to this particular model
944     return mesh_model_contains_appkey(model, appkey_index);
945 }
946 
947 // decrease use count and report as free if done
948 void mesh_access_message_processed(mesh_pdu_t * pdu){
949     if (mesh_access_received_pdu_refcount > 0){
950         mesh_access_received_pdu_refcount--;
951     }
952     if (mesh_access_received_pdu_refcount == 0){
953         mesh_upper_transport_message_processed_by_higher_layer(pdu);
954     }
955 }
956 
957 static void mesh_access_message_process_handler(mesh_pdu_t * pdu){
958 
959     // init use count
960     mesh_access_received_pdu_refcount = 1;
961 
962     // get opcode and size
963     uint32_t opcode = 0;
964     uint16_t opcode_size = 0;
965 
966     int ok = mesh_access_pdu_get_opcode( pdu, &opcode, &opcode_size);
967     if (!ok) {
968         mesh_access_message_processed(pdu);
969         return;
970     }
971 
972     uint16_t len = mesh_pdu_len(pdu);
973     printf("MESH Access Message, Opcode = %x: ", opcode);
974     printf_hexdump(mesh_pdu_data(pdu), len);
975 
976     uint16_t src = mesh_pdu_src(pdu);
977     uint16_t dst = mesh_pdu_dst(pdu);
978     uint16_t appkey_index = mesh_pdu_appkey_index(pdu);
979     if (mesh_network_address_unicast(dst)){
980         // loookup element by unicast address
981         mesh_element_t * element = mesh_node_element_for_unicast_address(dst);
982         if (element != NULL){
983             // iterate over models, look for operation
984             mesh_model_iterator_t model_it;
985             mesh_model_iterator_init(&model_it, element);
986             while (mesh_model_iterator_has_next(&model_it)){
987                 mesh_model_t * model = mesh_model_iterator_next(&model_it);
988                 // find opcode in table
989                 const mesh_operation_t * operation = mesh_model_lookup_operation(model, pdu);
990                 if (operation == NULL) continue;
991                 if (mesh_access_validate_appkey_index(model, appkey_index) == 0) continue;
992                 mesh_access_acknowledged_received(src, opcode);
993                 mesh_access_received_pdu_refcount++;
994                 operation->handler(model, pdu);
995             }
996         }
997     }
998     else if (mesh_network_address_group(dst)){
999 
1000         // handle fixed group address
1001         if (dst >= 0xff00){
1002             int deliver_to_primary_element = 1;
1003             switch (dst){
1004                 case MESH_ADDRESS_ALL_PROXIES:
1005                     if (mesh_foundation_gatt_proxy_get() == 1){
1006                         deliver_to_primary_element = 1;
1007                     }
1008                     break;
1009                 case MESH_ADDRESS_ALL_FRIENDS:
1010                     // TODO: not implemented
1011                     break;
1012                 case MESH_ADDRESS_ALL_RELAYS:
1013                     if (mesh_foundation_relay_get() == 1){
1014                         deliver_to_primary_element = 1;
1015                     }
1016                     break;
1017                 case MESH_ADDRESS_ALL_NODES:
1018                     deliver_to_primary_element = 1;
1019                     break;
1020                 default:
1021                     break;
1022             }
1023             if (deliver_to_primary_element){
1024                 mesh_model_iterator_t model_it;
1025                 mesh_model_iterator_init(&model_it, mesh_node_get_primary_element());
1026                 while (mesh_model_iterator_has_next(&model_it)){
1027                     mesh_model_t * model = mesh_model_iterator_next(&model_it);
1028                     // find opcode in table
1029                     const mesh_operation_t * operation = mesh_model_lookup_operation(model, pdu);
1030                     if (operation == NULL) continue;
1031                     if (mesh_access_validate_appkey_index(model, appkey_index) == 0) continue;
1032                     mesh_access_acknowledged_received(src, opcode);
1033                     mesh_access_received_pdu_refcount++;
1034                     operation->handler(model, pdu);
1035                 }
1036             }
1037         }
1038         else {
1039             // iterate over all elements / models, check subscription list
1040             mesh_element_iterator_t it;
1041             mesh_element_iterator_init(&it);
1042             while (mesh_element_iterator_has_next(&it)){
1043                 mesh_element_t * element = (mesh_element_t *) mesh_element_iterator_next(&it);
1044                 mesh_model_iterator_t model_it;
1045                 mesh_model_iterator_init(&model_it, element);
1046                 while (mesh_model_iterator_has_next(&model_it)){
1047                     mesh_model_t * model = mesh_model_iterator_next(&model_it);
1048                     if (mesh_model_contains_subscription(model, dst)){
1049                         // find opcode in table
1050                         const mesh_operation_t * operation = mesh_model_lookup_operation(model, pdu);
1051                         if (operation == NULL) continue;
1052                         if (mesh_access_validate_appkey_index(model, appkey_index) == 0) continue;
1053                         mesh_access_acknowledged_received(src, opcode);
1054                         mesh_access_received_pdu_refcount++;
1055                         operation->handler(model, pdu);
1056                     }
1057                 }
1058             }
1059         }
1060     }
1061 
1062     // we're done
1063     mesh_access_message_processed(pdu);
1064 }
1065 
1066 // Mesh Model Publication
1067 static btstack_timer_source_t mesh_access_publication_timer;
1068 
1069 static uint32_t mesh_model_publication_retransmit_count(uint8_t retransmit){
1070     return retransmit & 0x07u;
1071 }
1072 
1073 static uint32_t mesh_model_publication_retransmission_period_ms(uint8_t retransmit){
1074     return ((uint32_t)((retransmit >> 3) + 1)) * 50;
1075 }
1076 
1077 static void mesh_model_publication_setup_publication(mesh_publication_model_t * publication_model, uint32_t now){
1078 
1079     // set retransmit counter
1080     publication_model->retransmit_count = mesh_model_publication_retransmit_count(publication_model->retransmit);
1081 
1082     // schedule next publication or retransmission
1083     uint32_t publication_period_ms = mesh_access_time_gdtt2ms(publication_model->period) >> publication_model->period_divisor;
1084 
1085     // set next publication
1086     if (publication_period_ms != 0){
1087         publication_model->next_publication_ms = now + publication_period_ms;
1088         publication_model->state = MESH_MODEL_PUBLICATION_STATE_W4_PUBLICATION_MS;
1089     } else {
1090         publication_model->state = MESH_MODEL_PUBLICATION_STATE_IDLE;
1091     }
1092 }
1093 
1094 // assumes retransmit_count is valid
1095 static void mesh_model_publication_setup_retransmission(mesh_publication_model_t * publication_model, uint32_t now){
1096     uint32_t publication_period_ms = mesh_access_time_gdtt2ms(publication_model->period) >> publication_model->period_divisor;
1097 
1098     // retransmission done
1099     if (publication_model->retransmit_count == 0) {
1100         // wait for next main event if periodic and retransmission complete
1101         if (publication_period_ms != 0){
1102             publication_model->state = MESH_MODEL_PUBLICATION_STATE_W4_PUBLICATION_MS;
1103         } else {
1104             publication_model->state = MESH_MODEL_PUBLICATION_STATE_IDLE;
1105         }
1106         return;
1107     }
1108 
1109     // calc next retransmit time
1110     uint32_t retransmission_period_ms = mesh_model_publication_retransmission_period_ms(publication_model->retransmit) >> publication_model->period_divisor;
1111     uint32_t retransmission_ms = now + retransmission_period_ms;
1112 
1113     // check next publication timeout is before next retransmission
1114     if (publication_period_ms != 0){
1115         if (btstack_time_delta(retransmission_ms, publication_model->next_publication_ms) > 0) return;
1116     }
1117 
1118     // schedule next retransmission
1119     publication_model->next_retransmit_ms = retransmission_ms;
1120     publication_model->state = MESH_MODEL_PUBLICATION_STATE_W4_RETRANSMIT_MS;
1121 }
1122 
1123 static void mesh_model_publication_publish_now_model(mesh_model_t * mesh_model){
1124     mesh_publication_model_t * publication_model = mesh_model->publication_model;
1125     if (publication_model == NULL) return;
1126     if (publication_model->publish_state_fn == NULL) return;
1127     uint16_t dest = publication_model->address;
1128     if (dest == MESH_ADDRESS_UNSASSIGNED) return;
1129     uint16_t appkey_index = publication_model->appkey_index;
1130     mesh_transport_key_t * app_key = mesh_transport_key_get(appkey_index);
1131     if (app_key == NULL) return;
1132 
1133     // compose message
1134     mesh_pdu_t * pdu = (*publication_model->publish_state_fn)(mesh_model);
1135     if (pdu == NULL) return;
1136 
1137     // handle ttl = default
1138     uint8_t ttl = publication_model->ttl;
1139     if (ttl == 0xff){
1140         ttl = mesh_foundation_default_ttl_get();
1141     }
1142 
1143     mesh_upper_transport_setup_access_pdu_header(pdu, app_key->netkey_index, appkey_index, ttl, mesh_access_get_element_address(mesh_model), dest, 0);
1144     mesh_access_send_unacknowledged_pdu(pdu);
1145 }
1146 
1147 static void mesh_model_publication_run(btstack_timer_source_t * ts){
1148 
1149     uint32_t now = btstack_run_loop_get_time_ms();
1150 
1151     // iterate over elements and models and handle time-based transitions
1152     mesh_element_iterator_t element_it;
1153     mesh_element_iterator_init(&element_it);
1154     while (mesh_element_iterator_has_next(&element_it)){
1155         mesh_element_t * element = mesh_element_iterator_next(&element_it);
1156         mesh_model_iterator_t model_it;
1157         mesh_model_iterator_init(&model_it, element);
1158         while (mesh_model_iterator_has_next(&model_it)){
1159             mesh_model_t * mesh_model = mesh_model_iterator_next(&model_it);
1160             mesh_publication_model_t * publication_model = mesh_model->publication_model;
1161             if (publication_model == NULL) continue;
1162 
1163             // check if either timer fired
1164             switch (publication_model->state){
1165                 case MESH_MODEL_PUBLICATION_STATE_W4_PUBLICATION_MS:
1166                     if (btstack_time_delta(publication_model->next_publication_ms, now) > 0) break;
1167                     publication_model->state = MESH_MODEL_PUBLICATION_STATE_PUBLICATION_READY;
1168                     break;
1169                 case MESH_MODEL_PUBLICATION_STATE_W4_RETRANSMIT_MS:
1170                     if (btstack_time_delta(publication_model->next_retransmit_ms, now) > 0) break;
1171                     publication_model->state = MESH_MODEL_PUBLICATION_STATE_RETRANSMIT_READY;
1172                     break;
1173                 default:
1174                     break;
1175             }
1176 
1177             switch (publication_model->state){
1178                 case MESH_MODEL_PUBLICATION_STATE_PUBLICATION_READY:
1179                     // schedule next publication and retransmission
1180                     mesh_model_publication_setup_publication(publication_model, now);
1181                     mesh_model_publication_setup_retransmission(publication_model, now);
1182                     mesh_model_publication_publish_now_model(mesh_model);
1183                     break;
1184                 case MESH_MODEL_PUBLICATION_STATE_RETRANSMIT_READY:
1185                     // schedule next retransmission
1186                     publication_model->retransmit_count--;
1187                     mesh_model_publication_setup_retransmission(publication_model, now);
1188                     mesh_model_publication_publish_now_model(mesh_model);
1189                     break;
1190                 default:
1191                     break;
1192             }
1193         }
1194     }
1195 
1196     int32_t next_timeout_ms = 0;
1197     mesh_element_iterator_init(&element_it);
1198     while (mesh_element_iterator_has_next(&element_it)){
1199         mesh_element_t * element = mesh_element_iterator_next(&element_it);
1200         mesh_model_iterator_t model_it;
1201         mesh_model_iterator_init(&model_it, element);
1202         while (mesh_model_iterator_has_next(&model_it)){
1203             mesh_model_t * mesh_model = mesh_model_iterator_next(&model_it);
1204             mesh_publication_model_t * publication_model = mesh_model->publication_model;
1205             if (publication_model == NULL) continue;
1206 
1207             // schedule next
1208             int32_t timeout_delta_ms;
1209             switch (publication_model->state){
1210                 case MESH_MODEL_PUBLICATION_STATE_W4_PUBLICATION_MS:
1211                     timeout_delta_ms = btstack_time_delta(publication_model->next_publication_ms, now);
1212                     if (next_timeout_ms == 0 || timeout_delta_ms < next_timeout_ms){
1213                         next_timeout_ms = timeout_delta_ms;
1214                     }
1215                     break;
1216                 case MESH_MODEL_PUBLICATION_STATE_W4_RETRANSMIT_MS:
1217                     timeout_delta_ms = btstack_time_delta(publication_model->next_retransmit_ms, now);
1218                     if (next_timeout_ms == 0 || timeout_delta_ms < next_timeout_ms){
1219                         next_timeout_ms = timeout_delta_ms;
1220                     }
1221                     break;
1222                 default:
1223                     break;
1224             }
1225         }
1226     }
1227 
1228     // remove current timer if active
1229     if (ts == NULL){
1230         btstack_run_loop_remove_timer(&mesh_access_publication_timer);
1231 
1232     }
1233 
1234     // new timeout?
1235     if (next_timeout_ms == 0) return;
1236 
1237     // set timer
1238     btstack_run_loop_set_timer(&mesh_access_publication_timer, next_timeout_ms);
1239     btstack_run_loop_set_timer_handler(&mesh_access_publication_timer, mesh_model_publication_run);
1240     btstack_run_loop_add_timer(&mesh_access_publication_timer);
1241 }
1242 
1243 void mesh_model_publication_start(mesh_model_t * mesh_model){
1244     mesh_publication_model_t * publication_model = mesh_model->publication_model;
1245     if (publication_model == NULL) return;
1246 
1247     // publish right away
1248     publication_model->state = MESH_MODEL_PUBLICATION_STATE_PUBLICATION_READY;
1249     mesh_model_publication_run(NULL);
1250 }
1251 
1252 void mesh_model_publication_stop(mesh_model_t * mesh_model){
1253     mesh_publication_model_t * publication_model = mesh_model->publication_model;
1254     if (publication_model == NULL) return;
1255 
1256     // reset state
1257     publication_model->state = MESH_MODEL_PUBLICATION_STATE_IDLE;
1258 }
1259 
1260 void mesh_access_state_changed(mesh_model_t * mesh_model){
1261     mesh_publication_model_t * publication_model = mesh_model->publication_model;
1262     if (publication_model == NULL) return;
1263     publication_model->state = MESH_MODEL_PUBLICATION_STATE_PUBLICATION_READY;
1264     mesh_model_publication_run(NULL);
1265 }
1266 
1267