Custom Component: TouchPad Control

Playing around with the Canvas I have implemented a TouchPad like Control.

xValueProperty and yValueProperty are provided in a range from 0.0…1.0 respectively -1.0..1.0.

Thus this control can be used like an “Input-Device”, e.g. a Joystick (use two of them to operate a Quadrocopter ;-)) or a PitchControl (like the FX control of “DM1 – The Drum Machine” from Fingerlab):

JavaFX on Raspberry Pi: GPIO Controller (Part2)

Part1 of this little series of articles was about the hardware setup of my little Raspberry Pi GPIO project.
Now let’s focus the software.

The Schema

RaspiGpioControllSchema

GpioAdapterFX

For the bridge between Java and the Raspberry’s GPIO I took advantage of the great work of the Pi4J Project guys.
The com.pi4j.io.gpio.GpioController is a straighforward and simple wrapper to manage the Pi4J GPIOController with JavaFX Properties:


public class GpioAdapterFX{

  private GpioController GPIO;
  private ObservableMap<BooleanProperty, ChangeListener<Boolean>> pins;
  private BooleanProperty pin0StateProperty;
  private BooleanProperty pin1StateProperty;
  private BooleanProperty pin2StateProperty;
  private BooleanProperty pin3StateProperty;
  private BooleanProperty pin4StateProperty;
  private BooleanProperty pin5StateProperty;
  private BooleanProperty pin6StateProperty;
  private BooleanProperty pin7StateProperty;
  private Timeline testTimeline;

  public CpioFXAdapter() {
    init();
  }

 private void init() {
    pin0StateProperty = new SimpleBooleanProperty(Boolean.FALSE);
    pin1StateProperty = new SimpleBooleanProperty(Boolean.FALSE);
    pin2StateProperty = new SimpleBooleanProperty(Boolean.FALSE);
    pin3StateProperty = new SimpleBooleanProperty(Boolean.FALSE);
    pin4StateProperty = new SimpleBooleanProperty(Boolean.FALSE);
    pin5StateProperty = new SimpleBooleanProperty(Boolean.FALSE);
    pin6StateProperty = new SimpleBooleanProperty(Boolean.FALSE);
    pin7StateProperty = new SimpleBooleanProperty(Boolean.FALSE);

    pins = FXCollections.observableHashMap();
    pins.put(pin0StateProperty, null);
    pins.put(pin1StateProperty, null);
    pins.put(pin2StateProperty, null);
    pins.put(pin3StateProperty, null);
    pins.put(pin4StateProperty, null);
    pins.put(pin5StateProperty, null);
    pins.put(pin6StateProperty, null);
    pins.put(pin7StateProperty, null);
  }

