This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Sending messages from client to different LPNs

Hi,

I'm using the light switch example and lpn example from the Mesh SDK 4.1.0.

I have one Board as the light switch client (gateway), one as the light switch server (FN) and one lpn.

Provisioning is done with the Mesh app for android.

the lpn node will later be modified to act as a sensor to measure a distance and when the distance is lower than 1m, it will send a message to the gateway, similar to a button press.

The ideal is to have 50 lpn nodes which regularly send the on/off message (distance lower/higher than 1m) to the gateway. 

However, i need to be able to send a constant to every LPN seperately to calibrate my sensors.

How can I do this?

I had the LPN/FN set to subscribe to group address C000 and the gateway/LPN to publish to C000. This is how the example is supposed to work and so it does, but if i want to change the led1 of a specific LPN, i can't just send a message because it would change the message of every LPN in that group address. Also, As I can see, the  LPN is behaving as a client, is it even possible in this lpn example to send data to the LPN?

Do I have to create a new model and then send data over the new model and change publication address of that new model every time? and how do I change the publication address by software?

Thank you

Parents
  • This is how I implemented it right now and it seems to work. I used the the lpn and lightswitch examples and added a functionality to the lightswitch client and lpn example. Now i can send and receive from gateway(lightswitch client) and lpn. 

    However, I'm not sure if the lowpower functionality of the LPN is still working as intended now. I added the line 

    case NRF_MESH_EVT_LPN_FRIEND_POLL_COMPLETE:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Friend poll procedure complete\n");
                app_onoff_status_publish(&m_onoff_server_0); // I added this
                break;

    in the main.c of the lpn example inside the app_mesh_core_event_cb, so it updates the LEDs when it polls.

    Does this make sense? Is this how it's supposed to wirk?

    Thanks

  • Hi.

    If you want this to happen after each poll complete event, I guess this should be fine.

    I also want to comment on a few questions from your original question;
    If you publish a message to a group address, this will be received and processes by each node subscribing to that group address. If you want to send a message to a specific node, you should use the unicast address for the node instead.

    We have a section in our online documentation about Creating new models.

    Best regards

  • Hi Joakim

    Thanks for the reply. I am now trying to send a message from my gateway to a specific (server)Node. I have two server nodes with addresses 0x0002 and 0x0003. i want to send the onoff switch command to 0x0002 and leave 0x0003 as it is. However, I have problems changing the publication address.

    This is my code for changing the publication address:

    static void change_publication_address(access_model_handle_t handle, uint16_t address)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Change Publication address\n");
        uint32_t status = NRF_SUCCESS;  
        nrf_mesh_address_t publish_address_stored;
        destination_address = address;
        
        if(publish_address_handle != DSM_HANDLE_INVALID)
        {
            NRF_MESH_ASSERT(dsm_address_publish_remove(publish_address_handle) == NRF_SUCCESS);
        }
    
        if(access_model_publish_address_get(handle, &publish_address_handle) == NRF_SUCCESS)      
        {
            status = dsm_address_publish_add(destination_address, &publish_address_handle);       // add destination address        
        }   
        else
        {
            if(dsm_address_get(publish_address_handle, &publish_address_stored) == NRF_SUCCESS)
            {
                if((publish_address_stored.type == NRF_MESH_ADDRESS_TYPE_VIRTUAL)||(publish_address_stored.type != NRF_MESH_ADDRESS_TYPE_VIRTUAL && publish_address_stored.value != destination_address))
                {
                    NRF_MESH_ASSERT(dsm_address_publish_remove(publish_address_handle) == NRF_SUCCESS);
                    status = dsm_address_publish_add(destination_address, &publish_address_handle);
                }
                else
                {
                    // use the retrieved publish_address_handle
                }
            }
            else
            {
                status = dsm_address_publish_remove(publish_address_handle);
                status = dsm_address_publish_add(destination_address, &publish_address_handle);
            }
        }
    
        switch(status)
        {
            case NRF_ERROR_NO_MEM:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "NRF_ERROR_NO_MEM\n");
                return;
            case NRF_SUCCESS:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "NRF_SUCCESS\n");
                break;
            default:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Not defined ERROR\n");
                return;
        }
        NRF_MESH_ASSERT(access_model_publish_address_set(handle, publish_address_handle) == NRF_SUCCESS);  // change the address
    }
    

    When I call  change_publication_address(m_clients[0].model_handle, 0002); on the gateway, all the LEDs on the server DK go on and i get the error  app_error_weak.c,  105, Mesh assert at 0x000275CC (:0) in the RTT Viewer.

    The error occurs because of the line 

    NRF_MESH_ASSERT(access_model_publish_address_set(handle, publish_address_handle) == NRF_SUCCESS); which is at the bottom of my change_publication_address() function.

    The funny thing is, when I reset the gateway (reset button on DK), I see that the address was changed correctly and I am sending data to 0x0002 only. Can you help me with this?

    I link my main file in case it might help. 

    /* Copyright (c) 2010 - 2020, Nordic Semiconductor ASA
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     * list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #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"
    
    /* Provisioning and configuration */
    #include "mesh_provisionee.h"
    #include "mesh_app_utils.h"
    
    /* Models */
    #include "generic_onoff_client.h"
    #include "generic_onoff_server.h"
    
    /* 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"
    #include "ble_softdevice_support.h"
    
    /* UART stuff */
    #include <stdbool.h>
    #include <stdint.h>
    #include <stdio.h>
    #include "app_uart.h"
    #include "app_error.h"
    #include "nrf_delay.h"
    #include "nrf.h"
    #include "bsp.h"
    #if defined (UART_PRESENT)
    #include "nrf_uart.h"
    #endif
    #if defined (UARTE_PRESENT)
    #include "nrf_uarte.h"
    #endif
    
    
    /*****************************************************************************
     * SERVER config
     *****************************************************************************/
    /*
     * Definitions
    */
    #define ONOFF_SERVER_0_LED          (BSP_LED_0)
    #define APP_ONOFF_ELEMENT_INDEX     (0)
    
    /* 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)
    
    
    /*
     * Forward declaration of static functions
    */
    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 variables
    */
    static bool m_device_provisioned;
    
    /* 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);
    }
    
    /* Callback for reading the hardware state */
    static void app_onoff_server_get_cb(const app_onoff_server_t * p_server, bool * 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));
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "App OnOff Model Handle: %d\n", m_onoff_server_0.server.model_handle);
    }
    
    /*************************************************************************************************/
    
    
    
    /*****************************************************************************
     * Definitions
     *****************************************************************************/
    #define APP_STATE_OFF                (0)
    #define APP_STATE_ON                 (1)
    
    #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)
    
    
    /*****************************************************************************
     * 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);
    
    
    /*****************************************************************************
     * Static variables
     *****************************************************************************/
    static generic_onoff_client_t m_clients[CLIENT_MODEL_INSTANCE_COUNT];
    static bool                   m_device_provisioned;
    
    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
    
    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;
        static uint8_t tid = 0;
    
        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;
        }
    
        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: ONOFF SET %d\n", set_params.on_off);
    
        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);
                //printf("UART test ");
                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 (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 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, "adding server model\n");
        app_model_init();
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");
        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));
        }
    }
    
    /* change the publication address*/
    static dsm_handle_t publish_address_handle = DSM_HANDLE_INVALID;
    static uint16_t destination_address;                // global destination address variable
    
    static void change_publication_address(access_model_handle_t handle, uint16_t address)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Change Publication address\n"); // This is still printed out on the RTT viewer
        uint32_t status = NRF_SUCCESS;  
        nrf_mesh_address_t publish_address_stored;
        destination_address = address;
        
        if(publish_address_handle != DSM_HANDLE_INVALID)
        {
            NRF_MESH_ASSERT(dsm_address_publish_remove(publish_address_handle) == NRF_SUCCESS);
        }
    
        if(access_model_publish_address_get(handle, &publish_address_handle) == NRF_SUCCESS)      
        {
            status = dsm_address_publish_add(destination_address, &publish_address_handle);      
        }   
        else
        {
            if(dsm_address_get(publish_address_handle, &publish_address_stored) == NRF_SUCCESS)
            {
                if((publish_address_stored.type == NRF_MESH_ADDRESS_TYPE_VIRTUAL)||(publish_address_stored.type != NRF_MESH_ADDRESS_TYPE_VIRTUAL && publish_address_stored.value != destination_address))
                {
                    NRF_MESH_ASSERT(dsm_address_publish_remove(publish_address_handle) == NRF_SUCCESS);
                    status = dsm_address_publish_add(destination_address, &publish_address_handle);
                }
                else
                {
                    // use the retrieved publish_address_handle
                }
            }
            else
            {
                status = dsm_address_publish_remove(publish_address_handle);
                status = dsm_address_publish_add(destination_address, &publish_address_handle);
            }
        }
    
        switch(status)
        {
            case NRF_ERROR_NO_MEM:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "NRF_ERROR_NO_MEM\n");
                return;
            case NRF_SUCCESS:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "NRF_SUCCESS\n");
                break;
            default:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Not defined ERROR\n");
                return;
        }
        NRF_MESH_ASSERT(access_model_publish_address_set(handle, publish_address_handle) == NRF_SUCCESS);  // change the address
    }
    
    //This code below did not work at all, it crashed the server somehow
    //static uint32_t set_model_publish_address(uint16_t publish_address, access_model_handle_t model_handle) {
    //  uint32_t status = NRF_SUCCESS;
    //  dsm_handle_t publish_address_handle = DSM_HANDLE_INVALID;
    //  access_model_publish_address_get(model_handle, &publish_address_handle);
    //  NRF_MESH_ASSERT(dsm_address_publish_remove(publish_address_handle) == NRF_SUCCESS);
    //  status = dsm_address_publish_add(publish_address, &publish_address_handle);
    //  if (status != NRF_SUCCESS) {
    //    return status;
    //  } else {
    //    return access_model_publish_address_set(model_handle, publish_address_handle);
    //  }
    //}
    
    /*****************************************************************************
     * UART
     *****************************************************************************/
    #define UART_TX_BUF_SIZE 256                         /**< UART TX buffer size. */
    #define UART_RX_BUF_SIZE 256                         /**< UART RX buffer size. */
    /* When UART is used for communication with the host do not use flow control.*/
    #define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED
    
    void uart_event_handle(app_uart_evt_t * p_event)
    {
        static uint8_t data_array[20];
        //static uint8_t index = 0;
        uint32_t  err_code;
        generic_onoff_set_params_t set_params;
        model_transition_t transition_params;
        static uint8_t tid = 0;
        uint32_t status = NRF_SUCCESS;
    
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "UART Event\n");
    
        switch(p_event->evt_type)
        {
            case APP_UART_DATA_READY:
                app_uart_get(&data_array[0]);
                //index++;
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "UART Data received: ------------- %x\n", data_array[0]);
                if(data_array[0] == 0x61) // When i send an 'a' from my Python terminal. This is working
                {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "0x61 pressed, blinking LEDs ------------- ");
                    //set_model_publish_address(3, m_clients[0].model_handle);
                    change_publication_address(m_clients[0].model_handle, 0003); // This is called correctly
                }
                if(data_array[0] == 0x62) // When i send a 'ab' from my Python terminal. This is working
                {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "0x62 pressed, blinking LEDs ------------- ");
                    //set_model_publish_address(2, m_clients[0].model_handle);
                    change_publication_address(m_clients[0].model_handle, 0002);
                }
                break;
    
            case APP_UART_COMMUNICATION_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_communication);
                break;
    
            case APP_UART_FIFO_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_code);
                break;
        
            default:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Undifinded UART Handle state\n");
                break;
        }
    }
    
    void uart_init(void)
    {
    uint32_t err_code;
    
        bsp_board_init(BSP_INIT_LEDS);
    
        const app_uart_comm_params_t comm_params =
          {
              RX_PIN_NUMBER,
              TX_PIN_NUMBER,
              RTS_PIN_NUMBER,
              CTS_PIN_NUMBER,
              UART_HWFC,
              false,
    #if defined (UART_PRESENT)
              NRF_UART_BAUDRATE_115200
    #else
              NRF_UARTE_BAUDRATE_115200
    #endif
          };
    
        APP_UART_FIFO_INIT(&comm_params,
                             UART_RX_BUF_SIZE,
                             UART_TX_BUF_SIZE,
                             uart_event_handle,
                             APP_IRQ_PRIORITY_LOWEST,
                             err_code);
    
        APP_ERROR_CHECK(err_code);
    }
    
    
    /*************************************************************************************************/
    
    /*************************************************************************************************************************
     * LOCAL CONFIGURATION OF MESH FUNCTIONS
     *************************************************************************************************************************/
    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(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_CLIENT
            };
            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();
        uart_init();
    
        for (;;)
        {
            (void)sd_app_evt_wait();
        }
    }
    

    Thank you

