Hi,
I tried a light-switch example from SDK for mesh ver 4.1.0 on two nRF52840 DKs(first board with client and the second with server). I configured them with nRF Mesh app from Android and the example is works without problems.
But now, I am trying to modify the example to send a message from client to second client. I put all functions and headers included from main server in main client like in the code I inserted it:
#include <stdint.h> #include <string.h> /* HAL */ #include "boards.h" #include "simple_hal.h" #include "app_timer.h" /* Core */ #include "nrf_mesh_config_core.h" #include "nrf_mesh_gatt.h" #include "nrf_mesh_configure.h" #include "nrf_mesh.h" #include "mesh_stack.h" #include "device_state_manager.h" #include "access_config.h" #include "proxy.h" //new from server /* Provisioning and configuration */ #include "mesh_provisionee.h" #include "mesh_app_utils.h" /* Models */ #include "generic_onoff_client.h" #include "generic_onoff_server.h" //new from server /* Logging and RTT */ #include "log.h" #include "rtt_input.h" /* Example specific includes */ #include "app_config.h" #include "nrf_mesh_config_examples.h" #include "light_switch_example_common.h" #include "example_common.h" #include "app_onoff.h" //new from server #include "ble_softdevice_support.h" /***************************************************************************** * Definitions *****************************************************************************/ #define APP_STATE_OFF (0) #define APP_STATE_ON (1) #define VAL_LIGHT (15) #define APP_UNACK_MSG_REPEAT_COUNT (2) /* Controls if the model instance should force all mesh messages to be segmented messages. */ #define APP_FORCE_SEGMENTATION (false) /* Controls the MIC size used by the model instance for sending the mesh messages. */ #define APP_MIC_SIZE (NRF_MESH_TRANSMIC_SIZE_SMALL) /* Delay value used by the OnOff client for sending OnOff Set messages. */ #define APP_ONOFF_DELAY_MS (50) /* Transition time value used by the OnOff client for sending OnOff Set messages. */ #define APP_ONOFF_TRANSITION_TIME_MS (100) #define LED_TEST (BSP_LED_3) /////////////////////////////////////////////////////////////////new from server #define ONOFF_SERVER_0_LED (BSP_LED_0) #define APP_ONOFF_ELEMENT_INDEX (0) ///////////////////////////////////////////////////////////////// /***************************************************************************** * Forward declaration of static functions *****************************************************************************/ static void app_gen_onoff_client_publish_interval_cb(access_model_handle_t handle, void * p_self); static void app_generic_onoff_client_status_cb(const generic_onoff_client_t * p_self, const access_message_rx_meta_t * p_meta, const generic_onoff_status_params_t * p_in); static void app_gen_onoff_client_transaction_status_cb(access_model_handle_t model_handle, void * p_args, access_reliable_status_t status); ////////////////////////////////////////////////////////////////////////////////////////////new from server //static void app_onoff_server_set_cb(const app_onoff_server_t * p_server, bool onoff); //static void app_onoff_server_get_cb(const app_onoff_server_t * p_server, bool * p_present_onoff); //static void app_onoff_server_transition_cb(const app_onoff_server_t * p_server, // uint32_t transition_time_ms, bool target_onoff); static void app_onoff_server_set_cb(const app_onoff_server_t * p_server, uint32_t light); static void app_onoff_server_get_cb(const app_onoff_server_t * p_server, uint32_t * p_present_onoff); static void app_onoff_server_transition_cb(const app_onoff_server_t * p_server, uint32_t transition_time_ms, bool target_onoff); //////////////////////////////////////////////////////////////////////////////////////////// /***************************************************************************** * Static variables *****************************************************************************/ static generic_onoff_client_t m_clients[CLIENT_MODEL_INSTANCE_COUNT]; static bool m_device_provisioned; ////////////////////////////////////////////////////////////////////////////////////////////new from server /* Generic OnOff server structure definition and initialization */ APP_ONOFF_SERVER_DEF(m_onoff_server_0, APP_FORCE_SEGMENTATION, APP_MIC_SIZE, app_onoff_server_set_cb, app_onoff_server_get_cb, app_onoff_server_transition_cb) /* Callback for updating the hardware state */ //static void app_onoff_server_set_cb(const app_onoff_server_t * p_server, bool onoff) //{ // /* Resolve the server instance here if required, this example uses only 1 instance. */ // // __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting GPIO value: %d\n", onoff) // // hal_led_pin_set(ONOFF_SERVER_0_LED, onoff); //} static void app_onoff_server_set_cb(const app_onoff_server_t * p_server, uint32_t light) { /* Resolve the server instance here if required, this example uses only 1 instance. */ __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Value for light from client: %u\n", light) //hal_led_pin_set(ONOFF_SERVER_0_LED, onoff); } /* Callback for reading the hardware state */ static void app_onoff_server_get_cb(const app_onoff_server_t * p_server, uint32_t * p_present_onoff) { /* Resolve the server instance here if required, this example uses only 1 instance. */ //*p_present_onoff = hal_led_pin_get(ONOFF_SERVER_0_LED); } /* Callback for updating the hardware state */ static void app_onoff_server_transition_cb(const app_onoff_server_t * p_server, uint32_t transition_time_ms, bool target_onoff) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Transition time: %d, Target OnOff: %d\n", transition_time_ms, target_onoff); } static void app_model_init(void) { /* Instantiate onoff server on element index APP_ONOFF_ELEMENT_INDEX */ //ERROR_CHECK(app_onoff_init(&m_onoff_server_0, APP_ONOFF_ELEMENT_INDEX)); //orig //ERROR_CHECK(simple_on_off_server_init(&m_onoff_server_0, APP_ONOFF_ELEMENT_INDEX)); __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "App OnOff Model Handle: %d\n", m_onoff_server_0.server.model_handle); } //////////////////////////////////////////////////////////////////////////////////////////// const generic_onoff_client_callbacks_t client_cbs = { .onoff_status_cb = app_generic_onoff_client_status_cb, .ack_transaction_status_cb = app_gen_onoff_client_transaction_status_cb, .periodic_publish_cb = app_gen_onoff_client_publish_interval_cb }; static void device_identification_start_cb(uint8_t attention_duration_s) { hal_led_mask_set(LEDS_MASK, false); hal_led_blink_ms(BSP_LED_2_MASK | BSP_LED_3_MASK, LED_BLINK_ATTENTION_INTERVAL_MS, LED_BLINK_ATTENTION_COUNT(attention_duration_s)); } static void provisioning_aborted_cb(void) { hal_led_blink_stop(); } static void unicast_address_print(void) { dsm_local_unicast_address_t node_address; dsm_local_unicast_addresses_get(&node_address); __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node Address: 0x%04x \n", node_address.address_start); } static void provisioning_complete_cb(void) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Successfully provisioned\n"); #if MESH_FEATURE_GATT_ENABLED /* Restores the application parameters after switching from the Provisioning * service to the Proxy */ gap_params_init(); conn_params_init(); #endif unicast_address_print(); hal_led_blink_stop(); hal_led_mask_set(LEDS_MASK, LED_MASK_STATE_OFF); hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_PROV); } /* This callback is called periodically if model is configured for periodic publishing */ static void app_gen_onoff_client_publish_interval_cb(access_model_handle_t handle, void * p_self) { __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "Publish desired message here.\n"); } /* Acknowledged transaction status callback, if acknowledged transfer fails, application can * determine suitable course of action (e.g. re-initiate previous transaction) by using this * callback. */ static void app_gen_onoff_client_transaction_status_cb(access_model_handle_t model_handle, void * p_args, access_reliable_status_t status) { switch(status) { case ACCESS_RELIABLE_TRANSFER_SUCCESS: __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Acknowledged transfer success.\n"); break; case ACCESS_RELIABLE_TRANSFER_TIMEOUT: hal_led_blink_ms(LEDS_MASK, LED_BLINK_SHORT_INTERVAL_MS, LED_BLINK_CNT_NO_REPLY); __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Acknowledged transfer timeout.\n"); break; case ACCESS_RELIABLE_TRANSFER_CANCELLED: __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Acknowledged transfer cancelled.\n"); break; default: ERROR_CHECK(NRF_ERROR_INTERNAL); break; } } /* Generic OnOff client model interface: Process the received status message in this callback */ static void app_generic_onoff_client_status_cb(const generic_onoff_client_t * p_self, const access_message_rx_meta_t * p_meta, const generic_onoff_status_params_t * p_in) { if (p_in->remaining_time_ms > 0) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "OnOff server: 0x%04x, Present OnOff: %d, Target OnOff: %d, Remaining Time: %d ms\n", p_meta->src.value, p_in->present_on_off, p_in->target_on_off, p_in->remaining_time_ms); } else { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "OnOff server: 0x%04x, Present OnOff: %d\n", p_meta->src.value, p_in->present_on_off); } } static void node_reset(void) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- Node reset -----\n"); hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_RESET); /* This function may return if there are ongoing flash operations. */ mesh_stack_device_reset(); } static void config_server_evt_cb(const config_server_evt_t * p_evt) { if (p_evt->type == CONFIG_SERVER_EVT_NODE_RESET) { node_reset(); } } #if NRF_MESH_LOG_ENABLE static const char m_usage_string[] = "\n" "\t\t------------------------------------------------------------------------------------\n" "\t\t Button/RTT 1) Send a message to the odd group (address: 0xC003) to turn on LED 1.\n" "\t\t Button/RTT 2) Send a message to the odd group (address: 0xC003) to turn off LED 1.\n" "\t\t Button/RTT 3) Send a message to the even group (address: 0xC002) to turn on LED 1.\n" "\t\t Button/RTT 4) Send a message to the even group (address: 0xC002) to turn off LED 1.\n" "\t\t------------------------------------------------------------------------------------\n"; #endif //message format //typedef struct //{ // // unsigned char sourceNode[255]; // unsigned char destNode[255]; // unsigned int temperature; // unsigned int humidity; // unsigned int light; // unsigned int batteryLevel; // unsigned int digitalIN1; // unsigned int digitalOUT1; // //} message_param; static void button_event_handler(uint32_t button_number) { /* Increase button number because the buttons on the board is marked with 1 to 4 */ button_number++; __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number); uint32_t status = NRF_SUCCESS; generic_onoff_set_params_t set_params; model_transition_t transition_params; //message_param msg; static uint8_t tid = 0; //static uint32_t light = 5; // switch(button_number) // { // case 1: // case 3: // set_params.on_off = APP_STATE_ON; // break; // // case 2: // case 4: // set_params.on_off = APP_STATE_OFF; // break; // } switch(button_number) { case 1: set_params.light = VAL_LIGHT; break; } set_params.tid = tid++; transition_params.delay_ms = APP_ONOFF_DELAY_MS; transition_params.transition_time_ms = APP_ONOFF_TRANSITION_TIME_MS; __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Sending msg for test: Value for light: %u\n", set_params.light); // switch (button_number) // { // case 1: // case 2: // /* Demonstrate acknowledged transaction, using 1st client model instance */ // /* In this examples, users will not be blocked if the model is busy */ // (void)access_model_reliable_cancel(m_clients[0].model_handle); // status = generic_onoff_client_set(&m_clients[0], &set_params, &transition_params); // hal_led_pin_set(BSP_LED_0, set_params.on_off); // //send msg // generic_onoff_client_set(&m_clients[0], &msg, &transition_params); // __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Sending msg from %c\n", msg.sourceNode); // break; // // case 3: // case 4: // /* Demonstrate un-acknowledged transaction, using 2nd client model instance */ // status = generic_onoff_client_set_unack(&m_clients[1], &set_params, // &transition_params, APP_UNACK_MSG_REPEAT_COUNT); // hal_led_pin_set(BSP_LED_1, set_params.on_off); // break; // default: // __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string); // break; // } switch (button_number) { case 1: /* Demonstrate acknowledged transaction, using 1st client model instance */ /* In this examples, users will not be blocked if the model is busy */ (void)access_model_reliable_cancel(m_clients[0].model_handle); status = generic_onoff_client_set(&m_clients[0], &set_params, &transition_params); hal_led_pin_set(BSP_LED_0, 1); break; default: __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string); break; } switch (status) { case NRF_SUCCESS: break; case NRF_ERROR_NO_MEM: case NRF_ERROR_BUSY: case NRF_ERROR_INVALID_STATE: __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Client %u cannot send\n", button_number); hal_led_blink_ms(LEDS_MASK, LED_BLINK_SHORT_INTERVAL_MS, LED_BLINK_CNT_NO_REPLY); break; case NRF_ERROR_INVALID_PARAM: /* Publication not enabled for this client. One (or more) of the following is wrong: * - An application key is missing, or there is no application key bound to the model * - The client does not have its publication state set * * It is the provisioner that adds an application key, binds it to the model and sets * the model's publication state. */ __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Publication not configured for client %u\n", button_number); break; default: ERROR_CHECK(status); break; } } static void app_rtt_input_handler(int key) { if (key >= '1' && key <= '4') { uint32_t button_number = key - '1'; button_event_handler(button_number); } else { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string); } } static void models_init_cb(void) { __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n"); app_model_init(); //new from server for (uint32_t i = 0; i < CLIENT_MODEL_INSTANCE_COUNT; ++i) { m_clients[i].settings.p_callbacks = &client_cbs; m_clients[i].settings.timeout = 0; m_clients[i].settings.force_segmented = APP_FORCE_SEGMENTATION; m_clients[i].settings.transmic_size = APP_MIC_SIZE; ERROR_CHECK(generic_onoff_client_init(&m_clients[i], i + 1)); } } static void mesh_init(void) { mesh_stack_init_params_t init_params = { .core.irq_priority = NRF_MESH_IRQ_PRIORITY_LOWEST, .core.lfclksrc = DEV_BOARD_LF_CLK_CFG, .core.p_uuid = NULL, .models.models_init_cb = models_init_cb, .models.config_server_cb = config_server_evt_cb }; uint32_t status = mesh_stack_init(&init_params, &m_device_provisioned); switch (status) { case NRF_ERROR_INVALID_DATA: __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Data in the persistent memory was corrupted. Device starts as unprovisioned.\n"); __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Reset device before start provisioning.\n"); break; case NRF_SUCCESS: break; default: ERROR_CHECK(status); } } static void initialize(void) { __LOG_INIT(LOG_SRC_APP | LOG_SRC_ACCESS | LOG_SRC_BEARER, LOG_LEVEL_INFO, LOG_CALLBACK_DEFAULT); __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- BLE Mesh Light Switch Client Demo -----\n"); ERROR_CHECK(app_timer_init()); hal_leds_init(); #if BUTTON_BOARD ERROR_CHECK(hal_buttons_init(button_event_handler)); #endif ble_stack_init(); #if MESH_FEATURE_GATT_ENABLED gap_params_init(); conn_params_init(); #endif mesh_init(); } static void start(void) { rtt_input_enable(app_rtt_input_handler, RTT_INPUT_POLL_PERIOD_MS); if (!m_device_provisioned) { static const uint8_t static_auth_data[NRF_MESH_KEY_SIZE] = STATIC_AUTH_DATA; mesh_provisionee_start_params_t prov_start_params = { .p_static_data = static_auth_data, .prov_sd_ble_opt_set_cb = NULL, .prov_complete_cb = provisioning_complete_cb, .prov_device_identification_start_cb = device_identification_start_cb, .prov_device_identification_stop_cb = NULL, .prov_abort_cb = provisioning_aborted_cb, .p_device_uri = EX_URI_LS_SERVER }; ERROR_CHECK(mesh_provisionee_prov_start(&prov_start_params)); } else { unicast_address_print(); } mesh_app_uuid_print(nrf_mesh_configure_device_uuid_get()); ERROR_CHECK(mesh_stack_start()); __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string); hal_led_mask_set(LEDS_MASK, LED_MASK_STATE_OFF); hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_START); } int main(void) { initialize(); start(); for (;;) { //blink LEDs //hal_led_blink_ms(LED_TEST, LED_BLINK_INTERVAL_MS_TEST, LED_BLINK_CNT_TEST); (void)sd_app_evt_wait(); } }
After downloaded the modified example in boards, I configured them with nRF Mesh app like this: on first client board I set publication group address and for second client board I set subscribe. When I tested the subscribed client doesn't receive the message because I don't see logs in the SES console. Can you tell me what I did wrong or what do you suggest?
I found this similar post on DevZone: https://devzone.nordicsemi.com/f/nordic-q-a/34841/send-message-from-client-to-client-in-mesh ...but the webpage who linked in the post not working, can you updated it?
Kind regards,
Liv