/*
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
* Copyright (c) 2016 Vinayak Kariappa Chettimada
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <soc.h>
#include <device.h>
#include <clock_control.h>
#include <bluetooth/hci.h>
#include <misc/util.h>
#include "ll.h"
#include "hal/cpu.h"
#include "hal/rand.h"
#include "hal/ecb.h"
#include "hal/ccm.h"
#include "hal/radio.h"
#include "hal/debug.h"
#include "util/util.h"
#include "util/mem.h"
#include "util/memq.h"
#include "util/mayfly.h"
#include "ticker/ticker.h"
#include "pdu.h"
#include "ctrl.h"
#include "ctrl_internal.h"
#include "ll_filter.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
#include "common/log.h"
#define RADIO_TIFS 150
#define RADIO_CONN_EVENTS(x, y) ((u16_t)(((x) + (y) - 1) / (y)))
#if defined(CONFIG_BT_CTLR_PHY_CODED)
#define RADIO_PKT_TIME(octets, phy) \
(((phy) & BIT(2)) ? (80 + 256 + 16 + 24 + ((((2 + (octets) + 4) * 8) + \
24 + 3) * 8)) : \
(((octets) + 14) * 8 / BIT(((phy) & 0x03) >> 1)))
#else /* !CONFIG_BT_CTLR_PHY_CODED */
#define RADIO_PKT_TIME(octets, phy) \
(((octets) + 14) * 8 / BIT(((phy) & 0x03) >> 1))
#endif /* !CONFIG_BT_CTLR_PHY_CODED */
#define RADIO_TICKER_JITTER_US 16
#define RADIO_TICKER_START_PART_US 300
#define RADIO_TICKER_XTAL_OFFSET_US 1200
#define RADIO_TICKER_PREEMPT_PART_US 0
#define RADIO_TICKER_PREEMPT_PART_MIN_US 0
#define RADIO_TICKER_PREEMPT_PART_MAX_US RADIO_TICKER_XTAL_OFFSET_US
#if defined(CONFIG_BT_CTLR_CONN_RSSI)
#define RADIO_RSSI_SAMPLE_COUNT 10
#define RADIO_RSSI_THRESHOLD 4
#endif /* CONFIG_BT_CTLR_CONN_RSSI */
#define RADIO_IRK_COUNT_MAX 8
#define SILENT_CONNECTION 0
enum role {
ROLE_NONE,
ROLE_ADV,
ROLE_SCAN,
ROLE_SLAVE,
ROLE_MASTER,
};
enum state {
STATE_NONE,
STATE_RX,
STATE_TX,
STATE_CLOSE,
STATE_STOP,
STATE_ABORT,
};
struct advertiser {
struct shdr hdr;
u8_t is_enabled:1;
u8_t chan_map_current:3;
u8_t rfu:4;
#if defined(CONFIG_BT_CTLR_ADV_EXT)
u8_t phy_p:3;
#endif /* CONFIG_BT_CTLR_ADV_EXT */
u8_t chan_map:3;
u8_t filter_policy:2;
#if defined(CONFIG_BT_CTLR_PRIVACY)
u8_t rl_idx;
#endif /* CONFIG_BT_CTLR_PRIVACY */
struct radio_adv_data adv_data;
struct radio_adv_data scan_data;
struct connection *conn;
};
struct scanner {
struct shdr hdr;
u8_t is_enabled:1;
u8_t state:1;
u8_t chan:2;
u8_t rfu:4;
#if defined(CONFIG_BT_CTLR_ADV_EXT)
u8_t phy:3;
#endif /* CONFIG_BT_CTLR_ADV_EXT */
u8_t type:1;
u8_t filter_policy:2;
u8_t adv_addr_type:1;
u8_t init_addr_type:1;
#if defined(CONFIG_BT_CTLR_PRIVACY)
u8_t rpa_gen:1;
/* initiator only */
u8_t rl_idx;
#endif /* CONFIG_BT_CTLR_PRIVACY */
u8_t init_addr[BDADDR_SIZE];
u8_t adv_addr[BDADDR_SIZE];
u32_t ticks_window;
u16_t conn_interval;
u16_t conn_latency;
u16_t conn_timeout;
u32_t ticks_conn_slot;
struct connection *conn;
u32_t win_offset_us;
};
static struct {
struct device *hf_clock;
u32_t ticks_anchor;
u32_t remainder_anchor;
u8_t volatile ticker_id_prepare;
u8_t volatile ticker_id_event;
u8_t volatile ticker_id_stop;
enum role volatile role;
enum state state;
struct advertiser advertiser;
struct scanner scanner;
void *conn_pool;
void *conn_free;
u8_t connection_count;
struct connection *conn_curr;
u8_t packet_counter;
u8_t crc_expire;
u8_t data_chan_map[5];
u8_t data_chan_count;
u8_t sca;
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
/* DLE global settings */
u16_t default_tx_octets;
u16_t default_tx_time;
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
#if defined(CONFIG_BT_CTLR_PHY)
u16_t default_phy_tx;
u16_t default_phy_rx;
#endif /* CONFIG_BT_CTLR_PHY */
/** @todo below members to be made role specific and quota managed for
* Rx-es.
*/
/* Advertiser, Scanner, and Connections Rx data pool */
void *pkt_rx_data_pool;
void *pkt_rx_data_free;
u16_t packet_data_octets_max;
u16_t packet_rx_data_pool_size;
u16_t packet_rx_data_size;
u8_t packet_rx_data_count;
/* Free queue Rx data buffers */
struct radio_pdu_node_rx **packet_rx;
u8_t packet_rx_count;
u8_t volatile packet_rx_last;
u8_t packet_rx_acquire;
/* Controller to Host event-cum-data queue */
void *link_rx_pool;
void *link_rx_free;
void *link_rx_head;
void *volatile link_rx_tail;
u8_t link_rx_data_quota;
/* Connections common Tx ctrl and data pool */
void *pkt_tx_ctrl_pool;
void *pkt_tx_ctrl_free;
void *pkt_tx_data_pool;
void *pkt_tx_data_free;
u16_t packet_tx_data_size;
/* Host to Controller Tx, and Controller to Host Num complete queue */
struct pdu_data_q_tx *pkt_tx;
struct pdu_data_q_tx *pkt_release;
u8_t packet_tx_count;
u8_t volatile packet_tx_first;
u8_t packet_tx_last;
u8_t packet_release_first;
u8_t volatile packet_release_last;
u16_t fc_handle[TRIPLE_BUFFER_SIZE];
u8_t volatile fc_req;
u8_t fc_ack;
u8_t fc_ena;
u32_t ticks_active_to_start;
struct connection *conn_upd;
} _radio;
static u16_t const gc_lookup_ppm[] = { 500, 250, 150, 100, 75, 50, 30, 20 };
static void common_init(void);
static void ticker_success_assert(u32_t status, void *params);
static void ticker_stop_adv_assert(u32_t status, void *params);
static void ticker_stop_scan_assert(u32_t status, void *params);
static void ticker_update_adv_assert(u32_t status, void *params);
static void ticker_update_slave_assert(u32_t status, void *params);
static void event_inactive(u32_t ticks_at_expire, u32_t remainder,
u16_t lazy, void *context);
#if defined(RADIO_UNIT_TEST) && \
defined(CONFIG_BT_CTLR_CHAN_SEL_2)
static void chan_sel_2_ut(void);
#endif /* CONFIG_BT_CTLR_CHAN_SEL_2 */
static void adv_setup(void);
static void event_adv(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
void *context);
static void event_scan(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
void *context);
static void event_slave_prepare(u32_t ticks_at_expire, u32_t remainder,
u16_t lazy, void *context);
static void event_slave(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
void *context);
static void event_master_prepare(u32_t ticks_at_expire, u32_t remainder,
u16_t lazy, void *context);
static void event_master(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
void *context);
static void rx_packet_set(struct connection *conn,
struct pdu_data *pdu_data_rx);
static void tx_packet_set(struct connection *conn,
struct pdu_data *pdu_data_tx);
static void prepare_pdu_data_tx(struct connection *conn,
struct pdu_data **pdu_data_tx);
static void packet_rx_allocate(u8_t max);
static inline u8_t packet_rx_acquired_count_get(void);
static inline struct radio_pdu_node_rx *packet_rx_reserve_get(u8_t count);
static void packet_rx_enqueue(void);
static void packet_tx_enqueue(u8_t max);
static struct pdu_data *empty_tx_enqueue(struct connection *conn);
static void ctrl_tx_enqueue(struct connection *conn,
struct radio_pdu_node_tx *node_tx);
static void pdu_node_tx_release(u16_t handle,
struct radio_pdu_node_tx *node_tx);
static void connection_release(struct connection *conn);
static void terminate_ind_rx_enqueue(struct connection *conn, u8_t reason);
static u32_t conn_update(struct connection *conn, struct pdu_data *pdu_data_rx);
#if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
static u32_t conn_update_req(struct connection *conn);
#endif /* CONFIG_BT_CTLR_SCHED_ADVANCED */
static u32_t chan_map_update(struct connection *conn,
struct pdu_data *pdu_data_rx);
#if defined(CONFIG_BT_CTLR_PHY)
static inline u32_t phy_upd_ind(struct radio_pdu_node_rx *radio_pdu_node_rx,
u8_t *rx_enqueue);
#endif /* CONFIG_BT_CTLR_PHY */
#if defined(CONFIG_BT_CTLR_LE_ENC)
static void enc_req_reused_send(struct connection *conn,
struct radio_pdu_node_tx *node_tx);
static u8_t enc_rsp_send(struct connection *conn);
static u8_t start_enc_rsp_send(struct connection *conn,
struct pdu_data *pdu_ctrl_tx);
static u8_t pause_enc_rsp_send(struct connection *conn, u8_t req);
#endif /* CONFIG_BT_CTLR_LE_ENC */
static u8_t unknown_rsp_send(struct connection *conn, u8_t type);
static u8_t feature_rsp_send(struct connection *conn,
struct pdu_data *pdu_data_rx);
static u8_t version_ind_send(struct connection *conn,
struct pdu_data *pdu_data_rx, u8_t *rx_enqueue);
#if defined(CONFIG_BT_CTLR_LE_PING)
static u8_t ping_resp_send(struct connection *conn);
#endif /* CONFIG_BT_CTLR_LE_PING */
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) || \
defined(CONFIG_BT_CTLR_PHY)
static u8_t reject_ext_ind_send(struct connection *conn, u8_t reject_opcode,
u8_t error_code);
#endif
#if defined(