├── .clang-format ├── .editorconfig ├── .github ├── FUNDING.yml └── workflows │ └── gradle.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── TROUBLESHOOTING.md ├── build.gradle.kts ├── common.cmake ├── conventions ├── build.gradle.kts ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ ├── tel.schich.javacan.convention.arch-detect.gradle.kts │ ├── tel.schich.javacan.convention.base.gradle.kts │ ├── tel.schich.javacan.convention.native.gradle.kts │ └── tel.schich.javacan.convention.published.gradle.kts ├── core-arch-detect ├── build.gradle.kts └── src │ └── main │ └── java │ └── tel │ └── schich │ └── javacan │ └── JavaCANAutoDetect.java ├── core ├── CMakeLists.txt ├── build.gradle.kts └── src │ ├── include │ └── linux │ │ ├── can.h │ │ └── can │ │ ├── bcm.h │ │ ├── error.h │ │ ├── isotp.h │ │ ├── j1939.h │ │ ├── netlink.h │ │ └── raw.h │ ├── main │ ├── c │ │ ├── common.c │ │ ├── common.h │ │ ├── javacan_bcm.c │ │ ├── javacan_bufferhelper.c │ │ ├── javacan_isotp.c │ │ ├── javacan_j1939.c │ │ ├── javacan_networkdevice.c │ │ ├── javacan_raw.c │ │ └── javacan_socketcan.c │ └── java │ │ └── tel │ │ └── schich │ │ └── javacan │ │ ├── AbstractCanChannel.java │ │ ├── BcmCanChannel.java │ │ ├── BcmFlag.java │ │ ├── BcmMessage.java │ │ ├── BcmOpcode.java │ │ ├── CanChannels.java │ │ ├── CanFilter.java │ │ ├── CanFrame.java │ │ ├── CanId.java │ │ ├── CanSocketOptions.java │ │ ├── ImmutableJ1939Address.java │ │ ├── ImmutableJ1939ReceiveMessageHeader.java │ │ ├── ImmutableRawReceiveMessageHeader.java │ │ ├── IsotpAddress.java │ │ ├── IsotpCanChannel.java │ │ ├── IsotpCanChannelImpl.java │ │ ├── IsotpCanSocketOptions.java │ │ ├── IsotpFlowControlOptions.java │ │ ├── IsotpLinkLayerOptions.java │ │ ├── IsotpOptions.java │ │ ├── IsotpSocketAddress.java │ │ ├── J1939Address.java │ │ ├── J1939AddressBuffer.java │ │ ├── J1939CanChannel.java │ │ ├── J1939CanChannelImpl.java │ │ ├── J1939CanSocketOptions.java │ │ ├── J1939Filter.java │ │ ├── J1939ReceiveMessageHeader.java │ │ ├── J1939ReceiveMessageHeaderBuffer.java │ │ ├── J1939Utils.java │ │ ├── JavaCAN.java │ │ ├── NetworkDevice.java │ │ ├── RawCanChannel.java │ │ ├── RawCanChannelImpl.java │ │ ├── RawReceiveMessageHeader.java │ │ ├── RawReceiveMessageHeaderBuffer.java │ │ ├── ReceiveMessageHeader.java │ │ ├── SocketCAN.java │ │ ├── option │ │ ├── CanSocketOption.java │ │ └── package-info.java │ │ ├── package-info.java │ │ ├── platform │ │ ├── NativeChannel.java │ │ ├── Platform.java │ │ ├── UnsupportedPlatformException.java │ │ ├── linux │ │ │ ├── LinuxNativeOperationException.java │ │ │ ├── LinuxNetworkDevice.java │ │ │ ├── LinuxSocketOptionHandler.java │ │ │ ├── UnixFileDescriptor.java │ │ │ └── package-info.java │ │ └── package-info.java │ │ └── util │ │ ├── BufferHelper.java │ │ ├── CanUtils.java │ │ ├── EvictingQueue.java │ │ └── package-info.java │ ├── test │ └── java │ │ └── tel │ │ └── schich │ │ └── javacan │ │ └── test │ │ ├── BcmCanSocketTest.java │ │ ├── J1939CanSocketTest.java │ │ ├── J1939UtilsTest.java │ │ ├── RawCanSocketTest.java │ │ ├── isotp │ │ └── IsotpCanSocketOptionsTest.java │ │ └── linux │ │ └── LinuxNativeOperationExceptionTest.java │ └── testFixtures │ ├── java │ └── tel │ │ └── schich │ │ └── javacan │ │ ├── TestHelper.java │ │ └── test │ │ └── CanTestHelper.java │ └── resources │ └── logback-test.xml ├── epoll-arch-detect ├── build.gradle.kts └── src │ └── main │ └── java │ └── tel │ └── schich │ └── javacan │ └── platform │ └── linux │ └── epoll │ └── EPollAutoDetect.java ├── epoll ├── CMakeLists.txt ├── build.gradle.kts └── src │ ├── main │ ├── c │ │ └── javacan_epoll.c │ └── java │ │ └── tel │ │ └── schich │ │ └── javacan │ │ ├── package-info.java │ │ ├── platform │ │ └── linux │ │ │ └── epoll │ │ │ ├── EPoll.java │ │ │ ├── EPollException.java │ │ │ ├── EPollRegistration.java │ │ │ ├── EPollSelector.java │ │ │ └── package-info.java │ │ ├── select │ │ ├── IOEvent.java │ │ ├── IOSelector.java │ │ ├── SelectorRegistration.java │ │ └── package-info.java │ │ └── util │ │ ├── CanBroker.java │ │ ├── CopyingFrameHandlerProxy.java │ │ ├── CopyingMessageHandlerProxy.java │ │ ├── EventLoop.java │ │ ├── FrameHandler.java │ │ ├── IsotpListener.java │ │ ├── MessageHandler.java │ │ ├── PollExceptionHandler.java │ │ ├── PollFunction.java │ │ └── PollingThread.java │ └── test │ └── java │ └── tel │ └── schich │ └── javacan │ └── test │ ├── select │ └── EPollSelectorTest.java │ └── util │ ├── CanBrokerTest.java │ └── IsotpListenerTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── renovate.json5 ├── settings.gradle.kts ├── setup-vcan.sh └── tools ├── build.gradle.kts └── src └── main └── java └── tel └── schich └── javacan └── tools ├── CanDumpConverter.java └── package-info.java /.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignOperands: true 7 | AllowAllArgumentsOnNextLine: false 8 | AllowAllConstructorInitializersOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: Always 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: Always 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BreakBeforeBraces: Custom 19 | BraceWrapping: 20 | AfterCaseLabel: false 21 | AfterClass: false 22 | AfterControlStatement: Never 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | SplitEmptyFunction: false 31 | SplitEmptyRecord: true 32 | BreakBeforeBinaryOperators: None 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | ColumnLimit: 0 37 | CompactNamespaces: false 38 | ContinuationIndentWidth: 8 39 | IndentCaseLabels: true 40 | IndentPPDirectives: None 41 | IndentWidth: 4 42 | KeepEmptyLinesAtTheStartOfBlocks: true 43 | MaxEmptyLinesToKeep: 2 44 | NamespaceIndentation: All 45 | ObjCSpaceAfterProperty: false 46 | ObjCSpaceBeforeProtocolList: true 47 | PointerAlignment: Right 48 | ReflowComments: false 49 | SpaceAfterCStyleCast: true 50 | SpaceAfterLogicalNot: false 51 | SpaceAfterTemplateKeyword: false 52 | SpaceBeforeAssignmentOperators: true 53 | SpaceBeforeCpp11BracedList: false 54 | SpaceBeforeCtorInitializerColon: true 55 | SpaceBeforeInheritanceColon: true 56 | SpaceBeforeParens: ControlStatements 57 | SpaceBeforeRangeBasedForLoopColon: true 58 | SpaceInEmptyParentheses: false 59 | SpacesBeforeTrailingComments: 0 60 | SpacesInAngles: false 61 | SpacesInCStyleCastParentheses: false 62 | SpacesInContainerLiterals: false 63 | SpacesInParentheses: false 64 | SpacesInSquareBrackets: false 65 | TabWidth: 4 66 | UseTab: Never 67 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: pschichtel 4 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Java CI with Maven 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | submodules: recursive 19 | - name: Set up JDK 20 | uses: actions/setup-java@v3 21 | with: 22 | java-version: '11' 23 | distribution: 'temurin' 24 | cache: gradle 25 | - name: Setup Gradle 26 | uses: gradle/actions/setup-gradle@v3 27 | - name: Build 28 | run: ./gradlew --no-configuration-cache --no-parallel mavenCentralDeploy "-PsonatypeUsername=$SONATYPE_USERNAME" "-PsonatypePassword=$SONATYPE_PASSWORD" 29 | env: 30 | SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} 31 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | cmake-build-*/ 3 | *.iml 4 | target/ 5 | *.log 6 | .attach_pid* 7 | /.classpath 8 | /.cproject 9 | /.project 10 | .settings/ 11 | build/ 12 | .gradle/ 13 | .kotlin/ 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "dockcross"] 2 | path = dockcross 3 | url = ../dockcross-gradle-plugin.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | project(javacan-jni C) 3 | 4 | set(CMAKE_C_STANDARD 99) 5 | 6 | add_subdirectory(core) 7 | add_subdirectory(epoll) 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Phillip Schichtel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TROUBLESHOOTING.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | This is a document to collect various pitfalls when working with CAN devices. 4 | 5 | ## General 6 | 7 | A generally good first step in debugging issues is to use the tools from the [can-utils project](https://github.com/linux-can/can-utils). These tools make use of the same Kernel APIs and in many cases use very similar logic. If issues can be reproduced with these tools, then it is very likely not a JavaCAN issue. However, if you encounter such issues, I'd be happy to hear about them and possibly document them here. 8 | 9 | ## RAW 10 | 11 | ### 11 Bit vs 29 Bit Address Detection 12 | 13 | The CAN ID returned by `CanFrame.getId()` does not by itself carry the information whether it is an 11 bit (SFF) or 29 bit (EFF). 14 | While IDs that use more than the first 11 bits are definitely 29 bit IDs, shorter IDs may still be 29 bit addresses. 15 | The only robust indicator for the address length is the EFF flag in the raw CAN ID. So either use `CanFrame.isExtended()` or 16 | `CanId.isExtended(int)` on a raw CAN ID (e.g. from `CanFrame.getRawId()`). 17 | 18 | ## BCM 19 | 20 | Nothing here, yet. Pull Requests welcome! 21 | 22 | ## ISOTP 23 | 24 | ### Missing Padding 25 | 26 | Some controllers require ISOTP frames to be padded. The `IsotpOptions` configuration object can be used to configure the padding bytes. 27 | 28 | ### 11 Bit / 29 Bit Address Misalignment 29 | 30 | Some controllers accept frames addressed to it using 11 bit (SFF) addresses, but only respond using 29 bit (EFF) address. This can lead to frames being dropped due to misconfigured filters somewhere along the communication path. In this scenario `candump` will show incoming frames with zero padded 29 bit addresses while outgoing addresses are not zero padded 11 bit addresses. 31 | 32 | If you are affected by this issue, then a command like `echo "11 22 33 44 55 66 11 22 33 44 55" | isotpsend -s 1FF -d 17F -p 00 can0` would yield something like this: 33 | 34 | ``` 35 | (001.455852) can0 1FF [8] 10 0B 11 22 33 44 55 66 36 | (001.456351) can0 0000017F [8] 30 08 00 00 00 00 00 00 37 | ``` 38 | 39 | Note the different CAN IDs in the third column and the lack of further communication. 40 | 41 | The same command with EFF addresses (`echo "11 22 33 44 55 66 11 22 33 44 55" | isotpsend -s 000001FF -d 0000017F -p 00 can0`) could look like this: 42 | 43 | ``` 44 | (004.665204) can0 000001FF [8] 10 15 00 11 22 33 44 55 45 | (004.666507) can0 0000017F [8] 30 08 00 00 00 00 00 00 46 | (004.667960) can0 000001FF [8] 21 66 77 00 11 00 11 22 47 | (004.669110) can0 000001FF [8] 22 33 44 55 66 77 00 11 48 | (004.670046) can0 000001FF [2] 23 22 49 | ``` 50 | 51 | The concrete output is application specific. 52 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import pl.allegro.tech.build.axion.release.domain.PredefinedVersionCreator 2 | 3 | plugins { 4 | `maven-publish` 5 | id("io.github.gradle-nexus.publish-plugin") version "2.0.0" 6 | id("pl.allegro.tech.build.axion-release") version "1.18.16" 7 | } 8 | 9 | description = "JavaCAN is a binding to Linux' socketcan subsystem that feels native to Java developers." 10 | 11 | scmVersion { 12 | tag { 13 | prefix = "javacan-" 14 | } 15 | nextVersion { 16 | suffix = "SNAPSHOT" 17 | separator = "-" 18 | } 19 | versionCreator = PredefinedVersionCreator.SIMPLE.versionCreator 20 | } 21 | 22 | val gitVersion: String = scmVersion.version 23 | 24 | allprojects { 25 | group = "tel.schich" 26 | version = gitVersion 27 | } 28 | 29 | nexusPublishing { 30 | this.repositories { 31 | sonatype() 32 | } 33 | } 34 | 35 | val publishAllToMavenLocal by tasks.registering(DefaultTask::class) { 36 | group = "publishing" 37 | 38 | project.subprojects 39 | .flatMap { it.tasks } 40 | .filter { it.enabled } 41 | .filter { it.name == "publishToMavenLocal" } 42 | .forEach { 43 | this@registering.dependsOn(it) 44 | } 45 | } 46 | 47 | val testAll by tasks.registering(DefaultTask::class) { 48 | group = "verification" 49 | 50 | project.subprojects 51 | .flatMap { it.tasks .withType() } 52 | .filter { it.enabled } 53 | .forEach { 54 | this@registering.dependsOn(it) 55 | } 56 | } 57 | 58 | val mavenCentralDeploy by tasks.registering(DefaultTask::class) { 59 | group = "publishing" 60 | val isSnapshot = project.version.toString().endsWith("-SNAPSHOT") 61 | 62 | val publishTasks = subprojects 63 | .flatMap { it.tasks.withType() } 64 | .filter { it.repository.name == "sonatype" } 65 | dependsOn(publishTasks) 66 | if (!isSnapshot) { 67 | dependsOn(tasks.closeAndReleaseStagingRepositories) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /common.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_C_STANDARD 99) 2 | 3 | option(PROJECT_VERSION "The version of the maven project" "unspecified") 4 | option(IS_RELEASE "Whether this is a release build" OFF) 5 | option(LINK_STATICALLY "Whether this is a release build" OFF) 6 | 7 | find_package(Java 1.8 REQUIRED) 8 | 9 | include_directories( 10 | src/include 11 | "$ENV{JAVA_HOME}/include" 12 | "$ENV{JAVA_HOME}/include/linux" 13 | build/jni) 14 | 15 | add_compile_options(-Werror -fPIC -D "PROJECT_VERSION=${PROJECT_VERSION}") 16 | if(IS_RELEASE) 17 | add_compile_options(-O2 -flto) 18 | else() 19 | add_compile_options(-g3 -Og) 20 | endif() 21 | 22 | add_link_options(-z noexecstack -fvisibility=hidden) 23 | if(LINK_STATICALLY) 24 | add_link_options(-static) 25 | endif() 26 | -------------------------------------------------------------------------------- /conventions/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | gradlePluginPortal() 8 | } 9 | 10 | dependencies { 11 | api(plugin("tel.schich.dockcross", version = "0.2.3")) 12 | } 13 | 14 | fun plugin(id: String, version: String) = "$id:$id.gradle.plugin:$version" 15 | -------------------------------------------------------------------------------- /conventions/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenCentral() 4 | gradlePluginPortal() 5 | } 6 | } 7 | 8 | dependencyResolutionManagement { 9 | repositories { 10 | mavenCentral() 11 | } 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /conventions/src/main/kotlin/tel.schich.javacan.convention.arch-detect.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.gradle.kotlin.dsl.getValue 2 | import org.gradle.kotlin.dsl.provideDelegate 3 | import org.gradle.kotlin.dsl.registering 4 | 5 | plugins { 6 | id("tel.schich.javacan.convention.published") 7 | } 8 | 9 | val nativeLibs by configurations.registering 10 | 11 | tasks.jar.configure { 12 | dependsOn(nativeLibs) 13 | for (jar in nativeLibs.get().resolvedConfiguration.resolvedArtifacts) { 14 | val classifier = jar.classifier ?: continue 15 | from(zipTree(jar.file)) { 16 | include("native/*.so") 17 | into(classifier) 18 | } 19 | } 20 | } 21 | 22 | tasks.withType().configureEach { 23 | enabled = false 24 | } 25 | -------------------------------------------------------------------------------- /conventions/src/main/kotlin/tel.schich.javacan.convention.base.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `java-library` 3 | `java-test-fixtures` 4 | } 5 | 6 | val javaComponent = components["java"] as AdhocComponentWithVariants 7 | javaComponent.withVariantsFromConfiguration(configurations["testFixturesApiElements"]) { skip() } 8 | javaComponent.withVariantsFromConfiguration(configurations["testFixturesRuntimeElements"]) { skip() } 9 | 10 | java { 11 | toolchain { 12 | vendor = JvmVendorSpec.ADOPTIUM 13 | languageVersion = JavaLanguageVersion.of(8) 14 | } 15 | } 16 | 17 | tasks.withType().configureEach { 18 | options.compilerArgs.addAll( 19 | listOf( 20 | "-Xlint:deprecation", 21 | "-Xlint:unchecked", 22 | ) 23 | ) 24 | } 25 | 26 | repositories { 27 | mavenCentral() 28 | } 29 | 30 | dependencies { 31 | compileOnly("org.eclipse.jdt:org.eclipse.jdt.annotation:2.3.100") 32 | implementation("org.slf4j:slf4j-api:2.0.16") 33 | 34 | testImplementation("ch.qos.logback:logback-classic:1.3.14") 35 | 36 | "org.junit.jupiter:junit-jupiter-engine:5.11.3".also { 37 | testFixturesImplementation(it) 38 | testImplementation(it) 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /conventions/src/main/kotlin/tel.schich.javacan.convention.published.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("tel.schich.javacan.convention.base") 3 | signing 4 | `maven-publish` 5 | } 6 | 7 | val ci = System.getenv("CI") != null 8 | 9 | java { 10 | withSourcesJar() 11 | withJavadocJar() 12 | } 13 | 14 | publishing { 15 | publications { 16 | register("maven") { 17 | artifactId = "javacan-${project.name}" 18 | from(components["java"]) 19 | 20 | pom { 21 | name = "JavaCAN" 22 | description = project.description 23 | url = "https://github.com/pschichtel/JavaCAN" 24 | licenses { 25 | license { 26 | name = "MIT" 27 | url = "https://opensource.org/licenses/MIT" 28 | } 29 | } 30 | developers { 31 | developer { 32 | id.set("pschichtel") 33 | name.set("Phillip Schichtel") 34 | email.set("phillip@schich.tel") 35 | } 36 | } 37 | scm { 38 | url.set("https://github.com/pschichtel/JavaCAN") 39 | connection.set("scm:git:https://github.com/pschichtel/JavaCAN") 40 | developerConnection.set("scm:git:git@github.com:pschichtel/JavaCAN") 41 | } 42 | } 43 | } 44 | } 45 | } 46 | 47 | if (!ci) { 48 | signing { 49 | useGpgCmd() 50 | sign(publishing.publications) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /core-arch-detect/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("tel.schich.javacan.convention.arch-detect") 3 | } 4 | 5 | val nativeLibs = configurations.named("nativeLibs") 6 | 7 | dependencies { 8 | api(project(":core")) 9 | nativeLibs(project(mapOf("path" to ":core", "configuration" to "archDetectConfiguration"))) 10 | } 11 | 12 | publishing.publications.withType().configureEach { 13 | pom { 14 | description = "${rootProject.description} The ${project.name} module bundles all architectures and allows runtime architecture detection." 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core-arch-detect/src/main/java/tel/schich/javacan/JavaCANAutoDetect.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import tel.schich.javacan.platform.Platform; 26 | 27 | public class JavaCANAutoDetect { 28 | public static void initialize() { 29 | System.setProperty(Platform.classPathPropertyNameForLibrary(JavaCAN.LIB_NAME), "/" + Platform.detectCpuArch() + "/native/" + Platform.LINUX_LIBRARY_PREFIX + JavaCAN.LIB_NAME + ".so"); 30 | JavaCAN.initialize(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | project(javacan-core C) 3 | 4 | include(../common.cmake) 5 | 6 | add_library(javacan-core SHARED 7 | build/jni/core/jni-c-to-java.c 8 | src/main/c/common.c 9 | src/main/c/common.h 10 | src/main/c/javacan_bcm.c 11 | src/main/c/javacan_bufferhelper.c 12 | src/main/c/javacan_networkdevice.c 13 | src/main/c/javacan_socketcan.c 14 | src/main/c/javacan_j1939.c 15 | src/main/c/javacan_isotp.c 16 | src/main/c/javacan_raw.c) 17 | -------------------------------------------------------------------------------- /core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("tel.schich.javacan.convention.native") 3 | } 4 | 5 | publishing.publications.withType().configureEach { 6 | pom { 7 | description = "${rootProject.description} The ${project.name} module provides the basic socketcan bindings." 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /core/src/include/linux/can/bcm.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 | /* 3 | * linux/can/bcm.h 4 | * 5 | * Definitions for CAN Broadcast Manager (BCM) 6 | * 7 | * Author: Oliver Hartkopp 8 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 3. Neither the name of Volkswagen nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software 21 | * without specific prior written permission. 22 | * 23 | * Alternatively, provided that this notice is retained in full, this 24 | * software may be distributed under the terms of the GNU General 25 | * Public License ("GPL") version 2, in which case the provisions of the 26 | * GPL apply INSTEAD OF those given above. 27 | * 28 | * The provided data structures and external interfaces from this code 29 | * are not restricted to be used by modules with a GPL compatible license. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 42 | * DAMAGE. 43 | */ 44 | 45 | #ifndef _UAPI_CAN_BCM_H 46 | #define _UAPI_CAN_BCM_H 47 | 48 | #include 49 | #include 50 | 51 | struct bcm_timeval { 52 | long tv_sec; 53 | long tv_usec; 54 | }; 55 | 56 | /** 57 | * struct bcm_msg_head - head of messages to/from the broadcast manager 58 | * @opcode: opcode, see enum below. 59 | * @flags: special flags, see below. 60 | * @count: number of frames to send before changing interval. 61 | * @ival1: interval for the first @count frames. 62 | * @ival2: interval for the following frames. 63 | * @can_id: CAN ID of frames to be sent or received. 64 | * @nframes: number of frames appended to the message head. 65 | * @frames: array of CAN frames. 66 | */ 67 | struct bcm_msg_head { 68 | __u32 opcode; 69 | __u32 flags; 70 | __u32 count; 71 | struct bcm_timeval ival1, ival2; 72 | canid_t can_id; 73 | __u32 nframes; 74 | struct can_frame frames[]; 75 | }; 76 | 77 | enum { 78 | TX_SETUP = 1, /* create (cyclic) transmission task */ 79 | TX_DELETE, /* remove (cyclic) transmission task */ 80 | TX_READ, /* read properties of (cyclic) transmission task */ 81 | TX_SEND, /* send one CAN frame */ 82 | RX_SETUP, /* create RX content filter subscription */ 83 | RX_DELETE, /* remove RX content filter subscription */ 84 | RX_READ, /* read properties of RX content filter subscription */ 85 | TX_STATUS, /* reply to TX_READ request */ 86 | TX_EXPIRED, /* notification on performed transmissions (count=0) */ 87 | RX_STATUS, /* reply to RX_READ request */ 88 | RX_TIMEOUT, /* cyclic message is absent */ 89 | RX_CHANGED /* updated CAN frame (detected content change) */ 90 | }; 91 | 92 | #define SETTIMER 0x0001 93 | #define STARTTIMER 0x0002 94 | #define TX_COUNTEVT 0x0004 95 | #define TX_ANNOUNCE 0x0008 96 | #define TX_CP_CAN_ID 0x0010 97 | #define RX_FILTER_ID 0x0020 98 | #define RX_CHECK_DLC 0x0040 99 | #define RX_NO_AUTOTIMER 0x0080 100 | #define RX_ANNOUNCE_RESUME 0x0100 101 | #define TX_RESET_MULTI_IDX 0x0200 102 | #define RX_RTR_FRAME 0x0400 103 | #define CAN_FD_FRAME 0x0800 104 | 105 | #endif /* !_UAPI_CAN_BCM_H */ 106 | -------------------------------------------------------------------------------- /core/src/include/linux/can/j1939.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ 2 | /* 3 | * j1939.h 4 | * 5 | * Copyright (c) 2010-2011 EIA Electronics 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #ifndef _UAPI_CAN_J1939_H_ 13 | #define _UAPI_CAN_J1939_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #define J1939_MAX_UNICAST_ADDR 0xfd 20 | #define J1939_IDLE_ADDR 0xfe 21 | #define J1939_NO_ADDR 0xff /* == broadcast or no addr */ 22 | #define J1939_NO_NAME 0 23 | #define J1939_PGN_REQUEST 0x0ea00 /* Request PG */ 24 | #define J1939_PGN_ADDRESS_CLAIMED 0x0ee00 /* Address Claimed */ 25 | #define J1939_PGN_ADDRESS_COMMANDED 0x0fed8 /* Commanded Address */ 26 | #define J1939_PGN_PDU1_MAX 0x3ff00 27 | #define J1939_PGN_MAX 0x3ffff 28 | #define J1939_NO_PGN 0x40000 29 | 30 | /* J1939 Parameter Group Number 31 | * 32 | * bit 0-7 : PDU Specific (PS) 33 | * bit 8-15 : PDU Format (PF) 34 | * bit 16 : Data Page (DP) 35 | * bit 17 : Reserved (R) 36 | * bit 19-31 : set to zero 37 | */ 38 | typedef __u32 pgn_t; 39 | 40 | /* J1939 Priority 41 | * 42 | * bit 0-2 : Priority (P) 43 | * bit 3-7 : set to zero 44 | */ 45 | typedef __u8 priority_t; 46 | 47 | /* J1939 NAME 48 | * 49 | * bit 0-20 : Identity Number 50 | * bit 21-31 : Manufacturer Code 51 | * bit 32-34 : ECU Instance 52 | * bit 35-39 : Function Instance 53 | * bit 40-47 : Function 54 | * bit 48 : Reserved 55 | * bit 49-55 : Vehicle System 56 | * bit 56-59 : Vehicle System Instance 57 | * bit 60-62 : Industry Group 58 | * bit 63 : Arbitrary Address Capable 59 | */ 60 | typedef __u64 name_t; 61 | 62 | /* J1939 socket options */ 63 | #define SOL_CAN_J1939 (SOL_CAN_BASE + CAN_J1939) 64 | enum { 65 | SO_J1939_FILTER = 1, /* set filters */ 66 | SO_J1939_PROMISC = 2, /* set/clr promiscuous mode */ 67 | SO_J1939_SEND_PRIO = 3, 68 | SO_J1939_ERRQUEUE = 4, 69 | }; 70 | 71 | enum { 72 | SCM_J1939_DEST_ADDR = 1, 73 | SCM_J1939_DEST_NAME = 2, 74 | SCM_J1939_PRIO = 3, 75 | SCM_J1939_ERRQUEUE = 4, 76 | }; 77 | 78 | enum { 79 | J1939_NLA_PAD, 80 | J1939_NLA_BYTES_ACKED, 81 | J1939_NLA_TOTAL_SIZE, 82 | J1939_NLA_PGN, 83 | J1939_NLA_SRC_NAME, 84 | J1939_NLA_DEST_NAME, 85 | J1939_NLA_SRC_ADDR, 86 | J1939_NLA_DEST_ADDR, 87 | }; 88 | 89 | enum { 90 | J1939_EE_INFO_NONE, 91 | J1939_EE_INFO_TX_ABORT, 92 | J1939_EE_INFO_RX_RTS, 93 | J1939_EE_INFO_RX_DPO, 94 | J1939_EE_INFO_RX_ABORT, 95 | }; 96 | 97 | struct j1939_filter { 98 | name_t name; 99 | name_t name_mask; 100 | pgn_t pgn; 101 | pgn_t pgn_mask; 102 | __u8 addr; 103 | __u8 addr_mask; 104 | }; 105 | 106 | #define J1939_FILTER_MAX 512 /* maximum number of j1939_filter set via setsockopt() */ 107 | 108 | #endif /* !_UAPI_CAN_J1939_H_ */ 109 | -------------------------------------------------------------------------------- /core/src/include/linux/can/raw.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 | /* 3 | * linux/can/raw.h 4 | * 5 | * Definitions for raw CAN sockets 6 | * 7 | * Authors: Oliver Hartkopp 8 | * Urs Thuermann 9 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions 14 | * are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of Volkswagen nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * Alternatively, provided that this notice is retained in full, this 25 | * software may be distributed under the terms of the GNU General 26 | * Public License ("GPL") version 2, in which case the provisions of the 27 | * GPL apply INSTEAD OF those given above. 28 | * 29 | * The provided data structures and external interfaces from this code 30 | * are not restricted to be used by modules with a GPL compatible license. 31 | * 32 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 35 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 39 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 40 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 41 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 42 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 43 | * DAMAGE. 44 | */ 45 | 46 | #ifndef _UAPI_CAN_RAW_H 47 | #define _UAPI_CAN_RAW_H 48 | 49 | #include 50 | 51 | #define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW) 52 | #define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */ 53 | 54 | enum { 55 | SCM_CAN_RAW_ERRQUEUE = 1, 56 | }; 57 | 58 | /* for socket options affecting the socket (not the global system) */ 59 | 60 | enum { 61 | CAN_RAW_FILTER = 1, /* set 0 .. n can_filter(s) */ 62 | CAN_RAW_ERR_FILTER, /* set filter for error frames */ 63 | CAN_RAW_LOOPBACK, /* local loopback (default:on) */ 64 | CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */ 65 | CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ 66 | CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */ 67 | CAN_RAW_XL_FRAMES, /* allow CAN XL frames (default:off) */ 68 | }; 69 | 70 | #endif /* !_UAPI_CAN_RAW_H */ 71 | -------------------------------------------------------------------------------- /core/src/main/c/common.c: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | #include "common.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | int bind_tp_address(int sock, uint32_t interface, uint32_t rx, uint32_t tx) { 35 | struct sockaddr_can addr = {0}; 36 | addr.can_family = AF_CAN; 37 | addr.can_ifindex = (int) interface; 38 | addr.can_addr.tp.rx_id = rx; 39 | addr.can_addr.tp.tx_id = tx; 40 | 41 | return bind(sock, (const struct sockaddr *) &addr, sizeof(addr)); 42 | } 43 | 44 | int connect_tp_address(int sock, uint32_t interface, uint32_t rx, uint32_t tx) { 45 | struct sockaddr_can addr = {0}; 46 | addr.can_family = AF_CAN; 47 | addr.can_ifindex = (int) interface; 48 | addr.can_addr.tp.rx_id = rx; 49 | addr.can_addr.tp.tx_id = tx; 50 | 51 | return connect(sock, (const struct sockaddr *) &addr, sizeof(addr)); 52 | } 53 | 54 | int set_boolean_opt(int sock, int level, int opt, bool enable) { 55 | int enabled = enable ? 1 : 0; 56 | socklen_t len = sizeof(enabled); 57 | 58 | return setsockopt(sock, level, opt, &enabled, len); 59 | } 60 | 61 | int get_boolean_opt(int sock, int level, int opt) { 62 | int enabled; 63 | socklen_t len = sizeof(enabled); 64 | 65 | int result = getsockopt(sock, level, opt, &enabled, &len); 66 | if (result == -1) { 67 | return -1; 68 | } 69 | return enabled; 70 | } 71 | 72 | void throw_native_exception(JNIEnv *env, char *msg) { 73 | // It is necessary to get the errno before any Java or JNI function is called, as it 74 | // may become changed due to the VM operations. 75 | int errorNumber = errno; 76 | 77 | throw_tel_schich_javacan_platform_linux_LinuxNativeOperationException_cstr(env, msg, errorNumber, strerror(errorNumber)); 78 | } 79 | 80 | void parse_timestamp(struct cmsghdr *cmsg, jlong* software_seconds, jlong* software_nanos, jlong* hardware_seconds, jlong* hardware_nanos) { 81 | struct timeval tv; 82 | struct timespec ts; 83 | struct scm_timestamping timestamping; 84 | if (cmsg->cmsg_level == SOL_SOCKET) { 85 | switch (cmsg->cmsg_type) { 86 | case SO_TIMESTAMP: 87 | memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv)); 88 | *software_seconds = tv.tv_sec; 89 | *software_nanos = tv.tv_usec * 1000; 90 | break; 91 | case SO_TIMESTAMPNS: 92 | memcpy(&ts, CMSG_DATA(cmsg), sizeof(ts)); 93 | *software_seconds = ts.tv_sec; 94 | *software_nanos = ts.tv_nsec; 95 | break; 96 | case SO_TIMESTAMPING: 97 | memcpy(×tamping, CMSG_DATA(cmsg), sizeof(timestamping)); 98 | *software_seconds = timestamping.ts[0].tv_sec; 99 | *software_nanos = timestamping.ts[0].tv_nsec; 100 | *hardware_seconds = timestamping.ts[2].tv_sec; 101 | *hardware_nanos = timestamping.ts[2].tv_nsec; 102 | break; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /core/src/main/c/common.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | #ifndef _JAVACAN_HELPERS 24 | #define _JAVACAN_HELPERS 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define MICROS_PER_SECOND 1000000 32 | 33 | int bind_tp_address(int sock, uint32_t interface, uint32_t rx, uint32_t tx); 34 | int connect_tp_address(int sock, uint32_t interface, uint32_t rx, uint32_t tx); 35 | int set_boolean_opt(int sock, int level, int opt, bool enable); 36 | int get_boolean_opt(int sock, int level, int opt); 37 | void throw_native_exception(JNIEnv *env, char *msg); 38 | void parse_timestamp(struct cmsghdr *cmsg, jlong* software_seconds, jlong* software_nanos, jlong* hardware_seconds, jlong* hardware_nanos); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /core/src/main/c/javacan_bcm.c: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | #include "common.h" 24 | #include 25 | #include 26 | 27 | inline int create_can_bcm_socket() { 28 | return socket(PF_CAN, SOCK_DGRAM, CAN_BCM); 29 | } 30 | 31 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_SocketCAN_createBcmSocket(JNIEnv *env, jclass class) { 32 | jint fd = create_can_bcm_socket(); 33 | if (fd == -1) { 34 | throw_native_exception(env, "Unable to create BCM socket"); 35 | } 36 | return fd; 37 | } 38 | 39 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_BcmMessage_getHeaderSize(JNIEnv *env, jclass class) { 40 | return sizeof(struct bcm_msg_head); 41 | } 42 | 43 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_BcmMessage_getOffsetFlags(JNIEnv *env, jclass class) { 44 | return offsetof(struct bcm_msg_head, flags); 45 | } 46 | 47 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_BcmMessage_getOffsetCount(JNIEnv *env, jclass class) { 48 | return offsetof(struct bcm_msg_head, count); 49 | } 50 | 51 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_BcmMessage_getOffsetIval1Sec(JNIEnv *env, jclass class) { 52 | return offsetof(struct bcm_msg_head, ival1) + offsetof(struct bcm_timeval, tv_sec); 53 | } 54 | 55 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_BcmMessage_getOffsetIval1Usec(JNIEnv *env, jclass class) { 56 | return offsetof(struct bcm_msg_head, ival1) + offsetof(struct bcm_timeval, tv_usec); 57 | } 58 | 59 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_BcmMessage_getOffsetIval2Sec(JNIEnv *env, jclass class) { 60 | return offsetof(struct bcm_msg_head, ival2) + offsetof(struct bcm_timeval, tv_sec); 61 | } 62 | 63 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_BcmMessage_getOffsetIval2Usec(JNIEnv *env, jclass class) { 64 | return offsetof(struct bcm_msg_head, ival2) + offsetof(struct bcm_timeval, tv_usec); 65 | } 66 | 67 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_BcmMessage_getOffsetCanID(JNIEnv *env, jclass class) { 68 | return offsetof(struct bcm_msg_head, can_id); 69 | } 70 | 71 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_BcmMessage_getOffsetNFrames(JNIEnv *env, jclass class) { 72 | return offsetof(struct bcm_msg_head, nframes); 73 | } 74 | 75 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_BcmMessage_getOffsetFrames(JNIEnv *env, jclass class) { 76 | return offsetof(struct bcm_msg_head, frames); 77 | } 78 | -------------------------------------------------------------------------------- /core/src/main/c/javacan_bufferhelper.c: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | #include 24 | 25 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_util_BufferHelper_getLongSize(JNIEnv *env, jclass class) { 26 | return sizeof(long); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /core/src/main/c/javacan_networkdevice.c: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | #include "common.h" 24 | #include 25 | #include 26 | 27 | JNIEXPORT jint JNICALL Java_tel_schich_javacan_platform_linux_LinuxNetworkDevice_findDeviceIndexByName(JNIEnv *env, jclass clazz, jstring interfaceName) { 28 | const char* ifname = (*env)->GetStringUTFChars(env, interfaceName, NULL); 29 | if (ifname == NULL) { 30 | throw_native_exception(env, "failed to get c string from java string"); 31 | return -1; 32 | } 33 | unsigned int ifindex = if_nametoindex(ifname); 34 | if (ifindex == 0) { 35 | const char* prefix = "Failed to resolve the interface: "; 36 | char message[strlen(prefix) + strlen(ifname) + 1]; 37 | message[0] = 0; 38 | strcat((char *) &message, prefix); 39 | strcat((char *) &message, ifname); 40 | throw_native_exception(env, message); 41 | } 42 | (*env)->ReleaseStringUTFChars(env, interfaceName, ifname); 43 | return (jint)ifindex; 44 | } 45 | ; 46 | 47 | JNIEXPORT jstring JNICALL Java_tel_schich_javacan_platform_linux_LinuxNetworkDevice_findDeviceNameByIndex(JNIEnv *env, jclass clazz, jint index) { 48 | char interface_name[IF_NAMESIZE]; 49 | if (if_indextoname(index, interface_name) == NULL) { 50 | return NULL; 51 | } 52 | return (*env)->NewStringUTF(env, interface_name); 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/BcmFlag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import java.util.EnumSet; 26 | import java.util.Set; 27 | 28 | /** 29 | * The BcmFlag enum represent the Broadcast Manager message flags. When sending a message to the 30 | * broadcast manager, the ‘flags’ element influences the behavior. 31 | * 32 | * @see 33 | * Kernel CAN documentation: BCM message flags 34 | */ 35 | public enum BcmFlag { 36 | 37 | /** 38 | * Set the values of {@link BcmMessage#getInterval1() interval1}, {@link BcmMessage#getInterval2() 39 | * interval2} and {@link BcmMessage#getCount() count}. 40 | */ 41 | SETTIMER(0x0001), 42 | 43 | /** 44 | * Start the timer with the actual values of {@link BcmMessage#getInterval1() interval1}, 45 | * {@link BcmMessage#getInterval2() interval2} and {@link BcmMessage#getCount() count}. Starting the 46 | * timer leads simultaneously to emit a CAN frame. 47 | */ 48 | STARTTIMER(0x0002), 49 | 50 | /** 51 | * Create the message {@link BcmOpcode#TX_EXPIRED} when count expires. 52 | */ 53 | TX_COUNTEVT(0x0004), 54 | 55 | /** 56 | * A change of data by the process is emitted immediately. 57 | */ 58 | TX_ANNOUNCE(0x0008), 59 | 60 | /** 61 | * Copies the CAN ID from the message header to each subsequent frame in 62 | * {@link BcmMessage#getFrames() frames}. This is intended as usage simplification. For TX tasks the 63 | * unique CAN ID from the message header may differ from the CAN ID(s) stored for transmission in 64 | * the subsequent CAN frame(s). 65 | */ 66 | TX_CP_CAN_ID(0x0010), 67 | 68 | /** 69 | * Filter by CAN ID alone, no frames required ({@link BcmMessage#getFrameCount() frameCount==0}). 70 | */ 71 | RX_FILTER_ID(0x0020), 72 | 73 | /** 74 | * A change of the data-length-code (DLC) leads to a {@link BcmOpcode#RX_CHANGED}. 75 | */ 76 | RX_CHECK_DLC(0x0040), 77 | 78 | /** 79 | * Prevent automatically starting the timeout monitor. 80 | */ 81 | RX_NO_AUTOTIMER(0x0080), 82 | 83 | /** 84 | * If passed at {@link BcmOpcode#RX_SETUP} and a receive timeout occurred, a 85 | * {@link BcmOpcode#RX_CHANGED} message will be generated when the (cyclic) receive restarts. 86 | */ 87 | RX_ANNOUNCE_RESUME(0x0100), 88 | 89 | /** 90 | * Reset the index for the multiple frame transmission. 91 | */ 92 | TX_RESET_MULTI_IDX(0x0200), 93 | 94 | /** 95 | * Send reply for RTR-request (placed in {@code op->frames[0]}). 96 | */ 97 | RX_RTR_FRAME(0x0400), 98 | 99 | /** 100 | * Indicate that the subsequent frames of the message are defined as {@link CanFrame#isFDFrame() FD 101 | * frames}. 102 | */ 103 | CAN_FD_FRAME(0x0800); 104 | 105 | private final int bit; 106 | 107 | BcmFlag(int bit) { 108 | this.bit = bit; 109 | } 110 | 111 | /** 112 | * Get the Java representation for the native flags. 113 | * 114 | * @param nativeFlags from CAN socket 115 | * @return the set of flags 116 | */ 117 | public static Set fromNative(int nativeFlags) { 118 | EnumSet flags = EnumSet.noneOf(BcmFlag.class); 119 | for (BcmFlag flag : values()) { 120 | if ((flag.bit & nativeFlags) != 0) { 121 | flags.add(flag); 122 | } 123 | } 124 | return flags; 125 | } 126 | 127 | /** 128 | * Get the native representation for the given set of flags. 129 | * 130 | * @param flags the flags to convert 131 | * @return an integer bitmask 132 | */ 133 | public static int toNative(Set flags) { 134 | int nativeFlags = 0; 135 | for (BcmFlag flag : flags) { 136 | nativeFlags |= flag.bit; 137 | } 138 | return nativeFlags; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/BcmOpcode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | /** 26 | * The BcmOpcode defines the operation for the broadcast manager to carry out, or details the 27 | * broadcast managers response to several events, including user requests. 28 | *

