14a9a543dSMatthias Ringwald /* 24a9a543dSMatthias Ringwald * Copyright (C) 2020 BlueKitchen GmbH 34a9a543dSMatthias Ringwald * 44a9a543dSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 54a9a543dSMatthias Ringwald * modification, are permitted provided that the following conditions 64a9a543dSMatthias Ringwald * are met: 74a9a543dSMatthias Ringwald * 84a9a543dSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 94a9a543dSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 104a9a543dSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 114a9a543dSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 124a9a543dSMatthias Ringwald * documentation and/or other materials provided with the distribution. 134a9a543dSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 144a9a543dSMatthias Ringwald * contributors may be used to endorse or promote products derived 154a9a543dSMatthias Ringwald * from this software without specific prior written permission. 164a9a543dSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 174a9a543dSMatthias Ringwald * personal benefit and not for any commercial purpose or for 184a9a543dSMatthias Ringwald * monetary gain. 194a9a543dSMatthias Ringwald * 204a9a543dSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 214a9a543dSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 224a9a543dSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 234a9a543dSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 244a9a543dSMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 254a9a543dSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 264a9a543dSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 274a9a543dSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 284a9a543dSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 294a9a543dSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 304a9a543dSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 314a9a543dSMatthias Ringwald * SUCH DAMAGE. 324a9a543dSMatthias Ringwald * 334a9a543dSMatthias Ringwald * Please inquire about commercial licensing options at 344a9a543dSMatthias Ringwald * [email protected] 354a9a543dSMatthias Ringwald * 364a9a543dSMatthias Ringwald */ 374a9a543dSMatthias Ringwald 384a9a543dSMatthias Ringwald #define BTSTACK_FILE__ "ll_sx1280.c" 394a9a543dSMatthias Ringwald 404a9a543dSMatthias Ringwald #define DEBUG 414a9a543dSMatthias Ringwald 424a9a543dSMatthias Ringwald #include <string.h> 434a9a543dSMatthias Ringwald 444a9a543dSMatthias Ringwald #include "ll.h" 454a9a543dSMatthias Ringwald 464a9a543dSMatthias Ringwald #include "hw.h" 474a9a543dSMatthias Ringwald #include "radio.h" 484a9a543dSMatthias Ringwald #include "sx1280.h" 494a9a543dSMatthias Ringwald #include "debug.h" 504a9a543dSMatthias Ringwald #include "btstack_config.h" 514a9a543dSMatthias Ringwald #include "btstack_debug.h" 524a9a543dSMatthias Ringwald #include "btstack_memory.h" 534a9a543dSMatthias Ringwald #include "btstack_memory_pool.h" 544a9a543dSMatthias Ringwald #include "btstack_linked_queue.h" 554a9a543dSMatthias Ringwald #include "bluetooth_company_id.h" 564a9a543dSMatthias Ringwald #include "hal_cpu.h" 574a9a543dSMatthias Ringwald #include "hci_event.h" 584a9a543dSMatthias Ringwald #include "hopping.h" 594a9a543dSMatthias Ringwald #include "hal_timer.h" 604a9a543dSMatthias Ringwald 614a9a543dSMatthias Ringwald 624a9a543dSMatthias Ringwald // 634a9a543dSMatthias Ringwald // configuration 644a9a543dSMatthias Ringwald // 654a9a543dSMatthias Ringwald 664a9a543dSMatthias Ringwald #define AUTO_RX_TX_TIME_US 86 674a9a543dSMatthias Ringwald 684a9a543dSMatthias Ringwald #define TX_PARAMS_RAMP_TIME RADIO_RAMP_02_US 694a9a543dSMatthias Ringwald 704a9a543dSMatthias Ringwald // set output power in dBM, range [-18..+13] dBm - Bluetooth LE max is 10 dBM 714a9a543dSMatthias Ringwald #define TX_PARAMS_OUTPUT_POWER 10 724a9a543dSMatthias Ringwald 734a9a543dSMatthias Ringwald 744a9a543dSMatthias Ringwald 754a9a543dSMatthias Ringwald #define ACL_LE_MAX_PAYLOAD 31 764a9a543dSMatthias Ringwald #define ADV_MAX_PAYLOAD (6+6+22) 774a9a543dSMatthias Ringwald #define LL_MAX_PAYLOAD 37 784a9a543dSMatthias Ringwald 794a9a543dSMatthias Ringwald // split 256 bytes data buffer into 2 rx and 2 tx buffers 804a9a543dSMatthias Ringwald #define SX1280_RX0_OFFSET 0 814a9a543dSMatthias Ringwald #define SX1280_RX1_OFFSET 64 824a9a543dSMatthias Ringwald #define SX1280_TX0_OFFSET 128 834a9a543dSMatthias Ringwald #define SX1280_TX1_OFFSET 192 844a9a543dSMatthias Ringwald 854a9a543dSMatthias Ringwald 864a9a543dSMatthias Ringwald // Mask of IRQs to listen in tx and rx mode 874a9a543dSMatthias Ringwald #define RX_TX_IRQ_MASK (IRQ_RX_DONE | IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_CRC_ERROR) 884a9a543dSMatthias Ringwald 894a9a543dSMatthias Ringwald // sync hop delay - time we prepare for next connection event 904a9a543dSMatthias Ringwald #define SYNC_HOP_DELAY_US 600 914a9a543dSMatthias Ringwald 924a9a543dSMatthias Ringwald // num tx buffers for use by link layer 934a9a543dSMatthias Ringwald #define HCI_NUM_TX_BUFFERS_LL 4 944a9a543dSMatthias Ringwald 954a9a543dSMatthias Ringwald // num rx buffers 964a9a543dSMatthias Ringwald #define HCI_NUM_RX_BUFFERS 16 974a9a543dSMatthias Ringwald 984a9a543dSMatthias Ringwald // total number PDU buffers 994a9a543dSMatthias Ringwald #define MAX_NUM_LL_PDUS (HCI_NUM_TX_BUFFERS_STACK + HCI_NUM_TX_BUFFERS_LL + HCI_NUM_RX_BUFFERS) 1004a9a543dSMatthias Ringwald 1014a9a543dSMatthias Ringwald // HCI Connection Handle used for all HCI events/connections 1024a9a543dSMatthias Ringwald #define HCI_CON_HANDLE 0x0001 1034a9a543dSMatthias Ringwald 1044a9a543dSMatthias Ringwald // convert us to ticks, rounding to the closest tick count 1054a9a543dSMatthias Ringwald // @note us must be <= 1000000 us = 1 s 1064a9a543dSMatthias Ringwald #define US_TO_TICKS(US) (((((uint32_t)(US)) * 4096) + 6125) / 125000L) 1074a9a543dSMatthias Ringwald 1084a9a543dSMatthias Ringwald // ADV PDU Types 1094a9a543dSMatthias Ringwald enum pdu_adv_type { 1104a9a543dSMatthias Ringwald PDU_ADV_TYPE_ADV_IND = 0x00, 1114a9a543dSMatthias Ringwald PDU_ADV_TYPE_DIRECT_IND = 0x01, 1124a9a543dSMatthias Ringwald PDU_ADV_TYPE_NONCONN_IND = 0x02, 1134a9a543dSMatthias Ringwald PDU_ADV_TYPE_SCAN_REQ = 0x03, 1144a9a543dSMatthias Ringwald PDU_ADV_TYPE_AUX_SCAN_REQ = PDU_ADV_TYPE_SCAN_REQ, 1154a9a543dSMatthias Ringwald PDU_ADV_TYPE_SCAN_RSP = 0x04, 1164a9a543dSMatthias Ringwald PDU_ADV_TYPE_CONNECT_IND = 0x05, 1174a9a543dSMatthias Ringwald PDU_ADV_TYPE_AUX_CONNECT_REQ = PDU_ADV_TYPE_CONNECT_IND, 1184a9a543dSMatthias Ringwald PDU_ADV_TYPE_SCAN_IND = 0x06, 1194a9a543dSMatthias Ringwald PDU_ADV_TYPE_EXT_IND = 0x07, 1204a9a543dSMatthias Ringwald PDU_ADV_TYPE_AUX_ADV_IND = PDU_ADV_TYPE_EXT_IND, 1214a9a543dSMatthias Ringwald PDU_ADV_TYPE_AUX_SCAN_RSP = PDU_ADV_TYPE_EXT_IND, 1224a9a543dSMatthias Ringwald PDU_ADV_TYPE_AUX_SYNC_IND = PDU_ADV_TYPE_EXT_IND, 1234a9a543dSMatthias Ringwald PDU_ADV_TYPE_AUX_CHAIN_IND = PDU_ADV_TYPE_EXT_IND, 1244a9a543dSMatthias Ringwald PDU_ADV_TYPE_AUX_CONNECT_RSP = 0x08, 1254a9a543dSMatthias Ringwald }; 1264a9a543dSMatthias Ringwald 1274a9a543dSMatthias Ringwald // DATA PDU Types 1284a9a543dSMatthias Ringwald enum pdu_data_llid { 1294a9a543dSMatthias Ringwald PDU_DATA_LLID_RESV = 0x00, 1304a9a543dSMatthias Ringwald PDU_DATA_LLID_DATA_CONTINUE = 0x01, 1314a9a543dSMatthias Ringwald PDU_DATA_LLID_DATA_START = 0x02, 1324a9a543dSMatthias Ringwald PDU_DATA_LLID_CTRL = 0x03, 1334a9a543dSMatthias Ringwald }; 1344a9a543dSMatthias Ringwald 1354a9a543dSMatthias Ringwald // DATA Link Layer Control Types 1364a9a543dSMatthias Ringwald enum pdu_data_llctrl_type { 1374a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND = 0x00, 1384a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_CHAN_MAP_IND = 0x01, 1394a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_TERMINATE_IND = 0x02, 1404a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_ENC_REQ = 0x03, 1414a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_ENC_RSP = 0x04, 1424a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_START_ENC_REQ = 0x05, 1434a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_START_ENC_RSP = 0x06, 1444a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP = 0x07, 1454a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_FEATURE_REQ = 0x08, 1464a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_FEATURE_RSP = 0x09, 1474a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ = 0x0A, 1484a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_RSP = 0x0B, 1494a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_VERSION_IND = 0x0C, 1504a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_REJECT_IND = 0x0D, 1514a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_SLAVE_FEATURE_REQ = 0x0E, 1524a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ = 0x0F, 1534a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP = 0x10, 1544a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND = 0x11, 1554a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_PING_REQ = 0x12, 1564a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_PING_RSP = 0x13, 1574a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_LENGTH_REQ = 0x14, 1584a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_LENGTH_RSP = 0x15, 1594a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_PHY_REQ = 0x16, 1604a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_PHY_RSP = 0x17, 1614a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND = 0x18, 1624a9a543dSMatthias Ringwald PDU_DATA_LLCTRL_TYPE_MIN_USED_CHAN_IND = 0x19, 1634a9a543dSMatthias Ringwald }; 1644a9a543dSMatthias Ringwald 1654a9a543dSMatthias Ringwald // Radio State 1664a9a543dSMatthias Ringwald typedef enum { 1674a9a543dSMatthias Ringwald RADIO_LOWPOWER, 1684a9a543dSMatthias Ringwald RADIO_RX_ERROR, 1694a9a543dSMatthias Ringwald RADIO_TX_TIMEOUT, 1704a9a543dSMatthias Ringwald RADIO_W4_TX_DONE_TO_RX, 171*b97c8672SMatthias Ringwald RADIO_W4_TX_ONLY_DONE, 1724a9a543dSMatthias Ringwald RADIO_W4_TIMER, 1734a9a543dSMatthias Ringwald } radio_state_t; 1744a9a543dSMatthias Ringwald 1754a9a543dSMatthias Ringwald // Link Layer State 1764a9a543dSMatthias Ringwald typedef enum { 1774a9a543dSMatthias Ringwald LL_STATE_STANDBY, 1784a9a543dSMatthias Ringwald LL_STATE_SCANNING, 1794a9a543dSMatthias Ringwald LL_STATE_ADVERTISING, 1804a9a543dSMatthias Ringwald LL_STATE_INITIATING, 1814a9a543dSMatthias Ringwald LL_STATE_CONNECTED 1824a9a543dSMatthias Ringwald } ll_state_t; 1834a9a543dSMatthias Ringwald 1844a9a543dSMatthias Ringwald // Link Layer PDU Flags 1854a9a543dSMatthias Ringwald typedef enum { 1864a9a543dSMatthias Ringwald LL_PDU_FLAG_DATA_PDU = 1, 1874a9a543dSMatthias Ringwald } ll_pdu_flags; 1884a9a543dSMatthias Ringwald 1894a9a543dSMatthias Ringwald // Link Layer PDU, used in linked list 1904a9a543dSMatthias Ringwald typedef struct { 1914a9a543dSMatthias Ringwald // header 1924a9a543dSMatthias Ringwald void * item; 1934a9a543dSMatthias Ringwald hci_con_handle_t con_handle; 1944a9a543dSMatthias Ringwald uint8_t flags; 1954a9a543dSMatthias Ringwald // over the air data 1964a9a543dSMatthias Ringwald uint8_t header; 1974a9a543dSMatthias Ringwald uint8_t len; 1984a9a543dSMatthias Ringwald uint8_t payload[LL_MAX_PAYLOAD]; 1994a9a543dSMatthias Ringwald } ll_pdu_t; 2004a9a543dSMatthias Ringwald 2014a9a543dSMatthias Ringwald // channel table: freq in hertz and whitening seed 2024a9a543dSMatthias Ringwald static const struct { 2034a9a543dSMatthias Ringwald uint32_t freq_hz; 2044a9a543dSMatthias Ringwald uint8_t whitening; 2054a9a543dSMatthias Ringwald } channel_table[] = { 2064a9a543dSMatthias Ringwald { 2404000000, 0x01 /* 00000001 */ }, 2074a9a543dSMatthias Ringwald { 2406000000, 0x41 /* 01000001 */ }, 2084a9a543dSMatthias Ringwald { 2408000000, 0x21 /* 00100001 */ }, 2094a9a543dSMatthias Ringwald { 2410000000, 0x61 /* 01100001 */ }, 2104a9a543dSMatthias Ringwald { 2412000000, 0x11 /* 00010001 */ }, 2114a9a543dSMatthias Ringwald { 2414000000, 0x51 /* 01010001 */ }, 2124a9a543dSMatthias Ringwald { 2416000000, 0x31 /* 00110001 */ }, 2134a9a543dSMatthias Ringwald { 2418000000, 0x71 /* 01110001 */ }, 2144a9a543dSMatthias Ringwald { 2420000000, 0x09 /* 00001001 */ }, 2154a9a543dSMatthias Ringwald { 2422000000, 0x49 /* 01001001 */ }, 2164a9a543dSMatthias Ringwald { 2424000000, 0x29 /* 00101001 */ }, 2174a9a543dSMatthias Ringwald { 2428000000, 0x69 /* 01101001 */ }, 2184a9a543dSMatthias Ringwald { 2430000000, 0x19 /* 00011001 */ }, 2194a9a543dSMatthias Ringwald { 2432000000, 0x59 /* 01011001 */ }, 2204a9a543dSMatthias Ringwald { 2434000000, 0x39 /* 00111001 */ }, 2214a9a543dSMatthias Ringwald { 2436000000, 0x79 /* 01111001 */ }, 2224a9a543dSMatthias Ringwald { 2438000000, 0x05 /* 00000101 */ }, 2234a9a543dSMatthias Ringwald { 2440000000, 0x45 /* 01000101 */ }, 2244a9a543dSMatthias Ringwald { 2442000000, 0x25 /* 00100101 */ }, 2254a9a543dSMatthias Ringwald { 2444000000, 0x65 /* 01100101 */ }, 2264a9a543dSMatthias Ringwald { 2446000000, 0x15 /* 00010101 */ }, 2274a9a543dSMatthias Ringwald { 2448000000, 0x55 /* 01010101 */ }, 2284a9a543dSMatthias Ringwald { 2450000000, 0x35 /* 00110101 */ }, 2294a9a543dSMatthias Ringwald { 2452000000, 0x75 /* 01110101 */ }, 2304a9a543dSMatthias Ringwald { 2454000000, 0x0d /* 00001101 */ }, 2314a9a543dSMatthias Ringwald { 2456000000, 0x4d /* 01001101 */ }, 2324a9a543dSMatthias Ringwald { 2458000000, 0x2d /* 00101101 */ }, 2334a9a543dSMatthias Ringwald { 2460000000, 0x6d /* 01101101 */ }, 2344a9a543dSMatthias Ringwald { 2462000000, 0x1d /* 00011101 */ }, 2354a9a543dSMatthias Ringwald { 2464000000, 0x5d /* 01011101 */ }, 2364a9a543dSMatthias Ringwald { 2466000000, 0x3d /* 00111101 */ }, 2374a9a543dSMatthias Ringwald { 2468000000, 0x7d /* 01111101 */ }, 2384a9a543dSMatthias Ringwald { 2470000000, 0x03 /* 00000011 */ }, 2394a9a543dSMatthias Ringwald { 2472000000, 0x43 /* 01000011 */ }, 2404a9a543dSMatthias Ringwald { 2474000000, 0x23 /* 00100011 */ }, 2414a9a543dSMatthias Ringwald { 2476000000, 0x63 /* 01100011 */ }, 2424a9a543dSMatthias Ringwald { 2478000000, 0x13 /* 00010011 */ }, 2434a9a543dSMatthias Ringwald { 2402000000, 0x53 /* 01010011 */ }, 2444a9a543dSMatthias Ringwald { 2426000000, 0x33 /* 00110011 */ }, 2454a9a543dSMatthias Ringwald { 2480000000, 0x73 /* 01110011 */ }, 2464a9a543dSMatthias Ringwald }; 2474a9a543dSMatthias Ringwald 248f8278fd5SMatthias Ringwald // tx buffer offset 249f8278fd5SMatthias Ringwald static uint8_t tx_buffer_offset[] = { 250f8278fd5SMatthias Ringwald SX1280_TX0_OFFSET, 251f8278fd5SMatthias Ringwald SX1280_TX1_OFFSET 252f8278fd5SMatthias Ringwald }; 253f8278fd5SMatthias Ringwald 2544a9a543dSMatthias Ringwald // hopping context 2554a9a543dSMatthias Ringwald static hopping_t h; 2564a9a543dSMatthias Ringwald 2574a9a543dSMatthias Ringwald static struct { 2584a9a543dSMatthias Ringwald 2594a9a543dSMatthias Ringwald volatile bool synced; 2604a9a543dSMatthias Ringwald 2614a9a543dSMatthias Ringwald volatile uint16_t packet_nr_in_connection_event; 2624a9a543dSMatthias Ringwald 2634a9a543dSMatthias Ringwald volatile uint16_t conn_interval_1250us; 2644a9a543dSMatthias Ringwald volatile uint32_t conn_interval_us; 265c3c27692SMatthias Ringwald volatile uint16_t conn_interval_ticks; 2664a9a543dSMatthias Ringwald 2674a9a543dSMatthias Ringwald volatile uint16_t conn_latency; 2684a9a543dSMatthias Ringwald 2694a9a543dSMatthias Ringwald volatile uint16_t supervision_timeout_10ms; 2704a9a543dSMatthias Ringwald volatile uint32_t supervision_timeout_us; 2714a9a543dSMatthias Ringwald 2724a9a543dSMatthias Ringwald // 2734a9a543dSMatthias Ringwald volatile uint32_t time_without_any_packets_us; 2744a9a543dSMatthias Ringwald 2754a9a543dSMatthias Ringwald // access address 2764a9a543dSMatthias Ringwald volatile uint32_t aa; 2774a9a543dSMatthias Ringwald 2784a9a543dSMatthias Ringwald // start of current connection event 2794a9a543dSMatthias Ringwald volatile uint16_t anchor_ticks; 2804a9a543dSMatthias Ringwald 281f6933f57SMatthias Ringwald // latest time to send tx packet before sync hop 282f6933f57SMatthias Ringwald volatile uint16_t conn_latest_tx_ticks; 283f6933f57SMatthias Ringwald 284c3c27692SMatthias Ringwald // timeout for sync relative to anchor 285c3c27692SMatthias Ringwald volatile uint16_t conn_sync_hop_ticks; 286c3c27692SMatthias Ringwald 2874a9a543dSMatthias Ringwald // current channel 2884a9a543dSMatthias Ringwald volatile uint8_t channel; 2894a9a543dSMatthias Ringwald 2904a9a543dSMatthias Ringwald // CSA #2 supported 2914a9a543dSMatthias Ringwald uint8_t csa2_support; 2924a9a543dSMatthias Ringwald 2934a9a543dSMatthias Ringwald // channels selection algorithm index (1 for csa #2) 2944a9a543dSMatthias Ringwald volatile uint8_t channel_selection_algorithm; 2954a9a543dSMatthias Ringwald 2964a9a543dSMatthias Ringwald // current connection event, first one starts with 0 2974a9a543dSMatthias Ringwald // - needed for connection param and channel map updates as well as encryption 2984a9a543dSMatthias Ringwald volatile uint16_t connection_event; 2994a9a543dSMatthias Ringwald 3004a9a543dSMatthias Ringwald // pending channel map update 3014a9a543dSMatthias Ringwald volatile bool channel_map_update_pending; 3024a9a543dSMatthias Ringwald volatile uint16_t channel_map_update_instant; 3034a9a543dSMatthias Ringwald volatile uint8_t channel_map_update_map[5]; 3044a9a543dSMatthias Ringwald 3054a9a543dSMatthias Ringwald // pending connection param update 3064a9a543dSMatthias Ringwald volatile bool conn_param_update_pending; 3074a9a543dSMatthias Ringwald volatile uint16_t conn_param_update_instant; 3084a9a543dSMatthias Ringwald volatile uint8_t conn_param_update_win_size; 3094a9a543dSMatthias Ringwald volatile uint16_t conn_param_update_win_offset; 310982f09b4SMatthias Ringwald volatile uint16_t conn_param_update_interval_1250us; 3114a9a543dSMatthias Ringwald volatile uint16_t conn_param_update_latency; 3124a9a543dSMatthias Ringwald volatile uint32_t conn_param_update_timeout_us; 3134a9a543dSMatthias Ringwald 3144a9a543dSMatthias Ringwald // our bd_addr as little endian 3154a9a543dSMatthias Ringwald uint8_t bd_addr_le[6]; 3164a9a543dSMatthias Ringwald 3174a9a543dSMatthias Ringwald // peer addr 3184a9a543dSMatthias Ringwald uint8_t peer_addr_type; 3194a9a543dSMatthias Ringwald uint8_t peer_addr[6]; 3204a9a543dSMatthias Ringwald 3214a9a543dSMatthias Ringwald // adv data 3224a9a543dSMatthias Ringwald uint8_t adv_len; 3234a9a543dSMatthias Ringwald uint8_t adv_data[31]; 3244a9a543dSMatthias Ringwald 3254a9a543dSMatthias Ringwald // adv param 3264a9a543dSMatthias Ringwald uint8_t adv_map; 3274a9a543dSMatthias Ringwald uint32_t adv_interval_us; 328*b97c8672SMatthias Ringwald uint8_t adv_type; 3294a9a543dSMatthias Ringwald 33085bc6c7fSMatthias Ringwald // adv data 33185bc6c7fSMatthias Ringwald uint8_t scan_resp_len; 33285bc6c7fSMatthias Ringwald uint8_t scan_resp_data[31]; 33385bc6c7fSMatthias Ringwald 3344a9a543dSMatthias Ringwald // next expected sequence number 3354a9a543dSMatthias Ringwald volatile uint8_t next_expected_sequence_number; 3364a9a543dSMatthias Ringwald 3374a9a543dSMatthias Ringwald // transmit sequence number 3384a9a543dSMatthias Ringwald volatile uint8_t transmit_sequence_number; 3394a9a543dSMatthias Ringwald 3404a9a543dSMatthias Ringwald // num completed packets 3414a9a543dSMatthias Ringwald volatile uint8_t num_completed; 3424a9a543dSMatthias Ringwald 343f8278fd5SMatthias Ringwald // rx queue 344f8278fd5SMatthias Ringwald btstack_linked_queue_t rx_queue; 3454a9a543dSMatthias Ringwald 3466511f47bSMatthias Ringwald // current incoming packet 3474a9a543dSMatthias Ringwald ll_pdu_t * rx_pdu; 3484a9a543dSMatthias Ringwald 3490f3448bcSMatthias Ringwald // rx packet ready 3500f3448bcSMatthias Ringwald bool rx_pdu_received; 3510f3448bcSMatthias Ringwald 352f8278fd5SMatthias Ringwald // tx queue of outgoing pdus 3534a9a543dSMatthias Ringwald btstack_linked_queue_t tx_queue; 3544a9a543dSMatthias Ringwald 355f8278fd5SMatthias Ringwald // pdus transferred into controller tx buffers 356f8278fd5SMatthias Ringwald ll_pdu_t * tx_buffer_pdu[2]; 357f8278fd5SMatthias Ringwald 358f8278fd5SMatthias Ringwald // manage tx packets on controller 359f8278fd5SMatthias Ringwald uint8_t num_tx_pdus_on_controller; 360f8278fd5SMatthias Ringwald 361f8278fd5SMatthias Ringwald // index of next tx buffer to send 362f8278fd5SMatthias Ringwald uint8_t next_tx_buffer; 3634a9a543dSMatthias Ringwald 3644a9a543dSMatthias Ringwald } ctx; 3654a9a543dSMatthias Ringwald 3664a9a543dSMatthias Ringwald static radio_state_t radio_state = RADIO_LOWPOWER; 3674a9a543dSMatthias Ringwald 3684a9a543dSMatthias Ringwald // Buffer pool 3694a9a543dSMatthias Ringwald static ll_pdu_t ll_pdu_pool_storage[MAX_NUM_LL_PDUS]; 3704a9a543dSMatthias Ringwald static btstack_memory_pool_t ll_pdu_pool; 3714a9a543dSMatthias Ringwald 3724a9a543dSMatthias Ringwald // single ll control response 3734a9a543dSMatthias Ringwald static ll_pdu_t ll_tx_packet; 374b907bb6fSMatthias Ringwald static ll_pdu_t ll_empty_packet; 3754a9a543dSMatthias Ringwald 3764a9a543dSMatthias Ringwald // Link Layer State 3774a9a543dSMatthias Ringwald static ll_state_t ll_state; 3784a9a543dSMatthias Ringwald static uint32_t ll_scan_interval_us; 3794a9a543dSMatthias Ringwald static uint32_t ll_scan_window_us; 3804a9a543dSMatthias Ringwald 3814a9a543dSMatthias Ringwald static ll_pdu_t * ll_reserved_acl_buffer; 3824a9a543dSMatthias Ringwald static void (*controller_packet_handler)(uint8_t packet_type, uint8_t * packet, uint16_t size); 3834a9a543dSMatthias Ringwald 3844a9a543dSMatthias Ringwald static uint8_t ll_outgoing_hci_event[258]; 3854a9a543dSMatthias Ringwald static bool ll_send_disconnected; 3864a9a543dSMatthias Ringwald static bool ll_send_connection_complete; 3874a9a543dSMatthias Ringwald 3884a9a543dSMatthias Ringwald // prototypes 3894a9a543dSMatthias Ringwald static void radio_set_timer_ticks(uint32_t anchor_offset_ticks); 3904a9a543dSMatthias Ringwald 3914a9a543dSMatthias Ringwald 3924a9a543dSMatthias Ringwald // memory pool for acl-le pdus 3934a9a543dSMatthias Ringwald static ll_pdu_t * btstack_memory_ll_pdu_get(void){ 3944a9a543dSMatthias Ringwald void * buffer = btstack_memory_pool_get(&ll_pdu_pool); 3954a9a543dSMatthias Ringwald if (buffer){ 3964a9a543dSMatthias Ringwald memset(buffer, 0, sizeof(ll_pdu_t)); 3974a9a543dSMatthias Ringwald } 3984a9a543dSMatthias Ringwald return (ll_pdu_t *) buffer; 3994a9a543dSMatthias Ringwald } 4004a9a543dSMatthias Ringwald 4014a9a543dSMatthias Ringwald static void btstack_memory_ll_pdu_free(ll_pdu_t *acl_le_pdu){ 4024a9a543dSMatthias Ringwald btstack_memory_pool_free(&ll_pdu_pool, acl_le_pdu); 4034a9a543dSMatthias Ringwald } 4044a9a543dSMatthias Ringwald 40500652864SMatthias Ringwald static void radio_auto_tx_on(void){ 40600652864SMatthias Ringwald // SetAutoTX(150 ms) - direct write / ignore compensation 40700652864SMatthias Ringwald uint8_t buf[2]; 40800652864SMatthias Ringwald big_endian_store_16(buf, 0, AUTO_RX_TX_TIME_US); 40900652864SMatthias Ringwald SX1280HalWriteCommand( RADIO_SET_AUTOTX, buf, 2 ); 41000652864SMatthias Ringwald } 41100652864SMatthias Ringwald 41200652864SMatthias Ringwald static void radio_auto_tx_off(void){ 41300652864SMatthias Ringwald // SetAutoTX(0) - direct write / ignore compensation 41400652864SMatthias Ringwald uint8_t buf[2] = { 0, 0 }; 41500652864SMatthias Ringwald SX1280HalWriteCommand( RADIO_SET_AUTOTX, buf, 2 ); 41600652864SMatthias Ringwald } 4174a9a543dSMatthias Ringwald 4184a9a543dSMatthias Ringwald static bool receive_prepare_rx_bufffer(void){ 4194a9a543dSMatthias Ringwald if (ctx.rx_pdu == NULL){ 4204a9a543dSMatthias Ringwald ctx.rx_pdu = btstack_memory_ll_pdu_get(); 4214a9a543dSMatthias Ringwald } 4224a9a543dSMatthias Ringwald if (ctx.rx_pdu == NULL){ 4234a9a543dSMatthias Ringwald printf("No free RX buffer\n"); 4244a9a543dSMatthias Ringwald return false; 4254a9a543dSMatthias Ringwald } else { 4264a9a543dSMatthias Ringwald return true; 4274a9a543dSMatthias Ringwald } 4284a9a543dSMatthias Ringwald } 4294a9a543dSMatthias Ringwald 4309c622d6fSMatthias Ringwald static void receive_response(void){ 4314a9a543dSMatthias Ringwald if (receive_prepare_rx_bufffer()) { 43202e972abSMatthias Ringwald // 150 us would be enough, but the timeout seems to apply for AutoTx as well, so we use 250 us 43302e972abSMatthias Ringwald Radio.SetRx( ( TickTime_t ) { RADIO_TICK_SIZE_0015_US, 16 } ); 4344a9a543dSMatthias Ringwald } 4354a9a543dSMatthias Ringwald } 4364a9a543dSMatthias Ringwald 4374a9a543dSMatthias Ringwald static void receive_first_master(void){ 4384a9a543dSMatthias Ringwald if (receive_prepare_rx_bufffer()){ 4394a9a543dSMatthias Ringwald Radio.SetRx( ( TickTime_t ) { RADIO_TICK_SIZE_1000_US, 1000 } ); 4404a9a543dSMatthias Ringwald } 4414a9a543dSMatthias Ringwald } 4424a9a543dSMatthias Ringwald 4434a9a543dSMatthias Ringwald static void receive_master(void){ 4444a9a543dSMatthias Ringwald if (receive_prepare_rx_bufffer()) { 4454a9a543dSMatthias Ringwald Radio.SetRx((TickTime_t) {RADIO_TICK_SIZE_1000_US, 1}); 4464a9a543dSMatthias Ringwald } 4474a9a543dSMatthias Ringwald } 4484a9a543dSMatthias Ringwald 44985bc6c7fSMatthias Ringwald static void setup_adv_pdu(uint8_t offset, uint8_t header, uint8_t len, const uint8_t * data){ 45085bc6c7fSMatthias Ringwald uint8_t buffer[39]; 45185bc6c7fSMatthias Ringwald buffer[0] = header; 45285bc6c7fSMatthias Ringwald buffer[1] = 6 + len; 45385bc6c7fSMatthias Ringwald memcpy(&buffer[2], ctx.bd_addr_le, 6); 45485bc6c7fSMatthias Ringwald memcpy(&buffer[8], data, len); 45585bc6c7fSMatthias Ringwald uint16_t packet_size = 2 + buffer[1]; 45685bc6c7fSMatthias Ringwald SX1280HalWriteBuffer( offset, buffer, packet_size ); 4574a9a543dSMatthias Ringwald } 4584a9a543dSMatthias Ringwald 45985bc6c7fSMatthias Ringwald static void send_adv(void){ 46000652864SMatthias Ringwald 46100652864SMatthias Ringwald // enable AutoTX for potential Scan Response 46200652864SMatthias Ringwald // TODO: only if adv type allows for scanning 46300652864SMatthias Ringwald radio_auto_tx_on(); 46400652864SMatthias Ringwald 46585bc6c7fSMatthias Ringwald SX1280SetBufferBaseAddresses( SX1280_TX0_OFFSET, SX1280_RX0_OFFSET); 46685bc6c7fSMatthias Ringwald SX1280SetTx( ( TickTime_t ){ RADIO_TICK_SIZE_1000_US, 1 } ); 46785bc6c7fSMatthias Ringwald } 4684a9a543dSMatthias Ringwald 4694a9a543dSMatthias Ringwald static void select_channel(uint8_t channel){ 4704a9a543dSMatthias Ringwald // Set Whitening seed 4714a9a543dSMatthias Ringwald Radio.SetWhiteningSeed( channel_table[channel].whitening ); 4724a9a543dSMatthias Ringwald 4734a9a543dSMatthias Ringwald // Sel Frequency 4744a9a543dSMatthias Ringwald Radio.SetRfFrequency( channel_table[channel].freq_hz ); 4754a9a543dSMatthias Ringwald } 4764a9a543dSMatthias Ringwald 4774a9a543dSMatthias Ringwald static void next_channel(void){ 4784a9a543dSMatthias Ringwald switch (ctx.channel_selection_algorithm){ 4794a9a543dSMatthias Ringwald case 0: 4804a9a543dSMatthias Ringwald ctx.channel = hopping_csa1_get_next_channel( &h ); 4814a9a543dSMatthias Ringwald break; 4824a9a543dSMatthias Ringwald case 1: 4834a9a543dSMatthias Ringwald ctx.channel = hopping_csa2_get_channel_for_counter( &h, ctx.connection_event); 4844a9a543dSMatthias Ringwald break; 4854a9a543dSMatthias Ringwald default: 4864a9a543dSMatthias Ringwald break; 4874a9a543dSMatthias Ringwald } 4884a9a543dSMatthias Ringwald select_channel(ctx.channel); 4894a9a543dSMatthias Ringwald } 4904a9a543dSMatthias Ringwald 4914a9a543dSMatthias Ringwald static void ll_advertising_statemachine(void){ 4924a9a543dSMatthias Ringwald switch ( radio_state) { 4934a9a543dSMatthias Ringwald case RADIO_RX_ERROR: 4944a9a543dSMatthias Ringwald case RADIO_LOWPOWER: 4954a9a543dSMatthias Ringwald // find next channel 4964a9a543dSMatthias Ringwald while (ctx.channel < 40){ 4974a9a543dSMatthias Ringwald ctx.channel++; 4984a9a543dSMatthias Ringwald if ((ctx.adv_map & (1 << (ctx.channel - 37))) != 0) { 4994a9a543dSMatthias Ringwald // Set Channel 5004a9a543dSMatthias Ringwald select_channel(ctx.channel); 501*b97c8672SMatthias Ringwald if (ctx.adv_type == 3) { 502*b97c8672SMatthias Ringwald // Non connectable undirected advertising (ADV_NONCONN_IND) 503*b97c8672SMatthias Ringwald radio_state = RADIO_W4_TX_ONLY_DONE; 504*b97c8672SMatthias Ringwald } else { 505*b97c8672SMatthias Ringwald // All other are either connectable and/or scannable 5064a9a543dSMatthias Ringwald radio_state = RADIO_W4_TX_DONE_TO_RX; 507*b97c8672SMatthias Ringwald } 5084a9a543dSMatthias Ringwald send_adv(); 5094a9a543dSMatthias Ringwald break; 5104a9a543dSMatthias Ringwald } 5114a9a543dSMatthias Ringwald if (ctx.channel >= 40){ 5124a9a543dSMatthias Ringwald // Set timer 5134a9a543dSMatthias Ringwald radio_state = RADIO_W4_TIMER; 5144a9a543dSMatthias Ringwald uint32_t adv_interval_ticks = US_TO_TICKS(ctx.adv_interval_us); 5154a9a543dSMatthias Ringwald radio_set_timer_ticks(adv_interval_ticks); 5164a9a543dSMatthias Ringwald } 5174a9a543dSMatthias Ringwald } 5184a9a543dSMatthias Ringwald break; 5194a9a543dSMatthias Ringwald default: 5204a9a543dSMatthias Ringwald break; 5214a9a543dSMatthias Ringwald } 5224a9a543dSMatthias Ringwald } 5234a9a543dSMatthias Ringwald 5244a9a543dSMatthias Ringwald static void start_advertising(void){ 5254a9a543dSMatthias Ringwald 5264a9a543dSMatthias Ringwald Radio.StopAutoTx(); 5274a9a543dSMatthias Ringwald 5284a9a543dSMatthias Ringwald PacketParams_t packetParams; 5294a9a543dSMatthias Ringwald packetParams.PacketType = PACKET_TYPE_BLE; 5304a9a543dSMatthias Ringwald packetParams.Params.Ble.BlePacketType = BLE_EYELONG_1_0; 5314a9a543dSMatthias Ringwald packetParams.Params.Ble.ConnectionState = BLE_PAYLOAD_LENGTH_MAX_37_BYTES; 5324a9a543dSMatthias Ringwald packetParams.Params.Ble.CrcField = BLE_CRC_3B; 5334a9a543dSMatthias Ringwald packetParams.Params.Ble.Whitening = RADIO_WHITENING_ON; 5344a9a543dSMatthias Ringwald Radio.SetPacketParams( &packetParams ); 5354a9a543dSMatthias Ringwald 5364a9a543dSMatthias Ringwald // Set CRC init value 0x555555 5374a9a543dSMatthias Ringwald Radio.WriteRegister(0x9c7, 0x55 ); 5384a9a543dSMatthias Ringwald Radio.WriteRegister(0x9c8, 0x55 ); 5394a9a543dSMatthias Ringwald Radio.WriteRegister(0x9c9, 0x55 ); 5404a9a543dSMatthias Ringwald 5414a9a543dSMatthias Ringwald // Set AccessAddress for ADV packets 5424a9a543dSMatthias Ringwald Radio.SetBleAdvertizerAccessAddress( ); 5434a9a543dSMatthias Ringwald 54485bc6c7fSMatthias Ringwald // prepare adv and scan data in tx0 and tx1 54585bc6c7fSMatthias Ringwald setup_adv_pdu(SX1280_TX0_OFFSET, PDU_ADV_TYPE_ADV_IND, ctx.adv_len, ctx.adv_data); 54685bc6c7fSMatthias Ringwald setup_adv_pdu(SX1280_TX1_OFFSET, PDU_ADV_TYPE_SCAN_RSP, ctx.scan_resp_len, ctx.scan_resp_data); 54785bc6c7fSMatthias Ringwald 5484a9a543dSMatthias Ringwald radio_state = RADIO_LOWPOWER; 5494a9a543dSMatthias Ringwald ll_state = LL_STATE_ADVERTISING; 5504a9a543dSMatthias Ringwald 5514a9a543dSMatthias Ringwald // prepare 5524a9a543dSMatthias Ringwald ctx.channel = 36; 5534a9a543dSMatthias Ringwald ctx.anchor_ticks = hal_timer_get_ticks(); 5544a9a543dSMatthias Ringwald 5554a9a543dSMatthias Ringwald // and get started 5564a9a543dSMatthias Ringwald ll_advertising_statemachine(); 5574a9a543dSMatthias Ringwald } 5584a9a543dSMatthias Ringwald 5594a9a543dSMatthias Ringwald static void start_hopping(void){ 5604a9a543dSMatthias Ringwald PacketParams_t packetParams; 5614a9a543dSMatthias Ringwald packetParams.PacketType = PACKET_TYPE_BLE; 5624a9a543dSMatthias Ringwald packetParams.Params.Ble.BlePacketType = BLE_EYELONG_1_0; 5634a9a543dSMatthias Ringwald packetParams.Params.Ble.ConnectionState = BLE_PAYLOAD_LENGTH_MAX_31_BYTES; 5644a9a543dSMatthias Ringwald packetParams.Params.Ble.CrcField = BLE_CRC_3B; 5654a9a543dSMatthias Ringwald packetParams.Params.Ble.Whitening = RADIO_WHITENING_ON; 5664a9a543dSMatthias Ringwald Radio.SetPacketParams( &packetParams ); 5674a9a543dSMatthias Ringwald 5684a9a543dSMatthias Ringwald } 5694a9a543dSMatthias Ringwald 5704a9a543dSMatthias Ringwald static void radio_stop_timer(void){ 5714a9a543dSMatthias Ringwald hal_timer_stop(); 5724a9a543dSMatthias Ringwald } 5734a9a543dSMatthias Ringwald 5744a9a543dSMatthias Ringwald static void radio_set_timer_ticks(uint32_t anchor_offset_ticks){ 5754a9a543dSMatthias Ringwald radio_stop_timer(); 5764a9a543dSMatthias Ringwald // set timer for next radio event relative to anchor 5774a9a543dSMatthias Ringwald uint16_t timeout_ticks = (uint16_t) (ctx.anchor_ticks + anchor_offset_ticks); 5784a9a543dSMatthias Ringwald hal_timer_start(timeout_ticks); 5794a9a543dSMatthias Ringwald } 5804a9a543dSMatthias Ringwald 581eed650bfSMatthias Ringwald static void ctx_set_conn_interval(uint16_t conn_interval_1250us){ 582eed650bfSMatthias Ringwald ctx.conn_interval_1250us = conn_interval_1250us; 583c3c27692SMatthias Ringwald ctx.conn_interval_us = ctx.conn_interval_1250us * 1250; 584c3c27692SMatthias Ringwald ctx.conn_interval_ticks = US_TO_TICKS(ctx.conn_interval_us); 585c3c27692SMatthias Ringwald ctx.conn_sync_hop_ticks = US_TO_TICKS(ctx.conn_interval_us - SYNC_HOP_DELAY_US); 586f6933f57SMatthias Ringwald 587f6933f57SMatthias Ringwald // latest time to send a packet before getting ready for next cnonection event 588f6933f57SMatthias Ringwald uint16_t max_packet_time_incl_ifs_us = 500; 589f6933f57SMatthias Ringwald ctx.conn_latest_tx_ticks = US_TO_TICKS(ctx.conn_interval_us - SYNC_HOP_DELAY_US - max_packet_time_incl_ifs_us); 590eed650bfSMatthias Ringwald } 591eed650bfSMatthias Ringwald 5924a9a543dSMatthias Ringwald static void ll_terminate(void){ 5934a9a543dSMatthias Ringwald ll_state = LL_STATE_STANDBY; 5944a9a543dSMatthias Ringwald ctx.conn_param_update_pending = false; 5954a9a543dSMatthias Ringwald ctx.channel_map_update_pending = false; 5964a9a543dSMatthias Ringwald // stop sync hop timer 5974a9a543dSMatthias Ringwald radio_stop_timer(); 598f8278fd5SMatthias Ringwald // free outgoing tx packets 599f8278fd5SMatthias Ringwald uint8_t i; 600f8278fd5SMatthias Ringwald for (i=0;i<2;i++){ 60185a545aaSMatthias Ringwald ll_pdu_t * tx_pdu = ctx.tx_buffer_pdu[i]; 60285a545aaSMatthias Ringwald if ((tx_pdu != NULL) && (tx_pdu != &ll_tx_packet) && (tx_pdu != &ll_empty_packet)){ 60385a545aaSMatthias Ringwald btstack_memory_ll_pdu_free(tx_pdu); 604f8278fd5SMatthias Ringwald ctx.tx_buffer_pdu[i] = NULL; 605f8278fd5SMatthias Ringwald } 6064a9a543dSMatthias Ringwald } 6070f3448bcSMatthias Ringwald ctx.num_tx_pdus_on_controller = 0; 6084a9a543dSMatthias Ringwald // free queued tx packets 6094a9a543dSMatthias Ringwald while (true){ 61085a545aaSMatthias Ringwald ll_pdu_t * tx_pdu = (ll_pdu_t *) btstack_linked_queue_dequeue(&ctx.tx_queue); 61185a545aaSMatthias Ringwald if (tx_pdu != NULL) { 61285a545aaSMatthias Ringwald btstack_memory_ll_pdu_free(tx_pdu); 6134a9a543dSMatthias Ringwald } else { 6144a9a543dSMatthias Ringwald break; 6154a9a543dSMatthias Ringwald } 6164a9a543dSMatthias Ringwald } 6174a9a543dSMatthias Ringwald // disable auto tx 6184a9a543dSMatthias Ringwald Radio.StopAutoTx(); 6194a9a543dSMatthias Ringwald // notify host stack 6204a9a543dSMatthias Ringwald ll_send_disconnected = true; 6214a9a543dSMatthias Ringwald } 6224a9a543dSMatthias Ringwald 623f8278fd5SMatthias Ringwald // load queued tx pdu into next free tx buffer 624f8278fd5SMatthias Ringwald static void preload_tx_buffer(void){ 625f8278fd5SMatthias Ringwald if (ctx.num_tx_pdus_on_controller >= 2) return; 626f8278fd5SMatthias Ringwald 627f8278fd5SMatthias Ringwald ll_pdu_t * tx_pdu = (ll_pdu_t *) btstack_linked_queue_dequeue(&ctx.tx_queue); 628f8278fd5SMatthias Ringwald if (tx_pdu == NULL) return; 629f8278fd5SMatthias Ringwald 630f8278fd5SMatthias Ringwald const uint16_t max_packet_len = 2 + 27; 631f8278fd5SMatthias Ringwald uint8_t index = (ctx.next_tx_buffer + ctx.num_tx_pdus_on_controller) & 1; 632f8278fd5SMatthias Ringwald ctx.tx_buffer_pdu[index] = tx_pdu; 633f8278fd5SMatthias Ringwald SX1280HalWriteBuffer( tx_buffer_offset[index], (uint8_t *) &ctx.tx_buffer_pdu[index]->header, max_packet_len); 634f8278fd5SMatthias Ringwald 635f8278fd5SMatthias Ringwald ctx.num_tx_pdus_on_controller++; 636f8278fd5SMatthias Ringwald // printf("preload %u bytes into %u\n", ctx.tx_buffer_pdu[index]->len, index); 637f8278fd5SMatthias Ringwald } 638f8278fd5SMatthias Ringwald 6394a9a543dSMatthias Ringwald static void radio_timer_handler(void){ 6404a9a543dSMatthias Ringwald 6414a9a543dSMatthias Ringwald uint16_t t0 = hal_timer_get_ticks(); 6424a9a543dSMatthias Ringwald 6434a9a543dSMatthias Ringwald switch (ll_state){ 6444a9a543dSMatthias Ringwald case LL_STATE_CONNECTED: 6454a9a543dSMatthias Ringwald // check supervision timeout 6464a9a543dSMatthias Ringwald ctx.time_without_any_packets_us += ctx.conn_interval_us; 6474a9a543dSMatthias Ringwald if (ctx.time_without_any_packets_us > ctx.supervision_timeout_us) { 6484a9a543dSMatthias Ringwald printf("Supervision timeout\n\n"); 6494a9a543dSMatthias Ringwald ll_terminate(); 6504a9a543dSMatthias Ringwald return; 6514a9a543dSMatthias Ringwald } 6524a9a543dSMatthias Ringwald 6534a9a543dSMatthias Ringwald // prepare next connection event 6544a9a543dSMatthias Ringwald ctx.connection_event++; 655c3c27692SMatthias Ringwald ctx.anchor_ticks += ctx.conn_interval_ticks; 6564a9a543dSMatthias Ringwald 6574a9a543dSMatthias Ringwald ctx.packet_nr_in_connection_event = 0; 6584a9a543dSMatthias Ringwald next_channel(); 6594a9a543dSMatthias Ringwald 6604a9a543dSMatthias Ringwald if (ctx.channel_map_update_pending && (ctx.channel_map_update_instant == ctx.connection_event)) { 6614a9a543dSMatthias Ringwald hopping_set_channel_map( &h, (const uint8_t *) &ctx.channel_map_update_map ); 6624a9a543dSMatthias Ringwald ctx.channel_map_update_pending = false; 6634a9a543dSMatthias Ringwald } 6644a9a543dSMatthias Ringwald 6654a9a543dSMatthias Ringwald if (ctx.conn_param_update_pending && ((ctx.conn_param_update_instant) == ctx.connection_event) ) { 666eed650bfSMatthias Ringwald ctx_set_conn_interval(ctx.conn_param_update_interval_1250us); 6674a9a543dSMatthias Ringwald ctx.conn_latency = ctx.conn_param_update_latency; 6684a9a543dSMatthias Ringwald ctx.supervision_timeout_us = ctx.conn_param_update_timeout_us; 6694a9a543dSMatthias Ringwald ctx.conn_param_update_pending = false; 6704a9a543dSMatthias Ringwald 6714a9a543dSMatthias Ringwald log_info("Conn param update now"); 6724a9a543dSMatthias Ringwald 6734a9a543dSMatthias Ringwald radio_stop_timer(); 6744a9a543dSMatthias Ringwald ctx.synced = false; 6754a9a543dSMatthias Ringwald } 6764a9a543dSMatthias Ringwald 677f8278fd5SMatthias Ringwald // preload tx pdu 678f8278fd5SMatthias Ringwald preload_tx_buffer(); 679f8278fd5SMatthias Ringwald 6804a9a543dSMatthias Ringwald if (ctx.synced){ 6814a9a543dSMatthias Ringwald // restart radio timer (might get overwritten by first packet) 682c3c27692SMatthias Ringwald radio_set_timer_ticks(ctx.conn_sync_hop_ticks); 6834a9a543dSMatthias Ringwald 6844a9a543dSMatthias Ringwald receive_master(); 6854a9a543dSMatthias Ringwald } else { 6864a9a543dSMatthias Ringwald // just wait longer 6874a9a543dSMatthias Ringwald receive_first_master(); 6884a9a543dSMatthias Ringwald } 6894a9a543dSMatthias Ringwald 6900f3448bcSMatthias Ringwald // printf("--SYNC-Ch %02u-Event %04u - t %08u--\n", ctx.channel, ctx.connection_event, t0); 6914a9a543dSMatthias Ringwald break; 6924a9a543dSMatthias Ringwald case LL_STATE_ADVERTISING: 6934a9a543dSMatthias Ringwald // send adv on all configured channels 6944a9a543dSMatthias Ringwald ctx.channel = 36; 6954a9a543dSMatthias Ringwald ctx.anchor_ticks = t0; 6964a9a543dSMatthias Ringwald radio_stop_timer(); 6974a9a543dSMatthias Ringwald ll_advertising_statemachine(); 6984a9a543dSMatthias Ringwald radio_state = RADIO_LOWPOWER; 6994a9a543dSMatthias Ringwald break; 7004a9a543dSMatthias Ringwald default: 7014a9a543dSMatthias Ringwald break; 7024a9a543dSMatthias Ringwald } 7034a9a543dSMatthias Ringwald 7044a9a543dSMatthias Ringwald } 7054a9a543dSMatthias Ringwald 706e19f86faSMatthias Ringwald static void radio_fetch_rx_pdu(void){ 7079c622d6fSMatthias Ringwald 7080f3448bcSMatthias Ringwald if (!ctx.rx_pdu_received) return; 7090f3448bcSMatthias Ringwald ctx.rx_pdu_received = false; 7100f3448bcSMatthias Ringwald 711e19f86faSMatthias Ringwald // fetch reserved rx pdu 712e19f86faSMatthias Ringwald ll_pdu_t * rx_packet = ctx.rx_pdu; 713e19f86faSMatthias Ringwald btstack_assert(rx_packet != NULL); 714ba57c415SMatthias Ringwald 715ba57c415SMatthias Ringwald // read max packet 716ba57c415SMatthias Ringwald uint16_t max_packet_len = 2 + 27; 717ba57c415SMatthias Ringwald SX1280HalReadBuffer( SX1280_RX0_OFFSET, &rx_packet->header, max_packet_len); 718ba57c415SMatthias Ringwald 719ba57c415SMatthias Ringwald // queue if not empty 720ba57c415SMatthias Ringwald if (rx_packet->len != 0){ 721ba57c415SMatthias Ringwald 722ba57c415SMatthias Ringwald // packet used 723e19f86faSMatthias Ringwald ctx.rx_pdu = NULL; 724e19f86faSMatthias Ringwald 725e19f86faSMatthias Ringwald // mark as data packet 726e19f86faSMatthias Ringwald rx_packet->flags |= LL_PDU_FLAG_DATA_PDU; 727e19f86faSMatthias Ringwald 728e19f86faSMatthias Ringwald // queue received packet 729e19f86faSMatthias Ringwald btstack_linked_queue_enqueue(&ctx.rx_queue, (btstack_linked_item_t *) rx_packet); 730e19f86faSMatthias Ringwald } 731ba57c415SMatthias Ringwald } 732e19f86faSMatthias Ringwald 7334a9a543dSMatthias Ringwald /** Radio IRQ handlers */ 7344a9a543dSMatthias Ringwald static void radio_on_tx_done(void ){ 735782349f4SMatthias Ringwald switch (ll_state){ 736782349f4SMatthias Ringwald case LL_STATE_ADVERTISING: 7374a9a543dSMatthias Ringwald switch (radio_state){ 7384a9a543dSMatthias Ringwald case RADIO_W4_TX_DONE_TO_RX: 7399c622d6fSMatthias Ringwald receive_response(); 7409c622d6fSMatthias Ringwald break; 741*b97c8672SMatthias Ringwald case RADIO_W4_TX_ONLY_DONE: 742*b97c8672SMatthias Ringwald radio_state = RADIO_LOWPOWER; 743*b97c8672SMatthias Ringwald break; 7449c622d6fSMatthias Ringwald default: 7459c622d6fSMatthias Ringwald break; 7469c622d6fSMatthias Ringwald } 747782349f4SMatthias Ringwald break; 7489c622d6fSMatthias Ringwald case LL_STATE_CONNECTED: 749782349f4SMatthias Ringwald btstack_assert(radio_state == RADIO_W4_TX_DONE_TO_RX); 750782349f4SMatthias Ringwald receive_response(); 7519c622d6fSMatthias Ringwald radio_fetch_rx_pdu(); 752f8278fd5SMatthias Ringwald preload_tx_buffer(); 7534a9a543dSMatthias Ringwald break; 7544a9a543dSMatthias Ringwald default: 7554a9a543dSMatthias Ringwald break; 7564a9a543dSMatthias Ringwald } 7574a9a543dSMatthias Ringwald } 758fd9c0d70SMatthias Ringwald static void radio_prepare_auto_tx(uint16_t packet_end_ticks, uint8_t rx_len){ 759fd9c0d70SMatthias Ringwald // restart supervision timeout 760fd9c0d70SMatthias Ringwald ctx.time_without_any_packets_us = 0; 761fd9c0d70SMatthias Ringwald 762fd9c0d70SMatthias Ringwald // check if we can sent a full packet before sync hop 763fd9c0d70SMatthias Ringwald int16_t now_ticks = packet_end_ticks - ctx.anchor_ticks; 764fd9c0d70SMatthias Ringwald if (ctx.synced && (now_ticks > ctx.conn_latest_tx_ticks)){ 765fd9c0d70SMatthias Ringwald // disable AutoTX to abort sending of next packet 766fd9c0d70SMatthias Ringwald Radio.SetFs(); 767fd9c0d70SMatthias Ringwald log_info("Close before Sync hop: now %u > %u", now_ticks, ctx.conn_latest_tx_ticks); 768fd9c0d70SMatthias Ringwald 769fd9c0d70SMatthias Ringwald // get rx pdu and 770fd9c0d70SMatthias Ringwald radio_fetch_rx_pdu(); 771fd9c0d70SMatthias Ringwald return; 772fd9c0d70SMatthias Ringwald } 773fd9c0d70SMatthias Ringwald 774fd9c0d70SMatthias Ringwald // setup empty packet in ll buffer if no tx packet was preloaded 775fd9c0d70SMatthias Ringwald if (ctx.num_tx_pdus_on_controller == 0) { 776b907bb6fSMatthias Ringwald ctx.tx_buffer_pdu[ctx.next_tx_buffer] = &ll_empty_packet; 777fd9c0d70SMatthias Ringwald ctx.num_tx_pdus_on_controller++; 778b907bb6fSMatthias Ringwald ll_empty_packet.header = PDU_DATA_LLID_DATA_CONTINUE; 779b907bb6fSMatthias Ringwald ll_empty_packet.len = 0; 780fd9c0d70SMatthias Ringwald } 781fd9c0d70SMatthias Ringwald 782fd9c0d70SMatthias Ringwald // setup pdu header 783fd9c0d70SMatthias Ringwald uint8_t packet_header[2]; 784fd9c0d70SMatthias Ringwald uint8_t md = btstack_linked_queue_empty(&ctx.tx_queue) ? 0 : 1; 785fd9c0d70SMatthias Ringwald packet_header[0] = (md << 4) | (ctx.transmit_sequence_number << 3) | (ctx.next_expected_sequence_number << 2) | ctx.tx_buffer_pdu[ctx.next_tx_buffer]->header; 786fd9c0d70SMatthias Ringwald packet_header[1] = ctx.tx_buffer_pdu[ctx.next_tx_buffer]->len; 787fd9c0d70SMatthias Ringwald 788fd9c0d70SMatthias Ringwald // select outgoing tx buffer and update pdu header 789fd9c0d70SMatthias Ringwald SX1280SetBufferBaseAddresses( tx_buffer_offset[ctx.next_tx_buffer], SX1280_RX0_OFFSET); 790fd9c0d70SMatthias Ringwald SX1280HalWriteBuffer( tx_buffer_offset[ctx.next_tx_buffer], (uint8_t *) packet_header, sizeof(packet_header)); 791fd9c0d70SMatthias Ringwald 792fd9c0d70SMatthias Ringwald // update operating state 793fd9c0d70SMatthias Ringwald SX1280AutoTxWillStart(); 794fd9c0d70SMatthias Ringwald 795fd9c0d70SMatthias Ringwald // set anchor on first packet in connection event 796fd9c0d70SMatthias Ringwald if (ctx.packet_nr_in_connection_event == 0){ 797fd9c0d70SMatthias Ringwald 798fd9c0d70SMatthias Ringwald // preamble (1) + aa (4) + header (1) + len (1) + payload (len) + crc (3) -- ISR handler ca. 35 us 799fd9c0d70SMatthias Ringwald uint16_t timestamp_delay = (10 + rx_len) * 8 - 35; 800fd9c0d70SMatthias Ringwald uint16_t packet_start_ticks = packet_end_ticks - US_TO_TICKS(timestamp_delay); 801fd9c0d70SMatthias Ringwald 802fd9c0d70SMatthias Ringwald ctx.anchor_ticks = packet_start_ticks; 803fd9c0d70SMatthias Ringwald ctx.synced = true; 804fd9c0d70SMatthias Ringwald radio_set_timer_ticks(ctx.conn_sync_hop_ticks); 805fd9c0d70SMatthias Ringwald } 806fd9c0d70SMatthias Ringwald 807fd9c0d70SMatthias Ringwald ctx.packet_nr_in_connection_event++; 808fd9c0d70SMatthias Ringwald 809fd9c0d70SMatthias Ringwald // printf("RX %02x -- tx buffer %u, %02x %02x\n", rx_header, ctx.next_tx_buffer, packet_header[0], packet_header[1]); 810fd9c0d70SMatthias Ringwald } 8114a9a543dSMatthias Ringwald 8124a9a543dSMatthias Ringwald static void radio_on_rx_done(void ){ 8134a9a543dSMatthias Ringwald uint16_t packet_end_ticks = hal_timer_get_ticks(); 8146511f47bSMatthias Ringwald 8156511f47bSMatthias Ringwald if (ll_state == LL_STATE_ADVERTISING){ 8166511f47bSMatthias Ringwald 81700652864SMatthias Ringwald // get rx pdu header 81800652864SMatthias Ringwald uint8_t rx_header; 81900652864SMatthias Ringwald SX1280HalReadBuffer( SX1280_RX0_OFFSET, &rx_header, 1); 82000652864SMatthias Ringwald 82100652864SMatthias Ringwald // check for Scan Request 82200652864SMatthias Ringwald uint8_t pdu_type = rx_header & 0x0f; 82300652864SMatthias Ringwald if (pdu_type == PDU_ADV_TYPE_SCAN_REQ){ 82400652864SMatthias Ringwald // scan request, select TX1 for active AutoTx 82500652864SMatthias Ringwald SX1280SetBufferBaseAddresses( SX1280_TX1_OFFSET, SX1280_RX0_OFFSET); 826*b97c8672SMatthias Ringwald radio_state = RADIO_W4_TX_ONLY_DONE; 82700652864SMatthias Ringwald } else { 82800652864SMatthias Ringwald 8296511f47bSMatthias Ringwald // fetch reserved rx pdu 8306511f47bSMatthias Ringwald ll_pdu_t * rx_packet = ctx.rx_pdu; 8316511f47bSMatthias Ringwald btstack_assert(rx_packet != NULL); 8326511f47bSMatthias Ringwald ctx.rx_pdu = NULL; 8336511f47bSMatthias Ringwald 8346511f47bSMatthias Ringwald // no data packet 8356511f47bSMatthias Ringwald rx_packet->flags = 0; 8366511f47bSMatthias Ringwald uint16_t max_packet_len = 2 + LL_MAX_PAYLOAD; 8376511f47bSMatthias Ringwald 83800652864SMatthias Ringwald // no scan request, disable auto tx and read complete buffer 83900652864SMatthias Ringwald radio_auto_tx_off(); 8406511f47bSMatthias Ringwald SX1280HalReadBuffer( SX1280_RX0_OFFSET, &rx_packet->header, max_packet_len); 8416511f47bSMatthias Ringwald 8426511f47bSMatthias Ringwald // queue received packet 8436511f47bSMatthias Ringwald btstack_linked_queue_enqueue(&ctx.rx_queue, (btstack_linked_item_t *) rx_packet); 84400652864SMatthias Ringwald } 8456511f47bSMatthias Ringwald 8466511f47bSMatthias Ringwald } else if (ll_state == LL_STATE_CONNECTED){ 8476511f47bSMatthias Ringwald 848f8278fd5SMatthias Ringwald // get and parse rx pdu header 849e19f86faSMatthias Ringwald uint8_t rx_buffer[2]; 850e19f86faSMatthias Ringwald SX1280HalReadBuffer( SX1280_RX0_OFFSET, rx_buffer, 2); 851e19f86faSMatthias Ringwald uint8_t rx_header = rx_buffer[0]; 852e19f86faSMatthias Ringwald uint8_t rx_len = rx_buffer[1]; 853f8278fd5SMatthias Ringwald uint8_t next_expected_sequence_number = (rx_header >> 2) & 1; 854f8278fd5SMatthias Ringwald uint8_t sequence_number = (rx_header >> 3) & 1; 855f8278fd5SMatthias Ringwald // more data field not used yet 856f8278fd5SMatthias Ringwald // uint8_t more_data = (rx_packet->header >> 4) & 1; 8574a9a543dSMatthias Ringwald 85890dad2a7SMatthias Ringwald // only accept packets with new sequence number and len <= payload size 85990dad2a7SMatthias Ringwald if ((sequence_number == ctx.next_expected_sequence_number) && (rx_len <= LL_MAX_PAYLOAD)) { 8606e34cf2cSMatthias Ringwald 8616e34cf2cSMatthias Ringwald bool rx_buffer_available = receive_prepare_rx_bufffer(); 8626e34cf2cSMatthias Ringwald if (rx_buffer_available){ 8634a9a543dSMatthias Ringwald // update state 8644a9a543dSMatthias Ringwald ctx.next_expected_sequence_number = 1 - sequence_number; 8654a9a543dSMatthias Ringwald 8660f3448bcSMatthias Ringwald // register pdu fetch 8670f3448bcSMatthias Ringwald ctx.rx_pdu_received = true; 8680f3448bcSMatthias Ringwald } 8696e34cf2cSMatthias Ringwald } 8700f3448bcSMatthias Ringwald 871f8278fd5SMatthias Ringwald // report outgoing packet as ack'ed and free if confirmed by peer 872f8278fd5SMatthias Ringwald bool tx_acked = ctx.transmit_sequence_number != next_expected_sequence_number; 8734a9a543dSMatthias Ringwald if (tx_acked){ 874f8278fd5SMatthias Ringwald if (ctx.num_tx_pdus_on_controller > 0){ 875b907bb6fSMatthias Ringwald ll_pdu_t * acked_pdu = ctx.tx_buffer_pdu[ctx.next_tx_buffer]; 876b907bb6fSMatthias Ringwald btstack_assert(acked_pdu != NULL); 877f8278fd5SMatthias Ringwald // if non link-layer packet, free buffer and report as completed 878b907bb6fSMatthias Ringwald if ((acked_pdu != &ll_tx_packet) && (acked_pdu != &ll_empty_packet)){ 879b907bb6fSMatthias Ringwald btstack_memory_ll_pdu_free(acked_pdu); 880f8278fd5SMatthias Ringwald ctx.tx_buffer_pdu[ctx.next_tx_buffer] = NULL; 8814a9a543dSMatthias Ringwald ctx.num_completed++; 8824a9a543dSMatthias Ringwald } 883f8278fd5SMatthias Ringwald // next buffer 884f8278fd5SMatthias Ringwald ctx.num_tx_pdus_on_controller--; 885f8278fd5SMatthias Ringwald ctx.next_tx_buffer = (ctx.next_tx_buffer + 1 ) & 1; 8864a9a543dSMatthias Ringwald } 887f8278fd5SMatthias Ringwald ctx.transmit_sequence_number = next_expected_sequence_number; 8884a9a543dSMatthias Ringwald } 8894a9a543dSMatthias Ringwald 890fd9c0d70SMatthias Ringwald // packet received, now prepare for AutoTX 891fd9c0d70SMatthias Ringwald radio_prepare_auto_tx(packet_end_ticks, rx_len); 8924a9a543dSMatthias Ringwald } 8934a9a543dSMatthias Ringwald } 8944a9a543dSMatthias Ringwald 8954a9a543dSMatthias Ringwald static void radio_on_tx_timeout(void ){ 8964a9a543dSMatthias Ringwald radio_state = RADIO_TX_TIMEOUT; 8974a9a543dSMatthias Ringwald printf( "<>>>>>>>>TXE\n\r" ); 8984a9a543dSMatthias Ringwald } 8994a9a543dSMatthias Ringwald 9004a9a543dSMatthias Ringwald static void radio_on_rx_timeout(void ){ 9014a9a543dSMatthias Ringwald switch (ll_state){ 9024a9a543dSMatthias Ringwald case LL_STATE_ADVERTISING: 9034a9a543dSMatthias Ringwald radio_state = RADIO_RX_ERROR; 9044a9a543dSMatthias Ringwald break; 9054a9a543dSMatthias Ringwald default: 9064a9a543dSMatthias Ringwald break; 9074a9a543dSMatthias Ringwald } 9084a9a543dSMatthias Ringwald } 9094a9a543dSMatthias Ringwald 9104a9a543dSMatthias Ringwald static void radio_on_rx_error(IrqErrorCode_t errorCode ){ 911fd9c0d70SMatthias Ringwald uint16_t packet_end_ticks = hal_timer_get_ticks(); 912fd9c0d70SMatthias Ringwald uint8_t rx_buffer[2]; 913fd9c0d70SMatthias Ringwald uint8_t rx_len; 9144a9a543dSMatthias Ringwald switch (ll_state){ 9154a9a543dSMatthias Ringwald case LL_STATE_ADVERTISING: 9164a9a543dSMatthias Ringwald radio_state = RADIO_RX_ERROR; 9174a9a543dSMatthias Ringwald break; 918fd9c0d70SMatthias Ringwald case LL_STATE_CONNECTED: 919fd9c0d70SMatthias Ringwald // get len from rx pdu header 920fd9c0d70SMatthias Ringwald SX1280HalReadBuffer(SX1280_RX0_OFFSET, rx_buffer, 2); 921fd9c0d70SMatthias Ringwald rx_len = rx_buffer[1]; 922fd9c0d70SMatthias Ringwald radio_prepare_auto_tx(packet_end_ticks, rx_len); 923fd9c0d70SMatthias Ringwald break; 9244a9a543dSMatthias Ringwald default: 9254a9a543dSMatthias Ringwald break; 9264a9a543dSMatthias Ringwald } 9274a9a543dSMatthias Ringwald } 9284a9a543dSMatthias Ringwald 9294a9a543dSMatthias Ringwald const static RadioCallbacks_t Callbacks = 9304a9a543dSMatthias Ringwald { 9314a9a543dSMatthias Ringwald &radio_on_tx_done, // txDone 9324a9a543dSMatthias Ringwald &radio_on_rx_done, // rxDone 9334a9a543dSMatthias Ringwald NULL, // syncWordDone 9344a9a543dSMatthias Ringwald NULL, // headerDone 9354a9a543dSMatthias Ringwald &radio_on_tx_timeout, // txTimeout 9364a9a543dSMatthias Ringwald &radio_on_rx_timeout, // rxTimeout 9374a9a543dSMatthias Ringwald &radio_on_rx_error, // rxError 9384a9a543dSMatthias Ringwald NULL, // rangingDone 9394a9a543dSMatthias Ringwald NULL, // cadDone 9404a9a543dSMatthias Ringwald }; 9414a9a543dSMatthias Ringwald 9424a9a543dSMatthias Ringwald // Link Layer 9434a9a543dSMatthias Ringwald 9444a9a543dSMatthias Ringwald static void ll_emit_hci_event(const hci_event_t * event, ...){ 9454a9a543dSMatthias Ringwald va_list argptr; 9464a9a543dSMatthias Ringwald va_start(argptr, event); 9474a9a543dSMatthias Ringwald uint16_t length = hci_event_create_from_template_and_arglist(ll_outgoing_hci_event, event, argptr); 9484a9a543dSMatthias Ringwald va_end(argptr); 9494a9a543dSMatthias Ringwald controller_packet_handler(HCI_EVENT_PACKET, ll_outgoing_hci_event, length); 9504a9a543dSMatthias Ringwald } 9514a9a543dSMatthias Ringwald 9524a9a543dSMatthias Ringwald void ll_init(void){ 9534a9a543dSMatthias Ringwald 9544a9a543dSMatthias Ringwald // setup memory pools 9554a9a543dSMatthias Ringwald btstack_memory_pool_create(&ll_pdu_pool, ll_pdu_pool_storage, MAX_NUM_LL_PDUS, sizeof(ll_pdu_t)); 9564a9a543dSMatthias Ringwald 9574a9a543dSMatthias Ringwald // set test bd addr 33:33:33:33:33:33 9584a9a543dSMatthias Ringwald memset(ctx.bd_addr_le, 0x33, 6); 9594a9a543dSMatthias Ringwald 9604a9a543dSMatthias Ringwald // default channels, advertising interval 9614a9a543dSMatthias Ringwald ctx.adv_map = 0x7; 9624a9a543dSMatthias Ringwald ctx.adv_interval_us = 1280000; 9634a9a543dSMatthias Ringwald 9644a9a543dSMatthias Ringwald // init timer 9654a9a543dSMatthias Ringwald hal_timer_init(); 9664a9a543dSMatthias Ringwald hal_timer_set_callback(&radio_timer_handler); 9674a9a543dSMatthias Ringwald } 9684a9a543dSMatthias Ringwald 9694a9a543dSMatthias Ringwald void ll_radio_on(void){ 9702acaaa65SMatthias Ringwald 9714a9a543dSMatthias Ringwald Radio.Init( (RadioCallbacks_t *) &Callbacks ); 9724a9a543dSMatthias Ringwald Radio.SetRegulatorMode( USE_DCDC ); // Can also be set in LDO mode but consume more power 9734a9a543dSMatthias Ringwald Radio.SetInterruptMode( ); 9744a9a543dSMatthias Ringwald Radio.SetDioIrqParams( RX_TX_IRQ_MASK, RX_TX_IRQ_MASK, IRQ_RADIO_NONE, IRQ_RADIO_NONE ); 9754a9a543dSMatthias Ringwald 9764a9a543dSMatthias Ringwald ModulationParams_t modulationParams; 9774a9a543dSMatthias Ringwald modulationParams.PacketType = PACKET_TYPE_BLE; 9784a9a543dSMatthias Ringwald modulationParams.Params.Ble.BitrateBandwidth = GFSK_BLE_BR_1_000_BW_1_2; 9794a9a543dSMatthias Ringwald modulationParams.Params.Ble.ModulationIndex = GFSK_BLE_MOD_IND_0_50; 9804a9a543dSMatthias Ringwald modulationParams.Params.Ble.ModulationShaping = RADIO_MOD_SHAPING_BT_0_5; 9814a9a543dSMatthias Ringwald 9824a9a543dSMatthias Ringwald Radio.SetStandby( STDBY_RC ); 9834a9a543dSMatthias Ringwald Radio.SetPacketType( modulationParams.PacketType ); 9844a9a543dSMatthias Ringwald Radio.SetModulationParams( &modulationParams ); 9854a9a543dSMatthias Ringwald Radio.SetBufferBaseAddresses( SX1280_TX0_OFFSET, SX1280_RX0_OFFSET ); 9864a9a543dSMatthias Ringwald Radio.SetTxParams( TX_PARAMS_OUTPUT_POWER, TX_PARAMS_RAMP_TIME ); 9874a9a543dSMatthias Ringwald 9884a9a543dSMatthias Ringwald // Go back to Frequcency Synthesis Mode, reduces transition time between Rx<->TX 9894a9a543dSMatthias Ringwald Radio.SetAutoFS(1); 9904a9a543dSMatthias Ringwald 9914588b287SMatthias Ringwald uint16_t fw_version = SX1280GetFirmwareVersion(); 9924588b287SMatthias Ringwald printf("FW Version: 0x%04x\n", fw_version); 9934588b287SMatthias Ringwald 9942acaaa65SMatthias Ringwald // quick test 995ec59e786SMatthias Ringwald uint8_t data[] = {1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128 }; 9962acaaa65SMatthias Ringwald Radio.WriteBuffer(0, data, sizeof(data)); 997ec59e786SMatthias Ringwald uint8_t check[32]; 9982acaaa65SMatthias Ringwald Radio.ReadBuffer(0, check, sizeof(data)); 9992acaaa65SMatthias Ringwald if (memcmp(data, check, sizeof(data)) != 0) { 1000ec59e786SMatthias Ringwald printf("GOOD: "); printf_hexdump(data, sizeof(data)); 1001ec59e786SMatthias Ringwald printf("BAD: "); printf_hexdump(check, sizeof(data)); 10022acaaa65SMatthias Ringwald btstack_assert(false); 10032acaaa65SMatthias Ringwald } 10042acaaa65SMatthias Ringwald 10054a9a543dSMatthias Ringwald ll_state = LL_STATE_STANDBY; 10064a9a543dSMatthias Ringwald } 10074a9a543dSMatthias Ringwald 10084a9a543dSMatthias Ringwald static void ll_handle_conn_ind(ll_pdu_t * rx_packet){ 10094a9a543dSMatthias Ringwald printf("Connect Req: "); 10104a9a543dSMatthias Ringwald printf_hexdump(&rx_packet->header, rx_packet->len + 2); 10114a9a543dSMatthias Ringwald 10124a9a543dSMatthias Ringwald uint8_t * init_addr = &rx_packet->payload[0]; 10134a9a543dSMatthias Ringwald uint8_t * adv_addr = &rx_packet->payload[6]; 10144a9a543dSMatthias Ringwald uint8_t chan_sel = (rx_packet->header >> 5) & 1; 10154a9a543dSMatthias Ringwald 10164a9a543dSMatthias Ringwald // verify AdvA 10174a9a543dSMatthias Ringwald if (memcmp(ctx.bd_addr_le, adv_addr, 6) != 0){ 10184a9a543dSMatthias Ringwald // differs, go back to adv sending 10194a9a543dSMatthias Ringwald radio_state = RADIO_LOWPOWER; 10204a9a543dSMatthias Ringwald return; 10214a9a543dSMatthias Ringwald } 10224a9a543dSMatthias Ringwald 10234a9a543dSMatthias Ringwald // TODO: get remote addr type 10244a9a543dSMatthias Ringwald ctx.peer_addr_type = 0; 10254a9a543dSMatthias Ringwald memcpy(ctx.peer_addr, init_addr, 6); 10264a9a543dSMatthias Ringwald 10274a9a543dSMatthias Ringwald // get params for HCI event 10284a9a543dSMatthias Ringwald const uint8_t * ll_data = &rx_packet->payload[12]; 10294a9a543dSMatthias Ringwald 10304a9a543dSMatthias Ringwald ctx.aa = little_endian_read_32(ll_data, 0); 10314a9a543dSMatthias Ringwald uint8_t crc_init_0 = ll_data[4]; 10324a9a543dSMatthias Ringwald uint8_t crc_init_1 = ll_data[5]; 10334a9a543dSMatthias Ringwald uint8_t crc_init_2 = ll_data[6]; 10344a9a543dSMatthias Ringwald uint8_t win_size = ll_data[7]; 10354a9a543dSMatthias Ringwald uint16_t win_offset = little_endian_read_16(ll_data, 8); 1036eed650bfSMatthias Ringwald uint16_t conn_interval_1250us = little_endian_read_16(ll_data, 10); 10374a9a543dSMatthias Ringwald ctx.conn_latency = little_endian_read_16(ll_data, 12); 10384a9a543dSMatthias Ringwald ctx.supervision_timeout_10ms = little_endian_read_16(ll_data, 14); 10394a9a543dSMatthias Ringwald const uint8_t * channel_map = &ll_data[16]; 10404a9a543dSMatthias Ringwald uint8_t hop = ll_data[21] & 0x1f; 10414a9a543dSMatthias Ringwald uint8_t sca = ll_data[21] >> 5; 10424a9a543dSMatthias Ringwald 10434a9a543dSMatthias Ringwald UNUSED(sca); 10444a9a543dSMatthias Ringwald UNUSED(win_offset); 10454a9a543dSMatthias Ringwald UNUSED(win_size); 10464a9a543dSMatthias Ringwald 1047eed650bfSMatthias Ringwald ctx_set_conn_interval(conn_interval_1250us); 1048eed650bfSMatthias Ringwald 10494a9a543dSMatthias Ringwald // convert to us 10504a9a543dSMatthias Ringwald ctx.supervision_timeout_us = ctx.supervision_timeout_10ms * 10000; 10514a9a543dSMatthias Ringwald ctx.connection_event = 0; 10524a9a543dSMatthias Ringwald ctx.packet_nr_in_connection_event = 0; 10534a9a543dSMatthias Ringwald ctx.next_expected_sequence_number = 0; 10544a9a543dSMatthias Ringwald ctx.transmit_sequence_number = 0; 10554a9a543dSMatthias Ringwald 10564a9a543dSMatthias Ringwald // set AA 10574a9a543dSMatthias Ringwald Radio.SetBleAccessAddress(ctx.aa); 10584a9a543dSMatthias Ringwald 10594a9a543dSMatthias Ringwald // set CRC init value 10604a9a543dSMatthias Ringwald Radio.WriteRegister(0x9c7, crc_init_2); 10614a9a543dSMatthias Ringwald Radio.WriteRegister(0x9c8, crc_init_1); 10624a9a543dSMatthias Ringwald Radio.WriteRegister(0x9c9, crc_init_0); 10634a9a543dSMatthias Ringwald 10644a9a543dSMatthias Ringwald printf("Connection interval %u us\n", ctx.conn_interval_us); 10654a9a543dSMatthias Ringwald printf("Connection timeout %u us\n", ctx.supervision_timeout_us); 10664a9a543dSMatthias Ringwald printf("AA %08x\n", ctx.aa); 10674a9a543dSMatthias Ringwald printf("CRC Init 0x%02x%02x%02x\n", crc_init_2, crc_init_1, crc_init_0); 10684a9a543dSMatthias Ringwald 10694a9a543dSMatthias Ringwald // init hopping 10704a9a543dSMatthias Ringwald hopping_init( &h ); 10714a9a543dSMatthias Ringwald hopping_set_channel_map( &h, channel_map); 10724a9a543dSMatthias Ringwald ctx.channel_selection_algorithm = ctx.csa2_support & chan_sel; 10734a9a543dSMatthias Ringwald switch (ctx.channel_selection_algorithm){ 10744a9a543dSMatthias Ringwald case 0: 10754a9a543dSMatthias Ringwald hopping_csa1_set_hop_increment( &h, hop ); 10764a9a543dSMatthias Ringwald break; 10774a9a543dSMatthias Ringwald case 1: 10784a9a543dSMatthias Ringwald hopping_csa2_set_access_address( &h, ctx.aa); 10794a9a543dSMatthias Ringwald break; 10804a9a543dSMatthias Ringwald default: 10814a9a543dSMatthias Ringwald break; 10824a9a543dSMatthias Ringwald } 10834a9a543dSMatthias Ringwald next_channel(); 10844a9a543dSMatthias Ringwald 10854a9a543dSMatthias Ringwald start_hopping(); 10864a9a543dSMatthias Ringwald 108700652864SMatthias Ringwald radio_auto_tx_on(); 10884a9a543dSMatthias Ringwald 1089f8278fd5SMatthias Ringwald // pre-load tx pdu 10900f3448bcSMatthias Ringwald ctx.num_tx_pdus_on_controller = 0; 10910f3448bcSMatthias Ringwald ctx.next_tx_buffer = 0; 1092f8278fd5SMatthias Ringwald preload_tx_buffer(); 1093f8278fd5SMatthias Ringwald 10944a9a543dSMatthias Ringwald // get next packet 10954a9a543dSMatthias Ringwald ll_state = LL_STATE_CONNECTED; 10964a9a543dSMatthias Ringwald 10974a9a543dSMatthias Ringwald receive_first_master(); 10984a9a543dSMatthias Ringwald ll_send_connection_complete = true; 10994a9a543dSMatthias Ringwald } 11004a9a543dSMatthias Ringwald 1101ee00544bSMatthias Ringwald static void ll_queue_control_tx(void){ 1102ee00544bSMatthias Ringwald hal_cpu_disable_irqs(); 1103ee00544bSMatthias Ringwald btstack_linked_queue_enqueue(&ctx.tx_queue, (btstack_linked_item_t *) &ll_tx_packet); 1104ee00544bSMatthias Ringwald hal_cpu_enable_irqs(); 1105ee00544bSMatthias Ringwald } 1106ee00544bSMatthias Ringwald 11074a9a543dSMatthias Ringwald static void ll_handle_control(ll_pdu_t * rx_packet){ 11084a9a543dSMatthias Ringwald ll_pdu_t * tx_packet = &ll_tx_packet; 11094a9a543dSMatthias Ringwald uint8_t opcode = rx_packet->payload[0]; 11104a9a543dSMatthias Ringwald switch (opcode){ 11114a9a543dSMatthias Ringwald case PDU_DATA_LLCTRL_TYPE_VERSION_IND: 11124a9a543dSMatthias Ringwald tx_packet->len = 6; 11134a9a543dSMatthias Ringwald tx_packet->header = PDU_DATA_LLID_CTRL; 11144a9a543dSMatthias Ringwald tx_packet->payload[0] = PDU_DATA_LLCTRL_TYPE_VERSION_IND; 11154a9a543dSMatthias Ringwald tx_packet->payload[1] = 0x06; // VersNr = Bluetooth Core V4.0 11164a9a543dSMatthias Ringwald little_endian_store_16(tx_packet->payload, 2, BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH); 11174a9a543dSMatthias Ringwald little_endian_store_16(tx_packet->payload, 4, 0); 1118ee00544bSMatthias Ringwald ll_queue_control_tx(); 11194a9a543dSMatthias Ringwald printf("Queue Version Ind\n"); 11204a9a543dSMatthias Ringwald break; 11214a9a543dSMatthias Ringwald case PDU_DATA_LLCTRL_TYPE_FEATURE_REQ: 11224a9a543dSMatthias Ringwald tx_packet->len = 9; 11234a9a543dSMatthias Ringwald tx_packet->header = PDU_DATA_LLID_CTRL; 11244a9a543dSMatthias Ringwald tx_packet->payload[0] = PDU_DATA_LLCTRL_TYPE_FEATURE_RSP; 11254a9a543dSMatthias Ringwald // TODO: set features of our controller 11264a9a543dSMatthias Ringwald memset(&tx_packet->payload[1], 0, 8); 1127ee00544bSMatthias Ringwald ll_queue_control_tx(); 11284a9a543dSMatthias Ringwald printf("Queue Feature Rsp\n"); 11294a9a543dSMatthias Ringwald break; 11304a9a543dSMatthias Ringwald case PDU_DATA_LLCTRL_TYPE_CHAN_MAP_IND: 11314a9a543dSMatthias Ringwald memcpy((uint8_t *) ctx.channel_map_update_map, &rx_packet->payload[1], 5); 11324a9a543dSMatthias Ringwald ctx.channel_map_update_instant = little_endian_read_16(rx_packet->payload, 6); 11334a9a543dSMatthias Ringwald ctx.channel_map_update_pending = true; 11344a9a543dSMatthias Ringwald break; 11354a9a543dSMatthias Ringwald case PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND: 11364a9a543dSMatthias Ringwald ctx.conn_param_update_win_size = tx_packet->payload[1]; 11374a9a543dSMatthias Ringwald ctx.conn_param_update_win_offset = little_endian_read_16(rx_packet->payload, 2); 1138982f09b4SMatthias Ringwald ctx.conn_param_update_interval_1250us = little_endian_read_16(rx_packet->payload, 4); 11394a9a543dSMatthias Ringwald ctx.conn_param_update_latency = little_endian_read_16(rx_packet->payload, 6); 11404a9a543dSMatthias Ringwald ctx.conn_param_update_timeout_us = little_endian_read_16(rx_packet->payload, 8) * 10000; 11414a9a543dSMatthias Ringwald ctx.conn_param_update_instant = little_endian_read_16(rx_packet->payload, 10); 11424a9a543dSMatthias Ringwald ctx.conn_param_update_pending = true; 1143982f09b4SMatthias Ringwald log_info("PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND, conn interval %u 1250us at instant %u", 1144982f09b4SMatthias Ringwald (unsigned int) ctx.conn_param_update_interval_1250us, ctx.conn_param_update_instant); 11454a9a543dSMatthias Ringwald break; 11464a9a543dSMatthias Ringwald case PDU_DATA_LLCTRL_TYPE_TERMINATE_IND: 11474a9a543dSMatthias Ringwald printf("Terminate!\n"); 11484a9a543dSMatthias Ringwald ll_terminate(); 11494a9a543dSMatthias Ringwald break; 11504a9a543dSMatthias Ringwald default: 1151927d0c32SMatthias Ringwald btstack_assert(false); 1152927d0c32SMatthias Ringwald printf("Unhandled LL Control PDU 0x%02x\n", opcode); 11534a9a543dSMatthias Ringwald break; 11544a9a543dSMatthias Ringwald } 11554a9a543dSMatthias Ringwald } 11564a9a543dSMatthias Ringwald 11574a9a543dSMatthias Ringwald static void ll_handle_data(ll_pdu_t * rx_packet){ 11584a9a543dSMatthias Ringwald if (ll_state != LL_STATE_CONNECTED) return; 11590f3448bcSMatthias Ringwald btstack_assert(rx_packet->len <= LL_MAX_PAYLOAD); 11600f3448bcSMatthias Ringwald uint8_t acl_packet[4 + LL_MAX_PAYLOAD]; 11614a9a543dSMatthias Ringwald // ACL Header 11624a9a543dSMatthias Ringwald uint8_t ll_id = rx_packet->header & 3; 11634a9a543dSMatthias Ringwald acl_packet[0] = 0x01; 11644a9a543dSMatthias Ringwald acl_packet[1] = ll_id << 4; 11654a9a543dSMatthias Ringwald little_endian_store_16(acl_packet, 2, rx_packet->len); 11664a9a543dSMatthias Ringwald memcpy(&acl_packet[4], rx_packet->payload, rx_packet->len); 11674a9a543dSMatthias Ringwald (*controller_packet_handler)(HCI_ACL_DATA_PACKET, acl_packet, rx_packet->len + 4); 11684a9a543dSMatthias Ringwald } 11694a9a543dSMatthias Ringwald 11704a9a543dSMatthias Ringwald void ll_set_scan_parameters(uint8_t le_scan_type, uint16_t le_scan_interval, uint16_t le_scan_window, uint8_t own_address_type, uint8_t scanning_filter_policy){ 11714a9a543dSMatthias Ringwald // TODO .. store other params 11724a9a543dSMatthias Ringwald ll_scan_interval_us = ((uint32_t) le_scan_interval) * 625; 11734a9a543dSMatthias Ringwald ll_scan_window_us = ((uint32_t) le_scan_window) * 625; 11744a9a543dSMatthias Ringwald log_info("LE Scan Params: window %lu, interval %lu ms", ll_scan_interval_us, ll_scan_window_us); 11754a9a543dSMatthias Ringwald } 11764a9a543dSMatthias Ringwald 11774a9a543dSMatthias Ringwald static uint8_t ll_start_scanning(uint8_t filter_duplicates){ 11784a9a543dSMatthias Ringwald #if 0 11794a9a543dSMatthias Ringwald // COMMAND DISALLOWED if wrong state. 11804a9a543dSMatthias Ringwald if (ll_state != LL_STATE_STANDBY) return 0x0c; 11814a9a543dSMatthias Ringwald 11824a9a543dSMatthias Ringwald ll_state = LL_STATE_SCANNING; 11834a9a543dSMatthias Ringwald 11844a9a543dSMatthias Ringwald log_info("LE Scan Start: window %lu, interval %lu ms", ll_scan_interval_us, ll_scan_window_us); 11854a9a543dSMatthias Ringwald 11864a9a543dSMatthias Ringwald // reset timer and capature events 11874a9a543dSMatthias Ringwald NRF_TIMER0->TASKS_CLEAR = 1; 11884a9a543dSMatthias Ringwald NRF_TIMER0->TASKS_STOP = 1; 11894a9a543dSMatthias Ringwald NRF_TIMER0->EVENTS_COMPARE[0] = 0; 11904a9a543dSMatthias Ringwald NRF_TIMER0->EVENTS_COMPARE[1] = 0; 11914a9a543dSMatthias Ringwald 11924a9a543dSMatthias Ringwald // limit scanning 11934a9a543dSMatthias Ringwald if (ll_scan_window_us < ll_scan_interval_us){ 11944a9a543dSMatthias Ringwald // setup PPI to disable radio after end of scan_window 11954a9a543dSMatthias Ringwald NRF_TIMER0->CC[1] = ll_scan_window_us; 11964a9a543dSMatthias Ringwald NRF_PPI->CHENSET = 1 << 22; // TIMER0->EVENTS_COMPARE[1] -> RADIO->TASKS_DISABLE 11974a9a543dSMatthias Ringwald } 11984a9a543dSMatthias Ringwald 11994a9a543dSMatthias Ringwald // set timer to trigger IRQ for next scan interval 12004a9a543dSMatthias Ringwald NRF_TIMER0->CC[0] = ll_scan_interval_us; 12014a9a543dSMatthias Ringwald NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos; 12024a9a543dSMatthias Ringwald 12034a9a543dSMatthias Ringwald // next channel to scan 12044a9a543dSMatthias Ringwald int adv_channel = (random_generator_next() % 3) + 37; 12054a9a543dSMatthias Ringwald log_debug("LE Scan Channel: %u", adv_channel); 12064a9a543dSMatthias Ringwald 12074a9a543dSMatthias Ringwald // start receiving 12084a9a543dSMatthias Ringwald NRF_TIMER0->TASKS_START = 1; 12094a9a543dSMatthias Ringwald radio_receive_on_channel(adv_channel); 12104a9a543dSMatthias Ringwald #endif 12114a9a543dSMatthias Ringwald return 0; 12124a9a543dSMatthias Ringwald } 12134a9a543dSMatthias Ringwald 12144a9a543dSMatthias Ringwald static uint8_t ll_stop_scanning(void){ 12154a9a543dSMatthias Ringwald #if 0 12164a9a543dSMatthias Ringwald // COMMAND DISALLOWED if wrong state. 12174a9a543dSMatthias Ringwald if (ll_state != LL_STATE_SCANNING) return 0x0c; 12184a9a543dSMatthias Ringwald 12194a9a543dSMatthias Ringwald log_info("LE Scan Stop"); 12204a9a543dSMatthias Ringwald 12214a9a543dSMatthias Ringwald ll_state = LL_STATE_STANDBY; 12224a9a543dSMatthias Ringwald 12234a9a543dSMatthias Ringwald // stop radio 12244a9a543dSMatthias Ringwald radio_disable(); 12254a9a543dSMatthias Ringwald 12264a9a543dSMatthias Ringwald #endif 12274a9a543dSMatthias Ringwald return 0; 12284a9a543dSMatthias Ringwald } 12294a9a543dSMatthias Ringwald 12304a9a543dSMatthias Ringwald uint8_t ll_set_scan_enable(uint8_t le_scan_enable, uint8_t filter_duplicates){ 12314a9a543dSMatthias Ringwald if (le_scan_enable){ 12324a9a543dSMatthias Ringwald return ll_start_scanning(filter_duplicates); 12334a9a543dSMatthias Ringwald } else { 12344a9a543dSMatthias Ringwald return ll_stop_scanning(); 12354a9a543dSMatthias Ringwald } 12364a9a543dSMatthias Ringwald } 12374a9a543dSMatthias Ringwald 12384a9a543dSMatthias Ringwald static uint8_t ll_start_advertising(void){ 12394a9a543dSMatthias Ringwald // COMMAND DISALLOWED if wrong state. 12404a9a543dSMatthias Ringwald if (ll_state != LL_STATE_STANDBY) return ERROR_CODE_COMMAND_DISALLOWED; 12414a9a543dSMatthias Ringwald log_info("Start Advertising on channels 0x%0x, interval %lu us", ctx.adv_map, ctx.adv_interval_us); 12424a9a543dSMatthias Ringwald start_advertising(); 12434a9a543dSMatthias Ringwald return ERROR_CODE_SUCCESS; 12444a9a543dSMatthias Ringwald } 12454a9a543dSMatthias Ringwald 12464a9a543dSMatthias Ringwald static uint8_t ll_stop_advertising(void){ 12474a9a543dSMatthias Ringwald // COMMAND DISALLOWED if wrong state. 12484a9a543dSMatthias Ringwald if (ll_state != LL_STATE_ADVERTISING) return ERROR_CODE_COMMAND_DISALLOWED; 12494a9a543dSMatthias Ringwald 12504a9a543dSMatthias Ringwald // TODO: 12514a9a543dSMatthias Ringwald return ERROR_CODE_SUCCESS; 12524a9a543dSMatthias Ringwald } 12534a9a543dSMatthias Ringwald 12544a9a543dSMatthias Ringwald uint8_t ll_set_advertise_enable(uint8_t le_adv_enable){ 12554a9a543dSMatthias Ringwald if (le_adv_enable){ 12564a9a543dSMatthias Ringwald return ll_start_advertising(); 12574a9a543dSMatthias Ringwald } else { 12584a9a543dSMatthias Ringwald return ll_stop_advertising(); 12594a9a543dSMatthias Ringwald } 12604a9a543dSMatthias Ringwald } 12614a9a543dSMatthias Ringwald 12624a9a543dSMatthias Ringwald uint8_t ll_set_advertising_parameters(uint16_t advertising_interval_min, uint16_t advertising_interval_max, 12634a9a543dSMatthias Ringwald uint8_t advertising_type, uint8_t own_address_type, uint8_t peer_address_types, uint8_t * peer_address, 12644a9a543dSMatthias Ringwald uint8_t advertising_channel_map, uint8_t advertising_filter_policy){ 12654a9a543dSMatthias Ringwald 12664a9a543dSMatthias Ringwald // validate channel map 12674a9a543dSMatthias Ringwald if (advertising_channel_map == 0) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 12684a9a543dSMatthias Ringwald if ((advertising_channel_map & 0xf8) != 0) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 12694a9a543dSMatthias Ringwald 12704a9a543dSMatthias Ringwald // validate advertising interval 12714a9a543dSMatthias Ringwald if (advertising_interval_min < 0x20) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 12724a9a543dSMatthias Ringwald if (advertising_interval_min > 0x4000) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 12734a9a543dSMatthias Ringwald if (advertising_interval_max < 0x20) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 12744a9a543dSMatthias Ringwald if (advertising_interval_max > 0x4000) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 12754a9a543dSMatthias Ringwald if (advertising_interval_min > advertising_interval_max) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 12764a9a543dSMatthias Ringwald 12774a9a543dSMatthias Ringwald ctx.adv_map = advertising_channel_map; 12784a9a543dSMatthias Ringwald ctx.adv_interval_us = advertising_interval_max * 625; 1279*b97c8672SMatthias Ringwald ctx.adv_type= advertising_type; 12804a9a543dSMatthias Ringwald 12814a9a543dSMatthias Ringwald // TODO: validate other params 12824a9a543dSMatthias Ringwald // TODO: process other params 12834a9a543dSMatthias Ringwald 12844a9a543dSMatthias Ringwald return ERROR_CODE_SUCCESS; 12854a9a543dSMatthias Ringwald } 12864a9a543dSMatthias Ringwald 12874a9a543dSMatthias Ringwald uint8_t ll_set_advertising_data(uint8_t adv_len, const uint8_t * adv_data){ 12884a9a543dSMatthias Ringwald // COMMAND DISALLOWED if wrong state. 12894a9a543dSMatthias Ringwald if (ll_state == LL_STATE_ADVERTISING) return ERROR_CODE_COMMAND_DISALLOWED; 12904a9a543dSMatthias Ringwald if (adv_len > 31) return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 12914a9a543dSMatthias Ringwald ctx.adv_len = adv_len; 12924a9a543dSMatthias Ringwald memcpy(ctx.adv_data, adv_data, adv_len); 12934a9a543dSMatthias Ringwald 129485bc6c7fSMatthias Ringwald return ERROR_CODE_SUCCESS; 129585bc6c7fSMatthias Ringwald } 129685bc6c7fSMatthias Ringwald 129785bc6c7fSMatthias Ringwald uint8_t ll_set_scan_response_data(uint8_t adv_len, const uint8_t * adv_data){ 129885bc6c7fSMatthias Ringwald // COMMAND DISALLOWED if wrong state. 129985bc6c7fSMatthias Ringwald if (ll_state == LL_STATE_ADVERTISING) return ERROR_CODE_COMMAND_DISALLOWED; 130085bc6c7fSMatthias Ringwald if (adv_len > 31) return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 130185bc6c7fSMatthias Ringwald ctx.scan_resp_len = adv_len; 130285bc6c7fSMatthias Ringwald memcpy(ctx.scan_resp_data, adv_data, adv_len); 130385bc6c7fSMatthias Ringwald 13044a9a543dSMatthias Ringwald return ERROR_CODE_SUCCESS; 13054a9a543dSMatthias Ringwald } 13064a9a543dSMatthias Ringwald 13074a9a543dSMatthias Ringwald void ll_execute_once(void){ 13084a9a543dSMatthias Ringwald // process received packets 13094a9a543dSMatthias Ringwald while (1){ 13104a9a543dSMatthias Ringwald ll_pdu_t * rx_packet = (ll_pdu_t *) btstack_linked_queue_dequeue(&ctx.rx_queue); 13114a9a543dSMatthias Ringwald if (rx_packet == NULL) break; 13124a9a543dSMatthias Ringwald if (rx_packet->len > 0){ 13134a9a543dSMatthias Ringwald if ((rx_packet->flags & LL_PDU_FLAG_DATA_PDU) == 0){ 13144a9a543dSMatthias Ringwald // ADV PDU 13154a9a543dSMatthias Ringwald // connect ind? 13164a9a543dSMatthias Ringwald if ((rx_packet->header & 0x0f) == PDU_ADV_TYPE_CONNECT_IND){ 13174a9a543dSMatthias Ringwald ll_handle_conn_ind(rx_packet); 13184a9a543dSMatthias Ringwald } 13194a9a543dSMatthias Ringwald else { 13204a9a543dSMatthias Ringwald radio_state = RADIO_LOWPOWER; 13214a9a543dSMatthias Ringwald } 13224a9a543dSMatthias Ringwald } else { 13234a9a543dSMatthias Ringwald // DATA PDU 13244a9a543dSMatthias Ringwald uint8_t ll_id = rx_packet->header & 3; 13254a9a543dSMatthias Ringwald if (ll_id == PDU_DATA_LLID_CTRL) { 13264a9a543dSMatthias Ringwald ll_handle_control(rx_packet); 13274a9a543dSMatthias Ringwald } else { 13284a9a543dSMatthias Ringwald ll_handle_data(rx_packet); 13294a9a543dSMatthias Ringwald } 13304a9a543dSMatthias Ringwald } 13314a9a543dSMatthias Ringwald } 13324a9a543dSMatthias Ringwald // free packet 13334a9a543dSMatthias Ringwald btstack_memory_ll_pdu_free(rx_packet); 13344a9a543dSMatthias Ringwald } 13354a9a543dSMatthias Ringwald 13364a9a543dSMatthias Ringwald switch ( ll_state ){ 13374a9a543dSMatthias Ringwald case LL_STATE_ADVERTISING: 13384a9a543dSMatthias Ringwald ll_advertising_statemachine(); 13394a9a543dSMatthias Ringwald break; 13404a9a543dSMatthias Ringwald default: 13414a9a543dSMatthias Ringwald break; 13424a9a543dSMatthias Ringwald } 13434a9a543dSMatthias Ringwald 13444a9a543dSMatthias Ringwald // generate HCI events 13454a9a543dSMatthias Ringwald 13464a9a543dSMatthias Ringwald // report num complete packets 13474a9a543dSMatthias Ringwald /** critical section start */ 13484a9a543dSMatthias Ringwald hal_cpu_disable_irqs(); 13494a9a543dSMatthias Ringwald uint8_t num_completed = ctx.num_completed; 13504a9a543dSMatthias Ringwald ctx.num_completed = 0; 13514a9a543dSMatthias Ringwald hal_cpu_enable_irqs(); 13524a9a543dSMatthias Ringwald /** critical section end */ 13534a9a543dSMatthias Ringwald if (num_completed > 0){ 13544a9a543dSMatthias Ringwald ll_emit_hci_event(&hci_event_number_of_completed_packets_1, 1, HCI_CON_HANDLE, num_completed); 13554a9a543dSMatthias Ringwald } 13564a9a543dSMatthias Ringwald 13574a9a543dSMatthias Ringwald // report connection event 13584a9a543dSMatthias Ringwald if (ll_send_connection_complete){ 13594a9a543dSMatthias Ringwald ll_send_connection_complete = false; 13604a9a543dSMatthias Ringwald ll_emit_hci_event(&hci_subevent_le_connection_complete, 13614a9a543dSMatthias Ringwald ERROR_CODE_SUCCESS, HCI_CON_HANDLE, 0x01 /* slave */, ctx.peer_addr_type, ctx.peer_addr, 13624a9a543dSMatthias Ringwald ctx.conn_interval_1250us, ctx.conn_latency, ctx.supervision_timeout_10ms, 0 /* master clock accuracy */); 13634a9a543dSMatthias Ringwald } 13644a9a543dSMatthias Ringwald 13654a9a543dSMatthias Ringwald // report disconnection event 13664a9a543dSMatthias Ringwald if (ll_send_disconnected){ 13674a9a543dSMatthias Ringwald ll_send_disconnected = false; 13684a9a543dSMatthias Ringwald ll_emit_hci_event(&hci_event_disconnection_complete, ERROR_CODE_SUCCESS, HCI_CON_HANDLE, 0); 13694a9a543dSMatthias Ringwald } 13704a9a543dSMatthias Ringwald } 13714a9a543dSMatthias Ringwald bool ll_reserve_acl_packet(void){ 13724a9a543dSMatthias Ringwald if (ll_reserved_acl_buffer == NULL){ 13734a9a543dSMatthias Ringwald ll_reserved_acl_buffer = btstack_memory_ll_pdu_get(); 13744a9a543dSMatthias Ringwald } 13754a9a543dSMatthias Ringwald return ll_reserved_acl_buffer != NULL; 13764a9a543dSMatthias Ringwald } 13774a9a543dSMatthias Ringwald 13784a9a543dSMatthias Ringwald void ll_queue_acl_packet(const uint8_t * packet, uint16_t size){ 13794a9a543dSMatthias Ringwald btstack_assert(ll_reserved_acl_buffer != NULL); 13804a9a543dSMatthias Ringwald 13814a9a543dSMatthias Ringwald ll_pdu_t * tx_packet = ll_reserved_acl_buffer; 13824a9a543dSMatthias Ringwald ll_reserved_acl_buffer = NULL; 13834a9a543dSMatthias Ringwald 13844a9a543dSMatthias Ringwald switch ((packet[1] >> 4) & 0x03){ 13854a9a543dSMatthias Ringwald case 0: 13864a9a543dSMatthias Ringwald case 2: 13874a9a543dSMatthias Ringwald tx_packet->header = PDU_DATA_LLID_DATA_START; 13884a9a543dSMatthias Ringwald break; 13894a9a543dSMatthias Ringwald case 1: 13904a9a543dSMatthias Ringwald tx_packet->header = PDU_DATA_LLID_DATA_CONTINUE; 13914a9a543dSMatthias Ringwald break; 13924a9a543dSMatthias Ringwald case 3: 13934a9a543dSMatthias Ringwald while(1); 13944a9a543dSMatthias Ringwald break; 13954a9a543dSMatthias Ringwald default: 13964a9a543dSMatthias Ringwald break; 13974a9a543dSMatthias Ringwald } 13984a9a543dSMatthias Ringwald tx_packet->len = size - 4; 13994a9a543dSMatthias Ringwald memcpy(tx_packet->payload, &packet[4], size - 4); 14004a9a543dSMatthias Ringwald btstack_linked_queue_enqueue(&ctx.tx_queue, (btstack_linked_item_t *) tx_packet); 14014a9a543dSMatthias Ringwald } 14024a9a543dSMatthias Ringwald 14034a9a543dSMatthias Ringwald void ll_register_packet_handler(void (*packet_handler)(uint8_t packet_type, uint8_t * packet, uint16_t size)){ 14044a9a543dSMatthias Ringwald controller_packet_handler = packet_handler; 14054a9a543dSMatthias Ringwald } 1406