diff --git a/bom/openhab-core/pom.xml b/bom/openhab-core/pom.xml index 1bea7c150d4..df656f34fe2 100644 --- a/bom/openhab-core/pom.xml +++ b/bom/openhab-core/pom.xml @@ -262,6 +262,12 @@ ${project.version} compile + + org.openhab.core.bundles + org.openhab.core.io.transport.serial.purejavacomm + ${project.version} + compile + org.openhab.core.bundles org.openhab.core.io.transport.serial.rxtx diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/.classpath b/bundles/org.openhab.core.io.transport.serial.purejavacomm/.classpath new file mode 100644 index 00000000000..af4894f1819 --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/.classpath @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/.project b/bundles/org.openhab.core.io.transport.serial.purejavacomm/.project new file mode 100644 index 00000000000..0efc39652e1 --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/.project @@ -0,0 +1,34 @@ + + + org.openhab.core.io.transport.serial.javacomm + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + + + 1684860371393 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/.vscode/launch.json b/bundles/org.openhab.core.io.transport.serial.purejavacomm/.vscode/launch.json new file mode 100644 index 00000000000..8ea10f1d52b --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Debug (Attach) - openHAB", + "request": "attach", + "hostName": "localhost", + "port": 5005, + "preLaunchTask": "Build" + } + ] +} \ No newline at end of file diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/.vscode/settings.json b/bundles/org.openhab.core.io.transport.serial.purejavacomm/.vscode/settings.json new file mode 100644 index 00000000000..e012065081a --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "java.compile.nullAnalysis.mode": "automatic", + "java.configuration.updateBuildConfiguration": "interactive" +} \ No newline at end of file diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/.vscode/tasks.json b/bundles/org.openhab.core.io.transport.serial.purejavacomm/.vscode/tasks.json new file mode 100644 index 00000000000..4dfcef4ff1d --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/.vscode/tasks.json @@ -0,0 +1,149 @@ +{ + "version": "2.0.0", + "options": { + "env": { + "openhab_home": "/Users/kgoderis/Development/openhab-runtime", + "openhab_runtime": "/Users/kgoderis/Development/openhab-runtime/runtime", + "openhab_addons": "/Users/kgoderis/Development/openhab-runtime/addons", + "openhab_logs": "/Users/kgoderis/Development/openhab-runtime/userdata/logs", + "dist" : "org.openhab.core.io.transport.serial.purejavacomm-4.0.0-SNAPSHOT.jar" + } + }, + "tasks": [ + { + "label": "Start openHAB (Debug)", + "type": "shell", + "isBackground": true, + "command": "$openhab_home/start.sh debug", + "windows": { + "command": "& $env:openhab_home/start.bat debug" + }, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + }, + { + "label": "Stop openHAB", + "type": "shell", + "command": "$openhab_runtime/bin/stop", + "windows": { + "command": "& $env:openhab_runtime/bin/stop.bat" + }, + "problemMatcher": [] + }, + { + "label": "mvn Compile (Release)", + "type": "shell", + "command": "mvn", + "args": [ + "clean", + "install" + ], + "problemMatcher": [] + }, + { + "label": "mvn Compile (Online)", + "type": "shell", + "command": "mvn", + "args": [ + "clean", + "install", + "-DskipChecks" + ], + "problemMatcher": [] + }, + { + "label": "mvn Compile (Offline)", + "type": "shell", + "command": "mvn", + "args": [ + "-o", + "clean", + "install", + "-DskipChecks" + ], + "problemMatcher": [] + }, + { + "label": "Copy Distribution to Addons", + "type": "shell", + "command": "cp", + "args": [ + "${workspaceFolder}/target/$dist", + "$openhab_addons" + ], + "windows": { + "command": "copy", + "args": [ + "${workspaceFolder}/target/$env:dist", + "$env:openhab_addons" + ] + }, + "dependsOn": [ + "mvn Compile (Offline)" + ], + "problemMatcher": [] + }, + { + "label": "Build", + "dependsOn": [ + "Copy Distribution to Addons" + ], + "problemMatcher": [] + }, + { + "label": "Tail events.log", + "type": "shell", + "command": "tail", + "args": [ + "-n", + "50", + "-F", + "$openhab_logs/events.log" + ], + "windows": { + "command": "Get-Content", + "args": [ + "-Last", + "50", + "-Path", + "$env:openhab_logs/events.log", + "-Wait" + ] + }, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + }, + { + "label": "Tail openhab.log", + "type": "shell", + "command": "tail", + "args": [ + "-n", + "50", + "-F", + "$openhab_logs/openhab.log" + ], + "windows": { + "command": "Get-Content", + "args": [ + "-Last", + "50", + "-Path", + "$env:openhab_logs/openhab.log", + "-Wait" + ] + }, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/NOTICE b/bundles/org.openhab.core.io.transport.serial.purejavacomm/NOTICE new file mode 100644 index 00000000000..6c17d0d8a45 --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/NOTICE @@ -0,0 +1,14 @@ +This content is produced and maintained by the openHAB project. + +* Project home: https://www.openhab.org + +== Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License 2.0 which is available at +https://www.eclipse.org/legal/epl-2.0/. + +== Source Code + +https://github.com/openhab/openhab-core + diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/pom.xml b/bundles/org.openhab.core.io.transport.serial.purejavacomm/pom.xml new file mode 100644 index 00000000000..125325fe891 --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + + org.openhab.core.bundles + org.openhab.core.reactor.bundles + 4.0.0-SNAPSHOT + + + org.openhab.core.io.transport.serial.purejavacomm + + openHAB Core :: Bundles :: Serial Transport for Pure Java Communications API + + + + org.openhab.core.bundles + org.openhab.core.io.transport.serial + ${project.version} + + + org.opensmarthouse + purejavacomm + 1.0.5 + + + diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/PureJavaCommPortProvider.java b/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/PureJavaCommPortProvider.java new file mode 100644 index 00000000000..c4514c199e5 --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/PureJavaCommPortProvider.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.io.transport.serial.internal; + +import java.net.URI; +import java.util.Enumeration; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Consumer; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.io.transport.serial.ProtocolType; +import org.openhab.core.io.transport.serial.ProtocolType.PathType; +import org.openhab.core.io.transport.serial.SerialPortIdentifier; +import org.openhab.core.io.transport.serial.SerialPortProvider; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import purejavacomm.CommPortIdentifier; +import purejavacomm.NoSuchPortException; + +/** + * + * @author Łukasz Dywicki - Initial contribution + * @author Karel Goderis - added further methods + */ +@NonNullByDefault +@Component(service = SerialPortProvider.class) +public class PureJavaCommPortProvider implements SerialPortProvider { + + private final Logger logger = LoggerFactory.getLogger(PureJavaCommPortProvider.class); + + @Override + public @Nullable SerialPortIdentifier getPortIdentifier(URI port) { + CommPortIdentifier ident = null; + try { + ident = CommPortIdentifier.getPortIdentifier(port.getPath()); + } catch (NoSuchPortException e) { + logger.debug("No SerialPortIdentifier found for: {}", port.getPath()); + return null; + } + return new SerialPortIdentifierImpl(ident); + } + + @Override + public Stream getAcceptedProtocols() { + return Stream.of(new ProtocolType(PathType.LOCAL, "purejavacomm")); + } + + @Override + public Stream getSerialPortIdentifiers() { + @SuppressWarnings("unchecked") + final Enumeration ids = CommPortIdentifier.getPortIdentifiers(); + return StreamSupport.stream(new SplitIteratorForEnumeration<>(ids), false) + .filter(id -> id.getPortType() == CommPortIdentifier.PORT_SERIAL) + .map(sid -> new SerialPortIdentifierImpl(sid)); + } + + private static class SplitIteratorForEnumeration extends Spliterators.AbstractSpliterator { + private final Enumeration e; + + public SplitIteratorForEnumeration(final Enumeration e) { + super(Long.MAX_VALUE, Spliterator.ORDERED); + this.e = e; + } + + @Override + @NonNullByDefault({}) + public boolean tryAdvance(Consumer action) { + if (e.hasMoreElements()) { + action.accept(e.nextElement()); + return true; + } + return false; + } + + @Override + @NonNullByDefault({}) + public void forEachRemaining(Consumer action) { + while (e.hasMoreElements()) { + action.accept(e.nextElement()); + } + } + } +} diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/SerialPortEventImpl.java b/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/SerialPortEventImpl.java new file mode 100644 index 00000000000..e2c6ad6dd25 --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/SerialPortEventImpl.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.io.transport.serial.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.io.transport.serial.SerialPortEvent; + +/** + * Specific serial port event implementation. + * + * @author Łukasz Dywicki - Initial contribution + * @author Karel Goderis - added further methods + */ +@NonNullByDefault +public class SerialPortEventImpl implements SerialPortEvent { + + private final purejavacomm.SerialPortEvent event; + + /** + * Constructor. + * + * @param event the underlying event implementation + */ + public SerialPortEventImpl(final purejavacomm.SerialPortEvent event) { + this.event = event; + } + + @Override + public int getEventType() { + return event.getEventType(); + } + + @Override + public boolean getNewValue() { + return event.getNewValue(); + } +} diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/SerialPortIdentifierImpl.java b/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/SerialPortIdentifierImpl.java new file mode 100644 index 00000000000..45f024ab427 --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/SerialPortIdentifierImpl.java @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.io.transport.serial.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.io.transport.serial.PortInUseException; +import org.openhab.core.io.transport.serial.SerialPort; +import org.openhab.core.io.transport.serial.SerialPortIdentifier; + +import purejavacomm.CommPortIdentifier; + +/** + * Specific serial port identifier implementation. + * + * @author Łukasz Dywicki - Initial contribution + * @author Karel Goderis - added further methods + */ +@NonNullByDefault +public class SerialPortIdentifierImpl implements SerialPortIdentifier { + + final CommPortIdentifier id; + + /** + * Constructor. + * + * @param id the underlying comm port identifier implementation + */ + public SerialPortIdentifierImpl(final CommPortIdentifier id) { + this.id = id; + } + + @Override + public String getName() { + final String name = id.getName(); + return name != null ? name : ""; + } + + @Override + public SerialPort open(String owner, int timeout) throws PortInUseException { + + try { + return new SerialPortImpl((purejavacomm.SerialPort) id.open(owner, timeout)); + } catch (purejavacomm.PortInUseException e) { + String message = e.getMessage(); + if (message != null) { + throw new PortInUseException(message, e); + } else { + throw new PortInUseException(e); + } + } + } + + @Override + public boolean isCurrentlyOwned() { + return id.isCurrentlyOwned(); + } + + @Override + public @Nullable String getCurrentOwner() { + return id.getCurrentOwner(); + } + + public String toString() { + return getName() + " (pure java comm)"; + } +} diff --git a/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/SerialPortImpl.java b/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/SerialPortImpl.java new file mode 100644 index 00000000000..bbdff194eeb --- /dev/null +++ b/bundles/org.openhab.core.io.transport.serial.purejavacomm/src/main/java/org/openhab/core/io/transport/serial/internal/SerialPortImpl.java @@ -0,0 +1,260 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.io.transport.serial.internal; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.TooManyListenersException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.io.transport.serial.SerialPort; +import org.openhab.core.io.transport.serial.SerialPortEventListener; +import org.openhab.core.io.transport.serial.UnsupportedCommOperationException; + +import purejavacomm.SerialPortEvent; + +/** + * Specific serial port implementation. + * + * @author Łukasz Dywicki - Initial contribution + * @author Karel Goderis - added further methods + */ +@NonNullByDefault +public class SerialPortImpl implements SerialPort { + + private final purejavacomm.SerialPort sp; + + /** + * Constructor. + * + * @param sp the underlying serial port implementation + */ + public SerialPortImpl(final purejavacomm.SerialPort sp) { + this.sp = sp; + } + + @Override + public void close() { + sp.close(); + } + + @Override + public void setSerialPortParams(int baudrate, int dataBits, int stopBits, int parity) + throws UnsupportedCommOperationException { + try { + sp.setSerialPortParams(baudrate, dataBits, stopBits, parity); + } catch (purejavacomm.UnsupportedCommOperationException ex) { + throw new UnsupportedCommOperationException(ex); + } + } + + @Override + public @Nullable InputStream getInputStream() throws IOException { + return sp.getInputStream(); + } + + @Override + public @Nullable OutputStream getOutputStream() throws IOException { + return sp.getOutputStream(); + } + + @Override + public void addEventListener(SerialPortEventListener listener) throws TooManyListenersException { + sp.addEventListener(new purejavacomm.SerialPortEventListener() { + @Override + public void serialEvent(final @Nullable SerialPortEvent event) { + if (event == null) { + return; + } + listener.serialEvent(new org.openhab.core.io.transport.serial.SerialPortEvent() { + @Override + public int getEventType() { + return event.getEventType(); + } + + @Override + public boolean getNewValue() { + return event.getNewValue(); + } + }); + } + }); + } + + @Override + public void removeEventListener() { + sp.removeEventListener(); + } + + @Override + public void notifyOnDataAvailable(boolean enable) { + sp.notifyOnDataAvailable(enable); + } + + @Override + public void notifyOnBreakInterrupt(boolean enable) { + sp.notifyOnBreakInterrupt(enable); + } + + @Override + public void notifyOnFramingError(boolean enable) { + sp.notifyOnFramingError(enable); + } + + @Override + public void notifyOnOverrunError(boolean enable) { + sp.notifyOnOverrunError(enable); + } + + @Override + public void notifyOnParityError(boolean enable) { + sp.notifyOnParityError(enable); + } + + @Override + public void enableReceiveTimeout(int timeout) throws UnsupportedCommOperationException { + if (timeout < 0) { + throw new IllegalArgumentException(String.format("timeout must be non negative (is: %d)", timeout)); + } + try { + sp.enableReceiveTimeout(timeout); + } catch (purejavacomm.UnsupportedCommOperationException ex) { + throw new UnsupportedCommOperationException(ex); + } + } + + @Override + public void disableReceiveTimeout() { + sp.disableReceiveTimeout(); + } + + @Override + public String getName() { + return sp.getName(); + } + + @Override + public void setFlowControlMode(int flowcontrolRtsctsOut) throws UnsupportedCommOperationException { + try { + sp.setFlowControlMode(flowcontrolRtsctsOut); + } catch (purejavacomm.UnsupportedCommOperationException e) { + throw new UnsupportedCommOperationException(e); + } + } + + @Override + public void enableReceiveThreshold(int i) throws UnsupportedCommOperationException { + try { + sp.enableReceiveThreshold(i); + } catch (purejavacomm.UnsupportedCommOperationException e) { + throw new UnsupportedCommOperationException(e); + } + } + + @Override + public int getBaudRate() { + return sp.getBaudRate(); + } + + @Override + public int getDataBits() { + return sp.getDataBits(); + } + + @Override + public int getStopBits() { + return sp.getStopBits(); + } + + @Override + public int getParity() { + return sp.getParity(); + } + + @Override + public void notifyOnOutputEmpty(boolean enable) { + sp.notifyOnOutputEmpty(enable); + } + + @Override + public void notifyOnCTS(boolean enable) { + sp.notifyOnCTS(enable); + } + + @Override + public void notifyOnDSR(boolean enable) { + sp.notifyOnDSR(enable); + } + + @Override + public void notifyOnRingIndicator(boolean enable) { + sp.notifyOnRingIndicator(enable); + } + + @Override + public void notifyOnCarrierDetect(boolean enable) { + sp.notifyOnCarrierDetect(enable); + } + + @Override + public int getFlowControlMode() { + return getFlowControlMode(); + } + + @Override + public void setRTS(boolean enable) { + sp.setRTS(enable); + } + + @Override + public boolean isRTS() { + return sp.isRTS(); + } + + @Override + public void setDTR(boolean state) { + sp.setDTR(state); + } + + @Override + public boolean isDTR() { + return sp.isDTR(); + } + + @Override + public boolean isCTS() { + return sp.isCTS(); + } + + @Override + public boolean isDSR() { + return sp.isDSR(); + } + + @Override + public boolean isCD() { + return sp.isCD(); + } + + @Override + public boolean isRI() { + return sp.isRI(); + } + + @Override + public void sendBreak(int duration) { + sp.sendBreak(duration); + } +} diff --git a/bundles/pom.xml b/bundles/pom.xml index c0fac698fad..8f269564e58 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -73,6 +73,7 @@ org.openhab.core.io.transport.mqtt org.openhab.core.io.transport.serial org.openhab.core.io.transport.serial.javacomm + org.openhab.core.io.transport.serial.purejavacomm org.openhab.core.io.transport.serial.rxtx org.openhab.core.io.transport.serial.rxtx.rfc2217 org.openhab.core.io.transport.upnp diff --git a/features/karaf/openhab-core/src/main/feature/feature.xml b/features/karaf/openhab-core/src/main/feature/feature.xml index 5fe065535e4..c726f45d8b1 100644 --- a/features/karaf/openhab-core/src/main/feature/feature.xml +++ b/features/karaf/openhab-core/src/main/feature/feature.xml @@ -237,6 +237,16 @@ mvn:org.openhab.core.bundles/org.openhab.core.io.transport.serial.javacomm/${project.version} + + openhab-core-base + + openhab.tp;filter:="(&(feature=serial)(impl=purejavacomm))" + openhab.tp-serial-purejavacomm + + mvn:org.openhab.core.bundles/org.openhab.core.io.transport.serial/${project.version} + mvn:org.openhab.core.bundles/org.openhab.core.io.transport.serial.purejavacomm/${project.version} + + openhab-core-base diff --git a/features/karaf/openhab-tp/src/main/feature/feature.xml b/features/karaf/openhab-tp/src/main/feature/feature.xml index 96bfdbc5a43..5b2ace433eb 100644 --- a/features/karaf/openhab-tp/src/main/feature/feature.xml +++ b/features/karaf/openhab-tp/src/main/feature/feature.xml @@ -232,6 +232,13 @@ mvn:org.eclipse.kura/org.eclipse.soda.dk.comm.x86_64/1.2.201 + + openhab.tp;feature=serial;impl=purejavacomm + mvn:net.java.dev.jna/jna-platform/5.6.0 + mvn:net.java.dev.jna/jna/5.6.0 + mvn:org.opensmarthouse/purejavacomm/1.0.5 + + openhab.tp;feature=serial;impl=rxtx mvn:com.neuronrobotics/nrjavaserial/5.2.1.OH1