Gömülü Sistemlerde Assert Kullanımı
Daha önceki yazılarımda TDD kullanarak yazılım geliştirme süreçlerini bug-free bir duruma getirmek için edindiğim tecrübelerden bahsetmiştim. Şimdi ise yine bug yakalamakta oldukça kullanışlı ve basit bir yöntem olan Assert kullanımı ile ilgili bilgiler vereceğim.
Assert kullanımı gömülü yazılım süreçlerinde modüler entegrasyon sonrasında meydana gelebilecek bugların yakalanmasında oldukça faydalıdır. Yazılımda assertion kullanımını yaygın bir şekilde alışkanlık haline getirmek geliştirilen yazılımın sahaya çıkmadan veya yayınlanmadan önce sistemsel bugların ortaya çıkarılmasında büyük rol oynamaktadır. Gömülü sistemler bazında da hard fault durumu oluşmadan bir çok senaryoda sorunları yakalayabilme imkanı doğmaktadır.
Assertion gömülü yazılım geliştirme süreçlerinde
- Dinamik hafıza operasyonların kontrolü
- Fonksiyonların içerisinde parametre olarak alınan argümanların geçerlilik kontrolü
- Tanımlanmayan operasyonların kontrolü
- Sınır koşullarını sağlamayan tanımlamaların kontrolü
- Durum makinelerinde geçersiz durum geçişlerin kontrolü
gibi kontrol mekanizmalarının geliştirilmesinde yardımcı olmaktadır.
Standart kütüphanede var olan assert fonksiyonunun gömülü yazılımda direkt olarak kullanılması bir çok açıdan problem ve zorluk çıkarmaktadır. Örneğin ARM Compiler toolchain’de ARM C/C++ kütüphaneleri ile assert makrosunu kullanmak için aşağıdaki koşullardan birini sağlamak gerekiyor.
- strict, library_interface=aeabi_clib veya library_interface=aeabi_glibc ile derleme
- 00 veya 01 optimizasyon
- __ASSERT_MSG veya __AEABI_PORTABILITY_LEVEL sembol tanımlamasının yapılması
Bu şartlardan biri sağlandığında kütüphane tarafından __aeabi_assert() fonksiyonu çağrılmaktadır. Bu fonksiyon <assert.h> içerisinde extern olarak tanımlanmıştır bu yüzden de fonksiyonun asıl tanımlaması geliştirici tarafından yapılması gerekmektedir.
Yukarıda belirtilen koşulların sağlanmaması durumunda ise assert fonksiyonu abort() fonksiyonunu çağırmaktadır. Sistemi bu şekilde abort etme işlemcinin hard fault handler’ına zıplamasına sebebiyet verebilmektedir.
Bu yüzden temel işlevi çok basit olan bu assert fonksiyonunu kendimiz aynı görevi görecek şekilde aşağıdaki gibi yazmamız mümkündür.
Bu örnekte ASSERT adı ile bir makro oluşturulmuştur. __FILE__ ve __LINE__ preprocessor makroları kullanılarak assertion gerçekleştiğinde ilgili olayın gerçekleştiği dosyanın ismi ve satır numarası alınıp sonrasında bu bilgiler yazdırılarak program sonsuz döngüye alınmaktadır. Bu şekilde programın çalışması durdurularak debug çıktısı olarak ilgili dosya ismi ve satır numarası alınıp sistemde oluşan hatanın kaynağına gidebilmemiz mümkün olmaktadır.
Yukarıdaki örneği referans aldığımızda ise data_logger adında bir fonksiyon bulunmaktadır ve bu fonksiyon SD karta kayıt yapmaktadır. SD kart işlemlerini daha güvenli hale getirmek için max. veri boyutu koşulu belirlenmiştir. Bu fonksiyon ile örnek amaçlı olarak “Hello World” verisi kaydedildiğinde kaydedilecek verinin boyutu MAX_MSG_LOG_LENGTH’ten büyük olduğu için loglama yapılamadan assertion gerçekleşmektedir ve debug konsol ekranında aşağıdaki gibi bir çıktı alınmaktadır.
Assertion failed -> file: custom_assert.c, line: 32
Bu aşamada yazılım geliştirici tasarlanan sistemde loglama mimarisinde aslında bir sorun olduğunu, SD karta kaydedilecek verinin parçalanarak gönderilmesi noktasında bir bug oluştuğunu tespit ederek ilgili algoritmanın düzenlemesini gerçekleştirmektedir. Burada ayrıca bir dokümantasyonda oluşturulmaktadır. Bu fonksiyona bakan kişi SD karta kaydedilebilecek max. veri boyutunun 10 byte olması gerektiğini anlayabilmektedir.
Basit bir fonksiyon ile aslında uzun soluklu gömülü yazılım geliştirme süreçlerinde hataların bulunması noktasında çok faydalı olabilecek bir kullanımı tanıtmaya çalıştım.
Aşağıda belirttiğim referans linklerinde çok daha detaylı bilgilere ulaşılabilir. Başka farklı tasarımlarla da kendi assert fonksiyonunuzu yaratabilirsiniz. Ben kendi uygulamalarımda kullandığım tasarımı sundum.
Diğer yazılarımda görüşmek üzere…
Referanslar