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
  • Actually, I am running into the same issue. I want to shoot off  button_event_handler(1) not from rtt_input_handler callback but from another function (e.g. main). When I do that, I get the same mesh assert. Interestingly, the first time it works (after provisioning). But after power cycling it (settings are loaded), this does not work and it gives the mesh error.

    I have tracked it down to net_state_seqnum_alloc where m_net_state.seqnum is = m_net_state.seqnum_max_available. Possibly this appears based on from which context the send function is run?

  • FYI I think I have found a solution; I am using Mesh SDK 2.2. Tracking down the mesh assert address, I found NRF_MESH_ASSERT_DEBUG(bearer_event_in_correct_irq_priority()); in timer_scheduler.c to be the critical section. After some research, I found https://devzone.nordicsemi.com/f/nordic-q-a/41645/error-nrf_error_invalid_state-when-send-data-via-mesh-3-0/163725 respectively https://devzone.nordicsemi.com/f/nordic-q-a/38479/mesh-sdk-2-2-0-bug-in-mesh_opt_core_adv_set/148935#148935 . Nesting the message publish code in sd_nvic_critical_region_enter (answer at the bottom) solves this for me.

  • 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
    
    

  • I have applied the patch by making changes in various files suggested but now, I can't provision the board and assign a publishing/subscribing address as the board has all the LED's ON when I flash it whereas flashing the code should blink the LED's twice and turn them OFF.  

    Even the RTT viewer isn't showing any error when I flash the board. Reset button resets the board but it enters the same state again. Buttons on the board have no effect on the application.

  • Hi,

    I have an update. I have this patch up and running. You suggest writing similar functions for the generic level messages that I am willing to publish?

  • Okay, Onoff/Level server messages are being published successfully.

    Can I ask if there is any such patch for the client models either generic on off/client?

    Thank you.

Reply Children
No Data
Related