├── .github └── workflows │ └── build.yml ├── .gitignore ├── .idea ├── .gitignore ├── AndroidProjectSystem.xml ├── compiler.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── CHANGELOG.txt ├── LICENSE.txt ├── README.md ├── build.gradle ├── codecov.yml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml ├── settings.gradle ├── test ├── arduino_leonardo_bridge │ └── arduino_leonardo_bridge.ino ├── arduino_leonardo_bridge_castrated_cdc │ ├── CDC.cpp │ ├── README.md │ ├── USBCore.h │ └── arduino_leonardo_bridge_castrated_cdc.ino ├── arduino_leonardo_bridge_multi_cdc │ ├── CDC.cpp │ ├── README.md │ ├── USBCore.cpp │ ├── USBCore.h │ ├── USBDesc.h │ └── arduino_leonardo_bridge_multi_cdc.ino ├── pi_pico │ ├── README.md │ └── tinyusb_dev_cdc_dual_ports.uf2 └── rfc2217_server.diff ├── usbSerialExamples ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── hoho │ │ └── android │ │ └── usbserial │ │ └── examples │ │ ├── CustomProber.java │ │ ├── DevicesFragment.java │ │ ├── MainActivity.java │ │ └── TerminalFragment.java │ └── res │ ├── drawable │ ├── ic_delete_white_24dp.xml │ └── ic_send_white_24dp.xml │ ├── layout │ ├── activity_main.xml │ ├── device_list_header.xml │ ├── device_list_item.xml │ └── fragment_terminal.xml │ ├── menu │ ├── menu_devices.xml │ └── menu_terminal.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values │ ├── arrays.xml │ ├── colors.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── device_filter.xml └── usbSerialForAndroid ├── build.gradle ├── coverage.gradle ├── proguard-rules.pro └── src ├── androidTest ├── AndroidManifest.xml └── java │ └── com │ └── hoho │ └── android │ └── usbserial │ ├── CrossoverTest.java │ ├── DeviceTest.java │ ├── driver │ ├── CommonUsbSerialPortWrapper.java │ └── ProlificSerialPortWrapper.java │ └── util │ ├── TelnetWrapper.java │ ├── TestBuffer.java │ └── UsbWrapper.java ├── main ├── AndroidManifest.xml └── java │ └── com │ └── hoho │ └── android │ └── usbserial │ ├── driver │ ├── CdcAcmSerialDriver.java │ ├── Ch34xSerialDriver.java │ ├── ChromeCcdSerialDriver.java │ ├── CommonUsbSerialPort.java │ ├── Cp21xxSerialDriver.java │ ├── FtdiSerialDriver.java │ ├── GsmModemSerialDriver.java │ ├── ProbeTable.java │ ├── ProlificSerialDriver.java │ ├── SerialTimeoutException.java │ ├── UsbId.java │ ├── UsbSerialDriver.java │ ├── UsbSerialPort.java │ └── UsbSerialProber.java │ └── util │ ├── HexDump.java │ ├── MonotonicClock.java │ ├── SerialInputOutputManager.java │ ├── UsbUtils.java │ └── XonXoffFilter.java └── test └── java ├── android └── util │ ├── Log.java │ └── Pair.java └── com └── hoho └── android └── usbserial ├── driver ├── CdcAcmSerialDriverTest.java └── FtdiSerialDriverTest.java └── util ├── HexDumpText.java └── SerialInputOutputManagerTest.java /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: actions/setup-java@v3 13 | with: 14 | distribution: 'temurin' 15 | java-version: '17' 16 | - name: Build with Gradle 17 | run: ./gradlew assembleDebug 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Studio/Gradle 16 | *.iml 17 | .gradle/ 18 | build/ 19 | 20 | # User-specific stuff: 21 | .idea/workspace.xml 22 | .idea/tasks.xml 23 | .idea/dictionaries 24 | .idea/markdown-navigator*.xml 25 | 26 | # Sensitive or high-churn files: 27 | .idea/dataSources.ids 28 | .idea/dataSources.xml 29 | .idea/sqlDataSources.xml 30 | .idea/dynamic.xml 31 | .idea/uiDesigner.xml 32 | 33 | # Gradle: 34 | .idea/gradle.xml 35 | .idea/libraries 36 | .idea/jarRepositories.xml 37 | 38 | # Eclipse/Android/Misc 39 | .metadata/ 40 | local.properties 41 | *.DS_Store 42 | proguard/ 43 | jacoco.exec 44 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | caches 2 | codeStyles 3 | libraries 4 | workspace.xml 5 | androidTestResultsUserPreferences.xml 6 | appInsightsSettings.xml 7 | deploymentTargetDropDown.xml 8 | deploymentTargetSelector.xml 9 | other.xml 10 | -------------------------------------------------------------------------------- /.idea/AndroidProjectSystem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 31 | 54 | 55 | 56 | 57 | 58 | 59 | 61 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | For recent changelog look here: 2 | * https://github.com/mik3y/usb-serial-for-android/releases 3 | 4 | v0.2.0 (unreleased) 5 | * Gradle, Android Studio support. 6 | * New driver: CP2102 (thanks Ducky). 7 | * New prober support: LUFA Virtual Serial, Leaflabs Maple, Teensyduino. 8 | * New driver methods: getCD, getCTS, getDSR, getDTR, setDTR, getRI, getRTS, 9 | setRTS. 10 | * API change: setBaudrate() has been removed; use setParameters(). 11 | * API change: open() no longer implicitly sets the baud rate. Clients should 12 | call setParameters() immediately after open(), when necessary. 13 | * Library version is available in `com.hoho.android.usbserial.BuildInfo`. 14 | 15 | v0.1.0 (2012-10-12) 16 | * New driver: CdcAcmSerialDriver. 17 | * Better tuned read and write buffer sizes. 18 | 19 | v0.0.1 (2011-12-28) 20 | * Initial release. 21 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2011-2013 Google Inc. 4 | Copyright (c) 2013 Mike Wakerly 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Actions Status](https://github.com/mik3y/usb-serial-for-android/workflows/build/badge.svg)](https://github.com/mik3y/usb-serial-for-android/actions) 2 | [![Jitpack](https://jitpack.io/v/mik3y/usb-serial-for-android.svg)](https://jitpack.io/#mik3y/usb-serial-for-android) 3 | [![Codacy](https://app.codacy.com/project/badge/Grade/ef799bba8a7343818af0a90eba3ecb46)](https://app.codacy.com/gh/kai-morich/usb-serial-for-android-mik3y/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) 4 | [![codecov](https://codecov.io/gh/mik3y/usb-serial-for-android/branch/master/graph/badge.svg)](https://codecov.io/gh/mik3y/usb-serial-for-android) 5 | 6 | # usb-serial-for-android 7 | 8 | This is a driver library for communication with Arduinos and other USB serial hardware on 9 | Android, using the 10 | [Android USB Host Mode (OTG)](http://developer.android.com/guide/topics/connectivity/usb/host.html) 11 | available since Android 3.1 and working reliably since Android 4.2. 12 | 13 | No root access, ADK, or special kernel drivers are required; all drivers are implemented in 14 | Java. You get a raw serial port with `read()`, `write()`, and [other functions](https://github.com/mik3y/usb-serial-for-android/wiki/FAQ#Feature_Matrix) for use with your own protocols. 15 | 16 | ## Quick Start 17 | 18 | **1.** Add library to your project: 19 | 20 | Add jitpack.io repository to your root build.gradle: 21 | ```gradle 22 | allprojects { 23 | repositories { 24 | ... 25 | maven { url 'https://jitpack.io' } 26 | } 27 | } 28 | ``` 29 | 30 | Starting with gradle 6.8 you can alternatively add jitpack.io repository to your settings.gradle: 31 | ```gradle 32 | dependencyResolutionManagement { 33 | repositories { 34 | ... 35 | maven { url 'https://jitpack.io' } 36 | } 37 | } 38 | ``` 39 | 40 | If using gradle kotlin use line 41 | ```gradle.kts 42 | maven(url = "https://jitpack.io") 43 | ``` 44 | 45 | Add library to dependencies 46 | ```gradle 47 | dependencies { 48 | implementation 'com.github.mik3y:usb-serial-for-android:3.9.0' 49 | } 50 | ``` 51 | 52 | **2.** If the app should be notified when a device is attached, add 53 | [device_filter.xml](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples/src/main/res/xml/device_filter.xml) 54 | to your project's `res/xml/` directory and configure in your `AndroidManifest.xml`. 55 | 56 | ```xml 57 | 60 | 61 | 62 | 63 | 66 | 67 | ``` 68 | 69 | **3.** Use it! Example code snippet: 70 | 71 | open device: 72 | ```java 73 | // Find all available drivers from attached devices. 74 | UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); 75 | List availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager); 76 | if (availableDrivers.isEmpty()) { 77 | return; 78 | } 79 | 80 | // Open a connection to the first available driver. 81 | UsbSerialDriver driver = availableDrivers.get(0); 82 | UsbDeviceConnection connection = manager.openDevice(driver.getDevice()); 83 | if (connection == null) { 84 | // add UsbManager.requestPermission(driver.getDevice(), ..) handling here 85 | return; 86 | } 87 | 88 | UsbSerialPort port = driver.getPorts().get(0); // Most devices have just one port (port 0) 89 | port.open(connection); 90 | port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); 91 | ``` 92 | then use direct read/write 93 | ```java 94 | port.write(request, WRITE_WAIT_MILLIS); 95 | len = port.read(response, READ_WAIT_MILLIS); 96 | ``` 97 | or direct write + event driven read: 98 | ```java 99 | usbIoManager = new SerialInputOutputManager(usbSerialPort, this); 100 | usbIoManager.start(); 101 | ... 102 | port.write("hello".getBytes(), WRITE_WAIT_MILLIS); 103 | 104 | @Override 105 | public void onNewData(byte[] data) { 106 | runOnUiThread(() -> { textView.append(new String(data)); }); 107 | } 108 | ``` 109 | and finally: 110 | ```java 111 | port.close(); 112 | ``` 113 | 114 | For a simple example, see 115 | [UsbSerialExamples](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples) 116 | folder in this project. 117 | 118 | See separate github project [SimpleUsbTerminal](https://github.com/kai-morich/SimpleUsbTerminal) 119 | for a more complete example with: 120 | * Background service to stay connected while the app is not visible or rotating 121 | * Flow control 122 | 123 | ## Probing for Unrecognized Devices 124 | 125 | Sometimes you may need to do a little extra work to support devices which 126 | usb-serial-for-android doesn't (yet) know about -- but which you know to be 127 | compatible with one of the built-in drivers. This may be the case for a brand 128 | new device or for one using a custom VID/PID pair. 129 | 130 | UsbSerialProber is a class to help you find and instantiate compatible 131 | UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use 132 | the default prober returned by ``UsbSerialProber.getDefaultProber()``, which 133 | uses USB interface types and the built-in list of well-known VIDs and PIDs that 134 | are supported by our drivers. 135 | 136 | To use your own set of rules, create and use a custom prober: 137 | 138 | ```java 139 | // Probe for our custom FTDI device, which use VID 0x1234 and PID 0x0001 and 0x0002. 140 | ProbeTable customTable = new ProbeTable(); 141 | customTable.addProduct(0x1234, 0x0001, FtdiSerialDriver.class); 142 | customTable.addProduct(0x1234, 0x0002, FtdiSerialDriver.class); 143 | 144 | UsbSerialProber prober = new UsbSerialProber(customTable); 145 | List drivers = prober.findAllDrivers(usbManager); 146 | // ... 147 | ``` 148 | *Note*: as of v3.5.0 this library detects CDC/ACM devices by USB interface types instead of fixed VID+PID, 149 | so custom probers are typically not required any more for CDC/ACM devices. 150 | 151 | Of course, nothing requires you to use UsbSerialProber at all: you can 152 | instantiate driver classes directly if you know what you're doing; just supply 153 | a compatible UsbDevice. 154 | 155 | ## Compatible Devices 156 | 157 | This library supports USB to serial converter chips with specific drivers 158 | * FTDI FT232R, FT232H, FT2232H, FT4232H, FT230X, FT231X, FT234XD 159 | * Prolific PL2303 160 | * Silabs CP2102, CP210* 161 | * Qinheng CH340, CH341A 162 | 163 | some other device specific drivers 164 | * GsmModem devices, e.g. for Unisoc based Fibocom GSM modems 165 | * Chrome OS CCD (Closed Case Debugging) 166 | 167 | and devices implementing the generic CDC/ACM protocol like 168 | * Qinheng CH9102 169 | * Microchip MCP2221 170 | * Arduino using ATmega32U4 171 | * Digispark using V-USB software USB 172 | * ... 173 | 174 | ## Help & Discussion 175 | 176 | For common problems, see the [FAQ](https://github.com/mik3y/usb-serial-for-android/wiki/FAQ) wiki page. 177 | 178 | Are you using the library? Add your project to 179 | [ProjectsUsingUsbSerialForAndroid](https://github.com/mik3y/usb-serial-for-android/wiki/Projects-Using-usb-serial-for-android). 180 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level gradle script. 2 | 3 | buildscript { 4 | repositories { 5 | mavenCentral() 6 | google() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:8.9.1' 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | mavenCentral() 16 | google() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | max_report_age: off 3 | require_ci_to_pass: no 4 | notify: 5 | wait_for_ci: no -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true 3 | android.defaults.buildfeatures.buildconfig=true 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mik3y/usb-serial-for-android/c608aadc59d2d09f5e34ab928de42c16bf69864f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Oct 13 21:20:09 CEST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin, switch paths to Windows format before running java 129 | if $cygwin ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem http://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk17 3 | install: 4 | - ./gradlew :usbSerialForAndroid:publishToMavenLocal 5 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'usbSerialForAndroid', 'usbSerialExamples' 2 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge/arduino_leonardo_bridge.ino: -------------------------------------------------------------------------------- 1 | /* 2 | bridge USB-serial to hardware-serial 3 | 4 | for Arduinos based on ATmega32u4 (Leonardo and compatible Pro Micro, Micro) 5 | hardware serial is configured with baud-rate, databits, stopbits, parity as send over USB 6 | 7 | see https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino 8 | -> CDC.cpp|HardwareSerial.cpp for serial implementation details 9 | 10 | this sketch is mainly for demonstration / test of CDC communication 11 | performance as real usb-serial bridge would be inacceptable as each byte is send in separate USB packet 12 | */ 13 | 14 | uint32_t baud = 9600; 15 | uint8_t databits = 8; 16 | uint8_t stopbits = 1; 17 | uint8_t parity = 0; 18 | 19 | void setup() { 20 | Serial.begin(baud); // USB 21 | Serial1.begin(baud, SERIAL_8N1); 22 | } 23 | 24 | void loop() { 25 | // show USB connected state 26 | if (Serial) TXLED1; 27 | else TXLED0; 28 | 29 | // configure hardware serial 30 | if (Serial.baud() != baud || 31 | Serial.numbits() != databits || 32 | Serial.stopbits() != stopbits || 33 | Serial.paritytype() != parity) { 34 | baud = Serial.baud(); 35 | databits = Serial.numbits(); 36 | stopbits = Serial.stopbits(); 37 | parity = Serial.paritytype(); 38 | uint8_t config = 0; // ucsrc register 39 | switch (databits) { 40 | case 5: break; 41 | case 6: config |= 2; break; 42 | case 7: config |= 4; break; 43 | case 8: config |= 6; break; 44 | default: config |= 6; 45 | } 46 | switch (stopbits) { 47 | case 2: config |= 8; 48 | // 1.5 stopbits not supported 49 | } 50 | switch (parity) { 51 | case 1: config |= 0x30; break; // odd 52 | case 2: config |= 0x20; break; // even 53 | // mark, space not supported 54 | } 55 | Serial1.end(); 56 | Serial1.begin(baud, config); 57 | } 58 | 59 | // bridge 60 | if (Serial.available() > 0) 61 | Serial1.write(Serial.read()); 62 | if (Serial1.available() > 0) 63 | Serial.write(Serial1.read()); 64 | } 65 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge_castrated_cdc/CDC.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* Copyright (c) 2011, Peter Barrett 4 | ** 5 | ** Permission to use, copy, modify, and/or distribute this software for 6 | ** any purpose with or without fee is hereby granted, provided that the 7 | ** above copyright notice and this permission notice appear in all copies. 8 | ** 9 | ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 12 | ** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES 13 | ** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 14 | ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 15 | ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 16 | ** SOFTWARE. 17 | */ 18 | 19 | #include "USBCore.h" // kai:added 20 | #include "USBAPI.h" 21 | #include 22 | #include 23 | 24 | #if defined(USBCON) 25 | 26 | typedef struct 27 | { 28 | u32 dwDTERate; 29 | u8 bCharFormat; 30 | u8 bParityType; 31 | u8 bDataBits; 32 | u8 lineState; 33 | } LineInfo; 34 | 35 | static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; 36 | static volatile int32_t breakValue = -1; 37 | 38 | static u8 wdtcsr_save; 39 | 40 | #define WEAK __attribute__ ((weak)) 41 | 42 | extern const CDCDescriptor _cdcInterface PROGMEM; 43 | const CDCDescriptor _cdcInterface = 44 | { 45 | D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1), 46 | 47 | // CDC communication interface 48 | D_INTERFACE(CDC_ACM_INTERFACE,3,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), // kai 49 | D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd) 50 | D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not) 51 | D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported 52 | D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0 53 | D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40), 54 | 55 | // CDC data interface 56 | //D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0), // kai:removed 57 | D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0), 58 | D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0) 59 | }; 60 | 61 | bool isLUFAbootloader() 62 | { 63 | return pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE; 64 | } 65 | 66 | int CDC_GetInterface(u8* interfaceNum) 67 | { 68 | interfaceNum[0] += 1; // kai 69 | return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface)); 70 | } 71 | 72 | bool CDC_Setup(USBSetup& setup) 73 | { 74 | u8 r = setup.bRequest; 75 | u8 requestType = setup.bmRequestType; 76 | 77 | if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) 78 | { 79 | if (CDC_GET_LINE_CODING == r) 80 | { 81 | USB_SendControl(0,(void*)&_usbLineInfo,7); 82 | return true; 83 | } 84 | } 85 | 86 | if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) 87 | { 88 | if (CDC_SEND_BREAK == r) 89 | { 90 | breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; 91 | } 92 | 93 | if (CDC_SET_LINE_CODING == r) 94 | { 95 | USB_RecvControl((void*)&_usbLineInfo,7); 96 | } 97 | 98 | if (CDC_SET_CONTROL_LINE_STATE == r) 99 | { 100 | _usbLineInfo.lineState = setup.wValueL; 101 | 102 | // auto-reset into the bootloader is triggered when the port, already 103 | // open at 1200 bps, is closed. this is the signal to start the watchdog 104 | // with a relatively long period so it can finish housekeeping tasks 105 | // like servicing endpoints before the sketch ends 106 | 107 | uint16_t magic_key_pos = MAGIC_KEY_POS; 108 | 109 | // If we don't use the new RAMEND directly, check manually if we have a newer bootloader. 110 | // This is used to keep compatible with the old leonardo bootloaders. 111 | // You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check. 112 | #if MAGIC_KEY_POS != (RAMEND-1) 113 | // For future boards save the key in the inproblematic RAMEND 114 | // Which is reserved for the main() return value (which will never return) 115 | if (isLUFAbootloader()) { 116 | // horray, we got a new bootloader! 117 | magic_key_pos = (RAMEND-1); 118 | } 119 | #endif 120 | 121 | // We check DTR state to determine if host port is open (bit 0 of lineState). 122 | if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) 123 | { 124 | #if MAGIC_KEY_POS != (RAMEND-1) 125 | // Backup ram value if its not a newer bootloader and it hasn't already been saved. 126 | // This should avoid memory corruption at least a bit, not fully 127 | if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) { 128 | *(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos; 129 | } 130 | #endif 131 | // Store boot key 132 | *(uint16_t *)magic_key_pos = MAGIC_KEY; 133 | // Save the watchdog state in case the reset is aborted. 134 | wdtcsr_save = WDTCSR; 135 | wdt_enable(WDTO_120MS); 136 | } 137 | else if (*(uint16_t *)magic_key_pos == MAGIC_KEY) 138 | { 139 | // Most OSs do some intermediate steps when configuring ports and DTR can 140 | // twiggle more than once before stabilizing. 141 | // To avoid spurious resets we set the watchdog to 120ms and eventually 142 | // cancel if DTR goes back high. 143 | // Cancellation is only done if an auto-reset was started, which is 144 | // indicated by the magic key having been set. 145 | 146 | wdt_reset(); 147 | // Restore the watchdog state in case the sketch was using it. 148 | WDTCSR |= (1<= 0) { 185 | return 1 + USB_Available(CDC_RX); 186 | } 187 | return USB_Available(CDC_RX); 188 | } 189 | 190 | int Serial_::peek(void) 191 | { 192 | if (peek_buffer < 0) 193 | peek_buffer = USB_Recv(CDC_RX); 194 | return peek_buffer; 195 | } 196 | 197 | int Serial_::read(void) 198 | { 199 | if (peek_buffer >= 0) { 200 | int c = peek_buffer; 201 | peek_buffer = -1; 202 | return c; 203 | } 204 | return USB_Recv(CDC_RX); 205 | } 206 | 207 | int Serial_::availableForWrite(void) 208 | { 209 | return USB_SendSpace(CDC_TX); 210 | } 211 | 212 | void Serial_::flush(void) 213 | { 214 | USB_Flush(CDC_TX); 215 | } 216 | 217 | size_t Serial_::write(uint8_t c) 218 | { 219 | return write(&c, 1); 220 | } 221 | 222 | size_t Serial_::write(const uint8_t *buffer, size_t size) 223 | { 224 | /* only try to send bytes if the high-level CDC connection itself 225 | is open (not just the pipe) - the OS should set lineState when the port 226 | is opened and clear lineState when the port is closed. 227 | bytes sent before the user opens the connection or after 228 | the connection is closed are lost - just like with a UART. */ 229 | 230 | // TODO - ZE - check behavior on different OSes and test what happens if an 231 | // open connection isn't broken cleanly (cable is yanked out, host dies 232 | // or locks up, or host virtual serial port hangs) 233 | if (_usbLineInfo.lineState > 0) { 234 | int r = USB_Send(CDC_TX,buffer,size); 235 | if (r > 0) { 236 | return r; 237 | } else { 238 | setWriteError(); 239 | return 0; 240 | } 241 | } 242 | setWriteError(); 243 | return 0; 244 | } 245 | 246 | // This operator is a convenient way for a sketch to check whether the 247 | // port has actually been configured and opened by the host (as opposed 248 | // to just being connected to the host). It can be used, for example, in 249 | // setup() before printing to ensure that an application on the host is 250 | // actually ready to receive and display the data. 251 | // We add a short delay before returning to fix a bug observed by Federico 252 | // where the port is configured (lineState != 0) but not quite opened. 253 | Serial_::operator bool() { 254 | bool result = false; 255 | if (_usbLineInfo.lineState > 0) 256 | result = true; 257 | delay(10); 258 | return result; 259 | } 260 | 261 | unsigned long Serial_::baud() { 262 | // Disable interrupts while reading a multi-byte value 263 | uint32_t baudrate; 264 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 265 | baudrate = _usbLineInfo.dwDTERate; 266 | } 267 | return baudrate; 268 | } 269 | 270 | uint8_t Serial_::stopbits() { 271 | return _usbLineInfo.bCharFormat; 272 | } 273 | 274 | uint8_t Serial_::paritytype() { 275 | return _usbLineInfo.bParityType; 276 | } 277 | 278 | uint8_t Serial_::numbits() { 279 | return _usbLineInfo.bDataBits; 280 | } 281 | 282 | bool Serial_::dtr() { 283 | return _usbLineInfo.lineState & 0x1; 284 | } 285 | 286 | bool Serial_::rts() { 287 | return _usbLineInfo.lineState & 0x2; 288 | } 289 | 290 | int32_t Serial_::readBreak() { 291 | int32_t ret; 292 | // Disable IRQs while reading and clearing breakValue to make 293 | // sure we don't overwrite a value just set by the ISR. 294 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 295 | ret = breakValue; 296 | breakValue = -1; 297 | } 298 | return ret; 299 | } 300 | 301 | Serial_ Serial; 302 | 303 | #endif /* if defined(USBCON) */ 304 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge_castrated_cdc/README.md: -------------------------------------------------------------------------------- 1 | ## castrated CDC test (single interface with 3 endpoints) 2 | 3 | As mentioned [here](https://arduino.stackexchange.com/a/31695/62145), Arduino functions can be _overwritten_ by copying complete files into the own project. 4 | 5 | This is used to create a castrated CDC device with a single interface containing 3 endpoints. 6 | 7 | The modifications have been done against Arduino 1.8.10, for changes see comments containing `kai`. 8 | 9 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge_castrated_cdc/USBCore.h: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2010, Peter Barrett 3 | /* 4 | ** Permission to use, copy, modify, and/or distribute this software for 5 | ** any purpose with or without fee is hereby granted, provided that the 6 | ** above copyright notice and this permission notice appear in all copies. 7 | ** 8 | ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 9 | ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 11 | ** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES 12 | ** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 13 | ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 14 | ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 15 | ** SOFTWARE. 16 | */ 17 | 18 | #ifndef __USBCORE_H__ 19 | #define __USBCORE_H__ 20 | 21 | #include "USBAPI.h" 22 | 23 | // Standard requests 24 | #define GET_STATUS 0 25 | #define CLEAR_FEATURE 1 26 | #define SET_FEATURE 3 27 | #define SET_ADDRESS 5 28 | #define GET_DESCRIPTOR 6 29 | #define SET_DESCRIPTOR 7 30 | #define GET_CONFIGURATION 8 31 | #define SET_CONFIGURATION 9 32 | #define GET_INTERFACE 10 33 | #define SET_INTERFACE 11 34 | 35 | 36 | // bmRequestType 37 | #define REQUEST_HOSTTODEVICE 0x00 38 | #define REQUEST_DEVICETOHOST 0x80 39 | #define REQUEST_DIRECTION 0x80 40 | 41 | #define REQUEST_STANDARD 0x00 42 | #define REQUEST_CLASS 0x20 43 | #define REQUEST_VENDOR 0x40 44 | #define REQUEST_TYPE 0x60 45 | 46 | #define REQUEST_DEVICE 0x00 47 | #define REQUEST_INTERFACE 0x01 48 | #define REQUEST_ENDPOINT 0x02 49 | #define REQUEST_OTHER 0x03 50 | #define REQUEST_RECIPIENT 0x03 51 | 52 | #define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_CLASS | REQUEST_INTERFACE) 53 | #define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE) 54 | #define REQUEST_DEVICETOHOST_STANDARD_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE) 55 | 56 | // Class requests 57 | 58 | #define CDC_SET_LINE_CODING 0x20 59 | #define CDC_GET_LINE_CODING 0x21 60 | #define CDC_SET_CONTROL_LINE_STATE 0x22 61 | #define CDC_SEND_BREAK 0x23 62 | 63 | #define MSC_RESET 0xFF 64 | #define MSC_GET_MAX_LUN 0xFE 65 | 66 | // Descriptors 67 | 68 | #define USB_DEVICE_DESC_SIZE 18 69 | #define USB_CONFIGUARTION_DESC_SIZE 9 70 | #define USB_INTERFACE_DESC_SIZE 9 71 | #define USB_ENDPOINT_DESC_SIZE 7 72 | 73 | #define USB_DEVICE_DESCRIPTOR_TYPE 1 74 | #define USB_CONFIGURATION_DESCRIPTOR_TYPE 2 75 | #define USB_STRING_DESCRIPTOR_TYPE 3 76 | #define USB_INTERFACE_DESCRIPTOR_TYPE 4 77 | #define USB_ENDPOINT_DESCRIPTOR_TYPE 5 78 | 79 | // usb_20.pdf Table 9.6 Standard Feature Selectors 80 | #define DEVICE_REMOTE_WAKEUP 1 81 | #define ENDPOINT_HALT 2 82 | #define TEST_MODE 3 83 | 84 | // usb_20.pdf Figure 9-4. Information Returned by a GetStatus() Request to a Device 85 | #define FEATURE_SELFPOWERED_ENABLED (1 << 0) 86 | #define FEATURE_REMOTE_WAKEUP_ENABLED (1 << 1) 87 | 88 | #define USB_DEVICE_CLASS_COMMUNICATIONS 0x02 89 | #define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03 90 | #define USB_DEVICE_CLASS_STORAGE 0x08 91 | #define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF 92 | 93 | #define USB_CONFIG_POWERED_MASK 0x40 94 | #define USB_CONFIG_BUS_POWERED 0x80 95 | #define USB_CONFIG_SELF_POWERED 0xC0 96 | #define USB_CONFIG_REMOTE_WAKEUP 0x20 97 | 98 | // bMaxPower in Configuration Descriptor 99 | #define USB_CONFIG_POWER_MA(mA) ((mA)/2) 100 | 101 | // bEndpointAddress in Endpoint Descriptor 102 | #define USB_ENDPOINT_DIRECTION_MASK 0x80 103 | #define USB_ENDPOINT_OUT(addr) (lowByte((addr) | 0x00)) 104 | #define USB_ENDPOINT_IN(addr) (lowByte((addr) | 0x80)) 105 | 106 | #define USB_ENDPOINT_TYPE_MASK 0x03 107 | #define USB_ENDPOINT_TYPE_CONTROL 0x00 108 | #define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 109 | #define USB_ENDPOINT_TYPE_BULK 0x02 110 | #define USB_ENDPOINT_TYPE_INTERRUPT 0x03 111 | 112 | #define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF) 113 | 114 | #define CDC_V1_10 0x0110 115 | #define CDC_COMMUNICATION_INTERFACE_CLASS 0x02 116 | 117 | #define CDC_CALL_MANAGEMENT 0x01 118 | #define CDC_ABSTRACT_CONTROL_MODEL 0x02 119 | #define CDC_HEADER 0x00 120 | #define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02 121 | #define CDC_UNION 0x06 122 | #define CDC_CS_INTERFACE 0x24 123 | #define CDC_CS_ENDPOINT 0x25 124 | #define CDC_DATA_INTERFACE_CLASS 0x0A 125 | 126 | #define MSC_SUBCLASS_SCSI 0x06 127 | #define MSC_PROTOCOL_BULK_ONLY 0x50 128 | 129 | #ifndef USB_VERSION 130 | #define USB_VERSION 0x200 131 | #endif 132 | 133 | // Device 134 | typedef struct { 135 | u8 len; // 18 136 | u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE 137 | u16 usbVersion; // 0x200 or 0x210 138 | u8 deviceClass; 139 | u8 deviceSubClass; 140 | u8 deviceProtocol; 141 | u8 packetSize0; // Packet 0 142 | u16 idVendor; 143 | u16 idProduct; 144 | u16 deviceVersion; // 0x100 145 | u8 iManufacturer; 146 | u8 iProduct; 147 | u8 iSerialNumber; 148 | u8 bNumConfigurations; 149 | } DeviceDescriptor; 150 | 151 | // Config 152 | typedef struct { 153 | u8 len; // 9 154 | u8 dtype; // 2 155 | u16 clen; // total length 156 | u8 numInterfaces; 157 | u8 config; 158 | u8 iconfig; 159 | u8 attributes; 160 | u8 maxPower; 161 | } ConfigDescriptor; 162 | 163 | // String 164 | 165 | // Interface 166 | typedef struct 167 | { 168 | u8 len; // 9 169 | u8 dtype; // 4 170 | u8 number; 171 | u8 alternate; 172 | u8 numEndpoints; 173 | u8 interfaceClass; 174 | u8 interfaceSubClass; 175 | u8 protocol; 176 | u8 iInterface; 177 | } InterfaceDescriptor; 178 | 179 | // Endpoint 180 | typedef struct 181 | { 182 | u8 len; // 7 183 | u8 dtype; // 5 184 | u8 addr; 185 | u8 attr; 186 | u16 packetSize; 187 | u8 interval; 188 | } EndpointDescriptor; 189 | 190 | // Interface Association Descriptor 191 | // Used to bind 2 interfaces together in CDC compostite device 192 | typedef struct 193 | { 194 | u8 len; // 8 195 | u8 dtype; // 11 196 | u8 firstInterface; 197 | u8 interfaceCount; 198 | u8 functionClass; 199 | u8 funtionSubClass; 200 | u8 functionProtocol; 201 | u8 iInterface; 202 | } IADDescriptor; 203 | 204 | // CDC CS interface descriptor 205 | typedef struct 206 | { 207 | u8 len; // 5 208 | u8 dtype; // 0x24 209 | u8 subtype; 210 | u8 d0; 211 | u8 d1; 212 | } CDCCSInterfaceDescriptor; 213 | 214 | typedef struct 215 | { 216 | u8 len; // 4 217 | u8 dtype; // 0x24 218 | u8 subtype; 219 | u8 d0; 220 | } CDCCSInterfaceDescriptor4; 221 | 222 | typedef struct 223 | { 224 | u8 len; 225 | u8 dtype; // 0x24 226 | u8 subtype; // 1 227 | u8 bmCapabilities; 228 | u8 bDataInterface; 229 | } CMFunctionalDescriptor; 230 | 231 | typedef struct 232 | { 233 | u8 len; 234 | u8 dtype; // 0x24 235 | u8 subtype; // 1 236 | u8 bmCapabilities; 237 | } ACMFunctionalDescriptor; 238 | 239 | typedef struct 240 | { 241 | // IAD 242 | IADDescriptor iad; // Only needed on compound device 243 | 244 | // Control 245 | InterfaceDescriptor cif; // 246 | CDCCSInterfaceDescriptor header; 247 | CMFunctionalDescriptor callManagement; // Call Management 248 | ACMFunctionalDescriptor controlManagement; // ACM 249 | CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION 250 | EndpointDescriptor cifin; 251 | 252 | // Data 253 | //InterfaceDescriptor dif; // kai:removed 254 | EndpointDescriptor in; 255 | EndpointDescriptor out; 256 | } CDCDescriptor; 257 | 258 | typedef struct 259 | { 260 | InterfaceDescriptor msc; 261 | EndpointDescriptor in; 262 | EndpointDescriptor out; 263 | } MSCDescriptor; 264 | 265 | 266 | #define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \ 267 | { 18, 1, USB_VERSION, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs } 268 | 269 | #define D_CONFIG(_totalLength,_interfaces) \ 270 | { 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, USB_CONFIG_POWER_MA(500) } 271 | 272 | #define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \ 273 | { 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 } 274 | 275 | #define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \ 276 | { 7, 5, _addr,_attr,_packetSize, _interval } 277 | 278 | #define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \ 279 | { 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 } 280 | 281 | #define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } 282 | #define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 } 283 | 284 | // Bootloader related fields 285 | // Old Caterina bootloader places the MAGIC key into unsafe RAM locations (it can be rewritten 286 | // by the running sketch before to actual reboot). 287 | // Newer bootloaders, recognizable by the LUFA "signature" at the end of the flash, can handle both 288 | // the usafe and the safe location. 289 | #ifndef MAGIC_KEY 290 | #define MAGIC_KEY 0x7777 291 | #endif 292 | 293 | #ifndef MAGIC_KEY_POS 294 | #define MAGIC_KEY_POS 0x0800 295 | #endif 296 | 297 | #ifndef NEW_LUFA_SIGNATURE 298 | #define NEW_LUFA_SIGNATURE 0xDCFB 299 | #endif 300 | 301 | #endif 302 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge_castrated_cdc/arduino_leonardo_bridge_castrated_cdc.ino: -------------------------------------------------------------------------------- 1 | /* 2 | bridge USB-serial to hardware-serial 3 | 4 | for Arduinos based on ATmega32u4 (Leonardo and compatible Pro Micro, Micro) 5 | hardware serial is configured with baud-rate, databits, stopbits, parity as send over USB 6 | 7 | see https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino 8 | -> CDC.cpp|HardwareSerial.cpp for serial implementation details 9 | 10 | this sketch is mainly for demonstration / test of CDC communication 11 | performance as real usb-serial bridge would be inacceptable as each byte is send in separate USB packet 12 | */ 13 | 14 | uint32_t baud = 9600; 15 | uint8_t databits = 8; 16 | uint8_t stopbits = 1; 17 | uint8_t parity = 0; 18 | 19 | void setup() { 20 | Serial.begin(baud); // USB 21 | Serial1.begin(baud, SERIAL_8N1); 22 | } 23 | 24 | void loop() { 25 | // show USB connected state 26 | if (Serial) TXLED1; 27 | else TXLED0; 28 | 29 | // configure hardware serial 30 | if (Serial.baud() != baud || 31 | Serial.numbits() != databits || 32 | Serial.stopbits() != stopbits || 33 | Serial.paritytype() != parity) { 34 | baud = Serial.baud(); 35 | databits = Serial.numbits(); 36 | stopbits = Serial.stopbits(); 37 | parity = Serial.paritytype(); 38 | uint8_t config = 0; // ucsrc register 39 | switch (databits) { 40 | case 5: break; 41 | case 6: config |= 2; break; 42 | case 7: config |= 4; break; 43 | case 8: config |= 6; break; 44 | default: config |= 6; 45 | } 46 | switch (stopbits) { 47 | case 2: config |= 8; 48 | // 1.5 stopbits not supported 49 | } 50 | switch (parity) { 51 | case 1: config |= 0x30; break; // odd 52 | case 2: config |= 0x20; break; // even 53 | // mark, space not supported 54 | } 55 | Serial1.end(); 56 | Serial1.begin(baud, config); 57 | } 58 | 59 | // bridge 60 | if (Serial.available() > 0) 61 | Serial1.write(Serial.read()); 62 | if (Serial1.available() > 0) 63 | Serial.write(Serial1.read()); 64 | } 65 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge_multi_cdc/CDC.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* Copyright (c) 2011, Peter Barrett 4 | ** 5 | ** Permission to use, copy, modify, and/or distribute this software for 6 | ** any purpose with or without fee is hereby granted, provided that the 7 | ** above copyright notice and this permission notice appear in all copies. 8 | ** 9 | ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 12 | ** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES 13 | ** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 14 | ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 15 | ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 16 | ** SOFTWARE. 17 | */ 18 | 19 | #include "USBCore.h" // kai:added 20 | #include "USBAPI.h" 21 | #include "USBDesc.h" // kai:added 22 | #include 23 | #include 24 | 25 | #if defined(USBCON) 26 | 27 | typedef struct 28 | { 29 | u32 dwDTERate; 30 | u8 bCharFormat; 31 | u8 bParityType; 32 | u8 bDataBits; 33 | u8 lineState; 34 | } LineInfo; 35 | 36 | static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; 37 | static volatile int32_t breakValue = -1; 38 | 39 | static u8 wdtcsr_save; 40 | 41 | #define WEAK __attribute__ ((weak)) 42 | 43 | extern const CDCDescriptor _cdcInterface PROGMEM; 44 | const CDCDescriptor _cdcInterface = 45 | { 46 | D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1), 47 | 48 | // CDC communication interface 49 | D_INTERFACE(CDC_ACM_INTERFACE1,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), 50 | D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd) 51 | D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not) 52 | D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported 53 | D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE1,CDC_DATA_INTERFACE1), // Communication interface is master, data interface is slave 0 54 | D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM1),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40), 55 | 56 | // CDC data interface 57 | D_INTERFACE(CDC_DATA_INTERFACE1,2,CDC_DATA_INTERFACE_CLASS,0,0), 58 | D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT1),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0), 59 | D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN1 ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0) 60 | 61 | , // kai: added 62 | D_IAD(2,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1), 63 | 64 | // CDC communication interface 65 | D_INTERFACE(CDC_ACM_INTERFACE2,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), 66 | D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd) 67 | D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not) 68 | D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported 69 | D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE2,CDC_DATA_INTERFACE2), // Communication interface is master, data interface is slave 0 70 | D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM2),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40), 71 | 72 | // CDC data interface 73 | D_INTERFACE(CDC_DATA_INTERFACE2,2,CDC_DATA_INTERFACE_CLASS,0,0), 74 | D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT2),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0), 75 | D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN2),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0) 76 | }; 77 | 78 | bool isLUFAbootloader() 79 | { 80 | return pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE; 81 | } 82 | 83 | int CDC_GetInterface(u8* interfaceNum) 84 | { 85 | interfaceNum[0] += 4; // kai 86 | return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface)); 87 | } 88 | 89 | bool CDC_Setup(USBSetup& setup) 90 | { 91 | u8 r = setup.bRequest; 92 | u8 requestType = setup.bmRequestType; 93 | 94 | if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) 95 | { 96 | if (CDC_GET_LINE_CODING == r) 97 | { 98 | USB_SendControl(0,(void*)&_usbLineInfo,7); 99 | return true; 100 | } 101 | } 102 | 103 | if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) 104 | { 105 | if (CDC_SEND_BREAK == r) 106 | { 107 | breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; 108 | } 109 | 110 | if (CDC_SET_LINE_CODING == r) 111 | { 112 | USB_RecvControl((void*)&_usbLineInfo,7); 113 | } 114 | 115 | if (CDC_SET_CONTROL_LINE_STATE == r) 116 | { 117 | _usbLineInfo.lineState = setup.wValueL; 118 | 119 | // auto-reset into the bootloader is triggered when the port, already 120 | // open at 1200 bps, is closed. this is the signal to start the watchdog 121 | // with a relatively long period so it can finish housekeeping tasks 122 | // like servicing endpoints before the sketch ends 123 | 124 | uint16_t magic_key_pos = MAGIC_KEY_POS; 125 | 126 | // If we don't use the new RAMEND directly, check manually if we have a newer bootloader. 127 | // This is used to keep compatible with the old leonardo bootloaders. 128 | // You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check. 129 | #if MAGIC_KEY_POS != (RAMEND-1) 130 | // For future boards save the key in the inproblematic RAMEND 131 | // Which is reserved for the main() return value (which will never return) 132 | if (isLUFAbootloader()) { 133 | // horray, we got a new bootloader! 134 | magic_key_pos = (RAMEND-1); 135 | } 136 | #endif 137 | 138 | // We check DTR state to determine if host port is open (bit 0 of lineState). 139 | if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) 140 | { 141 | #if MAGIC_KEY_POS != (RAMEND-1) 142 | // Backup ram value if its not a newer bootloader and it hasn't already been saved. 143 | // This should avoid memory corruption at least a bit, not fully 144 | if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) { 145 | *(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos; 146 | } 147 | #endif 148 | // Store boot key 149 | *(uint16_t *)magic_key_pos = MAGIC_KEY; 150 | // Save the watchdog state in case the reset is aborted. 151 | wdtcsr_save = WDTCSR; 152 | wdt_enable(WDTO_120MS); 153 | } 154 | else if (*(uint16_t *)magic_key_pos == MAGIC_KEY) 155 | { 156 | // Most OSs do some intermediate steps when configuring ports and DTR can 157 | // twiggle more than once before stabilizing. 158 | // To avoid spurious resets we set the watchdog to 120ms and eventually 159 | // cancel if DTR goes back high. 160 | // Cancellation is only done if an auto-reset was started, which is 161 | // indicated by the magic key having been set. 162 | 163 | wdt_reset(); 164 | // Restore the watchdog state in case the sketch was using it. 165 | WDTCSR |= (1<= 0) { 202 | return 1 + USB_Available(CDC_RX); 203 | } 204 | return USB_Available(CDC_RX); 205 | } 206 | 207 | int Serial_::peek(void) 208 | { 209 | if (peek_buffer < 0) 210 | peek_buffer = USB_Recv(CDC_RX); 211 | return peek_buffer; 212 | } 213 | 214 | int Serial_::read(void) 215 | { 216 | if (peek_buffer >= 0) { 217 | int c = peek_buffer; 218 | peek_buffer = -1; 219 | return c; 220 | } 221 | return USB_Recv(CDC_RX); 222 | } 223 | 224 | int Serial_::availableForWrite(void) 225 | { 226 | return USB_SendSpace(CDC_TX); 227 | } 228 | 229 | void Serial_::flush(void) 230 | { 231 | USB_Flush(CDC_TX); 232 | } 233 | 234 | size_t Serial_::write(uint8_t c) 235 | { 236 | return write(&c, 1); 237 | } 238 | 239 | size_t Serial_::write(const uint8_t *buffer, size_t size) 240 | { 241 | /* only try to send bytes if the high-level CDC connection itself 242 | is open (not just the pipe) - the OS should set lineState when the port 243 | is opened and clear lineState when the port is closed. 244 | bytes sent before the user opens the connection or after 245 | the connection is closed are lost - just like with a UART. */ 246 | 247 | // TODO - ZE - check behavior on different OSes and test what happens if an 248 | // open connection isn't broken cleanly (cable is yanked out, host dies 249 | // or locks up, or host virtual serial port hangs) 250 | if (_usbLineInfo.lineState > 0) { 251 | int r = USB_Send(CDC_TX,buffer,size); 252 | if (r > 0) { 253 | return r; 254 | } else { 255 | setWriteError(); 256 | return 0; 257 | } 258 | } 259 | setWriteError(); 260 | return 0; 261 | } 262 | 263 | // This operator is a convenient way for a sketch to check whether the 264 | // port has actually been configured and opened by the host (as opposed 265 | // to just being connected to the host). It can be used, for example, in 266 | // setup() before printing to ensure that an application on the host is 267 | // actually ready to receive and display the data. 268 | // We add a short delay before returning to fix a bug observed by Federico 269 | // where the port is configured (lineState != 0) but not quite opened. 270 | Serial_::operator bool() { 271 | bool result = false; 272 | if (_usbLineInfo.lineState > 0) 273 | result = true; 274 | delay(10); 275 | return result; 276 | } 277 | 278 | unsigned long Serial_::baud() { 279 | // Disable interrupts while reading a multi-byte value 280 | uint32_t baudrate; 281 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 282 | baudrate = _usbLineInfo.dwDTERate; 283 | } 284 | return baudrate; 285 | } 286 | 287 | uint8_t Serial_::stopbits() { 288 | return _usbLineInfo.bCharFormat; 289 | } 290 | 291 | uint8_t Serial_::paritytype() { 292 | return _usbLineInfo.bParityType; 293 | } 294 | 295 | uint8_t Serial_::numbits() { 296 | return _usbLineInfo.bDataBits; 297 | } 298 | 299 | bool Serial_::dtr() { 300 | return _usbLineInfo.lineState & 0x1; 301 | } 302 | 303 | bool Serial_::rts() { 304 | return _usbLineInfo.lineState & 0x2; 305 | } 306 | 307 | int32_t Serial_::readBreak() { 308 | int32_t ret; 309 | // Disable IRQs while reading and clearing breakValue to make 310 | // sure we don't overwrite a value just set by the ISR. 311 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 312 | ret = breakValue; 313 | breakValue = -1; 314 | } 315 | return ret; 316 | } 317 | 318 | Serial_ Serial; 319 | 320 | #endif /* if defined(USBCON) */ 321 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge_multi_cdc/README.md: -------------------------------------------------------------------------------- 1 | ## multiple CDC interface test 2 | 3 | As mentioned [here](https://arduino.stackexchange.com/a/31695/62145), Arduino functions can be _overwritten_ by copying complete files into the own project. 4 | 5 | This is used to create a device with 2 CDC interfaces. For simplicity only one of both is functional (configurable in USBDesc.h) 6 | 7 | The modifications have been done against Arduino 1.8.10, for changes see comments containing `kai`. 8 | 9 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge_multi_cdc/USBCore.h: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2010, Peter Barrett 3 | /* 4 | ** Permission to use, copy, modify, and/or distribute this software for 5 | ** any purpose with or without fee is hereby granted, provided that the 6 | ** above copyright notice and this permission notice appear in all copies. 7 | ** 8 | ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 9 | ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 11 | ** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES 12 | ** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 13 | ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 14 | ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 15 | ** SOFTWARE. 16 | */ 17 | 18 | #ifndef __USBCORE_H__ 19 | #define __USBCORE_H__ 20 | 21 | #include "USBAPI.h" 22 | 23 | // Standard requests 24 | #define GET_STATUS 0 25 | #define CLEAR_FEATURE 1 26 | #define SET_FEATURE 3 27 | #define SET_ADDRESS 5 28 | #define GET_DESCRIPTOR 6 29 | #define SET_DESCRIPTOR 7 30 | #define GET_CONFIGURATION 8 31 | #define SET_CONFIGURATION 9 32 | #define GET_INTERFACE 10 33 | #define SET_INTERFACE 11 34 | 35 | 36 | // bmRequestType 37 | #define REQUEST_HOSTTODEVICE 0x00 38 | #define REQUEST_DEVICETOHOST 0x80 39 | #define REQUEST_DIRECTION 0x80 40 | 41 | #define REQUEST_STANDARD 0x00 42 | #define REQUEST_CLASS 0x20 43 | #define REQUEST_VENDOR 0x40 44 | #define REQUEST_TYPE 0x60 45 | 46 | #define REQUEST_DEVICE 0x00 47 | #define REQUEST_INTERFACE 0x01 48 | #define REQUEST_ENDPOINT 0x02 49 | #define REQUEST_OTHER 0x03 50 | #define REQUEST_RECIPIENT 0x03 51 | 52 | #define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_CLASS | REQUEST_INTERFACE) 53 | #define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE) 54 | #define REQUEST_DEVICETOHOST_STANDARD_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE) 55 | 56 | // Class requests 57 | 58 | #define CDC_SET_LINE_CODING 0x20 59 | #define CDC_GET_LINE_CODING 0x21 60 | #define CDC_SET_CONTROL_LINE_STATE 0x22 61 | #define CDC_SEND_BREAK 0x23 62 | 63 | #define MSC_RESET 0xFF 64 | #define MSC_GET_MAX_LUN 0xFE 65 | 66 | // Descriptors 67 | 68 | #define USB_DEVICE_DESC_SIZE 18 69 | #define USB_CONFIGUARTION_DESC_SIZE 9 70 | #define USB_INTERFACE_DESC_SIZE 9 71 | #define USB_ENDPOINT_DESC_SIZE 7 72 | 73 | #define USB_DEVICE_DESCRIPTOR_TYPE 1 74 | #define USB_CONFIGURATION_DESCRIPTOR_TYPE 2 75 | #define USB_STRING_DESCRIPTOR_TYPE 3 76 | #define USB_INTERFACE_DESCRIPTOR_TYPE 4 77 | #define USB_ENDPOINT_DESCRIPTOR_TYPE 5 78 | 79 | // usb_20.pdf Table 9.6 Standard Feature Selectors 80 | #define DEVICE_REMOTE_WAKEUP 1 81 | #define ENDPOINT_HALT 2 82 | #define TEST_MODE 3 83 | 84 | // usb_20.pdf Figure 9-4. Information Returned by a GetStatus() Request to a Device 85 | #define FEATURE_SELFPOWERED_ENABLED (1 << 0) 86 | #define FEATURE_REMOTE_WAKEUP_ENABLED (1 << 1) 87 | 88 | #define USB_DEVICE_CLASS_COMMUNICATIONS 0x02 89 | #define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03 90 | #define USB_DEVICE_CLASS_STORAGE 0x08 91 | #define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF 92 | 93 | #define USB_CONFIG_POWERED_MASK 0x40 94 | #define USB_CONFIG_BUS_POWERED 0x80 95 | #define USB_CONFIG_SELF_POWERED 0xC0 96 | #define USB_CONFIG_REMOTE_WAKEUP 0x20 97 | 98 | // bMaxPower in Configuration Descriptor 99 | #define USB_CONFIG_POWER_MA(mA) ((mA)/2) 100 | 101 | // bEndpointAddress in Endpoint Descriptor 102 | #define USB_ENDPOINT_DIRECTION_MASK 0x80 103 | #define USB_ENDPOINT_OUT(addr) (lowByte((addr) | 0x00)) 104 | #define USB_ENDPOINT_IN(addr) (lowByte((addr) | 0x80)) 105 | 106 | #define USB_ENDPOINT_TYPE_MASK 0x03 107 | #define USB_ENDPOINT_TYPE_CONTROL 0x00 108 | #define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 109 | #define USB_ENDPOINT_TYPE_BULK 0x02 110 | #define USB_ENDPOINT_TYPE_INTERRUPT 0x03 111 | 112 | #define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF) 113 | 114 | #define CDC_V1_10 0x0110 115 | #define CDC_COMMUNICATION_INTERFACE_CLASS 0x02 116 | 117 | #define CDC_CALL_MANAGEMENT 0x01 118 | #define CDC_ABSTRACT_CONTROL_MODEL 0x02 119 | #define CDC_HEADER 0x00 120 | #define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02 121 | #define CDC_UNION 0x06 122 | #define CDC_CS_INTERFACE 0x24 123 | #define CDC_CS_ENDPOINT 0x25 124 | #define CDC_DATA_INTERFACE_CLASS 0x0A 125 | 126 | #define MSC_SUBCLASS_SCSI 0x06 127 | #define MSC_PROTOCOL_BULK_ONLY 0x50 128 | 129 | #ifndef USB_VERSION 130 | #define USB_VERSION 0x200 131 | #endif 132 | 133 | // Device 134 | typedef struct { 135 | u8 len; // 18 136 | u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE 137 | u16 usbVersion; // 0x200 or 0x210 138 | u8 deviceClass; 139 | u8 deviceSubClass; 140 | u8 deviceProtocol; 141 | u8 packetSize0; // Packet 0 142 | u16 idVendor; 143 | u16 idProduct; 144 | u16 deviceVersion; // 0x100 145 | u8 iManufacturer; 146 | u8 iProduct; 147 | u8 iSerialNumber; 148 | u8 bNumConfigurations; 149 | } DeviceDescriptor; 150 | 151 | // Config 152 | typedef struct { 153 | u8 len; // 9 154 | u8 dtype; // 2 155 | u16 clen; // total length 156 | u8 numInterfaces; 157 | u8 config; 158 | u8 iconfig; 159 | u8 attributes; 160 | u8 maxPower; 161 | } ConfigDescriptor; 162 | 163 | // String 164 | 165 | // Interface 166 | typedef struct 167 | { 168 | u8 len; // 9 169 | u8 dtype; // 4 170 | u8 number; 171 | u8 alternate; 172 | u8 numEndpoints; 173 | u8 interfaceClass; 174 | u8 interfaceSubClass; 175 | u8 protocol; 176 | u8 iInterface; 177 | } InterfaceDescriptor; 178 | 179 | // Endpoint 180 | typedef struct 181 | { 182 | u8 len; // 7 183 | u8 dtype; // 5 184 | u8 addr; 185 | u8 attr; 186 | u16 packetSize; 187 | u8 interval; 188 | } EndpointDescriptor; 189 | 190 | // Interface Association Descriptor 191 | // Used to bind 2 interfaces together in CDC compostite device 192 | typedef struct 193 | { 194 | u8 len; // 8 195 | u8 dtype; // 11 196 | u8 firstInterface; 197 | u8 interfaceCount; 198 | u8 functionClass; 199 | u8 funtionSubClass; 200 | u8 functionProtocol; 201 | u8 iInterface; 202 | } IADDescriptor; 203 | 204 | // CDC CS interface descriptor 205 | typedef struct 206 | { 207 | u8 len; // 5 208 | u8 dtype; // 0x24 209 | u8 subtype; 210 | u8 d0; 211 | u8 d1; 212 | } CDCCSInterfaceDescriptor; 213 | 214 | typedef struct 215 | { 216 | u8 len; // 4 217 | u8 dtype; // 0x24 218 | u8 subtype; 219 | u8 d0; 220 | } CDCCSInterfaceDescriptor4; 221 | 222 | typedef struct 223 | { 224 | u8 len; 225 | u8 dtype; // 0x24 226 | u8 subtype; // 1 227 | u8 bmCapabilities; 228 | u8 bDataInterface; 229 | } CMFunctionalDescriptor; 230 | 231 | typedef struct 232 | { 233 | u8 len; 234 | u8 dtype; // 0x24 235 | u8 subtype; // 1 236 | u8 bmCapabilities; 237 | } ACMFunctionalDescriptor; 238 | 239 | typedef struct 240 | { 241 | // IAD 242 | IADDescriptor iad; // Only needed on compound device 243 | 244 | // Control 245 | InterfaceDescriptor cif; // 246 | CDCCSInterfaceDescriptor header; 247 | CMFunctionalDescriptor callManagement; // Call Management 248 | ACMFunctionalDescriptor controlManagement; // ACM 249 | CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION 250 | EndpointDescriptor cifin; 251 | 252 | // Data 253 | InterfaceDescriptor dif; 254 | EndpointDescriptor in; 255 | EndpointDescriptor out; 256 | 257 | // kai:added 258 | IADDescriptor iad2; // Only needed on compound device 259 | 260 | // Control 261 | InterfaceDescriptor cif2; // 262 | CDCCSInterfaceDescriptor header2; 263 | CMFunctionalDescriptor callManagement2; // Call Management 264 | ACMFunctionalDescriptor controlManagement2; // ACM 265 | CDCCSInterfaceDescriptor functionalDescriptor2; // CDC_UNION 266 | EndpointDescriptor cifin2; 267 | 268 | // Data 269 | InterfaceDescriptor dif2; 270 | EndpointDescriptor in2; 271 | EndpointDescriptor out2; 272 | } CDCDescriptor; 273 | 274 | typedef struct 275 | { 276 | InterfaceDescriptor msc; 277 | EndpointDescriptor in; 278 | EndpointDescriptor out; 279 | } MSCDescriptor; 280 | 281 | 282 | #define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \ 283 | { 18, 1, USB_VERSION, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs } 284 | 285 | #define D_CONFIG(_totalLength,_interfaces) \ 286 | { 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, USB_CONFIG_POWER_MA(500) } 287 | 288 | #define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \ 289 | { 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 } 290 | 291 | #define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \ 292 | { 7, 5, _addr,_attr,_packetSize, _interval } 293 | 294 | #define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \ 295 | { 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 } 296 | 297 | #define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } 298 | #define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 } 299 | 300 | // Bootloader related fields 301 | // Old Caterina bootloader places the MAGIC key into unsafe RAM locations (it can be rewritten 302 | // by the running sketch before to actual reboot). 303 | // Newer bootloaders, recognizable by the LUFA "signature" at the end of the flash, can handle both 304 | // the usafe and the safe location. 305 | #ifndef MAGIC_KEY 306 | #define MAGIC_KEY 0x7777 307 | #endif 308 | 309 | #ifndef MAGIC_KEY_POS 310 | #define MAGIC_KEY_POS 0x0800 311 | #endif 312 | 313 | #ifndef NEW_LUFA_SIGNATURE 314 | #define NEW_LUFA_SIGNATURE 0xDCFB 315 | #endif 316 | 317 | #endif 318 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge_multi_cdc/USBDesc.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Peter Barrett 3 | Copyright (c) 2015, Arduino LLC 4 | 5 | Permission to use, copy, modify, and/or distribute this software for 6 | any purpose with or without fee is hereby granted, provided that the 7 | above copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 12 | BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES 13 | OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 14 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 15 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 16 | SOFTWARE. 17 | */ 18 | 19 | #define PLUGGABLE_USB_ENABLED 20 | 21 | #if defined(EPRST6) 22 | #define USB_ENDPOINTS 7 // AtMegaxxU4 23 | #else 24 | #define USB_ENDPOINTS 5 // AtMegaxxU2 25 | #endif 26 | 27 | #define ISERIAL_MAX_LEN 20 28 | 29 | #define CDC_INTERFACE_COUNT 2 30 | #define CDC_ENPOINT_COUNT 3 31 | 32 | // kai:begin 33 | #undef CDC_ACM_INTERFACE 34 | #undef CDC_DATA_INTERFACE 35 | #undef CDC_FIRST_ENDPOINT 36 | #undef CDC_ENDPOINT_ACM 37 | #undef CDC_ENDPOINT_OUT 38 | #undef CDC_ENDPOINT_IN 39 | #undef CDC_RX 40 | #undef CDC_TX 41 | 42 | #define CDC_ACM_INTERFACE1 0 // CDC ACM 43 | #define CDC_DATA_INTERFACE1 1 // CDC Data 44 | #define CDC_FIRST_ENDPOINT1 1 45 | #define CDC_ENDPOINT_ACM1 (CDC_FIRST_ENDPOINT1) // CDC First 46 | #define CDC_ENDPOINT_OUT1 (CDC_FIRST_ENDPOINT1+1) 47 | #define CDC_ENDPOINT_IN1 (CDC_FIRST_ENDPOINT1+2) 48 | 49 | #define CDC_ACM_INTERFACE2 2 // CDC ACM 50 | #define CDC_DATA_INTERFACE2 3 // CDC Data 51 | #define CDC_FIRST_ENDPOINT2 4 52 | #define CDC_ENDPOINT_ACM2 (CDC_FIRST_ENDPOINT2) // CDC First 53 | #define CDC_ENDPOINT_OUT2 (CDC_FIRST_ENDPOINT2+1) 54 | #define CDC_ENDPOINT_IN2 (CDC_FIRST_ENDPOINT2+2) 55 | 56 | // only one of both interfaces is functional: 57 | #define ACTIVE_INTERFACE 1 58 | 59 | #if ACTIVE_INTERFACE == 1 60 | # define CDC_CLASS_INTERFACE CDC_ACM_INTERFACE1 61 | # define CDC_RX CDC_ENDPOINT_OUT1 62 | # define CDC_TX CDC_ENDPOINT_IN1 63 | #else 64 | # define CDC_CLASS_INTERFACE CDC_ACM_INTERFACE2 65 | # define CDC_RX CDC_ENDPOINT_OUT2 66 | # define CDC_TX CDC_ENDPOINT_IN2 67 | #endif 68 | 69 | #undef USB_VID 70 | #define USB_VID 0x2342 71 | // kai:end 72 | 73 | #define INTERFACE_COUNT (MSC_INTERFACE + MSC_INTERFACE_COUNT) 74 | 75 | #define IMANUFACTURER 1 76 | #define IPRODUCT 2 77 | #define ISERIAL 3 78 | -------------------------------------------------------------------------------- /test/arduino_leonardo_bridge_multi_cdc/arduino_leonardo_bridge_multi_cdc.ino: -------------------------------------------------------------------------------- 1 | /* 2 | bridge USB-serial to hardware-serial 3 | 4 | for Arduinos based on ATmega32u4 (Leonardo and compatible Pro Micro, Micro) 5 | hardware serial is configured with baud-rate, databits, stopbits, parity as send over USB 6 | 7 | see https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino 8 | -> CDC.cpp|HardwareSerial.cpp for serial implementation details 9 | 10 | this sketch is mainly for demonstration / test of CDC communication 11 | performance as real usb-serial bridge would be inacceptable as each byte is send in separate USB packet 12 | */ 13 | 14 | uint32_t baud = 9600; 15 | uint8_t databits = 8; 16 | uint8_t stopbits = 1; 17 | uint8_t parity = 0; 18 | 19 | void setup() { 20 | Serial.begin(baud); // USB 21 | Serial1.begin(baud, SERIAL_8N1); 22 | } 23 | 24 | void loop() { 25 | // show USB connected state 26 | if (Serial) TXLED1; 27 | else TXLED0; 28 | 29 | // configure hardware serial 30 | if (Serial.baud() != baud || 31 | Serial.numbits() != databits || 32 | Serial.stopbits() != stopbits || 33 | Serial.paritytype() != parity) { 34 | baud = Serial.baud(); 35 | databits = Serial.numbits(); 36 | stopbits = Serial.stopbits(); 37 | parity = Serial.paritytype(); 38 | uint8_t config = 0; // ucsrc register 39 | switch (databits) { 40 | case 5: break; 41 | case 6: config |= 2; break; 42 | case 7: config |= 4; break; 43 | case 8: config |= 6; break; 44 | default: config |= 6; 45 | } 46 | switch (stopbits) { 47 | case 2: config |= 8; 48 | // 1.5 stopbits not supported 49 | } 50 | switch (parity) { 51 | case 1: config |= 0x30; break; // odd 52 | case 2: config |= 0x20; break; // even 53 | // mark, space not supported 54 | } 55 | Serial1.end(); 56 | Serial1.begin(baud, config); 57 | } 58 | 59 | // bridge 60 | if (Serial.available() > 0) 61 | Serial1.write(Serial.read()); 62 | if (Serial1.available() > 0) 63 | Serial.write(Serial1.read()); 64 | } 65 | -------------------------------------------------------------------------------- /test/pi_pico/README.md: -------------------------------------------------------------------------------- 1 | 2 | # `tinyusb_dev_cdc_dual_ports.uf2` 3 | 4 | compiled from `C:/Program Files/Raspberry Pi/Pico SDK v1.5.1/pico-sdk/lib/tinyusb/examples/device/cdc_dual_ports` 5 | to `C:/Users/` _user_`/Documents/Pico-v1.5.1/pico-examples/build/usb/device/tinyusb_device_examples/cdc_dual_ports/tinyusb_dev_cdc_dual_ports.uf2` 6 | 7 | -------------------------------------------------------------------------------- /test/pi_pico/tinyusb_dev_cdc_dual_ports.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mik3y/usb-serial-for-android/c608aadc59d2d09f5e34ab928de42c16bf69864f/test/pi_pico/tinyusb_dev_cdc_dual_ports.uf2 -------------------------------------------------------------------------------- /test/rfc2217_server.diff: -------------------------------------------------------------------------------- 1 | *** /n/archiv/python/rfc2217_server.py 2018-03-10 09:02:07.613771600 +0100 2 | --- rfc2217_server.py 2018-03-09 20:57:44.933717100 +0100 3 | *************** 4 | *** 26,31 **** 5 | --- 26,32 ---- 6 | self, 7 | logger=logging.getLogger('rfc2217.server') if debug else None) 8 | self.log = logging.getLogger('redirector') 9 | + self.dlog = logging.getLogger('data') 10 | 11 | def statusline_poller(self): 12 | self.log.debug('status line poll thread started') 13 | *************** 14 | *** 55,60 **** 15 | --- 56,62 ---- 16 | try: 17 | data = self.serial.read(self.serial.in_waiting or 1) 18 | if data: 19 | + self.dlog.debug("serial read: "+data.encode('hex')) 20 | # escape outgoing data when needed (Telnet IAC (0xff) character) 21 | self.write(b''.join(self.rfc2217.escape(data))) 22 | except socket.error as msg: 23 | *************** 24 | *** 76,81 **** 25 | --- 78,84 ---- 26 | data = self.socket.recv(1024) 27 | if not data: 28 | break 29 | + self.dlog.debug("socket read: "+data.encode('hex')) 30 | self.serial.write(b''.join(self.rfc2217.filter(data))) 31 | except socket.error as msg: 32 | self.log.error('{}'.format(msg)) 33 | *************** 34 | *** 132,137 **** 35 | --- 135,141 ---- 36 | logging.basicConfig(level=logging.INFO) 37 | #~ logging.getLogger('root').setLevel(logging.INFO) 38 | logging.getLogger('rfc2217').setLevel(level) 39 | + logging.getLogger('data').setLevel(level) 40 | 41 | # connect to serial port 42 | ser = serial.serial_for_url(args.SERIALPORT, do_not_open=True) 43 | -------------------------------------------------------------------------------- /usbSerialExamples/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | android { 6 | compileSdkVersion 35 7 | 8 | compileOptions { 9 | sourceCompatibility JavaVersion.VERSION_1_8 10 | targetCompatibility JavaVersion.VERSION_1_8 11 | } 12 | 13 | defaultConfig { 14 | minSdkVersion 17 15 | targetSdkVersion 35 16 | vectorDrawables.useSupportLibrary = true 17 | 18 | missingDimensionStrategy 'device', 'anyDevice' 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled true 24 | } 25 | } 26 | namespace 'com.hoho.android.usbserial.examples' 27 | } 28 | 29 | dependencies { 30 | implementation project(':usbSerialForAndroid') 31 | implementation 'androidx.appcompat:appcompat:1.6.1' // later versions have minsdk 21 32 | implementation 'com.google.android.material:material:1.11.0' // later versions have minsdk 19 33 | } 34 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/java/com/hoho/android/usbserial/examples/CustomProber.java: -------------------------------------------------------------------------------- 1 | package com.hoho.android.usbserial.examples; 2 | 3 | import com.hoho.android.usbserial.driver.FtdiSerialDriver; 4 | import com.hoho.android.usbserial.driver.ProbeTable; 5 | import com.hoho.android.usbserial.driver.UsbSerialProber; 6 | 7 | /** 8 | * add devices here, that are not known to DefaultProber 9 | * 10 | * if the App should auto start for these devices, also 11 | * add IDs to app/src/main/res/xml/device_filter.xml 12 | */ 13 | class CustomProber { 14 | 15 | static UsbSerialProber getCustomProber() { 16 | ProbeTable customTable = new ProbeTable(); 17 | customTable.addProduct(0x1234, 0x0001, FtdiSerialDriver.class); // e.g. device with custom VID+PID 18 | customTable.addProduct(0x1234, 0x0002, FtdiSerialDriver.class); // e.g. device with custom VID+PID 19 | return new UsbSerialProber(customTable); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/java/com/hoho/android/usbserial/examples/DevicesFragment.java: -------------------------------------------------------------------------------- 1 | package com.hoho.android.usbserial.examples; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.hardware.usb.UsbDevice; 6 | import android.hardware.usb.UsbManager; 7 | import android.os.Bundle; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.fragment.app.Fragment; 11 | import androidx.fragment.app.ListFragment; 12 | import android.view.Menu; 13 | import android.view.MenuInflater; 14 | import android.view.MenuItem; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.widget.ArrayAdapter; 18 | import android.widget.ListView; 19 | import android.widget.TextView; 20 | import android.widget.Toast; 21 | 22 | import com.hoho.android.usbserial.driver.UsbSerialDriver; 23 | import com.hoho.android.usbserial.driver.UsbSerialProber; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Locale; 27 | 28 | public class DevicesFragment extends ListFragment { 29 | 30 | static class ListItem { 31 | UsbDevice device; 32 | int port; 33 | UsbSerialDriver driver; 34 | 35 | ListItem(UsbDevice device, int port, UsbSerialDriver driver) { 36 | this.device = device; 37 | this.port = port; 38 | this.driver = driver; 39 | } 40 | } 41 | 42 | private final ArrayList listItems = new ArrayList<>(); 43 | private ArrayAdapter listAdapter; 44 | private int baudRate = 19200; 45 | private boolean withIoManager = true; 46 | 47 | @Override 48 | public void onCreate(Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | setHasOptionsMenu(true); 51 | listAdapter = new ArrayAdapter(getActivity(), 0, listItems) { 52 | @NonNull 53 | @Override 54 | public View getView(int position, View view, @NonNull ViewGroup parent) { 55 | ListItem item = listItems.get(position); 56 | if (view == null) 57 | view = getActivity().getLayoutInflater().inflate(R.layout.device_list_item, parent, false); 58 | TextView text1 = view.findViewById(R.id.text1); 59 | TextView text2 = view.findViewById(R.id.text2); 60 | if(item.driver == null) 61 | text1.setText(""); 62 | else if(item.driver.getPorts().size() == 1) 63 | text1.setText(item.driver.getClass().getSimpleName().replace("SerialDriver","")); 64 | else 65 | text1.setText(item.driver.getClass().getSimpleName().replace("SerialDriver","")+", Port "+item.port); 66 | text2.setText(String.format(Locale.US, "Vendor %04X, Product %04X", item.device.getVendorId(), item.device.getProductId())); 67 | return view; 68 | } 69 | }; 70 | } 71 | 72 | @Override 73 | public void onActivityCreated(Bundle savedInstanceState) { 74 | super.onActivityCreated(savedInstanceState); 75 | setListAdapter(null); 76 | View header = getActivity().getLayoutInflater().inflate(R.layout.device_list_header, null, false); 77 | getListView().addHeaderView(header, null, false); 78 | setEmptyText(""); 79 | ((TextView) getListView().getEmptyView()).setTextSize(18); 80 | setListAdapter(listAdapter); 81 | } 82 | 83 | @Override 84 | public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) { 85 | inflater.inflate(R.menu.menu_devices, menu); 86 | } 87 | 88 | @Override 89 | public void onResume() { 90 | super.onResume(); 91 | refresh(); 92 | } 93 | 94 | @Override 95 | public boolean onOptionsItemSelected(MenuItem item) { 96 | int id = item.getItemId(); 97 | if(id == R.id.refresh) { 98 | refresh(); 99 | return true; 100 | } else if (id ==R.id.baud_rate) { 101 | final String[] values = getResources().getStringArray(R.array.baud_rates); 102 | int pos = java.util.Arrays.asList(values).indexOf(String.valueOf(baudRate)); 103 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 104 | builder.setTitle("Baud rate"); 105 | builder.setSingleChoiceItems(values, pos, (dialog, which) -> { 106 | baudRate = Integer.parseInt(values[which]); 107 | dialog.dismiss(); 108 | }); 109 | builder.create().show(); 110 | return true; 111 | } else if (id ==R.id.read_mode) { 112 | final String[] values = getResources().getStringArray(R.array.read_modes); 113 | int pos = withIoManager ? 0 : 1; // read_modes[0]=event/io-manager, read_modes[1]=direct 114 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 115 | builder.setTitle("Read mode"); 116 | builder.setSingleChoiceItems(values, pos, (dialog, which) -> { 117 | withIoManager = (which == 0); 118 | dialog.dismiss(); 119 | }); 120 | builder.create().show(); 121 | return true; 122 | } else { 123 | return super.onOptionsItemSelected(item); 124 | } 125 | } 126 | 127 | void refresh() { 128 | UsbManager usbManager = (UsbManager) getActivity().getSystemService(Context.USB_SERVICE); 129 | UsbSerialProber usbDefaultProber = UsbSerialProber.getDefaultProber(); 130 | UsbSerialProber usbCustomProber = CustomProber.getCustomProber(); 131 | listItems.clear(); 132 | for(UsbDevice device : usbManager.getDeviceList().values()) { 133 | UsbSerialDriver driver = usbDefaultProber.probeDevice(device); 134 | if(driver == null) { 135 | driver = usbCustomProber.probeDevice(device); 136 | } 137 | if(driver != null) { 138 | for(int port = 0; port < driver.getPorts().size(); port++) 139 | listItems.add(new ListItem(device, port, driver)); 140 | } else { 141 | listItems.add(new ListItem(device, 0, null)); 142 | } 143 | } 144 | listAdapter.notifyDataSetChanged(); 145 | } 146 | 147 | @Override 148 | public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) { 149 | ListItem item = listItems.get(position-1); 150 | if(item.driver == null) { 151 | Toast.makeText(getActivity(), "no driver", Toast.LENGTH_SHORT).show(); 152 | } else { 153 | Bundle args = new Bundle(); 154 | args.putInt("device", item.device.getDeviceId()); 155 | args.putInt("port", item.port); 156 | args.putInt("baud", baudRate); 157 | args.putBoolean("withIoManager", withIoManager); 158 | Fragment fragment = new TerminalFragment(); 159 | fragment.setArguments(args); 160 | getFragmentManager().beginTransaction().replace(R.id.fragment, fragment, "terminal").addToBackStack(null).commit(); 161 | } 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/java/com/hoho/android/usbserial/examples/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.hoho.android.usbserial.examples; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import androidx.fragment.app.FragmentManager; 6 | import androidx.appcompat.app.AppCompatActivity; 7 | import androidx.appcompat.widget.Toolbar; 8 | 9 | public class MainActivity extends AppCompatActivity implements FragmentManager.OnBackStackChangedListener { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_main); 15 | Toolbar toolbar = findViewById(R.id.toolbar); 16 | setSupportActionBar(toolbar); 17 | getSupportFragmentManager().addOnBackStackChangedListener(this); 18 | if (savedInstanceState == null) 19 | getSupportFragmentManager().beginTransaction().add(R.id.fragment, new DevicesFragment(), "devices").commit(); 20 | else 21 | onBackStackChanged(); 22 | } 23 | 24 | @Override 25 | public void onBackStackChanged() { 26 | getSupportActionBar().setDisplayHomeAsUpEnabled(getSupportFragmentManager().getBackStackEntryCount()>0); 27 | } 28 | 29 | @Override 30 | public boolean onSupportNavigateUp() { 31 | onBackPressed(); 32 | return true; 33 | } 34 | 35 | @Override 36 | protected void onNewIntent(Intent intent) { 37 | if("android.hardware.usb.action.USB_DEVICE_ATTACHED".equals(intent.getAction())) { 38 | TerminalFragment terminal = (TerminalFragment)getSupportFragmentManager().findFragmentByTag("terminal"); 39 | if (terminal != null) 40 | terminal.status("USB device detected"); 41 | } 42 | super.onNewIntent(intent); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/drawable/ic_delete_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/drawable/ic_send_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/layout/device_list_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/layout/device_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /usbSerialExamples/src/main/res/layout/fragment_terminal.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 21 | 22 | 31 | 32 | 35 | 36 | 43 | 44 | 53 | 54 | 57 | 58 | 67 | 68 | 77 | 78 | 79 | 80 | 84 | 85 | 95 | 96 |