Java tutorial
/** * openHAB, the open Home Automation Bus. * Copyright (C) 2010-2012, openHAB.org <admin@openhab.org> * * See the contributors.txt file in the distribution for a * full listing of individual contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses>. * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or * combining it with Eclipse (or a modified version of that library), * containing parts covered by the terms of the Eclipse Public License * (EPL), the licensors of this Program grant you additional permission * to convey the resulting work. */ package ch.wir_entwickeln.yavanna.serialport; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.TooManyListenersException; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import purejavacomm.CommPortIdentifier; import purejavacomm.PortInUseException; import purejavacomm.SerialPort; import purejavacomm.SerialPortEvent; import purejavacomm.SerialPortEventListener; import purejavacomm.UnsupportedCommOperationException; /** * This class represents a serial port. * * @author Kai Kreuzer * @author Ronny Stauffer * */ public class SerialPortCCI implements SerialPortEventListener { public static final int DEFAULT_BAUD_RATE = 9600; public static final DataBits DEFAULT_DATA_BITS = DataBits.EIGHT; public static final StopBits DEFAULT_STOP_BITS = StopBits.ONE; public static final Parity DEFAULT_PARITY = Parity.NONE; public enum DataBits { SEVEN(SerialPort.DATABITS_7), EIGHT(SerialPort.DATABITS_8); private final int numberOfDataBits; private DataBits(int numberOfDataBits) { assert numberOfDataBits == SerialPort.DATABITS_7 || numberOfDataBits == SerialPort.DATABITS_8; this.numberOfDataBits = numberOfDataBits; } public int getNumberOfDataBits() { return numberOfDataBits; } } public enum StopBits { ONE(SerialPort.STOPBITS_1), TWO(SerialPort.STOPBITS_2); private final int numberOfStopBits; private StopBits(int numberOfStopBits) { assert numberOfStopBits == SerialPort.STOPBITS_1 || numberOfStopBits == SerialPort.STOPBITS_2; this.numberOfStopBits = numberOfStopBits; } public int getNumberOfStopBits() { return numberOfStopBits; } } public enum Parity { NONE(SerialPort.PARITY_NONE), EVEN(SerialPort.PARITY_EVEN), ODD(SerialPort.PARITY_ODD); private final int parity; private Parity(int parity) { assert parity == SerialPort.PARITY_NONE || parity == SerialPort.PARITY_EVEN || parity == SerialPort.PARITY_ODD; this.parity = parity; } public int getParity() { return parity; } } private static final Logger logger = LoggerFactory.getLogger(SerialPortCCI.class); private final String portName; private final int baudRate; private final DataBits dataBits; private final StopBits stopBits; private final Parity parity; private SerialPort serialPort; private InputStream inputStream; private OutputStream outputStream; // To keep track of all data receivers protected Collection<SerialPortDataReceiver> dataReceivers = Collections .synchronizedSet(new HashSet<SerialPortDataReceiver>()); public SerialPortCCI(String portName) { this(portName, DEFAULT_BAUD_RATE); } public SerialPortCCI(String portName, int baudRate) { this(portName, baudRate, DEFAULT_DATA_BITS, DEFAULT_STOP_BITS, DEFAULT_PARITY); } public SerialPortCCI(String portName, int baudRate, DataBits dataBits, StopBits stopBits, Parity parity) { if (portName == null || portName.isEmpty()) { throw new IllegalArgumentException("portName must not be undefined or empty!"); } if (!(baudRate > 0)) { throw new IllegalArgumentException("baudRate must be > 0!"); } if (dataBits == null) { throw new NullPointerException("dataBits must not be undefined!"); } if (stopBits == null) { throw new NullPointerException("stopBits must not be undefined!"); } if (parity == null) { throw new NullPointerException("parity must not be undefined!"); } this.portName = portName; this.baudRate = baudRate; this.dataBits = dataBits; this.stopBits = stopBits; this.parity = parity; } public String getPort() { return portName; } public void addDataReceiver(SerialPortDataReceiver dataReceiver) { dataReceivers.add(dataReceiver); logger.debug("Data receiver have been added."); } public void removeDataReceiver(SerialPortDataReceiver dataReceiver) { dataReceivers.remove(dataReceiver); } /** * Initialize (= opens) the serial port. * * @throws SerialPortInitializationException If the serial port cannot be opened. */ @SuppressWarnings("rawtypes") public synchronized void initialize() throws SerialPortInitializationException { // Iterate over all available ports and if the requested port is found, initialize it CommPortIdentifier requestedPortID = null; Enumeration portIDList = CommPortIdentifier.getPortIdentifiers(); while (portIDList.hasMoreElements()) { CommPortIdentifier portID = (CommPortIdentifier) portIDList.nextElement(); if (portID.getPortType() == CommPortIdentifier.PORT_SERIAL) { if (portID.getName().equals(portName)) { logger.debug("Serial port {} has been found.", portName); requestedPortID = portID; } } } if (requestedPortID != null) { // Open the serial port try { serialPort = (SerialPort) requestedPortID.open("openHAB", 2000); } catch (PortInUseException e) { throw new SerialPortInitializationException(e); } try { try { // Set port parameters serialPort.setSerialPortParams(baudRate, dataBits.getNumberOfDataBits(), stopBits.getNumberOfStopBits(), parity.getParity()); } catch (UnsupportedCommOperationException e) { throw new SerialPortInitializationException(e); } // Get the input stream try { inputStream = serialPort.getInputStream(); } catch (IOException e) { throw new SerialPortInitializationException(e); } // Get the output stream try { outputStream = serialPort.getOutputStream(); } catch (IOException e) { throw new SerialPortInitializationException(e); } try { serialPort.addEventListener(this); } catch (TooManyListenersException e) { throw new SerialPortInitializationException(e); } // Activate the DATA_AVAILABLE notifier serialPort.notifyOnDataAvailable(true); } catch (SerialPortInitializationException e) { serialPort.close(); serialPort = null; } } else { StringBuilder availablePorts = new StringBuilder(); Enumeration portIDList2 = CommPortIdentifier.getPortIdentifiers(); while (portIDList2.hasMoreElements()) { CommPortIdentifier portID2 = (CommPortIdentifier) portIDList2.nextElement(); if (portID2.getPortType() == CommPortIdentifier.PORT_SERIAL) { availablePorts.append(String.format("%s\n", portID2.getName())); } } throw new SerialPortInitializationException( String.format("Serial port %s could not be found. Available ports are:\n%s", portName, availablePorts.toString())); } } private static final int INPUT_BUFFER_SIZE = 1024; public synchronized void serialEvent(SerialPortEvent event) { switch (event.getEventType()) { case SerialPortEvent.BI: case SerialPortEvent.OE: case SerialPortEvent.FE: case SerialPortEvent.PE: case SerialPortEvent.CD: case SerialPortEvent.CTS: case SerialPortEvent.DSR: case SerialPortEvent.RI: case SerialPortEvent.OUTPUT_BUFFER_EMPTY: break; case SerialPortEvent.DATA_AVAILABLE: // We get here if data has been received // Read data from serial port buffer int numberOfBytesRead = 0; byte[] inputBuffer = new byte[INPUT_BUFFER_SIZE]; try { while (inputStream.available() > 0) { numberOfBytesRead += inputStream.read(inputBuffer, numberOfBytesRead, INPUT_BUFFER_SIZE - numberOfBytesRead); } IOUtils.closeQuietly(inputStream); } catch (IOException e) { logger.debug("Error receiving data on serial port {}: {}", portName, e.getMessage()); } byte[] data = new byte[INPUT_BUFFER_SIZE]; int i = 0; for (byte inputBufferByte : inputBuffer) { if ((inputBufferByte & 0x80) > 0) { data[i++] = inputBufferByte; } } byte[] processBuffer = Arrays.copyOf(data, i); for (SerialPortDataReceiver dataReceiver : dataReceivers) { dataReceiver.processReceived(processBuffer); } break; } } /** * Sends data on the serial port. * * @param data The data to send. */ public synchronized void send(byte[] data) { String formattedData = new String(data).replaceAll(Character.toString((char) 13), "<CR>"); logger.debug("Sending '{}' on serial port {}...", new String[] { formattedData, portName }); try { // Write data to serial port buffer for (byte dataByte : data) { outputStream.write(dataByte); try { Thread.sleep(30); } catch (InterruptedException e) { // Ignore exception } } outputStream.flush(); } catch (IOException e) { logger.error("Error sending data on serial port {}: {}", portName, e.getMessage()); } } /** * Closes the serial port. */ public synchronized void close() { serialPort.removeEventListener(); try { inputStream.close(); } catch (IOException e) { logger.warn("Error closing serial port {}!", portName); } try { outputStream.close(); } catch (IOException e) { logger.warn("Error closing serial port {}!", portName); } serialPort.close(); serialPort = null; } }