/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.ebus.internal.connection; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.TooManyListenersException; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import gnu.io.UnsupportedCommOperationException; /** * This is the serial implementation of the eBus connector. It only handles * serial specific connection/disconnection. All logic is handled by * abstract class AbstractEBusConnector. * * @author Christian Sowada * @since 1.7.0 */ public class EBusSerialConnector extends AbstractEBusWriteConnector implements SerialPortEventListener { private static final Logger logger = LoggerFactory.getLogger(EBusSerialConnector.class); /** The serial object */ private SerialPort serialPort; /** The serial port name */ private String port; /** output stream for eBus communication */ private OutputStream outputStream; /** input stream for eBus communication */ private InputStream inputStream; /** * @param port */ public EBusSerialConnector(String port) { this.port = port; } /* * (non-Javadoc) * * @see org.openhab.binding.ebus.connection.AbstractEBusConnector#connect() */ @Override protected boolean connect() throws IOException { try { final CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(port); if (portIdentifier != null) { serialPort = portIdentifier.open("org.openhab.binding.ebus", 2000); serialPort.setSerialPortParams(2400, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); // set timeout 10 sec. serialPort.disableReceiveThreshold(); serialPort.enableReceiveTimeout(10000); // use event to let readByte wait until data is available, optimize cpu usage serialPort.addEventListener(this); serialPort.notifyOnDataAvailable(true); outputStream = serialPort.getOutputStream(); inputStream = serialPort.getInputStream(); return super.connect(); } } catch (NoSuchPortException e) { logger.error("Unable to connect to serial port {}", port); } catch (PortInUseException e) { logger.error("Serial port {} is already in use", port); } catch (UnsupportedCommOperationException e) { logger.error(e.toString(), e); } catch (TooManyListenersException e) { logger.error("Too many listeners error!", e); } serialPort = null; return false; } /* * (non-Javadoc) * * @see org.openhab.binding.ebus.connection.AbstractEBusConnector#disconnect() */ @Override protected boolean disconnect() throws IOException { if (serialPort == null) { return true; } // run the serial.close in a new not-interrupted thread to // prevent an IllegalMonitorStateException error Thread shutdownThread = new Thread(new Runnable() { @Override public void run() { IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(outputStream); if (serialPort != null) { serialPort.close(); serialPort = null; } } }, "eBUS serial shutdown thread"); shutdownThread.start(); try { // wait for shutdown shutdownThread.join(2000); } catch (InterruptedException e) { } return true; } /* * (non-Javadoc) * * @see gnu.io.SerialPortEventListener#serialEvent(gnu.io.SerialPortEvent) */ @Override public void serialEvent(SerialPortEvent event) { if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) { synchronized (inputStream) { inputStream.notifyAll(); } } } /* * (non-Javadoc) * * @see org.openhab.binding.ebus.internal.connection.AbstractEBusConnector#readByte() */ @Override protected int readByte(boolean lowLatency) throws IOException { if (lowLatency) { return inputStream.read(); } else { if (inputStream.available() > 0) { return inputStream.read(); } else { synchronized (inputStream) { try { inputStream.wait(3000); return inputStream.read(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return -1; } } } } /* * (non-Javadoc) * * @see org.openhab.binding.ebus.internal.connection.AbstractEBusWriteConnector#writeByte(int) */ @Override protected void writeByte(int b) throws IOException { outputStream.write(b); // no flush, sometimes it blocks infinitely } @Override protected boolean isReceiveBufferEmpty() throws IOException { return inputStream.available() == 0; } @Override protected boolean isConnected() { return inputStream != null; } @Override protected void resetInputBuffer() throws IOException { inputStream.skip(inputStream.available()); } @Override protected InputStream getInputStream() { return inputStream; } }