]> git.basschouten.com Git - openhab-addons.git/blob
261c0595f93d3f02cc990ec36e03ad4b209d5102
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.lirc.internal.connector;
14
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;
24
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;
30
31 /**
32  * Stream reader to parse LIRC output into messages
33  *
34  * @author Andrew Nagle
35  */
36 public class LIRCStreamReader extends Thread {
37
38     private final Logger logger = LoggerFactory.getLogger(LIRCStreamReader.class);
39
40     private static final Pattern EVENT_PATTERN = Pattern.compile("^([a-f0-9]+)\\s([a-f0-9]+)\\s(.+)\\s(.+)$");
41
42     private InputStream in;
43     private boolean interrupted = false;
44     private BufferedReader reader;
45     private LIRCConnector connector;
46
47     public LIRCStreamReader(LIRCConnector connector, InputStream in) {
48         this.connector = connector;
49         this.in = in;
50     }
51
52     @Override
53     public void interrupt() {
54         interrupted = true;
55         super.interrupt();
56     }
57
58     @Override
59     public void run() {
60         reader = new BufferedReader(new InputStreamReader(in));
61         String line;
62         String responseText = "";
63         while (!interrupted) {
64             try {
65                 line = reader.readLine();
66                 if (line == null) {
67                     throw new EOFException("lost connection");
68                 } else {
69                     logger.trace("Received message: {}", line);
70                     Matcher m = EVENT_PATTERN.matcher(line);
71                     if (m.matches()) {
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);
79                     } else {
80                         if ("BEGIN".equals(line)) {
81                             responseText = "";
82                         } else if ("END".equals(line)) {
83                             processResponse(responseText);
84                             responseText = null;
85                         } else {
86                             responseText += line + "\n";
87                         }
88                     }
89                 }
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());
96                 this.interrupt();
97             } catch (IOException e) {
98                 if (!interrupted) {
99                     logger.error("Reading from socket failed", e);
100                     connector.sendErrorToListeners(e.getMessage());
101                 }
102             } catch (LIRCResponseException e) {
103                 logger.error("Invalid message received", e);
104             }
105         }
106         try {
107             reader.close();
108         } catch (IOException e) {
109             logger.debug("Error while closing the input stream: {}", e.getMessage());
110         }
111     }
112
113     private void processResponse(String responseText) throws LIRCResponseException {
114         String[] parts = responseText.split("\n");
115         String command = parts[0];
116         boolean success = true;
117         int dataLength = 0;
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]);
122             } else {
123                 throw new LIRCResponseException("Malformed response");
124             }
125         }
126         if (parts.length > 2) {
127             if ("DATA".equals(parts[2]) && parts.length > 3) {
128                 dataLength = Integer.parseInt(parts[3]);
129             } else {
130                 throw new LIRCResponseException("Malformed response");
131             }
132         }
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));
138             }
139         }
140         LIRCResponse response = new LIRCResponse(command, success, data);
141         connector.sendMessageToListeners(response);
142     }
143 }