Python ile Paralel Port Kontrolü – Video

Pyparallel modülü yardımıyla Python’u kullanarak bilgisayarımızın paralel portunu kullanabiliriz. Bu yazıda bunun hakkında bilgi vereceğim. Öncesinde, paralel port yapısı hakkında kısa bir bilgiye buradan ulaşabilirsiniz. Pyparallel modülünün eski olduğu için şu an geliştirildiğini söyleyemiyorum. Bunun sebebi ise yeni bilgisayarlarda paralel port çıkışının olmaması, iyi ihtimal seri port çıkışının olması ve bildiğimiz üzere USB yaygınlığı.

Bu aşamada öncelikle şunları belirtelim. İlk olarak, elimizde bilgisayarımızın herhangi bir portuna giden .dll dosyası mevcutsa(mesela C ile yazılmış, sürücüleri kurulmuş bir halde), bu dosyalardaki fonksiyonlara Python üzerinden erişebiliriz. Ben bunları Java ile yapıyordum, Python’da tekrar öğrenmek istemiyorum. Ama Python kodları da çekici geliyor derseniz, pyjnius adlı modülle Python kodunun istediğiniz kısmından Java sınıflarına erişebilirsiniz.

Gerekli yönlendirmeleri en baştan yaptığıma inanarak devam edeyim. Pyserial adlı modül seri port iletişimini Python’a taşıyor. Bununla birlikte, pyparallel aslında bu modül sayfalarında, Türkçe olarak özetlersem, hala gelişim aşamasında gözüken ama geliştirilmediği neredeyse apaçık söylenen bir modül. Ama işin aslına bakacak olursak, işimize yarayabilecek her şey hazırlanmış ve çalışır durumda. Bu durumda eksik ne?

Geliştirilme aşaması yazması sanırım USB’den paralel port dönüştürücülere veya seri porttan paralel porta dönüştürücülere itafen yazılmış. Çünkü hazırlanan driverlar ne windowsta ne de modülün kendisi linuxta bu tip çevirici aparatları desteklemiyor. Kısacası, Python ile paralel port kullanmak istiyorsanız bilgisayarınızda bir paralel port çıkışı olmalı. En azından benim şu ana kadar gördüğüm bütün modüller bunu zorunlu kılıyor.

Ama Python’dan bahsetmişken, bu modülün sağladığı kolaylıklar elbet de var. Ama ondan bahsetmeden önce, nasıl yükleyeceğimize bir bakalım.

Windows için kurulum

Bu adreste hazırlanan dll dosyalarının üzerine .sys dosyaları eklenerek ve geliştirilerek şurada hazırlanan bir paket ile elinizde dll dosyalarına ulaşabildiğiniz her programlama dilinden bilgisayarınızın çıkışlarını kontrol imkanınız oluyor. Sitesinde seri portların da kontrol edilebildiği yazıyor, ben denemedim. 32 ve 64 bit işletim sistemleri için dll dosyaları mevcut durumda. Yukarıdaki linklerden indirebilirsiniz.

NOT: Güvenlik için girişlere 1K’lık dirençlerin koyulması gerektiği yazıyor. Bu konuda sorumluluk size ait. Önerim inpout32.dll yi indirirken readme dosyasına da göz atmanız. Ayrıca orda örnek uygulamalarda da açıklamalar yer alıyor.

Bu kurulumun ardından, ctypes modülü iile dll dosyalarına Python üzerinden erişme imkanımızı kullanarak inpout32.dll dosyasına ulaşıyoruz:

LPT-1 için port adresleri (LPT1 olup olmadığını, farklıysa adreslerin ne olduğunu aygıt yöneticisi altından görebilirsiniz.)

ctypes.windll.inpout32

0x378 data

0x379 status

0x37a control

Data, status veya control çıkışlarına veri gönderebilmek için, bunların port adreslerini yazmamız gerekiyor. Bunlar LPT1 port adresleridir. Şimdi yapacağımız iş, uygun fonksiyona port adresini yazmak ve çıkışı alabilmektir.

import ctypes
from time import sleep
for i in range(256):
    ctypes.windll.inpout32.Out32(0x378,i)
    sleep(0.25)

Şimdi kodun ne yaptığını görelim. Önce ctypes modülünü import ederek inpout32.dll dosyasına erişiyoruz. Daha sonra bu dll dosyasındaki Out32 fonksiyonuna 2 parametre yolluyoruz. Bunların ilki port adresi, ikincisi ise veri. Veri kısmına ikilik, onluk veya onaltılık sistemde sayı gönderebiliriz. Yani mesela 16 yerine 0b00001111 veya 0x0F gibi bir gönderim de mümkündü.

