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

Adding Simple OnOff Model to Generic OnOff Server Example

Hello,

I'm using Mesh SDk4.0.0 and SD v7.0.1. I have tested the light switch client and server examples. 

Now I want to add some more models for additional functionality. I want to start with adding simple onOff model present in models\vendor\simple_on_off directory. But I could not find any documentation regarding the actual steps/process to achieve this. Can you guide me how to do that? 

I would also like to add simple message model for sending/receiving strings of data instead of 1/0. This will help me better expand the functionality. However, simple OnOff seems to be an easier point to start.

I have been reading how to create new model, it's a pretty good guide to get started with creating a model. But the guide doesn't describe how to integrate it into an app, or more favorably, how to create a new app from scratch and use this model, hence creating a base for a larger application.

Parents
  • Hi Aftab,

    I have just accomplished your first task - implementing SimpleOnOff Server into LightSwitchServer Example.

    I commented out the initialization of the GenericOnOffServer and I only initialize SimpleOnOffServer.

    In addition to modifying the main.c file, simple_on_off_server.c should be added to the folder structure of the solution and in project options include folder of SimpleOnOffServer must be added to user include directories of preprocessor. (I hope I did not forget anything).

    Below is the modified main.c file. All changes are noted with a comment //NOTE. Additionaly button 2 alternatively calls get and set callbacks for testing purposes.

    /* 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 <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 "generic_onoff_server.h"
    #include "simple_on_off_server.h" //NOTE Added.
    
    /* 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 ONOFF_SERVER_2_LED          (BSP_LED_2) //NOTE Added.
    #define APP_ONOFF_ELEMENT_INDEX     (0)
    
    static bool m_device_provisioned;
    
    uint8_t my_test_uint8_t = 0; //NOTE Added for testing.
    
    /*************************************************************************************************/
    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);
    
    
    /* Generic OnOff server structure definition and initialization */
    APP_ONOFF_SERVER_DEF(m_onoff_server_0,
                         APP_CONFIG_FORCE_SEGMENTATION,
                         APP_CONFIG_MIC_SIZE,
                         app_onoff_server_set_cb,
                         app_onoff_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)
    {
        /* 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);
    }
    
    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);
    }
    
    
    // NOTE define set and get callbacks
    // This callback is called when a message with opcode set (0xC1) is received. 
    // It sets selected output to received bool value, and returns the new bool value
    static bool my_simple_onoff_server_set_cb(const simple_on_off_server_t * p_self, bool onoff)
    {
      /* If there are more servers, resolve it here. See above. */
      __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "MySimpleOnOffServer set CB setting GPIO value: %d\n", onoff);
      hal_led_pin_set(ONOFF_SERVER_2_LED, onoff);
      return hal_led_pin_get(ONOFF_SERVER_2_LED);
    }
    
    // This callback is called when a message with opcode get (0xC2) is received.
    // It returns the state of the output.
    static bool my_simple_onoff_server_get_cb(const simple_on_off_server_t * p_self)
    {
      /* If there are more servers, resolve it here. See above. */
      __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "MySimpleOnOffServer get CB reporting value: %d\n", hal_led_pin_get(ONOFF_SERVER_2_LED));
      return hal_led_pin_get(ONOFF_SERVER_2_LED);
    }
    
    //NOTE instantiate my_simple_onoff_server_0
    static simple_on_off_server_t my_simple_onoff_server_0 =
    {
    	.model_handle = NULL, //model_handle of type access_model_handle_t will be provided by init function.
    	.get_cb = my_simple_onoff_server_get_cb, //Pointer to get callback function.
    	.set_cb = my_simple_onoff_server_set_cb  //Pointer to set callback function.
    };
    
    
    /*************************************************************************************************/
    
    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 button_event_handler(uint32_t button_number)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);
        switch (button_number)
        {
            /* Pressing SW1 on the Development Kit will result in LED state to toggle and trigger
            the STATUS message to inform client about the state change. This is a demonstration of
            state change publication due to local event. */
            case 0:
            {
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "User action \n");
                hal_led_pin_set(ONOFF_SERVER_0_LED, !hal_led_pin_get(ONOFF_SERVER_0_LED));
                app_onoff_status_publish(&m_onoff_server_0);
                break;
            }
    
            /* NOTE: Added: "Button 2" is my test button. */
            case 1:
            {
                // Test what callbacks do:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Test Button pressed: %u\n", ++my_test_uint8_t);
                switch (my_test_uint8_t & 1)
                {
                  case 0:
                  {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Will call CB set with param: %u\n", !hal_led_pin_get(ONOFF_SERVER_2_LED));
                    my_simple_onoff_server_set_cb(&my_simple_onoff_server_0, !hal_led_pin_get(ONOFF_SERVER_2_LED));
                    break;
                  }
                  case 1:
                  {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Will call CB get.\n");
                    bool my_test_bool;
                    my_test_bool = my_simple_onoff_server_get_cb(&my_simple_onoff_server_0);
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "CB get reporting: %u\n", my_test_bool);
                    break;
                  }
                }
    
              break;
            }
    
    
            /* NOTE Changed: Pressing "Button 3" i.e. SW2 changes "LED3" i.e. LED2 (And sends status change msg TODO later) */
            case 2:
            {
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Custom User action button 2\n");
                hal_led_pin_set(ONOFF_SERVER_2_LED, !hal_led_pin_get(ONOFF_SERVER_2_LED));
                ERROR_CHECK(simple_on_off_server_status_publish(&my_simple_onoff_server_0, hal_led_pin_get(ONOFF_SERVER_2_LED)));
                break;
            }
    
    
            /* Initiate node reset */
            case 3:
            {
                /* Clear all the states to reset the node. */
                if (mesh_stack_is_device_provisioned())
                {
    #if MESH_FEATURE_GATT_PROXY_ENABLED
                    (void) proxy_stop();
    #endif
                    mesh_stack_config_clear();
                    node_reset();
                }
                else
                {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "The device is unprovisioned. Resetting has no effect.\n");
                }
                break;
            }
    
            default:
                break;
        }
    }
    
    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");
        //NOTE Only SimpleOnOffServer will be initialized. To use both models, constants in nrf_mesh_config.h should be adjusted to allow more models.
        //app_model_init();
        ERROR_CHECK(simple_on_off_server_init(&my_simple_onoff_server_0, APP_ONOFF_ELEMENT_INDEX)); //NOTE Added
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "My Simple OnOff Model Handle: %d\n", my_simple_onoff_server_0.model_handle);
    }
    
    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");
                break;
            case NRF_SUCCESS:
                break;
            default:
                ERROR_CHECK(status);
        }
    }
    
    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();
        }
    }
    

    I did not implement the Client yet.

    I hope this helps.

    Best regards,
    Matevz