29 | * This enum provides a Java representation of the opcodes defined in the Linux 30 | * {@code can/bcm.h include}. 31 | * 32 | * @see 33 | * Kernel CAN documentation: BCM operations 34 | */ 35 | public enum BcmOpcode { 36 | /** 37 | * Create a (cyclic) transmission task. 38 | */ 39 | TX_SETUP(1), 40 | 41 | /** 42 | * Remove a (cyclic) transmission task. 43 | */ 44 | TX_DELETE(2), 45 | 46 | /** 47 | * Read properties of (cyclic) transmission task. 48 | */ 49 | TX_READ(3), 50 | 51 | /** 52 | * Send one CAN frame. 53 | */ 54 | TX_SEND(4), 55 | 56 | /** 57 | * Create RX content filter subscription. 58 | */ 59 | RX_SETUP(5), 60 | 61 | /** 62 | * Remove RX content filter subscription. 63 | */ 64 | RX_DELETE(6), 65 | 66 | /** 67 | * Read properties of RX content filter subscription. 68 | */ 69 | RX_READ(7), 70 | 71 | /** 72 | * Reply to TX_READ request. 73 | */ 74 | TX_STATUS(8), 75 | 76 | /** 77 | * Notification on performed transmissions. ({@link BcmMessage#getCount() count==0}) 78 | */ 79 | TX_EXPIRED(9), 80 | 81 | /** 82 | * Reply to RX_READ request. 83 | */ 84 | RX_STATUS(10), 85 | 86 | /** 87 | * Cyclic message is absent. 88 | */ 89 | RX_TIMEOUT(11), 90 | 91 | /** 92 | * Updated CAN frame. (detected content change) 93 | */ 94 | RX_CHANGED(12); 95 | 96 | /** 97 | * The native representation as given in {@code bcm.h} 98 | */ 99 | public final int nativeOpcode; 100 | 101 | BcmOpcode(int nativeOpcode) { 102 | this.nativeOpcode = nativeOpcode; 103 | } 104 | 105 | /** 106 | * Get the Java representation for the native op-code. 107 | * 108 | * @param nativeOpcode from the CAN socket 109 | * @return the opcode 110 | * @throws IllegalArgumentException on an unknown op-code 111 | */ 112 | public static BcmOpcode fromNative(int nativeOpcode) { 113 | for (BcmOpcode opcode : values()) { 114 | if (nativeOpcode == opcode.nativeOpcode) { 115 | return opcode; 116 | } 117 | } 118 | throw new IllegalArgumentException("unknown BCM op-code: " + nativeOpcode); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/CanFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import java.util.Objects; 26 | 27 | import static tel.schich.javacan.CanId.ERR_FLAG; 28 | 29 | /** 30 | * This class represents a native CAN filter. 31 | */ 32 | public class CanFilter { 33 | 34 | /** 35 | * This bit inverts the filter. 36 | */ 37 | public static final int INVERTED_BIT = ERR_FLAG; 38 | 39 | /** 40 | * This predefined filter accepts any CAN ID. 41 | */ 42 | public static final CanFilter ANY = new CanFilter(0, 0); 43 | 44 | /** 45 | * This predefined filter accepts no CAN ID at all. 46 | */ 47 | public static final CanFilter NONE = new CanFilter(0); 48 | 49 | /** 50 | * The size of the native representation of a {@link tel.schich.javacan.CanFilter}. 51 | */ 52 | public static final int BYTES = Integer.BYTES * 2; 53 | 54 | /** 55 | * This filter mask can be used to match a CAN ID exactly. 56 | */ 57 | public static final int EXACT = -1; 58 | 59 | private final int id; 60 | private final int mask; 61 | 62 | /** 63 | * Creates a filter to exactly match the given ID. 64 | * 65 | * @param id the CAN ID to match 66 | */ 67 | public CanFilter(int id) { 68 | this(id, EXACT); 69 | } 70 | 71 | /** 72 | * Creates a filter with the given CAN ID and mask. 73 | * 74 | * @param id The CAN ID to match 75 | * @param mask the mask to match 76 | */ 77 | public CanFilter(int id, int mask) { 78 | this.id = id; 79 | this.mask = mask & ~ERR_FLAG; 80 | } 81 | 82 | /** 83 | * Gets the CAN ID to be matched by this filter. 84 | * 85 | * @return the CAN ID 86 | */ 87 | public int getId() { 88 | return id; 89 | } 90 | 91 | /** 92 | * Gets the mask to be used to match the CAN ID. 93 | * 94 | * @return the mask 95 | */ 96 | public int getMask() { 97 | return mask; 98 | } 99 | 100 | /** 101 | * Checks if this filter is inverted. 102 | * 103 | * @return true if this filter is inverted 104 | */ 105 | public boolean isInverted() { 106 | return (id & INVERTED_BIT) > 0; 107 | } 108 | 109 | /** 110 | * Checks if this filter matches its CAN ID exactly. 111 | * 112 | * @return true if this filter is exact 113 | */ 114 | public boolean isExact() { 115 | return mask == EXACT; 116 | } 117 | 118 | /** 119 | * Matches this filter against the given CAN ID. 120 | * This method is implemented exactly like the kernel implements the filtering. 121 | * 122 | * @param id the CAN ID to match 123 | * @return true if the given CAN ID would be accepted by this filter 124 | */ 125 | public boolean matchId(int id) { 126 | return (this.id & mask) == (id & mask); 127 | } 128 | 129 | @Override 130 | public boolean equals(Object o) { 131 | if (this == o) 132 | return true; 133 | if (o == null || getClass() != o.getClass()) 134 | return false; 135 | CanFilter canFilter = (CanFilter) o; 136 | return id == canFilter.id && mask == canFilter.mask; 137 | } 138 | 139 | @Override 140 | public int hashCode() { 141 | return Objects.hash(id, mask); 142 | } 143 | 144 | @Override 145 | public String toString() { 146 | return (isInverted() ? "~" : "") + String.format("CanFilter(id=%X, mask=%X)", id, mask); 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/CanId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | /** 26 | * This helper class provides methods and constants and work with the kernel's CAN IDs which include various metadata 27 | * bits. 28 | */ 29 | public class CanId { 30 | /** 31 | * This mask matches the extended frame format (EFF) flag bit. 32 | */ 33 | public static final int EFF_FLAG = 0b10000000_00000000_00000000_00000000; 34 | 35 | /** 36 | * This mask matches the remote transmission request flag bit. 37 | */ 38 | public static final int RTR_FLAG = 0b01000000_00000000_00000000_00000000; 39 | 40 | /** 41 | * This mask matches the error flag bit. 42 | */ 43 | public static final int ERR_FLAG = 0b00100000_00000000_00000000_00000000; 44 | 45 | /** 46 | * This mask matches the standard frame format (SFF) address bits (the 11 least significant bits). 47 | */ 48 | public static final int SFF_MASK = 0b00000000_00000000_00000111_11111111; 49 | 50 | /** 51 | * This mask matches the extended frame format (EFF) address bits (the 29 least significant bits). 52 | */ 53 | public static final int EFF_MASK = 0b00011111_11111111_11111111_11111111; 54 | 55 | /** 56 | * This mask matches the error bits (the 29 least significant bits). 57 | */ 58 | public static final int ERR_MASK = EFF_MASK; 59 | 60 | private CanId() {} 61 | 62 | /** 63 | * Returns the actual CAN ID from the kernel ID (either 11 bits for SFF or 29 bits for EFF IDs). 64 | * 65 | * @param id the kernel CAN ID 66 | * @return the actual CAN ID 67 | */ 68 | public static int getId(int id) { 69 | return (isExtended(id) ? (id & EFF_MASK) : (id & SFF_MASK)); 70 | } 71 | 72 | /** 73 | * Checks if this CAN ID uses the extended frame format. 74 | * 75 | * @param id the kernel CAN ID 76 | * @return true if the ID uses EFF 77 | */ 78 | public static boolean isExtended(int id) { 79 | return (id & EFF_FLAG) != 0; 80 | } 81 | 82 | /** 83 | * Checks if this CAN ID is an error. 84 | * 85 | * @param id the kernel CAN ID 86 | * @return true if the ID is an error 87 | */ 88 | public static boolean isError(int id) { 89 | return (id & ERR_FLAG) != 0; 90 | } 91 | 92 | /** 93 | * Returns the error code from the given ID. If this ID is not an error ID, the result is undefined. 94 | * 95 | * @param id the kernel CAN ID 96 | * @return the error bits, undefined if not an error ID 97 | */ 98 | public static int getError(int id) { 99 | return (id & ERR_MASK); 100 | } 101 | 102 | /** 103 | * Checks if this CAN ID is a remote-transmission-request ID. 104 | * 105 | * @param id the kernel CAN ID. 106 | * @return true if it is an RTR ID 107 | */ 108 | public static boolean isRemoteTransmissionRequest(int id) { 109 | return (id & RTR_FLAG) != 0; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/ImmutableJ1939Address.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import tel.schich.javacan.platform.linux.LinuxNetworkDevice; 26 | 27 | import java.util.Objects; 28 | 29 | /** 30 | * This class represents an immutable J1939 address, not suitable for native operations. 31 | */ 32 | public final class ImmutableJ1939Address implements J1939Address { 33 | private final LinuxNetworkDevice device; 34 | private final long name; 35 | private final int parameterGroupNumber; 36 | private final byte address; 37 | 38 | public ImmutableJ1939Address(NetworkDevice device, long name, int parameterGroupNumber, byte address) { 39 | if (!(device instanceof LinuxNetworkDevice)) { 40 | throw new IllegalArgumentException("Unsupported network device given!"); 41 | } 42 | this.device = (LinuxNetworkDevice) device; 43 | this.name = name; 44 | this.parameterGroupNumber = parameterGroupNumber; 45 | this.address = address; 46 | } 47 | 48 | public ImmutableJ1939Address(NetworkDevice device) { 49 | this(device, NO_NAME, NO_PGN, NO_ADDR); 50 | } 51 | 52 | @Override 53 | public LinuxNetworkDevice getDevice() { 54 | return device; 55 | } 56 | 57 | @Override 58 | public long getName() { 59 | return name; 60 | } 61 | 62 | @Override 63 | public int getParameterGroupNumber() { 64 | return parameterGroupNumber; 65 | } 66 | 67 | @Override 68 | public byte getAddress() { 69 | return address; 70 | } 71 | 72 | @Override 73 | public boolean equals(Object o) { 74 | if (this == o) return true; 75 | if (o == null || getClass() != o.getClass()) return false; 76 | ImmutableJ1939Address that = (ImmutableJ1939Address) o; 77 | return name == that.name && parameterGroupNumber == that.parameterGroupNumber && address == that.address && Objects.equals(device, that.device); 78 | } 79 | 80 | @Override 81 | public ImmutableJ1939Address copy() { 82 | return this; 83 | } 84 | 85 | @Override 86 | public int hashCode() { 87 | return Objects.hash(device, name, parameterGroupNumber, address); 88 | } 89 | 90 | @Override 91 | public String toString() { 92 | return "J1939Address{" + 93 | "device=" + device + 94 | ", name=" + name + 95 | ", parameterGroupNumber=" + parameterGroupNumber + 96 | ", address=" + address + 97 | '}'; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/ImmutableJ1939ReceiveMessageHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import java.time.Instant; 26 | import java.util.Objects; 27 | 28 | /** 29 | * This class represents immutable message headers included with J1939 messages, not suitable for native operations. 30 | */ 31 | public final class ImmutableJ1939ReceiveMessageHeader implements J1939ReceiveMessageHeader { 32 | private final ImmutableJ1939Address sourceAddress; 33 | private final Instant softwareTimestamp; 34 | private final Instant hardwareTimestamp; 35 | private final byte destinationAddress; 36 | private final long destinationName; 37 | private final byte priority; 38 | 39 | // TODO add support for SCM_J1939_ERRQUEUE 40 | 41 | public ImmutableJ1939ReceiveMessageHeader(ImmutableJ1939Address sourceAddress, Instant softwareTimestamp, Instant hardwareTimestamp, byte destinationAddress, long destinationName, byte priority) { 42 | this.sourceAddress = sourceAddress; 43 | this.softwareTimestamp = softwareTimestamp; 44 | this.hardwareTimestamp = hardwareTimestamp; 45 | this.destinationAddress = destinationAddress; 46 | this.destinationName = destinationName; 47 | this.priority = priority; 48 | } 49 | 50 | @Override 51 | public ImmutableJ1939Address getSourceAddress() { 52 | return sourceAddress; 53 | } 54 | 55 | @Override 56 | public Instant getSoftwareTimestamp() { 57 | return softwareTimestamp; 58 | } 59 | 60 | @Override 61 | public Instant getHardwareTimestamp() { 62 | return hardwareTimestamp; 63 | } 64 | 65 | @Override 66 | public byte getDestinationAddress() { 67 | return destinationAddress; 68 | } 69 | 70 | @Override 71 | public long getDestinationName() { 72 | return destinationName; 73 | } 74 | 75 | @Override 76 | public byte getPriority() { 77 | return priority; 78 | } 79 | 80 | @Override 81 | public ImmutableJ1939ReceiveMessageHeader copy() { 82 | return this; 83 | } 84 | 85 | @Override 86 | public boolean equals(Object o) { 87 | if (this == o) return true; 88 | if (o == null || getClass() != o.getClass()) return false; 89 | ImmutableJ1939ReceiveMessageHeader header = (ImmutableJ1939ReceiveMessageHeader) o; 90 | return destinationAddress == header.destinationAddress && 91 | destinationName == header.destinationName && 92 | priority == header.priority && 93 | Objects.equals(sourceAddress, header.sourceAddress) && 94 | Objects.equals(softwareTimestamp, header.softwareTimestamp) && 95 | Objects.equals(hardwareTimestamp, header.hardwareTimestamp); 96 | } 97 | 98 | @Override 99 | public int hashCode() { 100 | return Objects.hash(sourceAddress, softwareTimestamp, hardwareTimestamp, destinationAddress, destinationName, priority); 101 | } 102 | 103 | @Override 104 | public String toString() { 105 | return "ImmutableJ1939ReceiveMessageHeader{" + 106 | "sourceAddress=" + sourceAddress + 107 | ", softwareTimestamp=" + softwareTimestamp + 108 | ", hardwareTimestamp=" + hardwareTimestamp + 109 | ", destinationAddress=" + destinationAddress + 110 | ", destinationName=" + destinationName + 111 | ", priority=" + priority + 112 | '}'; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/ImmutableRawReceiveMessageHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import tel.schich.javacan.platform.linux.LinuxNetworkDevice; 26 | 27 | import java.time.Instant; 28 | import java.util.Objects; 29 | 30 | /** 31 | * This class represents immutable message headers included with RAW messages, not suitable for native operations. 32 | */ 33 | public final class ImmutableRawReceiveMessageHeader implements RawReceiveMessageHeader { 34 | 35 | private final LinuxNetworkDevice device; 36 | private final int dropCount; 37 | private final Instant softwareTimestamp; 38 | private final Instant hardwareTimestamp; 39 | 40 | public ImmutableRawReceiveMessageHeader(LinuxNetworkDevice device, int dropCount, Instant softwareTimestamp, Instant hardwareTimestamp) { 41 | this.device = device; 42 | this.dropCount = dropCount; 43 | this.softwareTimestamp = softwareTimestamp; 44 | this.hardwareTimestamp = hardwareTimestamp; 45 | } 46 | 47 | @Override 48 | public LinuxNetworkDevice getDevice() { 49 | return device; 50 | } 51 | 52 | @Override 53 | public int getDropCount() { 54 | return dropCount; 55 | } 56 | 57 | @Override 58 | public Instant getSoftwareTimestamp() { 59 | return softwareTimestamp; 60 | } 61 | 62 | @Override 63 | public Instant getHardwareTimestamp() { 64 | return hardwareTimestamp; 65 | } 66 | 67 | @Override 68 | public ImmutableRawReceiveMessageHeader copy() { 69 | return this; 70 | } 71 | 72 | @Override 73 | public boolean equals(Object o) { 74 | if (this == o) return true; 75 | if (o == null || getClass() != o.getClass()) return false; 76 | ImmutableRawReceiveMessageHeader that = (ImmutableRawReceiveMessageHeader) o; 77 | return dropCount == that.dropCount && Objects.equals(device, that.device) && Objects.equals(softwareTimestamp, that.softwareTimestamp) && Objects.equals(hardwareTimestamp, that.hardwareTimestamp); 78 | } 79 | 80 | @Override 81 | public int hashCode() { 82 | return Objects.hash(device, dropCount, softwareTimestamp, hardwareTimestamp); 83 | } 84 | 85 | @Override 86 | public String toString() { 87 | return "ImmutableRawReceiveMessageHeader{" + 88 | "device=" + device + 89 | ", dropCount=" + dropCount + 90 | ", softwareTimestamp=" + softwareTimestamp + 91 | ", hardwareTimestamp=" + hardwareTimestamp + 92 | '}'; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/IsotpCanChannel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import java.io.IOException; 26 | import java.nio.ByteBuffer; 27 | 28 | /** 29 | * This is the base class for ISOTP channels providing a minimal interface to send and receive messages. 30 | */ 31 | public abstract class IsotpCanChannel extends AbstractCanChannel { 32 | /** 33 | * The maximum message length. 34 | */ 35 | // TODO this might actually depend on whether FD or non-FD frames are being used 36 | public static final int MAX_MESSAGE_LENGTH = 4095; 37 | 38 | /** 39 | * Creates a new channel given the {@link java.nio.channels.spi.SelectorProvider} and the socket file descriptor. 40 | * 41 | * @param sock the socket file descriptor 42 | */ 43 | public IsotpCanChannel(int sock) { 44 | super(sock); 45 | } 46 | 47 | /** 48 | * Binds this channel to the given {@link tel.schich.javacan.NetworkDevice} and 49 | * {@link tel.schich.javacan.IsotpSocketAddress}es. 50 | * 51 | * @see bind man page 52 | * @param device the device to bind to 53 | * @param rx the receiving address to bind to 54 | * @param tx the transmitting address to bind to 55 | * @return fluent interface 56 | * @throws IOException if the native calls fail 57 | * @throws java.nio.channels.AlreadyBoundException if this channel has already been bound 58 | */ 59 | public abstract IsotpCanChannel bind(NetworkDevice device, IsotpSocketAddress rx, IsotpSocketAddress tx) throws IOException; 60 | 61 | /** 62 | * Returns the receiving {@link tel.schich.javacan.IsotpSocketAddress} this channel has been bound to. 63 | * 64 | * @return the receiving address 65 | * @throws java.nio.channels.NotYetBoundException if the channel has not been bound yet 66 | */ 67 | public abstract IsotpSocketAddress getRxAddress(); 68 | 69 | /** 70 | * Returns the transmitting {@link tel.schich.javacan.IsotpSocketAddress} this channel has been bound to. 71 | * 72 | * @return the transmitting address 73 | * @throws java.nio.channels.NotYetBoundException if the channel has not been bound yet 74 | */ 75 | public abstract IsotpSocketAddress getTxAddress(); 76 | 77 | /** 78 | * Reads a message from the socket into the given {@link java.nio.ByteBuffer}. Buffer position and limit will be 79 | * respected and will be updated according to the data that has been read. 80 | * If this channel is in blocking mode, this call might block indefinitely. 81 | * 82 | * @see read man page 83 | * @param buffer the destination buffer 84 | * @return the number of bytes that have been read 85 | * @throws IOException if the native calls fail 86 | */ 87 | public abstract int read(ByteBuffer buffer) throws IOException; 88 | 89 | /** 90 | * Writes a message from the given {@link java.nio.ByteBuffer} into this socket. Buffer position and limit will be 91 | * respected and will be updated according to the data that has been written. 92 | * If this channel is in blocking mode, this call might block indefinitely. 93 | * 94 | * @see write man page 95 | * @param buffer the source buffer 96 | * @return the number of bytes that have been written 97 | * @throws IOException if the native calls fail 98 | */ 99 | public abstract int write(ByteBuffer buffer) throws IOException; 100 | 101 | /** 102 | * Allocates a new direct {@link java.nio.ByteBuffer} that can hold any message. 103 | * 104 | * @return the newly allocated buffer 105 | */ 106 | public static ByteBuffer allocateSufficientMemory() { 107 | return JavaCAN.allocateUnordered(MAX_MESSAGE_LENGTH + 1); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/IsotpCanChannelImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import java.io.IOException; 26 | import java.nio.ByteBuffer; 27 | import java.nio.channels.AlreadyBoundException; 28 | import java.nio.channels.NotYetBoundException; 29 | 30 | import org.eclipse.jdt.annotation.Nullable; 31 | import tel.schich.javacan.platform.linux.LinuxNativeOperationException; 32 | import tel.schich.javacan.platform.linux.LinuxNetworkDevice; 33 | 34 | final class IsotpCanChannelImpl extends IsotpCanChannel { 35 | 36 | @Nullable 37 | private NetworkDevice device; 38 | @Nullable 39 | private IsotpSocketAddress rx; 40 | @Nullable 41 | private IsotpSocketAddress tx; 42 | 43 | public IsotpCanChannelImpl(int sock) { 44 | super(sock); 45 | } 46 | 47 | @Override 48 | public synchronized IsotpCanChannel bind(NetworkDevice device, IsotpSocketAddress rx, IsotpSocketAddress tx) throws IOException { 49 | if (isBound()) { 50 | throw new AlreadyBoundException(); 51 | } 52 | if (!(device instanceof LinuxNetworkDevice)) { 53 | throw new IllegalArgumentException("Unsupported network device given!"); 54 | } 55 | try { 56 | SocketCAN.bindTpAddress(getSocket(), ((LinuxNetworkDevice) device).getIndex(), rx.getId(), tx.getId()); 57 | } catch (LinuxNativeOperationException e) { 58 | throw checkForClosedChannel(e); 59 | } 60 | this.device = device; 61 | this.rx = rx; 62 | this.tx = tx; 63 | return this; 64 | } 65 | 66 | @Override 67 | public synchronized boolean isBound() { 68 | return this.device != null; 69 | } 70 | 71 | @Override 72 | public synchronized NetworkDevice getDevice() { 73 | if (!isBound()) { 74 | throw new NotYetBoundException(); 75 | } 76 | return this.device; 77 | } 78 | 79 | @Override 80 | public synchronized IsotpSocketAddress getRxAddress() { 81 | if (!isBound() || this.rx == null) { 82 | throw new NotYetBoundException(); 83 | } 84 | return this.rx; 85 | } 86 | 87 | @Override 88 | public synchronized IsotpSocketAddress getTxAddress() { 89 | if (!isBound() || this.tx == null) { 90 | throw new NotYetBoundException(); 91 | } 92 | return this.tx; 93 | } 94 | 95 | @Override 96 | public int read(ByteBuffer buffer) throws IOException { 97 | return (int) readSocket(buffer); 98 | } 99 | 100 | @Override 101 | public int write(ByteBuffer buffer) throws IOException { 102 | if (buffer.remaining() > MAX_MESSAGE_LENGTH) { 103 | throw new IllegalArgumentException("Message too long!"); 104 | } 105 | long bytesRead = writeSocket(buffer); 106 | return (int) bytesRead; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/IsotpFlowControlOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import tel.schich.jniaccess.JNIAccess; 26 | 27 | import java.util.Objects; 28 | 29 | /** 30 | * This class represents ISOTP's flow control options. 31 | */ 32 | public class IsotpFlowControlOptions { 33 | 34 | public static final IsotpFlowControlOptions DEFAULT = new IsotpFlowControlOptions( 35 | (byte) 0, 36 | (byte) 0x00, 37 | (byte) 0 38 | ); 39 | 40 | private final byte blockSize; 41 | private final byte minimumSeparationTime; 42 | private final byte maximumWaitFrameTransmission; 43 | 44 | @JNIAccess 45 | public IsotpFlowControlOptions(byte blockSize, byte minimumSeparationTime, byte maximumWaitFrameTransmission) { 46 | this.blockSize = blockSize; 47 | this.minimumSeparationTime = minimumSeparationTime; 48 | this.maximumWaitFrameTransmission = maximumWaitFrameTransmission; 49 | } 50 | 51 | public byte getBlockSize() { 52 | return blockSize; 53 | } 54 | 55 | public IsotpFlowControlOptions withBlockSize(byte blockSize) { 56 | return new IsotpFlowControlOptions( 57 | blockSize, 58 | minimumSeparationTime, 59 | maximumWaitFrameTransmission 60 | ); 61 | } 62 | 63 | public IsotpFlowControlOptions withBlockSize(int blockSize) { 64 | return withBlockSize((byte) blockSize); 65 | } 66 | 67 | public byte getMinimumSeparationTime() { 68 | return minimumSeparationTime; 69 | } 70 | 71 | public IsotpFlowControlOptions withMinimumSeparationTime(byte minimumSeparationTime) { 72 | return new IsotpFlowControlOptions( 73 | blockSize, 74 | minimumSeparationTime, 75 | maximumWaitFrameTransmission 76 | ); 77 | } 78 | 79 | public IsotpFlowControlOptions withMinimumSeparationTime(int minimumSeparationTime) { 80 | return withMinimumSeparationTime((byte) minimumSeparationTime); 81 | } 82 | 83 | public byte getMaximumWaitFrameTransmission() { 84 | return maximumWaitFrameTransmission; 85 | } 86 | 87 | public IsotpFlowControlOptions withMaximumWaitFrameTransmission(byte maximumWaitFrameTransmission) { 88 | return new IsotpFlowControlOptions( 89 | blockSize, 90 | minimumSeparationTime, 91 | maximumWaitFrameTransmission 92 | ); 93 | } 94 | 95 | public IsotpFlowControlOptions withMaximumWaitFrameTransmission(int maximumWaitFrameTransmission) { 96 | return withMaximumWaitFrameTransmission((byte) maximumWaitFrameTransmission); 97 | } 98 | 99 | @Override 100 | public boolean equals(Object o) { 101 | if (this == o) 102 | return true; 103 | if (o == null || getClass() != o.getClass()) 104 | return false; 105 | IsotpFlowControlOptions that = (IsotpFlowControlOptions) o; 106 | return blockSize == that.blockSize && minimumSeparationTime == that.minimumSeparationTime 107 | && maximumWaitFrameTransmission == that.maximumWaitFrameTransmission; 108 | } 109 | 110 | @Override 111 | public int hashCode() { 112 | return Objects.hash(blockSize, minimumSeparationTime, maximumWaitFrameTransmission); 113 | } 114 | 115 | @Override 116 | public String toString() { 117 | return "IsotpFlowControlOptions(" + "blockSize=" + blockSize + ", minimumSeparationTime=" 118 | + minimumSeparationTime + ", maximumWaitFrameTransmission=" + maximumWaitFrameTransmission + ')'; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/IsotpLinkLayerOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import tel.schich.jniaccess.JNIAccess; 26 | 27 | import java.util.Objects; 28 | 29 | /** 30 | * This class represents ISOTP's link layer options. 31 | */ 32 | public class IsotpLinkLayerOptions { 33 | 34 | public static final IsotpLinkLayerOptions DEFAULT = new IsotpLinkLayerOptions( 35 | (byte) RawCanChannel.MTU, 36 | (byte) CanFrame.MAX_DATA_LENGTH, 37 | (byte) 0 38 | ); 39 | 40 | private final byte maximumTransmissionUnit; 41 | private final byte transmissionDataLength; 42 | private final byte transmissionFlags; 43 | 44 | @JNIAccess 45 | public IsotpLinkLayerOptions(byte maximumTransmissionUnit, byte transmissionDataLength, byte transmissionFlags) { 46 | this.maximumTransmissionUnit = maximumTransmissionUnit; 47 | this.transmissionDataLength = transmissionDataLength; 48 | this.transmissionFlags = transmissionFlags; 49 | } 50 | 51 | public byte getMaximumTransmissionUnit() { 52 | return maximumTransmissionUnit; 53 | } 54 | 55 | public IsotpLinkLayerOptions withMaximumTransmissionUnit(byte maximumTransmissionUnit) { 56 | return new IsotpLinkLayerOptions( 57 | maximumTransmissionUnit, 58 | transmissionDataLength, 59 | transmissionFlags 60 | ); 61 | } 62 | 63 | public IsotpLinkLayerOptions withMaximumTransmissionUnit(int maximumTransmissionUnit) { 64 | return withMaximumTransmissionUnit((byte) maximumTransmissionUnit); 65 | } 66 | 67 | public byte getTransmissionDataLength() { 68 | return transmissionDataLength; 69 | } 70 | 71 | public IsotpLinkLayerOptions withTransmissionDataLength(byte transmissionDataLength) { 72 | return new IsotpLinkLayerOptions( 73 | maximumTransmissionUnit, 74 | transmissionDataLength, 75 | transmissionFlags 76 | ); 77 | } 78 | 79 | public IsotpLinkLayerOptions withTransmissionDataLength(int transmissionDataLength) { 80 | return withTransmissionDataLength((byte) transmissionDataLength); 81 | } 82 | 83 | public byte getTransmissionFlags() { 84 | return transmissionFlags; 85 | } 86 | 87 | public IsotpLinkLayerOptions withTransmissionFlags(byte transmissionFlags) { 88 | return new IsotpLinkLayerOptions( 89 | maximumTransmissionUnit, 90 | transmissionDataLength, 91 | transmissionFlags 92 | ); 93 | } 94 | 95 | public IsotpLinkLayerOptions withTransmissionFlags(int transmissionFlags) { 96 | return withTransmissionFlags((byte) transmissionFlags); 97 | } 98 | 99 | @Override 100 | public boolean equals(Object o) { 101 | if (this == o) 102 | return true; 103 | if (o == null || getClass() != o.getClass()) 104 | return false; 105 | IsotpLinkLayerOptions that = (IsotpLinkLayerOptions) o; 106 | return maximumTransmissionUnit == that.maximumTransmissionUnit 107 | && transmissionDataLength == that.transmissionDataLength && transmissionFlags == that.transmissionFlags; 108 | } 109 | 110 | @Override 111 | public int hashCode() { 112 | return Objects.hash(maximumTransmissionUnit, transmissionDataLength, transmissionFlags); 113 | } 114 | 115 | @Override 116 | public String toString() { 117 | return "IsotpLinkLayerOptions(" + "maximumTranmissionUnit=" + maximumTransmissionUnit 118 | + ", transmissionDataLength=" + transmissionDataLength + ", transmissionFlags=" + transmissionFlags 119 | + ')'; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/IsotpSocketAddress.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import java.net.SocketAddress; 26 | import java.util.Objects; 27 | 28 | /** 29 | * This class represents an ISOTP socket address and implements teh {@link java.net.SocketAddress} API. 30 | */ 31 | public class IsotpSocketAddress extends SocketAddress { 32 | private final int id; 33 | 34 | private IsotpSocketAddress(int id) { 35 | this.id = id; 36 | } 37 | 38 | /** 39 | * Returns the CAN ID of this ISOTP address. 40 | * 41 | * @return the CAN ID 42 | */ 43 | public int getId() { 44 | return id; 45 | } 46 | 47 | /** 48 | * Returns the return address of this address. 49 | * 50 | * @return the return address 51 | */ 52 | public IsotpSocketAddress returnAddress() { 53 | return new IsotpSocketAddress(IsotpAddress.returnAddress(id)); 54 | } 55 | 56 | /** 57 | * Checks if this address uses EFF. 58 | * 59 | * @return true if this address uses EFF 60 | */ 61 | public boolean isExtended() { 62 | return CanId.isExtended(id); 63 | } 64 | 65 | /** 66 | * Checks if this address is used to address functionally. 67 | * 68 | * @return true if this address is used to address functionally 69 | */ 70 | public boolean isFunctional() { 71 | return IsotpAddress.isFunctional(id); 72 | } 73 | 74 | @Override 75 | public boolean equals(Object o) { 76 | if (this == o) 77 | return true; 78 | if (o == null || getClass() != o.getClass()) 79 | return false; 80 | IsotpSocketAddress that = (IsotpSocketAddress) o; 81 | return id == that.id; 82 | } 83 | 84 | @Override 85 | public int hashCode() { 86 | return Objects.hash(id); 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | return "IsotpSocketAddress(" + "id=" + id + ')'; 92 | } 93 | 94 | /** 95 | * Creates a new ISOTP address using the given CAN ID. 96 | * 97 | * @param id the CAN ID 98 | * @return the new address instance 99 | */ 100 | public static IsotpSocketAddress isotpAddress(int id) { 101 | return new IsotpSocketAddress(id); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/J1939Address.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import tel.schich.javacan.platform.linux.LinuxNetworkDevice; 26 | 27 | /** 28 | * Classes implementing this interface represent a J1939 address. 29 | * 30 | * @see The Linux J1939 documentation 31 | */ 32 | public interface J1939Address { 33 | long NO_NAME = 0L; 34 | int NO_PGN = 0x40000; 35 | byte NO_ADDR = (byte) 0xFF; 36 | byte IDLE_ADDR = (byte) 0xFE; 37 | 38 | /** 39 | * The device a message has been received on. 40 | * 41 | * @return the device 42 | */ 43 | LinuxNetworkDevice getDevice(); 44 | 45 | /** 46 | * The J1939 name. 47 | * 48 | * @return the name 49 | */ 50 | long getName(); 51 | 52 | /** 53 | * The J1939 PGN. 54 | * 55 | * @return the PGN 56 | */ 57 | int getParameterGroupNumber(); 58 | 59 | /** 60 | * The J1939 address. 61 | * 62 | * @return the address 63 | */ 64 | byte getAddress(); 65 | 66 | /** 67 | * Copies the address into an immutable representation. 68 | * 69 | * @return An immutable copy of this address 70 | */ 71 | ImmutableJ1939Address copy(); 72 | 73 | /** 74 | * Creates a J1939 address from the given parameters. 75 | * 76 | * @param device the device of the address 77 | * @param name the J1939 name 78 | * @param parameterGroupNumber the J1939 PGN 79 | * @param address the J1939 address 80 | * @return an immutable representation of the address 81 | */ 82 | static ImmutableJ1939Address of(NetworkDevice device, long name, int parameterGroupNumber, byte address) { 83 | return new ImmutableJ1939Address(device, name, parameterGroupNumber, address); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/J1939AddressBuffer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import tel.schich.javacan.platform.linux.LinuxNetworkDevice; 26 | 27 | import java.nio.ByteBuffer; 28 | 29 | /** 30 | * This class represents a J1939 address that can be used for native operations. 31 | */ 32 | public final class J1939AddressBuffer implements J1939Address { 33 | 34 | static { 35 | JavaCAN.initialize(); 36 | } 37 | 38 | /** 39 | * The size of this data structure in memory. 40 | */ 41 | public static final int BYTES = getStructSize(); 42 | 43 | private static final int DEVICE_INDEX_OFFSET = getStructDeviceIndexOffset(); 44 | private static final int NAME_OFFSET = getStructNameOffset();; 45 | private static final int PGN_OFFSET = getStructPgnOffset(); 46 | private static final int ADDR_OFFSET = getStructAddrOffset(); 47 | 48 | private final ByteBuffer buffer; 49 | private final int offset; 50 | 51 | public J1939AddressBuffer() { 52 | this(JavaCAN.allocateOrdered(BYTES)); 53 | } 54 | 55 | public J1939AddressBuffer(ByteBuffer buffer) { 56 | this(buffer, buffer.position()); 57 | } 58 | 59 | public J1939AddressBuffer(ByteBuffer buffer, int offset) { 60 | this.buffer = buffer; 61 | this.offset = offset; 62 | } 63 | 64 | @Override 65 | public LinuxNetworkDevice getDevice() { 66 | return LinuxNetworkDevice.fromDeviceIndex(buffer.getInt(offset + DEVICE_INDEX_OFFSET)); 67 | } 68 | 69 | public J1939AddressBuffer setDevice(LinuxNetworkDevice device) { 70 | buffer.putInt(offset + DEVICE_INDEX_OFFSET, device.getIndex()); 71 | return this; 72 | } 73 | 74 | @Override 75 | public long getName() { 76 | return buffer.getLong(offset + NAME_OFFSET); 77 | } 78 | 79 | public J1939AddressBuffer setName(long name) { 80 | buffer.putLong(offset + NAME_OFFSET, name); 81 | return this; 82 | } 83 | 84 | @Override 85 | public int getParameterGroupNumber() { 86 | return buffer.getInt(offset + PGN_OFFSET); 87 | } 88 | 89 | public J1939AddressBuffer setParameterGroupNumber(int parameterGroupNumber) { 90 | buffer.putInt(offset + PGN_OFFSET, parameterGroupNumber); 91 | return this; 92 | } 93 | 94 | @Override 95 | public byte getAddress() { 96 | return buffer.get(offset + ADDR_OFFSET); 97 | } 98 | 99 | public J1939AddressBuffer setAddress(byte address) { 100 | buffer.put(offset + ADDR_OFFSET, address); 101 | return this; 102 | } 103 | 104 | public J1939AddressBuffer set(J1939Address other) { 105 | setDevice(other.getDevice()); 106 | setName(other.getName()); 107 | setParameterGroupNumber(other.getParameterGroupNumber()); 108 | setAddress(other.getAddress()); 109 | return this; 110 | } 111 | 112 | @Override 113 | public ImmutableJ1939Address copy() { 114 | return new ImmutableJ1939Address( 115 | getDevice(), 116 | getName(), 117 | getParameterGroupNumber(), 118 | getAddress() 119 | ); 120 | } 121 | 122 | private static native int getStructSize(); 123 | private static native int getStructDeviceIndexOffset(); 124 | private static native int getStructNameOffset(); 125 | private static native int getStructPgnOffset(); 126 | private static native int getStructAddrOffset(); 127 | } 128 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/J1939ReceiveMessageHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import java.time.Instant; 26 | 27 | /** 28 | * Classes implementing this interface represent message headers supplied by the kernel when reading a J1939 message. 29 | * 30 | * @see The Linux J1939 documentation 31 | */ 32 | public interface J1939ReceiveMessageHeader extends ReceiveMessageHeader { 33 | /** 34 | * The source address the messages has been received from. 35 | * 36 | * @return the source address 37 | */ 38 | J1939Address getSourceAddress(); 39 | 40 | /** 41 | * The destination address of the message. 42 | * 43 | * @return the destination address 44 | */ 45 | byte getDestinationAddress(); 46 | 47 | /** 48 | * The destination name of the message 49 | * 50 | * @return the destination name 51 | */ 52 | long getDestinationName(); 53 | 54 | /** 55 | * The priority of the message. 56 | * 57 | * @return the priority value 58 | */ 59 | byte getPriority(); 60 | 61 | /** 62 | * Copies the message headers into an immutable representation. 63 | * 64 | * @return An immutable copy of the headers 65 | */ 66 | ImmutableJ1939ReceiveMessageHeader copy(); 67 | } 68 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/J1939Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | /** 26 | * This class provides utility functions to work with J1939 messages 27 | */ 28 | public class J1939Utils { 29 | private J1939Utils() { 30 | } 31 | 32 | /** 33 | * Extracts the PGN from a raw EFF CAN ID. 34 | * 35 | * @param canId the raw EFF CAN ID 36 | * @return the PGN 37 | */ 38 | public static int parameterGroupNumberFromRawAddress(int canId) { 39 | return (canId >>> 8) & 0b0011_1111_1111_1111_1111; 40 | } 41 | 42 | /** 43 | * Extracts the source address from a raw EFF CAN ID. 44 | * 45 | * @param canId the raw EFF CAN ID 46 | * @return the source address 47 | */ 48 | public static byte sourceAddressFromRawAddress(int canId) { 49 | return (byte)(canId & 0b1111_1111); 50 | } 51 | 52 | /** 53 | * Extracts the priority from a raw EFF CAN ID. 54 | * 55 | * @param canId the raw EFF CAN ID 56 | * @return the priority 57 | */ 58 | public static byte priorityFromRawAddress(int canId) { 59 | return (byte)((canId >>> 26) & 0b0111); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/JavaCAN.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import tel.schich.javacan.platform.Platform; 26 | 27 | import java.nio.ByteBuffer; 28 | import java.nio.ByteOrder; 29 | 30 | public class JavaCAN { 31 | 32 | private static volatile boolean initialized = false; 33 | 34 | public static final String LIB_NAME = "javacan-core"; 35 | 36 | /** 37 | * Initializes the library by loading the native library. 38 | */ 39 | public synchronized static void initialize() { 40 | if (initialized) { 41 | return; 42 | } 43 | 44 | Platform.loadNativeLibrary(LIB_NAME, JavaCAN.class); 45 | 46 | initialized = true; 47 | } 48 | 49 | /** 50 | * A simple helper to allocate a {@link ByteBuffer} as needed by the underlying native code. 51 | * 52 | * @param capacity the capacity of the buffer. 53 | * @return the buffer in native byte order with the given capacity. 54 | */ 55 | public static ByteBuffer allocateOrdered(int capacity) { 56 | return allocateUnordered(capacity).order(ByteOrder.nativeOrder()); 57 | } 58 | 59 | /** 60 | * A simple helper to allocate a {@link ByteBuffer} as needed by the underlying native code. 61 | * 62 | * @param capacity the capacity of the buffer. 63 | * @return the buffer in default (unspecified) byte order with the given capacity. 64 | */ 65 | public static ByteBuffer allocateUnordered(int capacity) { 66 | return ByteBuffer.allocateDirect(capacity); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/NetworkDevice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import java.io.IOException; 26 | 27 | import org.eclipse.jdt.annotation.Nullable; 28 | import tel.schich.javacan.platform.UnsupportedPlatformException; 29 | import tel.schich.javacan.platform.linux.LinuxNetworkDevice; 30 | import tel.schich.javacan.platform.Platform; 31 | 32 | /** 33 | * This class represents a network device. 34 | */ 35 | public interface NetworkDevice { 36 | /** 37 | * Gets the name of the device. 38 | * 39 | * @return the device name, which can be null 40 | */ 41 | @Nullable 42 | String getName(); 43 | 44 | /** 45 | * Looks up a network device by name. 46 | * 47 | * @see if_nametoindex man page 48 | * @param name the concrete value is platform dependent, on Linux this might be "vcan0". 49 | * @return the network device. 50 | * @throws IOException if the underlying operation failed. The obvious example would be, that the device was not found. 51 | */ 52 | static NetworkDevice lookup(String name) throws IOException { 53 | switch (Platform.getOS()) { 54 | case LINUX: 55 | return LinuxNetworkDevice.lookup(name); 56 | default: 57 | throw new UnsupportedPlatformException(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/RawReceiveMessageHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import java.time.Instant; 26 | 27 | /** 28 | * Classes implementing this interface represent messages headers included with receive operations of raw CAN frames. 29 | */ 30 | public interface RawReceiveMessageHeader extends ReceiveMessageHeader { 31 | /** 32 | * The interface the frame was received on. 33 | * 34 | * @return the interface 35 | */ 36 | NetworkDevice getDevice(); 37 | 38 | /** 39 | * The number of frames that have been dropped since the channel has been created. This will always be 0 unless {@link CanSocketOptions#SO_RXQ_OVFL} is enabled. 40 | * 41 | * @return the number of dropped frames since channel creation 42 | */ 43 | int getDropCount(); 44 | 45 | /** 46 | * Copies the message headers into an immutable representation. 47 | * 48 | * @return An immutable copy of the headers 49 | */ 50 | ImmutableRawReceiveMessageHeader copy(); 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/ReceiveMessageHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import java.time.Instant; 26 | 27 | public interface ReceiveMessageHeader { 28 | /** 29 | * The timestamp the frame was received at. This is only a useful value, if timestamps are enabled on the channel. 30 | * The precision depends on the channel configuration, the runtime kernel and the hardware being used. 31 | * 32 | * @return the receive timestamp or the start of the unix epoch if no timestamp was available 33 | */ 34 | Instant getSoftwareTimestamp(); 35 | 36 | /** 37 | * The timestamp the frame was received at measured by the hardware. This is only a useful value, if hardware timestamps are enabled on the channel. 38 | * The precision depends on the channel configuration, the runtime kernel and the hardware being used. 39 | * 40 | * @return the receive timestamp or the start of the unix epoch if no timestamp was available 41 | */ 42 | Instant getHardwareTimestamp(); 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/option/CanSocketOption.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.option; 24 | 25 | import tel.schich.javacan.platform.linux.UnixFileDescriptor; 26 | 27 | import java.io.IOException; 28 | import java.net.SocketOption; 29 | 30 | /** 31 | * This class provides the base for all socket options by this library. 32 | * 33 | * @param the type of the option value 34 | */ 35 | public class CanSocketOption implements SocketOption { 36 | private final String name; 37 | private final Class type; 38 | private final Handler handler; 39 | 40 | public CanSocketOption(String name, Class type, Handler handler) { 41 | this.name = name; 42 | this.type = type; 43 | this.handler = handler; 44 | } 45 | 46 | @Override 47 | public String name() { 48 | return name; 49 | } 50 | 51 | @Override 52 | public Class type() { 53 | return type; 54 | } 55 | 56 | public Handler getHandler() { 57 | return handler; 58 | } 59 | 60 | /** 61 | * This interface needs to be implemented per option to call into native code to actually implement that option 62 | * change or extract the current value. 63 | * 64 | * @param the type of the option value 65 | */ 66 | public interface Handler { 67 | void set(UnixFileDescriptor handle, T val, boolean validate) throws IOException; 68 | T get(UnixFileDescriptor handle) throws IOException; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/option/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | @NonNullByDefault 24 | package tel.schich.javacan.option; 25 | 26 | import org.eclipse.jdt.annotation.NonNullByDefault; 27 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | @NonNullByDefault 24 | package tel.schich.javacan; 25 | 26 | import org.eclipse.jdt.annotation.NonNullByDefault; 27 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/platform/NativeChannel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.platform; 24 | 25 | import java.nio.channels.Channel; 26 | 27 | /** 28 | * This interface is intended for {@link java.nio.channels.Channel} implementations that are backed by native APIs 29 | * like for example Berkley sockets. It exposes a wrapper around the native handle for the 30 | * {@link java.nio.channels.Channel}'s connection (e.g. the socket file descriptor on Linux). 31 | * The handle can then be typed checked by the consumer to see if it can handle that kind of native 32 | * {@link java.nio.channels.Channel}. 33 | */ 34 | public interface NativeChannel extends Channel { 35 | /** 36 | * Exposes the internal "connection handle" without being specific about it. 37 | * 38 | * @return the native handle, never null. 39 | */ 40 | HandleType getHandle(); 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/platform/UnsupportedPlatformException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.platform; 24 | 25 | public class UnsupportedPlatformException extends RuntimeException { 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/platform/linux/LinuxNativeOperationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.platform.linux; 24 | 25 | import tel.schich.jniaccess.JNIAccess; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | * This exception is thrown when an error occurs during a native call. 31 | * It provides OS specific information if possible, but no guarantees are given that the information is correct and/or 32 | * complete. 33 | */ 34 | public class LinuxNativeOperationException extends IOException { 35 | 36 | /** 37 | * Bad file number 38 | */ 39 | public static final int EBADF = 9; 40 | 41 | /** 42 | * Try again 43 | */ 44 | public static final int EAGAIN = 11; 45 | 46 | /** 47 | * No such device 48 | */ 49 | public static final int ENODEV = 19; 50 | 51 | /** 52 | * The native error number or 0 if no native error code was provided. 53 | */ 54 | private final int errorNumber; 55 | /** 56 | * The native error message or {@code null} if no native message was provided. 57 | */ 58 | private final String errorString; 59 | 60 | /** 61 | * Create an instance with an OS error. This constructor will be called from native code. 62 | * 63 | * @param message of the exception 64 | * @param errorNumber as reported by the native OS function 65 | * @param errorString as returned by the native OS function {@code strerror(errno)} 66 | */ 67 | @JNIAccess 68 | public LinuxNativeOperationException(String message, int errorNumber, String errorString) { 69 | super(makeSuperMessage(message, errorNumber, errorString)); 70 | this.errorNumber = errorNumber; 71 | this.errorString = errorString; 72 | } 73 | 74 | private static String makeSuperMessage(String message, int errorNumber, String errorString) { 75 | if (errorNumber == 0) { 76 | return message; 77 | } else { 78 | return message + " - errorNumber=" + errorNumber + ", errorMessage='" + errorString + '\''; 79 | } 80 | } 81 | 82 | /** 83 | * This is the value returned by the {@code errno} macro when the error was detected. 84 | * Values being used within this code base should be added as constants to the class similar 85 | * to {@link LinuxNativeOperationException#EAGAIN} based on the constants defined in errno-base.h 86 | * 87 | * @return An OS error code 88 | */ 89 | public int getErrorNumber() { 90 | return this.errorNumber; 91 | } 92 | 93 | public boolean isBadFD() { 94 | return getErrorNumber() == EBADF; 95 | } 96 | 97 | /** 98 | * This is the value returned by the {@code strerror(errno)} macro when the error was detected. 99 | * 100 | * @return An OS error code or null of no string available 101 | */ 102 | public String getErrorString() { 103 | return errorString; 104 | } 105 | 106 | /** 107 | * Checks if the underlying OS error suggests retrying as a solution. 108 | * 109 | * @return true if a retry might be a viable resolution of this exception 110 | */ 111 | public boolean mayTryAgain() { 112 | if (errorNumber == 0) { 113 | return false; 114 | } 115 | return isTemporary(); 116 | } 117 | 118 | 119 | private boolean isTemporary() { 120 | switch (errorNumber) { 121 | case EAGAIN: 122 | return true; 123 | default: 124 | return false; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/platform/linux/LinuxNetworkDevice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.platform.linux; 24 | 25 | import org.eclipse.jdt.annotation.Nullable; 26 | import tel.schich.javacan.JavaCAN; 27 | import tel.schich.javacan.NetworkDevice; 28 | 29 | import java.io.IOException; 30 | import java.util.Objects; 31 | 32 | public class LinuxNetworkDevice implements NetworkDevice { 33 | 34 | static { 35 | JavaCAN.initialize(); 36 | } 37 | 38 | @Nullable 39 | private final String name; 40 | private final int index; 41 | 42 | private LinuxNetworkDevice(@Nullable String name, int index) { 43 | this.name = name; 44 | this.index = index; 45 | } 46 | 47 | @Nullable 48 | public String getName() { 49 | if (name == null) { 50 | try { 51 | return findDeviceNameByIndex(index); 52 | } catch (LinuxNativeOperationException ignored) { 53 | return null; 54 | } 55 | } 56 | return name; 57 | } 58 | 59 | /** 60 | * Gets the index of the device. 61 | * 62 | * @return the device index 63 | */ 64 | public int getIndex() { 65 | return index; 66 | } 67 | 68 | /** 69 | * Looks up a network device by name and constructs a new {@link NetworkDevice} instance from the 70 | * result. 71 | * 72 | * @param name the device name 73 | * @return the device wrapper 74 | * @throws java.io.IOException if the native calls fail 75 | */ 76 | public static NetworkDevice lookup(String name) throws IOException { 77 | int index = findDeviceIndexByName(name); 78 | return new LinuxNetworkDevice(name, index); 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | return "LinuxNetworkDevice(" + "name='" + getName() + '\'' + ", index=" + index + ')'; 84 | } 85 | 86 | @Override 87 | public boolean equals(Object o) { 88 | if (this == o) 89 | return true; 90 | if (o == null || getClass() != o.getClass()) 91 | return false; 92 | LinuxNetworkDevice dev = (LinuxNetworkDevice) o; 93 | return index == dev.index; 94 | } 95 | 96 | @Override 97 | public int hashCode() { 98 | return Objects.hash(index); 99 | } 100 | 101 | private static native int findDeviceIndexByName(String interfaceName) throws LinuxNativeOperationException; 102 | 103 | @Nullable 104 | private static native String findDeviceNameByIndex(int index) throws LinuxNativeOperationException; 105 | 106 | public static LinuxNetworkDevice fromDeviceIndex(int index) { 107 | return new LinuxNetworkDevice(null, index); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/platform/linux/LinuxSocketOptionHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.platform.linux; 24 | 25 | import tel.schich.javacan.option.CanSocketOption; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | * An abstract {@link tel.schich.javacan.option.CanSocketOption.Handler} implementation that verifies and unpacks 31 | * the given {@link UnixFileDescriptor} and forwards the file descriptor to the actual 32 | * implementation. 33 | * 34 | * @param type of the option value 35 | */ 36 | public abstract class LinuxSocketOptionHandler implements CanSocketOption.Handler { 37 | @Override 38 | public void set(UnixFileDescriptor handle, T val, boolean validate) throws IOException { 39 | set(handle.getValue(), val, validate); 40 | } 41 | 42 | @Override 43 | public T get(UnixFileDescriptor handle) throws IOException { 44 | return get(handle.getValue()); 45 | } 46 | 47 | protected abstract void set(int sock, T val, boolean validate) throws IOException; 48 | 49 | protected abstract T get(int sock) throws IOException; 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/platform/linux/UnixFileDescriptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.platform.linux; 24 | 25 | import java.util.Objects; 26 | 27 | /** 28 | * This class represents a UNIX file descriptor 29 | */ 30 | public class UnixFileDescriptor { 31 | private final int fd; 32 | 33 | /** 34 | * Creates an instance from the given file descriptor ID. 35 | * 36 | * @param fd the file descriptor ID 37 | */ 38 | public UnixFileDescriptor(int fd) { 39 | this.fd = fd; 40 | } 41 | 42 | /** 43 | * Returns the backing file descriptor ID. 44 | * 45 | * @return the file descriptor ID 46 | */ 47 | public int getValue() { 48 | return fd; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "UnixFileDescriptor(" + fd + ')'; 54 | } 55 | 56 | @Override 57 | public boolean equals(Object o) { 58 | if (this == o) return true; 59 | if (o == null || getClass() != o.getClass()) return false; 60 | UnixFileDescriptor that = (UnixFileDescriptor) o; 61 | return fd == that.fd; 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | return Objects.hash(fd); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/platform/linux/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | @NonNullByDefault 24 | package tel.schich.javacan.platform.linux; 25 | 26 | import org.eclipse.jdt.annotation.NonNullByDefault; 27 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/platform/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | @NonNullByDefault 24 | package tel.schich.javacan.platform; 25 | 26 | import org.eclipse.jdt.annotation.NonNullByDefault; 27 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/util/CanUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.util; 24 | 25 | import java.nio.ByteBuffer; 26 | 27 | public class CanUtils { 28 | 29 | private CanUtils() { 30 | } 31 | 32 | public static String hexDump(ByteBuffer data) { 33 | return hexDump(data, data.position(), data.remaining()); 34 | } 35 | 36 | public static String hexDump(ByteBuffer data, int offset, int length) { 37 | StringBuilder s = new StringBuilder(length * 2); 38 | if (length > 0) { 39 | s.append(String.format("%02X", data.get(offset))); 40 | for (int i = 1; i < length; ++i) { 41 | s.append('.').append(String.format("%02X", data.get(offset + i))); 42 | } 43 | } 44 | return s.toString(); 45 | } 46 | 47 | // see: https://github.com/torvalds/linux/blob/5f33a09e769a9da0482f20a6770a342842443776/net/can/isotp.c#L260 48 | private static final byte[] paddedDataLengthLookup = { 49 | 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0 - 8 */ 50 | 12, 12, 12, 12, /* 9 - 12 */ 51 | 16, 16, 16, 16, /* 13 - 16 */ 52 | 20, 20, 20, 20, /* 17 - 20 */ 53 | 24, 24, 24, 24, /* 21 - 24 */ 54 | 32, 32, 32, 32, 32, 32, 32, 32, /* 25 - 32 */ 55 | 48, 48, 48, 48, 48, 48, 48, 48, /* 33 - 40 */ 56 | 48, 48, 48, 48, 48, 48, 48, 48 /* 41 - 48 */ 57 | }; 58 | 59 | /** 60 | * Pads a DLC data length value as per ISO 11898-1. 61 | * 62 | * @param length the unpadded length 63 | * @return the padded length 64 | * 65 | * @see Implementation in Linux Kernel 66 | */ 67 | public static byte padDataLength(byte length) { 68 | if (length > 48) { 69 | return 64; 70 | } 71 | return paddedDataLengthLookup[length]; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/util/EvictingQueue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.util; 24 | 25 | /** 26 | * This queue scales very badly with increasing capacities. It is implemented this way to be easily viewable within a debugging 27 | * view, as the last message is always in the last array position. Debugging is the only intended use-case 28 | * for this queue! 29 | * @param The element type, should provide a good toString() implementation for debug purposes 30 | */ 31 | public final class EvictingQueue { 32 | private int i; 33 | private final T[] buf; 34 | 35 | @SuppressWarnings("unchecked") 36 | public EvictingQueue(int cap) { 37 | if (cap == 0) { 38 | throw new IllegalArgumentException("needs to handle at least one element!"); 39 | } 40 | buf = (T[]) new Object[cap]; 41 | } 42 | 43 | public synchronized void offer(T f) { 44 | i++; 45 | for (i = 1; i < buf.length; i++) { 46 | buf[i - 1] = buf[i]; 47 | } 48 | buf[buf.length - 1] = f; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/tel/schich/javacan/util/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | @NonNullByDefault 24 | package tel.schich.javacan.util; 25 | 26 | import org.eclipse.jdt.annotation.NonNullByDefault; 27 | -------------------------------------------------------------------------------- /core/src/test/java/tel/schich/javacan/test/J1939UtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.test; 24 | 25 | import org.junit.jupiter.api.Test; 26 | import tel.schich.javacan.J1939Utils; 27 | 28 | import static java.lang.Integer.toHexString; 29 | import static org.junit.jupiter.api.Assertions.*; 30 | 31 | class J1939UtilsTest { 32 | 33 | @Test 34 | void parameterGroupNumberFromRawAddress() { 35 | assertEquals(toHexString(0xEFA1), toHexString(J1939Utils.parameterGroupNumberFromRawAddress(0x18EFA1EB))); 36 | } 37 | 38 | @Test 39 | void sourceAddressFromRawAddress() { 40 | assertEquals(toHexString((byte)0xEB), toHexString(J1939Utils.sourceAddressFromRawAddress(0x18EFA1EB))); 41 | } 42 | 43 | @Test 44 | void priorityFromRawAddress() { 45 | assertEquals(6, J1939Utils.priorityFromRawAddress(0x18EFA1EB)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/src/test/java/tel/schich/javacan/test/linux/LinuxNativeOperationExceptionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.test.linux; 24 | 25 | 26 | import org.junit.jupiter.api.Test; 27 | import tel.schich.javacan.CanChannels; 28 | import tel.schich.javacan.NetworkDevice; 29 | import tel.schich.javacan.RawCanChannel; 30 | import tel.schich.javacan.TestHelper; 31 | import tel.schich.javacan.platform.linux.LinuxNativeOperationException; 32 | import tel.schich.javacan.test.CanTestHelper; 33 | 34 | import java.nio.channels.ClosedChannelException; 35 | import java.util.Arrays; 36 | 37 | import static org.junit.jupiter.api.Assertions.*; 38 | import static tel.schich.javacan.platform.linux.LinuxNativeOperationException.ENODEV; 39 | 40 | class LinuxNativeOperationExceptionTest { 41 | @Test 42 | void testInvalidFileDescriptorError() { 43 | ClosedChannelException ex = assertThrows(ClosedChannelException.class, () -> { 44 | try (RawCanChannel channel = TestHelper.createChannelWithFd(TestHelper.createInvalidFd())) { 45 | channel.bind(CanTestHelper.CAN_INTERFACE); 46 | fail("must fail due to invalid file descriptor"); 47 | } 48 | }); 49 | assertTrue(Arrays.stream(ex.getSuppressed()).anyMatch(e -> e instanceof LinuxNativeOperationException && ((LinuxNativeOperationException) e).isBadFD()), 50 | "must have suppressed a bad file descriptor"); 51 | } 52 | 53 | @Test 54 | void testUnknownDevice() { 55 | String ifName = "doesNotExist"; 56 | LinuxNativeOperationException ex = assertThrows(LinuxNativeOperationException.class, () -> NetworkDevice.lookup(ifName)); 57 | assertTrue(ex.getMessage().contains(ifName), "message contains interface name"); 58 | assertEquals(ENODEV, ex.getErrorNumber()); // No such device 59 | } 60 | 61 | @Test 62 | void testRepeatedClose() { 63 | assertDoesNotThrow(() -> { 64 | RawCanChannel channel = CanChannels.newRawChannel(CanTestHelper.CAN_INTERFACE); 65 | channel.close(); 66 | channel.close(); 67 | }); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /core/src/testFixtures/java/tel/schich/javacan/TestHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan; 24 | 25 | import org.junit.jupiter.api.Assertions; 26 | import tel.schich.javacan.platform.linux.LinuxNativeOperationException; 27 | 28 | import java.nio.ByteBuffer; 29 | 30 | public class TestHelper { 31 | 32 | public static RawCanChannel createChannelWithFd(int fd) { 33 | return new RawCanChannelImpl(fd); 34 | } 35 | 36 | public static int createInvalidFd() throws LinuxNativeOperationException { 37 | int fd = SocketCAN.createRawSocket(); 38 | SocketCAN.close(fd); 39 | return fd; 40 | } 41 | 42 | public static ByteBuffer directBufferOf(byte[] data) { 43 | ByteBuffer buffer = ByteBuffer.allocateDirect(data.length); 44 | buffer.put(data); 45 | buffer.flip(); 46 | return buffer; 47 | } 48 | 49 | public static void assertByteBufferEquals(ByteBuffer expected, ByteBuffer actual) { 50 | final ByteBuffer expectedArrayBacked = ByteBuffer.allocate(expected.remaining()); 51 | final ByteBuffer actualArrayBacked = ByteBuffer.allocate(actual.remaining()); 52 | 53 | expectedArrayBacked.put(expected); 54 | actualArrayBacked.put(actual); 55 | 56 | Assertions.assertArrayEquals(expectedArrayBacked.array(), actualArrayBacked.array()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/testFixtures/java/tel/schich/javacan/test/CanTestHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.test; 24 | 25 | import tel.schich.javacan.CanFrame; 26 | import tel.schich.javacan.JavaCAN; 27 | import tel.schich.javacan.NetworkDevice; 28 | import tel.schich.javacan.platform.linux.LinuxNetworkDevice; 29 | 30 | import java.io.IOException; 31 | import java.io.UncheckedIOException; 32 | import java.nio.ByteBuffer; 33 | import java.time.Duration; 34 | import java.time.Instant; 35 | 36 | public class CanTestHelper { 37 | public static final LinuxNetworkDevice CAN_INTERFACE = (LinuxNetworkDevice) lookupDev(); 38 | 39 | private static NetworkDevice lookupDev() { 40 | try { 41 | return NetworkDevice.lookup("vcan0"); 42 | } catch (IOException e) { 43 | e.printStackTrace(System.err); 44 | throw new UncheckedIOException(e); 45 | } 46 | } 47 | 48 | public static void sendFrameViaUtils(NetworkDevice device, CanFrame frame) throws IOException, InterruptedException { 49 | StringBuilder data = new StringBuilder(); 50 | if (frame.isRemoteTransmissionRequest()) { 51 | data.append('R'); 52 | } 53 | ByteBuffer buf = JavaCAN.allocateOrdered(CanFrame.MAX_FD_DATA_LENGTH); 54 | frame.getData(buf); 55 | buf.flip(); 56 | while (buf.hasRemaining()) { 57 | data.append(String.format("%02X", buf.get())); 58 | } 59 | 60 | String idString; 61 | if (frame.isExtended()) { 62 | idString = String.format("%08X", frame.getId()); 63 | } else { 64 | idString = String.format("%03X", frame.getId()); 65 | } 66 | 67 | String textFrame; 68 | if (frame.isFDFrame()) { 69 | textFrame = String.format("%s##%X%s", idString, frame.getFlags(), data); 70 | } else { 71 | textFrame = String.format("%s#%s", idString, data); 72 | } 73 | final ProcessBuilder cansend = new ProcessBuilder("cansend", device.getName(), textFrame); 74 | cansend.redirectError(ProcessBuilder.Redirect.INHERIT); 75 | cansend.redirectOutput(ProcessBuilder.Redirect.INHERIT); 76 | cansend.redirectInput(ProcessBuilder.Redirect.INHERIT); 77 | final Process proc = cansend.start(); 78 | int result = proc.waitFor(); 79 | if (result != 0) { 80 | throw new IllegalStateException("Failed to use cansend to send a CAN frame!"); 81 | } 82 | } 83 | 84 | public static void runDelayed(Duration d, IORunnable r) { 85 | new Thread(() -> { 86 | try { 87 | Thread.sleep(d.toMillis()); 88 | r.run(); 89 | } catch (Throwable e) { 90 | e.printStackTrace(System.err); 91 | } 92 | }).start(); 93 | } 94 | 95 | public interface IORunnable { 96 | void run() throws Exception; 97 | } 98 | 99 | public static Instant nowSeconds() { 100 | return Instant.ofEpochSecond(Instant.now().getEpochSecond(), 0); 101 | } 102 | public static Instant zeroTime() { 103 | return Instant.ofEpochSecond(0, 0); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /core/src/testFixtures/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | [%level] %logger{16} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /epoll-arch-detect/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("tel.schich.javacan.convention.arch-detect") 3 | } 4 | 5 | val nativeLibs = configurations.named("nativeLibs") 6 | 7 | dependencies { 8 | api(project(":epoll")) 9 | nativeLibs(project(mapOf("path" to ":epoll", "configuration" to "archDetectConfiguration"))) 10 | } 11 | 12 | publishing.publications.withType().configureEach { 13 | pom { 14 | description = "${rootProject.description} The ${project.name} module bundles all architectures and allows runtime architecture detection." 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /epoll-arch-detect/src/main/java/tel/schich/javacan/platform/linux/epoll/EPollAutoDetect.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.platform.linux.epoll; 24 | 25 | import tel.schich.javacan.platform.Platform; 26 | 27 | public class EPollAutoDetect { 28 | public static void initialize() { 29 | System.setProperty(Platform.classPathPropertyNameForLibrary(EPoll.LIB_NAME), "/" + Platform.detectCpuArch() + "/native/" + Platform.LINUX_LIBRARY_PREFIX + EPoll.LIB_NAME + ".so"); 30 | EPoll.initialize(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /epoll/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | project(javacan-epoll C) 3 | 4 | include(../common.cmake) 5 | 6 | add_library(javacan-epoll SHARED 7 | build/jni/epoll/jni-c-to-java.c 8 | src/main/c/javacan_epoll.c) 9 | -------------------------------------------------------------------------------- /epoll/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("tel.schich.javacan.convention.native") 3 | } 4 | 5 | dependencies { 6 | api(project(":core")) 7 | testImplementation(testFixtures(project(":core"))) 8 | } 9 | 10 | publishing.publications.withType().configureEach { 11 | pom { 12 | description = "${rootProject.description} The ${project.name} module provides facilities for reactive IO using Linux' epoll subsystem." 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | @NonNullByDefault 24 | package tel.schich.javacan; 25 | 26 | import org.eclipse.jdt.annotation.NonNullByDefault; 27 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/platform/linux/epoll/EPoll.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.platform.linux.epoll; 24 | 25 | import tel.schich.javacan.platform.Platform; 26 | import tel.schich.javacan.platform.linux.LinuxNativeOperationException; 27 | 28 | /** 29 | * This class specifies all supported native operations on the epoll subsystem. 30 | */ 31 | class EPoll { 32 | 33 | public static final String LIB_NAME = "javacan-epoll"; 34 | 35 | private static volatile boolean initialized = false; 36 | 37 | /** 38 | * Initializes the library by loading the native library. 39 | */ 40 | public synchronized static void initialize() { 41 | if (initialized) { 42 | return; 43 | } 44 | 45 | Platform.loadNativeLibrary(LIB_NAME, EPoll.class); 46 | 47 | initialized = true; 48 | } 49 | 50 | public static final int EPOLLIN = 0x001; 51 | public static final int EPOLLOUT = 0x004; 52 | 53 | public static native int create(); 54 | 55 | public static native int createEventfd(boolean block); 56 | 57 | public static native void signalEvent(int eventfd, long value) throws LinuxNativeOperationException; 58 | 59 | public static native long clearEvent(int eventfd); 60 | 61 | public static native long newEvents(int maxEvents); 62 | 63 | public static native void freeEvents(long eventsPointer); 64 | 65 | public static native void close(int fd) throws LinuxNativeOperationException; 66 | 67 | public static native void addFileDescriptor(int epollfd, int fd, int interests) throws LinuxNativeOperationException; 68 | 69 | public static native void removeFileDescriptor(int epollfd, int fd) throws LinuxNativeOperationException; 70 | 71 | public static native void updateFileDescriptor(int epollfd, int fd, int interests) throws LinuxNativeOperationException; 72 | 73 | public static native int poll(int epollfd, long eventsPointer, int maxEvents, long timeout) throws LinuxNativeOperationException; 74 | 75 | public static native int extractEvents(long eventsPointer, int n, int[] events, int[] fds); 76 | } 77 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/platform/linux/epoll/EPollException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.platform.linux.epoll; 24 | 25 | import tel.schich.javacan.platform.linux.LinuxNativeOperationException; 26 | import tel.schich.jniaccess.JNIAccess; 27 | 28 | /** 29 | * Signals a low-level error specific to the epoll subsystem. 30 | */ 31 | public class EPollException extends LinuxNativeOperationException { 32 | @JNIAccess 33 | public EPollException(String message, int errorNumber, String errorString) { 34 | super(message, errorNumber, errorString); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/platform/linux/epoll/EPollRegistration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.platform.linux.epoll; 24 | 25 | import tel.schich.javacan.platform.linux.UnixFileDescriptor; 26 | import tel.schich.javacan.select.SelectorRegistration; 27 | 28 | import java.nio.channels.Channel; 29 | import java.util.Collections; 30 | import java.util.EnumSet; 31 | import java.util.Set; 32 | 33 | /** 34 | * This class implements the {@link SelectorRegistration} API necessary for 35 | * {@link tel.schich.javacan.select.IOSelector}s. 36 | */ 37 | final public class EPollRegistration implements SelectorRegistration { 38 | 39 | private final EPollSelector selector; 40 | private final ChannelType channel; 41 | private final UnixFileDescriptor handle; 42 | private final Set operations; 43 | 44 | /** 45 | * Creates a new selection key given an {@link EPollSelector}, 46 | * a {@link java.nio.channels.SelectableChannel}, the underlying socket file descriptor and the interested ops. 47 | * @param selector the selector 48 | * @param channel the channel 49 | * @param handle the underlying socket file descriptor 50 | * @param operations the interested ops 51 | */ 52 | public EPollRegistration(EPollSelector selector, ChannelType channel, UnixFileDescriptor handle, Set operations) { 53 | this.selector = selector; 54 | this.channel = channel; 55 | this.handle = handle; 56 | this.operations = Collections.unmodifiableSet(EnumSet.copyOf(operations)); 57 | } 58 | 59 | /** 60 | * Returns the underlying file descriptor. 61 | * 62 | * @return the underlying file descriptor 63 | */ 64 | public UnixFileDescriptor getHandle() { 65 | return handle; 66 | } 67 | 68 | public ChannelType getChannel() { 69 | return channel; 70 | } 71 | 72 | @Override 73 | public EPollSelector getSelector() { 74 | return selector; 75 | } 76 | 77 | public synchronized Set getOperations() { 78 | return operations; 79 | } 80 | 81 | @Override 82 | public boolean equals(Object o) { 83 | if (this == o) 84 | return true; 85 | if (o == null || getClass() != o.getClass()) 86 | return false; 87 | return handle == ((EPollRegistration) o).handle; 88 | } 89 | 90 | @Override 91 | public int hashCode() { 92 | return handle.hashCode(); 93 | } 94 | 95 | @Override 96 | public String toString() { 97 | return "EPollRegistration(" + 98 | "selector=" + selector + 99 | ", channel=" + channel + 100 | ", fd=" + handle + 101 | ", operations=" + operations + 102 | ')'; 103 | } 104 | 105 | @Override 106 | public void close() throws Exception { 107 | getSelector().cancel(this); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/platform/linux/epoll/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | @NonNullByDefault 24 | package tel.schich.javacan.platform.linux.epoll; 25 | 26 | import org.eclipse.jdt.annotation.NonNullByDefault; 27 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/select/IOEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.select; 24 | 25 | import java.util.Objects; 26 | import java.util.Set; 27 | 28 | /** 29 | * This class represents an IO event that happened on a selected channel, which is a tuple consisting 30 | * of the {@link SelectorRegistration} and a set of {@link tel.schich.javacan.select.SelectorRegistration.Operation}s 31 | * that can be performed now. 32 | * 33 | * @param The type of the resource handle 34 | */ 35 | final public class IOEvent { 36 | private final SelectorRegistration registration; 37 | private final Set operations; 38 | 39 | public IOEvent(SelectorRegistration registration, Set operations) { 40 | this.registration = registration; 41 | this.operations = operations; 42 | } 43 | 44 | /** 45 | * The registration this event belongs to. 46 | * The channel type is not statically known at this point. 47 | * 48 | * @return the registration 49 | */ 50 | public SelectorRegistration getRegistration() { 51 | return registration; 52 | } 53 | 54 | /** 55 | * The operations that can be performed now. 56 | * 57 | * @return a set of operations 58 | */ 59 | public Set getOperations() { 60 | return operations; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return "IOEvent(" + 66 | "registration=" + registration + 67 | ", operations=" + operations + 68 | ')'; 69 | } 70 | 71 | @Override 72 | public boolean equals(Object o) { 73 | if (this == o) return true; 74 | if (o == null || getClass() != o.getClass()) return false; 75 | IOEvent ioEvent = (IOEvent) o; 76 | return registration.equals(ioEvent.registration) && 77 | operations.equals(ioEvent.operations); 78 | } 79 | 80 | @Override 81 | public int hashCode() { 82 | return Objects.hash(registration, operations); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/select/SelectorRegistration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.select; 24 | 25 | import java.nio.channels.Channel; 26 | import java.util.Set; 27 | 28 | /** 29 | * This interfaces describes a registration of a certain {@link Channel} to a certain {@link IOSelector}. 30 | * 31 | * @param The type of the resource handle 32 | * @param The type pf the channel 33 | */ 34 | public interface SelectorRegistration extends AutoCloseable { 35 | /** 36 | * The handle of the resources being selected. 37 | * 38 | * @return the handle 39 | */ 40 | HandleType getHandle(); 41 | 42 | /** 43 | * The selector that issued this registration. 44 | * 45 | * @return the selector 46 | */ 47 | IOSelector getSelector(); 48 | 49 | /** 50 | * The channel which was registered. 51 | * 52 | * @return the channel 53 | */ 54 | ChannelType getChannel(); 55 | 56 | /** 57 | * The operations this registration is interested in. 58 | * This value might not reflect updates of the registration at a later point in time! 59 | * 60 | * @return the set of operations this registration is interested in 61 | */ 62 | Set getOperations(); 63 | 64 | /** 65 | * A channel operation that can be selected on. 66 | */ 67 | enum Operation { 68 | /** 69 | * The channel can be read. 70 | */ 71 | READ, 72 | /** 73 | * The channel can be written. 74 | */ 75 | WRITE, 76 | /** 77 | * The channel can accept a connection. 78 | */ 79 | ACCEPT, 80 | /** 81 | * The channel can connect. 82 | */ 83 | CONNECT 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/select/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | @NonNullByDefault 24 | package tel.schich.javacan.select; 25 | 26 | import org.eclipse.jdt.annotation.NonNullByDefault; 27 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/util/CopyingFrameHandlerProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.util; 24 | 25 | import tel.schich.javacan.CanFrame; 26 | import tel.schich.javacan.RawCanChannel; 27 | 28 | /** 29 | * This simple {@link FrameHandler} proxy implementation copies the 30 | * {@link CanFrame} that is based on a shared buffer. 31 | * Copying the frame should be avoided if possible, but in some cases it is necessary, this proxy makes 32 | * sure the consumer can't accidentally forget to copy it. 33 | */ 34 | public class CopyingFrameHandlerProxy implements FrameHandler { 35 | private final FrameHandler delegate; 36 | 37 | public CopyingFrameHandlerProxy(FrameHandler delegate) { 38 | this.delegate = delegate; 39 | } 40 | 41 | @Override 42 | public void handle(RawCanChannel ch, CanFrame frame) { 43 | delegate.handle(ch, frame.copy()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/util/CopyingMessageHandlerProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.util; 24 | 25 | import tel.schich.javacan.IsotpCanChannel; 26 | 27 | import java.nio.ByteBuffer; 28 | 29 | /** 30 | * This simple {@link MessageHandler} proxy implementation copies the 31 | * shared read-only buffer passed in by the event loop into a new buffer that is also writable. 32 | * Copying the buffer should be avoided if possible, but in some cases it is necessary, this proxy makes 33 | * sure the consumer can't accidentally forget to copy it. 34 | */ 35 | final public class CopyingMessageHandlerProxy implements MessageHandler { 36 | private final MessageHandler delegate; 37 | 38 | public CopyingMessageHandlerProxy(MessageHandler delegate) { 39 | this.delegate = delegate; 40 | } 41 | 42 | @Override 43 | public void handle(IsotpCanChannel ch, ByteBuffer buffer) { 44 | ByteBuffer copy = ByteBuffer.allocate(buffer.remaining()); 45 | copy.put(buffer); 46 | copy.flip(); 47 | delegate.handle(ch, copy); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/util/FrameHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.util; 24 | 25 | import tel.schich.javacan.CanFrame; 26 | import tel.schich.javacan.RawCanChannel; 27 | 28 | /** 29 | * Frame handlers are called by a {@link tel.schich.javacan.util.CanBroker} for each {@link tel.schich.javacan.CanFrame} 30 | * received by the {@link tel.schich.javacan.RawCanChannel} it has been added with. 31 | */ 32 | @FunctionalInterface 33 | public interface FrameHandler { 34 | /** 35 | * Handles a received frame. 36 | * 37 | * @param ch the channel that received the frame 38 | * @param frame the frame that has been received 39 | */ 40 | void handle(RawCanChannel ch, CanFrame frame); 41 | } 42 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/util/MessageHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.util; 24 | 25 | import java.nio.ByteBuffer; 26 | 27 | import tel.schich.javacan.IsotpCanChannel; 28 | 29 | /** 30 | * Message handlers are called by a {@link tel.schich.javacan.util.IsotpListener} for each message received by the 31 | * {@link tel.schich.javacan.IsotpCanChannel} it was added with. 32 | */ 33 | @FunctionalInterface 34 | public interface MessageHandler { 35 | /** 36 | * Handles a received message. The given {@link java.nio.ByteBuffer} is read-only and its position and limit is set, 37 | * so the message can be read from it. 38 | * 39 | * @param ch the channel that received the message 40 | * @param buffer the buffer containing the message 41 | */ 42 | void handle(IsotpCanChannel ch, ByteBuffer buffer); 43 | } 44 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/util/PollExceptionHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.util; 24 | 25 | /** 26 | * Implementations of this interface are used to handle exceptions in a polling event loop. 27 | */ 28 | @FunctionalInterface 29 | public interface PollExceptionHandler { 30 | /** 31 | * handles an exception thrown in the event loop on the given thread. 32 | * 33 | * @param thread the thread the exception originated from 34 | * @param t the exception 35 | * @param terminal if the exception terminates the event loop 36 | * @return true if the event loop should terminate (will be ignored if terminal is true) 37 | */ 38 | boolean handle(Thread thread, Throwable t, boolean terminal); 39 | } -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/util/PollFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.util; 24 | 25 | import java.time.Duration; 26 | 27 | /** 28 | * This interface abstracts the actual polling out of the {@link tel.schich.javacan.util.PollingThread}. 29 | * An implementation should simply call {@link java.nio.channels.Selector#select(long)} or 30 | * {@link java.util.concurrent.BlockingQueue#poll(long, java.util.concurrent.TimeUnit)}, as long as it can be passed 31 | * a timeout in milliseconds. 32 | */ 33 | @FunctionalInterface 34 | public interface PollFunction { 35 | /** 36 | * Should invoke a blocking operation with the given timeout. 37 | * 38 | * @param timeout the timeout in milliseconds 39 | * @return true if the event loop should continue 40 | * @throws Exception the function may throw any {@link java.lang.Exception}, they will be handled upstream 41 | */ 42 | boolean poll(Duration timeout) throws Exception; 43 | } 44 | -------------------------------------------------------------------------------- /epoll/src/main/java/tel/schich/javacan/util/PollingThread.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.util; 24 | 25 | import java.time.Duration; 26 | import java.util.concurrent.ThreadFactory; 27 | 28 | import tel.schich.javacan.platform.linux.LinuxNativeOperationException; 29 | 30 | final class PollingThread { 31 | private final Poller poller; 32 | private final Thread thread; 33 | 34 | public PollingThread(Poller poller, Thread thread) { 35 | this.poller = poller; 36 | this.thread = thread; 37 | } 38 | 39 | public synchronized void start() { 40 | if (!thread.isAlive()) { 41 | thread.start(); 42 | } 43 | } 44 | 45 | public synchronized void stop() { 46 | this.poller.stop(); 47 | } 48 | 49 | public synchronized void join() throws InterruptedException { 50 | thread.join(); 51 | } 52 | 53 | static PollingThread create(String name, Duration timeout, ThreadFactory factory, PollFunction foo, PollExceptionHandler exceptionHandler) { 54 | Poller p = new Poller(name, timeout, foo, exceptionHandler); 55 | Thread t = factory.newThread(p); 56 | t.setUncaughtExceptionHandler(p); 57 | return new PollingThread(p, t); 58 | } 59 | 60 | final static class Poller implements Runnable, Thread.UncaughtExceptionHandler { 61 | private final String name; 62 | private final Duration timeout; 63 | private final PollFunction foo; 64 | private final PollExceptionHandler exceptionHandler; 65 | 66 | private volatile boolean keepPolling = true; 67 | 68 | Poller(String name, Duration timeout, PollFunction foo, PollExceptionHandler eh) { 69 | this.name = name; 70 | this.timeout = timeout; 71 | this.foo = foo; 72 | exceptionHandler = eh; 73 | } 74 | 75 | void stop() { 76 | keepPolling = false; 77 | } 78 | 79 | @Override 80 | public void run() { 81 | while (keepPolling) { 82 | try { 83 | if (!foo.poll(timeout)) { 84 | break; 85 | } 86 | } catch (Exception e) { 87 | if (!mayRetry(e) && !exceptionHandler.handle(Thread.currentThread(), e, false)) { 88 | throw new RuntimeException("Polling failed", e); 89 | } 90 | } 91 | } 92 | } 93 | 94 | @Override 95 | public void uncaughtException(Thread thread, Throwable t) { 96 | exceptionHandler.handle(thread, t, true); 97 | } 98 | 99 | private boolean mayRetry(Exception e) { 100 | if (e instanceof LinuxNativeOperationException) { 101 | return ((LinuxNativeOperationException) e).mayTryAgain(); 102 | } 103 | return false; 104 | } 105 | 106 | @Override 107 | public String toString() { 108 | return name; 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /epoll/src/test/java/tel/schich/javacan/test/util/CanBrokerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.test.util; 24 | 25 | import org.junit.jupiter.api.Test; 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | import tel.schich.javacan.CanFilter; 29 | import tel.schich.javacan.CanFrame; 30 | import tel.schich.javacan.platform.linux.epoll.EPollSelector; 31 | import tel.schich.javacan.test.CanTestHelper; 32 | import tel.schich.javacan.util.CanBroker; 33 | 34 | import java.io.IOException; 35 | import java.util.concurrent.CompletableFuture; 36 | import java.util.concurrent.ThreadFactory; 37 | 38 | import static java.util.concurrent.TimeUnit.SECONDS; 39 | import static org.junit.jupiter.api.Assertions.*; 40 | 41 | class CanBrokerTest { 42 | private static final Logger LOGGER = LoggerFactory.getLogger(CanBrokerTest.class); 43 | 44 | private static final ThreadFactory FACTORY = r -> { 45 | Thread t = new Thread(r); 46 | t.setName("can-broker-test" + Math.random()); 47 | return t; 48 | }; 49 | 50 | @Test 51 | void testLoopback() throws Exception { 52 | final int id = 0x7E0; 53 | CanFrame expected = CanFrame.create(id, CanFrame.FD_NO_FLAGS, new byte[]{1, 2, 3}); 54 | CanFilter filter = new CanFilter(id); 55 | 56 | CanBroker brokerA = new CanBroker(FACTORY, EPollSelector.open()); 57 | CanBroker brokerB = new CanBroker(FACTORY, EPollSelector.open()); 58 | 59 | brokerA.addFilter(filter); 60 | brokerB.addFilter(filter); 61 | 62 | CompletableFuture f = new CompletableFuture<>(); 63 | brokerA.addDevice(CanTestHelper.CAN_INTERFACE, (dev, frame) -> { 64 | f.complete(frame); 65 | try { 66 | brokerA.removeDevice(CanTestHelper.CAN_INTERFACE); 67 | } catch (IOException e) { 68 | fail("Removing the device from brokerA should not fail: " + e.getLocalizedMessage()); 69 | } 70 | }); 71 | 72 | brokerB.addDevice(CanTestHelper.CAN_INTERFACE, (d, frame) -> LOGGER.debug(String.valueOf(frame))); 73 | brokerB.send(expected); 74 | 75 | CanFrame actual = f.get(2, SECONDS); 76 | assertNotNull(actual, "CAN frame should have been captured!"); 77 | 78 | assertEquals(expected, actual, "What goes in should come out!"); 79 | } 80 | 81 | @Test 82 | void testExternal() throws Exception { 83 | 84 | final int id = 0x7E0; 85 | CanFrame expected = CanFrame.create(id, CanFrame.FD_NO_FLAGS, new byte[]{1, 2, 3}); 86 | CompletableFuture f = new CompletableFuture<>(); 87 | 88 | CanBroker can = new CanBroker(FACTORY, EPollSelector.open()); 89 | can.addFilter(new CanFilter(id)); 90 | can.addDevice(CanTestHelper.CAN_INTERFACE, (ch, frame) -> f.complete(frame)); 91 | 92 | CanTestHelper.sendFrameViaUtils(CanTestHelper.CAN_INTERFACE, expected); 93 | 94 | CanFrame actual = f.get(2, SECONDS); 95 | 96 | assertNotNull(actual, "CAN frame should have been captured!"); 97 | assertEquals(expected, actual, "What goes in should come out!"); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.configuration-cache=true 2 | org.gradle.parallel=true 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pschichtel/JavaCAN/63139105abc14ae5da09477d36a6c770843bc0bf/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "customManagers": [ 4 | { 5 | "fileMatch": ["^conventions/src/main/kotlin/tel\\.schich\\.javacan\\.convention\\.native\\.gradle\\.kts$"], 6 | "matchStrings": [ 7 | "dockcrossVersion\\s*=\\s*\"(?[^\"]+)\"" 8 | ], 9 | // this is hardcoded to linux-x64, but the tag would normally be aligned anyway 10 | "depNameTemplate": "docker.io/dockcross/linux-x64", 11 | "datasourceTemplate": "docker", 12 | "versioningTemplate": "loose", 13 | } 14 | ], 15 | } 16 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "javacan" 2 | 3 | pluginManagement { 4 | includeBuild("conventions") 5 | } 6 | 7 | plugins { 8 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0" 9 | } 10 | 11 | include("core") 12 | include("core-arch-detect") 13 | 14 | include("epoll") 15 | include("epoll-arch-detect") 16 | 17 | include("tools") 18 | -------------------------------------------------------------------------------- /setup-vcan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | sudo modprobe vcan can_raw can_bcm can_j1939 6 | 7 | interface_name="${1:-vcan0}" 8 | 9 | sudo ip link add dev "$interface_name" type vcan 10 | sudo ip link set up "$interface_name" 11 | 12 | if ! sudo modprobe can_isotp 13 | then 14 | echo "Failed to load the ISOTP module, related unit tests will probably fail" 15 | fi 16 | -------------------------------------------------------------------------------- /tools/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("tel.schich.javacan.convention.published") 3 | } 4 | 5 | dependencies { 6 | implementation(project(":core-arch-detect")) 7 | } 8 | 9 | tasks.withType().configureEach { 10 | enabled = false 11 | } 12 | 13 | publishing.publications.withType().configureEach { 14 | pom { 15 | description = "${rootProject.description} The ${project.name} module contains tools to work with socketcan and related tooling." 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tools/src/main/java/tel/schich/javacan/tools/CanDumpConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package tel.schich.javacan.tools; 24 | 25 | import java.io.BufferedReader; 26 | import java.io.BufferedWriter; 27 | import java.io.FileReader; 28 | import java.io.FileWriter; 29 | import java.io.IOException; 30 | import java.text.DateFormat; 31 | import java.text.ParseException; 32 | import java.text.SimpleDateFormat; 33 | import java.util.regex.Matcher; 34 | import java.util.regex.Pattern; 35 | 36 | /** 37 | * Converts a human-readable CAN dump into a {@code canplayer} replayable format. 38 | * Such a dump may have be created from the output of {@code candump} with the parameter {@code -t A} 39 | *

40 | * The input lines are transformed from
41 | * {@code " (2019-12-11 17:26:46.545849) can0 301 [8] 08 4C 01 4E 02 C2 0C 5C"}
42 | * to
43 | * {@code "(1576495052.545849) can0 301#084C014E02C20C5C"} 44 | *

45 | * The resulting dump can be replayed with the {@code canplayer} from the {@code can-utils} package. 46 | * 47 | * @author Maik Scheibler 48 | */ 49 | public class CanDumpConverter { 50 | 51 | private static final Pattern LINEPATTERN = Pattern.compile( 52 | " \\((\\d+-\\d+-\\d+ \\d+:\\d+:\\d+)(\\.\\d+)\\)\\s+(\\w+)\\s+(\\w+)\\s+\\[\\d]\\s+(.+)"); 53 | private static final DateFormat DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 54 | 55 | public static void main(String[] args) throws IOException, ParseException { 56 | if (args.length < 2) { 57 | System.out.println("usage: CANDumpConverter "); 58 | } 59 | 60 | try (BufferedReader reader = new BufferedReader(new FileReader(args[0]))) { 61 | try (BufferedWriter writer = new BufferedWriter(new FileWriter(args[1]))) { 62 | String line; 63 | while ((line = reader.readLine()) != null) { 64 | processLine(line, writer); 65 | } 66 | } 67 | } 68 | } 69 | 70 | private static void processLine(String line, BufferedWriter writer) throws ParseException, IOException { 71 | Matcher matcher = LINEPATTERN.matcher(line); 72 | if (!matcher.matches()) { 73 | System.out.println("ignoring line: " + line); 74 | return; 75 | } 76 | String builder = "(" + DATEFORMAT.parse(matcher.group(1)).getTime() / 1000 + // UNIX timestamp seconds 77 | matcher.group(2) + ") " + // microseconds 78 | matcher.group(3) + ' ' + // CAN interface 79 | matcher.group(4) + '#' + // CAN ID 80 | matcher.group(5).replaceAll("\\s", ""); // data bytes 81 | writer.write(builder); 82 | writer.newLine(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tools/src/main/java/tel/schich/javacan/tools/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * Copyright © 2018 Phillip Schichtel 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | 24 | /** 25 | * This package contains standalone runnable CAN related tools, mostly for development purposes. 26 | */ 27 | @NonNullByDefault 28 | package tel.schich.javacan.tools; 29 | 30 | import org.eclipse.jdt.annotation.NonNullByDefault; 31 | --------------------------------------------------------------------------------