This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Use p_event_data parameter of app_sched_event_put to pass just a uint32_t value to the handler parameter

I'm using SDK17.1 and pca10056 DK board. I want to use app_sched_event_put for a very simple purpose. I start a one second clock whose timeout handler increments a static local uint32_t counter. The timeout handler then uses app_sched_event_put to transfer the uint32_t one second counter's value, not it's address, to the app_sched_event_put's handler. Unfortunately, the handler's void *p_event_data looks like an address even after doing a (uint32_t)p_event_data cast.

Code sample followed by some RTTViewer output.

static bool main_loop_started = false;

// Scheduler settings
#define SCHED_MAX_EVENT_DATA_SIZE   APP_TIMER_SCHED_EVENT_DATA_SIZE
#define SCHED_QUEUE_SIZE            16

APP_TIMER_DEF(m_our_app_timer_id);
#define TIMER_INTERVAL   APP_TIMER_TICKS(1000)   // every 1000 msecs


void timer_timeout_action(void *p_event_data, uint16_t event_size)
{
    uint32_t loop_count = (uint32_t)p_event_data;
    NRF_LOG_INFO("        timeout_action:  p_event_data = %d  loop_count = %d", p_event_data, loop_count);
}


static void timer_timeout_handler(void * p_context)
{
    static uint32_t loop_count = 0;

    ++loop_count;

    if (main_loop_started)
    {
        app_sched_event_put((void *)loop_count, 0, timer_timeout_action);
        NRF_LOG_INFO("timeout_handler: &loop_count = %d  loop_count = %d", &loop_count, loop_count);
    }
}


static void timers_init(void)
{
    ret_code_t err_code;

    // Make sure the LF clock is running
    err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);
    nrf_drv_clock_lfclk_request(NULL);
    nrfx_clock_lfclk_start();

    // Initialize timer module
    err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);

    // Create timers
    err_code = app_timer_create(&m_our_app_timer_id, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
    APP_ERROR_CHECK(err_code);
}


static void application_timers_start(void)
{
    ret_code_t err_code;
    err_code = app_timer_start(m_our_app_timer_id, TIMER_INTERVAL, NULL);
    APP_ERROR_CHECK(err_code);
}


static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(get_Nordic_rtc_counter);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}


static void power_management_init(void)
{
    ret_code_t err_code;
    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
}


static void idle_state_handler(void)
{
    if (NRF_LOG_PROCESS() == false)
    {
        nrf_pwr_mgmt_run();
    }
}


int main(void)
{
    ret_code_t err_code;

    // Initialize
    APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
    log_init();

    timers_init();

    application_timers_start();

    power_management_init();

    NRF_LOG_INFO("DevKit APP Schedular practice started.\n");

    // Enter main loop.
    main_loop_started = true;
    for (;;)
    {
        app_sched_execute();
        idle_state_handler();
    }
}

00> [00:00:43.000,000] <info> app: timeout_handler: &loop_count = 536873844  loop_count = 43
00> [00:00:43.000,061] <info> app:         timeout_action:  p_event_data = 536874048  loop_count = 536874048
00> [00:00:44.000,000] <info> app: timeout_handler: &loop_count = 536873844  loop_count = 44
00> [00:00:44.000,061] <info> app:         timeout_action:  p_event_data = 536874056  loop_count = 536874056
00> [00:00:45.000,000] <info> app: timeout_handler: &loop_count = 536873844  loop_count = 45
00> [00:00:45.000,061] <info> app:         timeout_action:  p_event_data = 536874064  loop_count = 536874064
00> [00:00:46.000,000] <info> app: timeout_handler: &loop_count = 536873844  loop_count = 46
00> [00:00:46.000,061] <info> app:         timeout_action:  p_event_data = 536874072  loop_count = 536874072
00> [00:00:47.000,000] <info> app: timeout_handler: &loop_count = 536873844  loop_count = 47
00> [00:00:47.000,061] <info> app:         timeout_action:  p_event_data = 536874080  loop_count = 536874080
00> [00:00:48.000,000] <info> app: timeout_handler: &loop_count = 536873844  loop_count = 48
00> [00:00:48.000,061] <info> app:         timeout_action:  p_event_data = 536874088  loop_count = 536874088
00> [00:00:49.000,000] <info> app: timeout_handler: &loop_count = 536873844  loop_count = 49
00> [00:00:49.000,061] <info> app:         timeout_action:  p_event_data = 536874096  loop_count = 536874096
00> [00:00:50.000,000] <info> app: timeout_handler: &loop_count = 536873844  loop_count = 50
00> [00:00:50.000,061] <info> app:         timeout_action:  p_event_data = 536874104  loop_count = 536874104

As you can see from the RTTViewer output, the timer_timeout_action's void *p_event_data isn't loop_count's value.

