I consider trying to compile a certain C-programm which allows the control of Gembird SilverShield power outlets via USB for android. On my android HDMI TV-stick this would be very useful. There is an open project for this. It works under Linux and depends on libusb. The target platform is android ICS. I want to develop on Ubuntu Linux. What are the chances I get it working? What are the required steps. Setup android SDK, NDK, crosscompiler ...
There is an older question here, related to libusb on android but no information how.
Is it maybe easier to port the application to androids own usb library?
Libusb can work on a non-rooted android (provided the device supports USB host ... this is VERY important as not all devices do). You need to use the standard android USB stack. You can then get a device descriptor from the USBDevice and pass that over to libusb.
Unfortunately you also need to modify libusb. Fortunately other people have explained how you need to modify LibUSB.
LibUSB has been modified here.
Good luck!
Edit:
First you need to define a broadcast receiver:
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action))
{
synchronized (this)
{
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
{
if(device != null)
{
UsbDeviceConnection deviceConnection = mUsbManager.openDevice( device );
Log.d( "USB", deviceConnection.getSerial() );
}
}
else
{
Log.d( "USB", "permission denied for device " + device);
}
}
}
}
}
Now you need to create a USBManager and enumerate the devices:
mUsbManager = (UsbManager) getSystemService( Context.USB_SERVICE );
HashMap< String, UsbDevice > stringDeviceMap = mUsbManager.getDeviceList();
Collection< UsbDevice > usbDevices = stringDeviceMap.values();
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent( ACTION_USB_PERMISSION ), 0 );
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver( mUsbReceiver, filter );
Iterator< UsbDevice > usbDeviceIter = usbDevices.iterator();
while( usbDeviceIter.hasNext() )
{
if ( USBDeviceValid( usbDevice ) )
{
// Request permission to access the device.
mUsbManager.requestPermission( usbDevice, mPermissionIntent );
// Open the device.
UsbDeviceConnection connection = mUsbManager.openDevice( usbDevice );
int fd = connection.getFileDescriptor();
// Now pass the file descriptor to libusb through a native call.
}
}
Edit 2:
Getting libusb to build is just a matter of putting the files somewhere handy (I put them in jni/libusb) and then adding the following lines to your Android.mk:
include $(CLEAR_VARS)
LOCAL_MODULE := libusb
LOCAL_SRC_FILES := libusb/core.c libusb/descriptor.c libusb/io.c libusb/sync.c libusb/os/linux_usbfs.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
The solution I implemented is to open the USB device using the Java APIs and then using the file descriptor with libusb.I used libusb from openni project by primesense(https://github.com/OpenNI/OpenNI2)
Code bits:
int LibUsbAndroid::android_open(libusb_device *device, libusb_device_handle **devHandle)
{
int fd = USBJNICallbacks::getCallback()->getDeviceFd(device->bus_number, device->device_address);
__android_log_print(ANDROID_LOG_VERBOSE,"USB","Got FD:%d",fd);
if(fd==-1)
{
__android_log_print(ANDROID_LOG_ERROR,"USB","android_open, bad fd");
return -1;
}
return libusb_open(device, devHandle, fd);
}
public int getDeviceFd(int busNumber, int deviceAddress) {
UsbDevice device = findDevice(busNumber, deviceAddress);
if(device!=null)
{
mReceivedPermission = false;
PermissionRequester pr = new PermissionRequester(device);
pr.run();
if(!mUsbManager.hasPermission(device))
{
Log.v("USB", "Requesting permissiom to device");
mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filterPermission = new IntentFilter(ACTION_USB_PERMISSION);
mContext.registerReceiver(mUsbPermissionReceiver, filterPermission);
mUsbManager.requestPermission(device, mPermissionIntent);
}
else
{
Log.v("USB", "Already has permission");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mReceivedPermission = true;
Log.v("USB", "Opening device");
OpenDevice od = openDevice(device);
Log.v("USB", "Adding to open devices");
mOpenDevices.put(""+busNumber+"/"+deviceAddress, od);
}
Log.v("USB", "Waiting for permission");
waitForPermissionResult();
OpenDevice od = mOpenDevices.get(""+busNumber+"/"+deviceAddress);
if(od!=null)
{
Log.v("USB", "Getting FD");
int result = od.mConnection.getFileDescriptor();
Log.i("USB","USB File desc:"+result);
return result;
}
else
{
Log.v("USB", "Error getting FD");
return -1;
}
}
return -1;
}
private BroadcastReceiver mUsbPermissionReceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
Log.v("USB", "Received permission result");
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
Log.v("USB", "Received permission result OK");
if(device != null){
Log.v("USB", "Device OK");
mContext.unregisterReceiver(this);
Log.v("USB", "Openning device");
OpenDevice od = openDevice(device);
Log.v("USB", "Adding to open device list");
mOpenDevices.put(""+od.mBus+"/"+od.mAddress,od);
Log.v("USB", "Received permission is true");
mReceivedPermission = true;
}
else {
Log.d(TAG, "permission denied for device " + device);
}
}
}
}
}
};
public OpenDevice openDevice(UsbDevice device) {
UsbDeviceConnection connection = mUsbManager.openDevice(device);
Log.i("USB","Device name="+device.getDeviceName());
int bus = getBusNumber(device.getDeviceName());
int address = getAddress(device.getDeviceName());
return new OpenDevice(device, connection, bus, address);
}
int API_EXPORTED libusb_open(libusb_device *dev,
libusb_device_handle **handle, int fd)
{
struct libusb_context *ctx = DEVICE_CTX(dev);
struct libusb_device_handle *_handle;
size_t priv_size = usbi_backend->device_handle_priv_size;
int r;
usbi_dbg("open %d.%d", dev->bus_number, dev->device_address);
_handle = malloc(sizeof(*_handle) + priv_size);
if (!_handle)
return LIBUSB_ERROR_NO_MEM;
r = usbi_mutex_init(&_handle->lock, NULL);
if (r) {
free(_handle);
return LIBUSB_ERROR_OTHER;
}
_handle->dev = libusb_ref_device(dev);
_handle->claimed_interfaces = 0;
memset(&_handle->os_priv, 0, priv_size);
r = usbi_backend->open(_handle,fd);
if (r < 0) {
usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r);
libusb_unref_device(dev);
usbi_mutex_destroy(&_handle->lock);
free(_handle);
return r;
}
usbi_mutex_lock(&ctx->open_devs_lock);
list_add(&_handle->list, &ctx->open_devs);
usbi_mutex_unlock(&ctx->open_devs_lock);
*handle = _handle;
/* At this point, we want to interrupt any existing event handlers so
* that they realise the addition of the new device's poll fd. One
* example when this is desirable is if the user is running a separate
* dedicated libusb events handling thread, which is running with a long
* or infinite timeout. We want to interrupt that iteration of the loop,
* so that it picks up the new fd, and then continues. */
usbi_fd_notification(ctx);
return 0;
}
static int op_open(struct libusb_device_handle *handle, int fd)
{
struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
char filename[PATH_MAX];
_get_usbfs_path(handle->dev, filename);
usbi_dbg("opening %s", filename);
hpriv->fd = fd;
if (hpriv->fd < 0) {
if (errno == EACCES) {
usbi_err(HANDLE_CTX(handle), "libusb couldn't open USB device %s: "
"Permission denied.", filename);
usbi_err(HANDLE_CTX(handle),
"libusb requires write access to USB device nodes.");
return LIBUSB_ERROR_ACCESS;
} else if (errno == ENOENT) {
usbi_err(HANDLE_CTX(handle), "libusb couldn't open USB device %s: "
"No such file or directory.", filename);
return LIBUSB_ERROR_NO_DEVICE;
} else {
usbi_err(HANDLE_CTX(handle),
"open failed, code %d errno %d", hpriv->fd, errno);
return LIBUSB_ERROR_IO;
}
}
return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
}
Even if you get it compiled, Android is probably not going to let you access the USB device through libusb unless your device is rooted. If it is feasible to port your app to Android's native USB stack, that would almost certainly be a more stable solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With