All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.digi.xbee.api.connection.android.AndroidUSBInputStream Maven / Gradle / Ivy

There is a newer version: 1.3.2
Show newest version
/**
 * Copyright 2017, Digi International Inc.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
package com.digi.xbee.api.connection.android;

import java.io.IOException;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.digi.xbee.api.utils.HexUtils;

import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;

/**
 * This class acts as a wrapper to read data from the USB Interface in Android
 * behaving like an {@code InputputStream} class.
 * 
 * @since 1.2.0
 */
public class AndroidUSBInputStream extends InputStream {

	// Constants.
	private static final int READ_BUFFER_SIZE = 1024;
	private static final int OFFSET = 2;
	private static final int READ_TIMEOUT = 100;

	private static final String ERROR_THREAD_NOT_INITIALIZED = "Read thread not initialized, call first 'startReadThread()'";

	// Variables.
	private UsbDeviceConnection usbConnection;

	private UsbEndpoint receiveEndPoint;

	private boolean working = false;

	private Thread receiveThread;

	private CircularByteBuffer readBuffer;

	private AndroidXBeeInterface androidInterface;

	private Logger logger;
	
	/**
	 * Class constructor. Instantiates a new {@code AndroidUSBInputStream}
	 * object with the given parameters.
	 * 
	 * @param androidInterface The XBee Android interface to which this
	 *                         {@code AndroidUSBInputStream} belongs to.
	 * @param readEndpoint The USB end point to use to read data from.
	 * @param connection The USB connection to use to read data from.
	 * 
	 * @see AndroidXBeeInterface
	 * @see android.hardware.usb.UsbDeviceConnection
	 * @see android.hardware.usb.UsbEndpoint
	 */
	public AndroidUSBInputStream(AndroidXBeeInterface androidInterface, UsbEndpoint readEndpoint, UsbDeviceConnection connection) {
		this.usbConnection = connection;
		this.receiveEndPoint = readEndpoint;
		this.androidInterface = androidInterface;
		this.logger = LoggerFactory.getLogger(AndroidUSBInputStream.class);
	}

	/*
	 * (non-Javadoc)
	 * @see java.io.InputStream#read()
	 */
	@Override
	public int read() throws IOException {
		byte[] buffer = new byte[1];
		read(buffer);
		return buffer[0] & 0xFF;
	}

	/*
	 * (non-Javadoc)
	 * @see java.io.InputStream#read(byte[])
	 */
	@Override
	public int read(byte[] buffer) throws IOException {
		return read(buffer, 0, buffer.length);
	}

	/*
	 * (non-Javadoc)
	 * @see java.io.InputStream#read(byte[], int, int)
	 */
	@Override
	public int read(byte[] buffer, int offset, int length) throws IOException {
		if (readBuffer == null)
			throw new IOException(ERROR_THREAD_NOT_INITIALIZED);

		long deadLine = System.currentTimeMillis() + READ_TIMEOUT;
		int readBytes = 0;
		while (System.currentTimeMillis() < deadLine && readBytes <= 0)
			readBytes = readBuffer.read(buffer, offset, length);
		if (readBytes <= 0)
			return -1;
		byte[] readData = new byte[readBytes];
		System.arraycopy(buffer, offset, readData, 0, readBytes);
		logger.debug("Received a read request of " + length + " bytes, returning " + readData.length + ": " + HexUtils.byteArrayToHexString(readData));
		return readBytes;
	}

	/*
	 * (non-Javadoc)
	 * @see java.io.InputStream#available()
	 */
	@Override
	public int available() throws IOException {
		if (readBuffer == null)
			throw new IOException(ERROR_THREAD_NOT_INITIALIZED);

		return readBuffer.availableToRead();
	}

	/*
	 * (non-Javadoc)
	 * @see java.io.InputStream#skip(long)
	 */
	@Override
	public long skip(long byteCount) throws IOException {
		if (readBuffer == null)
			throw new IOException(ERROR_THREAD_NOT_INITIALIZED);

		return readBuffer.skip((int)byteCount);
	}

	/**
	 * Starts the USB input stream read thread to start reading data from the
	 * USB Android connection.
	 * 
	 * @see #stopReadThread()
	 */
	public void startReadThread() {
		if (!working) {
			readBuffer = new CircularByteBuffer(READ_BUFFER_SIZE);
			receiveThread = new Thread() {
				@Override
				public void run() {
					working = true;
					while (working) {
						byte[] buffer = new byte[1024];
						int receivedBytes = usbConnection.bulkTransfer(receiveEndPoint, buffer, buffer.length, READ_TIMEOUT) - OFFSET;
						if (receivedBytes > 0) {
							byte[] data = new byte[receivedBytes];
							System.arraycopy(buffer, OFFSET, data, 0, receivedBytes);
							logger.debug("Message received: " + HexUtils.byteArrayToHexString(data));
							readBuffer.write(buffer, OFFSET, receivedBytes);
							// Notify interface so that XBee Reader is notified about data available.
							synchronized (androidInterface) {
								androidInterface.notify();
							}
						}
					}
				};
			};
			receiveThread.start();
		}
	}

	/**
	 * Stops the USB input stream read thread.
	 * 
	 * @see #startReadThread()
	 */
	public void stopReadThread() {
		working = false;
		if (receiveThread != null)
			receiveThread.interrupt();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy