DSP

TinyOS 学习笔记之TOSSIM

2019-07-13 17:18发布

       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。 


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


后者是需要在PYTHONPATH环境变量内添加TinyOS附带的Python API的


路径,我将此行添加在/opt/tinyos-2.x/tinyos.sh文件内: 


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函数一样,例如: 


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


则输出Mote booted到Boot频道。不同的频道可以绑定到不同的输出口,可


以直接显示在屏幕上,也可以将输出信息写入文件、以便事后查阅。 


现在有一段NesC程序,描述的是Boot接口提供的booted事件: 


event void Boot.booted() { 


 dbg("Boot", "Application booted. "); 


 dbg("Radio", "Application booted again. "); 





按照要求,传感器节点在启动以后,需要输出两条消息,Application booted


输出到Boot 频道,Application booted again输出到Radio频道。 


执行TOSSIM需要一个简单的Python脚本,可以直接保存进入一个py文件,


由python直接一口气载入执行,也可以在python互动模式下,逐条输入指令


运行。脚本的开头基本都是一样的: 


from TOSSIM import * 


from tinyos.tossim.TossimApp import * 


t = Tossim([]) 因为我从没学过python,所以只能凭着经验去理解这些脚本指令。编译后会生


成一个TOSSIM.py的文件,前两句应该是和Java一样载入文件内的类,第三


句则是实例化一个Tossim类。方括号内是该类构建器的参数,这里默认不带任


何参数。需要知道Tossim类型对象内的属性和方法,则可以通过dir命令: 


>>> 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方法创建一个节点。 


m = t.getNode(1) 


这里我们创建一个ID为1的节点m。在NesC代码中,我们的两条信息,是


分别输出到Boot和Radio两个不同的频道,但是目前这两个频道都尚未派上用


场。我们希望Boot频道内的信息直接通过屏幕输出、显示出来,而Radio频道


的信息则写入log.txt文件内。 


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.信息。整个


脚本完成的代码是: 


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便可以在执行过程当中跟踪节点程序的执行情


况。我们把刚才的程序该一下: 


uint8_t counter = 0; 


event void Boot.booted() { 


 dbg("Boot", "Application booted. "); 


 dbg("Radio", "Application booted again. ");  counter ++; 





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


也做相应的修改: 


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。