| /* |
| * 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); |
| } |
| } |