Reply
  • Hi Joakim

    Thanks for the reply. I am now trying to send a message from my gateway to a specific (server)Node. I have two server nodes with addresses 0x0002 and 0x0003. i want to send the onoff switch command to 0x0002 and leave 0x0003 as it is. However, I have problems changing the publication address.

    This is my code for changing the publication address:

    static void change_publication_address(access_model_handle_t handle, uint16_t address)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Change Publication address\n");
        uint32_t status = NRF_SUCCESS;  
        nrf_mesh_address_t publish_address_stored;
        destination_address = address;
        
        if(publish_address_handle != DSM_HANDLE_INVALID)
        {
            NRF_MESH_ASSERT(dsm_address_publish_remove(publish_address_handle) == NRF_SUCCESS);
        }
    
        if(access_model_publish_address_get(handle, &publish_address_handle) == NRF_SUCCESS)      
        {
            status = dsm_address_publish_add(destination_address, &publish_address_handle);       // add destination address        
        }   
        else
        {
            if(dsm_address_get(publish_address_handle, &publish_address_stored) == NRF_SUCCESS)
            {
                if((publish_address_stored.type == NRF_MESH_ADDRESS_TYPE_VIRTUAL)||(publish_address_stored.type != NRF_MESH_ADDRESS_TYPE_VIRTUAL && publish_address_stored.value != destination_address))
                {
                    NRF_MESH_ASSERT(dsm_address_publish_remove(publish_address_handle) == NRF_SUCCESS);
                    status = dsm_address_publish_add(destination_address, &publish_address_handle);
                }
                else
                {
                    // use the retrieved publish_address_handle
                }
            }
            else
            {
                status = dsm_address_publish_remove(publish_address_handle);
                status = dsm_address_publish_add(destination_address, &publish_address_handle);
            }
        }
    
        switch(status)
        {
            case NRF_ERROR_NO_MEM:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "NRF_ERROR_NO_MEM\n");
                return;
            case NRF_SUCCESS:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "NRF_SUCCESS\n");
                break;
            default:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Not defined ERROR\n");
                return;
        }
        NRF_MESH_ASSERT(access_model_publish_address_set(handle, publish_address_handle) == NRF_SUCCESS);  // change the address
    }
    

    When I call  change_publication_address(m_clients[0].model_handle, 0002); on the gateway, all the LEDs on the server DK go on and i get the error  app_error_weak.c,  105, Mesh assert at 0x000275CC (:0) in the RTT Viewer.

    The error occurs because of the line 

    NRF_MESH_ASSERT(access_model_publish_address_set(handle, publish_address_handle) == NRF_SUCCESS); which is at the bottom of my change_publication_address() function.

    The funny thing is, when I reset the gateway (reset button on DK), I see that the address was changed correctly and I am sending data to 0x0002 only. Can you help me with this?

    I link my main file in case it might help. 

    /* Copyright (c) 2010 - 2020, Nordic Semiconductor ASA
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     * list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #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"
    
    /* Provisioning and configuration */
    #include "mesh_provisionee.h"
    #include "mesh_app_utils.h"
    
    /* Models */
    #include "generic_onoff_client.h"
    #include "generic_onoff_server.h"
    
    /* 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"
    #include "ble_softdevice_support.h"
    
    /* UART stuff */
    #include <stdbool.h>
    #include <stdint.h>
    #include <stdio.h>
    #include "app_uart.h"
    #include "app_error.h"
    #include "nrf_delay.h"
    #include "nrf.h"
    #include "bsp.h"
    #if defined (UART_PRESENT)
    #include "nrf_uart.h"
    #endif
    #if defined (UARTE_PRESENT)
    #include "nrf_uarte.h"
    #endif
    
    
    /*****************************************************************************
     * SERVER config
     *****************************************************************************/
    /*
     * Definitions
    */
    #define ONOFF_SERVER_0_LED          (BSP_LED_0)
    #define APP_ONOFF_ELEMENT_INDEX     (0)
    
    /* 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)
    
    
    /*
     * Forward declaration of static functions
    */
    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 variables
    */
    static bool m_device_provisioned;
    
    /* 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);
    }
    
    /* Callback for reading the hardware state */
    static void app_onoff_server_get_cb(const app_onoff_server_t * p_server, bool * 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));
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "App OnOff Model Handle: %d\n", m_onoff_server_0.server.model_handle);
    }
    
    /*************************************************************************************************/
    
    
    
    /*****************************************************************************
     * Definitions
     *****************************************************************************/
    #define APP_STATE_OFF                (0)
    #define APP_STATE_ON                 (1)
    
    #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)
    
    
    /*****************************************************************************
     * 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);
    
    
    /*****************************************************************************
     * Static variables
     *****************************************************************************/
    static generic_onoff_client_t m_clients[CLIENT_MODEL_INSTANCE_COUNT];
    static bool                   m_device_provisioned;
    
    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
    
    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;
        static uint8_t tid = 0;
    
        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;
        }
    
        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: ONOFF SET %d\n", set_params.on_off);
    
        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);
                //printf("UART test ");
                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 (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 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, "adding server model\n");
        app_model_init();
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");
        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));
        }
    }
    
    /* change the publication address*/
    static dsm_handle_t publish_address_handle = DSM_HANDLE_INVALID;
    static uint16_t destination_address;                // global destination address variable
    
    static void change_publication_address(access_model_handle_t handle, uint16_t address)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Change Publication address\n"); // This is still printed out on the RTT viewer
        uint32_t status = NRF_SUCCESS;  
        nrf_mesh_address_t publish_address_stored;
        destination_address = address;
        
        if(publish_address_handle != DSM_HANDLE_INVALID)
        {
            NRF_MESH_ASSERT(dsm_address_publish_remove(publish_address_handle) == NRF_SUCCESS);
        }
    
        if(access_model_publish_address_get(handle, &publish_address_handle) == NRF_SUCCESS)      
        {
            status = dsm_address_publish_add(destination_address, &publish_address_handle);      
        }   
        else
        {
            if(dsm_address_get(publish_address_handle, &publish_address_stored) == NRF_SUCCESS)
            {
                if((publish_address_stored.type == NRF_MESH_ADDRESS_TYPE_VIRTUAL)||(publish_address_stored.type != NRF_MESH_ADDRESS_TYPE_VIRTUAL && publish_address_stored.value != destination_address))
                {
                    NRF_MESH_ASSERT(dsm_address_publish_remove(publish_address_handle) == NRF_SUCCESS);
                    status = dsm_address_publish_add(destination_address, &publish_address_handle);
                }
                else
                {
                    // use the retrieved publish_address_handle
                }
            }
            else
            {
                status = dsm_address_publish_remove(publish_address_handle);
                status = dsm_address_publish_add(destination_address, &publish_address_handle);
            }
        }
    
        switch(status)
        {
            case NRF_ERROR_NO_MEM:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "NRF_ERROR_NO_MEM\n");
                return;
            case NRF_SUCCESS:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "NRF_SUCCESS\n");
                break;
            default:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Not defined ERROR\n");
                return;
        }
        NRF_MESH_ASSERT(access_model_publish_address_set(handle, publish_address_handle) == NRF_SUCCESS);  // change the address
    }
    
    //This code below did not work at all, it crashed the server somehow
    //static uint32_t set_model_publish_address(uint16_t publish_address, access_model_handle_t model_handle) {
    //  uint32_t status = NRF_SUCCESS;
    //  dsm_handle_t publish_address_handle = DSM_HANDLE_INVALID;
    //  access_model_publish_address_get(model_handle, &publish_address_handle);
    //  NRF_MESH_ASSERT(dsm_address_publish_remove(publish_address_handle) == NRF_SUCCESS);
    //  status = dsm_address_publish_add(publish_address, &publish_address_handle);
    //  if (status != NRF_SUCCESS) {
    //    return status;
    //  } else {
    //    return access_model_publish_address_set(model_handle, publish_address_handle);
    //  }
    //}
    
    /*****************************************************************************
     * UART
     *****************************************************************************/
    #define UART_TX_BUF_SIZE 256                         /**< UART TX buffer size. */
    #define UART_RX_BUF_SIZE 256                         /**< UART RX buffer size. */
    /* When UART is used for communication with the host do not use flow control.*/
    #define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED
    
    void uart_event_handle(app_uart_evt_t * p_event)
    {
        static uint8_t data_array[20];
        //static uint8_t index = 0;
        uint32_t  err_code;
        generic_onoff_set_params_t set_params;
        model_transition_t transition_params;
        static uint8_t tid = 0;
        uint32_t status = NRF_SUCCESS;
    
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "UART Event\n");
    
        switch(p_event->evt_type)
        {
            case APP_UART_DATA_READY:
                app_uart_get(&data_array[0]);
                //index++;
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "UART Data received: ------------- %x\n", data_array[0]);
                if(data_array[0] == 0x61) // When i send an 'a' from my Python terminal. This is working
                {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "0x61 pressed, blinking LEDs ------------- ");
                    //set_model_publish_address(3, m_clients[0].model_handle);
                    change_publication_address(m_clients[0].model_handle, 0003); // This is called correctly
                }
                if(data_array[0] == 0x62) // When i send a 'ab' from my Python terminal. This is working
                {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "0x62 pressed, blinking LEDs ------------- ");
                    //set_model_publish_address(2, m_clients[0].model_handle);
                    change_publication_address(m_clients[0].model_handle, 0002);
                }
                break;
    
            case APP_UART_COMMUNICATION_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_communication);
                break;
    
            case APP_UART_FIFO_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_code);
                break;
        
            default:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Undifinded UART Handle state\n");
                break;
        }
    }
    
    void uart_init(void)
    {
    uint32_t err_code;
    
        bsp_board_init(BSP_INIT_LEDS);
    
        const app_uart_comm_params_t comm_params =
          {
              RX_PIN_NUMBER,
              TX_PIN_NUMBER,
              RTS_PIN_NUMBER,
              CTS_PIN_NUMBER,
              UART_HWFC,
              false,
    #if defined (UART_PRESENT)
              NRF_UART_BAUDRATE_115200
    #else
              NRF_UARTE_BAUDRATE_115200
    #endif
          };
    
        APP_UART_FIFO_INIT(&comm_params,
                             UART_RX_BUF_SIZE,
                             UART_TX_BUF_SIZE,
                             uart_event_handle,
                             APP_IRQ_PRIORITY_LOWEST,
                             err_code);
    
        APP_ERROR_CHECK(err_code);
    }
    
    
    /*************************************************************************************************/
    
    /*************************************************************************************************************************
     * LOCAL CONFIGURATION OF MESH FUNCTIONS
     *************************************************************************************************************************/
    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(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_CLIENT
            };
            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();
        uart_init();
    
        for (;;)
        {
            (void)sd_app_evt_wait();
        }
    }
    

    Thank you

Children
No Data
Related