diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/app.iml b/app/app.iml
new file mode 100644
index 0000000..3df55b5
--- /dev/null
+++ b/app/app.iml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generateDebugSources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..2f6d8a6
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,28 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 28
+ defaultConfig {
+ applicationId "com.xbw.rosbridge"
+ minSdkVersion 21
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.2'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/src/androidTest/java/com/xbw/rosbridge/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/xbw/rosbridge/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..a3620a4
--- /dev/null
+++ b/app/src/androidTest/java/com/xbw/rosbridge/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.xbw.rosbridge;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.xbw.rosbridge", appContext.getPackageName());
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c8a40ca
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/xbw/rosbridge/MainActivity.java b/app/src/main/java/com/xbw/rosbridge/MainActivity.java
new file mode 100644
index 0000000..f462fc2
--- /dev/null
+++ b/app/src/main/java/com/xbw/rosbridge/MainActivity.java
@@ -0,0 +1,13 @@
+package com.xbw.rosbridge;
+
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+}
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..c7bd21d
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..d5fccc5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..84f1951
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a2f5908
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..1b52399
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..ff10afd
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..115a4c7
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..dcd3cd8
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..459ca60
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..8ca12fe
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..8e19b41
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b824ebd
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..4c19a13
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..c89145a
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ rosbridge
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/app/src/test/java/com/xbw/rosbridge/ExampleUnitTest.java b/app/src/test/java/com/xbw/rosbridge/ExampleUnitTest.java
new file mode 100644
index 0000000..afbc4bf
--- /dev/null
+++ b/app/src/test/java/com/xbw/rosbridge/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.xbw.rosbridge;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..1a3d812
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,27 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.1.2'
+
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..743d692
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,13 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7a3265e
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..863da2f
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sat Mar 16 11:39:26 CST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/local.properties b/local.properties
new file mode 100644
index 0000000..7db3efd
--- /dev/null
+++ b/local.properties
@@ -0,0 +1,9 @@
+## This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+#Sat Mar 16 11:39:26 CST 2019
+ndk.dir=/Users/xubowen/Library/Android/sdk/ndk-bundle
+sdk.dir=/Users/xubowen/Library/Android/sdk
diff --git a/ros/.gitignore b/ros/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/ros/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/ros/build.gradle b/ros/build.gradle
new file mode 100644
index 0000000..4d9d3ca
--- /dev/null
+++ b/ros/build.gradle
@@ -0,0 +1,37 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 28
+
+
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.2'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+ implementation 'com.googlecode.json-simple:json-simple:1.1'
+ implementation 'org.java-websocket:Java-WebSocket:1.3.9'
+ implementation 'de.greenrobot:eventbus:2.4.1'
+}
diff --git a/ros/proguard-rules.pro b/ros/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/ros/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/ros/ros.iml b/ros/ros.iml
new file mode 100644
index 0000000..b22b08f
--- /dev/null
+++ b/ros/ros.iml
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generateDebugSources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ros/src/androidTest/java/com/xbw/ros/ExampleInstrumentedTest.java b/ros/src/androidTest/java/com/xbw/ros/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..1090571
--- /dev/null
+++ b/ros/src/androidTest/java/com/xbw/ros/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.xbw.ros;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.xbw.ros.test", appContext.getPackageName());
+ }
+}
diff --git a/ros/src/main/AndroidManifest.xml b/ros/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..df458d1
--- /dev/null
+++ b/ros/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/ros/src/main/java/com/xbw/ros/Example.java b/ros/src/main/java/com/xbw/ros/Example.java
new file mode 100755
index 0000000..71b6a9b
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/Example.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) 2014 xbw Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros;
+
+import com.xbw.ros.message.Clock;
+import com.xbw.ros.message.Log;
+import com.xbw.ros.rosapi.message.Empty;
+import com.xbw.ros.rosapi.message.GetTime;
+import com.xbw.ros.rosapi.message.MessageDetails;
+import com.xbw.ros.rosapi.message.Type;
+import com.xbw.ros.rosbridge.ROSBridgeClient;
+
+public class Example {
+
+ public Example() {}
+
+ public static void main(String[] args) {
+ ROSBridgeClient client = new ROSBridgeClient("ws://162.243.238.80:9090");
+ client.connect();
+ //testTopic(client);
+ try {
+ testService(client);
+ }
+ catch (RuntimeException ex) {
+ ex.printStackTrace();
+ }
+ finally {
+ client.disconnect();
+ }
+ }
+
+ public static void testService(ROSBridgeClient client) {
+ try {
+ Service timeService =
+ new Service("/rosapi/get_time", Empty.class, GetTime.class, client);
+ timeService.verify();
+ //System.out.println("Time (secs): " + timeService.callBlocking(new Empty()).time.sec);
+
+ Service serviceTypeService =
+ new Service("/rosapi/service_type",
+ com.xbw.ros.rosapi.message.Service.class, Type.class, client);
+ serviceTypeService.verify();
+ String type = serviceTypeService.callBlocking(new com.xbw.ros.rosapi.message.Service("/rosapi/service_response_details")).type;
+
+ Service serviceDetails =
+ new Service("/rosapi/service_response_details",
+ Type.class, MessageDetails.class, client);
+ serviceDetails.verify();
+ //serviceDetails.callBlocking(new Type(type)).print();
+
+ com.xbw.ros.Topic logTopic =
+ new com.xbw.ros.Topic("/rosout", Log.class, client);
+ logTopic.verify();
+
+ /*
+ System.out.println("Nodes");
+ for (String s : client.getNodes())
+ System.out.println(" " + s);
+ System.out.println("Topics");
+ for (String s : client.getTopics()) {
+ System.out.println(s + ":");
+ client.getTopicMessageDetails(s).print();
+ }
+ System.out.println("Services");
+ for (String s : client.getServices()) {
+ System.out.println(s + ":");
+ client.getServiceRequestDetails(s).print();
+ System.out.println("-----------------");
+ client.getServiceResponseDetails(s).print();
+ }
+ */
+ }
+ catch (InterruptedException ex) {
+ System.out.println("Process was interrupted.");
+ }
+ /*
+ Service topicService =
+ new Service("/rosapi/topics", Empty.class, Topics.class, client);
+ Service typeService =
+ new Service("/rosapi/topic_type", Topic.class, Type.class, client);
+ Service messageService =
+ new Service("/rosapi/message_details", Type.class, MessageDetails.class, client);
+ try {
+ Topics topics = topicService.callBlocking(new Empty());
+ for (String topicString : topics.topics) {
+ Topic topic = new Topic();
+ topic.topic = topicString;
+ Type type = typeService.callBlocking(topic);
+ MessageDetails details = messageService.callBlocking(type);
+ System.out.println("Topic: " + topic.topic + " Type: " + type.type);
+ details.print();
+ System.out.println();
+ }
+ Type type = new Type();
+ type.type = "time";
+ System.out.print("Single type check on \'time\': ");
+ messageService.callBlocking(type).print();
+ }
+ catch (InterruptedException ex) {
+ System.out.println("testService: process was interrupted.");
+ }
+ */
+ }
+
+ public static void testTopic(ROSBridgeClient client) {
+ com.xbw.ros.Topic clockTopic = new com.xbw.ros.Topic("/clock", Clock.class, client);
+ clockTopic.subscribe();
+ try {Thread.sleep(20000);} catch(InterruptedException ex) {}
+ Clock cl = null;
+ try {
+ cl = clockTopic.take(); // just gets one
+ }
+ catch (InterruptedException ex) {}
+ cl.print();
+ cl.clock.nsecs++;
+ clockTopic.unsubscribe();
+ clockTopic.advertise();
+ clockTopic.publish(cl);
+ clockTopic.unadvertise();
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/MessageHandler.java b/ros/src/main/java/com/xbw/ros/MessageHandler.java
new file mode 100755
index 0000000..0f78910
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/MessageHandler.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2014 xbw Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros;
+
+import com.xbw.ros.message.Message;
+
+public interface MessageHandler {
+ public void onMessage(T message);
+}
diff --git a/ros/src/main/java/com/xbw/ros/PublishEvent.java b/ros/src/main/java/com/xbw/ros/PublishEvent.java
new file mode 100755
index 0000000..c241887
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/PublishEvent.java
@@ -0,0 +1,24 @@
+package com.xbw.ros;
+
+import com.xbw.ros.rosbridge.operation.Operation;
+
+/**EventBus event entity,describe ros server response info
+ * Created by xbw on 19-1-15.
+ */
+
+public class PublishEvent {
+ public String msg;
+ public String id;
+ public String name;
+ public String op;
+
+
+ public PublishEvent(Operation operation, String name, String content) {
+ if(operation != null) {
+ id = operation.id;
+ op = operation.op;
+ }
+ this.name = name;
+ msg = content;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/ROSClient.java b/ros/src/main/java/com/xbw/ros/ROSClient.java
new file mode 100755
index 0000000..af0ffe9
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/ROSClient.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2014 xbw Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.rosapi.message.TypeDef;
+import com.xbw.ros.rosbridge.FullMessageHandler;
+import com.xbw.ros.rosbridge.ROSBridgeClient;
+import com.xbw.ros.rosbridge.operation.Operation;
+
+public abstract class ROSClient {
+
+ public ROSClient() {}
+
+ public static ROSClient create(String uriString) {
+ // if we ever implement other ROSClient types, we'll key off the URI protocol (e.g., ws://)
+ // we'd also have to abstract out Topic and Service since they depend on the ROSBridge operations
+ return new ROSBridgeClient(uriString);
+ }
+
+ public abstract boolean connect();
+ public abstract boolean connect(ConnectionStatusListener listener);
+ public abstract void disconnect();
+ public abstract void send(Operation operation);
+ public abstract void send(String json);
+ public abstract void register(Class extends Operation> c,
+ String s,
+ Class extends Message> m,
+ FullMessageHandler h);
+ public abstract void unregister(Class extends Operation> c, String s);
+ public abstract void setDebug(boolean debug);
+ public abstract String[] getNodes() throws InterruptedException;
+ public abstract String[] getTopics() throws InterruptedException;
+ public abstract String[] getServices() throws InterruptedException;
+ public abstract TypeDef getTopicMessageDetails(String topic) throws InterruptedException;
+ public abstract TypeDef[] getTopicMessageList(String topic) throws InterruptedException;
+ public abstract TypeDef getServiceRequestDetails(String service) throws InterruptedException;
+ public abstract TypeDef[] getServiceRequestList(String service) throws InterruptedException;
+ public abstract TypeDef getServiceResponseDetails(String service) throws InterruptedException;
+ public abstract TypeDef[] getServiceResponseList(String service) throws InterruptedException;
+ public abstract TypeDef getTypeDetails(String type) throws InterruptedException;
+ public abstract TypeDef[] getTypeList(String type) throws InterruptedException;
+ public abstract void typeMatch(TypeDef t, Class extends Message> c) throws InterruptedException;
+ public abstract Object getUnderlyingClient(); // for debugging
+
+ public interface ConnectionStatusListener {
+ public void onConnect();
+ public void onDisconnect(boolean normal, String reason, int code);
+ public void onError(Exception ex);
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/Service.java b/ros/src/main/java/com/xbw/ros/Service.java
new file mode 100755
index 0000000..89946f0
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/Service.java
@@ -0,0 +1,134 @@
+/**
+ * Copyright (c) 2014 xbw Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.rosbridge.FullMessageHandler;
+import com.xbw.ros.rosbridge.operation.CallService;
+import com.xbw.ros.rosbridge.operation.ServiceResponse;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+public class Service extends Message implements FullMessageHandler {
+ private String service;
+ private Class extends ResponseType> responseType;
+ private Class extends CallType> callType;
+ private ROSClient client;
+ private Map calls;
+
+ public Service(String service, Class extends CallType> callType,
+ Class extends ResponseType> responseType, ROSClient client) {
+ this.service = service;
+ this.client = client;
+ this.responseType = responseType;
+ this.callType = callType;
+ calls = new HashMap();
+ }
+
+ // A result can only be returned once; it is cleared from the hash before
+ // being sent/returned. This is to ensure that results do not accumulate
+ // indefinitely. If callers need to keep these around they can set up their
+ // own hash.
+
+ @Override
+ public void onMessage(String id, Message response) {
+ //System.out.print("Service.onMessage: ");
+ //response.print();
+ CallRecord call = calls.get(id);
+ if(call == null) {
+ System.out.print("No caller service response");
+ return;
+ }
+ if (call.handler != null) {
+ calls.remove(id);
+ call.handler.onMessage((ResponseType) response);
+ }
+ else {
+ call.result = (ResponseType) response;
+ call.latch.countDown();
+ }
+ }
+
+ public String call(CallType args) {
+ return callImpl(args, null);
+ }
+
+ public void callWithHandler(CallType args, MessageHandler responseHandler) {
+ callImpl(args, responseHandler);
+ }
+
+ public ResponseType callBlocking(CallType args) throws InterruptedException {
+ return take(call(args));
+ }
+
+ private String callImpl(CallType args, MessageHandler responseHandler) {
+ client.register(ServiceResponse.class, service, responseType, this); // do this once on creation?
+ CallService messageCallService = new CallService(service, args);
+ String id = messageCallService.id;
+ CallRecord callRecord = new CallRecord(responseHandler);
+ calls.put(id, callRecord);
+ client.send(messageCallService);
+ return id;
+ }
+
+ public ResponseType poll(String id) {
+ CallRecord call = calls.get(id);
+ if (call.result != null)
+ calls.remove(id);
+ return call.result;
+ }
+
+ public ResponseType take(String id) throws InterruptedException {
+ CallRecord call = calls.get(id);
+ call.latch.await();
+ calls.remove(id);
+ return call.result;
+ }
+
+ public void verify() throws InterruptedException {
+
+ boolean hasService = false;
+ for (String s : client.getServices()) {
+ if (s.equals(service)) {
+ hasService = true;
+ break;
+ }
+ }
+ if (!hasService)
+ throw new RuntimeException("Service \'" + service + "\' not available.");
+
+ client.typeMatch(client.getServiceRequestDetails(service), callType);
+ client.typeMatch(client.getServiceResponseDetails(service), responseType);
+ }
+
+ private class CallRecord {
+ public ResponseType result;
+ public CountDownLatch latch;
+ public MessageHandler handler;
+
+ public CallRecord(MessageHandler handler) {
+ this.result = null;
+ this.latch = new CountDownLatch(1);
+ this.handler = handler;
+ }
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/Topic.java b/ros/src/main/java/com/xbw/ros/Topic.java
new file mode 100755
index 0000000..222b4c1
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/Topic.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2014 xbw Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.rosbridge.FullMessageHandler;
+import com.xbw.ros.rosbridge.operation.Advertise;
+import com.xbw.ros.rosbridge.operation.Operation;
+import com.xbw.ros.rosbridge.operation.Publish;
+import com.xbw.ros.rosbridge.operation.Subscribe;
+import com.xbw.ros.rosbridge.operation.Unadvertise;
+import com.xbw.ros.rosbridge.operation.Unsubscribe;
+
+import java.util.concurrent.LinkedBlockingQueue;
+
+
+public class Topic extends LinkedBlockingQueue implements FullMessageHandler {
+ protected String topic;
+ private Class extends T> type;
+ private String messageType;
+ private ROSClient client;
+ private Thread handlerThread;
+
+ public Topic(String topic, Class extends T> type, ROSClient client) {
+ this.topic = topic;
+ this.client = client;
+ this.type = type;
+ messageType = Message.getMessageType(type);
+ handlerThread = null;
+ }
+
+ @Override
+ public void onMessage(String id, Message message) {
+ add((T) message);
+ }
+
+
+ // warning: there is a delay between the completion of this method and
+ // the completion of the subscription; it takes longer than
+ // publishing multiple other messages, for example.
+ public void subscribe(MessageHandler handler) {
+ startRunner(handler);
+ subscribe();
+ }
+
+ public void subscribe() {
+ client.register(Publish.class, topic, type, this);
+ send(new Subscribe(topic, messageType));
+ }
+
+ public void unsubscribe() {
+ // need to handle race conditions in incoming message handler
+ // so that once unsubscribe has happened the handler gets no more
+ // messages
+ send(new Unsubscribe(topic));
+ client.unregister(Publish.class, topic);
+ stopRunner();
+ }
+
+ private void startRunner(MessageHandler handler) {
+ stopRunner();
+ handlerThread = new Thread(new MessageRunner(handler));
+ handlerThread.setName("Message handler for " + topic);
+ handlerThread.start();
+ }
+
+ private void stopRunner() {
+ if (handlerThread != null) {
+ handlerThread.interrupt();
+ clear();
+ handlerThread = null;
+ }
+ }
+
+
+ public void advertise() {
+ send(new Advertise(topic, messageType));
+ }
+
+ public void publish(T message) {
+ send(new Publish(topic, message));
+ }
+
+ public void unadvertise() {
+ send(new Unadvertise(topic));
+ }
+
+ private void send(Operation operation) {
+ client.send(operation);
+ }
+
+ public void verify() throws InterruptedException {
+
+ boolean hasTopic = false;
+ for (String s : client.getTopics()) {
+ if (s.equals(topic)) {
+ hasTopic = true;
+ break;
+ }
+ }
+ if (!hasTopic)
+ throw new RuntimeException("Topic \'" + topic + "\' not available.");
+
+ client.typeMatch(client.getTopicMessageDetails(topic), type);
+ }
+
+ private class MessageRunner implements Runnable {
+ private MessageHandler handler;
+
+ public MessageRunner(MessageHandler handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ public void run() {
+ while (!Thread.interrupted()) {
+ try {
+ handler.onMessage(take());
+ }
+ catch (InterruptedException ex) {
+ break;
+ }
+ }
+ }
+ }
+
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/Clock.java b/ros/src/main/java/com/xbw/ros/message/Clock.java
new file mode 100755
index 0000000..0d85982
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/Clock.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+@MessageType(string = "rosgraph_msgs/Clock")
+public class Clock extends Message {
+ public TimePrimitive clock;
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/Duration.java b/ros/src/main/java/com/xbw/ros/message/Duration.java
new file mode 100755
index 0000000..50b0314
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/Duration.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+@MessageType(string = "std_msgs/Duration")
+public class Duration extends DurationPrimitive {
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/DurationPrimitive.java b/ros/src/main/java/com/xbw/ros/message/DurationPrimitive.java
new file mode 100755
index 0000000..ddf87b0
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/DurationPrimitive.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+@MessageType(string = "duration")
+public class DurationPrimitive extends TimePrimitive {
+
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/Empty.java b/ros/src/main/java/com/xbw/ros/message/Empty.java
new file mode 100755
index 0000000..d48fbea
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/Empty.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+@MessageType(string = "std_srvs/Empty")
+public class Empty extends Message {
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/Header.java b/ros/src/main/java/com/xbw/ros/message/Header.java
new file mode 100755
index 0000000..4c335d5
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/Header.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+@MessageType(string = "std_msgs/Header")
+public class Header extends Message {
+ public long seq;
+ public TimePrimitive stamp;
+ public String frame_id;
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/Log.java b/ros/src/main/java/com/xbw/ros/message/Log.java
new file mode 100755
index 0000000..640b7a5
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/Log.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+@MessageType(string = "rosgraph_msgs/Log")
+public class Log extends Message {
+ public Header header;
+ public byte level;
+ public String name;
+ public String msg;
+ public String file;
+ public String function;
+ public long line;
+ public String[] topics;
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/Message.java b/ros/src/main/java/com/xbw/ros/message/Message.java
new file mode 100755
index 0000000..43e8b15
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/Message.java
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.util.Map;
+
+
+@MessageType(string = "message")
+public abstract class Message {
+
+ // Some requirements about message types:
+ // - It must have a MessageType declaration to be recognized on inbound messages
+ // - Every field must be explicitly designated as public
+ // - Every field that is not a primitive or near-primitive must be another Message class
+ // - If there is a non-empty constructor, you must also have an empty constructor
+ // - If it is set up as an inner class, it needs an explicit nullary constructor
+ // (note: I have seen an inner class otherwise fail, I have not tested it with the explicit constructor)
+
+ public static void register(Class c, Map messageClasses) {
+ try {
+ typecheck(c);
+
+ // Must register the class and not have duplicate
+ // This is not recursive because only the top level message class
+ // needs to be determined from the string - others are top-down.
+ String messageString = getMessageType(c);
+ Class existingClass = messageClasses.get(messageString);
+ if (existingClass != null && !existingClass.equals(c))
+ throw new MessageException("Message String \'" + messageString +
+ "\' is assigned to two different classes (" +
+ c.getName() + " and " + existingClass.getName() + ")");
+ messageClasses.put(messageString, c);
+ }
+ catch (MessageException ex) {
+ // should be changed to be a hooked method to give library user control
+ System.out.println(ex.getMessage());
+ }
+ }
+
+ public static String getMessageType(Class c) {
+ return ((MessageType) c.getAnnotation(MessageType.class)).string();
+ }
+
+ // this has never been used or tested but kind of belongs here
+ // commented out because it uses ReflectiveOperationException which is not available on Android
+ /*
+ public static Message newInstance(String className) {
+ try {
+ Class messageClass = Class.forName(className);
+ if (Message.class.isAssignableFrom(messageClass))
+ return (Message) messageClass.newInstance();
+ else throw new ClassCastException();
+ }
+ catch (ReflectiveOperationException ex) {
+ throw new RuntimeException("Unable to create message of class \'" + className + "\'.", ex);
+ }
+ }
+ */
+
+ // Could probably do more checking here, but not sure what right now
+ private static void typecheck(Class c) throws MessageException {
+
+ // Must inherit from Message
+ if (!Message.class.isAssignableFrom(c))
+ throw new MessageException("Class \'" + c.getName() +
+ "\' does not extend Message");
+
+ // Must have the MessageType annotation
+ if (getMessageType(c) == null)
+ throw new MessageException("Class \'" + c.getName() +
+ "\' is missing the MessageType annotation");
+
+ // All fields must also be valid Message classes
+ // Note that this also serves to force-load all the message classes
+ // so that they get registered
+ for (Field f : c.getFields()) {
+ Class fc = f.getType();
+ if (fc.isArray()) {
+ Class ac = fc.getComponentType();
+ if (!isPrimitive(ac))
+ typecheck(ac);
+ }
+ else if (!isPrimitive(fc))
+ typecheck(fc);
+ }
+ }
+
+ public void print() {
+ printMessage(this, "");
+ }
+
+ private static void printMessage(Object o, String indent) {
+ for (Field f : o.getClass().getFields()) {
+ Class c = f.getType();
+ Object fieldObject = getFieldObject(f, o);
+ if (fieldObject != null) {
+ if (isPrimitive(c))
+ System.out.println(indent + f.getName() + ": " + fieldObject);
+ else if (c.isArray()) {
+ System.out.println(indent + f.getName() + ": [");
+ printArray(fieldObject, indent + " ");
+ System.out.println(indent + "]");
+ }
+ else {
+ System.out.println(indent + f.getName() + ":");
+ printMessage(fieldObject, indent + " ");
+ }
+ }
+ }
+ }
+
+ private static void printArray(Object array, String indent) {
+ Class arrayClass = array.getClass().getComponentType();
+ for (int i = 0; i < Array.getLength(array); i++) {
+ Object elementObject = Array.get(array, i);
+ if (elementObject != null) {
+ if (isPrimitive(arrayClass))
+ System.out.println(indent + i + ": " + elementObject);
+ else if (arrayClass.isArray()) { // this is not actually allowed in ROS
+ System.out.println(indent + i + ": [");
+ printArray(elementObject, indent + " ");
+ System.out.println(indent + "]");
+ }
+ else {
+ System.out.println(indent + i + ":");
+ printMessage(elementObject, indent + " ");
+ }
+ }
+ }
+ // remember to print array indices
+ }
+
+ public static boolean isPrimitive(Class c) {
+ return (c.isPrimitive() ||
+ c.equals(String.class) ||
+ Number.class.isAssignableFrom(c) ||
+ c.equals(Boolean.class));
+ }
+
+
+ // Copied from com.jilk.ros.rosbridge.JSON
+ private static Object getFieldObject(Field f, Object o) {
+ Object fo = null;
+ try {
+ fo = f.get(o);
+ }
+ catch (IllegalAccessException ex) {
+ ex.printStackTrace();
+ }
+ return fo;
+ }
+
+ public void copyFrom(Message source) {
+ try {
+ if (source.getClass() != getClass())
+ throw new RuntimeException("Attempt to copy non-matching classes");
+ for (Field f : getClass().getFields()) {
+ Class fc = f.getType();
+ if (fc.isArray())
+ throw new RuntimeException("copyFrom - array types not implemented");
+ else if (!isPrimitive(fc))
+ ((Message) f.get(this)).copyFrom((Message) f.get(source));
+ else {
+ Object value = f.get(source);
+ f.set(this, value);
+ }
+ }
+ }
+ catch (IllegalAccessException ex) {
+ throw new RuntimeException ("copyFrom error", ex);
+ }
+ catch (ClassCastException ex) {
+ throw new RuntimeException ("copyFrom error", ex);
+ }
+ // ReflectiveOperationException is not available on Android (Java 1.6)
+ /*
+ catch (ReflectiveOperationException ex) {
+ throw new RuntimeException ("copyFrom error", ex);
+ }
+ */
+ }
+
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/MessageException.java b/ros/src/main/java/com/xbw/ros/message/MessageException.java
new file mode 100755
index 0000000..9cf74c2
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/MessageException.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+public class MessageException extends Exception {
+
+ public MessageException(String message) {
+ super(message);
+ }
+
+ public MessageException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
+
diff --git a/ros/src/main/java/com/xbw/ros/message/MessageType.java b/ros/src/main/java/com/xbw/ros/message/MessageType.java
new file mode 100755
index 0000000..80994e8
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/MessageType.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MessageType {
+ String string() default "";
+}
+
diff --git a/ros/src/main/java/com/xbw/ros/message/SemanticRequest.java b/ros/src/main/java/com/xbw/ros/message/SemanticRequest.java
new file mode 100755
index 0000000..cb30393
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/SemanticRequest.java
@@ -0,0 +1,13 @@
+package com.xbw.ros.message;
+
+/**
+ * Created by xbw on 19-1-15.
+ */
+@MessageType(string = "std_msgs/String")
+public class SemanticRequest extends Message {
+ public SemanticRequest(String args) {
+ jsonStr = args;
+ }
+
+ public String jsonStr;
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/SemanticResponse.java b/ros/src/main/java/com/xbw/ros/message/SemanticResponse.java
new file mode 100755
index 0000000..0e69065
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/SemanticResponse.java
@@ -0,0 +1,9 @@
+package com.xbw.ros.message;
+
+/**
+ * Created by xbw on 19-1-15.
+ */
+@MessageType(string = "std_msgs/String")
+public class SemanticResponse extends Message {
+ public String result;
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/StdMsg.java b/ros/src/main/java/com/xbw/ros/message/StdMsg.java
new file mode 100755
index 0000000..a69bc80
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/StdMsg.java
@@ -0,0 +1,9 @@
+package com.xbw.ros.message;
+
+/**
+ * Created by xbw on 19-1-15.
+ */
+@MessageType(string = "std_msgs/String")
+public class StdMsg extends Message {
+ public String data;
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/Time.java b/ros/src/main/java/com/xbw/ros/message/Time.java
new file mode 100755
index 0000000..6d225a3
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/Time.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+@MessageType(string = "std_msgs/Time")
+public class Time extends TimePrimitive {
+}
diff --git a/ros/src/main/java/com/xbw/ros/message/TimePrimitive.java b/ros/src/main/java/com/xbw/ros/message/TimePrimitive.java
new file mode 100755
index 0000000..1e103c7
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/message/TimePrimitive.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.message;
+
+@MessageType(string = "time")
+public class TimePrimitive extends Message {
+ public int secs; // when requesting this format from ROSbridge, it uses 'sec' (no 's')
+ public int nsecs; // when requesting this format from ROSbridge, it uses 'nsec'
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosapi/message/Empty.java b/ros/src/main/java/com/xbw/ros/rosapi/message/Empty.java
new file mode 100755
index 0000000..872f4cc
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosapi/message/Empty.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosapi.message;
+
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "std_msgs/Empty")
+public class Empty extends Message {
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosapi/message/GetTime.java b/ros/src/main/java/com/xbw/ros/rosapi/message/GetTime.java
new file mode 100755
index 0000000..cd7ae5e
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosapi/message/GetTime.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosapi.message;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+import com.xbw.ros.message.TimePrimitive;
+
+
+@MessageType(string = "rosapi/GetTimeResponse")
+public class GetTime extends Message {
+ public TimePrimitive time;
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosapi/message/MessageDetails.java b/ros/src/main/java/com/xbw/ros/rosapi/message/MessageDetails.java
new file mode 100755
index 0000000..f9db06a
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosapi/message/MessageDetails.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosapi.message;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "rosapi/MessageDetails")
+public class MessageDetails extends Message {
+ public TypeDef[] typedefs;
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosapi/message/Nodes.java b/ros/src/main/java/com/xbw/ros/rosapi/message/Nodes.java
new file mode 100755
index 0000000..cfdace0
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosapi/message/Nodes.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosapi.message;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "rosapi/Nodes")
+public class Nodes extends Message {
+ public String[] nodes;
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosapi/message/Service.java b/ros/src/main/java/com/xbw/ros/rosapi/message/Service.java
new file mode 100755
index 0000000..bc0694e
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosapi/message/Service.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosapi.message;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "rosapi/Service")
+public class Service extends Message {
+ public String service;
+
+ public Service() {}
+
+ public Service(String service) {
+ this.service = service;
+ }
+}
\ No newline at end of file
diff --git a/ros/src/main/java/com/xbw/ros/rosapi/message/Services.java b/ros/src/main/java/com/xbw/ros/rosapi/message/Services.java
new file mode 100755
index 0000000..36db261
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosapi/message/Services.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosapi.message;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "rosapi/Services")
+public class Services extends Message {
+ public String[] services;
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosapi/message/Topic.java b/ros/src/main/java/com/xbw/ros/rosapi/message/Topic.java
new file mode 100755
index 0000000..a4307c8
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosapi/message/Topic.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosapi.message;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "rosapi/Topic")
+public class Topic extends Message {
+ public String topic;
+
+ public Topic() {}
+
+ public Topic(String topic) {
+ this.topic = topic;
+ }
+}
\ No newline at end of file
diff --git a/ros/src/main/java/com/xbw/ros/rosapi/message/Topics.java b/ros/src/main/java/com/xbw/ros/rosapi/message/Topics.java
new file mode 100755
index 0000000..e2fe5b9
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosapi/message/Topics.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosapi.message;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "rosapi/Topics")
+public class Topics extends Message {
+ public String[] topics;
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosapi/message/Type.java b/ros/src/main/java/com/xbw/ros/rosapi/message/Type.java
new file mode 100755
index 0000000..501db19
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosapi/message/Type.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosapi.message;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "rosapi/Type")
+public class Type extends Message {
+ public String type;
+
+ public Type() {}
+
+ public Type(String type) {
+ this.type = type;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosapi/message/TypeDef.java b/ros/src/main/java/com/xbw/ros/rosapi/message/TypeDef.java
new file mode 100755
index 0000000..9090f89
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosapi/message/TypeDef.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosapi.message;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "rosapi/TypeDef")
+public class TypeDef extends Message {
+ public String type;
+ public String[] fieldnames;
+ public String[] fieldtypes;
+ public int[] fieldarraylen;
+ public String[] examples;
+
+ public static boolean match(String type, Class c) {
+ boolean result = false;
+ if (
+ (type.equals("bool") && ((boolean.class.equals(c)) || (Boolean.class.equals(c)))) ||
+ (type.equals("int8") && ((byte.class.equals(c)) || (Byte.class.equals(c)))) ||
+ (type.equals("byte") && ((byte.class.equals(c)) || (Byte.class.equals(c)))) || // deprecated
+ (type.equals("uint8") && ((short.class.equals(c)) || (Short.class.equals(c)))) ||
+ (type.equals("char") && ((short.class.equals(c)) || (Short.class.equals(c)))) || // deprecated
+ (type.equals("int16") && ((short.class.equals(c)) || (Short.class.equals(c)))) ||
+ (type.equals("uint16") && ((int.class.equals(c)) || (Integer.class.equals(c)))) ||
+ (type.equals("int32") && ((int.class.equals(c)) || (Integer.class.equals(c)))) ||
+ (type.equals("uint32") && ((long.class.equals(c)) || (Long.class.equals(c)))) ||
+ (type.equals("int64") && ((long.class.equals(c)) || (Long.class.equals(c)))) ||
+ (type.equals("float32") && ((float.class.equals(c)) || (Float.class.equals(c)))) ||
+ (type.equals("float64") && ((double.class.equals(c)) || (Double.class.equals(c)))) ||
+ (type.equals("uint64") && (java.math.BigInteger.class.equals(c))) ||
+ (type.equals("string") && (String.class.equals(c)))
+ )
+ result = true;
+
+ return result;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/FullMessageHandler.java b/ros/src/main/java/com/xbw/ros/rosbridge/FullMessageHandler.java
new file mode 100755
index 0000000..49668be
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/FullMessageHandler.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge;
+
+import com.xbw.ros.message.Message;
+
+public interface FullMessageHandler {
+ public void onMessage(String id, T message);
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/ROSBridgeClient.java b/ros/src/main/java/com/xbw/ros/rosbridge/ROSBridgeClient.java
new file mode 100755
index 0000000..d5fd06c
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/ROSBridgeClient.java
@@ -0,0 +1,260 @@
+/**
+ * Copyright (c) 2014 xbw Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge;
+
+import com.xbw.ros.ROSClient;
+import com.xbw.ros.Service;
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+import com.xbw.ros.rosapi.message.Empty;
+import com.xbw.ros.rosapi.message.MessageDetails;
+import com.xbw.ros.rosapi.message.Nodes;
+import com.xbw.ros.rosapi.message.Services;
+import com.xbw.ros.rosapi.message.Topic;
+import com.xbw.ros.rosapi.message.Topics;
+import com.xbw.ros.rosapi.message.Type;
+import com.xbw.ros.rosapi.message.TypeDef;
+import com.xbw.ros.rosbridge.implementation.ROSBridgeWebSocketClient;
+import com.xbw.ros.rosbridge.operation.Operation;
+
+import java.lang.reflect.Field;
+
+public class ROSBridgeClient extends ROSClient {
+ String uriString;
+ ROSBridgeWebSocketClient client;
+
+ public ROSBridgeClient(String uriString) {
+ this.uriString = uriString;
+ }
+
+ @Override
+ public boolean connect() {
+ return connect(null);
+ }
+
+ @Override
+ public boolean connect(ROSClient.ConnectionStatusListener listener) {
+ boolean result = false;
+ client = ROSBridgeWebSocketClient.create(uriString);
+ if (client != null) {
+ client.setListener(listener);
+ try {
+ result = client.connectBlocking();
+ }
+ catch (InterruptedException ex) {}
+ }
+ return result;
+ }
+
+ @Override
+ public void disconnect() {
+ try {
+ client.closeBlocking();
+ }
+ catch (InterruptedException ex) {}
+ }
+
+ @Override
+ public void send(Operation operation) {
+ client.send(operation);
+ }
+
+ @Override
+ public void send(String json) {
+ client.send(json);
+ }
+
+ @Override
+ public void register(Class extends Operation> c,
+ String s,
+ Class extends Message> m,
+ FullMessageHandler h) {
+ client.register(c, s, m, h);
+ }
+
+ @Override
+ public void unregister(Class extends Operation> c, String s) {
+ client.unregister(c, s);
+ }
+
+ @Override
+ public void setDebug(boolean debug) {
+ client.setDebug(debug);
+ }
+
+ @Override
+ public String[] getNodes() throws InterruptedException {
+ Service nodeService =
+ new Service("/rosapi/nodes", Empty.class, Nodes.class, this);
+ return nodeService.callBlocking(new Empty()).nodes;
+ }
+
+ @Override
+ public String[] getTopics() throws InterruptedException {
+ Service topicsService =
+ new Service("/rosapi/topics", Empty.class, Topics.class, this);
+ return topicsService.callBlocking(new Empty()).topics;
+ }
+
+ @Override
+ public String[] getServices() throws InterruptedException {
+ Service servicesService =
+ new Service("/rosapi/services", Empty.class, Services.class, this);
+ return servicesService.callBlocking(new Empty()).services;
+ }
+
+ @Override
+ public TypeDef getTopicMessageDetails(String topic) throws InterruptedException {
+ return getTypeDetails(getTopicType(topic));
+ }
+
+ @Override
+ public TypeDef[] getTopicMessageList(String topic) throws InterruptedException {
+ return getTypeList(getTopicType(topic));
+ }
+
+ @Override
+ public TypeDef getServiceRequestDetails(String service) throws InterruptedException {
+ return getTypeDetails(getServiceType(service), "Request", "/rosapi/service_request_details");
+ }
+
+ @Override
+ public TypeDef[] getServiceRequestList(String service) throws InterruptedException {
+ return getTypeList(getServiceType(service), "Request", "/rosapi/service_request_details");
+ }
+
+ @Override
+ public TypeDef getServiceResponseDetails(String service) throws InterruptedException {
+ return getTypeDetails(getServiceType(service), "Response", "/rosapi/service_response_details");
+ }
+
+ @Override
+ public TypeDef[] getServiceResponseList(String service) throws InterruptedException {
+ return getTypeList(getServiceType(service), "Response", "/rosapi/service_response_details");
+ }
+
+ @Override
+ public TypeDef[] getTypeList(String type) throws InterruptedException {
+ return getTypeList(type, "", "/rosapi/message_details");
+ }
+
+ @Override
+ public TypeDef getTypeDetails(String type) throws InterruptedException {
+ return getTypeDetails(type, "", "/rosapi/message_details");
+ }
+
+ private TypeDef[] getTypeList(String type, String suffix, String serviceName) throws InterruptedException {
+ Service messageDetailsService =
+ new Service(serviceName,
+ Type.class, MessageDetails.class, this);
+ return messageDetailsService.callBlocking(new Type(type)).typedefs;
+ }
+
+ private TypeDef getTypeDetails(String type, String suffix, String serviceName) throws InterruptedException {
+ Service messageDetailsService =
+ new Service(serviceName,
+ Type.class, MessageDetails.class, this);
+ return findType(type + suffix, messageDetailsService.callBlocking(new Type(type)).typedefs);
+ }
+
+ private String getTopicType(String topic) throws InterruptedException {
+ Service topicTypeService =
+ new Service("/rosapi/topic_type",
+ Topic.class, Type.class, this);
+ return topicTypeService.callBlocking(new Topic(topic)).type;
+ }
+
+ private String getServiceType(String service) throws InterruptedException {
+ Service serviceTypeService =
+ new Service("/rosapi/service_type",
+ com.xbw.ros.rosapi.message.Service.class, Type.class, this);
+ return serviceTypeService.callBlocking(new com.xbw.ros.rosapi.message.Service(service)).type;
+ }
+
+ private TypeDef findType(String type, TypeDef[] types) {
+ TypeDef result = null;
+ for (TypeDef t : types) {
+ if (t.type.equals(type)) {
+ result = t;
+ break;
+ }
+ }
+ //System.out.println("ROSBridgeClient.findType: ");
+ //result.print();
+ return result;
+ }
+
+ @Override
+ public void typeMatch(TypeDef t, Class extends Message> c) throws InterruptedException {
+ if (c == null)
+ throw new RuntimeException("No registered message type found for: " + t.type);
+ Field[] fields = c.getFields();
+ for (int i = 0; i < t.fieldnames.length; i++) {
+
+ // Field names
+ String classFieldName = fields[i].getName();
+ String typeFieldName = t.fieldnames[i];
+ if (!classFieldName.equals(typeFieldName))
+ typeMatchError(t, c, "field name", typeFieldName, classFieldName);
+
+ // Array type of field
+ boolean typeIsArray = (t.fieldarraylen[i] >= 0);
+ boolean fieldIsArray = fields[i].getType().isArray();
+ if (typeIsArray != fieldIsArray)
+ typeMatchError(t, c, "array mismatch", typeFieldName, classFieldName);
+
+ // Get base type of field
+ Class fieldClass = fields[i].getType();
+ if (fieldIsArray)
+ fieldClass = fields[i].getType().getComponentType();
+ String type = t.fieldtypes[i];
+
+ // Field type for primitivesclient
+ if (Message.isPrimitive(fieldClass)) {
+ if (!TypeDef.match(type, fieldClass))
+ typeMatchError(t, c, "type mismatch", type, fieldClass.getName());
+ }
+
+ // Field type for non-primitive classes, and recurse
+ else {
+ if (!Message.class.isAssignableFrom(fieldClass))
+ throw new RuntimeException("Member " + classFieldName +
+ " of class " + fieldClass.getName() + " does not extend Message.");
+ String fieldClassString = ((MessageType) fieldClass.getAnnotation(MessageType.class)).string();
+ if (!type.equals(fieldClassString))
+ typeMatchError(t, c, "message type mismatch", type, fieldClassString);
+ typeMatch(getTypeDetails(type), fieldClass);
+ }
+ }
+ }
+
+ private void typeMatchError(TypeDef t, Class extends Message> c,
+ String error, String tString, String cString) {
+ throw new RuntimeException("Type match error between " +
+ t.type + " and " + c.getName() + ": " +
+ error + ": \'" + tString + "\' does not match \'" + cString + "\'.");
+ }
+
+ @Override
+ public Object getUnderlyingClient() {
+ return client;
+ }
+
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/implementation/Base64.java b/ros/src/main/java/com/xbw/ros/rosbridge/implementation/Base64.java
new file mode 100755
index 0000000..f097dcd
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/implementation/Base64.java
@@ -0,0 +1,575 @@
+package com.xbw.ros.rosbridge.implementation;
+
+import java.util.Arrays;
+
+/** A very fast and memory efficient class to encode and decode to and from BASE64 in full accordance
+ * with RFC 2045.
+ * On Windows XP sp1 with 1.4.2_04 and later ;), this encoder and decoder is about 10 times faster
+ * on small arrays (10 - 1000 bytes) and 2-3 times as fast on larger arrays (10000 - 1000000 bytes)
+ * compared to sun.misc.Encoder()/Decoder().
+ *
+ * On byte arrays the encoder is about 20% faster than Jakarta Commons Base64 Codec for encode and
+ * about 50% faster for decoding large arrays. This implementation is about twice as fast on very small
+ * arrays (< 30 bytes). If source/destination is a String this
+ * version is about three times as fast due to the fact that the Commons Codec result has to be recoded
+ * to a String from byte[], which is very expensive.
+ *
+ * This encode/decode algorithm doesn't create any temporary arrays as many other codecs do, it only
+ * allocates the resulting array. This produces less garbage and it is possible to handle arrays twice
+ * as large as algorithms that create a temporary array. (E.g. Jakarta Commons Codec). It is unknown
+ * whether Sun's sun.misc.Encoder()/Decoder() produce temporary arrays but since performance
+ * is quite low it probably does.
+ *
+ * The encoder produces the same output as the Sun one except that the Sun's encoder appends
+ * a trailing line separator if the last character isn't a pad. Unclear why but it only adds to the
+ * length and is probably a side effect. Both are in conformance with RFC 2045 though.
+ * Commons codec seem to always att a trailing line separator.
+ *
+ * Note!
+ * The encode/decode method pairs (types) come in three versions with the exact same algorithm and
+ * thus a lot of code redundancy. This is to not create any temporary arrays for transcoding to/from different
+ * format types. The methods not used can simply be commented out.
+ *
+ * There is also a "fast" version of all decode methods that works the same way as the normal ones, but
+ * har a few demands on the decoded input. Normally though, these fast verions should be used if the source if
+ * the input is known and it hasn't bee tampered with.
+ *
+ * If you find the code useful or you find a bug, please send me a note at base64 @ miginfocom . com.
+ *
+ * Licence (BSD):
+ * ==============
+ *
+ * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * @version 2.2
+ * @author Mikael Grev
+ * Date: 2004-aug-02
+ * Time: 11:31:11
+ */
+
+public class Base64
+{
+ private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
+ private static final int[] IA = new int[256];
+ static {
+ Arrays.fill(IA, -1);
+ for (int i = 0, iS = CA.length; i < iS; i++)
+ IA[CA[i]] = i;
+ IA['='] = 0;
+ }
+
+ // ****************************************************************************************
+ // * char[] version
+ // ****************************************************************************************
+
+ /** Encodes a raw byte array into a BASE64 char[] representation i accordance with RFC 2045.
+ * @param sArr The bytes to convert. If null or length 0 an empty array will be returned.
+ * @param lineSep Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
+ * little faster.
+ * @return A BASE64 encoded array. Never null.
+ */
+ public final static char[] encodeToChar(byte[] sArr, boolean lineSep)
+ {
+ // Check special case
+ int sLen = sArr != null ? sArr.length : 0;
+ if (sLen == 0)
+ return new char[0];
+
+ int eLen = (sLen / 3) * 3; // Length of even 24-bits.
+ int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
+ int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
+ char[] dArr = new char[dLen];
+
+ // Encode even 24-bits
+ for (int s = 0, d = 0, cc = 0; s < eLen;) {
+ // Copy next three bytes into lower 24 bits of int, paying attension to sign.
+ int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
+
+ // Encode the int into four chars
+ dArr[d++] = CA[(i >>> 18) & 0x3f];
+ dArr[d++] = CA[(i >>> 12) & 0x3f];
+ dArr[d++] = CA[(i >>> 6) & 0x3f];
+ dArr[d++] = CA[i & 0x3f];
+
+ // Add optional line separator
+ if (lineSep && ++cc == 19 && d < dLen - 2) {
+ dArr[d++] = '\r';
+ dArr[d++] = '\n';
+ cc = 0;
+ }
+ }
+
+ // Pad and encode last bits if source isn't even 24 bits.
+ int left = sLen - eLen; // 0 - 2.
+ if (left > 0) {
+ // Prepare the int
+ int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
+
+ // Set last four chars
+ dArr[dLen - 4] = CA[i >> 12];
+ dArr[dLen - 3] = CA[(i >>> 6) & 0x3f];
+ dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '=';
+ dArr[dLen - 1] = '=';
+ }
+ return dArr;
+ }
+
+ /** Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with
+ * and without line separators.
+ * @param sArr The source array. null or length 0 will return an empty array.
+ * @return The decoded array of bytes. May be of length 0. Will be null if the legal characters
+ * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
+ */
+ public final static byte[] decode(char[] sArr)
+ {
+ // Check special case
+ int sLen = sArr != null ? sArr.length : 0;
+ if (sLen == 0)
+ return new byte[0];
+
+ // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
+ // so we don't have to reallocate & copy it later.
+ int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
+ for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
+ if (IA[sArr[i]] < 0)
+ sepCnt++;
+
+ // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
+ if ((sLen - sepCnt) % 4 != 0)
+ return null;
+
+ int pad = 0;
+ for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;)
+ if (sArr[i] == '=')
+ pad++;
+
+ int len = ((sLen - sepCnt) * 6 >> 3) - pad;
+
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ for (int s = 0, d = 0; d < len;) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = 0;
+ for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
+ int c = IA[sArr[s++]];
+ if (c >= 0)
+ i |= c << (18 - j * 6);
+ else
+ j--;
+ }
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ if (d < len) {
+ dArr[d++]= (byte) (i >> 8);
+ if (d < len)
+ dArr[d++] = (byte) i;
+ }
+ }
+ return dArr;
+ }
+
+ /** Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as
+ * fast as {@link #decode(char[])}. The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045
+ * + The array must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.
+ * @param sArr The source array. Length 0 will return an empty array. null will throw an exception.
+ * @return The decoded array of bytes. May be of length 0.
+ */
+ public final static byte[] decodeFast(char[] sArr)
+ {
+ // Check special case
+ int sLen = sArr.length;
+ if (sLen == 0)
+ return new byte[0];
+
+ int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
+
+ // Trim illegal chars from start
+ while (sIx < eIx && IA[sArr[sIx]] < 0)
+ sIx++;
+
+ // Trim illegal chars from end
+ while (eIx > 0 && IA[sArr[eIx]] < 0)
+ eIx--;
+
+ // get the padding count (=) (0, 1 or 2)
+ int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
+ int cCnt = eIx - sIx + 1; // Content count including possible separators
+ int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
+
+ int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ // Decode all but the last 0 - 2 bytes.
+ int d = 0;
+ for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ dArr[d++] = (byte) (i >> 8);
+ dArr[d++] = (byte) i;
+
+ // If line separator, jump over it.
+ if (sepCnt > 0 && ++cc == 19) {
+ sIx += 2;
+ cc = 0;
+ }
+ }
+
+ if (d < len) {
+ // Decode last 1-3 bytes (incl '=') into 1-3 bytes
+ int i = 0;
+ for (int j = 0; sIx <= eIx - pad; j++)
+ i |= IA[sArr[sIx++]] << (18 - j * 6);
+
+ for (int r = 16; d < len; r -= 8)
+ dArr[d++] = (byte) (i >> r);
+ }
+
+ return dArr;
+ }
+
+ // ****************************************************************************************
+ // * byte[] version
+ // ****************************************************************************************
+
+ /** Encodes a raw byte array into a BASE64 byte[] representation i accordance with RFC 2045.
+ * @param sArr The bytes to convert. If null or length 0 an empty array will be returned.
+ * @param lineSep Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
+ * little faster.
+ * @return A BASE64 encoded array. Never null.
+ */
+ public final static byte[] encodeToByte(byte[] sArr, boolean lineSep)
+ {
+ // Check special case
+ int sLen = sArr != null ? sArr.length : 0;
+ if (sLen == 0)
+ return new byte[0];
+
+ int eLen = (sLen / 3) * 3; // Length of even 24-bits.
+ int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
+ int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
+ byte[] dArr = new byte[dLen];
+
+ // Encode even 24-bits
+ for (int s = 0, d = 0, cc = 0; s < eLen;) {
+ // Copy next three bytes into lower 24 bits of int, paying attension to sign.
+ int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
+
+ // Encode the int into four chars
+ dArr[d++] = (byte) CA[(i >>> 18) & 0x3f];
+ dArr[d++] = (byte) CA[(i >>> 12) & 0x3f];
+ dArr[d++] = (byte) CA[(i >>> 6) & 0x3f];
+ dArr[d++] = (byte) CA[i & 0x3f];
+
+ // Add optional line separator
+ if (lineSep && ++cc == 19 && d < dLen - 2) {
+ dArr[d++] = '\r';
+ dArr[d++] = '\n';
+ cc = 0;
+ }
+ }
+
+ // Pad and encode last bits if source isn't an even 24 bits.
+ int left = sLen - eLen; // 0 - 2.
+ if (left > 0) {
+ // Prepare the int
+ int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
+
+ // Set last four chars
+ dArr[dLen - 4] = (byte) CA[i >> 12];
+ dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f];
+ dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
+ dArr[dLen - 1] = '=';
+ }
+ return dArr;
+ }
+
+ /** Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
+ * and without line separators.
+ * @param sArr The source array. Length 0 will return an empty array. null will throw an exception.
+ * @return The decoded array of bytes. May be of length 0. Will be null if the legal characters
+ * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
+ */
+ public final static byte[] decode(byte[] sArr)
+ {
+ // Check special case
+ int sLen = sArr.length;
+
+ // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
+ // so we don't have to reallocate & copy it later.
+ int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
+ for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
+ if (IA[sArr[i] & 0xff] < 0)
+ sepCnt++;
+
+ // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
+ if ((sLen - sepCnt) % 4 != 0)
+ return null;
+
+ int pad = 0;
+ for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0;)
+ if (sArr[i] == '=')
+ pad++;
+
+ int len = ((sLen - sepCnt) * 6 >> 3) - pad;
+
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ for (int s = 0, d = 0; d < len;) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = 0;
+ for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
+ int c = IA[sArr[s++] & 0xff];
+ if (c >= 0)
+ i |= c << (18 - j * 6);
+ else
+ j--;
+ }
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ if (d < len) {
+ dArr[d++]= (byte) (i >> 8);
+ if (d < len)
+ dArr[d++] = (byte) i;
+ }
+ }
+
+ return dArr;
+ }
+
+
+ /** Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
+ * fast as {@link #decode(byte[])}. The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045
+ * + The array must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.
+ * @param sArr The source array. Length 0 will return an empty array. null will throw an exception.
+ * @return The decoded array of bytes. May be of length 0.
+ */
+ public final static byte[] decodeFast(byte[] sArr)
+ {
+ // Check special case
+ int sLen = sArr.length;
+ if (sLen == 0)
+ return new byte[0];
+
+ int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
+
+ // Trim illegal chars from start
+ while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0)
+ sIx++;
+
+ // Trim illegal chars from end
+ while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0)
+ eIx--;
+
+ // get the padding count (=) (0, 1 or 2)
+ int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
+ int cCnt = eIx - sIx + 1; // Content count including possible separators
+ int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
+
+ int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ // Decode all but the last 0 - 2 bytes.
+ int d = 0;
+ for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ dArr[d++] = (byte) (i >> 8);
+ dArr[d++] = (byte) i;
+
+ // If line separator, jump over it.
+ if (sepCnt > 0 && ++cc == 19) {
+ sIx += 2;
+ cc = 0;
+ }
+ }
+
+ if (d < len) {
+ // Decode last 1-3 bytes (incl '=') into 1-3 bytes
+ int i = 0;
+ for (int j = 0; sIx <= eIx - pad; j++)
+ i |= IA[sArr[sIx++]] << (18 - j * 6);
+
+ for (int r = 16; d < len; r -= 8)
+ dArr[d++] = (byte) (i >> r);
+ }
+
+ return dArr;
+ }
+
+ // ****************************************************************************************
+ // * String version
+ // ****************************************************************************************
+
+ /** Encodes a raw byte array into a BASE64 String representation i accordance with RFC 2045.
+ * @param sArr The bytes to convert. If null or length 0 an empty array will be returned.
+ * @param lineSep Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
+ * little faster.
+ * @return A BASE64 encoded array. Never null.
+ */
+ public final static String encodeToString(byte[] sArr, boolean lineSep)
+ {
+ // Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower.
+ return new String(encodeToChar(sArr, lineSep));
+ }
+
+ /** Decodes a BASE64 encoded String. All illegal characters will be ignored and can handle both strings with
+ * and without line separators.
+ * Note! It can be up to about 2x the speed to call decode(str.toCharArray()) instead. That
+ * will create a temporary array though. This version will use str.charAt(i) to iterate the string.
+ * @param str The source string. null or length 0 will return an empty array.
+ * @return The decoded array of bytes. May be of length 0. Will be null if the legal characters
+ * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
+ */
+ public final static byte[] decode(String str)
+ {
+ // Check special case
+ int sLen = str != null ? str.length() : 0;
+ if (sLen == 0)
+ return new byte[0];
+
+ // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
+ // so we don't have to reallocate & copy it later.
+ int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
+ for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
+ if (IA[str.charAt(i)] < 0)
+ sepCnt++;
+
+ // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
+ if ((sLen - sepCnt) % 4 != 0)
+ return null;
+
+ // Count '=' at end
+ int pad = 0;
+ for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;)
+ if (str.charAt(i) == '=')
+ pad++;
+
+ int len = ((sLen - sepCnt) * 6 >> 3) - pad;
+
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ for (int s = 0, d = 0; d < len;) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = 0;
+ for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
+ int c = IA[str.charAt(s++)];
+ if (c >= 0)
+ i |= c << (18 - j * 6);
+ else
+ j--;
+ }
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ if (d < len) {
+ dArr[d++]= (byte) (i >> 8);
+ if (d < len)
+ dArr[d++] = (byte) i;
+ }
+ }
+ return dArr;
+ }
+
+ /** Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as
+ * fast as {@link #decode(String)}. The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045
+ * + The array must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.
+ * @param s The source string. Length 0 will return an empty array. null will throw an exception.
+ * @return The decoded array of bytes. May be of length 0.
+ */
+ public final static byte[] decodeFast(String s)
+ {
+ // Check special case
+ int sLen = s.length();
+ if (sLen == 0)
+ return new byte[0];
+
+ int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
+
+ // Trim illegal chars from start
+ while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0)
+ sIx++;
+
+ // Trim illegal chars from end
+ while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0)
+ eIx--;
+
+ // get the padding count (=) (0, 1 or 2)
+ int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end.
+ int cCnt = eIx - sIx + 1; // Content count including possible separators
+ int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0;
+
+ int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ // Decode all but the last 0 - 2 bytes.
+ int d = 0;
+ for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)];
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ dArr[d++] = (byte) (i >> 8);
+ dArr[d++] = (byte) i;
+
+ // If line separator, jump over it.
+ if (sepCnt > 0 && ++cc == 19) {
+ sIx += 2;
+ cc = 0;
+ }
+ }
+
+ if (d < len) {
+ // Decode last 1-3 bytes (incl '=') into 1-3 bytes
+ int i = 0;
+ for (int j = 0; sIx <= eIx - pad; j++)
+ i |= IA[s.charAt(sIx++)] << (18 - j * 6);
+
+ for (int r = 16; d < len; r -= 8)
+ dArr[d++] = (byte) (i >> r);
+ }
+
+ return dArr;
+ }
+}
\ No newline at end of file
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/implementation/JSON.java b/ros/src/main/java/com/xbw/ros/rosbridge/implementation/JSON.java
new file mode 100755
index 0000000..4685179
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/implementation/JSON.java
@@ -0,0 +1,335 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.implementation;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.rosbridge.indication.Indication;
+import com.xbw.ros.rosbridge.operation.Wrapper;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+
+import java.io.StringReader;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+
+
+// The slightly crazy abstractions here are designed to isolate knowledge of
+// the JSON library and data types from the Operation details of rosbridge.
+// Why is this important? A few reasons I can see. First, we might want
+// to change JSON libraries and this encapsulates all use of JSON-simple.
+// Second, as much as possible I would like the semantics of the rosbridge
+// protocol to be encapsulated in the Operation and its subclasses rather
+// than in a module that is essentially about serialization.
+//
+// Unfortunately the hierarchical Message abstraction is a bit broken
+// at the top level. Beginning at the actual operation (e.g., Publish), the
+// types of the fields are determined either by the fields themselves or by
+// an indicator. However, the type of the operation itself is not determined
+// this way, because the indicator is in the object itself, which means it
+// would have to be created before its type is known. Rather than build in
+// exceptions, I elected to create a "Wrapper" operation type that simply
+// wraps the concrete operation and copies its "op" field.
+//
+
+public class JSON {
+
+ /**
+ * Translates a Message recursively into JSON. Normally the Message is also an
+ * Operation, but it does not have to be. The caller constructs a complete
+ * message using @Operation and @Message types. This includes situations
+ * where one or more fields are marked to be turned into arrays, using @AsArray.
+ * @param m the @Message object to be recursively translated.
+ * @return the complete JSON string.
+ */
+ public static String toJSON(Message m) {
+ JSONObject jo = convertObjectToJSONObject(m); // Object to JSON-Simple
+ return jo.toJSONString(); // JSON-Simple to string
+ }
+
+ /**
+ * Translates JSON into a hierarchical Operation/Message structure.
+ * This includes handling fields that are @Indicated and @AsArray. If the
+ * @Class parameter is a @Wrapper, this is a special case whereby the
+ * object is wrapped to create a consistent hierarchy.
+ * @param json the source JSON string
+ * @param c the top level class of the JSON. Normally @Wrapper
+ * @param r the @Registry containing topic registrations
+ * @return the fully instantiated message hierarchy represented
+ * by the JSON string.
+ */
+ public static Message toMessage(String json, Class c, Registry r) {
+ JSONObject joUnwrapped = convertStringToJSONObject(json); // String to JSON-Simple
+ JSONObject jo = joUnwrapped;
+ if (Wrapper.class.isAssignableFrom(c))
+ jo = wrap(joUnwrapped, c); // wrap: a hack to make the hierarchy homogeneous
+ return convertJSONObjectToMessage(jo, c, r); // JSON-Simple to Message
+ }
+
+ // *** Create JSON from Messages *** //
+
+ // Translate the object into a JSON-Simple object, field-by-field,
+ // recursively via convertElementToJSON.
+ // except for the case where AsArray is indicated
+ private static JSONObject convertObjectToJSONObject(Object o) {
+ JSONObject result = new JSONObject();
+ for (Field f : o.getClass().getFields()) {
+ Object fieldObject = getFieldObject(f, o);
+ if (fieldObject != null) {
+ Object resultObject;
+ if (Indication.isBase64Encoded(f))
+ resultObject = convertByteArrayToBase64JSONString(fieldObject);
+ else if (Indication.asArray(f))
+ resultObject = convertObjectToJSONArray(fieldObject);
+ else resultObject = convertElementToJSON(fieldObject);
+ result.put(f.getName(), resultObject);
+ }
+ }
+ return result;
+ }
+
+ // Convert an array type to a JSON-Simple array, element-by-element,
+ // recursively via convertElementToJSON.
+ private static JSONArray convertArrayToJSONArray(Object array) {
+ JSONArray result = new JSONArray();
+ for (int i = 0; i < Array.getLength(array); i++) {
+ Object elementObject = Array.get(array, i);
+ if (elementObject != null) {
+ Object resultObject = convertElementToJSON(elementObject);
+ result.add(resultObject);
+ }
+ }
+ return result;
+ }
+
+ // For AsArray objects, convert the object to a JSON-Simple array
+ // NOTE: This relies on later versions of the JDK providing
+ // the fields in order.
+ private static JSONArray convertObjectToJSONArray(Object o) {
+ JSONArray result = new JSONArray();
+ for (Field f : o.getClass().getFields()) {
+ Object fieldObject = getFieldObject(f, o);
+ if (fieldObject != null) {
+ Object resultObject = convertElementToJSON(fieldObject);
+ result.add(resultObject);
+ }
+ }
+ return result;
+ }
+
+ // Convert the individual field or array element items recursively
+ private static Object convertElementToJSON(Object elementObject) {
+ Class elementClass = elementObject.getClass();
+ Object resultObject;
+ if (Message.isPrimitive(elementClass))
+ resultObject = elementObject;
+ else if (elementClass.isArray())
+ resultObject = convertArrayToJSONArray(elementObject);
+ else
+ resultObject = convertObjectToJSONObject(elementObject);
+ return resultObject;
+ }
+
+ // Special case for Base 64-encoded fields
+ private static Object convertByteArrayToBase64JSONString(Object fieldObject) {
+ return Base64.encodeToString((byte[]) fieldObject, false);
+ }
+
+ // This is just to buffer the code from the exception. Better error
+ // handling needed here.
+ private static Object getFieldObject(Field f, Object o) {
+ Object fo = null;
+ try {
+ fo = f.get(o);
+ }
+ catch (IllegalAccessException ex) {
+ ex.printStackTrace();
+ }
+ return fo;
+ }
+
+ // *** Create Messages from JSON *** //
+
+ // Use the JSON-simple parser to create the JSON-Simple object
+ private static JSONObject convertStringToJSONObject(String json) {
+ JSONObject result = null;
+ StringReader r = new StringReader(json);
+ JSONParser jp = new JSONParser();
+ try {
+ result = (JSONObject) jp.parse(r);
+ }
+ catch (Throwable t) {
+ System.out.println(t.getMessage());
+ }
+ r.close();
+ return result;
+ }
+
+ // A bit of a hack to create a consistent hierarchy with jsonbridge operations
+ // At least it does not depend on any specific field names, it just copies the
+ // Indicator and Indicated fields.
+ private static JSONObject wrap(JSONObject jo, Class c) {
+ JSONObject result = new JSONObject();
+ String indicatorName = Indication.getIndicatorName(c);
+ String indicatedName = Indication.getIndicatedName(c);
+ result.put(indicatorName, jo.get(indicatorName));
+ result.put(indicatedName, jo);
+ return result;
+ }
+
+ // Convert the JSON-Simple object to the indicated message, field-by-field
+ // recursively via convertElementToField.
+ private static Message convertJSONObjectToMessage(JSONObject jo, Class c, Registry r) {
+ //System.out.println("JSON.convertJSONObjectToMessage: " + jo.toJSONString());
+ try {
+ Message result = (Message) c.newInstance();
+ for (Field f : c.getFields()) {
+ Class fc = getFieldClass(result, jo, f, r);
+ Object lookup = jo.get(f.getName());
+ if (lookup != null) {
+ Object value = convertElementToField(lookup, fc, f, r);
+ f.set(result, value);
+ }
+ }
+ return result;
+ }
+ catch (Exception ex) {
+ //ex.printStackTrace();
+ return null;
+ }
+ }
+
+ // Convert the JSON-Simple array to the indicated message, element-by-element
+ // recursively via convertElementToField.
+ private static Object convertJSONArrayToArray(JSONArray ja, Class c, Registry r) {
+ Object result = Array.newInstance(c, ja.size());
+ for (int i = 0; i < ja.size(); i++) {
+ Object lookup = ja.get(i);
+ Object value = null;
+ if (lookup != null) {
+ if (lookup.getClass().equals(JSONObject.class))
+ value = convertJSONObjectToMessage((JSONObject) lookup, c, r);
+ else if (lookup.getClass().equals(JSONArray.class)) // this is not actually allowed in ROS
+ value = convertJSONArrayToArray((JSONArray) lookup, c.getComponentType(), r);
+ else
+ value = convertJSONPrimitiveToPrimitive(lookup, c);
+ Array.set(result, i, value);
+ }
+ }
+
+ return result;
+ }
+
+ // Convert a JSON-Simple array to a Message, field-by-field of the Message,
+ // element-by-element of the array, recursively via convertElementToField.
+ // NOTE: This relies on later versions of the JDK providing
+ // the fields in order.
+ private static Message convertJSONArrayToMessage(JSONArray ja, Class c, Registry r) {
+ try {
+ Message result = (Message) c.newInstance();
+ int arrayIndex = 0;
+ for (Field f : c.getFields()) {
+ Class fc = getFieldClass(result, null, f, r);
+ Object lookup = ja.get(arrayIndex++); // yes we are assuming that the fields are delivered in order
+ if (lookup != null) {
+ Object value = convertElementToField(lookup, fc, f, r);
+ f.set(result, value);
+ }
+ }
+
+ return result;
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ // Convert an individual array or object element to a field in the Message,
+ // recursively, and applying AsArray if needed.
+ private static Object convertElementToField(Object element, Class fc, Field f, Registry r) {
+ //System.out.println("JSON.convertElementToField: " + f.getName() + " " + fc.getName());
+ Object value;
+ if (element.getClass().equals(JSONObject.class)) {
+ //System.out.println("JSON.convertElementToField: JSON Object " + ((JSONObject) element).toJSONString());
+ value = convertJSONObjectToMessage((JSONObject) element, fc, r);
+ }
+ else if (element.getClass().equals(JSONArray.class)) {
+ //System.out.println("JSON.convertElementToField: JSON Array " + ((JSONArray) element).toJSONString());
+ if (Indication.asArray(f))
+ value = convertJSONArrayToMessage((JSONArray) element, fc, r);
+ else value = convertJSONArrayToArray((JSONArray) element, fc, r);
+ }
+ else {
+ //System.out.println("JSON.convertElementToField: Primitive " + element);
+ if (Indication.isBase64Encoded(f))
+ value = convertBase64JSONStringToByteArray(element);
+ else value = convertJSONPrimitiveToPrimitive(element, fc);
+ }
+
+ return value;
+ }
+
+ // Note that this is not checking ranges
+ public static Object convertJSONPrimitiveToPrimitive(Object o, Class c) {
+ Object result = o;
+ if (c.isPrimitive() || Number.class.isAssignableFrom(c)) {
+ if (c.equals(double.class) || c.equals(Double.class))
+ result = new Double(((Number) o).doubleValue());
+ else if (c.equals(float.class) || c.equals(Float.class))
+ result = new Float(((Number) o).floatValue());
+ else if (c.equals(long.class) || c.equals(Long.class))
+ result = new Long(((Number) o).longValue());
+ else if (int.class.equals(c) || c.equals(Integer.class))
+ result = new Integer(((Number) o).intValue());
+ else if (c.equals(short.class) || c.equals(Short.class))
+ result = new Short(((Number) o).shortValue());
+ else if (c.equals(byte.class) || c.equals(Byte.class))
+ result = new Byte(((Number) o).byteValue());
+ }
+ return result;
+ }
+
+ public static byte[] convertBase64JSONStringToByteArray(Object element) {
+ return Base64.decode((String) element);
+ }
+
+ // Determine the target class of a field in the object or array, based
+ // directly on the field's type, or using the Indicator if applicable,
+ // The Indicator field only provides the topic/service, so we have to look
+ // up the Class in the registry.
+ public static Class getFieldClass(Message parent, JSONObject jo, Field f, Registry r) {
+ Class fc;
+ fc = f.getType();
+ if (fc.isArray())
+ fc = f.getType().getComponentType();
+ if (Indication.isIndicated(f) && (jo != null)) {
+ //fc = Indication.getIndication(parent,
+ // (String) jo.get(Indication.getIndicatorName(parent.getClass())));
+ fc = r.lookup(parent.getClass(),
+ (String) jo.get(Indication.getIndicatorName(parent.getClass())));
+ //System.out.println("JSON.getFieldClass: parent class " + parent.getClass().getName() +
+ // " Indicator: " + Indication.getIndicatorName(parent.getClass()) +
+ // " result: " + fc.getName());
+ }
+ return fc;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/implementation/ROSBridgeWebSocketClient.java b/ros/src/main/java/com/xbw/ros/rosbridge/implementation/ROSBridgeWebSocketClient.java
new file mode 100755
index 0000000..baa8d76
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/implementation/ROSBridgeWebSocketClient.java
@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.implementation;
+
+import com.xbw.ros.PublishEvent;
+import com.xbw.ros.ROSClient;
+import com.xbw.ros.message.Message;
+import com.xbw.ros.rosbridge.FullMessageHandler;
+import com.xbw.ros.rosbridge.operation.Operation;
+import com.xbw.ros.rosbridge.operation.Publish;
+import com.xbw.ros.rosbridge.operation.ServiceResponse;
+
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.framing.CloseFrame;
+import org.java_websocket.handshake.ServerHandshake;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+import java.lang.reflect.Field;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.channels.SocketChannel;
+
+import de.greenrobot.event.EventBus;
+
+
+public class ROSBridgeWebSocketClient extends WebSocketClient {
+ private Registry classes;
+ private Registry handlers;
+ private boolean debug;
+ private ROSClient.ConnectionStatusListener listener;
+
+ ROSBridgeWebSocketClient(URI serverURI) {
+ super(serverURI);
+ classes = new Registry();
+ handlers = new Registry();
+ Operation.initialize(classes); // note, this ensures that the Message Map is initialized too
+ listener = null;
+ }
+
+ public static ROSBridgeWebSocketClient create(String URIString) {
+ ROSBridgeWebSocketClient client = null;
+ try {
+ URI uri = new URI(URIString);
+ client = new ROSBridgeWebSocketClient(uri);
+ }
+ catch (URISyntaxException ex) {
+ ex.printStackTrace();
+ }
+ return client;
+ }
+
+ public void setListener(ROSClient.ConnectionStatusListener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void onOpen(ServerHandshake handshakedata) {
+ if (listener != null)
+ listener.onConnect();
+ }
+
+ @Override
+ public void onMessage(String message) {
+ if (debug) System.out.println(" " + json);
+ send(json);
+ }
+
+ public void register(Class extends Operation> c,
+ String s,
+ Class extends Message> m,
+ FullMessageHandler h) {
+ Message.register(m, classes.get(Message.class));
+ classes.register(c, s, m);
+ if (h != null)
+ handlers.register(c, s, h);
+ }
+
+ public void unregister(Class extends Operation> c, String s) {
+ handlers.unregister(c, s);
+ // Note that there is no concept of unregistering a class - it can get replaced is all
+ }
+
+ public Class extends Message> getRegisteredMessage(String messageString) {
+ return classes.lookup(Message.class, messageString);
+ }
+
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/implementation/Registry.java b/ros/src/main/java/com/xbw/ros/rosbridge/implementation/Registry.java
new file mode 100755
index 0000000..ae8f0b7
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/implementation/Registry.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.implementation;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Registry extends HashMap> {
+
+ public void register(Class c, String s, T t) {
+ Map table = get(c);
+ if (table == null) {
+ table = new HashMap();
+ put(c, table);
+ }
+ table.put(s, t);
+ }
+
+ public void unregister(Class c, String s) {
+ Map table = get(c);
+ if (table != null)
+ table.remove(s);
+ }
+
+ public T lookup(Class c, String s) {
+ T result = null;
+ Map table = get(c);
+ if (table != null)
+ result = table.get(s);
+ return result;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/indication/AsArray.java b/ros/src/main/java/com/xbw/ros/rosbridge/indication/AsArray.java
new file mode 100755
index 0000000..3ebc0c9
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/indication/AsArray.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.indication;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface AsArray {
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/indication/Base64Encoded.java b/ros/src/main/java/com/xbw/ros/rosbridge/indication/Base64Encoded.java
new file mode 100755
index 0000000..d832d87
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/indication/Base64Encoded.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.indication;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Base64Encoded {
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indicate.java b/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indicate.java
new file mode 100755
index 0000000..4780445
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indicate.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.indication;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Indicate {
+ // if later we want multiple indicated fields, use an int here
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indicated.java b/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indicated.java
new file mode 100755
index 0000000..37038ba
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indicated.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.indication;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Indicated {
+ // if later we want multiple indicated fields, use an int here
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indication.java b/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indication.java
new file mode 100755
index 0000000..43c8fc8
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indication.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.indication;
+
+import java.lang.reflect.Field;
+
+public class Indication {
+ public static boolean isIndicated(Field f) {
+ return (f.getAnnotation(Indicated.class) != null);
+ }
+
+ public static boolean asArray(Field f) {
+ return (f.getAnnotation(AsArray.class) != null);
+ }
+
+ public static boolean isBase64Encoded(Field f) {
+ return ((f.getAnnotation(Base64Encoded.class) != null) &&
+ f.getType().isArray() &&
+ f.getType().getComponentType().equals(byte.class));
+ }
+
+ public static String getIndicatorName(Class c) {
+ return getName(c, Indicator.class);
+ }
+
+ public static String getIndicatedName(Class c) {
+ return getName(c, Indicated.class);
+ }
+
+ private static String getName(Class c, Class annotation) {
+ String result = null;
+ for (Field f : c.getFields()) {
+ if (f.getAnnotation(annotation) != null) {
+ result = f.getName();
+ break;
+ }
+ }
+ return result;
+ }
+
+ /*
+ public static Class getIndication(Object o, String s) {
+ Class c = o.getClass();
+ Class result = null;
+ try {
+ Method m = getIndicateMethod(c);
+ result = (Class) (m.invoke(o, s));
+ }
+ catch (ReflectiveOperationException ex) {
+ ex.printStackTrace();
+ }
+ return result;
+ }
+
+ private static Method getIndicateMethod(Class c) {
+ Method result = null;
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(Indicate.class) != null) {
+ result = m;
+ break;
+ }
+ }
+ return result;
+ }
+ */
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indicator.java b/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indicator.java
new file mode 100755
index 0000000..3d0fed6
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/indication/Indicator.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.indication;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Indicator {
+ // if later we want multiple indicated fields, use an int here
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/Advertise.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Advertise.java
new file mode 100755
index 0000000..cac86a8
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Advertise.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "advertise")
+public class Advertise extends Operation {
+ public String topic;
+ public String type;
+
+ public Advertise() {}
+
+ public Advertise(String topic, String type) {
+ this.topic = topic;
+ this.type = type;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/Authenticate.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Authenticate.java
new file mode 100755
index 0000000..30f813b
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Authenticate.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "auth")
+public class Authenticate extends Operation {
+ public String mac;
+ public String client;
+ public String dest;
+ public String rand;
+ public int t;
+ public String level;
+ public int end;
+
+ public Authenticate() {}
+
+ public Authenticate(
+ String mac,
+ String client,
+ String dest,
+ String rand,
+ int t,
+ String level,
+ int end)
+ {
+ this.mac = mac;
+ this.client = client;
+ this.dest = dest;
+ this.rand = rand;
+ this.t = t;
+ this.level = level;
+ this.end = end;
+
+ this.id = null; // even though id is on EVERY OTHER operation type
+ }
+
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/CallService.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/CallService.java
new file mode 100755
index 0000000..41137de
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/CallService.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+import com.xbw.ros.rosbridge.indication.AsArray;
+import com.xbw.ros.rosbridge.indication.Indicated;
+import com.xbw.ros.rosbridge.indication.Indicator;
+
+@MessageType(string = "call_service")
+public class CallService extends Operation {
+ @Indicator public String service;
+ @Indicated @AsArray public Message args;
+ public Integer fragment_size; // use Integer for optional items
+ public String compression;
+
+ public CallService() {}
+
+ public CallService(String service, Message args) {
+ this.service = service;
+ this.args = args;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/Fragment.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Fragment.java
new file mode 100755
index 0000000..406e2fe
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Fragment.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "fragment")
+public class Fragment extends Operation {
+ public String data;
+ public int num;
+ public int total;
+
+ public Fragment() {}
+
+ public Fragment(String data, int num, int total) {
+ this.data = data;
+ this.num = num;
+ this.total = total;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/Operation.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Operation.java
new file mode 100755
index 0000000..b494e9e
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Operation.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+import com.xbw.ros.rosbridge.implementation.JSON;
+import com.xbw.ros.rosbridge.implementation.Registry;
+
+@MessageType(string = "operation")
+public class Operation extends Message {
+ private static Long uid = 0L;
+
+ public String op;
+ public String id;
+
+ public Operation() {
+ this.op = getMessageType(getClass());
+ this.id = nextId();
+ }
+
+ private static synchronized String nextId() {
+ String result = uid.toString();
+ uid++;
+ return result;
+ }
+
+ public String toJSON() {
+ return JSON.toJSON(this);
+ }
+
+ public static Operation toOperation(String json, Registry registry) {
+ return ((Wrapper) JSON.toMessage(json, Wrapper.class, registry)).msg;
+ }
+
+ public static void initialize(Registry registry) {
+ initClass(registry, Advertise.class);
+ initClass(registry, Authenticate.class);
+ initClass(registry, CallService.class);
+ initClass(registry, Fragment.class);
+ initClass(registry, Operation.class);
+ initClass(registry, PNG.class);
+ initClass(registry, Publish.class);
+ initClass(registry, ServiceResponse.class);
+ initClass(registry, SetStatusLevel.class);
+ initClass(registry, Status.class);
+ initClass(registry, Subscribe.class);
+ initClass(registry, Unadvertise.class);
+ initClass(registry, Unsubscribe.class);
+ initClass(registry, Wrapper.class);
+
+ registry.register(Wrapper.class, Message.getMessageType(Publish.class), Publish.class);
+ registry.register(Wrapper.class, Message.getMessageType(CallService.class), CallService.class);
+ registry.register(Wrapper.class, Message.getMessageType(ServiceResponse.class), ServiceResponse.class);
+ }
+
+ private static void initClass(Registry registry, Class extends Message> c) {
+ registry.register(Message.class, Message.getMessageType(c), c);
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/PNG.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/PNG.java
new file mode 100755
index 0000000..3f9c333
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/PNG.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "png")
+public class PNG extends Operation {
+ public String data;
+ public Integer num; // use Integer for optional items
+ public Integer total; // use Integer for optional items
+
+ public PNG() {}
+
+ public PNG(String data) {
+ this.data = data;
+ }
+
+ public PNG(String data, int num, int total) {
+ this.data = data;
+ this.num = num;
+ this.total = total;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/Publish.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Publish.java
new file mode 100755
index 0000000..36db28f
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Publish.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+import com.xbw.ros.rosbridge.indication.Indicated;
+import com.xbw.ros.rosbridge.indication.Indicator;
+
+@MessageType(string = "publish")
+public class Publish extends Operation {
+
+ @Indicator public String topic;
+ @Indicated
+ public Message msg;
+
+ public Publish() {}
+
+ public Publish(String topic, Message msg) {
+ this.topic = topic;
+ this.msg = msg;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/ServiceResponse.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/ServiceResponse.java
new file mode 100755
index 0000000..54b592b
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/ServiceResponse.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.Message;
+import com.xbw.ros.message.MessageType;
+import com.xbw.ros.rosbridge.indication.Indicated;
+import com.xbw.ros.rosbridge.indication.Indicator;
+
+@MessageType(string = "service_response")
+public class ServiceResponse extends Operation {
+ @Indicator public String service;
+ public boolean result;
+ @Indicated public Message values;
+
+ public ServiceResponse() {}
+
+ public ServiceResponse(String service) {
+ this.service = service;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/SetStatusLevel.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/SetStatusLevel.java
new file mode 100755
index 0000000..fef3514
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/SetStatusLevel.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "set_level")
+public class SetStatusLevel extends Operation {
+ public String level;
+
+ public SetStatusLevel() {}
+
+ public SetStatusLevel(String level) {
+ this.level = null;
+ if ("none".equals(level) ||
+ "warning".equals(level) ||
+ "error".equals(level) ||
+ "info".equals(level))
+ this.level = level;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/Status.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Status.java
new file mode 100755
index 0000000..0256a93
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Status.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "status")
+public class Status extends Operation {
+ String level;
+ String msg;
+
+ public Status() {}
+
+ public Status(String level, String msg) {
+ this.level = level;
+ this.msg = msg;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/Subscribe.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Subscribe.java
new file mode 100755
index 0000000..7030c02
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Subscribe.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "subscribe")
+public class Subscribe extends Operation {
+ public String topic;
+ public String type;
+ public Integer throttle_rate; // use Integer for optional items
+ public Integer queue_length; // use Integer for optional items
+ public Integer fragment_size; // use Integer for optional items
+ public String compression;
+
+ public Subscribe() {}
+
+ public Subscribe(String topic, String type) {
+ this.topic = topic;
+ this.type = type;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/Unadvertise.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Unadvertise.java
new file mode 100755
index 0000000..745fd92
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Unadvertise.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "unadvertise")
+public class Unadvertise extends Operation {
+ public String topic;
+
+ public Unadvertise() {}
+
+ public Unadvertise(String topic) {
+ this.topic = topic;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/Unsubscribe.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Unsubscribe.java
new file mode 100755
index 0000000..30357ef
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Unsubscribe.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.MessageType;
+
+@MessageType(string = "unsubscribe")
+public class Unsubscribe extends Operation {
+ public String topic;
+
+ public Unsubscribe() {}
+
+ public Unsubscribe(String topic) {
+ this.topic = topic;
+ }
+}
diff --git a/ros/src/main/java/com/xbw/ros/rosbridge/operation/Wrapper.java b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Wrapper.java
new file mode 100755
index 0000000..a272d5d
--- /dev/null
+++ b/ros/src/main/java/com/xbw/ros/rosbridge/operation/Wrapper.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2014 Jilk Systems, Inc.
+ *
+ * This file is part of the Java ROSBridge Client.
+ *
+ * The Java ROSBridge Client is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Java ROSBridge Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+package com.xbw.ros.rosbridge.operation;
+
+import com.xbw.ros.message.MessageType;
+import com.xbw.ros.rosbridge.indication.Indicated;
+import com.xbw.ros.rosbridge.indication.Indicator;
+
+@MessageType(string = "wrapper")
+public class Wrapper extends Operation {
+ @Indicator public String op;
+ @Indicated
+ public Operation msg;
+
+ public Wrapper() {}
+}
diff --git a/ros/src/main/res/values/strings.xml b/ros/src/main/res/values/strings.xml
new file mode 100644
index 0000000..58cee94
--- /dev/null
+++ b/ros/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ ros
+
diff --git a/ros/src/test/java/com/xbw/ros/ExampleUnitTest.java b/ros/src/test/java/com/xbw/ros/ExampleUnitTest.java
new file mode 100644
index 0000000..8bbaaf1
--- /dev/null
+++ b/ros/src/test/java/com/xbw/ros/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.xbw.ros;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/rosbridge.iml b/rosbridge.iml
new file mode 100644
index 0000000..a30df64
--- /dev/null
+++ b/rosbridge.iml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..2d086eb
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app', ':ros'