Pi4J Wykonanie Future rzuca CancellationException

1

Witam!

Ostatnio klepię na Raspberry (i JEE na zmianę, żeby się nie znudzić) i rzuca mi wyjątek CancellationException.
Dioda mruga jak powinna, wysypuje się dopiero po zakończeniu tych 10 sekund. Docsy nic nie mówią. Czytałem tutaj i tu, że może to być niepoprawna ilość czasu przydzielona do wykonania zadania.
Chciałem zapytać czyja to wina - moja czy biblioteki?
Kod:

import com.pi4j.io.gpio.*;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * This example code demonstrates how to perform simple state
 * control of a GPIO pin on the Raspberry Pi.
 *
 * @author Robert Savage
 */
public class ControlGpioExample {

    public static void main(String[] args) throws InterruptedException {

        System.out.println("<--Pi4J--> GPIO Control Example ... started.");

        // create gpio controller
        final GpioController gpio = GpioFactory.getInstance();

        // provision gpio pin #01 as an output pin and turn on
        final GpioPinDigitalOutput pin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_01, "MyLED", PinState.HIGH);

        // set shutdown state for this pin
        pin.setShutdownOptions(true, PinState.LOW);

        Future f = pin.blink(100,10000);

        try {
            f.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        // stop all GPIO activity/threads by shutting down the GPIO controller
        // (this method will forcefully shutdown all GPIO monitoring threads and scheduled tasks)
        gpio.shutdown();

        System.out.println("Exiting ControlGpioExample");
    }
}

Stack trace:

<--Pi4J--> GPIO Control Example ... started.
Exception in thread "main" java.util.concurrent.CancellationException
	at java.util.concurrent.FutureTask.report(FutureTask.java:121)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at ControlGpioExample.main(ControlGpioExample.java:61)
1

Tak to napisali w Pi4J. Nie wiem co mieli na myśli, ale zawsze ten future będzie po blink cancellowany - nie poradzisz :
https://pi4j.com/apidocs/src-html/com/pi4j/io/gpio/tasks/impl/GpioBlinkStopTaskImpl.html
Weź może nie wywołuj tego .get() - to i tak smród.

0

Przy zwykłym wywołaniu:

pin.blink(100,10000);

dioda mruga tylko jeden raz i program kontynuuje swoje wykonanie.
Pytanie brzmi czy opakować ten smród w papierek od cukierka?

public void blink(final GpioPinDigitalOutput pin, long delay, long duration) throws ExecutionException {
	Future f = pin.blink(delay, duration);
	try {
		f.get();
	} catch (CancellationException e) {
		//Don't do anything
	}
}
0

A po prostu jakiś Thread.sleep Ci nie wystarczy ?

(ewentualnie isDone możesz sprawdzać - ale IMO to jest źle zrobione i trudno będzie ten kod "ładnie wywołać", moim zdaniem nie przyszło im do głowy, że ktoś z tego Future będzie faktycznie korzystał - normalnie blinkasz i idziesz dalej).

0

Ale jak? Po każdym wywołaniu tej metody?
Zapewne będę używał jej wielokrotnie w kodzie, potrzebowałbym czegoś w stylu Write once, use anywhere

1

Ewentualnie zaimplementuj swojego blinka lepiej. To nie jest dużo pracy.

0

Dobra, potrzebuję ewidentnie pomocy.

final GpioController gpio = GpioFactory.getInstance();

Tutaj z kodu singletona widać, że zwraca GpioControllerImpl jako GpioController

private static GpioController controller = null;
...
if (controller == null) {
	controller = new GpioControllerImpl();
}
// else return a copy of the existing controller
return controller;

Idziemy dalej. Ta linijka

final GpioPinDigitalOutput pin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_01, "MyLED", PinState.HIGH);

wywołuje metodę taką:

@Override
    public GpioPinDigitalOutput provisionDigitalOutputPin(Pin pin, String name, PinState defaultState) {
        return provisionDigitalOutputPin(defaultProvider, pin, name, defaultState);
    }

