|  | @@ -1,12 +1,12 @@
 | 
	
		
			
				|  |  |  /*
 | 
	
		
			
				|  |  |   * 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
 | 
	
	
		
			
				|  | @@ -16,12 +16,16 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  package org.ros.android.android_acm_serial;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -import com.google.common.base.Preconditions;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  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;
 | 
	
	
		
			
				|  | @@ -38,40 +42,91 @@ 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;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  public AcmDevice(UsbDeviceConnection usbDeviceConnection, UsbInterface usbInterface) {
 | 
	
		
			
				|  |  | +  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);
 | 
	
		
			
				|  |  | -    Preconditions.checkNotNull(usbInterface);  
 | 
	
		
			
				|  |  | -    Preconditions.checkState(usbDeviceConnection.claimInterface(usbInterface, true));
 | 
	
		
			
				|  |  |      this.usbDeviceConnection = usbDeviceConnection;
 | 
	
		
			
				|  |  | -    this.usbInterface = usbInterface;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    UsbEndpoint outgoingEndpoint = null;
 | 
	
		
			
				|  |  | -    UsbEndpoint incomingEndpoint = null;
 | 
	
		
			
				|  |  | -    for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
 | 
	
		
			
				|  |  | -      UsbEndpoint endpoint = usbInterface.getEndpoint(i);
 | 
	
		
			
				|  |  | -      if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
 | 
	
		
			
				|  |  | -        if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
 | 
	
		
			
				|  |  | -          outgoingEndpoint = endpoint;
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -          incomingEndpoint = endpoint;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +    // 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 (outgoingEndpoint == null || incomingEndpoint == null) {
 | 
	
		
			
				|  |  | -      throw new IllegalArgumentException("Not all endpoints found.");
 | 
	
		
			
				|  |  | +    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(outgoingEndpoint, null);
 | 
	
		
			
				|  |  | +    usbRequestPool.addEndpoint(acmUsbEndpoints.getOutgoing(), null);
 | 
	
		
			
				|  |  |      usbRequestPool.start();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    outputStream = new AcmOutputStream(usbRequestPool, outgoingEndpoint);
 | 
	
		
			
				|  |  | -    inputStream = new AcmInputStream(usbDeviceConnection, incomingEndpoint);
 | 
	
		
			
				|  |  | +    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) {
 | 
	
	
		
			
				|  | @@ -92,6 +147,14 @@ public class AcmDevice {
 | 
	
		
			
				|  |  |      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;
 | 
	
		
			
				|  |  |    }
 |