package org.droidplanner.services.android.impl.communication.connection.usb;
import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.util.Log;
import com.o3dr.services.android.lib.gcs.link.LinkConnectionStatus;
import org.droidplanner.services.android.impl.communication.connection.AndroidMavLinkConnection;
import org.droidplanner.services.android.impl.core.MAVLink.connection.MavLinkConnectionTypes;
import org.droidplanner.services.android.impl.core.model.Logger;
import org.droidplanner.services.android.impl.utils.AndroidLogger;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map.Entry;
public class UsbConnection extends AndroidMavLinkConnection {
private static final String TAG = UsbConnection.class.getSimpleName();
private static final int FTDI_DEVICE_VENDOR_ID = 0x0403;
protected final int mBaudRate;
private UsbConnectionImpl mUsbConnection;
public UsbConnection(Context parentContext, int baudRate) {
super(parentContext);
mBaudRate = baudRate;
}
@Override
protected void closeConnection() throws IOException {
if (mUsbConnection != null) {
mUsbConnection.closeUsbConnection();
}
}
@Override
protected void loadPreferences() {
}
@Override
protected void openConnection(Bundle connectionExtras) throws IOException {
if (mUsbConnection != null) {
try {
mUsbConnection.openUsbConnection(connectionExtras);
Log.d(TAG, "Reusing previous usb connection.");
return;
} catch (IOException e) {
Log.e(TAG, "Previous usb connection is not usable.", e);
mUsbConnection = null;
}
}
if (isFTDIdevice(context)) {
final UsbConnectionImpl tmp = new UsbFTDIConnection(context, this, mBaudRate);
try {
tmp.openUsbConnection(connectionExtras);
// If the call above is successful, 'mUsbConnection' will be set.
mUsbConnection = tmp;
Log.d(TAG, "Using FTDI usb connection.");
} catch (IOException e) {
Log.d(TAG, "Unable to open a ftdi usb connection. Falling back to the open "
+ "usb-library.", e);
}
}
// Fallback
if (mUsbConnection == null) {
final UsbConnectionImpl tmp = new UsbCDCConnection(context, this, mBaudRate);
// If an error happens here, let it propagate up the call chain since this is the fallback.
tmp.openUsbConnection(connectionExtras);
mUsbConnection = tmp;
Log.d(TAG, "Using open-source usb connection.");
}
}
private static boolean isFTDIdevice(Context context) {
UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
final HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
if (deviceList == null || deviceList.isEmpty()) {
return false;
}
for (Entry<String, UsbDevice> device : deviceList.entrySet()) {
if (device.getValue().getVendorId() == FTDI_DEVICE_VENDOR_ID) {
return true;
}
}
return false;
}
@Override
protected int readDataBlock(byte[] buffer) throws IOException {
if (mUsbConnection == null) {
throw new IOException("Uninitialized usb connection.");
}
return mUsbConnection.readDataBlock(buffer);
}
@Override
protected void sendBuffer(byte[] buffer) throws IOException {
if (mUsbConnection == null) {
throw new IOException("Uninitialized usb connection.");
}
mUsbConnection.sendBuffer(buffer);
}
@Override
public int getConnectionType() {
return MavLinkConnectionTypes.MAVLINK_CONNECTION_USB;
}
@Override
public String toString() {
if (mUsbConnection == null) {
return TAG;
}
return mUsbConnection.toString();
}
static abstract class UsbConnectionImpl {
protected final int mBaudRate;
protected final Context mContext;
private final UsbConnection parentConnection;
protected final Logger mLogger = AndroidLogger.getLogger();
protected UsbConnectionImpl(Context context, UsbConnection parentConn, int baudRate) {
mContext = context;
this.parentConnection = parentConn;
mBaudRate = baudRate;
}
protected void onUsbConnectionOpened(Bundle extras) {
parentConnection.onConnectionOpened(extras);
}
protected void onUsbConnectionStatus(LinkConnectionStatus connectionStatus) {
parentConnection.onConnectionStatus(connectionStatus);
}
protected abstract void closeUsbConnection() throws IOException;
protected abstract void openUsbConnection(Bundle extras) throws IOException;
protected abstract int readDataBlock(byte[] readData) throws IOException;
protected abstract void sendBuffer(byte[] buffer);
}
}