Nesc1.2简述

Nesc1.2简述 1 组件 ,nesC组件使用的是一个纯局部的命名空间,这就是说一个组件除了要声明它将执行的函数外,还要声明它所调用的函数。每一个组件都有一个形式说明(specification),这个形式说明是一段代码,它声明了组件所提供(执行)接口(函数)和所使用(调用)的接口(函数) 2 接口,接口(interface)是相关函数的一个集合,用户可以根据功能的需要定义自己的接口,但在定义接口中的函数时,必须使用command或event关键字声明该函数是命令或是事件,否则编译时会报错。 nesC有两种组件: 配件(configurations),用于将组件连接在一起从而形成一个新的组件。 模块(modules),提供了接口代码的实现,并且分配组件内部状态,是组件内部行为的具体实现。 配件和模块的主要区别是后者有实现代码但不能连接。前者没有代码,但可以连接。 模块相关概念: 1)分段操作(Split Phase),分段接口的一个重要的特征就是两个阶段的调用是相反的:向下调用是开始操作,向上的signal操作是完成操作。在nesC中,向下调用的是命令,而向上调用的是事件,接口指定了这种关系的两个方面。 连续操作 If (send()==SUCCESS) { sendCount++;} 分段操作 Send();//开始阶段 ...... Void sendDone(error_t err)//完成阶段 { If (err==SUCCESS){ sendCount ++;} } 分段接口实例: interface Read { command error_t read(); event void readDone( error_t result, val_t val ); } Read接口的提供者需要定义Read函数和通知Readdone事件,而Rend接口的使用者则需要定义Readdone事件,而且能够调用Read命令。 2)类型化接口 接口可以带有类型参数 ,接口的类型参数放在一对尖括号里,这个参数定义了它要处理的数据的类型。 如果提供者和使用者的接口都带有类型参数,那么在连接时,它们的类型必须匹配。 例:LocalTime接口带有一个precision_tag参数,定义在 pt/tinysos-2.x/tos/lib/timer目录中。如下: terface LocalTime { async command uint32_t get(); } 参数precision_tag虽然没有在接口的命令中出现,但它在连接时会被用于类型检查:该参数指明了最小的时间间隔。三种类型是TMili(毫秒),T32kHz和TMicro(微秒)。 3)模块实现(Module Implementation) 在Implementation{}内的就是模块的实现部分。模块必须实现它所提供的接口中的每个命令(即provide中的每个命令),和它所使用的接口中的每一个事件。 以sense为例: module SenseC { uses { interface Boot;//注意:Boot接口中有事件booted(),故须实现。 interface Leds; interface Timer;//此接口中有event void Timer.fired()须实现。 interface Read;// /此接口中有event void Read.readDone()须实现。 } Implementation // 以下是实现部分 { #define SAMPLING_FREQUENCY 100 event void Boot.booted() { call Timer.startPeriodic(SAMPLING_FREQUENCY);//调用了Timer接口的命令 } event void Timer.fired() //因为使用了Timer接口,所以必须实现Timer接口中定义的事件 { call Read.read();//调用了Read接口的命令} event void Read.readDone(error_t result, uint16_t data) //因为使用了Read接口,所以必须 { //实现 Read接口中定义的事件 if (result == SUCCESS){ if (data & 0x0004) call Leds.led2On(); else call Leds.led2Off(); if (data & 0x0002) call Leds.led1On(); else call Leds.led1Off(); if (data & 0x0001) call Leds.led0On(); else call Leds.led0Off(); } } } 4)配件和连接 组件之间是完全独立的,只有通过连接才能绑定到一 起 ,配件用于实现此功能。配件的定义与模块类似 使用了三个操作->,<-和=实现连接。前面两个是最基本的连接操作:箭头从使用者指向提供者。例如,下面两行是等同的: Sched.McuSleep -> Sleep; Sleep<-Sched.McuSleep; 一个直接的连接总是从使用者uses指向提供者provides,箭头的方向决定了调用关系和模块一样,配件可以提供和使用接口。但是由于配件没有代码实现,所以这些接口的实现必须依赖其他的组件。 5)扇入,扇出,combine函数 接口之间可以是n对k的关系,这里n是使用者uses数,k是提供者provides数. 扇出(fan-out)同一个调用者一次调用了多个函数。 扇入(fan-ins)用来描述多个人调用同一个函数。 接口之间是一个n对k的关系,任何提供者的signal将会引起n个使用者的事件处理函数,并且任何使用者调用一个命令将会调用k个提供者的命令。 combine函数,它将多个返回值组合后只返回一个值。一个数据类型可以有一个相关的combine函数。因为一个fan-out总是涉及到调用N个相同的函数,调用者最终得到的返回值是对所有的被调用者的返回值使用combine函数之后得到的返回值。 例: generic configuration AMSnoopingReceiverC(am_id_t AMId) { provides { interface Receive; interface Packet; interface AMPacket; } } implementation { components ActiveMessageC; Receive = ActiveMessageC.Snoop[AMId]; Receive = ActiveMessageC.Receive[AMId]; Packet = ActiveMessageC; AMPacket = ActiveMessageC; } AMSnoopingReceiverC .Receive既被映射到了ActiveMessageC.Snoop[AMId];又被映射到了ActiveMessageC.Receive[AMId]。则调用AMSnoopingReceiverC .Receive.getPayload()函数时,也就同时调用了ActiveMessageC.Snoop[AMId] .getPayload()和ActiveMessageC.Receive[AM Id] .getPayload(),但是这两个函数的调用顺序不确定。 6)参数化连接 参数化接口用于提供同一接口的多个实例。如: configuration ActiveMessageC { provides { interface SplitControl; interface AMSend[uint8_t id]; interface Receive[uint8_t id]; …… } } 这种其实相当于: onfiguration ActiveMessageC { provides { interface SplitControl; interface AMSend as AMSend1; interface AMSend as AMSend2; interface AMSend as AMSend3;//在这里1,2,3的函数实现是相同的。才可以用上面的参数来实现。 ................ interface Receive as Receive1; interface Receive as Receive2; interface Receive as Receive3; …… } } 那么它可以使用如下格式的配件: Configuration MyAppC{} Implementation { Components MainC, MyApp, ActiveMessageC; MainC.SoftwareInit->ActiveMessageC; MyApp.AMSend->ActiveMessageC.AMSend[100];//这里有100可以是用户自已指定的。 MyApp.Receive->ActiveMessageC.Receive[100]; } 故可以看出,参数化接口本质上是一个接口数组,数组的索引就是接口的参数。这样定义目的是函数实现的简单化。 nesC还提供了一个unique函数用于保证以参数不重复。例如: #include "AM.h" generic configuration AMSenderC(am_id_t AMId) { provides { interface AMSend; interface Packet; interface AMPacket; interface PacketAcknowledgements as Acks; } } implementation { components new AMQueueEntryP(AMId) as AMQueueEntryP; components AMQueueP, ActiveMessageC; AMQueueEntryP.Send -> AMQueueP.Send[unique(UQ_AMQUEUE_SEND)]; ......... } 在"AM.h"中,有如下定义:#define UQ_AMQUEUE_SEND “qmqueue.send” uniqueCount(UQ_AMQUEUE_SEND)用来计算共有多少次unique(UQ_AMQUEUE_SEND)。 7)通用组件(Generic Components) 通用组件不是单一实例的,它在配件内能被实例化。一般来说,组件是单一实例的,这就是说,组件的名字是全局命名空间一个单独的实体。一个组件只可以被实例化一次。当两个不同的组件引用MainC时,它们都将会引用同样的代码段和状态。但通用组件不是单一实例,它在配件内能被实例化。 通用组件与非通用组件原型定义的最大差别有两点: (1)在关键字component(表示module或configuration)之前有一个generic关键字,它表示该组件是通用组件。 (2)通用组件在组件名字后必须带有参数列表,从这方面来看类似于函数的定义。若该通用组件不需要参数,那么该参数列表为空。 目前通用组件支持如下三种类型的参数: 类型(types)参数:这些参数可以作为类型化接口的参数,声明时使用typedef。 数值常数(numeric constants)参数。 字符串常数(constant strings)参数。 使用通用组件时需要在配件中使用关键字new实例化一个通用组件,这个实例是配件所私有的。用户每使用户每使用一次new便被会创建一个实例。在使用关字new实例化通用组件的时候,系统使用了代码拷贝的方式生成新的实例。例如: Implementation{ Components new BitVectorC(10);//创建了一个大小为10的BitVectorC组件。同时也实现了//BitVectorC代码的拷贝。 } 通用模块带有三种参数,如果参数是一个类型,那么必须用typedef关键字声明。例如通用模块VirtualizeTimerC(opt/tinyos-2.x/ tos/lib/ timer),如下: eneric module VirtualizeTimerC(typedef precision_tag , int max_timers) { provides interface Timer as Timer[uint8_t num]; uses interface Timer as TimerFrom; } Implementation {…................…} 通用模块VirtualizeTimerC带有两个参数。precision_tag是定显示器精度参数。max_timers表示用户使用(实例化)的最大定时器个数。它通常使用uniquequeCount()计算得到。 #include "Timer.h" configuration HilTimerMilliC { provides interface Init; provides interface Timer as TimerMilli[uint8_t num]; provides interface LocalTime; } implementation { enum { TIMER_COUNT = uniqueCount(UQ_TIMER_MILLI) }; components AlarmCounterMilliP, new AlarmToTimerC(TMilli), new VirtualizeTimerC(TMilli, TIMER_COUNT),//在这里实例化了VirtualizeTimerC,//TMilli表示需要生成毫秒定时器,参数uniqueCount(UQ_TIMER_MILLI)表示需要生成的定//时器的总个数。而且因为VirtualizeTimerC是一个模块,所以实例化它就是需要为它分配///////必要的状态,同时会拷贝通用模块的代码从而生成一个新的模块实例。总之,在这个例///////子中生成了VirtualizeTimerC代码的拷贝,并且分配了uniqueCount(UQ_TIMER_MILLI) //////个毫秒精度的定时器。 new CounterToLocalTimeC(TMilli); Init = AlarmCounterMilliP; TimerMilli = VirtualizeTimerC; VirtualizeTimerC.TimerFrom -> AlarmToTimerC; AlarmToTimerC.Alarm -> AlarmCounterMilliP; LocalTime = CounterToLocalTimeC; CounterToLocalTimeC.Counter -> AlarmCounterMilliP; } 通用配件构成了更高层次的虚拟化和抽象。使用通用配件与使用通用模块的方法是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值