Ausführbarkeit von Code testen bzw. Remote Debugging

nonickatall

Mitglied
Wenn ich eine Anwendung schreibe, die von der Verfügbarkeit bestimmter Recourcen abhängt.
Also zum Beispiel bestimmte Hardware, Treiber, Netzwerkzugriff, Server-Dienste was auch immer, kann ich ja mit Remote Debugging arbeiten, wenn das auf der Maschine, auf der ich code, nicht der Fall ist.

In meinem Fall greife ich beispielsweise auf GPIO Pins auf einem Raspberry zu. Das klappt auch. Wenn ich an anderer Stelle codiere, also beispielsweise an der GUI arbeite und die GPIOS nicht brauche, möchte ich das Programm aber einfach unter Windows debuggen.

Dann muss ich ja irgendwie prüfen, ob ich die GPIOS aufrufen kann. Sonst führt der Aufruf ja zu möglicherweise zu einer Exception.

Macht man da, um am Beispiel GPIO zu bleiben, eine Methode mit einer Rückgabe in der Klasse GPIO, die mit try und catch arbeitet, um vorher zu prüfen, ob GPIO überhaupt verfügbar ist, die ich dann bei Programmstart einmal ausführe und dann im Code drauf reagiere? Also zum Beispiel Aufrufe an die GPIO Klasse gar nicht erst weiterleite, oder muss man dann im Grunde jede Methode mit try und catch versehen?

Wie macht man das sinnvoll? Nur mal so konzeptionell gefragt...
 
Entkopplung lautet hier das Zauberwort. Wie die im Detail aussieht, hängt aber von der Situation ab.

Wenn Du z. B. pi4j anschaust (eine Java-Lib, die ich gerade gegoogelt habe), dann ist dort bereits alles über Platform und Provider entkoppelt. Beispiel unter https://pi4j.com/documentation/create-context/

Du könntest also beim Programmstart feststellen, ob das Programm unter Windows läuft, falls ja, dann erzeugst Du einen Context mit gemockten Objekten, ansonsten mit "echten". Es könnte sogar sein, dass das Teil das automatisch macht, da müsste man sich jetzt ein wenig einlesen.

Aber das wäre so das Prinzip: Schnittstellen definieren, auf dem Pi und unter Windows unterschiedliche Implementierungen verwenden.
 
Top, wie immer hilfreich.. 👍

Das Ganze scheint für einen Anfänger nicht ganz einfach zu sein. 😵

Habe da jetzt mal einen Beispielcode implementiert, um das überhaupt mal zu testen.

Hat jetzt zwar mit der Ausgangsfrage nichts zu tun aber vielleicht hast Du dazu auch eine Idee.

Wenn ich folgenden Code verwende:

Java:
import com.pi4j.component.switches.SwitchListener;
import com.pi4j.component.switches.SwitchState;
import com.pi4j.component.switches.SwitchStateChangeEvent;
import com.pi4j.device.piface.PiFace;
import com.pi4j.device.piface.PiFaceLed;
import com.pi4j.device.piface.PiFaceSwitch;
import com.pi4j.device.piface.impl.PiFaceDevice;
import com.pi4j.wiringpi.Spi;

import java.io.IOException;

public class PiFaceApp {

    private static PiFace piface;

    public static void main(String[] args) {
        try {
            piface = new PiFaceDevice(PiFace.DEFAULT_ADDRESS, Spi.CHANNEL_0);
        } catch (IOException e) {
            piface = null;
            e.printStackTrace();
        }

        if (piface != null) {

            piface.getSwitch(PiFaceSwitch.S1).addListener(new SwitchListener() {

                public void onStateChange(SwitchStateChangeEvent switchStateChangeEvent) {
                    if (switchStateChangeEvent.getNewState() == SwitchState.ON) {
                        piface.getLed(PiFaceLed.LED0).on();
                    } else {
                        piface.getLed(PiFaceLed.LED0).off();
                    }
                }

            });

            piface.getSwitch(PiFaceSwitch.S2).addListener(new SwitchListener() {

                public void onStateChange(SwitchStateChangeEvent switchStateChangeEvent) {
                    if (switchStateChangeEvent.getNewState() == SwitchState.ON) {
                        piface.getLed(PiFaceLed.LED1).blink(200L);
                    } else {
                        piface.getLed(PiFaceLed.LED1).blink(0);
                        piface.getLed(PiFaceLed.LED1).off();
                    }
                }

            });

        }

    }
}

Und in Eclipse in den Projekteinstellungen "Build Path" die pi4j Libarys einbinde, die ich mir herunter geladen habe, dann läuft das Projekt natürlich nicht, wenn ich es auf Eclipse in Windows starte und wirft Exceptions.