 private ChangeListener<Boolean> createPinListener(final GpioPinDigitalOutput pin) {
    return new ChangeListener<Boolean>() {
      @Override
      public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
        if (newValue) {
          pin.high();
        } else {
          pin.low();
        }
      }
    };
  }

  /*
   * -------------------------- ACTIONS -------------------------- 
   */  
  public void connect() {

    GPIO = GpioFactory.getInstance();

     GpioPinDigitalOutput pin0 = GPIO.
            provisionDigitalOutputPin(RaspiPin.GPIO_00, "PIN0", PinState.LOW);
    GpioPinDigitalOutput pin1 = GPIO.
            provisionDigitalOutputPin(RaspiPin.GPIO_01, "PIN1", PinState.LOW);
    GpioPinDigitalOutput pin2 = GPIO.
            provisionDigitalOutputPin(RaspiPin.GPIO_02, "PIN2", PinState.LOW);
    GpioPinDigitalOutput pin3 = GPIO.
            provisionDigitalOutputPin(RaspiPin.GPIO_03, "PIN3", PinState.LOW);
    GpioPinDigitalOutput pin4 = GPIO.
            provisionDigitalOutputPin(RaspiPin.GPIO_04, "PIN4", PinState.LOW);
    GpioPinDigitalOutput pin5 = GPIO.
            provisionDigitalOutputPin(RaspiPin.GPIO_05, "PIN5", PinState.LOW);
    GpioPinDigitalOutput pin6 = GPIO.
            provisionDigitalOutputPin(RaspiPin.GPIO_06, "PIN6", PinState.LOW);
    GpioPinDigitalOutput pin7 = GPIO.
            provisionDigitalOutputPin(RaspiPin.GPIO_07, "PIN7", PinState.LOW);


    pins.put(pin0StateProperty, createPinListener(pin0));
    pins.put(pin1StateProperty, createPinListener(pin1));
    pins.put(pin2StateProperty, createPinListener(pin2));
    pins.put(pin3StateProperty, createPinListener(pin3));
    pins.put(pin4StateProperty, createPinListener(pin4));
    pins.put(pin5StateProperty, createPinListener(pin5));
    pins.put(pin6StateProperty, createPinListener(pin6));
    pins.put(pin7StateProperty, createPinListener(pin7));

    pin0StateProperty.addListener(pins.get(pin0StateProperty));
    pin1StateProperty.addListener(pins.get(pin1StateProperty));
    pin2StateProperty.addListener(pins.get(pin2StateProperty));
    pin3StateProperty.addListener(pins.get(pin3StateProperty));
    pin4StateProperty.addListener(pins.get(pin4StateProperty));
    pin5StateProperty.addListener(pins.get(pin5StateProperty));
    pin6StateProperty.addListener(pins.get(pin6StateProperty));
    pin7StateProperty.addListener(pins.get(pin7StateProperty));

    reset();
  }

 public void disconnect() {
    if (GPIO != null) {
      GPIO.shutdown();
    }
    for (BooleanProperty booleanProperty : pins.keySet()) {
      ChangeListener<Boolean> listener = pins.get(booleanProperty);
      if (listener != null) {
        booleanProperty.removeListener(listener);
      }
    }
  }

  public void setOnAllPins() {
    for (BooleanProperty booleanProperty : pins.keySet()) {
      booleanProperty.setValue(Boolean.TRUE);
    }
  }

  public void setOffAllPins() {
    for (BooleanProperty booleanProperty : pins.keySet()) {
      booleanProperty.setValue(Boolean.FALSE);
    }
  }

  public void reset() {
    if (testTimeline != null) {
      testTimeline.stop();
    }
    for (BooleanProperty booleanProperty : pins.keySet()) {
      booleanProperty.setValue(Boolean.FALSE);
    }
  }
 
}

SwitchBoardController

Finally the SwitchBoardController connects the UI to the GpioAdapterFX (bidirectional binding is my best friend).

To visualize the state of the GPIO Pins, I’m using Gerrit Grunwalds LED Control from his Enzo7 lib (a port of some of his JFXtras gauges to JavaFX 8).

public class SwitchBoardController implements Initializable {

  @FXML
  private GridPane buttonGridPane;
  @FXML
  private ToggleButton toogleGPIO0;
  @FXML
  private ToggleButton toogleGPIO1;
  @FXML
  private ToggleButton toogleGPIO2;
  @FXML
  private ToggleButton toogleGPIO3;
  @FXML
  private ToggleButton toogleGPIO4;
  @FXML
  private ToggleButton toogleGPIO5;
  @FXML
  private ToggleButton toogleGPIO6;
  @FXML
  private ToggleButton toogleGPIO7;
  @FXML
  private Button testButton;
  @FXML
  private Button resetButton;
  @FXML
  private Button exitButton;
  @FXML
  private ToggleButton gpioConnectButton;
  @FXML
  private ToggleGroup gpioConnectGroup;
  @FXML
  private ToggleButton gpioDisconnectButton;
  private GpioAdapterFX gpioAdapterFx;
  private Led indicatorGPIO0;
  private Led indicatorGPIO1;
  private Led indicatorGPIO2;
  private Led indicatorGPIO3;
  private Led indicatorGPIO4;
  private Led indicatorGPIO5;
  private Led indicatorGPIO6;
  private Led indicatorGPIO7;

