TinyOS'taki Blink Uygulamasının Detaylı Olarak İncelenmesi

Yazar:



Daha önceki yazıda "Blink" uygulamasını yalnızca TinyOS'un sağlıklı olarak çalışıp çalışmadığını test etmek için kullanmıştık.

Bakınız : TinyOS'u Blink Uygulaması İle Test Etmek

Sonrasında ise TinyOS'ta nesC ile geliştirilen uygulamaların genel yapısından bahsetmiştik.

Bakınız : TinyOS'ta NesC İle Geliştirilen Uygulamaların Genel Yapısı

Şimdi ise, "Blink" uygulamasının detaylarına ineceğiz. Eğer TinyOS platformunda yeniyseniz, programa daha iyi hakim olabilmeniz açısından bu yazı sizler için çok yararlı olacaktır.

Blink uygulaması, TinyOS içindeki "apps" klasörü içerisinde yer almaktadır. Uygulamanın kaynak kodlarını (source code), daha önceden kurulumunu TinyOS'a özel olarak anlattığım anlattığım "Eclipse" uygulaması ile düzenli bir şekilde görüntüleyebilirsiniz.

Blink uygulaması, TinyOS'a özel olarak geliştirilen NesC dilini kavrayabilmemiz için inceleyeceğimiz en basit örnektir. Bu uygulama yalnızca donanım (mote veya düğüm de denebilir) üzerindeki kırmızı ledi 1 Hz (hertz) ile açıp kapatıyor.

Blink uygulaması "BlinkM.nc" adlı bir modülden (module) ve "Blink.nc" adında bir konfigürasyon (configuration) dosyası olmak üzere 2 farklı bileşenden (component) oluşur. TinyOS'taki uygulamalar, uygulamanın kendinden sonra, tipik olarak isimlendirilen üst seviye konfigürasyon (configuration) dosyalarına ihtiyaç duyduğunu hatırlayın.

Bakınız : TinyOS ve NesC Nedir? Nesc Uygulamalarının Genel Yapısı Nedir?

Bu durumda Blink.nc dosyası, blink uygulaması ve NesC derleyicisinin çalıştırılabilir bir dosya oluşturabilmesi için derleyicinin kullandığı kaynak dosyasının, konfigürasyon (configuration) dosyasıdır.

Module dosyası dediğimiz BlinkM.nc dosyası ise, Blink uygulamasının, 'implementation' olarak adlandırılan kısmını oluşturur.

Tahmin edebileceğiniz gibi; Blink.nc configuration dosyası, Blink uygulamasının ihtiyaç duyduğu diğer bileşenler ile BlinkM.nc modülü arasında kablolama (wire) yapması için kullanılır.

Modüller ve konfigürasyonlar arasındaki ayrımın nedeni, bir sistem tasarımcısının uygulamaları hızla "bir araya getirmesini" sağlamaktır.  Örneğin bir sistem tasarımcısı, bir konfigürasyon dosyası sayesinde gerçekte kendi tasarlamadığı birden çok modülü basitçe bir araya getirebilir. Ayrıca başka bir uygulama geliştirici (developer), uygulama dahilinde kullanılabilen yeni kütüphanaler dizisi geliştirebilir.

Uygulama implemantation modülü için adlandırılan "BlinkM.nc" ve configuration işlemi için "BlinkC.nc" olarak belirtilen dosya adlandırmaları, TinyOS'un uygun gördüğü adlandırma şekilleridir. Siz de TinyOS'ta kendi uygulamanızı yazacağınız zaman, Blink uygulamasında olduğu gibi uygulamanızın implemantation modülü (uygulamadiM.nc) ve  configuration dosyasının (uygulamadiC.nc) adlandırma şeklini, aynı kurala uyarak adlandırmanızı tavsiye ederim.

Bakınız : TinyOS Naming Conventions (Adlandırma Kuralları)

Blink.nc Configuration

NesC derleyicisi (ncc), üst düzey configuration içeren dosya verildiğinde, nesC uygulamasını derler. Tipik TinyOS uygulamaları, platform seçimine izin veren ve uygulamanın üst düzey yapılandırmasında uygun seçeneklerle ncc'yi çağıran standart bir Makefile ile birlikte gelir.

