在学习TinyOS时,我的学习方法是学习安装TinyOS源码后得到的自带的例程,其中比较容易的例程就是Blink。下面可以看看Blink例程相关的两个文件,一个是配置组件文件BlinkLed.nc,一个是模块组件文件BlinkLEDM.nc。
BlinkLed.nc配置组件文件:
configuration BlinkLed
{
}
implementation
{
components BlinkLedM as App;
components MainC;
App.Boot-> MainC.Boot;
components LedsC;
App.Leds->LedsC.Leds ;
components new TimerMilliC() as Timer1;
App.Timer1->Timer1;
components new TimerMilliC() as Timer2;
App.Timer2->Timer2;
}
BlinkLed.nc配置组件文件中用到了MainC、LedsC及TimerMilliC这三个组件,并在该文件中对这三个组件的接口进行了连着。MainC与系统启动等有关,TimerMilliC容易发现与定时器有关,LedsC则与Led灯的操作相关。这里就先研究这个LedsC这个组件文件,可以通过命名规则看出这应该是一个配置组件文件里给出的。找到该文件LedsC.nc,查阅代码如下:
configuration LedsC {
provides interface Leds;
}
implementation {
components LedsP, PlatformLedsC;
Leds = LedsP;
LedsP.Init <- PlatformLedsC.Init;
LedsP.Led0 -> PlatformLedsC.Led0;
LedsP.Led1 -> PlatformLedsC.Led1;
LedsP.Led2 -> PlatformLedsC.Led2;
}
在该配置组件文件中为别的组件可以提供一个接口Leds。配置组件和模块组件一样,也可以提供和使用接口,但配置组件没有接口实现代码,只能将其他组件的接口连接起来。为了实现配置组件提供和使用接口所需要的代码,配置组件利用“=”操作符将其他组件的实现部分进行重命名作为自己实现代码中的一部分。因此这里就有了这句代码:
Leds = LedsP;
不太明白的是,为什么还要在该配置组件文件中加上如下代码???
LedsP.Init <- PlatformLedsC.Init;
LedsP.Led0 -> PlatformLedsC.Led0;
LedsP.Led1 -> PlatformLedsC.Led1;
LedsP.Led2 -> PlatformLedsC.Led2;
在该配置组件文件中用到了另外两个组件,一个是LedsP,这是一个模块组件;另一个则是PlatformLedsC,这是配置组件。以上两个组件均需要用到另外组件提供的接口,如LedsP需要Led0、Led1、Led2接口,而PlatformLedsC则用到Init接口,难道这是需要在LedsC.nc文件中加上如上4句代码的原因???下面来看看这两个组件文件的代码吧。
LedsP.nc文件提供了Init、Leds两个接口,使用了Led0、1、2接口。提供的命令函数有Init.init()、Leds.Led0On()、Leds.Led0Off()、Leds.Led0Toggle()、Leds.Led1On()、Leds.Led1Off()、Leds.Led1Toggle()、Leds.Led2On()、Leds.Led2Off()、Leds.Led2Toggle()、Ledsget()、Ledsset()。具体代码如下:
module LedsP @safe() {
provides {
interface Init;
interface Leds;
}
uses {
interface GeneralIO as Led0;
interface GeneralIO as Led1;
interface GeneralIO as Led2;
}
}
implementation {
command error_t Init.init() {
atomic {
dbg("Init", "LEDS: initialized.\n");
call Led0.makeOutput();
call Led1.makeOutput();
call Led2.makeOutput();
call Led0.set();
call Led1.set();
call Led2.set();
}
return SUCCESS;
}
/* Note: the call is inside the dbg, as it's typically a read of a volatile
location, so can't be deadcode eliminated */
#define DBGLED(n) \
dbg("LedsC", "LEDS: Led" #n " %s.\n", call Led ## n .get() ? "off" : "on");
async command void Leds.led0On() {
call Led0.clr();
DBGLED(0);
}
async command void Leds.led0Off() {
call Led0.set();
DBGLED(0);
}
async command void Leds.led0Toggle() {
call Led0.toggle();
DBGLED(0);
}
async command void Leds.led1On() {
call Led1.clr();
DBGLED(1);
}
async command void Leds.led1Off() {
call Led1.set();
DBGLED(1);
}
async command void Leds.led1Toggle() {
call Led1.toggle();
DBGLED(1);
}
async command void Leds.led2On() {
call Led2.clr();
DBGLED(2);
}
async command void Leds.led2Off() {
call Led2.set();
DBGLED(2);
}
async command void Leds.led2Toggle() {
call Led2.toggle();
DBGLED(2);
}
async command uint8_t Leds.get() {
uint8_t rval;
atomic {
rval = 0;
if (!call Led0.get()) {
rval |= LEDS_LED0;
}
if (!call Led1.get()) {
rval |= LEDS_LED1;
}
if (!call Led2.get()) {
rval |= LEDS_LED2;
}
}
return rval;
}
async command void Leds.set(uint8_t val) {
atomic {
if (val & LEDS_LED0) {
call Leds.led0On();
}
else {
call Leds.led0Off();
}
if (val & LEDS_LED1) {
call Leds.led1On();
}
else {
call Leds.led1Off();
}
if (val & LEDS_LED2) {
call Leds.led2On();
}
else {
call Leds.led2Off();
}
}
}
}
PlatformLedsC.nc文件提供的接口为Led0、1、2,通过接口可以调用命令函数,详细见上面LedsP.nc文件。至于使用到的Init接口,这里使用了该句代码进行了连接
Init = PlatformP.LedsInit;
那么在LedsC.nc配置文件中的连接绑,即将PlatformLedsC.Init绑定到LedsP.Init组件接口中又是什么意思?
LedsP.Init <- PlatformLedsC.Init;
PlatformLedsC.nc文件如下:
configuration PlatformLedsC
{
provides interface GeneralIO as Led0;
provides interface GeneralIO as Led1;
provides interface GeneralIO as Led2;
uses interface Init;
}
implementation
{
components HplCC2530GeneralIOC, PlatformP;
Init = PlatformP.LedsInit;
/*#ifdef GATEBOARD
Led0 = HplCC2530GeneralIOC.P1_Port[4]; //P14=Red Led
Led1 = HplCC2530GeneralIOC.P1_Port[1]; //P11=Blue Led
Led2 = HplCC2530GeneralIOC.P1_Port[0]; //P10=Yellow Led
#else
Led0 = HplCC2530GeneralIOC.P1_Port[2]; //P12=Red Led
Led1 = HplCC2530GeneralIOC.P1_Port[3]; //P13=Blue Led
Led2 = HplCC2530GeneralIOC.P2_Port[0]; //P20=Yellow Led
#endif
*/
Led0 = HplCC2530GeneralIOC.P1_Port[0]; //P12=Red Led
Led1 = HplCC2530GeneralIOC.P1_Port[1]; //P13=Blue Led
Led2 = HplCC2530GeneralIOC.P2_Port[2]; //P20=Yellow Led
}
最后我们再看看BlinkLEDM.nc模块组件文件,该文件具体实现了闪灯的功能,代码如下:
module BlinkLedM
{
uses interface Boot;
uses interface Leds;
uses interface Timer<TMilli> as Timer1;
uses interface Timer<TMilli> as Timer2;
}
implementation
{
task void Demo()
{
}
event void Boot.booted() {
call Timer1.startPeriodic(1024);
call Timer2.startPeriodic(1024);
call Leds.led0Off();
call Leds.led1Off();
}
event void Timer1.fired()
{
call Leds.led0Toggle();
}
event void Timer2.fired()
{
call Leds.led1Toggle();
}
}
BlinkLEDM.nc模块组件文件不难理解,这里就不再啰嗦了。针对本文中的那个问题,请看到的各位朋友帮忙看看到底是什么意思?为啥文章中标红的那四句要加上。在此感谢了!
By:霜月孤鸟
2015.12.11
==============================================================================================================
来自6lowpan/Zigbee开源交流群(312145492)群主的解答。
问题1:文件LedsC.nc中为何代码中出现最后四行的接口间的连接?
configuration LedsC {
provides interface Leds;
}
implementation {
components LedsP, PlatformLedsC;
Leds = LedsP;
LedsP.Init <- PlatformLedsC.Init;
LedsP.Led0 -> PlatformLedsC.Led0;
LedsP.Led1 -> PlatformLedsC.Led1;
LedsP.Led2 -> PlatformLedsC.Led2;
}
或者再去看看LedsP.nc
uses {
interface GeneralIO as Led0;
interface GeneralIO as Led1;
interface GeneralIO as Led2;
}
【飞机】开源的6lowpan(417837043) 2015/12/11 22:50:07
事实上需要 provider
LedsP.Init <- PlatformLedsC.Init;
LedsP.Led0 -> PlatformLedsC.Led0;
LedsP.Led1 -> PlatformLedsC.Led1;
LedsP.Led2 -> PlatformLedsC.Led2;
PlatformLedsC就是provider
这个是最基础的 从lib连向底层驱动的方式
【飞机】开源的6lowpan(417837043) 2015/12/11 22:51:28
注意configurationd的代码 不一定是有use interface的
但是对于他的xxP.nc文件 确使用了
那么久需要配置文件configuration 显示的 注册组件
当然这是群主回答的这个问题的其中一个方案,呵呵
问题2:LedsC.nc文件中有了“LedsP.Init <- PlatformLedsC.Init; ”这句。为啥PlatformLedsC.nc文件里面还要“Init = PlatformP.LedsInit;”?
回答如下:
那是他自己用的 初始化底层的
IO口初始化
平台的底层驱动
configuration PlatformLedsC
{
provides interface GeneralIO as Led0;
provides interface GeneralIO as Led1;
provides interface GeneralIO as Led2;
uses interface Init;
}
implementation
{
components HplCC2530GeneralIOC, PlatformP;
Init = PlatformP.LedsInit;
这个Init = PlatformP.LedsInit是PlatformLedsC配置组件自己用的,那他在LedsC.nc中不是也连接到了LedsP模块组件的LedsP.Init接口了?
configuration LedsC {
provides interface Leds;
}
implementation {
components LedsP, PlatformLedsC;
Leds = LedsP;
LedsP.Init <- PlatformLedsC.Init;