/** * 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.io.transport.cul.internal.serial; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.TooManyListenersException; import org.openhab.io.transport.cul.CULDeviceException; import org.openhab.io.transport.cul.internal.AbstractCULHandler; import org.openhab.io.transport.cul.internal.CULConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import gnu.io.CommPort; 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; /** * Implementation for culfw based devices which communicate via serial port * (cullite for example). This is based on rxtx and assumes constant parameters * for the serial port. * * @author Till Klocke * @since 1.4.0 */ public class CULSerialHandlerImpl extends AbstractCULHandler<CULSerialConfig> implements SerialPortEventListener { private final static Logger logger = LoggerFactory.getLogger(CULSerialHandlerImpl.class); private SerialPort serialPort; private BufferedWriter bw; private BufferedReader br; /** * Constructor including property map for specific configuration. * * @param config * Configuration for this implementation. */ public CULSerialHandlerImpl(CULConfig config) { super((CULSerialConfig) config); } @Override public void serialEvent(SerialPortEvent event) { if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) { synchronized (serialPort) { try { if (br == null) { logger.warn("BufferedReader for serial connection is null"); } else { String line = br.readLine(); processNextLine(line); } } catch (IOException e) { logger.warn("Can't read from serial device {}", config.getDeviceName(), e); tryReopenHardware(); } } } } @Override protected void openHardware() throws CULDeviceException { String deviceName = config.getDeviceAddress(); logger.debug("Opening serial CUL connection for {}", deviceName); try { CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(deviceName); if (portIdentifier.isCurrentlyOwned()) { throw new CULDeviceException( "The port " + deviceName + " is currenty used by " + portIdentifier.getCurrentOwner()); } CommPort port = portIdentifier.open(this.getClass().getName(), 2000); if (!(port instanceof SerialPort)) { throw new CULDeviceException("The device " + deviceName + " is not a serial port"); } serialPort = (SerialPort) port; serialPort.setSerialPortParams(config.getBaudRate(), SerialPort.DATABITS_8, SerialPort.STOPBITS_1, config.getParityMode()); InputStream is = serialPort.getInputStream(); OutputStream os = serialPort.getOutputStream(); synchronized (serialPort) { br = new BufferedReader(new InputStreamReader(is)); bw = new BufferedWriter(new OutputStreamWriter(os)); } serialPort.notifyOnDataAvailable(true); logger.debug("Adding serial port event listener"); serialPort.addEventListener(this); } catch (NoSuchPortException e) { throw new CULDeviceException(e); } catch (PortInUseException e) { throw new CULDeviceException(e); } catch (UnsupportedCommOperationException e) { throw new CULDeviceException(e); } catch (IOException e) { throw new CULDeviceException(e); } catch (TooManyListenersException e) { throw new CULDeviceException(e); } } @Override protected void closeHardware() { logger.debug("Closing serial device {}", config.getDeviceAddress()); if (serialPort != null) { serialPort.removeEventListener(); } try { if (br != null) { br.close(); } if (bw != null) { bw.close(); } } catch (IOException e) { logger.warn("Can't close the input and output streams properly", e); } finally { if (serialPort != null) { serialPort.close(); } } } private void tryReopenHardware() { closeHardware(); try { openHardware(); } catch (CULDeviceException e) { logger.warn("Failed to reopen serial connection after connection error", e); } } @Override protected void write(String command) { try { synchronized (serialPort) { if (bw == null) { logger.warn("BufferedWriter for serial connection is null"); } else { bw.write(command); bw.flush(); } } } catch (IOException e) { logger.warn("Can't write to serial device {}", config.getDeviceName(), e); tryReopenHardware(); } } }