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