[knx] FT12: Autodetect cEMI on Weinzierl devices (#14454)

Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
pull/14474/head
Holger Friedrich 2023-02-21 19:36:52 +01:00 committed by GitHub
parent 1a01a0e021
commit 4f1dd5792f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 62 additions and 4 deletions

View File

@ -12,7 +12,11 @@
*/
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();