[Major] Refactored code and added simple example use case

This commit is contained in:
Robert von Burg 2016-02-03 22:56:40 +01:00
parent 9fab58cb64
commit 5168f4e07b
8 changed files with 516 additions and 313 deletions

View File

@ -0,0 +1,23 @@
package ch.eitchnet.beaglebone;
public enum Direction {
IN("in"), OUT("out");
private String direction;
private Direction(String direction) {
this.direction = direction;
}
public String getDirection() {
return this.direction;
}
public static Direction getDirection(String directionS) {
if (directionS.equals(IN.direction))
return IN;
else if (directionS.equals(OUT.direction))
return OUT;
throw new IllegalArgumentException("No direction for value " + directionS);
}
}

View File

@ -0,0 +1,48 @@
package ch.eitchnet.beaglebone;
public class Gpio {
private final Pin pin;
private final String name;
private final Direction direction;
private String label;
private Signal signal;
public Gpio(Pin pin, Direction direction) {
this.pin = pin;
this.direction = direction;
this.name = "gpio" + pin.getGpioNr();
this.label = name;
this.signal = Signal.LOW;
}
public Pin getPin() {
return this.pin;
}
public String getName() {
return this.name;
}
public Gpio setLabel(String label) {
this.label = label;
return this;
}
public String getLabel() {
return this.label;
}
public Direction getDirection() {
return this.direction;
}
public Signal getSignal() {
return this.signal;
}
public Gpio setSignal(Signal signal) {
this.signal = signal;
return this;
}
}

View File

