1

Javafx Serial Port API — JSSC

Merhaba arkadaşlar bu yazımda javafx de  seri port okumanın altını üstünü karıştırmaya çalışacağım. Java’da süre gelen yapı nasıl vb. nasıl okuma yapılır nasıl bir mantıkla çalışır bunları anlatmaya çalışacağım. Malum artık dünya tek bir konu üzerinde gitmiyor. Birçok farklı iş alanı birbiri içine girdi ve herkesin yazılıma ihtayacı olur oldu. Bununla birlikte sadece yazılımında yetmediği durumlar ortaya çıktı. Yani bir insan düşünün hem bir programı yazılımı var aynı zamanda damar ve sinir bağlantıları var aynı zamanda iskelet sistemi var. Hepsi bir arada yani . işte bu hepsi bir aradılık herkesin birçok konuda az yada çok bilgi sahibi olmasını gerektirdi. Son zamanlarda popüler olan Arduino geliştirme kartları ile haşır neşir olanlar lamba yakıp söndürme işlemlerini geçip daha büyük işleri de yapmak ister oldu. Bilgisayardan veri aktarma gibi…. ki bu yazının konusu bu olacak. Bu yazımda Bilgisayardan böyle bir geliştirme kartına nasıl veri aktarabilirim. yada ordan aldığım bilgileri nasıl bilgisayar ortamına taşıyabilirim. Bu gibi sorulara javafx diliyle cevap vermeye çalışacağım. İşte buyrun başlayalım.

Aslında seriport okuma diye biraz araştırma yapsanız direk 3 parti bir çok yazılım ile seriport’tan bilgi okuyabilirsiniz. Ancak siz kendiniz bir proje/uygulama yaptınız peki bunun içine nasıl atacaksınız. Bunun için bir java api’sine ihtiyacınız olacak.  Seriport’dan veri okuma işi donanıma özgü bir iş. gerçek bir port üzerinden bu işi yapabileceksiniz.  Java Sun’da iken çıkan bir api var ancak bu api resmi bir api niteliğinde olmadığından 3 parti bir API’ye ihtiyacınız olacak.  Uzun yıllar boyunca javacılar için çok tercih edilin bir api olan RXTX apisi vardı. O da son versiyonunu 2010 yılında çıkararak kendini tarihe doğru attı. Bu api durdu ancak – Java Simple Serial Connector – diye bir Api çıktı . Kullanıcıların çoğunlukla tercih ettiği bir api haline geldi.

Java Simple Serial Connector

