diff --git a/.gitignore b/.gitignore index 34c8bf8..ad311ba 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ target/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + +# Intellij Files +.idea \ No newline at end of file diff --git a/src/main/java/ch/eitchnet/beaglebone/GpioBridge.java b/src/main/java/ch/eitchnet/beaglebone/GpioBridge.java index f5882c4..a0a5431 100644 --- a/src/main/java/ch/eitchnet/beaglebone/GpioBridge.java +++ b/src/main/java/ch/eitchnet/beaglebone/GpioBridge.java @@ -1,400 +1,96 @@ package ch.eitchnet.beaglebone; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - *
- * Main object to give access to GPIO ports on a Linux kernel - *
- * - *- * The {@link GpioBridge} is a singleton. Features include retrieving Pins, writing and reading values, as well as - * registering observers for changes to input pins - *
- * - *- * {@link Gpio} objects are cached and their {@link Signal} is set by the {@link GpioBridge} accordingly - *
- * - * @author Robert von Burg <eitch@eitchnet.ch> - */ -public class GpioBridge { - - private static final String GPIO_PATH = "/sys/class/gpio/"; - - private Map* Public API method to write the given {@link Signal} on the given {@link Gpio}'s pin. *
- * + * * @param gpio * the {@link Gpio} to which the {@link Signal} should be written * @param signal * the {@link Signal} to write to the given {@link Gpio} - * + * * @throws GpioException * if the direction of the {@link Gpio} is not {@link Direction#OUT}, or if something goes wrong while * writing to the file */ - public void writeValue(Gpio gpio, Signal signal) throws GpioException { - - synchronized (gpio) { - if (gpio.getDirection() != Direction.OUT) - throw new GpioException("For writing the direction must be " + Direction.OUT); - - File file = getGpioValuePath(gpio); - try (FileOutputStream out = new FileOutputStream(file)) { - - out.write(signal.getValueS().getBytes()); - out.flush(); - - gpio.setSignal(signal); - - } catch (Exception e) { - throw new GpioException("Failed to write GPIO " + gpio + " with signal " + signal, e); - } - - System.out.println("Set GPIO " + gpio.getPin() + " signal to " + gpio.getSignal()); - } - } + void writeValue(Gpio gpio, Signal signal) throws GpioException; /** ** Public API method to read the current {@link Signal} on the given {@link Gpio}'s pin. *
- * + * * @param gpio * the {@link Gpio} for which the {@link Signal} should be read - * + * * @return The {@link Gpio}'s current signal - * + * * @throws GpioException * if the direction of the {@link Gpio} is not {@link Direction#IN}, or if something goes wrong while * reading from the file */ - public Signal readValue(Gpio gpio) throws GpioException { - - synchronized (gpio) { - - if (gpio.getDirection() != Direction.IN) - throw new GpioException("For reading the direction must be " + Direction.IN); - - File file = getGpioValuePath(gpio); - try (BufferedReader fin = new BufferedReader(new FileReader(file))) { - - String valueS = fin.readLine(); - Signal signal = Signal.getSignal(valueS); - if (!gpio.getSignal().equals(signal)) - gpio.setSignal(signal); - - return signal; - - } catch (Exception e) { - throw new GpioException("Failed to read GPIO " + gpio, e); - } - } - } + Signal readValue(Gpio gpio) throws GpioException; /** * Starts the {@link GpioBridge}'s signal observing {@link Thread}. If no observers are registered with the * {@link #register(Gpio, GpioSignalListener)}-method, then this method needs not to be called. */ - public void start() { - - this.run = true; - this.thread = new Thread(() -> { - while (this.run) { - if (this.listeners.isEmpty()) { - synchronized (this) { - try { - wait(1000l); - } catch (InterruptedException e) { - System.out.println("Was interrupted. Stopping thread."); - this.run = false; - break; - } - } - } else { - - List* Returns the {@link Gpio} for the given {@link Direction}. *
- * + * ** Note: This method can not be called multiple times with different {@link Direction}s. The * {@link GpioBridge} does not handle pins that are simultaneously input and output as this is not supported by the * Linux kernel. *
- * + * * @param pin * The {@link Pin} for which the {@link Gpio} in the given {@link Direction} is to be returned * @param direction * the {@link Direction} for which this {@link Gpio} is to be returned - * + * * @return The {@link Gpio} with the configured {@link Direction} - * + * * @throws GpioException * If the given {@link Direction} does not match the kernel's configured direction, or if the file * permissions are not set so that the Java process can access the file (read access for input pin, * write access for output pin. */ - public synchronized Gpio getGpio(Pin pin, Direction direction) throws GpioException { - Gpio gpio = this.cache.get(pin); - if (gpio == null) { - - gpio = new Gpio(pin, direction); - - // validate direction - assertDirection(gpio); - - // validate file permissions - validateFilePermissions(gpio); - - this.cache.put(pin, gpio); - System.out.println("Initialized pin " + pin + " with direction " + direction + "."); - } - - return gpio; - } - - /** - * Validates the direction of the {@link Gpio} is the same as kernel's exported state - * - * @param gpio - * the {@link Gpio} been asserted for direction - * - * @throws GpioException - * if the assertion fails - */ - private void assertDirection(Gpio gpio) throws GpioException { - File file = getGpioDirectionPath(gpio); - Pin pin = gpio.getPin(); - try (BufferedReader fin = new BufferedReader(new FileReader(file))) { - - String directionS = fin.readLine(); - Direction dir = Direction.getDirection(directionS); - if (dir != gpio.getDirection()) - throw new GpioException("Actual direction of GPIO " + pin + " is " + dir + " not " + directionS); - - } catch (FileNotFoundException e) { - throw new GpioException("GPIO " + pin + " does not exist, was the pin exported to user space?", e); - } catch (IOException e) { - throw new GpioException("Failed to open GPIO " + pin, e); - } - } - - /** - * Validates the file permissions of the {@link Gpio} is correct for the {@link Gpio}'s {@link Direction}: - *+ * Main object to give access to GPIO ports on a Linux kernel + *
+ * + *+ * The {@link GpioBridge} is a singleton. Features include retrieving Pins, writing and reading values, as well as + * registering observers for changes to input pins + *
+ * + *+ * {@link Gpio} objects are cached and their {@link Signal} is set by the {@link GpioBridge} accordingly + *
+ * + * @author Robert von Burg <eitch@eitchnet.ch> + */ +public class GpioBridgeImpl implements GpioBridge { + + private static final String GPIO_PATH = "/sys/class/gpio/"; + + private Map+ * Public API method to write the given {@link Signal} on the given {@link Gpio}'s pin. + *
+ * + * @param gpio + * the {@link Gpio} to which the {@link Signal} should be written + * @param signal + * the {@link Signal} to write to the given {@link Gpio} + * + * @throws GpioException + * if the direction of the {@link Gpio} is not {@link Direction#OUT}, or if something goes wrong while + * writing to the file + */ + @Override + public void writeValue(Gpio gpio, Signal signal) throws GpioException { + + synchronized (gpio) { + if (gpio.getDirection() != Direction.OUT) + throw new GpioException("For writing the direction must be " + Direction.OUT); + + File file = getGpioValuePath(gpio); + try (FileOutputStream out = new FileOutputStream(file)) { + + out.write(signal.getValueS().getBytes()); + out.flush(); + + gpio.setSignal(signal); + + } catch (Exception e) { + throw new GpioException("Failed to write GPIO " + gpio + " with signal " + signal, e); + } + + System.out.println("Set GPIO " + gpio.getPin() + " signal to " + gpio.getSignal()); + } + } + + /** + *+ * Public API method to read the current {@link Signal} on the given {@link Gpio}'s pin. + *
+ * + * @param gpio + * the {@link Gpio} for which the {@link Signal} should be read + * + * @return The {@link Gpio}'s current signal + * + * @throws GpioException + * if the direction of the {@link Gpio} is not {@link Direction#IN}, or if something goes wrong while + * reading from the file + */ + @Override + public Signal readValue(Gpio gpio) throws GpioException { + + synchronized (gpio) { + + if (gpio.getDirection() != Direction.IN) + throw new GpioException("For reading the direction must be " + Direction.IN); + + File file = getGpioValuePath(gpio); + try (BufferedReader fin = new BufferedReader(new FileReader(file))) { + + String valueS = fin.readLine(); + Signal signal = Signal.getSignal(valueS); + if (!gpio.getSignal().equals(signal)) + gpio.setSignal(signal); + + return signal; + + } catch (Exception e) { + throw new GpioException("Failed to read GPIO " + gpio, e); + } + } + } + + /** + * Starts the {@link GpioBridge}'s signal observing {@link Thread}. If no observers are registered with the + * {@link #register(Gpio, GpioSignalListener)}-method, then this method needs not to be called. + */ + @Override + public void start() { + + this.run = true; + this.thread = new Thread(() -> { + while (this.run) { + if (this.listeners.isEmpty()) { + synchronized (this) { + try { + wait(1000l); + } catch (InterruptedException e) { + System.out.println("Was interrupted. Stopping thread."); + this.run = false; + break; + } + } + } else { + + List+ * Returns the {@link Gpio} for the given {@link Direction}. + *
+ * + *+ * Note: This method can not be called multiple times with different {@link Direction}s. The + * {@link GpioBridge} does not handle pins that are simultaneously input and output as this is not supported by the + * Linux kernel. + *
+ * + * @param pin + * The {@link Pin} for which the {@link Gpio} in the given {@link Direction} is to be returned + * @param direction + * the {@link Direction} for which this {@link Gpio} is to be returned + * + * @return The {@link Gpio} with the configured {@link Direction} + * + * @throws GpioException + * If the given {@link Direction} does not match the kernel's configured direction, or if the file + * permissions are not set so that the Java process can access the file (read access for input pin, + * write access for output pin. + */ + @Override + public synchronized Gpio getGpio(Pin pin, Direction direction) throws GpioException { + Gpio gpio = this.cache.get(pin); + if (gpio == null) { + + gpio = new Gpio(pin, direction); + + // validate direction + assertDirection(gpio); + + // validate file permissions + validateFilePermissions(gpio); + + this.cache.put(pin, gpio); + System.out.println("Initialized pin " + pin + " with direction " + direction + "."); + } + + return gpio; + } + + /** + * Validates the direction of the {@link Gpio} is the same as kernel's exported state + * + * @param gpio + * the {@link Gpio} been asserted for direction + * + * @throws GpioException + * if the assertion fails + */ + private void assertDirection(Gpio gpio) throws GpioException { + File file = getGpioDirectionPath(gpio); + Pin pin = gpio.getPin(); + try (BufferedReader fin = new BufferedReader(new FileReader(file))) { + + String directionS = fin.readLine(); + Direction dir = Direction.getDirection(directionS); + if (dir != gpio.getDirection()) + throw new GpioException("Actual direction of GPIO " + pin + " is " + dir + " not " + directionS); + + } catch (FileNotFoundException e) { + throw new GpioException("GPIO " + pin + " does not exist, was the pin exported to user space?", e); + } catch (IOException e) { + throw new GpioException("Failed to open GPIO " + pin, e); + } + } + + /** + * Validates the file permissions of the {@link Gpio} is correct for the {@link Gpio}'s {@link Direction}: + *