Problem with bt_mesh_resume() - errors -16 and -120

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 &comp;
}

Parents Reply Children
No Data
Related