├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── artnet.gif ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── javadoc.args ├── lib ├── build.gradle └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── deltaeight │ │ │ └── libartnet │ │ │ ├── builders │ │ │ ├── ArtDmxBuilder.java │ │ │ ├── ArtNetPacketBuilder.java │ │ │ ├── ArtPollBuilder.java │ │ │ ├── ArtPollReplyBuilder.java │ │ │ └── ArtTimeCodeBuilder.java │ │ │ ├── descriptors │ │ │ ├── ArtNet.java │ │ │ ├── EquipmentStyle.java │ │ │ ├── IndicatorState.java │ │ │ ├── InputStatus.java │ │ │ ├── OemCode.java │ │ │ ├── OpCode.java │ │ │ ├── OutputStatus.java │ │ │ ├── PortAddressingAuthority.java │ │ │ ├── PortStatus.java │ │ │ ├── PortType.java │ │ │ ├── Priority.java │ │ │ ├── Product.java │ │ │ └── TimeCodeType.java │ │ │ ├── network │ │ │ ├── ArtNetReceiver.java │ │ │ ├── ArtNetSender.java │ │ │ ├── ExceptionHandler.java │ │ │ ├── NetworkHandler.java │ │ │ ├── PacketReceiveDispatcher.java │ │ │ └── PacketReceiveHandler.java │ │ │ └── packets │ │ │ ├── ArtDmx.java │ │ │ ├── ArtNetPacket.java │ │ │ ├── ArtPoll.java │ │ │ ├── ArtPollReply.java │ │ │ └── ArtTimeCode.java │ └── resources │ │ └── de │ │ └── deltaeight │ │ └── libartnet │ │ └── descriptors │ │ └── OemCodes.json │ └── test │ └── java │ └── de │ └── deltaeight │ └── libartnet │ ├── builders │ ├── AbstractPacketBuilderTest.java │ ├── ArtDmxBuilderTest.java │ ├── ArtPollBuilderTest.java │ ├── ArtPollReplyBuilderTest.java │ └── ArtTimeCodeBuilderTest.java │ ├── doc │ ├── Receiver.java │ └── Sender.java │ └── network │ ├── AbstractNetworkHandlerTest.java │ ├── ArtNetReceiverTest.java │ ├── ArtNetSenderTest.java │ ├── DatagramSocketMockup.java │ └── NetworkPacketIntegrityTest.java ├── maven-key.gpg.enc ├── settings.gradle └── util ├── build.gradle └── src └── main └── java └── de └── deltaeight └── libartnet └── util └── OemJsonGenerator.java /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Code examples** 21 | Add code examples to help us understand your problem. 22 | 23 | **System:** 24 | - OS: [e.g. Windows 10 Pro] 25 | - JDK/JRE Version 26 | - Library version / last tested commit 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | .gradle 3 | build 4 | 5 | # IntelliJ project files 6 | .idea 7 | *.iml 8 | out 9 | gen 10 | 11 | # VSCode project files 12 | bin/ 13 | .settings 14 | .classpath 15 | .project 16 | 17 | 18 | # Misc 19 | /util/src/main/resources/de/deltaeight/libartnet/util/Art-NetOemCodes.h 20 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: gradle:jdk8 2 | 3 | variables: 4 | GRADLE_USER_HOME: $CI_PROJECT_DIR/.gradle 5 | 6 | cache: 7 | key: $CI_PROJECT_NAME 8 | paths: 9 | - .gradle/caches/ 10 | - .gradle/wrapper/ 11 | 12 | test: 13 | stage: test 14 | script: ./gradlew check -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | install: true 3 | 4 | jdk: 5 | - openjdk8 6 | 7 | stages: 8 | - test 9 | - name: deploy 10 | if: type = push AND tag IS present 11 | 12 | jobs: 13 | include: 14 | - stage: test 15 | script: "./gradlew check" 16 | - stage: deploy 17 | script: 18 | - "openssl aes-256-cbc -K $encrypted_0d982abece1d_key -iv $encrypted_0d982abece1d_iv -in maven-key.gpg.enc -out maven-key.gpg -d" 19 | - "./gradlew publish" 20 | on: 21 | branch: master 22 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at julian@deltaeight.de. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | Great that you are here and want to help! 4 | 5 | ## Documentation 6 | 7 | LibArtNet uses Javadoc comment blocks for documentation of the API. This should include a brief explanation of what 8 | classes/methods do and how to use them. You can also include the `@author`-tag if you wish. 9 | 10 | Please don't forget to describe what values are expected by methods and what they throw (and why). 11 | 12 | ## Testing 13 | 14 | LibArtNet uses [JUnit 5](https://junit.org/junit5/) as its Java test framework. Please make sure to write useful test 15 | cases for code you create. This ensures reliability and integrity of the library. 16 | 17 | ## Submitting changes 18 | 19 | When you want to submit code changes, please create a pull request including a clear list of what you changed. It would 20 | also be great if you could test as much as possible, the more coverage the better. 21 | 22 | Please follow the coding conventions below and try to add clear log messages to your commits. 23 | 24 | ## Coding conventions 25 | 26 | Nothing fancy here and you should get your head around it real quickly. 27 | 28 | * Intend using four spaces, **not tabs**! 29 | * Use `camelCase` rather than `snake_case`. 30 | * Classes start with a capital letter, variables don't. Constants are in `UPPER_CASE`. 31 | * Use lambda code whereever possible. 32 | * Opening braces belong in the same line. 33 | 34 | Thanks for reading! -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Julian Rabe 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. -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### General: 4 | 5 | * [ ] I followed the guidelines in the Contributing document 6 | * [ ] I have checked to ensure there aren't other open [Pull Requests](../../pulls) for the same update/change 7 | * [ ] I have written new tests for my core changes, as applicable 8 | * [ ] My submission passes new and existing tests 9 | * [ ] I have updated the documentation accordingly 10 | 11 | ### Type of changes ? 12 | * [ ] Bugfix 13 | * [ ] New feature, doesn't change API 14 | * [ ] New feature, adds to API but doesn't change old API 15 | * [ ] New feature, changes old API 16 | 17 | ### Changes by this PR 18 | 19 | ### Current behaviour 20 | 21 | 22 | 23 | ### New behaviour 24 | 25 | ### Other information 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LibArtNet [![Maven Central](https://img.shields.io/maven-central/v/de.deltaeight/LibArtNet.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22de.deltaeight%22%20AND%20a:%22LibArtNet%22) [![Javadocs](http://www.javadoc.io/badge/de.deltaeight/LibArtNet.svg?color=blue)](http://www.javadoc.io/doc/de.deltaeight/LibArtNet) [![Build Status](https://travis-ci.com/deltaeight/LibArtNet.svg?branch=master)](https://travis-ci.com/deltaeight/LibArtNet) 2 | 3 | LibArtNet is a Java implementation of the [Art-Net 4](https://art-net.org.uk) protocol as maintained by 4 | [Artistic License Ltd.](https://artisticlicence.com) 5 | 6 | 7 | **Please have in mind that LibArtNet is still in beta.** 8 | 9 | However, see the [feature list](#features), the [roadmap](#roadmap) and how to [contribute](#contribute) for further 10 | information. If you feel there is something missing that is not listed there, feel free to open an issue. 11 | 12 | ## Features 13 | 14 | * Basic Art-Net receiver 15 | * Basic Art-Net sender 16 | 17 | ### Supported Art-Net packets 18 | 19 | * ArtDmx 20 | * Sequence number 21 | * 15bit universe addressing 22 | * ArtPoll 23 | * unicast 24 | * sending `ArtPollReply` on state changes 25 | * priorities for diagnostic data 26 | * ArtPollReply 27 | * macros 28 | * remotes 29 | * OEM codes (all OEM codes built in) 30 | * short/long names 31 | * equipment styles 32 | * much more 33 | * ArtTimeCode 34 | * 24/25/29.97/30 fps 35 | 36 | ## Roadmap 37 | 38 | Planned features are 39 | 40 | * Art-Net controller, an abstraction layer using the existing receiver and sender to act as a console 41 | * Art-Net node, an abstraction layer using the existing receiver and sender to act as a node 42 | * RDM support 43 | 44 | ## Usage 45 | 46 | All classes are documented using [Javadoc](https://javadoc.io/doc/de.deltaeight/LibArtNet). However, if there is 47 | something missing or unclear, feel free to open an issue. 48 | 49 | ### Requirements 50 | 51 | * Java 1.8 or higher 52 | * Gradle if you want to compile from source 53 | 54 | ### Installation 55 | 56 | LibArtNet is available on [Maven Central](https://search.maven.org/search?q=g:%22de.deltaeight%22%20AND%20a:%22LibArtNet%22) 57 | and on the [release page](../../releases). 58 | 59 | #### Maven 60 | 61 | Add this dependency to `pom.xml`: 62 | 63 | ```xml 64 | 65 | de.deltaeight 66 | LibArtNet 67 | 1.1.2-beta 68 | 69 | ``` 70 | 71 | #### Gradle 72 | 73 | Add this to `build.gradle`: 74 | 75 | ```groovy 76 | dependencies { 77 | implementation 'de.deltaeight:LibArtNet:1.1.2-beta' 78 | } 79 | ``` 80 | 81 | ### Compiling from source 82 | 83 | To build a `.jar` file to use in your IDE, run 84 | 85 | ```bash 86 | ./gradlew :lib:jar 87 | ``` 88 | 89 | ### Usage examples 90 | 91 | #### Using the receiver 92 | 93 | The receiver needs receive handlers which are called when the appropriate packet is received: 94 | 95 | ```java 96 | ArtNetReceiver receiver = new ArtNetReceiver() 97 | .withArtDmxReceiveHandler(packet -> System.out.println("Channel 63 value: " + packet.getData()[62])); 98 | 99 | receiver.start(); 100 | 101 | // Do other stuff 102 | 103 | receiver.stop(); 104 | ``` 105 | 106 | #### Using the sender 107 | 108 | The sender needs Art-Net packets to send, therefore we need a builder instance for the desired packets first: 109 | 110 | ```java 111 | ArtPollReplyBuilder builder = new ArtPollReplyBuilder() 112 | // report as Robert Juliat Dalis Reference : 860 113 | .withProduct(OemCode.getProductByOemCode("OemRobertJulDalis1")) 114 | .withBindIp(new byte[]{127, 0, 0, 1}); 115 | 116 | ArtNetSender sender = new ArtNetSender(); 117 | sender.start(); 118 | 119 | sender.send(InetAddress.getByName("127.0.0.1"), builder.build()); 120 | 121 | // Do other stuff 122 | 123 | sender.stop(); 124 | ``` 125 | 126 | ## Contribute 127 | 128 | Your contribution is more than welcome! 129 | 130 | If you'd like to contribute, every help is much appreciated. Feel free to fork, create pull requests and open issues for 131 | bugs or feature requests. 132 | 133 | For bug reports, feature requests and pull requests there are templates that you can just fill out to provide us with 134 | the required information. 135 | 136 | Please have a look at the [contribution guide](CONTRIBUTING.md) and the [code of conduct](CODE_OF_CONDUCT.md) before 137 | you contribute. 138 | 139 | ## License 140 | 141 | LibArtNet is licensed under the MIT License. See [LICENSE.md](LICENSE.md) for details. 142 | -------------------------------------------------------------------------------- /artnet.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deltaeight/LibArtNet/90e4b834b44de6740cec11e2021bb61c05c447f4/artnet.gif -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | mavenCentral() 4 | } 5 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deltaeight/LibArtNet/90e4b834b44de6740cec11e2021bb61c05c447f4/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jul 02 18:14:44 CEST 2020 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /javadoc.args: -------------------------------------------------------------------------------- 1 | -protected 2 | -splitindex 3 | -author 4 | -version 5 | -sourcepath lib/src/main/java 6 | -subpackages de.deltaeight.libartnet -------------------------------------------------------------------------------- /lib/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'maven-publish' 4 | id 'signing' 5 | } 6 | 7 | group 'de.deltaeight' 8 | version '1.1.2-beta' 9 | 10 | sourceCompatibility = 1.8 11 | targetCompatibility = 1.8 12 | 13 | dependencies { 14 | 15 | implementation 'com.google.code.gson:gson:2.8.6' 16 | 17 | // Test framework 18 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2' 19 | testImplementation 'org.hamcrest:hamcrest:2.2' 20 | 21 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.2' 22 | } 23 | 24 | test { 25 | useJUnitPlatform() 26 | testLogging { 27 | events 'passed', 'skipped', 'failed' 28 | exceptionFormat 'full' 29 | } 30 | } 31 | 32 | java { 33 | withJavadocJar() 34 | withSourcesJar() 35 | } 36 | 37 | publishing { 38 | publications { 39 | mavenJava(MavenPublication) { 40 | 41 | from components.java 42 | 43 | pom { 44 | name = project.getName() 45 | description = 'Art-Net 4 protocol implementation in Java' 46 | url = 'https://github.com/deltaeight/LibArtNet' 47 | 48 | licenses { 49 | license { 50 | name = 'The MIT License' 51 | url = 'https://opensource.org/licenses/mit-license.php' 52 | } 53 | } 54 | 55 | developers { 56 | developer { 57 | id = 'schw4rzlicht' 58 | name = 'Julian Rabe' 59 | email = 'julian@deltaeight.de' 60 | } 61 | } 62 | 63 | scm { 64 | connection = 'scm:https://github.com/deltaeight/LibArtNet.git' 65 | developerConnection = 'scm:https://github.com/deltaeight/LibArtNet.git' 66 | url = 'https://github.com/deltaeight/LibArtNet' 67 | } 68 | } 69 | } 70 | } 71 | 72 | repositories { 73 | maven { 74 | def releasesRepoUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' 75 | def snapshotsRepoUrl = 'https://oss.sonatype.org/content/repositories/snapshots/' 76 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl 77 | credentials { 78 | username = System.getenv('MAVEN_REPO_USER') 79 | password = System.getenv('MAVEN_REPO_PASSWORD') 80 | } 81 | } 82 | } 83 | } 84 | 85 | gradle.taskGraph.whenReady { taskGraph -> 86 | if (taskGraph.allTasks.any { it instanceof Sign }) { 87 | allprojects { ext."signing.keyId" = System.getenv('MAVEN_SIGNING_KEY_ID') } 88 | allprojects { ext."signing.secretKeyRingFile" = '../maven-key.gpg' } 89 | allprojects { ext."signing.password" = System.getenv('MAVEN_SIGNING_KEY_PASSWORD') } 90 | } 91 | if (taskGraph.allTasks.any { it.name == 'build' || it.name == 'assemble' }) { 92 | tasks.findAll { it.name == 'signArchives' || it.name == 'signDocsJar' || it.name == 'signTestJar' }.each { task -> 93 | task.enabled = false 94 | } 95 | } 96 | } 97 | 98 | signing { 99 | sign publishing.publications.mavenJava 100 | } -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/builders/ArtDmxBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.builders; 23 | 24 | import java.util.Arrays; 25 | 26 | import de.deltaeight.libartnet.descriptors.ArtNet; 27 | import de.deltaeight.libartnet.descriptors.OpCode; 28 | import de.deltaeight.libartnet.packets.ArtDmx; 29 | 30 | /** 31 | * Builds instances of {@link ArtDmx}. 32 | *

