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 ∁ }