当前位置:首页 > TinyOS系统与nesC程序设计课内实验指导书
a. AMPacket:提供基本的AM访问 b. AMSend:提供基本的AM发送接口
(3)一个节点的AM地址可以在初始化的时候设置:
make install.n or meke reinstall.n ? 通信组件:
许多组件实现了基本通信接口与AM接口
(1)AMReceiverC - Provides: Receive, Packet, and AMPacket.
(2)AMSenderC-Provides: AMSend, Packet, AMPacket, RacketAcknowledgements as
Acks.
(3)AMSnooperC - Provides Receive, Packet, and AMPacket.
(4)AMSnoopingReceiverC - Provides Receive, Packet, and AMPacket.
(5)ActiveMessageAddressC – 提供用来得到或设置节点AM地址的命令(少用)
三 实验环境
1、JDK1.6 for windows 2、Cygwin with TinyOS 2.x 3、UltraEdit / EditPlus
四 实验内容和步骤 1、重新实现Blink
(1)进入tmp文件夹并创建文件夹,取名BlinkToRadio,进入这个文件夹。
cd /tmp
mkdir BlinkToRadio cd BlinkToRadio
(2)新建模块文件BlinkToRadio.nc
#include
#ifndef BLINKTORADIO_H #define BLINKTORADIO_H enum { TIMER_PERIOD_MILLI = 250 }; #endif (4)编写配件BlinkToRadioApp.nc,连接提供和使用各接口的组件 #include
typedef nx_struct BlinkToRadioMsg { nx_uint16_t nodeid; nx_uint16_t counter; } BlinkToRadioMsg; 除了struct和uint16_t前面的nx_前缀之外,上面的消息结构与C语言结构体基本一样。它是nesC所特有的,表示struct和uint16_t为外部类型(external types)。nx_前缀表示数据为外部类型的大端(big-endian)数据,小端(little-endian)前缀为nxle_。不同类型的节点会采用不同类型的处理器,它们对于字节、字等的存储机制有所不同,因而会引发计算机通信领域中一个很重要的问题,即通信双方交流的信息单元应该以什么样的顺序进行传送。如果不达成一致的规则,通信双方将无法进行正确的编/译码从而导致通信失败。TCP/IP各层协议将字节序定义为big-endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。nesC语言定义了外部类型,可以让程序员不必考虑字节序的重新排列。 3、发送数据包
定义好消息的数据结构,我们接下去要学习怎么把指定结构的数据包发送出去。首先我们因明确程序要完成的功能:在定时器每次触发的时候(i)计数器+1;(ii)把计数器值的最低三位显示在三盏灯上;(iii)把由发送节点的节点号和计数器值组成数据包通过无线收发器发送出去。为了完成上述功能,我们将程序分成以下几步:
(1)找出相应的接口和组件,使我们能够控制收发器(radio)并对message_t进行操作。我们使用AMSend接口来发送数据包,Packet和AMPacket接口进入message_t抽象数据类型。这些接口都用组件AMSendC来提供,虽然它们也可以由ActiveMessageC来提供,但是AMSendC提供了虚拟抽象(virtualized abstraction)。因为收发器是一个公共资源,不同的组件都可以使用,所以需要将它虚拟化以避免不同组件间的相互干扰(后面课程会讲)。同时,我们使用由组件ActiveMessageC提供的SplitControl来开启和关闭收发器。 (2)更新BlinkToRadio.nc中的module板块代码,用uses语句添加上述接口。 module BlinkToRadioC { ... uses interface Packet; uses interface AMPacket; uses interface AMSend; uses interface SplitControl as AMControl; } 注意,这里SplitControl被重命名为AMControl,通过as关键字。 (3)声明新变量,并初始化。
implementation { bool busy = FALSE; //标记无线电收发器是否忙碌 message_t pkt; ... }
在定时器开始之前,首先要彻底开启收发器。 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 AMControl.stopDone(error_t err) { } (4)添加程序逻辑。首先要检查busy标记,保证没有数据包正在发送。然后用一个指针指向一个数据包的payload部分,往payload里面各个域填写数据。最后通过send命令把数据包发送给所有接受范围内的节点(因为目的地址为AM_BROADCAST_ADDR)。如果成功(返回SUCCESS),则证实AM层已经收到数据包,准备发送。
event void Timer0.fired() { ... if (!busy) { BlinkToRadioMsg* btrpkt = (BlinkToRadioMsg*)(call Packet.getPayload(&pkt,NULL)); btrpkt->nodeid = TOS_NODE_ID; btrpkt->counter = counter; if (call AMSend.send(AM_BROADCAST_ADDR, &pkt, sizeof(BlinkToRadioMsg)) == SUCCESS){ busy = TRUE; } } } (5)实现所有用到的接口中所包含的事件(events)。通过观察Packet,AMPacket,AMSend接口,发现只有一个事件需要实现,即AMSend.sendDone:
/** * Signaled in response to an accepted send request. msg is * the message buffer sent, and error indicates whether * the send was successful. * * @param msg the packet which was submitted as a send request * @param error SUCCESS if it was sent successfully, FAIL if it was not, * ECANCEL if it was cancelled * @see send * @see cancel */ event void sendDone(message_t* msg, error_t error); 在AMSend.sendDone中,我们需要检查下所发送出去的消息缓存是否为本地消息缓存。因为假如有两个组件同时连接到一个AMSend,只要其中任何一个组件执行send命令后,这两个组件都将接受到sendDone事件。这样就会产生干扰。 event void AMSend.sendDone(message_t* msg, error_t error) { if (&pkt == msg) { busy = FALSE; } } (6)更新配件中implementation板块中的代码,添加相应的组件。
共分享92篇相关文档