PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Java und EventListener in Konsolenprogramm (möglichst einfach ;))


huha
2006-03-03, 18:41:39
Hallo!

Ich komme nach langer, langer Zeit auch mal wieder dazu, kurz was zusammenzuprogrammieren bzw. hatte dies zumindest vor; als Programmiersprache habe ich mir Java rausgesucht, weil ich annahm, daß das Programm meiner Wahl eigentlich recht schnell gemacht sein müßte und dann auch auf Windows sowie Linux laufen, was eines der Hauptkriterien ist (sonst hätte ich's mit VB gemacht, da brauche ich nämlich rd. 10 Zeilen für alles ;)). Wichtig ist auch, daß es ein Konsolenprogramm werden soll, da auf der Linuxkiste kein X-Server installiert ist.

Was will ich machen? Eigentlich ganz einfach: Das CTS- respektive RI-Flag des COM-Ports auslesen und bei Änderung dieses Flags reagieren. Das javax.comm-Package (welches nicht mehr für Windows erhältlich ist, daher verwende ich das gnu.io (http://www.rxtx.org)-Package, welches allerdings von den Funktionen identisch ist) stellt für sowas einen eventListener bereit, den SerialPortEventListener (http://java.sun.com/products/javacomm/reference/api/javax/comm/SerialPortEventListener.html).

Meine Idee war nun, kurz was zusammenzuschreiben, was dafür sorgt, daß Code ausgeführt wird, wenn sich der Status eines dieser Flags ändert und dann per getEventType und getNewValue (http://java.sun.com/products/javacomm/reference/api/javax/comm/SerialPortEvent.html#getEventType()) abzufragen, was und wie sich das geändert hat.

Soweit die Theorie; in der Praxis krieg' ich's allerdings nicht hin, daß der EventListener "läuft," also das restliche Programm wartet, es läuft einfach durch und terminiert dann. Wie kann ich das, was ich will, möglichst einfach erreichen? (Das Programm darf gerne unendlich lang laufen, zum Testen wäre eine Laufzeit von 10 Sekunden gut, wobei die Abbruchbedingung der wohl benötigten Schleife ja beliebig definiert werden kann).

Wie setze ich das am besten um? Ich denke, daß die Lösung ziemlich trivial sein muß, komme wohl aber einfach nicht darauf.

-huha

HellHorse
2006-03-03, 19:02:43
10 Sekunden warten.
Thread.sleep(10 * 1000);

Wenn du immer warten willst, kannst du sowas machen:

Object lock = new Object();
synchronized(lock) {
lock.wait();
}

Wenn du irgend eine Abbruchbedinung willst, machst du man besten ein Condition Objekt und wartest auf das.

huha
2006-03-03, 19:04:11
Geht der Spaß auch ohne Threads einfach im main()-Programm?

-huha

redfalcon
2006-03-03, 19:12:57
Geht der Spaß auch ohne Threads einfach im main()-Programm?

-huha

Wenn ich das richtig verstehe, willst du in der main()-Methode 10 Sekunden warten?


try
{
Thread.sleep(10000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}

huha
2006-03-03, 19:18:10
Wenn ich das richtig verstehe, willst du in der main()-Methode 10 Sekunden warten?


Jein ;) -- ich will, daß der eventListener in der main()-Methode 10 Sekunden lang guckt, ob ein Event ausgelöst wird, ich krieg's aber irgendwie nicht hin. Threads will ich dafür eigentlich nicht verwenden, da ich mich da erstmal in Thread-Programmierung und die damit verbundenen Schwierigkeiten einlesen müßte, wofür ich aktuell schlicht keine Zeit habe.

Wenn der COM-Port geöffnet ist, füge ich so den EventListener hinzu:


comport.addEventListener(new SerialPortEventListener() {

Hier Schleifenanfang
public void serialEvent(SerialPortEvent arg0) {
// CTS = 3
System.out.println("Event: " + arg0.getNewValue());
System.out.println("E: Schalterstatus " + comport.isCTS());
}
Hier Schleifenende

});


...was aber reichlich wenig bringt, da dieser EventListener einfach "überlaufen" wird, sprich: nicht anspricht, weil die Programmausführung wohl einfach fortgesetzt wird.

Rot eingetragen sind die Orte, an denen ich "dem Gefühl nach" den Anfang respektive das Ende einer while(Abbruchbedingung)-Schleife setzen würde, was aber nicht geht, weil dann seitens Eclipse rumgemeckert wird.

-huha

Legolas
2006-03-03, 19:39:06
Da der Listener wohl asynchron funktioniert wirst du um ein klein wenig Threadprogrammierung nicht herumkommen. Lass einfach, wie schon mehrfach vorgeschlagen, in der main Methode mit 'Thread.sleep(10000);' das Programm 10sec warten. Sollte in dieser Zeit ein Event reinkommen, so wird die Eventhandlingmethode angesprungen werden. Nach 10 sec wird dann dein Programm weiterlaufen bzw. falls nichts danach kommt, beendet werden.

huha
2006-03-03, 19:44:42
Da der Listener wohl asynchron funktioniert wirst du um ein klein wenig Threadprogrammierung nicht herumkommen. Lass einfach, wie schon mehrfach vorgeschlagen, in der main Methode mit 'Thread.sleep(10000);' das Programm 10sec warten. Sollte in dieser Zeit ein Event reinkommen, so wird die Eventhandlingmethode angesprungen werden. Nach 10 sec wird dann dein Programm weiterlaufen bzw. falls nichts danach kommt, beendet werden.

Wenn's so funktionieren würde, wie du schreibst (bzw. wie ich annehme, vielleicht bin ich auch zu blöde), dann wäre ja alles gut, aktuell funktioniert's aber nicht ;(


import java.util.TooManyListenersException;

import gnu.io.*;


public class statustest {
static CommPortIdentifier portid;
static SerialPort comport;
/**
* @param args
* @throws PortInUseException
* @throws NoSuchPortException
* @throws TooManyListenersException
*/
public static void main(String[] args) throws PortInUseException, NoSuchPortException, TooManyListenersException {
System.out.println("com-port raussuchen...");
portid = CommPortIdentifier.getPortIdentifier("COM1");
System.out.println("und öffnen...");
comport = (SerialPort) portid.open("testkennung", 100);
System.out.println("offen wie ein Scheunentor!");

System.out.println("Schalterstatus " + comport.isCTS());


comport.addEventListener(new SerialPortEventListener() {


public void serialEvent(SerialPortEvent arg0) {
// CTS = 3
System.out.println("Event: " + arg0.getNewValue());
System.out.println("E: Schalterstatus " + comport.isCTS());
}



});

try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


System.out.println("Schluß jetzt...");
comport.close();


}

}


...so spricht das Programm leider nicht auf Änderungen während der Laufzeit an, was mir eigentlich auch irgendwie klar ist, da der EventListener wohl doch in einen eigenen Thread verfrachtet gehört; die Frage ist nur, warum man den, wenn im Hauptprogramm sowieso nichts anderes passieren soll, nicht gleich im Hauptprogramm lassen kann-- dann bliebe auch die Beschäftigung mit Threadprogrammierung und -Synchronisation aus, für die ich momentan nicht wirklich die Zeit habe :(

-huha

Legolas
2006-03-03, 19:59:13
Der Listener ist denke ich sowieso automatisch in einem eigenen Thread, schliesslich ist das eine unvorhersehbare, nebenläufige Aktivität. Machst du das ganze unter Linux oder Windows? Weil du ja am Anfang nach COM1 suchst, was unter Linux wohl nicht so gut gehen würde.

huha
2006-03-03, 20:04:26
Der Listener ist denke ich sowieso automatisch in einem eigenen Thread, schliesslich ist das eine unvorhersehbare, nebenläufige Aktivität. Machst du das ganze unter Linux oder Windows? Weil du ja am Anfang nach COM1 suchst, was unter Linux wohl nicht so gut gehen würde.

Unter Windows, die Zeile

System.out.println("Schalterstatus " + comport.isCTS());

liefert mir auch den richtigen Wert zurück (nur zur Info: Ich habe mir einen Schalter gebastelt, der das CTS-Flag des COM-Ports setzt und der auch funktioniert (mit anderem Programm nachgeprüft), daran kann's also nicht liegen, daß der EventListener nicht anspringt oder sonstwie nicht reagiert...), der eventListener will aber nicht, auch wenn ich wie blöde auf dem Schalter rumdrücke. ;(

-huha

huha
2006-03-03, 20:43:16
Da ich blöde bin, habe ich mich jetzt einige Zeit damit rumgeschlagen und letztendlich erkannt, daß der EventListener gerne wüßte, bei was er sich melden soll, die Zeile

comport.notifyOnCTS(true); vor der Initialisierung des EventListeners hat also Wunder bewirkt und jetzt tut's =) -- trotzdem Dank an euch alle!

-huha