├── .github └── workflows │ ├── build.yml │ ├── cross-compile.yml │ └── release-new-version.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── ant └── build.xml ├── pom.xml ├── src ├── assembly │ └── one-off-jar.xml ├── main │ ├── cpp │ │ ├── _nix_based │ │ │ └── jssc.cpp │ │ ├── jssc_SerialNativeInterface.h │ │ ├── version.h.in │ │ └── windows │ │ │ └── jssc.cpp │ ├── java │ │ └── jssc │ │ │ ├── DefaultJniExtractorStub.java │ │ │ ├── SerialNativeInterface.java │ │ │ ├── SerialPort.java │ │ │ ├── SerialPortEvent.java │ │ │ ├── SerialPortEventListener.java │ │ │ ├── SerialPortException.java │ │ │ ├── SerialPortList.java │ │ │ └── SerialPortTimeoutException.java │ ├── module-info │ │ └── module-info.java │ └── resources-precompiled │ │ ├── README.md │ │ └── natives │ │ ├── linux_32 │ │ └── libjssc.so │ │ ├── linux_64 │ │ └── libjssc.so │ │ ├── linux_arm │ │ └── libjssc.so │ │ ├── linux_arm64 │ │ └── libjssc.so │ │ ├── linux_ppc │ │ └── libjssc.so │ │ ├── linux_riscv32 │ │ └── libjssc.so │ │ ├── linux_riscv64 │ │ └── libjssc.so │ │ ├── osx_64 │ │ └── libjssc.dylib │ │ ├── osx_arm64 │ │ └── libjssc.dylib │ │ ├── windows_32 │ │ └── jssc.dll │ │ ├── windows_64 │ │ └── jssc.dll │ │ └── windows_arm64 │ │ └── jssc.dll └── test │ ├── java │ └── jssc │ │ ├── SerialNativeInterfaceTest.java │ │ ├── VirtualPortTest.java │ │ ├── bootpath │ │ ├── ManualBootLibraryPathFailedTest.java │ │ └── ManualBootLibraryPathTest.java │ │ └── junit │ │ └── rules │ │ ├── BackgroundProcess.java │ │ ├── DisplayMethodNameRule.java │ │ └── VirtualPortRule.java │ └── resources │ └── log4j2.properties └── toolchain ├── Aarch64.cmake ├── Armhf.cmake ├── Armsf.cmake ├── Dockcross.cmake ├── Mingw32.cmake ├── Mingw64.cmake ├── MingwAarch64.cmake ├── Ppc64.cmake ├── Riscv32.cmake └── Riscv64.cmake /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | MAVEN_OPTS: -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn 7 | 8 | jobs: 9 | ubuntu: 10 | runs-on: [ubuntu-latest] 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | include: 15 | - profile: x86 16 | packages: g++-multilib 17 | 18 | - profile: x86_64 19 | packages: g++- 20 | 21 | - profile: armhf 22 | packages: g++-arm-linux-gnueabihf 23 | 24 | - profile: aarch64 25 | packages: g++-aarch64-linux-gnu 26 | 27 | - profile: riscv64 28 | packages: g++-riscv64-linux-gnu 29 | 30 | - profile: ppc64 31 | packages: g++-powerpc64le-linux-gnu 32 | 33 | - profile: mingw32 34 | packages: g++-mingw-w64-i686 35 | 36 | - profile: mingw64 37 | packages: g++-mingw-w64-x86-64 38 | 39 | - profile: mingwaarch64 40 | packages: clang 41 | steps: 42 | - name: Checkout 43 | uses: actions/checkout@v3 44 | 45 | - name: Setup Java 46 | uses: actions/setup-java@v3 47 | with: 48 | java-version: 11 49 | distribution: temurin 50 | 51 | - run: sudo apt-get update && sudo apt-get install socat ${{ matrix.packages }} 52 | - run: mvn -P "${{ matrix.profile }}" --batch-mode 53 | 54 | macos: 55 | runs-on: [macos-latest] 56 | strategy: 57 | fail-fast: false 58 | matrix: 59 | include: 60 | - profile: aarch64 61 | macos-deployment-target: 11.0 62 | sdk-version: MacOSX11.0.sdk 63 | - profile: x86_64 64 | macos-deployment-target: 10.9 65 | sdk-version: MacOSX10.9.sdk 66 | 67 | steps: 68 | - uses: actions/checkout@v3 69 | - uses: actions/setup-java@v3 70 | with: 71 | java-version: 11 72 | distribution: temurin 73 | 74 | - run: brew install socat 75 | 76 | - name: Get oldest supported SDK 77 | run: | 78 | wget -qO- https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/${{ matrix.sdk-version }}.tar.xz \ 79 | | tar -xjv -C $XCODE_16_DEVELOPER_DIR/Platforms/MacOSX.platform/Developer/SDKs 80 | 81 | - name: Set SDK version 82 | run: | 83 | export MACOSX_DEPLOYMENT_TARGET=${{ matrix.macos-deployment-target }} 84 | export SDKROOT=$XCODE_16_DEVELOPER_DIR/Platforms/MacOSX.platform/Developer/SDKs/${{ matrix.sdk-version }} 85 | export CMAKE_OSX_SYSROOT=$SDKROOT 86 | echo "MACOSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET" >> $GITHUB_ENV 87 | echo "SDKROOT=$SDKROOT" >> $GITHUB_ENV 88 | echo "CMAKE_OSX_SYSROOT=$CMAKE_OSX_SYSROOT" >> $GITHUB_ENV 89 | 90 | - run: mvn -P "${{ matrix.profile }}" --batch-mode 91 | 92 | windows: 93 | runs-on: [windows-latest] 94 | strategy: 95 | fail-fast: false 96 | matrix: 97 | include: 98 | - profile: aarch64 99 | 100 | - profile: x86_64 101 | 102 | steps: 103 | - uses: actions/checkout@v3 104 | - uses: actions/setup-java@v3 105 | with: 106 | java-version: 11 107 | distribution: temurin 108 | 109 | - run: mvn -P "${{ matrix.profile }}" --batch-mode -------------------------------------------------------------------------------- /.github/workflows/cross-compile.yml: -------------------------------------------------------------------------------- 1 | name: Cross-compile native libraries 2 | on: workflow_dispatch 3 | 4 | env: 5 | MAVEN_OPTS: -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn 6 | GITHUB_BOT_NAME: github-actions 7 | GITHUB_BOT_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com 8 | 9 | jobs: 10 | create-branch: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - run: echo "precompiled_branch=$(git branch --show-current)-precompiled-natives" >> $GITHUB_ENV 15 | - name: Create branch for precompiled natives 16 | run: git checkout -b ${{ env.precompiled_branch }} 17 | - name: Sync SerialNativeInterface version with the project pom version 18 | run: | 19 | FILE=src/main/java/jssc/SerialNativeInterface.java 20 | RELEASE_VERSION=$(mvn validate help:evaluate -Dexpression=release.version -q -DforceStdout) 21 | sed -i "s/private static final String libVersion =.*/private static final String libVersion = \"${RELEASE_VERSION}\";/" ${FILE} 22 | if [ $(git ls-files --modified) ]; then 23 | git config --global user.email "${GITHUB_BOT_EMAIL}" 24 | git config --global user.name "${GITHUB_BOT_NAME}" 25 | git commit ${FILE} --message "Update version in source files before building native libraries" 26 | fi 27 | - run: echo "rev=$(git rev-parse --short HEAD)" >> $GITHUB_ENV 28 | - run: git push --force origin HEAD 29 | outputs: 30 | precompiled_branch: ${{ env.precompiled_branch }} 31 | base_rev: ${{ env.rev }} 32 | 33 | linux-windows: 34 | runs-on: ubuntu-latest 35 | needs: create-branch 36 | strategy: 37 | matrix: 38 | include: 39 | - target: linux_32 40 | os_target_name: linux 41 | os_target_arch: x86_32 42 | os_target_bitness: 32 43 | image: docker.io/dockcross/linux-x86 44 | 45 | - target: linux_64 46 | os_target_name: linux 47 | os_target_arch: x86_64 48 | os_target_bitness: 64 49 | image: docker.io/dockcross/linux-x64 50 | 51 | - target: linux_arm 52 | os_target_name: linux 53 | os_target_arch: arm_32 54 | os_target_bitness: 32 55 | image: docker.io/dockcross/linux-armv6-lts 56 | 57 | - target: linux_arm64 58 | os_target_name: linux 59 | os_target_arch: aarch_64 60 | os_target_bitness: 64 61 | image: docker.io/dockcross/linux-arm64-lts 62 | 63 | - target: linux_riscv32 64 | os_target_name: linux 65 | os_target_arch: riscv32 66 | os_target_bitness: 32 67 | image: docker.io/dockcross/linux-riscv32 68 | 69 | - target: linux_riscv64 70 | os_target_name: linux 71 | os_target_arch: riscv64 72 | os_target_bitness: 64 73 | image: docker.io/dockcross/linux-riscv64 74 | 75 | - target: linux_ppc 76 | os_target_name: linux 77 | os_target_arch: ppc_64 78 | os_target_bitness: 64 79 | image: docker.io/dockcross/linux-ppc64le 80 | 81 | - target: windows_32 82 | os_target_name: windows 83 | os_target_arch: x86_32 84 | os_target_bitness: 32 85 | image: docker.io/dockcross/windows-static-x86 86 | 87 | - target: windows_64 88 | os_target_name: windows 89 | os_target_arch: x86_64 90 | os_target_bitness: 64 91 | image: docker.io/dockcross/windows-static-x64 92 | 93 | - target: windows_arm64 94 | os_target_name: windows 95 | os_target_arch: aarch_64 96 | os_target_bitness: 64 97 | image: docker.io/dockcross/windows-arm64 98 | 99 | steps: 100 | - name: Checkout 101 | uses: actions/checkout@v3 102 | 103 | - name: Pull docker images 104 | run: docker pull ${{ matrix.image }} 105 | 106 | - name: Set up JDK 11 107 | uses: actions/setup-java@v3 108 | with: 109 | java-version: 11 110 | distribution: temurin 111 | 112 | - name: Build for ${{ matrix.target }} in ${{ matrix.image }} 113 | run: | 114 | docker run --rm --workdir=/work \ 115 | --volume $PWD:/work \ 116 | --volume $HOME/.m2:/root/.m2 \ 117 | --env MAVEN_OPTS=${MAVEN_OPTS} \ 118 | ${{ matrix.image }} \ 119 | bash -c \ 120 | 'apt-get update && apt-get install --yes maven openjdk-17-jdk-headless && \ 121 | mvn -B clean install -P dockcross,update-resources-precompiled \ 122 | -Dos.target.name=${{ matrix.os_target_name }} \ 123 | -Dos.target.arch=${{ matrix.os_target_arch }} \ 124 | -Dos.target.bitness=${{ matrix.os_target_bitness }} \ 125 | ' 126 | 127 | - name: Push recompiled binaries 128 | run: | 129 | git config --global user.email "${GITHUB_BOT_EMAIL}" 130 | git config --global user.name "${GITHUB_BOT_NAME}" 131 | git fetch && git checkout -t origin/${{ needs.create-branch.outputs.precompiled_branch }} 132 | git add src/main/resources-precompiled/** 133 | git commit --allow-empty -m "Precompiled natives (@${{ needs.create-branch.outputs.base_rev }}) for ${{ matrix.target }}" 134 | while git pull --rebase && ! git push; do sleep 5; done 135 | 136 | macos: 137 | runs-on: macos-latest 138 | needs: create-branch 139 | strategy: 140 | matrix: 141 | include: 142 | - target: osx_64 143 | profile: 'x86_64' 144 | macos-deployment-target: 10.9 145 | sdk-version: MacOSX10.9.sdk 146 | 147 | - target: osx_arm64 148 | profile: 'aarch64' 149 | macos-deployment-target: 11.0 150 | sdk-version: MacOSX11.0.sdk 151 | 152 | steps: 153 | - name: Checkout 154 | uses: actions/checkout@v3 155 | 156 | - name: Set up JDK 11 157 | uses: actions/setup-java@v3 158 | with: 159 | java-version: 11 160 | distribution: temurin 161 | 162 | - run: brew install socat 163 | 164 | - name: Get oldest supported SDK 165 | run: | 166 | wget -qO- https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/${{ matrix.sdk-version }}.tar.xz \ 167 | | tar -xjv -C $XCODE_16_DEVELOPER_DIR/Platforms/MacOSX.platform/Developer/SDKs 168 | 169 | - name: Set SDK version 170 | run: | 171 | export MACOSX_DEPLOYMENT_TARGET=${{ matrix.macos-deployment-target }} 172 | export SDKROOT=$XCODE_16_DEVELOPER_DIR/Platforms/MacOSX.platform/Developer/SDKs/${{ matrix.sdk-version }} 173 | export CMAKE_OSX_SYSROOT=$SDKROOT 174 | echo "MACOSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET" >> $GITHUB_ENV 175 | echo "SDKROOT=$SDKROOT" >> $GITHUB_ENV 176 | echo "CMAKE_OSX_SYSROOT=$CMAKE_OSX_SYSROOT" >> $GITHUB_ENV 177 | - name: Build with Maven 178 | run: mvn -B clean install -P ${{ matrix.profile }},update-resources-precompiled 179 | 180 | - name: Push recompiled binaries 181 | run: | 182 | git config --global user.email "${GITHUB_BOT_EMAIL}" 183 | git config --global user.name "${GITHUB_BOT_NAME}" 184 | git fetch && git checkout -t origin/${{ needs.create-branch.outputs.precompiled_branch }} 185 | git add src/main/resources-precompiled/** 186 | git commit --allow-empty -m "Precompiled natives (@${{ needs.create-branch.outputs.base_rev }}) for ${{ matrix.target }}" 187 | while git pull --rebase && ! git push; do sleep 5; done 188 | 189 | single-commit: 190 | runs-on: ubuntu-latest 191 | needs: [create-branch, linux-windows, macos] 192 | steps: 193 | - uses: actions/checkout@v3 194 | - name: Squash into one commit 195 | run: | 196 | git config --global user.email "${GITHUB_BOT_EMAIL}" 197 | git config --global user.name "${GITHUB_BOT_NAME}" 198 | git fetch && git checkout -t origin/${{ needs.create-branch.outputs.precompiled_branch }} 199 | git reset --soft ${{ needs.create-branch.outputs.base_rev }} 200 | git add src/main/resources-precompiled/** 201 | git commit -m "Precompiled natives @${{ needs.create-branch.outputs.base_rev }}" 202 | git push -f 203 | -------------------------------------------------------------------------------- /.github/workflows/release-new-version.yml: -------------------------------------------------------------------------------- 1 | name: Release New Version 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | releaseVersion: 6 | description: 'Release version' 7 | required: false 8 | 9 | env: 10 | MAVEN_OPTS: -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn 11 | JAVA_TOOL_OPTIONS: -Duser.name=io.github.java-native 12 | GITHUB_BOT_NAME: github-actions 13 | GITHUB_BOT_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com 14 | 15 | jobs: 16 | maven-central-release: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | - run: git config --global user.email "${GITHUB_BOT_EMAIL}" 21 | - run: git config --global user.name "${GITHUB_BOT_NAME}" 22 | - name: Set up JDK 11 23 | uses: actions/setup-java@v3 24 | with: 25 | java-version: 11 26 | distribution: temurin 27 | server-id: ossrh 28 | server-username: OSSRH_TOKEN_USERNAME 29 | server-password: OSSRH_TOKEN_PASSWORD 30 | gpg-private-key: ${{ secrets.JAVA_NATIVE_PGP_KEY }} 31 | gpg-passphrase: PGP_KEY_PASSPHRASE 32 | - name: Set release version if provided as input 33 | if: github.event.inputs.releaseVersion != '' 34 | run: echo "VERSIONS=-DreleaseVersion=${{ github.event.inputs.releaseVersion }}" >> $GITHUB_ENV 35 | - name: Publish artifacts to Maven Central 36 | run: mvn -B release:prepare release:perform -P package,maven-central-release ${VERSIONS} 37 | env: 38 | OSSRH_TOKEN_USERNAME: ${{ secrets.OSSRH_TOKEN_USERNAME }} 39 | OSSRH_TOKEN_PASSWORD: ${{ secrets.OSSRH_TOKEN_PASSWORD }} 40 | PGP_KEY_PASSPHRASE: ${{ secrets.JAVA_NATIVE_PGP_KEY_PASSPHRASE }} 41 | - run: echo "releaseTag=$(git tag --points-at HEAD^)" >> $GITHUB_ENV 42 | - run: echo "releaseVersion=$(echo ${{ env.releaseTag }} | cut -c2-)" >> $GITHUB_ENV 43 | - name: Push changes back to repo 44 | run: git push && git push --tags --force 45 | outputs: 46 | releaseTag: ${{ env.releaseTag }} 47 | releaseVersion: ${{ env.releaseVersion }} 48 | 49 | github-release: 50 | runs-on: ubuntu-latest 51 | needs: maven-central-release 52 | steps: 53 | - uses: actions/checkout@v3 54 | with: 55 | ref: ${{ needs.maven-central-release.outputs.releaseTag }} 56 | - run: git config --global user.email "${GITHUB_BOT_EMAIL}" 57 | - run: git config --global user.name "${GITHUB_BOT_NAME}" 58 | - name: Set up JDK 11 59 | uses: actions/setup-java@v3 60 | with: 61 | java-version: 11 62 | distribution: temurin 63 | - name: Build jar with dependencies included 64 | run: mvn -B install -Ppackage,jar-with-dependencies 65 | - name: Publish as release 66 | uses: ncipollo/release-action@v1 67 | with: 68 | name: ${{ needs.maven-central-release.outputs.releaseVersion }} 69 | tag: ${{ needs.maven-central-release.outputs.releaseTag }} 70 | allowUpdates: true 71 | artifacts: target/*.jar 72 | token: ${{ secrets.GITHUB_TOKEN }} 73 | 74 | update-readme: 75 | runs-on: ubuntu-latest 76 | needs: maven-central-release 77 | env: 78 | ver: ${{ needs.maven-central-release.outputs.releaseVersion }} 79 | steps: 80 | - uses: actions/checkout@v3 81 | - run: | 82 | git config --global user.email "${GITHUB_BOT_EMAIL}" 83 | git config --global user.name "${GITHUB_BOT_NAME}" 84 | - run: | 85 | sed -i "/jssc<\/artifactId>/{n;s/.*<\/version>/${ver}<\/version>/}" README.md 86 | sed -i'.bak' -e "s/java-native:jssc:[A-Za-z0-9.-]*/java-native:jssc:${ver}/g" README.md 87 | - run: | 88 | if [ $(git ls-files --modified) ]; then 89 | git commit --all --message "Update versions in source files after new release" && git pull --rebase && git push 90 | fi 91 | 92 | update-wiki: 93 | runs-on: ubuntu-latest 94 | needs: maven-central-release 95 | env: 96 | ver: ${{ needs.maven-central-release.outputs.releaseVersion }} 97 | steps: 98 | - uses: actions/checkout@v3 99 | with: 100 | repository: ${{github.repository}}.wiki 101 | - run: | 102 | git config --global user.email "${GITHUB_BOT_EMAIL}" 103 | git config --global user.name "${GITHUB_BOT_NAME}" 104 | - run: | 105 | sed -i "/jssc<\/artifactId>/{n;s/.*<\/version>/${ver}<\/version>/}" Add-Dependency.md 106 | sed -i'.bak' -e "s/java-native:jssc:[A-Za-z0-9.-]*/java-native:jssc:${ver}/g" Add-Dependency.md 107 | - run: | 108 | if [ $(git ls-files --modified) ]; then 109 | git commit --all --message "Update wiki with latest version released to Maven Central" && git pull --rebase && git push 110 | fi 111 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | # the maven convention for built files 3 | target/ 4 | 5 | # Prerequisites 6 | *.d 7 | 8 | # Compiled Object files 9 | *.slo 10 | *.lo 11 | *.o 12 | *.obj 13 | 14 | # Precompiled Headers 15 | *.gch 16 | *.pch 17 | 18 | # Fortran module files 19 | *.mod 20 | *.smod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | 33 | # IDE files: IntellIJ 34 | .idea/ 35 | *.iml 36 | 37 | # IDE files: eclipse 38 | .settings/ 39 | 40 | # Java dumps 41 | core.*.dmp 42 | hs_err_pid*.log 43 | javacore.*.txt 44 | jitdump.*.dmp 45 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | cmake_policy(SET CMP0048 NEW) 3 | cmake_policy(SET CMP0042 NEW) 4 | 5 | # Get some architecture information 6 | if(WIN32) 7 | string(TOLOWER $ENV{PROCESSOR_ARCHITECTURE} OS_ARCH) 8 | set(OS_TYPE "Windows") 9 | else() 10 | execute_process(COMMAND uname -m OUTPUT_VARIABLE OS_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE) 11 | execute_process(COMMAND uname OUTPUT_VARIABLE OS_TYPE OUTPUT_STRIP_TRAILING_WHITESPACE) 12 | endif() 13 | 14 | # Determine if compiling on Apple and host arch before starting project 15 | if(APPLE AND NOT CMAKE_OSX_ARCHITECTURES) 16 | set(CMAKE_OSX_ARCHITECTURES "${OS_ARCH}" CACHE STRING "Build architectures for Mac OS X" FORCE) 17 | endif() 18 | 19 | project(jssc VERSION "" LANGUAGES CXX) 20 | 21 | # Use JAVA_HOME from Maven 22 | if(JAVA_HOME) 23 | # Sanitize path for cmake 24 | file(TO_CMAKE_PATH "${JAVA_HOME}" JAVA_HOME) 25 | message(STATUS "Picked up JAVA_HOME from Maven: ${JAVA_HOME}") 26 | # Sanitize accidental jre selection on Linux 27 | if(JAVA_HOME MATCHES "/jre$") 28 | STRING(REGEX REPLACE "/jre$" "/jdk" JAVA_HOME "${JAVA_HOME}") 29 | message(WARNING "Maven JAVA_HOME appears to be a JRE, trying to fix: ${JAVA_HOME}") 30 | endif() 31 | endif() 32 | 33 | find_package(Java) 34 | # Workaround for FindJNI, per https://stackoverflow.com/a/51764145/3196753 35 | set(JAVA_AWT_LIBRARY HeaderOnly) 36 | set(JAVA_JVM_LIBRARY HeaderOnly) 37 | set(JAVA_AWT_INCLUDE_PATH HeaderOnly) 38 | find_package(JNI REQUIRED) 39 | 40 | # Kitware-recommended technique for defaulting to 'Release' mode 41 | if(NOT CMAKE_BUILD_TYPE) 42 | message(STATUS "Setting build type to 'Release' as none was specified.") 43 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) 44 | # Set the possible values of build type for cmake-gui 45 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") 46 | endif() 47 | 48 | if(APPLE) 49 | # Locate IOKit framework for serial/ioss.h 50 | find_library(IOKit IOKit) 51 | if(IOKit) 52 | find_path(IOKit_INCLUDE_DIR NAMES IOKitLib.h HINTS ${IOKit_INC_SEARCH_PATH} ${IOKit_PKGC_INCLUDE_DIRS} PATH_SUFFIXES IOKit) 53 | list(APPEND JSSC_ADDITIONAL_INCLUDES ${IOKit_INCLUDE_DIR}) 54 | endif() 55 | 56 | # Handle edge-case with legacy versioned SDK headers (e.g. usr/include/c++/4.2.1) 57 | if(CMAKE_OSX_SYSROOT) 58 | file(GLOB std_versions "${CMAKE_OSX_SYSROOT}/usr/include/c++/*") 59 | foreach(std_version IN LISTS std_versions) 60 | if("${std_version}" MATCHES "/v[0-9]*$") 61 | # Ignore c++/v1 (should already be included) 62 | continue() 63 | elseif(IS_DIRECTORY "${std_version}") 64 | message(STATUS "Adding legacy include path: ${std_version}") 65 | list(APPEND JSSC_ADDITIONAL_INCLUDES "${std_version}") 66 | endif() 67 | endforeach() 68 | endif() 69 | endif() 70 | 71 | set(CMAKE_CXX_STANDARD 11) 72 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 73 | 74 | # Statically link gcc/c++ 75 | if(MSVC) 76 | # /MT = Multithread, static version of the run-time library 77 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 78 | elseif(WIN32) 79 | # Assume mingw, use "-static" 80 | set(CMAKE_CXX_STANDARD_LIBRARIES "-static ${CMAKE_CXX_STANDARD_LIBRARIES}") 81 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_SYSTEM_NAME STREQUAL "SunOS") 82 | set(CMAKE_CXX_STANDARD_LIBRARIES "-static-libgcc -static-libstdc++ ${CMAKE_CXX_STANDARD_LIBRARIES}") 83 | endif() 84 | 85 | if(WIN32) 86 | set(CPP_SOURCE "windows") 87 | # Remove "lib" prefix from windows binaries 88 | set(CMAKE_SHARED_LIBRARY_PREFIX "") 89 | # Disable optimization for Release builds (XP/Server 2003) 90 | if(NOT MSVC) 91 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O0") 92 | else() 93 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Od") 94 | endif() 95 | else() 96 | set(CPP_SOURCE "_nix_based") 97 | # Sane level of optimization for Release builds 98 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2") 99 | endif() 100 | 101 | # Detect platform if -DNATIVE_LIB_DIR is not provided 102 | # TODO: Handle arm, hardfloat, etc 103 | if(NOT NATIVE_LIB_DIR OR "${NATIVE_LIB_DIR}" STREQUAL "") 104 | # windows, linux, darwin, etc 105 | string(TOLOWER "${CMAKE_SYSTEM_NAME}" OS_NAME) 106 | if(OS_NAME MATCHES "darwin") 107 | set(OS_NAME "osx") 108 | endif() 109 | 110 | # bitness/suffix 111 | if(CMAKE_OSX_ARCHITECTURES) 112 | # can occur when calling cmake directly 113 | if(CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") 114 | set(OS_SUFFIX "arm64") 115 | else() 116 | set(OS_SUFFIX 64) 117 | endif() 118 | elseif("${OS_ARCH}" STREQUAL "aarch64" OR "${OS_ARCH}" STREQUAL "arm64") 119 | set(OS_SUFFIX "arm64") 120 | elseif("${OS_ARCH}" MATCHES "arm") 121 | set(OS_SUFFIX "arm") 122 | elseif("${OS_ARCH}" MATCHES "riscv32") 123 | set(OS_SUFFIX "riscv32") 124 | elseif("${OS_ARCH}" MATCHES "riscv64") 125 | set(OS_SUFFIX "riscv64") 126 | elseif(FORCE_M32) 127 | set(OS_SUFFIX 32) 128 | elseif(FORCE_M64) 129 | set(OS_SUFFIX 64) 130 | else() 131 | if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") 132 | set(OS_SUFFIX 64) 133 | else() 134 | set(OS_SUFFIX 32) 135 | endif() 136 | endif() 137 | 138 | # handle warnings 139 | if(OS_SUFFIX STREQUAL "arm") 140 | if(${CMAKE_VERSION} VERSION_LESS "3.10.0") 141 | message(WARNING "Cmake < 3.10.0 can't detect HAS_FPU. This only affects arm 32-bit builds.") 142 | else() 143 | cmake_host_system_information(RESULT OS_SUFFIX_SF QUERY HAS_FPU) 144 | # warn of native-lib-loader shortcomming 145 | IF(NOT OS_SUFFIX_SF EQUAL 1) 146 | message(WARNING "Soft float detected. We can't determine this at runtime; Compatibility will suffer.") 147 | ENDIF() 148 | endif() 149 | endif() 150 | 151 | set(NATIVE_LIB_DIR ${OS_NAME}_${OS_SUFFIX}) 152 | endif() 153 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/natives/${NATIVE_LIB_DIR}) 154 | 155 | # version.h using #cmakedefine for version from pom.xml. 156 | if(NOT JSSC_VERSION) 157 | # Fallback to parsing pom.xml if not provided 158 | set(JSSC_VERSION "0.0.0-UNKNOWN") 159 | file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml POM_FILE) 160 | foreach(POM_LINE ${POM_FILE}) 161 | # Assume first "" is the project version 162 | if(POM_LINE MATCHES "") 163 | string(REGEX REPLACE "^[ \t]+|<[^>]*>" "" DETECTED_VERSION "${POM_LINE}") 164 | string(STRIP "${DETECTED_VERSION}" DETECTED_VERSION) 165 | if(DETECTED_VERSION STREQUAL "") 166 | message(WARNING "Could not parse JSSC version from pom.xml, defaulting to \"${JSSC_VERSION}\"") 167 | else() 168 | set(JSSC_VERSION "${DETECTED_VERSION}") 169 | message(STATUS "Found JSSC version \"${JSSC_VERSION}\" in pom.xml") 170 | endif() 171 | break() 172 | endif() 173 | endforeach() 174 | else() 175 | message(STATUS "Release JSSC version based on pom.xml: \"${JSSC_VERSION}\"") 176 | endif() 177 | configure_file(src/main/cpp/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h @ONLY) 178 | 179 | add_library(jssc SHARED src/main/cpp/${CPP_SOURCE}/jssc.cpp) 180 | 181 | # Fall-back header for when maven is not available 182 | list(APPEND JSSC_ADDITIONAL_INCLUDES src/main/cpp/) 183 | target_include_directories(jssc PRIVATE ${JNI_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${JSSC_ADDITIONAL_INCLUDES}) 184 | 185 | set_target_properties(jssc PROPERTIES PUBLIC_HEADER ${CMAKE_CURRENT_BINARY_DIR}/jssc_SerialNativeInterface.h) 186 | set_target_properties(jssc PROPERTIES POSITION_INDEPENDENT_CODE ON) 187 | if(WIN32) 188 | # Fix paths for MSVC (Debug/Release) and MINGW 189 | set_target_properties(jssc PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") 190 | set_target_properties(jssc PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") 191 | endif() 192 | 193 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT WIN32 AND NOT FORCE_IGNORE) 194 | if(FORCE_M32) 195 | # Build 32-bit binary on Linux 196 | set_target_properties(jssc PROPERTIES COMPILE_FLAGS -m32 LINK_FLAGS -m32) 197 | elseif(FORCE_M64) 198 | # Build 64-bit binary on Linux 199 | set_target_properties(jssc PROPERTIES COMPILE_FLAGS -m64 LINK_FLAGS -m64) 200 | endif() 201 | endif() 202 | 203 | # Call strip on non-debug builds 204 | if(CMAKE_STRIP AND NOT CMAKE_BUILD_TYPE MATCHES "Deb") 205 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 206 | set(STRIP_ARGS -x) 207 | endif() 208 | add_custom_command(TARGET jssc POST_BUILD COMMAND "${CMAKE_STRIP}" ${STRIP_ARGS} $) 209 | endif() 210 | 211 | # Copy native library to target/classes for processing by junit, maven 212 | add_custom_command(TARGET jssc POST_BUILD 213 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/natives/ ${CMAKE_CURRENT_BINARY_DIR}/../classes/natives/ 214 | ) 215 | 216 | # Handle compiler warnings 217 | if(MSVC) 218 | #TODO Treat warnings as errors /WX 219 | target_compile_options(jssc PRIVATE /W4) 220 | else() 221 | #TODO Treat warnings as errors -Werror 222 | target_compile_options(jssc PRIVATE -Wall -Wextra -pedantic -Wno-long-long) 223 | endif() 224 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Travis-CI Status](https://travis-ci.org/java-native/jssc.svg?branch=master) 2 | 3 | A small, single Java library for working with serial ports across various systems based on the work from [scream3r/java-simple-serial-connector](https://github.com/scream3r/java-simple-serial-connector). 4 | 5 | ### Usage 6 | * [Download `.jar` manually](../../releases) or add using maven 7 | ```xml 8 | 9 | io.github.java-native 10 | jssc 11 | 2.10.0 12 | 13 | ``` 14 | * or Gradle (KTS) 15 | ```gradle 16 | repositories { 17 | mavenCentral() 18 | } 19 | dependencies { 20 | implementation("io.github.java-native:jssc:2.10.0") 21 | } 22 | ``` 23 | * or Gradle (Groovy) 24 | ```gradle 25 | repositories { 26 | mavenCentral() 27 | } 28 | dependencies { 29 | implementation 'io.github.java-native:jssc:2.10.0' 30 | } 31 | ``` 32 | * [API code examples](../../wiki/examples) 33 | 34 | ### Support 35 | * [Report a bug or request a feature](../../issues/new) 36 | 37 | ### Developers 38 | * [Compile this project from source](../../wiki/compiling) 39 | * [Chat on Discord](https://discord.gg/RBsUfE9sX9) 40 | -------------------------------------------------------------------------------- /ant/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | Tests will run only if the TARGET and HOST match:${line.separator}${line.separator} 215 | TARGET: ${os.target.classifier} 216 | DETECTED: ${os.detected.classifier} 217 | 218 | 219 | 220 | 221 | 222 | 223 | ===== ${maven.test.message} ===== 224 | 225 | 226 | 227 | 228 | 229 | 230 | File information: 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.github.java-native 6 | jssc 7 | 2.10.1-SNAPSHOT 8 | 9 | Java Simple Serial Connector 10 | 11 | A small, single Java library for working with serial ports across various systems 12 | based on the work from scream3r/java-simple-serial-connector. 13 | 14 | https://github.com/java-native/jssc 15 | 16 | 17 | 18 | GNU LGPL 3 19 | http://www.gnu.org/licenses/lgpl.txt 20 | repo 21 | 22 | 23 | 24 | 25 | 26 | Tres Finocchiaro 27 | https://github.com/tresf 28 | 29 | 30 | 31 | 32 | scm:git:https://github.com/java-native/jssc.git 33 | scm:git:git@github.com:java-native/jssc.git 34 | https://github.com/java-native/jssc 35 | HEAD 36 | 37 | 38 | 39 | 6 40 | UTF-8 41 | 42 | 43 | ${project.build.directory}/cmake 44 | ${project.build.directory}/props.properties 45 | ${project.basedir} 46 | 47 | 48 | false 49 | false 50 | false 51 | true 52 | 53 | 54 | 4.13.2 55 | 2.22.0 56 | 1.2.3 57 | 2.5.0 58 | 59 | 60 | 1.17 61 | 1.8 62 | 3.1.1 63 | 3.2.0 64 | 3.8.0 65 | 3.0.0-M3 66 | 3.0.1 67 | 3.1.1 68 | 3.1.1 69 | 3.6.0 70 | 1.6.7 71 | 1.7.0 72 | 3.0.0-M4 73 | 1.1 74 | 3.0.1 75 | 3.0.0-M4 76 | true 77 | 78 | 79 | 80 | 81 | org.scijava 82 | native-lib-loader 83 | ${dependency.nativelibloader.version} 84 | 85 | 86 | org.apache.logging.log4j 87 | log4j-core 88 | ${dependency.log4j.version} 89 | test 90 | 91 | 92 | org.apache.logging.log4j 93 | log4j-slf4j-impl 94 | ${dependency.log4j.version} 95 | test 96 | 97 | 98 | junit 99 | junit 100 | ${dependency.junit.version} 101 | test 102 | 103 | 104 | 105 | 106 | install 107 | 108 | 109 | ${project.basedir}/src/main/resources-precompiled 110 | 111 | 112 | 113 | 114 | 115 | kr.motd.maven 116 | os-maven-plugin 117 | ${plugin.osmaven.version} 118 | 119 | 120 | 121 | 122 | 123 | 124 | org.apache.maven.plugins 125 | maven-compiler-plugin 126 | ${plugin.compiler.version} 127 | 128 | 129 | org.apache.maven.plugins 130 | maven-javadoc-plugin 131 | ${plugin.javadoc.version} 132 | 133 | 134 | 135 | org.apache.maven.plugins 136 | maven-source-plugin 137 | ${plugin.source.version} 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | org.codehaus.mojo 148 | build-helper-maven-plugin 149 | ${plugin.build-helper-maven-version} 150 | 151 | 152 | set-release-version 153 | 154 | parse-version 155 | regex-property 156 | 157 | 158 | release.version 159 | . 160 | - 161 | 162 | ${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion} 163 | 164 | 165 | 166 | 167 | 168 | 169 | org.apache.maven.plugins 170 | maven-enforcer-plugin 171 | ${plugin.enforcer.version} 172 | 173 | 174 | recommended-jdk 175 | enforce 176 | 177 | 178 | 179 | [9,) 180 | WARN 181 | Current JDK does not support Java Platform Module System. Resulting jar cannot be used as Java module. 182 | 183 | 184 | (,12) 185 | WARN 186 | Current JDK does not support target version 6. Minimal JRE to use the library on is ${target.java.version}. 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | com.github.maven-nar 197 | nar-maven-plugin 198 | ${plugin.nar.version} 199 | true 200 | 201 | 202 | default-nar-javah 203 | 204 | nar-javah 205 | 206 | compile 207 | 208 | ${javah.skip} 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | org.apache.maven.plugins 217 | maven-antrun-plugin 218 | ${plugin.antrun.version} 219 | 220 | 221 | 222 | gather-props 223 | validate 224 | run 225 | 226 | 227 | 228 | 229 | 230 | true 231 | 232 | 233 | 234 | 235 | cmake-generate 236 | run 237 | generate-sources 238 | 239 | ${cmake.generate.skip} 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | cmake-build 248 | run 249 | compile 250 | 251 | ${cmake.build.skip} 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | update-resources-precompiled 260 | prepare-package 261 | run 262 | 263 | ${update-resources-precompiled.skip} 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | show-file-info 272 | install 273 | run 274 | 275 | ${cmake.build.skip} 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | org.apache.maven.plugins 287 | maven-compiler-plugin 288 | 289 | ${target.java.version} 290 | ${target.java.version} 291 | -Xlint:all 292 | true 293 | true 294 | 295 | 296 | 297 | 298 | org.apache.maven.plugins 299 | maven-surefire-plugin 300 | ${plugin.surfire.version} 301 | 302 | 303 | false 304 | 305 | 306 | ${maven.exclude.tests} 307 | 308 | 309 | 310 | 311 | 312 | org.apache.maven.plugins 313 | maven-jar-plugin 314 | ${plugin.jar.version} 315 | 316 | 317 | 318 | org.apache.maven.plugins 319 | maven-javadoc-plugin 320 | 321 | 322 | 323 | 324 | foo 325 | bar 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | org.apache.maven.plugins 334 | maven-assembly-plugin 335 | ${plugin.assembly.version} 336 | 337 | 338 | 339 | make-assembly 340 | package 341 | 342 | single 343 | 344 | 345 | ${cmake.generate.skip} 346 | 347 | ${project.basedir}/src/assembly/one-off-jar.xml 348 | 349 | 350 | 351 | 352 | 353 | fat-jar 354 | package 355 | 356 | single 357 | 358 | 359 | ${jar.dependencies.skip} 360 | false 361 | 362 | jar-with-dependencies 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | org.codehaus.mojo 372 | animal-sniffer-maven-plugin 373 | ${plugin.animalsniffer.version} 374 | 375 | 376 | org.codehaus.mojo.signature 377 | java16 378 | ${plugin.signature.version} 379 | 380 | 381 | 382 | 383 | ensure-java-1.6-class-library 384 | verify 385 | 386 | check 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 400 | 401 | jdk9+ 402 | 403 | [9,) 404 | 405 | 406 | true 407 | ${target.java.version} 408 | 1.20 409 | 410 | 411 | 412 | 413 | maven-compiler-plugin 414 | 415 | 416 | -h 417 | ${cmake.generated.directory} 418 | 419 | 420 | 421 | 422 | 423 | default-compile 424 | 425 | 9 426 | 427 | src/main/java 428 | src/main/module-info 429 | 430 | 431 | 432 | 433 | 434 | minimal-target-jre-recompile 435 | compile 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 445 | 446 | jdk12+ 447 | 448 | [12,) 449 | 450 | 451 | 7 452 | 453 | 454 | 455 | 456 | 457 | update-resources-precompiled 458 | 459 | false 460 | 461 | 462 | 463 | 464 | 465 | package 466 | 467 | true 468 | true 469 | true 470 | true 471 | 472 | 473 | 474 | 475 | 476 | org.apache.maven.plugins 477 | maven-source-plugin 478 | 479 | 480 | attach-sources 481 | 482 | jar-no-fork 483 | 484 | 485 | 486 | 487 | 488 | 489 | org.apache.maven.plugins 490 | maven-javadoc-plugin 491 | 492 | 493 | attach-javadocs 494 | 495 | jar 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | jar-with-dependencies 506 | 507 | false 508 | 509 | 510 | 511 | 512 | 513 | dockcross 514 | 515 | Dockcross 516 | 517 | 518 | 519 | 520 | 521 | aarch64 522 | 523 | aarch_64 524 | 525 | 526 | 527 | 528 | 529 | riscv64 530 | 531 | Riscv64 532 | 533 | linux 534 | riscv64 535 | 64 536 | 537 | 538 | 539 | 540 | 541 | riscv32 542 | 543 | Riscv32 544 | 545 | linux 546 | riscv32 547 | 32 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | x86_64 556 | 557 | x86_64 558 | 559 | 560 | 561 | 562 | 563 | x86 564 | 565 | x86_32 566 | 567 | 568 | 569 | 570 | 571 | mingw32 572 | 573 | Mingw32 574 | 575 | windows 576 | x86_32 577 | 32 578 | 579 | 580 | 581 | 582 | 583 | mingw64 584 | 585 | Mingw64 586 | 587 | windows 588 | x86_64 589 | 64 590 | 591 | 592 | 593 | 594 | 595 | mingwaarch64 596 | 597 | MingwAarch64 598 | 599 | windows 600 | aarch_64 601 | 64 602 | 603 | 604 | 605 | 606 | 607 | ppc64 608 | 609 | Ppc64 610 | 611 | linux 612 | ppc_64 613 | 64 614 | 615 | 616 | 617 | 618 | 619 | armhf 620 | 621 | Armhf 622 | 623 | linux 624 | 625 | arm_32 626 | 32 627 | 628 | 629 | 630 | 631 | 632 | armsf 633 | 634 | Armsf 635 | 636 | linux 637 | 638 | arm_32 639 | 32 640 | 641 | 642 | 643 | 644 | maven-central-release 645 | 646 | 647 | 648 | org.apache.maven.plugins 649 | maven-gpg-plugin 650 | ${plugin.gpg.version} 651 | 652 | 653 | sign-artifacts 654 | verify 655 | 656 | sign 657 | 658 | 659 | 660 | 661 | java-native 662 | gpg.passphrase 663 | 664 | --pinentry-mode 665 | loopback 666 | 667 | 668 | 669 | 670 | org.apache.maven.plugins 671 | maven-release-plugin 672 | ${plugin.release.version} 673 | 674 | v@{project.version} 675 | false 676 | true 677 | deploy 678 | 679 | 680 | 681 | org.sonatype.plugins 682 | nexus-staging-maven-plugin 683 | ${plugin.nexus-staging.version} 684 | true 685 | 686 | ossrh 687 | https://oss.sonatype.org/ 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | -------------------------------------------------------------------------------- /src/assembly/one-off-jar.xml: -------------------------------------------------------------------------------- 1 | 4 | 8 | ${maven.assembly.id} 9 | 10 | 11 | jar 12 | 13 | 14 | false 15 | 16 | 17 | 18 | / 19 | true 20 | true 21 | false 22 | true 23 | compile 24 | 25 | ${project.groupId}:${project.artifactId} 26 | 27 | 28 | 29 | 30 | 31 | 32 | ${cmake.generated.directory}/natives 33 | natives 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/cpp/jssc_SerialNativeInterface.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class jssc_SerialNativeInterface */ 4 | 5 | #ifndef _Included_jssc_SerialNativeInterface 6 | #define _Included_jssc_SerialNativeInterface 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | #undef jssc_SerialNativeInterface_OS_LINUX 11 | #define jssc_SerialNativeInterface_OS_LINUX 0L 12 | #undef jssc_SerialNativeInterface_OS_WINDOWS 13 | #define jssc_SerialNativeInterface_OS_WINDOWS 1L 14 | #undef jssc_SerialNativeInterface_OS_SOLARIS 15 | #define jssc_SerialNativeInterface_OS_SOLARIS 2L 16 | #undef jssc_SerialNativeInterface_OS_MAC_OS_X 17 | #define jssc_SerialNativeInterface_OS_MAC_OS_X 3L 18 | #undef jssc_SerialNativeInterface_ERR_PORT_BUSY 19 | #define jssc_SerialNativeInterface_ERR_PORT_BUSY -1LL 20 | #undef jssc_SerialNativeInterface_ERR_PORT_NOT_FOUND 21 | #define jssc_SerialNativeInterface_ERR_PORT_NOT_FOUND -2LL 22 | #undef jssc_SerialNativeInterface_ERR_PERMISSION_DENIED 23 | #define jssc_SerialNativeInterface_ERR_PERMISSION_DENIED -3LL 24 | #undef jssc_SerialNativeInterface_ERR_INCORRECT_SERIAL_PORT 25 | #define jssc_SerialNativeInterface_ERR_INCORRECT_SERIAL_PORT -4LL 26 | /* 27 | * Class: jssc_SerialNativeInterface 28 | * Method: getNativeLibraryVersion 29 | * Signature: ()Ljava/lang/String; 30 | */ 31 | JNIEXPORT jstring JNICALL Java_jssc_SerialNativeInterface_getNativeLibraryVersion 32 | (JNIEnv *, jclass); 33 | 34 | /* 35 | * Class: jssc_SerialNativeInterface 36 | * Method: openPort 37 | * Signature: (Ljava/lang/String;Z)J 38 | */ 39 | JNIEXPORT jlong JNICALL Java_jssc_SerialNativeInterface_openPort 40 | (JNIEnv *, jobject, jstring, jboolean); 41 | 42 | /* 43 | * Class: jssc_SerialNativeInterface 44 | * Method: setParams 45 | * Signature: (JIIIIZZI)Z 46 | */ 47 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setParams 48 | (JNIEnv *, jobject, jlong, jint, jint, jint, jint, jboolean, jboolean, jint); 49 | 50 | /* 51 | * Class: jssc_SerialNativeInterface 52 | * Method: purgePort 53 | * Signature: (JI)Z 54 | */ 55 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_purgePort 56 | (JNIEnv *, jobject, jlong, jint); 57 | 58 | /* 59 | * Class: jssc_SerialNativeInterface 60 | * Method: closePort 61 | * Signature: (J)Z 62 | */ 63 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_closePort 64 | (JNIEnv *, jobject, jlong); 65 | 66 | /* 67 | * Class: jssc_SerialNativeInterface 68 | * Method: setEventsMask 69 | * Signature: (JI)Z 70 | */ 71 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setEventsMask 72 | (JNIEnv *, jobject, jlong, jint); 73 | 74 | /* 75 | * Class: jssc_SerialNativeInterface 76 | * Method: getEventsMask 77 | * Signature: (J)I 78 | */ 79 | JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_getEventsMask 80 | (JNIEnv *, jobject, jlong); 81 | 82 | /* 83 | * Class: jssc_SerialNativeInterface 84 | * Method: waitEvents 85 | * Signature: (J)[[I 86 | */ 87 | JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_waitEvents 88 | (JNIEnv *, jobject, jlong); 89 | 90 | /* 91 | * Class: jssc_SerialNativeInterface 92 | * Method: setRTS 93 | * Signature: (JZ)Z 94 | */ 95 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setRTS 96 | (JNIEnv *, jobject, jlong, jboolean); 97 | 98 | /* 99 | * Class: jssc_SerialNativeInterface 100 | * Method: setDTR 101 | * Signature: (JZ)Z 102 | */ 103 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setDTR 104 | (JNIEnv *, jobject, jlong, jboolean); 105 | 106 | /* 107 | * Class: jssc_SerialNativeInterface 108 | * Method: readBytes 109 | * Signature: (JI)[B 110 | */ 111 | JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes 112 | (JNIEnv *, jobject, jlong, jint); 113 | 114 | /* 115 | * Class: jssc_SerialNativeInterface 116 | * Method: writeBytes 117 | * Signature: (J[B)Z 118 | */ 119 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_writeBytes 120 | (JNIEnv *, jobject, jlong, jbyteArray); 121 | 122 | /* 123 | * Class: jssc_SerialNativeInterface 124 | * Method: getBuffersBytesCount 125 | * Signature: (J)[I 126 | */ 127 | JNIEXPORT jintArray JNICALL Java_jssc_SerialNativeInterface_getBuffersBytesCount 128 | (JNIEnv *, jobject, jlong); 129 | 130 | /* 131 | * Class: jssc_SerialNativeInterface 132 | * Method: setFlowControlMode 133 | * Signature: (JI)Z 134 | */ 135 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setFlowControlMode 136 | (JNIEnv *, jobject, jlong, jint); 137 | 138 | /* 139 | * Class: jssc_SerialNativeInterface 140 | * Method: getFlowControlMode 141 | * Signature: (J)I 142 | */ 143 | JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_getFlowControlMode 144 | (JNIEnv *, jobject, jlong); 145 | 146 | /* 147 | * Class: jssc_SerialNativeInterface 148 | * Method: getSerialPortNames 149 | * Signature: ()[Ljava/lang/String; 150 | */ 151 | JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_getSerialPortNames 152 | (JNIEnv *, jobject); 153 | 154 | /* 155 | * Class: jssc_SerialNativeInterface 156 | * Method: getLinesStatus 157 | * Signature: (J)[I 158 | */ 159 | JNIEXPORT jintArray JNICALL Java_jssc_SerialNativeInterface_getLinesStatus 160 | (JNIEnv *, jobject, jlong); 161 | 162 | /* 163 | * Class: jssc_SerialNativeInterface 164 | * Method: sendBreak 165 | * Signature: (JI)Z 166 | */ 167 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_sendBreak 168 | (JNIEnv *, jobject, jlong, jint); 169 | 170 | #ifdef __cplusplus 171 | } 172 | #endif 173 | #endif -------------------------------------------------------------------------------- /src/main/cpp/version.h.in: -------------------------------------------------------------------------------- 1 | #cmakedefine JSSC_VERSION "@JSSC_VERSION@" 2 | -------------------------------------------------------------------------------- /src/main/cpp/windows/jssc.cpp: -------------------------------------------------------------------------------- 1 | /* jSSC (Java Simple Serial Connector) - serial port communication library. 2 | * © Alexey Sokolov (scream3r), 2010-2014. 3 | * 4 | * This file is part of jSSC. 5 | * 6 | * jSSC is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * jSSC is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with jSSC. If not, see . 18 | * 19 | * If you use jSSC in public project you can inform me about this by e-mail, 20 | * of course if you want it. 21 | * 22 | * e-mail: scream3r.org@gmail.com 23 | * web-site: http://scream3r.org | http://code.google.com/p/java-simple-serial-connector/ 24 | */ 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "version.h" 31 | 32 | //#include 33 | 34 | #define MAX_PORT_NAME_STR_LEN 32 35 | 36 | /* 37 | * Get native library version 38 | */ 39 | JNIEXPORT jstring JNICALL Java_jssc_SerialNativeInterface_getNativeLibraryVersion(JNIEnv *env, jclass) { 40 | return env->NewStringUTF(JSSC_VERSION); 41 | } 42 | 43 | /* 44 | * Port opening. 45 | * 46 | * In 2.2.0 added useTIOCEXCL (not used in Windows, only for compatibility with _nix version) 47 | */ 48 | JNIEXPORT jlong JNICALL Java_jssc_SerialNativeInterface_openPort(JNIEnv *env, jobject, jstring portName, jboolean){ 49 | char prefix[] = "\\\\.\\"; 50 | const char* port = env->GetStringUTFChars(portName, JNI_FALSE); 51 | 52 | //since 2.1.0 -> string concat fix 53 | char portFullName[MAX_PORT_NAME_STR_LEN]; 54 | 55 | if(strlen(prefix) + strlen(port) + 1 > sizeof(portFullName)){ 56 | return (jlong)((HANDLE)jssc_SerialNativeInterface_ERR_PORT_NOT_FOUND); 57 | } 58 | 59 | strcpy_s(portFullName, prefix); 60 | strcat_s(portFullName, port); 61 | //<- since 2.1.0 62 | 63 | HANDLE hComm = CreateFile(portFullName, 64 | GENERIC_READ | GENERIC_WRITE, 65 | 0, 66 | 0, 67 | OPEN_EXISTING, 68 | FILE_FLAG_OVERLAPPED, 69 | 0); 70 | env->ReleaseStringUTFChars(portName, port); 71 | 72 | //since 2.3.0 -> 73 | if(hComm != INVALID_HANDLE_VALUE){ 74 | DCB *dcb = new DCB(); 75 | if(!GetCommState(hComm, dcb)){ 76 | CloseHandle(hComm);//since 2.7.0 77 | hComm = (HANDLE)jssc_SerialNativeInterface_ERR_INCORRECT_SERIAL_PORT;//(-4)Incorrect serial port 78 | } 79 | delete dcb; 80 | } 81 | else { 82 | DWORD errorValue = GetLastError(); 83 | if(errorValue == ERROR_ACCESS_DENIED){ 84 | hComm = (HANDLE)jssc_SerialNativeInterface_ERR_PORT_BUSY;//(-1)Port busy 85 | } 86 | else if(errorValue == ERROR_FILE_NOT_FOUND){ 87 | hComm = (HANDLE)jssc_SerialNativeInterface_ERR_PORT_NOT_FOUND;//(-2)Port not found 88 | } 89 | } 90 | //<- since 2.3.0 91 | return (jlong)hComm;//since 2.4.0 changed to jlong 92 | } 93 | 94 | /* 95 | * Setting serial port params. 96 | * 97 | * In 2.6.0 added flags (not used in Windows, only for compatibility with _nix version) 98 | */ 99 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setParams 100 | (JNIEnv *, jobject, jlong portHandle, jint baudRate, jint byteSize, jint stopBits, jint parity, jboolean setRTS, jboolean setDTR, jint){ 101 | HANDLE hComm = (HANDLE)portHandle; 102 | DCB *dcb = new DCB(); 103 | jboolean returnValue = JNI_FALSE; 104 | if(GetCommState(hComm, dcb)){ 105 | dcb->BaudRate = static_cast(baudRate); 106 | dcb->ByteSize = static_cast(byteSize); 107 | dcb->StopBits = static_cast(stopBits); 108 | dcb->Parity = static_cast(parity); 109 | 110 | //since 0.8 -> 111 | if(setRTS == JNI_TRUE){ 112 | dcb->fRtsControl = RTS_CONTROL_ENABLE; 113 | } 114 | else { 115 | dcb->fRtsControl = RTS_CONTROL_DISABLE; 116 | } 117 | if(setDTR == JNI_TRUE){ 118 | dcb->fDtrControl = DTR_CONTROL_ENABLE; 119 | } 120 | else { 121 | dcb->fDtrControl = DTR_CONTROL_DISABLE; 122 | } 123 | dcb->fOutxCtsFlow = FALSE; 124 | dcb->fOutxDsrFlow = FALSE; 125 | dcb->fDsrSensitivity = FALSE; 126 | dcb->fTXContinueOnXoff = TRUE; 127 | dcb->fOutX = FALSE; 128 | dcb->fInX = FALSE; 129 | dcb->fErrorChar = FALSE; 130 | dcb->fNull = FALSE; 131 | dcb->fAbortOnError = FALSE; 132 | dcb->XonLim = 2048; 133 | dcb->XoffLim = 512; 134 | dcb->XonChar = (char)17; //DC1 135 | dcb->XoffChar = (char)19; //DC3 136 | //<- since 0.8 137 | 138 | if(SetCommState(hComm, dcb)){ 139 | 140 | //since 2.1.0 -> timeouts set previously by another application should be cleared 141 | COMMTIMEOUTS *lpCommTimeouts = new COMMTIMEOUTS(); 142 | lpCommTimeouts->ReadIntervalTimeout = 0; 143 | lpCommTimeouts->ReadTotalTimeoutConstant = 0; 144 | lpCommTimeouts->ReadTotalTimeoutMultiplier = 0; 145 | lpCommTimeouts->WriteTotalTimeoutConstant = 0; 146 | lpCommTimeouts->WriteTotalTimeoutMultiplier = 0; 147 | if(SetCommTimeouts(hComm, lpCommTimeouts)){ 148 | returnValue = JNI_TRUE; 149 | } 150 | delete lpCommTimeouts; 151 | //<- since 2.1.0 152 | } 153 | } 154 | delete dcb; 155 | return returnValue; 156 | } 157 | 158 | /* 159 | * PurgeComm 160 | */ 161 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_purgePort 162 | (JNIEnv *, jobject, jlong portHandle, jint flags){ 163 | HANDLE hComm = (HANDLE)portHandle; 164 | DWORD dwFlags = (DWORD)flags; 165 | return (PurgeComm(hComm, dwFlags) ? JNI_TRUE : JNI_FALSE); 166 | } 167 | 168 | /* 169 | * Port closing 170 | */ 171 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_closePort 172 | (JNIEnv *, jobject, jlong portHandle){ 173 | HANDLE hComm = (HANDLE)portHandle; 174 | return (CloseHandle(hComm) ? JNI_TRUE : JNI_FALSE); 175 | } 176 | 177 | /* 178 | * Set events mask 179 | */ 180 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setEventsMask 181 | (JNIEnv *, jobject, jlong portHandle, jint mask){ 182 | HANDLE hComm = (HANDLE)portHandle; 183 | DWORD dwEvtMask = (DWORD)mask; 184 | return (SetCommMask(hComm, dwEvtMask) ? JNI_TRUE : JNI_FALSE); 185 | } 186 | 187 | /* 188 | * Get events mask 189 | */ 190 | JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_getEventsMask 191 | (JNIEnv *, jobject, jlong portHandle){ 192 | HANDLE hComm = (HANDLE)portHandle; 193 | DWORD lpEvtMask; 194 | if(GetCommMask(hComm, &lpEvtMask)){ 195 | return (jint)lpEvtMask; 196 | } 197 | else { 198 | return -1; 199 | } 200 | } 201 | 202 | /* 203 | * Change RTS line state (ON || OFF) 204 | */ 205 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setRTS 206 | (JNIEnv *, jobject, jlong portHandle, jboolean enabled){ 207 | HANDLE hComm = (HANDLE)portHandle; 208 | if(enabled == JNI_TRUE){ 209 | return (EscapeCommFunction(hComm, SETRTS) ? JNI_TRUE : JNI_FALSE); 210 | } 211 | else { 212 | return (EscapeCommFunction(hComm, CLRRTS) ? JNI_TRUE : JNI_FALSE); 213 | } 214 | } 215 | 216 | /* 217 | * Change DTR line state (ON || OFF) 218 | */ 219 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setDTR 220 | (JNIEnv *, jobject, jlong portHandle, jboolean enabled){ 221 | HANDLE hComm = (HANDLE)portHandle; 222 | if(enabled == JNI_TRUE){ 223 | return (EscapeCommFunction(hComm, SETDTR) ? JNI_TRUE : JNI_FALSE); 224 | } 225 | else { 226 | return (EscapeCommFunction(hComm, CLRDTR) ? JNI_TRUE : JNI_FALSE); 227 | } 228 | } 229 | 230 | /* 231 | * Write data to port 232 | * portHandle - port handle 233 | * buffer - byte array for sending 234 | */ 235 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_writeBytes 236 | (JNIEnv *env, jobject, jlong portHandle, jbyteArray buffer){ 237 | HANDLE hComm = (HANDLE)portHandle; 238 | DWORD lpNumberOfBytesTransferred; 239 | DWORD lpNumberOfBytesWritten; 240 | jboolean returnValue = JNI_FALSE; 241 | if( buffer == NULL ){ 242 | jclass exClz = env->FindClass("java/lang/NullPointerException"); 243 | if( exClz != NULL ) env->ThrowNew(exClz, "buffer"); 244 | return 0; 245 | } 246 | jbyte* jBuffer = env->GetByteArrayElements(buffer, JNI_FALSE); 247 | if( jBuffer == NULL ){ 248 | jclass exClz = env->FindClass("java/lang/RuntimeException"); 249 | if( exClz != NULL ) env->ThrowNew(exClz, "jni->GetByteArrayElements() failed"); 250 | return 0; 251 | } 252 | OVERLAPPED *overlapped = new OVERLAPPED(); 253 | overlapped->hEvent = CreateEventA(NULL, true, false, NULL); 254 | if(WriteFile(hComm, jBuffer, (DWORD)env->GetArrayLength(buffer), &lpNumberOfBytesWritten, overlapped)){ 255 | returnValue = JNI_TRUE; 256 | } 257 | else if(GetLastError() == ERROR_IO_PENDING){ 258 | if(WaitForSingleObject(overlapped->hEvent, INFINITE) == WAIT_OBJECT_0){ 259 | if(GetOverlappedResult(hComm, overlapped, &lpNumberOfBytesTransferred, false)){ 260 | returnValue = JNI_TRUE; 261 | } 262 | } 263 | } 264 | env->ReleaseByteArrayElements(buffer, jBuffer, 0); 265 | CloseHandle(overlapped->hEvent); 266 | delete overlapped; 267 | return returnValue; 268 | } 269 | 270 | /* 271 | * Read data from port 272 | * portHandle - port handle 273 | * byteCount - count of bytes for reading 274 | */ 275 | JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes 276 | (JNIEnv *env, jobject, jlong portHandle, jint byteCount){ 277 | HANDLE hComm = (HANDLE)portHandle; 278 | DWORD lpNumberOfBytesTransferred; 279 | DWORD lpNumberOfBytesRead; 280 | jbyteArray returnArray = NULL; 281 | jbyte *lpBuffer = NULL; 282 | OVERLAPPED *overlapped = NULL; 283 | 284 | if( byteCount <= 0 ){ 285 | char emsg[64]; emsg[0] = '\0'; 286 | snprintf(emsg, sizeof emsg, "byteCount %d. Expected range: 1..2147483647", byteCount); 287 | jclass exClz = env->FindClass("java/lang/IllegalArgumentException"); 288 | if( exClz ) env->ThrowNew(exClz, emsg); 289 | returnArray = NULL; goto Finally; 290 | } 291 | 292 | returnArray = env->NewByteArray(byteCount); 293 | if( returnArray == NULL ) goto Finally; 294 | 295 | lpBuffer = (jbyte*)malloc(byteCount*sizeof*lpBuffer); 296 | if( !lpBuffer ){ 297 | char emsg[32]; emsg[0] = '\0'; 298 | snprintf(emsg, sizeof emsg, "malloc(%d) failed", byteCount*sizeof*lpBuffer); 299 | jclass exClz = env->FindClass("java/lang/RuntimeException"); 300 | if( exClz ) env->ThrowNew(exClz, emsg); 301 | returnArray = NULL; goto Finally; 302 | } 303 | 304 | overlapped = new OVERLAPPED(); 305 | overlapped->hEvent = CreateEventA(NULL, true, false, NULL); 306 | if(ReadFile(hComm, lpBuffer, (DWORD)byteCount, &lpNumberOfBytesRead, overlapped)){ 307 | env->SetByteArrayRegion(returnArray, 0, byteCount, lpBuffer); 308 | } 309 | else if(GetLastError() == ERROR_IO_PENDING){ 310 | if(WaitForSingleObject(overlapped->hEvent, INFINITE) == WAIT_OBJECT_0){ 311 | if(GetOverlappedResult(hComm, overlapped, &lpNumberOfBytesTransferred, false)){ 312 | env->SetByteArrayRegion(returnArray, 0, byteCount, lpBuffer); 313 | } 314 | } 315 | } 316 | else if(GetLastError() == ERROR_INVALID_HANDLE){ 317 | jclass exClz = env->FindClass("java/lang/IllegalArgumentException"); 318 | if( exClz != NULL ) env->ThrowNew(exClz, "EBADF"); 319 | } 320 | Finally: 321 | if( overlapped ){ 322 | CloseHandle(overlapped->hEvent); 323 | delete overlapped; 324 | } 325 | if( lpBuffer ) free(lpBuffer); 326 | return returnArray; 327 | } 328 | 329 | /* 330 | * Get bytes count in serial port buffers (Input and Output) 331 | */ 332 | JNIEXPORT jintArray JNICALL Java_jssc_SerialNativeInterface_getBuffersBytesCount 333 | (JNIEnv *env, jobject, jlong portHandle){ 334 | HANDLE hComm = (HANDLE)portHandle; 335 | jint returnValues[2]; 336 | returnValues[0] = -1; 337 | returnValues[1] = -1; 338 | jintArray returnArray = env->NewIntArray(2); 339 | DWORD lpErrors; 340 | COMSTAT *comstat = new COMSTAT(); 341 | if(ClearCommError(hComm, &lpErrors, comstat)){ 342 | returnValues[0] = (jint)comstat->cbInQue; 343 | returnValues[1] = (jint)comstat->cbOutQue; 344 | } 345 | else { 346 | returnValues[0] = -1; 347 | returnValues[1] = -1; 348 | } 349 | delete comstat; 350 | env->SetIntArrayRegion(returnArray, 0, 2, returnValues); 351 | return returnArray; 352 | } 353 | 354 | //since 0.8 -> 355 | const jint FLOWCONTROL_NONE = 0; 356 | const jint FLOWCONTROL_RTSCTS_IN = 1; 357 | const jint FLOWCONTROL_RTSCTS_OUT = 2; 358 | const jint FLOWCONTROL_XONXOFF_IN = 4; 359 | const jint FLOWCONTROL_XONXOFF_OUT = 8; 360 | //<- since 0.8 361 | 362 | /* 363 | * Setting flow control mode 364 | * 365 | * since 0.8 366 | */ 367 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_setFlowControlMode 368 | (JNIEnv *, jobject, jlong portHandle, jint mask){ 369 | HANDLE hComm = (HANDLE)portHandle; 370 | jboolean returnValue = JNI_FALSE; 371 | DCB *dcb = new DCB(); 372 | if(GetCommState(hComm, dcb)){ 373 | dcb->fRtsControl = RTS_CONTROL_ENABLE; 374 | dcb->fOutxCtsFlow = FALSE; 375 | dcb->fOutX = FALSE; 376 | dcb->fInX = FALSE; 377 | if(mask != FLOWCONTROL_NONE){ 378 | if((mask & FLOWCONTROL_RTSCTS_IN) == FLOWCONTROL_RTSCTS_IN){ 379 | dcb->fRtsControl = RTS_CONTROL_HANDSHAKE; 380 | } 381 | if((mask & FLOWCONTROL_RTSCTS_OUT) == FLOWCONTROL_RTSCTS_OUT){ 382 | dcb->fOutxCtsFlow = TRUE; 383 | } 384 | if((mask & FLOWCONTROL_XONXOFF_IN) == FLOWCONTROL_XONXOFF_IN){ 385 | dcb->fInX = TRUE; 386 | } 387 | if((mask & FLOWCONTROL_XONXOFF_OUT) == FLOWCONTROL_XONXOFF_OUT){ 388 | dcb->fOutX = TRUE; 389 | } 390 | } 391 | if(SetCommState(hComm, dcb)){ 392 | returnValue = JNI_TRUE; 393 | } 394 | } 395 | delete dcb; 396 | return returnValue; 397 | } 398 | 399 | /* 400 | * Getting flow control mode 401 | * 402 | * since 0.8 403 | */ 404 | JNIEXPORT jint JNICALL Java_jssc_SerialNativeInterface_getFlowControlMode 405 | (JNIEnv *, jobject, jlong portHandle){ 406 | HANDLE hComm = (HANDLE)portHandle; 407 | jint returnValue = 0; 408 | DCB *dcb = new DCB(); 409 | if(GetCommState(hComm, dcb)){ 410 | if(dcb->fRtsControl == RTS_CONTROL_HANDSHAKE){ 411 | returnValue |= FLOWCONTROL_RTSCTS_IN; 412 | } 413 | if(dcb->fOutxCtsFlow == TRUE){ 414 | returnValue |= FLOWCONTROL_RTSCTS_OUT; 415 | } 416 | if(dcb->fInX == TRUE){ 417 | returnValue |= FLOWCONTROL_XONXOFF_IN; 418 | } 419 | if(dcb->fOutX == TRUE){ 420 | returnValue |= FLOWCONTROL_XONXOFF_OUT; 421 | } 422 | } 423 | delete dcb; 424 | return returnValue; 425 | } 426 | 427 | /* 428 | * Send break for set duration 429 | * 430 | * since 0.8 431 | */ 432 | JNIEXPORT jboolean JNICALL Java_jssc_SerialNativeInterface_sendBreak 433 | (JNIEnv *, jobject, jlong portHandle, jint duration){ 434 | HANDLE hComm = (HANDLE)portHandle; 435 | jboolean returnValue = JNI_FALSE; 436 | if(duration > 0){ 437 | if(SetCommBreak(hComm) > 0){ 438 | Sleep(duration); 439 | if(ClearCommBreak(hComm) > 0){ 440 | returnValue = JNI_TRUE; 441 | } 442 | } 443 | } 444 | return returnValue; 445 | } 446 | 447 | /* 448 | * Wait event 449 | * portHandle - port handle 450 | */ 451 | JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_waitEvents 452 | (JNIEnv *env, jobject, jlong portHandle) { 453 | HANDLE hComm = (HANDLE)portHandle; 454 | DWORD lpEvtMask = 0; 455 | DWORD lpNumberOfBytesTransferred = 0; 456 | OVERLAPPED *overlapped = new OVERLAPPED(); 457 | jclass intClass = env->FindClass("[I"); 458 | jobjectArray returnArray; 459 | boolean functionSuccessful = false; 460 | overlapped->hEvent = CreateEventA(NULL, true, false, NULL); 461 | if(WaitCommEvent(hComm, &lpEvtMask, overlapped)){ 462 | functionSuccessful = true; 463 | } 464 | else if(GetLastError() == ERROR_IO_PENDING){ 465 | if(WaitForSingleObject(overlapped->hEvent, INFINITE) == WAIT_OBJECT_0){ 466 | if(GetOverlappedResult(hComm, overlapped, &lpNumberOfBytesTransferred, false)){ 467 | functionSuccessful = true; 468 | } 469 | } 470 | } 471 | if(functionSuccessful){ 472 | boolean executeGetCommModemStatus = false; 473 | boolean executeClearCommError = false; 474 | DWORD events[9];//fixed since 0.8 (old value is 8) 475 | jint eventsCount = 0; 476 | if((EV_BREAK & lpEvtMask) == EV_BREAK){ 477 | events[eventsCount] = EV_BREAK; 478 | eventsCount++; 479 | } 480 | if((EV_CTS & lpEvtMask) == EV_CTS){ 481 | events[eventsCount] = EV_CTS; 482 | eventsCount++; 483 | executeGetCommModemStatus = true; 484 | } 485 | if((EV_DSR & lpEvtMask) == EV_DSR){ 486 | events[eventsCount] = EV_DSR; 487 | eventsCount++; 488 | executeGetCommModemStatus = true; 489 | } 490 | if((EV_ERR & lpEvtMask) == EV_ERR){ 491 | events[eventsCount] = EV_ERR; 492 | eventsCount++; 493 | executeClearCommError = true; 494 | } 495 | if((EV_RING & lpEvtMask) == EV_RING){ 496 | events[eventsCount] = EV_RING; 497 | eventsCount++; 498 | executeGetCommModemStatus = true; 499 | } 500 | if((EV_RLSD & lpEvtMask) == EV_RLSD){ 501 | events[eventsCount] = EV_RLSD; 502 | eventsCount++; 503 | executeGetCommModemStatus = true; 504 | } 505 | if((EV_RXCHAR & lpEvtMask) == EV_RXCHAR){ 506 | events[eventsCount] = EV_RXCHAR; 507 | eventsCount++; 508 | executeClearCommError = true; 509 | } 510 | if((EV_RXFLAG & lpEvtMask) == EV_RXFLAG){ 511 | events[eventsCount] = EV_RXFLAG; 512 | eventsCount++; 513 | executeClearCommError = true; 514 | } 515 | if((EV_TXEMPTY & lpEvtMask) == EV_TXEMPTY){ 516 | events[eventsCount] = EV_TXEMPTY; 517 | eventsCount++; 518 | executeClearCommError = true; 519 | } 520 | /* 521 | * Execute GetCommModemStatus function if it's needed (get lines status) 522 | */ 523 | jint statusCTS = 0; 524 | jint statusDSR = 0; 525 | jint statusRING = 0; 526 | jint statusRLSD = 0; 527 | boolean successGetCommModemStatus = false; 528 | if(executeGetCommModemStatus){ 529 | DWORD lpModemStat; 530 | if(GetCommModemStatus(hComm, &lpModemStat)){ 531 | successGetCommModemStatus = true; 532 | if((MS_CTS_ON & lpModemStat) == MS_CTS_ON){ 533 | statusCTS = 1; 534 | } 535 | if((MS_DSR_ON & lpModemStat) == MS_DSR_ON){ 536 | statusDSR = 1; 537 | } 538 | if((MS_RING_ON & lpModemStat) == MS_RING_ON){ 539 | statusRING = 1; 540 | } 541 | if((MS_RLSD_ON & lpModemStat) == MS_RLSD_ON){ 542 | statusRLSD = 1; 543 | } 544 | } 545 | else { 546 | jint lastError = (jint)GetLastError(); 547 | statusCTS = lastError; 548 | statusDSR = lastError; 549 | statusRING = lastError; 550 | statusRLSD = lastError; 551 | } 552 | } 553 | /* 554 | * Execute ClearCommError function if it's needed (get count of bytes in buffers and errors) 555 | */ 556 | jint bytesCountIn = 0; 557 | jint bytesCountOut = 0; 558 | jint communicationsErrors = 0; 559 | boolean successClearCommError = false; 560 | if(executeClearCommError){ 561 | DWORD lpErrors; 562 | COMSTAT *comstat = new COMSTAT(); 563 | if(ClearCommError(hComm, &lpErrors, comstat)){ 564 | successClearCommError = true; 565 | bytesCountIn = (jint)comstat->cbInQue; 566 | bytesCountOut = (jint)comstat->cbOutQue; 567 | communicationsErrors = (jint)lpErrors; 568 | } 569 | else { 570 | jint lastError = (jint)GetLastError(); 571 | bytesCountIn = lastError; 572 | bytesCountOut = lastError; 573 | communicationsErrors = lastError; 574 | } 575 | delete comstat; 576 | } 577 | /* 578 | * Create int[][] for events values 579 | */ 580 | returnArray = env->NewObjectArray(eventsCount, intClass, NULL); 581 | /* 582 | * Set events values 583 | */ 584 | for(jint i = 0; i < eventsCount; i++){ 585 | jint returnValues[2]; 586 | switch(events[i]){ 587 | case EV_BREAK: 588 | returnValues[0] = (jint)events[i]; 589 | returnValues[1] = 0; 590 | goto forEnd; 591 | case EV_CTS: 592 | returnValues[1] = statusCTS; 593 | goto modemStatus; 594 | case EV_DSR: 595 | returnValues[1] = statusDSR; 596 | goto modemStatus; 597 | case EV_ERR: 598 | returnValues[1] = communicationsErrors; 599 | goto bytesAndErrors; 600 | case EV_RING: 601 | returnValues[1] = statusRING; 602 | goto modemStatus; 603 | case EV_RLSD: 604 | returnValues[1] = statusRLSD; 605 | goto modemStatus; 606 | case EV_RXCHAR: 607 | returnValues[1] = bytesCountIn; 608 | goto bytesAndErrors; 609 | case EV_RXFLAG: 610 | returnValues[1] = bytesCountIn; 611 | goto bytesAndErrors; 612 | case EV_TXEMPTY: 613 | returnValues[1] = bytesCountOut; 614 | goto bytesAndErrors; 615 | default: 616 | returnValues[0] = (jint)events[i]; 617 | returnValues[1] = 0; 618 | goto forEnd; 619 | }; 620 | modemStatus: { 621 | if(successGetCommModemStatus){ 622 | returnValues[0] = (jint)events[i]; 623 | } 624 | else { 625 | returnValues[0] = -1; 626 | } 627 | goto forEnd; 628 | } 629 | bytesAndErrors: { 630 | if(successClearCommError){ 631 | returnValues[0] = (jint)events[i]; 632 | } 633 | else { 634 | returnValues[0] = -1; 635 | } 636 | goto forEnd; 637 | } 638 | forEnd: { 639 | jintArray singleResultArray = env->NewIntArray(2); 640 | env->SetIntArrayRegion(singleResultArray, 0, 2, returnValues); 641 | env->SetObjectArrayElement(returnArray, i, singleResultArray); 642 | }; 643 | } 644 | } 645 | else { 646 | returnArray = env->NewObjectArray(1, intClass, NULL); 647 | jint returnValues[2]; 648 | returnValues[0] = -1; 649 | returnValues[1] = (jint)GetLastError(); 650 | jintArray singleResultArray = env->NewIntArray(2); 651 | env->SetIntArrayRegion(singleResultArray, 0, 2, returnValues); 652 | env->SetObjectArrayElement(returnArray, 0, singleResultArray); 653 | }; 654 | CloseHandle(overlapped->hEvent); 655 | delete overlapped; 656 | return returnArray; 657 | } 658 | 659 | /* 660 | * Get serial port names 661 | */ 662 | JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_getSerialPortNames 663 | (JNIEnv *env, jobject){ 664 | HKEY phkResult = NULL; 665 | LPCSTR lpSubKey = "HARDWARE\\DEVICEMAP\\SERIALCOMM\\"; 666 | jobjectArray returnArray = NULL; 667 | byte lpDataOnStack[256]; 668 | byte *lpData = lpDataOnStack; 669 | DWORD lpData_capacity = 256; 670 | char valueName[256]; 671 | DWORD valueNameSize; 672 | DWORD enumResult; 673 | boolean hasMoreElements = true; 674 | DWORD keysCount = 0; 675 | if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &phkResult) != ERROR_SUCCESS){ 676 | returnArray = NULL; 677 | goto Finally; 678 | } 679 | /* Iterate a 1st time to see how long our resulting array has to be. */ 680 | while(hasMoreElements){ 681 | valueNameSize = 256; 682 | enumResult = RegEnumValueA(phkResult, keysCount, valueName, &valueNameSize, NULL, NULL, NULL, NULL); 683 | if(enumResult == ERROR_SUCCESS){ 684 | keysCount++; 685 | } 686 | else if(enumResult == ERROR_NO_MORE_ITEMS){ 687 | hasMoreElements = false; 688 | } 689 | else { 690 | hasMoreElements = false; 691 | } 692 | } 693 | if(keysCount > 0){ 694 | jclass stringClass = env->FindClass("java/lang/String"); 695 | returnArray = env->NewObjectArray((jsize)keysCount, stringClass, NULL); 696 | DWORD lpcbData; 697 | DWORD result; 698 | /* iterate 2nd time but this time our array is ready to catch results. */ 699 | for(DWORD i = 0; i < keysCount; i++){ 700 | valueNameSize = 256; 701 | lpcbData = lpData_capacity; 702 | result = RegEnumValueA(phkResult, i, valueName, &valueNameSize, NULL, NULL, lpData, &lpcbData); 703 | if(result == ERROR_SUCCESS){ 704 | env->SetObjectArrayElement(returnArray, i, env->NewStringUTF((char*)lpData)); 705 | }else if(result == ERROR_MORE_DATA && lpData_capacity < UINT_MAX){ 706 | /* whoops our supplied buffer was not large enough. Fallback to a heap 707 | * allocd one. RegEnumValueA was kind enough to set 'lpcbData' to the 708 | * required length before return. */ 709 | lpData = (lpData == lpDataOnStack) ? NULL : lpData; 710 | /* MS doc is unclear to me if returned size includes the required 711 | * zero-term. So to stay safe, we provide one byte more. */ 712 | if(lpcbData < UINT_MAX) lpcbData += 1; 713 | byte *tmp = (byte*)realloc(lpData, lpcbData*sizeof*tmp); 714 | if(tmp == NULL){ 715 | jclass exClz = env->FindClass("java/lang/OutOfMemoryError"); 716 | if(exClz != NULL) env->ThrowNew(exClz, NULL); 717 | returnArray = NULL; 718 | goto Finally; 719 | } 720 | /* install new buffer and reset 'i' so we try the same element again. */ 721 | lpData_capacity = lpcbData; 722 | lpData = tmp; 723 | i -= 1; 724 | }else{ 725 | char exMsg[128]; 726 | snprintf(exMsg, sizeof exMsg, "RegEnumValueA(): Code %ld: " 727 | "https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes", 728 | result); 729 | jclass exClz = env->FindClass("java/lang/RuntimeException"); 730 | if(exClz != NULL) env->ThrowNew(exClz, exMsg); 731 | returnArray = NULL; 732 | goto Finally; 733 | } 734 | } 735 | } 736 | Finally: 737 | if(lpData != NULL && lpData != lpDataOnStack) free(lpData); 738 | if(phkResult != NULL) CloseHandle(phkResult); 739 | return returnArray; 740 | } 741 | 742 | /* 743 | * Get lines status 744 | * 745 | * returnValues[0] - CTS 746 | * returnValues[1] - DSR 747 | * returnValues[2] - RING 748 | * returnValues[3] - RLSD 749 | * 750 | */ 751 | JNIEXPORT jintArray JNICALL Java_jssc_SerialNativeInterface_getLinesStatus 752 | (JNIEnv *env, jobject, jlong portHandle){ 753 | HANDLE hComm = (HANDLE)portHandle; 754 | DWORD lpModemStat; 755 | jint returnValues[4]; 756 | for(jint i = 0; i < 4; i++){ 757 | returnValues[i] = 0; 758 | } 759 | jintArray returnArray = env->NewIntArray(4); 760 | if(GetCommModemStatus(hComm, &lpModemStat)){ 761 | if((MS_CTS_ON & lpModemStat) == MS_CTS_ON){ 762 | returnValues[0] = 1; 763 | } 764 | if((MS_DSR_ON & lpModemStat) == MS_DSR_ON){ 765 | returnValues[1] = 1; 766 | } 767 | if((MS_RING_ON & lpModemStat) == MS_RING_ON){ 768 | returnValues[2] = 1; 769 | } 770 | if((MS_RLSD_ON & lpModemStat) == MS_RLSD_ON){ 771 | returnValues[3] = 1; 772 | } 773 | } 774 | env->SetIntArrayRegion(returnArray, 0, 4, returnValues); 775 | return returnArray; 776 | } 777 | -------------------------------------------------------------------------------- /src/main/java/jssc/DefaultJniExtractorStub.java: -------------------------------------------------------------------------------- 1 | /** 2 | * License: https://opensource.org/licenses/BSD-3-Clause 3 | */ 4 | package jssc; 5 | 6 | import org.scijava.nativelib.DefaultJniExtractor; 7 | import org.scijava.nativelib.NativeLibraryUtil; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | 12 | /** 13 | * @author A. Tres Finocchiaro 14 | * 15 | * Stub DefaultJniExtractor class to allow native-lib-loader to conditionally 16 | * use a statically defined native search path bootPath when provided. 17 | */ 18 | public class DefaultJniExtractorStub extends DefaultJniExtractor { 19 | private File bootPath; 20 | 21 | /** 22 | * Default constructor 23 | */ 24 | public DefaultJniExtractorStub(Class libraryJarClass) throws IOException { 25 | super(libraryJarClass); 26 | } 27 | 28 | /** 29 | * Force native-lib-loader to first look in the location defined as bootPath 30 | * prior to extracting a native library, useful for sandboxed environments. 31 | * 32 | * NativeLoader.setJniExtractor(new DefaultJniExtractorStub(null, "/opt/nativelibs"))); 33 | * NativeLoader.loadLibrary("mylibrary"); 34 | * 35 | */ 36 | public DefaultJniExtractorStub(Class libraryJarClass, String bootPath) throws IOException { 37 | this(libraryJarClass); 38 | 39 | if(bootPath != null) { 40 | File bootTest = new File(bootPath); 41 | if(bootTest.exists()) { 42 | // assume a static, existing directory will contain the native libs 43 | this.bootPath = bootTest; 44 | } else { 45 | System.err.println("WARNING " + DefaultJniExtractorStub.class.getCanonicalName() + ": Boot path " + bootPath + " not found, falling back to default extraction behavior."); 46 | } 47 | } 48 | } 49 | 50 | /** 51 | * If a bootPath was provided to the constructor and exists, 52 | * calculate the File path without any extraction logic. 53 | * 54 | * If a bootPath was NOT provided or does NOT exist, fallback on 55 | * the default extraction behavior. 56 | */ 57 | @Override 58 | public File extractJni(String libPath, String libName) throws IOException { 59 | // Lie and pretend it's already extracted at the bootPath location 60 | if(bootPath != null) { 61 | return new File(bootPath, NativeLibraryUtil.getPlatformLibraryName(libName)); 62 | } 63 | // Fallback on default behavior 64 | return super.extractJni(libPath, libName); 65 | } 66 | 67 | @Override 68 | public void extractRegistered() throws IOException { 69 | if(bootPath != null) { 70 | return; // no-op 71 | } 72 | super.extractRegistered(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/jssc/SerialNativeInterface.java: -------------------------------------------------------------------------------- 1 | /* jSSC (Java Simple Serial Connector) - serial port communication library. 2 | * © Alexey Sokolov (scream3r), 2010-2014. 3 | * 4 | * This file is part of jSSC. 5 | * 6 | * jSSC is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * jSSC is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with jSSC. If not, see . 18 | * 19 | * If you use jSSC in public project you can inform me about this by e-mail, 20 | * of course if you want it. 21 | * 22 | * e-mail: scream3r.org@gmail.com 23 | * web-site: http://scream3r.org | http://code.google.com/p/java-simple-serial-connector/ 24 | */ 25 | package jssc; 26 | 27 | import org.scijava.nativelib.NativeLoader; 28 | 29 | import java.io.IOException; 30 | 31 | /** 32 | * 33 | * @author scream3r 34 | */ 35 | public class SerialNativeInterface { 36 | 37 | private static final String libVersion = "2.10.1"; 38 | 39 | /** Linux **/ 40 | public static final int OS_LINUX = 0; 41 | /** Windows **/ 42 | public static final int OS_WINDOWS = 1; 43 | /** Solaris **/ 44 | public static final int OS_SOLARIS = 2;//since 0.9.0 45 | /** MacOS **/ 46 | public static final int OS_MAC_OS_X = 3;//since 0.9.0 47 | /** Unknown **/ 48 | public static final int OS_UNKNOWN = -1;//since 0.9.0 49 | 50 | /** 51 | * Port is busy 52 | * 53 | * @since 2.3.0 54 | */ 55 | public static final long ERR_PORT_BUSY = -1; 56 | /** 57 | * Port is not found 58 | * 59 | * @since 2.3.0 60 | */ 61 | public static final long ERR_PORT_NOT_FOUND = -2; 62 | /** 63 | * Insufficient permissions to access port 64 | * 65 | * @since 2.3.0 66 | */ 67 | public static final long ERR_PERMISSION_DENIED = -3; 68 | /** 69 | * Serial port handle is incorrect 70 | * 71 | * @since 2.3.0 72 | */ 73 | public static final long ERR_INCORRECT_SERIAL_PORT = -4; 74 | 75 | /** 76 | * Disable exclusive lock for serial port 77 | * 78 | * Usage: 79 | * System.setProperty("jssc_no_tiocexcl", "true"); 80 | * 81 | * @since 2.6.0 82 | */ 83 | public static final String PROPERTY_JSSC_NO_TIOCEXCL = "JSSC_NO_TIOCEXCL"; 84 | /** 85 | * Ignore bytes with framing error or parity error 86 | * 87 | * Usage: 88 | * System.setProperty("jssc_ignpar", "true"); 89 | * 90 | * @since 2.6.0 91 | */ 92 | public static final String PROPERTY_JSSC_IGNPAR = "JSSC_IGNPAR"; 93 | /** 94 | * Mark bytes with parity error or framing error 95 | * 96 | * Usage: 97 | * System.setProperty("jssc_iparmrk", "true"); 98 | * 99 | * @since 2.6.0 100 | */ 101 | public static final String PROPERTY_JSSC_PARMRK = "JSSC_PARMRK"; 102 | 103 | private static int osType; 104 | static { 105 | String osName = System.getProperty("os.name"); 106 | if(osName.equals("Linux")) 107 | osType = OS_LINUX; 108 | else if(osName.startsWith("Win")) 109 | osType = OS_WINDOWS; 110 | else if(osName.equals("SunOS")) 111 | osType = OS_SOLARIS; 112 | else if(osName.equals("Mac OS X") || osName.equals("Darwin")) 113 | osType = OS_MAC_OS_X; 114 | else 115 | osType = OS_UNKNOWN; 116 | try { 117 | /* 118 | * JSSC includes a small, platform-specific shared library and uses native-lib-loader for extraction. 119 | * - First, native-lib-loader will attempt to load this library from the system library path. 120 | * - Next, it will fallback to jssc.boot.library.path 121 | * - Finally it will attempt to extract the library from from the jssc.jar file, and load it. 122 | */ 123 | NativeLoader.setJniExtractor(new DefaultJniExtractorStub(null, System.getProperty("jssc.boot.library.path"))); 124 | NativeLoader.loadLibrary("jssc"); 125 | } catch (IOException ioException) { 126 | throw new UnsatisfiedLinkError("Could not load the jssc library: " + ioException.getMessage()); 127 | } 128 | } 129 | 130 | /** 131 | * Default constructor 132 | * TODO: This class is effectively static, why instantiate it? 133 | */ 134 | public SerialNativeInterface() {} 135 | 136 | /** 137 | * Get OS type 138 | * 139 | * @return OS_LINUX, OS_WINDOWS, OS_SOLARIS,OS_MACOS 140 | * or OS_UNKNOWN if unknown. 141 | * 142 | * @since 0.8 143 | */ 144 | public static int getOsType() { 145 | return osType; 146 | } 147 | 148 | /** 149 | * Get library version 150 | * 151 | * @return Full library version in "major.minor.patch" format. 152 | * 153 | * @since 0.8 154 | */ 155 | public static String getLibraryVersion() { 156 | return libVersion; 157 | } 158 | 159 | /** 160 | * Get native library version 161 | * 162 | * @return Full native library version in "major.minor.patch" format. 163 | * 164 | * @since 2.8.0 165 | */ 166 | public static native String getNativeLibraryVersion(); 167 | 168 | /** 169 | * Open port 170 | * 171 | * @param portName name of port for opening 172 | * @param useTIOCEXCL enable/disable using of TIOCEXCL. Take effect only on *nix based systems 173 | * 174 | * @return handle of opened port or -1 if opening of the port was unsuccessful 175 | */ 176 | public native long openPort(String portName, boolean useTIOCEXCL); 177 | 178 | /** 179 | * Setting the parameters of opened port 180 | * 181 | * @param handle handle of opened port 182 | * @param baudRate data transfer rate 183 | * @param dataBits number of data bits 184 | * @param stopBits number of stop bits 185 | * @param parity parity 186 | * @param setRTS initial state of RTS line (ON/OFF) 187 | * @param setDTR initial state of DTR line (ON/OFF) 188 | * @param flags additional Native settings. Take effect only on *nix based systems 189 | * 190 | * @return If the operation is successfully completed, the method returns true, otherwise false 191 | */ 192 | public native boolean setParams(long handle, int baudRate, int dataBits, int stopBits, int parity, boolean setRTS, boolean setDTR, int flags); 193 | 194 | /** 195 | * Purge of input and output buffer 196 | * 197 | * @param handle handle of opened port 198 | * @param flags flags specifying required actions for purgePort method 199 | * 200 | * @return If the operation is successfully completed, the method returns true, otherwise false 201 | */ 202 | public native boolean purgePort(long handle, int flags); 203 | 204 | /** 205 | * Close port 206 | * 207 | * @param handle handle of opened port 208 | * 209 | * @return If the operation is successfully completed, the method returns true, otherwise false 210 | */ 211 | public native boolean closePort(long handle); 212 | 213 | /** 214 | * Set events mask 215 | * 216 | * @param handle handle of opened port 217 | * @param mask events mask 218 | * 219 | * @return If the operation is successfully completed, the method returns true, otherwise false 220 | */ 221 | public native boolean setEventsMask(long handle, int mask); 222 | 223 | /** 224 | * Get events mask 225 | * 226 | * @param handle handle of opened port 227 | * 228 | * @return Method returns event mask as a variable of int type 229 | */ 230 | public native int getEventsMask(long handle); 231 | 232 | /** 233 | * Wait events 234 | * 235 | * @param handle handle of opened port 236 | * 237 | * @return Method returns two-dimensional array containing event types and their values 238 | * (events[i][0] - event type, events[i][1] - event value). 239 | */ 240 | public native int[][] waitEvents(long handle); 241 | 242 | /** 243 | * Change RTS line state 244 | * 245 | * @param handle handle of opened port 246 | * @param value true - ON, false - OFF 247 | * 248 | * @return If the operation is successfully completed, the method returns true, otherwise false 249 | */ 250 | public native boolean setRTS(long handle, boolean value); 251 | 252 | /** 253 | * Change DTR line state 254 | * 255 | * @param handle handle of opened port 256 | * @param value true - ON, false - OFF 257 | * 258 | * @return If the operation is successfully completed, the method returns true, otherwise false 259 | */ 260 | public native boolean setDTR(long handle, boolean value); 261 | 262 | /** 263 | * Read data from port 264 | * 265 | * @param handle handle of opened port 266 | * @param byteCount count of bytes required to read 267 | * 268 | * @return Method returns the array of read bytes 269 | */ 270 | public native byte[] readBytes(long handle, int byteCount) throws IOException; 271 | 272 | /** 273 | * Write data to port 274 | * 275 | * @param handle handle of opened port 276 | * @param buffer array of bytes to write 277 | * 278 | * @return If the operation is successfully completed, the method returns true, otherwise false 279 | */ 280 | public native boolean writeBytes(long handle, byte[] buffer) throws IOException; 281 | 282 | /** 283 | * Get bytes count in buffers of port 284 | * 285 | * @param handle handle of opened port 286 | * 287 | * @return Method returns the array that contains info about bytes count in buffers: 288 | *
element 0 - input buffer 289 | *
element 1 - output buffer 290 | * 291 | * @since 0.8 292 | */ 293 | public native int[] getBuffersBytesCount(long handle) throws IOException; 294 | 295 | /** 296 | * Set flow control mode 297 | * 298 | * @param handle handle of opened port 299 | * @param mask mask of flow control mode 300 | * 301 | * @return If the operation is successfully completed, the method returns true, otherwise false 302 | * 303 | * @since 0.8 304 | */ 305 | public native boolean setFlowControlMode(long handle, int mask); 306 | 307 | /** 308 | * Get flow control mode 309 | * 310 | * @param handle handle of opened port 311 | * 312 | * @return Mask of set flow control mode 313 | * 314 | * @since 0.8 315 | */ 316 | public native int getFlowControlMode(long handle); 317 | 318 | /** 319 | * Get serial port names like an array of String 320 | * 321 | * @return unsorted array of String with port names 322 | */ 323 | public native String[] getSerialPortNames(); 324 | 325 | /** 326 | * Getting lines states 327 | * 328 | * @param handle handle of opened port 329 | * 330 | * @return Method returns the array containing information about lines in following order: 331 | *
element 0 - CTS line state 332 | *
element 1 - DSR line state 333 | *
element 2 - RING line state 334 | *
element 3 - RLSD line state 335 | */ 336 | public native int[] getLinesStatus(long handle); 337 | 338 | /** 339 | * Send Break signal for set duration 340 | * 341 | * @param handle handle of opened port 342 | * @param duration duration of Break signal, in milliseconds 343 | * @return If the operation is successfully completed, the method returns true, otherwise false 344 | * 345 | * @since 0.8 346 | */ 347 | public native boolean sendBreak(long handle, int duration); 348 | } 349 | -------------------------------------------------------------------------------- /src/main/java/jssc/SerialPortEvent.java: -------------------------------------------------------------------------------- 1 | /* jSSC (Java Simple Serial Connector) - serial port communication library. 2 | * © Alexey Sokolov (scream3r), 2010-2014. 3 | * 4 | * This file is part of jSSC. 5 | * 6 | * jSSC is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * jSSC is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with jSSC. If not, see . 18 | * 19 | * If you use jSSC in public project you can inform me about this by e-mail, 20 | * of course if you want it. 21 | * 22 | * e-mail: scream3r.org@gmail.com 23 | * web-site: http://scream3r.org | http://code.google.com/p/java-simple-serial-connector/ 24 | */ 25 | package jssc; 26 | 27 | /** 28 | * 29 | * @author scream3r 30 | */ 31 | public class SerialPortEvent { 32 | 33 | 34 | private SerialPort port; 35 | private int eventType; 36 | private int eventValue; 37 | 38 | @Deprecated 39 | private String portName; 40 | 41 | /** Deprecated: Use SerialPort.MASK_RXCHAR instead **/ 42 | @Deprecated 43 | public static final int RXCHAR = SerialPort.MASK_RXCHAR; 44 | 45 | /** Deprecated: Use SerialPort.MASK_RXFLAG instead **/ 46 | @Deprecated 47 | public static final int RXFLAG = SerialPort.MASK_RXFLAG; 48 | 49 | /** Deprecated: Use SerialPort.MASK_TXEMPTY instead **/ 50 | @Deprecated 51 | public static final int TXEMPTY = SerialPort.MASK_TXEMPTY; 52 | 53 | /** Deprecated: Use SerialPort.MASK_CTS instead **/ 54 | @Deprecated 55 | public static final int CTS = SerialPort.MASK_CTS; 56 | 57 | /** Deprecated: Use SerialPort.MASK_DSR instead **/ 58 | @Deprecated 59 | public static final int DSR = SerialPort.MASK_DSR; 60 | 61 | /** Deprecated: Use SerialPort.MASK_RLSD instead **/ 62 | @Deprecated 63 | public static final int RLSD = SerialPort.MASK_RLSD; 64 | 65 | /** Deprecated: Use SerialPort.MASK_BREAK instead **/ 66 | @Deprecated 67 | public static final int BREAK = SerialPort.MASK_BREAK; 68 | 69 | /** Deprecated: Use SerialPort.MASK_ERR instead **/ 70 | @Deprecated 71 | public static final int ERR = SerialPort.MASK_ERR; 72 | 73 | /** Deprecated: Use SerialPort.MASK_RING instead **/ 74 | @Deprecated 75 | public static final int RING = SerialPort.MASK_RING; 76 | 77 | /** 78 | * Constructs a SerialPortEvent representing a port, event type and event value. 79 | * 80 | * @param port SerialPort object which the event occurred 81 | * @param eventType Can be any value from SerialPort.MASK_* or LinuxEventThread.INTERRUPT_* 82 | * @param eventValue Event value which changes context depending on getEventType() 83 | * 84 | * @see #getEventType() 85 | */ 86 | public SerialPortEvent(SerialPort port, int eventType, int eventValue){ 87 | this.port = port; 88 | this.eventType = eventType; 89 | this.eventValue = eventValue; 90 | } 91 | 92 | /** 93 | * Constructs a SerialPortEvent representing a port, event type and event value. 94 | * Deprecated: Use SerialPortEvent(SerialPort, int, int) instead. 95 | * 96 | * @param portName port which the event occurred 97 | * @param eventType Can be any value from SerialPort.MASK_* or LinuxEventThread.INTERRUPT_* 98 | * @param eventValue Event value which changes context depending on getEventType() 99 | * 100 | * @see #SerialPortEvent(SerialPort, int, int) 101 | */ 102 | @Deprecated 103 | public SerialPortEvent(String portName, int eventType, int eventValue){ 104 | this.portName = portName; 105 | this.eventType = eventType; 106 | this.eventValue = eventValue; 107 | } 108 | 109 | /** 110 | * Getting the port that set off this event 111 | * 112 | * @return The SerialPort object the event occurred on 113 | */ 114 | public SerialPort getPort(){ 115 | return port; 116 | } 117 | 118 | /** 119 | * Getting port name which sent the event 120 | * 121 | * @return The port name the event occurred on 122 | */ 123 | @Deprecated 124 | public String getPortName() { 125 | return port.getPortName(); 126 | } 127 | 128 | /** 129 | * Getting event type 130 | * 131 | * @return The SerialPort.MASK_* event mask 132 | */ 133 | @SuppressWarnings("unused") 134 | public int getEventType() { 135 | return eventType; 136 | } 137 | 138 | /** 139 | * Getting event value 140 | *
141 | *
Event values depending on their types: 142 | *
RXCHAR - bytes count in input buffer 143 | *
RXFLAG - bytes count in input buffer (Not supported in Linux) 144 | *
TXEMPTY - bytes count in output buffer 145 | *
CTS - state of CTS line (0 - OFF, 1 - ON) 146 | *
DSR - state of DSR line (0 - OFF, 1 - ON) 147 | *
RLSD - state of RLSD line (0 - OFF, 1 - ON) 148 | *
BREAK - 0 149 | *
RING - state of RING line (0 - OFF, 1 - ON) 150 | *
ERR - mask of errors 151 | * @return Event value which changes context depending on getEventType() (see listing) 152 | */ 153 | @SuppressWarnings("unused") 154 | public int getEventValue() { 155 | return eventValue; 156 | } 157 | 158 | /** 159 | * Convenience method to check if getEventType() is SerialPort.MASK_RXCHAR 160 | * @return true or false 161 | */ 162 | @SuppressWarnings("unused") 163 | public boolean isRXCHAR() { 164 | return eventType == SerialPort.MASK_RXCHAR; 165 | } 166 | 167 | /** 168 | * Convenience method to check if getEventType() is SerialPort.MASK_RXFLAG 169 | * @return true or false 170 | */ 171 | @SuppressWarnings("unused") 172 | public boolean isRXFLAG() { 173 | return eventType == SerialPort.MASK_RXFLAG; 174 | } 175 | 176 | /** 177 | * Convenience method to check if getEventType() is SerialPort.MASK_TXEMPTY 178 | * @return true or false 179 | */ 180 | @SuppressWarnings("unused") 181 | public boolean isTXEMPTY() { 182 | return eventType == SerialPort.MASK_TXEMPTY; 183 | } 184 | 185 | /** 186 | * Convenience method to check if getEventType() is SerialPort.MASK_CTS 187 | * 188 | * @return true or false 189 | */ 190 | @SuppressWarnings("unused") 191 | public boolean isCTS() { 192 | return eventType == SerialPort.MASK_CTS; 193 | } 194 | 195 | /** 196 | * Convenience method to check if getEventType() is SerialPort.MASK_DSR 197 | * 198 | * @return true or false 199 | */ 200 | @SuppressWarnings("unused") 201 | public boolean isDSR() { 202 | return eventType == SerialPort.MASK_DSR; 203 | } 204 | 205 | /** 206 | * Convenience method to check if getEventType() is SerialPort.MASK_RLSD 207 | * 208 | * @return true or false 209 | */ 210 | @SuppressWarnings("unused") 211 | public boolean isRLSD() { 212 | return eventType == SerialPort.MASK_RLSD; 213 | } 214 | 215 | /** 216 | * Convenience method to check if getEventType() is SerialPort.MASK_BREAK 217 | * 218 | * @return true or false 219 | */ 220 | @SuppressWarnings("unused") 221 | public boolean isBREAK() { 222 | return eventType == SerialPort.MASK_BREAK; 223 | } 224 | 225 | /** 226 | * Convenience method to check if getEventType() is SerialPort.MASK_ERR 227 | * 228 | * @return true or false 229 | */ 230 | @SuppressWarnings("unused") 231 | public boolean isERR() { 232 | return eventType == SerialPort.MASK_ERR; 233 | } 234 | 235 | /** 236 | * Convenience method to check if getEventType() is SerialPort.MASK_RING 237 | * 238 | * @return true or false 239 | */ 240 | @SuppressWarnings("unused") 241 | public boolean isRING() { 242 | return eventType == SerialPort.MASK_RING; 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/main/java/jssc/SerialPortEventListener.java: -------------------------------------------------------------------------------- 1 | /* jSSC (Java Simple Serial Connector) - serial port communication library. 2 | * © Alexey Sokolov (scream3r), 2010-2014. 3 | * 4 | * This file is part of jSSC. 5 | * 6 | * jSSC is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * jSSC is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with jSSC. If not, see . 18 | * 19 | * If you use jSSC in public project you can inform me about this by e-mail, 20 | * of course if you want it. 21 | * 22 | * e-mail: scream3r.org@gmail.com 23 | * web-site: http://scream3r.org | http://code.google.com/p/java-simple-serial-connector/ 24 | */ 25 | package jssc; 26 | 27 | /** 28 | * 29 | * @author scream3r 30 | */ 31 | public interface SerialPortEventListener { 32 | /** 33 | * Called when an event fires 34 | * 35 | * @param serialPortEvent SerialPortEvent object containing port, event type and event data 36 | */ 37 | void serialEvent(SerialPortEvent serialPortEvent); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/jssc/SerialPortException.java: -------------------------------------------------------------------------------- 1 | /* jSSC (Java Simple Serial Connector) - serial port communication library. 2 | * © Alexey Sokolov (scream3r), 2010-2014. 3 | * 4 | * This file is part of jSSC. 5 | * 6 | * jSSC is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * jSSC is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with jSSC. If not, see . 18 | * 19 | * If you use jSSC in public project you can inform me about this by e-mail, 20 | * of course if you want it. 21 | * 22 | * e-mail: scream3r.org@gmail.com 23 | * web-site: http://scream3r.org | http://code.google.com/p/java-simple-serial-connector/ 24 | */ 25 | package jssc; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | * 31 | * @author scream3r 32 | */ 33 | public class SerialPortException extends IOException { 34 | final private static long serialVersionUID = 1L; 35 | /** Port already opened **/ 36 | final public static String TYPE_PORT_ALREADY_OPENED = "Port already opened"; 37 | /** Port not opened **/ 38 | final public static String TYPE_PORT_NOT_OPENED = "Port not opened"; 39 | /** Can't set mask **/ 40 | final public static String TYPE_CANT_SET_MASK = "Can't set mask"; 41 | /** Event listener already added **/ 42 | final public static String TYPE_LISTENER_ALREADY_ADDED = "Event listener already added"; 43 | /** Event listener thread interrupted **/ 44 | final public static String TYPE_LISTENER_THREAD_INTERRUPTED = "Event listener thread interrupted"; 45 | /** Can't remove event listener **/ 46 | final public static String TYPE_CANT_REMOVE_LISTENER = "Can't remove event listener"; 47 | /** 48 | * @since 0.9.0 49 | */ 50 | final public static String TYPE_PORT_BUSY = "Port busy"; 51 | /** 52 | * @since 0.9.0 53 | */ 54 | final public static String TYPE_PORT_NOT_FOUND = "Port not found"; 55 | /** 56 | * @since 2.2.0 57 | */ 58 | final public static String TYPE_PERMISSION_DENIED = "Permission denied"; 59 | /** 60 | * @since 2.3.0 61 | */ 62 | final public static String TYPE_INCORRECT_SERIAL_PORT = "Incorrect serial port"; 63 | 64 | /** Exception occurred in native code */ 65 | final public static String TYPE_NATIVE_EXCEPTION = "Native exception occurred: %s"; 66 | 67 | /** Serial port object **/ 68 | private SerialPort port; 69 | /** Method name **/ 70 | private String methodName; 71 | /** Exception type **/ 72 | private String exceptionType; 73 | 74 | /** Port name **/ 75 | @Deprecated 76 | private String portName; 77 | 78 | /** 79 | * Constructs a new SerialPortException 80 | * 81 | * @param port Port which the exception occurred on 82 | * @param methodName Method name which the exception occurred on 83 | * @param exceptionType Any SerialPortException.TYPE_* 84 | */ 85 | public SerialPortException(SerialPort port, String methodName, String exceptionType) { 86 | super("Port name - " + port.getPortName() + "; Method name - " + methodName + "; Exception type - " + exceptionType + "."); 87 | this.port = port; 88 | this.methodName = methodName; 89 | this.exceptionType = exceptionType; 90 | } 91 | 92 | /** 93 | * Constructs a new SerialPortException 94 | * Deprecated: Use SerialPortTimeoutException(SerialPort, String, String) instead. 95 | * 96 | * @param portName Port which the exception occurred on 97 | * @param methodName Method name which the exception occurred on 98 | * @param exceptionType Any SerialPortException.TYPE_* 99 | * 100 | * @see #SerialPortException(SerialPort, String, String) 101 | */ 102 | @Deprecated 103 | public SerialPortException(String portName, String methodName, String exceptionType) { 104 | super("Port name - " + portName + "; Method name - " + methodName + "; Exception type - " + exceptionType + "."); 105 | this.portName = portName; 106 | this.methodName = methodName; 107 | this.exceptionType = exceptionType; 108 | } 109 | 110 | public static SerialPortException wrapNativeException(Exception ex, SerialPort port, String methodName) { 111 | return new SerialPortException(port, methodName, String.format(TYPE_NATIVE_EXCEPTION, ex.getLocalizedMessage())); 112 | } 113 | 114 | /** 115 | * Getting port name during operation with which the exception was called 116 | * Deprecated: Use getPort().getName() instead. 117 | * 118 | * @return Port name 119 | */ 120 | @Deprecated 121 | public String getPortName() { 122 | return port != null ? port.getPortName() : portName; 123 | } 124 | 125 | /** 126 | * Gets the SerialPort which threw the exception 127 | * 128 | * @return SerialPort object 129 | */ 130 | @SuppressWarnings("unused") 131 | public SerialPort getPort() { 132 | return port; 133 | } 134 | 135 | /** 136 | * Gets the method name during execution of which the exception was called 137 | * 138 | * @return Calling method name 139 | */ 140 | @SuppressWarnings("unused") 141 | public String getMethodName() { 142 | return methodName; 143 | } 144 | 145 | /** 146 | * Getting exception type 147 | * 148 | * @return a value from SerialPortException.TYPE_* 149 | * or a custom String value if provided 150 | */ 151 | @SuppressWarnings("unused") 152 | public String getExceptionType() { 153 | return exceptionType; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/jssc/SerialPortList.java: -------------------------------------------------------------------------------- 1 | /* jSSC (Java Simple Serial Connector) - serial port communication library. 2 | * © Alexey Sokolov (scream3r), 2010-2014. 3 | * 4 | * This file is part of jSSC. 5 | * 6 | * jSSC is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * jSSC is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with jSSC. If not, see . 18 | * 19 | * If you use jSSC in public project you can inform me about this by e-mail, 20 | * of course if you want it. 21 | * 22 | * e-mail: scream3r.org@gmail.com 23 | * web-site: http://scream3r.org | http://code.google.com/p/java-simple-serial-connector/ 24 | */ 25 | package jssc; 26 | 27 | import java.io.File; 28 | import java.util.Comparator; 29 | import java.util.TreeSet; 30 | import java.util.regex.Pattern; 31 | 32 | /** 33 | * 34 | * @author scream3r 35 | */ 36 | public class SerialPortList { 37 | 38 | private static SerialNativeInterface serialInterface; 39 | private static final Pattern PORTNAMES_REGEXP; 40 | private static final String PORTNAMES_PATH; 41 | 42 | /** 43 | * Default constructor 44 | * private: no constructor available 45 | */ 46 | private SerialPortList() {} 47 | 48 | static { 49 | serialInterface = new SerialNativeInterface(); 50 | switch (SerialNativeInterface.getOsType()) { 51 | case SerialNativeInterface.OS_LINUX: { 52 | PORTNAMES_REGEXP = Pattern.compile("(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO|ttyM|ttyMXUSB|ttyMUE)[0-9]{1,3}"); 53 | PORTNAMES_PATH = "/dev/"; 54 | break; 55 | } 56 | case SerialNativeInterface.OS_SOLARIS: { 57 | PORTNAMES_REGEXP = Pattern.compile("[0-9]*|[a-z]*"); 58 | PORTNAMES_PATH = "/dev/term/"; 59 | break; 60 | } 61 | case SerialNativeInterface.OS_MAC_OS_X: { 62 | PORTNAMES_REGEXP = Pattern.compile("(tty|cu)\\..*"); 63 | PORTNAMES_PATH = "/dev/"; 64 | break; 65 | } 66 | case SerialNativeInterface.OS_WINDOWS: { 67 | PORTNAMES_REGEXP = Pattern.compile(""); 68 | PORTNAMES_PATH = ""; 69 | break; 70 | } 71 | default: { 72 | PORTNAMES_REGEXP = null; 73 | PORTNAMES_PATH = null; 74 | break; 75 | } 76 | } 77 | } 78 | 79 | //since 2.1.0 -> Fully rewritten port name comparator 80 | private static final Comparator PORTNAMES_COMPARATOR = new Comparator() { 81 | 82 | @Override 83 | public int compare(String valueA, String valueB) { 84 | 85 | if(valueA.equalsIgnoreCase(valueB)){ 86 | return valueA.compareTo(valueB); 87 | } 88 | 89 | int minLength = Math.min(valueA.length(), valueB.length()); 90 | 91 | int shiftA = 0; 92 | int shiftB = 0; 93 | 94 | for(int i = 0; i < minLength; i++){ 95 | char charA = valueA.charAt(i - shiftA); 96 | char charB = valueB.charAt(i - shiftB); 97 | if(charA != charB){ 98 | if(Character.isDigit(charA) && Character.isDigit(charB)){ 99 | int[] resultsA = getNumberAndLastIndex(valueA, i - shiftA); 100 | int[] resultsB = getNumberAndLastIndex(valueB, i - shiftB); 101 | 102 | if(resultsA[0] != resultsB[0]){ 103 | return resultsA[0] - resultsB[0]; 104 | } 105 | 106 | if(valueA.length() < valueB.length()){ 107 | i = resultsA[1]; 108 | shiftB = resultsA[1] - resultsB[1]; 109 | } 110 | else { 111 | i = resultsB[1]; 112 | shiftA = resultsB[1] - resultsA[1]; 113 | } 114 | } 115 | else { 116 | if(Character.toLowerCase(charA) - Character.toLowerCase(charB) != 0){ 117 | return Character.toLowerCase(charA) - Character.toLowerCase(charB); 118 | } 119 | } 120 | } 121 | } 122 | return valueA.compareToIgnoreCase(valueB); 123 | } 124 | 125 | /** 126 | * Evaluate port index/number from startIndex to the number end. For example: 127 | * for port name serial-123-FF you should invoke this method with startIndex = 7 128 | * 129 | * @return If port index/number correctly evaluated it value will be returned
130 | * returnArray[0] = index/number
131 | * returnArray[1] = stopIndex
132 | * 133 | * If incorrect:
134 | * returnArray[0] = -1
135 | * returnArray[1] = startIndex
136 | * 137 | * For this name serial-123-FF result is: 138 | * returnArray[0] = 123
139 | * returnArray[1] = 10
140 | */ 141 | private int[] getNumberAndLastIndex(String str, int startIndex) { 142 | String numberValue = ""; 143 | int[] returnValues = {-1, startIndex}; 144 | for(int i = startIndex; i < str.length(); i++){ 145 | returnValues[1] = i; 146 | char c = str.charAt(i); 147 | if(Character.isDigit(c)){ 148 | numberValue += c; 149 | } 150 | else { 151 | break; 152 | } 153 | } 154 | try { 155 | returnValues[0] = Integer.valueOf(numberValue); 156 | } 157 | catch (Exception ex) { 158 | //Do nothing 159 | } 160 | return returnValues; 161 | } 162 | }; 163 | //<-since 2.1.0 164 | 165 | /** 166 | * Get sorted array of serial ports in the system using default settings:
167 | * 168 | * Search path
169 | * Windows - ""(always ignored)
170 | * Linux - "/dev/"
171 | * Solaris - "/dev/term/"
172 | * MacOSX - "/dev/"
173 | * 174 | * RegExp
175 | * Windows - ""
176 | * Linux - "(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm)[0-9]{1,3}"
177 | * Solaris - "[0-9]*|[a-z]*"
178 | * MacOSX - "tty.(serial|usbserial|usbmodem).*"
179 | * 180 | * @return String array. If there is no ports in the system String[] 181 | * with zero length will be returned (since jSSC-0.8 in previous versions null will be returned) 182 | */ 183 | public static String[] getPortNames() { 184 | return getPortNames(PORTNAMES_PATH, PORTNAMES_REGEXP, PORTNAMES_COMPARATOR); 185 | } 186 | 187 | /** 188 | * Get sorted array of serial ports in the system located on searchPath 189 | * 190 | * @param searchPath Path for searching serial ports (not null)
191 | * The default search paths:
192 | * Linux, MacOSX: /dev/
193 | * Solaris: /dev/term/
194 | * Windows: this parameter ingored 195 | * 196 | * @return String array. If there is no ports in the system String[] 197 | * 198 | * @since 2.3.0 199 | */ 200 | public static String[] getPortNames(String searchPath) { 201 | return getPortNames(searchPath, PORTNAMES_REGEXP, PORTNAMES_COMPARATOR); 202 | } 203 | 204 | /** 205 | * Get sorted array of serial ports in the system matched pattern 206 | * 207 | * @param pattern RegExp pattern for matching port names (not null) 208 | * 209 | * @return String array. If there is no ports in the system String[] 210 | * 211 | * @since 2.3.0 212 | */ 213 | public static String[] getPortNames(Pattern pattern) { 214 | return getPortNames(PORTNAMES_PATH, pattern, PORTNAMES_COMPARATOR); 215 | } 216 | 217 | /** 218 | * Get sorted array of serial ports in the system matched pattern 219 | * 220 | * @param comparator Comparator for sotring port names (not null) 221 | * 222 | * @return String array. If there is no ports in the system String[] 223 | * 224 | * @since 2.3.0 225 | */ 226 | public static String[] getPortNames(Comparator comparator) { 227 | return getPortNames(PORTNAMES_PATH, PORTNAMES_REGEXP, comparator); 228 | } 229 | 230 | /** 231 | * Get sorted array of serial ports in the system located on searchPath, matched pattern 232 | * 233 | * @param searchPath Path for searching serial ports (not null)
234 | * The default search paths:
235 | * Linux, MacOSX: /dev/
236 | * Solaris: /dev/term/
237 | * Windows: this parameter ingored 238 | * @param pattern RegExp pattern for matching port names (not null) 239 | * 240 | * @return String array. If there is no ports in the system String[] 241 | * 242 | * @since 2.3.0 243 | */ 244 | public static String[] getPortNames(String searchPath, Pattern pattern) { 245 | return getPortNames(searchPath, pattern, PORTNAMES_COMPARATOR); 246 | } 247 | 248 | /** 249 | * Get sorted array of serial ports in the system located on searchPath and sorted by comparator 250 | * 251 | * @param searchPath Path for searching serial ports (not null)
252 | * The default search paths:
253 | * Linux, MacOSX: /dev/
254 | * Solaris: /dev/term/
255 | * Windows: this parameter ingored 256 | * @param comparator Comparator for sotring port names (not null) 257 | * 258 | * @return String array. If there is no ports in the system String[] 259 | * 260 | * @since 2.3.0 261 | */ 262 | public static String[] getPortNames(String searchPath, Comparator comparator) { 263 | return getPortNames(searchPath, PORTNAMES_REGEXP, comparator); 264 | } 265 | 266 | /** 267 | * Get sorted array of serial ports in the system matched pattern and sorted by comparator 268 | * 269 | * @param pattern RegExp pattern for matching port names (not null) 270 | * @param comparator Comparator for sotring port names (not null) 271 | * 272 | * @return String array. If there is no ports in the system String[] 273 | * 274 | * @since 2.3.0 275 | */ 276 | public static String[] getPortNames(Pattern pattern, Comparator comparator) { 277 | return getPortNames(PORTNAMES_PATH, pattern, comparator); 278 | } 279 | 280 | /** 281 | * Get sorted array of serial ports in the system located on searchPath, matched pattern and sorted by comparator 282 | * 283 | * @param searchPath Path for searching serial ports (not null)
284 | * The default search paths:
285 | * Linux, MacOSX: /dev/
286 | * Solaris: /dev/term/
287 | * Windows: this parameter ingored 288 | * @param pattern RegExp pattern for matching port names (not null) 289 | * @param comparator Comparator for sotring port names (not null) 290 | * 291 | * @return String array. If there is no ports in the system String[] 292 | * 293 | * @since 2.3.0 294 | */ 295 | public static String[] getPortNames(String searchPath, Pattern pattern, Comparator comparator) { 296 | if(searchPath == null || pattern == null || comparator == null){ 297 | return new String[]{}; 298 | } 299 | if(SerialNativeInterface.getOsType() == SerialNativeInterface.OS_WINDOWS){ 300 | return getWindowsPortNames(pattern, comparator); 301 | } 302 | return getUnixBasedPortNames(searchPath, pattern, comparator); 303 | } 304 | 305 | /** 306 | * Get serial port names in Windows 307 | * 308 | * @since 2.3.0 309 | */ 310 | private static String[] getWindowsPortNames(Pattern pattern, Comparator comparator) { 311 | String[] portNames = serialInterface.getSerialPortNames(); 312 | if(portNames == null){ 313 | return new String[]{}; 314 | } 315 | TreeSet ports = new TreeSet(comparator); 316 | for(String portName : portNames){ 317 | if(portName != null && pattern.matcher(portName).find()){ 318 | ports.add(portName); 319 | } 320 | } 321 | return ports.toArray(new String[ports.size()]); 322 | } 323 | 324 | /** 325 | * Universal method for getting port names of _nix based systems 326 | */ 327 | private static String[] getUnixBasedPortNames(String searchPath, Pattern pattern, Comparator comparator) { 328 | searchPath = (searchPath.equals("") ? searchPath : (searchPath.endsWith("/") ? searchPath : searchPath + "/")); 329 | String[] returnArray = new String[]{}; 330 | File dir = new File(searchPath); 331 | if(dir.exists() && dir.isDirectory()){ 332 | File[] files = dir.listFiles(); 333 | if(files.length > 0){ 334 | TreeSet portsTree = new TreeSet(comparator); 335 | for(File file : files){ 336 | String fileName = file.getName(); 337 | if(!file.isDirectory() && !file.isFile() && pattern.matcher(fileName).find()){ 338 | String portName = searchPath + fileName; 339 | // For linux ttyS0..31 serial ports check existence by opening each of them 340 | if (fileName.startsWith("ttyS")) { 341 | long portHandle = serialInterface.openPort(portName, false);//Open port without TIOCEXCL 342 | if(portHandle < 0 && portHandle != SerialNativeInterface.ERR_PORT_BUSY){ 343 | continue; 344 | } 345 | else if(portHandle != SerialNativeInterface.ERR_PORT_BUSY) { 346 | serialInterface.closePort(portHandle); 347 | } 348 | } 349 | portsTree.add(portName); 350 | } 351 | } 352 | returnArray = portsTree.toArray(returnArray); 353 | } 354 | } 355 | return returnArray; 356 | } 357 | } 358 | -------------------------------------------------------------------------------- /src/main/java/jssc/SerialPortTimeoutException.java: -------------------------------------------------------------------------------- 1 | /* jSSC (Java Simple Serial Connector) - serial port communication library. 2 | * © Alexey Sokolov (scream3r), 2010-2014. 3 | * 4 | * This file is part of jSSC. 5 | * 6 | * jSSC is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * jSSC is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with jSSC. If not, see . 18 | * 19 | * If you use jSSC in public project you can inform me about this by e-mail, 20 | * of course if you want it. 21 | * 22 | * e-mail: scream3r.org@gmail.com 23 | * web-site: http://scream3r.org | http://code.google.com/p/java-simple-serial-connector/ 24 | */ 25 | package jssc; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | * 31 | * @author scream3r 32 | */ 33 | public class SerialPortTimeoutException extends IOException { 34 | final private static long serialVersionUID = 1L; 35 | 36 | /** Serial port object **/ 37 | private SerialPort port; 38 | /** Method name **/ 39 | private String methodName; 40 | /** Timeout value **/ 41 | private int timeoutValue; 42 | 43 | /** Port name **/ 44 | @Deprecated 45 | private String portName; 46 | 47 | /** 48 | * Constructs a new SerialPortTimeoutException 49 | * 50 | * @param port Port which the exception occurred on 51 | * @param methodName Method name which the exception occurred on 52 | * @param timeoutValue Timeout value which the exception occurred on 53 | */ 54 | public SerialPortTimeoutException(SerialPort port, String methodName, int timeoutValue) { 55 | super("Port name - " + port.getPortName() + "; Method name - " + methodName + "; Serial port operation timeout (" + timeoutValue + " ms)."); 56 | this.port = port; 57 | this.methodName = methodName; 58 | this.timeoutValue = timeoutValue; 59 | } 60 | 61 | /** 62 | * Constructs a new SerialPortTimeoutException 63 | * Deprecated: Use SerialPortTimeoutException(SerialPort, String, int) instead. 64 | * 65 | * @param portName Port name which the exception occurred on 66 | * @param methodName Method name which the exception occurred on 67 | * @param timeoutValue Timeout value which the exception occurred on 68 | * 69 | * @see #SerialPortTimeoutException(SerialPort, String, int) 70 | */ 71 | @Deprecated 72 | public SerialPortTimeoutException(String portName, String methodName, int timeoutValue) { 73 | super("Port name - " + portName + "; Method name - " + methodName + "; Serial port operation timeout (" + timeoutValue + " ms)."); 74 | this.portName = portName; 75 | this.methodName = methodName; 76 | this.timeoutValue = timeoutValue; 77 | } 78 | 79 | /** 80 | * Getting port name during operation with which the exception was called 81 | * Deprecated: Use getPort().getName() instead. 82 | * 83 | * @return Port name 84 | */ 85 | @Deprecated 86 | public String getPortName() { 87 | return port != null ? port.getPortName() : portName; 88 | } 89 | 90 | /** 91 | * Gets the SerialPort which threw the exception 92 | * 93 | * @return SerialPort object 94 | */ 95 | @SuppressWarnings("unused") 96 | public SerialPort getPort() { 97 | return port; 98 | } 99 | 100 | /** 101 | * Gets the method name during execution of which the exception was called 102 | * 103 | * @return Calling method name 104 | */ 105 | @SuppressWarnings("unused") 106 | public String getMethodName() { 107 | return methodName; 108 | } 109 | 110 | /** 111 | * Gets timeout value of which the exception was called 112 | * 113 | * @return Calling method name 114 | */ 115 | @SuppressWarnings("unused") 116 | public int getTimeoutValue() { 117 | return timeoutValue; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/module-info/module-info.java: -------------------------------------------------------------------------------- 1 | @SuppressWarnings({ "requires-automatic", "requires-transitive-automatic" }) 2 | open module jssc { 3 | requires transitive org.scijava.nativelib; 4 | exports jssc; 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources-precompiled/README.md: -------------------------------------------------------------------------------- 1 | # Precompiled libraries 2 | 3 | The `native` folder contains precompiled libraries for distribution. 4 | If a library is missing, please consider a pull request or open an issue. 5 | 6 | Whenever the interface of `SerialNativeInterface.java` changes, developers 7 | are to recompile binaries for each platform. 8 | 9 | ## Valid paths 10 | 11 | The old path structure is ambiguous, but supported for compatibility. 12 | This structure must be used before `native-lib-loader` version 2.4.0. 13 | 14 | * `linux_32` 15 | * `linux_64` 16 | * `linux_arm` 17 | * `linux_arm64` 18 | * `mac_32` 19 | * `mac_64` 20 | * `windows_32` 21 | * `windows_64` 22 | 23 | 24 | ## Next version 25 | 26 | Note: Valid starting from `native-lib-loader` version 2.4.0 or later. 27 | The path names were aligned to the [os-maven-plugin](https://github.com/trustin/os-maven-plugin/). 28 | It follows the same conventions as the [osdetector-gradle-plugin](https://github.com/google/osdetector-gradle-plugin). 29 | 30 | * `linux-arm_32-32` 31 | * `linux-x86_32-32` (also alias of `linux-i386-64`) 32 | * `windows-x86_64-32` 33 | * `aix-ppc_64-64` 34 | * `linux-x86_64-64` 35 | * `linux-aarch_64-64` (instead of `linux-arm64-64`) 36 | * `linux-ppcle_64-64` 37 | * `mac-x86_64-64` 38 | * `mac-ppc_64-64` 39 | * `windows-x86_32-64` 40 | * `windows-x86_64-64` 41 | 42 | If an architecture, bitness or cpu feature is missing, please consider a pull request against `native-lib-loader` 43 | 44 | ## Activation 45 | 46 | No activation needed, a jar with these libraries is always built. 47 | Optionally, to skip native compilation and only build this artifact: 48 | 49 | ```bash 50 | mvn clean install -Ppackage 51 | ``` 52 | -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/linux_32/libjssc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/linux_32/libjssc.so -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/linux_64/libjssc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/linux_64/libjssc.so -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/linux_arm/libjssc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/linux_arm/libjssc.so -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/linux_arm64/libjssc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/linux_arm64/libjssc.so -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/linux_ppc/libjssc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/linux_ppc/libjssc.so -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/linux_riscv32/libjssc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/linux_riscv32/libjssc.so -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/linux_riscv64/libjssc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/linux_riscv64/libjssc.so -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/osx_64/libjssc.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/osx_64/libjssc.dylib -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/osx_arm64/libjssc.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/osx_arm64/libjssc.dylib -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/windows_32/jssc.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/windows_32/jssc.dll -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/windows_64/jssc.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/windows_64/jssc.dll -------------------------------------------------------------------------------- /src/main/resources-precompiled/natives/windows_arm64/jssc.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/java-native/jssc/e20a177ba065274e2a24c08e55a5d82fb7ea5516/src/main/resources-precompiled/natives/windows_arm64/jssc.dll -------------------------------------------------------------------------------- /src/test/java/jssc/SerialNativeInterfaceTest.java: -------------------------------------------------------------------------------- 1 | package jssc; 2 | 3 | import jssc.junit.rules.DisplayMethodNameRule; 4 | import org.junit.Assume; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.slf4j.Logger; 8 | 9 | import static org.hamcrest.CoreMatchers.is; 10 | import static org.hamcrest.CoreMatchers.not; 11 | import static org.hamcrest.CoreMatchers.nullValue; 12 | import static org.junit.Assert.assertThat; 13 | import static org.junit.Assert.assertTrue; 14 | import static org.junit.Assert.fail; 15 | import static org.junit.Assume.assumeFalse; 16 | import static org.junit.Assume.assumeTrue; 17 | import static org.slf4j.LoggerFactory.getLogger;; 18 | 19 | public class SerialNativeInterfaceTest extends DisplayMethodNameRule { 20 | 21 | private static final Logger log = getLogger(SerialNativeInterfaceTest.class); 22 | 23 | @Test 24 | public void testInitNativeInterface() { 25 | SerialNativeInterface serial = new SerialNativeInterface(); 26 | 27 | long handle = -1; 28 | try { 29 | handle = serial.openPort("ttyS0",false); 30 | assertThat(handle, is(not(-1L))); 31 | } finally { 32 | if (handle != -1) { 33 | serial.closePort(handle); 34 | } 35 | } 36 | } 37 | 38 | @Test 39 | public void testPrintVersion() { 40 | try { 41 | final String nativeLibraryVersion = SerialNativeInterface.getNativeLibraryVersion(); 42 | assertThat(nativeLibraryVersion, is(not(nullValue()))); 43 | assertThat(nativeLibraryVersion, is(not(""))); 44 | } catch (UnsatisfiedLinkError linkError) { 45 | linkError.printStackTrace(); 46 | fail("Should be able to call method!"); 47 | } 48 | 49 | } 50 | 51 | @Test(expected = java.io.IOException.class) 52 | public void reportsWriteErrorsAsIOException() throws Exception { 53 | Assume.assumeFalse(SerialNativeInterface.getOsType() == SerialNativeInterface.OS_WINDOWS); 54 | 55 | long fd = -1; /*bad file by intent*/ 56 | byte[] buf = new byte[]{ 0x6A, 0x73, 0x73, 0x63, 0x0A }; 57 | SerialNativeInterface testTarget = new SerialNativeInterface(); 58 | testTarget.writeBytes(fd, buf); 59 | } 60 | 61 | @Test 62 | public void throwsIllegalArgumentExceptionIfPortHandleIllegal() throws Exception { 63 | assumeFalse(SerialNativeInterface.getOsType() == SerialNativeInterface.OS_MAC_OS_X); 64 | 65 | SerialNativeInterface testTarget = new SerialNativeInterface(); 66 | try{ 67 | testTarget.readBytes(999, 42); 68 | fail("Where is the exception?"); 69 | }catch( IllegalArgumentException ex ){ 70 | assertTrue(ex.getMessage().contains("EBADF")); 71 | } 72 | } 73 | 74 | /** 75 | *

This is a duplicate of {@link #throwsIllegalArgumentExceptionIfPortHandleIllegal()} 76 | * but targets osx only. Not yet analyzed why osx (using select) hangs here. See also PR 155. Where this 78 | * was discovered.

79 | * 80 | *

TODO: Go down that rabbit hole and get rid of that "bug".

81 | */ 82 | @Test 83 | @org.junit.Ignore("TODO analyze where this osx hang comes from") 84 | public void throwsIllegalArgumentExceptionIfPortHandleIllegalOsx() throws Exception { 85 | assumeTrue(SerialNativeInterface.getOsType() == SerialNativeInterface.OS_MAC_OS_X); 86 | 87 | SerialNativeInterface testTarget = new SerialNativeInterface(); 88 | try{ 89 | testTarget.readBytes(999, 42); 90 | fail("Where is the exception?"); 91 | }catch( IllegalArgumentException ex ){ 92 | assertTrue(ex.getMessage().contains("EBADF")); 93 | } 94 | } 95 | 96 | @Test(expected = java.lang.NullPointerException.class) 97 | public void throwsNpeIfPassedBufferIsNull() throws Exception { 98 | new SerialNativeInterface().writeBytes(1, null); 99 | } 100 | 101 | @Test 102 | public void throwsIfCountNegative() throws Exception { 103 | SerialNativeInterface testTarget = new SerialNativeInterface(); 104 | byte[] ret; 105 | try{ 106 | ret = testTarget.readBytes(0, -42); 107 | fail("Where's the exception?"); 108 | }catch( IllegalArgumentException ex ){ 109 | assertTrue(ex.getMessage().contains("-42")); 110 | } 111 | } 112 | 113 | @Test 114 | public void throwsIfCountZero() throws Exception { 115 | SerialNativeInterface testTarget = new SerialNativeInterface(); 116 | byte[] ret; 117 | try{ 118 | ret = testTarget.readBytes(0, 0); 119 | fail("Where's the exception?"); 120 | }catch( IllegalArgumentException ex ){ 121 | assertTrue(ex.getMessage().contains("0")); 122 | } 123 | } 124 | 125 | @Test 126 | @org.junit.Ignore("This test only makes sense if it is run in a situation" 127 | +" where large memory allocations WILL fail (for example you could use" 128 | +" a virtual machine with low memory available). Because on regular" 129 | +" machines allocating 2GiB of RAM is not a problem at all and so the" 130 | +" test run will just happily wait infinitely for those 2GiB to arrive" 131 | +" at the stdin fd. Feel free to remove this test if you think it" 132 | +" doesn't make sense to have it here.") 133 | public void throwsIfRequestTooLarge() throws Exception { 134 | SerialNativeInterface testTarget = new SerialNativeInterface(); 135 | int tooLargeSize = Integer.MAX_VALUE; 136 | try{ 137 | byte[] ret = testTarget.readBytes(0, tooLargeSize); 138 | fail("Where's the exception?"); 139 | }catch( RuntimeException ex ){ 140 | log.debug("Thrown, as expected :)", ex); 141 | assertTrue(ex.getMessage().contains(String.valueOf(tooLargeSize))); 142 | } 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /src/test/java/jssc/VirtualPortTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * GNU Lesser General Public License v3.0 3 | * Copyright (C) 2019 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3 of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | package jssc; 21 | 22 | import static org.hamcrest.CoreMatchers.is; 23 | import static org.junit.Assert.assertThat; 24 | 25 | import java.io.IOException; 26 | import java.io.UnsupportedEncodingException; 27 | 28 | import jssc.junit.rules.DisplayMethodNameRule; 29 | import jssc.junit.rules.VirtualPortRule; 30 | import org.junit.Assume; 31 | import org.junit.Rule; 32 | import org.junit.Test; 33 | 34 | public class VirtualPortTest extends DisplayMethodNameRule { 35 | 36 | private static final String HELLO_WORLD = "Hello, world!"; 37 | 38 | private final byte[] bytes; 39 | 40 | @Rule 41 | public VirtualPortRule virtualPort = new VirtualPortRule(); 42 | 43 | public VirtualPortTest() throws UnsupportedEncodingException { 44 | this.bytes = HELLO_WORLD.getBytes("UTF-8"); 45 | } 46 | 47 | @Test 48 | public void testOpenPort() throws IOException { 49 | // given virtualcom port is available 50 | Assume.assumeTrue(this.virtualPort.isAvailable()); 51 | 52 | // given two virtual ports (null modem) 53 | final SerialNativeInterface serial1 = new SerialNativeInterface(); 54 | final long handle = serial1.openPort(this.virtualPort.getVirtualCom1().getAbsolutePath(), false); 55 | 56 | final SerialNativeInterface serial2 = new SerialNativeInterface(); 57 | final long handle2 = serial2.openPort(this.virtualPort.getVirtualCom2().getAbsolutePath(), false); 58 | 59 | // when bytes are written to port 1 60 | serial1.writeBytes(handle, this.bytes); 61 | serial1.closePort(handle); 62 | 63 | // expect same output on port 2. 64 | final byte[] readBytes = serial2.readBytes(handle2, this.bytes.length); 65 | serial2.closePort(handle2); 66 | 67 | final String readString = new String(readBytes, "UTF-8"); 68 | assertThat(readString, is(HELLO_WORLD)); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/test/java/jssc/bootpath/ManualBootLibraryPathFailedTest.java: -------------------------------------------------------------------------------- 1 | package jssc.bootpath; 2 | 3 | import jssc.SerialNativeInterface; 4 | import jssc.junit.rules.DisplayMethodNameRule; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertTrue; 8 | import static org.junit.Assert.fail; 9 | 10 | /** 11 | * Tests if a valid jssc.boot.library.path which does NOT contain a native library 12 | * will predictably fail. This test can be run regardless of whether or not a native binary was 13 | * created during the build process. 14 | * 15 | * TODO: This MUST be in its own class to run in a separate JVM (https://stackoverflow.com/questions/68657855) 16 | * - JUnit does NOT currently offer JVM unloading between methods. 17 | * - maven-surefire-plugin DOES offer JVM unloading between classes using reuseForks=false 18 | * - Unloading is needed due to NativeLoader.loadLibrary(...) calls System.loadLibrary(...) which is static 19 | */ 20 | public class ManualBootLibraryPathFailedTest extends DisplayMethodNameRule { 21 | @Test 22 | public void testBootPathOverride() { 23 | String nativeLibDir = "/"; // This should be valid on all platforms 24 | System.setProperty("jssc.boot.library.path", nativeLibDir); 25 | try { 26 | SerialNativeInterface.getNativeLibraryVersion(); 27 | fail("Library loading should fail if path provided exists but does not contain a native library"); 28 | } catch (UnsatisfiedLinkError ignore) { 29 | assertTrue("Library loading failed as expected with an invalid jssc.boot.library.path", true); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/jssc/bootpath/ManualBootLibraryPathTest.java: -------------------------------------------------------------------------------- 1 | package jssc.bootpath; 2 | 3 | import jssc.SerialNativeInterface; 4 | import jssc.junit.rules.DisplayMethodNameRule; 5 | import org.junit.Test; 6 | import org.scijava.nativelib.NativeLibraryUtil; 7 | 8 | import static org.hamcrest.CoreMatchers.*; 9 | import static org.junit.Assert.assertThat; 10 | import static org.junit.Assert.fail; 11 | 12 | /** 13 | * Tests if a valid jssc.boot.library.path which DOES contain a native library 14 | * will predictably pass. This test can ONLY be run regardless if a native binary was created 15 | * during the build process. See also maven.exclude.tests. 16 | * 17 | * TODO: This MUST be in its own class to run in a separate JVM (https://stackoverflow.com/questions/68657855) 18 | * - JUnit does NOT currently offer JVM unloading between methods. 19 | * - maven-surefire-plugin DOES offer JVM unloading between classes using reuseForks=false 20 | * - Unloading is needed due to NativeLoader.loadLibrary(...) calls System.loadLibrary(...) which is static 21 | */ 22 | public class ManualBootLibraryPathTest extends DisplayMethodNameRule { 23 | @Test 24 | public void testBootPathOverride() { 25 | String nativeLibDir = NativeLibraryUtil.getPlatformLibraryPath(System.getProperty("user.dir") + "/target/cmake/natives/"); 26 | System.setProperty("jssc.boot.library.path", nativeLibDir); 27 | try { 28 | final String nativeLibraryVersion = SerialNativeInterface.getNativeLibraryVersion(); 29 | assertThat(nativeLibraryVersion, is(not(nullValue()))); 30 | assertThat(nativeLibraryVersion, is(not(""))); 31 | } catch (UnsatisfiedLinkError linkError) { 32 | linkError.printStackTrace(); 33 | fail("Should be able to call method!"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/jssc/junit/rules/BackgroundProcess.java: -------------------------------------------------------------------------------- 1 | /* 2 | * GNU Lesser General Public License v3.0 3 | * Copyright (C) 2019 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3 of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | package jssc.junit.rules; 21 | 22 | public interface BackgroundProcess extends Runnable { 23 | 24 | Process getProcess(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/jssc/junit/rules/DisplayMethodNameRule.java: -------------------------------------------------------------------------------- 1 | package jssc.junit.rules; 2 | 3 | import org.apache.logging.log4j.LogManager; 4 | import org.apache.logging.log4j.Logger; 5 | import org.apache.logging.log4j.MarkerManager; 6 | import org.junit.Rule; 7 | import org.junit.rules.TestWatcher; 8 | import org.junit.runner.Description; 9 | 10 | /** 11 | * Adds the method name to the JUnit logs, useful for debugging 12 | */ 13 | public class DisplayMethodNameRule { 14 | @Rule 15 | public TestWatcher methodWatcher = new TestWatcher() { 16 | @Override 17 | protected void starting(Description description) { 18 | Logger log = LogManager.getLogger(description.getTestClass()); 19 | log.info(MarkerManager.getMarker("MethodName"), description.getMethodName()); 20 | } 21 | }; 22 | } -------------------------------------------------------------------------------- /src/test/java/jssc/junit/rules/VirtualPortRule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * GNU Lesser General Public License v3.0 3 | * Copyright (C) 2019 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3 of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | package jssc.junit.rules; 21 | 22 | import static java.util.Arrays.asList; 23 | 24 | import java.io.File; 25 | import java.io.IOException; 26 | import java.io.OutputStream; 27 | import java.security.SecureRandom; 28 | import java.util.ArrayList; 29 | import java.util.Arrays; 30 | import java.util.List; 31 | import java.util.Random; 32 | import java.util.concurrent.ExecutorService; 33 | import java.util.concurrent.Executors; 34 | import java.util.concurrent.Future; 35 | 36 | import org.apache.logging.log4j.LogManager; 37 | import org.apache.logging.log4j.Logger; 38 | 39 | import jssc.SerialNativeInterface; 40 | import org.junit.rules.TestRule; 41 | import org.junit.runner.Description; 42 | import org.junit.runners.model.Statement; 43 | 44 | public class VirtualPortRule implements TestRule { 45 | 46 | private static final Logger LOG = LogManager.getLogger(VirtualPortRule.class); 47 | 48 | private static final ExecutorService executor = Executors.newCachedThreadPool(); 49 | 50 | private final List> processes = new ArrayList>(); 51 | 52 | private OutputStream outputStream; 53 | 54 | private boolean isAvailable; 55 | 56 | private final Random random = new SecureRandom(); 57 | 58 | private File virtualCom1; 59 | private File virtualCom2; 60 | 61 | public VirtualPortRule() { 62 | } 63 | 64 | @Override 65 | public Statement apply(final Statement base, final Description description) { 66 | // skip / prevent deadlock if socat isn't available 67 | if (SerialNativeInterface.getOsType() == SerialNativeInterface.OS_WINDOWS || !execute("socat", "-V")) { 68 | return new Statement() { 69 | @Override 70 | public void evaluate() throws Throwable { 71 | base.evaluate(); 72 | } 73 | }; 74 | } 75 | 76 | initUnix(description); 77 | 78 | return new Statement() { 79 | 80 | @Override 81 | public void evaluate() throws Throwable { 82 | try { 83 | final BackgroundProcess socatProcess = openSocat(); 84 | final Future socatFuture = executor.submit(socatProcess); 85 | VirtualPortRule.this.processes.add(socatFuture); 86 | 87 | // Java 8: 88 | // System.timemillis… 89 | // while (!socatProcess.getProcess().isAlive()) { 90 | // Thread.sleep(50); 91 | // } 92 | 93 | // java 6 way… pretend it is running. 94 | Thread.sleep(500); 95 | 96 | VirtualPortRule.this.isAvailable = true; 97 | 98 | base.evaluate(); 99 | } finally { 100 | // stop socat 101 | for (final Future process : VirtualPortRule.this.processes) { 102 | process.cancel(true); 103 | } 104 | 105 | executor.shutdown(); 106 | } 107 | } 108 | }; 109 | } 110 | 111 | private void initUnix(final Description description) { 112 | final File testTargetDir = new File("./target").getAbsoluteFile(); 113 | final File virtualPortsDir = new File(testTargetDir, "virtual-ports"); 114 | 115 | virtualPortsDir.mkdirs(); 116 | 117 | final String filename1 = String 118 | .format("virtualcom-%s-%s-%d", description.getClassName(), description.getMethodName(), this.random.nextInt(10000)); 119 | this.virtualCom1 = new File(virtualPortsDir, filename1); 120 | final String fileName2 = String 121 | .format("virtualcom-%s-%s-%d", description.getClassName(), description.getMethodName(), this.random.nextInt(10000)); 122 | this.virtualCom2 = new File(virtualPortsDir, fileName2); 123 | } 124 | 125 | private BackgroundProcess openSocat() { 126 | return new BackgroundProcess() { 127 | 128 | private Process process; 129 | 130 | @Override 131 | public Process getProcess() { 132 | return this.process; 133 | } 134 | 135 | @Override 136 | public void run() { 137 | 138 | try { 139 | List cmds = asList( 140 | "socat", 141 | "pty,link=" + VirtualPortRule.this.virtualCom1.getAbsolutePath() + ",rawer,echo=0", 142 | "pty,link=" + VirtualPortRule.this.virtualCom2.getAbsolutePath() + ",rawer,echo=0" 143 | ); 144 | final ProcessBuilder processBuilder = new ProcessBuilder(cmds); 145 | processBuilder.redirectErrorStream(true); 146 | 147 | LOG.info("Process starting: {}", cmds); 148 | this.process = processBuilder.start(); 149 | LOG.info("Process started! [{}], ports: [{}] // [{}].", this.process, VirtualPortRule.this.virtualCom1.getName(), 150 | VirtualPortRule.this.virtualCom2.getName()); 151 | VirtualPortRule.this.outputStream = this.process.getOutputStream(); 152 | this.process.waitFor(); 153 | } catch (final IOException ioEx) { 154 | throw new IllegalStateException("unable to start socat!", ioEx); 155 | } catch (final InterruptedException interruptEx) { 156 | Thread.currentThread().interrupt(); 157 | LOG.debug("interrupted.", interruptEx); 158 | this.process.destroy(); 159 | } 160 | } 161 | }; 162 | } 163 | 164 | public OutputStream getOutputStream() { 165 | return this.outputStream; 166 | } 167 | 168 | public boolean isAvailable() { 169 | return this.isAvailable; 170 | } 171 | 172 | public File getVirtualCom1() { 173 | return this.virtualCom1; 174 | } 175 | 176 | public File getVirtualCom2() { 177 | return this.virtualCom2; 178 | } 179 | 180 | /** 181 | * Executes the provided command and waits for a zero (success) or non-zero (failure) return code 182 | */ 183 | private static boolean execute(String ... commands) { 184 | LOG.debug("Executing: {}", Arrays.toString(commands)); 185 | try { 186 | // Create and execute our new process 187 | Process p = Runtime.getRuntime().exec(commands); 188 | // Consume output to prevent deadlock 189 | while (p.getInputStream().read() != -1) {} 190 | p.waitFor(); 191 | return p.exitValue() == 0; 192 | } 193 | catch(InterruptedException ex) { 194 | LOG.warn("InterruptedException waiting for a return value from {}", Arrays.toString(commands), ex); 195 | } 196 | catch(IOException ex) { 197 | LOG.error("IOException executing: {}", Arrays.toString(commands), ex); 198 | } 199 | 200 | return false; 201 | } 202 | 203 | @Override 204 | public String toString() { 205 | return "VirtualPortRule{" + "processes=" + this.processes 206 | + ", outputStream=" + this.outputStream 207 | + ", isAvailable=" + this.isAvailable 208 | + ", random=" + this.random 209 | + ", virtualCom1=" + this.virtualCom1 210 | + ", virtualCom2=" + this.virtualCom2 211 | + '}'; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/test/resources/log4j2.properties: -------------------------------------------------------------------------------- 1 | # Logging settings for unit tests 2 | 3 | # The root logger with appender name 4 | rootLogger=INFO,STDOUT,TESTNAME 5 | 6 | # Assign STDOUT a valid appender & define its layout 7 | appender.console.name=STDOUT 8 | appender.console.type=Console 9 | appender.console.layout.type=PatternLayout 10 | appender.console.layout.pattern=[%highlight{%p}{INFO=blue}] [%c{1}] %m%n 11 | 12 | # Make logs for Junit4 method names look like maven 13 | appender.testName.name=TESTNAME 14 | appender.testName.type=Console 15 | appender.testName.layout.type=PatternLayout 16 | appender.testName.layout.pattern=[%highlight{%p}{INFO=blue}] Running %c.%highlight{%m}{FATAL=bold,white, ERROR=bold,white, WARN=bold,white, INFO=bold,white, DEBUG=bold,white, TRACE=bold,white}%n 17 | appender.testName.filter.1.type=MarkerFilter 18 | appender.testName.filter.1.marker=MethodName 19 | appender.console.filter.1.type=MarkerFilter 20 | appender.console.filter.1.marker=MethodName 21 | appender.console.filter.1.onMatch=DENY 22 | appender.console.filter.1.onMismatch=ACCEPT 23 | 24 | # Configures log-level of 'jssc' java package (Handy for debugging tests). 25 | #logger.jssc.name = jssc 26 | #logger.jssc.level = DEBUG 27 | -------------------------------------------------------------------------------- /toolchain/Aarch64.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(TOOLCHAIN_PREFIX aarch64-linux-gnu) 3 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) 4 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) 5 | set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip CACHE FILEPATH "" FORCE) 6 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}/) 7 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 8 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 9 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 10 | 11 | -------------------------------------------------------------------------------- /toolchain/Armhf.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(TOOLCHAIN_PREFIX arm-linux-gnueabi) 3 | 4 | message(STATUS "Note: Some compilers may require version information to be found") 5 | # set(COMPILER_VERSION "-4.7") 6 | 7 | set(TOOLCHAIN_SUFFIX hf) 8 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}${TOOLCHAIN_SUFFIX}-gcc${COMPILER_VERSION}) 9 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}${TOOLCHAIN_SUFFIX}-g++${COMPILER_VERSION}) 10 | set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}${TOOLCHAIN_SUFFIX}-strip CACHE FILEPATH "" FORCE) 11 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}${TOOLCHAIN_SUFFIX}/) 12 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 13 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 14 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 15 | 16 | -------------------------------------------------------------------------------- /toolchain/Armsf.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(TOOLCHAIN_PREFIX arm-linux-gnueabi) 3 | if(NOT SKIP_COMPILER_VERSION) 4 | SET(COMPILER_VERSION 5) 5 | if(NOT COMPILER_VERSION MATCHES "-.*") 6 | SET(COMPILER_VERSION "-${COMPILER_VERSION}") 7 | endif() 8 | endif() 9 | set(TOOLCHAIN_SUFFIX "") 10 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}${TOOLCHAIN_SUFFIX}-gcc${COMPILER_VERSION}) 11 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}${TOOLCHAIN_SUFFIX}-g++${COMPILER_VERSION}) 12 | set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}${TOOLCHAIN_SUFFIX}-strip CACHE FILEPATH "" FORCE) 13 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}${TOOLCHAIN_SUFFIX}/) 14 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 15 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 16 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 17 | 18 | -------------------------------------------------------------------------------- /toolchain/Dockcross.cmake: -------------------------------------------------------------------------------- 1 | include($ENV{CMAKE_TOOLCHAIN_FILE}) 2 | 3 | if($ENV{DEFAULT_DOCKCROSS_IMAGE} MATCHES "dockcross/windows-.*") 4 | set(CMAKE_SYSTEM_NAME Windows) 5 | else() 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | endif() 8 | 9 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 10 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 11 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) -------------------------------------------------------------------------------- /toolchain/Mingw32.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Windows) 2 | set(TOOLCHAIN_PREFIX i686-w64-mingw32) 3 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) 4 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) 5 | set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) 6 | set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip CACHE FILEPATH "" FORCE) 7 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}/) 8 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 9 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 10 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 11 | 12 | -------------------------------------------------------------------------------- /toolchain/Mingw64.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Windows) 2 | set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) 3 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) 4 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) 5 | set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) 6 | set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip CACHE FILEPATH "" FORCE) 7 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}/) 8 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 9 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 10 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 11 | 12 | -------------------------------------------------------------------------------- /toolchain/MingwAarch64.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Windows) 2 | 3 | # URL for llvm-mingw 4 | set(URL "https://github.com/mstorsjo/llvm-mingw/releases/download/20201020/llvm-mingw-20201020-msvcrt-ubuntu-18.04.tar.xz") 5 | set(SHA256 "96e94e469665ee5632fff32a19b589ae1698859189d85615f3062b1544510b75") 6 | get_filename_component(ARCHIVE_NAME "${URL}" NAME) 7 | set(ARCHIVE "${CMAKE_BINARY_DIR}/llvm-mingw/${ARCHIVE_NAME}") 8 | 9 | # Try to predict the subdirectory name from the file name 10 | string(REPLACE ".tar.xz" "" SUBDIR "${ARCHIVE_NAME}") 11 | 12 | # Prevent extract process from running more than once 13 | if(NOT TOOLCHAIN_LOCATION) 14 | if(NOT EXISTS "${CMAKE_BINARY_DIR}/llvm-mingw/${SUBDIR}") 15 | if(NOT EXISTS "${ARCHIVE}") 16 | file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/llvm-mingw") 17 | message(STATUS "Downloading ${URL} to ${ARCHIVE}...") 18 | file(DOWNLOAD ${URL} ${ARCHIVE} TIMEOUT 60 EXPECTED_HASH SHA256=${SHA256}) 19 | endif() 20 | message(STATUS "Extracting ${ARCHIVE} to ${CMAKE_BINARY_DIR}/llvm-mingw/${SUBDIR}/...") 21 | if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.18.0") 22 | file(ARCHIVE_EXTRACT INPUT "${ARCHIVE}" DESTINATION "${CMAKE_BINARY_DIR}/llvm-mingw") 23 | else() 24 | execute_process(COMMAND tar xf "${ARCHIVE}" -C "${CMAKE_BINARY_DIR}/llvm-mingw") 25 | endif() 26 | endif() 27 | endif() 28 | 29 | set(TOOLCHAIN_LOCATION "${CMAKE_BINARY_DIR}/llvm-mingw/${SUBDIR}/bin") 30 | set(TOOLCHAIN_PREFIX "${TOOLCHAIN_LOCATION}/aarch64-w64-mingw32") 31 | set(CMAKE_C_COMPILER "${TOOLCHAIN_PREFIX}-gcc") 32 | set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PREFIX}-g++") 33 | set(CMAKE_RC_COMPILER "${TOOLCHAIN_PREFIX}-windres") 34 | set(CMAKE_STRIP "${TOOLCHAIN_PREFIX}-strip" CACHE FILEPATH "" FORCE) 35 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 36 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 37 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 38 | -------------------------------------------------------------------------------- /toolchain/Ppc64.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(TOOLCHAIN_PREFIX powerpc64le-linux-gnu) 3 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) 4 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) 5 | set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip CACHE FILEPATH "" FORCE) 6 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}/) 7 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 8 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 9 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 10 | 11 | -------------------------------------------------------------------------------- /toolchain/Riscv32.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(TOOLCHAIN_PREFIX riscv32-linux-gnu) 3 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) 4 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) 5 | set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip CACHE FILEPATH "" FORCE) 6 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}/) 7 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 8 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 9 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 10 | 11 | -------------------------------------------------------------------------------- /toolchain/Riscv64.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(TOOLCHAIN_PREFIX riscv64-linux-gnu) 3 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) 4 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) 5 | set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip CACHE FILEPATH "" FORCE) 6 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}/) 7 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 8 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 9 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 10 | 11 | --------------------------------------------------------------------------------