edu.hawaii.soest.kilonalu.utilities.SerialChannel.java Source code

Java tutorial

Introduction

Here is the source code for edu.hawaii.soest.kilonalu.utilities.SerialChannel.java

Source

/**
 *  Copyright: 2010 Regents of the University of Hawaii and the
 *             School of Ocean and Earth Science and Technology
 *    Purpose: To provide a Java NIO channel for serial communication
 *    Authors: Christopher Jones
 *
 * $HeadURL$
 * $LastChangedDate$
 * $LastChangedBy$
 * $LastChangedRevision$
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package edu.hawaii.soest.kilonalu.utilities;

import edu.hawaii.soest.kilonalu.utilities.SerialWriter;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ReadOnlyBufferException;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.nio.channels.Channels;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.UnsupportedCommOperationException;

import org.apache.commons.codec.binary.Hex;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

/**
 *
 */
public class SerialChannel implements ByteChannel {

    /* The input stream underlying serial communication reads */
    private InputStream in;

    /* The output stream underlying serial communication writes */
    private OutputStream out;

    /* The buffered reader underlying serial communication reads */
    private BufferedReader serialReader;

    /* The serial writer underlying serial communication writes */
    private SerialWriter serialWriter;

    /** The serial write thread for all write operations */
    private Thread writeThread;

    /** The default serial port name used for serial communications */
    private static String DEFAULT_SERIAL_PORT = "/dev/ttyUSB0";

    /* The  serial port name used for serial communications */
    private String serialPortName = DEFAULT_SERIAL_PORT;

    /* The communications port identifier for the given serial port */
    private CommPortIdentifier portIdentifier;

    /* The serial port object representing the serial port */
    private SerialPort serialPort;

    /* A boolean field indicating the status of the serial connection */
    private boolean isOpen = false;

    /* The default log configuration file location */
    private final String DEFAULT_LOG_CONFIGURATION_FILE = "lib/log4j.properties";

    /* The log configuration file location */
    private String logConfigurationFile = DEFAULT_LOG_CONFIGURATION_FILE;

    /* The Logger instance used to log system messages */
    private static Logger logger = Logger.getLogger(SerialChannel.class);

    /**
     * Constructor: creates an empty SerialChannel object
     *
     * @param portName - the name of the communications port
     */
    public SerialChannel(String portName) {
        setSerialPort(portName);
        try {
            // establish the serial connection
            open();

        } catch (IOException ioe) {
            logger.debug("Couldn't open the serial port. " + "Error message is " + ioe.getMessage());
        }

    }

    private void open() throws IOException {
        try {

            this.portIdentifier = CommPortIdentifier.getPortIdentifier(this.serialPortName);

            if (portIdentifier.isCurrentlyOwned()) {
                logger.debug("Error: Port is currently in use.");
                throw new IOException("Error: Serial port is currently in use.");

            } else {

                CommPort commPort = portIdentifier.open(this.getClass().getName(), 2000);

                if (commPort instanceof SerialPort) {
                    this.serialPort = (SerialPort) commPort;
                    this.serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
                            SerialPort.PARITY_NONE);

                    this.in = serialPort.getInputStream();
                    this.serialReader = new BufferedReader(new InputStreamReader(this.in));
                    this.out = serialPort.getOutputStream();
                    this.serialWriter = new SerialWriter(this.out);
                    this.writeThread = new Thread(this.serialWriter, "SerialWriteThread");
                    this.writeThread.start();
                    this.isOpen = true;

                } else {
                    logger.debug("Error: Only serial ports are handled.");
                    throw new IOException("Error opening the the port. " + "The port is not a serial port.  Please "
                            + "provide a valid serial port name.");

                }
            }

        } catch (UnsupportedCommOperationException ucoe) {
            this.serialPort.close();
            throw new IOException(ucoe.getMessage());

        } catch (PortInUseException piue) {
            throw new IOException(piue.getMessage());

        } catch (NoSuchPortException nspe) {
            throw new IOException(nspe.getMessage());

        } catch (IOException ioe) {
            throw ioe;
        }
    }

    /**
     * A method used to read bytes from the serial port
     *
     * @param readBuffer - the ByteBuffer used to store the bytes read
     * @return count - the number of bytes read as an integer
     */
    public int read(ByteBuffer readBuffer) throws IOException {

        //byte[] buffer = new byte[8192];
        StringBuffer buffer = new StringBuffer();
        int count = 0;
        String line = null;

        try {
            line = this.serialReader.readLine();

            // only append the line read if it is not null, has a length
            // greater than zero, and isn't just a single null character.
            if (line != null && line.length() > 0 && !line.equals(new String(new byte[] { 0x00 }))) {
                buffer.append(line);
                buffer.append("\r\n"); //add termination bytes back into the line

                // filter null characters out of the string before putting the
                // bytes into the ByteBuffer.
                byte[] lineAsBytes = buffer.toString().getBytes();
                for (int i = 0; i < lineAsBytes.length; i++) {
                    if (lineAsBytes[i] != 0x00) {
                        readBuffer.put(lineAsBytes[i]);
                        count++;
                    }
                }

            } else {
                count = 0;

            }

        } catch (BufferOverflowException bofe) {
            logger.info("There a problem reading from the serial port: " + bofe.getMessage());
            this.serialPort.close();
            throw new IOException(bofe.getMessage());

        } catch (ReadOnlyBufferException robe) {
            logger.info("There a problem reading from the serial port: " + robe.getMessage());
            this.serialPort.close();
            throw new IOException(robe.getMessage());

        }
        return count;

    }

    /**
     * A method used to get the status of the serial port connection
     *
     * @return isOpen - true if the serial port is open
     */
    public boolean isOpen() {
        return this.isOpen;
    }

    /**
     * A method used to close the serial port connection
     */
    public void close() throws IOException {
        try {
            this.serialPort.close();
            this.isOpen = false;

        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

    /**
     * A method used to write bytes to the serial port
     *
     * @param  writeBuffer - The ByteBuffer with the bytes to write
     * @return count       - The number of bytes written to the serial port
     */
    public int write(ByteBuffer writeBuffer) throws IOException {

        try {
            return this.serialWriter.write(writeBuffer);

        } catch (IOException ioe) {
            throw ioe;

        }
    }

    /**
     * A method that returns the name of the serial port used for serial
     * communication.  This defaults to "/dev/ttyS0".  On Windows, this
     * should be set to the appropriate comm port (e.g. COM1).  For use with 
     * FTDI serial-to-USB adapters on Linux, use "/dev/ttyUSB0".
     *
     * @return serialPort - the name of the serial port
     */
    public String getSerialPort() {
        return this.serialPortName;

    }

    /**
     * A method used to set the name of the serial port used for serial
     * communication.
     */
    private void setSerialPort(String serialPortName) {
        this.serialPortName = serialPortName;

    }

}