/*
* This file is part of Android FTDI Serial
*
* Copyright (C) 2011 - Manuel Di Cerbo, Nexus-Computing GmbH
*
* Android FTDI Serial 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.
*
* Android FTDI Serial 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 Android FTDI Serial; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/*
* Thanks to the libftdi project http://www.intra2net.com/en/developer/libftdi/
*/
package ch.serverbox.android.ftdiusb;
import java.util.HashMap;
import java.util.Iterator;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
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 android.hardware.usb.UsbManager;
import android.util.Log;
//0403:6001 FTDI Serial
//0x81 EP IN
//0x02 EP OUT
/*
* handle.controlMsg(requestType = 0x40, request = 0, value = 0, index = 0, buffer = 0, timeout = 0)#reset
handle.controlMsg(requestType = 0x40, request = 0, value = 1, index = 0, buffer = 0, timeout = 0)#reset
handle.controlMsg(requestType = 0x40, request = 0, value = 2, index = 0, buffer = 0, timeout = 0)#reset
handle.controlMsg(requestType = 0x40, request = 0x03, value = 0x4138, index = 0, buffer = 0, timeout = 0)#9600 baudrate
*/
public class FTDI_USB_Handler {
protected static final String ACTION_USB_PERMISSION = "ch.serverbox.android.USB";
private static final String VID_PID = "0403:6001";
private UsbDeviceConnection conn = null;
private UsbInterface usbIf = null;
private UsbEndpoint epIN = null;
private UsbEndpoint epOUT = null;
protected Context activity = null;
private boolean mStopped = true;
protected Thread readThread = null;
public FTDI_USB_Handler(final Context a) {
activity = a;
readThread = new Thread() {
public void run() {
if (epIN != null) {
while (!isInterrupted()) {
int size;
byte[] buffer = new byte[64];
if (conn == null)
return;
size = conn.bulkTransfer(epIN, buffer, buffer.length, 0);
if (size > 2) {
byte[] buf_out = new byte[64];
for (int i = 2; i < buffer.length; i++) {
buf_out[i - 2] = buffer[i];
}
onDataReceived(buf_out, size - 2);
}
}
}
}
};
activity = a;
if (mStopped)
enumerate();
}
public void Stop() {
if (readThread.isAlive())
readThread.interrupt();
if (usbIf != null && conn != null) {
activity.unregisterReceiver(mPermissionReceiver);
conn.releaseInterface(usbIf);
conn.close();
}
}
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
UsbDevice dev = (UsbDevice) intent
.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (dev != null) {
if (String.format("%04X:%04X", dev.getVendorId(), dev.getProductId())
.equals(VID_PID)) {
if (usbIf != null && conn != null) {
conn.releaseInterface(usbIf);
conn.close();
}
}
}
}
}
};
private final BroadcastReceiver mPermissionReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
if (!intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
e("Permission not granted :(");
}
else {
l("Permission granted");
UsbDevice dev = (UsbDevice) intent
.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (dev != null) {
if (String.format("%04X:%04X", dev.getVendorId(),
dev.getProductId()).equals(VID_PID)) {
init_USB(dev);// has new thread
}
}
else {
e("device not present!");
}
}
}
}
};
private void enumerate() {
l("enumerating");
UsbManager usbman = (UsbManager) activity
.getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> devlist = usbman.getDeviceList();
Iterator<UsbDevice> deviter = devlist.values().iterator();
PendingIntent pi = PendingIntent.getBroadcast(activity, 0, new Intent(
ACTION_USB_PERMISSION), 0);
while (deviter.hasNext()) {
UsbDevice d = deviter.next();
l("Found device: "
+ String.format("%04X:%04X", d.getVendorId(), d.getProductId()));
if (String.format("%04X:%04X", d.getVendorId(), d.getProductId()).equals(
VID_PID)) {
// we need to upload the hex file, first request permission
l("Device under: " + d.getDeviceName());
activity.registerReceiver(mPermissionReceiver, new IntentFilter(
ACTION_USB_PERMISSION));
if (!usbman.hasPermission(d))
usbman.requestPermission(d, pi);
else
init_USB(d);
// init_USB(d);
break;
}
}
l("no more devices found");
}
private boolean init_USB(UsbDevice dev) {
showLog("Init_USB");
try {
if (dev == null)
return false;
UsbManager usbm = (UsbManager) activity
.getSystemService(Context.USB_SERVICE);
conn = usbm.openDevice(dev);
l("Interface Count: " + dev.getInterfaceCount());
l("Using "
+ String.format("%04X:%04X", dev.getVendorId(), dev.getProductId()));
if (!conn.claimInterface(dev.getInterface(0), true))
return false;
conn.controlTransfer(0x40, 0, 0, 0, null, 0, 0);// reset
conn.controlTransfer(0x40, 0, 1, 0, null, 0, 0);// clear Rx
conn.controlTransfer(0x40, 0, 2, 0, null, 0, 0);// clear Tx
conn.controlTransfer(0x40, 0x02, 0x1311, 0x40, null, 0, 0);// control flow
// XOFF/XON
// conn.controlTransfer(0x40, 0x04, 0x0008, 0, null, 0, 0); //data bit 8,
// parity none, stop bit 1, tx off
// conn.controlTransfer(0x40, 0x03, 0x809C, 0, null, 0, 0);//baudrate
// 19200
conn.controlTransfer(0x40, 0x03, 0x4138, 0, null, 0, 0);// baudrate 9600
usbIf = dev.getInterface(0);
for (int i = 0; i < usbIf.getEndpointCount(); i++) {
l("EP: " + String.format("0x%02X", usbIf.getEndpoint(i).getAddress()));
if (usbIf.getEndpoint(i).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
l("Bulk Endpoint");
if (usbIf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN)
epIN = usbIf.getEndpoint(i);
else
epOUT = usbIf.getEndpoint(i);
}
else {
l("Not Bulk");
}
}
activity.registerReceiver(mUsbReceiver, new IntentFilter(
UsbManager.ACTION_USB_DEVICE_DETACHED));
l("init_USB: epIN " + epIN + ", epOUT: " + epOUT);
readThread.start();
}
catch (final Exception e) {
e.printStackTrace();
}
showLog("init_USB finish");
return (epIN != null && epOUT != null);
}
public void write(final byte[] b) {
if (epOUT != null) {
new Thread(new Runnable() {
public void run() {
conn.bulkTransfer(epOUT, b, b.length, 0);
l("writing : " + new String(b));
}
}).start();
}
// showLog("write finish");
}
protected void onDataReceived(byte[] buffer, int size) {
l(buffer);
}
protected void l(Object s) {
Log.d("FTDI_USB", ">==< " + s.toString() + " >==<");
// showLog(s.toString());
}
protected void e(Object s) {
Log.e("FTDI_USB", ">==< " + s.toString() + " >==<");
showLog(s.toString());
}
void showLog(final String text){
Log.i("FTDI_USB", text);
}
}