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