package de.uniluebeck.itm.wsn.drivers.core.serialport; import de.uniluebeck.itm.wsn.drivers.core.AbstractConnection; import de.uniluebeck.itm.wsn.drivers.core.exception.PortNotFoundException; import de.uniluebeck.itm.wsn.drivers.core.util.JarUtil; import gnu.io.*; import org.apache.commons.lang3.SystemUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.util.TooManyListenersException; import static com.google.common.base.Preconditions.checkState; /** * A simple serial port connection implementation for general purpose use of the serial port. * * @author Malte Legenhausen */ public abstract class AbstractSerialPortConnection extends AbstractConnection implements SerialPortConnection, SerialPortEventListener { /** * Logger for this class. */ private static final Logger LOG = LoggerFactory.getLogger(AbstractSerialPortConnection.class); private static final int[] DEFAULT_CHANNELS = new int[]{ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }; /** * The default baud rate. */ public static final int DEFAULT_NORMAL_BAUD_RATE = 115200; /** * The default program baud rate. */ public static final int DEFAULT_PROGRAM_BAUD_RATE = 38400; /** * The maximum timeout for a connection try. */ protected static final int MAX_CONNECTION_TIMEOUT = 1000; /** * The baud rate that is used for normal operation. */ protected int normalBaudRate = DEFAULT_NORMAL_BAUD_RATE; /** * the baud rate that is used for programming the device. */ protected int programBaudRate = DEFAULT_PROGRAM_BAUD_RATE; /** * Serial port stop bits. */ protected int stopBits = SerialPort.STOPBITS_1; /** * Serial port data bits. */ protected int dataBits = SerialPort.DATABITS_8; /** * Parity bit that is used for normal operations. */ protected int normalParityBit = SerialPort.PARITY_NONE; /** * Parity bit that is used for programing. */ protected int programParityBit = SerialPort.PARITY_NONE; /** * The serial port instance. */ protected SerialPort serialPort; static { if (System.getProperty("disableEmbeddedRXTX") == null) { LOG.trace("Loading rxtxSerial from jar file"); JarUtil.loadLibrary("rxtxSerial"); } if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_MAC_OSX) { File lockDir = new File("/var/lock"); if (!lockDir.exists() || !lockDir.isDirectory()) { LOG.warn("No /var/lock directory found. Needed for RXTX Library. Try mkdir /var/lock."); } if (!lockDir.canRead() || !lockDir.canWrite()) { LOG.warn("/var/lock directory is not read and writable. Try chmod 777 /var/lock."); } } } @Override public SerialPort getSerialPort() { return serialPort; } @Override public void connect(final String port) throws IOException { super.connect(port); checkState(serialPort == null, "Serial port is already set. Disconnect first before retry."); try { connectSerialPort(port); setConnected(); } catch (final PortInUseException e) { LOG.error("Port {} already in use.", port); throw new IOException(e); } catch (final ClassCastException e) { LOG.error("Port {} is not a serial port.", port); throw new IOException(e); } catch (NoSuchPortException e) { LOG.warn("Port {} not found.", port); throw new PortNotFoundException(e); } } protected void connectSerialPort(final String port) throws PortInUseException, IOException, NoSuchPortException { serialPort = (SerialPort) CommPortIdentifier.getPortIdentifier(port).open("tr-gateway", MAX_CONNECTION_TIMEOUT); serialPort.notifyOnDataAvailable(true); try { serialPort.addEventListener(this); } catch (TooManyListenersException e) { LOG.error("Listener already added.", e); } setUri(port); setOutputStream(serialPort.getOutputStream()); setInputStream(serialPort.getInputStream()); setSerialPortMode(SerialPortMode.NORMAL); } @Override public void setSerialPortMode(final SerialPortMode mode) { int baudRate = SerialPortMode.PROGRAM.equals(mode) ? programBaudRate : normalBaudRate; int parityBit = SerialPortMode.PROGRAM.equals(mode) ? programParityBit : normalParityBit; try { serialPort.setSerialPortParams(baudRate, dataBits, stopBits, parityBit); } catch (final UnsupportedCommOperationException e) { LOG.warn("Problem while setting serial port params.", e); } serialPort.setDTR(false); serialPort.setRTS(false); LOG.debug("COM-Port parameters set to baud rate: " + serialPort.getBaudRate()); } @Override public void close() throws IOException { super.close(); if (serialPort != null) { serialPort.removeEventListener(); serialPort.close(); } } @Override public void serialEvent(final SerialPortEvent event) { switch (event.getEventType()) { case SerialPortEvent.DATA_AVAILABLE: signalDataAvailable(); break; default: LOG.debug("Serial event (other than data available): " + event); break; } } @Override public int[] getChannels() { return DEFAULT_CHANNELS; } public int getNormalBaudRate() { return normalBaudRate; } public void setNormalBaudRate(final int normalBaudRate) { this.normalBaudRate = normalBaudRate; } public int getProgramBaudRate() { return programBaudRate; } public void setProgramBaudRate(final int programBaudRate) { this.programBaudRate = programBaudRate; } public int getStopBits() { return stopBits; } public void setStopBits(final int stopBits) { this.stopBits = stopBits; } public int getDataBits() { return dataBits; } public void setDataBits(final int dataBits) { this.dataBits = dataBits; } public int getNormalParityBit() { return normalParityBit; } public void setNormalParityBit(final int normalParityBit) { this.normalParityBit = normalParityBit; } public int getProgramParityBit() { return programParityBit; } public void setProgramParityBit(final int programParityBit) { this.programParityBit = programParityBit; } }