I have successfully managed to both provision and configure the simple:_on_of_client.
but i'm having troubles configuring the simple_on_off server. I really have no idea how to fix the issue, but what seems to be the problem is getting a response from the server node. all this happens at the intial step (in the switch case).
Server output:
<t: 0>, main.c, 191, ----- BLE Mesh Light Switch Server Demo ----- <t: 13242>, main.c, 171, Initializing and adding models <t: 13244>, simple_on_off_server.c, 137, MODEL INIT SUCCESS <t: 17997>, mesh_app_utils.c, 65, Device UUID (raw): ABA35353C189664FB261427FA6ACB866 <t: 18000>, mesh_app_utils.c, 70, Device UUID : 5353A3AB-89C1-4F66-B261-427FA6ACB866 <t: 1125039>, main.c, 151, Successfully provisioned <t: 1125044>, main.c, 162, Node Address: 0x0102
provisioner output:
<t: 828781>, provisioner_helper.c, 303, Scanning For Unprovisioned Devices <t: 828818>, main.c, 109, Flash write complete <t: 829891>, provisioner_helper.c, 138, UUID : ABA35353C189664FB261427FA6ACB866 <t: 829894>, provisioner_helper.c, 142, ^RSSI: -66 <t: 829896>, provisioner_helper.c, 147, ^URI Hash: 74F97940 <t: 829901>, provisioner_helper.c, 153, URI hash matched. Provisioning ... <t: 837008>, provisioner_helper.c, 274, Provisioning link established <t: 915600>, provisioner_helper.c, 269, Static authentication data provided <t: 1054423>, provisioner_helper.c, 207, Provisioning completed received <t: 1054426>, provisioner_helper.c, 212, Adding device address, and device keys <t: 1054431>, provisioner_helper.c, 229, Addr: 0x0102 addr_handle: 1 netkey_handle: 0 devkey_handle: 3 <t: 1058004>, provisioner_helper.c, 166, Local provisioning link closed: prov_state: 2 remaining retries: 2 <t: 1058008>, main.c, 298, Provisioning successful <t: 1058011>, provisioner_helper.c, 196, Provisioning complete. Node addr: 0x0102 elements: 1 <t: 1058015>, node_setup.c, 699, Configuring Node: 0x0102 <t: 1058018>, node_setup.c, 592, Config client setup: devkey_handle:3 addr_handle:1 <t: 1058022>, node_setup.c, 325, SERVER about to be configured <t: 1058024>, node_setup.c, 354, Getting composition data <t: 1058035>, node_setup.c, 356, status in NODE_SETUP_CONFIG_COMPOSITION_GET is: 0 <t: 1058038>, node_setup.c, 358, exiting NODE_SETUP_CONFIG_COMPOSITION_GET <t: 1058074>, main.c, 109, Flash write complete <t: 1058108>, main.c, 109, Flash write complete <t: 1140794>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -63 <t: 1143383>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -58 <t: 1468648>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -64 <t: 1471110>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -64 <t: 1796645>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -59 <t: 1799119>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -59 <t: 2124352>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -61 <t: 2126786>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -61 <t: 2451865>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -65 <t: 2454435>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -65 <t: 2779514>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -61 <t: 2782278>, main.c, 329, Node 0x0100 alive with 0 active fault(s), RSSI: -61 <t: 3024114>, main.c, 350, Config client event <t: 3024116>, node_setup.c, 640, Acknowledged message status not received <t: 3024119>, node_setup.c, 644, Retry ...
The node_setup.c is modified to support the simple_on_off server/client, by only using one address, instead of the ODD EVEN method. But i doubt that matters, since the error already happens at NODE_SETUP_CONFIG_COMPOSITION_GET
node_setup.c:
/* Copyright (c) 2010 - 2019, 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 <stdbool.h>
#include <string.h>
#include <stdarg.h>
#include "nrf_mesh_utils.h"
#include "device_state_manager.h"
#include "timer_scheduler.h"
#include "config_client.h"
#include "config_server.h"
#include "access_config.h"
#include "generic_level_server.h"
#include "generic_level_client.h"
#include "generic_onoff_server.h"
#include "generic_onoff_client.h"
#include "health_common.h"
#include "provisioner_helper.h"
#include "node_setup.h"
#include "example_common.h"
#include "example_network_config.h"
#include "light_switch_example_common.h"
#include "mesh_app_utils.h"
#include "log.h"
#include "nrf_mesh_assert.h"
/* USER_NOTE: Add more steps here is you want to customize the nodes further. */
/* Node setup steps */
typedef enum
{
NODE_SETUP_IDLE,
NODE_SETUP_CONFIG_COMPOSITION_GET,
NODE_SETUP_CONFIG_NETWORK_TRANSMIT,
NODE_SETUP_CONFIG_APPKEY_ADD,
NODE_SETUP_CONFIG_APPKEY_BIND_HEALTH,
NODE_SETUP_CONFIG_APPKEY_BIND_ONOFF_SERVER,
NODE_SETUP_CONFIG_APPKEY_BIND_ONOFF_CLIENT,
NODE_SETUP_CONFIG_PUBLICATION_HEALTH,
NODE_SETUP_CONFIG_PUBLICATION_ONOFF_SERVER,
NODE_SETUP_CONFIG_PUBLICATION_ONOFF_CLIENT1,
NODE_SETUP_CONFIG_PUBLICATION_ONOFF_CLIENT2,
NODE_SETUP_CONFIG_SUBSCRIPTION_ONOFF_SERVER,
NODE_SETUP_DONE,
} config_steps_t;
/* Structure to hold the composition data */
typedef struct
{
uint16_t len;
struct
{
uint8_t page_number;
uint8_t data[NRF_MESH_SEG_PAYLOAD_SIZE_MAX];
}composition;
} composition_data_t;
/* Expected status structure, used for setup state machine */
typedef struct
{
uint8_t num_statuses;
uint16_t expected_opcode;
const access_status_t * p_statuses;
} expected_status_list_t;
typedef struct
{
uint8_t count;
timer_event_t timer;
} client_send_retry_t;
typedef enum
{
STATUS_CHECK_PASS,
STATUS_CHECK_FAIL,
STATUS_CHECK_UNEXPECTED_OPCODE
} status_check_t;
/* USER_NOTE:
You can define one or more such configuration steps for a given node in your network. The choice
of the steps can be done in @ref setup_select_steps() function.
*/
/* Sequence of steps for the client nodes */
static const config_steps_t client_config_steps[] =
{
NODE_SETUP_CONFIG_COMPOSITION_GET,
NODE_SETUP_CONFIG_NETWORK_TRANSMIT,
NODE_SETUP_CONFIG_APPKEY_ADD,
NODE_SETUP_CONFIG_APPKEY_BIND_HEALTH,
NODE_SETUP_CONFIG_PUBLICATION_HEALTH,
NODE_SETUP_CONFIG_APPKEY_BIND_ONOFF_CLIENT,
//NODE_SETUP_CONFIG_APPKEY_BIND_ONOFF_CLIENT,
NODE_SETUP_CONFIG_PUBLICATION_ONOFF_CLIENT1,
//NODE_SETUP_CONFIG_PUBLICATION_ONOFF_CLIENT2,
NODE_SETUP_DONE
};
/* Sequence of steps for the server nodes */
static const config_steps_t server_config_steps[] =
{
NODE_SETUP_CONFIG_COMPOSITION_GET,
NODE_SETUP_CONFIG_NETWORK_TRANSMIT,
NODE_SETUP_CONFIG_APPKEY_ADD,
NODE_SETUP_CONFIG_APPKEY_BIND_HEALTH,
NODE_SETUP_CONFIG_APPKEY_BIND_ONOFF_SERVER,
NODE_SETUP_CONFIG_PUBLICATION_ONOFF_SERVER,
NODE_SETUP_CONFIG_PUBLICATION_HEALTH,
NODE_SETUP_CONFIG_SUBSCRIPTION_ONOFF_SERVER,
NODE_SETUP_DONE
};
static uint16_t m_current_node_addr;
static uint16_t m_retry_count;
static client_send_retry_t m_send_timer;
static const uint8_t * mp_appkey;
static uint16_t m_appkey_idx;
static uint16_t m_netkey_idx;
static access_model_id_t m_client_model_id;
static access_model_id_t m_server_model_id;
static const config_steps_t m_idle_step = NODE_SETUP_IDLE;
static const config_steps_t * mp_config_step = &m_idle_step;
static node_setup_successful_cb_t m_node_setup_success_cb;
static node_setup_failed_cb_t m_node_setup_failed_cb;
static expected_status_list_t m_expected_status_list;
/* Forward declaration */
static void config_step_execute(void);
/*************************************************************************************************/
static void node_setup_state_clear(void)
{
timer_sch_abort(&m_send_timer.timer);
mp_config_step = &m_idle_step;
}
static void node_setup_succeed(void)
{
node_setup_state_clear();
m_node_setup_success_cb();
}
static void node_setup_fail(void)
{
node_setup_state_clear();
m_node_setup_failed_cb();
}
/* Set expected status opcode and acceptable value of status codes */
static void expected_status_set(uint32_t opcode, uint32_t n, const access_status_t * p_list)
{
if (n > 0)
{
NRF_MESH_ASSERT(p_list != NULL);
}
m_expected_status_list.expected_opcode = opcode;
m_expected_status_list.num_statuses = n;
m_expected_status_list.p_statuses = p_list;
}
static void config_step_retry_schedule(void)
{
NRF_MESH_ASSERT_DEBUG(m_send_timer.count > 0);
m_send_timer.count--;
timestamp_t next_timeout = timer_now() + MS_TO_US(CLIENT_BUSY_SEND_RETRY_DELAY_MS);
timer_sch_reschedule(&m_send_timer.timer, next_timeout);
}
/* Callback for the timer event */
static void client_send_timer_cb(timestamp_t timestamp, void * p_context)
{
/* retry the last step */
config_step_execute();
}
/**
* When config client status message is received, this function checks for the expected opcode, and
* status values. It is required by the node setup state machine.
*/
static status_check_t check_expected_status(uint16_t rx_opcode, const config_msg_t * p_msg)
{
uint8_t status = 0xFF;
if (rx_opcode != m_expected_status_list.expected_opcode)
{
__LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "Unexpected opcode: exp 0x%04x rx 0x%04x\n",
m_expected_status_list.expected_opcode, rx_opcode);
return STATUS_CHECK_UNEXPECTED_OPCODE;
}
switch (rx_opcode)
{
/* These messages do not have a STATUS field. */
case CONFIG_OPCODE_COMPOSITION_DATA_STATUS:
case CONFIG_OPCODE_NETWORK_TRANSMIT_STATUS:
break;
case CONFIG_OPCODE_MODEL_APP_STATUS:
status = p_msg->app_status.status;
break;
case CONFIG_OPCODE_MODEL_PUBLICATION_STATUS:
status = p_msg->publication_status.status;
break;
case CONFIG_OPCODE_MODEL_SUBSCRIPTION_STATUS:
status = p_msg->subscription_status.status;
break;
case CONFIG_OPCODE_APPKEY_STATUS:
status = p_msg->appkey_status.status;
break;
default:
/** USER_TO_CONFIGURE: Resolve additional required statuses in above switch case */
__LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "Handle additional statuses here");
ERROR_CHECK(NRF_ERROR_NOT_FOUND);
break;
}
if (m_expected_status_list.num_statuses == 0)
{
return STATUS_CHECK_PASS;
}
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "opcode status field: %d \n", status);
for (uint32_t i = 0; i < m_expected_status_list.num_statuses; i++)
{
if (status == m_expected_status_list.p_statuses[i])
{
return STATUS_CHECK_PASS;
}
}
return STATUS_CHECK_FAIL;
}
/*************************************************************************************************/
/* Application-specific functions for combining some commonly used structure assignments */
static void client_pub_state_set(config_publication_state_t *p_pubstate, uint16_t element_addr,
uint16_t publish_addr)
{
p_pubstate->element_address = element_addr;
p_pubstate->publish_address.type = nrf_mesh_address_type_get(publish_addr);
p_pubstate->publish_address.value = publish_addr;
p_pubstate->appkey_index = m_appkey_idx;
p_pubstate->frendship_credential_flag = false;
p_pubstate->publish_ttl = (SERVER_NODE_COUNT > NRF_MESH_TTL_MAX ? NRF_MESH_TTL_MAX : SERVER_NODE_COUNT);
p_pubstate->publish_period.step_num = 0;
p_pubstate->publish_period.step_res = ACCESS_PUBLISH_RESOLUTION_100MS;
p_pubstate->retransmit_count = 1;
p_pubstate->retransmit_interval = 0;
p_pubstate->model_id.company_id = m_client_model_id.company_id;
p_pubstate->model_id.model_id = m_client_model_id.model_id;
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Set: on/off client: 0x%04x pub addr: 0x%04x\n",
p_pubstate->element_address, p_pubstate->publish_address.value);
}
/*************************************************************************************************/
/* Node setup functionality related static functions */
/* USER_NOTE:
You can code any suitable logic here to select the configuration steps for a given
node in your network.
*/
/**
* Selects the configuration steps for the node.
*
* In this example, first device is always a light-switch Client. Subsequent devices are servers
* First two servers will act as unicast devices and other servers will be subscribed to the
* ODD or EVEN groups.
*
* @param[in] addr Address of the device being configured.
*
*/
static void setup_select_steps(uint16_t addr)
{
if (addr == UNPROV_START_ADDRESS)
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "CLIENT about to be configured\n");
mp_config_step = client_config_steps;
}
else
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "SERVER about to be configured\n");
mp_config_step = server_config_steps;
}
}
/** Step execution function for the configuration state machine. */
static void config_step_execute(void)
{
uint32_t status = NRF_ERROR_INVALID_STATE;
static uint16_t model_element_addr = 0;
/* This example configures the provisioned nodes in the following way
* Node 0: Client node (Switch)
* Node 1,2,3 ...: Server nodes (Lights)
*
* Group Even: All nodes with even address
* Group Odd: All nodes with odd address
*/
/* Customize configuration steps for client vs. server nodes.
* For client nodes: Skip, usual publication and subscription
*/
switch (*mp_config_step)
{
/* Read the composition data from the node: */
case NODE_SETUP_CONFIG_COMPOSITION_GET:
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Getting composition data\n");
status = config_client_composition_data_get(0x00);
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "status in NODE_SETUP_CONFIG_COMPOSITION_GET is: %d \n",status);
expected_status_set(CONFIG_OPCODE_COMPOSITION_DATA_STATUS, 0, NULL);
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "exiting NODE_SETUP_CONFIG_COMPOSITION_GET \n" );
break;
}
case NODE_SETUP_CONFIG_NETWORK_TRANSMIT:
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Updating network transmit: count: %d steps: %d\n",
NETWORK_TRANSMIT_COUNT, NETWORK_TRANSMIT_INTERVAL_STEPS);
status = config_client_network_transmit_set(NETWORK_TRANSMIT_COUNT, NETWORK_TRANSMIT_INTERVAL_STEPS);
expected_status_set(CONFIG_OPCODE_NETWORK_TRANSMIT_STATUS, 0 , NULL);
break;
}
/* Add the application key to the node: */
case NODE_SETUP_CONFIG_APPKEY_ADD:
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Adding appkey\n");
status = config_client_appkey_add(m_netkey_idx, m_appkey_idx, mp_appkey);
static const access_status_t exp_status[] = {ACCESS_STATUS_SUCCESS, ACCESS_STATUS_KEY_INDEX_ALREADY_STORED};
expected_status_set(CONFIG_OPCODE_APPKEY_STATUS, ARRAY_SIZE(exp_status), exp_status);
break;
}
/* Bind the health server to the application key: */
case NODE_SETUP_CONFIG_APPKEY_BIND_HEALTH:
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "App key bind: Health server\n");
access_model_id_t model_id;
model_id.company_id = ACCESS_COMPANY_ID_NONE;
model_id.model_id = HEALTH_SERVER_MODEL_ID;
uint16_t element_address = m_current_node_addr;
status = config_client_model_app_bind(element_address, m_appkey_idx, model_id);
static const access_status_t exp_status[] = {ACCESS_STATUS_SUCCESS};
expected_status_set(CONFIG_OPCODE_MODEL_APP_STATUS, ARRAY_SIZE(exp_status), exp_status);
break;
}
/* Bind the On/Off server to the application key: */
case NODE_SETUP_CONFIG_APPKEY_BIND_ONOFF_SERVER:
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "App key bind: 0x%04x server\n", m_server_model_id.model_id);
access_model_id_t model_id;
model_id.company_id = m_server_model_id.company_id;
model_id.model_id = m_server_model_id.model_id;
uint16_t element_address = m_current_node_addr;
status = config_client_model_app_bind(element_address, m_appkey_idx, model_id);
static const access_status_t exp_status[] = {ACCESS_STATUS_SUCCESS};
expected_status_set(CONFIG_OPCODE_MODEL_APP_STATUS, ARRAY_SIZE(exp_status), exp_status);
break;
}
/* Bind the On/Off client to the application key: */
case NODE_SETUP_CONFIG_APPKEY_BIND_ONOFF_CLIENT:
{
if (model_element_addr == 0)
{
model_element_addr = m_current_node_addr + 1;
}
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "App key bind: 0x%04x client on element 0x%04x\n", m_client_model_id.model_id, model_element_addr);
access_model_id_t model_id;
model_id.company_id = m_client_model_id.company_id;
model_id.model_id = m_client_model_id.model_id;
uint16_t element_address = model_element_addr;
status = config_client_model_app_bind(element_address, m_appkey_idx, model_id);
static const access_status_t exp_status[] = {ACCESS_STATUS_SUCCESS};
expected_status_set(CONFIG_OPCODE_MODEL_APP_STATUS, ARRAY_SIZE(exp_status), exp_status);
if (status == NRF_SUCCESS)
{
model_element_addr++;
}
break;
}
/* Configure the publication parameters for the Health server: */
case NODE_SETUP_CONFIG_PUBLICATION_HEALTH:
{
config_publication_state_t pubstate = {0};
pubstate.element_address = m_current_node_addr;
pubstate.publish_address.type = NRF_MESH_ADDRESS_TYPE_UNICAST;
pubstate.publish_address.value = PROVISIONER_ADDRESS;
pubstate.appkey_index = m_appkey_idx;
pubstate.frendship_credential_flag = false;
pubstate.publish_ttl = (SERVER_NODE_COUNT > NRF_MESH_TTL_MAX ? NRF_MESH_TTL_MAX : SERVER_NODE_COUNT);
pubstate.publish_period.step_num = 1;
pubstate.publish_period.step_res = ACCESS_PUBLISH_RESOLUTION_10S;
pubstate.retransmit_count = 1;
pubstate.retransmit_interval = 0;
pubstate.model_id.company_id = ACCESS_COMPANY_ID_NONE;
pubstate.model_id.model_id = HEALTH_SERVER_MODEL_ID;
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting publication address for the health server to 0x%04x\n", pubstate.publish_address.value);
status = config_client_model_publication_set(&pubstate);
static const access_status_t exp_status[] = {ACCESS_STATUS_SUCCESS};
expected_status_set(CONFIG_OPCODE_MODEL_PUBLICATION_STATUS, ARRAY_SIZE(exp_status), exp_status);
break;
}
/* Configure the publication parameters for the On/Off servers to publish to the
corresponding On/Off clients (ODD servers: Client on Element 1 and EVEN servers: Client on
element 2, of the client example). This demonstrates the state change publication due to local
event on the server. */
case NODE_SETUP_CONFIG_PUBLICATION_ONOFF_SERVER:
{
config_publication_state_t pubstate = {0};
pubstate.element_address = m_current_node_addr;
pubstate.publish_address.type = NRF_MESH_ADDRESS_TYPE_UNICAST;
/**
if ((m_current_node_addr % 2) == 0)
{
pubstate.publish_address.value = UNPROV_START_ADDRESS + ELEMENT_IDX_ONOFF_CLIENT2;
}
else
{
pubstate.publish_address.value = UNPROV_START_ADDRESS + ELEMENT_IDX_ONOFF_CLIENT1;
}
**/
pubstate.publish_address.value = UNPROV_START_ADDRESS + ELEMENT_IDX_ONOFF_CLIENT1;
pubstate.appkey_index = m_appkey_idx;
pubstate.frendship_credential_flag = false;
pubstate.publish_ttl = (SERVER_NODE_COUNT > NRF_MESH_TTL_MAX ? NRF_MESH_TTL_MAX : SERVER_NODE_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 = m_server_model_id.company_id;
pubstate.model_id.model_id = m_server_model_id.model_id;
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Set: 0x%04x server pub addr: 0x%04x\n", m_server_model_id.model_id, pubstate.publish_address.value);
status = config_client_model_publication_set(&pubstate);
static const access_status_t exp_status[] = {ACCESS_STATUS_SUCCESS};
expected_status_set(CONFIG_OPCODE_MODEL_PUBLICATION_STATUS, ARRAY_SIZE(exp_status), exp_status);
break;
}
/* Configure subscription address for the On/Off server */
case NODE_SETUP_CONFIG_SUBSCRIPTION_ONOFF_SERVER:
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Adding subscription\n");
uint16_t element_address = m_current_node_addr;
nrf_mesh_address_t address = {NRF_MESH_ADDRESS_TYPE_INVALID, 0, NULL};
address.type = NRF_MESH_ADDRESS_TYPE_GROUP;
/**
if (m_current_node_addr % 0x02)
{
address.value = GROUP_ADDRESS_ODD;
}
else
{
address.value = GROUP_ADDRESS_EVEN;
}
**/
address.value = GROUP_ADDRESS_ODD;
access_model_id_t model_id;
model_id.company_id = m_server_model_id.company_id;
model_id.model_id = m_server_model_id.model_id;
status = config_client_model_subscription_add(element_address, address, model_id);
static const access_status_t exp_status[] = {ACCESS_STATUS_SUCCESS};
expected_status_set(CONFIG_OPCODE_MODEL_SUBSCRIPTION_STATUS, ARRAY_SIZE(exp_status), exp_status);
break;
}
case NODE_SETUP_CONFIG_PUBLICATION_ONOFF_CLIENT1:
{
config_publication_state_t pubstate = {0};
client_pub_state_set(&pubstate,
m_current_node_addr + ELEMENT_IDX_ONOFF_CLIENT1,
GROUP_ADDRESS_ODD);
status = config_client_model_publication_set(&pubstate);
static const access_status_t exp_status[] = {ACCESS_STATUS_SUCCESS};
expected_status_set(CONFIG_OPCODE_MODEL_PUBLICATION_STATUS, ARRAY_SIZE(exp_status), exp_status);
break;
}
case NODE_SETUP_CONFIG_PUBLICATION_ONOFF_CLIENT2:
{
config_publication_state_t pubstate = {0};
client_pub_state_set(&pubstate,
m_current_node_addr + ELEMENT_IDX_ONOFF_CLIENT2,
GROUP_ADDRESS_EVEN);
status = config_client_model_publication_set(&pubstate);
static const access_status_t exp_status[] = {ACCESS_STATUS_SUCCESS};
expected_status_set(CONFIG_OPCODE_MODEL_PUBLICATION_STATUS, ARRAY_SIZE(exp_status), exp_status);
break;
}
default:
ERROR_CHECK(NRF_ERROR_NOT_FOUND);
break;
}
if (status != NRF_SUCCESS)
{
config_client_pending_msg_cancel();
if (m_send_timer.count > 0)
{
config_step_retry_schedule();
}
else
{
node_setup_fail();
}
}
}
/**
* This function retrieves the device key for the given address, and configures the tx and rx paths
* of the config client model.
*/
static void setup_config_client(uint16_t target_addr)
{
dsm_handle_t addr_handle = DSM_HANDLE_INVALID;
dsm_handle_t devkey_handle = DSM_HANDLE_INVALID;
nrf_mesh_address_t addr;
addr.type = NRF_MESH_ADDRESS_TYPE_UNICAST;
addr.value = target_addr;
/* Provisioner helper has stored address and device keys already. Retrieve them. */
ERROR_CHECK(dsm_address_handle_get(&addr, &addr_handle));
ERROR_CHECK(dsm_devkey_handle_get(addr.value, &devkey_handle));
/* Configure client to communicate with server at the given address */
ERROR_CHECK(config_client_server_bind(devkey_handle));
ERROR_CHECK(config_client_server_set(devkey_handle, addr_handle));
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Config client setup: devkey_handle:%d addr_handle:%d\n", devkey_handle, addr_handle);
}
static void config_client_msg_handle(const config_client_event_t * p_event,
uint16_t length)
{
if (*mp_config_step == NODE_SETUP_IDLE || *mp_config_step == NODE_SETUP_DONE)
{
__LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "Got unexpected config client message in state %u\n", *mp_config_step);
return;
}
else
{
status_check_t status = check_expected_status(p_event->opcode, p_event->p_msg);
if (status == STATUS_CHECK_PASS)
{
mp_config_step++;
m_send_timer.count = CLIENT_BUSY_SEND_RETRY_LIMIT;
if (*mp_config_step == NODE_SETUP_DONE)
{
node_setup_succeed();
}
else
{
config_step_execute();
}
}
else if (status == STATUS_CHECK_FAIL)
{
node_setup_fail();
}
}
}
/*************************************************************************************************/
/* Public functions */
/**
* Proccess the config client model events, and advances the node setup state machine to the next
* state, if expected status message is received.
*/
void node_setup_config_client_event_process(config_client_event_type_t event_type,
const config_client_event_t * p_event,
uint16_t length)
{
if (event_type == CONFIG_CLIENT_EVENT_TYPE_TIMEOUT)
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Acknowledged message status not received \n");
if (m_retry_count > 0)
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Retry ...\n");
m_retry_count--;
config_step_execute();
}
else
{
node_setup_fail();
}
}
else if (event_type == CONFIG_CLIENT_EVENT_TYPE_MSG)
{
NRF_MESH_ASSERT_DEBUG(p_event != NULL);
config_client_msg_handle(p_event, length);
}
}
/**
* Begins the node setup process.
*/
void node_setup_start(uint16_t address, uint8_t retry_cnt, const uint8_t * p_appkey,
uint16_t appkey_idx, uint16_t netkey_idx, const char * p_client_uri)
{
if (*mp_config_step != NODE_SETUP_IDLE)
{
__LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "Cannot start. Node setup procedure is in progress.\n");
return;
}
m_current_node_addr = address;
m_retry_count = retry_cnt;
m_send_timer.timer.cb = client_send_timer_cb;
m_send_timer.count = CLIENT_BUSY_SEND_RETRY_LIMIT;
mp_appkey = p_appkey;
m_appkey_idx = appkey_idx;
m_netkey_idx = netkey_idx;
/* The filter match will decide, which model pairs to pick up */
if (strcmp(p_client_uri, EX_URI_LS_CLIENT) == 0 || strcmp(p_client_uri, EX_URI_ENOCEAN) == 0)
{
m_client_model_id.model_id = GENERIC_ONOFF_CLIENT_MODEL_ID;
m_server_model_id.model_id = GENERIC_ONOFF_SERVER_MODEL_ID;
}
else if (strcmp(p_client_uri, EX_URI_DM_CLIENT) == 0)
{
m_client_model_id.model_id = GENERIC_LEVEL_CLIENT_MODEL_ID;
m_server_model_id.model_id = GENERIC_LEVEL_SERVER_MODEL_ID;
}
else
{
__LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "Invalid client URI identifier.\n");
NRF_MESH_ASSERT(false);
}
m_client_model_id.company_id = ACCESS_COMPANY_ID_NORDIC;
m_server_model_id.company_id = ACCESS_COMPANY_ID_NORDIC;
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Configuring Node: 0x%04X\n", m_current_node_addr);
setup_config_client(m_current_node_addr);
setup_select_steps(m_current_node_addr);
config_step_execute();
}
void node_setup_cb_set(node_setup_successful_cb_t config_success_cb,
node_setup_failed_cb_t config_failed_cb)
{
NRF_MESH_ASSERT(config_success_cb != NULL);
NRF_MESH_ASSERT(config_failed_cb != NULL);
m_node_setup_success_cb = config_success_cb;
m_node_setup_failed_cb = config_failed_cb;
}
I expect the mistake to be in the server implementation, since it is the one NOT acknowledging the configuration, but i really can't tell.
main.c (server)
#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"
/* Provisioning and configuration */
#include "mesh_provisionee.h"
#include "mesh_app_utils.h"
/* Models */
#include "C:\nRF_work\nrf5SDKforMeshv320src\models\vendor\simple_on_off\include\simple_on_off_server.h"
//#include "C:\Users\RAbbas\OneDrive - Emerson\Documents\repos\mesh test\model\server_models\s_model.h"
/* Logging and RTT */
#include "log.h"
#include "rtt_input.h"
/* Example specific includes */
#include "app_config.h"
#include "example_common.h"
#include "nrf_mesh_config_examples.h"
#include "light_switch_example_common.h"
//#include "app_onoff.h"
#include "ble_softdevice_support.h"
//#define ONOFF_SERVER_0_LED (BSP_LED_0)
//#define APP_ONOFF_ELEMENT_INDEX (0)
#define ON_OFF_MODEL_ELEMENT_INDEX (0)
static bool m_device_provisioned= 0;
/*************************************************************************************************/
//probably bad practice, but this is model value
static uint8_t value_of_on_off_model=0;
static bool app_on_off_model_server_set_cb(const simple_on_off_server_t * p_server, uint8_t value);
static bool app_on_off_model_server_get_cb(const simple_on_off_server_t * p_server, uint8_t * p_present_value);
// Generic OnOff server structure definition and initialization
/*
APP_TEST_MODEL_SERVER_DEF(m_test_model_server_0,
app_test_model_server_set_cb,
app_test_model_server_get_cb)
*/
const simple_on_off_server_t m_on_off_model_server_0 =
{
.set_cb = app_on_off_model_server_set_cb,
.get_cb = app_on_off_model_server_get_cb
};
// Callback for updating the hardware state
//static void app_onoff_server_set_cb(const app_onoff_server_t * p_server, bool onoff)
static bool app_on_off_model_server_set_cb(const simple_on_off_server_t * p_server, uint8_t value)
{
// 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)
value_of_on_off_model=value;
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "exiting set_cb, value is: %d \n", value_of_on_off_model);
//hal_led_pin_set(ONOFF_SERVER_0_LED, onoff);
return true;
}
//m Callback for reading the hardware state
//static void app_onoff_server_get_cb(const app_onoff_server_t * p_server, bool * p_present_onoff)
static bool app_on_off_model_server_get_cb(const simple_on_off_server_t * p_server, uint8_t * p_present_value)
{
// Resolve the server instance here if required, this example uses only 1 instance.
*p_present_value=value_of_on_off_model;
//*p_present_onoff = hal_led_pin_get(ONOFF_SERVER_0_LED);
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "exiting get_cb, value is: %d \n", value_of_on_off_model);
return true;
}
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));
ERROR_CHECK(simple_on_off_server_init(&m_on_off_model_server_0, ON_OFF_MODEL_ELEMENT_INDEX));
//__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "App OnOff Model Handle: %d\n", m_onoff_server_0.server.model_handle);
}
/*************************************************************************************************/
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();
}
}
/*
static void app_rtt_input_handler(int key)
{
if (key >= '0' && key <= '4')
{
uint32_t button_number = key - '0';
button_event_handler(button_number);
}
}
*/
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 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
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);
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);
}
static void models_init_cb(void)
{
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");
app_model_init();
}
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
};
ERROR_CHECK(mesh_stack_init(&init_params, &m_device_provisioned));
}
static void initialize(void)
{
__LOG_INIT(LOG_SRC_APP | LOG_SRC_FRIEND, LOG_LEVEL_DBG1, LOG_CALLBACK_DEFAULT);
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- BLE Mesh Light Switch Server 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_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));
}
mesh_app_uuid_print(nrf_mesh_configure_device_uuid_get());
ERROR_CHECK(mesh_stack_start());
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 (;;)
{
(void)sd_app_evt_wait();
}
}