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

Issue with Sending generic level messages from main()

Hi,

I am working with a motion sensor which sends a message when it detects a motion. I am communicating between the nRF52 DK and the sensor via UART. I am able to receive messages correctly. I am using the experimental_dimming_client example and I tried to send a generic level message whenever the sensor detects the motion. I added the UART library and added the functionality to send generic level messages upon detecting motion in the main() as follows:

for (;;)
    {
        uint8_t cr;
        while(app_uart_get(&cr) != NRF_SUCCESS);
        while(app_uart_put(cr) != NRF_SUCCESS);

        if(cr == 'M')
        {
            button_event_handler(1);
        }

        (void)sd_app_evt_wait();
    }

M indicates motion and button event handler sends the generic level messages.

Here comes the issue:

I haven't provisioned the board yet. When a motion is detected, the board is able to execute the the button_event_handler function for case 1 which is sending a set message.

Now I provisioned the device(didn't set the publication address). For these two situations, output looks like this:

When I add the publication address, it asserts an error: 

app_error_weak.c,  108, Mesh assert at 0x0002AEC6 (:0)

After this, I went back to the stock SDK and tried to send generic level messages from the main function (without UART) which resulted in a Mesh error 15 (Forbidden Command)

I have been trying to debug and find why I am unable to publish messages to an address from the main() but I am not successful yet.

What might be the reason? Any ideas on how to resolve it?

Thank you.

Parents Reply Children
  • Hi,

    Thanks for the reply. I tried making the changes to the mesh_stack.c file mentioned in the links above. I even tried calling mesh_opt_core_adv_set() function inside static void start(void) function only before mesh_stack_start() call and also in the mesh_stack.c between calls sd_nvic_critical_region_enter()/_exit().

    Adding these lines results in a Forbidden Command error 15 as shown below:

    I also added following lines in mesh_stack.c

    uint8_t is_nested;
    ERROR_CHECK(sd_nvic_critical_region_enter(&is_nested));

    mesh_opt_core_adv_set(CORE_TX_ROLE_ORIGINATOR, &net);

    ERROR_CHECK(sd_nvic_critical_region_exit(is_nested));

    Because I am using Mesh SDK 3.0.0, this solution isn't applicable. May be the support team know a better way to fix this issue.

    Thanks for your response pirast.

  • If I made any error in adding the lines to the code, kindly correct me.

    Thank you.

  • Might be that the messages are being sent too fast, can you try waiting for the NRF_MESH_EVT_TX_COMPLETE before sending a new message?

    Also, instead of running it in the for-loop you could create an interrupt that triggers whenever the sensor detects motion.

  • instead of running it in the for-loop you could create an interrupt that triggers whenever the sensor detects motion.

    That was the first thing that I did if you can see the question that I posted, I tried to send a generic level message upon receiving an indication from the sensor using UART that motion is detected.

    Might be that the messages are being sent too fast, can you try waiting for the NRF_MESH_EVT_TX_COMPLETE before sending a new message?

    I might have taken it that way already if the program crashes while sending the second message after successfully transmitting the first. But, I am unable to transfer the first message itself. 

    I also tried another thing, used the EnOcean switch example, instead of sending generic OnOff messages, I tried sending generic Level messages. They are transmitted without any error inside the app_switch_debounce().

    Why can these messages be transmitted from app_switch_debounce() in EnOcean example, but not from the main() in any example?

  • Hi,

    One of our developers from the Mesh team have made a patch to help you with this issue:

    The mesh stack will assert if Mesh APIs are not called from correct priority. In the thread mode of operation, it is not sufficient to only change the priority setting during mesh stack initialization. The application also needs to use app scheduler and ensure that softdevice events are dispatched using app scheduler.

    Apply this patch on the 3.1.0 release source. This patch will modify the example (light-switch-server) and model files to show following things:

    How to use thread mode of operation in the examples?:

    1. Adds app scheduler to the application (adds necessary sources/headers  to cmakelists and initialization code)

    2. Sends a mesh message from main loop as a demonstration (periodically turns off the LED on the server and publishes a status).

    3. Modifications required to handle button press events to correctly call mesh APIs from the thread priority. Shows the use of app scheduler.

    Date: Fri, 8 Feb 2019 13:20:11 +0100
    Subject: [PATCH] MBTLE-0000: Demonstrate thread mode. Demonstrate delayed
     reply.
    
    ---
     examples/common/include/app_onoff.h           | 16 ++++++
     examples/common/src/app_onoff.c               | 21 +++++++
     examples/light_switch/server/CMakeLists.txt   |  2 +
     .../light_switch/server/include/app_config.h  |  4 ++
     examples/light_switch/server/src/main.c       | 57 ++++++++++++++++++-
     .../include/generic_onoff_server.h            | 18 ++++++
     .../generic_onoff/src/generic_onoff_server.c  | 17 ++++++
     7 files changed, 132 insertions(+), 3 deletions(-)
    
    diff --git a/examples/common/include/app_onoff.h b/examples/common/include/app_onoff.h
    index b5650f6c9..b5feac6b1 100644
    --- a/examples/common/include/app_onoff.h
    +++ b/examples/common/include/app_onoff.h
    @@ -174,6 +174,20 @@ struct __app_onoff_server_t
      */
     void app_onoff_status_publish(app_onoff_server_t * p_server);
     
    +/** Sends another but delayed status message in response to the previously received message from the
    + * certain source.
    + *
    + * The appkey_handle, subnet_handle, and dst address are obtained from the previously received
    + * access message meta data.
    + *
    + * Call to this function initiates value fetch from the user application by calling a get callback,
    + * updates internal state, and publishes the Generic OnOff Status message, if non-zero src address is
    + * available in the previously received metadata.
    + *
    + * @param[in] p_server              Pointer to @ref __app_onoff_server_t [app_onoff_server_t] context
    + */
    +void app_onoff_delayed_status_reply(app_onoff_server_t * p_server);
    +
     /** Initializes the behavioral module for the generic OnOff model
      *
      * @param[in] p_server               Pointer to the application OnOff server struture array.
    @@ -188,5 +202,7 @@ void app_onoff_status_publish(app_onoff_server_t * p_server);
     */
     uint32_t app_onoff_init(app_onoff_server_t * p_server, uint8_t element_index);
     
    +
    +
     /** @} end of APP_ONOFF */
     #endif /* APP_ONOFF_H__ */
    diff --git a/examples/common/src/app_onoff.c b/examples/common/src/app_onoff.c
    index 50e094759..d36e413d9 100644
    --- a/examples/common/src/app_onoff.c
    +++ b/examples/common/src/app_onoff.c
    @@ -251,6 +251,27 @@ void app_onoff_status_publish(app_onoff_server_t * p_server)
         (void) generic_onoff_server_status_publish(&p_server->server, &status);
     }
     
    +void app_onoff_delayed_status_reply(app_onoff_server_t * p_server)
    +{
    +    if (p_server->server.last_access_meta.src.value == NRF_MESH_ADDR_UNASSIGNED)
    +    {
    +        return;
    +    }
    +
    +    p_server->onoff_get_cb(p_server, &p_server->state.present_onoff);
    +
    +    p_server->state.target_onoff = p_server->state.present_onoff;
    +    p_server->state.delay_ms = 0;
    +    p_server->state.remaining_time_ms = 0;
    +
    +    generic_onoff_status_params_t status = {
    +                .present_on_off = p_server->state.present_onoff,
    +                .target_on_off = p_server->state.target_onoff,
    +                .remaining_time_ms = p_server->state.remaining_time_ms
    +            };
    +    (void) generic_onoff_server_delayed_status_send(&p_server->server, &status);
    +}
    +
     uint32_t app_onoff_init(app_onoff_server_t * p_server, uint8_t element_index)
     {
         uint32_t status = NRF_ERROR_INTERNAL;
    diff --git a/examples/light_switch/server/CMakeLists.txt b/examples/light_switch/server/CMakeLists.txt
    index a05254243..1e858dde6 100644
    --- a/examples/light_switch/server/CMakeLists.txt
    +++ b/examples/light_switch/server/CMakeLists.txt
    @@ -8,6 +8,7 @@ add_executable(${target}
         "${MBTLE_SOURCE_DIR}/examples/common/src/rtt_input.c"
         "${CMAKE_SOURCE_DIR}/examples/common/src/simple_hal.c"
         "${CMAKE_SOURCE_DIR}/examples/common/src/mesh_app_utils.c"
    +    "${SDK_ROOT}/components/libraries/scheduler/app_scheduler.c"
         ${BLE_SOFTDEVICE_SUPPORT_SOURCE_FILES}
         ${WEAK_SOURCE_FILES}
         ${MESH_CORE_SOURCE_FILES}
    @@ -30,6 +31,7 @@ target_include_directories(${target} PUBLIC
         "${CMAKE_CURRENT_SOURCE_DIR}/../include"
         "${CMAKE_SOURCE_DIR}/examples/common/include"
         "${CMAKE_SOURCE_DIR}/external/rtt/include"
    +    "${SDK_ROOT}/components/libraries/scheduler"
         ${BLE_SOFTDEVICE_SUPPORT_INCLUDE_DIRS}
         ${CONFIG_SERVER_INCLUDE_DIRS}
         ${HEALTH_SERVER_INCLUDE_DIRS}
    diff --git a/examples/light_switch/server/include/app_config.h b/examples/light_switch/server/include/app_config.h
    index bea884968..867738ceb 100644
    --- a/examples/light_switch/server/include/app_config.h
    +++ b/examples/light_switch/server/include/app_config.h
    @@ -77,6 +77,10 @@
     #define APP_TIMER_ENABLED 1
     #define APP_TIMER_KEEPS_RTC_ACTIVE 1
     
    +#define APP_SCHEDULER_ENABLED 1
    +#define NRF_SDH_DISPATCH_MODEL 1
    +#define APP_TIMER_CONFIG_USE_SCHEDULER 1
    +
     /** @} end of APP_SDK_CONFIG */
     
     #endif /* APP_CONFIG_H__ */
    diff --git a/examples/light_switch/server/src/main.c b/examples/light_switch/server/src/main.c
    index 5ccdf76fd..c1651b12b 100644
    --- a/examples/light_switch/server/src/main.c
    +++ b/examples/light_switch/server/src/main.c
    @@ -71,10 +71,21 @@
     #include "light_switch_example_common.h"
     #include "app_onoff.h"
     #include "ble_softdevice_support.h"
    +#include "app_scheduler.h"
     
     #define ONOFF_SERVER_0_LED          (BSP_LED_0)
     #define APP_ONOFF_ELEMENT_INDEX     (0)
     
    +/* Select max event size. This must be large enough for app timer events as well.
    + * uint8_t => button number variable
    + * APP_TIMER_SCHED_EVENT_DATA_SIZE => App timer event
    + */
    +#define APP_SCHED_EVENT_SIZE        MAX(sizeof(uint8_t), APP_TIMER_SCHED_EVENT_DATA_SIZE)
    +#define APP_SCHED_QUEUE_SIZE        (50)
    +
    +#define APP_MAIN_AUTO_OFF_FACTOR    (1000)
    +#define LED_OFF                     (0)
    +
     static bool m_device_provisioned;
     
     /*************************************************************************************************/
    @@ -147,6 +158,14 @@ static void button_event_handler(uint32_t button_number)
                 break;
             }
     
    +        /* Demonstration: Send a delayed status message */
    +        case 1:
    +        {
    +            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Sending delayed response \n");
    +            app_onoff_delayed_status_reply(&m_onoff_server_0);
    +            break;
    +        }
    +
             /* Initiate node reset */
             case 3:
             {
    @@ -171,6 +190,21 @@ static void button_event_handler(uint32_t button_number)
         }
     }
     
    +static void button_event_handler_app_sched(void * p_event_data, uint16_t event_size)
    +{
    +    uint8_t * button_number = (uint8_t *) p_event_data;
    +    NRF_MESH_ASSERT(event_size == 1);
    +    button_event_handler(*button_number);
    +}
    +
    +static void button_event_handler_irq(uint32_t button_number)
    +{
    +    static uint8_t bt_num;
    +
    +    bt_num = button_number;
    +    app_sched_event_put((void *)&bt_num, sizeof(bt_num), button_event_handler_app_sched);
    +}
    +
     static void app_rtt_input_handler(int key)
     {
         if (key >= '0' && key <= '4')
    @@ -223,7 +257,8 @@ static void mesh_init(void)
     {
         mesh_stack_init_params_t init_params =
         {
    -        .core.irq_priority       = NRF_MESH_IRQ_PRIORITY_LOWEST,
    +        .core.irq_priority       = NRF_MESH_IRQ_PRIORITY_THREAD,
    +        //.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,
    @@ -241,7 +276,7 @@ static void initialize(void)
         hal_leds_init();
     
     #if BUTTON_BOARD
    -    ERROR_CHECK(hal_buttons_init(button_event_handler));
    +    ERROR_CHECK(hal_buttons_init(button_event_handler_irq));
     #endif
     
         ble_stack_init();
    @@ -283,11 +318,27 @@ static void start(void)
     
     int main(void)
     {
    +    APP_SCHED_INIT(APP_SCHED_EVENT_SIZE, APP_SCHED_QUEUE_SIZE);
         initialize();
         start();
     
    +    int i = 0;
         for (;;)
         {
    -        (void)sd_app_evt_wait();
    +        app_sched_execute();
    +
    +        bool done = nrf_mesh_process();
    +        if (done)
    +        {
    +            (void)sd_app_evt_wait();
    +        }
    +        /* Demonstrate sending of messages from main loop, by automatically turning off the LED
    +         * after few iterations. */
    +        i++;
    +        if ((i % APP_MAIN_AUTO_OFF_FACTOR) == 0)
    +        {
    +            hal_led_pin_set(ONOFF_SERVER_0_LED, LED_OFF);
    +            app_onoff_status_publish(&m_onoff_server_0);
    +        }
         }
     }
    diff --git a/models/model_spec/generic_onoff/include/generic_onoff_server.h b/models/model_spec/generic_onoff/include/generic_onoff_server.h
    index 5692ae6bb..11588f56c 100644
    --- a/models/model_spec/generic_onoff/include/generic_onoff_server.h
    +++ b/models/model_spec/generic_onoff/include/generic_onoff_server.h
    @@ -126,6 +126,9 @@ struct __generic_onoff_server_t
     
         /** Model settings and callbacks for this instance. */
         generic_onoff_server_settings_t settings;
    +
    +    /** Holding variable for the access metadata for previously received message */
    +    access_message_rx_meta_t last_access_meta;
     };
     
     /**
    @@ -154,5 +157,20 @@ uint32_t generic_onoff_server_init(generic_onoff_server_t * p_server, uint8_t el
      */
     uint32_t generic_onoff_server_status_publish(generic_onoff_server_t * p_server, const generic_onoff_status_params_t * p_params);
     
    +/**
    + * Publishes a delayed status message.
    + *
    + * This function can be used to publish a repeat delayed status message after user application has
    + * finished any custom processing on the received state value. This function will inturn fetch the
    + * current onoff state using get_cb callback.
    + *
    + * @param[in]     p_server                 Status server context pointer.
    + * @param[in]     p_params                 Message parameters.
    + *
    + */
    +uint32_t generic_onoff_server_delayed_status_send(generic_onoff_server_t * p_server,
    +                                                  const generic_onoff_status_params_t * p_params);
    +
    +
     /**@} end of GENERIC_ONOFF_SERVER */
     #endif /* GENERIC_ONOFF_SERVER_H__ */
    diff --git a/models/model_spec/generic_onoff/src/generic_onoff_server.c b/models/model_spec/generic_onoff/src/generic_onoff_server.c
    index 2448a9ad4..2cb7af275 100644
    --- a/models/model_spec/generic_onoff/src/generic_onoff_server.c
    +++ b/models/model_spec/generic_onoff/src/generic_onoff_server.c
    @@ -137,6 +137,7 @@ static void handle_set(access_model_handle_t model_handle, const access_message_
                     __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Server: delay_ms = %X\n", in_data_tr.delay_ms);
                 }
     
    +            p_server->last_access_meta = p_rx_msg->meta_data;
                 p_server->settings.p_callbacks->onoff_cbs.set_cb(p_server,
                                                                 &p_rx_msg->meta_data,
                                                                 &in_data,
    @@ -163,6 +164,7 @@ static void handle_get(access_model_handle_t model_handle, const access_message_
     
         if (get_params_validate(p_rx_msg))
         {
    +        p_server->last_access_meta = p_rx_msg->meta_data;
             p_server->settings.p_callbacks->onoff_cbs.get_cb(p_server, &p_rx_msg->meta_data, &out_data);
             (void) status_send(p_server, p_rx_msg, &out_data);
         }
    @@ -217,3 +219,18 @@ uint32_t generic_onoff_server_status_publish(generic_onoff_server_t * p_server,
     
         return status_send(p_server, NULL, p_params);
     }
    +
    +uint32_t generic_onoff_server_delayed_status_send(generic_onoff_server_t * p_server,
    +                                                  const generic_onoff_status_params_t * p_params)
    +{
    +    if (p_server == NULL ||
    +        p_params == NULL)
    +    {
    +        return NRF_ERROR_NULL;
    +    }
    +
    +    access_message_rx_t rx_message_ctx;
    +
    +    rx_message_ctx.meta_data = p_server->last_access_meta;
    +    return status_send(p_server, &rx_message_ctx, p_params);
    +}
    \ No newline at end of file
    -- 
    2.17.1.windows.2
    
    

Related