You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ry...@apache.org on 2017/04/27 21:45:55 UTC
[2/6] incubator-mynewt-core git commit: MYNEWT-723: Add control
procedure code and HCI command/event code.
MYNEWT-723: Add control procedure code and HCI command/event code.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/4e347012
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/4e347012
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/4e347012
Branch: refs/heads/bluetooth5
Commit: 4e347012011204fd92bf1c3512debe93ae802b2f
Parents: 46d67b0
Author: William San Filippo <wi...@runtime.io>
Authored: Sun Apr 23 15:02:14 2017 -0700
Committer: \u0141ukasz Rymanowski <lu...@codecoup.pl>
Committed: Thu Apr 27 23:38:58 2017 +0200
----------------------------------------------------------------------
.../controller/include/controller/ble_ll.h | 20 +-
.../controller/include/controller/ble_ll_conn.h | 57 +-
.../controller/include/controller/ble_ll_ctrl.h | 28 +-
.../controller/include/controller/ble_ll_hci.h | 2 +
net/nimble/controller/src/ble_ll.c | 12 +
net/nimble/controller/src/ble_ll_conn.c | 94 ++++
net/nimble/controller/src/ble_ll_conn_hci.c | 128 ++++-
net/nimble/controller/src/ble_ll_conn_priv.h | 4 +
net/nimble/controller/src/ble_ll_ctrl.c | 543 ++++++++++++++++++-
net/nimble/controller/src/ble_ll_hci.c | 83 +++
net/nimble/controller/src/ble_ll_hci_ev.c | 33 ++
net/nimble/controller/syscfg.yml | 10 +
net/nimble/include/nimble/hci_common.h | 10 +-
13 files changed, 988 insertions(+), 36 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/include/controller/ble_ll.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll.h b/net/nimble/controller/include/controller/ble_ll.h
index b2cff88..619d1a9 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -57,6 +57,12 @@ extern "C" {
#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)
@@ -90,18 +96,16 @@ struct ble_ll_obj
/* Number of ACL data packets supported */
uint8_t ll_num_acl_pkts;
-#ifdef BLE_XCVR_RFCLK
- uint8_t ll_rfclk_state;
- uint16_t ll_xtal_ticks;
-#else
- uint8_t _pad;
- uint16_t _pad16;
-#endif
-
/* 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;
+
#ifdef BLE_XCVR_RFCLK
+ uint8_t ll_rfclk_state;
+ uint16_t ll_xtal_ticks;
uint32_t ll_rfclk_start_time;
struct hal_timer ll_rfclk_timer;
#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/include/controller/ble_ll_conn.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_conn.h b/net/nimble/controller/include/controller/ble_ll_conn.h
index 7817c65..d3d7639 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -116,10 +116,40 @@ union ble_ll_conn_sm_flags {
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? */
} cfbit;
uint32_t conn_flags;
} __attribute__((packed));
+/**
+ * Structure used for PHY data inside a connection.
+ *
+ * cur_tx_phy: value denoting current tx_phy (not a bitmask!)
+ * cur_rx_phy: value denoting current rx phy (not a bitmask)
+ * pref_tx_phys: bitmask of preferred transmit PHYs
+ * pref_rx_phys: bitmask of preferred receive PHYs
+ * phy_options: preferred phy options for coded phy
+ */
+struct ble_ll_conn_phy_data
+{
+ uint8_t cur_tx_phy: 2;
+ uint8_t cur_rx_phy: 2;
+ uint8_t new_tx_phy: 2;
+ uint8_t new_rx_phy: 2;
+ uint16_t host_pref_tx_phys: 3;
+ uint16_t host_pref_rx_phys: 3;
+ uint16_t req_pref_tx_phys: 3;
+ uint16_t req_pref_rx_phys: 3;
+ uint16_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))
+
/* Connection state machine */
struct ble_ll_conn_sm
{
@@ -131,6 +161,12 @@ struct ble_ll_conn_sm
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;
@@ -145,6 +181,10 @@ struct ble_ll_conn_sm
uint16_t eff_max_tx_time;
uint16_t eff_max_rx_time;
+ /* XXX: TODO: could make this conditional */
+ struct ble_ll_conn_phy_data phy_data;
+ uint16_t phy_instant;
+
/* 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];
@@ -155,9 +195,6 @@ struct ble_ll_conn_sm
uint8_t last_unmapped_chan;
uint8_t num_used_chans;
- /* RSSI */
- int8_t conn_rssi;
-
/* Ack/Flow Control */
uint8_t tx_seqnum; /* note: can be 1 bit */
uint8_t next_exp_seqnum; /* note: can be 1 bit */
@@ -166,9 +203,6 @@ struct ble_ll_conn_sm
uint8_t last_rxd_hdr_byte; /* note: possibly can make 1 bit since we
only use the MD bit now */
- /* For privacy */
- int8_t rpa_index;
-
/* connection event mgmt */
uint8_t reject_reason;
uint8_t host_reply_opcode;
@@ -177,8 +211,8 @@ struct ble_ll_conn_sm
uint8_t cur_ctrl_proc;
uint8_t disconnect_reason;
uint8_t rxd_disconnect_reason;
- uint32_t common_features;
uint8_t vers_nr;
+ uint32_t common_features;
uint16_t pending_ctrl_procs;
uint16_t event_cntr;
uint16_t completed_pkts;
@@ -216,6 +250,10 @@ struct ble_ll_conn_sm
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 os_event conn_ev_end;
@@ -274,6 +312,11 @@ struct ble_ll_conn_sm
#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_TERMINATE_STARTED(csm) ((csm)->csmflags.cfbit.terminate_started)
+#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)
/* Role */
#define CONN_IS_MASTER(csm) (csm->conn_role == BLE_LL_CONN_ROLE_MASTER)
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/include/controller/ble_ll_ctrl.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_ctrl.h b/net/nimble/controller/include/controller/ble_ll_ctrl.h
index 23da308..95f56c4 100644
--- a/net/nimble/controller/include/controller/ble_ll_ctrl.h
+++ b/net/nimble/controller/include/controller/ble_ll_ctrl.h
@@ -38,7 +38,8 @@ extern "C" {
#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_NUM (9)
+#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 */
@@ -75,9 +76,13 @@ extern "C" {
#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)
/* Maximum opcode value */
-#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_LENGTH_RSP + 1)
+#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_MIN_USED_CHAN_IND + 1)
extern const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES];
@@ -131,6 +136,12 @@ struct ble_ll_enc_rsp
#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.
@@ -190,7 +201,7 @@ struct ble_ll_conn_params
uint16_t offset5;
};
-#define BLE_LL_CTRL_CONN_PARAMS_LEN (24)
+#define BLE_LL_CTRL_CONN_PARAMS_LEN (23)
/* LL control reject ind ext */
struct ble_ll_reject_ind_ext
@@ -221,6 +232,14 @@ struct ble_ll_len_req
#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)
+
/* API */
struct ble_ll_conn_sm;
void ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc);
@@ -251,8 +270,9 @@ 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);
-
+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);
#ifdef __cplusplus
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/include/controller/ble_ll_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_hci.h b/net/nimble/controller/include/controller/ble_ll_hci.h
index c2c4542..e54ec7e 100644
--- a/net/nimble/controller/include/controller/ble_ll_hci.h
+++ b/net/nimble/controller/include/controller/ble_ll_hci.h
@@ -54,6 +54,8 @@ int ble_ll_hci_event_send(uint8_t *evbuf);
/* Sends a command complete with a no-op opcode to host */
int 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 *cmdbuf, uint8_t *txphy, uint8_t *rxphy);
#ifdef __cplusplus
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/src/ble_ll.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll.c b/net/nimble/controller/src/ble_ll.c
index 5fe03d0..eb1534b 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -1174,6 +1174,10 @@ ble_ll_reset(void)
memset(&g_ble_ll_log, 0, sizeof(g_ble_ll_log));
#endif
+ /* Reset any preferred PHYs */
+ g_ble_ll_data.ll_pref_tx_phys = 0;
+ g_ble_ll_data.ll_pref_rx_phys = 0;
+
/* Reset connection module */
ble_ll_conn_module_reset();
@@ -1344,6 +1348,14 @@ ble_ll_init(void)
features |= BLE_LL_FEAT_CSA2;
#endif
+#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) == 1)
+ features |= BLE_LL_FEAT_LE_2M_PHY;
+#endif
+
+#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1)
+ features |= BLE_LL_FEAT_LE_CODED_PHY;
+#endif
+
/* Initialize random number generation */
ble_ll_rand_init();
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/src/ble_ll_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c
index e981cd7..0efbba2 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -229,6 +229,42 @@ STATS_NAME_END(ble_ll_conn_stats)
static void ble_ll_conn_event_end(struct os_event *ev);
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+/**
+ * Checks to see if we should start a PHY update procedure
+ *
+ * If current phy is not one of the preferred we need to start control
+ * procedure.
+ *
+ * XXX: we could also decide to change the PHY if RSSI is really good
+ * and we are currently at 1Mbps or lower data rate and we could use
+ * a higher data rate.
+ *
+ * @param connsm
+ * @return 0: success; -1: no phy update procedure started
+ */
+int
+ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *csm)
+{
+ int rc;
+
+ /* If no host preferences or */
+ if (((csm->phy_data.host_pref_tx_phys == 0) &&
+ (csm->phy_data.host_pref_rx_phys == 0)) ||
+ ((csm->phy_data.host_pref_tx_phys & CONN_CUR_TX_PHY_MASK(csm)) &&
+ (csm->phy_data.host_pref_rx_phys & CONN_CUR_RX_PHY_MASK(csm)))) {
+ rc = -1;
+ } else {
+ csm->phy_data.req_pref_tx_phys = csm->phy_data.host_pref_tx_phys;
+ csm->phy_data.req_pref_rx_phys = csm->phy_data.host_pref_rx_phys;
+ ble_ll_ctrl_proc_start(csm, BLE_LL_CTRL_PROC_PHY_UPDATE);
+ rc = 0;
+ }
+
+ return rc;
+}
+#endif
+
#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
static void
ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm)
@@ -905,6 +941,16 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm)
ble_ll_hci_ev_conn_update(connsm, update_status);
connsm->csmflags.cfbit.host_expects_upd_event = 0;
}
+
+ /* Check if we need to send PHY update complete event */
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ if (CONN_F_PHY_UPDATE_EVENT(connsm)) {
+ if (!ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS)) {
+ /* Sent event. Clear flag */
+ CONN_F_PHY_UPDATE_EVENT(connsm) = 0;
+ }
+ }
+#endif
}
/**
@@ -1640,6 +1686,17 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
connsm->conn_rssi = BLE_LL_CONN_UNKNOWN_RSSI;
connsm->rpa_index = -1;
+ /* XXX: TODO set these based on PHY that started connection */
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ connsm->phy_data.cur_tx_phy = BLE_HCI_LE_PHY_1M;
+ connsm->phy_data.cur_rx_phy = BLE_HCI_LE_PHY_1M;
+ connsm->phy_data.req_pref_tx_phys = 0;
+ connsm->phy_data.req_pref_rx_phys = 0;
+ connsm->phy_data.host_pref_tx_phys = g_ble_ll_data.ll_pref_tx_phys;
+ connsm->phy_data.host_pref_rx_phys = g_ble_ll_data.ll_pref_rx_phys;
+ connsm->phy_data.phy_options = 0;
+#endif
+
/* Reset current control procedure */
connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
connsm->pending_ctrl_procs = 0;
@@ -1836,6 +1893,8 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
/**
* Called to move to the next connection event.
*
+ * Context: Link Layer task.
+ *
* @param connsm
*
* @return int
@@ -1861,11 +1920,18 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
ble_ll_ctrl_terminate_start(connsm);
}
+ /*
+ * XXX TODO: I think this is technically incorrect. We can allow slave
+ * latency if we are doing one of these updates as long as we
+ * know that the master has received the ACK to the PDU that set
+ * the instant
+ */
/* Set event counter to the next connection event that we will tx/rx in */
itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
latency = 1;
if (connsm->csmflags.cfbit.allow_slave_latency &&
!connsm->csmflags.cfbit.conn_update_sched &&
+ !CONN_F_PHY_UPDATE_SCHED(connsm) &&
!connsm->csmflags.cfbit.chanmap_update_scheduled) {
if (connsm->csmflags.cfbit.pkt_rxd) {
latency += connsm->slave_latency;
@@ -1974,6 +2040,21 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
check to make sure we dont have to restart! */
}
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ if (CONN_F_PHY_UPDATE_SCHED(connsm) &&
+ (connsm->event_cntr == connsm->phy_instant)) {
+ /* Set cur phy to new phy */
+ connsm->phy_data.cur_tx_phy = connsm->phy_data.new_tx_phy;
+ connsm->phy_data.cur_rx_phy = connsm->phy_data.new_rx_phy;
+
+ /* Clear flags and set flag to send event at next instant */
+ CONN_F_PHY_UPDATE_SCHED(connsm) = 0;
+ CONN_F_PHY_UPDATE_EVENT(connsm) = 1;
+
+ ble_ll_ctrl_phy_update_proc_complete(connsm);
+ }
+#endif
+
/* Calculate data channel index of next connection event */
connsm->data_chan_index = ble_ll_conn_calc_dci(connsm, latency);
@@ -2125,6 +2206,19 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr)
/* Send connection complete event to inform host of connection */
if (rc) {
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ /*
+ * If we have default phy preferences and they are different than
+ * the current PHY's in use, start update procedure.
+ */
+ /*
+ * XXX: should we attempt to start this without knowing if
+ * the other side can support it?
+ */
+ if (!ble_ll_conn_chk_phy_upd_start(connsm)) {
+ CONN_F_CTRLR_PHY_UPDATE(connsm) = 1;
+ }
+#endif
/*
* Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets
* exceeds the minimum, data length procedure needs to occur
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/src/ble_ll_conn_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_hci.c b/net/nimble/controller/src/ble_ll_conn_hci.c
index 429fcb3..4f7390c 100644
--- a/net/nimble/controller/src/ble_ll_conn_hci.c
+++ b/net/nimble/controller/src/ble_ll_conn_hci.c
@@ -236,13 +236,6 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status,
/**
* Called to create and send the number of completed packets event to the
* host.
- *
- * Because of the ridiculous spec, all the connection handles are contiguous
- * and then all the completed packets are contiguous. In order to avoid
- * multiple passes through the connection list or allocating a large stack
- * variable or malloc, I just use the event buffer and place the completed
- * packets after the last possible handle. I then copy the completed packets
- * to make it contiguous with the handles.
*/
void
ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm)
@@ -1021,7 +1014,8 @@ ble_ll_conn_hci_set_data_len(uint8_t *cmdbuf, uint8_t *rspbuf, uint8_t *rsplen)
/*
* XXX: For now; we will simply ignore what the host asks as we are
- * allowed to do so by the spec.
+ * allowed to do so by the spec. If we implement this and something
+ * changes we need to send data length change event.
*/
}
@@ -1204,3 +1198,121 @@ wr_auth_exit:
return rc;
}
#endif
+
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+/**
+ * Read current phy for connection (OGF=8, OCF==0x0030)
+ *
+ * @param cmdbuf
+ * @param rsplen
+ *
+ * @return int
+ */
+int
+ble_ll_conn_hci_le_rd_phy(uint8_t *cmdbuf, uint8_t *rsp, uint8_t *rsplen)
+{
+ int rc;
+ uint16_t handle;
+ struct ble_ll_conn_sm *connsm;
+
+ handle = get_le16(cmdbuf);
+ connsm = ble_ll_conn_find_active_conn(handle);
+ if (!connsm) {
+ rc = BLE_ERR_UNK_CONN_ID;
+ } else {
+ rsp[2] = connsm->phy_data.cur_tx_phy;
+ rsp[3] = connsm->phy_data.cur_rx_phy;
+ rc = BLE_ERR_SUCCESS;
+ }
+
+ put_le16(rsp, handle);
+ *rsplen = BLE_HCI_LE_RD_PHY_RSPLEN;
+ return rc;
+}
+
+/**
+ * Set PHY preferences for connection
+ *
+ * @param cmdbuf
+ *
+ * @return int
+ */
+int
+ble_ll_conn_hci_le_set_phy(uint8_t *cmdbuf)
+{
+ int rc;
+ uint8_t phy_options;
+ uint8_t tx_phys;
+ uint8_t rx_phys;
+ uint16_t handle;
+ struct ble_ll_conn_sm *connsm;
+
+ handle = get_le16(cmdbuf);
+ connsm = ble_ll_conn_find_active_conn(handle);
+ if (!connsm) {
+ return BLE_ERR_UNK_CONN_ID;
+ }
+
+ /*
+ * If host has requested a PHY update and we are not finished do
+ * not allow another one
+ */
+ if (CONN_F_HOST_PHY_UPDATE(connsm)) {
+ return BLE_ERR_CMD_DISALLOWED;
+ }
+
+ phy_options = cmdbuf[5];
+ if (phy_options > BLE_HCI_LE_PHY_CODED_S8_PREF) {
+ return BLE_ERR_INV_HCI_CMD_PARMS;
+ }
+ connsm->phy_data.phy_options = phy_options;
+
+ /* Check valid parameters */
+ rc = ble_ll_hci_chk_phy_masks(cmdbuf + 2, &tx_phys, &rx_phys);
+ if (rc) {
+ goto phy_cmd_param_err;
+ }
+
+ connsm->phy_data.host_pref_tx_phys = tx_phys,
+ connsm->phy_data.host_pref_rx_phys = rx_phys;
+
+ /*
+ * The host preferences override the default phy preferences. Currently,
+ * the only reason the controller will initiate a procedure on its own
+ * is due to the fact that the host set default preferences. So if there
+ * is a pending control procedure and it has not yet started, we do not
+ * need to perform the default controller procedure.
+ */
+ if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE)) {
+ if (connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_PHY_UPDATE) {
+ CONN_F_CTRLR_PHY_UPDATE(connsm) = 0;
+ }
+ CONN_F_HOST_PHY_UPDATE(connsm) = 1;
+ } else {
+ /*
+ * We could be doing a peer-initiated PHY update procedure. If this
+ * is the case the requested phy preferences will not both be 0. If
+ * we are not done with a peer-initiated procedure we just set the
+ * pending bit but do not start the control procedure.
+ */
+ if (CONN_F_PEER_PHY_UPDATE(connsm)) {
+ connsm->pending_ctrl_procs |= BLE_LL_CTRL_PROC_PHY_UPDATE;
+ } else {
+ /* Check if we should start phy update procedure */
+ if (!ble_ll_conn_chk_phy_upd_start(connsm)) {
+ CONN_F_HOST_PHY_UPDATE(connsm) = 1;
+ } else {
+ /*
+ * Set flag to send a PHY update complete event. We set flag
+ * even if we do not do an update procedure since we have to
+ * inform the host even if we decide not to change anything.
+ */
+ CONN_F_PHY_UPDATE_EVENT(connsm) = 1;
+ }
+ }
+ }
+
+phy_cmd_param_err:
+ return rc;
+}
+#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/src/ble_ll_conn_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_priv.h b/net/nimble/controller/src/ble_ll_conn_priv.h
index 02cac60..13e03cf 100644
--- a/net/nimble/controller/src/ble_ll_conn_priv.h
+++ b/net/nimble/controller/src/ble_ll_conn_priv.h
@@ -162,6 +162,10 @@ void ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm);
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(uint8_t *cmdbuf, uint8_t *rsp, uint8_t *rsplen);
+int ble_ll_conn_hci_le_set_phy(uint8_t *cmdbuf);
+int ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *connsm);
+
#ifdef __cplusplus
}
#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/src/ble_ll_ctrl.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_ctrl.c b/net/nimble/controller/src/ble_ll_ctrl.c
index fe0831b..ed9f336 100644
--- a/net/nimble/controller/src/ble_ll_ctrl.c
+++ b/net/nimble/controller/src/ble_ll_ctrl.c
@@ -79,9 +79,88 @@
*/
const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES] =
{
- 11, 7, 1, 22, 12, 0, 0, 1, 8, 8, 0, 0, 5, 1, 8, 23, 23, 2, 0, 0, 8, 8
+ BLE_LL_CTRL_CONN_UPD_REQ_LEN,
+ BLE_LL_CTRL_CHAN_MAP_LEN,
+ BLE_LL_CTRL_TERMINATE_IND_LEN,
+ BLE_LL_CTRL_ENC_REQ_LEN,
+ BLE_LL_CTRL_ENC_RSP_LEN,
+ BLE_LL_CTRL_START_ENC_REQ_LEN,
+ BLE_LL_CTRL_START_ENC_RSP_LEN,
+ BLE_LL_CTRL_UNK_RSP_LEN,
+ BLE_LL_CTRL_FEATURE_LEN,
+ BLE_LL_CTRL_FEATURE_LEN,
+ BLE_LL_CTRL_PAUSE_ENC_REQ_LEN,
+ BLE_LL_CTRL_PAUSE_ENC_RSP_LEN,
+ BLE_LL_CTRL_VERSION_IND_LEN,
+ BLE_LL_CTRL_REJ_IND_LEN,
+ BLE_LL_CTRL_SLAVE_FEATURE_REQ_LEN,
+ BLE_LL_CTRL_CONN_PARAMS_LEN,
+ BLE_LL_CTRL_CONN_PARAMS_LEN,
+ BLE_LL_CTRL_REJECT_IND_EXT_LEN,
+ BLE_LL_CTRL_PING_LEN,
+ BLE_LL_CTRL_PING_LEN,
+ BLE_LL_CTRL_LENGTH_REQ_LEN,
+ BLE_LL_CTRL_LENGTH_REQ_LEN,
+ BLE_LL_CTRL_PHY_REQ_LEN,
+ BLE_LL_CTRL_PHY_RSP_LEN,
+ BLE_LL_CTRL_PHY_UPD_IND_LEN,
+ BLE_LL_CTRL_MIN_USED_CHAN_LEN
};
+/**
+ * Called to determine if a LL control procedure with an instant has
+ * been initiated.
+ *
+ * If the function returns a 0 it means no conflicting procedure has
+ * been initiated. Otherwise it returns the appropriate BLE error code to
+ * send.
+ *
+ * @param connsm Pointer to connection state machine.
+ * @param req_ctrl_proc The procedure that the peer is trying to initiate
+ *
+ * @return uint8_t
+ */
+uint8_t
+ble_ll_ctrl_proc_with_instant_initiated(struct ble_ll_conn_sm *connsm,
+ uint8_t req_ctrl_proc)
+{
+ uint8_t err;
+
+ switch (connsm->cur_ctrl_proc) {
+ case BLE_LL_CTRL_PROC_PHY_UPDATE:
+ case BLE_LL_CTRL_PROC_CONN_UPDATE:
+ case BLE_LL_CTRL_PROC_CONN_PARAM_REQ:
+ case BLE_LL_CTRL_PROC_CHAN_MAP_UPD:
+ if (req_ctrl_proc == connsm->cur_ctrl_proc) {
+ err = BLE_ERR_LMP_COLLISION;
+ } else if ((connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_UPDATE) &&
+ (req_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
+ err = BLE_ERR_LMP_COLLISION;
+ } else {
+ err = BLE_ERR_DIFF_TRANS_COLL;
+ }
+ break;
+ default:
+ err = 0;
+ }
+
+ return err;
+}
+
+/**
+ * Create a LL_REJECT_EXT_IND pdu.
+ *
+ * @param rej_opcode Opcode to be rejected.
+ * @param err: error response
+ * @param ctrdata: Pointer to where CtrData starts in pdu
+ */
+void
+ble_ll_ctrl_rej_ext_ind_make(uint8_t rej_opcode, uint8_t err, uint8_t *ctrdata)
+{
+ ctrdata[0] = rej_opcode;
+ ctrdata[1] = err;
+}
+
static int
ble_ll_ctrl_chk_supp_bytes(uint16_t bytes)
{
@@ -111,6 +190,32 @@ ble_ll_ctrl_chk_supp_time(uint16_t t)
return rc;
}
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+/**
+ * Called when an unknown response or ext reject received while performing
+ * a PHY update procedure
+ *
+ * @param connsm
+ * @param ble_err
+ */
+void
+ble_ll_ctrl_phy_update_rejected(strcut ble_ll_conn_sm *connsm, uint8_t ble_err)
+{
+ /* cancel any pending phy update procedures */
+ CLR_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
+
+ /* Check if the host wants an event */
+ if (CONN_F_HOST_PHY_UPDATE(connsm) == 1) {
+ ble_ll_hci_ev_phy_update(connsm, ble_err);
+ CONN_F_HOST_PHY_UPDATE(connsm) = 0;
+ }
+
+ /* Clear any bits for phy updates that might be in progress */
+ CONN_F_PEER_PHY_UPDATE(connsm) = 0;
+ CONN_F_CTRLR_PHY_UPDATE(connsm) = 0;
+}
+#endif
+
static int
ble_ll_ctrl_len_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
{
@@ -312,6 +417,12 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
#endif
ctrl_proc = BLE_LL_CTRL_PROC_LE_PING;
break;
+#if (BLE_LL_BT5_PHY_SUPPORTED ==1)
+ case BLE_LL_CTRL_PHY_REQ:
+ ble_ll_ctrl_phy_update_rejected(connsm, BLE_ERR_UNSUPP_REM_FEATURE);
+ ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE;
+ break;
+#endif
default:
ctrl_proc = BLE_LL_CTRL_PROC_NUM;
break;
@@ -329,6 +440,394 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
}
}
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+void
+ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm)
+{
+ int chk_proc_stop;
+ int chk_host_phy;
+
+ chk_proc_stop = 1;
+ chk_host_phy = 1;
+
+ if (CONN_F_PEER_PHY_UPDATE(connsm)) {
+ CONN_F_PEER_PHY_UPDATE(connsm) = 0;
+ /* Must check if we need to start procedure */
+ chk_proc_stop = 0;
+ } else if (CONN_F_CTRLR_PHY_UPDATE(connsm)) {
+ CONN_F_CTRLR_PHY_UPDATE(connsm) = 0;
+ } else {
+ /* Must be a host-initiated update */
+ CONN_F_HOST_PHY_UPDATE(connsm) = 0;
+ chk_host_phy = 0;
+ if (CONN_F_PHY_UPDATE_EVENT(connsm) == 0) {
+ ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS);
+ }
+ }
+
+ /* Must check if we need to start host procedure */
+ if (chk_host_phy) {
+ if (CONN_F_HOST_PHY_UPDATE(connsm) == 1) {
+ if (ble_ll_conn_chk_phy_upd_start(connsm)) {
+ CONN_F_HOST_PHY_UPDATE(connsm) = 0;
+ }
+ }
+ }
+
+ if (chk_proc_stop) {
+ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
+ }
+}
+
+/**
+ * Convert a phy mask to a numeric phy value.
+ *
+ * NOTE: only one bit should be set here and there should be at least one.
+ * If this function returns a 0 it is an error!
+ *
+ * @param phy_mask Bitmask of phy
+ *
+ * @return uint8_t The numeric value associated with the phy mask
+ *
+ * BLE_HCI_LE_PHY_1M (1)
+ * BLE_HCI_LE_PHY_2M (2)
+ * BLE_HCI_LE_PHY_CODED (3)
+ */
+static uint8_t
+ble_ll_ctrl_phy_mask_to_numeric(uint8_t phy_mask)
+{
+ uint8_t numeric;
+
+ /*
+ * NOTE: wipe out unsupported PHYs. There should not be an unsupported
+ * in this mask if the other side is working correctly.
+ */
+#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
+ phy_mask &= ~BLE_HCI_LE_PHY_2M_PREF_MASK;
+#endif
+#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
+ phy_mask &= ~BLE_HCI_LE_PHY_CODED_PREF_MASK;
+#endif
+
+ if (phy_mask & BLE_HCI_LE_PHY_1M_PREF_MASK) {
+ numeric = BLE_HCI_LE_PHY_1M;
+ phy_mask &= ~BLE_HCI_LE_PHY_1M_PREF_MASK;
+ } else if (phy_mask & BLE_HCI_LE_PHY_2M_PREF_MASK) {
+ numeric = BLE_HCI_LE_PHY_2M;
+ phy_mask &= ~BLE_HCI_LE_PHY_2M_PREF_MASK;
+ } else if (phy_mask & BLE_HCI_LE_PHY_CODED_PREF_MASK) {
+ numeric = BLE_HCI_LE_PHY_CODED;
+ phy_mask &= ~BLE_HCI_LE_PHY_CODED_PREF_MASK;
+ } else {
+ numeric = 0;
+ }
+
+ if (phy_mask != 0) {
+ numeric = 0;
+ }
+
+ return numeric;
+}
+
+/**
+ *
+ * There is probably a better way for the controller to choose which PHY use.
+ * There are no BER metrics and RSSI does not give you S/N so for now we will
+ * choose this heirarchy:
+ * -> if 2Mbps available, use it.
+ * -> If 1Mbps available, use it.
+ * -> otherwise use coded phy.
+ *
+ * @param prefs The mask of preferred phys
+ * @return uint8_t The phy to use (not a mask)
+ */
+static uint8_t
+ble_ll_ctrl_find_new_phy(uint8_t prefs)
+{
+ uint8_t new_phy;
+
+ new_phy = prefs;
+ if (new_phy) {
+ if (new_phy & BLE_HCI_LE_PHY_2M_PREF_MASK) {
+ new_phy = BLE_HCI_LE_PHY_2M;
+ } else if (new_phy & BLE_HCI_LE_PHY_1M_PREF_MASK) {
+ new_phy = BLE_HCI_LE_PHY_1M;
+ } else {
+ new_phy = BLE_HCI_LE_PHY_CODED;
+ }
+ }
+
+ return new_phy;
+}
+
+/**
+ * Create a LL_PHY_UPDATE_IND pdu
+ *
+ * @param connsm Pointer to connection state machine
+ * @param dptr Pointer to PHY_REQ or PHY_RSP data.
+ * @param ctrdata: Pointer to where CtrData of UPDATE_IND pdu starts
+ * @param slave_req flag denoting if slave requested this. 0: no 1:yes
+ */
+static void
+ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+ uint8_t *ctrdata, int slave_req)
+{
+ uint8_t m_to_s;
+ uint8_t s_to_m;
+ uint8_t tx_phys;
+ uint8_t rx_phys;
+ uint16_t instant;
+
+ /* Get preferences from PDU */
+ tx_phys = dptr[0];
+ rx_phys = dptr[1];
+
+ /* Get m_to_s and s_to_m masks */
+ if (slave_req) {
+ m_to_s = connsm->phy_data.host_pref_tx_phys & rx_phys;
+ s_to_m = connsm->phy_data.host_pref_rx_phys & tx_phys;
+ } else {
+ m_to_s = connsm->phy_data.req_pref_tx_phys & rx_phys;
+ s_to_m = connsm->phy_data.req_pref_rx_phys & tx_phys;
+ }
+
+ /* Find new phys. If not different than current, set to 0 */
+ m_to_s = ble_ll_ctrl_find_new_phy(m_to_s);
+ if (m_to_s == connsm->phy_data.cur_tx_phy) {
+ m_to_s = 0;
+ }
+
+ s_to_m = ble_ll_ctrl_find_new_phy(s_to_m);
+ if (s_to_m == connsm->phy_data.cur_rx_phy) {
+ s_to_m = 0;
+ }
+
+ /* At this point, m_to_s and s_to_m are not masks; they are numeric */
+
+ /*
+ * If not changing we still send update ind. Check if hosts expects
+ * the event and if so send it. Stop control procedure if it is the
+ * one running.
+ */
+ if ((m_to_s == 0) && (s_to_m == 0)) {
+ if (CONN_F_PEER_PHY_UPDATE(connsm)) {
+ CONN_F_PEER_PHY_UPDATE(connsm) = 0;
+ } else if (CONN_F_CTRLR_PHY_UPDATE(connsm)) {
+ CONN_F_CTRLR_PHY_UPDATE(connsm) = 0;
+ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
+ } else {
+ ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS);
+ CONN_F_HOST_PHY_UPDATE(connsm) = 0;
+ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
+ }
+ instant = 0;
+ } else {
+ /* Determine instant we will use. 6 more is minimum */
+ instant = connsm->event_cntr + connsm->slave_latency + 6 + 1;
+ connsm->phy_instant = instant;
+ CONN_F_PHY_UPDATE_SCHED(connsm) = 1;
+
+ /* Convert m_to_s and s_to_m to masks */
+ m_to_s = 1 << (m_to_s - 1);
+ s_to_m = 1 << (s_to_m - 1);
+
+ /* Set new phys to use when instant occurs */
+ connsm->phy_data.new_tx_phy = m_to_s;
+ connsm->phy_data.new_rx_phy = s_to_m;
+ }
+
+ ctrdata[0] = m_to_s;
+ ctrdata[1] = s_to_m;
+ put_le16(ctrdata + 2, instant);
+}
+
+/**
+ * Create a LL_PHY_REQ or LL_PHY_RSP pdu
+ *
+ * @param connsm Pointer to connection state machine
+ * @param ctrdata: Pointer to where CtrData starts in pdu
+ */
+static void
+ble_ll_ctrl_phy_req_rsp_make(struct ble_ll_conn_sm *connsm, uint8_t *ctrdata)
+{
+ ctrdata[0] = connsm->phy_data.host_pref_tx_phys;
+ ctrdata[1] = connsm->phy_data.host_pref_rx_phys;
+}
+
+static uint8_t
+ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req,
+ uint8_t *rsp)
+{
+ uint8_t rsp_opcode;
+ uint8_t err;
+
+ /*
+ * XXX: TODO if we have an instant in progress we should end connection.
+ * At least it seems that is the case. Need to figure out more from
+ * the spec here.
+ */
+
+ /* Check if we have already initiated a procedure with an instant */
+ err = ble_ll_ctrl_proc_with_instant_initiated(connsm,
+ BLE_LL_CTRL_PROC_PHY_UPDATE);
+
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+ if (err) {
+ ble_ll_ctrl_rej_ext_ind_make(BLE_LL_CTRL_PHY_REQ, err, rsp);
+ rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
+ } else {
+ /*
+ * NOTE: do not change order of these two lines as the call to
+ * make the LL_PHY_UPDATE_IND pdu might clear the flag.
+ */
+ CONN_F_PEER_PHY_UPDATE(connsm) = 1;
+ ble_ll_ctrl_phy_update_ind_make(connsm, req, rsp, 1);
+ rsp_opcode = BLE_LL_CTRL_PHY_UPDATE_IND;
+ }
+ } else {
+ /* XXX: deal with other control procedures that we need to stop */
+ if (err) {
+ if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) {
+ os_callout_stop(&connsm->ctrl_proc_rsp_timer);
+ connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
+ }
+
+ /* If there is a PHY update procedure pending clear it */
+ CLR_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
+
+ /* Need to send event to host if the host phy update is pending */
+ if (CONN_F_HOST_PHY_UPDATE(connsm)) {
+ CONN_F_HOST_PHY_UPDATE(connsm) = 0;
+ ble_ll_hci_ev_phy_update(connsm, err);
+ }
+
+ /* Clear any flags we do not want around */
+ CONN_F_CTRLR_PHY_UPDATE(connsm) = 0;
+ CONN_F_PHY_UPDATE_EVENT(connsm) = 0;
+ }
+
+ /* XXX: TODO: if we started another procedure with an instant
+ why are we doing this? Need to look into this */
+
+ /* Respond to master's phy update procedure */
+ CONN_F_PEER_PHY_UPDATE(connsm) = 1;
+ ble_ll_ctrl_phy_req_rsp_make(connsm, rsp);
+ rsp_opcode = BLE_LL_CTRL_PHY_RSP;
+ }
+ return rsp_opcode;
+}
+
+/**
+ * Process a received LL_PHY_RSP pdu
+ *
+ * @param connsm
+ * @param dptr Pointer to LL_PHY_RSP ctrdata
+ * @param rsp Pointer to CtrData of PHY_UPDATE_IND.
+ *
+ * @return uint8_t
+ */
+static uint8_t
+ble_ll_ctrl_rx_phy_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+ uint8_t *rsp)
+{
+ uint8_t rsp_opcode;
+
+ rsp_opcode = BLE_ERR_MAX;
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+ if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) {
+ ble_ll_ctrl_phy_update_ind_make(connsm, dptr, rsp, 0);
+ rsp_opcode = BLE_LL_CTRL_PHY_UPDATE_IND;
+ }
+
+ /*
+ * If not in the process of doing this control procedure something
+ * is wrong. End connection? Assert?
+ *
+ * XXX: TODO count some stat?
+ */
+ }
+
+ /* NOTE: slave should never receive one of these */
+
+ return rsp_opcode;
+}
+
+/**
+ * Called when a LL_PHY_UPDATE_IND pdu is received
+ *
+ * NOTE: slave is the only device that should receive this.
+ *
+ * @param connsm
+ * @param dptr
+ */
+void
+ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
+{
+ uint8_t new_tx_phy_mask;
+ uint8_t new_rx_phy_mask;
+ uint8_t new_tx_phy;
+ uint8_t new_rx_phy;
+ int no_change;
+ uint16_t instant;
+ uint16_t delta;
+
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+ /*
+ * Reception stops the procedure response timer but does not
+ * complete the procedure
+ */
+ if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) {
+ os_callout_stop(&connsm->ctrl_proc_rsp_timer);
+ }
+
+ /*
+ * XXX: Should we check to see if we are expecting to receive one
+ * of these, and if not, kill connection? Meaning we better be
+ * doing either a PEER, CTRLR, or HOST phy update.
+ */
+ /* get the new phy masks and see if we need to change */
+ new_tx_phy_mask = dptr[0];
+ new_rx_phy_mask = dptr[1];
+ instant = get_le16(dptr + 2);
+
+ no_change = 0;
+ if ((new_tx_phy_mask == 0) && (new_rx_phy_mask == 0)) {
+ /* No change in phy */
+ no_change = 1;
+ } else {
+ new_tx_phy = ble_ll_ctrl_phy_mask_to_numeric(new_tx_phy_mask);
+ new_rx_phy = ble_ll_ctrl_phy_mask_to_numeric(new_rx_phy_mask);
+
+ if ((new_tx_phy == 0) && (new_rx_phy == 0)) {
+ /* XXX: this is an error! What to do??? */
+ no_change = 1;
+ }
+
+ if ((new_tx_phy == connsm->phy_data.cur_tx_phy) &&
+ (new_rx_phy == connsm->phy_data.cur_tx_phy)) {
+ no_change = 1;
+ }
+ }
+
+ if (!no_change) {
+ /* If instant is in the past, we have to end the connection */
+ delta = (instant - connsm->event_cntr) & 0xFFFF;
+ if (delta >= 32767) {
+ ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED);
+ } else {
+ connsm->phy_data.new_tx_phy = new_tx_phy;
+ connsm->phy_data.new_rx_phy = new_rx_phy;
+ connsm->phy_instant = instant;
+ CONN_F_PHY_UPDATE_SCHED(connsm) = 1;
+ }
+ return;
+ }
+
+ ble_ll_ctrl_phy_update_proc_complete(connsm);
+ }
+}
+#endif
+
/**
* Create a link layer length request or length response PDU.
*
@@ -461,7 +960,6 @@ ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu)
* Called to create and send a LL_START_ENC_REQ or LL_START_ENC_RSP
*
* @param connsm
- * @param rej_opcode
* @param err
*
* @return int
@@ -919,7 +1417,7 @@ ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, uint8_t *rsp,
/**
* Called when we have received a LL_REJECT_IND or LL_REJECT_IND_EXT link
- * layer control Dat Channel pdu.
+ * layer control Data Channel pdu.
*
* @param connsm
* @param dptr
@@ -954,6 +1452,12 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED;
break;
#endif
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ case BLE_LL_CTRL_PROC_PHY_UPDATE:
+ ble_ll_ctrl_phy_update_rejected(connsm, ble_error);
+ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
+ break;
+#endif
default:
break;
}
@@ -964,13 +1468,11 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
*
* @param connsm
* @param dptr
- * @param rspbuf
*
* @return int
*/
static int
-ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
- uint8_t *rspbuf)
+ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
{
uint8_t rsp_opcode;
uint16_t conn_events;
@@ -1320,6 +1822,12 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc)
}
break;
#endif
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ case BLE_LL_CTRL_PROC_PHY_UPDATE:
+ opcode = BLE_LL_CTRL_PHY_REQ;
+ ble_ll_ctrl_phy_req_rsp_make(connsm, dptr);
+ break;
+#endif
default:
assert(0);
break;
@@ -1462,6 +1970,13 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm)
{
int i;
+ /* WWW: new rules! Cannot start certain control procedures if other
+ * ones are peer initiated. We need to wait. Deal with this.
+ *
+ * WWW: Do not forget code that when some of these things end we need
+ * to check to start other control procedures
+ */
+
/*
* If we are terminating, dont start any new procedures but start
* terminate if needed
@@ -1602,6 +2117,9 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
case BLE_LL_CTRL_PING_REQ:
feature = BLE_LL_FEAT_LE_PING;
break;
+ case BLE_LL_CTRL_PHY_REQ:
+ feature = BLE_LL_FEAT_LE_2M_PHY | BLE_LL_FEAT_LE_CODED_PHY;
+ break;
default:
feature = 0;
break;
@@ -1632,7 +2150,7 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
rsp_opcode = BLE_ERR_MAX;
switch (opcode) {
case BLE_LL_CTRL_CONN_UPDATE_REQ:
- rsp_opcode = ble_ll_ctrl_rx_conn_update(connsm, dptr, rspbuf);
+ rsp_opcode = ble_ll_ctrl_rx_conn_update(connsm, dptr);
break;
case BLE_LL_CTRL_CHANNEL_MAP_REQ:
ble_ll_ctrl_rx_chanmap_req(connsm, dptr);
@@ -1733,6 +2251,17 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
case BLE_LL_CTRL_REJECT_IND_EXT:
ble_ll_ctrl_rx_reject_ind(connsm, dptr, opcode);
break;
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ case BLE_LL_CTRL_PHY_REQ:
+ rsp_opcode = ble_ll_ctrl_rx_phy_req(connsm, dptr, rspdata);
+ break;
+ case BLE_LL_CTRL_PHY_RSP:
+ rsp_opcode = ble_ll_ctrl_rx_phy_rsp(connsm, dptr, rspdata);
+ break;
+ case BLE_LL_CTRL_PHY_UPDATE_IND:
+ ble_ll_ctrl_rx_phy_update_ind(connsm, dptr);
+ break;
+#endif
default:
/* Nothing to do here */
break;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/src/ble_ll_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_hci.c b/net/nimble/controller/src/ble_ll_hci.c
index 692c0c9..a6e4c56 100644
--- a/net/nimble/controller/src/ble_ll_hci.c
+++ b/net/nimble/controller/src/ble_ll_hci.c
@@ -290,6 +290,75 @@ ble_ll_hci_le_read_bufsize(uint8_t *rspbuf, uint8_t *rsplen)
return BLE_ERR_SUCCESS;
}
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+/**
+ * Checks the preferred phy masks for validity and places the preferred masks
+ * in the input phy masks
+ *
+ * @param cmdbuf Pointer to command buffer where phy masks are located
+ * @param txphy Pointer to output tx phy mask
+ * @param rxphy Pointer to output rx phy mask
+ *
+ * @return int BLE_ERR_SUCCESS or BLE_ERR_INV_HCI_CMD_PARMS
+ */
+int
+ble_ll_hci_chk_phy_masks(uint8_t *cmdbuf, uint8_t *txphy, uint8_t *rxphy)
+{
+ int rc;
+ uint8_t all_phys;
+ uint8_t rx_phys;
+ uint8_t tx_phys;
+
+ /* Check for valid values */
+ all_phys = cmdbuf[0];
+ tx_phys = cmdbuf[1] & BLE_HCI_LE_PHY_PREF_MASK_ALL;
+ rx_phys = cmdbuf[2] & BLE_HCI_LE_PHY_PREF_MASK_ALL;
+
+ if (((all_phys & BLE_HCI_LE_PHY_TX_PREF) && (tx_phys == 0)) ||
+ ((all_phys & BLE_HCI_LE_PHY_RX_PREF) && (rx_phys == 0))) {
+ rc = BLE_ERR_INV_HCI_CMD_PARMS;
+ } else {
+ /* If phy not supported, wipe its bit */
+#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
+ tx_phys &= ~BLE_HCI_LE_PHY_2M_PREF_MASK;
+ rx_phys &= ~BLE_HCI_LE_PHY_2M_PREF_MASK;
+#endif
+#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
+ tx_phys &= ~BLE_HCI_LE_PHY_CODED_PREF_MASK;
+ rx_phys &= ~BLE_HCI_LE_PHY_CODED_PREF_MASK;
+#endif
+ /* Set the default PHY preferences */
+ if ((all_phys & BLE_HCI_LE_PHY_TX_PREF) == 0) {
+ tx_phys = 0;
+ }
+ *txphy = tx_phys;
+ if ((all_phys & BLE_HCI_LE_PHY_RX_PREF) == 0) {
+ rx_phys = 0;
+ }
+ *rxphy = rx_phys;
+ rc = BLE_ERR_SUCCESS;
+ }
+ return rc;
+}
+
+/**
+ * Set PHY preferences for connection
+ *
+ * @param cmdbuf
+ *
+ * @return int
+ */
+static int
+ble_ll_hci_le_set_def_phy(uint8_t *cmdbuf)
+{
+ int rc;
+
+ rc = ble_ll_hci_chk_phy_masks(cmdbuf, &g_ble_ll_data.ll_pref_tx_phys,
+ &g_ble_ll_data.ll_pref_rx_phys);
+ return rc;
+}
+#endif
+
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) == 1)
/**
* HCI write suggested default data length command.
@@ -322,6 +391,8 @@ ble_ll_hci_le_wr_sugg_data_len(uint8_t *cmdbuf)
g_ble_ll_conn_params.sugg_tx_octets = (uint8_t)tx_oct;
g_ble_ll_conn_params.sugg_tx_time = tx_time;
+ /* XXX TODO: This has to change! They do not have to be the same
+ at this point. Deal with this */
if ((tx_time <= g_ble_ll_conn_params.supp_max_tx_time) &&
(tx_oct <= g_ble_ll_conn_params.supp_max_tx_octets)) {
g_ble_ll_conn_params.conn_init_max_tx_octets = tx_oct;
@@ -500,6 +571,7 @@ ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf)
case BLE_HCI_OCF_LE_START_ENCRYPT:
case BLE_HCI_OCF_LE_RD_P256_PUBKEY:
case BLE_HCI_OCF_LE_GEN_DHKEY:
+ case BLE_HCI_OCF_LE_SET_PHY:
rc = 1;
break;
default:
@@ -768,6 +840,17 @@ ble_ll_hci_le_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen)
case BLE_HCI_OCF_LE_RD_MAX_DATA_LEN:
rc = ble_ll_hci_le_rd_max_data_len(rspbuf, rsplen);
break;
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ case BLE_HCI_OCF_LE_RD_PHY:
+ rc = ble_ll_conn_hci_le_rd_phy(cmdbuf, rspbuf, rsplen);
+ break;
+ case BLE_HCI_OCF_LE_SET_DEFAULT_PHY:
+ rc = ble_ll_hci_le_set_def_phy(cmdbuf);
+ break;
+ case BLE_HCI_OCF_LE_SET_PHY:
+ rc = ble_ll_conn_hci_le_set_phy(cmdbuf);
+ break;
+#endif
default:
rc = BLE_ERR_UNKNOWN_HCI_CMD;
break;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/src/ble_ll_hci_ev.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_hci_ev.c b/net/nimble/controller/src/ble_ll_hci_ev.c
index 3319db3..2ee9908 100644
--- a/net/nimble/controller/src/ble_ll_hci_ev.c
+++ b/net/nimble/controller/src/ble_ll_hci_ev.c
@@ -292,3 +292,36 @@ ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm)
}
}
#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)
+{
+ int rc;
+ uint8_t *evbuf;
+
+ rc = 0;
+ if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE)) {
+ evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
+ if (evbuf) {
+ evbuf[0] = BLE_HCI_EVCODE_LE_META;
+ evbuf[1] = BLE_HCI_LE_PHY_UPD_COMP_LEN;
+ evbuf[2] = BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE;
+ evbuf[3] = status;
+ put_le16(evbuf + 4, connsm->conn_handle);
+ evbuf[6] = connsm->phy_data.cur_tx_phy;
+ evbuf[7] = connsm->phy_data.cur_rx_phy;
+ ble_ll_hci_event_send(evbuf);
+ } else {
+ rc = BLE_ERR_MEM_CAPACITY;
+ }
+ }
+ return rc;
+}
+#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/controller/syscfg.yml
----------------------------------------------------------------------
diff --git a/net/nimble/controller/syscfg.yml b/net/nimble/controller/syscfg.yml
index 0fe7a48..1b00a4e 100644
--- a/net/nimble/controller/syscfg.yml
+++ b/net/nimble/controller/syscfg.yml
@@ -210,6 +210,16 @@ syscfg.defs:
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_PUBLIC_DEV_ADDR:
description: >
Allows the target or app to override the public device address
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/4e347012/net/nimble/include/nimble/hci_common.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/hci_common.h b/net/nimble/include/nimble/hci_common.h
index 8ae29dc..f929d85 100644
--- a/net/nimble/include/nimble/hci_common.h
+++ b/net/nimble/include/nimble/hci_common.h
@@ -161,7 +161,6 @@ extern "C" {
#define BLE_HCI_OCF_LE_SET_PRIVACY_MODE (0x004E)
/* Command Specific Definitions */
-
#define BLE_HCI_VARIABLE_LEN (0xFF)
/* --- Disconnect command (OGF 0x01, OCF 0x0006) --- */
@@ -418,12 +417,19 @@ extern "C" {
#define BLE_HCI_RD_MAX_DATALEN_RSPLEN (8)
/* --- LE read maximum default PHY (OCF 0x0030) */
-#define BLE_HCI_LE_RD_PHY_LEN (2)
+#define BLE_HCI_LE_RD_PHY_LEN (2)
+#define BLE_HCI_LE_RD_PHY_RSPLEN (4)
+#define BLE_HCI_LE_PHY_1M (1)
+#define BLE_HCI_LE_PHY_2M (2)
+#define BLE_HCI_LE_PHY_CODED (3)
/* --- LE set default PHY (OCF 0x0031) */
#define BLE_HCI_LE_SET_DEFAULT_PHY_LEN (3)
#define BLE_HCI_LE_PHY_NO_TX_PREF_MASK (0x01)
#define BLE_HCI_LE_PHY_NO_RX_PREF_MASK (0x02)
+#define BLE_HCI_LE_PHY_PREF_MASK_ALL \
+ (BLE_HCI_LE_PHY_1M_PREF_MASK | BLE_HCI_LE_PHY_2M_PREF_MASK | \
+ BLE_HCI_LE_PHY_CODED_PREF_MASK)
#define BLE_HCI_LE_PHY_1M_PREF_MASK (0x01)
#define BLE_HCI_LE_PHY_2M_PREF_MASK (0x02)