2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.knx.internal.client;
15 import java.nio.ByteBuffer;
16 import java.text.MessageFormat;
17 import java.util.concurrent.TimeUnit;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
24 import tuwien.auto.calimero.IndividualAddress;
25 import tuwien.auto.calimero.KNXException;
26 import tuwien.auto.calimero.mgmt.Destination;
27 import tuwien.auto.calimero.mgmt.ManagementClient;
30 * Client for retrieving additional device descriptions.
32 * @author Simon Kaufmann - initial contribution and API.
36 public class DeviceInfoClientImpl implements DeviceInfoClient {
38 private final Logger logger = LoggerFactory.getLogger(DeviceInfoClientImpl.class);
39 private final ManagementClient managementClient;
41 DeviceInfoClientImpl(ManagementClient managementClient) {
42 this.managementClient = managementClient;
46 private interface ReadFunction<T, R> {
48 R apply(T t) throws KNXException, InterruptedException;
51 private byte @Nullable [] readFromManagementClient(String task, long timeout, IndividualAddress address,
52 ReadFunction<Destination, byte[]> function) {
53 final long start = System.nanoTime();
54 while ((System.nanoTime() - start) < TimeUnit.MILLISECONDS.toNanos(timeout)) {
55 Destination destination = null;
57 logger.trace("Going to {} of {} ", task, address);
58 destination = managementClient.createDestination(address, true);
59 byte[] result = function.apply(destination);
60 logger.trace("Finished to {} of {}, result: {}", task, address, result == null ? null : result.length);
62 } catch (KNXException e) {
63 logger.debug("Could not {} of {}: {}", task, address, e.getMessage());
65 // avoid trashing the log on connection loss
67 } catch (InterruptedException ignored) {
69 } catch (InterruptedException e) {
70 logger.trace("Interrupted to {}", task);
73 if (destination != null) {
74 destination.destroy();
81 private void authorize(boolean authenticate, Destination destination) throws KNXException, InterruptedException {
83 managementClient.authorize(destination, (ByteBuffer.allocate(4)).put((byte) 0xFF).put((byte) 0xFF)
84 .put((byte) 0xFF).put((byte) 0xFF).array());
89 public synchronized byte @Nullable [] readDeviceDescription(IndividualAddress address, int descType,
90 boolean authenticate, long timeout) {
91 String task = "read the device description";
92 return readFromManagementClient(task, timeout, address, destination -> {
93 authorize(authenticate, destination);
94 return managementClient.readDeviceDesc(destination, descType);
99 public synchronized byte @Nullable [] readDeviceMemory(IndividualAddress address, int startAddress, int bytes,
100 boolean authenticate, long timeout) {
101 String task = MessageFormat.format("read {0} bytes at memory location {1}", bytes, startAddress);
102 return readFromManagementClient(task, timeout, address, destination -> {
103 authorize(authenticate, destination);
104 return managementClient.readMemory(destination, startAddress, bytes);
109 public synchronized byte @Nullable [] readDeviceProperties(IndividualAddress address,
110 final int interfaceObjectIndex, final int propertyId, final int start, final int elements,
111 boolean authenticate, long timeout) {
112 String task = MessageFormat.format("read device property {0} at index {1}", propertyId, interfaceObjectIndex);
113 return readFromManagementClient(task, timeout, address, destination -> {
114 authorize(authenticate, destination);
115 return managementClient.readProperty(destination, interfaceObjectIndex, propertyId, start, elements);
120 public boolean isConnected() {
121 return managementClient.isOpen();