TinyOS总结(一)
一 命名的约定
(1) 所有的nesC文件的扩展名者是“.nc”。并且nesC编译器要求文件名与文件内定义的接口名或组件名相匹配。
(2) 目录名要使用小写字母。
(3) 接口名或组件名是以大写字母开关的混合形式。
(4) 所有的公共组件应当带有后缀“C”,所有的私有组件必须带有后缀“P”
(5) 接口名不能以“C”或“P”结尾。
(6) 如果接口和组件相关,除了组件名后缀(“C”和“P”)之外,建议两者采用相同的命名。
(7) 命令、事件、任务和函数都使用小写字母开头的混合形式。
(8) 常量名全部是大写字母,并且用下划线连接两个字词。推荐使用enum枚举不用#define。
(9) 模块内部变量使用以小写字母开头的混合形式。
二 接口(interface)
定义:就是一系列有名函数声明的集合。
作用: 是各个组件间的纽带。例如需要做一个应用,点亮LED灯。那应用自己写的组件名称是BlinkNoTimerTaskAppC(一般位于/opt /tinyos-2.1.1/apps/),而它需要使用的组件是tinyos写好的led组件(一般位于/opt/tinyos-2.2.1/tos /system)。但是两个是独立的,所以需要一个Led接口(位于/opt/tinyos-2.1.1/tos/interace)将它们联系起来。
请一定要记住,接口只有函数的声明,没有实现,实现依赖于具体的硬件芯片和硬件平台。关于接口里头的函数的实现可参看下一节。
interface Leds {
async command void led0On();
async command void led0Off();
async command void led0Toggle();
async command void led1On();
async command void led1Off();
async command void led1Toggle();
async command void led2On();
async command void led2Off();
async command void led2Toggle();
async command uint8_t get();
async command void set(uint8_t val);
}
官方给的文档中语法定义如下所示:
nesC-file:
includes-listopt interface //标识符列表
...
interface:
interface identifer {declaration-list} // 1: interface indtifer 接口类型标识符(具有全局的作用范围,并且属于分开的命名空间即组件和接口类型命名空间用此区分其它的接口和所有组件)
// 2: declaration-list 给出了相应接口的定义。声明列表由具有命令或事件的存储类型的函数定义构成,否则会产生编译错误
stroage-class-specifier:also one of command event async
三 实现
有了上一小节对interface的介绍。相信对已经对interface有一定的理解。但肯定有疑惑,接口只有声明没有实现的吗?为什么不也在接口实现呢。
我是样理解的,主要原因有2点:
(1)增强操作系统的抽象能力。因为接口的实现肯定依赖于具体的硬件芯片和硬件平台,如果实现代码了写出来,那么换过另外一个硬件芯片或者平台那直接要求重写接口代码。
(2)接口本身的定义就是不包括具体的实现的。接口 - 只提供一个访问的途径和方法并不是具体的实现。
那随之而来的疑问是就是实现在哪里呢?
为回答这个问题,首先回顾刚才写到的接口的作用:“接口是用来联结两个不同的组件的纽带”。那么实现可以参看所联结的纽带。
同样以“BlinkLed”为例:
(0.1)在应用层中通常有两个组件代码,一个是配件,一个是模块。
BlinkNoTimerTaskAppC.nc -- 是配件位于/opt/tinyos-2.1.1/apps
BlinkNoTimerTaskC.nc -- 是模块位于/opt/tinyos-2.1.1/apps
配件主要是负责联结规范元素。而模块的功能是利用或提供接口,来实现要求的应用,注意这里并不是接口中定义的命令或事件的实现,只是利用它们调用它们。
(0.2)然后我们再看看接口Leds的定义。
Leds.nc -- 接口代码位于/opt/tinyos-2.1.1/tos/interface
正如之前所介绍的那样,它只是一系列命令或者事件的声明。
(0.3)下面我们再回过头看看BlinkNoTimerTaskAppC.nc配件文件中相关的代码。
配件的主要功能是将模块中声明要使用的接口(都位于/opt/tinyos-2.1.1/tos/interface)与tinyos操作系统中相关定 义的组件(/opt/tinyos-2.1.1/tos/system)相联结。在该应用中我们具体需要使用的接口都会在相应的模块组件中声明(即 BlinkNoTimerTaskC.nc)。
(0.4)ok, 我们已经知道了使用的接口即为Leds.nc文件。那为了寻找具体点亮led的代码,就需要查看另外一端tinyos操作系统中提供的组件代码。进入 /opt/tinyos-2.1.1/tos/system中你会发现有两个与led相关的组件代码:LedsC.nc 和 LedsP.nc。
LedsC.nc 是配件组件。 LedsP.nc 是模块组件。
首先我们来看看模块组件LedsP.nc它声明哪些了接口,从此也可以看出它联结的两端到底是什么组件。
provides {
interface Init;
interface Leds;
}
uses {
interface GeneralIO as Led0;
interface GeneralIO as Led1;
interface GeneralIO as Led2;
}
从此,我们可以发现,它一端提供Leds接口(也就是接口文件中的接口),同时另一端使用GeneralIO接口,看此接口名称就会发现它其实就是联结 的具体开发平台(注意此处是硬件开发平台不是具体硬件芯片)。至此,应该陷约感觉到我们已经从软件应用层代码,到了具体硬件平台的管脚定义了。如果你还不 相信此接口是与具体硬件平台相关,那么你可以再看看配件代码LedsC.nc看它将Led0接口(也就是GeneralIO接口)联结的组件名称。
LedsP.Led0 -> PlatformLedsC.Led0;
LedsP.Led1 -> PlatformLedsC.Led1;
LedsP.Led2 -> PlatformLedsC.Led2;
就此就应该相信了它是与具体硬件平台相关的了吧。在我们进一步深入了解PlatformLedsC.nc代码之前,我们可以回过头看看,模块代码 LedsC.nc代码的相关实现。 你会有意外的收获。在它的implementation中你看到有很多函数准确来说是命令或事件,这些函数其实就是接 口Led的实现。所以总结一句:Led的接口中声明的函数是在tinyos系统中LedP.nc组件(/opt/tinyos-2.1.1/tos /system)中实现的。
(0.5) 但 是熟悉嵌入式开发的同学肯定会有所疑问,在LedP.nc组件中函数只是调用了一些函数(问:有了之前的讲解,那这些函数的声明你知道是在哪吗?答:肯定 是组件使用的接口GeneralIO接口,它联结的组件是LedC和PlatformLeds.nc。 问:那函数的具体实现会在哪呢,那肯定是接口联结 的另外一组件,PlatformLeds.nc)。所以这个三元组是 (LedC <- GeneralIO ->PlatformLeds)。依照上面的讲解,我们先看看
所以你想进一步查看具体的实现代码,就得到cd到平台代码文件夹中去了。此代码独立于tinyos操作系统,因为不同的硬件平台的实现是不一样的。至于具体使用的哪个平台,怎么体现在程序中呢,这就靠编译文件Makefile了。
我们先切入到platforms文件夹中了,具体应该在/tos/platforms/xxxx(xxxx是指具体的硬件平台请注意是硬件平台俗称开发 板不是芯片)。我们以CC2430开发平台CC2430EM为例(是TI出的开发板,目前国内大多数开发板都基本兼容)。在/http: //www.cnblogs.com/platforms/cc2430em文件夹中可以找到PlatformLedsC.nc文件,它是一个配件形式的 组件。
Configuration PlatformLedsC
{
provides interface GeneralIO as Led0;
...
}
再看这一句:
Led0_rev -> HplMcs51GeneralIOC.P10;
它又将Led0绑定到了HplMcs51GeneralIOC 组件中。所以具体的硬件实现就要查看HplMcs51GeneralIOC.nc文件。
在此,我也有个疑问为什么这个文件是在/opt/tinyos-2.x-contrib/diku/mcs51/tos/chips/mcs51,目录下呢,我个人理解应该是在
/opt/tinyos-2.x-contrib/diku/mcs51/tos/chips/cc2430下面啊...不解。
至此,应该对整个过程有非常深入的了解了吧。
Bye-bye ^^