Reply
  • Hi Aftab,

    I have just accomplished your first task - implementing SimpleOnOff Server into LightSwitchServer Example.

    I commented out the initialization of the GenericOnOffServer and I only initialize SimpleOnOffServer.

    In addition to modifying the main.c file, simple_on_off_server.c should be added to the folder structure of the solution and in project options include folder of SimpleOnOffServer must be added to user include directories of preprocessor. (I hope I did not forget anything).

    Below is the modified main.c file. All changes are noted with a comment //NOTE. Additionaly button 2 alternatively calls get and set callbacks for testing purposes.

    /* 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 <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 "generic_onoff_server.h"
    #include "simple_on_off_server.h" //NOTE Added.
    
    /* 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 ONOFF_SERVER_2_LED          (BSP_LED_2) //NOTE Added.
    #define APP_ONOFF_ELEMENT_INDEX     (0)
    
    static bool m_device_provisioned;
    
    uint8_t my_test_uint8_t = 0; //NOTE Added for testing.
    
    /*************************************************************************************************/
    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);
    
    
    /* Generic OnOff server structure definition and initialization */
    APP_ONOFF_SERVER_DEF(m_onoff_server_0,
                         APP_CONFIG_FORCE_SEGMENTATION,
                         APP_CONFIG_MIC_SIZE,
                         app_onoff_server_set_cb,
                         app_onoff_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)
    {
        /* 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);
    }
    
    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);
    }
    
    
    // NOTE define set and get callbacks
    // This callback is called when a message with opcode set (0xC1) is received. 
    // It sets selected output to received bool value, and returns the new bool value
    static bool my_simple_onoff_server_set_cb(const simple_on_off_server_t * p_self, bool onoff)
    {
      /* If there are more servers, resolve it here. See above. */
      __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "MySimpleOnOffServer set CB setting GPIO value: %d\n", onoff);
      hal_led_pin_set(ONOFF_SERVER_2_LED, onoff);
      return hal_led_pin_get(ONOFF_SERVER_2_LED);
    }
    
    // This callback is called when a message with opcode get (0xC2) is received.
    // It returns the state of the output.
    static bool my_simple_onoff_server_get_cb(const simple_on_off_server_t * p_self)
    {
      /* If there are more servers, resolve it here. See above. */
      __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "MySimpleOnOffServer get CB reporting value: %d\n", hal_led_pin_get(ONOFF_SERVER_2_LED));
      return hal_led_pin_get(ONOFF_SERVER_2_LED);
    }
    
    //NOTE instantiate my_simple_onoff_server_0
    static simple_on_off_server_t my_simple_onoff_server_0 =
    {
    	.model_handle = NULL, //model_handle of type access_model_handle_t will be provided by init function.
    	.get_cb = my_simple_onoff_server_get_cb, //Pointer to get callback function.
    	.set_cb = my_simple_onoff_server_set_cb  //Pointer to set callback function.
    };
    
    
    /*************************************************************************************************/
    
    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 button_event_handler(uint32_t button_number)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);
        switch (button_number)
        {
            /* Pressing SW1 on the Development Kit will result in LED state to toggle and trigger
            the STATUS message to inform client about the state change. This is a demonstration of
            state change publication due to local event. */
            case 0:
            {
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "User action \n");
                hal_led_pin_set(ONOFF_SERVER_0_LED, !hal_led_pin_get(ONOFF_SERVER_0_LED));
                app_onoff_status_publish(&m_onoff_server_0);
                break;
            }
    
            /* NOTE: Added: "Button 2" is my test button. */
            case 1:
            {
                // Test what callbacks do:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Test Button pressed: %u\n", ++my_test_uint8_t);
                switch (my_test_uint8_t & 1)
                {
                  case 0:
                  {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Will call CB set with param: %u\n", !hal_led_pin_get(ONOFF_SERVER_2_LED));
                    my_simple_onoff_server_set_cb(&my_simple_onoff_server_0, !hal_led_pin_get(ONOFF_SERVER_2_LED));
                    break;
                  }
                  case 1:
                  {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Will call CB get.\n");
                    bool my_test_bool;
                    my_test_bool = my_simple_onoff_server_get_cb(&my_simple_onoff_server_0);
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "CB get reporting: %u\n", my_test_bool);
                    break;
                  }
                }
    
              break;
            }
    
    
            /* NOTE Changed: Pressing "Button 3" i.e. SW2 changes "LED3" i.e. LED2 (And sends status change msg TODO later) */
            case 2:
            {
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Custom User action button 2\n");
                hal_led_pin_set(ONOFF_SERVER_2_LED, !hal_led_pin_get(ONOFF_SERVER_2_LED));
                ERROR_CHECK(simple_on_off_server_status_publish(&my_simple_onoff_server_0, hal_led_pin_get(ONOFF_SERVER_2_LED)));
                break;
            }
    
    
            /* Initiate node reset */
            case 3:
            {
                /* Clear all the states to reset the node. */
                if (mesh_stack_is_device_provisioned())
                {
    #if MESH_FEATURE_GATT_PROXY_ENABLED
                    (void) proxy_stop();
    #endif
                    mesh_stack_config_clear();
                    node_reset();
                }
                else
                {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "The device is unprovisioned. Resetting has no effect.\n");
                }
                break;
            }
    
            default:
                break;
        }
    }
    
    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");
        //NOTE Only SimpleOnOffServer will be initialized. To use both models, constants in nrf_mesh_config.h should be adjusted to allow more models.
        //app_model_init();
        ERROR_CHECK(simple_on_off_server_init(&my_simple_onoff_server_0, APP_ONOFF_ELEMENT_INDEX)); //NOTE Added
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "My Simple OnOff Model Handle: %d\n", my_simple_onoff_server_0.model_handle);
    }
    
    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");
                break;
            case NRF_SUCCESS:
                break;
            default:
                ERROR_CHECK(status);
        }
    }
    
    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();
        }
    }
    

    I did not implement the Client yet.

    I hope this helps.

    Best regards,
    Matevz

