diff --git a/README.md b/README.md
index 35ef613..1c2366d 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,9 @@
-# ch.eitchnet.beaglebone
-ch.eitchnet.beaglebone
+# BeagleBoneBlack Java Pin Bridge
+
+## Setup
+
+
+## Build
+
+## Running
+
diff --git a/compile_dts.sh b/compile_dts.sh
new file mode 100755
index 0000000..f62b6f5
--- /dev/null
+++ b/compile_dts.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+SLOTS=/sys/devices/platform/bone_capemgr/slots
+PINS=/sys/kernel/debug/pinctrl/44e10800.pinmux/pins
+
+# http://kilobaser.com/blog/2014-07-28-beaglebone-black-devicetreeoverlay-generator
+# https://github.com/jadonk/validation-scripts/tree/master/test-capemgr
+
+echo "Compiling pinctrl-eitchnet..."
+dtc -O dtb -o pinctrl-eitchnet-00A0.dtbo -b 0 -@ pinctrl-eitchnet.dts
+
+echo
+echo "Install with:"
+echo "$ sudo cp pinctrl-eitchnet-00A0.dtbo /lib/firmware/"
+echo "$ echo pinctrl-eitchnet | sudo tee $SLOTS"
+
+echo
+echo "Remove with:"
+echo "$ cat $SLOTS | grep pinctrl-eitchnet"
+echo "15: P-O-L- 0 Override Board Name,00A0,Override Manuf,pinctrl-eitchnet"
+echo "$ echo -15 | sudo tee $SLOTS"
+
+exit 0
\ No newline at end of file
diff --git a/exportPins.sh b/exportPins.sh
new file mode 100755
index 0000000..5c727c7
--- /dev/null
+++ b/exportPins.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+set -e
+
+echo -e "Exporting Pins to userspace..."
+
+if [ "$(whoami)" != "root" ] ; then
+ echo "Please run as root!"
+ exit 1
+fi
+
+GPIO_DIR="/sys/class/gpio"
+USER="ubuntu"
+
+if [ ! -d "${GPIO_DIR}" ] ; then
+ echo -e "ERROR: Missing GPIO directory ${GPIO_DIR}"
+fi
+
+cd "${GPIO_DIR}"
+
+function export_pin() {
+ direction="$1"
+ gpio_no="$2"
+ gpio_name="gpio${gpio_no}"
+
+ echo "Setting direction of ${gpio_name} to ${direction}..."
+
+ if [ ! -d "${gpio_name}" ] ; then
+ echo "${gpio_no}" > export
+ else
+ echo "GPIO ${gpio_no} was already exported, only verifying direction..."
+ fi
+
+ echo "${direction}" > "${gpio_name}/direction"
+
+ if [ "${direction}" == "in" ] ; then
+ echo "Current value of ${gpio_name} is $(cat ${gpio_name}/value)"
+ else
+ echo "Setting value of ${gpio_name} to 0"
+ fi
+
+ chown ${USER} "${gpio_name}/value"
+}
+
+##
+## IN Pins
+##
+
+echo
+echo "Setting input pins..."
+
+# P8.7
+export_pin in 66
+# P8.8
+export_pin in 67
+# P8.9
+export_pin in 69
+
+##
+## Out pins
+##
+
+echo
+echo "Setting output pins..."
+
+# P8.10
+export_pin out 68
+# P8.11
+export_pin out 45
+# P8.12
+export_pin out 44
+# P8.14
+export_pin out 26
+# P8.15
+export_pin out 47
+# P8.16
+export_pin out 46
+
+echo -e "Done."
+
+exit 0
\ No newline at end of file
diff --git a/pinctrl-eitchnet.dts b/pinctrl-eitchnet.dts
new file mode 100644
index 0000000..cf9df5c
--- /dev/null
+++ b/pinctrl-eitchnet.dts
@@ -0,0 +1,45 @@
+/dts-v1/;
+/plugin/;
+
+/{
+ compatible = "ti,beaglebone", "ti,beaglebone-black";
+
+ /* identification */
+ part-number = "pinctrl-eitchnet";
+
+ /* https://github.com/derekmolloy/boneDeviceTree/blob/master/docs/BeagleboneBlackP9HeaderTable.pdf */
+ fragment@0 {
+ target = <&am33xx_pinmux>;
+ __overlay__ {
+ pinctrl_eitchnet: pinmux_pinctrl_eitchnet {
+ pinctrl-single,pins = <
+
+ /* 0x27 INPUT */
+ 0x090 0x2f /* P8_07 66 INPUT MODE7 none */
+ 0x094 0x2f /* P8_08 67 INPUT MODE7 none */
+ 0x09c 0x2f /* P8_09 69 INPUT MODE7 none */
+
+ /* 0x07 OUTPUT */
+ 0x098 0x0f /* P8_10 68 OUTPUT MODE7 none */
+ 0x034 0x0f /* P8_11 45 OUTPUT MODE7 none */
+ 0x030 0x0f /* P8_12 44 OUTPUT MODE7 none */
+ 0x028 0x0f /* P8_14 26 OUTPUT MODE7 none */
+ 0x03c 0x0f /* P8_15 47 OUTPUT MODE7 none */
+ 0x038 0x0f /* P8_16 46 OUTPUT MODE7 none */
+ >;
+ };
+ };
+ };
+
+ fragment@1 {
+ target = <&ocp>;
+ __overlay__ {
+ pinctrl_eitchnet_pinmux {
+ compatible = "bone-pinmux-helper";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_eitchnet>;
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/pinctrl-test-0.dts b/pinctrl-test-0.dts
new file mode 100644
index 0000000..191158e
--- /dev/null
+++ b/pinctrl-test-0.dts
@@ -0,0 +1,33 @@
+/dts-v1/;
+/plugin/;
+
+/{
+ compatible = "ti,beaglebone", "ti,beaglebone-black";
+
+ /* identification */
+ part-number = "pinctrl-test-0";
+
+ /* https://github.com/derekmolloy/boneDeviceTree/blob/master/docs/BeagleboneBlackP9HeaderTable.pdf */
+ fragment@0 {
+ target = <&am33xx_pinmux>;
+ __overlay__ {
+ pinctrl_test: pinctrl_test_0_pins {
+ pinctrl-single,pins = <
+ 0x164 0x00 /* P9_42 muxRegOffset, OUTPUT | MODE0 */
+ >;
+ };
+ };
+ };
+
+ fragment@1 {
+ target = <&ocp>;
+ __overlay__ {
+ test_helper: helper {
+ compatible = "bone-pinmux-helper";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_test>;
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/pom.xml b/pom.xml
index d33480f..497e9ff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,27 +1,63 @@
- 4.0.0
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
- ch.eitchnet
- ch.eitchnet.beaglebone
- 0.1.0-SNAPSHOT
- jar
+ ch.eitchnet
+ ch.eitchnet.beaglebone
+ 0.1.0-SNAPSHOT
+ jar
- ch.eitchnet.beaglebone
- http://maven.apache.org
+ ch.eitchnet.beaglebone
+ http://maven.apache.org
-
- UTF-8
- 1.8
- 1.8
-
-
-
-
- junit
- junit
- 4.12
- test
-
-
+
+ UTF-8
+ 1.8
+ 1.8
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+
+ BeagleBone
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.6
+
+
+
+ true
+
+ ch.eitchnet.beaglebone.GpioBridgeTest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/setOutPin.sh b/setOutPin.sh
new file mode 100755
index 0000000..7e2f8d4
--- /dev/null
+++ b/setOutPin.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+set -e
+
+GPIO_DIR="/sys/class/gpio"
+
+if [ ! -d "${GPIO_DIR}" ] ; then
+ echo -e "ERROR: Missing GPIO directory ${GPIO_DIR}"
+fi
+
+cd "${GPIO_DIR}"
+
+if [ "$#" != 2 ] ; then
+ echo "Usage: $0 "
+ exit 1
+fi
+
+gpio_no="$1"
+gpio_name="gpio${gpio_no}"
+value="$2"
+
+direction="$(cat ${gpio_name}/direction)"
+if [ "${direction}" != "out" ] ; then
+ echo "Current direction is not in, can't set output pin!"
+fi
+
+echo "Setting output pin ${gpio_name} to value ${value}"
+echo ${value} | sudo tee "${GPIO_DIR}/${gpio_name}/value"
+
+exit 0
diff --git a/src/main/java/ch/eitchnet/beaglebone/Gpio.java b/src/main/java/ch/eitchnet/beaglebone/Gpio.java
index 552d8a7..6a53807 100644
--- a/src/main/java/ch/eitchnet/beaglebone/Gpio.java
+++ b/src/main/java/ch/eitchnet/beaglebone/Gpio.java
@@ -3,7 +3,7 @@ package ch.eitchnet.beaglebone;
public class Gpio {
private final Pin pin;
- private final String name;
+ private final String kernelName;
private final Direction direction;
private String label;
private Signal signal;
@@ -11,8 +11,8 @@ public class Gpio {
public Gpio(Pin pin, Direction direction) {
this.pin = pin;
this.direction = direction;
- this.name = "gpio" + pin.getGpioNr();
- this.label = name;
+ this.kernelName = "gpio" + pin.getGpioNr();
+ this.label = kernelName;
this.signal = Signal.LOW;
}
@@ -20,8 +20,8 @@ public class Gpio {
return this.pin;
}
- public String getName() {
- return this.name;
+ public String getKernelName() {
+ return this.kernelName;
}
public Gpio setLabel(String label) {
@@ -45,4 +45,9 @@ public class Gpio {
this.signal = signal;
return this;
}
+
+ @Override
+ public String toString() {
+ return this.pin.toString();
+ }
}
\ 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 3a14dea..09ba05c 100644
--- a/src/main/java/ch/eitchnet/beaglebone/GpioBridge.java
+++ b/src/main/java/ch/eitchnet/beaglebone/GpioBridge.java
@@ -2,6 +2,7 @@ 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;
@@ -23,12 +24,20 @@ public class GpioBridge {
this.listeners = Collections.synchronizedMap(new HashMap<>());
}
- public void writeValue(Gpio gpio, Signal signal) {
+ private File getGpioValuePath(Gpio gpio) {
+ return new File(GpioBridgeTest.GPIO_PATH, gpio.getKernelName() + "/value");
+ }
+
+ private File getGpioDirectionPath(Gpio gpio) {
+ return new File(GpioBridgeTest.GPIO_PATH, gpio.getKernelName() + "/direction");
+ }
+
+ public void writeValue(Gpio gpio, Signal signal) throws GpioException {
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");
+ File file = getGpioValuePath(gpio);
try (FileOutputStream out = new FileOutputStream(file)) {
out.write(signal.getValueS().getBytes());
@@ -37,12 +46,35 @@ public class GpioBridge {
gpio.setSignal(signal);
} catch (Exception e) {
- e.printStackTrace();
+ throw new GpioException("Failed to write GPIO " + gpio + " with signal " + signal, e);
}
System.out.println("Set GPIO " + gpio.getPin() + " signal to " + gpio.getSignal());
}
+ public Signal readValue(Gpio gpio) throws GpioException {
+
+ synchronized (gpio) {
+
+ if (gpio.getDirection() != Direction.IN)
+ throw new IllegalArgumentException("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);
+ }
+ }
+ }
+
public void start() {
this.run = true;
@@ -52,8 +84,10 @@ public class GpioBridge {
synchronized (this) {
try {
wait(1000l);
- } catch (Exception e) {
- e.printStackTrace();
+ } catch (InterruptedException e) {
+ System.out.println("Was interrupted. Stopping thread.");
+ this.run = false;
+ break;
}
}
} else {
@@ -62,19 +96,18 @@ public class GpioBridge {
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);
+ try {
+ synchronized (gpio) {
+ Signal currentSignal = gpio.getSignal();
+ Signal newSignal = readValue(gpio);
+ if (currentSignal != newSignal)
+ changes.add(gpio);
}
-
} catch (Exception e) {
+ System.out.println("Failed to read GPIO " + gpio + " due to:");
e.printStackTrace();
+ this.run = false;
+ break;
}
}
}
@@ -89,20 +122,28 @@ public class GpioBridge {
+ ". Notifying " + listeners.size() + " listeners.");
for (GpioSignalListener listener : listeners) {
- listener.notify(gpio);
+ try {
+ listener.notify(gpio);
+ } catch (Exception e) {
+ System.out.println("Failed to update listener " + listener + " due to:");
+ e.printStackTrace();
+ }
}
}
}
try {
Thread.sleep(200l);
- } catch (Exception e) {
- e.printStackTrace();
+ } catch (InterruptedException e) {
+ System.out.println("Was interrupted. Stopping thread.");
+ this.run = false;
+ break;
}
}
}
} , "gpio_reader");
this.thread.start();
+ System.out.println("Started GPIO bridge.");
}
public void stop() {
@@ -111,38 +152,66 @@ public class GpioBridge {
try {
this.thread.join(5000l);
} catch (InterruptedException e) {
- e.printStackTrace();
+ System.out.println("Was interrupted while waiting for thread to stop?!");
}
}
- public Gpio getGpio(Pin pin, Direction direction) {
+ public synchronized Gpio getGpio(Pin pin, Direction direction) throws GpioException {
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))) {
+ // validate direction
+ validateDirection(pin, direction, gpio);
- 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();
- }
+ // validate file permissions
+ validateFilePermissions(direction, gpio);
this.cache.put(pin, gpio);
+ System.out.println("Initialized pin " + pin + " with direction " + direction + ".");
}
return gpio;
}
- public void register(Gpio gpio, GpioSignalListener listener) {
+ private void validateDirection(Pin pin, Direction direction, Gpio gpio) throws GpioException {
+ File file = getGpioDirectionPath(gpio);
+ try (BufferedReader fin = new BufferedReader(new FileReader(file))) {
+
+ String directionS = fin.readLine();
+ Direction dir = Direction.getDirection(directionS);
+ if (dir != direction)
+ throw new GpioException(
+ "Actual direction of GPIO " + gpio.getPin() + " 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);
+ }
+ }
+
+ private void validateFilePermissions(Direction direction, Gpio gpio) throws GpioException {
+ File gpioValuePath = getGpioValuePath(gpio);
+ if (direction == Direction.IN) {
+ if (!gpioValuePath.canRead())
+ throw new GpioException("GPIO " + gpio + " has direction " + direction
+ + " and is not readable. Are the file permissions ok?");
+
+ } else if (direction == Direction.OUT) {
+ if (!gpioValuePath.canWrite())
+ throw new GpioException("GPIO " + gpio + " has direction " + direction
+ + " and is not writable. Are the file permissions ok?");
+ } else {
+ throw new RuntimeException("Unhandled Direction " + direction);
+ }
+ }
+
+ public void register(Gpio gpio, GpioSignalListener listener) throws GpioException {
if (gpio.getDirection() != Direction.IN)
- throw new IllegalArgumentException("For reading the direction must be " + Direction.IN);
+ throw new GpioException("For reading the direction must be " + Direction.IN);
synchronized (this.listeners) {
List listeners = this.listeners.get(gpio);
diff --git a/src/main/java/ch/eitchnet/beaglebone/GpioException.java b/src/main/java/ch/eitchnet/beaglebone/GpioException.java
new file mode 100644
index 0000000..d1dc730
--- /dev/null
+++ b/src/main/java/ch/eitchnet/beaglebone/GpioException.java
@@ -0,0 +1,14 @@
+package ch.eitchnet.beaglebone;
+
+public class GpioException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public GpioException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public GpioException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ch/eitchnet/beaglebone/GpioSignalListener.java b/src/main/java/ch/eitchnet/beaglebone/GpioSignalListener.java
index d8722ca..c997ce5 100644
--- a/src/main/java/ch/eitchnet/beaglebone/GpioSignalListener.java
+++ b/src/main/java/ch/eitchnet/beaglebone/GpioSignalListener.java
@@ -1,5 +1,5 @@
package ch.eitchnet.beaglebone;
public interface GpioSignalListener {
- public void notify(Gpio gpio);
+ public void notify(Gpio gpio) throws Exception;
}
\ No newline at end of file
diff --git a/src/main/java/ch/eitchnet/beaglebone/Pin.java b/src/main/java/ch/eitchnet/beaglebone/Pin.java
index 338950e..998b398 100644
--- a/src/main/java/ch/eitchnet/beaglebone/Pin.java
+++ b/src/main/java/ch/eitchnet/beaglebone/Pin.java
@@ -2,13 +2,13 @@ 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_03("P8.03", 1, 6),
+ P8_04("P8.04", 1, 7),
+ P8_05("P8.05", 1, 2),
+ P8_06("P8.06", 1, 3),
+ P8_07("P8.07", 2, 2),
+ P8_08("P8.08", 2, 3),
+ P8_09("P8.09", 2, 5),
P8_10("P8.10", 2, 4),
P8_11("P8.11", 1, 13),
P8_12("P8.12", 1, 12),
@@ -68,8 +68,10 @@ public enum Pin {
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);
+ P9_41A("P9.41A", 0, 20),
+ P9_41B("P9.41B", 3, 20),
+ P9_42A("P9.42A", 0, 7),
+ P9_42B("P9.42B", 3, 18);
private String label;
private int chip;
@@ -96,4 +98,9 @@ public enum Pin {
public int getGpioNr() {
return this.chip * 32 + this.pin;
}
+
+ @Override
+ public String toString() {
+ return this.label;
+ }
}
diff --git a/src/main/java/ch/eitchnet/beaglebone/Signal.java b/src/main/java/ch/eitchnet/beaglebone/Signal.java
index 2e9d969..6708964 100644
--- a/src/main/java/ch/eitchnet/beaglebone/Signal.java
+++ b/src/main/java/ch/eitchnet/beaglebone/Signal.java
@@ -52,4 +52,9 @@ public enum Signal {
return HIGH;
throw new IllegalArgumentException("No signal for value " + valueS);
}
+
+ @Override
+ public String toString() {
+ return name();
+ }
}
\ No newline at end of file