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

cannot receive message

Hi all,

I am using nRF SDK for Mesh v1.0.1 and I want to implement following as in picture:

I am publishing to group address (group address because in the future I want to use more nodes with simple OnOff server model). I send the message from the OnOff client to the OnOff server, the light switch turns on. But I am not receiving message after publishing  to that group address (I didnt change code for switch server and from the simple_on_off_server.c I can see that after receiving SIMPLE_ON_OFF_OPCODE_SET_UNRELIABLE the callback function responds with publish_state() to the address set as publish address for that simple OnOff server model - and that is set by provisioner). In nrf connect app I can see, that the message is sent from the OnOff server model, but not received by simple OnOff client model. First I thought that I set the bad Publish address for OnOff server model (set to PROVISIONER ADDRESS + 1 - in nrf_mesh_config_app.h set the right count of models[3] and elements[2 for light switch client example]) but I dont think that this is the issue. I enclose key parts of code: 

SERVER_COUNT set to 1, because I provision only 1 element

key functions from main.c: 

SERVER_COUNT set to 1 because I want to provision only one element

access_setu() function and all the necessary configuring for OnOff client model:

static void access_setup(void)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting up access layer and models\n");

    dsm_init();
    access_init();

    m_netkey_handle = DSM_HANDLE_INVALID;
    m_appkey_handle = DSM_HANDLE_INVALID;
    for (uint32_t i = 0; i < SERVER_COUNT; ++i)
    {
        m_devkey_handles[i] = DSM_HANDLE_INVALID;
        m_server_handles[i] = DSM_HANDLE_INVALID;
    }
    m_group_handle = DSM_HANDLE_INVALID;

    /* Initialize and enable all the models before calling ***_flash_config_load. */
    ERROR_CHECK(config_client_init(config_client_event_cb));
    ERROR_CHECK(health_client_init(&m_health_client, 0, health_event_cb));

    for (uint32_t i = 0; i < 1; ++i)
    {
        m_clients[i].status_cb = client_status_cb;
        ERROR_CHECK(simple_on_off_client_init(&m_clients[i], i+1));//i+1 because i dont want to have together
                                                                   //in element0 OnOff model with control model and health model
    }

    if (dsm_flash_config_load())
    {
        m_provisioned_devices = provisioned_device_handles_load();
    }
    else
    {
        /* Set and add local addresses and keys, if flash recovery fails. */
        dsm_local_unicast_address_t local_address = {PROVISIONER_ADDRESS, 2};
        ERROR_CHECK(dsm_local_unicast_addresses_set(&local_address));

        ERROR_CHECK(dsm_address_publish_add(GROUP_ADDRESS, &m_group_handle));
        ERROR_CHECK(dsm_subnet_add(0, m_netkey, &m_netkey_handle));
        ERROR_CHECK(dsm_appkey_add(0, m_netkey_handle, m_appkey, &m_appkey_handle));
    }

    if (access_flash_config_load())
    {
        m_configured_devices = configured_devices_count_get();
    }
    else
    {
        /* Bind the keys to the health client. */
        ERROR_CHECK(access_model_application_bind(m_health_client.model_handle, m_appkey_handle));
        ERROR_CHECK(access_model_publish_application_set(m_health_client.model_handle, m_appkey_handle));

        ERROR_CHECK(access_model_application_bind(m_clients[0].model_handle, m_appkey_handle));
        ERROR_CHECK(access_model_publish_application_set(m_clients[0].model_handle, m_appkey_handle));
        ERROR_CHECK(access_model_publish_address_set(m_clients[0].model_handle, m_group_handle));
        access_flash_config_store();
    }

    provisioner_init();
    if (m_configured_devices < m_provisioned_devices)//tu sa jedna o pocty serverov nie clientov
    {
        provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices);
    }
    else if (m_provisioned_devices < SERVER_COUNT)
    {
        provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
    }
}

void provisioner_prov_complete_cb(const nrf_mesh_prov_evt_complete_t * p_prov_data)
{
    /* We should not get here if all servers are provisioned. */
    NRF_MESH_ASSERT(m_configured_devices < SERVER_COUNT);

    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Provisioning complete. Adding address 0x%04x.\n", p_prov_data->address);

    
    ERROR_CHECK(dsm_address_publish_add(p_prov_data->address, &m_server_handles[m_provisioned_devices]));
    ERROR_CHECK(dsm_devkey_add(p_prov_data->address, m_netkey_handle, p_prov_data->p_devkey, &m_devkey_handles[m_provisioned_devices]));

   
    ERROR_CHECK(config_client_server_bind(m_devkey_handles[m_provisioned_devices]));
    ERROR_CHECK(config_client_server_set(m_devkey_handles[m_provisioned_devices],
                                         m_server_handles[m_provisioned_devices]));

    m_provisioned_devices++;

    /* Move on to the configuration step. */
    provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices);
}

