mesh: Move heartbeat to separate module

Encapsulates the Heartbeat state and functionality in a separate
heartbeat module, removing all manipulation of the heartbeat state from
the transport and config server modules.

this is port of 0dc9e5cd9695e4ab403bf13f4d51d84de6a5ebb9
This commit is contained in:
Krzysztof Kopyściński
2020-11-18 13:14:08 +01:00
committed by Łukasz Rymanowski
parent 4435537603
commit c06a03adfc
16 changed files with 665 additions and 456 deletions
+12 -6
View File
@@ -33,8 +33,11 @@ struct bt_mesh_cfg_srv {
uint8_t frnd; /* Friend state */
uint8_t default_ttl; /* Default TTL */
/* Heartbeat Publication */
struct bt_mesh_hb_pub {
/** Heartbeat Publication parameters.
*
* @deprecated in favor of standalone API in bluetooth/mesh/heartbeat.h.
*/
struct {
struct k_delayed_work timer;
uint16_t dst;
@@ -43,10 +46,13 @@ struct bt_mesh_cfg_srv {
uint8_t ttl;
uint16_t feat;
uint16_t net_idx;
} hb_pub;
} hb_pub; /* _deprectated */
/* Heartbeat Subscription */
struct bt_mesh_hb_sub {
/** Heartbeat Subscription parameters.
*
* @deprecated in favor of standalone API in bluetooth/mesh/heartbeat.h.
*/
struct {
int64_t expiry;
uint16_t src;
@@ -57,7 +63,7 @@ struct bt_mesh_cfg_srv {
/* Optional subscription tracking function */
void (*func)(uint8_t hops, uint16_t feat);
} hb_sub;
} hb_sub; /* _deprectated */
};
extern const struct bt_mesh_model_op bt_mesh_cfg_srv_op[];
+2
View File
@@ -286,6 +286,7 @@ void net_buf_reserve(struct os_mbuf *om, size_t reserve);
#define BT_GATT_CCC_NOTIFY BLE_GATT_CHR_PROP_NOTIFY
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
/** 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.
@@ -336,6 +337,7 @@ struct k_delayed_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);
bool k_delayed_work_pending(struct k_delayed_work *w);
void k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms);
int64_t k_uptime_get(void);
uint32_t k_uptime_get_32(void);
+123
View File
@@ -0,0 +1,123 @@
/** @file
* @brief Bluetooth Mesh Heartbeat API.
*/
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BLUETOOTH_MESH_HEARTBEAT_H_
#define _BLUETOOTH_MESH_HEARTBEAT_H_
/**
* @brief Bluetooth Mesh
* @defgroup bt_mesh_heartbeat Bluetooth Mesh Heartbeat
* @ingroup bt_mesh
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/** Heartbeat Publication parameters */
struct bt_mesh_hb_pub {
/** Destination address. */
uint16_t dst;
/** Remaining publish count. */
uint16_t count;
/** Time To Live value. */
uint8_t ttl;
/**
* Bitmap of features that trigger a Heartbeat publication if
* they change. Legal values are @ref BT_MESH_FEAT_RELAY,
* @ref BT_MESH_FEAT_PROXY, @ref BT_MESH_FEAT_FRIEND and
* @ref BT_MESH_FEAT_LOW_POWER.
*/
uint16_t feat;
/** Network index used for publishing. */
uint16_t net_idx;
/** Publication period in seconds. */
uint32_t period;
};
/** Heartbeat Subscription parameters. */
struct bt_mesh_hb_sub {
/** Subscription period in seconds. */
uint32_t period;
/** Remaining subscription time in seconds. */
uint32_t remaining;
/** Source address to receive Heartbeats from. */
uint16_t src;
/** Destination address to received Heartbeats on. */
uint16_t dst;
/** The number of received Heartbeat messages so far. */
uint16_t count;
/**
* Minimum hops in received messages, ie the shortest registered
* path from the publishing node to the subscribing node. A
* Heartbeat received from an immediate neighbor has hop
* count = 1.
*/
uint8_t min_hops;
/**
* Maximum hops in received messages, ie the longest registered
* path from the publishing node to the subscribing node. A
* Heartbeat received from an immediate neighbor has hop
* count = 1.
*/
uint8_t max_hops;
};
/** Heartbeat callback structure */
struct bt_mesh_hb_cb {
/** @brief Receive callback for heartbeats.
*
* Gets called on every received Heartbeat that matches the current
* Heartbeat subscription parameters.
*
* @param sub Current Heartbeat subscription parameters.
* @param hops The number of hops the Heartbeat was received
* with.
* @param feat The feature set of the publishing node. The
* value is a bitmap of @ref BT_MESH_FEAT_RELAY,
* @ref BT_MESH_FEAT_PROXY,
* @ref BT_MESH_FEAT_FRIEND and
* @ref BT_MESH_FEAT_LOW_POWER.
*/
void (*recv)(const struct bt_mesh_hb_sub *sub, uint8_t hops,
uint16_t feat);
/** @brief Subscription end callback for heartbeats.
*
* Gets called when the subscription period ends, providing a summary
* of the received heartbeat messages.
*
* @param sub Current Heartbeat subscription parameters.
*/
void (*sub_end)(const struct bt_mesh_hb_sub *sub);
};
/** @brief Get the current Heartbeat publication parameters.
*
* @param get Heartbeat publication parameters return buffer.
*/
void bt_mesh_hb_pub_get(struct bt_mesh_hb_pub *get);
/** @brief Get the current Heartbeat subscription parameters.
*
* @param get Heartbeat subscription parameters return buffer.
*/
void bt_mesh_hb_sub_get(struct bt_mesh_hb_sub *get);
extern struct bt_mesh_hb_cb hb_cb;
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* _BLUETOOTH_MESH_HEARTBEAT_H_ */
+79 -298
View File
@@ -22,6 +22,7 @@
#include "rpl.h"
#include "lpn.h"
#include "transport.h"
#include "heartbeat.h"
#include "crypto.h"
#include "access.h"
#include "beacon.h"
@@ -643,9 +644,7 @@ static void gatt_proxy_set(struct bt_mesh_model *model,
bt_mesh_adv_update();
if (cfg->hb_pub.feat & BT_MESH_FEAT_PROXY) {
(void)bt_mesh_heartbeat_send(NULL, NULL);
}
bt_mesh_hb_feature_changed(BT_MESH_FEAT_PROXY);
send_status:
send_gatt_proxy_status(model, ctx);
@@ -757,9 +756,7 @@ static void relay_set(struct bt_mesh_model *model,
BT_MESH_TRANSMIT_COUNT(cfg->relay_retransmit),
BT_MESH_TRANSMIT_INT(cfg->relay_retransmit));
if ((cfg->hb_pub.feat & BT_MESH_FEAT_RELAY) && change) {
(void)bt_mesh_heartbeat_send(NULL, NULL);
}
bt_mesh_hb_feature_changed(BT_MESH_FEAT_RELAY);
} else {
BT_WARN("Invalid Relay value 0x%02x", buf->om_data[0]);
goto done;
@@ -1744,18 +1741,6 @@ static void net_key_update(struct bt_mesh_model *model,
send_net_key_status(model, ctx, idx, status);
}
static void hb_pub_disable(struct bt_mesh_cfg_srv *cfg)
{
BT_DBG("");
cfg->hb_pub.dst = BT_MESH_ADDR_UNASSIGNED;
cfg->hb_pub.count = 0;
cfg->hb_pub.ttl = 0;
cfg->hb_pub.period = 0;
k_delayed_work_cancel(&cfg->hb_pub.timer);
}
static void net_key_del(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
@@ -2201,9 +2186,7 @@ static void friend_set(struct bt_mesh_model *model,
}
}
if (cfg->hb_pub.feat & BT_MESH_FEAT_FRIEND) {
(void)bt_mesh_heartbeat_send(NULL, NULL);
}
bt_mesh_hb_feature_changed(BT_MESH_FEAT_FRIEND);
send_status:
send_friend_status(model, ctx);
@@ -2317,17 +2300,6 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
send_krp_status(model, ctx, idx, phase, status);
}
static uint8_t hb_log(uint16_t val)
{
if (!val) {
return 0x00;
} else if (val == 0xffff) {
return 0xff;
} else {
return 32 - __builtin_clz(val);
}
}
static uint8_t hb_pub_count_log(uint16_t val)
{
if (!val) {
@@ -2341,17 +2313,6 @@ static uint8_t hb_pub_count_log(uint16_t val)
}
}
static uint16_t hb_pwr2(uint8_t val, uint8_t sub)
{
if (!val) {
return 0x0000;
} else if (val == 0xff || val == 0x11) {
return 0xffff;
} else {
return (1 << (val - sub));
}
}
struct hb_pub_param {
uint16_t dst;
uint8_t count_log;
@@ -2363,10 +2324,9 @@ struct hb_pub_param {
static void hb_pub_send_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, uint8_t status,
struct hb_pub_param *orig_msg)
const struct bt_mesh_hb_pub *pub)
{
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_PUB_STATUS, 10);
struct bt_mesh_cfg_srv *cfg = model->user_data;
BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status);
@@ -2374,20 +2334,13 @@ static void hb_pub_send_status(struct bt_mesh_model *model,
net_buf_simple_add_u8(msg, status);
if (orig_msg) {
memcpy(net_buf_simple_add(msg, sizeof(*orig_msg)), orig_msg,
sizeof(*orig_msg));
goto send;
}
net_buf_simple_add_le16(msg, pub->dst);
net_buf_simple_add_u8(msg, hb_pub_count_log(pub->count));
net_buf_simple_add_u8(msg, bt_mesh_hb_log(pub->period));
net_buf_simple_add_u8(msg, pub->ttl);
net_buf_simple_add_le16(msg, pub->feat);
net_buf_simple_add_le16(msg, pub->net_idx);
net_buf_simple_add_le16(msg, cfg->hb_pub.dst);
net_buf_simple_add_u8(msg, hb_pub_count_log(cfg->hb_pub.count));
net_buf_simple_add_u8(msg, cfg->hb_pub.period);
net_buf_simple_add_u8(msg, cfg->hb_pub.ttl);
net_buf_simple_add_le16(msg, cfg->hb_pub.feat);
net_buf_simple_add_le16(msg, cfg->hb_pub.net_idx);
send:
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
BT_ERR("Unable to send Heartbeat Publication Status");
}
@@ -2399,9 +2352,13 @@ static void heartbeat_pub_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct bt_mesh_hb_pub pub;
BT_DBG("src 0x%04x", ctx->addr);
hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL);
bt_mesh_hb_pub_get(&pub);
hb_pub_send_status(model, ctx, STATUS_SUCCESS, &pub);
}
static void heartbeat_pub_set(struct bt_mesh_model *model,
@@ -2409,27 +2366,32 @@ static void heartbeat_pub_set(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct hb_pub_param *param = (void *)buf->om_data;
struct bt_mesh_cfg_srv *cfg = model->user_data;
uint16_t dst, feat, idx;
struct bt_mesh_hb_pub pub;
uint8_t status;
BT_DBG("src 0x%04x", ctx->addr);
dst = sys_le16_to_cpu(param->dst);
pub.dst = sys_le16_to_cpu(param->dst);
pub.count = bt_mesh_hb_pwr2(param->count_log);
pub.period = bt_mesh_hb_pwr2(param->period_log);
pub.ttl = param->ttl;
pub.feat = sys_le16_to_cpu(param->feat);
pub.net_idx = sys_le16_to_cpu(param->net_idx);
/* All other address types but virtual are valid */
if (BT_MESH_ADDR_IS_VIRTUAL(dst)) {
if (BT_MESH_ADDR_IS_VIRTUAL(pub.dst)) {
status = STATUS_INVALID_ADDRESS;
goto failed;
goto rsp;
}
if (param->count_log > 0x11 && param->count_log != 0xff) {
status = STATUS_CANNOT_SET;
goto failed;
goto rsp;
}
if (param->period_log > 0x10) {
status = STATUS_CANNOT_SET;
goto failed;
goto rsp;
}
if (param->ttl > BT_MESH_TTL_MAX && param->ttl != BT_MESH_TTL_DEFAULT) {
@@ -2437,84 +2399,32 @@ static void heartbeat_pub_set(struct bt_mesh_model *model,
return;
}
feat = sys_le16_to_cpu(param->feat);
idx = sys_le16_to_cpu(param->net_idx);
if (idx > 0xfff) {
BT_ERR("Invalid NetKeyIndex 0x%04x", idx);
if (pub.net_idx > 0xfff) {
BT_ERR("Invalid NetKeyIndex 0x%04x", pub.net_idx);
return;
}
if (!bt_mesh_subnet_get(idx)) {
status = STATUS_INVALID_NETKEY;
goto failed;
}
cfg->hb_pub.dst = dst;
cfg->hb_pub.period = param->period_log;
cfg->hb_pub.feat = feat & BT_MESH_FEAT_SUPPORTED;
cfg->hb_pub.net_idx = idx;
if (dst == BT_MESH_ADDR_UNASSIGNED) {
hb_pub_disable(cfg);
} else {
/* 2^(n-1) */
cfg->hb_pub.count = hb_pwr2(param->count_log, 1);
cfg->hb_pub.ttl = param->ttl;
BT_DBG("period %u ms", hb_pwr2(param->period_log, 1) * 1000);
/* The first Heartbeat message shall be published as soon
* as possible after the Heartbeat Publication Period state
* has been configured for periodic publishing.
*/
if (param->period_log && param->count_log) {
k_work_submit(&cfg->hb_pub.timer.work);
} else {
k_delayed_work_cancel(&cfg->hb_pub.timer);
}
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_hb_pub();
}
hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL);
return;
failed:
hb_pub_send_status(model, ctx, status, param);
status = bt_mesh_hb_pub_set(&pub);
rsp:
hb_pub_send_status(model, ctx, status, &pub);
}
static void hb_sub_send_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, uint8_t status)
struct bt_mesh_msg_ctx *ctx,
const struct bt_mesh_hb_sub *sub)
{
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_SUB_STATUS, 9);
struct bt_mesh_cfg_srv *cfg = model->user_data;
uint16_t period;
int64_t uptime;
BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status);
uptime = k_uptime_get();
if (uptime > cfg->hb_sub.expiry) {
period = 0;
} else {
period = (cfg->hb_sub.expiry - uptime) / 1000;
}
BT_DBG("src 0x%04x ", ctx->addr);
bt_mesh_model_msg_init(msg, OP_HEARTBEAT_SUB_STATUS);
net_buf_simple_add_u8(msg, status);
net_buf_simple_add_le16(msg, cfg->hb_sub.src);
net_buf_simple_add_le16(msg, cfg->hb_sub.dst);
net_buf_simple_add_u8(msg, hb_log(period));
net_buf_simple_add_u8(msg, hb_log(cfg->hb_sub.count));
net_buf_simple_add_u8(msg, cfg->hb_sub.min_hops);
net_buf_simple_add_u8(msg, cfg->hb_sub.max_hops);
net_buf_simple_add_u8(msg, STATUS_SUCCESS);
net_buf_simple_add_le16(msg, sub->src);
net_buf_simple_add_le16(msg, sub->dst);
net_buf_simple_add_u8(msg, bt_mesh_hb_log(sub->remaining));
net_buf_simple_add_u8(msg, bt_mesh_hb_log(sub->count));
net_buf_simple_add_u8(msg, sub->min_hops);
net_buf_simple_add_u8(msg, sub->max_hops);
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
@@ -2528,92 +2438,58 @@ static void heartbeat_sub_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct bt_mesh_hb_sub sub;
BT_DBG("src 0x%04x", ctx->addr);
hb_sub_send_status(model, ctx, STATUS_SUCCESS);
bt_mesh_hb_sub_get(&sub);
hb_sub_send_status(model, ctx, &sub);
}
static void heartbeat_sub_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct bt_mesh_cfg_srv *cfg = model->user_data;
uint8_t period_log, status;
struct bt_mesh_hb_sub sub;
uint16_t sub_src, sub_dst;
uint8_t sub_period;
int32_t period_ms;
uint32_t period;
BT_DBG("src 0x%04x", ctx->addr);
sub_src = net_buf_simple_pull_le16(buf);
sub_dst = net_buf_simple_pull_le16(buf);
sub_period = net_buf_simple_pull_u8(buf);
period_log = net_buf_simple_pull_u8(buf);
BT_DBG("sub_src 0x%04x sub_dst 0x%04x period 0x%02x",
sub_src, sub_dst, sub_period);
sub_src, sub_dst, period_log);
if (sub_src != BT_MESH_ADDR_UNASSIGNED &&
!BT_MESH_ADDR_IS_UNICAST(sub_src)) {
BT_WARN("Prohibited source address");
if (period_log > 0x11) {
BT_WARN("Prohibited subscription period 0x%02x", period_log);
return;
}
if (BT_MESH_ADDR_IS_VIRTUAL(sub_dst) || BT_MESH_ADDR_IS_RFU(sub_dst) ||
(BT_MESH_ADDR_IS_UNICAST(sub_dst) &&
sub_dst != bt_mesh_primary_addr())) {
BT_WARN("Prohibited destination address");
return;
}
period = bt_mesh_hb_pwr2(period_log);
if (sub_period > 0x11) {
BT_WARN("Prohibited subscription period 0x%02x", sub_period);
return;
}
if (sub_src == BT_MESH_ADDR_UNASSIGNED ||
sub_dst == BT_MESH_ADDR_UNASSIGNED ||
sub_period == 0x00) {
/* Only an explicit address change to unassigned should
* trigger clearing of the values according to
* MESH/NODE/CFG/HBS/BV-02-C.
status = bt_mesh_hb_sub_set(sub_src, sub_dst, period);
if (status != STATUS_SUCCESS) {
/* All errors are caused by invalid packets, which should be
* ignored.
*/
if (sub_src == BT_MESH_ADDR_UNASSIGNED ||
sub_dst == BT_MESH_ADDR_UNASSIGNED) {
cfg->hb_sub.src = BT_MESH_ADDR_UNASSIGNED;
cfg->hb_sub.dst = BT_MESH_ADDR_UNASSIGNED;
cfg->hb_sub.min_hops = BT_MESH_TTL_MAX;
cfg->hb_sub.max_hops = 0;
cfg->hb_sub.count = 0;
}
period_ms = 0;
} else {
cfg->hb_sub.src = sub_src;
cfg->hb_sub.dst = sub_dst;
cfg->hb_sub.min_hops = BT_MESH_TTL_MAX;
cfg->hb_sub.max_hops = 0;
cfg->hb_sub.count = 0;
period_ms = hb_pwr2(sub_period, 1) * 1000;
return;
}
/* Let the transport layer know it needs to handle this address */
bt_mesh_set_hb_sub_dst(cfg->hb_sub.dst);
BT_DBG("period_ms %u", (unsigned) period_ms);
if (period_ms) {
cfg->hb_sub.expiry = k_uptime_get() + period_ms;
} else {
cfg->hb_sub.expiry = 0;
}
hb_sub_send_status(model, ctx, STATUS_SUCCESS);
bt_mesh_hb_sub_get(&sub);
/* MESH/NODE/CFG/HBS/BV-01-C expects the MinHops to be 0x7f after
* disabling subscription, but 0x00 for subsequent Get requests.
*/
if (!period_ms) {
cfg->hb_sub.min_hops = 0;
if (!period_log) {
sub.min_hops = BT_MESH_TTL_MAX;
}
hb_sub_send_status(model, ctx, &sub);
}
const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = {
@@ -2667,59 +2543,6 @@ const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = {
BT_MESH_MODEL_OP_END,
};
static void hb_publish_end_cb(int err, void *cb_data)
{
struct bt_mesh_cfg_srv *cfg = cb_data;
uint16_t period_ms;
period_ms = hb_pwr2(cfg->hb_pub.period, 1) * 1000U;
if (period_ms && cfg->hb_pub.count > 1) {
k_delayed_work_submit(&cfg->hb_pub.timer, K_MSEC(period_ms));
}
if (cfg->hb_pub.count != 0xffff) {
cfg->hb_pub.count--;
}
}
static void hb_publish_start_cb(uint16_t duration, int err, void *cb_data)
{
if (err) {
hb_publish_end_cb(err, cb_data);
}
}
static void hb_publish(struct ble_npl_event *work)
{
static const struct bt_mesh_send_cb publish_cb = {
.start = hb_publish_start_cb,
.end = hb_publish_end_cb,
};
struct bt_mesh_cfg_srv *cfg = ble_npl_event_get_arg(work);
struct bt_mesh_subnet *sub;
int err;
BT_DBG("hb_pub.count: %u", cfg->hb_pub.count);
sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx);
if (!sub) {
BT_ERR("No matching subnet for idx 0x%02x",
cfg->hb_pub.net_idx);
cfg->hb_pub.dst = BT_MESH_ADDR_UNASSIGNED;
return;
}
if (cfg->hb_pub.count == 0) {
return;
}
err = bt_mesh_heartbeat_send(&publish_cb, cfg);
if (err) {
hb_publish_end_cb(err, cfg);
}
}
static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg)
{
if (cfg->relay > 0x02) {
@@ -2745,6 +2568,14 @@ static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg)
return true;
}
static void (*hb_sub_cb)(uint8_t hops, uint16_t features);
struct bt_mesh_hb_cb hb_cb;
static void hb_recv_wrapper(const struct bt_mesh_hb_sub *sub, uint8_t hops, uint16_t features)
{
hb_sub_cb(hops, features);
}
static int cfg_srv_init(struct bt_mesh_model *model)
{
struct bt_mesh_cfg_srv *cfg = model->user_data;
@@ -2768,6 +2599,11 @@ static int cfg_srv_init(struct bt_mesh_model *model)
return -EINVAL;
}
if (cfg->hb_sub.func) {
hb_sub_cb = cfg->hb_sub.func;
hb_cb.recv = hb_recv_wrapper;
}
/*
* Configuration Model security is device-key based and only the local
* device-key is allowed to access this model.
@@ -2786,11 +2622,6 @@ static int cfg_srv_init(struct bt_mesh_model *model)
cfg->gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED;
}
k_delayed_work_init(&cfg->hb_pub.timer, hb_publish);
k_delayed_work_add_arg(&cfg->hb_pub.timer, cfg);
cfg->hb_pub.net_idx = BT_MESH_KEY_UNUSED;
cfg->hb_sub.expiry = 0;
cfg->model = model;
conf = cfg;
@@ -2828,49 +2659,9 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
void bt_mesh_cfg_reset(void)
{
struct bt_mesh_cfg_srv *cfg = conf;
BT_DBG("");
bt_mesh_set_hb_sub_dst(BT_MESH_ADDR_UNASSIGNED);
cfg->hb_sub.src = BT_MESH_ADDR_UNASSIGNED;
cfg->hb_sub.dst = BT_MESH_ADDR_UNASSIGNED;
cfg->hb_sub.expiry = 0;
bt_mesh_model_foreach(mod_reset, NULL);
}
void bt_mesh_heartbeat(uint16_t src, uint16_t dst, uint8_t hops, uint16_t feat)
{
struct bt_mesh_cfg_srv *cfg = conf;
if (src != cfg->hb_sub.src || dst != cfg->hb_sub.dst) {
BT_WARN("No subscription for received heartbeat");
return;
}
if (k_uptime_get() > cfg->hb_sub.expiry) {
BT_WARN("Heartbeat subscription period expired");
return;
}
cfg->hb_sub.min_hops = min(cfg->hb_sub.min_hops, hops);
cfg->hb_sub.max_hops = max(cfg->hb_sub.max_hops, hops);
if (cfg->hb_sub.count < 0xffff) {
cfg->hb_sub.count++;
}
BT_DBG("src 0x%04x dst 0x%04x hops %u min %u max %u count %u", src,
dst, hops, cfg->hb_sub.min_hops, cfg->hb_sub.max_hops,
cfg->hb_sub.count);
if (cfg->hb_sub.func) {
cfg->hb_sub.func(hops, feat);
}
}
uint8_t bt_mesh_net_transmit_get(void)
{
if (conf) {
@@ -2935,16 +2726,6 @@ uint8_t bt_mesh_default_ttl_get(void)
return DEFAULT_TTL;
}
struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void)
{
return &conf->hb_pub;
}
void bt_mesh_hb_pub_disable(void)
{
hb_pub_disable(conf);
}
struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void)
{
return conf;
-4
View File
@@ -128,12 +128,8 @@ struct label {
void bt_mesh_cfg_reset(void);
void bt_mesh_heartbeat(uint16_t src, uint16_t dst, uint8_t hops, uint16_t feat);
void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time);
struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void);
void bt_mesh_hb_pub_disable(void);
struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void);
uint8_t bt_mesh_net_transmit_get(void);
+6
View File
@@ -408,6 +408,12 @@ k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f)
#endif
}
bool
k_delayed_work_pending(struct k_delayed_work *w)
{
return ble_npl_callout_is_active(&w->work);
}
void
k_delayed_work_cancel(struct k_delayed_work *w)
{
+350
View File
@@ -0,0 +1,350 @@
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#define MESH_LOG_MODULE BLE_MESH_HEARTBEAT_LOG
#include "mesh_priv.h"
#include "net.h"
#include "rpl.h"
#include "access.h"
#include "lpn.h"
#include "settings.h"
#include "transport.h"
#include "heartbeat.h"
#include "foundation.h"
#include "mesh/glue.h"
static struct bt_mesh_hb_pub pub;
static struct bt_mesh_hb_sub sub;
static struct k_delayed_work sub_timer;
static struct k_delayed_work pub_timer;
static int64_t sub_remaining(void)
{
if (sub.dst == BT_MESH_ADDR_UNASSIGNED) {
return 0U;
}
return k_delayed_work_remaining_get(&sub_timer) / MSEC_PER_SEC;
}
static void hb_publish_end_cb(int err, void *cb_data)
{
if (pub.period && pub.count > 1) {
k_delayed_work_submit(&pub_timer, K_SECONDS(pub.period));
}
if (pub.count != 0xffff) {
pub.count--;
}
}
static void notify_recv(uint8_t hops, uint16_t feat)
{
sub.remaining = sub_remaining();
if (hb_cb.recv != NULL) {
hb_cb.recv(&sub, hops, feat);
}
}
static void notify_sub_end(void)
{
sub.remaining = 0;
if (hb_cb.sub_end != NULL) {
hb_cb.sub_end(&sub);
}
}
static void sub_end(struct ble_npl_event *work)
{
notify_sub_end();
}
static int heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data)
{
uint16_t feat = 0U;
struct __packed {
uint8_t init_ttl;
uint16_t feat;
} hb;
struct bt_mesh_msg_ctx ctx = {
.net_idx = pub.net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = pub.dst,
.send_ttl = pub.ttl,
};
struct bt_mesh_net_tx tx = {
.sub = bt_mesh_subnet_get(pub.net_idx),
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
.xmit = bt_mesh_net_transmit_get(),
};
/* Do nothing if heartbeat publication is not enabled */
if (pub.dst == BT_MESH_ADDR_UNASSIGNED) {
return 0U;
}
hb.init_ttl = pub.ttl;
if (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED) {
feat |= BT_MESH_FEAT_RELAY;
}
if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) {
feat |= BT_MESH_FEAT_PROXY;
}
if (bt_mesh_friend_get() == BT_MESH_FRIEND_ENABLED) {
feat |= BT_MESH_FEAT_FRIEND;
}
if (bt_mesh_lpn_established()) {
feat |= BT_MESH_FEAT_LOW_POWER;
}
hb.feat = sys_cpu_to_be16(feat);
BT_DBG("InitTTL %u feat 0x%04x", pub.ttl, feat);
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb),
cb, cb_data);
}
static void hb_publish_start_cb(uint16_t duration, int err, void *cb_data)
{
if (err) {
hb_publish_end_cb(err, cb_data);
}
}
static void hb_publish(struct ble_npl_event *work)
{
static const struct bt_mesh_send_cb publish_cb = {
.start = hb_publish_start_cb,
.end = hb_publish_end_cb,
};
struct bt_mesh_subnet *sub;
int err;
BT_DBG("hb_pub.count: %u", pub.count);
sub = bt_mesh_subnet_get(pub.net_idx);
if (!sub) {
BT_ERR("No matching subnet for idx 0x%02x", pub.net_idx);
pub.dst = BT_MESH_ADDR_UNASSIGNED;
return;
}
if (pub.count == 0U) {
return;
}
err = heartbeat_send(&publish_cb, NULL);
if (err) {
hb_publish_end_cb(err, NULL);
}
}
int bt_mesh_hb_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
{
uint8_t init_ttl, hops;
uint16_t feat;
if (buf->om_len < 3) {
BT_ERR("Too short heartbeat message");
return -EINVAL;
}
init_ttl = (net_buf_simple_pull_u8(buf) & 0x7f);
feat = net_buf_simple_pull_be16(buf);
hops = (init_ttl - rx->ctx.recv_ttl + 1);
if (rx->ctx.addr != sub.src || rx->ctx.recv_dst != sub.dst) {
BT_DBG("No subscription for received heartbeat");
return 0;
}
if (!k_delayed_work_pending(&sub_timer)) {
BT_DBG("Heartbeat subscription period expired");
return 0;
}
sub.min_hops = MIN(sub.min_hops, hops);
sub.max_hops = MAX(sub.max_hops, hops);
if (sub.count < 0xffff) {
sub.count++;
}
BT_DBG("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x",
rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops,
(hops == 1U) ? "" : "s", feat);
notify_recv(hops, feat);
return 0;
}
static void pub_disable(void)
{
BT_DBG("");
pub.dst = BT_MESH_ADDR_UNASSIGNED;
pub.count = 0U;
pub.ttl = 0U;
pub.period = 0U;
k_delayed_work_cancel(&pub_timer);
}
uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub)
{
if (!new_pub || new_pub->dst == BT_MESH_ADDR_UNASSIGNED) {
pub_disable();
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
bt_mesh_is_provisioned()) {
bt_mesh_store_hb_pub();
}
return STATUS_SUCCESS;
}
if (!bt_mesh_subnet_get(new_pub->net_idx)) {
BT_ERR("Unknown NetKey 0x%04x", new_pub->net_idx);
return STATUS_INVALID_NETKEY;
}
new_pub->feat &= BT_MESH_FEAT_SUPPORTED;
pub = *new_pub;
if (!bt_mesh_is_provisioned()) {
return STATUS_SUCCESS;
}
/* The first Heartbeat message shall be published as soon as possible
* after the Heartbeat Publication Period state has been configured for
* periodic publishing.
*/
if (pub.period && pub.count) {
k_work_submit(&pub_timer.work);
} else {
k_delayed_work_cancel(&pub_timer);
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_hb_pub();
}
return STATUS_SUCCESS;
}
void bt_mesh_hb_pub_get(struct bt_mesh_hb_pub *get)
{
*get = pub;
}
uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period)
{
if (src != BT_MESH_ADDR_UNASSIGNED && !BT_MESH_ADDR_IS_UNICAST(src)) {
BT_WARN("Prohibited source address");
return STATUS_INVALID_ADDRESS;
}
if (BT_MESH_ADDR_IS_VIRTUAL(dst) || BT_MESH_ADDR_IS_RFU(dst) ||
(BT_MESH_ADDR_IS_UNICAST(dst) && dst != bt_mesh_primary_addr())) {
BT_WARN("Prohibited destination address");
return STATUS_INVALID_ADDRESS;
}
if (period > (1U << 16)) {
BT_WARN("Prohibited subscription period %u s", period);
return STATUS_CANNOT_SET;
}
/* Only an explicit address change to unassigned should trigger clearing
* of the values according to MESH/NODE/CFG/HBS/BV-02-C.
*/
if (src == BT_MESH_ADDR_UNASSIGNED || dst == BT_MESH_ADDR_UNASSIGNED) {
sub.src = BT_MESH_ADDR_UNASSIGNED;
sub.dst = BT_MESH_ADDR_UNASSIGNED;
sub.min_hops = 0U;
sub.max_hops = 0U;
sub.count = 0U;
sub.period = sub.period - sub_remaining();
k_delayed_work_cancel(&sub_timer);
notify_sub_end();
} else if (period) {
sub.src = src;
sub.dst = dst;
sub.min_hops = BT_MESH_TTL_MAX;
sub.max_hops = 0U;
sub.count = 0U;
sub.period = period;
k_delayed_work_submit(&sub_timer, K_SECONDS(period));
} else {
/* Clearing the period should stop heartbeat subscription
* without clearing the parameters, so we can still read them.
*/
sub.period = sub.period - sub_remaining();
k_delayed_work_cancel(&sub_timer);
notify_sub_end();
}
return STATUS_SUCCESS;
}
void bt_mesh_hb_sub_get(struct bt_mesh_hb_sub *get)
{
*get = sub;
get->remaining = sub_remaining();
}
void bt_mesh_hb_feature_changed(uint16_t features)
{
if (pub.dst == BT_MESH_ADDR_UNASSIGNED) {
return;
}
if (!(pub.feat & features)) {
return;
}
heartbeat_send(NULL, NULL);
}
void bt_mesh_hb_init(void)
{
pub.net_idx = BT_MESH_KEY_UNUSED;
k_delayed_work_init(&pub_timer, hb_publish);
k_delayed_work_init(&sub_timer, sub_end);
}
void bt_mesh_hb_start(void)
{
if (pub.count && pub.period) {
BT_DBG("Starting heartbeat publication");
k_work_submit(&pub_timer.work);
}
}
void bt_mesh_hb_suspend(void)
{
k_delayed_work_cancel(&pub_timer);
}
void bt_mesh_hb_resume(void)
{
if (pub.period && pub.count) {
BT_DBG("Starting heartbeat publication");
k_work_submit(&pub_timer.work);
}
}
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "mesh/heartbeat.h"
static inline uint16_t bt_mesh_hb_pwr2(uint8_t val)
{
if (!val) {
return 0x0000;
} else if (val == 0xff || val == 0x11) {
return 0xffff;
} else {
return (1 << (val - 1));
}
}
static inline uint8_t bt_mesh_hb_log(uint32_t val)
{
if (!val) {
return 0x00;
} else if (val == 0xffff) {
return 0xff;
} else {
return 32 - __builtin_clz(val);
}
}
void bt_mesh_hb_init(void);
void bt_mesh_hb_start(void);
void bt_mesh_hb_suspend(void);
void bt_mesh_hb_resume(void);
int bt_mesh_hb_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf);
void bt_mesh_hb_feature_changed(uint16_t features);
uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *hb_pub);
uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period);
+3 -9
View File
@@ -19,6 +19,7 @@
#include "adv.h"
#include "net.h"
#include "transport.h"
#include "heartbeat.h"
#include "access.h"
#include "beacon.h"
#include "foundation.h"
@@ -195,7 +196,6 @@ static int send_friend_clear(void)
static void clear_friendship(bool force, bool disable)
{
struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get();
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
BT_DBG("force %u disable %u", force, disable);
@@ -242,9 +242,7 @@ static void clear_friendship(bool force, bool disable)
*/
lpn->groups_changed = 1;
if (cfg->hb_pub.feat & BT_MESH_FEAT_LOW_POWER) {
(void)bt_mesh_heartbeat_send(NULL, NULL);
}
bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER);
if (disable) {
lpn_set_state(BT_MESH_LPN_DISABLED);
@@ -959,8 +957,6 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
}
if (!lpn->established) {
struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get();
/* This is normally checked on the transport layer, however
* in this state we're also still accepting master
* credentials so we need to ensure the right ones (Friend
@@ -975,9 +971,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
BT_INFO("Friendship established with 0x%04x", lpn->frnd);
if (cfg->hb_pub.feat & BT_MESH_FEAT_LOW_POWER) {
(void)bt_mesh_heartbeat_send(NULL, NULL);
}
bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER);
if (lpn_cb) {
lpn_cb(lpn->frnd, true);
+8 -1
View File
@@ -30,6 +30,7 @@
#include "access.h"
#include "foundation.h"
#include "proxy.h"
#include "heartbeat.h"
#include "shell.h"
#include "mesh_priv.h"
#include "settings.h"
@@ -261,7 +262,7 @@ int bt_mesh_suspend(void)
return err;
}
bt_mesh_hb_pub_disable();
bt_mesh_hb_suspend();
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) {
bt_mesh_beacon_disable();
@@ -303,6 +304,8 @@ int bt_mesh_resume(void)
return err;
}
bt_mesh_hb_resume();
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) {
bt_mesh_beacon_enable();
}
@@ -340,6 +343,7 @@ int bt_mesh_init(uint8_t own_addr_type, const struct bt_mesh_prov *prov,
bt_mesh_net_init();
bt_mesh_trans_init();
bt_mesh_hb_init();
bt_mesh_beacon_init();
bt_mesh_adv_init();
@@ -403,6 +407,9 @@ int bt_mesh_start(void)
bt_mesh_prov_complete(sub->net_idx, addr);
}
bt_mesh_hb_start();
bt_mesh_model_foreach(model_start, NULL);
return 0;
+19 -43
View File
@@ -18,6 +18,7 @@
#include "rpl.h"
#include "crypto.h"
#include "transport.h"
#include "heartbeat.h"
#include "access.h"
#include "foundation.h"
#include "proxy.h"
@@ -420,27 +421,12 @@ static int app_key_set(int argc, char **argv, char *val)
static int hb_pub_set(int argc, char **argv, char *val)
{
struct bt_mesh_hb_pub *pub = bt_mesh_hb_pub_get();
struct bt_mesh_hb_pub pub;
struct hb_pub_val hb_val;
int len, err;
BT_DBG("val %s", val ? val : "(null)");
if (!pub) {
return -ENOENT;
}
if (!val) {
pub->dst = BT_MESH_ADDR_UNASSIGNED;
pub->count = 0;
pub->ttl = 0;
pub->period = 0;
pub->feat = 0;
BT_DBG("Cleared heartbeat publication");
return 0;
}
len = sizeof(hb_val);
err = settings_bytes_from_str(val, &hb_val, &len);
if (err) {
@@ -454,18 +440,20 @@ static int hb_pub_set(int argc, char **argv, char *val)
return -EINVAL;
}
pub->dst = hb_val.dst;
pub->period = hb_val.period;
pub->ttl = hb_val.ttl;
pub->feat = hb_val.feat;
pub->net_idx = hb_val.net_idx;
pub.dst = hb_val.dst;
pub.period = bt_mesh_hb_pwr2(hb_val.period);
pub.ttl = hb_val.ttl;
pub.feat = hb_val.feat;
pub.net_idx = hb_val.net_idx;
if (hb_val.indefinite) {
pub->count = 0xffff;
pub.count = 0xffff;
} else {
pub->count = 0;
pub.count = 0;
}
(void)bt_mesh_hb_pub_set(&pub);
BT_DBG("Restored heartbeat publication");
return 0;
@@ -1032,7 +1020,6 @@ static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
static int mesh_commit(void)
{
struct bt_mesh_hb_pub *hb_pub;
struct bt_mesh_cfg_srv *cfg;
if (!bt_mesh_subnet_next(NULL)) {
@@ -1050,13 +1037,6 @@ static int mesh_commit(void)
bt_mesh_model_foreach(commit_mod, NULL);
hb_pub = bt_mesh_hb_pub_get();
if (hb_pub && hb_pub->dst != BT_MESH_ADDR_UNASSIGNED &&
hb_pub->count && hb_pub->period) {
BT_DBG("Starting heartbeat publication");
k_work_submit(&hb_pub->timer.work);
}
cfg = bt_mesh_cfg_get();
if (cfg && stored_cfg.valid) {
cfg->net_transmit = stored_cfg.cfg.net_transmit;
@@ -1305,24 +1285,20 @@ static void store_pending_rpl(struct bt_mesh_rpl *rpl, void *user_data)
static void store_pending_hb_pub(void)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct hb_pub_val))];
struct bt_mesh_hb_pub *pub = bt_mesh_hb_pub_get();
struct hb_pub_val val;
char *str;
int err;
if (!pub) {
return;
}
if (pub->dst == BT_MESH_ADDR_UNASSIGNED) {
bt_mesh_hb_pub_get(&pub);
if (pub.dst == BT_MESH_ADDR_UNASSIGNED) {
str = NULL;
} else {
val.indefinite = (pub->count == 0xffff);
val.dst = pub->dst;
val.period = pub->period;
val.ttl = pub->ttl;
val.feat = pub->feat;
val.net_idx = pub->net_idx;
val.indefinite = (pub.count == 0xffff);
val.dst = pub.dst;
val.period = bt_mesh_hb_log(pub.period);
val.ttl = pub.ttl;
val.feat = pub.feat;
val.net_idx = pub.net_idx;
str = settings_str_from_bytes(&val, sizeof(val),
buf, sizeof(buf));
+1 -1
View File
@@ -9,7 +9,7 @@
#include <stdint.h>
#include <sys/types.h>
#include "mesh/glue.h"
#define BT_MESH_NET_FLAG_KR BIT(0)
#define BT_MESH_NET_FLAG_IVU BIT(1)
+2 -90
View File
@@ -26,6 +26,7 @@
#include "access.h"
#include "foundation.h"
#include "settings.h"
#include "heartbeat.h"
#include "transport.h"
#include "testing.h"
@@ -116,13 +117,6 @@ K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4);
static struct bt_mesh_va virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT];
static uint16_t hb_sub_dst = BT_MESH_ADDR_UNASSIGNED;
void bt_mesh_set_hb_sub_dst(uint16_t addr)
{
hb_sub_dst = addr;
}
static int send_unseg(struct bt_mesh_net_tx *tx, struct os_mbuf *sdu,
const struct bt_mesh_send_cb *cb, void *cb_data,
const uint8_t *ctl_op)
@@ -860,36 +854,6 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr,
return 0;
}
static int trans_heartbeat(struct bt_mesh_net_rx *rx,
struct os_mbuf *buf)
{
uint8_t init_ttl, hops;
uint16_t feat;
if (buf->om_len < 3) {
BT_ERR("Too short heartbeat message");
return -EINVAL;
}
if (rx->ctx.recv_dst != hb_sub_dst) {
BT_WARN("Ignoring heartbeat to non-subscribed destination");
return 0;
}
init_ttl = (net_buf_simple_pull_u8(buf) & 0x7f);
feat = net_buf_simple_pull_be16(buf);
hops = (init_ttl - rx->ctx.recv_ttl + 1);
BT_DBG("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x",
rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops,
(hops == 1) ? "" : "s", feat);
bt_mesh_heartbeat(rx->ctx.addr, rx->ctx.recv_dst, hops, feat);
return 0;
}
static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr,
struct os_mbuf *buf, uint64_t *seq_auth)
{
@@ -901,7 +865,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr,
case TRANS_CTL_OP_ACK:
return trans_ack(rx, hdr, buf, seq_auth);
case TRANS_CTL_OP_HEARTBEAT:
return trans_heartbeat(rx, buf);
return bt_mesh_hb_recv(rx, buf);
}
/* Only acks and heartbeats may need processing without local_match */
@@ -1636,58 +1600,6 @@ void bt_mesh_trans_init(void)
}
}
int bt_mesh_heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data)
{
struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get();
uint16_t feat = 0U;
struct __packed {
uint8_t init_ttl;
uint16_t feat;
} hb;
struct bt_mesh_msg_ctx ctx = {
.net_idx = cfg->hb_pub.net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = cfg->hb_pub.dst,
.send_ttl = cfg->hb_pub.ttl,
};
struct bt_mesh_net_tx tx = {
.sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx),
.ctx = &ctx,
.src = bt_mesh_model_elem(cfg->model)->addr,
.xmit = bt_mesh_net_transmit_get(),
};
/* Do nothing if heartbeat publication is not enabled */
if (cfg->hb_pub.dst == BT_MESH_ADDR_UNASSIGNED) {
return 0;
}
hb.init_ttl = cfg->hb_pub.ttl;
if (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED) {
feat |= BT_MESH_FEAT_RELAY;
}
if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) {
feat |= BT_MESH_FEAT_PROXY;
}
if (bt_mesh_friend_get() == BT_MESH_FRIEND_ENABLED) {
feat |= BT_MESH_FEAT_FRIEND;
}
if (bt_mesh_lpn_established()) {
feat |= BT_MESH_FEAT_LOW_POWER;
}
hb.feat = sys_cpu_to_be16(feat);
BT_DBG("InitTTL %u feat 0x%04x", cfg->hb_pub.ttl, feat);
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb),
cb, cb_data);
}
struct bt_mesh_va *bt_mesh_va_get(uint16_t index)
{
if (index >= ARRAY_SIZE(virtual_addrs)) {
-4
View File
@@ -89,8 +89,6 @@ struct bt_mesh_va {
uint8_t uuid[16];
};
void bt_mesh_set_hb_sub_dst(uint16_t addr);
bool bt_mesh_tx_in_progress(void);
void bt_mesh_rx_reset(void);
@@ -107,8 +105,6 @@ void bt_mesh_trans_init(void);
void bt_mesh_trans_reset(void);
int bt_mesh_heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data);
struct bt_mesh_va *bt_mesh_va_get(uint16_t index);
struct bt_mesh_va *bt_mesh_va_find(uint8_t uuid[16]);
+13
View File
@@ -722,6 +722,15 @@ syscfg.defs:
Minimum level for the BLE Mesh Replay protection list log.
value: 1
BLE_MESH_HEARTBEAT_LOG_MOD:
description: >
Numeric module ID to use for BLE Mesh Replay protection list messages.
value: 26
BLE_MESH_HEARTBEAT_LOG_LVL:
description: >
Minimum level for the BLE Mesh Replay protection list log.
value: 1
syscfg.logs:
BLE_MESH_LOG:
module: MYNEWT_VAL(BLE_MESH_LOG_MOD)
@@ -791,6 +800,10 @@ syscfg.logs:
module: MYNEWT_VAL(BLE_MESH_PROVISIONER_LOG_MOD)
level: MYNEWT_VAL(BLE_MESH_PROVISIONER_LOG_LVL)
BLE_MESH_HEARTBEAT_LOG:
module: MYNEWT_VAL(BLE_MESH_HEARTBEAT_LOG_MOD)
level: MYNEWT_VAL(BLE_MESH_HEARTBEAT_LOG_LVL)
syscfg.vals.BLE_MESH_SHELL:
BLE_MESH_CFG_CLI: 1
BLE_MESH_HEALTH_CLI: 1
@@ -127,6 +127,13 @@
#define BLE_MESH_PROV_DEVICE_LOG_CRITICAL(...) MODLOG_CRITICAL(24, __VA_ARGS__)
#define BLE_MESH_PROV_DEVICE_LOG_DISABLED(...) MODLOG_DISABLED(24, __VA_ARGS__)
#define BLE_MESH_HEARTBEAT_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_HEARTBEAT_LOG_INFO(...) MODLOG_INFO(25, __VA_ARGS__)
#define BLE_MESH_HEARTBEAT_LOG_WARN(...) MODLOG_WARN(25, __VA_ARGS__)
#define BLE_MESH_HEARTBEAT_LOG_ERROR(...) MODLOG_ERROR(25, __VA_ARGS__)
#define BLE_MESH_HEARTBEAT_LOG_CRITICAL(...) MODLOG_CRITICAL(25, __VA_ARGS__)
#define BLE_MESH_HEARTBEAT_LOG_DISABLED(...) MODLOG_DISABLED(25, __VA_ARGS__)
#define DFLT_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define DFLT_LOG_INFO(...) MODLOG_INFO(0, __VA_ARGS__)
#define DFLT_LOG_WARN(...) MODLOG_WARN(0, __VA_ARGS__)