, która wywołuje metodę:

    @Override
    public GpioPinDigitalOutput provisionDigitalOutputPin(GpioProvider provider, Pin pin, String name, PinState defaultState) {
        // create new GPIO pin instance
        GpioPinDigitalOutput gpioPin = (GpioPinDigitalOutput)provisionPin(provider, pin, name, PinMode.DIGITAL_OUTPUT, defaultState);

        // apply default state
        if (defaultState != null) {
            gpioPin.setState(defaultState);
        }
        // return new new pin instance
        return gpioPin;
    }

, więc musimy jeszcze sprawdzić co robi provisionPin, aby wiedzieć co zwraca (jaką implementację, a nie interfejs).
Oto ona:

@Override
    public GpioPin provisionPin(GpioProvider provider, Pin pin, String name, PinMode mode, PinState defaultState) {

        // if the provider does not match the pin's provider then throw an error
        if(!provider.getName().equals(pin.getProvider())){
            throw new PinProviderException(provider, pin);
        }

        // if an existing pin has been previously created, then throw an error
        for(GpioPin p : pins) {
            if (p.getProvider().equals(provider) && p.getPin().equals(pin)) {
                throw new GpioPinExistsException(pin);
            }
        }

        // create new GPIO pin instance
        GpioPin gpioPin = new GpioPinImpl(this, provider, pin);

        // set the gpio pin name
        if (name != null) {
            gpioPin.setName(name);
        }

        // export this pin
        gpioPin.export(mode, defaultState);

        // add this new pin instance to the managed collection
        pins.add(gpioPin);

        // return new new pin instance
        return gpioPin;
    }

, czyli szukałem GpioPinImpl.
Wchodzę do klasy i już wiem co mam zaimplementować:

public class GpioPinImpl implements GpioPin,
                                    GpioPinDigitalInput,
                                    GpioPinDigitalOutput,
                                    GpioPinDigitalMultipurpose,
                                    GpioPinAnalogInput,
                                    GpioPinAnalogOutput,
                                    GpioPinPwmOutput,
                                    GpioPinInput,
                                    GpioPinOutput

Na dzisiaj chyba wystarczy zabawy

0

Nie dam rady napisać własnej implementacji, nie jestem jeszcze na wystarczającym poziomie. Do zamknięcia

0

A po prostu jakiś Thread.sleep Ci nie wystarczy ?

Ale jak? Po każdym wywołaniu tej metody?

No a czemu nie? Skoro chcesz napisać funkcję, która przez 10 sekund nic nie robi tylko miga, to uśpij wątek. W pseudokodzie:

blink(10000)
sleep(10000)

Albo tak:

blink(100000)
sleep(10000)
wylaczBlink()

W czym problem?

0

@Burdzi0: a nie możesz zrobić sobie jakiegoś zwykłego wrappera?

0

Jestem na to za głupi.
Dlaczego kiedy próbuję opakować GpioPinImpl w nową klasę, np.:

import com.pi4j.io.gpio.*;
import com.pi4j.io.gpio.impl.GpioPinImpl;

public class LedGpioPinDigitalOutput extends GpioPinImpl  {

    public LedGpioPinDigitalOutput(GpioController gpio, GpioProvider provider, Pin pin) {
        super(gpio, provider, pin);
    }

