本文先给出Contiki编程的代码框架,接着,介绍了用宏实现三种程序基本结构(即顺序、选择、循环)的基本框架,最后介绍了挂起进程相关的API。

1. 代码框架

Contiki实际编程通常只需替代Hello world的内容,main函数内容甚至无需修改,大概的代码框架如下(以两个进程为例):

/*步骤1:包含需要的头文件*/
#include "contiki.h"
#include "debug-uart.h"

/*步骤2:用PROCESS宏声明进程执行主体,并定义进程*/
PROCESS(example_1_process, "Example 1"); //PROCESS(name, strname)    
PROCESS(example_2_process, "Example 1");

/*步骤3:用AUTOSTART_PROCESSES宏让进程自启动*/
AUTOSTART_PROCESSES(&example_1_process, &example_2_process); //AUTOSTART_PROCESSES(...)    

/*步骤4:定义进程执行主体thread*/
PROCESS_THREAD(example_1_process, ev, data) //PROCESS_THREAD(name, ev, data)
{
  PROCESS_BEGIN();  /*代码总是以宏PROCESS_BEGIN开始*/

  /*example_1_process的代码*/

  PROCESS_END();  /*代码总是以宏PROCESS_END结束*/
}

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

  /*example_2_process的代码*/

  PROCESS_END();
}

可参考博文《实例hello_world剖析》以获得更直观的认识,接下来给出三种程序基本结构(即顺序、选择、循环)的模式。

2. 顺序&选择&循环

2.1 顺序

PROCESS_BEGIN();
(*...*)
PROCESS_WAIT_UNTIL(cond1); //注1
(*...*)
PROCESS_END();

2.2 循环

PROCESS_BEGIN();
(*...*)
while (cond1)
  PROCESS_WAIT_UNTIL(cond1 or cond2); //注1
(*...*)
PROCESS_END();

2.3 选择

PROCESS_BEGIN();
(*...*)
if (condtion)
  PROCESS_WAIT_UNTIL(cond2a); //注1
else
  PROCESS_WAIT_UNTIL(cond2b); //注1
(*...*)
PROCESS_END();

注1:这里不一定非得用宏PROCESS_WAIT_UNTIL,事实上有很多选择,比如宏PROCESS_WAIT_EVENT_UNTIL(c)、宏PROCESS_WAIT_EVENT()、宏PROCESS_YIELD_UNTIL(c)等(请参见本文第三部分),实际编程应根据实际情况加以选择。

3. 挂起进程相关API

3.1 概述

表1给出挂起进程相关API的功能描述,事实上,实际编程所关心的是,什么时候继续执行宏后面的内容,3.2~3.6给出了详见分析。

表1 Contiki挂起进程相关API[1]

方法 描述
PROCESS_WAIT_EVENT() Wait for an event to be posted to the process.
PROCESS_YIELD() Yield the currently running process.
PROCESS_WAIT_EVENT_UNTIL(c) Wait for an event to be posted to the process, with an extra condition.
PROCESS_YIELD_UNTIL(c) Yield the currently running process until a condition occurs.
PROCESS_WAIT_UNTIL(c) Wait for a condition to occur.
PROCESS_WAIT_WHILE(c) Block and wait while condition is true.
PROCESS_PT_SPAWN(pt, thread) Spawn a protothread from the process.
PROCESS_PAUSE() Yield the process for a short while.

3.2 PROCESS_WAIT_EVENT和PROCESS_YIELD

从代码展开来看,宏PROCESS_WAIT_EVENT和宏PROCESS_YIELD实现的功能是一样的(或者说PROCESS_WAIT_EVENT只是PROCESS_YIELD的一个别名),只是两种不同的描述。也就是说当PT_YIELD_FLAG为1时(即该进程再次被调度的时候,想想PROCESS_BEGIN宏包含语句PT_YIELD_FLAG=1),才执行宏后面的代码,否则返回。代码展开如下:

#define PROCESS_WAIT_EVENT() PROCESS_YIELD()
#define PROCESS_YIELD() PT_YIELD(process_pt)

