6 Şubat 2019 Çarşamba

LINUX KERNEL KATMANINDA ÇALIŞAN NEM ÖLÇER DRIVER

          LINUX KERNEL KATMANINDA ÇALIŞAN NEM ÖLÇER DRIVER

Projenin amacı :

Projemizn amacı Arduino kullanarak ortamdaki nemi ölçmek

Kullanacak olduğumuz DHT11 Nem Sensörü analog sensör yapısında olduğundan dolayı araya ek olarak Arduino bağladık. USB serial üzerinden haberleşeceğiz.

Arduino Nedir?

Arduino bir I/O kartı ve Processing/Wiring dilinin bir uygulamasını içeren geliştirme ortamından oluşan bir fiziksel programlama platformudur. 

Character Device Driver Nedir?

Character Device kullanıcı uygulamasına veri aktarır. Character Device bir bayt verisini karakter karekter akışı anında okuyarak veya yazarken  seri portlar gibi davranır. Seri haberleşmeye, video çekmeye ve ses aygıtlarına arabirim oluşturmak için gereken driverlara ortam sağlar. 

File_operations yapısı “linux/fs.h” dosyasında tanımlanmıştır ve aygıt üzerinde çeşitli işlemler yapan sürücünün tanımladığı işlevlere işaretçiler içerir. Yapının her alanı, istenen bir işlemi gerçekleştirmek için sürücü tarafından tanımlanan bazı fonksiyonların adresine karşılık gelir. Örneğin, her karakter sürücüsünün cihazdan okuyan bir işlevi tanımlaması gerekir. File_operations yapısı, bu işlemi yapan modülün fonksiyonunun adresini tutar.

İşletim sistemi device ile doğrudan iletişim kuramaz , aygıtların arka planında aygıta özel olan olaylar ile ilgilenmezler. device driver gereklidir.

Karakter aygıtları(character device) karakter akımlarını kabul eder yada dağıtırlar.Adreslenemezler ve bu aygıtlarda arama işlemi gerçekleştirilemez.Yazıcılar, ağ aygıtları, mouse bu aygıtlara örnek verilebilir. İşletim sisteminin dosya sistemi bu aygıtların hepsi ile soyut aygıtlar olarak ilgilenir. Aygıtların arka planında aygıta özel olan olaylar ile ilgilenmezler.

Proje Adımları

İlk olarak kullandığımız fonksiyonlar için gerekli olan kütüphaneleri , modül lisans ve sahipliği ekliyoruz:


Global değişkenlerimizi tanımlıyoruz; Sensörden bilgiyi alan bilgi_oku(char*); fonksiyonu bildirimini yapıyoruz:


Karakter aygıtımız için gerekli olan open, close, read ve write fonksiyonlarımızı yazıyoruz. Read fonksiyonu içerisinden bilgi_oku() fonksiyonu ile sensörden gelen veriyi buf değişkenine atıyoruz.


Daha sonra “buf” a atılan veriyi simple_read_from_buffer() fonksiyonu ile user katmanına  gönderiyoruz. **Kullanılan fonksiyonlar kernel sürümüne göre farklılık gösterebilir.**

Kernel modülümüzün çalışması için gerekli ana fonksiyonlarını struct yapısında belirtiyoruz:


Arduinoyu bilgisayara bağladığımızda arduino tarafından /dev klasöründe “ttyACM0” isimli bir device oluşturulur ve device’ın ismi bilgisayardan bilgisayara değişiklik gösterebilir. “ls -al /dev” komutu ile veya kabloyu bilgisayara taktıktan sonra “dmesg” komutu ile logdan device’ın ismine bakabiliriz. . filp_open() ile bu device’ı kernelda dosya olarak kullanabiliyoruz.

bilgi_al() fonksiyonu ile “ttyACM0” dan gelen verileri alıyoruz ve read fonksiyonunda user’a gönderiyoruz:


Modül yüklenmek için __init fonksiyonunu kullanır. alloc_chrdev_region() ile device’a major numarası atanıyor. Eğer alloc_chrdev_region() fonksiyonu negatif değer döndürür ise kernel’da hata oluşmuştur. 
Fonksiyonlardan biri negatif değer döndürür ise problem oluştuğu anlamına gelir. device_create()  /dev dizininde device oluşturulur.

cdev_add()  karakter device’ı sisteme ekliyoruz. 

/dev dizininde driver’ımızı oluşturduk.


Modül kaldırıldığında __exit() fonksiyonu çalışır. Oluşturulan device’lar ve modüller kaldırılır:

                                                   
                              
Sağdaki DHT11 nem sensörünü Arduino ‘ ya bağladık.

Sensörün GND ucunu arduino nun GND bağlantısı ile bağlıyoruz. 
Sensörün POWER ucunu arduino nun 5V luk kısmına bağlıyoruz.
Sensörün DATA ucunu arduino nun 2 nolu kısmına bağlıyoruz.( 2 olmasını sebebi arduino kodlarındaki verdigimiz port kısmında belirtiyoruz.)

ARDUİNO KODU:


 Derleme ve Çalıştırma

Makefile dosyası:

*
*
*
*
*

sensorD.c ve Makefile dosyalarımızı oluşturup aynı klasöre attıktan sonra klasör içinde sağ tıklayıp terminali açıyoruz. “sudo make” yazıp root şifremizi girerek derlemeyi başlatıyoruz. Eğer derleme başarılı olursa klasörde .ko .mod vs uzantılı başka dosyalar oluşacaktır. Ardından “sudo insmod sensorD.ko” komutu ile modülümüzü sisteme ekliyoruz. “lsmod” ile modülün eklenip eklenmediğine bakabilirsiniz:


“cat” komutu ile HumiDevice içerisinde ki veri çıktısını konsoldan okuyabiliyoruz.

Okuma işlemi sonucu ekrana yazdırılan değerler:
 (sensöre üfleyip nem değerini değiştirmeyi unutmuşuz!)



                                                                                                THE END






   

18 Ocak 2019 Cuma

PROC PROGRAMLAMA İLE MATRİS TRANSPOZU

PROC PROGRAMLAMA İLE MATRİS TRANSPOZU 
Proc Programlama Nedir?
  Proc, Linux’ta bir sanal/sahte dosya sistemidir(proc file system). Sanal veya sahte(pseudo) denmesinin sebebi hard diskte yer kaplamamasından dolayıdır, tamamen Ram’de çalışır. Proc, procces yani işlem, süreç anlamlarına gelir.
Proc dosyaları bize kernel modülleri, driverlar ve çekirdek iç yapıları hakkında bilgi ve kontrol sağlar. Ram’de çalışan proccesleri dosya olarak bize gösterir. Proc ile sistemde çalışan programlar hakkında bilgi almak, çekirdek parametrelerini değiştirmek ve çalışmakta olan sistemde güncellemeler yapmak mümkündür.
Kısaca bilgisayarınızda çalışan proccesleri kontrol etmek, bilgi almak veya kendi dosyanızı oluşturmak istiyorsanız işletim sistemine müdahale etmeniz gereken kısım Proc File System dir.

Proc Dosyaları Nasıl Oluşur?
Proc dosyaları, bilgisayarı başlatıp Linux’u açtığınızda kernel ve kernel modülleri tarafından bellekte oluşturulur ve “/proc” dizininde bulunur, bilgisayar kapanınca silinir. Terminalde “cd /proc” yazıp dizine giderek ardından “ls –al” yazarak bütün proc dosyalarını görebilirsiniz. Birkaç tanesi hariç bütün dosyaların yanında boyut olarak 0(sıfır) yazar, hard diskte olmadığı için boyutları sıfır görünür.
Kendi projemiz için yazacağımız programda modülü sisteme yüklerken proc dosyamız da bellekte oluşacak.