İkilik modta saydırmak amacıyla 0 dan 255 e kadar olan sayıları for döngüsü yardımıyla sırayla çıkış fonksiyonuna yolladık. Ucuna ledler bağladığınızda ikilik modta saydığını görebilirsiniz. Bunun videosu yukarıda mevcut. time modülünden sleep() fonksiyonunu da geçişler arasına saniyenin 14’ü kadar bekleme koyabilmek için ekledim.

Şu anlık datayı kullanarak verilerimizi paralel porttan dışarı gönderebiliriz. Bu konuda wx modülü kullanılarak Adam Pierce tarafından hazırlanmış bir kodu da paylaşalım. Python ile paralel port üzerinde tam bir kontrol sağlayan ve görsel bir program olan portmon‘un kodlarını incelemenin faydalı olacağını düşünüyorum. Ayrıca sadece portu kontrol etmek isteyenler için(asıl ekleme amacım) kodlamadan kurtaracak bir uygulama. Kaynak kodtaki mail adresini yazarına sorun olmaması için sildim(spam programlarından kaçınma amacıyla). Ulaşmak isteyenler sorarlarsa adresi kendilerine iletirim. Kodlara geçelim:

"""This Python application shows the status of all the parallel printer
lines and also allows you to set the state of control and data bits.
Note this is for SPP printer ports.

Written by Adam Pierce <mail is deleted against spam, it will be given on request> 10-Aug-2009

This code is public domain. You can copy it or use it for any purpose."""

import wx
import ctypes

class MainWindow(wx.Frame):
    """Main window for the port monitor application"""
    def __init__(self, parent, id, title):
        self.statusBase = 10
        self.ctrlBase   = 20
        self.dataBase   = 30

        wx.Frame.__init__(self, parent, id, title, size=(640,160))
        panel = wx.Panel(self, 1)
        grid = wx.GridSizer(3, 9)

        grid.Add(wx.StaticText(panel, -1, "STATUS"))
        self.statusBusy     = wx.CheckBox(panel, self.statusBase + 7, "/BUSY")
        self.statusAck      = wx.CheckBox(panel, self.statusBase + 6, "ACK")
        self.statusPaperOut = wx.CheckBox(panel, self.statusBase + 5, "PAPEROUT")
        self.statusSelect   = wx.CheckBox(panel, self.statusBase + 4, "SELECT")
        self.statusError    = wx.CheckBox(panel, self.statusBase + 3, "ERROR")
        grid.Add(self.statusBusy)
        grid.Add(self.statusAck)
        grid.Add(self.statusPaperOut)
        grid.Add(self.statusSelect)
        grid.Add(self.statusError)
        grid.Add(wx.StaticText(panel, -1, ""))
        grid.Add(wx.StaticText(panel, -1, ""))
        grid.Add(wx.StaticText(panel, -1, ""))
        self.statusBusy.Enable(False)
        self.statusAck.Enable(False)
        self.statusPaperOut.Enable(False)
        self.statusSelect.Enable(False)
        self.statusError.Enable(False)

        self.ctrlSelect   = wx.CheckBox(panel, self.ctrlBase + 3, "/SELECT")
        self.ctrlInit     = wx.CheckBox(panel, self.ctrlBase + 2, "INITIALIZE")
        self.ctrlLineFeed = wx.CheckBox(panel, self.ctrlBase + 1, "/LINEFEED")
        self.ctrlStrobe   = wx.CheckBox(panel, self.ctrlBase + 0, "/STROBE")
        grid.Add(wx.StaticText(panel, -1, "CONTROL"))
        grid.Add(wx.StaticText(panel, -1, ""))
        grid.Add(wx.StaticText(panel, -1, ""))
        grid.Add(wx.StaticText(panel, -1, ""))
        grid.Add(wx.StaticText(panel, -1, ""))
        grid.Add(self.ctrlSelect)
        grid.Add(self.ctrlInit)
        grid.Add(self.ctrlLineFeed)
        grid.Add(self.ctrlStrobe)
        for i in range(self.ctrlBase, self.ctrlBase + 4):
            wx.EVT_CHECKBOX(self, i, self.OnControlBit)

        self.dataBit = (wx.CheckBox(panel, self.dataBase + 7, "7"),
                        wx.CheckBox(panel, self.dataBase + 6, "6"),
                        wx.CheckBox(panel, self.dataBase + 5, "5"),
                        wx.CheckBox(panel, self.dataBase + 4, "4"),
                        wx.CheckBox(panel, self.dataBase + 3, "3"),
                        wx.CheckBox(panel, self.dataBase + 2, "2"),
                        wx.CheckBox(panel, self.dataBase + 1, "1"),
                        wx.CheckBox(panel, self.dataBase + 0, "0"))
        grid.Add(wx.StaticText(panel, -1, "DATA"))
        grid.AddMany(self.dataBit)
        for i in range(self.dataBase, self.dataBase + 8):
            wx.EVT_CHECKBOX(self, i, self.OnDataBit)

        panel.SetSizer(grid)
        self.UpdateStatus()
        self.UpdateControl()
        self.UpdateData()

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
        self.timer.Start(100)

        self.Show(True)

    def UpdateData(self):
        d = ctypes.windll.inpout32.Inp32(0x378)
        for i in range(8):
            self.dataBit[i].SetValue(d & 0x80)
            d = d << 1

    def UpdateControl(self):
        c = ctypes.windll.inpout32.Inp32(0x37A)
        self.ctrlSelect.SetValue(c & 0x08)
        self.ctrlInit.SetValue(c & 0x04)
        self.ctrlLineFeed.SetValue(c & 0x02)
        self.ctrlStrobe.SetValue(c & 0x01)

    def UpdateStatus(self):
        d = ctypes.windll.inpout32.Inp32(0x379)
        self.statusBusy.SetValue(d & 0x80)
        self.statusAck.SetValue(d & 0x40)
        self.statusPaperOut.SetValue(d & 0x20)
        self.statusSelect.SetValue(d & 0x10)
        self.statusError.SetValue(d & 0x08)

    def ToggleBit(self, port, bit, state):
        d = ctypes.windll.inpout32.Inp32(port)
        if state:
            d = d | (1 << bit)
        else:
            d = d & ~(1 << bit)
        ctypes.windll.inpout32.Out32(port, d)
        self.SetLabel('port ' + str(port) + ' = ' + str(d))

    def OnControlBit(self, event):
        bit = event.GetId() - self.ctrlBase
        self.ToggleBit(0x37A, bit, event.GetEventObject().GetValue())

    def OnDataBit(self, event):
        bit = event.GetId() - self.dataBase
        val = event.GetEventObject().GetValue()
        self.ToggleBit(0x378, bit, val)

    def OnTimer(self, event):
        self.UpdateStatus()

