分享

TOSSIM学习使用笔记

 幸福的乐土 2012-04-06

TOSSIM学习使用笔记


最近很懒一直没有更新,都是在随便搞搞NesC,写点东西,多出时间来关注下日本地震。最近需要调试个程序,所以关注了一下TOSSIM。

TOSSIM是TinyOS自带的模拟器,但是说它是模拟器似乎又不是很准确,按照文档自己的说法,TOSSIM更像是一个library,就是所谓的类库。需要编译以后执行。按照我自己的理解,此前你将你的NesC程序编译,安装进传感器,你的程序执行时是和传感器上的实物硬件沟通,但是使用TOSSIM编译之后,TOSSIM会模仿系统各个组件的工作,从而你的程序实际上是在和TOSSIM的组件沟通。说白了就是,TOSSIM把你的NesC程序封装起来了。不知道里面的措辞是否准确,或者是理解上面是否还有些问题,但是我觉得差不多就是这个意思。

TOSSIM目前只支持虚拟micaz传感器,但是如果是用来比较两种不同的算法,或者是纯粹为了调试程序,适用平台不是特别重要。编译也非常简单,就是命令由此前的:

make micaz

变成:

make micaz sim

一般情况下是不会出现问题的,Ubuntu默认安装了Python。最常见的不过就是无法找到Python.h文件:

Python.h: No such file or directory

或者是找不到tinyos.tossim.TossimApp包:

No module named tinyos.tossim.TossimApp

两种情况在TOSSIM的文档当中都有介绍解决办法。前者是前往文件/opt/tinyos-2.x/support/make/sim.extra,在PFLAGS行下指定Python.h文件的路径,通常是在/usr/include/python2.x/文件夹内,我系统上面的是2.6。

1
CFLAGS += -I/usr/include/python2.6/

后者是需要在PYTHONPATH环境变量内添加TinyOS附带的Python API的路径,我将此行添加在/opt/tinyos-2.x/tinyos.sh文件内:

1
export PYTHONPATH=$PYTHONPATH:$TOSROOT/support/sdk/python

一般就没什么问题了。编译的过程当中可能会出现一打warning,不是什么大问题,感觉主要是python版本引起的,只要成功编译就没问题了。

*** Successfully built micaz TOSSIM library.

我目前主要是用来调试程序,所以主要是一个需要输出调试信息,另一个就是需要访问变量。NesC带来的四条命令,分别是dbg,dbg_clear,dbgerror还有dbgerror_clear。dbg是输出一条带传感器节点ID的普通调试信息,dbgerror则是输出一条带ID的错误信息,两者唯一的区别就是输出信息时候的开头不一样。dbg输出信息开头为DEBUG,dbgerror输出时则显示ERROR。而带clear后缀的两条命令和前两者使用一样,唯一的区别就是不带ID。

dbg带两个参数,前者是信息输出的频道(不是真正意义上的频道,而是一个比喻),后者是信息本身,信息的书写和sprintf函数一样,例如:

1
dbg("Boot", "Mote booted");

则输出Mote booted到Boot频道。不同的频道可以绑定到不同的输出口,可以直接显示在屏幕上,也可以将输出信息写入文件、以便事后查阅。
现在有一段NesC程序,描述的是Boot接口提供的booted事件:

1
2
3
4
event void Boot.booted() {
    dbg("Boot", "Application booted.\n");
    dbg("Radio", "Application booted again.\n");
}

按照要求,传感器节点在启动以后,需要输出两条消息,Application booted输出到Boot 频道,Application booted again输出到Radio频道。

执行TOSSIM需要一个简单的Python脚本,可以直接保存进入一个py文件,由python直接一口气载入执行,也可以在python互动模式下,逐条输入指令运行。脚本的开头基本都是一样的:

1
2
3
from TOSSIM import *
from tinyos.tossim.TossimApp import *
t = Tossim([])

因为我从没学过python,所以只能凭着经验去理解这些脚本指令。编译后会生成一个TOSSIM.py的文件,前两句应该是和Java一样载入文件内的类,第三句则是实例化一个Tossim类。方括号内是该类构建器的参数,这里默认不带任何参数。需要知道Tossim类型对象内的属性和方法,则可以通过dir命令:

