I am trying to communicate with USB device from Android-based smartphone via OTG. I was able to communicate with my device using Android USB Host API. The problem of USB Host API solution is performance (single bulk transfer bounded by 16384 bytes).
The libusb can perform larger requests and now I am trying to integrate it using Android NDK. I succeeded to compile libusb sources for Android and even initUSB(), but libusb_open(dev, &dev_handle) returns -3 (Access denied).
How can I pass the file descriptor
int fd = connection.getFileDescriptor()
to libusb after getting USB_PERMISSION under Android USB Host API and get USB device access under libusb?
This is what you are looking for.
https://github.com/kuldeepdhaka/libusb/tree/android-open2
just compile it and drop it in. :)
see the "How To for Android" section for full usage.
i made all the required modification to libusb (and im also using it).
It has SELinux fix for "Android 5.0"+ too.
See also https://github.com/libusb/libusb/wiki/Android which now discusses android a little bit. Here is the quote from the proposed readme change (2021-02):
Runtime Permissions:
--------------------
The Runtime Permissions on Android can be transfered from Java to Native over the following approach:
Java:
// obtaining the Usb Permissions over the android.hardware.usb.UsbManager class
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
for (UsbDevice usbDevice : deviceList.values()) { usbManager.requestPermission(usbDevice, mPermissionIntent); }
// get the native FileDescriptor of the UsbDevice and transfer it to Native over JNI or JNA
UsbDeviceConnection usbDeviceConnection = usbManager.openDevice(camDevice);
int fileDescriptor = usbDeviceConnection.getFileDescriptor();
// JNA sample method:
JNA.INSTANCE.set_the_native_Descriptor(fileDescriptor);
Native:
// Initialize LibUsb on Android
set_the_native_Descriptor(int fileDescriptor) {
libusb_context *ctx;
libusb_device_handle *devh;
libusb_set_option(&ctx, LIBUSB_OPTION_WEAK_AUTHORITY, NULL); // important for Android
libusb_init(&ctx);
libusb_wrap_sys_device(NULL, (intptr_t)fileDescriptor, &devh);
// From this point you can regulary use all LibUsb functions as usual.
}
Related
I am trying to integrate the NXP 7150 drivers into Android P for an x86 based platform.
Here are the integration guidelines given : https://www.nxp.com/docs/en/application-note/AN11690.pdf
Since x86 does not support device tree as of now, I need to use the Platform data. But I am not sure in which file should I place this info :
static struct pn544_i2c_platform_data nfc_pdata = {
.irq_gpio = GPIO_TO_PIN(1,29),
.ven_gpio = GPIO_TO_PIN(0,30),
.firm_gpio = GPIO_UNUSED
.clkreq_gpio = GPIO_UNUSED
};
static struct i2c_board_info __initdata nfc_board_info[] = {
{
I2C_BOARD_INFO("pn547", 0x28),
.platform_data = &nfc_pdata,
},
};
I have minimal driver development knowledge, hence I am not able to figure out. I have built the driver as a builtin module. I understand that I need to plug the PN7150 dongle and then put the device info somewhere in the kernel code, which can call the probe of the driver on boot up. Please help.
As I told in my comment as well; but if you don't have any board file (which I am assuming is not available in your X86 Arch code) then you can simply make a new kernel modul. Inside the init function of kernel module you can register your I2C device info:
static int __init dummy_nfc_init(void) {
i2c_register_board_info(1, nfc_board_info,
ARRAY_SIZE(nfc_board_info));
}
module_init(dummy_nfc_init);
In the example while registering the board info 1 is I2C bus number. In your case you need to modify the bus number. You can make this dummy driver as built-in. So when your PN7150 driver .-name will matched with I2C_BOARD_INFO name "pn547" driver probe function will get called while for other callback function and read/write operation slave address 0x28 and I2C bus number should matched.
I'm programming with Android Studio for an Android Things target on a Pico i.MX7Dual development board.
I have an usb-serial converter ("USB to 4-Port Serial") and I want to communicate with each of the serial ports.
I tried to use USB Host API to list the device :
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
Log.d("USBList",device.toString());
}
And I obtain that in the Logcat :
D/USBList: UsbDevice[mName=/dev/bus/usb/001/005,mVendorId=38672,mProductId=30784,mClass=255,mSubclass=0,mProtocol=255,mManufacturerName=null,mProductName=null,mVersion=2.0,mSerialNumber=null,mConfigurations=[
UsbConfiguration[mId=1,mName=null,mAttributes=160,mMaxPower=50,mInterfaces=[
UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=255,mSubclass=0,mProtocol=255,mEndpoints=[
UsbEndpoint[mAddress=129,mAttributes=2,mMaxPacketSize=512,mInterval=255]
UsbEndpoint[mAddress=2,mAttributes=2,mMaxPacketSize=512,mInterval=255]
UsbEndpoint[mAddress=131,mAttributes=2,mMaxPacketSize=512,mInterval=255]
UsbEndpoint[mAddress=4,mAttributes=2,mMaxPacketSize=512,mInterval=255]
UsbEndpoint[mAddress=133,mAttributes=2,mMaxPacketSize=512,mInterval=255]
UsbEndpoint[mAddress=6,mAttributes=2,mMaxPacketSize=512,mInterval=255]
UsbEndpoint[mAddress=135,mAttributes=2,mMaxPacketSize=512,mInterval=255]
UsbEndpoint[mAddress=8,mAttributes=2,mMaxPacketSize=512,mInterval=255]
UsbEndpoint[mAddress=137,mAttributes=3,mMaxPacketSize=16,mInterval=5]]]]
If I understand, I have to communicate with the UsbEndpoint via the UsbInterface but I've only 4 serial ports but get 9 UsbEndpoints.
So I don't know what to do next to identify the good UsbEndPoint to communicate with it.
Thanks in advance.
Most USB-serial converters are supported by the Android Things Peripheral I/O API, so the first thing I would recommend you check is whether or not your converter shows up as a UartDevice under the peripheral list:
PeripheralManager.getInstance().getUartDeviceList()
The devices will usually how up with name like USB1-1:1.0.
If your device is not supported by this subsystem, then you may need to dive deeper into the USB APIs. Let's decode your endpoint descriptor output a bit more. Your device has 8 endpoints of type "Bulk" (mAttributes=2), and one of type Interrupt (mAttributes=3). The bulk endpoints are paired for each serial channel (one for input, one for output). You would need to read each endpoint's direction value to know for sure (not printed in the log). The order in which they are listed most likely indicates the pairing for each channel.
You will then need to contact the manufacturer of your USB device and find the datasheet that describes the protocol they use to transfer data. The device/interface classes are all 0xFF (255), which means "vendor-specific". In essence, it means they don't conform to a standard USB device class and they need to provide documentation on the protocol.
I want to know my Smartphone Bluetooth hardware version thats the device using. Is there any way to get the Bluetooth hardware version using adb command or anything else (without spec).
You cannot determine Bluetooth version.
But you can determine
Normal Bluetooth or
Bluetooth Low Energy
Using this code:
PackageManager pm = getActivity().getPackageManager();
boolean isBT = pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
boolean isBLE = pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
To get the hardware information from a Bluetooth chipset you normally use the Read Local Version Information HCI command. Found a function for it in hci.c:
int hci_read_local_version(int dd, struct hci_version *ver, int to)
{
...
Not sure if this function is available in adb, but perhaps you could write a little program?
I have a custom built Android device which is Single Board Computer with a display unit. It has Android 4.1 installed on it and has a USB port. Within an app I created an sqlite database. I want to transfer the database to a usb flash drive using the aforementioned USB port. I understand Android documentation enough to be able to establish a connection between USB host and Accessory. I am able to detect my flash drive using an intent filter.
The following is a code snippet to transfer a byte array using USB classes.
private Byte[] bytes
private static int TIMEOUT = 0;
private boolean forceClaim = true;
...
UsbInterface intf = device.getInterface(0);
UsbEndpoint endpoint = intf.getEndpoint(0);
UsbDeviceConnection connection = mUsbManager.openDevice(device);
connection.claimInterface(intf, forceClaim);
connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT);
Here a bytearray is transferred using the USB interface. I want to be able to transfer an sqlite database using the same. Is that possible? How can I do it?
As is documented in several other questions here, Android APIs support only raw transfers, so you would have to implement an entire filesystem in your app.
Since your device is custom, you would be better off creating a Linux-level daemon or (bulletproof!) setuid tool to mount the USB drive at operating system level, and leverage the filesystem code already present in the Lunux kernel. Then you can simply perform normal file operations to it. You might even be able to modify Android's vold to do this - because you control the Android install, you have this class of options which a typical 3rd party developer targeting locked down phones does not.
I am trying to connect an Android phone via USB to an accessory (in this case a MacBook pro) and use getDeviceList() to verify that the connection is recognized and print the description of the UsbDevice object to the screen via toString() using the following code:
//as host
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
String s = "";
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
manager.requestPermission(device, mPermissionIntent);
Log.d("List Devices", device.toString());
s += device.toString();
}
The code sample came almost directly from the Android Developer site, but multiple phones do not seem to be recognizing any peripheral. Similarly, I have tried treating the Android phone as the accessory, but am getting similar results. Any help is appreciated.
Regarding Accessory Mode, from Android Developer's Guide:
USB accessory mode allows users to connect USB host hardware specifically designed for Android-powered devices. The accessories must adhere to the Android accessory protocol outlined in the Android Accessory Development Kit documentation.
Therefore, only devices that have implemented the AOA (Android Open Accessory) protocol will show up as a UsbAccessory from the phone.
As for Host Mode, the phone itself must have permitted it or else it will not really work. True, full support for Host Mode right out of the box seems very rare on most Android phones/tablets. This answer demonstrates how to get your phone/tablet to fully support Host Mode if it doesn't already, but note that this requires root access.