Autoprovisioning and autoconfiguring of nRF52840

Hello,

After a lot of efforts I managed to autoprovision and autoconfigure my nrf52840 board (provisioning and configuring inside the software and not through external app).

In particular, I have configured a switch and a led like a client and his server in an element of my node.

All is OK: when I toggle the switch the led goes on/off

But when I try to configure another couple of led/switch I fail.

The file that I use for provisioning is this:

#include "provision.h"
#include <zephyr/logging/log.h>

LOG_MODULE_DECLARE(main);

static const uint8_t net_key[16] = {
	0x6f, 0xea, 0x5b, 0x86, 0x38, 0x45, 0x26, 0xb9,
	0x0e, 0x7b, 0x73, 0x0c, 0x69, 0x94, 0x75, 0x0a,
};

static const uint8_t dev_key[16] = {
	0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01,
	0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01,
};

static const uint8_t first_app_key[16] = {
    // First AppKey
	0x8c, 0x32, 0x9f, 0x41, 0xd1, 0xd2, 0xc2, 0x9f,
	0x5a, 0xb7, 0x09, 0x0c, 0x0b, 0x31, 0x4d, 0x1d,
};

static const uint8_t second_app_key[16] = {
    0x88, 0xed, 0x35, 0xc4, 0x95, 0x01, 0xaf, 0x8a,
	0xce, 0x47, 0xd3, 0x11, 0xbf, 0x77, 0xb4, 0xc1,
};

static const uint8_t third_app_key[16] = {
	0x6a, 0x1a, 0xf1, 0xdb, 0xe8, 0x38, 0xdc, 0xf5,
	0x5c, 0x83, 0xa5, 0x33, 0x35, 0xd2, 0xe9, 0xde,
};

static uint16_t net_idx = 0;
static uint32_t iv_index = 0;
static uint8_t flags;
static bool needs_configuration = false;

uint16_t addr = 0x8000;

void configure()
{
	int res;
	uint8_t status = 0;

	if (needs_configuration)
	{
		if (addr == 0x8000)
		{
			LOG_ERR("Device hasn't been provisioned yet.");
			return;
		}

		LOG_INF("Configuring addr %d...", addr);

		res = bt_mesh_cfg_cli_net_key_add(net_idx, addr, net_idx, net_key, NULL);
		LOG_INF("NetKey %d: res %d, status = %d", net_idx, res, status);

		res = bt_mesh_cfg_cli_app_key_add(net_idx, addr, net_idx, 0, first_app_key, NULL);
		LOG_INF("AppKey 0: res %d, status = %d", res, status);

		res = bt_mesh_cfg_cli_app_key_add(net_idx, addr, net_idx, 1, second_app_key, NULL);
		LOG_INF("AppKey 1: res %d, status = %d", res, status);

		res = bt_mesh_cfg_cli_app_key_add(net_idx, addr, net_idx, 2, third_app_key, NULL);
		LOG_INF("AppKey 2: res %d, status = %d", res, status);

		LOG_INF("Configuration completed");
	}
}

void provision()
{

	int err;
	volatile uint32_t *node_addr  = (volatile uint32_t *) 0x10001080; // address node in UICR
	addr = *node_addr;
	/*err = sys_csrand_get(&addr, 2);
	if (err != 0)
	{
		LOG_ERR("Could not get a random address");
		return;
	}
	else
	{
		addr %= 0x7fff;
	}*/
	
	err = bt_mesh_provision(net_key, net_idx, flags, iv_index, addr, dev_key);
	if (err == -EALREADY)
	{
		LOG_INF("Using stored settings");
	}
	else if (err)
	{
		LOG_ERR("Provisioning failed (err %d)", err);
		return;
	}
	else
	{
		LOG_INF("Provisioning completed");
		// configure(addr);
	}
	needs_configuration = true;
}

Instead the file for configuring switch/led (and also chat in my example) is this:

#include "model_handler.h"
#include <zephyr/logging/log.h>
#include "reset_node.h"

#define BUTTON_IDX 0
#define LED_IDX 0
LOG_MODULE_REGISTER(model_handler, CONFIG_BT_MESH_MODEL_HANDLER_LOG_LEVEL);

/* HEALTH SERVER INIT */
/* Model Pub must be initialized here because the macro is defined as static, therefore it can't be externally defined and included here. */
BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);
/* Model Health srv and srv callbacks must be initialized in the caller file due to a conflict with health_srv.c */
static const struct bt_mesh_health_srv_cb health_srv_cb = {
	.attn_on = attention_on,
	.attn_off = attention_off,
};
static struct bt_mesh_health_srv health_srv = {
	.cb = &health_srv_cb,
};

/* CONFIGURATION CLIENT INIT */
const struct bt_mesh_cfg_cli_cb cfg_cli_cb = {};
struct bt_mesh_cfg_cli cli_data = {
	.cb = &cfg_cli_cb};