1
2
3
4
5
6
7
8
dir(t)
['__class__', '__del__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__',
'__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'__swig_getmethods__', '__swig_setmethods__', '__weakref__', 'addChannel', 'currentNode',
'getNode', 'init', 'mac', 'newPacket', 'radio', 'randomSeed', 'removeChannel',
'runNextEvent', 'setCurrentNode', 'setTime', 'this', 'thisown', 'ticksPerSecond', 'time',
'timeStr']

带__前后缀的为对象属性,不带前后缀的则为Tossim类的方法。然后我们可以使用该对象的getNode方法创建一个节点。

1
m = t.getNode(1)

这里我们创建一个ID为1的节点m。在NesC代码中,我们的两条信息,是分别输出到Boot和Radio两个不同的频道,但是目前这两个频道都尚未派上用场。我们希望Boot频道内的信息直接通过屏幕输出、显示出来,而Radio频道的信息则写入log.txt文件内。

1
2
3
4
f = open("log.txt", "w")
t.addChannel("Boot", sys.stdout)
t.addChannel("Radio", f)
m.turnOn()

我们首先以写入模式(w)打开一个名叫log.txt的文件,然后开始向t,也就是Tossim对象内添加频道。Boot频道被指向sys.stdout,也就是标准输出,而Radio频道则被添加到f,也就是我们的文件。最后使用m节点的turnOn方法,启动节点。随着节点启动,booted事件被执行,两条dgb执行也被逐一执行。不出意外的话,屏幕上会显示?Applicaion booted。然后在当前目录下会多出一个log.txt文件,打开会发现Application booted again.信息。整个脚本完成的代码是:

1
2
3
4
5
6
7
8
9
from TOSSIM import *
from tinyos.tossim.TossimApp import *
 
t = Tossim([])
m = t.getNode(1)
f = open("log.txt", "w")
t.addChannel("Boot", sys.stdout)
t.addChannel("Radio", f)
m.turnOn()

你可以直接启动python,逐行输入执行,也可以保存为,例如sim.py文件,然后通过指令python sim.py来执行。这里Tossim还有一个有用的方法,就是runNextEvent。顾名思义,就是执行下一个事件。但是在执行事件前,记得需要先创建并且启动一个节点。

然后是一个简单的查看变量值的例子,TOSSIM目前尚不支持查看struct内的值,但是可以查看描述程序执行状态的普通变量的值。程序编译完以后会生成一个app.xml文件,里面包含了所有程序内的变量、组件信息,所以只要把这些信息“喂”给TOSSIM,TOSSIM便可以在执行过程当中跟踪节点程序的执行情况。我们把刚才的程序该一下:

1
2
3
4
5
6
uint8_t counter = 0;
event void Boot.booted() {
    dbg("Boot", "Application booted.\n");
    dbg("Radio", "Application booted again.\n");
    counter ++;
}

也就是变量counter初始化为0,在节点启动之后,自增为1。然后将sim.py也做相应的修改:

1
2
3
4
5
6
7
8
9
10
from TOSSIM import *
from tinyos.tossim.TossimApp import *
 
n = NescApp()
v = n.variables.variables()
t = Tossim(v)
m = t.getNode(1)
m.turnOn()
v = m.getVariable("RadioCountToLedsC.counter")
print(v.getData())

首先是创建一个NescApp的对象,然后通过该对象的variables属性的variables方法返回程序内所有的变量。然后实例化Tossim对象的时候,将变量作为参数地交给Tossim类的构建器,这样Tossim执行时便会跟踪程序内的变量变化。再往后就是前面已经介绍过了,通过getNode创建一个节点,然后启动该节点。按照程序内的描述,节点在启动之后,counter变量会自增。然后通过节点的getVariable方法取回counter变量,而参数里面的RadioCountToLedsC则为NesC组件的名称。最后,用print命令把代表变量counter的对象v的值显示出来。不出意外的话,显示为1。

这些只是TOSSIM的简单应用,但是已经可以帮到不少忙了。还有其他更复杂一点的应用,例如多个节点间的交互等等,详细可以看Doc。先写到这里了,下班回家了。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多