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.ESP3Packet;
26 import org.openhab.binding.enocean.internal.messages.ESP3PacketFactory;
27 import org.openhab.binding.enocean.internal.messages.Response;
28 import org.openhab.core.io.transport.serial.SerialPortManager;
29 import org.openhab.core.util.HexUtils;
33 * @author Daniel Weber - Initial contribution
36 public class EnOceanESP3Transceiver extends EnOceanTransceiver {
38 public EnOceanESP3Transceiver(String path, TransceiverErrorListener errorListener,
39 ScheduledExecutorService scheduler, @Nullable SerialPortManager serialPortManager) {
40 super(path, errorListener, scheduler, serialPortManager);
49 byte[] dataBuffer = new byte[ENOCEAN_MAX_DATA];
50 ReadingState state = ReadingState.WaitingForSyncByte;
51 int currentPosition = 0;
53 int optionalLength = -1;
57 protected void processMessage(byte firstByte) {
58 byte[] readingBuffer = new byte[ENOCEAN_MAX_DATA];
63 readingBuffer[0] = firstByte;
64 InputStream localInPutStream = this.inputStream;
65 if (localInPutStream == null) {
66 throw new IOException("could not read from inputstream");
68 bytesRead = localInPutStream.read(readingBuffer, 1, localInPutStream.available());
69 if (bytesRead == -1) {
70 throw new IOException("could not read from inputstream");
73 Future<?> localReadingTask = readingTask;
74 if (localReadingTask == null || localReadingTask.isCancelled()) {
79 for (int p = 0; p < bytesRead; p++) {
80 byteBuffer = readingBuffer[p];
83 case WaitingForSyncByte:
84 if (byteBuffer == ESP3Packet.ESP3_SYNC_BYTE) {
85 state = ReadingState.ReadingHeader;
86 logger.trace("Received Sync Byte");
90 if (currentPosition == ESP3Packet.ESP3_HEADER_LENGTH) {
91 if (ESP3Packet.checkCRC8(dataBuffer, ESP3Packet.ESP3_HEADER_LENGTH, byteBuffer)
92 && ((dataBuffer[0] & 0xFF) << 8) + (dataBuffer[1] & 0xFF)
93 + (dataBuffer[2] & 0xFF) > 0) {
94 state = ReadingState.ReadingData;
96 dataLength = ((dataBuffer[0] & 0xFF << 8) | (dataBuffer[1] & 0xFF));
97 optionalLength = dataBuffer[2] & 0xFF;
98 packetType = dataBuffer[3];
101 if (packetType == 3) {
102 logger.trace("Received sub_msg");
105 logger.trace(">> Received header, data length {} optional length {} packet type {}",
106 dataLength, optionalLength, packetType);
108 // check if we find a sync byte in current buffer
110 for (int i = 0; i < ESP3Packet.ESP3_HEADER_LENGTH; i++) {
111 if (dataBuffer[i] == ESP3Packet.ESP3_SYNC_BYTE) {
117 if (copyFrom != -1) {
118 System.arraycopy(dataBuffer, copyFrom, dataBuffer, 0,
119 ESP3Packet.ESP3_HEADER_LENGTH - copyFrom);
120 state = ReadingState.ReadingHeader;
121 currentPosition = ESP3Packet.ESP3_HEADER_LENGTH - copyFrom;
122 dataBuffer[currentPosition++] = byteBuffer;
125 state = byteBuffer == ESP3Packet.ESP3_SYNC_BYTE ? ReadingState.ReadingHeader
126 : ReadingState.WaitingForSyncByte;
128 logger.trace("CrC8 header check not successful");
131 dataBuffer[currentPosition++] = byteBuffer;
135 if (currentPosition == dataLength + optionalLength) {
136 if (ESP3Packet.checkCRC8(dataBuffer, dataLength + optionalLength, byteBuffer)) {
137 state = ReadingState.WaitingForSyncByte;
138 BasePacket packet = ESP3PacketFactory.buildPacket(dataLength, optionalLength,
139 packetType, dataBuffer);
141 if (packet != null) {
142 switch (packet.getPacketType()) {
144 logger.debug("Common command: {}",
145 HexUtils.bytesToHex(packet.getPayload()));
149 informListeners(packet);
157 case REMOTE_MAN_COMMAND:
160 Response response = (Response) packet;
161 logger.debug("{} with code {} payload {} received",
162 packet.getPacketType().name(), response.getResponseType().name(),
163 HexUtils.bytesToHex(packet.getPayload())); // Responses do not have
165 handleResponse(response);
168 case SMART_ACK_COMMAND:
174 logger.trace("Unknown ESP3Packet: {}", HexUtils
175 .bytesToHex(Arrays.copyOf(dataBuffer, dataLength + optionalLength)));
178 state = byteBuffer == ESP3Packet.ESP3_SYNC_BYTE ? ReadingState.ReadingHeader
179 : ReadingState.WaitingForSyncByte;
180 logger.trace("ESP3Packet malformed: {}",
181 HexUtils.bytesToHex(Arrays.copyOf(dataBuffer, dataLength + optionalLength)));
185 dataLength = optionalLength = packetType = -1;
187 dataBuffer[currentPosition++] = byteBuffer;
192 } catch (IOException ioexception) {
193 logger.trace("Unable to process message", ioexception);
194 TransceiverErrorListener localListener = errorListener;
195 if (localListener != null) {
196 localListener.errorOccured(ioexception);
203 protected byte[] serializePacket(BasePacket packet) throws EnOceanException {
204 return new ESP3Packet(packet).serialize();