]> git.basschouten.com Git - openhab-addons.git/blob
05c2ff1311ed0b6944871bc6f1bb06d803f876c0
[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.epsonprojector.internal.connector;
14
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.io.OutputStream;
18 import java.nio.charset.StandardCharsets;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.epsonprojector.internal.EpsonProjectorException;
23 import org.openhab.core.io.transport.serial.PortInUseException;
24 import org.openhab.core.io.transport.serial.SerialPort;
25 import org.openhab.core.io.transport.serial.SerialPortEvent;
26 import org.openhab.core.io.transport.serial.SerialPortEventListener;
27 import org.openhab.core.io.transport.serial.SerialPortIdentifier;
28 import org.openhab.core.io.transport.serial.SerialPortManager;
29 import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * Connector for serial port communication.
35  *
36  * @author Pauli Anttila - Initial contribution
37  * @author Michael Lobstein - Improvements for OH3
38  */
39 @NonNullByDefault
40 public class EpsonProjectorSerialConnector implements EpsonProjectorConnector, SerialPortEventListener {
41
42     private final Logger logger = LoggerFactory.getLogger(EpsonProjectorSerialConnector.class);
43     private final String serialPortName;
44     private final SerialPortManager serialPortManager;
45
46     private @Nullable InputStream in = null;
47     private @Nullable OutputStream out = null;
48     private @Nullable SerialPort serialPort = null;
49
50     public EpsonProjectorSerialConnector(SerialPortManager serialPortManager, String serialPort) {
51         this.serialPortManager = serialPortManager;
52         this.serialPortName = serialPort;
53     }
54
55     @Override
56     public void connect() throws EpsonProjectorException {
57         try {
58             logger.debug("Open connection to serial port '{}'", serialPortName);
59
60             SerialPortIdentifier serialPortIdentifier = serialPortManager.getIdentifier(serialPortName);
61
62             if (serialPortIdentifier == null) {
63                 throw new IOException("Unknown serial port");
64             }
65             SerialPort serialPort = serialPortIdentifier.open(this.getClass().getName(), 2000);
66             serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
67             serialPort.enableReceiveThreshold(1);
68             serialPort.disableReceiveTimeout();
69
70             InputStream in = serialPort.getInputStream();
71             OutputStream out = serialPort.getOutputStream();
72
73             if (in != null && out != null) {
74                 out.flush();
75                 if (in.markSupported()) {
76                     in.reset();
77                 }
78
79                 serialPort.notifyOnDataAvailable(true);
80
81                 this.serialPort = serialPort;
82                 this.in = in;
83                 this.out = out;
84             }
85         } catch (PortInUseException | UnsupportedCommOperationException | IOException e) {
86             throw new EpsonProjectorException(e);
87         }
88     }
89
90     @Override
91     public void disconnect() throws EpsonProjectorException {
92         InputStream in = this.in;
93         OutputStream out = this.out;
94         SerialPort serialPort = this.serialPort;
95
96         if (out != null) {
97             logger.debug("Close serial out stream");
98             try {
99                 out.close();
100             } catch (IOException e) {
101                 logger.debug("Error occurred when closing serial out stream: {}", e.getMessage());
102             }
103             this.out = null;
104         }
105         if (in != null) {
106             logger.debug("Close serial in stream");
107             try {
108                 in.close();
109             } catch (IOException e) {
110                 logger.debug("Error occurred when closing serial in stream: {}", e.getMessage());
111             }
112             this.in = null;
113         }
114         if (serialPort != null) {
115             logger.debug("Close serial port");
116             serialPort.close();
117             serialPort.removeEventListener();
118             this.serialPort = null;
119         }
120
121         logger.debug("Closed");
122     }
123
124     @Override
125     public String sendMessage(String data, int timeout) throws EpsonProjectorException {
126         InputStream in = this.in;
127         OutputStream out = this.out;
128
129         if (in == null || out == null) {
130             connect();
131             in = this.in;
132             out = this.out;
133         }
134
135         try {
136             if (in != null && out != null) {
137                 // flush input stream
138                 if (in.markSupported()) {
139                     in.reset();
140                 } else {
141                     while (in.available() > 0) {
142                         int availableBytes = in.available();
143
144                         if (availableBytes > 0) {
145                             byte[] tmpData = new byte[availableBytes];
146                             in.read(tmpData, 0, availableBytes);
147                         }
148                     }
149                 }
150                 return sendMmsg(data, timeout);
151             } else {
152                 return "";
153             }
154         } catch (IOException e) {
155             logger.debug("IO error occurred...reconnect and resend once: {}", e.getMessage());
156             disconnect();
157             connect();
158
159             try {
160                 return sendMmsg(data, timeout);
161             } catch (IOException e1) {
162                 throw new EpsonProjectorException(e);
163             }
164         }
165     }
166
167     @Override
168     public void serialEvent(SerialPortEvent arg0) {
169     }
170
171     private String sendMmsg(String data, int timeout) throws IOException, EpsonProjectorException {
172         String resp = "";
173
174         InputStream in = this.in;
175         OutputStream out = this.out;
176
177         if (in != null && out != null) {
178             out.write(data.getBytes(StandardCharsets.US_ASCII));
179             out.write("\r\n".getBytes(StandardCharsets.US_ASCII));
180             out.flush();
181
182             long startTime = System.currentTimeMillis();
183             long elapsedTime = 0;
184
185             while (elapsedTime < timeout) {
186                 int availableBytes = in.available();
187                 if (availableBytes > 0) {
188                     byte[] tmpData = new byte[availableBytes];
189                     int readBytes = in.read(tmpData, 0, availableBytes);
190                     resp = resp.concat(new String(tmpData, 0, readBytes, StandardCharsets.US_ASCII));
191
192                     if (resp.contains(":")) {
193                         return resp;
194                     }
195                 } else {
196                     try {
197                         Thread.sleep(100);
198                     } catch (InterruptedException e) {
199                         throw new EpsonProjectorException(e);
200                     }
201                 }
202
203                 elapsedTime = System.currentTimeMillis() - startTime;
204             }
205         }
206
207         return resp;
208     }
209 }