/* ELEMENTS */
static struct bt_mesh_elem elements[] = {
	BT_MESH_ELEM(1,
				 BT_MESH_MODEL_LIST(
					 BT_MESH_MODEL_CFG_SRV,
					 BT_MESH_MODEL_CFG_CLI(&cli_data),
					 BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
					 BT_MESH_MODEL_DFD_SRV(&dfd_srv),
					 BT_MESH_MODEL_ONOFF_CLI(&buttons[BUTTON_IDX].client),
					 BT_MESH_MODEL_ONOFF_SRV(&led_ctx[LED_IDX].srv)),
				 BT_MESH_MODEL_LIST(
					 BT_MESH_MODEL_CHAT_CLI(&chat))),
	BT_MESH_ELEM(2,
				 BT_MESH_MODEL_LIST(
					 BT_MESH_MODEL_DFU_SRV(&dfu_srv)),
				 BT_MESH_MODEL_NONE),
};

/* COMPOSITION */
static const struct bt_mesh_comp comp = {
	.cid = CONFIG_BT_COMPANY_ID,
	.elem = elements,
	.elem_count = ARRAY_SIZE(elements),
};

const struct bt_mesh_comp *model_handler_init(void)
{
	dk_button_handler_add(&button_handler);
	dk_button_handler_add(&reset_handler);

	// health_k_work_init_delayable();
#ifdef CONFIG_MODEL_CHAT_SHELL
	chat_k_work_init_delayable();
#endif
	return &comp;
}

/**********************************************************************************/
/****************************** App Key Callbacks *********************************/
/**********************************************************************************/
#include <../subsys/bluetooth/mesh/mesh.h>