Verständlich, denn es gibt ja auch keine Hardware dazu und vermutlich sind die Libarys auch nicht Windows kompatibel.

Wenn ich das Ganze als .jar exportiere, dann sind die Libaries ja enthalten und ich kann das Ganze auf dem Raspberry starten.

Starte ich es in einer SSH Konsole mit "java -jar TestA.java" läuft die Anwendung wie sie soll.

Starte ich das Ganze aber in Eclipse "Remote", was mit einem anderen Projekt funktioniert, dann bekomme ich folgende Fehlermeldungen:

Java:
Mai 01, 2021 7:52:06 NACHM. com.pi4j.util.NativeLibraryLoader load

SEVERE: Unable to load [libpi4j.so] using path: [/lib/raspberrypi/dynamic/libpi4j.so]

java.lang.IllegalArgumentException: The path has to be absolute, but found: \lib\raspberrypi\dynamic\libpi4j.so

    at com.pi4j.util.NativeLibraryLoader.loadLibraryFromClasspath(NativeLibraryLoader.java:136)

    at com.pi4j.util.NativeLibraryLoader.load(NativeLibraryLoader.java:105)

    at com.pi4j.wiringpi.Spi.<clinit>(Spi.java:80)

    at PiFaceApp.main(PiFaceApp.java:19)

Hast du dazu eine Idee?

Vielen Dank im Voraus
Ralf
 
Wenn ich es richtig sehe, musst Du Version 2.x von pi4j verwenden. Auf der oben verlinkten Seite steht: "Version 1 was implemented using a static singleton, while version 2 uses a “Context” to avoid static singletons."

Beispiele für V2 sind auf der Seite auch angegeben, z. B. https://pi4j.com/documentation/io-examples/digital-output/

Mehr kann ich dazu nicht sagen, ohne es ausprobiert zu haben 🙂
 
Wenn ich es richtig sehe, musst Du Version 2.x von pi4j verwenden. Auf der oben verlinkten Seite steht: "Version 1 was implemented using a static singleton, while version 2 uses a “Context” to avoid static singletons."

Beispiele für V2 sind auf der Seite auch angegeben, z. B. https://pi4j.com/documentation/io-examples/digital-output/

Mehr kann ich dazu nicht sagen, ohne es ausprobiert zu haben 🙂
Hallo,

danke für deine Antwort. Bin erst jetzt dazu gekommen mal weiter zu machen. Ich denke nicht das dies an der Version liegt. Ich habe mir mal ein anderes Beispiel herunter geladen und in mein Projekt eingebunden.

Beispiel

Da sieht man unter "EXAMPLE JAVA PROGRAM" das in einem Link die GithubRepository der Pi4j Version 1.4 hinterlegt ist.

Die habe ich auch installiert und in Eclipse als Libary hinterlegt. Wenn ich die Main Methode ändere und die Klasse aus meinem Projekt heraus aufrufe, dann bekomme ich bei "Remote Debug" Ausführung in Eclipse die Fehlermeldung:

Java:
Mai 04, 2021 12:12:16 VORM. com.pi4j.util.NativeLibraryLoader load
SEVERE: Unable to load [libpi4j.so] using path: [/lib/raspberrypi/dynamic/libpi4j.so]
java.lang.IllegalArgumentException: The path has to be absolute, but found: \lib\raspberrypi\dynamic\libpi4j.so
    at com.pi4j.util.NativeLibraryLoader.loadLibraryFromClasspath(NativeLibraryLoader.java:136)
    at com.pi4j.util.NativeLibraryLoader.load(NativeLibraryLoader.java:105)
    at com.pi4j.wiringpi.Spi.<clinit>(Spi.java:80)
    at myhome.Pi4j_Test.start(Pi4j_Test.java:32)
    at myhome.MyHomeStart.main(MyHomeStart.java:54)

Exportiere ich das aber als Jar File, kann ich es auf dem Raspberry problemlos mit "java -jar Myhome.jar" aufrufen. Also kommen die Libaries ja korrekt im Jar File mit.

Was mich wundert ist der Teil der Fehlmeldung die sagt: "The path has to be absolute, but found: \lib\raspberrypi\dynamic\libpi4.so"

Ich binde ja die Libs einfach im Projekt unter "Properties/Build Path/Libaries" ein und da steht natürlich zunächst ein absoluter Pfad, der aber natürlich auf der Eclipse Maschine liegt. Im Grunde muss!! der Pfad ja relativ sein, sonst läuft das Ganze ja nicht auf Linux und Windows bzw. auf anderen Maschinen, ohne die gleiche Pfadstruktur.

Wo ist da mein Denkfehler?

Hast du, oder gerne natürlich auch andere, 😉 noch eine Idee?

LG
Ralf
 

Zurück
Oben