  /**
   * Initializes the controller class.
   */
  @Override
  public void initialize(URL url, ResourceBundle rb) {
    assert buttonGridPane != null : "fx:id=\"buttonGridPane\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert exitButton != null : "fx:id=\"exitButton\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert gpioConnectButton != null : "fx:id=\"gpioConnectButton\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert gpioConnectGroup != null : "fx:id=\"gpioConnectGroup\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert gpioDisconnectButton != null : "fx:id=\"gpioDisconnectButton\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert resetButton != null : "fx:id=\"resetButton\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert testButton != null : "fx:id=\"testButton\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert toogleGPIO0 != null : "fx:id=\"toogleCPIO0\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert toogleGPIO1 != null : "fx:id=\"toogleCPIO1\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert toogleGPIO2 != null : "fx:id=\"toogleCPIO2\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert toogleGPIO3 != null : "fx:id=\"toogleCPIO3\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert toogleGPIO4 != null : "fx:id=\"toogleCPIO4\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert toogleGPIO5 != null : "fx:id=\"toogleCPIO5\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert toogleGPIO6 != null : "fx:id=\"toogleCPIO6\" was not injected: check your FXML file 'SwitchBoard.fxml'.";
    assert toogleGPIO7 != null : "fx:id=\"toogleCPIO7\" was not injected: check your FXML file 'SwitchBoard.fxml'.";

    gpioAdapterFx = new GpioAdapterFX();

    indicatorGPIO0 = createIndicator();
    indicatorGPIO1 = createIndicator();
    indicatorGPIO2 = createIndicator();
    indicatorGPIO3 = createIndicator();
    indicatorGPIO4 = createIndicator();
    indicatorGPIO5 = createIndicator();
    indicatorGPIO6 = createIndicator();
    indicatorGPIO7 = createIndicator();

    buttonGridPane
            .add(indicatorGPIO0, 0, 0);
    buttonGridPane.add(indicatorGPIO1, 1, 0);
    buttonGridPane.add(indicatorGPIO2, 2, 0);
    buttonGridPane.add(indicatorGPIO3, 3, 0);
    buttonGridPane.add(indicatorGPIO4, 4, 0);
    buttonGridPane.add(indicatorGPIO5, 5, 0);
    buttonGridPane.add(indicatorGPIO6, 6, 0);
    buttonGridPane.add(indicatorGPIO7, 7, 0);

    indicatorGPIO0.onProperty().
            bindBidirectional(gpioAdapterFx.pin0StateProperty());
    indicatorGPIO1.onProperty().
            bindBidirectional(gpioAdapterFx.pin1StateProperty());
    indicatorGPIO2.onProperty().
            bindBidirectional(gpioAdapterFx.pin2StateProperty());
    indicatorGPIO3.onProperty().
            bindBidirectional(gpioAdapterFx.pin3StateProperty());
    indicatorGPIO4.onProperty().
            bindBidirectional(gpioAdapterFx.pin4StateProperty());
    indicatorGPIO5.onProperty().
            bindBidirectional(gpioAdapterFx.pin5StateProperty());
    indicatorGPIO6.onProperty().
            bindBidirectional(gpioAdapterFx.pin6StateProperty());
    indicatorGPIO7.onProperty().
            bindBidirectional(gpioAdapterFx.pin7StateProperty());

    toogleGPIO0.selectedProperty().
            bindBidirectional(gpioAdapterFx.pin0StateProperty());
    toogleGPIO1.selectedProperty().
            bindBidirectional(gpioAdapterFx.pin1StateProperty());
    toogleGPIO2.selectedProperty().
            bindBidirectional(gpioAdapterFx.pin2StateProperty());
    toogleGPIO3.selectedProperty().
            bindBidirectional(gpioAdapterFx.pin3StateProperty());
    toogleGPIO4.selectedProperty().
            bindBidirectional(gpioAdapterFx.pin4StateProperty());
    toogleGPIO5.selectedProperty().
            bindBidirectional(gpioAdapterFx.pin5StateProperty());
    toogleGPIO6.selectedProperty().
            bindBidirectional(gpioAdapterFx.pin6StateProperty());
    toogleGPIO7.selectedProperty().
            bindBidirectional(gpioAdapterFx.pin7StateProperty());
  }

  private Led createIndicator() {
    return LedBuilder.create().
            prefHeight(80.0).
            prefWidth(80.0).
            build();
  }

