除非特别说明,所有的程序都是基于tinyos-1.3的,并在VM 模拟Win xp 32位下用cygwin调试运行。
思想:
Tinyos使用的是一种特殊的,面向组件的编程思想,这种思想和用惯了面向对象的编程思想的我来说,非常不习惯。Tinyos和nesC为什么难学? 因为他没有正常的教科书,不像C, C++,Java 一样有专门的书或者资料,告诉你需要实现什么功能,要去用到什么类(这里是组件),要去用什么接口,要去用什么函数。 Tinyos完全没有这些东西,什么都是让你自己去摸索和实践。
所以你有太多的不习惯:
你不习惯NesC程序的基本组成是Component,每个Component是一个*.nc文件。这里不像Java,大家都知道java当中的类是有继承关系,有子类超类等等。你只需要知道一些简单的类,就可以自己扩展学习,即使有没见过的类,也可以找到很详细的介绍和使用方法。NesC中没有类的概念,自然也就没有子类超类,没有继承,也就是说,如果你知道有这么一个Component,你就可以用这个Component 可以完成一定的工作。但是如果你不知道这个Component呢,尤其是某些底层的Component 那么嘿嘿~~!! 要么你像我一样,去逼自己看懂系统提供那些的Component,要么自己写一个。可问题你现在连最简单的blink程序都看不懂,更何况自己写了。所以每个用NesC的初学者都和瞎子差不多,说白了,你就是什么都不会的。你的C还有java经验都根本没用。当然,你会if 还有for语句,这是你在学习tinyos中唯一比买菜大妈强的地方。
你不习惯NesC程序的中Component的使用方法。
NesC程序中采用了一种所谓的wiring的机制来指明component与component之间的关系。
一个Component调用其他的Component的方式是使用 “interface”,使用方用关键字“uses”的interface连接到提供方 “provides”的interface。那么使用方就可以在自己的实现中去使用来自提供方“interface”当中的方法。在这里必须强调:
A.
一个组件如果use某个interface,就必须实现这个interface当中的event。
B.
一个组件如果provide某个interface,就必须实现这个interface当中所有的command。
Interface我个人把他看成是系统可以识别的方法或者说函数的集合,或者可以说系统的API,通常interface的内容是几个command 和/或 event的声明。单看interface文件而言,command和event里面的内容是空着的,这点和java很像。
command 和 event是逻辑代码具体实现的地方,他们的具体内容由provide他们的component来实现。我们所熟悉的内容在这里出现,if和for都可以在这里出现了。我的理解,command和event就是我们熟悉的c语言当中的函数,或者java当中的方法。因为command出现了标志性的括号,比如init()。注意,在被调用的时候,Command用“call”,event用“signal”。
TinyOS提供了一些系统interface,用来完成基本的程序功能。这里很神奇,因为知道某个interface就可以直接完成你的工作,但是作为学习者的我们就非常的累,你必须去熟悉和了解这些interface对应的功能和用法。比如stdcontrol接口就是用来控制程序流程,有3个command,分别是init(),start(),stop()。再比如Leds接口是用来控制传感器上的灯的,有很多command,比如redon(),redoff()就是控制红灯亮暗。
在component,interface,command/event当中是有层次关系的。
一般来说,component是最高级的,可以理解为Interface是 Component的下层,command/event是interface的下层。Component. Interface. Command()
常见的Component分为两类,“configuration”和“module”
“configuration”用来完成component之 间的连接。这个是tinyos特有的。至少在我学习过的语言中,是独一无二的。我不评价这种机制好或者是不好,但是既然学习了这门语言,也就好好学习这个机制。
这个机制可以说是tinyos的核心,所以必须明白,而且要非常清楚! 它涉及到所有的nesC程序,所以可以认为这里是学明白nesC的关键。
有两个关键字来实现wiring,我翻译成“连接”好了。关键字 “à”和“ß”永远是将一个使用(uses)的接口于一个提供(provides)的接口相连接。 也就是说只有使用者组件能够调用提供者组件的接口。反过来就不可以。
Tinyos中,组件和接口是一个多对多的关系,即一个组件可以连接到很多接口,反过来说,很多组件都可以提供一个相同的接口!(核心!最难理解的地方!)
前面说,不同的组件可以提供相同的接口,如果组件ComA,ComB都提供了某一个接口InterfaceC, 那么,当组件ComD需要去访问InterfaceC接口时,怎么办? 它访问的到底是ComA提供的InterfaceC还是ComB提供InterfaceC的呢? 要知道,虽然接口的名称是一样的,但是不同组件提供的相同接口却是实现不同的功能。
所以配置文件就产生了,它的目的就是声明你要访问的组件名称,并且将它所提供的接口与你真正想要使用的接口相连接。
“module”才是一个组件的真实实现,用来完成该Component的功能,名字常常是xxxxxM,可以和configuration文件对应起来。 Module要声明自己使用和提供的借口,所以“module”当中是实现command和event的真正场所,当然还有特殊的内部函数和task都在这里实现。在被调用的时候,task用post,command用“call”,event用“signal”。
一般来说,TinyOS中的调度机制比较简单,TinyOS的调度遵循FIFS(先来先服务)规则。没有事件发生时任务列表按着FIFS进行处理,当事件发生时发生抢占,产生中断处理。它仅设置一个任务队列。关键字post将一个任务添加到任务队列中。不同的Task之间没 有优先级,但task可以被interrupt
handler打断。为防止全局变量等公用数据被非正常修改,nesC规定只在task中进入公共的数据部分。使用 “async”关键字可以指出某个command或者event可以在有中断时使用。为了协调任务和中断的执行,nesC使用 关键字“atomic”去指出代码不可被打断。
我不知道tinyos和 NesC的作者是不是吃大便长大的,本来就很晦涩难懂的nesC语言也不写个清晰的文档来解释清楚。也许可能是Tinyos tutorial 的作者英文很差(PS:这个是我美国导师说的)。在这里,请本blog的看官请注意,如果你是美式教材或者tinyos官方文档的支持者,你根本就不应该来看这篇文章,因为这篇文章就写给看不懂官方文档的同学看的。你看得懂官方文档或者说喜欢美国人的思维方式来介绍新知识新技术的方法,说明你英语和计算机科学水平比我高,所以也不用看加上我自身理解的NesC程序解释和指导的博文。虽然我在美国,但是我一点也不觉得美国的教材写的好。相反,根据我多年的教学经验和我自身的学习经验,我个人是非常认同和支持国内的很多c或者java教材的写法,层次感很清楚,介绍的内容由浅入深,知识慢慢学来。
该日志由 sundae 于3年前发表在综合分类下,最后更新于 2012年10月08日.
转载请注明: 第2篇 入门-tinyos编程思想(我对TinyOS1.x的理解,个人心血之作)