xref: /btstack/src/mesh/pb_adv.c (revision 77ba3d3f9fd2c90e975cda31e3c706784e95d43a)
1*77ba3d3fSMatthias Ringwald /*
2*77ba3d3fSMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3*77ba3d3fSMatthias Ringwald  *
4*77ba3d3fSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*77ba3d3fSMatthias Ringwald  * modification, are permitted provided that the following conditions
6*77ba3d3fSMatthias Ringwald  * are met:
7*77ba3d3fSMatthias Ringwald  *
8*77ba3d3fSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*77ba3d3fSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*77ba3d3fSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*77ba3d3fSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*77ba3d3fSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*77ba3d3fSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*77ba3d3fSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*77ba3d3fSMatthias Ringwald  *    from this software without specific prior written permission.
16*77ba3d3fSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*77ba3d3fSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*77ba3d3fSMatthias Ringwald  *    monetary gain.
19*77ba3d3fSMatthias Ringwald  *
20*77ba3d3fSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*77ba3d3fSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*77ba3d3fSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*77ba3d3fSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*77ba3d3fSMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*77ba3d3fSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*77ba3d3fSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*77ba3d3fSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*77ba3d3fSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*77ba3d3fSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*77ba3d3fSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*77ba3d3fSMatthias Ringwald  * SUCH DAMAGE.
32*77ba3d3fSMatthias Ringwald  *
33*77ba3d3fSMatthias Ringwald  * Please inquire about commercial licensing options at
34*77ba3d3fSMatthias Ringwald  * [email protected]
35*77ba3d3fSMatthias Ringwald  *
36*77ba3d3fSMatthias Ringwald  */
37*77ba3d3fSMatthias Ringwald 
38*77ba3d3fSMatthias Ringwald #define __BTSTACK_FILE__ "pb_adv.c"
39*77ba3d3fSMatthias Ringwald 
40*77ba3d3fSMatthias Ringwald #include <stdint.h>
41*77ba3d3fSMatthias Ringwald #include <stdio.h>
42*77ba3d3fSMatthias Ringwald #include <stdlib.h>
43*77ba3d3fSMatthias Ringwald #include <string.h>
44*77ba3d3fSMatthias Ringwald #include "mesh/adv_bearer.h"
45*77ba3d3fSMatthias Ringwald #include "mesh/beacon.h"
46*77ba3d3fSMatthias Ringwald #include "provisioning.h"
47*77ba3d3fSMatthias Ringwald #include "btstack_util.h"
48*77ba3d3fSMatthias Ringwald #include "btstack_debug.h"
49*77ba3d3fSMatthias Ringwald #include "btstack_event.h"
50*77ba3d3fSMatthias Ringwald 
51*77ba3d3fSMatthias Ringwald #define PB_ADV_LINK_OPEN_RETRANSMIT_MS 1000
52*77ba3d3fSMatthias Ringwald 
53*77ba3d3fSMatthias Ringwald static void pb_adv_run(void);
54*77ba3d3fSMatthias Ringwald 
55*77ba3d3fSMatthias Ringwald /* taps: 32 31 29 1; characteristic polynomial: x^32 + x^31 + x^29 + x + 1 */
56*77ba3d3fSMatthias Ringwald #define LFSR(a) ((a >> 1) ^ (uint32_t)((0 - (a & 1u)) & 0xd0000001u))
57*77ba3d3fSMatthias Ringwald 
58*77ba3d3fSMatthias Ringwald // PB-ADV - Provisioning Bearer using Advertisement Bearer
59*77ba3d3fSMatthias Ringwald 
60*77ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_LINK_OPEN              0x00
61*77ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_LINK_ACK               0x01
62*77ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_LINK_CLOSE             0x02
63*77ba3d3fSMatthias Ringwald 
64*77ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_TRANSACTION_TIMEOUT_MS 30000
65*77ba3d3fSMatthias Ringwald 
66*77ba3d3fSMatthias Ringwald #define MESH_PB_ADV_MAX_PDU_SIZE  100
67*77ba3d3fSMatthias Ringwald #define MESH_PB_ADV_MAX_SEGMENTS    8
68*77ba3d3fSMatthias Ringwald #define MESH_PB_ADV_START_PAYLOAD  20
69*77ba3d3fSMatthias Ringwald #define MESH_PB_ADV_CONT_PAYLOAD   23
70*77ba3d3fSMatthias Ringwald 
71*77ba3d3fSMatthias Ringwald typedef enum mesh_gpcf_format {
72*77ba3d3fSMatthias Ringwald     MESH_GPCF_TRANSACTION_START = 0,
73*77ba3d3fSMatthias Ringwald     MESH_GPCF_TRANSACTION_ACK,
74*77ba3d3fSMatthias Ringwald     MESH_GPCF_TRANSACTION_CONT,
75*77ba3d3fSMatthias Ringwald     MESH_GPCF_PROV_BEARER_CONTROL,
76*77ba3d3fSMatthias Ringwald } mesh_gpcf_format_t;
77*77ba3d3fSMatthias Ringwald 
78*77ba3d3fSMatthias Ringwald typedef enum {
79*77ba3d3fSMatthias Ringwald     LINK_STATE_W4_OPEN,
80*77ba3d3fSMatthias Ringwald     LINK_STATE_W2_SEND_ACK,
81*77ba3d3fSMatthias Ringwald     LINK_STATE_W4_ACK,
82*77ba3d3fSMatthias Ringwald     LINK_STATE_OPEN,
83*77ba3d3fSMatthias Ringwald     LINK_STATE_CLOSING,
84*77ba3d3fSMatthias Ringwald } link_state_t;
85*77ba3d3fSMatthias Ringwald static link_state_t link_state;
86*77ba3d3fSMatthias Ringwald 
87*77ba3d3fSMatthias Ringwald static const uint8_t * pb_adv_own_device_uuid;
88*77ba3d3fSMatthias Ringwald 
89*77ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
90*77ba3d3fSMatthias Ringwald static const uint8_t * pb_adv_peer_device_uuid;
91*77ba3d3fSMatthias Ringwald #endif
92*77ba3d3fSMatthias Ringwald 
93*77ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_buffer[MESH_PB_ADV_MAX_PDU_SIZE];   // TODO: how large are prov messages?
94*77ba3d3fSMatthias Ringwald 
95*77ba3d3fSMatthias Ringwald // single adv link
96*77ba3d3fSMatthias Ringwald static uint16_t pb_adv_cid = 1;
97*77ba3d3fSMatthias Ringwald static uint8_t  pb_adv_provisioner_role;
98*77ba3d3fSMatthias Ringwald 
99*77ba3d3fSMatthias Ringwald // link state
100*77ba3d3fSMatthias Ringwald static uint32_t pb_adv_link_id;
101*77ba3d3fSMatthias Ringwald static uint8_t  pb_adv_link_close_reason;
102*77ba3d3fSMatthias Ringwald static uint8_t  pb_adv_link_close_countdown;
103*77ba3d3fSMatthias Ringwald 
104*77ba3d3fSMatthias Ringwald // random delay for outgoing packets
105*77ba3d3fSMatthias Ringwald static uint32_t pb_adv_lfsr;
106*77ba3d3fSMatthias Ringwald static uint8_t                pb_adv_random_delay_active;
107*77ba3d3fSMatthias Ringwald static btstack_timer_source_t pb_adv_random_delay_timer;
108*77ba3d3fSMatthias Ringwald 
109*77ba3d3fSMatthias Ringwald // incoming message
110*77ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_transaction_nr_prev;
111*77ba3d3fSMatthias Ringwald static uint16_t pb_adv_msg_in_len;   //
112*77ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_fcs;
113*77ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_last_segment;
114*77ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_segments_missing; // bitfield for segmentes 1-n
115*77ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_transaction_nr;
116*77ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_send_ack;
117*77ba3d3fSMatthias Ringwald 
118*77ba3d3fSMatthias Ringwald // oputgoing message
119*77ba3d3fSMatthias Ringwald static uint8_t         pb_adv_msg_out_active;
120*77ba3d3fSMatthias Ringwald static uint8_t         pb_adv_msg_out_transaction_nr;
121*77ba3d3fSMatthias Ringwald static uint8_t         pb_adv_msg_out_completed_transaction_nr;
122*77ba3d3fSMatthias Ringwald static uint16_t        pb_adv_msg_out_len;
123*77ba3d3fSMatthias Ringwald static uint16_t        pb_adv_msg_out_pos;
124*77ba3d3fSMatthias Ringwald static uint8_t         pb_adv_msg_out_seg;
125*77ba3d3fSMatthias Ringwald static uint32_t        pb_adv_msg_out_start;
126*77ba3d3fSMatthias Ringwald static const uint8_t * pb_adv_msg_out_buffer;
127*77ba3d3fSMatthias Ringwald 
128*77ba3d3fSMatthias Ringwald static btstack_packet_handler_t pb_adv_packet_handler;
129*77ba3d3fSMatthias Ringwald 
130*77ba3d3fSMatthias Ringwald // poor man's random number generator
131*77ba3d3fSMatthias Ringwald static uint32_t pb_adv_random(void){
132*77ba3d3fSMatthias Ringwald     pb_adv_lfsr = LFSR(pb_adv_lfsr);
133*77ba3d3fSMatthias Ringwald     return pb_adv_lfsr;
134*77ba3d3fSMatthias Ringwald }
135*77ba3d3fSMatthias Ringwald 
136*77ba3d3fSMatthias Ringwald static void pb_adv_emit_pdu_sent(uint8_t status){
137*77ba3d3fSMatthias Ringwald     uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status};
138*77ba3d3fSMatthias Ringwald     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
139*77ba3d3fSMatthias Ringwald }
140*77ba3d3fSMatthias Ringwald 
141*77ba3d3fSMatthias Ringwald static void pb_adv_emit_link_open(uint8_t status, uint16_t pb_adv_cid){
142*77ba3d3fSMatthias Ringwald     uint8_t event[7] = { HCI_EVENT_MESH_META, 5, MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN, status};
143*77ba3d3fSMatthias Ringwald     little_endian_store_16(event, 4, pb_adv_cid);
144*77ba3d3fSMatthias Ringwald     event[6] = PB_TYPE_ADV;
145*77ba3d3fSMatthias Ringwald     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
146*77ba3d3fSMatthias Ringwald }
147*77ba3d3fSMatthias Ringwald 
148*77ba3d3fSMatthias Ringwald static void pb_adv_emit_link_close(uint16_t pb_adv_cid, uint8_t reason){
149*77ba3d3fSMatthias Ringwald     uint8_t event[5] = { HCI_EVENT_MESH_META, 3, MESH_SUBEVENT_PB_TRANSPORT_LINK_CLOSED};
150*77ba3d3fSMatthias Ringwald     little_endian_store_16(event, 4, pb_adv_cid);
151*77ba3d3fSMatthias Ringwald     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
152*77ba3d3fSMatthias Ringwald }
153*77ba3d3fSMatthias Ringwald 
154*77ba3d3fSMatthias Ringwald static void pb_adv_handle_bearer_control(uint32_t link_id, uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
155*77ba3d3fSMatthias Ringwald     uint8_t bearer_opcode = pdu[0] >> 2;
156*77ba3d3fSMatthias Ringwald     uint8_t reason;
157*77ba3d3fSMatthias Ringwald     switch (bearer_opcode){
158*77ba3d3fSMatthias Ringwald         case MESH_GENERIC_PROVISIONING_LINK_OPEN: // Open a session on a bearer with a device
159*77ba3d3fSMatthias Ringwald             // does it match our device_uuid?
160*77ba3d3fSMatthias Ringwald             if (!pb_adv_own_device_uuid) break;
161*77ba3d3fSMatthias Ringwald             if (memcmp(&pdu[1], pb_adv_own_device_uuid, 16) != 0) break;
162*77ba3d3fSMatthias Ringwald             switch(link_state){
163*77ba3d3fSMatthias Ringwald                 case LINK_STATE_W4_OPEN:
164*77ba3d3fSMatthias Ringwald                     pb_adv_link_id = link_id;
165*77ba3d3fSMatthias Ringwald                     pb_adv_provisioner_role = 0;
166*77ba3d3fSMatthias Ringwald                     pb_adv_msg_in_transaction_nr = 0xff;  // first transaction nr will be 0x00
167*77ba3d3fSMatthias Ringwald                     pb_adv_msg_in_transaction_nr_prev = 0xff;
168*77ba3d3fSMatthias Ringwald                     log_info("link open, id %08x", pb_adv_link_id);
169*77ba3d3fSMatthias Ringwald                     printf("PB-ADV: Link Open %08x\n", pb_adv_link_id);
170*77ba3d3fSMatthias Ringwald                     link_state = LINK_STATE_W2_SEND_ACK;
171*77ba3d3fSMatthias Ringwald                     adv_bearer_request_can_send_now_for_pb_adv();
172*77ba3d3fSMatthias Ringwald                     pb_adv_emit_link_open(0, pb_adv_cid);
173*77ba3d3fSMatthias Ringwald                     break;
174*77ba3d3fSMatthias Ringwald                 case LINK_STATE_OPEN:
175*77ba3d3fSMatthias Ringwald                     if (pb_adv_link_id != link_id) break;
176*77ba3d3fSMatthias Ringwald                     log_info("link open, resend ACK");
177*77ba3d3fSMatthias Ringwald                     link_state = LINK_STATE_W2_SEND_ACK;
178*77ba3d3fSMatthias Ringwald                     adv_bearer_request_can_send_now_for_pb_adv();
179*77ba3d3fSMatthias Ringwald                     break;
180*77ba3d3fSMatthias Ringwald                 default:
181*77ba3d3fSMatthias Ringwald                     break;
182*77ba3d3fSMatthias Ringwald             }
183*77ba3d3fSMatthias Ringwald             break;
184*77ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
185*77ba3d3fSMatthias Ringwald         case MESH_GENERIC_PROVISIONING_LINK_ACK:   // Acknowledge a session on a bearer
186*77ba3d3fSMatthias Ringwald             if (link_state != LINK_STATE_W4_ACK) break;
187*77ba3d3fSMatthias Ringwald             link_state = LINK_STATE_OPEN;
188*77ba3d3fSMatthias Ringwald             pb_adv_msg_out_transaction_nr = 0;
189*77ba3d3fSMatthias Ringwald             pb_adv_msg_in_transaction_nr = 0x7f;    // first transaction nr will be 0x80
190*77ba3d3fSMatthias Ringwald             pb_adv_msg_in_transaction_nr_prev = 0x7f;
191*77ba3d3fSMatthias Ringwald             btstack_run_loop_remove_timer(&pb_adv_random_delay_timer);
192*77ba3d3fSMatthias Ringwald             log_info("link open, id %08x", pb_adv_link_id);
193*77ba3d3fSMatthias Ringwald             printf("PB-ADV: Link Open %08x\n", pb_adv_link_id);
194*77ba3d3fSMatthias Ringwald             pb_adv_emit_link_open(0, pb_adv_cid);
195*77ba3d3fSMatthias Ringwald             break;
196*77ba3d3fSMatthias Ringwald #endif
197*77ba3d3fSMatthias Ringwald         case MESH_GENERIC_PROVISIONING_LINK_CLOSE: // Close a session on a bearer
198*77ba3d3fSMatthias Ringwald             // does it match link id
199*77ba3d3fSMatthias Ringwald             if (link_id != pb_adv_link_id) break;
200*77ba3d3fSMatthias Ringwald             reason = pdu[1];
201*77ba3d3fSMatthias Ringwald             link_state = LINK_STATE_W4_OPEN;
202*77ba3d3fSMatthias Ringwald             log_info("link close, reason %x", reason);
203*77ba3d3fSMatthias Ringwald             pb_adv_emit_link_close(pb_adv_cid, reason);
204*77ba3d3fSMatthias Ringwald             break;
205*77ba3d3fSMatthias Ringwald         default:
206*77ba3d3fSMatthias Ringwald             log_info("BearerOpcode %x reserved for future use\n", bearer_opcode);
207*77ba3d3fSMatthias Ringwald             break;
208*77ba3d3fSMatthias Ringwald     }
209*77ba3d3fSMatthias Ringwald }
210*77ba3d3fSMatthias Ringwald 
211*77ba3d3fSMatthias Ringwald static void pb_adv_pdu_complete(void){
212*77ba3d3fSMatthias Ringwald 
213*77ba3d3fSMatthias Ringwald     // Verify FCS
214*77ba3d3fSMatthias Ringwald     uint8_t pdu_crc = btstack_crc8_calc((uint8_t*)pb_adv_msg_in_buffer, pb_adv_msg_in_len);
215*77ba3d3fSMatthias Ringwald     if (pdu_crc != pb_adv_msg_in_fcs){
216*77ba3d3fSMatthias Ringwald         printf("Incoming PDU: fcs %02x, calculated %02x -> drop packet\n", pb_adv_msg_in_fcs, btstack_crc8_calc(pb_adv_msg_in_buffer, pb_adv_msg_in_len));
217*77ba3d3fSMatthias Ringwald         return;
218*77ba3d3fSMatthias Ringwald     }
219*77ba3d3fSMatthias Ringwald 
220*77ba3d3fSMatthias Ringwald     printf("PB-ADV: %02x complete\n", pb_adv_msg_in_transaction_nr);
221*77ba3d3fSMatthias Ringwald 
222*77ba3d3fSMatthias Ringwald     // transaction complete
223*77ba3d3fSMatthias Ringwald     pb_adv_msg_in_transaction_nr_prev = pb_adv_msg_in_transaction_nr;
224*77ba3d3fSMatthias Ringwald     if (pb_adv_provisioner_role){
225*77ba3d3fSMatthias Ringwald         pb_adv_msg_in_transaction_nr = 0x7f;    // invalid
226*77ba3d3fSMatthias Ringwald     } else {
227*77ba3d3fSMatthias Ringwald         pb_adv_msg_in_transaction_nr = 0xff;    // invalid
228*77ba3d3fSMatthias Ringwald     }
229*77ba3d3fSMatthias Ringwald 
230*77ba3d3fSMatthias Ringwald     // Ack Transaction
231*77ba3d3fSMatthias Ringwald     pb_adv_msg_in_send_ack = 1;
232*77ba3d3fSMatthias Ringwald     pb_adv_run();
233*77ba3d3fSMatthias Ringwald 
234*77ba3d3fSMatthias Ringwald     // Forward to Provisioning
235*77ba3d3fSMatthias Ringwald     pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, pb_adv_msg_in_buffer, pb_adv_msg_in_len);
236*77ba3d3fSMatthias Ringwald }
237*77ba3d3fSMatthias Ringwald 
238*77ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_start(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
239*77ba3d3fSMatthias Ringwald 
240*77ba3d3fSMatthias Ringwald     // resend ack if packet from previous transaction received
241*77ba3d3fSMatthias Ringwald     if (transaction_nr != 0xff && transaction_nr == pb_adv_msg_in_transaction_nr_prev){
242*77ba3d3fSMatthias Ringwald         printf("PB_ADV: %02x transaction complete, resending ack \n", transaction_nr);
243*77ba3d3fSMatthias Ringwald         pb_adv_msg_in_send_ack = 1;
244*77ba3d3fSMatthias Ringwald         return;
245*77ba3d3fSMatthias Ringwald     }
246*77ba3d3fSMatthias Ringwald 
247*77ba3d3fSMatthias Ringwald     // new transaction?
248*77ba3d3fSMatthias Ringwald     if (transaction_nr != pb_adv_msg_in_transaction_nr){
249*77ba3d3fSMatthias Ringwald 
250*77ba3d3fSMatthias Ringwald         // check len
251*77ba3d3fSMatthias Ringwald         uint16_t msg_len = big_endian_read_16(pdu, 1);
252*77ba3d3fSMatthias Ringwald         if (msg_len > MESH_PB_ADV_MAX_PDU_SIZE){
253*77ba3d3fSMatthias Ringwald             // abort transaction
254*77ba3d3fSMatthias Ringwald             return;
255*77ba3d3fSMatthias Ringwald         }
256*77ba3d3fSMatthias Ringwald 
257*77ba3d3fSMatthias Ringwald         // check num segments
258*77ba3d3fSMatthias Ringwald         uint8_t last_segment = pdu[0] >> 2;
259*77ba3d3fSMatthias Ringwald         if (last_segment >= MESH_PB_ADV_MAX_SEGMENTS){
260*77ba3d3fSMatthias Ringwald             // abort transaction
261*77ba3d3fSMatthias Ringwald             return;
262*77ba3d3fSMatthias Ringwald         }
263*77ba3d3fSMatthias Ringwald 
264*77ba3d3fSMatthias Ringwald         printf("PB-ADV: %02x started\n", transaction_nr);
265*77ba3d3fSMatthias Ringwald 
266*77ba3d3fSMatthias Ringwald         pb_adv_msg_in_transaction_nr = transaction_nr;
267*77ba3d3fSMatthias Ringwald         pb_adv_msg_in_len            = msg_len;
268*77ba3d3fSMatthias Ringwald         pb_adv_msg_in_fcs            = pdu[3];
269*77ba3d3fSMatthias Ringwald         pb_adv_msg_in_last_segment   = last_segment;
270*77ba3d3fSMatthias Ringwald 
271*77ba3d3fSMatthias Ringwald         // set bits for  segments 1..n (segment 0 already received in this message)
272*77ba3d3fSMatthias Ringwald         pb_adv_msg_in_segments_missing = (1 << last_segment) - 1;
273*77ba3d3fSMatthias Ringwald 
274*77ba3d3fSMatthias Ringwald         // store payload
275*77ba3d3fSMatthias Ringwald         uint16_t payload_len = size - 4;
276*77ba3d3fSMatthias Ringwald         memcpy(pb_adv_msg_in_buffer, &pdu[4], payload_len);
277*77ba3d3fSMatthias Ringwald 
278*77ba3d3fSMatthias Ringwald         // complete?
279*77ba3d3fSMatthias Ringwald         if (pb_adv_msg_in_segments_missing == 0){
280*77ba3d3fSMatthias Ringwald             pb_adv_pdu_complete();
281*77ba3d3fSMatthias Ringwald         }
282*77ba3d3fSMatthias Ringwald     }
283*77ba3d3fSMatthias Ringwald }
284*77ba3d3fSMatthias Ringwald 
285*77ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_cont(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
286*77ba3d3fSMatthias Ringwald 
287*77ba3d3fSMatthias Ringwald     // check transaction nr
288*77ba3d3fSMatthias Ringwald     if (transaction_nr != 0xff && transaction_nr == pb_adv_msg_in_transaction_nr_prev){
289*77ba3d3fSMatthias Ringwald         printf("PB_ADV: %02x transaction complete, resending resending ack\n", transaction_nr);
290*77ba3d3fSMatthias Ringwald         pb_adv_msg_in_send_ack = 1;
291*77ba3d3fSMatthias Ringwald         return;
292*77ba3d3fSMatthias Ringwald     }
293*77ba3d3fSMatthias Ringwald 
294*77ba3d3fSMatthias Ringwald     if (transaction_nr != pb_adv_msg_in_transaction_nr){
295*77ba3d3fSMatthias Ringwald         printf("PB-ADV: %02x received msg for transaction nr %x\n", pb_adv_msg_in_transaction_nr, transaction_nr);
296*77ba3d3fSMatthias Ringwald         return;
297*77ba3d3fSMatthias Ringwald     }
298*77ba3d3fSMatthias Ringwald 
299*77ba3d3fSMatthias Ringwald     // validate seg nr
300*77ba3d3fSMatthias Ringwald     uint8_t seg = pdu[0] >> 2;
301*77ba3d3fSMatthias Ringwald     if (seg >= MESH_PB_ADV_MAX_SEGMENTS || seg == 0){
302*77ba3d3fSMatthias Ringwald         return;
303*77ba3d3fSMatthias Ringwald     }
304*77ba3d3fSMatthias Ringwald 
305*77ba3d3fSMatthias Ringwald     // check if segment already received
306*77ba3d3fSMatthias Ringwald     uint8_t seg_mask = 1 << (seg-1);
307*77ba3d3fSMatthias Ringwald     if ((pb_adv_msg_in_segments_missing & seg_mask) == 0){
308*77ba3d3fSMatthias Ringwald         printf("PB-ADV: %02x, segment %u already received\n", transaction_nr, seg);
309*77ba3d3fSMatthias Ringwald         return;
310*77ba3d3fSMatthias Ringwald     }
311*77ba3d3fSMatthias Ringwald     printf("PB-ADV: %02x, segment %u stored\n", transaction_nr, seg);
312*77ba3d3fSMatthias Ringwald 
313*77ba3d3fSMatthias Ringwald     // calculate offset and fragment size
314*77ba3d3fSMatthias Ringwald     uint16_t msg_pos = MESH_PB_ADV_START_PAYLOAD + (seg-1) * MESH_PB_ADV_CONT_PAYLOAD;
315*77ba3d3fSMatthias Ringwald     uint16_t fragment_size = size - 1;
316*77ba3d3fSMatthias Ringwald 
317*77ba3d3fSMatthias Ringwald     // check size if last segment
318*77ba3d3fSMatthias Ringwald     if (seg == pb_adv_msg_in_last_segment && (msg_pos + fragment_size) != pb_adv_msg_in_len){
319*77ba3d3fSMatthias Ringwald         // last segment has invalid size
320*77ba3d3fSMatthias Ringwald         return;
321*77ba3d3fSMatthias Ringwald     }
322*77ba3d3fSMatthias Ringwald 
323*77ba3d3fSMatthias Ringwald     // store segment and mark as received
324*77ba3d3fSMatthias Ringwald     memcpy(&pb_adv_msg_in_buffer[msg_pos], &pdu[1], fragment_size);
325*77ba3d3fSMatthias Ringwald     pb_adv_msg_in_segments_missing &= ~seg_mask;
326*77ba3d3fSMatthias Ringwald 
327*77ba3d3fSMatthias Ringwald      // last segment
328*77ba3d3fSMatthias Ringwald      if (pb_adv_msg_in_segments_missing == 0){
329*77ba3d3fSMatthias Ringwald         pb_adv_pdu_complete();
330*77ba3d3fSMatthias Ringwald     }
331*77ba3d3fSMatthias Ringwald }
332*77ba3d3fSMatthias Ringwald 
333*77ba3d3fSMatthias Ringwald static void pb_adv_outgoing_transation_complete(uint8_t status){
334*77ba3d3fSMatthias Ringwald     // stop sending
335*77ba3d3fSMatthias Ringwald     pb_adv_msg_out_active = 0;
336*77ba3d3fSMatthias Ringwald     // emit done
337*77ba3d3fSMatthias Ringwald     pb_adv_emit_pdu_sent(status);
338*77ba3d3fSMatthias Ringwald     // keep track of ack'ed transactions
339*77ba3d3fSMatthias Ringwald     pb_adv_msg_out_completed_transaction_nr = pb_adv_msg_out_transaction_nr;
340*77ba3d3fSMatthias Ringwald     // increment outgoing transaction nr
341*77ba3d3fSMatthias Ringwald     pb_adv_msg_out_transaction_nr++;
342*77ba3d3fSMatthias Ringwald     if (pb_adv_msg_out_transaction_nr == 0x00){
343*77ba3d3fSMatthias Ringwald         // Device role
344*77ba3d3fSMatthias Ringwald         pb_adv_msg_out_transaction_nr = 0x80;
345*77ba3d3fSMatthias Ringwald     }
346*77ba3d3fSMatthias Ringwald     if (pb_adv_msg_out_transaction_nr == 0x80){
347*77ba3d3fSMatthias Ringwald         // Provisioner role
348*77ba3d3fSMatthias Ringwald         pb_adv_msg_out_transaction_nr = 0x00;
349*77ba3d3fSMatthias Ringwald     }
350*77ba3d3fSMatthias Ringwald }
351*77ba3d3fSMatthias Ringwald 
352*77ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_ack(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
353*77ba3d3fSMatthias Ringwald     if (transaction_nr == pb_adv_msg_out_transaction_nr){
354*77ba3d3fSMatthias Ringwald         printf("PB-ADV: %02x ACK received\n", transaction_nr);
355*77ba3d3fSMatthias Ringwald         pb_adv_outgoing_transation_complete(ERROR_CODE_SUCCESS);
356*77ba3d3fSMatthias Ringwald     } else if (transaction_nr == pb_adv_msg_out_completed_transaction_nr){
357*77ba3d3fSMatthias Ringwald         // Transaction ack received again
358*77ba3d3fSMatthias Ringwald     } else {
359*77ba3d3fSMatthias Ringwald         printf("PB-ADV: %02x unexpected Transaction ACK %x recevied\n", pb_adv_msg_out_transaction_nr, transaction_nr);
360*77ba3d3fSMatthias Ringwald     }
361*77ba3d3fSMatthias Ringwald }
362*77ba3d3fSMatthias Ringwald 
363*77ba3d3fSMatthias Ringwald static int pb_adv_packet_to_send(void){
364*77ba3d3fSMatthias Ringwald     return pb_adv_msg_in_send_ack || pb_adv_msg_out_active || (link_state == LINK_STATE_W4_ACK);
365*77ba3d3fSMatthias Ringwald }
366*77ba3d3fSMatthias Ringwald 
367*77ba3d3fSMatthias Ringwald static void pb_adv_timer_handler(btstack_timer_source_t * ts){
368*77ba3d3fSMatthias Ringwald     pb_adv_random_delay_active = 0;
369*77ba3d3fSMatthias Ringwald     if (!pb_adv_packet_to_send()) return;
370*77ba3d3fSMatthias Ringwald     adv_bearer_request_can_send_now_for_pb_adv();
371*77ba3d3fSMatthias Ringwald }
372*77ba3d3fSMatthias Ringwald 
373*77ba3d3fSMatthias Ringwald static void pb_adv_run(void){
374*77ba3d3fSMatthias Ringwald     if (!pb_adv_packet_to_send()) return;
375*77ba3d3fSMatthias Ringwald     if (pb_adv_random_delay_active) return;
376*77ba3d3fSMatthias Ringwald 
377*77ba3d3fSMatthias Ringwald     // spec recommends 20-50 ms, we use 20-51 ms
378*77ba3d3fSMatthias Ringwald     pb_adv_random_delay_active = 1;
379*77ba3d3fSMatthias Ringwald     uint16_t random_delay_ms = 20 + (pb_adv_random() & 0x1f);
380*77ba3d3fSMatthias Ringwald     log_info("random delay %u ms", random_delay_ms);
381*77ba3d3fSMatthias Ringwald     btstack_run_loop_set_timer_handler(&pb_adv_random_delay_timer, &pb_adv_timer_handler);
382*77ba3d3fSMatthias Ringwald     btstack_run_loop_set_timer(&pb_adv_random_delay_timer, random_delay_ms);
383*77ba3d3fSMatthias Ringwald     btstack_run_loop_add_timer(&pb_adv_random_delay_timer);
384*77ba3d3fSMatthias Ringwald }
385*77ba3d3fSMatthias Ringwald 
386*77ba3d3fSMatthias Ringwald static void pb_adv_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
387*77ba3d3fSMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
388*77ba3d3fSMatthias Ringwald     const uint8_t * data;
389*77ba3d3fSMatthias Ringwald     uint8_t  length;
390*77ba3d3fSMatthias Ringwald     uint32_t link_id;
391*77ba3d3fSMatthias Ringwald     uint8_t  transaction_nr;
392*77ba3d3fSMatthias Ringwald     uint8_t  generic_provisioning_control;
393*77ba3d3fSMatthias Ringwald     switch(packet[0]){
394*77ba3d3fSMatthias Ringwald         case GAP_EVENT_ADVERTISING_REPORT:
395*77ba3d3fSMatthias Ringwald 
396*77ba3d3fSMatthias Ringwald             data = gap_event_advertising_report_get_data(packet);
397*77ba3d3fSMatthias Ringwald             // PDB ADV PDU
398*77ba3d3fSMatthias Ringwald             length = data[0];
399*77ba3d3fSMatthias Ringwald             link_id = big_endian_read_32(data, 2);
400*77ba3d3fSMatthias Ringwald             transaction_nr = data[6];
401*77ba3d3fSMatthias Ringwald             // generic provision PDU
402*77ba3d3fSMatthias Ringwald             generic_provisioning_control = data[7];
403*77ba3d3fSMatthias Ringwald             mesh_gpcf_format_t generic_provisioning_control_format = (mesh_gpcf_format_t) generic_provisioning_control & 3;
404*77ba3d3fSMatthias Ringwald 
405*77ba3d3fSMatthias Ringwald             // unless, we're waiting for LINK_OPEN, check link_id
406*77ba3d3fSMatthias Ringwald             if (link_state != LINK_STATE_W4_OPEN){
407*77ba3d3fSMatthias Ringwald                 if (link_id != pb_adv_link_id) break;
408*77ba3d3fSMatthias Ringwald             }
409*77ba3d3fSMatthias Ringwald 
410*77ba3d3fSMatthias Ringwald             if (generic_provisioning_control_format == MESH_GPCF_PROV_BEARER_CONTROL){
411*77ba3d3fSMatthias Ringwald                 pb_adv_handle_bearer_control(link_id, transaction_nr, &data[7], length-6);
412*77ba3d3fSMatthias Ringwald                 break;
413*77ba3d3fSMatthias Ringwald             }
414*77ba3d3fSMatthias Ringwald 
415*77ba3d3fSMatthias Ringwald             // verify link id and link state
416*77ba3d3fSMatthias Ringwald             if (link_state != LINK_STATE_OPEN) break;
417*77ba3d3fSMatthias Ringwald 
418*77ba3d3fSMatthias Ringwald             switch (generic_provisioning_control_format){
419*77ba3d3fSMatthias Ringwald                 case MESH_GPCF_TRANSACTION_START:
420*77ba3d3fSMatthias Ringwald                     pb_adv_handle_transaction_start(transaction_nr, &data[7], length-6);
421*77ba3d3fSMatthias Ringwald                     break;
422*77ba3d3fSMatthias Ringwald                 case MESH_GPCF_TRANSACTION_CONT:
423*77ba3d3fSMatthias Ringwald                     pb_adv_handle_transaction_cont(transaction_nr, &data[7], length-6);
424*77ba3d3fSMatthias Ringwald                     break;
425*77ba3d3fSMatthias Ringwald                 case MESH_GPCF_TRANSACTION_ACK:
426*77ba3d3fSMatthias Ringwald                     pb_adv_handle_transaction_ack(transaction_nr, &data[7], length-6);
427*77ba3d3fSMatthias Ringwald                     break;
428*77ba3d3fSMatthias Ringwald                 default:
429*77ba3d3fSMatthias Ringwald                     break;
430*77ba3d3fSMatthias Ringwald             }
431*77ba3d3fSMatthias Ringwald             pb_adv_run();
432*77ba3d3fSMatthias Ringwald             break;
433*77ba3d3fSMatthias Ringwald         case HCI_EVENT_MESH_META:
434*77ba3d3fSMatthias Ringwald             switch(packet[2]){
435*77ba3d3fSMatthias Ringwald                 case MESH_SUBEVENT_CAN_SEND_NOW:
436*77ba3d3fSMatthias Ringwald                     if (link_state == LINK_STATE_W4_ACK){
437*77ba3d3fSMatthias Ringwald                         // build packet
438*77ba3d3fSMatthias Ringwald                         uint8_t buffer[22];
439*77ba3d3fSMatthias Ringwald                         big_endian_store_32(buffer, 0, pb_adv_link_id);
440*77ba3d3fSMatthias Ringwald                         buffer[4] = 0;            // Transaction ID = 0
441*77ba3d3fSMatthias Ringwald                         buffer[5] = (0 << 2) | 3; // Link Open | Provisioning Bearer Control
442*77ba3d3fSMatthias Ringwald                         memcpy(&buffer[6], pb_adv_peer_device_uuid, 16);
443*77ba3d3fSMatthias Ringwald                         adv_bearer_send_pb_adv(buffer, sizeof(buffer));
444*77ba3d3fSMatthias Ringwald                         log_info("link open %08x", pb_adv_link_id);
445*77ba3d3fSMatthias Ringwald                         printf("PB-ADV: Sending Link Open for device uuid: ");
446*77ba3d3fSMatthias Ringwald                         printf_hexdump(pb_adv_peer_device_uuid, 16);
447*77ba3d3fSMatthias Ringwald                         btstack_run_loop_set_timer_handler(&pb_adv_random_delay_timer, &pb_adv_timer_handler);
448*77ba3d3fSMatthias Ringwald                         btstack_run_loop_set_timer(&pb_adv_random_delay_timer, PB_ADV_LINK_OPEN_RETRANSMIT_MS);
449*77ba3d3fSMatthias Ringwald                         btstack_run_loop_add_timer(&pb_adv_random_delay_timer);
450*77ba3d3fSMatthias Ringwald                         break;
451*77ba3d3fSMatthias Ringwald                     }
452*77ba3d3fSMatthias Ringwald                     if (link_state == LINK_STATE_CLOSING){
453*77ba3d3fSMatthias Ringwald                         log_info("link close %08x", pb_adv_link_id);
454*77ba3d3fSMatthias Ringwald                         printf("PB-ADV: Sending Link Close\n");
455*77ba3d3fSMatthias Ringwald                         // build packet
456*77ba3d3fSMatthias Ringwald                         uint8_t buffer[7];
457*77ba3d3fSMatthias Ringwald                         big_endian_store_32(buffer, 0, pb_adv_link_id);
458*77ba3d3fSMatthias Ringwald                         buffer[4] = 0;            // Transaction ID = 0
459*77ba3d3fSMatthias Ringwald                         buffer[5] = (2 << 2) | 3; // Link Close | Provisioning Bearer Control
460*77ba3d3fSMatthias Ringwald                         buffer[6] = pb_adv_link_close_reason;
461*77ba3d3fSMatthias Ringwald                         adv_bearer_send_pb_adv(buffer, sizeof(buffer));
462*77ba3d3fSMatthias Ringwald                         pb_adv_link_close_countdown--;
463*77ba3d3fSMatthias Ringwald                         if (pb_adv_link_close_countdown) {
464*77ba3d3fSMatthias Ringwald                             adv_bearer_request_can_send_now_for_pb_adv();
465*77ba3d3fSMatthias Ringwald                         } else {
466*77ba3d3fSMatthias Ringwald                             link_state = LINK_STATE_W4_OPEN;
467*77ba3d3fSMatthias Ringwald                         }
468*77ba3d3fSMatthias Ringwald                         break;
469*77ba3d3fSMatthias Ringwald                     }
470*77ba3d3fSMatthias Ringwald                     if (link_state == LINK_STATE_W2_SEND_ACK){
471*77ba3d3fSMatthias Ringwald                         link_state = LINK_STATE_OPEN;
472*77ba3d3fSMatthias Ringwald                         pb_adv_msg_out_transaction_nr = 0x80;
473*77ba3d3fSMatthias Ringwald                         // build packet
474*77ba3d3fSMatthias Ringwald                         uint8_t buffer[6];
475*77ba3d3fSMatthias Ringwald                         big_endian_store_32(buffer, 0, pb_adv_link_id);
476*77ba3d3fSMatthias Ringwald                         buffer[4] = 0;
477*77ba3d3fSMatthias Ringwald                         buffer[5] = (1 << 2) | 3; // Link Ack | Provisioning Bearer Control
478*77ba3d3fSMatthias Ringwald                         adv_bearer_send_pb_adv(buffer, sizeof(buffer));
479*77ba3d3fSMatthias Ringwald                         log_info("link ack %08x", pb_adv_link_id);
480*77ba3d3fSMatthias Ringwald                         printf("PB-ADV: Sending Link Open Ack\n");
481*77ba3d3fSMatthias Ringwald                         break;
482*77ba3d3fSMatthias Ringwald                     }
483*77ba3d3fSMatthias Ringwald                     if (pb_adv_msg_in_send_ack){
484*77ba3d3fSMatthias Ringwald                         pb_adv_msg_in_send_ack = 0;
485*77ba3d3fSMatthias Ringwald                         uint8_t buffer[6];
486*77ba3d3fSMatthias Ringwald                         big_endian_store_32(buffer, 0, pb_adv_link_id);
487*77ba3d3fSMatthias Ringwald                         buffer[4] = pb_adv_msg_in_transaction_nr_prev;
488*77ba3d3fSMatthias Ringwald                         buffer[5] = MESH_GPCF_TRANSACTION_ACK;
489*77ba3d3fSMatthias Ringwald                         adv_bearer_send_pb_adv(buffer, sizeof(buffer));
490*77ba3d3fSMatthias Ringwald                         log_info("transaction ack %08x", pb_adv_link_id);
491*77ba3d3fSMatthias Ringwald                         printf("PB-ADV: %02x sending ACK\n", pb_adv_msg_in_transaction_nr_prev);
492*77ba3d3fSMatthias Ringwald                         pb_adv_run();
493*77ba3d3fSMatthias Ringwald                         break;
494*77ba3d3fSMatthias Ringwald                     }
495*77ba3d3fSMatthias Ringwald                     if (pb_adv_msg_out_active){
496*77ba3d3fSMatthias Ringwald 
497*77ba3d3fSMatthias Ringwald                         // check timeout for outgoing message
498*77ba3d3fSMatthias Ringwald                         // since uint32_t is used and time now must be greater than pb_adv_msg_out_start,
499*77ba3d3fSMatthias Ringwald                         // this claculation is correct even when the run loop time overruns
500*77ba3d3fSMatthias Ringwald                         uint32_t transaction_time_ms = btstack_run_loop_get_time_ms() - pb_adv_msg_out_start;
501*77ba3d3fSMatthias Ringwald                         if (transaction_time_ms >= MESH_GENERIC_PROVISIONING_TRANSACTION_TIMEOUT_MS){
502*77ba3d3fSMatthias Ringwald                             pb_adv_outgoing_transation_complete(ERROR_CODE_CONNECTION_TIMEOUT);
503*77ba3d3fSMatthias Ringwald                             return;
504*77ba3d3fSMatthias Ringwald                         }
505*77ba3d3fSMatthias Ringwald 
506*77ba3d3fSMatthias Ringwald                         uint8_t buffer[29]; // ADV MTU
507*77ba3d3fSMatthias Ringwald                         big_endian_store_32(buffer, 0, pb_adv_link_id);
508*77ba3d3fSMatthias Ringwald                         buffer[4] = pb_adv_msg_out_transaction_nr;
509*77ba3d3fSMatthias Ringwald                         uint16_t bytes_left;
510*77ba3d3fSMatthias Ringwald                         uint16_t pos;
511*77ba3d3fSMatthias Ringwald                         if (pb_adv_msg_out_pos == 0){
512*77ba3d3fSMatthias Ringwald                             // Transaction start
513*77ba3d3fSMatthias Ringwald                             int seg_n = pb_adv_msg_out_len / 24;
514*77ba3d3fSMatthias Ringwald                             pb_adv_msg_out_seg = 0;
515*77ba3d3fSMatthias Ringwald                             buffer[5] = seg_n << 2 | MESH_GPCF_TRANSACTION_START;
516*77ba3d3fSMatthias Ringwald                             big_endian_store_16(buffer, 6, pb_adv_msg_out_len);
517*77ba3d3fSMatthias Ringwald                             buffer[8] = btstack_crc8_calc((uint8_t*)pb_adv_msg_out_buffer, pb_adv_msg_out_len);
518*77ba3d3fSMatthias Ringwald                             pos = 9;
519*77ba3d3fSMatthias Ringwald                             bytes_left = 24 - 4;
520*77ba3d3fSMatthias Ringwald                             printf("PB-ADV: %02x Sending Start: ", pb_adv_msg_out_transaction_nr);
521*77ba3d3fSMatthias Ringwald                         } else {
522*77ba3d3fSMatthias Ringwald                             // Transaction continue
523*77ba3d3fSMatthias Ringwald                             buffer[5] = pb_adv_msg_out_seg << 2 | MESH_GPCF_TRANSACTION_CONT;
524*77ba3d3fSMatthias Ringwald                             pos = 6;
525*77ba3d3fSMatthias Ringwald                             bytes_left = 24 - 1;
526*77ba3d3fSMatthias Ringwald                             printf("PB-ADV: %02x Sending Cont:  ", pb_adv_msg_out_transaction_nr);
527*77ba3d3fSMatthias Ringwald                         }
528*77ba3d3fSMatthias Ringwald                         pb_adv_msg_out_seg++;
529*77ba3d3fSMatthias Ringwald                         uint16_t bytes_to_copy = btstack_min(bytes_left, pb_adv_msg_out_len - pb_adv_msg_out_pos);
530*77ba3d3fSMatthias Ringwald                         memcpy(&buffer[pos], &pb_adv_msg_out_buffer[pb_adv_msg_out_pos], bytes_to_copy);
531*77ba3d3fSMatthias Ringwald                         pos += bytes_to_copy;
532*77ba3d3fSMatthias Ringwald                         printf("bytes %02u, pos %02u, len %02u: ", bytes_to_copy, pb_adv_msg_out_pos, pb_adv_msg_out_len);
533*77ba3d3fSMatthias Ringwald                         printf_hexdump(buffer, pos);
534*77ba3d3fSMatthias Ringwald                         pb_adv_msg_out_pos += bytes_to_copy;
535*77ba3d3fSMatthias Ringwald 
536*77ba3d3fSMatthias Ringwald                         if (pb_adv_msg_out_pos == pb_adv_msg_out_len){
537*77ba3d3fSMatthias Ringwald                             // done
538*77ba3d3fSMatthias Ringwald                             pb_adv_msg_out_pos = 0;
539*77ba3d3fSMatthias Ringwald                         }
540*77ba3d3fSMatthias Ringwald                         adv_bearer_send_pb_adv(buffer, pos);
541*77ba3d3fSMatthias Ringwald                         pb_adv_run();
542*77ba3d3fSMatthias Ringwald                         break;
543*77ba3d3fSMatthias Ringwald                     }
544*77ba3d3fSMatthias Ringwald                     break;
545*77ba3d3fSMatthias Ringwald                 default:
546*77ba3d3fSMatthias Ringwald                     break;
547*77ba3d3fSMatthias Ringwald             }
548*77ba3d3fSMatthias Ringwald         default:
549*77ba3d3fSMatthias Ringwald             break;
550*77ba3d3fSMatthias Ringwald     }
551*77ba3d3fSMatthias Ringwald }
552*77ba3d3fSMatthias Ringwald 
553*77ba3d3fSMatthias Ringwald void pb_adv_init(uint8_t * device_uuid){
554*77ba3d3fSMatthias Ringwald     pb_adv_own_device_uuid = device_uuid;
555*77ba3d3fSMatthias Ringwald     adv_bearer_register_for_pb_adv(&pb_adv_handler);
556*77ba3d3fSMatthias Ringwald     pb_adv_lfsr = 0x12345678;
557*77ba3d3fSMatthias Ringwald     pb_adv_random();
558*77ba3d3fSMatthias Ringwald }
559*77ba3d3fSMatthias Ringwald 
560*77ba3d3fSMatthias Ringwald void pb_adv_register_packet_handler(btstack_packet_handler_t packet_handler){
561*77ba3d3fSMatthias Ringwald     pb_adv_packet_handler = packet_handler;
562*77ba3d3fSMatthias Ringwald }
563*77ba3d3fSMatthias Ringwald 
564*77ba3d3fSMatthias Ringwald void pb_adv_send_pdu(uint16_t pb_adv_cid, const uint8_t * pdu, uint16_t size){
565*77ba3d3fSMatthias Ringwald     UNUSED(pb_adv_cid);
566*77ba3d3fSMatthias Ringwald     printf("PB-ADV: Send packet ");
567*77ba3d3fSMatthias Ringwald     printf_hexdump(pdu, size);
568*77ba3d3fSMatthias Ringwald     pb_adv_msg_out_buffer = pdu;
569*77ba3d3fSMatthias Ringwald     pb_adv_msg_out_len    = size;
570*77ba3d3fSMatthias Ringwald     pb_adv_msg_out_pos = 0;
571*77ba3d3fSMatthias Ringwald     pb_adv_msg_out_start = btstack_run_loop_get_time_ms();
572*77ba3d3fSMatthias Ringwald     pb_adv_msg_out_active = 1;
573*77ba3d3fSMatthias Ringwald     pb_adv_run();
574*77ba3d3fSMatthias Ringwald }
575*77ba3d3fSMatthias Ringwald 
576*77ba3d3fSMatthias Ringwald /**
577*77ba3d3fSMatthias Ringwald  * Close Link
578*77ba3d3fSMatthias Ringwald  * @param pb_adv_cid
579*77ba3d3fSMatthias Ringwald  */
580*77ba3d3fSMatthias Ringwald void pb_adv_close_link(uint16_t pb_adv_cid, uint8_t reason){
581*77ba3d3fSMatthias Ringwald     switch (link_state){
582*77ba3d3fSMatthias Ringwald         case LINK_STATE_W4_ACK:
583*77ba3d3fSMatthias Ringwald         case LINK_STATE_OPEN:
584*77ba3d3fSMatthias Ringwald         case LINK_STATE_W2_SEND_ACK:
585*77ba3d3fSMatthias Ringwald             pb_adv_emit_link_close(pb_adv_cid, 0);
586*77ba3d3fSMatthias Ringwald             link_state = LINK_STATE_CLOSING;
587*77ba3d3fSMatthias Ringwald             pb_adv_link_close_countdown = 3;
588*77ba3d3fSMatthias Ringwald             pb_adv_link_close_reason = reason;
589*77ba3d3fSMatthias Ringwald             adv_bearer_request_can_send_now_for_pb_adv();
590*77ba3d3fSMatthias Ringwald             break;
591*77ba3d3fSMatthias Ringwald         case LINK_STATE_W4_OPEN:
592*77ba3d3fSMatthias Ringwald         case LINK_STATE_CLOSING:
593*77ba3d3fSMatthias Ringwald             // nothing to do
594*77ba3d3fSMatthias Ringwald             break;
595*77ba3d3fSMatthias Ringwald     }
596*77ba3d3fSMatthias Ringwald }
597*77ba3d3fSMatthias Ringwald 
598*77ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
599*77ba3d3fSMatthias Ringwald uint16_t pb_adv_create_link(const uint8_t * device_uuid){
600*77ba3d3fSMatthias Ringwald     if (link_state != LINK_STATE_W4_OPEN) return 0;
601*77ba3d3fSMatthias Ringwald 
602*77ba3d3fSMatthias Ringwald     pb_adv_peer_device_uuid = device_uuid;
603*77ba3d3fSMatthias Ringwald     pb_adv_provisioner_role = 1;
604*77ba3d3fSMatthias Ringwald 
605*77ba3d3fSMatthias Ringwald     // create new 32-bit link id
606*77ba3d3fSMatthias Ringwald     pb_adv_link_id = pb_adv_random();
607*77ba3d3fSMatthias Ringwald 
608*77ba3d3fSMatthias Ringwald     // after sending OPEN, we wait for an ACK
609*77ba3d3fSMatthias Ringwald     link_state = LINK_STATE_W4_ACK;
610*77ba3d3fSMatthias Ringwald 
611*77ba3d3fSMatthias Ringwald     // request outgoing
612*77ba3d3fSMatthias Ringwald     adv_bearer_request_can_send_now_for_pb_adv();
613*77ba3d3fSMatthias Ringwald 
614*77ba3d3fSMatthias Ringwald     // dummy pb_adv_cid
615*77ba3d3fSMatthias Ringwald     return pb_adv_cid;
616*77ba3d3fSMatthias Ringwald }
617*77ba3d3fSMatthias Ringwald #endif
618*77ba3d3fSMatthias Ringwald 
619