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; } 通用配件構成了更高層次的虛擬化和抽象。使用通用配件與使用通用模塊的方法是一樣的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章