@ -0,0 +1,175 @@
package ch.eitchnet.beaglebone;
import java.io.BufferedReader;
import java.io.File;
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;
public class GpioBridge {
private Map<Pin, Gpio> cache;
private Map<Gpio, List<GpioSignalListener>> listeners;
private Thread thread;
private volatile boolean run;
public GpioBridge() {
this.cache = new HashMap<>();
this.listeners = Collections.synchronizedMap(new HashMap<>());
}
public void writeValue(Gpio gpio, Signal signal) {
if (gpio.getDirection() != Direction.OUT)
throw new IllegalArgumentException("For writing the direction must be " + Direction.OUT);
File file = new File(GpioBridgeTest.GPIO_PATH, gpio.getName() + "/value");
try (FileOutputStream out = new FileOutputStream(file)) {
out.write(signal.getValueS().getBytes());
out.flush();
gpio.setSignal(signal);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Set GPIO " + gpio.getPin() + " signal to " + gpio.getSignal());
}
public void start() {
this.run = true;
this.thread = new Thread(() -> {
while (this.run) {
if (this.listeners.isEmpty()) {
synchronized (this) {
try {
wait(1000l);
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
List<Gpio> changes = new ArrayList<>();
synchronized (this.listeners) {
for (Gpio gpio : this.listeners.keySet()) {
File file = new File(GpioBridgeTest.GPIO_PATH, gpio.getName() + "/value");
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);
changes.add(gpio);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (!changes.isEmpty())
System.out.println("Found " + changes.size() + " GPIO changes.");
for (Gpio gpio : changes) {
synchronized (this.listeners) {
List<GpioSignalListener> listeners = this.listeners.get(gpio);
System.out.println("GPIO " + gpio.getPin() + " changed to " + gpio.getSignal()
+ ". Notifying " + listeners.size() + " listeners.");
for (GpioSignalListener listener : listeners) {
listener.notify(gpio);
}
}
}
try {
Thread.sleep(200l);
} catch (Exception e) {
e.printStackTrace();
}
}
}
} , "gpio_reader");
this.thread.start();
}
public void stop() {
this.run = false;
this.thread.interrupt();
try {
this.thread.join(5000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public Gpio getGpio(Pin pin, Direction direction) {
Gpio gpio = this.cache.get(pin);
if (gpio == null) {
gpio = new Gpio(pin, direction);
File file = new File(GpioBridgeTest.GPIO_PATH, gpio.getName() + "/direction");
try (BufferedReader fin = new BufferedReader(new FileReader(file))) {
String directionS = fin.readLine();
Direction dir = Direction.getDirection(directionS);
if (dir != direction)
throw new IllegalArgumentException(
"Actual direction of GPIO " + gpio.getPin() + " is " + dir + " not " + directionS);
} catch (IOException e) {
e.printStackTrace();
}
this.cache.put(pin, gpio);
}
return gpio;
}
public void register(Gpio gpio, GpioSignalListener listener) {
if (gpio.getDirection() != Direction.IN)
throw new IllegalArgumentException("For reading the direction must be " + Direction.IN);
synchronized (this.listeners) {
List<GpioSignalListener> listeners = this.listeners.get(gpio);
if (listeners == null) {
listeners = new ArrayList<>();
this.listeners.put(gpio, listeners);
}
listeners.add(listener);
}
synchronized (this) {
notifyAll();
}
}
public void unregister(GpioBridgeTest gpio, GpioSignalListener listener) {
synchronized (this.listeners) {
List<GpioSignalListener> listeners = this.listeners.get(gpio);
if (listeners == null) {
return;
}
listeners.remove(listener);
if (listeners.isEmpty())
this.listeners.remove(gpio);
}
}
}

View File

@ -0,0 +1,5 @@
package ch.eitchnet.beaglebone;
public interface GpioSignalListener {
public void notify(Gpio gpio);
}

View File

@ -1,313 +0,0 @@
package ch.eitchnet.beaglebone;
import java.io.BufferedReader;
import java.io.File;
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;
public class GpioTest {
private static final String GPIO_PATH = "/sys/class/gpio/";
public static void main(String[] args) throws Exception {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
GpioHandler gpioHandler = new GpioHandler();
Gpio p8_11 = gpioHandler.getGpio(45, Direction.IN);
Gpio p8_12 = gpioHandler.getGpio(44, Direction.OUT);
gpioHandler.register(p8_11, (g) -> {
System.out.println("New GPIO " + g.getNumber() + " signal " + g.getSignal());
});
gpioHandler.start();
while (true) {
gpioHandler.writeValue(p8_12, p8_12.getSignal().getOpposite());
Thread.sleep(1000);
}
}
public interface GpioSignalListener {
public void notify(Gpio gpio);
}
public static class GpioHandler {
private Map<Integer, Gpio> cache;
private Map<Gpio, List<GpioSignalListener>> listeners;
private Thread thread;
private volatile boolean run;
public GpioHandler() {
this.cache = new HashMap<>();
this.listeners = Collections.synchronizedMap(new HashMap<>());
}
public void writeValue(Gpio gpio, Signal signal) {
if (gpio.getDirection() != Direction.OUT)
throw new IllegalArgumentException("For writing the direction must be " + Direction.OUT);
File file = new File(GPIO_PATH, gpio.getName() + "/value");
try (FileOutputStream out = new FileOutputStream(file)) {
out.write(signal.getValueS().getBytes());
out.flush();
gpio.setSignal(signal);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Set GPIO " + gpio.getNumber() + " signal to " + gpio.getSignal());
}
public void start() {
this.run = true;
this.thread = new Thread(() -> {
while (this.run) {
if (this.listeners.isEmpty()) {
synchronized (this) {
try {
wait(1000l);
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
List<Gpio> changes = new ArrayList<>();
synchronized (this.listeners) {
for (Gpio gpio : this.listeners.keySet()) {
File file = new File(GPIO_PATH, gpio.getName() + "/value");
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);
changes.add(gpio);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (!changes.isEmpty())
System.out.println("Found " + changes.size() + " GPIO changes.");
for (Gpio gpio : changes) {
synchronized (this.listeners) {
List<GpioSignalListener> listeners = this.listeners.get(gpio);
System.out.println("GPIO " + gpio.getNumber() + " changed to " + gpio.getSignal()
+ ". Notifying " + listeners.size() + " listeners.");
for (GpioSignalListener listener : listeners) {
listener.notify(gpio);
}
}
}
try {
Thread.sleep(200l);
} catch (Exception e) {
e.printStackTrace();
}
}
}
} , "gpio_reader");
this.thread.start();
}
public void stop() {
this.run = false;
this.thread.interrupt();
try {
this.thread.join(5000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public Gpio getGpio(int number, Direction direction) {
Gpio gpio = this.cache.get(number);
if (gpio == null) {
gpio = new Gpio(number, direction);
File file = new File(GPIO_PATH, gpio.getName() + "/direction");
try (BufferedReader fin = new BufferedReader(new FileReader(file))) {
String directionS = fin.readLine();
Direction dir = Direction.getDirection(directionS);
if (dir != direction)
throw new IllegalArgumentException(
"Actual direction of GPIO " + gpio.getNumber() + " is " + dir + " not " + directionS);
} catch (IOException e) {
e.printStackTrace();
}
this.cache.put(number, gpio);
}
return gpio;
}
public void register(Gpio gpio, GpioSignalListener listener) {
if (gpio.getDirection() != Direction.IN)
throw new IllegalArgumentException("For reading the direction must be " + Direction.IN);
synchronized (this.listeners) {
List<GpioSignalListener> listeners = this.listeners.get(gpio);
if (listeners == null) {
listeners = new ArrayList<>();
this.listeners.put(gpio, listeners);
}
listeners.add(listener);
}
synchronized (this) {
notifyAll();
}
}
public void unregister(Gpio gpio, GpioSignalListener listener) {
synchronized (this.listeners) {
List<GpioSignalListener> listeners = this.listeners.get(gpio);
if (listeners == null) {
return;
}
listeners.remove(listener);
if (listeners.isEmpty())
this.listeners.remove(gpio);
}
}
}
public static class Gpio {
private final int number;
private final String name;
private final Direction direction;
private Signal signal;
Gpio(int number, Direction direction) {
this.number = number;
this.direction = direction;
this.name = "gpio" + number;
this.signal = Signal.LOW;
}
public int getNumber() {
return this.number;
}
public String getName() {
return this.name;
}
public Direction getDirection() {
return this.direction;
}
public Signal getSignal() {
return this.signal;
}
public void setSignal(Signal signal) {
this.signal = signal;
}
}
public enum Direction {
IN("in"), OUT("out");
private String direction;
private Direction(String direction) {
this.direction = direction;
}
public String getDirection() {
return this.direction;
}
public static Direction getDirection(String directionS) {
if (directionS.equals(IN.direction))
return IN;
else if (directionS.equals(OUT.direction))
return OUT;
throw new IllegalArgumentException("No direction for value " + directionS);
}
}
public enum Signal {
LOW(0, "0", false, "low"), HIGH(1, "1", true, "high");
private int value;
private String valueS;
private boolean high;
private String signal;
private Signal(int value, String valueS, boolean high, String signal) {
this.value = value;
this.valueS = valueS;
this.high = high;
this.signal = signal;
}
public int getValue() {
return this.value;
}
public String getValueS() {
return this.valueS;
}
public boolean isHigh() {
return this.high;
}
public String getSignal() {
return this.signal;
}
public Signal getOpposite() {
if (this.high)
return LOW;
return HIGH;
}
public static Signal getSignal(int value) {
if (value == 0)
return LOW;
else if (value == 1)
return HIGH;
throw new IllegalArgumentException("No signal for value " + value);
}
public static Signal getSignal(String valueS) {
if (valueS.equals(LOW.valueS))
return LOW;
else if (valueS.equals(HIGH.valueS))
return HIGH;
throw new IllegalArgumentException("No signal for value " + valueS);
}
}
}

View File

@ -0,0 +1,99 @@
package ch.eitchnet.beaglebone;
public enum Pin {
P8_3("P8.3", 1, 6),
P8_4("P8.4", 1, 7),
P8_5("P8.5", 1, 2),
P8_6("P8.6", 1, 3),
P8_7("P8.7", 2, 2),
P8_8("P8.8", 2, 3),
P8_9("P8.9", 2, 2),
P8_10("P8.10", 2, 4),
P8_11("P8.11", 1, 13),
P8_12("P8.12", 1, 12),
P8_13("P8.13", 0, 23),
P8_14("P8.14", 0, 26),
P8_15("P8.15", 1, 15),
P8_16("P8.16", 1, 14),
P8_17("P8.17", 0, 27),
P8_18("P8.18", 2, 1),
P8_19("P8.19", 0, 22),
P8_20("P8.20", 1, 31),
P8_21("P8.21", 1, 30),
P8_22("P8.22", 1, 5),
P8_23("P8.23", 1, 4),
P8_24("P8.24", 1, 1),
P8_25("P8.25", 1, 0),
P8_26("P8.26", 1, 29),
P8_27("P8.27", 2, 22),
P8_28("P8.28", 2, 24),
P8_29("P8.29", 2, 23),
P8_30("P8.30", 2, 25),
P8_31("P8.31", 0, 10),
P8_32("P8.32", 0, 11),
P8_33("P8.33", 0, 9),
P8_34("P8.34", 2, 17),
P8_35("P8.35", 0, 8),
P8_36("P8.36", 2, 16),
P8_37("P8.37", 2, 14),
P8_38("P8.38", 2, 15),
P8_39("P8.39", 2, 12),
P8_40("P8.40", 2, 13),
P8_41("P8.41", 2, 10),
P8_42("P8.42", 2, 11),
P8_43("P8.43", 2, 8),
P8_44("P8.44", 2, 9),
P8_45("P8.45", 2, 6),
P8_46("P8.46", 2, 7),
P9_11("P9.11", 0, 30),
P9_12("P9.12", 1, 28),
P9_13("P9.13", 0, 31),
P9_14("P9.14", 1, 18),
P9_15("P9.15", 1, 16),
P9_16("P9.16", 1, 19),
P9_17("P9.17", 0, 5),
P9_18("P9.18", 0, 4),
P9_19("P9.19", 0, 13),
P9_20("P9.20", 0, 12),
P9_21("P9.21", 0, 3),
P9_22("P9.22", 0, 2),
P9_23("P9.23", 1, 17),
P9_24("P9.24", 0, 15),
P9_25("P9.25", 3, 21),
P9_26("P9.26", 0, 14),
P9_27("P9.27", 3, 19),
P9_28("P9.28", 3, 17),
P9_29("P9.29", 3, 15),
P9_30("P9.30", 3, 16),
P9_31("P9.31", 3, 14),
P9_41("P9.41", 0, 20),
P9_42("P9.42", 0, 7);
private String label;
private int chip;
private int pin;
private Pin(String label, int chip, int pin) {
this.label = label;
this.chip = chip;
this.pin = pin;
}
public String getLabel() {
return this.label;
}
public int getChip() {
return this.chip;
}
public int getPin() {
return this.pin;
}
public int getGpioNr() {
return this.chip * 32 + this.pin;
}
}

View File

@ -0,0 +1,55 @@
package ch.eitchnet.beaglebone;
public enum Signal {
LOW(0, "0", false, "low"), HIGH(1, "1", true, "high");
private int value;
private String valueS;
private boolean high;
private String signal;
private Signal(int value, String valueS, boolean high, String signal) {
this.value = value;
this.valueS = valueS;
this.high = high;
this.signal = signal;
}
public int getValue() {
return this.value;
}
public String getValueS() {
return this.valueS;
}
public boolean isHigh() {
return this.high;
}
public String getSignal() {
return this.signal;
}
public Signal getOpposite() {
if (this.high)
return LOW;
return HIGH;
}
public static Signal getSignal(int value) {
if (value == 0)
return LOW;
else if (value == 1)
return HIGH;
throw new IllegalArgumentException("No signal for value " + value);
}
public static Signal getSignal(String valueS) {
if (valueS.equals(LOW.valueS))
return LOW;
else if (valueS.equals(HIGH.valueS))
return HIGH;
throw new IllegalArgumentException("No signal for value " + valueS);
}
}

View File

@ -0,0 +1,111 @@
package ch.eitchnet.beaglebone;
public class GpioBridgeTest {
static final String GPIO_PATH = "/sys/class/gpio/";
private static Gpio redBtn;
private static Gpio blueBtn;
private static Gpio greenBtn;
private static Gpio green0;
private static Gpio yellow0;
private static Gpio yellow1;
private static Gpio yellow2;
private static Gpio green1;
private static Gpio red0;
private static Thread workThread;
private static volatile boolean doWork;
private static volatile Gpio workBtnPressed;
public static void main(String[] args) throws Exception {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
GpioBridge gpioBridge = new GpioBridge();
redBtn = gpioBridge.getGpio(Pin.P9_11, Direction.IN).setLabel("Red");
blueBtn = gpioBridge.getGpio(Pin.P9_12, Direction.IN).setLabel("Blue");
greenBtn = gpioBridge.getGpio(Pin.P9_13, Direction.IN).setLabel("Green");
green0 = gpioBridge.getGpio(Pin.P9_14, Direction.OUT).setLabel("green0");
yellow0 = gpioBridge.getGpio(Pin.P9_15, Direction.OUT).setLabel("yellow0");
yellow1 = gpioBridge.getGpio(Pin.P9_16, Direction.OUT).setLabel("yellow1");
yellow2 = gpioBridge.getGpio(Pin.P9_17, Direction.OUT).setLabel("yellow2");
green1 = gpioBridge.getGpio(Pin.P9_18, Direction.OUT).setLabel("green1");
red0 = gpioBridge.getGpio(Pin.P9_21, Direction.OUT).setLabel("red0");
GpioSignalListener btnListener = (g) -> {
if (g.getSignal().isHigh())
System.out.println("User pressed " + g.getLabel() + " button.");
else
System.out.println("User released " + g.getLabel() + " button.");
};
gpioBridge.register(redBtn, btnListener);
gpioBridge.register(blueBtn, btnListener);
gpioBridge.register(greenBtn, btnListener);
gpioBridge.register(greenBtn, g -> startWork(gpioBridge));
gpioBridge.register(blueBtn, g -> stopWork(blueBtn, gpioBridge));
gpioBridge.register(redBtn, g -> stopWork(redBtn, gpioBridge));
gpioBridge.start();
}
private static void startWork(GpioBridge gpioBridge) {
doWork = true;
workThread = new Thread(new Runnable() {
@Override
public void run() {
try {
gpioBridge.writeValue(green0, Signal.HIGH);
while (doWork) {
gpioBridge.writeValue(yellow0, yellow0.getSignal().getOpposite());
Thread.sleep(250L);
if (!doWork)
break;
gpioBridge.writeValue(yellow1, yellow1.getSignal().getOpposite());
Thread.sleep(250L);
if (!doWork)
break;
gpioBridge.writeValue(yellow2, yellow2.getSignal().getOpposite());
Thread.sleep(250L);
}
gpioBridge.writeValue(green0, Signal.LOW);
if (workBtnPressed == null) {
System.out.println("Uh-oh, no workBtnPressed set! Something is bad!");
gpioBridge.writeValue(green1, Signal.HIGH);
gpioBridge.writeValue(red0, Signal.HIGH);
} else if (workBtnPressed == blueBtn) {
System.out.println("Work completed successfully!");
gpioBridge.writeValue(green1, Signal.HIGH);
} else {
System.out.println("Work failed!");
gpioBridge.writeValue(red0, Signal.HIGH);
}
} catch (InterruptedException e) {
throw new RuntimeException("Failed to do work.", e);
}
}
}, "work");
workThread.start();
}
private static void stopWork(Gpio btnPressed, GpioBridge gpioBridge) {
workBtnPressed = btnPressed;
doWork = false;
try {
workThread.join(2000l);
} catch (InterruptedException e) {
throw new RuntimeException("Was interrupted while stopping work!", e);
}
}
}