Matrisin Transpozunu Alan Proc Dosyası 
 Projemizde matris boyutlarını ve matris elemanlarını göndererek bize matrisin transpozunu gösteren kendi oluşturacağımız bir proc dosyası programlayacağız.
Örn: proc dosyasına “2x3 5 3 7 1 9 3” gönderdiğimiz zaman bize
                      5   3   7                                    5   1
Matris: 2x3   1   9   3       Transpozu: 3x2    3   9       şeklinde yazacak.     
                                                                     7   3

İlk adım olarak modül oluşturacağız ve modülü kullanarak da proc dosyası oluşturacağız. Sublime text editör kullanmanız kolaylık sağlar. 

**Proc dosyalarını kullanabilmek için gerekli 4 temel fonksiyon vardır:

  • Dosyayı açmak için open 
  • Yazmak için write 
  • Okumak için read 
  • Kapatmak için exit
 Ve Proc’larda mutlaka modül lisans ve sahip bilgisi olmalıdır.

Makefile 
.c uzantılı dosyamızı derlemek için makefile dosyamızı yazıyoruz öncelikle:



Üstteki Makefile dosyasında dikkat edilmesi gereken 2 şey vardır: 
1. $(MAKE) ve rm ile başlayan satırlardan önce tab ile boşluk yapın, space kullanırsanız derleme yapmaz. 
2. .c uzantılı dosya ismi ile Makefile’da ki .o kısmı aynı olmalı. matris.c ve matris.o gibi 



matris.c dosyası 
.c dosyamızı oluşturup içine gerekli kütüphaneleri ve proc ismi tanımlıyoruz:


    Ardından temel modül fonksiyonlarımız olan “init ve exit” fonksiyonlarımızı yazıyoruz. init’in içine yazdığımız “proc_create()” procumuzu oluşturan fonksiyondur.
insmod” ile modülü eklerken init çalıştığı için init’in içinde ki “proc_create()” de çalışır.
rmmod” ile modülü silerken exit fonksiyonu çalışır ve exit’in içinde ki “remove_proc_entry()” de çalışarak bellekte ki proc silinir:


    Şimdi de read, write fonksiyonlarımızı ve proc yapısını belirten “struct file_operations” yazıyoruz. Write user dan kernele veri göndermek için kullanılır, read ise kernelden user a veri göndermek için kullanılır.
    Struct içine “.read ve .write” ile read ve write fonksiyonunun adını yazıyoruz. “echo” yazdırma komutu ile write fonksiyonu devreye girer ve proc dosyasına veri gönderilir, “cat” ile read devreye girer ve procta ki verileri bize gösterir. 
    Write fonksiyonunda “echo” ile kullanıcıdan gelen string buf’a ve stringin uzunluğu count’a atılır. Read fonksiyonunda ise “cat” ile kernelden gelen veri buf’a ve verinin uzunluğu count’a atılır. “copy_from_user()” user katmanında ki veriyi kernele yazdırır, “copy_to_user()” ise kernel katmanında ki veriyi user katmanına yazdırır.
    Write fonksiyonu içinde “copy_from_user(msg,buf,count);” ile buf’ta ki veriyi global değişkenimiz olan msg ye atıyoruz. msg global olduğu için diğer fonksiyonlarda da kullanıp işlenebilir.
    Read içinde de kendi kullanıp işlediğimiz msg2 değişkenini buf’a atıp kullanıcıya gönderiyoruz.
Dikkat edilmesi gereken şey cat yazılınca read_proc’un döngü şeklinde çalışmasıdır. Count her döngü başında 13071 gibi bir değer alır ve sıfırlanmadan read durmaz. Prink ile read deki değişkenleri loga yazdırarak inceleyebilirsiniz. Bu nedenle read in içinde kendi fonksiyonlarınızı kullanmayınız, write içinde kullanabilirsiniz: 


