本文先给出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]