I'am trying to make a android tablet communicate with a USB device (STM32 Nucleo). I developped a sketch available on github :
- the mobile application is developped with Xamarin and VS Studio. It acts as usb host
- the STM32 Nucleo application is developped with STMCube and uses it's USB stack to act as a CDC device.
- I developped a small master/slave protocol to echange "register" id/value. The device is the slave.
I managed to make it work using the Android.hardware.usb API. But I must use a native C shared object library for communication as it used on other platform, and that's where I am having trouble now. I embbeded the library using swig and build it with VS Studio. I tried two ways to make the library communicate with the device :
- From the Android side get permission and fd and pass it to the library that does standard read/write opérations.
- From the Android do the same as above, but also pass with fd the endpoints numbers that uses the linux usbdevice_fs API to call bulk transfers; more o less like presented at that question.
Both methods fail and returns an error about the fd that does not exist. I checked the fd and and enpoints values, they're same as the Android. I launched the android usb device monitor, I can't find the created fd. I can't use any android shell like termux to list the process /proc tree. But still I can use tehm in the Android side.
From the community I checked that passing fd to the native library is the right method. I don't know what to do now, is there some more permission to ask ?
Below is how I retrieve the fd :
_devHandle.usbdev = _devHandle.usbManager.DeviceList[name];
// Ask for permission to access the created device
if (!_devHandle.usbManager.HasPermission(_devHandle.usbdev))
{
PendingIntent pi = PendingIntent.GetBroadcast((ContextWrapper)_context, 0, new Intent(ACTION_USB_PERMISSION), 0);
_devHandle.usbManager.RequestPermission(_devHandle.usbdev, pi);
/* We check the permission was given
*/
if (!_devHandle.usbManager.HasPermission(_devHandle.usbdev))
{
// Loose !
Log.Debug("pandavcom", "FAILED : did not have persmission to open device" + _devHandle.usbdev.DeviceName);
return;
}
}
// Now open the port, with the USB Manager : we get the fd/enpoints and pass it to library, no more
_devHandle.connection = _devHandle.usbManager.OpenDevice(_devHandle.usbdev);
if (_devHandle.connection != null)
{
if (OpenInterface(_devHandle.usbdev, _devHandle.connection, ref _devHandle.usbIface, ref _devHandle.ep_in, ref _devHandle.ep_out) == 0)
{
_devHandle.fd = _devHandle.connection.FileDescriptor;
Log.Debug("pandavcom", "opened device endpoint" + _devHandle.usbdev.DeviceName + "with descriptor: " + _devHandle.fd);
}
else
{
Log.Debug("pandavcom", "FAILED : open device endpoint" + _devHandle.usbdev.DeviceName);
}
}
So I made it working, thanks tho the guys of the libusb mailing list. Actually the mad resistor libusb could only send data to device. Now with the officiel libusb there's a way to do it, that is still recent.
So the process is :
get with android the device permission and the file descriptor
pass the file descriptor to your native code and execute this step to initliaze libusb on the fd :
(FD = FileDescriptor from Android.USBManager)
The code above was sent over the mailing. An example of integration is available on my github project. I'm still validating this solution on more Android tablet.