1 TestRPL例程的功能
Implementation of the RadioCountToLedsapplication. RadioCountToLeds maintains a 4Hz counter, broadcasting its valuein an AM packet every time it gets updated. A RadioCountToLeds node that hearsa counter displays the bottom three bits on its LEDs. This application is auseful test to show that basic AM communication and timers work.
该例程实现了RadioCountToLeds。RadioCountToLeds包含了一个4Hz的计数器,当其值被更新时,通过AM包广播其值。某个RadioCountToLeds节点收到该计数值时用三个LED显示计数值的最低三位。该应用程序是一个有意义的代码,可以测试基本的AM通信模块和定时器模块是否正确。
这里有一个疑问,为什么串口和无线都可以用 AM组件??
2 模块组件文件TestRPLC.nc
#include "Timer.h"
#include "TestRPL.h"
#include "lib6lowpan/ip.h"
#include "blip_printf.h"
这里用到的主要的头文件应为TestRPL.h及lib6lowpan/ip.h
module TestRPLC @safe() {
uses {
interfaceLeds;
interfaceBoot;
interfaceTimer<TMilli> as MilliTimer;
interfaceTimer<TMilli> as Timer;
interfaceRPLRoutingEngine as RPLRoute;
interface RootControl;
interface StdControl as RoutingControl;
interface SplitControl;
interface UDP as RPLUDP;
interfaceRPLDAORoutingEngine as RPLDAO;
interfaceRandom;
}
}
这些接口中不少都是陌生的接口。好多接口并不在目录\tos\interfaces中。其中RPLRoutingEngine、RPLDAORoutingEngine接口在目录\tos\lib\net\rpl下。UDP接口在目录\tos\lib\net\blip下。
implementation {
#ifndef RPL_ROOT_ADDR
#define RPL_ROOT_ADDR 1
#endif
#define UDP_PORT 5678
struct in6_addrMULTICAST_ADDR;
bool locked;
uint16_t counter = 0;
以上为定义变量,定义了IpV6的多播地址,忙标志locked,计数值counter。接下来是Boot.booted事件。
event void Boot.booted() {
memset(MULTICAST_ADDR.s6_addr, 0, 16);
MULTICAST_ADDR.s6_addr[0] = 0xFF;
MULTICAST_ADDR.s6_addr[1] = 0x2;
MULTICAST_ADDR.s6_addr[15] = 0x1A;
//callLcd.initialize();
if(TOS_NODE_ID == RPL_ROOT_ADDR){
callRootControl.setRoot();
}
callRoutingControl.start();
//callRoutingControl.start();
callSplitControl.start();
callRPLUDP.bind(UDP_PORT);
}
在该事件处理函数中进行了几项工作:一,为刚刚定义的多播地址赋值,0xff,0x2,0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a。二,判断节点的ID号是否为1即根节点,如果该节点的号是1则调用RootControl.setRoot()命令函数将该节点设置为根节点。三,Routing和Split开始。四,调用UDP接口绑定端口,接着就可以进行Socket通信了。
uint32_tcountrx = 0;
uint32_tcounttx = 0;
此处无话。
event voidRPLUDP.recvfrom(struct sockaddr_in6 *from, void *payload, uint16_t len, struct ip6_metadata*meta){
nx_uint16_ttemp[10];
memcpy(temp,(uint8_t*)payload, len);
callLeds.led2Toggle();
printf(">>>> RX %d %d %d %lu \n", TOS_NODE_ID,temp[0], temp[9], ++countrx);
printfflush();
}
端口收到数据,并进行处理。首先,将收到的有效载荷存放于temp,存放的长度为len。然后,反转led2。最后,打印信息, >>>>RX 节点号,第一及最后一个字节,数据包的序号。
event voidSplitControl.startDone(error_t err){
while( callRPLDAO.startDAO() != SUCCESS );
if(TOS_NODE_ID != RPL_ROOT_ADDR){
callTimer.startOneShot((call Random.rand16()%2)*2048U);
}
}
SplitControl接口到底啥作用,目前还没搞清楚!!
event void Timer.fired(){
callMilliTimer.startOneShot(PACKET_INTERVAL + (call Random.rand16() % 100));
}
定时时间到后触发该事件。定义一个随机的产生时间长度的定时器。目的??此处的PACKET_INTERVAL在makefile中给出了
################################################################################
### Configure this application
################################################################################
# 5 second packet generation interval
CFLAGS+=-DPACKET_INTERVAL=5120UL
task voidsendTask(){
structsockaddr_in6 dest;
nx_uint16_ttemp[10];
uint8_t i;
//callDraw.fill(COLOR_BLACK);
for(i=0;i<10;i++){
temp[i] =0xABCD;
}
temp[0] =TOS_NODE_ID;
temp[9] =counttx;
memcpy(dest.sin6_addr.s6_addr, call RPLRoute.getDodagId(), sizeof(structin6_addr));
if(dest.sin6_addr.s6_addr[15] != 0) // destination is set as root!
++counttx;
//if(dest.sin6_addr.s6_addr[0] == 0xAA)
callLeds.led0Toggle();
dest.sin6_port= htons(UDP_PORT);
printf("Generate Packet at %d \n", TOS_NODE_ID);
callRPLUDP.sendto(&dest, temp, 20);
}
写一个发送数据的任务sendTask(),待后面投递给任务。
event void MilliTimer.fired(){
//callLeds.led1Toggle();
callMilliTimer.startOneShot(PACKET_INTERVAL + (call Random.rand16() % 100));
postsendTask();
}
event voidSplitControl.stopDone(error_t err){}
}
在定时器定时时间到后触发的事件处理函数中再次启动一次某个随机时间长度的定时器,并投递sendTask()任务。
By:霜月孤鸟
2015.12.28-29