void provisioner_config_successful_cb(void)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Configuration of device %u successful\n", m_configured_devices);


    hal_led_pin_set(BSP_LED_0 + m_configured_devices, false);
    m_configured_devices++;

    if (m_configured_devices < SERVER_COUNT)
    {
        provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
        hal_led_pin_set(BSP_LED_0 + m_configured_devices, true);
    }
    else
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "All servers provisioned\n");
        hal_led_blink_ms(LEDS_MASK, 100, 4);
    }
}

from provisioner.c:

the handler prov_evt_handler() completed fine

I went through this steps by incrementing ->

static const config_steps_t server_config[]=
{
PROV_STATE_CONFIG_COMPOSITION_GET,
PROV_STATE_CONFIG_APPKEY_ADD,
PROV_STATE_CONFIG_APPKEY_BIND_HEALTH,
PROV_STATE_CONFIG_APPKEY_BIND_ONOFF,
PROV_STATE_CONFIG_PUBLICATION_HEALTH,
PROV_STATE_CONFIG_PUBLICATION_ONOFF,
PROV_STATE_CONFIG_SUBSCRIPTION,
};

i include where i have doubts:

 /* Configure the publication parameters for the On/Off server: */
        case PROV_STATE_CONFIG_PUBLICATION_ONOFF:
        {
            config_publication_state_t pubstate = {0};
            pubstate.element_address = m_target_address;
            pubstate.publish_address.type = NRF_MESH_ADDRESS_TYPE_UNICAST;

            pubstate.publish_address.value = PROVISIONER_ADDRESS + 1; 
            pubstate.appkey_index = 0;
            pubstate.frendship_credential_flag = false;
            pubstate.publish_ttl = SERVER_COUNT;
            pubstate.publish_period.step_num = 0;
            pubstate.publish_period.step_res = ACCESS_PUBLISH_RESOLUTION_100MS;
            pubstate.retransmit_count = 1;
            pubstate.retransmit_interval = 0;
            pubstate.model_id.company_id = ACCESS_COMPANY_ID_NORDIC;
            pubstate.model_id.model_id = SIMPLE_ON_OFF_SERVER_MODEL_ID;
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting publication address for the On/Off server to 0x%04x\n", pubstate.publish_address.value);

            ERROR_CHECK(config_client_model_publication_set(&pubstate));

            break;
        }
        
        
        

What am I missing? Something to change in mesh_config_app.h or what? Thankful for each one answer. 

Patrik 

Parents
  • Why did you change the for loop in access_setup() from i < CLIENT_COUNT to:

        for (uint32_t i = 0; i < 1; ++i)
        {
            m_clients[i].status_cb = client_status_cb;
            ERROR_CHECK(simple_on_off_client_init(&m_clients[i], i+1));//i+1 because i dont want to have together
                                                                       //in element0 OnOff model with control model and health model
        }

    From what I understand, you want to call the simple_on_off_client_init() function twice if you have one client & one server.

    Also, in your access_setup() function, you changed these three functions from m_clients[GROUP_CLIENT_INDEX] to:

            ERROR_CHECK(access_model_application_bind(m_clients[0].model_handle, m_appkey_handle));
            ERROR_CHECK(access_model_publish_application_set(m_clients[0].model_handle, m_appkey_handle));
            ERROR_CHECK(access_model_publish_address_set(m_clients[0].model_handle, m_group_handle));

    What was the reason for this? I believe the idea there is to set the publish address for the group address. The publish address for the configured server is set in the access_model_publish_address_set() function in provisioner_config_successful_cb() in the main.c file of the light switch client example.

    Also, you changed the code in the PROV_STATE_CONFIG_PUBLICATION_ONOFF case inside do_config_step() from:

    pubstate.publish_address.value = PROVISIONER_ADDRESS + m_target_address - UNPROV_START_ADDRESS;

    to:

    pubstate.publish_address.value = PROVISIONER_ADDRESS + 1; 

    What was the reason for this?

