org.ros.android.android_acm_serial.AcmDevice.java Source code

Java tutorial

Introduction

Here is the source code for org.ros.android.android_acm_serial.AcmDevice.java

Source

/*
 * Copyright (C) 2011 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.ros.android.android_acm_serial;

import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;

import com.google.common.base.Preconditions;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ros.exception.RosRuntimeException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * @author damonkohler@google.com (Damon Kohler)
 */
public class AcmDevice {

    private static final int CONTROL_TRANSFER_TIMEOUT = 3000; // ms

    private final UsbDeviceConnection usbDeviceConnection;
    private final UsbDevice usbDevice;
    private final UsbInterface usbInterface;
    private final InputStream inputStream;
    private final OutputStream outputStream;
    private final UsbRequestPool usbRequestPool;

    private static final Log log = LogFactory.getLog(AcmDevice.class);

    /**
     * Auxiliary data class. Used to group the pair of USB endpoints
     * used for ACM communication
     */
    private class AcmUsbEndpoints {
        private final UsbEndpoint incoming;
        private final UsbEndpoint outgoing;

        public AcmUsbEndpoints(UsbEndpoint incoming, UsbEndpoint outgoing) {
            this.incoming = incoming;
            this.outgoing = outgoing;
        }

        private UsbEndpoint getOutgoing() {
            return outgoing;
        }

        private UsbEndpoint getIncoming() {
            return incoming;
        }
    }

    public AcmDevice(UsbDeviceConnection usbDeviceConnection, UsbDevice usbDevice) {
        Preconditions.checkNotNull(usbDeviceConnection);
        this.usbDeviceConnection = usbDeviceConnection;

        // Go through all declared interfaces and automatically select the one that looks
        // like an ACM interface
        UsbInterface usbInterface = null;
        AcmUsbEndpoints acmUsbEndpoints = null;
        for (int i = 0; i < usbDevice.getInterfaceCount() && acmUsbEndpoints == null; i++) {
            usbInterface = usbDevice.getInterface(i);
            Preconditions.checkNotNull(usbInterface);
            Preconditions.checkState(usbDeviceConnection.claimInterface(usbInterface, true));
            acmUsbEndpoints = getAcmEndpoints(usbInterface);
        }
        if (acmUsbEndpoints == null) {
            throw new IllegalArgumentException(
                    "Couldn't find an interface that looks like ACM on this USB device: " + usbDevice);
        }

        this.usbInterface = usbInterface;
        this.usbDevice = usbDevice;
        usbRequestPool = new UsbRequestPool(usbDeviceConnection);
        usbRequestPool.addEndpoint(acmUsbEndpoints.getOutgoing(), null);
        usbRequestPool.start();

        outputStream = new AcmOutputStream(usbRequestPool, acmUsbEndpoints.getOutgoing());
        inputStream = new AcmInputStream(usbDeviceConnection, acmUsbEndpoints.getIncoming());
    }

    /**
     * Goes through the given UsbInterface's endpoints and finds the incoming
     * and outgoing bulk transfer endpoints.
     * @return Array with incoming (first) and outgoing (second) USB endpoints
     * @return <code>null</code>  in case either of the endpoints is not found
     */
    private AcmUsbEndpoints getAcmEndpoints(UsbInterface usbInterface) {
        UsbEndpoint outgoingEndpoint = null;
        UsbEndpoint incomingEndpoint = null;
        for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
            UsbEndpoint endpoint = usbInterface.getEndpoint(i);
            log.info("Interface: " + i + "/" + "Class: " + usbInterface.getInterfaceClass());
            if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) {
                if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                    log.info("Endpoint " + i + "/" + usbInterface.getEndpointCount() + ": " + endpoint + ". Type = "
                            + endpoint.getType());
                    outgoingEndpoint = endpoint;
                } else if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                    log.info("Endpoint " + i + "/" + usbInterface.getEndpointCount() + ": " + endpoint + ". Type = "
                            + endpoint.getType());
                    incomingEndpoint = endpoint;
                }
            }
        }
        if (outgoingEndpoint == null || incomingEndpoint == null) {
            return null;
        } else {
            return new AcmUsbEndpoints(incomingEndpoint, outgoingEndpoint);
        }
    }

    public void setLineCoding(BitRate bitRate, StopBits stopBits, Parity parity, DataBits dataBits) {
        ByteBuffer buffer = ByteBuffer.allocate(7);
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        buffer.putInt(bitRate.getBitRate());
        buffer.put(stopBits.getStopBits());
        buffer.put(parity.getParity());
        buffer.put(dataBits.getDataBits());
        setLineCoding(buffer.array());
    }

    private void setLineCoding(byte[] lineCoding) {
        int byteCount;
        byteCount = usbDeviceConnection.controlTransfer(0x21, 0x20, 0, 0, lineCoding, lineCoding.length,
                CONTROL_TRANSFER_TIMEOUT);
        Preconditions.checkState(byteCount == lineCoding.length, "Failed to set line coding.");
    }

    public UsbDevice getUsbDevice() {
        return this.usbDevice;
    }

    public UsbInterface getUsbInterface() {
        return usbInterface;
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    public OutputStream getOutputStream() {
        return outputStream;
    }

    public void close() {
        usbDeviceConnection.releaseInterface(usbInterface);
        usbDeviceConnection.close();
        try {
            inputStream.close();
            outputStream.close();
        } catch (IOException e) {
            throw new RosRuntimeException(e);
        }
    }
}