  /*
   * -------------------------- ACTIONS -------------------------- 
   */
  @FXML
  public void testAction() {
    gpioAdapterFx.test();
  }

  @FXML
  public void resetAction() {
    gpioAdapterFx.reset();
  }

  @FXML
  public void gpioDisconnectAction() {
    gpioAdapterFx.disconnect();
  }

  @FXML
  public void gpioConnectAction() {
    gpioAdapterFx.connect();
  }

  @FXML
  public void exitAction() {
    gpioAdapterFx.reset();
    gpioAdapterFx.disconnect();
    Platform.exit();
  }
}

You can find the complete code here.

The runfxapp skript may help you to run the app on your Raspberry.

Stay tuned…

Inspired by Oliver Schneiders blog post I have already ordered the transmitter to control my wireless power outlets (but shipping from Hong Kong will take some weeks…).

JavaFX on Raspberry Pi: GPIO Controller (Part1)

I have started a new leisure time project with my Raspberry Pi.
Target: control the outside lighting around my house (yes, magic words these days: HOME AUTOMATION).

But let’s see how far I will get ;-).

Until now I created a very simple JavaFX UI to control and test the 8 GPIO-out pin states:

GPIO Control UI

But first lets have a look at the setup:

Used Hardware

System setup

Construction

So I armed myself with a soldering gun, brazed the Adafruit Pi Cobbler and sticked together the electical parts on the bread board according to the pin numbering:

WiringPi pin number scheme

gpio-control-example
(Source: pi4j.com)

DSC_3980

DSC_3982

And: Action!

Part2

JavaFX on Raspberry Pi: runfxapp v1.1

I have updated my runfxapp skript:

Feel free to load it: runfxapp 1.1

Please find installation instructions and usage hints in my previous post.

#!/bin/bash 
#
#############################################################
#
# Script: runfxapp
#
# Start JavaFX apps more conveniently.
#
# (c) copyright 2013 Jens Deters, mail@jensd.de, www.jensd.de
#
#############################################################

JAVA_HOME=/opt/jdk1.8.0
JAVA_MAIN=$JAVA_HOME/bin/java
LIBS=/opt/pi4j/lib/*:/opt/lib/*
SCRIPT=$0
EXIT_SUCCESS=0
EXIT_FAILURE=1
EXIT_ERROR=2
APP_JAR="NO JAR DEFINED"
VERBOSE=n
APP_VERSION=1.1

function usage {
 echo "runfxapp v$APP_VERSION"
 echo "Usage: $(basename $SCRIPT .sh) [-v] [-h] [-j <PATH_TO_JAR>] <MAIN_CLASS>" >&2
 [[ $# -eq 1 ]] && exit $1 || exit $EXIT_FAILURE
}

function check_preconditions {

 if [[ ! -f $JAVA_MAIN ]];then
    echo "Error: Can't find '$JAVA_MAIN'. Please check your JDK installation AND/OR correct 'JAVA_HOME' in: $SCRIPT"
    exit $EXIT_ERROR
 fi

 if [[ ! -f $APP_JAR ]];then
    echo "Error: Can't find application JAR: '$APP_JAR'." 
    exit $EXIT_ERRORR
 fi
}


while getopts ':j:hv' OPTION ; do
 case $OPTION in
 v) VERBOSE=y
 ;;
 h) usage $EXIT_SUCCESS
 ;;
 j) APP_JAR="$OPTARG"
 ;;
 \?) echo "Error: Unknown Option \"-$OPTARG\"." >&2
     usage $EXIT_ERROR
 ;;
 esac
done

shift $(( OPTIND - 1 ))
if (( $# < 1 )) ; then
 echo "Error: MainClass is needed:" >&2
 usage $EXIT_ERROR
fi

check_preconditions

COMMAND="sudo $JAVA_MAIN -Djavafx.platform=eglfb -classpath .:classes:$LIBS:$JAVA_HOME/jre/lib/jfxrt.jar:$APP_JAR $@"

if [[ $VERBOSE = y ]] ; then
 echo "Attempt to execute: $COMMAND"
fi

$COMMAND

exit $EXIT_SUCCESS