void on_app_key_added(uint16_t app_idx, uint16_t net_idx)
{
	int res;
	uint8_t status = 0;
	const struct bt_mesh_elem *elem;
	uint16_t addr;
	uint16_t elem_addr;

	switch (app_idx)
	{
	// Chat Vendor Model
	case (0):
	{
		elem = bt_mesh_model_elem(chat.model);
		addr = elem->rt->addr - elem->loc + 1;
		elem_addr = addr + elem->loc - 1;

		uint16_t sub_addr = 0xc000;
		struct bt_mesh_cfg_cli_mod_pub pub = {
			.addr = sub_addr,
			.app_idx = app_idx,
			.ttl = CONFIG_BT_MESH_DEFAULT_TTL,
			.transmit = BT_MESH_TRANSMIT(0, 10),
		};

		LOG_INF("addr = %d - elem_addr = %d - net_idx = %d - app_idx = %d", addr, elem_addr, net_idx, app_idx);
		res = bt_mesh_cfg_cli_mod_app_bind_vnd(net_idx, addr, elem_addr, app_idx, BT_MESH_CHAT_CLI_VENDOR_MODEL_ID, BT_MESH_CHAT_CLI_VENDOR_COMPANY_ID, NULL);
		LOG_INF("bind res = %d, status = %d", res, status);
		status = 0;
		res = bt_mesh_cfg_cli_mod_pub_set_vnd(net_idx, addr, elem_addr, BT_MESH_CHAT_CLI_VENDOR_MODEL_ID, BT_MESH_CHAT_CLI_VENDOR_COMPANY_ID, &pub, NULL);
		LOG_INF("pub res = %d, status = %d", res, status);
		status = 0;
		res = bt_mesh_cfg_cli_mod_sub_add_vnd(net_idx, addr, elem_addr, sub_addr, BT_MESH_CHAT_CLI_VENDOR_MODEL_ID, BT_MESH_CHAT_CLI_VENDOR_COMPANY_ID, NULL);
		LOG_INF("sub res = %d, status = %d", res, status);

		break;
	}
	// Light switch and Light server models
	case (1):
	{
		elem = bt_mesh_model_elem(led_ctx[LED_IDX].srv.model);
		addr = elem->rt->addr - elem->loc + 1;
		elem_addr = addr + elem->loc - 1;
		uint16_t sub_addr = 0xc001;

		LOG_INF("addr = %d - elem_addr = %d - net_idx = %d - app_idx = %d", addr, elem_addr, net_idx, app_idx);
		res = bt_mesh_cfg_cli_mod_app_bind(net_idx, addr, elem_addr, app_idx, BT_MESH_MODEL_ID_GEN_ONOFF_SRV, NULL);
		LOG_INF("bind res = %d.", res);
		res = bt_mesh_cfg_cli_mod_sub_add(net_idx, addr, elem_addr, sub_addr, BT_MESH_MODEL_ID_GEN_ONOFF_SRV, NULL);
		LOG_INF("sub res = %d.", res);

		elem = bt_mesh_model_elem(buttons[BUTTON_IDX].client.model);
		addr = elem->rt->addr - elem->loc + 1;
		elem_addr = addr + elem->loc - 1;
		struct bt_mesh_cfg_cli_mod_pub pub = {
			.addr = sub_addr,
			.app_idx = app_idx,
			.ttl = CONFIG_BT_MESH_DEFAULT_TTL,
			.transmit = BT_MESH_TRANSMIT(1, 10),
		};

		LOG_INF("addr = %d - elem_addr = %d - net_idx = %d - app_idx = %d", addr, elem_addr, net_idx, app_idx);
		res = bt_mesh_cfg_cli_mod_app_bind(net_idx, addr, elem_addr, app_idx, BT_MESH_MODEL_ID_GEN_ONOFF_CLI, NULL);
		LOG_INF("bind res = %d.", res);
		res = bt_mesh_cfg_cli_mod_pub_set(net_idx, addr, elem_addr, BT_MESH_MODEL_ID_GEN_ONOFF_CLI, &pub, NULL);
		LOG_INF("pub res = %d.", res);
		break;
	}
	// DFU and DFD
	case (2):
	{

		elem = bt_mesh_model_elem(dfd_srv.mod);
		addr = elem->rt->addr - elem->loc + 1;
		elem_addr = addr + elem->loc - 1;
		LOG_INF("addr = %d - elem_addr = %d - net_idx = %d - app_idx = %d", addr, elem_addr, net_idx, app_idx);
		res = bt_mesh_cfg_cli_mod_app_bind(net_idx, addr, elem_addr, app_idx, BT_MESH_MODEL_ID_BLOB_CLI, NULL);
		LOG_INF("bind res = %d, status = %d", res, status);
		LOG_INF("addr = %d - elem_addr = %d - net_idx = %d - app_idx = %d", addr, elem_addr, net_idx, app_idx);
		res = bt_mesh_cfg_cli_mod_app_bind(net_idx, addr, elem_addr, app_idx, BT_MESH_MODEL_ID_DFU_CLI, NULL);
		LOG_INF("bind res = %d, status = %d", res, status);
		LOG_INF("addr = %d - elem_addr = %d - net_idx = %d - app_idx = %d", addr, elem_addr, net_idx, app_idx);
		res = bt_mesh_cfg_cli_mod_app_bind(net_idx, addr, elem_addr, app_idx, BT_MESH_MODEL_ID_BLOB_SRV, NULL);
		LOG_INF("bind res = %d, status = %d", res, status);
		LOG_INF("addr = %d - elem_addr = %d - net_idx = %d - app_idx = %d", addr, elem_addr, net_idx, app_idx);
		res = bt_mesh_cfg_cli_mod_app_bind(net_idx, addr, elem_addr, app_idx, BT_MESH_MODEL_ID_DFD_SRV, NULL);
		LOG_INF("bind res = %d, status = %d", res, status);

		elem = bt_mesh_model_elem(dfu_srv.mod);
		addr = elem->rt->addr - elem->loc + 1;
		elem_addr = addr + elem->loc - 1;
		LOG_INF("addr = %d - elem_addr = %d - net_idx = %d - app_idx = %d", addr, elem_addr, net_idx, app_idx);
		res = bt_mesh_cfg_cli_mod_app_bind(net_idx, addr, elem_addr, app_idx, BT_MESH_MODEL_ID_BLOB_SRV, NULL);
		LOG_INF("bind res = %d, status = %d", res, status);
		LOG_INF("addr = %d - elem_addr = %d - net_idx = %d - app_idx = %d", addr, elem_addr, net_idx, app_idx);
		res = bt_mesh_cfg_cli_mod_app_bind(net_idx, addr, elem_addr, app_idx, BT_MESH_MODEL_ID_DFU_SRV, NULL);
		LOG_INF("bind res = %d, status = %d", res, status);

		break;
	}

	default:
	{
		LOG_ERR("Unforseen AppKey idx %d", app_idx);
	}
	}
}

void on_app_key_event(uint16_t app_idx, uint16_t net_idx, enum bt_mesh_key_evt evt)
{
	switch (evt)
	{
	case BT_MESH_KEY_ADDED:
	{

		on_app_key_added(app_idx, net_idx);

		break;
	}
	case BT_MESH_KEY_DELETED:
	{

		break;
	}
	case BT_MESH_KEY_UPDATED:
	{

		break;
	}
	case BT_MESH_KEY_SWAPPED:
	{

		break;
	}
	case BT_MESH_KEY_REVOKED:
	{

		break;
	}
	}

	// LOG_INF("AppKey event: AppIDX=%d - NetIDX=%d - evt=%d", app_idx, net_idx, evt);
}

BT_MESH_APP_KEY_CB_DEFINE(on_app_key_event);

What have I to do for adding another couple of switch/led (client/server), so that when I toggle the second switch the second led goes on/off?

I'm ready to add other information if these can permit you to resolve.

Thank you in advance for your replay

Related