    public void blockingBlink(long delay){
        super.blink(delay);
        try {
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

i próbuję wywołać w ten sposób:

System.out.println("<--Pi4J--> GPIO Control Example ... started.");

        // create gpio controller
        final GpioController gpio = GpioFactory.getInstance();

        // provision gpio pin #01 as an output pin and turn on
        final GpioPinDigitalOutput pin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_01, "MyLED", PinState.HIGH);

        LedGpioPinDigitalOutput led = (LedGpioPinDigitalOutput) pin;
        // set shutdown state for this pin
        pin.setShutdownOptions(true, PinState.LOW);

        led.blockingBlink(3000);

obrywam

<--Pi4J--> GPIO Control Example ... started.
Exception in thread "main" java.lang.ClassCastException: com.pi4j.io.gpio.impl.GpioPinImpl cannot be cast to LedGpioPinDigitalOutput
	at ControlGpioExample.main(ControlGpioExample.java:56)

Klasa GpioPinImpl ma taką deklarację:

public class GpioPinImpl implements GpioPin,
                                    GpioPinDigitalInput,
                                    GpioPinDigitalOutput,
                                    GpioPinDigitalMultipurpose,
                                    GpioPinAnalogInput,
                                    GpioPinAnalogOutput,
                                    GpioPinPwmOutput,
                                    GpioPinInput,
                                    GpioPinOutput
{///

więc dziedziczenie powoduje, że moja klasa automatycznie implementuje w/w interfejsy, a jakoś ten class cast

 LedGpioPinDigitalOutput led = (LedGpioPinDigitalOutput) pin;

wywala wszystko do góry nogami. Chwilę nie programowałem, więc nie wykluczam, że moje zdolności są <=0. Może warto przerzucić to do Newbie

0

Potrzebuję pomocy. Uparłem się na własną implementację, ale kompletnie nie wiem jak się do tego zabrać.
@jarekr000000, @scibi92, @jarekczek nie rozumiem jak biblioteka jest skonstruowana. Pomoglibyście mi zrozumieć, który konkretnie interfejs/klasę mam zaimplementować/dziedziczyć, aby osiągnąć swój cel?
Jak na razie próbowałem, stworzyć własny interfejs dziedziczący po GpioPinDigitalOutput:

import com.pi4j.io.gpio.GpioPinDigitalOutput;

public interface LedGpioPinDigitalOutput extends GpioPinDigitalOutput {
    void blockingBlink(long delay, long duration);
}

i własną klasę dziedziczącą po GpioPinImpl implementującą wyżej ukazany interfejs:

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioPin;
import com.pi4j.io.gpio.GpioProvider;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.impl.GpioPinImpl;

public class LedGpioPinImpl extends GpioPinImpl implements LedGpioPinDigitalOutput{

    public LedGpioPinImpl(GpioController gpio, GpioProvider provider, Pin pin) {
        super(gpio, provider, pin);
    }

    @Override
    public void blockingBlink(long delay, long duration) {
        blink(delay, duration);
        try {
            Thread.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Wywołuję to w ten sposób:

        final GpioController gpio = GpioFactory.getInstance();

        // provision gpio pin #01 as an output pin and turn on
        final GpioPinDigitalOutput pin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_01, "MyLED", PinState.HIGH);

        pin.setShutdownOptions(true, PinState.LOW);

        LedGpioPinDigitalOutput led = (LedGpioPinDigitalOutput) pin;

        led.blockingBlink(50,3000);

Ciągle nie rozumiem dlaczego obrywam ClassCastException? Help

0

Ale przecież masz już tą funkcję napisaną, w Twoim drugim poście...

1

Dobra, przeczytałem trochę więcej z tego wątku

  1. migasz 10 razy na sekundę. Najwyższa częstotliwość jaką widziałem w przykładach to 4 Hz.
    Diody różnie działają, za duża częstotliwość jest niewidoczna dla ludzkiego oka.

  2. nie wiem po co używasz future, wszystkie przykłady które znalazłem poniżej są bezwątkowe (chyba że ktoś bierze Thread.sleep() za wielowątkowość)

https://calpilot.wordpress.com/2014/06/21/rpi-pi4j-tutorial-2-gpio-output/
http://www.admfactory.com/blinking-led-on-raspberry-pi-using-java/
https://github.com/Pi4J/pi4j/blob/master/pi4j-example/src/main/java/BlinkGpioExample.java

A tu wersja z future:
https://github.com/Pi4J/pi4j/blob/master/pi4j-example/src/main/java/bananapi/GpioOutputExample.java

1 użytkowników online, w tym zalogowanych: 0, gości: 1