33 | * See the Art-Net Specification for details. 34 | * 35 | * @author Julian Rabe 36 | * @see ArtDmx 37 | * @see Art-Net Specification 38 | */ 39 | public class ArtDmxBuilder extends ArtNetPacketBuilder { 40 | 41 | private static final byte[] OP_CODE_BYTES = OpCode.OpDmx.getBytesLittleEndian(); 42 | private final byte[] data; 43 | private int sequence; 44 | private int physical; 45 | private int subnetAddress; 46 | private int universeAddress; 47 | private int netAddress; 48 | private int dataSize; 49 | 50 | private boolean changed; 51 | private ArtDmx artDmx; 52 | 53 | public ArtDmxBuilder() { 54 | data = new byte[512]; 55 | changed = true; 56 | } 57 | 58 | /** 59 | * {@inheritDoc} 60 | * 61 | * @return {@link ArtDmx} instance. 62 | * @see ArtNetPacketBuilder#build() 63 | */ 64 | @Override 65 | public ArtDmx build() { 66 | 67 | if (changed) { 68 | 69 | if (dataSize % 2 > 0) { 70 | data[dataSize++] = 0x00; 71 | } 72 | 73 | byte[] bytes = new byte[18 + dataSize]; 74 | 75 | System.arraycopy(ArtNet.HEADER.getBytes(), 0, bytes, 0, 8); 76 | System.arraycopy(OP_CODE_BYTES, 0, bytes, 8, 2); 77 | System.arraycopy(ArtNet.PROTOCOL_REVISION.getBytes(), 0, bytes, 10, 2); 78 | 79 | bytes[12] = (byte) sequence; 80 | bytes[13] = (byte) physical; 81 | bytes[14] = (byte) (subnetAddress << 4 | universeAddress); 82 | bytes[15] = (byte) netAddress; 83 | bytes[16] = (byte) (dataSize >> 8); 84 | bytes[17] = (byte) dataSize; 85 | 86 | System.arraycopy(data, 0, bytes, 18, dataSize); 87 | 88 | artDmx = new ArtDmx(sequence, physical, netAddress, subnetAddress, universeAddress, 89 | Arrays.copyOfRange(data, 0, dataSize), bytes); 90 | 91 | changed = false; 92 | } 93 | 94 | return artDmx; 95 | } 96 | 97 | /** 98 | * {@inheritDoc} 99 | * 100 | * @return {@link ArtDmx} instance. 101 | * @see ArtNetPacketBuilder#build() 102 | */ 103 | @Override 104 | public ArtDmx buildFromBytes(byte[] packetData) { 105 | if (packetData[8] == OP_CODE_BYTES[0] && packetData[9] == OP_CODE_BYTES[1]) { 106 | 107 | byte[] data = new byte[packetData[16] << 8 | packetData[17]]; 108 | System.arraycopy(packetData, 18, data, 0, data.length); 109 | 110 | int subUni = packetData[14]; 111 | 112 | return new ArtDmx(packetData[12] & 0xFF, packetData[13] & 0xFF, packetData[15], (subUni & 0xFF) >>> 4, 113 | subUni & 0xF, data.clone(), packetData.clone()); 114 | } 115 | return null; 116 | } 117 | 118 | public int getSequence() { 119 | return sequence; 120 | } 121 | 122 | public void setSequence(int sequence) { 123 | if (this.sequence != sequence) { 124 | if (0 > sequence || sequence > 255) { 125 | throw new IllegalArgumentException("Illegal sequence number!"); 126 | } 127 | this.sequence = sequence; 128 | changed = true; 129 | } 130 | } 131 | 132 | public ArtDmxBuilder withSequence(int sequence) { 133 | setSequence(sequence); 134 | return this; 135 | } 136 | 137 | public int getPhysical() { 138 | return physical; 139 | } 140 | 141 | public void setPhysical(int physical) { 142 | if (this.physical != physical) { 143 | if (0 > physical || physical > 255) { 144 | throw new IllegalArgumentException("Illegal physical port number!"); 145 | } 146 | this.physical = physical; 147 | changed = true; 148 | } 149 | } 150 | 151 | public ArtDmxBuilder withPhysical(int physical) { 152 | setPhysical(physical); 153 | return this; 154 | } 155 | 156 | public int getSubnetAddress() { 157 | return subnetAddress; 158 | } 159 | 160 | public void setSubnetAddress(int subnetAddress) { 161 | if (this.subnetAddress != subnetAddress) { 162 | if (0 > subnetAddress || subnetAddress > 15) { 163 | throw new IllegalArgumentException("Illegal subnet address!"); 164 | } 165 | this.subnetAddress = subnetAddress; 166 | changed = true; 167 | } 168 | } 169 | 170 | public ArtDmxBuilder withSubnetAddress(int subnetAddress) { 171 | setSubnetAddress(subnetAddress); 172 | return this; 173 | } 174 | 175 | public int getUniverseAddress() { 176 | return universeAddress; 177 | } 178 | 179 | public void setUniverseAddress(int universeAddress) { 180 | if (this.universeAddress != universeAddress) { 181 | if (0 > universeAddress || universeAddress > 15) { 182 | throw new IllegalArgumentException("Illegal universe address!"); 183 | } 184 | this.universeAddress = universeAddress; 185 | changed = true; 186 | } 187 | } 188 | 189 | public ArtDmxBuilder withUniverseAddress(int universeAddress) { 190 | setUniverseAddress(universeAddress); 191 | return this; 192 | } 193 | 194 | public int getNetAddress() { 195 | return netAddress; 196 | } 197 | 198 | public void setNetAddress(int netAddress) { 199 | if (this.netAddress != netAddress) { 200 | if (0 > netAddress || netAddress > 127) { 201 | throw new IllegalArgumentException("Illegal net address!"); 202 | } 203 | this.netAddress = netAddress; 204 | changed = true; 205 | } 206 | } 207 | 208 | public ArtDmxBuilder withNetAddress(int netAddress) { 209 | setNetAddress(netAddress); 210 | return this; 211 | } 212 | 213 | public int getDataSize() { 214 | return dataSize; 215 | } 216 | 217 | public byte[] getData() { 218 | return Arrays.copyOfRange(data, 0, dataSize); 219 | } 220 | 221 | public void setData(byte[] data) { 222 | if (data != null) { 223 | if (data.length > 512) { 224 | throw new IllegalArgumentException("Payload too large!"); 225 | } 226 | 227 | System.arraycopy(data, 0, this.data, 0, data.length); 228 | 229 | dataSize = data.length; 230 | changed = true; 231 | } 232 | } 233 | 234 | public byte getData(int index) { 235 | if (0 > index || index > 511) { 236 | throw new IllegalArgumentException("Illegal data index!"); 237 | } 238 | if (index > dataSize - 1) { 239 | return 0x00; 240 | } 241 | return data[index]; 242 | } 243 | 244 | public void setData(int index, byte data) { 245 | if (0 > index || index > 511) { 246 | throw new IllegalArgumentException("Illegal data index!"); 247 | } 248 | 249 | for (int i = dataSize; i < index; i++) { 250 | this.data[i] = 0x00; 251 | } 252 | 253 | this.data[index] = data; 254 | dataSize = index + 1; 255 | changed = true; 256 | } 257 | 258 | public ArtDmxBuilder withData(byte[] data) { 259 | setData(data); 260 | return this; 261 | } 262 | 263 | public ArtDmxBuilder withData(int index, byte data) { 264 | setData(index, data); 265 | return this; 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/builders/ArtNetPacketBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.builders; 23 | 24 | import de.deltaeight.libartnet.packets.ArtNetPacket; 25 | 26 | /** 27 | * Builder class for {@link ArtNetPacket}s. Can be used to build packets from received payloads. 28 | * 29 | * @param The {@link ArtNetPacket} implementation the implementing builder class is used for. 30 | * @author Julian Rabe 31 | */ 32 | public abstract class ArtNetPacketBuilder { 33 | 34 | /** 35 | * Builds and returns an instance of {@link ArtNetPacket}. 36 | * 37 | * @return {@link ArtNetPacket} instance. 38 | */ 39 | public abstract T build(); 40 | 41 | /** 42 | * Builds and returns an instance of {@link ArtNetPacket}. 43 | * 44 | * @param packetData The payload received via {@code UDP}. 45 | * @return {@link ArtNetPacket} instance. 46 | */ 47 | public abstract T buildFromBytes(byte[] packetData); 48 | } 49 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/builders/ArtPollBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.builders; 23 | 24 | import de.deltaeight.libartnet.descriptors.ArtNet; 25 | import de.deltaeight.libartnet.descriptors.OpCode; 26 | import de.deltaeight.libartnet.descriptors.Priority; 27 | import de.deltaeight.libartnet.packets.ArtPoll; 28 | 29 | /** 30 | * Builds instances of {@link ArtPoll}. 31 | *

32 | * Default diagnose data priority is {@link Priority#Low}. 33 | *

34 | * See the Art-Net Specification for details. 35 | * 36 | * @author Julian Rabe 37 | * @see ArtPoll 38 | * @see Art-Net Specification 39 | */ 40 | public class ArtPollBuilder extends ArtNetPacketBuilder { 41 | 42 | private static final byte[] OP_CODE_BYTES = OpCode.OpPoll.getBytesLittleEndian(); 43 | 44 | private boolean disableVlcTransmission; 45 | private boolean unicastDiagnosticMessages; 46 | private boolean sendDiagnosticMessages; 47 | private boolean sendArtPollReplyOnChanges; 48 | private Priority priority; 49 | 50 | private boolean changed; 51 | private ArtPoll artPoll; 52 | 53 | public ArtPollBuilder() { 54 | priority = Priority.Low; 55 | changed = true; 56 | } 57 | 58 | /** 59 | * {@inheritDoc} 60 | * 61 | * @return {@link ArtPoll} instance. 62 | * @see ArtNetPacketBuilder#build() 63 | */ 64 | @Override 65 | public ArtPoll build() { 66 | if (changed) { 67 | 68 | byte[] bytes = new byte[14]; 69 | System.arraycopy(ArtNet.HEADER.getBytes(), 0, bytes, 0, 8); 70 | System.arraycopy(OP_CODE_BYTES, 0, bytes, 8, 2); 71 | System.arraycopy(ArtNet.PROTOCOL_REVISION.getBytes(), 0, bytes, 10, 2); 72 | 73 | if (disableVlcTransmission) { 74 | bytes[12] |= 0b00010000; 75 | } 76 | if (unicastDiagnosticMessages) { 77 | bytes[12] |= 0b00001000; 78 | } 79 | if (sendDiagnosticMessages) { 80 | bytes[12] |= 0b00000100; 81 | } 82 | if (sendArtPollReplyOnChanges) { 83 | bytes[12] |= 0b00000010; 84 | } 85 | 86 | bytes[13] = priority.getValue(); 87 | 88 | artPoll = new ArtPoll(vlcTransmissionDisabled(), unicastDiagnosticMessages(), sendDiagnosticMessages(), 89 | sendArtPollReplyOnChanges(), getPriority(), bytes.clone()); 90 | 91 | changed = false; 92 | } 93 | 94 | return artPoll; 95 | } 96 | 97 | /** 98 | * {@inheritDoc} 99 | * 100 | * @return {@link ArtPoll} instance. 101 | * @see ArtNetPacketBuilder#build() 102 | */ 103 | @Override 104 | public ArtPoll buildFromBytes(byte[] packetData) { 105 | if (packetData[8] == OP_CODE_BYTES[0] && packetData[9] == OP_CODE_BYTES[1]) { 106 | 107 | return new ArtPoll((packetData[12] & 0b00010000) > 0, (packetData[12] & 0b00001000) > 0, 108 | (packetData[12] & 0b00000100) > 0, (packetData[12] & 0b00000010) > 0, Priority.getPriority(packetData[13]), 109 | packetData.clone()); 110 | } 111 | return null; 112 | } 113 | 114 | public boolean vlcTransmissionDisabled() { 115 | return disableVlcTransmission; 116 | } 117 | 118 | public void setDisableVlcTransmission(boolean disableVlcTransmission) { 119 | if (this.disableVlcTransmission != disableVlcTransmission) { 120 | this.disableVlcTransmission = disableVlcTransmission; 121 | changed = true; 122 | } 123 | } 124 | 125 | public ArtPollBuilder withDisableVlcTransmission(boolean disableVlcTransmission) { 126 | setDisableVlcTransmission(disableVlcTransmission); 127 | return this; 128 | } 129 | 130 | public boolean unicastDiagnosticMessages() { 131 | return unicastDiagnosticMessages; 132 | } 133 | 134 | public void setUnicastDiagnosticMessages(boolean unicastDiagnosticMessages) { 135 | if (this.unicastDiagnosticMessages != unicastDiagnosticMessages) { 136 | this.unicastDiagnosticMessages = unicastDiagnosticMessages; 137 | changed = true; 138 | } 139 | } 140 | 141 | public ArtPollBuilder withUnicastDiagnosticMessages(boolean unicastDiagnosticMessages) { 142 | setUnicastDiagnosticMessages(unicastDiagnosticMessages); 143 | return this; 144 | } 145 | 146 | public boolean sendDiagnosticMessages() { 147 | return sendDiagnosticMessages; 148 | } 149 | 150 | public void setSendDiagnosticMessages(boolean sendDiagnosticMessages) { 151 | if (this.sendDiagnosticMessages != sendDiagnosticMessages) { 152 | this.sendDiagnosticMessages = sendDiagnosticMessages; 153 | changed = true; 154 | } 155 | } 156 | 157 | public ArtPollBuilder withSendDiagnosticMessages(boolean sendDiagnosticMessages) { 158 | setSendDiagnosticMessages(sendDiagnosticMessages); 159 | return this; 160 | } 161 | 162 | public boolean sendArtPollReplyOnChanges() { 163 | return sendArtPollReplyOnChanges; 164 | } 165 | 166 | public void setSendArtPollReplyOnChanges(boolean sendArtPollReplyOnChanges) { 167 | if (this.sendArtPollReplyOnChanges != sendArtPollReplyOnChanges) { 168 | this.sendArtPollReplyOnChanges = sendArtPollReplyOnChanges; 169 | changed = true; 170 | } 171 | } 172 | 173 | public ArtPollBuilder withSendArtPollReplyOnChanges(boolean sendArtPollReplyOnChanges) { 174 | setSendArtPollReplyOnChanges(sendArtPollReplyOnChanges); 175 | return this; 176 | } 177 | 178 | public Priority getPriority() { 179 | return priority; 180 | } 181 | 182 | public void setPriority(Priority priority) { 183 | 184 | if (priority == null) { 185 | priority = Priority.Low; 186 | } 187 | 188 | if (this.priority != priority) { 189 | this.priority = priority; 190 | changed = true; 191 | } 192 | } 193 | 194 | public ArtPollBuilder withPriority(Priority priority) { 195 | setPriority(priority); 196 | return this; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/builders/ArtTimeCodeBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.builders; 23 | 24 | import de.deltaeight.libartnet.descriptors.ArtNet; 25 | import de.deltaeight.libartnet.descriptors.OpCode; 26 | import de.deltaeight.libartnet.descriptors.TimeCodeType; 27 | import de.deltaeight.libartnet.packets.ArtPoll; 28 | import de.deltaeight.libartnet.packets.ArtTimeCode; 29 | 30 | /** 31 | * Builds instances of {@link ArtTimeCode}. 32 | *

33 | * Default {@link TimeCodeType} is {@link TimeCodeType#Film}. 34 | *

35 | * See the Art-Net Specification for details. 36 | * 37 | * @author Julian Rabe 38 | * @see ArtTimeCode 39 | * @see Art-Net Specification 40 | */ 41 | public class ArtTimeCodeBuilder extends ArtNetPacketBuilder { 42 | 43 | private static final byte[] OP_CODE_BYTES = OpCode.OpTimeCode.getBytesLittleEndian(); 44 | 45 | private TimeCodeType type; 46 | private int hours; 47 | private int minutes; 48 | private int seconds; 49 | private int frames; 50 | 51 | private boolean changed; 52 | private ArtTimeCode artTimeCode; 53 | 54 | public ArtTimeCodeBuilder() { 55 | type = TimeCodeType.Film; 56 | changed = true; 57 | } 58 | 59 | /** 60 | * {@inheritDoc} 61 | * 62 | * @return {@link ArtTimeCode} instance. 63 | * @see ArtNetPacketBuilder#build() 64 | */ 65 | @Override 66 | public ArtTimeCode build() { 67 | if (changed) { 68 | 69 | byte[] bytes = new byte[19]; 70 | System.arraycopy(ArtNet.HEADER.getBytes(), 0, bytes, 0, 8); 71 | System.arraycopy(OP_CODE_BYTES, 0, bytes, 8, 2); 72 | System.arraycopy(ArtNet.PROTOCOL_REVISION.getBytes(), 0, bytes, 10, 2); 73 | 74 | bytes[14] = (byte) frames; 75 | bytes[15] = (byte) seconds; 76 | bytes[16] = (byte) minutes; 77 | bytes[17] = (byte) hours; 78 | bytes[18] = type.getByte(); 79 | 80 | artTimeCode = new ArtTimeCode(type, hours, minutes, seconds, frames, bytes.clone()); 81 | 82 | changed = false; 83 | } 84 | 85 | return artTimeCode; 86 | } 87 | 88 | /** 89 | * {@inheritDoc} 90 | * 91 | * @return {@link ArtPoll} instance. 92 | * @see ArtNetPacketBuilder#build() 93 | */ 94 | @Override 95 | public ArtTimeCode buildFromBytes(byte[] packetData) { 96 | if (packetData[8] == OP_CODE_BYTES[0] && packetData[9] == OP_CODE_BYTES[1]) { 97 | 98 | return new ArtTimeCode(TimeCodeType.getTimeCodeType(packetData[18]), packetData[17], packetData[16], 99 | packetData[15], packetData[14], packetData.clone()); 100 | } 101 | return null; 102 | } 103 | 104 | public TimeCodeType getType() { 105 | return type; 106 | } 107 | 108 | public void setType(TimeCodeType type) { 109 | if (this.type != type) { 110 | 111 | if (type == null) { 112 | type = TimeCodeType.Film; 113 | } 114 | 115 | if (frames > Math.ceil(type.getFramerate())) { 116 | frames = (int) (Math.ceil(type.getFramerate()) - 1); 117 | } 118 | 119 | this.type = type; 120 | changed = true; 121 | } 122 | } 123 | 124 | public ArtTimeCodeBuilder withType(TimeCodeType type) { 125 | setType(type); 126 | return this; 127 | } 128 | 129 | public int getHours() { 130 | return hours; 131 | } 132 | 133 | public void setHours(int hours) { 134 | if (this.hours != hours) { 135 | 136 | if (0 > hours || hours > 23) { 137 | throw new IllegalArgumentException("Illegal hours value!"); 138 | } 139 | 140 | this.hours = hours; 141 | changed = true; 142 | } 143 | } 144 | 145 | public ArtTimeCodeBuilder withHours(int hours) { 146 | setHours(hours); 147 | return this; 148 | } 149 | 150 | public int getMinutes() { 151 | return minutes; 152 | } 153 | 154 | public void setMinutes(int minutes) { 155 | if (this.minutes != minutes) { 156 | 157 | if (0 > minutes || minutes > 59) { 158 | throw new IllegalArgumentException("Illegal minutes value!"); 159 | } 160 | 161 | this.minutes = minutes; 162 | changed = true; 163 | } 164 | } 165 | 166 | public ArtTimeCodeBuilder withMinutes(int minutes) { 167 | setMinutes(minutes); 168 | return this; 169 | } 170 | 171 | public int getSeconds() { 172 | return seconds; 173 | } 174 | 175 | public void setSeconds(int seconds) { 176 | if (this.seconds != seconds) { 177 | 178 | if (0 > seconds || seconds > 59) { 179 | throw new IllegalArgumentException("Illegal seconds value!"); 180 | } 181 | 182 | this.seconds = seconds; 183 | changed = true; 184 | } 185 | } 186 | 187 | public ArtTimeCodeBuilder withSeconds(int seconds) { 188 | setSeconds(seconds); 189 | return this; 190 | } 191 | 192 | public int getFrames() { 193 | return frames; 194 | } 195 | 196 | public void setFrames(int frames) { 197 | if (this.frames != frames) { 198 | 199 | if (0 > frames || frames > Math.ceil(type.getFramerate()) - 1) { 200 | throw new IllegalArgumentException("Illegal frames value!"); 201 | } 202 | 203 | this.frames = frames; 204 | changed = true; 205 | } 206 | } 207 | 208 | public ArtTimeCodeBuilder withFrames(int frames) { 209 | setFrames(frames); 210 | return this; 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/ArtNet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | /** 25 | * @author Julian Rabe 26 | * @see Art-Net Specification 27 | */ 28 | public enum ArtNet { 29 | 30 | /** 31 | * The protocol revision this library works with (14). 32 | */ 33 | PROTOCOL_REVISION(14), 34 | 35 | /** 36 | * The Art-Net Header to send with in every {@link de.deltaeight.libartnet.packets.ArtNetPacket} ("Art-Net\0"). 37 | */ 38 | HEADER(new byte[]{0x41, 0x72, 0x74, 0x2D, 0x4E, 0x65, 0x74, 0x00}), 39 | 40 | /** 41 | * The UDP port on which network traffic is handled ({@code 0x1936}). 42 | */ 43 | PORT(0x1936); 44 | 45 | private final byte[] bytes; 46 | 47 | ArtNet(byte[] bytes) { 48 | this.bytes = bytes; 49 | } 50 | 51 | ArtNet(int value) { 52 | byte[] bytes = new byte[2]; 53 | bytes[0] = (byte) (value >> 8); 54 | bytes[1] = (byte) value; 55 | this.bytes = bytes; 56 | } 57 | 58 | /** 59 | * @return Bytes in big endian byte order. 60 | */ 61 | public byte[] getBytes() { 62 | return bytes; 63 | } 64 | 65 | /** 66 | * @return Bytes in little endian byte order. 67 | */ 68 | public byte[] getBytesLittleEndian() { 69 | byte[] result = new byte[bytes.length]; 70 | for (int i = 0; i < bytes.length; i++) { 71 | result[i] = bytes[bytes.length - i - 1]; 72 | } 73 | return result; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/EquipmentStyle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | /** 25 | * Supported equipment styles and their bytes 26 | * 27 | * @author Julian Rabe 28 | * @see de.deltaeight.libartnet.packets.ArtPollReply 29 | * @see Art-Net Specification 30 | */ 31 | public enum EquipmentStyle { 32 | 33 | Node(0x00), 34 | Controller(0x01), 35 | MediaServer(0x02), 36 | Routing(0x03), 37 | Backup(0x04), 38 | Config(0x05), 39 | Visualiser(0x06); 40 | 41 | private final byte value; 42 | 43 | EquipmentStyle(int value) { 44 | this.value = (byte) value; 45 | } 46 | 47 | public static EquipmentStyle getEquipmentStyle(int value) { 48 | if (value > values().length - 1) { 49 | return Config; 50 | } 51 | return values()[value]; 52 | } 53 | 54 | public byte getValue() { 55 | return value; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/IndicatorState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | /** 25 | * Represents an indicator state. 26 | * 27 | * @author Julian Rabe 28 | * @see de.deltaeight.libartnet.packets.ArtPollReply 29 | * @see Art-Net Specification 30 | */ 31 | public enum IndicatorState { 32 | 33 | Unknown(0b00000000), 34 | LocateIdentify(0b00000001), 35 | Mute(0b00000010), 36 | Normal(0b00000011); 37 | 38 | private final byte value; 39 | 40 | IndicatorState(int value) { 41 | this.value = (byte) value; 42 | } 43 | 44 | public byte getValue() { 45 | return value; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/InputStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | import java.util.Objects; 25 | 26 | /** 27 | * Represents the status of an input port. 28 | * 29 | * @author Julian Rabe 30 | * @see de.deltaeight.libartnet.packets.ArtPollReply 31 | * @see Art-Net Specification 32 | */ 33 | public class InputStatus extends PortStatus { 34 | 35 | public static final InputStatus DEFAULT = new InputStatus(false, false, false, false, false, false); 36 | 37 | private final boolean dataReceived; 38 | private final boolean inputDisabled; 39 | private final boolean errorsDetected; 40 | 41 | public InputStatus(boolean dataReceived, 42 | boolean includesTestPackets, 43 | boolean includesSIPs, 44 | boolean includesTextPackets, 45 | boolean inputDisabled, 46 | boolean errorsDetected) { 47 | 48 | super(includesTestPackets, includesSIPs, includesTextPackets); 49 | 50 | this.dataReceived = dataReceived; 51 | this.inputDisabled = inputDisabled; 52 | this.errorsDetected = errorsDetected; 53 | } 54 | 55 | public static InputStatus buildFromByte(byte b) { 56 | return new InputStatus((b & 0b10000000) > 0, (b & 0b01000000) > 0, (b & 0b00100000) > 0, 57 | (b & 0b00010000) > 0, (b & 0b00001000) > 0, (b & 0b00000100) > 0); 58 | } 59 | 60 | public byte getByte() { 61 | byte result = 0x00; 62 | if (dataReceived) { 63 | result |= 0b10000000; 64 | } 65 | if (includesTestPackets()) { 66 | result |= 0b01000000; 67 | } 68 | if (includesSIPs()) { 69 | result |= 0b00100000; 70 | } 71 | if (includesTextPackets()) { 72 | result |= 0b00010000; 73 | } 74 | if (inputDisabled) { 75 | result |= 0b00001000; 76 | } 77 | if (errorsDetected) { 78 | result |= 0b00000100; 79 | } 80 | return result; 81 | } 82 | 83 | @Override 84 | public boolean equals(Object o) { 85 | if (this == o) return true; 86 | if (o == null || getClass() != o.getClass()) return false; 87 | if (!super.equals(o)) return false; 88 | InputStatus that = (InputStatus) o; 89 | return dataReceived == that.dataReceived && 90 | inputDisabled == that.inputDisabled && 91 | errorsDetected == that.errorsDetected; 92 | } 93 | 94 | @Override 95 | public int hashCode() { 96 | return Objects.hash(dataReceived, inputDisabled, errorsDetected); 97 | } 98 | 99 | public boolean isDataReceived() { 100 | return dataReceived; 101 | } 102 | 103 | public boolean isInputDisabled() { 104 | return inputDisabled; 105 | } 106 | 107 | public boolean isErrorsDetected() { 108 | return errorsDetected; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/OemCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | import com.google.gson.Gson; 25 | 26 | import java.io.BufferedReader; 27 | import java.io.InputStreamReader; 28 | import java.util.HashMap; 29 | 30 | /** 31 | * Imports products with OEM codes as assigned by Artistic License Ltd. and makes them searchable. 32 | * 33 | * @author Julian Rabe 34 | * @see de.deltaeight.libartnet.packets.ArtPollReply 35 | * @see Art-NetOemCodes.h 36 | */ 37 | public class OemCode { 38 | 39 | private static final HashMap productsByProductCode; 40 | private static final HashMap productsByOemCode; 41 | private static final Product unknownProduct; 42 | 43 | static { 44 | 45 | productsByProductCode = new HashMap<>(); 46 | productsByOemCode = new HashMap<>(); 47 | unknownProduct = new Product("Unknown", 32767, "N/A", 48 | "N/A", 0, 0, false, false, 49 | "N/A", "N/A"); 50 | 51 | addProduct(unknownProduct); 52 | 53 | Product[] products = new Gson().fromJson(new BufferedReader(new InputStreamReader( 54 | OemCode.class.getResourceAsStream("OemCodes.json"))), Product[].class); 55 | 56 | if (products != null) { 57 | for (Product product : products) { 58 | addProduct(product); 59 | } 60 | } 61 | } 62 | 63 | private static void addProduct(Product product) { 64 | productsByProductCode.put(product.getProductCode(), product); 65 | productsByOemCode.put(product.getOemCode(), product); 66 | } 67 | 68 | /** 69 | * @param productCode The code to search for. 70 | * @return The {@link Product} matching {@code productCode} or the unknown product if none exists. 71 | */ 72 | public static Product getProductByProductCode(int productCode) { 73 | return productsByProductCode.getOrDefault(productCode, unknownProduct); 74 | } 75 | 76 | /** 77 | * @param oemCode The code to search for. 78 | * @return The {@link Product} matching {@code oemCode} or the unknown product if none exists. 79 | */ 80 | public static Product getProductByOemCode(String oemCode) { 81 | return productsByOemCode.getOrDefault(oemCode, unknownProduct); 82 | } 83 | 84 | /** 85 | * @return The unknown product. 86 | */ 87 | public static Product getUnknownProduct() { 88 | return unknownProduct; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/OpCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | /** 25 | * Available OpCodes and their bytes 26 | * 27 | * @author Julian Rabe 28 | * @see Art-Net Specification 29 | */ 30 | public enum OpCode { 31 | 32 | OpPoll(0x2000), 33 | OpPollReply(0x2100), 34 | OpDiagData(0x2300), 35 | OpCommand(0x2400), 36 | OpOutput(0x5000), 37 | OpDmx(OpOutput), 38 | OpNzs(0x5100), 39 | OpSync(0x5200), 40 | OpAddress(0x6000), 41 | OpInput(0x7000), 42 | OpTodRequest(0x8000), 43 | OpTodData(0x8100), 44 | OpTodControl(0x8200), 45 | OpRdm(0x8300), 46 | OpRdmSub(0x8400), 47 | OpVideoSetup(0xA010), 48 | OpVideoPalette(0xA020), 49 | OpVideoData(0xA040), 50 | OpFirmwareMaster(0xF200), 51 | OpFirmwareReply(0xF300), 52 | OpFileTnMaster(0xF400), 53 | OpFileFnMaster(0xF500), 54 | OpFileFnReply(0xF600), 55 | OpIpProg(0xF800), 56 | OpIpProgReply(0xF900), 57 | OpMedia(0x9000), 58 | OpMediaPatch(0x9100), 59 | OpMediaControl(0x9200), 60 | OpMediaControlReply(0x9300), 61 | OpTimeCode(0x9700), 62 | OpTimeSync(0x9800), 63 | OpTrigger(0x9900), 64 | OpDirectory(0x9A00), 65 | OpDirectoryReply(0x9B00); 66 | 67 | private final byte[] bytes; 68 | 69 | OpCode(int value) { 70 | this.bytes = new byte[]{(byte) (value >> 8), (byte) value}; 71 | } 72 | 73 | OpCode(OpCode opCode) { 74 | this.bytes = opCode.bytes; 75 | } 76 | 77 | /** 78 | * @return Bytes in big endian byte order. 79 | */ 80 | public byte[] getBytes() { 81 | return bytes; 82 | } 83 | 84 | /** 85 | * @return Bytes in little endian byte order. 86 | */ 87 | public byte[] getBytesLittleEndian() { 88 | byte[] result = new byte[2]; 89 | result[0] = bytes[1]; 90 | result[1] = bytes[0]; 91 | return result; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/OutputStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | import java.util.Objects; 25 | 26 | /** 27 | * Represents the status of an output port. 28 | * 29 | * @author Julian Rabe 30 | * @see de.deltaeight.libartnet.packets.ArtPollReply 31 | * @see Art-Net Specification 32 | */ 33 | public class OutputStatus extends PortStatus { 34 | 35 | public static final OutputStatus DEFAULT = new OutputStatus(false, false, false, false, false, false, false, false); 36 | 37 | private final boolean dataTransmitted; 38 | private final boolean merging; 39 | private final boolean outputShort; 40 | private final boolean mergeModeLTP; 41 | private final boolean transmittingSACN; 42 | 43 | public OutputStatus(boolean dataTransmitted, 44 | boolean includesTestPackets, 45 | boolean includesSIPs, 46 | boolean includesTextPackets, 47 | boolean merging, 48 | boolean outputShort, 49 | boolean mergeModeLTP, 50 | boolean transmittingSACN) { 51 | 52 | super(includesTestPackets, includesSIPs, includesTextPackets); 53 | 54 | this.dataTransmitted = dataTransmitted; 55 | this.merging = merging; 56 | this.outputShort = outputShort; 57 | this.mergeModeLTP = mergeModeLTP; 58 | this.transmittingSACN = transmittingSACN; 59 | } 60 | 61 | public static OutputStatus buildFromByte(byte b) { 62 | return new OutputStatus((b & 0b10000000) > 0, (b & 0b01000000) > 0, (b & 0b00100000) > 0, 63 | (b & 0b000100000) > 0, (b & 0b00001000) > 0, (b & 0b00000100) > 0, 64 | (b & 0b00000010) > 0, (b & 0b00000001) > 0); 65 | } 66 | 67 | public byte getByte() { 68 | byte result = 0x00; 69 | if (dataTransmitted) { 70 | result |= 0b10000000; 71 | } 72 | if (includesTestPackets()) { 73 | result |= 0b01000000; 74 | } 75 | if (includesSIPs()) { 76 | result |= 0b00100000; 77 | } 78 | if (includesTextPackets()) { 79 | result |= 0b00010000; 80 | } 81 | if (merging) { 82 | result |= 0b00001000; 83 | } 84 | if (outputShort) { 85 | result |= 0b00000100; 86 | } 87 | if (mergeModeLTP) { 88 | result |= 0b00000010; 89 | } 90 | if (transmittingSACN) { 91 | result |= 0b00000001; 92 | } 93 | return result; 94 | } 95 | 96 | @Override 97 | public int hashCode() { 98 | return Objects.hash(dataTransmitted, merging, outputShort, mergeModeLTP, transmittingSACN); 99 | } 100 | 101 | @Override 102 | public boolean equals(Object o) { 103 | if (this == o) return true; 104 | if (o == null || getClass() != o.getClass()) return false; 105 | if (!super.equals(o)) return false; 106 | OutputStatus that = (OutputStatus) o; 107 | return dataTransmitted == that.dataTransmitted && 108 | merging == that.merging && 109 | outputShort == that.outputShort && 110 | mergeModeLTP == that.mergeModeLTP && 111 | transmittingSACN == that.transmittingSACN; 112 | } 113 | 114 | public boolean isDataTransmitted() { 115 | return dataTransmitted; 116 | } 117 | 118 | public boolean isMerging() { 119 | return merging; 120 | } 121 | 122 | public boolean isOutputShort() { 123 | return outputShort; 124 | } 125 | 126 | public boolean isMergeModeLTP() { 127 | return mergeModeLTP; 128 | } 129 | 130 | public boolean isTransmittingSACN() { 131 | return transmittingSACN; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/PortAddressingAuthority.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | /** 25 | * Represents the port addressing authority. 26 | * 27 | * @author Julian Rabe 28 | * @see de.deltaeight.libartnet.packets.ArtPollReply 29 | * @see Art-Net Specification 30 | */ 31 | public enum PortAddressingAuthority { 32 | 33 | Unknown(0b00000000), 34 | FrontPanel(0b00000001), 35 | Network(0b00000010), 36 | NotUsed(0b00000011); 37 | 38 | private final byte value; 39 | 40 | PortAddressingAuthority(int value) { 41 | this.value = (byte) value; 42 | } 43 | 44 | public byte getValue() { 45 | return value; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/PortStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | import java.util.Objects; 25 | 26 | /** 27 | * Describes the status of a data port. 28 | * 29 | * @author Julian Rabe 30 | */ 31 | public abstract class PortStatus { 32 | 33 | private final boolean includesTestPackets; 34 | private final boolean includesSIPs; 35 | private final boolean includesTextPackets; 36 | 37 | PortStatus(boolean includesTestPackets, 38 | boolean includesSIPs, 39 | boolean includesTextPackets) { 40 | 41 | this.includesTestPackets = includesTestPackets; 42 | this.includesSIPs = includesSIPs; 43 | this.includesTextPackets = includesTextPackets; 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return Objects.hash(includesTestPackets, includesSIPs, includesTextPackets); 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) return true; 54 | if (o == null || getClass() != o.getClass()) return false; 55 | PortStatus that = (PortStatus) o; 56 | return includesTestPackets == that.includesTestPackets && 57 | includesSIPs == that.includesSIPs && 58 | includesTextPackets == that.includesTextPackets; 59 | } 60 | 61 | public boolean includesTestPackets() { 62 | return includesTestPackets; 63 | } 64 | 65 | public boolean includesSIPs() { 66 | return includesSIPs; 67 | } 68 | 69 | public boolean includesTextPackets() { 70 | return includesTextPackets; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/PortType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | import java.util.Objects; 25 | 26 | /** 27 | * Represents a port type. 28 | * 29 | * @author Julian Rabe 30 | * @see de.deltaeight.libartnet.packets.ArtPollReply 31 | * @see Art-Net Specification 32 | */ 33 | public class PortType { 34 | 35 | public static final PortType DEFAULT = new PortType(false, false, Protocol.DMX512); 36 | 37 | private final boolean outputSupported; 38 | private final boolean inputSupported; 39 | private final Protocol protocol; 40 | 41 | public PortType(boolean outputSupported, boolean inputSupported, Protocol protocol) { 42 | this.outputSupported = outputSupported; 43 | this.inputSupported = inputSupported; 44 | this.protocol = protocol; 45 | } 46 | 47 | public static PortType buildFromByte(byte b) { 48 | return new PortType((b & 0b10000000) > 0, (b & 0b01000000) > 0, Protocol.getProtocol(b & 0b00000111)); 49 | } 50 | 51 | public byte getByte() { 52 | byte result = 0x00; 53 | if (outputSupported) { 54 | result |= 0b10000000; 55 | } 56 | if (inputSupported) { 57 | result |= 0b01000000; 58 | } 59 | result |= protocol.getValue(); 60 | return result; 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return Objects.hash(outputSupported, inputSupported, protocol); 66 | } 67 | 68 | @Override 69 | public boolean equals(Object o) { 70 | if (this == o) return true; 71 | if (o == null || getClass() != o.getClass()) return false; 72 | PortType portType = (PortType) o; 73 | return outputSupported == portType.outputSupported && 74 | inputSupported == portType.inputSupported && 75 | protocol == portType.protocol; 76 | } 77 | 78 | public boolean isOutputSupported() { 79 | return outputSupported; 80 | } 81 | 82 | public boolean isInputSupported() { 83 | return inputSupported; 84 | } 85 | 86 | public Protocol getProtocol() { 87 | return protocol; 88 | } 89 | 90 | /** 91 | * Represents a Protocol for input/output ports. 92 | * 93 | * @author Julian Rabe 94 | * @see Art-Net Specification 95 | */ 96 | public enum Protocol { 97 | 98 | DMX512(0b00000000), 99 | MIDI(0b00000001), 100 | AVAB(0b00000010), 101 | COLORTRAN_CMX(0b00000011), 102 | ADB625(0b00000100), 103 | ARTNET(0b00000101); 104 | 105 | private final byte value; 106 | 107 | Protocol(int value) { 108 | this.value = (byte) value; 109 | } 110 | 111 | public static Protocol getProtocol(int value) { 112 | if (value > values().length - 1) { 113 | return DMX512; 114 | } 115 | return values()[value]; 116 | } 117 | 118 | public byte getValue() { 119 | return value; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/Priority.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | import java.util.HashMap; 25 | 26 | /** 27 | * Priorities for diag data and their bytes 28 | * 29 | * @author Julian Rabe 30 | * @see de.deltaeight.libartnet.packets.ArtPoll 31 | * @see Art-Net Specification 32 | */ 33 | public enum Priority { 34 | 35 | Low(0x10), 36 | Medium(0x40), 37 | High(0x80), 38 | Critical(0xE0), 39 | Volatile(0xF0); 40 | 41 | private static final HashMap priorities; 42 | 43 | static { 44 | priorities = new HashMap<>(5); 45 | for (Priority value : values()) { 46 | priorities.put(value.getValue(), value); 47 | } 48 | } 49 | 50 | private final byte value; 51 | 52 | Priority(int value) { 53 | this.value = (byte) value; 54 | } 55 | 56 | public static Priority getPriority(byte value) { 57 | return priorities.getOrDefault(value, Low); 58 | } 59 | 60 | public byte getValue() { 61 | return value; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/Product.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | /** 25 | * Represents a product defined by Artistic License Ltd. 26 | * 27 | * @author Julian Rabe 28 | * @see de.deltaeight.libartnet.descriptors.OemCode 29 | */ 30 | public class Product { 31 | 32 | private final String oemCode; 33 | private final int productCode; 34 | private final String manufacturer; 35 | private final String name; 36 | private final int dmxOutputs; 37 | private final int dmxInputs; 38 | private final boolean dmxPortsPhysical; 39 | private final boolean supportsRdm; 40 | private final String supportEmail; 41 | private final String supportName; 42 | 43 | /** 44 | * @param oemCode The OEM code assigned by Artistic License Ltd. 45 | * @param productCode The product code assigned by Artistic License Ltd. 46 | * @param manufacturer The manufacturer of the product 47 | * @param name The name of the product 48 | * @param dmxOutputs The amount of DMX outputs 49 | * @param dmxInputs The amount of DMX inputs 50 | * @param dmxPortsPhysical Whether the product has physical DMX ports or not. 51 | * @param supportsRdm Whether the product supports RDM or not. 52 | * @param supportEmail The Email address of the customer support. 53 | * @param supportName The name of the customer support. 54 | */ 55 | Product(String oemCode, 56 | int productCode, 57 | String manufacturer, 58 | String name, 59 | int dmxOutputs, 60 | int dmxInputs, 61 | boolean dmxPortsPhysical, 62 | boolean supportsRdm, 63 | String supportEmail, 64 | String supportName) { 65 | 66 | this.oemCode = oemCode; 67 | this.productCode = productCode; 68 | this.manufacturer = manufacturer; 69 | this.name = name; 70 | this.dmxOutputs = dmxOutputs; 71 | this.dmxInputs = dmxInputs; 72 | this.dmxPortsPhysical = dmxPortsPhysical; 73 | this.supportsRdm = supportsRdm; 74 | this.supportEmail = supportEmail; 75 | this.supportName = supportName; 76 | } 77 | 78 | public String getOemCode() { 79 | return oemCode; 80 | } 81 | 82 | public int getProductCode() { 83 | return productCode; 84 | } 85 | 86 | public String getManufacturer() { 87 | return manufacturer; 88 | } 89 | 90 | public String getName() { 91 | return name; 92 | } 93 | 94 | public int getDmxOutputs() { 95 | return dmxOutputs; 96 | } 97 | 98 | public int getDmxInputs() { 99 | return dmxInputs; 100 | } 101 | 102 | public boolean isDmxPortsPhysical() { 103 | return dmxPortsPhysical; 104 | } 105 | 106 | public boolean supportsRdm() { 107 | return supportsRdm; 108 | } 109 | 110 | public String getSupportEmail() { 111 | return supportEmail; 112 | } 113 | 114 | public String getSupportName() { 115 | return supportName; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/descriptors/TimeCodeType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.descriptors; 23 | 24 | /** 25 | * Available timecode types and their framerates. 26 | * 27 | * @author Julian Rabe 28 | * @see de.deltaeight.libartnet.packets.ArtTimeCode 29 | */ 30 | public enum TimeCodeType { 31 | 32 | Film(24, 0x00), 33 | EBU(25, 0x01), 34 | DF(29.97f, 0x02), 35 | SMPTE(30, 0x03); 36 | 37 | private final float framerate; 38 | private final int value; 39 | 40 | TimeCodeType(float framerate, int value) { 41 | this.framerate = framerate; 42 | this.value = value; 43 | } 44 | 45 | public static TimeCodeType getTimeCodeType(int value) { 46 | if (value > values().length - 1) { 47 | return Film; 48 | } 49 | return values()[value]; 50 | } 51 | 52 | public float getFramerate() { 53 | return framerate; 54 | } 55 | 56 | public byte getByte() { 57 | return (byte) value; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/network/ArtNetReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | import java.net.DatagramPacket; 25 | import java.net.DatagramSocket; 26 | import java.net.SocketException; 27 | import java.util.Arrays; 28 | import java.util.HashSet; 29 | import java.util.concurrent.ConcurrentHashMap; 30 | import java.util.concurrent.ExecutorService; 31 | import java.util.concurrent.ForkJoinPool; 32 | 33 | import de.deltaeight.libartnet.builders.ArtDmxBuilder; 34 | import de.deltaeight.libartnet.builders.ArtPollBuilder; 35 | import de.deltaeight.libartnet.builders.ArtPollReplyBuilder; 36 | import de.deltaeight.libartnet.builders.ArtTimeCodeBuilder; 37 | import de.deltaeight.libartnet.descriptors.ArtNet; 38 | import de.deltaeight.libartnet.packets.ArtDmx; 39 | import de.deltaeight.libartnet.packets.ArtNetPacket; 40 | import de.deltaeight.libartnet.packets.ArtPoll; 41 | import de.deltaeight.libartnet.packets.ArtPollReply; 42 | import de.deltaeight.libartnet.packets.ArtTimeCode; 43 | 44 | /** 45 | * Provides a multi-threaded receiver which listens to UDP network traffic and uses {@link PacketReceiveHandler} 46 | * instances to react to known packets. 47 | * 48 | * @author Julian Rabe 49 | * @see ArtNetSender 50 | */ 51 | public class ArtNetReceiver extends NetworkHandler { 52 | 53 | private final ExecutorService workingPool; 54 | private final byte[] buffer; 55 | private final ConcurrentHashMap, PacketReceiveDispatcher> packetReceiveDispatcher; 56 | private final HashSet> artDmxReceiveHandlers; 57 | private final HashSet> artPollReceiveHandlers; 58 | private final HashSet> artPollReplyReceiveHandlers; 59 | private final HashSet> artTimeCodeReceiveHandlers; 60 | 61 | /** 62 | * Initializes an instance for use. 63 | * 64 | * @param workingPool The {@link ExecutorService} to use. 65 | * @param socket The {@link DatagramSocket} to use. 66 | */ 67 | public ArtNetReceiver(ExecutorService workingPool, DatagramSocket socket) { 68 | super(socket); 69 | 70 | if (socket.getLocalPort() != 0x1936) { 71 | throw new IllegalArgumentException("Illegal socket port " + socket.getLocalPort() + "!"); 72 | } 73 | 74 | this.workingPool = workingPool; 75 | 76 | buffer = new byte[530]; 77 | packetReceiveDispatcher = new ConcurrentHashMap<>(); 78 | 79 | artDmxReceiveHandlers = new HashSet<>(); 80 | artPollReceiveHandlers = new HashSet<>(); 81 | artPollReplyReceiveHandlers = new HashSet<>(); 82 | artTimeCodeReceiveHandlers = new HashSet<>(); 83 | } 84 | 85 | /** 86 | * Initializes an instance for use but creates a default {@link DatagramSocket} bound to Port {@code 0x1936}. 87 | * 88 | * @param workingPool The {@link ExecutorService} to use. 89 | * @throws SocketException When it was not possible to bind to Port {@code 0x1936}, the socket is not able to switch 90 | * to broadcast or is not able to bind multiple addresses. 91 | */ 92 | public ArtNetReceiver(ExecutorService workingPool) throws SocketException { 93 | this(workingPool, new DatagramSocket(0x1936)); 94 | socket.setBroadcast(true); 95 | socket.setReuseAddress(true); 96 | } 97 | 98 | /** 99 | * Initializes an instance for use but uses the common {@link ForkJoinPool} shared across the JVM. 100 | * 101 | * @param socket The {@link DatagramSocket} to use. 102 | * @see ForkJoinPool#commonPool() 103 | */ 104 | public ArtNetReceiver(DatagramSocket socket) { 105 | this(ForkJoinPool.commonPool(), socket); 106 | } 107 | 108 | /** 109 | * Initializes an instance for use but creates a default {@link DatagramSocket} bound to Port {@code 0x1936} and 110 | * uses the common {@link ForkJoinPool} shared across the JVM. 111 | * 112 | * @throws SocketException When it was not possible to bind to Port {@code 0x1936}, the socket is not able to switch 113 | * to broadcast or is not able to bind multiple addresses. 114 | * @see ForkJoinPool#commonPool() 115 | */ 116 | public ArtNetReceiver() throws SocketException { 117 | this(ForkJoinPool.commonPool(), new DatagramSocket(0x1936)); 118 | socket.setBroadcast(true); 119 | socket.setReuseAddress(true); 120 | } 121 | 122 | @Override 123 | void run() throws Exception { 124 | DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length); 125 | socket.receive(datagramPacket); 126 | 127 | if (datagramPacket.getLength() > 10 128 | && Arrays.equals(ArtNet.HEADER.getBytes(), Arrays.copyOfRange(datagramPacket.getData(), 0, 8))) { 129 | 130 | for (PacketReceiveDispatcher dispatcher : packetReceiveDispatcher.values()) { 131 | 132 | if (dispatcher.handleReceive(datagramPacket.getData().clone())) { 133 | break; 134 | } 135 | } 136 | } 137 | } 138 | 139 | /** 140 | * {@inheritDoc} 141 | */ 142 | @Override 143 | public void stop() { 144 | super.stop(); 145 | if (getState() == State.Running) { 146 | workingPool.shutdown(); 147 | } 148 | } 149 | 150 | /** 151 | * Adds a {@link PacketReceiveHandler} which is called when {@link ArtDmx} packets are received. 152 | * 153 | * @param handler The {@link PacketReceiveHandler} to use. 154 | */ 155 | public void addArtDmxReceiveHandler(PacketReceiveHandler handler) { 156 | if (!packetReceiveDispatcher.containsKey(ArtDmx.class)) { 157 | packetReceiveDispatcher.put(ArtDmx.class, new PacketReceiveDispatcher<>(workingPool, 158 | new ArtDmxBuilder(), artDmxReceiveHandlers)); 159 | } 160 | artDmxReceiveHandlers.add(handler); 161 | 162 | } 163 | 164 | public void removeArtDmxReceiveHandler(PacketReceiveHandler handler) { 165 | artDmxReceiveHandlers.remove(handler); 166 | if (artDmxReceiveHandlers.isEmpty()) { 167 | packetReceiveDispatcher.remove(ArtDmx.class); 168 | } 169 | } 170 | 171 | /** 172 | * @param handler The {@link PacketReceiveHandler} to use. 173 | * @return Current {@link ArtNetReceiver} instance for fluent code style. 174 | * @see #addArtDmxReceiveHandler(PacketReceiveHandler) 175 | */ 176 | public ArtNetReceiver withArtDmxReceiveHandler(PacketReceiveHandler handler) { 177 | addArtDmxReceiveHandler(handler); 178 | return this; 179 | } 180 | 181 | public ArtNetReceiver withoutArtDmxReceiveHandler(PacketReceiveHandler handler) { 182 | removeArtDmxReceiveHandler(handler); 183 | return this; 184 | } 185 | 186 | /** 187 | * Adds a {@link PacketReceiveHandler} which is called when {@link ArtPoll} packets are received. 188 | * 189 | * @param handler The {@link PacketReceiveHandler} to use. 190 | */ 191 | public void addArtPollReceiveHandler(PacketReceiveHandler handler) { 192 | if (!packetReceiveDispatcher.containsKey(ArtPoll.class)) { 193 | packetReceiveDispatcher.put(ArtPoll.class, new PacketReceiveDispatcher<>(workingPool, 194 | new ArtPollBuilder(), artPollReceiveHandlers)); 195 | } 196 | artPollReceiveHandlers.add(handler); 197 | 198 | } 199 | 200 | public void removeArtPollReceiveHandler(PacketReceiveHandler handler) { 201 | artPollReceiveHandlers.remove(handler); 202 | if (artPollReceiveHandlers.isEmpty()) { 203 | packetReceiveDispatcher.remove(ArtPoll.class); 204 | } 205 | } 206 | 207 | /** 208 | * @param handler The {@link PacketReceiveHandler} to use. 209 | * @return Current {@link ArtNetReceiver} instance for fluent code style. 210 | * @see #addArtPollReceiveHandler(PacketReceiveHandler) 211 | */ 212 | public ArtNetReceiver withArtPollReceiveHandler(PacketReceiveHandler handler) { 213 | addArtPollReceiveHandler(handler); 214 | return this; 215 | } 216 | 217 | public ArtNetReceiver withoutArtPollReceiveHandler(PacketReceiveHandler handler) { 218 | removeArtPollReceiveHandler(handler); 219 | return this; 220 | } 221 | 222 | /** 223 | * Adds a {@link PacketReceiveHandler} which is called when {@link ArtPollReply} packets are received. 224 | * 225 | * @param handler The {@link PacketReceiveHandler} to use. 226 | */ 227 | public void addArtPollReplyReceiveHandler(PacketReceiveHandler handler) { 228 | if (!packetReceiveDispatcher.containsKey(ArtPollReply.class)) { 229 | packetReceiveDispatcher.put(ArtPollReply.class, new PacketReceiveDispatcher<>(workingPool, 230 | new ArtPollReplyBuilder(), artPollReplyReceiveHandlers)); 231 | } 232 | artPollReplyReceiveHandlers.add(handler); 233 | 234 | } 235 | 236 | public void removeArtPollReplyReceiveHandler(PacketReceiveHandler handler) { 237 | artPollReplyReceiveHandlers.remove(handler); 238 | if (artPollReplyReceiveHandlers.isEmpty()) { 239 | packetReceiveDispatcher.remove(ArtPollReply.class); 240 | } 241 | } 242 | 243 | /** 244 | * @param handler The {@link PacketReceiveHandler} to use. 245 | * @return Current {@link ArtNetReceiver} instance for fluent code style. 246 | * @see #addArtPollReplyReceiveHandler(PacketReceiveHandler) 247 | */ 248 | public ArtNetReceiver withArtPollReplyReceiveHandler(PacketReceiveHandler handler) { 249 | addArtPollReplyReceiveHandler(handler); 250 | return this; 251 | } 252 | 253 | public ArtNetReceiver withoutArtPollReplyReceiveHandler(PacketReceiveHandler handler) { 254 | removeArtPollReplyReceiveHandler(handler); 255 | return this; 256 | } 257 | 258 | /** 259 | * Adds a {@link PacketReceiveHandler} which is called when {@link ArtTimeCode} packets are received. 260 | * 261 | * @param handler The {@link PacketReceiveHandler} to use. 262 | */ 263 | public void addArtTimeCodeReceiveHandler(PacketReceiveHandler handler) { 264 | if (!packetReceiveDispatcher.containsKey(ArtTimeCode.class)) { 265 | packetReceiveDispatcher.put(ArtTimeCode.class, new PacketReceiveDispatcher<>(workingPool, 266 | new ArtTimeCodeBuilder(), artTimeCodeReceiveHandlers)); 267 | } 268 | artTimeCodeReceiveHandlers.add(handler); 269 | 270 | } 271 | 272 | public void removeArtTimeCodeReceiveHandler(PacketReceiveHandler handler) { 273 | artTimeCodeReceiveHandlers.remove(handler); 274 | if (artTimeCodeReceiveHandlers.isEmpty()) { 275 | packetReceiveDispatcher.remove(ArtTimeCode.class); 276 | } 277 | } 278 | 279 | /** 280 | * @param handler The {@link PacketReceiveHandler} to use. 281 | * @return Current {@link ArtNetReceiver} instance for fluent code style. 282 | * @see #addArtTimeCodeReceiveHandler(PacketReceiveHandler) 283 | */ 284 | public ArtNetReceiver withArtTimeCodeReceiveHandler(PacketReceiveHandler handler) { 285 | addArtTimeCodeReceiveHandler(handler); 286 | return this; 287 | } 288 | 289 | public ArtNetReceiver withoutArtTimeCodeReceiveHandler(PacketReceiveHandler handler) { 290 | removeArtTimeCodeReceiveHandler(handler); 291 | return this; 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/network/ArtNetSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | import java.net.DatagramPacket; 25 | import java.net.DatagramSocket; 26 | import java.net.InetAddress; 27 | import java.net.SocketException; 28 | import java.util.concurrent.LinkedBlockingQueue; 29 | 30 | import de.deltaeight.libartnet.packets.ArtNetPacket; 31 | 32 | /** 33 | * Provides a sender which queues packets to send. 34 | * 35 | * @author Julian Rabe 36 | * @see ArtNetReceiver 37 | */ 38 | public class ArtNetSender extends NetworkHandler { 39 | 40 | private final LinkedBlockingQueue packetQueue; 41 | 42 | /** 43 | * Initializes an instance for use. 44 | * 45 | * @param socket The {@link DatagramSocket} to use. 46 | */ 47 | public ArtNetSender(DatagramSocket socket) { 48 | super(socket); 49 | packetQueue = new LinkedBlockingQueue<>(); 50 | } 51 | 52 | /** 53 | * Initializes an instance for use but creates a default {@link DatagramSocket} bound to Port {@code 0x1936}. 54 | * 55 | * @throws SocketException When socket is not usable. 56 | */ 57 | public ArtNetSender() throws SocketException { 58 | this(new DatagramSocket()); 59 | } 60 | 61 | @Override 62 | void run() throws Exception { 63 | socket.send(packetQueue.take()); 64 | } 65 | 66 | /** 67 | * Queues the desired {@link ArtNetPacket} for sending. 68 | * 69 | * @param address The {@link InetAddress} to send to. 70 | * @param packet The {@link ArtNetPacket} to send. 71 | * @return {@code true} if queueing was successful, {@code false} if not. 72 | */ 73 | public boolean send(InetAddress address, ArtNetPacket packet) { 74 | return packetQueue.offer(new DatagramPacket(packet.getBytes(), packet.getBytes().length, address, 0x1936)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/network/ExceptionHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | /** 25 | * Used to handle exceptions thrown by network handlers. 26 | * 27 | * @author Julian Rabe 28 | * @see ArtNetReceiver 29 | */ 30 | @FunctionalInterface 31 | public interface ExceptionHandler { 32 | 33 | /** 34 | * Is called when an exception is thrown. 35 | * 36 | * @param exception The exception that was thrown. 37 | */ 38 | void handleException(Exception exception); 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/network/NetworkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | import java.net.DatagramSocket; 25 | 26 | /** 27 | * Provides a basic template for network handlers with a worker thread and states. 28 | * 29 | * @author Julian Rabe 30 | */ 31 | abstract class NetworkHandler { 32 | 33 | final DatagramSocket socket; 34 | private final Thread workerThread; 35 | private State state; 36 | private ExceptionHandler exceptionHandler; 37 | 38 | /** 39 | * @param socket The {@link DatagramSocket} to use. 40 | * @throws IllegalArgumentException if {@code socket} is on a different port than {@code 0x1936}. 41 | */ 42 | NetworkHandler(DatagramSocket socket) { 43 | 44 | this.socket = socket; 45 | 46 | workerThread = new Thread() { 47 | 48 | @Override 49 | public void run() { 50 | while (!isInterrupted()) { 51 | try { 52 | NetworkHandler.this.run(); 53 | } catch (Exception e) { 54 | if (!isInterrupted()) { 55 | if (exceptionHandler != null) { 56 | exceptionHandler.handleException(e); 57 | } else { 58 | interrupt(); 59 | } 60 | } 61 | } 62 | } 63 | } 64 | }; 65 | 66 | workerThread.setName("ArtNet Network Worker"); 67 | workerThread.setDaemon(true); 68 | 69 | state = State.Initialized; 70 | } 71 | 72 | /** 73 | * Is run in {@link #workerThread}. 74 | * 75 | * @throws Exception Can be anything and is forwarded to {@link #exceptionHandler} if set. 76 | */ 77 | abstract void run() throws Exception; 78 | 79 | /** 80 | * Starts working. Only possible if not already running or stopped. 81 | *

82 | * It is recommended, to check the state using {@link #getState()} before calling. 83 | * 84 | * @throws IllegalStateException When {@link #getState()} {@code != } {@link State#Initialized}. 85 | * @see #stop() 86 | * @see State 87 | */ 88 | public void start() { 89 | if (state == State.Initialized) { 90 | workerThread.start(); 91 | state = State.Running; 92 | } else if (state == State.Running) { 93 | throw new IllegalStateException("Already running!"); 94 | } else { 95 | throw new IllegalStateException("Not initialized!"); 96 | } 97 | } 98 | 99 | /** 100 | * Stops working and closes the underlying socket. Only possible if running. 101 | *

102 | * It is recommended, to check the state using {@link #getState()} before calling. 103 | * 104 | * @throws IllegalStateException When {@link #getState()} {@code != } {@link State#Running}. 105 | * @see #start() 106 | * @see State 107 | */ 108 | public void stop() { 109 | if (state == State.Running) { 110 | workerThread.interrupt(); 111 | socket.close(); 112 | state = State.Stopped; 113 | } else { 114 | throw new IllegalStateException("Not Running!"); 115 | } 116 | } 117 | 118 | public State getState() { 119 | return state; 120 | } 121 | 122 | public ExceptionHandler getExceptionHandler() { 123 | return exceptionHandler; 124 | } 125 | 126 | /** 127 | * Sets the {@link ExceptionHandler} which is called when exceptions are thrown while listening to the UDP port. 128 | * 129 | * @param exceptionHandler The {@link ExceptionHandler} to use. 130 | */ 131 | public void setExceptionHandler(ExceptionHandler exceptionHandler) { 132 | this.exceptionHandler = exceptionHandler; 133 | } 134 | 135 | /** 136 | * @param exceptionHandler The {@link ExceptionHandler} to use. 137 | * @return Current {@link NetworkHandler} instance for fluent code style. 138 | * @see #setExceptionHandler(ExceptionHandler) 139 | */ 140 | public NetworkHandler withExceptionHandler(ExceptionHandler exceptionHandler) { 141 | setExceptionHandler(exceptionHandler); 142 | return this; 143 | } 144 | 145 | /** 146 | * Represents the state of the {@link NetworkHandler}. 147 | *

148 | * During the lifecycle of a {@link NetworkHandler}, it passes three states: {@link #Initialized}, {@link #Running} 149 | * and {@link #Stopped}. Once stopped, a {@link NetworkHandler} cannot be started again. 150 | * 151 | * @author Julian Rabe 152 | */ 153 | public enum State { 154 | 155 | /** 156 | * After a {@link NetworkHandler} is initialized, the socket is open and the handler is ready to be used. 157 | *

158 | * When in this state, calling {@link NetworkHandler#stop()} is illegal. 159 | */ 160 | Initialized, 161 | 162 | /** 163 | * When {@link NetworkHandler#start()} is called, the {@link NetworkHandler} starts its worker-threads. 164 | *

165 | * When in this state, calling {@link NetworkHandler#start()} is illegal. 166 | */ 167 | Running, 168 | 169 | /** 170 | * When {@link NetworkHandler#stop()} is called, the {@link NetworkHandler} stops its worker-threads and closes 171 | * the underlying socket. 172 | *

173 | * When in this state, calling both {@link NetworkHandler#start()} and {@link NetworkHandler#stop()} is illegal. 174 | */ 175 | Stopped 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/network/PacketReceiveDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | import de.deltaeight.libartnet.builders.ArtNetPacketBuilder; 25 | import de.deltaeight.libartnet.packets.ArtNetPacket; 26 | 27 | import java.util.Set; 28 | import java.util.concurrent.ExecutorService; 29 | 30 | /** 31 | * Used to enforce strong typing in {@link ArtNetReceiver} when handling received packets. 32 | * 33 | * @param The {@link ArtNetPacket} this {@link PacketReceiveDispatcher} handles. 34 | * @author Julian Rabe 35 | * @see PacketReceiveHandler 36 | * @see ArtNetReceiver 37 | */ 38 | class PacketReceiveDispatcher { 39 | 40 | private final ExecutorService workingPool; 41 | private final ArtNetPacketBuilder packetBuilder; 42 | private final Set> receiveHandlers; 43 | 44 | PacketReceiveDispatcher(ExecutorService workingPool, 45 | ArtNetPacketBuilder packetBuilder, 46 | Set> receiveHandlers) { 47 | 48 | this.workingPool = workingPool; 49 | this.packetBuilder = packetBuilder; 50 | this.receiveHandlers = receiveHandlers; 51 | } 52 | 53 | boolean handleReceive(byte[] packetData) { 54 | T packet = packetBuilder.buildFromBytes(packetData); 55 | if (packet != null) { 56 | receiveHandlers.forEach(receiveHandler -> workingPool.submit(() -> receiveHandler.handle(packet))); 57 | } 58 | return false; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/network/PacketReceiveHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | import de.deltaeight.libartnet.packets.ArtNetPacket; 25 | 26 | /** 27 | * Provides functionality for received {@link ArtNetPacket} instances. 28 | * 29 | * @param The {@link ArtNetPacket} implementation the implementing class is used for. 30 | */ 31 | @FunctionalInterface 32 | public interface PacketReceiveHandler { 33 | 34 | /** 35 | * Is called by {@link ArtNetReceiver} when an {@link ArtNetPacket} of type {@link T} was received. 36 | * 37 | * @param packet The {@link ArtNetPacket} which was received. 38 | */ 39 | void handle(T packet); 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/packets/ArtDmx.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.packets; 23 | 24 | import de.deltaeight.libartnet.builders.ArtDmxBuilder; 25 | 26 | import java.util.Arrays; 27 | import java.util.Objects; 28 | 29 | /** 30 | * Represents an {@code ArtDmx} packet containing DMX values. 31 | *

32 | * See the Art-Net Specification for details. 33 | * 34 | * @author Julian Rabe 35 | * @see ArtDmxBuilder 36 | * @see Art-Net Specification 37 | */ 38 | public class ArtDmx extends ArtNetPacket { 39 | 40 | private final int sequence; 41 | private final int physical; 42 | private final int netAddress; 43 | private final int subnetAddress; 44 | private final int universeAddress; 45 | private final byte[] data; 46 | 47 | public ArtDmx(int sequence, 48 | int physical, 49 | int netAddress, 50 | int subnetAddress, 51 | int universeAddress, 52 | byte[] data, 53 | byte[] bytes) { 54 | 55 | super(bytes); 56 | 57 | this.sequence = sequence; 58 | this.physical = physical; 59 | this.netAddress = netAddress; 60 | this.subnetAddress = subnetAddress; 61 | this.universeAddress = universeAddress; 62 | this.data = data; 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | int result = Objects.hash(sequence, physical, netAddress, subnetAddress, universeAddress); 68 | result = 31 * result + Arrays.hashCode(data); 69 | return result; 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 | ArtDmx artDmx = (ArtDmx) o; 77 | return sequence == artDmx.sequence && 78 | physical == artDmx.physical && 79 | netAddress == artDmx.netAddress && 80 | subnetAddress == artDmx.subnetAddress && 81 | universeAddress == artDmx.universeAddress && 82 | Arrays.equals(data, artDmx.data); 83 | } 84 | 85 | public int getSequence() { 86 | return sequence; 87 | } 88 | 89 | public int getPhysical() { 90 | return physical; 91 | } 92 | 93 | public int getNetAddress() { 94 | return netAddress; 95 | } 96 | 97 | public int getSubnetAddress() { 98 | return subnetAddress; 99 | } 100 | 101 | public int getUniverseAddress() { 102 | return universeAddress; 103 | } 104 | 105 | public byte[] getData() { 106 | return data; 107 | } 108 | 109 | public int[] getIntData() { 110 | int[] result = new int[data.length]; 111 | 112 | for (int i = 0; i < data.length; i++) { 113 | result[i] = data[i] & 0xFF; 114 | } 115 | 116 | return result; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/packets/ArtNetPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.packets; 23 | 24 | import de.deltaeight.libartnet.builders.ArtNetPacketBuilder; 25 | 26 | /** 27 | * Represents Art-Net packets 28 | * 29 | * @author Julian Rabe 30 | * @see ArtNetPacketBuilder 31 | */ 32 | public abstract class ArtNetPacket { 33 | 34 | private final byte[] bytes; 35 | 36 | ArtNetPacket(byte[] bytes) { 37 | this.bytes = bytes; 38 | } 39 | 40 | /** 41 | * @return Payload to send over the network. 42 | */ 43 | public byte[] getBytes() { 44 | return bytes.clone(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/packets/ArtPoll.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.packets; 23 | 24 | import de.deltaeight.libartnet.builders.ArtPollBuilder; 25 | import de.deltaeight.libartnet.descriptors.Priority; 26 | 27 | import java.util.Objects; 28 | 29 | /** 30 | * Represents an {@code ArtPoll} packet which requests other Art-Net nodes on the network to reply with 31 | * {@link ArtPollReply}. 32 | *

33 | * See the Art-Net Specification for details. 34 | * 35 | * @author Julian Rabe 36 | * @see ArtPollReply 37 | * @see ArtPollBuilder 38 | * @see Art-Net Specification 39 | */ 40 | public class ArtPoll extends ArtNetPacket { 41 | 42 | private final boolean enableVlcTransmission; 43 | private final boolean unicastDiagnosticMessages; 44 | private final boolean sendDiagnosticMessages; 45 | private final boolean sendArtPollReplyOnChanges; 46 | private final Priority priority; 47 | 48 | public ArtPoll(boolean enableVlcTransmission, 49 | boolean unicastDiagnosticMessages, 50 | boolean sendDiagnosticMessages, 51 | boolean sendArtPollReplyOnChanges, 52 | Priority priority, 53 | byte[] bytes) { 54 | 55 | super(bytes); 56 | 57 | this.enableVlcTransmission = enableVlcTransmission; 58 | this.unicastDiagnosticMessages = unicastDiagnosticMessages; 59 | this.sendDiagnosticMessages = sendDiagnosticMessages; 60 | this.sendArtPollReplyOnChanges = sendArtPollReplyOnChanges; 61 | this.priority = priority; 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | return Objects.hash(enableVlcTransmission, unicastDiagnosticMessages, sendDiagnosticMessages, 67 | sendArtPollReplyOnChanges, priority); 68 | } 69 | 70 | @Override 71 | public boolean equals(Object o) { 72 | if (this == o) return true; 73 | if (o == null || getClass() != o.getClass()) return false; 74 | ArtPoll artPoll = (ArtPoll) o; 75 | return enableVlcTransmission == artPoll.enableVlcTransmission && 76 | unicastDiagnosticMessages == artPoll.unicastDiagnosticMessages && 77 | sendDiagnosticMessages == artPoll.sendDiagnosticMessages && 78 | sendArtPollReplyOnChanges == artPoll.sendArtPollReplyOnChanges && 79 | priority == artPoll.priority; 80 | } 81 | 82 | public boolean isEnableVlcTransmission() { 83 | return enableVlcTransmission; 84 | } 85 | 86 | public boolean isUnicastDiagnosticMessages() { 87 | return unicastDiagnosticMessages; 88 | } 89 | 90 | public boolean isSendDiagnosticMessages() { 91 | return sendDiagnosticMessages; 92 | } 93 | 94 | public boolean isSendArtPollReplyOnChanges() { 95 | return sendArtPollReplyOnChanges; 96 | } 97 | 98 | public Priority getPriority() { 99 | return priority; 100 | } 101 | } -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/packets/ArtPollReply.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.packets; 23 | 24 | import java.util.Arrays; 25 | import java.util.Objects; 26 | 27 | import de.deltaeight.libartnet.builders.ArtPollReplyBuilder; 28 | import de.deltaeight.libartnet.descriptors.EquipmentStyle; 29 | import de.deltaeight.libartnet.descriptors.IndicatorState; 30 | import de.deltaeight.libartnet.descriptors.InputStatus; 31 | import de.deltaeight.libartnet.descriptors.OutputStatus; 32 | import de.deltaeight.libartnet.descriptors.PortAddressingAuthority; 33 | import de.deltaeight.libartnet.descriptors.PortType; 34 | import de.deltaeight.libartnet.descriptors.Product; 35 | 36 | /** 37 | * Represents an {@code ArtPollReply} packet containing node information about the sender. This is sent periodically or 38 | * as an answer to {@link ArtPoll} packets. 39 | *

40 | * See the Art-Net Specification for details. 41 | * 42 | * @author Julian Rabe 43 | * @see ArtPoll 44 | * @see ArtPollReplyBuilder 45 | * @see Art-Net Specification 46 | */ 47 | public class ArtPollReply extends ArtNetPacket { 48 | 49 | private final byte[] ipAddress; 50 | private final int nodeVersion; 51 | private final int netAddress; 52 | private final int subnetAddress; 53 | private final Product product; 54 | private final int ubeaVersion; 55 | private final IndicatorState indicatorState; 56 | private final PortAddressingAuthority portAddressingAuthority; 57 | private final boolean bootedFromRom; 58 | private final boolean rdmSupport; 59 | private final boolean ubeaPresent; 60 | private final String estaManufacturer; 61 | private final String shortName; 62 | private final String longName; 63 | private final String nodeReport; 64 | private final PortType[] portTypes; 65 | private final InputStatus[] inputStatuses; 66 | private final OutputStatus[] outputStatuses; 67 | private final int[] inputUniverseAddresses; 68 | private final int[] outputUniverseAddresses; 69 | private final boolean[] macrosActive; 70 | private final boolean[] remotesActive; 71 | private final EquipmentStyle equipmentStyle; 72 | private final byte[] macAddress; 73 | private final byte[] bindIp; 74 | private final int bindIndex; 75 | private final boolean webBrowserConfigurationSupport; 76 | private final boolean ipIsDhcpConfigured; 77 | private final boolean dhcpSupport; 78 | private final boolean longPortAddressSupport; 79 | private final boolean canSwitchToSACN; 80 | private final boolean squawking; 81 | 82 | public ArtPollReply(byte[] ipAddress, 83 | int nodeVersion, 84 | int netAddress, 85 | int subnetAddress, 86 | Product product, 87 | int ubeaVersion, 88 | IndicatorState indicatorState, 89 | PortAddressingAuthority portAddressingAuthority, 90 | boolean bootedFromRom, 91 | boolean rdmSupport, 92 | boolean ubeaPresent, 93 | String estaManufacturer, 94 | String shortName, 95 | String longName, 96 | String nodeReport, 97 | PortType[] portTypes, 98 | InputStatus[] inputStatuses, 99 | OutputStatus[] outputStatuses, 100 | int[] inputUniverseAddresses, 101 | int[] outputUniverseAddresses, 102 | boolean[] macrosActive, 103 | boolean[] remotesActive, 104 | EquipmentStyle equipmentStyle, 105 | byte[] macAddress, 106 | byte[] bindIp, 107 | int bindIndex, 108 | boolean webBrowserConfigurationSupport, 109 | boolean ipIsDhcpConfigured, 110 | boolean dhcpSupport, 111 | boolean longPortAddressSupport, 112 | boolean canSwitchToSACN, 113 | boolean squawking, 114 | byte[] bytes) { 115 | 116 | super(bytes); 117 | 118 | this.ipAddress = ipAddress; 119 | this.nodeVersion = nodeVersion; 120 | this.netAddress = netAddress; 121 | this.subnetAddress = subnetAddress; 122 | this.product = product; 123 | this.ubeaVersion = ubeaVersion; 124 | this.indicatorState = indicatorState; 125 | this.portAddressingAuthority = portAddressingAuthority; 126 | this.bootedFromRom = bootedFromRom; 127 | this.rdmSupport = rdmSupport; 128 | this.ubeaPresent = ubeaPresent; 129 | this.estaManufacturer = estaManufacturer.substring(0, Math.min(estaManufacturer.length(), 2)); 130 | this.shortName = shortName.substring(0, Math.min(shortName.length(), 17)); 131 | this.longName = longName.substring(0, Math.min(longName.length(), 63)); 132 | this.nodeReport = nodeReport; 133 | this.portTypes = portTypes; 134 | this.inputStatuses = inputStatuses; 135 | this.outputStatuses = outputStatuses; 136 | this.inputUniverseAddresses = inputUniverseAddresses; 137 | this.outputUniverseAddresses = outputUniverseAddresses; 138 | this.macrosActive = macrosActive; 139 | this.remotesActive = remotesActive; 140 | this.equipmentStyle = equipmentStyle; 141 | this.macAddress = macAddress; 142 | this.bindIp = bindIp; 143 | this.bindIndex = bindIndex; 144 | this.webBrowserConfigurationSupport = webBrowserConfigurationSupport; 145 | this.ipIsDhcpConfigured = ipIsDhcpConfigured; 146 | this.dhcpSupport = dhcpSupport; 147 | this.longPortAddressSupport = longPortAddressSupport; 148 | this.canSwitchToSACN = canSwitchToSACN; 149 | this.squawking = squawking; 150 | } 151 | 152 | @Override 153 | public int hashCode() { 154 | 155 | int result = Objects.hash(nodeVersion, netAddress, subnetAddress, product, ubeaVersion, indicatorState, 156 | portAddressingAuthority, bootedFromRom, rdmSupport, ubeaPresent, estaManufacturer, shortName, longName, 157 | nodeReport, equipmentStyle, bindIndex, webBrowserConfigurationSupport, ipIsDhcpConfigured, dhcpSupport, 158 | longPortAddressSupport, canSwitchToSACN, squawking); 159 | 160 | result = 31 * result + Arrays.hashCode(ipAddress); 161 | result = 31 * result + Arrays.hashCode(portTypes); 162 | result = 31 * result + Arrays.hashCode(inputStatuses); 163 | result = 31 * result + Arrays.hashCode(outputStatuses); 164 | result = 31 * result + Arrays.hashCode(inputUniverseAddresses); 165 | result = 31 * result + Arrays.hashCode(outputUniverseAddresses); 166 | result = 31 * result + Arrays.hashCode(macrosActive); 167 | result = 31 * result + Arrays.hashCode(remotesActive); 168 | result = 31 * result + Arrays.hashCode(macAddress); 169 | result = 31 * result + Arrays.hashCode(bindIp); 170 | 171 | return result; 172 | } 173 | 174 | @Override 175 | public boolean equals(Object o) { 176 | if (this == o) return true; 177 | if (o == null || getClass() != o.getClass()) return false; 178 | ArtPollReply that = (ArtPollReply) o; 179 | return nodeVersion == that.nodeVersion && 180 | netAddress == that.netAddress && 181 | subnetAddress == that.subnetAddress && 182 | ubeaVersion == that.ubeaVersion && 183 | bootedFromRom == that.bootedFromRom && 184 | rdmSupport == that.rdmSupport && 185 | ubeaPresent == that.ubeaPresent && 186 | bindIndex == that.bindIndex && 187 | webBrowserConfigurationSupport == that.webBrowserConfigurationSupport && 188 | ipIsDhcpConfigured == that.ipIsDhcpConfigured && 189 | dhcpSupport == that.dhcpSupport && 190 | longPortAddressSupport == that.longPortAddressSupport && 191 | canSwitchToSACN == that.canSwitchToSACN && 192 | squawking == that.squawking && 193 | Arrays.equals(ipAddress, that.ipAddress) && 194 | product == that.product && 195 | indicatorState == that.indicatorState && 196 | portAddressingAuthority == that.portAddressingAuthority && 197 | Objects.equals(estaManufacturer, that.estaManufacturer) && 198 | Objects.equals(shortName, that.shortName) && 199 | Objects.equals(longName, that.longName) && 200 | Objects.equals(nodeReport, that.nodeReport) && 201 | Arrays.equals(portTypes, that.portTypes) && 202 | Arrays.equals(inputStatuses, that.inputStatuses) && 203 | Arrays.equals(outputStatuses, that.outputStatuses) && 204 | Arrays.equals(inputUniverseAddresses, that.inputUniverseAddresses) && 205 | Arrays.equals(outputUniverseAddresses, that.outputUniverseAddresses) && 206 | Arrays.equals(macrosActive, that.macrosActive) && 207 | Arrays.equals(remotesActive, that.remotesActive) && 208 | equipmentStyle == that.equipmentStyle && 209 | Arrays.equals(macAddress, that.macAddress) && 210 | Arrays.equals(bindIp, that.bindIp); 211 | } 212 | 213 | public byte[] getIpAddress() { 214 | return ipAddress; 215 | } 216 | 217 | public int getNodeVersion() { 218 | return nodeVersion; 219 | } 220 | 221 | public int getNetAddress() { 222 | return netAddress; 223 | } 224 | 225 | public int getSubnetAddress() { 226 | return subnetAddress; 227 | } 228 | 229 | public Product getProduct() { 230 | return product; 231 | } 232 | 233 | public int getUbeaVersion() { 234 | return ubeaVersion; 235 | } 236 | 237 | public IndicatorState getIndicatorState() { 238 | return indicatorState; 239 | } 240 | 241 | public PortAddressingAuthority getPortAddressingAuthority() { 242 | return portAddressingAuthority; 243 | } 244 | 245 | public boolean isBootedFromRom() { 246 | return bootedFromRom; 247 | } 248 | 249 | public boolean supportsRdm() { 250 | return rdmSupport; 251 | } 252 | 253 | public boolean isUbeaPresent() { 254 | return ubeaPresent; 255 | } 256 | 257 | public String getEstaManufacturer() { 258 | return estaManufacturer; 259 | } 260 | 261 | public String getShortName() { 262 | return shortName; 263 | } 264 | 265 | public String getLongName() { 266 | return longName; 267 | } 268 | 269 | public String getNodeReport() { 270 | return nodeReport; 271 | } 272 | 273 | public PortType[] getPortTypes() { 274 | return portTypes.clone(); 275 | } 276 | 277 | public InputStatus[] getInputStatuses() { 278 | return inputStatuses.clone(); 279 | } 280 | 281 | public OutputStatus[] getOutputStatuses() { 282 | return outputStatuses.clone(); 283 | } 284 | 285 | public int[] getInputUniverseAddresses() { 286 | return inputUniverseAddresses.clone(); 287 | } 288 | 289 | public int[] getOutputUniverseAddresses() { 290 | return outputUniverseAddresses.clone(); 291 | } 292 | 293 | public boolean[] getMacrosActive() { 294 | return macrosActive.clone(); 295 | } 296 | 297 | public boolean[] getRemotesActive() { 298 | return remotesActive.clone(); 299 | } 300 | 301 | public EquipmentStyle getEquipmentStyle() { 302 | return equipmentStyle; 303 | } 304 | 305 | public byte[] getMacAddress() { 306 | return macAddress.clone(); 307 | } 308 | 309 | public byte[] getBindIp() { 310 | return bindIp; 311 | } 312 | 313 | public int getBindIndex() { 314 | return bindIndex; 315 | } 316 | 317 | public boolean supportsWebBrowserConfiguration() { 318 | return webBrowserConfigurationSupport; 319 | } 320 | 321 | public boolean ipIsDhcpConfigured() { 322 | return ipIsDhcpConfigured; 323 | } 324 | 325 | public boolean supportsDhcp() { 326 | return dhcpSupport; 327 | } 328 | 329 | public boolean supportsLongAddresses() { 330 | return longPortAddressSupport; 331 | } 332 | 333 | public boolean canSwitchToSACN() { 334 | return canSwitchToSACN; 335 | } 336 | 337 | public boolean isSquawking() { 338 | return squawking; 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /lib/src/main/java/de/deltaeight/libartnet/packets/ArtTimeCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.packets; 23 | 24 | import de.deltaeight.libartnet.builders.ArtTimeCodeBuilder; 25 | import de.deltaeight.libartnet.descriptors.TimeCodeType; 26 | 27 | import java.util.Objects; 28 | 29 | /** 30 | * Represents an {@code ArtTimeCode} packet containing timecode information. 31 | *

32 | * See the Art-Net Specification for details. 33 | * 34 | * @author Julian Rabe 35 | * @see ArtTimeCodeBuilder 36 | * @see Art-Net Specification 37 | */ 38 | public class ArtTimeCode extends ArtNetPacket { 39 | 40 | private final TimeCodeType type; 41 | private final int hours; 42 | private final int minutes; 43 | private final int seconds; 44 | private final int frames; 45 | 46 | public ArtTimeCode(TimeCodeType type, int hours, int minutes, int seconds, int frames, byte[] bytes) { 47 | 48 | super(bytes); 49 | this.type = type; 50 | this.hours = hours; 51 | this.minutes = minutes; 52 | this.seconds = seconds; 53 | this.frames = frames; 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | return Objects.hash(frames, seconds, minutes, hours, type); 59 | } 60 | 61 | @Override 62 | public boolean equals(Object o) { 63 | if (this == o) return true; 64 | if (o == null || getClass() != o.getClass()) return false; 65 | ArtTimeCode that = (ArtTimeCode) o; 66 | return frames == that.frames && 67 | seconds == that.seconds && 68 | minutes == that.minutes && 69 | hours == that.hours && 70 | type == that.type; 71 | } 72 | 73 | public TimeCodeType getType() { 74 | return type; 75 | } 76 | 77 | public int getHours() { 78 | return hours; 79 | } 80 | 81 | public int getMinutes() { 82 | return minutes; 83 | } 84 | 85 | public int getSeconds() { 86 | return seconds; 87 | } 88 | 89 | public int getFrames() { 90 | return frames; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/builders/AbstractPacketBuilderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.builders; 23 | 24 | import de.deltaeight.libartnet.packets.ArtNetPacket; 25 | 26 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | 29 | abstract class AbstractPacketBuilderTest { 30 | 31 | static void assertPackets(byte[] expectedBytes, ArtNetPacketBuilder builder) { 32 | 33 | ArtNetPacket outboundPacket = builder.build(); 34 | ArtNetPacket inboundPacket = builder.buildFromBytes(expectedBytes); 35 | 36 | assertArrayEquals(expectedBytes, outboundPacket.getBytes()); 37 | assertEquals(outboundPacket, inboundPacket); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/builders/ArtDmxBuilderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.builders; 23 | 24 | import org.junit.jupiter.api.Test; 25 | 26 | import static org.junit.jupiter.api.Assertions.*; 27 | 28 | class ArtDmxBuilderTest extends AbstractPacketBuilderTest { 29 | 30 | private static final byte[] DEFAULT_PACKET = getExpectedData(0x00, 0x00, 0x00, 0x00, 0x00, new byte[0]); 31 | 32 | private static byte[] getExpectedData(int sequence, 33 | int physical, 34 | int netAddress, 35 | int subnetAddress, 36 | int universeAddress, 37 | byte[] data) { 38 | 39 | byte[] bytes = new byte[18 + data.length]; 40 | 41 | System.arraycopy(new byte[]{ 42 | 0x41, 0x72, 0x74, 0x2D, 0x4E, 0x65, 0x74, 0x00, // Header 43 | 0x00, 0x50, // OpCode 44 | 0x00, 0x0E, // Protocol version 45 | }, 0, bytes, 0, 12); 46 | 47 | bytes[12] = (byte) sequence; 48 | bytes[13] = (byte) physical; 49 | bytes[14] = (byte) (subnetAddress << 4 | universeAddress); 50 | bytes[15] = (byte) netAddress; 51 | bytes[16] = (byte) (data.length >> 8); 52 | bytes[17] = (byte) data.length; 53 | 54 | System.arraycopy(data, 0, bytes, 18, data.length); 55 | 56 | return bytes; 57 | } 58 | 59 | @Test 60 | void build() { 61 | assertPackets(DEFAULT_PACKET, new ArtDmxBuilder()); 62 | } 63 | 64 | @Test 65 | void sequence() { 66 | 67 | byte[] expectedDataSequence1 = getExpectedData(0x01, 0x00, 0x00, 0x00, 0x00, new byte[0]); 68 | byte[] expectedDataSequence255 = getExpectedData(0xff, 0x00, 0x00, 0x00, 0x00, new byte[0]); 69 | 70 | ArtDmxBuilder builder = new ArtDmxBuilder(); 71 | 72 | assertEquals(0, builder.getSequence()); 73 | 74 | builder.setSequence(1); 75 | assertEquals(1, builder.getSequence()); 76 | assertPackets(expectedDataSequence1, builder); 77 | 78 | builder.setSequence(0); 79 | assertEquals(0, builder.getSequence()); 80 | assertPackets(DEFAULT_PACKET, builder); 81 | 82 | builder.setSequence(255); 83 | assertEquals(255, builder.getSequence()); 84 | assertPackets(expectedDataSequence255, builder); 85 | 86 | assertSame(builder, builder.withSequence(1)); 87 | assertEquals(1, builder.getSequence()); 88 | assertPackets(expectedDataSequence1, builder); 89 | 90 | assertSame(builder, builder.withSequence(0)); 91 | assertEquals(0, builder.getSequence()); 92 | assertPackets(DEFAULT_PACKET, builder); 93 | 94 | assertSame(builder, builder.withSequence(255)); 95 | assertEquals(255, builder.getSequence()); 96 | assertPackets(expectedDataSequence255, builder); 97 | 98 | assertThrows(IllegalArgumentException.class, () -> builder.setSequence(-1)); 99 | assertThrows(IllegalArgumentException.class, () -> builder.withSequence(256)); 100 | } 101 | 102 | @Test 103 | void physical() { 104 | 105 | byte[] expectedDataPhysical1 = getExpectedData(0x00, 0x01, 0x00, 0x00, 0x00, new byte[0]); 106 | byte[] expectedDataPhysical255 = getExpectedData(0x00, 0xff, 0x00, 0x00, 0x00, new byte[0]); 107 | 108 | ArtDmxBuilder builder = new ArtDmxBuilder(); 109 | 110 | assertEquals(0, builder.getPhysical()); 111 | 112 | builder.setPhysical(1); 113 | assertEquals(1, builder.getPhysical()); 114 | assertPackets(expectedDataPhysical1, builder); 115 | 116 | builder.setPhysical(0); 117 | assertEquals(0, builder.getPhysical()); 118 | assertPackets(DEFAULT_PACKET, builder); 119 | 120 | builder.setPhysical(255); 121 | assertEquals(255, builder.getPhysical()); 122 | assertPackets(expectedDataPhysical255, builder); 123 | 124 | assertSame(builder, builder.withPhysical(1)); 125 | assertEquals(1, builder.getPhysical()); 126 | assertPackets(expectedDataPhysical1, builder); 127 | 128 | assertSame(builder, builder.withPhysical(0)); 129 | assertEquals(0, builder.getPhysical()); 130 | assertPackets(DEFAULT_PACKET, builder); 131 | 132 | assertSame(builder, builder.withPhysical(255)); 133 | assertEquals(255, builder.getPhysical()); 134 | assertPackets(expectedDataPhysical255, builder); 135 | 136 | assertThrows(IllegalArgumentException.class, () -> builder.setPhysical(-1)); 137 | assertThrows(IllegalArgumentException.class, () -> builder.withPhysical(256)); 138 | } 139 | 140 | @Test 141 | void subnetAddress() { 142 | 143 | byte[] expectedDataSubnet1 = getExpectedData(0x00, 0x00, 0x00, 0x01, 0x00, new byte[0]); 144 | byte[] expectedDataSubnet15 = getExpectedData(0x00, 0x00, 0x00, 0x0f, 0x00, new byte[0]); 145 | 146 | ArtDmxBuilder builder = new ArtDmxBuilder(); 147 | 148 | assertEquals(0, builder.getSubnetAddress()); 149 | 150 | builder.setSubnetAddress(1); 151 | assertEquals(1, builder.getSubnetAddress()); 152 | assertPackets(expectedDataSubnet1, builder); 153 | 154 | builder.setSubnetAddress(0); 155 | assertEquals(0, builder.getSubnetAddress()); 156 | assertPackets(DEFAULT_PACKET, builder); 157 | 158 | builder.setSubnetAddress(15); 159 | assertEquals(15, builder.getSubnetAddress()); 160 | assertPackets(expectedDataSubnet15, builder); 161 | 162 | assertSame(builder, builder.withSubnetAddress(1)); 163 | assertEquals(1, builder.getSubnetAddress()); 164 | assertPackets(expectedDataSubnet1, builder); 165 | 166 | assertSame(builder, builder.withSubnetAddress(0)); 167 | assertEquals(0, builder.getSubnetAddress()); 168 | assertPackets(DEFAULT_PACKET, builder); 169 | 170 | assertSame(builder, builder.withSubnetAddress(15)); 171 | assertEquals(15, builder.getSubnetAddress()); 172 | assertPackets(expectedDataSubnet15, builder); 173 | 174 | assertThrows(IllegalArgumentException.class, () -> builder.setSubnetAddress(-1)); 175 | assertThrows(IllegalArgumentException.class, () -> builder.withSubnetAddress(16)); 176 | } 177 | 178 | @Test 179 | void universeAddress() { 180 | 181 | byte[] expectedDataUniverse1 = getExpectedData(0x00, 0x00, 0x00, 0x00, 0x01, new byte[0]); 182 | byte[] expectedDataUniverse15 = getExpectedData(0x00, 0x00, 0x00, 0x00, 0x0f, new byte[0]); 183 | 184 | ArtDmxBuilder builder = new ArtDmxBuilder(); 185 | 186 | assertEquals(0, builder.getUniverseAddress()); 187 | 188 | builder.setUniverseAddress(1); 189 | assertEquals(1, builder.getUniverseAddress()); 190 | assertPackets(expectedDataUniverse1, builder); 191 | 192 | builder.setUniverseAddress(0); 193 | assertEquals(0, builder.getUniverseAddress()); 194 | assertPackets(DEFAULT_PACKET, builder); 195 | 196 | builder.setUniverseAddress(15); 197 | assertEquals(15, builder.getUniverseAddress()); 198 | assertPackets(expectedDataUniverse15, builder); 199 | 200 | assertSame(builder, builder.withUniverseAddress(1)); 201 | assertEquals(1, builder.getUniverseAddress()); 202 | assertPackets(expectedDataUniverse1, builder); 203 | 204 | assertSame(builder, builder.withUniverseAddress(0)); 205 | assertEquals(0, builder.getUniverseAddress()); 206 | assertPackets(DEFAULT_PACKET, builder); 207 | 208 | assertSame(builder, builder.withUniverseAddress(15)); 209 | assertEquals(15, builder.getUniverseAddress()); 210 | assertPackets(expectedDataUniverse15, builder); 211 | 212 | assertThrows(IllegalArgumentException.class, () -> builder.setUniverseAddress(-1)); 213 | assertThrows(IllegalArgumentException.class, () -> builder.withUniverseAddress(16)); 214 | } 215 | 216 | @Test 217 | void netAddress() { 218 | 219 | byte[] expectedDataNetAddress1 = getExpectedData(0x00, 0x00, 0x01, 0x00, 0x00, new byte[0]); 220 | byte[] expectedDataNetAddress127 = getExpectedData(0x00, 0x00, 0x7f, 0x00, 0x00, new byte[0]); 221 | 222 | ArtDmxBuilder builder = new ArtDmxBuilder(); 223 | 224 | assertEquals(0, builder.getNetAddress()); 225 | 226 | builder.setNetAddress(1); 227 | assertEquals(1, builder.getNetAddress()); 228 | assertPackets(expectedDataNetAddress1, builder); 229 | 230 | builder.setNetAddress(0); 231 | assertEquals(0, builder.getNetAddress()); 232 | assertPackets(DEFAULT_PACKET, builder); 233 | 234 | builder.setNetAddress(127); 235 | assertEquals(127, builder.getNetAddress()); 236 | assertPackets(expectedDataNetAddress127, builder); 237 | 238 | builder.setNetAddress(0); 239 | assertEquals(0, builder.getNetAddress()); 240 | assertPackets(DEFAULT_PACKET, builder); 241 | 242 | assertSame(builder, builder.withNetAddress(1)); 243 | assertEquals(1, builder.getNetAddress()); 244 | assertPackets(expectedDataNetAddress1, builder); 245 | 246 | assertSame(builder, builder.withNetAddress(0)); 247 | assertEquals(0, builder.getNetAddress()); 248 | assertPackets(DEFAULT_PACKET, builder); 249 | 250 | assertSame(builder, builder.withNetAddress(127)); 251 | assertEquals(127, builder.getNetAddress()); 252 | assertPackets(expectedDataNetAddress127, builder); 253 | 254 | assertThrows(IllegalArgumentException.class, () -> builder.setNetAddress(-1)); 255 | assertThrows(IllegalArgumentException.class, () -> builder.withNetAddress(128)); 256 | } 257 | 258 | @Test 259 | void data() { 260 | 261 | ArtDmxBuilder builder = new ArtDmxBuilder(); 262 | 263 | assertEquals(0, builder.getDataSize()); 264 | assertArrayEquals(new byte[0], builder.getData()); 265 | 266 | assertEquals(0x00, builder.getData(0)); 267 | assertEquals(0x00, builder.getData(511)); 268 | 269 | assertThrows(IllegalArgumentException.class, () -> builder.getData(-1)); 270 | assertThrows(IllegalArgumentException.class, () -> builder.getData(512)); 271 | 272 | builder.setData(2, (byte) 0x0F); 273 | assertEquals(3, builder.getDataSize()); 274 | assertEquals(0x0F, builder.getData(2)); 275 | assertArrayEquals(new byte[]{0x00, 0x00, 0x0F}, builder.getData()); 276 | assertPackets(getExpectedData(0x00, 0x00, 0x00, 0x00, 0x00, new byte[]{0x00, 0x00, 0x0F, 0x00}), builder); 277 | 278 | assertThrows(IllegalArgumentException.class, () -> builder.setData(512, (byte) 0xFF)); 279 | 280 | builder.setData(new byte[]{0x0F}); 281 | assertEquals(1, builder.getDataSize()); 282 | assertArrayEquals(new byte[]{0x0F}, builder.getData()); 283 | assertPackets(getExpectedData(0x00, 0x00, 0x00, 0x00, 0x00, new byte[]{0x0F, 0x00}), builder); 284 | 285 | assertThrows(IllegalArgumentException.class, () -> builder.setData(new byte[513])); 286 | 287 | assertSame(builder, builder.withData(2, (byte) 0x12)); 288 | assertEquals(3, builder.getDataSize()); 289 | assertEquals(0x12, builder.getData(2)); 290 | assertArrayEquals(new byte[]{0x0F, 0x00, 0x12}, builder.getData()); 291 | assertPackets(getExpectedData(0x00, 0x00, 0x00, 0x00, 0x00, new byte[]{0x0F, 0x00, 0x12, 0x00}), builder); 292 | 293 | assertThrows(IllegalArgumentException.class, () -> builder.withData(512, (byte) 0xFF)); 294 | 295 | assertSame(builder, builder.withData(new byte[]{0x21, 0x22})); 296 | assertEquals(2, builder.getDataSize()); 297 | assertArrayEquals(new byte[]{0x21, 0x22}, builder.getData()); 298 | assertPackets(getExpectedData(0x00, 0x00, 0x00, 0x00, 0x00, new byte[]{0x21, 0x22}), builder); 299 | 300 | assertThrows(IllegalArgumentException.class, () -> builder.withData(new byte[513])); 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/builders/ArtPollBuilderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.builders; 23 | 24 | import de.deltaeight.libartnet.descriptors.Priority; 25 | import org.junit.jupiter.api.Test; 26 | 27 | import static org.junit.jupiter.api.Assertions.*; 28 | 29 | class ArtPollBuilderTest extends AbstractPacketBuilderTest { 30 | 31 | private byte[] getExpectedData(int talkToMe, int priority) { 32 | return new byte[]{ 33 | 0x41, 0x72, 0x74, 0x2D, 0x4E, 0x65, 0x74, 0x00, // Header 34 | 0x00, 0x20, // OpCode 35 | 0x00, 0x0E, // Protocol version 36 | (byte) talkToMe, (byte) priority 37 | }; 38 | } 39 | 40 | @Test 41 | void build() { 42 | assertPackets(getExpectedData(0x00, 0x10), new ArtPollBuilder()); 43 | } 44 | 45 | @Test 46 | void disableVlcTransmission() { 47 | 48 | ArtPollBuilder builder = new ArtPollBuilder(); 49 | 50 | assertFalse(builder.vlcTransmissionDisabled()); 51 | 52 | builder.setDisableVlcTransmission(true); 53 | assertTrue(builder.vlcTransmissionDisabled()); 54 | assertPackets(getExpectedData(0x10, 0x10), builder); 55 | 56 | builder.setDisableVlcTransmission(false); 57 | assertFalse(builder.vlcTransmissionDisabled()); 58 | assertPackets(getExpectedData(0x00, 0x10), builder); 59 | 60 | assertSame(builder, builder.withDisableVlcTransmission(true)); 61 | assertTrue(builder.vlcTransmissionDisabled()); 62 | assertPackets(getExpectedData(0x10, 0x10), builder); 63 | 64 | assertSame(builder, builder.withDisableVlcTransmission(false)); 65 | assertFalse(builder.vlcTransmissionDisabled()); 66 | assertPackets(getExpectedData(0x00, 0x10), builder); 67 | } 68 | 69 | @Test 70 | void unicastDiagnosticMessages() { 71 | 72 | ArtPollBuilder builder = new ArtPollBuilder(); 73 | 74 | assertFalse(builder.unicastDiagnosticMessages()); 75 | 76 | builder.setUnicastDiagnosticMessages(true); 77 | assertTrue(builder.unicastDiagnosticMessages()); 78 | assertPackets(getExpectedData(0x08, 0x10), builder); 79 | 80 | builder.setUnicastDiagnosticMessages(false); 81 | assertFalse(builder.unicastDiagnosticMessages()); 82 | assertPackets(getExpectedData(0x00, 0x10), builder); 83 | 84 | assertSame(builder, builder.withUnicastDiagnosticMessages(true)); 85 | assertTrue(builder.unicastDiagnosticMessages()); 86 | assertPackets(getExpectedData(0x08, 0x10), builder); 87 | 88 | assertSame(builder, builder.withUnicastDiagnosticMessages(false)); 89 | assertFalse(builder.unicastDiagnosticMessages()); 90 | assertPackets(getExpectedData(0x00, 0x10), builder); 91 | } 92 | 93 | @Test 94 | void sendDiagnosticMessages() { 95 | 96 | ArtPollBuilder builder = new ArtPollBuilder(); 97 | 98 | assertFalse(builder.sendDiagnosticMessages()); 99 | 100 | builder.setSendDiagnosticMessages(true); 101 | assertTrue(builder.sendDiagnosticMessages()); 102 | assertPackets(getExpectedData(0x04, 0x10), builder); 103 | 104 | builder.setSendDiagnosticMessages(false); 105 | assertFalse(builder.sendDiagnosticMessages()); 106 | assertPackets(getExpectedData(0x00, 0x10), builder); 107 | 108 | assertSame(builder, builder.withSendDiagnosticMessages(true)); 109 | assertTrue(builder.sendDiagnosticMessages()); 110 | assertPackets(getExpectedData(0x04, 0x10), builder); 111 | 112 | assertSame(builder, builder.withSendDiagnosticMessages(false)); 113 | assertFalse(builder.sendDiagnosticMessages()); 114 | assertPackets(getExpectedData(0x00, 0x10), builder); 115 | } 116 | 117 | @Test 118 | void sendArtPollReplyOnChanges() { 119 | 120 | ArtPollBuilder builder = new ArtPollBuilder(); 121 | 122 | assertFalse(builder.sendArtPollReplyOnChanges()); 123 | 124 | builder.setSendArtPollReplyOnChanges(true); 125 | assertTrue(builder.sendArtPollReplyOnChanges()); 126 | assertPackets(getExpectedData(0x02, 0x10), builder); 127 | 128 | builder.setSendArtPollReplyOnChanges(false); 129 | assertFalse(builder.sendArtPollReplyOnChanges()); 130 | assertPackets(getExpectedData(0x00, 0x10), builder); 131 | 132 | assertSame(builder, builder.withSendArtPollReplyOnChanges(true)); 133 | assertTrue(builder.sendArtPollReplyOnChanges()); 134 | assertPackets(getExpectedData(0x02, 0x10), builder); 135 | 136 | assertSame(builder, builder.withSendArtPollReplyOnChanges(false)); 137 | assertFalse(builder.sendArtPollReplyOnChanges()); 138 | assertPackets(getExpectedData(0x00, 0x10), builder); 139 | } 140 | 141 | @Test 142 | void booleanProperties() { 143 | 144 | ArtPollBuilder builder = new ArtPollBuilder() 145 | .withDisableVlcTransmission(true) 146 | .withUnicastDiagnosticMessages(true) 147 | .withSendDiagnosticMessages(true) 148 | .withSendArtPollReplyOnChanges(true); 149 | 150 | assertPackets(getExpectedData(0x1E, 0x10), builder); 151 | } 152 | 153 | @Test 154 | void priority() { 155 | 156 | Priority[] testValues = {Priority.Medium, Priority.High, Priority.Critical, Priority.Volatile, Priority.Low}; 157 | byte[] testBytes = {0x40, (byte) 0x80, (byte) 0xE0, (byte) 0xF0, 0x10}; 158 | 159 | ArtPollBuilder builder = new ArtPollBuilder(); 160 | 161 | assertSame(Priority.Low, builder.getPriority()); 162 | 163 | for (int i = 0; i < testValues.length; i++) { 164 | 165 | Priority testValue = testValues[i]; 166 | byte testByte = testBytes[i]; 167 | 168 | builder.setPriority(testValue); 169 | assertSame(builder.getPriority(), testValue); 170 | assertPackets(getExpectedData(0x00, testByte), builder); 171 | 172 | assertSame(builder, builder.withPriority(null)); 173 | assertSame(builder.getPriority(), Priority.Low); 174 | assertPackets(getExpectedData(0x00, 0x10), builder); 175 | } 176 | } 177 | } -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/builders/ArtTimeCodeBuilderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.builders; 23 | 24 | import de.deltaeight.libartnet.descriptors.TimeCodeType; 25 | import org.junit.jupiter.api.Test; 26 | 27 | import static org.junit.jupiter.api.Assertions.*; 28 | 29 | class ArtTimeCodeBuilderTest extends AbstractPacketBuilderTest { 30 | 31 | private static final byte[] DEFAULT_PACKET = getExpectedData(0, 0, 0, 0, 0); 32 | 33 | private static byte[] getExpectedData(int type, int hours, int minutes, int seconds, int frames) { 34 | return new byte[]{ 35 | 0x41, 0x72, 0x74, 0x2D, 0x4E, 0x65, 0x74, 0x00, // Header 36 | 0x00, (byte) 0x97, // OpCode 37 | 0x00, 0x0E, // Protocol version 38 | 0x00, 0x00, // Filler 39 | (byte) frames, (byte) seconds, (byte) minutes, 40 | (byte) hours, (byte) type 41 | }; 42 | } 43 | 44 | @Test 45 | void build() { 46 | assertPackets(DEFAULT_PACKET, new ArtTimeCodeBuilder()); 47 | } 48 | 49 | @Test 50 | void type() { 51 | 52 | byte[] expectedData = getExpectedData(1, 0, 0, 0, 0); 53 | 54 | ArtTimeCodeBuilder builder = new ArtTimeCodeBuilder(); 55 | 56 | assertSame(TimeCodeType.Film, builder.getType()); 57 | 58 | builder.setType(TimeCodeType.EBU); 59 | assertSame(TimeCodeType.EBU, builder.getType()); 60 | assertPackets(expectedData, builder); 61 | 62 | builder.setType(null); 63 | assertSame(TimeCodeType.Film, builder.getType()); 64 | assertPackets(DEFAULT_PACKET, builder); 65 | 66 | assertSame(builder, builder.withType(TimeCodeType.EBU)); 67 | assertSame(TimeCodeType.EBU, builder.getType()); 68 | assertPackets(expectedData, builder); 69 | 70 | assertSame(builder, builder.withType(null)); 71 | assertSame(TimeCodeType.Film, builder.getType()); 72 | assertPackets(DEFAULT_PACKET, builder); 73 | } 74 | 75 | @Test 76 | void hours() { 77 | 78 | ArtTimeCodeBuilder builder = new ArtTimeCodeBuilder(); 79 | 80 | assertEquals(0, builder.getHours()); 81 | 82 | builder.setHours(23); 83 | assertEquals(23, builder.getHours()); 84 | assertPackets(getExpectedData(0, 23, 0, 0, 0), builder); 85 | 86 | assertSame(builder, builder.withHours(0)); 87 | assertEquals(0, builder.getHours()); 88 | assertPackets(DEFAULT_PACKET, builder); 89 | 90 | assertThrows(IllegalArgumentException.class, () -> builder.setHours(-1)); 91 | assertThrows(IllegalArgumentException.class, () -> builder.withHours(24)); 92 | } 93 | 94 | @Test 95 | void minutes() { 96 | 97 | ArtTimeCodeBuilder builder = new ArtTimeCodeBuilder(); 98 | 99 | assertEquals(0, builder.getMinutes()); 100 | 101 | builder.setMinutes(59); 102 | assertEquals(59, builder.getMinutes()); 103 | assertPackets(getExpectedData(0, 0, 59, 0, 0), builder); 104 | 105 | assertSame(builder, builder.withMinutes(0)); 106 | assertEquals(0, builder.getMinutes()); 107 | assertPackets(DEFAULT_PACKET, builder); 108 | 109 | assertThrows(IllegalArgumentException.class, () -> builder.setMinutes(-1)); 110 | assertThrows(IllegalArgumentException.class, () -> builder.withMinutes(60)); 111 | } 112 | 113 | @Test 114 | void seconds() { 115 | 116 | ArtTimeCodeBuilder builder = new ArtTimeCodeBuilder(); 117 | 118 | assertEquals(0, builder.getSeconds()); 119 | 120 | builder.setSeconds(59); 121 | assertEquals(59, builder.getSeconds()); 122 | assertPackets(getExpectedData(0, 0, 0, 59, 0), builder); 123 | 124 | assertSame(builder, builder.withSeconds(0)); 125 | assertEquals(0, builder.getSeconds()); 126 | assertPackets(DEFAULT_PACKET, builder); 127 | 128 | assertThrows(IllegalArgumentException.class, () -> builder.setSeconds(-1)); 129 | assertThrows(IllegalArgumentException.class, () -> builder.withSeconds(60)); 130 | } 131 | 132 | @Test 133 | void frames() { 134 | 135 | ArtTimeCodeBuilder builder = new ArtTimeCodeBuilder(); 136 | 137 | assertEquals(0, builder.getFrames()); 138 | 139 | builder.setFrames(23); 140 | assertEquals(23, builder.getFrames()); 141 | assertPackets(getExpectedData(0, 0, 0, 0, 23), builder); 142 | 143 | assertSame(builder, builder.withFrames(0)); 144 | assertEquals(0, builder.getFrames()); 145 | assertPackets(DEFAULT_PACKET, builder); 146 | 147 | assertThrows(IllegalArgumentException.class, () -> builder.setFrames(-1)); 148 | assertThrows(IllegalArgumentException.class, () -> builder.withFrames(24)); 149 | 150 | builder.setType(TimeCodeType.EBU); 151 | assertDoesNotThrow(() -> builder.setFrames(24)); 152 | assertThrows(IllegalArgumentException.class, () -> builder.setFrames(25)); 153 | 154 | builder.setType(TimeCodeType.DF); 155 | assertDoesNotThrow(() -> builder.setFrames(25)); 156 | assertDoesNotThrow(() -> builder.setFrames(29)); 157 | assertThrows(IllegalArgumentException.class, () -> builder.setFrames(30)); 158 | 159 | builder.setType(TimeCodeType.SMPTE); 160 | assertDoesNotThrow(() -> builder.setFrames(29)); 161 | assertThrows(IllegalArgumentException.class, () -> builder.setFrames(30)); 162 | 163 | builder.setFrames(28); 164 | builder.setType(TimeCodeType.Film); 165 | assertEquals(23, builder.getFrames()); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/doc/Receiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.doc; 23 | 24 | import de.deltaeight.libartnet.network.ArtNetReceiver; 25 | import org.junit.jupiter.api.Test; 26 | 27 | import java.net.SocketException; 28 | 29 | class Receiver { 30 | 31 | @Test 32 | void usingTheReceiver() throws SocketException { 33 | 34 | ArtNetReceiver receiver = new ArtNetReceiver() 35 | .withArtDmxReceiveHandler(packet -> System.out.println("Channel 63 value: " + packet.getData()[62])); 36 | 37 | receiver.start(); 38 | 39 | // Do other stuff 40 | 41 | receiver.stop(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/doc/Sender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.doc; 23 | 24 | import de.deltaeight.libartnet.builders.ArtPollReplyBuilder; 25 | import de.deltaeight.libartnet.descriptors.OemCode; 26 | import de.deltaeight.libartnet.network.ArtNetSender; 27 | import org.junit.jupiter.api.Test; 28 | 29 | import java.net.InetAddress; 30 | import java.net.SocketException; 31 | import java.net.UnknownHostException; 32 | 33 | class Sender { 34 | 35 | @Test 36 | void usingTheSender() throws SocketException, UnknownHostException { 37 | 38 | ArtPollReplyBuilder builder = new ArtPollReplyBuilder() 39 | .withProduct(OemCode.getProductByOemCode("OemRobertJulDalis1")) 40 | .withBindIp(new byte[]{127, 0, 0, 1}); 41 | 42 | ArtNetSender sender = new ArtNetSender(); 43 | sender.start(); 44 | 45 | sender.send(InetAddress.getByName("127.0.0.1"), builder.build()); 46 | 47 | // Do other stuff 48 | 49 | sender.stop(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/network/AbstractNetworkHandlerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | import org.junit.jupiter.api.Test; 25 | 26 | import java.io.IOException; 27 | import java.net.DatagramSocket; 28 | import java.net.SocketException; 29 | import java.util.concurrent.CountDownLatch; 30 | import java.util.concurrent.TimeUnit; 31 | import java.util.concurrent.atomic.AtomicReference; 32 | 33 | import static org.hamcrest.CoreMatchers.*; 34 | import static org.hamcrest.MatcherAssert.assertThat; 35 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 36 | import static org.junit.jupiter.api.Assertions.assertThrows; 37 | 38 | abstract class AbstractNetworkHandlerTest { 39 | 40 | abstract T getNewInstance(DatagramSocket datagramSocket); 41 | 42 | abstract void provokeException(T networkHandler) throws Exception; 43 | 44 | @Test 45 | final void states() throws SocketException { 46 | 47 | DatagramSocketMockup datagramSocketMockup = new DatagramSocketMockup(); 48 | T networkHandler = getNewInstance(datagramSocketMockup); 49 | 50 | assertThat(networkHandler.getState(), is(sameInstance(NetworkHandler.State.Initialized))); 51 | assertThrows(IllegalStateException.class, networkHandler::stop); 52 | 53 | assertDoesNotThrow(networkHandler::start); 54 | 55 | assertThat(networkHandler.getState(), is(sameInstance(NetworkHandler.State.Running))); 56 | assertThrows(IllegalStateException.class, networkHandler::start); 57 | 58 | assertDoesNotThrow(networkHandler::stop); 59 | 60 | assertThat(networkHandler.getState(), is(sameInstance(NetworkHandler.State.Stopped))); 61 | assertThrows(IllegalStateException.class, networkHandler::start); 62 | assertThrows(IllegalStateException.class, networkHandler::stop); 63 | } 64 | 65 | @Test 66 | final void exceptionHandler() throws Exception { 67 | 68 | AtomicReference handledException = new AtomicReference<>(); 69 | CountDownLatch latch = new CountDownLatch(1); 70 | 71 | T networkHandler = getNewInstance(new DatagramSocketMockup(true)); 72 | networkHandler.setExceptionHandler(exception -> { 73 | handledException.set(exception); 74 | latch.countDown(); 75 | }); 76 | 77 | networkHandler.start(); 78 | 79 | provokeException(networkHandler); 80 | 81 | assertThat(latch.await(3, TimeUnit.SECONDS), is(true)); 82 | assertThat(handledException.get(), is(instanceOf(IOException.class))); 83 | 84 | networkHandler.stop(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/network/ArtNetReceiverTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | import org.junit.jupiter.api.Test; 25 | 26 | import java.net.DatagramSocket; 27 | import java.net.SocketException; 28 | import java.util.concurrent.CountDownLatch; 29 | import java.util.concurrent.TimeUnit; 30 | import java.util.concurrent.atomic.AtomicReference; 31 | 32 | import de.deltaeight.libartnet.builders.ArtDmxBuilder; 33 | import de.deltaeight.libartnet.builders.ArtNetPacketBuilder; 34 | import de.deltaeight.libartnet.builders.ArtPollBuilder; 35 | import de.deltaeight.libartnet.builders.ArtPollReplyBuilder; 36 | import de.deltaeight.libartnet.builders.ArtTimeCodeBuilder; 37 | import de.deltaeight.libartnet.packets.ArtNetPacket; 38 | 39 | import static org.hamcrest.CoreMatchers.equalTo; 40 | import static org.hamcrest.CoreMatchers.is; 41 | import static org.hamcrest.MatcherAssert.assertThat; 42 | import static org.junit.jupiter.api.Assertions.assertThrows; 43 | 44 | class ArtNetReceiverTest extends AbstractNetworkHandlerTest { 45 | 46 | @Override 47 | ArtNetReceiver getNewInstance(DatagramSocket datagramSocket) { 48 | return new ArtNetReceiver(datagramSocket); 49 | } 50 | 51 | @Override 52 | void provokeException(ArtNetReceiver networkHandler) { 53 | // Do nothing 54 | } 55 | 56 | @Test 57 | final void constructor() { 58 | assertThrows(IllegalArgumentException.class, () -> getNewInstance(new DatagramSocketMockup(666))); 59 | } 60 | 61 | private void testReceiveHandler(ArtNetReceiverPreparation artNetReceiverPreparation, 62 | ArtNetPacketBuilder packetBuilder) 63 | 64 | throws SocketException, InterruptedException { 65 | 66 | AtomicReference packetReference = new AtomicReference<>(); 67 | CountDownLatch latch = new CountDownLatch(1); 68 | 69 | DatagramSocketMockup datagramSocketMockup = new DatagramSocketMockup(); 70 | 71 | artNetReceiverPreparation.prepare(new ArtNetReceiver(datagramSocketMockup), packet -> { 72 | packetReference.set(packet); 73 | latch.countDown(); 74 | }).start(); 75 | 76 | T packet = packetBuilder.build(); 77 | 78 | datagramSocketMockup.injectPacket(packet); 79 | 80 | assertThat(latch.await(3, TimeUnit.SECONDS), is(true)); 81 | assertThat(packet, is(equalTo(packetReference.get()))); 82 | } 83 | 84 | @Test 85 | void receiveHandlers() throws SocketException, InterruptedException { 86 | testReceiveHandler(ArtNetReceiver::withArtDmxReceiveHandler, new ArtDmxBuilder()); 87 | testReceiveHandler(ArtNetReceiver::withArtPollReceiveHandler, new ArtPollBuilder()); 88 | testReceiveHandler(ArtNetReceiver::withArtPollReplyReceiveHandler, new ArtPollReplyBuilder()); 89 | testReceiveHandler(ArtNetReceiver::withArtTimeCodeReceiveHandler, new ArtTimeCodeBuilder()); 90 | } 91 | 92 | @FunctionalInterface 93 | private interface ArtNetReceiverPreparation { 94 | 95 | ArtNetReceiver prepare(ArtNetReceiver artNetReceiver, PacketReceiveHandler packetReceiveHandler); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/network/ArtNetSenderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2019 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | import de.deltaeight.libartnet.builders.ArtDmxBuilder; 25 | import de.deltaeight.libartnet.packets.ArtDmx; 26 | import org.junit.jupiter.api.Test; 27 | 28 | import java.net.*; 29 | import java.util.concurrent.CountDownLatch; 30 | import java.util.concurrent.TimeUnit; 31 | import java.util.concurrent.atomic.AtomicReference; 32 | 33 | import static org.hamcrest.CoreMatchers.equalToObject; 34 | import static org.hamcrest.CoreMatchers.is; 35 | import static org.hamcrest.MatcherAssert.assertThat; 36 | 37 | class ArtNetSenderTest extends AbstractNetworkHandlerTest { 38 | 39 | @Override 40 | ArtNetSender getNewInstance(DatagramSocket datagramSocket) { 41 | return new ArtNetSender(datagramSocket); 42 | } 43 | 44 | @Override 45 | void provokeException(ArtNetSender networkHandler) throws Exception { 46 | networkHandler.send(InetAddress.getByName("127.0.0.1"), new ArtDmxBuilder().build()); 47 | } 48 | 49 | @Test 50 | final void send() throws SocketException, UnknownHostException, InterruptedException { 51 | 52 | AtomicReference receivedPacket = new AtomicReference<>(); 53 | CountDownLatch latch = new CountDownLatch(1); 54 | 55 | ArtDmx artDmx = new ArtDmxBuilder().build(); 56 | 57 | DatagramSocketMockup datagramSocketMockup = new DatagramSocketMockup(); 58 | datagramSocketMockup.setOnPacketSent(packet -> { 59 | receivedPacket.set(packet); 60 | latch.countDown(); 61 | }); 62 | 63 | ArtNetSender artNetSender = new ArtNetSender(datagramSocketMockup); 64 | artNetSender.start(); 65 | artNetSender.send(InetAddress.getByName("127.0.0.1"), artDmx); 66 | 67 | assertThat(latch.await(3, TimeUnit.SECONDS), is(true)); 68 | assertThat(artDmx.getBytes(), is(equalToObject(receivedPacket.get().getData()))); 69 | 70 | artNetSender.stop(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/network/DatagramSocketMockup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2018 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | import de.deltaeight.libartnet.packets.ArtNetPacket; 25 | 26 | import java.io.IOException; 27 | import java.net.DatagramPacket; 28 | import java.net.DatagramSocket; 29 | import java.net.SocketException; 30 | 31 | class DatagramSocketMockup extends DatagramSocket { 32 | 33 | private final int localPort; 34 | private boolean throwIoException; 35 | private ArtNetPacket injectArtNetPacket; 36 | private boolean closed; 37 | private PacketSentHandler onPacketSent; 38 | 39 | DatagramSocketMockup() throws SocketException { 40 | this.localPort = 0x1936; 41 | } 42 | 43 | DatagramSocketMockup(int localPort) throws SocketException { 44 | this.localPort = localPort; 45 | } 46 | 47 | DatagramSocketMockup(boolean throwIoException) throws SocketException { 48 | this(); 49 | this.throwIoException = throwIoException; 50 | } 51 | 52 | @Override 53 | public void send(DatagramPacket p) throws IOException { 54 | if (throwIoException) { 55 | throw new IOException(); 56 | } else if (onPacketSent != null) { 57 | onPacketSent.handle(p); 58 | } 59 | } 60 | 61 | @Override 62 | public synchronized void receive(DatagramPacket packet) throws IOException { 63 | boolean wait = true; 64 | while (!closed && wait) { 65 | try { 66 | if (throwIoException) { 67 | throwIoException = false; 68 | throw new IOException(); 69 | } else if (injectArtNetPacket != null) { 70 | packet.setData(injectArtNetPacket.getBytes()); 71 | packet.setPort(0x1936); 72 | packet.setLength(injectArtNetPacket.getBytes().length); 73 | injectArtNetPacket = null; 74 | wait = false; 75 | } 76 | if (wait) { 77 | Thread.sleep(10); 78 | } 79 | } catch (InterruptedException ignored) { 80 | } 81 | } 82 | } 83 | 84 | @Override 85 | public int getLocalPort() { 86 | return localPort; 87 | } 88 | 89 | @Override 90 | public void close() { 91 | closed = true; 92 | } 93 | 94 | void injectPacket(ArtNetPacket packet) { 95 | injectArtNetPacket = packet; 96 | } 97 | 98 | void setOnPacketSent(PacketSentHandler onPacketSent) { 99 | this.onPacketSent = onPacketSent; 100 | } 101 | 102 | @FunctionalInterface 103 | interface PacketSentHandler { 104 | 105 | void handle(DatagramPacket packet); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lib/src/test/java/de/deltaeight/libartnet/network/NetworkPacketIntegrityTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.network; 23 | 24 | import org.junit.jupiter.api.Test; 25 | 26 | import java.net.DatagramSocket; 27 | import java.net.InetAddress; 28 | import java.net.SocketException; 29 | import java.net.UnknownHostException; 30 | import java.util.ArrayList; 31 | import java.util.HashMap; 32 | import java.util.concurrent.ConcurrentLinkedQueue; 33 | 34 | import de.deltaeight.libartnet.builders.ArtDmxBuilder; 35 | import de.deltaeight.libartnet.packets.ArtDmx; 36 | 37 | import static org.hamcrest.MatcherAssert.assertThat; 38 | import static org.hamcrest.Matchers.equalTo; 39 | import static org.hamcrest.Matchers.is; 40 | 41 | class NetworkPacketIntegrityTest { 42 | 43 | @Test 44 | void networkPacketIntegrityTest() 45 | throws SocketException, UnknownHostException, InterruptedException { 46 | 47 | // Adjust number of test packets. 512 * 256 is maximum for discrete packet numbering. 48 | // Too many packets may increase packet loss. 49 | int numberOfTestPackets = 10000; 50 | 51 | ArrayList builders = new ArrayList<>(128 * 16 * 16); 52 | for (int i = 0; i < 128; i++) { 53 | for (int j = 0; j < 16; j++) { 54 | for (int k = 0; k < 16; k++) { 55 | builders.add(new ArtDmxBuilder() 56 | .withNetAddress(i) 57 | .withSubnetAddress(j) 58 | .withUniverseAddress(k)); 59 | } 60 | } 61 | } 62 | 63 | byte[][] dataSources = new byte[numberOfTestPackets][]; 64 | for (int i = 0; i < numberOfTestPackets; i++) { 65 | dataSources[i] = getDataArray(i); 66 | } 67 | 68 | ConcurrentLinkedQueue receivedPackets = new ConcurrentLinkedQueue<>(); 69 | ArtNetReceiver receiver = new ArtNetReceiver() 70 | .withArtDmxReceiveHandler(receivedPackets::add); 71 | receiver.start(); 72 | 73 | Thread.sleep(2000); 74 | 75 | HashMap sentPackets = new HashMap<>(); 76 | ArtNetSender sender = new ArtNetSender(new DatagramSocket()); 77 | sender.start(); 78 | InetAddress ip = InetAddress.getByName("127.0.0.1"); 79 | int builderCounter = 0; 80 | for (int i = 0; i < numberOfTestPackets; i++) { 81 | byte[] data = dataSources[i]; 82 | ArtDmx packet = builders.get(builderCounter) 83 | .withData(data) 84 | .build(); 85 | sentPackets.put(getHash(packet), packet); 86 | sender.send(ip, packet); 87 | 88 | if (++builderCounter == builders.size()) { 89 | builderCounter = 0; 90 | } 91 | } 92 | 93 | int receivedPacketCounter = 0; 94 | long end = System.currentTimeMillis() + 2000; 95 | while (System.currentTimeMillis() < end) { 96 | ArtDmx receivedPacket = receivedPackets.poll(); 97 | if (receivedPacket != null) { 98 | ArtDmx sentPacket = sentPackets.get(getHash(receivedPacket)); 99 | assertThat(receivedPacket, is(equalTo(sentPacket))); 100 | assertThat(receivedPacket.getData(), is(equalTo(sentPacket.getData()))); 101 | assertThat(receivedPacket.getBytes(), is(equalTo(sentPacket.getBytes()))); 102 | receivedPacketCounter++; 103 | } 104 | } 105 | 106 | System.out.println("Sent packets: " + sentPackets.size()); 107 | System.out.println("Received packets: " + receivedPacketCounter); 108 | System.out.println("Loss: " + (1 - ((receivedPacketCounter * 1d) / sentPackets.size()))); 109 | 110 | sender.stop(); 111 | receiver.stop(); 112 | } 113 | 114 | private String getHash(byte[] data, int netAddress, int subnetAddress, int universeAddress) { 115 | int sum = 0; 116 | for (byte datum : data) { 117 | sum += datum & 0xFF; 118 | } 119 | return sum + " " + netAddress + " " + subnetAddress + " " + universeAddress; 120 | } 121 | 122 | private String getHash(ArtDmx packet) { 123 | return getHash(packet.getData(), packet.getNetAddress(), packet.getSubnetAddress(), 124 | packet.getUniverseAddress()); 125 | } 126 | 127 | private byte[] getDataArray(int index) { 128 | byte[] result = new byte[512]; 129 | for (int i = 0; i < 512; i++) { 130 | result[i] = (byte) (index >>> 8 * i); 131 | if (result[i] == 0) { 132 | break; 133 | } 134 | } 135 | return result; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /maven-key.gpg.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deltaeight/LibArtNet/90e4b834b44de6740cec11e2021bb61c05c447f4/maven-key.gpg.enc -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'lib' 2 | include 'util' 3 | 4 | rootProject.name = 'LibArtNet' 5 | project(':lib').name = 'LibArtNet' -------------------------------------------------------------------------------- /util/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | group 'de.deltaeight' 6 | version '1.0-beta' 7 | 8 | sourceCompatibility = 1.8 9 | targetCompatibility = 1.8 10 | 11 | dependencies { 12 | 13 | // Test framework 14 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2' 15 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.2' 16 | } 17 | 18 | test { 19 | useJUnitPlatform() 20 | } 21 | -------------------------------------------------------------------------------- /util/src/main/java/de/deltaeight/libartnet/util/OemJsonGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * LibArtNet 3 | * 4 | * Art-Net(TM) Designed by and Copyright Artistic Licence Holdings Ltd 5 | * 6 | * Copyright (c) 2020 Julian Rabe 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of 14 | * the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 17 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | package de.deltaeight.libartnet.util; 23 | 24 | import java.io.IOException; 25 | import java.net.URISyntaxException; 26 | import java.nio.file.Files; 27 | import java.nio.file.Paths; 28 | import java.util.LinkedList; 29 | import java.util.List; 30 | import java.util.StringJoiner; 31 | import java.util.regex.Matcher; 32 | import java.util.regex.Pattern; 33 | 34 | /** 35 | * This is a nifty tool to auto-generate the {@code OemCode} enum. All you need is {@code Art-NetOemCodes.h} from 36 | * Artistic License Ltd. which you can obtain 37 | * here. You will then need 38 | * to put it into the resources of this package. {@link #main(String...)} will then generate the enum under 39 | * {@code lib/src/main/java/de/deltaeight/libartnet/descriptors/OemCode.java}. 40 | * 41 | * @author Julian Rabe 42 | */ 43 | public class OemJsonGenerator { 44 | 45 | private static final Pattern pattern = Pattern.compile("#define (Oem[a-zA-Z0-9_]+)[ \\xA0]+" + 46 | "0x([a-fA-F0-9]{4})[ \\xA0]+" + 47 | "//Manufacturer:[ \\xA0](.+)[ \\xA0]+" + 48 | "ProductName:[ \\xA0](.+)[ \\xA0]+" + 49 | "NumDmxIn:[ \\xA0](\\d+)[ \\xA0]+" + 50 | "NumDmxOut:[ \\xA0](\\d+)[ \\xA0]+" + 51 | "DmxPortPhysical:[ \\xA0]((?:[jnyJNY])|(?:[nN]o)|(?:[yY]es)|(?:[pP]hysical)|\\d).*[ \\xA0]+" + 52 | "RdmSupported:[ \\xA0]((?:[jnyJNY])|(?:[nN]o)|(?:[yY]es)|(?:RDM))[ \\xA0]+" + 53 | "SupportEmail:[ \\xA0](.*)[ \\xA0]+" + 54 | "SupportName:[ \\xA0](.*)[ \\xA0]+" + 55 | "CoWeb:.*"); 56 | 57 | public static void main(String... args) throws IOException, URISyntaxException { 58 | 59 | List lines = Files.readAllLines(Paths.get(OemJsonGenerator.class 60 | .getResource("Art-NetOemCodes.h").toURI())); 61 | 62 | StringJoiner parsedLines = new StringJoiner(",\n"); 63 | LinkedList unparsedLines = new LinkedList<>(); 64 | 65 | int productCounter = 0; 66 | 67 | for (String line : lines) { 68 | 69 | String codeEntry = createCodeEntry(line); 70 | 71 | if (codeEntry != null) { 72 | parsedLines.add(codeEntry); 73 | productCounter++; 74 | } else { 75 | unparsedLines.add(line); 76 | } 77 | } 78 | 79 | Files.write(Paths.get("lib/src/main/resources/de/deltaeight/libartnet/descriptors/OemCodes.json"), 80 | ("[\n" + parsedLines.toString() + "\n]").getBytes()); 81 | 82 | System.out.println("Result written to OemCodes.json!"); 83 | System.out.println("Products parsed: " + productCounter); 84 | System.out.println("Unparsed lines: " + unparsedLines.size()); 85 | System.out.println(); 86 | System.out.println("Unparsed lines follow:"); 87 | System.out.println("######################"); 88 | 89 | for (String line : unparsedLines) { 90 | if (!line.replaceAll("\\s", "").isEmpty()) { 91 | System.out.println(line); 92 | } 93 | } 94 | } 95 | 96 | private static String createCodeEntry(String line) { 97 | 98 | Matcher matcher = pattern.matcher(line); 99 | if (matcher.matches()) { 100 | 101 | boolean dmxPortsPhysical; 102 | try { 103 | dmxPortsPhysical = Integer.parseInt(matcher.group(7)) > 0; 104 | } catch (NumberFormatException e) { 105 | dmxPortsPhysical = matcher.group(7).equalsIgnoreCase("y") 106 | || matcher.group(7).equalsIgnoreCase("yes") 107 | || matcher.group(7).equalsIgnoreCase("physical"); 108 | } 109 | 110 | boolean supportsRdm = matcher.group(8).equalsIgnoreCase("y") 111 | || matcher.group(8).equalsIgnoreCase("yes") 112 | || matcher.group(8).equalsIgnoreCase("rdm"); 113 | 114 | return " { " + 115 | "\"oemCode\": \"" + matcher.group(1) + "\", " + 116 | "\"productCode\": " + Integer.parseInt(matcher.group(2), 16) + ", " + 117 | "\"manufacturer\": \"" + matcher.group(3) + "\", " + 118 | "\"name\": \"" + matcher.group(4) + "\", " + 119 | "\"dmxOutputs\": " + Integer.parseInt(matcher.group(5)) + ", " + 120 | "\"dmxInputs\": " + Integer.parseInt(matcher.group(6)) + ", " + 121 | "\"dmxPortsPhysical\": \"" + dmxPortsPhysical + "\", " + 122 | "\"supportsRdm\": \"" + supportsRdm + "\", " + 123 | "\"supportEmail\": \"" + matcher.group(9) + "\", " + 124 | "\"supportName\": \"" + matcher.group(10) + "\" " + 125 | "}"; 126 | } 127 | 128 | return null; 129 | } 130 | } 131 | --------------------------------------------------------------------------------