Şimdi de proc işlemlerinde kullanılacak değişken ve fonksiyon modüllerini yazıyoruz. Global değişkenlerimiz static olmalı: 



      Ve şimdi matrisin transpozunu alıp global değişkenlere yazdığımız fonksiyonları yazıyoruz. 
     *Procu çalıştırırken “echo  2x3 5 3 9 2 4 7 > matrisProc” komutunu kullanacağız. Bu komutu kullanırken echo dan sonra ki “2x3 5 3 9 2 4 7”  kısmı string olarak proca gönderilir. Bu sayıları kullanabilmek için intigera dönüştürmek lazım.* 
     mxn şeklinde gelen stringi döngülerde kullanabilmek için “kstrtol()” fonksiyonu ile long intiger a dönüştürüyoruz. Bu şekilde matris boyutlarını elde ediyoruz:



     Ve echo ile gelen mxn den sonra yazılan elemanları stringden long intigera dönüştürüyoruz. Long intiger’a dönüştürdüğümüz elemanları aynı döngü içinde dizi[m*n] intiger arrayine atıyoruz:


   Dizi boyutlarını m ve n global değişkenlerine atadık ve matris elemanlarını da dizi isimli yerel değişkene atadık. Fonksiyon sonunda diziyi matris ve transpozunu oluşturmak için matrisArryaz() fonksiyonuna referans olarak gönderdik.

   Matris boyutlarını ve elemanlarını aldıktan sonra dizide ki matris elemanlarıyla döngü kullanarak matris[][]’i oluşturuyoruz. Matrisi oluşturduktan sonra yine döngü yardımıyla transpozunu
matrisT[][] ye atıyoruz. Bu işlemleri yaparken matrisi ve transpozunu printk ile log’a da yazıyoruz :


   Son olarak oluşturduğumuz matrisi ve transpozunu procta “cat” komutu ile göstermek için bunları global msg2 char değişkenine atıyoruz. “sprintf()” fonksiyonu istenilen şeyi içine intiger char long vs ekleyip stringe dönüştürerek istenilen bir char arrayine kaydetmeyi sağlıyor. Bizde sprintf kullanarak matrisi ve transpozunu msg2 ye yazdırdık:



x += sprintf(&msg2[x], ”……..”,m,n);” özel bir kullanım. Daha fazla bilgi için: https://stackoverflow.com/questions/30234363/how-can-i-store-an-int-array-intostring



Derleme ve Çalıştırma
      matris.c ve Makefile dosyalarımızı oluşturup aynı klasöre attıktan sonra klasör içinde sağ tıklayıp terminali açıyoruz. “sudo make” yazıp şifremizi girerek derlemeyi başlatıyoruz. Eğer derleme başarılı olursa klasörde .ko .mod vs uzantılı başka dosyalar oluşacaktır. Ardından “sudo insmod matris.ko” komutu ile modülümüzü sisteme ekliyoruz. “lsmod” ile modülün eklenip eklenmediğine bakabilirsiniz:


 Modül sisteme eklenince programda matrisProc ismini verdiğimiz proc dosyamızda “/proc” dizininde oluşmuştur. “ls -al /proc“ ile procun oluşup oluşmadığına bakabilirsiniz. Proc eklendikten sonra “cd /proc” ile proc klasörüne geçiyoruz. “sudo su” komutu ile root yetkisi alıyoruz. 
echo 2x3 5 7 3 9 1 6 > matrisProc veya echo “2x3 5 7 3 9 1 6” > matrisProc yazıyoruz, tırnak işareti olsun olmasın fark etmez, iki durumda da string olarak tanır. Ardından “cat matrisProc” ile procun içini okuyoruz:

Log dosyasına yazdırdıklarımızı da görmek için “dmesg” komutunu kullanıyoruz:


                                                                                                                          THE END