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.enocean.internal.transceiver;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.util.Arrays;
18 import java.util.concurrent.Future;
19 import java.util.concurrent.ScheduledExecutorService;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.enocean.internal.EnOceanException;
24 import org.openhab.binding.enocean.internal.messages.BasePacket;
25 import org.openhab.binding.enocean.internal.messages.ERP1Message;
26 import org.openhab.binding.enocean.internal.messages.ERP1Message.RORG;
27 import org.openhab.binding.enocean.internal.messages.ESP2Packet;
28 import org.openhab.binding.enocean.internal.messages.ESP2PacketConverter;
29 import org.openhab.binding.enocean.internal.messages.Response;
30 import org.openhab.core.io.transport.serial.SerialPortManager;
31 import org.openhab.core.util.HexUtils;
35 * @author Daniel Weber - Initial contribution
38 public class EnOceanESP2Transceiver extends EnOceanTransceiver {
40 public EnOceanESP2Transceiver(String path, TransceiverErrorListener errorListener,
41 ScheduledExecutorService scheduler, @Nullable SerialPortManager serialPortManager) {
42 super(path, errorListener, scheduler, serialPortManager);
46 WaitingForFirstSyncByte,
47 WaitingForSecondSyncByte,
52 byte[] dataBuffer = new byte[ESP2Packet.ESP_PACKET_LENGTH];
53 ReadingState state = ReadingState.WaitingForFirstSyncByte;
54 int currentPosition = 0;
59 protected void processMessage(byte firstByte) {
60 byte[] readingBuffer = new byte[ENOCEAN_MAX_DATA];
65 readingBuffer[0] = firstByte;
66 InputStream localInputStream = inputStream;
67 if (localInputStream == null) {
68 throw new IOException("could not read from inputstream, it was null");
70 bytesRead = localInputStream.read(readingBuffer, 1, localInputStream.available());
71 if (bytesRead == -1) {
72 throw new IOException("could not read from inputstream");
75 Future<?> localReadingTask = readingTask;
76 if (localReadingTask == null || localReadingTask.isCancelled()) {
81 for (int p = 0; p < bytesRead; p++) {
82 byteBuffer = readingBuffer[p];
85 case WaitingForFirstSyncByte:
86 if (byteBuffer == ESP2Packet.ENOCEAN_ESP2_FIRSTSYNC_BYTE) {
87 state = ReadingState.WaitingForSecondSyncByte;
88 logger.trace("Received First Sync Byte");
91 case WaitingForSecondSyncByte:
92 if (byteBuffer == ESP2Packet.ENOCEAN_ESP2_SECONDSYNC_BYTE) {
93 state = ReadingState.ReadingHeader;
94 logger.trace("Received Second Sync Byte");
98 state = ReadingState.ReadingData;
101 dataBuffer[currentPosition++] = byteBuffer;
102 dataLength = ((dataBuffer[0] & 0xFF) & 0b11111);
103 packetType = (byte) ((dataBuffer[0] & 0xFF) >> 5);
105 logger.trace(">> Received header, data length {} packet type {}", dataLength, packetType);
109 if (currentPosition == dataLength) {
110 if (ESP2Packet.validateCheckSum(dataBuffer, dataLength, byteBuffer)) {
111 BasePacket packet = ESP2PacketConverter.buildPacket(dataLength, packetType, dataBuffer);
112 if (packet != null) {
113 switch (packet.getPacketType()) {
115 ERP1Message msg = (ERP1Message) packet;
116 logger.debug("Converted to: {} with RORG {} for {}",
117 packet.getPacketType().name(), msg.getRORG().name(),
118 HexUtils.bytesToHex(msg.getSenderId()));
120 if (msg.getRORG() != RORG.Unknown) {
121 informListeners(msg);
123 logger.debug("Received unknown RORG");
128 Response response = (Response) packet;
129 logger.debug("Converted to: {} with code {}", packet.getPacketType().name(),
130 response.getResponseType().name());
132 handleResponse(response);
139 if (dataBuffer[1] != (byte) 0xFC) {
140 byte[] array = Arrays.copyOf(dataBuffer, dataLength);
141 String packetString = array != null ? HexUtils.bytesToHex(array) : "";
142 logger.debug("Unknown/unsupported ESP2Packet: {}", packetString);
146 logger.debug("ESP2Packet malformed: {}", HexUtils.bytesToHex(dataBuffer));
149 state = byteBuffer == ESP2Packet.ENOCEAN_ESP2_FIRSTSYNC_BYTE
150 ? ReadingState.WaitingForSecondSyncByte
151 : ReadingState.WaitingForFirstSyncByte;
154 dataLength = packetType = -1;
156 dataBuffer[currentPosition++] = byteBuffer;
161 } catch (IOException ioexception) {
162 logger.trace("Unable to process message", ioexception);
163 TransceiverErrorListener localListener = errorListener;
164 if (localListener != null) {
165 localListener.errorOccured(ioexception);
172 protected byte[] serializePacket(BasePacket packet) throws EnOceanException {
173 return new ESP2Packet(packet).serialize();