xref: /btstack/chipset/sx128x/ll_sx1280.c (revision f8278fd5f20b332de01bdcd7c78c85b333f93c6a)
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,
1714a9a543dSMatthias Ringwald     RADIO_W4_TIMER,
1724a9a543dSMatthias Ringwald } radio_state_t;
1734a9a543dSMatthias Ringwald 
1744a9a543dSMatthias Ringwald // Link Layer State
1754a9a543dSMatthias Ringwald typedef enum {
1764a9a543dSMatthias Ringwald     LL_STATE_STANDBY,
1774a9a543dSMatthias Ringwald     LL_STATE_SCANNING,
1784a9a543dSMatthias Ringwald     LL_STATE_ADVERTISING,
1794a9a543dSMatthias Ringwald     LL_STATE_INITIATING,
1804a9a543dSMatthias Ringwald     LL_STATE_CONNECTED
1814a9a543dSMatthias Ringwald } ll_state_t;
1824a9a543dSMatthias Ringwald 
1834a9a543dSMatthias Ringwald // Link Layer PDU Flags
1844a9a543dSMatthias Ringwald typedef enum {
1854a9a543dSMatthias Ringwald     LL_PDU_FLAG_DATA_PDU = 1,
1864a9a543dSMatthias Ringwald } ll_pdu_flags;
1874a9a543dSMatthias Ringwald 
1884a9a543dSMatthias Ringwald // Link Layer PDU, used in linked list
1894a9a543dSMatthias Ringwald typedef struct {
1904a9a543dSMatthias Ringwald     // header
1914a9a543dSMatthias Ringwald     void *                 item;
1924a9a543dSMatthias Ringwald     hci_con_handle_t       con_handle;
1934a9a543dSMatthias Ringwald     uint8_t                flags;
1944a9a543dSMatthias Ringwald     // over the air data
1954a9a543dSMatthias Ringwald     uint8_t                header;
1964a9a543dSMatthias Ringwald     uint8_t                len;
1974a9a543dSMatthias Ringwald     uint8_t                payload[LL_MAX_PAYLOAD];
1984a9a543dSMatthias Ringwald } ll_pdu_t;
1994a9a543dSMatthias Ringwald 
2004a9a543dSMatthias Ringwald // channel table: freq in hertz and whitening seed
2014a9a543dSMatthias Ringwald static const struct {
2024a9a543dSMatthias Ringwald     uint32_t freq_hz;
2034a9a543dSMatthias Ringwald     uint8_t  whitening;
2044a9a543dSMatthias Ringwald }  channel_table[] = {
2054a9a543dSMatthias Ringwald         { 2404000000, 0x01 /* 00000001 */ },
2064a9a543dSMatthias Ringwald         { 2406000000, 0x41 /* 01000001 */ },
2074a9a543dSMatthias Ringwald         { 2408000000, 0x21 /* 00100001 */ },
2084a9a543dSMatthias Ringwald         { 2410000000, 0x61 /* 01100001 */ },
2094a9a543dSMatthias Ringwald         { 2412000000, 0x11 /* 00010001 */ },
2104a9a543dSMatthias Ringwald         { 2414000000, 0x51 /* 01010001 */ },
2114a9a543dSMatthias Ringwald         { 2416000000, 0x31 /* 00110001 */ },
2124a9a543dSMatthias Ringwald         { 2418000000, 0x71 /* 01110001 */ },
2134a9a543dSMatthias Ringwald         { 2420000000, 0x09 /* 00001001 */ },
2144a9a543dSMatthias Ringwald         { 2422000000, 0x49 /* 01001001 */ },
2154a9a543dSMatthias Ringwald         { 2424000000, 0x29 /* 00101001 */ },
2164a9a543dSMatthias Ringwald         { 2428000000, 0x69 /* 01101001 */ },
2174a9a543dSMatthias Ringwald         { 2430000000, 0x19 /* 00011001 */ },
2184a9a543dSMatthias Ringwald         { 2432000000, 0x59 /* 01011001 */ },
2194a9a543dSMatthias Ringwald         { 2434000000, 0x39 /* 00111001 */ },
2204a9a543dSMatthias Ringwald         { 2436000000, 0x79 /* 01111001 */ },
2214a9a543dSMatthias Ringwald         { 2438000000, 0x05 /* 00000101 */ },
2224a9a543dSMatthias Ringwald         { 2440000000, 0x45 /* 01000101 */ },
2234a9a543dSMatthias Ringwald         { 2442000000, 0x25 /* 00100101 */ },
2244a9a543dSMatthias Ringwald         { 2444000000, 0x65 /* 01100101 */ },
2254a9a543dSMatthias Ringwald         { 2446000000, 0x15 /* 00010101 */ },
2264a9a543dSMatthias Ringwald         { 2448000000, 0x55 /* 01010101 */ },
2274a9a543dSMatthias Ringwald         { 2450000000, 0x35 /* 00110101 */ },
2284a9a543dSMatthias Ringwald         { 2452000000, 0x75 /* 01110101 */ },
2294a9a543dSMatthias Ringwald         { 2454000000, 0x0d /* 00001101 */ },
2304a9a543dSMatthias Ringwald         { 2456000000, 0x4d /* 01001101 */ },
2314a9a543dSMatthias Ringwald         { 2458000000, 0x2d /* 00101101 */ },
2324a9a543dSMatthias Ringwald         { 2460000000, 0x6d /* 01101101 */ },
2334a9a543dSMatthias Ringwald         { 2462000000, 0x1d /* 00011101 */ },
2344a9a543dSMatthias Ringwald         { 2464000000, 0x5d /* 01011101 */ },
2354a9a543dSMatthias Ringwald         { 2466000000, 0x3d /* 00111101 */ },
2364a9a543dSMatthias Ringwald         { 2468000000, 0x7d /* 01111101 */ },
2374a9a543dSMatthias Ringwald         { 2470000000, 0x03 /* 00000011 */ },
2384a9a543dSMatthias Ringwald         { 2472000000, 0x43 /* 01000011 */ },
2394a9a543dSMatthias Ringwald         { 2474000000, 0x23 /* 00100011 */ },
2404a9a543dSMatthias Ringwald         { 2476000000, 0x63 /* 01100011 */ },
2414a9a543dSMatthias Ringwald         { 2478000000, 0x13 /* 00010011 */ },
2424a9a543dSMatthias Ringwald         { 2402000000, 0x53 /* 01010011 */ },
2434a9a543dSMatthias Ringwald         { 2426000000, 0x33 /* 00110011 */ },
2444a9a543dSMatthias Ringwald         { 2480000000, 0x73 /* 01110011 */ },
2454a9a543dSMatthias Ringwald };
2464a9a543dSMatthias Ringwald 
247*f8278fd5SMatthias Ringwald // tx buffer offset
248*f8278fd5SMatthias Ringwald static uint8_t tx_buffer_offset[] = {
249*f8278fd5SMatthias Ringwald         SX1280_TX0_OFFSET,
250*f8278fd5SMatthias Ringwald         SX1280_TX1_OFFSET
251*f8278fd5SMatthias Ringwald };
252*f8278fd5SMatthias Ringwald 
2534a9a543dSMatthias Ringwald // hopping context
2544a9a543dSMatthias Ringwald static hopping_t h;
2554a9a543dSMatthias Ringwald 
2564a9a543dSMatthias Ringwald static struct {
2574a9a543dSMatthias Ringwald 
2584a9a543dSMatthias Ringwald     volatile bool     synced;
2594a9a543dSMatthias Ringwald 
2604a9a543dSMatthias Ringwald     volatile uint16_t packet_nr_in_connection_event;
2614a9a543dSMatthias Ringwald 
2624a9a543dSMatthias Ringwald     volatile uint16_t conn_interval_1250us;
2634a9a543dSMatthias Ringwald     volatile uint32_t conn_interval_us;
264c3c27692SMatthias Ringwald 	volatile uint16_t conn_interval_ticks;
2654a9a543dSMatthias Ringwald 
2664a9a543dSMatthias Ringwald     volatile uint16_t conn_latency;
2674a9a543dSMatthias Ringwald 
2684a9a543dSMatthias Ringwald     volatile uint16_t supervision_timeout_10ms;
2694a9a543dSMatthias Ringwald     volatile uint32_t supervision_timeout_us;
2704a9a543dSMatthias Ringwald 
2714a9a543dSMatthias Ringwald     //
2724a9a543dSMatthias Ringwald     volatile uint32_t time_without_any_packets_us;
2734a9a543dSMatthias Ringwald 
2744a9a543dSMatthias Ringwald     // access address
2754a9a543dSMatthias Ringwald     volatile uint32_t aa;
2764a9a543dSMatthias Ringwald 
2774a9a543dSMatthias Ringwald     // start of current connection event
2784a9a543dSMatthias Ringwald     volatile uint16_t anchor_ticks;
2794a9a543dSMatthias Ringwald 
280f6933f57SMatthias Ringwald 	// latest time to send tx packet before sync hop
281f6933f57SMatthias Ringwald 	volatile uint16_t conn_latest_tx_ticks;
282f6933f57SMatthias Ringwald 
283c3c27692SMatthias Ringwald 	// timeout for sync relative to anchor
284c3c27692SMatthias Ringwald 	volatile uint16_t conn_sync_hop_ticks;
285c3c27692SMatthias Ringwald 
2864a9a543dSMatthias Ringwald     // current channel
2874a9a543dSMatthias Ringwald     volatile uint8_t  channel;
2884a9a543dSMatthias Ringwald 
2894a9a543dSMatthias Ringwald     // CSA #2 supported
2904a9a543dSMatthias Ringwald     uint8_t csa2_support;
2914a9a543dSMatthias Ringwald 
2924a9a543dSMatthias Ringwald     // channels selection algorithm index (1 for csa #2)
2934a9a543dSMatthias Ringwald     volatile uint8_t channel_selection_algorithm;
2944a9a543dSMatthias Ringwald 
2954a9a543dSMatthias Ringwald     // current connection event, first one starts with 0
2964a9a543dSMatthias Ringwald     // - needed for connection param and channel map updates as well as encryption
2974a9a543dSMatthias Ringwald     volatile uint16_t connection_event;
2984a9a543dSMatthias Ringwald 
2994a9a543dSMatthias Ringwald     // pending channel map update
3004a9a543dSMatthias Ringwald     volatile bool     channel_map_update_pending;
3014a9a543dSMatthias Ringwald     volatile uint16_t channel_map_update_instant;
3024a9a543dSMatthias Ringwald     volatile uint8_t  channel_map_update_map[5];
3034a9a543dSMatthias Ringwald 
3044a9a543dSMatthias Ringwald     // pending connection param update
3054a9a543dSMatthias Ringwald     volatile bool     conn_param_update_pending;
3064a9a543dSMatthias Ringwald     volatile uint16_t conn_param_update_instant;
3074a9a543dSMatthias Ringwald     volatile uint8_t  conn_param_update_win_size;
3084a9a543dSMatthias Ringwald     volatile uint16_t conn_param_update_win_offset;
309982f09b4SMatthias Ringwald     volatile uint16_t conn_param_update_interval_1250us;
3104a9a543dSMatthias Ringwald     volatile uint16_t conn_param_update_latency;
3114a9a543dSMatthias Ringwald     volatile uint32_t conn_param_update_timeout_us;
3124a9a543dSMatthias Ringwald 
3134a9a543dSMatthias Ringwald     // our bd_addr as little endian
3144a9a543dSMatthias Ringwald     uint8_t bd_addr_le[6];
3154a9a543dSMatthias Ringwald 
3164a9a543dSMatthias Ringwald     // peer addr
3174a9a543dSMatthias Ringwald     uint8_t peer_addr_type;
3184a9a543dSMatthias Ringwald     uint8_t peer_addr[6];
3194a9a543dSMatthias Ringwald 
3204a9a543dSMatthias Ringwald     // adv data
3214a9a543dSMatthias Ringwald     uint8_t adv_len;
3224a9a543dSMatthias Ringwald     uint8_t adv_data[31];
3234a9a543dSMatthias Ringwald 
3244a9a543dSMatthias Ringwald     // adv param
3254a9a543dSMatthias Ringwald     uint8_t  adv_map;
3264a9a543dSMatthias Ringwald     uint32_t adv_interval_us;
3274a9a543dSMatthias Ringwald 
3284a9a543dSMatthias Ringwald     // next expected sequence number
3294a9a543dSMatthias Ringwald     volatile uint8_t next_expected_sequence_number;
3304a9a543dSMatthias Ringwald 
3314a9a543dSMatthias Ringwald     // transmit sequence number
3324a9a543dSMatthias Ringwald     volatile uint8_t transmit_sequence_number;
3334a9a543dSMatthias Ringwald 
3344a9a543dSMatthias Ringwald     // num completed packets
3354a9a543dSMatthias Ringwald     volatile uint8_t num_completed;
3364a9a543dSMatthias Ringwald 
337*f8278fd5SMatthias Ringwald     // rx queue
338*f8278fd5SMatthias Ringwald     btstack_linked_queue_t rx_queue;
3394a9a543dSMatthias Ringwald 
3406511f47bSMatthias Ringwald     // current incoming packet
3414a9a543dSMatthias Ringwald     ll_pdu_t * rx_pdu;
3424a9a543dSMatthias Ringwald 
343*f8278fd5SMatthias Ringwald     // tx queue of outgoing pdus
3444a9a543dSMatthias Ringwald     btstack_linked_queue_t tx_queue;
3454a9a543dSMatthias Ringwald 
346*f8278fd5SMatthias Ringwald     // pdus transferred into controller tx buffers
347*f8278fd5SMatthias Ringwald     ll_pdu_t * tx_buffer_pdu[2];
348*f8278fd5SMatthias Ringwald 
349*f8278fd5SMatthias Ringwald     // manage tx packets on controller
350*f8278fd5SMatthias Ringwald     uint8_t num_tx_pdus_on_controller;
351*f8278fd5SMatthias Ringwald 
352*f8278fd5SMatthias Ringwald     // index of next tx buffer to send
353*f8278fd5SMatthias Ringwald     uint8_t next_tx_buffer;
3544a9a543dSMatthias Ringwald 
3554a9a543dSMatthias Ringwald } ctx;
3564a9a543dSMatthias Ringwald 
3574a9a543dSMatthias Ringwald static radio_state_t radio_state = RADIO_LOWPOWER;
3584a9a543dSMatthias Ringwald 
3594a9a543dSMatthias Ringwald // Buffer pool
3604a9a543dSMatthias Ringwald static ll_pdu_t ll_pdu_pool_storage[MAX_NUM_LL_PDUS];
3614a9a543dSMatthias Ringwald static btstack_memory_pool_t ll_pdu_pool;
3624a9a543dSMatthias Ringwald 
3634a9a543dSMatthias Ringwald // single ll control response
3644a9a543dSMatthias Ringwald static ll_pdu_t ll_tx_packet;
3654a9a543dSMatthias Ringwald 
3664a9a543dSMatthias Ringwald // Link Layer State
3674a9a543dSMatthias Ringwald static ll_state_t ll_state;
3684a9a543dSMatthias Ringwald static uint32_t ll_scan_interval_us;
3694a9a543dSMatthias Ringwald static uint32_t ll_scan_window_us;
3704a9a543dSMatthias Ringwald 
3714a9a543dSMatthias Ringwald static ll_pdu_t * ll_reserved_acl_buffer;
3724a9a543dSMatthias Ringwald static void (*controller_packet_handler)(uint8_t packet_type, uint8_t * packet, uint16_t size);
3734a9a543dSMatthias Ringwald 
3744a9a543dSMatthias Ringwald static uint8_t ll_outgoing_hci_event[258];
3754a9a543dSMatthias Ringwald static bool ll_send_disconnected;
3764a9a543dSMatthias Ringwald static bool ll_send_connection_complete;
3774a9a543dSMatthias Ringwald 
3784a9a543dSMatthias Ringwald // prototypes
3794a9a543dSMatthias Ringwald static void radio_set_timer_ticks(uint32_t anchor_offset_ticks);
3804a9a543dSMatthias Ringwald 
3814a9a543dSMatthias Ringwald 
3824a9a543dSMatthias Ringwald // memory pool for acl-le pdus
3834a9a543dSMatthias Ringwald static ll_pdu_t * btstack_memory_ll_pdu_get(void){
3844a9a543dSMatthias Ringwald     void * buffer = btstack_memory_pool_get(&ll_pdu_pool);
3854a9a543dSMatthias Ringwald     if (buffer){
3864a9a543dSMatthias Ringwald         memset(buffer, 0, sizeof(ll_pdu_t));
3874a9a543dSMatthias Ringwald     }
3884a9a543dSMatthias Ringwald     return (ll_pdu_t *) buffer;
3894a9a543dSMatthias Ringwald }
3904a9a543dSMatthias Ringwald 
3914a9a543dSMatthias Ringwald static void btstack_memory_ll_pdu_free(ll_pdu_t *acl_le_pdu){
3924a9a543dSMatthias Ringwald     btstack_memory_pool_free(&ll_pdu_pool, acl_le_pdu);
3934a9a543dSMatthias Ringwald }
3944a9a543dSMatthias Ringwald 
3954a9a543dSMatthias Ringwald 
3964a9a543dSMatthias Ringwald static bool receive_prepare_rx_bufffer(void){
3974a9a543dSMatthias Ringwald     if (ctx.rx_pdu == NULL){
3984a9a543dSMatthias Ringwald         ctx.rx_pdu = btstack_memory_ll_pdu_get();
3994a9a543dSMatthias Ringwald     }
4004a9a543dSMatthias Ringwald     if (ctx.rx_pdu == NULL){
4014a9a543dSMatthias Ringwald         printf("No free RX buffer\n");
4024a9a543dSMatthias Ringwald         return false;
4034a9a543dSMatthias Ringwald     } else {
4044a9a543dSMatthias Ringwald         return true;
4054a9a543dSMatthias Ringwald     }
4064a9a543dSMatthias Ringwald }
4074a9a543dSMatthias Ringwald 
4089c622d6fSMatthias Ringwald static void receive_response(void){
4094a9a543dSMatthias Ringwald     if (receive_prepare_rx_bufffer()) {
4104a9a543dSMatthias Ringwald         Radio.SetRx( ( TickTime_t ) { RADIO_TICK_SIZE_0015_US, 10 } );  // 220 us
4114a9a543dSMatthias Ringwald     }
4124a9a543dSMatthias Ringwald }
4134a9a543dSMatthias Ringwald 
4144a9a543dSMatthias Ringwald static void receive_first_master(void){
4154a9a543dSMatthias Ringwald     if (receive_prepare_rx_bufffer()){
4164a9a543dSMatthias Ringwald         Radio.SetRx( ( TickTime_t ) { RADIO_TICK_SIZE_1000_US, 1000 } );
4174a9a543dSMatthias Ringwald     }
4184a9a543dSMatthias Ringwald }
4194a9a543dSMatthias Ringwald 
4204a9a543dSMatthias Ringwald static void receive_master(void){
4214a9a543dSMatthias Ringwald     if (receive_prepare_rx_bufffer()) {
4224a9a543dSMatthias Ringwald         Radio.SetRx((TickTime_t) {RADIO_TICK_SIZE_1000_US, 1});
4234a9a543dSMatthias Ringwald     }
4244a9a543dSMatthias Ringwald }
4254a9a543dSMatthias Ringwald 
4264a9a543dSMatthias Ringwald 
4274a9a543dSMatthias Ringwald static void send_adv(void){
4284a9a543dSMatthias Ringwald     // setup advertisement: header (2) + addr (6) + data (31)
4294a9a543dSMatthias Ringwald     uint8_t adv_buffer[39];
4304a9a543dSMatthias Ringwald     adv_buffer[0] = PDU_ADV_TYPE_ADV_IND;  // TODO: also set private address bits
4314a9a543dSMatthias Ringwald     adv_buffer[1] = 6 + ctx.adv_len;
4324a9a543dSMatthias Ringwald     memcpy(&adv_buffer[2], ctx.bd_addr_le, 6);
4334a9a543dSMatthias Ringwald     memcpy(&adv_buffer[8], ctx.adv_data, ctx.adv_len);
4344a9a543dSMatthias Ringwald     uint16_t packet_size = 2 + adv_buffer[1];
4354a9a543dSMatthias Ringwald     SX1280HalWriteBuffer( SX1280_TX0_OFFSET, adv_buffer, packet_size );
4364a9a543dSMatthias Ringwald     SX1280SetTx( ( TickTime_t ){ RADIO_TICK_SIZE_1000_US, 1 } );
4374a9a543dSMatthias Ringwald }
4384a9a543dSMatthias Ringwald 
4394a9a543dSMatthias Ringwald 
4404a9a543dSMatthias Ringwald static void select_channel(uint8_t channel){
4414a9a543dSMatthias Ringwald     // Set Whitening seed
4424a9a543dSMatthias Ringwald     Radio.SetWhiteningSeed( channel_table[channel].whitening );
4434a9a543dSMatthias Ringwald 
4444a9a543dSMatthias Ringwald     // Sel Frequency
4454a9a543dSMatthias Ringwald     Radio.SetRfFrequency( channel_table[channel].freq_hz );
4464a9a543dSMatthias Ringwald }
4474a9a543dSMatthias Ringwald 
4484a9a543dSMatthias Ringwald static void next_channel(void){
4494a9a543dSMatthias Ringwald     switch (ctx.channel_selection_algorithm){
4504a9a543dSMatthias Ringwald         case 0:
4514a9a543dSMatthias Ringwald             ctx.channel = hopping_csa1_get_next_channel( &h );
4524a9a543dSMatthias Ringwald             break;
4534a9a543dSMatthias Ringwald         case 1:
4544a9a543dSMatthias Ringwald             ctx.channel = hopping_csa2_get_channel_for_counter( &h,  ctx.connection_event);
4554a9a543dSMatthias Ringwald             break;
4564a9a543dSMatthias Ringwald         default:
4574a9a543dSMatthias Ringwald             break;
4584a9a543dSMatthias Ringwald     }
4594a9a543dSMatthias Ringwald     select_channel(ctx.channel);
4604a9a543dSMatthias Ringwald }
4614a9a543dSMatthias Ringwald 
4624a9a543dSMatthias Ringwald static void ll_advertising_statemachine(void){
4634a9a543dSMatthias Ringwald     switch ( radio_state) {
4644a9a543dSMatthias Ringwald         case RADIO_RX_ERROR:
4654a9a543dSMatthias Ringwald         case RADIO_LOWPOWER:
4664a9a543dSMatthias Ringwald             // find next channel
4674a9a543dSMatthias Ringwald             while (ctx.channel < 40){
4684a9a543dSMatthias Ringwald                 ctx.channel++;
4694a9a543dSMatthias Ringwald                 if ((ctx.adv_map & (1 << (ctx.channel - 37))) != 0) {
4704a9a543dSMatthias Ringwald                     // Set Channel
4714a9a543dSMatthias Ringwald                     select_channel(ctx.channel);
4724a9a543dSMatthias Ringwald                     radio_state = RADIO_W4_TX_DONE_TO_RX;
4734a9a543dSMatthias Ringwald                     send_adv();
4744a9a543dSMatthias Ringwald                     break;
4754a9a543dSMatthias Ringwald                 }
4764a9a543dSMatthias Ringwald                 if (ctx.channel >= 40){
4774a9a543dSMatthias Ringwald                     // Set timer
4784a9a543dSMatthias Ringwald                     radio_state = RADIO_W4_TIMER;
4794a9a543dSMatthias Ringwald                     uint32_t adv_interval_ticks = US_TO_TICKS(ctx.adv_interval_us);
4804a9a543dSMatthias Ringwald                     radio_set_timer_ticks(adv_interval_ticks);
4814a9a543dSMatthias Ringwald                 }
4824a9a543dSMatthias Ringwald             }
4834a9a543dSMatthias Ringwald             break;
4844a9a543dSMatthias Ringwald         default:
4854a9a543dSMatthias Ringwald             break;
4864a9a543dSMatthias Ringwald     }
4874a9a543dSMatthias Ringwald }
4884a9a543dSMatthias Ringwald 
4894a9a543dSMatthias Ringwald static void start_advertising(void){
4904a9a543dSMatthias Ringwald 
4914a9a543dSMatthias Ringwald     Radio.StopAutoTx();
4924a9a543dSMatthias Ringwald 
4934a9a543dSMatthias Ringwald     PacketParams_t packetParams;
4944a9a543dSMatthias Ringwald     packetParams.PacketType = PACKET_TYPE_BLE;
4954a9a543dSMatthias Ringwald     packetParams.Params.Ble.BlePacketType = BLE_EYELONG_1_0;
4964a9a543dSMatthias Ringwald     packetParams.Params.Ble.ConnectionState = BLE_PAYLOAD_LENGTH_MAX_37_BYTES;
4974a9a543dSMatthias Ringwald     packetParams.Params.Ble.CrcField = BLE_CRC_3B;
4984a9a543dSMatthias Ringwald     packetParams.Params.Ble.Whitening = RADIO_WHITENING_ON;
4994a9a543dSMatthias Ringwald     Radio.SetPacketParams( &packetParams );
5004a9a543dSMatthias Ringwald 
5014a9a543dSMatthias Ringwald     // Set CRC init value 0x555555
5024a9a543dSMatthias Ringwald     Radio.WriteRegister(0x9c7, 0x55 );
5034a9a543dSMatthias Ringwald     Radio.WriteRegister(0x9c8, 0x55 );
5044a9a543dSMatthias Ringwald     Radio.WriteRegister(0x9c9, 0x55 );
5054a9a543dSMatthias Ringwald 
5064a9a543dSMatthias Ringwald     // Set AccessAddress for ADV packets
5074a9a543dSMatthias Ringwald     Radio.SetBleAdvertizerAccessAddress( );
5084a9a543dSMatthias Ringwald 
5094a9a543dSMatthias Ringwald     radio_state = RADIO_LOWPOWER;
5104a9a543dSMatthias Ringwald     ll_state = LL_STATE_ADVERTISING;
5114a9a543dSMatthias Ringwald 
5124a9a543dSMatthias Ringwald     // prepare
5134a9a543dSMatthias Ringwald     ctx.channel = 36;
5144a9a543dSMatthias Ringwald     ctx.anchor_ticks = hal_timer_get_ticks();
5154a9a543dSMatthias Ringwald 
5164a9a543dSMatthias Ringwald     // and get started
5174a9a543dSMatthias Ringwald     ll_advertising_statemachine();
5184a9a543dSMatthias Ringwald }
5194a9a543dSMatthias Ringwald 
5204a9a543dSMatthias Ringwald static void start_hopping(void){
5214a9a543dSMatthias Ringwald     PacketParams_t packetParams;
5224a9a543dSMatthias Ringwald     packetParams.PacketType = PACKET_TYPE_BLE;
5234a9a543dSMatthias Ringwald     packetParams.Params.Ble.BlePacketType = BLE_EYELONG_1_0;
5244a9a543dSMatthias Ringwald     packetParams.Params.Ble.ConnectionState = BLE_PAYLOAD_LENGTH_MAX_31_BYTES;
5254a9a543dSMatthias Ringwald     packetParams.Params.Ble.CrcField = BLE_CRC_3B;
5264a9a543dSMatthias Ringwald     packetParams.Params.Ble.Whitening = RADIO_WHITENING_ON;
5274a9a543dSMatthias Ringwald     Radio.SetPacketParams( &packetParams );
5284a9a543dSMatthias Ringwald 
5294a9a543dSMatthias Ringwald }
5304a9a543dSMatthias Ringwald 
5314a9a543dSMatthias Ringwald static void radio_stop_timer(void){
5324a9a543dSMatthias Ringwald     hal_timer_stop();
5334a9a543dSMatthias Ringwald }
5344a9a543dSMatthias Ringwald 
5354a9a543dSMatthias Ringwald static void radio_set_timer_ticks(uint32_t anchor_offset_ticks){
5364a9a543dSMatthias Ringwald     radio_stop_timer();
5374a9a543dSMatthias Ringwald     // set timer for next radio event relative to anchor
5384a9a543dSMatthias Ringwald     uint16_t timeout_ticks = (uint16_t) (ctx.anchor_ticks + anchor_offset_ticks);
5394a9a543dSMatthias Ringwald     hal_timer_start(timeout_ticks);
5404a9a543dSMatthias Ringwald }
5414a9a543dSMatthias Ringwald 
542eed650bfSMatthias Ringwald static void ctx_set_conn_interval(uint16_t conn_interval_1250us){
543eed650bfSMatthias Ringwald 	ctx.conn_interval_1250us = conn_interval_1250us;
544c3c27692SMatthias Ringwald 	ctx.conn_interval_us     = ctx.conn_interval_1250us * 1250;
545c3c27692SMatthias Ringwald 	ctx.conn_interval_ticks  = US_TO_TICKS(ctx.conn_interval_us);
546c3c27692SMatthias Ringwald 	ctx.conn_sync_hop_ticks  = US_TO_TICKS(ctx.conn_interval_us - SYNC_HOP_DELAY_US);
547f6933f57SMatthias Ringwald 
548f6933f57SMatthias Ringwald 	// latest time to send a packet before getting ready for next cnonection event
549f6933f57SMatthias Ringwald 	uint16_t max_packet_time_incl_ifs_us = 500;
550f6933f57SMatthias Ringwald 	ctx.conn_latest_tx_ticks = US_TO_TICKS(ctx.conn_interval_us - SYNC_HOP_DELAY_US - max_packet_time_incl_ifs_us);
551eed650bfSMatthias Ringwald }
552eed650bfSMatthias Ringwald 
5534a9a543dSMatthias Ringwald static void ll_terminate(void){
5544a9a543dSMatthias Ringwald     ll_state = LL_STATE_STANDBY;
5554a9a543dSMatthias Ringwald     ctx.conn_param_update_pending = false;
5564a9a543dSMatthias Ringwald     ctx.channel_map_update_pending = false;
5574a9a543dSMatthias Ringwald     // stop sync hop timer
5584a9a543dSMatthias Ringwald     radio_stop_timer();
559*f8278fd5SMatthias Ringwald     // free outgoing tx packets
560*f8278fd5SMatthias Ringwald     uint8_t i;
561*f8278fd5SMatthias Ringwald     for (i=0;i<2;i++){
562*f8278fd5SMatthias Ringwald         if ((ctx.tx_buffer_pdu[i] != NULL) && (ctx.tx_buffer_pdu[i] != &ll_tx_packet)){
563*f8278fd5SMatthias Ringwald             btstack_memory_ll_pdu_free(ctx.tx_buffer_pdu[i]);
564*f8278fd5SMatthias Ringwald             ctx.tx_buffer_pdu[i] = NULL;
565*f8278fd5SMatthias Ringwald         }
5664a9a543dSMatthias Ringwald     }
5674a9a543dSMatthias Ringwald     // free queued tx packets
5684a9a543dSMatthias Ringwald     while (true){
5694a9a543dSMatthias Ringwald         ll_pdu_t * tx_packet = (ll_pdu_t *) btstack_linked_queue_dequeue(&ctx.tx_queue);
5704a9a543dSMatthias Ringwald         if (tx_packet != NULL) {
5714a9a543dSMatthias Ringwald             btstack_memory_ll_pdu_free(tx_packet);
5724a9a543dSMatthias Ringwald         } else {
5734a9a543dSMatthias Ringwald             break;
5744a9a543dSMatthias Ringwald         }
5754a9a543dSMatthias Ringwald     }
5764a9a543dSMatthias Ringwald     // disable auto tx
5774a9a543dSMatthias Ringwald     Radio.StopAutoTx();
5784a9a543dSMatthias Ringwald     // notify host stack
5794a9a543dSMatthias Ringwald     ll_send_disconnected = true;
5804a9a543dSMatthias Ringwald }
5814a9a543dSMatthias Ringwald 
582*f8278fd5SMatthias Ringwald // load queued tx pdu into next free tx buffer
583*f8278fd5SMatthias Ringwald static void preload_tx_buffer(void){
584*f8278fd5SMatthias Ringwald     if (ctx.num_tx_pdus_on_controller >= 2) return;
585*f8278fd5SMatthias Ringwald 
586*f8278fd5SMatthias Ringwald     ll_pdu_t * tx_pdu = (ll_pdu_t *) btstack_linked_queue_dequeue(&ctx.tx_queue);
587*f8278fd5SMatthias Ringwald     if (tx_pdu == NULL) return;
588*f8278fd5SMatthias Ringwald 
589*f8278fd5SMatthias Ringwald 	const uint16_t max_packet_len = 2 + 27;
590*f8278fd5SMatthias Ringwald     uint8_t index = (ctx.next_tx_buffer + ctx.num_tx_pdus_on_controller) & 1;
591*f8278fd5SMatthias Ringwald     ctx.tx_buffer_pdu[index] = tx_pdu;
592*f8278fd5SMatthias Ringwald     SX1280HalWriteBuffer( tx_buffer_offset[index], (uint8_t *) &ctx.tx_buffer_pdu[index]->header, max_packet_len);
593*f8278fd5SMatthias Ringwald 
594*f8278fd5SMatthias Ringwald     ctx.num_tx_pdus_on_controller++;
595*f8278fd5SMatthias Ringwald 	// printf("preload %u bytes into %u\n", ctx.tx_buffer_pdu[index]->len, index);
596*f8278fd5SMatthias Ringwald }
597*f8278fd5SMatthias Ringwald 
5984a9a543dSMatthias Ringwald static void radio_timer_handler(void){
5994a9a543dSMatthias Ringwald 
6004a9a543dSMatthias Ringwald     uint16_t t0 = hal_timer_get_ticks();
6014a9a543dSMatthias Ringwald 
6024a9a543dSMatthias Ringwald     switch (ll_state){
6034a9a543dSMatthias Ringwald         case LL_STATE_CONNECTED:
6044a9a543dSMatthias Ringwald             // check supervision timeout
6054a9a543dSMatthias Ringwald             ctx.time_without_any_packets_us += ctx.conn_interval_us;
6064a9a543dSMatthias Ringwald             if (ctx.time_without_any_packets_us > ctx.supervision_timeout_us) {
6074a9a543dSMatthias Ringwald                 printf("Supervision timeout\n\n");
6084a9a543dSMatthias Ringwald                 ll_terminate();
6094a9a543dSMatthias Ringwald                 return;
6104a9a543dSMatthias Ringwald             }
6114a9a543dSMatthias Ringwald 
6124a9a543dSMatthias Ringwald             // prepare next connection event
6134a9a543dSMatthias Ringwald             ctx.connection_event++;
614c3c27692SMatthias Ringwald             ctx.anchor_ticks += ctx.conn_interval_ticks;
6154a9a543dSMatthias Ringwald 
6164a9a543dSMatthias Ringwald             ctx.packet_nr_in_connection_event = 0;
6174a9a543dSMatthias Ringwald             next_channel();
6184a9a543dSMatthias Ringwald 
6194a9a543dSMatthias Ringwald             if (ctx.channel_map_update_pending && (ctx.channel_map_update_instant == ctx.connection_event)) {
6204a9a543dSMatthias Ringwald                 hopping_set_channel_map( &h, (const uint8_t *) &ctx.channel_map_update_map );
6214a9a543dSMatthias Ringwald                 ctx.channel_map_update_pending = false;
6224a9a543dSMatthias Ringwald             }
6234a9a543dSMatthias Ringwald 
6244a9a543dSMatthias Ringwald             if (ctx.conn_param_update_pending && ((ctx.conn_param_update_instant) == ctx.connection_event) ) {
625eed650bfSMatthias Ringwald             	ctx_set_conn_interval(ctx.conn_param_update_interval_1250us);
6264a9a543dSMatthias Ringwald                 ctx.conn_latency            = ctx.conn_param_update_latency;
6274a9a543dSMatthias Ringwald                 ctx.supervision_timeout_us  = ctx.conn_param_update_timeout_us;
6284a9a543dSMatthias Ringwald                 ctx.conn_param_update_pending = false;
6294a9a543dSMatthias Ringwald 
6304a9a543dSMatthias Ringwald                 log_info("Conn param update now");
6314a9a543dSMatthias Ringwald 
6324a9a543dSMatthias Ringwald                 radio_stop_timer();
6334a9a543dSMatthias Ringwald                 ctx.synced = false;
6344a9a543dSMatthias Ringwald             }
6354a9a543dSMatthias Ringwald 
636*f8278fd5SMatthias Ringwald             // preload tx pdu
637*f8278fd5SMatthias Ringwald 			preload_tx_buffer();
638*f8278fd5SMatthias Ringwald 
6394a9a543dSMatthias Ringwald             if (ctx.synced){
6404a9a543dSMatthias Ringwald                 // restart radio timer (might get overwritten by first packet)
641c3c27692SMatthias Ringwald                 radio_set_timer_ticks(ctx.conn_sync_hop_ticks);
6424a9a543dSMatthias Ringwald 
6434a9a543dSMatthias Ringwald                 receive_master();
6444a9a543dSMatthias Ringwald             } else {
6454a9a543dSMatthias Ringwald                 // just wait longer
6464a9a543dSMatthias Ringwald                 receive_first_master();
6474a9a543dSMatthias Ringwald             }
6484a9a543dSMatthias Ringwald 
6494a9a543dSMatthias Ringwald             printf("--SYNC-Ch %02u-Event %04u - t %08u--\n", ctx.channel, ctx.connection_event, t0);
6504a9a543dSMatthias Ringwald             break;
6514a9a543dSMatthias Ringwald         case LL_STATE_ADVERTISING:
6524a9a543dSMatthias Ringwald             // send adv on all configured channels
6534a9a543dSMatthias Ringwald             ctx.channel = 36;
6544a9a543dSMatthias Ringwald             ctx.anchor_ticks = t0;
6554a9a543dSMatthias Ringwald             radio_stop_timer();
6564a9a543dSMatthias Ringwald             ll_advertising_statemachine();
6574a9a543dSMatthias Ringwald             radio_state = RADIO_LOWPOWER;
6584a9a543dSMatthias Ringwald             break;
6594a9a543dSMatthias Ringwald         default:
6604a9a543dSMatthias Ringwald             break;
6614a9a543dSMatthias Ringwald     }
6624a9a543dSMatthias Ringwald 
6634a9a543dSMatthias Ringwald }
6644a9a543dSMatthias Ringwald 
665e19f86faSMatthias Ringwald static void radio_fetch_rx_pdu(void){
6669c622d6fSMatthias Ringwald 
667e19f86faSMatthias Ringwald 	// fetch reserved rx pdu
668e19f86faSMatthias Ringwald 	ll_pdu_t * rx_packet = ctx.rx_pdu;
669e19f86faSMatthias Ringwald 	btstack_assert(rx_packet != NULL);
670ba57c415SMatthias Ringwald 
671ba57c415SMatthias Ringwald 	// read max packet
672ba57c415SMatthias Ringwald 	uint16_t max_packet_len = 2 + 27;
673ba57c415SMatthias Ringwald 	SX1280HalReadBuffer( SX1280_RX0_OFFSET, &rx_packet->header, max_packet_len);
674ba57c415SMatthias Ringwald 
675ba57c415SMatthias Ringwald 	// queue if not empty
676ba57c415SMatthias Ringwald 	if (rx_packet->len != 0){
677ba57c415SMatthias Ringwald 
678ba57c415SMatthias Ringwald 		// packet used
679e19f86faSMatthias Ringwald 		ctx.rx_pdu = NULL;
680e19f86faSMatthias Ringwald 
681e19f86faSMatthias Ringwald 		// mark as data packet
682e19f86faSMatthias Ringwald 		rx_packet->flags |= LL_PDU_FLAG_DATA_PDU;
683e19f86faSMatthias Ringwald 
684e19f86faSMatthias Ringwald 		// queue received packet
685e19f86faSMatthias Ringwald 		btstack_linked_queue_enqueue(&ctx.rx_queue, (btstack_linked_item_t *) rx_packet);
686e19f86faSMatthias Ringwald 	}
687ba57c415SMatthias Ringwald }
688e19f86faSMatthias Ringwald 
6894a9a543dSMatthias Ringwald /** Radio IRQ handlers */
6904a9a543dSMatthias Ringwald static void radio_on_tx_done(void ){
6914a9a543dSMatthias Ringwald     switch (radio_state){
6924a9a543dSMatthias Ringwald         case RADIO_W4_TX_DONE_TO_RX:
6939c622d6fSMatthias Ringwald             receive_response();
6949c622d6fSMatthias Ringwald             break;
6959c622d6fSMatthias Ringwald         default:
6969c622d6fSMatthias Ringwald             break;
6979c622d6fSMatthias Ringwald     }
6989c622d6fSMatthias Ringwald     switch (ll_state){
6999c622d6fSMatthias Ringwald         case LL_STATE_CONNECTED:
7009c622d6fSMatthias Ringwald             radio_fetch_rx_pdu();
701*f8278fd5SMatthias Ringwald             preload_tx_buffer();
7024a9a543dSMatthias Ringwald             break;
7034a9a543dSMatthias Ringwald         default:
7044a9a543dSMatthias Ringwald             break;
7054a9a543dSMatthias Ringwald     }
7064a9a543dSMatthias Ringwald }
7074a9a543dSMatthias Ringwald 
7084a9a543dSMatthias Ringwald static void radio_on_rx_done(void ){
7094a9a543dSMatthias Ringwald     uint16_t packet_end_ticks = hal_timer_get_ticks();
7106511f47bSMatthias Ringwald 
7116511f47bSMatthias Ringwald 	if (ll_state == LL_STATE_ADVERTISING){
7126511f47bSMatthias Ringwald 
7136511f47bSMatthias Ringwald 		// fetch reserved rx pdu
7146511f47bSMatthias Ringwald 		ll_pdu_t * rx_packet = ctx.rx_pdu;
7156511f47bSMatthias Ringwald 		btstack_assert(rx_packet != NULL);
7166511f47bSMatthias Ringwald 		ctx.rx_pdu = NULL;
7176511f47bSMatthias Ringwald 
7186511f47bSMatthias Ringwald 		// no data packet
7196511f47bSMatthias Ringwald 		rx_packet->flags = 0;
7206511f47bSMatthias Ringwald 		uint16_t max_packet_len = 2 + LL_MAX_PAYLOAD;
7216511f47bSMatthias Ringwald 
7226511f47bSMatthias Ringwald 		SX1280HalReadBuffer( SX1280_RX0_OFFSET, &rx_packet->header, max_packet_len);
7236511f47bSMatthias Ringwald 
7246511f47bSMatthias Ringwald 		// queue received packet
7256511f47bSMatthias Ringwald 		btstack_linked_queue_enqueue(&ctx.rx_queue, (btstack_linked_item_t *) rx_packet);
7266511f47bSMatthias Ringwald 
7276511f47bSMatthias Ringwald 	} else if (ll_state == LL_STATE_CONNECTED){
7286511f47bSMatthias Ringwald 
729*f8278fd5SMatthias Ringwald 		// get and parse rx pdu header
730e19f86faSMatthias Ringwald 		uint8_t rx_buffer[2];
731e19f86faSMatthias Ringwald 		SX1280HalReadBuffer( SX1280_RX0_OFFSET, rx_buffer, 2);
732e19f86faSMatthias Ringwald 		uint8_t rx_header = rx_buffer[0];
733e19f86faSMatthias Ringwald 		uint8_t rx_len    = rx_buffer[1];
734*f8278fd5SMatthias Ringwald         uint8_t next_expected_sequence_number = (rx_header >> 2) & 1;
735*f8278fd5SMatthias Ringwald         uint8_t sequence_number = (rx_header >> 3) & 1;
736*f8278fd5SMatthias Ringwald         // more data field not used yet
737*f8278fd5SMatthias Ringwald         // uint8_t more_data = (rx_packet->header >> 4) & 1;
7384a9a543dSMatthias Ringwald 
7394a9a543dSMatthias Ringwald         // update state
7404a9a543dSMatthias Ringwald         ctx.next_expected_sequence_number = 1 - sequence_number;
7414a9a543dSMatthias Ringwald 
742*f8278fd5SMatthias Ringwald         // report outgoing packet as ack'ed and free if confirmed by peer
743*f8278fd5SMatthias Ringwald         bool tx_acked = ctx.transmit_sequence_number != next_expected_sequence_number;
7444a9a543dSMatthias Ringwald         if (tx_acked){
745*f8278fd5SMatthias Ringwald             if (ctx.num_tx_pdus_on_controller > 0){
746*f8278fd5SMatthias Ringwald             	btstack_assert(ctx.tx_buffer_pdu[ctx.next_tx_buffer] != NULL);
747*f8278fd5SMatthias Ringwald             	// if non link-layer packet, free buffer and report as completed
748*f8278fd5SMatthias Ringwald 				if (ctx.tx_buffer_pdu[ctx.next_tx_buffer] != &ll_tx_packet){
749*f8278fd5SMatthias Ringwald 					btstack_memory_ll_pdu_free(ctx.tx_buffer_pdu[ctx.next_tx_buffer]);
750*f8278fd5SMatthias Ringwald 					ctx.tx_buffer_pdu[ctx.next_tx_buffer] = NULL;
7514a9a543dSMatthias Ringwald 					ctx.num_completed++;
7524a9a543dSMatthias Ringwald 				}
753*f8278fd5SMatthias Ringwald 				// next buffer
754*f8278fd5SMatthias Ringwald 				ctx.num_tx_pdus_on_controller--;
755*f8278fd5SMatthias Ringwald 				ctx.next_tx_buffer = (ctx.next_tx_buffer + 1 ) & 1;
7564a9a543dSMatthias Ringwald 			}
757*f8278fd5SMatthias Ringwald             ctx.transmit_sequence_number = next_expected_sequence_number;
7584a9a543dSMatthias Ringwald         }
7594a9a543dSMatthias Ringwald 
7604a9a543dSMatthias Ringwald         // restart supervision timeout
7614a9a543dSMatthias Ringwald         ctx.time_without_any_packets_us = 0;
7624a9a543dSMatthias Ringwald 
763*f8278fd5SMatthias Ringwald         // check if we can sent a full packet before sync hop
764f6933f57SMatthias Ringwald         int16_t now_ticks = packet_end_ticks - ctx.anchor_ticks;
765f0a70bc3SMatthias Ringwald         if (ctx.synced && (now_ticks > ctx.conn_latest_tx_ticks)){
766*f8278fd5SMatthias Ringwald             // disable AutoTX to abort sending of next packet
7674a9a543dSMatthias Ringwald             Radio.SetFs();
768*f8278fd5SMatthias Ringwald             log_info("Close before Sync hop: now %u > %u", now_ticks, ctx.conn_latest_tx_ticks);
7694b3f0d98SMatthias Ringwald 
770*f8278fd5SMatthias Ringwald             // get rx pdu and
7714b3f0d98SMatthias Ringwald 			radio_fetch_rx_pdu();
7724a9a543dSMatthias Ringwald             return;
7734a9a543dSMatthias Ringwald         }
7744a9a543dSMatthias Ringwald 
775*f8278fd5SMatthias Ringwald         // setup empty packet in ll buffer if no tx packet was preloaded
776*f8278fd5SMatthias Ringwald 		if (ctx.num_tx_pdus_on_controller == 0) {
777*f8278fd5SMatthias Ringwald 			ctx.tx_buffer_pdu[ctx.next_tx_buffer] = &ll_tx_packet;
778*f8278fd5SMatthias Ringwald 			ctx.num_tx_pdus_on_controller++;
779*f8278fd5SMatthias Ringwald 			ll_tx_packet.header = PDU_DATA_LLID_DATA_CONTINUE;
780*f8278fd5SMatthias Ringwald 			ll_tx_packet.len = 0;
7814a9a543dSMatthias Ringwald 		}
7824a9a543dSMatthias Ringwald 
783*f8278fd5SMatthias Ringwald 		// setup pdu header
784*f8278fd5SMatthias Ringwald 		uint8_t packet_header[2];
785*f8278fd5SMatthias Ringwald 		uint8_t md = btstack_linked_queue_empty(&ctx.tx_queue) ? 0 : 1;
786*f8278fd5SMatthias 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;
787*f8278fd5SMatthias Ringwald 		packet_header[1] = ctx.tx_buffer_pdu[ctx.next_tx_buffer]->len;
788*f8278fd5SMatthias Ringwald 
789*f8278fd5SMatthias Ringwald 		// select outgoing tx buffer and update pdu header
790*f8278fd5SMatthias Ringwald 		SX1280SetBufferBaseAddresses( tx_buffer_offset[ctx.next_tx_buffer], SX1280_RX0_OFFSET);
791*f8278fd5SMatthias Ringwald 		SX1280HalWriteBuffer( tx_buffer_offset[ctx.next_tx_buffer], (uint8_t *) packet_header, sizeof(packet_header));
792*f8278fd5SMatthias Ringwald 
7934a9a543dSMatthias Ringwald         // update operating state
7944a9a543dSMatthias Ringwald         SX1280AutoTxWillStart();
7954a9a543dSMatthias Ringwald 
7964a9a543dSMatthias Ringwald         // set anchor on first packet in connection event
7974a9a543dSMatthias Ringwald         if (ctx.packet_nr_in_connection_event == 0){
7984a9a543dSMatthias Ringwald 
7994a9a543dSMatthias Ringwald             // preamble (1) + aa (4) + header (1) + len (1) + payload (len) + crc (3) -- ISR handler ca. 35 us
800e19f86faSMatthias Ringwald             uint16_t timestamp_delay = (10 + rx_len) * 8 - 35;
8014a9a543dSMatthias Ringwald             uint16_t packet_start_ticks = packet_end_ticks - US_TO_TICKS(timestamp_delay);
8024a9a543dSMatthias Ringwald 
8034a9a543dSMatthias Ringwald             ctx.anchor_ticks = packet_start_ticks;
8044a9a543dSMatthias Ringwald             ctx.synced = true;
805c3c27692SMatthias Ringwald             radio_set_timer_ticks(ctx.conn_sync_hop_ticks);
8064a9a543dSMatthias Ringwald         }
8074a9a543dSMatthias Ringwald 
8084a9a543dSMatthias Ringwald         ctx.packet_nr_in_connection_event++;
8094a9a543dSMatthias Ringwald 
810*f8278fd5SMatthias Ringwald 		printf("RX %02x -- tx buffer %u, %02x %02x\n", rx_header, ctx.next_tx_buffer, packet_header[0], packet_header[1]);
8114a9a543dSMatthias Ringwald     }
8124a9a543dSMatthias Ringwald }
8134a9a543dSMatthias Ringwald 
8144a9a543dSMatthias Ringwald static void radio_on_tx_timeout(void ){
8154a9a543dSMatthias Ringwald     radio_state = RADIO_TX_TIMEOUT;
8164a9a543dSMatthias Ringwald     printf( "<>>>>>>>>TXE\n\r" );
8174a9a543dSMatthias Ringwald }
8184a9a543dSMatthias Ringwald 
8194a9a543dSMatthias Ringwald static void radio_on_rx_timeout(void ){
8204a9a543dSMatthias Ringwald     switch (ll_state){
8214a9a543dSMatthias Ringwald         case LL_STATE_ADVERTISING:
8224a9a543dSMatthias Ringwald             radio_state = RADIO_RX_ERROR;
8234a9a543dSMatthias Ringwald             break;
8244a9a543dSMatthias Ringwald         default:
8254a9a543dSMatthias Ringwald             break;
8264a9a543dSMatthias Ringwald     }
8274a9a543dSMatthias Ringwald }
8284a9a543dSMatthias Ringwald 
8294a9a543dSMatthias Ringwald static void radio_on_rx_error(IrqErrorCode_t errorCode ){
8304a9a543dSMatthias Ringwald     switch (ll_state){
8314a9a543dSMatthias Ringwald         case LL_STATE_ADVERTISING:
8324a9a543dSMatthias Ringwald             radio_state = RADIO_RX_ERROR;
8334a9a543dSMatthias Ringwald             break;
8344a9a543dSMatthias Ringwald         default:
8354a9a543dSMatthias Ringwald             break;
8364a9a543dSMatthias Ringwald     }
8374a9a543dSMatthias Ringwald }
8384a9a543dSMatthias Ringwald 
8394a9a543dSMatthias Ringwald const static RadioCallbacks_t Callbacks =
8404a9a543dSMatthias Ringwald {
8414a9a543dSMatthias Ringwald     &radio_on_tx_done,     // txDone
8424a9a543dSMatthias Ringwald     &radio_on_rx_done,     // rxDone
8434a9a543dSMatthias Ringwald     NULL,                  // syncWordDone
8444a9a543dSMatthias Ringwald     NULL,                  // headerDone
8454a9a543dSMatthias Ringwald     &radio_on_tx_timeout,  // txTimeout
8464a9a543dSMatthias Ringwald     &radio_on_rx_timeout,  // rxTimeout
8474a9a543dSMatthias Ringwald     &radio_on_rx_error,    // rxError
8484a9a543dSMatthias Ringwald     NULL,                  // rangingDone
8494a9a543dSMatthias Ringwald     NULL,                  // cadDone
8504a9a543dSMatthias Ringwald };
8514a9a543dSMatthias Ringwald 
8524a9a543dSMatthias Ringwald // Link Layer
8534a9a543dSMatthias Ringwald 
8544a9a543dSMatthias Ringwald static void ll_emit_hci_event(const hci_event_t * event, ...){
8554a9a543dSMatthias Ringwald     va_list argptr;
8564a9a543dSMatthias Ringwald     va_start(argptr, event);
8574a9a543dSMatthias Ringwald     uint16_t length = hci_event_create_from_template_and_arglist(ll_outgoing_hci_event, event, argptr);
8584a9a543dSMatthias Ringwald     va_end(argptr);
8594a9a543dSMatthias Ringwald     controller_packet_handler(HCI_EVENT_PACKET, ll_outgoing_hci_event, length);
8604a9a543dSMatthias Ringwald }
8614a9a543dSMatthias Ringwald 
8624a9a543dSMatthias Ringwald void ll_init(void){
8634a9a543dSMatthias Ringwald 
8644a9a543dSMatthias Ringwald     // setup memory pools
8654a9a543dSMatthias Ringwald     btstack_memory_pool_create(&ll_pdu_pool, ll_pdu_pool_storage, MAX_NUM_LL_PDUS, sizeof(ll_pdu_t));
8664a9a543dSMatthias Ringwald 
8674a9a543dSMatthias Ringwald     // set test bd addr 33:33:33:33:33:33
8684a9a543dSMatthias Ringwald     memset(ctx.bd_addr_le, 0x33, 6);
8694a9a543dSMatthias Ringwald 
8704a9a543dSMatthias Ringwald     // default channels, advertising interval
8714a9a543dSMatthias Ringwald     ctx.adv_map = 0x7;
8724a9a543dSMatthias Ringwald     ctx.adv_interval_us = 1280000;
8734a9a543dSMatthias Ringwald 
8744a9a543dSMatthias Ringwald     // init timer
8754a9a543dSMatthias Ringwald     hal_timer_init();
8764a9a543dSMatthias Ringwald     hal_timer_set_callback(&radio_timer_handler);
8774a9a543dSMatthias Ringwald }
8784a9a543dSMatthias Ringwald 
8794a9a543dSMatthias Ringwald void ll_radio_on(void){
8802acaaa65SMatthias Ringwald 
8814a9a543dSMatthias Ringwald     Radio.Init( (RadioCallbacks_t *) &Callbacks );
8824a9a543dSMatthias Ringwald     Radio.SetRegulatorMode( USE_DCDC ); // Can also be set in LDO mode but consume more power
8834a9a543dSMatthias Ringwald     Radio.SetInterruptMode( );
8844a9a543dSMatthias Ringwald     Radio.SetDioIrqParams( RX_TX_IRQ_MASK, RX_TX_IRQ_MASK, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
8854a9a543dSMatthias Ringwald 
8864a9a543dSMatthias Ringwald     ModulationParams_t modulationParams;
8874a9a543dSMatthias Ringwald     modulationParams.PacketType = PACKET_TYPE_BLE;
8884a9a543dSMatthias Ringwald     modulationParams.Params.Ble.BitrateBandwidth = GFSK_BLE_BR_1_000_BW_1_2;
8894a9a543dSMatthias Ringwald     modulationParams.Params.Ble.ModulationIndex = GFSK_BLE_MOD_IND_0_50;
8904a9a543dSMatthias Ringwald     modulationParams.Params.Ble.ModulationShaping = RADIO_MOD_SHAPING_BT_0_5;
8914a9a543dSMatthias Ringwald 
8924a9a543dSMatthias Ringwald     Radio.SetStandby( STDBY_RC );
8934a9a543dSMatthias Ringwald     Radio.SetPacketType( modulationParams.PacketType );
8944a9a543dSMatthias Ringwald     Radio.SetModulationParams( &modulationParams );
8954a9a543dSMatthias Ringwald     Radio.SetBufferBaseAddresses( SX1280_TX0_OFFSET, SX1280_RX0_OFFSET );
8964a9a543dSMatthias Ringwald     Radio.SetTxParams( TX_PARAMS_OUTPUT_POWER, TX_PARAMS_RAMP_TIME );
8974a9a543dSMatthias Ringwald 
8984a9a543dSMatthias Ringwald     // Go back to Frequcency Synthesis Mode, reduces transition time between Rx<->TX
8994a9a543dSMatthias Ringwald     Radio.SetAutoFS(1);
9004a9a543dSMatthias Ringwald 
9012acaaa65SMatthias Ringwald     // quick test
9022acaaa65SMatthias Ringwald     uint8_t data[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
9032acaaa65SMatthias Ringwald     Radio.WriteBuffer(0, data, sizeof(data));
9042acaaa65SMatthias Ringwald     uint8_t check[8];
9052acaaa65SMatthias Ringwald     Radio.ReadBuffer(0, check, sizeof(data));
9062acaaa65SMatthias Ringwald     if (memcmp(data, check, sizeof(data)) != 0){
9072acaaa65SMatthias Ringwald         printf_hexdump(data, sizeof(data));
9082acaaa65SMatthias Ringwald         printf_hexdump(check, sizeof(data));
9092acaaa65SMatthias Ringwald         btstack_assert(false);
9102acaaa65SMatthias Ringwald     }
9112acaaa65SMatthias Ringwald 
9124a9a543dSMatthias Ringwald     ll_state = LL_STATE_STANDBY;
9134a9a543dSMatthias Ringwald }
9144a9a543dSMatthias Ringwald 
9154a9a543dSMatthias Ringwald static void ll_handle_conn_ind(ll_pdu_t * rx_packet){
9164a9a543dSMatthias Ringwald     printf("Connect Req: ");
9174a9a543dSMatthias Ringwald     printf_hexdump(&rx_packet->header, rx_packet->len + 2);
9184a9a543dSMatthias Ringwald 
9194a9a543dSMatthias Ringwald     uint8_t * init_addr = &rx_packet->payload[0];
9204a9a543dSMatthias Ringwald     uint8_t * adv_addr =  &rx_packet->payload[6];
9214a9a543dSMatthias Ringwald     uint8_t   chan_sel = (rx_packet->header >> 5) & 1;
9224a9a543dSMatthias Ringwald 
9234a9a543dSMatthias Ringwald     // verify AdvA
9244a9a543dSMatthias Ringwald     if (memcmp(ctx.bd_addr_le, adv_addr, 6) != 0){
9254a9a543dSMatthias Ringwald         // differs, go back to adv sending
9264a9a543dSMatthias Ringwald         radio_state = RADIO_LOWPOWER;
9274a9a543dSMatthias Ringwald         return;
9284a9a543dSMatthias Ringwald     }
9294a9a543dSMatthias Ringwald 
9304a9a543dSMatthias Ringwald     // TODO: get remote addr type
9314a9a543dSMatthias Ringwald     ctx.peer_addr_type = 0;
9324a9a543dSMatthias Ringwald     memcpy(ctx.peer_addr, init_addr, 6);
9334a9a543dSMatthias Ringwald 
9344a9a543dSMatthias Ringwald     // get params for HCI event
9354a9a543dSMatthias Ringwald     const uint8_t * ll_data = &rx_packet->payload[12];
9364a9a543dSMatthias Ringwald 
9374a9a543dSMatthias Ringwald     ctx.aa                        = little_endian_read_32(ll_data, 0);
9384a9a543dSMatthias Ringwald     uint8_t crc_init_0            = ll_data[4];
9394a9a543dSMatthias Ringwald     uint8_t crc_init_1            = ll_data[5];
9404a9a543dSMatthias Ringwald     uint8_t crc_init_2            = ll_data[6];
9414a9a543dSMatthias Ringwald     uint8_t win_size              = ll_data[7];
9424a9a543dSMatthias Ringwald     uint16_t win_offset           = little_endian_read_16(ll_data, 8);
943eed650bfSMatthias Ringwald     uint16_t conn_interval_1250us = little_endian_read_16(ll_data, 10);
9444a9a543dSMatthias Ringwald     ctx.conn_latency              = little_endian_read_16(ll_data, 12);
9454a9a543dSMatthias Ringwald     ctx.supervision_timeout_10ms  = little_endian_read_16(ll_data, 14);
9464a9a543dSMatthias Ringwald     const uint8_t * channel_map = &ll_data[16];
9474a9a543dSMatthias Ringwald     uint8_t hop = ll_data[21] & 0x1f;
9484a9a543dSMatthias Ringwald     uint8_t sca = ll_data[21] >> 5;
9494a9a543dSMatthias Ringwald 
9504a9a543dSMatthias Ringwald     UNUSED(sca);
9514a9a543dSMatthias Ringwald     UNUSED(win_offset);
9524a9a543dSMatthias Ringwald     UNUSED(win_size);
9534a9a543dSMatthias Ringwald 
954eed650bfSMatthias Ringwald 	ctx_set_conn_interval(conn_interval_1250us);
955eed650bfSMatthias Ringwald 
9564a9a543dSMatthias Ringwald     // convert to us
9574a9a543dSMatthias Ringwald     ctx.supervision_timeout_us  = ctx.supervision_timeout_10ms  * 10000;
9584a9a543dSMatthias Ringwald     ctx.connection_event = 0;
9594a9a543dSMatthias Ringwald     ctx.packet_nr_in_connection_event = 0;
9604a9a543dSMatthias Ringwald     ctx.next_expected_sequence_number = 0;
9614a9a543dSMatthias Ringwald     ctx.transmit_sequence_number = 0;
9624a9a543dSMatthias Ringwald 
9634a9a543dSMatthias Ringwald     // set AA
9644a9a543dSMatthias Ringwald     Radio.SetBleAccessAddress(ctx.aa);
9654a9a543dSMatthias Ringwald 
9664a9a543dSMatthias Ringwald     // set CRC init value
9674a9a543dSMatthias Ringwald     Radio.WriteRegister(0x9c7, crc_init_2);
9684a9a543dSMatthias Ringwald     Radio.WriteRegister(0x9c8, crc_init_1);
9694a9a543dSMatthias Ringwald     Radio.WriteRegister(0x9c9, crc_init_0);
9704a9a543dSMatthias Ringwald 
9714a9a543dSMatthias Ringwald     printf("Connection interval %u us\n", ctx.conn_interval_us);
9724a9a543dSMatthias Ringwald     printf("Connection timeout  %u us\n", ctx.supervision_timeout_us);
9734a9a543dSMatthias Ringwald     printf("AA %08x\n", ctx.aa);
9744a9a543dSMatthias Ringwald     printf("CRC Init 0x%02x%02x%02x\n", crc_init_2, crc_init_1, crc_init_0);
9754a9a543dSMatthias Ringwald 
9764a9a543dSMatthias Ringwald     // init hopping
9774a9a543dSMatthias Ringwald     hopping_init( &h );
9784a9a543dSMatthias Ringwald     hopping_set_channel_map( &h, channel_map);
9794a9a543dSMatthias Ringwald     ctx.channel_selection_algorithm = ctx.csa2_support & chan_sel;
9804a9a543dSMatthias Ringwald     switch (ctx.channel_selection_algorithm){
9814a9a543dSMatthias Ringwald         case 0:
9824a9a543dSMatthias Ringwald             hopping_csa1_set_hop_increment(  &h, hop );
9834a9a543dSMatthias Ringwald             break;
9844a9a543dSMatthias Ringwald         case 1:
9854a9a543dSMatthias Ringwald             hopping_csa2_set_access_address( &h, ctx.aa);
9864a9a543dSMatthias Ringwald             break;
9874a9a543dSMatthias Ringwald         default:
9884a9a543dSMatthias Ringwald             break;
9894a9a543dSMatthias Ringwald     }
9904a9a543dSMatthias Ringwald     next_channel();
9914a9a543dSMatthias Ringwald 
9924a9a543dSMatthias Ringwald     start_hopping();
9934a9a543dSMatthias Ringwald 
9944a9a543dSMatthias Ringwald     // Enable Rx->Tx in 150 us for BLE
9954a9a543dSMatthias Ringwald     // Note: Driver subtracts AUTO_RX_TX_OFFSET (33) from it and 150 should be correct, Raccoon reports 181 us then, so -31
9964a9a543dSMatthias Ringwald     // Radio.SetAutoTx(119);
9974a9a543dSMatthias Ringwald 
9984a9a543dSMatthias Ringwald     // SetAutoTX(100) - direct write / ignore compensation
9994a9a543dSMatthias Ringwald     uint8_t buf[2];
10004a9a543dSMatthias Ringwald     big_endian_store_16(buf, 0, AUTO_RX_TX_TIME_US);
10014a9a543dSMatthias Ringwald     SX1280HalWriteCommand( RADIO_SET_AUTOTX, buf, 2 );
10024a9a543dSMatthias Ringwald 
1003*f8278fd5SMatthias Ringwald 	// pre-load tx pdu
1004*f8278fd5SMatthias Ringwald 	preload_tx_buffer();
1005*f8278fd5SMatthias Ringwald 
10064a9a543dSMatthias Ringwald     // get next packet
10074a9a543dSMatthias Ringwald     ll_state = LL_STATE_CONNECTED;
10084a9a543dSMatthias Ringwald 
10094a9a543dSMatthias Ringwald     receive_first_master();
10104a9a543dSMatthias Ringwald     ll_send_connection_complete = true;
10114a9a543dSMatthias Ringwald }
10124a9a543dSMatthias Ringwald 
10134a9a543dSMatthias Ringwald static void ll_handle_control(ll_pdu_t * rx_packet){
10144a9a543dSMatthias Ringwald     ll_pdu_t * tx_packet = &ll_tx_packet;
10154a9a543dSMatthias Ringwald     uint8_t opcode = rx_packet->payload[0];
10164a9a543dSMatthias Ringwald     switch (opcode){
10174a9a543dSMatthias Ringwald         case PDU_DATA_LLCTRL_TYPE_VERSION_IND:
10184a9a543dSMatthias Ringwald             tx_packet->len = 6;
10194a9a543dSMatthias Ringwald             tx_packet->header = PDU_DATA_LLID_CTRL;
10204a9a543dSMatthias Ringwald             tx_packet->payload[0] = PDU_DATA_LLCTRL_TYPE_VERSION_IND;
10214a9a543dSMatthias Ringwald             tx_packet->payload[1] = 0x06; // VersNr = Bluetooth Core V4.0
10224a9a543dSMatthias Ringwald             little_endian_store_16(tx_packet->payload, 2, BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH);
10234a9a543dSMatthias Ringwald             little_endian_store_16(tx_packet->payload, 4, 0);
10244a9a543dSMatthias Ringwald             btstack_linked_queue_enqueue(&ctx.tx_queue, (btstack_linked_item_t *) tx_packet);
10254a9a543dSMatthias Ringwald             printf("Queue Version Ind\n");
10264a9a543dSMatthias Ringwald             break;
10274a9a543dSMatthias Ringwald         case PDU_DATA_LLCTRL_TYPE_FEATURE_REQ:
10284a9a543dSMatthias Ringwald             tx_packet->len = 9;
10294a9a543dSMatthias Ringwald             tx_packet->header = PDU_DATA_LLID_CTRL;
10304a9a543dSMatthias Ringwald             tx_packet->payload[0] = PDU_DATA_LLCTRL_TYPE_FEATURE_RSP;
10314a9a543dSMatthias Ringwald             // TODO: set features of our controller
10324a9a543dSMatthias Ringwald             memset(&tx_packet->payload[1], 0, 8);
10334a9a543dSMatthias Ringwald             btstack_linked_queue_enqueue(&ctx.tx_queue, (btstack_linked_item_t *) tx_packet);
10344a9a543dSMatthias Ringwald             printf("Queue Feature Rsp\n");
10354a9a543dSMatthias Ringwald             break;
10364a9a543dSMatthias Ringwald         case PDU_DATA_LLCTRL_TYPE_CHAN_MAP_IND:
10374a9a543dSMatthias Ringwald             memcpy((uint8_t *) ctx.channel_map_update_map, &rx_packet->payload[1], 5);
10384a9a543dSMatthias Ringwald             ctx.channel_map_update_instant   = little_endian_read_16(rx_packet->payload, 6);
10394a9a543dSMatthias Ringwald             ctx.channel_map_update_pending   = true;
10404a9a543dSMatthias Ringwald             break;
10414a9a543dSMatthias Ringwald         case PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND:
10424a9a543dSMatthias Ringwald             ctx.conn_param_update_win_size        = tx_packet->payload[1];
10434a9a543dSMatthias Ringwald             ctx.conn_param_update_win_offset      = little_endian_read_16(rx_packet->payload, 2);
1044982f09b4SMatthias Ringwald             ctx.conn_param_update_interval_1250us = little_endian_read_16(rx_packet->payload, 4);
10454a9a543dSMatthias Ringwald             ctx.conn_param_update_latency         = little_endian_read_16(rx_packet->payload, 6);
10464a9a543dSMatthias Ringwald             ctx.conn_param_update_timeout_us      = little_endian_read_16(rx_packet->payload, 8) * 10000;
10474a9a543dSMatthias Ringwald             ctx.conn_param_update_instant         = little_endian_read_16(rx_packet->payload, 10);
10484a9a543dSMatthias Ringwald             ctx.conn_param_update_pending         = true;
1049982f09b4SMatthias Ringwald             log_info("PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND, conn interval %u 1250us at instant %u",
1050982f09b4SMatthias Ringwald                      (unsigned int) ctx.conn_param_update_interval_1250us, ctx.conn_param_update_instant);
10514a9a543dSMatthias Ringwald             break;
10524a9a543dSMatthias Ringwald         case PDU_DATA_LLCTRL_TYPE_TERMINATE_IND:
10534a9a543dSMatthias Ringwald             printf("Terminate!\n");
10544a9a543dSMatthias Ringwald             ll_terminate();
10554a9a543dSMatthias Ringwald             break;
10564a9a543dSMatthias Ringwald         default:
10574a9a543dSMatthias Ringwald             break;
10584a9a543dSMatthias Ringwald     }
10594a9a543dSMatthias Ringwald }
10604a9a543dSMatthias Ringwald 
10614a9a543dSMatthias Ringwald static void ll_handle_data(ll_pdu_t * rx_packet){
10624a9a543dSMatthias Ringwald     if (ll_state != LL_STATE_CONNECTED) return;
10634a9a543dSMatthias Ringwald     uint8_t acl_packet[40];
10644a9a543dSMatthias Ringwald     // ACL Header
10654a9a543dSMatthias Ringwald     uint8_t ll_id = rx_packet->header & 3;
10664a9a543dSMatthias Ringwald     acl_packet[0] = 0x01;
10674a9a543dSMatthias Ringwald     acl_packet[1] = ll_id << 4;
10684a9a543dSMatthias Ringwald     little_endian_store_16(acl_packet, 2, rx_packet->len);
10694a9a543dSMatthias Ringwald     memcpy(&acl_packet[4], rx_packet->payload, rx_packet->len);
10704a9a543dSMatthias Ringwald     (*controller_packet_handler)(HCI_ACL_DATA_PACKET, acl_packet, rx_packet->len + 4);
10714a9a543dSMatthias Ringwald }
10724a9a543dSMatthias Ringwald 
10734a9a543dSMatthias 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){
10744a9a543dSMatthias Ringwald     // TODO .. store other params
10754a9a543dSMatthias Ringwald     ll_scan_interval_us = ((uint32_t) le_scan_interval) * 625;
10764a9a543dSMatthias Ringwald     ll_scan_window_us   = ((uint32_t) le_scan_window)   * 625;
10774a9a543dSMatthias Ringwald     log_info("LE Scan Params: window %lu, interval %lu ms", ll_scan_interval_us, ll_scan_window_us);
10784a9a543dSMatthias Ringwald }
10794a9a543dSMatthias Ringwald 
10804a9a543dSMatthias Ringwald static uint8_t ll_start_scanning(uint8_t filter_duplicates){
10814a9a543dSMatthias Ringwald #if 0
10824a9a543dSMatthias Ringwald     // COMMAND DISALLOWED if wrong state.
10834a9a543dSMatthias Ringwald     if (ll_state != LL_STATE_STANDBY)  return 0x0c;
10844a9a543dSMatthias Ringwald 
10854a9a543dSMatthias Ringwald     ll_state = LL_STATE_SCANNING;
10864a9a543dSMatthias Ringwald 
10874a9a543dSMatthias Ringwald     log_info("LE Scan Start: window %lu, interval %lu ms", ll_scan_interval_us, ll_scan_window_us);
10884a9a543dSMatthias Ringwald 
10894a9a543dSMatthias Ringwald     // reset timer and capature events
10904a9a543dSMatthias Ringwald     NRF_TIMER0->TASKS_CLEAR = 1;
10914a9a543dSMatthias Ringwald     NRF_TIMER0->TASKS_STOP  = 1;
10924a9a543dSMatthias Ringwald     NRF_TIMER0->EVENTS_COMPARE[0] = 0;
10934a9a543dSMatthias Ringwald     NRF_TIMER0->EVENTS_COMPARE[1] = 0;
10944a9a543dSMatthias Ringwald 
10954a9a543dSMatthias Ringwald     // limit scanning
10964a9a543dSMatthias Ringwald     if (ll_scan_window_us < ll_scan_interval_us){
10974a9a543dSMatthias Ringwald         // setup PPI to disable radio after end of scan_window
10984a9a543dSMatthias Ringwald         NRF_TIMER0->CC[1]    = ll_scan_window_us;
10994a9a543dSMatthias Ringwald         NRF_PPI->CHENSET     = 1 << 22; // TIMER0->EVENTS_COMPARE[1] ->  RADIO->TASKS_DISABLE
11004a9a543dSMatthias Ringwald     }
11014a9a543dSMatthias Ringwald 
11024a9a543dSMatthias Ringwald     // set timer to trigger IRQ for next scan interval
11034a9a543dSMatthias Ringwald     NRF_TIMER0->CC[0]    = ll_scan_interval_us;
11044a9a543dSMatthias Ringwald     NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
11054a9a543dSMatthias Ringwald 
11064a9a543dSMatthias Ringwald     // next channel to scan
11074a9a543dSMatthias Ringwald     int adv_channel = (random_generator_next() % 3) + 37;
11084a9a543dSMatthias Ringwald     log_debug("LE Scan Channel: %u", adv_channel);
11094a9a543dSMatthias Ringwald 
11104a9a543dSMatthias Ringwald     // start receiving
11114a9a543dSMatthias Ringwald     NRF_TIMER0->TASKS_START = 1;
11124a9a543dSMatthias Ringwald     radio_receive_on_channel(adv_channel);
11134a9a543dSMatthias Ringwald #endif
11144a9a543dSMatthias Ringwald     return 0;
11154a9a543dSMatthias Ringwald }
11164a9a543dSMatthias Ringwald 
11174a9a543dSMatthias Ringwald static uint8_t ll_stop_scanning(void){
11184a9a543dSMatthias Ringwald #if 0
11194a9a543dSMatthias Ringwald     // COMMAND DISALLOWED if wrong state.
11204a9a543dSMatthias Ringwald     if (ll_state != LL_STATE_SCANNING)  return 0x0c;
11214a9a543dSMatthias Ringwald 
11224a9a543dSMatthias Ringwald     log_info("LE Scan Stop");
11234a9a543dSMatthias Ringwald 
11244a9a543dSMatthias Ringwald     ll_state = LL_STATE_STANDBY;
11254a9a543dSMatthias Ringwald 
11264a9a543dSMatthias Ringwald     // stop radio
11274a9a543dSMatthias Ringwald     radio_disable();
11284a9a543dSMatthias Ringwald 
11294a9a543dSMatthias Ringwald #endif
11304a9a543dSMatthias Ringwald     return 0;
11314a9a543dSMatthias Ringwald }
11324a9a543dSMatthias Ringwald 
11334a9a543dSMatthias Ringwald uint8_t ll_set_scan_enable(uint8_t le_scan_enable, uint8_t filter_duplicates){
11344a9a543dSMatthias Ringwald     if (le_scan_enable){
11354a9a543dSMatthias Ringwald         return ll_start_scanning(filter_duplicates);
11364a9a543dSMatthias Ringwald     } else {
11374a9a543dSMatthias Ringwald         return ll_stop_scanning();
11384a9a543dSMatthias Ringwald     }
11394a9a543dSMatthias Ringwald }
11404a9a543dSMatthias Ringwald 
11414a9a543dSMatthias Ringwald static uint8_t ll_start_advertising(void){
11424a9a543dSMatthias Ringwald     // COMMAND DISALLOWED if wrong state.
11434a9a543dSMatthias Ringwald     if (ll_state != LL_STATE_STANDBY) return ERROR_CODE_COMMAND_DISALLOWED;
11444a9a543dSMatthias Ringwald     log_info("Start Advertising on channels 0x%0x, interval %lu us", ctx.adv_map, ctx.adv_interval_us);
11454a9a543dSMatthias Ringwald     start_advertising();
11464a9a543dSMatthias Ringwald     return ERROR_CODE_SUCCESS;
11474a9a543dSMatthias Ringwald }
11484a9a543dSMatthias Ringwald 
11494a9a543dSMatthias Ringwald static uint8_t ll_stop_advertising(void){
11504a9a543dSMatthias Ringwald     // COMMAND DISALLOWED if wrong state.
11514a9a543dSMatthias Ringwald     if (ll_state != LL_STATE_ADVERTISING) return ERROR_CODE_COMMAND_DISALLOWED;
11524a9a543dSMatthias Ringwald 
11534a9a543dSMatthias Ringwald     // TODO:
11544a9a543dSMatthias Ringwald     return ERROR_CODE_SUCCESS;
11554a9a543dSMatthias Ringwald }
11564a9a543dSMatthias Ringwald 
11574a9a543dSMatthias Ringwald uint8_t ll_set_advertise_enable(uint8_t le_adv_enable){
11584a9a543dSMatthias Ringwald     if (le_adv_enable){
11594a9a543dSMatthias Ringwald         return ll_start_advertising();
11604a9a543dSMatthias Ringwald     } else {
11614a9a543dSMatthias Ringwald         return ll_stop_advertising();
11624a9a543dSMatthias Ringwald     }
11634a9a543dSMatthias Ringwald }
11644a9a543dSMatthias Ringwald 
11654a9a543dSMatthias Ringwald uint8_t ll_set_advertising_parameters(uint16_t advertising_interval_min, uint16_t advertising_interval_max,
11664a9a543dSMatthias Ringwald                                       uint8_t advertising_type, uint8_t own_address_type, uint8_t peer_address_types, uint8_t * peer_address,
11674a9a543dSMatthias Ringwald                                       uint8_t advertising_channel_map, uint8_t advertising_filter_policy){
11684a9a543dSMatthias Ringwald 
11694a9a543dSMatthias Ringwald     // validate channel map
11704a9a543dSMatthias Ringwald     if (advertising_channel_map == 0) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
11714a9a543dSMatthias Ringwald     if ((advertising_channel_map & 0xf8) != 0) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
11724a9a543dSMatthias Ringwald 
11734a9a543dSMatthias Ringwald     // validate advertising interval
11744a9a543dSMatthias Ringwald     if (advertising_interval_min < 0x20)   return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
11754a9a543dSMatthias Ringwald     if (advertising_interval_min > 0x4000) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
11764a9a543dSMatthias Ringwald     if (advertising_interval_max < 0x20)   return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
11774a9a543dSMatthias Ringwald     if (advertising_interval_max > 0x4000) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
11784a9a543dSMatthias Ringwald     if (advertising_interval_min > advertising_interval_max) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
11794a9a543dSMatthias Ringwald 
11804a9a543dSMatthias Ringwald     ctx.adv_map = advertising_channel_map;
11814a9a543dSMatthias Ringwald     ctx.adv_interval_us = advertising_interval_max * 625;
11824a9a543dSMatthias Ringwald 
11834a9a543dSMatthias Ringwald     // TODO: validate other params
11844a9a543dSMatthias Ringwald     // TODO: process other params
11854a9a543dSMatthias Ringwald 
11864a9a543dSMatthias Ringwald     return ERROR_CODE_SUCCESS;
11874a9a543dSMatthias Ringwald }
11884a9a543dSMatthias Ringwald 
11894a9a543dSMatthias Ringwald uint8_t ll_set_advertising_data(uint8_t adv_len, const uint8_t * adv_data){
11904a9a543dSMatthias Ringwald     // COMMAND DISALLOWED if wrong state.
11914a9a543dSMatthias Ringwald     if (ll_state == LL_STATE_ADVERTISING) return ERROR_CODE_COMMAND_DISALLOWED;
11924a9a543dSMatthias Ringwald     if (adv_len > 31) return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
11934a9a543dSMatthias Ringwald     ctx.adv_len = adv_len;
11944a9a543dSMatthias Ringwald     memcpy(ctx.adv_data, adv_data, adv_len);
11954a9a543dSMatthias Ringwald 
11964a9a543dSMatthias Ringwald     // TODO:
11974a9a543dSMatthias Ringwald     return ERROR_CODE_SUCCESS;
11984a9a543dSMatthias Ringwald }
11994a9a543dSMatthias Ringwald 
12004a9a543dSMatthias Ringwald void ll_execute_once(void){
12014a9a543dSMatthias Ringwald     // process received packets
12024a9a543dSMatthias Ringwald     while (1){
12034a9a543dSMatthias Ringwald         ll_pdu_t * rx_packet = (ll_pdu_t *) btstack_linked_queue_dequeue(&ctx.rx_queue);
12044a9a543dSMatthias Ringwald         if (rx_packet == NULL) break;
12054a9a543dSMatthias Ringwald         if (rx_packet->len > 0){
12064a9a543dSMatthias Ringwald             if ((rx_packet->flags & LL_PDU_FLAG_DATA_PDU) == 0){
12074a9a543dSMatthias Ringwald                 // ADV PDU
12084a9a543dSMatthias Ringwald                 // connect ind?
12094a9a543dSMatthias Ringwald                 if ((rx_packet->header & 0x0f) == PDU_ADV_TYPE_CONNECT_IND){
12104a9a543dSMatthias Ringwald                     ll_handle_conn_ind(rx_packet);
12114a9a543dSMatthias Ringwald                 }
12124a9a543dSMatthias Ringwald                 else {
12134a9a543dSMatthias Ringwald                     radio_state = RADIO_LOWPOWER;
12144a9a543dSMatthias Ringwald                 }
12154a9a543dSMatthias Ringwald             } else {
12164a9a543dSMatthias Ringwald                 // DATA PDU
12174a9a543dSMatthias Ringwald                 uint8_t ll_id = rx_packet->header & 3;
12184a9a543dSMatthias Ringwald                 if (ll_id == PDU_DATA_LLID_CTRL) {
12194a9a543dSMatthias Ringwald                     ll_handle_control(rx_packet);
12204a9a543dSMatthias Ringwald                 } else {
12214a9a543dSMatthias Ringwald                     ll_handle_data(rx_packet);
12224a9a543dSMatthias Ringwald                 }
12234a9a543dSMatthias Ringwald             }
12244a9a543dSMatthias Ringwald         }
12254a9a543dSMatthias Ringwald         // free packet
12264a9a543dSMatthias Ringwald         btstack_memory_ll_pdu_free(rx_packet);
12274a9a543dSMatthias Ringwald     }
12284a9a543dSMatthias Ringwald 
12294a9a543dSMatthias Ringwald     switch ( ll_state ){
12304a9a543dSMatthias Ringwald         case LL_STATE_ADVERTISING:
12314a9a543dSMatthias Ringwald             ll_advertising_statemachine();
12324a9a543dSMatthias Ringwald             break;
12334a9a543dSMatthias Ringwald         default:
12344a9a543dSMatthias Ringwald             break;
12354a9a543dSMatthias Ringwald     }
12364a9a543dSMatthias Ringwald 
12374a9a543dSMatthias Ringwald     // generate HCI events
12384a9a543dSMatthias Ringwald 
12394a9a543dSMatthias Ringwald     // report num complete packets
12404a9a543dSMatthias Ringwald     /** critical section start */
12414a9a543dSMatthias Ringwald     hal_cpu_disable_irqs();
12424a9a543dSMatthias Ringwald     uint8_t num_completed = ctx.num_completed;
12434a9a543dSMatthias Ringwald     ctx.num_completed = 0;
12444a9a543dSMatthias Ringwald     hal_cpu_enable_irqs();
12454a9a543dSMatthias Ringwald     /** critical section end */
12464a9a543dSMatthias Ringwald     if (num_completed > 0){
12474a9a543dSMatthias Ringwald         ll_emit_hci_event(&hci_event_number_of_completed_packets_1, 1, HCI_CON_HANDLE, num_completed);
12484a9a543dSMatthias Ringwald     }
12494a9a543dSMatthias Ringwald 
12504a9a543dSMatthias Ringwald     // report connection event
12514a9a543dSMatthias Ringwald     if (ll_send_connection_complete){
12524a9a543dSMatthias Ringwald         ll_send_connection_complete = false;
12534a9a543dSMatthias Ringwald         ll_emit_hci_event(&hci_subevent_le_connection_complete,
12544a9a543dSMatthias Ringwald                                  ERROR_CODE_SUCCESS, HCI_CON_HANDLE, 0x01 /* slave */, ctx.peer_addr_type, ctx.peer_addr,
12554a9a543dSMatthias Ringwald                                  ctx.conn_interval_1250us, ctx.conn_latency, ctx.supervision_timeout_10ms, 0 /* master clock accuracy */);
12564a9a543dSMatthias Ringwald     }
12574a9a543dSMatthias Ringwald 
12584a9a543dSMatthias Ringwald     // report disconnection event
12594a9a543dSMatthias Ringwald     if (ll_send_disconnected){
12604a9a543dSMatthias Ringwald         ll_send_disconnected = false;
12614a9a543dSMatthias Ringwald         ll_emit_hci_event(&hci_event_disconnection_complete, ERROR_CODE_SUCCESS, HCI_CON_HANDLE, 0);
12624a9a543dSMatthias Ringwald     }
12634a9a543dSMatthias Ringwald }
12644a9a543dSMatthias Ringwald bool ll_reserve_acl_packet(void){
12654a9a543dSMatthias Ringwald     if (ll_reserved_acl_buffer == NULL){
12664a9a543dSMatthias Ringwald         ll_reserved_acl_buffer = btstack_memory_ll_pdu_get();
12674a9a543dSMatthias Ringwald     }
12684a9a543dSMatthias Ringwald     return ll_reserved_acl_buffer != NULL;
12694a9a543dSMatthias Ringwald }
12704a9a543dSMatthias Ringwald 
12714a9a543dSMatthias Ringwald void ll_queue_acl_packet(const uint8_t * packet, uint16_t size){
12724a9a543dSMatthias Ringwald     btstack_assert(ll_reserved_acl_buffer != NULL);
12734a9a543dSMatthias Ringwald 
12744a9a543dSMatthias Ringwald     ll_pdu_t * tx_packet = ll_reserved_acl_buffer;
12754a9a543dSMatthias Ringwald     ll_reserved_acl_buffer = NULL;
12764a9a543dSMatthias Ringwald 
12774a9a543dSMatthias Ringwald     switch ((packet[1] >> 4) & 0x03){
12784a9a543dSMatthias Ringwald         case 0:
12794a9a543dSMatthias Ringwald         case 2:
12804a9a543dSMatthias Ringwald             tx_packet->header = PDU_DATA_LLID_DATA_START;
12814a9a543dSMatthias Ringwald             break;
12824a9a543dSMatthias Ringwald         case 1:
12834a9a543dSMatthias Ringwald             tx_packet->header = PDU_DATA_LLID_DATA_CONTINUE;
12844a9a543dSMatthias Ringwald             break;
12854a9a543dSMatthias Ringwald         case 3:
12864a9a543dSMatthias Ringwald             while(1);
12874a9a543dSMatthias Ringwald             break;
12884a9a543dSMatthias Ringwald         default:
12894a9a543dSMatthias Ringwald             break;
12904a9a543dSMatthias Ringwald     }
12914a9a543dSMatthias Ringwald     tx_packet->len = size - 4;
12924a9a543dSMatthias Ringwald     memcpy(tx_packet->payload, &packet[4], size - 4);
12934a9a543dSMatthias Ringwald     btstack_linked_queue_enqueue(&ctx.tx_queue, (btstack_linked_item_t *) tx_packet);
12944a9a543dSMatthias Ringwald }
12954a9a543dSMatthias Ringwald 
12964a9a543dSMatthias Ringwald void ll_register_packet_handler(void (*packet_handler)(uint8_t packet_type, uint8_t * packet, uint16_t size)){
12974a9a543dSMatthias Ringwald     controller_packet_handler = packet_handler;
12984a9a543dSMatthias Ringwald }
1299