Hi, I'm having an issue with the bt_mesh_resume() function in my project based on Zephyr and Bluetooth Mesh. My code is trying to cycle the Mesh network on and off to save power — it should stay active for 20 seconds and then sleep for 30 seconds. However, when calling bt_mesh_resume(), I encounter the following errors:
- -16 (EBUSY) - It seems something is blocking the Mesh from resuming.
- -120 (ENOMSG) - It appears to be a message-related error in the Mesh communication.
I'm using a modified version of the mesh_chat example, which processes messages without needing UART shell. I want the Mesh to work for a set time after provisioning, without using a Friend node or Low Power node features.
Here is a fragment of my logs:
Waiting for provisioning... [00:00:14.884,521] <inf> bt_mesh_main: Primary Element: 0x007e [00:00:14.884,521] <dbg> bt_mesh_main: bt_mesh_provision: net_idx 0x0000 flags 0x00 iv_index 0x0000 [00:00:14.893,432] <inf> chat: The mesh node is provisioned. The client address is 0x007e. [00:00:14.893,493] <inf> chat: Current presence: available [00:00:15.011,077] <inf> chat: Mesh cycle start Failed to resume Mesh (err -120) [00:00:35.011,169] <err> bt_adv: No valid legacy adv Entering sleep mode
Here is a fragment of my code:
static void exit_sleep(void)
{
int err;
err = bt_mesh_resume();
if (err) {
printk("Failed to resume Mesh (err %d)\n", err);
// I'm considering using bt_mesh_reset() or reinitializing the Mesh.
} else {
mesh_active = true;
set_adv_parameters();
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
printk("Mesh resumed\n");
}
}
Has anyone encountered similar issues? I've tried resetting the Mesh with bt_mesh_reset() and reinitializing it, but it hasn't resolved the problem. I'm using nRF52832 with Zephyr 2.6.1.
Any help would be greatly appreciated!
#include <zephyr/bluetooth/bluetooth.h>
#include <bluetooth/mesh/models.h>
#include <bluetooth/mesh/dk_prov.h>
#include <dk_buttons_and_leds.h>
#include <zephyr/logging/log.h>
#include <zephyr/kernel.h>
#include <nrfx_power.h>
#define SLEEP_TIME K_SECONDS(30) // Czas snu - zwiększony dla oszczędności energii
#define WAKE_TIME K_SECONDS(20) // Krótszy czas aktywności
LOG_MODULE_REGISTER(chat, CONFIG_LOG_DEFAULT_LEVEL);
static bool mesh_active = false;
static void configure_low_power(void)
{
// Konfiguracja niskiego poboru mocy dla nRF52832
NRF_POWER->DCDCEN = 1; // Włączenie przetwornika DC/DC
NRF_POWER->TASKS_LOWPWR = 1; // Przełączenie w tryb niskiego poboru mocy
}
static void set_adv_parameters(void)
{
struct bt_le_adv_param adv_param = {
.options = BT_LE_ADV_OPT_CONNECTABLE,
.interval_min = 160,
.interval_max = 1600,
};
int err = bt_le_adv_start(&adv_param, NULL, 0, NULL, NULL);
if (err) {
printk("Advertising failed to start (err %d)\n", err);
}
}
static void bt_ready(int err)
{
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
configure_low_power();
err = bt_mesh_init(bt_mesh_dk_prov_init(), model_handler_init());
if (err) {
printk("Mesh initialization failed (err %d)\n", err);
return;
}
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
mesh_active = true;
printk("Mesh initialized\n");
}
static void enter_sleep(void)
{
if (!mesh_active) {
return;
}
bt_le_adv_stop();
bt_mesh_suspend();
mesh_active = false;
printk("Entering sleep mode\n");
// Wykorzystanie trybu System OFF dla maksymalnej oszczędności energii
nrf_power_system_off(NRF_POWER);
}
static void exit_sleep(void)
{
configure_low_power();
int err = bt_mesh_resume();
if (err) {
printk("Failed to resume Mesh (err %d)\n", err);
bt_mesh_reset();
bt_ready(0);
} else {
mesh_active = true;
set_adv_parameters();
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
printk("Mesh resumed\n");
}
}
static void enter_sleep(void)
{
if (!mesh_active) {
return;
}
bt_le_adv_stop();
bt_mesh_suspend();
mesh_active = false;
printk("Entering sleep mode\n");
// Zamiast System OFF, używamy deep sleep
k_sleep(SLEEP_TIME);
}
static void exit_sleep(void)
{
configure_low_power();
int err = bt_mesh_resume();
if (err) {
printk("Failed to resume Mesh (err %d)\n", err);
bt_mesh_reset();
bt_ready(0);
} else {
mesh_active = true;
set_adv_parameters();
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
printk("Mesh resumed\n");
}
}
void main(void)
{
int err = bt_enable(bt_ready);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
while (1) {
if (bt_mesh_is_provisioned()) {
LOG_INF("Mesh cycle start\n");
exit_sleep(); // Włączamy mesh
k_sleep(WAKE_TIME);
enter_sleep(); // Wyłączamy mesh
} else {
printk("Waiting for provisioning...\n");
k_sleep(K_MSEC(5000)); // Czekamy 5 sekund przed ponownym sprawdzeniem
}
}
}
#include <stdio.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <bluetooth/mesh/models.h>
#include <dk_buttons_and_leds.h>
#include <zephyr/kernel.h>
#include "sleep_config.h"
#include <zephyr/drivers/gpio.h>
#include "chat_cli.h"
#include "model_handler.h"
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(chat);
#define TIMER_INST_IDX 0
#define TIME_TO_WAIT_MS 5000UL
/******************************************************************************/
/***************************** Chat model setup *******************************/
/******************************************************************************/
struct presence_cache {
uint16_t addr;
enum bt_mesh_chat_cli_presence presence;
};
/* Cache of Presence values of other chat clients. */
static struct presence_cache presence_cache[
CONFIG_BT_MESH_CHAT_SAMPLE_PRESENCE_CACHE_SIZE];
static const uint8_t *presence_string[] = {
[BT_MESH_CHAT_CLI_PRESENCE_AVAILABLE] = "available",
[BT_MESH_CHAT_CLI_PRESENCE_AWAY] = "away",
[BT_MESH_CHAT_CLI_PRESENCE_DO_NOT_DISTURB] = "dnd",
[BT_MESH_CHAT_CLI_PRESENCE_INACTIVE] = "inactive",
};
/**
* Returns true if the specified address is an address of the local element.
*/
static bool address_is_local(const struct bt_mesh_model *mod, uint16_t addr)
{
return bt_mesh_model_elem(mod)->rt->addr == addr;
}
/**
* Returns true if the provided address is unicast address.
*/
static bool address_is_unicast(uint16_t addr)
{
return (addr > 0) && (addr <= 0x7FFF);
}
/**
* Returns true if the node is new or the presence status is different from
* the one stored in the cache.
*/
static bool presence_cache_entry_check_and_update(uint16_t addr,
enum bt_mesh_chat_cli_presence presence)
{
static size_t presence_cache_head;
size_t i;
/* Find address in cache. */
for (i = 0; i < ARRAY_SIZE(presence_cache); i++) {
if (presence_cache[i].addr == addr) {
if (presence_cache[i].presence == presence) {
return false;
}
/* Break since the node in the cache. */
break;
}
}
/* Not in cache. */
if (i == ARRAY_SIZE(presence_cache)) {
for (i = 0; i < ARRAY_SIZE(presence_cache); i++) {
if (!presence_cache[i].addr) {
break;
}
}
/* Cache is full. */
if (i == ARRAY_SIZE(presence_cache)) {
i = presence_cache_head;
presence_cache_head = (presence_cache_head + 1)
% CONFIG_BT_MESH_CHAT_SAMPLE_PRESENCE_CACHE_SIZE;
}
}
/* Update cache. */
presence_cache[i].addr = addr;
presence_cache[i].presence = presence;
return true;
}
static void print_client_status(void);
static void handle_chat_start(struct bt_mesh_chat_cli *chat)
{
print_client_status();
}
static void handle_chat_presence(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
enum bt_mesh_chat_cli_presence presence)
{
if (address_is_local(chat->model, ctx->addr)) {
if (address_is_unicast(ctx->recv_dst)) {
LOG_INF( "<you> are %s",
presence_string[presence]);
}
} else {
if (address_is_unicast(ctx->recv_dst)) {
LOG_INF( "<0x%04X> is %s", ctx->addr,
presence_string[presence]);
} else if (presence_cache_entry_check_and_update(ctx->addr,
presence)) {
LOG_INF( "<0x%04X> is now %s",
ctx->addr,
presence_string[presence]);
}
}
}
static void handle_chat_message(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
const uint8_t *msg)
{
/* Don't print own messages. */
if (address_is_local(chat->model, ctx->addr)) {
return;
}
LOG_INF( "<0x%04X>: %s", ctx->addr, msg);
}
/******************************************************************************/
/********************************Thread config*********************************/
/******************************************************************************/
void temperature_measure(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
const uint8_t *msg)
{
int err;
static uint32_t die_temp;
NRF_TEMP->TASKS_START = 1;//Start temperature measurement
while (NRF_TEMP->EVENTS_DATARDY == 0) {}
NRF_TEMP->EVENTS_DATARDY = 0;//Temperature measurement complete, data ready
die_temp = NRF_TEMP->TEMP ;
NRF_TEMP->TASKS_STOP = 1; //Stop temperature measurement
float temp= (float)die_temp/4;
char tempv2[6];
gcvt(temp,6,tempv2);
char res[30]="Temperatura wynosi: ";
char senddata[60];
sprintf(senddata,"%s %s", res,tempv2);
err = bt_mesh_chat_cli_private_message_send(chat, ctx->addr, senddata);
LOG_INF("Temperatura wynosi: %s \n",tempv2);
if (err) {
LOG_WRN("Failed to publish message: %d", err);
}
}
void temperature_measure_LP(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
const uint8_t *msg)
{
int err;
static uint32_t die_temp;
NRF_TEMP->TASKS_START = 1;//Start temperature measurement
while (NRF_TEMP->EVENTS_DATARDY == 0) {}
NRF_TEMP->EVENTS_DATARDY = 0;//Temperature measurement complete, data ready
die_temp = NRF_TEMP->TEMP ;
NRF_TEMP->TASKS_STOP = 1; //Stop temperature measurement
float temp= (float)die_temp/4;
char tempv2[6];
gcvt(temp,6,tempv2);
char res[30]="Temperatura wynosi: ";
char senddata[60];
sprintf(senddata,"%s %s", res,tempv2);
err = bt_mesh_chat_cli_private_message_send_NACK(chat, ctx->addr, senddata);
LOG_INF("Temperatura wynosi: %s \n",tempv2);
if (err) {
LOG_WRN("Failed to publish message: %d", err);
}
}
volatile bool state=false;
int temp_interval=300;
#define STACK_SIZE 4096
#define PRIORITY 7
#define SLEEP_TIME_MS temp_interval;
k_tid_t my_thread_id;
K_THREAD_STACK_DEFINE(my_thread_stack, STACK_SIZE);
static struct k_thread my_thread_data;
static struct cmd_thread_data {
struct bt_mesh_chat_cli *chat;
struct bt_mesh_msg_ctx *ctx;
const uint8_t *msg;
};
void tempstat_thread(void *arg1, void *arg2, void *arg3);
static int tempstat_on(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
const uint8_t *msg);
static int tempstat_off(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
const uint8_t *msg);
/******************************************************************************/
/***************************** Receiver config ********************************/
/******************************************************************************/
// Send temperature
static int confset_command(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
const uint8_t *msg) {
// Próbujemy sparsować dane przy użyciu sscanf
int interval;
char status;
uint8_t *input=msg;
// Oczekujemy, że format wiadomości będzie: "tconf:<liczba>:<char>"
int result = sscanf(input, "tconf:%d:%c", &interval, &status);
// Sprawdzamy, czy udało się prawidłowo sparsować oba elementy
if (result == 2) {
// Przypisujemy wartość interval do zmiennej temp_interval
temp_interval = interval;
// Sprawdzamy znak 'char' i ustawiamy wartość zmiennej state
if (status == 'y') {
tempstat_on(chat,ctx,msg);
} else if (status == 'n') {
tempstat_off(chat,ctx,msg);
} else {
return -1; // Błędny znak
}
return 1; // Sukces
}
return 0; // Nieprawidłowy format
}
static int tslset_command(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
const uint8_t *msg) {
int interval_sl;
int interval_al;
char status;
uint8_t *input = msg;
int result =sscanf(input, "tsl:%d:%d:%c", &interval_al,&interval_sl,&status);
// Sprawdzamy, czy udało się prawidłowo sparsować oba elementy
if (result == 3) {
// Przypisujemy wartość interval do zmiennej temp_interval
// Sprawdzamy znak 'char' i ustawiamy wartość zmiennej state
if (status == 'y') {
update_sleep_parameters(interval_al,interval_sl,true);
LOG_INF("%d:%d:%d \n",interval_al,interval_sl,true);
} else if (status == 'n') {
update_sleep_parameters(interval_al,interval_sl,false);
LOG_INF("%d:%d:%d \n",interval_al,interval_sl,false);
} else {
return -1; // Błędny znak
}
return 1; // Sukces
}
return 0; // Nieprawidłowy format
}
//Struct for easier command interpretation
struct cmd_react
{
char message[200];
};
static void handle_chat_private_message(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
const uint8_t *msg)
{
struct cmd_react *cmd = (struct cmd_react *)msg;
struct cmd_react start = {"temp_start"};
struct cmd_react stop = {"temp_stop"};
struct cmd_react show = {"tshow"};
LOG_INF("Print temperature 1: %s", start.message);
LOG_INF("Stop printing 2: %s", stop.message);
LOG_INF("Print current config: %s", show.message);
int err;
/* Nie obsługujemy własnych wiadomości */
if (address_is_local(chat->model, ctx->addr)) {
return;
}
/* Odbieramy tylko wiadomości od 0x1000 */
if (ctx->addr == 0x1000) {
/* Komenda start */
if (strncmp((char *)msg, start.message, strlen(start.message)) == 0) {
temperature_measure_LP(chat, ctx, msg);
}
/* Ustawienia konfiguracji */
else if (confset_command(chat,ctx,msg) == 1) {
LOG_INF("Config loaded: %s \n",msg);
}
else if (tslset_command(chat,ctx,msg)==1)
{
LOG_INF("Sleep config loaded:%s \n",msg);
temperature_measure_LP(chat,ctx,msg);
}
/* Pokazanie aktualnej konfiguracji */
else if (strcmp((char *)msg, show.message) == 0) {
char reply_time[200];
sprintf(reply_time, "sconf: %i:%i\n", temp_interval, state ? 1 : 0);
err = bt_mesh_chat_cli_private_message_send(chat, ctx->addr, reply_time);
if (err) {
LOG_WRN("Failed to publish message: %d", err);
}
}
/* Nieznana komenda */
else {
err = bt_mesh_chat_cli_private_message_send(chat, ctx->addr, "Nieznana komenda.");
if (err) {
LOG_WRN("Failed to publish message: %d", err);
}
}
}
LOG_INF("<0x%04X>: you %s", ctx->addr, msg);
}
static void handle_chat_message_reply(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx)
{
LOG_INF( "<0x%04X> received the message", ctx->addr);
}
static const struct bt_mesh_chat_cli_handlers chat_handlers = {
.start = handle_chat_start,
.presence = handle_chat_presence,
.message = handle_chat_message,
.private_message = handle_chat_private_message,
.message_reply = handle_chat_message_reply,
};
/* .. include_startingpoint_model_handler_rst_1 */
static struct bt_mesh_chat_cli chat = {
.handlers = &chat_handlers,
};
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(
1,
BT_MESH_MODEL_LIST(
BT_MESH_MODEL_CFG_SRV,
),
BT_MESH_MODEL_LIST(BT_MESH_MODEL_CHAT_CLI(&chat))),
};
/* .. include_endpoint_model_handler_rst_1 */
static void print_client_status(void)
{
if (!bt_mesh_is_provisioned()) {
LOG_INF(
"The mesh node is not provisioned. Please provision the mesh node before using the chat.");
} else {
LOG_INF(
"The mesh node is provisioned. The client address is 0x%04x.",
bt_mesh_model_elem(chat.model)->rt->addr);
}
LOG_INF( "Current presence: %s",
presence_string[chat.presence]);
}
void tempstat_thread(void *arg1, void *arg2, void *arg3) {
struct cmd_thread_data *data = (struct cmd_thread_data *)arg1;
struct bt_mesh_msg_ctx local_ctx = *data->ctx; // Kopia kontekstu
while (state) {
LOG_INF("Thread running, sending temperature...");
temperature_measure(data->chat, &local_ctx, data->msg);
k_msleep(temp_interval); // Użycie globalnej zmiennej
}
LOG_INF("Temperature status thread stopped.");
}
static int tempstat_on(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
const uint8_t *msg)
{
if (state) {
LOG_INF("Temperature is already being sent.");
return 0;
}
state = true;
LOG_INF("Starting temperature status sending.");
// Używamy dynamicznej alokacji pamięci dla danych wątku
struct cmd_thread_data *data = k_malloc(sizeof(struct cmd_thread_data));
if (data == NULL) {
LOG_ERR("Failed to allocate memory for thread data.");
state = false;
return -ENOMEM;
}
data->chat = chat;
data->ctx = ctx;
data->msg = msg;
// Uruchomienie wątku
my_thread_id = k_thread_create(&my_thread_data, my_thread_stack,
K_THREAD_STACK_SIZEOF(my_thread_stack),
tempstat_thread,
data, NULL, NULL,
PRIORITY, 0, K_NO_WAIT);
if (my_thread_id == NULL) {
LOG_ERR("Failed to create temperature status thread.");
k_free(data);
state = false;
return -ENOMEM;
} else {
LOG_INF("Temperature status thread started.");
}
return 0;
}
static int tempstat_off(struct bt_mesh_chat_cli *chat,
struct bt_mesh_msg_ctx *ctx,
const uint8_t *msg)
{
if (!state) {
LOG_INF("Tempstat is not running!");
return 0;
}
state = false; // Zatrzymanie wątku
k_thread_abort(my_thread_id); // Zatrzymanie wątku
LOG_INF("Tempstat stopped.");
return 0;
}
static const struct bt_mesh_comp comp = {
.cid = CONFIG_BT_COMPANY_ID,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
/******************************************************************************/
/******************************** Public API **********************************/
/******************************************************************************/
const struct bt_mesh_comp *model_handler_init(void)
{
return ∁
}