我需要在Android上与HID设备进行交互。问题是我正在使用Qt Android,并且没有使用Java UsbManager类。
是否有任何C库可以链接,以便在Android上与HID设备通信,而无需使用Java API?
我找到了这个:
http://source.android.com/devices/reference/bt__hh_8h_source.html
这似乎是定义HID通信的标头,但我找不到相关的库。有什么想法吗?
提前致谢。
我需要在Android上与HID设备进行交互。问题是我正在使用Qt Android,并且没有使用Java UsbManager类。
是否有任何C库可以链接,以便在Android上与HID设备通信,而无需使用Java API?
我找到了这个:
http://source.android.com/devices/reference/bt__hh_8h_source.html
这似乎是定义HID通信的标头,但我找不到相关的库。有什么想法吗?
提前致谢。
我已经找到了一种方法来实现这个。在我的情况下,我正在为一个设备开发控制面板,并且需要使其在没有root的情况下在每个设备上运行。
基本上,我使用UsbManager来查找并抓取设备。然后我打开设备并从UsbDeviceConnection调用getFileDescriptor()方法。然后我将该整数传递到本地代码端。从那里,我可以轻松地使用任何类型的请求从设备中获取数据,而无需通过JNI在本地代码和Java之间传递数据,这是缓慢而繁琐的工作。
最棘手的部分实际上是执行ioctl调用,这需要有特殊的格式。
部分代码已经在libusb源代码中很好地说明了,因为这是他们实现对Linux内核的libsub调用的方式。
如果有人知道更好的解决方案,请让我知道。
带有USBManager钩子的Android活动代码:
public class MyActivity extends QtActivity
{
private static MyActivity m_instance;
private UsbAccessory accessory;
private String TAG = "TAG";
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
private PendingIntent mPermissionIntent;
private UsbManager manager;
private UsbDeviceConnection connection;
private HashMap<Integer, Integer> connectedDevices;
public MyActivity()
{
m_instance = this;
connectedDevices = new HashMap<Integer, Integer>();
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
manager = (UsbManager) getSystemService(Context.USB_SERVICE);
registerReceiver(usbManagerBroadcastReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED));
registerReceiver(usbManagerBroadcastReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));
registerReceiver(usbManagerBroadcastReceiver, new IntentFilter(ACTION_USB_PERMISSION));
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
final Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
@Override
public void run()
{
checkForDevices();
}
}, 1000);
}
@Override
public void onDestroy()
{
super.onDestroy();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
}
private static native void notifyDeviceAttached(int fd);
private static native void notifyDeviceDetached(int fd);
private final BroadcastReceiver usbManagerBroadcastReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent)
{
try
{
String action = intent.getAction();
Log.d(TAG, "INTENT ACTION: " + action);
if (ACTION_USB_PERMISSION.equals(action))
{
Log.d(TAG, "onUsbPermission");
synchronized (this)
{
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
{
if(device != null)
{
int fd = connectToDevice(device);
Log.d(TAG,"device file descriptor: " + fd);
notifyDeviceAttached(fd);
}
}
else
{
Log.d(TAG, "permission denied for device " + device);
}
}
}
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action))
{
Log.d(TAG, "onDeviceConnected");
synchronized(this)
{
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null)
{
manager.requestPermission(device, mPermissionIntent);
}
}
}
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action))
{
Log.d(TAG, "onDeviceDisconnected");
synchronized(this)
{
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
int fd = connectedDevices.get(device.getDeviceId());
Log.d(TAG, "device: " + device.getDeviceId() + " disconnected. fd: " + fd);
notifyDeviceDetached(fd);
connectedDevices.remove(device.getDeviceId());
}
}
}
catch(Exception e)
{
Log.d(TAG, "Exception: " + e);
}
}
};
private int connectToDevice(UsbDevice device)
{
connection = manager.openDevice(device);
// if we make this, kernel driver will be disconnected
connection.claimInterface(device.getInterface(0), true);
Log.d(TAG, "inserting device with id: " + device.getDeviceId() + " and file descriptor: " + connection.getFileDescriptor());
connectedDevices.put(device.getDeviceId(), connection.getFileDescriptor());
return connection.getFileDescriptor();
}
private void checkForDevices()
{
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while(deviceIterator.hasNext())
{
UsbDevice device = deviceIterator.next();
if (device.getVendorId()==VID && device.getProductId()==PID)
{
Log.d(TAG, "Found a device: " + device);
manager.requestPermission(device, mPermissionIntent);
}
}
}
}
当连接或断开具有所需VID和PID的设备时,将调用原生调用notifyDeviceAttached(int fd)和notifyDeviceDetached(int fd),并发送设备的文件描述符到本机端。 在我的案例中,我实例化了一个类型为Device的类。此时设备已经打开,您可以开始对其进行调用。在Linux中,您可以像libusb一样进行ioctl调用。 您可以查看下面的代码以获取getFeature和setFeature。如果您需要比这更多的内容,则可以查看libusb源代码。
C++本地端代码:
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#include <QDebug>
#include <QElapsedTimer>
static inline uint16_t cpu_to_le16(const uint16_t x)
{
union
{
uint8_t b8[2];
uint16_t b16;
} _tmp;
_tmp.b8[1] = (uint8_t) (x >> 8);
_tmp.b8[0] = (uint8_t) (x & 0xff);
return _tmp.b16;
}
struct usbdevfs_ctrltransfer
{
unsigned char bRequestType;
unsigned char bRequest;
unsigned short wValue;
unsigned short wIndex;
unsigned short wLength;
unsigned int timeout;
void *data;
};
Device::Device(int fileDescriptor, QObject *parent) :
fd(fileDescriptor)
{
}
int Device::getFeature(unsigned char reportId, unsigned char *buffer, int length)
{
struct usbdevfs_ctrltransfer data;
data.bRequestType = (0x01 << 5)|0x01|0x80;
data.bRequest = 0x01;
data.wValue = cpu_to_le16((3 << 8) | reportId);
data.wIndex = cpu_to_le16(0);
data.wLength = cpu_to_le16(length);
data.data = buffer;
data.timeout = 1000;
int res = ioctl(fd, _IOWR('U', 0, struct usbdevfs_ctrltransfer), &data);
if (res<0)
{
qDebug() << "error: " << strerror(errno);
}
return res;
}
int Device::setFeature(unsigned char reportId, unsigned char *buffer, int length)
{
struct usbdevfs_ctrltransfer data;
data.bRequestType = (0x01 << 5)|0x01|0x00;
data.bRequest = 0x09;
data.wValue = cpu_to_le16((3 << 8) | reportId);
data.wIndex = cpu_to_le16(0);
data.wLength = cpu_to_le16(length);
data.data = buffer;
data.timeout = 1000;
int res = ioctl(fd, _IOWR('U', 0, struct usbdevfs_ctrltransfer), &data);
if (res<0)
{
qDebug() << "error: " << strerror(errno);
}
return res;
}
敬礼,
Nuno Santos