Bluetooth: Mesh: Use more accurate timing for LPN functions

Update the advertising callback to include the exact duration that we
will be sending out the packet. This is useful since sometimes we want
to use the end point of the advertising as the reference time to count
when some other action should take place.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2017-11-09 16:50:40 +02:00 committed by Johan Hedberg
commit 1d86ef0955
9 changed files with 43 additions and 33 deletions

View file

@ -63,13 +63,13 @@ static const u8_t adv_type[] = {
NET_BUF_POOL_DEFINE(adv_buf_pool, CONFIG_BT_MESH_ADV_BUF_COUNT,
BT_MESH_ADV_DATA_SIZE, sizeof(struct bt_mesh_adv), NULL);
static inline void adv_sent(struct net_buf *buf, int err)
static inline void adv_sent(struct net_buf *buf, u16_t duration, int err)
{
if (BT_MESH_ADV(buf)->busy) {
BT_MESH_ADV(buf)->busy = 0;
if (BT_MESH_ADV(buf)->sent) {
BT_MESH_ADV(buf)->sent(buf, err);
BT_MESH_ADV(buf)->sent(buf, duration, err);
}
}
@ -103,7 +103,7 @@ static inline void adv_send(struct net_buf *buf)
param.own_addr = NULL;
err = bt_le_adv_start(&param, &ad, 1, NULL, 0);
adv_sent(buf, err);
adv_sent(buf, duration, err);
if (err) {
BT_ERR("Advertising failed: err %d", err);
return;

View file

@ -17,7 +17,8 @@ enum bt_mesh_adv_type {
BT_MESH_ADV_BEACON,
};
typedef void (*bt_mesh_adv_func_t)(struct net_buf *buf, int err);
typedef void (*bt_mesh_adv_func_t)(struct net_buf *buf, u16_t duration,
int err);
struct bt_mesh_adv {
bt_mesh_adv_func_t sent;

View file

@ -73,14 +73,14 @@ static void cache_add(u8_t data[21], u16_t net_idx)
memcpy(beacon_cache[net_idx].data, data, 21);
}
static void beacon_complete(struct net_buf *buf, int err)
static void beacon_complete(struct net_buf *buf, u16_t duration, int err)
{
struct bt_mesh_subnet *sub;
BT_DBG("err %d", err);
sub = &bt_mesh.sub[BT_MESH_ADV(buf)->user_data[0]];
sub->beacon_sent = k_uptime_get_32();
sub->beacon_sent = k_uptime_get_32() + duration;
}
void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,

View file

@ -780,7 +780,7 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
}
}
static void buf_sent(struct net_buf *buf, int err)
static void buf_sent(struct net_buf *buf, u16_t duration, int err)
{
struct bt_mesh_friend *frnd = NULL;
int i;
@ -801,11 +801,11 @@ static void buf_sent(struct net_buf *buf, int err)
frnd->pending_buf = 0;
if (frnd->established) {
k_delayed_work_submit(&frnd->timer, frnd->poll_to);
k_delayed_work_submit(&frnd->timer, duration + frnd->poll_to);
BT_DBG("Waiting %u ms for next poll", frnd->poll_to);
} else {
/* Friend offer timeout is 1 second */
k_delayed_work_submit(&frnd->timer, K_SECONDS(1));
k_delayed_work_submit(&frnd->timer, duration + K_SECONDS(1));
BT_DBG("Waiting for first poll");
/* Friend Offer doesn't follow the re-sending semantics */

View file

@ -44,14 +44,13 @@
#define POLL_RETRY_TIMEOUT K_MSEC(100)
#define REQ_ATTEMPTS(lpn) ((lpn)->poll_timeout < K_SECONDS(3) ? 2 : 4)
#define REQ_RETRY_DURATION(lpn) (4 * (LPN_RECV_DELAY + (lpn)->adv_duration + \
(lpn)->recv_win + POLL_RETRY_TIMEOUT))
#define REQ_RETRY_DURATION(lpn) (REQ_ATTEMPTS(lpn) * \
(LPN_RECV_DELAY + (lpn)->recv_win + \
POLL_RETRY_TIMEOUT))
#define POLL_TIMEOUT_MAX(lpn) ((CONFIG_BT_MESH_LPN_POLL_TIMEOUT * 100) - \
REQ_RETRY_DURATION(lpn))
#define POLL_TIMEOUT(lpn) ((CONFIG_BT_MESH_LPN_POLL_TIMEOUT * 100) - \
REQ_RETRY_DURATION(lpn))
#define REQ_ATTEMPTS(lpn) (POLL_TIMEOUT_MAX(lpn) < K_SECONDS(3) ? 2 : 4)
#define CLEAR_ATTEMPTS 2
@ -100,7 +99,7 @@ static inline void lpn_set_state(int state)
static void clear_friendship(bool disable);
static void friend_clear_sent(struct net_buf *buf, int err)
static void friend_clear_sent(struct net_buf *buf, u16_t duration, int err)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
@ -119,7 +118,7 @@ static void friend_clear_sent(struct net_buf *buf, int err)
}
lpn_set_state(BT_MESH_LPN_CLEAR);
k_delayed_work_submit(&bt_mesh.lpn.timer, FRIEND_REQ_TIMEOUT);
k_delayed_work_submit(&lpn->timer, duration + FRIEND_REQ_TIMEOUT);
}
static int send_friend_clear(void)
@ -194,7 +193,7 @@ static void clear_friendship(bool disable)
k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT);
}
static void friend_req_sent(struct net_buf *buf, int err)
static void friend_req_sent(struct net_buf *buf, u16_t duration, int err)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
@ -283,7 +282,7 @@ static inline void group_clear(atomic_t *target, atomic_t *source)
#endif
}
static void req_sent(struct net_buf *buf, int err)
static void req_sent(struct net_buf *buf, u16_t duration, int err)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
@ -299,6 +298,7 @@ static void req_sent(struct net_buf *buf, int err)
}
lpn->req_attempts++;
lpn->adv_duration = duration;
if (lpn->established || IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) {
lpn_set_state(BT_MESH_LPN_RECV_DELAY);
@ -309,7 +309,8 @@ static void req_sent(struct net_buf *buf, int err)
LPN_RECV_DELAY - SCAN_LATENCY);
} else {
k_delayed_work_submit(&lpn->timer,
LPN_RECV_DELAY + lpn->recv_win);
LPN_RECV_DELAY + duration +
lpn->recv_win);
}
}
@ -722,7 +723,8 @@ static void lpn_timeout(struct k_work *work)
break;
case BT_MESH_LPN_REQ_WAIT:
bt_mesh_scan_enable();
k_delayed_work_submit(&lpn->timer, FRIEND_REQ_SCAN);
k_delayed_work_submit(&lpn->timer,
lpn->adv_duration + FRIEND_REQ_SCAN);
lpn_set_state(BT_MESH_LPN_WAIT_OFFER);
break;
case BT_MESH_LPN_WAIT_OFFER:
@ -755,10 +757,11 @@ static void lpn_timeout(struct k_work *work)
clear_friendship(false);
break;
case BT_MESH_LPN_RECV_DELAY:
k_delayed_work_submit(&lpn->timer,
lpn->adv_duration + SCAN_LATENCY +
lpn->recv_win);
bt_mesh_scan_enable();
lpn_set_state(BT_MESH_LPN_WAIT_UPDATE);
k_delayed_work_submit(&lpn->timer,
lpn->recv_win + SCAN_LATENCY);
break;
case BT_MESH_LPN_WAIT_UPDATE:
update_timeout(lpn);
@ -804,12 +807,13 @@ static s32_t poll_timeout(struct bt_mesh_lpn *lpn)
{
/* If we're waiting for segment acks keep polling at high freq */
if (bt_mesh_tx_in_progress()) {
return min(POLL_TIMEOUT(lpn), K_SECONDS(1));
return min(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1));
}
if (lpn->poll_timeout < POLL_TIMEOUT(lpn)) {
if (lpn->poll_timeout < POLL_TIMEOUT_MAX(lpn)) {
lpn->poll_timeout *= 2;
lpn->poll_timeout = min(lpn->poll_timeout, POLL_TIMEOUT(lpn));
lpn->poll_timeout = min(lpn->poll_timeout,
POLL_TIMEOUT_MAX(lpn));
}
BT_DBG("Poll Timeout is %ums", lpn->poll_timeout);
@ -926,7 +930,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
BT_INFO("Friendship established with 0x%04x", lpn->frnd);
/* Set initial poll timeout */
lpn->poll_timeout = min(POLL_TIMEOUT(lpn), K_SECONDS(1));
lpn->poll_timeout = min(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1));
}
friend_response_received(lpn);

