]> git.basschouten.com Git - openhab-addons.git/blob
ca4bf6a45f4f71890f0951051f6bad2872271166
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.rfxcom.internal.connector;
14
15 import java.io.IOException;
16 import java.io.OutputStream;
17 import java.util.TooManyListenersException;
18
19 import org.openhab.binding.rfxcom.internal.config.RFXComBridgeConfiguration;
20 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
21 import org.openhab.core.io.transport.serial.PortInUseException;
22 import org.openhab.core.io.transport.serial.SerialPort;
23 import org.openhab.core.io.transport.serial.SerialPortEvent;
24 import org.openhab.core.io.transport.serial.SerialPortEventListener;
25 import org.openhab.core.io.transport.serial.SerialPortIdentifier;
26 import org.openhab.core.io.transport.serial.SerialPortManager;
27 import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
28 import org.openhab.core.util.HexUtils;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33  * RFXCOM connector for serial port communication.
34  *
35  * @author Pauli Anttila - Initial contribution
36  */
37 public class RFXComSerialConnector extends RFXComBaseConnector implements SerialPortEventListener {
38     private final Logger logger = LoggerFactory.getLogger(RFXComSerialConnector.class);
39
40     private OutputStream out;
41     private SerialPort serialPort;
42     private final SerialPortManager serialPortManager;
43
44     private final String readerThreadName;
45     private Thread readerThread;
46
47     public RFXComSerialConnector(SerialPortManager serialPortManager, String readerThreadName) {
48         super();
49         this.serialPortManager = serialPortManager;
50         this.readerThreadName = readerThreadName;
51     }
52
53     @Override
54     public void connect(RFXComBridgeConfiguration device)
55             throws RFXComException, PortInUseException, UnsupportedCommOperationException, IOException {
56         SerialPortIdentifier portIdentifier = serialPortManager.getIdentifier(device.serialPort);
57         if (portIdentifier == null) {
58             logger.debug("No serial port {}", device.serialPort);
59             throw new RFXComException("No serial port " + device.serialPort);
60         }
61
62         SerialPort commPort = portIdentifier.open(this.getClass().getName(), 2000);
63
64         serialPort = commPort;
65         serialPort.setSerialPortParams(38400, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
66         serialPort.enableReceiveThreshold(1);
67         serialPort.enableReceiveTimeout(100); // In ms. Small values mean faster shutdown but more cpu usage.
68
69         in = serialPort.getInputStream();
70         out = serialPort.getOutputStream();
71
72         out.flush();
73         if (in.markSupported()) {
74             in.reset();
75         }
76
77         // RXTX serial port library causes high CPU load
78         // Start event listener, which will just sleep and slow down event loop
79         try {
80             serialPort.addEventListener(this);
81             serialPort.notifyOnDataAvailable(true);
82             logger.debug("Serial port event listener started");
83         } catch (TooManyListenersException e) {
84         }
85
86         readerThread = new RFXComStreamReader(this, readerThreadName);
87         readerThread.start();
88     }
89
90     @Override
91     public void disconnect() {
92         logger.debug("Disconnecting");
93
94         if (serialPort != null) {
95             serialPort.removeEventListener();
96             logger.debug("Serial port event listener stopped");
97         }
98
99         if (readerThread != null) {
100             logger.debug("Interrupt serial listener");
101             readerThread.interrupt();
102             try {
103                 readerThread.join();
104             } catch (InterruptedException e) {
105             }
106         }
107
108         if (out != null) {
109             logger.debug("Close serial out stream");
110             try {
111                 out.close();
112             } catch (IOException e) {
113                 logger.debug("Error while closing the out stream: {}", e.getMessage());
114             }
115         }
116         if (in != null) {
117             logger.debug("Close serial in stream");
118             try {
119                 in.close();
120             } catch (IOException e) {
121                 logger.debug("Error while closing the in stream: {}", e.getMessage());
122             }
123         }
124
125         if (serialPort != null) {
126             logger.debug("Close serial port");
127             serialPort.close();
128         }
129
130         readerThread = null;
131         serialPort = null;
132         out = null;
133         in = null;
134
135         logger.debug("Closed");
136     }
137
138     @Override
139     public void sendMessage(byte[] data) throws IOException {
140         if (out == null) {
141             throw new IOException("Not connected sending messages is not possible");
142         }
143
144         if (logger.isTraceEnabled()) {
145             logger.trace("Send data (len={}): {}", data.length, HexUtils.bytesToHex(data));
146         }
147
148         out.write(data);
149         out.flush();
150     }
151
152     @Override
153     public void serialEvent(SerialPortEvent arg0) {
154         try {
155             /*
156              * See more details from
157              * https://github.com/NeuronRobotics/nrjavaserial/issues/22
158              */
159             logger.trace("RXTX library CPU load workaround, sleep forever");
160             Thread.sleep(Long.MAX_VALUE);
161         } catch (InterruptedException ignore) {
162         }
163     }
164 }