diff --git a/examples/provisioner/CMakeLists.txt b/examples/provisioner/CMakeLists.txt index e60858743..d7b670b92 100644 --- a/examples/provisioner/CMakeLists.txt +++ b/examples/provisioner/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable(${target} ${WEAK_SOURCE_FILES} ${MESH_CORE_SOURCE_FILES} ${MESH_BEARER_SOURCE_FILES} + ${GENERIC_ONOFF_CLIENT_SOURCE_FILES} ${CONFIG_CLIENT_SOURCE_FILES} ${CONFIG_SERVER_SOURCE_FILES} ${HEALTH_SERVER_SOURCE_FILES} diff --git a/examples/provisioner/include/nrf_mesh_config_app.h b/examples/provisioner/include/nrf_mesh_config_app.h index c659c8a6f..779b69e00 100644 --- a/examples/provisioner/include/nrf_mesh_config_app.h +++ b/examples/provisioner/include/nrf_mesh_config_app.h @@ -97,7 +97,8 @@ #define ACCESS_MODEL_COUNT (1 + /* Configuration client */ \ 1 + /* Configuration server */ \ 1 + /* Health server */ \ - 1 /* Health client */) + 1 + /* Health client */ \ + 2 /* Generic OnOff client (2 groups) */) /** * The number of elements in the application. @@ -105,7 +106,8 @@ * @warning If the application is to support _multiple instances_ of the _same_ model, these instances * cannot be in the same element and a separate element is needed for each new instance of the same model. */ -#define ACCESS_ELEMENT_COUNT (1) /* Provisioner node has only 1 element */ +#define CLIENT_MODEL_INSTANCE_COUNT (2) +#define ACCESS_ELEMENT_COUNT (1 + CLIENT_MODEL_INSTANCE_COUNT) /* Provisioner node has only 1 element */ /** * The number of scene setup server instances used by the application. This is only used to @@ -165,7 +167,7 @@ /** Maximum number of non-virtual addresses. One for each of the servers and a group address. */ #define DSM_NONVIRTUAL_ADDR_MAX (1 + /* For self address. */\ GROUP_ADDR_COUNT + /* Group addresses. */\ - 2 * MAX_PROVISIONEE_NUMBER) + 2 * MAX_PROVISIONEE_NUMBER) /** @} end of DSM_CONFIG */ /** @} */ diff --git a/examples/provisioner/src/main.c b/examples/provisioner/src/main.c index 821a862d9..f15cd3afb 100644 --- a/examples/provisioner/src/main.c +++ b/examples/provisioner/src/main.c @@ -65,6 +65,7 @@ #include "config_client.h" #include "config_server.h" #include "health_client.h" +#include "generic_onoff_client.h" /* Logging and RTT */ #include "rtt_input.h" @@ -97,6 +98,107 @@ static void app_mesh_core_event_cb (const nrf_mesh_evt_t * p_evt); static void app_start(void); + + + +/***************************************************************************** + * 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]; + +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 +}; + +/* 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(HAL_LED_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 variables *****************************************************************************/ @@ -365,6 +467,7 @@ static const char m_usage_string[] = "\n" "\t\t--------------------------------------------------------------------------------\n" "\t\t Button/RTT 1) Initiate provisioning and configuration of unprovisioned devices.\n" + "\t\t Button/RTT 3) Send Generic OnOff Set Unack message. \n" "\t\t Button/RTT 4) Clear all the states to reset the node.\n" "\t\t--------------------------------------------------------------------------------\n"; #endif @@ -389,6 +492,32 @@ static void button_event_handler(uint32_t button_number) break; } + case 3: + { + uint32_t status; + static bool state; + generic_onoff_set_params_t set_params = { + .on_off = state ? APP_STATE_ON : APP_STATE_OFF, + }; + model_transition_t transition_params; + static uint8_t tid = 0; + + state = !state; + + 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); + + status = generic_onoff_client_set_unack(&m_clients[0], &set_params, + &transition_params, APP_UNACK_MSG_REPEAT_COUNT); + __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Client send status: %d\n", status); + status = generic_onoff_client_set_unack(&m_clients[1], &set_params, + &transition_params, APP_UNACK_MSG_REPEAT_COUNT); + __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Client send status: %d\n", status); + break; + } + /* Initiate node reset */ case 4: { @@ -433,6 +562,16 @@ void models_init_cb(void) * health client : To be able to interact with other health servers */ ERROR_CHECK(config_client_init(app_config_client_event_cb)); ERROR_CHECK(health_client_init(&m_dev_handles.m_health_client_instance, 0, app_health_event_cb)); + + for (uint32_t i = 0; i < CLIENT_MODEL_INSTANCE_COUNT; ++i) + { + m_clients[i].settings.p_callbacks = &client_cbs; + m_clients[i].settings.timeout = 0; + m_clients[i].settings.force_segmented = APP_FORCE_SEGMENTATION; + m_clients[i].settings.transmic_size = APP_MIC_SIZE; + + ERROR_CHECK(generic_onoff_client_init(&m_clients[i], i + 1)); + } } static void mesh_init(void) @@ -482,6 +621,40 @@ static void mesh_init(void) prov_helper_provision_self(); app_default_models_bind_setup(); app_data_store_cb(); + + for (uint32_t i = 0; i < CLIENT_MODEL_INSTANCE_COUNT; ++i) + { + /** Configure Model Subscription. */ + dsm_handle_t subscription_address_handle; + uint32_t subscription_address = ((i + 1) & 1) ? SERVER_PUB_GROUP_ADDRESS_EVEN : SERVER_PUB_GROUP_ADDRESS_ODD; + ERROR_CHECK(dsm_address_subscription_add(subscription_address, &subscription_address_handle)); + ERROR_CHECK(access_model_subscription_add(m_clients[i].model_handle, subscription_address_handle)); + + /** Configure Model Publication. */ + uint32_t publish_address = ((i + 1) & 1) ? CLIENT_PUB_GROUP_ADDRESS_EVEN : CLIENT_PUB_GROUP_ADDRESS_ODD; + dsm_handle_t publish_address_handle = DSM_HANDLE_INVALID; + + ERROR_CHECK(dsm_address_publish_add(publish_address, &publish_address_handle)); + + access_publish_period_t publish_period = + { + .step_num = 1, + .step_res = ACCESS_PUBLISH_RESOLUTION_10S + }; + access_publish_retransmit_t publish_retransmit = + { + .count = 1, + .interval_steps = 0, + }; + dsm_handle_t publish_appkey_handle = dsm_appkey_index_to_appkey_handle(APPKEY_INDEX); + + ERROR_CHECK(access_model_publish_retransmit_set(m_clients[i].model_handle, publish_retransmit)); + ERROR_CHECK(access_model_publish_address_set(m_clients[i].model_handle, publish_address_handle)); + ERROR_CHECK(access_model_publish_application_set(m_clients[i].model_handle, publish_appkey_handle)); + ERROR_CHECK(access_model_publish_ttl_set(m_clients[i].model_handle, ACCESS_DEFAULT_TTL)); + ERROR_CHECK(access_model_publish_period_set(m_clients[i].model_handle, (access_publish_resolution_t) publish_period.step_res, publish_period.step_num)); + + } } else {