Reply
  • Why did you change the for loop in access_setup() from i < CLIENT_COUNT to:

        for (uint32_t i = 0; i < 1; ++i)
        {
            m_clients[i].status_cb = client_status_cb;
            ERROR_CHECK(simple_on_off_client_init(&m_clients[i], i+1));//i+1 because i dont want to have together
                                                                       //in element0 OnOff model with control model and health model
        }

    From what I understand, you want to call the simple_on_off_client_init() function twice if you have one client & one server.

    Also, in your access_setup() function, you changed these three functions from m_clients[GROUP_CLIENT_INDEX] to:

            ERROR_CHECK(access_model_application_bind(m_clients[0].model_handle, m_appkey_handle));
            ERROR_CHECK(access_model_publish_application_set(m_clients[0].model_handle, m_appkey_handle));
            ERROR_CHECK(access_model_publish_address_set(m_clients[0].model_handle, m_group_handle));

    What was the reason for this? I believe the idea there is to set the publish address for the group address. The publish address for the configured server is set in the access_model_publish_address_set() function in provisioner_config_successful_cb() in the main.c file of the light switch client example.

    Also, you changed the code in the PROV_STATE_CONFIG_PUBLICATION_ONOFF case inside do_config_step() from:

    pubstate.publish_address.value = PROVISIONER_ADDRESS + m_target_address - UNPROV_START_ADDRESS;

    to:

    pubstate.publish_address.value = PROVISIONER_ADDRESS + 1; 

    What was the reason for this?

Children
  • oh yes, many things are hardcoded with the purpose to examine my understanding of bluetooh mesh speification. My mistake, in the future for better understanding I will post with using macros :) 

    1) change from i < client_count to i < 1 .....  - hardcoded part and I wanted to call the simple_on_off_client_init() just once because on node1 (as in the picture above) I have just one simple OnOff client model. In node 2 there is simple OnOff server model called with simple_on_off_server_init(). 

    2) should I have declared - #define GROUP_CLIENT_INDEX (0) . In 1) in for loop I have declared just one (the for loop cycles just once with condition i < 1) simple_on_off_client_t structure, i.e. m_clients[0] and  that structure contains the necessary parameters for controlling one server model in node2 which is subscribing to group address (it likely makes no sense to publish to group address to one server model which is subscribing to that group address, but in the future i want to add more server models to subscribe to that group address)

    Yes I erased the function access_model_publish_address_set() from the callback function provisioner_config_successful_cb, because with this step I would change the publish address to the particular server model (and I am trying to publish to group address).

    3) again hardcoded part. but it is the same in my case, PROVISIONER_ADDRESS + m_target_address - UNPROV_START_ADDRESS == PROVISIONER_ADDRESS + 1. From the picture above there you can see the exact addresses for my elements used in code, from there that PROVISIONER_ADDRESS + 1 (the address for element in which is OnOff client model - I also suppose that the function dsm_local_unicast_addresses_set() sets the addresses in increments of 1 beginning with the addres we declare in dsm_local_unicast_address_t structure)

  • 1) If I were you, I would definitely take a look at this devzone case. I agree with you that on first sight, it doesn't make sense why you should initialize the simple_on_off_client model more than once. What is happening though is that for each client & server, a single simple_on_off_client model is initialized on the client to enable the light switch functionality (i.e. turning on/off the lights on the server). Since you have one client & one server, two elements (i.e. controllable part of a node, e.g. an LED) will be initialized with one OnOffClient model each. The first element sets up communication to the server to turn on & off the server LED, while the second element will handle communication to the group address (to turn off the light on multiple servers).

    2) If you take a look at the mesh sdk v1.0.1 light switch client code, you can see that the server node needs to be configured before access_model_publish_address_set() is called inside provisioner_config_successful_cb(). This could well be a reason why your code is not working.

    3) You are correct that the unicast addresses are set in increments of one. Take a look at:

        provisioner_init();
        if (m_configured_devices < m_provisioned_devices)
        {
            provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices);
        }
        else if (m_provisioned_devices < SERVER_COUNT)
        {
            provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
        }

    inside access_setup() of the light switch client example. The unicast address arguments (m_configured_devices & m_provisioned_devices) inside provisioner_configure() & provisioner_wait_for_unprov() get incremented inside provisioner_config_successful_cb() & provisioner_prov_complete_cb().

    The Getting Started link in the Nordic Infocenter has some useful information for understanding the light switch example & the Mesh SDK better.

Related