Bu JSSC apisi ( Github: https://github.com/scream3r) Alexey Sokolov tarafından GPL lisansı ile kullanıma sunuldu.  En son versiyonu 

jSSC-2.8.0 Release version (24.01.2014)

olarak github’da gözüküyor.  Arduino ide tarafından da bu ide tercih edilmekte.  JSSC bütün platformlarda ve İşletim sistemlerinde çalışmakta. RXTX Apisine göre daha hızlı ve daha stabil. Tek bir .jar dosyası halinde indiriyor ve projenize ekliyorsunuz extra herhangi bir şey eklemeye gerek yok.  En son jar dosyasını https://github.com/scream3r/javasimple-serial-connector/releases bu adresten indirebilirsiniz. Projenizde jssc  paketi olarak gözükecek eğer kütüphanelere bakarsanız. 

Şimdi bir örnek üzerinden giderek konuya hakim olmaya çalışalım. 

Seriport iletişim için Serial ve OrientationFX classları ile StringProperty nesnemizi kullanacağız. StringProperty nesnemizle son satırdaki bilgiyi okuyacağız. 

SerialPort class’ımızı yazalım

package com.company;

import java.util.Arrays;
import java.util.List;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import jssc.SerialPort;
import jssc.SerialPortException;
import jssc.SerialPortList;

public class Serial {

    /* List of usual serial ports. Add more or remove those you don't need */
    private static final List<String> USUAL_PORTS = Arrays.asList(
            "/dev/cu.usbmodem1411", "/dev/tty.usbmodem1421", // Mac OS X
            "/dev/usbdev","/dev/ttyUSB","/dev/ttyACM", "/dev/serial", // Linux
            "COM3","COM4","COM5","COM6" // Windows
    );

    private final String ardPort;
    private SerialPort serPort;
    public static final String SEPARATOR = " ";
    private static final String LINE_SEPARATOR = "\r\n";
    private StringBuilder sb = new StringBuilder();
    private final StringProperty line = new SimpleStringProperty("");
    public Serial() {
        this("");
    }
    public Serial(String port) {
        ardPort =port;
    }
    /* connect() metodu arduinonun bağlı olduğu portu bulmaya çalışır..
     *  Eğer port'u bulursa portu açar ve sürekli portu dinleyen bir listener ekler
     *  bir satır döndğünde StringProperty'e bu  değer set edilir.
     * StringBuilder ise veriyi almak ve sonundan line değerini çıkarmak için kullanılıyor.
     *
     */

    // Kart'a bağlanmak için kullanılan metodumuz
    public boolean connect(){
        Arrays.asList(SerialPortList.getPortNames())
                .stream()
                .filter(name ->
                        ((!ardPort.isEmpty() && name.equals(ardPort)) ||
                                (ardPort.isEmpty() &&
                                        USUAL_PORTS.stream()
                                                .anyMatch(p -> name.startsWith(p)))))
                .findFirst()
                .ifPresent(name -> {
                    try {
                        serPort = new SerialPort(name);
                        System.out.println("Connecting to " + serPort.getPortName());
                        if (serPort.openPort()) {
                            serPort.setParams(SerialPort.BAUDRATE_9600,
                                    SerialPort.DATABITS_8,
                                    SerialPort.STOPBITS_1,
                                    SerialPort.PARITY_NONE);
                            serPort.setEventsMask(SerialPort.MASK_RXCHAR);
                            serPort.addEventListener(event -> {
                                if (event.isRXCHAR()) {
                                    try {
                                        sb.append(serPort.readString(event.getEventValue()));
                                        String ch = sb.toString();
                                        if (ch.endsWith(LINE_SEPARATOR)) {
                                            // gelme zamanını ekliyoruz.
                                            line.set(Long.toString(System.currentTimeMillis())
                                                    .concat(SEPARATOR)
                                                    .concat(ch.substring(
                                                            0, ch.indexOf(LINE_SEPARATOR))));
                                            sb = new StringBuilder();
                                        }
                                    } catch (SerialPortException e) {
                                        System.out.println("Seri Port Hatası: " + e.toString());
                                    }
                                }
                            });
                        }
                    } catch (SerialPortException ex) {
                        System.out.println("Hata: Port '" + name + "': " + ex.toString());
                    }
                });
        return serPort != null;
    }



    public void write(String text) {
        try {
            serPort.writeBytes(text.getBytes());
        } catch (SerialPortException ex) {
            System.out.println("Yazma Hatası :  '" + text + "': " + ex.toString());
        }
    }

    public void disconnect() {
        if (serPort != null) {
            try {
                serPort.removeEventListener();
                if (serPort.isOpened()) {
                    serPort.closePort();
                }
            } catch (SerialPortException ex) {
                System.out.println("Port kapatılırken bir hata oluştu: " + ex.toString());
            }
            System.out.println("Bağlantı Kapatılıyor: comm port kapatıldı.");
        }
    }


    public StringProperty getLine() {
        return line;
    }


    public String getPortName() {
        return serPort != null ? serPort.getPortName() : "";
    }
}

Şimdi yukarıdaki kodları tek tek nasıl çalışıyor diye inceleyelim.

private static final List<String> USUAL_PORTS = Arrays.asList(
"/dev/cu.usbmodem1411", "/dev/tty.usbmodem1421", // Mac OS X
"/dev/usbdev","/dev/ttyUSB","/dev/ttyACM", "/dev/serial", // Linux
"COM3","COM4","COM5","COM6" // Windows
);
private final String ardPort;
public Serial() {
this("");
}
public Serial(String port) {
ardPort =port;
}

İlk olarak jssc.jar api’sini projemize ekliyoruz. Bağlantı kurabileceğimiz muhtemel portları bir liste haline getiriyoruz.  Kendi sistemenizdeki bağlı portları aktif olarak alabileceğiniz gibi başka sistemlere ait portlarıda silebilirsiniz. ardPort değişkenine herhangi bir port atamasını burada yapmıyoruz constructor’dan doğru atama yapacağız.

connect() metodunu inceleyelim. Öncelikle connect metodu bizim sistemimizde olan geçerli portları buluyor. 

public boolean connect(){
Arrays.asList(SerialPortList.getPortNames())
.stream()
.filter(name ->
((!ardPort.isEmpty() && name.equals(ardPort)) ||
(ardPort.isEmpty() &&
USUAL_PORTS.stream()
.anyMatch(p -> name.startsWith(p)))))
.findFirst()

Eğer bu metod ile geçerli bir port bulursa portu açmak için bazı parametrelerlerle denemeler yapacak. 

.ifPresent(name -> {
try {
serPort = new SerialPort(name);
System.out.println("Connecting to " + serPort.getPortName());
if (serPort.openPort()) {
serPort.setParams(SerialPort.BAUDRATE_9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serPort.setEventsMask(SerialPort.MASK_RXCHAR);

Evet bağlantı parametrelerini de geçtik . Şimdiki işimiz  port açıldığına göre , artık portu dinlemeye başlamanız lazım. SerialPortEvent buffer’ı sürekli kontrol eder ve event.getEventValue()  metodu byte sayısı belirlenir.readString(int byteCount) metodu buffer doldukça datayı döndürecek.  Okunan veriler bir StringBuilder’da saklanıbilir her satır “\r\n”  ile ayrılabilir. Aynı zamanda her okunan satır için bir de zaman bilgisi ekleniyor. Eğer arduino ile birden fazla değeri port’a yazıyorsanız bunların arasına anlaşılır bir ayraç ekleyerek porta yazmalısınız.

serPort.addEventListener(event -> {
if (event.isRXCHAR()) {
try {
sb.append(serPort.readString(event.getEventValue()));
String ch = sb.toString();
if (ch.endsWith(LINE_SEPARATOR)) {
// add timestamp
line.set(Long.toString(System.currentTimeMillis())
.concat(SEPARATOR)
.concat(ch.substring(
0, ch.indexOf(LINE_SEPARATOR))));
sb = new StringBuilder();
}
} catch (SerialPortException e) {
System.out.println("Serial error: " + e.toString());
}
}
});

Son olarak disconnect() metodunu inceleyceğiz. bu metod hem listener’ı kaldırıyor hemde portu kapatma işlemini yapıyor.

public void disconnect() {
if (serPort != null) {
try {
serPort.removeEventListener();
if (serPort.isOpened()) {
serPort.closePort();
}
} catch (SerialPortException ex) {
System.out.println("ERROR closing port exception: " + ex.toString());
}
System.out.println("Disconnecting: comm port closed.");
}
}

Şimdi Main metodu içinde çağıralım ve değer okuması yapalım bakalım neler olacak.

public class OrientationFX extends Application {
private Serial serial;
@Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(new StackPane(), 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
serial = new Serial();
serial.getLine().addListener((obs, ov, nv) -> {
String[] split = nv.split("\\s");
System.out.println("Orientation " + split[1] + " " + split[2] + " " + split[3]);
});
serial.connect();
}
@Override
public void stop() throws Exception {
if (serial != null) {
serial.disconnect();
}
}
}
Çalıştıralim ve görelim bakalalım hangi değerleri yazacak
Connecting to COM5
208.50 -1.67 -0.42
208.48 -2.14 -0.20
208.49 -1.75 -0.42
208.46 -2.11 -0.12
208.47 -1.79 -0.43
Disconnecting: comm port closed

bu örnekte getLine ile ulaşılan bir Property nesnesi olduğunu da unutmalayalım. 

Kaynak: JAVAFX 9 By Example, 3rd Edition Kitabından çevirmeye çalıştım . herkese kolay gelsin

admin

One Comment

  1. çok teşekkürler. gayet açıklayıcı olmuş. Javada yeniyim. Benim için bir çok konuda yol gösterici bir makale oldu.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir