TinyOS、库及其应用程序都是用nesC语言编写的。TinyOS是一种面向传感器网络的新型操作系统,它最初是用汇编和C语言编写的。但在应用过程中,发现C语言不能有效方便地支持面向传感器网络的应用和操作系统的开发,相关工作人员为此对C语言进行了一定的扩展,开发出nesC语言。
1.nesC语言结构
nesC是C语言的扩展,精通C语言的程序员掌握这种语言相对比较快。与C语言的存储格式不同,用nesC语言编写的文件是以“.nc”为后缀。每个nc文件实现一个组件功能(组件化/模块化)。在nesC程序中,主要定义两种功能不同的组件——模块(module)和配件(configuration)。
模块主要用于描述组件的接口函数功能以及具体的实现过程,每个模块的具体执行都由4个相关部分组成:命令函数、事件函数、数据帧和一组执行线程。其中,命令函数是可直接执行,也可调用底层模块的命令,但必须有返回值,来表示命令是否完成。返回值有3种可能:成功、失败、分步执行。事件函数是由硬件事件触发执行的,底层模块的事件函数与硬件中断直接关联,包括外部事件、时钟事件、计数器事件。一个事件函数将事件信息放置在自己的数据帧中,再通过产生线程、触发上层模块的事件函数、调用底层模块的命令函数等方式进行相应处理,因此节点的硬件事件会触发两条可能的执行方向——模块间向上的事件函数调用和模块间向下的命令函数调用。配件主要是描述组件不同接口的关系,完成各个组件接口之间的相互连接和调用。相关执行部分主要包含提供给其他组件的接口和配件要使用的接口的组件接口列表和如何将各个组件接口连接在一起的执行连接列表。基于nesC语言的一般程序框架图如图4-9所示。
模块和配件的定义格式如下:
在模块中,关键字“implementation”必须包含实现模块提供和使用接口声明的全部命令和事件。在配件中,关键字“implementation”定义执行部分,连接用“->”、“=”、“<-”等符号表示,“->”表示位于左边的组件接口要调用位于右边的组件接口。
接口名应该是动词或名词,如果由多个单词组成,则每个单词的首字母要大写,例如,ADC、Range、SendMsg、BombillaLocks。
图4-9 基于nesC语言的一般程序框架图
组件名应该为名词,如果由多个单词组成,则每个单词首字母要大写。关于组件名有两种情况:一是以大写字母“C”为结尾的,另一种是以大写字母“M”为结尾的。这是为了互相区分接口及其提供者配件、模块。
大写字母“C”代表Component。它用于区分一个接口(例如Timer)和该接口的提供者(例如TimerC)。
大写字母“M”代表Module。当一个逻辑组件同时拥有配件和模块时,遵循此规则。例如,在tos/system目录下的Timer。TimerC组件是一个配件,并且连接其使用到的接口至Clock和LED接口的提供者。换句话说,任何直接使用TimerM的必须自己在代码中明确地将TimerM使用到的接口连接到提供者。例如,IntToRfm、IntToRfmM、TimerC、TimerM、UARTM。
所有的nesC文件必须以“.nc”为后缀。文件名必须可以体现出其所包含的内容特征,例如,Counter.nc、IntToRfm.nc、IntToRfmM.nc、TimerC.nc、TimerM.nc、UARTM.nc。
不管是模块还是配件,每个组件都包含了定义和实现两部分。被提供者和被使用者都是通过调用接口来实现各个接口的通信和函数的功能,不同的模块也可以实现相同的接口。接口可以是命令和事件,也可以是单独定义的一组命令。在应用程序中存在多个配置文件,并且配件之间存在一个层次关系,最上面的为顶层配件文件(每个应用程序必须有一个顶层配件),定义了Main组件接口与其他组件接口的连接方式以及各个接口间的调用关系。
2.nesC应用程序的分析
每一个nesC应用程序都是由一个或多个组件通过接口连接起来,并通过ncc/gcc编译生成一个完整的可执行程序。下面以TinyOS软件中的Blink(灯闪烁实例)应用程序为例,具体介绍nesC应用程序结构。
Blink程序是一个简单的nesC应用程序。它的主要功能是每隔1s的时间间隔亮一次,关闭系统时红灯亮。其程序主要包括3个子文件Blink.nc、BlinkM.nc和SingleTimer.nc。
(1)Blink.nc文件
这个文件为整个程序的顶层配件文件,关键字为configuration,通过“->”连接各个对应的接口。文件关键内容如下:
从上述代码中可看出,该配件使用了Main组件,定义了Main接口和其他组件的调用关系,是整个程序的主文件,每个nesC应用程序都必须包含一个顶层配置文件。
(2)BlinkM.nc文件
BlinkM.nc为模块文件,关键字为module、command,通过其调用StdControl接口中的3个命令“init,start,stop”连接接口,是实现Blink程序的具体功能。内容如下:
(www.daowen.com)
(3)SingleTimer.nc文件
SingleTimer.nc为一个配件文件,主要通过TimerC和StdControl组件接口实现与其他组件之间的调用关系,配件文件还定义了一个唯一时间参数化的接口Timer。下面给出部分伪代码:
注意,程序中斜体字表示nesC语法中所用到的关键字。
将nesC编写的配件文件、模块文件通过接口联系起来就形成了图4-10所示的Blink组件接口的逻辑关系。从图中可清晰地看出在Blink程序中组件之间的调用关系,各配件文件(如SingleTimer和LedsC)以层次的形式连接,体现了nesC组件化/模块化的思想。
3.nesC程序的仿真
关于nesC应用程序的执行,在TinyOS上提供了一个可视化图形仿真器——Tinyviz,观测TinyOS应用程序具体功能的执行过程。以TinyOS自带的app应用文件Blink程序执行过程为例,其他基于TinyOS开发的应用程序软件调试、仿真均可用以下执行方法。
图4-10 Blink组件接口的逻辑关系
(1)运行环境
在PC上安装TinyOS的运行平台,具体安装过程和安装Windows系统一样。为避免与PC自身系统的冲突,可将安装包tinyos-1.1.0.exe(软件版本以实际仿真的版本为主,现升级到TinyOS-2.1)安装到指定路径(本仿真软件环境是安装在D盘下)。这个安装包已经包含了Java、Cygwin,TinyOS相关软件和相关编译器,同时提供像mica、micaz等硬件驱动,针对不同硬件编译生成可执行文件下载。
(2)执行步骤
1)打开生成的cygwin图标(Linux建立在Windows下的软件平台),在光标下进入仿真环境路径(安装在D盘下):
cygdrive/d/tinyos/cygwin/opt/…/tinyos/sim,寻找软件仿真路径。
2)输入make,之后将生成一个执行脚本文件Tinyviz.jar。
3)进入应用程序路径。在相同的路径下进入Blink目录下。
4)输入makepc,在PC上对Blink程序进行编译、仿真,若有相关硬件,则输入硬件名称,如makemicaz,在Blink文件下会生成一个PC文件夹,里面包含了在PC上Blink主程序main.exe。
5)打开Blink/PC路径,输入:tinyviz-run main.exe10(10为传感器节点的仿真个数)。
利用可视化Tinyviz将调用接口使Blink程序执行的仿真结果通过图形显示出来,仿真结果如图4-11所示。最上面一层显示了整个程序仿真时间长度和仿真终止按键。图中每个节点的位置可以任意布置,仿真间隔时间也能自行设定。Blink程序的主要功能是每经过1s的时间间隔,每个仿真节点上红灯会闪烁1次,如图中节点0红灯是灭的,节点6红灯是亮的。该图很清晰地将nesC编写的应用程序功能仿真出来,对具体代码的硬件化执行提供了实现方法。
图4-11 基于TinyOS的Blink程序运行图
通过对Blink程序的详细分析可以看出,用nesC编写的程序能很好地将组件化/模块化的思想应用到程序中,对于其他nesC应用程序编写也能调用各组件接口,代码量少,能快速建立程序中模块间的连接,减少执行任务和事件驱动时线程间不必要的资源消耗,其具体功能可通过仿真软件反映出来。掌握nesC的语法,可以大大地降低实现无线传感器网络操作系统和上层的应用程序的复杂度,为深入学习与研究TinyOS系统以及其上应用程序的设计提供了参考方法。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。