In some cases the Friendship & Low Power Node features aren't available or feasible, however power saving is nevertheless required. This patch introduces two new APIs to suspend and resume the Mesh network. Currently, what this impacts is the LE scanning, the ability to allocate new outgoing buffers, as well as the model publishing, beacon and heartbeat timers. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
310 lines
6.0 KiB
C
310 lines
6.0 KiB
C
/* Bluetooth Mesh */
|
|
|
|
/*
|
|
* Copyright (c) 2017 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr.h>
|
|
#include <stdbool.h>
|
|
#include <errno.h>
|
|
|
|
#include <net/buf.h>
|
|
#include <bluetooth/bluetooth.h>
|
|
#include <bluetooth/conn.h>
|
|
#include <bluetooth/uuid.h>
|
|
#include <bluetooth/mesh.h>
|
|
|
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG)
|
|
#define LOG_MODULE_NAME bt_mesh_main
|
|
#include "common/log.h"
|
|
|
|
#include "test.h"
|
|
#include "adv.h"
|
|
#include "prov.h"
|
|
#include "net.h"
|
|
#include "beacon.h"
|
|
#include "lpn.h"
|
|
#include "friend.h"
|
|
#include "transport.h"
|
|
#include "access.h"
|
|
#include "foundation.h"
|
|
#include "proxy.h"
|
|
#include "settings.h"
|
|
#include "mesh.h"
|
|
|
|
int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
|
|
u8_t flags, u32_t iv_index, u16_t addr,
|
|
const u8_t dev_key[16])
|
|
{
|
|
bool pb_gatt_enabled;
|
|
int err;
|
|
|
|
BT_INFO("Primary Element: 0x%04x", addr);
|
|
BT_DBG("net_idx 0x%04x flags 0x%02x iv_index 0x%04x",
|
|
net_idx, flags, iv_index);
|
|
|
|
if (atomic_test_and_set_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
|
return -EALREADY;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) {
|
|
if (bt_mesh_proxy_prov_disable() == 0) {
|
|
pb_gatt_enabled = true;
|
|
} else {
|
|
pb_gatt_enabled = false;
|
|
}
|
|
} else {
|
|
pb_gatt_enabled = false;
|
|
}
|
|
|
|
err = bt_mesh_net_create(net_idx, flags, net_key, iv_index);
|
|
if (err) {
|
|
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) && pb_gatt_enabled) {
|
|
bt_mesh_proxy_prov_enable();
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
bt_mesh.seq = 0U;
|
|
|
|
bt_mesh_comp_provision(addr);
|
|
|
|
memcpy(bt_mesh.dev_key, dev_key, 16);
|
|
|
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
BT_DBG("Storing network information persistently");
|
|
bt_mesh_store_net();
|
|
bt_mesh_store_subnet(&bt_mesh.sub[0]);
|
|
bt_mesh_store_iv(false);
|
|
}
|
|
|
|
bt_mesh_net_start();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void bt_mesh_reset(void)
|
|
{
|
|
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
|
return;
|
|
}
|
|
|
|
bt_mesh.iv_index = 0U;
|
|
bt_mesh.seq = 0U;
|
|
|
|
memset(bt_mesh.flags, 0, sizeof(bt_mesh.flags));
|
|
|
|
k_delayed_work_cancel(&bt_mesh.ivu_timer);
|
|
|
|
bt_mesh_cfg_reset();
|
|
|
|
bt_mesh_rx_reset();
|
|
bt_mesh_tx_reset();
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
|
bt_mesh_lpn_disable(true);
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
|
|
bt_mesh_friend_clear_net_idx(BT_MESH_KEY_ANY);
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
|
|
bt_mesh_proxy_gatt_disable();
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
bt_mesh_clear_net();
|
|
}
|
|
|
|
(void)memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key));
|
|
|
|
bt_mesh_scan_disable();
|
|
bt_mesh_beacon_disable();
|
|
|
|
bt_mesh_comp_unprovision();
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PROV)) {
|
|
bt_mesh_prov_reset();
|
|
}
|
|
}
|
|
|
|
bool bt_mesh_is_provisioned(void)
|
|
{
|
|
return atomic_test_bit(bt_mesh.flags, BT_MESH_VALID);
|
|
}
|
|
|
|
int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers)
|
|
{
|
|
if (bt_mesh_is_provisioned()) {
|
|
return -EALREADY;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_DEBUG)) {
|
|
const struct bt_mesh_prov *prov = bt_mesh_prov_get();
|
|
struct bt_uuid_128 uuid = { .uuid.type = BT_UUID_TYPE_128 };
|
|
|
|
memcpy(uuid.val, prov->uuid, 16);
|
|
BT_INFO("Device UUID: %s", bt_uuid_str(&uuid.uuid));
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) &&
|
|
(bearers & BT_MESH_PROV_ADV)) {
|
|
/* Make sure we're scanning for provisioning inviations */
|
|
bt_mesh_scan_enable();
|
|
/* Enable unprovisioned beacon sending */
|
|
bt_mesh_beacon_enable();
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) &&
|
|
(bearers & BT_MESH_PROV_GATT)) {
|
|
bt_mesh_proxy_prov_enable();
|
|
bt_mesh_adv_update();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers)
|
|
{
|
|
if (bt_mesh_is_provisioned()) {
|
|
return -EALREADY;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) &&
|
|
(bearers & BT_MESH_PROV_ADV)) {
|
|
bt_mesh_beacon_disable();
|
|
bt_mesh_scan_disable();
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) &&
|
|
(bearers & BT_MESH_PROV_GATT)) {
|
|
bt_mesh_proxy_prov_disable();
|
|
bt_mesh_adv_update();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void model_suspend(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
|
|
bool vnd, bool primary, void *user_data)
|
|
{
|
|
if (mod->pub && mod->pub->update) {
|
|
mod->pub->count = 0;
|
|
k_delayed_work_cancel(&mod->pub->timer);
|
|
}
|
|
}
|
|
|
|
int bt_mesh_suspend(void)
|
|
{
|
|
int err;
|
|
|
|
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (atomic_test_and_set_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
|
|
return -EALREADY;
|
|
}
|
|
|
|
err = bt_mesh_scan_disable();
|
|
if (err) {
|
|
atomic_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED);
|
|
BT_WARN("Disabling scanning failed (err %d)", err);
|
|
return err;
|
|
}
|
|
|
|
bt_mesh_hb_pub_disable();
|
|
|
|
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) {
|
|
bt_mesh_beacon_disable();
|
|
}
|
|
|
|
bt_mesh_model_foreach(model_suspend, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
|
|
bool vnd, bool primary, void *user_data)
|
|
{
|
|
if (mod->pub && mod->pub->update) {
|
|
s32_t period_ms = bt_mesh_model_pub_period_get(mod);
|
|
|
|
if (period_ms) {
|
|
k_delayed_work_submit(&mod->pub->timer, period_ms);
|
|
}
|
|
}
|
|
}
|
|
|
|
int bt_mesh_resume(void)
|
|
{
|
|
int err;
|
|
|
|
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
|
|
return -EALREADY;
|
|
}
|
|
|
|
err = bt_mesh_scan_enable();
|
|
if (err) {
|
|
BT_WARN("Re-enabling scanning failed (err %d)", err);
|
|
atomic_set_bit(bt_mesh.flags, BT_MESH_SUSPENDED);
|
|
return err;
|
|
}
|
|
|
|
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) {
|
|
bt_mesh_beacon_enable();
|
|
}
|
|
|
|
bt_mesh_model_foreach(model_resume, NULL);
|
|
|
|
return err;
|
|
}
|
|
|
|
int bt_mesh_init(const struct bt_mesh_prov *prov,
|
|
const struct bt_mesh_comp *comp)
|
|
{
|
|
int err;
|
|
|
|
err = bt_mesh_test();
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
err = bt_mesh_comp_register(comp);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PROV)) {
|
|
err = bt_mesh_prov_init(prov);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
}
|
|
|
|
bt_mesh_net_init();
|
|
bt_mesh_trans_init();
|
|
bt_mesh_beacon_init();
|
|
bt_mesh_adv_init();
|
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PROXY)) {
|
|
bt_mesh_proxy_init();
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
bt_mesh_settings_init();
|
|
}
|
|
|
|
return 0;
|
|
}
|