sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

HIDDeviceUSB.java (9017B)


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