contikicontiki-process

How to post two different events to the same Contiki process?


I have two Contiki processes with one process, master, posting two different events to a second process, send. The first event sent is PROCESS_EVENT_CONTINUE and the second event is PROCESS_EVENT_MSG.

I am posting these events sequentially, one after another, from the process called main.

The complete code is:

#include "contiki.h"
#include "lib/list.h"
#include "lib/memb.h"
#include "lib/random.h"
#include "net/rime/rime.h"

#include<stdio.h>

PROCESS(master, "master_DGHS"); 
PROCESS(send, "master_DGHS"); 

AUTOSTART_PROCESSES( &master, &send);

PROCESS_THREAD(master, ev, data)
{
    PROCESS_BEGIN();

    process_post(&send, PROCESS_EVENT_CONTINUE, NULL);
    process_post(&send, PROCESS_EVENT_MSG, NULL);

    PROCESS_END();
}


PROCESS_THREAD(send, ev, data)
{
    static struct etimer et;

    PROCESS_BEGIN();

    while(1)
    {
        PROCESS_WAIT_EVENT(); 
        if(ev == PROCESS_EVENT_CONTINUE)
        {
            printf("PROCESS_EVENT_CONTINUE\n");
            etimer_set(&et, CLOCK_SECOND );
            PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));

        }else
        if(ev == PROCESS_EVENT_MSG)
        {
            printf("PROCESS_EVENT_MSG\n");
            etimer_set(&et, CLOCK_SECOND  );
            PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
        }

    }
    PROCESS_END();
 }

The problem is that the second process send sees the first event (it prints PROCESS_EVENT_CONTINUE), but it doesn't see the second event (it does not print PROCESS_EVENT_MSG).

In other words, the second event gets lost. However if I remove the source line

PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));

the second process send sees both events (both PROCESS_EVENT_CONTINUE and PROCESS_EVENT_MSG are printed). So, adding this source line causes the second event, PROCESS_EVENT_MSG, to be ignored or discarded.

Why does adding this source line result in the second event getting lost?


Solution

  • The problem is that PROCESS_WAIT_EVENT_UNTIL consumes all events until the loop's condition becomes true.

    By calling PROCESS_WAIT_EVENT_UNTIL() in the area separated by the PROCESS_BEGIN() and PROCESS_END() calls, one can yield control to the scheduler, and only resume execution when an event is delivered. A condition is given as an argument to PROCESS_WAIT_EVENT_UNTIL(), and this condition must be fulfilled for the processes to continue execution after the call to PROCESS_WAIT_EVENT_UNTIL(). If the condition is not fulfilled, the process yields control back to the OS until a new event is delivered.

    This is the sequence of actions in your example:

    1. The send process gets PROCESS_EVENT_CONTINUE event.
    2. The process executes the first printf, sets up a timer, and enters PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
    3. The send process gets PROCESS_EVENT_MSG event immediately after.
    4. The process is still in the WAIT_EVENT_UNTIL loop and discards the second event, because the timer is not expired yet.
    5. The timer expires and the send process gets PROCESS_EVENT_TIMER event.
    6. The process exits the wait loop.

    So, the second event is received by the process, but not acted upon, since the process is waiting for another event. Hope that now you understand why removing the WAIT_EVENT_UNTIL macro solves this issue.