blob: b3ecf70d13192ab6dbe42fc9caa819ef2c453f57 [file] [log] [blame]
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/printk.h>
#include <settings/settings.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/mesh.h>
static const u16_t net_idx;
static const u16_t app_idx;
static u16_t self_addr = 1, node_addr;
static const u8_t dev_uuid[16] = { 0xdd, 0xdd };
static u8_t node_uuid[16];
K_SEM_DEFINE(sem_unprov_beacon, 0, 1);
K_SEM_DEFINE(sem_node_added, 0, 1);
static struct bt_mesh_cfg_srv cfg_srv = {
.relay = BT_MESH_RELAY_ENABLED,
.beacon = BT_MESH_BEACON_DISABLED,
.frnd = BT_MESH_FRIEND_NOT_SUPPORTED,
.default_ttl = 7,
/* 3 transmissions with 20ms interval */
.net_transmit = BT_MESH_TRANSMIT(2, 20),
.relay_retransmit = BT_MESH_TRANSMIT(3, 20),
};
static struct bt_mesh_cfg_cli cfg_cli = {
};
static void health_current_status(struct bt_mesh_health_cli *cli, u16_t addr,
u8_t test_id, u16_t cid, u8_t *faults,
size_t fault_count)
{
size_t i;
printk("Health Current Status from 0x%04x\n", addr);
if (!fault_count) {
printk("Health Test ID 0x%02x Company ID 0x%04x: no faults\n",
test_id, cid);
return;
}
printk("Health Test ID 0x%02x Company ID 0x%04x Fault Count %zu:\n",
test_id, cid, fault_count);
for (i = 0; i < fault_count; i++) {
printk("\t0x%02x\n", faults[i]);
}
}
static struct bt_mesh_health_cli health_cli = {
.current_status = health_current_status,
};
static struct bt_mesh_model root_models[] = {
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
BT_MESH_MODEL_HEALTH_CLI(&health_cli),
};
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
};
static const struct bt_mesh_comp comp = {
.cid = BT_COMP_ID_LF,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
static void setup_cdb(void)
{
struct bt_mesh_cdb_app_key *key;
key = bt_mesh_cdb_app_key_alloc(net_idx, app_idx);
if (key == NULL) {
printk("Failed to allocate app-key 0x%04x\n", app_idx);
return;
}
bt_rand(key->keys[0].app_key, 16);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_cdb_app_key_store(key);
}
}
static void configure_self(struct bt_mesh_cdb_node *self)
{
struct bt_mesh_cdb_app_key *key;
int err;
printk("Configuring self...\n");
key = bt_mesh_cdb_app_key_get(app_idx);
if (key == NULL) {
printk("No app-key 0x%04x\n", app_idx);
return;
}
/* Add Application Key */
err = bt_mesh_cfg_app_key_add(self->net_idx, self->addr, self->net_idx,
app_idx, key->keys[0].app_key, NULL);
if (err < 0) {
printk("Failed to add app-key (err %d)\n", err);
return;
}
err = bt_mesh_cfg_mod_app_bind(self->net_idx, self->addr, self->addr,
app_idx, BT_MESH_MODEL_ID_HEALTH_CLI,
NULL);
if (err < 0) {
printk("Failed to bind app-key (err %d)\n", err);
return;
}
atomic_set_bit(self->flags, BT_MESH_CDB_NODE_CONFIGURED);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_cdb_node_store(self);
}
printk("Configuration complete\n");
}
static void configure_node(struct bt_mesh_cdb_node *node)
{
struct bt_mesh_cdb_app_key *key;
struct bt_mesh_cfg_mod_pub pub;
u8_t status;
int err;
printk("Configuring node 0x%04x...\n", node->addr);
key = bt_mesh_cdb_app_key_get(app_idx);
if (key == NULL) {
printk("No app-key 0x%04x\n", app_idx);
return;
}
/* Add Application Key */
err = bt_mesh_cfg_app_key_add(net_idx, node->addr, net_idx, app_idx,
key->keys[0].app_key, NULL);
if (err < 0) {
printk("Failed to add app-key (err %d)\n", err);
return;
}
/* Bind to Health model */
err = bt_mesh_cfg_mod_app_bind(net_idx, node->addr, node->addr, app_idx,
BT_MESH_MODEL_ID_HEALTH_SRV, NULL);
if (err < 0) {
printk("Failed to bind app-key (err %d)\n", err);
return;
}
pub.addr = 1;
pub.app_idx = key->app_idx;
pub.cred_flag = false;
pub.ttl = 7;
pub.period = BT_MESH_PUB_PERIOD_10SEC(1);
pub.transmit = 0;
err = bt_mesh_cfg_mod_pub_set(net_idx, node->addr, node->addr,
BT_MESH_MODEL_ID_HEALTH_SRV, &pub,
&status);
if (err < 0) {
printk("mod_pub_set %d, %d\n", err, status);
return;
}
atomic_set_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_cdb_node_store(node);
}
printk("Configuration complete\n");
}
static void unprovisioned_beacon(u8_t uuid[16],
bt_mesh_prov_oob_info_t oob_info,
u32_t *uri_hash)
{
memcpy(node_uuid, uuid, 16);
k_sem_give(&sem_unprov_beacon);
}
static void node_added(u16_t net_idx, u8_t uuid[16], u16_t addr, u8_t num_elem)
{
node_addr = addr;
k_sem_give(&sem_node_added);
}
static const struct bt_mesh_prov prov = {
.uuid = dev_uuid,
.unprovisioned_beacon = unprovisioned_beacon,
.node_added = node_added,
};
static int bt_ready(void)
{
u8_t net_key[16], dev_key[16];
int err;
err = bt_mesh_init(&prov, &comp);
if (err) {
printk("Initializing mesh failed (err %d)\n", err);
return err;
}
printk("Mesh initialized\n");
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
printk("Loading stored settings\n");
settings_load();
}
bt_rand(net_key, 16);
err = bt_mesh_cdb_create(net_key);
if (err == -EALREADY) {
printk("Using stored CDB\n");
} else if (err) {
printk("Failed to create CDB (err %d)\n", err);
return err;
} else {
printk("Created CDB\n");
setup_cdb();
}
bt_rand(dev_key, 16);
err = bt_mesh_provision(net_key, BT_MESH_NET_PRIMARY, 0, 0, self_addr,
dev_key);
if (err == -EALREADY) {
printk("Using stored settings\n");
} else if (err) {
printk("Provisioning failed (err %d)\n", err);
return err;
} else {
printk("Provisioning completed\n");
}
return 0;
}
static u8_t check_unconfigured(struct bt_mesh_cdb_node *node, void *data)
{
if (!atomic_test_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED)) {
if (node->addr == self_addr) {
configure_self(node);
} else {
configure_node(node);
}
}
return BT_MESH_CDB_ITER_CONTINUE;
}
void main(void)
{
char uuid_hex_str[32 + 1];
int err;
printk("Initializing...\n");
/* Initialize the Bluetooth Subsystem */
err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\n");
bt_ready();
while (1) {
k_sem_reset(&sem_unprov_beacon);
k_sem_reset(&sem_node_added);
bt_mesh_cdb_node_foreach(check_unconfigured, NULL);
printk("Waiting for unprovisioned beacon...\n");
err = k_sem_take(&sem_unprov_beacon, K_SECONDS(10));
if (err == -EAGAIN) {
continue;
}
bin2hex(node_uuid, 16, uuid_hex_str, sizeof(uuid_hex_str));
printk("Provisioning %s\n", uuid_hex_str);
err = bt_mesh_provision_adv(node_uuid, net_idx, 0, 0);
if (err < 0) {
printk("Provisioning failed (err %d)\n", err);
continue;
}
printk("Waiting for node to be added...\n");
err = k_sem_take(&sem_node_added, K_SECONDS(10));
if (err == -EAGAIN) {
printk("Timeout waiting for node to be added\n");
continue;
}
printk("Added node 0x%04x\n", node_addr);
}
}