Bluetooth: Controller: A full, hardware-agnostic BLE Link Layer
The ll/ folder contains a full implementation of a BLE Link Layer interfacing with a baseband and a radio through radio.h. The current code implements most Bluetooth 4.2 features and is currently functional and tested with nRF5x ICs from Nordic Semiconductor. Jira: ZEP-702 Origin: Original Change-Id: Ib79cd97142d1a72c99dcf2a88116ac97ddd90a2b Signed-off-by: Vinayak Chettimada <vinayak.kariappa.chettimada@nordicsemi.no> Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
parent
c160a0548d
commit
48c48711e6
|
@ -1,5 +1,6 @@
|
|||
ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/drivers/bluetooth/controller/util
|
||||
ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/drivers/bluetooth/controller/hal
|
||||
ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/drivers/bluetooth/controller/ll
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/mem.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/memq.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/work.o
|
||||
|
@ -10,4 +11,7 @@ obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/rtc.o
|
|||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/rand.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/ecb.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/radio.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += ll/ticker.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += ll/ctrl.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += ll/ll.o
|
||||
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hci/hci.o
|
||||
|
|
7632
drivers/bluetooth/controller/ll/ctrl.c
Normal file
7632
drivers/bluetooth/controller/ll/ctrl.c
Normal file
File diff suppressed because it is too large
Load diff
255
drivers/bluetooth/controller/ll/ctrl.h
Normal file
255
drivers/bluetooth/controller/ll/ctrl.h
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _CTRL_H_
|
||||
#define _CTRL_H_
|
||||
|
||||
/*****************************************************************************
|
||||
* Zephyr Kconfig defined
|
||||
****************************************************************************/
|
||||
#ifdef CONFIG_BLUETOOTH_MAX_CONN
|
||||
#define RADIO_CONNECTION_CONTEXT_MAX CONFIG_BLUETOOTH_MAX_CONN
|
||||
#else
|
||||
#define RADIO_CONNECTION_CONTEXT_MAX 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLUETOOTH_CONTROLLER_DATA_LENGTH
|
||||
#define RADIO_LL_LENGTH_OCTETS_RX_MAX \
|
||||
CONFIG_BLUETOOTH_CONTROLLER_DATA_LENGTH
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLUETOOTH_CONTROLLER_RX_BUFFERS
|
||||
#define RADIO_PACKET_COUNT_RX_MAX \
|
||||
CONFIG_BLUETOOTH_CONTROLLER_RX_BUFFERS
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLUETOOTH_CONTROLLER_TX_BUFFERS
|
||||
#define RADIO_PACKET_COUNT_TX_MAX \
|
||||
CONFIG_BLUETOOTH_CONTROLLER_TX_BUFFERS
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Timer Resources (Controller defined)
|
||||
****************************************************************************/
|
||||
#define RADIO_TICKER_ID_EVENT 0
|
||||
#define RADIO_TICKER_ID_MARKER_0 1
|
||||
#define RADIO_TICKER_ID_PRE_EMPT 2
|
||||
#define RADIO_TICKER_ID_ADV_STOP 3
|
||||
#define RADIO_TICKER_ID_OBS_STOP 4
|
||||
#define RADIO_TICKER_ID_ADV 5
|
||||
#define RADIO_TICKER_ID_OBS 6
|
||||
#define RADIO_TICKER_ID_FIRST_CONNECTION 7
|
||||
|
||||
#define RADIO_TICKER_INSTANCE_ID_RADIO 0
|
||||
#define RADIO_TICKER_INSTANCE_ID_APP 1
|
||||
|
||||
#define RADIO_TICKER_USERS 3
|
||||
|
||||
#define RADIO_TICKER_USER_ID_WORKER 0
|
||||
#define RADIO_TICKER_USER_ID_JOB 1
|
||||
#define RADIO_TICKER_USER_ID_APP 2
|
||||
|
||||
#define RADIO_TICKER_USER_WORKER_OPS (7 + 1)
|
||||
#define RADIO_TICKER_USER_JOB_OPS (2 + 1)
|
||||
#define RADIO_TICKER_USER_APP_OPS (1 + 1)
|
||||
#define RADIO_TICKER_USER_OPS (RADIO_TICKER_USER_WORKER_OPS \
|
||||
+ RADIO_TICKER_USER_JOB_OPS \
|
||||
+ RADIO_TICKER_USER_APP_OPS \
|
||||
)
|
||||
|
||||
#define RADIO_TICKER_NODES (RADIO_TICKER_ID_FIRST_CONNECTION \
|
||||
+ RADIO_CONNECTION_CONTEXT_MAX \
|
||||
)
|
||||
|
||||
/*****************************************************************************
|
||||
* Controller Interface Defines
|
||||
****************************************************************************/
|
||||
#define RADIO_BLE_VERSION_NUMBER (0x08)
|
||||
#define RADIO_BLE_COMPANY_ID (0xFFFF)
|
||||
#define RADIO_BLE_SUB_VERSION_NUMBER (0xFFFF)
|
||||
#define RADIO_BLE_FEATURES (0x1F) /* LE Ping, Slave Initiated
|
||||
* Feature request, Extended
|
||||
* Reject Indication, Conn Param
|
||||
* Req Procedure, LE encryption.
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* Controller Reference Defines (compile time override-able)
|
||||
****************************************************************************/
|
||||
/* Minimum LL Payload support (Dont change). */
|
||||
#define RADIO_LL_LENGTH_OCTETS_RX_MIN 27
|
||||
#define RADIO_LL_LENGTH_TIME_RX_MIN (((RADIO_LL_LENGTH_OCTETS_RX_MIN) \
|
||||
+ 14) * 8 \
|
||||
)
|
||||
|
||||
/* Maximum LL Payload support (27 to 251). */
|
||||
#ifndef RADIO_LL_LENGTH_OCTETS_RX_MAX
|
||||
#define RADIO_LL_LENGTH_OCTETS_RX_MAX 251
|
||||
#endif
|
||||
#define RADIO_LL_LENGTH_TIME_RX_MAX (((RADIO_LL_LENGTH_OCTETS_RX_MAX) \
|
||||
+ 14) * 8 \
|
||||
)
|
||||
/* Implementation default L2CAP MTU */
|
||||
#ifndef RADIO_L2CAP_MTU_MAX
|
||||
#define RADIO_L2CAP_MTU_MAX (RADIO_LL_LENGTH_OCTETS_RX_MAX - 4)
|
||||
#endif
|
||||
|
||||
/* Maximise L2CAP MTU to LL data PDU size */
|
||||
#if (RADIO_L2CAP_MTU_MAX < (RADIO_LL_LENGTH_OCTETS_RX_MAX - 4))
|
||||
#undef RADIO_L2CAP_MTU_MAX
|
||||
#define RADIO_L2CAP_MTU_MAX (RADIO_LL_LENGTH_OCTETS_RX_MAX - 4)
|
||||
#endif
|
||||
|
||||
/* Maximum LL PDU Receive pool size. */
|
||||
#ifndef RADIO_PACKET_COUNT_RX_MAX
|
||||
#define RADIO_PACKET_COUNT_RX ((RADIO_L2CAP_MTU_MAX + \
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX \
|
||||
+ 3) \
|
||||
/ \
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX \
|
||||
)
|
||||
#define RADIO_PACKET_COUNT_RX_MAX (RADIO_PACKET_COUNT_RX + \
|
||||
((RADIO_CONNECTION_CONTEXT_MAX - 1) * \
|
||||
(RADIO_PACKET_COUNT_RX - 1)) \
|
||||
)
|
||||
#endif /* RADIO_PACKET_COUNT_RX_MAX */
|
||||
|
||||
/* Maximum LL PDU Transmit pool size and application tx count. */
|
||||
#ifndef RADIO_PACKET_COUNT_TX_MAX
|
||||
#define RADIO_PACKET_COUNT_APP_TX_MAX (RADIO_CONNECTION_CONTEXT_MAX)
|
||||
#define RADIO_PACKET_COUNT_TX_MAX (RADIO_PACKET_COUNT_RX_MAX + \
|
||||
RADIO_PACKET_COUNT_APP_TX_MAX \
|
||||
)
|
||||
#else
|
||||
#define RADIO_PACKET_COUNT_APP_TX_MAX (RADIO_PACKET_COUNT_TX_MAX)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Controller Interface Structures
|
||||
****************************************************************************/
|
||||
struct radio_adv_data {
|
||||
uint8_t data[DOUBLE_BUFFER_SIZE][RADIO_ACPDU_SIZE_MAX];
|
||||
uint8_t first;
|
||||
uint8_t last;
|
||||
};
|
||||
|
||||
struct __packed radio_le_conn_cmplt {
|
||||
uint8_t status;
|
||||
uint8_t role;
|
||||
uint8_t peer_addr_type;
|
||||
uint8_t peer_addr[BDADDR_SIZE];
|
||||
uint8_t own_addr_type;
|
||||
uint8_t own_addr[BDADDR_SIZE];
|
||||
uint8_t peer_irk_index;
|
||||
uint16_t interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
uint8_t mca;
|
||||
};
|
||||
|
||||
struct __packed radio_le_conn_update_cmplt {
|
||||
uint8_t status;
|
||||
uint16_t interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
};
|
||||
|
||||
struct radio_pdu_node_tx {
|
||||
void *next;
|
||||
uint8_t pdu_data[1];
|
||||
};
|
||||
|
||||
enum radio_pdu_node_rx_type {
|
||||
NODE_RX_TYPE_NONE,
|
||||
NODE_RX_TYPE_DC_PDU,
|
||||
NODE_RX_TYPE_PROFILE,
|
||||
NODE_RX_TYPE_REPORT,
|
||||
NODE_RX_TYPE_CONNECTION,
|
||||
NODE_RX_TYPE_TERMINATE,
|
||||
NODE_RX_TYPE_CONN_UPDATE,
|
||||
NODE_RX_TYPE_ENC_REFRESH,
|
||||
NODE_RX_TYPE_APTO,
|
||||
NODE_RX_TYPE_RSSI,
|
||||
};
|
||||
|
||||
struct radio_pdu_node_rx_hdr {
|
||||
enum radio_pdu_node_rx_type type;
|
||||
uint16_t handle;
|
||||
union {
|
||||
void *next;
|
||||
void *link;
|
||||
uint8_t packet_release_last;
|
||||
} onion;
|
||||
};
|
||||
|
||||
struct radio_pdu_node_rx {
|
||||
struct radio_pdu_node_rx_hdr hdr;
|
||||
uint8_t pdu_data[1];
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Controller Interface Functions
|
||||
****************************************************************************/
|
||||
uint32_t radio_init(uint8_t sca, uint8_t connection_count_max,
|
||||
uint8_t rx_count_max, uint8_t tx_count_max,
|
||||
uint16_t data_octets_max, uint8_t *mem_radio,
|
||||
uint16_t mem_size);
|
||||
void radio_ticks_active_to_start_set(uint32_t ticks_active_to_start);
|
||||
struct radio_adv_data *radio_adv_data_get(void);
|
||||
struct radio_adv_data *radio_scan_data_get(void);
|
||||
void radio_filter_clear(void);
|
||||
uint32_t radio_filter_add(uint8_t addr_type, uint8_t *addr);
|
||||
void radio_irk_clear(void);
|
||||
uint32_t radio_irk_add(uint8_t *irk);
|
||||
uint32_t radio_adv_enable(uint16_t interval, uint8_t chl_map,
|
||||
uint8_t filter_policy);
|
||||
uint32_t radio_adv_disable(void);
|
||||
uint32_t radio_scan_enable(uint8_t scan_type, uint8_t init_addr_type,
|
||||
uint8_t *init_addr, uint16_t interval,
|
||||
uint16_t window, uint8_t filter_policy);
|
||||
uint32_t radio_scan_disable(void);
|
||||
uint32_t radio_connect_enable(uint8_t adv_addr_type, uint8_t *adv_addr,
|
||||
uint16_t interval, uint16_t latency,
|
||||
uint16_t timeout);
|
||||
uint32_t radio_connect_disable(void);
|
||||
uint32_t radio_conn_update(uint16_t handle, uint8_t cmd, uint8_t status,
|
||||
uint16_t interval, uint16_t latency,
|
||||
uint16_t timeout);
|
||||
uint32_t radio_chm_update(uint8_t *chm);
|
||||
uint32_t radio_chm_get(uint16_t handle, uint8_t *chm);
|
||||
uint32_t radio_enc_req_send(uint16_t handle, uint8_t *rand, uint8_t *ediv,
|
||||
uint8_t *ltk);
|
||||
uint32_t radio_start_enc_req_send(uint16_t handle, uint8_t err_code,
|
||||
uint8_t const *const ltk);
|
||||
uint32_t radio_feature_req_send(uint16_t handle);
|
||||
uint32_t radio_version_ind_send(uint16_t handle);
|
||||
uint32_t radio_terminate_ind_send(uint16_t handle, uint8_t reason);
|
||||
uint32_t radio_length_req_send(uint16_t handle, uint16_t tx_octets);
|
||||
uint8_t radio_rx_get(struct radio_pdu_node_rx **radio_pdu_node_rx,
|
||||
uint16_t *handle);
|
||||
void radio_rx_dequeue(void);
|
||||
void radio_rx_mem_release(struct radio_pdu_node_rx **radio_pdu_node_rx);
|
||||
uint8_t radio_rx_fc_set(uint16_t handle, uint8_t fc);
|
||||
struct radio_pdu_node_tx *radio_tx_mem_acquire(void);
|
||||
void radio_tx_mem_release(struct radio_pdu_node_tx *pdu_data_node_tx);
|
||||
uint32_t radio_tx_mem_enqueue(uint16_t handle,
|
||||
struct radio_pdu_node_tx *pdu_data_node_tx);
|
||||
|
||||
extern void radio_active_callback(uint8_t active);
|
||||
extern void radio_event_callback(void);
|
||||
|
||||
#endif
|
240
drivers/bluetooth/controller/ll/ctrl_internal.h
Normal file
240
drivers/bluetooth/controller/ll/ctrl_internal.h
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "util/defines.h"
|
||||
#include "pdu.h"
|
||||
#include "ctrl.h"
|
||||
|
||||
enum llcp {
|
||||
LLCP_NONE,
|
||||
LLCP_CONNECTION_UPDATE,
|
||||
LLCP_CHANNEL_MAP,
|
||||
LLCP_ENCRYPTION,
|
||||
LLCP_FEATURE_EXCHANGE,
|
||||
LLCP_VERSION_EXCHANGE,
|
||||
/* LLCP_TERMINATE, */
|
||||
LLCP_PING,
|
||||
/* LLCP_LENGTH, */
|
||||
};
|
||||
|
||||
|
||||
struct shdr {
|
||||
uint32_t ticks_xtal_to_start;
|
||||
uint32_t ticks_active_to_start;
|
||||
uint32_t ticks_preempt_to_start;
|
||||
uint32_t ticks_slot;
|
||||
};
|
||||
|
||||
struct connection {
|
||||
struct shdr hdr;
|
||||
|
||||
uint8_t access_addr[4];
|
||||
uint8_t crc_init[3];
|
||||
uint8_t data_channel_map[5];
|
||||
uint8_t data_channel_count;
|
||||
uint8_t data_channel_hop;
|
||||
uint8_t data_channel_use;
|
||||
uint16_t handle;
|
||||
uint16_t event_counter;
|
||||
uint16_t conn_interval;
|
||||
uint16_t latency;
|
||||
uint16_t latency_prepare;
|
||||
uint16_t latency_event;
|
||||
uint16_t sug_tx_octets;
|
||||
uint16_t max_tx_octets;
|
||||
uint16_t max_rx_octets;
|
||||
uint16_t supervision_reload;
|
||||
uint16_t supervision_expire;
|
||||
uint16_t procedure_reload;
|
||||
uint16_t procedure_expire;
|
||||
uint16_t appto_reload;
|
||||
uint16_t appto_expire;
|
||||
uint16_t apto_reload;
|
||||
uint16_t apto_expire;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint8_t role:1;
|
||||
uint8_t connect_expire;
|
||||
} master;
|
||||
struct {
|
||||
uint8_t role:1;
|
||||
uint8_t sca:3;
|
||||
uint8_t latency_cancel:1;
|
||||
uint32_t window_widening_periodic_us;
|
||||
uint32_t window_widening_max_us;
|
||||
uint32_t window_widening_prepare_us;
|
||||
uint32_t window_widening_event_us;
|
||||
uint32_t window_size_prepare_us;
|
||||
uint32_t window_size_event_us;
|
||||
uint32_t force;
|
||||
uint32_t ticks_to_offset;
|
||||
} slave;
|
||||
} role;
|
||||
|
||||
uint8_t llcp_req;
|
||||
uint8_t llcp_ack;
|
||||
enum llcp llcp_type;
|
||||
union {
|
||||
struct {
|
||||
uint16_t interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
uint8_t preferred_periodicity;
|
||||
uint16_t instant;
|
||||
uint16_t offset0;
|
||||
uint16_t offset1;
|
||||
uint16_t offset2;
|
||||
uint16_t offset3;
|
||||
uint16_t offset4;
|
||||
uint16_t offset5;
|
||||
uint32_t ticks_ref;
|
||||
uint32_t ticks_to_offset_next;
|
||||
uint32_t win_offset_us;
|
||||
uint16_t *pdu_win_offset;
|
||||
uint8_t win_size;
|
||||
uint8_t state:3;
|
||||
#define LLCP_CONN_STATE_INPROG 0 /* master + slave proc in progress
|
||||
* until instant
|
||||
*/
|
||||
#define LLCP_CONN_STATE_INITIATE 1 /* master sends conn_update */
|
||||
#define LLCP_CONN_STATE_REQ 2 /* master / slave send req */
|
||||
#define LLCP_CONN_STATE_RSP 3 /* master rej / slave rej/rsp */
|
||||
#define LLCP_CONN_STATE_APP_WAIT 4 /* app resp */
|
||||
#define LLCP_CONN_STATE_RSP_WAIT 5 /* master rsp or slave conn_update
|
||||
* or rej
|
||||
*/
|
||||
uint8_t is_internal:2;
|
||||
} connection_update;
|
||||
struct {
|
||||
uint8_t initiate;
|
||||
uint8_t chm[5];
|
||||
uint16_t instant;
|
||||
} channel_map;
|
||||
struct {
|
||||
uint8_t error_code;
|
||||
uint8_t rand[8];
|
||||
uint8_t ediv[2];
|
||||
uint8_t ltk[16];
|
||||
uint8_t skd[16];
|
||||
} encryption;
|
||||
} llcp;
|
||||
|
||||
uint8_t llcp_features;
|
||||
|
||||
struct {
|
||||
uint8_t tx:1;
|
||||
uint8_t rx:1;
|
||||
uint8_t version_number;
|
||||
uint16_t company_id;
|
||||
uint16_t sub_version_number;
|
||||
} llcp_version;
|
||||
|
||||
struct {
|
||||
uint8_t req;
|
||||
uint8_t ack;
|
||||
uint8_t reason_own;
|
||||
uint8_t reason_peer;
|
||||
struct {
|
||||
struct radio_pdu_node_rx_hdr hdr;
|
||||
uint8_t reason;
|
||||
} radio_pdu_node_rx;
|
||||
} llcp_terminate;
|
||||
|
||||
struct {
|
||||
uint8_t req;
|
||||
uint8_t ack;
|
||||
uint8_t state:2;
|
||||
#define LLCP_LENGTH_STATE_REQ 0
|
||||
#define LLCP_LENGTH_STATE_ACK_WAIT 1
|
||||
#define LLCP_LENGTH_STATE_RSP_WAIT 2
|
||||
#define LLCP_LENGTH_STATE_RESIZE 3
|
||||
uint16_t rx_octets;
|
||||
uint16_t tx_octets;
|
||||
} llcp_length;
|
||||
|
||||
uint8_t sn:1;
|
||||
uint8_t nesn:1;
|
||||
uint8_t pause_rx:1;
|
||||
uint8_t pause_tx:1;
|
||||
uint8_t enc_rx:1;
|
||||
uint8_t enc_tx:1;
|
||||
uint8_t refresh:1;
|
||||
uint8_t empty:1;
|
||||
|
||||
struct ccm ccm_rx;
|
||||
struct ccm ccm_tx;
|
||||
|
||||
struct radio_pdu_node_tx *pkt_tx_head;
|
||||
struct radio_pdu_node_tx *pkt_tx_ctrl;
|
||||
struct radio_pdu_node_tx *pkt_tx_data;
|
||||
struct radio_pdu_node_tx *pkt_tx_last;
|
||||
uint8_t packet_tx_head_len;
|
||||
uint8_t packet_tx_head_offset;
|
||||
|
||||
uint8_t rssi_latest;
|
||||
uint8_t rssi_reported;
|
||||
uint8_t rssi_sample_count;
|
||||
};
|
||||
#define CONNECTION_T_SIZE ALIGN4(sizeof(struct connection))
|
||||
|
||||
struct pdu_data_q_tx {
|
||||
uint16_t handle;
|
||||
struct radio_pdu_node_tx *node_tx;
|
||||
};
|
||||
|
||||
/** @todo fix starvation when ctrl rx in radio ISR
|
||||
* for multiple connections needs to tx back to peer.
|
||||
*/
|
||||
#define PACKET_MEM_COUNT_TX_CTRL 2
|
||||
|
||||
#define LL_MEM_CONN (sizeof(struct connection) * RADIO_CONNECTION_CONTEXT_MAX)
|
||||
|
||||
#define LL_MEM_RXQ (sizeof(void *) * (RADIO_PACKET_COUNT_RX_MAX + 4))
|
||||
#define LL_MEM_TXQ (sizeof(struct pdu_data_q_tx) * \
|
||||
(RADIO_PACKET_COUNT_TX_MAX + 2))
|
||||
|
||||
#define LL_MEM_RX_POOL_SZ (ALIGN4(__builtin_offsetof(struct radio_pdu_node_rx,\
|
||||
pdu_data) + (\
|
||||
((RADIO_ACPDU_SIZE_MAX + 1) < \
|
||||
(__builtin_offsetof(struct pdu_data, payload) + \
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX)) ? \
|
||||
((__builtin_offsetof(struct pdu_data, payload) + \
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX) * \
|
||||
(RADIO_PACKET_COUNT_RX_MAX + 3)) \
|
||||
: \
|
||||
((RADIO_ACPDU_SIZE_MAX + 1) * \
|
||||
(RADIO_PACKET_COUNT_RX_MAX + 3)) \
|
||||
)))
|
||||
|
||||
#define LL_MEM_RX_LINK_POOL (sizeof(void *) * 2 * ((RADIO_PACKET_COUNT_RX_MAX +\
|
||||
4) + RADIO_CONNECTION_CONTEXT_MAX))
|
||||
|
||||
#define LL_MEM_TX_CTRL_POOL ((ALIGN4(__builtin_offsetof( \
|
||||
struct radio_pdu_node_tx, pdu_data) + \
|
||||
__builtin_offsetof(struct pdu_data, payload) + 27)) * \
|
||||
PACKET_MEM_COUNT_TX_CTRL)
|
||||
#define LL_MEM_RX_DATA_POOL ((ALIGN4(__builtin_offsetof( \
|
||||
struct radio_pdu_node_tx, pdu_data) + \
|
||||
__builtin_offsetof(struct pdu_data, payload) + \
|
||||
RADIO_LL_LENGTH_OCTETS_RX_MAX)) \
|
||||
* (RADIO_PACKET_COUNT_TX_MAX + 2))
|
||||
|
||||
#define LL_MEM_TOTAL (LL_MEM_CONN + LL_MEM_RXQ + (LL_MEM_TXQ * 2) + \
|
||||
LL_MEM_RX_POOL_SZ + \
|
||||
LL_MEM_RX_LINK_POOL + LL_MEM_TX_CTRL_POOL + LL_MEM_RX_DATA_POOL)
|
295
drivers/bluetooth/controller/ll/ll.c
Normal file
295
drivers/bluetooth/controller/ll/ll.c
Normal file
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "defines.h"
|
||||
#include "mem.h"
|
||||
#include "ticker.h"
|
||||
#include "ccm.h"
|
||||
#include "radio.h"
|
||||
#include "pdu.h"
|
||||
#include "ctrl.h"
|
||||
|
||||
#include "ll.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
static struct {
|
||||
uint8_t pub_addr[BDADDR_SIZE];
|
||||
uint8_t rnd_addr[BDADDR_SIZE];
|
||||
} _ll_context;
|
||||
|
||||
static struct {
|
||||
uint16_t interval;
|
||||
uint8_t adv_type:4;
|
||||
uint8_t tx_addr:1;
|
||||
uint8_t rx_addr:1;
|
||||
uint8_t filter_policy:2;
|
||||
uint8_t chl_map:3;
|
||||
uint8_t adv_addr[BDADDR_SIZE];
|
||||
uint8_t direct_addr[BDADDR_SIZE];
|
||||
} _ll_adv_params;
|
||||
|
||||
static struct {
|
||||
uint16_t interval;
|
||||
uint16_t window;
|
||||
uint8_t scan_type:1;
|
||||
uint8_t tx_addr:1;
|
||||
uint8_t filter_policy:1;
|
||||
} _ll_scan_params;
|
||||
|
||||
void ll_address_get(uint8_t addr_type, uint8_t *bdaddr)
|
||||
{
|
||||
if (addr_type) {
|
||||
memcpy(bdaddr, &_ll_context.rnd_addr[0], BDADDR_SIZE);
|
||||
} else {
|
||||
memcpy(bdaddr, &_ll_context.pub_addr[0], BDADDR_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void ll_address_set(uint8_t addr_type, uint8_t const *const bdaddr)
|
||||
{
|
||||
if (addr_type) {
|
||||
memcpy(&_ll_context.rnd_addr[0], bdaddr, BDADDR_SIZE);
|
||||
} else {
|
||||
memcpy(&_ll_context.pub_addr[0], bdaddr, BDADDR_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void ll_adv_params_set(uint16_t interval, uint8_t adv_type,
|
||||
uint8_t own_addr_type, uint8_t direct_addr_type,
|
||||
uint8_t const *const direct_addr, uint8_t chl_map,
|
||||
uint8_t filter_policy)
|
||||
{
|
||||
struct radio_adv_data *radio_adv_data;
|
||||
struct pdu_adv *pdu;
|
||||
|
||||
/** @todo check and fail if adv role active else
|
||||
* update (implemented below) current index elements for
|
||||
* both adv and scan data.
|
||||
*/
|
||||
|
||||
/* remember params so that set adv/scan data and adv enable
|
||||
* interface can correctly update adv/scan data in the
|
||||
* double buffer between caller and controller context.
|
||||
*/
|
||||
_ll_adv_params.interval = interval;
|
||||
_ll_adv_params.chl_map = chl_map;
|
||||
_ll_adv_params.filter_policy = filter_policy;
|
||||
_ll_adv_params.adv_type = adv_type;
|
||||
_ll_adv_params.tx_addr = own_addr_type;
|
||||
_ll_adv_params.rx_addr = 0;
|
||||
|
||||
/* update the current adv data */
|
||||
radio_adv_data = radio_adv_data_get();
|
||||
pdu = (struct pdu_adv *)&radio_adv_data->data[radio_adv_data->last][0];
|
||||
pdu->type = _ll_adv_params.adv_type;
|
||||
pdu->tx_addr = _ll_adv_params.tx_addr;
|
||||
if (adv_type == PDU_ADV_TYPE_DIRECT_IND) {
|
||||
_ll_adv_params.rx_addr = direct_addr_type;
|
||||
memcpy(&_ll_adv_params.direct_addr[0], direct_addr,
|
||||
BDADDR_SIZE);
|
||||
memcpy(&pdu->payload.direct_ind.init_addr[0],
|
||||
direct_addr, BDADDR_SIZE);
|
||||
pdu->len = sizeof(struct pdu_adv_payload_direct_ind);
|
||||
} else if (pdu->len == 0) {
|
||||
pdu->len = BDADDR_SIZE;
|
||||
}
|
||||
pdu->rx_addr = _ll_adv_params.rx_addr;
|
||||
|
||||
/* update the current scan data */
|
||||
radio_adv_data = radio_scan_data_get();
|
||||
pdu = (struct pdu_adv *)&radio_adv_data->data[radio_adv_data->last][0];
|
||||
pdu->type = PDU_ADV_TYPE_SCAN_RESP;
|
||||
pdu->tx_addr = _ll_adv_params.tx_addr;
|
||||
pdu->rx_addr = 0;
|
||||
if (pdu->len == 0) {
|
||||
pdu->len = BDADDR_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void ll_adv_data_set(uint8_t len, uint8_t const *const data)
|
||||
{
|
||||
struct radio_adv_data *radio_adv_data;
|
||||
struct pdu_adv *pdu;
|
||||
uint8_t last;
|
||||
|
||||
/** @todo dont update data if directed adv type. */
|
||||
|
||||
/* use the last index in double buffer, */
|
||||
radio_adv_data = radio_adv_data_get();
|
||||
if (radio_adv_data->first == radio_adv_data->last) {
|
||||
last = radio_adv_data->last + 1;
|
||||
if (last == DOUBLE_BUFFER_SIZE) {
|
||||
last = 0;
|
||||
}
|
||||
} else {
|
||||
last = radio_adv_data->last;
|
||||
}
|
||||
|
||||
/* update adv pdu fields. */
|
||||
pdu = (struct pdu_adv *)&radio_adv_data->data[last][0];
|
||||
pdu->type = _ll_adv_params.adv_type;
|
||||
pdu->tx_addr = _ll_adv_params.tx_addr;
|
||||
pdu->rx_addr = _ll_adv_params.rx_addr;
|
||||
memcpy(&pdu->payload.adv_ind.addr[0],
|
||||
&_ll_adv_params.adv_addr[0], BDADDR_SIZE);
|
||||
if (_ll_adv_params.adv_type == PDU_ADV_TYPE_DIRECT_IND) {
|
||||
memcpy(&pdu->payload.direct_ind.init_addr[0],
|
||||
&_ll_adv_params.direct_addr[0], BDADDR_SIZE);
|
||||
pdu->len = sizeof(struct pdu_adv_payload_direct_ind);
|
||||
} else {
|
||||
memcpy(&pdu->payload.adv_ind.data[0], data, len);
|
||||
pdu->len = BDADDR_SIZE + len;
|
||||
}
|
||||
|
||||
/* commit the update so controller picks it. */
|
||||
radio_adv_data->last = last;
|
||||
}
|
||||
|
||||
void ll_scan_data_set(uint8_t len, uint8_t const *const data)
|
||||
{
|
||||
struct radio_adv_data *radio_scan_data;
|
||||
struct pdu_adv *pdu;
|
||||
uint8_t last;
|
||||
|
||||
/* use the last index in double buffer, */
|
||||
radio_scan_data = radio_scan_data_get();
|
||||
if (radio_scan_data->first == radio_scan_data->last) {
|
||||
last = radio_scan_data->last + 1;
|
||||
if (last == DOUBLE_BUFFER_SIZE) {
|
||||
last = 0;
|
||||
}
|
||||
} else {
|
||||
last = radio_scan_data->last;
|
||||
}
|
||||
|
||||
/* update scan pdu fields. */
|
||||
pdu = (struct pdu_adv *)&radio_scan_data->data[last][0];
|
||||
pdu->type = PDU_ADV_TYPE_SCAN_RESP;
|
||||
pdu->tx_addr = _ll_adv_params.tx_addr;
|
||||
pdu->rx_addr = 0;
|
||||
pdu->len = BDADDR_SIZE + len;
|
||||
memcpy(&pdu->payload.scan_resp.addr[0],
|
||||
&_ll_adv_params.adv_addr[0], BDADDR_SIZE);
|
||||
memcpy(&pdu->payload.scan_resp.data[0], data, len);
|
||||
|
||||
/* commit the update so controller picks it. */
|
||||
radio_scan_data->last = last;
|
||||
}
|
||||
|
||||
uint32_t ll_adv_enable(uint8_t enable)
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
if (enable) {
|
||||
struct radio_adv_data *radio_adv_data;
|
||||
struct radio_adv_data *radio_scan_data;
|
||||
struct pdu_adv *pdu_adv;
|
||||
struct pdu_adv *pdu_scan;
|
||||
|
||||
/** @todo move the addr remembered into controller
|
||||
* this way when implementing Privacy 1.2, generated
|
||||
* new resolvable addresses can be used instantly.
|
||||
*/
|
||||
|
||||
/* remember addr to use and also update the addr in
|
||||
* both adv and scan PDUs.
|
||||
*/
|
||||
radio_adv_data = radio_adv_data_get();
|
||||
radio_scan_data = radio_scan_data_get();
|
||||
pdu_adv = (struct pdu_adv *)&radio_adv_data->data
|
||||
[radio_adv_data->last][0];
|
||||
pdu_scan = (struct pdu_adv *)&radio_scan_data->data
|
||||
[radio_scan_data->last][0];
|
||||
if (_ll_adv_params.tx_addr) {
|
||||
memcpy(&_ll_adv_params.adv_addr[0],
|
||||
&_ll_context.rnd_addr[0], BDADDR_SIZE);
|
||||
memcpy(&pdu_adv->payload.adv_ind.addr[0],
|
||||
&_ll_context.rnd_addr[0], BDADDR_SIZE);
|
||||
memcpy(&pdu_scan->payload.scan_resp.addr[0],
|
||||
&_ll_context.rnd_addr[0], BDADDR_SIZE);
|
||||
} else {
|
||||
memcpy(&_ll_adv_params.adv_addr[0],
|
||||
&_ll_context.pub_addr[0], BDADDR_SIZE);
|
||||
memcpy(&pdu_adv->payload.adv_ind.addr[0],
|
||||
&_ll_context.pub_addr[0], BDADDR_SIZE);
|
||||
memcpy(&pdu_scan->payload.scan_resp.addr[0],
|
||||
&_ll_context.pub_addr[0], BDADDR_SIZE);
|
||||
}
|
||||
|
||||
status = radio_adv_enable(_ll_adv_params.interval,
|
||||
_ll_adv_params.chl_map,
|
||||
_ll_adv_params.filter_policy);
|
||||
} else {
|
||||
status = radio_adv_disable();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void ll_scan_params_set(uint8_t scan_type, uint16_t interval, uint16_t window,
|
||||
uint8_t own_addr_type, uint8_t filter_policy)
|
||||
{
|
||||
_ll_scan_params.scan_type = scan_type;
|
||||
_ll_scan_params.interval = interval;
|
||||
_ll_scan_params.window = window;
|
||||
_ll_scan_params.tx_addr = own_addr_type;
|
||||
_ll_scan_params.filter_policy = filter_policy;
|
||||
}
|
||||
|
||||
uint32_t ll_scan_enable(uint8_t enable)
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
if (enable) {
|
||||
status = radio_scan_enable(_ll_scan_params.scan_type,
|
||||
_ll_scan_params.tx_addr,
|
||||
(_ll_scan_params.tx_addr) ?
|
||||
&_ll_context.rnd_addr[0] :
|
||||
&_ll_context.pub_addr[0],
|
||||
_ll_scan_params.interval,
|
||||
_ll_scan_params.window,
|
||||
_ll_scan_params.filter_policy);
|
||||
} else {
|
||||
status = radio_scan_disable();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint32_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window,
|
||||
uint8_t filter_policy, uint8_t peer_addr_type,
|
||||
uint8_t *peer_addr, uint8_t own_addr_type,
|
||||
uint16_t interval, uint16_t latency,
|
||||
uint16_t timeout)
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
status = radio_connect_enable(peer_addr_type, peer_addr, interval,
|
||||
latency, timeout);
|
||||
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return radio_scan_enable(0, own_addr_type, (own_addr_type) ?
|
||||
&_ll_context.rnd_addr[0] :
|
||||
&_ll_context.pub_addr[0],
|
||||
scan_interval, scan_window, filter_policy);
|
||||
}
|
39
drivers/bluetooth/controller/ll/ll.h
Normal file
39
drivers/bluetooth/controller/ll/ll.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _LL_H_
|
||||
#define _LL_H_
|
||||
|
||||
void ll_address_get(uint8_t addr_type, uint8_t *p_bdaddr);
|
||||
void ll_address_set(uint8_t addr_type, uint8_t const *const p_bdaddr);
|
||||
void ll_adv_params_set(uint16_t interval, uint8_t adv_type,
|
||||
uint8_t own_addr_type, uint8_t direct_addr_type,
|
||||
uint8_t const *const p_direct_addr, uint8_t chl_map,
|
||||
uint8_t filter_policy);
|
||||
void ll_adv_data_set(uint8_t len, uint8_t const *const p_data);
|
||||
void ll_scan_data_set(uint8_t len, uint8_t const *const p_data);
|
||||
uint32_t ll_adv_enable(uint8_t enable);
|
||||
void ll_scan_params_set(uint8_t scan_type, uint16_t interval, uint16_t window,
|
||||
uint8_t own_addr_type, uint8_t filter_policy);
|
||||
uint32_t ll_scan_enable(uint8_t enable);
|
||||
uint32_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window,
|
||||
uint8_t filter_policy, uint8_t peer_addr_type,
|
||||
uint8_t *p_peer_addr, uint8_t own_addr_type,
|
||||
uint16_t interval, uint16_t latency,
|
||||
uint16_t timeout);
|
||||
|
||||
#endif /* _LL_H_ */
|
260
drivers/bluetooth/controller/ll/pdu.h
Normal file
260
drivers/bluetooth/controller/ll/pdu.h
Normal file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PDU_H_
|
||||
#define _PDU_H_
|
||||
|
||||
#include <toolchain.h>
|
||||
|
||||
struct __packed pdu_adv_payload_adv_ind {
|
||||
uint8_t addr[BDADDR_SIZE];
|
||||
uint8_t data[31];
|
||||
};
|
||||
|
||||
struct __packed pdu_adv_payload_direct_ind {
|
||||
uint8_t adv_addr[BDADDR_SIZE];
|
||||
uint8_t init_addr[BDADDR_SIZE];
|
||||
};
|
||||
|
||||
struct __packed pdu_adv_payload_scan_resp {
|
||||
uint8_t addr[BDADDR_SIZE];
|
||||
uint8_t data[31];
|
||||
};
|
||||
|
||||
struct __packed pdu_adv_payload_scan_req {
|
||||
uint8_t scan_addr[BDADDR_SIZE];
|
||||
uint8_t adv_addr[BDADDR_SIZE];
|
||||
};
|
||||
|
||||
struct __packed pdu_adv_payload_connect_req {
|
||||
uint8_t init_addr[BDADDR_SIZE];
|
||||
uint8_t adv_addr[BDADDR_SIZE];
|
||||
struct __packed {
|
||||
uint8_t access_addr[4];
|
||||
uint8_t crc_init[3];
|
||||
uint8_t win_size;
|
||||
uint16_t win_offset;
|
||||
uint16_t interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
uint8_t channel_map[5];
|
||||
uint8_t hop:5;
|
||||
uint8_t sca:3;
|
||||
} lldata;
|
||||
};
|
||||
|
||||
enum pdu_adv_type {
|
||||
PDU_ADV_TYPE_ADV_IND = 0x00,
|
||||
PDU_ADV_TYPE_DIRECT_IND = 0x01,
|
||||
PDU_ADV_TYPE_NONCONN_IND = 0x02,
|
||||
PDU_ADV_TYPE_SCAN_REQ = 0x03,
|
||||
PDU_ADV_TYPE_SCAN_RESP = 0x04,
|
||||
PDU_ADV_TYPE_CONNECT_REQ = 0x05,
|
||||
PDU_ADV_TYPE_SCAN_IND = 0x06,
|
||||
};
|
||||
|
||||
struct __packed pdu_adv {
|
||||
uint8_t type:4;
|
||||
uint8_t rfu0:2;
|
||||
uint8_t tx_addr:1;
|
||||
uint8_t rx_addr:1;
|
||||
uint8_t len:6;
|
||||
uint8_t rfu1:2;
|
||||
uint8_t nrf_radio_s1;
|
||||
union __packed {
|
||||
struct pdu_adv_payload_adv_ind adv_ind;
|
||||
struct pdu_adv_payload_direct_ind direct_ind;
|
||||
struct pdu_adv_payload_scan_req scan_req;
|
||||
struct pdu_adv_payload_scan_resp scan_resp;
|
||||
struct pdu_adv_payload_connect_req connect_req;
|
||||
} payload;
|
||||
};
|
||||
|
||||
enum pdu_data_llid {
|
||||
PDU_DATA_LLID_RESV = 0x00,
|
||||
PDU_DATA_LLID_DATA_CONTINUE = 0x01,
|
||||
PDU_DATA_LLID_DATA_START = 0x02,
|
||||
PDU_DATA_LLID_CTRL = 0x03,
|
||||
};
|
||||
|
||||
enum pdu_data_llctrl_type {
|
||||
PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_REQ = 0x00,
|
||||
PDU_DATA_LLCTRL_TYPE_CHANNEL_MAP_REQ = 0x01,
|
||||
PDU_DATA_LLCTRL_TYPE_TERMINATE_IND = 0x02,
|
||||
PDU_DATA_LLCTRL_TYPE_ENC_REQ = 0x03,
|
||||
PDU_DATA_LLCTRL_TYPE_ENC_RSP = 0x04,
|
||||
PDU_DATA_LLCTRL_TYPE_START_ENC_REQ = 0x05,
|
||||
PDU_DATA_LLCTRL_TYPE_START_ENC_RSP = 0x06,
|
||||
PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP = 0x07,
|
||||
PDU_DATA_LLCTRL_TYPE_FEATURE_REQ = 0x08,
|
||||
PDU_DATA_LLCTRL_TYPE_FEATURE_RSP = 0x09,
|
||||
PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ = 0x0A,
|
||||
PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_RSP = 0x0B,
|
||||
PDU_DATA_LLCTRL_TYPE_VERSION_IND = 0x0C,
|
||||
PDU_DATA_LLCTRL_TYPE_REJECT_IND = 0x0D,
|
||||
PDU_DATA_LLCTRL_TYPE_SLAVE_FEATURE_REQ = 0x0E,
|
||||
PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ = 0x0F,
|
||||
PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP = 0x10,
|
||||
PDU_DATA_LLCTRL_TYPE_REJECT_IND_EXT = 0x11,
|
||||
PDU_DATA_LLCTRL_TYPE_PING_REQ = 0x12,
|
||||
PDU_DATA_LLCTRL_TYPE_PING_RSP = 0x13,
|
||||
PDU_DATA_LLCTRL_TYPE_LENGTH_REQ = 0x14,
|
||||
PDU_DATA_LLCTRL_TYPE_LENGTH_RSP = 0x15,
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_conn_update_req {
|
||||
uint8_t win_size;
|
||||
uint16_t win_offset;
|
||||
uint16_t interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
uint16_t instant;
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_channel_map_req {
|
||||
uint8_t chm[5];
|
||||
uint16_t instant;
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_terminate_ind {
|
||||
uint8_t error_code;
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_enc_req {
|
||||
uint8_t rand[8];
|
||||
uint8_t ediv[2];
|
||||
uint8_t skdm[8];
|
||||
uint8_t ivm[4];
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_enc_rsp {
|
||||
uint8_t skds[8];
|
||||
uint8_t ivs[4];
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_unknown_rsp {
|
||||
uint8_t type;
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_feature_req {
|
||||
uint8_t features[8];
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_feature_rsp {
|
||||
uint8_t features[8];
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_version_ind {
|
||||
uint8_t version_number;
|
||||
uint16_t company_id;
|
||||
uint16_t sub_version_number;
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_reject_ind {
|
||||
uint8_t error_code;
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_conn_param_req {
|
||||
uint16_t interval_min;
|
||||
uint16_t interval_max;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
uint8_t preferred_periodicity;
|
||||
uint16_t reference_conn_event_count;
|
||||
uint16_t offset0;
|
||||
uint16_t offset1;
|
||||
uint16_t offset2;
|
||||
uint16_t offset3;
|
||||
uint16_t offset4;
|
||||
uint16_t offset5;
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_conn_param_rsp {
|
||||
uint16_t interval_min;
|
||||
uint16_t interval_max;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
uint8_t preferred_periodicity;
|
||||
uint16_t reference_conn_event_count;
|
||||
uint16_t offset0;
|
||||
uint16_t offset1;
|
||||
uint16_t offset2;
|
||||
uint16_t offset3;
|
||||
uint16_t offset4;
|
||||
uint16_t offset5;
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_reject_ind_ext {
|
||||
uint8_t reject_opcode;
|
||||
uint8_t error_code;
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl_length_req_rsp {
|
||||
uint16_t max_rx_octets;
|
||||
uint16_t max_rx_time;
|
||||
uint16_t max_tx_octets;
|
||||
uint16_t max_tx_time;
|
||||
};
|
||||
|
||||
struct __packed pdu_data_llctrl {
|
||||
uint8_t opcode;
|
||||
union __packed {
|
||||
struct pdu_data_llctrl_conn_update_req conn_update_req;
|
||||
struct pdu_data_llctrl_channel_map_req channel_map_req;
|
||||
struct pdu_data_llctrl_terminate_ind terminate_ind;
|
||||
struct pdu_data_llctrl_enc_req enc_req;
|
||||
struct pdu_data_llctrl_enc_rsp enc_rsp;
|
||||
struct pdu_data_llctrl_unknown_rsp unknown_rsp;
|
||||
struct pdu_data_llctrl_feature_req feature_req;
|
||||
struct pdu_data_llctrl_feature_rsp feature_rsp;
|
||||
struct pdu_data_llctrl_version_ind version_ind;
|
||||
struct pdu_data_llctrl_reject_ind reject_ind;
|
||||
struct pdu_data_llctrl_feature_req slave_feature_req;
|
||||
struct pdu_data_llctrl_conn_param_req conn_param_req;
|
||||
struct pdu_data_llctrl_conn_param_rsp conn_param_rsp;
|
||||
struct pdu_data_llctrl_reject_ind_ext reject_ind_ext;
|
||||
struct pdu_data_llctrl_length_req_rsp length_req;
|
||||
struct pdu_data_llctrl_length_req_rsp length_rsp;
|
||||
} ctrldata;
|
||||
};
|
||||
|
||||
struct __packed profile {
|
||||
uint32_t min;
|
||||
uint32_t avg;
|
||||
uint32_t max;
|
||||
};
|
||||
|
||||
struct __packed pdu_data {
|
||||
uint8_t ll_id:2;
|
||||
uint8_t nesn:1;
|
||||
uint8_t sn:1;
|
||||
uint8_t md:1;
|
||||
uint8_t rfu0:3;
|
||||
|
||||
uint8_t len:8;
|
||||
|
||||
uint8_t resv:8;
|
||||
|
||||
union __packed {
|
||||
uint8_t lldata[1];
|
||||
struct pdu_data_llctrl llctrl;
|
||||
uint8_t rssi;
|
||||
struct profile profile;
|
||||
} payload;
|
||||
};
|
||||
|
||||
#endif /* _PDU_H_ */
|
1537
drivers/bluetooth/controller/ll/ticker.c
Normal file
1537
drivers/bluetooth/controller/ll/ticker.c
Normal file
File diff suppressed because it is too large
Load diff
138
drivers/bluetooth/controller/ll/ticker.h
Normal file
138
drivers/bluetooth/controller/ll/ticker.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TICKER_H_
|
||||
#define _TICKER_H_
|
||||
|
||||
/** \brief Macro to translate microseconds to tick units.
|
||||
*
|
||||
* \note This returns the floor value.
|
||||
*/
|
||||
#define TICKER_US_TO_TICKS(x) \
|
||||
( \
|
||||
((uint32_t)(((uint64_t) (x) * 1000000000UL) / 30517578125UL)) \
|
||||
& 0x00FFFFFF \
|
||||
)
|
||||
|
||||
/** \brief Macro returning remainder in nanoseconds over-and-above a tick unit.
|
||||
*/
|
||||
#define TICKER_REMAINDER(x) \
|
||||
( \
|
||||
( \
|
||||
((uint64_t) (x) * 1000000000UL) \
|
||||
- ((uint64_t) TICKER_US_TO_TICKS(x) * 30517578125UL) \
|
||||
) \
|
||||
/ 1000UL \
|
||||
)
|
||||
|
||||
/** \brief Macro to translate tick units to microseconds.
|
||||
*/
|
||||
#define TICKER_TICKS_TO_US(x) \
|
||||
((uint32_t)(((uint64_t) (x) * 30517578125UL) / 1000000000UL))
|
||||
|
||||
/** \defgroup Timer API return codes.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#define TICKER_STATUS_SUCCESS 0 /**< Success. */
|
||||
#define TICKER_STATUS_FAILURE 1 /**< Failure. */
|
||||
#define TICKER_STATUS_BUSY 2 /**< Busy, requested feature will
|
||||
* complete later in time as job is
|
||||
* disabled or at lower execution
|
||||
* priority than the caller.
|
||||
*/
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** \defgroup Timer API common defaults parameter values.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#define TICKER_NULL ((uint8_t)((uint8_t)0 - 1))
|
||||
#define TICKER_NULL_REMAINDER 0
|
||||
#define TICKER_NULL_PERIOD 0
|
||||
#define TICKER_NULL_SLOT 0
|
||||
#define TICKER_NULL_LAZY 0
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** \brief Timer node type size.
|
||||
*/
|
||||
#define TICKER_NODE_T_SIZE 36
|
||||
|
||||
/** \brief Timer user type size.
|
||||
*/
|
||||
#define TICKER_USER_T_SIZE 8
|
||||
|
||||
/** \brief Timer user operation type size.
|
||||
*/
|
||||
#define TICKER_USER_OP_T_SIZE 44
|
||||
|
||||
/** \brief Timer timeout function type.
|
||||
*/
|
||||
typedef void (*ticker_timeout_func) (uint32_t ticks_at_expire,
|
||||
uint32_t remainder, uint16_t lazy,
|
||||
void *context);
|
||||
|
||||
/** \brief Timer operation complete function type.
|
||||
*/
|
||||
typedef void (*ticker_op_func) (uint32_t status, void *op_context);
|
||||
|
||||
/** \brief Timer module initialization.
|
||||
*
|
||||
* \param[in] instance_index Timer mode instance 0 or 1 (uses RTC0 CMP0 or
|
||||
* CMP1 respectively).
|
||||
* \param[in] count_node Max. no. of ticker nodes to initialise.
|
||||
* \param[in] node
|
||||
* \param[in] count_user
|
||||
* \param[in] user
|
||||
* \param[in] count_op
|
||||
* \param[in] user_op
|
||||
*/
|
||||
uint32_t ticker_init(uint8_t instance_index, uint8_t count_node, void *node,
|
||||
uint8_t count_user, void *user, uint8_t count_op,
|
||||
void *user_op);
|
||||
void ticker_trigger(uint8_t instance_index);
|
||||
uint32_t ticker_start(uint8_t instance_index, uint8_t user_id,
|
||||
uint8_t ticker_id, uint32_t ticks_anchor,
|
||||
uint32_t ticks_first, uint32_t ticks_periodic,
|
||||
uint32_t remainder_periodic, uint16_t lazy,
|
||||
uint16_t ticks_slot,
|
||||
ticker_timeout_func ticker_timeout_func, void *context,
|
||||
ticker_op_func fp_op_func, void *op_context);
|
||||
uint32_t ticker_update(uint8_t instance_index, uint8_t user_id,
|
||||
uint8_t ticker_id, uint16_t ticks_drift_plus,
|
||||
uint16_t ticks_drift_minus, uint16_t ticks_slot_plus,
|
||||
uint16_t ticks_slot_minus, uint16_t lazy, uint8_t force,
|
||||
ticker_op_func fp_op_func, void *op_context);
|
||||
uint32_t ticker_stop(uint8_t instance_index, uint8_t user_id,
|
||||
uint8_t ticker_id, ticker_op_func fp_op_func,
|
||||
void *op_context);
|
||||
uint32_t ticker_next_slot_get(uint8_t instance_index, uint8_t user_id,
|
||||
uint8_t *ticker_id_head,
|
||||
uint32_t *ticks_current,
|
||||
uint32_t *ticks_to_expire,
|
||||
ticker_op_func fp_op_func, void *op_context);
|
||||
uint32_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id,
|
||||
ticker_op_func fp_op_func, void *op_context);
|
||||
void ticker_job_sched(uint8_t instance_index);
|
||||
uint32_t ticker_ticks_now_get(void);
|
||||
uint32_t ticker_ticks_diff_get(uint32_t ticks_now, uint32_t ticks_old);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue