Add Nimble in libs directory

This commit is contained in:
JF
2020-04-26 10:25:59 +02:00
parent 032fad094c
commit bdc10744fb
633 changed files with 228083 additions and 834 deletions

View File

@@ -0,0 +1,116 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_HW_
#define H_BLE_HW_
#ifdef __cplusplus
extern "C" {
#endif
#include "syscfg/syscfg.h"
#if defined(ARCH_sim)
#define BLE_USES_HW_WHITELIST (0)
#else
#define BLE_USES_HW_WHITELIST MYNEWT_VAL(BLE_HW_WHITELIST_ENABLE)
#endif
/* Returns the number of hw whitelist elements */
uint8_t ble_hw_whitelist_size(void);
/* Clear the whitelist */
void ble_hw_whitelist_clear(void);
/* Remove a device from the hw whitelist */
void ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type);
/* Add a device to the hw whitelist */
int ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type);
/* Enable hw whitelisting */
void ble_hw_whitelist_enable(void);
/* Enable hw whitelisting */
void ble_hw_whitelist_disable(void);
/* Boolean function returning true if address matches a whitelist entry */
int ble_hw_whitelist_match(void);
/* Encrypt data */
struct ble_encryption_block;
int ble_hw_encrypt_block(struct ble_encryption_block *ecb);
/* Random number generation */
typedef void (*ble_rng_isr_cb_t)(uint8_t rnum);
int ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias);
/**
* Start the random number generator
*
* @return int
*/
int ble_hw_rng_start(void);
/**
* Stop the random generator
*
* @return int
*/
int ble_hw_rng_stop(void);
/**
* Read the random number generator.
*
* @return uint8_t
*/
uint8_t ble_hw_rng_read(void);
/* Clear the resolving list*/
void ble_hw_resolv_list_clear(void);
/* Add a device to the hw resolving list */
int ble_hw_resolv_list_add(uint8_t *irk);
/* Remove a device from the hw resolving list */
void ble_hw_resolv_list_rmv(int index);
/* Returns the size of the whitelist in HW */
uint8_t ble_hw_resolv_list_size(void);
/* Enable the resolving list */
void ble_hw_resolv_list_enable(void);
/* Disables resolving list devices */
void ble_hw_resolv_list_disable(void);
/* Returns index of resolved address; -1 if not resolved */
int ble_hw_resolv_list_match(void);
/* Returns public device address or -1 if not present */
int ble_hw_get_public_addr(ble_addr_t *addr);
/* Returns random static address or -1 if not present */
int ble_hw_get_static_addr(ble_addr_t *addr);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_HW_ */

View File

@@ -0,0 +1,587 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_
#define H_BLE_LL_
#include "stats/stats.h"
#include "os/os_cputime.h"
#include "nimble/nimble_opt.h"
#include "nimble/nimble_npl.h"
#include "controller/ble_phy.h"
#ifdef MYNEWT
#include "controller/ble_ll_ctrl.h"
#include "hal/hal_system.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
#error 32.768kHz clock required
#endif
#if defined(MYNEWT) && MYNEWT_VAL(BLE_LL_VND_EVENT_ON_ASSERT)
#ifdef NDEBUG
#define BLE_LL_ASSERT(cond) (void(0))
#else
#define BLE_LL_ASSERT(cond) \
if (!(cond)) { \
if (hal_debugger_connected()) { \
assert(0);\
} else {\
ble_ll_hci_ev_send_vendor_err(__FILE__, __LINE__); \
while(1) {}\
}\
}
#endif
#else
#define BLE_LL_ASSERT(cond) assert(cond)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
#define BLE_LL_BT5_PHY_SUPPORTED (1)
#else
#define BLE_LL_BT5_PHY_SUPPORTED (0)
#endif
/* Controller revision. */
#define BLE_LL_SUB_VERS_NR (0x0000)
/* Timing jitter as per spec is +/16 usecs */
#define BLE_LL_JITTER_USECS (16)
/* Packet queue header definition */
STAILQ_HEAD(ble_ll_pkt_q, os_mbuf_pkthdr);
/*
* Global Link Layer data object. There is only one Link Layer data object
* per controller although there may be many instances of the link layer state
* machine running.
*/
struct ble_ll_obj
{
/* Supported features */
uint64_t ll_supp_features;
/* Current Link Layer state */
uint8_t ll_state;
/* Number of ACL data packets supported */
uint8_t ll_num_acl_pkts;
/* ACL data packet size */
uint16_t ll_acl_pkt_size;
/* Preferred PHY's */
uint8_t ll_pref_tx_phys;
uint8_t ll_pref_rx_phys;
/* Task event queue */
struct ble_npl_eventq ll_evq;
/* Wait for response timer */
struct hal_timer ll_wfr_timer;
/* Packet receive queue (and event). Holds received packets from PHY */
struct ble_npl_event ll_rx_pkt_ev;
struct ble_ll_pkt_q ll_rx_pkt_q;
/* Packet transmit queue */
struct ble_npl_event ll_tx_pkt_ev;
struct ble_ll_pkt_q ll_tx_pkt_q;
/* Data buffer overflow event */
struct ble_npl_event ll_dbuf_overflow_ev;
/* Number of completed packets event */
struct ble_npl_event ll_comp_pkt_ev;
/* HW error callout */
struct ble_npl_callout ll_hw_err_timer;
};
extern struct ble_ll_obj g_ble_ll_data;
/* Link layer statistics */
STATS_SECT_START(ble_ll_stats)
STATS_SECT_ENTRY(hci_cmds)
STATS_SECT_ENTRY(hci_cmd_errs)
STATS_SECT_ENTRY(hci_events_sent)
STATS_SECT_ENTRY(bad_ll_state)
STATS_SECT_ENTRY(bad_acl_hdr)
STATS_SECT_ENTRY(no_bufs)
STATS_SECT_ENTRY(rx_adv_pdu_crc_ok)
STATS_SECT_ENTRY(rx_adv_pdu_crc_err)
STATS_SECT_ENTRY(rx_adv_bytes_crc_ok)
STATS_SECT_ENTRY(rx_adv_bytes_crc_err)
STATS_SECT_ENTRY(rx_data_pdu_crc_ok)
STATS_SECT_ENTRY(rx_data_pdu_crc_err)
STATS_SECT_ENTRY(rx_data_bytes_crc_ok)
STATS_SECT_ENTRY(rx_data_bytes_crc_err)
STATS_SECT_ENTRY(rx_adv_malformed_pkts)
STATS_SECT_ENTRY(rx_adv_ind)
STATS_SECT_ENTRY(rx_adv_direct_ind)
STATS_SECT_ENTRY(rx_adv_nonconn_ind)
STATS_SECT_ENTRY(rx_adv_ext_ind)
STATS_SECT_ENTRY(rx_scan_reqs)
STATS_SECT_ENTRY(rx_scan_rsps)
STATS_SECT_ENTRY(rx_connect_reqs)
STATS_SECT_ENTRY(rx_scan_ind)
STATS_SECT_ENTRY(rx_aux_connect_rsp)
STATS_SECT_ENTRY(adv_txg)
STATS_SECT_ENTRY(adv_late_starts)
STATS_SECT_ENTRY(adv_resched_pdu_fail)
STATS_SECT_ENTRY(adv_drop_event)
STATS_SECT_ENTRY(sched_state_conn_errs)
STATS_SECT_ENTRY(sched_state_adv_errs)
STATS_SECT_ENTRY(scan_starts)
STATS_SECT_ENTRY(scan_stops)
STATS_SECT_ENTRY(scan_req_txf)
STATS_SECT_ENTRY(scan_req_txg)
STATS_SECT_ENTRY(scan_rsp_txg)
STATS_SECT_ENTRY(aux_missed_adv)
STATS_SECT_ENTRY(aux_scheduled)
STATS_SECT_ENTRY(aux_received)
STATS_SECT_ENTRY(aux_fired_for_read)
STATS_SECT_ENTRY(aux_allocated)
STATS_SECT_ENTRY(aux_freed)
STATS_SECT_ENTRY(aux_sched_cb)
STATS_SECT_ENTRY(aux_conn_req_tx)
STATS_SECT_ENTRY(aux_conn_rsp_tx)
STATS_SECT_ENTRY(aux_conn_rsp_err)
STATS_SECT_ENTRY(aux_scan_req_tx)
STATS_SECT_ENTRY(aux_scan_rsp_err)
STATS_SECT_ENTRY(aux_chain_cnt)
STATS_SECT_ENTRY(aux_chain_err)
STATS_SECT_ENTRY(aux_scan_drop)
STATS_SECT_ENTRY(adv_evt_dropped)
STATS_SECT_ENTRY(scan_timer_stopped)
STATS_SECT_ENTRY(scan_timer_restarted)
STATS_SECT_ENTRY(periodic_adv_drop_event)
STATS_SECT_ENTRY(periodic_chain_drop_event)
STATS_SECT_ENTRY(sync_event_failed)
STATS_SECT_ENTRY(sync_received)
STATS_SECT_ENTRY(sync_chain_failed)
STATS_SECT_ENTRY(sync_missed_err)
STATS_SECT_ENTRY(sync_crc_err)
STATS_SECT_ENTRY(sync_rx_buf_err)
STATS_SECT_ENTRY(sync_scheduled)
STATS_SECT_ENTRY(sched_state_sync_errs)
STATS_SECT_ENTRY(sched_invalid_pdu)
STATS_SECT_END
extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats;
/* States */
#define BLE_LL_STATE_STANDBY (0)
#define BLE_LL_STATE_ADV (1)
#define BLE_LL_STATE_SCANNING (2)
#define BLE_LL_STATE_INITIATING (3)
#define BLE_LL_STATE_CONNECTION (4)
#define BLE_LL_STATE_DTM (5)
#define BLE_LL_STATE_SYNC (6)
/* LL Features */
#define BLE_LL_FEAT_LE_ENCRYPTION (0x0000000001)
#define BLE_LL_FEAT_CONN_PARM_REQ (0x0000000002)
#define BLE_LL_FEAT_EXTENDED_REJ (0x0000000004)
#define BLE_LL_FEAT_SLAVE_INIT (0x0000000008)
#define BLE_LL_FEAT_LE_PING (0x0000000010)
#define BLE_LL_FEAT_DATA_LEN_EXT (0x0000000020)
#define BLE_LL_FEAT_LL_PRIVACY (0x0000000040)
#define BLE_LL_FEAT_EXT_SCAN_FILT (0x0000000080)
#define BLE_LL_FEAT_LE_2M_PHY (0x0000000100)
#define BLE_LL_FEAT_STABLE_MOD_ID_TX (0x0000000200)
#define BLE_LL_FEAT_STABLE_MOD_ID_RX (0x0000000400)
#define BLE_LL_FEAT_LE_CODED_PHY (0x0000000800)
#define BLE_LL_FEAT_EXT_ADV (0x0000001000)
#define BLE_LL_FEAT_PERIODIC_ADV (0x0000002000)
#define BLE_LL_FEAT_CSA2 (0x0000004000)
#define BLE_LL_FEAT_LE_POWER_CLASS_1 (0x0000008000)
#define BLE_LL_FEAT_MIN_USED_CHAN (0x0000010000)
#define BLE_LL_FEAT_CTE_REQ (0x0000020000)
#define BLE_LL_FEAT_CTE_RSP (0x0000040000)
#define BLE_LL_FEAT_CTE_TX (0x0000080000)
#define BLE_LL_FEAT_CTE_RX (0x0000100000)
#define BLE_LL_FEAT_CTE_AOD (0x0000200000)
#define BLE_LL_FEAT_CTE_AOA (0x0000400000)
#define BLE_LL_FEAT_CTE_RECV (0x0000800000)
#define BLE_LL_FEAT_SYNC_TRANS_SEND (0x0001000000)
#define BLE_LL_FEAT_SYNC_TRANS_RECV (0x0002000000)
#define BLE_LL_FEAT_SCA_UPDATE (0x0004000000)
#define BLE_LL_FEAT_REM_PKEY (0x0008000000)
#define BLE_LL_FEAT_CIS_MASTER (0x0010000000)
#define BLE_LL_FEAT_CIS_SLAVE (0x0020000000)
#define BLE_LL_FEAT_ISO_BROADCASTER (0x0040000000)
#define BLE_LL_FEAT_SYNC_RECV (0x0080000000)
#define BLE_LL_FEAT_ISO_HOST_SUPPORT (0x0100000000)
#define BLE_LL_FEAT_POWER_CTRL_REQ (0x0200000000)
#define BLE_LL_FEAT_POWER_CHANGE_IND (0x0400000000)
#define BLE_LL_FEAT_PATH_LOSS_MON (0x0800000000)
/* This is initial mask, so if feature exchange will not happen,
* but host will want to use this procedure, we will try. If not
* succeed, feature bit will be cleared.
* Look at LL Features above to find out what is allowed
*/
#define BLE_LL_CONN_INITIAL_FEATURES (0x00000022)
#define BLE_LL_CONN_CLEAR_FEATURE(connsm, feature) (connsm->conn_features &= ~(feature))
/* All the features which can be controlled by the Host */
#define BLE_LL_HOST_CONTROLLED_FEATURES (BLE_LL_FEAT_ISO_HOST_SUPPORT)
/* LL timing */
#define BLE_LL_IFS (150) /* usecs */
#define BLE_LL_MAFS (300) /* usecs */
/*
* BLE LL device address. Note that element 0 of the array is the LSB and
* is sent over the air first. Byte 5 is the MSB and is the last one sent over
* the air.
*/
#define BLE_DEV_ADDR_LEN (6) /* bytes */
struct ble_dev_addr
{
uint8_t u8[BLE_DEV_ADDR_LEN];
};
#define BLE_IS_DEV_ADDR_STATIC(addr) ((addr->u8[5] & 0xc0) == 0xc0)
#define BLE_IS_DEV_ADDR_RESOLVABLE(addr) ((addr->u8[5] & 0xc0) == 0x40)
#define BLE_IS_DEV_ADDR_UNRESOLVABLE(addr) ((addr->u8[5] & 0xc0) == 0x00)
/*
* LL packet format
*
* -> Preamble (1/2 bytes)
* -> Access Address (4 bytes)
* -> PDU (2 to 257 octets)
* -> CRC (3 bytes)
*/
#define BLE_LL_PREAMBLE_LEN (1)
#define BLE_LL_ACC_ADDR_LEN (4)
#define BLE_LL_CRC_LEN (3)
#define BLE_LL_PDU_HDR_LEN (2)
#define BLE_LL_MAX_PAYLOAD_LEN (255)
#define BLE_LL_MIN_PDU_LEN (BLE_LL_PDU_HDR_LEN)
#define BLE_LL_MAX_PDU_LEN ((BLE_LL_PDU_HDR_LEN) + (BLE_LL_MAX_PAYLOAD_LEN))
#define BLE_LL_CRCINIT_ADV (0x555555)
/* Access address for advertising channels */
#define BLE_ACCESS_ADDR_ADV (0x8E89BED6)
/*
* Advertising PDU format:
* -> 2 byte header
* -> LSB contains pdu type, txadd and rxadd bits.
* -> MSB contains length (6 bits). Length is length of payload. Does
* not include the header length itself.
* -> Payload (max 37 bytes)
*/
#define BLE_ADV_PDU_HDR_TYPE_MASK (0x0F)
#define BLE_ADV_PDU_HDR_CHSEL_MASK (0x20)
#define BLE_ADV_PDU_HDR_TXADD_MASK (0x40)
#define BLE_ADV_PDU_HDR_RXADD_MASK (0x80)
/* Advertising channel PDU types */
#define BLE_ADV_PDU_TYPE_ADV_IND (0)
#define BLE_ADV_PDU_TYPE_ADV_DIRECT_IND (1)
#define BLE_ADV_PDU_TYPE_ADV_NONCONN_IND (2)
#define BLE_ADV_PDU_TYPE_SCAN_REQ (3)
#define BLE_ADV_PDU_TYPE_SCAN_RSP (4)
#define BLE_ADV_PDU_TYPE_CONNECT_IND (5)
#define BLE_ADV_PDU_TYPE_ADV_SCAN_IND (6)
#define BLE_ADV_PDU_TYPE_ADV_EXT_IND (7)
#define BLE_ADV_PDU_TYPE_AUX_ADV_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND
#define BLE_ADV_PDU_TYPE_AUX_SCAN_RSP BLE_ADV_PDU_TYPE_ADV_EXT_IND
#define BLE_ADV_PDU_TYPE_AUX_SYNC_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND
#define BLE_ADV_PDU_TYPE_AUX_CHAIN_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND
#define BLE_ADV_PDU_TYPE_AUX_CONNECT_REQ BLE_ADV_PDU_TYPE_CONNECT_IND
#define BLE_ADV_PDU_TYPE_AUX_SCAN_REQ BLE_ADV_PDU_TYPE_SCAN_REQ
#define BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP (8)
/* Extended Header Length (6b) + AdvMode (2b) */
#define BLE_LL_EXT_ADV_HDR_LEN (1)
#define BLE_LL_EXT_ADV_ADVA_BIT (0)
#define BLE_LL_EXT_ADV_TARGETA_BIT (1)
#define BLE_LL_EXT_ADV_CTE_INFO_BIT (2)
#define BLE_LL_EXT_ADV_DATA_INFO_BIT (3)
#define BLE_LL_EXT_ADV_AUX_PTR_BIT (4)
#define BLE_LL_EXT_ADV_SYNC_INFO_BIT (5)
#define BLE_LL_EXT_ADV_TX_POWER_BIT (6)
#define BLE_LL_EXT_ADV_FLAGS_SIZE (1)
#define BLE_LL_EXT_ADV_ADVA_SIZE (6)
#define BLE_LL_EXT_ADV_TARGETA_SIZE (6)
#define BLE_LL_EXT_ADV_DATA_INFO_SIZE (2)
#define BLE_LL_EXT_ADV_AUX_PTR_SIZE (3)
#define BLE_LL_EXT_ADV_SYNC_INFO_SIZE (18)
#define BLE_LL_EXT_ADV_TX_POWER_SIZE (1)
#define BLE_LL_EXT_ADV_MODE_NON_CONN (0x00)
#define BLE_LL_EXT_ADV_MODE_CONN (0x01)
#define BLE_LL_EXT_ADV_MODE_SCAN (0x02)
/* If Channel Selection Algorithm #2 is supported */
#define BLE_ADV_PDU_HDR_CHSEL (0x20)
/*
* TxAdd and RxAdd bit definitions. A 0 is a public address; a 1 is a
* random address.
*/
#define BLE_ADV_PDU_HDR_TXADD_RAND (0x40)
#define BLE_ADV_PDU_HDR_RXADD_RAND (0x80)
/*
* Data Channel format
*
* -> Header (2 bytes)
* -> LSB contains llid, nesn, sn and md
* -> MSB contains length (8 bits)
* -> Payload (0 to 251)
* -> MIC (0 or 4 bytes)
*/
#define BLE_LL_DATA_HDR_LLID_MASK (0x03)
#define BLE_LL_DATA_HDR_NESN_MASK (0x04)
#define BLE_LL_DATA_HDR_SN_MASK (0x08)
#define BLE_LL_DATA_HDR_MD_MASK (0x10)
#define BLE_LL_DATA_HDR_RSRVD_MASK (0xE0)
#define BLE_LL_DATA_PDU_MAX_PYLD (251)
#define BLE_LL_DATA_MIC_LEN (4)
/* LLID definitions */
#define BLE_LL_LLID_RSRVD (0)
#define BLE_LL_LLID_DATA_FRAG (1)
#define BLE_LL_LLID_DATA_START (2)
#define BLE_LL_LLID_CTRL (3)
/*
* CONNECT_REQ
* -> InitA (6 bytes)
* -> AdvA (6 bytes)
* -> LLData (22 bytes)
* -> Access address (4 bytes)
* -> CRC init (3 bytes)
* -> WinSize (1 byte)
* -> WinOffset (2 bytes)
* -> Interval (2 bytes)
* -> Latency (2 bytes)
* -> Timeout (2 bytes)
* -> Channel Map (5 bytes)
* -> Hop Increment (5 bits)
* -> SCA (3 bits)
*
* InitA is the initiators public (TxAdd=0) or random (TxAdd=1) address.
* AdvaA is the advertisers public (RxAdd=0) or random (RxAdd=1) address.
* LLData contains connection request data.
* aa: Link Layer's access address
* crc_init: The CRC initialization value used for CRC calculation.
* winsize: The transmit window size = winsize * 1.25 msecs
* winoffset: The transmit window offset = winoffset * 1.25 msecs
* interval: The connection interval = interval * 1.25 msecs.
* latency: connection slave latency = latency
* timeout: Connection supervision timeout = timeout * 10 msecs.
* chanmap: contains channel mapping indicating used and unused data
* channels. Only bits that are 1 are usable. LSB is channel 0.
* hop_inc: Hop increment used for frequency hopping. Random value in
* range of 5 to 16.
*/
#define BLE_CONNECT_REQ_LEN (34)
#define BLE_CONNECT_REQ_PDU_LEN (BLE_CONNECT_REQ_LEN + BLE_LL_PDU_HDR_LEN)
#define BLE_SCAN_REQ_LEN (12)
#define BLE_SCAN_RSP_MAX_LEN (37)
#define BLE_SCAN_RSP_MAX_EXT_LEN (251)
#define BLE_LL_ADDR_SUBTYPE_IDENTITY (0)
#define BLE_LL_ADDR_SUBTYPE_RPA (1)
#define BLE_LL_ADDR_SUBTYPE_NRPA (2)
/*--- External API ---*/
/* Initialize the Link Layer */
void ble_ll_init(void);
/* Reset the Link Layer */
int ble_ll_reset(void);
int ble_ll_is_valid_public_addr(const uint8_t *addr);
/* 'Boolean' function returning true if address is a valid random address */
int ble_ll_is_valid_random_addr(const uint8_t *addr);
/*
* Check if given own_addr_type is valid for current controller configuration
* given the random address provided (when applicable)
*/
int ble_ll_is_valid_own_addr_type(uint8_t own_addr_type,
const uint8_t *random_addr);
/* Calculate the amount of time in microseconds a PDU with payload length of
* 'payload_len' will take to transmit on a PHY 'phy_mode'. */
uint32_t ble_ll_pdu_tx_time_get(uint16_t payload_len, int phy_mode);
/* Calculate maximum octets of PDU payload which can be transmitted during
* 'usecs' on a PHY 'phy_mode'. */
uint16_t ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode);
/* Is this address a resolvable private address? */
int ble_ll_is_rpa(const uint8_t *addr, uint8_t addr_type);
int ble_ll_addr_subtype(const uint8_t *addr, uint8_t addr_type);
/* Is this address an identity address? */
int ble_ll_addr_is_id(uint8_t *addr, uint8_t addr_type);
/* Is 'addr' our device address? 'addr_type' is public (0) or random (!=0) */
int ble_ll_is_our_devaddr(uint8_t *addr, int addr_type);
/* Get identity address 'addr_type' is public (0) or random (!=0) */
uint8_t *ble_ll_get_our_devaddr(uint8_t addr_type);
/**
* Called to put a packet on the Link Layer transmit packet queue.
*
* @param txpdu Pointer to transmit packet
*/
void ble_ll_acl_data_in(struct os_mbuf *txpkt);
/**
* Allocates mbuf for received PDU
*
* This allocated mbuf (may be chained if necessary) that has capacity large
* enough to store received PDU of given length. It does not set mbufs length
* as this has to be done by PHY when copying data.
*
* @param len Length of PDU, including PDU header and excluding MIC (if encrypted)
*
* @return mbuf large enough to store received PDU on success
* NULL on failure (oom)
*/
struct os_mbuf *ble_ll_rxpdu_alloc(uint16_t len);
/* Tell the Link Layer there has been a data buffer overflow */
void ble_ll_data_buffer_overflow(void);
/* Tell the link layer there has been a hardware error */
void ble_ll_hw_error(void);
/*--- PHY interfaces ---*/
struct ble_mbuf_hdr;
/* Called by the PHY when a packet has started */
int ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *hdr);
/* Called by the PHY when a packet reception ends */
int ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr);
/* Helper callback to tx mbuf using ble_phy_tx() */
uint8_t ble_ll_tx_mbuf_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte);
uint8_t ble_ll_tx_flat_mbuf_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte);
/*--- Controller API ---*/
void ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr);
/* Set the link layer state */
void ble_ll_state_set(uint8_t ll_state);
/* Get the link layer state */
uint8_t ble_ll_state_get(void);
/* Send an event to LL task */
void ble_ll_event_send(struct ble_npl_event *ev);
/* Hand received pdu's to LL task */
void ble_ll_rx_pdu_in(struct os_mbuf *rxpdu);
/*
* Set public address
*
* This can be used to set controller public address from vendor specific storage,
* usually should be done in hal_bsp_init().
* Shall be *only* called before LL is initialized, i.e. before sysinit stage.
*/
int ble_ll_set_public_addr(const uint8_t *addr);
/* Set random address */
int ble_ll_set_random_addr(const uint8_t *cmdbuf, uint8_t len, bool hci_adv_ext);
/* Wait for response timer expiration callback */
void ble_ll_wfr_timer_exp(void *arg);
/* Read set of features supported by the Link Layer */
uint64_t ble_ll_read_supp_features(void);
/* Set host supported features */
int ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len);
/* Read set of states supported by the Link Layer */
uint64_t ble_ll_read_supp_states(void);
/* Check if octets and time are valid. Returns 0 if not valid */
int ble_ll_chk_txrx_octets(uint16_t octets);
int ble_ll_chk_txrx_time(uint16_t time);
/* Random numbers */
int ble_ll_rand_init(void);
void ble_ll_rand_sample(uint8_t rnum);
int ble_ll_rand_data_get(uint8_t *buf, uint8_t len);
void ble_ll_rand_prand_get(uint8_t *prand);
int ble_ll_rand_start(void);
// TODO added by JF, don't know why I need this?
void ble_ll_task(void *arg);
static inline int
ble_ll_get_addr_type(uint8_t txrxflag)
{
if (txrxflag) {
return BLE_HCI_ADV_OWN_ADDR_RANDOM;
}
return BLE_HCI_ADV_OWN_ADDR_PUBLIC;
}
/* Convert usecs to ticks and round up to nearest tick */
static inline uint32_t
ble_ll_usecs_to_ticks_round_up(uint32_t usecs)
{
return os_cputime_usecs_to_ticks(usecs + 30);
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
/* LTK 0x4C68384139F574D836BCF34E9DFB01BF */
extern const uint8_t g_bletest_LTK[];
extern uint16_t g_bletest_EDIV;
extern uint64_t g_bletest_RAND;
extern uint64_t g_bletest_SKDm;
extern uint64_t g_bletest_SKDs;
extern uint32_t g_bletest_IVm;
extern uint32_t g_bletest_IVs;
#endif
#if MYNEWT_VAL(BLE_LL_DTM)
void ble_ll_dtm_init(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_LL_ */

View File

@@ -0,0 +1,209 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_ADV_
#define H_BLE_LL_ADV_
#include "syscfg/syscfg.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* ADV event timing
* T_advEvent = advInterval + advDelay
*
* advInterval: increments of 625 usecs
* advDelay: RAND[0, 10] msecs
*
*/
#define BLE_LL_ADV_ITVL (625) /* usecs */
#define BLE_LL_ADV_ITVL_MIN (32) /* units */
#define BLE_LL_ADV_ITVL_MAX (16384) /* units */
#define BLE_LL_ADV_ITVL_MS_MIN (20) /* msecs */
#define BLE_LL_ADV_ITVL_MS_MAX (10240) /* msecs */
#define BLE_LL_ADV_ITVL_SCAN_MIN (160) /* units */
#define BLE_LL_ADV_ITVL_SCAN_MS_MIN (100) /* msecs */
#define BLE_LL_ADV_ITVL_NONCONN_MS_MIN (100) /* msecs */
#define BLE_LL_ADV_DELAY_MS_MIN (0) /* msecs */
#define BLE_LL_ADV_DELAY_MS_MAX (10) /* msecs */
#define BLE_LL_ADV_PDU_ITVL_LD_MS_MAX (10) /* msecs */
#define BLE_LL_ADV_PDU_ITVL_HD_MS_MAX (3750) /* usecs */
#define BLE_LL_ADV_STATE_HD_MAX (1280) /* msecs */
#define BLE_LL_ADV_PERIODIC_ITVL (1250) /* usecs */
/* Maximum advertisement data length */
#define BLE_ADV_LEGACY_DATA_MAX_LEN (31)
#define BLE_ADV_LEGACY_MAX_PKT_LEN (37)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
#define BLE_ADV_DATA_MAX_LEN MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)
#else
#define BLE_ADV_DATA_MAX_LEN BLE_ADV_LEGACY_DATA_MAX_LEN
#endif
/*
* ADV_IND
* -> AdvA (6 bytes)
* -> AdvData (0 - 31 bytes)
*
* The advertising address (AdvA) is a public address (TxAdd=0) or random
* address (TxAdd = 1)
*/
#define BLE_ADV_IND_MIN_LEN (6)
#define BLE_ADV_IND_MAX_LEN (37)
/*
* ADV_DIRECT_IND
* -> AdvA (6 bytes)
* -> InitA (6 bytes)
*
* AdvA is the advertisers public address (TxAdd=0) or random address
* (TxAdd = 1).
*
* InitA is the initiators public or random address. This is the address
* to which this packet is addressed.
*
*/
#define BLE_ADV_DIRECT_IND_LEN (12)
/*
* ADV_NONCONN_IND
* -> AdvA (6 bytes)
* -> AdvData (0 - 31 bytes)
*
* The advertising address (AdvA) is a public address (TxAdd=0) or random
* address (TxAdd = 1)
*
*/
#define BLE_ADV_NONCONN_IND_MIN_LEN (6)
#define BLE_ADV_NONCONN_IND_MAX_LEN (37)
/*
* ADV_SCAN_IND
* -> AdvA (6 bytes)
* -> AdvData (0 - 31 bytes)
*
* The advertising address (AdvA) is a public address (TxAdd=0) or random
* address (TxAdd = 1)
*
*/
#define BLE_ADV_SCAN_IND_MIN_LEN (6)
#define BLE_ADV_SCAN_IND_MAX_LEN (37)
/*---- HCI ----*/
struct ble_ll_adv_sm;
struct ble_ll_conn_sm;
/* Start an advertiser */
int ble_ll_adv_start_req(uint8_t adv_chanmask, uint8_t adv_type,
uint8_t *init_addr, uint16_t adv_itvl, void *handle);
/* Start or stop advertising */
int ble_ll_hci_adv_set_enable(const uint8_t *cmdbuf, uint8_t len);
/* Set legacy advertising data */
int ble_ll_hci_set_adv_data(const uint8_t *cmdbuf, uint8_t len);
/* Set scan response data */
int ble_ll_hci_set_scan_rsp_data(const uint8_t *cmd, uint8_t cmd_len);
/* Set advertising parameters */
int ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len);
/* Read advertising channel power */
int ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen);
/*---- API used by BLE LL ----*/
/* Send the connection complete event */
void ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm,
struct ble_mbuf_hdr *rxhdr);
/* Returns local resolvable private address */
uint8_t *ble_ll_adv_get_local_rpa(struct ble_ll_adv_sm *advsm);
/* Returns peer resolvable private address */
uint8_t *ble_ll_adv_get_peer_rpa(struct ble_ll_adv_sm *advsm);
/* Called to initialize advertising functionality. */
void ble_ll_adv_init(void);
/* Called when LL wait for response timer expires in advertising state */
void ble_ll_adv_wfr_timer_exp(void);
/* Called to reset the advertiser. */
void ble_ll_adv_reset(void);
/* Called on rx pdu start when in advertising state */
int ble_ll_adv_rx_isr_start(uint8_t pdu_type);
/* Called on rx pdu end when in advertising state */
int ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok);
/* Processes received packets at the link layer task */
void ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf,
struct ble_mbuf_hdr *hdr);
/* Boolean function denoting whether or not the whitelist can be changed */
int ble_ll_adv_can_chg_whitelist(void);
/*
* Called when an advertising event has been removed from the scheduler
* without being run.
*/
void ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm);
/*
* Called when a periodic event has been removed from the scheduler
* without being run.
*/
void ble_ll_adv_periodic_rmvd_from_sched(struct ble_ll_adv_sm *advsm);
/* Called to halt currently running advertising event */
void ble_ll_adv_halt(void);
/* Called to determine if advertising is enabled */
uint8_t ble_ll_adv_enabled(void);
int ble_ll_adv_hci_set_random_addr(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_adv_set_random_addr(const uint8_t *addr, uint8_t instance);
int ble_ll_adv_remove(const uint8_t *addr, uint8_t len);
int ble_ll_adv_clear_all(void);
int ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_adv_ext_set_adv_data(const uint8_t *cmdbuf, uint8_t cmdlen);
int ble_ll_adv_ext_set_scan_rsp(const uint8_t *cmdbuf, uint8_t cmdlen);
int ble_ll_adv_ext_set_enable(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_adv_periodic_set_param(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
/* Called to notify adv code about RPA rotation */
void ble_ll_adv_rpa_timeout(void);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_ADV_ */

View File

@@ -0,0 +1,425 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_CONN_
#define H_BLE_LL_CONN_
#include "os/os.h"
#include "nimble/ble.h"
#include "nimble/hci_common.h"
#include "nimble/nimble_npl.h"
#include "controller/ble_ll_sched.h"
#include "controller/ble_ll_ctrl.h"
#include "controller/ble_phy.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Roles */
#define BLE_LL_CONN_ROLE_NONE (0)
#define BLE_LL_CONN_ROLE_MASTER (1)
#define BLE_LL_CONN_ROLE_SLAVE (2)
/* Connection states */
#define BLE_LL_CONN_STATE_IDLE (0)
#define BLE_LL_CONN_STATE_CREATED (1)
#define BLE_LL_CONN_STATE_ESTABLISHED (2)
/* Channel map size */
#define BLE_LL_CONN_CHMAP_LEN (5)
/* Definitions for source clock accuracy */
#define BLE_MASTER_SCA_251_500_PPM (0)
#define BLE_MASTER_SCA_151_250_PPM (1)
#define BLE_MASTER_SCA_101_150_PPM (2)
#define BLE_MASTER_SCA_76_100_PPM (3)
#define BLE_MASTER_SCA_51_75_PPM (4)
#define BLE_MASTER_SCA_31_50_PPM (5)
#define BLE_MASTER_SCA_21_30_PPM (6)
#define BLE_MASTER_SCA_0_20_PPM (7)
/* Definition for RSSI when the RSSI is unknown */
#define BLE_LL_CONN_UNKNOWN_RSSI (127)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
/*
* Encryption states for a connection
*
* NOTE: the states are ordered so that we can check to see if the state
* is greater than ENCRYPTED. If so, it means that the start or pause
* encryption procedure is running and we should not send data pdu's.
*/
enum conn_enc_state {
CONN_ENC_S_UNENCRYPTED = 1,
CONN_ENC_S_ENCRYPTED,
CONN_ENC_S_ENC_RSP_WAIT,
CONN_ENC_S_PAUSE_ENC_RSP_WAIT,
CONN_ENC_S_PAUSED,
CONN_ENC_S_START_ENC_REQ_WAIT,
CONN_ENC_S_START_ENC_RSP_WAIT,
CONN_ENC_S_LTK_REQ_WAIT,
CONN_ENC_S_LTK_NEG_REPLY
};
/*
* Note that the LTK is the key, the SDK is the plain text, and the
* session key is the cipher text portion of the encryption block.
*
* NOTE: we have intentionally violated the specification by making the
* transmit and receive packet counters 32-bits as opposed to 39 (as per the
* specification). We do this to save code space, ram and calculation time. The
* only drawback is that any encrypted connection that sends more than 2^32
* packets will suffer a MIC failure and thus be disconnected.
*/
struct ble_ll_conn_enc_data
{
uint8_t enc_state;
uint8_t tx_encrypted;
uint16_t enc_div;
uint32_t tx_pkt_cntr;
uint32_t rx_pkt_cntr;
uint64_t host_rand_num;
uint8_t iv[8];
struct ble_encryption_block enc_block;
};
#endif
/* Connection state machine flags. */
union ble_ll_conn_sm_flags {
struct {
uint32_t pkt_rxd:1;
uint32_t terminate_ind_txd:1;
uint32_t terminate_ind_rxd:1;
uint32_t terminate_ind_rxd_acked:1;
uint32_t allow_slave_latency:1;
uint32_t slave_set_last_anchor:1;
uint32_t awaiting_host_reply:1;
uint32_t terminate_started:1;
uint32_t conn_update_sched:1;
uint32_t host_expects_upd_event:1;
uint32_t version_ind_sent:1;
uint32_t rxd_version_ind:1;
uint32_t chanmap_update_scheduled:1;
uint32_t conn_empty_pdu_txd:1;
uint32_t last_txd_md:1;
uint32_t conn_req_txd:1;
uint32_t send_ltk_req:1;
uint32_t encrypted:1;
uint32_t encrypt_chg_sent:1;
uint32_t le_ping_supp:1;
uint32_t csa2_supp:1;
uint32_t host_phy_update: 1;
uint32_t phy_update_sched: 1;
uint32_t ctrlr_phy_update: 1;
uint32_t phy_update_event: 1;
uint32_t peer_phy_update: 1; /* XXX:combine with ctrlr udpate bit? */
uint32_t aux_conn_req: 1;
uint32_t rxd_features:1;
uint32_t pending_hci_rd_features:1;
uint32_t pending_initiate_dle:1;
} cfbit;
uint32_t conn_flags;
} __attribute__((packed));
/**
* Structure used for PHY data inside a connection.
*
* NOTE: the new phy's are the phys we will change to when a phy update
* procedure is ongoing and the event counter hits the instant.
*
* tx_phy_mode: chip specific phy mode for tx
* rx_phy_mode: chip specific phy mode for rx
* cur_tx_phy: value denoting current tx_phy (not a bitmask!)
* cur_rx_phy: value denoting current rx phy (not a bitmask!)
* new_tx_phy: value denoting new tx_phy (not a bitmask!)
* new_rx_phy: value denoting new rx phy (not a bitmask!)
* req_pref_tx_phy: tx phy sent in a phy request (may be different than host)
* req_pref_rx_phy: rx phy sent in a phy request (may be different than host)
* host_pref_tx_phys: bitmask of preferred transmit PHYs sent by host
* host_pref_rx_phys: bitmask of preferred receive PHYs sent by host
* phy_options: preferred phy options for coded phy
*/
struct ble_ll_conn_phy_data
{
uint32_t tx_phy_mode: 2;
uint32_t rx_phy_mode: 2;
uint32_t cur_tx_phy: 2;
uint32_t cur_rx_phy: 2;
uint32_t new_tx_phy: 2;
uint32_t new_rx_phy: 2;
uint32_t host_pref_tx_phys_mask: 3;
uint32_t host_pref_rx_phys_mask: 3;
uint32_t req_pref_tx_phys_mask: 3;
uint32_t req_pref_rx_phys_mask: 3;
uint32_t phy_options: 2;
} __attribute__((packed));
#define CONN_CUR_TX_PHY_MASK(csm) (1 << ((csm)->phy_data.cur_tx_phy - 1))
#define CONN_CUR_RX_PHY_MASK(csm) (1 << ((csm)->phy_data.cur_rx_phy - 1))
struct hci_conn_update
{
uint16_t handle;
uint16_t conn_itvl_min;
uint16_t conn_itvl_max;
uint16_t conn_latency;
uint16_t supervision_timeout;
uint16_t min_ce_len;
uint16_t max_ce_len;
};
struct hci_ext_conn_params
{
uint16_t scan_itvl;
uint16_t scan_window;
uint16_t conn_itvl_min;
uint16_t conn_itvl_max;
uint16_t conn_latency;
uint16_t supervision_timeout;
uint16_t min_ce_len;
uint16_t max_ce_len;
};
struct hci_ext_create_conn
{
uint8_t filter_policy;
uint8_t own_addr_type;
uint8_t peer_addr_type;
uint8_t peer_addr[BLE_DEV_ADDR_LEN];
uint8_t init_phy_mask;
struct hci_ext_conn_params params[3];
};
/* Connection state machine */
struct ble_ll_conn_sm
{
/* Connection state machine flags */
union ble_ll_conn_sm_flags csmflags;
/* Current connection handle, state and role */
uint16_t conn_handle;
uint8_t conn_state;
uint8_t conn_role; /* Can possibly be 1 bit */
/* RSSI */
int8_t conn_rssi;
/* For privacy */
int8_t rpa_index;
/* Connection data length management */
uint8_t max_tx_octets;
uint8_t max_rx_octets;
uint8_t rem_max_tx_octets;
uint8_t rem_max_rx_octets;
uint8_t eff_max_tx_octets;
uint8_t eff_max_rx_octets;
uint16_t max_tx_time;
uint16_t max_rx_time;
uint16_t rem_max_tx_time;
uint16_t rem_max_rx_time;
uint16_t eff_max_tx_time;
uint16_t eff_max_rx_time;
uint8_t max_tx_octets_phy_mode[BLE_PHY_NUM_MODE];
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
uint16_t host_req_max_tx_time;
#endif
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
struct ble_ll_conn_phy_data phy_data;
uint16_t phy_instant;
uint8_t phy_tx_transition;
#endif
/* Used to calculate data channel index for connection */
uint8_t chanmap[BLE_LL_CONN_CHMAP_LEN];
uint8_t req_chanmap[BLE_LL_CONN_CHMAP_LEN];
uint16_t chanmap_instant;
uint16_t channel_id; /* TODO could be union with hop and last chan used */
uint8_t hop_inc;
uint8_t data_chan_index;
uint8_t last_unmapped_chan;
uint8_t num_used_chans;
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
uint8_t period_occ_mask; /* mask: period 0 = 0x01, period 3 = 0x08 */
#endif
/* Ack/Flow Control */
uint8_t tx_seqnum; /* note: can be 1 bit */
uint8_t next_exp_seqnum; /* note: can be 1 bit */
uint8_t cons_rxd_bad_crc; /* note: can be 1 bit */
uint8_t last_rxd_sn; /* note: cant be 1 bit given current code */
uint8_t last_rxd_hdr_byte; /* note: possibly can make 1 bit since we
only use the MD bit now */
/* connection event mgmt */
uint8_t reject_reason;
uint8_t host_reply_opcode;
uint8_t master_sca;
uint8_t tx_win_size;
uint8_t cur_ctrl_proc;
uint8_t disconnect_reason;
uint8_t rxd_disconnect_reason;
uint8_t vers_nr;
uint8_t conn_features;
uint8_t remote_features[7];
uint16_t pending_ctrl_procs;
uint16_t event_cntr;
uint16_t completed_pkts;
uint16_t comp_id;
uint16_t sub_vers_nr;
uint16_t auth_pyld_tmo; /* could be ifdef'd. 10 msec units */
uint32_t access_addr;
uint32_t crcinit; /* only low 24 bits used */
/* XXX: do we need ce_end_time? Cant this be sched end time? */
uint32_t ce_end_time; /* cputime at which connection event should end */
uint32_t terminate_timeout;
uint32_t last_scheduled;
/* Connection timing */
uint16_t conn_itvl;
uint16_t slave_latency;
uint16_t supervision_tmo;
uint16_t min_ce_len;
uint16_t max_ce_len;
uint16_t tx_win_off;
uint32_t anchor_point;
uint8_t anchor_point_usecs; /* XXX: can this be uint8_t ?*/
uint8_t conn_itvl_usecs;
uint32_t conn_itvl_ticks;
uint32_t last_anchor_point; /* Slave only */
uint32_t slave_cur_tx_win_usecs;
uint32_t slave_cur_window_widening;
uint32_t last_rxd_pdu_cputime; /* Used exclusively for supervision timer */
/*
* Used to mark that identity address was used as InitA
*/
uint8_t inita_identity_used;
/* address information */
uint8_t own_addr_type;
uint8_t peer_addr_type;
uint8_t peer_addr[BLE_DEV_ADDR_LEN];
/*
* XXX: TODO. Could save memory. Have single event at LL and put these
* on a singly linked list. Only would need list pointer here.
*/
/* Connection end event */
struct ble_npl_event conn_ev_end;
/* Packet transmit queue */
struct os_mbuf *cur_tx_pdu;
STAILQ_HEAD(conn_txq_head, os_mbuf_pkthdr) conn_txq;
/* List entry for active/free connection pools */
union {
SLIST_ENTRY(ble_ll_conn_sm) act_sle;
STAILQ_ENTRY(ble_ll_conn_sm) free_stqe;
};
/* LL control procedure response timer */
struct ble_npl_callout ctrl_proc_rsp_timer;
/* For scheduling connections */
struct ble_ll_sched_item conn_sch;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
struct ble_npl_callout auth_pyld_timer;
#endif
/*
* XXX: a note on all these structures for control procedures. First off,
* all of these need to be ifdef'd to save memory. Another thing to
* consider is this: since most control procedures can only run when no
* others are running, can I use just one structure (a union)? Should I
* allocate these from a pool? Not sure what to do. For now, I just use
* a large chunk of memory per connection.
*/
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
struct ble_ll_conn_enc_data enc_data;
#endif
/*
* For connection update procedure. XXX: can make this a pointer and
* malloc it if we want to save space.
*/
struct hci_conn_update conn_param_req;
/* For connection update procedure */
struct ble_ll_conn_upd_req conn_update_req;
/* XXX: for now, just store them all */
struct ble_ll_conn_params conn_cp;
struct ble_ll_scan_sm *scansm;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
struct hci_ext_create_conn initial_params;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
uint8_t sync_transfer_mode;
uint16_t sync_transfer_skip;
uint32_t sync_transfer_sync_timeout;
#endif
};
/* Flags */
#define CONN_F_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.conn_update_sched)
#define CONN_F_EMPTY_PDU_TXD(csm) ((csm)->csmflags.cfbit.conn_empty_pdu_txd)
#define CONN_F_LAST_TXD_MD(csm) ((csm)->csmflags.cfbit.last_txd_md)
#define CONN_F_CONN_REQ_TXD(csm) ((csm)->csmflags.cfbit.conn_req_txd)
#define CONN_F_ENCRYPTED(csm) ((csm)->csmflags.cfbit.encrypted)
#define CONN_F_ENC_CHANGE_SENT(csm) ((csm)->csmflags.cfbit.encrypt_chg_sent)
#define CONN_F_LE_PING_SUPP(csm) ((csm)->csmflags.cfbit.le_ping_supp)
#define CONN_F_TERMINATE_STARTED(csm) ((csm)->csmflags.cfbit.terminate_started)
#define CONN_F_CSA2_SUPP(csm) ((csm)->csmflags.cfbit.csa2_supp)
#define CONN_F_HOST_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.host_phy_update)
#define CONN_F_PHY_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.phy_update_sched)
#define CONN_F_CTRLR_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.ctrlr_phy_update)
#define CONN_F_PHY_UPDATE_EVENT(csm) ((csm)->csmflags.cfbit.phy_update_event)
#define CONN_F_PEER_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.peer_phy_update)
#define CONN_F_AUX_CONN_REQ(csm) ((csm)->csmflags.cfbit.aux_conn_req)
/* Role */
#define CONN_IS_MASTER(csm) (csm->conn_role == BLE_LL_CONN_ROLE_MASTER)
#define CONN_IS_SLAVE(csm) (csm->conn_role == BLE_LL_CONN_ROLE_SLAVE)
/*
* Given a handle, returns an active connection state machine (or NULL if the
* handle does not exist
*
*/
struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle);
/* required for unit testing */
uint8_t ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency);
/* used to get anchor point for connection event specified */
void ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event,
uint32_t *anchor, uint8_t *anchor_usecs);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_CONN_ */

View File

@@ -0,0 +1,313 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_CTRL_
#define H_BLE_LL_CTRL_
#ifdef __cplusplus
extern "C" {
#endif
/*
* LL control procedures. This "enumeration" is not in the specification;
* It is used to determine which LL control procedure is currently running
* in a connection and which ones may be pending.
*/
#define BLE_LL_CTRL_PROC_CONN_UPDATE (0)
#define BLE_LL_CTRL_PROC_CHAN_MAP_UPD (1)
#define BLE_LL_CTRL_PROC_ENCRYPT (2)
#define BLE_LL_CTRL_PROC_FEATURE_XCHG (3)
#define BLE_LL_CTRL_PROC_VERSION_XCHG (4)
#define BLE_LL_CTRL_PROC_TERMINATE (5)
#define BLE_LL_CTRL_PROC_CONN_PARAM_REQ (6)
#define BLE_LL_CTRL_PROC_LE_PING (7)
#define BLE_LL_CTRL_PROC_DATA_LEN_UPD (8)
#define BLE_LL_CTRL_PROC_PHY_UPDATE (9)
#define BLE_LL_CTRL_PROC_NUM (10)
#define BLE_LL_CTRL_PROC_IDLE (255)
/* Checks if a particular control procedure is running */
#define IS_PENDING_CTRL_PROC(sm, proc) (sm->pending_ctrl_procs & (1 << proc))
#define CLR_PENDING_CTRL_PROC(sm, proc) (sm->pending_ctrl_procs &= ~(1 << proc))
/* LL control procedure timeout */
#define BLE_LL_CTRL_PROC_TIMEOUT_MS (40000) /* ms */
/*
* LL CTRL PDU format
* -> Opcode (1 byte)
* -> Data (0 - 26 bytes)
*/
#define BLE_LL_CTRL_CONN_UPDATE_IND (0)
#define BLE_LL_CTRL_CHANNEL_MAP_REQ (1)
#define BLE_LL_CTRL_TERMINATE_IND (2)
#define BLE_LL_CTRL_ENC_REQ (3)
#define BLE_LL_CTRL_ENC_RSP (4)
#define BLE_LL_CTRL_START_ENC_REQ (5)
#define BLE_LL_CTRL_START_ENC_RSP (6)
#define BLE_LL_CTRL_UNKNOWN_RSP (7)
#define BLE_LL_CTRL_FEATURE_REQ (8)
#define BLE_LL_CTRL_FEATURE_RSP (9)
#define BLE_LL_CTRL_PAUSE_ENC_REQ (10)
#define BLE_LL_CTRL_PAUSE_ENC_RSP (11)
#define BLE_LL_CTRL_VERSION_IND (12)
#define BLE_LL_CTRL_REJECT_IND (13)
#define BLE_LL_CTRL_SLAVE_FEATURE_REQ (14)
#define BLE_LL_CTRL_CONN_PARM_REQ (15)
#define BLE_LL_CTRL_CONN_PARM_RSP (16)
#define BLE_LL_CTRL_REJECT_IND_EXT (17)
#define BLE_LL_CTRL_PING_REQ (18)
#define BLE_LL_CTRL_PING_RSP (19)
#define BLE_LL_CTRL_LENGTH_REQ (20)
#define BLE_LL_CTRL_LENGTH_RSP (21)
#define BLE_LL_CTRL_PHY_REQ (22)
#define BLE_LL_CTRL_PHY_RSP (23)
#define BLE_LL_CTRL_PHY_UPDATE_IND (24)
#define BLE_LL_CTRL_MIN_USED_CHAN_IND (25)
#define BLE_LL_CTRL_CTE_REQ (26)
#define BLE_LL_CTRL_CTE_RSP (27)
#define BLE_LL_CTRL_PERIODIC_SYNC_IND (28)
#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ (29)
#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP (30)
/* Maximum opcode value */
#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_CLOCK_ACCURACY_RSP + 1)
extern const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES];
/* Maximum LL control PDU size */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
#define BLE_LL_CTRL_MAX_PDU_LEN (35)
#else
#define BLE_LL_CTRL_MAX_PDU_LEN (27)
#endif
/* LL control connection update request */
struct ble_ll_conn_upd_req
{
uint8_t winsize;
uint16_t winoffset;
uint16_t interval;
uint16_t latency;
uint16_t timeout;
uint16_t instant;
};
#define BLE_LL_CTRL_CONN_UPD_REQ_LEN (11)
/* LL control channel map request */
struct ble_ll_chan_map_req
{
uint8_t chmap[5];
uint16_t instant;
};
#define BLE_LL_CTRL_CHAN_MAP_LEN (7)
/*
* LL control terminate ind
* -> error code (1 byte)
*/
#define BLE_LL_CTRL_TERMINATE_IND_LEN (1)
/* LL control enc req */
struct ble_ll_enc_req
{
uint8_t rand[8];
uint16_t ediv;
uint8_t skdm[8];
uint32_t ivm;
};
#define BLE_LL_CTRL_ENC_REQ_LEN (22)
/* LL control enc rsp */
struct ble_ll_enc_rsp
{
uint8_t skds[8];
uint32_t ivs;
};
#define BLE_LL_CTRL_ENC_RSP_LEN (12)
/* LL control start/pause enc request and response */
#define BLE_LL_CTRL_START_ENC_REQ_LEN (0)
#define BLE_LL_CTRL_START_ENC_RSP_LEN (0)
#define BLE_LL_CTRL_PAUSE_ENC_REQ_LEN (0)
#define BLE_LL_CTRL_PAUSE_ENC_RSP_LEN (0)
/*
* LL control unknown response
* -> 1 byte which contains the unknown or un-supported opcode.
*/
#define BLE_LL_CTRL_UNK_RSP_LEN (1)
/*
* LL control feature req and LL control feature rsp
* -> 8 bytes of data containing features supported by device.
*/
#define BLE_LL_CTRL_FEATURE_LEN (8)
/*
* LL control version ind
* -> version (1 byte):
* Contains the version number of the bluetooth controller specification.
* -> comp_id (2 bytes)
* Contains the company identifier of the manufacturer of the controller.
* -> sub_ver_num: Contains a unique value for implementation or revision of
* the bluetooth controller.
*/
struct ble_ll_version_ind
{
uint8_t ble_ctrlr_ver;
uint16_t company_id;
uint16_t sub_ver_num;
};
#define BLE_LL_CTRL_VERSION_IND_LEN (5)
/*
* LL control reject ind
* -> error code (1 byte): contains reason why request was rejected.
*/
#define BLE_LL_CTRL_REJ_IND_LEN (1)
/*
* LL control slave feature req
* -> 8 bytes of data containing features supported by device.
*/
#define BLE_LL_CTRL_SLAVE_FEATURE_REQ_LEN (8)
/* LL control connection param req and connection param rsp */
struct ble_ll_conn_params
{
uint16_t interval_min;
uint16_t interval_max;
uint16_t latency;
uint16_t timeout;
uint8_t pref_periodicity;
uint16_t ref_conn_event_cnt;
uint16_t offset0;
uint16_t offset1;
uint16_t offset2;
uint16_t offset3;
uint16_t offset4;
uint16_t offset5;
};
#define BLE_LL_CTRL_CONN_PARAMS_LEN (23)
/* LL control reject ind ext */
struct ble_ll_reject_ind_ext
{
uint8_t reject_opcode;
uint8_t err_code;
};
#define BLE_LL_CTRL_REJECT_IND_EXT_LEN (2)
/* LL control ping req and ping rsp (contain no data) */
#define BLE_LL_CTRL_PING_LEN (0)
/*
* LL control length req and length rsp
* -> max_rx_bytes (2 bytes): defines connMaxRxOctets. Range 27 to 251
* -> max_rx_time (2 bytes): defines connMaxRxTime. Range 328 to 2120 usecs.
* -> max_tx_bytes (2 bytes): defines connMaxTxOctets. Range 27 to 251
* -> max_tx_time (2 bytes): defines connMaxTxTime. Range 328 to 2120 usecs.
*/
struct ble_ll_len_req
{
uint16_t max_rx_bytes;
uint16_t max_rx_time;
uint16_t max_tx_bytes;
uint16_t max_tx_time;
};
#define BLE_LL_CTRL_LENGTH_REQ_LEN (8)
/* PHY request/response */
#define BLE_LL_CTRL_PHY_REQ_LEN (2)
#define BLE_LL_CTRL_PHY_RSP_LEN (2)
#define BLE_LL_CTRL_PHY_UPD_IND_LEN (4)
/* Min used channels */
#define BLE_LL_CTRL_MIN_USED_CHAN_LEN (2)
/* CTE REQ */
#define BLE_LL_CTRL_CTE_REQ_LEN (1)
/* CTE RSP (contains no data) */
#define BLE_LL_CTRL_CTE_RSP_LEN (0)
/* Periodic Sync Transfer IND */
#define BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN (34)
/* Clock accuracy request/response */
#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ_LEN (1)
#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP_LEN (1)
/* API */
struct ble_ll_conn_sm;
void ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc);
void ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc);
int ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om);
void ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm);
void ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm);
int ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode);
uint8_t ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm,
uint8_t *rsp,
struct ble_ll_conn_params *req);
int ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm,
uint8_t rej_opcode, uint8_t err);
int ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm);
int ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf *rxpdu);
int ble_ll_ctrl_enc_allowed_pdu_tx(struct os_mbuf_pkthdr *pkthdr);
int ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm);
int ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu);
void ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm);
void ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm,
struct ble_ll_conn_params *cp);
void ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status);
void ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm,
uint8_t status);
void ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status);
void ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status);
int ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm);
int ble_ll_hci_ev_hw_err(uint8_t hw_err);
void ble_ll_hci_ev_databuf_overflow(void);
void ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm);
void ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer,
uint8_t peer_addr_type);
void ble_ll_hci_ev_send_scan_timeout(void);
void ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle,
uint16_t conn_handle, uint8_t events);
int ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status);
void ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm);
void ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm);
void ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm);
void ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line);
uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask);
uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_CTRL_ */

View File

@@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_HCI_
#define H_BLE_LL_HCI_
#ifdef __cplusplus
extern "C" {
#endif
#include "nimble/hci_common.h"
/* For supported commands */
#define BLE_LL_SUPP_CMD_LEN (42)
extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN];
/* The largest event the controller will send. */
#define BLE_LL_MAX_EVT_LEN MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)
/*
* This determines the number of outstanding commands allowed from the
* host to the controller. NOTE: you cannot change this without modifying
* other portions of the code as we currently use a global os event for
* the command; you would need to allocate a pool of these.
*/
#define BLE_LL_CFG_NUM_HCI_CMD_PKTS (1)
typedef void (*ble_ll_hci_post_cmd_complete_cb)(void);
/* Initialize LL HCI */
void ble_ll_hci_init(void);
/* Used to determine if the LE event is enabled/disabled */
bool ble_ll_hci_is_le_event_enabled(unsigned int subev);
/* Used to determine if event is enabled/disabled */
bool ble_ll_hci_is_event_enabled(unsigned int evcode);
/* Send event from controller to host */
int ble_ll_hci_event_send(struct ble_hci_ev *hci_ev);
/* Sends a command complete with a no-op opcode to host */
void ble_ll_hci_send_noop(void);
/* Checks the preferref phy masks from set default phy and set phy commands */
int ble_ll_hci_chk_phy_masks(uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys,
uint8_t *txphy, uint8_t *rxphy);
/* Returns true if Extended Advertising HCI commands are in use */
bool ble_ll_hci_adv_mode_ext(void);
/* Get TX power compensation rounded to integer dB */
int8_t ble_ll_get_tx_pwr_compensation(void);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_HCI_ */

View File

@@ -0,0 +1,116 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_RESOLV_
#define H_BLE_LL_RESOLV_
#ifdef __cplusplus
extern "C" {
#endif
/*
* An entry in the resolving list.
* The identity address is stored in little endian format.
* The local rpa is stored in little endian format.
* The IRKs are stored in big endian format.
*
* Note:
* rl_local_irk and rl_peer_irk need to be word aligned
*/
struct ble_ll_resolv_entry
{
uint8_t rl_addr_type;
uint8_t rl_priv_mode;
uint8_t rl_has_local;
uint8_t rl_has_peer;
uint8_t rl_local_irk[16];
uint8_t rl_peer_irk[16];
uint8_t rl_identity_addr[BLE_DEV_ADDR_LEN];
uint8_t rl_local_rpa[BLE_DEV_ADDR_LEN];
uint8_t rl_peer_rpa[BLE_DEV_ADDR_LEN];
};
extern struct ble_ll_resolv_entry g_ble_ll_resolv_list[];
/* Clear the resolving list */
int ble_ll_resolv_list_clr(void);
/* Read the size of the resolving list */
int ble_ll_resolv_list_read_size(uint8_t *rspbuf, uint8_t *rsplen);
/* Add a device to the resolving list */
int ble_ll_resolv_list_add(const uint8_t *cmdbuf, uint8_t len);
/* Remove a device from the resolving list */
int ble_ll_resolv_list_rmv(const uint8_t *cmdbuf, uint8_t len);
/* Address resolution enable command */
int ble_ll_resolv_enable_cmd(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_resolv_peer_addr_rd(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_resolv_local_addr_rd(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
/* Finds 'addr' in resolving list. Doesnt check if address resolution enabled */
struct ble_ll_resolv_entry *
ble_ll_resolv_list_find(const uint8_t *addr, uint8_t addr_type);
/* Returns true if address resolution is enabled */
uint8_t ble_ll_resolv_enabled(void);
/* Reset private address resolution */
void ble_ll_resolv_list_reset(void);
/* Generate local or peer RPA. It is up to caller to make sure required IRK
* is present on RL
*/
void ble_ll_resolv_get_priv_addr(struct ble_ll_resolv_entry *rl, int local,
uint8_t *addr);
void ble_ll_resolv_set_peer_rpa(int index, uint8_t *rpa);
void ble_ll_resolv_set_local_rpa(int index, uint8_t *rpa);
/* Generate a resolvable private address. */
int ble_ll_resolv_gen_rpa(uint8_t *addr, uint8_t addr_type, uint8_t *rpa,
int local);
/* Set the resolvable private address timeout */
int ble_ll_resolv_set_rpa_tmo(const uint8_t *cmdbuf, uint8_t len);
/* Set the privacy mode */
int ble_ll_resolve_set_priv_mode(const uint8_t *cmdbuf, uint8_t len);
/* Get the RPA timeout, in seconds */
uint32_t ble_ll_resolv_get_rpa_tmo(void);
/* Resolve a resolvable private address */
int ble_ll_resolv_rpa(const uint8_t *rpa, const uint8_t *irk);
/* Try to resolve peer RPA and return index on RL if matched */
int ble_ll_resolv_peer_rpa_any(const uint8_t *rpa);
/* Initialize resolv*/
void ble_ll_resolv_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_RFMGMT_
#define H_BLE_LL_RFMGMT_
#ifdef __cplusplus
extern "C" {
#endif
void ble_ll_rfmgmt_init(void);
#if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0
void ble_ll_rfmgmt_reset(void);
/* Notify rfmgmt that scan window has changed (only called from ble_ll_scan) */
void ble_ll_rfmgmt_scan_changed(bool enabled, uint32_t next_window);
/* Notify rfmgmt that 1st scheduled item has changed (only called from ble_ll_sched) */
void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *first);
/* Notify rfmgmt that RF is no longer needed by current event */
void ble_ll_rfmgmt_release(void);
/* Enables RF immediately and returns tick at which RF will be fully enabled */
uint32_t ble_ll_rfmgmt_enable_now(void);
/* Returns true only if RF is currently fully enabled (i.e. not off or enabling) */
bool ble_ll_rfmgmt_is_enabled(void);
#else
static inline void ble_ll_rfmgmt_reset(void) { }
static inline void ble_ll_rfmgmt_scan_changed(bool e, uint32_t n) { }
static inline void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *f) { }
static inline void ble_ll_rfmgmt_release(void) { }
static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return 0; }
static inline bool ble_ll_rfmgmt_is_enabled(void) { return true; }
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_RFMGMT_ */

View File

@@ -0,0 +1,293 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_SCAN_
#define H_BLE_LL_SCAN_
#include "controller/ble_ll_sched.h"
#include "hal/hal_timer.h"
#include "syscfg/syscfg.h"
#include "nimble/nimble_npl.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* SCAN_REQ
* -> ScanA (6 bytes)
* -> AdvA (6 bytes)
*
* ScanA is the scanners public (TxAdd=0) or random (TxAdd = 1) address
* AdvaA is the advertisers public (RxAdd=0) or random (RxAdd=1) address.
*
* Sent by the LL in the Scanning state; received by the LL in the advertising
* state. The advertising address is the intended recipient of this frame.
*/
#define BLE_SCAN_REQ_LEN (12)
/*
* SCAN_RSP
* -> AdvA (6 bytes)
* -> ScanRspData (0 - 31 bytes)
*
* AdvaA is the advertisers public (TxAdd=0) or random (TxAdd=1) address.
* ScanRspData may contain any data from the advertisers host.
*
* Sent by the LL in the advertising state; received by the LL in the
* scanning state.
*/
#define BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN (31)
#define BLE_SCAN_LEGACY_MAX_PKT_LEN (37)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
#define BLE_SCAN_RSP_DATA_MAX_LEN MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)
/* For Bluetooth 5.0 we need state machine for two PHYs*/
#define BLE_LL_SCAN_PHY_NUMBER (2)
#else
#define BLE_LL_SCAN_PHY_NUMBER (1)
#define BLE_SCAN_RSP_DATA_MAX_LEN BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN
#endif
#define PHY_UNCODED (0)
#define PHY_CODED (1)
#define BLE_LL_EXT_ADV_MODE_NON_CONN (0x00)
#define BLE_LL_EXT_ADV_MODE_CONN (0x01)
#define BLE_LL_EXT_ADV_MODE_SCAN (0x02)
/* All values are stored as ticks */
struct ble_ll_scan_timing {
uint32_t interval;
uint32_t window;
uint32_t start_time;
};
struct ble_ll_scan_params
{
uint8_t phy;
uint8_t own_addr_type;
uint8_t scan_filt_policy;
uint8_t configured;
uint8_t scan_type;
uint8_t scan_chan;
struct ble_ll_scan_timing timing;
};
#define BLE_LL_AUX_HAS_ADVA 0x01
#define BLE_LL_AUX_HAS_TARGETA 0x02
#define BLE_LL_AUX_HAS_ADI 0x04
#define BLE_LL_AUX_IS_MATCHED 0x08
#define BLE_LL_AUX_IS_TARGETA_RESOLVED 0x10
#define BLE_LL_AUX_FLAG_HCI_SENT_ANY 0x02
#define BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED 0x04
#define BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED 0x08
#define BLE_LL_AUX_FLAG_SCAN_COMPLETE 0x10
#define BLE_LL_AUX_FLAG_SCAN_ERROR 0x20
#define BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED 0x40
#define BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED 0x80
struct ble_ll_aux_data {
uint8_t flags;
/*
* Since aux_data can be accessed from ISR and LL, we have separate copies
* of flags to make sure that ISR does not modify flags while LL uses them.
* ISR updates 'flags_isr' and LL adds these to 'flags_ll' which it then
* uses for further processing allowing to update 'flags_isr' if another
* scan for given 'aux_data' is scheduled. Note that flags must not be unset
* while aux_data is valid.
*/
uint8_t flags_isr;
uint8_t flags_ll;
uint8_t ref_cnt;
uint8_t chan;
uint8_t aux_phy;
uint8_t aux_primary_phy;
uint8_t mode;
uint8_t scanning;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
int8_t rpa_index;
#endif
uint16_t adi;
uint32_t offset;
uint8_t offset_units;
uint8_t adva[6];
uint8_t adva_type;
uint8_t targeta[6];
uint8_t targeta_type;
uint16_t evt_type;
struct ble_ll_sched_item sch;
struct ble_hci_ev *evt;
struct ble_npl_event ev;
};
struct ble_ll_scan_pdu_data {
uint8_t hdr_byte;
/* ScanA for SCAN_REQ and InitA for CONNECT_IND */
union {
uint8_t scana[BLE_DEV_ADDR_LEN];
uint8_t inita[BLE_DEV_ADDR_LEN];
};
uint8_t adva[BLE_DEV_ADDR_LEN];
};
struct ble_ll_scan_sm
{
uint8_t scan_enabled;
uint8_t own_addr_type;
uint8_t scan_filt_dups;
uint8_t scan_rsp_pending;
uint8_t scan_rsp_cons_fails;
uint8_t scan_rsp_cons_ok;
uint8_t scan_peer_rpa[BLE_DEV_ADDR_LEN];
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
ble_npl_time_t scan_nrpa_timer;
uint8_t scan_nrpa[BLE_DEV_ADDR_LEN];
#endif
struct ble_ll_scan_pdu_data pdu_data;
/* XXX: Shall we count backoff per phy? */
uint16_t upper_limit;
uint16_t backoff_count;
uint32_t scan_win_start_time;
struct ble_npl_event scan_sched_ev;
struct hal_timer scan_timer;
struct ble_npl_event scan_interrupted_ev;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
struct hal_timer duration_timer;
struct hal_timer period_timer;
uint32_t duration_ticks;
uint32_t period_ticks;
uint8_t ext_scanning;
#endif
uint8_t restart_timer_needed;
struct ble_ll_aux_data *cur_aux_data;
struct ble_ll_scan_params *scanp;
struct ble_ll_scan_params *scanp_next;
struct ble_ll_scan_params scanp_phys[BLE_LL_SCAN_PHY_NUMBER];
};
/* Scan types */
#define BLE_SCAN_TYPE_PASSIVE (BLE_HCI_SCAN_TYPE_PASSIVE)
#define BLE_SCAN_TYPE_ACTIVE (BLE_HCI_SCAN_TYPE_ACTIVE)
#define BLE_SCAN_TYPE_INITIATE (2)
/*---- HCI ----*/
/* Set scanning parameters */
int ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len);
/* Turn scanning on/off */
int ble_ll_hci_scan_set_enable(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_hci_ext_scan_set_enable(const uint8_t *cmdbuf, uint8_t len);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
int ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len);
#endif
/*--- Controller Internal API ---*/
/* Initialize the scanner */
void ble_ll_scan_init(void);
/* Reset the scanner */
void ble_ll_scan_reset(void);
/* Called when Link Layer starts to receive a PDU and is in scanning state */
int ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags);
/* Called when Link Layer has finished receiving a PDU while scanning */
int ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok);
/* Process a scan response PDU */
void ble_ll_scan_rx_pkt_in(uint8_t pdu_type, struct os_mbuf *om,
struct ble_mbuf_hdr *hdr);
/* Boolean function denoting whether or not the whitelist can be changed */
int ble_ll_scan_can_chg_whitelist(void);
/* Boolean function returning true if scanning enabled */
int ble_ll_scan_enabled(void);
/* Boolean function returns true if whitelist is enabled for scanning */
int ble_ll_scan_whitelist_enabled(void);
/* Initialize the scanner when we start initiating */
struct hci_create_conn;
int ble_ll_scan_initiator_start(struct hci_create_conn *hcc,
struct ble_ll_scan_sm **sm);
/* Returns storage for PDU data (for SCAN_REQ or CONNECT_IND) */
struct ble_ll_scan_pdu_data *ble_ll_scan_get_pdu_data(void);
/* Called to set the resolvable private address of the last connected peer */
void ble_ll_scan_set_peer_rpa(uint8_t *rpa);
/* Returns peer RPA of last connection made */
uint8_t *ble_ll_scan_get_peer_rpa(void);
/* Returns the local RPA used by the scanner/initiator */
uint8_t *ble_ll_scan_get_local_rpa(void);
/* Stop the scanning state machine */
void ble_ll_scan_sm_stop(int chk_disable);
/* Resume scanning */
void ble_ll_scan_chk_resume(void);
/* Called when wait for response timer expires in scanning mode */
void ble_ll_scan_wfr_timer_exp(void);
/* Called when scan could be interrupted */
void ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm);
int ble_ll_scan_adv_decode_addr(uint8_t pdu_type, uint8_t *rxbuf,
struct ble_mbuf_hdr *ble_hdr,
uint8_t **addr, uint8_t *addr_type,
uint8_t **inita, uint8_t *init_addr_type,
int *ext_mode);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
int ble_ll_scan_update_aux_data(struct ble_mbuf_hdr *ble_hdr, uint8_t *rxbuf,
bool *adva_present);
/* Initialize the extended scanner when we start initiating */
struct hci_ext_create_conn;
int ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc,
struct ble_ll_scan_sm **sm);
/* Called to parse extended advertising*/
struct ble_ll_aux_data *ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_scan);
void ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_scan);
void ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data);
#endif
/* Called to halt currently running scan */
void ble_ll_scan_halt(void);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_SCAN_ */

View File

@@ -0,0 +1,216 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_SCHED_
#define H_BLE_LL_SCHED_
#ifdef __cplusplus
extern "C" {
#endif
/* Time per BLE scheduler slot */
#define BLE_LL_SCHED_USECS_PER_SLOT (1250)
#define BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT (41) /* 1 tick = 30.517 usecs */
/*
* Worst case time needed for scheduled advertising item. This is the longest
* possible time to receive a scan request and send a scan response (with the
* appropriate IFS time between them). This number is calculated using the
* following formula: IFS + SCAN_REQ + IFS + SCAN_RSP = 150 + 176 + 150 + 376.
* Note: worst case time to tx adv, rx scan req and send scan rsp is 1228 usecs.
* This assumes maximum sized advertising PDU and scan response PDU.
*
* For connectable advertising events no scan request is allowed. In this case
* we just need to receive a connect request PDU: IFS + CONNECT_REQ = 150 + 352.
* Note: worst-case is 376 + 150 + 352 = 878 usecs
*
* NOTE: The advertising PDU transmit time is NOT included here since we know
* how long that will take (worst-case is 376 usecs).
*/
#define BLE_LL_SCHED_ADV_MAX_USECS (852)
#define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS (502)
#define BLE_LL_SCHED_MAX_ADV_PDU_USECS (376)
/*
* This is the offset from the start of the scheduled item until the actual
* tx/rx should occur, in ticks.
*/
extern uint8_t g_ble_ll_sched_offset_ticks;
/*
* This is the number of slots needed to transmit and receive a maximum
* size PDU, including an IFS time before each. The actual time is
* 2120 usecs for tx/rx and 150 for IFS = 4540 usecs.
*/
#define BLE_LL_SCHED_MAX_TXRX_SLOT (4 * BLE_LL_SCHED_USECS_PER_SLOT)
/* BLE scheduler errors */
#define BLE_LL_SCHED_ERR_OVERLAP (1)
/* Types of scheduler events */
#define BLE_LL_SCHED_TYPE_ADV (1)
#define BLE_LL_SCHED_TYPE_SCAN (2)
#define BLE_LL_SCHED_TYPE_CONN (3)
#define BLE_LL_SCHED_TYPE_AUX_SCAN (4)
#define BLE_LL_SCHED_TYPE_DTM (5)
#define BLE_LL_SCHED_TYPE_PERIODIC (6)
#define BLE_LL_SCHED_TYPE_SYNC (7)
/* Return values for schedule callback. */
#define BLE_LL_SCHED_STATE_RUNNING (0)
#define BLE_LL_SCHED_STATE_DONE (1)
/* Callback function */
struct ble_ll_sched_item;
typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch);
typedef void (*sched_remove_cb_func)(struct ble_ll_sched_item *sch);
/*
* Strict connection scheduling (for the master) is different than how
* connections are normally scheduled. With strict connection scheduling we
* introduce the concept of a "period". A period is a collection of slots. Each
* slot is 1.25 msecs in length. The number of slots in a period is determined
* by the syscfg value BLE_LL_CONN_INIT_SLOTS. A collection of periods is called
* an epoch. The length of an epoch is determined by the number of connections
* (BLE_MAX_CONNECTIONS plus BLE_LL_ADD_STRICT_SCHED_PERIODS). Connections
* will be scheduled at period boundaries. Any scanning/initiating/advertising
* will be done in unused periods, if possible.
*/
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
#define BLE_LL_SCHED_PERIODS (MYNEWT_VAL(BLE_MAX_CONNECTIONS) + \
MYNEWT_VAL(BLE_LL_ADD_STRICT_SCHED_PERIODS))
struct ble_ll_sched_obj
{
uint8_t sch_num_occ_periods;
uint32_t sch_occ_period_mask;
uint32_t sch_ticks_per_period;
uint32_t sch_ticks_per_epoch;
uint32_t sch_epoch_start;
};
extern struct ble_ll_sched_obj g_ble_ll_sched_data;
/*
* XXX: TODO:
* -> How do we know epoch start is up to date? Not wrapped?
* -> for now, only do this with no more than 32 connections.
* -> Do not let initiating occur if no empty sched slots
*/
#endif
/*
* Schedule item
* sched_type: This is the type of the schedule item.
* enqueued: Flag denoting if item is on the scheduler list. 0: no, 1:yes
* remainder: # of usecs from offset till tx/rx should occur
* txrx_offset: Number of ticks from start time until tx/rx should occur.
*
*/
struct ble_ll_sched_item
{
uint8_t sched_type;
uint8_t enqueued;
uint8_t remainder;
uint32_t start_time;
uint32_t end_time;
void *cb_arg;
sched_cb_func sched_cb;
TAILQ_ENTRY(ble_ll_sched_item) link;
};
/* Initialize the scheduler */
int ble_ll_sched_init(void);
/* Remove item(s) from schedule */
int ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch);
void ble_ll_sched_rmv_elem_type(uint8_t type, sched_remove_cb_func remove_cb);
/* Schedule a new master connection */
struct ble_ll_conn_sm;
int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len);
/* Schedule a new slave connection */
int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm);
struct ble_ll_adv_sm;
typedef void ble_ll_sched_adv_new_cb(struct ble_ll_adv_sm *advsm,
uint32_t sch_start, void *arg);
/* Schedule a new advertising event */
int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch,
ble_ll_sched_adv_new_cb cb, void *arg);
/* Schedule periodic advertising event */
int ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, uint32_t *start,
bool after_overlap);
int ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch,
uint32_t anchor_point,
uint8_t anchor_point_usecs,
uint32_t window_widening, int8_t phy_mode);
int ble_ll_sched_sync(struct ble_ll_sched_item *sch,
uint32_t beg_cputime, uint32_t rem_usecs, uint32_t offset,
int8_t phy_mode);
/* Reschedule an advertising event */
int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start,
uint32_t max_delay_ticks);
/* Reschedule and advertising pdu */
int ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch);
/* Reschedule a connection that had previously been scheduled or that is over */
int ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm * connsm);
/**
* Called to determine when the next scheduled event will occur.
*
* If there are not scheduled events this function returns 0; otherwise it
* returns 1 and *next_event_time is set to the start time of the next event.
*
* @param next_event_time cputime at which next scheduled event will occur
*
* @return int 0: No events are scheduled 1: there is an upcoming event
*/
int ble_ll_sched_next_time(uint32_t *next_event_time);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
struct ble_ll_scan_sm;
struct ble_ll_aux_data;
int ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr,
struct ble_ll_scan_sm *scansm,
struct ble_ll_aux_data *aux_scan);
int ble_ll_sched_scan_req_over_aux_ptr(uint32_t chan, uint8_t phy_mode);
#endif
/* Stop the scheduler */
void ble_ll_sched_stop(void);
#if MYNEWT_VAL(BLE_LL_DTM)
int ble_ll_sched_dtm(struct ble_ll_sched_item *sch);
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_LL_SCHED_ */

View File

@@ -0,0 +1,74 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_SYNC_
#define H_BLE_LL_SYNC_
#include <stdint.h>
#include "nimble/ble.h"
#include "controller/ble_ll_hci.h"
#include "controller/ble_ll_conn.h"
#ifdef __cplusplus
extern "C" {
#endif
struct ble_ll_sync_sm;
int ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb);
int ble_ll_sync_terminate(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_sync_list_clear(void);
int ble_ll_sync_list_size(uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_sync_transfer(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
void ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm,
const uint8_t *sync_ind, bool reports_disabled,
uint16_t max_skip, uint32_t sync_timeout);
void ble_ll_sync_transfer_disconnected(struct ble_ll_conn_sm *connsm);
void ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type,
int rpa_index, uint8_t sid,
struct ble_mbuf_hdr *rxhdr,
const uint8_t *syncinfo);
int ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr);
int ble_ll_sync_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr);
void ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr);
void ble_ll_sync_wfr_timer_exp(void);
void ble_ll_sync_halt(void);
void ble_ll_sync_rmvd_from_sched(struct ble_ll_sync_sm *sm);
uint32_t ble_ll_sync_get_event_end_time(void);
bool ble_ll_sync_enabled(void);
void ble_ll_sync_reset(void);
void ble_ll_sync_init(void);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_SYNC_ */

View File

@@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_LL_TEST_
#define H_LL_TEST_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
int ble_ll_csa2_test_all(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_TRACE_
#define H_BLE_LL_TRACE_
#include "os/os_trace_api.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_LL_TRACE_ID_SCHED 0
#define BLE_LL_TRACE_ID_RX_START 1
#define BLE_LL_TRACE_ID_RX_END 2
#define BLE_LL_TRACE_ID_WFR_EXP 3
#define BLE_LL_TRACE_ID_CTRL_RX 4
#define BLE_LL_TRACE_ID_CONN_EV_START 5
#define BLE_LL_TRACE_ID_CONN_EV_END 6
#define BLE_LL_TRACE_ID_CONN_END 7
#define BLE_LL_TRACE_ID_CONN_TX 8
#define BLE_LL_TRACE_ID_CONN_RX 9
#define BLE_LL_TRACE_ID_ADV_TXDONE 10
#define BLE_LL_TRACE_ID_ADV_HALT 11
#define BLE_LL_TRACE_ID_AUX_REF 12
#define BLE_LL_TRACE_ID_AUX_UNREF 13
#if MYNEWT_VAL(BLE_LL_SYSVIEW)
extern uint32_t ble_ll_trace_off;
void ble_ll_trace_init(void);
static inline void
ble_ll_trace_u32(unsigned id, uint32_t p1)
{
os_trace_api_u32(ble_ll_trace_off + id, p1);
}
static inline void
ble_ll_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2)
{
os_trace_api_u32x2(ble_ll_trace_off + id, p1, p2);
}
static inline void
ble_ll_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3)
{
os_trace_api_u32x3(ble_ll_trace_off + id, p1, p2, p3);
}
#else
static inline void
ble_ll_trace_init(void)
{
}
static inline void
ble_ll_trace_u32(unsigned id, uint32_t p1)
{
}
static inline void
ble_ll_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2)
{
}
static inline void
ble_ll_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3)
{
}
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_TRACE_ */

View File

@@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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>
uint32_t ble_ll_utils_calc_access_addr(void);
uint8_t ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap);
uint8_t ble_ll_utils_calc_dci_csa2(uint16_t event_cntr, uint16_t channel_id,
uint8_t num_used_chans, const uint8_t *chanmap);
uint8_t ble_ll_utils_calc_num_used_chans(const uint8_t *chanmap);
uint32_t ble_ll_utils_calc_window_widening(uint32_t anchor_point,
uint32_t last_anchor_point,
uint8_t master_sca);

View File

@@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_WHITELIST_
#define H_BLE_LL_WHITELIST_
#ifdef __cplusplus
extern "C" {
#endif
/* Clear the whitelist */
int ble_ll_whitelist_clear(void);
/* Read the size of the whitelist */
int ble_ll_whitelist_read_size(uint8_t *rspbuf, uint8_t *rsplen);
/* Add a device to the whitelist */
int ble_ll_whitelist_add(const uint8_t *cmdbuf, uint8_t len);
/* Remove a device fromthe whitelist */
int ble_ll_whitelist_rmv(const uint8_t *cmdbuf, uint8_t len);
/* Enable whitelisting */
void ble_ll_whitelist_enable(void);
/* Disable whitelisting */
void ble_ll_whitelist_disable(void);
/* Boolean function returning true if address matches a whitelist entry */
int ble_ll_whitelist_match(uint8_t *addr, uint8_t addr_type, int is_ident);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_WHITELIST_ */

View File

@@ -0,0 +1,242 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_PHY_
#define H_BLE_PHY_
#include "nimble/hci_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Forward declarations */
struct os_mbuf;
/* Channel/Frequency defintions */
#define BLE_PHY_NUM_CHANS (40)
#define BLE_PHY_NUM_DATA_CHANS (37)
#define BLE_PHY_CHAN0_FREQ_MHZ (2402)
#define BLE_PHY_DATA_CHAN0_FREQ_MHZ (2404)
#define BLE_PHY_CHAN_SPACING_MHZ (2)
#define BLE_PHY_NUM_ADV_CHANS (3)
#define BLE_PHY_ADV_CHAN_START (37)
/* Power */
#define BLE_PHY_MAX_PWR_DBM (10)
/* Deviation */
#define BLE_PHY_DEV_KHZ (185)
#define BLE_PHY_BINARY_ZERO (-BLE_PHY_DEV)
#define BLE_PHY_BINARY_ONE (BLE_PHY_DEV)
/* Max. clock drift */
#define BLE_PHY_MAX_DRIFT_PPM (50)
/* Data rate */
#define BLE_PHY_BIT_RATE_BPS (1000000)
/* Macros */
#define BLE_IS_ADV_CHAN(chan) (chan >= BLE_PHY_ADV_CHAN_START)
#define BLE_IS_DATA_CHAN(chan) (chan < BLE_PHY_ADV_CHAN_START)
/* PHY states */
#define BLE_PHY_STATE_IDLE (0)
#define BLE_PHY_STATE_RX (1)
#define BLE_PHY_STATE_TX (2)
/* BLE PHY transitions */
#define BLE_PHY_TRANSITION_NONE (0)
#define BLE_PHY_TRANSITION_RX_TX (1)
#define BLE_PHY_TRANSITION_TX_RX (2)
/* PHY error codes */
#define BLE_PHY_ERR_RADIO_STATE (1)
#define BLE_PHY_ERR_INIT (2)
#define BLE_PHY_ERR_INV_PARAM (3)
#define BLE_PHY_ERR_NO_BUFS (4)
#define BLE_PHY_ERR_TX_LATE (5)
#define BLE_PHY_ERR_RX_LATE (6)
/* Maximun PDU length. Includes LL header of 2 bytes and 255 bytes payload. */
#define BLE_PHY_MAX_PDU_LEN (257)
/* Wait for response timer */
typedef void (*ble_phy_tx_end_func)(void *arg);
/* Initialize the PHY */
int ble_phy_init(void);
/* Reset the PHY */
int ble_phy_reset(void);
/* Set the PHY channel */
int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit);
/* Set transmit start time */
int ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs);
/* Set receive start time */
int ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs);
/* Set the transmit end callback and argument */
void ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg);
typedef uint8_t (*ble_phy_tx_pducb_t)(uint8_t *dptr, void *pducb_arg,
uint8_t *hdr_byte);
/* Place the PHY into transmit mode */
int ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans);
/* Place the PHY into receive mode */
int ble_phy_rx(void);
/* Copies the received PHY buffer into the allocated pdu */
void ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu);
/* Set the transmit power */
int ble_phy_txpwr_set(int dbm);
/* Get highest allowed power from range */
int ble_phy_txpower_round(int dbm);
/* Get the transmit power */
int ble_phy_txpwr_get(void);
/* Set RX path power compensation value rounded to integer dB */
void ble_phy_set_rx_pwr_compensation(int8_t compensation);
/* Disable the PHY */
void ble_phy_disable(void);
#define BLE_PHY_WFR_ENABLE_RX (0)
#define BLE_PHY_WFR_ENABLE_TXRX (1)
void ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs);
/* Starts rf clock */
void ble_phy_rfclk_enable(void);
/* Stops rf clock */
void ble_phy_rfclk_disable(void);
/*
* Used to restart reception on same channel after wfr timer expiration or
* frame received.
*/
void ble_phy_restart_rx(void);
/* Gets the current state of the PHY */
int ble_phy_state_get(void);
/* Gets current state of transceiver */
uint8_t ble_phy_xcvr_state_get(void);
/* Returns 'true' if a reception has started */
int ble_phy_rx_started(void);
/*
* Returns the maximum supported tx/rx PDU payload size, in bytes, for data
* channel PDUs (this does not apply to advertising channel PDUs). Note
* that the data channel PDU is composed of a 2-byte header, the payload, and
* an optional MIC. The maximum payload is 251 bytes.
*/
uint8_t ble_phy_max_data_pdu_pyld(void);
/* Gets the current access address */
uint32_t ble_phy_access_addr_get(void);
/* Enable encryption */
void ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key,
uint8_t is_master);
/* Disable encryption */
void ble_phy_encrypt_disable(void);
/* Set the packet counters and dir used by LE encyption */
void ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir);
/* Enable phy resolving list */
void ble_phy_resolv_list_enable(void);
/* Disable phy resolving list */
void ble_phy_resolv_list_disable(void);
/*
* PHY mode values for 1M, 2M and Coded S=8 are the same as corresponding values
* of PHY. This makes conversion between 'phy' and 'phy_mode' easier and it also
* means that default coding for Coded will be S=8, unless explicitly translated
* to S=2.
*/
#define BLE_PHY_MODE_CODED_500KBPS (0)
#define BLE_PHY_MODE_1M (1)
#define BLE_PHY_MODE_2M (2)
#define BLE_PHY_MODE_CODED_125KBPS (3)
/* The number of different modes */
#define BLE_PHY_NUM_MODE (4)
/* PHY numbers (compatible with HCI) */
#define BLE_PHY_1M (BLE_HCI_LE_PHY_1M)
#define BLE_PHY_2M (BLE_HCI_LE_PHY_2M)
#define BLE_PHY_CODED (BLE_HCI_LE_PHY_CODED)
/* PHY bitmasks (compatible with HCI) */
#define BLE_PHY_MASK_1M (BLE_HCI_LE_PHY_1M_PREF_MASK)
#define BLE_PHY_MASK_2M (BLE_HCI_LE_PHY_2M_PREF_MASK)
#define BLE_PHY_MASK_CODED (BLE_HCI_LE_PHY_CODED_PREF_MASK)
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY))
uint32_t ble_phy_mode_pdu_start_off(int phy);
void ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode);
#else
#define ble_phy_mode_pdu_start_off(phy) (40)
#endif
int ble_phy_get_cur_phy(void);
static inline int ble_ll_phy_to_phy_mode(int phy, int phy_options)
{
int phy_mode;
/*
* 'phy' value can be used as 'phy_mode' value unless S=2 coding is explicitly
* required. By default we'll use S=2 for Coded.
*/
phy_mode = phy;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
if (phy == BLE_PHY_CODED && phy_options == BLE_HCI_LE_PHY_CODED_S2_PREF) {
phy_mode = BLE_PHY_MODE_CODED_500KBPS;
}
#endif
return phy_mode;
}
#if MYNEWT_VAL(BLE_LL_DTM)
void ble_phy_enable_dtm(void);
void ble_phy_disable_dtm(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_PHY_ */

View File

@@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_PHY_TRACE_
#define H_BLE_PHY_TRACE_
#include "os/os_trace_api.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_PHY_TRACE_ID_START_TX 0
#define BLE_PHY_TRACE_ID_START_RX 1
#define BLE_PHY_TRACE_ID_DISABLE 2
#if MYNEWT_VAL(BLE_PHY_SYSVIEW)
extern uint32_t ble_phy_trace_off;
void ble_phy_trace_init(void);
static inline void
ble_phy_trace_void(unsigned id)
{
os_trace_api_void(ble_phy_trace_off + id);
}
static inline void
ble_phy_trace_u32(unsigned id, uint32_t p1)
{
os_trace_api_u32(ble_phy_trace_off + id, p1);
}
static inline void
ble_phy_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2)
{
os_trace_api_u32x2(ble_phy_trace_off + id, p1, p2);
}
static inline void
ble_phy_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3)
{
os_trace_api_u32x3(ble_phy_trace_off + id, p1, p2, p3);
}
#else
static inline void
ble_phy_trace_init(void)
{
}
static inline void
ble_phy_trace_void(unsigned id)
{
}
static inline void
ble_phy_trace_u32(unsigned id, uint32_t p1)
{
}
static inline void
ble_phy_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2)
{
}
static inline void
ble_phy_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3)
{
}
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_PHY_TRACE_ */

View File

@@ -0,0 +1,38 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
pkg.name: nimble/controller
pkg.description: Controller side of the nimble Bluetooth Smart stack.
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
- ble
- bluetooth
pkg.req_apis:
- ble_driver
- ble_transport
- stats
pkg.deps:
- "@apache-mynewt-core/kernel/os"
- nimble
pkg.init:
ble_ll_init: 'MYNEWT_VAL(BLE_LL_SYSINIT_STAGE)'

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,226 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_CONN_PRIV_
#define H_BLE_LL_CONN_PRIV_
#include "controller/ble_ll_conn.h"
#include "controller/ble_ll_hci.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Definitions for min/max RX/TX time/bytes values allowed for connections.
* Source: Core 5.0 specification, Vol 6, Part B, section 4.5.10
*/
#define BLE_LL_CONN_SUPP_TIME_MIN (328) /* usecs */
#define BLE_LL_CONN_SUPP_TIME_MAX (17040) /* usecs */
#define BLE_LL_CONN_SUPP_TIME_MIN_UNCODED (328) /* usecs */
#define BLE_LL_CONN_SUPP_TIME_MAX_UNCODED (2120) /* usecs */
#define BLE_LL_CONN_SUPP_TIME_MIN_CODED (2704) /* usecs */
#define BLE_LL_CONN_SUPP_TIME_MAX_CODED (17040) /* usecs */
#define BLE_LL_CONN_SUPP_BYTES_MIN (27) /* bytes */
#define BLE_LL_CONN_SUPP_BYTES_MAX (251) /* bytes */
/* Connection event timing */
#define BLE_LL_CONN_INITIAL_OFFSET (1250)
#define BLE_LL_CONN_ITVL_USECS (1250)
#define BLE_LL_CONN_TX_WIN_USECS (1250)
#define BLE_LL_CONN_TX_OFF_USECS (1250)
#define BLE_LL_CONN_CE_USECS (625)
#define BLE_LL_CONN_TX_WIN_MIN (1) /* in tx win units */
#define BLE_LL_CONN_SLAVE_LATENCY_MAX (499)
/* Connection handle range */
#define BLE_LL_CONN_MAX_CONN_HANDLE (0x0EFF)
/* Offset (in bytes) of advertising address in connect request */
#define BLE_LL_CONN_REQ_ADVA_OFF (BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN)
/* Default authenticated payload timeout (30 seconds; in 10 msecs increments) */
#define BLE_LL_CONN_DEF_AUTH_PYLD_TMO (3000)
#define BLE_LL_CONN_AUTH_PYLD_OS_TMO(x) ble_npl_time_ms_to_ticks32((x) * 10)
/* Global Link Layer connection parameters */
struct ble_ll_conn_global_params
{
uint8_t master_chan_map[BLE_LL_CONN_CHMAP_LEN];
uint8_t num_used_chans;
uint8_t supp_max_tx_octets;
uint8_t supp_max_rx_octets;
uint8_t conn_init_max_tx_octets;
uint8_t sugg_tx_octets;
uint16_t sugg_tx_time;
uint16_t conn_init_max_tx_time;
uint16_t conn_init_max_tx_time_uncoded;
uint16_t conn_init_max_tx_time_coded;
uint16_t supp_max_tx_time;
uint16_t supp_max_rx_time;
};
extern struct ble_ll_conn_global_params g_ble_ll_conn_params;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
struct ble_ll_conn_sync_transfer_params
{
uint32_t sync_timeout_us;
uint16_t max_skip;
uint8_t mode;
};
extern struct ble_ll_conn_sync_transfer_params g_ble_ll_conn_sync_transfer_params;
#endif
/* Some data structures used by other LL routines */
SLIST_HEAD(ble_ll_conn_active_list, ble_ll_conn_sm);
STAILQ_HEAD(ble_ll_conn_free_list, ble_ll_conn_sm);
extern struct ble_ll_conn_active_list g_ble_ll_conn_active_list;
extern struct ble_ll_conn_free_list g_ble_ll_conn_free_list;
/* Pointer to connection state machine we are trying to create */
extern struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
/* Generic interface */
struct ble_ll_len_req;
struct ble_mbuf_hdr;
struct ble_ll_adv_sm;
struct hci_create_conn
{
uint16_t scan_itvl;
uint16_t scan_window;
uint8_t filter_policy;
uint8_t peer_addr_type;
uint8_t peer_addr[BLE_DEV_ADDR_LEN];
uint8_t own_addr_type;
uint16_t conn_itvl_min;
uint16_t conn_itvl_max;
uint16_t conn_latency;
uint16_t supervision_timeout;
uint16_t min_ce_len;
uint16_t max_ce_len;
};
void ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm);
void ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
void ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om,
uint8_t hdr_byte, uint8_t length);
struct ble_ll_conn_sm *ble_ll_conn_sm_get(void);
void ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
struct hci_create_conn *hcc);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
void ble_ll_conn_ext_master_init(struct ble_ll_conn_sm *connsm,
struct hci_ext_create_conn *hcc);
void ble_ll_conn_ext_set_params(struct ble_ll_conn_sm *connsm,
struct hci_ext_conn_params *hcc_params,
int phy);
#endif
struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle);
void ble_ll_conn_update_eff_data_len(struct ble_ll_conn_sm *connsm);
/* Advertising interface */
int ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat,
struct ble_mbuf_hdr *rxhdr, bool force_csa2);
/* Link Layer interface */
void ble_ll_conn_module_init(void);
void ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap);
void ble_ll_conn_module_reset(void);
void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len);
int ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa);
int ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr);
void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr);
void ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf,
struct ble_mbuf_hdr *ble_hdr);
int ble_ll_init_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *ble_hdr);
int ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
struct ble_mbuf_hdr *ble_hdr);
void ble_ll_conn_wfr_timer_exp(void);
void ble_ll_conn_init_wfr_timer_exp(void);
int ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2);
uint32_t ble_ll_conn_get_ce_end_time(void);
void ble_ll_conn_event_halt(void);
void ble_ll_conn_reset_pending_aux_conn_rsp(void);
bool ble_ll_conn_init_pending_aux_conn_rsp(void);
/* HCI */
void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm,
uint8_t reason);
void ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm *connsm);
int ble_ll_conn_hci_disconnect_cmd(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_rd_rem_ver_cmd(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb);
void ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm);
void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status,
uint8_t *evbuf, struct ble_ll_adv_sm *advsm);
void ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
int ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max,
uint16_t latency, uint16_t spvn_tmo);
int ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_rd_rssi(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf,
uint8_t *rsplen);
int ble_ll_conn_hci_rd_chan_map(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_set_data_len(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_le_start_encrypt(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_le_ltk_reply(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_le_ltk_neg_reply(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_wr_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_rd_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
void ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm);
#else
#define ble_ll_conn_auth_pyld_timer_start(x)
#endif
int ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg);
int ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg);
int ble_ll_conn_hci_le_rd_phy(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rsp, uint8_t *rsplen);
int ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *connsm);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
int ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t cmdlen);
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
int ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len);
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_CONN_PRIV_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,726 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 "syscfg/syscfg.h"
#include "sysinit/sysinit.h"
#if MYNEWT_VAL(BLE_LL_DTM)
#include <assert.h>
#include "os/os.h"
#include "stats/stats.h"
#include "controller/ble_ll.h"
#include "controller/ble_phy.h"
#include "controller/ble_ll_sched.h"
#include "controller/ble_ll_rfmgmt.h"
#include "ble_ll_dtm_priv.h"
STATS_SECT_START(ble_ll_dtm_stats)
STATS_SECT_ENTRY(rx_count)
STATS_SECT_ENTRY(tx_failed)
STATS_SECT_ENTRY(rx_failed)
STATS_SECT_END
STATS_SECT_DECL(ble_ll_dtm_stats) ble_ll_dtm_stats;
STATS_NAME_START(ble_ll_dtm_stats)
STATS_NAME(ble_ll_dtm_stats, rx_count)
STATS_NAME(ble_ll_dtm_stats, tx_failed)
STATS_NAME(ble_ll_dtm_stats, rx_failed)
STATS_NAME_END(ble_phy_stats)
struct dtm_ctx {
uint8_t payload_packet;
uint8_t itvl_rem_usec;
uint16_t num_of_packets;
uint32_t itvl_ticks;
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
uint16_t num_of_packets_max;
#endif
int active;
uint8_t rf_channel;
uint8_t phy_mode;
struct os_mbuf *om;
struct ble_npl_event evt;
struct ble_ll_sched_item sch;
uint32_t pdu_start_ticks;
uint8_t pdu_start_usecs;
};
static struct dtm_ctx g_ble_ll_dtm_ctx;
static const uint8_t g_ble_ll_dtm_prbs9_data[] =
{
0xff, 0xc1, 0xfb, 0xe8, 0x4c, 0x90, 0x72, 0x8b,
0xe7, 0xb3, 0x51, 0x89, 0x63, 0xab, 0x23, 0x23,
0x02, 0x84, 0x18, 0x72, 0xaa, 0x61, 0x2f, 0x3b,
0x51, 0xa8, 0xe5, 0x37, 0x49, 0xfb, 0xc9, 0xca,
0x0c, 0x18, 0x53, 0x2c, 0xfd, 0x45, 0xe3, 0x9a,
0xe6, 0xf1, 0x5d, 0xb0, 0xb6, 0x1b, 0xb4, 0xbe,
0x2a, 0x50, 0xea, 0xe9, 0x0e, 0x9c, 0x4b, 0x5e,
0x57, 0x24, 0xcc, 0xa1, 0xb7, 0x59, 0xb8, 0x87,
0xff, 0xe0, 0x7d, 0x74, 0x26, 0x48, 0xb9, 0xc5,
0xf3, 0xd9, 0xa8, 0xc4, 0xb1, 0xd5, 0x91, 0x11,
0x01, 0x42, 0x0c, 0x39, 0xd5, 0xb0, 0x97, 0x9d,
0x28, 0xd4, 0xf2, 0x9b, 0xa4, 0xfd, 0x64, 0x65,
0x06, 0x8c, 0x29, 0x96, 0xfe, 0xa2, 0x71, 0x4d,
0xf3, 0xf8, 0x2e, 0x58, 0xdb, 0x0d, 0x5a, 0x5f,
0x15, 0x28, 0xf5, 0x74, 0x07, 0xce, 0x25, 0xaf,
0x2b, 0x12, 0xe6, 0xd0, 0xdb, 0x2c, 0xdc, 0xc3,
0x7f, 0xf0, 0x3e, 0x3a, 0x13, 0xa4, 0xdc, 0xe2,
0xf9, 0x6c, 0x54, 0xe2, 0xd8, 0xea, 0xc8, 0x88,
0x00, 0x21, 0x86, 0x9c, 0x6a, 0xd8, 0xcb, 0x4e,
0x14, 0x6a, 0xf9, 0x4d, 0xd2, 0x7e, 0xb2, 0x32,
0x03, 0xc6, 0x14, 0x4b, 0x7f, 0xd1, 0xb8, 0xa6,
0x79, 0x7c, 0x17, 0xac, 0xed, 0x06, 0xad, 0xaf,
0x0a, 0x94, 0x7a, 0xba, 0x03, 0xe7, 0x92, 0xd7,
0x15, 0x09, 0x73, 0xe8, 0x6d, 0x16, 0xee, 0xe1,
0x3f, 0x78, 0x1f, 0x9d, 0x09, 0x52, 0x6e, 0xf1,
0x7c, 0x36, 0x2a, 0x71, 0x6c, 0x75, 0x64, 0x44,
0x80, 0x10, 0x43, 0x4e, 0x35, 0xec, 0x65, 0x27,
0x0a, 0xb5, 0xfc, 0x26, 0x69, 0x3f, 0x59, 0x99,
0x01, 0x63, 0x8a, 0xa5, 0xbf, 0x68, 0x5c, 0xd3,
0x3c, 0xbe, 0x0b, 0xd6, 0x76, 0x83, 0xd6, 0x57,
0x05, 0x4a, 0x3d, 0xdd, 0x81, 0x73, 0xc9, 0xeb,
0x8a, 0x84, 0x39, 0xf4, 0x36, 0x0b, 0xf7
};
static const uint8_t g_ble_ll_dtm_prbs15_data[] =
{
0xff, 0x7f, 0xf0, 0x3e, 0x3a, 0x13, 0xa4, 0xdc,
0xe2, 0xf9, 0x6c, 0x54, 0xe2, 0xd8, 0xea, 0xc8,
0x88, 0x00, 0x21, 0x86, 0x9c, 0x6a, 0xd8, 0xcb,
0x4e, 0x14, 0x6a, 0xf9, 0x4d, 0xd2, 0x7e, 0xb2,
0x32, 0x03, 0xc6, 0x14, 0x4b, 0x7f, 0xd1, 0xb8,
0xa6, 0x79, 0x7c, 0x17, 0xac, 0xed, 0x06, 0xad,
0xaf, 0x0a, 0x94, 0x7a, 0xba, 0x03, 0xe7, 0x92,
0xd7, 0x15, 0x09, 0x73, 0xe8, 0x6d, 0x16, 0xee,
0xe1, 0x3f, 0x78, 0x1f, 0x9d, 0x09, 0x52, 0x6e,
0xf1, 0x7c, 0x36, 0x2a, 0x71, 0x6c, 0x75, 0x64,
0x44, 0x80, 0x10, 0x43, 0x4e, 0x35, 0xec, 0x65,
0x27, 0x0a, 0xb5, 0xfc, 0x26, 0x69, 0x3f, 0x59,
0x99, 0x01, 0x63, 0x8a, 0xa5, 0xbf, 0x68, 0x5c,
0xd3, 0x3c, 0xbe, 0x0b, 0xd6, 0x76, 0x83, 0xd6,
0x57, 0x05, 0x4a, 0x3d, 0xdd, 0x81, 0x73, 0xc9,
0xeb, 0x8a, 0x84, 0x39, 0xf4, 0x36, 0x0b, 0xf7,
0xf0, 0x1f, 0xbc, 0x8f, 0xce, 0x04, 0x29, 0xb7,
0x78, 0x3e, 0x1b, 0x95, 0x38, 0xb6, 0x3a, 0x32,
0x22, 0x40, 0x88, 0x21, 0xa7, 0x1a, 0xf6, 0xb2,
0x13, 0x85, 0x5a, 0x7e, 0x93, 0xb4, 0x9f, 0xac,
0xcc, 0x80, 0x31, 0xc5, 0xd2, 0x5f, 0x34, 0xae,
0x69, 0x1e, 0xdf, 0x05, 0x6b, 0xbb, 0x41, 0xeb,
0xab, 0x02, 0xa5, 0x9e, 0xee, 0xc0, 0xb9, 0xe4,
0x75, 0x45, 0xc2, 0x1c, 0x7a, 0x9b, 0x85, 0x7b,
0xf8, 0x0f, 0xde, 0x47, 0x67, 0x82, 0x94, 0x5b,
0x3c, 0x9f, 0x8d, 0x4a, 0x1c, 0x5b, 0x1d, 0x19,
0x11, 0x20, 0xc4, 0x90, 0x53, 0x0d, 0x7b, 0xd9,
0x89, 0x42, 0x2d, 0xbf, 0x49, 0xda, 0x4f, 0x56,
0x66, 0xc0, 0x98, 0x62, 0xe9, 0x2f, 0x1a, 0xd7,
0x34, 0x8f, 0xef, 0x82, 0xb5, 0xdd, 0xa0, 0xf5,
0x55, 0x81, 0x52, 0x4f, 0x77, 0xe0, 0x5c, 0xf2,
0xba, 0x22, 0x61, 0x0e, 0xbd, 0xcd, 0xc2
};
static const uint8_t channel_rf_to_index[] = {
37, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 38, 11 ,12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 39
};
#define BLE_DTM_SYNC_WORD (0x71764129)
#define BLE_DTM_CRC (0x555555)
static void ble_ll_dtm_ctx_free(struct dtm_ctx * ctx);
static void
ble_ll_dtm_set_next(struct dtm_ctx *ctx)
{
struct ble_ll_sched_item *sch = &ctx->sch;
ctx->pdu_start_ticks += ctx->itvl_ticks;
ctx->pdu_start_usecs += ctx->itvl_rem_usec;
if (ctx->pdu_start_usecs >= 31) {
ctx->pdu_start_ticks++;
ctx->pdu_start_usecs -= 31;
}
sch->start_time = ctx->pdu_start_ticks;
sch->remainder = ctx->pdu_start_usecs;
sch->start_time -= g_ble_ll_sched_offset_ticks;
}
static void
ble_ll_dtm_ev_tx_resched_cb(struct ble_npl_event *evt) {
/* It is called in LL context */
struct dtm_ctx *ctx = ble_npl_event_get_arg(evt);
int rc;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
if (!ctx->active || !ctx->om) {
OS_EXIT_CRITICAL(sr);
return;
}
OS_EXIT_CRITICAL(sr);
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
if (g_ble_ll_dtm_ctx.num_of_packets_max &&
(g_ble_ll_dtm_ctx.num_of_packets == g_ble_ll_dtm_ctx.num_of_packets_max)) {
/*
* XXX do not send more packets, but also do not stop DTM - it shall be
* stopped as usual by HCI command since there is no standard way to
* signal end of test to host.
*/
return;
}
#endif
ble_ll_dtm_set_next(ctx);
rc = ble_ll_sched_dtm(&ctx->sch);
BLE_LL_ASSERT(rc == 0);
}
static int ble_ll_dtm_rx_start(void);
static void
ble_ll_dtm_ev_rx_restart_cb(struct ble_npl_event *evt) {
if (ble_ll_dtm_rx_start() != 0) {
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt);
STATS_INC(ble_ll_dtm_stats, rx_failed);
}
}
static void
ble_ll_dtm_tx_done(void *arg)
{
struct dtm_ctx *ctx;
ctx = arg;
if (!ctx->active) {
return;
}
g_ble_ll_dtm_ctx.num_of_packets++;
/* Reschedule event in LL context */
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt);
ble_ll_state_set(BLE_LL_STATE_STANDBY);
}
static int
ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch)
{
struct dtm_ctx *ctx = sch->cb_arg;
int rc;
if (!ctx->active) {
return BLE_LL_SCHED_STATE_DONE;
}
rc = ble_phy_setchan(channel_rf_to_index[ctx->rf_channel],
BLE_DTM_SYNC_WORD, BLE_DTM_CRC);
if (rc != 0) {
BLE_LL_ASSERT(0);
return BLE_LL_SCHED_STATE_DONE;
}
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY))
ble_phy_mode_set(ctx->phy_mode, ctx->phy_mode);
#endif
ble_phy_set_txend_cb(ble_ll_dtm_tx_done, ctx);
ble_phy_txpwr_set(0);
sch->start_time += g_ble_ll_sched_offset_ticks;
rc = ble_phy_tx_set_start_time(sch->start_time, sch->remainder);
if (rc) {
goto resched;
}
rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, ctx->om, BLE_PHY_TRANSITION_NONE);
if (rc) {
goto resched;
}
ble_ll_state_set(BLE_LL_STATE_DTM);
return BLE_LL_SCHED_STATE_DONE;
resched:
/* Reschedule from LL task if late for this PDU */
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt);
STATS_INC(ble_ll_dtm_stats, tx_failed);
return BLE_LL_SCHED_STATE_DONE;
}
static void
ble_ll_dtm_calculate_itvl(struct dtm_ctx *ctx, uint8_t len,
uint16_t cmd_interval, int phy_mode)
{
uint32_t l;
uint32_t itvl_usec;
uint32_t itvl_ticks;
/* Calculate interval as per spec Bluetooth 5.0 Vol 6. Part F, 4.1.6 */
l = ble_ll_pdu_tx_time_get(len + BLE_LL_PDU_HDR_LEN, phy_mode);
itvl_usec = ((l + 249 + 624) / 625) * 625;
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
if (cmd_interval > itvl_usec) {
itvl_usec = cmd_interval;
}
#endif
itvl_ticks = os_cputime_usecs_to_ticks(itvl_usec);
ctx->itvl_rem_usec = (itvl_usec - os_cputime_ticks_to_usecs(itvl_ticks));
if (ctx->itvl_rem_usec == 31) {
ctx->itvl_rem_usec = 0;
++itvl_ticks;
}
ctx->itvl_ticks = itvl_ticks;
}
static int
ble_ll_dtm_tx_create_ctx(uint8_t packet_payload, uint8_t len,
uint8_t rf_channel, uint8_t phy_mode,
uint16_t cmd_interval, uint16_t cmd_pkt_count)
{
int rc = 0;
uint8_t byte_pattern;
struct ble_mbuf_hdr *ble_hdr;
struct os_mbuf *m;
struct dtm_ctx *ctx = &g_ble_ll_dtm_ctx;
struct ble_ll_sched_item *sch = &ctx->sch;
/* MSYS is big enough to get continues memory */
m = os_msys_get_pkthdr(len, sizeof(struct ble_mbuf_hdr));
ctx->om = m;
BLE_LL_ASSERT(g_ble_ll_dtm_ctx.om);
ctx->phy_mode = phy_mode;
ctx->rf_channel = rf_channel;
ctx->num_of_packets = 0;
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
ctx->num_of_packets_max = cmd_pkt_count;
#endif
/* Set BLE transmit header */
ble_hdr = BLE_MBUF_HDR_PTR(m);
ble_hdr->txinfo.flags = 0;
ble_hdr->txinfo.offset = 0;
ble_hdr->txinfo.pyld_len = len;
ble_hdr->txinfo.hdr_byte = packet_payload;
switch(packet_payload) {
case 0x00:
if (os_mbuf_copyinto(m, 0, &g_ble_ll_dtm_prbs9_data, len)) {
return 1;
}
goto schedule;
case 0x01:
byte_pattern = 0x0F;
break;
case 0x02:
byte_pattern = 0x55;
break;
case 0x03:
if (os_mbuf_copyinto(m, 0, &g_ble_ll_dtm_prbs15_data, len)) {
return 1;
}
goto schedule;
case 0x04:
byte_pattern = 0xFF;
break;
case 0x05:
byte_pattern = 0x00;
break;
case 0x06:
byte_pattern = 0xF0;
break;
case 0x07:
byte_pattern = 0xAA;
break;
default:
return 1;
}
for (rc = 0; rc < len; rc++) {
if (os_mbuf_copyinto(m, rc, &byte_pattern, 1)) {
return 1;
}
}
schedule:
ble_phy_enable_dtm();
sch->sched_cb = ble_ll_dtm_tx_sched_cb;
sch->cb_arg = ctx;
sch->sched_type = BLE_LL_SCHED_TYPE_DTM;
/* Prepare os_event */
ble_npl_event_init(&ctx->evt, ble_ll_dtm_ev_tx_resched_cb, ctx);
ble_ll_dtm_calculate_itvl(ctx, len, cmd_interval, phy_mode);
ctx->pdu_start_ticks = ble_ll_rfmgmt_enable_now();
ctx->pdu_start_usecs = 0;
ble_ll_dtm_set_next(ctx);
/* Set some start point for TX packets */
rc = ble_ll_sched_dtm(sch);
BLE_LL_ASSERT(rc == 0);
g_ble_ll_dtm_ctx.active = 1;
return 0;
}
static int
ble_ll_dtm_rx_start(void)
{
os_sr_t sr;
int rc;
rc = ble_phy_setchan(channel_rf_to_index[g_ble_ll_dtm_ctx.rf_channel],
BLE_DTM_SYNC_WORD, BLE_DTM_CRC);
if (rc) {
return rc;
}
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY))
ble_phy_mode_set(g_ble_ll_dtm_ctx.phy_mode, g_ble_ll_dtm_ctx.phy_mode);
#endif
OS_ENTER_CRITICAL(sr);
rc = ble_phy_rx_set_start_time(os_cputime_get32(), 0);
OS_EXIT_CRITICAL(sr);
if (rc && rc != BLE_PHY_ERR_RX_LATE) {
return rc;
}
ble_ll_state_set(BLE_LL_STATE_DTM);
return 0;
}
static int
ble_ll_dtm_rx_sched_cb(struct ble_ll_sched_item *sch)
{
if (ble_ll_dtm_rx_start() != 0) {
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt);
STATS_INC(ble_ll_dtm_stats, rx_failed);
}
return BLE_LL_SCHED_STATE_DONE;
}
static int
ble_ll_dtm_rx_create_ctx(uint8_t rf_channel, uint8_t phy_mode)
{
struct ble_ll_sched_item *sch = &g_ble_ll_dtm_ctx.sch;
int rc;
g_ble_ll_dtm_ctx.phy_mode = phy_mode;
g_ble_ll_dtm_ctx.rf_channel = rf_channel;
STATS_CLEAR(ble_ll_dtm_stats, rx_count);
ble_npl_event_init(&g_ble_ll_dtm_ctx.evt, ble_ll_dtm_ev_rx_restart_cb,
NULL);
sch->sched_cb = ble_ll_dtm_rx_sched_cb;
sch->cb_arg = &g_ble_ll_dtm_ctx;
sch->sched_type = BLE_LL_SCHED_TYPE_DTM;
sch->start_time = ble_ll_rfmgmt_enable_now();
rc = ble_ll_sched_dtm(sch);
BLE_LL_ASSERT(rc == 0);
ble_phy_enable_dtm();
g_ble_ll_dtm_ctx.active = 1;
return 0;
}
static void
ble_ll_dtm_ctx_free(struct dtm_ctx * ctx)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
if (!ctx->active) {
OS_EXIT_CRITICAL(sr);
return;
}
ble_ll_sched_rmv_elem(&ctx->sch);
ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt);
ble_phy_disable();
ble_phy_disable_dtm();
ble_ll_state_set(BLE_LL_STATE_STANDBY);
ble_ll_rfmgmt_release();
os_mbuf_free_chain(ctx->om);
memset(ctx, 0, sizeof(*ctx));
OS_EXIT_CRITICAL(sr);
}
static int
ble_ll_dtm_tx_test(uint8_t tx_chan, uint8_t len, uint8_t packet_payload,
uint8_t hci_phy, uint16_t interval, uint16_t pkt_count)
{
uint8_t phy_mode;
if (g_ble_ll_dtm_ctx.active) {
return BLE_ERR_CTLR_BUSY;
}
switch (hci_phy) {
case BLE_HCI_LE_PHY_1M:
phy_mode = BLE_PHY_MODE_1M;
break;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
case BLE_HCI_LE_PHY_2M:
phy_mode = BLE_PHY_MODE_2M;
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
case BLE_HCI_LE_PHY_CODED_S8:
phy_mode = BLE_PHY_MODE_CODED_125KBPS;
break;
case BLE_HCI_LE_PHY_CODED_S2:
phy_mode = BLE_PHY_MODE_CODED_500KBPS;
break;
#endif
default:
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (tx_chan > 0x27 || packet_payload > 0x07) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (ble_ll_dtm_tx_create_ctx(packet_payload, len, tx_chan, phy_mode,
interval, pkt_count)) {
return BLE_ERR_UNSPECIFIED;
}
return BLE_ERR_SUCCESS;
}
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
static int
ble_ll_hci_dtm_tx_test_ext(const uint8_t *cmdbuf)
{
const struct ble_hci_le_tx_test_ext_cp *cmd = (const void *) cmdbuf;
return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload,
BLE_HCI_LE_PHY_1M, le16toh(cmd->interval),
le16toh(cmd->pkt_count));
}
static int
ble_ll_hci_dtm_tx_test_v2_ext(const uint8_t *cmdbuf)
{
const struct ble_hci_le_tx_test_v2_ext_cp *cmd = (const void *) cmdbuf;
return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload,
cmd->phy, le16toh(cmd->interval),
le16toh(cmd->pkt_count));
}
#endif
int
ble_ll_hci_dtm_tx_test(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_tx_test_cp *cmd = (const void *) cmdbuf;
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
if (len == sizeof(struct ble_hci_le_tx_test_ext_cp)) {
return ble_ll_hci_dtm_tx_test_ext(cmdbuf);
}
#endif
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload,
BLE_HCI_LE_PHY_1M, 0, 0);
}
int
ble_ll_hci_dtm_tx_test_v2(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_tx_test_v2_cp *cmd = (const void *) cmdbuf;
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
if (len == sizeof(struct ble_hci_le_tx_test_v2_ext_cp)) {
return ble_ll_hci_dtm_tx_test_v2_ext(cmdbuf);
}
#endif
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload,
cmd->phy, 0, 0);
}
static int
ble_ll_dtm_rx_test(uint8_t rx_chan, uint8_t hci_phy)
{
uint8_t phy_mode;
if (g_ble_ll_dtm_ctx.active) {
return BLE_ERR_CTLR_BUSY;
}
switch (hci_phy) {
case BLE_HCI_LE_PHY_1M:
phy_mode = BLE_PHY_MODE_1M;
break;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
case BLE_HCI_LE_PHY_2M:
phy_mode = BLE_PHY_MODE_2M;
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
case BLE_HCI_LE_PHY_CODED:
phy_mode = BLE_PHY_MODE_CODED_500KBPS;
break;
#endif
default:
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (rx_chan > 0x27) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (ble_ll_dtm_rx_create_ctx(rx_chan, phy_mode)) {
return BLE_ERR_UNSPECIFIED;
}
return BLE_ERR_SUCCESS;
}
int ble_ll_hci_dtm_rx_test(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_rx_test_cp *cmd = (const void *) cmdbuf;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
return ble_ll_dtm_rx_test(cmd->rx_chan, BLE_HCI_LE_PHY_1M);
}
int ble_ll_hci_dtm_rx_test_v2(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_rx_test_v2_cp *cmd = (const void *) cmdbuf;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* TODO ignoring modulation index */
return ble_ll_dtm_rx_test(cmd->rx_chan, cmd->phy);
}
int ble_ll_dtm_end_test(uint8_t *rsp, uint8_t *rsplen)
{
put_le16(rsp, g_ble_ll_dtm_ctx. num_of_packets);
*rsplen = 2;
ble_ll_dtm_ctx_free(&g_ble_ll_dtm_ctx);
return BLE_ERR_SUCCESS;
}
int ble_ll_dtm_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa)
{
return 0;
}
void
ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
{
if (BLE_MBUF_HDR_CRC_OK(hdr)) {
/* XXX Compare data. */
g_ble_ll_dtm_ctx.num_of_packets++;
STATS_INC(ble_ll_dtm_stats, rx_count);
}
if (ble_ll_dtm_rx_start() != 0) {
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt);
STATS_INC(ble_ll_dtm_stats, rx_failed);
}
}
int
ble_ll_dtm_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
{
struct os_mbuf *rxpdu;
if (!g_ble_ll_dtm_ctx.active) {
return -1;
}
rxpdu = ble_ll_rxpdu_alloc(rxbuf[1] + BLE_LL_PDU_HDR_LEN);
/* Copy the received pdu and hand it up */
if (rxpdu) {
ble_phy_rxpdu_copy(rxbuf, rxpdu);
ble_ll_rx_pdu_in(rxpdu);
}
return 0;
}
void
ble_ll_dtm_wfr_timer_exp(void)
{
/* Should not be needed */
BLE_LL_ASSERT(0);
}
void
ble_ll_dtm_reset(void)
{
ble_ll_dtm_ctx_free(&g_ble_ll_dtm_ctx);
}
void
ble_ll_dtm_init(void)
{
int rc;
rc = stats_init_and_reg(STATS_HDR(ble_ll_dtm_stats),
STATS_SIZE_INIT_PARMS(ble_ll_dtm_stats, STATS_SIZE_32),
STATS_NAME_INIT_PARMS(ble_ll_dtm_stats),
"ble_ll_dtm");
SYSINIT_PANIC_ASSERT(rc == 0);
}
#endif

View File

@@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_TEST_PRIV_
#define H_BLE_LL_TEST_PRIV_
#include <stdint.h>
#include <stdbool.h>
#include "nimble/ble.h"
int ble_ll_hci_dtm_tx_test(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_hci_dtm_tx_test_v2(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_hci_dtm_rx_test(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_hci_dtm_rx_test_v2(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_dtm_end_test(uint8_t *rsp, uint8_t *rsplen);
int ble_ll_dtm_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa);
int ble_ll_dtm_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr);
void ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr);
void ble_ll_dtm_wfr_timer_exp(void);
void ble_ll_dtm_reset(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,522 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include <string.h>
#include "syscfg/syscfg.h"
#include "nimble/ble.h"
#include "nimble/hci_common.h"
#include "nimble/ble_hci_trans.h"
#include "controller/ble_ll.h"
#include "controller/ble_ll_hci.h"
#include "controller/ble_ll_ctrl.h"
#include "ble_ll_conn_priv.h"
#if (BLETEST_CONCURRENT_CONN_TEST == 1)
extern void bletest_ltk_req_reply(uint16_t handle);
#endif
/**
* Send a data length change event for a connection to the host.
*
* @param connsm Pointer to connection state machine
*/
void
ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm)
{
struct ble_hci_ev_le_subev_data_len_chg *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_DATA_LEN_CHG)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_DATA_LEN_CHG;
ev->conn_handle = htole16(connsm->conn_handle);
ev->max_tx_octets = htole16(connsm->eff_max_tx_octets);
ev->max_tx_time = htole16(connsm->eff_max_tx_time);
ev->max_rx_octets = htole16(connsm->eff_max_rx_octets);
ev->max_rx_time = htole16(connsm->eff_max_rx_time);
ble_ll_hci_event_send(hci_ev);
}
}
}
/**
* Send a connection parameter request event for a connection to the host.
*
* @param connsm Pointer to connection state machine
*/
void
ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm,
struct ble_ll_conn_params *cp)
{
struct ble_hci_ev_le_subev_rem_conn_param_req *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ;
ev->conn_handle = htole16(connsm->conn_handle);
ev->min_interval = htole16(cp->interval_min);
ev->max_interval = htole16(cp->interval_max);
ev->latency = htole16(cp->latency);
ev->timeout = htole16(cp->timeout);
ble_ll_hci_event_send(hci_ev);
}
}
}
/**
* Send a connection update event.
*
* @param connsm Pointer to connection state machine
* @param status The error code.
*/
void
ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status)
{
struct ble_hci_ev_le_subev_conn_upd_complete *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE;
ev->status = status;
ev->conn_handle = htole16(connsm->conn_handle);
ev->conn_itvl = htole16(connsm->conn_itvl);
ev->conn_latency = htole16(connsm->slave_latency);
ev->supervision_timeout = htole16(connsm->supervision_tmo);
ble_ll_hci_event_send(hci_ev);
}
}
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
void
ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status)
{
struct ble_hci_ev_enc_key_refresh *ev_key_refresh;
struct ble_hci_ev_enrypt_chg *ev_enc_chf;
struct ble_hci_ev *hci_ev;
if (CONN_F_ENC_CHANGE_SENT(connsm) == 0) {
if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_ENCRYPT_CHG)) {
hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_ENCRYPT_CHG;
hci_ev->length = sizeof(*ev_enc_chf);
ev_enc_chf = (void *) hci_ev->data;
ev_enc_chf->status = status;
ev_enc_chf->connection_handle = htole16(connsm->conn_handle);
ev_enc_chf->enabled = (status == BLE_ERR_SUCCESS) ? 0x01 : 0x00;
ble_ll_hci_event_send(hci_ev);
}
}
CONN_F_ENC_CHANGE_SENT(connsm) = 1;
return;
}
if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_ENC_KEY_REFRESH)) {
hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_ENC_KEY_REFRESH;
hci_ev->length = sizeof(*ev_key_refresh);
ev_key_refresh = (void *) hci_ev->data;
ev_key_refresh->status = status;
ev_key_refresh->conn_handle = htole16(connsm->conn_handle);
ble_ll_hci_event_send(hci_ev);
}
}
}
/**
* Send a long term key request event for a connection to the host.
*
* @param connsm Pointer to connection state machine
*/
int
ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm)
{
struct ble_hci_ev_le_subev_lt_key_req *ev;
struct ble_hci_ev *hci_ev;
int rc;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_LT_KEY_REQ)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_LT_KEY_REQ;
ev->conn_handle = htole16(connsm->conn_handle);
ev->rand = htole64(connsm->enc_data.host_rand_num);
ev->div = htole16(connsm->enc_data.enc_div);
ble_ll_hci_event_send(hci_ev);
}
rc = 0;
} else {
rc = -1;
}
#if (BLETEST_CONCURRENT_CONN_TEST == 1)
if (rc == 0) {
bletest_ltk_req_reply(connsm->conn_handle);
}
#endif
return rc;
}
#endif
void
ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm, uint8_t status)
{
struct ble_hci_ev_le_subev_rd_rem_used_feat *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT;
ev->status = status;
ev->conn_handle = htole16(connsm->conn_handle);
ev->features[0] = connsm->conn_features;
memcpy(ev->features + 1, connsm->remote_features, 7);
ble_ll_hci_event_send(hci_ev);
}
}
}
void
ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status)
{
struct ble_hci_ev_rd_rem_ver_info_cmp *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->status = status;
ev->conn_handle = htole16(connsm->conn_handle);
ev->version = connsm->vers_nr;
ev->manufacturer = htole16(connsm->comp_id);
ev->subversion = htole16(connsm->sub_vers_nr);
ble_ll_hci_event_send(hci_ev);
}
}
}
/**
* Send a HW error to the host.
*
* @param hw_err
*
* @return int 0: event masked or event sent, -1 otherwise
*/
int
ble_ll_hci_ev_hw_err(uint8_t hw_err)
{
struct ble_hci_ev_hw_error *ev;
struct ble_hci_ev *hci_ev;
int rc;
rc = 0;
if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_HW_ERROR)) {
hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_HW_ERROR;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->hw_code = hw_err;
ble_ll_hci_event_send(hci_ev);
} else {
rc = -1;
}
}
return rc;
}
void
ble_ll_hci_ev_databuf_overflow(void)
{
struct ble_hci_ev_data_buf_overflow *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_DATA_BUF_OVERFLOW)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_DATA_BUF_OVERFLOW;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->link_type = BLE_HCI_EVENT_ACL_BUF_OVERFLOW;
ble_ll_hci_event_send(hci_ev);
}
}
}
/**
* Send a LE Channel Selection Algorithm event.
*
* @param connsm Pointer to connection state machine
*/
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2)
void
ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm)
{
struct ble_hci_ev_le_subev_chan_sel_alg *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CHAN_SEL_ALG)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_CHAN_SEL_ALG;
ev->conn_handle = htole16(connsm->conn_handle);
ev->csa = connsm->csmflags.cfbit.csa2_supp ? 0x01 : 0x00;
ble_ll_hci_event_send(hci_ev);
}
}
}
#endif
/**
* Sends the LE Scan Request Received event
*
*/
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
void
ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer,
uint8_t peer_addr_type)
{
struct ble_hci_ev_le_subev_scan_req_rcvd *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD;
ev->adv_handle = adv_handle;
ev->peer_addr_type = peer_addr_type;
memcpy(ev->peer_addr, peer, BLE_DEV_ADDR_LEN);
ble_ll_hci_event_send(hci_ev);
}
}
}
#endif
/**
* Sends the LE Scan Timeout Event
*
*/
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
void
ble_ll_hci_ev_send_scan_timeout(void)
{
struct ble_hci_ev_le_subev_scan_timeout *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_TIMEOUT)) {
hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_SCAN_TIMEOUT;
ble_ll_hci_event_send(hci_ev);
}
}
}
#endif
/**
* Sends the LE Advertising Set Terminated event
*
*/
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
void
ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle,
uint16_t conn_handle, uint8_t events)
{
struct ble_hci_ev_le_subev_adv_set_terminated *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED;
ev->status = status;
ev->adv_handle = adv_handle;
ev->conn_handle = htole16(conn_handle);
ev->num_events = events;
ble_ll_hci_event_send(hci_ev);
}
}
}
#endif
/**
* Send a PHY update complete event
*
* @param connsm Pointer to connection state machine
* @param status error status of event
*/
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
int
ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status)
{
struct ble_hci_ev_le_subev_phy_update_complete *ev;
struct ble_hci_ev *hci_ev;
int rc;
rc = 0;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE;
ev->status = status;
ev->conn_handle = htole16(connsm->conn_handle);
ev->tx_phy = connsm->phy_data.cur_tx_phy;
ev->rx_phy = connsm->phy_data.cur_rx_phy;
ble_ll_hci_event_send(hci_ev);
} else {
rc = BLE_ERR_MEM_CAPACITY;
}
}
return rc;
}
#endif
void
ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line)
{
struct ble_hci_ev_vendor_debug *ev;
struct ble_hci_ev *hci_ev;
unsigned int str_len;
bool skip = true;
uint8_t digit;
int max_len;
int i;
/* 6 is for line number ":00000" , we assume files have no more than 64k of
* lines
*/
max_len = BLE_HCI_MAX_DATA_LEN - sizeof(*ev) - 6;
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_VENDOR_DEBUG;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
/* Debug id for future use */
ev->id = 0x00;
/* snprintf would be nicer but this is heavy on flash
* len = snprintf((char *) ev->data, max_len, "%s:%u", file, line);
* if (len < 0) {
* len = 0;
* } else if (len > max_len) {
* len = max_len;
* }
*
* hci_ev->length += len;
*/
str_len = strlen(file);
if (str_len > max_len) {
str_len = max_len;
}
memcpy(ev->data, file, str_len);
ev->data[str_len++] = ':';
for (i = 100000; i >= 10; i /= 10) {
digit = (line % i) / (i/10);
if (!digit && skip) {
continue;
}
skip = false;
ev->data[str_len++] = '0' + digit;
}
hci_ev->length += str_len;
ble_ll_hci_event_send(hci_ev);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_PRIV_
#define H_BLE_LL_PRIV_
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MYNEWT
#include "syscfg/syscfg.h"
#include "hal/hal_gpio.h"
#define BLE_LL_DEBUG_GPIO_INIT(_name) \
if (MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name) >= 0) { \
hal_gpio_init_out(MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name), 0); \
}
#define BLE_LL_DEBUG_GPIO(_name, _val) \
if (MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name) >= 0) { \
hal_gpio_write(MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name), !!(_val)); \
}
#else
#define BLE_LL_DEBUG_GPIO_INIT(_name) (void)(0)
#define BLE_LL_DEBUG_GPIO(_name, _val) (void)(0)
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_PRIV_ */

View File

@@ -0,0 +1,185 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include <string.h>
#include "syscfg/syscfg.h"
#include "os/os.h"
#include "nimble/ble.h"
#include "nimble/nimble_opt.h"
#include "controller/ble_hw.h"
#include "controller/ble_ll.h"
#if MYNEWT_VAL(TRNG)
#include "trng/trng.h"
#endif
#if MYNEWT_VAL(TRNG)
static struct trng_dev *g_trng;
#else
/* This is a simple circular buffer for holding N samples of random data */
struct ble_ll_rnum_data
{
uint8_t *rnd_in;
uint8_t *rnd_out;
volatile uint8_t rnd_size;
};
struct ble_ll_rnum_data g_ble_ll_rnum_data;
uint8_t g_ble_ll_rnum_buf[MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)];
#define IS_RNUM_BUF_END(x) \
(x == &g_ble_ll_rnum_buf[MYNEWT_VAL(BLE_LL_RNG_BUFSIZE) - 1])
void
ble_ll_rand_sample(uint8_t rnum)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
if (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)) {
++g_ble_ll_rnum_data.rnd_size;
g_ble_ll_rnum_data.rnd_in[0] = rnum;
if (IS_RNUM_BUF_END(g_ble_ll_rnum_data.rnd_in)) {
g_ble_ll_rnum_data.rnd_in = g_ble_ll_rnum_buf;
} else {
++g_ble_ll_rnum_data.rnd_in;
}
} else {
/* Stop generating random numbers as we are full */
ble_hw_rng_stop();
}
OS_EXIT_CRITICAL(sr);
}
#endif
/* Get 'len' bytes of random data */
int
ble_ll_rand_data_get(uint8_t *buf, uint8_t len)
{
#if MYNEWT_VAL(TRNG)
size_t num;
while (len) {
num = trng_read(g_trng, buf, len);
buf += num;
len -= num;
}
#else
uint8_t rnums;
os_sr_t sr;
while (len != 0) {
OS_ENTER_CRITICAL(sr);
rnums = g_ble_ll_rnum_data.rnd_size;
if (rnums > len) {
rnums = len;
}
len -= rnums;
g_ble_ll_rnum_data.rnd_size -= rnums;
while (rnums) {
buf[0] = g_ble_ll_rnum_data.rnd_out[0];
if (IS_RNUM_BUF_END(g_ble_ll_rnum_data.rnd_out)) {
g_ble_ll_rnum_data.rnd_out = g_ble_ll_rnum_buf;
} else {
++g_ble_ll_rnum_data.rnd_out;
}
++buf;
--rnums;
}
OS_EXIT_CRITICAL(sr);
/* Make sure rng is started! */
ble_hw_rng_start();
/* Wait till bytes are in buffer. */
if (len) {
while ((g_ble_ll_rnum_data.rnd_size < len) &&
(g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE))) {
/* Spin here */
}
}
}
#endif
return BLE_ERR_SUCCESS;
}
/**
* Called to obtain a "prand" as defined in core V4.2 Vol 6 Part B 1.3.2.2
*
* @param prand
*/
void
ble_ll_rand_prand_get(uint8_t *prand)
{
uint16_t sum;
while (1) {
/* Get 24 bits of random data */
ble_ll_rand_data_get(prand, 3);
/* Prand cannot be all zeros or 1's. */
sum = prand[0] + prand[1] + prand[2];
if ((sum != 0) && (sum != (3 * 0xff))) {
break;
}
}
/* Upper two bits must be 01 */
prand[2] &= ~0xc0;
prand[2] |= 0x40;
}
/**
* Start the generation of random numbers
*
* @return int
*/
int
ble_ll_rand_start(void)
{
#if MYNEWT_VAL(TRNG)
/* Nothing to do - this is handled by driver */
#else
/* Start the generation of numbers if we are not full */
if (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)) {
ble_hw_rng_start();
}
#endif
return 0;
}
/**
* Initialize LL random number generation. Should be called only once on
* initialization.
*
* @return int
*/
int
ble_ll_rand_init(void)
{
#if MYNEWT_VAL(TRNG)
g_trng = (struct trng_dev *) os_dev_open("trng", OS_TIMEOUT_NEVER, NULL);
#else
g_ble_ll_rnum_data.rnd_in = g_ble_ll_rnum_buf;
g_ble_ll_rnum_data.rnd_out = g_ble_ll_rnum_buf;
ble_hw_rng_init(ble_ll_rand_sample, 1);
#endif
return 0;
}

View File

@@ -0,0 +1,753 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include <string.h>
#include "syscfg/syscfg.h"
#include "os/os.h"
#include "nimble/ble.h"
#include "nimble/nimble_opt.h"
#include "controller/ble_ll.h"
#include "controller/ble_ll_resolv.h"
#include "controller/ble_ll_hci.h"
#include "controller/ble_ll_scan.h"
#include "controller/ble_ll_adv.h"
#include "controller/ble_ll_sync.h"
#include "controller/ble_hw.h"
#include "ble_ll_conn_priv.h"
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
struct ble_ll_resolv_data
{
uint8_t addr_res_enabled;
uint8_t rl_size;
uint8_t rl_cnt_hw;
uint8_t rl_cnt;
ble_npl_time_t rpa_tmo;
struct ble_npl_callout rpa_timer;
};
struct ble_ll_resolv_data g_ble_ll_resolv_data;
__attribute__((aligned(4)))
struct ble_ll_resolv_entry g_ble_ll_resolv_list[MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)];
static int
ble_ll_is_controller_busy(void)
{
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
if (ble_ll_sync_enabled()) {
return 1;
}
#endif
return ble_ll_adv_enabled() || ble_ll_scan_enabled() ||
g_ble_ll_conn_create_sm;
}
/**
* Called to determine if a change is allowed to the resolving list at this
* time. We are not allowed to modify the resolving list if address translation
* is enabled and we are either scanning, advertising, or attempting to create
* a connection.
*
* @return int 0: not allowed. 1: allowed.
*/
static int
ble_ll_resolv_list_chg_allowed(void)
{
int rc;
if (g_ble_ll_resolv_data.addr_res_enabled &&
ble_ll_is_controller_busy()) {
rc = 0;
} else {
rc = 1;
}
return rc;
}
/**
* Called to generate a resolvable private address in rl structure
*
* @param rl
* @param local
*/
static void
ble_ll_resolv_gen_priv_addr(struct ble_ll_resolv_entry *rl, int local)
{
uint8_t *irk;
uint8_t *prand;
struct ble_encryption_block ecb;
uint8_t *addr;
BLE_LL_ASSERT(rl != NULL);
if (local) {
addr = rl->rl_local_rpa;
irk = rl->rl_local_irk;
} else {
addr = rl->rl_peer_rpa;
irk = rl->rl_peer_irk;
}
/* Get prand */
prand = addr + 3;
ble_ll_rand_prand_get(prand);
/* Calculate hash, hash = ah(local IRK, prand) */
memcpy(ecb.key, irk, 16);
memset(ecb.plain_text, 0, 13);
ecb.plain_text[13] = prand[2];
ecb.plain_text[14] = prand[1];
ecb.plain_text[15] = prand[0];
/* Calculate hash */
ble_hw_encrypt_block(&ecb);
addr[0] = ecb.cipher_text[15];
addr[1] = ecb.cipher_text[14];
addr[2] = ecb.cipher_text[13];
}
/**
* Called when the Resolvable private address timer expires. This timer
* is used to regenerate local and peers RPA's in the resolving list.
*/
static void
ble_ll_resolv_rpa_timer_cb(struct ble_npl_event *ev)
{
int i;
os_sr_t sr;
struct ble_ll_resolv_entry *rl;
rl = &g_ble_ll_resolv_list[0];
for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) {
if (rl->rl_has_local) {
OS_ENTER_CRITICAL(sr);
ble_ll_resolv_gen_priv_addr(rl, 1);
OS_EXIT_CRITICAL(sr);
}
if (rl->rl_has_peer) {
OS_ENTER_CRITICAL(sr);
ble_ll_resolv_gen_priv_addr(rl, 0);
OS_EXIT_CRITICAL(sr);
}
++rl;
}
ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer,
g_ble_ll_resolv_data.rpa_tmo);
ble_ll_adv_rpa_timeout();
}
/**
* Called to determine if the IRK is all zero.
*
* @param irk
*
* @return int 0: IRK is zero . 1: IRK has non-zero value.
*/
static int
ble_ll_resolv_irk_nonzero(const uint8_t *irk)
{
int i;
int rc;
rc = 0;
for (i = 0; i < 16; ++i) {
if (*irk != 0) {
rc = 1;
break;
}
++irk;
}
return rc;
}
/**
* Clear the resolving list
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_ll_resolv_list_clr(void)
{
/* Check proper state */
if (!ble_ll_resolv_list_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Sets total on list to 0. Clears HW resolve list */
g_ble_ll_resolv_data.rl_cnt_hw = 0;
g_ble_ll_resolv_data.rl_cnt = 0;
ble_hw_resolv_list_clear();
/* stop RPA timer when clearing RL */
ble_npl_callout_stop(&g_ble_ll_resolv_data.rpa_timer);
return BLE_ERR_SUCCESS;
}
/**
* Read the size of the resolving list. This is the total number of resolving
* list entries allowed by the controller.
*
* @param rspbuf Pointer to response buffer
*
* @return int 0: success.
*/
int
ble_ll_resolv_list_read_size(uint8_t *rspbuf, uint8_t *rsplen)
{
struct ble_hci_le_rd_resolv_list_size_rp *rsp = (void *) rspbuf;
rsp->size = g_ble_ll_resolv_data.rl_size;
*rsplen = sizeof(*rsp);
return BLE_ERR_SUCCESS;
}
/**
* Used to determine if the device is on the resolving list.
*
* @param addr
* @param addr_type Public address (0) or random address (1)
*
* @return int 0: device is not on resolving list; otherwise the return value
* is the 'position' of the device in the resolving list (the index of the
* element plus 1).
*/
static int
ble_ll_is_on_resolv_list(const uint8_t *addr, uint8_t addr_type)
{
int i;
struct ble_ll_resolv_entry *rl;
rl = &g_ble_ll_resolv_list[0];
for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) {
if ((rl->rl_addr_type == addr_type) &&
(!memcmp(&rl->rl_identity_addr[0], addr, BLE_DEV_ADDR_LEN))) {
return i + 1;
}
++rl;
}
return 0;
}
/**
* Used to determine if the device is on the resolving list.
*
* @param addr
* @param addr_type Public address (0) or random address (1)
*
* @return Pointer to resolving list entry or NULL if no entry found.
*/
struct ble_ll_resolv_entry *
ble_ll_resolv_list_find(const uint8_t *addr, uint8_t addr_type)
{
int i;
struct ble_ll_resolv_entry *rl;
rl = &g_ble_ll_resolv_list[0];
for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) {
if ((rl->rl_addr_type == addr_type) &&
(!memcmp(&rl->rl_identity_addr[0], addr, BLE_DEV_ADDR_LEN))) {
return rl;
}
++rl;
}
return NULL;
}
/**
* Add a device to the resolving list
*
* @return int
*/
int
ble_ll_resolv_list_add(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_add_resolv_list_cp *cmd = (const void *) cmdbuf;
struct ble_ll_resolv_entry *rl;
int rc = BLE_ERR_SUCCESS;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* Must be in proper state */
if (!ble_ll_resolv_list_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Check if we have any open entries */
if (g_ble_ll_resolv_data.rl_cnt >= g_ble_ll_resolv_data.rl_size) {
return BLE_ERR_MEM_CAPACITY;
}
/* spec is not clear on how to handle this but make sure host is aware
* that new keys are not used in that case
*/
if (ble_ll_is_on_resolv_list(cmd->peer_id_addr, cmd->peer_addr_type)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* we keep this sorted in a way that entries with peer_irk are first */
if (ble_ll_resolv_irk_nonzero(cmd->peer_irk)) {
memmove(&g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt_hw + 1],
&g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt_hw],
(g_ble_ll_resolv_data.rl_cnt - g_ble_ll_resolv_data.rl_cnt_hw) *
sizeof(g_ble_ll_resolv_list[0]));
rl = &g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt_hw];
} else {
rl = &g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt];
}
memset (rl, 0, sizeof(*rl));
rl->rl_addr_type = cmd->peer_addr_type;
memcpy(rl->rl_identity_addr, cmd->peer_id_addr, BLE_DEV_ADDR_LEN);
if (ble_ll_resolv_irk_nonzero(cmd->peer_irk)) {
swap_buf(rl->rl_peer_irk, cmd->peer_irk, 16);
rl->rl_has_peer = 1;
/* generate peer RPA now, those will be updated by timer when
* resolution is enabled
*/
ble_ll_resolv_gen_priv_addr(rl, 0);
}
if (ble_ll_resolv_irk_nonzero(cmd->local_irk)) {
swap_buf(rl->rl_local_irk, cmd->local_irk, 16);
rl->rl_has_local = 1;
/* generate local RPA now, those will be updated by timer when
* resolution is enabled
*/
ble_ll_resolv_gen_priv_addr(rl, 1);
}
/* By default use privacy network mode */
rl->rl_priv_mode = BLE_HCI_PRIVACY_NETWORK;
/* Add peers IRKs to HW resolving list. Should always succeed since we
* already checked if there is room for it.
*/
if (rl->rl_has_peer) {
rc = ble_hw_resolv_list_add(rl->rl_peer_irk);
BLE_LL_ASSERT(rc == BLE_ERR_SUCCESS);
g_ble_ll_resolv_data.rl_cnt_hw++;
}
g_ble_ll_resolv_data.rl_cnt++;
/* start RPA timer if this was first element added to RL */
if (g_ble_ll_resolv_data.rl_cnt == 1) {
ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer,
g_ble_ll_resolv_data.rpa_tmo);
}
return rc;
}
/**
* Remove a device from the resolving list
*
* @param cmdbuf
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_ll_resolv_list_rmv(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_rmv_resolve_list_cp *cmd = (const void *) cmdbuf;
int position;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* Must be in proper state */
if (!ble_ll_resolv_list_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Remove from IRK records */
position = ble_ll_is_on_resolv_list(cmd->peer_id_addr, cmd->peer_addr_type);
if (position) {
BLE_LL_ASSERT(position <= g_ble_ll_resolv_data.rl_cnt);
memmove(&g_ble_ll_resolv_list[position - 1],
&g_ble_ll_resolv_list[position],
(g_ble_ll_resolv_data.rl_cnt - position) *
sizeof(g_ble_ll_resolv_list[0]));
g_ble_ll_resolv_data.rl_cnt--;
/* Remove from HW list */
if (position <= g_ble_ll_resolv_data.rl_cnt_hw) {
ble_hw_resolv_list_rmv(position - 1);
g_ble_ll_resolv_data.rl_cnt_hw--;
}
/* stop RPA timer if list is empty */
if (g_ble_ll_resolv_data.rl_cnt == 0) {
ble_npl_callout_stop(&g_ble_ll_resolv_data.rpa_timer);
}
return BLE_ERR_SUCCESS;
}
return BLE_ERR_UNK_CONN_ID;
}
/**
* Called to enable or disable address resolution in the controller
*
* @param cmdbuf
*
* @return int
*/
int
ble_ll_resolv_enable_cmd(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_set_addr_res_en_cp *cmd = (const void *) cmdbuf;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (ble_ll_is_controller_busy()) {
return BLE_ERR_CMD_DISALLOWED;
}
if (cmd->enable > 1) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
g_ble_ll_resolv_data.addr_res_enabled = cmd->enable;
return BLE_ERR_SUCCESS;
}
int
ble_ll_resolv_peer_addr_rd(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen)
{
const struct ble_hci_le_rd_peer_recolv_addr_cp *cmd = (const void *) cmdbuf;
struct ble_hci_le_rd_peer_recolv_addr_rp *rsp = (void *) rspbuf;
struct ble_ll_resolv_entry *rl;
int rc;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
rl = ble_ll_resolv_list_find(cmd->peer_id_addr, cmd->peer_addr_type);
if (rl) {
memcpy(rsp->rpa, rl->rl_peer_rpa, BLE_DEV_ADDR_LEN);
rc = BLE_ERR_SUCCESS;
} else {
memset(rsp->rpa, 0, BLE_DEV_ADDR_LEN);
rc = BLE_ERR_UNK_CONN_ID;
}
*rsplen = sizeof(*rsp);
return rc;
}
int
ble_ll_resolv_local_addr_rd(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen)
{
const struct ble_hci_le_rd_local_recolv_addr_cp *cmd = (const void *) cmdbuf;
struct ble_hci_le_rd_local_recolv_addr_rp *rsp = (void *) rspbuf;
struct ble_ll_resolv_entry *rl;
int rc;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
rl = ble_ll_resolv_list_find(cmd->peer_id_addr, cmd->peer_addr_type);
if (rl) {
memcpy(rsp->rpa, rl->rl_local_rpa, BLE_DEV_ADDR_LEN);
rc = BLE_ERR_SUCCESS;
} else {
memset(rsp->rpa, 0, BLE_DEV_ADDR_LEN);
rc = BLE_ERR_UNK_CONN_ID;
}
*rsplen = sizeof(*rsp);
return rc;
}
/**
* Set the resolvable private address timeout.
*
* @param cmdbuf
*
* @return int
*/
int
ble_ll_resolv_set_rpa_tmo(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_set_rpa_tmo_cp *cmd = (const void *)cmdbuf;
uint16_t tmo_secs;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
tmo_secs = le16toh(cmd->rpa_timeout);
if (!((tmo_secs > 0) && (tmo_secs <= 0xA1B8))) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
g_ble_ll_resolv_data.rpa_tmo = ble_npl_time_ms_to_ticks32(tmo_secs * 1000);
/* restart timer if there is something on RL */
if (g_ble_ll_resolv_data.rl_cnt) {
ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer,
g_ble_ll_resolv_data.rpa_tmo);
}
return BLE_ERR_SUCCESS;
}
int
ble_ll_resolve_set_priv_mode(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_set_privacy_mode_cp *cmd = (const void *) cmdbuf;
struct ble_ll_resolv_entry *rl;
if (ble_ll_is_controller_busy()) {
return BLE_ERR_CMD_DISALLOWED;
}
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
rl = ble_ll_resolv_list_find(cmd->peer_id_addr, cmd->peer_id_addr_type);
if (!rl) {
return BLE_ERR_UNK_CONN_ID;
}
if (cmd->mode > BLE_HCI_PRIVACY_DEVICE) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
rl->rl_priv_mode = cmd->mode;
return BLE_ERR_SUCCESS;
}
/**
* Returns the Resolvable Private address timeout, in os ticks
*
*
* @return uint32_t
*/
uint32_t
ble_ll_resolv_get_rpa_tmo(void)
{
return g_ble_ll_resolv_data.rpa_tmo;
}
void
ble_ll_resolv_get_priv_addr(struct ble_ll_resolv_entry *rl, int local,
uint8_t *addr)
{
os_sr_t sr;
BLE_LL_ASSERT(rl != NULL);
BLE_LL_ASSERT(addr != NULL);
OS_ENTER_CRITICAL(sr);
if (local) {
BLE_LL_ASSERT(rl->rl_has_local);
memcpy(addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN);
} else {
BLE_LL_ASSERT(rl->rl_has_peer);
memcpy(addr, rl->rl_peer_rpa, BLE_DEV_ADDR_LEN);
}
OS_EXIT_CRITICAL(sr);
}
void
ble_ll_resolv_set_peer_rpa(int index, uint8_t *rpa)
{
os_sr_t sr;
struct ble_ll_resolv_entry *rl;
OS_ENTER_CRITICAL(sr);
rl = &g_ble_ll_resolv_list[index];
memcpy(rl->rl_peer_rpa, rpa, BLE_DEV_ADDR_LEN);
OS_EXIT_CRITICAL(sr);
}
void
ble_ll_resolv_set_local_rpa(int index, uint8_t *rpa)
{
os_sr_t sr;
struct ble_ll_resolv_entry *rl;
OS_ENTER_CRITICAL(sr);
rl = &g_ble_ll_resolv_list[index];
memcpy(rl->rl_local_rpa, rpa, BLE_DEV_ADDR_LEN);
OS_EXIT_CRITICAL(sr);
}
/**
* Generate a resolvable private address.
*
* @param addr
* @param addr_type
* @param rpa
*
* @return int
*/
int
ble_ll_resolv_gen_rpa(uint8_t *addr, uint8_t addr_type, uint8_t *rpa, int local)
{
struct ble_ll_resolv_entry *rl;
rl = ble_ll_resolv_list_find(addr, addr_type);
if (rl) {
if ((local && rl->rl_has_local) || (!local && rl->rl_has_peer)) {
ble_ll_resolv_get_priv_addr(rl, local, rpa);
return 1;
}
}
return 0;
}
/**
* Resolve a Resolvable Private Address
*
* @param rpa
* @param index
*
* @return int
*/
int
ble_ll_resolv_rpa(const uint8_t *rpa, const uint8_t *irk)
{
int rc;
const uint32_t *irk32;
uint32_t *key32;
uint32_t *pt32;
struct ble_encryption_block ecb;
irk32 = (const uint32_t *)irk;
key32 = (uint32_t *)&ecb.key[0];
key32[0] = irk32[0];
key32[1] = irk32[1];
key32[2] = irk32[2];
key32[3] = irk32[3];
pt32 = (uint32_t *)&ecb.plain_text[0];
pt32[0] = 0;
pt32[1] = 0;
pt32[2] = 0;
pt32[3] = 0;
ecb.plain_text[15] = rpa[3];
ecb.plain_text[14] = rpa[4];
ecb.plain_text[13] = rpa[5];
ble_hw_encrypt_block(&ecb);
if ((ecb.cipher_text[15] == rpa[0]) && (ecb.cipher_text[14] == rpa[1]) &&
(ecb.cipher_text[13] == rpa[2])) {
rc = 1;
} else {
rc = 0;
}
return rc;
}
int
ble_ll_resolv_peer_rpa_any(const uint8_t *rpa)
{
int i;
for (i = 0; i < g_ble_ll_resolv_data.rl_cnt_hw; i++) {
if (ble_ll_resolv_rpa(rpa, g_ble_ll_resolv_list[i].rl_peer_irk)) {
return i;
}
}
return -1;
}
/**
* Returns whether or not address resolution is enabled.
*
* @return uint8_t
*/
uint8_t
ble_ll_resolv_enabled(void)
{
return g_ble_ll_resolv_data.addr_res_enabled;
}
/**
* Called to reset private address resolution module.
*/
void
ble_ll_resolv_list_reset(void)
{
g_ble_ll_resolv_data.addr_res_enabled = 0;
ble_npl_callout_stop(&g_ble_ll_resolv_data.rpa_timer);
ble_ll_resolv_list_clr();
ble_ll_resolv_init();
}
void
ble_ll_resolv_init(void)
{
uint8_t hw_size;
/* Default is 15 minutes */
g_ble_ll_resolv_data.rpa_tmo = ble_npl_time_ms_to_ticks32(15 * 60 * 1000);
hw_size = ble_hw_resolv_list_size();
if (hw_size > MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)) {
hw_size = MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE);
}
g_ble_ll_resolv_data.rl_size = hw_size;
ble_npl_callout_init(&g_ble_ll_resolv_data.rpa_timer,
&g_ble_ll_data.ll_evq,
ble_ll_resolv_rpa_timer_cb,
NULL);
}
#endif /* if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) */

View File

@@ -0,0 +1,346 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <stddef.h>
#include <assert.h>
#include <stddef.h>
#include "syscfg/syscfg.h"
#include "os/os_cputime.h"
#include "controller/ble_phy.h"
#include "controller/ble_ll.h"
#include "controller/ble_ll_sched.h"
#include "controller/ble_ll_rfmgmt.h"
#if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0
enum ble_ll_rfmgmt_state {
RFMGMT_STATE_OFF = 0,
RFMGMT_STATE_ENABLING = 1,
RFMGMT_STATE_ENABLED = 2,
};
struct ble_ll_rfmgmt_data {
enum ble_ll_rfmgmt_state state;
uint16_t ticks_to_enabled;
struct hal_timer timer;
bool timer_scheduled;
uint32_t timer_scheduled_at;
bool enable_scan;
bool enable_sched;
uint32_t enable_scan_at;
uint32_t enable_sched_at;
uint32_t enabled_at;
struct ble_npl_event release_ev;
};
static struct ble_ll_rfmgmt_data g_ble_ll_rfmgmt_data;
static void
ble_ll_rfmgmt_enable(void)
{
OS_ASSERT_CRITICAL();
if (g_ble_ll_rfmgmt_data.state == RFMGMT_STATE_OFF) {
g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_ENABLING;
g_ble_ll_rfmgmt_data.enabled_at = os_cputime_get32();
ble_phy_rfclk_enable();
}
}
static void
ble_ll_rfmgmt_disable(void)
{
OS_ASSERT_CRITICAL();
if (g_ble_ll_rfmgmt_data.state != RFMGMT_STATE_OFF) {
ble_phy_rfclk_disable();
g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_OFF;
}
}
static void
ble_ll_rfmgmt_timer_reschedule(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
uint32_t enable_at;
/* Figure out when we need to enable RF */
if (rfmgmt->enable_scan && rfmgmt->enable_sched) {
if (CPUTIME_LT(rfmgmt->enable_scan_at, rfmgmt->enable_sched_at)) {
enable_at = rfmgmt->enable_scan_at;
} else {
enable_at = rfmgmt->enable_sched_at;
}
} else if (rfmgmt->enable_scan) {
enable_at = rfmgmt->enable_scan_at;
} else if (rfmgmt->enable_sched) {
enable_at = rfmgmt->enable_sched_at;
} else {
rfmgmt->timer_scheduled = false;
os_cputime_timer_stop(&rfmgmt->timer);
return;
}
if (rfmgmt->timer_scheduled) {
/*
* If there is timer already scheduled at the same time we do not need
* to do anything. Otherwise we need to stop timer and schedule it again
* regardless if it's earlier or later to make sure it fires at the time
* something expects it.
*/
if (rfmgmt->timer_scheduled_at == enable_at) {
return;
}
rfmgmt->timer_scheduled = false;
os_cputime_timer_stop(&rfmgmt->timer);
}
/*
* In case timer was requested to be enabled before current time, just make
* sure it's enabled and assume caller can deal with this. This will happen
* if something is scheduled "now" since "enable_at" is in the past, but in
* such case it's absolutely harmless since we already have clock enabled
* and this will do nothing.
*/
if (CPUTIME_LEQ(enable_at, os_cputime_get32())) {
ble_ll_rfmgmt_enable();
return;
}
rfmgmt->timer_scheduled = true;
rfmgmt->timer_scheduled_at = enable_at;
os_cputime_timer_start(&rfmgmt->timer, enable_at);
}
static void
ble_ll_rfmgmt_timer_exp(void *arg)
{
g_ble_ll_rfmgmt_data.timer_scheduled = false;
ble_ll_rfmgmt_enable();
}
static void
ble_ll_rfmgmt_release_ev(struct ble_npl_event *ev)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
uint32_t now;
bool can_disable;
uint8_t lls;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
now = os_cputime_get32();
can_disable = true;
lls = ble_ll_state_get();
if (rfmgmt->enable_scan && CPUTIME_GEQ(now, rfmgmt->enable_scan_at)) {
/* Blocked by scan */
can_disable = false;
} else if (rfmgmt->enable_sched && CPUTIME_GEQ(now, rfmgmt->enable_sched_at)) {
/* Blocked by scheduler item */
can_disable = false;
} else if (lls != BLE_LL_STATE_STANDBY) {
/* Blocked by LL state */
can_disable = false;
}
if (can_disable) {
ble_ll_rfmgmt_disable();
}
OS_EXIT_CRITICAL(sr);
}
static uint32_t
ble_ll_rfmgmt_ticks_to_enabled(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
uint32_t rem_ticks;
uint32_t now;
switch (rfmgmt->state) {
case RFMGMT_STATE_OFF:
rem_ticks = rfmgmt->ticks_to_enabled;
break;
case RFMGMT_STATE_ENABLING:
now = os_cputime_get32();
if (CPUTIME_LT(now, rfmgmt->enabled_at + rfmgmt->ticks_to_enabled)) {
rem_ticks = rfmgmt->enabled_at + rfmgmt->ticks_to_enabled - now;
break;
}
rfmgmt->state = RFMGMT_STATE_ENABLED;
/* no break */
case RFMGMT_STATE_ENABLED:
rem_ticks = 0;
break;
default:
BLE_LL_ASSERT(0);
rem_ticks = 0;
break;
}
return rem_ticks;
}
void
ble_ll_rfmgmt_init(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
rfmgmt->state = RFMGMT_STATE_OFF;
rfmgmt->ticks_to_enabled =
ble_ll_usecs_to_ticks_round_up(MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME));
rfmgmt->timer_scheduled = false;
os_cputime_timer_init(&rfmgmt->timer, ble_ll_rfmgmt_timer_exp, NULL);
ble_npl_event_init(&rfmgmt->release_ev, ble_ll_rfmgmt_release_ev, NULL);
}
void
ble_ll_rfmgmt_reset(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
rfmgmt->timer_scheduled = false;
rfmgmt->timer_scheduled_at = 0;
os_cputime_timer_stop(&rfmgmt->timer);
ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev);
ble_ll_rfmgmt_disable();
rfmgmt->enable_scan = false;
rfmgmt->enable_scan_at = 0;
rfmgmt->enable_sched = false;
rfmgmt->enable_sched_at = 0;
rfmgmt->enabled_at = 0;
}
void
ble_ll_rfmgmt_scan_changed(bool enabled, uint32_t next_window)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
rfmgmt->enable_scan = enabled;
rfmgmt->enable_scan_at = next_window - rfmgmt->ticks_to_enabled;
ble_ll_rfmgmt_timer_reschedule();
OS_EXIT_CRITICAL(sr);
}
void
ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *first)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
rfmgmt->enable_sched = (first != NULL);
if (first) {
rfmgmt->enable_sched_at = first->start_time - rfmgmt->ticks_to_enabled;
}
ble_ll_rfmgmt_timer_reschedule();
OS_EXIT_CRITICAL(sr);
}
void
ble_ll_rfmgmt_release(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev);
if (g_ble_ll_rfmgmt_data.state != RFMGMT_STATE_OFF) {
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev);
}
OS_EXIT_CRITICAL(sr);
}
uint32_t
ble_ll_rfmgmt_enable_now(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
uint32_t enabled_at;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
ble_ll_rfmgmt_enable();
if (rfmgmt->state == RFMGMT_STATE_ENABLED) {
enabled_at = os_cputime_get32();
} else {
enabled_at = rfmgmt->enabled_at + rfmgmt->ticks_to_enabled + 1;
}
OS_EXIT_CRITICAL(sr);
return enabled_at;
}
bool
ble_ll_rfmgmt_is_enabled(void)
{
bool ret;
OS_ASSERT_CRITICAL();
ret = ble_ll_rfmgmt_ticks_to_enabled() == 0;
return ret;
}
#else
void
ble_ll_rfmgmt_init(void)
{
static bool enabled = false;
if (!enabled) {
ble_phy_rfclk_enable();
}
enabled = true;
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,458 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 "nimble/ble.h"
#include "nimble/nimble_opt.h"
#include "nimble/hci_common.h"
#include "controller/ble_ll.h"
#include "controller/ble_ll_hci.h"
/* Octet 0 */
#define BLE_SUPP_CMD_DISCONNECT (1 << 5)
#define BLE_LL_SUPP_CMD_OCTET_0 (BLE_SUPP_CMD_DISCONNECT)
/* Octet 5 */
#define BLE_SUPP_CMD_SET_EVENT_MASK (1 << 6)
#define BLE_LL_SUPP_CMD_OCTET_5 (BLE_SUPP_CMD_SET_EVENT_MASK)
/* Octet 10 */
#define BLE_SUPP_CMD_RD_TX_PWR (0 << 2)
#define BLE_LL_SUPP_CMD_OCTET_10 (BLE_SUPP_CMD_RD_TX_PWR)
/* Octet 14 */
#define BLE_SUPP_CMD_RD_LOC_VER (1 << 3)
#define BLE_SUPP_CMD_RD_LOC_SUPP_FEAT (1 << 5)
#define BLE_LL_SUPP_CMD_OCTET_14 \
( \
BLE_SUPP_CMD_RD_LOC_VER | \
BLE_SUPP_CMD_RD_LOC_SUPP_FEAT \
)
/* Octet 15 */
#define BLE_SUPP_CMD_RD_BD_ADDR (1 << 1)
#define BLE_SUPP_CMD_RD_RSSI (1 << 5)
#define BLE_LL_SUPP_CMD_OCTET_15 \
( \
BLE_SUPP_CMD_RD_BD_ADDR | \
BLE_SUPP_CMD_RD_RSSI \
)
/* Octet 25 */
#define BLE_SUPP_CMD_LE_SET_EV_MASK (1 << 0)
#define BLE_SUPP_CMD_LE_RD_BUF_SIZE (1 << 1)
#define BLE_SUPP_CMD_LE_RD_LOC_FEAT (1 << 2)
#define BLE_SUPP_CMD_LE_SET_RAND_ADDR (1 << 4)
#define BLE_SUPP_CMD_LE_SET_ADV_PARAMS (1 << 5)
#define BLE_SUPP_CMD_LE_SET_ADV_TX_PWR (1 << 6)
#define BLE_SUPP_CMD_LE_SET_ADV_DATA (1 << 7)
#define BLE_LL_SUPP_CMD_OCTET_25 \
( \
BLE_SUPP_CMD_LE_SET_EV_MASK | \
BLE_SUPP_CMD_LE_RD_BUF_SIZE | \
BLE_SUPP_CMD_LE_RD_LOC_FEAT | \
BLE_SUPP_CMD_LE_SET_RAND_ADDR | \
BLE_SUPP_CMD_LE_SET_ADV_PARAMS | \
BLE_SUPP_CMD_LE_SET_ADV_TX_PWR | \
BLE_SUPP_CMD_LE_SET_ADV_DATA \
)
/* Octet 26 */
#define BLE_SUPP_CMD_LE_SET_SCAN_RSP_DATA (1 << 0)
#define BLE_SUPP_CMD_LE_SET_ADV_ENABLE (1 << 1)
#define BLE_SUPP_CMD_LE_SET_SCAN_PARAMS (1 << 2)
#define BLE_SUPP_CMD_LE_SET_SCAN_ENABLE (1 << 3)
#define BLE_SUPP_CMD_LE_CREATE_CONN (1 << 4)
#define BLE_SUPP_CMD_LE_CREATE_CONN_CANCEL (1 << 5)
#define BLE_SUPP_CMD_LE_RD_WHITELIST_SIZE (1 << 6)
#define BLE_SUPP_CMD_LE_CLR_WHITELIST (1 << 7)
#define BLE_LL_SUPP_CMD_OCTET_26 \
( \
BLE_SUPP_CMD_LE_SET_SCAN_RSP_DATA | \
BLE_SUPP_CMD_LE_SET_ADV_ENABLE | \
BLE_SUPP_CMD_LE_SET_SCAN_PARAMS | \
BLE_SUPP_CMD_LE_SET_SCAN_ENABLE | \
BLE_SUPP_CMD_LE_CREATE_CONN | \
BLE_SUPP_CMD_LE_CREATE_CONN_CANCEL | \
BLE_SUPP_CMD_LE_RD_WHITELIST_SIZE | \
BLE_SUPP_CMD_LE_CLR_WHITELIST \
)
/* Octet 27 */
#define BLE_SUPP_CMD_LE_ADD_DEV_WHITELIST (1 << 0)
#define BLE_SUPP_CMD_LE_RMV_DEV_WHITELIST (1 << 1)
#define BLE_SUPP_CMD_LE_CONN_UPDATE (1 << 2)
#define BLE_SUPP_CMD_LE_SET_HOST_CHAN_CLASS (1 << 3)
#define BLE_SUPP_CMD_LE_RD_CHAN_MAP (1 << 4)
#define BLE_SUPP_CMD_LE_RD_REM_USED_FEAT (1 << 5)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
#define BLE_SUPP_CMD_LE_ENCRYPT (1 << 6)
#else
#define BLE_SUPP_CMD_LE_ENCRYPT (0 << 6)
#endif
#define BLE_SUPP_CMD_LE_RAND (1 << 7)
#define BLE_LL_SUPP_CMD_OCTET_27 \
( \
BLE_SUPP_CMD_LE_ENCRYPT | \
BLE_SUPP_CMD_LE_RAND | \
BLE_SUPP_CMD_LE_ADD_DEV_WHITELIST | \
BLE_SUPP_CMD_LE_RMV_DEV_WHITELIST | \
BLE_SUPP_CMD_LE_CONN_UPDATE | \
BLE_SUPP_CMD_LE_SET_HOST_CHAN_CLASS | \
BLE_SUPP_CMD_LE_RD_CHAN_MAP | \
BLE_SUPP_CMD_LE_RD_REM_USED_FEAT \
)
/* Octet 28 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
#define BLE_SUPP_CMD_LE_START_ENCRYPT (1 << 0)
#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (1 << 1)
#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (1 << 2)
#else
#define BLE_SUPP_CMD_LE_START_ENCRYPT (0 << 0)
#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (0 << 1)
#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (0 << 2)
#endif
#define BLE_SUPP_CMD_LE_READ_SUPP_STATES (1 << 3)
#if MYNEWT_VAL(BLE_LL_DTM)
#define BLE_SUPP_CMD_LE_RX_TEST (1 << 4)
#define BLE_SUPP_CMD_LE_TX_TEST (1 << 5)
#define BLE_SUPP_CMD_LE_TEST_END (1 << 6)
#else
#define BLE_SUPP_CMD_LE_RX_TEST (0 << 4)
#define BLE_SUPP_CMD_LE_TX_TEST (0 << 5)
#define BLE_SUPP_CMD_LE_TEST_END (0 << 6)
#endif
#define BLE_LL_SUPP_CMD_OCTET_28 \
( \
BLE_SUPP_CMD_LE_START_ENCRYPT | \
BLE_SUPP_CMD_LE_LTK_REQ_REPLY | \
BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY | \
BLE_SUPP_CMD_LE_READ_SUPP_STATES | \
BLE_SUPP_CMD_LE_RX_TEST | \
BLE_SUPP_CMD_LE_TX_TEST | \
BLE_SUPP_CMD_LE_TEST_END \
)
/* Octet 33 */
#define BLE_SUPP_CMD_LE_REM_CONN_PRR (1 << 4)
#define BLE_SUPP_CMD_LE_REM_CONN_PRNR (1 << 5)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT)
#define BLE_SUPP_CMD_LE_SET_DATALEN (1 << 6)
#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (1 << 7)
#else
#define BLE_SUPP_CMD_LE_SET_DATALEN (0 << 6)
#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_33 \
( \
BLE_SUPP_CMD_LE_REM_CONN_PRR | \
BLE_SUPP_CMD_LE_REM_CONN_PRNR | \
BLE_SUPP_CMD_LE_SET_DATALEN | \
BLE_SUPP_CMD_LE_RD_SUGG_DATALEN \
)
/* Octet 34 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT)
#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (1 << 0)
#else
#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (0 << 0)
#endif
#define BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK (0 << 1)
#define BLE_SUPP_CMD_LE_GENERATE_DH_KEY (0 << 2)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
#define BLE_SUPP_CMD_LE_ADD_RESOLV_LIST (1 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST (1 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST (1 << 5)
#define BLE_SUPP_CMD_LE_RD_RESOLV_SIZE (1 << 6)
#define BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR (1 << 7)
#else
#define BLE_SUPP_CMD_LE_ADD_RESOLV_LIST (0 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST (0 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST (0 << 5)
#define BLE_SUPP_CMD_LE_RD_RESOLV_SIZE (0 << 6)
#define BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_34 \
( \
BLE_SUPP_CMD_LE_WR_SUGG_DATALEN | \
BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK | \
BLE_SUPP_CMD_LE_GENERATE_DH_KEY | \
BLE_SUPP_CMD_LE_ADD_RESOLV_LIST | \
BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST | \
BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST | \
BLE_SUPP_CMD_LE_RD_RESOLV_SIZE | \
BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR \
)
/* Octet 35 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
#define BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR (1 << 0)
#define BLE_SUPP_CMD_LE_SET_ADDR_RES_EN (1 << 1)
#define BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO (1 << 2)
#else
#define BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR (0 << 0)
#define BLE_SUPP_CMD_LE_SET_ADDR_RES_EN (0 << 1)
#define BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO (0 << 2)
#endif
#define BLE_SUPP_CMD_LE_RD_MAX_DATALEN (1 << 3)
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
#define BLE_SUPP_CMD_LE_READ_PHY (1 << 4)
#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (1 << 5)
#define BLE_SUPP_CMD_LE_SET_PHY (1 << 6)
#else
#define BLE_SUPP_CMD_LE_READ_PHY (0 << 4)
#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (0 << 5)
#define BLE_SUPP_CMD_LE_SET_PHY (0 << 6)
#endif
#if MYNEWT_VAL(BLE_LL_DTM)
#define BLE_SUPP_CMD_LE_ENHANCED_RX_TEST (1 << 7)
#else
#define BLE_SUPP_CMD_LE_ENHANCED_RX_TEST (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_35 \
( \
BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR | \
BLE_SUPP_CMD_LE_SET_ADDR_RES_EN | \
BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO | \
BLE_SUPP_CMD_LE_RD_MAX_DATALEN | \
BLE_SUPP_CMD_LE_READ_PHY | \
BLE_SUPP_CMD_LE_SET_DEFAULT_PHY | \
BLE_SUPP_CMD_LE_SET_PHY | \
BLE_SUPP_CMD_LE_ENHANCED_RX_TEST \
)
/* Octet 36 */
#if MYNEWT_VAL(BLE_LL_DTM)
#define BLE_SUPP_CMD_LE_ENHANCED_TX_TEST (1 << 0)
#else
#define BLE_SUPP_CMD_LE_ENHANCED_TX_TEST (0 << 0)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
#define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (1 << 1)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (1 << 2)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (1 << 3)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP (1 << 4)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE (1 << 5)
#define BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN (1 << 6)
#define BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS (1 << 7)
#else
#define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (0 << 1)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (0 << 2)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (0 << 3)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP (0 << 4)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE (0 << 5)
#define BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN (0 << 6)
#define BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_36 \
( \
BLE_SUPP_CMD_LE_ENHANCED_TX_TEST | \
BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR | \
BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM | \
BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA | \
BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP | \
BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE | \
BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN | \
BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS \
)
/* Octet 37 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
#define BLE_SUPP_CMD_LE_REMOVE_ADVS (1 << 0)
#define BLE_SUPP_CMD_LE_CLEAR_ADVS (1 << 1)
#else
#define BLE_SUPP_CMD_LE_REMOVE_ADVS (0 << 0)
#define BLE_SUPP_CMD_LE_CLEAR_ADVS (0 << 1)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
#define BLE_SUPP_CMD_LE_SET_PADV_PARAM (1 << 2)
#define BLE_SUPP_CMD_LE_SET_PADV_DATA (1 << 3)
#define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (1 << 4)
#else
#define BLE_SUPP_CMD_LE_SET_PADV_PARAM (0 << 2)
#define BLE_SUPP_CMD_LE_SET_PADV_DATA (0 << 3)
#define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (0 << 4)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (1 << 5)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (1 << 6)
#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (1 << 7)
#else
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (0 << 5)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (0 << 6)
#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_37 \
( \
BLE_SUPP_CMD_LE_REMOVE_ADVS | \
BLE_SUPP_CMD_LE_CLEAR_ADVS | \
BLE_SUPP_CMD_LE_SET_PADV_PARAM | \
BLE_SUPP_CMD_LE_SET_PADV_DATA | \
BLE_SUPP_CMD_LE_SET_PADV_ENABLE | \
BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM | \
BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE | \
BLE_SUPP_CMD_LE_EXT_CREATE_CONN \
)
/* Octet 38 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC (1 << 0)
#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C (1 << 1)
#define BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC (1 << 2)
#define BLE_SUPP_CMD_LE_ADD_PADV_LIST (1 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_PADV_LIST (1 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_PADV_LIST (1 << 5)
#define BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE (1 << 6)
#else
#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC (0 << 0)
#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C (0 << 1)
#define BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC (0 << 2)
#define BLE_SUPP_CMD_LE_ADD_PADV_LIST (0 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_PADV_LIST (0 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_PADV_LIST (0 << 5)
#define BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE (0 << 6)
#endif
#define BLE_SUPP_CMD_LE_RD_TX_POWER (1 << 7)
#define BLE_LL_SUPP_CMD_OCTET_38 \
( \
BLE_SUPP_CMD_LE_PADV_CREATE_SYNC | \
BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C | \
BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC | \
BLE_SUPP_CMD_LE_ADD_PADV_LIST | \
BLE_SUPP_CMD_LE_REMOVE_PADV_LIST | \
BLE_SUPP_CMD_LE_CLEAR_PADV_LIST | \
BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE | \
BLE_SUPP_CMD_LE_RD_TX_POWER \
)
/* Octet 39 */
#define BLE_SUPP_CMD_LE_RD_RF_PATH_COMP (1 << 0)
#define BLE_SUPP_CMD_LE_WR_RF_PATH_COMP (1 << 1)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
#define BLE_SUPP_CMD_LE_SET_PRIVACY_MODE (1 << 2)
#else
#define BLE_SUPP_CMD_LE_SET_PRIVACY_MODE (0 << 2)
#endif
#define BLE_LL_SUPP_CMD_OCTET_39 \
( \
BLE_SUPP_CMD_LE_RD_RF_PATH_COMP | \
BLE_SUPP_CMD_LE_WR_RF_PATH_COMP | \
BLE_SUPP_CMD_LE_SET_PRIVACY_MODE \
)
/* Octet 40 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_VERSION) >= 51
#define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (1 << 5)
#else
#define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (0 << 5)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER (1 << 6)
#define BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER (1 << 7)
#else
#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER (0 << 6)
#define BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_40 \
( \
BLE_SUPP_CMD_LE_PADV_RECV_ENABLE | \
BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER | \
BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER \
)
/* Octet 41 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (1 << 0)
#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (1 << 1)
#else
#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (0 << 0)
#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (0 << 1)
#endif
#define BLE_LL_SUPP_CMD_OCTET_41 \
( \
BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS | \
BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS \
)
/* Defines the array of supported commands */
const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN] =
{
BLE_LL_SUPP_CMD_OCTET_0, /* Octet 0 */
0,
0,
0,
0,
BLE_LL_SUPP_CMD_OCTET_5,
0,
0,
0, /* Octet 8 */
0,
BLE_LL_SUPP_CMD_OCTET_10,
0,
0,
0,
BLE_LL_SUPP_CMD_OCTET_14,
BLE_LL_SUPP_CMD_OCTET_15,
0, /* Octet 16 */
0,
0,
0,
0,
0,
0,
0,
0, /* Octet 24 */
BLE_LL_SUPP_CMD_OCTET_25,
BLE_LL_SUPP_CMD_OCTET_26,
BLE_LL_SUPP_CMD_OCTET_27,
BLE_LL_SUPP_CMD_OCTET_28,
0,
0,
0,
0, /* Octet 32 */
BLE_LL_SUPP_CMD_OCTET_33,
BLE_LL_SUPP_CMD_OCTET_34,
BLE_LL_SUPP_CMD_OCTET_35,
BLE_LL_SUPP_CMD_OCTET_36,
BLE_LL_SUPP_CMD_OCTET_37,
BLE_LL_SUPP_CMD_OCTET_38,
BLE_LL_SUPP_CMD_OCTET_39,
BLE_LL_SUPP_CMD_OCTET_40, /* Octet 40 */
BLE_LL_SUPP_CMD_OCTET_41,
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 "syscfg/syscfg.h"
#include "os/os_trace_api.h"
#if MYNEWT_VAL(BLE_LL_SYSVIEW)
static os_trace_module_t g_ble_ll_trace_mod;
uint32_t ble_ll_trace_off;
static void
ble_ll_trace_module_send_desc(void)
{
os_trace_module_desc(&g_ble_ll_trace_mod, "0 ll_sched lls=%u cputime=%u start_time=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "1 ll_rx_start lls=%u pdu_type=%x");
os_trace_module_desc(&g_ble_ll_trace_mod, "2 ll_rx_end pdu_type=%x len=%u flags=%x");
os_trace_module_desc(&g_ble_ll_trace_mod, "3 ll_wfr_timer_exp lls=%u xcvr=%u rx_start=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "4 ll_ctrl_rx opcode=%u len=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "5 ll_conn_ev_start conn_handle=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "6 ll_conn_ev_end conn_handle=%u event_cntr=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "7 ll_conn_end conn_handle=%u event_cntr=%u err=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "8 ll_conn_tx len=%u offset=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "9 ll_conn_rx conn_sn=%u pdu_nesn=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "10 ll_adv_txdone inst=%u chanset=%x");
os_trace_module_desc(&g_ble_ll_trace_mod, "11 ll_adv_halt inst=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "12 ll_aux_ref aux=%p ref=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "13 ll_aux_unref aux=%p ref=%u");
}
void
ble_ll_trace_init(void)
{
ble_ll_trace_off =
os_trace_module_register(&g_ble_ll_trace_mod, "ble_ll", 12,
ble_ll_trace_module_send_desc);
}
#endif

View File

@@ -0,0 +1,301 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include <stdlib.h>
#include "nimble/ble.h"
#include "controller/ble_ll.h"
#include "controller/ble_ll_utils.h"
/* 37 bits require 5 bytes */
#define BLE_LL_CHMAP_LEN (5)
/* Sleep clock accuracy table (in ppm) */
static const uint16_t g_ble_sca_ppm_tbl[8] = {
500, 250, 150, 100, 75, 50, 30, 20
};
uint32_t
ble_ll_utils_calc_access_addr(void)
{
uint32_t aa;
uint16_t aa_low;
uint16_t aa_high;
uint32_t temp;
uint32_t mask;
uint32_t prev_bit;
uint8_t bits_diff;
uint8_t consecutive;
uint8_t transitions;
uint8_t ones;
int tmp;
/* Calculate a random access address */
aa = 0;
while (1) {
/* Get two, 16-bit random numbers */
aa_low = rand() & 0xFFFF;
aa_high = rand() & 0xFFFF;
/* All four bytes cannot be equal */
if (aa_low == aa_high) {
continue;
}
/* Upper 6 bits must have 2 transitions */
tmp = (int16_t)aa_high >> 10;
if (__builtin_popcount(tmp ^ (tmp >> 1)) < 2) {
continue;
}
/* Cannot be access address or be 1 bit different */
aa = aa_high;
aa = (aa << 16) | aa_low;
bits_diff = 0;
temp = aa ^ BLE_ACCESS_ADDR_ADV;
for (mask = 0x00000001; mask != 0; mask <<= 1) {
if (mask & temp) {
++bits_diff;
if (bits_diff > 1) {
break;
}
}
}
if (bits_diff <= 1) {
continue;
}
/* Cannot have more than 24 transitions */
transitions = 0;
consecutive = 1;
ones = 0;
mask = 0x00000001;
while (mask < 0x80000000) {
prev_bit = aa & mask;
mask <<= 1;
if (mask & aa) {
if (prev_bit == 0) {
++transitions;
consecutive = 1;
} else {
++consecutive;
}
} else {
if (prev_bit == 0) {
++consecutive;
} else {
++transitions;
consecutive = 1;
}
}
if (prev_bit) {
ones++;
}
/* 8 lsb should have at least three 1 */
if (mask == 0x00000100 && ones < 3) {
break;
}
/* 16 lsb should have no more than 11 transitions */
if (mask == 0x00010000 && transitions > 11) {
break;
}
/* This is invalid! */
if (consecutive > 6) {
/* Make sure we always detect invalid sequence below */
mask = 0;
break;
}
}
/* Invalid sequence found */
if (mask != 0x80000000) {
continue;
}
/* Cannot be more than 24 transitions */
if (transitions > 24) {
continue;
}
/* We have a valid access address */
break;
}
return aa;
}
uint8_t
ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap)
{
uint8_t cntr;
uint8_t mask;
uint8_t usable_chans;
uint8_t chan;
int i, j;
/* NOTE: possible to build a map but this would use memory. For now,
* we just calculate
* Iterate through channel map to find this channel
*/
chan = 0;
cntr = 0;
for (i = 0; i < BLE_LL_CHMAP_LEN; i++) {
usable_chans = chanmap[i];
if (usable_chans != 0) {
mask = 0x01;
for (j = 0; j < 8; j++) {
if (usable_chans & mask) {
if (cntr == remap_index) {
return (chan + j);
}
++cntr;
}
mask <<= 1;
}
}
chan += 8;
}
/* we should never reach here */
BLE_LL_ASSERT(0);
return 0;
}
uint8_t
ble_ll_utils_calc_num_used_chans(const uint8_t *chmap)
{
int i;
int j;
uint8_t mask;
uint8_t chanbyte;
uint8_t used_channels;
used_channels = 0;
for (i = 0; i < BLE_LL_CHMAP_LEN; ++i) {
chanbyte = chmap[i];
if (chanbyte) {
if (chanbyte == 0xff) {
used_channels += 8;
} else {
mask = 0x01;
for (j = 0; j < 8; ++j) {
if (chanbyte & mask) {
++used_channels;
}
mask <<= 1;
}
}
}
}
return used_channels;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2)
static uint16_t
ble_ll_utils_csa2_perm(uint16_t in)
{
uint16_t out = 0;
int i;
for (i = 0; i < 8; i++) {
out |= ((in >> i) & 0x00000001) << (7 - i);
}
for (i = 8; i < 16; i++) {
out |= ((in >> i) & 0x00000001) << (15 + 8 - i);
}
return out;
}
static uint16_t
ble_ll_utils_csa2_prng(uint16_t counter, uint16_t ch_id)
{
uint16_t prn_e;
prn_e = counter ^ ch_id;
prn_e = ble_ll_utils_csa2_perm(prn_e);
prn_e = (prn_e * 17) + ch_id;
prn_e = ble_ll_utils_csa2_perm(prn_e);
prn_e = (prn_e * 17) + ch_id;
prn_e = ble_ll_utils_csa2_perm(prn_e);
prn_e = (prn_e * 17) + ch_id;
prn_e = prn_e ^ ch_id;
return prn_e;
}
uint8_t
ble_ll_utils_calc_dci_csa2(uint16_t event_cntr, uint16_t channel_id,
uint8_t num_used_chans, const uint8_t *chanmap)
{
uint16_t channel_unmapped;
uint8_t remap_index;
uint16_t prn_e;
uint8_t bitpos;
prn_e = ble_ll_utils_csa2_prng(event_cntr, channel_id);
channel_unmapped = prn_e % 37;
/*
* If unmapped channel is the channel index of a used channel it is used
* as channel index.
*/
bitpos = 1 << (channel_unmapped & 0x07);
if (chanmap[channel_unmapped >> 3] & bitpos) {
return channel_unmapped;
}
remap_index = (num_used_chans * prn_e) / 0x10000;
return ble_ll_utils_remapped_channel(remap_index, chanmap);
}
#endif
uint32_t
ble_ll_utils_calc_window_widening(uint32_t anchor_point,
uint32_t last_anchor_point,
uint8_t master_sca)
{
uint32_t total_sca_ppm;
uint32_t window_widening;
int32_t time_since_last_anchor;
uint32_t delta_msec;
window_widening = 0;
time_since_last_anchor = (int32_t)(anchor_point - last_anchor_point);
if (time_since_last_anchor > 0) {
delta_msec = os_cputime_ticks_to_usecs(time_since_last_anchor) / 1000;
total_sca_ppm = g_ble_sca_ppm_tbl[master_sca] +
MYNEWT_VAL(BLE_LL_OUR_SCA);
window_widening = (total_sca_ppm * delta_msec) / 1000;
}
return window_widening;
}

View File

@@ -0,0 +1,287 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include <string.h>
#include "syscfg/syscfg.h"
#include "os/os.h"
#include "nimble/ble.h"
#include "nimble/nimble_opt.h"
#include "ble/xcvr.h"
#include "controller/ble_ll_whitelist.h"
#include "controller/ble_ll_hci.h"
#include "controller/ble_ll_adv.h"
#include "controller/ble_ll_scan.h"
#include "controller/ble_hw.h"
#if (MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) < BLE_HW_WHITE_LIST_SIZE)
#define BLE_LL_WHITELIST_SIZE MYNEWT_VAL(BLE_LL_WHITELIST_SIZE)
#else
#define BLE_LL_WHITELIST_SIZE BLE_HW_WHITE_LIST_SIZE
#endif
struct ble_ll_whitelist_entry
{
uint8_t wl_valid;
uint8_t wl_addr_type;
uint8_t wl_dev_addr[BLE_DEV_ADDR_LEN];
};
struct ble_ll_whitelist_entry g_ble_ll_whitelist[BLE_LL_WHITELIST_SIZE];
static int
ble_ll_whitelist_chg_allowed(void)
{
int rc;
/*
* This command is not allowed if:
* -> advertising uses the whitelist and we are currently advertising.
* -> scanning uses the whitelist and is enabled.
* -> initiating uses whitelist and a LE create connection command is in
* progress
*/
rc = 1;
if (!ble_ll_adv_can_chg_whitelist() || !ble_ll_scan_can_chg_whitelist()) {
rc = 0;
}
return rc;
}
/**
* Clear the whitelist.
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_ll_whitelist_clear(void)
{
int i;
struct ble_ll_whitelist_entry *wl;
/* Check proper state */
if (!ble_ll_whitelist_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Set the number of entries to 0 */
wl = &g_ble_ll_whitelist[0];
for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) {
wl->wl_valid = 0;
++wl;
}
#if (BLE_USES_HW_WHITELIST == 1)
ble_hw_whitelist_clear();
#endif
return BLE_ERR_SUCCESS;
}
/**
* Read the size of the whitelist. This is the total number of whitelist
* entries allowed by the controller.
*
* @param rspbuf Pointer to response buffer
*
* @return int 0: success.
*/
int
ble_ll_whitelist_read_size(uint8_t *rspbuf, uint8_t *rsplen)
{
struct ble_hci_le_rd_white_list_rp *rsp = (void *) rspbuf;
rsp->size = BLE_LL_WHITELIST_SIZE;
*rsplen = sizeof(*rsp);
return BLE_ERR_SUCCESS;
}
/**
* Searches the whitelist to determine if the address is present in the
* whitelist. This is an internal API that only searches the link layer
* whitelist and does not care about the hardware whitelist
*
* @param addr Device or identity address to check.
* @param addr_type Public address (0) or random address (1)
*
* @return int 0: device is not on whitelist; otherwise the return value
* is the 'position' of the device in the whitelist (the index of the element
* plus 1).
*/
static int
ble_ll_whitelist_search(const uint8_t *addr, uint8_t addr_type)
{
int i;
struct ble_ll_whitelist_entry *wl;
wl = &g_ble_ll_whitelist[0];
for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) {
if ((wl->wl_valid) && (wl->wl_addr_type == addr_type) &&
(!memcmp(&wl->wl_dev_addr[0], addr, BLE_DEV_ADDR_LEN))) {
return i + 1;
}
++wl;
}
return 0;
}
/**
* Is there a match between the device and a device on the whitelist.
*
* NOTE: This API uses the HW, if present, to determine if there was a match
* between a received address and an address in the whitelist. If the HW does
* not support whitelisting this API is the same as the whitelist search API
*
* @param addr
* @param addr_type Public address (0) or random address (1)
* @param is_ident True if addr is an identity address; false otherwise
*
* @return int
*/
int
ble_ll_whitelist_match(uint8_t *addr, uint8_t addr_type, int is_ident)
{
int rc;
#if (BLE_USES_HW_WHITELIST == 1)
/*
* XXX: This should be changed. This is HW specific: some HW may be able
* to both resolve a private address and perform a whitelist check. The
* current BLE hw cannot support this.
*/
if (is_ident) {
rc = ble_ll_whitelist_search(addr, addr_type);
} else {
rc = ble_hw_whitelist_match();
}
#else
rc = ble_ll_whitelist_search(addr, addr_type);
#endif
return rc;
}
/**
* Add a device to the whitelist
*
* @return int
*/
int
ble_ll_whitelist_add(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_add_whte_list_cp *cmd = (const void *) cmdbuf;
struct ble_ll_whitelist_entry *wl;
int rc;
int i;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* Must be in proper state */
if (!ble_ll_whitelist_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Check if we have any open entries */
rc = BLE_ERR_SUCCESS;
if (!ble_ll_whitelist_search(cmd->addr, cmd->addr_type)) {
wl = &g_ble_ll_whitelist[0];
for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) {
if (wl->wl_valid == 0) {
memcpy(&wl->wl_dev_addr[0], cmd->addr, BLE_DEV_ADDR_LEN);
wl->wl_addr_type = cmd->addr_type;
wl->wl_valid = 1;
break;
}
++wl;
}
if (i == BLE_LL_WHITELIST_SIZE) {
rc = BLE_ERR_MEM_CAPACITY;
} else {
#if (BLE_USES_HW_WHITELIST == 1)
rc = ble_hw_whitelist_add(cmd->addr, cmd->addr_type);
#endif
}
}
return rc;
}
/**
* Remove a device from the whitelist
*
* @param cmdbuf
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_ll_whitelist_rmv(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_rmv_white_list_cp *cmd = (const void *) cmdbuf;
int position;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* Must be in proper state */
if (!ble_ll_whitelist_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
position = ble_ll_whitelist_search(cmd->addr, cmd->addr_type);
if (position) {
g_ble_ll_whitelist[position - 1].wl_valid = 0;
}
#if (BLE_USES_HW_WHITELIST == 1)
ble_hw_whitelist_rmv(cmd->addr, cmd->addr_type);
#endif
return BLE_ERR_SUCCESS;
}
/**
* Enable whitelisting.
*
* Note: This function has no effect if we are not using HW whitelisting
*/
void
ble_ll_whitelist_enable(void)
{
#if (BLE_USES_HW_WHITELIST == 1)
ble_hw_whitelist_enable();
#endif
}
/**
* Disable whitelisting.
*
* Note: This function has no effect if we are not using HW whitelisting
*/
void
ble_ll_whitelist_disable(void)
{
#if (BLE_USES_HW_WHITELIST == 1)
ble_hw_whitelist_disable();
#endif
}

View File

@@ -0,0 +1,434 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
syscfg.defs:
BLE_CONTROLLER:
description: >
Indicates that NimBLE controller is present. The default value for
this setting shall not be overriden.
value: 1
BLE_HW_WHITELIST_ENABLE:
description: >
Used to enable hardware white list
value: 1
BLE_LL_SYSVIEW:
description: >
Enable SystemView tracing module for controller.
value: 0
BLE_LL_PRIO:
description: 'The priority of the LL task'
type: 'task_priority'
value: 0
# Sleep clock accuracy (sca). This is the amount of drift in the system
# during when the device is sleeping (in parts per million).
#
# NOTE: 'the' master sca is an enumerated value based on the sca. Rather
# than have a piece of code calculate this value, the developer must set
# this value based on the value of the SCA using the following table:
#
# SCA between 251 and 500 ppm (inclusive); master sca = 0
# SCA between 151 and 250 ppm (inclusive); master sca = 1
# SCA between 101 and 150 ppm (inclusive); master sca = 2
# SCA between 76 and 100 ppm (inclusive); master sca = 3
# SCA between 51 and 75 ppm (inclusive); master sca = 4
# SCA between 31 and 50 ppm (inclusive); master sca = 5
# SCA between 21 and 30 ppm (inclusive); master sca = 6
# SCA between 0 and 20 ppm (inclusive); master sca = 7
#
# For example:
# if your clock drift is 101 ppm, your master should be set to 2.
# if your clock drift is 20, your master sca should be set to 7.
#
# The values provided below are merely meant to be an example and should
# be replaced by values appropriate for your platform.
BLE_LL_OUR_SCA:
description: 'The system clock accuracy of the device.'
value: '60' # in ppm
BLE_LL_MASTER_SCA:
description: 'Enumerated value based on our sca'
value: '4'
BLE_LL_TX_PWR_DBM:
description: 'Transmit power level.'
value: '0'
BLE_LL_NUM_COMP_PKT_ITVL_MS:
description: >
Determines the interval at which the controller will send the
number of completed packets event to the host. Rate is in milliseconds.
value: 2000
BLE_LL_MFRG_ID:
description: >
Manufacturer ID. Should be set to unique ID per manufacturer.
value: '0xFFFF'
# Configuration items for the number of duplicate advertisers and the
# number of advertisers from which we have heard a scan response.
BLE_LL_NUM_SCAN_DUP_ADVS:
description: 'The number of duplicate advertisers stored.'
value: '8'
BLE_LL_NUM_SCAN_RSP_ADVS:
description: >
The number of advertisers from which we have heard a scan
response. Prevents sending duplicate events to host.
value: '8'
BLE_LL_WHITELIST_SIZE:
description: 'Size of the LL whitelist.'
value: '8'
BLE_LL_RESOLV_LIST_SIZE:
description: 'Size of the resolving list.'
value: '4'
# Data length management definitions for connections. These define the
# maximum size of the PDU's that will be sent and/or received in a
# connection.
BLE_LL_MAX_PKT_SIZE:
description: 'The maximum PDU size that can be sent/received'
value: '251'
BLE_LL_SUPP_MAX_RX_BYTES:
description: 'The maximum supported received PDU size'
value: MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE)
BLE_LL_SUPP_MAX_TX_BYTES:
description: 'The maximum supported transmit PDU size'
value: MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE)
BLE_LL_CONN_INIT_MAX_TX_BYTES:
description: >
Used to set the initial maximum transmit PDU size in a
connection. If this is set to a value greater than 27,
the controller will automatically attempt to do the
data length update procedure. The host can always tell
the controller to update this value.
value: '27'
# The number of slots that will be allocated to each connection
BLE_LL_CONN_INIT_SLOTS:
description: >
This is the number of "slots" allocated to a connection when scheduling
connections. Each slot is 1.25 msecs long. Note that a connection event may
last longer than the number of slots allocated here and may also end earlier
(depending on when the next scheduled event occurs and how much data needs
to be transferred in the connection). However, you will be guaranteed that
a connection event will be given this much time, if needed. Consecutively
scheduled items will be at least this far apart
value: '4'
BLE_LL_CONN_INIT_MIN_WIN_OFFSET:
description: >
This is the minimum number of "slots" for WindowOffset value used for
CONNECT_IND when creating new connection as a master. Each slot is 1.25
msecs long. Increasing this value will delay first connection event after
connection is created. However, older TI CC254x controllers cannot change
connection parameters later if WindowOffset was set to 0 in CONNECT_IND. To
ensure interoperability with such devices set this value to 2 (or more).
value: '0'
# Strict scheduling
BLE_LL_STRICT_CONN_SCHEDULING:
description: >
Forces the scheduler on a central to schedule connections in fixed
time intervals called periods. If set to 0, the scheduler is not forced
to do this. If set to 1, the scheduler will only schedule connections at
period boundaries. See comments in ble_ll_sched.h for more details.
value: '0'
BLE_LL_ADD_STRICT_SCHED_PERIODS:
description: >
The number of additional periods that will be allocated for strict
scheduling. The total # of periods allocated for strict scheduling
will be equal to the number of connections plus this number.
value: '0'
BLE_LL_USECS_PER_PERIOD:
description: >
The number of usecs per period.
value: '3250'
# The number of random bytes to store
BLE_LL_RNG_BUFSIZE:
description: >
The number of random bytes that the link layer will try to
always have available for the host to use. Decreasing this
value may cause host delays if the host needs lots of random
material often.
value: '32'
BLE_LL_RFMGMT_ENABLE_TIME:
description: >
Time required for radio and/or related components to be fully
enabled before any request from LL is sent. This value is used
by rfmgmt to enable PHY in advance, before request from LL is
made. It depends on radio driver selected and may also depend
on hardware used:
- nrf51 - time required for XTAL to settle
- nrf52 - time required for XTAL to settle
Value is specified in microseconds. If set to 0, rfmgmt keeps
PHY enabled all the time.
value: MYNEWT_VAL(BLE_XTAL_SETTLE_TIME)
# Configuration for LL supported features.
#
# There are a total 8 features that the LL can support. These can be found
# in v4.2, Vol 6 Part B Section 4.6.
#
# These feature definitions are used to inform a host or other controller
# about the LL features supported by the controller.
#
# NOTE: 'the' controller always supports extended reject indicate and thus
# is not listed here.
BLE_LL_CFG_FEAT_LE_ENCRYPTION:
description: >
This option enables/disables encryption support in the controller.
This option saves both both code and RAM.
value: '1'
BLE_LL_CFG_FEAT_CONN_PARAM_REQ:
description: >
This option enables/disables the connection parameter request
procedure. This is implemented in the controller but is disabled
by default.
value: '1'
BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG:
description: >
This option allows a slave to initiate the feature exchange
procedure. This feature is implemented but currently has no impact
on code or ram size
value: '1'
BLE_LL_CFG_FEAT_LE_PING:
description: >
This option allows a controller to send/receive LE pings.
Currently, this feature is not implemented by the controller so
turning it on or off has no effect.
value: 'MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION'
BLE_LL_CFG_FEAT_DATA_LEN_EXT:
description: >
This option enables/disables the data length update procedure in
the controller. If enabled, the controller is allowed to change the
size of tx/rx pdu's used in a connection. This option has only
minor impact on code size and non on RAM.
value: '1'
BLE_LL_CFG_FEAT_LL_PRIVACY:
description: >
This option is used to enable/disable LL privacy.
value: '1'
BLE_LL_CFG_FEAT_LE_CSA2:
description: >
This option is used to enable/disable support for LE Channel
Selection Algorithm #2.
value: '0'
BLE_LL_CFG_FEAT_LE_2M_PHY:
description: >
This option is used to enable/disable support for the 2Mbps PHY.
value: '0'
BLE_LL_CFG_FEAT_LE_CODED_PHY:
description: >
This option is used to enable/disable support for the coded PHY.
value: '0'
BLE_LL_CFG_FEAT_LL_EXT_ADV:
description: >
This option is used to enable/disable support for Extended
Advertising Feature. That means extended scanner, advertiser
and connect.
value: MYNEWT_VAL(BLE_EXT_ADV)
BLE_LL_CFG_FEAT_LL_PERIODIC_ADV:
description: >
This option is used to enable/disable support for Periodic
Advertising Feature.
value: MYNEWT_VAL(BLE_PERIODIC_ADV)
BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_CNT:
description: >
This option is used to configure number of supported periodic syncs.
value: MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS)
BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_LIST_CNT:
description: >
Size of Periodic Advertiser sync list.
value: MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS)
BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER:
description: >
This option is use to enable/disable support for Periodic
Advertising Sync Transfer Feature.
value: MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
BLE_LL_EXT_ADV_AUX_PTR_CNT:
description: >
This option configure a max number of scheduled outstanding auxiliary
packets for receive on secondary advertising channel.
value: 0
BLE_PUBLIC_DEV_ADDR:
description: >
Allows the target or app to override the public device address
used by the controller. If all zero, the controller will
attempt to retrieve the public device address from its
chip specific location. If non-zero, this address will
be used.
value: "(uint8_t[6]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
BLE_LL_DTM:
description: >
Enables HCI Test commands needed for Bluetooth SIG certification
value: MYNEWT_VAL(BLE_LL_DIRECT_TEST_MODE)
BLE_LL_DTM_EXTENSIONS:
description: >
Enables non-standard extensions to HCI test commands. Once enabled,
HCI_LE_Transmitter_Test accepts extra parameters in addition to
those defined in Core specification
interval (2 octets) interval between packets (usecs), overrides
standard interval
pkt_count (2 octets) number of packets to transmit, controller
will automatically stop sending packets
after given number of packets was sent
Setting either of these parameters to 0 will configure for default
behavior, as per Core specification.
If specified interval is shorter then allowed by specification it
will be ignored.
Extended parameters shall immediately follow standard parameters.
Controller can accept both standard and extended version of command
depending on specified HCI command length.
value: 0
BLE_LL_VND_EVENT_ON_ASSERT:
description: >
This options enables controller to send a vendor-specific event on
an assertion in controller code. The event contains file name and
line number where assertion occured.
value: 0
BLE_LL_SYSINIT_STAGE:
description: >
Sysinit stage for the NimBLE controller.
value: 250
BLE_LL_DEBUG_GPIO_HCI_CMD:
description: >
GPIO pin number to debug HCI commands flow. Pin is set to high state
when HCI command is being processed.
value: -1
BLE_LL_DEBUG_GPIO_HCI_EV:
description: >
GPIO pin number to debug HCI events flow. Pin is set to high state
when HCI event is being sent.
value: -1
BLE_LL_DEBUG_GPIO_SCHED_RUN:
description: >
GPIO pin number to debug scheduler running (on timer). Pin is set
to high state while scheduler is running.
value: -1
BLE_LL_DEBUG_GPIO_SCHED_ITEM_CB:
description: >
GPIO pin number to debug scheduler item execution times. Pin is set
to high state while item is executed.
value: -1
# Below settings allow to change scheduler timings. These should be left at
# default values unless you know what you are doing!
BLE_LL_SCHED_AUX_MAFS_DELAY:
description: >
Additional delay [us] between last ADV_EXT_IND and AUX_ADV_IND PDUs
when scheduling extended advertising event. This extends T_MAFS.
value: 0
BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY:
description: >
Additional delay [us] between consecutive AUX_CHAIN_IND PDUs
when scheduling extended or periodic advertising event. This extends
T_MAFS.
value: 0
BLE_LL_SCHED_SCAN_AUX_PDU_LEN:
description: >
This is expected PDU len for AUX_ADV_IND and subsequent
AUX_CHAIN_IND. When scheduling scan scheduler will reserve time for
receiving this amount of time. Setting this to high value improves
reception of large PDUs but results in wasting scheduler space when
receiving small PDUs only. On the other hand too low value can
result in not being able to scan whole PDU due to being preempted
by next scheduled item. By default size matching legacy ADV_IND PDU
payload is used: ExtHeader (Flags, AdvA, ADI) + 31 bytes of data.
range: 1..257
value: 41
BLE_LL_SCHED_SCAN_SYNC_PDU_LEN:
description: >
This is expected PDU len for AUX_SYNC_IND and subsequent
AUX_CHAIN_IND. When scheduling scan scheduler will reserve time for
receiving this amount of time. Setting this to high value improves
reception of large PDUs but results in wasting scheduler space when
receiving small PDUs only. On the other hand too low value can
result in not being able to scan whole PDU due to being preempted
by next scheduled item. By default size matching PDU with legacy
data size is used: ExtHeader + 31 bytes of data.
range: 1..257
value: 32
# deprecated settings (to be defunct/removed eventually)
BLE_LL_DIRECT_TEST_MODE:
description: use BLE_LL_DTM instead
value: 0
deprecated: 1
BLE_XTAL_SETTLE_TIME:
description: use BLE_LL_RFMGMT_ENABLE_TIME instead
value: 0
deprecated: 1
# defunct settings (to be removed eventually)
BLE_DEVICE:
description: Superseded by BLE_CONTROLLER
value: 1
defunct: 1
BLE_LP_CLOCK:
description: Superseded by BLE_CONTROLLER
value: 1
defunct: 1
BLE_NUM_COMP_PKT_RATE:
description: Superseded by BLE_LL_NUM_COMP_PKT_ITVL_MS
value: '(2 * OS_TICKS_PER_SEC)'
defunct: 1
syscfg.vals.BLE_LL_CFG_FEAT_LL_EXT_ADV:
BLE_LL_CFG_FEAT_LE_CSA2: 1
BLE_HW_WHITELIST_ENABLE: 0
BLE_LL_EXT_ADV_AUX_PTR_CNT: 5
# Enable vendor event on assert in standalone build to make failed assertions in
# controller code visible when connected to external host
syscfg.vals.!BLE_HOST:
BLE_LL_VND_EVENT_ON_ASSERT: 1
syscfg.restrictions:
- OS_CPUTIME_FREQ == 32768

View File

@@ -0,0 +1,34 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
pkg.name: nimble/controller/test
pkg.type: unittest
pkg.description: "NimBLE controller unit tests."
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
pkg.deps:
- "@apache-mynewt-core/test/testutil"
- nimble/controller
pkg.deps.SELFTEST:
- "@apache-mynewt-core/sys/console/stub"
- "@apache-mynewt-core/sys/log/full"
- "@apache-mynewt-core/sys/stats/stub"
- nimble/drivers/native
- nimble/transport/ram

View File

@@ -0,0 +1,115 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <string.h>
#include "testutil/testutil.h"
#include "controller/ble_ll_test.h"
#include "controller/ble_ll_conn.h"
#include "ble_ll_csa2_test.h"
TEST_CASE_SELF(ble_ll_csa2_test_1)
{
struct ble_ll_conn_sm conn;
uint8_t rc;
/*
* Note: This test only verified mapped channel. Sample data also specifies
* prn_e and unmapped channel values but those would require extra access
* to internal state of algorithm which is not exposed.
*/
memset(&conn, 0, sizeof(conn));
CONN_F_CSA2_SUPP(&conn) = 1;
/*
* based on sample data from CoreSpec 5.0 Vol 6 Part C 3.1
* (all channels used)
*/
conn.channel_id = ((0x8e89bed6 & 0xffff0000) >> 16) ^
(0x8e89bed6 & 0x0000ffff);
conn.num_used_chans = 37;
conn.chanmap[0] = 0xff;
conn.chanmap[1] = 0xff;
conn.chanmap[2] = 0xff;
conn.chanmap[3] = 0xff;
conn.chanmap[4] = 0x1f;
conn.event_cntr = 1;
rc = ble_ll_conn_calc_dci(&conn, 0);
TEST_ASSERT(rc == 20);
conn.event_cntr = 2;
rc = ble_ll_conn_calc_dci(&conn, 0);
TEST_ASSERT(rc == 6);
conn.event_cntr = 3;
rc = ble_ll_conn_calc_dci(&conn, 0);
TEST_ASSERT(rc == 21);
}
TEST_CASE_SELF(ble_ll_csa2_test_2)
{
struct ble_ll_conn_sm conn;
uint8_t rc;
/*
* Note: This test only verified mapped channel. Sample data also specifies
* prn_e and unmapped channel values but those would require extra access
* to internal state of algorithm which is not exposed.
*/
memset(&conn, 0, sizeof(conn));
CONN_F_CSA2_SUPP(&conn) = 1;
/*
* based on sample data from CoreSpec 5.0 Vol 6 Part C 3.2
* (9 channels used)
*/
conn.channel_id = ((0x8e89bed6 & 0xffff0000) >> 16) ^
(0x8e89bed6 & 0x0000ffff);
conn.num_used_chans = 9;
conn.chanmap[0] = 0x00;
conn.chanmap[1] = 0x06;
conn.chanmap[2] = 0xe0;
conn.chanmap[3] = 0x00;
conn.chanmap[4] = 0x1e;
conn.event_cntr = 6;
rc = ble_ll_conn_calc_dci(&conn, 0);
TEST_ASSERT(rc == 23);
conn.event_cntr = 7;
rc = ble_ll_conn_calc_dci(&conn, 0);
TEST_ASSERT(rc == 9);
conn.event_cntr = 8;
rc = ble_ll_conn_calc_dci(&conn, 0);
TEST_ASSERT(rc == 34);
}
TEST_SUITE(ble_ll_csa2_test_suite)
{
ble_ll_csa2_test_1();
ble_ll_csa2_test_2();
}

View File

@@ -0,0 +1,27 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_LL_CSA2_TEST_
#define H_BLE_LL_CSA2_TEST_
#include "testutil/testutil.h"
TEST_SUITE_DECL(ble_ll_csa2_test_suite);
#endif

View File

@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 "sysinit/sysinit.h"
#include "syscfg/syscfg.h"
#include "controller/ble_ll_test.h"
#include "os/os.h"
#include "testutil/testutil.h"
#include "ble_ll_csa2_test.h"
#if MYNEWT_VAL(SELFTEST)
int
main(int argc, char **argv)
{
ble_ll_csa2_test_suite();
return tu_any_failed;
}
#endif

View File

@@ -0,0 +1,25 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
syscfg.vals:
BLE_LL_CFG_FEAT_LE_CSA2: 1
# Prevent priority conflict with controller task.
MCU_TIMER_POLLER_PRIO: 1
MCU_UART_POLLER_PRIO: 2
NATIVE_SOCKETS_PRIO: 3

View File

@@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_XCVR_
#define H_BLE_XCVR_
#ifdef __cplusplus
extern "C" {
#endif
/* Transceiver specific defintions */
#define XCVR_RX_START_DELAY_USECS (140)
#define XCVR_TX_START_DELAY_USECS (140)
#define XCVR_PROC_DELAY_USECS (100)
#define XCVR_TX_SCHED_DELAY_USECS \
(XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
#define XCVR_RX_SCHED_DELAY_USECS \
(XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
/*
* Define HW whitelist size. This is the total possible whitelist size;
* not necessarily the size that will be used (may be smaller)
*/
#define BLE_HW_WHITE_LIST_SIZE (0)
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_XCVR_ */

View File

@@ -0,0 +1,30 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
pkg.name: nimble/drivers/native
pkg.description: BLE driver for simulations.
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
- ble
- bluetooth
pkg.apis: ble_driver
pkg.deps:
- nimble/controller

View File

@@ -0,0 +1,239 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include <string.h>
#include "syscfg/syscfg.h"
#include "os/os.h"
#include "nimble/ble.h"
#include "nimble/nimble_opt.h"
#include "controller/ble_hw.h"
/* Total number of white list elements supported by nrf52 */
#define BLE_HW_WHITE_LIST_SIZE (0)
/* We use this to keep track of which entries are set to valid addresses */
static uint8_t g_ble_hw_whitelist_mask;
/* Returns public device address or -1 if not present */
int
ble_hw_get_public_addr(ble_addr_t *addr)
{
return -1;
}
/* Returns random static address or -1 if not present */
int
ble_hw_get_static_addr(ble_addr_t *addr)
{
return -1;
}
/**
* Clear the whitelist
*
* @return int
*/
void
ble_hw_whitelist_clear(void)
{
g_ble_hw_whitelist_mask = 0;
}
/**
* Add a device to the hw whitelist
*
* @param addr
* @param addr_type
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type)
{
return BLE_ERR_MEM_CAPACITY;
}
/**
* Remove a device from the hw whitelist
*
* @param addr
* @param addr_type
*
*/
void
ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type)
{
return;
}
/**
* Returns the size of the whitelist in HW
*
* @return int Number of devices allowed in whitelist
*/
uint8_t
ble_hw_whitelist_size(void)
{
return BLE_HW_WHITE_LIST_SIZE;
}
/**
* Enable the whitelisted devices
*/
void
ble_hw_whitelist_enable(void)
{
return;
}
/**
* Disables the whitelisted devices
*/
void
ble_hw_whitelist_disable(void)
{
return;
}
/**
* Boolean function which returns true ('1') if there is a match on the
* whitelist.
*
* @return int
*/
int
ble_hw_whitelist_match(void)
{
return 0;
}
/* Encrypt data */
int
ble_hw_encrypt_block(struct ble_encryption_block *ecb)
{
return -1;
}
/**
* Initialize the random number generator
*
* @param cb
* @param bias
*
* @return int
*/
int
ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
{
return -1;
}
/**
* Start the random number generator
*
* @return int
*/
int
ble_hw_rng_start(void)
{
return -1;
}
/**
* Stop the random generator
*
* @return int
*/
int
ble_hw_rng_stop(void)
{
return -1;
}
/**
* Read the random number generator.
*
* @return uint8_t
*/
uint8_t
ble_hw_rng_read(void)
{
return 0;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
/**
* Clear the resolving list
*
* @return int
*/
void
ble_hw_resolv_list_clear(void)
{
}
/**
* Add a device to the hw resolving list
*
* @param irk Pointer to IRK to add
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_hw_resolv_list_add(uint8_t *irk)
{
return BLE_ERR_MEM_CAPACITY;
}
/**
* Remove a device from the hw resolving list
*
* @param index Index of IRK to remove
*/
void
ble_hw_resolv_list_rmv(int index)
{
}
/**
* Returns the size of the resolving list. NOTE: this returns the maximum
* allowable entries in the HW. Configuration options may limit this.
*
* @return int Number of devices allowed in resolving list
*/
uint8_t
ble_hw_resolv_list_size(void)
{
return 0;
}
/**
* Called to determine if the address received was resolved.
*
* @return int Negative values indicate unresolved address; positive values
* indicate index in resolving list of resolved address.
*/
int
ble_hw_resolv_list_match(void)
{
return -1;
}
#endif

View File

@@ -0,0 +1,652 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include "syscfg/syscfg.h"
#include "os/os.h"
#include "ble/xcvr.h"
#include "nimble/ble.h"
#include "nimble/nimble_opt.h"
#include "controller/ble_phy.h"
#include "controller/ble_ll.h"
/* BLE PHY data structure */
struct ble_phy_obj
{
uint8_t phy_stats_initialized;
int8_t phy_txpwr_dbm;
int16_t rx_pwr_compensation;
uint8_t phy_chan;
uint8_t phy_state;
uint8_t phy_transition;
uint8_t phy_rx_started;
uint8_t phy_encrypted;
uint8_t phy_privacy;
uint8_t phy_tx_pyld_len;
uint32_t phy_aar_scratch;
uint32_t phy_access_address;
struct ble_mbuf_hdr rxhdr;
void *txend_arg;
uint8_t *rxdptr;
ble_phy_tx_end_func txend_cb;
};
struct ble_phy_obj g_ble_phy_data;
/* Statistics */
struct ble_phy_statistics
{
uint32_t tx_good;
uint32_t tx_fail;
uint32_t tx_late;
uint32_t tx_bytes;
uint32_t rx_starts;
uint32_t rx_aborts;
uint32_t rx_valid;
uint32_t rx_crc_err;
uint32_t phy_isrs;
uint32_t radio_state_errs;
uint32_t no_bufs;
};
struct ble_phy_statistics g_ble_phy_stats;
static uint8_t g_ble_phy_tx_buf[BLE_PHY_MAX_PDU_LEN];
/* XCVR object to emulate transceiver */
struct xcvr_data
{
uint32_t irq_status;
};
static struct xcvr_data g_xcvr_data;
#define BLE_XCVR_IRQ_F_RX_START (0x00000001)
#define BLE_XCVR_IRQ_F_RX_END (0x00000002)
#define BLE_XCVR_IRQ_F_TX_START (0x00000004)
#define BLE_XCVR_IRQ_F_TX_END (0x00000008)
#define BLE_XCVR_IRQ_F_BYTE_CNTR (0x00000010)
/* "Rail" power level if outside supported range */
#define BLE_XCVR_TX_PWR_MAX_DBM (30)
#define BLE_XCVR_TX_PWR_MIN_DBM (-20)
/* Statistics */
STATS_SECT_START(ble_phy_stats)
STATS_SECT_ENTRY(phy_isrs)
STATS_SECT_ENTRY(tx_good)
STATS_SECT_ENTRY(tx_fail)
STATS_SECT_ENTRY(tx_late)
STATS_SECT_ENTRY(tx_bytes)
STATS_SECT_ENTRY(rx_starts)
STATS_SECT_ENTRY(rx_aborts)
STATS_SECT_ENTRY(rx_valid)
STATS_SECT_ENTRY(rx_crc_err)
STATS_SECT_ENTRY(rx_late)
STATS_SECT_ENTRY(no_bufs)
STATS_SECT_ENTRY(radio_state_errs)
STATS_SECT_ENTRY(rx_hw_err)
STATS_SECT_ENTRY(tx_hw_err)
STATS_SECT_END
STATS_SECT_DECL(ble_phy_stats) ble_phy_stats;
STATS_NAME_START(ble_phy_stats)
STATS_NAME(ble_phy_stats, phy_isrs)
STATS_NAME(ble_phy_stats, tx_good)
STATS_NAME(ble_phy_stats, tx_fail)
STATS_NAME(ble_phy_stats, tx_late)
STATS_NAME(ble_phy_stats, tx_bytes)
STATS_NAME(ble_phy_stats, rx_starts)
STATS_NAME(ble_phy_stats, rx_aborts)
STATS_NAME(ble_phy_stats, rx_valid)
STATS_NAME(ble_phy_stats, rx_crc_err)
STATS_NAME(ble_phy_stats, rx_late)
STATS_NAME(ble_phy_stats, no_bufs)
STATS_NAME(ble_phy_stats, radio_state_errs)
STATS_NAME(ble_phy_stats, rx_hw_err)
STATS_NAME(ble_phy_stats, tx_hw_err)
STATS_NAME_END(ble_phy_stats)
/* XXX: TODO:
* 1) Test the following to make sure it works: suppose an event is already
* set to 1 and the interrupt is not enabled. What happens if you enable the
* interrupt with the event bit already set to 1
* 2) how to deal with interrupts?
*/
static uint32_t
ble_xcvr_get_irq_status(void)
{
return g_xcvr_data.irq_status;
}
static void
ble_xcvr_clear_irq(uint32_t mask)
{
g_xcvr_data.irq_status &= ~mask;
}
/**
* Copies the data from the phy receive buffer into a mbuf chain.
*
* @param dptr Pointer to receive buffer
* @param rxpdu Pointer to already allocated mbuf chain
*
* NOTE: the packet header already has the total mbuf length in it. The
* lengths of the individual mbufs are not set prior to calling.
*
*/
void
ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu)
{
uint16_t rem_bytes;
uint16_t mb_bytes;
uint16_t copylen;
uint32_t *dst;
uint32_t *src;
struct os_mbuf *m;
struct ble_mbuf_hdr *ble_hdr;
struct os_mbuf_pkthdr *pkthdr;
/* Better be aligned */
assert(((uint32_t)dptr & 3) == 0);
pkthdr = OS_MBUF_PKTHDR(rxpdu);
rem_bytes = pkthdr->omp_len;
/* Fill in the mbuf pkthdr first. */
dst = (uint32_t *)(rxpdu->om_data);
src = (uint32_t *)dptr;
mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4);
copylen = min(mb_bytes, rem_bytes);
copylen &= 0xFFFC;
rem_bytes -= copylen;
mb_bytes -= copylen;
rxpdu->om_len = copylen;
while (copylen > 0) {
*dst = *src;
++dst;
++src;
copylen -= 4;
}
/* Copy remaining bytes */
m = rxpdu;
while (rem_bytes > 0) {
/* If there are enough bytes in the mbuf, copy them and leave */
if (rem_bytes <= mb_bytes) {
memcpy(m->om_data + m->om_len, src, rem_bytes);
m->om_len += rem_bytes;
break;
}
m = SLIST_NEXT(m, om_next);
assert(m != NULL);
mb_bytes = m->om_omp->omp_databuf_len;
copylen = min(mb_bytes, rem_bytes);
copylen &= 0xFFFC;
rem_bytes -= copylen;
mb_bytes -= copylen;
m->om_len = copylen;
dst = (uint32_t *)m->om_data;
while (copylen > 0) {
*dst = *src;
++dst;
++src;
copylen -= 4;
}
}
/* Copy ble header */
ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr));
}
void
ble_phy_isr(void)
{
int rc;
uint8_t transition;
uint32_t irq_en;
struct ble_mbuf_hdr *ble_hdr;
/* Check for disabled event. This only happens for transmits now */
irq_en = ble_xcvr_get_irq_status();
if (irq_en & BLE_XCVR_IRQ_F_TX_END) {
/* Better be in TX state! */
assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
ble_xcvr_clear_irq(BLE_XCVR_IRQ_F_TX_END);
transition = g_ble_phy_data.phy_transition;
if (transition == BLE_PHY_TRANSITION_TX_RX) {
/* Disable the phy */
/* XXX: count no bufs? */
ble_phy_disable();
} else {
/* Better not be going from rx to tx! */
assert(transition == BLE_PHY_TRANSITION_NONE);
}
}
/* We get this if we have started to receive a frame */
if (irq_en & BLE_XCVR_IRQ_F_RX_START) {
ble_xcvr_clear_irq(BLE_XCVR_IRQ_F_RX_START);
/* Call Link Layer receive start function */
rc = ble_ll_rx_start(g_ble_phy_data.rxdptr, g_ble_phy_data.phy_chan,
&g_ble_phy_data.rxhdr);
if (rc >= 0) {
/* XXX: set rx end enable isr */
} else {
/* Disable PHY */
ble_phy_disable();
irq_en = 0;
++g_ble_phy_stats.rx_aborts;
}
/* Count rx starts */
++g_ble_phy_stats.rx_starts;
}
/* Receive packet end (we dont enable this for transmit) */
if (irq_en & BLE_XCVR_IRQ_F_RX_END) {
ble_xcvr_clear_irq(BLE_XCVR_IRQ_F_RX_END);
/* Construct BLE header before handing up */
ble_hdr = &g_ble_phy_data.rxhdr;
ble_hdr->rxinfo.flags = 0;
/* XXX: dummy rssi */
ble_hdr->rxinfo.rssi = -77 + g_ble_phy_data.rx_pwr_compensation;
ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
ble_hdr->rxinfo.phy = BLE_PHY_1M;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
ble_hdr->rxinfo.aux_data = NULL;
#endif
/* Count PHY valid packets */
++g_ble_phy_stats.rx_valid;
ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK;
/* Call Link Layer receive payload function */
rc = ble_ll_rx_end(g_ble_phy_data.rxdptr, ble_hdr);
if (rc < 0) {
/* Disable the PHY. */
ble_phy_disable();
}
}
/* Count # of interrupts */
++g_ble_phy_stats.phy_isrs;
}
/**
* ble phy init
*
* Initialize the PHY. This is expected to be called once.
*
* @return int 0: success; PHY error code otherwise
*/
int
ble_phy_init(void)
{
/* Set phy channel to an invalid channel so first set channel works */
g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS;
g_ble_phy_data.rx_pwr_compensation = 0;
/* XXX: emulate ISR? */
return 0;
}
int
ble_phy_rx(void)
{
/* Check radio state */
if (ble_phy_state_get() != BLE_PHY_STATE_IDLE) {
ble_phy_disable();
++g_ble_phy_stats.radio_state_errs;
return BLE_PHY_ERR_RADIO_STATE;
}
g_ble_phy_data.phy_state = BLE_PHY_STATE_RX;
return 0;
}
void
ble_phy_restart_rx(void)
{
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
/**
* Called to enable encryption at the PHY. Note that this state will persist
* in the PHY; in other words, if you call this function you have to call
* disable so that future PHY transmits/receives will not be encrypted.
*
* @param pkt_counter
* @param iv
* @param key
* @param is_master
*/
void
ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key,
uint8_t is_master)
{
}
void
ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir)
{
}
void
ble_phy_encrypt_disable(void)
{
}
#endif
void
ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
{
/* Set transmit end callback and arg */
g_ble_phy_data.txend_cb = txend_cb;
g_ble_phy_data.txend_arg = arg;
}
/**
* Called to set the start time of a transmission.
*
* This function is called to set the start time when we are not going from
* rx to tx automatically.
*
* NOTE: care must be taken when calling this function. The channel should
* already be set.
*
* @param cputime
* @param rem_usecs
*
* @return int
*/
int
ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
{
return 0;
}
/**
* Called to set the start time of a reception
*
* This function acts a bit differently than transmit. If we are late getting
* here we will still attempt to receive.
*
* NOTE: care must be taken when calling this function. The channel should
* already be set.
*
* @param cputime
* @param rem_usecs
*
* @return int
*/
int
ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
{
return 0;
}
int
ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans)
{
uint8_t hdr_byte;
int rc;
if (ble_phy_state_get() != BLE_PHY_STATE_IDLE) {
ble_phy_disable();
++g_ble_phy_stats.radio_state_errs;
return BLE_PHY_ERR_RADIO_STATE;
}
/* Select tx address */
if (g_ble_phy_data.phy_chan < BLE_PHY_NUM_DATA_CHANS) {
/* XXX: fix this */
assert(0);
} else {
}
/* Set the PHY transition */
g_ble_phy_data.phy_transition = end_trans;
/* Set phy state to transmitting and count packet statistics */
g_ble_phy_data.phy_state = BLE_PHY_STATE_TX;
++g_ble_phy_stats.tx_good;
g_ble_phy_stats.tx_bytes += pducb(g_ble_phy_tx_buf, pducb_arg, &hdr_byte) +
BLE_LL_PDU_HDR_LEN;
rc = BLE_ERR_SUCCESS;
return rc;
}
/**
* ble phy txpwr set
*
* Set the transmit output power (in dBm).
*
* NOTE: If the output power specified is within the BLE limits but outside
* the chip limits, we "rail" the power level so we dont exceed the min/max
* chip values.
*
* @param dbm Power output in dBm.
*
* @return int 0: success; anything else is an error
*/
int
ble_phy_txpwr_set(int dbm)
{
/* Check valid range */
assert(dbm <= BLE_PHY_MAX_PWR_DBM);
/* "Rail" power level if outside supported range */
if (dbm > BLE_XCVR_TX_PWR_MAX_DBM) {
dbm = BLE_XCVR_TX_PWR_MAX_DBM;
} else {
if (dbm < BLE_XCVR_TX_PWR_MIN_DBM) {
dbm = BLE_XCVR_TX_PWR_MIN_DBM;
}
}
g_ble_phy_data.phy_txpwr_dbm = dbm;
return 0;
}
/**
* ble phy txpwr round
*
* Get the rounded transmit output power (in dBm).
*
* @param dbm Power output in dBm.
*
* @return int Rounded power in dBm
*/
int ble_phy_txpower_round(int dbm)
{
/* "Rail" power level if outside supported range */
if (dbm > BLE_XCVR_TX_PWR_MAX_DBM) {
dbm = BLE_XCVR_TX_PWR_MAX_DBM;
} else {
if (dbm < BLE_XCVR_TX_PWR_MIN_DBM) {
dbm = BLE_XCVR_TX_PWR_MIN_DBM;
}
}
return dbm;
}
/**
* ble phy txpwr get
*
* Get the transmit power.
*
* @return int The current PHY transmit power, in dBm
*/
int
ble_phy_txpwr_get(void)
{
return g_ble_phy_data.phy_txpwr_dbm;
}
void
ble_phy_set_rx_pwr_compensation(int8_t compensation)
{
g_ble_phy_data.rx_pwr_compensation = compensation;
}
/**
* ble phy setchan
*
* Sets the logical frequency of the transceiver. The input parameter is the
* BLE channel index (0 to 39, inclusive). The NRF52 frequency register
* works like this: logical frequency = 2400 + FREQ (MHz).
*
* Thus, to get a logical frequency of 2402 MHz, you would program the
* FREQUENCY register to 2.
*
* @param chan This is the Data Channel Index or Advertising Channel index
*
* @return int 0: success; PHY error code otherwise
*/
int
ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit)
{
assert(chan < BLE_PHY_NUM_CHANS);
/* Check for valid channel range */
if (chan >= BLE_PHY_NUM_CHANS) {
return BLE_PHY_ERR_INV_PARAM;
}
g_ble_phy_data.phy_access_address = access_addr;
g_ble_phy_data.phy_chan = chan;
return 0;
}
/**
* Disable the PHY. This will do the following:
* -> Turn off all phy interrupts.
* -> Disable internal shortcuts.
* -> Disable the radio.
* -> Sets phy state to idle.
*/
void
ble_phy_disable(void)
{
g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
}
/* Gets the current access address */
uint32_t ble_phy_access_addr_get(void)
{
return g_ble_phy_data.phy_access_address;
}
/**
* Return the phy state
*
* @return int The current PHY state.
*/
int
ble_phy_state_get(void)
{
return g_ble_phy_data.phy_state;
}
/**
* Called to see if a reception has started
*
* @return int
*/
int
ble_phy_rx_started(void)
{
return g_ble_phy_data.phy_rx_started;
}
/**
* Called to return the maximum data pdu payload length supported by the
* phy. For this chip, if encryption is enabled, the maximum payload is 27
* bytes.
*
* @return uint8_t Maximum data channel PDU payload size supported
*/
uint8_t
ble_phy_max_data_pdu_pyld(void)
{
return BLE_LL_DATA_PDU_MAX_PYLD;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
void
ble_phy_resolv_list_enable(void)
{
g_ble_phy_data.phy_privacy = 1;
}
void
ble_phy_resolv_list_disable(void)
{
g_ble_phy_data.phy_privacy = 0;
}
/**
* Return the transceiver state
*
* @return int transceiver state.
*/
uint8_t
ble_phy_xcvr_state_get(void)
{
return g_ble_phy_data.phy_state;
}
#endif
void
ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs)
{
}
void
ble_phy_rfclk_enable(void)
{
}
void
ble_phy_rfclk_disable(void)
{
}

View File

@@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_XCVR_
#define H_BLE_XCVR_
#ifdef __cplusplus
extern "C" {
#endif
/* Transceiver specific defintions */
/* NOTE: we have to account for the RTC output compare issue */
#define XCVR_PROC_DELAY_USECS (230)
#define XCVR_RX_START_DELAY_USECS (140)
#define XCVR_TX_START_DELAY_USECS (140)
#define XCVR_TX_SCHED_DELAY_USECS \
(XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
#define XCVR_RX_SCHED_DELAY_USECS \
(XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
/*
* Define HW whitelist size. This is the total possible whitelist size;
* not necessarily the size that will be used (may be smaller)
*/
#define BLE_HW_WHITE_LIST_SIZE (8)
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_XCVR_ */

View File

@@ -0,0 +1,31 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
pkg.name: nimble/drivers/nrf51
pkg.description: BLE driver for nRF51 systems.
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
- ble
- bluetooth
pkg.apis: ble_driver
pkg.deps:
- nimble
- nimble/controller

View File

@@ -0,0 +1,488 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include <string.h>
#include "syscfg/syscfg.h"
#include "os/os.h"
#include "ble/xcvr.h"
#include "nimble/ble.h"
#include "nimble/nimble_opt.h"
#include "nrfx.h"
#include "controller/ble_hw.h"
#if MYNEWT
#include "mcu/cmsis_nvic.h"
#else
#include "core_cm0.h"
#include <nimble/nimble_npl_os.h>
#endif
#include "os/os_trace_api.h"
/* Total number of resolving list elements */
#define BLE_HW_RESOLV_LIST_SIZE (16)
/* We use this to keep track of which entries are set to valid addresses */
static uint8_t g_ble_hw_whitelist_mask;
/* Random number generator isr callback */
ble_rng_isr_cb_t g_ble_rng_isr_cb;
/* If LL privacy is enabled, allocate memory for AAR */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
/* The NRF51 supports up to 16 IRK entries */
#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16)
#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
#else
#define NRF_IRK_LIST_ENTRIES (16)
#endif
/* NOTE: each entry is 16 bytes long. */
uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4];
/* Current number of IRK entries */
uint8_t g_nrf_num_irks;
#endif
/* Returns public device address or -1 if not present */
int
ble_hw_get_public_addr(ble_addr_t *addr)
{
uint32_t addr_high;
uint32_t addr_low;
/* Does FICR have a public address */
if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) {
return -1;
}
/* Copy into device address. We can do this because we know platform */
addr_low = NRF_FICR->DEVICEADDR[0];
addr_high = NRF_FICR->DEVICEADDR[1];
memcpy(addr->val, &addr_low, 4);
memcpy(&addr->val[4], &addr_high, 2);
addr->type = BLE_ADDR_PUBLIC;
return 0;
}
/* Returns random static address or -1 if not present */
int
ble_hw_get_static_addr(ble_addr_t *addr)
{
int rc;
if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) {
memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4);
memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2);
addr->val[5] |= 0xc0;
addr->type = BLE_ADDR_RANDOM;
rc = 0;
} else {
rc = -1;
}
return rc;
}
/**
* Clear the whitelist
*
* @return int
*/
void
ble_hw_whitelist_clear(void)
{
NRF_RADIO->DACNF = 0;
g_ble_hw_whitelist_mask = 0;
}
/**
* Add a device to the hw whitelist
*
* @param addr
* @param addr_type
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type)
{
int i;
uint32_t mask;
/* Find first ununsed device address match element */
mask = 0x01;
for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
if ((mask & g_ble_hw_whitelist_mask) == 0) {
NRF_RADIO->DAB[i] = get_le32(addr);
NRF_RADIO->DAP[i] = get_le16(addr + 4);
if (addr_type == BLE_ADDR_RANDOM) {
NRF_RADIO->DACNF |= (mask << 8);
}
g_ble_hw_whitelist_mask |= mask;
return BLE_ERR_SUCCESS;
}
mask <<= 1;
}
return BLE_ERR_MEM_CAPACITY;
}
/**
* Remove a device from the hw whitelist
*
* @param addr
* @param addr_type
*
*/
void
ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type)
{
int i;
uint8_t cfg_addr;
uint16_t dap;
uint16_t txadd;
uint32_t dab;
uint32_t mask;
/* Find first ununsed device address match element */
dab = get_le32(addr);
dap = get_le16(addr + 4);
txadd = NRF_RADIO->DACNF >> 8;
mask = 0x01;
for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
if (mask & g_ble_hw_whitelist_mask) {
if ((dab == NRF_RADIO->DAB[i]) && (dap == NRF_RADIO->DAP[i])) {
cfg_addr = txadd & mask;
if (addr_type == BLE_ADDR_RANDOM) {
if (cfg_addr != 0) {
break;
}
} else {
if (cfg_addr == 0) {
break;
}
}
}
}
mask <<= 1;
}
if (i < BLE_HW_WHITE_LIST_SIZE) {
g_ble_hw_whitelist_mask &= ~mask;
NRF_RADIO->DACNF &= ~mask;
}
}
/**
* Returns the size of the whitelist in HW
*
* @return int Number of devices allowed in whitelist
*/
uint8_t
ble_hw_whitelist_size(void)
{
return BLE_HW_WHITE_LIST_SIZE;
}
/**
* Enable the whitelisted devices
*/
void
ble_hw_whitelist_enable(void)
{
/* Enable the configured device addresses */
NRF_RADIO->DACNF |= g_ble_hw_whitelist_mask;
}
/**
* Disables the whitelisted devices
*/
void
ble_hw_whitelist_disable(void)
{
/* Disable all whitelist devices */
NRF_RADIO->DACNF &= 0x0000ff00;
}
/**
* Boolean function which returns true ('1') if there is a match on the
* whitelist.
*
* @return int
*/
int
ble_hw_whitelist_match(void)
{
return (int)NRF_RADIO->EVENTS_DEVMATCH;
}
/* Encrypt data */
int
ble_hw_encrypt_block(struct ble_encryption_block *ecb)
{
int rc;
uint32_t end;
uint32_t err;
/* Stop ECB */
NRF_ECB->TASKS_STOPECB = 1;
/* XXX: does task stop clear these counters? Anyway to do this quicker? */
NRF_ECB->EVENTS_ENDECB = 0;
NRF_ECB->EVENTS_ERRORECB = 0;
NRF_ECB->ECBDATAPTR = (uint32_t)ecb;
/* Start ECB */
NRF_ECB->TASKS_STARTECB = 1;
/* Wait till error or done */
rc = 0;
while (1) {
end = NRF_ECB->EVENTS_ENDECB;
err = NRF_ECB->EVENTS_ERRORECB;
if (end || err) {
if (err) {
rc = -1;
}
break;
}
}
return rc;
}
/**
* Random number generator ISR.
*/
static void
ble_rng_isr(void)
{
uint8_t rnum;
os_trace_isr_enter();
/* No callback? Clear and disable interrupts */
if (g_ble_rng_isr_cb == NULL) {
NRF_RNG->INTENCLR = 1;
NRF_RNG->EVENTS_VALRDY = 0;
(void)NRF_RNG->SHORTS;
os_trace_isr_exit();
return;
}
/* If there is a value ready grab it */
if (NRF_RNG->EVENTS_VALRDY) {
NRF_RNG->EVENTS_VALRDY = 0;
rnum = (uint8_t)NRF_RNG->VALUE;
(*g_ble_rng_isr_cb)(rnum);
}
os_trace_isr_exit();
}
/**
* Initialize the random number generator
*
* @param cb
* @param bias
*
* @return int
*/
int
ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
{
/* Set bias */
if (bias) {
NRF_RNG->CONFIG = 1;
} else {
NRF_RNG->CONFIG = 0;
}
/* If we were passed a function pointer we need to enable the interrupt */
if (cb != NULL) {
#ifndef RIOT_VERSION
NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
#endif
#if MYNEWT
NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr);
#else
ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr);
#endif
NVIC_EnableIRQ(RNG_IRQn);
g_ble_rng_isr_cb = cb;
}
return 0;
}
/**
* Start the random number generator
*
* @return int
*/
int
ble_hw_rng_start(void)
{
os_sr_t sr;
/* No need for interrupt if there is no callback */
OS_ENTER_CRITICAL(sr);
NRF_RNG->EVENTS_VALRDY = 0;
if (g_ble_rng_isr_cb) {
NRF_RNG->INTENSET = 1;
}
NRF_RNG->TASKS_START = 1;
OS_EXIT_CRITICAL(sr);
return 0;
}
/**
* Stop the random generator
*
* @return int
*/
int
ble_hw_rng_stop(void)
{
os_sr_t sr;
/* No need for interrupt if there is no callback */
OS_ENTER_CRITICAL(sr);
NRF_RNG->INTENCLR = 1;
NRF_RNG->TASKS_STOP = 1;
NRF_RNG->EVENTS_VALRDY = 0;
OS_EXIT_CRITICAL(sr);
return 0;
}
/**
* Read the random number generator.
*
* @return uint8_t
*/
uint8_t
ble_hw_rng_read(void)
{
uint8_t rnum;
/* Wait for a sample */
while (NRF_RNG->EVENTS_VALRDY == 0) {
}
NRF_RNG->EVENTS_VALRDY = 0;
rnum = (uint8_t)NRF_RNG->VALUE;
return rnum;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
/**
* Clear the resolving list
*
* @return int
*/
void
ble_hw_resolv_list_clear(void)
{
g_nrf_num_irks = 0;
}
/**
* Add a device to the hw resolving list
*
* @param irk Pointer to IRK to add
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_hw_resolv_list_add(uint8_t *irk)
{
uint32_t *nrf_entry;
/* Find first ununsed device address match element */
if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) {
return BLE_ERR_MEM_CAPACITY;
}
/* Copy into irk list */
nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks];
memcpy(nrf_entry, irk, 16);
/* Add to total */
++g_nrf_num_irks;
return BLE_ERR_SUCCESS;
}
/**
* Remove a device from the hw resolving list
*
* @param index Index of IRK to remove
*/
void
ble_hw_resolv_list_rmv(int index)
{
uint32_t *irk_entry;
if (index < g_nrf_num_irks) {
--g_nrf_num_irks;
irk_entry = &g_nrf_irk_list[index];
if (g_nrf_num_irks > index) {
memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index));
}
}
}
/**
* Returns the size of the resolving list. NOTE: this returns the maximum
* allowable entries in the HW. Configuration options may limit this.
*
* @return int Number of devices allowed in resolving list
*/
uint8_t
ble_hw_resolv_list_size(void)
{
return BLE_HW_RESOLV_LIST_SIZE;
}
/**
* Called to determine if the address received was resolved.
*
* @return int Negative values indicate unresolved address; positive values
* indicate index in resolving list of resolved address.
*/
int
ble_hw_resolv_list_match(void)
{
uint32_t index;
if (NRF_AAR->EVENTS_END) {
if (NRF_AAR->EVENTS_RESOLVED) {
index = NRF_AAR->STATUS;
return (int)index;
}
}
return -1;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_XCVR_
#define H_BLE_XCVR_
#ifdef __cplusplus
extern "C" {
#endif
#define XCVR_RX_RADIO_RAMPUP_USECS (40)
#define XCVR_TX_RADIO_RAMPUP_USECS (40)
/*
* NOTE: we have to account for the RTC output compare issue. We want it to be
* 5 ticks.
*/
#define XCVR_PROC_DELAY_USECS (153)
#define XCVR_RX_START_DELAY_USECS (XCVR_RX_RADIO_RAMPUP_USECS)
#define XCVR_TX_START_DELAY_USECS (XCVR_TX_RADIO_RAMPUP_USECS)
#define XCVR_TX_SCHED_DELAY_USECS \
(XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
#define XCVR_RX_SCHED_DELAY_USECS \
(XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
/*
* Define HW whitelist size. This is the total possible whitelist size;
* not necessarily the size that will be used (may be smaller)
*/
#define BLE_HW_WHITE_LIST_SIZE (8)
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_XCVR_ */

View File

@@ -0,0 +1,31 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
pkg.name: nimble/drivers/nrf52
pkg.description: BLE driver for nRF52 systems.
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
- ble
- bluetooth
pkg.apis: ble_driver
pkg.deps:
- nimble
- nimble/controller

View File

@@ -0,0 +1,488 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include <string.h>
#include "syscfg/syscfg.h"
#include "os/os.h"
#include "ble/xcvr.h"
#include "nimble/ble.h"
#include "nimble/nimble_opt.h"
#include "nrfx.h"
#include "controller/ble_hw.h"
#if MYNEWT
#include "mcu/cmsis_nvic.h"
#else
#include "core_cm4.h"
#include <nimble/nimble_npl_os.h>
#endif
#include "os/os_trace_api.h"
/* Total number of resolving list elements */
#define BLE_HW_RESOLV_LIST_SIZE (16)
/* We use this to keep track of which entries are set to valid addresses */
static uint8_t g_ble_hw_whitelist_mask;
/* Random number generator isr callback */
ble_rng_isr_cb_t g_ble_rng_isr_cb;
/* If LL privacy is enabled, allocate memory for AAR */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
/* The NRF51 supports up to 16 IRK entries */
#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16)
#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
#else
#define NRF_IRK_LIST_ENTRIES (16)
#endif
/* NOTE: each entry is 16 bytes long. */
uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4];
/* Current number of IRK entries */
uint8_t g_nrf_num_irks;
#endif
/* Returns public device address or -1 if not present */
int
ble_hw_get_public_addr(ble_addr_t *addr)
{
uint32_t addr_high;
uint32_t addr_low;
/* Does FICR have a public address */
if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) {
return -1;
}
/* Copy into device address. We can do this because we know platform */
addr_low = NRF_FICR->DEVICEADDR[0];
addr_high = NRF_FICR->DEVICEADDR[1];
memcpy(addr->val, &addr_low, 4);
memcpy(&addr->val[4], &addr_high, 2);
addr->type = BLE_ADDR_PUBLIC;
return 0;
}
/* Returns random static address or -1 if not present */
int
ble_hw_get_static_addr(ble_addr_t *addr)
{
int rc;
if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) {
memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4);
memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2);
addr->val[5] |= 0xc0;
addr->type = BLE_ADDR_RANDOM;
rc = 0;
} else {
rc = -1;
}
return rc;
}
/**
* Clear the whitelist
*
* @return int
*/
void
ble_hw_whitelist_clear(void)
{
NRF_RADIO->DACNF = 0;
g_ble_hw_whitelist_mask = 0;
}
/**
* Add a device to the hw whitelist
*
* @param addr
* @param addr_type
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type)
{
int i;
uint32_t mask;
/* Find first ununsed device address match element */
mask = 0x01;
for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
if ((mask & g_ble_hw_whitelist_mask) == 0) {
NRF_RADIO->DAB[i] = get_le32(addr);
NRF_RADIO->DAP[i] = get_le16(addr + 4);
if (addr_type == BLE_ADDR_RANDOM) {
NRF_RADIO->DACNF |= (mask << 8);
}
g_ble_hw_whitelist_mask |= mask;
return BLE_ERR_SUCCESS;
}
mask <<= 1;
}
return BLE_ERR_MEM_CAPACITY;
}
/**
* Remove a device from the hw whitelist
*
* @param addr
* @param addr_type
*
*/
void
ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type)
{
int i;
uint8_t cfg_addr;
uint16_t dap;
uint16_t txadd;
uint32_t dab;
uint32_t mask;
/* Find first ununsed device address match element */
dab = get_le32(addr);
dap = get_le16(addr + 4);
txadd = NRF_RADIO->DACNF >> 8;
mask = 0x01;
for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
if (mask & g_ble_hw_whitelist_mask) {
if ((dab == NRF_RADIO->DAB[i]) && (dap == NRF_RADIO->DAP[i])) {
cfg_addr = txadd & mask;
if (addr_type == BLE_ADDR_RANDOM) {
if (cfg_addr != 0) {
break;
}
} else {
if (cfg_addr == 0) {
break;
}
}
}
}
mask <<= 1;
}
if (i < BLE_HW_WHITE_LIST_SIZE) {
g_ble_hw_whitelist_mask &= ~mask;
NRF_RADIO->DACNF &= ~mask;
}
}
/**
* Returns the size of the whitelist in HW
*
* @return int Number of devices allowed in whitelist
*/
uint8_t
ble_hw_whitelist_size(void)
{
return BLE_HW_WHITE_LIST_SIZE;
}
/**
* Enable the whitelisted devices
*/
void
ble_hw_whitelist_enable(void)
{
/* Enable the configured device addresses */
NRF_RADIO->DACNF |= g_ble_hw_whitelist_mask;
}
/**
* Disables the whitelisted devices
*/
void
ble_hw_whitelist_disable(void)
{
/* Disable all whitelist devices */
NRF_RADIO->DACNF &= 0x0000ff00;
}
/**
* Boolean function which returns true ('1') if there is a match on the
* whitelist.
*
* @return int
*/
int
ble_hw_whitelist_match(void)
{
return (int)NRF_RADIO->EVENTS_DEVMATCH;
}
/* Encrypt data */
int
ble_hw_encrypt_block(struct ble_encryption_block *ecb)
{
int rc;
uint32_t end;
uint32_t err;
/* Stop ECB */
NRF_ECB->TASKS_STOPECB = 1;
/* XXX: does task stop clear these counters? Anyway to do this quicker? */
NRF_ECB->EVENTS_ENDECB = 0;
NRF_ECB->EVENTS_ERRORECB = 0;
NRF_ECB->ECBDATAPTR = (uint32_t)ecb;
/* Start ECB */
NRF_ECB->TASKS_STARTECB = 1;
/* Wait till error or done */
rc = 0;
while (1) {
end = NRF_ECB->EVENTS_ENDECB;
err = NRF_ECB->EVENTS_ERRORECB;
if (end || err) {
if (err) {
rc = -1;
}
break;
}
}
return rc;
}
/**
* Random number generator ISR.
*/
static void
ble_rng_isr(void)
{
uint8_t rnum;
os_trace_isr_enter();
/* No callback? Clear and disable interrupts */
if (g_ble_rng_isr_cb == NULL) {
NRF_RNG->INTENCLR = 1;
NRF_RNG->EVENTS_VALRDY = 0;
(void)NRF_RNG->SHORTS;
os_trace_isr_exit();
return;
}
/* If there is a value ready grab it */
if (NRF_RNG->EVENTS_VALRDY) {
NRF_RNG->EVENTS_VALRDY = 0;
rnum = (uint8_t)NRF_RNG->VALUE;
(*g_ble_rng_isr_cb)(rnum);
}
os_trace_isr_exit();
}
/**
* Initialize the random number generator
*
* @param cb
* @param bias
*
* @return int
*/
int
ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
{
/* Set bias */
if (bias) {
NRF_RNG->CONFIG = 1;
} else {
NRF_RNG->CONFIG = 0;
}
/* If we were passed a function pointer we need to enable the interrupt */
if (cb != NULL) {
#ifndef RIOT_VERSION
NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
#endif
#if MYNEWT
NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr);
#else
ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr);
#endif
NVIC_EnableIRQ(RNG_IRQn);
g_ble_rng_isr_cb = cb;
}
return 0;
}
/**
* Start the random number generator
*
* @return int
*/
int
ble_hw_rng_start(void)
{
os_sr_t sr;
/* No need for interrupt if there is no callback */
OS_ENTER_CRITICAL(sr);
NRF_RNG->EVENTS_VALRDY = 0;
if (g_ble_rng_isr_cb) {
NRF_RNG->INTENSET = 1;
}
NRF_RNG->TASKS_START = 1;
OS_EXIT_CRITICAL(sr);
return 0;
}
/**
* Stop the random generator
*
* @return int
*/
int
ble_hw_rng_stop(void)
{
os_sr_t sr;
/* No need for interrupt if there is no callback */
OS_ENTER_CRITICAL(sr);
NRF_RNG->INTENCLR = 1;
NRF_RNG->TASKS_STOP = 1;
NRF_RNG->EVENTS_VALRDY = 0;
OS_EXIT_CRITICAL(sr);
return 0;
}
/**
* Read the random number generator.
*
* @return uint8_t
*/
uint8_t
ble_hw_rng_read(void)
{
uint8_t rnum;
/* Wait for a sample */
while (NRF_RNG->EVENTS_VALRDY == 0) {
}
NRF_RNG->EVENTS_VALRDY = 0;
rnum = (uint8_t)NRF_RNG->VALUE;
return rnum;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
/**
* Clear the resolving list
*
* @return int
*/
void
ble_hw_resolv_list_clear(void)
{
g_nrf_num_irks = 0;
}
/**
* Add a device to the hw resolving list
*
* @param irk Pointer to IRK to add
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_hw_resolv_list_add(uint8_t *irk)
{
uint32_t *nrf_entry;
/* Find first ununsed device address match element */
if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) {
return BLE_ERR_MEM_CAPACITY;
}
/* Copy into irk list */
nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks];
memcpy(nrf_entry, irk, 16);
/* Add to total */
++g_nrf_num_irks;
return BLE_ERR_SUCCESS;
}
/**
* Remove a device from the hw resolving list
*
* @param index Index of IRK to remove
*/
void
ble_hw_resolv_list_rmv(int index)
{
uint32_t *irk_entry;
if (index < g_nrf_num_irks) {
--g_nrf_num_irks;
irk_entry = &g_nrf_irk_list[index];
if (g_nrf_num_irks > index) {
memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index));
}
}
}
/**
* Returns the size of the resolving list. NOTE: this returns the maximum
* allowable entries in the HW. Configuration options may limit this.
*
* @return int Number of devices allowed in resolving list
*/
uint8_t
ble_hw_resolv_list_size(void)
{
return BLE_HW_RESOLV_LIST_SIZE;
}
/**
* Called to determine if the address received was resolved.
*
* @return int Negative values indicate unresolved address; positive values
* indicate index in resolving list of resolved address.
*/
int
ble_hw_resolv_list_match(void)
{
uint32_t index;
if (NRF_AAR->EVENTS_END) {
if (NRF_AAR->EVENTS_RESOLVED) {
index = NRF_AAR->STATUS;
return (int)index;
}
}
return -1;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 "syscfg/syscfg.h"
#include "os/os_trace_api.h"
#if MYNEWT_VAL(BLE_PHY_SYSVIEW)
static os_trace_module_t g_ble_phy_trace_mod;
uint32_t ble_phy_trace_off;
static void
ble_phy_trace_module_send_desc(void)
{
os_trace_module_desc(&g_ble_phy_trace_mod, "0 phy_set_tx cputime=%u usecs=%u");
os_trace_module_desc(&g_ble_phy_trace_mod, "1 phy_set_rx cputime=%u usecs=%u");
os_trace_module_desc(&g_ble_phy_trace_mod, "2 phy_disable");
}
void
ble_phy_trace_init(void)
{
ble_phy_trace_off =
os_trace_module_register(&g_ble_phy_trace_mod, "ble_phy", 3,
ble_phy_trace_module_send_desc);
}
#endif

View File

@@ -0,0 +1,75 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
syscfg.defs:
BLE_PHY_SYSVIEW:
description: >
Enable SystemView tracing module for radio driver.
value: 0
BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN:
description: >
This defines additional margin for T_IFS tolerance while in
RX on coded phy to allow maintaining connections with some
controllers that exceed proper T_IFS (150 usecs) by more
than allowed 2 usecs.
This value shall be only used for debugging purposes. It is
strongly recommended to keep this settings at default value
to ensure compliance with specification.
value: 0
BLE_PHY_DBG_TIME_TXRXEN_READY_PIN:
description: >
When set to proper GPIO pin number, this pin will be set
to high state when radio is enabled using PPI channels
20 or 21 and back to low state on radio EVENTS_READY.
This can be used to measure radio ram-up time.
value: -1
BLE_PHY_DBG_TIME_ADDRESS_END_PIN:
description: >
When set to proper GPIO pin number, this pin will be set
to high state on radio EVENTS_ADDRESS and back to low state
on radio EVENTS_END.
This can be used to measure radio pipeline delays.
value: -1
BLE_PHY_DBG_TIME_WFR_PIN:
description: >
When set to proper GPIO pin number, this pin will be set
to high state on radio EVENTS_RXREADY and back to low
state when wfr timer expires.
This can be used to check if wfr is calculated properly.
value: -1
BLE_PHY_NRF52840_ERRATA_164:
description: >
Enable workaround for anomaly 164 found in nRF52840.
"[164] RADIO: Low selectivity in long range mode"
This shall be only enabled for:
- nRF52840 Engineering A
value: 0
BLE_PHY_NRF52840_ERRATA_191:
description: >
Enable workaround for anomaly 191 found in nRF52840.
"[191] RADIO: High packet error rate in BLE Long Range mode"
This shall be only enabled for:
- nRF52840 Engineering B
- nRF52840 Engineering C
- nRF52840 Rev 1 (final silicon)
value: 1

View File

@@ -0,0 +1,194 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_ATT_
#define H_BLE_ATT_
/**
* @brief Bluetooth Attribute Protocol (ATT)
* @defgroup bt_att Bluetooth Attribute Protocol (ATT)
* @ingroup bt_host
* @{
*/
#include "os/queue.h"
#ifdef __cplusplus
extern "C" {
#endif
struct os_mbuf;
#define BLE_ATT_UUID_PRIMARY_SERVICE 0x2800
#define BLE_ATT_UUID_SECONDARY_SERVICE 0x2801
#define BLE_ATT_UUID_INCLUDE 0x2802
#define BLE_ATT_UUID_CHARACTERISTIC 0x2803
#define BLE_ATT_ERR_INVALID_HANDLE 0x01
#define BLE_ATT_ERR_READ_NOT_PERMITTED 0x02
#define BLE_ATT_ERR_WRITE_NOT_PERMITTED 0x03
#define BLE_ATT_ERR_INVALID_PDU 0x04
#define BLE_ATT_ERR_INSUFFICIENT_AUTHEN 0x05
#define BLE_ATT_ERR_REQ_NOT_SUPPORTED 0x06
#define BLE_ATT_ERR_INVALID_OFFSET 0x07
#define BLE_ATT_ERR_INSUFFICIENT_AUTHOR 0x08
#define BLE_ATT_ERR_PREPARE_QUEUE_FULL 0x09
#define BLE_ATT_ERR_ATTR_NOT_FOUND 0x0a
#define BLE_ATT_ERR_ATTR_NOT_LONG 0x0b
#define BLE_ATT_ERR_INSUFFICIENT_KEY_SZ 0x0c
#define BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN 0x0d
#define BLE_ATT_ERR_UNLIKELY 0x0e
#define BLE_ATT_ERR_INSUFFICIENT_ENC 0x0f
#define BLE_ATT_ERR_UNSUPPORTED_GROUP 0x10
#define BLE_ATT_ERR_INSUFFICIENT_RES 0x11
#define BLE_ATT_OP_ERROR_RSP 0x01
#define BLE_ATT_OP_MTU_REQ 0x02
#define BLE_ATT_OP_MTU_RSP 0x03
#define BLE_ATT_OP_FIND_INFO_REQ 0x04
#define BLE_ATT_OP_FIND_INFO_RSP 0x05
#define BLE_ATT_OP_FIND_TYPE_VALUE_REQ 0x06
#define BLE_ATT_OP_FIND_TYPE_VALUE_RSP 0x07
#define BLE_ATT_OP_READ_TYPE_REQ 0x08
#define BLE_ATT_OP_READ_TYPE_RSP 0x09
#define BLE_ATT_OP_READ_REQ 0x0a
#define BLE_ATT_OP_READ_RSP 0x0b
#define BLE_ATT_OP_READ_BLOB_REQ 0x0c
#define BLE_ATT_OP_READ_BLOB_RSP 0x0d
#define BLE_ATT_OP_READ_MULT_REQ 0x0e
#define BLE_ATT_OP_READ_MULT_RSP 0x0f
#define BLE_ATT_OP_READ_GROUP_TYPE_REQ 0x10
#define BLE_ATT_OP_READ_GROUP_TYPE_RSP 0x11
#define BLE_ATT_OP_WRITE_REQ 0x12
#define BLE_ATT_OP_WRITE_RSP 0x13
#define BLE_ATT_OP_PREP_WRITE_REQ 0x16
#define BLE_ATT_OP_PREP_WRITE_RSP 0x17
#define BLE_ATT_OP_EXEC_WRITE_REQ 0x18
#define BLE_ATT_OP_EXEC_WRITE_RSP 0x19
#define BLE_ATT_OP_NOTIFY_REQ 0x1b
#define BLE_ATT_OP_INDICATE_REQ 0x1d
#define BLE_ATT_OP_INDICATE_RSP 0x1e
#define BLE_ATT_OP_WRITE_CMD 0x52
#define BLE_ATT_ATTR_MAX_LEN 512
#define BLE_ATT_F_READ 0x01
#define BLE_ATT_F_WRITE 0x02
#define BLE_ATT_F_READ_ENC 0x04
#define BLE_ATT_F_READ_AUTHEN 0x08
#define BLE_ATT_F_READ_AUTHOR 0x10
#define BLE_ATT_F_WRITE_ENC 0x20
#define BLE_ATT_F_WRITE_AUTHEN 0x40
#define BLE_ATT_F_WRITE_AUTHOR 0x80
#define HA_FLAG_PERM_RW (BLE_ATT_F_READ | BLE_ATT_F_WRITE)
#define BLE_ATT_ACCESS_OP_READ 1
#define BLE_ATT_ACCESS_OP_WRITE 2
/** Default ATT MTU. Also the minimum. */
#define BLE_ATT_MTU_DFLT 23
/**
* An ATT MTU of 527 allows the largest ATT command (signed write) to contain a
* 512-byte attribute value.
*/
#define BLE_ATT_MTU_MAX 527
/**
* Reads a locally registered attribute. If the specified attribute handle
* corresponds to a GATT characteristic value or descriptor, the read is
* performed by calling the registered GATT access callback.
*
* @param attr_handle The 16-bit handle of the attribute to read.
* @param out_om On success, this is made to point to a
* newly-allocated mbuf containing the
* attribute data read.
*
* @return 0 on success;
* NimBLE host ATT return code if the attribute
* access callback reports failure;
* NimBLE host core return code on unexpected
* error.
*/
int ble_att_svr_read_local(uint16_t attr_handle, struct os_mbuf **out_om);
/**
* Writes a locally registered attribute. This function consumes the supplied
* mbuf regardless of the outcome. If the specified attribute handle
* corresponds to a GATT characteristic value or descriptor, the write is
* performed by calling the registered GATT access callback.
*
* @param attr_handle The 16-bit handle of the attribute to write.
* @param om The value to write to the attribute.
*
* @return 0 on success;
* NimBLE host ATT return code if the attribute
* access callback reports failure;
* NimBLE host core return code on unexpected
* error.
*/
int ble_att_svr_write_local(uint16_t attr_handle, struct os_mbuf *om);
/**
* Retrieves the ATT MTU of the specified connection. If an MTU exchange for
* this connection has occurred, the MTU is the lower of the two peers'
* preferred values. Otherwise, the MTU is the default value of 23.
*
* @param conn_handle The handle of the connection to query.
*
* @return The specified connection's ATT MTU, or 0 if
* there is no such connection.
*/
uint16_t ble_att_mtu(uint16_t conn_handle);
/**
* Retrieves the preferred ATT MTU. This is the value indicated by the device
* during an ATT MTU exchange.
*
* @return The preferred ATT MTU.
*/
uint16_t ble_att_preferred_mtu(void);
/**
* Sets the preferred ATT MTU; the device will indicate this value in all
* subsequent ATT MTU exchanges. The ATT MTU of a connection is equal to the
* lower of the two peers' preferred MTU values. The ATT MTU is what dictates
* the maximum size of any message sent during a GATT procedure.
*
* The specified MTU must be within the following range: [23, BLE_ATT_MTU_MAX].
* 23 is a minimum imposed by the Bluetooth specification; BLE_ATT_MTU_MAX is a
* NimBLE compile-time setting.
*
* @param mtu The preferred ATT MTU.
*
* @return 0 on success;
* BLE_HS_EINVAL if the specified value is not
* within the allowed range.
*/
int ble_att_set_preferred_mtu(uint16_t mtu);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

View File

@@ -0,0 +1,117 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_EDDYSTONE_
#define H_BLE_EDDYSTONE_
/**
* @brief Eddystone - BLE beacon from Google
* @defgroup bt_eddystone Eddystone - BLE beacon from Google
* @ingroup bt_host
* @{
*/
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
struct ble_hs_adv_fields;
#define BLE_EDDYSTONE_MAX_UUIDS16 3
#define BLE_EDDYSTONE_URL_MAX_LEN 17
#define BLE_EDDYSTONE_URL_SCHEME_HTTP_WWW 0
#define BLE_EDDYSTONE_URL_SCHEME_HTTPS_WWW 1
#define BLE_EDDYSTONE_URL_SCHEME_HTTP 2
#define BLE_EDDYSTONE_URL_SCHEME_HTTPS 3
#define BLE_EDDYSTONE_URL_SUFFIX_COM_SLASH 0x00
#define BLE_EDDYSTONE_URL_SUFFIX_ORG_SLASH 0x01
#define BLE_EDDYSTONE_URL_SUFFIX_EDU_SLASH 0x02
#define BLE_EDDYSTONE_URL_SUFFIX_NET_SLASH 0x03
#define BLE_EDDYSTONE_URL_SUFFIX_INFO_SLASH 0x04
#define BLE_EDDYSTONE_URL_SUFFIX_BIZ_SLASH 0x05
#define BLE_EDDYSTONE_URL_SUFFIX_GOV_SLASH 0x06
#define BLE_EDDYSTONE_URL_SUFFIX_COM 0x07
#define BLE_EDDYSTONE_URL_SUFFIX_ORG 0x08
#define BLE_EDDYSTONE_URL_SUFFIX_EDU 0x09
#define BLE_EDDYSTONE_URL_SUFFIX_NET 0x0a
#define BLE_EDDYSTONE_URL_SUFFIX_INFO 0x0b
#define BLE_EDDYSTONE_URL_SUFFIX_BIZ 0x0c
#define BLE_EDDYSTONE_URL_SUFFIX_GOV 0x0d
#define BLE_EDDYSTONE_URL_SUFFIX_NONE 0xff
/**
* Configures the device to advertise Eddystone UID beacons.
*
* @param adv_fields The base advertisement fields to transform into
* an eddystone beacon. All configured fields
* are preserved; you probably want to clear
* this struct before calling this function.
* @param uid The 16-byte UID to advertise.
* @param measured_power The Measured Power (RSSI value at 0 Meter).
*
* @return 0 on success;
* BLE_HS_EBUSY if advertising is in progress;
* BLE_HS_EMSGSIZE if the specified data is too
* large to fit in an advertisement;
* Other nonzero on failure.
*/
int ble_eddystone_set_adv_data_uid(struct ble_hs_adv_fields *adv_fields,
void *uid, int8_t measured_power);
/**
* Configures the device to advertise Eddystone URL beacons.
*
* @param adv_fields The base advertisement fields to transform into
* an eddystone beacon. All configured fields
* are preserved; you probably want to clear
* this struct before calling this function.
* @param url_scheme The prefix of the URL; one of the
* BLE_EDDYSTONE_URL_SCHEME values.
* @param url_body The middle of the URL. Don't include the
* suffix if there is a suitable suffix code.
* @param url_body_len The string length of the url_body argument.
* @param url_suffix The suffix of the URL; one of the
* BLE_EDDYSTONE_URL_SUFFIX values; use
* BLE_EDDYSTONE_URL_SUFFIX_NONE if the suffix
* is embedded in the body argument.
* @param measured_power The Measured Power (RSSI value at 0 Meter).
*
* @return 0 on success;
* BLE_HS_EBUSY if advertising is in progress;
* BLE_HS_EMSGSIZE if the specified data is too
* large to fit in an advertisement;
* Other nonzero on failure.
*/
int ble_eddystone_set_adv_data_url(struct ble_hs_adv_fields *adv_fields,
uint8_t url_scheme, char *url_body,
uint8_t url_body_len, uint8_t suffix,
int8_t measured_power);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,896 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_GATT_
#define H_BLE_GATT_
/**
* @brief Bluetooth Generic Attribute Profile (GATT)
* @defgroup bt_gatt Bluetooth Generic Attribute Profile (GATT)
* @ingroup bt_host
* @{
*/
#include <inttypes.h>
#include "host/ble_att.h"
#include "host/ble_uuid.h"
#ifdef __cplusplus
extern "C" {
#endif
struct ble_hs_conn;
struct ble_att_error_rsp;
struct ble_hs_cfg;
#define BLE_GATT_REGISTER_OP_SVC 1
#define BLE_GATT_REGISTER_OP_CHR 2
#define BLE_GATT_REGISTER_OP_DSC 3
#define BLE_GATT_SVC_UUID16 0x1801
#define BLE_GATT_DSC_CLT_CFG_UUID16 0x2902
#define BLE_GATT_CHR_PROP_BROADCAST 0x01
#define BLE_GATT_CHR_PROP_READ 0x02
#define BLE_GATT_CHR_PROP_WRITE_NO_RSP 0x04
#define BLE_GATT_CHR_PROP_WRITE 0x08
#define BLE_GATT_CHR_PROP_NOTIFY 0x10
#define BLE_GATT_CHR_PROP_INDICATE 0x20
#define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE 0x40
#define BLE_GATT_CHR_PROP_EXTENDED 0x80
#define BLE_GATT_ACCESS_OP_READ_CHR 0
#define BLE_GATT_ACCESS_OP_WRITE_CHR 1
#define BLE_GATT_ACCESS_OP_READ_DSC 2
#define BLE_GATT_ACCESS_OP_WRITE_DSC 3
#define BLE_GATT_CHR_F_BROADCAST 0x0001
#define BLE_GATT_CHR_F_READ 0x0002
#define BLE_GATT_CHR_F_WRITE_NO_RSP 0x0004
#define BLE_GATT_CHR_F_WRITE 0x0008
#define BLE_GATT_CHR_F_NOTIFY 0x0010
#define BLE_GATT_CHR_F_INDICATE 0x0020
#define BLE_GATT_CHR_F_AUTH_SIGN_WRITE 0x0040
#define BLE_GATT_CHR_F_RELIABLE_WRITE 0x0080
#define BLE_GATT_CHR_F_AUX_WRITE 0x0100
#define BLE_GATT_CHR_F_READ_ENC 0x0200
#define BLE_GATT_CHR_F_READ_AUTHEN 0x0400
#define BLE_GATT_CHR_F_READ_AUTHOR 0x0800
#define BLE_GATT_CHR_F_WRITE_ENC 0x1000
#define BLE_GATT_CHR_F_WRITE_AUTHEN 0x2000
#define BLE_GATT_CHR_F_WRITE_AUTHOR 0x4000
#define BLE_GATT_SVC_TYPE_END 0
#define BLE_GATT_SVC_TYPE_PRIMARY 1
#define BLE_GATT_SVC_TYPE_SECONDARY 2
/*** @client. */
struct ble_gatt_error {
uint16_t status;
uint16_t att_handle;
};
struct ble_gatt_svc {
uint16_t start_handle;
uint16_t end_handle;
ble_uuid_any_t uuid;
};
struct ble_gatt_attr {
uint16_t handle;
uint16_t offset;
struct os_mbuf *om;
};
struct ble_gatt_chr {
uint16_t def_handle;
uint16_t val_handle;
uint8_t properties;
ble_uuid_any_t uuid;
};
struct ble_gatt_dsc {
uint16_t handle;
ble_uuid_any_t uuid;
};
typedef int ble_gatt_mtu_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
uint16_t mtu, void *arg);
typedef int ble_gatt_disc_svc_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
const struct ble_gatt_svc *service,
void *arg);
/**
* The host will free the attribute mbuf automatically after the callback is
* executed. The application can take ownership of the mbuf and prevent it
* from being freed by assigning NULL to attr->om.
*/
typedef int ble_gatt_attr_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg);
/**
* The host will free the attribute mbufs automatically after the callback is
* executed. The application can take ownership of the mbufs and prevent them
* from being freed by assigning NULL to each attribute's om field.
*/
typedef int ble_gatt_reliable_attr_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attrs,
uint8_t num_attrs, void *arg);
typedef int ble_gatt_chr_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
const struct ble_gatt_chr *chr, void *arg);
typedef int ble_gatt_dsc_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
uint16_t chr_val_handle,
const struct ble_gatt_dsc *dsc,
void *arg);
/**
* Initiates GATT procedure: Exchange MTU.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_exchange_mtu(uint16_t conn_handle,
ble_gatt_mtu_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Discover All Primary Services.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*/
int ble_gattc_disc_all_svcs(uint16_t conn_handle,
ble_gatt_disc_svc_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Discover Primary Service by Service UUID.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param service_uuid128 The 128-bit UUID of the service to discover.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid,
ble_gatt_disc_svc_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Find Included Services.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param start_handle The handle to begin the search at (generally
* the service definition handle).
* @param end_handle The handle to end the search at (generally the
* last handle in the service).
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle,
ble_gatt_disc_svc_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Discover All Characteristics of a Service.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param start_handle The handle to begin the search at (generally
* the service definition handle).
* @param end_handle The handle to end the search at (generally the
* last handle in the service).
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, ble_gatt_chr_fn *cb,
void *cb_arg);
/**
* Initiates GATT procedure: Discover Characteristics by UUID.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param start_handle The handle to begin the search at (generally
* the service definition handle).
* @param end_handle The handle to end the search at (generally the
* last handle in the service).
* @param chr_uuid128 The 128-bit UUID of the characteristic to
* discover.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, const ble_uuid_t *uuid,
ble_gatt_chr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Discover All Characteristic Descriptors.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The handle of the characteristic value
* attribute.
* @param chr_end_handle The last handle in the characteristic
* definition.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle,
ble_gatt_dsc_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Read Characteristic Value.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to read.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Read Using Characteristic UUID.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param start_handle The first handle to search (generally the
* handle of the service definition).
* @param end_handle The last handle to search (generally the
* last handle in the service definition).
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, const ble_uuid_t *uuid,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Read Long Characteristic Values.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param handle The handle of the characteristic value to read.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_read_long(uint16_t conn_handle, uint16_t handle, uint16_t offset,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Read Multiple Characteristic Values.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param handles An array of 16-bit attribute handles to read.
* @param num_handles The number of entries in the "handles" array.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles,
uint8_t num_handles, ble_gatt_attr_fn *cb,
void *cb_arg);
/**
* Initiates GATT procedure: Write Without Response. This function consumes
* the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
* @param txom The value to write to the characteristic.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
struct os_mbuf *om);
/**
* Initiates GATT procedure: Write Without Response. This function consumes
* the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
* @param value The value to write to the characteristic.
* @param value_len The number of bytes to write.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_write_no_rsp_flat(uint16_t conn_handle, uint16_t attr_handle,
const void *data, uint16_t data_len);
/**
* Initiates GATT procedure: Write Characteristic Value. This function
* consumes the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
* @param txom The value to write to the characteristic.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle,
struct os_mbuf *om,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Write Characteristic Value (flat buffer version).
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
* @param value The value to write to the characteristic.
* @param value_len The number of bytes to write.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle,
const void *data, uint16_t data_len,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Write Long Characteristic Values. This function
* consumes the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
* @param txom The value to write to the characteristic.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle,
uint16_t offset, struct os_mbuf *om,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Reliable Writes. This function consumes the
* supplied mbufs regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attrs An array of attribute descriptors; specifies
* which characteristics to write to and what
* data to write to them. The mbuf pointer in
* each attribute is set to NULL by this
* function.
* @param num_attrs The number of characteristics to write; equal
* to the number of elements in the 'attrs'
* array.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*/
int ble_gattc_write_reliable(uint16_t conn_handle,
struct ble_gatt_attr *attrs,
int num_attrs, ble_gatt_reliable_attr_fn *cb,
void *cb_arg);
/**
* Sends a "free-form" characteristic notification. This function consumes the
* supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The attribute handle to indicate in the
* outgoing notification.
* @param txom The value to write to the characteristic.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle,
struct os_mbuf *om);
/**
* Sends a characteristic notification. The content of the message is read
* from the specified characteristic.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The value attribute handle of the
* characteristic to include in the outgoing
* notification.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle);
/**
* Sends a "free-form" characteristic indication. The provided mbuf contains
* the indication payload. This function consumes the supplied mbuf regardless
* of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The value attribute handle of the
* characteristic to include in the outgoing
* indication.
* @param txom The data to include in the indication.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle,
struct os_mbuf *txom);
/**
* Sends a characteristic indication. The content of the message is read from
* the specified characteristic.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The value attribute handle of the
* characteristic to include in the outgoing
* indication.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle);
int ble_gattc_init(void);
/*** @server. */
struct ble_gatt_access_ctxt;
typedef int ble_gatt_access_fn(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
typedef uint16_t ble_gatt_chr_flags;
struct ble_gatt_chr_def {
/**
* Pointer to characteristic UUID; use BLE_UUIDxx_DECLARE macros to declare
* proper UUID; NULL if there are no more characteristics in the service.
*/
const ble_uuid_t *uuid;
/**
* Callback that gets executed when this characteristic is read or
* written.
*/
ble_gatt_access_fn *access_cb;
/** Optional argument for callback. */
void *arg;
/**
* Array of this characteristic's descriptors. NULL if no descriptors.
* Do not include CCCD; it gets added automatically if this
* characteristic's notify or indicate flag is set.
*/
struct ble_gatt_dsc_def *descriptors;
/** Specifies the set of permitted operations for this characteristic. */
ble_gatt_chr_flags flags;
/** Specifies minimum required key size to access this characteristic. */
uint8_t min_key_size;
/**
* At registration time, this is filled in with the characteristic's value
* attribute handle.
*/
uint16_t *val_handle;
};
struct ble_gatt_svc_def {
/**
* One of the following:
* o BLE_GATT_SVC_TYPE_PRIMARY - primary service
* o BLE_GATT_SVC_TYPE_SECONDARY - secondary service
* o 0 - No more services in this array.
*/
uint8_t type;
/**
* Pointer to service UUID; use BLE_UUIDxx_DECLARE macros to declare
* proper UUID; NULL if there are no more characteristics in the service.
*/
const ble_uuid_t *uuid;
/**
* Array of pointers to other service definitions. These services are
* reported as "included services" during service discovery. Terminate the
* array with NULL.
*/
const struct ble_gatt_svc_def **includes;
/**
* Array of characteristic definitions corresponding to characteristics
* belonging to this service.
*/
const struct ble_gatt_chr_def *characteristics;
};
struct ble_gatt_dsc_def {
/**
* Pointer to descriptor UUID; use BLE_UUIDxx_DECLARE macros to declare
* proper UUID; NULL if there are no more characteristics in the service.
*/
const ble_uuid_t *uuid;
/** Specifies the set of permitted operations for this descriptor. */
uint8_t att_flags;
/** Specifies minimum required key size to access this descriptor. */
uint8_t min_key_size;
/** Callback that gets executed when the descriptor is read or written. */
ble_gatt_access_fn *access_cb;
/** Optional argument for callback. */
void *arg;
};
/**
* Context for an access to a GATT characteristic or descriptor. When a client
* reads or writes a locally registered characteristic or descriptor, an
* instance of this struct gets passed to the application callback.
*/
struct ble_gatt_access_ctxt {
/**
* Indicates the gatt operation being performed. This is equal to one of
* the following values:
* o BLE_GATT_ACCESS_OP_READ_CHR
* o BLE_GATT_ACCESS_OP_WRITE_CHR
* o BLE_GATT_ACCESS_OP_READ_DSC
* o BLE_GATT_ACCESS_OP_WRITE_DSC
*/
uint8_t op;
/**
* A container for the GATT access data.
* o For reads: The application populates this with the value of the
* characteristic or descriptor being read.
* o For writes: This is already populated with the value being written
* by the peer. If the application wishes to retain this mbuf for
* later use, the access callback must set this pointer to NULL to
* prevent the stack from freeing it.
*/
struct os_mbuf *om;
/**
* The GATT operation being performed dictates which field in this union is
* valid. If a characteristic is being accessed, the chr field is valid.
* Otherwise a descriptor is being accessed, in which case the dsc field
* is valid.
*/
union {
/**
* The characteristic definition corresponding to the characteristic
* being accessed. This is what the app registered at startup.
*/
const struct ble_gatt_chr_def *chr;
/**
* The descriptor definition corresponding to the descriptor being
* accessed. This is what the app registered at startup.
*/
const struct ble_gatt_dsc_def *dsc;
};
};
/**
* Context passed to the registration callback; represents the GATT service,
* characteristic, or descriptor being registered.
*/
struct ble_gatt_register_ctxt {
/**
* Indicates the gatt registration operation just performed. This is
* equal to one of the following values:
* o BLE_GATT_REGISTER_OP_SVC
* o BLE_GATT_REGISTER_OP_CHR
* o BLE_GATT_REGISTER_OP_DSC
*/
uint8_t op;
/**
* The value of the op field determines which field in this union is valid.
*/
union {
/** Service; valid if op == BLE_GATT_REGISTER_OP_SVC. */
struct {
/** The ATT handle of the service definition attribute. */
uint16_t handle;
/**
* The service definition representing the service being
* registered.
*/
const struct ble_gatt_svc_def *svc_def;
} svc;
/** Characteristic; valid if op == BLE_GATT_REGISTER_OP_CHR. */
struct {
/** The ATT handle of the characteristic definition attribute. */
uint16_t def_handle;
/** The ATT handle of the characteristic value attribute. */
uint16_t val_handle;
/**
* The characteristic definition representing the characteristic
* being registered.
*/
const struct ble_gatt_chr_def *chr_def;
/**
* The service definition corresponding to the characteristic's
* parent service.
*/
const struct ble_gatt_svc_def *svc_def;
} chr;
/** Descriptor; valid if op == BLE_GATT_REGISTER_OP_DSC. */
struct {
/** The ATT handle of the descriptor definition attribute. */
uint16_t handle;
/**
* The descriptor definition corresponding to the descriptor being
* registered.
*/
const struct ble_gatt_dsc_def *dsc_def;
/**
* The characteristic definition corresponding to the descriptor's
* parent characteristic.
*/
const struct ble_gatt_chr_def *chr_def;
/**
* The service definition corresponding to the descriptor's
* grandparent service
*/
const struct ble_gatt_svc_def *svc_def;
} dsc;
};
};
typedef void ble_gatt_register_fn(struct ble_gatt_register_ctxt *ctxt,
void *arg);
/**
* Queues a set of service definitions for registration. All services queued
* in this manner get registered when ble_gatts_start() is called.
*
* @param svcs An array of service definitions to queue for
* registration. This array must be
* terminated with an entry whose 'type'
* equals 0.
*
* @return 0 on success;
* BLE_HS_ENOMEM on heap exhaustion.
*/
int ble_gatts_add_svcs(const struct ble_gatt_svc_def *svcs);
/**
* Set visibility of local GATT service. Invisible services are not removed
* from database but are not discoverable by peer devices. Service Changed
* should be handled by application when needed by calling
* ble_svc_gatt_changed().
*
* @param handle Handle of service
* @param visible non-zero if service should be visible
*
* @return 0 on success;
* BLE_HS_ENOENT if service wasn't found.
*/
int ble_gatts_svc_set_visibility(uint16_t handle, int visible);
/**
* Adjusts a host configuration object's settings to accommodate the specified
* service definition array. This function adds the counts to the appropriate
* fields in the supplied configuration object without clearing them first, so
* it can be called repeatedly with different inputs to calculate totals. Be
* sure to zero the GATT server settings prior to the first call to this
* function.
*
* @param defs The service array containing the resource
* definitions to be counted.
*
* @return 0 on success;
* BLE_HS_EINVAL if the svcs array contains an
* invalid resource definition.
*/
int ble_gatts_count_cfg(const struct ble_gatt_svc_def *defs);
/**
* Send notification (or indication) to any connected devices that have
* subscribed for notification (or indication) for specified characteristic.
*
* @param chr_val_handle Characteristic value handle
*/
void ble_gatts_chr_updated(uint16_t chr_val_handle);
/**
* Retrieves the attribute handle associated with a local GATT service.
*
* @param uuid The UUID of the service to look up.
* @param out_handle On success, populated with the handle of the
* service attribute. Pass null if you don't
* need this value.
*
* @return 0 on success;
* BLE_HS_ENOENT if the specified service could
* not be found.
*/
int ble_gatts_find_svc(const ble_uuid_t *uuid, uint16_t *out_handle);
/**
* Retrieves the pair of attribute handles associated with a local GATT
* characteristic.
*
* @param svc_uuid The UUID of the parent service.
* @param chr_uuid The UUID of the characteristic to look up.
* @param out_def_handle On success, populated with the handle
* of the characteristic definition attribute.
* Pass null if you don't need this value.
* @param out_val_handle On success, populated with the handle
* of the characteristic value attribute.
* Pass null if you don't need this value.
*
* @return 0 on success;
* BLE_HS_ENOENT if the specified service or
* characteristic could not be found.
*/
int ble_gatts_find_chr(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid,
uint16_t *out_def_handle, uint16_t *out_val_handle);
/**
* Retrieves the attribute handle associated with a local GATT descriptor.
*
* @param svc_uuid The UUID of the grandparent service.
* @param chr_uuid The UUID of the parent characteristic.
* @param dsc_uuid The UUID of the descriptor ro look up.
* @param out_handle On success, populated with the handle
* of the descriptor attribute. Pass null if
* you don't need this value.
*
* @return 0 on success;
* BLE_HS_ENOENT if the specified service,
* characteristic, or descriptor could not be
* found.
*/
int ble_gatts_find_dsc(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid,
const ble_uuid_t *dsc_uuid, uint16_t *out_dsc_handle);
typedef void (*ble_gatt_svc_foreach_fn)(const struct ble_gatt_svc_def *svc,
uint16_t handle,
uint16_t end_group_handle,
void *arg);
/**
* Prints dump of local GATT database. This is useful to log local state of
* database in human readable form.
*/
void ble_gatts_show_local(void);
/**
* Resets the GATT server to its initial state. On success, this function
* removes all supported services, characteristics, and descriptors. This
* function requires that:
* o No peers are connected, and
* o No GAP operations are active (advertise, discover, or connect).
*
* @return 0 on success;
* BLE_HS_EBUSY if the GATT server could not be
* reset due to existing connections or active
* GAP procedures.
*/
int ble_gatts_reset(void);
/**
* Makes all registered services available to peers. This function gets called
* automatically by the NimBLE host on startup; manual calls are only necessary
* for replacing the set of supported services with a new one. This function
* requires that:
* o No peers are connected, and
* o No GAP operations are active (advertise, discover, or connect).
*
* @return 0 on success;
* A BLE host core return code on unexpected
* error.
*/
int ble_gatts_start(void);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

View File

@@ -0,0 +1,386 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_HS_
#define H_BLE_HS_
/**
* @brief Bluetooth Host
* @defgroup bt_host Bluetooth Host
* @{
*/
#include <inttypes.h>
#include "nimble/hci_common.h"
#include "host/ble_att.h"
#include "host/ble_eddystone.h"
#include "host/ble_gap.h"
#include "host/ble_gatt.h"
#include "host/ble_hs_adv.h"
#include "host/ble_hs_id.h"
#include "host/ble_hs_hci.h"
#include "host/ble_hs_log.h"
#include "host/ble_hs_mbuf.h"
#include "host/ble_hs_stop.h"
#include "host/ble_ibeacon.h"
#include "host/ble_l2cap.h"
#include "host/ble_sm.h"
#include "host/ble_store.h"
#include "host/ble_uuid.h"
#include "nimble/nimble_npl.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_HS_FOREVER INT32_MAX
/** Connection handle not present */
#define BLE_HS_CONN_HANDLE_NONE 0xffff
/**
* @brief Bluetooth Host Error Code
* @defgroup bt_host_err Bluetooth Host Error Code
*
* Defines error codes returned by Bluetooth host. If error comes from specific
* component (eg L2CAP or Security Manager) it is shifted by base allowing to
* identify component.
* @{
*/
#define BLE_HS_EAGAIN 1
#define BLE_HS_EALREADY 2
#define BLE_HS_EINVAL 3
#define BLE_HS_EMSGSIZE 4
#define BLE_HS_ENOENT 5
#define BLE_HS_ENOMEM 6
#define BLE_HS_ENOTCONN 7
#define BLE_HS_ENOTSUP 8
#define BLE_HS_EAPP 9
#define BLE_HS_EBADDATA 10
#define BLE_HS_EOS 11
#define BLE_HS_ECONTROLLER 12
#define BLE_HS_ETIMEOUT 13
#define BLE_HS_EDONE 14
#define BLE_HS_EBUSY 15
#define BLE_HS_EREJECT 16
#define BLE_HS_EUNKNOWN 17
#define BLE_HS_EROLE 18
#define BLE_HS_ETIMEOUT_HCI 19
#define BLE_HS_ENOMEM_EVT 20
#define BLE_HS_ENOADDR 21
#define BLE_HS_ENOTSYNCED 22
#define BLE_HS_EAUTHEN 23
#define BLE_HS_EAUTHOR 24
#define BLE_HS_EENCRYPT 25
#define BLE_HS_EENCRYPT_KEY_SZ 26
#define BLE_HS_ESTORE_CAP 27
#define BLE_HS_ESTORE_FAIL 28
#define BLE_HS_EPREEMPTED 29
#define BLE_HS_EDISABLED 30
#define BLE_HS_ESTALLED 31
/** Error base for ATT errors */
#define BLE_HS_ERR_ATT_BASE 0x100
/** Converts error to ATT base */
#define BLE_HS_ATT_ERR(x) ((x) ? BLE_HS_ERR_ATT_BASE + (x) : 0)
/** Error base for HCI errors */
#define BLE_HS_ERR_HCI_BASE 0x200
/** Converts error to HCI base */
#define BLE_HS_HCI_ERR(x) ((x) ? BLE_HS_ERR_HCI_BASE + (x) : 0)
/** Error base for L2CAP errors */
#define BLE_HS_ERR_L2C_BASE 0x300
/** Converts error to L2CAP base */
#define BLE_HS_L2C_ERR(x) ((x) ? BLE_HS_ERR_L2C_BASE + (x) : 0)
/** Error base for local Security Manager errors */
#define BLE_HS_ERR_SM_US_BASE 0x400
/** Converts error to local Security Manager base */
#define BLE_HS_SM_US_ERR(x) ((x) ? BLE_HS_ERR_SM_US_BASE + (x) : 0)
/** Error base for remote (peer) Security Manager errors */
#define BLE_HS_ERR_SM_PEER_BASE 0x500
/** Converts error to remote (peer) Security Manager base */
#define BLE_HS_SM_PEER_ERR(x) ((x) ? BLE_HS_ERR_SM_PEER_BASE + (x) : 0)
/** Error base for hardware errors */
#define BLE_HS_ERR_HW_BASE 0x600
/** Converts error to hardware error base */
#define BLE_HS_HW_ERR(x) (BLE_HS_ERR_HW_BASE + (x))
/**
* @}
*/
/**
* @brief Bluetooth Host Configuration
* @defgroup bt_host_conf Bluetooth Host Configuration
*
* @{
*/
/**
* @brief Local Input-Output capabilities of device
* @defgroup bt_host_io_local Local Input-Output capabilities of device
*
* @{
*/
/** DisplayOnly IO capability */
#define BLE_HS_IO_DISPLAY_ONLY 0x00
/** DisplayYesNo IO capability */
#define BLE_HS_IO_DISPLAY_YESNO 0x01
/** KeyboardOnly IO capability */
#define BLE_HS_IO_KEYBOARD_ONLY 0x02
/** NoInputNoOutput IO capability */
#define BLE_HS_IO_NO_INPUT_OUTPUT 0x03
/** KeyboardDisplay Only IO capability */
#define BLE_HS_IO_KEYBOARD_DISPLAY 0x04
/**
* @}
*/
/** @brief Stack reset callback
*
* @param reason Reason code for reset
*/
typedef void ble_hs_reset_fn(int reason);
/** @brief Stack sync callback */
typedef void ble_hs_sync_fn(void);
/** @brief Bluetooth Host main configuration structure
*
* Those can be used by application to configure stack.
*
* The only reason Security Manager (sm_ members) is configurable at runtime is
* to simplify security testing. Defaults for those are configured by selecting
* proper options in application's syscfg.
*/
struct ble_hs_cfg {
/**
* An optional callback that gets executed upon registration of each GATT
* resource (service, characteristic, or descriptor).
*/
ble_gatt_register_fn *gatts_register_cb;
/**
* An optional argument that gets passed to the GATT registration
* callback.
*/
void *gatts_register_arg;
/** Security Manager Local Input Output Capabilities */
uint8_t sm_io_cap;
/** @brief Security Manager OOB flag
*
* If set proper flag in Pairing Request/Response will be set.
*/
unsigned sm_oob_data_flag:1;
/** @brief Security Manager Bond flag
*
* If set proper flag in Pairing Request/Response will be set. This results
* in storing keys distributed during bonding.
*/
unsigned sm_bonding:1;
/** @brief Security Manager MITM flag
*
* If set proper flag in Pairing Request/Response will be set. This results
* in requiring Man-In-The-Middle protection when pairing.
*/
unsigned sm_mitm:1;
/** @brief Security Manager Secure Connections flag
*
* If set proper flag in Pairing Request/Response will be set. This results
* in using LE Secure Connections for pairing if also supported by remote
* device. Fallback to legacy pairing if not supported by remote.
*/
unsigned sm_sc:1;
/** @brief Security Manager Key Press Notification flag
*
* Currently unsupported and should not be set.
*/
unsigned sm_keypress:1;
/** @brief Security Manager Local Key Distribution Mask */
uint8_t sm_our_key_dist;
/** @brief Security Manager Remote Key Distribution Mask */
uint8_t sm_their_key_dist;
/** @brief Stack reset callback
*
* This callback is executed when the host resets itself and the controller
* due to fatal error.
*/
ble_hs_reset_fn *reset_cb;
/** @brief Stack sync callback
*
* This callback is executed when the host and controller become synced.
* This happens at startup and after a reset.
*/
ble_hs_sync_fn *sync_cb;
/* XXX: These need to go away. Instead, the nimble host package should
* require the host-store API (not yet implemented)..
*/
/** Storage Read callback handles read of security material */
ble_store_read_fn *store_read_cb;
/** Storage Write callback handles write of security material */
ble_store_write_fn *store_write_cb;
/** Storage Delete callback handles deletion of security material */
ble_store_delete_fn *store_delete_cb;
/** @brief Storage Status callback.
*
* This callback gets executed when a persistence operation cannot be
* performed or a persistence failure is imminent. For example, if is
* insufficient storage capacity for a record to be persisted, this
* function gets called to give the application the opportunity to make
* room.
*/
ble_store_status_fn *store_status_cb;
/** An optional argument that gets passed to the storage status callback. */
void *store_status_arg;
};
extern struct ble_hs_cfg ble_hs_cfg;
/**
* @}
*/
/**
* @brief Indicates whether the host is enabled. The host is enabled if it is
* starting or fully started. It is disabled if it is stopping or stopped.
*
* @return 1 if the host is enabled;
* 0 if the host is disabled.
*/
int ble_hs_is_enabled(void);
/**
* Indicates whether the host has synchronized with the controller.
* Synchronization must occur before any host procedures can be performed.
*
* @return 1 if the host and controller are in sync;
* 0 if the host and controller are out of sync.
*/
int ble_hs_synced(void);
/**
* Synchronizes the host with the controller by sending a sequence of HCI
* commands. This function must be called before any other host functionality
* is used, but it must be called after both the host and controller are
* initialized. Typically, the host-parent-task calls this function at the top
* of its task routine. This function must only be called in the host parent
* task. A safe alternative for starting the stack from any task is to call
* `ble_hs_sched_start()`.
*
* If the host fails to synchronize with the controller (if the controller is
* not fully booted, for example), the host will attempt to resynchronize every
* 100 ms. For this reason, an error return code is not necessarily fatal.
*
* @return 0 on success; nonzero on error.
*/
int ble_hs_start(void);
/**
* Enqueues a host start event to the default event queue. The actual host
* startup is performed in the host parent task, but using the default queue
* here ensures the event won't run until the end of main() when this is
* called during system initialization. This allows the application to
* configure the host package in the meantime.
*
* If auto-start is disabled, the application should use this function to start
* the BLE stack. This function can be called at any time as long as the host
* is stopped. When the host successfully starts, the application is notified
* via the ble_hs_cfg.sync_cb callback.
*/
void ble_hs_sched_start(void);
/**
* Causes the host to reset the NimBLE stack as soon as possible. The
* application is notified when the reset occurs via the host reset callback.
*
* @param reason The host error code that gets passed to the reset callback.
*/
void ble_hs_sched_reset(int reason);
/**
* Designates the specified event queue for NimBLE host work. By default, the
* host uses the default event queue and runs in the main task. This function
* is useful if you want the host to run in a different task.
*
* @param evq The event queue to use for host work.
*/
void ble_hs_evq_set(struct ble_npl_eventq *evq);
/**
* Initializes the NimBLE host. This function must be called before the OS is
* started. The NimBLE stack requires an application task to function. One
* application task in particular is designated as the "host parent task". In
* addition to application-specific work, the host parent task does work for
* NimBLE by processing events generated by the host.
*/
void ble_hs_init(void);
/**
* @brief Called when the system is shutting down. Stops the BLE host.
*
* @param reason The reason for the shutdown. One of the
* HAL_RESET_[...] codes or an
* implementation-defined value.
*
* @return SYSDOWN_IN_PROGRESS.
*/
int ble_hs_shutdown(int reason);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

View File

@@ -0,0 +1,177 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_HS_ADV_
#define H_BLE_HS_ADV_
#include <inttypes.h>
#include "host/ble_uuid.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_HS_ADV_MAX_SZ BLE_HCI_MAX_ADV_DATA_LEN
/** Max field payload size (account for 2-byte header). */
#define BLE_HS_ADV_MAX_FIELD_SZ (BLE_HS_ADV_MAX_SZ - 2)
struct ble_hs_adv_field {
uint8_t length;
uint8_t type;
uint8_t value[0];
};
typedef int (* ble_hs_adv_parse_func_t) (const struct ble_hs_adv_field *,
void *);
struct ble_hs_adv_fields {
/*** 0x01 - Flags. */
uint8_t flags;
/*** 0x02,0x03 - 16-bit service class UUIDs. */
const ble_uuid16_t *uuids16;
uint8_t num_uuids16;
unsigned uuids16_is_complete:1;
/*** 0x04,0x05 - 32-bit service class UUIDs. */
const ble_uuid32_t *uuids32;
uint8_t num_uuids32;
unsigned uuids32_is_complete:1;
/*** 0x06,0x07 - 128-bit service class UUIDs. */
const ble_uuid128_t *uuids128;
uint8_t num_uuids128;
unsigned uuids128_is_complete:1;
/*** 0x08,0x09 - Local name. */
const uint8_t *name;
uint8_t name_len;
unsigned name_is_complete:1;
/*** 0x0a - Tx power level. */
int8_t tx_pwr_lvl;
unsigned tx_pwr_lvl_is_present:1;
/*** 0x0d - Slave connection interval range. */
const uint8_t *slave_itvl_range;
/*** 0x16 - Service data - 16-bit UUID. */
const uint8_t *svc_data_uuid16;
uint8_t svc_data_uuid16_len;
/*** 0x17 - Public target address. */
const uint8_t *public_tgt_addr;
uint8_t num_public_tgt_addrs;
/*** 0x19 - Appearance. */
uint16_t appearance;
unsigned appearance_is_present:1;
/*** 0x1a - Advertising interval. */
uint16_t adv_itvl;
unsigned adv_itvl_is_present:1;
/*** 0x20 - Service data - 32-bit UUID. */
const uint8_t *svc_data_uuid32;
uint8_t svc_data_uuid32_len;
/*** 0x21 - Service data - 128-bit UUID. */
const uint8_t *svc_data_uuid128;
uint8_t svc_data_uuid128_len;
/*** 0x24 - URI. */
const uint8_t *uri;
uint8_t uri_len;
/*** 0xff - Manufacturer specific data. */
const uint8_t *mfg_data;
uint8_t mfg_data_len;
};
#define BLE_HS_ADV_TYPE_FLAGS 0x01
#define BLE_HS_ADV_TYPE_INCOMP_UUIDS16 0x02
#define BLE_HS_ADV_TYPE_COMP_UUIDS16 0x03
#define BLE_HS_ADV_TYPE_INCOMP_UUIDS32 0x04
#define BLE_HS_ADV_TYPE_COMP_UUIDS32 0x05
#define BLE_HS_ADV_TYPE_INCOMP_UUIDS128 0x06
#define BLE_HS_ADV_TYPE_COMP_UUIDS128 0x07
#define BLE_HS_ADV_TYPE_INCOMP_NAME 0x08
#define BLE_HS_ADV_TYPE_COMP_NAME 0x09
#define BLE_HS_ADV_TYPE_TX_PWR_LVL 0x0a
#define BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE 0x12
#define BLE_HS_ADV_TYPE_SOL_UUIDS16 0x14
#define BLE_HS_ADV_TYPE_SOL_UUIDS128 0x15
#define BLE_HS_ADV_TYPE_SVC_DATA_UUID16 0x16
#define BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR 0x17
#define BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR 0x18
#define BLE_HS_ADV_TYPE_APPEARANCE 0x19
#define BLE_HS_ADV_TYPE_ADV_ITVL 0x1a
#define BLE_HS_ADV_TYPE_SVC_DATA_UUID32 0x20
#define BLE_HS_ADV_TYPE_SVC_DATA_UUID128 0x21
#define BLE_HS_ADV_TYPE_URI 0x24
#define BLE_HS_ADV_TYPE_MESH_PROV 0x29
#define BLE_HS_ADV_TYPE_MESH_MESSAGE 0x2a
#define BLE_HS_ADV_TYPE_MESH_BEACON 0x2b
#define BLE_HS_ADV_TYPE_MFG_DATA 0xff
#define BLE_HS_ADV_FLAGS_LEN 1
#define BLE_HS_ADV_F_DISC_LTD 0x01
#define BLE_HS_ADV_F_DISC_GEN 0x02
#define BLE_HS_ADV_F_BREDR_UNSUP 0x04
#define BLE_HS_ADV_TX_PWR_LVL_LEN 1
/**
* Set the tx_pwr_lvl field to this if you want the stack to fill in the tx
* power level field.
*/
#define BLE_HS_ADV_TX_PWR_LVL_AUTO (-128)
#define BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN 4
#define BLE_HS_ADV_SVC_DATA_UUID16_MIN_LEN 2
#define BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN 6
#define BLE_HS_ADV_APPEARANCE_LEN 2
#define BLE_HS_ADV_ADV_ITVL_LEN 2
#define BLE_HS_ADV_SVC_DATA_UUID32_MIN_LEN 4
#define BLE_HS_ADV_SVC_DATA_UUID128_MIN_LEN 16
int ble_hs_adv_set_fields_mbuf(const struct ble_hs_adv_fields *adv_fields,
struct os_mbuf *om);
int ble_hs_adv_set_fields(const struct ble_hs_adv_fields *adv_fields,
uint8_t *dst, uint8_t *dst_len, uint8_t max_len);
int ble_hs_adv_parse_fields(struct ble_hs_adv_fields *adv_fields,
const uint8_t *src, uint8_t src_len);
int ble_hs_adv_parse(const uint8_t *data, uint8_t length,
ble_hs_adv_parse_func_t func, void *user_data);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,98 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_HS_HCI_
#define H_BLE_HS_HCI_
/**
* @brief Bluetooth Host HCI utils
* @defgroup bt_host_hci Bluetooth Host HCI utils
* @ingroup bt_host
* @{
*/
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Queries the controller for the channel map used with the specified
* connection. The channel map is represented as an array of five bytes, with
* each bit corresponding to an individual channel. The array is interpreted
* as little-endian, such that:
* map[0] & 0x01 --> Channel 0.
* map[0] & 0x02 --> Channel 1.
* ...
* map[1] & 0x01 --> Channel 8.
*
* As there are 37 channels, only the first 37 bits get written.
*
* If a bit is 1, the corresponding channel is used. Otherwise, the channel is
* unused.
*
* @param conn_handle The handle of the connection whose channel map
* is being read.
* @param out_chan_map On success, the retrieved channel map gets
* written here. This buffer must have a size
* >= 5 bytes.
*
* @return 0 on success;
* A BLE host HCI return code if the controller
* rejected the request;
* A BLE host core return code on unexpected
* error.
*/
int ble_hs_hci_read_chan_map(uint16_t conn_handle, uint8_t *out_chan_map);
/**
* Instructs the controller to use the specified channel map. The channel map
* is represented as an array of five bytes, with each bit corresponding to an
* individual channel. The array is interpreted as little-endian, such that:
* map[0] & 0x01 --> Channel 0.
* map[0] & 0x02 --> Channel 1.
* ...
* map[1] & 0x01 --> Channel 8.
*
* As there are 37 channels, only the first 37 bits should be written are used.
*
* If a bit is 1, the corresponding channel can be used. Otherwise, the
* channel should not be used.
*
* @param chan_map The channel map to configure. This buffer
* should have a size of 5 bytes.
*
* @return 0 on success;
* A BLE host HCI return code if the controller
* rejected the request;
* A BLE host core return code on unexpected
* error.
*/
int ble_hs_hci_set_chan_class(const uint8_t *chan_map);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

View File

@@ -0,0 +1,132 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_HS_ID_
#define H_BLE_HS_ID_
/**
* @brief Bluetooth Host Identity
* @defgroup bt_host_id Bluetooth Host Identity
* @ingroup bt_host
* @{
*/
#include <inttypes.h>
#include "nimble/ble.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Generates a new random address. This function does not configure the device
* with the new address; the caller can use the address in subsequent
* operations.
*
* @param nrpa The type of random address to generate:
* 0: static
* 1: non-resolvable private
* @param out_addr On success, the generated address gets written
* here.
*
* @return 0 on success; nonzero on failure.
*/
int ble_hs_id_gen_rnd(int nrpa, ble_addr_t *out_addr);
/**
* Sets the device's random address. The address type (static vs.
* non-resolvable private) is inferred from the most-significant byte of the
* address. The address is specified in host byte order (little-endian!).
*
* @param rnd_addr The random address to set.
*
* @return 0 on success;
* BLE_HS_EINVAL if the specified address is not a
* valid static random or non-resolvable
* private address.
* Other nonzero on error.
*/
int ble_hs_id_set_rnd(const uint8_t *rnd_addr);
/**
* Retrieves one of the device's identity addresses. The device can have two
* identity addresses: one public and one random. The id_addr_type argument
* specifies which of these two addresses to retrieve.
*
* @param id_addr_type The type of identity address to retrieve.
* Valid values are:
* o BLE_ADDR_PUBLIC
* o BLE_ADDR_RANDOM
* @param out_id_addr On success, the requested identity address is
* copied into this buffer. The buffer must
* be at least six bytes in size. Pass NULL
* if you do not require this information.
* @param out_is_nrpa On success, the pointed-to value indicates
* whether the retrieved address is a
* non-resolvable private address. Pass NULL
* if you do not require this information.
*
* @return 0 on success;
* BLE_HS_EINVAL if an invalid address type was
* specified;
* BLE_HS_ENOADDR if the device does not have an
* identity address of the requested type;
* Other BLE host core code on error.
*/
int ble_hs_id_copy_addr(uint8_t id_addr_type, uint8_t *out_id_addr,
int *out_is_nrpa);
/**
* Determines the best address type to use for automatic address type
* resolution. Calculation of the best address type is done as follows:
*
* if privacy requested:
* if we have a random static address:
* --> RPA with static random ID
* else
* --> RPA with public ID
* end
* else
* if we have a random static address:
* --> random static address
* else
* --> public address
* end
* end
*
* @param privacy (0/1) Whether to use a private address.
* @param out_addr_type On success, the "own addr type" code gets
* written here.
*
* @return 0 if an address type was successfully inferred.
* BLE_HS_ENOADDR if the device does not have a
* suitable address.
* Other BLE host core code on error.
*/
int ble_hs_id_infer_auto(int privacy, uint8_t *out_addr_type);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

View File

@@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_HS_LOG_
#define H_BLE_HS_LOG_
#include "modlog/modlog.h"
/* Only include the logcfg header if this version of newt can generate it. */
#if MYNEWT_VAL(NEWT_FEATURE_LOGCFG)
#include "logcfg/logcfg.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct os_mbuf;
#define BLE_HS_LOG(lvl, ...) \
BLE_HS_LOG_ ## lvl(__VA_ARGS__)
#define BLE_HS_LOG_ADDR(lvl, addr) \
BLE_HS_LOG_ ## lvl("%02x:%02x:%02x:%02x:%02x:%02x", \
(addr)[5], (addr)[4], (addr)[3], \
(addr)[2], (addr)[1], (addr)[0])
void ble_hs_log_mbuf(const struct os_mbuf *om);
void ble_hs_log_flat_buf(const void *data, int len);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,82 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_HS_MBUF_
#define H_BLE_HS_MBUF_
/**
* @brief Bluetooth Host chained memory buffer (mbuf)
* @defgroup bt_host_mbuf Bluetooth Host chained memory buffer (mbuf)
* @ingroup bt_host
* @{
*/
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
struct os_mbuf;
/**
* Allocates an mbuf suitable for an ATT command packet. The resulting packet
* has sufficient leading space for:
* - ACL data header
* - L2CAP B-frame header
* - Largest ATT command base (prepare write request / response).
*
* @return An empty mbuf on success, NULL on error.
*/
struct os_mbuf *ble_hs_mbuf_att_pkt(void);
/**
* Allocates an mbuf and fills it with the contents of the specified flat
* buffer.
*
* @param buf The flat buffer to copy from.
* @param len The length of the flat buffer.
*
* @return A newly-allocated mbuf on success, NULL on error.
*/
struct os_mbuf *ble_hs_mbuf_from_flat(const void *buf, uint16_t len);
/**
* Copies the contents of an mbuf into the specified flat buffer. If the flat
* buffer is too small to contain the mbuf's contents, it is filled to capacity
* and BLE_HS_EMSGSIZE is returned.
*
* @param om The mbuf to copy from.
* @param flat The destination flat buffer.
* @param max_len The size of the flat buffer.
* @param out_copy_len The number of bytes actually copied gets written here.
*
* @return 0 on success or BLE host core return code on error.
*/
int ble_hs_mbuf_to_flat(const struct os_mbuf *om, void *flat, uint16_t max_len,
uint16_t *out_copy_len);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

View File

@@ -0,0 +1,70 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_HS_STOP_
#define H_BLE_HS_STOP_
/** @typedef ble_hs_stop_fn
* @brief Callback function; reports the result of a host stop procedure.
*
* @param status The result of the host stop procedure. One of
* the HAL_RESET_[...] codes or an
* implementation-defined value.
* @param arg Optional argument specified when the stop
* procedure was initiated.
*
*/
typedef void ble_hs_stop_fn(int status, void *arg);
/**
* @brief Used to report the result of a stop procedure.
*
* This should be used as an opaque structure and not modified manually.
*/
struct ble_hs_stop_listener {
ble_hs_stop_fn *fn;
void *arg;
SLIST_ENTRY(ble_hs_stop_listener) link;
};
/**
* @brief Stops the BLE host.
*
* Aborts all active GAP procedures and terminates all open connections.
* Connection termination is performed asynchronously, so this function's
* result is reported via the provided listener.
*
* @param listener A listener to populate. This object's initial
* value doesn't matter, but its lifetime must
* extend until the stop procedure completes.
* @param fn The callback to execute when the stop procedure
* completes.
* @param arg Optional argument to pass to the callback.
*
* @return 0: Stop procedure successfully initiated.
* BLE_HS_EBUSY: Stop procedure already in
* progress; the provided callback gets called
* when the procedure completes.
* BLE_HS_EALREADY: Host already stopped; the
* provided callback does *not* get called.
*/
int ble_hs_stop(struct ble_hs_stop_listener *listener,
ble_hs_stop_fn *fn, void *arg);
#endif

View File

@@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_IBEACON_
#define H_BLE_IBEACON_
#ifdef __cplusplus
extern "C" {
#endif
int ble_ibeacon_set_adv_data(void *uuid128, uint16_t major,
uint16_t minor, int8_t measured_power);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,266 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_L2CAP_
#define H_BLE_L2CAP_
#include "nimble/nimble_opt.h"
#ifdef __cplusplus
extern "C" {
#endif
struct ble_l2cap_sig_update_req;
struct ble_hs_conn;
#define BLE_L2CAP_CID_ATT 4
#define BLE_L2CAP_CID_SIG 5
#define BLE_L2CAP_CID_SM 6
#define BLE_L2CAP_SIG_OP_REJECT 0x01
#define BLE_L2CAP_SIG_OP_CONNECT_REQ 0x02
#define BLE_L2CAP_SIG_OP_CONNECT_RSP 0x03
#define BLE_L2CAP_SIG_OP_CONFIG_REQ 0x04
#define BLE_L2CAP_SIG_OP_CONFIG_RSP 0x05
#define BLE_L2CAP_SIG_OP_DISCONN_REQ 0x06
#define BLE_L2CAP_SIG_OP_DISCONN_RSP 0x07
#define BLE_L2CAP_SIG_OP_ECHO_REQ 0x08
#define BLE_L2CAP_SIG_OP_ECHO_RSP 0x09
#define BLE_L2CAP_SIG_OP_INFO_REQ 0x0a
#define BLE_L2CAP_SIG_OP_INFO_RSP 0x0b
#define BLE_L2CAP_SIG_OP_CREATE_CHAN_REQ 0x0c
#define BLE_L2CAP_SIG_OP_CREATE_CHAN_RSP 0x0d
#define BLE_L2CAP_SIG_OP_MOVE_CHAN_REQ 0x0e
#define BLE_L2CAP_SIG_OP_MOVE_CHAN_RSP 0x0f
#define BLE_L2CAP_SIG_OP_MOVE_CHAN_CONF_REQ 0x10
#define BLE_L2CAP_SIG_OP_MOVE_CHAN_CONF_RSP 0x11
#define BLE_L2CAP_SIG_OP_UPDATE_REQ 0x12
#define BLE_L2CAP_SIG_OP_UPDATE_RSP 0x13
#define BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_REQ 0x14
#define BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_RSP 0x15
#define BLE_L2CAP_SIG_OP_FLOW_CTRL_CREDIT 0x16
#define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_REQ 0x17
#define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_RSP 0x18
#define BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_REQ 0x19
#define BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_RSP 0x1A
#define BLE_L2CAP_SIG_OP_MAX 0x1B
#define BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD 0x0000
#define BLE_L2CAP_SIG_ERR_MTU_EXCEEDED 0x0001
#define BLE_L2CAP_SIG_ERR_INVALID_CID 0x0002
#define BLE_L2CAP_COC_ERR_CONNECTION_SUCCESS 0x0000
#define BLE_L2CAP_COC_ERR_UNKNOWN_LE_PSM 0x0002
#define BLE_L2CAP_COC_ERR_NO_RESOURCES 0x0004
#define BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHEN 0x0005
#define BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHOR 0x0006
#define BLE_L2CAP_COC_ERR_INSUFFICIENT_KEY_SZ 0x0007
#define BLE_L2CAP_COC_ERR_INSUFFICIENT_ENC 0x0008
#define BLE_L2CAP_COC_ERR_INVALID_SOURCE_CID 0x0009
#define BLE_L2CAP_COC_ERR_SOURCE_CID_ALREADY_USED 0x000A
#define BLE_L2CAP_COC_ERR_UNACCEPTABLE_PARAMETERS 0x000B
#define BLE_L2CAP_COC_ERR_INVALID_PARAMETERS 0x000C
#define BLE_L2CAP_ERR_RECONFIG_SUCCEED 0x0000
#define BLE_L2CAP_ERR_RECONFIG_REDUCTION_MTU_NOT_ALLOWED 0x0001
#define BLE_L2CAP_ERR_RECONFIG_REDUCTION_MPS_NOT_ALLOWED 0x0002
#define BLE_L2CAP_ERR_RECONFIG_INVALID_DCID 0x0003
#define BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM 0x0004
#define BLE_L2CAP_EVENT_COC_CONNECTED 0
#define BLE_L2CAP_EVENT_COC_DISCONNECTED 1
#define BLE_L2CAP_EVENT_COC_ACCEPT 2
#define BLE_L2CAP_EVENT_COC_DATA_RECEIVED 3
#define BLE_L2CAP_EVENT_COC_TX_UNSTALLED 4
#define BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED 5
#define BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED 6
typedef void ble_l2cap_sig_update_fn(uint16_t conn_handle, int status,
void *arg);
struct ble_l2cap_sig_update_params {
uint16_t itvl_min;
uint16_t itvl_max;
uint16_t slave_latency;
uint16_t timeout_multiplier;
};
int ble_l2cap_sig_update(uint16_t conn_handle,
struct ble_l2cap_sig_update_params *params,
ble_l2cap_sig_update_fn *cb, void *cb_arg);
struct ble_l2cap_chan;
/**
* Represents a L2CAP-related event.
* When such an event occurs, the host notifies the application by passing an
* instance of this structure to an application-specified callback.
*/
struct ble_l2cap_event {
/**
* Indicates the type of L2CAP event that occurred. This is one of the
* BLE_L2CAP_EVENT codes.
*/
uint8_t type;
/**
* A discriminated union containing additional details concerning the L2CAP
* event. The 'type' field indicates which member of the union is valid.
*/
union {
/**
* Represents a connection attempt. Valid for the following event
* types:
* o BLE_L2CAP_EVENT_COC_CONNECTED */
struct {
/**
* The status of the connection attempt;
* o 0: the connection was successfully established.
* o BLE host error code: the connection attempt failed for
* the specified reason.
*/
int status;
/** Connection handle of the relevant connection */
uint16_t conn_handle;
/** The L2CAP channel of the relevant L2CAP connection. */
struct ble_l2cap_chan *chan;
} connect;
/**
* Represents a terminated connection. Valid for the following event
* types:
* o BLE_L2CAP_EVENT_COC_DISCONNECTED
*/
struct {
/** Connection handle of the relevant connection */
uint16_t conn_handle;
/** Information about the L2CAP connection prior to termination. */
struct ble_l2cap_chan *chan;
} disconnect;
/**
* Represents connection accept. Valid for the following event
* types:
* o BLE_L2CAP_EVENT_COC_ACCEPT
*/
struct {
/** Connection handle of the relevant connection */
uint16_t conn_handle;
/** MTU supported by peer device on the channel */
uint16_t peer_sdu_size;
/** The L2CAP channel of the relevant L2CAP connection. */
struct ble_l2cap_chan *chan;
} accept;
/**
* Represents received data. Valid for the following event
* types:
* o BLE_L2CAP_EVENT_COC_DATA_RECEIVED
*/
struct {
/** Connection handle of the relevant connection */
uint16_t conn_handle;
/** The L2CAP channel of the relevant L2CAP connection. */
struct ble_l2cap_chan *chan;
/** The mbuf with received SDU. */
struct os_mbuf *sdu_rx;
} receive;
/**
* Represents tx_unstalled data. Valid for the following event
* types:
* o BLE_L2CAP_EVENT_COC_TX_UNSTALLED
*/
struct {
/** Connection handle of the relevant connection */
uint16_t conn_handle;
/** The L2CAP channel of the relevant L2CAP connection. */
struct ble_l2cap_chan *chan;
/**
* The status of the send attempt which was stalled due to
* lack of credits; This can be non zero only if there
* is an issue with memory allocation for following SDU fragments.
* In such a case last SDU has been partially sent to peer device
* and it is up to application to decide how to handle it.
*/
int status;
} tx_unstalled;
/**
* Represents reconfiguration done. Valid for the following event
* types:
* o BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED
* o BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED
*/
struct {
/**
* The status of the reconfiguration attempt;
* o 0: the reconfiguration was successfully done.
* o BLE host error code: the reconfiguration attempt failed for
* the specified reason.
*/
int status;
/** Connection handle of the relevant connection */
uint16_t conn_handle;
/** The L2CAP channel of the relevant L2CAP connection. */
struct ble_l2cap_chan *chan;
} reconfigured;
};
};
struct ble_l2cap_chan_info {
uint16_t scid;
uint16_t dcid;
uint16_t our_l2cap_mtu;
uint16_t peer_l2cap_mtu;
uint16_t psm;
uint16_t our_coc_mtu;
uint16_t peer_coc_mtu;
};
typedef int ble_l2cap_event_fn(struct ble_l2cap_event *event, void *arg);
uint16_t ble_l2cap_get_conn_handle(struct ble_l2cap_chan *chan);
int ble_l2cap_create_server(uint16_t psm, uint16_t mtu,
ble_l2cap_event_fn *cb, void *cb_arg);
int ble_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
struct os_mbuf *sdu_rx,
ble_l2cap_event_fn *cb, void *cb_arg);
int ble_l2cap_disconnect(struct ble_l2cap_chan *chan);
int ble_l2cap_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_tx);
int ble_l2cap_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx);
int ble_l2cap_get_chan_info(struct ble_l2cap_chan *chan, struct ble_l2cap_chan_info *chan_info);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_MONITOR_
#define H_BLE_MONITOR_
#include <syscfg/syscfg.h>
#undef BLE_MONITOR
#define BLE_MONITOR (MYNEWT_VAL(BLE_MONITOR_UART) || MYNEWT_VAL(BLE_MONITOR_RTT))
#ifdef __cplusplus
extern "C" {
#endif
int ble_monitor_log(int level, const char *fmt, ...);
int ble_monitor_out(int c);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,124 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_SM_
#define H_BLE_SM_
#include <inttypes.h>
#include "syscfg/syscfg.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_SM_ERR_PASSKEY 0x01
#define BLE_SM_ERR_OOB 0x02
#define BLE_SM_ERR_AUTHREQ 0x03
#define BLE_SM_ERR_CONFIRM_MISMATCH 0x04
#define BLE_SM_ERR_PAIR_NOT_SUPP 0x05
#define BLE_SM_ERR_ENC_KEY_SZ 0x06
#define BLE_SM_ERR_CMD_NOT_SUPP 0x07
#define BLE_SM_ERR_UNSPECIFIED 0x08
#define BLE_SM_ERR_REPEATED 0x09
#define BLE_SM_ERR_INVAL 0x0a
#define BLE_SM_ERR_DHKEY 0x0b
#define BLE_SM_ERR_NUMCMP 0x0c
#define BLE_SM_ERR_ALREADY 0x0d
#define BLE_SM_ERR_CROSS_TRANS 0x0e
#define BLE_SM_ERR_MAX_PLUS_1 0x0f
#define BLE_SM_PAIR_ALG_JW 0
#define BLE_SM_PAIR_ALG_PASSKEY 1
#define BLE_SM_PAIR_ALG_OOB 2
#define BLE_SM_PAIR_ALG_NUMCMP 3
#define BLE_SM_PAIR_KEY_DIST_ENC 0x01
#define BLE_SM_PAIR_KEY_DIST_ID 0x02
#define BLE_SM_PAIR_KEY_DIST_SIGN 0x04
#define BLE_SM_PAIR_KEY_DIST_LINK 0x08
#define BLE_SM_PAIR_KEY_DIST_RESERVED 0xf0
#define BLE_SM_IO_CAP_DISP_ONLY 0x00
#define BLE_SM_IO_CAP_DISP_YES_NO 0x01
#define BLE_SM_IO_CAP_KEYBOARD_ONLY 0x02
#define BLE_SM_IO_CAP_NO_IO 0x03
#define BLE_SM_IO_CAP_KEYBOARD_DISP 0x04
#define BLE_SM_IO_CAP_RESERVED 0x05
#define BLE_SM_PAIR_OOB_NO 0x00
#define BLE_SM_PAIR_OOB_YES 0x01
#define BLE_SM_PAIR_OOB_RESERVED 0x02
#define BLE_SM_PAIR_AUTHREQ_BOND 0x01
#define BLE_SM_PAIR_AUTHREQ_MITM 0x04
#define BLE_SM_PAIR_AUTHREQ_SC 0x08
#define BLE_SM_PAIR_AUTHREQ_KEYPRESS 0x10
#define BLE_SM_PAIR_AUTHREQ_RESERVED 0xe2
#define BLE_SM_PAIR_KEY_SZ_MIN 7
#define BLE_SM_PAIR_KEY_SZ_MAX 16
/*
* The security manager asks the application to perform a key generation
* action. The application passes the passkey back to SM via
* ble_sm_inject_io().
*/
#define BLE_SM_IOACT_NONE 0
#define BLE_SM_IOACT_OOB 1
#define BLE_SM_IOACT_INPUT 2
#define BLE_SM_IOACT_DISP 3
#define BLE_SM_IOACT_NUMCMP 4
#define BLE_SM_IOACT_OOB_SC 5
#define BLE_SM_IOACT_MAX_PLUS_ONE 6
struct ble_sm_sc_oob_data {
/** Random Number. */
uint8_t r[16];
/** Confirm Value. */
uint8_t c[16];
};
struct ble_sm_io {
uint8_t action;
union {
uint32_t passkey;
uint8_t oob[16];
uint8_t numcmp_accept;
struct {
struct ble_sm_sc_oob_data *local;
struct ble_sm_sc_oob_data *remote;
} oob_sc_data;
};
};
int ble_sm_sc_oob_generate_data(struct ble_sm_sc_oob_data *oob_data);
#if NIMBLE_BLE_SM
int ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey);
#else
#define ble_sm_inject_io(conn_handle, pkey) \
((void)(conn_handle), BLE_HS_ENOTSUP)
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,303 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_STORE_
#define H_BLE_STORE_
#include <inttypes.h>
#include "nimble/ble.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_STORE_OBJ_TYPE_OUR_SEC 1
#define BLE_STORE_OBJ_TYPE_PEER_SEC 2
#define BLE_STORE_OBJ_TYPE_CCCD 3
/** Failed to persist record; insufficient storage capacity. */
#define BLE_STORE_EVENT_OVERFLOW 1
/** About to execute a procedure that may fail due to overflow. */
#define BLE_STORE_EVENT_FULL 2
/**
* Used as a key for lookups of security material. This struct corresponds to
* the following store object types:
* o BLE_STORE_OBJ_TYPE_OUR_SEC
* o BLE_STORE_OBJ_TYPE_PEER_SEC
*/
struct ble_store_key_sec {
/**
* Key by peer identity address;
* peer_addr=BLE_ADDR_NONE means don't key off peer.
*/
ble_addr_t peer_addr;
/** Key by ediv; ediv_rand_present=0 means don't key off ediv. */
uint16_t ediv;
/** Key by rand_num; ediv_rand_present=0 means don't key off rand_num. */
uint64_t rand_num;
unsigned ediv_rand_present:1;
/** Number of results to skip; 0 means retrieve the first match. */
uint8_t idx;
};
/**
* Represents stored security material. This struct corresponds to the
* following store object types:
* o BLE_STORE_OBJ_TYPE_OUR_SEC
* o BLE_STORE_OBJ_TYPE_PEER_SEC
*/
struct ble_store_value_sec {
ble_addr_t peer_addr;
uint8_t key_size;
uint16_t ediv;
uint64_t rand_num;
uint8_t ltk[16];
uint8_t ltk_present:1;
uint8_t irk[16];
uint8_t irk_present:1;
uint8_t csrk[16];
uint8_t csrk_present:1;
unsigned authenticated:1;
uint8_t sc:1;
};
/**
* Used as a key for lookups of stored client characteristic configuration
* descriptors (CCCDs). This struct corresponds to the BLE_STORE_OBJ_TYPE_CCCD
* store object type.
*/
struct ble_store_key_cccd {
/**
* Key by peer identity address;
* peer_addr=BLE_ADDR_NONE means don't key off peer.
*/
ble_addr_t peer_addr;
/**
* Key by characteristic value handle;
* chr_val_handle=0 means don't key off characteristic handle.
*/
uint16_t chr_val_handle;
/** Number of results to skip; 0 means retrieve the first match. */
uint8_t idx;
};
/**
* Represents a stored client characteristic configuration descriptor (CCCD).
* This struct corresponds to the BLE_STORE_OBJ_TYPE_CCCD store object type.
*/
struct ble_store_value_cccd {
ble_addr_t peer_addr;
uint16_t chr_val_handle;
uint16_t flags;
unsigned value_changed:1;
};
/**
* Used as a key for store lookups. This union must be accompanied by an
* object type code to indicate which field is valid.
*/
union ble_store_key {
struct ble_store_key_sec sec;
struct ble_store_key_cccd cccd;
};
/**
* Represents stored data. This union must be accompanied by an object type
* code to indicate which field is valid.
*/
union ble_store_value {
struct ble_store_value_sec sec;
struct ble_store_value_cccd cccd;
};
struct ble_store_status_event {
/**
* The type of event being reported; one of the BLE_STORE_EVENT_TYPE_[...]
* codes.
*/
int event_code;
/**
* Additional data related to the event; the valid field is inferred from
* the obj_type,event_code pair.
*/
union {
/**
* Represents a write that failed due to storage exhaustion. Valid for
* the following event types:
* o BLE_STORE_EVENT_OVERFLOW
*/
struct {
/** The type of object that failed to be written. */
int obj_type;
/** The object that failed to be written. */
const union ble_store_value *value;
} overflow;
/**
* Represents the possibility that a scheduled write will fail due to
* storage exhaustion. Valid for the following event types:
* o BLE_STORE_EVENT_FULL
*/
struct {
/** The type of object that may fail to be written. */
int obj_type;
/** The handle of the connection which prompted the write. */
uint16_t conn_handle;
} full;
};
};
/**
* Searches the store for an object matching the specified criteria. If a
* match is found, it is read from the store and the dst parameter is populated
* with the retrieved object.
*
* @param obj_type The type of object to search for; one of the
* BLE_STORE_OBJ_TYPE_[...] codes.
* @param key Specifies properties of the object to search
* for. An object is retrieved if it matches
* these criteria.
* @param dst On success, this is populated with the
* retrieved object.
*
* @return 0 if an object was successfully retreived;
* BLE_HS_ENOENT if no matching object was found;
* Other nonzero on error.
*/
typedef int ble_store_read_fn(int obj_type, const union ble_store_key *key,
union ble_store_value *dst);
/**
* Writes the specified object to the store. If an object with the same
* identity is already in the store, it is replaced. If the store lacks
* sufficient capacity to write the object, this function may remove previously
* stored values to make room.
*
* @param obj_type The type of object being written; one of the
* BLE_STORE_OBJ_TYPE_[...] codes.
* @param val The object to persist.
*
* @return 0 if the object was successfully written;
* Other nonzero on error.
*/
typedef int ble_store_write_fn(int obj_type, const union ble_store_value *val);
/**
* Searches the store for the first object matching the specified criteria. If
* a match is found, it is deleted from the store.
*
* @param obj_type The type of object to delete; one of the
* BLE_STORE_OBJ_TYPE_[...] codes.
* @param key Specifies properties of the object to search
* for. An object is deleted if it matches
* these criteria.
* @return 0 if an object was successfully retrieved;
* BLE_HS_ENOENT if no matching object was found;
* Other nonzero on error.
*/
typedef int ble_store_delete_fn(int obj_type, const union ble_store_key *key);
/**
* Indicates an inability to perform a store operation. This callback should
* do one of two things:
* o Address the problem and return 0, indicating that the store operation
* should proceed.
* o Return nonzero to indicate that the store operation should be aborted.
*
* @param event Describes the store event being reported.
* @param arg Optional user argument.
*
* @return 0 if the store operation should proceed;
* nonzero if the store operation should be
* aborted.
*/
typedef int ble_store_status_fn(struct ble_store_status_event *event,
void *arg);
int ble_store_read(int obj_type, const union ble_store_key *key,
union ble_store_value *val);
int ble_store_write(int obj_type, const union ble_store_value *val);
int ble_store_delete(int obj_type, const union ble_store_key *key);
int ble_store_overflow_event(int obj_type, const union ble_store_value *value);
int ble_store_full_event(int obj_type, uint16_t conn_handle);
int ble_store_read_our_sec(const struct ble_store_key_sec *key_sec,
struct ble_store_value_sec *value_sec);
int ble_store_write_our_sec(const struct ble_store_value_sec *value_sec);
int ble_store_delete_our_sec(const struct ble_store_key_sec *key_sec);
int ble_store_read_peer_sec(const struct ble_store_key_sec *key_sec,
struct ble_store_value_sec *value_sec);
int ble_store_write_peer_sec(const struct ble_store_value_sec *value_sec);
int ble_store_delete_peer_sec(const struct ble_store_key_sec *key_sec);
int ble_store_read_cccd(const struct ble_store_key_cccd *key,
struct ble_store_value_cccd *out_value);
int ble_store_write_cccd(const struct ble_store_value_cccd *value);
int ble_store_delete_cccd(const struct ble_store_key_cccd *key);
void ble_store_key_from_value_sec(struct ble_store_key_sec *out_key,
const struct ble_store_value_sec *value);
void ble_store_key_from_value_cccd(struct ble_store_key_cccd *out_key,
const struct ble_store_value_cccd *value);
void ble_store_key_from_value(int obj_type,
union ble_store_key *out_key,
const union ble_store_value *value);
typedef int ble_store_iterator_fn(int obj_type,
union ble_store_value *val,
void *cookie);
int ble_store_iterate(int obj_type,
ble_store_iterator_fn *callback,
void *cookie);
int ble_store_clear(void);
/*** Utility functions. */
int ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs,
int *out_num_peers,
int max_peers);
int ble_store_util_delete_all(int type, const union ble_store_key *key);
int ble_store_util_delete_peer(const ble_addr_t *peer_id_addr);
int ble_store_util_delete_oldest_peer(void);
int ble_store_util_count(int type, int *out_count);
int ble_store_util_status_rr(struct ble_store_status_event *event, void *arg);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,182 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 H_BLE_UUID_
#define H_BLE_UUID_
/**
* @brief Bluetooth UUID
* @defgroup bt_uuid Bluetooth UUID
* @ingroup bt_host
* @{
*/
#include <inttypes.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
struct os_mbuf;
/** Type of UUID */
enum {
/** 16-bit UUID (BT SIG assigned) */
BLE_UUID_TYPE_16 = 16,
/** 32-bit UUID (BT SIG assigned) */
BLE_UUID_TYPE_32 = 32,
/** 128-bit UUID */
BLE_UUID_TYPE_128 = 128,
};
/** Generic UUID type, to be used only as a pointer */
typedef struct {
/** Type of the UUID */
uint8_t type;
} ble_uuid_t;
/** 16-bit UUID */
typedef struct {
ble_uuid_t u;
uint16_t value;
} ble_uuid16_t;
/** 32-bit UUID */
typedef struct {
ble_uuid_t u;
uint32_t value;
} ble_uuid32_t;
/** 128-bit UUID */
typedef struct {
ble_uuid_t u;
uint8_t value[16];
} ble_uuid128_t;
/** Universal UUID type, to be used for any-UUID static allocation */
typedef union {
ble_uuid_t u;
ble_uuid16_t u16;
ble_uuid32_t u32;
ble_uuid128_t u128;
} ble_uuid_any_t;
#define BLE_UUID16_INIT(uuid16) \
{ \
.u.type = BLE_UUID_TYPE_16, \
.value = (uuid16), \
}
#define BLE_UUID32_INIT(uuid32) \
{ \
.u.type = BLE_UUID_TYPE_32, \
.value = (uuid32), \
}
#define BLE_UUID128_INIT(uuid128...) \
{ \
.u.type = BLE_UUID_TYPE_128, \
.value = { uuid128 }, \
}
#define BLE_UUID16_DECLARE(uuid16) \
((ble_uuid_t *) (&(ble_uuid16_t) BLE_UUID16_INIT(uuid16)))
#define BLE_UUID32_DECLARE(uuid32) \
((ble_uuid_t *) (&(ble_uuid32_t) BLE_UUID32_INIT(uuid32)))
#define BLE_UUID128_DECLARE(uuid128...) \
((ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT(uuid128)))
#define BLE_UUID16(u) \
((ble_uuid16_t *) (u))
#define BLE_UUID32(u) \
((ble_uuid32_t *) (u))
#define BLE_UUID128(u) \
((ble_uuid128_t *) (u))
/** Size of buffer needed to store UUID as a string.
* Includes trailing \0.
*/
#define BLE_UUID_STR_LEN (37)
/** @brief Constructs a UUID object from a byte array.
*
* @param uuid On success, this gets populated with the constructed UUID.
* @param buf The source buffer to parse.
* @param len The size of the buffer, in bytes.
*
* @return 0 on success, BLE_HS_EINVAL if the source buffer does not contain
* a valid UUID.
*/
int ble_uuid_init_from_buf(ble_uuid_any_t *uuid, const void *buf, size_t len);
/** @brief Compares two Bluetooth UUIDs.
*
* @param uuid1 The first UUID to compare.
* @param uuid2 The second UUID to compare.
*
* @return 0 if the two UUIDs are equal, nonzero if the UUIDs differ.
*/
int ble_uuid_cmp(const ble_uuid_t *uuid1, const ble_uuid_t *uuid2);
/** @brief Copy Bluetooth UUID
*
* @param dst Destination UUID.
* @param src Source UUID.
*/
void ble_uuid_copy(ble_uuid_any_t *dst, const ble_uuid_t *src);
/** @brief Converts the specified UUID to its string representation.
*
* Example string representations:
* o 16-bit: 0x1234
* o 32-bit: 0x12345678
* o 128-bit: 12345678-1234-1234-1234-123456789abc
*
* @param uuid The source UUID to convert.
* @param dst The destination buffer.
*
* @return A pointer to the supplied destination buffer.
*/
char *ble_uuid_to_str(const ble_uuid_t *uuid, char *dst);
/** @brief Converts the specified 16-bit UUID to a uint16_t.
*
* @param uuid The source UUID to convert.
*
* @return The converted integer on success, NULL if the specified UUID is
* not 16 bits.
*/
uint16_t ble_uuid_u16(const ble_uuid_t *uuid);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* _BLE_HOST_UUID_H */

View File

@@ -0,0 +1,656 @@
/** @file
* @brief Bluetooth Mesh Access Layer APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_MESH_ACCESS_H
#define __BT_MESH_ACCESS_H
/**
* @brief Bluetooth Mesh Access Layer
* @defgroup bt_mesh_access Bluetooth Mesh Access Layer
* @ingroup bt_mesh
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
#define BT_MESH_ADDR_UNASSIGNED 0x0000
#define BT_MESH_ADDR_ALL_NODES 0xffff
#define BT_MESH_ADDR_PROXIES 0xfffc
#define BT_MESH_ADDR_FRIENDS 0xfffd
#define BT_MESH_ADDR_RELAYS 0xfffe
#define BT_MESH_KEY_UNUSED 0xffff
#define BT_MESH_KEY_DEV 0xfffe
#define BT_MESH_KEY_DEV_LOCAL BT_MESH_KEY_DEV
#define BT_MESH_KEY_DEV_REMOTE 0xfffd
#define BT_MESH_KEY_DEV_ANY 0xfffc
#define BT_MESH_IS_DEV_KEY(key) (key == BT_MESH_KEY_DEV_LOCAL || \
key == BT_MESH_KEY_DEV_REMOTE)
/** Helper to define a mesh element within an array.
*
* In case the element has no SIG or Vendor models the helper
* macro BT_MESH_MODEL_NONE can be given instead.
*
* @param _loc Location Descriptor.
* @param _mods Array of models.
* @param _vnd_mods Array of vendor models.
*/
#define BT_MESH_ELEM(_loc, _mods, _vnd_mods) \
{ \
.loc = (_loc), \
.model_count = ARRAY_SIZE(_mods), \
.models = (_mods), \
.vnd_model_count = ARRAY_SIZE(_vnd_mods), \
.vnd_models = (_vnd_mods), \
}
/** Abstraction that describes a Mesh Element */
struct bt_mesh_elem {
/* Unicast Address. Set at runtime during provisioning. */
u16_t addr;
/* Location Descriptor (GATT Bluetooth Namespace Descriptors) */
const u16_t loc;
const u8_t model_count;
const u8_t vnd_model_count;
struct bt_mesh_model * const models;
struct bt_mesh_model * const vnd_models;
};
/* Foundation Models */
#define BT_MESH_MODEL_ID_CFG_SRV 0x0000
#define BT_MESH_MODEL_ID_CFG_CLI 0x0001
#define BT_MESH_MODEL_ID_HEALTH_SRV 0x0002
#define BT_MESH_MODEL_ID_HEALTH_CLI 0x0003
/* Models from the Mesh Model Specification */
#define BT_MESH_MODEL_ID_GEN_ONOFF_SRV 0x1000
#define BT_MESH_MODEL_ID_GEN_ONOFF_CLI 0x1001
#define BT_MESH_MODEL_ID_GEN_LEVEL_SRV 0x1002
#define BT_MESH_MODEL_ID_GEN_LEVEL_CLI 0x1003
#define BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV 0x1004
#define BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI 0x1005
#define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV 0x1006
#define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV 0x1007
#define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI 0x1008
#define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV 0x1009
#define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV 0x100a
#define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI 0x100b
#define BT_MESH_MODEL_ID_GEN_BATTERY_SRV 0x100c
#define BT_MESH_MODEL_ID_GEN_BATTERY_CLI 0x100d
#define BT_MESH_MODEL_ID_GEN_LOCATION_SRV 0x100e
#define BT_MESH_MODEL_ID_GEN_LOCATION_SETUPSRV 0x100f
#define BT_MESH_MODEL_ID_GEN_LOCATION_CLI 0x1010
#define BT_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV 0x1011
#define BT_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV 0x1012
#define BT_MESH_MODEL_ID_GEN_USER_PROP_SRV 0x1013
#define BT_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV 0x1014
#define BT_MESH_MODEL_ID_GEN_PROP_CLI 0x1015
#define BT_MESH_MODEL_ID_SENSOR_SRV 0x1100
#define BT_MESH_MODEL_ID_SENSOR_SETUP_SRV 0x1101
#define BT_MESH_MODEL_ID_SENSOR_CLI 0x1102
#define BT_MESH_MODEL_ID_TIME_SRV 0x1200
#define BT_MESH_MODEL_ID_TIME_SETUP_SRV 0x1201
#define BT_MESH_MODEL_ID_TIME_CLI 0x1202
#define BT_MESH_MODEL_ID_SCENE_SRV 0x1203
#define BT_MESH_MODEL_ID_SCENE_SETUP_SRV 0x1204
#define BT_MESH_MODEL_ID_SCENE_CLI 0x1205
#define BT_MESH_MODEL_ID_SCHEDULER_SRV 0x1206
#define BT_MESH_MODEL_ID_SCHEDULER_SETUP_SRV 0x1207
#define BT_MESH_MODEL_ID_SCHEDULER_CLI 0x1208
#define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV 0x1300
#define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV 0x1301
#define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI 0x1302
#define BT_MESH_MODEL_ID_LIGHT_CTL_SRV 0x1303
#define BT_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV 0x1304
#define BT_MESH_MODEL_ID_LIGHT_CTL_CLI 0x1305
#define BT_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV 0x1306
#define BT_MESH_MODEL_ID_LIGHT_HSL_SRV 0x1307
#define BT_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV 0x1308
#define BT_MESH_MODEL_ID_LIGHT_HSL_CLI 0x1309
#define BT_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV 0x130a
#define BT_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV 0x130b
#define BT_MESH_MODEL_ID_LIGHT_XYL_SRV 0x130c
#define BT_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV 0x130d
#define BT_MESH_MODEL_ID_LIGHT_XYL_CLI 0x130e
#define BT_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f
#define BT_MESH_MODEL_ID_LIGHT_LC_SETUPSRV 0x1310
#define BT_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311
/** Message sending context. */
struct bt_mesh_msg_ctx {
/** NetKey Index of the subnet to send the message on. */
u16_t net_idx;
/** AppKey Index to encrypt the message with. */
u16_t app_idx;
/** Remote address. */
u16_t addr;
/** Destination address of a received message. Not used for sending. */
u16_t recv_dst;
/** RSSI of received packet. Not used for sending. */
s8_t recv_rssi;
/** Received TTL value. Not used for sending. */
u8_t recv_ttl;
/** Force sending reliably by using segment acknowledgement */
bool send_rel;
/** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */
u8_t send_ttl;
};
struct bt_mesh_model_op {
/* OpCode encoded using the BT_MESH_MODEL_OP_* macros */
const u32_t opcode;
/* Minimum required message length */
const size_t min_len;
/* Message handler for the opcode */
void (*const func)(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf);
};
#define BT_MESH_MODEL_OP_1(b0) (b0)
#define BT_MESH_MODEL_OP_2(b0, b1) (((b0) << 8) | (b1))
#define BT_MESH_MODEL_OP_3(b0, cid) ((((b0) << 16) | 0xc00000) | (cid))
#define BT_MESH_MODEL_OP_END { 0, 0, NULL }
#define BT_MESH_MODEL_NO_OPS ((struct bt_mesh_model_op []) \
{ BT_MESH_MODEL_OP_END })
/** Helper to define an empty model array */
#define BT_MESH_MODEL_NONE ((struct bt_mesh_model []){})
/** Length of a short Mesh MIC. */
#define BT_MESH_MIC_SHORT 4
/** Length of a long Mesh MIC. */
#define BT_MESH_MIC_LONG 8
/** @def BT_MESH_MODEL_OP_LEN
*
* @brief Helper to determine the length of an opcode.
*
* @param _op Opcode.
*/
#define BT_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3)
/** @def BT_MESH_MODEL_BUF_LEN
*
* @brief Helper for model message buffer length.
*
* Returns the length of a Mesh model message buffer, including the opcode
* length and a short MIC.
*
* @param _op Opcode of the message.
* @param _payload_len Length of the model payload.
*/
#define BT_MESH_MODEL_BUF_LEN(_op, _payload_len) \
(BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_SHORT)
/** @def BT_MESH_MODEL_BUF_LEN_LONG_MIC
*
* @brief Helper for model message buffer length.
*
* Returns the length of a Mesh model message buffer, including the opcode
* length and a long MIC.
*
* @param _op Opcode of the message.
* @param _payload_len Length of the model payload.
*/
#define BT_MESH_MODEL_BUF_LEN_LONG_MIC(_op, _payload_len) \
(BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_LONG)
/** @def BT_MESH_MODEL_BUF_DEFINE
*
* @brief Define a Mesh model message buffer using @ref NET_BUF_SIMPLE.
*
* @param _op Opcode of the message.
* @param _payload_len Length of the model message payload.
*/
#define BT_MESH_MODEL_BUF(_op, _payload_len) \
NET_BUF_SIMPLE(BT_MESH_MODEL_BUF_LEN(_op, (_payload_len)))
/** @def BT_MESH_MODEL_CB
*
* @brief Composition data SIG model entry with callback functions.
*
* @param _id Model ID.
* @param _op Array of model opcode handlers.
* @param _pub Model publish parameters.
* @param _user_data User data for the model.
* @param _cb Callback structure, or NULL to keep no callbacks.
*/
#define BT_MESH_MODEL_CB(_id, _op, _pub, _user_data, _cb) \
{ \
.id = (_id), \
.op = _op, \
.keys = { [0 ... (CONFIG_BT_MESH_MODEL_KEY_COUNT - 1)] = \
BT_MESH_KEY_UNUSED }, \
.pub = _pub, \
.groups = { [0 ... (CONFIG_BT_MESH_MODEL_GROUP_COUNT - 1)] = \
BT_MESH_ADDR_UNASSIGNED }, \
.user_data = _user_data, \
.cb = _cb, \
}
/** @def BT_MESH_MODEL_VND_CB
*
* @brief Composition data vendor model entry with callback functions.
*
* @param _company Company ID.
* @param _id Model ID.
* @param _op Array of model opcode handlers.
* @param _pub Model publish parameters.
* @param _user_data User data for the model.
* @param _cb Callback structure, or NULL to keep no callbacks.
*/
#define BT_MESH_MODEL_VND_CB(_company, _id, _op, _pub, _user_data, _cb) \
{ \
.vnd.company = (_company), \
.vnd.id = (_id), \
.op = _op, \
.pub = _pub, \
.keys = { [0 ... (CONFIG_BT_MESH_MODEL_KEY_COUNT - 1)] = \
BT_MESH_KEY_UNUSED }, \
.groups = { [0 ... (CONFIG_BT_MESH_MODEL_GROUP_COUNT - 1)] = \
BT_MESH_ADDR_UNASSIGNED }, \
.user_data = _user_data, \
.cb = _cb, \
}
/** @def BT_MESH_MODEL
*
* @brief Composition data SIG model entry.
*
* @param _id Model ID.
* @param _op Array of model opcode handlers.
* @param _pub Model publish parameters.
* @param _user_data User data for the model.
*/
#define BT_MESH_MODEL(_id, _op, _pub, _user_data) \
BT_MESH_MODEL_CB(_id, _op, _pub, _user_data, NULL)
/** @def BT_MESH_MODEL_VND
*
* @brief Composition data vendor model entry.
*
* @param _company Company ID.
* @param _id Model ID.
* @param _op Array of model opcode handlers.
* @param _pub Model publish parameters.
* @param _user_data User data for the model.
*/
#define BT_MESH_MODEL_VND(_company, _id, _op, _pub, _user_data) \
BT_MESH_MODEL_VND_CB(_company, _id, _op, _pub, _user_data, NULL)
/** @def BT_MESH_TRANSMIT
*
* @brief Encode transmission count & interval steps.
*
* @param count Number of retransmissions (first transmission is excluded).
* @param int_ms Interval steps in milliseconds. Must be greater than 0,
* less than or equal to 320, and a multiple of 10.
*
* @return Mesh transmit value that can be used e.g. for the default
* values of the configuration model data.
*/
#define BT_MESH_TRANSMIT(count, int_ms) ((count) | (((int_ms / 10) - 1) << 3))
/** @def BT_MESH_TRANSMIT_COUNT
*
* @brief Decode transmit count from a transmit value.
*
* @param transmit Encoded transmit count & interval value.
*
* @return Transmission count (actual transmissions is N + 1).
*/
#define BT_MESH_TRANSMIT_COUNT(transmit) (((transmit) & (u8_t)BIT_MASK(3)))
/** @def BT_MESH_TRANSMIT_INT
*
* @brief Decode transmit interval from a transmit value.
*
* @param transmit Encoded transmit count & interval value.
*
* @return Transmission interval in milliseconds.
*/
#define BT_MESH_TRANSMIT_INT(transmit) ((((transmit) >> 3) + 1) * 10)
/** @def BT_MESH_PUB_TRANSMIT
*
* @brief Encode Publish Retransmit count & interval steps.
*
* @param count Number of retransmissions (first transmission is excluded).
* @param int_ms Interval steps in milliseconds. Must be greater than 0
* and a multiple of 50.
*
* @return Mesh transmit value that can be used e.g. for the default
* values of the configuration model data.
*/
#define BT_MESH_PUB_TRANSMIT(count, int_ms) BT_MESH_TRANSMIT(count, \
(int_ms) / 5)
/** @def BT_MESH_PUB_TRANSMIT_COUNT
*
* @brief Decode Pubhlish Retransmit count from a given value.
*
* @param transmit Encoded Publish Retransmit count & interval value.
*
* @return Retransmission count (actual transmissions is N + 1).
*/
#define BT_MESH_PUB_TRANSMIT_COUNT(transmit) BT_MESH_TRANSMIT_COUNT(transmit)
/** @def BT_MESH_PUB_TRANSMIT_INT
*
* @brief Decode Publish Retransmit interval from a given value.
*
* @param transmit Encoded Publish Retransmit count & interval value.
*
* @return Transmission interval in milliseconds.
*/
#define BT_MESH_PUB_TRANSMIT_INT(transmit) ((((transmit) >> 3) + 1) * 50)
/** Model publication context. */
struct bt_mesh_model_pub {
/** The model the context belongs to. Initialized by the stack. */
struct bt_mesh_model *mod;
u16_t addr; /**< Publish Address. */
u16_t key; /**< Publish AppKey Index. */
u8_t ttl; /**< Publish Time to Live. */
u8_t retransmit; /**< Retransmit Count & Interval Steps. */
u8_t period; /**< Publish Period. */
u8_t period_div:4, /**< Divisor for the Period. */
cred:1, /**< Friendship Credentials Flag. */
fast_period:1,/**< Use FastPeriodDivisor */
count:3; /**< Retransmissions left. */
u32_t period_start; /**< Start of the current period. */
/** @brief Publication buffer, containing the publication message.
*
* The application is expected to initialize this with
* a valid net_buf_simple pointer, with the help of e.g.
* the NET_BUF_SIMPLE() macro. The publication buffer must
* contain a valid publication message before calling the
* bt_mesh_model_publish() API or after the publication's
* @ref bt_mesh_model_pub.update callback has been called
* and returned success. The buffer must be created outside
* of function context, i.e. it must not be on the stack.
* This is most conveniently acheived by creating it inline
* when declaring the publication context:
*
* static struct bt_mesh_model_pub my_pub = {
* .msg = NET_BUF_SIMPLE(size),
* };
*/
struct os_mbuf *msg;
/** @brief Callback for updating the publication buffer.
*
* When set to NULL, the model is assumed not to support
* periodic publishing. When set to non-NULL the callback
* will be called periodically and is expected to update
* @ref bt_mesh_model_pub.msg with a valid publication
* message.
*
* @param mod The Model the Publication Context belogs to.
*
* @return Zero on success or (negative) error code otherwise.
*/
int (*update)(struct bt_mesh_model *mod);
/** Publish Period Timer. Only for stack-internal use. */
struct k_delayed_work timer;
};
/** Model callback functions. */
struct bt_mesh_model_cb {
/** @brief Set value handler of user data tied to the model.
*
* @sa settings_handler::h_set
*
* @param model Model to set the persistent data of.
* @param val Data from the backend.
*
* @return 0 on success, error otherwise.
*/
int (*const settings_set)(struct bt_mesh_model *model, char *val);
/** @brief Callback called when all settings have been loaded.
*
* This handler gets called after the settings have been loaded in
* full.
*
* @sa settings_handler::h_commit
*
* @param model Model this callback belongs to.
*
* @return 0 on success, error otherwise.
*/
int (*const settings_commit)(struct bt_mesh_model *model);
/** @brief Model init callback.
*
* Called on every model instance during mesh initialization.
*
* @param model Model to be initialized.
*
* @return 0 on success, error otherwise.
*/
int (*const init)(struct bt_mesh_model *model);
/** @brief Model reset callback.
*
* Called when the mesh node is reset. All model data is deleted on
* reset, and the model should clear its state.
*
* @param model Model this callback belongs to.
*/
void (*const reset)(struct bt_mesh_model *model);
};
/** Abstraction that describes a Mesh Model instance */
struct bt_mesh_model {
union {
const u16_t id;
struct {
u16_t company;
u16_t id;
} vnd;
};
/* Internal information, mainly for persistent storage */
u8_t elem_idx; /* Belongs to Nth element */
u8_t mod_idx; /* Is the Nth model in the element */
u16_t flags; /* Model flags for internal bookkeeping */
/* Model Publication */
struct bt_mesh_model_pub * const pub;
/* AppKey List */
u16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT];
/* Subscription List (group or virtual addresses) */
u16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT];
const struct bt_mesh_model_op * const op;
/* Model callback structure. */
const struct bt_mesh_model_cb * const cb;
#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS)
/* Pointer to the next model in a model extension tree. */
struct bt_mesh_model *next;
/* Pointer to the first model this model extends. */
struct bt_mesh_model *extends;
#endif
/* Model-specific user data */
void *user_data;
};
struct bt_mesh_send_cb {
void (*start)(u16_t duration, int err, void *cb_data);
void (*end)(int err, void *cb_data);
};
void bt_mesh_model_msg_init(struct os_mbuf *msg, u32_t opcode);
/** Special TTL value to request using configured default TTL */
#define BT_MESH_TTL_DEFAULT 0xff
/** Maximum allowed TTL value */
#define BT_MESH_TTL_MAX 0x7f
/**
* @brief Send an Access Layer message.
*
* @param model Mesh (client) Model that the message belongs to.
* @param ctx Message context, includes keys, TTL, etc.
* @param msg Access Layer payload (the actual message to be sent).
* @param cb Optional "message sent" callback.
* @param cb_data User data to be passed to the callback.
*
* @return 0 on success, or (negative) error code on failure.
*/
int bt_mesh_model_send(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *msg,
const struct bt_mesh_send_cb *cb,
void *cb_data);
/**
* @brief Send a model publication message.
*
* Before calling this function, the user needs to ensure that the model
* publication message (@ref bt_mesh_model_pub.msg) contains a valid
* message to be sent. Note that this API is only to be used for
* non-period publishing. For periodic publishing the app only needs
* to make sure that @ref bt_mesh_model_pub.msg contains a valid message
* whenever the @ref bt_mesh_model_pub.update callback is called.
*
* @param model Mesh (client) Model that's publishing the message.
*
* @return 0 on success, or (negative) error code on failure.
*/
int bt_mesh_model_publish(struct bt_mesh_model *model);
/**
* @brief Get the element that a model belongs to.
*
* @param mod Mesh model.
*
* @return Pointer to the element that the given model belongs to.
*/
struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod);
/** @brief Find a SIG model.
*
* @param elem Element to search for the model in.
* @param id Model ID of the model.
*
* @return A pointer to the Mesh model matching the given parameters, or NULL
* if no SIG model with the given ID exists in the given element.
*/
struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem,
u16_t id);
/** @brief Find a vendor model.
*
* @param elem Element to search for the model in.
* @param company Company ID of the model.
* @param id Model ID of the model.
*
* @return A pointer to the Mesh model matching the given parameters, or NULL
* if no vendor model with the given ID exists in the given element.
*/
struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem,
u16_t company, u16_t id);
/** @brief Get whether the model is in the primary element of the device.
*
* @param mod Mesh model.
*
* @return true if the model is on the primary element, false otherwise.
*/
static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod)
{
return (mod->elem_idx == 0);
}
/** @brief Immediately store the model's user data in persistent storage.
*
* @param mod Mesh model.
* @param vnd This is a vendor model.
* @param data Model data to store, or NULL to delete any model data.
* @param data_len Length of the model data.
*
* @return 0 on success, or (negative) error code on failure.
*/
int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd,
const void *data, size_t data_len);
/** @brief Let a model extend another.
*
* Mesh models may be extended to reuse their functionality, forming a more
* complex model. A Mesh model may extend any number of models, in any element.
* The extensions may also be nested, ie a model that extends another may itself
* be extended. Extensions may not be cyclical, and a model can only be extended
* by one other model.
*
* A set of models that extend each other form a model extension tree.
*
* All models in an extension tree share one subscription list per element. The
* access layer will utilize the combined subscription list of all models in an
* extension tree and element, giving the models extended subscription list
* capacity.
*
* @param[in] mod Mesh model.
* @param[in] base_mod The model being extended.
*
* @retval 0 Successfully extended the base_mod model.
* @retval -EALREADY The base_mod model is already extended.
*/
int bt_mesh_model_extend(struct bt_mesh_model *mod,
struct bt_mesh_model *base_mod);
/** Node Composition */
struct bt_mesh_comp {
u16_t cid;
u16_t pid;
u16_t vid;
size_t elem_count;
struct bt_mesh_elem *elem;
};
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __BT_MESH_ACCESS_H */

View File

@@ -0,0 +1,234 @@
/** @file
* @brief Bluetooth Mesh Configuration Client Model APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_MESH_CFG_CLI_H
#define __BT_MESH_CFG_CLI_H
/**
* @brief Bluetooth Mesh
* @defgroup bt_mesh_cfg_cli Bluetooth Mesh Configuration Client Model
* @ingroup bt_mesh
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/** Mesh Configuration Client Model Context */
struct bt_mesh_cfg_cli {
struct bt_mesh_model *model;
struct k_sem op_sync;
u32_t op_pending;
void *op_param;
};
extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb;
#define BT_MESH_MODEL_CFG_CLI(cli_data) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_CFG_CLI, bt_mesh_cfg_cli_op, NULL, \
cli_data, &bt_mesh_cfg_cli_cb)
int bt_mesh_cfg_comp_data_get(u16_t net_idx, u16_t addr, u8_t page,
u8_t *status, struct os_mbuf *comp);
int bt_mesh_cfg_beacon_get(u16_t net_idx, u16_t addr, u8_t *status);
int bt_mesh_cfg_beacon_set(u16_t net_idx, u16_t addr, u8_t val, u8_t *status);
int bt_mesh_cfg_ttl_get(u16_t net_idx, u16_t addr, u8_t *ttl);
int bt_mesh_cfg_ttl_set(u16_t net_idx, u16_t addr, u8_t val, u8_t *ttl);
int bt_mesh_cfg_friend_get(u16_t net_idx, u16_t addr, u8_t *status);
int bt_mesh_cfg_friend_set(u16_t net_idx, u16_t addr, u8_t val, u8_t *status);
int bt_mesh_cfg_gatt_proxy_get(u16_t net_idx, u16_t addr, u8_t *status);
int bt_mesh_cfg_gatt_proxy_set(u16_t net_idx, u16_t addr, u8_t val,
u8_t *status);
int bt_mesh_cfg_relay_get(u16_t net_idx, u16_t addr, u8_t *status,
u8_t *transmit);
int bt_mesh_cfg_relay_set(u16_t net_idx, u16_t addr, u8_t new_relay,
u8_t new_transmit, u8_t *status, u8_t *transmit);
int bt_mesh_cfg_net_key_add(u16_t net_idx, u16_t addr, u16_t key_net_idx,
const u8_t net_key[16], u8_t *status);
int bt_mesh_cfg_app_key_add(u16_t net_idx, u16_t addr, u16_t key_net_idx,
u16_t key_app_idx, const u8_t app_key[16],
u8_t *status);
int bt_mesh_cfg_mod_app_bind(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_app_idx, u16_t mod_id, u8_t *status);
int bt_mesh_cfg_mod_app_bind_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_app_idx, u16_t mod_id, u16_t cid,
u8_t *status);
/** @def BT_MESH_PUB_PERIOD_100MS
*
* @brief Helper macro to encode model publication period in units of 100ms
*
* @param steps Number of 100ms steps.
*
* @return Encoded value that can be assigned to bt_mesh_cfg_mod_pub.period
*/
#define BT_MESH_PUB_PERIOD_100MS(steps) ((steps) & BIT_MASK(6))
/** @def BT_MESH_PUB_PERIOD_SEC
*
* @brief Helper macro to encode model publication period in units of 1 second
*
* @param steps Number of 1 second steps.
*
* @return Encoded value that can be assigned to bt_mesh_cfg_mod_pub.period
*/
#define BT_MESH_PUB_PERIOD_SEC(steps) (((steps) & BIT_MASK(6)) | (1 << 6))
/** @def BT_MESH_PUB_PERIOD_10SEC
*
* @brief Helper macro to encode model publication period in units of 10
* seconds
*
* @param steps Number of 10 second steps.
*
* @return Encoded value that can be assigned to bt_mesh_cfg_mod_pub.period
*/
#define BT_MESH_PUB_PERIOD_10SEC(steps) (((steps) & BIT_MASK(6)) | (2 << 6))
/** @def BT_MESH_PUB_PERIOD_10MIN
*
* @brief Helper macro to encode model publication period in units of 10
* minutes
*
* @param steps Number of 10 minute steps.
*
* @return Encoded value that can be assigned to bt_mesh_cfg_mod_pub.period
*/
#define BT_MESH_PUB_PERIOD_10MIN(steps) (((steps) & BIT_MASK(6)) | (3 << 6))
struct bt_mesh_cfg_mod_pub {
u16_t addr;
u16_t app_idx;
bool cred_flag;
u8_t ttl;
u8_t period;
u8_t transmit;
};
int bt_mesh_cfg_mod_pub_get(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_id, struct bt_mesh_cfg_mod_pub *pub,
u8_t *status);
int bt_mesh_cfg_mod_pub_get_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_id, u16_t cid,
struct bt_mesh_cfg_mod_pub *pub, u8_t *status);
int bt_mesh_cfg_mod_pub_set(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_id, struct bt_mesh_cfg_mod_pub *pub,
u8_t *status);
int bt_mesh_cfg_mod_pub_set_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_id, u16_t cid,
struct bt_mesh_cfg_mod_pub *pub, u8_t *status);
int bt_mesh_cfg_mod_sub_add(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t sub_addr, u16_t mod_id, u8_t *status);
int bt_mesh_cfg_mod_sub_add_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t sub_addr, u16_t mod_id, u16_t cid,
u8_t *status);
int bt_mesh_cfg_mod_sub_del(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t sub_addr, u16_t mod_id, u8_t *status);
int bt_mesh_cfg_mod_sub_del_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t sub_addr, u16_t mod_id, u16_t cid,
u8_t *status);
int bt_mesh_cfg_mod_sub_overwrite(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t sub_addr, u16_t mod_id, u8_t *status);
int bt_mesh_cfg_mod_sub_overwrite_vnd(u16_t net_idx, u16_t addr,
u16_t elem_addr, u16_t sub_addr,
u16_t mod_id, u16_t cid, u8_t *status);
int bt_mesh_cfg_mod_sub_va_add(u16_t net_idx, u16_t addr, u16_t elem_addr,
const u8_t label[16], u16_t mod_id,
u16_t *virt_addr, u8_t *status);
int bt_mesh_cfg_mod_sub_va_add_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
const u8_t label[16], u16_t mod_id,
u16_t cid, u16_t *virt_addr, u8_t *status);
int bt_mesh_cfg_mod_sub_va_del(u16_t net_idx, u16_t addr, u16_t elem_addr,
const u8_t label[16], u16_t mod_id,
u16_t *virt_addr, u8_t *status);
int bt_mesh_cfg_mod_sub_va_del_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
const u8_t label[16], u16_t mod_id,
u16_t cid, u16_t *virt_addr, u8_t *status);
int bt_mesh_cfg_mod_sub_va_overwrite(u16_t net_idx, u16_t addr,
u16_t elem_addr, const u8_t label[16],
u16_t mod_id, u16_t *virt_addr,
u8_t *status);
int bt_mesh_cfg_mod_sub_va_overwrite_vnd(u16_t net_idx, u16_t addr,
u16_t elem_addr, const u8_t label[16],
u16_t mod_id, u16_t cid,
u16_t *virt_addr, u8_t *status);
struct bt_mesh_cfg_hb_sub {
u16_t src;
u16_t dst;
u8_t period;
u8_t count;
u8_t min;
u8_t max;
};
int bt_mesh_cfg_hb_sub_set(u16_t net_idx, u16_t addr,
struct bt_mesh_cfg_hb_sub *sub, u8_t *status);
int bt_mesh_cfg_hb_sub_get(u16_t net_idx, u16_t addr,
struct bt_mesh_cfg_hb_sub *sub, u8_t *status);
struct bt_mesh_cfg_hb_pub {
u16_t dst;
u8_t count;
u8_t period;
u8_t ttl;
u16_t feat;
u16_t net_idx;
};
int bt_mesh_cfg_hb_pub_set(u16_t net_idx, u16_t addr,
const struct bt_mesh_cfg_hb_pub *pub, u8_t *status);
int bt_mesh_cfg_hb_pub_get(u16_t net_idx, u16_t addr,
struct bt_mesh_cfg_hb_pub *pub, u8_t *status);
s32_t bt_mesh_cfg_cli_timeout_get(void);
void bt_mesh_cfg_cli_timeout_set(s32_t timeout);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __BT_MESH_CFG_CLI_H */

View File

@@ -0,0 +1,78 @@
/** @file
* @brief Bluetooth Mesh Configuration Server Model APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_MESH_CFG_SRV_H
#define __BT_MESH_CFG_SRV_H
/**
* @brief Bluetooth Mesh
* @defgroup bt_mesh_cfg_srv Bluetooth Mesh Configuration Server Model
* @ingroup bt_mesh
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/** Mesh Configuration Server Model Context */
struct bt_mesh_cfg_srv {
struct bt_mesh_model *model;
u8_t net_transmit; /* Network Transmit state */
u8_t relay; /* Relay Mode state */
u8_t relay_retransmit; /* Relay Retransmit state */
u8_t beacon; /* Secure Network Beacon state */
u8_t gatt_proxy; /* GATT Proxy state */
u8_t frnd; /* Friend state */
u8_t default_ttl; /* Default TTL */
/* Heartbeat Publication */
struct bt_mesh_hb_pub {
struct k_delayed_work timer;
u16_t dst;
u16_t count;
u8_t period;
u8_t ttl;
u16_t feat;
u16_t net_idx;
} hb_pub;
/* Heartbeat Subscription */
struct bt_mesh_hb_sub {
s64_t expiry;
u16_t src;
u16_t dst;
u16_t count;
u8_t min_hops;
u8_t max_hops;
/* Optional subscription tracking function */
void (*func)(u8_t hops, u16_t feat);
} hb_sub;
};
extern const struct bt_mesh_model_op bt_mesh_cfg_srv_op[];
extern const struct bt_mesh_model_cb bt_mesh_cfg_srv_cb;
#define BT_MESH_MODEL_CFG_SRV(srv_data) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_CFG_SRV, bt_mesh_cfg_srv_op, NULL, \
srv_data, &bt_mesh_cfg_srv_cb)
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __BT_MESH_CFG_SRV_H */

View File

@@ -0,0 +1,502 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 _MESH_GLUE_
#define _MESH_GLUE_
#include <assert.h>
#include <errno.h>
#include "syscfg/syscfg.h"
#include "logcfg/logcfg.h"
#include "modlog/modlog.h"
#include "nimble/nimble_npl.h"
#include "os/os_mbuf.h"
#include "os/queue.h"
#include "nimble/ble.h"
#include "host/ble_hs.h"
#include "host/ble_uuid.h"
#include "../src/ble_sm_priv.h"
#include "../src/ble_hs_hci_priv.h"
#include "tinycrypt/aes.h"
#include "tinycrypt/constants.h"
#include "tinycrypt/utils.h"
#include "tinycrypt/cmac_mode.h"
#include "tinycrypt/ecc_dh.h"
#if MYNEWT_VAL(BLE_MESH_SETTINGS)
#include "config/config.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define u8_t uint8_t
#define s8_t int8_t
#define u16_t uint16_t
#define s16_t int16_t
#define u32_t uint32_t
#define u64_t uint64_t
#define s64_t int64_t
#define s32_t int32_t
/** @brief Helper to declare elements of bt_data arrays
*
* This macro is mainly for creating an array of struct bt_data
* elements which is then passed to bt_le_adv_start().
*
* @param _type Type of advertising data field
* @param _data Pointer to the data field payload
* @param _data_len Number of bytes behind the _data pointer
*/
#define BT_DATA(_type, _data, _data_len) \
{ \
.type = (_type), \
.data_len = (_data_len), \
.data = (const u8_t *)(_data), \
}
/** @brief Helper to declare elements of bt_data arrays
*
* This macro is mainly for creating an array of struct bt_data
* elements which is then passed to bt_le_adv_start().
*
* @param _type Type of advertising data field
* @param _bytes Variable number of single-byte parameters
*/
#define BT_DATA_BYTES(_type, _bytes...) \
BT_DATA(_type, ((u8_t []) { _bytes }), \
sizeof((u8_t []) { _bytes }))
/* EIR/AD data type definitions */
#define BT_DATA_FLAGS 0x01 /* AD flags */
#define BT_DATA_UUID16_SOME 0x02 /* 16-bit UUID, more available */
#define BT_DATA_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
#define BT_DATA_UUID32_SOME 0x04 /* 32-bit UUID, more available */
#define BT_DATA_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
#define BT_DATA_UUID128_SOME 0x06 /* 128-bit UUID, more available */
#define BT_DATA_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
#define BT_DATA_NAME_SHORTENED 0x08 /* Shortened name */
#define BT_DATA_NAME_COMPLETE 0x09 /* Complete name */
#define BT_DATA_TX_POWER 0x0a /* Tx Power */
#define BT_DATA_SOLICIT16 0x14 /* Solicit UUIDs, 16-bit */
#define BT_DATA_SOLICIT128 0x15 /* Solicit UUIDs, 128-bit */
#define BT_DATA_SVC_DATA16 0x16 /* Service data, 16-bit UUID */
#define BT_DATA_GAP_APPEARANCE 0x19 /* GAP appearance */
#define BT_DATA_SOLICIT32 0x1f /* Solicit UUIDs, 32-bit */
#define BT_DATA_SVC_DATA32 0x20 /* Service data, 32-bit UUID */
#define BT_DATA_SVC_DATA128 0x21 /* Service data, 128-bit UUID */
#define BT_DATA_URI 0x24 /* URI */
#define BT_DATA_MESH_PROV 0x29 /* Mesh Provisioning PDU */
#define BT_DATA_MESH_MESSAGE 0x2a /* Mesh Networking PDU */
#define BT_DATA_MESH_BEACON 0x2b /* Mesh Beacon */
#define BT_DATA_MANUFACTURER_DATA 0xff /* Manufacturer Specific Data */
#define BT_LE_AD_LIMITED 0x01 /* Limited Discoverable */
#define BT_LE_AD_GENERAL 0x02 /* General Discoverable */
#define BT_LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */
#define sys_put_be16(a,b) put_be16(b, a)
#define sys_put_le16(a,b) put_le16(b, a)
#define sys_put_be32(a,b) put_be32(b, a)
#define sys_get_be16(a) get_be16(a)
#define sys_get_le16(a) get_le16(a)
#define sys_get_be32(a) get_be32(a)
#define sys_cpu_to_be16(a) htobe16(a)
#define sys_cpu_to_be32(a) htobe32(a)
#define sys_be32_to_cpu(a) be32toh(a)
#define sys_be16_to_cpu(a) be16toh(a)
#define sys_le16_to_cpu(a) le16toh(a)
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
#define CODE_UNREACHABLE __builtin_unreachable()
#define __ASSERT(code, str) \
do { \
if (!(code)) BT_ERR(str); \
assert(code); \
} while (0);
#define __ASSERT_NO_MSG(test) __ASSERT(test, "")
/* Mesh is designed to not use mbuf chains */
#if BT_DBG_ENABLED
#define ASSERT_NOT_CHAIN(om) assert(SLIST_NEXT(om, om_next) == NULL)
#else
#define ASSERT_NOT_CHAIN(om) (void)(om)
#endif
#define __packed __attribute__((__packed__))
#define MSEC_PER_SEC (1000)
#define K_MSEC(ms) (ms)
#define K_SECONDS(s) K_MSEC((s) * MSEC_PER_SEC)
#define K_MINUTES(m) K_SECONDS((m) * 60)
#define K_HOURS(h) K_MINUTES((h) * 60)
#ifndef BIT
#define BIT(n) (1UL << (n))
#endif
#define BIT_MASK(n) (BIT(n) - 1)
#define BT_GAP_ADV_FAST_INT_MIN_1 0x0030 /* 30 ms */
#define BT_GAP_ADV_FAST_INT_MAX_1 0x0060 /* 60 ms */
#define BT_GAP_ADV_FAST_INT_MIN_2 0x00a0 /* 100 ms */
#define BT_GAP_ADV_FAST_INT_MAX_2 0x00f0 /* 150 ms */
#define BT_GAP_ADV_SLOW_INT_MIN 0x0640 /* 1 s */
#define BT_GAP_ADV_SLOW_INT_MAX 0x0780 /* 1.2 s */
#ifndef MESH_LOG_MODULE
#define MESH_LOG_MODULE BLE_MESH_LOG
#endif
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define BLE_MESH_LOG(lvl, ...) CAT(MESH_LOG_MODULE, CAT(_, lvl))(__VA_ARGS__)
#define BT_DBG(fmt, ...) BLE_MESH_LOG(DEBUG, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_INFO(fmt, ...) BLE_MESH_LOG(INFO, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_WARN(fmt, ...) BLE_MESH_LOG(WARN, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_ERR(fmt, ...) BLE_MESH_LOG(ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_GATT_ERR(_att_err) (-(_att_err))
typedef ble_addr_t bt_addr_le_t;
#define k_fifo_init(queue) ble_npl_eventq_init(queue)
#define net_buf_simple_tailroom(buf) OS_MBUF_TRAILINGSPACE(buf)
#define net_buf_tailroom(buf) net_buf_simple_tailroom(buf)
#define net_buf_headroom(buf) ((buf)->om_data - &(buf)->om_databuf[buf->om_pkthdr_len])
#define net_buf_simple_headroom(buf) net_buf_headroom(buf)
#define net_buf_simple_tail(buf) ((buf)->om_data + (buf)->om_len)
struct net_buf_simple_state {
/** Offset of the data pointer from the beginning of the storage */
u16_t offset;
/** Length of data */
u16_t len;
};
static inline struct os_mbuf * NET_BUF_SIMPLE(uint16_t size)
{
struct os_mbuf *buf;
buf = os_msys_get(size, 0);
assert(buf);
return buf;
}
#define K_NO_WAIT (0)
#define K_FOREVER (-1)
#if MYNEWT_VAL(BLE_EXT_ADV)
#define BT_MESH_ADV_INST (MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES))
#if MYNEWT_VAL(BLE_MESH_PROXY)
/* Note that BLE_MULTI_ADV_INSTANCES contains number of additional instances.
* Instance 0 is always there
*/
#if MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) < 1
#error "Mesh needs at least BLE_MULTI_ADV_INSTANCES set to 1"
#endif
#define BT_MESH_ADV_GATT_INST (MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) - 1)
#endif /* BLE_MESH_PROXY */
#endif /* BLE_EXT_ADV */
/* This is by purpose */
static inline void net_buf_simple_init(struct os_mbuf *buf,
size_t reserve_head)
{
/* This is called in Zephyr after init.
* Note in Mynewt case we don't care abour reserved head*/
buf->om_data = &buf->om_databuf[buf->om_pkthdr_len] + reserve_head;
buf->om_len = 0;
}
void net_buf_put(struct ble_npl_eventq *fifo, struct os_mbuf *buf);
void * net_buf_ref(struct os_mbuf *om);
void net_buf_unref(struct os_mbuf *om);
uint16_t net_buf_simple_pull_le16(struct os_mbuf *om);
uint16_t net_buf_simple_pull_be16(struct os_mbuf *om);
uint32_t net_buf_simple_pull_be32(struct os_mbuf *om);
uint32_t net_buf_simple_pull_le32(struct os_mbuf *om);
uint8_t net_buf_simple_pull_u8(struct os_mbuf *om);
void net_buf_simple_add_le16(struct os_mbuf *om, uint16_t val);
void net_buf_simple_add_be16(struct os_mbuf *om, uint16_t val);
void net_buf_simple_add_u8(struct os_mbuf *om, uint8_t val);
void net_buf_simple_add_be32(struct os_mbuf *om, uint32_t val);
void net_buf_simple_add_le32(struct os_mbuf *om, uint32_t val);
void net_buf_add_zeros(struct os_mbuf *om, uint8_t len);
void net_buf_simple_push_le16(struct os_mbuf *om, uint16_t val);
void net_buf_simple_push_be16(struct os_mbuf *om, uint16_t val);
void net_buf_simple_push_u8(struct os_mbuf *om, uint8_t val);
void *net_buf_simple_pull(struct os_mbuf *om, uint8_t len);
void *net_buf_simple_pull_mem(struct os_mbuf *om, uint8_t len);
void *net_buf_simple_add(struct os_mbuf *om, uint8_t len);
bool k_fifo_is_empty(struct ble_npl_eventq *q);
void *net_buf_get(struct ble_npl_eventq *fifo,s32_t t);
uint8_t *net_buf_simple_push(struct os_mbuf *om, uint8_t len);
void net_buf_reserve(struct os_mbuf *om, size_t reserve);
#define net_buf_add_mem(a,b,c) os_mbuf_append(a,b,c)
#define net_buf_simple_add_mem(a,b,c) os_mbuf_append(a,b,c)
#define net_buf_add_u8(a,b) net_buf_simple_add_u8(a,b)
#define net_buf_add(a,b) net_buf_simple_add(a,b)
#define net_buf_clone(a, b) os_mbuf_dup(a)
#define net_buf_add_be32(a, b) net_buf_simple_add_be32(a, b)
#define net_buf_add_be16(a, b) net_buf_simple_add_be16(a, b)
#define net_buf_pull(a, b) net_buf_simple_pull(a, b)
#define net_buf_pull_mem(a, b) net_buf_simple_pull_mem(a, b)
#define net_buf_pull_u8(a) net_buf_simple_pull_u8(a)
#define net_buf_pull_be16(a) net_buf_simple_pull_be16(a)
#define net_buf_skip(a, b) net_buf_simple_pull_mem(a, b)
#define BT_GATT_CCC_NOTIFY BLE_GATT_CHR_PROP_NOTIFY
/** Description of different data types that can be encoded into
* advertising data. Used to form arrays that are passed to the
* bt_le_adv_start() function.
*/
struct bt_data {
u8_t type;
u8_t data_len;
const u8_t *data;
};
struct bt_pub_key_cb {
/** @brief Callback type for Public Key generation.
*
* Used to notify of the local public key or that the local key is not
* available (either because of a failure to read it or because it is
* being regenerated).
*
* @param key The local public key, or NULL in case of no key.
*/
void (*func)(const u8_t key[64]);
struct bt_pub_key_cb *_next;
};
typedef void (*bt_dh_key_cb_t)(const u8_t key[32]);
int bt_dh_key_gen(const u8_t remote_pk[64], bt_dh_key_cb_t cb);
int bt_pub_key_gen(struct bt_pub_key_cb *new_cb);
uint8_t *bt_pub_key_get(void);
int bt_rand(void *buf, size_t len);
const char * bt_hex(const void *buf, size_t len);
int bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data);
void bt_mesh_register_gatt(void);
int bt_le_adv_start(const struct ble_gap_adv_params *param,
const struct bt_data *ad, size_t ad_len,
const struct bt_data *sd, size_t sd_len);
int bt_le_adv_stop(bool proxy);
struct k_delayed_work {
struct ble_npl_callout work;
};
void k_work_init(struct ble_npl_callout *work, ble_npl_event_fn handler);
void k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f);
void k_delayed_work_cancel(struct k_delayed_work *w);
void k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms);
int64_t k_uptime_get(void);
u32_t k_uptime_get_32(void);
void k_sleep(int32_t duration);
void k_work_submit(struct ble_npl_callout *w);
void k_work_add_arg(struct ble_npl_callout *w, void *arg);
void k_delayed_work_add_arg(struct k_delayed_work *w, void *arg);
uint32_t k_delayed_work_remaining_get(struct k_delayed_work *w);
static inline void net_buf_simple_save(struct os_mbuf *buf,
struct net_buf_simple_state *state)
{
state->offset = net_buf_simple_headroom(buf);
state->len = buf->om_len;
}
static inline void net_buf_simple_restore(struct os_mbuf *buf,
struct net_buf_simple_state *state)
{
buf->om_data = &buf->om_databuf[buf->om_pkthdr_len] + state->offset;
buf->om_len = state->len;
}
static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
{
__ASSERT(((src < dst && (src + length) <= dst) ||
(src > dst && (dst + length) <= src)),
"Source and destination buffers must not overlap");
src += length - 1;
for (; length > 0; length--) {
*((u8_t *)dst++) = *((u8_t *)src--);
}
}
#define popcount(x) __builtin_popcount(x)
static inline unsigned int find_lsb_set(u32_t op)
{
return __builtin_ffs(op);
}
static inline unsigned int find_msb_set(u32_t op)
{
if (!op)
return 0;
return 32 - __builtin_clz(op);
}
#define CONFIG_BT_MESH_FRIEND BLE_MESH_FRIEND
#define CONFIG_BT_MESH_GATT_PROXY BLE_MESH_GATT_PROXY
#define CONFIG_BT_MESH_IV_UPDATE_TEST BLE_MESH_IV_UPDATE_TEST
#define CONFIG_BT_MESH_LOW_POWER BLE_MESH_LOW_POWER
#define CONFIG_BT_MESH_LPN_AUTO BLE_MESH_LPN_AUTO
#define CONFIG_BT_MESH_LPN_ESTABLISHMENT BLE_MESH_LPN_ESTABLISHMENT
#define CONFIG_BT_MESH_PB_ADV BLE_MESH_PB_ADV
#define CONFIG_BT_MESH_PB_GATT BLE_MESH_PB_GATT
#define CONFIG_BT_MESH_PROV BLE_MESH_PROV
#define CONFIG_BT_MESH_PROXY BLE_MESH_PROXY
#define CONFIG_BT_TESTING BLE_MESH_TESTING
#define CONFIG_BT_SETTINGS BLE_MESH_SETTINGS
#define CONFIG_SETTINGS BLE_MESH_SETTINGS
#define CONFIG_BT_MESH_PROVISIONER BLE_MESH_PROVISIONER
/* Above flags are used with IS_ENABLED macro */
#define IS_ENABLED(config) MYNEWT_VAL(config)
#define CONFIG_BT_MESH_LPN_GROUPS MYNEWT_VAL(BLE_MESH_LPN_GROUPS)
#define CONFIG_BT_MESH_ADV_BUF_COUNT MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)
#define CONFIG_BT_MESH_FRIEND_QUEUE_SIZE MYNEWT_VAL(BLE_MESH_FRIEND_QUEUE_SIZE)
#define CONFIG_BT_MESH_FRIEND_RECV_WIN MYNEWT_VAL(BLE_MESH_FRIEND_RECV_WIN)
#define CONFIG_BT_MESH_LPN_POLL_TIMEOUT MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT)
#define CONFIG_BT_MESH_MODEL_GROUP_COUNT MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT)
#define CONFIG_BT_MESH_MODEL_KEY_COUNT MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT)
#define CONFIG_BT_MESH_NODE_ID_TIMEOUT MYNEWT_VAL(BLE_MESH_NODE_ID_TIMEOUT)
#define CONFIG_BT_MAX_CONN MYNEWT_VAL(BLE_MAX_CONNECTIONS)
#define CONFIG_BT_MESH_SEQ_STORE_RATE MYNEWT_VAL(BLE_MESH_SEQ_STORE_RATE)
#define CONFIG_BT_MESH_RPL_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_RPL_STORE_TIMEOUT)
#define CONFIG_BT_MESH_APP_KEY_COUNT MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT)
#define CONFIG_BT_MESH_SUBNET_COUNT MYNEWT_VAL(BLE_MESH_SUBNET_COUNT)
#define CONFIG_BT_MESH_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_STORE_TIMEOUT)
#define CONFIG_BT_MESH_IVU_DIVIDER MYNEWT_VAL(BLE_MESH_IVU_DIVIDER)
#define CONFIG_BT_DEVICE_NAME MYNEWT_VAL(BLE_MESH_DEVICE_NAME)
#define CONFIG_BT_MESH_TX_SEG_MAX MYNEWT_VAL(BLE_MESH_TX_SEG_MAX)
#define CONFIG_BT_MESH_LABEL_COUNT MYNEWT_VAL(BLE_MESH_LABEL_COUNT)
#define CONFIG_BT_MESH_NODE_COUNT MYNEWT_VAL(BLE_MESH_NODE_COUNT)
#define printk console_printf
#define CONTAINER_OF(ptr, type, field) \
((type *)(((char *)(ptr)) - offsetof(type, field)))
#define k_sem ble_npl_sem
static inline void k_sem_init(struct k_sem *sem, unsigned int initial_count,
unsigned int limit)
{
ble_npl_sem_init(sem, initial_count);
}
static inline int k_sem_take(struct k_sem *sem, s32_t timeout)
{
uint32_t ticks;
ble_npl_time_ms_to_ticks(timeout, &ticks);
return - ble_npl_sem_pend(sem, ticks);
}
static inline void k_sem_give(struct k_sem *sem)
{
ble_npl_sem_release(sem);
}
/* Helpers to access the storage array, since we don't have access to its
* type at this point anymore.
*/
#define BUF_SIZE(pool) (pool->omp_pool->mp_block_size)
static inline int net_buf_id(struct os_mbuf *buf)
{
struct os_mbuf_pool *pool = buf->om_omp;
u8_t *pool_start = (u8_t *)pool->omp_pool->mp_membuf_addr;
u8_t *buf_ptr = (u8_t *)buf;
return (buf_ptr - pool_start) / BUF_SIZE(pool);
}
/* XXX: We should not use os_mbuf_pkthdr chains to represent a list of
* packets, this is a hack. For now this is not an issue, because mesh
* does not use os_mbuf chains. We should change this in the future.
*/
STAILQ_HEAD(net_buf_slist_t, os_mbuf_pkthdr);
void net_buf_slist_init(struct net_buf_slist_t *list);
bool net_buf_slist_is_empty(struct net_buf_slist_t *list);
struct os_mbuf *net_buf_slist_peek_head(struct net_buf_slist_t *list);
struct os_mbuf *net_buf_slist_peek_next(struct os_mbuf *buf);
struct os_mbuf *net_buf_slist_get(struct net_buf_slist_t *list);
void net_buf_slist_put(struct net_buf_slist_t *list, struct os_mbuf *buf);
void net_buf_slist_remove(struct net_buf_slist_t *list, struct os_mbuf *prev,
struct os_mbuf *cur);
void net_buf_slist_merge_slist(struct net_buf_slist_t *list,
struct net_buf_slist_t *list_to_append);
#define NET_BUF_SLIST_FOR_EACH_NODE(head, var) STAILQ_FOREACH(var, head, omp_next)
#if MYNEWT_VAL(BLE_MESH_SETTINGS)
#define settings_load conf_load
int settings_bytes_from_str(char *val_str, void *vp, int *len);
char *settings_str_from_bytes(const void *vp, int vp_len,
char *buf, int buf_len);
#define snprintk snprintf
#define BT_SETTINGS_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
#define settings_save_one conf_save_one
#else
static inline int
settings_load(void)
{
return 0;
}
#endif /* MYNEWT_VAL(MYNEWT_VAL_BLE_MESH_SETTINGS) */
#define BUILD_ASSERT(cond) _Static_assert(cond, "")
#ifdef __cplusplus
}
#endif
#endif /* _MESH_GLUE_ */

View File

@@ -0,0 +1,81 @@
/** @file
* @brief Bluetooth Mesh Health Client Model APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_MESH_HEALTH_CLI_H
#define __BT_MESH_HEALTH_CLI_H
/**
* @brief Bluetooth Mesh
* @defgroup bt_mesh_health_cli Bluetooth Mesh Health Client Model
* @ingroup bt_mesh
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/** Mesh Health Client Model Context */
struct bt_mesh_health_cli {
struct bt_mesh_model *model;
void (*current_status)(struct bt_mesh_health_cli *cli, u16_t addr,
u8_t test_id, u16_t cid, u8_t *faults,
size_t fault_count);
struct k_sem op_sync;
u32_t op_pending;
void *op_param;
};
extern const struct bt_mesh_model_op bt_mesh_health_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_health_cli_cb;
#define BT_MESH_MODEL_HEALTH_CLI(cli_data) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_CLI, bt_mesh_health_cli_op, \
NULL, cli_data, &bt_mesh_health_cli_cb)
int bt_mesh_health_cli_set(struct bt_mesh_model *model);
int bt_mesh_health_fault_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t *test_id, u8_t *faults,
size_t *fault_count);
int bt_mesh_health_fault_clear(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t *test_id, u8_t *faults,
size_t *fault_count);
int bt_mesh_health_fault_test(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t test_id, u8_t *faults,
size_t *fault_count);
int bt_mesh_health_period_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *divisor);
int bt_mesh_health_period_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t divisor, u8_t *updated_divisor);
int bt_mesh_health_attention_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *attention);
int bt_mesh_health_attention_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t attention, u8_t *updated_attention);
s32_t bt_mesh_health_cli_timeout_get(void);
void bt_mesh_health_cli_timeout_set(s32_t timeout);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __BT_MESH_HEALTH_CLI_H */

View File

@@ -0,0 +1,100 @@
/** @file
* @brief Bluetooth Mesh Health Server Model APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_MESH_HEALTH_SRV_H
#define __BT_MESH_HEALTH_SRV_H
/**
* @brief Mesh Bluetooth Mesh Health Server Model
* @defgroup bt_mesh_health_srv
* @ingroup bt_mesh
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
struct bt_mesh_health_srv_cb {
/* Fetch current faults */
int (*fault_get_cur)(struct bt_mesh_model *model, u8_t *test_id,
u16_t *company_id, u8_t *faults,
u8_t *fault_count);
/* Fetch registered faults */
int (*fault_get_reg)(struct bt_mesh_model *model, u16_t company_id,
u8_t *test_id, u8_t *faults,
u8_t *fault_count);
/* Clear registered faults */
int (*fault_clear)(struct bt_mesh_model *model, u16_t company_id);
/* Run a specific test */
int (*fault_test)(struct bt_mesh_model *model, u8_t test_id,
u16_t company_id);
/* Attention on */
void (*attn_on)(struct bt_mesh_model *model);
/* Attention off */
void (*attn_off)(struct bt_mesh_model *model);
};
/** @def BT_MESH_HEALTH_FAULT_MSG
*
* A helper to define a health fault message.
*
* @param max_faults Maximum number of faults the element can have.
*
* @return a New net_buf_simple of the needed size.
*/
#define BT_MESH_HEALTH_FAULT_MSG(max_faults) \
NET_BUF_SIMPLE(1 + 3 + (max_faults))
/** Mesh Health Server Model Context */
struct bt_mesh_health_srv {
struct bt_mesh_model *model;
/* Optional callback struct */
const struct bt_mesh_health_srv_cb *cb;
/* Attention Timer state */
struct k_delayed_work attn_timer;
};
int bt_mesh_fault_update(struct bt_mesh_elem *elem);
extern const struct bt_mesh_model_op bt_mesh_health_srv_op[];
extern const struct bt_mesh_model_cb bt_mesh_health_srv_cb;
/** @def BT_MESH_MODEL_HEALTH_SRV
*
* Define a new health server model. Note that this API needs to be
* repeated for each element that the application wants to have a
* health server model on. Each instance also needs a unique
* bt_mesh_health_srv and bt_mesh_model_pub context.
*
* @param srv Pointer to a unique struct bt_mesh_health_srv.
* @param pub Pointer to a unique struct bt_mesh_model_pub.
*
* @return New mesh model instance.
*/
#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_op, \
pub, srv, &bt_mesh_health_srv_cb)
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __BT_MESH_HEALTH_SRV_H */

View File

@@ -0,0 +1,441 @@
/** @file
* @brief Bluetooth Mesh Profile APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_MESH_MAIN_H
#define __BT_MESH_MAIN_H
/**
* @brief Bluetooth Mesh Provisioning
* @defgroup bt_mesh_prov Bluetooth Mesh Provisioning
* @ingroup bt_mesh
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
BT_MESH_NO_OUTPUT = 0,
BT_MESH_BLINK = BIT(0),
BT_MESH_BEEP = BIT(1),
BT_MESH_VIBRATE = BIT(2),
BT_MESH_DISPLAY_NUMBER = BIT(3),
BT_MESH_DISPLAY_STRING = BIT(4),
} bt_mesh_output_action_t;
typedef enum {
BT_MESH_NO_INPUT = 0,
BT_MESH_PUSH = BIT(0),
BT_MESH_TWIST = BIT(1),
BT_MESH_ENTER_NUMBER = BIT(2),
BT_MESH_ENTER_STRING = BIT(3),
} bt_mesh_input_action_t;
typedef enum {
BT_MESH_PROV_ADV = BIT(0),
BT_MESH_PROV_GATT = BIT(1),
} bt_mesh_prov_bearer_t;
typedef enum {
BT_MESH_PROV_OOB_OTHER = BIT(0),
BT_MESH_PROV_OOB_URI = BIT(1),
BT_MESH_PROV_OOB_2D_CODE = BIT(2),
BT_MESH_PROV_OOB_BAR_CODE = BIT(3),
BT_MESH_PROV_OOB_NFC = BIT(4),
BT_MESH_PROV_OOB_NUMBER = BIT(5),
BT_MESH_PROV_OOB_STRING = BIT(6),
/* 7 - 10 are reserved */
BT_MESH_PROV_OOB_ON_BOX = BIT(11),
BT_MESH_PROV_OOB_IN_BOX = BIT(12),
BT_MESH_PROV_OOB_ON_PAPER = BIT(13),
BT_MESH_PROV_OOB_IN_MANUAL = BIT(14),
BT_MESH_PROV_OOB_ON_DEV = BIT(15),
} bt_mesh_prov_oob_info_t;
/** Provisioning properties & capabilities. */
struct bt_mesh_prov {
/** The UUID that's used when advertising as unprovisioned */
const u8_t *uuid;
/** Optional URI. This will be advertised separately from the
* unprovisioned beacon, however the unprovisioned beacon will
* contain a hash of it so the two can be associated by the
* provisioner.
*/
const char *uri;
/** Out of Band information field. */
bt_mesh_prov_oob_info_t oob_info;
/** Static OOB value */
const u8_t *static_val;
/** Static OOB value length */
u8_t static_val_len;
/** Maximum size of Output OOB supported */
u8_t output_size;
/** Supported Output OOB Actions */
u16_t output_actions;
/* Maximum size of Input OOB supported */
u8_t input_size;
/** Supported Input OOB Actions */
u16_t input_actions;
/** @brief Output of a number is requested.
*
* This callback notifies the application that it should
* output the given number using the given action.
*
* @param act Action for outputting the number.
* @param num Number to be outputted.
*
* @return Zero on success or negative error code otherwise
*/
int (*output_number)(bt_mesh_output_action_t act, u32_t num);
/** @brief Output of a string is requested.
*
* This callback notifies the application that it should
* display the given string to the user.
*
* @param str String to be displayed.
*
* @return Zero on success or negative error code otherwise
*/
int (*output_string)(const char *str);
/** @brief Input is requested.
*
* This callback notifies the application that it should
* request input from the user using the given action. The
* requested input will either be a string or a number, and
* the application needs to consequently call the
* bt_mesh_input_string() or bt_mesh_input_number() functions
* once the data has been acquired from the user.
*
* @param act Action for inputting data.
* @param num Maximum size of the inputted data.
*
* @return Zero on success or negative error code otherwise
*/
int (*input)(bt_mesh_input_action_t act, u8_t size);
/** @brief The other device finished their OOB input.
*
* This callback notifies the application that it should stop
* displaying its output OOB value, as the other party finished their
* OOB input.
*/
void (*input_complete)(void);
/** @brief Unprovisioned beacon has been received.
*
* This callback notifies the application that an unprovisioned
* beacon has been received.
*
* @param uuid UUID
* @param oob_info OOB Information
* @param uri_hash Pointer to URI Hash value. NULL if no hash was
* present in the beacon.
*/
void (*unprovisioned_beacon)(u8_t uuid[16],
bt_mesh_prov_oob_info_t oob_info,
u32_t *uri_hash);
/** @brief Provisioning link has been opened.
*
* This callback notifies the application that a provisioning
* link has been opened on the given provisioning bearer.
*
* @param bearer Provisioning bearer.
*/
void (*link_open)(bt_mesh_prov_bearer_t bearer);
/** @brief Provisioning link has been closed.
*
* This callback notifies the application that a provisioning
* link has been closed on the given provisioning bearer.
*
* @param bearer Provisioning bearer.
*/
void (*link_close)(bt_mesh_prov_bearer_t bearer);
/** @brief Provisioning is complete.
*
* This callback notifies the application that provisioning has
* been successfully completed, and that the local node has been
* assigned the specified NetKeyIndex and primary element address.
*
* @param net_idx NetKeyIndex given during provisioning.
* @param addr Primary element address.
*/
void (*complete)(u16_t net_idx, u16_t addr);
/** @brief A new node has been added to the provisioning database.
*
* This callback notifies the application that provisioning has
* been successfully completed, and that a node has been assigned
* the specified NetKeyIndex and primary element address.
*
* @param net_idx NetKeyIndex given during provisioning.
* @param addr Primary element address.
* @param num_elem Number of elements that this node has.
*/
void (*node_added)(u16_t net_idx, u16_t addr, u8_t num_elem);
/** @brief Node has been reset.
*
* This callback notifies the application that the local node
* has been reset and needs to be reprovisioned. The node will
* not automatically advertise as unprovisioned, rather the
* bt_mesh_prov_enable() API needs to be called to enable
* unprovisioned advertising on one or more provisioning bearers.
*/
void (*reset)(void);
};
/** @brief Provide provisioning input OOB string.
*
* This is intended to be called after the bt_mesh_prov input callback
* has been called with BT_MESH_ENTER_STRING as the action.
*
* @param str String.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_input_string(const char *str);
/** @brief Provide provisioning input OOB number.
*
* This is intended to be called after the bt_mesh_prov input callback
* has been called with BT_MESH_ENTER_NUMBER as the action.
*
* @param num Number.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_input_number(u32_t num);
/** @brief Enable specific provisioning bearers
*
* Enable one or more provisioning bearers.
*
* @param bearers Bit-wise or of provisioning bearers.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers);
/** @brief Disable specific provisioning bearers
*
* Disable one or more provisioning bearers.
*
* @param bearers Bit-wise or of provisioning bearers.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers);
/**
* @}
*/
/**
* @brief Bluetooth Mesh
* @defgroup bt_mesh Bluetooth Mesh
* @ingroup bluetooth
* @{
*/
/* Primary Network Key index */
#define BT_MESH_NET_PRIMARY 0x000
#define BT_MESH_RELAY_DISABLED 0x00
#define BT_MESH_RELAY_ENABLED 0x01
#define BT_MESH_RELAY_NOT_SUPPORTED 0x02
#define BT_MESH_BEACON_DISABLED 0x00
#define BT_MESH_BEACON_ENABLED 0x01
#define BT_MESH_GATT_PROXY_DISABLED 0x00
#define BT_MESH_GATT_PROXY_ENABLED 0x01
#define BT_MESH_GATT_PROXY_NOT_SUPPORTED 0x02
#define BT_MESH_FRIEND_DISABLED 0x00
#define BT_MESH_FRIEND_ENABLED 0x01
#define BT_MESH_FRIEND_NOT_SUPPORTED 0x02
#define BT_MESH_NODE_IDENTITY_STOPPED 0x00
#define BT_MESH_NODE_IDENTITY_RUNNING 0x01
#define BT_MESH_NODE_IDENTITY_NOT_SUPPORTED 0x02
/* Features */
#define BT_MESH_FEAT_RELAY BIT(0)
#define BT_MESH_FEAT_PROXY BIT(1)
#define BT_MESH_FEAT_FRIEND BIT(2)
#define BT_MESH_FEAT_LOW_POWER BIT(3)
#define BT_MESH_FEAT_SUPPORTED (BT_MESH_FEAT_RELAY | \
BT_MESH_FEAT_PROXY | \
BT_MESH_FEAT_FRIEND | \
BT_MESH_FEAT_LOW_POWER)
/** @brief Initialize Mesh support
*
* After calling this API, the node will not automatically advertise as
* unprovisioned, rather the bt_mesh_prov_enable() API needs to be called
* to enable unprovisioned advertising on one or more provisioning bearers.
*
* @param own_addr_type Node address type
* @param prov Node provisioning information.
* @param comp Node Composition.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_init(u8_t own_addr_type,
const struct bt_mesh_prov *prov,
const struct bt_mesh_comp *comp);
/** @brief Reset the state of the local Mesh node.
*
* Resets the state of the node, which means that it needs to be
* reprovisioned to become an active node in a Mesh network again.
*
* After calling this API, the node will not automatically advertise as
* unprovisioned, rather the bt_mesh_prov_enable() API needs to be called
* to enable unprovisioned advertising on one or more provisioning bearers.
*
*/
void bt_mesh_reset(void);
/** @brief Suspend the Mesh network temporarily.
*
* This API can be used for power saving purposes, but the user should be
* aware that leaving the local node suspended for a long period of time
* may cause it to become permanently disconnected from the Mesh network.
* If at all possible, the Friendship feature should be used instead, to
* make the node into a Low Power Node.
*
* @return 0 on success, or (negative) error code on failure.
*/
int bt_mesh_suspend(void);
/** @brief Resume a suspended Mesh network.
*
* This API resumes the local node, after it has been suspended using the
* bt_mesh_suspend() API.
*
* @return 0 on success, or (negative) error code on failure.
*/
int bt_mesh_resume(void);
/** @brief Provision the local Mesh Node.
*
* This API should normally not be used directly by the application. The
* only exception is for testing purposes where manual provisioning is
* desired without an actual external provisioner.
*
* @param net_key Network Key
* @param net_idx Network Key Index
* @param flags Provisioning Flags
* @param iv_index IV Index
* @param addr Primary element address
* @param dev_key Device Key
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
u8_t flags, u32_t iv_index, u16_t addr,
const u8_t dev_key[16]);
/** @brief Provision a Mesh Node using PB-ADV
*
* @param uuid UUID
* @param net_idx Network Key Index
* @param addr Address to assign to remote device. If addr is 0, the lowest
* available address will be chosen.
* @param attention_duration The attention duration to be send to remote device
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_provision_adv(const u8_t uuid[16], u16_t net_idx, u16_t addr,
u8_t attention_duration);
/** @brief Check if the local node has been provisioned.
*
* This API can be used to check if the local node has been provisioned
* or not. It can e.g. be helpful to determine if there was a stored
* network in flash, i.e. if the network was restored after calling
* settings_load().
*
* @return True if the node is provisioned. False otherwise.
*/
bool bt_mesh_is_provisioned(void);
/** @brief Toggle the IV Update test mode
*
* This API is only available if the IV Update test mode has been enabled
* in Kconfig. It is needed for passing most of the IV Update qualification
* test cases.
*
* @param enable true to enable IV Update test mode, false to disable it.
*/
void bt_mesh_iv_update_test(bool enable);
/** @brief Toggle the IV Update state
*
* This API is only available if the IV Update test mode has been enabled
* in Kconfig. It is needed for passing most of the IV Update qualification
* test cases.
*
* @return true if IV Update In Progress state was entered, false otherwise.
*/
bool bt_mesh_iv_update(void);
/** @brief Toggle the Low Power feature of the local device
*
* Enables or disables the Low Power feature of the local device. This is
* exposed as a run-time feature, since the device might want to change
* this e.g. based on being plugged into a stable power source or running
* from a battery power source.
*
* @param enable true to enable LPN functionality, false to disable it.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_lpn_set(bool enable);
/** @brief Send out a Friend Poll message.
*
* Send a Friend Poll message to the Friend of this node. If there is no
* established Friendship the function will return an error.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_lpn_poll(void);
/** @brief Register a callback for Friendship changes.
*
* Registers a callback that will be called whenever Friendship gets
* established or is lost.
*
* @param cb Function to call when the Friendship status changes.
*/
void bt_mesh_lpn_set_cb(void (*cb)(u16_t friend_addr, bool established));
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __BT_MESH_MAIN_H */

View File

@@ -0,0 +1,26 @@
/** @file
* @brief Bluetooth Mesh Profile APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_MESH_H
#define __BT_MESH_H
#include <stddef.h>
#include "syscfg/syscfg.h"
#include "os/os_mbuf.h"
#include "glue.h"
#include "access.h"
#include "main.h"
#include "cfg_srv.h"
#include "health_srv.h"
#include "cfg_cli.h"
#include "health_cli.h"
#include "proxy.h"
#endif /* __BT_MESH_H */

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __MODEL_CLI_H__
#define __MODEL_CLI_H__
#ifdef __cplusplus
extern "C" {
#endif
struct bt_mesh_gen_model_cli {
struct bt_mesh_model *model;
struct k_sem op_sync;
u32_t op_pending;
void *op_param;
};
extern const struct bt_mesh_model_op gen_onoff_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_gen_onoff_cli_cb;
#define BT_MESH_MODEL_GEN_ONOFF_CLI(cli_data, pub) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, pub,\
cli_data, &bt_mesh_gen_onoff_cli_cb)
extern const struct bt_mesh_model_op gen_level_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_gen_level_cli_cb;
#define BT_MESH_MODEL_GEN_LEVEL_CLI(cli_data, pub) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_LEVEL_CLI, gen_level_cli_op, pub,\
cli_data, &bt_mesh_gen_level_cli_cb)
int bt_mesh_gen_onoff_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *state);
int bt_mesh_gen_onoff_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t val, u8_t *state);
int bt_mesh_gen_level_get(u16_t net_idx, u16_t addr, u16_t app_idx,
s16_t *level);
int bt_mesh_gen_level_set(u16_t net_idx, u16_t addr, u16_t app_idx,
s16_t val, s16_t *state);
#ifdef __cplusplus
}
#endif
#endif /* __MODEL_CLI_H__ */

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __MODEL_SRV_H__
#define __MODEL_SRV_H__
#ifdef __cplusplus
extern "C" {
#endif
struct bt_mesh_gen_onoff_srv {
struct bt_mesh_model *model;
int (*get)(struct bt_mesh_model *model, u8_t *state);
int (*set)(struct bt_mesh_model *model, u8_t state);
};
extern const struct bt_mesh_model_op gen_onoff_srv_op[];
extern const struct bt_mesh_model_cb gen_onoff_srv_cb;
#define BT_MESH_MODEL_GEN_ONOFF_SRV(srv, pub) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, \
gen_onoff_srv_op, pub, srv, &gen_onoff_srv_cb)
struct bt_mesh_gen_level_srv {
struct bt_mesh_model *model;
int (*get)(struct bt_mesh_model *model, s16_t *level);
int (*set)(struct bt_mesh_model *model, s16_t level);
};
extern const struct bt_mesh_model_op gen_level_srv_op[];
extern const struct bt_mesh_model_cb gen_level_srv_cb;
#define BT_MESH_MODEL_GEN_LEVEL_SRV(srv, pub) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, \
gen_level_srv_op, pub, srv, &gen_level_srv_cb)
struct bt_mesh_light_lightness_srv {
struct bt_mesh_model *model;
int (*get)(struct bt_mesh_model *model, s16_t *level);
int (*set)(struct bt_mesh_model *model, s16_t level);
};
extern const struct bt_mesh_model_op light_lightness_srv_op[];
extern const struct bt_mesh_model_cb light_lightness_srv_cb;
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_SRV(srv, pub) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV, \
light_lightness_srv_op, pub, srv, &light_lightness_srv_cb)
void bt_mesh_set_gen_onoff_srv_cb(int (*get)(struct bt_mesh_model *model, u8_t *state),
int (*set)(struct bt_mesh_model *model, u8_t state));
void bt_mesh_set_gen_level_srv_cb(int (*get)(struct bt_mesh_model *model, s16_t *level),
int (*set)(struct bt_mesh_model *model, s16_t level));
void bt_mesh_set_light_lightness_srv_cb(int (*get)(struct bt_mesh_model *model, s16_t *level),
int (*set)(struct bt_mesh_model *model, s16_t level));
#ifdef __cplusplus
}
#endif
#endif /* __MODEL_SRV_H__ */

View File

@@ -0,0 +1,27 @@
/** @file
* @brief Bluetooth Mesh Porting APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_MESH_PORTING_H
#define __BT_MESH_PORTING_H
#ifdef __cplusplus
extern "C" {
#endif
void mesh_adv_thread(void *args);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __BT_MESH_PORTING_H */

View File

@@ -0,0 +1,43 @@
/** @file
* @brief Bluetooth Mesh Proxy APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_MESH_PROXY_H
#define __BT_MESH_PROXY_H
/**
* @brief Bluetooth Mesh Proxy
* @defgroup bt_mesh_proxy Bluetooth Mesh Proxy
* @ingroup bt_mesh
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Enable advertising with Node Identity.
*
* This API requires that GATT Proxy support has been enabled. Once called
* each subnet will start advertising using Node Identity for the next
* 60 seconds.
*
* @return 0 on success, or (negative) error code on failure.
*/
int bt_mesh_proxy_identity_enable(void);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __BT_MESH_PROXY_H */

View File

@@ -0,0 +1,468 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
*
* @brief Single-linked list implementation
*
* Single-linked list implementation using inline macros/functions.
* This API is not thread safe, and thus if a list is used across threads,
* calls to functions must be protected with synchronization primitives.
*/
#ifndef __SLIST_H__
#define __SLIST_H__
#include <stddef.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
struct _snode {
struct _snode *next;
};
typedef struct _snode sys_snode_t;
struct _slist {
sys_snode_t *head;
sys_snode_t *tail;
};
typedef struct _slist sys_slist_t;
/**
* @brief Provide the primitive to iterate on a list
* Note: the loop is unsafe and thus __sn should not be removed
*
* User _MUST_ add the loop statement curly braces enclosing its own code:
*
* SYS_SLIST_FOR_EACH_NODE(l, n) {
* <user code>
* }
*
* This and other SYS_SLIST_*() macros are not thread safe.
*
* @param __sl A pointer on a sys_slist_t to iterate on
* @param __sn A sys_snode_t pointer to peek each node of the list
*/
#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \
for (__sn = sys_slist_peek_head(__sl); __sn; \
__sn = sys_slist_peek_next(__sn))
/**
* @brief Provide the primitive to iterate on a list, from a node in the list
* Note: the loop is unsafe and thus __sn should not be removed
*
* User _MUST_ add the loop statement curly braces enclosing its own code:
*
* SYS_SLIST_ITERATE_FROM_NODE(l, n) {
* <user code>
* }
*
* Like SYS_SLIST_FOR_EACH_NODE(), but __dn already contains a node in the list
* where to start searching for the next entry from. If NULL, it starts from
* the head.
*
* This and other SYS_SLIST_*() macros are not thread safe.
*
* @param __sl A pointer on a sys_slist_t to iterate on
* @param __sn A sys_snode_t pointer to peek each node of the list
* it contains the starting node, or NULL to start from the head
*/
#define SYS_SLIST_ITERATE_FROM_NODE(__sl, __sn) \
for (__sn = __sn ? sys_slist_peek_next_no_check(__sn) \
: sys_slist_peek_head(__sl); \
__sn; \
__sn = sys_slist_peek_next(__sn))
/**
* @brief Provide the primitive to safely iterate on a list
* Note: __sn can be removed, it will not break the loop.
*
* User _MUST_ add the loop statement curly braces enclosing its own code:
*
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) {
* <user code>
* }
*
* This and other SYS_SLIST_*() macros are not thread safe.
*
* @param __sl A pointer on a sys_slist_t to iterate on
* @param __sn A sys_snode_t pointer to peek each node of the list
* @param __sns A sys_snode_t pointer for the loop to run safely
*/
#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \
for (__sn = sys_slist_peek_head(__sl), \
__sns = sys_slist_peek_next(__sn); \
__sn; __sn = __sns, \
__sns = sys_slist_peek_next(__sn))
/*
* @brief Provide the primitive to resolve the container of a list node
* Note: it is safe to use with NULL pointer nodes
*
* @param __ln A pointer on a sys_node_t to get its container
* @param __cn Container struct type pointer
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_CONTAINER(__ln, __cn, __n) \
((__ln) ? CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL)
/*
* @brief Provide the primitive to peek container of the list head
*
* @param __sl A pointer on a sys_slist_t to peek
* @param __cn Container struct type pointer
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \
SYS_SLIST_CONTAINER(sys_slist_peek_head(__sl), __cn, __n)
/*
* @brief Provide the primitive to peek container of the list tail
*
* @param __sl A pointer on a sys_slist_t to peek
* @param __cn Container struct type pointer
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \
SYS_SLIST_CONTAINER(sys_slist_peek_tail(__sl), __cn, __n)
/*
* @brief Provide the primitive to peek the next container
*
* @param __cn Container struct type pointer
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n) \
((__cn) ? SYS_SLIST_CONTAINER(sys_slist_peek_next(&((__cn)->__n)), \
__cn, __n) : NULL)
/**
* @brief Provide the primitive to iterate on a list under a container
* Note: the loop is unsafe and thus __cn should not be detached
*
* User _MUST_ add the loop statement curly braces enclosing its own code:
*
* SYS_SLIST_FOR_EACH_CONTAINER(l, c, n) {
* <user code>
* }
*
* @param __sl A pointer on a sys_slist_t to iterate on
* @param __cn A pointer to peek each entry of the list
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); __cn; \
__cn = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
/**
* @brief Provide the primitive to safely iterate on a list under a container
* Note: __cn can be detached, it will not break the loop.
*
* User _MUST_ add the loop statement curly braces enclosing its own code:
*
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) {
* <user code>
* }
*
* @param __sl A pointer on a sys_slist_t to iterate on
* @param __cn A pointer to peek each entry of the list
* @param __cns A pointer for the loop to run safely
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \
__cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n); __cn; \
__cn = __cns, __cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
/**
* @brief Initialize a list
*
* @param list A pointer on the list to initialize
*/
static inline void sys_slist_init(sys_slist_t *list)
{
list->head = NULL;
list->tail = NULL;
}
#define SYS_SLIST_STATIC_INIT(ptr_to_list) {NULL, NULL}
/**
* @brief Test if the given list is empty
*
* @param list A pointer on the list to test
*
* @return a boolean, true if it's empty, false otherwise
*/
static inline bool sys_slist_is_empty(sys_slist_t *list)
{
return (!list->head);
}
/**
* @brief Peek the first node from the list
*
* @param list A point on the list to peek the first node from
*
* @return A pointer on the first node of the list (or NULL if none)
*/
static inline sys_snode_t *sys_slist_peek_head(sys_slist_t *list)
{
return list->head;
}
/**
* @brief Peek the last node from the list
*
* @param list A point on the list to peek the last node from
*
* @return A pointer on the last node of the list (or NULL if none)
*/
static inline sys_snode_t *sys_slist_peek_tail(sys_slist_t *list)
{
return list->tail;
}
/**
* @brief Peek the next node from current node, node is not NULL
*
* Faster then sys_slist_peek_next() if node is known not to be NULL.
*
* @param node A pointer on the node where to peek the next node
*
* @return a pointer on the next node (or NULL if none)
*/
static inline sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node)
{
return node->next;
}
/**
* @brief Peek the next node from current node
*
* @param node A pointer on the node where to peek the next node
*
* @return a pointer on the next node (or NULL if none)
*/
static inline sys_snode_t *sys_slist_peek_next(sys_snode_t *node)
{
return node ? sys_slist_peek_next_no_check(node) : NULL;
}
/**
* @brief Prepend a node to the given list
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param node A pointer on the node to prepend
*/
static inline void sys_slist_prepend(sys_slist_t *list,
sys_snode_t *node)
{
node->next = list->head;
list->head = node;
if (!list->tail) {
list->tail = list->head;
}
}
/**
* @brief Append a node to the given list
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param node A pointer on the node to append
*/
static inline void sys_slist_append(sys_slist_t *list,
sys_snode_t *node)
{
node->next = NULL;
if (!list->tail) {
list->tail = node;
list->head = node;
} else {
list->tail->next = node;
list->tail = node;
}
}
/**
* @brief Append a list to the given list
*
* Append a singly-linked, NULL-terminated list consisting of nodes containing
* the pointer to the next node as the first element of a node, to @a list.
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param head A pointer to the first element of the list to append
* @param tail A pointer to the last element of the list to append
*/
static inline void sys_slist_append_list(sys_slist_t *list,
void *head, void *tail)
{
if (!list->tail) {
list->head = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
} else {
list->tail->next = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
}
}
/**
* @brief merge two slists, appending the second one to the first
*
* When the operation is completed, the appending list is empty.
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param list_to_append A pointer to the list to append.
*/
static inline void sys_slist_merge_slist(sys_slist_t *list,
sys_slist_t *list_to_append)
{
sys_slist_append_list(list, list_to_append->head,
list_to_append->tail);
sys_slist_init(list_to_append);
}
/**
* @brief Insert a node to the given list
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param prev A pointer on the previous node
* @param node A pointer on the node to insert
*/
static inline void sys_slist_insert(sys_slist_t *list,
sys_snode_t *prev,
sys_snode_t *node)
{
if (!prev) {
sys_slist_prepend(list, node);
} else if (!prev->next) {
sys_slist_append(list, node);
} else {
node->next = prev->next;
prev->next = node;
}
}
/**
* @brief Fetch and remove the first node of the given list
*
* List must be known to be non-empty.
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
*
* @return A pointer to the first node of the list
*/
static inline sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list)
{
sys_snode_t *node = list->head;
list->head = node->next;
if (list->tail == node) {
list->tail = list->head;
}
return node;
}
/**
* @brief Fetch and remove the first node of the given list
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
*
* @return A pointer to the first node of the list (or NULL if empty)
*/
static inline sys_snode_t *sys_slist_get(sys_slist_t *list)
{
return sys_slist_is_empty(list) ? NULL : sys_slist_get_not_empty(list);
}
/**
* @brief Remove a node
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param prev_node A pointer on the previous node
* (can be NULL, which means the node is the list's head)
* @param node A pointer on the node to remove
*/
static inline void sys_slist_remove(sys_slist_t *list,
sys_snode_t *prev_node,
sys_snode_t *node)
{
if (!prev_node) {
list->head = node->next;
/* Was node also the tail? */
if (list->tail == node) {
list->tail = list->head;
}
} else {
prev_node->next = node->next;
/* Was node the tail? */
if (list->tail == node) {
list->tail = prev_node;
}
}
node->next = NULL;
}
/**
* @brief Find and remove a node from a list
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param node A pointer on the node to remove from the list
*
* @return true if node was removed
*/
static inline bool sys_slist_find_and_remove(sys_slist_t *list,
sys_snode_t *node)
{
sys_snode_t *prev = NULL;
sys_snode_t *test;
SYS_SLIST_FOR_EACH_NODE(list, test) {
if (test == node) {
sys_slist_remove(list, prev, node);
return true;
}
prev = test;
}
return false;
}
#ifdef __cplusplus
}
#endif
#endif /* __SLIST_H__ */

View File

@@ -0,0 +1,105 @@
/**
* @file testing.h
* @brief Internal API for Bluetooth testing.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_TESTING_H
#define __BT_TESTING_H
#include "slist.h"
#include "glue.h"
#include "access.h"
/**
* @brief Bluetooth testing
* @defgroup bt_test_cb Bluetooth testing callbacks
* @ingroup bluetooth
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Bluetooth Testing callbacks structure.
*
* Callback structure to be used for Bluetooth testing purposes.
* Allows access to Bluetooth stack internals, not exposed by public API.
*/
struct bt_test_cb {
void (*mesh_net_recv)(u8_t ttl, u8_t ctl, u16_t src, u16_t dst,
const void *payload, size_t payload_len);
void (*mesh_model_bound)(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx);
void (*mesh_model_unbound)(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx);
void (*mesh_prov_invalid_bearer)(u8_t opcode);
void (*mesh_trans_incomp_timer_exp)(void);
sys_snode_t node;
};
/** Register callbacks for Bluetooth testing purposes
*
* @param cb bt_test_cb callback structure
*/
void bt_test_cb_register(struct bt_test_cb *cb);
/** Unregister callbacks for Bluetooth testing purposes
*
* @param cb bt_test_cb callback structure
*/
void bt_test_cb_unregister(struct bt_test_cb *cb);
/** Send Friend Subscription List Add message.
*
* Used by Low Power node to send the group address for which messages are to
* be stored by Friend node.
*
* @param group Group address
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_test_mesh_lpn_group_add(u16_t group);
/** Send Friend Subscription List Remove message.
*
* Used by Low Power node to remove the group addresses from Friend node
* subscription list. Messages sent to those addresses will not be stored
* by Friend node.
*
* @param groups Group addresses
* @param groups_count Group addresses count
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_test_mesh_lpn_group_remove(u16_t *groups, size_t groups_count);
/** Clear replay protection list cache.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_test_mesh_rpl_clear(void);
u8_t mod_bind(struct bt_mesh_model *model, u16_t key_idx);
u8_t mod_unbind(struct bt_mesh_model *model, u16_t key_idx, bool store);
int cmd_mesh_init(int argc, char *argv[]);
int bt_test_shell_init(void);
int bt_test_bind_app_key_to_model(struct bt_mesh_model *model, u16_t key_idx, u16_t id);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __BT_TESTING_H */

View File

@@ -0,0 +1,49 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
pkg.name: nimble/host/mesh
pkg.description: Bluetooth Mesh
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
- ble
- bluetooth
- mesh
pkg.deps:
- "@apache-mynewt-core/kernel/os"
- "@apache-mynewt-core/util/mem"
- "@apache-mynewt-core/crypto/tinycrypt"
- nimble
- nimble/host
pkg.deps.BLE_MESH_SHELL:
- "@apache-mynewt-core/sys/shell"
pkg.deps.BLE_MESH_SETTINGS:
- "@apache-mynewt-core/encoding/base64"
- "@apache-mynewt-core/sys/config"
pkg.req_apis:
- log
- stats
pkg.init:
bt_mesh_register_gatt: 'MYNEWT_VAL(BLE_MESH_SYSINIT_STAGE)'
ble_mesh_shell_init: 'MYNEWT_VAL(BLE_MESH_SYSINIT_STAGE_SHELL)'

View File

@@ -0,0 +1,856 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_ACCESS_LOG
#include <errno.h>
#include <os/os_mbuf.h>
#include "mesh/mesh.h"
#include "mesh_priv.h"
#include "adv.h"
#include "net.h"
#include "lpn.h"
#include "transport.h"
#include "access.h"
#include "foundation.h"
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
#include "mesh/model_cli.h"
#endif
static const struct bt_mesh_comp *dev_comp;
static u16_t dev_primary_addr;
void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
struct bt_mesh_elem *elem,
bool vnd, bool primary,
void *user_data),
void *user_data)
{
int i, j;
for (i = 0; i < dev_comp->elem_count; i++) {
struct bt_mesh_elem *elem = &dev_comp->elem[i];
for (j = 0; j < elem->model_count; j++) {
struct bt_mesh_model *model = &elem->models[j];
func(model, elem, false, i == 0, user_data);
}
for (j = 0; j < elem->vnd_model_count; j++) {
struct bt_mesh_model *model = &elem->vnd_models[j];
func(model, elem, true, i == 0, user_data);
}
}
}
s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
{
int period;
if (!mod->pub) {
return 0;
}
switch (mod->pub->period >> 6) {
case 0x00:
/* 1 step is 100 ms */
period = K_MSEC((mod->pub->period & BIT_MASK(6)) * 100);
break;
case 0x01:
/* 1 step is 1 second */
period = K_SECONDS(mod->pub->period & BIT_MASK(6));
break;
case 0x02:
/* 1 step is 10 seconds */
period = K_SECONDS((mod->pub->period & BIT_MASK(6)) * 10);
break;
case 0x03:
/* 1 step is 10 minutes */
period = K_MINUTES((mod->pub->period & BIT_MASK(6)) * 10);
break;
default:
CODE_UNREACHABLE;
}
if (mod->pub->fast_period) {
return period >> mod->pub->period_div;
} else {
return period;
}
}
static s32_t next_period(struct bt_mesh_model *mod)
{
struct bt_mesh_model_pub *pub = mod->pub;
u32_t elapsed, period;
period = bt_mesh_model_pub_period_get(mod);
if (!period) {
return 0;
}
elapsed = k_uptime_get_32() - pub->period_start;
BT_DBG("Publishing took %ums", (unsigned) elapsed);
if (elapsed > period) {
BT_WARN("Publication sending took longer than the period");
/* Return smallest positive number since 0 means disabled */
return K_MSEC(1);
}
return period - elapsed;
}
static void publish_sent(int err, void *user_data)
{
struct bt_mesh_model *mod = user_data;
s32_t delay;
BT_DBG("err %d", err);
if (mod->pub->count) {
delay = BT_MESH_PUB_TRANSMIT_INT(mod->pub->retransmit);
} else {
delay = next_period(mod);
}
if (delay) {
BT_DBG("Publishing next time in %dms", (int) delay);
k_delayed_work_submit(&mod->pub->timer, delay);
}
}
static void publish_start(u16_t duration, int err, void *user_data)
{
struct bt_mesh_model *mod = user_data;
struct bt_mesh_model_pub *pub = mod->pub;
if (err) {
BT_ERR("Failed to publish: err %d", err);
return;
}
/* Initialize the timestamp for the beginning of a new period */
if (pub->count == BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit)) {
pub->period_start = k_uptime_get_32();
}
}
static const struct bt_mesh_send_cb pub_sent_cb = {
.start = publish_start,
.end = publish_sent,
};
static int publish_retransmit(struct bt_mesh_model *mod)
{
struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_model_pub *pub = mod->pub;
struct bt_mesh_app_key *key;
struct bt_mesh_msg_ctx ctx = {
.addr = pub->addr,
.send_ttl = pub->ttl,
};
struct bt_mesh_net_tx tx = {
.ctx = &ctx,
.src = bt_mesh_model_elem(mod)->addr,
.xmit = bt_mesh_net_transmit_get(),
.friend_cred = pub->cred,
};
int err;
key = bt_mesh_app_key_find(pub->key);
if (!key) {
err = -EADDRNOTAVAIL;
goto done;
}
tx.sub = bt_mesh_subnet_get(key->net_idx);
ctx.net_idx = key->net_idx;
ctx.app_idx = key->app_idx;
net_buf_simple_init(sdu, 0);
net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len);
pub->count--;
err = bt_mesh_trans_send(&tx, sdu, &pub_sent_cb, mod);
done:
os_mbuf_free_chain(sdu);
return err;
}
static void mod_publish(struct ble_npl_event *work)
{
struct bt_mesh_model_pub *pub = ble_npl_event_get_arg(work);
s32_t period_ms;
int err;
BT_DBG("");
period_ms = bt_mesh_model_pub_period_get(pub->mod);
BT_DBG("period %u ms", (unsigned) period_ms);
if (pub->count) {
err = publish_retransmit(pub->mod);
if (err) {
BT_ERR("Failed to retransmit (err %d)", err);
pub->count = 0;
/* Continue with normal publication */
if (period_ms) {
k_delayed_work_submit(&pub->timer, period_ms);
}
}
return;
}
if (!period_ms) {
return;
}
__ASSERT_NO_MSG(pub->update != NULL);
err = pub->update(pub->mod);
if (err) {
BT_ERR("Failed to update publication message");
return;
}
err = bt_mesh_model_publish(pub->mod);
if (err) {
BT_ERR("Publishing failed (err %d)", err);
}
}
struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod)
{
return &dev_comp->elem[mod->elem_idx];
}
struct bt_mesh_model *bt_mesh_model_get(bool vnd, u8_t elem_idx, u8_t mod_idx)
{
struct bt_mesh_elem *elem;
if (elem_idx >= dev_comp->elem_count) {
BT_ERR("Invalid element index %u", elem_idx);
return NULL;
}
elem = &dev_comp->elem[elem_idx];
if (vnd) {
if (mod_idx >= elem->vnd_model_count) {
BT_ERR("Invalid vendor model index %u", mod_idx);
return NULL;
}
return &elem->vnd_models[mod_idx];
} else {
if (mod_idx >= elem->model_count) {
BT_ERR("Invalid SIG model index %u", mod_idx);
return NULL;
}
return &elem->models[mod_idx];
}
}
static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
bool vnd, bool primary, void *user_data)
{
int i;
if (mod->pub) {
mod->pub->mod = mod;
k_delayed_work_init(&mod->pub->timer, mod_publish);
k_delayed_work_add_arg(&mod->pub->timer, mod->pub);
}
for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
mod->keys[i] = BT_MESH_KEY_UNUSED;
}
mod->elem_idx = elem - dev_comp->elem;
if (vnd) {
mod->mod_idx = mod - elem->vnd_models;
} else {
mod->mod_idx = mod - elem->models;
}
if (mod->cb && mod->cb->init) {
mod->cb->init(mod);
}
}
int bt_mesh_comp_register(const struct bt_mesh_comp *comp)
{
/* There must be at least one element */
if (!comp->elem_count) {
return -EINVAL;
}
dev_comp = comp;
bt_mesh_model_foreach(mod_init, NULL);
return 0;
}
void bt_mesh_comp_provision(u16_t addr)
{
int i;
dev_primary_addr = addr;
BT_DBG("addr 0x%04x elem_count %zu", addr, dev_comp->elem_count);
for (i = 0; i < dev_comp->elem_count; i++) {
struct bt_mesh_elem *elem = &dev_comp->elem[i];
elem->addr = addr++;
BT_DBG("addr 0x%04x mod_count %u vnd_mod_count %u",
elem->addr, elem->model_count, elem->vnd_model_count);
}
}
void bt_mesh_comp_unprovision(void)
{
BT_DBG("");
dev_primary_addr = BT_MESH_ADDR_UNASSIGNED;
bt_mesh_model_foreach(mod_init, NULL);
}
u16_t bt_mesh_primary_addr(void)
{
return dev_primary_addr;
}
static u16_t *model_group_get(struct bt_mesh_model *mod, u16_t addr)
{
int i;
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (mod->groups[i] == addr) {
return &mod->groups[i];
}
}
return NULL;
}
struct find_group_visitor_ctx {
u16_t *entry;
struct bt_mesh_model *mod;
u16_t addr;
};
static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod,
u32_t depth, void *user_data)
{
struct find_group_visitor_ctx *ctx = user_data;
if (mod->elem_idx != ctx->mod->elem_idx) {
return BT_MESH_WALK_CONTINUE;
}
ctx->entry = model_group_get(mod, ctx->addr);
if (ctx->entry) {
ctx->mod = mod;
return BT_MESH_WALK_STOP;
}
return BT_MESH_WALK_CONTINUE;
}
u16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, u16_t addr)
{
struct find_group_visitor_ctx ctx = {
.mod = *mod,
.entry = NULL,
.addr = addr,
};
bt_mesh_model_tree_walk(bt_mesh_model_root(*mod),
find_group_mod_visitor, &ctx);
*mod = ctx.mod;
return ctx.entry;
}
static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
u16_t group_addr)
{
struct bt_mesh_model *model;
u16_t *match;
int i;
for (i = 0; i < elem->model_count; i++) {
model = &elem->models[i];
match = model_group_get(model, group_addr);
if (match) {
return model;
}
}
for (i = 0; i < elem->vnd_model_count; i++) {
model = &elem->vnd_models[i];
match = model_group_get(model, group_addr);
if (match) {
return model;
}
}
return NULL;
}
struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr)
{
u16_t index;
if (BT_MESH_ADDR_IS_UNICAST(addr)) {
index = (addr - dev_comp->elem[0].addr);
if (index < dev_comp->elem_count) {
return &dev_comp->elem[index];
} else {
return NULL;
}
}
for (index = 0; index < dev_comp->elem_count; index++) {
struct bt_mesh_elem *elem = &dev_comp->elem[index];
if (bt_mesh_elem_find_group(elem, addr)) {
return elem;
}
}
return NULL;
}
u8_t bt_mesh_elem_count(void)
{
return dev_comp->elem_count;
}
static bool model_has_key(struct bt_mesh_model *mod, u16_t key)
{
int i;
for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
if (mod->keys[i] == key ||
(mod->keys[i] == BT_MESH_KEY_DEV_ANY &&
BT_MESH_IS_DEV_KEY(key))) {
return true;
}
}
return false;
}
static bool model_has_dst(struct bt_mesh_model *mod, u16_t dst)
{
if (BT_MESH_ADDR_IS_UNICAST(dst)) {
return (dev_comp->elem[mod->elem_idx].addr == dst);
} else if (BT_MESH_ADDR_IS_GROUP(dst) || BT_MESH_ADDR_IS_VIRTUAL(dst)) {
return bt_mesh_model_find_group(&mod, dst);
}
return (mod->elem_idx == 0 && bt_mesh_fixed_group_match(dst));
}
static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models,
u8_t model_count, u32_t opcode,
struct bt_mesh_model **model)
{
u8_t i;
for (i = 0; i < model_count; i++) {
const struct bt_mesh_model_op *op;
*model = &models[i];
for (op = (*model)->op; op->func; op++) {
if (op->opcode == opcode) {
return op;
}
}
}
*model = NULL;
return NULL;
}
static int get_opcode(struct os_mbuf *buf, u32_t *opcode)
{
switch (buf->om_data[0] >> 6) {
case 0x00:
case 0x01:
if (buf->om_data[0] == 0x7f) {
BT_ERR("Ignoring RFU OpCode");
return -EINVAL;
}
*opcode = net_buf_simple_pull_u8(buf);
return 0;
case 0x02:
if (buf->om_len < 2) {
BT_ERR("Too short payload for 2-octet OpCode");
return -EINVAL;
}
*opcode = net_buf_simple_pull_be16(buf);
return 0;
case 0x03:
if (buf->om_len < 3) {
BT_ERR("Too short payload for 3-octet OpCode");
return -EINVAL;
}
*opcode = net_buf_simple_pull_u8(buf) << 16;
*opcode |= net_buf_simple_pull_le16(buf);
return 0;
}
CODE_UNREACHABLE;
}
bool bt_mesh_fixed_group_match(u16_t addr)
{
/* Check for fixed group addresses */
switch (addr) {
case BT_MESH_ADDR_ALL_NODES:
return true;
case BT_MESH_ADDR_PROXIES:
return (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
case BT_MESH_ADDR_FRIENDS:
return (bt_mesh_friend_get() == BT_MESH_FRIEND_ENABLED);
case BT_MESH_ADDR_RELAYS:
return (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED);
default:
return false;
}
}
void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
{
struct bt_mesh_model *models, *model;
const struct bt_mesh_model_op *op;
u32_t opcode;
u8_t count;
int i;
BT_DBG("app_idx 0x%04x src 0x%04x dst 0x%04x", rx->ctx.app_idx,
rx->ctx.addr, rx->ctx.recv_dst);
BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
if (get_opcode(buf, &opcode) < 0) {
BT_WARN("Unable to decode OpCode");
return;
}
BT_DBG("OpCode 0x%08x", (unsigned) opcode);
for (i = 0; i < dev_comp->elem_count; i++) {
struct bt_mesh_elem *elem = &dev_comp->elem[i];
struct net_buf_simple_state state;
/* SIG models cannot contain 3-byte (vendor) OpCodes, and
* vendor models cannot contain SIG (1- or 2-byte) OpCodes, so
* we only need to do the lookup in one of the model lists.
*/
if (BT_MESH_MODEL_OP_LEN(opcode) < 3) {
models = elem->models;
count = elem->model_count;
} else {
models = elem->vnd_models;
count = elem->vnd_model_count;
}
op = find_op(models, count, opcode, &model);
if (!op) {
BT_DBG("No OpCode 0x%08x for elem %d", opcode, i);
continue;
}
if (!model_has_key(model, rx->ctx.app_idx)) {
continue;
}
if (!model_has_dst(model, rx->ctx.recv_dst)) {
continue;
}
if (buf->om_len < op->min_len) {
BT_ERR("Too short message for OpCode 0x%08x", opcode);
continue;
}
/* The callback will likely parse the buffer, so
* store the parsing state in case multiple models
* receive the message.
*/
net_buf_simple_save(buf, &state);
op->func(model, &rx->ctx, buf);
net_buf_simple_restore(buf, &state);
}
}
void bt_mesh_model_msg_init(struct os_mbuf *msg, u32_t opcode)
{
net_buf_simple_init(msg, 0);
switch (BT_MESH_MODEL_OP_LEN(opcode)) {
case 1:
net_buf_simple_add_u8(msg, opcode);
break;
case 2:
net_buf_simple_add_be16(msg, opcode);
break;
case 3:
net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff));
net_buf_simple_add_le16(msg, opcode & 0xffff);
break;
default:
BT_WARN("Unknown opcode format");
break;
}
}
static int model_send(struct bt_mesh_model *model,
struct bt_mesh_net_tx *tx, bool implicit_bind,
struct os_mbuf *msg,
const struct bt_mesh_send_cb *cb, void *cb_data)
{
BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->ctx->net_idx,
tx->ctx->app_idx, tx->ctx->addr);
BT_DBG("len %u: %s", msg->om_len, bt_hex(msg->om_data, msg->om_len));
if (!bt_mesh_is_provisioned()) {
BT_ERR("Local node is not yet provisioned");
return -EAGAIN;
}
if (net_buf_simple_tailroom(msg) < 4) {
BT_ERR("Not enough tailroom for TransMIC");
return -EINVAL;
}
if (msg->om_len > BT_MESH_TX_SDU_MAX - 4) {
BT_ERR("Too big message");
return -EMSGSIZE;
}
if (!implicit_bind && !model_has_key(model, tx->ctx->app_idx)) {
BT_ERR("Model not bound to AppKey 0x%04x", tx->ctx->app_idx);
return -EINVAL;
}
return bt_mesh_trans_send(tx, msg, cb, cb_data);
}
int bt_mesh_model_send(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *msg,
const struct bt_mesh_send_cb *cb, void *cb_data)
{
struct bt_mesh_net_tx tx = {
.sub = bt_mesh_subnet_get(ctx->net_idx),
.ctx = ctx,
.src = bt_mesh_model_elem(model)->addr,
.xmit = bt_mesh_net_transmit_get(),
.friend_cred = 0,
};
return model_send(model, &tx, false, msg, cb, cb_data);
}
int bt_mesh_model_publish(struct bt_mesh_model *model)
{
struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_model_pub *pub = model->pub;
struct bt_mesh_app_key *key;
struct bt_mesh_msg_ctx ctx = {
};
struct bt_mesh_net_tx tx = {
.ctx = &ctx,
.src = bt_mesh_model_elem(model)->addr,
.xmit = bt_mesh_net_transmit_get(),
};
int err;
BT_DBG("");
if (!pub) {
err = -ENOTSUP;
goto done;
}
if (pub->addr == BT_MESH_ADDR_UNASSIGNED) {
err = -EADDRNOTAVAIL;
goto done;
}
key = bt_mesh_app_key_find(pub->key);
if (!key) {
err = -EADDRNOTAVAIL;
goto done;
}
if (pub->msg->om_len + 4 > BT_MESH_TX_SDU_MAX) {
BT_ERR("Message does not fit maximum SDU size");
err = -EMSGSIZE;
goto done;
}
if (pub->count) {
BT_WARN("Clearing publish retransmit timer");
k_delayed_work_cancel(&pub->timer);
}
net_buf_simple_init(sdu, 0);
net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len);
ctx.addr = pub->addr;
ctx.send_ttl = pub->ttl;
ctx.net_idx = key->net_idx;
ctx.app_idx = key->app_idx;
tx.friend_cred = pub->cred;
tx.sub = bt_mesh_subnet_get(ctx.net_idx),
pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit);
BT_DBG("Publish Retransmit Count %u Interval %ums", pub->count,
BT_MESH_PUB_TRANSMIT_INT(pub->retransmit));
err = model_send(model, &tx, true, sdu, &pub_sent_cb, model);
if (err) {
/* Don't try retransmissions for this publish attempt */
pub->count = 0;
/* Make sure the publish timer gets reset */
publish_sent(err, model);
}
done:
os_mbuf_free_chain(sdu);
return err;
}
struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem,
u16_t company, u16_t id)
{
u8_t i;
for (i = 0; i < elem->vnd_model_count; i++) {
if (elem->vnd_models[i].vnd.company == company &&
elem->vnd_models[i].vnd.id == id) {
return &elem->vnd_models[i];
}
}
return NULL;
}
struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem,
u16_t id)
{
u8_t i;
for (i = 0; i < elem->model_count; i++) {
if (elem->models[i].id == id) {
return &elem->models[i];
}
}
return NULL;
}
const struct bt_mesh_comp *bt_mesh_comp_get(void)
{
return dev_comp;
}
struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod)
{
#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS
while (mod->next) {
mod = mod->next;
}
#endif
return mod;
}
void bt_mesh_model_tree_walk(struct bt_mesh_model *root,
enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod,
u32_t depth,
void *user_data),
void *user_data)
{
struct bt_mesh_model *m = root;
u32_t depth = 0;
do {
if (cb(m, depth, user_data) == BT_MESH_WALK_STOP) {
return;
}
#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS)
if (m->extends) {
m = m->extends;
depth++;
} else if (m->flags & BT_MESH_MOD_NEXT_IS_PARENT) {
m = m->next->next;
depth--;
} else {
m = m->next;
}
#endif
} while (m && m != root);
}
#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS)
int bt_mesh_model_extend(struct bt_mesh_model *mod,
struct bt_mesh_model *base_mod)
{
/* Form a cyclical LCRS tree:
* The extends-pointer points to the first child, and the next-pointer
* points to the next sibling. The last sibling is marked by the
* BT_MESH_MOD_NEXT_IS_PARENT flag, and its next-pointer points back to
* the parent. This way, the whole tree is accessible from any node.
*
* We add children (extend them) by inserting them as the first child.
*/
if (base_mod->next) {
return -EALREADY;
}
if (mod->extends) {
base_mod->next = mod->extends;
} else {
base_mod->next = mod;
base_mod->flags |= BT_MESH_MOD_NEXT_IS_PARENT;
}
mod->extends = base_mod;
return 0;
}
#endif

View File

@@ -0,0 +1,67 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ACCESS_H__
#define __ACCESS_H__
#include "mesh/mesh.h"
/* bt_mesh_model.flags */
enum {
BT_MESH_MOD_BIND_PENDING = BIT(0),
BT_MESH_MOD_SUB_PENDING = BIT(1),
BT_MESH_MOD_PUB_PENDING = BIT(2),
BT_MESH_MOD_DATA_PRESENT = BIT(3),
BT_MESH_MOD_NEXT_IS_PARENT = BIT(4),
};
/* Tree walk return codes */
enum bt_mesh_walk {
BT_MESH_WALK_STOP,
BT_MESH_WALK_CONTINUE,
};
void bt_mesh_elem_register(struct bt_mesh_elem *elem, u8_t count);
u8_t bt_mesh_elem_count(void);
/* Find local element based on unicast or group address */
struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr);
struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod);
void bt_mesh_model_tree_walk(struct bt_mesh_model *root,
enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod,
u32_t depth,
void *user_data),
void *user_data);
u16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, u16_t addr);
bool bt_mesh_fixed_group_match(u16_t addr);
void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
struct bt_mesh_elem *elem,
bool vnd, bool primary,
void *user_data),
void *user_data);
s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod);
void bt_mesh_comp_provision(u16_t addr);
void bt_mesh_comp_unprovision(void);
u16_t bt_mesh_primary_addr(void);
const struct bt_mesh_comp *bt_mesh_comp_get(void);
struct bt_mesh_model *bt_mesh_model_get(bool vnd, u8_t elem_idx, u8_t mod_idx);
void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf);
int bt_mesh_comp_register(const struct bt_mesh_comp *comp);
#endif

View File

@@ -0,0 +1,439 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_ADV_LOG
#include "mesh/mesh.h"
#include "host/ble_hs_adv.h"
#include "host/ble_gap.h"
#include "nimble/hci_common.h"
#include "mesh/porting.h"
#include "adv.h"
#include "net.h"
#include "foundation.h"
#include "beacon.h"
#include "prov.h"
#include "proxy.h"
/* Convert from ms to 0.625ms units */
#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5)
/* Window and Interval are equal for continuous scanning */
#define MESH_SCAN_INTERVAL_MS 30
#define MESH_SCAN_WINDOW_MS 30
#define MESH_SCAN_INTERVAL ADV_SCAN_UNIT(MESH_SCAN_INTERVAL_MS)
#define MESH_SCAN_WINDOW ADV_SCAN_UNIT(MESH_SCAN_WINDOW_MS)
/* Pre-5.0 controllers enforce a minimum interval of 100ms
* whereas 5.0+ controllers can go down to 20ms.
*/
#define ADV_INT_DEFAULT_MS 100
#define ADV_INT_FAST_MS 20
static s32_t adv_int_min = ADV_INT_DEFAULT_MS;
/* TinyCrypt PRNG consumes a lot of stack space, so we need to have
* an increased call stack whenever it's used.
*/
#if MYNEWT
#define ADV_STACK_SIZE 768
OS_TASK_STACK_DEFINE(g_blemesh_stack, ADV_STACK_SIZE);
struct os_task adv_task;
#endif
static struct ble_npl_eventq adv_queue;
extern u8_t g_mesh_addr_type;
static int adv_initialized = false;
static os_membuf_t adv_buf_mem[OS_MEMPOOL_SIZE(
MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT),
BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE)];
struct os_mbuf_pool adv_os_mbuf_pool;
static struct os_mempool adv_buf_mempool;
static const u8_t adv_type[] = {
[BT_MESH_ADV_PROV] = BLE_HS_ADV_TYPE_MESH_PROV,
[BT_MESH_ADV_DATA] = BLE_HS_ADV_TYPE_MESH_MESSAGE,
[BT_MESH_ADV_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON,
[BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI,
};
static struct bt_mesh_adv adv_pool[CONFIG_BT_MESH_ADV_BUF_COUNT];
static struct bt_mesh_adv *adv_alloc(int id)
{
return &adv_pool[id];
}
static inline void adv_send_start(u16_t duration, int err,
const struct bt_mesh_send_cb *cb,
void *cb_data)
{
if (cb && cb->start) {
cb->start(duration, err, cb_data);
}
}
static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb,
void *cb_data)
{
if (cb && cb->end) {
cb->end(err, cb_data);
}
}
static inline void adv_send(struct os_mbuf *buf)
{
const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb;
void *cb_data = BT_MESH_ADV(buf)->cb_data;
struct ble_gap_adv_params param = { 0 };
u16_t duration, adv_int;
struct bt_data ad;
int err;
adv_int = max(adv_int_min,
BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit));
#if MYNEWT_VAL(BLE_CONTROLLER)
duration = ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) *
(adv_int + 10));
#else
duration = (MESH_SCAN_WINDOW_MS +
((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) *
(adv_int + 10)));
#endif
BT_DBG("type %u om_len %u: %s", BT_MESH_ADV(buf)->type,
buf->om_len, bt_hex(buf->om_data, buf->om_len));
BT_DBG("count %u interval %ums duration %ums",
BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int,
duration);
ad.type = adv_type[BT_MESH_ADV(buf)->type];
ad.data_len = buf->om_len;
ad.data = buf->om_data;
param.itvl_min = ADV_SCAN_UNIT(adv_int);
param.itvl_max = param.itvl_min;
param.conn_mode = BLE_GAP_CONN_MODE_NON;
err = bt_le_adv_start(&param, &ad, 1, NULL, 0);
net_buf_unref(buf);
adv_send_start(duration, err, cb, cb_data);
if (err) {
BT_ERR("Advertising failed: err %d", err);
return;
}
BT_DBG("Advertising started. Sleeping %u ms", duration);
k_sleep(K_MSEC(duration));
err = bt_le_adv_stop(false);
adv_send_end(err, cb, cb_data);
if (err) {
BT_ERR("Stopping advertising failed: err %d", err);
return;
}
BT_DBG("Advertising stopped");
}
void
mesh_adv_thread(void *args)
{
static struct ble_npl_event *ev;
struct os_mbuf *buf;
#if (MYNEWT_VAL(BLE_MESH_PROXY))
s32_t timeout;
#endif
BT_DBG("started");
while (1) {
#if (MYNEWT_VAL(BLE_MESH_PROXY))
ev = ble_npl_eventq_get(&adv_queue, 0);
while (!ev) {
timeout = bt_mesh_proxy_adv_start();
BT_DBG("Proxy Advertising up to %d ms", (int) timeout);
// FIXME: should we redefine K_SECONDS macro instead in glue?
if (timeout != K_FOREVER) {
timeout = ble_npl_time_ms_to_ticks32(timeout);
}
ev = ble_npl_eventq_get(&adv_queue, timeout);
bt_mesh_proxy_adv_stop();
}
#else
ev = ble_npl_eventq_get(&adv_queue, BLE_NPL_TIME_FOREVER);
#endif
if (!ev || !ble_npl_event_get_arg(ev)) {
continue;
}
buf = ble_npl_event_get_arg(ev);
/* busy == 0 means this was canceled */
if (BT_MESH_ADV(buf)->busy) {
BT_MESH_ADV(buf)->busy = 0;
adv_send(buf);
} else {
net_buf_unref(buf);
}
/* os_sched(NULL); */
}
}
void bt_mesh_adv_update(void)
{
static struct ble_npl_event ev = { };
BT_DBG("");
ble_npl_eventq_put(&adv_queue, &ev);
}
struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool,
bt_mesh_adv_alloc_t get_id,
enum bt_mesh_adv_type type,
u8_t xmit, s32_t timeout)
{
struct bt_mesh_adv *adv;
struct os_mbuf *buf;
if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
BT_WARN("Refusing to allocate buffer while suspended");
return NULL;
}
buf = os_mbuf_get_pkthdr(pool, BT_MESH_ADV_USER_DATA_SIZE);
if (!buf) {
return NULL;
}
adv = get_id(net_buf_id(buf));
BT_MESH_ADV(buf) = adv;
memset(adv, 0, sizeof(*adv));
adv->type = type;
adv->xmit = xmit;
adv->ref_cnt = 1;
ble_npl_event_set_arg(&adv->ev, buf);
return buf;
}
struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit,
s32_t timeout)
{
return bt_mesh_adv_create_from_pool(&adv_os_mbuf_pool, adv_alloc, type,
xmit, timeout);
}
void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb,
void *cb_data)
{
BT_DBG("buf %p, type 0x%02x len %u: %s", buf, BT_MESH_ADV(buf)->type, buf->om_len,
bt_hex(buf->om_data, buf->om_len));
BT_MESH_ADV(buf)->cb = cb;
BT_MESH_ADV(buf)->cb_data = cb_data;
BT_MESH_ADV(buf)->busy = 1;
net_buf_put(&adv_queue, net_buf_ref(buf));
}
static void bt_mesh_scan_cb(const bt_addr_le_t *addr, s8_t rssi,
u8_t adv_type, struct os_mbuf *buf)
{
if (adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
return;
}
#if BT_MESH_EXTENDED_DEBUG
BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
#endif
while (buf->om_len > 1) {
struct net_buf_simple_state state;
u8_t len, type;
len = net_buf_simple_pull_u8(buf);
/* Check for early termination */
if (len == 0) {
return;
}
if (len > buf->om_len) {
BT_WARN("AD malformed");
return;
}
net_buf_simple_save(buf, &state);
type = net_buf_simple_pull_u8(buf);
switch (type) {
case BLE_HS_ADV_TYPE_MESH_MESSAGE:
bt_mesh_net_recv(buf, rssi, BT_MESH_NET_IF_ADV);
break;
#if MYNEWT_VAL(BLE_MESH_PB_ADV)
case BLE_HS_ADV_TYPE_MESH_PROV:
bt_mesh_pb_adv_recv(buf);
break;
#endif
case BLE_HS_ADV_TYPE_MESH_BEACON:
bt_mesh_beacon_recv(buf);
break;
default:
break;
}
net_buf_simple_restore(buf, &state);
net_buf_simple_pull(buf, len);
}
}
void bt_mesh_adv_init(void)
{
int rc;
/* Advertising should only be initialized once. Calling
* os_task init the second time will result in an assert. */
if (adv_initialized) {
return;
}
rc = os_mempool_init(&adv_buf_mempool, MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT),
BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE,
adv_buf_mem, "adv_buf_pool");
assert(rc == 0);
rc = os_mbuf_pool_init(&adv_os_mbuf_pool, &adv_buf_mempool,
BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE,
MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT));
assert(rc == 0);
ble_npl_eventq_init(&adv_queue);
#if MYNEWT
os_task_init(&adv_task, "mesh_adv", mesh_adv_thread, NULL,
MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), OS_WAIT_FOREVER,
g_blemesh_stack, ADV_STACK_SIZE);
#endif
/* For BT5 controllers we can have fast advertising interval */
if (ble_hs_hci_get_hci_version() >= BLE_HCI_VER_BCS_5_0) {
adv_int_min = ADV_INT_FAST_MS;
}
adv_initialized = true;
}
int
ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg)
{
#if MYNEWT_VAL(BLE_EXT_ADV)
struct ble_gap_ext_disc_desc *ext_desc;
#endif
struct ble_gap_disc_desc *desc;
struct os_mbuf *buf = NULL;
#if BT_MESH_EXTENDED_DEBUG
BT_DBG("event->type %d", event->type);
#endif
switch (event->type) {
#if MYNEWT_VAL(BLE_EXT_ADV)
case BLE_GAP_EVENT_EXT_DISC:
ext_desc = &event->ext_disc;
buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
if (!buf || os_mbuf_append(buf, ext_desc->data, ext_desc->length_data)) {
BT_ERR("Could not append data");
goto done;
}
bt_mesh_scan_cb(&ext_desc->addr, ext_desc->rssi,
ext_desc->legacy_event_type, buf);
break;
#endif
case BLE_GAP_EVENT_DISC:
desc = &event->disc;
buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
if (!buf || os_mbuf_append(buf, desc->data, desc->length_data)) {
BT_ERR("Could not append data");
goto done;
}
bt_mesh_scan_cb(&desc->addr, desc->rssi, desc->event_type, buf);
break;
default:
break;
}
done:
if (buf) {
os_mbuf_free_chain(buf);
}
return 0;
}
int bt_mesh_scan_enable(void)
{
int err;
#if MYNEWT_VAL(BLE_EXT_ADV)
struct ble_gap_ext_disc_params uncoded_params =
{ .itvl = MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW,
.passive = 1 };
BT_DBG("");
err = ble_gap_ext_disc(g_mesh_addr_type, 0, 0, 0, 0, 0,
&uncoded_params, NULL, NULL, NULL);
#else
struct ble_gap_disc_params scan_param =
{ .passive = 1, .filter_duplicates = 0, .itvl =
MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW };
BT_DBG("");
err = ble_gap_disc(g_mesh_addr_type, BLE_HS_FOREVER, &scan_param,
NULL, NULL);
#endif
if (err && err != BLE_HS_EALREADY) {
BT_ERR("starting scan failed (err %d)", err);
return err;
}
return 0;
}
int bt_mesh_scan_disable(void)
{
int err;
BT_DBG("");
err = ble_gap_disc_cancel();
if (err && err != BLE_HS_EALREADY) {
BT_ERR("stopping scan failed (err %d)", err);
return err;
}
return 0;
}

View File

@@ -0,0 +1,79 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ADV_H__
#define __ADV_H__
/* Maximum advertising data payload for a single data type */
#include "mesh/mesh.h"
#define BT_MESH_ADV(om) (*(struct bt_mesh_adv **) OS_MBUF_USRHDR(om))
#define BT_MESH_ADV_DATA_SIZE 31
/* The user data is a pointer (4 bytes) to struct bt_mesh_adv */
#define BT_MESH_ADV_USER_DATA_SIZE (sizeof(struct bt_mesh_adv *))
#define BT_MESH_MBUF_HEADER_SIZE (sizeof(struct os_mbuf_pkthdr) + \
BT_MESH_ADV_USER_DATA_SIZE +\
sizeof(struct os_mbuf))
enum bt_mesh_adv_type
{
BT_MESH_ADV_PROV,
BT_MESH_ADV_DATA,
BT_MESH_ADV_BEACON,
BT_MESH_ADV_URI,
};
typedef void (*bt_mesh_adv_func_t)(struct os_mbuf *buf, u16_t duration,
int err, void *user_data);
struct bt_mesh_adv {
const struct bt_mesh_send_cb *cb;
void *cb_data;
u8_t type:2,
busy:1;
u8_t xmit;
/* For transport layer segment sending */
struct {
u8_t attempts;
} seg;
u8_t flags;
int ref_cnt;
struct ble_npl_event ev;
};
typedef struct bt_mesh_adv *(*bt_mesh_adv_alloc_t)(int id);
/* xmit_count: Number of retransmissions, i.e. 0 == 1 transmission */
struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit,
s32_t timeout);
struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool,
bt_mesh_adv_alloc_t get_id,
enum bt_mesh_adv_type type,
u8_t xmit, s32_t timeout);
void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb,
void *cb_data);
void bt_mesh_adv_update(void);
void bt_mesh_adv_init(void);
int bt_mesh_scan_enable(void);
int bt_mesh_scan_disable(void);
int ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg);
#endif

View File

@@ -0,0 +1,409 @@
/* atomic operations */
/*
* Copyright (c) 1997-2015, Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ATOMIC_H__
#define __ATOMIC_H__
#ifdef __cplusplus
extern "C"
{
#endif
typedef int atomic_t;
typedef atomic_t atomic_val_t;
/**
* @defgroup atomic_apis Atomic Services APIs
* @ingroup kernel_apis
* @{
*/
/**
* @brief Atomic compare-and-set.
*
* This routine performs an atomic compare-and-set on @a target. If the current
* value of @a target equals @a old_value, @a target is set to @a new_value.
* If the current value of @a target does not equal @a old_value, @a target
* is left unchanged.
*
* @param target Address of atomic variable.
* @param old_value Original value to compare against.
* @param new_value New value to store.
* @return 1 if @a new_value is written, 0 otherwise.
*/
static inline int atomic_cas(atomic_t *target, atomic_val_t old_value,
atomic_val_t new_value)
{
return __atomic_compare_exchange_n(target, &old_value, new_value,
0, __ATOMIC_SEQ_CST,
__ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic addition.
*
* This routine performs an atomic addition on @a target.
*
* @param target Address of atomic variable.
* @param value Value to add.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic subtraction.
*
* This routine performs an atomic subtraction on @a target.
*
* @param target Address of atomic variable.
* @param value Value to subtract.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic increment.
*
* This routine performs an atomic increment by 1 on @a target.
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_inc(atomic_t *target)
{
return atomic_add(target, 1);
}
/**
*
* @brief Atomic decrement.
*
* This routine performs an atomic decrement by 1 on @a target.
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_dec(atomic_t *target)
{
return atomic_sub(target, 1);
}
/**
*
* @brief Atomic get.
*
* This routine performs an atomic read on @a target.
*
* @param target Address of atomic variable.
*
* @return Value of @a target.
*/
static inline atomic_val_t atomic_get(const atomic_t *target)
{
return __atomic_load_n(target, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic get-and-set.
*
* This routine atomically sets @a target to @a value and returns
* the previous value of @a target.
*
* @param target Address of atomic variable.
* @param value Value to write to @a target.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
{
/* This builtin, as described by Intel, is not a traditional
* test-and-set operation, but rather an atomic exchange operation. It
* writes value into *ptr, and returns the previous contents of *ptr.
*/
return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic clear.
*
* This routine atomically sets @a target to zero and returns its previous
* value. (Hence, it is equivalent to atomic_set(target, 0).)
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_clear(atomic_t *target)
{
return atomic_set(target, 0);
}
/**
*
* @brief Atomic bitwise inclusive OR.
*
* This routine atomically sets @a target to the bitwise inclusive OR of
* @a target and @a value.
*
* @param target Address of atomic variable.
* @param value Value to OR.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise exclusive OR (XOR).
*
* This routine atomically sets @a target to the bitwise exclusive OR (XOR) of
* @a target and @a value.
*
* @param target Address of atomic variable.
* @param value Value to XOR
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise AND.
*
* This routine atomically sets @a target to the bitwise AND of @a target
* and @a value.
*
* @param target Address of atomic variable.
* @param value Value to AND.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise NAND.
*
* This routine atomically sets @a target to the bitwise NAND of @a target
* and @a value. (This operation is equivalent to target = ~(target & value).)
*
* @param target Address of atomic variable.
* @param value Value to NAND.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST);
}
/**
* @brief Initialize an atomic variable.
*
* This macro can be used to initialize an atomic variable. For example,
* @code atomic_t my_var = ATOMIC_INIT(75); @endcode
*
* @param i Value to assign to atomic variable.
*/
#define ATOMIC_INIT(i) (i)
/**
* @cond INTERNAL_HIDDEN
*/
#define ATOMIC_BITS (sizeof(atomic_val_t) * 8)
#define ATOMIC_MASK(bit) (1 << ((bit) & (ATOMIC_BITS - 1)))
#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
/**
* INTERNAL_HIDDEN @endcond
*/
/**
* @brief Define an array of atomic variables.
*
* This macro defines an array of atomic variables containing at least
* @a num_bits bits.
*
* @note
* If used from file scope, the bits of the array are initialized to zero;
* if used from within a function, the bits are left uninitialized.
*
* @param name Name of array of atomic variables.
* @param num_bits Number of bits needed.
*/
#define ATOMIC_DEFINE(name, num_bits) \
atomic_t name[1 + ((num_bits) - 1) / ATOMIC_BITS]
/**
* @brief Atomically test a bit.
*
* This routine tests whether bit number @a bit of @a target is set or not.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return 1 if the bit was set, 0 if it wasn't.
*/
static inline int
atomic_test_bit(const atomic_t *target, int bit)
{
atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
return (1 & (val >> (bit & (ATOMIC_BITS - 1))));
}
/**
* @brief Atomically test and clear a bit.
*
* Atomically clear bit number @a bit of @a target and return its old value.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return 1 if the bit was set, 0 if it wasn't.
*/
static inline int
atomic_test_and_clear_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_val_t old;
old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
return (old & mask) != 0;
}
/**
* @brief Atomically set a bit.
*
* Atomically set bit number @a bit of @a target and return its old value.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return 1 if the bit was set, 0 if it wasn't.
*/
static inline int
atomic_test_and_set_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_val_t old;
old = atomic_or(ATOMIC_ELEM(target, bit), mask);
return (old & mask) != 0;
}
/**
* @brief Atomically clear a bit.
*
* Atomically clear bit number @a bit of @a target.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return N/A
*/
static inline void
atomic_clear_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_and(ATOMIC_ELEM(target, bit), ~mask);
}
/**
* @brief Atomically set a bit.
*
* Atomically set bit number @a bit of @a target.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return N/A
*/
static inline void
atomic_set_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_or(ATOMIC_ELEM(target, bit), mask);
}
/**
* @brief Atomically set a bit to a given value.
*
* Atomically set bit number @a bit of @a target to value @a val.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
* @param val true for 1, false for 0.
*
* @return N/A
*/
static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
{
atomic_val_t mask = ATOMIC_MASK(bit);
if (val) {
(void)atomic_or(ATOMIC_ELEM(target, bit), mask);
} else {
(void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
}
}
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __ATOMIC_H__ */

View File

@@ -0,0 +1,441 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_BEACON_LOG
#include <errno.h>
#include <assert.h>
#include "os/os_mbuf.h"
#include "mesh/mesh.h"
#include "adv.h"
#include "mesh_priv.h"
#include "net.h"
#include "prov.h"
#include "crypto.h"
#include "beacon.h"
#include "foundation.h"
#define UNPROVISIONED_INTERVAL (K_SECONDS(5))
#define PROVISIONED_INTERVAL (K_SECONDS(10))
#define BEACON_TYPE_UNPROVISIONED 0x00
#define BEACON_TYPE_SECURE 0x01
/* 3 transmissions, 20ms interval */
#define UNPROV_XMIT BT_MESH_TRANSMIT(2, 20)
/* 1 transmission, 20ms interval */
#define PROV_XMIT BT_MESH_TRANSMIT(0, 20)
static struct k_delayed_work beacon_timer;
static struct bt_mesh_subnet *cache_check(u8_t data[21])
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
if (!memcmp(sub->beacon_cache, data, 21)) {
return sub;
}
}
return NULL;
}
static void cache_add(u8_t data[21], struct bt_mesh_subnet *sub)
{
memcpy(sub->beacon_cache, data, 21);
}
static void beacon_complete(int err, void *user_data)
{
struct bt_mesh_subnet *sub = user_data;
BT_DBG("err %d", err);
sub->beacon_sent = k_uptime_get_32();
}
void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
struct os_mbuf *buf)
{
u8_t flags = bt_mesh_net_flags(sub);
struct bt_mesh_subnet_keys *keys;
net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE);
if (sub->kr_flag) {
keys = &sub->keys[1];
} else {
keys = &sub->keys[0];
}
net_buf_simple_add_u8(buf, flags);
/* Network ID */
net_buf_simple_add_mem(buf, keys->net_id, 8);
/* IV Index */
net_buf_simple_add_be32(buf, bt_mesh.iv_index);
net_buf_simple_add_mem(buf, sub->auth, 8);
BT_DBG("net_idx 0x%04x flags 0x%02x NetID %s", sub->net_idx,
flags, bt_hex(keys->net_id, 8));
BT_DBG("IV Index 0x%08x Auth %s", (unsigned) bt_mesh.iv_index,
bt_hex(sub->auth, 8));
}
/* If the interval has passed or is within 5 seconds from now send a beacon */
#define BEACON_THRESHOLD(sub) (K_SECONDS(10 * ((sub)->beacons_last + 1)) - \
K_SECONDS(5))
static int secure_beacon_send(void)
{
static const struct bt_mesh_send_cb send_cb = {
.end = beacon_complete,
};
u32_t now = k_uptime_get_32();
int i;
BT_DBG("");
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
struct os_mbuf *buf;
u32_t time_diff;
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
time_diff = now - sub->beacon_sent;
if (time_diff < K_SECONDS(600) &&
time_diff < BEACON_THRESHOLD(sub)) {
continue;
}
buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, PROV_XMIT,
K_NO_WAIT);
if (!buf) {
BT_ERR("Unable to allocate beacon buffer");
return -ENOBUFS;
}
bt_mesh_beacon_create(sub, buf);
bt_mesh_adv_send(buf, &send_cb, sub);
net_buf_unref(buf);
}
return 0;
}
static int unprovisioned_beacon_send(void)
{
const struct bt_mesh_prov *prov;
u8_t uri_hash[16] = { 0 };
struct os_mbuf *buf;
u16_t oob_info;
BT_DBG("unprovisioned_beacon_send");
buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, UNPROV_XMIT, K_NO_WAIT);
if (!buf) {
BT_ERR("Unable to allocate beacon buffer");
return -ENOBUFS;
}
prov = bt_mesh_prov_get();
net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED);
net_buf_add_mem(buf, prov->uuid, 16);
if (prov->uri && bt_mesh_s1(prov->uri, uri_hash) == 0) {
oob_info = prov->oob_info | BT_MESH_PROV_OOB_URI;
} else {
oob_info = prov->oob_info;
}
net_buf_add_be16(buf, oob_info);
net_buf_add_mem(buf, uri_hash, 4);
bt_mesh_adv_send(buf, NULL, NULL);
net_buf_unref(buf);
if (prov->uri) {
size_t len;
buf = bt_mesh_adv_create(BT_MESH_ADV_URI, UNPROV_XMIT,
K_NO_WAIT);
if (!buf) {
BT_ERR("Unable to allocate URI buffer");
return -ENOBUFS;
}
len = strlen(prov->uri);
if (net_buf_tailroom(buf) < len) {
BT_WARN("Too long URI to fit advertising data");
} else {
net_buf_add_mem(buf, prov->uri, len);
bt_mesh_adv_send(buf, NULL, NULL);
}
net_buf_unref(buf);
}
return 0;
}
static void unprovisioned_beacon_recv(struct os_mbuf *buf)
{
#if MYNEWT_VAL(BLE_MESH_PB_ADV)
const struct bt_mesh_prov *prov;
u8_t *uuid;
u16_t oob_info;
u32_t uri_hash_val;
u32_t *uri_hash = NULL;
if (buf->om_len != 18 && buf->om_len != 22) {
BT_ERR("Invalid unprovisioned beacon length (%u)", buf->om_len);
return;
}
uuid = net_buf_simple_pull_mem(buf, 16);
oob_info = net_buf_simple_pull_be16(buf);
if (buf->om_len == 4) {
uri_hash_val = net_buf_simple_pull_be32(buf);
uri_hash = &uri_hash_val;
}
BT_DBG("uuid %s", bt_hex(uuid, 16));
prov = bt_mesh_prov_get();
if (prov->unprovisioned_beacon) {
prov->unprovisioned_beacon(uuid,
(bt_mesh_prov_oob_info_t)oob_info,
uri_hash);
}
#endif
}
static void update_beacon_observation(void)
{
static bool first_half;
int i;
/* Observation period is 20 seconds, whereas the beacon timer
* runs every 10 seconds. We process what's happened during the
* window only after the seconnd half.
*/
first_half = !first_half;
if (first_half) {
return;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
sub->beacons_last = sub->beacons_cur;
sub->beacons_cur = 0;
}
}
static void beacon_send(struct ble_npl_event *work)
{
/* Don't send anything if we have an active provisioning link */
if ((MYNEWT_VAL(BLE_MESH_PROV)) && bt_prov_active()) {
k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL);
return;
}
BT_DBG("");
if (bt_mesh_is_provisioned()) {
update_beacon_observation();
secure_beacon_send();
/* Only resubmit if beaconing is still enabled */
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED ||
atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) {
k_delayed_work_submit(&beacon_timer,
PROVISIONED_INTERVAL);
}
} else if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) {
unprovisioned_beacon_send();
k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL);
}
}
static void secure_beacon_recv(struct os_mbuf *buf)
{
u8_t *data, *net_id, *auth;
struct bt_mesh_subnet *sub;
u32_t iv_index;
bool new_key, kr_change, iv_change;
u8_t flags;
if (buf->om_len < 21) {
BT_ERR("Too short secure beacon (len %u)", buf->om_len);
return;
}
sub = cache_check(buf->om_data);
if (sub) {
/* We've seen this beacon before - just update the stats */
goto update_stats;
}
/* So we can add to the cache if auth matches */
data = buf->om_data;
flags = net_buf_simple_pull_u8(buf);
net_id = net_buf_simple_pull_mem(buf, 8);
iv_index = net_buf_simple_pull_be32(buf);
auth = buf->om_data;
BT_DBG("flags 0x%02x id %s iv_index 0x%08x",
flags, bt_hex(net_id, 8), (unsigned) iv_index);
sub = bt_mesh_subnet_find(net_id, flags, iv_index, auth, &new_key);
if (!sub) {
BT_DBG("No subnet that matched beacon");
return;
}
if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !new_key) {
BT_WARN("Ignoring Phase 2 KR Update secured using old key");
return;
}
cache_add(data, sub);
/* If we have NetKey0 accept initiation only from it */
if (bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY) &&
sub->net_idx != BT_MESH_KEY_PRIMARY) {
BT_WARN("Ignoring secure beacon on non-primary subnet");
goto update_stats;
}
BT_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x",
sub->net_idx, (unsigned) iv_index, (unsigned) bt_mesh.iv_index);
if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) &&
(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ==
BT_MESH_IV_UPDATE(flags))) {
bt_mesh_beacon_ivu_initiator(false);
}
iv_change = bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(flags));
kr_change = bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(flags), new_key);
if (kr_change) {
bt_mesh_net_beacon_update(sub);
}
if (iv_change) {
/* Update all subnets */
bt_mesh_net_sec_update(NULL);
} else if (kr_change) {
/* Key Refresh without IV Update only impacts one subnet */
bt_mesh_net_sec_update(sub);
}
update_stats:
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED &&
sub->beacons_cur < 0xff) {
sub->beacons_cur++;
}
}
void bt_mesh_beacon_recv(struct os_mbuf *buf)
{
u8_t type;
BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
if (buf->om_len < 1) {
BT_ERR("Too short beacon");
return;
}
type = net_buf_simple_pull_u8(buf);
switch (type) {
case BEACON_TYPE_UNPROVISIONED:
unprovisioned_beacon_recv(buf);
break;
case BEACON_TYPE_SECURE:
secure_beacon_recv(buf);
break;
default:
BT_WARN("Unknown beacon type 0x%02x", type);
break;
}
}
void bt_mesh_beacon_init(void)
{
k_delayed_work_init(&beacon_timer, beacon_send);
}
void bt_mesh_beacon_ivu_initiator(bool enable)
{
atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_INITIATOR, enable);
if (enable) {
k_work_submit(&beacon_timer.work);
} else if (bt_mesh_beacon_get() == BT_MESH_BEACON_DISABLED) {
k_delayed_work_cancel(&beacon_timer);
}
}
void bt_mesh_beacon_enable(void)
{
int i;
if (!bt_mesh_is_provisioned()) {
k_work_submit(&beacon_timer.work);
return;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
sub->beacons_last = 0;
sub->beacons_cur = 0;
bt_mesh_net_beacon_update(sub);
}
k_work_submit(&beacon_timer.work);
}
void bt_mesh_beacon_disable(void)
{
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) {
k_delayed_work_cancel(&beacon_timer);
}
}

View File

@@ -0,0 +1,26 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BEACON_H__
#define __BEACON_H__
#include "os/os_mbuf.h"
void bt_mesh_beacon_enable(void);
void bt_mesh_beacon_disable(void);
void bt_mesh_beacon_ivu_initiator(bool enable);
void bt_mesh_beacon_recv(struct os_mbuf *buf);
void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
struct os_mbuf *buf);
void bt_mesh_beacon_init(void);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More