#define PT_YIELD(pt)                \
  do
  {                        \
    PT_YIELD_FLAG = 0;                \
    LC_SET((pt)->lc);                \
    if(PT_YIELD_FLAG == 0)
    {            \
      return PT_YIELDED;            \
    }                        \
  } while(0)

3.3 PROCESS_WAIT_EVENT_UNTIL和PROCESS_YIELD_UNTIL

根3.2类似,宏PROCESS_WAIT_EVENT_UNTIL和宏PROCESS_YIELD_UNTIL是一组,在3.2的基础是增加了额外的一个条件,也就是说当PT_YIELD_FLAG为1且条件为true时(即进程再次被调度的时候,条件为true,因为PROCESS_BEGIN宏已包含语句PT_YIELD_FLAG),才执行宏后面的代码,否则返回。代码展开如下:

#define PROCESS_WAIT_EVENT_UNTIL(c) PROCESS_YIELD_UNTIL(c)
  #define PROCESS_YIELD_UNTIL(c) PT_YIELD_UNTIL(process_pt, c)

  #define PT_YIELD_UNTIL(pt, cond)        \
  do
  {                        \
    PT_YIELD_FLAG = 0;                \
    LC_SET((pt)->lc);                \
    if((PT_YIELD_FLAG == 0) || !(cond))
    {    \
      return PT_YIELDED;            \
    }                        \
  } while(0)

3.4 PROCESS_WAIT_UNTIL和PROCESS_WAIT_WHILE

从代码展开来看,宏PROCESS_WAIT_UNTIL和宏PROCESS_WAIT_WHILE判断的条件相反,PROCESS_WAIT_UNTIL宏当条件为真时(即某个事件发生),执行宏后面的内容。而PROCESS_WAIT_WHILE宏当条件为假时,执行宏后面的内容(即当条件为真时,阻塞该进程)。

/*PROCESS_WAIT_UNTIL宏展开*/
#define PROCESS_WAIT_UNTIL(c) PT_WAIT_UNTIL(process_pt, c)

/*PROCESS_WAIT_WHILE宏展开*/
#define PROCESS_WAIT_WHILE(c) PT_WAIT_WHILE(process_pt, c)
#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond))

/*PT_WAIT_UNTIL宏展开*/
#define PT_WAIT_UNTIL(pt, condition)     \
  do
  {                        \
    LC_SET((pt)->lc);                \
    if(!(condition))
    {                \
      return PT_WAITING;            \
    }                        \
  } while(0)

3.5 PROCESS_PT_SPAWN

PROCESS_PT_SPAWN用于产生一个子protothread,若执行完thread并退出PT_EXITED,则继续执行宏PROCESS_PT_SPAWN后面的内容。宏一层层展开如下:

#define PROCESS_PT_SPAWN(pt, thread) PT_SPAWN(process_pt, pt, thread)
#define PT_SPAWN(pt, child, thread)        \
  do
  {                        \
    PT_INIT((child));                \
    PT_WAIT_THREAD((pt), (thread));        \
  } while(0)

#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))

#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond))

#define PT_SCHEDULE(f) ((f) < PT_EXITED)

3.6 PROCESS_PAUSE

PROCESS_PAUSE用于向进程传递事件PROCESS_EVENT_CONTINUE,并等到任一事件发生,即被挂起了(但我并没有看到哪个地方对事件PROCESS_EVENT_CONTINUE优先处理了)。宏展开如下如下:

#define PROCESS_PAUSE()
do
{                \
  process_post(PROCESS_CURRENT(), PROCESS_EVENT_CONTINUE, NULL);    \
  PROCESS_WAIT_EVENT();                            \
} while(0)

3.7 PROCESS_WAIT_EVENT_UNTIL与PROCESS_WAIT_UNTIL区别

从上述3.3和3.4代码展开可以看出,宏PROCESS_WAIT_EVENT_UNTIL和宏PROCESS_WAIT_UNTIL的区别在于:前者除了要判断条件外,还需判断PT_YIELD_FLAG;而后者只需判断条件。并且返回值也不一样。

参考资料:

[1]

本文系Spark & Shine原创,转载需注明出处本文最近一次修改时间 2022-03-20 23:39

results matching ""

    No results matching ""