*/
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;
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.
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();