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
232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald * GMBH 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,
171b97c8672SMatthias 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;
328b97c8672SMatthias 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
btstack_memory_ll_pdu_get(void)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
btstack_memory_ll_pdu_free(ll_pdu_t * acl_le_pdu)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
radio_auto_tx_on(void)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
radio_auto_tx_off(void)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
receive_prepare_rx_bufffer(void)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
receive_response(void)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
receive_first_master(void)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
receive_master(void)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
setup_adv_pdu(uint8_t offset,uint8_t header,uint8_t len,const uint8_t * data)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
send_adv(void)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
select_channel(uint8_t channel)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
next_channel(void)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
ll_advertising_statemachine(void)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);
501b97c8672SMatthias Ringwald if (ctx.adv_type == 3) {
502b97c8672SMatthias Ringwald // Non connectable undirected advertising (ADV_NONCONN_IND)
503b97c8672SMatthias Ringwald radio_state = RADIO_W4_TX_ONLY_DONE;
504b97c8672SMatthias Ringwald } else {
505b97c8672SMatthias Ringwald // All other are either connectable and/or scannable
5064a9a543dSMatthias Ringwald radio_state = RADIO_W4_TX_DONE_TO_RX;
507b97c8672SMatthias 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
start_advertising(void)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
start_hopping(void)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
radio_stop_timer(void)5704a9a543dSMatthias Ringwald static void radio_stop_timer(void){
5714a9a543dSMatthias Ringwald hal_timer_stop();
5724a9a543dSMatthias Ringwald }
5734a9a543dSMatthias Ringwald
radio_set_timer_ticks(uint32_t anchor_offset_ticks)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
ctx_set_conn_interval(uint16_t conn_interval_1250us)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
ll_terminate(void)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
preload_tx_buffer(void)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
radio_timer_handler(void)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
radio_fetch_rx_pdu(void)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 */
radio_on_tx_done(void)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;
741b97c8672SMatthias Ringwald case RADIO_W4_TX_ONLY_DONE:
742b97c8672SMatthias Ringwald radio_state = RADIO_LOWPOWER;
743b97c8672SMatthias 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 }
radio_prepare_auto_tx(uint16_t packet_end_ticks,uint8_t rx_len)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
radio_on_rx_done(void)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);
826b97c8672SMatthias 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
radio_on_tx_timeout(void)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
radio_on_rx_timeout(void)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
radio_on_rx_error(IrqErrorCode_t errorCode)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
ll_emit_hci_event(const hci_event_t * event,...)9444a9a543dSMatthias Ringwald static void ll_emit_hci_event(const hci_event_t * event, ...){
9454a9a543dSMatthias Ringwald va_list argptr;
9464a9a543dSMatthias Ringwald va_start(argptr, event);
947*cf1c3df9SMatthias Ringwald uint16_t length = hci_event_create_from_template_and_arglist(ll_outgoing_hci_event, sizeof(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
ll_init(void)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
ll_radio_on(void)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
ll_handle_conn_ind(ll_pdu_t * rx_packet)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
ll_queue_control_tx(void)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
ll_handle_control(ll_pdu_t * rx_packet)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:
11368f693d4aSMatthias Ringwald ctx.conn_param_update_win_size = rx_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
ll_handle_data(ll_pdu_t * rx_packet)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
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)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
ll_start_scanning(uint8_t filter_duplicates)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
ll_stop_scanning(void)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
ll_set_scan_enable(uint8_t le_scan_enable,uint8_t filter_duplicates)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
ll_start_advertising(void)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
ll_stop_advertising(void)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
ll_set_advertise_enable(uint8_t le_adv_enable)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
ll_set_advertising_parameters(uint16_t advertising_interval_min,uint16_t advertising_interval_max,uint8_t advertising_type,uint8_t own_address_type,uint8_t peer_address_types,uint8_t * peer_address,uint8_t advertising_channel_map,uint8_t advertising_filter_policy)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;
1279b97c8672SMatthias 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
ll_set_advertising_data(uint8_t adv_len,const uint8_t * adv_data)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
ll_set_scan_response_data(uint8_t adv_len,const uint8_t * adv_data)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
ll_execute_once(void)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 }
ll_reserve_acl_packet(void)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
ll_queue_acl_packet(const uint8_t * packet,uint16_t size)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
ll_register_packet_handler(void (* packet_handler)(uint8_t packet_type,uint8_t * packet,uint16_t size))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