Blink.nc (Configuration Dosyası)
configuration Blink {
}
implementation {
  components Main, BlinkM, SingleTimer, LedsC;

  Main.StdControl -> BlinkM.StdControl;
  Main.StdControl -> SingleTimer.StdControl;
  BlinkM.Timer -> SingleTimer.Timer;
  BlinkM.Leds -> LedsC;
}

İlk satıra baktığınızda, dosyasının bir yapılandırma dosyasını olduğunu gösteren "configuration" anahtar kelimesinin kullanıldığını görüyorsunuz. Bu işlemle bu dosyanın "Blink" adı verilen bir "configuration" dosyası olduğunu tanımlamış olduk. Burada "configuration" içerisinde bir modülde olduğu gibi "uses" ve "provide" tanımlaması yapılabilir. Burada unutulmaması gereken şey ise, bir "configuration" dosyası arayüzleri kulanabilir veya yeni bir arayüz sağlayabilir.

Gerçek yapılandırmalar (konfigürasyonlar) ise aslında "implementation" anahtar kelimesi adı altındaki parantezler içinde tanımlanmaktadır. Bunun (implementation) içerisinde de yararlanılan bileşenler (componenets) belirtilir. Bu örneğimizde Main, BlinkM, SingleTimer, LedsC bileşenlerinden faydalanılmış olduğunu görmekteyiz. Kalan kısımlar ise bileşenler tarafından kullanılan,   başkaları tarafından yapılmış, birbiri ile bağlantılı arayüzlerden (interface) oluşur.

Main, TinyOS'ta ilk olarak çalıştırılan bileşendir. TinyOS'ta ilk çalışan komut ise, "Main.StdControl.init()" komutudur. StdControl denen şey, TinyOS'ta ortak olarak kullanılan bir arayüzdür. TinyOS klasörünüzün içerisinde yer alan "tos/interfaces" klasörüne girerek StdControl.nc dosyasının içeriğini inceleyebilirsiniz.

Bakınız :

StdControl.nc
interface StdControl {
  command result_t init();
  command result_t start();
  command result_t stop();
}

Bu interface, TinyOS bileşenlerinin (components) kurulumu ve çalıştırılmasını sağlar. Bu sebeple configuration dosyasının içerisinden çağrılması gereken bir interface'tir.  Gördüğünüz StdControl.nc dosyası 3 komuttan oluşmaktadır.

init()  : Bir bileşen ilk defa başlatılacağında / çalıştırılacağında çağrılır.
start(): Uygulama ilk defa çalıştırılacağında çağrılır.
stop() : Bileşen durduğunda çağrılır. Örneğin kontrol edilen cihaz kapatıldığında.

init() birden çok kez çağrılabilir. Sadece ve sadece, start() ve stop() komutları çağrıldıktan sonra init() çağrılmaz.

Bir bileşen üzerinden çağrılan init(), o bileşenin tüm alt bileşenlerinden de çağırmalıdır.

Bakınız :

  Main.StdControl -> BlinkM.StdControl;
  Main.StdControl -> SingleTimer.StdControl;

Blink configuration, Main'deki StdControl arayüzünü (interface) hem BlinkM hem de SingleTimer'deki StdControl arayüzünü bağlar. SingleTimer.StdControl.init () ve BlinkM.StdControl.init () ise,  Main.StdControl.init () tarafından çağrılır. Aynı kural, start () ve stop () komutları için de geçerlidir.

Kullanılmış arabirimler ile ilgili olarak, alt bileşen başlatma işlevlerinin, kullanan bileşen tarafından açıkça çağrılması gerektiğini unutmamak önemlidir. Örneğin, BlinkM modülü Leds arayüzünü kullanır, bu nedenle Leds.init () açık bir şekilde BlinkM.init() içinden çağrılır.

NesC arayüzleri arasındaki ilişkileri belirlemek için "->" oku kullanır. Okun sol tarafı, sağ taraftaki uygulamanın arabirimini uygulamaya bağlar. Başka bir deyişle, arayüzü (interface) kullanan bileşen soldadır ve soldaki bileşen sağdaki arayüzü çağırarak, (veya uygulamamıza bağlayarak) kullanabilmemizi sağlar.

Bu açıklamayı daha iyi anlamak için, şu ifadeyi açıklayalım :

BlinkM.Timer -> SingleTimer.Timer; 

