I had a similar problem last week trying to understand the callbacks with events queues, but perhaps the following sample code I put together will clarify something. It uses the second approach mentioned by Chris, which is a dedicated processing task for the event queues so that I know the priority level the events will be executed within.

This code sets up a HW interrupt on a GPIO pin, and when we enter the interrupt service routine we add an event to the eventq. This event is handled outside the ISR context at a later less critical time. It just does blinky now which could be safely done inside the ISR, of course, but it's a useful real world example of when you would want to use event queues in my opinion to get in and out of the ISR as quickly as possible.

Kevin

#include "os/os.h"
#include "bsp/bsp.h"
#include "hal/hal_gpio.h"
#include <assert.h>
#include <string.h>
#ifdef ARCH_sim
#include <mcu/mcu_sim.h>
#endif

#define IRQ_PIN             (20)
#define EVENT_TASK_PRIO     (1)
#define EVENT_STACK_SIZE    OS_STACK_ALIGN(128)

struct os_task event_task;
os_stack_t event_stack[EVENT_STACK_SIZE];
static struct os_eventq irq_evq;

static int init_tasks(void);
static void gpio_task_irq_deferred_handler(struct os_event *);

static struct os_event gpio_irq_handle_event = {
    .ev_cb = gpio_task_irq_deferred_handler,
};

/**
 * This function will be called when the gpio_irq_handle_event is pulled
 * from the message queue.
 */
static void
gpio_task_irq_deferred_handler(struct os_event *ev)
{
    hal_gpio_toggle(LED_2);
}

/**
* This task serves as a container for the shell and newtmgr packages. These
 * packages enqueue timer events when they need this task to do work.
 */
static void
event_task_handler(void *arg)
{
    while (1) {
        os_eventq_run(&irq_evq);
    }
}

/**
 * This function handles the HW GPIO interrupt and registers an event in
 * the event queue to defer taking action here in the ISR context.
 */
static void
gpio_irq_handler(void *arg)
{
    /* Add item to event queue for processing later, etc. ... */
    os_eventq_put(&irq_evq, &gpio_irq_handle_event);
}

/**
 * init_tasks
 *
 * Called by main.c after os_init(). This function performs initializations
 * that are required before tasks are running.
 *
 * @return int 0 success; error otherwise.
 */
static int
init_tasks(void)
{
    /* Init IRQ pin: falling edge, pullup enabled */
    hal_gpio_irq_init(IRQ_PIN,
                      gpio_irq_handler,
                      NULL,
                      HAL_GPIO_TRIG_FALLING,
                      HAL_GPIO_PULL_UP);

    /* Enable the IRQ */
    hal_gpio_irq_enable(IRQ_PIN);

    /* Setup the LED pins */
    hal_gpio_init_out(LED_BLINK_PIN, 1);
    hal_gpio_init_out(LED_2, 0);

    os_task_init(&event_task, "irq", event_task_handler, NULL,
EVENT_TASK_PRIO, OS_WAIT_FOREVER, event_stack, EVENT_STACK_SIZE);

    os_eventq_init(&irq_evq);
    os_eventq_dflt_set(&irq_evq);

    return 0;
}

/**
 * main
 *
* The main function for the project. This function initializes the os, calls * init_tasks to initialize tasks (and possibly other objects), then starts the
 * OS. We should not return from os start.
 *
 * @return int NOTE: this function should never return!
 */
int
main(int argc, char **argv)
{
    int rc;

#ifdef ARCH_sim
    mcu_sim_parse_args(argc, argv);
#endif

    os_init();

    rc = init_tasks();
    os_start();

    /* os start should never return. If it does, this should be an error */
    assert(0);

    return rc;
}


On 02/01/17 11:26, then yon wrote:
Dear Chris,

I tried to apply your solution but i stuck somewhere in middle as the handler parameter is diff that cause build error

void shell_task_handler(void *arg)
static void queue_task_handler(struct os_event *ev)

1. At os_eventq_init(&shell_task_evq);

2. At os_task_init(&queue_task, "queue", queue_task_handler, NULL, QUEUE_TASK_PRIO, OS_WAIT_FOREVER, queue_stack, QUEUE_STACK_SIZE);


Thank you for your fast response and happy new year.

Regards,
Then Yoong Ze

On 2/1/2017 2:25 PM, Christopher Collins wrote:
Hi Then,

On Mon, Jan 02, 2017 at 01:23:33PM +0800, then yon wrote:
Dear Support,

I been using MyNewt v1.0.0-dev, and i tried to make use of Mqueue.

What i did was following the tutorial below:

https://mynewt.apache.org/os/core_os/mqueue/mqueue/
Since the tutorial is not updated, i tried to modify it but unfortunately i can't make it work.
[...]

Your code looks good.  There is just one crucial step missing: a task
needs to poll the eventq you created (queue_task_evq).  Just to clarify
how mqueues work: when os_mqueue_put() is called, two things happen:
     1. The specified mbuf is placed on the mqueue.
     2. The event associated with the mqueue is put on the specified
        eventq, but only if the event is not already enqueued.

If a task is listening on the eventq, then it can your mqueue processing
function when it sees the mqueue event.

I think you have two options:
     1. Remove queue_task_evq from your code; use the other eventq
        (blinky_evq) with your mqueue.  blinky_evq is already being
        processed correctly by the shell_task_handler() function, so if
        you enqueue an mqueue event to it, your mqueue data will get
        processed.

     2. Create an additional task which processes the queue_task_evq
        eventq.  This task's handler would probably look identical to
        shell_task_handler(), i.e., a tight loop that repeatedly calls
        os_eventq_run().

I recommend trying the simpler option 1 first.  Generally, it is best to
minimize the number of tasks your app uses so that it requires less RAM.

Thanks,
Chris
.




Reply via email to