SDL  2.0
HIDDeviceUSB.java
Go to the documentation of this file.
1 package org.libsdl.app;
2 
3 import android.hardware.usb.*;
4 import android.os.Build;
5 import android.util.Log;
6 import java.util.Arrays;
7 
8 class HIDDeviceUSB implements HIDDevice {
9 
10  private static final String TAG = "hidapi";
11 
12  protected HIDDeviceManager mManager;
13  protected UsbDevice mDevice;
14  protected int mInterface;
15  protected int mDeviceId;
16  protected UsbDeviceConnection mConnection;
17  protected UsbEndpoint mInputEndpoint;
18  protected UsbEndpoint mOutputEndpoint;
19  protected InputThread mInputThread;
20  protected boolean mRunning;
21  protected boolean mFrozen;
22 
23  public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_number) {
24  mManager = manager;
25  mDevice = usbDevice;
26  mInterface = interface_number;
27  mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
28  mRunning = false;
29  }
30 
31  public String getIdentifier() {
32  return String.format("%s/%x/%x", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId());
33  }
34 
35  @Override
36  public int getId() {
37  return mDeviceId;
38  }
39 
40  @Override
41  public int getVendorId() {
42  return mDevice.getVendorId();
43  }
44 
45  @Override
46  public int getProductId() {
47  return mDevice.getProductId();
48  }
49 
50  @Override
51  public String getSerialNumber() {
52  String result = null;
53  if (Build.VERSION.SDK_INT >= 21) {
54  result = mDevice.getSerialNumber();
55  }
56  if (result == null) {
57  result = "";
58  }
59  return result;
60  }
61 
62  @Override
63  public int getVersion() {
64  return 0;
65  }
66 
67  @Override
68  public String getManufacturerName() {
69  String result = null;
70  if (Build.VERSION.SDK_INT >= 21) {
71  result = mDevice.getManufacturerName();
72  }
73  if (result == null) {
74  result = String.format("%x", getVendorId());
75  }
76  return result;
77  }
78 
79  @Override
80  public String getProductName() {
81  String result = null;
82  if (Build.VERSION.SDK_INT >= 21) {
83  result = mDevice.getProductName();
84  }
85  if (result == null) {
86  result = String.format("%x", getProductId());
87  }
88  return result;
89  }
90 
91  public UsbDevice getDevice() {
92  return mDevice;
93  }
94 
95  public String getDeviceName() {
96  return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
97  }
98 
99  @Override
100  public boolean open() {
101  mConnection = mManager.getUSBManager().openDevice(mDevice);
102  if (mConnection == null) {
103  Log.w(TAG, "Unable to open USB device " + getDeviceName());
104  return false;
105  }
106 
107  // Force claim all interfaces
108  for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
109  UsbInterface iface = mDevice.getInterface(i);
110 
111  if (!mConnection.claimInterface(iface, true)) {
112  Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
113  close();
114  return false;
115  }
116  }
117 
118  // Find the endpoints
119  UsbInterface iface = mDevice.getInterface(mInterface);
120  for (int j = 0; j < iface.getEndpointCount(); j++) {
121  UsbEndpoint endpt = iface.getEndpoint(j);
122  switch (endpt.getDirection()) {
123  case UsbConstants.USB_DIR_IN:
124  if (mInputEndpoint == null) {
125  mInputEndpoint = endpt;
126  }
127  break;
128  case UsbConstants.USB_DIR_OUT:
129  if (mOutputEndpoint == null) {
130  mOutputEndpoint = endpt;
131  }
132  break;
133  }
134  }
135 
136  // Make sure the required endpoints were present
137  if (mInputEndpoint == null || mOutputEndpoint == null) {
138  Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
139  close();
140  return false;
141  }
142 
143  // Start listening for input
144  mRunning = true;
145  mInputThread = new InputThread();
146  mInputThread.start();
147 
148  return true;
149  }
150 
151  @Override
152  public int sendFeatureReport(byte[] report) {
153  int res = -1;
154  int offset = 0;
155  int length = report.length;
156  boolean skipped_report_id = false;
157  byte report_number = report[0];
158 
159  if (report_number == 0x0) {
160  ++offset;
161  --length;
162  skipped_report_id = true;
163  }
164 
165  res = mConnection.controlTransfer(
166  UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_OUT,
167  0x09/*HID set_report*/,
168  (3/*HID feature*/ << 8) | report_number,
169  0,
170  report, offset, length,
171  1000/*timeout millis*/);
172 
173  if (res < 0) {
174  Log.w(TAG, "sendFeatureReport() returned " + res + " on device " + getDeviceName());
175  return -1;
176  }
177 
178  if (skipped_report_id) {
179  ++length;
180  }
181  return length;
182  }
183 
184  @Override
185  public int sendOutputReport(byte[] report) {
186  int r = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
187  if (r != report.length) {
188  Log.w(TAG, "sendOutputReport() returned " + r + " on device " + getDeviceName());
189  }
190  return r;
191  }
192 
193  @Override
194  public boolean getFeatureReport(byte[] report) {
195  int res = -1;
196  int offset = 0;
197  int length = report.length;
198  boolean skipped_report_id = false;
199  byte report_number = report[0];
200 
201  if (report_number == 0x0) {
202  /* Offset the return buffer by 1, so that the report ID
203  will remain in byte 0. */
204  ++offset;
205  --length;
206  skipped_report_id = true;
207  }
208 
209  res = mConnection.controlTransfer(
210  UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_IN,
211  0x01/*HID get_report*/,
212  (3/*HID feature*/ << 8) | report_number,
213  0,
214  report, offset, length,
215  1000/*timeout millis*/);
216 
217  if (res < 0) {
218  Log.w(TAG, "getFeatureReport() returned " + res + " on device " + getDeviceName());
219  return false;
220  }
221 
222  if (skipped_report_id) {
223  ++res;
224  ++length;
225  }
226 
227  byte[] data;
228  if (res == length) {
229  data = report;
230  } else {
231  data = Arrays.copyOfRange(report, 0, res);
232  }
233  mManager.HIDDeviceFeatureReport(mDeviceId, data);
234 
235  return true;
236  }
237 
238  @Override
239  public void close() {
240  mRunning = false;
241  if (mInputThread != null) {
242  while (mInputThread.isAlive()) {
243  mInputThread.interrupt();
244  try {
245  mInputThread.join();
246  } catch (InterruptedException e) {
247  // Keep trying until we're done
248  }
249  }
250  mInputThread = null;
251  }
252  if (mConnection != null) {
253  for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
254  UsbInterface iface = mDevice.getInterface(i);
255  mConnection.releaseInterface(iface);
256  }
257  mConnection.close();
258  mConnection = null;
259  }
260  }
261 
262  @Override
263  public void shutdown() {
264  close();
265  mManager = null;
266  }
267 
268  @Override
269  public void setFrozen(boolean frozen) {
270  mFrozen = frozen;
271  }
272 
273  protected class InputThread extends Thread {
274  @Override
275  public void run() {
276  int packetSize = mInputEndpoint.getMaxPacketSize();
277  byte[] packet = new byte[packetSize];
278  while (mRunning) {
279  int r;
280  try
281  {
282  r = mConnection.bulkTransfer(mInputEndpoint, packet, packetSize, 1000);
283  }
284  catch (Exception e)
285  {
286  Log.v(TAG, "Exception in UsbDeviceConnection bulktransfer: " + e);
287  break;
288  }
289  if (r < 0) {
290  // Could be a timeout or an I/O error
291  }
292  if (r > 0) {
293  byte[] data;
294  if (r == packetSize) {
295  data = packet;
296  } else {
297  data = Arrays.copyOfRange(packet, 0, r);
298  }
299 
300  if (!mFrozen) {
301  mManager.HIDDeviceInputReport(mDeviceId, data);
302  }
303  }
304  }
305  }
306  }
307 }
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2079
GLuint64EXT * result
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 Uint32 * e
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLintptr offset
GLuint res
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
GLuint GLfloat x0
#define TAG
Definition: hid.cpp:16
GLuint GLsizei GLsizei * length