├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── maven_publish.gradle
├── sample
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── android
│ │ └── serialport
│ │ └── sample
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── android
│ │ │ └── serialport
│ │ │ └── sample
│ │ │ ├── Application.java
│ │ │ ├── ConsoleActivity.java
│ │ │ ├── LoopbackActivity.java
│ │ │ ├── MainMenu.java
│ │ │ ├── Sending01010101Activity.java
│ │ │ ├── SerialPortActivity.java
│ │ │ └── SerialPortPreferences.java
│ └── res
│ │ ├── drawable
│ │ └── icon.png
│ │ ├── layout
│ │ ├── console.xml
│ │ ├── loopback.xml
│ │ ├── main.xml
│ │ └── sending01010101.xml
│ │ ├── values
│ │ ├── baudrates.xml
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ └── serial_port_preferences.xml
│ └── test
│ └── java
│ └── android
│ └── serialport
│ └── sample
│ └── ExampleUnitTest.java
├── serialport
├── .gitignore
├── CMakeLists.txt
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── cpp
│ ├── SerialPort.c
│ ├── SerialPort.h
│ └── gen_SerialPort_h.sh
│ ├── java
│ └── android
│ │ └── serialport
│ │ ├── SerialPort.java
│ │ └── SerialPortFinder.java
│ └── res
│ └── values
│ └── strings.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .idea
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android-SerialPort-API
2 | [Fork](https://code.google.com/archive/p/android-serialport-api/)自Google开源的Android串口通信Demo,修改成Android Studio项目
3 |
4 | This lib is a [fork](https://code.google.com/archive/p/android-serialport-api/) of the Android serial port communication Demo open sourced by Google.
5 |
6 | ## Installation & Usage
7 | **Gradle**
8 |
9 | 添加依赖:
10 |
11 | Add the dependency:
12 |
13 | ```
14 | allprojects {
15 | repositories {
16 | ...
17 | jcenter()
18 | mavenCentral() // since 2.1.3
19 | }
20 | }
21 |
22 | dependencies {
23 | // 传统4KB内存页面版本
24 | implementation 'com.licheedev:android-serialport:2.1.4'
25 | // 适配16KB页面版本,https://developer.android.google.cn/guide/practices/page-sizes?hl=zh-cn
26 | implementation 'com.licheedev:android-serialport:2.1.5'
27 | }
28 | ```
29 |
30 | **Import**
31 |
32 | ```java
33 | import android.serialport.SerialPort;
34 | ```
35 |
36 | **`su` path**
37 |
38 | In order to read/write to a serial port in Android you'll need `su` binary installed on device (this can be done by rooting the device). Usually Android devices that has the ability to communicate with serial ports have `su` installed on the default path `"/system/bin/su"`. To change this use:
39 |
40 | ```java
41 | // su默认路径为 "/system/bin/su"
42 | // The default path of su is "/system/bin/su"
43 | // 可通过此方法修改
44 | // If the path is different then change it using this
45 | SerialPort.setSuPath("/system/xbin/su");
46 | ```
47 |
48 | **Usage**
49 |
50 | ```java
51 | // 默认8N1(8数据位、无校验位、1停止位)
52 | // Default 8N1 (8 data bits, no parity bit, 1 stop bit)
53 | SerialPort serialPort = new SerialPort(path, baudrate);
54 |
55 | // 可选配置数据位、校验位、停止位 - 7E2(7数据位、偶校验、2停止位)
56 | // or with builder (with optional configurations) - 7E2 (7 data bits, even parity, 2 stop bits)
57 | SerialPort serialPort = SerialPort
58 | .newBuilder(path, baudrate)
59 | // 校验位;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
60 | // Check bit; 0: no check bit (NONE, default); 1: odd check bit (ODD); 2: even check bit (EVEN)
61 | // .parity(2)
62 | // 数据位,默认8;可选值为5~8
63 | // Data bit, default 8; optional value is 5~8
64 | // .dataBits(7)
65 | // 停止位,默认1;1:1位停止位;2:2位停止位
66 | // Stop bit, default 1; 1:1 stop bit; 2: 2 stop bit
67 | // .stopBits(2)
68 | .build();
69 |
70 | // read/write to serial port - needs to be in different thread!
71 | InputStream in = serialPort.getInputStream();
72 | OutputStream out = serialPort.getOutputStream();
73 |
74 | // close
75 | serialPort.tryClose();
76 | ```
77 |
78 | 实现方式参考
79 |
80 | Implementation reference
81 | 1. Check [sample project](https://github.com/licheedev/Android-SerialPort-API/tree/master/sample)
82 | 2. https://juejin.im/post/5c010a19e51d456ac27b40fc
83 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 | mavenCentral()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:4.2.2'
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.4.32'
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 | mavenCentral()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
29 | ext {
30 | compileSdkVersion = 29
31 |
32 | minSdkVersion = 8
33 | targetSdkVersion = 29
34 |
35 | versionCode = 3
36 | versionName = "2.1.5"
37 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Mon Sep 18 19:30:46 CST 2017
16 | android.enableJetifier=true
17 | android.useAndroidX=true
18 | org.gradle.jvmargs=-Xmx1536m
19 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/licheedev/Android-SerialPort-API/0768a6bbb9bfb9cace71253a5b1a4b1c5e9f541b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Sep 06 10:04:58 CST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/maven_publish.gradle:
--------------------------------------------------------------------------------
1 | // 依赖信息
2 | def groupIdDefined = "com.licheedev"
3 | def artifactIdDefined = "android-serialport"
4 | // 如果是测试版,版本号后面加上 -SNAPSHOT
5 | def versionDefined = rootProject.ext.versionName
6 | // 其他信息
7 | def gitUrl = "https://github.com/licheedev/Android-SerialPort-API"
8 |
9 | // 配置是否上传
10 | def toUpload = true
11 |
12 | //在根build.gradle中加入,最新版本号参考 https://github.com/Kotlin/dokka#using-dokka
13 | //classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.4.32'
14 |
15 | //在module的build.gradle末位加入
16 | //apply from: '../maven_publish.gradle'
17 |
18 | if (toUpload) {
19 | apply plugin: 'signing'
20 | apply plugin: 'maven-publish'
21 | apply plugin: 'org.jetbrains.dokka'
22 |
23 | //
24 | // 打包源码
25 | task sourcesJar(type: Jar) {
26 | from android.sourceSets.main.java.srcDirs
27 | classifier = 'sources'
28 | }
29 |
30 | task javadoc(type: Javadoc) {
31 | failOnError false
32 | source = android.sourceSets.main.java.sourceFiles
33 | options {
34 | encoding = "utf-8"
35 | charSet 'UTF-8'
36 | }
37 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
38 | classpath += configurations.compile
39 | }
40 |
41 | // 打包javadoc
42 | task javadocJar(type: Jar, dependsOn: javadoc) {
43 | classifier = 'javadoc'
44 | from javadoc.destinationDir
45 | }
46 |
47 | // 打包包含kotlin源码的javadoc
48 | task kotlinDocJar(type: Jar, dependsOn: dokkaHtml) {
49 | classifier = 'javadoc'
50 | from dokkaHtml.outputDirectory
51 | }
52 | //
53 |
54 | afterEvaluate {
55 |
56 | publishing {
57 | publications {
58 | mavenAndroid(MavenPublication) {
59 | from components.release
60 |
61 | groupId "$groupIdDefined"
62 | artifactId "$artifactIdDefined"
63 | version "$versionDefined"
64 | // 上传source
65 | artifact sourcesJar
66 | // 上传javadoc
67 | if (project.plugins.hasPlugin('kotlin-android')) {
68 | artifact kotlinDocJar
69 | } else {
70 | artifact javadocJar
71 | }
72 |
73 | pom {
74 | name = 'Android-SerialPort-API'
75 | description = 'Android-SerialPort-API'
76 | url = "$gitUrl"
77 |
78 | //licenses {
79 | // license {
80 | // name = 'The MIT License'
81 | // url = 'https://opensource.org/licenses/MIT'
82 | // }
83 | //}
84 |
85 | licenses {
86 | license {
87 | name = 'The Apache License, Version 2.0'
88 | url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
89 | }
90 | }
91 |
92 | developers {
93 | developer {
94 | id = 'licheedev'
95 | name = 'John Lee'
96 | email = 'licheedev@foxmail.com'
97 | }
98 | }
99 | scm {
100 | connection = "$gitUrl"
101 | developerConnection = "${gitUrl}.git"
102 | url = "$gitUrl"
103 | }
104 | }
105 | }
106 | }
107 |
108 | repositories {
109 |
110 | maven {
111 | // 依赖发布地址
112 | def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
113 | def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
114 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
115 |
116 | // 配置账号密码
117 | println "user=${ossrhUsername},key=${ossrhPassword}"
118 | credentials {
119 | username "${ossrhUsername}"
120 | password "${ossrhPassword}"
121 | }
122 | }
123 | }
124 | }
125 |
126 | signing {
127 | sign publishing.publications.mavenAndroid
128 | }
129 | }
130 | }
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion rootProject.ext.compileSdkVersion
5 |
6 | defaultConfig {
7 | applicationId "android.serialport.sample"
8 | minSdkVersion 15
9 | targetSdkVersion rootProject.ext.targetSdkVersion
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | implementation fileTree(include: ['*.jar'], dir: 'libs')
25 | androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
26 | exclude group: 'com.android.support', module: 'support-annotations'
27 | })
28 | implementation 'androidx.appcompat:appcompat:1.2.0'
29 | testImplementation 'junit:junit:4.13'
30 | //implementation project(':serialport')
31 | implementation 'com.licheedev:android-serialport:2.1.5'
32 | }
33 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\DevTools\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/sample/src/androidTest/java/android/serialport/sample/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package android.serialport.sample;
2 |
3 | import android.content.Context;
4 | import androidx.test.platform.app.InstrumentationRegistry;
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("android.serialport.sample", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/sample/src/main/java/android/serialport/sample/Application.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2009 Cedric Priscal
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package android.serialport.sample;
18 |
19 | import android.content.SharedPreferences;
20 | import android.serialport.SerialPort;
21 | import android.serialport.SerialPortFinder;
22 | import java.io.IOException;
23 | import java.security.InvalidParameterException;
24 |
25 | public class Application extends android.app.Application {
26 |
27 | public SerialPortFinder mSerialPortFinder = new SerialPortFinder();
28 | private SerialPort mSerialPort = null;
29 |
30 | public SerialPort getSerialPort()
31 | throws SecurityException, IOException, InvalidParameterException {
32 | if (mSerialPort == null) {
33 | /* Read serial port parameters */
34 |
35 | String packageName = getPackageName();
36 | SharedPreferences sp = getSharedPreferences(packageName + "_preferences", MODE_PRIVATE);
37 | String path = sp.getString("DEVICE", "");
38 | int baudrate = Integer.decode(sp.getString("BAUDRATE", "-1"));
39 |
40 | /* Check parameters */
41 | if ((path.length() == 0) || (baudrate == -1)) {
42 | throw new InvalidParameterException();
43 | }
44 |
45 | /* Open the serial port */
46 | //mSerialPort = new SerialPort(new File(path), baudrate, 0);
47 |
48 | SerialPort serialPort = SerialPort //
49 | .newBuilder(path, baudrate) // 串口地址地址,波特率
50 | .parity(2) // 校验位;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
51 | .dataBits(7) // 数据位,默认8;可选值为5~8
52 | .stopBits(2) // 停止位,默认1;1:1位停止位;2:2位停止位
53 | .build();
54 |
55 | mSerialPort = serialPort;
56 | }
57 | return mSerialPort;
58 | }
59 |
60 | public void closeSerialPort() {
61 | if (mSerialPort != null) {
62 | mSerialPort.close();
63 | mSerialPort = null;
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/sample/src/main/java/android/serialport/sample/ConsoleActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2009 Cedric Priscal
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package android.serialport.sample;
18 |
19 | import java.io.IOException;
20 |
21 | import android.os.Bundle;
22 | import android.view.KeyEvent;
23 | import android.widget.EditText;
24 | import android.widget.TextView;
25 | import android.widget.TextView.OnEditorActionListener;
26 |
27 | public class ConsoleActivity extends SerialPortActivity {
28 |
29 | EditText mReception;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.console);
35 |
36 | // setTitle("Loopback test");
37 | mReception = (EditText) findViewById(R.id.EditTextReception);
38 |
39 | EditText Emission = (EditText) findViewById(R.id.EditTextEmission);
40 | Emission.setOnEditorActionListener(new OnEditorActionListener() {
41 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
42 | int i;
43 | CharSequence t = v.getText();
44 | char[] text = new char[t.length()];
45 | for (i = 0; i < t.length(); i++) {
46 | text[i] = t.charAt(i);
47 | }
48 | try {
49 | mOutputStream.write(new String(text).getBytes());
50 | mOutputStream.write('\n');
51 | } catch (IOException e) {
52 | e.printStackTrace();
53 | }
54 | return false;
55 | }
56 | });
57 | }
58 |
59 | @Override
60 | protected void onDataReceived(final byte[] buffer, final int size) {
61 | runOnUiThread(new Runnable() {
62 | public void run() {
63 | if (mReception != null) {
64 | mReception.append(new String(buffer, 0, size));
65 | }
66 | }
67 | });
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/sample/src/main/java/android/serialport/sample/LoopbackActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2009 Cedric Priscal
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package android.serialport.sample;
18 |
19 | import java.io.IOException;
20 |
21 | import android.os.Bundle;
22 | import android.widget.TextView;
23 |
24 | public class LoopbackActivity extends SerialPortActivity {
25 |
26 | byte mValueToSend;
27 | boolean mByteReceivedBack;
28 | Object mByteReceivedBackSemaphore = new Object();
29 | Integer mIncoming = new Integer(0);
30 | Integer mOutgoing = new Integer(0);
31 | Integer mLost = new Integer(0);
32 | Integer mCorrupted = new Integer(0);
33 |
34 | SendingThread mSendingThread;
35 | TextView mTextViewOutgoing;
36 | TextView mTextViewIncoming;
37 | TextView mTextViewLost;
38 | TextView mTextViewCorrupted;
39 |
40 | private class SendingThread extends Thread {
41 | @Override
42 | public void run() {
43 | while (!isInterrupted()) {
44 | synchronized (mByteReceivedBackSemaphore) {
45 | mByteReceivedBack = false;
46 | try {
47 | if (mOutputStream != null) {
48 | mOutputStream.write(mValueToSend);
49 | } else {
50 | return;
51 | }
52 | } catch (IOException e) {
53 | e.printStackTrace();
54 | return;
55 | }
56 | mOutgoing++;
57 | // Wait for 100ms before sending next byte, or as soon as
58 | // the sent byte has been read back.
59 | try {
60 | mByteReceivedBackSemaphore.wait(100);
61 | if (mByteReceivedBack == true) {
62 | // Byte has been received
63 | mIncoming++;
64 | } else {
65 | // Timeout
66 | mLost++;
67 | }
68 | runOnUiThread(new Runnable() {
69 | public void run() {
70 | mTextViewOutgoing.setText(mOutgoing.toString());
71 | mTextViewLost.setText(mLost.toString());
72 | mTextViewIncoming.setText(mIncoming.toString());
73 | mTextViewCorrupted.setText(mCorrupted.toString());
74 | }
75 | });
76 | } catch (InterruptedException e) {
77 | }
78 | }
79 | }
80 | }
81 | }
82 |
83 | @Override
84 | protected void onCreate(Bundle savedInstanceState) {
85 | super.onCreate(savedInstanceState);
86 | setContentView(R.layout.loopback);
87 | mTextViewOutgoing = (TextView) findViewById(R.id.TextViewOutgoingValue);
88 | mTextViewIncoming = (TextView) findViewById(R.id.TextViewIncomingValue);
89 | mTextViewLost = (TextView) findViewById(R.id.textViewLostValue);
90 | mTextViewCorrupted = (TextView) findViewById(R.id.textViewCorruptedValue);
91 | if (mSerialPort != null) {
92 | mSendingThread = new SendingThread();
93 | mSendingThread.start();
94 | }
95 | }
96 |
97 | @Override
98 | protected void onDataReceived(byte[] buffer, int size) {
99 |
100 | synchronized (mByteReceivedBackSemaphore) {
101 | int i;
102 | for (i = 0; i < size; i++) {
103 | if ((buffer[i] == mValueToSend) && (mByteReceivedBack == false)) {
104 | mValueToSend++;
105 | // This byte was expected
106 | // Wake-up the sending thread
107 | mByteReceivedBack = true;
108 | mByteReceivedBackSemaphore.notify();
109 | } else {
110 | // The byte was not expected
111 | mCorrupted++;
112 | }
113 | }
114 | }
115 | }
116 |
117 | @Override
118 | protected void onDestroy() {
119 | if (mSendingThread != null) mSendingThread.interrupt();
120 | super.onDestroy();
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/sample/src/main/java/android/serialport/sample/MainMenu.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2009 Cedric Priscal
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package android.serialport.sample;
18 |
19 | import android.app.Activity;
20 | import android.app.AlertDialog;
21 | import android.content.Intent;
22 | import android.os.Bundle;
23 | import android.view.View;
24 | import android.widget.Button;
25 |
26 | public class MainMenu extends Activity {
27 |
28 | /** Called when the activity is first created. */
29 | @Override
30 | public void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.main);
33 |
34 | final Button buttonSetup = (Button) findViewById(R.id.ButtonSetup);
35 | buttonSetup.setOnClickListener(new View.OnClickListener() {
36 | public void onClick(View v) {
37 | startActivity(new Intent(MainMenu.this, SerialPortPreferences.class));
38 | }
39 | });
40 |
41 | final Button buttonConsole = (Button) findViewById(R.id.ButtonConsole);
42 | buttonConsole.setOnClickListener(new View.OnClickListener() {
43 | public void onClick(View v) {
44 | startActivity(new Intent(MainMenu.this, ConsoleActivity.class));
45 | }
46 | });
47 |
48 | final Button buttonLoopback = (Button) findViewById(R.id.ButtonLoopback);
49 | buttonLoopback.setOnClickListener(new View.OnClickListener() {
50 | public void onClick(View v) {
51 | startActivity(new Intent(MainMenu.this, LoopbackActivity.class));
52 | }
53 | });
54 |
55 | final Button button01010101 = (Button) findViewById(R.id.Button01010101);
56 | button01010101.setOnClickListener(new View.OnClickListener() {
57 | public void onClick(View v) {
58 | startActivity(new Intent(MainMenu.this, Sending01010101Activity.class));
59 | }
60 | });
61 |
62 | final Button buttonAbout = (Button) findViewById(R.id.ButtonAbout);
63 | buttonAbout.setOnClickListener(new View.OnClickListener() {
64 | public void onClick(View v) {
65 | AlertDialog.Builder builder = new AlertDialog.Builder(MainMenu.this);
66 | builder.setTitle("About");
67 | builder.setMessage(R.string.about_msg);
68 | builder.show();
69 | }
70 | });
71 |
72 | final Button buttonQuit = (Button) findViewById(R.id.ButtonQuit);
73 | buttonQuit.setOnClickListener(new View.OnClickListener() {
74 | public void onClick(View v) {
75 | MainMenu.this.finish();
76 | }
77 | });
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/sample/src/main/java/android/serialport/sample/Sending01010101Activity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 Cedric Priscal
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package android.serialport.sample;
18 |
19 | import java.io.IOException;
20 | import java.util.Arrays;
21 |
22 | import android.os.Bundle;
23 |
24 | public class Sending01010101Activity extends SerialPortActivity {
25 |
26 | SendingThread mSendingThread;
27 | byte[] mBuffer;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.sending01010101);
33 | mBuffer = new byte[1024];
34 | Arrays.fill(mBuffer, (byte) 0x55);
35 | if (mSerialPort != null) {
36 | mSendingThread = new SendingThread();
37 | mSendingThread.start();
38 | }
39 | }
40 |
41 | @Override
42 | protected void onDataReceived(byte[] buffer, int size) {
43 | // ignore incoming data
44 | }
45 |
46 | private class SendingThread extends Thread {
47 | @Override
48 | public void run() {
49 | while (!isInterrupted()) {
50 | try {
51 | if (mOutputStream != null) {
52 | mOutputStream.write(mBuffer);
53 | } else {
54 | return;
55 | }
56 | } catch (IOException e) {
57 | e.printStackTrace();
58 | return;
59 | }
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/sample/src/main/java/android/serialport/sample/SerialPortActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2009 Cedric Priscal
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package android.serialport.sample;
18 |
19 | import android.app.Activity;
20 | import android.app.AlertDialog;
21 | import android.content.DialogInterface;
22 | import android.content.DialogInterface.OnClickListener;
23 | import android.os.Bundle;
24 | import android.serialport.SerialPort;
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 | import java.io.OutputStream;
28 | import java.security.InvalidParameterException;
29 |
30 | public abstract class SerialPortActivity extends Activity {
31 |
32 | protected Application mApplication;
33 | protected SerialPort mSerialPort;
34 | protected OutputStream mOutputStream;
35 | private InputStream mInputStream;
36 | private ReadThread mReadThread;
37 |
38 | private class ReadThread extends Thread {
39 |
40 | @Override
41 | public void run() {
42 | super.run();
43 | while (!isInterrupted()) {
44 | int size;
45 | try {
46 | byte[] buffer = new byte[64];
47 | if (mInputStream == null) return;
48 | size = mInputStream.read(buffer);
49 | if (size > 0) {
50 | onDataReceived(buffer, size);
51 | }
52 | } catch (IOException e) {
53 | e.printStackTrace();
54 | return;
55 | }
56 | }
57 | }
58 | }
59 |
60 | private void DisplayError(int resourceId) {
61 | AlertDialog.Builder b = new AlertDialog.Builder(this);
62 | b.setTitle("Error");
63 | b.setMessage(resourceId);
64 | b.setPositiveButton("OK", new OnClickListener() {
65 | public void onClick(DialogInterface dialog, int which) {
66 | SerialPortActivity.this.finish();
67 | }
68 | });
69 | b.show();
70 | }
71 |
72 | @Override
73 | protected void onCreate(Bundle savedInstanceState) {
74 | super.onCreate(savedInstanceState);
75 | mApplication = (Application) getApplication();
76 | try {
77 | mSerialPort = mApplication.getSerialPort();
78 | mOutputStream = mSerialPort.getOutputStream();
79 | mInputStream = mSerialPort.getInputStream();
80 |
81 | /* Create a receiving thread */
82 | mReadThread = new ReadThread();
83 | mReadThread.start();
84 | } catch (SecurityException e) {
85 | DisplayError(R.string.error_security);
86 | } catch (IOException e) {
87 | DisplayError(R.string.error_unknown);
88 | } catch (InvalidParameterException e) {
89 | DisplayError(R.string.error_configuration);
90 | }
91 | }
92 |
93 | protected abstract void onDataReceived(final byte[] buffer, final int size);
94 |
95 | @Override
96 | protected void onDestroy() {
97 | if (mReadThread != null) mReadThread.interrupt();
98 | mApplication.closeSerialPort();
99 | mSerialPort = null;
100 | super.onDestroy();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/sample/src/main/java/android/serialport/sample/SerialPortPreferences.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2009 Cedric Priscal
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package android.serialport.sample;
18 |
19 | import android.os.Bundle;
20 | import android.preference.ListPreference;
21 | import android.preference.Preference;
22 | import android.preference.Preference.OnPreferenceChangeListener;
23 | import android.preference.PreferenceActivity;
24 | import android.serialport.SerialPortFinder;
25 |
26 | public class SerialPortPreferences extends PreferenceActivity {
27 |
28 | private Application mApplication;
29 | private SerialPortFinder mSerialPortFinder;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 |
35 | mApplication = (Application) getApplication();
36 | mSerialPortFinder = mApplication.mSerialPortFinder;
37 |
38 | addPreferencesFromResource(R.xml.serial_port_preferences);
39 |
40 | // Devices
41 | final ListPreference devices = (ListPreference) findPreference("DEVICE");
42 | String[] entries = mSerialPortFinder.getAllDevices();
43 | String[] entryValues = mSerialPortFinder.getAllDevicesPath();
44 | devices.setEntries(entries);
45 | devices.setEntryValues(entryValues);
46 | devices.setSummary(devices.getValue());
47 | devices.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
48 | public boolean onPreferenceChange(Preference preference, Object newValue) {
49 | preference.setSummary((String) newValue);
50 | return true;
51 | }
52 | });
53 |
54 | // Baud rates
55 | final ListPreference baudrates = (ListPreference) findPreference("BAUDRATE");
56 | baudrates.setSummary(baudrates.getValue());
57 | baudrates.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
58 | public boolean onPreferenceChange(Preference preference, Object newValue) {
59 | preference.setSummary((String) newValue);
60 | return true;
61 | }
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/licheedev/Android-SerialPort-API/0768a6bbb9bfb9cace71253a5b1a4b1c5e9f541b/sample/src/main/res/drawable/icon.png
--------------------------------------------------------------------------------
/sample/src/main/res/layout/console.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
17 |
18 |
19 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/loopback.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
21 |
22 |
28 |
29 |
30 |
35 |
36 |
43 |
44 |
50 |
51 |
52 |
56 |
57 |
64 |
65 |
71 |
72 |
73 |
77 |
78 |
85 |
86 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
23 |
24 |
30 |
31 |
37 |
38 |
44 |
45 |
51 |
52 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/sending01010101.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/baudrates.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - 50
6 | - 75
7 | - 110
8 | - 134
9 | - 150
10 | - 200
11 | - 300
12 | - 600
13 | - 1200
14 | - 1800
15 | - 2400
16 | - 4800
17 | - 9600
18 | - 19200
19 | - 38400
20 | - 57600
21 | - 115200
22 | - 230400
23 | - 460800
24 | - 500000
25 | - 576000
26 | - 921600
27 | - 1000000
28 | - 1152000
29 | - 1500000
30 | - 2000000
31 | - 2500000
32 | - 3000000
33 | - 3500000
34 | - 4000000
35 |
36 |
37 | - 50
38 | - 75
39 | - 110
40 | - 134
41 | - 150
42 | - 200
43 | - 300
44 | - 600
45 | - 1200
46 | - 1800
47 | - 2400
48 | - 4800
49 | - 9600
50 | - 19200
51 | - 38400
52 | - 57600
53 | - 115200
54 | - 230400
55 | - 460800
56 | - 500000
57 | - 576000
58 | - 921600
59 | - 1000000
60 | - 1152000
61 | - 1500000
62 | - 2000000
63 | - 2500000
64 | - 3000000
65 | - 3500000
66 | - 4000000
67 |
68 |
69 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Serial Port API sample
4 |
5 | Serial Port API sample v1.1\n
6 | \n
7 | This program is the sample application provided with project android-serialport-api.\n
8 | \n
9 | More information and bug report on [http://code.google.com/p/android-serialport-api]\n
10 | \n
11 | Copyright 2010-2011 Cedric Priscal\n
12 | \n
13 | Licensed under the Apache License, Version 2.0 (the "License");
14 | you may not use this file except in compliance with the License.
15 | You may obtain a copy of the License at\n
16 | \n
17 | http://www.apache.org/licenses/LICENSE-2.0\n
18 | \n
19 | Unless required by applicable law or agreed to in writing, software
20 | distributed under the License is distributed on an "AS IS" BASIS,
21 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 | See the License for the specific language governing permissions and
23 | limitations under the License.\n
24 |
25 | Please configure your serial port first.
26 | You do not have read/write permission to the serial
27 | port.
28 | The serial port can not be opened for an unknown
29 | reason.
30 |
31 |
32 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/xml/serial_port_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/test/java/android/serialport/sample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package android.serialport.sample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/serialport/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | .externalNativeBuild
3 | .cxx
4 |
--------------------------------------------------------------------------------
/serialport/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Sets the minimum version of CMake required to build your native library.
2 | # This ensures that a certain set of CMake features is available to
3 | # your build.
4 |
5 | cmake_minimum_required(VERSION 3.18.1)
6 |
7 | # Specifies a library name, specifies whether the library is STATIC or
8 | # SHARED, and provides relative paths to the source code. You can
9 | # define multiple libraries by adding multiple add.library() commands,
10 | # and CMake builds them for you. When you build your app, Gradle
11 | # automatically packages shared libraries with your APK.
12 |
13 | add_library( # Specifies the name of the library.
14 | serial_port
15 |
16 | # Sets the library as a shared library.
17 | SHARED
18 |
19 | # Provides a relative path to your source file(s).
20 | src/main/cpp/SerialPort.c )
21 |
22 | find_library( # Sets the name of the path variable.
23 | log-lib
24 |
25 | # Specifies the name of the NDK library that
26 | # you want CMake to locate.
27 | log )
28 |
29 | # Specifies libraries CMake should link to your target library. You
30 | # can link multiple libraries, such as libraries you define in this
31 | # build script, prebuilt third-party libraries, or system libraries.
32 |
33 | target_link_libraries( # Specifies the target library.
34 | serial_port
35 |
36 | # Links the target library to the log library
37 | # included in the NDK.
38 | ${log-lib} )
39 |
40 | target_link_options(
41 | serial_port
42 | PRIVATE
43 | "-Wl,-z,max-page-size=16384"
44 | )
--------------------------------------------------------------------------------
/serialport/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 |
4 | android {
5 | compileSdkVersion rootProject.ext.compileSdkVersion
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.ext.minSdkVersion
9 | targetSdkVersion rootProject.ext.targetSdkVersion
10 | versionCode 1
11 | versionName rootProject.ext.versionName
12 |
13 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | externalNativeBuild {
22 | cmake {
23 | path 'CMakeLists.txt'
24 | version "3.18.1"
25 | }
26 | }
27 | packagingOptions {
28 | jniLibs {
29 | useLegacyPackaging true
30 | }
31 | }
32 | }
33 |
34 | dependencies {
35 | // compile fileTree(dir: 'libs', include: ['*.jar'])
36 | // androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
37 | // exclude group: 'com.android.support', module: 'support-annotations'
38 | // })
39 | // compile 'com.android.support:appcompat-v7:25.3.0'
40 | // testCompile 'junit:junit:4.12'
41 |
42 |
43 | api "androidx.annotation:annotation:1.1.0"
44 | }
45 |
46 | apply from: '../maven_publish.gradle'
47 |
48 |
--------------------------------------------------------------------------------
/serialport/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\DevTools\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/serialport/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/serialport/src/main/cpp/SerialPort.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2009-2011 Cedric Priscal
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | #include "SerialPort.h"
26 |
27 | #include "android/log.h"
28 |
29 | static const char *TAG = "serial_port";
30 | #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
31 | #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
32 | #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
33 |
34 | static speed_t getBaudrate(jint baudrate) {
35 | switch (baudrate) {
36 | case 0:
37 | return B0;
38 | case 50:
39 | return B50;
40 | case 75:
41 | return B75;
42 | case 110:
43 | return B110;
44 | case 134:
45 | return B134;
46 | case 150:
47 | return B150;
48 | case 200:
49 | return B200;
50 | case 300:
51 | return B300;
52 | case 600:
53 | return B600;
54 | case 1200:
55 | return B1200;
56 | case 1800:
57 | return B1800;
58 | case 2400:
59 | return B2400;
60 | case 4800:
61 | return B4800;
62 | case 9600:
63 | return B9600;
64 | case 19200:
65 | return B19200;
66 | case 38400:
67 | return B38400;
68 | case 57600:
69 | return B57600;
70 | case 115200:
71 | return B115200;
72 | case 230400:
73 | return B230400;
74 | case 460800:
75 | return B460800;
76 | case 500000:
77 | return B500000;
78 | case 576000:
79 | return B576000;
80 | case 921600:
81 | return B921600;
82 | case 1000000:
83 | return B1000000;
84 | case 1152000:
85 | return B1152000;
86 | case 1500000:
87 | return B1500000;
88 | case 2000000:
89 | return B2000000;
90 | case 2500000:
91 | return B2500000;
92 | case 3000000:
93 | return B3000000;
94 | case 3500000:
95 | return B3500000;
96 | case 4000000:
97 | return B4000000;
98 | default:
99 | return -1;
100 | }
101 | }
102 |
103 | /*
104 | * Class: android_serialport_SerialPort
105 | * Method: open
106 | * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
107 | */
108 | JNIEXPORT jobject JNICALL Java_android_serialport_SerialPort_open
109 | (JNIEnv *env, jobject thiz, jstring path, jint baudrate, jint dataBits, jint parity,
110 | jint stopBits,
111 | jint flags) {
112 |
113 | int fd;
114 | speed_t speed;
115 | jobject mFileDescriptor;
116 |
117 | /* Check arguments */
118 | {
119 | speed = getBaudrate(baudrate);
120 | if (speed == -1) {
121 | /* TODO: throw an exception */
122 | LOGE("Invalid baudrate");
123 | return NULL;
124 | }
125 | }
126 |
127 | /* Opening device */
128 | {
129 | jboolean iscopy;
130 | const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
131 | LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
132 | fd = open(path_utf, O_RDWR | flags);
133 | LOGD("open() fd = %d", fd);
134 | (*env)->ReleaseStringUTFChars(env, path, path_utf);
135 | if (fd == -1) {
136 | /* Throw an exception */
137 | LOGE("Cannot open port");
138 | /* TODO: throw an exception */
139 | return NULL;
140 | }
141 | }
142 |
143 | /* Configure device */
144 | {
145 | struct termios cfg;
146 | LOGD("Configuring serial port");
147 | if (tcgetattr(fd, &cfg)) {
148 | LOGE("tcgetattr() failed");
149 | close(fd);
150 | /* TODO: throw an exception */
151 | return NULL;
152 | }
153 |
154 | cfmakeraw(&cfg);
155 | cfsetispeed(&cfg, speed);
156 | cfsetospeed(&cfg, speed);
157 |
158 |
159 | cfg.c_cflag &= ~CSIZE;
160 | switch (dataBits) {
161 | case 5:
162 | cfg.c_cflag |= CS5; //使用5位数据位
163 | break;
164 | case 6:
165 | cfg.c_cflag |= CS6; //使用6位数据位
166 | break;
167 | case 7:
168 | cfg.c_cflag |= CS7; //使用7位数据位
169 | break;
170 | case 8:
171 | cfg.c_cflag |= CS8; //使用8位数据位
172 | break;
173 | default:
174 | cfg.c_cflag |= CS8;
175 | break;
176 | }
177 |
178 | switch (parity) {
179 | case 0:
180 | cfg.c_cflag &= ~PARENB; //无奇偶校验
181 | break;
182 | case 1:
183 | cfg.c_cflag |= (PARODD | PARENB); //奇校验
184 | break;
185 | case 2:
186 | cfg.c_iflag &= ~(IGNPAR | PARMRK); // 偶校验
187 | cfg.c_iflag |= INPCK;
188 | cfg.c_cflag |= PARENB;
189 | cfg.c_cflag &= ~PARODD;
190 | break;
191 | default:
192 | cfg.c_cflag &= ~PARENB;
193 | break;
194 | }
195 |
196 | switch (stopBits) {
197 | case 1:
198 | cfg.c_cflag &= ~CSTOPB; //1位停止位
199 | break;
200 | case 2:
201 | cfg.c_cflag |= CSTOPB; //2位停止位
202 | break;
203 | default:
204 | cfg.c_cflag &= ~CSTOPB; //1位停止位
205 | break;
206 | }
207 |
208 | if (tcsetattr(fd, TCSANOW, &cfg)) {
209 | LOGE("tcsetattr() failed");
210 | close(fd);
211 | /* TODO: throw an exception */
212 | return NULL;
213 | }
214 | }
215 |
216 | /* Create a corresponding file descriptor */
217 | {
218 | jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
219 | jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V");
220 | jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
221 | mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
222 | (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd);
223 | }
224 |
225 | return mFileDescriptor;
226 | }
227 |
228 | /*
229 | * Class: cedric_serial_SerialPort
230 | * Method: close
231 | * Signature: ()V
232 | */
233 | JNIEXPORT void JNICALL Java_android_serialport_SerialPort_close
234 | (JNIEnv *env, jobject thiz) {
235 | jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
236 | jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");
237 |
238 | jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
239 | jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");
240 |
241 | jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
242 | jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);
243 |
244 | LOGD("close(fd = %d)", descriptor);
245 | close(descriptor);
246 | }
247 |
248 |
--------------------------------------------------------------------------------
/serialport/src/main/cpp/SerialPort.h:
--------------------------------------------------------------------------------
1 | /* DO NOT EDIT THIS FILE - it is machine generated */
2 | #include
3 | /* Header for class android_serialport_SerialPort */
4 |
5 | #ifndef _Included_android_serialport_SerialPort
6 | #define _Included_android_serialport_SerialPort
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 | /*
11 | * Class: android_serialport_SerialPort
12 | * Method: open
13 | * Signature: (Ljava/lang/String;IIIII)Ljava/io/FileDescriptor;
14 | */
15 | JNIEXPORT jobject JNICALL Java_android_serialport_SerialPort_open
16 | (JNIEnv *, jobject, jstring, jint, jint, jint, jint, jint);
17 |
18 | /*
19 | * Class: android_serialport_SerialPort
20 | * Method: close
21 | * Signature: ()V
22 | */
23 | JNIEXPORT void JNICALL Java_android_serialport_SerialPort_close
24 | (JNIEnv *, jobject);
25 |
26 | #ifdef __cplusplus
27 | }
28 | #endif
29 | #endif
30 | /* Header for class android_serialport_SerialPort_Builder */
31 |
32 | #ifndef _Included_android_serialport_SerialPort_Builder
33 | #define _Included_android_serialport_SerialPort_Builder
34 | #ifdef __cplusplus
35 | extern "C" {
36 | #endif
37 | #ifdef __cplusplus
38 | }
39 | #endif
40 | #endif
41 |
--------------------------------------------------------------------------------
/serialport/src/main/cpp/gen_SerialPort_h.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | javah -o SerialPort.h -jni -classpath ../java android.serialport.SerialPort
3 |
4 |
--------------------------------------------------------------------------------
/serialport/src/main/java/android/serialport/SerialPort.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2009 Cedric Priscal
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package android.serialport;
18 |
19 | import android.util.Log;
20 | import androidx.annotation.NonNull;
21 | import androidx.annotation.Nullable;
22 | import java.io.File;
23 | import java.io.FileDescriptor;
24 | import java.io.FileInputStream;
25 | import java.io.FileOutputStream;
26 | import java.io.IOException;
27 | import java.io.InputStream;
28 | import java.io.OutputStream;
29 |
30 | public final class SerialPort {
31 |
32 | private static final String TAG = "SerialPort";
33 |
34 | public static final String DEFAULT_SU_PATH = "/system/bin/su";
35 |
36 | private static String sSuPath = DEFAULT_SU_PATH;
37 | private File device;
38 | private int baudrate;
39 | private int dataBits;
40 | private int parity;
41 | private int stopBits;
42 | private int flags;
43 |
44 | /**
45 | * Set the su binary path, the default su binary path is {@link #DEFAULT_SU_PATH}
46 | *
47 | * @param suPath su binary path
48 | */
49 | public static void setSuPath(@Nullable String suPath) {
50 | if (suPath == null) {
51 | return;
52 | }
53 | sSuPath = suPath;
54 | }
55 |
56 | /**
57 | * Get the su binary path
58 | *
59 | * @return
60 | */
61 | @NonNull
62 | public static String getSuPath() {
63 | return sSuPath;
64 | }
65 |
66 | /*
67 | * Do not remove or rename the field mFd: it is used by native method close();
68 | */
69 | private FileDescriptor mFd;
70 | private FileInputStream mFileInputStream;
71 | private FileOutputStream mFileOutputStream;
72 |
73 | /**
74 | * 串口
75 | *
76 | * @param device 串口设备文件
77 | * @param baudrate 波特率
78 | * @param dataBits 数据位;默认8,可选值为5~8
79 | * @param parity 奇偶校验;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
80 | * @param stopBits 停止位;默认1;1:1位停止位;2:2位停止位
81 | * @param flags 默认0
82 | * @throws SecurityException
83 | * @throws IOException
84 | */
85 | public SerialPort(
86 | @NonNull File device, int baudrate, int dataBits, int parity, int stopBits,
87 | int flags
88 | ) throws SecurityException, IOException {
89 |
90 | this.device = device;
91 | this.baudrate = baudrate;
92 | this.dataBits = dataBits;
93 | this.parity = parity;
94 | this.stopBits = stopBits;
95 | this.flags = flags;
96 |
97 | if (!device.exists()) {
98 | throw new IOException("SerialPort(" + device.getAbsolutePath() + ") not exists");
99 | }
100 |
101 | /* Check access permission */
102 | if (!device.canRead() || !device.canWrite()) {
103 | try {
104 | /* Missing read/write permission, trying to chmod the file */
105 | Process su;
106 | su = Runtime.getRuntime().exec(sSuPath);
107 | String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" + "exit\n";
108 | su.getOutputStream().write(cmd.getBytes());
109 | if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) {
110 | throw new SecurityException();
111 | }
112 | } catch (Exception e) {
113 | e.printStackTrace();
114 | throw new SecurityException();
115 | }
116 | }
117 |
118 | mFd = open(device.getAbsolutePath(), baudrate, dataBits, parity, stopBits, flags);
119 | if (mFd == null) {
120 | Log.e(TAG, "native open returns null");
121 | throw new IOException("native open" +
122 | "SerialPort(" + device.getAbsolutePath()
123 | + ") returns null");
124 | }
125 | mFileInputStream = new FileInputStream(mFd);
126 | mFileOutputStream = new FileOutputStream(mFd);
127 | }
128 |
129 | /**
130 | * 串口,默认的8n1
131 | *
132 | * @param device 串口设备文件
133 | * @param baudrate 波特率
134 | * @throws SecurityException
135 | * @throws IOException
136 | */
137 | public SerialPort(@NonNull File device, int baudrate) throws SecurityException, IOException {
138 | this(device, baudrate, 8, 0, 1, 0);
139 | }
140 |
141 | /**
142 | * 串口
143 | *
144 | * @param device 串口设备文件
145 | * @param baudrate 波特率
146 | * @param dataBits 数据位;默认8,可选值为5~8
147 | * @param parity 奇偶校验;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
148 | * @param stopBits 停止位;默认1;1:1位停止位;2:2位停止位
149 | * @throws SecurityException
150 | * @throws IOException
151 | */
152 | public SerialPort(@NonNull File device, int baudrate, int dataBits, int parity, int stopBits)
153 | throws SecurityException, IOException {
154 | this(device, baudrate, dataBits, parity, stopBits, 0);
155 | }
156 |
157 | // Getters and setters
158 | @NonNull
159 | public InputStream getInputStream() {
160 | return mFileInputStream;
161 | }
162 |
163 | @NonNull
164 | public OutputStream getOutputStream() {
165 | return mFileOutputStream;
166 | }
167 |
168 | /** 串口设备文件 */
169 | @NonNull
170 | public File getDevice() {
171 | return device;
172 | }
173 |
174 | /** 波特率 */
175 | public int getBaudrate() {
176 | return baudrate;
177 | }
178 |
179 | /** 数据位;默认8,可选值为5~8 */
180 | public int getDataBits() {
181 | return dataBits;
182 | }
183 |
184 | /** 奇偶校验;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN) */
185 | public int getParity() {
186 | return parity;
187 | }
188 |
189 | /** 停止位;默认1;1:1位停止位;2:2位停止位 */
190 | public int getStopBits() {
191 | return stopBits;
192 | }
193 |
194 | public int getFlags() {
195 | return flags;
196 | }
197 |
198 | // JNI
199 | private native FileDescriptor open(
200 | String absolutePath, int baudrate, int dataBits, int parity,
201 | int stopBits, int flags
202 | );
203 |
204 | public native void close();
205 |
206 | /** 关闭流和串口,已经try-catch */
207 | public void tryClose() {
208 | try {
209 | mFileInputStream.close();
210 | } catch (IOException e) {
211 | //e.printStackTrace();
212 | }
213 |
214 | try {
215 | mFileOutputStream.close();
216 | } catch (IOException e) {
217 | //e.printStackTrace();
218 | }
219 |
220 | try {
221 | close();
222 | } catch (Exception e) {
223 | //e.printStackTrace();
224 | }
225 | }
226 |
227 | static {
228 | System.loadLibrary("serial_port");
229 | }
230 |
231 | public static Builder newBuilder(File device, int baudrate) {
232 | return new Builder(device, baudrate);
233 | }
234 |
235 | public static Builder newBuilder(String devicePath, int baudrate) {
236 | return new Builder(devicePath, baudrate);
237 | }
238 |
239 | public final static class Builder {
240 |
241 | private File device;
242 | private int baudrate;
243 | private int dataBits = 8;
244 | private int parity = 0;
245 | private int stopBits = 1;
246 | private int flags = 0;
247 |
248 | private Builder(File device, int baudrate) {
249 | this.device = device;
250 | this.baudrate = baudrate;
251 | }
252 |
253 | private Builder(String devicePath, int baudrate) {
254 | this(new File(devicePath), baudrate);
255 | }
256 |
257 | /**
258 | * 数据位
259 | *
260 | * @param dataBits 默认8,可选值为5~8
261 | * @return
262 | */
263 | public Builder dataBits(int dataBits) {
264 | this.dataBits = dataBits;
265 | return this;
266 | }
267 |
268 | /**
269 | * 校验位
270 | *
271 | * @param parity 0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
272 | * @return
273 | */
274 | public Builder parity(int parity) {
275 | this.parity = parity;
276 | return this;
277 | }
278 |
279 | /**
280 | * 停止位
281 | *
282 | * @param stopBits 默认1;1:1位停止位;2:2位停止位
283 | * @return
284 | */
285 | public Builder stopBits(int stopBits) {
286 | this.stopBits = stopBits;
287 | return this;
288 | }
289 |
290 | /**
291 | * 标志
292 | *
293 | * @param flags 默认0
294 | * @return
295 | */
296 | public Builder flags(int flags) {
297 | this.flags = flags;
298 | return this;
299 | }
300 |
301 | /**
302 | * 打开并返回串口
303 | *
304 | * @return
305 | * @throws SecurityException
306 | * @throws IOException
307 | */
308 | public SerialPort build() throws SecurityException, IOException {
309 | return new SerialPort(device, baudrate, dataBits, parity, stopBits, flags);
310 | }
311 | }
312 | }
313 |
--------------------------------------------------------------------------------
/serialport/src/main/java/android/serialport/SerialPortFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2009 Cedric Priscal
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package android.serialport;
18 |
19 | import android.util.Log;
20 | import java.io.File;
21 | import java.io.FileReader;
22 | import java.io.IOException;
23 | import java.io.LineNumberReader;
24 | import java.util.Iterator;
25 | import java.util.Vector;
26 |
27 | public class SerialPortFinder {
28 |
29 | public class Driver {
30 | public Driver(String name, String root) {
31 | mDriverName = name;
32 | mDeviceRoot = root;
33 | }
34 |
35 | private String mDriverName;
36 | private String mDeviceRoot;
37 | Vector mDevices = null;
38 |
39 | public Vector getDevices() {
40 | if (mDevices == null) {
41 | mDevices = new Vector();
42 | File dev = new File("/dev");
43 |
44 | File[] files = dev.listFiles();
45 |
46 | if (files != null) {
47 | int i;
48 | for (i = 0; i < files.length; i++) {
49 | if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {
50 | Log.d(TAG, "Found new device: " + files[i]);
51 | mDevices.add(files[i]);
52 | }
53 | }
54 | }
55 | }
56 | return mDevices;
57 | }
58 |
59 | public String getName() {
60 | return mDriverName;
61 | }
62 | }
63 |
64 | private static final String TAG = "SerialPort";
65 |
66 | private Vector mDrivers = null;
67 |
68 | Vector getDrivers() throws IOException {
69 | if (mDrivers == null) {
70 | mDrivers = new Vector();
71 | LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
72 | String l;
73 | while ((l = r.readLine()) != null) {
74 | // Issue 3:
75 | // Since driver name may contain spaces, we do not extract driver name with split()
76 | String drivername = l.substring(0, 0x15).trim();
77 | String[] w = l.split(" +");
78 | if ((w.length >= 5) && (w[w.length - 1].equals("serial"))) {
79 | Log.d(TAG, "Found new driver " + drivername + " on " + w[w.length - 4]);
80 | mDrivers.add(new Driver(drivername, w[w.length - 4]));
81 | }
82 | }
83 | r.close();
84 | }
85 | return mDrivers;
86 | }
87 |
88 | public String[] getAllDevices() {
89 | Vector devices = new Vector();
90 | // Parse each driver
91 | Iterator itdriv;
92 | try {
93 | itdriv = getDrivers().iterator();
94 | while (itdriv.hasNext()) {
95 | Driver driver = itdriv.next();
96 | Iterator itdev = driver.getDevices().iterator();
97 | while (itdev.hasNext()) {
98 | String device = itdev.next().getName();
99 | String value = String.format("%s (%s)", device, driver.getName());
100 | devices.add(value);
101 | }
102 | }
103 | } catch (IOException e) {
104 | e.printStackTrace();
105 | }
106 | return devices.toArray(new String[devices.size()]);
107 | }
108 |
109 | public String[] getAllDevicesPath() {
110 | Vector devices = new Vector();
111 | // Parse each driver
112 | Iterator itdriv;
113 | try {
114 | itdriv = getDrivers().iterator();
115 | while (itdriv.hasNext()) {
116 | Driver driver = itdriv.next();
117 | Iterator itdev = driver.getDevices().iterator();
118 | while (itdev.hasNext()) {
119 | String device = itdev.next().getAbsolutePath();
120 | devices.add(device);
121 | }
122 | }
123 | } catch (IOException e) {
124 | e.printStackTrace();
125 | }
126 | return devices.toArray(new String[devices.size()]);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/serialport/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SerialPortSource
3 |
4 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':serialport', ':sample'
2 |
--------------------------------------------------------------------------------