/* * Copyright (c) 2018-2019 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #if defined(CONFIG_BT_CTLR_RX_PDU_META) #include "lll_meta.h" #endif /* CONFIG_BT_CTLR_RX_PDU_META */ #define TICKER_INSTANCE_ID_CTLR 0 #define TICKER_USER_ID_LLL MAYFLY_CALL_ID_0 #define TICKER_USER_ID_ULL_HIGH MAYFLY_CALL_ID_1 #define TICKER_USER_ID_ULL_LOW MAYFLY_CALL_ID_2 #define TICKER_USER_ID_THREAD MAYFLY_CALL_ID_PROGRAM #define EVENT_PIPELINE_MAX 7 #define EVENT_DONE_MAX 3 #define HDR_ULL(p) ((void *)((u8_t *)(p) + sizeof(struct evt_hdr))) #define HDR_ULL2LLL(p) ((struct lll_hdr *)((u8_t *)(p) + \ sizeof(struct ull_hdr))) #define HDR_LLL2EVT(p) ((struct evt_hdr *)((struct lll_hdr *)(p))->parent) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) #define XON_BITMASK BIT(31) /* XTAL has been retained from previous prepare */ #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ #if defined(CONFIG_BT_BROADCASTER) && defined(CONFIG_BT_ADV_SET) #define BT_CTLR_ADV_MAX (CONFIG_BT_ADV_SET + 1) #else #define BT_CTLR_ADV_MAX 1 #endif enum { TICKER_ID_LLL_PREEMPT = 0, #if defined(CONFIG_BT_BROADCASTER) TICKER_ID_ADV_STOP, TICKER_ID_ADV_BASE, #if defined(CONFIG_BT_CTLR_ADV_EXT) || defined(CONFIG_BT_HCI_MESH_EXT) TICKER_ID_ADV_LAST = ((TICKER_ID_ADV_BASE) + (BT_CTLR_ADV_MAX) - 1), #endif /* !CONFIG_BT_CTLR_ADV_EXT || !CONFIG_BT_HCI_MESH_EXT */ #endif /* CONFIG_BT_BROADCASTER */ #if defined(CONFIG_BT_OBSERVER) TICKER_ID_SCAN_STOP, TICKER_ID_SCAN_BASE, TICKER_ID_SCAN_LAST = TICKER_ID_SCAN_BASE, #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_CONN) TICKER_ID_CONN_BASE, TICKER_ID_CONN_LAST = ((TICKER_ID_CONN_BASE) + (CONFIG_BT_MAX_CONN) - 1), #endif /* CONFIG_BT_CONN */ TICKER_ID_MAX, }; #if defined(CONFIG_BT_BROADCASTER) && !defined(CONFIG_BT_CTLR_ADV_EXT) && \ !defined(CONFIG_BT_HCI_MESH_EXT) #define TICKER_ID_ADV_LAST TICKER_ID_ADV_BASE #endif #define TICKER_ID_ULL_BASE ((TICKER_ID_LLL_PREEMPT) + 1) enum ull_status { ULL_STATUS_SUCCESS, ULL_STATUS_FAILURE, ULL_STATUS_BUSY, }; struct evt_hdr { u32_t ticks_xtal_to_start; u32_t ticks_active_to_start; u32_t ticks_preempt_to_start; u32_t ticks_slot; }; struct ull_hdr { u8_t ref; /* Number of ongoing (between Prepare and Done) events */ void (*disabled_cb)(void *param); void *disabled_param; }; struct lll_hdr { void *parent; u8_t is_stop:1; }; struct lll_prepare_param { u32_t ticks_at_expire; u32_t remainder; u16_t lazy; void *param; }; typedef int (*lll_prepare_cb_t)(struct lll_prepare_param *prepare_param); typedef int (*lll_is_abort_cb_t)(void *next, int prio, void *curr, lll_prepare_cb_t *resume_cb, int *resume_prio); typedef void (*lll_abort_cb_t)(struct lll_prepare_param *prepare_param, void *param); struct lll_event { struct lll_prepare_param prepare_param; lll_prepare_cb_t prepare_cb; lll_is_abort_cb_t is_abort_cb; lll_abort_cb_t abort_cb; int prio; u8_t is_resume:1; u8_t is_aborted:1; }; enum node_rx_type { /* Unused */ NODE_RX_TYPE_NONE = 0x00, /* Signals completion of RX event */ NODE_RX_TYPE_EVENT_DONE = 0x01, /* Signals arrival of RX Data Channel payload */ NODE_RX_TYPE_DC_PDU = 0x02, /* Signals release of RX Data Channel payload */ NODE_RX_TYPE_DC_PDU_RELEASE = 0x03, #if defined(CONFIG_BT_OBSERVER) /* Advertisement report from scanning */ NODE_RX_TYPE_REPORT = 0x04, #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_CTLR_ADV_EXT) NODE_RX_TYPE_EXT_1M_REPORT = 0x05, NODE_RX_TYPE_EXT_CODED_REPORT = 0x06, #endif /* CONFIG_BT_CTLR_ADV_EXT */ #if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY) NODE_RX_TYPE_SCAN_REQ = 0x07, #endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */ #if defined(CONFIG_BT_CONN) NODE_RX_TYPE_CONNECTION = 0x08, NODE_RX_TYPE_TERMINATE = 0x09, NODE_RX_TYPE_CONN_UPDATE = 0x0A, NODE_RX_TYPE_ENC_REFRESH = 0x0B, #if defined(CONFIG_BT_CTLR_LE_PING) NODE_RX_TYPE_APTO = 0x0C, #endif /* CONFIG_BT_CTLR_LE_PING */ NODE_RX_TYPE_CHAN_SEL_ALGO = 0x0D, #if defined(CONFIG_BT_CTLR_PHY) NODE_RX_TYPE_PHY_UPDATE = 0x0E, #endif /* CONFIG_BT_CTLR_PHY */ #if defined(CONFIG_BT_CTLR_CONN_RSSI) NODE_RX_TYPE_RSSI = 0x0F, #endif /* CONFIG_BT_CTLR_CONN_RSSI */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CTLR_PROFILE_ISR) NODE_RX_TYPE_PROFILE = 0x10, #endif /* CONFIG_BT_CTLR_PROFILE_ISR */ #if defined(CONFIG_BT_CTLR_ADV_INDICATION) NODE_RX_TYPE_ADV_INDICATION = 0x11, #endif /* CONFIG_BT_CTLR_ADV_INDICATION */ #if defined(CONFIG_BT_CTLR_SCAN_INDICATION) NODE_RX_TYPE_SCAN_INDICATION = 0x12, #endif /* CONFIG_BT_CTLR_SCAN_INDICATION */ #if defined(CONFIG_BT_HCI_MESH_EXT) NODE_RX_TYPE_MESH_ADV_CPLT = 0x13, NODE_RX_TYPE_MESH_REPORT = 0x14, #endif /* CONFIG_BT_HCI_MESH_EXT */ /* Following proprietary defines must be at end of enum range */ #if defined(CONFIG_BT_CTLR_USER_EXT) NODE_RX_TYPE_USER_START = 0x15, NODE_RX_TYPE_USER_END = NODE_RX_TYPE_USER_START + CONFIG_BT_CTLR_USER_EVT_RANGE, #endif /* CONFIG_BT_CTLR_USER_EXT */ }; /* Footer of node_rx_hdr */ struct node_rx_ftr { void *param; void *extra; u32_t ticks_anchor; u32_t us_radio_end; u32_t us_radio_rdy; u8_t rssi; #if defined(CONFIG_BT_CTLR_PRIVACY) u8_t rl_idx; #endif /* CONFIG_BT_CTLR_PRIVACY */ #if defined(CONFIG_BT_CTLR_EXT_SCAN_FP) u8_t direct; #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ #if defined(CONFIG_BT_HCI_MESH_EXT) u8_t chan_idx; #endif /* CONFIG_BT_HCI_MESH_EXT */ }; /* Header of node_rx_pdu */ struct node_rx_hdr { union { void *next; memq_link_t *link; u8_t ack_last; }; enum node_rx_type type; u8_t user_meta; /* User metadata */ u16_t handle; union { #if defined(CONFIG_BT_CTLR_RX_PDU_META) lll_rx_pdu_meta_t rx_pdu_meta; #endif /* CONFIG_BT_CTLR_RX_PDU_META */ struct node_rx_ftr rx_ftr; }; }; struct node_rx_pdu { struct node_rx_hdr hdr; u8_t pdu[0]; }; enum { EVENT_DONE_EXTRA_TYPE_NONE, EVENT_DONE_EXTRA_TYPE_CONN, /* Following proprietary defines must be at end of enum range */ #if defined(CONFIG_BT_CTLR_USER_EXT) EVENT_DONE_EXTRA_TYPE_USER_START, EVENT_DONE_EXTRA_TYPE_USER_END = EVENT_DONE_EXTRA_TYPE_USER_START + CONFIG_BT_CTLR_USER_EVT_RANGE, #endif /* CONFIG_BT_CTLR_USER_EXT */ }; struct event_done_extra_slave { u32_t start_to_address_actual_us; u32_t window_widening_event_us; u32_t preamble_to_addr_us; }; struct event_done_extra { u8_t type; union { struct { u16_t trx_cnt; u8_t crc_valid; #if defined(CONFIG_BT_CTLR_LE_ENC) u8_t mic_state; #endif /* CONFIG_BT_CTLR_LE_ENC */ union { struct event_done_extra_slave slave; }; }; }; }; struct node_rx_event_done { struct node_rx_hdr hdr; void *param; struct event_done_extra extra; }; static inline void lll_hdr_init(void *lll, void *parent) { struct lll_hdr *hdr = lll; hdr->parent = parent; hdr->is_stop = 0U; } static inline int lll_stop(void *lll) { struct lll_hdr *hdr = lll; int ret = !!hdr->is_stop; hdr->is_stop = 1U; return ret; } static inline int lll_is_stop(void *lll) { struct lll_hdr *hdr = lll; return !!hdr->is_stop; } int lll_init(void); int lll_reset(void); int lll_prepare(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, lll_prepare_cb_t prepare_cb, int prio, struct lll_prepare_param *prepare_param); void lll_resume(void *param); void lll_disable(void *param); u32_t lll_radio_is_idle(void); s8_t lll_radio_tx_pwr_min_get(void); s8_t lll_radio_tx_pwr_max_get(void); s8_t lll_radio_tx_pwr_floor(s8_t tx_pwr_lvl); int ull_prepare_enqueue(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, struct lll_prepare_param *prepare_param, lll_prepare_cb_t prepare_cb, int prio, u8_t is_resume); void *ull_prepare_dequeue_get(void); void *ull_prepare_dequeue_iter(u8_t *idx); void *ull_pdu_rx_alloc_peek(u8_t count); void *ull_pdu_rx_alloc_peek_iter(u8_t *idx); void *ull_pdu_rx_alloc(void); void ull_rx_put(memq_link_t *link, void *rx); void ull_rx_sched(void); void *ull_event_done_extra_get(void); void *ull_event_done(void *param);