View file

@ -841,7 +841,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf,
bt_mesh_elem_find(tx->ctx->addr)) {
net_buf_put(&bt_mesh.local_queue, net_buf_ref(buf));
if (cb) {
cb(buf, 0);
cb(buf, 0, 0);
}
k_work_submit(&bt_mesh.local_work);
} else {

View file

@ -168,6 +168,9 @@ struct bt_mesh_lpn {
/* Previous Friend of this LPN */
u16_t old_friend;
/* Duration reported for last advertising packet */
u16_t adv_duration;
/* Next LPN related action timer */
struct k_delayed_work timer;

View file

@ -188,13 +188,14 @@ static const struct bt_mesh_prov *prov;
static void close_link(u8_t err, u8_t reason);
#if defined(CONFIG_BT_MESH_PB_ADV)
static void buf_sent(struct net_buf *buf, int err)
static void buf_sent(struct net_buf *buf, u16_t duration, int err)
{
if (!link.tx.buf[0]) {
return;
}
k_delayed_work_submit(&link.tx.retransmit, RETRANSMIT_TIMEOUT);
k_delayed_work_submit(&link.tx.retransmit,
duration + RETRANSMIT_TIMEOUT);
}
static void free_segments(void)
@ -266,7 +267,7 @@ static struct net_buf *adv_buf_create(void)
static u8_t pending_ack = XACT_NVAL;
static void ack_complete(struct net_buf *buf, int err)
static void ack_complete(struct net_buf *buf, u16_t duration, int err)
{
BT_DBG("xact %u complete", (u8_t)pending_ack);
pending_ack = XACT_NVAL;

View file

@ -200,11 +200,12 @@ static inline void seg_tx_complete(struct seg_tx *tx, int err)
seg_tx_reset(tx);
}
static void seg_sent(struct net_buf *buf, int err)
static void seg_sent(struct net_buf *buf, u16_t duration, int err)
{
struct seg_tx *tx = &seg_tx[BT_MESH_ADV(buf)->seg.tx_id];
k_delayed_work_submit(&tx->retransmit, SEG_RETRANSMIT_TIMEOUT);
k_delayed_work_submit(&tx->retransmit,
duration + SEG_RETRANSMIT_TIMEOUT);
}
static void seg_tx_send_unacked(struct seg_tx *tx)