Children
  • Thanks Matevz,

    Using this method I have added simple_onoff_model and tested it, working fine. I also added simple_message_server which seems working as provisioning is successful and can send data. But the data is not as expected. I was expecting a string but some garbage is being received.

    On sending data, in the my_simple_message_server_set_cb() function, I get response on RTT like:

    <t:    3497967>, main.c,  136, MySimpleMessageServer set CB scr=, dst= data: °, len: 2

    I'm attaching the project and simple_message_model files.

    mesh_light_server_modified_code.zip

    I have also noticed that in the Vendor Model Controls (nRF Mesh mobile app), Parameters does not allow to send data more than one byte, how to send a string through it?

  • I have tried to translate what I receive, this is what I receive:

     2392286>, main.c,  137, Á

    It seems that I receive character Á in the data field which is equivalent to 0xC1 hex. Hence I'm receiving the Opcode sent from Mesh app instead of actual data. Any pointer why I'm getting this?

  • There was error in initializing the model here:

    static void models_init_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");
        //NOTE Only SimpleOnOffServer will be initialized. To use both models, constants in nrf_mesh_config.h should be adjusted to allow more models.
        //app_model_init();
    //    ERROR_CHECK(simple_on_off_server_init(&my_simple_onoff_server_0, APP_ONOFF_ELEMENT_INDEX)); //NOTE Added
    //    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "My Simple OnOff Model Handle: %d\n", my_simple_onoff_server_0.model_handle);
        ERROR_CHECK(simple_message_server_init(&my_simple_message_server_0, APP_ONOFF_ELEMENT_INDEX)); //NOTE Added
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "My Simple Message Model Handle: %d\n", my_simple_message_server_0.model_handle);
    }

    After this, I was able to receive data from provisioner/mobile app.

Related