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.lirc.internal.connector;
15 import java.io.BufferedReader;
16 import java.io.EOFException;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.InputStreamReader;
20 import java.io.InterruptedIOException;
21 import java.util.Arrays;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
25 import org.openhab.binding.lirc.internal.LIRCResponseException;
26 import org.openhab.binding.lirc.internal.messages.LIRCButtonEvent;
27 import org.openhab.binding.lirc.internal.messages.LIRCResponse;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * Stream reader to parse LIRC output into messages
34 * @author Andrew Nagle
36 public class LIRCStreamReader extends Thread {
38 private final Logger logger = LoggerFactory.getLogger(LIRCStreamReader.class);
40 private static final Pattern EVENT_PATTERN = Pattern.compile("^([a-f0-9]+)\\s([a-f0-9]+)\\s(.+)\\s(.+)$");
42 private InputStream in;
43 private boolean interrupted = false;
44 private BufferedReader reader;
45 private LIRCConnector connector;
47 public LIRCStreamReader(LIRCConnector connector, InputStream in) {
48 this.connector = connector;
53 public void interrupt() {
60 reader = new BufferedReader(new InputStreamReader(in));
62 String responseText = "";
63 while (!interrupted) {
65 line = reader.readLine();
67 throw new EOFException("lost connection");
69 logger.trace("Received message: {}", line);
70 Matcher m = EVENT_PATTERN.matcher(line);
72 String code = m.group(1);
73 String repeatsHex = m.group(2);
74 String button = m.group(3);
75 String remote = m.group(4);
76 int repeats = Integer.parseInt(repeatsHex, 16);
77 LIRCButtonEvent buttonMessage = new LIRCButtonEvent(remote, button, repeats, code);
78 connector.sendButtonToListeners(buttonMessage);
80 if ("BEGIN".equals(line)) {
82 } else if ("END".equals(line)) {
83 processResponse(responseText);
86 responseText += line + "\n";
90 } catch (InterruptedIOException e) {
91 Thread.currentThread().interrupt();
92 logger.error("Interrupted via InterruptedIOException");
93 } catch (EOFException e) {
94 logger.error("Lost connection to LIRC server", e);
95 connector.sendErrorToListeners(e.getMessage());
97 } catch (IOException e) {
99 logger.error("Reading from socket failed", e);
100 connector.sendErrorToListeners(e.getMessage());
102 } catch (LIRCResponseException e) {
103 logger.error("Invalid message received", e);
108 } catch (IOException e) {
109 logger.debug("Error while closing the input stream: {}", e.getMessage());
113 private void processResponse(String responseText) throws LIRCResponseException {
114 String[] parts = responseText.split("\n");
115 String command = parts[0];
116 boolean success = true;
118 String[] data = null;
119 if (parts.length > 1) {
120 if ("SUCCESS".equals(parts[1]) || "ERROR".equals(parts[1])) {
121 success = "SUCCESS".equals(parts[1]);
123 throw new LIRCResponseException("Malformed response");
126 if (parts.length > 2) {
127 if ("DATA".equals(parts[2]) && parts.length > 3) {
128 dataLength = Integer.parseInt(parts[3]);
130 throw new LIRCResponseException("Malformed response");
133 if (parts.length > 4) {
134 data = Arrays.copyOfRange(parts, 4, parts.length);
135 if (data.length != dataLength) {
136 throw new LIRCResponseException(String
137 .format("Data does not match expected length. Expected: %s, Got: %s", dataLength, data.length));
140 LIRCResponse response = new LIRCResponse(command, success, data);
141 connector.sendMessageToListeners(response);