├── .gitattributes ├── .github └── workflows │ ├── build_snapshot.yml │ ├── release_to_maven_central.yml │ └── update_docs.yml ├── .gitignore ├── AUTHORS.md ├── COPYING ├── COPYING.LESSER ├── LICENSE-APACHE-2.0 ├── LICENSE-LGPL-3.0 ├── NOTICE ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src ├── external └── android.jar ├── main ├── c │ ├── Posix │ │ ├── Makefile │ │ ├── PosixHelperFunctions.c │ │ ├── PosixHelperFunctions.h │ │ ├── SerialPort_Posix.c │ │ ├── com_fazecast_jSerialComm_SerialPort.h │ │ ├── jni │ │ │ ├── Android.mk │ │ │ └── Application.mk │ │ └── termios2.h │ └── Windows │ │ ├── Makefile │ │ ├── Makefile.native │ │ ├── SerialPort_Windows.c │ │ ├── WindowsHelperFunctions.c │ │ ├── WindowsHelperFunctions.h │ │ ├── ftdi │ │ └── ftd2xx.h │ │ └── win32 │ │ └── jni_md.h ├── java │ └── com │ │ └── fazecast │ │ └── jSerialComm │ │ ├── SerialPort.java │ │ ├── SerialPortDataListener.java │ │ ├── SerialPortDataListenerWithExceptions.java │ │ ├── SerialPortEvent.java │ │ ├── SerialPortIOException.java │ │ ├── SerialPortInvalidPortException.java │ │ ├── SerialPortMessageListener.java │ │ ├── SerialPortMessageListenerWithExceptions.java │ │ ├── SerialPortPacketListener.java │ │ ├── SerialPortThreadFactory.java │ │ ├── SerialPortTimeoutException.java │ │ ├── android │ │ └── AndroidPort.java │ │ └── package-info.java └── resources │ └── Android │ ├── AndroidManifest.xml │ ├── arm64-v8a │ └── libjSerialComm.so │ ├── armeabi-v7a │ └── libjSerialComm.so │ ├── x86 │ └── libjSerialComm.so │ └── x86_64 │ └── libjSerialComm.so ├── moduleInfo └── java │ └── module-info.java └── test ├── c ├── Makefile ├── testEnumeratePosix.c ├── testEnumerateWindows.c ├── testEventsWindows.c ├── testOpenClose.c ├── testPollPosix.c └── testRS485.c └── java └── com └── fazecast └── jSerialComm └── SerialPortTest.java /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/workflows/build_snapshot.yml: -------------------------------------------------------------------------------- 1 | name: Generate Snapshot 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | publishsnapshot: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check out source code 13 | uses: actions/checkout@v4 14 | 15 | - name: Get latest commit SHA 16 | id: gitsha 17 | run: echo "sha=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_OUTPUT 18 | 19 | - name: Get source code version number 20 | id: gitversion 21 | run: echo "version=$(grep -o "versionString = [^, ;]*" src/main/java/com/fazecast/jSerialComm/SerialPort.java | grep -o "\".*\"" | grep -o [^\"].*[^\"])" >> $GITHUB_OUTPUT 22 | 23 | - name: Update library version string 24 | run: | 25 | sed -i "s/versionString = [^, ;]*/versionString = \"${{ steps.gitversion.outputs.version }}-${{ steps.gitsha.outputs.sha }}-SNAPSHOT\"/g" src/main/java/com/fazecast/jSerialComm/SerialPort.java 26 | sed -i "s/nativeLibraryVersion\[\] = [^, ;]*/nativeLibraryVersion\[\] = \"${{ steps.gitversion.outputs.version }}-${{ steps.gitsha.outputs.sha }}-SNAPSHOT\"/g" src/main/c/Posix/SerialPort_Posix.c 27 | sed -i "s/nativeLibraryVersion\[\] = [^, ;]*/nativeLibraryVersion\[\] = \"${{ steps.gitversion.outputs.version }}-${{ steps.gitsha.outputs.sha }}-SNAPSHOT\"/g" src/main/c/Windows/SerialPort_Windows.c 28 | 29 | - name: Build native libraries using Docker toolchain 30 | uses: addnab/docker-run-action@v3 31 | with: 32 | image: fazecast/jserialcomm:builder 33 | options: --user root --privileged --rm -v ${{ github.workspace }}:/home/toolchain/jSerialComm 34 | run: /home/toolchain/compile.sh libs 35 | 36 | - name: Set up Java build environment 37 | uses: actions/setup-java@v4 38 | with: 39 | distribution: 'zulu' 40 | java-version: '11' 41 | 42 | - name: Setup Gradle 43 | uses: gradle/actions/setup-gradle@v3 44 | with: 45 | gradle-version: 8.1.1 46 | 47 | - name: Build SNAPSHOT using Gradle 48 | run: gradle build 49 | env: 50 | LIB_VERSION: ${{ steps.gitversion.outputs.version }}-SNAPSHOT 51 | 52 | - name: Publish SNAPSHOT using Gradle 53 | run: gradle publish 54 | env: 55 | LIB_VERSION: ${{ steps.gitversion.outputs.version }}-SNAPSHOT 56 | MAVEN_USERNAME: ${{ secrets.OSS_SONATYPE_USERNAME }} 57 | MAVEN_PASSWORD: ${{ secrets.OSS_SONATYPE_PASSWORD }} 58 | SIGNING_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} 59 | SIGNING_PASSWORD: ${{ secrets.MAVEN_GPG_PASSPHRASE }} 60 | 61 | - name: Check out Wiki source data 62 | uses: actions/checkout@v4 63 | with: 64 | repository: ${{ github.repository }}.wiki 65 | path: markdown 66 | 67 | - name: Update and publish Wiki SNAPSHOT link 68 | run: | 69 | xmlResult=$(wget -qO- https://oss.sonatype.org/content/repositories/snapshots/com/fazecast/jSerialComm/${{ steps.gitversion.outputs.version }}-SNAPSHOT/maven-metadata.xml) 70 | snapshot=$(echo $xmlResult | grep -o ".*") 71 | timestamp=$(echo $snapshot | grep -o ".*" | grep -o "[0-9][^<]*") 72 | buildNumber=$(echo $snapshot | grep -o ".*" | grep -o "[0-9][^<]*") 73 | cd markdown 74 | sed -i "s@\*\*Snapshot Version\*\*:.*@\*\*Snapshot Version\*\*: \*${{ steps.gitversion.outputs.version }}-SNAPSHOT\* ([[Download JAR file here|https://oss.sonatype.org/content/repositories/snapshots/com/fazecast/jSerialComm/${{ steps.gitversion.outputs.version }}-SNAPSHOT/jSerialComm-${{ steps.gitversion.outputs.version }}-$timestamp-$buildNumber.jar]])@" Home.md 75 | git config --local user.email "action@github.com" 76 | git config --local user.name "GitHub Action" 77 | git add . 78 | git diff-index --quiet HEAD || git commit -m "New SNAPSHOT version" && git push 79 | -------------------------------------------------------------------------------- /.github/workflows/release_to_maven_central.yml: -------------------------------------------------------------------------------- 1 | name: Release to Maven Central 2 | 3 | on: [workflow_dispatch] 4 | 5 | jobs: 6 | buildpublish: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Check out source code 10 | uses: actions/checkout@v4 11 | 12 | - name: Get source code version number 13 | id: gitversion 14 | run: echo "version=$(grep -o "versionString = [^, ;]*" src/main/java/com/fazecast/jSerialComm/SerialPort.java | grep -o "\".*\"" | grep -o [^\"].*[^\"])" >> $GITHUB_OUTPUT 15 | 16 | - name: Update library version string 17 | run: | 18 | sed -i "s/@version .*/@version ${{ steps.gitversion.outputs.version }}/" src/main/java/com/fazecast/jSerialComm/package-info.java 19 | sed -i "s/nativeLibraryVersion\[\] = [^, ;]*/nativeLibraryVersion\[\] = \"${{ steps.gitversion.outputs.version }}\"/g" src/main/c/Posix/SerialPort_Posix.c 20 | sed -i "s/nativeLibraryVersion\[\] = [^, ;]*/nativeLibraryVersion\[\] = \"${{ steps.gitversion.outputs.version }}\"/g" src/main/c/Windows/SerialPort_Windows.c 21 | 22 | - name: Build native libraries using Docker toolchain 23 | uses: addnab/docker-run-action@v3 24 | with: 25 | image: fazecast/jserialcomm:builder 26 | options: --user root --privileged --rm -v ${{ github.workspace }}:/home/toolchain/jSerialComm 27 | run: /home/toolchain/compile.sh libs 28 | 29 | - name: Set up Java build environment 30 | uses: actions/setup-java@v4 31 | with: 32 | distribution: 'zulu' 33 | java-version: '11' 34 | 35 | - name: Setup Gradle 36 | uses: gradle/actions/setup-gradle@v3 37 | with: 38 | gradle-version: 8.1.1 39 | 40 | - name: Build library using Gradle 41 | run: gradle build 42 | env: 43 | LIB_VERSION: ${{ steps.gitversion.outputs.version }} 44 | 45 | - name: Publish library using Gradle 46 | run: gradle publish 47 | env: 48 | LIB_VERSION: ${{ steps.gitversion.outputs.version }} 49 | MAVEN_USERNAME: ${{ secrets.OSS_SONATYPE_USERNAME }} 50 | MAVEN_PASSWORD: ${{ secrets.OSS_SONATYPE_PASSWORD }} 51 | SIGNING_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} 52 | SIGNING_PASSWORD: ${{ secrets.MAVEN_GPG_PASSPHRASE }} 53 | 54 | - name: Generate changelog 55 | id: changelog 56 | uses: metcalfc/changelog-generator@v4.3.1 57 | with: 58 | myToken: ${{ secrets.GRADLE_UPDATE_PAT }} 59 | 60 | - name: Create GitHub release 61 | uses: ncipollo/release-action@v1 62 | with: 63 | token: ${{ secrets.GRADLE_UPDATE_PAT }} 64 | name: "jSerialComm v${{ steps.gitversion.outputs.version }}" 65 | tag: "v${{ steps.gitversion.outputs.version }}" 66 | body: ${{ steps.changelog.outputs.changelog }} 67 | commit: "master" 68 | artifacts: "build/libs/jSerialComm-${{ steps.gitversion.outputs.version }}.jar" 69 | generateReleaseNotes: false 70 | prerelease: false 71 | makeLatest: true 72 | draft: true 73 | 74 | - name: Check out library documentation 75 | uses: actions/checkout@v4 76 | with: 77 | ref: gh-pages 78 | path: documentation 79 | 80 | - name: Update Javadoc library documentation 81 | run: rm -rf documentation/binaries/* documentation/javadoc && mv build/docs/javadoc documentation/ && sed -i "s@content/com/fazecast/jSerialComm/[^\"]*@content/com/fazecast/jSerialComm/${{ steps.gitversion.outputs.version }}/jSerialComm-${{ steps.gitversion.outputs.version }}.jar@g" documentation/index.html 82 | 83 | - name: Publish new library documentation 84 | uses: s0/git-publish-subdir-action@develop 85 | env: 86 | REPO: self 87 | BRANCH: gh-pages 88 | FOLDER: documentation 89 | GITHUB_TOKEN: ${{ secrets.GRADLE_UPDATE_PAT }} 90 | MESSAGE: "Updated docs to v${{ steps.gitversion.outputs.version }}" 91 | 92 | - name: Check out Wiki source data 93 | uses: actions/checkout@v4 94 | with: 95 | repository: ${{ github.repository }}.wiki 96 | path: markdown 97 | 98 | - name: Update and publish Wiki release link 99 | run: | 100 | cd markdown 101 | sed -i "s@\*\*Current Version\*\*:.*@\*\*Current Version\*\*: \*${{ steps.gitversion.outputs.version }}\* ([[Download JAR file here|https://oss.sonatype.org/service/local/repositories/releases/content/com/fazecast/jSerialComm/${{ steps.gitversion.outputs.version }}/jSerialComm-${{ steps.gitversion.outputs.version }}.jar]])@" Home.md 102 | git config --local user.email "action@github.com" 103 | git config --local user.name "GitHub Action" 104 | git add . 105 | git diff-index --quiet HEAD || git commit -m "New jSerialComm release version" && git push 106 | -------------------------------------------------------------------------------- /.github/workflows/update_docs.yml: -------------------------------------------------------------------------------- 1 | name: Update Documentation 2 | 3 | on: [workflow_dispatch] 4 | 5 | jobs: 6 | update: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Check out source code 10 | uses: actions/checkout@v4 11 | 12 | - name: Get source code version number 13 | id: gitversion 14 | run: echo "version=$(grep -o "versionString = [^, ;]*" src/main/java/com/fazecast/jSerialComm/SerialPort.java | grep -o "\".*\"" | grep -o [^\"].*[^\"])" >> $GITHUB_OUTPUT 15 | 16 | - name: Set up Java build environment 17 | uses: actions/setup-java@v4 18 | with: 19 | distribution: 'zulu' 20 | java-version: '11' 21 | 22 | - name: Setup Gradle 23 | uses: gradle/actions/setup-gradle@v3 24 | with: 25 | gradle-version: 8.1.1 26 | 27 | - name: Build library using Gradle 28 | run: gradle build 29 | env: 30 | LIB_VERSION: ${{ steps.gitversion.outputs.version }} 31 | 32 | - name: Check out library documentation 33 | uses: actions/checkout@v4 34 | with: 35 | ref: gh-pages 36 | path: documentation 37 | 38 | - name: Update Javadoc library documentation 39 | run: rm -rf documentation/binaries/* documentation/javadoc && mv build/docs/javadoc documentation/ && sed -i "s@content/com/fazecast/jSerialComm/[^\"]*@content/com/fazecast/jSerialComm/${{ steps.gitversion.outputs.version }}/jSerialComm-${{ steps.gitversion.outputs.version }}.jar@g" documentation/index.html 40 | 41 | - name: Publish new library documentation 42 | uses: s0/git-publish-subdir-action@develop 43 | env: 44 | REPO: self 45 | BRANCH: gh-pages 46 | FOLDER: documentation 47 | GITHUB_TOKEN: ${{ secrets.GRADLE_UPDATE_PAT }} 48 | MESSAGE: "Updated docs to v${{ steps.gitversion.outputs.version }}" 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | bin 3 | site 4 | build 5 | toolchain 6 | 7 | # Generated files for JNI 8 | src/main/c/com_fazecast_jSerialComm_SerialPort.h 9 | 10 | # Binary Library Files # 11 | src/main/resources 12 | 13 | # Mobile Tools for Java (J2ME) 14 | .mtj.tmp/ 15 | 16 | # Package Files # 17 | *.jar 18 | *.war 19 | *.ear 20 | 21 | # Allow Android JAR 22 | !android.jar 23 | 24 | # Allow Gradle Wrapper Files 25 | !gradle-wrapper.jar 26 | 27 | # Gradle Files # 28 | .gradle 29 | gradle.properties 30 | build.gradle.private 31 | build.gradle.private.android 32 | 33 | # Eclipse Files # 34 | .settings 35 | .project 36 | .cproject 37 | .classpath 38 | 39 | # IntelliJ IDEA Files # 40 | .idea 41 | *.iml 42 | 43 | # MacOS Files # 44 | .DS_Store 45 | 46 | # Visual Studio Code Files # 47 | .vscode 48 | 49 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 50 | hs_err_pid* 51 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # Maintainer 2 | 3 | Will Hedgecock 4 | 5 | # Original Authors 6 | 7 | Will Hedgecock 8 | 9 | # Contributors 10 | 11 | * Will Hedgecock 12 | * Frederik Schubert 13 | * Farrell Farahbod 14 | * Michael Kaesbauer 15 | * Josh Lubawy 16 | * Fede Claramonte 17 | * Lukas Jane 18 | * Kevin Herron 19 | * Sean Wilson 20 | * Amit Kumar Mondal 21 | * Oliver Treichel 22 | * Steve Perkins 23 | * Ingo Wassink 24 | * Naresh Goyal 25 | * Syed Seth 26 | -------------------------------------------------------------------------------- /COPYING.LESSER: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /LICENSE-APACHE-2.0: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSE-LGPL-3.0: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Fazecast jSerialComm 2 | Copyright (C) 2012-2022 Fazecast, Inc. 3 | 4 | This product includes software developed at Fazecast, Inc: you can 5 | redistribute it and/or modify it under the terms of either the Apache 6 | Software License, version 2, or the GNU Lesser General Public License 7 | as published by the Free Software Foundation, version 3 or above. 8 | 9 | jSerialComm is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 11 | or FITNESS FOR A PARTICULAR PURPOSE. 12 | 13 | You should have received a copy of both the GNU Lesser General Public 14 | License and the Apache Software License along with jSerialComm. If not, 15 | see and . 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jSerialComm 2 | 3 | _A platform-independent serial port access library for Java._ 4 | 5 | 6 | ## Usage 7 | 8 | For usage examples, please refer to the [Usage wiki](https://github.com/Fazecast/jSerialComm/wiki/Usage-Examples). 9 | 10 | If you intend to use the library in multiple applications simultaneously, you may need 11 | to set the ```fazecast.jSerialComm.appid``` property before accessing the SerialPort class 12 | so that applications don't accidentally delete each others' temporary files during boot-up 13 | (**this should almost never be necessary**): 14 | 15 | ``` 16 | System.setProperty("fazecast.jSerialComm.appid", "YOUR_APPLICATION_IDENTIFIER") 17 | ``` 18 | 19 | Alternately, if you plan to use the library within an Apache Tomcat application, please set 20 | the ```jSerialComm.library.randomizeNativeName``` property to true before accessing the 21 | SerialPort class to address an issue whereby the Tomcat bootloader tries to reinitialize 22 | the library multiple times. This can either be done using ```-DjSerialComm.library.randomizeNativeName="true"``` 23 | as a command line parameter or by calling the following within your own application before 24 | using any SerialPort functionality: 25 | 26 | ``` 27 | System.setProperty("jSerialComm.library.randomizeNativeName", "true") 28 | ``` 29 | 30 | In order to use the ```jSerialComm``` library in your own project, you must simply 31 | include the JAR file in your build path and import it like any other 32 | Java package using ```import com.fazecast.jSerialComm.*;```. 33 | 34 | Alternately, you can automatically add ```jSerialComm``` to your project as a 35 | dependency from the ```Maven Central Repository```. Use the following dependency 36 | declaration depending on your build system: 37 | 38 | * Maven: 39 | 40 | ``` 41 | 42 | com.fazecast 43 | jSerialComm 44 | [2.0.0,3.0.0) 45 | 46 | ``` 47 | 48 | * Ivy: 49 | 50 | ``` 51 | 52 | ``` 53 | 54 | * Groovy: 55 | 56 | ``` 57 | @Grab(group='com.fazecast', module='jSerialComm', version='[2.0.0,3.0.0)') 58 | ``` 59 | 60 | * Gradle: 61 | 62 | ``` 63 | compile 'com.fazecast:jSerialComm:[2.0.0,3.0.0)' 64 | ``` 65 | 66 | * Gradle (.kts): 67 | 68 | ``` 69 | compile("com.fazecast:jSerialComm:[2.0.0,3.0.0)") 70 | ``` 71 | 72 | * Buildr: 73 | 74 | ``` 75 | compile.with 'com.fazecast:jSerialComm:jar:[2.0.0,3.0.0)' 76 | ``` 77 | 78 | * Scala/SBT: 79 | 80 | ``` 81 | libraryDependencies += "com.fazecast" % "jSerialComm" % "[2.0.0,3.0.0)" 82 | ``` 83 | 84 | * Leiningen: 85 | 86 | ``` 87 | [com.fazecast/jSerialComm "[2.0.0,3.0.0)"] 88 | ``` 89 | 90 | Finally, if you are working on a device that provides no other means of allowing temporary native files to run, jSerialComm supports loading a pre-extracted version of its native library from a user-defined location using the startup flag: `-DjSerialComm.library.path=""`, where `LIB_PATH` can either be a directory containing the single native jSerialComm library for your correct architecture or the entire extracted arch-specific directory structure from inside the jSerialComm JAR file; however, this should be used as a last resort as it makes versioning and upgrading much more difficult and error-prone. 91 | 92 | 93 | ## Troubleshooting 94 | 95 | If you are using Linux and this library does not appear to be working, ensure 96 | that you have the correct permissions set to access the serial port on your system. 97 | One way to test this is to run your application as root or by using the 98 | ```sudo``` command. If everything works, you will need to either run your 99 | application as ```root``` in the future or fix the permissions on your system. 100 | For further instructions, refer to the [Troubleshooting wiki](https://github.com/Fazecast/jSerialComm/wiki/Troubleshooting). 101 | 102 | On some very few systems which use custom ARM-based CPUs and/or have extremely 103 | restrictive permissions, the library may be unable to determine that the 104 | underlying system architecture is ARM. In this case, you can force the 105 | library to disable its auto-detect functionality and instead directly specify 106 | the architecture using the Java ```os.arch_full``` system property. Acceptable 107 | values for this property are currently one of: ``armv5``, ``armv6``, ``armv7``, 108 | ``armv8_32``, ``armv8_64``, ``ppc64le``, ``x86``, or ``x86_64``. 109 | 110 | Additionally, some systems may block execution of libraries from the system 111 | temp folder. If you are experiencing this problem, you can specify a different, 112 | less restrictive temp folder by adding 113 | ```System.setProperty("java.io.tmpdir", "/folder/where/execution/is/allowed")``` 114 | to your program before the first use of this library. When doing this, make sure 115 | that the folder you specify already exists and has the correct permissions set 116 | to allow execution of a shared library. 117 | 118 | Optionally, the same result can be achieved by running your Java application 119 | from the command line and specifying the `java.io.tmpdir` directory as an 120 | additional parameter, 121 | e.g.: ```java -Djava.io.tmpdir=/folder/of/your/choice -jar yourApplication.jar``` 122 | 123 | On Windows, you may be able to achieve the same result by setting the TMP 124 | environment variable (either through the Settings->System Properties->Environment 125 | Variables GUI or via ```SET TMP=C:\Desired\Tmp\Folder``` in a command terminal), 126 | although setting this variable through Java is preferable when possible. 127 | 128 | An additional note for Linux users: If you are operating this library in 129 | event-based mode, the ```LISTENING_EVENT_DATA_WRITTEN``` event will never occur. 130 | This is not a bug, but rather a limitation of the Linux operating system. 131 | 132 | For other troubleshooting issues, please see if you can find an answer in either 133 | the [Usage-Examples wiki](https://github.com/Fazecast/jSerialComm/wiki/Usage-Examples) 134 | or the [Troubleshooting Wiki](https://github.com/Fazecast/jSerialComm/wiki/Troubleshooting). 135 | 136 | If your question is still not answered, feel free to open an issue report on 137 | this project's [GitHub page](https://github.com/Fazecast/jSerialComm/issues), 138 | and we will be glad to look into it. 139 | 140 | 141 | ## Building 142 | 143 | Building this library yourself is not advised (at least not for distribution) 144 | since it requires native compilation across multiple platforms. It is 145 | recommended to simply use the pre-built ```jSerialComm``` library in your 146 | application. For installation/usage instructions, please skip to the [usage](#usage) 147 | section. 148 | 149 | If you do choose to build this library from source, please follow the instructions 150 | in the [Building Tutorial](https://github.com/Fazecast/jSerialComm/wiki/Building-Tutorial) 151 | to set up the required toolchains. 152 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | gradlePluginPortal() 5 | } 6 | } 7 | 8 | plugins { 9 | id 'maven-publish' 10 | id 'biz.aQute.bnd.builder' version '6.0.0' 11 | id 'signing' 12 | } 13 | 14 | dependencies { 15 | compileOnly fileTree(dir: 'src/external', include: ['android*.jar']) 16 | } 17 | 18 | group = 'com.fazecast' 19 | archivesBaseName = 'jSerialComm' 20 | version = System.getenv("LIB_VERSION") ?: '2.11.1' 21 | ext.moduleName = 'com.fazecast.jSerialComm' 22 | 23 | sourceCompatibility = 6 24 | targetCompatibility = 6 25 | 26 | javadoc { 27 | title archivesBaseName + ' ' + version + ' API' 28 | options { 29 | links 'https://docs.oracle.com/en/java/javase/12/docs/api/' 30 | } 31 | } 32 | 33 | sourceSets { 34 | main { 35 | java { 36 | srcDirs = ['src/main/java'] 37 | } 38 | } 39 | moduleInfo { 40 | java { 41 | srcDirs = ['src/moduleInfo/java'] 42 | } 43 | } 44 | } 45 | 46 | compileModuleInfoJava { 47 | sourceCompatibility = 9 48 | targetCompatibility = 9 49 | inputs.property("moduleName", moduleName) 50 | 51 | doFirst { 52 | classpath = files() 53 | options.sourcepath = files(sourceSets.moduleInfo.java.srcDirs) 54 | options.compilerArgs = [ 55 | '--module-path', classpath.asPath, 56 | '-d', sourceSets.main.output.classesDirs.asPath 57 | ] 58 | } 59 | } 60 | 61 | jar { 62 | from sourceSets.main.output 63 | from sourceSets.moduleInfo.output 64 | 65 | bnd ( 66 | '-exportcontents': 'com.fazecast.jSerialComm;version="' + archiveVersion.get() + '"', 67 | 'Import-Package': '!android.*', 68 | 'Bundle-Name': 'jSerialComm', 69 | 'Bundle-SymbolicName': 'com.fazecast.jSerialComm', 70 | 'Bundle-Description': 'Java Serial Communications Library', 71 | 'Bundle-Vendor': 'Fazecast, Inc.', 72 | 'Require-Capability': 'osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.6))"', 73 | 'Implementation-Title': 'jSerialComm: Java Serial Communications Library', 74 | 'Implementation-Version': archiveVersion.get(), 75 | 'Implementation-Vendor': 'Fazecast, Inc.', 76 | 'Sealed': 'true' 77 | ) 78 | } 79 | 80 | tasks.withType(JavaCompile) { 81 | options.compilerArgs.add('-Xlint:-options') 82 | } 83 | 84 | task testJar(type: Jar) { 85 | archiveClassifier = 'test' 86 | from sourceSets.test.output, sourceSets.main.output 87 | 88 | manifest { 89 | attributes 'Main-Class': 'com.fazecast.jSerialComm.SerialPortTest', 90 | 'Implementation-Title': 'jSerialComm: Java Serial Communications Library', 91 | 'Implementation-Version': archiveVersion.get(), 92 | 'Implementation-Vendor': 'Fazecast, Inc.', 93 | 'Sealed': 'true' 94 | } 95 | } 96 | 97 | task javadocJar(type: Jar) { 98 | archiveClassifier = 'javadoc' 99 | from javadoc 100 | } 101 | 102 | task sourcesJar(type: Jar) { 103 | archiveClassifier = 'sources' 104 | from sourceSets.main.allSource 105 | } 106 | 107 | artifacts { 108 | archives jar, javadocJar, sourcesJar, testJar 109 | } 110 | 111 | java { 112 | withJavadocJar() 113 | withSourcesJar() 114 | } 115 | 116 | publishing { 117 | publications { 118 | maven(MavenPublication) { 119 | groupId = group 120 | artifactId = archivesBaseName 121 | version = version 122 | from components.java 123 | 124 | versionMapping { 125 | usage('java-api') { 126 | fromResolutionOf('runtimeClasspath') 127 | } 128 | usage('java-runtime') { 129 | fromResolutionResult() 130 | } 131 | } 132 | 133 | pom { 134 | name = 'jSerialComm' 135 | description = 'A platform-independent serial communications library for Java.' 136 | url = 'http://fazecast.github.io/jSerialComm/' 137 | 138 | scm { 139 | connection = 'scm:git:https://github.com/Fazecast/jSerialComm.git' 140 | developerConnection = 'scm:git:https://github.com/Fazecast/jSerialComm.git' 141 | url = 'https://github.com/Fazecast/jSerialComm' 142 | } 143 | 144 | licenses { 145 | license { 146 | name = 'GNU Lesser GPL, Version 3' 147 | url = 'http://www.gnu.org/licenses/lgpl.html' 148 | } 149 | license { 150 | name = 'Apache Software License, Version 2.0' 151 | url = 'http://www.apache.org/licenses/LICENSE-2.0' 152 | } 153 | } 154 | 155 | developers { 156 | developer { 157 | id = 'hedgecrw' 158 | name = 'Will Hedgecock' 159 | email = 'will.hedgecock@fazecast.com' 160 | } 161 | } 162 | } 163 | } 164 | } 165 | 166 | repositories { 167 | maven { 168 | name = "OSSRH" 169 | def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 170 | def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" 171 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl 172 | credentials { 173 | username = project.findProperty("ossrhUsername") ?: System.getenv("MAVEN_USERNAME") 174 | password = project.findProperty("ossrhPassword") ?: System.getenv("MAVEN_PASSWORD") 175 | } 176 | } 177 | } 178 | } 179 | 180 | signing { 181 | def signingKey = System.getenv("SIGNING_KEY") 182 | def signingPassword = System.getenv("SIGNING_PASSWORD") 183 | if (signingKey && signingPassword) 184 | useInMemoryPgpKeys(signingKey, signingPassword) 185 | sign publishing.publications.maven 186 | } 187 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fazecast/jSerialComm/a8a307deed68bca2dda3048c1ecc5481eb5783fb/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip 5 | networkTimeout=10000 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original 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 | # https://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 POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 134 | 135 | Please set the JAVA_HOME variable in your environment to match the 136 | location of your Java installation." 137 | fi 138 | 139 | # Increase the maximum file descriptors if we can. 140 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 141 | case $MAX_FD in #( 142 | max*) 143 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 144 | # shellcheck disable=SC3045 145 | MAX_FD=$( ulimit -H -n ) || 146 | warn "Could not query maximum file descriptor limit" 147 | esac 148 | case $MAX_FD in #( 149 | '' | soft) :;; #( 150 | *) 151 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 152 | # shellcheck disable=SC3045 153 | ulimit -n "$MAX_FD" || 154 | warn "Could not set maximum file descriptor limit to $MAX_FD" 155 | esac 156 | fi 157 | 158 | # Collect all arguments for the java command, stacking in reverse order: 159 | # * args from the command line 160 | # * the main class name 161 | # * -classpath 162 | # * -D...appname settings 163 | # * --module-path (only if needed) 164 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 165 | 166 | # For Cygwin or MSYS, switch paths to Windows format before running java 167 | if "$cygwin" || "$msys" ; then 168 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 169 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 170 | 171 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 172 | 173 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 174 | for arg do 175 | if 176 | case $arg in #( 177 | -*) false ;; # don't mess with options #( 178 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 179 | [ -e "$t" ] ;; #( 180 | *) false ;; 181 | esac 182 | then 183 | arg=$( cygpath --path --ignore --mixed "$arg" ) 184 | fi 185 | # Roll the args list around exactly as many times as the number of 186 | # args, so each arg winds up back in the position where it started, but 187 | # possibly modified. 188 | # 189 | # NB: a `for` loop captures its iteration list before it begins, so 190 | # changing the positional parameters here affects neither the number of 191 | # iterations, nor the values presented in `arg`. 192 | shift # remove old arg 193 | set -- "$@" "$arg" # push replacement arg 194 | done 195 | fi 196 | 197 | 198 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 199 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 200 | 201 | # Collect all arguments for the java command; 202 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 203 | # shell script including quotes and variable substitutions, so put them in 204 | # double quotes to make sure that they get re-expanded; and 205 | # * put everything else in single quotes, so that it's not re-expanded. 206 | 207 | set -- \ 208 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 209 | -classpath "$CLASSPATH" \ 210 | org.gradle.wrapper.GradleWrapperMain \ 211 | "$@" 212 | 213 | # Stop when "xargs" is not available. 214 | if ! command -v xargs >/dev/null 2>&1 215 | then 216 | die "xargs is not available" 217 | fi 218 | 219 | # Use "xargs" to parse quoted args. 220 | # 221 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 222 | # 223 | # In Bash we could simply go: 224 | # 225 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 226 | # set -- "${ARGS[@]}" "$@" 227 | # 228 | # but POSIX shell has neither arrays nor command substitution, so instead we 229 | # post-process each arg (as a line of input to sed) to backslash-escape any 230 | # character that might be a shell metacharacter, then use eval to reverse 231 | # that process (while maintaining the separation between arguments), and wrap 232 | # the whole thing up as a single "set" statement. 233 | # 234 | # This will of course break if any of these variables contains a newline or 235 | # an unmatched quote. 236 | # 237 | 238 | eval "set -- $( 239 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 240 | xargs -n1 | 241 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 242 | tr '\n' ' ' 243 | )" '"$@"' 244 | 245 | exec "$JAVACMD" "$@" 246 | -------------------------------------------------------------------------------- /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 https://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 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 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 %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 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 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /src/external/android.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fazecast/jSerialComm/a8a307deed68bca2dda3048c1ecc5481eb5783fb/src/external/android.jar -------------------------------------------------------------------------------- /src/main/c/Posix/PosixHelperFunctions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PosixHelperFunctions.h 3 | * 4 | * Created on: Mar 10, 2015 5 | * Last Updated on: Apr 10, 2024 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2024 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | #ifndef __POSIX_HELPER_FUNCTIONS_HEADER_H__ 27 | #define __POSIX_HELPER_FUNCTIONS_HEADER_H__ 28 | 29 | // Serial port JNI header file 30 | #include 31 | #include 32 | #include "com_fazecast_jSerialComm_SerialPort.h" 33 | 34 | // Serial port data structure 35 | typedef struct serialPort 36 | { 37 | pthread_mutex_t eventMutex; 38 | pthread_cond_t eventReceived; 39 | pthread_t eventsThread1, eventsThread2; 40 | char *portPath, *friendlyName, *portDescription, *portLocation, *serialNumber, *manufacturer; 41 | int errorLineNumber, errorNumber, handle, eventsMask, event, vendorID, productID; 42 | volatile char enumerated, eventListenerRunning, eventListenerUsesThreads; 43 | } serialPort; 44 | 45 | // Common port storage functionality 46 | typedef struct serialPortVector 47 | { 48 | serialPort **ports; 49 | int length, capacity; 50 | } serialPortVector; 51 | serialPort* pushBack(serialPortVector* vector, const char* key, const char* friendlyName, const char* description, const char* location, const char* serialNumber, const char* manufacturer, int vid, int pid); 52 | serialPort* fetchPort(serialPortVector* vector, const char* key); 53 | void removePort(serialPortVector* vector, serialPort* port); 54 | void cleanUpVector(serialPortVector* vector); 55 | 56 | // Forced definitions 57 | #ifndef CMSPAR 58 | #define CMSPAR 010000000000 59 | #endif 60 | #ifndef O_CLOEXEC 61 | #define O_CLOEXEC 0 62 | #endif 63 | 64 | // Linux-specific functionality 65 | #if defined(__linux__) 66 | 67 | typedef int baud_rate; 68 | 69 | #ifdef __ANDROID__ 70 | extern int ioctl(int __fd, int __request, ...); 71 | #else 72 | extern int ioctl(int __fd, unsigned long int __request, ...); 73 | #endif 74 | 75 | 76 | // Solaris-specific functionality 77 | #elif defined(__sun__) 78 | 79 | #define faccessat(dirfd, pathname, mode, flags) access(pathname, mode) 80 | 81 | #define LOCK_SH 1 82 | #define LOCK_EX 2 83 | #define LOCK_NB 4 84 | #define LOCK_UN 8 85 | typedef int baud_rate; 86 | 87 | extern int ioctl(int __fd, int __request, ...); 88 | int flock(int fd, int op); 89 | 90 | 91 | // FreeBSD-specific functionality 92 | #elif defined(__FreeBSD__) || defined(__OpenBSD__) 93 | 94 | typedef int baud_rate; 95 | 96 | 97 | // Apple-specific functionality 98 | #elif defined(__APPLE__) 99 | 100 | #define fdatasync fsync 101 | 102 | typedef speed_t baud_rate; 103 | 104 | #endif 105 | 106 | 107 | // Common Posix functionality 108 | void searchForComPorts(serialPortVector* comPorts); 109 | int setConfigOptions(int portFD, baud_rate baudRate, struct termios *options); 110 | int verifyAndSetUserPortGroup(const char *portFile); 111 | 112 | #endif // #ifndef __POSIX_HELPER_FUNCTIONS_HEADER_H__ 113 | -------------------------------------------------------------------------------- /src/main/c/Posix/com_fazecast_jSerialComm_SerialPort.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_fazecast_jSerialComm_SerialPort */ 4 | 5 | #ifndef _Included_com_fazecast_jSerialComm_SerialPort 6 | #define _Included_com_fazecast_jSerialComm_SerialPort 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | #undef com_fazecast_jSerialComm_SerialPort_NO_PARITY 11 | #define com_fazecast_jSerialComm_SerialPort_NO_PARITY 0L 12 | #undef com_fazecast_jSerialComm_SerialPort_ODD_PARITY 13 | #define com_fazecast_jSerialComm_SerialPort_ODD_PARITY 1L 14 | #undef com_fazecast_jSerialComm_SerialPort_EVEN_PARITY 15 | #define com_fazecast_jSerialComm_SerialPort_EVEN_PARITY 2L 16 | #undef com_fazecast_jSerialComm_SerialPort_MARK_PARITY 17 | #define com_fazecast_jSerialComm_SerialPort_MARK_PARITY 3L 18 | #undef com_fazecast_jSerialComm_SerialPort_SPACE_PARITY 19 | #define com_fazecast_jSerialComm_SerialPort_SPACE_PARITY 4L 20 | #undef com_fazecast_jSerialComm_SerialPort_ONE_STOP_BIT 21 | #define com_fazecast_jSerialComm_SerialPort_ONE_STOP_BIT 1L 22 | #undef com_fazecast_jSerialComm_SerialPort_ONE_POINT_FIVE_STOP_BITS 23 | #define com_fazecast_jSerialComm_SerialPort_ONE_POINT_FIVE_STOP_BITS 2L 24 | #undef com_fazecast_jSerialComm_SerialPort_TWO_STOP_BITS 25 | #define com_fazecast_jSerialComm_SerialPort_TWO_STOP_BITS 3L 26 | #undef com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DISABLED 27 | #define com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DISABLED 0L 28 | #undef com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED 29 | #define com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED 1L 30 | #undef com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_CTS_ENABLED 31 | #define com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_CTS_ENABLED 16L 32 | #undef com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DSR_ENABLED 33 | #define com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DSR_ENABLED 256L 34 | #undef com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DTR_ENABLED 35 | #define com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_DTR_ENABLED 4096L 36 | #undef com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_IN_ENABLED 37 | #define com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_IN_ENABLED 65536L 38 | #undef com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED 39 | #define com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED 1048576L 40 | #undef com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING 41 | #define com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING 0L 42 | #undef com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING 43 | #define com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING 1L 44 | #undef com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING 45 | #define com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING 16L 46 | #undef com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING 47 | #define com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING 256L 48 | #undef com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER 49 | #define com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER 4096L 50 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_TIMED_OUT 51 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_TIMED_OUT 0L 52 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE 53 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE 1L 54 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED 55 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED 16L 56 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN 57 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN 256L 58 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT 59 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT 65536L 60 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CARRIER_DETECT 61 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CARRIER_DETECT 131072L 62 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CTS 63 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CTS 262144L 64 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DSR 65 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DSR 524288L 66 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_RING_INDICATOR 67 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_RING_INDICATOR 1048576L 68 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_FRAMING_ERROR 69 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_FRAMING_ERROR 2097152L 70 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR 71 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR 4194304L 72 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR 73 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR 8388608L 74 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PARITY_ERROR 75 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PARITY_ERROR 16777216L 76 | #undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED 77 | #define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED 268435456L 78 | /* 79 | * Class: com_fazecast_jSerialComm_SerialPort 80 | * Method: uninitializeLibrary 81 | * Signature: ()V 82 | */ 83 | JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibrary 84 | (JNIEnv *, jclass); 85 | 86 | /* 87 | * Class: com_fazecast_jSerialComm_SerialPort 88 | * Method: getCommPortsNative 89 | * Signature: ()[Lcom/fazecast/jSerialComm/SerialPort; 90 | */ 91 | JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPortsNative 92 | (JNIEnv *, jclass); 93 | 94 | /* 95 | * Class: com_fazecast_jSerialComm_SerialPort 96 | * Method: getNativeLibraryVersion 97 | * Signature: ()Ljava/lang/String; 98 | */ 99 | JNIEXPORT jstring JNICALL Java_com_fazecast_jSerialComm_SerialPort_getNativeLibraryVersion 100 | (JNIEnv *, jclass); 101 | 102 | /* 103 | * Class: com_fazecast_jSerialComm_SerialPort 104 | * Method: retrievePortDetails 105 | * Signature: ()V 106 | */ 107 | JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_retrievePortDetails 108 | (JNIEnv *, jobject); 109 | 110 | /* 111 | * Class: com_fazecast_jSerialComm_SerialPort 112 | * Method: openPortNative 113 | * Signature: ()J 114 | */ 115 | JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative 116 | (JNIEnv *, jobject); 117 | 118 | /* 119 | * Class: com_fazecast_jSerialComm_SerialPort 120 | * Method: closePortNative 121 | * Signature: (J)J 122 | */ 123 | JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNative 124 | (JNIEnv *, jobject, jlong); 125 | 126 | /* 127 | * Class: com_fazecast_jSerialComm_SerialPort 128 | * Method: configPort 129 | * Signature: (J)Z 130 | */ 131 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort 132 | (JNIEnv *, jobject, jlong); 133 | 134 | /* 135 | * Class: com_fazecast_jSerialComm_SerialPort 136 | * Method: flushRxTxBuffers 137 | * Signature: (J)Z 138 | */ 139 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_flushRxTxBuffers 140 | (JNIEnv *, jobject, jlong); 141 | 142 | /* 143 | * Class: com_fazecast_jSerialComm_SerialPort 144 | * Method: waitForEvent 145 | * Signature: (J)I 146 | */ 147 | JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent 148 | (JNIEnv *, jobject, jlong); 149 | 150 | /* 151 | * Class: com_fazecast_jSerialComm_SerialPort 152 | * Method: bytesAvailable 153 | * Signature: (J)I 154 | */ 155 | JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAvailable 156 | (JNIEnv *, jobject, jlong); 157 | 158 | /* 159 | * Class: com_fazecast_jSerialComm_SerialPort 160 | * Method: bytesAwaitingWrite 161 | * Signature: (J)I 162 | */ 163 | JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAwaitingWrite 164 | (JNIEnv *, jobject, jlong); 165 | 166 | /* 167 | * Class: com_fazecast_jSerialComm_SerialPort 168 | * Method: readBytes 169 | * Signature: (J[BIIII)I 170 | */ 171 | JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes 172 | (JNIEnv *, jobject, jlong, jbyteArray, jint, jint, jint, jint); 173 | 174 | /* 175 | * Class: com_fazecast_jSerialComm_SerialPort 176 | * Method: writeBytes 177 | * Signature: (J[BIII)I 178 | */ 179 | JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes 180 | (JNIEnv *, jobject, jlong, jbyteArray, jint, jint, jint); 181 | 182 | /* 183 | * Class: com_fazecast_jSerialComm_SerialPort 184 | * Method: setEventListeningStatus 185 | * Signature: (JZ)V 186 | */ 187 | JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_setEventListeningStatus 188 | (JNIEnv *, jobject, jlong, jboolean); 189 | 190 | /* 191 | * Class: com_fazecast_jSerialComm_SerialPort 192 | * Method: setBreak 193 | * Signature: (J)Z 194 | */ 195 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setBreak 196 | (JNIEnv *, jobject, jlong); 197 | 198 | /* 199 | * Class: com_fazecast_jSerialComm_SerialPort 200 | * Method: clearBreak 201 | * Signature: (J)Z 202 | */ 203 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearBreak 204 | (JNIEnv *, jobject, jlong); 205 | 206 | /* 207 | * Class: com_fazecast_jSerialComm_SerialPort 208 | * Method: setRTS 209 | * Signature: (J)Z 210 | */ 211 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setRTS 212 | (JNIEnv *, jobject, jlong); 213 | 214 | /* 215 | * Class: com_fazecast_jSerialComm_SerialPort 216 | * Method: clearRTS 217 | * Signature: (J)Z 218 | */ 219 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearRTS 220 | (JNIEnv *, jobject, jlong); 221 | 222 | /* 223 | * Class: com_fazecast_jSerialComm_SerialPort 224 | * Method: setDTR 225 | * Signature: (J)Z 226 | */ 227 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setDTR 228 | (JNIEnv *, jobject, jlong); 229 | 230 | /* 231 | * Class: com_fazecast_jSerialComm_SerialPort 232 | * Method: clearDTR 233 | * Signature: (J)Z 234 | */ 235 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearDTR 236 | (JNIEnv *, jobject, jlong); 237 | 238 | /* 239 | * Class: com_fazecast_jSerialComm_SerialPort 240 | * Method: getCTS 241 | * Signature: (J)Z 242 | */ 243 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCTS 244 | (JNIEnv *, jobject, jlong); 245 | 246 | /* 247 | * Class: com_fazecast_jSerialComm_SerialPort 248 | * Method: getDSR 249 | * Signature: (J)Z 250 | */ 251 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDSR 252 | (JNIEnv *, jobject, jlong); 253 | 254 | /* 255 | * Class: com_fazecast_jSerialComm_SerialPort 256 | * Method: getDCD 257 | * Signature: (J)Z 258 | */ 259 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDCD 260 | (JNIEnv *, jobject, jlong); 261 | 262 | /* 263 | * Class: com_fazecast_jSerialComm_SerialPort 264 | * Method: getDTR 265 | * Signature: (J)Z 266 | */ 267 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDTR 268 | (JNIEnv *, jobject, jlong); 269 | 270 | /* 271 | * Class: com_fazecast_jSerialComm_SerialPort 272 | * Method: getRTS 273 | * Signature: (J)Z 274 | */ 275 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getRTS 276 | (JNIEnv *, jobject, jlong); 277 | 278 | /* 279 | * Class: com_fazecast_jSerialComm_SerialPort 280 | * Method: getRI 281 | * Signature: (J)Z 282 | */ 283 | JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getRI 284 | (JNIEnv *, jobject, jlong); 285 | 286 | /* 287 | * Class: com_fazecast_jSerialComm_SerialPort 288 | * Method: getLastErrorLocation 289 | * Signature: (J)I 290 | */ 291 | JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_getLastErrorLocation 292 | (JNIEnv *, jobject, jlong); 293 | 294 | /* 295 | * Class: com_fazecast_jSerialComm_SerialPort 296 | * Method: getLastErrorCode 297 | * Signature: (J)I 298 | */ 299 | JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_getLastErrorCode 300 | (JNIEnv *, jobject, jlong); 301 | 302 | #ifdef __cplusplus 303 | } 304 | #endif 305 | #endif 306 | -------------------------------------------------------------------------------- /src/main/c/Posix/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := jSerialComm 6 | TARGET_OUT := ../../resources/Android/$(TARGET_ARCH_ABI) 7 | LOCAL_SRC_FILES := ../SerialPort_Posix.c ../PosixHelperFunctions.c 8 | LOCAL_CFLAGS := -fsigned-char -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 9 | LOCAL_LDLIBS := -llog 10 | 11 | include $(BUILD_SHARED_LIBRARY) 12 | 13 | HOST_OS := $(strip $(HOST_OS)) 14 | ifeq ($(OS),Windows_NT) 15 | all: 16 | rmdir /Q /S libs obj 17 | else 18 | all: 19 | rm -rf libs obj 20 | endif -------------------------------------------------------------------------------- /src/main/c/Posix/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := all 2 | APP_PLATFORM := android-21 3 | APP_MODULES := jSerialComm 4 | APP_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 5 | -------------------------------------------------------------------------------- /src/main/c/Posix/termios2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * termios2.h 3 | * 4 | * Created on: Jul 06, 2023 5 | * Last Updated on: Dec 14, 2023 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2023 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | #ifndef __TERMIOS2_HEADER_H__ 27 | #define __TERMIOS2_HEADER_H__ 28 | 29 | #include 30 | 31 | #if defined (__powerpc__) || defined (__powerpc64__) 32 | 33 | #define T2CSANOW _IOW('t', 20, struct termios2) 34 | #define BOTHER 00037 35 | #define K_NCCS 19 36 | struct termios2 { 37 | tcflag_t c_iflag; 38 | tcflag_t c_oflag; 39 | tcflag_t c_cflag; 40 | tcflag_t c_lflag; 41 | cc_t c_cc[K_NCCS]; 42 | cc_t c_line; 43 | speed_t c_ispeed; 44 | speed_t c_ospeed; 45 | }; 46 | 47 | 48 | #elif defined (__mips__) 49 | 50 | #define T2CSANOW TCSETS2 51 | #define BOTHER CBAUDEX 52 | #define K_NCCS 23 53 | struct termios2 { 54 | tcflag_t c_iflag; 55 | tcflag_t c_oflag; 56 | tcflag_t c_cflag; 57 | tcflag_t c_lflag; 58 | cc_t c_line; 59 | cc_t c_cc[K_NCCS]; 60 | speed_t c_ispeed; 61 | speed_t c_ospeed; 62 | }; 63 | 64 | 65 | #else 66 | 67 | #define T2CSANOW TCSETS2 68 | #ifndef NCCS 69 | #define K_NCCS 19 70 | #else 71 | #define K_NCCS NCCS 72 | #endif 73 | #ifndef BOTHER 74 | #define BOTHER CBAUDEX 75 | #endif 76 | 77 | #if !defined(__ANDROID__) 78 | 79 | struct termios2 { 80 | tcflag_t c_iflag; 81 | tcflag_t c_oflag; 82 | tcflag_t c_cflag; 83 | tcflag_t c_lflag; 84 | cc_t c_line; 85 | cc_t c_cc[K_NCCS]; 86 | speed_t c_ispeed; 87 | speed_t c_ospeed; 88 | }; 89 | 90 | #endif 91 | 92 | #endif 93 | 94 | #endif // #ifndef __TERMIOS2_HEADER_H__ 95 | -------------------------------------------------------------------------------- /src/main/c/Windows/Makefile: -------------------------------------------------------------------------------- 1 | # Compiler tools, commands, and flags 2 | COMPILE_X86 := i686-pc-win32-msvc-gcc 3 | COMPILE_X64 := x86_64-pc-win32-msvc-gcc 4 | COMPILE_ARM := arm-pc-win32-msvc-gcc 5 | COMPILE_ARM64 := aarch64-pc-win32-msvc-gcc 6 | LINK_X86 := i686-pc-win32-msvc-ld 7 | LINK_X64 := x86_64-pc-win32-msvc-ld 8 | LINK_ARM := arm-pc-win32-msvc-ld 9 | LINK_ARM64 := aarch64-pc-win32-msvc-ld 10 | CFLAGS := -Os -flto 11 | CFLAGS_X86 := -O0 12 | LDFLAGS := -flto -Wl,/DLL 13 | LDFLAGS_X86 := -Wl,/DLL 14 | JDK_HOME := $(shell echo "`dirname $$(dirname $$(readlink -f $$(which javac)))`") 15 | INCLUDES := -I"$(JDK_HOME)/include" -Iwin32 16 | LIBRARIES := -lAdvAPI32 -lSetupAPI -lshell32 17 | DELETE := @rm 18 | MKDIR := @mkdir 19 | COPY := @cp 20 | MOVE := @mv 21 | PRINT := @echo 22 | 23 | # Java and resource definitions 24 | LIBRARY_NAME := jSerialComm.dll 25 | BUILD_DIR := ../../../../build 26 | RESOURCE_DIR := ../../../../src/main/resources/Windows 27 | JAVA_SOURCE_DIR := ../../../../src/main/java/com/fazecast/jSerialComm 28 | FULL_CLASS := com.fazecast.jSerialComm.SerialPort 29 | JAVA_CLASS_DIR := $(BUILD_DIR)/com/fazecast/jSerialComm 30 | JNI_HEADER_FILE := com_fazecast_jSerialComm_SerialPort.h 31 | JNI_HEADER := ../$(JNI_HEADER_FILE) 32 | ANDROID_JAR := ../../../external/android.jar 33 | JAVA_CLASS := $(JAVA_CLASS_DIR)/SerialPort.class 34 | JFLAGS := --release 6 -Xlint:-options 35 | JAVAC := "$(JDK_HOME)/bin/javac" 36 | 37 | # Architecture-dependent library variables 38 | OBJECTSx86 := $(BUILD_DIR)/x86/SerialPort_Windows.o $(BUILD_DIR)/x86/WindowsHelperFunctions.o 39 | OBJECTSx64 := $(BUILD_DIR)/x86_64/SerialPort_Windows.o $(BUILD_DIR)/x86_64/WindowsHelperFunctions.o 40 | OBJECTSarm := $(BUILD_DIR)/armv7/SerialPort_Windows.o $(BUILD_DIR)/armv7/WindowsHelperFunctions.o 41 | OBJECTSarm64 := $(BUILD_DIR)/aarch64/SerialPort_Windows.o $(BUILD_DIR)/aarch64/WindowsHelperFunctions.o 42 | 43 | # Define phony and suffix rules 44 | .PHONY: all win32 win64 winarm winarm64 checkdirs clean 45 | .SUFFIXES: 46 | .SUFFIXES: .c .o .class .java .h 47 | 48 | # Default build target not possible due to different architecture compilers 49 | all : win32 win64 winarm winarm64 50 | $(DELETE) -rf "$(BUILD_DIR)" 51 | $(DELETE) -rf ../*.h $(JNI_HEADER_FILE) 52 | clean : 53 | $(DELETE) -rf "$(BUILD_DIR)" 54 | $(DELETE) -rf ../*.h $(JNI_HEADER_FILE) 55 | 56 | # Build architecture-specific Windows libraries 57 | win32 : $(JAVA_CLASS_DIR) $(BUILD_DIR)/x86 $(BUILD_DIR)/x86/$(LIBRARY_NAME) 58 | $(MKDIR) -p $(RESOURCE_DIR)/x86/ 59 | $(COPY) $(BUILD_DIR)/x86/*.dll $(RESOURCE_DIR)/x86/ 60 | win64 : $(JAVA_CLASS_DIR) $(BUILD_DIR)/x86_64 $(BUILD_DIR)/x86_64/$(LIBRARY_NAME) 61 | $(MKDIR) -p $(RESOURCE_DIR)/x86_64 62 | $(COPY) $(BUILD_DIR)/x86_64/*.dll $(RESOURCE_DIR)/x86_64 63 | winarm : $(JAVA_CLASS_DIR) $(BUILD_DIR)/armv7 $(BUILD_DIR)/armv7/$(LIBRARY_NAME) 64 | $(MKDIR) -p $(RESOURCE_DIR)/armv7/ 65 | $(COPY) $(BUILD_DIR)/armv7/*.dll $(RESOURCE_DIR)/armv7/ 66 | winarm64 : $(JAVA_CLASS_DIR) $(BUILD_DIR)/aarch64 $(BUILD_DIR)/aarch64/$(LIBRARY_NAME) 67 | $(MKDIR) -p $(RESOURCE_DIR)/aarch64/ 68 | $(COPY) $(BUILD_DIR)/aarch64/*.dll $(RESOURCE_DIR)/aarch64/ 69 | 70 | # Rule to create build directories 71 | $(BUILD_DIR)/x86 : 72 | $(MKDIR) -p $@ 73 | $(BUILD_DIR)/x86_64 : 74 | $(MKDIR) -p $@ 75 | $(BUILD_DIR)/armv7 : 76 | $(MKDIR) -p $@ 77 | $(BUILD_DIR)/aarch64 : 78 | $(MKDIR) -p $@ 79 | $(JAVA_CLASS_DIR) : 80 | $(MKDIR) -p $@ 81 | 82 | # Build rules for all libraries 83 | $(BUILD_DIR)/x86/$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSx86) 84 | $(LINK_X86) $(LDFLAGS_X86) -o $@ $(OBJECTSx86) $(LIBRARIES) 85 | $(BUILD_DIR)/x86_64/$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSx64) 86 | $(LINK_X64) $(LDFLAGS) -o $@ $(OBJECTSx64) $(LIBRARIES) 87 | $(BUILD_DIR)/armv7/$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSarm) 88 | $(LINK_ARM) $(LDFLAGS) -o $@ $(OBJECTSarm) $(LIBRARIES) 89 | $(BUILD_DIR)/aarch64/$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSarm64) 90 | $(LINK_ARM64) $(LDFLAGS) -o $@ $(OBJECTSarm64) $(LIBRARIES) 91 | 92 | # Suffix rules to get from *.c -> *.o 93 | $(BUILD_DIR)/x86/%.o : %.c 94 | $(COMPILE_X86) $(INCLUDES) $(CFLAGS_X86) -c $< -o $@ 95 | $(BUILD_DIR)/x86_64/%.o : %.c 96 | $(COMPILE_X64) $(INCLUDES) $(CFLAGS) -c $< -o $@ 97 | $(BUILD_DIR)/armv7/%.o : %.c 98 | $(COMPILE_ARM) $(INCLUDES) $(CFLAGS) -c $< -o $@ 99 | $(BUILD_DIR)/aarch64/%.o : %.c 100 | $(COMPILE_ARM64) $(INCLUDES) $(CFLAGS) -c $< -o $@ 101 | 102 | # Rule to build JNI header file 103 | $(JNI_HEADER) : $(JAVA_CLASS) 104 | $(COPY) $@ ./ 105 | 106 | # Suffix rule to get from *.java -> *.class 107 | $(JAVA_CLASS) : 108 | $(JAVAC) $(JFLAGS) -d $(JAVA_CLASS_DIR)/../../.. -cp $(JAVA_SOURCE_DIR)/../../..:$(ANDROID_JAR) $(JAVA_SOURCE_DIR)/$(basename $(notdir $@)).java -h .. 109 | -------------------------------------------------------------------------------- /src/main/c/Windows/Makefile.native: -------------------------------------------------------------------------------- 1 | # Windows specific library variables 2 | COMPILE = cl 3 | LINK = link 4 | CFLAGS = /c /O2 /GF /GL /MT /EHsc /fp:precise /J /nologo /TC /Zi 5 | LDFLAGS = /DLL /LTCG /NOASSEMBLY /NOLOGO /INCREMENTAL:NO /DEBUG /OPT:REF,ICF,LBR 6 | INCLUDES = /I"$(JDK_HOME)\include" /I"$(JDK_HOME)\include\win32" 7 | LIBRARIES = Advapi32.lib SetupAPI.lib Shell32.lib 8 | DELETE = @del /q /f 9 | RMDIR = @rd /q /s 10 | MKDIR = @md 11 | COPY = @copy /y 12 | MOVE = @move /y 13 | PRINT = @echo 14 | 15 | # Ensure that JDK_HOME is defined 16 | !IFNDEF JDK_HOME 17 | ! IF [echo off && FOR /F "usebackq tokens=2 delims==" %i IN (`java -XshowSettings:properties -version 2^>^&1 ^| findstr "java.home"`) DO SET JDK_HOME=%~i && $(MAKE) /$(MAKEFLAGS) /nologo /f $(MAKEDIR)\Makefile.native && exit /b] == 0 18 | ! ENDIF 19 | !ELSE 20 | 21 | # Locate the Java JDK and the Visual Studio 2022 installation 22 | JDK_HOME = $(strip $(JDK_HOME)) 23 | VS_HOME = "$(VS2022INSTALLDIR)\VC\Auxiliary\Build\vcvarsall.bat" 24 | 25 | # Java and resource definitions 26 | LIBRARY_NAME = jSerialComm.dll 27 | BUILD_DIR = ..\..\..\..\build 28 | RESOURCE_DIR = ..\..\..\..\src\main\resources\Windows 29 | JAVA_SOURCE_DIR = ..\..\..\..\src\main\java\com\fazecast\jSerialComm 30 | FULL_CLASS = com.fazecast.jSerialComm.SerialPort 31 | JAVA_CLASS_DIR = $(BUILD_DIR)\com\fazecast\jSerialComm 32 | JNI_HEADER_FILE = com_fazecast_jSerialComm_SerialPort.h 33 | JNI_HEADER = ..\$(JNI_HEADER_FILE) 34 | ANDROID_JAR = ..\..\..\external/android.jar 35 | JAVA_CLASS = $(JAVA_CLASS_DIR)\SerialPort.class 36 | JFLAGS = --release 6 -Xlint:-options 37 | JAVAC = "$(JDK_HOME)\bin\javac" 38 | 39 | # Architecture-dependent library variables 40 | OBJECTSx86 = $(BUILD_DIR)\x86\SerialPort_Windows.obj $(BUILD_DIR)\x86\WindowsHelperFunctions.obj 41 | OBJECTSx86_64 = $(BUILD_DIR)\x86_64\SerialPort_Windows.obj $(BUILD_DIR)\x86_64\WindowsHelperFunctions.obj 42 | OBJECTSarmv7 = $(BUILD_DIR)\armv7\SerialPort_Windows.obj $(BUILD_DIR)\armv7\WindowsHelperFunctions.obj 43 | OBJECTSaarch64 = $(BUILD_DIR)\aarch64\SerialPort_Windows.obj $(BUILD_DIR)\aarch64\WindowsHelperFunctions.obj 44 | 45 | # Define phony and suffix rules 46 | .PHONY: all win32 win64 winarm winarm64 47 | .SUFFIXES: 48 | .SUFFIXES: .c .obj .class .java .h 49 | 50 | # Default build target 51 | all : win32 win64 winarm winarm64 52 | $(DELETE) ..\*.h $(JNI_HEADER_FILE) *.pdb 53 | 54 | # Build architecture-specific Windows libraries 55 | win32 : $(BUILD_DIR)\x86 $(BUILD_DIR)\x86\$(LIBRARY_NAME) 56 | $(COPY) $(BUILD_DIR)\x86\*.dll $(RESOURCE_DIR)\x86 57 | $(RMDIR) $(BUILD_DIR) 58 | win64 : $(BUILD_DIR)\x86_64 $(BUILD_DIR)\x86_64\$(LIBRARY_NAME) 59 | $(COPY) $(BUILD_DIR)\x86_64\*.dll $(RESOURCE_DIR)\x86_64 60 | $(RMDIR) $(BUILD_DIR) 61 | winarm : $(BUILD_DIR)\armv7 $(BUILD_DIR)\armv7\$(LIBRARY_NAME) 62 | $(COPY) $(BUILD_DIR)\armv7\*.dll $(RESOURCE_DIR)\armv7 63 | $(RMDIR) $(BUILD_DIR) 64 | winarm64 : $(BUILD_DIR)\aarch64 $(BUILD_DIR)\aarch64\$(LIBRARY_NAME) 65 | $(COPY) $(BUILD_DIR)\aarch64\*.dll $(RESOURCE_DIR)\aarch64 66 | $(RMDIR) $(BUILD_DIR) 67 | 68 | # Rule to create build directories 69 | $(BUILD_DIR)\x86 : 70 | $(MKDIR) "$@" 71 | $(BUILD_DIR)\x86_64 : 72 | $(MKDIR) "$@" 73 | $(BUILD_DIR)\armv7 : 74 | $(MKDIR) "$@" 75 | $(BUILD_DIR)\aarch64 : 76 | $(MKDIR) "$@" 77 | 78 | # Build rules for all libraries 79 | $(BUILD_DIR)\x86\$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSx86) 80 | $(VS_HOME) x86 & $(LINK) $(LDFLAGS) /MACHINE:X86 /OUT:$@ $(OBJECTSx86) $(LIBRARIES) 81 | $(BUILD_DIR)\x86_64\$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSx86_64) 82 | $(VS_HOME) x64 & $(LINK) $(LDFLAGS) /MACHINE:X64 /OUT:$@ $(OBJECTSx86_64) $(LIBRARIES) 83 | $(BUILD_DIR)\armv7\$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSarmv7) 84 | $(VS_HOME) x86_arm & $(LINK) $(LDFLAGS) /MACHINE:ARM /OUT:$@ $(OBJECTSarmv7) $(LIBRARIES) 85 | $(BUILD_DIR)\aarch64\$(LIBRARY_NAME) : $(JNI_HEADER) $(OBJECTSaarch64) 86 | $(VS_HOME) x64_arm64 & $(LINK) $(LDFLAGS) /MACHINE:ARM64 /OUT:$@ $(OBJECTSaarch64) $(LIBRARIES) 87 | 88 | # Suffix rules to get from *.c -> *.obj 89 | $(OBJECTSx86) : 90 | $(VS_HOME) x86 & $(COMPILE) $(CFLAGS) $(INCLUDES) $(*B).c -Fo$@ 91 | $(OBJECTSx86_64) : 92 | $(VS_HOME) x64 & $(COMPILE) $(CFLAGS) $(INCLUDES) $(*B).c -Fo$@ 93 | $(OBJECTSarmv7) : 94 | $(VS_HOME) x86_arm & $(COMPILE) $(CFLAGS) $(INCLUDES) $(*B).c -Fo$@ 95 | $(OBJECTSaarch64) : 96 | $(VS_HOME) x64_arm64 & $(COMPILE) $(CFLAGS) $(INCLUDES) $(*B).c -Fo$@ 97 | 98 | # Rule to build JNI header file 99 | $(JNI_HEADER) : $(JAVA_CLASS) 100 | $(COPY) $@ .\ 101 | 102 | # Suffix rule to get from *.java -> *.class 103 | $(JAVA_CLASS) : 104 | $(JAVAC) $(JFLAGS) -d $(JAVA_CLASS_DIR)\..\..\.. -cp $(JAVA_SOURCE_DIR)\..\..\..:$(ANDROID_JAR) $(JAVA_SOURCE_DIR)\$(*B).java -h .. 105 | 106 | !ENDIF 107 | -------------------------------------------------------------------------------- /src/main/c/Windows/WindowsHelperFunctions.c: -------------------------------------------------------------------------------- 1 | /* 2 | * WindowsHelperFunctions.c 3 | * 4 | * Created on: May 05, 2015 5 | * Last Updated on: Apr 10, 2024 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2024 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | #ifdef _WIN32 27 | #define WINVER _WIN32_WINNT_WINXP 28 | #define _WIN32_WINNT _WIN32_WINNT_WINXP 29 | #define NTDDI_VERSION NTDDI_WINXP 30 | #define WIN32_LEAN_AND_MEAN 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include "WindowsHelperFunctions.h" 38 | 39 | // Common storage functionality 40 | serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description, const wchar_t* location, const wchar_t* serialNumber, const wchar_t* manufacturer, int vid, int pid) 41 | { 42 | // Allocate memory for the new SerialPort storage structure 43 | unsigned char containsSlashes = ((key[0] == L'\\') && (key[1] == L'\\') && (key[2] == L'.') && (key[3] == L'\\')); 44 | if (vector->capacity == vector->length) 45 | { 46 | serialPort** newArray = (serialPort**)realloc(vector->ports, ++vector->capacity * sizeof(serialPort*)); 47 | if (newArray) 48 | vector->ports = newArray; 49 | else 50 | { 51 | vector->capacity--; 52 | return NULL; 53 | } 54 | } 55 | serialPort* port = (serialPort*)malloc(sizeof(serialPort)); 56 | if (port) 57 | vector->ports[vector->length++] = port; 58 | else 59 | return NULL; 60 | 61 | // Initialize the storage structure 62 | memset(port, 0, sizeof(serialPort)); 63 | port->handle = (void*)-1; 64 | port->enumerated = 1; 65 | port->vendorID = vid; 66 | port->productID = pid; 67 | port->portPath = (wchar_t*)malloc((wcslen(key)+(containsSlashes ? 1 : 5))*sizeof(wchar_t)); 68 | port->portLocation = (wchar_t*)malloc((wcslen(location)+1)*sizeof(wchar_t)); 69 | port->friendlyName = (wchar_t*)malloc((wcslen(friendlyName)+1)*sizeof(wchar_t)); 70 | port->serialNumber = (wchar_t*)malloc((wcslen(serialNumber)+1)*sizeof(wchar_t)); 71 | port->manufacturer = (wchar_t*)malloc((wcslen(manufacturer)+1)*sizeof(wchar_t)); 72 | port->portDescription = (wchar_t*)malloc((wcslen(description)+1)*sizeof(wchar_t)); 73 | if (!port->portPath || !port->portLocation || !port->friendlyName || !port->serialNumber || !port->manufacturer || !port->portDescription) 74 | { 75 | // Clean up memory associated with the port 76 | vector->length--; 77 | if (port->portPath) 78 | free(port->portPath); 79 | if (port->portLocation) 80 | free(port->portLocation); 81 | if (port->friendlyName) 82 | free(port->friendlyName); 83 | if (port->serialNumber) 84 | free(port->serialNumber); 85 | if (port->manufacturer) 86 | free(port->manufacturer); 87 | if (port->portDescription) 88 | free(port->portDescription); 89 | free(port); 90 | return NULL; 91 | } 92 | 93 | // Store port strings 94 | if (containsSlashes) 95 | wcscpy_s(port->portPath, wcslen(key)+1, key); 96 | else 97 | { 98 | wcscpy_s(port->portPath, wcslen(key)+5, L"\\\\.\\"); 99 | wcscat_s(port->portPath, wcslen(key)+5, key); 100 | } 101 | wcscpy_s(port->portLocation, wcslen(location)+1, location); 102 | wcscpy_s(port->friendlyName, wcslen(friendlyName)+1, friendlyName); 103 | wcscpy_s(port->portDescription, wcslen(description)+1, description); 104 | wcscpy_s(port->serialNumber, wcslen(serialNumber)+1, serialNumber); 105 | wcscpy_s(port->manufacturer, wcslen(manufacturer)+1, manufacturer); 106 | 107 | // Return the newly created serial port structure 108 | return port; 109 | } 110 | 111 | serialPort* fetchPort(serialPortVector* vector, const wchar_t* key) 112 | { 113 | // Retrieve the serial port specified by the passed-in key 114 | int keyOffset = ((key[0] == L'\\') && (key[1] == L'\\') && (key[2] == L'.') && (key[3] == L'\\')) ? 0 : 4; 115 | for (int i = 0; i < vector->length; ++i) 116 | if (wcscmp(key, vector->ports[i]->portPath + keyOffset) == 0) 117 | return vector->ports[i]; 118 | return NULL; 119 | } 120 | 121 | void removePort(serialPortVector* vector, serialPort* port) 122 | { 123 | // Clean up memory associated with the port 124 | free(port->portPath); 125 | free(port->portLocation); 126 | free(port->friendlyName); 127 | free(port->serialNumber); 128 | free(port->manufacturer); 129 | free(port->portDescription); 130 | 131 | // Move up all remaining ports in the serial port listing 132 | for (int i = 0; i < vector->length; ++i) 133 | if (vector->ports[i] == port) 134 | { 135 | for (int j = i; j < (vector->length - 1); ++j) 136 | vector->ports[j] = vector->ports[j+1]; 137 | vector->length--; 138 | break; 139 | } 140 | 141 | // Free the serial port structure memory 142 | free(port); 143 | } 144 | 145 | void cleanUpVector(serialPortVector* vector) 146 | { 147 | while (vector->length) 148 | removePort(vector, vector->ports[0]); 149 | if (vector->ports) 150 | free(vector->ports); 151 | vector->ports = NULL; 152 | vector->length = vector->capacity = 0; 153 | } 154 | 155 | // Windows-specific functionality 156 | void reduceLatencyToMinimum(const wchar_t* portName, unsigned char requestElevatedPermissions) 157 | { 158 | // Search for this port in all FTDI enumerated ports 159 | HKEY key, paramKey; 160 | DWORD maxSubkeySize, maxPortNameSize = 8; 161 | if ((RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", 0, KEY_READ, &key) == ERROR_SUCCESS) && 162 | (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, &maxSubkeySize, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)) 163 | { 164 | maxSubkeySize += 32; 165 | DWORD index = 0, subkeySize = maxSubkeySize; 166 | wchar_t *subkey = (wchar_t*)malloc(maxSubkeySize * sizeof(wchar_t)), *portPath = (wchar_t*)malloc(maxPortNameSize * sizeof(wchar_t)); 167 | while (subkey && portPath && (RegEnumKeyExW(key, index++, subkey, &subkeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)) 168 | { 169 | // Retrieve the current port latency value 170 | size_t convertedSize; 171 | char *subkeyString = NULL; 172 | subkeySize = maxSubkeySize; 173 | DWORD desiredLatency = 2, oldLatency = 2; 174 | if ((wcstombs_s(&convertedSize, NULL, 0, subkey, 0) == 0) && (convertedSize < 255)) 175 | { 176 | subkeyString = (char*)malloc(convertedSize); 177 | if (subkeyString && (wcstombs_s(NULL, subkeyString, convertedSize, subkey, convertedSize - 1) == 0) && 178 | (wcscat_s(subkey, maxSubkeySize, L"\\0000\\Device Parameters") == 0)) 179 | { 180 | if (RegOpenKeyExW(key, subkey, 0, KEY_QUERY_VALUE, ¶mKey) == ERROR_SUCCESS) 181 | { 182 | DWORD oldLatencySize = sizeof(DWORD), portNameSize = maxPortNameSize * sizeof(wchar_t); 183 | if ((RegQueryValueExW(paramKey, L"PortName", NULL, NULL, (LPBYTE)portPath, &portNameSize) == ERROR_SUCCESS) && (wcscmp(portName, portPath) == 0)) 184 | RegQueryValueExW(paramKey, L"LatencyTimer", NULL, NULL, (LPBYTE)&oldLatency, &oldLatencySize); 185 | RegCloseKey(paramKey); 186 | } 187 | } 188 | } 189 | 190 | // Update the port latency value if it is too high 191 | if (oldLatency > desiredLatency) 192 | { 193 | if (RegOpenKeyExW(key, subkey, 0, KEY_SET_VALUE, ¶mKey) == ERROR_SUCCESS) 194 | { 195 | RegSetValueExW(paramKey, L"LatencyTimer", 0, REG_DWORD, (LPBYTE)&desiredLatency, sizeof(desiredLatency)); 196 | RegCloseKey(paramKey); 197 | } 198 | else if (requestElevatedPermissions) 199 | { 200 | // Create registry update file 201 | char *workingDirectory = _getcwd(NULL, 0); 202 | wchar_t *workingDirectoryWide = _wgetcwd(NULL, 0); 203 | int workingDirectoryLength = strlen(workingDirectory) + 1; 204 | char *registryFileName = (char*)malloc(workingDirectoryLength + 8); 205 | wchar_t *paramsString = (wchar_t*)malloc((workingDirectoryLength + 11) * sizeof(wchar_t)); 206 | sprintf(registryFileName, "%s\\del.reg", workingDirectory); 207 | swprintf(paramsString, workingDirectoryLength + 11, L"/s %s\\del.reg", workingDirectoryWide); 208 | FILE *registryFile = fopen(registryFileName, "wb"); 209 | if (registryFile) 210 | { 211 | fprintf(registryFile, "Windows Registry Editor Version 5.00\n\n"); 212 | fprintf(registryFile, "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS\\%s\\0000\\Device Parameters]\n", subkeyString); 213 | fprintf(registryFile, "\"LatencyTimer\"=dword:00000002\n\n"); 214 | fclose(registryFile); 215 | } 216 | 217 | // Launch a new administrative process to update the registry value 218 | SHELLEXECUTEINFOW shExInfo = { 0 }; 219 | shExInfo.cbSize = sizeof(shExInfo); 220 | shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; 221 | shExInfo.hwnd = NULL; 222 | shExInfo.lpVerb = L"runas"; 223 | shExInfo.lpFile = L"C:\\Windows\\regedit.exe"; 224 | shExInfo.lpParameters = paramsString; 225 | shExInfo.lpDirectory = NULL; 226 | shExInfo.nShow = SW_SHOW; 227 | shExInfo.hInstApp = 0; 228 | if (ShellExecuteExW(&shExInfo)) 229 | { 230 | WaitForSingleObject(shExInfo.hProcess, INFINITE); 231 | CloseHandle(shExInfo.hProcess); 232 | } 233 | 234 | // Delete the registry update file 235 | remove(registryFileName); 236 | free(workingDirectoryWide); 237 | free(workingDirectory); 238 | free(registryFileName); 239 | free(paramsString); 240 | } 241 | } 242 | 243 | // Clean up memory 244 | if (subkeyString) 245 | free(subkeyString); 246 | } 247 | RegCloseKey(key); 248 | free(portPath); 249 | free(subkey); 250 | } 251 | } 252 | 253 | int getPortPathFromSerial(wchar_t* portPath, int portPathLength, const char* ftdiSerialNumber) 254 | { 255 | // Search for this port in all FTDI enumerated ports 256 | int found = 0; 257 | HKEY key, paramKey; 258 | DWORD maxSubkeySize; 259 | if ((RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", 0, KEY_READ, &key) == ERROR_SUCCESS) && 260 | (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, &maxSubkeySize, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)) 261 | { 262 | maxSubkeySize += 32; 263 | DWORD index = 0, subkeySize = maxSubkeySize; 264 | wchar_t *subkey = (wchar_t*)malloc(maxSubkeySize * sizeof(wchar_t)); 265 | while (subkey && (RegEnumKeyExW(key, index++, subkey, &subkeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)) 266 | { 267 | // Convert this string from wchar* to char* 268 | size_t convertedSize; 269 | subkeySize = maxSubkeySize; 270 | if ((wcstombs_s(&convertedSize, NULL, 0, subkey, 0) == 0) && (convertedSize < 255)) 271 | { 272 | char *subkeyString = (char*)malloc(convertedSize); 273 | if (subkeyString && (wcstombs_s(NULL, subkeyString, convertedSize, subkey, convertedSize - 1) == 0)) 274 | { 275 | // Determine if this device matches the specified serial number 276 | if (ftdiSerialNumber && strstr(subkeyString, ftdiSerialNumber) && (wcscat_s(subkey, maxSubkeySize, L"\\0000\\Device Parameters") == 0)) 277 | { 278 | DWORD portNameSize = portPathLength; 279 | if ((RegOpenKeyExW(key, subkey, 0, KEY_QUERY_VALUE, ¶mKey) == ERROR_SUCCESS) && 280 | (RegQueryValueExW(paramKey, L"PortName", NULL, NULL, (LPBYTE)portPath, &portNameSize) == ERROR_SUCCESS)) 281 | { 282 | found = 1; 283 | RegCloseKey(paramKey); 284 | } 285 | } 286 | } 287 | if (subkeyString) 288 | free(subkeyString); 289 | } 290 | } 291 | RegCloseKey(key); 292 | if (subkey) 293 | free(subkey); 294 | } 295 | return found; 296 | } 297 | 298 | #endif 299 | -------------------------------------------------------------------------------- /src/main/c/Windows/WindowsHelperFunctions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * WindowsHelperFunctions.h 3 | * 4 | * Created on: May 05, 2015 5 | * Last Updated on: Apr 10, 2024 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2024 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__ 27 | #define __WINDOWS_HELPER_FUNCTIONS_HEADER_H__ 28 | 29 | // Serial port JNI header file 30 | #include "../com_fazecast_jSerialComm_SerialPort.h" 31 | 32 | // Serial port data structure 33 | typedef struct serialPort 34 | { 35 | void *handle; 36 | wchar_t *portPath, *friendlyName, *portDescription, *portLocation, *serialNumber, *manufacturer; 37 | int errorLineNumber, errorNumber, vendorID, productID; 38 | volatile char enumerated, eventListenerRunning; 39 | char ftdiSerialNumber[16]; 40 | } serialPort; 41 | 42 | // Common storage functionality 43 | typedef struct serialPortVector 44 | { 45 | serialPort **ports; 46 | int length, capacity; 47 | } serialPortVector; 48 | serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description, const wchar_t* location, const wchar_t* serialNumber, const wchar_t* manufacturer, int vid, int pid); 49 | serialPort* fetchPort(serialPortVector* vector, const wchar_t* key); 50 | void removePort(serialPortVector* vector, serialPort* port); 51 | void cleanUpVector(serialPortVector* vector); 52 | 53 | // Windows-specific functionality 54 | void reduceLatencyToMinimum(const wchar_t* portName, unsigned char requestElevatedPermissions); 55 | int getPortPathFromSerial(wchar_t* portPath, int portPathLength, const char* ftdiSerialNumber); 56 | 57 | #endif // #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__ 58 | -------------------------------------------------------------------------------- /src/main/c/Windows/win32/jni_md.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved. 3 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | */ 25 | 26 | #ifndef _JAVASOFT_JNI_MD_H_ 27 | #define _JAVASOFT_JNI_MD_H_ 28 | 29 | #define JNIEXPORT __declspec(dllexport) 30 | #define JNIIMPORT __declspec(dllimport) 31 | #define JNICALL __stdcall 32 | 33 | // 'long' is always 32 bit on windows so this matches what jdk expects 34 | typedef long jint; 35 | typedef __int64 jlong; 36 | typedef signed char jbyte; 37 | 38 | #endif /* !_JAVASOFT_JNI_MD_H_ */ 39 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/SerialPortDataListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortDataListener.java 3 | * 4 | * Created on: Feb 25, 2015 5 | * Last Updated on: Jun 08, 2022 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2022 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | import java.util.EventListener; 29 | 30 | /** 31 | * This interface must be implemented to enable simple event-based serial port I/O. 32 | * 33 | * @see java.util.EventListener 34 | */ 35 | public interface SerialPortDataListener extends EventListener 36 | { 37 | /** 38 | * Must be overridden to return one or more desired event constants for which the {@link #serialEvent(SerialPortEvent)} callback should be triggered. 39 | *

40 | * Valid event constants are: 41 | *

42 | *      {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
43 | *      {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
44 | *      {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
45 | *      {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED}
46 | *      {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
47 | *      {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
48 | *      {@link SerialPort#LISTENING_EVENT_CTS}
49 | *      {@link SerialPort#LISTENING_EVENT_DSR}
50 | *      {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
51 | *      {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
52 | *      {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
53 | *      {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
54 | *      {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
55 | *

56 | * Two or more events may be OR'd together to listen for multiple events; however, if {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE} is OR'd with {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}, the {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED} flag will take precedence. 57 | *

58 | * Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN} 59 | * event will never be called on a non-Windows system. 60 | *

61 | * It is recommended to only use the {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}, {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}, 62 | * {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}, and/or {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED} listening events in production or cross-platform code 63 | * since underlying differences and lack of support for the control line status and error events among the various operating systems and device drivers make it 64 | * unlikely that code listening for these events will behave similarly across different serial devices or OS's, if it works at all. 65 | * 66 | * @return The event constants that should trigger the {@link #serialEvent(SerialPortEvent)} callback. 67 | * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE 68 | * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED 69 | * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN 70 | * @see SerialPort#LISTENING_EVENT_PORT_DISCONNECTED 71 | * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT 72 | * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT 73 | * @see SerialPort#LISTENING_EVENT_CTS 74 | * @see SerialPort#LISTENING_EVENT_DSR 75 | * @see SerialPort#LISTENING_EVENT_RING_INDICATOR 76 | * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR 77 | * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR 78 | * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR 79 | * @see SerialPort#LISTENING_EVENT_PARITY_ERROR 80 | */ 81 | int getListeningEvents(); 82 | 83 | /** 84 | * Called whenever one or more of the serial port events specified by the {@link #getListeningEvents()} method occurs. 85 | *

86 | * Note that your implementation of this function should always perform as little data processing as possible, as the speed at which this callback will fire is at the mercy of the underlying operating system. If you need to collect a large amount of data, application-level buffering should be implemented and data processing should occur on a separate thread. 87 | * 88 | * @param event A {@link SerialPortEvent} object containing information and/or data about the serial events that occurred. 89 | * @see SerialPortEvent 90 | */ 91 | void serialEvent(SerialPortEvent event); 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/SerialPortDataListenerWithExceptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortDataListenerWithExceptions.java 3 | * 4 | * Created on: Jul 11, 2019 5 | * Last Updated on: Jun 08, 2022 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2022 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | /** 29 | * This interface must be implemented to enable simple event-based serial port I/O with a custom Exception callback. 30 | * 31 | * @see com.fazecast.jSerialComm.SerialPortDataListener 32 | * @see java.util.EventListener 33 | */ 34 | public interface SerialPortDataListenerWithExceptions extends SerialPortDataListener 35 | { 36 | /** 37 | * Must be overridden to handle any Java exceptions that occur asynchronously in this data listener. 38 | * 39 | * @param e An {@link Exception} object containing information about the exception that occurred. 40 | */ 41 | void catchException(Exception e); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/SerialPortEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortEvent.java 3 | * 4 | * Created on: Feb 25, 2015 5 | * Last Updated on: Jun 08, 2022 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2022 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | import java.util.EventObject; 29 | 30 | /** 31 | * This class describes an asynchronous serial port event. 32 | * 33 | * @see java.util.EventObject 34 | */ 35 | public class SerialPortEvent extends EventObject 36 | { 37 | private static final long serialVersionUID = 3060830619653354150L; 38 | private final int eventType; 39 | private final byte[] serialData; 40 | 41 | /** 42 | * Constructs a {@link SerialPortEvent} object corresponding to the specified serial event type. 43 | *

44 | * This constructor should only be used when the {@link SerialPortEvent} does not contain any data bytes. 45 | *

46 | * Valid serial event types are: 47 | *

48 | *      {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
49 | *      {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
50 | *      {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
51 | *      {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED}
52 | *      {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
53 | *      {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
54 | *      {@link SerialPort#LISTENING_EVENT_CTS}
55 | *      {@link SerialPort#LISTENING_EVENT_DSR}
56 | *      {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
57 | *      {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
58 | *      {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
59 | *      {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
60 | *      {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
61 | *

62 | * Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN} 63 | * event will never be called on a non-Windows system. 64 | *

65 | * Also, most control line status and error events from {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT} to {@link SerialPort#LISTENING_EVENT_PARITY_ERROR} 66 | * are unlikely to function the same across different operating systems or serial devices on the same operating system, if they work properly at all. 67 | * 68 | * @param comPort The {@link SerialPort} about which this object is being created. 69 | * @param serialEventType The type of serial port event that this object describes. 70 | * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE 71 | * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED 72 | * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN 73 | * @see SerialPort#LISTENING_EVENT_PORT_DISCONNECTED 74 | * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT 75 | * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT 76 | * @see SerialPort#LISTENING_EVENT_CTS 77 | * @see SerialPort#LISTENING_EVENT_DSR 78 | * @see SerialPort#LISTENING_EVENT_RING_INDICATOR 79 | * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR 80 | * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR 81 | * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR 82 | * @see SerialPort#LISTENING_EVENT_PARITY_ERROR 83 | */ 84 | public SerialPortEvent(SerialPort comPort, int serialEventType) 85 | { 86 | super(comPort); 87 | eventType = serialEventType; 88 | serialData = null; 89 | } 90 | 91 | /** 92 | * Constructs a {@link SerialPortEvent} object corresponding to the specified serial event type and containing the passed-in data bytes. 93 | *

94 | * Valid serial event types are: 95 | *

96 | *      {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
97 | *      {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
98 | *      {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
99 | *      {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED}
100 | *      {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
101 | *      {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
102 | *      {@link SerialPort#LISTENING_EVENT_CTS}
103 | *      {@link SerialPort#LISTENING_EVENT_DSR}
104 | *      {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
105 | *      {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
106 | *      {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
107 | *      {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
108 | *      {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
109 | *

110 | * Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN} 111 | * event will never be called on a non-Windows system. 112 | *

113 | * Also, most control line status and error events from {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT} to {@link SerialPort#LISTENING_EVENT_PARITY_ERROR} 114 | * are unlikely to function the same across different operating systems or serial devices on the same operating system, if they work properly at all. 115 | * 116 | * @param comPort The {@link SerialPort} about which this object is being created. 117 | * @param serialEventType The type of serial port event that this object describes. 118 | * @param data The raw data bytes corresponding to this serial port event. 119 | * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE 120 | * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED 121 | * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN 122 | * @see SerialPort#LISTENING_EVENT_PORT_DISCONNECTED 123 | * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT 124 | * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT 125 | * @see SerialPort#LISTENING_EVENT_CTS 126 | * @see SerialPort#LISTENING_EVENT_DSR 127 | * @see SerialPort#LISTENING_EVENT_RING_INDICATOR 128 | * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR 129 | * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR 130 | * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR 131 | * @see SerialPort#LISTENING_EVENT_PARITY_ERROR 132 | */ 133 | public SerialPortEvent(SerialPort comPort, int serialEventType, byte[] data) 134 | { 135 | super(comPort); 136 | eventType = serialEventType; 137 | serialData = data; 138 | } 139 | 140 | /** 141 | * Returns a string representation of the type of event represented by this object. 142 | * 143 | * @return A string representation of the type of event represented by this object. 144 | */ 145 | @Override 146 | public final String toString() { 147 | switch(eventType) { 148 | case SerialPort.LISTENING_EVENT_DATA_AVAILABLE: return "LISTENING_EVENT_DATA_AVAILABLE"; 149 | case SerialPort.LISTENING_EVENT_DATA_RECEIVED: return "LISTENING_EVENT_DATA_RECEIVED"; 150 | case SerialPort.LISTENING_EVENT_DATA_WRITTEN: return "LISTENING_EVENT_DATA_WRITTEN"; 151 | case SerialPort.LISTENING_EVENT_PORT_DISCONNECTED: return "LISTENING_EVENT_PORT_DISCONNECTED"; 152 | case SerialPort.LISTENING_EVENT_BREAK_INTERRUPT: return "LISTENING_EVENT_BREAK_INTERRUPT"; 153 | case SerialPort.LISTENING_EVENT_CARRIER_DETECT: return "LISTENING_EVENT_CARRIER_DETECT"; 154 | case SerialPort.LISTENING_EVENT_CTS: return "LISTENING_EVENT_CTS"; 155 | case SerialPort.LISTENING_EVENT_DSR: return "LISTENING_EVENT_DSR"; 156 | case SerialPort.LISTENING_EVENT_RING_INDICATOR: return "LISTENING_EVENT_RING_INDICATOR"; 157 | case SerialPort.LISTENING_EVENT_FRAMING_ERROR: return "LISTENING_EVENT_FRAMING_ERROR"; 158 | case SerialPort.LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR: return "LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR"; 159 | case SerialPort.LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR: return "LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR"; 160 | case SerialPort.LISTENING_EVENT_PARITY_ERROR: return "LISTENING_EVENT_PARITY_ERROR"; 161 | default: return "LISTENING_EVENT_UNKNOWN_TYPE"; 162 | } 163 | } 164 | 165 | /** 166 | * Returns the {@link SerialPort} that triggered this event. 167 | * 168 | * @return The {@link SerialPort} that triggered this event. 169 | */ 170 | public final SerialPort getSerialPort() { return (SerialPort)source; } 171 | 172 | /** 173 | * Returns the type of serial port events that caused this object to be created. 174 | *

175 | * Return value will be a bitmask containing one or more of the following items OR'd together: 176 | *

177 | *      {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
178 | *      {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
179 | *      {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
180 | *      {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED}
181 | *      {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
182 | *      {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
183 | *      {@link SerialPort#LISTENING_EVENT_CTS}
184 | *      {@link SerialPort#LISTENING_EVENT_DSR}
185 | *      {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
186 | *      {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
187 | *      {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
188 | *      {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
189 | *      {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
190 | *

191 | * Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN} 192 | * event will never be called on a non-Windows system. 193 | *

194 | * Also, most control line status and error events from {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT} to {@link SerialPort#LISTENING_EVENT_PARITY_ERROR} 195 | * are unlikely to function the same across different operating systems or serial devices on the same operating system, if they work properly at all. 196 | * 197 | * @return The serial port event that this object describes. 198 | * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE 199 | * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED 200 | * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN 201 | * @see SerialPort#LISTENING_EVENT_PORT_DISCONNECTED 202 | * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT 203 | * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT 204 | * @see SerialPort#LISTENING_EVENT_CTS 205 | * @see SerialPort#LISTENING_EVENT_DSR 206 | * @see SerialPort#LISTENING_EVENT_RING_INDICATOR 207 | * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR 208 | * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR 209 | * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR 210 | * @see SerialPort#LISTENING_EVENT_PARITY_ERROR 211 | */ 212 | public final int getEventType() { return eventType; } 213 | 214 | /** 215 | * Returns any raw data bytes associated with this serial port event. 216 | * 217 | * @return Any data bytes associated with this serial port event or null if none exist. 218 | */ 219 | public final byte[] getReceivedData() { return serialData; } 220 | } 221 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/SerialPortIOException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortIOException.java 3 | * 4 | * Created on: Aug 08, 2018 5 | * Last Updated on: Jun 08, 2022 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2022 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | import java.io.IOException; 29 | 30 | /** 31 | * This class describes a serial port IO exception. 32 | * 33 | * @see java.io.IOException 34 | */ 35 | public final class SerialPortIOException extends IOException 36 | { 37 | private static final long serialVersionUID = 3353684802475494674L; 38 | 39 | /** 40 | * Constructs a {@link SerialPortIOException} with the specified detail message. 41 | * 42 | * @param message The detail message (which is saved for later retrieval by the {@link SerialPortIOException#getMessage()} method). 43 | */ 44 | public SerialPortIOException(String message) 45 | { 46 | super(message); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/SerialPortInvalidPortException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortInvalidPortException.java 3 | * 4 | * Created on: Apr 15, 2019 5 | * Last Updated on: Jun 08, 2022 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2022 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | /** 29 | * This class describes a serial port invalid port exception. 30 | * 31 | * @see java.lang.RuntimeException 32 | */ 33 | public final class SerialPortInvalidPortException extends RuntimeException 34 | { 35 | private static final long serialVersionUID = 3420177672598538224L; 36 | 37 | /** 38 | * Constructs a {@link SerialPortInvalidPortException} with the specified detail message and cause. 39 | *

40 | * Note that the detail message associated with cause is not automatically incorporated into this exception's detail message. 41 | * 42 | * @param message message The detail message (which is saved for later retrieval by the {@link SerialPortInvalidPortException#getMessage()} method). 43 | * @param cause The cause (which is saved for later retrieval by the {@link SerialPortInvalidPortException#getCause()} method). (A null value is permitted, and indicates that the cause is nonexistent or unknown.) 44 | */ 45 | public SerialPortInvalidPortException(String message, Throwable cause) 46 | { 47 | super(message, cause); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/SerialPortMessageListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortMessageListener.java 3 | * 4 | * Created on: Mar 14, 2019 5 | * Last Updated on: Jun 08, 2022 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2020 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | /** 29 | * This interface must be implemented to enable delimited message reads using event-based serial port I/O. 30 | *

31 | * Note: Using this interface will negate any serial port read timeout settings since they make no sense in an asynchronous context. 32 | * 33 | * @see com.fazecast.jSerialComm.SerialPortDataListener 34 | * @see java.util.EventListener 35 | */ 36 | public interface SerialPortMessageListener extends SerialPortDataListener 37 | { 38 | /** 39 | * Must be overridden to return the expected message delimiter bytes that must be encountered before the {@link #serialEvent(SerialPortEvent)} callback is triggered. 40 | * 41 | * @return A byte array containing the expected message delimiters that must be encountered before the {@link #serialEvent(SerialPortEvent)} callback is triggered. 42 | */ 43 | byte[] getMessageDelimiter(); 44 | 45 | /** 46 | * Must be overridden to return whether the message delimiter indicates the end or the beginning of a message. 47 | * 48 | * @return A boolean indicating whether the message delimiter indicates the end or the beginning of a message. 49 | */ 50 | boolean delimiterIndicatesEndOfMessage(); 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/SerialPortMessageListenerWithExceptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortMessageListenerWithExceptions.java 3 | * 4 | * Created on: Jan 03, 2020 5 | * Last Updated on: Jun 08, 2022 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2022 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | /** 29 | * This interface must be implemented to enable delimited message reads using event-based serial port I/O with a custom Exception callback. 30 | *

31 | * Note: Using this interface will negate any serial port read timeout settings since they make no sense in an asynchronous context. 32 | * 33 | * @see com.fazecast.jSerialComm.SerialPortMessageListener 34 | * @see com.fazecast.jSerialComm.SerialPortDataListener 35 | * @see java.util.EventListener 36 | */ 37 | public interface SerialPortMessageListenerWithExceptions extends SerialPortMessageListener 38 | { 39 | /** 40 | * Must be overridden to handle any Java exceptions that occur asynchronously in this data listener. 41 | * 42 | * @param e An {@link Exception} object containing information about the exception that occurred. 43 | */ 44 | void catchException(Exception e); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/SerialPortPacketListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortPacketListener.java 3 | * 4 | * Created on: Feb 25, 2015 5 | * Last Updated on: Jun 08, 2022 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2022 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | /** 29 | * This interface must be implemented to enable full packet reads using event-based serial port I/O. 30 | *

31 | * Note: Using this interface will negate any serial port read timeout settings since they make no sense in an asynchronous context. 32 | * 33 | * @see com.fazecast.jSerialComm.SerialPortDataListener 34 | * @see java.util.EventListener 35 | */ 36 | public interface SerialPortPacketListener extends SerialPortDataListener 37 | { 38 | /** 39 | * Must be overridden to return the desired number of bytes that must be read before the {@link #serialEvent(SerialPortEvent)} callback is triggered. 40 | * 41 | * @return The number of bytes that must be read before the {@link #serialEvent(SerialPortEvent)} callback is triggered. 42 | */ 43 | int getPacketSize(); 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/SerialPortThreadFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortThreadFactory.java 3 | * 4 | * Created on: May 31, 2022 5 | * Last Updated on: Jun 08, 2022 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2022 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | import java.util.concurrent.ThreadFactory; 29 | 30 | /** 31 | * This class is used to create internal jSerialComm threads. 32 | * 33 | * A user can call the {@link #set(ThreadFactory)} method to override the way in which threads are created. 34 | * 35 | * @see java.util.concurrent.ThreadFactory 36 | */ 37 | public class SerialPortThreadFactory 38 | { 39 | // Default ThreadFactory instance 40 | private static ThreadFactory instance = new ThreadFactory() 41 | { 42 | @Override 43 | public Thread newThread(Runnable r) { return new Thread(r); } 44 | }; 45 | 46 | /** 47 | * Returns the current {@link java.util.concurrent.ThreadFactory} instance associated with this library. 48 | * 49 | * @return The current {@link java.util.concurrent.ThreadFactory} instance. 50 | * @see java.util.concurrent.ThreadFactory 51 | */ 52 | public static ThreadFactory get() { return instance; } 53 | 54 | /** 55 | * Allows a user to define a custom thread factory to be used by this library for creating new threads. 56 | *

57 | * Such a custom factory method may be used, for example, to set all new threads to run as daemons. 58 | * 59 | * @param threadFactory A user-defined custom thread factory instance. 60 | * @see java.util.concurrent.ThreadFactory 61 | */ 62 | public static void set(ThreadFactory threadFactory) 63 | { 64 | instance = threadFactory; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/SerialPortTimeoutException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortTimeoutException.java 3 | * 4 | * Created on: Aug 08, 2018 5 | * Last Updated on: Jun 08, 2022 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2022 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | import java.io.InterruptedIOException; 29 | 30 | /** 31 | * This class describes a serial port timeout exception. 32 | * 33 | * @see java.io.InterruptedIOException 34 | */ 35 | public final class SerialPortTimeoutException extends InterruptedIOException 36 | { 37 | private static final long serialVersionUID = 3209035213903386044L; 38 | 39 | /** 40 | * Constructs a {@link SerialPortTimeoutException} with the specified detail message. 41 | * 42 | * @param message The detail message (which is saved for later retrieval by the {@link SerialPortTimeoutException#getMessage()} method). 43 | */ 44 | public SerialPortTimeoutException(String message) 45 | { 46 | super(message); 47 | bytesTransferred = 0; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/android/AndroidPort.java: -------------------------------------------------------------------------------- 1 | /* 2 | * AndroidPort.java 3 | * 4 | * Created on: Feb 15, 2022 5 | * Last Updated on: Jul 27, 2023 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2022-2023 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm.android; 27 | 28 | import com.fazecast.jSerialComm.SerialPort; 29 | 30 | import android.app.Application; 31 | import android.app.PendingIntent; 32 | import android.content.BroadcastReceiver; 33 | import android.content.Context; 34 | import android.content.Intent; 35 | import android.content.IntentFilter; 36 | import android.content.pm.PackageManager; 37 | import android.hardware.usb.UsbDevice; 38 | import android.hardware.usb.UsbDeviceConnection; 39 | import android.hardware.usb.UsbEndpoint; 40 | import android.hardware.usb.UsbInterface; 41 | import android.hardware.usb.UsbManager; 42 | import android.util.Log; 43 | 44 | import java.lang.reflect.Constructor; 45 | import java.lang.reflect.Field; 46 | import java.util.HashMap; 47 | 48 | public abstract class AndroidPort 49 | { 50 | // USB request and recipient types 51 | protected static final int USB_REQUEST_TYPE_STANDARD = 0; 52 | protected static final int USB_REQUEST_TYPE_CLASS = 0x01 << 5; 53 | protected static final int USB_REQUEST_TYPE_VENDOR = 0x02 << 5; 54 | protected static final int USB_REQUEST_TYPE_RESERVED = 0x03 << 5; 55 | protected static final int USB_ENDPOINT_IN = 0x80; 56 | protected static final int USB_ENDPOINT_OUT = 0x00; 57 | protected static final int USB_RECIPIENT_DEVICE = 0x00; 58 | protected static final int USB_RECIPIENT_INTERFACE = 0x01; 59 | protected static final int USB_RECIPIENT_ENDPOINT = 0x02; 60 | protected static final int USB_RECIPIENT_OTHER = 0x03; 61 | 62 | // Static shared port parameters 63 | protected static Application context = null; 64 | protected static UsbManager usbManager = null; 65 | 66 | // Static private port parameters 67 | private static final String ACTION_USB_PERMISSION = "com.fazecast.jSerialComm.USB_PERMISSION"; 68 | private static volatile boolean userPermissionGranted = false, awaitingUserPermission = false; 69 | private static PendingIntent permissionIntent = null; 70 | 71 | // Shared serial port parameters 72 | protected final UsbDevice usbDevice; 73 | protected UsbInterface usbInterface = null; 74 | protected UsbDeviceConnection usbConnection = null; 75 | protected UsbEndpoint usbDeviceIn = null, usbDeviceOut = null; 76 | protected volatile int writeBufferIndex = 0, writeBufferLength = 1024; 77 | protected volatile int readBufferIndex = 0, readBufferOffset = 0, readBufferLength = 1024; 78 | protected final byte[] readBuffer = new byte[readBufferLength], writeBuffer = new byte[writeBufferLength]; 79 | 80 | // Private constructor so that class can only be created by the enumeration method 81 | protected AndroidPort(UsbDevice device) { usbDevice = device; } 82 | 83 | // Method to set the Android application context 84 | public static void setAndroidContext(Object androidContext) { context = Application.class.cast(androidContext); } 85 | 86 | // USB event handler 87 | private static final BroadcastReceiver usbReceiver = new BroadcastReceiver() { 88 | public void onReceive(Context context, Intent intent) { 89 | if (intent.getAction().equals(ACTION_USB_PERMISSION)) { 90 | synchronized (AndroidPort.class) { 91 | userPermissionGranted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false); 92 | awaitingUserPermission = false; 93 | AndroidPort.class.notifyAll(); 94 | } 95 | } else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) { 96 | UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 97 | if (device != null) 98 | Log.i("jSerialComm", "Port was disconnected. Need TODO something"); 99 | // TODO: Alert event waiting thread, close port, set to null 100 | } 101 | } 102 | }; 103 | 104 | // Port enumeration method 105 | public static SerialPort[] getCommPortsNative() 106 | { 107 | // Ensure that the Android application context has been specified 108 | if (context == null) 109 | throw new RuntimeException("The Android application context must be specified using 'setAndroidContext()' before making any jSerialComm library calls."); 110 | 111 | // Ensure that the device has a USB Manager 112 | if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_HOST)) 113 | return new SerialPort[0]; 114 | 115 | // Register a listener to handle permission request responses 116 | if (permissionIntent == null) { 117 | permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0); 118 | IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); 119 | filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); 120 | context.registerReceiver(usbReceiver, filter); 121 | } 122 | 123 | // Enumerate all serial ports on the device 124 | usbManager = (UsbManager)context.getApplicationContext().getSystemService(Context.USB_SERVICE); 125 | HashMap deviceList = usbManager.getDeviceList(); 126 | SerialPort[] portsList = new SerialPort[deviceList.size()]; 127 | 128 | // Create and return the SerialPort port listing 129 | int i = 0; 130 | for (UsbDevice device : deviceList.values()) { 131 | // TODO: Determine the type of port 132 | AndroidPort androidPort = null; 133 | 134 | // Create a new serial port object and add it to the port listing 135 | SerialPort serialPort = null; 136 | try { 137 | Constructor serialPortConstructor = SerialPort.class.getDeclaredConstructor(String.class, String.class, String.class, String.class, String.class, int.class, int.class); 138 | serialPortConstructor.setAccessible(true); 139 | serialPort = serialPortConstructor.newInstance("COM" + (i+1), device.getDeviceName(), device.getProductName(), device.getSerialNumber(), device.getSerialNumber(), device.getVendorId(), device.getProductId()); 140 | Field privateAndroidPort = SerialPort.class.getDeclaredField("androidPort"); 141 | privateAndroidPort.setAccessible(true); 142 | privateAndroidPort.set(serialPort, androidPort); 143 | portsList[i++] = serialPort; 144 | } catch (Exception e) { 145 | e.printStackTrace(); 146 | continue; 147 | } 148 | 149 | Log.i("jSerialComm", "System Port Name: " + serialPort.getSystemPortName()); 150 | Log.i("jSerialComm", "System Port Path: " + serialPort.getSystemPortPath()); 151 | Log.i("jSerialComm", "Descriptive Port Name: " + serialPort.getDescriptivePortName()); 152 | Log.i("jSerialComm", "Port Description: " + serialPort.getPortDescription()); 153 | Log.i("jSerialComm", "Serial Number: " + serialPort.getSerialNumber()); 154 | Log.i("jSerialComm", "Location: " + serialPort.getPortLocation()); 155 | Log.i("jSerialComm", "Vendor ID: " + serialPort.getVendorID()); 156 | Log.i("jSerialComm", "Product ID: " + serialPort.getProductID()); 157 | } 158 | return portsList; 159 | } 160 | 161 | // Native port opening method 162 | public long openPortNative(SerialPort serialPort) 163 | { 164 | // Obtain user permission to open the port 165 | if (!usbManager.hasPermission(usbDevice)) { 166 | synchronized (AndroidPort.class) { 167 | awaitingUserPermission = true; 168 | while (awaitingUserPermission) { 169 | usbManager.requestPermission(usbDevice, permissionIntent); 170 | try { AndroidPort.class.wait(); } catch (InterruptedException ignored) { } 171 | } 172 | if (!userPermissionGranted) 173 | return 0L; 174 | } 175 | } 176 | 177 | // Open and configure the port using chip-specific methods 178 | usbConnection = usbManager.openDevice(usbDevice); 179 | if ((usbConnection == null) || !openPort() || !configPort(serialPort)) 180 | closePortNative(); 181 | 182 | // Return whether the port was successfully opened 183 | return (usbConnection != null) ? 1L: 0L; 184 | } 185 | 186 | // Native port closing method 187 | public long closePortNative() 188 | { 189 | // Close the port using chip-specific methods 190 | if ((usbConnection != null) && closePort()) { 191 | usbConnection.close(); 192 | usbConnection = null; 193 | usbInterface = null; 194 | usbDeviceOut = null; 195 | usbDeviceIn = null; 196 | } 197 | 198 | // Return whether the port was successfully closed 199 | return (usbConnection == null) ? 0L : 1L; 200 | } 201 | 202 | // Shared VID/PID-to-long creation method 203 | protected static long makeVidPid(int vid, int pid) { return (((long)vid << 16) & 0xFFFF0000) | ((long)pid & 0x0000FFFF); } 204 | 205 | // Android Port required interface 206 | public abstract boolean openPort(); 207 | public abstract boolean closePort(); 208 | public abstract boolean configPort(SerialPort serialPort); 209 | public abstract boolean flushRxTxBuffers(); 210 | public abstract int waitForEvent(); 211 | public abstract int bytesAvailable(); 212 | public abstract int bytesAwaitingWrite(); 213 | public abstract int readBytes(byte[] buffer, long bytesToRead, long offset, int timeoutMode, int readTimeout); 214 | public abstract int writeBytes(byte[] buffer, long bytesToWrite, long offset, int timeoutMode); 215 | public abstract void setEventListeningStatus(boolean eventListenerRunning); 216 | public abstract boolean setBreak(); 217 | public abstract boolean clearBreak(); 218 | public abstract boolean setRTS(); 219 | public abstract boolean clearRTS(); 220 | public abstract boolean setDTR(); 221 | public abstract boolean clearDTR(); 222 | public abstract boolean getCTS(); 223 | public abstract boolean getDSR(); 224 | public abstract boolean getDCD(); 225 | public abstract boolean getDTR(); 226 | public abstract boolean getRTS(); 227 | public abstract boolean getRI(); 228 | public abstract int getLastErrorLocation(); 229 | public abstract int getLastErrorCode(); 230 | } 231 | -------------------------------------------------------------------------------- /src/main/java/com/fazecast/jSerialComm/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * package-info.java 3 | * 4 | * Created on: Jun 08, 2022 5 | * Last Updated on: Jun 29, 2023 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2023 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | /** 27 | * This package contains all of the classes and interfaces that make up the 28 | * Java serial communications library. 29 | * 30 | * @author Will Hedgecock <will.hedgecock@fazecast.com> 31 | * @version 2.11.1 32 | */ 33 | package com.fazecast.jSerialComm; 34 | -------------------------------------------------------------------------------- /src/main/resources/Android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/main/resources/Android/arm64-v8a/libjSerialComm.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fazecast/jSerialComm/a8a307deed68bca2dda3048c1ecc5481eb5783fb/src/main/resources/Android/arm64-v8a/libjSerialComm.so -------------------------------------------------------------------------------- /src/main/resources/Android/armeabi-v7a/libjSerialComm.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fazecast/jSerialComm/a8a307deed68bca2dda3048c1ecc5481eb5783fb/src/main/resources/Android/armeabi-v7a/libjSerialComm.so -------------------------------------------------------------------------------- /src/main/resources/Android/x86/libjSerialComm.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fazecast/jSerialComm/a8a307deed68bca2dda3048c1ecc5481eb5783fb/src/main/resources/Android/x86/libjSerialComm.so -------------------------------------------------------------------------------- /src/main/resources/Android/x86_64/libjSerialComm.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fazecast/jSerialComm/a8a307deed68bca2dda3048c1ecc5481eb5783fb/src/main/resources/Android/x86_64/libjSerialComm.so -------------------------------------------------------------------------------- /src/moduleInfo/java/module-info.java: -------------------------------------------------------------------------------- 1 | module com.fazecast.jSerialComm { 2 | exports com.fazecast.jSerialComm; 3 | } -------------------------------------------------------------------------------- /src/test/c/Makefile: -------------------------------------------------------------------------------- 1 | # Compiler tools, commands, and flags 2 | COMPILE = gcc 3 | COMPILE_WIN = cl 4 | LINK = gcc 5 | LINK_WIN = link 6 | BUILD_DIR = build 7 | JDK_HOME = $(shell if [ "`uname`" = "Darwin" ]; then echo "`/usr/libexec/java_home`"; else echo "$$JDK_HOME"; fi) 8 | INCLUDES = -I"../../main/c/Posix" -I"../../main/c/Windows" -I"$(JDK_HOME)/include" -I"$(JDK_HOME)/include/win32" -I"$(JDK_HOME)/include/linux" -I"$(JDK_HOME)/include/darwin" -I"$(JDK_HOME)/include/solaris" 9 | CFLAGS = -fPIC -O0 -g -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 $(shell if [ "`uname`" != "Darwin" ]; then echo "-static-libgcc"; fi) 10 | CFLAGS_WIN = /c /O2 /GF /GL /MT /EHsc /fp:precise /J /nologo /TC /Zi 11 | LDFLAGS = -O0 -g $(shell if [ "`uname`" != "Darwin" ]; then echo "-static-libgcc"; fi) 12 | LDFLAGS_WIN = /LTCG /NOLOGO /INCREMENTAL:NO /DEBUG /OPT:REF,ICF,LBR 13 | LIBRARIES = $(shell if [ "`uname`" = "Darwin" ]; then echo "-framework Cocoa -framework IOKit"; else echo "-pthread"; fi) 14 | LIBRARIES_WIN = Advapi32.lib SetupAPI.lib Shell32.lib 15 | DELETE = @rm 16 | MKDIR = @mkdir -p 17 | COPY = @cp 18 | MOVE = @mv 19 | PRINT = @echo 20 | 21 | # Define phony and suffix rules 22 | .PHONY: all clean 23 | .SUFFIXES: 24 | .SUFFIXES: .cpp .c .o .h 25 | vpath %.c ../../main/c/Posix ../../main/c/Windows 26 | 27 | # Default build target does nothing 28 | all : 29 | $(PRINT) You must specify a specify test to make! 30 | clean : 31 | $(DELETE) -rf "$(BUILD_DIR)" 32 | $(DELETE) -rf *.pdb *.exe 33 | 34 | # Rule to create build directories 35 | $(BUILD_DIR) : 36 | $(MKDIR) -p $@ 37 | 38 | # Build rules for all tests 39 | testOpenClose : $(BUILD_DIR)/testOpenClose.o $(BUILD_DIR)/PosixHelperFunctions.o 40 | $(LINK) $(LDFLAGS) $(LIBRARIES) -o $@ $^ 41 | testRS485 : $(BUILD_DIR)/testRS485.o 42 | $(LINK) $(LDFLAGS) $(LIBRARIES) -o $@ $^ 43 | testEnumeratePosix : $(BUILD_DIR)/testEnumeratePosix.o $(BUILD_DIR)/PosixHelperFunctions.o 44 | $(LINK) $(LDFLAGS) $(LIBRARIES) -o $@ $^ 45 | testEnumerateWindows : $(BUILD_DIR)/testEnumerateWindows.obj $(BUILD_DIR)/WindowsHelperFunctions.obj 46 | $(LINK_WIN) $(LDFLAGS_WIN) /OUT:$@.exe $^ $(LIBRARIES_WIN) 47 | testEventsWindows : $(BUILD_DIR)/testEventsWindows.obj $(BUILD_DIR)/WindowsHelperFunctions.obj 48 | $(LINK_WIN) $(LDFLAGS_WIN) /OUT:$@.exe $^ $(LIBRARIES_WIN) 49 | testPollPosix : $(BUILD_DIR)/testPollPosix.o $(BUILD_DIR)/PosixHelperFunctions.o 50 | $(LINK) $(LDFLAGS) $(LIBRARIES) -o $@ $^ 51 | 52 | # Suffix rules to get from *.c -> *.o 53 | $(BUILD_DIR)/testEnumerateWindows.obj : testEnumerateWindows.c 54 | $(MKDIR) $(BUILD_DIR) 55 | $(COPY) ../../main/c/Posix/*.h ../../main/c/ 56 | $(COMPILE_WIN) $(INCLUDES) $(CFLAGS_WIN) -c $< -Fo$@ 57 | $(DELETE) ../../main/c/*.h 58 | $(BUILD_DIR)/testEventsWindows.obj : testEventsWindows.c 59 | $(MKDIR) $(BUILD_DIR) 60 | $(COPY) ../../main/c/Posix/*.h ../../main/c/ 61 | $(COMPILE_WIN) $(INCLUDES) $(CFLAGS_WIN) -c $< -Fo$@ 62 | $(DELETE) ../../main/c/*.h 63 | $(BUILD_DIR)/WindowsHelperFunctions.obj : WindowsHelperFunctions.c 64 | $(MKDIR) $(BUILD_DIR) 65 | $(COPY) ../../main/c/Posix/*.h ../../main/c/ 66 | $(COMPILE_WIN) $(INCLUDES) $(CFLAGS_WIN) -c $< -Fo$@ 67 | $(DELETE) ../../main/c/*.h 68 | $(BUILD_DIR)/%.o : %.c 69 | $(MKDIR) $(BUILD_DIR) 70 | $(COMPILE) $(INCLUDES) $(CFLAGS) -c $< -o $@ 71 | -------------------------------------------------------------------------------- /src/test/c/testEnumeratePosix.c: -------------------------------------------------------------------------------- 1 | #include "PosixHelperFunctions.h" 2 | 3 | static serialPortVector comPorts = { NULL, 0, 0 }; 4 | 5 | int main(void) 6 | { 7 | // Enumerate all serial ports 8 | searchForComPorts(&comPorts); 9 | 10 | // Output all enumerated ports 11 | printf("Initial enumeration:\n\n"); 12 | for (int i = 0; i < comPorts.length; ++i) 13 | { 14 | serialPort *port = comPorts.ports[i]; 15 | printf("\t%s: Friendly Name = %s, Description = %s, Location = %s, VID/PID = %04X/%04X, Serial = %s\n", port->portPath, port->friendlyName, port->portDescription, port->portLocation, port->vendorID, port->productID, port->serialNumber); 16 | } 17 | 18 | // Reset the enumerated flag on all non-open serial ports 19 | for (int i = 0; i < comPorts.length; ++i) 20 | comPorts.ports[i]->enumerated = (comPorts.ports[i]->handle > 0); 21 | 22 | // Re-enumerate all serial ports 23 | searchForComPorts(&comPorts); 24 | 25 | // Remove all non-enumerated ports from the serial port listing 26 | for (int i = 0; i < comPorts.length; ++i) 27 | if (!comPorts.ports[i]->enumerated) 28 | { 29 | removePort(&comPorts, comPorts.ports[i]); 30 | i--; 31 | } 32 | 33 | // Output all enumerated ports once again 34 | printf("\nSecond enumeration:\n\n"); 35 | for (int i = 0; i < comPorts.length; ++i) 36 | { 37 | serialPort *port = comPorts.ports[i]; 38 | printf("\t%s: Friendly Name = %s, Description = %s, Location = %s, VID/PID = %04X/%04X, Serial = %s\n", port->portPath, port->friendlyName, port->portDescription, port->portLocation, port->vendorID, port->productID, port->serialNumber); 39 | } 40 | 41 | // Clean up all memory and return 42 | cleanUpVector(&comPorts); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/test/c/testEventsWindows.c: -------------------------------------------------------------------------------- 1 | #define WINVER _WIN32_WINNT_VISTA 2 | #define _WIN32_WINNT _WIN32_WINNT_VISTA 3 | #define NTDDI_VERSION NTDDI_VISTA 4 | #define WIN32_LEAN_AND_MEAN 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "../../main/c/Windows/ftdi/ftd2xx.h" 17 | #include "WindowsHelperFunctions.h" 18 | 19 | static const int eventsToMonitor = com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED | com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED; 20 | static const int timeoutMode = com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING; 21 | static const DWORD readTimeout = 0, writeTimeout = 0; 22 | 23 | BOOL configPort(void *portHandle) 24 | { 25 | // Retrieve existing port configuration 26 | DCB dcbSerialParams; 27 | memset(&dcbSerialParams, 0, sizeof(DCB)); 28 | dcbSerialParams.DCBlength = sizeof(DCB); 29 | DWORD receiveDeviceQueueSize = 4096, sendDeviceQueueSize = 4096; 30 | if (!SetupComm(portHandle, receiveDeviceQueueSize, sendDeviceQueueSize) || !GetCommState(portHandle, &dcbSerialParams)) 31 | { 32 | printf("Error Line = %d, Code = %d\n", __LINE__ - 2, GetLastError()); 33 | return FALSE; 34 | } 35 | 36 | // Set updated port parameters 37 | dcbSerialParams.BaudRate = 9600; 38 | dcbSerialParams.ByteSize = 8; 39 | dcbSerialParams.StopBits = ONESTOPBIT; 40 | dcbSerialParams.Parity = NOPARITY; 41 | dcbSerialParams.fParity = FALSE; 42 | dcbSerialParams.fBinary = TRUE; 43 | dcbSerialParams.fAbortOnError = FALSE; 44 | dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE; 45 | dcbSerialParams.fOutxCtsFlow = FALSE; 46 | dcbSerialParams.fOutxDsrFlow = FALSE; 47 | dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE; 48 | dcbSerialParams.fDsrSensitivity = FALSE; 49 | dcbSerialParams.fOutX = FALSE; 50 | dcbSerialParams.fInX = FALSE; 51 | dcbSerialParams.fTXContinueOnXoff = TRUE; 52 | dcbSerialParams.fErrorChar = FALSE; 53 | dcbSerialParams.fNull = FALSE; 54 | dcbSerialParams.XonLim = 2048; 55 | dcbSerialParams.XoffLim = 512; 56 | dcbSerialParams.XonChar = 17; 57 | dcbSerialParams.XoffChar = 19; 58 | 59 | // Apply changes 60 | if (!SetCommState(portHandle, &dcbSerialParams)) 61 | { 62 | printf("Error Line = %d, Code = %d\n", __LINE__ - 2, GetLastError()); 63 | return FALSE; 64 | } 65 | 66 | // Get event flags from the Java class 67 | int eventFlags = EV_ERR; 68 | if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) || (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED)) 69 | eventFlags |= EV_RXCHAR; 70 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN) 71 | eventFlags |= EV_TXEMPTY; 72 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT) 73 | eventFlags |= EV_BREAK; 74 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CTS) 75 | eventFlags |= EV_CTS; 76 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DSR) 77 | eventFlags |= EV_DSR; 78 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_RING_INDICATOR) 79 | eventFlags |= EV_RING; 80 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CARRIER_DETECT) 81 | eventFlags |= EV_RLSD; 82 | 83 | // Set updated port timeouts 84 | COMMTIMEOUTS timeouts; 85 | memset(&timeouts, 0, sizeof(COMMTIMEOUTS)); 86 | timeouts.WriteTotalTimeoutMultiplier = 0; 87 | if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) 88 | { 89 | // Force specific read timeouts if we are monitoring data received 90 | timeouts.ReadIntervalTimeout = MAXDWORD; 91 | timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; 92 | timeouts.ReadTotalTimeoutConstant = 1000; 93 | timeouts.WriteTotalTimeoutConstant = 0; 94 | } 95 | else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER) 96 | { 97 | timeouts.ReadIntervalTimeout = MAXDWORD; 98 | timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; 99 | timeouts.ReadTotalTimeoutConstant = 0x0FFFFFFF; 100 | timeouts.WriteTotalTimeoutConstant = writeTimeout; 101 | } 102 | else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) 103 | { 104 | timeouts.ReadIntervalTimeout = MAXDWORD; 105 | timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; 106 | timeouts.ReadTotalTimeoutConstant = readTimeout ? readTimeout : 0x0FFFFFFF; 107 | timeouts.WriteTotalTimeoutConstant = writeTimeout; 108 | } 109 | else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) 110 | { 111 | timeouts.ReadIntervalTimeout = 0; 112 | timeouts.ReadTotalTimeoutMultiplier = 0; 113 | timeouts.ReadTotalTimeoutConstant = readTimeout; 114 | timeouts.WriteTotalTimeoutConstant = writeTimeout; 115 | } 116 | else // Non-blocking 117 | { 118 | timeouts.ReadIntervalTimeout = MAXDWORD; 119 | timeouts.ReadTotalTimeoutMultiplier = 0; 120 | timeouts.ReadTotalTimeoutConstant = 0; 121 | timeouts.WriteTotalTimeoutConstant = writeTimeout; 122 | } 123 | 124 | // Apply changes 125 | if (!SetCommTimeouts(portHandle, &timeouts) || !SetCommMask(portHandle, eventFlags)) 126 | { 127 | printf("Error Line = %d, Code = %d\n", __LINE__ - 2, GetLastError()); 128 | return FALSE; 129 | } 130 | return TRUE; 131 | } 132 | 133 | void* openPortNative(const char *portName) 134 | { 135 | // Try to open the serial port with read/write access 136 | void *portHandle = CreateFileA(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL); 137 | if (portHandle != INVALID_HANDLE_VALUE) 138 | { 139 | // Configure the port parameters and timeouts 140 | if (!configPort(portHandle)) 141 | { 142 | // Close the port if there was a problem setting the parameters 143 | PurgeComm(portHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); 144 | if (CancelIoEx) 145 | CancelIoEx(portHandle, NULL); 146 | SetCommMask(portHandle, 0); 147 | CloseHandle(portHandle); 148 | portHandle = INVALID_HANDLE_VALUE; 149 | } 150 | } 151 | return portHandle; 152 | } 153 | 154 | void closePortNative(void *portHandle) 155 | { 156 | // Force the port to enter non-blocking mode to ensure that any current reads return 157 | COMMTIMEOUTS timeouts; 158 | memset(&timeouts, 0, sizeof(COMMTIMEOUTS)); 159 | timeouts.WriteTotalTimeoutMultiplier = 0; 160 | timeouts.ReadIntervalTimeout = MAXDWORD; 161 | timeouts.ReadTotalTimeoutMultiplier = 0; 162 | timeouts.ReadTotalTimeoutConstant = 0; 163 | timeouts.WriteTotalTimeoutConstant = 0; 164 | SetCommTimeouts(portHandle, &timeouts); 165 | 166 | // Purge any outstanding port operations 167 | PurgeComm(portHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); 168 | if (CancelIoEx) 169 | CancelIoEx(portHandle, NULL); 170 | SetCommMask(portHandle, 0); 171 | 172 | // Close the port 173 | if (!CloseHandle(portHandle)) 174 | printf("Error Line = %d, Code = %d\n", __LINE__ - 1, GetLastError()); 175 | } 176 | 177 | int waitForEvent(void *portHandle) 178 | { 179 | // Create an asynchronous event structure 180 | OVERLAPPED overlappedStruct; 181 | memset(&overlappedStruct, 0, sizeof(OVERLAPPED)); 182 | overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 183 | int event = com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_TIMED_OUT; 184 | if (!overlappedStruct.hEvent) 185 | { 186 | printf("Error Line = %d, Code = %d\n", __LINE__ - 3, GetLastError()); 187 | return event; 188 | } 189 | 190 | // Wait for a serial port event 191 | DWORD eventMask = 0, errorMask = 0, waitValue, numBytesTransferred; 192 | if (!WaitCommEvent(portHandle, &eventMask, &overlappedStruct)) 193 | { 194 | if ((GetLastError() == ERROR_IO_PENDING) || (GetLastError() == ERROR_INVALID_PARAMETER)) 195 | { 196 | do { waitValue = WaitForSingleObject(overlappedStruct.hEvent, 500); } 197 | while (waitValue == WAIT_TIMEOUT); 198 | if ((waitValue != WAIT_OBJECT_0) || !GetOverlappedResult(portHandle, &overlappedStruct, &numBytesTransferred, FALSE)) 199 | { 200 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED; 201 | printf("Error Line = %d, Code = %d, Wait Value = %d\n", __LINE__ - 3, GetLastError(), waitValue); 202 | CloseHandle(overlappedStruct.hEvent); 203 | return event; 204 | } 205 | } 206 | else // Problem occurred 207 | { 208 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED; 209 | printf("Error Line = %d, Code = %d\n", __LINE__ - 17, GetLastError()); 210 | CloseHandle(overlappedStruct.hEvent); 211 | return event; 212 | } 213 | } 214 | 215 | // Retrieve and clear any serial port errors 216 | COMSTAT commInfo; 217 | if (ClearCommError(portHandle, &errorMask, &commInfo)) 218 | { 219 | if (errorMask & CE_BREAK) 220 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT; 221 | if (errorMask & CE_FRAME) 222 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_FRAMING_ERROR; 223 | if (errorMask & CE_OVERRUN) 224 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR; 225 | if (errorMask & CE_RXOVER) 226 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR; 227 | if (errorMask & CE_RXPARITY) 228 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PARITY_ERROR; 229 | } 230 | 231 | // Parse any received serial port events 232 | if (eventMask & EV_BREAK) 233 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT; 234 | if (eventMask & EV_TXEMPTY) 235 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN; 236 | if ((eventMask & EV_RXCHAR) && (commInfo.cbInQue > 0)) 237 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE; 238 | if (eventMask & EV_CTS) 239 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CTS; 240 | if (eventMask & EV_DSR) 241 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DSR; 242 | if (eventMask & EV_RING) 243 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_RING_INDICATOR; 244 | if (eventMask & EV_RLSD) 245 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CARRIER_DETECT; 246 | 247 | // Return the serial event type 248 | CloseHandle(overlappedStruct.hEvent); 249 | return event; 250 | } 251 | 252 | int main(int argc, char *argv[]) 253 | { 254 | // Check for correct input parameters 255 | if (argc != 2) 256 | { 257 | printf("USAGE: ./testEventsWindows [PORT_FILE_NAME]\n"); 258 | return -1; 259 | } 260 | 261 | // Open the serial port 262 | void *portHandle = INVALID_HANDLE_VALUE; 263 | if ((portHandle = openPortNative(argv[1])) == INVALID_HANDLE_VALUE) 264 | { 265 | printf("ERROR: Could not open port: %s\n", argv[1]); 266 | return -2; 267 | } 268 | printf("Port opened\n"); 269 | 270 | // Wait forever for incoming events 271 | int events = 0; 272 | while ((events & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED) == 0) 273 | { 274 | events = waitForEvent(portHandle); 275 | printf("Received Events: %d\n", events); 276 | if (events & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED) 277 | printf(" Including LISTENING_EVENT_PORT_DISCONNECTED\n"); 278 | if (events & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) 279 | printf(" Including LISTENING_EVENT_DATA_AVAILABLE\n"); 280 | if (events & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN) 281 | printf(" Including LISTENING_EVENT_DATA_WRITTEN\n"); 282 | } 283 | 284 | // Close the serial port 285 | closePortNative(portHandle); 286 | return 0; 287 | } 288 | -------------------------------------------------------------------------------- /src/test/c/testOpenClose.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #if defined(__linux__) 13 | #include 14 | #define termios asmtermios 15 | #define termio asmtermio 16 | #define winsize asmwinsize 17 | #include 18 | #include 19 | #undef termio 20 | #undef termios 21 | #undef winsize 22 | #ifndef SER_RS485_TERMINATE_BUS 23 | #define SER_RS485_TERMINATE_BUS (1 << 5) 24 | #endif 25 | #elif defined(__APPLE__) 26 | #include 27 | #include 28 | #include 29 | #include 30 | #endif 31 | #include 32 | #include 33 | #include "PosixHelperFunctions.h" 34 | 35 | 36 | // Global static variables 37 | static volatile long portHandle = -1, readBufferLength = 0; 38 | static char *comPort = NULL, *readBuffer = NULL; 39 | 40 | 41 | // JNI functionality 42 | bool configTimeouts(long serialPortFD, int timeoutMode, int readTimeout, int writeTimeout, int eventsToMonitor) 43 | { 44 | // Get port timeouts from Java class 45 | int flags = 0; 46 | struct termios options = { 0 }; 47 | baud_rate baudRate = 9600; 48 | tcgetattr(serialPortFD, &options); 49 | 50 | // Set updated port timeouts 51 | if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) && (readTimeout > 0)) // Read Semi-blocking with timeout 52 | { 53 | options.c_cc[VMIN] = 0; 54 | options.c_cc[VTIME] = readTimeout / 100; 55 | } 56 | else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) // Read Semi-blocking without timeout 57 | { 58 | options.c_cc[VMIN] = 1; 59 | options.c_cc[VTIME] = 0; 60 | } 61 | else if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) && (readTimeout > 0)) // Read Blocking with timeout 62 | { 63 | options.c_cc[VMIN] = 0; 64 | options.c_cc[VTIME] = readTimeout / 100; 65 | } 66 | else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) // Read Blocking without timeout 67 | { 68 | options.c_cc[VMIN] = 1; 69 | options.c_cc[VTIME] = 0; 70 | } 71 | else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER) > 0) // Scanner Mode 72 | { 73 | options.c_cc[VMIN] = 1; 74 | options.c_cc[VTIME] = 1; 75 | } 76 | else // Non-blocking 77 | { 78 | flags = O_NONBLOCK; 79 | options.c_cc[VMIN] = 0; 80 | options.c_cc[VTIME] = 0; 81 | } 82 | 83 | // Apply changes 84 | if (fcntl(serialPortFD, F_SETFL, flags)) 85 | return false; 86 | if (tcsetattr(serialPortFD, TCSANOW, &options) || tcsetattr(serialPortFD, TCSANOW, &options)) 87 | return false; 88 | if (!getBaudRateCode(baudRate) && setBaudRateCustom(serialPortFD, baudRate)) 89 | return false; 90 | return true; 91 | } 92 | 93 | bool configPort(long serialPortFD) 94 | { 95 | // Get port parameters from Java class 96 | baud_rate baudRate = 9600; 97 | int byteSizeInt = 8; 98 | int stopBitsInt = 1; 99 | int parityInt = 0; 100 | int flowControl = 0; 101 | int sendDeviceQueueSize = 4096; 102 | int receiveDeviceQueueSize = 4096; 103 | int rs485DelayBefore = 0; 104 | int rs485DelayAfter = 0; 105 | int timeoutMode = 0; 106 | int readTimeout = 0; 107 | int writeTimeout = 0; 108 | int eventsToMonitor = 0; 109 | unsigned char rs485ModeEnabled = false; 110 | unsigned char rs485ActiveHigh = true; 111 | unsigned char rs485EnableTermination = false; 112 | unsigned char rs485RxDuringTx = false; 113 | unsigned char isDtrEnabled = true; 114 | unsigned char isRtsEnabled = true; 115 | char xonStartChar = 17; 116 | char xoffStopChar = 19; 117 | 118 | // Clear any serial port flags and set up raw non-canonical port parameters 119 | struct termios options = { 0 }; 120 | tcgetattr(serialPortFD, &options); 121 | options.c_cc[VSTART] = (unsigned char)xonStartChar; 122 | options.c_cc[VSTOP] = (unsigned char)xoffStopChar; 123 | options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | INPCK | IGNPAR | IGNCR | ICRNL | IXON | IXOFF); 124 | options.c_oflag &= ~OPOST; 125 | options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 126 | options.c_cflag &= ~(CSIZE | PARENB | CMSPAR | PARODD | CSTOPB | CRTSCTS); 127 | 128 | // Update the user-specified port parameters 129 | tcflag_t byteSize = (byteSizeInt == 5) ? CS5 : (byteSizeInt == 6) ? CS6 : (byteSizeInt == 7) ? CS7 : CS8; 130 | tcflag_t parity = (parityInt == com_fazecast_jSerialComm_SerialPort_NO_PARITY) ? 0 : (parityInt == com_fazecast_jSerialComm_SerialPort_ODD_PARITY) ? (PARENB | PARODD) : (parityInt == com_fazecast_jSerialComm_SerialPort_EVEN_PARITY) ? PARENB : (parityInt == com_fazecast_jSerialComm_SerialPort_MARK_PARITY) ? (PARENB | CMSPAR | PARODD) : (PARENB | CMSPAR); 131 | options.c_cflag |= (byteSize | parity | CLOCAL | CREAD); 132 | if (!isDtrEnabled || !isRtsEnabled) 133 | options.c_cflag &= ~HUPCL; 134 | if (!rs485ModeEnabled) 135 | options.c_iflag |= BRKINT; 136 | if (stopBitsInt == com_fazecast_jSerialComm_SerialPort_TWO_STOP_BITS) 137 | options.c_cflag |= CSTOPB; 138 | if (((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_CTS_ENABLED) > 0) || ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_RTS_ENABLED) > 0)) 139 | options.c_cflag |= CRTSCTS; 140 | if (byteSizeInt < 8) 141 | options.c_iflag |= ISTRIP; 142 | if (parityInt != 0) 143 | options.c_iflag |= (INPCK | IGNPAR); 144 | if ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_IN_ENABLED) > 0) 145 | options.c_iflag |= IXOFF; 146 | if ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED) > 0) 147 | options.c_iflag |= IXON; 148 | 149 | // Set baud rate and apply changes 150 | baud_rate baudRateCode = getBaudRateCode(baudRate); 151 | if (!baudRateCode) 152 | baudRateCode = B38400; 153 | cfsetispeed(&options, baudRateCode); 154 | cfsetospeed(&options, baudRateCode); 155 | if (tcsetattr(serialPortFD, TCSANOW, &options) || tcsetattr(serialPortFD, TCSANOW, &options)) 156 | return false; 157 | 158 | // Attempt to set the transmit buffer size and any necessary custom baud rates 159 | #if defined(__linux__) 160 | 161 | struct serial_struct serInfo = { 0 }; 162 | if (!ioctl(serialPortFD, TIOCGSERIAL, &serInfo)) 163 | { 164 | serInfo.xmit_fifo_size = sendDeviceQueueSize; 165 | serInfo.flags |= ASYNC_LOW_LATENCY; 166 | ioctl(serialPortFD, TIOCSSERIAL, &serInfo); 167 | } 168 | 169 | // Attempt to set the requested RS-485 mode 170 | struct serial_rs485 rs485Conf = { 0 }; 171 | if (!ioctl(serialPortFD, TIOCGRS485, &rs485Conf)) 172 | { 173 | if (rs485ModeEnabled) 174 | rs485Conf.flags |= SER_RS485_ENABLED; 175 | else 176 | rs485Conf.flags &= ~SER_RS485_ENABLED; 177 | if (rs485ActiveHigh) 178 | { 179 | rs485Conf.flags |= SER_RS485_RTS_ON_SEND; 180 | rs485Conf.flags &= ~(SER_RS485_RTS_AFTER_SEND); 181 | } 182 | else 183 | { 184 | rs485Conf.flags &= ~(SER_RS485_RTS_ON_SEND); 185 | rs485Conf.flags |= SER_RS485_RTS_AFTER_SEND; 186 | } 187 | if (rs485RxDuringTx) 188 | rs485Conf.flags |= SER_RS485_RX_DURING_TX; 189 | else 190 | rs485Conf.flags &= ~(SER_RS485_RX_DURING_TX); 191 | if (rs485EnableTermination) 192 | rs485Conf.flags |= SER_RS485_TERMINATE_BUS; 193 | else 194 | rs485Conf.flags &= ~(SER_RS485_TERMINATE_BUS); 195 | rs485Conf.delay_rts_before_send = rs485DelayBefore / 1000; 196 | rs485Conf.delay_rts_after_send = rs485DelayAfter / 1000; 197 | if (ioctl(serialPortFD, TIOCSRS485, &rs485Conf)) 198 | return false; 199 | } 200 | #endif 201 | 202 | // Configure the serial port read and write timeouts 203 | return configTimeouts(serialPortFD, timeoutMode, readTimeout, writeTimeout, eventsToMonitor); 204 | } 205 | 206 | long openPortNative(void) 207 | { 208 | const char *portName = comPort; 209 | unsigned char disableExclusiveLock = false; 210 | unsigned char disableAutoConfig = false; 211 | 212 | // Try to open existing serial port with read/write access 213 | int serialPortFD = -1; 214 | if ((serialPortFD = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC)) > 0) 215 | { 216 | // Ensure that multiple root users cannot access the device simultaneously 217 | if (!disableExclusiveLock && flock(serialPortFD, LOCK_EX | LOCK_NB)) 218 | { 219 | while (close(serialPortFD) && (errno == EINTR)) 220 | errno = 0; 221 | serialPortFD = -1; 222 | } 223 | else if (!disableAutoConfig && !configPort(serialPortFD)) 224 | { 225 | // Close the port if there was a problem setting the parameters 226 | fcntl(serialPortFD, F_SETFL, O_NONBLOCK); 227 | while ((close(serialPortFD) == -1) && (errno == EINTR)) 228 | errno = 0; 229 | serialPortFD = -1; 230 | } 231 | } 232 | 233 | return serialPortFD; 234 | } 235 | 236 | long closePortNative(long serialPortFD) 237 | { 238 | // Force the port to enter non-blocking mode to ensure that any current reads return 239 | struct termios options = { 0 }; 240 | tcgetattr(serialPortFD, &options); 241 | options.c_cc[VMIN] = 0; 242 | options.c_cc[VTIME] = 0; 243 | fcntl(serialPortFD, F_SETFL, O_NONBLOCK); 244 | tcsetattr(serialPortFD, TCSANOW, &options); 245 | tcsetattr(serialPortFD, TCSANOW, &options); 246 | 247 | // Unblock, unlock, and close the port 248 | fsync(serialPortFD); 249 | tcdrain(serialPortFD); 250 | tcflush(serialPortFD, TCIOFLUSH); 251 | flock(serialPortFD, LOCK_UN | LOCK_NB); 252 | while (close(serialPortFD) && (errno == EINTR)) 253 | errno = 0; 254 | serialPortFD = -1; 255 | return -1; 256 | } 257 | 258 | int readBytes(long serialPortFD, char* buffer, long bytesToRead, long offset, int timeoutMode, int readTimeout) 259 | { 260 | // Ensure that the allocated read buffer is large enough 261 | int numBytesRead, numBytesReadTotal = 0, bytesRemaining = bytesToRead, ioctlResult = 0; 262 | if (bytesToRead > readBufferLength) 263 | { 264 | char *newMemory = (char*)realloc(readBuffer, bytesToRead); 265 | if (!newMemory) 266 | return -1; 267 | readBuffer = newMemory; 268 | readBufferLength = bytesToRead; 269 | } 270 | 271 | // Infinite blocking mode specified, don't return until we have completely finished the read 272 | if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) && (readTimeout == 0)) 273 | { 274 | // While there are more bytes we are supposed to read 275 | while (bytesRemaining > 0) 276 | { 277 | // Attempt to read some number of bytes from the serial port 278 | do { errno = 0; numBytesRead = read(serialPortFD, readBuffer + numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR)); 279 | if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1))) 280 | break; 281 | 282 | // Fix index variables 283 | numBytesReadTotal += numBytesRead; 284 | bytesRemaining -= numBytesRead; 285 | } 286 | } 287 | else if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING) > 0) // Blocking mode, but not indefinitely 288 | { 289 | // Get current system time 290 | struct timeval expireTime = { 0 }, currTime = { 0 }; 291 | gettimeofday(&expireTime, NULL); 292 | expireTime.tv_usec += (readTimeout * 1000); 293 | if (expireTime.tv_usec > 1000000) 294 | { 295 | expireTime.tv_sec += (expireTime.tv_usec * 0.000001); 296 | expireTime.tv_usec = (expireTime.tv_usec % 1000000); 297 | } 298 | 299 | // While there are more bytes we are supposed to read and the timeout has not elapsed 300 | do 301 | { 302 | do { errno = 0; numBytesRead = read(serialPortFD, readBuffer + numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR)); 303 | if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1))) 304 | break; 305 | 306 | // Fix index variables 307 | numBytesReadTotal += numBytesRead; 308 | bytesRemaining -= numBytesRead; 309 | 310 | // Get current system time 311 | gettimeofday(&currTime, NULL); 312 | } while ((bytesRemaining > 0) && ((expireTime.tv_sec > currTime.tv_sec) || ((expireTime.tv_sec == currTime.tv_sec) && (expireTime.tv_usec > currTime.tv_usec)))); 313 | } 314 | else // Semi- or non-blocking specified 315 | { 316 | // Read from the port 317 | do { errno = 0; numBytesRead = read(serialPortFD, readBuffer, bytesToRead); } while ((numBytesRead < 0) && (errno == EINTR)); 318 | if (numBytesRead > 0) 319 | numBytesReadTotal = numBytesRead; 320 | } 321 | 322 | // Return number of bytes read if successful 323 | memcpy(buffer, readBuffer, numBytesReadTotal); 324 | return (numBytesRead == -1) ? -1 : numBytesReadTotal; 325 | } 326 | 327 | void* readingThread(void *arg) 328 | { 329 | // Read forever in a loop while the port is open 330 | char readBuffer[2048]; 331 | while (portHandle > 0) 332 | { 333 | printf("\nBeginning blocking read...\n"); 334 | int numBytesRead = readBytes(portHandle, readBuffer, sizeof(readBuffer), 0, com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING, 0); 335 | printf("Read %d bytes\n", numBytesRead); 336 | } 337 | return NULL; 338 | } 339 | int testCloseSeparateThread(void) 340 | { 341 | // Open the serial port 342 | if ((portHandle = openPortNative()) <= 0) 343 | { 344 | printf("ERROR: Could not open port: %s\n", comPort); 345 | return -1; 346 | } 347 | printf("Port opened: %s\n", comPort); 348 | 349 | // Configure the serial port for indefinitely blocking reads 350 | if (!configTimeouts(portHandle, com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING, 0, 0, 0)) 351 | { 352 | printf("ERROR: Could not configure port timeouts\n"); 353 | return -2; 354 | } 355 | printf("Blocking read timeouts successfully configured\n"); 356 | 357 | // Start a new thread to continuously read from the serial port for 5 seconds 358 | pthread_t pid; 359 | if (pthread_create(&pid, NULL, &readingThread, NULL)) 360 | { 361 | printf("ERROR: Could not create a reading thread\n"); 362 | return -3; 363 | } 364 | sleep(5); 365 | 366 | // Close the serial port 367 | printf("\nAttempting to close serial port from a separate thread...\n"); 368 | if ((portHandle = closePortNative(portHandle)) > 0) 369 | { 370 | printf("ERROR: Could not close port: %s\n", comPort); 371 | return -4; 372 | } 373 | printf("Port closed\n"); 374 | 375 | // Wait for the reading thread to return 376 | pthread_join(pid, NULL); 377 | printf("Reading thread successfully returned\n"); 378 | return 0; 379 | } 380 | 381 | int testSimpleOpenClose(void) 382 | { 383 | // Open the serial port 384 | if ((portHandle = openPortNative()) <= 0) 385 | { 386 | printf("ERROR: Could not open port: %s\n", comPort); 387 | return -2; 388 | } 389 | printf("Port opened\n"); 390 | 391 | // Close the serial port 392 | if ((portHandle = closePortNative(portHandle)) > 0) 393 | { 394 | printf("ERROR: Could not close port: %s\n", comPort); 395 | return -3; 396 | } 397 | printf("Port closed\n"); 398 | return 0; 399 | } 400 | 401 | int main(int argc, char *argv[]) 402 | { 403 | // Check for correct input parameters 404 | if (argc != 2) 405 | { 406 | printf("USAGE: ./testOpenClose [PORT_FILE_NAME]\n"); 407 | return -1; 408 | } 409 | comPort = argv[1]; 410 | 411 | // Perform one of the above open/close tests 412 | return testCloseSeparateThread(); 413 | //return testSimpleOpenClose(); 414 | } 415 | -------------------------------------------------------------------------------- /src/test/c/testPollPosix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "PosixHelperFunctions.h" 15 | 16 | static serialPortVector serialPorts = { NULL, 0, 0 }; 17 | static serialPort *currentPort = NULL; 18 | 19 | #define PERR 0b001000000000 20 | #define PHUP 0b000100000000 21 | #define PIN 0b000010000000 22 | #define PNVAL 0b000001000000 23 | #define POUT 0b000000100000 24 | #define PPRI 0b000000010000 25 | #define PRDBAND 0b000000001000 26 | #define PRDNORM 0b000000000100 27 | #define PWRBAND 0b000000000010 28 | #define PWRNORM 0b000000000001 29 | 30 | unsigned short convertEventCodes(short revents) 31 | { 32 | unsigned short eventBits = 0; 33 | if (revents & POLLERR) 34 | eventBits |= PERR; 35 | if (revents & POLLHUP) 36 | eventBits |= PHUP; 37 | if (revents & POLLIN) 38 | eventBits |= PIN; 39 | if (revents & POLLNVAL) 40 | eventBits |= PNVAL; 41 | if (revents & POLLOUT) 42 | eventBits |= POUT; 43 | if (revents & POLLPRI) 44 | eventBits |= PPRI; 45 | if (revents & POLLRDBAND) 46 | eventBits |= PRDBAND; 47 | if (revents & POLLRDNORM) 48 | eventBits |= PRDNORM; 49 | if (revents & POLLWRBAND) 50 | eventBits |= PWRBAND; 51 | if (revents & POLLWRNORM) 52 | eventBits |= PWRNORM; 53 | return eventBits; 54 | } 55 | 56 | void ctrlCHandler(int dummy) 57 | { 58 | if (currentPort) 59 | currentPort->eventListenerRunning = 0; 60 | else 61 | { 62 | printf("\n"); 63 | exit(0); 64 | } 65 | } 66 | 67 | int configPort(serialPort *port) 68 | { 69 | // Clear any serial port flags and set up raw non-canonical port parameters 70 | struct termios options = { 0 }; 71 | tcgetattr(port->handle, &options); 72 | options.c_cc[VSTART] = (unsigned char)17; 73 | options.c_cc[VSTOP] = (unsigned char)19; 74 | options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | INPCK | IGNPAR | IGNCR | ICRNL | IXON | IXOFF | IXANY); 75 | options.c_oflag &= ~OPOST; 76 | options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 77 | options.c_cflag &= ~(CSIZE | PARENB | CMSPAR | PARODD | CSTOPB | CRTSCTS); 78 | 79 | // Update the user-specified port parameters 80 | int baudRate = 115200; 81 | tcflag_t byteSize = CS8; 82 | tcflag_t parity = 0; 83 | options.c_cflag |= (byteSize | parity | CLOCAL | CREAD); 84 | options.c_cflag &= ~HUPCL; 85 | 86 | // Configure the serial port read and write timeouts 87 | int flags = 0; 88 | port->eventsMask = com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED;// | com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE; 89 | options.c_cc[VMIN] = 0; 90 | options.c_cc[VTIME] = 10; 91 | 92 | // Apply changes 93 | if (fcntl(port->handle, F_SETFL, flags)) 94 | return 0; 95 | if (setConfigOptions(port->handle, baudRate, &options)) 96 | return 0; 97 | return 1; 98 | } 99 | 100 | int waitForEvent(serialPort *port) 101 | { 102 | // Initialize local variables 103 | int pollResult; 104 | short pollEventsMask = ((port->eventsMask & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) || (port->eventsMask & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED)) ? (POLLIN | POLLERR) : (POLLHUP | POLLERR); 105 | jint event = com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_TIMED_OUT; 106 | struct pollfd waitingSet = { port->handle, pollEventsMask, 0 }; 107 | 108 | // Wait for a serial port event 109 | do 110 | { 111 | waitingSet.revents = 0; 112 | pollResult = poll(&waitingSet, 1, 1000); 113 | printf("Poll Result: %d, Revents: %hu, Codes: %hu\n", pollResult, waitingSet.revents, convertEventCodes(waitingSet.revents)); 114 | } 115 | while ((pollResult == 0) && port->eventListenerRunning); 116 | 117 | // Return the detected port events 118 | if (waitingSet.revents & (POLLHUP | POLLNVAL)) 119 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED; 120 | else if (waitingSet.revents & POLLIN) 121 | event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE; 122 | return event; 123 | } 124 | 125 | int main(void) 126 | { 127 | // Enumerate all serial ports 128 | signal(SIGINT, ctrlCHandler); 129 | searchForComPorts(&serialPorts); 130 | 131 | // Prompt user which port to open 132 | int userSelection = -1; 133 | while ((userSelection < 0) || (userSelection >= serialPorts.length)) 134 | { 135 | printf("Select the index of the serial device to connect to:\n\n"); 136 | for (int i = 0; i < serialPorts.length; ++i) 137 | { 138 | serialPort *port = serialPorts.ports[i]; 139 | printf("\t[%d]: %s (Description = %s)\n", i, port->portPath, port->portDescription); 140 | } 141 | printf("\nTarget device index: "); 142 | scanf("%d", &userSelection); 143 | } 144 | serialPort *port = serialPorts.ports[userSelection]; 145 | 146 | // Try to open the serial port with read/write access 147 | int portHandle = open(port->portPath, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC); 148 | if (portHandle > 0) 149 | { 150 | // Set the newly opened port handle in the serial port structure 151 | port->handle = portHandle; 152 | 153 | // Quickly set the desired RTS/DTR line status immediately upon opening 154 | int modemBits = TIOCM_DTR; 155 | ioctl(port->handle, TIOCMBIS, &modemBits); 156 | modemBits = TIOCM_RTS; 157 | ioctl(port->handle, TIOCMBIS, &modemBits); 158 | 159 | // Ensure that multiple root users cannot access the device simultaneously 160 | if (flock(port->handle, LOCK_EX | LOCK_NB)) 161 | { 162 | while (close(port->handle) && (errno == EINTR)) 163 | errno = 0; 164 | port->handle = -1; 165 | } 166 | else if (!configPort(port)) 167 | { 168 | // Close the port if there was a problem setting the parameters 169 | fcntl(port->handle, F_SETFL, O_NONBLOCK); 170 | while (close(port->handle) && (errno == EINTR)) 171 | errno = 0; 172 | port->handle = -1; 173 | } 174 | 175 | // Start listening for events 176 | currentPort = port; 177 | port->eventListenerRunning = 1; 178 | while (port->eventListenerRunning) 179 | { 180 | int event = waitForEvent(port); 181 | if (event != com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_TIMED_OUT) 182 | printf("Received event: %s\n", event == com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED ? "Disconnected" : "Available"); 183 | if (event == com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PORT_DISCONNECTED) 184 | port->eventListenerRunning = 0; 185 | else if (event == com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) 186 | tcflush(port->handle, TCIOFLUSH); 187 | } 188 | 189 | // Close the port 190 | struct termios options = { 0 }; 191 | tcgetattr(port->handle, &options); 192 | options.c_cc[VMIN] = 0; 193 | options.c_cc[VTIME] = 0; 194 | fcntl(port->handle, F_SETFL, O_NONBLOCK); 195 | tcsetattr(port->handle, TCSANOW, &options); 196 | fdatasync(port->handle); 197 | tcflush(port->handle, TCIOFLUSH); 198 | flock(port->handle, LOCK_UN | LOCK_NB); 199 | while (close(port->handle) && (errno == EINTR)) 200 | errno = 0; 201 | port->handle = -1; 202 | } 203 | 204 | // Clean up all memory and return 205 | cleanUpVector(&serialPorts); 206 | return 0; 207 | } 208 | -------------------------------------------------------------------------------- /src/test/c/testRS485.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #define termios asmtermios 11 | #define termio asmtermio 12 | #define winsize asmwinsize 13 | #include 14 | #include 15 | #undef termio 16 | #undef termios 17 | #undef winsize 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | // Ensure that port handle was passed in 22 | if (argc != 2) 23 | { 24 | printf("Usage: ./testRS485 /dev/port/path\n"); 25 | return 0; 26 | } 27 | const char *portName = argv[1]; 28 | 29 | // Open serial port 30 | int portHandle = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC); 31 | if (portHandle > 0) 32 | { 33 | // Ensure that multiple root users cannot access the device simultaneously 34 | if (flock(portHandle, LOCK_EX | LOCK_NB)) 35 | { 36 | while (close(portHandle) && (errno == EINTR)) 37 | errno = 0; 38 | portHandle = -1; 39 | } 40 | } 41 | if (portHandle <= 0) 42 | { 43 | printf("Error opening port at %s\n", portName); 44 | return -1; 45 | } 46 | 47 | // Attempt to retrieve RS485 configuration from connected device 48 | struct serial_rs485 rs485Conf = { 0 }; 49 | int retVal = ioctl(portHandle, TIOCGRS485, &rs485Conf); 50 | if (retVal) 51 | { 52 | printf("Error retrieving RS485 configuration, Code = %d, Errno = %d\n", retVal, errno); 53 | return -2; 54 | } 55 | 56 | // Attempt to enable RS485 configuration 57 | rs485Conf.flags |= SER_RS485_ENABLED; 58 | rs485Conf.flags |= SER_RS485_RTS_ON_SEND; 59 | rs485Conf.flags &= ~(SER_RS485_RTS_AFTER_SEND); 60 | rs485Conf.flags &= ~(SER_RS485_RX_DURING_TX); 61 | rs485Conf.flags &= ~(SER_RS485_TERMINATE_BUS); 62 | rs485Conf.delay_rts_before_send = 1; 63 | rs485Conf.delay_rts_after_send = 1; 64 | retVal = ioctl(portHandle, TIOCSRS485, &rs485Conf); 65 | if (retVal) 66 | { 67 | printf("Error enabling RS485 configuration, Code = %d, Errno = %d\n", retVal, errno); 68 | return -3; 69 | } 70 | 71 | // Attempt to disable RS485 configuration 72 | rs485Conf.flags &= ~SER_RS485_ENABLED; 73 | rs485Conf.flags &= ~(SER_RS485_RTS_ON_SEND); 74 | rs485Conf.flags |= SER_RS485_RTS_AFTER_SEND; 75 | rs485Conf.flags |= SER_RS485_RX_DURING_TX; 76 | rs485Conf.flags |= SER_RS485_TERMINATE_BUS; 77 | retVal = ioctl(portHandle, TIOCSRS485, &rs485Conf); 78 | if (retVal) 79 | { 80 | printf("Error disabling RS485 configuration, Code = %d, Errno = %d\n", retVal, errno); 81 | return -4; 82 | } 83 | 84 | // Unblock, unlock, and close the port 85 | fsync(portHandle); 86 | tcdrain(portHandle); 87 | tcflush(portHandle, TCIOFLUSH); 88 | flock(portHandle, LOCK_UN | LOCK_NB); 89 | while (close(portHandle) && (errno == EINTR)) 90 | errno = 0; 91 | portHandle = -1; 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /src/test/java/com/fazecast/jSerialComm/SerialPortTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SerialPortTest.java 3 | * 4 | * Created on: Feb 27, 2015 5 | * Last Updated on: Apr 11, 2024 6 | * Author: Will Hedgecock 7 | * 8 | * Copyright (C) 2012-2024 Fazecast, Inc. 9 | * 10 | * This file is part of jSerialComm. 11 | * 12 | * jSerialComm is free software: you can redistribute it and/or modify 13 | * it under the terms of either the Apache Software License, version 2, or 14 | * the GNU Lesser General Public License as published by the Free Software 15 | * Foundation, version 3 or above. 16 | * 17 | * jSerialComm is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * 21 | * You should have received a copy of both the GNU Lesser General Public 22 | * License and the Apache Software License along with jSerialComm. If not, 23 | * see and . 24 | */ 25 | 26 | package com.fazecast.jSerialComm; 27 | 28 | import java.io.InputStream; 29 | import java.util.Scanner; 30 | 31 | /** 32 | * This class provides a test case for the jSerialComm library. 33 | * 34 | * @see java.io.InputStream 35 | * @see java.io.OutputStream 36 | */ 37 | public class SerialPortTest 38 | { 39 | private static final class PacketListener implements SerialPortPacketListener 40 | { 41 | @Override 42 | public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_RECEIVED; } 43 | @Override 44 | public void serialEvent(SerialPortEvent event) 45 | { 46 | byte[] newData = event.getReceivedData(); 47 | System.out.println("Received data of size: " + newData.length); 48 | for (int i = 0; i < newData.length; ++i) 49 | System.out.print((char)newData[i]); 50 | System.out.println("\n"); 51 | } 52 | @Override 53 | public int getPacketSize() { return 100; } 54 | } 55 | 56 | private static final class MessageListener implements SerialPortMessageListener 57 | { 58 | public String byteToHex(byte num) 59 | { 60 | char[] hexDigits = new char[2]; 61 | hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16); 62 | hexDigits[1] = Character.forDigit((num & 0xF), 16); 63 | return new String(hexDigits); 64 | } 65 | @Override 66 | public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_RECEIVED; } 67 | @Override 68 | public void serialEvent(SerialPortEvent event) 69 | { 70 | byte[] byteArray = event.getReceivedData(); 71 | StringBuffer hexStringBuffer = new StringBuffer(); 72 | for (int i = 0; i < byteArray.length; i++) 73 | hexStringBuffer.append(byteToHex(byteArray[i])); 74 | System.out.println("Received the following message: " + hexStringBuffer.toString()); 75 | } 76 | @Override 77 | public byte[] getMessageDelimiter() { return new byte[]{ (byte)0xB5, (byte)0x62 }; } 78 | @Override 79 | public boolean delimiterIndicatesEndOfMessage() { return false; } 80 | } 81 | 82 | static public void main(String[] args) 83 | { 84 | System.out.println("\nUsing Library Version v" + SerialPort.getVersion()); 85 | SerialPort.allowPortOpenForEnumeration(); 86 | SerialPort.autoCleanupAtShutdown(); 87 | SerialPort.addShutdownHook(new Thread() { public void run() { System.out.println("\nRunning shutdown hook"); } }); 88 | SerialPort[] ports = SerialPort.getCommPorts(); 89 | System.out.println("\nAvailable Ports:\n"); 90 | for (int i = 0; i < ports.length; ++i) 91 | System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + " (" + ports[i].getSystemPortPath() + "): " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription() + " @ " + ports[i].getPortLocation() + " (VID = " + ports[i].getVendorID() + ", PID = " + ports[i].getProductID() + ", Serial = " + ports[i].getSerialNumber() + ", Manufacturer = " + ports[i].getManufacturer() + ")"); 92 | System.out.println("\nRe-enumerating ports again in 2 seconds...\n"); 93 | try { Thread.sleep(2000); } catch (Exception e) {} 94 | ports = SerialPort.getCommPorts(); 95 | System.out.println("Available Ports:\n"); 96 | for (int i = 0; i < ports.length; ++i) 97 | System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + " (" + ports[i].getSystemPortPath() + "): " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription() + " @ " + ports[i].getPortLocation() + " (VID = " + ports[i].getVendorID() + ", PID = " + ports[i].getProductID() + ", Serial = " + ports[i].getSerialNumber() + ", Manufacturer = " + ports[i].getManufacturer() + ")"); 98 | SerialPort ubxPort; 99 | System.out.print("\nChoose your desired serial port or enter -1 to specify a port directly: "); 100 | int serialPortChoice = -2; 101 | Scanner inputScanner = new Scanner(System.in); 102 | try { 103 | serialPortChoice = inputScanner.nextInt(); 104 | } catch (Exception e) {} 105 | if (serialPortChoice == -2) 106 | { 107 | inputScanner.close(); 108 | return; 109 | } 110 | else if (serialPortChoice == -1) 111 | { 112 | String serialPortDescriptor = ""; 113 | System.out.print("\nSpecify your desired serial port descriptor: "); 114 | try { 115 | while (serialPortDescriptor.isEmpty()) 116 | serialPortDescriptor = inputScanner.nextLine(); 117 | } catch (Exception e) { e.printStackTrace(); } 118 | ubxPort = SerialPort.getCommPort(serialPortDescriptor); 119 | } 120 | else 121 | ubxPort = ports[serialPortChoice]; 122 | ubxPort.allowElevatedPermissionsRequest(); 123 | byte[] readBuffer = new byte[2048]; 124 | System.out.println("\nPre-setting RTS: " + (ubxPort.setRTS() ? "Success" : "Failure")); 125 | boolean openedSuccessfully = ubxPort.openPort(0); 126 | System.out.println("\nOpening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + " - " + ubxPort.getPortDescription() + ": " + openedSuccessfully); 127 | if (!openedSuccessfully) 128 | { 129 | System.out.println("Error code was " + ubxPort.getLastErrorCode() + " at Line " + ubxPort.getLastErrorLocation()); 130 | inputScanner.close(); 131 | return; 132 | } 133 | System.out.println("Setting read timeout mode to non-blocking"); 134 | ubxPort.setBaudRate(115200); 135 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 1000, 0); 136 | try 137 | { 138 | for (int i = 0; i < 3; ++i) 139 | { 140 | System.out.println("\nReading #" + i); 141 | System.out.println("Available: " + ubxPort.bytesAvailable()); 142 | int numRead = ubxPort.readBytes(readBuffer, readBuffer.length); 143 | System.out.println("Read " + numRead + " bytes."); 144 | } 145 | } catch (Exception e) { e.printStackTrace(); } 146 | System.out.println("\nSetting read timeout mode to semi-blocking with a timeout of 200ms"); 147 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 200, 0); 148 | try 149 | { 150 | for (int i = 0; i < 3; ++i) 151 | { 152 | System.out.println("\nReading #" + i); 153 | System.out.println("Available: " + ubxPort.bytesAvailable()); 154 | int numRead = ubxPort.readBytes(readBuffer, readBuffer.length); 155 | System.out.println("Read " + numRead + " bytes."); 156 | } 157 | } catch (Exception e) { e.printStackTrace(); } 158 | System.out.println("\nSetting read timeout mode to semi-blocking with no timeout"); 159 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 0, 0); 160 | System.out.println("\nWaiting for available bytes to read..."); 161 | while (ubxPort.bytesAvailable() == 0); 162 | System.out.println("Available: " + ubxPort.bytesAvailable()); 163 | System.out.println("Flushing read buffers: " + ubxPort.flushIOBuffers()); 164 | try 165 | { 166 | for (int i = 0; i < 3; ++i) 167 | { 168 | System.out.println("\nReading #" + i); 169 | System.out.println("Available: " + ubxPort.bytesAvailable()); 170 | int numRead = ubxPort.readBytes(readBuffer, readBuffer.length); 171 | System.out.println("Read " + numRead + " bytes."); 172 | } 173 | } catch (Exception e) { e.printStackTrace(); } 174 | System.out.println("\nSetting read timeout mode to blocking with a timeout of 100ms"); 175 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 100, 0); 176 | try 177 | { 178 | for (int i = 0; i < 3; ++i) 179 | { 180 | System.out.println("\nReading #" + i); 181 | System.out.println("Available: " + ubxPort.bytesAvailable()); 182 | int numRead = ubxPort.readBytes(readBuffer, readBuffer.length); 183 | System.out.println("Read " + numRead + " bytes."); 184 | } 185 | } catch (Exception e) { e.printStackTrace(); } 186 | System.out.println("\nSetting read timeout mode to blocking with no timeout"); 187 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 0, 0); 188 | try 189 | { 190 | for (int i = 0; i < 3; ++i) 191 | { 192 | System.out.println("\nReading #" + i); 193 | System.out.println("Available: " + ubxPort.bytesAvailable()); 194 | int numRead = ubxPort.readBytes(readBuffer, readBuffer.length); 195 | System.out.println("Read " + numRead + " bytes."); 196 | } 197 | } catch (Exception e) { e.printStackTrace(); } 198 | System.out.println("\nSwitching over to event-based reading"); 199 | System.out.println("\nListening for any amount of data available\n"); 200 | ubxPort.addDataListener(new SerialPortDataListener() { 201 | @Override 202 | public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_AVAILABLE; } 203 | @Override 204 | public void serialEvent(SerialPortEvent event) 205 | { 206 | SerialPort comPort = event.getSerialPort(); 207 | System.out.println("Available: " + comPort.bytesAvailable() + " bytes."); 208 | byte[] newData = new byte[comPort.bytesAvailable()]; 209 | int numRead = comPort.readBytes(newData, newData.length); 210 | System.out.println("Read " + numRead + " bytes."); 211 | } 212 | }); 213 | try { Thread.sleep(5000); } catch (Exception e) {} 214 | ubxPort.removeDataListener(); 215 | System.out.println("\nNow listening for full 100-byte data packets\n"); 216 | PacketListener listener = new PacketListener(); 217 | ubxPort.addDataListener(listener); 218 | try { Thread.sleep(5000); } catch (Exception e) {} 219 | ubxPort.removeDataListener(); 220 | System.out.println("\nNow listening for byte-delimited binary messages\n"); 221 | MessageListener messageListener = new MessageListener(); 222 | ubxPort.addDataListener(messageListener); 223 | try { Thread.sleep(5000); } catch (Exception e) {} 224 | ubxPort.removeDataListener(); 225 | System.out.println("\n\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort()); 226 | try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); } 227 | System.out.println("Reopening " + ubxPort.getDescriptivePortName() + ": " + ubxPort.openPort() + "\n"); 228 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0); 229 | InputStream in = ubxPort.getInputStream(); 230 | try 231 | { 232 | for (int j = 0; j < 1000; ++j) 233 | System.out.print((char)in.read()); 234 | in.close(); 235 | } catch (Exception e) { e.printStackTrace(); } 236 | System.out.println("\n\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort()); 237 | openedSuccessfully = ubxPort.openPort(0); 238 | System.out.println("Reopening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + ": " + openedSuccessfully); 239 | if (!openedSuccessfully) 240 | { 241 | inputScanner.close(); 242 | return; 243 | } 244 | System.out.println("\n\nReading for 5 seconds then closing from a separate thread..."); 245 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 0, 0); 246 | final SerialPort finalPort = ubxPort; 247 | Thread thread = new Thread(new Runnable() 248 | { 249 | @Override 250 | public void run() 251 | { 252 | byte[] buffer = new byte[2048]; 253 | while (finalPort.isOpen()) 254 | { 255 | System.out.println("\nStarting blocking read..."); 256 | int numRead = finalPort.readBytes(buffer, buffer.length); 257 | System.out.println("Read " + numRead + " bytes"); 258 | } 259 | System.out.println("\nPort was successfully closed from a separate thread"); 260 | } 261 | }); 262 | thread.start(); 263 | try { Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } 264 | System.out.println("\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort()); 265 | try { thread.join(); } catch (Exception e) { e.printStackTrace(); } 266 | openedSuccessfully = ubxPort.openPort(0); 267 | System.out.println("\nReopening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + ": " + openedSuccessfully); 268 | if (!openedSuccessfully) 269 | { 270 | inputScanner.close(); 271 | return; 272 | } 273 | System.out.println("\n\nNow waiting asynchronously for all possible listening events..."); 274 | ubxPort.addDataListener(new SerialPortDataListener() { 275 | @Override 276 | public int getListeningEvents() { return SerialPort.LISTENING_EVENT_PARITY_ERROR | SerialPort.LISTENING_EVENT_DATA_WRITTEN | SerialPort.LISTENING_EVENT_BREAK_INTERRUPT | 277 | SerialPort.LISTENING_EVENT_CARRIER_DETECT | SerialPort.LISTENING_EVENT_CTS | SerialPort.LISTENING_EVENT_DSR | SerialPort.LISTENING_EVENT_RING_INDICATOR | SerialPort.LISTENING_EVENT_PORT_DISCONNECTED | 278 | SerialPort.LISTENING_EVENT_FRAMING_ERROR | SerialPort.LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR | SerialPort.LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR | SerialPort.LISTENING_EVENT_DATA_AVAILABLE; } 279 | @Override 280 | public void serialEvent(SerialPortEvent event) 281 | { 282 | System.out.println("Received event type: " + event.toString()); 283 | if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_AVAILABLE) 284 | { 285 | byte[] buffer = new byte[event.getSerialPort().bytesAvailable()]; 286 | event.getSerialPort().readBytes(buffer, buffer.length); 287 | System.out.println(" Reading " + buffer.length + " bytes"); 288 | } 289 | } 290 | }); 291 | try { Thread.sleep(5000); } catch (Exception e) {} 292 | ubxPort.removeDataListener(); 293 | ubxPort.closePort(); 294 | openedSuccessfully = ubxPort.openPort(0); 295 | System.out.println("\nReopening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + ": " + openedSuccessfully); 296 | if (!openedSuccessfully) 297 | { 298 | inputScanner.close(); 299 | return; 300 | } 301 | System.out.println("\n\nUnplug the device sometime in the next 10 seconds to ensure that it closes properly...\n"); 302 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 0, 0); 303 | ubxPort.addDataListener(new SerialPortDataListener() { 304 | @Override 305 | public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_AVAILABLE; } 306 | @Override 307 | public void serialEvent(SerialPortEvent event) 308 | { 309 | SerialPort comPort = event.getSerialPort(); 310 | System.out.println("Available: " + comPort.bytesAvailable() + " bytes."); 311 | byte[] newData = new byte[comPort.bytesAvailable()]; 312 | int numRead = comPort.readBytes(newData, newData.length); 313 | System.out.println("Read " + numRead + " bytes."); 314 | } 315 | }); 316 | try { Thread.sleep(10000); } catch (Exception e) {} 317 | ubxPort.removeDataListener(); 318 | System.out.println("\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort()); 319 | 320 | /*System.out.println("\n\nAttempting to read from two serial ports simultaneously\n"); 321 | System.out.println("\nAvailable Ports:\n"); 322 | for (int i = 0; i < ports.length; ++i) 323 | System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + ": " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription()); 324 | SerialPort ubxPort2; 325 | System.out.print("\nChoose your second desired serial port, or enter -1 to skip this test: "); 326 | serialPortChoice = 0; 327 | try { 328 | Scanner inputScanner = new Scanner(System.in); 329 | serialPortChoice = inputScanner.nextInt(); 330 | inputScanner.close(); 331 | } catch (Exception e) {} 332 | if (serialPortChoice != -1) 333 | { 334 | ubxPort2 = ports[serialPortChoice]; 335 | ubxPort2.openPort(); 336 | try 337 | { 338 | System.out.print("\nReading from first serial port...\n\n"); 339 | in = ubxPort.getInputStream(); 340 | InputStream in2 = ubxPort2.getInputStream(); 341 | for (int j = 0; j < 1000; ++j) 342 | System.out.print((char)in.read()); 343 | System.out.print("\nReading from second serial port...\n\n"); 344 | for (int j = 0; j < 100; ++j) 345 | System.out.print((char)in2.read()); 346 | System.out.print("\nReading from first serial port again...\n\n"); 347 | for (int j = 0; j < 1000; ++j) 348 | System.out.print((char)in.read()); 349 | in.close(); 350 | in2.close(); 351 | } 352 | catch (SerialPortIOException e) { e.printStackTrace(); } 353 | catch (Exception e) { e.printStackTrace(); } 354 | } 355 | System.out.println("\n\nEntering Java-based InputStream in Scanner mode and reading 200 lines\n"); 356 | ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0); 357 | Scanner scanner = new Scanner(ubxPort.getInputStream()); 358 | for (int i = 1; i < 201; ++i) 359 | if (scanner.hasNextLine()) 360 | System.out.println("Full Line #" + i + ": " + scanner.nextLine()); 361 | scanner.close(); 362 | System.out.println("\n\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());*/ 363 | inputScanner.close(); 364 | } 365 | } 366 | --------------------------------------------------------------------------------