在
tinyos中,
程序的执行是串行的,按照官方
教程的说法,也就是split-phase,分相的执行的模式。以下面的程序为例:
#include <Timer.h>
#include "BlinkToRadio.h"
module BlinkToRadioC {
uses interface Boot;
uses interface Leds;
uses interface Timer<TMilli> as Timer0;
uses interface Packet;
uses interface AMPacket;
uses interface AMSend;
uses interface SplitControl as AMControl;
uses interface Receive;
}
implementation {
bool busy=FALSE;
message_t pkt;
uint16_t counter = 0;
event void Boot.booted() {
call AMControl.start();
}
event void AMControl.startDone(error_t err){
if(err==SUCCESS){
call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
}
else{
call AMControl.start();
}
}
event void AMSend.sendDone(message_t* msg,error_t error){
if(&pkt==msg){
busy=FALSE;
}
}
event void AMControl.stopDone(error_t err){
}
event message_t* Receive.receive(message_t* msg,void* payload,uint8_t len){
if(len==sizeof(BlinkToRadioMsg)){
BlinkToRadioMsg* btrpkt=(BlinkToRadioMsg*)payload;
call Leds.set(btrpkt->counter);
}
return msg;
}
event void Timer0.fired() {
counter++;
if(!busy){
BlinkToRadioMsg* btrpkt=(BlinkToRadioMsg*)(call Packet.getPayload(&pkt,sizeof(BlinkToRadioMsg)));
btrpkt->nodeid=TOS_NODE_ID;
btrpkt->counter=counter;
if(call AMSend.send(AM_BROADCAST_ADDR,&pkt,sizeof(BlinkToRadioMsg))==SUCCESS){
busy=TRUE;
}
}
}
}
程序的入口是boot,正如C中的main()函数一样,是整个程序的起点。在boot中,有call命令,调用AMControl.start()命令,调用该命令,就会激发AMControl.startDone(error_t err)事件,该事件的参数err是一个状态参数,如果成功启动了AMControl,err的值就是SUCCESS。
在AMControl.startDone()事件体中的语句:call Timer0.startPeriodic(TIMER_PERIOD_MILLI);,该调用,激发Timer0每隔TIMER_PERIOD_MILLI启动一次。也就是过TIMER_PERIOD_MILLI毫秒后,激发Timer0.fired()事件。在Timer0.fired()事件体中,下面的这句意思是:
call AMSend.send(AM_BROADCAST_ADDR,&pkt,sizeof(BlinkToRadioMsg))==SUCCESS,将包pkt发送出去,第一个参数是目的地址,这里AM_BROADCAST_ADDR是用广播的方式发送出去。接着就会执行AMSend.sendDone(message_t* msg,error_t error)事件,这两个参数,我不太清楚,到底什么意思,你们可以去看看它的API:
\cygwin\opt\tinyos-2.x\tos\interfaces\AMSend.nc。
接着大家会发现,在sendDone中并没有调用命令、事件的语句。大家可能觉得程序执行不下去了,那个message_t* Receive.receive(message_t* msg,void* payload,uint8_t len)什么时候执行,可能就想不通了。其实,这个receive是在节点接收到其他节点发送来的 数据包的时候,自动激发节点执行receive事件。
对于其他程序,程序的执行大体如此,大家可以按照这种方式分析其他的程序。另外,在程序中,对于task,post这个任务,就是要求程序立刻执行这个任务。对于事件,可以在程序体中,使用signal调用这个事件,这样的话,该事件就会立即执行,而不是等到调用该事件之后激发了。
event void AMSend.sendDone(message_t* msg,error_t error){
if(&pkt==msg){
busy=FALSE;
}
//这里就会调用receive事件,注意,参数必须传递正确,这里的参数是有问题的。
Signal Receive.receive( msg,payload,len)
}
这些都是个人理解,有不妥的地方,敬请指正。
#include <Timer.h>
#include "BlinkToRadio.h"
module BlinkToRadioC {
uses interface Boot;
uses interface Leds;
uses interface Timer<TMilli> as Timer0;
uses interface Packet;
uses interface AMPacket;
uses interface AMSend;
uses interface SplitControl as AMControl;
uses interface Receive;
}
implementation {
bool busy=FALSE;
message_t pkt;
uint16_t counter = 0;
event void Boot.booted() {
call AMControl.start();
}
event void AMControl.startDone(error_t err){
if(err==SUCCESS){
call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
}
else{
call AMControl.start();
}
}
event void AMSend.sendDone(message_t* msg,error_t error){
if(&pkt==msg){
busy=FALSE;
}
}
event void AMControl.stopDone(error_t err){
}
event message_t* Receive.receive(message_t* msg,void* payload,uint8_t len){
if(len==sizeof(BlinkToRadioMsg)){
BlinkToRadioMsg* btrpkt=(BlinkToRadioMsg*)payload;
call Leds.set(btrpkt->counter);
}
return msg;
}
event void Timer0.fired() {
counter++;
if(!busy){
BlinkToRadioMsg* btrpkt=(BlinkToRadioMsg*)(call Packet.getPayload(&pkt,sizeof(BlinkToRadioMsg)));
btrpkt->nodeid=TOS_NODE_ID;
btrpkt->counter=counter;
if(call AMSend.send(AM_BROADCAST_ADDR,&pkt,sizeof(BlinkToRadioMsg))==SUCCESS){
busy=TRUE;
}
}
}
}
程序的入口是boot,正如C中的main()函数一样,是整个程序的起点。在boot中,有call命令,调用AMControl.start()命令,调用该命令,就会激发AMControl.startDone(error_t err)事件,该事件的参数err是一个状态参数,如果成功启动了AMControl,err的值就是SUCCESS。
在AMControl.startDone()事件体中的语句:call Timer0.startPeriodic(TIMER_PERIOD_MILLI);,该调用,激发Timer0每隔TIMER_PERIOD_MILLI启动一次。也就是过TIMER_PERIOD_MILLI毫秒后,激发Timer0.fired()事件。在Timer0.fired()事件体中,下面的这句意思是:
call AMSend.send(AM_BROADCAST_ADDR,&pkt,sizeof(BlinkToRadioMsg))==SUCCESS,将包pkt发送出去,第一个参数是目的地址,这里AM_BROADCAST_ADDR是用广播的方式发送出去。接着就会执行AMSend.sendDone(message_t* msg,error_t error)事件,这两个参数,我不太清楚,到底什么意思,你们可以去看看它的API:
\cygwin\opt\tinyos-2.x\tos\interfaces\AMSend.nc。
接着大家会发现,在sendDone中并没有调用命令、事件的语句。大家可能觉得程序执行不下去了,那个message_t* Receive.receive(message_t* msg,void* payload,uint8_t len)什么时候执行,可能就想不通了。其实,这个receive是在节点接收到其他节点发送来的 数据包的时候,自动激发节点执行receive事件。
对于其他程序,程序的执行大体如此,大家可以按照这种方式分析其他的程序。另外,在程序中,对于task,post这个任务,就是要求程序立刻执行这个任务。对于事件,可以在程序体中,使用signal调用这个事件,这样的话,该事件就会立即执行,而不是等到调用该事件之后激发了。
event void AMSend.sendDone(message_t* msg,error_t error){
if(&pkt==msg){
busy=FALSE;
}
//这里就会调用receive事件,注意,参数必须传递正确,这里的参数是有问题的。
Signal Receive.receive( msg,payload,len)
}
这些都是个人理解,有不妥的地方,敬请指正。