diff --git a/Makefile b/Makefile index 97c9151c2f75e126d5a2f10797cb3605a44e701a..bca70425691042288dc58e33054fcbdf3e607b28 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,10 @@ build/lib/%.o: %.c Makefile | build/lib $(ADAPTORS) $(PLUGINS): $(MAKE) -C $@ +.PHONY: $(PLUGINS) $(ADAPTORS) +$(ADAPTORS) $(PLUGINS): + $(MAKE) -C $@ + .PHONY: TAR TAR: git archive \ @@ -60,6 +64,7 @@ clean: rm -f moberg-*.spec rm -f moberg-*.tar.gz make -C test clean + for d in $(ADAPTORS) ; do make -C $$d clean ; done build/libmoberg.so: build/lib/moberg.o build/libmoberg.so: build/lib/moberg_config.o diff --git a/adaptors/java/Makefile b/adaptors/java/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1687218a0c4e8e721d514409ded5c6953116424f --- /dev/null +++ b/adaptors/java/Makefile @@ -0,0 +1,5 @@ +all: + make -f src/Makefile + +clean: + make -f src/Makefile clean diff --git a/adaptors/java/README b/adaptors/java/README new file mode 100644 index 0000000000000000000000000000000000000000..8dbdf8d69ca1e3611b9eec4b0ca49494e99145cf --- /dev/null +++ b/adaptors/java/README @@ -0,0 +1 @@ +Moberg support for java \ No newline at end of file diff --git a/adaptors/java/src/Makefile b/adaptors/java/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d82b2637be1a974ffecde8b1304299fd25d5dfeb --- /dev/null +++ b/adaptors/java/src/Makefile @@ -0,0 +1,66 @@ +VERSION=1.0 +JARNAME=Moberg +TARFILE=java_se.lth.control.realtime.Moberg-$(VERSION).tar.gz +JNINAME=se_lth_control_realtime_moberg_Moberg + +JAVAH_PATH=$(shell javah -Xbootclasspath/p:build -version >/dev/null 2>&1 && \ + echo -Xbootclasspath/p:build || echo -bootclasspath build) +JNI_INCLUDE=/usr/lib/jvm/java/include/ +CC=gcc +CC_JNI_FLAGS=-Wall -Werror -shared -fPIC \ + -I$(JNI_INCLUDE) -I$(JNI_INCLUDE)/linux -Ibuild \ + -lmoberg +JAVADIR=/tmp +INSTALL_DIR=$(JAVADIR)/$(JARNAME) +JAR_DIR=$(INSTALL_DIR)/jre/lib/ext/ +SO_DIR=$(INSTALL_DIR)/jre/lib/$(shell /bin/sh ./src/getProperty_os_arch) +SRCFILES=README \ + src/Makefile \ + src/getProperty_os_arch \ + $(JNINAME:%=src/%.c) \ + $(JAVAFILES:%=src/%) +JAVAFILES=$(shell find src -name '*.java' | sed -e 's:^src/::g') + +all: JAVAC build/$(JARNAME).jar $(JNINAME:%=build/lib%.so) + +install: install_src install_jar install_so + +install_src: + for f in $(SRCFILES) ; do install -D $$f $(INSTALL_DIR)/$$f ; done + +install_jar: build/$(JARNAME).jar + install -d $(JAR_DIR) + install build/$(JARNAME).jar $(JAR_DIR) + +install_so: $(JNINAME:%=install_%.so) + +install_%.so: build/lib%.so + install -d $(SO_DIR) + install $< $(SO_DIR) + +JAVAC: $(JAVAFILES:%.java=build/%.class) + +build/%.class: src/%.java +# Recompile all javafiles at once (do JIT compilation once) + mkdir -p build + cd src ; javac -d ../build -target 1.5 -source 1.5 $(JAVAFILES) + +build/$(JARNAME).jar: JAVAC + jar -cf $@ \ + -C build se \ + $(SRCFILES) + +build/%.h: $(shell echo $(JNINAME:%=build/%.class) | sed -e 's:_:/:g') +# Too many dependencies, base the ones we need on $* (matches % above) + javah -o $@ -force $(JAVAH_PATH) $(shell echo $* | sed -e s/_/./g) + +build/lib%.so: $(JNINAME:%=build/%.h) $(JNINAME:%=src/%.c) +# Too many dependencies, base the ones we need on $* (matches % above) + $(CC) -o $@ $(CC_JNI_FLAGS) -I. src/$*.c + +clean: + rm -rf build *~ + +TAR: + mkdir -p build + tar -C .. -cvzf build/$(TARFILE) $(SRCFILES:%=$(shell basename $$(pwd))/%) diff --git a/adaptors/java/src/getProperty_os_arch b/adaptors/java/src/getProperty_os_arch new file mode 100755 index 0000000000000000000000000000000000000000..a178e0fd0ed0680f062098222ee31e6ef49c2c4a --- /dev/null +++ b/adaptors/java/src/getProperty_os_arch @@ -0,0 +1,14 @@ +#!/usr/bin/sh + +BASENAME=`basename $0` +cat > ${BASENAME}.java << EOF +public class ${BASENAME} { + + public static void main(String[] args) { + System.out.println(System.getProperty("os.arch")); + } +} +EOF +javac ${BASENAME}.java +java ${BASENAME} +rm ${BASENAME}.java ${BASENAME}.class diff --git a/adaptors/java/src/se/lth/control/realtime/AlreadyAllocatedException.java b/adaptors/java/src/se/lth/control/realtime/AlreadyAllocatedException.java new file mode 100644 index 0000000000000000000000000000000000000000..91e8253fd899ff499153429657e68cffcfbf68a7 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/AlreadyAllocatedException.java @@ -0,0 +1,30 @@ +/** + * se.lth.control.realtime.moberg.AlreadyAllocatedException.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime; + +public class AlreadyAllocatedException extends IOChannelException { + + private static final long serialVersionUID = 1L; + + public AlreadyAllocatedException(String kind, int index) { + super(kind, index, "is already allocated"); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/AnalogIn.java b/adaptors/java/src/se/lth/control/realtime/AnalogIn.java new file mode 100644 index 0000000000000000000000000000000000000000..3fc715f9fefa6e947ee35bb66753a7c9b9050951 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/AnalogIn.java @@ -0,0 +1,42 @@ +/** + * se.lth.control.realtime.AnalogIn.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime; + +import se.lth.control.realtime.moberg.Moberg; + +public class AnalogIn extends IOChannel { + + public AnalogIn(final int index) throws IOChannelException { + super(index); + } + + protected void open() throws IOChannelException { + Moberg.analogInOpen(index); + } + + protected void close() throws IOChannelException { + Moberg.analogInClose(index); + } + + public double get() throws IOChannelException { + return Moberg.analogIn(index); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/AnalogOut.java b/adaptors/java/src/se/lth/control/realtime/AnalogOut.java new file mode 100644 index 0000000000000000000000000000000000000000..4310079bf5560794574a3979aef27abdea591645 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/AnalogOut.java @@ -0,0 +1,46 @@ +/** + * se.lth.control.realtime.AnalogOut.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime; + + +import java.util.BitSet; + +import se.lth.control.realtime.moberg.Moberg; + + +public class AnalogOut extends IOChannel { + + public AnalogOut(int index) throws IOChannelException { + super(index); + } + + public void open() throws IOChannelException { + Moberg.analogOutOpen(index); + } + + public void close() throws IOChannelException { + Moberg.analogOutClose(index); + } + + public void set(double value) throws IOChannelException { + Moberg.analogOut(index, value); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/DigitalIn.java b/adaptors/java/src/se/lth/control/realtime/DigitalIn.java new file mode 100644 index 0000000000000000000000000000000000000000..e34e28bce878997f80d4465d178a7e40bc21adfd --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/DigitalIn.java @@ -0,0 +1,44 @@ +/** + * se.lth.control.realtime.DigitalIn.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime; + +import java.util.BitSet; + +import se.lth.control.realtime.moberg.Moberg; + +public class DigitalIn extends IOChannel { + + public DigitalIn(int index) throws IOChannelException { + super(index); + } + + public void open() throws IOChannelException { + Moberg.digitalInOpen(index); + } + + public void close() throws IOChannelException { + Moberg.digitalInClose(index); + } + + public boolean get() throws IOChannelException { + return Moberg.digitalIn(index); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/DigitalOut.java b/adaptors/java/src/se/lth/control/realtime/DigitalOut.java new file mode 100644 index 0000000000000000000000000000000000000000..a14f189f62d3c0b40eb729bdc7100dcd3bc67f3d --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/DigitalOut.java @@ -0,0 +1,43 @@ +/** + * se.lth.control.realtime.DigitalOut.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime; + +import java.util.BitSet; + +import se.lth.control.realtime.moberg.Moberg; + +public class DigitalOut extends IOChannel { + + public DigitalOut(int index) throws IOChannelException { + super(index); + } + + public void open() throws IOChannelException { + Moberg.digitalOutOpen(index); + } + public void close() throws IOChannelException { + Moberg.digitalOutClose(index); + } + + public void set(boolean value) throws IOChannelException { + Moberg.digitalOut(index, value); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/EncoderIn.java b/adaptors/java/src/se/lth/control/realtime/EncoderIn.java new file mode 100644 index 0000000000000000000000000000000000000000..d1f919d70b805a61845e512614c83b067899b52c --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/EncoderIn.java @@ -0,0 +1,44 @@ +/** + * se.lth.control.realtime.EncoderIn.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime; + +import java.util.BitSet; + +import se.lth.control.realtime.moberg.Moberg; + +public class EncoderIn extends IOChannel { + + public EncoderIn(int index) throws IOChannelException { + super(index); + } + + protected void open() throws IOChannelException { + Moberg.encoderInOpen(index); + } + + protected void close() throws IOChannelException { + Moberg.encoderInClose(index); + } + + public long get() throws IOChannelException { + return Moberg.encoderIn(index); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/IOChannel.java b/adaptors/java/src/se/lth/control/realtime/IOChannel.java new file mode 100644 index 0000000000000000000000000000000000000000..6f83f0ceaccd811c62e326d1db393eabbe0c8179 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/IOChannel.java @@ -0,0 +1,88 @@ +/** + * se.lth.control.realtime.moberg.IOChannel.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * Copyright (C) 2014 Alfred Theorin <alfred.theorin@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime; + +import java.util.HashMap; +import java.util.BitSet; + +public abstract class IOChannel { + + private static HashMap allocations = new HashMap(); + + public final int index; + private BitSet allocation; + private boolean isAllocated = false; + + public IOChannel(int index) throws IOChannelException { + this.index = index; + open(); + allocate(); + } + + private BitSet getAllocation() { + BitSet result = allocation; + if (result == null) { + result = (BitSet)allocations.get(this.getClass().getName()); + if (result == null) { + result = new BitSet(); + allocations.put(this.getClass().getName(), result); + } + } + return result; + } + + private synchronized void allocate() throws IOChannelException { + if (getAllocation().get(index)) { + // Try to free unreferenced channels + System.gc(); + System.runFinalization(); + } + if (getAllocation().get(index)) { + try { + close(); + } catch (IOChannelException e) { + } + throw new AlreadyAllocatedException(this.getClass().getName(), index); + } + getAllocation().set(index); + isAllocated = true; + } + + private synchronized void deallocate() { + if (isAllocated) { + getAllocation().clear(index); + try { + close(); + } catch (IOChannelException e) { + } + isAllocated = false; + } + } + + + protected abstract void open() throws IOChannelException; + protected abstract void close() throws IOChannelException; + + protected void finalize() throws IOChannelException { + deallocate(); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/IOChannelException.java b/adaptors/java/src/se/lth/control/realtime/IOChannelException.java new file mode 100644 index 0000000000000000000000000000000000000000..69ff09630fd1288b978aff56737ccbdf7ddd3d31 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/IOChannelException.java @@ -0,0 +1,32 @@ +/** + * se.lth.control.realtime.IOChannelException.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime; + +import java.io.IOException; + +public class IOChannelException extends IOException { + + private static final long serialVersionUID = 1L; + + public IOChannelException(String kind, int index, String s) { + super(kind + " channel #" + index + " " + s); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/moberg/Moberg.java b/adaptors/java/src/se/lth/control/realtime/moberg/Moberg.java new file mode 100644 index 0000000000000000000000000000000000000000..2a79c03ccf8cade5e6be27dcec2c9008621195c4 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/moberg/Moberg.java @@ -0,0 +1,51 @@ +/** + * se.lth.control.realtime.moberg.Moberg.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime.moberg; + +import java.io.File; + +public class Moberg { + public static native void analogInOpen(int index) throws MobergException; + public static native void analogInClose(int index) throws MobergException; + public static native double analogIn(int index) throws MobergException; + + public static native void analogOutOpen(int index) throws MobergException; + public static native void analogOutClose(int index) throws MobergException; + public static native void analogOut(int index, double value) throws MobergException; + + public static native void digitalInOpen(int index) throws MobergException; + public static native void digitalInClose(int index) throws MobergException; + public static native boolean digitalIn(int index) throws MobergException; + + public static native void digitalOutOpen(int index) throws MobergException; + public static native void digitalOutClose(int index) throws MobergException; + public static native void digitalOut(int index, boolean value) throws MobergException; + + public static native void encoderInOpen(int index) throws MobergException; + public static native void encoderInClose(int index) throws MobergException; + public static native long encoderIn(int index) throws MobergException; + + private static native void Init(); + + static { + System.loadLibrary("se_lth_control_realtime_moberg_Moberg"); + Init(); + } +} diff --git a/adaptors/java/src/se/lth/control/realtime/moberg/MobergConfigurationFileNotFoundError.java b/adaptors/java/src/se/lth/control/realtime/moberg/MobergConfigurationFileNotFoundError.java new file mode 100644 index 0000000000000000000000000000000000000000..7daa0fed48dba5c7c7978d11a43a5aa060bbc7e0 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/moberg/MobergConfigurationFileNotFoundError.java @@ -0,0 +1,31 @@ +/** + * se.lth.control.realtime.moberg.MobergConfigurationFileNotFoundError.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime.moberg; + + +public class MobergConfigurationFileNotFoundError extends Error { + + private static final long serialVersionUID = 1L; + + public MobergConfigurationFileNotFoundError(int index) { + super("Moberg configuration file '/etc/moberg.conf' was not found"); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/moberg/MobergDeviceDoesNotExistException.java b/adaptors/java/src/se/lth/control/realtime/moberg/MobergDeviceDoesNotExistException.java new file mode 100644 index 0000000000000000000000000000000000000000..ffc876f1e0834f0eef05f974327e6d3e11ee7b02 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/moberg/MobergDeviceDoesNotExistException.java @@ -0,0 +1,31 @@ +/** + * se.lth.control.realtime.moberg.MobergDeviceDoesNotExistException.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime.moberg; + + +public class MobergDeviceDoesNotExistException extends MobergException { + + private static final long serialVersionUID = 1L; + + public MobergDeviceDoesNotExistException(int index) { + super(index, "does not exist"); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/moberg/MobergDeviceReadException.java b/adaptors/java/src/se/lth/control/realtime/moberg/MobergDeviceReadException.java new file mode 100644 index 0000000000000000000000000000000000000000..2b9b056b13df7816d71b44daca60f431fad2edff --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/moberg/MobergDeviceReadException.java @@ -0,0 +1,31 @@ +/** + * se.lth.control.realtime.moberg.MobergDeviceReadException.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime.moberg; + + +public class MobergDeviceReadException extends MobergException { + + private static final long serialVersionUID = 1L; + + public MobergDeviceReadException(int index) { + super(index, "read failed"); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/moberg/MobergDeviceWriteException.java b/adaptors/java/src/se/lth/control/realtime/moberg/MobergDeviceWriteException.java new file mode 100644 index 0000000000000000000000000000000000000000..fa24bd15f85c07623fbc7ecb95a606b644397736 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/moberg/MobergDeviceWriteException.java @@ -0,0 +1,31 @@ +/** + * se.lth.control.realtime.moberg.MobergDeviceWriteException.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime.moberg; + + +public class MobergDeviceWriteException extends MobergException { + + private static final long serialVersionUID = 1L; + + public MobergDeviceWriteException(int index) { + super(index, "write failed"); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/moberg/MobergException.java b/adaptors/java/src/se/lth/control/realtime/moberg/MobergException.java new file mode 100644 index 0000000000000000000000000000000000000000..015acd002c10f33bab4ba6efac97b573c2d7e3f3 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/moberg/MobergException.java @@ -0,0 +1,32 @@ +/** + * se.lth.control.realtime.moberg.MobergException.java + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package se.lth.control.realtime.moberg; + +import se.lth.control.realtime.IOChannelException; + +public class MobergException extends IOChannelException { + + private static final long serialVersionUID = 1L; + + public MobergException(int index, String reason) { + super("Moberg", index, reason); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/moberg/MobergNotOpenException.java b/adaptors/java/src/se/lth/control/realtime/moberg/MobergNotOpenException.java new file mode 100644 index 0000000000000000000000000000000000000000..2e23889d1aecc3c1518f61893b951b4c829775d9 --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/moberg/MobergNotOpenException.java @@ -0,0 +1,12 @@ +package se.lth.control.realtime.moberg; + + +public class MobergNotOpenException extends MobergException { + + private static final long serialVersionUID = 1L; + + public MobergNotOpenException(int index) { + super(index, "is not open"); + } + +} diff --git a/adaptors/java/src/se/lth/control/realtime/moberg/MobergRangeNotFoundException.java b/adaptors/java/src/se/lth/control/realtime/moberg/MobergRangeNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..fb4d8d0ac2b3cd1bd3f23a145d51d9dac0b77c2c --- /dev/null +++ b/adaptors/java/src/se/lth/control/realtime/moberg/MobergRangeNotFoundException.java @@ -0,0 +1,12 @@ +package se.lth.control.realtime.moberg; + + +public class MobergRangeNotFoundException extends MobergException { + + private static final long serialVersionUID = 1L; + + public MobergRangeNotFoundException(int index) { + super(index, "has no range information"); + } + +} diff --git a/adaptors/java/src/se_lth_control_realtime_moberg_Moberg.c b/adaptors/java/src/se_lth_control_realtime_moberg_Moberg.c new file mode 100644 index 0000000000000000000000000000000000000000..9363df3b46e52f98835d00e215429764613e5f73 --- /dev/null +++ b/adaptors/java/src/se_lth_control_realtime_moberg_Moberg.c @@ -0,0 +1,413 @@ +/** + * se_lth_control_realtime_moberg_Moberg.c + * + * Copyright (C) 2005-2019 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <jni.h> +#include "se_lth_control_realtime_moberg_Moberg.h" +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <moberg.h> + +static void throwMoberg(JNIEnv *env, int chan, char *exceptionName) +{ + jclass exceptionClass = 0; + jmethodID exceptionClassInit = 0; + jobject exception = 0; + jint result = -1; + + exceptionClass = + (*env)->FindClass(env, exceptionName); + if (exceptionClass) { + exceptionClassInit = (*env)->GetMethodID(env, exceptionClass, + "<init>", "(I)V"); + } + if (exceptionClassInit) { + exception = (*env)->NewObject(env, exceptionClass, exceptionClassInit, + chan); + } + if (exception) { + result = (*env)->Throw(env, exception); + } + if (result != 0) { + fprintf(stderr, "%s: %d\n", exceptionName, chan); + } +} + +static void throwMobergNotOpenException(JNIEnv *env, int chan) +{ + throwMoberg(env, chan, "se/lth/control/realtime/moberg/MobergNotOpenException"); +} + +static void throwMobergDeviceDoesNotExistException(JNIEnv *env, int chan) +{ + throwMoberg(env, chan, "se/lth/control/realtime/moberg/MobergDeviceDoesNotExistException"); +} + +#if 0 +static void throwMobergDeviceReadException(JNIEnv *env, int chan) +{ + throwMoberg(env, chan, "se/lth/control/realtime/moberg/MobergDeviceReadException"); +} + +static void throwMobergDeviceWriteException(JNIEnv *env, int chan) +{ + throwMoberg(env, chan, "se/lth/control/realtime/moberg/MobergDeviceWriteException"); +} + +static void throwMobergRangeNotFoundException(JNIEnv *env, int chan) +{ + throwMoberg(env, chan, "se/lth/control/realtime/moberg/MobergRangeNotFoundException"); +} + +static void throwMobergConfigurationFileNotFoundError(JNIEnv *env) +{ + throwMoberg(env, 0, "se/lth/control/realtime/moberg/MobergConfigurationFileNotFoundError"); +} +#endif + +static struct list { + int capacity; + struct channel { + int count; + union { + struct moberg_analog_in analog_in; + struct moberg_analog_out analog_out; + struct moberg_digital_in digital_in; + struct moberg_digital_out digital_out; + struct moberg_encoder_in encoder_in; + }; + } *channel; +} analog_in = { .capacity=0, .channel=NULL }, + analog_out = { .capacity=0, .channel=NULL }, + digital_in = { .capacity=0, .channel=NULL }, + digital_out = { .capacity=0, .channel=NULL }, + encoder_in = { .capacity=0, .channel=NULL }; + +struct { + int count; + struct moberg *moberg; +} g_moberg = { 0, NULL }; + +static int up() +{ + if (g_moberg.count <= 0) { + g_moberg.moberg = moberg_new(NULL); + } + g_moberg.count++; + return 0; +} + +static int down() +{ + g_moberg.count--; + if (g_moberg.count <= 0) { + moberg_free(g_moberg.moberg); + g_moberg.moberg = NULL; + } + return 0; +} + +static struct channel *channel_get(struct list *list, int index) +{ + if (index < list->capacity && list->channel[index].count > 0) { + return &list->channel[index]; + } + return NULL; +} + +static int channel_set(struct list *list, int index, struct channel channel) +{ + if (list->capacity < index) { + int capacity = index + 1; + void *new = realloc(list->channel, capacity * sizeof(*list->channel)); + if (new) { + void *p = new + list->capacity * sizeof(*list->channel); + memset(p, 0, (capacity - list->capacity) * sizeof(*list->channel)); + list->channel = new; + list->capacity = capacity; + } + } + if (0 <= index && index < list->capacity) { + list->channel[index] = channel; + return 1; + } else { + return 0; + } +} + +static int channel_up(struct list *list, int index) +{ + struct channel *channel = channel_get(list, index); + if (channel) { + up(); + channel->count++; + return 1; + } + return 0; +} + +static struct channel *channel_down(struct list *list, int index) +{ + struct channel *channel = channel_get(list, index); + if (channel) { + down(); + channel->count--; + return channel; + } + return NULL; +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_analogInOpen( + JNIEnv *env, jclass obj, jint index +) +{ + if (! channel_up(&analog_in, index)) { + struct channel channel; + up(); + if (! moberg_analog_in_open(g_moberg.moberg, index, &channel.analog_in)) { + down(); + throwMobergDeviceDoesNotExistException(env, index); + } else { + channel.count = 1; + channel_set(&analog_in, index, channel); + } + } +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_analogInClose( + JNIEnv *env, jclass obj, jint index +) +{ + struct channel *channel = channel_down(&analog_in, index); + if (! channel) { + throwMobergDeviceDoesNotExistException(env, index); + } else if (channel->count == 0) { + moberg_analog_in_close(g_moberg.moberg, index, channel->analog_in); + } +} + + +JNIEXPORT jdouble JNICALL +Java_se_lth_control_realtime_moberg_Moberg_analogIn( + JNIEnv *env, jobject obj, jint index +) +{ + double result = 0.0; + + struct channel *channel = channel_get(&analog_in, index); + if (! channel) { + throwMobergNotOpenException(env, index); + } else { + channel->analog_in.read(channel->analog_in.context, &result); + } + return result; +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_analogOutOpen( + JNIEnv *env, jclass obj, jint index +) +{ + if (! channel_up(&analog_out, index)) { + struct channel channel; + up(); + if (! moberg_analog_out_open(g_moberg.moberg, index, &channel.analog_out)) { + down(); + throwMobergDeviceDoesNotExistException(env, index); + } else { + channel.count = 1; + channel_set(&analog_out, index, channel); + } + } +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_analogOutClose( + JNIEnv *env, jclass obj, jint index +) +{ + struct channel *channel = channel_down(&analog_out, index); + if (! channel) { + throwMobergDeviceDoesNotExistException(env, index); + } else if (channel->count == 0) { + moberg_analog_out_close(g_moberg.moberg, index, channel->analog_out); + } +} + + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_analogOut( + JNIEnv *env, jobject obj, jint index, jdouble value +) +{ + struct channel *channel = channel_get(&analog_out, index); + if (! channel) { + throwMobergNotOpenException(env, index); + } else { + channel->analog_out.write(channel->analog_out.context, value); + } +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_digitalInOpen( + JNIEnv *env, jclass obj, jint index +) +{ + if (! channel_up(&digital_in, index)) { + struct channel channel; + up(); + if (! moberg_digital_in_open(g_moberg.moberg, index, &channel.digital_in)) { + down(); + throwMobergDeviceDoesNotExistException(env, index); + } else { + channel.count = 1; + channel_set(&digital_in, index, channel); + } + } +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_digitalInClose( + JNIEnv *env, jclass obj, jint index +) +{ + struct channel *channel = channel_down(&digital_in, index); + if (! channel) { + throwMobergDeviceDoesNotExistException(env, index); + } else if (channel->count == 0) { + moberg_digital_in_close(g_moberg.moberg, index, channel->digital_in); + } +} + +JNIEXPORT jboolean JNICALL +Java_se_lth_control_realtime_moberg_Moberg_digitalIn( + JNIEnv *env, jobject obj, jint index +) +{ + int result = 0; + + struct channel *channel = channel_get(&digital_in, index); + if (! channel) { + throwMobergNotOpenException(env, index); + } else { + channel->digital_in.read(channel->digital_in.context, &result); + } + return result; +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_digitalOutOpen( + JNIEnv *env, jclass obj, jint index +) +{ + if (! channel_up(&digital_out, index)) { + struct channel channel; + up(); + if (! moberg_digital_out_open(g_moberg.moberg, index, &channel.digital_out)) { + down(); + throwMobergDeviceDoesNotExistException(env, index); + } else { + channel.count = 1; + channel_set(&digital_out, index, channel); + } + } +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_digitalOutClose( + JNIEnv *env, jclass obj, jint index +) +{ + struct channel *channel = channel_down(&digital_out, index); + if (! channel) { + throwMobergDeviceDoesNotExistException(env, index); + } else if (channel->count == 0) { + moberg_digital_out_close(g_moberg.moberg, index, channel->digital_out); + } +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_digitalOut( + JNIEnv *env, jobject obj, jint index, jboolean value +) +{ + struct channel *channel = channel_get(&digital_out, index); + if (! channel) { + throwMobergNotOpenException(env, index); + } else { + channel->digital_out.write(channel->digital_out.context, value); + } +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_encoderInOpen( + JNIEnv *env, jclass obj, jint index +) +{ + if (! channel_up(&encoder_in, index)) { + struct channel channel; + up(); + if (! moberg_encoder_in_open(g_moberg.moberg, index, &channel.encoder_in)) { + down(); + throwMobergDeviceDoesNotExistException(env, index); + } else { + channel.count = 1; + channel_set(&encoder_in, index, channel); + } + } +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_encoderInClose( + JNIEnv *env, jclass obj, jint index +) +{ + struct channel *channel = channel_down(&encoder_in, index); + if (! channel) { + throwMobergDeviceDoesNotExistException(env, index); + } else if (channel->count == 0) { + moberg_encoder_in_close(g_moberg.moberg, index, channel->encoder_in); + } +} + +JNIEXPORT jlong JNICALL +Java_se_lth_control_realtime_moberg_Moberg_encoderIn( + JNIEnv *env, jobject obj, jint index +) +{ + long result = 0; + + struct channel *channel = channel_get(&encoder_in, index); + if (! channel) { + throwMobergNotOpenException(env, index); + } else { + channel->encoder_in.read(channel->encoder_in.context, &result); + } + return result; +} + +JNIEXPORT void JNICALL +Java_se_lth_control_realtime_moberg_Moberg_Init( + JNIEnv *env, jobject obj +) +{ +} diff --git a/adaptors/matlab/Makefile b/adaptors/matlab/Makefile index 561bfd6da50cf58ee9fecd5e3cb29de9a65785bf..d59df2125d6e652de64bd868eb56e0087dcab901 100644 --- a/adaptors/matlab/Makefile +++ b/adaptors/matlab/Makefile @@ -3,6 +3,8 @@ CCFLAGS+=-Wall -Werror -O3 -I. -I../.. -g all: $(LIBRARIES:%=../../build/%) +clean: + ../../build/libmoberg4simulink.so: moberg4simulink.c Makefile $(CC) -o $@ $(CCFLAGS) -L../../build -shared -fPIC -lmoberg $< diff --git a/moberg.spec.template b/moberg.spec.template index 36e54381770aed0586f9e451dfbac82797eef6d7..504f1ae33f9ad2a46f15f320ef8b8c88fcc840d7 100644 --- a/moberg.spec.template +++ b/moberg.spec.template @@ -9,6 +9,7 @@ BuildRequires: gcc BuildRequires: comedilib-devel BuildRequires: valgrind BuildRequires: libxdg-basedir-devel +BuildRequires: java-devel %description Shared library for abstracting physical process I/O (analog, digital @@ -30,12 +31,19 @@ Requires: %{name} = %{version}-%{release} Development files for %{name} %package matlab -Summary: Matlab development files for %{name} +Summary: Matlab support files for %{name} Requires: %{name} = %{version}-%{release} Requires: %{name}-devel = %{version}-%{release} %description matlab -Matlab development files for %{name} +Matlab support files for %{name} + +%package java +Summary: Java support files for %{name} +Requires: %{name} = %{version}-%{release} + +%description java +Java support files for %{name} %prep