| @@ -1,9 +1,10 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <merger version="3"><dataSet config="21.0.3"><source path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\build\intermediates\exploded-aar\com.android.support\support-v4\21.0.3\res"/></dataSet><dataSet config="0.2.0-SNAPSHOT"><source path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\build\intermediates\exploded-aar\com.hoho.android\usbSerialForAndroid\0.2.0-SNAPSHOT\res"/></dataSet><dataSet config="main"><source path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res"><file name="earth" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable\earth.jpg" qualifiers="" type="drawable"/><file name="jupiter" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable\jupiter.jpg" qualifiers="" type="drawable"/><file name="mars" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable\mars.jpg" qualifiers="" type="drawable"/><file name="mercury" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable\mercury.jpg" qualifiers="" type="drawable"/><file name="neptune" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable\neptune.jpg" qualifiers="" type="drawable"/><file name="saturn" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable\saturn.jpg" qualifiers="" type="drawable"/><file name="uranus" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable\uranus.jpg" qualifiers="" type="drawable"/><file name="venus" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable\venus.jpg" qualifiers="" type="drawable"/><file name="action_search" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-hdpi\action_search.png" qualifiers="hdpi-v4" type="drawable"/><file name="drawer_shadow" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-hdpi\drawer_shadow.9.png" qualifiers="hdpi-v4" type="drawable"/><file name="ic_drawer" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-hdpi\ic_drawer.png" qualifiers="hdpi-v4" type="drawable"/><file name="ic_launcher" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-hdpi\ic_launcher.png" qualifiers="hdpi-v4" type="drawable"/><file name="action_search" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-mdpi\action_search.png" qualifiers="mdpi-v4" type="drawable"/><file name="drawer_shadow" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-mdpi\drawer_shadow.9.png" qualifiers="mdpi-v4" type="drawable"/><file name="ic_drawer" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-mdpi\ic_drawer.png" qualifiers="mdpi-v4" type="drawable"/><file name="ic_launcher" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-mdpi\ic_launcher.png" qualifiers="mdpi-v4" type="drawable"/><file name="action_search" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-xhdpi\action_search.png" qualifiers="xhdpi-v4" type="drawable"/><file name="drawer_shadow" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-xhdpi\drawer_shadow.9.png" qualifiers="xhdpi-v4" type="drawable"/><file name="ic_drawer" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-xhdpi\ic_drawer.png" qualifiers="xhdpi-v4" type="drawable"/><file name="ic_launcher" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-xhdpi\ic_launcher.png" qualifiers="xhdpi-v4" type="drawable"/><file name="ic_launcher" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\drawable-xxhdpi\ic_launcher.png" qualifiers="xxhdpi-v4" type="drawable"/><file name="activity_main" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\layout\activity_main.xml" qualifiers="" type="layout"/><file name="arduino_serial" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\layout\arduino_serial.xml" qualifiers="" type="layout"/><file name="bluetooth" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\layout\bluetooth.xml" qualifiers="" type="layout"/><file name="device_list" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\layout\device_list.xml" qualifiers="" type="layout"/><file name="drawer_list_item" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\layout\drawer_list_item.xml" qualifiers="" type="layout"/><file name="fragment_planet" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\layout\fragment_planet.xml" qualifiers="" type="layout"/><file name="graph" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\layout\graph.xml" qualifiers="" type="layout"/><file name="main" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\layout\main.xml" qualifiers="" type="layout"/><file name="serial_console" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\layout\serial_console.xml" qualifiers="" type="layout"/><file name="main" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\menu\main.xml" qualifiers="" type="menu"/><file path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\values\dimens.xml" qualifiers=""><dimen name="pie_segment_label_font_size">10dp</dimen><dimen name="activity_vertical_margin">16dp</dimen><dimen name="domain_label_font_size">13dp</dimen><dimen name="range_label_font_size">13dp</dimen><dimen name="activity_horizontal_margin">16dp</dimen><dimen name="navigation_drawer_width">240dp</dimen><dimen name="title_font_size">20dp</dimen><dimen name="legend_text_font_size">20dp</dimen><dimen name="range_tick_label_font_size">15dp</dimen><dimen name="domain_tick_label_font_size">15dp</dimen></file><file path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\values\strings.xml" qualifiers=""><string name="hello_world">Hello world!</string><string name="drawer_close">Close navigation drawer</string><string name="app_not_available">Sorry, there\'s no web browser available</string><string name="action_settings">Settings</string><string name="app_name">Reading Tracker</string><string name="on">Turn On</string><string-array name="nav_drawer_items"> | ||
| <item>Weekly Tracker</item> | ||
| <item>Reading notifications</item> | ||
| <item>Recommendations</item> | ||
| <item>Write a review</item> | ||
| <item>Share</item> | ||
| <item>Pair Device</item> | ||
| <item>Data Transfer Test</item> | ||
| </string-array><string name="refreshing">Refreshing...</string><string name="action_websearch">Web search</string><string name="Visible">Get Visible</string><string name="app_name_serial">Serial Example</string><string name="app_title">USB Serial Example</string><string name="off">Turn Off</string><string name="drawer_open">Open navigation drawer</string><string name="List">List Devices</string></file><file name="device_filter" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\xml\device_filter.xml" qualifiers="" type="xml"/><file name="line_point_formatter_with_plf1" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\xml\line_point_formatter_with_plf1.xml" qualifiers="" type="xml"/><file name="line_point_formatter_with_plf2" path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\main\res\xml\line_point_formatter_with_plf2.xml" qualifiers="" type="xml"/></source><source path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\build\generated\res\rs\debug"/><source path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\build\generated\res\generated\debug"/></dataSet><dataSet config="debug"><source path="C:\Users\Cain\AndroidStudioProjects\Bookstackv2\app\src\debug\res"/></dataSet><mergedItems/></merger> |
| @@ -0,0 +1,50 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:orientation="vertical" android:layout_width="match_parent" | ||
| android:layout_height="match_parent"> | ||
|
|
||
| <TextView | ||
| android:id="@+id/demoTitle" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:layout_alignParentTop="true" | ||
| android:layout_centerHorizontal="true" | ||
| android:text="@string/app_title" | ||
| android:textSize="24sp" | ||
| android:textStyle="bold" /> | ||
|
|
||
| <TextView | ||
| android:id="@+id/progressBarTitle" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/demoTitle" | ||
| android:layout_centerHorizontal="true" | ||
| android:text="@string/refreshing" | ||
| android:padding="8dp" | ||
| android:textSize="18sp" /> | ||
|
|
||
| <ProgressBar | ||
| android:id="@+id/progressBar" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/progressBarTitle" | ||
| android:layout_centerHorizontal="true" | ||
| android:padding="8dp" | ||
| style="@android:style/Widget.Holo.ProgressBar.Horizontal" | ||
| android:indeterminate="true" /> | ||
|
|
||
| <View | ||
| android:id="@+id/separator" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="1dip" | ||
| android:layout_below="@+id/progressBar" | ||
| android:layout_centerHorizontal="true" | ||
| android:background="#eeeeee" /> | ||
|
|
||
| <ListView | ||
| android:id="@+id/deviceList" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/separator" /> | ||
|
|
||
| </LinearLayout><!-- From: file:/C:/Users/Cain/AndroidStudioProjects/Bookstackv2/app/src/main/res/layout/arduino_serial.xml --> |
| @@ -0,0 +1,56 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| xmlns:tools="http://schemas.android.com/tools" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="match_parent" | ||
| android:paddingBottom="@dimen/activity_vertical_margin" | ||
| android:paddingLeft="@dimen/activity_horizontal_margin" | ||
| android:paddingRight="@dimen/activity_horizontal_margin" | ||
| android:paddingTop="@dimen/activity_vertical_margin" | ||
| tools:context=".MainActivity" > | ||
|
|
||
| <TextView | ||
| android:id="@+id/demoTitle" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:layout_alignParentTop="true" | ||
| android:layout_centerHorizontal="true" | ||
| android:text="@string/app_title" | ||
| android:textSize="24sp" | ||
| android:textStyle="bold" /> | ||
|
|
||
| <TextView | ||
| android:id="@+id/progressBarTitle" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/demoTitle" | ||
| android:layout_centerHorizontal="true" | ||
| android:text="@string/refreshing" | ||
| android:padding="8dp" | ||
| android:textSize="18sp" /> | ||
|
|
||
| <ProgressBar | ||
| android:id="@+id/progressBar" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/progressBarTitle" | ||
| android:layout_centerHorizontal="true" | ||
| android:padding="8dp" | ||
| style="@android:style/Widget.Holo.ProgressBar.Horizontal" | ||
| android:indeterminate="true" /> | ||
|
|
||
| <View | ||
| android:id="@+id/separator" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="1dip" | ||
| android:layout_below="@+id/progressBar" | ||
| android:layout_centerHorizontal="true" | ||
| android:background="#eeeeee" /> | ||
|
|
||
| <ListView | ||
| android:id="@+id/deviceList" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/separator" /> | ||
|
|
||
| </RelativeLayout><!-- From: file:/C:/Users/Cain/AndroidStudioProjects/Bookstackv2/app/src/main/res/layout/device_list.xml --> |
| @@ -0,0 +1,56 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| xmlns:tools="http://schemas.android.com/tools" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="match_parent" | ||
| android:paddingBottom="@dimen/activity_vertical_margin" | ||
| android:paddingLeft="@dimen/activity_horizontal_margin" | ||
| android:paddingRight="@dimen/activity_horizontal_margin" | ||
| android:paddingTop="@dimen/activity_vertical_margin" | ||
| tools:context=".MainActivity" > | ||
|
|
||
| <TextView | ||
| android:id="@+id/demoTitle" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:layout_alignParentTop="true" | ||
| android:layout_centerHorizontal="true" | ||
| android:text="@string/app_title" | ||
| android:textSize="24sp" | ||
| android:textStyle="bold" /> | ||
|
|
||
| <TextView | ||
| android:id="@+id/progressBarTitle" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/demoTitle" | ||
| android:layout_centerHorizontal="true" | ||
| android:text="@string/refreshing" | ||
| android:padding="8dp" | ||
| android:textSize="18sp" /> | ||
|
|
||
| <ProgressBar | ||
| android:id="@+id/progressBar" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/progressBarTitle" | ||
| android:layout_centerHorizontal="true" | ||
| android:padding="8dp" | ||
| style="@android:style/Widget.Holo.ProgressBar.Horizontal" | ||
| android:indeterminate="true" /> | ||
|
|
||
| <View | ||
| android:id="@+id/separator" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="1dip" | ||
| android:layout_below="@+id/progressBar" | ||
| android:layout_centerHorizontal="true" | ||
| android:background="#eeeeee" /> | ||
|
|
||
| <ListView | ||
| android:id="@+id/deviceList" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/separator" /> | ||
|
|
||
| </RelativeLayout><!-- From: file:/C:/Users/Cain/AndroidStudioProjects/Bookstackv2/app/src/main/res/layout/main.xml --> |
| @@ -0,0 +1,36 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="match_parent" > | ||
|
|
||
| <TextView | ||
| android:id="@+id/demoTitle" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_alignParentTop="true" | ||
| android:text="@string/app_title" | ||
| android:textSize="24sp" | ||
| android:textStyle="bold" /> | ||
|
|
||
| <View | ||
| android:id="@+id/separator" | ||
| android:layout_width="match_parent" | ||
| android:layout_below="@+id/demoTitle" | ||
| android:layout_height="1dip" | ||
| android:background="#eeeeee" /> | ||
|
|
||
| <ScrollView | ||
| android:id="@+id/demoScroller" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/separator" > | ||
|
|
||
| <TextView | ||
| android:id="@+id/consoleText" | ||
| android:textIsSelectable="true" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:typeface="monospace" /> | ||
| </ScrollView> | ||
|
|
||
| </RelativeLayout><!-- From: file:/C:/Users/Cain/AndroidStudioProjects/Bookstackv2/app/src/main/res/layout/serial_console.xml --> |
| @@ -0,0 +1,21 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <resources> | ||
| <!-- 0x0403 / 0x6001: FTDI FT232R UART --> | ||
| <usb-device vendor-id="1027" product-id="24577" /> | ||
|
|
||
| <!-- 0x0403 / 0x6015: FTDI FT231X --> | ||
| <usb-device vendor-id="1027" product-id="24597" /> | ||
|
|
||
| <!-- 0x2341 / Arduino --> | ||
| <usb-device vendor-id="9025" /> | ||
|
|
||
| <!-- 0x16C0 / 0x0483: Teensyduino --> | ||
| <usb-device vendor-id="5824" product-id="1155" /> | ||
|
|
||
| <!-- 0x10C4 / 0xEA60: CP210x UART Bridge --> | ||
| <usb-device vendor-id="4292" product-id="60000" /> | ||
|
|
||
| <!-- 0x067B / 0x2303: Prolific PL2303 --> | ||
| <usb-device vendor-id="1659" product-id="8963" /> | ||
| </resources> | ||
| <!-- From: file:/C:/Users/Cain/AndroidStudioProjects/Bookstackv2/app/src/main/res/xml/device_filter.xml --> |
| @@ -0,0 +1,21 @@ | ||
| # Studio/Gradle | ||
| *.iml | ||
| .gradle/ | ||
| build/ | ||
|
|
||
| # Intellij IDEA (see https://intellij-support.jetbrains.com/entries/23393067) | ||
| .idea/workspace.xml | ||
| .idea/tasks.xml | ||
| .idea/datasources.xml | ||
| .idea/dataSources.ids | ||
|
|
||
| # generated files | ||
| bin/ | ||
| gen/ | ||
|
|
||
| # Eclipse/Android/Misc | ||
| .metadata/ | ||
| local.properties | ||
| *.DS_Store | ||
| proguard/ | ||
|
|
| @@ -0,0 +1,17 @@ | ||
| Current Version (in development) | ||
| * Gradle, Android Studio support. | ||
| * New driver: CP2102 (thanks Ducky). | ||
| * New prober support: LUFA Virtual Serial, Leaflabs Maple, Teensyduino. | ||
| * New driver methods: getCD, getCTS, getDSR, getDTR, setDTR, getRI, getRTS, | ||
| setRTS. | ||
| * API change: setBaudrate() has been removed; use setParameters(). | ||
| * API change: open() no longer implicitly sets the baud rate. Clients should | ||
| call setParameters() immediately after open(), when necessary. | ||
| * Library version is available in `com.hoho.android.usbserial.BuildInfo`. | ||
|
|
||
| v0.1.0 (2012-10-12) | ||
| * New driver: CdcAcmSerialDriver. | ||
| * Better tuned read and write buffer sizes. | ||
|
|
||
| v0.0.1 (2011-12-28) | ||
| * Initial release. |
| @@ -0,0 +1,142 @@ | ||
| # usb-serial-for-android | ||
|
|
||
| This is a driver library for communication with Arduinos and other USB serial hardware on | ||
| Android, using the | ||
| [Android USB Host API](http://developer.android.com/guide/topics/connectivity/usb/host.html) | ||
| available on Android 3.1+. | ||
|
|
||
| No root access, ADK, or special kernel drivers are required; all drivers are implemented in | ||
| Java. You get a raw serial port with `read()`, `write()`, and other basic | ||
| functions for use with your own protocols. | ||
|
|
||
| * **Homepage**: https://github.com/mik3y/usb-serial-for-android | ||
| * **Google group**: http://groups.google.com/group/usb-serial-for-android | ||
| * **Latest release**: [v0.1.0](https://github.com/mik3y/usb-serial-for-android/releases) | ||
|
|
||
| ## Quick Start | ||
|
|
||
| **1.** [Link your project](https://github.com/mik3y/usb-serial-for-android/wiki/Building-From-Source) to the library. | ||
|
|
||
| **2.** Copy [device_filter.xml](http://usb-serial-for-android.googlecode.com/git/UsbSerialExamples/res/xml/device_filter.xml) to your project's `res/xml/` directory. | ||
|
|
||
| **3.** Configure your `AndroidManifest.xml` to notify your app when a device is attached (see [Android USB Host documentation](http://developer.android.com/guide/topics/connectivity/usb/host.html#discovering-d) for help). | ||
|
|
||
| ```xml | ||
| <activity | ||
| android:name="..." | ||
| ...> | ||
| <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" /> | ||
| </activity> | ||
| ``` | ||
|
|
||
| **5.** Use it! Example code snippet: | ||
|
|
||
| ```java | ||
| // Find all available drivers from attached devices. | ||
| UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); | ||
| List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager); | ||
| if (availableDrivers.isEmpty()) { | ||
| return; | ||
| } | ||
| // Open a connection to the first available driver. | ||
| UsbSerialDriver driver = availableDrivers.get(0); | ||
| UsbDeviceConnection connection = manager.openDevice(driver.getDevice()); | ||
| if (connection == null) { | ||
| // You probably need to call UsbManager.requestPermission(driver.getDevice(), ..) | ||
| return; | ||
| } | ||
| // Read some data! Most have just one port (port 0). | ||
| UsbSerialPort port = driver.getPort(0); | ||
| port.open(connection); | ||
| try { | ||
| port.setBaudRate(115200); | ||
| byte buffer[] = new byte[16]; | ||
| int numBytesRead = port.read(buffer, 1000); | ||
| Log.d(TAG, "Read " + numBytesRead + " bytes."); | ||
| } catch (IOException e) { | ||
| // Deal with error. | ||
| } finally { | ||
| port.close(); | ||
| } | ||
| ``` | ||
|
|
||
| For a more complete example, see the | ||
| [UsbSerialExamples project](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples) | ||
| in git, which is a simple application for reading and showing serial data. | ||
|
|
||
| A [simple Arduino application](https://github.com/mik3y/usb-serial-for-android/blob/master/arduino) | ||
| is also available which can be used for testing. | ||
|
|
||
|
|
||
| ## Probing for Unrecognized Devices | ||
|
|
||
| Sometimes you may need to do a little extra work to support devices which | ||
| usb-serial-for-android doesn't [yet] know about -- but which you know to be | ||
| compatible with one of the built-in drivers. This may be the case for a brand | ||
| new device or for one using a custom VID/PID pair. | ||
|
|
||
| UsbSerialProber is a class to help you find and instantiate compatible | ||
| UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use | ||
| the default prober returned by ``UsbSerialProber.getDefaultProber()``, which | ||
| uses the built-in list of well-known VIDs and PIDs that are supported by our | ||
| drivers. | ||
|
|
||
| To use your own set of rules, create and use a custom prober: | ||
|
|
||
| ```java | ||
| // Probe for our custom CDC devices, which use VID 0x1234 | ||
| // and PIDS 0x0001 and 0x0002. | ||
| ProbeTable customTable = new ProbeTable(); | ||
| customTable.addProduct(0x1234, 0x0001, CdcAcmSerialDriver.class); | ||
| customTable.addProduct(0x1234, 0x0002, CdcAcmSerialDriver.class); | ||
| UsbSerialProber prober = new UsbSerialProber(customTable); | ||
| List<UsbSerialDriver> drivers = prober.findAllDrivers(usbManager); | ||
| // ... | ||
| ``` | ||
|
|
||
| Of course, nothing requires you to use UsbSerialProber at all: you can | ||
| instantiate driver classes directly if you know what you're doing; just supply | ||
| a compatible UsbDevice. | ||
|
|
||
|
|
||
| ## Compatible Devices | ||
|
|
||
| * *Serial chips:* FT232R, CDC/ACM (eg Arduino Uno) and possibly others. | ||
| See [CompatibleSerialDevices](https://github.com/mik3y/usb-serial-for-android/wiki/Compatible-Serial-Devices). | ||
| * *Android phones and tablets:* Nexus 7, Motorola Xoom, and many others. | ||
| See [CompatibleAndroidDevices](https://github.com/mik3y/usb-serial-for-android/wiki/Compatible-Android-Devices). | ||
|
|
||
|
|
||
| ## Author, License, and Copyright | ||
|
|
||
| usb-serial-for-android is written and maintained by *mike wakerly*. | ||
|
|
||
| This library is licensed under *LGPL Version 2.1*. Please see LICENSE.txt for the | ||
| complete license. | ||
|
|
||
| Copyright 2011-2012, Google Inc. All Rights Reserved. | ||
|
|
||
| Portions of this library are based on libftdi | ||
| (http://www.intra2net.com/en/developer/libftdi). Please see | ||
| FtdiSerialDriver.java for more information. | ||
|
|
||
| ## Help & Discussion | ||
|
|
||
| For common problems, see the | ||
| [Troubleshooting](https://github.com/mik3y/usb-serial-for-android/wiki/Troubleshooting) | ||
| wiki page. | ||
|
|
||
| For other help and discussion, please join our Google Group, | ||
| [usb-serial-for-android](https://groups.google.com/forum/?fromgroups#!forum/usb-serial-for-android). | ||
|
|
||
| Are you using the library? Let us know on the group and we'll add your project to | ||
| [ProjectsUsingUsbSerialForAndroid](https://github.com/mik3y/usb-serial-for-android/wiki/Projects-Using-usb-serial-for-android). | ||
|
|
| @@ -0,0 +1,43 @@ | ||
| /* Copyright 2012 Google Inc. | ||
| * | ||
| * This library is free software; you can redistribute it and/or | ||
| * modify it under the terms of the GNU Lesser General Public | ||
| * License as published by the Free Software Foundation; either | ||
| * version 2.1 of the License, or (at your option) any later version. | ||
| * | ||
| * This library is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * Lesser General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public | ||
| * License along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | ||
| * USA. | ||
| * | ||
| * Project home page: http://code.google.com/p/usb-serial-for-android/ | ||
| */ | ||
|
|
||
| // Sample Arduino sketch for use with usb-serial-for-android. | ||
| // Prints an ever-increasing counter, and writes back anything | ||
| // it receives. | ||
|
|
||
| static int counter = 0; | ||
| void setup() { | ||
| Serial.begin(115200); | ||
| } | ||
|
|
||
| void loop() { | ||
| Serial.print("Tick #"); | ||
| Serial.print(counter++, DEC); | ||
| Serial.print("\n"); | ||
|
|
||
| if (Serial.peek() != -1) { | ||
| Serial.print("Read: "); | ||
| do { | ||
| Serial.print((char) Serial.read()); | ||
| } while (Serial.peek() != -1); | ||
| Serial.print("\n"); | ||
| } | ||
| delay(1000); | ||
| } |
| @@ -0,0 +1,16 @@ | ||
| // Top-level gradle script. | ||
|
|
||
| buildscript { | ||
| repositories { | ||
| mavenCentral() | ||
| } | ||
| dependencies { | ||
| classpath 'com.android.tools.build:gradle:1.0.0' | ||
| } | ||
| } | ||
|
|
||
| allprojects { | ||
| repositories { | ||
| mavenCentral() | ||
| } | ||
| } |
| @@ -0,0 +1,6 @@ | ||
| #Thu Feb 26 13:05:12 EST 2015 | ||
| distributionBase=GRADLE_USER_HOME | ||
| distributionPath=wrapper/dists | ||
| zipStoreBase=GRADLE_USER_HOME | ||
| zipStorePath=wrapper/dists | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip |
| @@ -0,0 +1,164 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| ############################################################################## | ||
| ## | ||
| ## Gradle start up script for UN*X | ||
| ## | ||
| ############################################################################## | ||
|
|
||
| # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||
| DEFAULT_JVM_OPTS="" | ||
|
|
||
| APP_NAME="Gradle" | ||
| APP_BASE_NAME=`basename "$0"` | ||
|
|
||
| # Use the maximum available, or set MAX_FD != -1 to use that value. | ||
| MAX_FD="maximum" | ||
|
|
||
| warn ( ) { | ||
| echo "$*" | ||
| } | ||
|
|
||
| die ( ) { | ||
| echo | ||
| echo "$*" | ||
| echo | ||
| exit 1 | ||
| } | ||
|
|
||
| # OS specific support (must be 'true' or 'false'). | ||
| cygwin=false | ||
| msys=false | ||
| darwin=false | ||
| case "`uname`" in | ||
| CYGWIN* ) | ||
| cygwin=true | ||
| ;; | ||
| Darwin* ) | ||
| darwin=true | ||
| ;; | ||
| MINGW* ) | ||
| msys=true | ||
| ;; | ||
| esac | ||
|
|
||
| # For Cygwin, ensure paths are in UNIX format before anything is touched. | ||
| if $cygwin ; then | ||
| [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` | ||
| fi | ||
|
|
||
| # Attempt to set APP_HOME | ||
| # Resolve links: $0 may be a link | ||
| PRG="$0" | ||
| # Need this for relative symlinks. | ||
| while [ -h "$PRG" ] ; do | ||
| ls=`ls -ld "$PRG"` | ||
| link=`expr "$ls" : '.*-> \(.*\)$'` | ||
| if expr "$link" : '/.*' > /dev/null; then | ||
| PRG="$link" | ||
| else | ||
| PRG=`dirname "$PRG"`"/$link" | ||
| fi | ||
| done | ||
| SAVED="`pwd`" | ||
| cd "`dirname \"$PRG\"`/" >&- | ||
| APP_HOME="`pwd -P`" | ||
| cd "$SAVED" >&- | ||
|
|
||
| CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | ||
|
|
||
| # Determine the Java command to use to start the JVM. | ||
| if [ -n "$JAVA_HOME" ] ; then | ||
| if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | ||
| # IBM's JDK on AIX uses strange locations for the executables | ||
| JAVACMD="$JAVA_HOME/jre/sh/java" | ||
| else | ||
| JAVACMD="$JAVA_HOME/bin/java" | ||
| fi | ||
| if [ ! -x "$JAVACMD" ] ; then | ||
| die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | ||
| Please set the JAVA_HOME variable in your environment to match the | ||
| location of your Java installation." | ||
| fi | ||
| else | ||
| JAVACMD="java" | ||
| which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||
| Please set the JAVA_HOME variable in your environment to match the | ||
| location of your Java installation." | ||
| fi | ||
|
|
||
| # Increase the maximum file descriptors if we can. | ||
| if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then | ||
| MAX_FD_LIMIT=`ulimit -H -n` | ||
| if [ $? -eq 0 ] ; then | ||
| if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | ||
| MAX_FD="$MAX_FD_LIMIT" | ||
| fi | ||
| ulimit -n $MAX_FD | ||
| if [ $? -ne 0 ] ; then | ||
| warn "Could not set maximum file descriptor limit: $MAX_FD" | ||
| fi | ||
| else | ||
| warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | ||
| fi | ||
| fi | ||
|
|
||
| # For Darwin, add options to specify how the application appears in the dock | ||
| if $darwin; then | ||
| GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | ||
| fi | ||
|
|
||
| # For Cygwin, switch paths to Windows format before running java | ||
| if $cygwin ; then | ||
| APP_HOME=`cygpath --path --mixed "$APP_HOME"` | ||
| CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | ||
|
|
||
| # We build the pattern for arguments to be converted via cygpath | ||
| ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | ||
| SEP="" | ||
| for dir in $ROOTDIRSRAW ; do | ||
| ROOTDIRS="$ROOTDIRS$SEP$dir" | ||
| SEP="|" | ||
| done | ||
| OURCYGPATTERN="(^($ROOTDIRS))" | ||
| # Add a user-defined pattern to the cygpath arguments | ||
| if [ "$GRADLE_CYGPATTERN" != "" ] ; then | ||
| OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | ||
| fi | ||
| # Now convert the arguments - kludge to limit ourselves to /bin/sh | ||
| i=0 | ||
| for arg in "$@" ; do | ||
| CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | ||
| CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option | ||
|
|
||
| if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition | ||
| eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | ||
| else | ||
| eval `echo args$i`="\"$arg\"" | ||
| fi | ||
| i=$((i+1)) | ||
| done | ||
| case $i in | ||
| (0) set -- ;; | ||
| (1) set -- "$args0" ;; | ||
| (2) set -- "$args0" "$args1" ;; | ||
| (3) set -- "$args0" "$args1" "$args2" ;; | ||
| (4) set -- "$args0" "$args1" "$args2" "$args3" ;; | ||
| (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | ||
| (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | ||
| (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | ||
| (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | ||
| (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | ||
| esac | ||
| fi | ||
|
|
||
| # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules | ||
| function splitJvmOpts() { | ||
| JVM_OPTS=("$@") | ||
| } | ||
| eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS | ||
| JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" | ||
|
|
||
| exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
| @@ -0,0 +1,90 @@ | ||
| @if "%DEBUG%" == "" @echo off | ||
| @rem ########################################################################## | ||
| @rem | ||
| @rem Gradle startup script for Windows | ||
| @rem | ||
| @rem ########################################################################## | ||
|
|
||
| @rem Set local scope for the variables with windows NT shell | ||
| if "%OS%"=="Windows_NT" setlocal | ||
|
|
||
| @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||
| set DEFAULT_JVM_OPTS= | ||
|
|
||
| set DIRNAME=%~dp0 | ||
| if "%DIRNAME%" == "" set DIRNAME=. | ||
| set APP_BASE_NAME=%~n0 | ||
| set APP_HOME=%DIRNAME% | ||
|
|
||
| @rem Find java.exe | ||
| if defined JAVA_HOME goto findJavaFromJavaHome | ||
|
|
||
| set JAVA_EXE=java.exe | ||
| %JAVA_EXE% -version >NUL 2>&1 | ||
| if "%ERRORLEVEL%" == "0" goto init | ||
|
|
||
| echo. | ||
| echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||
| echo. | ||
| echo Please set the JAVA_HOME variable in your environment to match the | ||
| echo location of your Java installation. | ||
|
|
||
| goto fail | ||
|
|
||
| :findJavaFromJavaHome | ||
| set JAVA_HOME=%JAVA_HOME:"=% | ||
| set JAVA_EXE=%JAVA_HOME%/bin/java.exe | ||
|
|
||
| if exist "%JAVA_EXE%" goto init | ||
|
|
||
| echo. | ||
| echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | ||
| echo. | ||
| echo Please set the JAVA_HOME variable in your environment to match the | ||
| echo location of your Java installation. | ||
|
|
||
| goto fail | ||
|
|
||
| :init | ||
| @rem Get command-line arguments, handling Windowz variants | ||
|
|
||
| if not "%OS%" == "Windows_NT" goto win9xME_args | ||
| if "%@eval[2+2]" == "4" goto 4NT_args | ||
|
|
||
| :win9xME_args | ||
| @rem Slurp the command line arguments. | ||
| set CMD_LINE_ARGS= | ||
| set _SKIP=2 | ||
|
|
||
| :win9xME_args_slurp | ||
| if "x%~1" == "x" goto execute | ||
|
|
||
| set CMD_LINE_ARGS=%* | ||
| goto execute | ||
|
|
||
| :4NT_args | ||
| @rem Get arguments from the 4NT Shell from JP Software | ||
| set CMD_LINE_ARGS=%$ | ||
|
|
||
| :execute | ||
| @rem Setup the command line | ||
|
|
||
| set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||
|
|
||
| @rem Execute Gradle | ||
| "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | ||
|
|
||
| :end | ||
| @rem End local scope for the variables with windows NT shell | ||
| if "%ERRORLEVEL%"=="0" goto mainEnd | ||
|
|
||
| :fail | ||
| rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||
| rem the _cmd.exe /c_ return code! | ||
| if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||
| exit /b 1 | ||
|
|
||
| :mainEnd | ||
| if "%OS%"=="Windows_NT" endlocal | ||
|
|
||
| :omega |
| @@ -0,0 +1 @@ | ||
| include 'usbSerialForAndroid', 'usbSerialExamples' |
| @@ -0,0 +1,15 @@ | ||
| apply plugin: 'android' | ||
|
|
||
| android { | ||
| compileSdkVersion 19 | ||
| buildToolsVersion "19.1" | ||
|
|
||
| defaultConfig { | ||
| minSdkVersion 14 | ||
| targetSdkVersion 19 | ||
| } | ||
| } | ||
|
|
||
| dependencies { | ||
| compile project(':usbSerialForAndroid') | ||
| } |
| @@ -0,0 +1,39 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
| package="com.hoho.android.usbserial.examples" | ||
| android:versionCode="1" | ||
| android:versionName="1.0" > | ||
|
|
||
| <uses-sdk android:minSdkVersion="12" /> | ||
|
|
||
| <uses-feature android:name="android.hardware.usb.host" /> | ||
|
|
||
| <application | ||
| android:icon="@drawable/ic_launcher" | ||
| android:label="@string/app_name" > | ||
| <activity | ||
| android:name="com.hoho.android.usbserial.examples.DeviceListActivity" | ||
| android:label="@string/app_name" | ||
| android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" > | ||
| <intent-filter> | ||
| <action android:name="android.intent.action.MAIN" /> | ||
|
|
||
| <category android:name="android.intent.category.DEFAULT" /> | ||
| <category android:name="android.intent.category.LAUNCHER" /> | ||
| </intent-filter> | ||
| <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" /> | ||
| </activity> | ||
| <activity | ||
| android:name="com.hoho.android.usbserial.examples.SerialConsoleActivity" | ||
| android:label="@string/app_name" | ||
| android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" > | ||
| </activity> | ||
| </application> | ||
|
|
||
| </manifest> |
| @@ -0,0 +1,207 @@ | ||
| /* Copyright 2011-2013 Google Inc. | ||
| * Copyright 2013 mike wakerly <opensource@hoho.com> | ||
| * | ||
| * This library is free software; you can redistribute it and/or | ||
| * modify it under the terms of the GNU Lesser General Public | ||
| * License as published by the Free Software Foundation; either | ||
| * version 2.1 of the License, or (at your option) any later version. | ||
| * | ||
| * This library is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * Lesser General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public | ||
| * License along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | ||
| * USA. | ||
| * | ||
| * Project home page: https://github.com/mik3y/usb-serial-for-android | ||
| */ | ||
|
|
||
| package src.com.hoho.android.usbserial.examples; | ||
|
|
||
| import android.app.Activity; | ||
| import android.content.Context; | ||
| import android.hardware.usb.UsbDevice; | ||
| import android.hardware.usb.UsbManager; | ||
| import android.os.AsyncTask; | ||
| import android.os.Bundle; | ||
| import android.os.Handler; | ||
| import android.os.Message; | ||
| import android.os.SystemClock; | ||
| import android.util.Log; | ||
| import android.view.LayoutInflater; | ||
| import android.view.View; | ||
| import android.view.ViewGroup; | ||
| import android.widget.AdapterView; | ||
| import android.widget.ArrayAdapter; | ||
| import android.widget.ListView; | ||
| import android.widget.ProgressBar; | ||
| import android.widget.TextView; | ||
| import android.widget.TwoLineListItem; | ||
|
|
||
| import com.hoho.android.usbserial.driver.UsbSerialDriver; | ||
| import com.hoho.android.usbserial.driver.UsbSerialPort; | ||
| import com.hoho.android.usbserial.driver.UsbSerialProber; | ||
| import com.hoho.android.usbserial.examples.R; | ||
| import com.hoho.android.usbserial.util.HexDump; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| /** | ||
| * Shows a {@link android.widget.ListView} of available USB devices. | ||
| * | ||
| * @author mike wakerly (opensource@hoho.com) | ||
| */ | ||
| public class DeviceListActivity extends Activity { | ||
|
|
||
| private final String TAG = DeviceListActivity.class.getSimpleName(); | ||
|
|
||
| private UsbManager mUsbManager; | ||
| private ListView mListView; | ||
| private TextView mProgressBarTitle; | ||
| private ProgressBar mProgressBar; | ||
|
|
||
| private static final int MESSAGE_REFRESH = 101; | ||
| private static final long REFRESH_TIMEOUT_MILLIS = 5000; | ||
|
|
||
| private final Handler mHandler = new Handler() { | ||
| @Override | ||
| public void handleMessage(Message msg) { | ||
| switch (msg.what) { | ||
| case MESSAGE_REFRESH: | ||
| refreshDeviceList(); | ||
| mHandler.sendEmptyMessageDelayed(MESSAGE_REFRESH, REFRESH_TIMEOUT_MILLIS); | ||
| break; | ||
| default: | ||
| super.handleMessage(msg); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| }; | ||
|
|
||
| private List<UsbSerialPort> mEntries = new ArrayList<UsbSerialPort>(); | ||
| private ArrayAdapter<UsbSerialPort> mAdapter; | ||
|
|
||
| @Override | ||
| public void onCreate(Bundle savedInstanceState) { | ||
| super.onCreate(savedInstanceState); | ||
| setContentView(R.layout.main); | ||
|
|
||
| mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); | ||
| mListView = (ListView) findViewById(R.id.deviceList); | ||
| mProgressBar = (ProgressBar) findViewById(R.id.progressBar); | ||
| mProgressBarTitle = (TextView) findViewById(R.id.progressBarTitle); | ||
|
|
||
| mAdapter = new ArrayAdapter<UsbSerialPort>(this, | ||
| android.R.layout.simple_expandable_list_item_2, mEntries) { | ||
| @Override | ||
| public View getView(int position, View convertView, ViewGroup parent) { | ||
| final TwoLineListItem row; | ||
| if (convertView == null){ | ||
| final LayoutInflater inflater = | ||
| (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); | ||
| row = (TwoLineListItem) inflater.inflate(android.R.layout.simple_list_item_2, null); | ||
| } else { | ||
| row = (TwoLineListItem) convertView; | ||
| } | ||
|
|
||
| final UsbSerialPort port = mEntries.get(position); | ||
| final UsbSerialDriver driver = port.getDriver(); | ||
| final UsbDevice device = driver.getDevice(); | ||
|
|
||
| final String title = String.format("Vendor %s Product %s", | ||
| HexDump.toHexString((short) device.getVendorId()), | ||
| HexDump.toHexString((short) device.getProductId())); | ||
| row.getText1().setText(title); | ||
|
|
||
| final String subtitle = driver.getClass().getSimpleName(); | ||
| row.getText2().setText(subtitle); | ||
|
|
||
| return row; | ||
| } | ||
|
|
||
| }; | ||
| mListView.setAdapter(mAdapter); | ||
|
|
||
| mListView.setOnItemClickListener(new ListView.OnItemClickListener() { | ||
| @Override | ||
| public void onItemClick(AdapterView<?> parent, View view, int position, long id) { | ||
| Log.d(TAG, "Pressed item " + position); | ||
| if (position >= mEntries.size()) { | ||
| Log.w(TAG, "Illegal position."); | ||
| return; | ||
| } | ||
|
|
||
| final UsbSerialPort port = mEntries.get(position); | ||
| showConsoleActivity(port); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| @Override | ||
| protected void onResume() { | ||
| super.onResume(); | ||
| mHandler.sendEmptyMessage(MESSAGE_REFRESH); | ||
| } | ||
|
|
||
| @Override | ||
| protected void onPause() { | ||
| super.onPause(); | ||
| mHandler.removeMessages(MESSAGE_REFRESH); | ||
| } | ||
|
|
||
| private void refreshDeviceList() { | ||
| showProgressBar(); | ||
|
|
||
| new AsyncTask<Void, Void, List<UsbSerialPort>>() { | ||
| @Override | ||
| protected List<UsbSerialPort> doInBackground(Void... params) { | ||
| Log.d(TAG, "Refreshing device list ..."); | ||
| SystemClock.sleep(1000); | ||
|
|
||
| final List<UsbSerialDriver> drivers = | ||
| UsbSerialProber.getDefaultProber().findAllDrivers(mUsbManager); | ||
|
|
||
| final List<UsbSerialPort> result = new ArrayList<UsbSerialPort>(); | ||
| for (final UsbSerialDriver driver : drivers) { | ||
| final List<UsbSerialPort> ports = driver.getPorts(); | ||
| Log.d(TAG, String.format("+ %s: %s port%s", | ||
| driver, Integer.valueOf(ports.size()), ports.size() == 1 ? "" : "s")); | ||
| result.addAll(ports); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| @Override | ||
| protected void onPostExecute(List<UsbSerialPort> result) { | ||
| mEntries.clear(); | ||
| mEntries.addAll(result); | ||
| mAdapter.notifyDataSetChanged(); | ||
| mProgressBarTitle.setText( | ||
| String.format("%s device(s) found",Integer.valueOf(mEntries.size()))); | ||
| hideProgressBar(); | ||
| Log.d(TAG, "Done refreshing, " + mEntries.size() + " entries found."); | ||
| } | ||
|
|
||
| }.execute((Void) null); | ||
| } | ||
|
|
||
| private void showProgressBar() { | ||
| mProgressBar.setVisibility(View.VISIBLE); | ||
| mProgressBarTitle.setText(R.string.refreshing); | ||
| } | ||
|
|
||
| private void hideProgressBar() { | ||
| mProgressBar.setVisibility(View.INVISIBLE); | ||
| } | ||
|
|
||
| private void showConsoleActivity(UsbSerialPort port) { | ||
| SerialConsoleActivity.show(this, port); | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,191 @@ | ||
| /* Copyright 2011-2013 Google Inc. | ||
| * Copyright 2013 mike wakerly <opensource@hoho.com> | ||
| * | ||
| * This library is free software; you can redistribute it and/or | ||
| * modify it under the terms of the GNU Lesser General Public | ||
| * License as published by the Free Software Foundation; either | ||
| * version 2.1 of the License, or (at your option) any later version. | ||
| * | ||
| * This library is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * Lesser General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public | ||
| * License along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | ||
| * USA. | ||
| * | ||
| * Project home page: https://github.com/mik3y/usb-serial-for-android | ||
| */ | ||
|
|
||
| package src.com.hoho.android.usbserial.examples; | ||
|
|
||
| import android.app.Activity; | ||
| import android.content.Context; | ||
| import android.content.Intent; | ||
| import android.hardware.usb.UsbDeviceConnection; | ||
| import android.hardware.usb.UsbManager; | ||
| import android.os.Bundle; | ||
| import android.util.Log; | ||
| import android.widget.ScrollView; | ||
| import android.widget.TextView; | ||
|
|
||
| import com.hoho.android.usbserial.driver.UsbSerialPort; | ||
| import com.hoho.android.usbserial.examples.R; | ||
| import com.hoho.android.usbserial.util.HexDump; | ||
| import com.hoho.android.usbserial.util.SerialInputOutputManager; | ||
|
|
||
| import java.io.IOException; | ||
| import java.util.concurrent.ExecutorService; | ||
| import java.util.concurrent.Executors; | ||
|
|
||
| /** | ||
| * Monitors a single {@link UsbSerialPort} instance, showing all data | ||
| * received. | ||
| * | ||
| * @author mike wakerly (opensource@hoho.com) | ||
| */ | ||
| public class SerialConsoleActivity extends Activity { | ||
|
|
||
| private final String TAG = SerialConsoleActivity.class.getSimpleName(); | ||
|
|
||
| /** | ||
| * Driver instance, passed in statically via | ||
| * {@link #show(android.content.Context, UsbSerialPort)}. | ||
| * | ||
| * <p/> | ||
| * This is a devious hack; it'd be cleaner to re-create the driver using | ||
| * arguments passed in with the {@link #startActivity(android.content.Intent)} intent. We | ||
| * can get away with it because both activities will run in the same | ||
| * process, and this is a simple demo. | ||
| */ | ||
| private static UsbSerialPort sPort = null; | ||
|
|
||
| private TextView mTitleTextView; | ||
| private TextView mDumpTextView; | ||
| private ScrollView mScrollView; | ||
|
|
||
| private final ExecutorService mExecutor = Executors.newSingleThreadExecutor(); | ||
|
|
||
| private SerialInputOutputManager mSerialIoManager; | ||
|
|
||
| private final SerialInputOutputManager.Listener mListener = | ||
| new SerialInputOutputManager.Listener() { | ||
|
|
||
| @Override | ||
| public void onRunError(Exception e) { | ||
| Log.d(TAG, "Runner stopped."); | ||
| } | ||
|
|
||
| @Override | ||
| public void onNewData(final byte[] data) { | ||
| SerialConsoleActivity.this.runOnUiThread(new Runnable() { | ||
| @Override | ||
| public void run() { | ||
| SerialConsoleActivity.this.updateReceivedData(data); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
|
|
||
| @Override | ||
| public void onCreate(Bundle savedInstanceState) { | ||
| super.onCreate(savedInstanceState); | ||
| setContentView(R.layout.serial_console); | ||
| mTitleTextView = (TextView) findViewById(R.id.demoTitle); | ||
| mDumpTextView = (TextView) findViewById(R.id.consoleText); | ||
| mScrollView = (ScrollView) findViewById(R.id.demoScroller); | ||
| } | ||
|
|
||
| @Override | ||
| protected void onPause() { | ||
| super.onPause(); | ||
| stopIoManager(); | ||
| if (sPort != null) { | ||
| try { | ||
| sPort.close(); | ||
| } catch (IOException e) { | ||
| // Ignore. | ||
| } | ||
| sPort = null; | ||
| } | ||
| finish(); | ||
| } | ||
|
|
||
| @Override | ||
| protected void onResume() { | ||
| super.onResume(); | ||
| Log.d(TAG, "Resumed, port=" + sPort); | ||
| if (sPort == null) { | ||
| mTitleTextView.setText("No serial device."); | ||
| } else { | ||
| final UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); | ||
|
|
||
| UsbDeviceConnection connection = usbManager.openDevice(sPort.getDriver().getDevice()); | ||
| if (connection == null) { | ||
| mTitleTextView.setText("Opening device failed"); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| sPort.open(connection); | ||
| sPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); | ||
| } catch (IOException e) { | ||
| Log.e(TAG, "Error setting up device: " + e.getMessage(), e); | ||
| mTitleTextView.setText("Error opening device: " + e.getMessage()); | ||
| try { | ||
| sPort.close(); | ||
| } catch (IOException e2) { | ||
| // Ignore. | ||
| } | ||
| sPort = null; | ||
| return; | ||
| } | ||
| mTitleTextView.setText("Serial device: " + sPort.getClass().getSimpleName()); | ||
| } | ||
| onDeviceStateChange(); | ||
| } | ||
|
|
||
| private void stopIoManager() { | ||
| if (mSerialIoManager != null) { | ||
| Log.i(TAG, "Stopping io manager .."); | ||
| mSerialIoManager.stop(); | ||
| mSerialIoManager = null; | ||
| } | ||
| } | ||
|
|
||
| private void startIoManager() { | ||
| if (sPort != null) { | ||
| Log.i(TAG, "Starting io manager .."); | ||
| mSerialIoManager = new SerialInputOutputManager(sPort, mListener); | ||
| mExecutor.submit(mSerialIoManager); | ||
| } | ||
| } | ||
|
|
||
| private void onDeviceStateChange() { | ||
| stopIoManager(); | ||
| startIoManager(); | ||
| } | ||
|
|
||
| private void updateReceivedData(byte[] data) { | ||
| final String message = "Read " + data.length + " bytes: \n" | ||
| + HexDump.dumpHexString(data) + "\n\n"; | ||
| mDumpTextView.append(message); | ||
| mScrollView.smoothScrollTo(0, mDumpTextView.getBottom()); | ||
| } | ||
|
|
||
| /** | ||
| * Starts the activity, using the supplied driver instance. | ||
| * | ||
| * @param context | ||
| * @param port | ||
| */ | ||
| static void show(Context context, UsbSerialPort port) { | ||
| sPort = port; | ||
| final Intent intent = new Intent(context, SerialConsoleActivity.class); | ||
| intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY); | ||
| context.startActivity(intent); | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,50 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="match_parent" > | ||
|
|
||
| <TextView | ||
| android:id="@+id/demoTitle" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:layout_alignParentTop="true" | ||
| android:layout_centerHorizontal="true" | ||
| android:text="@string/app_title" | ||
| android:textSize="24sp" | ||
| android:textStyle="bold" /> | ||
|
|
||
| <TextView | ||
| android:id="@+id/progressBarTitle" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/demoTitle" | ||
| android:layout_centerHorizontal="true" | ||
| android:text="@string/refreshing" | ||
| android:padding="8dp" | ||
| android:textSize="18sp" /> | ||
|
|
||
| <ProgressBar | ||
| android:id="@+id/progressBar" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/progressBarTitle" | ||
| android:layout_centerHorizontal="true" | ||
| android:padding="8dp" | ||
| style="@android:style/Widget.Holo.ProgressBar.Horizontal" | ||
| android:indeterminate="true" /> | ||
|
|
||
| <View | ||
| android:id="@+id/separator" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="1dip" | ||
| android:layout_below="@+id/progressBar" | ||
| android:layout_centerHorizontal="true" | ||
| android:background="#eeeeee" /> | ||
|
|
||
| <ListView | ||
| android:id="@+id/deviceList" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/separator" /> | ||
|
|
||
| </RelativeLayout> |
| @@ -0,0 +1,36 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="match_parent" > | ||
|
|
||
| <TextView | ||
| android:id="@+id/demoTitle" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_alignParentTop="true" | ||
| android:text="@string/app_title" | ||
| android:textSize="24sp" | ||
| android:textStyle="bold" /> | ||
|
|
||
| <View | ||
| android:id="@+id/separator" | ||
| android:layout_width="match_parent" | ||
| android:layout_below="@+id/demoTitle" | ||
| android:layout_height="1dip" | ||
| android:background="#eeeeee" /> | ||
|
|
||
| <ScrollView | ||
| android:id="@+id/demoScroller" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_below="@+id/separator" > | ||
|
|
||
| <TextView | ||
| android:id="@+id/consoleText" | ||
| android:textIsSelectable="true" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:typeface="monospace" /> | ||
| </ScrollView> | ||
|
|
||
| </RelativeLayout> |
| @@ -0,0 +1,8 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <resources> | ||
|
|
||
| <string name="app_title">USB Serial Example</string> | ||
| <string name="app_name">Serial Example</string> | ||
| <string name="refreshing">Refreshing...</string> | ||
|
|
||
| </resources> |
| @@ -0,0 +1,20 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <resources> | ||
| <!-- 0x0403 / 0x6001: FTDI FT232R UART --> | ||
| <usb-device vendor-id="1027" product-id="24577" /> | ||
|
|
||
| <!-- 0x0403 / 0x6015: FTDI FT231X --> | ||
| <usb-device vendor-id="1027" product-id="24597" /> | ||
|
|
||
| <!-- 0x2341 / Arduino --> | ||
| <usb-device vendor-id="9025" /> | ||
|
|
||
| <!-- 0x16C0 / 0x0483: Teensyduino --> | ||
| <usb-device vendor-id="5824" product-id="1155" /> | ||
|
|
||
| <!-- 0x10C4 / 0xEA60: CP210x UART Bridge --> | ||
| <usb-device vendor-id="4292" product-id="60000" /> | ||
|
|
||
| <!-- 0x067B / 0x2303: Prolific PL2303 --> | ||
| <usb-device vendor-id="1659" product-id="8963" /> | ||
| </resources> |
| @@ -0,0 +1,10 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
| package="com.hoho.android.usbserial" | ||
| android:versionCode="1" | ||
| android:versionName="1.0"> | ||
| <uses-sdk android:minSdkVersion="12" /> | ||
| <activity | ||
| android:name="bookstack.SerialConsoleActivity" /> | ||
|
|
||
| </manifest> |
| @@ -0,0 +1,19 @@ | ||
| package com.hoho.android.usbserial; | ||
|
|
||
| /** | ||
| * Static container of information about this library. | ||
| */ | ||
| public final class BuildInfo { | ||
|
|
||
| /** | ||
| * The current version of this library. Values are of the form | ||
| * "major.minor.micro[-suffix]". A suffix of "-pre" indicates a pre-release | ||
| * of the version preceeding it. | ||
| */ | ||
| public static final String VERSION = "0.2.0-pre"; | ||
|
|
||
| private BuildInfo() { | ||
| throw new IllegalStateException("Non-instantiable class."); | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,353 @@ | ||
| /* Copyright 2011-2013 Google Inc. | ||
| * Copyright 2013 mike wakerly <opensource@hoho.com> | ||
| * | ||
| * This library is free software; you can redistribute it and/or | ||
| * modify it under the terms of the GNU Lesser General Public | ||
| * License as published by the Free Software Foundation; either | ||
| * version 2.1 of the License, or (at your option) any later version. | ||
| * | ||
| * This library is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * Lesser General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public | ||
| * License along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | ||
| * USA. | ||
| * | ||
| * Project home page: https://github.com/mik3y/usb-serial-for-android | ||
| */ | ||
|
|
||
| package com.hoho.android.usbserial.driver; | ||
|
|
||
| import android.hardware.usb.UsbConstants; | ||
| import android.hardware.usb.UsbDevice; | ||
| import android.hardware.usb.UsbDeviceConnection; | ||
| import android.hardware.usb.UsbEndpoint; | ||
| import android.hardware.usb.UsbInterface; | ||
| import android.hardware.usb.UsbRequest; | ||
| import android.os.Build; | ||
| import android.util.Log; | ||
|
|
||
| import java.io.IOException; | ||
| import java.nio.ByteBuffer; | ||
| import java.util.Collections; | ||
| import java.util.LinkedHashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * USB CDC/ACM serial driver implementation. | ||
| * | ||
| * @author mike wakerly (opensource@hoho.com) | ||
| * @see <a | ||
| * href="http://www.usb.org/developers/devclass_docs/usbcdc11.pdf">Universal | ||
| * Serial Bus Class Definitions for Communication Devices, v1.1</a> | ||
| */ | ||
| public class CdcAcmSerialDriver implements UsbSerialDriver { | ||
|
|
||
| private final String TAG = CdcAcmSerialDriver.class.getSimpleName(); | ||
|
|
||
| private final UsbDevice mDevice; | ||
| private final UsbSerialPort mPort; | ||
|
|
||
| public CdcAcmSerialDriver(UsbDevice device) { | ||
| mDevice = device; | ||
| mPort = new CdcAcmSerialPort(device, 0); | ||
| } | ||
|
|
||
| @Override | ||
| public UsbDevice getDevice() { | ||
| return mDevice; | ||
| } | ||
|
|
||
| @Override | ||
| public List<UsbSerialPort> getPorts() { | ||
| return Collections.singletonList(mPort); | ||
| } | ||
|
|
||
| class CdcAcmSerialPort extends CommonUsbSerialPort { | ||
|
|
||
| private final boolean mEnableAsyncReads; | ||
| private UsbInterface mControlInterface; | ||
| private UsbInterface mDataInterface; | ||
|
|
||
| private UsbEndpoint mControlEndpoint; | ||
| private UsbEndpoint mReadEndpoint; | ||
| private UsbEndpoint mWriteEndpoint; | ||
|
|
||
| private boolean mRts = false; | ||
| private boolean mDtr = false; | ||
|
|
||
| private static final int USB_RECIP_INTERFACE = 0x01; | ||
| private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE; | ||
|
|
||
| private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2 | ||
| private static final int GET_LINE_CODING = 0x21; | ||
| private static final int SET_CONTROL_LINE_STATE = 0x22; | ||
| private static final int SEND_BREAK = 0x23; | ||
|
|
||
| public CdcAcmSerialPort(UsbDevice device, int portNumber) { | ||
| super(device, portNumber); | ||
| mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1); | ||
| } | ||
|
|
||
| @Override | ||
| public UsbSerialDriver getDriver() { | ||
| return CdcAcmSerialDriver.this; | ||
| } | ||
|
|
||
| @Override | ||
| public void open(UsbDeviceConnection connection) throws IOException { | ||
| if (mConnection != null) { | ||
| throw new IOException("Already open"); | ||
| } | ||
|
|
||
| mConnection = connection; | ||
| boolean opened = false; | ||
| try { | ||
| Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount()); | ||
| mControlInterface = mDevice.getInterface(0); | ||
| Log.d(TAG, "Control iface=" + mControlInterface); | ||
| // class should be USB_CLASS_COMM | ||
|
|
||
| if (!mConnection.claimInterface(mControlInterface, true)) { | ||
| throw new IOException("Could not claim control interface."); | ||
| } | ||
| mControlEndpoint = mControlInterface.getEndpoint(0); | ||
| Log.d(TAG, "Control endpoint direction: " + mControlEndpoint.getDirection()); | ||
|
|
||
| Log.d(TAG, "Claiming data interface."); | ||
| mDataInterface = mDevice.getInterface(1); | ||
| Log.d(TAG, "data iface=" + mDataInterface); | ||
| // class should be USB_CLASS_CDC_DATA | ||
|
|
||
| if (!mConnection.claimInterface(mDataInterface, true)) { | ||
| throw new IOException("Could not claim data interface."); | ||
| } | ||
| mReadEndpoint = mDataInterface.getEndpoint(1); | ||
| Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection()); | ||
| mWriteEndpoint = mDataInterface.getEndpoint(0); | ||
| Log.d(TAG, "Write endpoint direction: " + mWriteEndpoint.getDirection()); | ||
| if (mEnableAsyncReads) { | ||
| Log.d(TAG, "Async reads enabled"); | ||
| } else { | ||
| Log.d(TAG, "Async reads disabled."); | ||
| } | ||
| opened = true; | ||
| } finally { | ||
| if (!opened) { | ||
| mConnection = null; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private int sendAcmControlMessage(int request, int value, byte[] buf) { | ||
| return mConnection.controlTransfer( | ||
| USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000); | ||
| } | ||
|
|
||
| @Override | ||
| public void close() throws IOException { | ||
| if (mConnection == null) { | ||
| throw new IOException("Already closed"); | ||
| } | ||
| mConnection.close(); | ||
| mConnection = null; | ||
| } | ||
|
|
||
| @Override | ||
| public int read(byte[] dest, int timeoutMillis) throws IOException { | ||
| if (mEnableAsyncReads) { | ||
| final UsbRequest request = new UsbRequest(); | ||
| try { | ||
| request.initialize(mConnection, mReadEndpoint); | ||
| final ByteBuffer buf = ByteBuffer.wrap(dest); | ||
| if (!request.queue(buf, dest.length)) { | ||
| throw new IOException("Error queueing request."); | ||
| } | ||
|
|
||
| final UsbRequest response = mConnection.requestWait(); | ||
| if (response == null) { | ||
| throw new IOException("Null response"); | ||
| } | ||
|
|
||
| final int nread = buf.position(); | ||
| if (nread > 0) { | ||
| //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); | ||
| return nread; | ||
| } else { | ||
| return 0; | ||
| } | ||
| } finally { | ||
| request.close(); | ||
| } | ||
| } | ||
|
|
||
| final int numBytesRead; | ||
| synchronized (mReadBufferLock) { | ||
| int readAmt = Math.min(dest.length, mReadBuffer.length); | ||
| numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt, | ||
| timeoutMillis); | ||
| if (numBytesRead < 0) { | ||
| // This sucks: we get -1 on timeout, not 0 as preferred. | ||
| // We *should* use UsbRequest, except it has a bug/api oversight | ||
| // where there is no way to determine the number of bytes read | ||
| // in response :\ -- http://b.android.com/28023 | ||
| if (timeoutMillis == Integer.MAX_VALUE) { | ||
| // Hack: Special case "~infinite timeout" as an error. | ||
| return -1; | ||
| } | ||
| return 0; | ||
| } | ||
| System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead); | ||
| } | ||
| return numBytesRead; | ||
| } | ||
|
|
||
| @Override | ||
| public int write(byte[] src, int timeoutMillis) throws IOException { | ||
| // TODO(mikey): Nearly identical to FtdiSerial write. Refactor. | ||
| int offset = 0; | ||
|
|
||
| while (offset < src.length) { | ||
| final int writeLength; | ||
| final int amtWritten; | ||
|
|
||
| synchronized (mWriteBufferLock) { | ||
| final byte[] writeBuffer; | ||
|
|
||
| writeLength = Math.min(src.length - offset, mWriteBuffer.length); | ||
| if (offset == 0) { | ||
| writeBuffer = src; | ||
| } else { | ||
| // bulkTransfer does not support offsets, make a copy. | ||
| System.arraycopy(src, offset, mWriteBuffer, 0, writeLength); | ||
| writeBuffer = mWriteBuffer; | ||
| } | ||
|
|
||
| amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, | ||
| timeoutMillis); | ||
| } | ||
| if (amtWritten <= 0) { | ||
| throw new IOException("Error writing " + writeLength | ||
| + " bytes at offset " + offset + " length=" + src.length); | ||
| } | ||
|
|
||
| Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); | ||
| offset += amtWritten; | ||
| } | ||
| return offset; | ||
| } | ||
|
|
||
| @Override | ||
| public void setParameters(int baudRate, int dataBits, int stopBits, int parity) { | ||
| byte stopBitsByte; | ||
| switch (stopBits) { | ||
| case STOPBITS_1: stopBitsByte = 0; break; | ||
| case STOPBITS_1_5: stopBitsByte = 1; break; | ||
| case STOPBITS_2: stopBitsByte = 2; break; | ||
| default: throw new IllegalArgumentException("Bad value for stopBits: " + stopBits); | ||
| } | ||
|
|
||
| byte parityBitesByte; | ||
| switch (parity) { | ||
| case PARITY_NONE: parityBitesByte = 0; break; | ||
| case PARITY_ODD: parityBitesByte = 1; break; | ||
| case PARITY_EVEN: parityBitesByte = 2; break; | ||
| case PARITY_MARK: parityBitesByte = 3; break; | ||
| case PARITY_SPACE: parityBitesByte = 4; break; | ||
| default: throw new IllegalArgumentException("Bad value for parity: " + parity); | ||
| } | ||
|
|
||
| byte[] msg = { | ||
| (byte) ( baudRate & 0xff), | ||
| (byte) ((baudRate >> 8 ) & 0xff), | ||
| (byte) ((baudRate >> 16) & 0xff), | ||
| (byte) ((baudRate >> 24) & 0xff), | ||
| stopBitsByte, | ||
| parityBitesByte, | ||
| (byte) dataBits}; | ||
| sendAcmControlMessage(SET_LINE_CODING, 0, msg); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean getCD() throws IOException { | ||
| return false; // TODO | ||
| } | ||
|
|
||
| @Override | ||
| public boolean getCTS() throws IOException { | ||
| return false; // TODO | ||
| } | ||
|
|
||
| @Override | ||
| public boolean getDSR() throws IOException { | ||
| return false; // TODO | ||
| } | ||
|
|
||
| @Override | ||
| public boolean getDTR() throws IOException { | ||
| return mDtr; | ||
| } | ||
|
|
||
| @Override | ||
| public void setDTR(boolean value) throws IOException { | ||
| mDtr = value; | ||
| setDtrRts(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean getRI() throws IOException { | ||
| return false; // TODO | ||
| } | ||
|
|
||
| @Override | ||
| public boolean getRTS() throws IOException { | ||
| return mRts; | ||
| } | ||
|
|
||
| @Override | ||
| public void setRTS(boolean value) throws IOException { | ||
| mRts = value; | ||
| setDtrRts(); | ||
| } | ||
|
|
||
| private void setDtrRts() { | ||
| int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0); | ||
| sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| public static Map<Integer, int[]> getSupportedDevices() { | ||
| final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>(); | ||
| supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUINO), | ||
| new int[] { | ||
| UsbId.ARDUINO_UNO, | ||
| UsbId.ARDUINO_UNO_R3, | ||
| UsbId.ARDUINO_MEGA_2560, | ||
| UsbId.ARDUINO_MEGA_2560_R3, | ||
| UsbId.ARDUINO_SERIAL_ADAPTER, | ||
| UsbId.ARDUINO_SERIAL_ADAPTER_R3, | ||
| UsbId.ARDUINO_MEGA_ADK, | ||
| UsbId.ARDUINO_MEGA_ADK_R3, | ||
| UsbId.ARDUINO_LEONARDO, | ||
| }); | ||
| supportedDevices.put(Integer.valueOf(UsbId.VENDOR_VAN_OOIJEN_TECH), | ||
| new int[] { | ||
| UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL, | ||
| }); | ||
| supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ATMEL), | ||
| new int[] { | ||
| UsbId.ATMEL_LUFA_CDC_DEMO_APP, | ||
| }); | ||
| supportedDevices.put(Integer.valueOf(UsbId.VENDOR_LEAFLABS), | ||
| new int[] { | ||
| UsbId.LEAFLABS_MAPLE, | ||
| }); | ||
| return supportedDevices; | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,167 @@ | ||
| /* Copyright 2011-2013 Google Inc. | ||
| * Copyright 2013 mike wakerly <opensource@hoho.com> | ||
| * | ||
| * This library is free software; you can redistribute it and/or | ||
| * modify it under the terms of the GNU Lesser General Public | ||
| * License as published by the Free Software Foundation; either | ||
| * version 2.1 of the License, or (at your option) any later version. | ||
| * | ||
| * This library is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * Lesser General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public | ||
| * License along with this library; if not, write to the Free Software | ||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | ||
| * USA. | ||
| * | ||
| * Project home page: https://github.com/mik3y/usb-serial-for-android | ||
| */ | ||
|
|
||
| package com.hoho.android.usbserial.driver; | ||
|
|
||
| import android.hardware.usb.UsbDevice; | ||
| import android.hardware.usb.UsbDeviceConnection; | ||
|
|
||
| import java.io.IOException; | ||
|
|
||
| /** | ||
| * A base class shared by several driver implementations. | ||
| * | ||
| * @author mike wakerly (opensource@hoho.com) | ||
| */ | ||
| abstract class CommonUsbSerialPort implements UsbSerialPort { | ||
|
|
||
| public static final int DEFAULT_READ_BUFFER_SIZE = 16 * 1024; | ||
| public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024; | ||
|
|
||
| protected final UsbDevice mDevice; | ||
| protected final int mPortNumber; | ||
|
|
||
| // non-null when open() | ||
| protected UsbDeviceConnection mConnection = null; | ||
|
|
||
| protected final Object mReadBufferLock = new Object(); | ||
| protected final Object mWriteBufferLock = new Object(); | ||
|
|
||
| /** Internal read buffer. Guarded by {@link #mReadBufferLock}. */ | ||
| protected byte[] mReadBuffer; | ||
|
|
||
| /** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */ | ||
| protected byte[] mWriteBuffer; | ||
|
|
||
| public CommonUsbSerialPort(UsbDevice device, int portNumber) { | ||
| mDevice = device; | ||
| mPortNumber = portNumber; | ||
|
|
||
| mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE]; | ||
| mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE]; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return String.format("<%s device_name=%s device_id=%s port_number=%s>", | ||
| getClass().getSimpleName(), mDevice.getDeviceName(), | ||
| mDevice.getDeviceId(), mPortNumber); | ||
| } | ||
|
|
||
| /** | ||
| * Returns the currently-bound USB device. | ||
| * | ||
| * @return the device | ||
| */ | ||
| public final UsbDevice getDevice() { | ||
| return mDevice; | ||
| } | ||
|
|
||
| @Override | ||
| public int getPortNumber() { | ||
| return mPortNumber; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the device serial number | ||
| * @return serial number | ||
| */ | ||
| @Override | ||
| public String getSerial() { | ||
| return mConnection.getSerial(); | ||
| } | ||
|
|
||
| /** | ||
| * Sets the size of the internal buffer used to exchange data with the USB | ||
| * stack for read operations. Most users should not need to change this. | ||
| * | ||
| * @param bufferSize the size in bytes | ||
| */ | ||
| public final void setReadBufferSize(int bufferSize) { | ||
| synchronized (mReadBufferLock) { | ||
| if (bufferSize == mReadBuffer.length) { | ||
| return; | ||
| } | ||
| mReadBuffer = new byte[bufferSize]; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Sets the size of the internal buffer used to exchange data with the USB | ||
| * stack for write operations. Most users should not need to change this. | ||
| * | ||
| * @param bufferSize the size in bytes | ||
| */ | ||
| public final void setWriteBufferSize(int bufferSize) { | ||
| synchronized (mWriteBufferLock) { | ||
| if (bufferSize == mWriteBuffer.length) { | ||
| return; | ||
| } | ||
| mWriteBuffer = new byte[bufferSize]; | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public abstract void open(UsbDeviceConnection connection) throws IOException; | ||
|
|
||
| @Override | ||
| public abstract void close() throws IOException; | ||
|
|
||
| @Override | ||
| public abstract int read(final byte[] dest, final int timeoutMillis) throws IOException; | ||
|
|
||
| @Override | ||
| public abstract int write(final byte[] src, final int timeoutMillis) throws IOException; | ||
|
|
||
| @Override | ||
| public abstract void setParameters( | ||
| int baudRate, int dataBits, int stopBits, int parity) throws IOException; | ||
|
|
||
| @Override | ||
| public abstract boolean getCD() throws IOException; | ||
|
|
||
| @Override | ||
| public abstract boolean getCTS() throws IOException; | ||
|
|
||
| @Override | ||
| public abstract boolean getDSR() throws IOException; | ||
|
|
||
| @Override | ||
| public abstract boolean getDTR() throws IOException; | ||
|
|
||
| @Override | ||
| public abstract void setDTR(boolean value) throws IOException; | ||
|
|
||
| @Override | ||
| public abstract boolean getRI() throws IOException; | ||
|
|
||
| @Override | ||
| public abstract boolean getRTS() throws IOException; | ||
|
|
||
| @Override | ||
| public abstract void setRTS(boolean value) throws IOException; | ||
|
|
||
| @Override | ||
| public boolean purgeHwBuffers(boolean flushReadBuffers, boolean flushWriteBuffers) throws IOException { | ||
| return !flushReadBuffers && !flushWriteBuffers; | ||
| } | ||
|
|
||
| } |