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.satel.internal.protocol;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.io.OutputStream;
18 import java.util.TooManyListenersException;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
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.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * Represents Satel INT-RS module. Implements methods required to connect and
33 * communicate with that module over serial protocol.
35 * @author Krzysztof Goworek - Initial contribution
38 public class IntRSModule extends SatelModule {
40 private final Logger logger = LoggerFactory.getLogger(IntRSModule.class);
42 private final String port;
44 private final SerialPortManager serialPortManager;
47 * Creates new instance with port and timeout set to specified values.
49 * @param port serial port the module is connected to
50 * @param serialPortManager serial port manager object
51 * @param timeout timeout value in milliseconds for connect/read/write operations
52 * @param extPayloadSupport if <code>true</code>, the module supports extended command payload for reading
55 public IntRSModule(String port, SerialPortManager serialPortManager, int timeout, boolean extPayloadSupport) {
56 super(timeout, extPayloadSupport);
59 this.serialPortManager = serialPortManager;
63 protected CommunicationChannel connect() throws ConnectionFailureException {
64 logger.info("Connecting to INT-RS module at {}", this.port);
67 SerialPortIdentifier portIdentifier = serialPortManager.getIdentifier(this.port);
68 if (portIdentifier == null) {
69 throw new ConnectionFailureException(String.format("Port %s does not exist", this.port));
71 SerialPort serialPort = portIdentifier.open("org.openhab.binding.satel", 2000);
72 boolean supportsReceiveTimeout = false;
73 serialPort.setSerialPortParams(19200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
75 serialPort.enableReceiveTimeout(this.getTimeout());
76 supportsReceiveTimeout = true;
77 } catch (UnsupportedCommOperationException e) {
78 logger.debug("Receive timeout is unsupported for port {}", this.port);
81 serialPort.enableReceiveThreshold(1);
82 } catch (UnsupportedCommOperationException e) {
83 logger.debug("Receive threshold is unsupported for port {}", this.port);
85 // RXTX serial port library causes high CPU load
86 // Start event listener, which will just sleep and slow down event
88 serialPort.addEventListener(new SerialPortEventListener() {
90 public void serialEvent(SerialPortEvent ev) {
92 logger.trace("RXTX library CPU load workaround, sleep forever");
93 Thread.sleep(Long.MAX_VALUE);
94 } catch (InterruptedException e) {
98 serialPort.notifyOnDataAvailable(false);
100 logger.info("INT-RS module connected successfuly");
101 return new SerialCommunicationChannel(serialPort, supportsReceiveTimeout);
102 } catch (PortInUseException e) {
103 throw new ConnectionFailureException(String.format("Port %s in use", this.port), e);
104 } catch (UnsupportedCommOperationException e) {
105 throw new ConnectionFailureException(String.format("Unsupported comm operation on port %s", this.port), e);
106 } catch (TooManyListenersException e) {
107 throw new ConnectionFailureException(String.format("Too many listeners on port %s", this.port), e);
111 private class SerialCommunicationChannel implements CommunicationChannel {
113 private final SerialPort serialPort;
115 private final boolean supportsReceiveTimeout;
117 public SerialCommunicationChannel(SerialPort serialPort, boolean supportsReceiveTimeout) {
118 this.serialPort = serialPort;
119 this.supportsReceiveTimeout = supportsReceiveTimeout;
123 public InputStream getInputStream() throws IOException {
124 final InputStream stream = this.serialPort.getInputStream();
125 if (stream != null) {
128 throw new IOException("Selected port doesn't support receiving data: " + this.serialPort.getName());
132 public OutputStream getOutputStream() throws IOException {
133 final OutputStream stream = this.serialPort.getOutputStream();
134 if (stream != null) {
137 throw new IOException("Selected port doesn't support sending data: " + this.serialPort.getName());
141 public void disconnect() {
142 logger.debug("Closing connection to INT-RS module");
144 this.serialPort.close();
145 logger.info("Connection to INT-RS module has been closed");
146 } catch (Exception e) {
147 logger.error("An error occurred during closing serial port", e);
152 public boolean supportsReceiveTimeout() {
153 return supportsReceiveTimeout;