]> git.basschouten.com Git - openhab-addons.git/commitdiff
[knx] FT12: Autodetect cEMI on Weinzierl devices (#14454)
authorHolger Friedrich <holgerfriedrich@users.noreply.github.com>
Tue, 21 Feb 2023 18:36:52 +0000 (19:36 +0100)
committerGitHub <noreply@github.com>
Tue, 21 Feb 2023 18:36:52 +0000 (19:36 +0100)
Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/SerialClient.java

index 24a5d6f5f25df1692c56f2d59cde16402a597749..20e269f8300f685a6fc36a4497aa64cfd78a7d15 100644 (file)
  */
 package org.openhab.binding.knx.internal.client;
 
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -22,10 +26,12 @@ import org.openhab.core.thing.ThingUID;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import tuwien.auto.calimero.Connection.BlockingMode;
 import tuwien.auto.calimero.KNXException;
 import tuwien.auto.calimero.link.KNXNetworkLink;
 import tuwien.auto.calimero.link.KNXNetworkLinkFT12;
 import tuwien.auto.calimero.link.medium.TPSettings;
+import tuwien.auto.calimero.serial.FT12Connection;
 
 /**
  * Serial specific {@link AbstractKNXClient} implementation.
@@ -54,21 +60,73 @@ public class SerialClient extends AbstractKNXClient {
         this.useCemi = useCemi;
     }
 
+    /**
+     * try autodetection of cEMI devices via the PEI identification frame
+     *
+     * @implNote This is based on an vendor specific extension and may not work for other devices.
+     */
+    protected boolean detectCemi() throws InterruptedException {
+        final byte[] peiIdentifyReqFrame = { (byte) 0xa7 };
+        final byte peiIdentifyCon = (byte) 0xa8;
+        final byte peiWzIdentFrameLength = 11;
+
+        logger.trace("Checking for cEMI support");
+
+        try (FT12Connection serialConnection = new FT12Connection(serialPort)) {
+            final CompletableFuture<byte[]> frameListener = new CompletableFuture<byte[]>();
+            serialConnection.addConnectionListener(frameReceived -> {
+                final byte[] content = frameReceived.getFrameBytes();
+                if ((content.length > 0) && (content[0] == peiIdentifyCon)) {
+                    logger.trace("Received PEI confirmation of {} bytes", content.length);
+                    frameListener.complete(content);
+                }
+            });
+
+            serialConnection.send(peiIdentifyReqFrame, BlockingMode.NonBlocking);
+            byte[] content = frameListener.get(1, TimeUnit.SECONDS);
+
+            if (peiWzIdentFrameLength == content.length) {
+                // standard emi2 frame contain 9 bytes,
+                // content[1..2] physical address
+                // content[3..8] serial no
+                //
+                // Weinzierl adds 2 extra bytes, 0x0004 for capablity cEMI,
+                // see "Weinzierl KNX BAOS Starter Kit, User Guide"
+                if (0 == content[9] && 4 == content[10]) {
+                    logger.debug("Detected device with cEMI support");
+                    return true;
+                }
+            }
+        } catch (final ExecutionException | TimeoutException | KNXException na) {
+            if (logger.isTraceEnabled()) {
+                logger.trace("Exception detecting cEMI: ", na);
+            }
+        }
+
+        logger.trace("Did not detect device with cEMI support");
+        return false;
+    }
+
     @Override
     protected KNXNetworkLink establishConnection() throws KNXException, InterruptedException {
         try {
-            logger.debug("Establishing connection to KNX bus through FT1.2 on serial port {}{}.", serialPort,
-                    (useCemi ? " using CEMI" : ""));
+            boolean useCemiL = useCemi;
+            if (!useCemiL) {
+                useCemiL = detectCemi();
+            }
+            logger.debug("Establishing connection to KNX bus through FT1.2 on serial port {}{}{}", serialPort,
+                    (useCemiL ? " using cEMI" : ""), ((useCemiL != useCemi) ? " (autodetected)" : ""));
             // CEMI support by Calimero library, userful for newer serial devices like KNX RF sticks, kBerry,
             // etc.; default is still old EMI frame format
-            if (useCemi) {
+            if (useCemiL) {
                 return KNXNetworkLinkFT12.newCemiLink(serialPort, new TPSettings());
             }
+
             return new KNXNetworkLinkFT12(serialPort, new TPSettings());
 
         } catch (NoClassDefFoundError e) {
             throw new KNXException(
-                    "The serial FT1.2 KNX connection requires the RXTX libraries to be available, but they could not be found!",
+                    "The serial FT1.2 KNX connection requires the serial libraries to be available, but they could not be found!",
                     e);
         } catch (KNXException e) {
             final String msg = e.getMessage();