You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2022/04/07 12:18:59 UTC
[mynewt-nimble] 03/04: nimble/ll: Add Connection Subrate Request/Update procedures
This is an automated email from the ASF dual-hosted git repository.
andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 7a79799238e9d9c9d2cc57130f08276b5642e3d1
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Tue Feb 8 16:01:55 2022 +0100
nimble/ll: Add Connection Subrate Request/Update procedures
---
nimble/controller/include/controller/ble_ll_conn.h | 36 +++++
nimble/controller/include/controller/ble_ll_ctrl.h | 5 +-
.../controller/include/controller/ble_ll_utils.h | 4 +
nimble/controller/src/ble_ll.c | 4 +
nimble/controller/src/ble_ll_conn.c | 166 ++++++++++++++++++-
nimble/controller/src/ble_ll_conn_priv.h | 7 +
nimble/controller/src/ble_ll_ctrl.c | 179 +++++++++++++++++++++
7 files changed, 395 insertions(+), 6 deletions(-)
diff --git a/nimble/controller/include/controller/ble_ll_conn.h b/nimble/controller/include/controller/ble_ll_conn.h
index 85f59bcf..a50e6e69 100644
--- a/nimble/controller/include/controller/ble_ll_conn.h
+++ b/nimble/controller/include/controller/ble_ll_conn.h
@@ -132,6 +132,8 @@ union ble_ll_conn_sm_flags {
uint32_t rxd_features:1;
uint32_t pending_hci_rd_features:1;
uint32_t pending_initiate_dle:1;
+ uint32_t subrate_trans:1;
+ uint32_t subrate_ind_txd:1;
} cfbit;
uint32_t conn_flags;
} __attribute__((packed));
@@ -183,6 +185,22 @@ struct hci_conn_update
uint16_t max_ce_len;
};
+struct ble_ll_conn_subrate_params {
+ uint16_t subrate_factor;
+ uint16_t subrate_base_event;
+ uint16_t periph_latency;
+ uint16_t cont_num;
+ uint16_t supervision_tmo;
+};
+
+struct ble_ll_conn_subrate_req_params {
+ uint16_t subrate_min;
+ uint16_t subrate_max;
+ uint16_t max_latency;
+ uint16_t cont_num;
+ uint16_t supervision_tmo;
+};
+
/* Connection state machine */
struct ble_ll_conn_sm
{
@@ -284,10 +302,21 @@ struct ble_ll_conn_sm
uint16_t periph_latency;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ uint16_t acc_subrate_min;
+ uint16_t acc_subrate_max;
+ uint16_t acc_max_latency;
+ uint16_t acc_cont_num;
+ uint16_t acc_supervision_tmo;
+
uint16_t subrate_base_event;
uint16_t subrate_factor;
uint16_t cont_num;
uint16_t last_pdu_event;
+
+ union {
+ struct ble_ll_conn_subrate_params subrate_trans;
+ struct ble_ll_conn_subrate_req_params subrate_req;
+ };
#endif
/*
@@ -464,6 +493,13 @@ void ble_ll_conn_created_on_aux(struct os_mbuf *rxpdu,
uint8_t *targeta);
#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+int ble_ll_conn_subrate_req_llcp(struct ble_ll_conn_sm *connsm,
+ struct ble_ll_conn_subrate_req_params *srp);
+void ble_ll_conn_subrate_set(struct ble_ll_conn_sm *connsm,
+ struct ble_ll_conn_subrate_params *sp);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/nimble/controller/include/controller/ble_ll_ctrl.h b/nimble/controller/include/controller/ble_ll_ctrl.h
index 423d13af..17300dc2 100644
--- a/nimble/controller/include/controller/ble_ll_ctrl.h
+++ b/nimble/controller/include/controller/ble_ll_ctrl.h
@@ -41,7 +41,9 @@ extern "C" {
#define BLE_LL_CTRL_PROC_PHY_UPDATE (9)
#define BLE_LL_CTRL_PROC_SCA_UPDATE (10)
#define BLE_LL_CTRL_PROC_CIS_CREATE (11)
-#define BLE_LL_CTRL_PROC_NUM (12)
+#define BLE_LL_CTRL_PROC_SUBRATE_REQ (12)
+#define BLE_LL_CTRL_PROC_SUBRATE_UPDATE (13)
+#define BLE_LL_CTRL_PROC_NUM (14)
#define BLE_LL_CTRL_PROC_IDLE (255)
/* Checks if a particular control procedure is running */
@@ -307,6 +309,7 @@ int ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm,
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_start(struct ble_ll_conn_sm *connsm, struct os_mbuf *txpdu);
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);
diff --git a/nimble/controller/include/controller/ble_ll_utils.h b/nimble/controller/include/controller/ble_ll_utils.h
index ae8abfb3..16b91a0c 100644
--- a/nimble/controller/include/controller/ble_ll_utils.h
+++ b/nimble/controller/include/controller/ble_ll_utils.h
@@ -19,6 +19,10 @@
#include <stdint.h>
+#define INT16_GT(_a, _b) ((int16_t)((_a) - (_b)) > 0)
+#define INT16_LT(_a, _b) ((int16_t)((_a) - (_b)) < 0)
+#define INT16_LTE(_a, _b) ((int16_t)((_a) - (_b)) <= 0)
+
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_dci_csa2(uint16_t counter, uint16_t chan_id,
diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c
index f7ab7751..b9d9d7b1 100644
--- a/nimble/controller/src/ble_ll.c
+++ b/nimble/controller/src/ble_ll.c
@@ -1943,6 +1943,10 @@ ble_ll_init(void)
features |= BLE_LL_FEAT_ISO_HOST_SUPPORT;
#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ features |= BLE_LL_FEAT_CONN_SUBRATING;
+#endif
+
lldata->ll_supp_features = features;
/* Initialize random number generation */
diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c
index b328296d..4c60c461 100644
--- a/nimble/controller/src/ble_ll_conn.c
+++ b/nimble/controller/src/ble_ll_conn.c
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+#include <errno.h>
#include "syscfg/syscfg.h"
#include "os/os.h"
#include "nimble/ble.h"
@@ -948,6 +949,17 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm)
}
}
#endif
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
+ if (connsm->csmflags.cfbit.subrate_ind_txd) {
+ ble_ll_conn_subrate_set(connsm, &connsm->subrate_trans);
+ connsm->subrate_trans.subrate_factor = 0;
+ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SUBRATE_UPDATE);
+ connsm->csmflags.cfbit.subrate_ind_txd = 0;
+ }
+#endif /* BLE_LL_CTRL_SUBRATE_IND */
+#endif /* BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE */
}
/**
@@ -1109,6 +1121,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm)
pktlen = pkthdr->omp_len;
if (llid == BLE_LL_LLID_CTRL) {
cur_txlen = pktlen;
+ ble_ll_ctrl_tx_start(connsm, m);
} else {
cur_txlen = ble_ll_conn_adjust_pyld_len(connsm, pktlen);
}
@@ -1689,6 +1702,14 @@ ble_ll_conn_central_common_init(struct ble_ll_conn_sm *connsm)
memcpy(connsm->chanmap, g_ble_ll_conn_params.central_chan_map,
BLE_LL_CONN_CHMAP_LEN);
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ connsm->acc_subrate_min = g_ble_ll_conn_params.acc_subrate_min;
+ connsm->acc_subrate_max = g_ble_ll_conn_params.acc_subrate_max;
+ connsm->acc_max_latency = g_ble_ll_conn_params.acc_max_latency;
+ connsm->acc_cont_num = g_ble_ll_conn_params.acc_cont_num;
+ connsm->acc_supervision_tmo = g_ble_ll_conn_params.acc_supervision_tmo;
+#endif
+
/* Calculate random access address and crc initialization value */
connsm->access_addr = ble_ll_utils_calc_access_addr();
connsm->crcinit = ble_ll_rand() & 0xffffff;
@@ -2213,6 +2234,12 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
uint8_t next_is_subrated;
uint16_t subrate_factor;
uint16_t event_cntr_diff;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ struct ble_ll_conn_subrate_params *cstp;
+ uint16_t trans_next_event_cntr;
+ uint16_t subrate_conn_upd_event_cntr;
+#endif
+
/* XXX: deal with connection request procedure here as well */
ble_ll_conn_chk_csm_flags(connsm);
@@ -2272,18 +2299,63 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
if (use_periph_latency) {
next_event_cntr += subrate_factor * connsm->periph_latency;
}
+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
- /* Make this our next base event. This is technically incorrect, because
- * subrate base event is determined by LL_SUBRATE_IND and shall only be
- * changed if counter wrapped, but that does not really matter as once
- * set it's only used internally.
+ /* If we are in subrate transition mode, we should also listen on
+ * subrated connection events based on new parameters.
*/
- connsm->subrate_base_event = next_event_cntr;
+ if (connsm->csmflags.cfbit.subrate_trans) {
+ BLE_LL_ASSERT(CONN_IS_CENTRAL(connsm));
+
+ cstp = &connsm->subrate_trans;
+ trans_next_event_cntr = cstp->subrate_base_event;
+ while (INT16_LTE(trans_next_event_cntr, connsm->event_cntr)) {
+ trans_next_event_cntr += cstp->subrate_factor;
+ }
+ cstp->subrate_base_event = trans_next_event_cntr;
+
+ if (INT16_LT(trans_next_event_cntr, next_event_cntr)) {
+ next_event_cntr = trans_next_event_cntr;
+ next_is_subrated = 0;
+ }
+ }
#endif
} else {
next_event_cntr = connsm->event_cntr + 1;
}
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ /* If connection update is scheduled, peripheral shall listen at instant
+ * and one connection event before instant regardless of subrating.
+ */
+ if (CONN_IS_PERIPHERAL(connsm) &&
+ connsm->csmflags.cfbit.conn_update_sched &&
+ (connsm->subrate_factor > 1)) {
+ subrate_conn_upd_event_cntr = connsm->conn_update_req.instant - 1;
+ if (connsm->event_cntr == subrate_conn_upd_event_cntr) {
+ subrate_conn_upd_event_cntr++;
+ }
+
+ if (INT16_GT(next_event_cntr, subrate_conn_upd_event_cntr)) {
+ next_event_cntr = subrate_conn_upd_event_cntr;
+ next_is_subrated = 0;
+ }
+ }
+
+ /* Set next connection event as a subrate base event if that connection
+ * event is a subrated event, this simplifies calculations later.
+ * Note that according to spec base event should only be changed on
+ * wrap-around, but since we only use this value internally we can use any
+ * valid value.
+ */
+ if (next_is_subrated ||
+ (connsm->subrate_base_event +
+ connsm->subrate_factor == next_event_cntr)) {
+ connsm->subrate_base_event = next_event_cntr;
+ }
+#endif
+
event_cntr_diff = next_event_cntr - connsm->event_cntr;
BLE_LL_ASSERT(event_cntr_diff > 0);
@@ -2339,6 +2411,14 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
connsm->csmflags.cfbit.host_expects_upd_event = 1;
}
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ if (connsm->conn_itvl != upd->interval) {
+ connsm->subrate_base_event = connsm->event_cntr;
+ connsm->subrate_factor = 1;
+ connsm->cont_num = 0;
+ }
+#endif
+
connsm->supervision_tmo = upd->timeout;
connsm->periph_latency = upd->latency;
connsm->tx_win_size = upd->winsize;
@@ -3959,6 +4039,74 @@ err_periph_start:
}
#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+int
+ble_ll_conn_subrate_req_llcp(struct ble_ll_conn_sm *connsm,
+ struct ble_ll_conn_subrate_req_params *srp)
+{
+ BLE_LL_ASSERT(connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL);
+
+ if ((srp->subrate_min < 0x0001) || (srp->subrate_min > 0x01f4) ||
+ (srp->subrate_max < 0x0001) || (srp->subrate_max > 0x01f4) ||
+ (srp->max_latency > 0x01f3) || (srp->cont_num > 0x01f3) ||
+ (srp->supervision_tmo < 0x000a) || (srp->supervision_tmo > 0x0c80)) {
+ return -EINVAL;
+ }
+
+ if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
+ return -EBUSY;
+ }
+
+ if ((srp->max_latency > connsm->acc_max_latency) ||
+ (srp->supervision_tmo > connsm->acc_supervision_tmo) ||
+ (srp->subrate_max < connsm->acc_subrate_min) ||
+ (srp->subrate_min > connsm->acc_subrate_max) ||
+ ((connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS * srp->subrate_min *
+ (srp->max_latency + 1)) * 2 >= srp->supervision_tmo *
+ BLE_HCI_CONN_SPVN_TMO_UNITS * 1000)) {
+ return -EINVAL;
+ }
+
+ connsm->subrate_trans.subrate_factor = min(connsm->acc_subrate_max,
+ srp->subrate_max);
+ connsm->subrate_trans.subrate_base_event = connsm->event_cntr;
+ connsm->subrate_trans.periph_latency = min(connsm->acc_max_latency,
+ srp->max_latency);
+ connsm->subrate_trans.cont_num = min(max(connsm->acc_cont_num,
+ srp->cont_num),
+ connsm->subrate_trans.subrate_factor - 1);
+ connsm->subrate_trans.supervision_tmo = min(connsm->supervision_tmo,
+ srp->supervision_tmo);
+
+ ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_SUBRATE_UPDATE, NULL);
+
+ return 0;
+}
+
+void
+ble_ll_conn_subrate_set(struct ble_ll_conn_sm *connsm,
+ struct ble_ll_conn_subrate_params *sp)
+{
+ int16_t event_cntr_diff;
+ int16_t subrate_events_diff;
+
+ /* Assume parameters were checked by caller */
+
+ connsm->subrate_factor = sp->subrate_factor;
+ connsm->subrate_base_event = sp->subrate_base_event;
+ connsm->periph_latency = sp->periph_latency;
+ connsm->cont_num = sp->cont_num;
+ connsm->supervision_tmo = sp->supervision_tmo;
+
+ /* Let's update subrate base event to "latest" one */
+ event_cntr_diff = connsm->event_cntr - connsm->subrate_base_event;
+ subrate_events_diff = event_cntr_diff / connsm->subrate_factor;
+ connsm->subrate_base_event += connsm->subrate_factor * subrate_events_diff;
+
+ /* TODO send hci event */
+}
+#endif
+
#define MAX_TIME_UNCODED(_maxbytes) \
ble_ll_pdu_tx_time_get(_maxbytes + BLE_LL_DATA_MIC_LEN, \
BLE_PHY_MODE_1M);
@@ -4044,6 +4192,14 @@ ble_ll_conn_module_reset(void)
memset(conn_params->central_chan_map, 0xff, BLE_LL_CONN_CHMAP_LEN - 1);
conn_params->central_chan_map[4] = 0x1f;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ conn_params->acc_subrate_min = 0x0001;
+ conn_params->acc_subrate_max = 0x0001;
+ conn_params->acc_max_latency = 0x0000;
+ conn_params->acc_cont_num = 0x0000;
+ conn_params->acc_supervision_tmo = 0x0c80;
+#endif
+
/* Reset statistics */
STATS_RESET(ble_ll_conn_stats);
diff --git a/nimble/controller/src/ble_ll_conn_priv.h b/nimble/controller/src/ble_ll_conn_priv.h
index 7541f642..c05e1955 100644
--- a/nimble/controller/src/ble_ll_conn_priv.h
+++ b/nimble/controller/src/ble_ll_conn_priv.h
@@ -79,6 +79,13 @@ struct ble_ll_conn_global_params
uint16_t conn_init_max_tx_time_coded;
uint16_t supp_max_tx_time;
uint16_t supp_max_rx_time;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ uint16_t acc_subrate_min;
+ uint16_t acc_subrate_max;
+ uint16_t acc_max_latency;
+ uint16_t acc_cont_num;
+ uint16_t acc_supervision_tmo;
+#endif
#endif
};
extern struct ble_ll_conn_global_params g_ble_ll_conn_params;
diff --git a/nimble/controller/src/ble_ll_ctrl.c b/nimble/controller/src/ble_ll_ctrl.c
index 04b93543..f29d3154 100644
--- a/nimble/controller/src/ble_ll_ctrl.c
+++ b/nimble/controller/src/ble_ll_ctrl.c
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <assert.h>
#include <string.h>
+#include <errno.h>
#include "syscfg/syscfg.h"
#include "nimble/ble.h"
#include "nimble/nimble_opt.h"
@@ -408,7 +409,12 @@ ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld,
* request will actually get sent. We add one more event plus the
* minimum as per the spec of 6 connection events.
*/
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ instant = connsm->subrate_base_event + 6 * connsm->subrate_factor *
+ (connsm->periph_latency + 1);
+#else
instant = connsm->event_cntr + connsm->periph_latency + 6 + 1;
+#endif
/*
* XXX: This should change in the future, but for now we will just
@@ -1144,6 +1150,126 @@ ble_ll_ctrl_rx_sca_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+static void
+ble_ll_ctrl_subrate_req_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld,
+ struct ble_ll_conn_subrate_req_params *srp)
+{
+ put_le16(pyld + 0, srp->subrate_min);
+ put_le16(pyld + 2, srp->subrate_max);
+ put_le16(pyld + 4, srp->max_latency);
+ put_le16(pyld + 6, srp->cont_num);
+ put_le16(pyld + 8, srp->supervision_tmo);
+}
+
+static void
+ble_ll_ctrl_subrate_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld,
+ struct ble_ll_conn_subrate_params *sp)
+{
+ put_le16(pyld + 0, sp->subrate_factor);
+ put_le16(pyld + 2, sp->subrate_base_event);
+ put_le16(pyld + 4, sp->periph_latency);
+ put_le16(pyld + 6, sp->cont_num);
+ put_le16(pyld + 8, sp->supervision_tmo);
+}
+
+static uint8_t
+ble_ll_ctrl_rx_subrate_req(struct ble_ll_conn_sm *connsm, uint8_t *req,
+ uint8_t *rsp)
+{
+ struct ble_ll_conn_subrate_req_params params;
+ struct ble_ll_conn_subrate_req_params *srp = ¶ms;
+ uint8_t err;
+ int rc;
+
+#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL)
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) {
+ return BLE_LL_CTRL_UNKNOWN_RSP;
+ }
+#endif
+
+ if ((ble_ll_read_supp_features() & BLE_LL_FEAT_CONN_SUBRATING_HOST) == 0) {
+ ble_ll_ctrl_rej_ext_ind_make(BLE_LL_CTRL_SUBRATE_REQ,
+ BLE_ERR_UNSUPP_REM_FEATURE, rsp);
+ return BLE_LL_CTRL_REJECT_IND_EXT;
+ }
+
+ srp->subrate_min = get_le16(req + 0);
+ srp->subrate_max = get_le16(req + 2);
+ srp->max_latency = get_le16(req + 4);
+ srp->cont_num = get_le16(req + 6);
+ srp->supervision_tmo = get_le16(req + 8);
+
+ rc = ble_ll_conn_subrate_req_llcp(connsm, srp);
+ if (rc < 0) {
+ if (rc == -EINVAL) {
+ err = BLE_ERR_INV_LMP_LL_PARM;
+ } else if (rc == -ENOTSUP) {
+ err = BLE_ERR_UNSUPP_REM_FEATURE;
+ } else if (rc == -EBUSY) {
+ err = BLE_ERR_DIFF_TRANS_COLL;
+ } else {
+ err = BLE_ERR_UNSPECIFIED;
+ }
+
+ ble_ll_ctrl_rej_ext_ind_make(BLE_LL_CTRL_SUBRATE_REQ, err, rsp);
+
+ return BLE_LL_CTRL_REJECT_IND_EXT;
+ }
+
+ return BLE_ERR_MAX;
+}
+
+static uint8_t
+ble_ll_ctrl_rx_subrate_ind(struct ble_ll_conn_sm *connsm, uint8_t *req,
+ uint8_t *rsp)
+{
+ struct ble_ll_conn_subrate_params params;
+ struct ble_ll_conn_subrate_params *sp = ¶ms;
+ uint32_t t1, t2;
+
+#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) {
+ return BLE_LL_CTRL_UNKNOWN_RSP;
+ }
+#endif
+
+ sp->subrate_factor = get_le16(req + 0);
+ sp->subrate_base_event = get_le16(req + 2);
+ sp->periph_latency = get_le16(req + 4);
+ sp->cont_num = get_le16(req + 6);
+ sp->supervision_tmo = get_le16(req + 8);
+
+ /* This is probably not really useful since we shall apply new parameters
+ * immediately after receiving LL_SUBRATE_IND and central shall apply those
+ * parameters after receiving ack which it already did, so it's too late
+ * here to do anything useful. Let's just send LL_REJECT_EXT_IND anyway just
+ * for debugging purposes and reset to subrate factor of 1 and no latency,
+ * perhaps we can find some connection event from central and send our PDU.
+ */
+ t1 = connsm->conn_itvl * sp->subrate_factor * (sp->periph_latency + 1) *
+ BLE_LL_CONN_ITVL_USECS;
+ t2 = sp->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000 / 2;
+ if ((sp->subrate_factor < 1) || (sp->subrate_factor > 500) ||
+ (sp->cont_num > sp->subrate_factor - 1) ||
+ (sp->subrate_factor * (sp->periph_latency + 1) > 500) || (t1 >= t2)) {
+
+ sp->subrate_factor = 1;
+ sp->subrate_base_event = connsm->event_cntr;
+ sp->periph_latency = 0;
+ sp->cont_num = 0;
+ sp->supervision_tmo = connsm->supervision_tmo;
+
+ return BLE_ERR_MAX;
+ }
+
+ ble_ll_conn_subrate_set(connsm, sp);
+ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SUBRATE_REQ);
+
+ return BLE_ERR_MAX;
+}
+#endif
+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
static uint8_t
ble_ll_ctrl_rx_cis_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
@@ -1865,6 +1991,13 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE);
break;
#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ case BLE_LL_CTRL_PROC_SUBRATE_REQ:
+ /* TODO: send event to host */
+ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SUBRATE_UPDATE);
+ break;
+#endif
+
default:
break;
}
@@ -2376,6 +2509,21 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc, void *data)
opcode = BLE_LL_CTRL_CIS_REQ;
ble_ll_ctrl_cis_create(connsm, ctrdata);
break;
+#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL)
+ case BLE_LL_CTRL_PROC_SUBRATE_REQ:
+ opcode = BLE_LL_CTRL_SUBRATE_REQ;
+ ble_ll_ctrl_subrate_req_make(connsm, ctrdata, &connsm->subrate_req);
+ break;
+#endif
+#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
+ case BLE_LL_CTRL_PROC_SUBRATE_UPDATE:
+ opcode = BLE_LL_CTRL_SUBRATE_IND;
+ ble_ll_ctrl_subrate_ind_make(connsm, ctrdata,
+ &connsm->subrate_trans);
+ break;
+#endif
#endif
default:
BLE_LL_ASSERT(0);
@@ -2840,6 +2988,14 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
case BLE_LL_CTRL_PERIODIC_SYNC_IND:
rsp_opcode = ble_ll_ctrl_rx_periodic_sync_ind(connsm, dptr);
break;
+#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+ case BLE_LL_CTRL_SUBRATE_REQ:
+ rsp_opcode = ble_ll_ctrl_rx_subrate_req(connsm, dptr, rspdata);
+ break;
+ case BLE_LL_CTRL_SUBRATE_IND:
+ rsp_opcode = ble_ll_ctrl_rx_subrate_ind(connsm, dptr, rspdata);
+ break;
#endif
default:
/* Nothing to do here */
@@ -2924,6 +3080,21 @@ ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm, uint8_t rej_opcode,
return rc;
}
+int
+ble_ll_ctrl_tx_start(struct ble_ll_conn_sm *connsm, struct os_mbuf *txpdu)
+{
+ uint8_t opcode;
+
+ opcode = txpdu->om_data[0];
+ switch (opcode) {
+ case BLE_LL_CTRL_SUBRATE_IND:
+ connsm->csmflags.cfbit.subrate_trans = 1;
+ break;
+ }
+
+ return 0;
+}
+
/**
* Called when a Link Layer Control pdu has been transmitted successfully.
* This is called when we have a received a PDU during the ISR.
@@ -3017,6 +3188,14 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm)
ble_ll_ctrl_phy_tx_transition_get(txpdu->om_data[2]);
break;
#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
+#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
+ case BLE_LL_CTRL_SUBRATE_IND:
+ connsm->csmflags.cfbit.subrate_trans = 0;
+ connsm->csmflags.cfbit.subrate_ind_txd = 1;
+ break;
+#endif /* BLE_LL_CTRL_SUBRATE_IND */
+#endif /* BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE */
default:
break;
}