Burada BlinkM, Timer arayüzünü (interface) kullanır. Bunu kulanabilmesi için ise, SingleTimer bileşeni tarafından sunulan Timer arayüzüne başvuruluyor. Böylece sağ taraftan "provide" edilen "Timer" arabirimi (interface), sol tarafta kullanılmış oldu. Bu configuration işlemi sayesinde, "Timer" arayüzünü artık BlinkM uygulamamızda kullanabileceğiz.

Dosya yolları :

Okun sol tarafında yer alam Timer => tos/interfaces/Timer.nc
Okun sağ tarafında yer alam Timer => tos/lib/SingleTimer.nc

Unutmayın! Her zaman okun sol tarafı arabirimleri (interfaces) ifade eder, sağ tarafı ise uygulamaları (implementations) ifade eder.

nesC, tek bir arayüzün çoklu implementation olayını desteklemektedir. Timer interface implementation işlemi buna güzel bir örnektir. TimerC bileşeni, Timer id değerini parametre olarak kullanarak çoklu implement yaparken, SingleTimer bileşeni yalnızca bir Timer arayüzünü implement eder.

Bazı wiring (bağlama/yapılandırma) işlemleri, uzun uzun yazılmaması adına kısaca şu şekilde yazılabilir :

  BlinkM.Leds -> LedsC;

Bu işlem aslında şununla aynıdır :

  BlinkM.Leds -> LedsC.Leds;

Eğer ki ok işaretinin sağ tarafında, interface ismi uzunca tanımlanmamış ise, nesC derleyicisi default olarak sol tarafta tanımlı olan interface değişkenini kullanmayı dener.

BlinkM.nc Modülü

Şimdi ise BlinkM.nc adı verilen Blink modülünü inceleyeceğiz.

BlinkM.nc
module BlinkM {
  provides {
    interface StdControl;
  }
  uses {
    interface Timer;
    interface Leds;
  }
}
// kod burada devam eder..


Tanımlamanın ilk başında, dosyamızın bir modül dosyası olduğunu belirttik. Daha sonrasında ise, hangi arabirimleri (arayüz/interface) hazır TinyOS kütüphanesinden sağlayacağımızı "provides" ile, hangilerini kullanacağımızı ise "uses" süslü parantezleri içinde tanımladık. Bu açıklamayı biraz daha açacak olursak, şöyle diyebiliriz :

BlinkM modülü, StdControl arabirimini (interface) implement etmektedir. Daha önceden de açıkladığımız gibi StdControl, Blink bileşenlerinin (components) kurulumu ve başlatılması için gerekli tanımlamadır.

Blink modülünün ayrıca "uses" içerisinde "Timer" ve "Leds" adında iki arabirimi kullandığını görmekteyiz. Bu işlemin anlamı da şudur. Blink modülü, "Timer" ve "Leds" arabirimleri içerisinde tanımlı olan tüm "command" ve "events"leri kullanabilir anlamına gelmektedir.

Leds arabiriminde redOn(), redOff() gibisinden, donanım üzerindeki farklı renkteki ledleri açıp kapatacak komutlar (command) yer almaktadır. BlinkM modülü Leds arabirimini (interface) kullandığı (uses) için, bu komutlardan (command) istediği birini çağırabilir. Burada unutmamanız gereken şey, Leds'nin yalnızca bir interface olduğudur. Implementation olayını,  Blink.nc adını verdiğimiz configuration dosyasında tanımlamıştık.

Şimdi de Timer arabirimini (interface) inceleyelim.

Timer.nc
interface Timer {
  command result_t start(char type, uint32_t interval);
  command result_t stop();
  event result_t fired();
}

Timer interface içerisinde start() and stop() commands tanımlamaları ve bir adet fired() adlı verilen event tanımlaması yer almaktadır.

start() adlı komut (command) iki parametre alır. Önce ikinci parametreden bahsedeyim.  start() komutunun ikinci parametresi, sonlanmasını istediğimiz işlemin, milisecond cinsinden, ne kadar süre sonra sonlanacağını tanımlamamızı sağlar.

İlk parametre ise, zamanlayıcının türünü tanımlar. Geçerli olan iki zamanlayıcı türü vardır. Bunlardan biri TIMER_REPEAT bir diğer ise, TIMER_ONE_SHOT'tır.  TIMER_ONE_SHOT türü tanımlı ise işlemimiz, ikinci parametrede belirtilen süre bitene kadar çalışır. TIMER_REPEAT türü tanımlı ise işlemimiz, biz stop() komutu belirtinceye kadar sürekli olarak çalışmaya devam eder.

