في يوم من الأيام ، كنت بحاجة إلى جهاز واحد تم التحكم فيه عبر USB من برنامج سطح مكتب ليتم التحكم فيه أيضًا عبر تطبيق Android. كانت الخصوصية هي أنه لم يتم استخدام HID و CDC وفئات الأجهزة القياسية الأخرى. تم نقل البيانات من خلال النقل الجماعي ونقاط النهاية. كانت مكتبة libusb أساس العمل مع USB.
سننشئ تطبيق اختبار يمكن من خلاله نقل البيانات العشوائية وتلقيها من الجهاز.
سوف أتطرق إلى النقاط الرئيسية ، وسيكون الرابط إلى الرمز الكامل في النهاية.
بادئ ذي بدء ، نعمل وفقًا للوثائق الرسمية للعمل مع UsbHost.
أضف خطًا إلى البيان
<uses-feature android:name="android.hardware.usb.host"/>
إذا أردنا الكشف عن الجهاز تلقائيًا وبدء التطبيق ، فعندئذٍ نكتب ما يلي في البيان الخاص بالنشاط الرئيسي.
<intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter"/>
حدد لجهازنا VID و PID في الملف بالموارد device_filter.xml
<resources> <usb-device product-id="0037" vendor-id="8742"/> </resources>
نحصل على مدير USB في طريقة onCreate.
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE)
بعد ذلك ، نحصل على قائمة بالأجهزة المتصلة بـ USB ، ومن بينها نبحث عن جهاز من فئة USB_CLASS_PER_INTERFACE نحتاجه.
UsbDevice findDevice(UsbManager usbManager) { for (UsbDevice usbDevice : usbManager.getDeviceList().values()) { if (usbDevice.getDeviceClass() == UsbConstants.USB_CLASS_PER_INTERFACE) { return usbDevice; } else { UsbInterface usbInterface = findInterface(usbDevice); if (usbInterface != null) return usbDevice; } } return null; } UsbInterface findInterface(UsbDevice usbDevice) { for (int nIf = 0; nIf < usbDevice.getInterfaceCount(); nIf++) { UsbInterface usbInterface = usbDevice.getInterface(nIf); if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_PER_INTERFACE) { return usbInterface; } } return null; }
بعد ذلك ، نجد الواجهة التي نحتاجها ، ولا تنس التحقق من الأذونات ، والتكرار على جميع نقاط التحكم ، ومن بينها نختار نقاط القراءة والكتابة ، وأخيرًا نتواصل.
private void initUsbDevice() { PendingIntent mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(mUsbReceiver, filter); mUsbManager.requestPermission(mUsbDevice, mPermissionIntent); mUsbInterface = findInterface(mUsbDevice); for (int nEp = 0; nEp < mUsbInterface.getEndpointCount(); nEp++) { UsbEndpoint tmpEndpoint = mUsbInterface.getEndpoint(nEp); if (tmpEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_BULK) continue; if ((mOutEndpoint == null) && (tmpEndpoint.getDirection() == UsbConstants.USB_DIR_OUT)) { mOutEndpoint = tmpEndpoint; } else if ((mInEndpoint == null) && (tmpEndpoint.getDirection() == UsbConstants.USB_DIR_IN)) { mInEndpoint = tmpEndpoint; } } if (mOutEndpoint == null) { Toast.makeText(this, "no endpoints", Toast.LENGTH_LONG).show(); } mConnection = mUsbManager.openDevice(mUsbDevice); if (mConnection == null) { Toast.makeText(this, "can't open device", Toast.LENGTH_SHORT).show(); return; } mConnection.claimInterface(mUsbInterface, true); startIoManager(); }
للعمل مع I / O ، التخزين المؤقت للبيانات ، عدم التزامن ، وأشياء أخرى مريحة ، يتم استخدام فئة المدير المساعد ، ولكن في الجوهر ، يتم تقليل تبادل البيانات إلى التعليمات البرمجية التالية.
القراءة:
mConnection.bulkTransfer(mInEndpoint, data, size, READ_TIMEOUT);
سجل:
int bytesWritten = mConnection.bulkTransfer(mOutEndpoint, Arrays.copyOfRange(data, offset, offset + size), size, WRITE_TIMEOUT);
بهذه الطريقة ، يتم إرسال واستقبال حزم BulkTransfer.
نتيجة لذلك ، يمكن لتطبيقنا البسيط نقل واستقبال البيانات التعسفية.


يعمل!
مشروع
تطبيق الاختبار هذا
على جيثبروابط مفيدة:
- مكتبة للعمل مع FT232 وأجهزة CDC الأخرى على Android.
- وثائق Android الرسمية للعمل مع UsbHost.