app = wx.PySimpleApp()
myframe = MainWindow(None, wx.ID_ANY, 'Parallel Port Monitor by Adam Pierce <adam@siliconsparrow.com>')
app.MainLoop()

Linuxta Pyparallel Kurulumu

Linuxta işimiz biraz daha rahat. Mint üzerinde direk yazılım merkezini açıp python-parallel(olmazsa pyparallel) aramasını yaptırın. Ardından gelen uygulamayı yüklediğinizde işiniz bitmiş oluyor. Burdaki kodlar ise biraz daha farklı. Windowsta kullandığımız dosya port adresini bildiğimizde her yere veri gönderebilmemizi sağlıyordu. Bu paralel port üzerine yazılmış bir modül olduğu için diğer çıkışları kontrol etmemize izin vermiyor. Şimdi kodlara geçelim:

import parallel
from time import sleep
cikis = parallel.Parallel()

for i in range(255):
    cikis.setdata(i)
    sleep(0.25)

parallel importumuzun içerisindeki Parallel sınıfını cikis isimli değişkene örnekledikten sonra, bunun methodlarından olan setData()’yı kullandık. Bu içerisine sadece gönderilecek veriyi alıyor. Burda da Windows kodunda olduğu gibi ikilik modta saydırmayı tercih ettik. Aralarda ise yine 14 saniyelik beklemeleri time.sleep ile sağladık.

Burada tahmin edeceğimiz gibi portun çıkışında neler olup bittiğini öğrenmek için getData() fonksiyonunu kullanabiliriz. Ya da istersek, kullanabileceğimiz bütün metotların isimleri için dir(“parallel”) yazabilir, hatta bunu bir döngü içerisinde daha düzenli bir şekilde bastırabiliriz.

Bu kodu çalıştırdığımızda muhtemelen izinlerle ilgili bir sıkıntı yaşıyoruzdur. Ben çözümünü burda bulmuştum ancak daha sonra ana dökümantasyonu olan burda ve ilk bulduğum sitede de bahsi geçen şu adreste de olduğunu farkettim. Kodu çalıştırmadan önce konsolda şunları çalıştırmamız gerekiyor. Sebebi ise dökümantasyonun alt kısmında açıklanmış, ilgilenenler bakabilir. Yine de sorun yaşarsanız, programınız bilgisayarın bir portunu kullanacağı için ona sudo yetkisi vermeniz gerekiyor olabilir.

sudo rmmod lp
sudo modprobe ppdev

Uzak bilgisayardan paralel portun nasıl kontrol edildiğiyle ilgili uygulamayı çektiğim video:

 

 
comments powered by Disqus