Uygulama, sürenin dolduğunu ise şu event sayesinde anlayabiliyor :

event result_t fired();

Event, arayüz uygulamasının (implementation of interface) belli bir olay gerçekleştiğinde, sinyal vereceği bir fonksiyondur. Belirlenen zaman aralığı aşıldığında bu durum, fired() event'ine bildirilir.


Timer.nc arabirimi, bize yalnızca command olarak tanımlanmış bileşenler değil, ayrıca, kullanıcılar tarafından kullanılıp, kontrol edilebilen "event"lar sunduğu için, Timer.nc için için çift yönlü interface diyebiliriz. Hatırlarsanız, StdControl.nc arabirimi (interface) yalnızca command'lar içeriyordu. Bir interface uygulamasındaki (implementation) "Event" dediğimiz olayı, callback yapan (geri dönüş değeri olan) bir fonksiyon gibi düşünebilirsiniz. Bir modülde "uses" içerisinde, kullanılacak olan "interface" tanımlanır demiştik. Kullanılacak olan interface'e ait event() modül içinde belirtmelidir.

Bakınız :

BlinkM.nc Implementation Kısmı
implementation {

  command result_t StdControl.init() {
    call Leds.init();
    return SUCCESS;
  }

  command result_t StdControl.start() {
    return call Timer.start(TIMER_REPEAT, 1000) ;
  }

  command result_t StdControl.stop() {
    return call Timer.stop();
  }

  event result_t Timer.fired()
  {
    call Leds.redToggle();
    return SUCCESS;
  }
}


Gördüğünüz gibi BlinkM modülü StdControl interface'ine ait olan,  StdControl.init(), StdControl.start(), and StdControl.stop() komutlarını implement etmiş. Timer.fired() dediğimiz event, implement edilmiş. Çünkü event kullanacağımı "module" içerisindeki süslü parantezler içerisinde böyle bir event kullanacağımızı belirtmiştik. O yüzden bu 'event'i kullanmamız gerekiyor.

init() komutu StdControll adlı interface'ten implement edilmiştir. StdControll.init() komutu içerisinde call Leds.init() yaparak, Leds'in alt bileşenleri de çağrılarak başlatılmış (initialize) oldular.

StdControl.start() komutunun içerisinde her 1000 milisaniyede bir defa süresi dolan bir Timer tanımlanmış. Burada birinci parametre TIMER_REPEATER olduğu için, işlem 1000 milisaniyede bir defa tekrar edecektir.

Son olarak ise, Timer.fired() olayı (event) tetiklendiğinde, Leds.redToggle() işlemi ile LED renginin kırmızıya dönmesini sağlamış oluruz.

TinyOS ile ilgili tüm dökümanlara, "doc" klasöründen veya http://tinyos.stanford.edu/tinyos-wiki adresinden ulaşabilirsiniz.

Bu yazının orjinaline şu linkten ulaşabilirsiniz : https://www.cse.iitd.ernet.in/~pulkit/embedded2/docs/lesson1.html

Yazının çevirisi tamamen Ali ARSLAN tarafından yapılmış olup, ilk defa Blogkafem.net üzerinden yayınlanmıştır. Kopyalamanız halinde lütfen kaynak gösteriniz. Konuyla ilgili farkettiğiniz çeviri veya yazım hatalarını, aşağıdaki yorum formu aracılığıyla iletebilirsiniz. İyi çalışmalar.

Thanks to Indian Institute of Technology Delhi for TinyOS documentation that they present. (Sundukları TinyOS dokümanları için Hindistan Teknoloji Enstitüsü'ne teşekkürler.)

0 yorum:

Yorum Sayfası :


Yorum formuna konuyla ilgili görüş ve sorularınızı bırakabilirsiniz.

Yorumunuza mümkün olan en kısa sürede dönüş yapılacağından emin olabilirsiniz.


Eklenen yorumlar, moderatör onayından sonra yayınlanmaktadır.

BLOGKAFEM.NET © Copyright 2008-2023
Sitedeki yazıların her hakkı BLOGKAFEM.NET sitesine aittir.
Kopyalanması halinde lütfen kaynak gösteriniz.
DMCA.com Protection Status
Anasayfa | Hakkında | İletişim