/** * 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.insteonplm.internal.driver; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import org.apache.commons.lang.StringUtils; 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.UnsupportedCommOperationException; /** * Implements IOStream for serial devices. * * @author Bernd Pfrommer * @author Daniel Pfrommer * @since 1.7.0 */ public class SerialIOStream extends IOStream { private static final Logger logger = LoggerFactory.getLogger(SerialIOStream.class); private SerialPort m_port = null; private final String m_appName = "PLM"; private final int m_speed = 19200; // baud rate private String m_devName = null; public SerialIOStream(String devName) { m_devName = devName; } @Override public boolean open() { try { updateSerialProperties(m_devName); CommPortIdentifier ci = CommPortIdentifier.getPortIdentifier(m_devName); CommPort cp = ci.open(m_appName, 1000); if (cp instanceof SerialPort) { m_port = (SerialPort) cp; } else { throw new IllegalStateException("unknown port type"); } m_port.setSerialPortParams(m_speed, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); m_port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE); logger.debug("setting port speed to {}", m_speed); m_port.disableReceiveFraming(); m_port.enableReceiveThreshold(1); // m_port.disableReceiveTimeout(); m_port.enableReceiveTimeout(1000); m_in = m_port.getInputStream(); m_out = m_port.getOutputStream(); logger.info("successfully opened port {}", m_devName); return true; } catch (IOException e) { logger.error("cannot open port: {}, got IOException ", m_devName, e); } catch (PortInUseException e) { logger.error("cannot open port: {}, it is in use!", m_devName); } catch (UnsupportedCommOperationException e) { logger.error("got unsupported operation {} on port {}", e.getMessage(), m_devName); } catch (NoSuchPortException e) { logger.error("got no such port for {}", m_devName); } catch (IllegalStateException e) { logger.error("got unknown port type for {}", m_devName); } return false; } private void updateSerialProperties(String devName) { /* * By default, RXTX searches only devices /dev/ttyS* and * /dev/ttyUSB*, and will therefore not find devices that * have been symlinked. Adding them however is tricky, see below. */ // // first go through the port identifiers to find any that are not in // "gnu.io.rxtx.SerialPorts" // ArrayList<String> allPorts = new ArrayList<String>(); @SuppressWarnings("rawtypes") Enumeration portList = CommPortIdentifier.getPortIdentifiers(); while (portList.hasMoreElements()) { CommPortIdentifier id = (CommPortIdentifier) portList.nextElement(); if (id.getPortType() == CommPortIdentifier.PORT_SERIAL) { allPorts.add(id.getName()); } } logger.trace("ports found from identifiers: {}", StringUtils.join(allPorts, ":")); // // now add our port so it's in the list // if (!allPorts.contains(devName)) { allPorts.add(devName); } // // add any that are already in "gnu.io.rxtx.SerialPorts" // so we don't accidentally overwrite some of those ports String ports = System.getProperty("gnu.io.rxtx.SerialPorts"); if (ports != null) { ArrayList<String> propPorts = new ArrayList<String>(Arrays.asList(ports.split(":"))); for (String p : propPorts) { if (!allPorts.contains(p)) { allPorts.add(p); } } } String finalPorts = StringUtils.join(allPorts, ":"); logger.trace("final port list: {}", finalPorts); // // Finally overwrite the "gnu.io.rxtx.SerialPorts" System property. // // Note: calling setProperty() is not threadsafe. All bindings run in // the same address space, System.setProperty() is globally visible // to all bindings. // This means if multiple bindings use the serial port there is a // race condition where two bindings could be changing the properties // at the same time // System.setProperty("gnu.io.rxtx.SerialPorts", finalPorts); } @Override public void close() { if (m_port != null) { m_port.close(); } m_port = null; } }