Can I use the app_sched_event_put's p_event_data pointer's memory slot to hold a single uint32_t value and pass it as such to the handler?

I'm motivated to do this because if app_sched_execute starts a process that takes longer than a second, I could wind up with two events in the queue pointing to the same value, (the increment of the increment), instead of two different values, (the current increment and the previous increment).

I would like to add that providing a sizeof(uint32_t) as app_sched_event_put's 2nd parameter doesn't change the outcome.

Parents
  • Hi Matty, 

    Could you let me know why you only want to have the value but not the pointer  ? 
    Our design of the app_sched module is that it would be able to accept any data that feed into app_sched_event_put() and be able to deliver that data to the handler() later on when it's executed in main context. This is the reason we use a pointer. So that the function only need to know the address and the size of the data. 

    Do you see any problem converting the pointer back to the value ? 

    By the way when you do  app_sched_event_put((void *)loop_count, 0, timer_timeout_action);, you should choose the correct event_data_size instead of 0 as you are using now. 

    So you should have something like this: 

     app_sched_event_put(&loop_count, sizeof(loop_count), timer_timeout_action);

  • Hi Hung, Thanks for the reply. Let me try to go through it step by step.

    Could you let me know why you only want to have the value but not the pointer  ? 

    This is a Proof of Concept. My thinking is that there is already a pointer, a 32bit register, allocated to the app_sched_event_put call and that is all I need for the information I want to get across to the handler,

    My motivation is to avoid passing inaccurate information to the handler. For my application, it is conceivable that some other interrupt context could do an app_sched_event_put that initiates a main context process that takes longer than 1 second.

    For me, the value of the one second counter, (loop_count), is important. Lets start at the beginning where loop_count is zero, line 20.

    A timer interrupt triggers timer_timeout_handler which increments loop_count to 1.

    timer_timeout_handler() calls app_sched_event_put() to place the timer_timeout_action call on the app_scheduler queue, with a pointer to loop_count instead of loop_count's value of 1.

    app_sched_execute() in the main forever loop doles out some other app_scheduler events that will take more than a second to complete.

    In the meantime, another timer interrupt occurs and timer_timeout_handler() increments loop_count to 2.

    timer_timeout_handler() calls app_sched_event_put() to place the timer_timeout_action call on the app_scheduler queue, with a pointer to loop_count instead of it's value of 2.

    app_sched_execute() and the app_scheduler finally get to the first timer_timeout_action() call in the queue and call it.

    timer_timeout_action() will get a value of 2 delivered to it and not a value of 1,

    Then app_sched_execute() and the app_scheduler will send the 2nd queued up timer_timeout_action() call.

    timer_timeout_action() will get another value of 2 delivered to it.

    For me, the value of loop_count delivered to timer_timeout_action() by the app_scheduler is important because timer_timeout_action() will use it in a context specific manner. timer_timeout_action() needs to know that the loop_count value is actually 1 in the first queued message and that loop_count's value is 2 in the second queued message.

    Does this answer your question?

    By the way when you do  app_sched_event_put((void *)loop_count, 0, timer_timeout_action);, you should choose the correct event_data_size instead of 0 as you are using now. 

    The size passed in app_sched_event_put() is the size of the data that the pointer points to. I would have thought that when the pointer is the data and doesn't point to anything then the size is zero.

    Also I have tried specifying a sizeof(uint32_t) to no avail.

  • In the following simple case where I use nrf_delay_ms(4500) periodically in the forever loop to simulate some other app_scheduler events that will take more than a second to complete, it looks like my fears are unwarranted. Since app_sched_event_put() is not using the same pointer for loop_count in each queued message, the unique value for each loop_count iteration is kept on the queue and passed to the handler.

    static bool main_loop_started = false;
    static uint32_t m_count = 0;
    
    // Scheduler settings
    #define SCHED_MAX_EVENT_DATA_SIZE   APP_TIMER_SCHED_EVENT_DATA_SIZE
    #define SCHED_QUEUE_SIZE            16
    
    APP_TIMER_DEF(m_our_app_timer_id);
    #define TIMER_INTERVAL   APP_TIMER_TICKS(1000)   // every 1000 msecs
    
    
    void timer_timeout_action(void *p_event_data, uint16_t event_size)
    {
        uint32_t *loop_count = (uint32_t *)p_event_data;
        NRF_LOG_INFO("       timeout_action:  loop_count = %d  *loop_count = %d", loop_count, *loop_count);
        display_result (*loop_count);  // In another module and just does a NRF_LOG_INFO.
    }
    
    
    static void timer_timeout_handler(void * p_context)
    {
        static uint32_t loop_count = 0;
    
        ++loop_count;
    
        if (main_loop_started)
        {
            app_sched_event_put((void *)(&loop_count), sizeof(uint32_t), timer_timeout_action);
            m_count++;
            NRF_LOG_INFO("timeout_handler: &loop_count = %d  loop_count = %d", &loop_count, loop_count);
        }
    }
    
    
    static void timers_init(void)
    {
        ret_code_t err_code;
    
        // Make sure the LF clock is running
        err_code = nrf_drv_clock_init();
        APP_ERROR_CHECK(err_code);
        nrf_drv_clock_lfclk_request(NULL);
        nrfx_clock_lfclk_start();
    
        // Initialize timer module
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
        // Create timers
        err_code = app_timer_create(&m_our_app_timer_id, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    static void application_timers_start(void)
    {
        ret_code_t err_code;
        err_code = app_timer_start(m_our_app_timer_id, TIMER_INTERVAL, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(get_Nordic_rtc_counter);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    static void power_management_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    static void idle_state_handler(void)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    
    int main(void)
    {
        ret_code_t err_code;
    
        // Initialize
        APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
        log_init();
    
        timers_init();
    
        application_timers_start();
    
        power_management_init();
    
        NRF_LOG_INFO("DevKit APP Schedular practice started.\n");
    
        // Enter main loop.
        main_loop_started = true;
        for (;;)
        {
            app_sched_execute();
            if (!(m_count % 15))
                nrf_delay_ms(4500);
            idle_state_handler();
        }
    }

    00> [00:00:44.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 44
    00> [00:00:44.000,000] <info> app:        timeout_action:  loop_count = 536873956  *loop_count = 44
    00> [00:00:44.000,000] <info> rtclk:             m_result = 44
    00> [00:00:45.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 45
    00> [00:00:45.000,000] <info> app:        timeout_action:  loop_count = 536873964  *loop_count = 45
    00> [00:00:45.000,000] <info> rtclk:             m_result = 45
    00> [00:00:46.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 46
    00> [00:00:47.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 47
    00> [00:00:48.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 48
    00> [00:00:49.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 49
    00> [00:00:49.466,796] <info> app:        timeout_action:  loop_count = 536873972  *loop_count = 46
    00> [00:00:49.466,796] <info> rtclk:             m_result = 46
    00> [00:00:49.466,796] <info> app:        timeout_action:  loop_count = 536873980  *loop_count = 47
    00> [00:00:49.466,857] <info> rtclk:             m_result = 47
    00> [00:00:49.466,857] <info> app:        timeout_action:  loop_count = 536873988  *loop_count = 48
    00> [00:00:49.466,857] <info> rtclk:             m_result = 48
    00> [00:00:49.466,857] <info> app:        timeout_action:  loop_count = 536873996  *loop_count = 49
    00> [00:00:49.466,857] <info> rtclk:             m_result = 49
    00> [00:00:50.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 50
    00> [00:00:50.000,000] <info> app:        timeout_action:  loop_count = 536874004  *loop_count = 50
    00> [00:00:50.000,000] <info> rtclk:             m_result = 50
    00> [00:00:51.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 51
    00> [00:00:51.000,000] <info> app:        timeout_action:  loop_count = 536874012  *loop_count = 51
    00> [00:00:51.000,000] <info> rtclk:             m_result = 51
    

    During the 4.5 second delay, you can see the 4 timer_timeout_handler() calls where loop_count is being incremented and timer_timeout_action() is being put in the app_scheduler's queue. The delay is followed by the app_scheduler calling the 4 timer_timeout_action() in the order they were put on it's queue, (FirstInFirstOut), and each with their unique loop_count value.

    But could you please tell me if my original supposition is possible? Can I use the pointer to hold a uint32_t instead of an address?

Reply
  • In the following simple case where I use nrf_delay_ms(4500) periodically in the forever loop to simulate some other app_scheduler events that will take more than a second to complete, it looks like my fears are unwarranted. Since app_sched_event_put() is not using the same pointer for loop_count in each queued message, the unique value for each loop_count iteration is kept on the queue and passed to the handler.

    static bool main_loop_started = false;
    static uint32_t m_count = 0;
    
    // Scheduler settings
    #define SCHED_MAX_EVENT_DATA_SIZE   APP_TIMER_SCHED_EVENT_DATA_SIZE
    #define SCHED_QUEUE_SIZE            16
    
    APP_TIMER_DEF(m_our_app_timer_id);
    #define TIMER_INTERVAL   APP_TIMER_TICKS(1000)   // every 1000 msecs
    
    
    void timer_timeout_action(void *p_event_data, uint16_t event_size)
    {
        uint32_t *loop_count = (uint32_t *)p_event_data;
        NRF_LOG_INFO("       timeout_action:  loop_count = %d  *loop_count = %d", loop_count, *loop_count);
        display_result (*loop_count);  // In another module and just does a NRF_LOG_INFO.
    }
    
    
    static void timer_timeout_handler(void * p_context)
    {
        static uint32_t loop_count = 0;
    
        ++loop_count;
    
        if (main_loop_started)
        {
            app_sched_event_put((void *)(&loop_count), sizeof(uint32_t), timer_timeout_action);
            m_count++;
            NRF_LOG_INFO("timeout_handler: &loop_count = %d  loop_count = %d", &loop_count, loop_count);
        }
    }
    
    
    static void timers_init(void)
    {
        ret_code_t err_code;
    
        // Make sure the LF clock is running
        err_code = nrf_drv_clock_init();
        APP_ERROR_CHECK(err_code);
        nrf_drv_clock_lfclk_request(NULL);
        nrfx_clock_lfclk_start();
    
        // Initialize timer module
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
        // Create timers
        err_code = app_timer_create(&m_our_app_timer_id, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    static void application_timers_start(void)
    {
        ret_code_t err_code;
        err_code = app_timer_start(m_our_app_timer_id, TIMER_INTERVAL, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(get_Nordic_rtc_counter);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    static void power_management_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    static void idle_state_handler(void)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    
    int main(void)
    {
        ret_code_t err_code;
    
        // Initialize
        APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
        log_init();
    
        timers_init();
    
        application_timers_start();
    
        power_management_init();
    
        NRF_LOG_INFO("DevKit APP Schedular practice started.\n");
    
        // Enter main loop.
        main_loop_started = true;
        for (;;)
        {
            app_sched_execute();
            if (!(m_count % 15))
                nrf_delay_ms(4500);
            idle_state_handler();
        }
    }

    00> [00:00:44.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 44
    00> [00:00:44.000,000] <info> app:        timeout_action:  loop_count = 536873956  *loop_count = 44
    00> [00:00:44.000,000] <info> rtclk:             m_result = 44
    00> [00:00:45.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 45
    00> [00:00:45.000,000] <info> app:        timeout_action:  loop_count = 536873964  *loop_count = 45
    00> [00:00:45.000,000] <info> rtclk:             m_result = 45
    00> [00:00:46.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 46
    00> [00:00:47.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 47
    00> [00:00:48.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 48
    00> [00:00:49.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 49
    00> [00:00:49.466,796] <info> app:        timeout_action:  loop_count = 536873972  *loop_count = 46
    00> [00:00:49.466,796] <info> rtclk:             m_result = 46
    00> [00:00:49.466,796] <info> app:        timeout_action:  loop_count = 536873980  *loop_count = 47
    00> [00:00:49.466,857] <info> rtclk:             m_result = 47
    00> [00:00:49.466,857] <info> app:        timeout_action:  loop_count = 536873988  *loop_count = 48
    00> [00:00:49.466,857] <info> rtclk:             m_result = 48
    00> [00:00:49.466,857] <info> app:        timeout_action:  loop_count = 536873996  *loop_count = 49
    00> [00:00:49.466,857] <info> rtclk:             m_result = 49
    00> [00:00:50.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 50
    00> [00:00:50.000,000] <info> app:        timeout_action:  loop_count = 536874004  *loop_count = 50
    00> [00:00:50.000,000] <info> rtclk:             m_result = 50
    00> [00:00:51.000,000] <info> app: timeout_handler: &loop_count = 536874020  loop_count = 51
    00> [00:00:51.000,000] <info> app:        timeout_action:  loop_count = 536874012  *loop_count = 51
    00> [00:00:51.000,000] <info> rtclk:             m_result = 51
    

    During the 4.5 second delay, you can see the 4 timer_timeout_handler() calls where loop_count is being incremented and timer_timeout_action() is being put in the app_scheduler's queue. The delay is followed by the app_scheduler calling the 4 timer_timeout_action() in the order they were put on it's queue, (FirstInFirstOut), and each with their unique loop_count value.

    But could you please tell me if my original supposition is possible? Can I use the pointer to hold a uint32_t instead of an address?

Children
  • Hi Matty, 

    Yes, what you observed is correct. The app_scheduler take in to account that and do a copy of the content of the data point into its own buffer. 
    (I also didn't know about this before)

    So here is the code inside app_sched_event_put(), and you can see that the data is copied into the buffer using memcpy: 

    So, you don't really have to worry that the subsequence events may change the original data of the previous event if it's not executed fast enough. 

  • Since,

    The memcpy() function shall copy event_data_size bytes from the object pointed to by p_event_data into the object pointed to by &m_queue_event_data[event_index * m_queue_event_size].

    my idea of using the app_sched_event_put's p_event_data pointer's memory slot to hold a single uint32_t value can not be possible. Just examining the SDK/components/libraries/scheduler/app_scheduler.c would have told me that idea could never work. The app_scheduler is using my uint32_t as an address location from which to begin copying if a event_data_size is given. If event_data_size is zero nothing is copied. In either case, the app_scheduler's queue never gets my uint32_t value.

    So case closed. Thank you.

Related