event) {
+ this.mEventBus.dispatchEvent(event);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/build.gradle b/src/android/TelinkBleMeshLib/build.gradle
new file mode 100644
index 00000000..0258185b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/build.gradle
@@ -0,0 +1,78 @@
+apply plugin: 'com.android.library'
+apply plugin: 'maven-publish'
+
+android {
+ compileSdkVersion 29
+ buildToolsVersion "29.0.1"
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 26
+ versionCode 3
+ versionName "3.3.3.5"
+
+ 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.madgag.spongycastle:core:1.58.0.0'
+ implementation 'com.madgag.spongycastle:prov:1.58.0.0'
+
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ // testImplementation 'junit:junit:4.12'
+ // androidTestImplementation 'com.android.support.test:runner:0.5'
+ // androidTestImplementation 'com.android.support.test.espresso:espresso-core:2.2.2'
+}
+
+repositories {
+ mavenCentral()
+ google()
+}
+
+buildscript {
+ repositories {
+ jcenter()
+ mavenCentral()
+ google()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.5.0'
+ classpath 'com.madgag.spongycastle:core:1.58.0.0'
+ classpath 'com.madgag.spongycastle:prov:1.58.0.0'
+ classpath 'androidx.appcompat:appcompat:1.1.0'
+ }
+}
+
+task sourceJar(type: Jar) {
+ from android.sourceSets.main.java.srcDirs
+ classifier "sources"
+}
+
+publishing {
+ publications {
+ bar(MavenPublication) {
+ groupId 'com.telink.ble'
+ artifactId 'telink-ble-mesh-lib'
+ version '0.1'
+ artifact(sourceJar)
+ artifact("$buildDir/outputs/aar/telink-ble-mesh-release.aar")
+ }
+ }
+ repositories {
+ maven {
+ url "$buildDir/src"
+ }
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/build/outputs/aar/TelinkBleMeshLib-debug.aar b/src/android/TelinkBleMeshLib/build/outputs/aar/TelinkBleMeshLib-debug.aar
new file mode 100644
index 00000000..32857db1
Binary files /dev/null and b/src/android/TelinkBleMeshLib/build/outputs/aar/TelinkBleMeshLib-debug.aar differ
diff --git a/src/android/TelinkBleMeshLib/build/outputs/aar/TelinkBleMeshLib.aar b/src/android/TelinkBleMeshLib/build/outputs/aar/TelinkBleMeshLib.aar
new file mode 100644
index 00000000..f6cbddee
Binary files /dev/null and b/src/android/TelinkBleMeshLib/build/outputs/aar/TelinkBleMeshLib.aar differ
diff --git a/src/android/TelinkBleMeshLib/gradle-wrapper.properties b/src/android/TelinkBleMeshLib/gradle-wrapper.properties
new file mode 100644
index 00000000..b66802c7
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/gradle-wrapper.properties
@@ -0,0 +1 @@
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
\ No newline at end of file
diff --git a/src/android/TelinkBleMeshLib/gradle/wrapper/gradle-wrapper.jar b/src/android/TelinkBleMeshLib/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..5c2d1cf0
Binary files /dev/null and b/src/android/TelinkBleMeshLib/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/src/android/TelinkBleMeshLib/gradle/wrapper/gradle-wrapper.properties b/src/android/TelinkBleMeshLib/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..f4d7b2bf
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/src/android/TelinkBleMeshLib/gradlew b/src/android/TelinkBleMeshLib/gradlew
new file mode 100755
index 00000000..b0d6d0ab
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/gradlew
@@ -0,0 +1,188 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## 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='"-Xmx64m" "-Xms64m"'
+
+# 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/src/android/TelinkBleMeshLib/gradlew.bat b/src/android/TelinkBleMeshLib/gradlew.bat
new file mode 100644
index 00000000..15e1ee37
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@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="-Xmx64m" "-Xms64m"
+
+@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/src/android/TelinkBleMeshLib/proguard-rules.pro b/src/android/TelinkBleMeshLib/proguard-rules.pro
new file mode 100644
index 00000000..f1b42451
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/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/src/android/TelinkBleMeshLib/publish.gradle b/src/android/TelinkBleMeshLib/publish.gradle
new file mode 100644
index 00000000..e69de29b
diff --git a/src/android/TelinkBleMeshLib/repositories.gradle b/src/android/TelinkBleMeshLib/repositories.gradle
new file mode 100644
index 00000000..6f48f26c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/repositories.gradle
@@ -0,0 +1,22 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or ag reed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+ext.repos = {
+ google()
+ jcenter()
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/AndroidManifest.xml b/src/android/TelinkBleMeshLib/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..e64f7f09
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/AndroidManifest.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/Encipher.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/Encipher.java
new file mode 100644
index 00000000..5cc6c51e
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/Encipher.java
@@ -0,0 +1,448 @@
+/********************************************************************************************************
+ * @file Encipher.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core;
+
+import com.telink.ble.mesh.util.MeshLogger;
+
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.engines.AESEngine;
+import org.spongycastle.crypto.engines.AESLightEngine;
+import org.spongycastle.crypto.macs.CMac;
+import org.spongycastle.crypto.modes.CCMBlockCipher;
+import org.spongycastle.crypto.params.AEADParameters;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.jce.ECNamedCurveTable;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+import org.spongycastle.util.BigIntegers;
+
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+
+import javax.crypto.KeyAgreement;
+
+/**
+ * Created by kee on 2019/7/19.
+ */
+
+public final class Encipher {
+
+ private static final byte[] SALT_INPUT_K2 = "smk2".getBytes();
+
+ private static final byte[] SALT_INPUT_K3 = "smk3".getBytes();
+
+ private static final byte[] SALT_INPUT_K4 = "smk4".getBytes();
+
+ // private static final byte[] SALT_INPUT_SMK4 = "smk4".getBytes();
+ // “id6” || 0x01
+ private static final byte[] SALT_K3_M = new byte[]{0x69, 0x64, 0x36, 0x34, 0x01};
+
+ // // “id64” || 0x01
+ private static final byte[] SALT_K4_M = new byte[]{0x69, 0x64, 0x36, 0x01};
+
+ private static final byte[] SALT_NKIK = "nkik".getBytes();
+
+ private static final byte[] SALT_BKIK = "nkbk".getBytes();
+
+ private static final byte[] SALT_ID128 = "id128".getBytes();
+
+ // 48 bit
+ private static final byte[] NODE_IDENTITY_HASH_PADDING = new byte[]{0, 0, 0, 0, 0, 0};
+
+ public static final byte[] PRCK = "prck".getBytes();
+
+ public static final byte[] PRSK = "prsk".getBytes();
+
+ public static final byte[] PRSN = "prsn".getBytes();
+
+ public static final byte[] PRDK = "prdk".getBytes();
+
+
+ public static KeyPair generateKeyPair() {
+ try {
+ // secp256r1
+ ECNamedCurveParameterSpec ecParamSpec = ECNamedCurveTable.getParameterSpec("P-256");
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("ECDH", "SC");
+ generator.initialize(ecParamSpec);
+
+ return generator.generateKeyPair();
+ } catch (Exception e) {
+ MeshLogger.log("generate key pair err!");
+ return null;
+ }
+ }
+
+ public static byte[] generateECDH(byte[] xy, PrivateKey provisionerPrivateKey) {
+ try {
+ BigInteger x = BigIntegers.fromUnsignedByteArray(xy, 0, 32);
+ BigInteger y = BigIntegers.fromUnsignedByteArray(xy, 32, 32);
+
+ ECParameterSpec ecParameters = ECNamedCurveTable.getParameterSpec("secp256r1");
+ ECCurve curve = ecParameters.getCurve();
+ ECPoint ecPoint = curve.validatePoint(x, y);
+
+ ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint, ecParameters);
+ KeyFactory keyFactory;
+ keyFactory = KeyFactory.getInstance("ECDH", "SC");
+ ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);
+
+ KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "SC");
+ keyAgreement.init(provisionerPrivateKey);
+ keyAgreement.doPhase(publicKey, true);
+ return keyAgreement.generateSecret();
+ } catch (NoSuchAlgorithmException | IllegalArgumentException | NoSuchProviderException | InvalidKeySpecException | InvalidKeyException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * aes-cmac
+ *
+ * k is the 128-bit key
+ * m is the variable length data to be authenticated
+ */
+ public static byte[] aesCmac(byte[] content, byte[] key) {
+ CipherParameters cipherParameters = new KeyParameter(key);
+ BlockCipher blockCipher = new AESEngine();
+ CMac mac = new CMac(blockCipher);
+
+ mac.init(cipherParameters);
+ mac.update(content, 0, content.length);
+ byte[] re = new byte[16];
+ mac.doFinal(re, 0);
+ return re;
+ }
+
+ private static final byte[] SALT_KEY_ZERO =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ /**
+ * S1
+ * s1(M) = AES-CMAC ZERO (M)
+ *
+ * @param m input
+ * @return re
+ */
+ public static byte[] generateSalt(byte[] m) {
+ return aesCmac(m, SALT_KEY_ZERO);
+ }
+
+ /*
+ The inputs to function k1 are:
+N is 0 or more octets SALT is 128 bits
+P is 0 or more octets
+The key (T) is computed as follows: T = AES-CMAC SALT (N)
+The output of the key generation function k1 is as follows: k1(N, SALT, P) = AES-CMACT (P)
+ */
+
+
+ /**
+ * @param data target data
+ * @param k key
+ * @param n nonce
+ * @param micSize mic
+ * @param encrypt true: encryption, false: decryption
+ * @return result
+ */
+ public static byte[] ccm(byte[] data, byte[] k, byte[] n, int micSize, boolean encrypt) {
+ byte[] result = new byte[data.length + (encrypt ? micSize : (-micSize))];
+ CCMBlockCipher ccmBlockCipher = new CCMBlockCipher(new AESEngine());
+ AEADParameters aeadParameters = new AEADParameters(new KeyParameter(k), micSize * 8, n);
+ ccmBlockCipher.init(encrypt, aeadParameters);
+ ccmBlockCipher.processBytes(data, 0, data.length, result, data.length);
+ try {
+ ccmBlockCipher.doFinal(result, 0);
+ return result;
+ } catch (InvalidCipherTextException e) {
+ return null;
+ }
+ }
+
+
+ public static byte[] aes(byte[] data, byte[] key) {
+ final byte[] encrypted = new byte[data.length];
+ final CipherParameters cipherParameters = new KeyParameter(key);
+ final AESLightEngine engine = new AESLightEngine();
+ engine.init(true, cipherParameters);
+ engine.processBlock(data, 0, encrypted, 0);
+
+ return encrypted;
+ }
+
+
+ public static byte[] k1(byte[] ecdh, byte[] salt, byte[] text) {
+ byte[] t = aesCmac(ecdh, salt);
+ return aesCmac(text, t);
+ }
+
+ public static byte[][] calculateNetKeyK2(byte[] netKey) {
+ return k2(netKey, new byte[]{0});
+ }
+
+ public static byte[][] k2(byte[] data, byte[] p) {
+
+ byte[] salt = generateSalt(SALT_INPUT_K2);
+ byte[] t = aesCmac(data, salt);
+
+ byte[] t0 = {};
+ final ByteBuffer inputBufferT0 = ByteBuffer.allocate(t0.length + p.length + 1);
+ inputBufferT0.put(t0);
+ inputBufferT0.put(p);
+ inputBufferT0.put((byte) 0x01);
+ final byte[] t1 = aesCmac(inputBufferT0.array(), t);
+// final byte nid = (byte) (t1[15] & 0x7F);
+
+ final ByteBuffer inputBufferT1 = ByteBuffer.allocate(t1.length + p.length + 1);
+ inputBufferT1.put(t1);
+ inputBufferT1.put(p);
+ inputBufferT1.put((byte) 0x02);
+ // encryptionKey
+ final byte[] t2 = aesCmac(inputBufferT1.array(), t);
+
+ final ByteBuffer inputBufferT2 = ByteBuffer.allocate(t2.length + p.length + 1);
+ inputBufferT2.put(t2);
+ inputBufferT2.put(p);
+ inputBufferT2.put((byte) 0x03);
+ // privacyKey
+ final byte[] t3 = aesCmac(inputBufferT2.array(), t);
+
+ return new byte[][]{t1, t2, t3};
+ }
+
+ public static byte[] k3(byte[] n) {
+ byte[] salt = generateSalt(SALT_INPUT_K3);
+ byte[] t = aesCmac(n, salt);
+ byte[] result = aesCmac(SALT_K3_M, t);
+ byte[] networkId = new byte[8];
+ int srcOffset = result.length - networkId.length;
+ System.arraycopy(result, srcOffset, networkId, 0, networkId.length);
+ return networkId;
+ }
+
+
+ public static byte k4(byte[] n) {
+ byte[] salt = generateSalt(SALT_INPUT_K4);
+ byte[] t = aesCmac(n, salt);
+ byte[] result = aesCmac(SALT_K4_M, t);
+ return (byte) ((result[15]) & 0x3F);
+ }
+
+ public static byte[] generateNodeIdentityHash(byte[] identityKey, byte[] random, int src) {
+ int length = NODE_IDENTITY_HASH_PADDING.length + random.length + 2;
+ ByteBuffer bufferHashInput = ByteBuffer.allocate(length).order(ByteOrder.BIG_ENDIAN);
+ bufferHashInput.put(NODE_IDENTITY_HASH_PADDING);
+ bufferHashInput.put(random);
+ bufferHashInput.putShort((short) src);
+ byte[] hashInput = bufferHashInput.array();
+ byte[] hash = aes(hashInput, identityKey);
+
+ ByteBuffer buffer = ByteBuffer.allocate(8);
+ buffer.put(hash, 8, 8);
+
+ return buffer.array();
+ }
+
+ public static byte[] generateIdentityKey(byte[] networkKey) {
+ byte[] salt = generateSalt(SALT_NKIK);
+ ByteBuffer buffer = ByteBuffer.allocate(SALT_ID128.length + 1);
+ buffer.put(SALT_ID128);
+ buffer.put((byte) 0x01);
+ byte[] p = buffer.array();
+ return k1(networkKey, salt, p);
+ }
+
+ public static byte[] generateBeaconKey(byte[] networkKey) {
+ byte[] salt = generateSalt(SALT_BKIK);
+ ByteBuffer buffer = ByteBuffer.allocate(SALT_ID128.length + 1);
+ buffer.put(SALT_ID128);
+ buffer.put((byte) 0x01);
+ byte[] p = buffer.array();
+ return k1(networkKey, salt, p);
+ }
+
+ /**
+ * @param data online status data
+ * @param key netKey->beaconKey
+ * @return decryption result
+ */
+ public static byte[] decryptOnlineStatus(byte[] data, byte[] key) {
+ final int ivLen = 4;
+ byte[] iv = new byte[ivLen];
+ System.arraycopy(data, 0, iv, 0, ivLen);
+
+ final int micLen = 2;
+ byte[] mic = new byte[micLen];
+ int micIndex = data.length - micLen;
+ System.arraycopy(data, micIndex, mic, 0, micLen);
+
+ int len = data.length - ivLen - micLen;
+ byte[] status = new byte[len];
+ System.arraycopy(data, ivLen, status, 0, len);
+
+// int result = aes_att_decryption_packet_online_st(key, iv, ivLen, mic, micLen, status, len);
+
+ byte[] e = new byte[16], r = new byte[16];
+
+ ///////////////// calculate enc ////////////////////////
+ System.arraycopy(iv, 0, r, 1, ivLen);
+
+// memcpy(r + 1, iv, iv_len);
+ for (int i = 0; i < len; i++) {
+ if ((i & 15) == 0) {
+ e = aes(r, key);
+ r[0]++;
+ }
+ status[i] ^= e[i & 15];
+ }
+ ///////////// calculate mic ///////////////////////
+ r = new byte[16];
+// memset(r, 0, 16);
+ System.arraycopy(iv, 0, r, 0, ivLen);
+// memcpy(r, iv, iv_len);
+ r[ivLen] = (byte) len;
+ r = aes(r, key);
+
+ for (int i = 0; i < len; i++) {
+ r[i & 15] ^= status[i];
+
+ if ((i & 15) == 15 || i == len - 1) {
+ r = aes(r, key);
+ }
+ }
+
+ for (int i = 0; i < micLen; i++) {
+ if (mic[i] != r[i]) {
+ return null; //Failed
+ }
+ }
+
+ System.arraycopy(status, 0, data, ivLen, status.length);
+ return data;
+ }
+
+
+ /**
+ * check version & time & Serial Number
+ *
+ *
+ * "ecdsa-with-SHA256"
+ * check certificate data and return inner public key
+ *
+ * @param cerData certificate data formatted by x509 der
+ * @return public key
+ */
+ public static byte[] checkCertificate(byte[] cerData) {
+ CertificateFactory factory = null;
+ try {
+ factory = CertificateFactory.getInstance("X.509");
+
+ X509Certificate certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(cerData));
+ if (certificate.getVersion() != 3) {
+ MeshLogger.d("version check err");
+ return null;
+ }
+
+ int serialNumber = certificate.getSerialNumber().intValue();
+ if (serialNumber != 4096) {
+ MeshLogger.d("serial number check err");
+ return null;
+ }
+
+ /**
+ * check datetime validity
+ */
+ certificate.checkValidity();
+
+ /**
+ * get X509 version
+ */
+ certificate.getVersion();
+
+ /**
+ * get subject names ,
+ */
+ certificate.getSubjectAlternativeNames();
+ certificate.getExtendedKeyUsage();
+// byte[] publicKey = certificate.getPublicKey().getEncoded();
+
+ Signature verifier = Signature.getInstance(certificate.getSigAlgName(), "SC");
+// verifier.initVerify(certificate.getPublicKey()); // This cert is signed by CA
+ verifier.initVerify(certificate); // This cert is signed by CA
+ verifier.update(certificate.getTBSCertificate()); //TBS is to get the "To Be Signed" part of the certificate - .getEncoded() gets the whole cert, which includes the signature
+ boolean result = verifier.verify(certificate.getSignature());
+
+
+ java.security.interfaces.ECPublicKey pk = (java.security.interfaces.ECPublicKey) certificate.getPublicKey();
+ byte[] keyX = pk.getW().getAffineX().toByteArray();
+ if (keyX.length > 32) {
+ byte[] x = new byte[32];
+ System.arraycopy(keyX, 1, x, 0, 32);
+ keyX = x;
+ }
+ byte[] keyY = pk.getW().getAffineY().toByteArray();
+ if (keyY.length > 32) {
+ byte[] y = new byte[32];
+ System.arraycopy(keyY, 1, y, 0, 32);
+ keyY = y;
+ }
+
+ byte[] pubKeyKey = new byte[keyX.length + keyY.length];
+ System.arraycopy(keyX, 0, pubKeyKey, 0, keyX.length);
+ System.arraycopy(keyY, 0, pubKeyKey, keyX.length, keyY.length);
+
+ if (result) {
+ System.out.println("signature validation pass");
+// return null;
+ return pubKeyKey;
+ } else {
+ System.out.println("signature validation failed");
+ return null;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/MeshUtils.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/MeshUtils.java
new file mode 100644
index 00000000..94e64781
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/MeshUtils.java
@@ -0,0 +1,287 @@
+/********************************************************************************************************
+ * @file MeshUtils.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core;
+
+import android.os.ParcelUuid;
+
+import com.telink.ble.mesh.core.ble.MeshScanRecord;
+import com.telink.ble.mesh.core.ble.UUIDInfo;
+import com.telink.ble.mesh.util.Arrays;
+
+import java.io.ByteArrayInputStream;
+import java.nio.ByteOrder;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.ECPublicKey;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+
+public final class MeshUtils {
+
+ // public static final int DEVICE_ADDRESS_MAX = 0xFFFE; // 0x00FF
+
+ public static final int UNICAST_ADDRESS_MAX = 0x7FFF; // 0x7F00
+ public static final int UNICAST_ADDRESS_MIN = 0x0001; // 0x0001
+
+ public static final String CHARS = "123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ+-*/<>/?!@#$%^&;'[]{}|,.";
+
+ public static final int ADDRESS_BROADCAST = 0xFFFF;
+
+ // 1970 -- 2000 offset second
+ public static final long TAI_OFFSET_SECOND = 946684800;
+
+ public static final long UNSIGNED_INTEGER_MAX = 0xFFFFFFFFL;
+
+ private static SecureRandom rng;
+
+ private MeshUtils() {
+ }
+
+ public static byte[] generateRandom(int length) {
+
+ byte[] data = new byte[length];
+
+ synchronized (MeshUtils.class) {
+ if (rng == null) {
+ rng = new SecureRandom();
+ }
+ }
+
+ rng.nextBytes(data);
+
+ return data;
+ }
+
+ public static long getTaiTime() {
+ return Calendar.getInstance().getTimeInMillis() / 1000 - TAI_OFFSET_SECOND;
+ }
+
+ /**
+ * Mesh V1.0 3.7.3.1 Operation codes
+ * Opcode Format
+ * Notes
+ * 0xxxxxxx (excluding 01111111)
+ * 1-octet Opcodes
+ * 01111111
+ * Reserved for Future Use
+ * 10xxxxxx xxxxxxxx
+ * 2-octet Opcodes
+ * 11xxxxxx zzzzzzzz
+ * 3-octet Opcodes
+ */
+
+ /*public static OpcodeType getOpType(byte opFst) {
+// final int opVal = getValue();
+ return (opFst & bit(7)) != 0
+ ?
+ ((opFst & bit(6)) != 0 ? OpcodeType.VENDOR : OpcodeType.SIG_2)
+ :
+ OpcodeType.SIG_1;
+ }*/
+ public static int bit(int n) {
+ return 1 << n;
+ }
+
+ public static byte[] generateChars(int length) {
+
+ int charLen = CHARS.length() - 1;
+ int charAt;
+
+ byte[] data = new byte[length];
+
+ for (int i = 0; i < length; i++) {
+ charAt = (int) Math.round(Math.random() * charLen);
+ data[i] = (byte) CHARS.charAt(charAt);
+ }
+
+ return data;
+ }
+
+
+ /**
+ * convert byte buffer to integer
+ *
+ * @param buffer target buffer
+ * @param order {@link ByteOrder#BIG_ENDIAN} and {@link ByteOrder#LITTLE_ENDIAN}
+ * @return int value, max 32-bit length
+ */
+ public static int bytes2Integer(byte[] buffer, ByteOrder order) {
+ int re = 0;
+ int valLen = (buffer.length > 4 ? 4 : buffer.length);
+ for (int i = 0; i < valLen; i++) {
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ re |= (buffer[i] & 0xFF) << (8 * i);
+ } else if (order == ByteOrder.BIG_ENDIAN) {
+ re |= (buffer[i] & 0xFF) << (8 * (valLen - i - 1));
+ }
+ }
+ return re;
+ }
+
+ /**
+ * @param buffer target buffer
+ * @param offset buffer start position
+ * @param size selected bytes length
+ * @param order ByteOrder
+ * @return int value
+ */
+ public static int bytes2Integer(byte[] buffer, int offset, int size, ByteOrder order) {
+ int re = 0;
+ int valLen = Math.min(4, size);
+ for (int i = 0; i < valLen; i++) {
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ re |= (buffer[i + offset] & 0xFF) << (8 * i);
+ } else if (order == ByteOrder.BIG_ENDIAN) {
+ re |= (buffer[i + offset] & 0xFF) << (8 * (valLen - i - 1));
+ }
+ }
+ return re;
+ }
+
+ public static long bytes2Long(byte[] buffer, int offset, int size, ByteOrder order) {
+ long re = 0;
+ int valLen = Math.min(8, size);
+ for (int i = 0; i < valLen; i++) {
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ re |= (buffer[i + offset] & 0xFF) << (8 * i);
+ } else if (order == ByteOrder.BIG_ENDIAN) {
+ re |= (buffer[i + offset] & 0xFF) << (8 * (valLen - i - 1));
+ }
+ }
+ return re;
+ }
+
+ public static byte[] integer2Bytes(int i, int size, ByteOrder order) {
+ if (size > 4) size = 4;
+ byte[] re = new byte[size];
+ for (int j = 0; j < size; j++) {
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ re[j] = (byte) (i >> (8 * j));
+ } else {
+ re[size - j - 1] = (byte) (i >> (8 * j));
+ }
+ }
+ return re;
+ }
+
+ /**
+ * @param hex input
+ * @return int value
+ */
+ public static int hexString2Int(String hex, ByteOrder order) {
+ byte[] buf = Arrays.hexToBytes(hex);
+ return bytes2Integer(buf, order);
+ }
+
+ public static byte[] sequenceNumber2Buffer(int sequenceNumber) {
+ return integer2Bytes(sequenceNumber, 3, ByteOrder.BIG_ENDIAN);
+ }
+
+ public static byte generateAid(byte[] key) {
+ return Encipher.k4(key);
+ }
+
+ public static int getMicSize(byte szmic) {
+ return szmic == 0 ? 4 : 8;
+ }
+
+ public static boolean validUnicastAddress(int address) {
+ return (address & 0xFFFF) <= UNICAST_ADDRESS_MAX && (address & 0xFFFF) >= UNICAST_ADDRESS_MIN;
+ }
+
+ public static boolean validGroupAddress(int address) {
+ return (address & 0xFFFF) < 0xFF00 && (address & 0xFFFF) >= 0xC000;
+ }
+
+ public static double mathLog2(int i) {
+ return Math.log(i) / Math.log(2);
+ }
+
+ public static long unsignedIntegerCompare(int a, int b) {
+ return (a & UNSIGNED_INTEGER_MAX) - (b & UNSIGNED_INTEGER_MAX);
+ }
+
+ static final String FORMAT_1_BYTES = "%02X";
+ static final String FORMAT_2_BYTES = "%04X";
+ static final String FORMAT_3_BYTES = "%06X";
+ static final String FORMAT_4_BYTES = "%08X";
+
+ public static String formatIntegerByHex(int value) {
+ if (value <= -1) {
+ return String.format(FORMAT_4_BYTES, value);
+ } else if (value <= 0xFF) {
+ return String.format(FORMAT_1_BYTES, value);
+ } else if (value <= 0xFFFF) {
+ return String.format(FORMAT_2_BYTES, value);
+ } else {
+ return String.format(FORMAT_3_BYTES, value);
+ }
+ }
+
+ /**
+ * @param unprovisioned true: get provision service data, false: get proxy service data
+ */
+ public static byte[] getMeshServiceData(byte[] scanRecord, boolean unprovisioned) {
+ MeshScanRecord meshScanRecord = MeshScanRecord.parseFromBytes(scanRecord);
+ return meshScanRecord.getServiceData(ParcelUuid.fromString((unprovisioned ? UUIDInfo.SERVICE_PROVISION : UUIDInfo.SERVICE_PROXY).toString()));
+ }
+
+ /**
+ * get missing bit position
+ */
+ public static List parseMissingBitField(@NonNull byte[] params, int offset) {
+ List missingChunks = new ArrayList<>();
+ final int BYTE_LEN = 8;
+ byte val;
+ for (int basePosition = 0; offset < params.length; offset++, basePosition += BYTE_LEN) {
+ val = params[offset];
+ for (int i = 0; i < BYTE_LEN; i++) {
+ boolean missing = ((val >> i) & 0b01) == 1;
+ if (missing) {
+ missingChunks.add(basePosition + i);
+ }
+ }
+ }
+ return missingChunks;
+ }
+
+
+ /**
+ * @return is certificate based supported
+ */
+ public static boolean isCertSupported(int oobInfo) {
+ return (oobInfo & MeshUtils.bit(7)) != 0;
+ }
+
+ /**
+ * @return is provisioning record supported
+ */
+ public static boolean isPvRecordSupported(int oobInfo) {
+ return (oobInfo & MeshUtils.bit(8)) != 0;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/AccessBridge.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/AccessBridge.java
new file mode 100644
index 00000000..7e428bd2
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/AccessBridge.java
@@ -0,0 +1,59 @@
+/********************************************************************************************************
+ * @file AccessBridge.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.access;
+
+import com.telink.ble.mesh.core.message.MeshMessage;
+
+/**
+ * Created by kee on 2019/9/11.
+ */
+
+public interface AccessBridge {
+
+ /**
+ * BINDING flow
+ */
+ int MODE_BINDING = 1;
+
+ /**
+ * firmware updating (mesh ota)
+ */
+ int MODE_FIRMWARE_UPDATING = 2;
+
+ // remote provision
+ int MODE_REMOTE_PROVISIONING = 3;
+
+ int MODE_FAST_PROVISION = 4;
+
+ /**
+ * prepared to send mesh message
+ *
+ * @return if message sent
+ */
+ boolean onAccessMessagePrepared(MeshMessage meshMessage, int mode);
+
+ /**
+ * @param state binding state
+ * @param desc desc
+ */
+ void onAccessStateChanged(int state, String desc, int mode, Object obj);
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/BindingBearer.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/BindingBearer.java
new file mode 100644
index 00000000..0472562f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/BindingBearer.java
@@ -0,0 +1,41 @@
+/********************************************************************************************************
+ * @file BindingBearer.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.access;
+
+/**
+ * bearer
+ * Created by kee on 2019/9/5.
+ */
+
+public enum BindingBearer {
+ /**
+ * binding only when target device is direct connected
+ */
+ GattOnly,
+
+ /**
+ * binding if mesh proxy is connected
+ */
+ Any,
+
+ Flex
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/BindingController.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/BindingController.java
new file mode 100644
index 00000000..76a7cfd0
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/BindingController.java
@@ -0,0 +1,387 @@
+/********************************************************************************************************
+ * @file BindingController.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.access;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.message.MeshSigModel;
+import com.telink.ble.mesh.core.message.NotificationMessage;
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.config.AppKeyAddMessage;
+import com.telink.ble.mesh.core.message.config.AppKeyStatusMessage;
+import com.telink.ble.mesh.core.message.config.CompositionDataGetMessage;
+import com.telink.ble.mesh.core.message.config.CompositionDataStatusMessage;
+import com.telink.ble.mesh.core.message.config.ModelAppBindMessage;
+import com.telink.ble.mesh.core.message.config.ModelAppStatusMessage;
+import com.telink.ble.mesh.entity.BindingDevice;
+import com.telink.ble.mesh.entity.CompositionData;
+import com.telink.ble.mesh.util.MeshLogger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * binding flow,
+ * 1. get composition data
+ * 2. add app key
+ * 3. bind app key for selected models or all models
+ * Created by kee on 2019/9/10.
+ */
+
+public class BindingController {
+
+ private final String LOG_TAG = "Binding";
+
+ public static final int STATE_FAIL = 0;
+
+ public static final int STATE_SUCCESS = 1;
+
+ /**
+ * init
+ */
+ private static final int STEP_INIT = 0;
+
+ /**
+ * getting composition data
+ */
+ private static final int STEP_GET_CPS = 1;
+
+ /**
+ * app key adding
+ */
+ private static final int STEP_APP_KEY_ADD = 2;
+
+ /**
+ * key binding one by one
+ */
+ private static final int STEP_APP_KEY_BIND = 3;
+
+ private int step = STEP_INIT;
+
+ private int netKeyIndex;
+
+ private byte[] appKey;
+
+ /**
+ * binding target node
+ */
+ private BindingDevice bindingDevice;
+
+ /**
+ * binding models index
+ */
+ private int modelIndex = 0;
+ // private int appKeyIndex;
+ /**
+ * target models in binding device
+ */
+ private List bindingModels = new ArrayList<>();
+
+ // for command sent
+ private AccessBridge accessBridge;
+
+ private Handler delayHandler;
+
+ private static final long BINDING_TIMEOUT_GATT = 30 * 1000;
+
+ private static final long BINDING_TIMEOUT_ADV = 60 * 1000;
+
+ public BindingController(HandlerThread handlerThread) {
+ this.delayHandler = new Handler(handlerThread.getLooper());
+ }
+
+ public void register(AccessBridge accessBridge) {
+ this.accessBridge = accessBridge;
+ }
+
+ public BindingDevice getBindingDevice() {
+ return bindingDevice;
+ }
+
+ public void begin(int netKeyIndex, byte[] appKey, BindingDevice device) {
+ this.netKeyIndex = netKeyIndex;
+ this.bindingDevice = device;
+ this.appKey = appKey;
+ this.bindingModels.clear();
+ this.modelIndex = 0;
+
+ delayHandler.removeCallbacks(bindingTimeoutTask);
+ delayHandler.postDelayed(bindingTimeoutTask,
+ isGattBearer() ? BINDING_TIMEOUT_GATT : BINDING_TIMEOUT_ADV);
+
+ log("binding begin: defaultBound? " + device.isDefaultBound());
+ if (bindingDevice.isDefaultBound()) {
+ addAppKey();
+ } else {
+ if (bindingDevice.getCompositionData() == null) {
+ this.getCompositionData();
+ } else {
+ onCompositionDataReceived(bindingDevice.getCompositionData());
+ }
+
+ }
+ }
+
+ public void clear() {
+ if (delayHandler != null) {
+ delayHandler.removeCallbacksAndMessages(null);
+ }
+ modelIndex = 0;
+ step = STEP_INIT;
+ this.bindingModels.clear();
+ }
+
+ private boolean isGattBearer() {
+ return bindingDevice != null && bindingDevice.getBearer() == BindingBearer.GattOnly;
+ }
+
+ private void getCompositionData() {
+ updateStep(STEP_GET_CPS);
+ onMeshMessagePrepared(new CompositionDataGetMessage(this.bindingDevice.getMeshAddress()));
+ }
+
+ private void addAppKey() {
+ log("add app key");
+ updateStep(STEP_APP_KEY_ADD);
+ AppKeyAddMessage command = new AppKeyAddMessage(this.bindingDevice.getMeshAddress());
+ command.setNetKeyIndex(this.netKeyIndex);
+ command.setAppKeyIndex(this.bindingDevice.getAppKeyIndex());
+ command.setAppKey(this.appKey);
+ onMeshMessagePrepared(command);
+ }
+
+ private void onMeshMessagePrepared(MeshMessage meshMessage) {
+ if (accessBridge != null) {
+ if (!isGattBearer()) {
+ meshMessage.setRetryCnt(8);
+ }
+ boolean isMessageSent = accessBridge.onAccessMessagePrepared(meshMessage, AccessBridge.MODE_BINDING);
+ if (!isMessageSent) {
+ onBindFail("binding message sent error");
+ }
+ }
+ }
+
+ private void bindNextModel() {
+
+ if (bindingModels.size() > modelIndex) {
+ BindingModel bindingModel = bindingModels.get(modelIndex);
+ int modelId = bindingModel.modelId;
+ ModelAppBindMessage command = new ModelAppBindMessage(bindingDevice.getMeshAddress());
+
+ int eleAdr = bindingDevice.getMeshAddress() + bindingModel.elementOffset;
+ command.setElementAddress(eleAdr);
+ command.setAppKeyIndex(bindingDevice.getAppKeyIndex());
+ command.setSigModel(bindingModel.sig);
+ command.setModelIdentifier(modelId);
+ log("bind next model: " + Integer.toHexString(modelId) + " at: " + Integer.toHexString(eleAdr));
+ onMeshMessagePrepared(command);
+ } else {
+ onBindSuccess();
+ }
+ }
+
+ private void updateStep(int step) {
+ log("upate step: " + step);
+ this.step = step;
+ }
+
+ private void onCompositionDataReceived(CompositionData compositionData) {
+ // for test , false
+ List modelsInCps = getAllModels(compositionData);
+ if (modelsInCps == null || modelsInCps.size() == 0) {
+ onBindFail("no models in composition data");
+ return;
+ }
+ this.bindingModels.clear();
+ this.modelIndex = 0;
+ if (bindingDevice.getModels() == null) {
+ this.bindingModels.addAll(modelsInCps);
+ } else {
+ // models filter
+ outer:
+ for (BindingModel bindingModel : modelsInCps) {
+ for (int modelId : bindingDevice.getModels()) {
+ if (bindingModel.modelId == modelId) {
+ this.bindingModels.add(bindingModel);
+ continue outer;
+ }
+ }
+ }
+ }
+
+ if (this.bindingModels.size() == 0) {
+ onBindFail("no target models found");
+ } else {
+
+ log("models prepared: " + this.bindingModels.size());
+ /*for (BindingModel bindingModel :
+ bindingModels) {
+ logMessage( "model - " + bindingModel.modelId);
+ }*/
+ bindingDevice.setCompositionData(compositionData);
+ addAppKey();
+ }
+ }
+
+ private List getAllModels(CompositionData compositionData) {
+ if (compositionData.elements == null) return null;
+
+ List models = new ArrayList<>();
+
+ int offset = 0;
+ for (CompositionData.Element ele : compositionData.elements) {
+ if (ele.sigModels != null) {
+ for (int modelId : ele.sigModels) {
+ if (!MeshSigModel.isConfigurationModel(modelId)) {
+ models.add(new BindingModel(modelId, offset, true));
+ }
+ }
+
+ }
+ if (ele.vendorModels != null) {
+ for (int modelId : ele.vendorModels) {
+ models.add(new BindingModel(modelId, offset, false));
+ }
+ }
+ offset++;
+ }
+
+ return models;
+ }
+
+ public void onMessageNotification(NotificationMessage message) {
+ Opcode opcode = Opcode.valueOf(message.getOpcode());
+ if (opcode == null) return;
+ switch (opcode) {
+ case COMPOSITION_DATA_STATUS:
+ if (step != STEP_GET_CPS) {
+ log("step not getting cps");
+ return;
+ }
+ CompositionData compositionData = ((CompositionDataStatusMessage) message.getStatusMessage()).getCompositionData();
+ onCompositionDataReceived(compositionData);
+ break;
+
+ case APPKEY_STATUS:
+ if (step != STEP_APP_KEY_ADD) {
+ log("step not app key adding");
+ return;
+ }
+
+ AppKeyStatusMessage appKeyStatusMessage = ((AppKeyStatusMessage) message.getStatusMessage());
+ if (appKeyStatusMessage.getStatus() == 0) {
+ log("app key add success");
+ if (bindingDevice.isDefaultBound()) {
+ log("default bound complete");
+ onBindSuccess();
+ } else {
+ updateStep(STEP_APP_KEY_BIND);
+ bindNextModel();
+ }
+ } else {
+ onBindFail("app key status error");
+ }
+
+ break;
+
+ case MODE_APP_STATUS:
+ if (step != STEP_APP_KEY_BIND) {
+ log("step not app key binding");
+ return;
+ }
+ ModelAppStatusMessage appStatus = ((ModelAppStatusMessage) message.getStatusMessage());
+ if (bindingModels.size() > modelIndex) {
+ final int modelId = bindingModels.get(modelIndex).modelId;
+ final boolean sig = bindingModels.get(modelIndex).sig;
+ if (modelId == appStatus.getModelIdentifier()) {
+ if (!sig || appStatus.getStatus() == 0) {
+ modelIndex++;
+ bindNextModel();
+ } else {
+ onBindFail("mode app status error");
+ }
+ } else {
+ log("model id error");
+ bindNextModel();
+ }
+ }
+ break;
+ }
+ }
+
+ public void onBindingCommandComplete(boolean success, int opcode, int rspMax, int rspCount) {
+ if (!success) {
+ onBindFail("binding command send fail");
+ }
+ }
+
+ private void onBindFail(String desc) {
+ log("binding fail: " + desc);
+ onBindingComplete();
+ onBindState(STATE_FAIL, desc);
+ }
+
+ private void onBindSuccess() {
+ onBindingComplete();
+ onBindState(STATE_SUCCESS, "binding success");
+ }
+
+ private void onBindingComplete() {
+ clear();
+ }
+
+ private void onBindState(int state, String desc) {
+ if (accessBridge != null) {
+ accessBridge.onAccessStateChanged(state, desc, AccessBridge.MODE_BINDING, null);
+ }
+ }
+
+ private class BindingModel {
+ int modelId;
+ int elementOffset;
+ boolean sig;
+
+ public BindingModel(int modelId, int offset, boolean sig) {
+ this.modelId = modelId;
+ this.elementOffset = offset;
+ this.sig = sig;
+ }
+ }
+
+ private Runnable bindingTimeoutTask = new Runnable() {
+ @Override
+ public void run() {
+ onBindFail("binding timeout");
+ }
+ };
+
+ private void log(String logInfo) {
+ log(logInfo, MeshLogger.LEVEL_DEBUG);
+ }
+
+ private void log(String logMessage, int level) {
+ MeshLogger.log(logMessage, LOG_TAG, level);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/BlobTransfer.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/BlobTransfer.java
new file mode 100644
index 00000000..f4221a84
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/BlobTransfer.java
@@ -0,0 +1,21 @@
+package com.telink.ble.mesh.core.access;
+
+public class BlobTransfer {
+ Direction direction = Direction.INITIATOR_TO_DISTRIBUTOR;
+
+ byte[] firmware;
+
+
+
+ enum Direction {
+ /**
+ * initiator to distributor
+ */
+ INITIATOR_TO_DISTRIBUTOR,
+
+ /**
+ * distributor to updating nodes
+ */
+ DISTRIBUTOR_TO_NODE
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FastProvisioningController.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FastProvisioningController.java
new file mode 100644
index 00000000..373520d5
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FastProvisioningController.java
@@ -0,0 +1,511 @@
+/********************************************************************************************************
+ * @file FastProvisioningController.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.access;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.message.NotificationMessage;
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.fastpv.MeshAddressStatusMessage;
+import com.telink.ble.mesh.core.message.fastpv.MeshConfirmRequestMessage;
+import com.telink.ble.mesh.core.message.fastpv.MeshGetAddressMessage;
+import com.telink.ble.mesh.core.message.fastpv.MeshProvisionCompleteMessage;
+import com.telink.ble.mesh.core.message.fastpv.MeshSetAddressMessage;
+import com.telink.ble.mesh.core.message.fastpv.MeshSetNetInfoMessage;
+import com.telink.ble.mesh.core.message.fastpv.ResetNetworkMessage;
+import com.telink.ble.mesh.entity.FastProvisioningConfiguration;
+import com.telink.ble.mesh.entity.FastProvisioningDevice;
+import com.telink.ble.mesh.foundation.MeshConfiguration;
+import com.telink.ble.mesh.util.Arrays;
+import com.telink.ble.mesh.util.MeshLogger;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+
+
+/**
+ * fast provisioning flow:
+ * 1. connect to unprovisioned device
+ * 2. send vendor command VD_MESH_RESET_NETWORK to 0xFFFF on proxy handle (user define)
+ * 3. reset provisioner mesh netKey/keyIndex and appKey/keyIndex ivIndex to default after 2000ms
+ * 4. send VD_MESH_ADDR_GET command to address 0xFFFF , pid and mac will response when device received command
+ * cache mesh address status until timeout
+ * 5. send VD_MESH_ADDR_SET command to default unicast address one by one
+ * 6. send VD_MESH_PROV_DATA_SET to 0xFFFF: setting network info
+ * 7. send VD_MESH_PROV_CONFIRM : if receive device response VD_MESH_PROV_CONFIRM_STS when it do not received network info,
+ * resend VD_MESH_PROV_DATA_SET
+ * 8. if no device response, send VD_MESH_PROV_COMPLETE to set network back
+ *
+ *
+ * Created by kee on 2019/9/26.
+ */
+public class FastProvisioningController {
+
+ private final String LOG_TAG = "FastProv";
+
+ /**
+ * 5 minutes
+ */
+ private static final int FLOW_TIMEOUT = 5 * 60 * 1000;
+
+ // provisioner delay after command delay
+ private static final int PROVISIONER_DELAY = 500;
+
+ /**
+ * mesh get address timeout
+ */
+ private static final int FAST_SCANNING_TIMEOUT = 3500;
+
+ /**
+ * confirm check timeout
+ */
+ private static final int CONFIRM_CHECK_TIMEOUT = 3000;
+
+ private static final int ROUND_MAX = 10;
+ /**
+ * opcode:
+ * #define VD_MESH_RESET_NETWORK 0xC5
+ * #define VD_MESH_ADDR_GET 0xC6
+ * #define VD_MESH_ADDR_GET_STS 0xC7
+ * #define VD_MESH_ADDR_SET 0xC8
+ * #define VD_MESH_ADDR_SET_STS 0xC9
+ * #define VD_MESH_PROV_DATA_SET 0xCA
+ * #define VD_MESH_PROV_CONFIRM 0xCB
+ * #define VD_MESH_PROV_CONFIRM_STS 0xCC
+ * #define VD_MESH_PROV_COMPLETE 0xCD
+ *
+ * FAST_PROV_IDLE,
+ * FAST_PROV_START,
+ * FAST_PROV_RESET_NETWORK,
+ * FAST_PROV_GET_ADDR,
+ * FAST_PROV_GET_ADDR_RETRY,
+ * FAST_PROV_SET_ADDR,
+ * FAST_PROV_NET_INFO,
+ * FAST_PROV_CONFIRM,
+ * FAST_PROV_CONFIRM_OK,
+ * FAST_PROV_COMPLETE,
+ * FAST_PROV_TIME_OUT,
+ */
+
+ public static final int STATE_IDLE = 0x10;
+
+ public static final int STATE_RESET_NETWORK = 0x11;
+
+ public static final int STATE_GET_ADDR = 0x12;
+
+ public static final int STATE_SET_ADDR = 0x13;
+
+ public static final int STATE_SET_ADDR_SUCCESS = 0x16;
+
+ public static final int STATE_SET_NET_INFO = 0x14;
+
+ public static final int STATE_CONFIRM = 0x15;
+
+
+ public static final int STATE_FAIL = 0x18;
+
+ public static final int STATE_SUCCESS = 0x19;
+
+
+ private int state;
+
+ private Handler delayHandler;
+
+ private AccessBridge accessBridge;
+
+ private FastProvisioningConfiguration configuration;
+
+ // cached address message
+ private ArrayList provisioningDeviceList = new ArrayList<>();
+
+ /**
+ * mesh setting index
+ * set device mesh address one by one
+ */
+ private int settingIndex;
+
+ /**
+ * origin mesh config
+ */
+ private MeshConfiguration originMeshConfiguration;
+
+ /**
+ * if need retry after
+ */
+ private boolean confirmRetryNeeded = false;
+
+ private static final int CONFIRM_RETRY_MAX = 5;
+
+ private int confirmRetryCnt = 0;
+
+ public FastProvisioningController(HandlerThread handlerThread) {
+ delayHandler = new Handler(handlerThread.getLooper());
+ }
+
+ public void register(AccessBridge accessBridge) {
+ this.accessBridge = accessBridge;
+ }
+
+ public FastProvisioningConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ public void init(FastProvisioningConfiguration configuration, MeshConfiguration meshConfiguration) {
+ this.configuration = configuration;
+ this.originMeshConfiguration = meshConfiguration;
+ }
+
+ public void begin() {
+ log("begin");
+ delayHandler.removeCallbacks(flowTimeoutTask);
+ delayHandler.postDelayed(flowTimeoutTask, FLOW_TIMEOUT);
+ resetNetwork();
+ }
+
+ public void clear() {
+ this.state = STATE_IDLE;
+ if (delayHandler != null) {
+ delayHandler.removeCallbacksAndMessages(null);
+ }
+ provisioningDeviceList.clear();
+ }
+
+ public void stop() {
+ if (this.state != STATE_IDLE) {
+ sendCompleteMessage();
+ }
+ clear();
+ }
+
+ private Runnable flowTimeoutTask = new Runnable() {
+ @Override
+ public void run() {
+ onFastProvisionComplete(false, "fast provision timeout");
+ }
+ };
+
+ /**
+ * reset network to default
+ */
+ private void resetNetwork() {
+
+ // send reset message by local network info
+ ResetNetworkMessage resetMessage = ResetNetworkMessage.getSimple(0xFFFF,
+ originMeshConfiguration.getDefaultAppKeyIndex(),
+ this.configuration.getResetDelay());
+ if (this.onMeshMessagePrepared(resetMessage)) {
+ // if reset message sent, start reset timer
+ onStateUpdate(STATE_RESET_NETWORK, "reset provisioner network", null);
+ delayHandler.removeCallbacks(resetNetworkTask);
+ delayHandler.postDelayed(resetNetworkTask, PROVISIONER_DELAY + configuration.getResetDelay());
+ } else {
+ onFastProvisionComplete(false, "reset command send err");
+ }
+ }
+
+ private Runnable resetNetworkTask = new Runnable() {
+ @Override
+ public void run() {
+ restartScanningTimeoutTask();
+ startFastScanning();
+ }
+ };
+
+ // get address
+ private void startFastScanning() {
+ onStateUpdate(STATE_GET_ADDR, "mesh get address", null);
+ MeshGetAddressMessage getAddressMessage = MeshGetAddressMessage.getSimple(0xFFFF, configuration.getDefaultAppKeyIndex(), ROUND_MAX, configuration.getScanningPid());
+ onMeshMessagePrepared(getAddressMessage);
+ }
+
+ private void restartScanningTimeoutTask() {
+ delayHandler.removeCallbacks(fastScanningTimeoutTask);
+ delayHandler.postDelayed(fastScanningTimeoutTask, FAST_SCANNING_TIMEOUT);
+ }
+
+ private Runnable fastScanningTimeoutTask = new Runnable() {
+ @Override
+ public void run() {
+ if (provisioningDeviceList.size() > 0) {
+ settingIndex = -1;
+ setNextMeshAddress();
+ } else {
+ onFastProvisionComplete(false, "no device found");
+ }
+ }
+ };
+
+ private void setNextMeshAddress() {
+ settingIndex++;
+ if (provisioningDeviceList.size() > settingIndex) {
+ FastProvisioningDevice provisioningDevice = provisioningDeviceList.get(settingIndex);
+ if (provisioningDevice != null) {
+ log(String.format("mesh set next address: mac -- %s originAddress -- %04X newAddress -- %04X index -- %02d",
+ Arrays.bytesToHexString(provisioningDevice.getMac()),
+ provisioningDevice.getOriginAddress(),
+ provisioningDevice.getNewAddress(), settingIndex));
+ onStateUpdate(STATE_SET_ADDR, "mesh set address", provisioningDevice);
+
+ MeshSetAddressMessage setAddressMessage = MeshSetAddressMessage.getSimple(
+ provisioningDevice.getOriginAddress(),
+ configuration.getDefaultAppKeyIndex(),
+ Arrays.reverse(provisioningDevice.getMac()),
+ provisioningDevice.getNewAddress()
+ );
+ onMeshMessagePrepared(setAddressMessage);
+ } else {
+ log("provisioning device not found");
+ }
+
+ } else {
+ log("all device set address complete");
+ confirmRetryCnt = 0;
+ setMeshNetInfo();
+ }
+ }
+
+ private void setMeshNetInfo() {
+ onStateUpdate(STATE_SET_NET_INFO, "mesh set net info", null);
+ byte[] netInfoData = getNetInfoData();
+ MeshSetNetInfoMessage setNetInfoMessage = MeshSetNetInfoMessage.getSimple(0xFFFF,
+ configuration.getDefaultAppKeyIndex(),
+ netInfoData);
+ onMeshMessagePrepared(setNetInfoMessage);
+
+ sendConfirmRequest();
+ }
+
+ private void sendConfirmRequest() {
+ onStateUpdate(STATE_CONFIRM, "fast provision confirming", null);
+ confirmRetryNeeded = false;
+ MeshConfirmRequestMessage confirmRequestMessage = MeshConfirmRequestMessage.getSimple(0xFFFF, configuration.getDefaultAppKeyIndex());
+ onMeshMessagePrepared(confirmRequestMessage);
+ delayHandler.postDelayed(confirmCheckTimeoutTask, CONFIRM_CHECK_TIMEOUT);
+ }
+
+ private Runnable confirmCheckTimeoutTask = new Runnable() {
+ @Override
+ public void run() {
+ if (confirmRetryNeeded) {
+ confirmRetryCnt++;
+ if (confirmRetryCnt > CONFIRM_RETRY_MAX) {
+ onFastProvisionComplete(false, "confirm check retry max");
+ } else {
+ setMeshNetInfo();
+// sendConfirmRequest();
+ }
+ } else {
+ onFastProvisionComplete(true, "confirm check success");
+ }
+ }
+ };
+
+ //
+
+ /**
+ * @param success true: no confirm response, all device provision success
+ * false: other error
+ */
+ private void onFastProvisionComplete(final boolean success, String desc) {
+ log("complete: " + desc + " success?" + success);
+ sendCompleteMessage();
+ delayHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ clear();
+ onStateUpdate(success ? STATE_SUCCESS : STATE_FAIL, "fast provision complete", null);
+ }
+ }, PROVISIONER_DELAY + configuration.getResetDelay());
+ }
+
+ private void sendCompleteMessage() {
+ MeshProvisionCompleteMessage completeMessage = MeshProvisionCompleteMessage.getSimple(0xFFFF,
+ configuration.getDefaultAppKeyIndex(),
+ configuration.getResetDelay());
+ onMeshMessagePrepared(completeMessage);
+ }
+
+ private boolean onMeshMessagePrepared(MeshMessage meshMessage) {
+ log("mesh message prepared: " + meshMessage.getClass().getSimpleName()
+ + String.format(" opcode: 0x%04X -- dst: 0x%04X", meshMessage.getOpcode(), meshMessage.getDestinationAddress()));
+ if (accessBridge != null) {
+ boolean isMessageSent = accessBridge.onAccessMessagePrepared(meshMessage, AccessBridge.MODE_FIRMWARE_UPDATING);
+ if (!isMessageSent) {
+ log("message send error");
+ }
+ return isMessageSent;
+ }
+ return false;
+ }
+
+ private int getProvisioningMeshAddress(int pid) {
+ int elementCount = configuration.getElementCount(pid);
+ if (elementCount != 0) {
+ int address = configuration.getProvisioningIndex();
+ if (MeshUtils.validUnicastAddress(address)) {
+ configuration.increaseProvisioningIndex(elementCount);
+ return address;
+ } else {
+ log("invalid address", MeshLogger.LEVEL_WARN);
+ }
+ } else {
+ log("pid not found", MeshLogger.LEVEL_WARN);
+ }
+ return 0;
+ }
+
+ public void onFastProvisioningCommandComplete(boolean success, int opcode, int rspMax, int rspCount) {
+
+ if (opcode == Opcode.VD_MESH_ADDR_SET.value && state == STATE_SET_ADDR) {
+ if (!success) {
+ setNextMeshAddress();
+ }
+ }
+
+ }
+
+
+ public void onMessageNotification(NotificationMessage message) {
+ Opcode opcode = Opcode.valueOf(message.getOpcode());
+ log("message notification: " + opcode);
+ if (opcode == null) return;
+ switch (opcode) {
+ case VD_MESH_ADDR_GET_STS:
+ if (state == STATE_GET_ADDR) {
+
+ MeshAddressStatusMessage statusMessage = (MeshAddressStatusMessage) message.getStatusMessage();
+ int originAddress = message.getSrc();
+ int pid = statusMessage.getPid();
+ log("device address notify: " + Arrays.bytesToHexString(statusMessage.getMac()));
+ int newAddress = getProvisioningMeshAddress(pid);
+ if (newAddress != 0) {
+ int elementCount = configuration.getElementCount(pid);
+ FastProvisioningDevice fastProvisioningDevice = new FastProvisioningDevice(
+ originAddress,
+ newAddress,
+ pid,
+ elementCount,
+ statusMessage.getMac());
+ if (!provisioningDeviceList.contains(fastProvisioningDevice)) {
+ provisioningDeviceList.add(fastProvisioningDevice);
+ restartScanningTimeoutTask();
+ } else {
+ log("provisioning device exists: " + Arrays.bytesToHexString(statusMessage.getMac()));
+ }
+ }
+
+ }
+
+
+ break;
+
+ case VD_MESH_ADDR_SET_STS: {
+ if (state == STATE_SET_ADDR) {
+ int srcAdr = message.getSrc();
+ FastProvisioningDevice device = getProvisioningDeviceByAddress(srcAdr);
+ if (device != null) {
+ onStateUpdate(STATE_SET_ADDR_SUCCESS, "device set address success", device);
+ setNextMeshAddress();
+ }
+ }
+ }
+
+ break;
+
+ case VD_MESH_PROV_CONFIRM_STS: {
+ if (state == STATE_CONFIRM) {
+ confirmRetryNeeded = true;
+ }
+ }
+ break;
+ }
+ }
+
+
+ private FastProvisioningDevice getProvisioningDeviceByAddress(int meshAddress) {
+ for (FastProvisioningDevice device : provisioningDeviceList) {
+ if (device.getOriginAddress() == meshAddress) {
+ return device;
+ }
+ }
+ return null;
+ }
+
+ private void onStateUpdate(int state, String desc, Object obj) {
+ this.state = state;
+ if (accessBridge != null) {
+ accessBridge.onAccessStateChanged(state, desc, AccessBridge.MODE_FAST_PROVISION, obj);
+ }
+ }
+
+ private void log(String logMessage) {
+ log(logMessage, MeshLogger.LEVEL_DEBUG);
+ }
+
+ private void log(String logMessage, int level) {
+ MeshLogger.log(logMessage, LOG_TAG, level);
+ }
+
+ public byte[] getNetInfoData() {
+
+ byte[] netKey = originMeshConfiguration.networkKey;
+ int netKeyIndex = originMeshConfiguration.netKeyIndex;
+ int appKeyIndex = originMeshConfiguration.getDefaultAppKeyIndex();
+ byte[] appKey = originMeshConfiguration.getDefaultAppKey();
+ if (appKey == null) {
+ throw new RuntimeException("app key not found!");
+ }
+
+ int ivIndex = originMeshConfiguration.ivIndex;
+ byte ivUpdateFlag = 0;
+
+
+ byte[] pvData = new byte[25];
+ System.arraycopy(netKey, 0, pvData, 0, 16);
+
+ // key index : little-endian
+ pvData[16] = (byte) (netKeyIndex & 0xFF);
+ pvData[17] = (byte) ((netKeyIndex >> 8) & 0xFF);
+ // iv update flag
+ pvData[18] = ivUpdateFlag;
+
+ // iv index : big-endian
+ pvData[19] = (byte) ((ivIndex >> 24) & 0xFF);
+ pvData[20] = (byte) ((ivIndex >> 16) & 0xFF);
+ pvData[21] = (byte) ((ivIndex >> 8) & 0xFF);
+ pvData[22] = (byte) ((ivIndex) & 0xFF);
+ // ignore address
+ // pvData[23] = (byte) (adr & 0xFF);
+ // pvData[24] = (byte) ((adr >> 8) & 0xFF);
+
+ int netAppKeyIndex = (netKeyIndex & 0x0FFF) | ((appKeyIndex & 0x0FFF) << 12);
+ byte[] indexesBuf = MeshUtils.integer2Bytes(netAppKeyIndex, 3, ByteOrder.LITTLE_ENDIAN);
+ return ByteBuffer.allocate(25 + 19).order(ByteOrder.LITTLE_ENDIAN).put(pvData)
+ .put(indexesBuf)
+ .put(appKey).array();
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FirmwareUpdateDistributor.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FirmwareUpdateDistributor.java
new file mode 100644
index 00000000..3cebf139
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FirmwareUpdateDistributor.java
@@ -0,0 +1,7 @@
+package com.telink.ble.mesh.core.access;
+
+public abstract class FirmwareUpdateDistributor {
+ abstract void startDistribution();
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FirmwareUpdateInitiator.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FirmwareUpdateInitiator.java
new file mode 100644
index 00000000..ecc158fd
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FirmwareUpdateInitiator.java
@@ -0,0 +1,43 @@
+package com.telink.ble.mesh.core.access;
+
+import com.telink.ble.mesh.core.message.firmwaredistribution.FDCapabilitiesGetMessage;
+
+/**
+ *
+ */
+public class FirmwareUpdateInitiator {
+
+
+ /**
+ *
+ */
+// void getDistCap(int );
+
+ /**
+ * firmware distribution capabilities get
+ */
+ void fdCapGet(int distributorAddress, int appKeyIndex){
+
+ }
+
+ /**
+ * firmware update information get
+ */
+ private void fwUpdateInfoGet() {
+
+ }
+
+ /**
+ * firmware update firmware metadata check
+ */
+ private void fwUpdateFwMetadataCheck() {
+
+ }
+
+ /**
+ * firmware distribution receivers add
+ */
+ private void fwDistributionReceiversAdd() {
+
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FirmwareUpdatingController.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FirmwareUpdatingController.java
new file mode 100644
index 00000000..ad8070db
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/FirmwareUpdatingController.java
@@ -0,0 +1,987 @@
+/********************************************************************************************************
+ * @file FirmwareUpdatingController.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.access;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.message.MeshSigModel;
+import com.telink.ble.mesh.core.message.NotificationMessage;
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.config.ConfigStatus;
+import com.telink.ble.mesh.core.message.config.ModelSubscriptionSetMessage;
+import com.telink.ble.mesh.core.message.config.ModelSubscriptionStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareMetadataCheckMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareMetadataStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareUpdateApplyMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareUpdateCancelMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareUpdateGetMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareUpdateInfoGetMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareUpdateInfoStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareUpdateStartMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareUpdateStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatePhase;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdateStatus;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobBlockGetMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobBlockStartMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobBlockStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobChunkTransferMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobInfoGetMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobInfoStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobTransferGetMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobTransferStartMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobTransferStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.TransferStatus;
+import com.telink.ble.mesh.core.networking.NetworkingController;
+import com.telink.ble.mesh.entity.FirmwareUpdateConfiguration;
+import com.telink.ble.mesh.entity.MeshUpdatingDevice;
+import com.telink.ble.mesh.util.MeshLogger;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+
+/**
+ * Mesh firmware updating
+ * Created by kee on 2020/04/13.
+ */
+public class FirmwareUpdatingController {
+
+ private final String LOG_TAG = "FwUpdate";
+
+ /**
+ * all complete, fail or success
+ */
+ public static final int STATE_SUCCESS = 0x00;
+
+ /**
+ * chunks sending progress
+ */
+ public static final int STATE_PROGRESS = 0x01;
+
+ /**
+ * device succeed when apply status success
+ */
+ public static final int STATE_DEVICE_SUCCESS = 0x02;
+
+ /**
+ * device failed at every step status err
+ */
+ public static final int STATE_DEVICE_FAIL = 0x03;
+
+ /**
+ * mesh updating flow failed
+ */
+ public static final int STATE_FAIL = 0x04;
+
+
+ /**
+ * params check err
+ */
+ public static final int STATE_STOPPED = 0x05;
+
+
+ /**
+ * prepare complete when STEP_BLOB_TRANSFER_START sent success
+ */
+ public static final int STATE_PREPARED = 0x06;
+
+ /**
+ * get firmware info err
+ */
+// public static final int STATE_ACTION_EXECUTE_FAIL = 0x05;
+
+ /**
+ * initial
+ */
+ private static final int STEP_INITIAL = 0;
+
+ /**
+ * set subscription at firmware-updating-model
+ */
+ private static final int STEP_SET_SUBSCRIPTION = 1;
+
+ /**
+ * get firmware information
+ */
+ private static final int STEP_GET_FIRMWARE_INFO = 2;
+
+ /**
+ * check firmware metadata
+ */
+ private static final int STEP_METADATA_CHECK = 3;
+
+ /**
+ * firmware update start
+ */
+ private static final int STEP_UPDATE_START = 4;
+
+ /**
+ * blob transfer get
+ */
+ private static final int STEP_BLOB_TRANSFER_GET = 5;
+
+ /**
+ * get blob info
+ */
+ private static final int STEP_GET_BLOB_INFO = 6;
+
+ /**
+ * blob transfer start
+ */
+ private static final int STEP_BLOB_TRANSFER_START = 7;
+
+ /**
+ * blob block transfer start
+ */
+ private static final int STEP_BLOB_BLOCK_TRANSFER_START = 8;
+
+ /**
+ * sending chunk data
+ */
+ private static final int STEP_BLOB_CHUNK_SENDING = 9;
+
+ /**
+ * get block
+ *
+ * @see Opcode#BLOB_BLOCK_STATUS
+ */
+ private static final int STEP_GET_BLOB_BLOCK = 10;
+
+
+ /**
+ * get firmware update after block sent complete
+ */
+ private static final int STEP_UPDATE_GET = 11;
+
+ /**
+ * firmware update apply
+ */
+ private static final int STEP_UPDATE_APPLY = 12;
+
+ /**
+ * all complete
+ */
+ private static final int STEP_UPDATE_COMPLETE = 13;
+
+ /**
+ * manual stopping mesh updating flow
+ */
+ private static final int STEP_UPDATE_ABORTING = -1;
+
+ /**
+ * step
+ */
+ private int step = STEP_INITIAL;
+
+ /**
+ * node address | ignore
+ */
+ private List nodes;
+
+// private int[] nodeAddresses;
+
+ /**
+ * group address for subscription
+ */
+ private int groupAddress;
+
+ /**
+ * app key index that updating model bound with
+ */
+ private int appKeyIndex;
+
+ /**
+ * operation index
+ */
+ private int nodeIndex;
+
+// private int companyId;
+
+// private int firmwareId;
+
+ private long blobId;
+
+
+ // firmware[2-5] + [0, 0, 0, 0]
+ private byte[] metadata = new byte[8];
+
+ private int metadataIndex = 0;
+
+ private MeshFirmwareParser firmwareParser = new MeshFirmwareParser();
+
+ private byte[] firmwareData;
+
+ /**
+ * received missing chunk number
+ */
+ private ArrayList missingChunks = new ArrayList<>();
+
+ private int missingChunkIndex = 0;
+
+ /**
+ * mix format : mix all format received after checkMissingChunks {@link #checkMissingChunks()}
+ */
+ private int mixFormat = -1;
+
+ private Handler delayHandler;
+
+ private AccessBridge accessBridge;
+
+ /**
+ * update only direct connected device
+ */
+ private boolean isGattMode = false;
+
+ private int gattAddress = -1;
+
+ // check if last chunk in block needs segmentation
+ private int dleLength = 11;
+ // for missing test
+ boolean test = true;
+
+ public FirmwareUpdatingController(HandlerThread handlerThread) {
+ delayHandler = new Handler(handlerThread.getLooper());
+ }
+
+ public void register(AccessBridge accessBridge) {
+ this.accessBridge = accessBridge;
+ }
+
+ /**
+ * ignore distribution start action
+ *
+ * 1. get all nodes's firmware information ->
+ * 2. subscribe target group address
+ * 3. distribution start (ignore)
+ * 4. send block
+ */
+ public void begin(FirmwareUpdateConfiguration configuration) {
+ if (configuration == null) {
+ onUpdatingFail(STATE_FAIL, "updating params null");
+ return;
+ }
+ test = true;
+ this.isGattMode = configuration.isSingleAndDirect();
+ this.dleLength = configuration.getDleLength();
+ this.firmwareData = configuration.getFirmwareData();
+ if (firmwareData.length < 6) {
+ return;
+ }
+ this.metadata = configuration.getMetadata();
+
+ // reset when device chunk size received
+// this.firmwareParser.reset(configuration.getFirmwareData());
+ log(" config -- " + configuration.toString());
+ log("isGattMode? " + isGattMode);
+ this.appKeyIndex = configuration.getAppKeyIndex();
+ this.groupAddress = configuration.getGroupAddress();
+ this.nodes = configuration.getUpdatingDevices();
+ this.blobId = configuration.getBlobId();
+ this.nodeIndex = 0;
+ if (nodes != null && nodes.size() != 0) {
+
+ /*if (this.isGattMode){
+ this.step = STEP_GET_FIRMWARE_INFO;
+ }else {
+ this.step = STEP_SET_SUBSCRIPTION;
+ }*/
+ if (this.isGattMode) {
+ this.gattAddress = this.nodes.get(0).getMeshAddress();
+ }
+ this.step = STEP_SET_SUBSCRIPTION;
+ executeUpdatingAction();
+ } else {
+ onUpdatingFail(STATE_FAIL, "params err when action begin");
+ }
+ }
+
+ public void clear() {
+ if (delayHandler != null) {
+ delayHandler.removeCallbacksAndMessages(null);
+ }
+ step = STEP_INITIAL;
+ }
+
+ public void stop() {
+ if (step == STEP_INITIAL) {
+ log("mesh updating not running");
+ } else {
+ delayHandler.removeCallbacksAndMessages(null);
+ delayHandler.postDelayed(stoppingCheckTask, 5 * 1000);
+ step = STEP_UPDATE_ABORTING;
+ FirmwareUpdateCancelMessage firmwareUpdateCancelMessage = FirmwareUpdateCancelMessage.getSimple(0xFFFF, appKeyIndex);
+ onMeshMessagePrepared(firmwareUpdateCancelMessage);
+ }
+ }
+
+ private Runnable stoppingCheckTask = new Runnable() {
+ @Override
+ public void run() {
+ onUpdatingStopped();
+ }
+ };
+
+ private void sendChunks() {
+ byte[] chunkData = firmwareParser.nextChunk();
+ final int chunkIndex = firmwareParser.currentChunkIndex();
+ /*if (test) {
+ if (firmwareParser.currentChunkIndex() == 2) {
+ byte[] missingChunkData = firmwareParser.nextChunk();
+ test = false;
+ }
+ }*/
+ if (chunkData != null) {
+ validateUpdatingProgress();
+// int chunkNumber = firmwareParser.currentChunkIndex();
+
+ BlobChunkTransferMessage blobChunkTransferMessage = generateChunkTransferMessage(chunkIndex, chunkData);
+
+ log("next chunk transfer msg: " + blobChunkTransferMessage.toString());
+
+ onMeshMessagePrepared(blobChunkTransferMessage);
+ if (!isGattMode) {
+ delayHandler.postDelayed(chunkSendingTask, getChunkSendingInterval());
+ } else {
+ int len = chunkData.length + 3;
+ boolean segment = len > dleLength;
+ if (!segment) {
+ sendChunks();
+ }
+ }
+ } else {
+ log("chunks sent complete at: block -- " + firmwareParser.currentBlockIndex()
+ + " chunk -- " + firmwareParser.currentChunkIndex());
+ checkMissingChunks();
+ }
+ }
+
+
+ private void checkMissingChunks() {
+ log("check missing chunks");
+ missingChunks.clear();
+ mixFormat = -1;
+ step = STEP_GET_BLOB_BLOCK;
+ nodeIndex = 0;
+ executeUpdatingAction();
+ }
+
+
+ private void resendMissingChunks() {
+ if (missingChunkIndex >= missingChunks.size()) {
+ // all missing chunk sent
+ log("all missing chunks sent complete: " + missingChunkIndex);
+ checkMissingChunks();
+ } else {
+ int chunkNumber = missingChunks.get(missingChunkIndex);
+ log("missing chunks: " + chunkNumber);
+ byte[] chunkData = firmwareParser.chunkAt(chunkNumber);
+ if (chunkData == null) {
+ log("chunk index overflow when resending chunk: " + chunkNumber);
+ return;
+ }
+ BlobChunkTransferMessage blobChunkTransferMessage = generateChunkTransferMessage(chunkNumber, chunkData);
+ onMeshMessagePrepared(blobChunkTransferMessage);
+ delayHandler.postDelayed(missingChunkSendingTask, getChunkSendingInterval());
+ }
+ }
+
+ /*private long getChunkSendingInterval() {
+ // relay 320 ms
+
+ long interval = firmwareParser.getChunkSize() / 12 * NetworkingController.NETWORKING_INTERVAL + NetworkingController.NETWORKING_INTERVAL;
+ final long min = 5 * 1000;
+ interval = Math.max(min, interval);
+ log("chunk sending interval: " + interval);
+ return interval;
+ }*/
+
+ private long getChunkSendingInterval() {
+ // relay 320 ms
+
+ if (isGattMode) {
+ return 100;
+ }
+
+ // 12
+ // 208
+ // chunk size + opcode(1 byte)
+ final int chunkMsgLen = firmwareParser.getChunkSize() + 1;
+ final int unsegLen = NetworkingController.unsegmentedAccessLength;
+ final int segLen = unsegLen + 1;
+ int segmentCnt = chunkMsgLen == unsegLen ? 1 : (chunkMsgLen % segLen == 0 ? chunkMsgLen / segLen : (chunkMsgLen / segLen + 1));
+ long interval = segmentCnt * NetworkingController.NETWORKING_INTERVAL;
+// final long min = 5 * 1000;
+ // use 5000 when DLE disabled, use 300 when DLE enabled
+ final long min = unsegLen == NetworkingController.UNSEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH_DEFAULT ? 5 * 1000 : 300;
+ interval = Math.max(min, interval);
+ log("chunk sending interval: " + interval);
+ return interval;
+ }
+
+ private Runnable missingChunkSendingTask = new Runnable() {
+ @Override
+ public void run() {
+ missingChunkIndex++;
+ resendMissingChunks();
+ }
+ };
+
+ private Runnable chunkSendingTask = new Runnable() {
+ @Override
+ public void run() {
+ sendChunks();
+ }
+ };
+
+ private BlobChunkTransferMessage generateChunkTransferMessage(int chunkNumber, byte[] chunkData) {
+ int address = isGattMode ? gattAddress : groupAddress;
+ return BlobChunkTransferMessage.getSimple(address, appKeyIndex, chunkNumber, chunkData);
+ }
+
+
+ /**
+ * execute updating actions(one by one && step by step)
+ * one device by one device
+ * if all devices executed, then next step
+ */
+ // draft feature
+ private void executeUpdatingAction() {}
+
+
+ private void removeFailedDevices() {
+ Iterator iterator = nodes.iterator();
+ MeshUpdatingDevice updatingNode;
+ while (iterator.hasNext()) {
+ updatingNode = iterator.next();
+ if (updatingNode.getState() == MeshUpdatingDevice.STATE_FAIL) {
+ iterator.remove();
+ }
+ }
+ }
+
+ private void onMeshMessagePrepared(MeshMessage meshMessage) {
+ meshMessage.setRetryCnt(10);
+ log("mesh message prepared: " + meshMessage.getClass().getSimpleName()
+ + String.format(" opcode: 0x%04X -- dst: 0x%04X", meshMessage.getOpcode(), meshMessage.getDestinationAddress()));
+ if (accessBridge != null) {
+ boolean isMessageSent = accessBridge.onAccessMessagePrepared(meshMessage, AccessBridge.MODE_FIRMWARE_UPDATING);
+ if (!isMessageSent) {
+
+ if (meshMessage instanceof BlobChunkTransferMessage) {
+ onUpdatingFail(-1, "chunk transfer message sent error");
+ } else {
+ if (nodes.size() > nodeIndex) {
+ onDeviceFail(nodes.get(nodeIndex), String.format("mesh message sent error -- opcode: 0x%04X", meshMessage.getOpcode()));
+ }
+ }
+
+ }
+ }
+ }
+
+ public void onSegmentComplete(boolean success) {
+ if (isGattMode && step == STEP_BLOB_CHUNK_SENDING) {
+ if (success) {
+ sendChunks();
+ } else {
+ onUpdatingFail(STATE_FAIL, "chunk send fail -- segment message send fail");
+ }
+ }
+ }
+
+ // 在 发包过程中 retry导致的收多次
+ public void onMessageNotification(NotificationMessage message) {
+ Opcode opcode = Opcode.valueOf(message.getOpcode());
+ log("message notification: " + opcode);
+ if (step == STEP_INITIAL) {
+ log("notification when idle");
+ return;
+ }
+ if (opcode == null) return;
+ final int src = message.getSrc();
+
+ if (nodes.size() <= nodeIndex) {
+ log("node index overflow", MeshLogger.LEVEL_WARN);
+ return;
+ }
+
+ if (nodes.get(nodeIndex).getMeshAddress() != src) {
+ log("unexpected notification src", MeshLogger.LEVEL_WARN);
+ return;
+ }
+
+ switch (opcode) {
+
+ case FIRMWARE_UPDATE_INFORMATION_STATUS:
+ onFirmwareInfoStatus((FirmwareUpdateInfoStatusMessage) message.getStatusMessage());
+ break;
+
+ case CFG_MODEL_SUB_STATUS:
+ onSubscriptionStatus((ModelSubscriptionStatusMessage) message.getStatusMessage());
+ break;
+
+ case BLOB_INFORMATION_STATUS:
+ onBlobInfoStatus((BlobInfoStatusMessage) message.getStatusMessage());
+ break;
+
+ case FIRMWARE_UPDATE_FIRMWARE_METADATA_STATUS:
+ onMetadataStatus((FirmwareMetadataStatusMessage) message.getStatusMessage());
+ break;
+
+ case FIRMWARE_UPDATE_STATUS:
+ onFirmwareUpdateStatus((FirmwareUpdateStatusMessage) message.getStatusMessage());
+ break;
+
+ case BLOB_TRANSFER_STATUS:
+ onBlobTransferStatus((BlobTransferStatusMessage) message.getStatusMessage());
+ break;
+
+
+ /*case BLOB_BLOCK_STATUS: OBJ_BLOCK_TRANSFER_STATUS:
+ onBlockTransferStatus((BlobBlockStatusMessage) message.getStatusMessage());
+ break;*/
+
+ case BLOB_BLOCK_STATUS:
+ onBlobBlockStatus(message);
+ break;
+ }
+ }
+
+ private void onFirmwareInfoStatus(FirmwareUpdateInfoStatusMessage firmwareInfoStatusMessage) {
+ log("firmware info status: " + firmwareInfoStatusMessage.toString());
+ if (step != STEP_GET_FIRMWARE_INFO) {
+ log("not at STEP_GET_FIRMWARE_INFO");
+ return;
+ }
+
+ int firstIndex = firmwareInfoStatusMessage.getFirstIndex();
+ int companyId = firmwareInfoStatusMessage.getListCount();
+ List firmwareInformationList
+ = firmwareInfoStatusMessage.getFirmwareInformationList();
+ nodeIndex++;
+ executeUpdatingAction();
+ }
+
+ private void onSubscriptionStatus(ModelSubscriptionStatusMessage subscriptionStatusMessage) {
+ log("subscription status: " + subscriptionStatusMessage.toString());
+ if (step != STEP_SET_SUBSCRIPTION) {
+ log("not at STEP_SET_SUBSCRIPTION");
+ return;
+ }
+ if (subscriptionStatusMessage.getStatus() != ConfigStatus.SUCCESS.code) {
+ onDeviceFail(nodes.get(nodeIndex), "grouping status err " + subscriptionStatusMessage.getStatus());
+ }
+ nodeIndex++;
+ executeUpdatingAction();
+ }
+
+
+ /**
+ * response of {@link BlobInfoStatusMessage}
+ */
+ private void onBlobInfoStatus(BlobInfoStatusMessage objectInfoStatusMessage) {
+
+
+ log("object info status: " + objectInfoStatusMessage.toString());
+ if (step != STEP_GET_BLOB_INFO) {
+ log("not at STEP_GET_BLOB_INFO");
+ return;
+ }
+ int blockSize = (int) Math.pow(2, objectInfoStatusMessage.getMaxBlockSizeLog());
+ int chunkSize = objectInfoStatusMessage.getMaxChunkSize();
+ log("chunk size : " + chunkSize + " block size: " + blockSize);
+ this.firmwareParser.reset(firmwareData, blockSize, chunkSize);
+ nodeIndex++;
+ executeUpdatingAction();
+ }
+
+ private void onMetadataStatus(FirmwareMetadataStatusMessage metadataStatusMessage) {
+ UpdateStatus status = UpdateStatus.valueOf(metadataStatusMessage.getStatus());
+ if (step == STEP_METADATA_CHECK) {
+ if (status != UpdateStatus.SUCCESS) {
+ onDeviceFail(nodes.get(nodeIndex), "metadata check error: " + status.desc);
+ }
+ nodeIndex++;
+ executeUpdatingAction();
+ } else {
+ log("metadata received when not checking", MeshLogger.LEVEL_WARN);
+ }
+ }
+
+ /**
+ * response of {@link FirmwareUpdateStartMessage} , {@link FirmwareUpdateGetMessage}
+ * and {@link FirmwareUpdateApplyMessage}
+ */
+ private void onFirmwareUpdateStatus(FirmwareUpdateStatusMessage firmwareUpdateStatusMessage) {
+
+ log("firmware update status: " + " at: " + getStepDesc(step)
+ + " -- " + firmwareUpdateStatusMessage.toString());
+ final UpdateStatus status = UpdateStatus.valueOf(firmwareUpdateStatusMessage.getStatus() & 0xFF);
+
+ if (status != UpdateStatus.SUCCESS) {
+ onDeviceFail(nodes.get(nodeIndex), "firmware update status err");
+ } else {
+ final int step = this.step;
+ /*boolean pass = (step == STEP_UPDATE_START && phase == FirmwareUpdateStatusMessage.PHASE_IN_PROGRESS)
+ || (step == STEP_UPDATE_GET && phase == FirmwareUpdateStatusMessage.PHASE_READY)
+ || (step == STEP_UPDATE_APPLY && phase == FirmwareUpdateStatusMessage.PHASE_IDLE);*/
+ boolean pass = true;
+ if (!pass) {
+ onDeviceFail(nodes.get(nodeIndex), "firmware update phase err");
+ } else {
+ final UpdatePhase phase = UpdatePhase.valueOf(firmwareUpdateStatusMessage.getPhase() & 0xFF);
+ if (step == STEP_UPDATE_APPLY) {
+ if (phase == UpdatePhase.VERIFICATION_SUCCESS
+ || phase == UpdatePhase.APPLYING_UPDATE) {
+ onDeviceSuccess(nodes.get(nodeIndex));
+ } else {
+ onDeviceFail(nodes.get(nodeIndex), "phase error when update apply");
+ }
+ }
+ }
+ }
+ nodeIndex++;
+ executeUpdatingAction();
+
+ }
+
+ /**
+ * response of {@link BlobTransferStartMessage}
+ */
+ private void onBlobTransferStatus(BlobTransferStatusMessage transferStatusMessage) {
+ log("object transfer status: " + transferStatusMessage.toString());
+ if (step == STEP_BLOB_TRANSFER_START || step == STEP_BLOB_TRANSFER_GET) {
+ UpdateStatus status = UpdateStatus.valueOf(transferStatusMessage.getStatus());
+
+ if (status != UpdateStatus.SUCCESS) {
+ onDeviceFail(nodes.get(nodeIndex), "object transfer status err");
+ }
+ nodeIndex++;
+ executeUpdatingAction();
+ }
+
+ /*byte status = transferStatusMessage.getStatus();
+ if (status != ObjectTransferStatusMessage.STATUS_READY
+ && status != ObjectTransferStatusMessage.STATUS_BUSY_ACTIVE) {
+ onDeviceFail(nodes.get(nodeIndex), "object transfer status err");
+ }*/
+
+ }
+
+ /**
+ * response of {@link BlobBlockStartMessage} before start chunks sending
+ */
+ private void onBlockTransferStatus(BlobBlockStatusMessage blockTransferStatusMessage) {
+ log("block transfer status: " + blockTransferStatusMessage.toString());
+ int status = blockTransferStatusMessage.getStatus();
+ /*if (status != ObjectBlockTransferStatusMessage.STATUS_ACCEPTED) {
+ onDeviceFail(nodes.get(nodeIndex), "object block transfer status err");
+ }*/
+ nodeIndex++;
+ executeUpdatingAction();
+ }
+
+ /**
+ * response of BLOCK_GET
+ * {@link #checkMissingChunks()}
+ * {@link BlobBlockStartMessage}
+ */
+ private void onBlobBlockStatus(NotificationMessage message) {
+ if (step != STEP_GET_BLOB_BLOCK && step != STEP_BLOB_BLOCK_TRANSFER_START) {
+ return;
+ }
+ BlobBlockStatusMessage blobBlockStatusMessage = (BlobBlockStatusMessage) message.getStatusMessage();
+ log("block status: " + blobBlockStatusMessage.toString());
+ int srcAddress = message.getSrc();
+ TransferStatus transferStatus = TransferStatus.valueOf(blobBlockStatusMessage.getStatus() & 0xFF);
+ if (transferStatus != TransferStatus.SUCCESS) {
+ onDeviceFail(nodes.get(nodeIndex), "block status err");
+ } else {
+ // only check chunk missing when STEP_GET_BLOB_BLOCK
+ if (step == STEP_GET_BLOB_BLOCK) {
+ int format = blobBlockStatusMessage.getFormat();
+
+ mixFormat(format);
+
+ switch (format) {
+ case BlobBlockStatusMessage.FORMAT_ALL_CHUNKS_MISSING:
+ log(String.format("all chunks missing: %04X", srcAddress));
+ break;
+
+ case BlobBlockStatusMessage.FORMAT_NO_CHUNKS_MISSING:
+ log(String.format("no chunks missing: %04X", srcAddress));
+ break;
+
+ case BlobBlockStatusMessage.FORMAT_SOME_CHUNKS_MISSING:
+ mixMissingChunks(blobBlockStatusMessage.getMissingChunks());
+ break;
+
+ case BlobBlockStatusMessage.FORMAT_ENCODED_MISSING_CHUNKS:
+ mixMissingChunks(blobBlockStatusMessage.getEncodedMissingChunks());
+ break;
+ }
+ }
+ }
+
+ nodeIndex++;
+ executeUpdatingAction();
+
+
+ /*switch (objectBlockStatusMessage.getStatus()) {
+ case ObjectBlockStatusMessage.STATUS_ALL_CHUNKS_RECEIVED:
+ // all chunks data received
+ log("no chunks missing");
+ nodeIndex++;
+ executeUpdatingAction();
+ break;
+
+ case ObjectBlockStatusMessage.STATUS_NOT_ALL_CHUNKS_RECEIVED:
+ // chunk missing
+ int[] missingChunksList = objectBlockStatusMessage.getMissingChunksList();
+ if (missingChunksList != null) {
+ for (int chunkNum : missingChunksList) {
+ missingChunks.add(chunkNum);
+ }
+ nodeIndex++;
+ executeUpdatingAction();
+ } else {
+ log("missing chunk data not found at status: " + objectBlockStatusMessage.getStatus());
+ }
+ break;
+
+ case ObjectBlockStatusMessage.STATUS_WRONG_CHECKSUM:
+ case ObjectBlockStatusMessage.STATUS_WRONG_OBJECT_ID:
+ case ObjectBlockStatusMessage.STATUS_WRONG_BLOCK:
+ // err
+ MeshUpdatingDevice device = getDeviceByAddress(srcAddress);
+ if (device != null) {
+ onDeviceFail(device, "block status err");
+ } else {
+ log(String.format("device not found , mesh address: %04X", srcAddress));
+ }
+ break;
+
+ }*/
+ }
+
+ private void mixFormat(int format) {
+ if (this.mixFormat == BlobBlockStatusMessage.FORMAT_ALL_CHUNKS_MISSING) {
+ return;
+ }
+ if (this.mixFormat == -1) {
+ this.mixFormat = format;
+ } else if (this.mixFormat != format && format != BlobBlockStatusMessage.FORMAT_NO_CHUNKS_MISSING) {
+ this.mixFormat = format;
+ }
+ }
+
+ private void mixMissingChunks(List chunks) {
+ if (this.mixFormat == BlobBlockStatusMessage.FORMAT_ALL_CHUNKS_MISSING) return;
+ if (chunks != null) {
+ for (int chunkNumber : chunks) {
+ if (!missingChunks.contains(chunkNumber)) {
+ missingChunks.add(chunkNumber);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * reliable command complete
+ */
+ public void onUpdatingCommandComplete(boolean success, int opcode, int rspMax, int rspCount) {
+ log(String.format("updating command complete: opcode-%04X success?-%b", opcode, success));
+ if (!success) {
+
+ /*
+ STEP_SET_SUBSCRIPTION = 1;
+ STEP_GET_FIRMWARE_INFO = 2;
+ STEP_METADATA_CHECK = 3;
+ STEP_UPDATE_START = 4;
+ STEP_BLOB_TRANSFER_GET = 5;
+ STEP_GET_BLOB_INFO = 6;
+ STEP_BLOB_TRANSFER_START = 7;
+ STEP_BLOB_BLOCK_TRANSFER_START = 8;
+ STEP_BLOB_CHUNK_SENDING = 9;
+ STEP_GET_BLOB_BLOCK = 10;
+ STEP_UPDATE_GET = 11;
+ STEP_UPDATE_APPLY = 12;
+ STEP_UPDATE_COMPLETE = 13;
+ */
+
+ // command timeout
+ final boolean deviceFailed =
+ (opcode ==
+ Opcode.CFG_MODEL_SUB_ADD.value && step == STEP_SET_SUBSCRIPTION) ||
+ (opcode == Opcode.FIRMWARE_UPDATE_INFORMATION_GET.value && step == STEP_GET_FIRMWARE_INFO) ||
+ (opcode == Opcode.FIRMWARE_UPDATE_FIRMWARE_METADATA_CHECK.value && step == STEP_METADATA_CHECK) ||
+ (opcode == Opcode.FIRMWARE_UPDATE_START.value && step == STEP_UPDATE_START) ||
+ (opcode == Opcode.BLOB_TRANSFER_GET.value && step == STEP_BLOB_TRANSFER_GET) ||
+
+ (opcode == Opcode.BLOB_INFORMATION_GET.value && step == STEP_GET_BLOB_INFO) ||
+
+ (opcode == Opcode.BLOB_TRANSFER_START.value && step == STEP_BLOB_TRANSFER_START) ||
+ (opcode == Opcode.BLOB_BLOCK_START.value && step == STEP_BLOB_BLOCK_TRANSFER_START)
+ || (opcode == Opcode.BLOB_BLOCK_GET.value && step == STEP_GET_BLOB_BLOCK)
+ || (opcode == Opcode.FIRMWARE_UPDATE_GET.value && step == STEP_UPDATE_GET)
+ || (opcode == Opcode.FIRMWARE_UPDATE_APPLY.value && step == STEP_UPDATE_APPLY);
+ if (deviceFailed) {
+ String desc = String.format(Locale.getDefault(), "device failed at step: %02d when sending: 0x%04X", step, opcode);
+ onDeviceFail(nodes.get(nodeIndex), desc);
+ nodeIndex++;
+ executeUpdatingAction();
+ }
+ }
+ }
+
+ private void validateUpdatingProgress() {
+ if (firmwareParser.validateProgress()) {
+ final int progress = firmwareParser.getProgress();
+ log("chunk sending progress: " + progress);
+ onStateUpdate(STATE_PROGRESS, "progress update", progress);
+ }
+ }
+
+ private MeshUpdatingDevice getDeviceByAddress(int meshAddress) {
+ for (MeshUpdatingDevice device : nodes) {
+ if (device.getMeshAddress() == meshAddress) return device;
+ }
+ return null;
+ }
+
+
+ private void onDeviceFail(MeshUpdatingDevice device, String desc) {
+ log(String.format("node updating fail: %04X -- " + desc, device.getMeshAddress()));
+ device.setState(MeshUpdatingDevice.STATE_FAIL);
+ onStateUpdate(STATE_DEVICE_FAIL,
+ String.format("node updating fail: %04X -- ", device.getMeshAddress()),
+ device);
+ }
+
+ private void onDeviceSuccess(MeshUpdatingDevice device) {
+ log(String.format("node updating success: %04X -- ", device.getMeshAddress()));
+ device.setState(MeshUpdatingDevice.STATE_SUCCESS);
+ onStateUpdate(STATE_DEVICE_SUCCESS,
+ String.format("node updating success: %04X -- ", device.getMeshAddress()),
+ device);
+ }
+
+ /**
+ * at least one device success
+ */
+ private void onUpdatingSuccess() {
+ onStateUpdate(STATE_PROGRESS, "update complete -> progress ", 100);
+ log("updating complete");
+ this.step = STEP_INITIAL;
+ onStateUpdate(STATE_SUCCESS, "updating success", null);
+ }
+
+ /**
+ * no device success
+ */
+ private void onUpdatingFail(int state, String desc) {
+ log("updating failed: " + state + " -- " + desc);
+ this.step = STEP_INITIAL;
+ onStateUpdate(state, desc, null);
+ onMeshMessagePrepared(FirmwareUpdateCancelMessage.getSimple(0xFFFF, appKeyIndex));
+ }
+
+
+ public void onUpdatingStopped() {
+ log("updating stopped");
+ this.step = STEP_INITIAL;
+ onStateUpdate(STATE_STOPPED, "updating stopped", null);
+ }
+
+ private void onStateUpdate(int state, String desc, Object obj) {
+ if (accessBridge != null) {
+ accessBridge.onAccessStateChanged(state, desc, AccessBridge.MODE_FIRMWARE_UPDATING, obj);
+ }
+ }
+
+ /**
+ * get step description
+ */
+ private String getStepDesc(int step) {
+ switch (step) {
+
+ case STEP_INITIAL:
+ return "initial";
+
+ case STEP_GET_FIRMWARE_INFO:
+ return "get-firmware-info";
+
+ case STEP_SET_SUBSCRIPTION:
+ return "set-subscription";
+
+ case STEP_GET_BLOB_INFO:
+ return "get-blob-info";
+
+ case STEP_METADATA_CHECK:
+ return "metadata-check";
+
+ case STEP_UPDATE_START:
+ return "update-start";
+
+ case STEP_BLOB_TRANSFER_START:
+ return "blob-transfer-start";
+
+ case STEP_BLOB_TRANSFER_GET:
+ return "blob transfer get";
+
+ case STEP_BLOB_BLOCK_TRANSFER_START:
+ return "block-transfer-start";
+
+ case STEP_BLOB_CHUNK_SENDING:
+ return "blob-chunk-sending";
+
+ case STEP_GET_BLOB_BLOCK:
+ return "get-blob-block";
+
+ case STEP_UPDATE_GET:
+ return "update-get";
+
+ case STEP_UPDATE_APPLY:
+ return "update-apply";
+
+ case STEP_UPDATE_COMPLETE:
+ return "update-complete";
+ }
+ return "unknown";
+ }
+
+ private void log(String logMessage) {
+ log(logMessage, MeshLogger.LEVEL_DEBUG);
+ }
+
+ private void log(String logMessage, int level) {
+ MeshLogger.log(logMessage, LOG_TAG, level);
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/MeshFUController.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/MeshFUController.java
new file mode 100644
index 00000000..8020f8ce
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/MeshFUController.java
@@ -0,0 +1,52 @@
+package com.telink.ble.mesh.core.access;
+
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.message.NotificationMessage;
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * Mesh firmware update controller
+ */
+public class MeshFUController {
+
+ AccessBridge accessBridge;
+ int localAddress = 0x0001;
+ int distributorAddress = 0;
+
+ void start(int distributorAddress) {
+ this.distributorAddress = distributorAddress;
+ }
+
+ void onMeshMessageResponse(NotificationMessage notificationMessage) {
+
+ }
+
+ void onMeshMessagePrepared(MeshMessage meshMessage) {
+
+ if (meshMessage.getDestinationAddress() == localAddress) {
+ responseLocalMessage(meshMessage);
+ } else {
+ accessBridge.onAccessMessagePrepared(meshMessage, AccessBridge.MODE_FIRMWARE_UPDATING);
+ }
+ }
+
+ /**
+ * @param meshMessage
+ */
+ private void responseLocalMessage(MeshMessage meshMessage) {
+ final int op = meshMessage.getOpcode();
+ final int rspOp = meshMessage.getResponseOpcode();
+ if (rspOp == Opcode.FD_STATUS.value) {
+
+ } else if (rspOp == Opcode.FD_CAPABILITIES_STATUS.value) {
+
+ } else if (rspOp == Opcode.FD_FIRMWARE_STATUS.value) {
+
+ } else if (rspOp == Opcode.FD_RECEIVERS_STATUS.value) {
+
+ } else if (rspOp == Opcode.FD_UPLOAD_STATUS.value) {
+
+ }
+
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/MeshFirmwareParser.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/MeshFirmwareParser.java
new file mode 100644
index 00000000..49041c15
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/MeshFirmwareParser.java
@@ -0,0 +1,216 @@
+/********************************************************************************************************
+ * @file MeshFirmwareParser.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.access;
+
+import java.util.zip.CRC32;
+
+/**
+ * Created by kee on 2019/10/12.
+ */
+
+public class MeshFirmwareParser {
+
+// private static final int DEFAULT_OBJECT_ID = 0x8877665544332211L;
+
+ private static final int DEFAULT_BLOCK_SIZE = 4 * 1024;
+
+ private static final int DEFAULT_CHUNK_SIZE = 256;
+
+ private byte[] firmwareData;
+
+// private long objectId = DEFAULT_OBJECT_ID;
+
+ private int objectSize;
+
+ private int mBlockSize = DEFAULT_BLOCK_SIZE;
+
+ private int mChunkSize = DEFAULT_CHUNK_SIZE;
+
+ private int curBlockIndex;
+
+ private int curChunkIndex;
+
+ private int totalBlockNumber;
+
+ private int totalChunkNumber;
+
+ private int progress = -1;
+
+ public void reset(byte[] data) {
+ this.firmwareData = data;
+ this.objectSize = data.length;
+
+ this.curBlockIndex = -1;
+ this.curChunkIndex = -1;
+ progress = -1;
+ totalBlockNumber = (int) Math.ceil(((double) objectSize) / mBlockSize);
+ totalChunkNumber = (int) Math.ceil(((double) objectSize) / mChunkSize);
+ }
+
+ public void reset(byte[] data, int blockSize, int chunkSize) {
+ this.mBlockSize = blockSize;
+ this.mChunkSize = chunkSize;
+ this.reset(data);
+ }
+
+
+ /**
+ * prepare for next block
+ *
+ * @return if has next
+ */
+ public int nextBlock() {
+ curChunkIndex = -1;
+ return ++curBlockIndex;
+ }
+
+ public void resetBlock() {
+ curBlockIndex = -1;
+ }
+
+ public boolean hasNextBlock() {
+ return curBlockIndex + 1 < totalBlockNumber;
+ }
+
+ public int getCurBlockSize() {
+ int blockSize;
+
+ if (hasNextBlock() || (objectSize % mBlockSize) == 0) {
+ // not the last block or last block size is mBlockSize
+ blockSize = mBlockSize;
+ } else {
+ blockSize = objectSize % mBlockSize;
+ }
+ return blockSize;
+ }
+
+
+ /**
+ * refresh progress by chunk/total
+ *
+ * @return progress
+ */
+ public boolean validateProgress() {
+ // Math.ceil(mBlockSize/mChunkSize)
+ float chunkNumberOffset = curBlockIndex * (mBlockSize / mChunkSize) + (curChunkIndex + 1);
+ // max 99
+ int progress = (int) (chunkNumberOffset * 99 / totalChunkNumber);
+ if (progress <= this.progress) {
+ return false;
+ }
+ this.progress = progress;
+ return true;
+ }
+
+ public int getProgress() {
+ return progress;
+ }
+
+ /**
+ * generate next chunk at current block
+ *
+ * @return chunk-message or null when all chunk sent
+ */
+ public byte[] nextChunk() {
+ int chunkNumber;
+ double blockSize = getCurBlockSize();
+
+ chunkNumber = (int) Math.ceil(blockSize / mChunkSize);
+
+ if (curChunkIndex + 1 < chunkNumber) {
+ // has next
+ curChunkIndex++;
+ int chunkSize;
+ if (curChunkIndex + 1 < chunkNumber || blockSize % mChunkSize == 0) {
+ chunkSize = mChunkSize;
+ } else {
+ chunkSize = (int) (blockSize % mChunkSize);
+ }
+
+ byte[] chunkData = new byte[chunkSize];
+ int offset = curBlockIndex * mBlockSize + curChunkIndex * mChunkSize;
+ System.arraycopy(firmwareData, offset, chunkData, 0, chunkSize);
+
+
+ return chunkData;
+ } else {
+ return null;
+ }
+ }
+
+
+ public byte[] chunkAt(int chunkIndex) {
+ int chunkNumber;
+
+ double blockSize = getCurBlockSize();
+
+ chunkNumber = (int) Math.ceil(blockSize / mChunkSize);
+ if (chunkIndex >= chunkNumber) return null;
+
+ int chunkSize;
+ if (chunkIndex + 1 < chunkNumber || blockSize % mChunkSize == 0) {
+
+ chunkSize = mChunkSize;
+ } else {
+ chunkSize = (int) (blockSize % mChunkSize);
+ }
+
+ byte[] chunkData = new byte[chunkSize];
+ int offset = curBlockIndex * mBlockSize + chunkIndex * mChunkSize;
+ System.arraycopy(firmwareData, offset, chunkData, 0, chunkSize);
+
+ return chunkData;
+
+ }
+
+ public int currentBlockIndex() {
+ return curBlockIndex;
+ }
+
+ public int currentChunkIndex() {
+ return curChunkIndex;
+ }
+
+ public int getObjectSize() {
+ return objectSize;
+ }
+
+ public int getBlockSize() {
+ return mBlockSize;
+ }
+
+ public int getChunkSize() {
+ return mChunkSize;
+ }
+
+ /**
+ * get current block checksum
+ */
+ public int getBlockChecksum() {
+ int blockSize = getCurBlockSize();
+ byte[] blockData = new byte[blockSize];
+ System.arraycopy(firmwareData, curBlockIndex * mBlockSize, blockData, 0, blockSize);
+ CRC32 crc32 = new CRC32();
+ crc32.update(blockData);
+ return (int) crc32.getValue();
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/RemoteProvisioningController.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/RemoteProvisioningController.java
new file mode 100644
index 00000000..9df4ca1b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/access/RemoteProvisioningController.java
@@ -0,0 +1,360 @@
+/********************************************************************************************************
+ * @file RemoteProvisioningController.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.access;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.message.NotificationMessage;
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.rp.LinkCloseMessage;
+import com.telink.ble.mesh.core.message.rp.LinkOpenMessage;
+import com.telink.ble.mesh.core.message.rp.LinkStatusMessage;
+import com.telink.ble.mesh.core.message.rp.ProvisioningPDUOutboundReportMessage;
+import com.telink.ble.mesh.core.message.rp.ProvisioningPDUReportMessage;
+import com.telink.ble.mesh.core.message.rp.ProvisioningPduSendMessage;
+import com.telink.ble.mesh.core.provisioning.ProvisioningBridge;
+import com.telink.ble.mesh.core.provisioning.ProvisioningController;
+import com.telink.ble.mesh.core.proxy.ProxyPDU;
+import com.telink.ble.mesh.entity.RemoteProvisioningDevice;
+import com.telink.ble.mesh.util.Arrays;
+import com.telink.ble.mesh.util.MeshLogger;
+
+/**
+ * Mesh remote provision
+ * Created by kee on 2019/9/26.
+ * retransmit provisioning pdu when timeout
+ * cache provisioning pdu when last pdu transmitting
+ */
+
+public class RemoteProvisioningController implements ProvisioningBridge {
+ private final String LOG_TAG = "RemotePv";
+
+ public static final int STATE_INIT = 0x00;
+
+ public static final int STATE_LINK_OPENING = 0x01;
+
+ public static final int STATE_PROVISIONING = 0x02;
+
+ public static final int STATE_PROVISION_SUCCESS = 0x03;
+
+ public static final int STATE_PROVISION_FAIL = 0x04;
+
+ public static final int STATE_LINK_CLOSING = 0x05;
+
+ private int state;
+
+ private ProvisioningController provisioningController;
+ private RemoteProvisioningDevice provisioningDevice;
+
+ private AccessBridge accessBridge;
+
+// private int appKeyIndex;
+
+ private static final int OUTBOUND_INIT_VALUE = 1;
+
+ private int outboundNumber = OUTBOUND_INIT_VALUE;
+
+ private int inboundPDUNumber = 0;
+
+ /**
+ * waiting for outbound report when provisioning pdu sent
+ */
+ private boolean outboundReportWaiting = false;
+
+ private final Object WAITING_LOCK = new Object();
+
+ // transmitting provisioning pdu, this may be retransmit if outbound report not received when timeout
+ private byte[] cachePdu = null;
+
+ private byte[] transmittingPdu = null;
+
+ private boolean provisionSuccess = false;
+
+ private Handler delayHandler;
+
+ private static final long OUTBOUND_WAITING_TIMEOUT = 500;
+
+ public RemoteProvisioningController(HandlerThread handlerThread) {
+ delayHandler = new Handler(handlerThread.getLooper());
+ }
+
+ /**
+ * after provisioningDataPdu sent, waiting for ProvisioningPDUOutboundReport status
+ */
+ public void register(AccessBridge accessBridge) {
+ this.accessBridge = accessBridge;
+ }
+
+ public void begin(ProvisioningController provisioningController, RemoteProvisioningDevice remoteProvisioningDevice) {
+ log(String.format("remote provisioning begin: server -- %04X uuid -- %s",
+ remoteProvisioningDevice.getServerAddress(),
+ Arrays.bytesToHexString(remoteProvisioningDevice.getUuid())));
+ this.outboundNumber = OUTBOUND_INIT_VALUE;
+ this.inboundPDUNumber = -1;
+ this.cachePdu = null;
+ this.outboundReportWaiting = false;
+ this.provisionSuccess = false;
+ state = STATE_INIT;
+ this.provisioningController = provisioningController;
+ this.provisioningDevice = remoteProvisioningDevice;
+ linkOpen();
+ }
+
+ public void clear() {
+ this.state = STATE_INIT;
+ this.cachePdu = null;
+ this.transmittingPdu = null;
+ this.provisioningController = null;
+ if (delayHandler != null) {
+ delayHandler.removeCallbacksAndMessages(null);
+ }
+ }
+
+ public RemoteProvisioningDevice getProvisioningDevice() {
+ return provisioningDevice;
+ }
+
+ private void startProvisioningFlow() {
+ this.state = STATE_PROVISIONING;
+ if (provisioningController != null) {
+ provisioningController.setProvisioningBridge(this);
+ provisioningController.begin(this.provisioningDevice);
+ }
+ }
+
+
+ /**
+ * rsp link status
+ */
+ private void linkOpen() {
+ int serverAddress = provisioningDevice.getServerAddress();
+ byte[] uuid = provisioningDevice.getUuid();
+ MeshMessage linkOpenMessage = LinkOpenMessage.getSimple(serverAddress, 1, uuid);
+ linkOpenMessage.setRetryCnt(8);
+ this.state = STATE_LINK_OPENING;
+ this.onMeshMessagePrepared(linkOpenMessage);
+ }
+
+ private void linkClose(boolean success) {
+ this.state = STATE_LINK_CLOSING;
+ int serverAddress = provisioningDevice.getServerAddress();
+ byte reason = success ? LinkCloseMessage.REASON_SUCCESS : LinkCloseMessage.REASON_FAIL;
+ LinkCloseMessage linkCloseMessage = LinkCloseMessage.getSimple(serverAddress, 1, reason);
+ this.onMeshMessagePrepared(linkCloseMessage);
+ }
+
+ private void onLinkStatus(LinkStatusMessage linkStatusMessage) {
+ log("link status : " + linkStatusMessage.toString());
+ if (state == STATE_LINK_OPENING) {
+ startProvisioningFlow();
+ } else if (state == STATE_PROVISIONING) {
+ log("link status when provisioning");
+ } else if (state == STATE_LINK_CLOSING) {
+ this.state = provisionSuccess ? STATE_PROVISION_SUCCESS : STATE_PROVISION_FAIL;
+ onRemoteProvisioningComplete();
+ }
+
+ }
+
+ private void onProvisioningPduNotify(ProvisioningPDUReportMessage provisioningPDUReportMessage) {
+ log("provisioning pdu report : " + provisioningPDUReportMessage.toString()
+ + " -- " + this.inboundPDUNumber);
+ byte[] pduData = provisioningPDUReportMessage.getProvisioningPDU();
+ int inboundPDUNumber = provisioningPDUReportMessage.getInboundPDUNumber() & 0xFF;
+ if (inboundPDUNumber <= this.inboundPDUNumber) {
+ log("repeated provisioning pdu received");
+ return;
+ }
+ if (provisioningController != null) {
+ provisioningController.pushNotification(pduData);
+ }
+ }
+
+ private void resendProvisionPdu() {
+ delayHandler.removeCallbacks(resendProvisionPduTask);
+ delayHandler.postDelayed(resendProvisionPduTask, 2 * 1000);
+ }
+
+ private void onOutboundReport(ProvisioningPDUOutboundReportMessage outboundReportMessage) {
+ int outboundPDUNumber = outboundReportMessage.getOutboundPDUNumber() & 0xFF;
+ log("outbound report message received: " + outboundPDUNumber + " waiting? " + this.outboundReportWaiting);
+ if (this.outboundNumber == outboundPDUNumber) {
+ synchronized (WAITING_LOCK) {
+ delayHandler.removeCallbacks(resendProvisionPduTask);
+ transmittingPdu = null;
+ outboundReportWaiting = false;
+ log("stop outbound waiting: " + this.outboundNumber);
+ this.outboundNumber++;
+ if (this.cachePdu != null) {
+ this.onCommandPrepared(ProxyPDU.TYPE_PROVISIONING_PDU, this.cachePdu);
+ this.cachePdu = null;
+ } else {
+ log("no cached provisioning pdu: waiting for provisioning response");
+ }
+ }
+
+ } else if (outboundReportWaiting) {
+ log("outbound number not pair");
+ /*outboundReportWaiting = false;
+ if (this.transmittingPdu != null) {
+ this.onCommandPrepared(ProxyPDU.TYPE_PROVISIONING_PDU, this.transmittingPdu);
+ }*/
+ }
+ }
+
+ public void onMessageNotification(NotificationMessage message) {
+ Opcode opcode = Opcode.valueOf(message.getOpcode());
+ if (opcode == null) return;
+ switch (opcode) {
+ case REMOTE_PROV_LINK_STS:
+ onLinkStatus((LinkStatusMessage) message.getStatusMessage());
+ break;
+
+ case REMOTE_PROV_PDU_REPORT:
+ onProvisioningPduNotify((ProvisioningPDUReportMessage) message.getStatusMessage());
+ break;
+ case REMOTE_PROV_PDU_OUTBOUND_REPORT:
+ onOutboundReport((ProvisioningPDUOutboundReportMessage) message.getStatusMessage());
+ break;
+ }
+ }
+
+ public void onRemoteProvisioningCommandComplete(boolean success, int opcode, int rspMax, int rspCount) {
+ if (!success) {
+ onCommandError(opcode);
+ }
+ }
+
+ private void onCommandError(int opcode) {
+ if (opcode == Opcode.REMOTE_PROV_LINK_OPEN.value) {
+ onProvisioningComplete(false, "link open err");
+ } else if (opcode == Opcode.REMOTE_PROV_LINK_CLOSE.value) {
+ this.state = provisionSuccess ? STATE_PROVISION_SUCCESS : STATE_PROVISION_FAIL;
+ onRemoteProvisioningComplete();
+ } else if (opcode == Opcode.REMOTE_PROV_PDU_SEND.value) {
+ log("provisioning pdu send error");
+ onProvisioningComplete(false, "provision pdu send error");
+ }
+ }
+
+ private void onProvisioningComplete(boolean success, String desc) {
+ delayHandler.removeCallbacksAndMessages(null);
+ provisionSuccess = success;
+ if (!success && provisioningController != null) {
+ provisioningController.clear();
+ }
+ linkClose(success);
+ }
+
+ private void onRemoteProvisioningComplete() {
+ if (accessBridge != null) {
+ accessBridge.onAccessStateChanged(this.state, "remote provisioning complete", AccessBridge.MODE_REMOTE_PROVISIONING, this.provisioningDevice);
+ }
+ }
+
+ private Runnable resendProvisionPduTask = new Runnable() {
+ @Override
+ public void run() {
+ log("resend provision pdu: waitingOutbound?" + outboundReportWaiting);
+ if (transmittingPdu != null) {
+ synchronized (WAITING_LOCK) {
+ if (outboundReportWaiting) {
+ outboundReportWaiting = false;
+ onCommandPrepared(ProxyPDU.TYPE_PROVISIONING_PDU, transmittingPdu);
+ }
+ }
+ } else {
+ log("transmitting pdu error");
+ }
+ }
+ };
+
+ // draft feature
+ private void onMeshMessagePrepared(MeshMessage meshMessage) {}
+
+
+ @Override
+ public void onProvisionStateChanged(int state, String desc) {
+ log("provisioning state changed: " + state + " -- " + desc);
+ if (state == ProvisioningController.STATE_COMPLETE) {
+ onProvisioningComplete(true, desc);
+ } else if (state == ProvisioningController.STATE_FAILED) {
+ onProvisioningComplete(false, desc);
+ }
+ }
+
+
+ /*private Runnable provisioningPduTimeoutTask = new Runnable() {
+ @Override
+ public void run() {
+ if (outboundReportWaiting && transmittingPdu != null) {
+ outboundReportWaiting = false;
+ logMessage("provisioning pdu timeout: " + Arrays.bytesToHexString(transmittingPdu));
+ onCommandPrepared(ProxyPDU.TYPE_PROVISIONING_PDU, transmittingPdu);
+ }
+ }
+ };*/
+
+ /**
+ * send provisioning pdu by ProvisioningController
+ */
+ @Override
+ public void onCommandPrepared(byte type, byte[] data) {
+ if (type != ProxyPDU.TYPE_PROVISIONING_PDU) return;
+
+ synchronized (WAITING_LOCK) {
+ if (outboundReportWaiting) {
+ if (cachePdu == null) {
+ cachePdu = data;
+ } else {
+ log("cache pdu already exists");
+ }
+ return;
+ }
+ }
+
+ transmittingPdu = data.clone();
+
+ ProvisioningPduSendMessage provisioningPduSendMessage = ProvisioningPduSendMessage.getSimple(
+ provisioningDevice.getServerAddress(),
+ 0,
+ (byte) this.outboundNumber,
+ transmittingPdu
+ );
+ provisioningPduSendMessage.setRetryCnt(8);
+// delayHandler.removeCallbacks(provisioningPduTimeoutTask);
+// delayHandler.postDelayed(provisioningPduTimeoutTask, OUTBOUND_WAITING_TIMEOUT);
+ log("send provisioning pdu: " + this.outboundNumber);
+ onMeshMessagePrepared(provisioningPduSendMessage);
+ }
+
+
+ private void log(String logMessage) {
+ log(logMessage, MeshLogger.LEVEL_DEBUG);
+ }
+
+ private void log(String logMessage, int level) {
+ MeshLogger.log(logMessage, LOG_TAG, level);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/BleScanner.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/BleScanner.java
new file mode 100644
index 00000000..9ea3e04e
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/BleScanner.java
@@ -0,0 +1,444 @@
+/********************************************************************************************************
+ * @file BleScanner.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.ble;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.ParcelUuid;
+import android.text.TextUtils;
+
+import com.telink.ble.mesh.util.ContextUtil;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import androidx.annotation.Nullable;
+
+public class BleScanner {
+
+ public static final int CODE_START_FAIL = 0x06;
+
+ private ScannerType mScannerType;
+
+ private BluetoothAdapter.LeScanCallback mLeScanCallback;
+
+ private BluetoothLeScanner mLeScanner;
+
+ private ScanCallback mScanCallback;
+
+ private final Object SCANNING_STATE_LOCK = new Object();
+
+ private boolean isScanning = false;
+
+ private ScannerCallback mScannerCallback;
+
+ private LeScanFilter mLeScanFilter;
+
+ private LeScanSetting mLeScanSetting;
+
+ private Handler mDelayHandler;
+
+ private long mLastScanStartTime = 0;
+
+ /**
+ * check is any device found by scanning
+ * if false && location not enable, show
+ */
+ private boolean anyDeviceFound = false;
+
+ private BleScanner() {
+ }
+
+ public void setScannerCallback(ScannerCallback scannerCallback) {
+ this.mScannerCallback = scannerCallback;
+ }
+
+ public BleScanner(ScannerType scannerType, HandlerThread handlerThread) {
+ this.mDelayHandler = new Handler(handlerThread.getLooper());
+ if (scannerType == null || !ContextUtil.versionAboveL()) {
+ this.mScannerType = ScannerType.DEFAULT;
+ } else {
+ this.mScannerType = scannerType;
+ }
+ switch (mScannerType) {
+ case DEFAULT:
+ initDefaultScanner();
+ break;
+
+ case Lollipop:
+ initLollipopScanner();
+ break;
+ }
+ }
+
+ public boolean isEnabled() {
+ return BluetoothAdapter.getDefaultAdapter().isEnabled();
+ }
+
+ public void enableBluetooth() {
+ BluetoothAdapter.getDefaultAdapter().enable();
+ }
+
+ private void initDefaultScanner() {
+ mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
+
+ @Override
+ public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
+ anyDeviceFound = true;
+ if (mLeScanFilter != null) {
+ final LeScanFilter filter = mLeScanFilter;
+ if (filter.macExclude != null && filter.macExclude.length != 0) {
+ for (String mac : filter.macExclude) {
+ if (mac.equalsIgnoreCase(device.getAddress())) {
+ return;
+ }
+ }
+ }
+
+ boolean isTarget = true;
+ if (filter.macInclude != null && filter.macInclude.length != 0) {
+ isTarget = false;
+ for (String mac : filter.macInclude) {
+ if (mac.equalsIgnoreCase(device.getAddress())) {
+ isTarget = true;
+ break;
+ }
+ }
+ }
+
+
+ if (isTarget && filter.nameInclude != null && filter.nameInclude.length != 0) {
+ isTarget = false;
+ final String deviceName = device.getName();
+ if (!TextUtils.isEmpty(device.getName())) {
+ for (String name : filter.nameInclude) {
+ if (deviceName.equals(name)) {
+ isTarget = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (isTarget) {
+ onDeviceScanned(device, rssi, scanRecord);
+ }
+ } else {
+ onDeviceScanned(device, rssi, scanRecord);
+ }
+ }
+ };
+ }
+
+ private void initLollipopScanner() {
+ mLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
+ mScanCallback = new ScanCallback() {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ super.onScanResult(callbackType, result);
+ anyDeviceFound = true;
+ BluetoothDevice device = result.getDevice();
+ byte[] scanRecord = result.getScanRecord().getBytes();
+ int rssi = result.getRssi();
+ if (mLeScanFilter != null) {
+ final LeScanFilter filter = mLeScanFilter;
+ if (filter.macExclude != null && filter.macExclude.length != 0) {
+ for (String mac : filter.macExclude) {
+ if (mac.equalsIgnoreCase(device.getAddress())) {
+ return;
+ }
+ }
+ }
+ }
+ onDeviceScanned(device, rssi, scanRecord);
+
+ }
+
+ @Override
+ public void onBatchScanResults(List results) {
+ super.onBatchScanResults(results);
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ super.onScanFailed(errorCode);
+ BleScanner.this.onScanFailed(errorCode, "scanner failed by : " + errorCode);
+ }
+ };
+ }
+
+ private void onDeviceScanned(BluetoothDevice bluetoothDevice, int rssi, byte[] scanRecord) {
+ if (scanRecord == null) return;
+ if (mScannerCallback != null) {
+ mScannerCallback.onLeScan(bluetoothDevice, rssi, scanRecord);
+ }
+ }
+
+ public synchronized void stopScan() {
+
+ if (!isScanning) {
+ return;
+ }
+ stopScanningTimeoutTask();
+ stopScanningTask();
+ if (mScannerType == ScannerType.DEFAULT) {
+ stopLeScan();
+ } else if (mScannerType == ScannerType.Lollipop) {
+ stopLollipopScan();
+ }
+ isScanning = false;
+ if (mScannerCallback != null) {
+ mScannerCallback.onStoppedScan();
+ }
+ }
+
+ /**
+ * start bluetooth low energy scanning
+ *
+ * @param leScanFilter scanning filter
+ * @param leScanSetting scanning setting
+ */
+ public synchronized void startScan(@Nullable LeScanFilter leScanFilter, @Nullable LeScanSetting leScanSetting) {
+
+ mDelayHandler.removeCallbacksAndMessages(null);
+ /*if (!isEnabled()) {
+ return;
+ }*/
+
+ if (isScanning) {
+ stopScan();
+ }
+ anyDeviceFound = false;
+ isScanning = true;
+ this.mLeScanFilter = leScanFilter;
+ if (leScanSetting == null) {
+ mLeScanSetting = LeScanSetting.getDefault();
+ } else {
+ mLeScanSetting = leScanSetting;
+ }
+
+ long scanDelay = 0;
+
+ long scanSpacing = mLeScanSetting.spacing;
+
+ long currentTime = System.currentTimeMillis();
+ if (scanSpacing > 0 && currentTime - mLastScanStartTime < scanSpacing) {
+ scanDelay = scanSpacing - (currentTime - mLastScanStartTime);
+ if (scanDelay > scanSpacing) scanDelay = scanSpacing;
+ }
+ mLastScanStartTime = currentTime;
+ startScanningTask(scanDelay);
+ }
+
+ private void startScanningTimeoutTask(long timeout) {
+ mDelayHandler.removeCallbacks(scanningTimeoutTask);
+ mDelayHandler.postDelayed(scanningTimeoutTask, timeout);
+ }
+
+ private void stopScanningTimeoutTask() {
+ mDelayHandler.removeCallbacks(scanningTimeoutTask);
+ }
+
+ private Runnable scanningTimeoutTask = new Runnable() {
+ @Override
+ public void run() {
+ stopScan();
+ if (mScannerCallback != null) {
+ mScannerCallback.onScanTimeout(anyDeviceFound);
+ }
+ }
+ };
+
+ private void startScanningTask(long delay) {
+ mDelayHandler.removeCallbacks(scanningStartTask);
+ mDelayHandler.postDelayed(scanningStartTask, delay);
+ }
+
+ private void stopScanningTask() {
+ mDelayHandler.removeCallbacks(scanningStartTask);
+ }
+
+
+ private Runnable scanningStartTask = new Runnable() {
+ @Override
+ public void run() {
+ boolean scanStarted = false;
+ if (mScannerType == ScannerType.DEFAULT) {
+ scanStarted = startLeScan(mLeScanFilter);
+ } else if (mScannerType == ScannerType.Lollipop) {
+ scanStarted = startLollipopScan(mLeScanFilter, null);
+ }
+ startScanningTimeoutTask(mLeScanSetting.timeout);
+ if (scanStarted) {
+ if (mScannerCallback != null) {
+ mScannerCallback.onStartedScan();
+ }
+ } else {
+ onScanFailed(CODE_START_FAIL, "scan action start failed");
+ }
+
+ }
+ };
+
+ private void onScanFailed(int errorCode, String desc) {
+ isScanning = false;
+ if (mScannerCallback != null) {
+ mScannerCallback.onScanFail(errorCode);
+ }
+ }
+
+ private boolean startLeScan(LeScanFilter leScanFilter) {
+ if (mLeScanCallback != null) {
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ return bluetoothAdapter.startLeScan(leScanFilter == null ? null : leScanFilter.uuidInclude, mLeScanCallback);
+ } else {
+ return false;
+ }
+
+ }
+
+ private boolean startLollipopScan(LeScanFilter leScanFilter, ScanSettings scanSettings) {
+ if (mLeScanner != null && mScanCallback != null) {
+ List scanFilters = buildLeScanFilter(leScanFilter);
+ if (scanSettings == null) {
+ scanSettings = buildDefaultScanSettings();
+ }
+
+ mLeScanner.startScan(scanFilters, scanSettings, mScanCallback);
+ return true;
+ }
+
+ return false;
+ }
+
+ private void stopLeScan() {
+ if (mLeScanCallback != null) {
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ bluetoothAdapter.stopLeScan(mLeScanCallback);
+ }
+ }
+
+ private void stopLollipopScan() {
+ if (mLeScanner != null && mScanCallback != null) {
+ mLeScanner.stopScan(mScanCallback);
+ }
+ }
+
+ public boolean isBluetoothSupported() {
+ return BluetoothAdapter.getDefaultAdapter() != null;
+ }
+
+ public boolean isBluetoothEnabled() {
+ return BluetoothAdapter.getDefaultAdapter() != null
+ && BluetoothAdapter.getDefaultAdapter().isEnabled();
+ }
+
+ private List buildLeScanFilter(LeScanFilter filter) {
+
+ if (filter == null) {
+ return null;
+ }
+
+ int maxSize = Collections.max(Arrays.asList(
+ filter.uuidInclude == null ? 0 : filter.uuidInclude.length,
+ filter.macInclude == null ? 0 : filter.macInclude.length,
+ filter.nameInclude == null ? 0 : filter.nameInclude.length
+ ));
+ if (maxSize == 0) {
+ return null;
+ }
+
+ List results = new ArrayList<>();
+ ScanFilter.Builder builder;
+ for (int i = 0; i < maxSize; i++) {
+ builder = new ScanFilter.Builder();
+ if (filter.uuidInclude != null && filter.uuidInclude.length > i) {
+ builder.setServiceUuid(ParcelUuid.fromString(filter.uuidInclude[i].toString()));
+ }
+ if (filter.macInclude != null && filter.macInclude.length > i) {
+ builder.setDeviceAddress(filter.macInclude[i]);
+ }
+
+ if (filter.nameInclude != null && filter.nameInclude.length > i) {
+ builder.setDeviceName(filter.nameInclude[i]);
+ }
+ results.add(builder.build());
+ }
+
+ return results;
+ }
+
+ private ScanSettings buildDefaultScanSettings() {
+ ScanSettings.Builder builder = new ScanSettings.Builder()
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+ .setReportDelay(0);
+ if (ContextUtil.SDK_VERSION >= 23) {
+ builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
+ builder.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE);
+ builder.setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT);
+ }
+ if (ContextUtil.SDK_VERSION >= 26) {
+ builder.setLegacy(true);
+ builder.setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED);
+ }
+ return builder.build();
+
+ }
+
+ /**
+ * Scanner Types for different SDK-VERSION
+ */
+ public enum ScannerType {
+ /**
+ * for android-sdk 18 (4.3)
+ */
+ DEFAULT,
+
+ /**
+ * for android-sdk 21 (5.0)
+ */
+ Lollipop,
+
+ }
+
+
+ public interface ScannerCallback {
+ void onLeScan(BluetoothDevice bluetoothDevice, int rssi, byte[] scanRecord);
+
+ void onScanFail(int errorCode);
+
+ void onStartedScan();
+
+ void onStoppedScan();
+
+ void onScanTimeout(boolean anyDeviceFound);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/GattConnection.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/GattConnection.java
new file mode 100644
index 00000000..814151de
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/GattConnection.java
@@ -0,0 +1,1329 @@
+/********************************************************************************************************
+ * @file GattConnection.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.ble;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattService;
+import android.content.Context;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+import com.telink.ble.mesh.core.proxy.ProxyPDU;
+import com.telink.ble.mesh.util.Arrays;
+import com.telink.ble.mesh.util.MeshLogger;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Queue;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import androidx.annotation.NonNull;
+
+public class GattConnection extends BluetoothGattCallback {
+
+ private final String LOG_TAG = "GATT";
+
+ private Context mContext;
+
+ private Handler mHandler;
+
+ private BluetoothGatt mGatt;
+
+ private BluetoothDevice mBluetoothDevice;
+
+ private final Object CONNECTION_STATE_LOCK = new Object();
+
+ protected final Runnable mConnectionTimeoutRunnable = new ConnectionTimeoutRunnable();
+
+ protected final Runnable mDisconnectionTimeoutRunnable = new DisconnectionTimeoutRunnable();
+
+ protected final Runnable mServicesDiscoveringRunnable = new ServicesDiscoveringRunnable();
+
+ protected final Runnable mCommandTimeoutRunnable = new CommandTimeoutRunnable();
+
+ protected final Handler mRequestTimeoutHandler = new Handler(Looper.getMainLooper());
+
+ private final Queue mGattRequestQueue = new ConcurrentLinkedQueue<>();
+
+ private final Object COMMAND_PROCESSING_LOCK = new Object();
+
+ private boolean isRequestProcessing = false;
+
+ private AtomicBoolean isConnectWaiting = new AtomicBoolean(false);
+
+ private long commandTimeoutMill = 10 * 1000;
+ /**
+ * connection timeout used on {@link #connect()}
+ */
+ private static final int CONNECTION_TIMEOUT = 10 * 1000;
+
+ private static final int DISCONNECTION_TIMEOUT = 2 * 1000;
+
+ /**
+ * {@link BluetoothGatt#STATE_CONNECTED}
+ */
+ private int mConnectionState;
+
+ private static final int CONN_STATE_IDLE = 0;
+ private static final int CONN_STATE_CONNECTING = 1;
+ private static final int CONN_STATE_CONNECTED = 2;
+ private static final int CONN_STATE_DISCONNECTING = 3;
+// private static final int CONN_STATE_CLOSED = 4;
+
+ /**
+ * services get by gatt#discoverServices
+ */
+ protected List mServices;
+
+ private ConnectionCallback mConnectionCallback;
+
+ private byte[] proxyNotificationSegBuffer;
+
+ private int mtu = 23;
+
+ private static final int MTU_SIZE_MAX = 517;
+
+ public GattConnection(Context context, HandlerThread thread) {
+ mContext = context.getApplicationContext();
+ mHandler = new Handler(thread.getLooper());
+ }
+
+ public void setConnectionCallback(ConnectionCallback connectionCallback) {
+ this.mConnectionCallback = connectionCallback;
+ }
+
+ /*public static GattConnection createNewInstance(Context context, BluetoothDevice device) {
+ GattConnection gattDevice = new GattConnection(context);
+ gattDevice.mBluetoothDevice = device;
+ return gattDevice;
+ }*/
+
+ public boolean isConnected() {
+ synchronized (CONNECTION_STATE_LOCK) {
+ return mConnectionState == CONN_STATE_CONNECTED;
+ }
+ }
+
+ public boolean isProxyNodeConnected() {
+ return isProxyNodeConnected(false);
+ }
+
+ /**
+ * @return proxy node connected
+ */
+ public boolean isProxyNodeConnected(boolean real) {
+ if (isConnected()) {
+ return getProxyService(real) != null;
+ }
+ return false;
+ }
+
+ /**
+ * @return un-provisioned node connected
+ */
+ public boolean isUnPvNodeConnected() {
+ if (isConnected()) {
+ return getProvisionService() != null;
+ }
+ return false;
+ }
+
+ public void proxyInit() {
+ enableNotifications();
+ writeCCCForPx();
+// writeCCCForPv();
+ }
+
+ public void provisionInit() {
+ enableNotifications();
+ writeCCCForPv();
+ writeCCCForPx();
+ }
+
+ /**
+ * @param type proxy pdu type
+ * @param data data excluding type
+ */
+ public void sendMeshData(byte type, byte[] data) {
+ // opcode: 1 byte, handle: 2 bytes
+ final int mtu = this.mtu - 3;
+ final boolean isProvisioningPdu = type == ProxyPDU.TYPE_PROVISIONING_PDU;
+ if (data.length > mtu - 1) {
+ double ceil = Math.ceil(((double) data.length) / (mtu - 1));
+ int pktNum = (int) ceil;
+ byte oct0;
+ byte[] pkt;
+ for (int i = 0; i < pktNum; i++) {
+ if (i != pktNum - 1) {
+ if (i == 0) {
+ oct0 = (byte) (ProxyPDU.SAR_SEG_FIRST | type);
+ } else {
+ oct0 = (byte) (ProxyPDU.SAR_SEG_CONTINUE | type);
+ }
+ pkt = new byte[mtu];
+ pkt[0] = oct0;
+ System.arraycopy(data, (mtu - 1) * i, pkt, 1, mtu - 1);
+ } else {
+ oct0 = (byte) (ProxyPDU.SAR_SEG_LAST | type);
+ int restSize = data.length - (mtu - 1) * i;
+ pkt = new byte[restSize + 1];
+ pkt[0] = oct0;
+ System.arraycopy(data, (mtu - 1) * i, pkt, 1, restSize);
+ }
+ log("send segment pkt: " + Arrays.bytesToHexString(pkt, ":"));
+ if (isProvisioningPdu) {
+ sendPvRequest(pkt);
+ } else {
+ sendProxyRequest(pkt);
+ }
+ }
+ } else {
+ byte[] proxyData = new byte[data.length + 1];
+ proxyData[0] = type;
+ System.arraycopy(data, 0, proxyData, 1, data.length);
+ log("send unsegment pkt: " + Arrays.bytesToHexString(proxyData, ":"));
+ if (isProvisioningPdu) {
+ sendPvRequest(proxyData);
+ } else {
+ sendProxyRequest(proxyData);
+ }
+ }
+ }
+
+
+ // 27 18
+ public void writeCCCForPv() {
+ log("write ccc in provision service");
+ GattRequest cmd = GattRequest.newInstance();
+ BluetoothGattService service = getProvisionService();
+ if (service == null) return;
+ cmd.serviceUUID = service.getUuid();
+ cmd.characteristicUUID = UUIDInfo.CHARACTERISTIC_PB_OUT;
+ cmd.descriptorUUID = UUIDInfo.DESCRIPTOR_CFG_UUID;
+ cmd.data = new byte[]{0x01, 0x00};
+ cmd.type = GattRequest.RequestType.WRITE_DESCRIPTOR;
+ sendRequest(cmd);
+ }
+
+
+ // 28 18
+ public void writeCCCForPx() {
+ log("write ccc in proxy service");
+ GattRequest cmd = GattRequest.newInstance();
+ BluetoothGattService service = getProxyService(false);
+ if (service == null) return;
+ cmd.serviceUUID = service.getUuid();
+ cmd.characteristicUUID = UUIDInfo.CHARACTERISTIC_PROXY_OUT;
+ cmd.descriptorUUID = UUIDInfo.DESCRIPTOR_CFG_UUID;
+ cmd.data = new byte[]{0x01, 0x00};
+ cmd.type = GattRequest.RequestType.WRITE_DESCRIPTOR;
+ sendRequest(cmd);
+ }
+
+ public boolean enableOnlineStatus() {
+ GattRequest cmd = GattRequest.newInstance();
+ if (!isConnected()) return false;
+ if (!checkOnlineStatusService()) return false;
+ cmd.serviceUUID = UUIDInfo.SERVICE_ONLINE_STATUS;
+ cmd.characteristicUUID = UUIDInfo.CHARACTERISTIC_ONLINE_STATUS;
+ cmd.data = new byte[]{0x01};
+ cmd.type = GattRequest.RequestType.WRITE_NO_RESPONSE;
+ sendRequest(cmd);
+ return true;
+ }
+
+
+ private void sendPvRequest(byte[] data) {
+ GattRequest cmd = GattRequest.newInstance();
+ cmd.characteristicUUID = UUIDInfo.CHARACTERISTIC_PB_IN;
+ BluetoothGattService service = getProvisionService();
+ if (service == null) return;
+ cmd.serviceUUID = service.getUuid();
+ cmd.data = data.clone();
+ cmd.type = GattRequest.RequestType.WRITE_NO_RESPONSE;
+ sendRequest(cmd);
+ }
+
+ private void sendProxyRequest(byte[] data) {
+ GattRequest cmd = GattRequest.newInstance();
+ BluetoothGattService service = getProxyService(false);
+ if (service == null) return;
+ cmd.serviceUUID = service.getUuid();
+ cmd.characteristicUUID = UUIDInfo.CHARACTERISTIC_PROXY_IN;
+ cmd.data = data.clone();
+ cmd.type = GattRequest.RequestType.WRITE_NO_RESPONSE;
+ sendRequest(cmd);
+ }
+
+
+ private void enableNotifications() {
+ GattRequest gattRequest;
+ BluetoothGattService provisionService = getProvisionService();
+ if (provisionService != null) {
+ gattRequest = GattRequest.newInstance();
+ gattRequest.type = GattRequest.RequestType.ENABLE_NOTIFY;
+ gattRequest.serviceUUID = provisionService.getUuid();
+ gattRequest.characteristicUUID = UUIDInfo.CHARACTERISTIC_PB_OUT;
+ sendRequest(gattRequest);
+ }
+
+ BluetoothGattService proxyService = getProxyService(false);
+ if (proxyService != null) {
+ gattRequest = GattRequest.newInstance();
+ gattRequest.type = GattRequest.RequestType.ENABLE_NOTIFY;
+ gattRequest.serviceUUID = proxyService.getUuid();
+ gattRequest.characteristicUUID = UUIDInfo.CHARACTERISTIC_PROXY_OUT;
+ sendRequest(gattRequest);
+ }
+
+ {
+ gattRequest = GattRequest.newInstance();
+ gattRequest.type = GattRequest.RequestType.ENABLE_NOTIFY;
+ gattRequest.serviceUUID = UUIDInfo.SERVICE_ONLINE_STATUS;
+ gattRequest.characteristicUUID = UUIDInfo.CHARACTERISTIC_ONLINE_STATUS;
+ sendRequest(gattRequest);
+ }
+ }
+
+ private boolean checkOnlineStatusService() {
+ if (this.mServices == null) return false;
+ for (BluetoothGattService service : mServices) {
+ if (service.getUuid().equals(UUIDInfo.SERVICE_ONLINE_STATUS)) {
+ for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
+ if (characteristic.getUuid().equals(UUIDInfo.CHARACTERISTIC_ONLINE_STATUS)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private BluetoothGattService getProvisionService() {
+ final List services = this.mServices;
+ if (services == null) return null;
+ for (BluetoothGattService service :
+ services) {
+ if (service.getUuid().equals(UUIDInfo.SERVICE_PROVISION) || service.getUuid().equals(UUIDInfo.SERVICE_MESH_FLEX)) {
+ for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
+ if (characteristic.getUuid().equals(UUIDInfo.CHARACTERISTIC_PB_IN)) {
+ return service;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param real true: only check PROXY_SERVICE_UUID,
+ * false: check PROXY_SERVICE_UUID and MESH_FLEX_SERVICE_UUID
+ */
+ private BluetoothGattService getProxyService(boolean real) {
+ final List services = this.mServices;
+ if (services == null) return null;
+ for (BluetoothGattService service : services) {
+ if ((service.getUuid().equals(UUIDInfo.SERVICE_PROXY))
+ || (!real && service.getUuid().equals(UUIDInfo.SERVICE_MESH_FLEX))) {
+ for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
+ if (characteristic.getUuid().equals(UUIDInfo.CHARACTERISTIC_PROXY_IN)) {
+ return service;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+
+ public void connect(BluetoothDevice bluetoothDevice) {
+ if (bluetoothDevice.equals(mBluetoothDevice)) {
+ connect();
+ } else {
+ this.mBluetoothDevice = bluetoothDevice;
+ if (this.disconnect()) {
+ // waiting for disconnected callback
+ log(" waiting for disconnect -- ");
+ isConnectWaiting.set(true);
+ } else {
+ log(" already disconnected -- ");
+ // execute connecting action
+ this.connect();
+ }
+ }
+ }
+
+
+ public void connect() {
+ synchronized (CONNECTION_STATE_LOCK) {
+ if (mConnectionState == CONN_STATE_CONNECTED) {
+ this.onConnected();
+ if (mServices != null) {
+ this.onServicesDiscoveredComplete(mServices);
+ }
+ /* auto discover services when connection established */
+ } else if (mConnectionState == CONN_STATE_IDLE) {
+ this.mConnectionState = CONN_STATE_CONNECTING;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ this.mGatt = this.mBluetoothDevice.connectGatt(mContext, false, this, BluetoothDevice.TRANSPORT_LE);
+ } else {
+ this.mGatt = this.mBluetoothDevice.connectGatt(mContext, false, this);
+ }
+ if (this.mGatt == null) {
+ this.disconnect();
+ this.mConnectionState = CONN_STATE_IDLE;
+ this.onDisconnected();
+ } else {
+ mHandler.postDelayed(mConnectionTimeoutRunnable, CONNECTION_TIMEOUT);
+ }
+ }
+ /* ignore CONN_STATE_DISCONNECTING and CONN_STATE_CONNECTING */
+ }
+ }
+
+ /**
+ * @return true: onDisconnected will callback
+ * false: no callback
+ */
+ public boolean disconnect() {
+ this.clear();
+ synchronized (this.CONNECTION_STATE_LOCK) {
+ if (mConnectionState == CONN_STATE_IDLE) return false;
+ if (this.mGatt != null) {
+ if (mConnectionState == CONN_STATE_CONNECTED) {
+ this.mConnectionState = CONN_STATE_DISCONNECTING;
+ this.mGatt.disconnect();
+ } else if (mConnectionState == CONN_STATE_CONNECTING) {
+ this.mGatt.disconnect();
+ this.mGatt.close();
+ this.mConnectionState = CONN_STATE_IDLE;
+ return false;
+ }
+ } else {
+ this.mConnectionState = CONN_STATE_IDLE;
+ return false;
+ }
+ }
+ startDisconnectionCheck();
+ return true;
+ }
+
+
+ private void startDisconnectionCheck() {
+ mHandler.removeCallbacks(mDisconnectionTimeoutRunnable);
+ mHandler.postDelayed(mDisconnectionTimeoutRunnable, DISCONNECTION_TIMEOUT);
+ }
+
+ private void startServicesDiscovering() {
+ long delay;
+ if (mBluetoothDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
+ // waiting for encryption procedure
+ delay = 1600;
+ } else {
+ delay = 300;
+ }
+ mHandler.removeCallbacks(mServicesDiscoveringRunnable);
+ mHandler.postDelayed(mServicesDiscoveringRunnable, delay);
+ }
+
+ private void clear() {
+ this.refreshCache();
+ this.cancelCommandTimeoutTask();
+ this.mGattRequestQueue.clear();
+ this.isRequestProcessing = false;
+ this.mHandler.removeCallbacksAndMessages(null);
+ }
+
+ private void onConnected() {
+ this.mHandler.removeCallbacks(mConnectionTimeoutRunnable);
+ if (mConnectionCallback != null) {
+ mConnectionCallback.onConnected();
+ }
+ }
+
+ public void requestConnectionPriority(int connectionPriority) {
+ if (mGatt != null) {
+ mGatt.requestConnectionPriority(connectionPriority);
+ }
+ }
+
+ public boolean refreshCache() {
+ if (Build.VERSION.SDK_INT >= 27) return false;
+ if (mGatt == null) {
+ log("refresh error: gatt null");
+ return false;
+ } else {
+ log("Device#refreshCache#prepare");
+ }
+ try {
+ BluetoothGatt localBluetoothGatt = mGatt;
+ Method localMethod = localBluetoothGatt.getClass().getMethod("refresh", new Class[0]);
+ if (localMethod != null) {
+ boolean bool = (Boolean) localMethod.invoke(localBluetoothGatt, new Object[0]);
+ /*if (bool) {
+ mDelayHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ gatt.discoverServices();
+ }
+ }, 0);
+ }*/
+ return bool;
+ }
+ } catch (Exception localException) {
+ log("An exception occurs while refreshing device");
+ }
+ return false;
+ }
+
+
+ private void onServicesDiscoveredComplete(List services) {
+ /*StringBuffer serviceInfo = new StringBuffer("\n");
+
+ for (BluetoothGattService service : services) {
+ serviceInfo.append(service.getUuid().toString()).append("\n");
+ for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
+ serviceInfo.append("chara: \t");
+ serviceInfo.append(characteristic.getUuid().toString()).append("\n");
+ }
+ }
+ log("services: " + serviceInfo);*/
+ log("service discover complete");
+ if (mConnectionCallback != null) {
+ mConnectionCallback.onServicesDiscovered(services);
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ this.mGatt.requestMtu(MTU_SIZE_MAX);
+ }
+ }
+
+ private void onDisconnected() {
+ this.mHandler.removeCallbacks(mDisconnectionTimeoutRunnable);
+ this.mHandler.removeCallbacks(mServicesDiscoveringRunnable);
+ this.mServices = null;
+ if (isConnectWaiting.get()) {
+ isConnectWaiting.set(false);
+ this.connect();
+ } else {
+ if (mConnectionCallback != null) {
+ mConnectionCallback.onDisconnected();
+ }
+ }
+
+
+ }
+
+
+ public String getMacAddress() {
+ if (mBluetoothDevice == null) return null;
+ return mBluetoothDevice.getAddress();
+ }
+
+ public String getDeviceName() {
+ if (mBluetoothDevice == null) return null;
+ return mBluetoothDevice.getName();
+ }
+
+ public int getMtu() {
+ return this.mtu;
+ }
+
+ /************************************************************************
+ * gatt operation
+ ************************************************************************/
+
+ public boolean sendRequest(@NonNull GattRequest gattRequest) {
+ synchronized (this.CONNECTION_STATE_LOCK) {
+ if (this.mConnectionState != CONN_STATE_CONNECTED)
+ return false;
+ }
+ mGattRequestQueue.add(gattRequest);
+ postRequest();
+ return true;
+ }
+
+ private void postRequest() {
+ synchronized (COMMAND_PROCESSING_LOCK) {
+ if (isRequestProcessing) {
+ return;
+ }
+ }
+
+ synchronized (mGattRequestQueue) {
+ if (!mGattRequestQueue.isEmpty()) {
+ GattRequest gattRequest = mGattRequestQueue.peek();
+ if (gattRequest != null) {
+ synchronized (COMMAND_PROCESSING_LOCK) {
+ isRequestProcessing = true;
+ }
+ processRequest(gattRequest);
+ }
+ }
+ }
+ }
+
+ private void processRequest(GattRequest gattRequest) {
+ GattRequest.RequestType requestType = gattRequest.type;
+ log("process request : " + gattRequest.toString(), MeshLogger.LEVEL_VERBOSE);
+ switch (requestType) {
+ case READ:
+ this.postCommandTimeoutTask();
+ this.readCharacteristic(gattRequest);
+ break;
+ case WRITE:
+ this.postCommandTimeoutTask();
+ this.writeCharacteristic(gattRequest, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
+ break;
+ case WRITE_NO_RESPONSE:
+ this.postCommandTimeoutTask();
+ this.writeCharacteristic(gattRequest, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
+ break;
+ case READ_DESCRIPTOR:
+ this.postCommandTimeoutTask();
+ this.readDescriptor(gattRequest);
+ break;
+ case WRITE_DESCRIPTOR:
+ this.postCommandTimeoutTask();
+ this.writeDescriptor(gattRequest);
+ break;
+ case ENABLE_NOTIFY:
+ this.enableNotification(gattRequest);
+ break;
+ case DISABLE_NOTIFY:
+ this.disableNotification(gattRequest);
+ break;
+ }
+ }
+
+
+ private void postCommandTimeoutTask() {
+
+ if (this.commandTimeoutMill <= 0)
+ return;
+
+ this.mRequestTimeoutHandler.removeCallbacksAndMessages(null);
+ this.mRequestTimeoutHandler.postDelayed(this.mCommandTimeoutRunnable, this.commandTimeoutMill);
+ }
+
+ private void cancelCommandTimeoutTask() {
+ this.mRequestTimeoutHandler.removeCallbacksAndMessages(null);
+ }
+
+
+ private void onNotify(BluetoothGattCharacteristic characteristic, byte[] data) {
+ final UUID charUUID = characteristic.getUuid();
+ final UUID serviceUUID = characteristic.getService().getUuid();
+ if (!charUUID.equals(UUIDInfo.CHARACTERISTIC_PB_OUT) && !charUUID.equals(UUIDInfo.CHARACTERISTIC_PROXY_OUT)) {
+ if (mConnectionCallback != null) {
+ mConnectionCallback.onNotify(serviceUUID, charUUID, data);
+ }
+ return;
+ }
+ log("on notify -- " + Arrays.bytesToHexString(data, ":"), MeshLogger.LEVEL_VERBOSE);
+
+ if (data == null || data.length == 0) {
+ log("empty packet received!", MeshLogger.LEVEL_WARN);
+ return;
+ }
+ byte[] completePacket = getCompletePacket(data);
+ if (completePacket == null) {
+ log("waiting for segment pkt", MeshLogger.LEVEL_VERBOSE);
+ return;
+ }
+ log("completed notification data: " + Arrays.bytesToHexString(completePacket, ":"));
+ if (completePacket.length <= 1) {
+ log("complete notification length err", MeshLogger.LEVEL_WARN);
+ return;
+ }
+ if (mConnectionCallback != null) {
+ mConnectionCallback.onNotify(serviceUUID, charUUID, completePacket);
+ }
+ }
+
+ private byte[] getCompletePacket(byte[] data) {
+ byte sar = (byte) (data[0] & ProxyPDU.BITS_SAR);
+ switch (sar) {
+ case ProxyPDU.SAR_COMPLETE:
+ return data;
+
+ case ProxyPDU.SAR_SEG_FIRST:
+ data[0] = (byte) (data[0] & ProxyPDU.BITS_TYPE);
+ proxyNotificationSegBuffer = data;
+ return null;
+
+ case ProxyPDU.SAR_SEG_CONTINUE:
+ case ProxyPDU.SAR_SEG_LAST:
+ if (proxyNotificationSegBuffer != null) {
+ int segType = proxyNotificationSegBuffer[0] & ProxyPDU.BITS_TYPE;
+ int dataType = data[0] & ProxyPDU.BITS_TYPE;
+
+ // check if pkt typeValue equals
+ if (segType == dataType && data.length > 1) {
+ byte[] tempBuffer = new byte[proxyNotificationSegBuffer.length + data.length - 1];
+ System.arraycopy(proxyNotificationSegBuffer, 0, tempBuffer, 0, proxyNotificationSegBuffer.length);
+ System.arraycopy(data, 1, tempBuffer, proxyNotificationSegBuffer.length, data.length - 1);
+ if (sar == ProxyPDU.SAR_SEG_CONTINUE) {
+ proxyNotificationSegBuffer = tempBuffer;
+ return null;
+ } else {
+ proxyNotificationSegBuffer = null;
+ return tempBuffer;
+ }
+ } else {
+ log("other segment ", MeshLogger.LEVEL_WARN);
+ }
+ } else {
+ log("segment first pkt no found", MeshLogger.LEVEL_WARN);
+ }
+
+ default:
+ return null;
+ }
+ }
+
+ private void onRequestError(String errorMsg) {
+ log("request error: " + errorMsg);
+ GattRequest request;
+ synchronized (mGattRequestQueue) {
+ request = this.mGattRequestQueue.poll();
+ }
+ if (request != null) {
+ GattRequest.Callback requestCallback = request.callback;
+ if (requestCallback != null) {
+ requestCallback.error(request, errorMsg);
+ }
+ }
+ }
+
+
+ private boolean onRequestTimeout(@NonNull GattRequest gattRequest) {
+ log("gatt request timeout", MeshLogger.LEVEL_VERBOSE);
+ GattRequest.Callback requestCallback = gattRequest.callback;
+ if (requestCallback != null) {
+ return requestCallback.timeout(gattRequest);
+ }
+ return false;
+ }
+
+
+ /**
+ * @param data command response
+ */
+ private void onRequestSuccess(byte[] data) {
+ GattRequest gattRequest = mGattRequestQueue.poll();
+ if (gattRequest != null) {
+ log("request success: tag - " + gattRequest.tag, MeshLogger.LEVEL_VERBOSE);
+ GattRequest.Callback requestCallback = gattRequest.callback;
+ if (requestCallback != null) {
+ requestCallback.success(gattRequest, data);
+ }
+ } else {
+ log("request not found");
+ }
+ }
+
+ private void onRequestComplete() {
+
+ log("gatt request completed", MeshLogger.LEVEL_VERBOSE);
+
+ synchronized (this.COMMAND_PROCESSING_LOCK) {
+ if (this.isRequestProcessing)
+ this.isRequestProcessing = false;
+ }
+
+ this.postRequest();
+ }
+
+ public void enableNotification(GattRequest gattRequest) {
+
+ boolean success = true;
+ String errorMsg = "";
+ final UUID serviceUUID = gattRequest.serviceUUID;
+ final UUID characteristicUUID = gattRequest.characteristicUUID;
+ BluetoothGattService service = this.mGatt.getService(serviceUUID);
+ if (service != null) {
+ BluetoothGattCharacteristic characteristic = this
+ .findNotifyCharacteristic(service, characteristicUUID);
+
+ if (characteristic != null) {
+
+ if (!this.mGatt.setCharacteristicNotification(characteristic,
+ true)) {
+ success = false;
+ errorMsg = "enable notification error";
+ }
+
+ } else {
+ success = false;
+ errorMsg = "no characteristic";
+ }
+ } else {
+ success = false;
+ errorMsg = "service is not offered by the remote device";
+ }
+
+ if (!success) {
+ String errInfo = "enable notification error: " + errorMsg + " - " + characteristicUUID;
+ this.onRequestError(errInfo);
+ } else {
+ this.onRequestSuccess(null);
+ }
+ this.onRequestComplete();
+ }
+
+ private void disableNotification(GattRequest gattRequest) {
+
+ boolean success = true;
+ String errorMsg = "";
+ final UUID serviceUUID = gattRequest.serviceUUID;
+ final UUID characteristicUUID = gattRequest.characteristicUUID;
+ BluetoothGattService service = this.mGatt.getService(serviceUUID);
+
+ if (service != null) {
+
+ BluetoothGattCharacteristic characteristic = this
+ .findNotifyCharacteristic(service, characteristicUUID);
+
+ if (characteristic != null) {
+ if (!this.mGatt.setCharacteristicNotification(characteristic,
+ false)) {
+ success = false;
+ errorMsg = "disable notification error";
+ }
+
+ } else {
+ success = false;
+ errorMsg = "no characteristic";
+ }
+
+ } else {
+ success = false;
+ errorMsg = "service is not offered by the remote device";
+ }
+
+ if (!success) {
+ String errInfo = "disable notification error: " + errorMsg + " - " + characteristicUUID;
+ log(errInfo);
+ this.onRequestError(errInfo);
+ } else {
+ this.onRequestSuccess(null);
+ }
+ this.onRequestComplete();
+ }
+
+
+ private void readDescriptor(GattRequest gattRequest) {
+
+ boolean success = true;
+ String errorMsg = "";
+ final UUID serviceUUID = gattRequest.serviceUUID;
+ final UUID characteristicUUID = gattRequest.characteristicUUID;
+ final UUID descriptorUUID = gattRequest.descriptorUUID;
+ BluetoothGattService service = this.mGatt.getService(serviceUUID);
+
+ if (service != null) {
+
+ BluetoothGattCharacteristic characteristic = service
+ .getCharacteristic(characteristicUUID);
+
+ if (characteristic != null) {
+
+ BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descriptorUUID);
+ if (descriptor != null) {
+ if (!this.mGatt.readDescriptor(descriptor)) {
+ success = false;
+ errorMsg = "read descriptor error";
+ }
+ } else {
+ success = false;
+ errorMsg = "read descriptor error - descriptor not found";
+ }
+
+ } else {
+ success = false;
+ errorMsg = "read characteristic error - characteristic not found";
+ }
+ } else {
+ success = false;
+ errorMsg = "service is not offered by the remote device";
+ }
+
+ if (!success) {
+ this.onRequestError(errorMsg);
+ this.onRequestComplete();
+ }
+ }
+
+ private void writeDescriptor(GattRequest gattRequest) {
+
+ boolean success = true;
+ String errorMsg = "";
+ final UUID serviceUUID = gattRequest.serviceUUID;
+ final UUID characteristicUUID = gattRequest.characteristicUUID;
+ final UUID descriptorUUID = gattRequest.descriptorUUID;
+ byte[] data = gattRequest.data;
+ BluetoothGattService service = this.mGatt.getService(serviceUUID);
+
+ if (service != null) {
+ BluetoothGattCharacteristic characteristic = service.getCharacteristic(characteristicUUID);
+
+ if (characteristic != null) {
+
+ BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descriptorUUID);
+ if (descriptor != null) {
+ descriptor.setValue(data);
+ if (!this.mGatt.writeDescriptor(descriptor)) {
+ success = false;
+ errorMsg = "write characteristic error";
+ }
+ } else {
+ success = false;
+ errorMsg = "no descriptor";
+ }
+
+
+ } else {
+ success = false;
+ errorMsg = "no characteristic";
+ }
+ } else {
+ success = false;
+ errorMsg = "service is not offered by the remote device";
+ }
+
+ if (!success) {
+ this.onRequestError(errorMsg);
+ this.onRequestComplete();
+ }
+ }
+
+
+ private void readCharacteristic(GattRequest request) {
+
+ boolean success = true;
+ String errorMsg = "";
+ final UUID serviceUUID = request.serviceUUID;
+ final UUID characteristicUUID = request.characteristicUUID;
+ BluetoothGattService service = this.mGatt.getService(serviceUUID);
+
+ if (service != null) {
+ BluetoothGattCharacteristic characteristic = service
+ .getCharacteristic(characteristicUUID);
+
+ if (characteristic != null) {
+
+ if (!this.mGatt.readCharacteristic(characteristic)) {
+ success = false;
+ errorMsg = "read characteristic error";
+ }
+
+ } else {
+ success = false;
+ errorMsg = "read characteristic error - characteristic not found";
+ }
+ } else {
+ success = false;
+ errorMsg = "service is not offered by the remote device";
+ }
+
+ if (!success) {
+ this.onRequestError(errorMsg);
+ this.onRequestComplete();
+ }
+ }
+
+ private void writeCharacteristic(GattRequest gattRequest,
+ int writeType) {
+
+ boolean success = true;
+ String errorMsg = "";
+ final UUID serviceUUID = gattRequest.serviceUUID;
+ final UUID characteristicUUID = gattRequest.characteristicUUID;
+ final byte[] data = gattRequest.data;
+ BluetoothGattService service = this.mGatt.getService(serviceUUID);
+
+ if (service != null) {
+ BluetoothGattCharacteristic characteristic = this
+ .findWritableCharacteristic(service, characteristicUUID,
+ writeType);
+ if (characteristic != null) {
+
+ characteristic.setValue(data);
+ characteristic.setWriteType(writeType);
+
+ if (!this.mGatt.writeCharacteristic(characteristic)) {
+ success = false;
+ errorMsg = "write characteristic error";
+ }
+
+ } else {
+ success = false;
+ errorMsg = "no characteristic";
+ }
+ } else {
+ success = false;
+ errorMsg = "service is not offered by the remote device";
+ }
+
+ if (!success) {
+ this.onRequestError(errorMsg);
+ this.onRequestComplete();
+ }
+ }
+
+
+ private BluetoothGattCharacteristic findWritableCharacteristic(
+ BluetoothGattService service, UUID characteristicUUID, int writeType) {
+
+ BluetoothGattCharacteristic characteristic = null;
+
+ int writeProperty = BluetoothGattCharacteristic.PROPERTY_WRITE;
+
+ if (writeType == BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) {
+ writeProperty = BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE;
+ }
+
+ List characteristics = service
+ .getCharacteristics();
+
+ for (BluetoothGattCharacteristic c : characteristics) {
+ if ((c.getProperties() & writeProperty) != 0
+ && characteristicUUID.equals(c.getUuid())) {
+ characteristic = c;
+ break;
+ }
+ }
+
+ return characteristic;
+ }
+
+ private BluetoothGattCharacteristic findNotifyCharacteristic(
+ BluetoothGattService service, UUID characteristicUUID) {
+
+ BluetoothGattCharacteristic characteristic = null;
+
+ List characteristics = service
+ .getCharacteristics();
+
+ for (BluetoothGattCharacteristic c : characteristics) {
+ if ((c.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0
+ && characteristicUUID.equals(c.getUuid())) {
+ characteristic = c;
+ break;
+ }
+ }
+
+ if (characteristic != null)
+ return characteristic;
+
+ for (BluetoothGattCharacteristic c : characteristics) {
+ if ((c.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0
+ && characteristicUUID.equals(c.getUuid())) {
+ characteristic = c;
+ break;
+ }
+ }
+
+ return characteristic;
+ }
+
+ /************************************************************************
+ * gatt [end]
+ ************************************************************************/
+
+
+ /************************************************************************
+ * gatt callback [start]
+ ************************************************************************/
+
+ /**
+ * gatt#setPreferredPhy callback
+ */
+ @Override
+ public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
+ super.onPhyUpdate(gatt, txPhy, rxPhy, status);
+
+ }
+
+ /**
+ * gatt#readPhy callback
+ */
+ @Override
+ public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
+ super.onPhyRead(gatt, txPhy, rxPhy, status);
+ }
+
+ /**
+ * connection/disconnection callback
+ */
+ @Override
+ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+ log("onConnectionStateChange status :" + status + " state : " + newState);
+ if (newState == BluetoothGatt.STATE_CONNECTED) {
+ synchronized (CONNECTION_STATE_LOCK) {
+ this.mConnectionState = CONN_STATE_CONNECTED;
+ }
+ this.onConnected();
+ startServicesDiscovering();
+ } else {
+ synchronized (this.CONNECTION_STATE_LOCK) {
+ log("Close");
+ if (this.mGatt != null) {
+ this.mGatt.close();
+ }
+ this.clear();
+ this.mConnectionState = CONN_STATE_IDLE;
+ this.onDisconnected();
+ }
+ }
+
+ }
+
+ /**
+ * gatt#discoverServices callback
+ */
+ @Override
+ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ List services = gatt.getServices();
+ this.mServices = services;
+ this.onServicesDiscoveredComplete(services);
+ } else {
+ log("Service discovery failed");
+ this.disconnect();
+ }
+ }
+
+ @Override
+ public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
+ super.onCharacteristicRead(gatt, characteristic, status);
+ this.cancelCommandTimeoutTask();
+ if (gattStatusSuccess(status)) {
+ byte[] data = characteristic.getValue();
+ this.onRequestSuccess(data);
+ } else {
+ this.onRequestError("read characteristic failed");
+ }
+ this.onRequestComplete();
+ }
+
+ @Override
+ public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
+ super.onCharacteristicWrite(gatt, characteristic, status);
+ this.cancelCommandTimeoutTask();
+ if (gattStatusSuccess(status)) {
+ this.onRequestSuccess(null);
+ } else {
+ this.onRequestError("write characteristic fail");
+ }
+ this.onRequestComplete();
+ }
+
+ @Override
+ public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ super.onCharacteristicChanged(gatt, characteristic);
+ this.onNotify(characteristic, characteristic.getValue());
+ }
+
+ @Override
+ public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ super.onDescriptorRead(gatt, descriptor, status);
+ this.cancelCommandTimeoutTask();
+ if (gattStatusSuccess(status)) {
+ this.onRequestSuccess(descriptor.getValue());
+ } else {
+ this.onRequestError("read descriptor fail");
+ }
+ this.onRequestComplete();
+ }
+
+ @Override
+ public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ super.onDescriptorWrite(gatt, descriptor, status);
+ this.cancelCommandTimeoutTask();
+ if (gattStatusSuccess(status)) {
+ this.onRequestSuccess(null);
+ } else {
+ this.onRequestError("write descriptor fail");
+ }
+ this.onRequestComplete();
+ }
+
+ @Override
+ public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
+ super.onReliableWriteCompleted(gatt, status);
+ }
+
+ @Override
+ public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
+ super.onReadRemoteRssi(gatt, rssi, status);
+ }
+
+ @Override
+ public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
+ log("onMtuChanged: " + mtu);
+ super.onMtuChanged(gatt, mtu, status);
+ if (gattStatusSuccess(status)) {
+ this.mtu = mtu;
+ }
+ }
+
+ /************************************************************************
+ * gatt callback [end]
+ ************************************************************************/
+
+ private final class ConnectionTimeoutRunnable implements Runnable {
+
+ @Override
+ public void run() {
+ if (!disconnect()) {
+ onDisconnected();
+ }
+ }
+ }
+
+ private final class DisconnectionTimeoutRunnable implements Runnable {
+
+ @Override
+ public void run() {
+ log("disconnection timeout");
+ synchronized (CONNECTION_STATE_LOCK) {
+ if (mGatt != null) {
+ mGatt.disconnect();
+ mGatt.close();
+ }
+ mConnectionState = CONN_STATE_IDLE;
+ onDisconnected();
+ }
+
+ }
+ }
+
+ private final class ServicesDiscoveringRunnable implements Runnable {
+
+ @Override
+ public void run() {
+ if (mGatt == null || !mGatt.discoverServices()) {
+ disconnect();
+ } else {
+ log("start services discovering");
+ }
+ }
+ }
+
+ private final class CommandTimeoutRunnable implements Runnable {
+
+ @Override
+ public void run() {
+
+ synchronized (mGattRequestQueue) {
+
+ GattRequest gattRequest = mGattRequestQueue.peek();
+
+ if (gattRequest != null) {
+
+ boolean retry = onRequestTimeout(gattRequest);
+
+ if (retry) {
+ processRequest(gattRequest);
+ } else {
+ gattRequest.clear();
+ mGattRequestQueue.poll();
+ onRequestComplete();
+ }
+ }
+ }
+ }
+ }
+
+
+ private boolean gattStatusSuccess(int status) {
+ return status == BluetoothGatt.GATT_SUCCESS;
+ }
+
+ /**
+ * gatt status description
+ *
+ * @param status gatt status
+ * @return desc
+ */
+ private String getGattStatusDesc(int status) {
+ switch (status) {
+ case BluetoothGatt.GATT_SUCCESS:
+ return "success";
+ case BluetoothGatt.GATT_READ_NOT_PERMITTED:
+ return "read not permitted";
+
+ case BluetoothGatt.GATT_WRITE_NOT_PERMITTED:
+ return "write not permitted";
+
+ case BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION:
+ return "insufficient authentication";
+
+ case BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED:
+ return "request not supported";
+
+ case BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION:
+ return "insufficient encryption";
+
+ case BluetoothGatt.GATT_INVALID_OFFSET:
+ return "invalid offset";
+
+ case BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH:
+ return "invalid attribute length";
+
+ case BluetoothGatt.GATT_CONNECTION_CONGESTED:
+ return "connection congested";
+
+ case BluetoothGatt.GATT_FAILURE:
+ return "failure";
+ default:
+ return "unknown";
+ }
+ }
+
+ public interface ConnectionCallback {
+ void onConnected();
+
+ void onDisconnected();
+
+ void onServicesDiscovered(List services);
+
+ void onNotify(UUID serviceUUID, UUID charUUID, byte[] data);
+ }
+
+ private void log(String logMessage) {
+ log(logMessage, MeshLogger.LEVEL_DEBUG);
+ }
+
+ private void log(String logMessage, int level) {
+ MeshLogger.log(logMessage, LOG_TAG, level);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/GattOtaController.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/GattOtaController.java
new file mode 100644
index 00000000..871d3a20
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/GattOtaController.java
@@ -0,0 +1,280 @@
+/********************************************************************************************************
+ * @file GattOtaController.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.ble;
+
+import android.os.Build;
+import android.os.Handler;
+
+import com.telink.ble.mesh.util.MeshLogger;
+import com.telink.ble.mesh.util.OtaPacketParser;
+
+public class GattOtaController {
+
+ private final String LOG_TAG = "GATT-OTA";
+
+ public static final int OTA_STATE_SUCCESS = 1;
+ public static final int OTA_STATE_FAILURE = 0;
+ public static final int OTA_STATE_PROGRESS = 2;
+
+ protected Handler mTimeoutHandler;
+
+ private static final int OTA_PREPARE = 0xFF00;
+ private static final int OTA_START = 0xFF01;
+ private static final int OTA_END = 0xFF02;
+
+ private static final int TAG_OTA_WRITE = 1;
+ private static final int TAG_OTA_READ = 2;
+ private static final int TAG_OTA_LAST = 3;
+
+ private static final int TAG_OTA_PREPARE = 6; // prepare
+ private static final int TAG_OTA_START = 7; // start
+ private static final int TAG_OTA_END = 8; // end
+
+ private GattConnection mConnection;
+
+ private GattOtaCallback mCallback;
+
+ private final OtaPacketParser mOtaParser = new OtaPacketParser();
+
+ private int readCnt = 0;
+
+
+ private static final int DEFAULT_READ_INTERVAL = 8;
+
+ private int readInterval = DEFAULT_READ_INTERVAL;
+
+
+ public GattOtaController(GattConnection gattConnection) {
+ mTimeoutHandler = new Handler();
+ mConnection = gattConnection;
+ }
+
+ public void setCallback(GattOtaCallback callback) {
+ this.mCallback = callback;
+ }
+
+ public void begin(byte[] firmware) {
+ begin(firmware, DEFAULT_READ_INTERVAL);
+ }
+
+
+ public void begin(byte[] firmware, int readInterval) {
+ log("Start OTA");
+ this.clear();
+ this.mOtaParser.set(firmware);
+ this.readInterval = readInterval;
+ this.sendOTAPrepareCommand();
+ }
+
+ private void clear() {
+ this.readCnt = 0;
+ this.mOtaParser.clear();
+ }
+
+ private void sendRequest(GattRequest request) {
+ if (mConnection != null) {
+ mConnection.sendRequest(request);
+ }
+ }
+
+
+ public void otaWriteData(byte[] data, int tag) {
+ GattRequest cmd = GattRequest.newInstance();
+ cmd.characteristicUUID = UUIDInfo.CHARACTERISTIC_UUID_OTA;
+ cmd.serviceUUID = UUIDInfo.SERVICE_UUID_OTA;
+ cmd.data = data.clone();
+ cmd.tag = tag;
+ cmd.type = GattRequest.RequestType.WRITE_NO_RESPONSE;
+ cmd.callback = this.mOtaRequestCallback;
+ sendRequest(cmd);
+ }
+
+
+ public int getOtaProgress() {
+ return this.mOtaParser.getProgress();
+ }
+
+
+ private void setOtaProgressChanged() {
+ if (this.mOtaParser.invalidateProgress()) {
+ onOtaProgress();
+ }
+ }
+
+ private void onOtaSuccess() {
+ if (mCallback != null) {
+ mCallback.onOtaStateChanged(OTA_STATE_SUCCESS);
+ }
+ }
+
+ private void onOtaFailure() {
+ if (mCallback != null) {
+ mCallback.onOtaStateChanged(OTA_STATE_FAILURE);
+ }
+ }
+
+ private void onOtaProgress() {
+ if (mCallback != null) {
+ mCallback.onOtaStateChanged(OTA_STATE_PROGRESS);
+ }
+ }
+
+ private void sendOTAPrepareCommand() {
+ otaWriteData(new byte[]{OTA_PREPARE & 0xFF, (byte) (OTA_PREPARE >> 8 & 0xFF)}, TAG_OTA_PREPARE);
+ }
+
+ // send ota start command
+ private void sendOtaStartCommand() {
+ otaWriteData(new byte[]{OTA_START & 0xFF, (byte) (OTA_START >> 8 & 0xFF)}, TAG_OTA_START);
+ }
+
+ private void sendOtaEndCommand() {
+ int index = mOtaParser.getIndex();
+ byte[] data = new byte[6];
+ data[0] = OTA_END & 0xFF;
+ data[1] = (byte) ((OTA_END >> 8) & 0xFF);
+ data[2] = (byte) (index & 0xFF);
+ data[3] = (byte) (index >> 8 & 0xFF);
+ data[4] = (byte) (~index & 0xFF);
+ data[5] = (byte) (~index >> 8 & 0xFF);
+ otaWriteData(data, TAG_OTA_END);
+ }
+
+
+ private void sendNextOtaPacketCommand() {
+ if (this.mOtaParser.hasNextPacket()) {
+ byte[] data = this.mOtaParser.getNextPacket();
+ int tag = this.mOtaParser.isLast() ? TAG_OTA_LAST : TAG_OTA_WRITE;
+ otaWriteData(data, tag);
+
+ }
+ }
+
+ private boolean validateOta() {
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) return false;
+
+ if (readInterval <= 0) return false;
+
+ /*
+ * read
+ */
+ int sectionSize = 16 * readInterval;
+ int sendTotal = this.mOtaParser.getNextPacketIndex() * 16;
+// logMessage("ota onCommandSampled byte length : " + sendTotal);
+ if (sendTotal > 0 && sendTotal % sectionSize == 0) {
+ log("onCommandSampled ota read packet " + mOtaParser.getNextPacketIndex(), MeshLogger.LEVEL_VERBOSE);
+ GattRequest cmd = GattRequest.newInstance();
+ cmd.serviceUUID = UUIDInfo.SERVICE_UUID_OTA;
+ cmd.characteristicUUID = UUIDInfo.CHARACTERISTIC_UUID_OTA;
+ cmd.type = GattRequest.RequestType.READ;
+ cmd.tag = TAG_OTA_READ;
+ cmd.callback = mOtaRequestCallback;
+ readCnt++;
+ log("cur read count: " + readCnt);
+ this.sendRequest(cmd);
+ return true;
+ }
+ return false;
+ }
+
+
+ private void onOTACmdSuccess(GattRequest command, Object data) {
+
+ if (command.tag.equals(TAG_OTA_PREPARE)) {
+ sendOtaStartCommand();
+ } else if (command.tag.equals(TAG_OTA_START)) {
+ sendNextOtaPacketCommand();
+ } else if (command.tag.equals(TAG_OTA_END)) {
+ setOtaProgressChanged();
+ clear();
+ onOtaSuccess();
+ } else if (command.tag.equals(TAG_OTA_LAST)) {
+ sendOtaEndCommand();
+ } else if (command.tag.equals(TAG_OTA_WRITE)) {
+ if (!validateOta()) {
+ sendNextOtaPacketCommand();
+ }
+ setOtaProgressChanged();
+ } else if (command.tag.equals(TAG_OTA_READ)) {
+ sendNextOtaPacketCommand();
+ }
+
+
+ }
+
+ private void onOtaCmdError(GattRequest request) {
+ if (request.tag.equals(TAG_OTA_END)) {
+ // ota success
+ setOtaProgressChanged();
+ clear();
+ onOtaSuccess();
+ } else {
+ clear();
+ onOtaFailure();
+ }
+ }
+
+ private void onOtaCmdTimeout(GattRequest request) {
+ if (request.tag.equals(TAG_OTA_END)) {
+ // ota success
+ setOtaProgressChanged();
+ clear();
+ onOtaSuccess();
+ } else {
+ clear();
+ onOtaFailure();
+ }
+ }
+
+ private GattRequest.Callback mOtaRequestCallback = new GattRequest.Callback() {
+ @Override
+ public void success(GattRequest request, Object obj) {
+ onOTACmdSuccess(request, obj);
+ }
+
+ @Override
+ public void error(GattRequest request, String errorMsg) {
+ onOtaCmdError(request);
+ }
+
+ @Override
+ public boolean timeout(GattRequest request) {
+ onOtaCmdTimeout(request);
+ return false;
+ }
+ };
+
+
+ public interface GattOtaCallback {
+ void onOtaStateChanged(int state);
+ }
+
+ private void log(String logMessage) {
+ log(logMessage, MeshLogger.LEVEL_DEBUG);
+ }
+
+ private void log(String logMessage, int level) {
+ MeshLogger.log(logMessage, LOG_TAG, level);
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/GattRequest.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/GattRequest.java
new file mode 100644
index 00000000..b5a0d927
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/GattRequest.java
@@ -0,0 +1,102 @@
+/********************************************************************************************************
+ * @file GattRequest.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+
+package com.telink.ble.mesh.core.ble;
+
+
+import com.telink.ble.mesh.util.Arrays;
+
+import java.util.UUID;
+
+public class GattRequest {
+
+ public UUID serviceUUID;
+ public UUID characteristicUUID;
+ public UUID descriptorUUID;
+ public RequestType type;
+ public byte[] data;
+ public Object tag;
+ public int delay;
+ public Callback callback;
+
+ public GattRequest() {
+ this(null, null, RequestType.WRITE);
+ }
+
+ public GattRequest(UUID serviceUUID, UUID characteristicUUID, RequestType type) {
+ this(serviceUUID, characteristicUUID, type, null);
+ }
+
+ public GattRequest(UUID serviceUUID, UUID characteristicUUID, RequestType type,
+ byte[] data) {
+ this(serviceUUID, characteristicUUID, type, data, null);
+ }
+
+ public GattRequest(UUID serviceUUID, UUID characteristicUUID, RequestType type,
+ byte[] data, Object tag) {
+
+ this.serviceUUID = serviceUUID;
+ this.characteristicUUID = characteristicUUID;
+ this.type = type;
+ this.data = data;
+ this.tag = tag;
+ }
+
+ public static GattRequest newInstance() {
+ return new GattRequest();
+ }
+
+ public void clear() {
+ this.serviceUUID = null;
+ this.characteristicUUID = null;
+ this.descriptorUUID = null;
+ this.data = null;
+ }
+
+ @Override
+ public String toString() {
+ String d;
+ if (data != null) {
+ d = Arrays.bytesToHexString(this.data);
+ } else {
+ d = "null";
+ }
+ return "{ tag : " + this.tag + ", type : " + this.type
+ + " CHARACTERISTIC_UUID :" + characteristicUUID.toString() + " data: " + d + " delay :" + delay + "}";
+ }
+
+ public enum RequestType {
+ READ, READ_DESCRIPTOR, WRITE, WRITE_NO_RESPONSE, WRITE_DESCRIPTOR, ENABLE_NOTIFY, DISABLE_NOTIFY
+ }
+
+ public interface Callback {
+
+ void success(GattRequest request, Object obj);
+
+ void error(GattRequest request, String errorMsg);
+
+ /**
+ * @return retry
+ */
+ boolean timeout(GattRequest request);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/LeScanFilter.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/LeScanFilter.java
new file mode 100644
index 00000000..6706eb00
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/LeScanFilter.java
@@ -0,0 +1,44 @@
+/********************************************************************************************************
+ * @file LeScanFilter.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.ble;
+
+
+import java.util.UUID;
+
+/**
+ * Created by kee on 2018/7/19.
+ */
+
+public class LeScanFilter {
+
+ // null means not in filter
+
+ public UUID[] uuidInclude = null;
+
+ public String[] macInclude = null;
+
+ public String[] macExclude = null;
+
+// public int[] companyIdInclude = null;
+
+ public String[] nameInclude = null;
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/LeScanSetting.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/LeScanSetting.java
new file mode 100644
index 00000000..67bafea9
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/LeScanSetting.java
@@ -0,0 +1,54 @@
+/********************************************************************************************************
+ * @file LeScanSetting.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.ble;
+
+/**
+ * Created by kee on 2019/9/9.
+ */
+
+public class LeScanSetting {
+
+ /**
+ * time between last scanning start time
+ */
+ public long spacing;
+
+ /**
+ * time of scanning
+ */
+ public long timeout;
+
+ public static LeScanSetting getDefault() {
+ LeScanSetting setting = new LeScanSetting();
+ setting.spacing = 5 * 1000;
+ setting.timeout = 60 * 1000;
+ return setting;
+ }
+
+ public LeScanSetting() {
+ }
+
+ public LeScanSetting(long spacing, long during) {
+ this.spacing = spacing;
+ this.timeout = during;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/MeshBluetoothUUID.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/MeshBluetoothUUID.java
new file mode 100644
index 00000000..9482ff95
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/MeshBluetoothUUID.java
@@ -0,0 +1,305 @@
+/********************************************************************************************************
+ * @file MeshBluetoothUUID.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.ble;
+
+import android.os.ParcelUuid;
+
+import com.telink.ble.mesh.core.MeshUtils;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.UUID;
+
+/**
+ * Created by kee on 2019/2/28.
+ */
+
+
+public final class MeshBluetoothUUID {
+ /*
+ * See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs for the
+ * various services. The following 128 bit values are calculated as: uuid * 2^96 + BASE_UUID
+ */
+ public static final ParcelUuid AudioSink =
+ ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid AudioSource =
+ ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid AdvAudioDist =
+ ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid HSP =
+ ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid HSP_AG =
+ ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid Handsfree =
+ ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid Handsfree_AG =
+ ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid AvrcpController =
+ ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid AvrcpTarget =
+ ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid ObexObjectPush =
+ ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
+ public static final ParcelUuid Hid =
+ ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
+ public static final ParcelUuid Hogp =
+ ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
+ public static final ParcelUuid PANU =
+ ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid NAP =
+ ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid BNEP =
+ ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid PBAP_PSE =
+ ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid MAP =
+ ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid MNS =
+ ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid MAS =
+ ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid BASE_UUID =
+ ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
+ /** Length of bytes for 16 bit UUID */
+ public static final int UUID_BYTES_16_BIT = 2;
+ /** Length of bytes for 32 bit UUID */
+ public static final int UUID_BYTES_32_BIT = 4;
+ /** Length of bytes for 128 bit UUID */
+ public static final int UUID_BYTES_128_BIT = 16;
+ public static final ParcelUuid[] RESERVED_UUIDS = {
+ AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
+ ObexObjectPush, PANU, NAP, MAP, MNS, MAS };
+
+ public static boolean isAudioSource(ParcelUuid uuid) {
+ return uuid.equals(AudioSource);
+ }
+
+ public static boolean isAudioSink(ParcelUuid uuid) {
+ return uuid.equals(AudioSink);
+ }
+
+ public static boolean isAdvAudioDist(ParcelUuid uuid) {
+ return uuid.equals(AdvAudioDist);
+ }
+
+ public static boolean isHandsfree(ParcelUuid uuid) {
+ return uuid.equals(Handsfree);
+ }
+
+ public static boolean isHeadset(ParcelUuid uuid) {
+ return uuid.equals(HSP);
+ }
+
+ public static boolean isAvrcpController(ParcelUuid uuid) {
+ return uuid.equals(AvrcpController);
+ }
+
+ public static boolean isAvrcpTarget(ParcelUuid uuid) {
+ return uuid.equals(AvrcpTarget);
+ }
+
+ public static boolean isInputDevice(ParcelUuid uuid) {
+ return uuid.equals(Hid);
+ }
+
+ public static boolean isPanu(ParcelUuid uuid) {
+ return uuid.equals(PANU);
+ }
+
+ public static boolean isNap(ParcelUuid uuid) {
+ return uuid.equals(NAP);
+ }
+
+ public static boolean isBnep(ParcelUuid uuid) {
+ return uuid.equals(BNEP);
+ }
+
+ public static boolean isMap(ParcelUuid uuid) {
+ return uuid.equals(MAP);
+ }
+
+ public static boolean isMns(ParcelUuid uuid) {
+ return uuid.equals(MNS);
+ }
+
+ public static boolean isMas(ParcelUuid uuid) {
+ return uuid.equals(MAS);
+ }
+
+ /**
+ * Returns true if ParcelUuid is present in uuidArray
+ *
+ * @param uuidArray - Array of ParcelUuids
+ * @param uuid
+ */
+ public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
+ if ((uuidArray == null || uuidArray.length == 0) && uuid == null) {
+ return true;
+ }
+ if (uuidArray == null) {
+ return false;
+ }
+ for (ParcelUuid element : uuidArray) {
+ if (element.equals(uuid)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if there any common ParcelUuids in uuidA and uuidB.
+ *
+ * @param uuidA - List of ParcelUuids
+ * @param uuidB - List of ParcelUuids
+ */
+ public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
+ if (uuidA == null && uuidB == null) {
+ return true;
+ }
+ if (uuidA == null) {
+ return uuidB.length == 0 ? true : false;
+ }
+ if (uuidB == null) {
+ return uuidA.length == 0 ? true : false;
+ }
+ HashSet uuidSet = new HashSet(Arrays.asList(uuidA));
+ for (ParcelUuid uuid : uuidB) {
+ if (uuidSet.contains(uuid)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if all the ParcelUuids in ParcelUuidB are present in ParcelUuidA
+ *
+ * @param uuidA - Array of ParcelUuidsA
+ * @param uuidB - Array of ParcelUuidsB
+ */
+ public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
+ if (uuidA == null && uuidB == null) {
+ return true;
+ }
+ if (uuidA == null) {
+ return uuidB.length == 0 ? true : false;
+ }
+ if (uuidB == null) {
+ return true;
+ }
+ HashSet uuidSet = new HashSet(Arrays.asList(uuidA));
+ for (ParcelUuid uuid : uuidB) {
+ if (!uuidSet.contains(uuid)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Extract the Service Identifier or the actual uuid from the Parcel Uuid. For example, if
+ * 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid, this function will return 110B
+ *
+ * @param parcelUuid
+ * @return the service identifier.
+ */
+ public static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) {
+ UUID uuid = parcelUuid.getUuid();
+ long value = (uuid.getMostSignificantBits() & 0x0000FFFF00000000L) >>> 32;
+ return (int) value;
+ }
+
+ /**
+ * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID,
+ * but the returned UUID is always in 128-bit format. Note UUID is little endian in Bluetooth.
+ *
+ * @param uuidBytes Byte representation of uuid.
+ * @return {@link ParcelUuid} parsed from bytes.
+ * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
+ */
+ public static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
+ if (uuidBytes == null) {
+ throw new IllegalArgumentException("uuidBytes cannot be null");
+ }
+ int length = uuidBytes.length;
+ if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT &&
+ length != UUID_BYTES_128_BIT) {
+ throw new IllegalArgumentException("uuidBytes length invalid - " + length);
+ }
+ // Construct a 128 bit UUID.
+ if (length == UUID_BYTES_128_BIT) {
+ ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
+ long msb = buf.getLong(8);
+ long lsb = buf.getLong(0);
+ return new ParcelUuid(new UUID(msb, lsb));
+ }
+ // For 16 bit and 32 bit UUID we need to convert them to 128 bit value.
+ // 128_bit_value = uuid * 2^96 + BASE_UUID
+ long shortUuid;
+ if (length == UUID_BYTES_16_BIT) {
+ shortUuid = uuidBytes[0] & 0xFF;
+ shortUuid += (uuidBytes[1] & 0xFF) << 8;
+ } else {
+ shortUuid = uuidBytes[0] & 0xFF;
+ shortUuid += (uuidBytes[1] & 0xFF) << 8;
+ shortUuid += (uuidBytes[2] & 0xFF) << 16;
+ shortUuid += (uuidBytes[3] & 0xFF) << 24;
+ }
+ long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32);
+ long lsb = BASE_UUID.getUuid().getLeastSignificantBits();
+ return new ParcelUuid(new UUID(msb, lsb));
+ }
+
+ /**
+ * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid.
+ *
+ * @param parcelUuid
+ * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
+ */
+ public static boolean is16BitUuid(ParcelUuid parcelUuid) {
+ UUID uuid = parcelUuid.getUuid();
+ if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
+ return false;
+ }
+ return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
+ }
+
+ /**
+ * Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid.
+ *
+ * @param parcelUuid
+ * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise.
+ */
+ public static boolean is32BitUuid(ParcelUuid parcelUuid) {
+ UUID uuid = parcelUuid.getUuid();
+ if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
+ return false;
+ }
+ if (is16BitUuid(parcelUuid)) {
+ return false;
+ }
+ return ((uuid.getMostSignificantBits() & MeshUtils.UNSIGNED_INTEGER_MAX) == 0x1000L);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/MeshScanRecord.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/MeshScanRecord.java
new file mode 100644
index 00000000..06c2b64c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/MeshScanRecord.java
@@ -0,0 +1,278 @@
+/********************************************************************************************************
+ * @file MeshScanRecord.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.ble;
+
+import android.os.ParcelUuid;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Created by kee on 2019/2/28.
+ */
+
+public class MeshScanRecord {
+
+ private static final int DATA_TYPE_FLAGS = 0x01;
+ private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02;
+ private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;
+ private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04;
+ private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05;
+ private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06;
+ private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07;
+ private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;
+ private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
+ private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
+ private static final int DATA_TYPE_SERVICE_DATA = 0x16;
+ private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
+
+ // Flags of the advertising data.
+ private final int mAdvertiseFlags;
+
+ @Nullable
+ private final List mServiceUuids;
+
+ private final SparseArray mManufacturerSpecificData;
+
+ private final Map mServiceData;
+
+ // Transmission power level(in dB).
+ private final int mTxPowerLevel;
+
+ // Local name of the Bluetooth LE device.
+ private final String mDeviceName;
+
+ // Raw bytes of scan record.
+ private final byte[] mBytes;
+
+
+ /**
+ * Returns the advertising flags indicating the discoverable mode and capability of the device.
+ * Returns -1 if the flag field is not set.
+ */
+ public int getAdvertiseFlags() {
+ return mAdvertiseFlags;
+ }
+
+ /**
+ * Returns a list of service UUIDs within the advertisement that are used to identify the
+ * bluetooth GATT services.
+ */
+ public List getServiceUuids() {
+ return mServiceUuids;
+ }
+
+ /**
+ * Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific
+ * data.
+ */
+ public SparseArray getManufacturerSpecificData() {
+ return mManufacturerSpecificData;
+ }
+
+ /**
+ * Returns the manufacturer specific data associated with the manufacturer id. Returns
+ * {@code null} if the {@code manufacturerId} is not found.
+ */
+ @Nullable
+ public byte[] getManufacturerSpecificData(int manufacturerId) {
+ return mManufacturerSpecificData.get(manufacturerId);
+ }
+
+ /**
+ * Returns a map of service UUID and its corresponding service data.
+ */
+ public Map getServiceData() {
+ return mServiceData;
+ }
+
+ /**
+ * Returns the service data byte array associated with the {@code serviceUuid}. Returns
+ * {@code null} if the {@code serviceDataUuid} is not found.
+ */
+ @Nullable
+ public byte[] getServiceData(ParcelUuid serviceDataUuid) {
+ if (serviceDataUuid == null) {
+ return null;
+ }
+ return mServiceData.get(serviceDataUuid);
+ }
+
+ /**
+ * Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE}
+ * if the field is not set. This value can be used to calculate the path loss of a received
+ * packet using the following equation:
+ *
+ * pathloss = txPowerLevel - rssi
+ */
+ public int getTxPowerLevel() {
+ return mTxPowerLevel;
+ }
+
+ /**
+ * Returns the local name of the BLE device. The is a UTF-8 encoded string.
+ */
+ @Nullable
+ public String getDeviceName() {
+ return mDeviceName;
+ }
+
+ /**
+ * Returns raw bytes of scan record.
+ */
+ public byte[] getBytes() {
+ return mBytes;
+ }
+
+ private MeshScanRecord(List serviceUuids,
+ SparseArray manufacturerData,
+ Map serviceData,
+ int advertiseFlags, int txPowerLevel,
+ String localName, byte[] bytes) {
+ mServiceUuids = serviceUuids;
+ mManufacturerSpecificData = manufacturerData;
+ mServiceData = serviceData;
+ mDeviceName = localName;
+ mAdvertiseFlags = advertiseFlags;
+ mTxPowerLevel = txPowerLevel;
+ mBytes = bytes;
+ }
+
+
+ public static MeshScanRecord parseFromBytes(byte[] scanRecord) {
+ if (scanRecord == null) {
+ return null;
+ }
+
+ int currentPos = 0;
+ int advertiseFlag = -1;
+ List serviceUuids = new ArrayList();
+ String localName = null;
+ int txPowerLevel = Integer.MIN_VALUE;
+
+ SparseArray manufacturerData = new SparseArray();
+ Map serviceData = new HashMap<>();
+
+ try {
+ while (currentPos < scanRecord.length) {
+ // length is unsigned int.
+ int length = scanRecord[currentPos++] & 0xFF;
+ if (length == 0) {
+ break;
+ }
+ // Note the length includes the length of the field type itself.
+ int dataLength = length - 1;
+ // fieldType is unsigned int.
+ int fieldType = scanRecord[currentPos++] & 0xFF;
+ switch (fieldType) {
+ case DATA_TYPE_FLAGS:
+ advertiseFlag = scanRecord[currentPos] & 0xFF;
+ break;
+ case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:
+ case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:
+ parseServiceUuid(scanRecord, currentPos,
+ dataLength, MeshBluetoothUUID.UUID_BYTES_16_BIT, serviceUuids);
+ break;
+ case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:
+ case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:
+ parseServiceUuid(scanRecord, currentPos, dataLength,
+ MeshBluetoothUUID.UUID_BYTES_32_BIT, serviceUuids);
+ break;
+ case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:
+ case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:
+ parseServiceUuid(scanRecord, currentPos, dataLength,
+ MeshBluetoothUUID.UUID_BYTES_128_BIT, serviceUuids);
+ break;
+ case DATA_TYPE_LOCAL_NAME_SHORT:
+ case DATA_TYPE_LOCAL_NAME_COMPLETE:
+ localName = new String(
+ extractBytes(scanRecord, currentPos, dataLength));
+ break;
+ case DATA_TYPE_TX_POWER_LEVEL:
+ txPowerLevel = scanRecord[currentPos];
+ break;
+ case DATA_TYPE_SERVICE_DATA:
+ // The first two bytes of the service data are service data UUID in little
+ // endian. The rest bytes are service data.
+ int serviceUuidLength = MeshBluetoothUUID.UUID_BYTES_16_BIT;
+ byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
+ serviceUuidLength);
+ ParcelUuid serviceDataUuid = MeshBluetoothUUID.parseUuidFrom(
+ serviceDataUuidBytes);
+ byte[] serviceDataArray = extractBytes(scanRecord,
+ currentPos + serviceUuidLength, dataLength - serviceUuidLength);
+ serviceData.put(serviceDataUuid, serviceDataArray);
+ break;
+ case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
+ // The first two bytes of the manufacturer specific data are
+ // manufacturer ids in little endian.
+ int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +
+ (scanRecord[currentPos] & 0xFF);
+ byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2,
+ dataLength - 2);
+ manufacturerData.put(manufacturerId, manufacturerDataBytes);
+ break;
+ default:
+ // Just ignore, we don't handle such data type.
+ break;
+ }
+ currentPos += dataLength;
+ }
+
+ if (serviceUuids.isEmpty()) {
+ serviceUuids = null;
+ }
+ return new MeshScanRecord(serviceUuids, manufacturerData, serviceData,
+ advertiseFlag, txPowerLevel, localName, scanRecord);
+ } catch (Exception e) {
+ // As the record is invalid, ignore all the parsed results for this packet
+ // and return an empty record with raw scanRecord bytes in results
+ return new MeshScanRecord(null, null, null, -1, Integer.MIN_VALUE, null, scanRecord);
+ }
+ }
+
+
+ private static int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength,
+ int uuidLength, List serviceUuids) {
+ while (dataLength > 0) {
+ byte[] uuidBytes = extractBytes(scanRecord, currentPos,
+ uuidLength);
+ serviceUuids.add(MeshBluetoothUUID.parseUuidFrom(uuidBytes));
+ dataLength -= uuidLength;
+ currentPos += uuidLength;
+ }
+ return currentPos;
+ }
+
+
+ // Helper method to extract bytes from byte array.
+ private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
+ byte[] bytes = new byte[length];
+ System.arraycopy(scanRecord, start, bytes, 0, length);
+ return bytes;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/UUIDInfo.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/UUIDInfo.java
new file mode 100644
index 00000000..588fd217
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/ble/UUIDInfo.java
@@ -0,0 +1,55 @@
+/********************************************************************************************************
+ * @file UUIDInfo.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.ble;
+
+import java.util.UUID;
+
+/**
+ * Created by kee on 2018/7/19.
+ */
+
+public class UUIDInfo {
+
+ public static final UUID SERVICE_UUID_OTA = UUID.fromString("00010203-0405-0607-0809-0A0B0C0D1912");
+ public static final UUID CHARACTERISTIC_UUID_OTA = UUID.fromString("00010203-0405-0607-0809-0A0B0C0D2B12");
+
+ public static final UUID SERVICE_MESH_FLEX = UUID.fromString("00007FDD-0000-1000-8000-00805F9B34FB");
+
+ public static final UUID SERVICE_PROVISION = UUID.fromString("00001827-0000-1000-8000-00805F9B34FB");
+ public static final UUID CHARACTERISTIC_PB_IN = UUID.fromString("00002ADB-0000-1000-8000-00805F9B34FB");
+ public static final UUID CHARACTERISTIC_PB_OUT = UUID.fromString("00002ADC-0000-1000-8000-00805F9B34FB");
+
+ public static final UUID SERVICE_PROXY = UUID.fromString("00001828-0000-1000-8000-00805F9B34FB");
+ public static final UUID CHARACTERISTIC_PROXY_IN = UUID.fromString("00002ADD-0000-1000-8000-00805F9B34FB");
+ public static final UUID CHARACTERISTIC_PROXY_OUT = UUID.fromString("00002ADE-0000-1000-8000-00805F9B34FB");
+
+ public static final UUID SERVICE_ONLINE_STATUS = UUID.fromString("00010203-0405-0607-0809-0A0B0C0D1A10");
+ public static final UUID CHARACTERISTIC_ONLINE_STATUS = UUID.fromString("00010203-0405-0607-0809-0A0B0C0D1A11");
+
+ public static final UUID DESCRIPTOR_CFG_UUID = UUID.fromString("00002902-0000-1000-8000-00805F9B34FB");
+
+ public static final UUID SERVICE_DEVICE_INFO = UUID.fromString("0000180A-0000-1000-8000-00805F9B34FB");
+
+ public static final UUID CHARACTERISTIC_FW_VERSION = UUID.fromString("00002A26-0000-1000-8000-00805F9B34FB");
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/HeartbeatStatus.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/HeartbeatStatus.java
new file mode 100644
index 00000000..3b1ddb95
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/HeartbeatStatus.java
@@ -0,0 +1,68 @@
+/********************************************************************************************************
+ * @file HeartbeatStatus.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message;
+
+import com.telink.ble.mesh.core.MeshUtils;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/23.
+ */
+public class HeartbeatStatus {
+
+ /**
+ * Reserved for Future Use
+ */
+ private int rfu;
+
+ /**
+ * 7 bits
+ * Initial TTL used when sending the message
+ */
+ private int initTTL;
+
+ /**
+ * Bit field of currently active features of the node
+ */
+ private int features;
+
+ public void parse(byte[] transportPdu) {
+ this.rfu = (transportPdu[0] & 0xFF) >> 7;
+ this.initTTL = transportPdu[0] & 0x7F;
+ this.features = MeshUtils.bytes2Integer(new byte[]{transportPdu[1], transportPdu[2]},
+ ByteOrder.BIG_ENDIAN);
+ }
+
+
+ public int getRfu() {
+ return rfu;
+ }
+
+ public int getInitTTL() {
+ return initTTL;
+ }
+
+ public int getFeatures() {
+ return features;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/MeshMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/MeshMessage.java
new file mode 100644
index 00000000..8f3fc2f5
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/MeshMessage.java
@@ -0,0 +1,266 @@
+/********************************************************************************************************
+ * @file MeshMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message;
+
+import com.telink.ble.mesh.core.networking.AccessLayerPDU;
+import com.telink.ble.mesh.core.networking.AccessType;
+
+/**
+ * Created by kee on 2019/8/14.
+ */
+public class MeshMessage {
+
+ /**
+ * access message
+ */
+ public static final int CTL_ACCESS = 0;
+
+ /**
+ * control message
+ * never used by api
+ */
+ public static final int CTL_CONTROL = 1;
+
+ /**
+ * default retry count
+ */
+ public static final int DEFAULT_RETRY_CNT = 2;
+
+ /**
+ * default szmic
+ */
+ public static final int DEFAULT_ASZMIC = 0;
+
+ /**
+ * invalid opcode
+ */
+ public static final int OPCODE_INVALID = -1;
+
+ public static final int DEFAULT_TTL = 10;
+
+ /**
+ * message opcode
+ * {@link AccessLayerPDU#opcode}
+ */
+ protected int opcode;
+
+ /**
+ * message params
+ * {@link AccessLayerPDU#params}
+ */
+ protected byte[] params;
+
+ /**
+ * device key or appliction key determined by accessType {@link #accessType}
+ */
+ protected byte[] accessKey;
+
+ /**
+ * access typeValue
+ *
+ * @see AccessType#DEVICE for config message
+ * @see AccessType#APPLICATION for common message
+ */
+ protected AccessType accessType = AccessType.APPLICATION;
+
+ /**
+ * only used when accessType==APPLICATION
+ */
+ protected int appKeyIndex;
+
+ /**
+ * 0: 4 bytes trans mic
+ * 1: 8 bytes trans mic
+ */
+ protected int szmic = DEFAULT_ASZMIC;
+
+ protected int sourceAddress;
+
+ protected int destinationAddress;
+
+ protected int ctl = CTL_ACCESS;
+
+ protected int ttl = DEFAULT_TTL;
+
+ protected int retryCnt = DEFAULT_RETRY_CNT;
+
+ protected int responseMax = 0;
+
+ /**
+ * if message contains tid
+ *
+ * @see com.telink.ble.mesh.core.networking.NetworkingController#tid
+ */
+// protected boolean containsTid = false;
+
+
+
+// boolean reliable = false;
+
+ /**
+ * message response opcode
+ * defines message is reliable {@link #isReliable()}
+ */
+ protected int responseOpcode = OPCODE_INVALID;
+
+ /**
+ * tid position in params
+ * if message dose not contains tid, tid position should be invalid value (such as -1)
+ */
+ protected int tidPosition = -1;
+
+ protected boolean isSegmented = false;
+
+ /**
+ * if true, message will be cached and checked completion by message response or retryCnt == 0
+ * if false, message will not be cached and checked
+ */
+ public boolean isReliable() {
+ return getResponseOpcode() != OPCODE_INVALID;
+ }
+
+ public int getResponseOpcode() {
+ return responseOpcode;
+ }
+
+ public void setResponseOpcode(int responseOpcode) {
+ this.responseOpcode = responseOpcode;
+ }
+
+ public int getTidPosition() {
+ return tidPosition;
+ }
+
+ public void setTidPosition(int tidPosition) {
+ this.tidPosition = tidPosition;
+ }
+
+ public int getOpcode() {
+ return opcode;
+ }
+
+ public void setOpcode(int opcode) {
+ this.opcode = opcode;
+ }
+
+ public byte[] getParams() {
+ return params;
+ }
+
+ public void setParams(byte[] params) {
+ this.params = params;
+ }
+
+ public int getRetryCnt() {
+ return retryCnt;
+ }
+
+ public void setRetryCnt(int retryCnt) {
+ this.retryCnt = retryCnt;
+ }
+
+ public int getResponseMax() {
+ return responseMax;
+ }
+
+ public void setResponseMax(int responseMax) {
+ this.responseMax = responseMax;
+ }
+
+ public AccessType getAccessType() {
+ return accessType;
+ }
+
+ public void setAccessType(AccessType accessType) {
+ this.accessType = accessType;
+ }
+
+ public int getCtl() {
+ return this.ctl;
+ }
+
+ /**
+ * @deprecated
+ */
+ public void setCtl(int ctl) {
+ this.ctl = ctl;
+ }
+
+ public int getTtl() {
+ return ttl;
+ }
+
+ public void setTtl(int ttl) {
+ this.ttl = ttl;
+ }
+
+ /**
+ * mic size
+ */
+ public int getSzmic() {
+ return szmic;
+ }
+
+ public void setSzmic(int szmic) {
+ this.szmic = szmic;
+ }
+
+ public byte[] getAccessKey() {
+ return accessKey;
+ }
+
+ public void setAccessKey(byte[] accessKey) {
+ this.accessKey = accessKey;
+ }
+
+ public int getSourceAddress() {
+ return sourceAddress;
+ }
+
+ public void setSourceAddress(int sourceAddress) {
+ this.sourceAddress = sourceAddress;
+ }
+
+ public int getDestinationAddress() {
+ return destinationAddress;
+ }
+
+ public void setDestinationAddress(int destinationAddress) {
+ this.destinationAddress = destinationAddress;
+ }
+
+ public int getAppKeyIndex() {
+ return appKeyIndex;
+ }
+
+ public void setAppKeyIndex(int appKeyIndex) {
+ this.appKeyIndex = appKeyIndex;
+ }
+
+ public boolean isSegmented() {
+ return isSegmented;
+ }
+
+ public void setSegmented(boolean segmented) {
+ isSegmented = segmented;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/MeshSigModel.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/MeshSigModel.java
new file mode 100644
index 00000000..e0ab205f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/MeshSigModel.java
@@ -0,0 +1,211 @@
+/********************************************************************************************************
+ * @file MeshSigModel.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message;
+
+import java.io.Serializable;
+
+/**
+ * Created by kee on 2018/6/6.
+ */
+
+public enum MeshSigModel implements Serializable {
+
+ SIG_MD_CFG_SERVER(0x0000, "config server", "", true),
+ SIG_MD_CFG_CLIENT(0x0001, "config client", "", true),
+
+
+ SIG_MD_HEALTH_SERVER(0x0002, "health server", "health server", false),
+ SIG_MD_HEALTH_CLIENT(0x0003, "health client", "health client", false),
+
+
+ SIG_MD_REMOTE_PROV_SERVER(0x0004, "rp", "", true),
+ SIG_MD_REMOTE_PROV_CLIENT(0x0005, "rp", "", true),
+ SIG_MD_DF_CFG_S(0x0006, "", "cfg server", true),
+ SIG_MD_DF_CFG_C(0x0007, "", "cfg client", true),
+ SIG_MD_BRIDGE_CFG_SERVER(0x0008, "", "", true),
+ SIG_MD_BRIDGE_CFG_CLIENT(0x0009, "", "", true),
+
+ SIG_MD_PRIVATE_BEACON_SERVER(0x000a, "", "", true),
+ SIG_MD_PRIVATE_BEACON_CLIENT(0x000b, "", "", true),
+
+
+ SIG_MD_G_ONOFF_S(0x1000, "Generic OnOff Server", "Generic"),
+ SIG_MD_G_ONOFF_C(0x1001, "Generic OnOff Client", "Generic"),
+ SIG_MD_G_LEVEL_S(0x1002, "Generic Level Server", "Generic"),
+ SIG_MD_G_LEVEL_C(0x1003, "Generic Level Client", "Generic"),
+ SIG_MD_G_DEF_TRANSIT_TIME_S(0x1004, "Generic Default Transition Time Server ", "Generic"),
+ SIG_MD_G_DEF_TRANSIT_TIME_C(0x1005, "Generic Default Transition Time Client ", "Generic"),
+ SIG_MD_G_POWER_ONOFF_S(0x1006, "Generic Power OnOff Server", "Generic"),
+ SIG_MD_G_POWER_ONOFF_SETUP_S(0x1007, "Generic Power OnOff Setup Server", "Generic"),
+ SIG_MD_G_POWER_ONOFF_C(0x1008, "Generic Power OnOff Client", "Generic"),
+ SIG_MD_G_POWER_LEVEL_S(0x1009, "Generic Power Level Server", "Generic"),
+ SIG_MD_G_POWER_LEVEL_SETUP_S(0x100A, "Generic Power Level Setup Server", "Generic"),
+ SIG_MD_G_POWER_LEVEL_C(0x100B, "Generic Power Level Client", "Generic"),
+ SIG_MD_G_BAT_S(0x100C, "Generic Battery Server", "Generic"),
+ SIG_MD_G_BAT_C(0x100D, "Generic Battery Client", "Generic"),
+ SIG_MD_G_LOCATION_S(0x100E, "Generic Location Server", "Generic"),
+ SIG_MD_G_LOCATION_SETUP_S(0x100F, "Generic Location Setup Server", "Generic"),
+ SIG_MD_G_LOCATION_C(0x1010, "Generic Location Client", "Generic"),
+ SIG_MD_G_ADMIN_PROP_S(0x1011, "Generic Admin Property Server", "Generic"),
+ SIG_MD_G_MFR_PROP_S(0x1012, "Generic Manufacturer Property Server", "Generic"),
+ SIG_MD_G_USER_PROP_S(0x1013, "Generic User Property Server", "Generic"),
+ SIG_MD_G_CLIENT_PROP_S(0x1014, "Generic Client Property Server", "Generic"),
+ SIG_MD_G_PROP_C(0x1015, "Generic Property Client", "Generic"), // original: SIG_MD_G_PROP_S (may be err)
+
+ SIG_MD_SENSOR_S(0x1100, "Sensor Server", "Sensors"),
+ SIG_MD_SENSOR_SETUP_S(0x1101, "Sensor Setup Server", "Sensors"),
+ SIG_MD_SENSOR_C(0x1102, "Sensor Client", "Sensors"),
+
+ SIG_MD_TIME_S(0x1200, "Time Server", "Time and Scenes"),
+ SIG_MD_TIME_SETUP_S(0x1201, "Time Setup Server", "Time and Scenes"),
+ SIG_MD_TIME_C(0x1202, "Time Client", "Time and Scenes"),
+ SIG_MD_SCENE_S(0x1203, "Scene Server", "Time and Scenes"),
+ SIG_MD_SCENE_SETUP_S(0x1204, "Scene Setup Server", "Time and Scenes"),
+ SIG_MD_SCENE_C(0x1205, "Scene Client", "Time and Scenes"),
+ SIG_MD_SCHED_S(0x1206, "MeshScheduler Server", "Time and Scenes"),
+ SIG_MD_SCHED_SETUP_S(0x1207, "MeshScheduler Setup Server", "Time and Scenes"),
+ SIG_MD_SCHED_C(0x1208, "MeshScheduler Client", "Time and Scenes"),
+
+ SIG_MD_LIGHTNESS_S(0x1300, "Light Lightness Server", "Lighting"),
+ SIG_MD_LIGHTNESS_SETUP_S(0x1301, "Light Lightness Setup Server", "Lighting"),
+ SIG_MD_LIGHTNESS_C(0x1302, "Light Lightness Client", "Lighting"),
+ SIG_MD_LIGHT_CTL_S(0x1303, "Light CTL Server", "Lighting"),
+ SIG_MD_LIGHT_CTL_SETUP_S(0x1304, "Light CTL Setup Server", "Lighting"),
+ SIG_MD_LIGHT_CTL_C(0x1305, "Light CTL Client", "Lighting"),
+ SIG_MD_LIGHT_CTL_TEMP_S(0x1306, "Light CTL Temperature Server", "Lighting"),
+ SIG_MD_LIGHT_HSL_S(0x1307, "Light HSL Server", "Lighting"),
+ SIG_MD_LIGHT_HSL_SETUP_S(0x1308, "Light HSL Setup Server", "Lighting"),
+ SIG_MD_LIGHT_HSL_C(0x1309, "Light HSL Client", "Lighting"),
+ SIG_MD_LIGHT_HSL_HUE_S(0x130A, "Light HSL Hue Server", "Lighting"),
+ SIG_MD_LIGHT_HSL_SAT_S(0x130B, "Light HSL Saturation Server", "Lighting"),
+ SIG_MD_LIGHT_XYL_S(0x130C, "Light xyL Server", "Lighting"),
+ SIG_MD_LIGHT_XYL_SETUP_S(0x130D, "Light xyL Setup Server", "Lighting"),
+ SIG_MD_LIGHT_XYL_C(0x130E, "Light xyL Client", "Lighting"),
+ SIG_MD_LIGHT_LC_S(0x130F, "Light LC Server", "Lighting"),
+ SIG_MD_LIGHT_LC_SETUP_S(0x1310, "Light LC Setup Server", "Lighting"),
+ SIG_MD_LIGHT_LC_C(0x1311, "Light LC Client", "Lighting"),
+
+
+ SIG_MD_CFG_DF_S(0xBF30, "direct forwarding server", "", true),
+ SIG_MD_CFG_DF_C(0xBF31, "direct forwarding client", "", true),
+
+ SIG_MD_CFG_BRIDGE_S(0xBF32, "subnet bridge server", "", true),
+ SIG_MD_CFG_BRIDGE_C(0xBF33, "subnet bridge client", "", true),
+
+ /**
+ * firmware update model
+ */
+ SIG_MD_FW_UPDATE_S(0xFE00, "firmware update server", "OTA"),
+ SIG_MD_FW_UPDATE_C(0xFE01, "firmware update client", "OTA"),
+ SIG_MD_FW_DISTRIBUT_S(0xFE02, "firmware distribute server", "OTA"),
+ SIG_MD_FW_DISTRIBUT_C(0xFE03, "firmware distribute client", "OTA"),
+ SIG_MD_OBJ_TRANSFER_S(0xFF00, "object transfer server", "OTA"),
+ SIG_MD_OBJ_TRANSFER_C(0xFF01, "object transfer client", "OTA"),
+ ;
+
+ /**
+ * sig model id
+ * 2 bytes
+ */
+ public int modelId;
+
+ /**
+ * model name
+ */
+ public String modelName;
+
+ /**
+ * model group desc
+ */
+ public String group;
+ public boolean isConfigModel = false;
+
+ public boolean selected;
+
+ MeshSigModel(int modelId, String modelName, String group) {
+ this(modelId, modelName, group, false);
+ }
+
+ MeshSigModel(int modelId, String modelName, String group, boolean isConfigModel) {
+ this.modelId = modelId;
+ this.modelName = modelName;
+ this.group = group;
+ this.isConfigModel = isConfigModel;
+ }
+
+ public static boolean isConfigurationModel(int modelId) {
+ MeshSigModel model = getById(modelId);
+ return model != null && model.isConfigModel;
+ }
+
+ // default sub list
+ public static MeshSigModel[] getDefaultSubList() {
+ return new MeshSigModel[]{SIG_MD_G_ONOFF_S, SIG_MD_LIGHTNESS_S, SIG_MD_LIGHT_CTL_S,
+ SIG_MD_LIGHT_CTL_TEMP_S, SIG_MD_LIGHT_HSL_S};
+
+ }
+
+ public static MeshSigModel getById(int modelId) {
+ for (MeshSigModel model :
+ values()) {
+ if (model.modelId == modelId) return model;
+ }
+ return null;
+ }
+
+
+ /*public static MeshSigModel[] getConfigSimilarity() {
+ return new MeshSigModel[]{
+ SIG_MD_CFG_SERVER, SIG_MD_CFG_CLIENT,
+ SIG_MD_REMOTE_PROV_SERVER, SIG_MD_REMOTE_PROV_CLIENT,
+ SIG_MD_DF_CFG_S, SIG_MD_DF_CFG_C,
+ SIG_MD_BRIDGE_CFG_SERVER, SIG_MD_BRIDGE_CFG_CLIENT,
+ SIG_MD_PRIVATE_BEACON_SERVER, SIG_MD_PRIVATE_BEACON_CLIENT
+ };
+ }*/
+
+ /*
+ const u32 MODEL_ID_DEV_KEY[] = {
+ SIG_MD_CFG_SERVER, SIG_MD_CFG_CLIENT,
+ SIG_MD_REMOTE_PROV_SERVER, SIG_MD_REMOTE_PROV_CLIENT,
+ SIG_MD_DF_CFG_S, SIG_MD_DF_CFG_C,
+ SIG_MD_BRIDGE_CFG_SERVER, SIG_MD_BRIDGE_CFG_CLIENT,
+ SIG_MD_PRIVATE_BEACON_SERVER, SIG_MD_PRIVATE_BEACON_CLIENT
+};
+
+#define SIG_MD_CFG_SERVER 0x0000 // for test high byte
+#define SIG_MD_CFG_CLIENT 0x0001
+//#define SIG_MD_HEALTH_SERVER 0x0002
+//#define SIG_MD_HEALTH_CLIENT 0x0003
+#define SIG_MD_REMOTE_PROV_SERVER 0x0004
+#define SIG_MD_REMOTE_PROV_CLIENT 0x0005
+#define SIG_MD_DF_CFG_S 0x0006
+#define SIG_MD_DF_CFG_C 0x0007
+#define SIG_MD_BRIDGE_CFG_SERVER 0x0008
+#define SIG_MD_BRIDGE_CFG_CLIENT 0x0009
+#define SIG_MD_PRIVATE_BEACON_SERVER 0x000a
+#define SIG_MD_PRIVATE_BEACON_CLIENT 0x000b
+
+ */
+
+}
+
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/MeshStatus.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/MeshStatus.java
new file mode 100644
index 00000000..73ac15f1
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/MeshStatus.java
@@ -0,0 +1,187 @@
+/********************************************************************************************************
+ * @file MeshStatus.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message;
+
+import android.util.SparseArray;
+
+import com.telink.ble.mesh.core.message.config.AppKeyStatusMessage;
+import com.telink.ble.mesh.core.message.config.BridgingTableStatusMessage;
+import com.telink.ble.mesh.core.message.config.CompositionDataStatusMessage;
+import com.telink.ble.mesh.core.message.config.ModelAppStatusMessage;
+import com.telink.ble.mesh.core.message.config.ModelPublicationStatusMessage;
+import com.telink.ble.mesh.core.message.config.ModelSubscriptionStatusMessage;
+import com.telink.ble.mesh.core.message.config.NetKeyStatusMessage;
+import com.telink.ble.mesh.core.message.config.NodeIdentityStatusMessage;
+import com.telink.ble.mesh.core.message.config.NodeResetStatusMessage;
+import com.telink.ble.mesh.core.message.config.SubnetBridgeStatusMessage;
+import com.telink.ble.mesh.core.message.fastpv.MeshAddressStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareMetadataStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareUpdateInfoStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.FirmwareUpdateStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobBlockStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobInfoStatusMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobPartialBlockReportMessage;
+import com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer.BlobTransferStatusMessage;
+import com.telink.ble.mesh.core.message.generic.LevelStatusMessage;
+import com.telink.ble.mesh.core.message.generic.OnOffStatusMessage;
+import com.telink.ble.mesh.core.message.lighting.CtlStatusMessage;
+import com.telink.ble.mesh.core.message.lighting.CtlTemperatureStatusMessage;
+import com.telink.ble.mesh.core.message.lighting.HslStatusMessage;
+import com.telink.ble.mesh.core.message.lighting.HslTargetStatusMessage;
+import com.telink.ble.mesh.core.message.lighting.LightnessStatusMessage;
+import com.telink.ble.mesh.core.message.rp.LinkStatusMessage;
+import com.telink.ble.mesh.core.message.rp.ProvisioningPDUOutboundReportMessage;
+import com.telink.ble.mesh.core.message.rp.ProvisioningPDUReportMessage;
+import com.telink.ble.mesh.core.message.rp.ScanReportStatusMessage;
+import com.telink.ble.mesh.core.message.rp.ScanStatusMessage;
+import com.telink.ble.mesh.core.message.scene.SceneRegisterStatusMessage;
+import com.telink.ble.mesh.core.message.scene.SceneStatusMessage;
+import com.telink.ble.mesh.core.message.scheduler.SchedulerActionStatusMessage;
+import com.telink.ble.mesh.core.message.scheduler.SchedulerStatusMessage;
+import com.telink.ble.mesh.core.message.time.TimeStatusMessage;
+
+/**
+ * All registered StatusMessage should have empty constructor for [Creating Instance]
+ * {@link StatusMessage#createByAccessMessage(int, byte[])}
+ * Created by kee on 2019/9/3.
+ */
+
+public class MeshStatus {
+ /**
+ * status message opcode {@link com.telink.ble.mesh.core.networking.AccessLayerPDU#opcode}
+ */
+ private int opcode;
+
+ /**
+ * message info: Class extends StatusMessage
+ *
+ * @see StatusMessage
+ */
+ private Class statusMessageCls;
+
+ public MeshStatus(int opcode, Class statusMessageCls) {
+ this.opcode = opcode;
+ this.statusMessageCls = statusMessageCls;
+ }
+
+ public Class getStatusMessageCls() {
+ return statusMessageCls;
+ }
+
+ public void setStatusMessageCls(Class statusMessageCls) {
+ this.statusMessageCls = statusMessageCls;
+ }
+
+ public int getOpcode() {
+ return opcode;
+ }
+
+ public void setOpcode(int opcode) {
+ this.opcode = opcode;
+ }
+
+ public static class Container {
+
+ private static SparseArray statusMap = new SparseArray<>();
+
+ static {
+ register(Opcode.COMPOSITION_DATA_STATUS.value, CompositionDataStatusMessage.class);
+ register(Opcode.MODE_APP_STATUS.value, ModelAppStatusMessage.class);
+ register(Opcode.APPKEY_STATUS.value, AppKeyStatusMessage.class);
+ register(Opcode.NODE_RESET_STATUS.value, NodeResetStatusMessage.class);
+ register(Opcode.CFG_MODEL_SUB_STATUS.value, ModelSubscriptionStatusMessage.class);
+ register(Opcode.CFG_MODEL_PUB_STATUS.value, ModelPublicationStatusMessage.class);
+ register(Opcode.NODE_ID_STATUS.value, NodeIdentityStatusMessage.class);
+ register(Opcode.NETKEY_STATUS.value, NetKeyStatusMessage.class);
+
+ register(Opcode.SUBNET_BRIDGE_STATUS.value, SubnetBridgeStatusMessage.class);
+ register(Opcode.BRIDGING_TABLE_STATUS.value, BridgingTableStatusMessage.class);
+
+ // generic
+ register(Opcode.G_ONOFF_STATUS.value, OnOffStatusMessage.class);
+ register(Opcode.G_LEVEL_STATUS.value, LevelStatusMessage.class);
+
+ // lighting
+ register(Opcode.LIGHTNESS_STATUS.value, LightnessStatusMessage.class);
+ register(Opcode.LIGHT_CTL_TEMP_STATUS.value, CtlTemperatureStatusMessage.class);
+ register(Opcode.LIGHT_CTL_STATUS.value, CtlStatusMessage.class);
+
+ register(Opcode.LIGHT_HSL_STATUS.value, HslStatusMessage.class);
+ register(Opcode.LIGHT_HSL_TARGET_STATUS.value, HslTargetStatusMessage.class);
+
+ // time
+ register(Opcode.TIME_STATUS.value, TimeStatusMessage.class);
+
+ // scene
+ register(Opcode.SCENE_STATUS.value, SceneStatusMessage.class);
+ register(Opcode.SCENE_REG_STATUS.value, SceneRegisterStatusMessage.class);
+
+ // scheduler status
+ register(Opcode.SCHD_STATUS.value, SchedulerStatusMessage.class);
+ register(Opcode.SCHD_ACTION_STATUS.value, SchedulerActionStatusMessage.class);
+
+
+ // mesh firmware update
+ register(Opcode.FIRMWARE_UPDATE_INFORMATION_STATUS.value, FirmwareUpdateInfoStatusMessage.class);
+ register(Opcode.FIRMWARE_UPDATE_FIRMWARE_METADATA_STATUS.value, FirmwareMetadataStatusMessage.class);
+ register(Opcode.FIRMWARE_UPDATE_STATUS.value, FirmwareUpdateStatusMessage.class);
+
+ /// blob transfer
+ register(Opcode.BLOB_BLOCK_STATUS.value, BlobBlockStatusMessage.class);
+ register(Opcode.BLOB_INFORMATION_STATUS.value, BlobInfoStatusMessage.class);
+ register(Opcode.BLOB_TRANSFER_STATUS.value, BlobTransferStatusMessage.class);
+ register(Opcode.BLOB_PARTIAL_BLOCK_REPORT.value, BlobPartialBlockReportMessage.class);
+ /*register(Opcode.FW_INFO_STATUS.value, FirmwareInfoStatusMessage.class);
+ register(Opcode.FW_DISTRIBUT_STATUS.value, FirmwareDistributionStatusMessage.class);
+ register(Opcode.FW_UPDATE_STATUS.value, FirmwareUpdateStatusMessage.class);
+ register(Opcode.OBJ_BLOCK_STATUS.value, ObjectBlockStatusMessage.class);
+ register(Opcode.OBJ_BLOCK_TRANSFER_STATUS.value, ObjectBlockTransferStatusMessage.class);
+ register(Opcode.OBJ_INFO_STATUS.value, ObjectInfoStatusMessage.class);
+ register(Opcode.OBJ_TRANSFER_STATUS.value, ObjectTransferStatusMessage.class);*/
+
+ // remote provision
+ register(Opcode.REMOTE_PROV_SCAN_STS.value, ScanStatusMessage.class);
+ register(Opcode.REMOTE_PROV_SCAN_REPORT.value, ScanReportStatusMessage.class);
+ register(Opcode.REMOTE_PROV_LINK_STS.value, LinkStatusMessage.class);
+ register(Opcode.REMOTE_PROV_PDU_REPORT.value, ProvisioningPDUReportMessage.class);
+ register(Opcode.REMOTE_PROV_PDU_OUTBOUND_REPORT.value, ProvisioningPDUOutboundReportMessage.class);
+// register(Opcode.REMOTE_PROV_SCAN_CAPA_STS.value, ObjectTransferStatusMessage.class);
+
+ // fast provision [vendor]
+ register(Opcode.VD_MESH_ADDR_GET_STS.value, MeshAddressStatusMessage.class);
+ }
+
+ public static void register(MeshStatus status) {
+ statusMap.put(status.opcode, status.statusMessageCls);
+ }
+
+ public static void register(int opcode, Class statusMessageCls) {
+ statusMap.put(opcode, statusMessageCls);
+ }
+
+ public static Class getMessageClass(int opcode) {
+ return statusMap.get(opcode);
+ }
+
+
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/NotificationMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/NotificationMessage.java
new file mode 100644
index 00000000..3bb0f175
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/NotificationMessage.java
@@ -0,0 +1,132 @@
+/********************************************************************************************************
+ * @file NotificationMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * NotificationMessage is used to notify mesh status changed
+ *
+ * Created by kee on 2019/9/3.
+ */
+public class NotificationMessage implements Parcelable {
+ private int src;
+ private int dst;
+ private int opcode;
+
+ // params raw data
+ private byte[] params;
+
+ /**
+ * parsed message by params, if opcode is registered in {@link MeshStatus.Container}
+ * otherwise statusMessage will be null
+ */
+ private StatusMessage statusMessage;
+
+ public NotificationMessage(int src, int dst, int opcode, byte[] params) {
+ this.src = src;
+ this.dst = dst;
+ this.opcode = opcode;
+ this.params = params;
+ parseStatusMessage();
+ }
+
+ private void parseStatusMessage() {
+ this.statusMessage = StatusMessage.createByAccessMessage(opcode, params);
+ }
+
+
+ protected NotificationMessage(Parcel in) {
+ src = in.readInt();
+ dst = in.readInt();
+ opcode = in.readInt();
+ params = in.createByteArray();
+ statusMessage = in.readParcelable(StatusMessage.class.getClassLoader());
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public NotificationMessage createFromParcel(Parcel in) {
+ return new NotificationMessage(in);
+ }
+
+ @Override
+ public NotificationMessage[] newArray(int size) {
+ return new NotificationMessage[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(src);
+ dest.writeInt(dst);
+ dest.writeInt(opcode);
+ dest.writeByteArray(params);
+ dest.writeParcelable(statusMessage, flags);
+ }
+
+ public int getSrc() {
+ return src;
+ }
+
+ public void setSrc(int src) {
+ this.src = src;
+ }
+
+ public int getDst() {
+ return dst;
+ }
+
+ public void setDst(int dst) {
+ this.dst = dst;
+ }
+
+ public int getOpcode() {
+ return opcode;
+ }
+
+ public void setOpcode(int opcode) {
+ this.opcode = opcode;
+ }
+
+ public byte[] getParams() {
+ return params;
+ }
+
+ public void setParams(byte[] params) {
+ this.params = params;
+ }
+
+ public StatusMessage getStatusMessage() {
+ return statusMessage;
+ }
+
+ public void setStatusMessage(StatusMessage statusMessage) {
+ this.statusMessage = statusMessage;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/Opcode.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/Opcode.java
new file mode 100644
index 00000000..885d5d52
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/Opcode.java
@@ -0,0 +1,448 @@
+/********************************************************************************************************
+ * @file Opcode.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message;
+
+
+import androidx.annotation.Nullable;
+
+public enum Opcode {
+
+ APPKEY_ADD(0x00, "Add Application key"),
+ APPKEY_UPDATE(0x01),
+ COMPOSITION_DATA_STATUS(0x02),
+ CFG_MODEL_PUB_SET(0x03),
+ HEALTH_CURRENT_STATUS(0x04),
+ HEALTH_FAULT_STATUS(0x05),
+ HEARTBEAT_PUB_STATUS(0x06),
+
+
+ // config
+ APPKEY_DEL(0x0080),
+ APPKEY_GET(0x0180),
+ APPKEY_LIST(0x0280),
+ APPKEY_STATUS(0x0380),
+
+ // attenttion timer
+ HEALTH_ATTENTION_GET(0x0480),
+ HEALTH_ATTENTION_SET(0x0580),
+ HEALTH_ATTENTION_SET_NOACK(0x0680),
+ HEALTH_ATTENTION_STATUS(0x0780),
+
+ COMPOSITION_DATA_GET(0x0880),
+ CFG_BEACON_GET(0x0980),
+ CFG_BEACON_SET(0x0A80),
+ CFG_BEACON_STATUS(0x0B80),
+ CFG_DEFAULT_TTL_GET(0x0C80),
+ CFG_DEFAULT_TTL_SET(0x0D80),
+ CFG_DEFAULT_TTL_STATUS(0x0E80),
+ CFG_FRIEND_GET(0x0F80),
+ CFG_FRIEND_SET(0x1080),
+ CFG_FRIEND_STATUS(0x1180),
+ CFG_GATT_PROXY_GET(0x1280),
+ CFG_GATT_PROXY_SET(0x1380),
+ CFG_GATT_PROXY_STATUS(0x1480),
+ CFG_KEY_REFRESH_PHASE_GET(0x1580),
+ CFG_KEY_REFRESH_PHASE_SET(0x1680),
+ CFG_KEY_REFRESH_PHASE_STATUS(0x1780),
+ CFG_MODEL_PUB_GET(0x1880),
+ CFG_MODEL_PUB_STATUS(0x1980),
+ CFG_MODEL_PUB_VIRTUAL_ADR_SET(0x1A80),
+ CFG_MODEL_SUB_ADD(0x1B80),
+ CFG_MODEL_SUB_DEL(0x1C80),
+ CFG_MODEL_SUB_DEL_ALL(0x1D80),
+ CFG_MODEL_SUB_OVER_WRITE(0x1E80),
+ CFG_MODEL_SUB_STATUS(0x1F80),
+ CFG_MODEL_SUB_VIRTUAL_ADR_ADD(0x2080),
+ CFG_MODEL_SUB_VIRTUAL_ADR_DEL(0x2180),
+ CFG_MODEL_SUB_VIRTUAL_ADR_OVER_WRITE(0x2280),
+ CFG_NW_TRANSMIT_GET(0x2380),
+ CFG_NW_TRANSMIT_SET(0x2480),
+ CFG_NW_TRANSMIT_STATUS(0x2580),
+ CFG_RELAY_GET(0x2680),
+ CFG_RELAY_SET(0x2780),
+ CFG_RELAY_STATUS(0x2880),
+ CFG_SIG_MODEL_SUB_GET(0x2980),
+ CFG_SIG_MODEL_SUB_LIST(0x2A80),
+ CFG_VENDOR_MODEL_SUB_GET(0x2B80),
+ CFG_VENDOR_MODEL_SUB_LIST(0x2C80),
+ CFG_LPN_POLL_TIMEOUT_GET(0x2D80),
+ CFG_LPN_POLL_TIMEOUT_STATUS(0x2E80),
+
+
+ HEALTH_FAULT_CLEAR(0x2F80),
+ HEALTH_FAULT_CLEAR_NOACK(0x3080),
+ HEALTH_FAULT_GET(0x3180),
+ HEALTH_FAULT_TEST(0x3280),
+ HEALTH_FAULT_TEST_NOACK(0x3380),
+
+ HEALTH_PERIOD_GET(0x3480),
+ HEALTH_PERIOD_SET(0x3580),
+ HEALTH_PERIOD_SET_NOACK(0x3680),
+ HEALTH_PERIOD_STATUS(0x3780),
+
+ HEARTBEAT_PUB_GET(0x3880),
+ HEARTBEAT_PUB_SET(0x3980),
+ HEARTBEAT_SUB_GET(0x3A80),
+ HEARTBEAT_SUB_SET(0x3B80),
+ HEARTBEAT_SUB_STATUS(0x3C80),
+
+ MODE_APP_BIND(0x3D80),
+ MODE_APP_STATUS(0x3E80),
+ MODE_APP_UNBIND(0x3F80),
+ NETKEY_ADD(0x4080),
+ NETKEY_DEL(0x4180),
+ NETKEY_GET(0x4280),
+ NETKEY_LIST(0x4380),
+ NETKEY_STATUS(0x4480),
+ NETKEY_UPDATE(0x4580),
+ NODE_ID_GET(0x4680),
+ NODE_ID_SET(0x4780),
+ NODE_ID_STATUS(0x4880),
+ NODE_RESET(0x4980),
+ NODE_RESET_STATUS(0x4A80),
+ SIG_MODEL_APP_GET(0x4B80),
+ SIG_MODEL_APP_LIST(0x4C80),
+ VENDOR_MODEL_APP_GET(0x4D80),
+ VENDOR_MODEL_APP_LIST(0x4E80),
+
+ // subnet bridge
+ SUBNET_BRIDGE_GET(0x70BF),
+ SUBNET_BRIDGE_SET(0x71BF),
+ SUBNET_BRIDGE_STATUS(0x72BF),
+ BRIDGING_TABLE_ADD(0x73BF),
+ BRIDGING_TABLE_REMOVE(0x74BF),
+ BRIDGING_TABLE_STATUS(0x75BF),
+ BRIDGED_SUBNETS_GET(0x76BF),
+ BRIDGED_SUBNETS_LIST(0x77BF),
+ BRIDGING_TABLE_GET(0x78BF),
+ BRIDGING_TABLE_LIST(0x79BF),
+ BRIDGE_CAPABILITY_GET(0x7ABF),
+ BRIDGE_CAPABILITY_STATUS(0x7BBF),
+
+
+ // generic
+ G_ONOFF_GET(0x0182),
+ G_ONOFF_SET(0x0282),
+ G_ONOFF_SET_NOACK(0x0382),
+ G_ONOFF_STATUS(0x0482),
+
+ G_LEVEL_GET(0x0582),
+ G_LEVEL_SET(0x0682),
+ G_LEVEL_SET_NOACK(0x0782),
+ G_LEVEL_STATUS(0x0882),
+ G_DELTA_SET(0x0982),
+ G_DELTA_SET_NOACK(0x0A82),
+ G_MOVE_SET(0x0B82),
+ G_MOVE_SET_NOACK(0x0C82),
+
+ G_DEF_TRANS_TIME_GET(0x0D82),
+ G_DEF_TRANS_TIME_SET(0x0E82),
+ G_DEF_TRANS_TIME_SET_NOACK(0x0F82),
+ G_DEF_TRANS_TIME_STATUS(0x1082),
+
+ G_ON_POWER_UP_GET(0x1182),
+ G_ON_POWER_UP_STATUS(0x1282),
+ G_ON_POWER_UP_SET(0x1382),
+ G_ON_POWER_UP_SET_NOACK(0x1482),
+
+ G_POWER_LEVEL_GET(0x1582),
+ G_POWER_LEVEL_SET(0x1682),
+ G_POWER_LEVEL_SET_NOACK(0x1782),
+ G_POWER_LEVEL_STATUS(0x1882),
+ G_POWER_LEVEL_LAST_GET(0x1982),
+ G_POWER_LEVEL_LAST_STATUS(0x1A82),
+ G_POWER_DEF_GET(0x1B82),
+ G_POWER_DEF_STATUS(0x1C82),
+ G_POWER_LEVEL_RANGE_GET(0x1D82),
+ G_POWER_LEVEL_RANGE_STATUS(0x1E82),
+ G_POWER_DEF_SET(0x1F82),
+ G_POWER_DEF_SET_NOACK(0x2082),
+ G_POWER_LEVEL_RANGE_SET(0x2182),
+ G_POWER_LEVEL_RANGE_SET_NOACK(0x2282),
+
+ G_BATTERY_GET(0x2382),
+ G_BATTERY_STATUS(0x2482),
+
+ G_LOCATION_GLOBAL_GET(0x2582),
+ G_LOCATION_GLOBAL_STATUS(0x40),
+ G_LOCATION_LOCAL_GET(0x2682),
+ G_LOCATION_LOCAL_STATUS(0x2782),
+ G_LOCATION_GLOBAL_SET(0x41),
+ G_LOCATION_GLOBAL_SET_NOACK(0x42),
+ G_LOCATION_LOCAL_SET(0x2882),
+ G_LOCATION_LOCAL_SET_NOACK(0x2982),
+
+ // lighting
+ LIGHTNESS_GET(0x4B82),
+ LIGHTNESS_SET(0x4C82),
+ LIGHTNESS_SET_NOACK(0x4D82),
+ LIGHTNESS_STATUS(0x4E82),
+ LIGHTNESS_LINEAR_GET(0x4F82),
+ LIGHTNESS_LINEAR_SET(0x5082),
+ LIGHTNESS_LINEAR_SET_NOACK(0x5182),
+ LIGHTNESS_LINEAR_STATUS(0x5282),
+ LIGHTNESS_LAST_GET(0x5382),
+ LIGHTNESS_LAST_STATUS(0x5482),
+ LIGHTNESS_DEFULT_GET(0x5582),
+ LIGHTNESS_DEFULT_STATUS(0x5682),
+ LIGHTNESS_RANGE_GET(0x5782),
+ LIGHTNESS_RANGE_STATUS(0x5882),
+ LIGHTNESS_DEFULT_SET(0x5982),
+ LIGHTNESS_DEFULT_SET_NOACK(0x5A82),
+ LIGHTNESS_RANGE_SET(0x5B82),
+ LIGHTNESS_RANGE_SET_NOACK(0x5C82),
+ LIGHT_CTL_GET(0x5D82),
+ LIGHT_CTL_SET(0x5E82),
+ LIGHT_CTL_SET_NOACK(0x5F82),
+ LIGHT_CTL_STATUS(0x6082),
+ LIGHT_CTL_TEMP_GET(0x6182),
+ LIGHT_CTL_TEMP_RANGE_GET(0x6282),
+ LIGHT_CTL_TEMP_RANGE_STATUS(0x6382),
+ LIGHT_CTL_TEMP_SET(0x6482),
+ LIGHT_CTL_TEMP_SET_NOACK(0x6582),
+ LIGHT_CTL_TEMP_STATUS(0x6682),
+ LIGHT_CTL_DEFULT_GET(0x6782),
+ LIGHT_CTL_DEFULT_STATUS(0x6882),
+ LIGHT_CTL_DEFULT_SET(0x6982),
+ LIGHT_CTL_DEFULT_SET_NOACK(0x6A82),
+ LIGHT_CTL_TEMP_RANGE_SET(0x6B82),
+ LIGHT_CTL_TEMP_RANGE_SET_NOACK(0x6C82),
+
+ // HSL
+ LIGHT_HSL_GET(0x6D82),
+ LIGHT_HSL_HUE_GET(0x6E82),
+ LIGHT_HSL_HUE_SET(0x6F82),
+ LIGHT_HSL_HUE_SET_NOACK(0x7082),
+ LIGHT_HSL_HUE_STATUS(0x7182),
+ LIGHT_HSL_SAT_GET(0x7282),
+ LIGHT_HSL_SAT_SET(0x7382),
+ LIGHT_HSL_SAT_SET_NOACK(0x7482),
+ LIGHT_HSL_SAT_STATUS(0x7582),
+ LIGHT_HSL_SET(0x7682),
+ LIGHT_HSL_SET_NOACK(0x7782),
+ LIGHT_HSL_STATUS(0x7882),
+ LIGHT_HSL_TARGET_GET(0x7982),
+ LIGHT_HSL_TARGET_STATUS(0x7A82),
+ LIGHT_HSL_DEF_GET(0x7B82),
+ LIGHT_HSL_DEF_STATUS(0x7C82),
+ LIGHT_HSL_RANGE_GET(0x7D82),
+ LIGHT_HSL_RANGE_STATUS(0x7E82),
+ LIGHT_HSL_DEF_SET(0x7F82),
+ LIGHT_HSL_DEF_SET_NOACK(0x8082),
+ LIGHT_HSL_RANGE_SET(0x8182),
+ LIGHT_HSL_RANGE_SET_NOACK(0x8282),
+
+ // time
+ TIME_GET(0x3782),
+ TIME_SET(0x5C),
+ TIME_STATUS(0x5D),
+ TIME_ROLE_GET(0x3882),
+ TIME_ROLE_SET(0x3982),
+ TIME_ROLE_STATUS(0x3A82),
+ TIME_ZONE_GET(0x3B82),
+ TIME_ZONE_SET(0x3C82),
+ TIME_ZONE_STATUS(0x3D82),
+ TAI_UTC_DELTA_GET(0x3E82),
+ TAI_UTC_DELTA_SET(0x3F82),
+ TAI_UTC_DELTA_STATUS(0x4082),
+
+ // scheduler
+ SCHD_ACTION_GET(0x4882),
+ SCHD_ACTION_STATUS(0x5F),
+ SCHD_GET(0x4982),
+ SCHD_STATUS(0x4A82),
+ SCHD_ACTION_SET(0x60),
+ SCHD_ACTION_SET_NOACK(0x61),
+
+ // scene
+ SCENE_GET(0x4182),
+ SCENE_RECALL(0x4282),
+ SCENE_RECALL_NOACK(0x4382),
+ SCENE_STATUS(0x5E),
+ SCENE_REG_GET(0x4482),
+ SCENE_REG_STATUS(0x4582),
+ SCENE_STORE(0x4682),
+ SCENE_STORE_NOACK(0x4782),
+ SCENE_DEL(0x9E82),
+ SCENE_DEL_NOACK(0x9F82),
+
+ // remote provision
+ REMOTE_PROV_SCAN_CAPA_GET(0x4F80),
+ REMOTE_PROV_SCAN_CAPA_STS(0x5080),
+ REMOTE_PROV_SCAN_GET(0x5180),
+ REMOTE_PROV_SCAN_START(0x5280),
+ REMOTE_PROV_SCAN_STOP(0x5380),
+ REMOTE_PROV_SCAN_STS(0x5480),
+ REMOTE_PROV_SCAN_REPORT(0x5580),
+ REMOTE_PROV_EXTEND_SCAN_START(0x5680),
+ REMOTE_PROV_EXTEND_SCAN_REPORT(0x5780),
+ REMOTE_PROV_LINK_GET(0x5880),
+ REMOTE_PROV_LINK_OPEN(0x5980),
+ REMOTE_PROV_LINK_CLOSE(0x5A80),
+ REMOTE_PROV_LINK_STS(0x5B80),
+ REMOTE_PROV_LINK_REPORT(0x5C80),
+ REMOTE_PROV_PDU_SEND(0x5D80),
+ REMOTE_PROV_PDU_OUTBOUND_REPORT(0x5E80),
+ REMOTE_PROV_PDU_REPORT(0x5F80),
+
+ // mesh OTA
+ // firmware
+ /*FW_INFO_GET(0x01B6),
+ FW_INFO_STATUS(0x02B6),
+ FW_UPDATE_GET(0x03B6),
+ FW_UPDATE_PREPARE(0x04B6),
+ FW_UPDATE_START(0x05B6),
+ FW_UPDATE_ABORT(0x06B6),
+ FW_UPDATE_APPLY(0x07B6),
+ FW_UPDATE_STATUS(0x08B6),
+ FW_DISTRIBUT_GET(0x09B6),
+ FW_DISTRIBUT_START(0x0AB6),
+ FW_DISTRIBUT_STOP(0x0BB6),
+ FW_DISTRIBUT_STATUS(0x0CB6),
+ FW_DISTRIBUT_DETAIL_GET(0x0DB6),
+ FW_DISTRIBUT_DETAIL_LIST(0x0EB6),
+ // object
+ OBJ_TRANSFER_GET(0x01B7),
+ OBJ_TRANSFER_START(0x02B7),
+ OBJ_TRANSFER_ABORT(0x03B7),
+ OBJ_TRANSFER_STATUS(0x04B7),
+ OBJ_BLOCK_TRANSFER_START(0x05B7),
+ OBJ_BLOCK_TRANSFER_STATUS(0x06B7),
+ OBJ_CHUNK_TRANSFER(0x7D),
+ OBJ_BLOCK_GET(0x7E),
+ OBJ_BLOCK_STATUS(0x09B7),
+ OBJ_INFO_GET(0x0AB7),
+ OBJ_INFO_STATUS(0x0BB7),*/
+
+ /**
+ * BLOB Transfer
+ */
+ BLOB_TRANSFER_GET(0x01B7),
+ BLOB_TRANSFER_START(0x02B7),
+ BLOB_TRANSFER_CANCEL(0x03B7),
+ BLOB_TRANSFER_STATUS(0x04B7),
+ BLOB_BLOCK_GET(0x07B7),
+ BLOB_BLOCK_START(0x05B7),
+ BLOB_BLOCK_STATUS(0x7E),
+ BLOB_CHUNK_TRANSFER(0x7D),
+ BLOB_INFORMATION_GET(0x0AB7),
+ BLOB_INFORMATION_STATUS(0x0BB7),
+ BLOB_PARTIAL_BLOCK_REPORT(0x7C),
+
+
+ /**
+ * Firmware Update
+ */
+ FIRMWARE_UPDATE_INFORMATION_GET(0x01B6),
+ FIRMWARE_UPDATE_INFORMATION_STATUS(0x02B6),
+ FIRMWARE_UPDATE_FIRMWARE_METADATA_CHECK(0x03B6),
+ FIRMWARE_UPDATE_FIRMWARE_METADATA_STATUS(0x04B6),
+ FIRMWARE_UPDATE_GET(0x05B6),
+ FIRMWARE_UPDATE_START(0x06B6),
+ FIRMWARE_UPDATE_CANCEL(0x07B6),
+ FIRMWARE_UPDATE_APPLY(0x08B6),
+ FIRMWARE_UPDATE_STATUS(0x09B6),
+
+ /**
+ * Firmware Distribution
+ */
+ FD_GET(0x24B7),
+ FD_START(0x6C),
+ FD_CANCEL(0x25B7),
+ FD_APPLY(0x26B7),
+ FD_STATUS(0x6B),
+ FD_RECEIVERS_GET(0x6F),
+ FD_RECEIVERS_LIST(0x20B7),
+ FD_RECEIVERS_ADD(0x21B7),
+ FD_RECEIVERS_DELETE_ALL(0x22B7),
+ FD_RECEIVERS_STATUS(0x6E),
+ FD_CAPABILITIES_GET(0x23B7),
+ FD_CAPABILITIES_STATUS(0x6D),
+ FD_UPLOAD_GET(0x27B7),
+ FD_UPLOAD_START(0x6A),
+ FD_UPLOAD_OOB_START(0x60),
+ FD_UPLOAD_CANCEL(0x28B7),
+ FD_UPLOAD_STATUS(0x5F),
+ FD_FIRMWARE_GET(0x5E),
+ FD_FIRMWARE_STATUS(0x5C),
+ FD_FIRMWARE_GET_BY_INDEX(0x29B7),
+ FD_FIRMWARE_DELETE(0x5D),
+ FD_FIRMWARE_DELETE_ALL(0x2AB7),
+
+ /**
+ * fast provision, telink private [vendor command]
+ */
+ VD_MESH_RESET_NETWORK(0x0211C5),
+ VD_MESH_ADDR_GET(0x0211C6),
+ VD_MESH_ADDR_GET_STS(0x0211C7),
+ VD_MESH_ADDR_SET(0x0211C8),
+ VD_MESH_ADDR_SET_STS(0x0211C9),
+ VD_MESH_PROV_DATA_SET(0x0211CA),
+ VD_MESH_PROV_CONFIRM(0x0211CB),
+ VD_MESH_PROV_CONFIRM_STS(0x0211CC),
+ VD_MESH_PROV_COMPLETE(0x0211CD);
+
+ public final int value;
+ public final String info;
+
+ /**
+ * if command is reliable
+ * -1 unknown default
+ * 0 unreliable
+ * 1 reliable
+ */
+ private final int reliable;
+
+ Opcode(int value) {
+ this.value = value;
+ this.info = "";
+ this.reliable = -1;
+ }
+
+ Opcode(int value, @Nullable String info) {
+ this.value = value;
+ this.info = info;
+ this.reliable = -1;
+ }
+
+ Opcode(int value, String info, int reliable) {
+ this.value = value;
+ this.info = info;
+ this.reliable = reliable;
+ }
+
+ public static Opcode valueOf(int value) {
+ for (Opcode op :
+ values()) {
+ if (op.value == value) {
+ return op;
+ }
+ }
+ return null;
+ }
+
+
+ public int getReliable() {
+ return reliable;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/OpcodeType.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/OpcodeType.java
new file mode 100644
index 00000000..71ffb7ad
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/OpcodeType.java
@@ -0,0 +1,47 @@
+/********************************************************************************************************
+ * @file OpcodeType.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message;
+
+import com.telink.ble.mesh.core.MeshUtils;
+
+public enum OpcodeType {
+ SIG_1(1),
+ SIG_2(2),
+ VENDOR(3);
+
+ public final int length;
+
+ OpcodeType(int length) {
+ this.length = length;
+ }
+
+ /**
+ * @param opFst first byte of opcode
+ */
+ public static OpcodeType getByFirstByte(byte opFst) {
+ return (opFst & MeshUtils.bit(7)) != 0
+ ?
+ ((opFst & MeshUtils.bit(6)) != 0 ? VENDOR : SIG_2)
+ :
+ SIG_1;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/StatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/StatusMessage.java
new file mode 100644
index 00000000..0adef866
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/StatusMessage.java
@@ -0,0 +1,151 @@
+/********************************************************************************************************
+ * @file StatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message;
+
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.networking.AccessLayerPDU;
+
+/**
+ * status notification by acknowledged message
+ * Created by kee on 2019/8/20.
+ */
+public abstract class StatusMessage implements Parcelable {
+
+ public StatusMessage() {
+
+ }
+
+
+// public abstract int getDataLength();
+
+ /**
+ * parse status message with access layer pdu params
+ * {@link AccessLayerPDU#params}
+ */
+ public abstract void parse(byte[] params);
+
+
+ /**
+ * create new StatusMessage by opcode
+ *
+ * @return result can be null when target opcode is not registered in MeshStatus
+ * {@link MeshStatus.Container}
+ */
+ public static StatusMessage createByAccessMessage(int opcode, byte[] params) {
+
+ Class messageClass = MeshStatus.Container.getMessageClass(opcode);
+ if (messageClass != null) {
+ Object msgClass = null;
+ try {
+ msgClass = messageClass.newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ if (msgClass instanceof StatusMessage) {
+ StatusMessage statusMessage = (StatusMessage) msgClass;
+ statusMessage.parse(params);
+ return statusMessage;
+ }
+ }
+
+ return null;
+ }
+
+
+}
+
+
+/**
+ * ALL status message opcode
+ */
+ /*
+
+ Opcode messageOpcode = Opcode.valueOf(opcode);
+ StatusMessage statusMessage = null;
+ if (messageOpcode == null) return null;
+ switch (messageOpcode) {
+ case COMPOSITION_DATA_STATUS:
+ case HEALTH_CURRENT_STATUS:
+ case HEALTH_FAULT_STATUS:
+ case HEARTBEAT_PUB_STATUS:
+ case APPKEY_STATUS:
+ case HEALTH_ATTENTION_STATUS:
+ case CFG_BEACON_STATUS:
+ case CFG_DEFAULT_TTL_STATUS:
+ case CFG_FRIEND_STATUS:
+ case CFG_GATT_PROXY_STATUS:
+ case CFG_KEY_REFRESH_PHASE_STATUS:
+ case CFG_MODEL_PUB_STATUS:
+ case CFG_MODEL_SUB_STATUS:
+ case CFG_NW_TRANSMIT_STATUS:
+ case CFG_RELAY_STATUS:
+ case CFG_LPN_POLL_TIMEOUT_STATUS:
+ case HEALTH_PERIOD_STATUS:
+ case HEARTBEAT_SUB_STATUS:
+ case MODE_APP_STATUS:
+ case NETKEY_STATUS:
+ case NODE_ID_STATUS:
+ case NODE_RESET_STATUS:
+
+ case G_ONOFF_STATUS:
+ statusMessage = new OnOffStatusMessage();
+ break;
+ case G_LEVEL_STATUS:
+ case G_DEF_TRANS_TIME_STATUS:
+ case G_ON_POWER_UP_STATUS:
+ case G_POWER_LEVEL_STATUS:
+ case G_POWER_LEVEL_LAST_STATUS:
+ case G_POWER_DEF_STATUS:
+ case G_POWER_LEVEL_RANGE_STATUS:
+ case G_BATTERY_STATUS:
+ case G_LOCATION_GLOBAL_STATUS:
+ case G_LOCATION_LOCAL_STATUS:
+ case LIGHTNESS_STATUS:
+ case LIGHTNESS_LINEAR_STATUS:
+ case LIGHTNESS_LAST_STATUS:
+ case LIGHTNESS_DEFULT_STATUS:
+ case LIGHTNESS_RANGE_STATUS:
+ case LIGHT_CTL_STATUS:
+ case LIGHT_CTL_TEMP_RANGE_STATUS:
+ case LIGHT_CTL_TEMP_STATUS:
+ case LIGHT_CTL_DEFULT_STATUS:
+ case LIGHT_HSL_HUE_STATUS:
+ case LIGHT_HSL_SAT_STATUS:
+ case LIGHT_HSL_STATUS:
+ case LIGHT_HSL_TARGET_STATUS:
+ case LIGHT_HSL_DEF_STATUS:
+ case LIGHT_HSL_RANGE_STATUS:
+ case TIME_STATUS:
+ case TIME_ROLE_STATUS:
+ case TIME_ZONE_STATUS:
+ case TAI_UTC_DELTA_STATUS:
+ case SCHD_ACTION_STATUS:
+ case SCHD_STATUS:
+ case SCENE_STATUS:
+ case SCENE_REG_STATUS:
+
+
+ break;
+ }
+
+ */
\ No newline at end of file
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/AppKeyAddMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/AppKeyAddMessage.java
new file mode 100644
index 00000000..d061b3bd
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/AppKeyAddMessage.java
@@ -0,0 +1,87 @@
+/********************************************************************************************************
+ * @file AppKeyAddMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/12.
+ */
+
+public class AppKeyAddMessage extends ConfigMessage {
+
+
+ private int netKeyIndex;
+
+ private int appKeyIndex;
+
+ private byte[] appKey;
+
+ public AppKeyAddMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ public void setNetKeyIndex(int netKeyIndex) {
+ this.netKeyIndex = netKeyIndex;
+ }
+
+ public void setAppKeyIndex(int appKeyIndex) {
+ this.appKeyIndex = appKeyIndex;
+ }
+
+
+ public void setAppKey(byte[] appKey) {
+ this.appKey = appKey;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.APPKEY_ADD.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.APPKEY_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+
+ // netKey index lower 12 bits
+ // appKey index higher 12 bits
+
+ int netAppKeyIndex = (netKeyIndex & 0x0FFF) | ((appKeyIndex & 0x0FFF) << 12);
+// int netAppKeyIndex = ((netKeyIndex & 0x0FFF) << 12) | ((appKeyIndex & 0x0FFF));
+ byte[] indexesBuf = MeshUtils.integer2Bytes(netAppKeyIndex, 3, ByteOrder.LITTLE_ENDIAN);
+
+ ByteBuffer paramsBuffer = ByteBuffer.allocate(3 + 16).order(ByteOrder.LITTLE_ENDIAN)
+ .put(indexesBuf)
+ .put(appKey);
+ return paramsBuffer.array();
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/AppKeyStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/AppKeyStatusMessage.java
new file mode 100644
index 00000000..44436fca
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/AppKeyStatusMessage.java
@@ -0,0 +1,111 @@
+/********************************************************************************************************
+ * @file AppKeyStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/9/10.
+ */
+
+public class AppKeyStatusMessage extends StatusMessage {
+
+ /**
+ * 1 byte
+ */
+ private byte status;
+
+ /**
+ * 12 bits
+ */
+ private int netKeyIndex;
+
+ /**
+ * 12 bits
+ */
+ private int appKeyIndex;
+
+
+ public AppKeyStatusMessage() {
+ }
+
+ protected AppKeyStatusMessage(Parcel in) {
+ status = in.readByte();
+ netKeyIndex = in.readInt();
+ appKeyIndex = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public AppKeyStatusMessage createFromParcel(Parcel in) {
+ return new AppKeyStatusMessage(in);
+ }
+
+ @Override
+ public AppKeyStatusMessage[] newArray(int size) {
+ return new AppKeyStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ status = params[0];
+
+ int netAppKeyIndex = MeshUtils.bytes2Integer(new byte[]{
+ params[1], params[2], params[3],
+ }, ByteOrder.LITTLE_ENDIAN);
+
+ this.netKeyIndex = netAppKeyIndex & 0x0FFF;
+ this.appKeyIndex = (netAppKeyIndex >> 12) & 0x0FFF;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(status);
+ dest.writeInt(netKeyIndex);
+ dest.writeInt(appKeyIndex);
+ }
+
+ public byte getStatus() {
+ return status;
+ }
+
+ public int getNetKeyIndex() {
+ return netKeyIndex;
+ }
+
+ public int getAppKeyIndex() {
+ return appKeyIndex;
+ }
+
+}
+
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/BridgingTableAddMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/BridgingTableAddMessage.java
new file mode 100644
index 00000000..d88faa83
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/BridgingTableAddMessage.java
@@ -0,0 +1,92 @@
+/********************************************************************************************************
+ * @file AppKeyAddMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2021/1/14.
+ */
+public class BridgingTableAddMessage extends ConfigMessage {
+
+ /**
+ * Allowed directions for the bridged traffic
+ * 8 bits
+ */
+ public byte directions;
+
+ /**
+ * NetKey Index of the first subnet
+ * 12 bits
+ */
+ public int netKeyIndex1;
+
+ /**
+ * NetKey Index of the second subnet
+ * 12 bits
+ */
+ public int netKeyIndex2;
+
+ /**
+ * Address of the node in the first subnet
+ * 16 bits
+ */
+ public int address1;
+
+ /**
+ * Address of the node in the second subnet
+ * 16 bits
+ */
+ public int address2;
+
+
+ public BridgingTableAddMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.BRIDGING_TABLE_ADD.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.BRIDGING_TABLE_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ int netKeyIndexes = (netKeyIndex1 & 0x0FFF) | ((netKeyIndex2 & 0x0FFF) << 12);
+ byte[] indexesBuf = MeshUtils.integer2Bytes(netKeyIndexes, 3, ByteOrder.LITTLE_ENDIAN);
+ return ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN)
+ .put(directions)
+ .put(indexesBuf)
+ .putShort((short) address1)
+ .putShort((short) address2).array();
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/BridgingTableRemoveMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/BridgingTableRemoveMessage.java
new file mode 100644
index 00000000..d8e6ad19
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/BridgingTableRemoveMessage.java
@@ -0,0 +1,86 @@
+/********************************************************************************************************
+ * @file AppKeyAddMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2021/1/14.
+ */
+public class BridgingTableRemoveMessage extends ConfigMessage {
+
+
+ /**
+ * NetKey Index of the first subnet
+ * 12 bits
+ */
+ public int netKeyIndex1;
+
+ /**
+ * NetKey Index of the second subnet
+ * 12 bits
+ */
+ public int netKeyIndex2;
+
+ /**
+ * Address of the node in the first subnet
+ * 16 bits
+ */
+ public int address1;
+
+ /**
+ * Address of the node in the second subnet
+ * 16 bits
+ */
+ public int address2;
+
+
+ public BridgingTableRemoveMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.BRIDGING_TABLE_REMOVE.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.BRIDGING_TABLE_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ int netKeyIndexes = (netKeyIndex1 & 0x0FFF) | ((netKeyIndex2 & 0x0FFF) << 12);
+ byte[] indexesBuf = MeshUtils.integer2Bytes(netKeyIndexes, 3, ByteOrder.LITTLE_ENDIAN);
+ return ByteBuffer.allocate(7).order(ByteOrder.LITTLE_ENDIAN)
+ .put(indexesBuf)
+ .putShort((short) address1)
+ .putShort((short) address2).array();
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/BridgingTableStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/BridgingTableStatusMessage.java
new file mode 100644
index 00000000..16ebbb18
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/BridgingTableStatusMessage.java
@@ -0,0 +1,157 @@
+/********************************************************************************************************
+ * @file BridgingTableStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2021/1/14.
+ */
+public class BridgingTableStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * Status Code for the requesting message
+ * 8 bits
+ */
+ private int status;
+
+ /**
+ * Allowed directions for bridged traffic or bridged traffic not allowed
+ * 8 bits
+ */
+ private byte currentDirections;
+
+ /**
+ * NetKey Index of the first subnet
+ * 12 bits
+ */
+ public int netKeyIndex1;
+
+ /**
+ * NetKey Index of the second subnet
+ * 12 bits
+ */
+ public int netKeyIndex2;
+
+ /**
+ * Address of the node in the first subnet
+ * 16 bits
+ */
+ public int address1;
+
+ /**
+ * Address of the node in the second subnet
+ * 16 bits
+ */
+ public int address2;
+
+
+ public BridgingTableStatusMessage() {
+ }
+
+
+ protected BridgingTableStatusMessage(Parcel in) {
+ status = in.readInt();
+ currentDirections = in.readByte();
+ netKeyIndex1 = in.readInt();
+ netKeyIndex2 = in.readInt();
+ address1 = in.readInt();
+ address2 = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public BridgingTableStatusMessage createFromParcel(Parcel in) {
+ return new BridgingTableStatusMessage(in);
+ }
+
+ @Override
+ public BridgingTableStatusMessage[] newArray(int size) {
+ return new BridgingTableStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.status = params[index++] & 0xFF;
+ this.currentDirections = params[index++];
+
+ int netKeyIndexes = MeshUtils.bytes2Integer(new byte[]{
+ params[index++], params[index++], params[index++],
+ }, ByteOrder.LITTLE_ENDIAN);
+
+ this.netKeyIndex1 = netKeyIndexes & 0x0FFF;
+ this.netKeyIndex2 = (netKeyIndexes >> 12) & 0x0FFF;
+
+
+ this.address1 = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.address2 = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ }
+
+
+ public int getStatus() {
+ return status;
+ }
+
+ public byte getCurrentDirections() {
+ return currentDirections;
+ }
+
+ public int getNetKeyIndex1() {
+ return netKeyIndex1;
+ }
+
+ public int getNetKeyIndex2() {
+ return netKeyIndex2;
+ }
+
+ public int getAddress1() {
+ return address1;
+ }
+
+ public int getAddress2() {
+ return address2;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeByte(currentDirections);
+ dest.writeInt(netKeyIndex1);
+ dest.writeInt(netKeyIndex2);
+ dest.writeInt(address1);
+ dest.writeInt(address2);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/CompositionDataGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/CompositionDataGetMessage.java
new file mode 100644
index 00000000..69401b36
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/CompositionDataGetMessage.java
@@ -0,0 +1,53 @@
+/********************************************************************************************************
+ * @file CompositionDataGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * Created by kee on 2019/8/12.
+ */
+
+public class CompositionDataGetMessage extends ConfigMessage {
+
+
+ public CompositionDataGetMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.COMPOSITION_DATA_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.COMPOSITION_DATA_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return new byte[]{(byte) 0xFF};
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/CompositionDataStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/CompositionDataStatusMessage.java
new file mode 100644
index 00000000..ee6a3c61
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/CompositionDataStatusMessage.java
@@ -0,0 +1,87 @@
+/********************************************************************************************************
+ * @file CompositionDataStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+import com.telink.ble.mesh.entity.CompositionData;
+
+/**
+ * node reset status is empty message
+ * Created by kee on 2019/9/18.
+ */
+
+public class CompositionDataStatusMessage extends StatusMessage implements Parcelable {
+
+ private byte page;
+
+ private CompositionData compositionData;
+
+ public CompositionDataStatusMessage() {
+ }
+
+ protected CompositionDataStatusMessage(Parcel in) {
+ page = in.readByte();
+ compositionData = in.readParcelable(CompositionData.class.getClassLoader());
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public CompositionDataStatusMessage createFromParcel(Parcel in) {
+ return new CompositionDataStatusMessage(in);
+ }
+
+ @Override
+ public CompositionDataStatusMessage[] newArray(int size) {
+ return new CompositionDataStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ page = params[0];
+ byte[] cpsData = new byte[params.length - 1];
+ System.arraycopy(params, 1, cpsData, 0, cpsData.length);
+ compositionData = CompositionData.from(cpsData);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(page);
+ dest.writeParcelable(compositionData, flags);
+ }
+
+ public byte getPage() {
+ return page;
+ }
+
+ public CompositionData getCompositionData() {
+ return compositionData;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ConfigMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ConfigMessage.java
new file mode 100644
index 00000000..acac2b99
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ConfigMessage.java
@@ -0,0 +1,51 @@
+/********************************************************************************************************
+ * @file ConfigMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.networking.AccessType;
+
+import androidx.annotation.IntRange;
+
+/**
+ * configuration message
+ * Created by kee on 2019/8/14.
+ */
+public abstract class ConfigMessage extends MeshMessage {
+
+ public ConfigMessage(@IntRange(from = 1, to = 0x7FFF) int destinationAddress) {
+ this.destinationAddress = destinationAddress;
+ // default rsp max
+ this.responseMax = 1;
+ }
+
+ /**
+ * for config message , AKF is 0
+ *
+ * @return application key flag
+ */
+ @Override
+ public AccessType getAccessType() {
+ return AccessType.DEVICE;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ConfigStatus.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ConfigStatus.java
new file mode 100644
index 00000000..ecec4596
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ConfigStatus.java
@@ -0,0 +1,81 @@
+/********************************************************************************************************
+ * @file ConfigStatus.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+public enum ConfigStatus {
+
+ SUCCESS(0x00, "Success"),
+
+ /**
+ * error code
+ */
+ INVALID_ADDRESS(0x01, "Invalid Address"),
+
+ INVALID_MODEL(0x02, "Invalid Model"),
+
+ INVALID_APPKEY_INDEX(0x03, "Invalid AppKey Index"),
+
+ INVALID_NETKEY_INDEX(0x04, "Invalid NetKey Index"),
+
+ INSUFFICIENT_RESOURCES(0x05, "Insufficient Resources"),
+
+ KEY_INDEX_ALREADY_STORED(0x06, "Key Index Already Stored"),
+
+ INVALID_PUBLISH_PARAMETERS(0x07, "Invalid Publish Parameters"),
+
+ NOT_A_SUBSCRIBE_MODEL(0x08, "Not a Subscribe Model"),
+
+ STORAGE_FAILURE(0x09, "Storage Failure"),
+
+ FEATURE_NOT_SUPPORTED(0x0A, "Feature Not Supported"),
+
+ CANNOT_UPDATE(0x0B, "Cannot Update"),
+
+ CANNOT_REMOVE(0x0C, "Cannot Remove"),
+
+ CANNOT_BIND(0x0D, "Cannot Bind"),
+
+ TEMPORARILY_UNABLE_TO_CHANGE_STATE(0x0E, "Temporarily Unable to Change State"),
+
+ CANNOT_SET(0x0F, "Cannot Set"),
+
+ UNSPECIFIED_ERROR(0x10, "Unspecified Error"),
+
+ INVALID_BINDING(0x11, "Invalid Binding"),
+
+ UNKNOWN_ERROR(0xFF, "unknown error");
+
+ public final int code;
+ public final String desc;
+
+ ConfigStatus(int code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static ConfigStatus valueOf(int code) {
+ for (ConfigStatus status : values()) {
+ if (status.code == code) return status;
+ }
+ return UNKNOWN_ERROR;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/HeartbeatPublicationSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/HeartbeatPublicationSetMessage.java
new file mode 100644
index 00000000..6e1893f0
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/HeartbeatPublicationSetMessage.java
@@ -0,0 +1,93 @@
+/********************************************************************************************************
+ * @file HeartbeatPublicationSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/23.
+ */
+
+public class HeartbeatPublicationSetMessage extends ConfigMessage {
+
+ private int destination;
+
+ private byte countLog;
+
+ private byte periodLog;
+
+ private byte hbTtl;
+
+ // 2 bytes
+ private int features;
+
+ // 2 bytes
+ private int netKeyIndex;
+
+ public HeartbeatPublicationSetMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.HEARTBEAT_PUB_SET.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ ByteBuffer byteBuffer = ByteBuffer.allocate(9).order(ByteOrder.LITTLE_ENDIAN);
+ byteBuffer.putShort((short) destination)
+ .put(countLog)
+ .put(periodLog)
+ .put(hbTtl)
+ .putShort((short) features)
+ .putShort((short) netKeyIndex);
+ return byteBuffer.array();
+ }
+
+ public void setDestination(int destination) {
+ this.destination = destination;
+ }
+
+ public void setCountLog(byte countLog) {
+ this.countLog = countLog;
+ }
+
+ public void setPeriodLog(byte periodLog) {
+ this.periodLog = periodLog;
+ }
+
+ public void setHbTtl(byte hbTtl) {
+ this.hbTtl = hbTtl;
+ }
+
+ public void setFeatures(int features) {
+ this.features = features;
+ }
+
+ public void setNetKeyIndex(int netKeyIndex) {
+ this.netKeyIndex = netKeyIndex;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelAppBindMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelAppBindMessage.java
new file mode 100644
index 00000000..c93d91ba
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelAppBindMessage.java
@@ -0,0 +1,109 @@
+/********************************************************************************************************
+ * @file ModelAppBindMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/12.
+ */
+
+public class ModelAppBindMessage extends ConfigMessage {
+
+ /**
+ * Address of the element
+ * 2 bytes
+ */
+ private int elementAddress;
+
+ /**
+ * Index of the AppKey
+ * 2 bytes, really 12 bit used
+ */
+ private int appKeyIndex;
+
+ /**
+ * SIG Model ID or Vendor Model ID
+ * if SIG: 2 bytes
+ * else : 4 bytes
+ */
+ private int modelIdentifier;
+
+ private boolean isSigModel = true;
+
+ public ModelAppBindMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ public void setElementAddress(int elementAddress) {
+ this.elementAddress = elementAddress;
+ }
+
+ public void setAppKeyIndex(int appKeyIndex) {
+ this.appKeyIndex = appKeyIndex;
+ }
+
+ public void setModelIdentifier(int modelIdentifier) {
+ this.modelIdentifier = modelIdentifier;
+ }
+
+ public void setSigModel(boolean sigModel) {
+ isSigModel = sigModel;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.MODE_APP_BIND.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.MODE_APP_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ // check if sig model or vendor model
+// boolean isSigModel = isSigModel(this.modelIdentifier);
+ int bufferSize = isSigModel ? 6 : 8;
+ ByteBuffer paramsBuffer = ByteBuffer.allocate(bufferSize).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) this.elementAddress)
+ .putShort((short) this.appKeyIndex);
+ if (isSigModel) {
+ paramsBuffer.putShort((short) this.modelIdentifier);
+ } else {
+ paramsBuffer.putInt(this.modelIdentifier);
+ }
+ return paramsBuffer.array();
+ }
+
+ /**
+ * @deprecated
+ */
+ private boolean isSigModel(int modelIdentifier) {
+ return modelIdentifier <= 0xFFFF;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelAppStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelAppStatusMessage.java
new file mode 100644
index 00000000..1e824442
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelAppStatusMessage.java
@@ -0,0 +1,122 @@
+/********************************************************************************************************
+ * @file ModelAppStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/9/10.
+ */
+
+public class ModelAppStatusMessage extends StatusMessage implements Parcelable {
+
+ private static final int MODEL_STATUS_SIG_LEN = 7;
+
+ private static final int MODEL_STATUS_VENDOR_LEN = 9;
+
+ private byte status;
+
+ private int elementAddress;
+
+ private int appKeyIndex;
+
+ /**
+ * 2 or 4 bytes
+ */
+ private int modelIdentifier;
+
+ public ModelAppStatusMessage() {
+ }
+
+ protected ModelAppStatusMessage(Parcel in) {
+ status = in.readByte();
+ elementAddress = in.readInt();
+ appKeyIndex = in.readInt();
+ modelIdentifier = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ModelAppStatusMessage createFromParcel(Parcel in) {
+ return new ModelAppStatusMessage(in);
+ }
+
+ @Override
+ public ModelAppStatusMessage[] newArray(int size) {
+ return new ModelAppStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ status = params[index++];
+
+ elementAddress = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ appKeyIndex = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ int modelIdLen;
+ if (params.length == MODEL_STATUS_SIG_LEN) {
+ modelIdLen = 2;
+ } else {
+ modelIdLen = 4;
+ }
+ modelIdentifier = MeshUtils.bytes2Integer(params, index, modelIdLen, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(status);
+ dest.writeInt(elementAddress);
+ dest.writeInt(appKeyIndex);
+ dest.writeInt(modelIdentifier);
+ }
+
+ public byte getStatus() {
+ return status;
+ }
+
+ public int getElementAddress() {
+ return elementAddress;
+ }
+
+ public int getAppKeyIndex() {
+ return appKeyIndex;
+ }
+
+ public int getModelIdentifier() {
+ return modelIdentifier;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelPublicationSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelPublicationSetMessage.java
new file mode 100644
index 00000000..591989e0
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelPublicationSetMessage.java
@@ -0,0 +1,64 @@
+/********************************************************************************************************
+ * @file ModelPublicationSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.entity.ModelPublication;
+
+/**
+ * Created by kee on 2019/8/12.
+ */
+
+public class ModelPublicationSetMessage extends ConfigMessage {
+
+ private ModelPublication modelPublication;
+
+ public ModelPublicationSetMessage(int destinationAddress, ModelPublication modelPublication) {
+ super(destinationAddress);
+ this.modelPublication = modelPublication;
+ this.responseOpcode = Opcode.CFG_MODEL_PUB_STATUS.value;
+ this.responseMax = 1;
+ }
+
+ public ModelPublicationSetMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.CFG_MODEL_PUB_SET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.CFG_MODEL_PUB_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return modelPublication.toBytes();
+ }
+
+ public void setModelPublication(ModelPublication modelPublication) {
+ this.modelPublication = modelPublication;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelPublicationStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelPublicationStatusMessage.java
new file mode 100644
index 00000000..2f2edd3b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelPublicationStatusMessage.java
@@ -0,0 +1,112 @@
+/********************************************************************************************************
+ * @file ModelPublicationStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+import com.telink.ble.mesh.entity.ModelPublication;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/9/10.
+ */
+
+public class ModelPublicationStatusMessage extends StatusMessage implements Parcelable {
+
+ private byte status;
+
+ private ModelPublication publication;
+
+ public ModelPublicationStatusMessage() {
+ }
+
+ protected ModelPublicationStatusMessage(Parcel in) {
+ status = in.readByte();
+ publication = in.readParcelable(ModelPublication.class.getClassLoader());
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ModelPublicationStatusMessage createFromParcel(Parcel in) {
+ return new ModelPublicationStatusMessage(in);
+ }
+
+ @Override
+ public ModelPublicationStatusMessage[] newArray(int size) {
+ return new ModelPublicationStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] data) {
+ int index = 0;
+ this.status = data[index++];
+
+ ModelPublication modelPublication = new ModelPublication();
+ modelPublication.elementAddress = MeshUtils.bytes2Integer(data, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ modelPublication.publishAddress = MeshUtils.bytes2Integer(data, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ modelPublication.appKeyIndex = (data[index++] & 0xFF) | ((data[index] & 0b1111) << 8);
+
+ modelPublication.credentialFlag = (data[index] >> 4) & 0b1;
+ modelPublication.rfu = (data[index] >> 5) & 0b111;
+ index++;
+
+ modelPublication.ttl = data[index++];
+ modelPublication.period = data[index++];
+ modelPublication.retransmitCount = (data[index] >> 5) & 0b111;
+ modelPublication.retransmitIntervalSteps = data[index++] & 0x1F;
+
+ modelPublication.modelId = (data[index++] & 0xFF) | ((data[index++] & 0xFF) << 8);
+ if ((index + 2) <= data.length) {
+ modelPublication.sig = true;
+ modelPublication.modelId |= ((data[index++] & 0xFF) << 16) | ((data[index] & 0xFF) << 24);
+ }
+ this.publication = modelPublication;
+ }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(status);
+ dest.writeParcelable(publication, flags);
+ }
+
+ public byte getStatus() {
+ return status;
+ }
+
+ public ModelPublication getPublication() {
+ return publication;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelSubscriptionSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelSubscriptionSetMessage.java
new file mode 100644
index 00000000..687d17ba
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelSubscriptionSetMessage.java
@@ -0,0 +1,126 @@
+/********************************************************************************************************
+ * @file ModelSubscriptionSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * grouping
+ * Created by kee on 2019/8/12.
+ */
+
+public class ModelSubscriptionSetMessage extends ConfigMessage {
+
+ private static final int PARAM_LEN_SIG = 6;
+
+ private static final int PARAM_LEN_VENDOR = 8;
+
+ public static final int MODE_ADD = 0;
+
+ public static final int MODE_DELETE = 1;
+
+ private int mode = MODE_ADD;
+
+ private int elementAddress;
+
+ /**
+ * group address
+ */
+ private int address;
+
+ /**
+ * 2 or 4 bytes
+ * determined by sig
+ */
+ private int modelIdentifier;
+
+ /**
+ * is sig or vendor
+ */
+ private boolean isSig = true;
+
+
+ public static ModelSubscriptionSetMessage getSimple(int destinationAddress, int mode, int elementAddress, int groupAddress, int modelId, boolean isSig) {
+ ModelSubscriptionSetMessage message = new ModelSubscriptionSetMessage(destinationAddress);
+ message.mode = mode;
+ message.elementAddress = elementAddress;
+ message.address = groupAddress;
+ message.modelIdentifier = modelId;
+ message.isSig = isSig;
+ return message;
+ }
+
+ public ModelSubscriptionSetMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return mode == MODE_ADD ? Opcode.CFG_MODEL_SUB_ADD.value : Opcode.CFG_MODEL_SUB_DEL.value ;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.CFG_MODEL_SUB_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ if (isSig) {
+ return ByteBuffer.allocate(PARAM_LEN_SIG).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) elementAddress)
+ .putShort((short) address)
+ .putShort((short) modelIdentifier)
+ .array();
+ } else {
+ return ByteBuffer.allocate(PARAM_LEN_VENDOR).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) elementAddress)
+ .putShort((short) address)
+ .putInt(modelIdentifier)
+ .array();
+ }
+
+ }
+
+ public void setMode(int mode) {
+ this.mode = mode;
+ }
+
+ public void setElementAddress(int elementAddress) {
+ this.elementAddress = elementAddress;
+ }
+
+ public void setAddress(int address) {
+ this.address = address;
+ }
+
+ public void setModelIdentifier(int modelIdentifier) {
+ this.modelIdentifier = modelIdentifier;
+ }
+
+ public void setSig(boolean sig) {
+ isSig = sig;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelSubscriptionStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelSubscriptionStatusMessage.java
new file mode 100644
index 00000000..8a36b432
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/ModelSubscriptionStatusMessage.java
@@ -0,0 +1,145 @@
+/********************************************************************************************************
+ * @file ModelSubscriptionStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/9/10.
+ */
+
+public class ModelSubscriptionStatusMessage extends StatusMessage implements Parcelable {
+
+ private static final int DATA_LEN_SIG = 7;
+
+ private static final int DATA_LEN_VENDOR = 9;
+
+ private byte status;
+
+ private int elementAddress;
+
+ /**
+ * group address
+ */
+ private int address;
+
+ /**
+ * 2 or 4 bytes
+ * determined by sig
+ */
+ private int modelIdentifier;
+
+ /**
+ * is sig or vendor
+ */
+ private boolean isSig = true;
+
+
+ public ModelSubscriptionStatusMessage() {
+ }
+
+
+ protected ModelSubscriptionStatusMessage(Parcel in) {
+ status = in.readByte();
+ elementAddress = in.readInt();
+ address = in.readInt();
+ modelIdentifier = in.readInt();
+ isSig = in.readByte() != 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ModelSubscriptionStatusMessage createFromParcel(Parcel in) {
+ return new ModelSubscriptionStatusMessage(in);
+ }
+
+ @Override
+ public ModelSubscriptionStatusMessage[] newArray(int size) {
+ return new ModelSubscriptionStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ isSig = params.length == DATA_LEN_SIG;
+
+ int index = 0;
+ status = params[index++];
+ elementAddress = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ address = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ modelIdentifier = MeshUtils.bytes2Integer(params, index, isSig ? 2 : 4, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(status);
+ dest.writeInt(elementAddress);
+ dest.writeInt(address);
+ dest.writeInt(modelIdentifier);
+ dest.writeByte((byte) (isSig ? 1 : 0));
+ }
+
+ public byte getStatus() {
+ return status;
+ }
+
+ public int getElementAddress() {
+ return elementAddress;
+ }
+
+ public int getAddress() {
+ return address;
+ }
+
+ public int getModelIdentifier() {
+ return modelIdentifier;
+ }
+
+ public boolean isSig() {
+ return isSig;
+ }
+
+ @Override
+ public String toString() {
+ return "ModelSubscriptionStatusMessage{" +
+ "status=" + status +
+ ", elementAddress=" + elementAddress +
+ ", address=" + address +
+ ", modelIdentifier=" + modelIdentifier +
+ ", isSig=" + isSig +
+ '}';
+ }
+}
+
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetKeyAddMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetKeyAddMessage.java
new file mode 100644
index 00000000..03ea019b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetKeyAddMessage.java
@@ -0,0 +1,70 @@
+/********************************************************************************************************
+ * @file AppKeyAddMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/12.
+ */
+
+public class NetKeyAddMessage extends ConfigMessage {
+
+
+ public int netKeyIndex;
+
+ public byte[] netKey;
+
+
+ public NetKeyAddMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ public NetKeyAddMessage(int destinationAddress, int netKeyIndex, byte[] netKey) {
+ super(destinationAddress);
+ this.netKeyIndex = netKeyIndex;
+ this.netKey = netKey;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.NETKEY_ADD.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.NETKEY_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ ByteBuffer paramsBuffer = ByteBuffer.allocate(2 + 16).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) this.netKeyIndex)
+ .put(netKey);
+ return paramsBuffer.array();
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetKeyDeleteMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetKeyDeleteMessage.java
new file mode 100644
index 00000000..eda5e70d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetKeyDeleteMessage.java
@@ -0,0 +1,66 @@
+/********************************************************************************************************
+ * @file AppKeyAddMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/12.
+ */
+
+public class NetKeyDeleteMessage extends ConfigMessage {
+
+
+ public int netKeyIndex;
+
+
+ public NetKeyDeleteMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ public NetKeyDeleteMessage(int destinationAddress, int netKeyIndex) {
+ super(destinationAddress);
+ this.netKeyIndex = netKeyIndex;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.NETKEY_DEL.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.NETKEY_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ ByteBuffer paramsBuffer = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) this.netKeyIndex);
+ return paramsBuffer.array();
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetKeyStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetKeyStatusMessage.java
new file mode 100644
index 00000000..f9453424
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetKeyStatusMessage.java
@@ -0,0 +1,96 @@
+/********************************************************************************************************
+ * @file NodeIdentityStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/9/10.
+ */
+
+public class NetKeyStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * 1 byte
+ */
+ private int status;
+
+ /**
+ * 2 bytes
+ */
+ private int netKeyIndex;
+
+
+ public NetKeyStatusMessage() {
+ }
+
+
+ protected NetKeyStatusMessage(Parcel in) {
+ status = in.readInt();
+ netKeyIndex = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public NetKeyStatusMessage createFromParcel(Parcel in) {
+ return new NetKeyStatusMessage(in);
+ }
+
+ @Override
+ public NetKeyStatusMessage[] newArray(int size) {
+ return new NetKeyStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ status = params[index++] & 0xFF;
+ netKeyIndex = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public int getNetKeyIndex() {
+ return netKeyIndex;
+ }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(netKeyIndex);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetworkTransmitSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetworkTransmitSetMessage.java
new file mode 100644
index 00000000..5d77ff4d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetworkTransmitSetMessage.java
@@ -0,0 +1,74 @@
+/********************************************************************************************************
+ * @file NetworkTransmitSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * set network transmit params
+ * Network transmit params are used when node sending network pdu from self -- source address is self --
+ * Meanwhile relay params are used when relay network pdu, generally smaller than network transmit
+ * Created by kee on 2020/03/20.
+ */
+
+public class NetworkTransmitSetMessage extends ConfigMessage {
+
+
+ // networkTransmitCount, default is 5
+ private int count;
+
+
+ // networkTransmitIntervalSteps, default is 2
+ // transmission interval = (Network Transmit Interval Steps + 1) * 10
+ private int intervalSteps;
+
+ public NetworkTransmitSetMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public void setIntervalSteps(int intervalSteps) {
+ this.intervalSteps = intervalSteps;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.CFG_NW_TRANSMIT_SET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.CFG_NW_TRANSMIT_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return new byte[]{
+ (byte) ((count & 0b111) | (intervalSteps << 3))
+ };
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetworkTransmitStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetworkTransmitStatusMessage.java
new file mode 100644
index 00000000..3c65e5a1
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NetworkTransmitStatusMessage.java
@@ -0,0 +1,86 @@
+/********************************************************************************************************
+ * @file NetworkTransmitStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+/**
+ * Created by kee on 2019/9/10.
+ */
+
+public class NetworkTransmitStatusMessage extends StatusMessage implements Parcelable {
+
+ private int count;
+
+ private int intervalSteps;
+
+
+ public NetworkTransmitStatusMessage() {
+ }
+
+
+ protected NetworkTransmitStatusMessage(Parcel in) {
+ count = in.readInt();
+ intervalSteps = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public NetworkTransmitStatusMessage createFromParcel(Parcel in) {
+ return new NetworkTransmitStatusMessage(in);
+ }
+
+ @Override
+ public NetworkTransmitStatusMessage[] newArray(int size) {
+ return new NetworkTransmitStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] data) {
+ int index = 0;
+ this.count = data[0] & 0b111;
+ this.intervalSteps = (data[0] & 0xFF) >> 3;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public int getIntervalSteps() {
+ return intervalSteps;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(count);
+ dest.writeInt(intervalSteps);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeIdentity.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeIdentity.java
new file mode 100644
index 00000000..9c35ccec
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeIdentity.java
@@ -0,0 +1,47 @@
+/********************************************************************************************************
+ * @file NodeIdentity.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+public enum NodeIdentity {
+ STOPPED(0, "Node Identity for a subnet is stopped"),
+
+ RUNNING(1, "Node Identity for a subnet is running"),
+
+ UNSUPPORTED(2, "Node Identity is not supported"),
+
+ UNKNOWN_ERROR(0xFF, "unknown error");
+
+ public final int code;
+ public final String desc;
+
+ NodeIdentity(int code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static NodeIdentity valueOf(int code) {
+ for (NodeIdentity status : values()) {
+ if (status.code == code) return status;
+ }
+ return UNKNOWN_ERROR;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeIdentitySetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeIdentitySetMessage.java
new file mode 100644
index 00000000..6b467474
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeIdentitySetMessage.java
@@ -0,0 +1,72 @@
+/********************************************************************************************************
+ * @file NodeIdentitySetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/12.
+ */
+
+public class NodeIdentitySetMessage extends ConfigMessage {
+
+ private int netKeyIndex;
+
+ private int identity;
+
+ public NodeIdentitySetMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.NODE_ID_SET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.NODE_ID_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+
+ // netKey index lower 12 bits
+ int netAppKeyIndex = (netKeyIndex & 0x0FFF);
+ ByteBuffer paramsBuffer = ByteBuffer.allocate(3).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) (netKeyIndex & 0x0FFF))
+ .put((byte) identity);
+ return paramsBuffer.array();
+ }
+
+ public void setNetKeyIndex(int netKeyIndex) {
+ this.netKeyIndex = netKeyIndex;
+ }
+
+ public void setIdentity(int identity) {
+ this.identity = identity;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeIdentityStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeIdentityStatusMessage.java
new file mode 100644
index 00000000..f7d1cd9b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeIdentityStatusMessage.java
@@ -0,0 +1,107 @@
+/********************************************************************************************************
+ * @file NodeIdentityStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/9/10.
+ */
+
+public class NodeIdentityStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * 1 byte
+ */
+ private int status;
+
+ /**
+ * 2 bytes
+ */
+ private int netKeyIndex;
+
+ /**
+ * 1 byte
+ */
+ private int identity;
+
+ public NodeIdentityStatusMessage() {
+ }
+
+
+ protected NodeIdentityStatusMessage(Parcel in) {
+ status = in.readInt();
+ netKeyIndex = in.readInt();
+ identity = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public NodeIdentityStatusMessage createFromParcel(Parcel in) {
+ return new NodeIdentityStatusMessage(in);
+ }
+
+ @Override
+ public NodeIdentityStatusMessage[] newArray(int size) {
+ return new NodeIdentityStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ status = params[index++] & 0xFF;
+ netKeyIndex = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ identity = params[index] & 0xFF;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public int getNetKeyIndex() {
+ return netKeyIndex;
+ }
+
+ public int getIdentity() {
+ return identity;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(netKeyIndex);
+ dest.writeInt(identity);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeResetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeResetMessage.java
new file mode 100644
index 00000000..3d60bf57
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeResetMessage.java
@@ -0,0 +1,51 @@
+/********************************************************************************************************
+ * @file NodeResetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * Node reset
+ * Created by kee on 2019/8/12.
+ */
+
+public class NodeResetMessage extends ConfigMessage {
+
+ public NodeResetMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.NODE_RESET.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return null;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.NODE_RESET_STATUS.value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeResetStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeResetStatusMessage.java
new file mode 100644
index 00000000..58952a81
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/NodeResetStatusMessage.java
@@ -0,0 +1,68 @@
+/********************************************************************************************************
+ * @file NodeResetStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+/**
+ * node reset status is empty message
+ * Created by kee on 2019/9/18.
+ */
+
+public class NodeResetStatusMessage extends StatusMessage implements Parcelable {
+
+ public NodeResetStatusMessage() {
+ }
+
+ protected NodeResetStatusMessage(Parcel in) {
+
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public NodeResetStatusMessage createFromParcel(Parcel in) {
+ return new NodeResetStatusMessage(in);
+ }
+
+ @Override
+ public NodeResetStatusMessage[] newArray(int size) {
+ return new NodeResetStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/SubnetBridgeGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/SubnetBridgeGetMessage.java
new file mode 100644
index 00000000..8c00d859
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/SubnetBridgeGetMessage.java
@@ -0,0 +1,57 @@
+/********************************************************************************************************
+ * @file AppKeyAddMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * Created by kee on 2021/1/14.
+ */
+
+public class SubnetBridgeGetMessage extends ConfigMessage {
+
+
+ public SubnetBridgeGetMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ public SubnetBridgeGetMessage(int destinationAddress, byte bridgeState) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.SUBNET_BRIDGE_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.SUBNET_BRIDGE_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return null;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/SubnetBridgeSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/SubnetBridgeSetMessage.java
new file mode 100644
index 00000000..357f589f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/SubnetBridgeSetMessage.java
@@ -0,0 +1,59 @@
+/********************************************************************************************************
+ * @file AppKeyAddMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * Created by kee on 2021/1/14.
+ */
+
+public class SubnetBridgeSetMessage extends ConfigMessage {
+
+ public byte subnetBridgeState;
+
+ public SubnetBridgeSetMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ public SubnetBridgeSetMessage(int destinationAddress, byte bridgeState) {
+ super(destinationAddress);
+ this.subnetBridgeState = bridgeState;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.SUBNET_BRIDGE_SET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.SUBNET_BRIDGE_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return new byte[]{subnetBridgeState};
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/SubnetBridgeStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/SubnetBridgeStatusMessage.java
new file mode 100644
index 00000000..f029dd16
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/config/SubnetBridgeStatusMessage.java
@@ -0,0 +1,80 @@
+/********************************************************************************************************
+ * @file NodeIdentityStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.config;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+/**
+ * Created by kee on 2019/9/10.
+ */
+
+public class SubnetBridgeStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * 1 byte
+ * 0x00 Subnet bridge functionality is disabled.
+ * 0x01 Subnet bridge functionality is enabled.
+ */
+ private byte subnetBridgeState;
+
+ public SubnetBridgeStatusMessage() {
+ }
+
+
+ protected SubnetBridgeStatusMessage(Parcel in) {
+ subnetBridgeState = in.readByte();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public SubnetBridgeStatusMessage createFromParcel(Parcel in) {
+ return new SubnetBridgeStatusMessage(in);
+ }
+
+ @Override
+ public SubnetBridgeStatusMessage[] newArray(int size) {
+ return new SubnetBridgeStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ subnetBridgeState = params[0];
+ }
+
+ public byte getSubnetBridgeState() {
+ return subnetBridgeState;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(subnetBridgeState);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshAddressStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshAddressStatusMessage.java
new file mode 100644
index 00000000..14f4873d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshAddressStatusMessage.java
@@ -0,0 +1,102 @@
+/********************************************************************************************************
+ * @file MeshAddressStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.fastpv;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class MeshAddressStatusMessage extends StatusMessage implements Parcelable {
+
+ private byte[] mac;
+
+ private int pid;
+
+
+ public MeshAddressStatusMessage() {
+ }
+
+
+ protected MeshAddressStatusMessage(Parcel in) {
+ mac = in.createByteArray();
+ pid = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public MeshAddressStatusMessage createFromParcel(Parcel in) {
+ return new MeshAddressStatusMessage(in);
+ }
+
+ @Override
+ public MeshAddressStatusMessage[] newArray(int size) {
+ return new MeshAddressStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ final int macLen = 6;
+ this.mac = new byte[6];
+ System.arraycopy(params, 0, this.mac, 0, macLen);
+ index += macLen;
+ this.pid = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByteArray(mac);
+ dest.writeInt(pid);
+ }
+
+ public byte[] getMac() {
+ return mac;
+ }
+
+ public int getPid() {
+ return pid;
+ }
+
+ @Override
+ public String toString() {
+ return "MeshAddressStatusMessage{" +
+ "mac=" + Arrays.toString(mac) +
+ ", pid=" + pid +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshConfirmRequestMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshConfirmRequestMessage.java
new file mode 100644
index 00000000..9691e9e3
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshConfirmRequestMessage.java
@@ -0,0 +1,56 @@
+/********************************************************************************************************
+ * @file MeshConfirmRequestMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.fastpv;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+
+public class MeshConfirmRequestMessage extends GenericMessage {
+
+ public static MeshConfirmRequestMessage getSimple(int destinationAddress, int appKeyIndex) {
+ MeshConfirmRequestMessage message = new MeshConfirmRequestMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(0);
+ message.setRetryCnt(1);
+ return message;
+ }
+
+ public MeshConfirmRequestMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.VD_MESH_PROV_CONFIRM.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.VD_MESH_PROV_CONFIRM_STS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return null;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshGetAddressMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshGetAddressMessage.java
new file mode 100644
index 00000000..d896539d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshGetAddressMessage.java
@@ -0,0 +1,66 @@
+/********************************************************************************************************
+ * @file MeshGetAddressMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.fastpv;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+
+import java.nio.ByteOrder;
+
+public class MeshGetAddressMessage extends GenericMessage {
+
+ private int pid;
+
+ public static MeshGetAddressMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax, int pid) {
+ MeshGetAddressMessage message = new MeshGetAddressMessage(destinationAddress, appKeyIndex);
+ message.setRetryCnt(0);
+ message.setResponseMax(rspMax);
+ message.pid = pid;
+ return message;
+ }
+
+ public MeshGetAddressMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.VD_MESH_ADDR_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.VD_MESH_ADDR_GET_STS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return MeshUtils.integer2Bytes(this.pid, 2, ByteOrder.LITTLE_ENDIAN);
+ }
+
+
+ public void setPid(int pid) {
+ this.pid = pid;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshProvisionCompleteMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshProvisionCompleteMessage.java
new file mode 100644
index 00000000..245bda3d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshProvisionCompleteMessage.java
@@ -0,0 +1,67 @@
+/********************************************************************************************************
+ * @file MeshProvisionCompleteMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.fastpv;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+
+import java.nio.ByteOrder;
+
+public class MeshProvisionCompleteMessage extends GenericMessage {
+
+ /**
+ * milliseconds
+ * 2 bytes
+ */
+ private int delay;
+
+ public static MeshProvisionCompleteMessage getSimple(int destinationAddress, int appKeyIndex, int delay) {
+ MeshProvisionCompleteMessage message = new MeshProvisionCompleteMessage(destinationAddress, appKeyIndex);
+ message.delay = delay;
+ return message;
+ }
+
+ public MeshProvisionCompleteMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.VD_MESH_PROV_COMPLETE.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return OPCODE_INVALID;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return MeshUtils.integer2Bytes(delay, 2, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ public void setDelay(int delay) {
+ this.delay = delay;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshSetAddressMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshSetAddressMessage.java
new file mode 100644
index 00000000..d7e0ff49
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshSetAddressMessage.java
@@ -0,0 +1,70 @@
+/********************************************************************************************************
+ * @file MeshSetAddressMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.fastpv;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class MeshSetAddressMessage extends GenericMessage {
+
+ private byte[] mac;
+ private int newMeshAddress;
+
+ public static MeshSetAddressMessage getSimple(int destinationAddress, int appKeyIndex, byte[] mac, int newMeshAddress) {
+ MeshSetAddressMessage message = new MeshSetAddressMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ message.mac = mac;
+ message.newMeshAddress = newMeshAddress;
+ return message;
+ }
+
+ public MeshSetAddressMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.VD_MESH_ADDR_SET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.VD_MESH_ADDR_SET_STS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).put(mac).putShort((short) newMeshAddress).array();
+ }
+
+ public void setMac(byte[] mac) {
+ this.mac = mac;
+ }
+
+ public void setNewMeshAddress(int newMeshAddress) {
+ this.newMeshAddress = newMeshAddress;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshSetNetInfoMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshSetNetInfoMessage.java
new file mode 100644
index 00000000..3f4be2b4
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/MeshSetNetInfoMessage.java
@@ -0,0 +1,61 @@
+/********************************************************************************************************
+ * @file MeshSetNetInfoMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.fastpv;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+
+public class MeshSetNetInfoMessage extends GenericMessage {
+
+ private byte[] netInfoData;
+
+ public static MeshSetNetInfoMessage getSimple(int destinationAddress, int appKeyIndex, byte[] netInfoData) {
+ MeshSetNetInfoMessage message = new MeshSetNetInfoMessage(destinationAddress, appKeyIndex);
+ message.netInfoData = netInfoData;
+ return message;
+ }
+
+ public MeshSetNetInfoMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.VD_MESH_PROV_DATA_SET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return OPCODE_INVALID;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return netInfoData;
+ }
+
+ public void setNetInfoData(byte[] netInfoData) {
+ this.netInfoData = netInfoData;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/ResetNetworkMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/ResetNetworkMessage.java
new file mode 100644
index 00000000..fd4ae2f8
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/fastpv/ResetNetworkMessage.java
@@ -0,0 +1,67 @@
+/********************************************************************************************************
+ * @file ResetNetworkMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.fastpv;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+
+import java.nio.ByteOrder;
+
+public class ResetNetworkMessage extends GenericMessage {
+
+ /**
+ * milliseconds
+ * 2 bytes
+ */
+ private int delay;
+
+ public static ResetNetworkMessage getSimple(int destinationAddress, int appKeyIndex, int delay) {
+ ResetNetworkMessage message = new ResetNetworkMessage(destinationAddress, appKeyIndex);
+ message.delay = delay;
+ return message;
+ }
+
+ public ResetNetworkMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.VD_MESH_RESET_NETWORK.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return OPCODE_INVALID;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return MeshUtils.integer2Bytes(delay, 2, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ public void setDelay(int delay) {
+ this.delay = delay;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/DistributorCapabilities.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/DistributorCapabilities.java
new file mode 100644
index 00000000..abbda181
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/DistributorCapabilities.java
@@ -0,0 +1,16 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+public interface DistributorCapabilities {
+
+
+
+ enum OOBRetrievalSupported {
+ SUPPORTED(1),
+ NotSupported(0);
+ final int value;
+
+ OOBRetrievalSupported(int value) {
+ this.value = value;
+ }
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDApplyMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDApplyMessage.java
new file mode 100644
index 00000000..352bb5a0
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDApplyMessage.java
@@ -0,0 +1,35 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+
+/**
+ * The Firmware Distribution Apply message is an acknowledged message
+ * sent from a Firmware Distribution Client to a Firmware Distribution Server to apply the firmware image on the Updating nodes.
+ * The response to a Firmware Distribution Apply message is a Firmware Distribution Status message.
+ */
+public class FDApplyMessage extends UpdatingMessage {
+
+
+ public FDApplyMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDApplyMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDApplyMessage message = new FDApplyMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_APPLY.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_STATUS.value;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDCancelMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDCancelMessage.java
new file mode 100644
index 00000000..8d621862
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDCancelMessage.java
@@ -0,0 +1,34 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+/**
+ * The Firmware Distribution Cancel message is an acknowledged message
+ * sent by a Firmware Distribution Client to stop the firmware image distribution from a Firmware Distribution Server.
+ * The response to a Firmware Distribution Cancel message is a Firmware Distribution Status message.
+ */
+public class FDCancelMessage extends UpdatingMessage {
+
+
+ public FDCancelMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDCancelMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDCancelMessage message = new FDCancelMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_CANCEL.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_STATUS.value;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDCapabilitiesGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDCapabilitiesGetMessage.java
new file mode 100644
index 00000000..d0e13388
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDCapabilitiesGetMessage.java
@@ -0,0 +1,29 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+public class FDCapabilitiesGetMessage extends UpdatingMessage {
+
+
+ public FDCapabilitiesGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDCapabilitiesGetMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDCapabilitiesGetMessage message = new FDCapabilitiesGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_CAPABILITIES_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_CAPABILITIES_STATUS.value;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDCapabilitiesStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDCapabilitiesStatusMessage.java
new file mode 100644
index 00000000..fa787728
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDCapabilitiesStatusMessage.java
@@ -0,0 +1,216 @@
+/********************************************************************************************************
+ * @file BlobTransferStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Firmware Distribution Capabilities Status
+ * response to a Firmware Distributor Capabilities Get message
+ *
+ * @see FDCapabilitiesGetMessage
+ */
+public class FDCapabilitiesStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * Max Distribution Receivers List Size
+ * Maximum number of entries in the Distribution Receivers List state
+ * 2 bytes
+ */
+ public int maxReceiversListSize;
+
+ /**
+ * Max Firmware Images List Size
+ * Maximum number of entries in the Firmware Images List state
+ * 2 bytes
+ */
+ private int maxImagesListSize;
+
+ /**
+ * Max Firmware Image Size
+ * Maximum size of one firmware image (in octets)
+ * 4 bytes
+ */
+ private int maxImageSize;
+
+ /**
+ * Max Upload Space
+ * Total space dedicated to storage of firmware images (in octets)
+ * 4 bytes
+ */
+ private int maxUploadSpace;
+
+ /**
+ * Remaining Upload Space
+ * Remaining available space in firmware image storage (in octets)
+ * 4 bytes
+ */
+ private int remainingUploadSpace;
+
+
+ /**
+ * Out-of-Band Retrieval Supported
+ * Value of the Out-of-Band Retrieval Supported state
+ * 1 byte
+ */
+ private int oobRetrievalSupported;
+
+ /**
+ * Supported URI Scheme Names
+ * Value of the Supported URI Scheme Names state
+ * Variable
+ */
+ private byte[] uriSchemeNames;
+
+
+ public FDCapabilitiesStatusMessage() {
+ }
+
+ protected FDCapabilitiesStatusMessage(Parcel in) {
+ maxReceiversListSize = in.readInt();
+ maxImagesListSize = in.readInt();
+ maxImageSize = in.readInt();
+ maxUploadSpace = in.readInt();
+ remainingUploadSpace = in.readInt();
+ oobRetrievalSupported = in.readInt();
+ uriSchemeNames = in.createByteArray();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FDCapabilitiesStatusMessage createFromParcel(Parcel in) {
+ return new FDCapabilitiesStatusMessage(in);
+ }
+
+ @Override
+ public FDCapabilitiesStatusMessage[] newArray(int size) {
+ return new FDCapabilitiesStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+
+ this.maxReceiversListSize = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ this.maxImagesListSize = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ maxImageSize = MeshUtils.bytes2Integer(params, index, 4, ByteOrder.LITTLE_ENDIAN);
+ index += 4;
+
+ maxUploadSpace = MeshUtils.bytes2Integer(params, index, 4, ByteOrder.LITTLE_ENDIAN);
+ index += 4;
+
+ remainingUploadSpace = MeshUtils.bytes2Integer(params, index, 4, ByteOrder.LITTLE_ENDIAN);
+ index += 4;
+
+ oobRetrievalSupported = params[index++] & 0xFF;
+
+ if (oobRetrievalSupported == DistributorCapabilities.OOBRetrievalSupported.SUPPORTED.value) {
+ uriSchemeNames = new byte[params.length - index];
+ System.arraycopy(params, index, uriSchemeNames, 0, uriSchemeNames.length);
+ } else {
+ uriSchemeNames = null;
+ }
+ }
+
+ public int getMaxReceiversListSize() {
+ return maxReceiversListSize;
+ }
+
+ public void setMaxReceiversListSize(int maxReceiversListSize) {
+ this.maxReceiversListSize = maxReceiversListSize;
+ }
+
+ public int getMaxImagesListSize() {
+ return maxImagesListSize;
+ }
+
+ public void setMaxImagesListSize(int maxImagesListSize) {
+ this.maxImagesListSize = maxImagesListSize;
+ }
+
+ public int getMaxImageSize() {
+ return maxImageSize;
+ }
+
+ public void setMaxImageSize(int maxImageSize) {
+ this.maxImageSize = maxImageSize;
+ }
+
+ public int getMaxUploadSpace() {
+ return maxUploadSpace;
+ }
+
+ public void setMaxUploadSpace(int maxUploadSpace) {
+ this.maxUploadSpace = maxUploadSpace;
+ }
+
+ public int getRemainingUploadSpace() {
+ return remainingUploadSpace;
+ }
+
+ public void setRemainingUploadSpace(int remainingUploadSpace) {
+ this.remainingUploadSpace = remainingUploadSpace;
+ }
+
+ public int getOobRetrievalSupported() {
+ return oobRetrievalSupported;
+ }
+
+ public void setOobRetrievalSupported(int oobRetrievalSupported) {
+ this.oobRetrievalSupported = oobRetrievalSupported;
+ }
+
+ public byte[] getUriSchemeNames() {
+ return uriSchemeNames;
+ }
+
+ public void setUriSchemeNames(byte[] uriSchemeNames) {
+ this.uriSchemeNames = uriSchemeNames;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(maxReceiversListSize);
+ dest.writeInt(maxImagesListSize);
+ dest.writeInt(maxImageSize);
+ dest.writeInt(maxUploadSpace);
+ dest.writeInt(remainingUploadSpace);
+ dest.writeInt(oobRetrievalSupported);
+ dest.writeByteArray(uriSchemeNames);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareDeleteAllMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareDeleteAllMessage.java
new file mode 100644
index 00000000..1f3f29d1
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareDeleteAllMessage.java
@@ -0,0 +1,41 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+/**
+ * The Firmware Distribution Firmware Delete All message is an acknowledged message sent by a Firmware Distribution Client to delete all firmware images stored on a Firmware Distribution Server.
+ * The response to a Firmware Distribution Firmware Delete All message is a Firmware Distribution Firmware Status message.
+ */
+public class FDFirmwareDeleteAllMessage extends UpdatingMessage {
+
+ /**
+ * Firmware ID
+ * The Firmware ID identifying the firmware image to check
+ * Variable length
+ */
+ public int firmwareID;
+
+
+ public FDFirmwareDeleteAllMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDFirmwareDeleteAllMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDFirmwareDeleteAllMessage message = new FDFirmwareDeleteAllMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_FIRMWARE_DELETE.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_UPLOAD_STATUS.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareDeleteMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareDeleteMessage.java
new file mode 100644
index 00000000..49365835
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareDeleteMessage.java
@@ -0,0 +1,41 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+/**
+ * The Firmware Distribution Firmware Delete message is an acknowledged message sent by a Firmware Distribution Client to delete a stored firmware image on a Firmware Distribution Server.
+ * The response to a Firmware Distribution Firmware Delete message is a Firmware Distribution Firmware Status message.
+ */
+public class FDFirmwareDeleteMessage extends UpdatingMessage {
+
+ /**
+ * Firmware ID
+ * The Firmware ID identifying the firmware image to check
+ * Variable length
+ */
+ public int firmwareID;
+
+
+ public FDFirmwareDeleteMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDFirmwareDeleteMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDFirmwareDeleteMessage message = new FDFirmwareDeleteMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_FIRMWARE_DELETE.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_UPLOAD_STATUS.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareGetByIndexMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareGetByIndexMessage.java
new file mode 100644
index 00000000..d52cd67d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareGetByIndexMessage.java
@@ -0,0 +1,41 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+/**
+ * The Firmware Distribution Upload Start message is an acknowledged message sent by a Firmware Distribution Client to start a firmware image upload to a Firmware Distribution Server.
+ * The response to a Firmware Distribution Upload Start message is a Firmware Distribution Upload Status message.
+ */
+public class FDFirmwareGetByIndexMessage extends UpdatingMessage {
+
+ /**
+ * Distribution Firmware Image Index
+ * Index of the entry in the Firmware Images List state
+ * 2 bytes
+ */
+ public int distImageIndex;
+
+
+ public FDFirmwareGetByIndexMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDFirmwareGetByIndexMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDFirmwareGetByIndexMessage message = new FDFirmwareGetByIndexMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_FIRMWARE_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_UPLOAD_STATUS.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareGetMessage.java
new file mode 100644
index 00000000..1280c233
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareGetMessage.java
@@ -0,0 +1,41 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+/**
+ * The Firmware Distribution Upload Start message is an acknowledged message sent by a Firmware Distribution Client to start a firmware image upload to a Firmware Distribution Server.
+ * The response to a Firmware Distribution Upload Start message is a Firmware Distribution Upload Status message.
+ */
+public class FDFirmwareGetMessage extends UpdatingMessage {
+
+ /**
+ * Firmware ID
+ * The Firmware ID identifying the firmware image to check
+ * Variable length
+ */
+ public int firmwareID;
+
+
+ public FDFirmwareGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDFirmwareGetMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDFirmwareGetMessage message = new FDFirmwareGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_FIRMWARE_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_UPLOAD_STATUS.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareStatusMessage.java
new file mode 100644
index 00000000..af95e326
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDFirmwareStatusMessage.java
@@ -0,0 +1,110 @@
+/********************************************************************************************************
+ * @file BlobTransferStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+public class FDFirmwareStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * Status Code for the requesting message
+ * 1 byte
+ */
+ public int status;
+
+ /**
+ * Entry Count
+ * The number of firmware images stored on the Firmware Distribution Server
+ * 2 bytes
+ */
+ public int entryCount;
+
+ /**
+ * Distribution Firmware Image Index
+ * Index of the firmware image in the Firmware Images List state
+ * 2 bytes
+ */
+ public int distImageIndex;
+
+ /**
+ * Firmware ID
+ * Identifies associated firmware image
+ * Variable length
+ */
+ public byte[] firmwareID;
+
+ public FDFirmwareStatusMessage() {
+ }
+
+
+ protected FDFirmwareStatusMessage(Parcel in) {
+ status = in.readInt();
+ entryCount = in.readInt();
+ distImageIndex = in.readInt();
+ firmwareID = in.createByteArray();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FDFirmwareStatusMessage createFromParcel(Parcel in) {
+ return new FDFirmwareStatusMessage(in);
+ }
+
+ @Override
+ public FDFirmwareStatusMessage[] newArray(int size) {
+ return new FDFirmwareStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.status = params[index++] & 0xFF;
+ this.entryCount = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ this.distImageIndex = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ if (params.length == 5) return;
+ this.firmwareID = new byte[params.length - index];
+ System.arraycopy(params, index, this.firmwareID, 0, this.firmwareID.length);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(entryCount);
+ dest.writeInt(distImageIndex);
+ dest.writeByteArray(firmwareID);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDGetMessage.java
new file mode 100644
index 00000000..cdf09aea
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDGetMessage.java
@@ -0,0 +1,30 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+public class FDGetMessage extends UpdatingMessage {
+
+
+ public FDGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDGetMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDGetMessage message = new FDGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_STATUS.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversAddMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversAddMessage.java
new file mode 100644
index 00000000..6769fecd
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversAddMessage.java
@@ -0,0 +1,52 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+import java.util.List;
+
+public class FDReceiversAddMessage extends UpdatingMessage {
+
+ /**
+ * Receiver Entry: every entry is 3 bytes
+ */
+ public List entries;
+
+ public FDReceiversAddMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDReceiversAddMessage getSimple(int destinationAddress, int appKeyIndex, List entries) {
+ FDReceiversAddMessage message = new FDReceiversAddMessage(destinationAddress, appKeyIndex);
+ message.entries = entries;
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_RECEIVERS_ADD.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_RECEIVERS_STATUS.value;
+ }
+
+ static public class ReceiverEntry {
+ /**
+ * The unicast address of the Updating node
+ * 2 bytes
+ */
+ public int address;
+
+ /**
+ * Update Firmware Image Index
+ * The index of the firmware image in the Firmware Information List state to be updated
+ * 1 byte
+ */
+ public int imageIndex;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversDeleteAllMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversDeleteAllMessage.java
new file mode 100644
index 00000000..b495a635
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversDeleteAllMessage.java
@@ -0,0 +1,29 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+public class FDReceiversDeleteAllMessage extends UpdatingMessage {
+
+
+ public FDReceiversDeleteAllMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDReceiversDeleteAllMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDReceiversDeleteAllMessage message = new FDReceiversDeleteAllMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_RECEIVERS_DELETE_ALL.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_RECEIVERS_STATUS.value;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversGetMessage.java
new file mode 100644
index 00000000..87186491
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversGetMessage.java
@@ -0,0 +1,45 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+public class FDReceiversGetMessage extends UpdatingMessage {
+
+ /**
+ * first index
+ * Index of the first requested entry from the Distribution Receivers List state
+ * 2 bytes
+ */
+ public int firstIndex;
+
+ /**
+ * Entries Limit
+ * Maximum number of entries that the server includes in a Firmware Distribution Receivers List message
+ * 2 bytes
+ */
+ public int entriesLimit;
+
+ public FDReceiversGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDReceiversGetMessage getSimple(int destinationAddress, int appKeyIndex, int firstIndex, int entriesLimit) {
+ FDReceiversGetMessage message = new FDReceiversGetMessage(destinationAddress, appKeyIndex);
+ message.firstIndex = firstIndex;
+ message.entriesLimit = entriesLimit;
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_RECEIVERS_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_RECEIVERS_LIST.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversListMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversListMessage.java
new file mode 100644
index 00000000..b5f1db30
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversListMessage.java
@@ -0,0 +1,137 @@
+/********************************************************************************************************
+ * @file BlobTransferStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.util.List;
+
+/**
+ * response to a Firmware Distribution Receivers Get message
+ *
+ * @see FDReceiversGetMessage
+ */
+public class FDReceiversListMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * Receivers List Count
+ * The number of entries in the Distribution Receivers List state
+ * 2 bytes
+ */
+ private int receiversListCount;
+
+
+ /**
+ * First Index
+ * 2 bytes
+ */
+ private int firstIndex;
+
+ /**
+ * List of entries
+ * Optional
+ */
+ private List List;
+
+ public FDReceiversListMessage() {
+ }
+
+ protected FDReceiversListMessage(Parcel in) {
+ receiversListCount = in.readInt();
+ firstIndex = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FDReceiversListMessage createFromParcel(Parcel in) {
+ return new FDReceiversListMessage(in);
+ }
+
+ @Override
+ public FDReceiversListMessage[] newArray(int size) {
+ return new FDReceiversListMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(receiversListCount);
+ dest.writeInt(firstIndex);
+ }
+
+ static public class DistributionReceiver {
+ /**
+ * Address
+ * 15 least significant bits of the unicast address of the Updating node
+ * 15 bits
+ */
+ public int address;
+ /**
+ * Retrieved Update Phase
+ * Retrieved Update Phase state of the Updating node
+ * 4 bits
+ */
+ public byte retrievedUpdatePhase;
+ /**
+ * Update Status
+ * Status of the last operation with the Firmware Update Server
+ * 3 bits
+ */
+ public byte updateStatus;
+
+ /**
+ * Transfer Status
+ * Status of the last operation with the BLOB Transfer Server
+ * 4 bits
+ */
+ public byte transferStatus;
+
+
+ /**
+ * Transfer Progress
+ * Progress of the BLOB transfer in 2 percent increments
+ * 6 bits
+ */
+ public byte transferProgress;
+
+ /**
+ * Update Firmware Image Index
+ * Index of the firmware image on the Firmware Information List state that is being updated.
+ * 8 bits
+ */
+ public byte imageIndex;
+
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversStatusMessage.java
new file mode 100644
index 00000000..f05c44fc
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDReceiversStatusMessage.java
@@ -0,0 +1,101 @@
+/********************************************************************************************************
+ * @file BlobTransferStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+public class FDReceiversStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * Status Code for the requesting message
+ * 1 byte
+ */
+ private int status;
+
+ /**
+ * Receivers List Count
+ * The number of entries in the Distribution Receivers List state
+ * 2 bytes
+ */
+ private int receiversListCount;
+
+ public FDReceiversStatusMessage() {
+ }
+
+
+ protected FDReceiversStatusMessage(Parcel in) {
+ status = in.readInt();
+ receiversListCount = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FDReceiversStatusMessage createFromParcel(Parcel in) {
+ return new FDReceiversStatusMessage(in);
+ }
+
+ @Override
+ public FDReceiversStatusMessage[] newArray(int size) {
+ return new FDReceiversStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.status = params[index++] & 0xFF;
+ this.receiversListCount = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public int getReceiversListCount() {
+ return receiversListCount;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(receiversListCount);
+ }
+
+ @Override
+ public String toString() {
+ return "FirmwareDistributionReceiversStatus{" +
+ "status=" + status +
+ ", receiversListCount=" + receiversListCount +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDStartMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDStartMessage.java
new file mode 100644
index 00000000..cfcc2606
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDStartMessage.java
@@ -0,0 +1,90 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+/**
+ * The Firmware Distribution Start message is an acknowledged message sent by a Firmware Distribution Client to start the firmware image distribution to the Updating nodes in the Distribution Receivers List.
+ * The response to a Firmware Distribution Start message is a Firmware Distribution Status message.
+ * @see
+ */
+public class FDStartMessage extends UpdatingMessage {
+
+
+ /**
+ * Distribution AppKey Index
+ * Index of the application key used in a firmware image distribution
+ * 16 bits
+ */
+ public int distributionAppKeyIndex;
+
+ /**
+ * Distribution TTL
+ * Time To Live value used in a firmware image distribution
+ * 8 bits
+ */
+ public int distributionTTL;
+
+ /**
+ * Distribution Timeout Base
+ * Used to compute the timeout of the firmware image distribution
+ * 16 bits
+ */
+ public int distributionTimeoutBase;
+
+ /**
+ * Distribution Transfer Mode
+ * Mode of the transfer
+ * 2 bits
+ */
+ public int distributionTransferMode;
+
+ /**
+ * Update Policy
+ * Firmware update policy
+ * 1 bit
+ */
+ public int updatePolicy;
+
+ /**
+ * Reserved for Future Use
+ * 5 bits
+ */
+ public int RFU = 0;
+
+ /**
+ * Distribution Firmware Image Index
+ * Index of the firmware image in the Firmware Images List state to use during firmware image distribution
+ * 16 bits
+ */
+ public int distributionImageIndex;
+
+ /**
+ * Distribution Multicast Address
+ * Multicast address used in a firmware image distribution
+ * 16 or 128 bits
+ */
+ public int distributionMulticastAddress;
+
+ public FDStartMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDStartMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDStartMessage message = new FDStartMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_START.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_STATUS.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDStatusMessage.java
new file mode 100644
index 00000000..43526b2d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDStatusMessage.java
@@ -0,0 +1,188 @@
+/********************************************************************************************************
+ * @file BlobTransferStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * The Firmware Distribution Status message is an unacknowledged message sent by a Firmware Distribution Server to report the status of a firmware image distribution.
+ * A Firmware Distribution Status message is sent as a response to:
+ * Firmware Distribution Get message,
+ * Firmware Distribution Start message, Firmware Distribution Cancel message,
+ * Firmware Distribution Apply message.
+ */
+public class FDStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * Status
+ * Status Code for the requesting message
+ * 8 bits
+ */
+ public int status;
+
+ /**
+ * Distribution Phase
+ * Phase of the firmware image distribution
+ * 8 bits
+ */
+ public int distPhase;
+
+ /**
+ * Distribution Multicast Address
+ * Multicast address used in firmware image distribution
+ * (Optional)
+ * 16 bits
+ */
+ public int distMulticastAddress;
+
+ /**
+ * Distribution AppKey Index
+ * Index of an application key used in a firmware image distribution
+ * 16 bits
+ */
+ public int distAppKeyIndex;
+
+ /**
+ * Distribution TTL
+ * Time To Live value used in a firmware image distribution
+ * 8 bits
+ */
+ public int distTTL;
+
+ /**
+ * Distribution Timeout Base
+ * Used to compute the timeout of the firmware image distribution
+ * 16 bits
+ */
+ public int distTimeoutBase;
+
+ /**
+ * Distribution Transfer Mode
+ * Mode of the transfer
+ * 2 bits
+ */
+ public int distTransferMode;
+
+ /**
+ * Update Policy
+ * Firmware update policy
+ * 1 bit
+ */
+ public int updatePolicy;
+
+ /**
+ * RFU
+ * Reserved for Future Use
+ * 5 bits
+ */
+ public int RFU;
+
+ /**
+ * Distribution Firmware Image Index
+ * The index of the firmware image in the Firmware Images List state used during firmware image distribution (C.1)
+ * 16 bits
+ */
+ public int distImageIndex;
+
+ public FDStatusMessage() {
+ }
+
+
+ protected FDStatusMessage(Parcel in) {
+ status = in.readInt();
+ distPhase = in.readInt();
+ distMulticastAddress = in.readInt();
+ distAppKeyIndex = in.readInt();
+ distTTL = in.readInt();
+ distTimeoutBase = in.readInt();
+ distTransferMode = in.readInt();
+ updatePolicy = in.readInt();
+ RFU = in.readInt();
+ distImageIndex = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FDStatusMessage createFromParcel(Parcel in) {
+ return new FDStatusMessage(in);
+ }
+
+ @Override
+ public FDStatusMessage[] newArray(int size) {
+ return new FDStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.status = params[index++] & 0xFF;
+ this.distPhase = params[index++] & 0xFF;
+ if (params.length == 2) {
+ // distMulticastAddress is not present
+ return;
+ }
+
+ // distMulticastAddress is present
+ this.distMulticastAddress = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.distAppKeyIndex = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ this.distTTL = params[index++] & 0xFF;
+ this.distTimeoutBase = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ this.distTransferMode = params[index] & 0b11;
+
+ this.updatePolicy = (params[index] >> 2) & 0b01;
+
+ this.RFU = (params[index] >> 3) & 0x1F;
+
+ this.distImageIndex = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(distPhase);
+ dest.writeInt(distMulticastAddress);
+ dest.writeInt(distAppKeyIndex);
+ dest.writeInt(distTTL);
+ dest.writeInt(distTimeoutBase);
+ dest.writeInt(distTransferMode);
+ dest.writeInt(updatePolicy);
+ dest.writeInt(RFU);
+ dest.writeInt(distImageIndex);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadCancelMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadCancelMessage.java
new file mode 100644
index 00000000..a176ba0a
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadCancelMessage.java
@@ -0,0 +1,34 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+/**
+ * The Firmware Distribution Upload Cancel message is an acknowledged message sent by a Firmware Distribution Client to stop a firmware image upload to a Firmware Distribution Server.
+ * The response to a Firmware Distribution Upload Cancel message is a Firmware Distribution Upload Status message.
+ */
+public class FDUploadCancelMessage extends UpdatingMessage {
+
+
+ public FDUploadCancelMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDUploadCancelMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDUploadCancelMessage message = new FDUploadCancelMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_UPLOAD_CANCEL.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_UPLOAD_STATUS.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadGetMessage.java
new file mode 100644
index 00000000..8ffd3793
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadGetMessage.java
@@ -0,0 +1,34 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+/**
+ * The Firmware Distribution Upload Get message is an acknowledged message sent by a Firmware Distribution Client to check the status of a firmware image upload to a Firmware Distribution Server.
+ * The response to a Firmware Distribution Upload Get message is a Firmware Distribution Upload Status message.
+ */
+public class FDUploadGetMessage extends UpdatingMessage {
+
+
+ public FDUploadGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDUploadGetMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDUploadGetMessage message = new FDUploadGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_UPLOAD_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_UPLOAD_STATUS.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadOOBStartMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadOOBStartMessage.java
new file mode 100644
index 00000000..88f4955d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadOOBStartMessage.java
@@ -0,0 +1,54 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+/**
+ * The Firmware Distribution Upload OOB Start message is an acknowledged message
+ * sent by a Firmware Distribution Client to start a firmware image upload to a Firmware Distribution Server using an out-of-band mechanism.
+ */
+public class FDUploadOOBStartMessage extends UpdatingMessage {
+
+ /**
+ * Upload URI Length
+ * Length of the Upload URI field
+ * 1 byte
+ */
+ public int uploadURILength;
+
+ /**
+ * Upload URI
+ * URI for the firmware image source
+ * 1 to 255 bytes
+ */
+ public int uploadURI;
+
+ /**
+ * Upload Firmware ID
+ * The Firmware ID value used to generate the URI query string
+ * Variable length
+ */
+ public int uploadFirmwareID;
+
+ public FDUploadOOBStartMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDUploadOOBStartMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDUploadOOBStartMessage message = new FDUploadOOBStartMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_UPLOAD_START.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_UPLOAD_STATUS.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadStartMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadStartMessage.java
new file mode 100644
index 00000000..6bd5ec8c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadStartMessage.java
@@ -0,0 +1,83 @@
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+/**
+ * The Firmware Distribution Upload Start message is an acknowledged message sent by a Firmware Distribution Client to start a firmware image upload to a Firmware Distribution Server.
+ * The response to a Firmware Distribution Upload Start message is a Firmware Distribution Upload Status message.
+ */
+public class FDUploadStartMessage extends UpdatingMessage {
+
+ /**
+ * Upload TTL
+ * Time To Live value used in a firmware image upload
+ * 1 byte
+ */
+ public int uploadTTL;
+
+ /**
+ * Upload Timeout Base
+ * Used to compute the timeout of the firmware image upload
+ * 2 bytes
+ */
+ public int uploadTimeoutBase;
+
+ /**
+ * Upload BLOB ID
+ * BLOB identifier for the firmware image
+ * 8 bytes
+ */
+ public int uploadBLOBID;
+
+ /**
+ * Upload Firmware Size
+ * Firmware image size (in octets)
+ * 4 bytes
+ */
+ public int uploadFirmwareSize;
+
+ /**
+ * Upload Firmware Metadata Length
+ * Size of the Upload Firmware Metadata field
+ * 1 byte
+ */
+ public int uploadFirmwareMetadataLength;
+
+ /**
+ * Upload Firmware Metadata
+ * Vendor-specific firmware metadata
+ * 1 to 255 bytes
+ */
+ public int uploadFirmwareMetadata;
+
+ /**
+ * Upload Firmware ID
+ * The Firmware ID identifying the firmware image being uploaded
+ * Variable
+ */
+ public int uploadFirmwareID;
+
+
+ public FDUploadStartMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ public static FDUploadStartMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FDUploadStartMessage message = new FDUploadStartMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FD_UPLOAD_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FD_UPLOAD_STATUS.value;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadStatusMessage.java
new file mode 100644
index 00000000..bbd60846
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwaredistribution/FDUploadStatusMessage.java
@@ -0,0 +1,106 @@
+/********************************************************************************************************
+ * @file BlobTransferStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwaredistribution;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+public class FDUploadStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * Status Code for the requesting message
+ * 1 byte
+ */
+ private int status;
+
+ /**
+ * Upload Phase
+ * Phase of the firmware image upload to a Firmware Distribution Server
+ * 1 byte
+ */
+ public int uploadPhase;
+
+ /**
+ * Upload Progress
+ * A percentage indicating the progress of the firmware image upload (Optional)
+ * 0x00 -> 0x64
+ * 0 -> 100
+ * 1 byte
+ */
+ public int uploadProgress;
+
+ /**
+ * Upload Firmware ID
+ * The Firmware ID identifying the firmware image being uploaded
+ * Variable
+ */
+ public byte[] uploadFirmwareID;
+
+ public FDUploadStatusMessage() {
+ }
+
+
+ protected FDUploadStatusMessage(Parcel in) {
+ status = in.readInt();
+ uploadPhase = in.readInt();
+ uploadProgress = in.readInt();
+ uploadFirmwareID = in.createByteArray();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FDUploadStatusMessage createFromParcel(Parcel in) {
+ return new FDUploadStatusMessage(in);
+ }
+
+ @Override
+ public FDUploadStatusMessage[] newArray(int size) {
+ return new FDUploadStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.status = params[index++] & 0xFF;
+ this.uploadPhase = params[index++] & 0xFF;
+ if (params.length == 2) return;
+ this.uploadProgress = params[index++] & 0xFF;
+ this.uploadFirmwareID = new byte[params.length - index];
+ System.arraycopy(params, index, this.uploadFirmwareID, 0, this.uploadFirmwareID.length);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(uploadPhase);
+ dest.writeInt(uploadProgress);
+ dest.writeByteArray(uploadFirmwareID);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/AdditionalInformation.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/AdditionalInformation.java
new file mode 100644
index 00000000..6687b4bc
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/AdditionalInformation.java
@@ -0,0 +1,52 @@
+/********************************************************************************************************
+ * @file AdditionalInformation.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+public enum AdditionalInformation {
+
+
+ No_changes(0x00, "No changes to node composition data"),
+
+ CHANGES_1(0x01, "Node composition data changed. The node does not support remote provisioning."),
+
+ CHANGES_2(0x02, "Node composition data changed, and remote provisioning is supported. " +
+ "The node supports remote provisioning and composition data page 0x80. Page 0x80 contains different composition data than page 0x0."),
+
+ CHANGES_3(0x03, "Node unprovisioned. The node is unprovisioned after successful application of a verified firmware image."),
+
+ UNKNOWN_ERROR(0xFF, "unknown error");
+
+ public final int code;
+ public final String desc;
+
+ AdditionalInformation(int code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static AdditionalInformation valueOf(int code) {
+ for (AdditionalInformation status : values()) {
+ if (status.code == code) return status;
+ }
+ return UNKNOWN_ERROR;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/DistributionStatus.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/DistributionStatus.java
new file mode 100644
index 00000000..6b3297b1
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/DistributionStatus.java
@@ -0,0 +1,66 @@
+/********************************************************************************************************
+ * @file DistributionStatus.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+public enum DistributionStatus {
+
+
+ SUCCESS(0x00, "The message was processed successfully"),
+
+ OUT_OF_RESOURCES(0x01, "Insufficient resources on the node"),
+
+ INVALID_APPKEY_INDEX(0x02, "The AppKey identified by the AppKey Index is not known to the node"),
+
+ NODES_LIST_EMPTY(0x03, "There are no Updating nodes in the Nodes List state"),
+
+
+ INVALID_PHASE(0x04, "The operation cannot be performed while the server is in the current phase"),
+
+ FIRMWARE_NOT_FOUND(0x05, "The requested firmware image is not stored on the Distributor"),
+
+ BUSY_WITH_TRANSFER(0x06, "Another upload is in progress"),
+
+ URI_NOT_SUPPORTED(0x07, "The URI scheme name indicated by the Update URI is not supported"),
+
+ URI_MALFORMED(0x08, "The format of the Update URI is invalid"),
+
+ DISTRIBUTOR_BUSY(0x09, "Another firmware image distribution is in progress"),
+
+ INTERNAL_ERROR(0x0A, "An internal error occurred on the node"),
+
+ UNKNOWN_ERROR(0xFF, "unknown error");
+
+ public final int code;
+ public final String desc;
+
+ DistributionStatus(int code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static DistributionStatus valueOf(int code) {
+ for (DistributionStatus status : values()) {
+ if (status.code == code) return status;
+ }
+ return UNKNOWN_ERROR;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareMetadataCheckMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareMetadataCheckMessage.java
new file mode 100644
index 00000000..376a6b83
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareMetadataCheckMessage.java
@@ -0,0 +1,92 @@
+/********************************************************************************************************
+ * @file FirmwareMetadataCheckMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * check whether the node can accept a firmware update.
+ */
+public class FirmwareMetadataCheckMessage extends UpdatingMessage {
+
+ /**
+ * Index of the firmware image in the Firmware Information List state to check
+ * 1 byte
+ */
+ private int updateFirmwareImageIndex;
+
+ /**
+ * If the value of the Incoming Firmware Metadata Length field is greater than 0,
+ * the Incoming Firmware Metadata field shall be present.
+ */
+ private byte[] incomingFirmwareMetadata;
+
+ public static FirmwareMetadataCheckMessage getSimple(int destinationAddress, int appKeyIndex,
+ int index, byte[] incomingFirmwareMetadata) {
+ FirmwareMetadataCheckMessage message = new FirmwareMetadataCheckMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ message.updateFirmwareImageIndex = index;
+ message.incomingFirmwareMetadata = incomingFirmwareMetadata;
+
+ return message;
+ }
+
+ public FirmwareMetadataCheckMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FIRMWARE_UPDATE_FIRMWARE_METADATA_CHECK.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FIRMWARE_UPDATE_FIRMWARE_METADATA_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+
+ int metadataLen = (incomingFirmwareMetadata == null || incomingFirmwareMetadata.length <= 0) ? 0 : incomingFirmwareMetadata.length;
+
+ final int len = 1 + metadataLen;
+ ByteBuffer buffer = ByteBuffer.allocate(len).order(ByteOrder.LITTLE_ENDIAN)
+ .put((byte) updateFirmwareImageIndex);
+
+ if (metadataLen != 0) {
+ buffer.put(incomingFirmwareMetadata);
+ }
+ return buffer.array();
+ }
+
+ public void setUpdateFirmwareImageIndex(int updateFirmwareImageIndex) {
+ this.updateFirmwareImageIndex = updateFirmwareImageIndex;
+ }
+
+ public void setIncomingFirmwareMetadata(byte[] incomingFirmwareMetadata) {
+ this.incomingFirmwareMetadata = incomingFirmwareMetadata;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareMetadataStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareMetadataStatusMessage.java
new file mode 100644
index 00000000..d676eade
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareMetadataStatusMessage.java
@@ -0,0 +1,104 @@
+/********************************************************************************************************
+ * @file FirmwareMetadataStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+public class FirmwareMetadataStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * @see UpdateStatus
+ * 3 bits
+ */
+ private int status;
+
+ /**
+ * 5 bits
+ *
+ * @see AdditionalInformation
+ */
+ private int additionalInformation;
+
+ /**
+ * Index of the firmware image in the Firmware Information List state that was checked
+ * 8 bits
+ */
+ private int updateFirmwareImageIndex;
+
+
+ public FirmwareMetadataStatusMessage() {
+ }
+
+
+ protected FirmwareMetadataStatusMessage(Parcel in) {
+ status = in.readInt();
+ additionalInformation = in.readInt();
+ updateFirmwareImageIndex = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FirmwareMetadataStatusMessage createFromParcel(Parcel in) {
+ return new FirmwareMetadataStatusMessage(in);
+ }
+
+ @Override
+ public FirmwareMetadataStatusMessage[] newArray(int size) {
+ return new FirmwareMetadataStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.status = params[index] & 0x07;
+ this.additionalInformation = (params[index++] >> 3) & 0x1F;
+ this.updateFirmwareImageIndex = params[index] & 0xFF;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(additionalInformation);
+ dest.writeInt(updateFirmwareImageIndex);
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public int getAdditionalInformation() {
+ return additionalInformation;
+ }
+
+ public int getUpdateFirmwareImageIndex() {
+ return updateFirmwareImageIndex;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateApplyMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateApplyMessage.java
new file mode 100644
index 00000000..431ce711
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateApplyMessage.java
@@ -0,0 +1,52 @@
+/********************************************************************************************************
+ * @file FirmwareUpdateApplyMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+
+public class FirmwareUpdateApplyMessage extends UpdatingMessage {
+
+
+ public static FirmwareUpdateApplyMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FirmwareUpdateApplyMessage message = new FirmwareUpdateApplyMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ public FirmwareUpdateApplyMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FIRMWARE_UPDATE_APPLY.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FIRMWARE_UPDATE_STATUS.value;
+ }
+
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateCancelMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateCancelMessage.java
new file mode 100644
index 00000000..d99f560d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateCancelMessage.java
@@ -0,0 +1,52 @@
+/********************************************************************************************************
+ * @file FirmwareUpdateCancelMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+
+public class FirmwareUpdateCancelMessage extends UpdatingMessage {
+
+
+ public static FirmwareUpdateCancelMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FirmwareUpdateCancelMessage message = new FirmwareUpdateCancelMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ public FirmwareUpdateCancelMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FIRMWARE_UPDATE_CANCEL.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FIRMWARE_UPDATE_STATUS.value;
+ }
+
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateGetMessage.java
new file mode 100644
index 00000000..89434f68
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateGetMessage.java
@@ -0,0 +1,52 @@
+/********************************************************************************************************
+ * @file FirmwareUpdateGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+
+public class FirmwareUpdateGetMessage extends UpdatingMessage {
+
+
+ public static FirmwareUpdateGetMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FirmwareUpdateGetMessage message = new FirmwareUpdateGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ public FirmwareUpdateGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FIRMWARE_UPDATE_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FIRMWARE_UPDATE_STATUS.value;
+ }
+
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateInfoGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateInfoGetMessage.java
new file mode 100644
index 00000000..bd88256c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateInfoGetMessage.java
@@ -0,0 +1,75 @@
+/********************************************************************************************************
+ * @file FirmwareUpdateInfoGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+public class FirmwareUpdateInfoGetMessage extends UpdatingMessage {
+
+ /**
+ * Index of the first requested entry from the Firmware Information List state
+ * 1 byte
+ */
+ private byte firstIndex;
+
+ /**
+ * Maximum number of entries that the server includes in a Firmware Update Information Status message
+ * 1 byte
+ */
+ private byte entriesLimit;
+
+
+ public static FirmwareUpdateInfoGetMessage getSimple(int destinationAddress, int appKeyIndex) {
+ FirmwareUpdateInfoGetMessage message = new FirmwareUpdateInfoGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ message.firstIndex = 0;
+ message.entriesLimit = 1;
+ return message;
+ }
+
+ public FirmwareUpdateInfoGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FIRMWARE_UPDATE_INFORMATION_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FIRMWARE_UPDATE_INFORMATION_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return new byte[]{firstIndex, entriesLimit};
+ }
+
+ public void setFirstIndex(byte firstIndex) {
+ this.firstIndex = firstIndex;
+ }
+
+ public void setEntriesLimit(byte entriesLimit) {
+ this.entriesLimit = entriesLimit;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateInfoStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateInfoStatusMessage.java
new file mode 100644
index 00000000..7122a502
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateInfoStatusMessage.java
@@ -0,0 +1,216 @@
+/********************************************************************************************************
+ * @file FirmwareUpdateInfoStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FirmwareUpdateInfoStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * The number of entries in the Firmware Information List state of the server
+ * 1 byte
+ */
+ private int listCount;
+
+ /**
+ * Index of the first requested entry from the Firmware Information List state
+ * 1 byte
+ */
+ private int firstIndex;
+
+ /**
+ * List of entries
+ */
+ private List firmwareInformationList;
+
+ public FirmwareUpdateInfoStatusMessage() {
+ }
+
+
+ protected FirmwareUpdateInfoStatusMessage(Parcel in) {
+ listCount = in.readInt();
+ firstIndex = in.readInt();
+ firmwareInformationList = in.createTypedArrayList(FirmwareInformationEntry.CREATOR);
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FirmwareUpdateInfoStatusMessage createFromParcel(Parcel in) {
+ return new FirmwareUpdateInfoStatusMessage(in);
+ }
+
+ @Override
+ public FirmwareUpdateInfoStatusMessage[] newArray(int size) {
+ return new FirmwareUpdateInfoStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.listCount = params[index++] & 0xFF;
+
+ this.firstIndex = params[index++] & 0xFF;
+
+ firmwareInformationList = new ArrayList<>();
+ FirmwareInformationEntry informationEntry;
+ int firmwareIdLength;
+ byte[] currentFirmwareID;
+ int uriLen;
+ byte[] updateURI;
+ for (int i = 0; i < this.listCount; i++) {
+
+ firmwareIdLength = params[index++] & 0xFF;
+ if (firmwareIdLength > 0) {
+ currentFirmwareID = new byte[firmwareIdLength];
+ System.arraycopy(params, index, currentFirmwareID, 0, firmwareIdLength);
+ index += firmwareIdLength;
+ } else {
+ currentFirmwareID = null;
+ }
+
+ uriLen = params[index++];
+ if (uriLen > 0) {
+ updateURI = new byte[uriLen];
+ System.arraycopy(params, index, updateURI, 0, uriLen);
+ index += uriLen;
+ } else {
+ updateURI = null;
+ }
+ informationEntry = new FirmwareInformationEntry();
+ informationEntry.currentFirmwareIDLength = firmwareIdLength;
+ informationEntry.currentFirmwareID = currentFirmwareID;
+ informationEntry.updateURILength = uriLen;
+ informationEntry.updateURI = updateURI;
+
+ firmwareInformationList.add(informationEntry);
+ }
+
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(listCount);
+ dest.writeInt(firstIndex);
+ dest.writeTypedList(firmwareInformationList);
+ }
+
+ public int getListCount() {
+ return listCount;
+ }
+
+ public int getFirstIndex() {
+ return firstIndex;
+ }
+
+ public List getFirmwareInformationList() {
+ return firmwareInformationList;
+ }
+
+ public FirmwareInformationEntry getFirstEntry() {
+ if (firmwareInformationList == null || firmwareInformationList.size() < (firstIndex + 1)) {
+ return null;
+ }
+ return firmwareInformationList.get(firstIndex);
+ }
+
+ public static class FirmwareInformationEntry implements Parcelable {
+ /**
+ * Length of the Current Firmware ID field
+ * 1 byte
+ */
+ public int currentFirmwareIDLength;
+
+ /**
+ * Identifies the firmware image on the node or any subsystem on the node.
+ * Variable
+ */
+ public byte[] currentFirmwareID;
+
+ /**
+ * Length of the Update URI field
+ * 1 byte
+ */
+ public int updateURILength;
+
+ /**
+ * URI used to retrieve a new firmware image
+ * If the value of the Update URI Length field is greater than 0, the Update URI field shall be present.
+ */
+ public byte[] updateURI;
+
+ public FirmwareInformationEntry() {
+ }
+
+ protected FirmwareInformationEntry(Parcel in) {
+ currentFirmwareIDLength = in.readInt();
+ currentFirmwareID = in.createByteArray();
+ updateURILength = in.readInt();
+ updateURI = in.createByteArray();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FirmwareInformationEntry createFromParcel(Parcel in) {
+ return new FirmwareInformationEntry(in);
+ }
+
+ @Override
+ public FirmwareInformationEntry[] newArray(int size) {
+ return new FirmwareInformationEntry[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(currentFirmwareIDLength);
+ dest.writeByteArray(currentFirmwareID);
+ dest.writeInt(updateURILength);
+ dest.writeByteArray(updateURI);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "FirmwareUpdateInfoStatusMessage{" +
+ "listCount=" + listCount +
+ ", firstIndex=" + firstIndex +
+ ", firmwareInformationList=" + firmwareInformationList.size() +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateStartMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateStartMessage.java
new file mode 100644
index 00000000..7a0984ec
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateStartMessage.java
@@ -0,0 +1,124 @@
+/********************************************************************************************************
+ * @file FirmwareUpdateStartMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class FirmwareUpdateStartMessage extends UpdatingMessage {
+
+ /**
+ * default ttl
+ */
+ public static final byte DEFAULT_UPDATE_TTL = 10;
+
+ /**
+ * Time To Live value to use during firmware image transfer
+ * 1 byte
+ */
+ private byte updateTtl = DEFAULT_UPDATE_TTL;
+
+ /**
+ * Used to compute the timeout of the firmware image transfer
+ * Client Timeout = [12,000 * (Client Timeout Base + 1) + 100 * Transfer TTL] milliseconds
+ * using blockSize
+ * 2 bytes
+ */
+ private int updateTimeoutBase;
+
+ /**
+ * BLOB identifier for the firmware image
+ * 8 bytes
+ */
+ private long updateBLOBID;
+
+ /**
+ * Index of the firmware image in the Firmware Information List state to be updated
+ * 1 byte
+ */
+ private int updateFirmwareImageIndex;
+
+ /**
+ * Vendor-specific firmware metadata
+ * If the value of the Incoming Firmware Metadata Length field is greater than 0,
+ * the Incoming Firmware Metadata field shall be present.
+ * 1-255 bytes
+ */
+ private byte[] metadata;
+
+ public static FirmwareUpdateStartMessage getSimple(int destinationAddress, int appKeyIndex,
+ int updateTimeoutBase, long blobId, byte[] metadata) {
+ FirmwareUpdateStartMessage message = new FirmwareUpdateStartMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ message.updateTimeoutBase = updateTimeoutBase;
+ message.updateBLOBID = blobId;
+ message.updateFirmwareImageIndex = 0;
+ message.metadata = metadata;
+ return message;
+ }
+
+ public FirmwareUpdateStartMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.FIRMWARE_UPDATE_START.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.FIRMWARE_UPDATE_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ final int len = 12 + metadata.length;
+ ByteBuffer bf = ByteBuffer.allocate(len).order(ByteOrder.LITTLE_ENDIAN)
+ .put(updateTtl).putShort((short) updateTimeoutBase)
+ .putLong(updateBLOBID).put((byte) updateFirmwareImageIndex).put(metadata);
+ return bf.array();
+ }
+
+ public void setUpdateTtl(byte updateTtl) {
+ this.updateTtl = updateTtl;
+ }
+
+ public void setUpdateTimeoutBase(int updateTimeoutBase) {
+ this.updateTimeoutBase = updateTimeoutBase;
+ }
+
+ public void setUpdateBLOBID(long updateBLOBID) {
+ this.updateBLOBID = updateBLOBID;
+ }
+
+ public void setUpdateFirmwareImageIndex(int updateFirmwareImageIndex) {
+ this.updateFirmwareImageIndex = updateFirmwareImageIndex;
+ }
+
+ public void setMetadata(byte[] metadata) {
+ this.metadata = metadata;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateStatusMessage.java
new file mode 100644
index 00000000..01573a09
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/FirmwareUpdateStatusMessage.java
@@ -0,0 +1,199 @@
+/********************************************************************************************************
+ * @file FirmwareUpdateStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+public class FirmwareUpdateStatusMessage extends StatusMessage implements Parcelable {
+
+
+ /**
+ * @see UpdateStatus
+ * 3 lower bits in first byte
+ */
+ private int status;
+
+ /**
+ * 3 higher bits in first byte (2 bits rfu)
+ */
+ private int phase;
+
+ /**
+ * Time To Live value to use during firmware image transfer
+ * 1 byte
+ */
+ private byte updateTtl;
+
+
+ /**
+ * 5 bits (3 bits rfu)
+ */
+ private int additionalInfo;
+
+ /**
+ * Used to compute the timeout of the firmware image transfer
+ * Client Timeout = [12,000 * (Client Timeout Base + 1) + 100 * Transfer TTL] milliseconds
+ * using blockSize
+ * 2 bytes
+ */
+ private int updateTimeoutBase;
+
+ /**
+ * BLOB identifier for the firmware image
+ * 8 bytes
+ */
+ private long updateBLOBID;
+
+ /**
+ * length: 1 byte
+ */
+ private int updateFirmwareImageIndex;
+
+ /**
+ * If the Update TTL field is present,
+ * the Additional Information field, Update Timeout field, BLOB ID field, and Installed Firmware ID field shall be present;
+ * otherwise, the Additional Information field, Update Timeout field, BLOB ID field, and Installed Firmware ID field shall not be present.
+ */
+ private boolean isComplete = false;
+
+ public FirmwareUpdateStatusMessage() {
+ }
+
+
+ protected FirmwareUpdateStatusMessage(Parcel in) {
+ status = in.readInt();
+ phase = in.readInt();
+ updateTtl = in.readByte();
+ additionalInfo = in.readInt();
+ updateTimeoutBase = in.readInt();
+ updateBLOBID = in.readLong();
+ updateFirmwareImageIndex = in.readInt();
+ isComplete = in.readByte() != 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FirmwareUpdateStatusMessage createFromParcel(Parcel in) {
+ return new FirmwareUpdateStatusMessage(in);
+ }
+
+ @Override
+ public FirmwareUpdateStatusMessage[] newArray(int size) {
+ return new FirmwareUpdateStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+
+ this.status = params[index] & 0x07;
+
+ this.phase = (params[index] & 0xFF) >> 5;
+
+ isComplete = params.length > 1;
+ if (!isComplete) return;
+ index++;
+
+ this.updateTtl = params[index++];
+
+ this.additionalInfo = (params[index++] & 0x1F);
+
+ this.updateTimeoutBase = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ this.updateBLOBID = MeshUtils.bytes2Integer(params, index, 8, ByteOrder.LITTLE_ENDIAN);
+ index += 8;
+
+ this.updateFirmwareImageIndex = params[index] & 0xFF;
+
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(phase);
+ dest.writeByte(updateTtl);
+ dest.writeInt(additionalInfo);
+ dest.writeInt(updateTimeoutBase);
+ dest.writeLong(updateBLOBID);
+ dest.writeInt(updateFirmwareImageIndex);
+ dest.writeByte((byte) (isComplete ? 1 : 0));
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public int getPhase() {
+ return phase;
+ }
+
+ public byte getUpdateTtl() {
+ return updateTtl;
+ }
+
+ public int getAdditionalInfo() {
+ return additionalInfo;
+ }
+
+ public int getUpdateTimeoutBase() {
+ return updateTimeoutBase;
+ }
+
+ public long getUpdateBLOBID() {
+ return updateBLOBID;
+ }
+
+ public int getUpdateFirmwareImageIndex() {
+ return updateFirmwareImageIndex;
+ }
+
+ public boolean isComplete() {
+ return isComplete;
+ }
+
+ @Override
+ public String toString() {
+ return "FirmwareUpdateStatusMessage{" +
+ "status=" + status +
+ ", phase=" + phase +
+ ", updateTtl=" + updateTtl +
+ ", additionalInfo=" + additionalInfo +
+ ", updateTimeoutBase=" + updateTimeoutBase +
+ ", updateBLOBID=0x" + Long.toHexString(updateBLOBID) +
+ ", updateFirmwareImageIndex=" + updateFirmwareImageIndex +
+ ", isComplete=" + isComplete +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/UpdatePhase.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/UpdatePhase.java
new file mode 100644
index 00000000..397a32a7
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/UpdatePhase.java
@@ -0,0 +1,56 @@
+/********************************************************************************************************
+ * @file UpdatePhase.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+public enum UpdatePhase {
+
+ IDLE(0x00, "Ready to start a Receive Firmware procedure"),
+
+ TRANSFER_ERROR(0x01, "The Transfer BLOB procedure failed."),
+
+ TRANSFER_ACTIVE(0x02, "The Receive Firmware procedure is being executed"),
+
+ VERIFICATION_ACTIVE(0x03, "The Verify Firmware procedure is being executed"),
+
+ VERIFICATION_SUCCESS(0x04, "The Verify Firmware procedure completed successfully."),
+
+ VERIFICATION_FAILED(0x05, "The Verify Firmware procedure failed."),
+
+ APPLYING_UPDATE(0x06, "The Apply New Firmware procedure is being executed."),
+
+ UNKNOWN_ERROR(0xFF, "unknown error");
+
+ public final int code;
+ public final String desc;
+
+ UpdatePhase(int code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static UpdatePhase valueOf(int code) {
+ for (UpdatePhase status : values()) {
+ if (status.code == code) return status;
+ }
+ return UNKNOWN_ERROR;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/UpdateStatus.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/UpdateStatus.java
new file mode 100644
index 00000000..c28e214f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/UpdateStatus.java
@@ -0,0 +1,58 @@
+/********************************************************************************************************
+ * @file UpdateStatus.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+public enum UpdateStatus {
+
+ SUCCESS(0x00, "The message was processed successfully"),
+
+ METADATA_CHECK_FAILED(0x01, "The metadata check failed"),
+
+ INVALID_FIRMWARE_ID(0x02, "The message contains a Firmware ID value that is not expected"),
+
+ OUT_OF_RESOURCES(0x03, "Insufficient resources on the node"),
+
+ BLOB_TRANSFER_BUSY(0x04, "Another BLOB transfer is in progress"),
+
+ INVALID_COMMAND(0x05, "The operation cannot be performed while the server is in the current phase"),
+
+ TEMPORARILY_UNAVAILABLE(0x06, "The server cannot start a firmware update"),
+
+ INTERNAL_ERROR(0x07, "An internal error occurred on the node"),
+
+ UNKNOWN_ERROR(0xFF, "unknown error");
+
+ public final int code;
+ public final String desc;
+
+ UpdateStatus(int code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static UpdateStatus valueOf(int code) {
+ for (UpdateStatus status : values()) {
+ if (status.code == code) return status;
+ }
+ return UNKNOWN_ERROR;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/UpdatingMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/UpdatingMessage.java
new file mode 100644
index 00000000..b56a8d25
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/UpdatingMessage.java
@@ -0,0 +1,36 @@
+/********************************************************************************************************
+ * @file UpdatingMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate;
+
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.networking.AccessType;
+
+
+public abstract class UpdatingMessage extends MeshMessage {
+
+ public UpdatingMessage(int destinationAddress, int appKeyIndex) {
+ this.destinationAddress = destinationAddress;
+ this.appKeyIndex = appKeyIndex;
+ this.accessType = AccessType.APPLICATION;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobBlockGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobBlockGetMessage.java
new file mode 100644
index 00000000..73c1e895
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobBlockGetMessage.java
@@ -0,0 +1,53 @@
+/********************************************************************************************************
+ * @file BlobBlockGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+
+public class BlobBlockGetMessage extends UpdatingMessage {
+
+
+ public static BlobBlockGetMessage getSimple(int destinationAddress, int appKeyIndex) {
+ BlobBlockGetMessage message = new BlobBlockGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ public BlobBlockGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.BLOB_BLOCK_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.BLOB_BLOCK_STATUS.value;
+ }
+
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobBlockStartMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobBlockStartMessage.java
new file mode 100644
index 00000000..f7719558
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobBlockStartMessage.java
@@ -0,0 +1,85 @@
+/********************************************************************************************************
+ * @file BlobBlockStartMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class BlobBlockStartMessage extends UpdatingMessage {
+
+
+ /**
+ * Block number of the incoming block
+ * 2 bytes
+ */
+ private int blockNumber;
+
+ /**
+ * Chunk size (in octets) for the incoming block
+ * 2 bytes
+ */
+ private int chunkSize;
+
+
+ public static BlobBlockStartMessage getSimple(int destinationAddress, int appKeyIndex,
+ int blockNumber,
+ int chunkSize) {
+ BlobBlockStartMessage message = new BlobBlockStartMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ message.blockNumber = blockNumber;
+ message.chunkSize = chunkSize;
+ return message;
+ }
+
+ public BlobBlockStartMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.BLOB_BLOCK_START.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.BLOB_BLOCK_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) blockNumber)
+ .putShort((short) chunkSize).array();
+ }
+
+ public void setBlockNumber(int blockNumber) {
+ this.blockNumber = blockNumber;
+ }
+
+ public void setChunkSize(int chunkSize) {
+ this.chunkSize = chunkSize;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobBlockStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobBlockStatusMessage.java
new file mode 100644
index 00000000..3f531626
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobBlockStatusMessage.java
@@ -0,0 +1,204 @@
+/********************************************************************************************************
+ * @file BlobBlockStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+public class BlobBlockStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * All chunks in the block are missing.
+ */
+ public static final int FORMAT_ALL_CHUNKS_MISSING = 0x00;
+
+ /**
+ * All chunks in the block have been received.
+ */
+ public static final int FORMAT_NO_CHUNKS_MISSING = 0x01;
+
+ /**
+ * At least one chunk has been received and at least one chunk is missing.
+ */
+ public static final int FORMAT_SOME_CHUNKS_MISSING = 0x02;
+
+ /**
+ * List of chunks requested by the server
+ */
+ public static final int FORMAT_ENCODED_MISSING_CHUNKS = 0x03;
+
+ /**
+ * Status Code for the requesting message
+ * lower 4 bits in first byte
+ *
+ * @see TransferStatus
+ */
+ private int status;
+
+ /**
+ * Indicates the format used to report missing chunks
+ * higher 2 bits in first byte
+ */
+ private int format;
+
+ /**
+ * Transfer phase
+ */
+ // remote in R06 -- 20200618
+// private int transferPhase;
+
+ /**
+ * Block number of the current block
+ * 16 bits
+ */
+ private int blockNumber;
+
+ /**
+ * Chunk Size (in octets) for the current block
+ * 16 bits
+ */
+ private int chunkSize;
+
+ /**
+ * Bit field of missing chunks for this block
+ */
+ private List missingChunks;
+
+ /**
+ * List of chunks requested by the server
+ * using UTF-8
+ */
+ private List encodedMissingChunks;
+
+
+ public BlobBlockStatusMessage() {
+ }
+
+
+ protected BlobBlockStatusMessage(Parcel in) {
+ status = in.readInt();
+ format = in.readInt();
+// transferPhase = in.readInt();
+ blockNumber = in.readInt();
+ chunkSize = in.readInt();
+ missingChunks = new ArrayList<>();
+ in.readList(missingChunks, null);
+ encodedMissingChunks = new ArrayList<>();
+ in.readList(encodedMissingChunks, null);
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public BlobBlockStatusMessage createFromParcel(Parcel in) {
+ return new BlobBlockStatusMessage(in);
+ }
+
+ @Override
+ public BlobBlockStatusMessage[] newArray(int size) {
+ return new BlobBlockStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.status = params[index] & 0x0F;
+ this.format = (params[index++] >> 6) & 0x03;
+// transferPhase = params[index++] & 0xFF;
+ this.blockNumber = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.chunkSize = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ if (format == FORMAT_SOME_CHUNKS_MISSING) {
+ missingChunks = MeshUtils.parseMissingBitField(params, index);
+ } else if (format == FORMAT_ENCODED_MISSING_CHUNKS) {
+ encodedMissingChunks = new ArrayList<>();
+ byte[] missing = new byte[params.length - index];
+ System.arraycopy(params, index, missing, 0, missing.length);
+ String decodeMissingChunks = new String(missing, Charset.forName("UTF-8"));
+ for (char c : decodeMissingChunks.toCharArray()) {
+ encodedMissingChunks.add(c & 0xFFFF);
+ }
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(format);
+// dest.writeInt(transferPhase);
+ dest.writeInt(blockNumber);
+ dest.writeInt(chunkSize);
+ dest.writeList(missingChunks);
+ dest.writeList(encodedMissingChunks);
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public int getFormat() {
+ return format;
+ }
+
+ public int getBlockNumber() {
+ return blockNumber;
+ }
+
+ public long getChunkSize() {
+ return chunkSize;
+ }
+
+ public List getMissingChunks() {
+ return missingChunks;
+ }
+
+ public List getEncodedMissingChunks() {
+ return encodedMissingChunks;
+ }
+
+ @Override
+ public String toString() {
+ return "BlobBlockStatusMessage{" +
+ "status=" + status +
+ ", format=" + format +
+ ", blockNumber=" + blockNumber +
+ ", chunkSize=" + chunkSize +
+ ", missingChunks=" + (missingChunks == null ? "null" : missingChunks.size()) +
+ ", encodedMissingChunks=" + (encodedMissingChunks == null ? "null" : encodedMissingChunks.size()) +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobChunkTransferMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobChunkTransferMessage.java
new file mode 100644
index 00000000..82b51233
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobChunkTransferMessage.java
@@ -0,0 +1,94 @@
+/********************************************************************************************************
+ * @file BlobChunkTransferMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+import com.telink.ble.mesh.util.Arrays;
+
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class BlobChunkTransferMessage extends UpdatingMessage {
+
+
+ /**
+ * The chunk’s number in a set of chunks in a block
+ * 2 bytes
+ */
+ private int chunkNumber;
+
+ /**
+ * Binary data from the current block
+ */
+ private byte[] chunkData;
+
+
+ public static BlobChunkTransferMessage getSimple(int destinationAddress, int appKeyIndex,
+ int chunkNumber,
+ byte[] chunkData) {
+ BlobChunkTransferMessage message = new BlobChunkTransferMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ message.chunkNumber = chunkNumber;
+ message.chunkData = chunkData;
+ return message;
+ }
+
+ public BlobChunkTransferMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.BLOB_CHUNK_TRANSFER.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return OPCODE_INVALID;
+ }
+
+ @Override
+ public byte[] getParams() {
+ ByteBuffer bf = ByteBuffer.allocate(2 + chunkData.length).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) chunkNumber)
+ .put(chunkData);
+ return bf.array();
+ }
+
+ @Override
+ public String toString() {
+ return "BlobChunkTransferMessage{" +
+ "chunkNumber=" + chunkNumber +
+ ", chunkData=" + Arrays.bytesToHexString(chunkData) +
+ '}';
+ }
+
+ public void setChunkNumber(int chunkNumber) {
+ this.chunkNumber = chunkNumber;
+ }
+
+ public void setChunkData(byte[] chunkData) {
+ this.chunkData = chunkData;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobInfoGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobInfoGetMessage.java
new file mode 100644
index 00000000..490eba2a
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobInfoGetMessage.java
@@ -0,0 +1,53 @@
+/********************************************************************************************************
+ * @file BlobInfoGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+
+public class BlobInfoGetMessage extends UpdatingMessage {
+
+
+ public static BlobInfoGetMessage getSimple(int destinationAddress, int appKeyIndex) {
+ BlobInfoGetMessage message = new BlobInfoGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ public BlobInfoGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.BLOB_INFORMATION_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.BLOB_INFORMATION_STATUS.value;
+ }
+
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobInfoStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobInfoStatusMessage.java
new file mode 100644
index 00000000..79bb3920
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobInfoStatusMessage.java
@@ -0,0 +1,169 @@
+/********************************************************************************************************
+ * @file BlobInfoStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+public class BlobInfoStatusMessage extends StatusMessage implements Parcelable {
+
+
+ /**
+ * Minimum block size supported by the server
+ * 1 byte
+ */
+ private int minBlockSizeLog;
+
+ /**
+ * Maximum block size supported by the server
+ * 1 byte
+ */
+ private int maxBlockSizeLog;
+
+ /**
+ * Maximum number of chunks in block supported by the server
+ * 2 bytes
+ */
+ private int maxTotalChunks;
+
+ /**
+ * Maximum chunk size supported by the server
+ * 2 bytes
+ */
+ private int maxChunkSize;
+
+ /**
+ * Maximum BLOB size supported by the server
+ * 4 bytes
+ */
+ private int maxBLOBSize;
+
+ /**
+ * MTU size supported by the server
+ * 2 bytes
+ */
+ private int serverMTUSize;
+
+ /**
+ * BLOB transfer modes supported by the server
+ * 1 byte
+ */
+ private int supportedTransferMode;
+
+ public BlobInfoStatusMessage() {
+ }
+
+
+ protected BlobInfoStatusMessage(Parcel in) {
+ minBlockSizeLog = in.readInt();
+ maxBlockSizeLog = in.readInt();
+ maxTotalChunks = in.readInt();
+ maxChunkSize = in.readInt();
+ maxBLOBSize = in.readInt();
+ serverMTUSize = in.readInt();
+ supportedTransferMode = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public BlobInfoStatusMessage createFromParcel(Parcel in) {
+ return new BlobInfoStatusMessage(in);
+ }
+
+ @Override
+ public BlobInfoStatusMessage[] newArray(int size) {
+ return new BlobInfoStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.minBlockSizeLog = params[index++] & 0xFF;
+ this.maxBlockSizeLog = params[index++] & 0xFF;
+
+ this.maxTotalChunks = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ this.maxChunkSize = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ this.maxBLOBSize = MeshUtils.bytes2Integer(params, index, 4, ByteOrder.LITTLE_ENDIAN);
+ index += 4;
+
+ this.serverMTUSize = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ this.supportedTransferMode = params[index];
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(minBlockSizeLog);
+ dest.writeInt(maxBlockSizeLog);
+ dest.writeInt(maxTotalChunks);
+ dest.writeInt(maxChunkSize);
+ dest.writeInt(maxBLOBSize);
+ dest.writeInt(serverMTUSize);
+ dest.writeInt(supportedTransferMode);
+ }
+
+ public int getMinBlockSizeLog() {
+ return minBlockSizeLog;
+ }
+
+ public int getMaxBlockSizeLog() {
+ return maxBlockSizeLog;
+ }
+
+ public int getMaxTotalChunks() {
+ return maxTotalChunks;
+ }
+
+ public int getMaxChunkSize() {
+ return maxChunkSize;
+ }
+
+ public int getMaxBLOBSize() {
+ return maxBLOBSize;
+ }
+
+ public int getServerMTUSize() {
+ return serverMTUSize;
+ }
+
+ public int getSupportedTransferMode() {
+ return supportedTransferMode;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobPartialBlockReportMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobPartialBlockReportMessage.java
new file mode 100644
index 00000000..66b983d9
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobPartialBlockReportMessage.java
@@ -0,0 +1,85 @@
+/********************************************************************************************************
+ * @file BlobPartialBlockReportMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+
+public class BlobPartialBlockReportMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * List of chunks requested by the server
+ * using UTF-8
+ */
+ private ArrayList encodedMissingChunks;
+
+
+ public BlobPartialBlockReportMessage() {
+
+ }
+
+
+ protected BlobPartialBlockReportMessage(Parcel in) {
+ encodedMissingChunks = new ArrayList<>();
+ in.readList(encodedMissingChunks, null);
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public BlobPartialBlockReportMessage createFromParcel(Parcel in) {
+ return new BlobPartialBlockReportMessage(in);
+ }
+
+ @Override
+ public BlobPartialBlockReportMessage[] newArray(int size) {
+ return new BlobPartialBlockReportMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ encodedMissingChunks = new ArrayList<>();
+ String decodeMissingChunks = new String(params, Charset.forName("UTF-8"));
+ for (char c : decodeMissingChunks.toCharArray()) {
+ encodedMissingChunks.add(c & 0xFFFF);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeList(encodedMissingChunks);
+ }
+
+ public ArrayList getEncodedMissingChunks() {
+ return encodedMissingChunks;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferCancelMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferCancelMessage.java
new file mode 100644
index 00000000..d8c17b4c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferCancelMessage.java
@@ -0,0 +1,71 @@
+/********************************************************************************************************
+ * @file BlobTransferCancelMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class BlobTransferCancelMessage extends UpdatingMessage {
+
+ /**
+ * BLOB identifier
+ * 64 bits
+ */
+ private long blobId;
+
+ public static BlobTransferCancelMessage getSimple(int destinationAddress, int appKeyIndex,
+ long blobId) {
+ BlobTransferCancelMessage message = new BlobTransferCancelMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ message.blobId = blobId;
+ return message;
+ }
+
+ public BlobTransferCancelMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.BLOB_TRANSFER_CANCEL.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.BLOB_TRANSFER_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return ByteBuffer.allocate(16).order(ByteOrder.LITTLE_ENDIAN)
+ .putLong(blobId)
+ .array();
+ }
+
+ public void setBlobId(long blobId) {
+ this.blobId = blobId;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferGetMessage.java
new file mode 100644
index 00000000..447b15a3
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferGetMessage.java
@@ -0,0 +1,53 @@
+/********************************************************************************************************
+ * @file BlobTransferGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+
+public class BlobTransferGetMessage extends UpdatingMessage {
+
+
+ public static BlobTransferGetMessage getSimple(int destinationAddress, int appKeyIndex) {
+ BlobTransferGetMessage message = new BlobTransferGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ return message;
+ }
+
+ public BlobTransferGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.BLOB_TRANSFER_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.BLOB_TRANSFER_STATUS.value;
+ }
+
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferStartMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferStartMessage.java
new file mode 100644
index 00000000..7695fbae
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferStartMessage.java
@@ -0,0 +1,122 @@
+/********************************************************************************************************
+ * @file BlobTransferStartMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class BlobTransferStartMessage extends UpdatingMessage {
+
+ /**
+ * BLOB transfer mode
+ * higher 2 bits in first byte
+ */
+ private TransferMode transferMode = TransferMode.PUSH;
+
+ /**
+ * BLOB identifier
+ * 64 bits
+ */
+ private long blobId;
+
+ /**
+ * BLOB size in octets
+ * 32 bits
+ */
+ private int blobSize;
+
+ /**
+ * Indicates the block size
+ * 8 bits
+ */
+ private int blockSizeLog;
+
+ /**
+ * MTU size supported by the client
+ */
+ private int clientMTUSize;
+
+
+ public static BlobTransferStartMessage getSimple(int destinationAddress, int appKeyIndex,
+ long blobId,
+ int blobSize,
+ byte blockSizeLog,
+ int clientMTUSize) {
+ BlobTransferStartMessage message = new BlobTransferStartMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(1);
+ message.blobId = blobId;
+ message.blobSize = blobSize;
+ message.blockSizeLog = blockSizeLog;
+ message.clientMTUSize = clientMTUSize;
+ return message;
+ }
+
+ public BlobTransferStartMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.BLOB_TRANSFER_START.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.BLOB_TRANSFER_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ final byte modeValue = (byte) (transferMode.mode << 6);
+
+ return ByteBuffer.allocate(16).order(ByteOrder.LITTLE_ENDIAN)
+ .put(modeValue)
+ .putLong(blobId)
+ .putInt(blobSize)
+ .put((byte) blockSizeLog)
+ .putShort((short) clientMTUSize).array();
+ }
+
+ public void setTransferMode(TransferMode transferMode) {
+ this.transferMode = transferMode;
+ }
+
+ public void setBlobId(long blobId) {
+ this.blobId = blobId;
+ }
+
+ public void setBlobSize(int blobSize) {
+ this.blobSize = blobSize;
+ }
+
+ public void setBlockSizeLog(int blockSizeLog) {
+ this.blockSizeLog = blockSizeLog;
+ }
+
+ public void setClientMTUSize(int clientMTUSize) {
+ this.clientMTUSize = clientMTUSize;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferStatusMessage.java
new file mode 100644
index 00000000..c7314004
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/BlobTransferStatusMessage.java
@@ -0,0 +1,202 @@
+/********************************************************************************************************
+ * @file BlobTransferStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+public class BlobTransferStatusMessage extends StatusMessage implements Parcelable {
+
+ /**
+ * Status Code for the requesting message
+ * lower 4 bits in first byte
+ */
+ private int status;
+
+ /**
+ * BLOB transfer mode
+ * higher 2 bits in first byte
+ */
+ private int transferMode;
+
+ /**
+ * Transfer phase
+ * 8 bits
+ */
+ private byte transferPhase;
+
+ /**
+ * BLOB identifier (Optional)
+ * 64 bits
+ */
+ private long blobId;
+
+ /**
+ * BLOB size in octets
+ * If the BLOB ID field is present, then the BLOB Size field may be present;
+ * otherwise, the BLOB Size field shall not be present.
+ * 32 bits
+ */
+ private int blobSize;
+
+ /**
+ * Indicates the block size
+ * 8 bits
+ * present if blobSize is present
+ */
+ private int blockSizeLog;
+
+ /**
+ * MTU size in octets
+ * 16 bits
+ * present if blobSize is present
+ */
+ private int transferMTUSize;
+
+ /**
+ * Bit field indicating blocks that were not received
+ * length: Variable, currently 64 bits max
+ * present if blobSize is present
+ */
+ private List blocksNotReceived;
+
+ public BlobTransferStatusMessage() {
+ }
+
+
+ protected BlobTransferStatusMessage(Parcel in) {
+ status = in.readInt();
+ transferMode = in.readInt();
+ transferPhase = in.readByte();
+ blobId = in.readLong();
+ blobSize = in.readInt();
+ blockSizeLog = in.readInt();
+ transferMTUSize = in.readInt();
+ blocksNotReceived = new ArrayList<>();
+ in.readList(blocksNotReceived, null);
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public BlobTransferStatusMessage createFromParcel(Parcel in) {
+ return new BlobTransferStatusMessage(in);
+ }
+
+ @Override
+ public BlobTransferStatusMessage[] newArray(int size) {
+ return new BlobTransferStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.status = params[index] & 0x0F;
+ this.transferMode = (params[index++] >> 6) & 0x03;
+ this.transferPhase = params[index++];
+
+ if (params.length < 10) return;
+
+ this.blobId = MeshUtils.bytes2Long(params, index, 8, ByteOrder.LITTLE_ENDIAN);
+ index += 8;
+
+ if (params.length == 10) return;
+
+ this.blobSize = MeshUtils.bytes2Integer(params, index, 4, ByteOrder.LITTLE_ENDIAN);
+ index += 4;
+ this.blockSizeLog = params[index++] & 0xFF;
+ this.transferMTUSize = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+
+ this.blocksNotReceived = MeshUtils.parseMissingBitField(params, index);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(status);
+ dest.writeInt(transferMode);
+ dest.writeByte(transferPhase);
+ dest.writeLong(blobId);
+ dest.writeInt(blobSize);
+ dest.writeInt(blockSizeLog);
+ dest.writeInt(transferMTUSize);
+ dest.writeList(blocksNotReceived);
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public int getTransferMode() {
+ return transferMode;
+ }
+
+ public byte getTransferPhase() {
+ return transferPhase;
+ }
+
+ public long getBlobId() {
+ return blobId;
+ }
+
+ public int getBlobSize() {
+ return blobSize;
+ }
+
+ public int getBlockSizeLog() {
+ return blockSizeLog;
+ }
+
+ public int getTransferMTUSize() {
+ return transferMTUSize;
+ }
+
+ public List getBlocksNotReceived() {
+ return blocksNotReceived;
+ }
+
+ @Override
+ public String toString() {
+ return "BlobTransferStatusMessage{" +
+ "status=" + status +
+ ", transferMode=" + transferMode +
+ ", transferPhase=" + transferPhase +
+ ", blobId=0x" + Long.toHexString(blobId) +
+ ", blobSize=" + blobSize +
+ ", blockSizeLog=" + blockSizeLog +
+ ", transferMTUSize=" + transferMTUSize +
+ ", blocksNotReceived=" + blocksNotReceived +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/TransferMode.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/TransferMode.java
new file mode 100644
index 00000000..b4b85168
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/TransferMode.java
@@ -0,0 +1,51 @@
+/********************************************************************************************************
+ * @file TransferMode.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+/**
+ * The Transfer Mode state is a 2-bit value that indicates the mode of the BLOB transfer
+ */
+public enum TransferMode {
+
+ NONE(0x00, "No Active Transfer"),
+
+ PUSH(0x01, "Push BLOB Transfer Mode"),
+
+ PULL(0x02, "Pull BLOB Transfer Mode"),
+
+ Prohibited(0x03, "Prohibited");
+
+ public final int mode;
+ public final String desc;
+
+ TransferMode(int mode, String desc) {
+ this.mode = mode;
+ this.desc = desc;
+ }
+
+ public static TransferMode valueOf(int mode) {
+ for (TransferMode status : values()) {
+ if (status.mode == mode) return status;
+ }
+ return Prohibited;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/TransferPhase.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/TransferPhase.java
new file mode 100644
index 00000000..8353979b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/TransferPhase.java
@@ -0,0 +1,58 @@
+/********************************************************************************************************
+ * @file TransferPhase.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+public enum TransferPhase {
+
+ INACTIVE(0x00,
+ "The BLOB Transfer Server is awaiting configuration and cannot receive a BLOB."),
+
+ WAITING_FOR_TRANSFER_START(0x01,
+ "The BLOB Transfer Server is ready to receive the BLOB identified by the Expected BLOB ID."),
+
+ WAITING_FOR_NEXT_BLOCK(0x02,
+ "The BLOB Transfer Server is waiting for the next block of data."),
+
+ WAITING_FOR_NEXT_CHUNK(0x03,
+ "The BLOB Transfer Server is waiting for the next chunk of data."),
+
+ COMPLETE(0x04, "The BLOB was transferred successfully."),
+
+ SUSPENDED(0x05, "The Initialize and Receive BLOB procedure is paused."),
+
+ UNKNOWN_ERROR(0x0A, "unknown error");
+
+ public final int code;
+ public final String desc;
+
+ TransferPhase(int code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static TransferPhase valueOf(int code) {
+ for (TransferPhase status : values()) {
+ if (status.code == code) return status;
+ }
+ return UNKNOWN_ERROR;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/TransferStatus.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/TransferStatus.java
new file mode 100644
index 00000000..d2e81ba2
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/firmwareupdate/blobtransfer/TransferStatus.java
@@ -0,0 +1,62 @@
+/********************************************************************************************************
+ * @file TransferStatus.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.firmwareupdate.blobtransfer;
+
+public enum TransferStatus {
+
+ SUCCESS(0x00, "The message was processed successfully"),
+
+ INVALID_BLOCK_NUMBER(0x01, "The Block Number field value is not within the range of blocks being transferred"),
+
+ INVALID_BLOCK_SIZE(0x02, "The block size is smaller than the size indicated by the Min Block Size Log state or is larger than the size indicated by the Max Block Size Log state."),
+
+ INVALID_CHUNK_SIZE(0x03, " The chunk size exceeds the size indicated by the Max Chunk Size state, or the number of chunks exceeds the number specified by the Max Total Chunks state."),
+
+ INVALID_STATE(0x04, "The operation cannot be performed while the server is in the current phase."),
+
+ INVALID_PARAMETER(0x05, "A parameter value in the message cannot be accepted."),
+
+ WRONG_BLOB_ID(0x06, "The message contains a BLOB ID value that is not expected."),
+
+ BLOB_TOO_LARGE(0x07, "There is not enough space available in memory to receive the BLOB."),
+
+ UNSUPPORTED_TRANSFER_MODE(0x08, "The transfer mode is not supported by the BLOB Transfer Server model."),
+
+ INTERNAL_ERROR(0x09, "An internal error occurred on the node"),
+
+ UNKNOWN_ERROR(0x0A, "unknown error");
+
+ public final int code;
+ public final String desc;
+
+ TransferStatus(int code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public static TransferStatus valueOf(int code) {
+ for (TransferStatus status : values()) {
+ if (status.code == code) return status;
+ }
+ return UNKNOWN_ERROR;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/DeltaSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/DeltaSetMessage.java
new file mode 100644
index 00000000..3c0e7bcf
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/DeltaSetMessage.java
@@ -0,0 +1,106 @@
+/********************************************************************************************************
+ * @file DeltaSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.generic;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class DeltaSetMessage extends GenericMessage {
+
+ private int deltaLevel;
+
+ private byte tid;
+
+ private byte transitionTime;
+
+ private byte delay;
+
+ private boolean ack;
+
+ private boolean isComplete = false;
+
+
+ public static DeltaSetMessage getSimple(int destinationAddress, int appKeyIndex, int deltaLevel, boolean ack, int rspMax) {
+ DeltaSetMessage deltaSetMessage = new DeltaSetMessage(destinationAddress, appKeyIndex);
+ deltaSetMessage.deltaLevel = deltaLevel;
+ deltaSetMessage.transitionTime = 0;
+ deltaSetMessage.delay = 0;
+
+ deltaSetMessage.ack = ack;
+ deltaSetMessage.responseOpcode = Opcode.G_LEVEL_STATUS.value;
+ deltaSetMessage.responseMax = rspMax;
+ return deltaSetMessage;
+ }
+
+
+ public DeltaSetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ setTidPosition(4);
+ }
+
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.G_DELTA_SET.value : Opcode.G_DELTA_SET_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return
+ isComplete ?
+ ByteBuffer.allocate(7).order(ByteOrder.LITTLE_ENDIAN).putInt(deltaLevel)
+ .put(tid).put(transitionTime).put(delay).array()
+ :
+ ByteBuffer.allocate(5).order(ByteOrder.LITTLE_ENDIAN).putInt(deltaLevel)
+ .put(tid).array();
+ }
+
+ public void setDeltaLevel(int deltaLevel) {
+ this.deltaLevel = deltaLevel;
+ }
+
+ public void setTid(byte tid) {
+ this.tid = tid;
+ }
+
+ public void setTransitionTime(byte transitionTime) {
+ this.transitionTime = transitionTime;
+ }
+
+ public void setDelay(byte delay) {
+ this.delay = delay;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+
+ public void setComplete(boolean complete) {
+ isComplete = complete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/GenericMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/GenericMessage.java
new file mode 100644
index 00000000..e990de87
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/GenericMessage.java
@@ -0,0 +1,39 @@
+/********************************************************************************************************
+ * @file GenericMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.generic;
+
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.networking.AccessType;
+
+/**
+ * generic model message
+ * Created by kee on 2019/8/14.
+ */
+
+public abstract class GenericMessage extends MeshMessage {
+
+ public GenericMessage(int destinationAddress, int appKeyIndex) {
+ this.destinationAddress = destinationAddress;
+ this.appKeyIndex = appKeyIndex;
+ this.accessType = AccessType.APPLICATION;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/LevelGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/LevelGetMessage.java
new file mode 100644
index 00000000..9d77649a
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/LevelGetMessage.java
@@ -0,0 +1,46 @@
+/********************************************************************************************************
+ * @file LevelGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.generic;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * generic level get
+ * Created by kee on 2019/8/20.
+ */
+public class LevelGetMessage extends GenericMessage {
+
+
+ public LevelGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.G_LEVEL_GET.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return null;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/LevelSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/LevelSetMessage.java
new file mode 100644
index 00000000..253f5ce9
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/LevelSetMessage.java
@@ -0,0 +1,100 @@
+/********************************************************************************************************
+ * @file LevelSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.generic;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * define level set and level set no ack
+ * by {@link #ack}
+ * Created by kee on 2019/8/14.
+ */
+public class LevelSetMessage extends GenericMessage {
+ // 1: on, 0: off
+ private int level;
+
+ private byte tid = 0;
+
+ private byte transitionTime = 0;
+
+ private byte delay = 0;
+
+ private boolean ack = false;
+
+ /**
+ * is complete message with optional params filled
+ */
+ private boolean isComplete = false;
+
+ public LevelSetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ setTidPosition(2);
+ }
+
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.G_LEVEL_SET.value : Opcode.G_LEVEL_SET_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return isComplete ?
+ new byte[]{
+ (byte) this.level,
+ (byte) (this.level >> 8),
+ this.tid,
+ this.transitionTime,
+ this.delay
+ }
+ :
+ new byte[]{
+ (byte) this.level,
+ (byte) (this.level >> 8),
+ this.tid
+ };
+ }
+
+ public void setLevel(int level) {
+ this.level = level;
+ }
+
+ public void setTid(byte tid) {
+ this.tid = tid;
+ }
+
+ public void setTransitionTime(byte transitionTime) {
+ this.transitionTime = transitionTime;
+ }
+
+ public void setDelay(byte delay) {
+ this.delay = delay;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+
+ public void setComplete(boolean complete) {
+ isComplete = complete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/LevelStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/LevelStatusMessage.java
new file mode 100644
index 00000000..b4c57abc
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/LevelStatusMessage.java
@@ -0,0 +1,116 @@
+/********************************************************************************************************
+ * @file LevelStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.generic;
+
+import android.os.Parcel;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/9/3.
+ */
+
+public class LevelStatusMessage extends StatusMessage {
+
+ private static final int DATA_LEN_COMPLETE = 5;
+
+ /**
+ * The present value of the Generic Level state.
+ * 2 bytes
+ */
+ private int presentLevel;
+
+ /**
+ * The target value of the Generic Level state (Optional).
+ * 2 bytes
+ */
+ private int targetLevel;
+
+ private byte remainingTime;
+
+ private boolean isComplete = false;
+
+ public LevelStatusMessage() {
+ }
+
+ protected LevelStatusMessage(Parcel in) {
+ presentLevel = in.readInt();
+ targetLevel = in.readInt();
+ remainingTime = in.readByte();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public LevelStatusMessage createFromParcel(Parcel in) {
+ return new LevelStatusMessage(in);
+ }
+
+ @Override
+ public LevelStatusMessage[] newArray(int size) {
+ return new LevelStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.presentLevel = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ if (params.length == DATA_LEN_COMPLETE) {
+ this.isComplete = true;
+ this.targetLevel = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.remainingTime = params[index];
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(presentLevel);
+ dest.writeInt(targetLevel);
+ dest.writeByte(remainingTime);
+ }
+
+ public int getPresentLevel() {
+ return presentLevel;
+ }
+
+ public int getTargetLevel() {
+ return targetLevel;
+ }
+
+ public byte getRemainingTime() {
+ return remainingTime;
+ }
+
+ public boolean isComplete() {
+ return isComplete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/MoveSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/MoveSetMessage.java
new file mode 100644
index 00000000..bf9d116a
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/MoveSetMessage.java
@@ -0,0 +1,96 @@
+/********************************************************************************************************
+ * @file MoveSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.generic;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class MoveSetMessage extends GenericMessage {
+
+ private int deltaLevel;
+
+ private byte tid;
+
+ private byte transitionTime;
+
+ private byte delay;
+
+ private boolean ack;
+
+ private boolean isComplete = false;
+
+ public MoveSetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ setTidPosition(2);
+ }
+
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.G_MOVE_SET.value : Opcode.G_MOVE_SET_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return
+ isComplete ?
+ ByteBuffer.allocate(5)
+ .order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) deltaLevel)
+ .put(tid).put(transitionTime).put(delay).array()
+ :
+ ByteBuffer.allocate(3)
+ .order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) deltaLevel)
+ .put(tid).array();
+ }
+
+ public void setDeltaLevel(int deltaLevel) {
+ this.deltaLevel = deltaLevel;
+ }
+
+ public void setTid(byte tid) {
+ this.tid = tid;
+ }
+
+ public void setTransitionTime(byte transitionTime) {
+ this.transitionTime = transitionTime;
+ }
+
+ public void setDelay(byte delay) {
+ this.delay = delay;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+
+ public void setComplete(boolean complete) {
+ isComplete = complete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/OnOffGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/OnOffGetMessage.java
new file mode 100644
index 00000000..8dea7f8b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/OnOffGetMessage.java
@@ -0,0 +1,58 @@
+/********************************************************************************************************
+ * @file OnOffGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.generic;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class OnOffGetMessage extends GenericMessage {
+
+
+ public static OnOffGetMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax) {
+ OnOffGetMessage message = new OnOffGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public OnOffGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.G_ONOFF_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.G_ONOFF_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return null;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/OnOffSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/OnOffSetMessage.java
new file mode 100644
index 00000000..fc0dc841
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/OnOffSetMessage.java
@@ -0,0 +1,133 @@
+/********************************************************************************************************
+ * @file OnOffSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.generic;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * include on off set and on off set no ack
+ * by {@link #ack}
+ * Created by kee on 2019/8/14.
+ */
+public class OnOffSetMessage extends GenericMessage {
+
+ public static final byte ON = 1;
+
+ public static final byte OFF = 0;
+
+ // 1: on, 0: off
+ private byte onOff;
+
+ private byte tid = 0;
+
+ private byte transitionTime = 0;
+
+ private byte delay = 0;
+
+ private boolean ack = false;
+
+ private boolean isComplete = false;
+
+ public static OnOffSetMessage getSimple(int address, int appKeyIndex, int onOff, boolean ack, int rspMax) {
+ OnOffSetMessage message = new OnOffSetMessage(address, appKeyIndex);
+ message.onOff = (byte) onOff;
+ message.ack = ack;
+ message.setTidPosition(1);
+ message.setResponseMax(rspMax);
+ // for test
+ // message.ack = false;
+// message.isComplete = true;
+ return message;
+ }
+
+ public OnOffSetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return ack ? Opcode.G_ONOFF_STATUS.value : super.getResponseOpcode();
+ }
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.G_ONOFF_SET.value : Opcode.G_ONOFF_SET_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ /*byte[] realParams = isComplete ?
+ new byte[]{
+ this.onOff,
+ this.tid,
+ this.transitionTime,
+ this.delay
+ }
+ :
+ new byte[]{
+ this.onOff,
+ this.tid
+ }
+ ;
+ byte[] params = new byte[378];
+ System.arraycopy(realParams, 0, params, 0, realParams.length);
+ return params;*/
+ return
+ isComplete ?
+ new byte[]{
+ this.onOff,
+ this.tid,
+ this.transitionTime,
+ this.delay
+ }
+ :
+ new byte[]{
+ this.onOff,
+ this.tid
+ }
+ ;
+ }
+
+ public void setOnOff(byte onOff) {
+ this.onOff = onOff;
+ }
+
+ public void setTid(byte tid) {
+ this.tid = tid;
+ }
+
+ public void setTransitionTime(byte transitionTime) {
+ this.transitionTime = transitionTime;
+ }
+
+ public void setDelay(byte delay) {
+ this.delay = delay;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+
+ public void setComplete(boolean complete) {
+ isComplete = complete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/OnOffStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/OnOffStatusMessage.java
new file mode 100644
index 00000000..a64fa3e3
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/generic/OnOffStatusMessage.java
@@ -0,0 +1,109 @@
+/********************************************************************************************************
+ * @file OnOffStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.generic;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class OnOffStatusMessage extends StatusMessage implements Parcelable {
+
+ private static final int DATA_LEN_COMPLETE = 3;
+
+ private byte presentOnOff;
+
+ /**
+ * The target value of the Generic OnOff state (optional).
+ */
+ private byte targetOnOff;
+
+ private byte remainingTime;
+
+ private boolean isComplete = false;
+
+ public OnOffStatusMessage() {
+ }
+
+
+ protected OnOffStatusMessage(Parcel in) {
+ presentOnOff = in.readByte();
+ targetOnOff = in.readByte();
+ remainingTime = in.readByte();
+ isComplete = in.readByte() != 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public OnOffStatusMessage createFromParcel(Parcel in) {
+ return new OnOffStatusMessage(in);
+ }
+
+ @Override
+ public OnOffStatusMessage[] newArray(int size) {
+ return new OnOffStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ this.presentOnOff = params[0];
+ if (params.length == DATA_LEN_COMPLETE) {
+ this.isComplete = true;
+ this.targetOnOff = params[1];
+ this.remainingTime = params[2];
+ }
+ }
+
+ public byte getPresentOnOff() {
+ return presentOnOff;
+ }
+
+ public byte getTargetOnOff() {
+ return targetOnOff;
+ }
+
+ public byte getRemainingTime() {
+ return remainingTime;
+ }
+
+ public boolean isComplete() {
+ return isComplete;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(presentOnOff);
+ dest.writeByte(targetOnOff);
+ dest.writeByte(remainingTime);
+ dest.writeByte((byte) (isComplete ? 1 : 0));
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlGetMessage.java
new file mode 100644
index 00000000..99115ee2
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlGetMessage.java
@@ -0,0 +1,51 @@
+/********************************************************************************************************
+ * @file CtlGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * Created by kee on 2019/9/19.
+ */
+
+public class CtlGetMessage extends LightingMessage {
+
+ public static CtlGetMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax) {
+ CtlGetMessage message = new CtlGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public CtlGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.LIGHT_CTL_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.LIGHT_CTL_STATUS.value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlSetMessage.java
new file mode 100644
index 00000000..c559c61c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlSetMessage.java
@@ -0,0 +1,130 @@
+/********************************************************************************************************
+ * @file CtlSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * include CLT set and CTL set no ack
+ * by {@link #ack}
+ * Created by kee on 2019/8/14.
+ */
+public class CtlSetMessage extends GenericMessage {
+
+ private int lightness;
+
+ private int temperature;
+
+ private int deltaUV;
+
+ // transaction id
+ private byte tid = 0;
+
+ private byte transitionTime = 0;
+
+ private byte delay = 0;
+
+ private boolean ack = false;
+
+ private boolean isComplete = false;
+
+ public static CtlSetMessage getSimple(int address, int appKeyIndex, int lightness, int temperature, int deltaUV, boolean ack, int rspMax) {
+ CtlSetMessage message = new CtlSetMessage(address, appKeyIndex);
+ message.lightness = lightness;
+ message.temperature = temperature;
+ message.deltaUV = deltaUV;
+ message.ack = ack;
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public CtlSetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ setTidPosition(6);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return ack ? Opcode.LIGHT_CTL_STATUS.value : super.getResponseOpcode();
+ }
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.LIGHT_CTL_SET.value : Opcode.LIGHT_CTL_SET_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return
+ isComplete ?
+ ByteBuffer.allocate(9).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) lightness)
+ .putShort((short) temperature)
+ .putShort((short) deltaUV)
+ .put(tid)
+ .put(transitionTime)
+ .put(delay).array()
+ :
+ ByteBuffer.allocate(7).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) lightness)
+ .putShort((short) temperature)
+ .putShort((short) deltaUV)
+ .put(tid).array()
+ ;
+ }
+
+ public void setLightness(int lightness) {
+ this.lightness = lightness;
+ }
+
+ public void setTemperature(int temperature) {
+ this.temperature = temperature;
+ }
+
+ public void setDeltaUV(int deltaUV) {
+ this.deltaUV = deltaUV;
+ }
+
+ public void setTid(byte tid) {
+ this.tid = tid;
+ }
+
+ public void setTransitionTime(byte transitionTime) {
+ this.transitionTime = transitionTime;
+ }
+
+ public void setDelay(byte delay) {
+ this.delay = delay;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+
+ public void setComplete(boolean complete) {
+ isComplete = complete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlStatusMessage.java
new file mode 100644
index 00000000..416ebec0
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlStatusMessage.java
@@ -0,0 +1,153 @@
+/********************************************************************************************************
+ * @file CtlStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class CtlStatusMessage extends StatusMessage implements Parcelable {
+
+ private static final int DATA_LEN_COMPLETE = 9;
+
+ private int presentLightness;
+
+ private int presentTemperature;
+
+ /**
+ * The target value of the Lightness/Temperature state (optional).
+ */
+ private int targetLightness;
+
+ private int targetTemperature;
+
+
+ private byte remainingTime;
+
+ /**
+ * tag of is complete message
+ */
+ private boolean isComplete = false;
+
+ public CtlStatusMessage() {
+ }
+
+ protected CtlStatusMessage(Parcel in) {
+ presentLightness = in.readInt();
+ presentTemperature = in.readInt();
+ targetLightness = in.readInt();
+ targetTemperature = in.readInt();
+ remainingTime = in.readByte();
+ isComplete = in.readByte() != 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public CtlStatusMessage createFromParcel(Parcel in) {
+ return new CtlStatusMessage(in);
+ }
+
+ @Override
+ public CtlStatusMessage[] newArray(int size) {
+ return new CtlStatusMessage[size];
+ }
+ };
+
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.presentLightness = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.presentTemperature = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ if (params.length == DATA_LEN_COMPLETE) {
+ this.isComplete = true;
+ this.targetLightness = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.targetTemperature = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.remainingTime = params[index];
+ }
+ }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(presentLightness);
+ dest.writeInt(presentTemperature);
+ dest.writeInt(targetLightness);
+ dest.writeInt(targetTemperature);
+ dest.writeByte(remainingTime);
+ dest.writeByte((byte) (isComplete ? 1 : 0));
+ }
+
+
+ public int getPresentLightness() {
+ return presentLightness;
+ }
+
+ public int getPresentTemperature() {
+ return presentTemperature;
+ }
+
+ public int getTargetLightness() {
+ return targetLightness;
+ }
+
+ public int getTargetTemperature() {
+ return targetTemperature;
+ }
+
+ public byte getRemainingTime() {
+ return remainingTime;
+ }
+
+ public boolean isComplete() {
+ return isComplete;
+ }
+
+ @Override
+ public String toString() {
+ return "CtlStatusMessage{" +
+ "presentLightness=" + presentLightness +
+ ", presentTemperature=" + presentTemperature +
+ ", targetLightness=" + targetLightness +
+ ", targetTemperature=" + targetTemperature +
+ ", remainingTime=" + remainingTime +
+ ", isComplete=" + isComplete +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlTemperatureGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlTemperatureGetMessage.java
new file mode 100644
index 00000000..740a725e
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlTemperatureGetMessage.java
@@ -0,0 +1,51 @@
+/********************************************************************************************************
+ * @file CtlTemperatureGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * Created by kee on 2019/9/19.
+ */
+
+public class CtlTemperatureGetMessage extends LightingMessage {
+
+ public static CtlTemperatureGetMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax) {
+ CtlTemperatureGetMessage message = new CtlTemperatureGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public CtlTemperatureGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.LIGHT_CTL_TEMP_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.LIGHT_CTL_TEMP_STATUS.value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlTemperatureSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlTemperatureSetMessage.java
new file mode 100644
index 00000000..cf8ec2de
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlTemperatureSetMessage.java
@@ -0,0 +1,120 @@
+/********************************************************************************************************
+ * @file CtlTemperatureSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * include CLT Temperature set and CTL Temperature set no ack
+ * by {@link #ack}
+ * Created by kee on 2019/8/14.
+ */
+public class CtlTemperatureSetMessage extends GenericMessage {
+
+ private int temperature;
+
+ private int deltaUV;
+
+ // transaction id
+ private byte tid = 0;
+
+ private byte transitionTime = 0;
+
+ private byte delay = 0;
+
+ private boolean ack = false;
+
+ private boolean isComplete = false;
+
+ public static CtlTemperatureSetMessage getSimple(int address, int appKeyIndex, int temperature, int deltaUV, boolean ack, int rspMax) {
+ CtlTemperatureSetMessage message = new CtlTemperatureSetMessage(address, appKeyIndex);
+ message.temperature = temperature;
+ message.deltaUV = deltaUV;
+ message.ack = ack;
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public CtlTemperatureSetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ setTidPosition(4);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return ack ? Opcode.LIGHT_CTL_TEMP_STATUS.value : super.getResponseOpcode();
+ }
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.LIGHT_CTL_TEMP_SET.value : Opcode.LIGHT_CTL_TEMP_SET_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return
+ isComplete ?
+ ByteBuffer.allocate(7).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) temperature)
+ .putShort((short) deltaUV)
+ .put(tid)
+ .put(transitionTime)
+ .put(delay).array()
+ :
+ ByteBuffer.allocate(5).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) temperature)
+ .putShort((short) deltaUV)
+ .put(tid).array();
+ }
+
+ public void setTemperature(int temperature) {
+ this.temperature = temperature;
+ }
+
+ public void setDeltaUV(int deltaUV) {
+ this.deltaUV = deltaUV;
+ }
+
+ public void setTid(byte tid) {
+ this.tid = tid;
+ }
+
+ public void setTransitionTime(byte transitionTime) {
+ this.transitionTime = transitionTime;
+ }
+
+ public void setDelay(byte delay) {
+ this.delay = delay;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+
+ public void setComplete(boolean complete) {
+ isComplete = complete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlTemperatureStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlTemperatureStatusMessage.java
new file mode 100644
index 00000000..159b966c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/CtlTemperatureStatusMessage.java
@@ -0,0 +1,137 @@
+/********************************************************************************************************
+ * @file CtlTemperatureStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class CtlTemperatureStatusMessage extends StatusMessage implements Parcelable {
+
+ private static final int DATA_LEN_COMPLETE = 9;
+
+
+ private int presentTemperature;
+
+ private int presentDeltaUV;
+
+ private int targetTemperature;
+
+ private int targetDeltaUV;
+
+
+ private byte remainingTime;
+
+ /**
+ * tag of is complete message
+ */
+ private boolean isComplete = false;
+
+ public CtlTemperatureStatusMessage() {
+ }
+
+ protected CtlTemperatureStatusMessage(Parcel in) {
+ presentTemperature = in.readInt();
+ presentDeltaUV = in.readInt();
+ targetTemperature = in.readInt();
+ targetDeltaUV = in.readInt();
+ remainingTime = in.readByte();
+ isComplete = in.readByte() != 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public CtlTemperatureStatusMessage createFromParcel(Parcel in) {
+ return new CtlTemperatureStatusMessage(in);
+ }
+
+ @Override
+ public CtlTemperatureStatusMessage[] newArray(int size) {
+ return new CtlTemperatureStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.presentTemperature = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.presentDeltaUV = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ if (params.length == DATA_LEN_COMPLETE) {
+ this.isComplete = true;
+ this.targetTemperature = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.targetDeltaUV = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.remainingTime = params[index];
+ }
+ }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(presentTemperature);
+ dest.writeInt(presentDeltaUV);
+ dest.writeInt(targetTemperature);
+ dest.writeInt(targetDeltaUV);
+ dest.writeByte(remainingTime);
+ dest.writeByte((byte) (isComplete ? 1 : 0));
+ }
+
+ public int getPresentTemperature() {
+ return presentTemperature;
+ }
+
+ public int getPresentDeltaUV() {
+ return presentDeltaUV;
+ }
+
+ public int getTargetTemperature() {
+ return targetTemperature;
+ }
+
+ public int getTargetDeltaUV() {
+ return targetDeltaUV;
+ }
+
+ public byte getRemainingTime() {
+ return remainingTime;
+ }
+
+ public boolean isComplete() {
+ return isComplete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslGetMessage.java
new file mode 100644
index 00000000..db29ffd5
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslGetMessage.java
@@ -0,0 +1,51 @@
+/********************************************************************************************************
+ * @file HslGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * Created by kee on 2019/9/19.
+ */
+
+public class HslGetMessage extends LightingMessage {
+
+ public static HslGetMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax) {
+ HslGetMessage message = new HslGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public HslGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.LIGHT_HSL_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.LIGHT_HSL_STATUS.value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslSetMessage.java
new file mode 100644
index 00000000..6fcc133e
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslSetMessage.java
@@ -0,0 +1,130 @@
+/********************************************************************************************************
+ * @file HslSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * include HSL set and HSL set no ack
+ * by {@link #ack}
+ * Created by kee on 2019/8/14.
+ */
+public class HslSetMessage extends GenericMessage {
+
+ private int lightness;
+
+ private int hue;
+
+ private int saturation;
+
+ // transaction id
+ private byte tid = 0;
+
+ private byte transitionTime = 0;
+
+ private byte delay = 0;
+
+ private boolean ack = false;
+
+ // if contains #transitionTime and #delay
+ private boolean isComplete = false;
+
+ public static HslSetMessage getSimple(int address, int appKeyIndex, int lightness, int hue, int saturation, boolean ack, int rspMax) {
+ HslSetMessage message = new HslSetMessage(address, appKeyIndex);
+ message.lightness = lightness;
+ message.hue = hue;
+ message.saturation = saturation;
+ message.ack = ack;
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public HslSetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ setTidPosition(6);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return ack ? Opcode.LIGHT_HSL_STATUS.value : super.getResponseOpcode();
+ }
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.LIGHT_HSL_SET.value : Opcode.LIGHT_HSL_SET_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return
+ isComplete ?
+ ByteBuffer.allocate(9).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) lightness)
+ .putShort((short) hue)
+ .putShort((short) saturation)
+ .put(tid)
+ .put(transitionTime)
+ .put(delay).array()
+ :
+ ByteBuffer.allocate(7).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) lightness)
+ .putShort((short) hue)
+ .putShort((short) saturation)
+ .put(tid).array();
+ }
+
+ public void setLightness(int lightness) {
+ this.lightness = lightness;
+ }
+
+ public void setHue(int hue) {
+ this.hue = hue;
+ }
+
+ public void setSaturation(int saturation) {
+ this.saturation = saturation;
+ }
+
+ public void setTid(byte tid) {
+ this.tid = tid;
+ }
+
+ public void setTransitionTime(byte transitionTime) {
+ this.transitionTime = transitionTime;
+ }
+
+ public void setDelay(byte delay) {
+ this.delay = delay;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+
+ public void setComplete(boolean complete) {
+ isComplete = complete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslStatusMessage.java
new file mode 100644
index 00000000..5d7ee72f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslStatusMessage.java
@@ -0,0 +1,126 @@
+/********************************************************************************************************
+ * @file HslStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * There is no target info in status message
+ *
+ * @see HslTargetStatusMessage
+ * Created by kee on 2019/8/20.
+ */
+public class HslStatusMessage extends StatusMessage implements Parcelable {
+
+ private static final int DATA_LEN_COMPLETE = 7;
+
+ private int lightness;
+
+ private int hue;
+
+ private int saturation;
+
+ private byte remainingTime;
+
+ /**
+ * tag of is complete message
+ */
+ private boolean isComplete = false;
+
+ public HslStatusMessage() {
+ }
+
+ protected HslStatusMessage(Parcel in) {
+ lightness = in.readInt();
+ hue = in.readInt();
+ saturation = in.readInt();
+ remainingTime = in.readByte();
+ isComplete = in.readByte() != 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(lightness);
+ dest.writeInt(hue);
+ dest.writeInt(saturation);
+ dest.writeByte(remainingTime);
+ dest.writeByte((byte) (isComplete ? 1 : 0));
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public HslStatusMessage createFromParcel(Parcel in) {
+ return new HslStatusMessage(in);
+ }
+
+ @Override
+ public HslStatusMessage[] newArray(int size) {
+ return new HslStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.lightness = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.hue = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.saturation = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ if (params.length == DATA_LEN_COMPLETE) {
+ this.isComplete = true;
+ this.remainingTime = params[index];
+ }
+ }
+
+ public int getLightness() {
+ return lightness;
+ }
+
+ public int getHue() {
+ return hue;
+ }
+
+ public int getSaturation() {
+ return saturation;
+ }
+
+ public byte getRemainingTime() {
+ return remainingTime;
+ }
+
+ public boolean isComplete() {
+ return isComplete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslTargetGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslTargetGetMessage.java
new file mode 100644
index 00000000..9c6dd81f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslTargetGetMessage.java
@@ -0,0 +1,51 @@
+/********************************************************************************************************
+ * @file HslTargetGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+/**
+ * Created by kee on 2019/9/19.
+ */
+
+public class HslTargetGetMessage extends LightingMessage {
+
+ public static HslTargetGetMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax) {
+ HslTargetGetMessage message = new HslTargetGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public HslTargetGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.LIGHT_HSL_TARGET_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.LIGHT_HSL_TARGET_STATUS.value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslTargetStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslTargetStatusMessage.java
new file mode 100644
index 00000000..71252cbb
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/HslTargetStatusMessage.java
@@ -0,0 +1,124 @@
+/********************************************************************************************************
+ * @file HslTargetStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * There is no target info in status message
+ * Created by kee on 2019/8/20.
+ */
+public class HslTargetStatusMessage extends StatusMessage implements Parcelable {
+
+ private static final int DATA_LEN_COMPLETE = 7;
+
+ private int targetLightness;
+
+ private int targetHue;
+
+ private int targetSaturation;
+
+ private byte remainingTime;
+
+ /**
+ * tag of is complete message
+ */
+ private boolean isComplete = false;
+
+ public HslTargetStatusMessage() {
+ }
+
+ protected HslTargetStatusMessage(Parcel in) {
+ targetLightness = in.readInt();
+ targetHue = in.readInt();
+ targetSaturation = in.readInt();
+ remainingTime = in.readByte();
+ isComplete = in.readByte() != 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public HslTargetStatusMessage createFromParcel(Parcel in) {
+ return new HslTargetStatusMessage(in);
+ }
+
+ @Override
+ public HslTargetStatusMessage[] newArray(int size) {
+ return new HslTargetStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.targetLightness = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.targetHue = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ this.targetSaturation = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ if (params.length == DATA_LEN_COMPLETE) {
+ this.isComplete = true;
+ this.remainingTime = params[index];
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(targetLightness);
+ dest.writeInt(targetHue);
+ dest.writeInt(targetSaturation);
+ dest.writeByte(remainingTime);
+ dest.writeByte((byte) (isComplete ? 1 : 0));
+ }
+
+ public int getTargetLightness() {
+ return targetLightness;
+ }
+
+ public int getTargetHue() {
+ return targetHue;
+ }
+
+ public int getTargetSaturation() {
+ return targetSaturation;
+ }
+
+ public byte getRemainingTime() {
+ return remainingTime;
+ }
+
+ public boolean isComplete() {
+ return isComplete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightingMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightingMessage.java
new file mode 100644
index 00000000..aff8f1ce
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightingMessage.java
@@ -0,0 +1,37 @@
+/********************************************************************************************************
+ * @file LightingMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.networking.AccessType;
+
+
+public abstract class LightingMessage extends MeshMessage {
+
+ public LightingMessage(int destinationAddress, int appKeyIndex) {
+ this.destinationAddress = destinationAddress;
+ this.appKeyIndex = appKeyIndex;
+ this.accessType = AccessType.APPLICATION;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightnessGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightnessGetMessage.java
new file mode 100644
index 00000000..f7143087
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightnessGetMessage.java
@@ -0,0 +1,52 @@
+/********************************************************************************************************
+ * @file LightnessGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.OnOffGetMessage;
+
+/**
+ * Created by kee on 2019/9/19.
+ */
+
+public class LightnessGetMessage extends LightingMessage {
+
+ public static LightnessGetMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax) {
+ LightnessGetMessage message = new LightnessGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public LightnessGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.LIGHTNESS_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.LIGHTNESS_STATUS.value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightnessSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightnessSetMessage.java
new file mode 100644
index 00000000..a5d8274e
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightnessSetMessage.java
@@ -0,0 +1,112 @@
+/********************************************************************************************************
+ * @file LightnessSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+/**
+ * include lightness set and lightness set no ack
+ * by {@link #ack}
+ * Created by kee on 2019/8/14.
+ */
+public class LightnessSetMessage extends GenericMessage {
+ // 2 bytes
+ private int lightness;
+
+ // transaction id
+ private byte tid = 0;
+
+ private byte transitionTime = 0;
+
+ private byte delay = 0;
+
+ private boolean ack = false;
+
+ private boolean isComplete = false;
+
+ public static LightnessSetMessage getSimple(int address, int appKeyIndex, int lightness, boolean ack, int rspMax) {
+ LightnessSetMessage message = new LightnessSetMessage(address, appKeyIndex);
+ message.lightness = lightness;
+ message.ack = ack;
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public LightnessSetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ setTidPosition(2);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return ack ? Opcode.LIGHTNESS_STATUS.value : super.getResponseOpcode();
+ }
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.LIGHTNESS_SET.value : Opcode.LIGHTNESS_SET_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return
+ isComplete ?
+ new byte[]{
+ (byte) this.lightness,
+ (byte) (this.lightness >> 8),
+ this.tid,
+ this.transitionTime,
+ this.delay
+ }
+ :
+ new byte[]{
+ (byte) this.lightness,
+ (byte) (this.lightness >> 8),
+ this.tid
+ };
+ }
+
+ public void setLightness(int lightness) {
+ this.lightness = lightness;
+ }
+
+ public void setTid(byte tid) {
+ this.tid = tid;
+ }
+
+ public void setTransitionTime(byte transitionTime) {
+ this.transitionTime = transitionTime;
+ }
+
+ public void setDelay(byte delay) {
+ this.delay = delay;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+
+ public void setComplete(boolean complete) {
+ isComplete = complete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightnessStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightnessStatusMessage.java
new file mode 100644
index 00000000..78c1e3cf
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/lighting/LightnessStatusMessage.java
@@ -0,0 +1,114 @@
+/********************************************************************************************************
+ * @file LightnessStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.lighting;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class LightnessStatusMessage extends StatusMessage implements Parcelable {
+
+ private static final int DATA_LEN_COMPLETE = 5;
+
+ private int presentLightness;
+
+ /**
+ * The target value of the Lightness state (optional).
+ */
+ private int targetLightness;
+
+ private byte remainingTime;
+
+ /**
+ * tag of is complete message
+ */
+ private boolean isComplete = false;
+
+ public LightnessStatusMessage() {
+ }
+
+ protected LightnessStatusMessage(Parcel in) {
+ presentLightness = in.readInt();
+ targetLightness = in.readInt();
+ remainingTime = in.readByte();
+ isComplete = in.readByte() != 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public LightnessStatusMessage createFromParcel(Parcel in) {
+ return new LightnessStatusMessage(in);
+ }
+
+ @Override
+ public LightnessStatusMessage[] newArray(int size) {
+ return new LightnessStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ this.presentLightness = MeshUtils.bytes2Integer(params, 0, 2, ByteOrder.LITTLE_ENDIAN);
+ if (params.length == DATA_LEN_COMPLETE) {
+ this.isComplete = true;
+ this.targetLightness = MeshUtils.bytes2Integer(params, 2, 2, ByteOrder.LITTLE_ENDIAN);
+ this.remainingTime = params[4];
+ }
+ }
+
+ public int getPresentLightness() {
+ return presentLightness;
+ }
+
+ public int getTargetLightness() {
+ return targetLightness;
+ }
+
+ public byte getRemainingTime() {
+ return remainingTime;
+ }
+
+ public boolean isComplete() {
+ return isComplete;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(presentLightness);
+ dest.writeInt(targetLightness);
+ dest.writeByte(remainingTime);
+ dest.writeByte((byte) (isComplete ? 1 : 0));
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/LinkCloseMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/LinkCloseMessage.java
new file mode 100644
index 00000000..328311ad
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/LinkCloseMessage.java
@@ -0,0 +1,71 @@
+/********************************************************************************************************
+ * @file LinkCloseMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+
+public class LinkCloseMessage extends RemoteProvisionMessage {
+
+
+ public static final byte REASON_SUCCESS = 0x00;
+
+ public static final byte REASON_PROHIBITED = 0x01;
+
+ public static final byte REASON_FAIL = 0x02;
+
+ /**
+ * 1 byte
+ */
+ private byte reason;
+
+ public static LinkCloseMessage getSimple(int destinationAddress, int rspMax, byte reason) {
+ LinkCloseMessage message = new LinkCloseMessage(destinationAddress);
+ message.setResponseMax(rspMax);
+ message.reason = reason;
+ return message;
+ }
+
+ public LinkCloseMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.REMOTE_PROV_LINK_CLOSE.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.REMOTE_PROV_LINK_STS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return new byte[]{reason};
+ }
+
+ public void setReason(byte reason) {
+ this.reason = reason;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/LinkOpenMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/LinkOpenMessage.java
new file mode 100644
index 00000000..0bf5fb87
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/LinkOpenMessage.java
@@ -0,0 +1,64 @@
+/********************************************************************************************************
+ * @file LinkOpenMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+
+public class LinkOpenMessage extends RemoteProvisionMessage {
+
+ /**
+ * 16 bytes
+ */
+ private byte[] uuid;
+
+ public static LinkOpenMessage getSimple(int destinationAddress, int rspMax, byte[] uuid) {
+ LinkOpenMessage message = new LinkOpenMessage(destinationAddress);
+ message.setResponseMax(rspMax);
+ message.uuid = uuid;
+ return message;
+ }
+
+ public LinkOpenMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.REMOTE_PROV_LINK_OPEN.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.REMOTE_PROV_LINK_STS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return uuid;
+ }
+
+ public void setUuid(byte[] uuid) {
+ this.uuid = uuid;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/LinkStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/LinkStatusMessage.java
new file mode 100644
index 00000000..13744d83
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/LinkStatusMessage.java
@@ -0,0 +1,94 @@
+/********************************************************************************************************
+ * @file LinkStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class LinkStatusMessage extends StatusMessage implements Parcelable {
+
+ private byte status;
+
+ private byte rpState;
+
+
+ public LinkStatusMessage() {
+ }
+
+ protected LinkStatusMessage(Parcel in) {
+ status = in.readByte();
+ rpState = in.readByte();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public LinkStatusMessage createFromParcel(Parcel in) {
+ return new LinkStatusMessage(in);
+ }
+
+ @Override
+ public LinkStatusMessage[] newArray(int size) {
+ return new LinkStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.status = params[index++];
+ this.rpState = params[index++];
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(status);
+ dest.writeByte(rpState);
+ }
+
+ public byte getRpState() {
+ return rpState;
+ }
+
+ public byte getStatus() {
+ return status;
+ }
+
+
+ @Override
+ public String toString() {
+ return "LinkStatusMessage{" +
+ "status=" + status +
+ ", rpState=" + rpState +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ProvisioningPDUOutboundReportMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ProvisioningPDUOutboundReportMessage.java
new file mode 100644
index 00000000..4707b19d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ProvisioningPDUOutboundReportMessage.java
@@ -0,0 +1,76 @@
+/********************************************************************************************************
+ * @file ProvisioningPDUOutboundReportMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class ProvisioningPDUOutboundReportMessage extends StatusMessage implements Parcelable {
+
+ private byte outboundPDUNumber;
+
+
+ public ProvisioningPDUOutboundReportMessage() {
+ }
+
+
+ protected ProvisioningPDUOutboundReportMessage(Parcel in) {
+ outboundPDUNumber = in.readByte();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ProvisioningPDUOutboundReportMessage createFromParcel(Parcel in) {
+ return new ProvisioningPDUOutboundReportMessage(in);
+ }
+
+ @Override
+ public ProvisioningPDUOutboundReportMessage[] newArray(int size) {
+ return new ProvisioningPDUOutboundReportMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ this.outboundPDUNumber = params[0];
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(outboundPDUNumber);
+ }
+
+ public byte getOutboundPDUNumber() {
+ return outboundPDUNumber;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ProvisioningPDUReportMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ProvisioningPDUReportMessage.java
new file mode 100644
index 00000000..ccdaf5ee
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ProvisioningPDUReportMessage.java
@@ -0,0 +1,98 @@
+/********************************************************************************************************
+ * @file ProvisioningPDUReportMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+import com.telink.ble.mesh.util.Arrays;
+
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class ProvisioningPDUReportMessage extends StatusMessage implements Parcelable {
+
+ private byte inboundPDUNumber;
+
+ private byte[] provisioningPDU;
+
+ public ProvisioningPDUReportMessage() {
+ }
+
+
+ protected ProvisioningPDUReportMessage(Parcel in) {
+ inboundPDUNumber = in.readByte();
+ provisioningPDU = in.createByteArray();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ProvisioningPDUReportMessage createFromParcel(Parcel in) {
+ return new ProvisioningPDUReportMessage(in);
+ }
+
+ @Override
+ public ProvisioningPDUReportMessage[] newArray(int size) {
+ return new ProvisioningPDUReportMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ this.inboundPDUNumber = params[0];
+ if (params.length > 1) {
+ int pduLen = params.length - 1;
+ provisioningPDU = new byte[pduLen];
+ System.arraycopy(params, 1, this.provisioningPDU, 0, pduLen);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(inboundPDUNumber);
+ dest.writeByteArray(provisioningPDU);
+ }
+
+ public byte getInboundPDUNumber() {
+ return inboundPDUNumber;
+ }
+
+ public byte[] getProvisioningPDU() {
+ return provisioningPDU;
+ }
+
+ @Override
+ public String toString() {
+ return "ProvisioningPDUReportMessage{" +
+ "inboundPDUNumber=" + inboundPDUNumber +
+ ", provisioningPDU=" + Arrays.bytesToHexString(provisioningPDU) +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ProvisioningPduSendMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ProvisioningPduSendMessage.java
new file mode 100644
index 00000000..e462e7b9
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ProvisioningPduSendMessage.java
@@ -0,0 +1,81 @@
+/********************************************************************************************************
+ * @file ProvisioningPduSendMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.firmwareupdate.UpdatingMessage;
+
+
+import java.nio.ByteBuffer;
+
+public class ProvisioningPduSendMessage extends RemoteProvisionMessage {
+
+ private byte outboundPDUNumber;
+
+ /**
+ * 16 bytes
+ */
+ private byte[] provisioningPDU;
+
+ /**
+ * @param destinationAddress server address
+ */
+ public static ProvisioningPduSendMessage getSimple(int destinationAddress, int rspMax,
+ byte outboundPDUNumber,
+ byte[] provisioningPDU) {
+ ProvisioningPduSendMessage message = new ProvisioningPduSendMessage(destinationAddress);
+ message.setResponseMax(rspMax);
+ message.outboundPDUNumber = outboundPDUNumber;
+ message.provisioningPDU = provisioningPDU;
+ return message;
+ }
+
+ public ProvisioningPduSendMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.REMOTE_PROV_PDU_SEND.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return OPCODE_INVALID;
+// return Opcode.REMOTE_PROV_PDU_OUTBOUND_REPORT.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return ByteBuffer.allocate(1 + provisioningPDU.length)
+ .put(outboundPDUNumber)
+ .put(provisioningPDU).array();
+ }
+
+ public void setOutboundPDUNumber(byte outboundPDUNumber) {
+ this.outboundPDUNumber = outboundPDUNumber;
+ }
+
+ public void setProvisioningPDU(byte[] provisioningPDU) {
+ this.provisioningPDU = provisioningPDU;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/RPStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/RPStatusMessage.java
new file mode 100644
index 00000000..7dc5e5cf
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/RPStatusMessage.java
@@ -0,0 +1,62 @@
+/********************************************************************************************************
+ * @file RPStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public abstract class RPStatusMessage extends StatusMessage {
+
+ /**
+ * defines status codes for Remote Provisioning Server messages that contain a status code.
+ */
+
+ public static final byte CODE_SUCCESS = 0x00;
+
+ public static final byte CODE_SCANNING_CANNOT_START = 0x01;
+
+ public static final byte CODE_INVALID_STATE = 0x02;
+
+ public static final byte CODE_LIMITED_RESOURCES = 0x03;
+
+ public static final byte CODE_LINK_CANNOT_OPEN = 0x04;
+
+ public static final byte CODE_LINK_OPEN_FAILED = 0x05;
+
+ public static final byte CODE_LINK_CLOSED_BY_DEVICE = 0x06;
+
+ public static final byte CODE_LINK_CLOSED_BY_SERVER = 0x07;
+
+ public static final byte CODE_LINK_CLOSED_BY_CLIENT = 0x08;
+
+ public static final byte CODE_LINK_CLOSED_AS_CANNOT_RECEIVE_PDU = 0x09;
+
+ public static final byte CODE_LINK_CLOSED_AS_CANNOT_SEND_PDU = 0x0A;
+
+ public static final byte CODE_LINK_CLOSED_AS_CANNOT_DELIVER_PDU_REPORT = 0x0B;
+
+ public static final byte CODE_LINK_CLOSED_AS_CANNOT_DELIVER_PDU_OUTBOUND_REPORT = 0x0C;
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/RemoteProvisionMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/RemoteProvisionMessage.java
new file mode 100644
index 00000000..7d96ef14
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/RemoteProvisionMessage.java
@@ -0,0 +1,32 @@
+/********************************************************************************************************
+ * @file RemoteProvisionMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import com.telink.ble.mesh.core.message.config.ConfigMessage;
+
+import androidx.annotation.IntRange;
+
+public class RemoteProvisionMessage extends ConfigMessage {
+ public RemoteProvisionMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ScanReportStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ScanReportStatusMessage.java
new file mode 100644
index 00000000..94a33f6e
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ScanReportStatusMessage.java
@@ -0,0 +1,100 @@
+/********************************************************************************************************
+ * @file ScanReportStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class ScanReportStatusMessage extends StatusMessage implements Parcelable {
+
+ private byte rssi;
+
+ // 16 bytes
+ private byte[] uuid;
+
+ // 2 bytes
+ private int oob;
+
+ public ScanReportStatusMessage() {
+ }
+
+ protected ScanReportStatusMessage(Parcel in) {
+ rssi = in.readByte();
+ uuid = in.createByteArray();
+ oob = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ScanReportStatusMessage createFromParcel(Parcel in) {
+ return new ScanReportStatusMessage(in);
+ }
+
+ @Override
+ public ScanReportStatusMessage[] newArray(int size) {
+ return new ScanReportStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.rssi = params[index++];
+ this.uuid = new byte[16];
+ System.arraycopy(params, index, this.uuid, 0, this.uuid.length);
+ index += this.uuid.length;
+ this.oob = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(rssi);
+ dest.writeByteArray(uuid);
+ dest.writeInt(oob);
+ }
+
+ public byte getRssi() {
+ return rssi;
+ }
+
+ public byte[] getUuid() {
+ return uuid;
+ }
+
+ public int getOob() {
+ return oob;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ScanStartMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ScanStartMessage.java
new file mode 100644
index 00000000..fd260aab
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ScanStartMessage.java
@@ -0,0 +1,91 @@
+/********************************************************************************************************
+ * @file ScanStartMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import com.telink.ble.mesh.core.message.Opcode;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class ScanStartMessage extends RemoteProvisionMessage {
+
+ /**
+ * 1 bytes
+ */
+ private byte scannedItemsLimit;
+
+ /**
+ * 1 bytes
+ */
+ private byte timeout;
+
+ /**
+ * Device UUID (Optional)
+ */
+ private byte[] uuid;
+
+ public static ScanStartMessage getSimple(int destinationAddress, int rspMax, byte scannedItemsLimit, byte timeout) {
+ ScanStartMessage message = new ScanStartMessage(destinationAddress);
+ message.setResponseMax(rspMax);
+ message.scannedItemsLimit = scannedItemsLimit;
+ message.timeout = timeout;
+ return message;
+ }
+
+ public ScanStartMessage(int destinationAddress) {
+ super(destinationAddress);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.REMOTE_PROV_SCAN_START.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+// return Opcode.REMOTE_PROV_SCAN_STS.value;
+ return super.getResponseOpcode();
+ }
+
+ @Override
+ public byte[] getParams() {
+ int len = uuid == null ? 2 : 18;
+ ByteBuffer bf = ByteBuffer.allocate(len).order(ByteOrder.LITTLE_ENDIAN)
+ .put(scannedItemsLimit).put(timeout);
+ if (uuid != null) {
+ bf.put(uuid);
+ }
+ return bf.array();
+ }
+
+ public void setScannedItemsLimit(byte scannedItemsLimit) {
+ this.scannedItemsLimit = scannedItemsLimit;
+ }
+
+ public void setTimeout(byte timeout) {
+ this.timeout = timeout;
+ }
+
+ public void setUuid(byte[] uuid) {
+ this.uuid = uuid;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ScanStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ScanStatusMessage.java
new file mode 100644
index 00000000..f017f9c8
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/ScanStatusMessage.java
@@ -0,0 +1,103 @@
+/********************************************************************************************************
+ * @file ScanStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.rp;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class ScanStatusMessage extends StatusMessage implements Parcelable {
+
+ private byte status;
+
+ private byte rpScanningState;
+
+ private byte scannedItemsLimit;
+
+ private byte timeout;
+
+ public ScanStatusMessage() {
+ }
+
+
+ protected ScanStatusMessage(Parcel in) {
+ status = in.readByte();
+ rpScanningState = in.readByte();
+ scannedItemsLimit = in.readByte();
+ timeout = in.readByte();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(status);
+ dest.writeByte(rpScanningState);
+ dest.writeByte(scannedItemsLimit);
+ dest.writeByte(timeout);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ScanStatusMessage createFromParcel(Parcel in) {
+ return new ScanStatusMessage(in);
+ }
+
+ @Override
+ public ScanStatusMessage[] newArray(int size) {
+ return new ScanStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.status = params[index++];
+ this.rpScanningState = params[index++];
+ this.scannedItemsLimit = params[index++];
+ this.timeout = params[index];
+ }
+
+ public byte getStatus() {
+ return status;
+ }
+
+ public byte getRpScanningState() {
+ return rpScanningState;
+ }
+
+ public byte getScannedItemsLimit() {
+ return scannedItemsLimit;
+ }
+
+ public byte getTimeout() {
+ return timeout;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/package-info.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/package-info.java
new file mode 100644
index 00000000..41dcd31f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/rp/package-info.java
@@ -0,0 +1,23 @@
+/********************************************************************************************************
+ * @file package-info.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+//remote provisioning messages
+package com.telink.ble.mesh.core.message.rp;
\ No newline at end of file
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneDeleteMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneDeleteMessage.java
new file mode 100644
index 00000000..2d0c7970
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneDeleteMessage.java
@@ -0,0 +1,72 @@
+/********************************************************************************************************
+ * @file SceneDeleteMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scene;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+/**
+ * scene store
+ * Created by kee on 2019/8/14.
+ */
+public class SceneDeleteMessage extends GenericMessage {
+
+ // scene id
+ private int sceneNumber;
+
+ private boolean ack;
+
+ public static SceneDeleteMessage getSimple(int address, int appKeyIndex, int sceneNumber, boolean ack, int rspMax) {
+ SceneDeleteMessage message = new SceneDeleteMessage(address, appKeyIndex);
+ message.sceneNumber = sceneNumber;
+ message.ack = ack;
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public SceneDeleteMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return ack ? Opcode.SCENE_REG_STATUS.value : super.getResponseOpcode();
+ }
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.SCENE_DEL.value : Opcode.SCENE_DEL_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return new byte[]{(byte) sceneNumber, (byte) (sceneNumber >> 8)};
+ }
+
+ public void setSceneNumber(int sceneNumber) {
+ this.sceneNumber = sceneNumber;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneGetMessage.java
new file mode 100644
index 00000000..e9ae9002
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneGetMessage.java
@@ -0,0 +1,52 @@
+/********************************************************************************************************
+ * @file SceneGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scene;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.lighting.LightingMessage;
+
+/**
+ * Created by kee on 2019/9/19.
+ */
+
+public class SceneGetMessage extends LightingMessage {
+
+ public static SceneGetMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax) {
+ SceneGetMessage message = new SceneGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public SceneGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.SCENE_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.SCENE_STATUS.value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneRecallMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneRecallMessage.java
new file mode 100644
index 00000000..7ab60a10
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneRecallMessage.java
@@ -0,0 +1,111 @@
+/********************************************************************************************************
+ * @file SceneRecallMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scene;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * SCENE recall and XX no ack
+ * by {@link #ack}
+ * Created by kee on 2019/8/14.
+ */
+public class SceneRecallMessage extends GenericMessage {
+
+ private int sceneNumber;
+
+ // transition id
+ private byte tid = 0;
+
+ private byte transitionTime = 0;
+
+ private byte delay = 0;
+
+ private boolean ack = false;
+
+ private boolean isComplete = false;
+
+ public static SceneRecallMessage getSimple(int address, int appKeyIndex, int sceneNumber, boolean ack, int rspMax) {
+ SceneRecallMessage message = new SceneRecallMessage(address, appKeyIndex);
+ message.sceneNumber = sceneNumber;
+ message.ack = ack;
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public SceneRecallMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ setTidPosition(2);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return ack ? Opcode.SCENE_STATUS.value : super.getResponseOpcode();
+ }
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.SCENE_RECALL.value : Opcode.SCENE_RECALL_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return
+ isComplete ?
+ ByteBuffer.allocate(5).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) sceneNumber)
+ .put(tid)
+ .put(transitionTime)
+ .put(delay).array()
+ :
+ ByteBuffer.allocate(3).order(ByteOrder.LITTLE_ENDIAN)
+ .putShort((short) sceneNumber)
+ .put(tid).array();
+ }
+
+ public void setSceneNumber(int sceneNumber) {
+ this.sceneNumber = sceneNumber;
+ }
+
+ public void setTid(byte tid) {
+ this.tid = tid;
+ }
+
+ public void setTransitionTime(byte transitionTime) {
+ this.transitionTime = transitionTime;
+ }
+
+ public void setDelay(byte delay) {
+ this.delay = delay;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+
+ public void setComplete(boolean complete) {
+ isComplete = complete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneRegisterGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneRegisterGetMessage.java
new file mode 100644
index 00000000..3bd0564c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneRegisterGetMessage.java
@@ -0,0 +1,52 @@
+/********************************************************************************************************
+ * @file SceneRegisterGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scene;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.lighting.LightingMessage;
+
+/**
+ * Created by kee on 2019/9/19.
+ */
+
+public class SceneRegisterGetMessage extends LightingMessage {
+
+ public static SceneRegisterGetMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax) {
+ SceneRegisterGetMessage message = new SceneRegisterGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public SceneRegisterGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.SCENE_REG_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.SCENE_REG_STATUS.value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneRegisterStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneRegisterStatusMessage.java
new file mode 100644
index 00000000..b7efca23
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneRegisterStatusMessage.java
@@ -0,0 +1,104 @@
+/********************************************************************************************************
+ * @file SceneRegisterStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scene;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class SceneRegisterStatusMessage extends StatusMessage implements Parcelable {
+
+ private byte statusCode;
+
+ private int currentScene;
+
+ private int[] scenes;
+
+ public SceneRegisterStatusMessage() {
+ }
+
+ protected SceneRegisterStatusMessage(Parcel in) {
+ statusCode = in.readByte();
+ currentScene = in.readInt();
+ scenes = in.createIntArray();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public SceneRegisterStatusMessage createFromParcel(Parcel in) {
+ return new SceneRegisterStatusMessage(in);
+ }
+
+ @Override
+ public SceneRegisterStatusMessage[] newArray(int size) {
+ return new SceneRegisterStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.statusCode = params[index++];
+ this.currentScene = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ int rst = params.length - index;
+ if (rst > 0 && rst % 2 == 0) {
+ scenes = new int[rst / 2];
+ for (int i = 0; i < scenes.length; i++) {
+ scenes[i] = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ }
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(statusCode);
+ dest.writeInt(currentScene);
+ dest.writeIntArray(scenes);
+ }
+
+ public byte getStatusCode() {
+ return statusCode;
+ }
+
+ public int getCurrentScene() {
+ return currentScene;
+ }
+
+ public int[] getScenes() {
+ return scenes;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneStatusMessage.java
new file mode 100644
index 00000000..6d8c8572
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneStatusMessage.java
@@ -0,0 +1,124 @@
+/********************************************************************************************************
+ * @file SceneStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scene;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class SceneStatusMessage extends StatusMessage implements Parcelable {
+
+ private static final int DATA_LEN_COMPLETE = 6;
+
+ private byte statusCode;
+
+ private int currentScene;
+
+ private int targetScene;
+
+ private byte remainingTime;
+
+ /**
+ * tag of is complete message
+ */
+ private boolean isComplete = false;
+
+ public SceneStatusMessage() {
+ }
+
+ protected SceneStatusMessage(Parcel in) {
+ statusCode = in.readByte();
+ currentScene = in.readInt();
+ targetScene = in.readInt();
+ remainingTime = in.readByte();
+ isComplete = in.readByte() != 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public SceneStatusMessage createFromParcel(Parcel in) {
+ return new SceneStatusMessage(in);
+ }
+
+ @Override
+ public SceneStatusMessage[] newArray(int size) {
+ return new SceneStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.statusCode = params[index++];
+ this.currentScene = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ if (params.length == DATA_LEN_COMPLETE) {
+ this.isComplete = true;
+ this.targetScene = MeshUtils.bytes2Integer(params, index, 2, ByteOrder.LITTLE_ENDIAN);
+ index += 2;
+ remainingTime = params[index];
+ }
+ }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(statusCode);
+ dest.writeInt(currentScene);
+ dest.writeInt(targetScene);
+ dest.writeByte(remainingTime);
+ dest.writeByte((byte) (isComplete ? 1 : 0));
+ }
+
+ public byte getStatusCode() {
+ return statusCode;
+ }
+
+ public int getCurrentScene() {
+ return currentScene;
+ }
+
+ public int getTargetScene() {
+ return targetScene;
+ }
+
+ public byte getRemainingTime() {
+ return remainingTime;
+ }
+
+ public boolean isComplete() {
+ return isComplete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneStoreMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneStoreMessage.java
new file mode 100644
index 00000000..12e69ef2
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scene/SceneStoreMessage.java
@@ -0,0 +1,72 @@
+/********************************************************************************************************
+ * @file SceneStoreMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scene;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+/**
+ * scene store
+ * Created by kee on 2019/8/14.
+ */
+public class SceneStoreMessage extends GenericMessage {
+
+ // scene id
+ private int sceneNumber;
+
+ private boolean ack;
+
+ public static SceneStoreMessage getSimple(int address, int appKeyIndex, int sceneNumber, boolean ack, int rspMax) {
+ SceneStoreMessage message = new SceneStoreMessage(address, appKeyIndex);
+ message.sceneNumber = sceneNumber;
+ message.ack = ack;
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public SceneStoreMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return ack ? Opcode.SCENE_REG_STATUS.value : super.getResponseOpcode();
+ }
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.SCENE_STORE.value : Opcode.SCENE_STORE_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return new byte[]{(byte) sceneNumber, (byte) (sceneNumber >> 8)};
+ }
+
+ public void setSceneNumber(int sceneNumber) {
+ this.sceneNumber = sceneNumber;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerActionGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerActionGetMessage.java
new file mode 100644
index 00000000..f7dd01a5
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerActionGetMessage.java
@@ -0,0 +1,66 @@
+/********************************************************************************************************
+ * @file SchedulerActionGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scheduler;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+/**
+ * scheduler action get
+ * Created by kee on 2019/8/14.
+ */
+public class SchedulerActionGetMessage extends GenericMessage {
+
+ // scene id
+ private byte index;
+
+
+ public static SchedulerActionGetMessage getSimple(int address, int appKeyIndex, byte schedulerIndex, int rspMax) {
+ SchedulerActionGetMessage message = new SchedulerActionGetMessage(address, appKeyIndex);
+ message.index = schedulerIndex;
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public SchedulerActionGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.SCHD_ACTION_STATUS.value;
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.SCHD_ACTION_GET.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return new byte[]{index};
+ }
+
+ public void setIndex(byte index) {
+ this.index = index;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerActionSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerActionSetMessage.java
new file mode 100644
index 00000000..d8be40b4
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerActionSetMessage.java
@@ -0,0 +1,73 @@
+/********************************************************************************************************
+ * @file SchedulerActionSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scheduler;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+import com.telink.ble.mesh.entity.Scheduler;
+
+/**
+ * include Scheduler Action set and Scheduler Action set no ack
+ * by {@link #ack}
+ * Created by kee on 2019/8/14.
+ */
+public class SchedulerActionSetMessage extends GenericMessage {
+
+ private Scheduler scheduler;
+
+ private boolean ack = false;
+
+ public static SchedulerActionSetMessage getSimple(int address, int appKeyIndex, Scheduler scheduler, boolean ack, int rspMax) {
+ SchedulerActionSetMessage message = new SchedulerActionSetMessage(address, appKeyIndex);
+ message.scheduler = scheduler;
+ message.ack = ack;
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public SchedulerActionSetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return ack ? Opcode.SCHD_ACTION_STATUS.value : super.getResponseOpcode();
+ }
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.SCHD_ACTION_SET.value : Opcode.SCHD_ACTION_SET_NOACK.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ return scheduler.toBytes();
+ }
+
+ public void setScheduler(Scheduler scheduler) {
+ this.scheduler = scheduler;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerActionStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerActionStatusMessage.java
new file mode 100644
index 00000000..8f155352
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerActionStatusMessage.java
@@ -0,0 +1,75 @@
+/********************************************************************************************************
+ * @file SchedulerActionStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scheduler;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.StatusMessage;
+import com.telink.ble.mesh.entity.Scheduler;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class SchedulerActionStatusMessage extends StatusMessage implements Parcelable {
+
+ private Scheduler scheduler;
+
+ public SchedulerActionStatusMessage() {
+ }
+
+ protected SchedulerActionStatusMessage(Parcel in) {
+ scheduler = in.readParcelable(Scheduler.class.getClassLoader());
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public SchedulerActionStatusMessage createFromParcel(Parcel in) {
+ return new SchedulerActionStatusMessage(in);
+ }
+
+ @Override
+ public SchedulerActionStatusMessage[] newArray(int size) {
+ return new SchedulerActionStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ this.scheduler = Scheduler.fromBytes(params);
+ }
+
+ public Scheduler getScheduler() {
+ return scheduler;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(scheduler, flags);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerGetMessage.java
new file mode 100644
index 00000000..7d50d881
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerGetMessage.java
@@ -0,0 +1,52 @@
+/********************************************************************************************************
+ * @file SchedulerGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scheduler;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.lighting.LightingMessage;
+
+/**
+ * Created by kee on 2019/9/19.
+ */
+
+public class SchedulerGetMessage extends LightingMessage {
+
+ public static SchedulerGetMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax) {
+ SchedulerGetMessage message = new SchedulerGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public SchedulerGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.SCHD_GET.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.SCHD_STATUS.value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerStatusMessage.java
new file mode 100644
index 00000000..40f70128
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/scheduler/SchedulerStatusMessage.java
@@ -0,0 +1,81 @@
+/********************************************************************************************************
+ * @file SchedulerStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.scheduler;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class SchedulerStatusMessage extends StatusMessage implements Parcelable {
+
+
+ /**
+ * Bit field indicating defined Actions in the Schedule Register
+ */
+ private int schedules;
+
+ public SchedulerStatusMessage() {
+ }
+
+ protected SchedulerStatusMessage(Parcel in) {
+ schedules = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public SchedulerStatusMessage createFromParcel(Parcel in) {
+ return new SchedulerStatusMessage(in);
+ }
+
+ @Override
+ public SchedulerStatusMessage[] newArray(int size) {
+ return new SchedulerStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ this.schedules = MeshUtils.bytes2Integer(params, ByteOrder.LITTLE_ENDIAN);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(schedules);
+ }
+
+ public long getSchedules() {
+ return schedules;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeGetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeGetMessage.java
new file mode 100644
index 00000000..271e646b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeGetMessage.java
@@ -0,0 +1,52 @@
+/********************************************************************************************************
+ * @file TimeGetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.time;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.lighting.LightingMessage;
+
+/**
+ * Created by kee on 2019/9/19.
+ */
+
+public class TimeGetMessage extends LightingMessage {
+
+ public static TimeGetMessage getSimple(int destinationAddress, int appKeyIndex, int rspMax) {
+ TimeGetMessage message = new TimeGetMessage(destinationAddress, appKeyIndex);
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public TimeGetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getOpcode() {
+ return Opcode.TIME_STATUS.value;
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return Opcode.TIME_STATUS.value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeMessage.java
new file mode 100644
index 00000000..6e994196
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeMessage.java
@@ -0,0 +1,36 @@
+/********************************************************************************************************
+ * @file TimeMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.time;
+
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.networking.AccessType;
+
+public abstract class TimeMessage extends MeshMessage {
+
+ public TimeMessage(int destinationAddress, int appKeyIndex) {
+ this.destinationAddress = destinationAddress;
+ this.appKeyIndex = appKeyIndex;
+ this.accessType = AccessType.APPLICATION;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeSetMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeSetMessage.java
new file mode 100644
index 00000000..24f1f8bd
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeSetMessage.java
@@ -0,0 +1,144 @@
+/********************************************************************************************************
+ * @file TimeSetMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.time;
+
+import com.telink.ble.mesh.core.message.Opcode;
+import com.telink.ble.mesh.core.message.generic.GenericMessage;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * time set
+ * Created by kee on 2019/8/14.
+ */
+public class TimeSetMessage extends GenericMessage {
+
+ /**
+ * TAI seconds
+ * 40 bits
+ * The current TAI time in seconds
+ */
+ private long taiSeconds;
+
+ /**
+ * 8 bits
+ * The sub-second time in units of 1/256th second
+ */
+ private byte subSecond;
+
+ /**
+ * 8 bits
+ * The estimated uncertainty in 10 millisecond steps
+ */
+ private byte uncertainty;
+
+ /**
+ * 1 bit
+ * 0 = No Time Authority, 1 = Time Authority
+ */
+ private byte timeAuthority;
+
+ /**
+ * TAI-UTC Delta
+ * 15 bits
+ * Current difference between TAI and UTC in seconds
+ */
+ private int delta;
+
+ /**
+ * Time Zone Offset
+ * 8 bits
+ * The local time zone offset in 15-minute increments
+ */
+ private int zoneOffset;
+
+ /**
+ * no-ack for time-status message
+ */
+ private boolean ack = false;
+
+ public static TimeSetMessage getSimple(int address, int appKeyIndex, long taiSeconds, int zoneOffset, int rspMax) {
+ TimeSetMessage message = new TimeSetMessage(address, appKeyIndex);
+ message.taiSeconds = taiSeconds;
+ message.zoneOffset = zoneOffset;
+ message.setResponseMax(rspMax);
+ return message;
+ }
+
+ public TimeSetMessage(int destinationAddress, int appKeyIndex) {
+ super(destinationAddress, appKeyIndex);
+ }
+
+ @Override
+ public int getResponseOpcode() {
+ return ack ? Opcode.TIME_STATUS.value : OPCODE_INVALID;
+ }
+
+ @Override
+ public int getOpcode() {
+ return ack ? Opcode.TIME_SET.value : Opcode.TIME_STATUS.value;
+ }
+
+ @Override
+ public byte[] getParams() {
+ ByteBuffer byteBuffer = ByteBuffer.allocate(10).order(ByteOrder.LITTLE_ENDIAN);
+ byteBuffer.put((byte) (taiSeconds))
+ .put((byte) (taiSeconds >> 8))
+ .put((byte) (taiSeconds >> 16))
+ .put((byte) (taiSeconds >> 24))
+ .put((byte) (taiSeconds >> 32))
+ .put(subSecond)
+ .put(uncertainty)
+ .putShort((short) ((delta << 1) | timeAuthority))
+ .put((byte) (zoneOffset));
+ return byteBuffer.array();
+ }
+
+ public void setTaiSeconds(long taiSeconds) {
+ this.taiSeconds = taiSeconds;
+ }
+
+ public void setSubSecond(byte subSecond) {
+ this.subSecond = subSecond;
+ }
+
+ public void setUncertainty(byte uncertainty) {
+ this.uncertainty = uncertainty;
+ }
+
+ public void setTimeAuthority(byte timeAuthority) {
+ this.timeAuthority = timeAuthority;
+ }
+
+ public void setDelta(int delta) {
+ this.delta = delta;
+ }
+
+ public void setZoneOffset(int zoneOffset) {
+ this.zoneOffset = zoneOffset;
+ }
+
+ public void setAck(boolean ack) {
+ this.ack = ack;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeStatusMessage.java
new file mode 100644
index 00000000..c1f62e8f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/message/time/TimeStatusMessage.java
@@ -0,0 +1,200 @@
+/********************************************************************************************************
+ * @file TimeStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.message.time;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.StatusMessage;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/20.
+ */
+
+public class TimeStatusMessage extends StatusMessage implements Parcelable {
+
+ private static final int DATA_LEN_COMPLETE = 10;
+
+ /**
+ * TAI seconds
+ * 40 bits
+ * The current TAI time in seconds
+ *
+ * If the TAI Seconds field is 0x0000000000
+ * the Subsecond, Uncertainty, Time Authority, TAI-UTC Delta and Time Zone Offset fields shall be omitted;
+ * otherwise these fields shall be present.
+ */
+ private long taiSeconds;
+
+ /**
+ * 8 bits
+ * The sub-second time in units of 1/256th second
+ */
+ private byte subSecond;
+
+ /**
+ * 8 bits
+ * The estimated uncertainty in 10 millisecond steps
+ */
+ private byte uncertainty;
+
+ /**
+ * 1 bit
+ * 0 = No Time Authority, 1 = Time Authority
+ */
+ private byte timeAuthority;
+
+ /**
+ * TAI-UTC Delta
+ * 15 bits
+ * Current difference between TAI and UTC in seconds
+ */
+ private int delta;
+
+ /**
+ * Time Zone Offset
+ * 8 bits
+ * The local time zone offset in 15-minute increments
+ */
+ private int zoneOffset;
+
+ /**
+ * tag of is complete message
+ */
+ private boolean isComplete = false;
+
+ public TimeStatusMessage() {
+ }
+
+ protected TimeStatusMessage(Parcel in) {
+ taiSeconds = in.readLong();
+ subSecond = in.readByte();
+ uncertainty = in.readByte();
+ timeAuthority = in.readByte();
+ delta = in.readInt();
+ zoneOffset = in.readInt();
+ isComplete = in.readByte() != 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public TimeStatusMessage createFromParcel(Parcel in) {
+ return new TimeStatusMessage(in);
+ }
+
+ @Override
+ public TimeStatusMessage[] newArray(int size) {
+ return new TimeStatusMessage[size];
+ }
+ };
+
+ @Override
+ public void parse(byte[] params) {
+ int index = 0;
+ this.taiSeconds = MeshUtils.bytes2Long(params, index, 5, ByteOrder.LITTLE_ENDIAN);
+ index += 5;
+ // tai
+ if (params.length == DATA_LEN_COMPLETE) {
+ this.isComplete = true;
+ this.subSecond = params[index++];
+ this.uncertainty = params[index++];
+ this.timeAuthority = (byte) (params[index] & 0b01);
+ this.delta = (params[index++] & 0xEF) | ((params[index++] & 0xFF) << 8);
+ this.zoneOffset = params[index] & 0xFF;
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(taiSeconds);
+ dest.writeByte(subSecond);
+ dest.writeByte(uncertainty);
+ dest.writeByte(timeAuthority);
+ dest.writeInt(delta);
+ dest.writeInt(zoneOffset);
+ dest.writeByte((byte) (isComplete ? 1 : 0));
+ }
+
+ public long getTaiSeconds() {
+ return taiSeconds;
+ }
+
+ public byte getSubSecond() {
+ return subSecond;
+ }
+
+ public byte getUncertainty() {
+ return uncertainty;
+ }
+
+ public byte getTimeAuthority() {
+ return timeAuthority;
+ }
+
+ public int getDelta() {
+ return delta;
+ }
+
+ public int getZoneOffset() {
+ return zoneOffset;
+ }
+
+ public boolean isComplete() {
+ return isComplete;
+ }
+
+ public void setTaiSeconds(long taiSeconds) {
+ this.taiSeconds = taiSeconds;
+ }
+
+ public void setSubSecond(byte subSecond) {
+ this.subSecond = subSecond;
+ }
+
+ public void setUncertainty(byte uncertainty) {
+ this.uncertainty = uncertainty;
+ }
+
+ public void setTimeAuthority(byte timeAuthority) {
+ this.timeAuthority = timeAuthority;
+ }
+
+ public void setDelta(int delta) {
+ this.delta = delta;
+ }
+
+ public void setZoneOffset(int zoneOffset) {
+ this.zoneOffset = zoneOffset;
+ }
+
+ public void setComplete(boolean complete) {
+ isComplete = complete;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/AccessLayerPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/AccessLayerPDU.java
new file mode 100644
index 00000000..712b4097
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/AccessLayerPDU.java
@@ -0,0 +1,93 @@
+/********************************************************************************************************
+ * @file AccessLayerPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking;
+
+/**
+ * access payload
+ * Created by kee on 2019/7/29.
+ */
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.OpcodeType;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * An access payload may be sent in up to 32 segments of 12 octets each.
+ * This implies that the maximum number of octets is 384 including the TransMIC
+ *
+ * 12 * 32
+ * packet-len * packet-cnt
+ *
+ * transMIC 4 bytes
+ * at least 1 byte opcode
+ */
+public class AccessLayerPDU implements NetworkingPDU {
+ // 1, 2 or 3 bytes
+ public int opcode;
+
+ // 0 ~ 379 bytes
+ public byte[] params;
+
+// public byte[] decryptedPayload;
+
+ private AccessLayerPDU() {
+ }
+
+
+ public AccessLayerPDU(int opcode, byte[] params) {
+ this.opcode = opcode;
+ this.params = params;
+ }
+
+
+ public static AccessLayerPDU parse(byte[] payload) {
+ AccessLayerPDU accessPDU = new AccessLayerPDU();
+ OpcodeType opType = OpcodeType.getByFirstByte(payload[0]);
+
+ accessPDU.opcode = 0;
+ int index = 0;
+ for (int i = 0; i < opType.length; i++) {
+ accessPDU.opcode |= (payload[index++] & 0xFF) << (8 * i);
+ }
+
+ final int paramLen = payload.length - opType.length;
+ accessPDU.params = new byte[paramLen];
+ System.arraycopy(payload, index, accessPDU.params, 0, paramLen);
+ return accessPDU;
+ }
+
+
+ @Override
+ public byte[] toByteArray() {
+ int opcodeLen = OpcodeType.getByFirstByte((byte) opcode).length;
+ if (params == null || params.length == 0) {
+ return MeshUtils.integer2Bytes(opcode, opcodeLen, ByteOrder.LITTLE_ENDIAN);
+ } else {
+ return ByteBuffer.allocate(opcodeLen + params.length).order(ByteOrder.LITTLE_ENDIAN)
+ .put(MeshUtils.integer2Bytes(opcode, opcodeLen, ByteOrder.LITTLE_ENDIAN))
+ .put(params)
+ .array();
+ }
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/AccessType.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/AccessType.java
new file mode 100644
index 00000000..9d51537d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/AccessType.java
@@ -0,0 +1,60 @@
+/********************************************************************************************************
+ * @file AccessType.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking;
+
+
+/**
+ * Access Command
+ * Created by kee on 2019/8/12.
+ */
+public enum AccessType {
+ /**
+ * for common model and vendor model
+ * use application key for encryption/decryption
+ */
+ APPLICATION(1),
+
+ /**
+ * for config model settings
+ * use device key for encryption/decryption
+ */
+ DEVICE(0);
+
+
+ public static AccessType getByAkf(byte akf) {
+ for (AccessType at :
+ values()) {
+ if (at.akf == akf) {
+ return at;
+ }
+ }
+ return null;
+ }
+
+ public final byte akf;
+
+ AccessType(int akf) {
+ this.akf = (byte) akf;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkLayerPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkLayerPDU.java
new file mode 100644
index 00000000..2e101075
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkLayerPDU.java
@@ -0,0 +1,358 @@
+/********************************************************************************************************
+ * @file NetworkLayerPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking;
+
+
+import com.telink.ble.mesh.core.Encipher;
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.util.MeshLogger;
+
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class NetworkLayerPDU {
+
+ /**
+ * Least significant bit of IV Index
+ * 1 bit
+ */
+ private byte ivi;
+
+ /**
+ * network id
+ * 7 bits
+ * Value derived from the NetKey used to identify the Encryption Key and Privacy Key used to secure this PDU
+ */
+ private byte nid;
+
+ /**
+ * Network Control
+ * 1 bit
+ * determine if the message is part of a Control MeshCommand or an Access MeshCommand
+ */
+ private byte ctl;
+
+ /**
+ * Time To Live
+ * 7 bits
+ * value:
+ * 0 = has not been relayed and will not be relayed
+ * 1 = may have been relayed, but will not be relayed
+ * 2 to 126 = may have been relayed and can be relayed
+ * 127 = has not been relayed and can be relayed
+ */
+ private byte ttl;
+
+ /**
+ * Sequence Number
+ * 24 bits == 3 bytes
+ */
+ private int seq;
+
+ /**
+ * Source Address
+ * 16 bits == 2 bytes
+ * shall be unicast address
+ */
+ private int src;
+
+ /**
+ * Destination Address
+ * 16 bits == 2 bytes
+ * shall be a unicast address, a group address, or a virtual address
+ */
+ private int dst;
+
+ /**
+ * Transport Protocol Data Unit
+ * 8 to 128 bits
+ * When the CTL bit is 0, the TransportPDU field shall be a maximum of 128 bits.
+ * When the CTL bit is 1, the TransportPDU field shall be a maximum of 96 bits.
+ */
+ private byte[] transportPDU;
+
+ /**
+ * MeshCommand Integrity Check for Network
+ * 32 or 64 bits
+ * When the CTL bit is 0, the NetMIC field shall be 32 bits.
+ * When the CTL bit is 1, the NetMIC field shall be 64 bits.
+ */
+// private int transMic;
+ protected NetworkEncryptionSuite encryptionSuite;
+
+ public NetworkLayerPDU(NetworkEncryptionSuite encryptionSuite) {
+ this.encryptionSuite = encryptionSuite;
+ }
+
+ /*public NetworkLayerPDU(int ivIndex, byte[] encryptionKey, byte[] privacyKey, int nid) {
+ this.ivIndex = ivIndex;
+ this.encryptionKey = encryptionKey;
+ this.privacyKey = privacyKey;
+ this.nid = nid;
+ }*/
+
+
+ public byte[] generateEncryptedPayload() {
+ final byte iviNid = (byte) ((ivi << 7) | nid);
+ final byte ctlTTL = (byte) ((ctl << 7) | ttl);
+
+ final byte[] encryptedPayload = encryptNetworkPduPayload(transportPDU);
+// MeshLogger.log("encryptedPayload: " + Arrays.bytesToHexString(encryptedPayload, ""));
+ final byte[] privacyRandom = createPrivacyRandom(encryptedPayload);
+ final byte[] pecb = createPECB(privacyRandom);
+// MeshLogger.log("pecb: " + Arrays.bytesToHexString(pecb, ""));
+
+ final byte[] header = createObfuscatedNetworkHeader(ctlTTL, seq, src, pecb);
+// MeshLogger.log("obfuscateNetworkHeader: " + Arrays.bytesToHexString(header, ""));
+
+ return ByteBuffer.allocate(1 + header.length + encryptedPayload.length).order(ByteOrder.BIG_ENDIAN)
+ .put(iviNid)
+ .put(header)
+ .put(encryptedPayload)
+ .array();
+ }
+
+ private byte[] createObfuscatedNetworkHeader(final byte ctlTTL, int sno, final int src, final byte[] pecb) {
+
+ byte[] seqNo = MeshUtils.integer2Bytes(sno, 3, ByteOrder.BIG_ENDIAN);
+ final ByteBuffer buffer = ByteBuffer.allocate(1 + seqNo.length + 2).order(ByteOrder.BIG_ENDIAN);
+ buffer.put(ctlTTL);
+ buffer.put(seqNo); //sequence number
+ buffer.putShort((short) src); //source address
+
+ final byte[] headerBuffer = buffer.array();
+
+// MeshLogger.log("NetworkHeader: " + Arrays.bytesToHexString(headerBuffer, ""));
+
+ final ByteBuffer bufferPECB = ByteBuffer.allocate(6);
+ bufferPECB.put(pecb, 0, 6);
+
+ final byte[] obfuscated = new byte[6];
+ for (int i = 0; i < 6; i++)
+ obfuscated[i] = (byte) (headerBuffer[i] ^ pecb[i]);
+
+ return obfuscated;
+ }
+
+ private byte[] createPECB(byte[] privacyRandom) {
+ final ByteBuffer buffer = ByteBuffer.allocate(5 + privacyRandom.length + 4);
+ buffer.order(ByteOrder.BIG_ENDIAN);
+ buffer.put(new byte[]{0x00, 0x00, 0x00, 0x00, 0x00});
+ buffer.putInt(this.encryptionSuite.ivIndex);
+ buffer.put(privacyRandom);
+ final byte[] temp = buffer.array();
+ return Encipher.aes(temp, this.encryptionSuite.privacyKey);
+ }
+
+ private byte[] createPrivacyRandom(byte[] encryptedUpperTransportPDU) {
+ final byte[] privacyRandom = new byte[7];
+ System.arraycopy(encryptedUpperTransportPDU, 0, privacyRandom, 0, privacyRandom.length);
+ return privacyRandom;
+ }
+
+
+ private byte[] encryptNetworkPduPayload(byte[] lowerPDU) {
+ // seqNo 3 bytes
+// byte ctlTTL = (byte) ((ctl << 7) | ttl);
+// byte[] seqNo = MeshUtils.integer2Bytes(seq, 3, ByteOrder.BIG_ENDIAN);
+// final byte[] networkNonce = NonceGenerator.generateNetworkNonce(ctlTTL, seqNo, src, this.encryptionSuite.ivIndex);
+ byte[] networkNonce = generateNonce();
+// MeshLogger.log("networkNonce: " + Arrays.bytesToHexString(networkNonce, ""));
+ final byte[] unencryptedNetworkPayload = ByteBuffer.allocate(2 + lowerPDU.length).order(ByteOrder.BIG_ENDIAN).putShort((short) dst).put(lowerPDU).array();
+ return Encipher.ccm(unencryptedNetworkPayload, this.encryptionSuite.encryptionKey, networkNonce, getMicLen(), true);
+ }
+
+ protected byte[] generateNonce() {
+ byte ctlTTL = (byte) ((ctl << 7) | ttl);
+ byte[] seqNo = MeshUtils.integer2Bytes(seq, 3, ByteOrder.BIG_ENDIAN);
+ return NonceGenerator.generateNetworkNonce(ctlTTL, seqNo, src, this.encryptionSuite.ivIndex);
+ }
+
+ private int getMicLen() {
+ return ctl == 0 ? 4 : 8;
+ }
+
+ /**
+ * parse
+ */
+ public byte[] parseObfuscatedNetworkHeader(byte[] pdu) {
+ final ByteBuffer obfuscatedNetworkBuffer = ByteBuffer.allocate(6);
+ obfuscatedNetworkBuffer.order(ByteOrder.BIG_ENDIAN);
+ obfuscatedNetworkBuffer.put(pdu, 1, 6);
+ final byte[] obfuscatedData = obfuscatedNetworkBuffer.array();
+
+ final ByteBuffer privacyRandomBuffer = ByteBuffer.allocate(7);
+ privacyRandomBuffer.order(ByteOrder.BIG_ENDIAN);
+ privacyRandomBuffer.put(pdu, 7, 7);
+ final byte[] privacyRandom = createPrivacyRandom(privacyRandomBuffer.array());
+
+ final byte[] pecb = createPECB(privacyRandom);
+ final byte[] deobfuscatedData = new byte[6];
+
+ for (int i = 0; i < 6; i++)
+ deobfuscatedData[i] = (byte) (obfuscatedData[i] ^ pecb[i]);
+
+ return deobfuscatedData;
+ }
+
+ public boolean parse(byte[] pduData) {
+
+ int iviNid = pduData[0] & 0xFF;
+ int ivi = iviNid >> 7;
+ int nid = iviNid & 0x7F;
+ MeshLogger.i("ivi -- " + ivi + " nid -- " + nid);
+ if (!validateNetworkPdu(ivi, nid)) {
+ MeshLogger.i("ivi or nid invalid: ivi -- " + ivi + " nid -- " + nid +
+ " encryptSuit : ivi -- " + encryptionSuite.ivIndex + " nid -- " + encryptionSuite.nid);
+ return false;
+ }
+
+ byte[] originalHeader = this.parseObfuscatedNetworkHeader(pduData);
+ int ctlTtl = originalHeader[0];
+ int ctl = (ctlTtl >> 7) & 0x01;
+ int ttl = ctlTtl & 0x7F;
+ byte[] sequenceNumber = ByteBuffer.allocate(3).order(ByteOrder.BIG_ENDIAN).put(originalHeader, 1, 3).array();
+ int src = (((originalHeader[4] & 0xFF) << 8) + (originalHeader[5] & 0xFF));
+ this.setIvi((byte) ivi);
+ this.setNid((byte) nid);
+ this.setCtl((byte) ctl);
+ this.setTtl((byte) ttl);
+ this.setSeq(MeshUtils.bytes2Integer(sequenceNumber, ByteOrder.BIG_ENDIAN));
+ this.setSrc(src);
+
+ byte[] networkNonce = generateNonce();
+// byte[] networkNonce = NonceGenerator.generateNetworkNonce((byte) ctlTtl, sequenceNumber, src, this.encryptionSuite.ivIndex);
+
+
+ final int dstTransportLen = pduData.length - (1 + originalHeader.length);
+
+ final byte[] dstTransportPayload = new byte[dstTransportLen];
+ System.arraycopy(pduData, 7, dstTransportPayload, 0, dstTransportLen);
+
+ // decrypted dest + transport(lower) payload
+ final byte[] decDstTransportPayload = Encipher.ccm(dstTransportPayload, this.encryptionSuite.encryptionKey, networkNonce, getMicLen(), false);
+
+ if (decDstTransportPayload == null) {
+ MeshLogger.i("network layer decrypt err");
+ return false;
+ }
+
+ int dstAdr = ((decDstTransportPayload[0] & 0xFF) << 8) | (decDstTransportPayload[1] & 0xFF);
+
+ byte[] lowerTransportPdu = new byte[decDstTransportPayload.length - 2];
+ System.arraycopy(decDstTransportPayload, 2, lowerTransportPdu, 0, lowerTransportPdu.length);
+
+ this.dst = dstAdr;
+ this.setTransportPDU(lowerTransportPdu);
+ return true;
+ }
+
+ private boolean validateNetworkPdu(int ivi, int nid) {
+ return nid == this.encryptionSuite.nid && ivi == (this.encryptionSuite.ivIndex & 0b01);
+ }
+
+ public byte getIvi() {
+ return ivi;
+ }
+
+ public void setIvi(byte ivi) {
+ this.ivi = ivi;
+ }
+
+ public byte getNid() {
+ return nid;
+ }
+
+ public void setNid(byte nid) {
+ this.nid = nid;
+ }
+
+ public byte getCtl() {
+ return ctl;
+ }
+
+ public void setCtl(byte ctl) {
+ this.ctl = ctl;
+ }
+
+ public byte getTtl() {
+ return ttl;
+ }
+
+ public void setTtl(byte ttl) {
+ this.ttl = ttl;
+ }
+
+ public int getSeq() {
+ return seq;
+ }
+
+ public void setSeq(int seq) {
+ this.seq = seq;
+ }
+
+ public int getSrc() {
+ return src;
+ }
+
+ public void setSrc(int src) {
+ this.src = src;
+ }
+
+ public int getDst() {
+ return dst;
+ }
+
+ public void setDst(int dst) {
+ this.dst = dst;
+ }
+
+ public byte[] getTransportPDU() {
+ return transportPDU;
+ }
+
+ public void setTransportPDU(byte[] transportPDU) {
+ this.transportPDU = transportPDU;
+ }
+
+ public static class NetworkEncryptionSuite {
+
+ // for encryption
+ public int ivIndex;
+
+ protected byte[] encryptionKey;
+
+
+ protected byte[] privacyKey;
+
+ protected int nid;
+
+ public NetworkEncryptionSuite(int ivIndex, byte[] encryptionKey, byte[] privacyKey, int nid) {
+ this.ivIndex = ivIndex;
+ this.encryptionKey = encryptionKey;
+ this.privacyKey = privacyKey;
+ this.nid = nid;
+ }
+ }
+}
+
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkingBridge.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkingBridge.java
new file mode 100644
index 00000000..4e56107b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkingBridge.java
@@ -0,0 +1,71 @@
+/********************************************************************************************************
+ * @file NetworkingBridge.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking;
+
+import com.telink.ble.mesh.core.proxy.ProxyPDU;
+
+/**
+ * Created by kee on 2019/8/15.
+ */
+
+public interface NetworkingBridge {
+
+ /**
+ * @param type proxy pdu typeValue {@link ProxyPDU#type}
+ * @param data gatt data
+ */
+ void onCommandPrepared(byte type, byte[] data);
+
+ /**
+ * application layer should save updated network info
+ */
+ void onNetworkInfoUpdate(int sequenceNumber, int ivIndex);
+
+ /**
+ * mesh model message
+ */
+ void onMeshMessageReceived(int src, int dst, int opcode, byte[] params);
+
+ /**
+ * received proxy status message when set filter type, or add/remove address
+ * @param address connected node unicast address
+ */
+ void onProxyInitComplete(boolean success, int address);
+
+
+ /**
+ * heartbeat message received
+ *
+ * @param data heartbeat data
+ */
+ void onHeartbeatMessageReceived(int src, int dst, byte[] data);
+
+ /**
+ * @param success if response received
+ * @param opcode command opcode
+ * @param rspMax expect response max
+ * @param rspCount received response count
+ */
+ void onReliableMessageComplete(boolean success, int opcode, int rspMax, int rspCount);
+
+ void onSegmentMessageComplete(boolean success);
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkingController.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkingController.java
new file mode 100644
index 00000000..5d655791
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkingController.java
@@ -0,0 +1,1653 @@
+/********************************************************************************************************
+ * @file NetworkingController.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.SparseLongArray;
+
+import com.telink.ble.mesh.core.Encipher;
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.message.MeshMessage;
+import com.telink.ble.mesh.core.networking.beacon.MeshBeaconPDU;
+import com.telink.ble.mesh.core.networking.beacon.SecureNetworkBeacon;
+import com.telink.ble.mesh.core.networking.transport.lower.LowerTransportPDU;
+import com.telink.ble.mesh.core.networking.transport.lower.SegmentAcknowledgmentMessage;
+import com.telink.ble.mesh.core.networking.transport.lower.SegmentedAccessMessagePDU;
+import com.telink.ble.mesh.core.networking.transport.lower.TransportControlMessagePDU;
+import com.telink.ble.mesh.core.networking.transport.lower.UnsegmentedAccessMessagePDU;
+import com.telink.ble.mesh.core.networking.transport.lower.UnsegmentedControlMessagePDU;
+import com.telink.ble.mesh.core.networking.transport.upper.UpperTransportAccessPDU;
+import com.telink.ble.mesh.core.proxy.ProxyAddAddressMessage;
+import com.telink.ble.mesh.core.proxy.ProxyConfigurationMessage;
+import com.telink.ble.mesh.core.proxy.ProxyConfigurationPDU;
+import com.telink.ble.mesh.core.proxy.ProxyFilterStatusMessage;
+import com.telink.ble.mesh.core.proxy.ProxyFilterType;
+import com.telink.ble.mesh.core.proxy.ProxyPDU;
+import com.telink.ble.mesh.core.proxy.ProxySetFilterTypeMessage;
+import com.telink.ble.mesh.foundation.MeshConfiguration;
+import com.telink.ble.mesh.util.Arrays;
+import com.telink.ble.mesh.util.MeshLogger;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * networking packet
+ * partition and composition
+ */
+
+/**
+ * Created by kee on 2019/7/31.
+ */
+public class NetworkingController {
+
+ private final String LOG_TAG = "Networking";
+ // include mic(4)
+ public static final int UNSEGMENTED_TRANSPORT_PAYLOAD_MAX_LENGTH = 15;
+
+ public static final int UNSEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH_DEFAULT = 11;
+
+// private static final int SEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH = 12;
+
+ public static final int UNSEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH_DLE = 225;
+
+// private static final int SEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH = UNSEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH + 1;
+
+ private boolean dleEnabled = false;
+
+ // segmentedAccessLength = unsegmentedAccessLength + 1
+ public static int unsegmentedAccessLength = UNSEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH_DLE;
+
+
+ private static final int DEFAULT_SEQUENCE_NUMBER_UPDATE_STEP = 0x100;
+
+ /**
+ * executing iv update procedure when connect proxy node success
+ * based on sequence number value >= THRESHOLD_SEQUENCE_NUMBER
+ *
+ * @see #checkSequenceNumber(byte[], byte[])
+ */
+ private final static int THRESHOLD_SEQUENCE_NUMBER = 0xC00000;
+
+
+ // for test
+// private final static int THRESHOLD_SEQUENCE_NUMBER = 0x0100;
+
+ /**
+ * receive
+ */
+ private final static int TRANSPORT_IN = 0x00;
+
+ /**
+ * transmit
+ */
+ private final static int TRANSPORT_OUT = 0x01;
+
+ private AtomicInteger mSequenceNumber = new AtomicInteger(0x0001);
+
+ private boolean isIvUpdating = false;
+
+ private byte nid;
+
+ private byte[] encryptionKey;
+
+ private byte[] privacyKey;
+
+ private int netKeyIndex;
+
+ /**
+ * deviceKey and unicastAddress map
+ */
+ private SparseArray deviceKeyMap;
+
+ /**
+ * save device sequence number and compare with sequence number in received network pdu
+ * if sequence number in network pud is not larger than saved sequence number, drop this pdu
+ */
+ private SparseIntArray deviceSequenceNumberMap = new SparseIntArray();
+
+ /**
+ * appKey and appKeyIndex map
+ */
+ private SparseArray appKeyMap;
+
+ /**
+ * from mesh configuration
+ */
+ private int initIvIndex = 0;
+
+ /**
+ * unsigned 32-bit integer
+ */
+ private long ivIndex = 0;
+
+ private int localAddress = 0x7FFF;
+
+ /**
+ * direct connected node mesh address
+ */
+ private int directAddress = 0;
+
+ /**
+ * model message transition id
+ * All tid in message(if contains) will be valued by this variable
+ */
+ private AtomicInteger tid = new AtomicInteger(0);
+
+ /**
+ * 13 bits
+ */
+ private static final int SEQ_ZERO_LIMIT = 0x1FFF;
+
+ /**
+ * received segmented message buffer by notification
+ */
+ private SparseArray receivedSegmentedMessageBuffer = new SparseArray<>();
+
+
+ private static final int SEQ_AUTH_BUF_CAPACITY = 10;
+
+ /**
+ * segment completed auth buffer
+ */
+ private SparseLongArray completedSeqAuthBuffer = new SparseLongArray();
+
+ /**
+ * segment busy auth buffer
+ */
+ private SparseLongArray busySeqAuthBuffer = new SparseLongArray();
+
+ /**
+ * sent segmented message buffer
+ */
+ private SparseArray sentSegmentedMessageBuffer = new SparseArray<>();
+
+// private SparseArray receivedSegmentedMessageBuffer;
+
+ /**
+ * last seqAuth in segmented pdu
+ * 0: segment idle
+ * others: segment busy
+ */
+ private long lastSeqAuth = 0;
+
+ private int lastSegSrc = 0;
+
+ // if last RX segment packets complete
+ private boolean lastSegComplete = true;
+
+
+ private NetworkingBridge mNetworkingBridge;
+
+ private int mSnoUpdateStep = DEFAULT_SEQUENCE_NUMBER_UPDATE_STEP;
+
+ private Handler mDelayHandler;
+
+ private SegmentAckMessageSentTask mAccessSegCheckTask = new SegmentAckMessageSentTask();
+
+ // waiting for segment ack message
+ private SegmentBlockWaitingTask mSegmentBlockWaitingTask = new SegmentBlockWaitingTask();
+
+ private static final int BLOCK_ACK_WAITING_TIMEOUT = 15 * 1000;
+
+ private boolean segmentedBusy = false;
+
+ private Runnable segmentedMessageTimeoutTask = new SegmentedMessageTimeoutTask();
+
+ /**
+ * sending message with ack
+ * only one reliable message can be sent at one time
+ *
+ * for reliable message,
+ */
+ private MeshMessage mSendingReliableMessage;
+
+ private boolean reliableBusy = false;
+
+ // reliable
+ private final Object RELIABLE_SEGMENTED_LOCK = new Object();
+
+ private static final int RELIABLE_MESSAGE_TIMEOUT = 960; // 2 * 1000
+
+ private Set mResponseMessageBuffer = new LinkedHashSet<>();
+
+ private int proxyFilterInitStep = 0;
+
+ private static final int PROXY_FILTER_INIT_STEP_SET_TYPE = 1;
+
+ private static final int PROXY_FILTER_SET_STEP_ADD_ADR = 2;
+
+ private static final int PROXY_FILTER_INIT_TIMEOUT = 5 * 1000;
+
+ /**
+ * networking pud sending prepared queue
+ */
+ private final Queue mNetworkingQueue = new ConcurrentLinkedQueue<>();
+
+ public static final long NETWORKING_INTERVAL = 320; // 240 ms
+
+ private final Object mNetworkBusyLock = new Object();
+
+ private boolean networkingBusy = false;
+
+
+ public NetworkingController(HandlerThread handlerThread) {
+ this.mDelayHandler = new Handler(handlerThread.getLooper());
+ this.appKeyMap = new SparseArray<>();
+ this.deviceKeyMap = new SparseArray<>();
+ }
+
+ public void setNetworkingBridge(NetworkingBridge networkingBridge) {
+ this.mNetworkingBridge = networkingBridge;
+ }
+
+ public void setup(MeshConfiguration configuration) {
+ this.clear();
+ this.initIvIndex = configuration.ivIndex;
+ this.ivIndex = initIvIndex & MeshUtils.UNSIGNED_INTEGER_MAX;
+ int seqNo = configuration.sequenceNumber;
+ this.mSequenceNumber.set(initSequenceNumber(seqNo));
+ this.netKeyIndex = configuration.netKeyIndex;
+ byte[][] k2Output = Encipher.calculateNetKeyK2(configuration.networkKey);
+ this.nid = (byte) (k2Output[0][15] & 0x7F);
+ this.encryptionKey = k2Output[1];
+ this.privacyKey = k2Output[2];
+
+ this.appKeyMap = configuration.appKeyMap;
+ this.deviceKeyMap = configuration.deviceKeyMap;
+
+ this.localAddress = configuration.localAddress;
+ }
+
+
+ public void clear() {
+ if (mDelayHandler != null) {
+ mDelayHandler.removeCallbacksAndMessages(null);
+ }
+
+ this.networkingBusy = false;
+ this.segmentedBusy = false;
+ this.reliableBusy = false;
+ this.mNetworkingQueue.clear();
+ this.lastSeqAuth = 0;
+ this.lastSegSrc = 0;
+ this.directAddress = 0;
+ this.lastSegComplete = true;
+ this.deviceSequenceNumberMap.clear();
+ this.receivedSegmentedMessageBuffer.clear();
+ this.sentSegmentedMessageBuffer.clear();
+ this.mResponseMessageBuffer.clear();
+ this.isIvUpdating = false;
+ this.lastSegComplete = true;
+ }
+
+ public void addDeviceKey(int unicastAddress, byte[] deviceKey) {
+ this.deviceKeyMap.put(unicastAddress, deviceKey);
+ }
+
+ public void enableDLE(boolean enable) {
+ this.dleEnabled = enable;
+ unsegmentedAccessLength = enable ? UNSEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH_DLE : UNSEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH_DEFAULT;
+ log("enableDLE: " + enable + " -- value : " + unsegmentedAccessLength);
+ }
+
+ public int getSegmentAccessLength() {
+ return unsegmentedAccessLength;
+ }
+
+ public void removeDeviceKey(int unicastAddress) {
+ this.deviceKeyMap.remove(unicastAddress);
+ }
+
+
+ private synchronized void saveCompletedSeqAuth(int src, long seqAuth) {
+ log(String.format(Locale.getDefault(), "save complete seqAuth src: 0x%04X -- seqAuth: 0x%014X", src, seqAuth));
+ this.completedSeqAuthBuffer.put(src, seqAuth);
+ /*if (this.completedSeqAuthBuffer.size() > SEQ_AUTH_BUF_CAPACITY) {
+ log("remove buffer");
+ this.completedSeqAuthBuffer.removeAt(SEQ_AUTH_BUF_CAPACITY);
+ }*/
+ }
+
+ private boolean isCompleteAuthExists(int src, long seqAuth) {
+ return this.completedSeqAuthBuffer.get(src, 0) == seqAuth;
+ }
+
+ private synchronized void saveBusySeqAuth(int src, long seqAuth) {
+ log(String.format(Locale.getDefault(), "save busy seqAuth src: 0x%04X -- seqAuth: 0x%014X", src, seqAuth));
+ this.busySeqAuthBuffer.put(src, seqAuth);
+ }
+
+ private boolean isBusyAuthExists(int src, long seqAuth) {
+ return this.busySeqAuthBuffer.get(src, 0) == seqAuth;
+ }
+
+ /**
+ * check SequenceNumber when proxy connected
+ * sendIvUpdatingBeacon
+ */
+ public void checkSequenceNumber(byte[] networkId, byte[] beaconKey) {
+ final boolean updatingNeeded = this.mSequenceNumber.get() >= THRESHOLD_SEQUENCE_NUMBER;
+ SecureNetworkBeacon networkBeacon = SecureNetworkBeacon.createIvUpdatingBeacon((int) this.ivIndex, networkId, beaconKey, updatingNeeded);
+ this.isIvUpdating = updatingNeeded;
+ if (isIvUpdating) {
+ this.ivIndex += 1;
+ }
+ log(networkBeacon.toString());
+ sendMeshBeaconPdu(networkBeacon);
+ }
+
+ private void onIvUpdated(long newIvIndex) {
+ if (newIvIndex > initIvIndex) {
+ log(String.format(" iv updated to %08X", newIvIndex));
+ this.deviceSequenceNumberMap.clear();
+ this.mSequenceNumber.set(0);
+ if (mNetworkingBridge != null) {
+ mNetworkingBridge.onNetworkInfoUpdate(mSequenceNumber.get(), (int) newIvIndex);
+ }
+ } else {
+ log(" iv not updated");
+ }
+ }
+
+ private void onIvIndexReceived(long remoteIvIndex, boolean updating) {
+ log(String.format("iv index received iv: %08X -- updating: %b -- localIv: %08X -- updating: %b ",
+ remoteIvIndex,
+ updating,
+ this.ivIndex,
+ this.isIvUpdating));
+ // d-value
+ long dVal = remoteIvIndex - this.ivIndex;
+
+ if (dVal == 0) {
+ // remote node iv update complete
+ if (!updating && this.isIvUpdating) {
+ this.isIvUpdating = false;
+ this.onIvUpdated(remoteIvIndex);
+ }
+ } else if (dVal > 0) {
+ log("larger iv index received");
+ if (dVal <= 42) {
+ this.isIvUpdating = updating;
+ this.ivIndex = remoteIvIndex;
+
+ this.onIvUpdated(updating ? remoteIvIndex - 1 : remoteIvIndex);
+ } else {
+ log("iv index dVal greater than 42");
+ }
+
+ } else {
+ log(" smaller iv index received", MeshLogger.LEVEL_WARN);
+ }
+ }
+
+ private int initSequenceNumber(int sequenceNumber) {
+ if (mSnoUpdateStep == 0 || mSnoUpdateStep == 1) return sequenceNumber;
+ int initSno = (sequenceNumber / mSnoUpdateStep + 1) * mSnoUpdateStep;
+ onSequenceNumberUpdate(initSno);
+ log("init sno: " + initSno);
+ return initSno;
+ }
+
+ private void sendProxyConfigurationMessage(ProxyConfigurationMessage message) {
+ byte[] transportPdu = message.toByteArray();
+ ProxyConfigurationPDU networkLayerPDU = createProxyConfigurationPdu(transportPdu,
+ localAddress, getTransmitIvIndex(), this.mSequenceNumber.get());
+ sendProxyNetworkPdu(networkLayerPDU);
+ }
+
+ public boolean sendMeshMessage(MeshMessage meshMessage) {
+
+ int dst = meshMessage.getDestinationAddress();
+ if (!validateDestinationAddress(dst)) {
+ log("invalid dst address: " + String.format("%04X", dst), MeshLogger.LEVEL_WARN);
+ return false;
+ }
+
+ AccessType accessType = meshMessage.getAccessType();
+ byte[] encryptionKey;
+ if (accessType == AccessType.APPLICATION) {
+ encryptionKey = getAppKey(meshMessage.getAppKeyIndex());
+ } else {
+ encryptionKey = getDeviceKey(meshMessage.getDestinationAddress());
+ }
+
+ if (encryptionKey == null) {
+ log("access key not found : " + accessType, MeshLogger.LEVEL_WARN);
+ return false;
+ }
+ meshMessage.setAccessKey(encryptionKey);
+
+
+ return postMeshMessage(meshMessage, false);
+ }
+
+
+ /**
+ * @return if message will be sent
+ */
+ private boolean postMeshMessage(MeshMessage meshMessage, boolean retry) {
+ int dst = meshMessage.getDestinationAddress();
+ int src = localAddress;
+ int aszmic = meshMessage.getSzmic();
+ byte akf = meshMessage.getAccessType().akf;
+ byte aid;
+ if (meshMessage.getAccessType() == AccessType.APPLICATION) {
+ aid = Encipher.k4(meshMessage.getAccessKey());
+ } else {
+ aid = 0x00;
+ }
+
+ int sequenceNumber = mSequenceNumber.get();
+
+ final byte[] params = meshMessage.getParams();
+ final int tidPos = meshMessage.getTidPosition();
+ if (params != null && tidPos >= 0 && params.length > tidPos) {
+ params[tidPos] = retry ? (byte) this.tid.get() : (byte) this.tid.incrementAndGet();
+ }
+
+ AccessLayerPDU accessPDU = new AccessLayerPDU(meshMessage.getOpcode(), params);
+
+ byte[] accessPduData = accessPDU.toByteArray();
+
+// boolean segmented = accessPduData.length > UNSEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH;
+ boolean segmented = accessPduData.length > unsegmentedAccessLength;
+ meshMessage.setSegmented(segmented);
+ if (segmented) {
+ synchronized (RELIABLE_SEGMENTED_LOCK) {
+ if (segmentedBusy) {
+ log("segment message send err: segmented busy");
+ return false;
+ }
+ }
+ }
+
+ log("post access pdu: " + Arrays.bytesToHexString(accessPDU.toByteArray(), ""));
+
+ int ivIndex = getTransmitIvIndex();
+
+ UpperTransportAccessPDU upperPDU = createUpperTransportAccessPDU(accessPduData,
+ meshMessage.getAccessKey(),
+ (byte) meshMessage.getSzmic(),
+ meshMessage.getAccessType(),
+ ivIndex,
+ sequenceNumber, src, dst);
+
+ if (upperPDU == null) {
+ log("create upper transport pdu err: encrypt err", MeshLogger.LEVEL_WARN);
+ return false;
+ }
+ log("upper transport pdu: " + Arrays.bytesToHexString(upperPDU.getEncryptedPayload(), ""));
+
+ // check message reliable
+ final boolean reliable = meshMessage.isReliable();
+
+ // upperPDU.getEncryptedPayload().length <= UNSEGMENTED_TRANSPORT_PAYLOAD_MAX_LENGTH
+ //
+ /*
+ for unsegmented & reliable message, start reliable timeout check immediately,
+ for segmented & reliable message, start reliable timeout check when received block ack
+ */
+ if (!segmented) {
+ log("send unsegmented access message");
+
+ if (reliable) {
+ if (reliableBusy) {
+ log("unsegmented reliable message send err: busy", MeshLogger.LEVEL_WARN);
+ return false;
+ }
+ reliableBusy = true;
+ mSendingReliableMessage = meshMessage;
+ restartReliableMessageTimeoutTask();
+ }
+
+ UnsegmentedAccessMessagePDU unsegmentedMessagePDU = createUnsegmentedAccessMessage(upperPDU.getEncryptedPayload(), akf, aid);
+ NetworkLayerPDU networkPDU = createNetworkPDU(unsegmentedMessagePDU.toByteArray(),
+ meshMessage.getCtl(), meshMessage.getTtl(), src, dst, ivIndex, sequenceNumber);
+ sendNetworkPdu(networkPDU);
+ } else {
+ synchronized (RELIABLE_SEGMENTED_LOCK) {
+ if (reliable) {
+ if (reliableBusy) {
+ log("segmented reliable message send err: busy", MeshLogger.LEVEL_WARN);
+ return false;
+ }
+ reliableBusy = true;
+ mSendingReliableMessage = meshMessage;
+// restartReliableMessageTimeoutTask(); //
+ }
+ SparseArray segmentedAccessMessages = createSegmentedAccessMessage(upperPDU.getEncryptedPayload(), akf, aid, aszmic, sequenceNumber);
+ if (segmentedAccessMessages.size() == 0) return false;
+
+ log("send segmented access message");
+ List networkLayerPduList = new ArrayList<>();
+ for (int i = 0; i < segmentedAccessMessages.size(); i++) {
+ byte[] lowerTransportPdu = segmentedAccessMessages.get(i).toByteArray();
+ NetworkLayerPDU networkPDU = createNetworkPDU(lowerTransportPdu,
+ meshMessage.getCtl(), meshMessage.getTtl(), src, dst, ivIndex, sequenceNumber + i);
+ networkLayerPduList.add(networkPDU);
+ }
+ if (MeshUtils.validUnicastAddress(dst)) {
+ this.sentSegmentedMessageBuffer = segmentedAccessMessages.clone();
+ startSegmentedMessageTimeoutCheck();
+ startSegmentedBlockAckWaiting(meshMessage.getCtl(), meshMessage.getTtl(), src, dst);
+ } else if (reliable) {
+ restartReliableMessageTimeoutTask();
+ }
+ sendNetworkPduList(networkLayerPduList);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * proxy filter init steps:
+ * 1. set white list
+ * 2. add localAddress and 0xFFFF into address array
+ */
+ public void proxyFilterInit() {
+ proxyFilterInitStep = 0;
+ mDelayHandler.removeCallbacks(proxyFilterInitTimeoutTask);
+ mDelayHandler.postDelayed(proxyFilterInitTimeoutTask, PROXY_FILTER_INIT_TIMEOUT);
+ setFilterType(ProxyFilterType.WhiteList);
+ }
+
+ private void setFilterType(ProxyFilterType filterType) {
+ ProxySetFilterTypeMessage message = new ProxySetFilterTypeMessage(filterType.value);
+ sendProxyConfigurationMessage(message);
+ }
+
+ private void addFilterAddress(int[] addressArray) {
+ ProxyAddAddressMessage addAddressMessage = new ProxyAddAddressMessage(addressArray);
+ sendProxyConfigurationMessage(addAddressMessage);
+ }
+
+ private boolean validateDestinationAddress(int address) {
+ return address != 0;
+ }
+
+ /**
+ * get app key in map
+ *
+ * @return app key at index
+ */
+ private byte[] getAppKey(int appKeyIndex) {
+ if (this.appKeyMap == null) return null;
+ return this.appKeyMap.get(appKeyIndex);
+ }
+
+
+ /**
+ * get device key for config model message when akf==0
+ * {@link AccessType#DEVICE}
+ *
+ * @param unicastAddress node address
+ * @return device key
+ */
+ private byte[] getDeviceKey(int unicastAddress) {
+ if (this.deviceKeyMap == null) return null;
+ return this.deviceKeyMap.get(unicastAddress);
+ }
+
+
+ private void startSegmentedMessageTimeoutCheck() {
+ segmentedBusy = true;
+ mDelayHandler.removeCallbacks(segmentedMessageTimeoutTask);
+ mDelayHandler.postDelayed(segmentedMessageTimeoutTask, BLOCK_ACK_WAITING_TIMEOUT);
+ }
+
+ private void startSegmentedBlockAckWaiting(int ctl, int ttl, int src, int dst) {
+ mDelayHandler.removeCallbacks(mSegmentBlockWaitingTask);
+ mSegmentBlockWaitingTask.resetParams(ctl, ttl, src, dst);
+ mDelayHandler.postDelayed(mSegmentBlockWaitingTask, getSegmentedTimeout(ttl, true));
+ }
+
+ /**
+ * stop segmented message block acknowledgment waiting
+ *
+ * @param complete true: when timeout {@link #BLOCK_ACK_WAITING_TIMEOUT}
+ * or block ack shows all segmented message received
+ * false: when checking block ack
+ */
+ private void stopSegmentedBlockAckWaiting(boolean complete, boolean success) {
+ log(String.format("stop segmented block waiting, complete - %B success - %B", complete, success));
+ mDelayHandler.removeCallbacks(mSegmentBlockWaitingTask);
+ if (complete) {
+ onSegmentedMessageComplete(success);
+ }
+ }
+
+ /**
+ * segment message sent complete
+ *
+ * @param success true: received completed block
+ * false: timeout
+ */
+ private void onSegmentedMessageComplete(boolean success) {
+ log("segmented message complete, success? : " + success);
+ // clear segment state
+ clearSegmentSendingState(success);
+
+ // check reliable state
+ if (reliableBusy) {
+ /*
+ if segmented message sent success, check response after #@link{RELIABLE_MESSAGE_TIMEOUT}
+ else if segmented message timeout, retry immediately
+ */
+ if (success) {
+ restartReliableMessageTimeoutTask();
+ } else {
+ // if segment timeout , no need to resend reliable message
+ onReliableMessageComplete(false);
+ }
+ }
+ }
+
+ private void clearSegmentSendingState(boolean success) {
+ segmentedBusy = false;
+ mDelayHandler.removeCallbacks(segmentedMessageTimeoutTask);
+ sentSegmentedMessageBuffer.clear();
+ if (mNetworkingBridge != null) {
+ mNetworkingBridge.onSegmentMessageComplete(success);
+ }
+ /*final MeshMessage meshMessage = mSendingReliableMessage;
+ if (meshMessage != null){
+ int opcode = meshMessage.getOpcode();
+
+ }*/
+
+ }
+
+ private long getSegmentedTimeout(int ttl, boolean outer) {
+
+ final int relayTimeout = 300;
+ final int segmentAckTimeout = 200 + 50 * ttl;
+ long timeout;
+ if (outer) {
+ // send
+ int queueSize;
+ synchronized (mNetworkingQueue) {
+ queueSize = mNetworkingQueue.size();
+ }
+ timeout = relayTimeout + segmentAckTimeout + queueSize * NETWORKING_INTERVAL;
+ } else {
+ // receive
+ timeout = relayTimeout + segmentAckTimeout;
+ }
+ log("get segment ack timeout: " + timeout);
+ return timeout;
+ }
+
+ private long getReliableMessageTimeout() {
+ int queueSize;
+ synchronized (mNetworkingQueue) {
+ queueSize = mNetworkingQueue.size();
+ }
+
+ // 960
+// long timeout = 1280 + queueSize * NETWORKING_INTERVAL;
+ long timeout = (dleEnabled ? 2560 : 1280) + queueSize * NETWORKING_INTERVAL;
+ log("reliable message timeout:" + timeout);
+ return timeout;
+ }
+
+ private void increaseSequenceNumber() {
+ int latestValue = mSequenceNumber.incrementAndGet();
+ onSequenceNumberUpdate(latestValue);
+ }
+
+ private void sendNetworkPduList(List networkPduList) {
+ if (mNetworkingBridge != null) {
+ for (NetworkLayerPDU networkLayerPDU : networkPduList) {
+ byte[] networkPduPayload = networkLayerPDU.generateEncryptedPayload();
+ log("multi network pdu: " + Arrays.bytesToHexString(networkPduPayload, ":"));
+ onNetworkingPduPrepared(networkPduPayload, networkLayerPDU.getDst());
+ }
+ }
+ }
+
+ private void sendNetworkPdu(NetworkLayerPDU networkPdu) {
+ if (mNetworkingBridge != null) {
+ byte[] networkPduPayload = networkPdu.generateEncryptedPayload();
+ log("single network pdu: " + Arrays.bytesToHexString(networkPduPayload, ":"));
+ onNetworkingPduPrepared(networkPduPayload, networkPdu.getDst());
+ }
+ }
+
+ private void sendProxyNetworkPdu(ProxyConfigurationPDU networkPdu) {
+ if (mNetworkingBridge != null) {
+ byte[] networkPduPayload = networkPdu.generateEncryptedPayload();
+ log("proxy network pdu: " + Arrays.bytesToHexString(networkPduPayload, ":"));
+ mNetworkingBridge.onCommandPrepared(ProxyPDU.TYPE_PROXY_CONFIGURATION, networkPduPayload);
+ }
+ }
+
+ private void onNetworkingPduPrepared(byte[] payload, int dstAddress) {
+ log("networking pud prepared: " + Arrays.bytesToHexString(payload, ":") + " busy?-" + networkingBusy);
+
+ synchronized (mNetworkBusyLock) {
+ if (!networkingBusy) {
+ boolean directPdu = dstAddress == this.directAddress;
+ if (directPdu) {
+ log("networking pdu sending direct ");
+ if (mNetworkingBridge != null) {
+ mNetworkingBridge.onCommandPrepared(ProxyPDU.TYPE_NETWORK_PDU, payload);
+ }
+ return;
+ }
+ }
+ }
+
+ synchronized (mNetworkingQueue) {
+ mNetworkingQueue.add(payload);
+ }
+ synchronized (mNetworkBusyLock) {
+ if (!networkingBusy) {
+ networkingBusy = true;
+ pollNetworkingQueue();
+ }
+ }
+ }
+
+
+ private void pollNetworkingQueue() {
+ byte[] payload;
+ synchronized (mNetworkingQueue) {
+ payload = mNetworkingQueue.poll();
+ }
+ if (payload == null) {
+ log("networking pud poll: null");
+ synchronized (mNetworkBusyLock) {
+ networkingBusy = false;
+ }
+ } else {
+ log("networking pud poll: " + Arrays.bytesToHexString(payload, ":"));
+ if (mNetworkingBridge != null) {
+ mNetworkingBridge.onCommandPrepared(ProxyPDU.TYPE_NETWORK_PDU, payload);
+ }
+ mDelayHandler.removeCallbacks(networkingSendingTask);
+ mDelayHandler.postDelayed(networkingSendingTask, NETWORKING_INTERVAL);
+ }
+ }
+
+ private Runnable networkingSendingTask = new Runnable() {
+ @Override
+ public void run() {
+ pollNetworkingQueue();
+ }
+ };
+
+ /**
+ * seqNo update by step
+ * {@link #mSnoUpdateStep}
+ *
+ * @param latestSequenceNumber latest sequenceNumber
+ */
+ private void onSequenceNumberUpdate(int latestSequenceNumber) {
+ if (mNetworkingBridge != null) {
+ if (mSnoUpdateStep == 0 || latestSequenceNumber % mSnoUpdateStep == 0) {
+ mNetworkingBridge.onNetworkInfoUpdate(latestSequenceNumber, (int) this.ivIndex);
+ }
+ }
+ }
+
+
+ public void parseMeshBeacon(byte[] payload, byte[] networkId, byte[] networkBeaconKey) {
+ SecureNetworkBeacon networkBeacon = SecureNetworkBeacon.from(payload);
+ // validate beacon data
+ if (networkBeacon != null) {
+ log("SecureNetworkBeacon received: " + networkBeacon.toString());
+ if (networkBeacon.validateAuthValue(networkId, networkBeaconKey)) {
+ int ivIndex = networkBeacon.getIvIndex();
+ boolean isIvUpdating = networkBeacon.isIvUpdating();
+ onIvIndexReceived(ivIndex & MeshUtils.UNSIGNED_INTEGER_MAX, isIvUpdating);
+ } else {
+ log("network beacon check err");
+ }
+
+ } else {
+ log("network beacon parse err");
+ }
+ }
+
+ /**
+ * accepted when received networking pdu
+ *
+ * @param ivi 1-bit
+ * @return ivIndex
+ */
+ private int getAcceptedIvIndex(int ivi) {
+ log(String.format("getAcceptedIvIndex : %08X", ivIndex) + " ivi: " + ivi);
+ boolean ivChecked = (ivIndex & 0b01) == ivi;
+ return ivChecked ? (int) ivIndex : (int) (ivIndex - 1);
+ }
+
+ private int getTransmitIvIndex() {
+ int re = (int) (!isIvUpdating ? ivIndex : ivIndex - 1);
+ log(String.format("getTransmitIvIndex : %08X", re));
+ return re;
+ }
+
+ private void sendMeshBeaconPdu(MeshBeaconPDU meshBeaconPDU) {
+ if (mNetworkingBridge != null) {
+ mNetworkingBridge.onCommandPrepared(ProxyPDU.TYPE_MESH_BEACON, meshBeaconPDU.toBytes());
+ }
+ }
+
+ /**
+ * @param payload data payload
+ */
+ public void parseNetworkPdu(byte[] payload) {
+
+ int ivi = (payload[0] & 0xFF) >> 7;
+ int ivIndex = getAcceptedIvIndex(ivi);
+ NetworkLayerPDU networkLayerPDU = new NetworkLayerPDU(
+ new NetworkLayerPDU.NetworkEncryptionSuite(ivIndex, this.encryptionKey, this.privacyKey, this.nid)
+ );
+ if (networkLayerPDU.parse(payload)) {
+ if (!validateSequenceNumber(networkLayerPDU)) {
+ log("network pdu sequence number check err", MeshLogger.LEVEL_WARN);
+ return;
+ }
+ if (networkLayerPDU.getCtl() == MeshMessage.CTL_ACCESS) {
+ parseAccessMessage(networkLayerPDU);
+ } else {
+ parseControlMessage(networkLayerPDU);
+ }
+
+ } else {
+ log("network layer parse err", MeshLogger.LEVEL_WARN);
+ }
+ }
+
+ public void parseProxyConfigurationPdu(byte[] payload) {
+ int ivi = (payload[0] & 0xFF) >> 7;
+ int ivIndex = getAcceptedIvIndex(ivi);
+ ProxyConfigurationPDU proxyNetworkPdu = new ProxyConfigurationPDU(
+ new NetworkLayerPDU.NetworkEncryptionSuite(ivIndex, this.encryptionKey, this.privacyKey, this.nid)
+ );
+ if (proxyNetworkPdu.parse(payload)) {
+ if (!validateSequenceNumber(proxyNetworkPdu)) {
+ log("proxy config pdu sequence number check err", MeshLogger.LEVEL_WARN);
+ return;
+ }
+ log(String.format("proxy network pdu src: %04X dst: %04X", proxyNetworkPdu.getSrc(), proxyNetworkPdu.getDst()));
+ onProxyConfigurationNotify(proxyNetworkPdu.getTransportPDU(), proxyNetworkPdu.getSrc());
+ }
+
+ }
+
+ private void onProxyConfigurationNotify(byte[] proxyConfigMessage, int src) {
+ log("onProxyConfigurationNotify: "
+ + Arrays.bytesToHexString(proxyConfigMessage, ":"));
+ ProxyFilterStatusMessage proxyFilterStatusMessage = ProxyFilterStatusMessage.fromBytes(proxyConfigMessage);
+ if (proxyFilterStatusMessage != null) {
+
+ // target Filter type is whitelist
+ if (proxyFilterStatusMessage.getFilterType() == ProxyFilterType.WhiteList.value) {
+ if (proxyFilterInitStep < 0) {
+ log("filter init action not started!", MeshLogger.LEVEL_WARN);
+ return;
+ }
+ this.directAddress = src;
+ proxyFilterInitStep++;
+ if (proxyFilterInitStep == PROXY_FILTER_INIT_STEP_SET_TYPE) {
+ addFilterAddress(new int[]{localAddress, 0xFFFF});
+ } else if (proxyFilterInitStep == PROXY_FILTER_SET_STEP_ADD_ADR) {
+ onProxyInitComplete(true);
+ }
+ }
+
+ }
+ }
+
+ private Runnable proxyFilterInitTimeoutTask = new Runnable() {
+ @Override
+ public void run() {
+ log("filter init timeout");
+ onProxyInitComplete(false);
+ }
+ };
+
+ private void onProxyInitComplete(boolean success) {
+ proxyFilterInitStep = -1;
+ if (success) {
+ mDelayHandler.removeCallbacks(proxyFilterInitTimeoutTask);
+ }
+ if (mNetworkingBridge != null) {
+ mNetworkingBridge.onProxyInitComplete(success, this.directAddress);
+ }
+ }
+
+ private boolean validateSequenceNumber(NetworkLayerPDU networkLayerPDU) {
+ int src = networkLayerPDU.getSrc();
+ int pduSequenceNumber = networkLayerPDU.getSeq();
+ int deviceSequenceNumber = this.deviceSequenceNumberMap.get(src, -1);
+ boolean pass = true;
+ if (deviceSequenceNumber == -1) {
+ this.deviceSequenceNumberMap.put(src, pduSequenceNumber);
+ } else {
+ if (pduSequenceNumber > deviceSequenceNumber) {
+ this.deviceSequenceNumberMap.put(src, pduSequenceNumber);
+ } else {
+ log(String.format("validate sequence number error src: %04X -- pdu-sno: %06X -- dev-sno: %06X", src, pduSequenceNumber, deviceSequenceNumber));
+ pass = false;
+ }
+ }
+ return pass;
+ }
+
+ private void parseControlMessage(NetworkLayerPDU networkLayerPDU) {
+ byte[] lowerTransportPduData = networkLayerPDU.getTransportPDU();
+ int segOpcode = lowerTransportPduData[0] & 0xFF;
+ int seg = segOpcode >> 7;
+ int opcode = segOpcode & 0x7F;
+ log("parse control message seg:" + seg + " -- opcode:" + opcode);
+ if (seg == LowerTransportPDU.SEG_TYPE_UNSEGMENTED) {
+ if (opcode == TransportControlMessagePDU.CONTROL_MESSAGE_OPCODE_SEG_ACK) {
+ SegmentAcknowledgmentMessage segmentAckMessage = new SegmentAcknowledgmentMessage();
+ if (segmentAckMessage.parse(lowerTransportPduData)) {
+ onSegmentAckMessageReceived(segmentAckMessage);
+ }
+ } else if (opcode == TransportControlMessagePDU.CONTROL_MESSAGE_OPCODE_HEARTBEAT) {
+ onHeartbeatNotify(networkLayerPDU.getSrc(), networkLayerPDU.getDst(), lowerTransportPduData);
+ }
+ }
+ }
+
+
+ private void onHeartbeatNotify(int src, int dst, byte[] transportPdu) {
+ log("on heart beat notify: " + Arrays.bytesToHexString(transportPdu, ":"));
+ if (mNetworkingBridge != null) {
+ mNetworkingBridge.onHeartbeatMessageReceived(src, dst, transportPdu);
+ }
+ }
+
+ /**
+ * when receive Segment Acknowledgment Message
+ * check if is segmented message sending,
+ * and check blockAck value , if segmented message missing, resend
+ */
+ private void onSegmentAckMessageReceived(SegmentAcknowledgmentMessage segmentAckMessage) {
+ log("onSegmentAckMessageReceived: " + segmentAckMessage.toString());
+ if (segmentedBusy) {
+ resendSegmentedMessages(segmentAckMessage.getSeqZero(), segmentAckMessage.getBlockAck());
+ } else {
+ log("Segment Acknowledgment Message err: segmented messages not sending", MeshLogger.LEVEL_WARN);
+ }
+ }
+
+ /**
+ * @param seqZero valued by block ack message or -1 when not received any block ack message;
+ * so if seqZero is -1, resend all segmented messages
+ * @param blockAck valued by block ack message showing missing segmented messages or 0 when not received any block ack message
+ */
+ private void resendSegmentedMessages(int seqZero, int blockAck) {
+ final SparseArray messageBuffer = sentSegmentedMessageBuffer.clone();
+ log("resendSegmentedMessages: seqZero: " + seqZero
+ + " block ack: " + blockAck
+ + " buffer size: " + messageBuffer.size());
+ if (messageBuffer.size() != 0) {
+ SegmentedAccessMessagePDU message0 = messageBuffer.get(messageBuffer.keyAt(0));
+ int messageSeqZero = message0.getSeqZero();
+
+ if (seqZero != -1) {
+ if (seqZero == messageSeqZero) {
+ stopSegmentedBlockAckWaiting(false, false);
+ } else {
+ return;
+ }
+ }
+
+
+ int ctl = mSegmentBlockWaitingTask.ctl;
+ int ttl = mSegmentBlockWaitingTask.ttl;
+ int src = mSegmentBlockWaitingTask.src;
+ int dst = mSegmentBlockWaitingTask.dst;
+
+// int blockAck = segmentAckMessage.getBlockAck();
+ int messageSegN = message0.getSegN();
+ boolean messageReceived;
+ SegmentedAccessMessagePDU messagePDU;
+ int ivIndex = getTransmitIvIndex();
+ int sequenceNumber = mSequenceNumber.get();
+ int addedValue = 0;
+ List networkLayerPduList = new ArrayList<>();
+ for (int i = 0; i <= messageSegN; i++) {
+ messageReceived = (blockAck & MeshUtils.bit(i)) != 0;
+ if (!messageReceived) {
+ // message miss
+ messagePDU = messageBuffer.get(i);
+ byte[] lowerTransportPdu = messagePDU.toByteArray();
+ log("resend segmented message: seqZero:" + messagePDU.getSeqZero() + " -- segO:" + messagePDU.getSegO());
+ NetworkLayerPDU networkPDU = createNetworkPDU(lowerTransportPdu,
+ ctl, ttl, src, dst, ivIndex, sequenceNumber + addedValue);
+ addedValue++;
+ networkLayerPduList.add(networkPDU);
+ }
+ }
+
+ if (networkLayerPduList.size() == 0) {
+ // all received
+ stopSegmentedBlockAckWaiting(true, true);
+ } else {
+ startSegmentedBlockAckWaiting(ctl, ttl, src, dst);
+ sendNetworkPduList(networkLayerPduList);
+ }
+
+ }
+
+
+ }
+
+
+ /**
+ * parse lower transport pdu
+ */
+ private void parseAccessMessage(NetworkLayerPDU networkLayerPDU) {
+ log("parse access message");
+ int src = networkLayerPDU.getSrc();
+ int dst = networkLayerPDU.getDst();
+
+ if (MeshUtils.validUnicastAddress(dst)) {
+ if (dst != localAddress) {
+ return;
+ }
+ }
+
+ byte[] lowerTransportData = networkLayerPDU.getTransportPDU();
+
+ byte lowerTransportHeader = lowerTransportData[0];
+ int seg = (lowerTransportHeader >> 7) & 0b01;
+ AccessLayerPDU accessPDU;
+ if (seg == 1) {
+ log("parse segmented access message");
+
+ /*
+ * tick refresh if received segment busy
+ */
+ /*if (reliableBusy) {
+ log("refresh reliable tick because of segment network pdu received");
+ restartReliableMessageTimeoutTask();
+ }*/
+ accessPDU = parseSegmentedAccessMessage(networkLayerPDU);
+
+ } else {
+ log("parse unsegmented access message");
+ accessPDU = parseUnsegmentedAccessMessage(networkLayerPDU);
+ }
+
+ if (accessPDU != null) {
+ onAccessPduReceived(src, dst, accessPDU);
+ }
+ }
+
+
+ /**
+ * refresh reliable message status, then invoke message callback
+ */
+ private void onAccessPduReceived(int src, int dst, AccessLayerPDU accessPDU) {
+
+ log(String.format("access pdu received at 0x%04X: opcode -- 0x%04X", src, accessPDU.opcode)
+ + " params -- " + Arrays.bytesToHexString(accessPDU.params, ""));
+ // check reliable message state
+ updateReliableMessage(src, accessPDU);
+ if (mNetworkingBridge != null) {
+ mNetworkingBridge.onMeshMessageReceived(src, dst, accessPDU.opcode, accessPDU.params);
+ }
+ }
+
+ private void updateReliableMessage(int src, AccessLayerPDU accessLayerPDU) {
+ if (!reliableBusy) return;
+ if (mSendingReliableMessage != null && mSendingReliableMessage.getResponseOpcode() == accessLayerPDU.opcode) {
+ mResponseMessageBuffer.add(src);
+ if (mResponseMessageBuffer.size() >= mSendingReliableMessage.getResponseMax()) {
+
+ onReliableMessageComplete(true);
+ }
+ }
+ }
+
+ /**
+ * reliable command complete
+ *
+ * @param success if command response received
+ */
+ private void onReliableMessageComplete(boolean success) {
+ mDelayHandler.removeCallbacks(reliableMessageTimeoutTask);
+ int opcode = mSendingReliableMessage.getOpcode();
+ int rspMax = mSendingReliableMessage.getResponseMax();
+ int rspCount = mResponseMessageBuffer.size();
+ log(String.format("Reliable Message Complete: %06X success?: %b", opcode, success));
+ mResponseMessageBuffer.clear();
+ synchronized (RELIABLE_SEGMENTED_LOCK) {
+ reliableBusy = false;
+ if (success) {
+ if (segmentedBusy && mSendingReliableMessage.isSegmented()) {
+ segmentedBusy = false;
+ stopSegmentedBlockAckWaiting(true, true);
+// mDelayHandler.removeCallbacks(mSegmentBlockWaitingTask);
+ }
+ }
+ }
+ if (mNetworkingBridge != null) {
+ mNetworkingBridge.onReliableMessageComplete(success, opcode, rspMax, rspCount);
+ }
+ }
+
+ /**
+ * start or refresh tick
+ */
+ private void restartReliableMessageTimeoutTask() {
+ log("restart reliable message timeout task, immediate");
+ mDelayHandler.removeCallbacks(reliableMessageTimeoutTask);
+ mDelayHandler.postDelayed(reliableMessageTimeoutTask, getReliableMessageTimeout());
+ }
+
+ private Runnable reliableMessageTimeoutTask = new Runnable() {
+ @Override
+ public void run() {
+ final MeshMessage meshMessage = mSendingReliableMessage;
+ if (meshMessage != null) {
+ log(String.format(Locale.getDefault(), "reliable message retry segmentRxComplete? %B retryCnt: %d %s opcode: %06X", lastSegComplete, meshMessage.getRetryCnt(), meshMessage.getClass().getSimpleName(), meshMessage.getOpcode()));
+ if (lastSegComplete) {
+ if (meshMessage.getRetryCnt() <= 0) {
+ onReliableMessageComplete(false);
+ } else {
+ // resend mesh message
+ meshMessage.setRetryCnt(meshMessage.getRetryCnt() - 1);
+ synchronized (RELIABLE_SEGMENTED_LOCK) {
+ reliableBusy = false;
+ if (segmentedBusy && meshMessage.isSegmented()) {
+ stopSegmentedBlockAckWaiting(true, false);
+ }
+ }
+ postMeshMessage(meshMessage, true);
+ }
+ } else {
+ // receiving rx segment packet
+ restartReliableMessageTimeoutTask();
+ }
+
+
+ }
+ }
+ };
+
+
+ // parse unsegmented access message lower transport PDU
+ private AccessLayerPDU parseUnsegmentedAccessMessage(NetworkLayerPDU networkLayerPDU) {
+ byte[] lowerTransportData = networkLayerPDU.getTransportPDU();
+ byte header = lowerTransportData[0]; //Lower transport pdu starts here
+ int akf = (header >> 6) & 0x01;
+
+ int ivIndex = networkLayerPDU.encryptionSuite.ivIndex;
+
+ UnsegmentedAccessMessagePDU unsegmentedAccessMessagePDU = new UnsegmentedAccessMessagePDU();
+ if (unsegmentedAccessMessagePDU.parse(networkLayerPDU)) {
+
+ UpperTransportAccessPDU.UpperTransportEncryptionSuite upperTransportEncryptionSuite;
+ if (AccessType.DEVICE.akf == akf) {
+ upperTransportEncryptionSuite = new UpperTransportAccessPDU.UpperTransportEncryptionSuite(getDeviceKey(networkLayerPDU.getSrc()), ivIndex);
+ } else {
+ List appKeyList = getAppKeyList();
+ upperTransportEncryptionSuite = new UpperTransportAccessPDU.UpperTransportEncryptionSuite(appKeyList, ivIndex);
+ }
+
+ UpperTransportAccessPDU upperTransportAccessPDU = new UpperTransportAccessPDU(upperTransportEncryptionSuite);
+ boolean decRe = upperTransportAccessPDU.parseAndDecryptUnsegmentedMessage(unsegmentedAccessMessagePDU, networkLayerPDU.getSeq(), networkLayerPDU.getSrc(), networkLayerPDU.getDst());
+ if (decRe) {
+ return AccessLayerPDU.parse(upperTransportAccessPDU.getDecryptedPayload());
+ } else {
+ log("unsegmented access message parse err", MeshLogger.LEVEL_WARN);
+ }
+ }
+ return null;
+ }
+
+ private List getAppKeyList() {
+ if (this.appKeyMap != null && this.appKeyMap.size() != 0) {
+ List appKeyList = new ArrayList<>();
+ for (int i = 0; i < appKeyMap.size(); i++) {
+ appKeyList.add(appKeyMap.get(appKeyMap.keyAt(i)));
+ }
+ return appKeyList;
+ }
+ return null;
+ }
+
+ private void checkSegmentBlock(boolean immediate, int ttl, int src) {
+ if (immediate) {
+ stopSegmentTimeoutTask();
+ } else {
+ restartSegmentTimeoutTask();
+ }
+ mDelayHandler.removeCallbacks(mAccessSegCheckTask);
+ long timeout = immediate ? 0 : getSegmentedTimeout(ttl, false);
+ mAccessSegCheckTask.src = src;
+ mAccessSegCheckTask.ttl = ttl;
+ log("check segment block: immediate-" + immediate + " ttl-" + ttl + " src-" + src + " timeout-" + timeout);
+ mDelayHandler.postDelayed(mAccessSegCheckTask, timeout);
+ }
+
+ private void stopSegmentBlockAckTask() {
+ mDelayHandler.removeCallbacks(mAccessSegCheckTask);
+ }
+
+
+ private void sendSegmentBlockAck(int src, int ttl) {
+ log("send segment block ack:" + src);
+ final SparseArray messages = receivedSegmentedMessageBuffer.clone();
+ if (messages.size() > 0) {
+// int segN = -1;
+ int seqZero = -1;
+ int blockAck = 0;
+ int segO;
+ int segN = -1;
+ SegmentedAccessMessagePDU message;
+ for (int i = 0; i < messages.size(); i++) {
+ segO = messages.keyAt(i);
+ message = messages.get(segO);
+ if (segN == -1) {
+ segN = message.getSegN();
+ }
+ if (seqZero == -1) {
+ seqZero = message.getSeqZero();
+ }
+ blockAck |= (1 << segO);
+ }
+
+ SegmentAcknowledgmentMessage segmentAckMessage = new SegmentAcknowledgmentMessage(seqZero, blockAck);
+ sendSegmentAckMessage(segmentAckMessage, src);
+
+ boolean complete = messages.size() == (segN + 1);
+ if (!complete) {
+ mDelayHandler.removeCallbacks(mAccessSegCheckTask);
+ long timeout = getSegmentedTimeout(ttl, false);
+ mDelayHandler.postDelayed(mAccessSegCheckTask, timeout);
+ }
+ }
+ }
+
+ /**
+ * send segment busy
+ */
+ private void sendSegmentBlockBusyAck(int src, int seqZero, long seqAuth) {
+ log("send segment block busy ack:" + src);
+ saveBusySeqAuth(src, seqAuth);
+ SegmentAcknowledgmentMessage segmentAckMessage = new SegmentAcknowledgmentMessage(seqZero, 0);
+ sendSegmentAckMessage(segmentAckMessage, src);
+ }
+
+ private void sendSegmentAckMessage(SegmentAcknowledgmentMessage segmentAcknowledgmentMessage, int dst) {
+ log("send segment ack: " + segmentAcknowledgmentMessage.toString());
+ sendUnsegmentedControlMessage(segmentAcknowledgmentMessage, dst);
+ }
+
+ private void sendUnsegmentedControlMessage(UnsegmentedControlMessagePDU controlMessagePDU, int dst) {
+ byte[] data = controlMessagePDU.toByteArray();
+ log("send control message: " + Arrays.bytesToHexString(data, ""));
+ int ctl = MeshMessage.CTL_CONTROL;
+ int ttl = 5;
+ int src = localAddress;
+ int ivIndex = getTransmitIvIndex();
+ NetworkLayerPDU networkPDU = createNetworkPDU(data, ctl, ttl, src, dst, ivIndex, mSequenceNumber.get());
+ sendNetworkPdu(networkPDU);
+ }
+
+ /**
+ * not receive any segment with current segAuth
+ */
+ private static final long SEG_TIMEOUT = 10 * 1000;
+ private Runnable segmentTimeoutTask = new Runnable() {
+ @Override
+ public void run() {
+ stopSegmentBlockAckTask();
+ log(String.format(Locale.getDefault(), "segment timeout : lastSeqAuth: 0x%014X -- src: %02d",
+ lastSeqAuth,
+ lastSegSrc));
+ lastSegComplete = true;
+ lastSegSrc = 0;
+ lastSeqAuth = 0;
+ }
+ };
+
+ private void restartSegmentTimeoutTask() {
+ mDelayHandler.removeCallbacks(segmentTimeoutTask);
+ mDelayHandler.postDelayed(segmentTimeoutTask, SEG_TIMEOUT);
+ }
+
+ private void stopSegmentTimeoutTask() {
+ mDelayHandler.removeCallbacks(segmentTimeoutTask);
+ }
+
+ private void sendSegmentCompleteBlockAck(int src, int segN, int seqZero) {
+ int blockAck = 0;
+ for (int i = 0; i < segN + 1; i++) {
+ blockAck |= (1 << i);
+ }
+ SegmentAcknowledgmentMessage segmentAckMessage = new SegmentAcknowledgmentMessage(seqZero, blockAck);
+ sendSegmentAckMessage(segmentAckMessage, src);
+ }
+
+ /**
+ * parse segmented access message
+ * check auth
+ */
+ private AccessLayerPDU parseSegmentedAccessMessage(NetworkLayerPDU networkLayerPDU) {
+ SegmentedAccessMessagePDU message = new SegmentedAccessMessagePDU();
+ message.parse(networkLayerPDU);
+ final int src = networkLayerPDU.getSrc();
+ int ttl = networkLayerPDU.getTtl() & 0xFF;
+ int sequenceNumber = networkLayerPDU.getSeq();
+
+ int seqLowerBitValue = sequenceNumber & SEQ_ZERO_LIMIT;
+
+ int seqZero = message.getSeqZero();
+
+ int seqHigherBitValue;
+ if (seqLowerBitValue < seqZero) {
+ seqHigherBitValue = (sequenceNumber - (SEQ_ZERO_LIMIT + 1)) & 0xFFE000;
+ } else {
+ seqHigherBitValue = sequenceNumber & 0xFFE000;
+ }
+
+ // sequence number of first segmented message
+ int transportSeqNo = seqHigherBitValue | seqZero;
+ int ivIndex = networkLayerPDU.encryptionSuite.ivIndex;
+ // seq auth: ivIndex(32bits) | seqNo(11bits) | seqZero(13bits)
+ // 0x7FFFFFFFL remove highest bit
+ long seqAuth = (transportSeqNo & 0xFFFFFFL) | ((ivIndex & 0x7FFFFFFFL) << 24);
+
+ int segO = message.getSegO();
+ int segN = message.getSegN();
+
+ log(String.format(Locale.getDefault(), "lastComplete? :%B -- seqAuth: 0x%014X -- lastSeqAuth: 0x%014X -- src: 0x%04X -- lastSrc: 0x%04X -- seg0: %02d -- segN: %02d",
+ lastSegComplete,
+ seqAuth,
+ lastSeqAuth,
+ src,
+ lastSegSrc,
+ segO,
+ segN));
+
+ if (isBusyAuthExists(src, seqAuth)) {
+ log("busy auth exists");
+ sendSegmentBlockBusyAck(src, seqZero, seqAuth);
+ return null;
+ }
+
+ if (isCompleteAuthExists(src, seqAuth)) {
+ log("complete auth exists");
+ sendSegmentCompleteBlockAck(src, segN, seqZero);
+ return null;
+ }
+
+ AccessLayerPDU accessPDU = null;
+
+ if (seqAuth != lastSeqAuth || lastSegSrc != src) {
+ if (lastSegComplete) {
+ log("last segment complete");
+ // save last seqAuth
+ saveCompletedSeqAuth(lastSegSrc, lastSeqAuth);
+ lastSegComplete = false;
+ // new segment message
+ lastSeqAuth = seqAuth;
+ lastSegSrc = src;
+ receivedSegmentedMessageBuffer.clear();
+ } else {
+ sendSegmentBlockBusyAck(src, seqZero, seqAuth);
+ return null;
+ }
+ }
+
+ /* if (seqAuth != lastSeqAuth || lastSegSrc != src) {
+ if (lastSegComplete) {
+ log("last segment complete");
+ // save last seqAuth
+ saveCompletedSeqAuth(lastSegSrc, lastSeqAuth);
+ lastSegComplete = false;
+ // new segment message
+ lastSeqAuth = seqAuth;
+ lastSegSrc = src;
+ receivedSegmentedMessageBuffer.clear();
+ receivedSegmentedMessageBuffer.put(segO, message);
+ checkSegmentBlock(false, ttl, src);
+ } else {
+ sendSegmentBlockBusyAck(src, seqZero, seqAuth);
+ }
+ } else*/
+ {
+ receivedSegmentedMessageBuffer.put(segO, message);
+
+ int messageCnt = receivedSegmentedMessageBuffer.size();
+ log("received segment message count: " + messageCnt);
+
+ if (messageCnt != segN + 1) {
+ lastSeqAuth = seqAuth;
+ checkSegmentBlock(false, ttl, src);
+ } else {
+ lastSegComplete = true;
+ checkSegmentBlock(true, ttl, src);
+ if (isCompleteAuthExists(src, seqAuth)) {
+ log(" seqAuth already received: " + seqAuth);
+ lastSeqAuth = 0;
+ return null;
+ }
+ UpperTransportAccessPDU.UpperTransportEncryptionSuite encryptionSuite;
+ int akf = message.getAkf();
+ if (akf == AccessType.APPLICATION.akf) {
+ encryptionSuite = new UpperTransportAccessPDU.UpperTransportEncryptionSuite(getAppKeyList(), ivIndex);
+ } else {
+ byte[] deviceKey = getDeviceKey(src);
+ if (deviceKey == null) {
+ log("Device key not found when decrypt segmented access message", MeshLogger.LEVEL_WARN);
+ return null;
+ }
+ encryptionSuite = new UpperTransportAccessPDU.UpperTransportEncryptionSuite(deviceKey, ivIndex);
+ }
+
+ UpperTransportAccessPDU upperTransportAccessPDU = new UpperTransportAccessPDU(encryptionSuite);
+ upperTransportAccessPDU.parseAndDecryptSegmentedMessage(receivedSegmentedMessageBuffer.clone(), transportSeqNo, src, networkLayerPDU.getDst());
+
+ byte[] completeTransportPdu = upperTransportAccessPDU.getDecryptedPayload();
+
+ log("decrypted upper: " + Arrays.bytesToHexString(completeTransportPdu, ""));
+ if (completeTransportPdu != null) {
+ accessPDU = AccessLayerPDU.parse(completeTransportPdu);
+ } else {
+ log("upper pdu decryption error: ", MeshLogger.LEVEL_WARN);
+ }
+ }
+ }
+ return accessPDU;
+ }
+
+
+ private UpperTransportAccessPDU createUpperTransportAccessPDU(byte[] accessPDU, byte[] key, byte szmic, AccessType accessType, int ivIndex, int seqNo, int src, int dst) {
+
+ UpperTransportAccessPDU.UpperTransportEncryptionSuite encryptionSuite;
+
+
+ if (accessType == AccessType.APPLICATION) {
+ List appKeyList = new ArrayList<>();
+ appKeyList.add(key);
+ encryptionSuite = new UpperTransportAccessPDU.UpperTransportEncryptionSuite(appKeyList, ivIndex);
+ } else {
+ encryptionSuite = new UpperTransportAccessPDU.UpperTransportEncryptionSuite(key, ivIndex);
+ }
+ UpperTransportAccessPDU upperTransportAccessPDU =
+ new UpperTransportAccessPDU(encryptionSuite);
+ if (upperTransportAccessPDU.encrypt(accessPDU, szmic, accessType, seqNo, src, dst)) {
+ return upperTransportAccessPDU;
+ } else {
+ return null;
+ }
+
+
+ }
+
+
+ /*private SparseArray createLowerTransportPDU(byte[] upperTransportPDU, byte akf, byte aid, int aszmic, int seqNo) {
+ SparseArray lowerTransportPduMap;
+ if (upperTransportPDU.length <= UNSEGMENTED_TRANSPORT_PAYLOAD_MAX_LENGTH) {
+ LowerTransportPDU lowerTransportPDU = createUnsegmentedAccessMessage(upperTransportPDU, akf, aid);
+ lowerTransportPduMap = new SparseArray<>();
+ lowerTransportPduMap.put(0, lowerTransportPDU);
+ } else {
+ lowerTransportPduMap = createSegmentedAccessMessage(upperTransportPDU, akf, aid, aszmic, seqNo);
+ }
+ return lowerTransportPduMap;
+ }*/
+
+ private SparseArray createSegmentedAccessMessage(byte[] encryptedUpperTransportPDU, byte akf, byte aid, int aszmic, int sequenceNumber) {
+
+ final int segmentedAccessLen = unsegmentedAccessLength + 1;
+ byte[] seqNoBuffer = MeshUtils.integer2Bytes(sequenceNumber, 3, ByteOrder.BIG_ENDIAN);
+ // 13 lowest bits
+ int seqZero = ((seqNoBuffer[1] & 0x1F) << 8) | (seqNoBuffer[2] & 0xFF);
+
+ // segment pdu number
+ int segNum = (int) Math.ceil(((double) encryptedUpperTransportPDU.length) / segmentedAccessLen); // SEGMENTED_ACCESS_PAYLOAD_MAX_LENGTH
+ int segN = segNum - 1; // index from 0
+ log("create segmented access message: seqZero - " + seqZero + " segN - " + segN);
+
+ SparseArray lowerTransportPDUArray = new SparseArray<>();
+ int offset = 0;
+ int segmentedLength;
+ SegmentedAccessMessagePDU lowerTransportPDU;
+ for (int segOffset = 0; segOffset < segNum; segOffset++) {
+ segmentedLength = Math.min(encryptedUpperTransportPDU.length - offset, segmentedAccessLen);
+ lowerTransportPDU = new SegmentedAccessMessagePDU();
+ lowerTransportPDU.setAkf(akf);
+ lowerTransportPDU.setAid(aid);
+ lowerTransportPDU.setSzmic(aszmic);
+ lowerTransportPDU.setSeqZero(seqZero);
+ lowerTransportPDU.setSegO(segOffset);
+ lowerTransportPDU.setSegN(segN);
+ lowerTransportPDU.setSegmentM(ByteBuffer.allocate(segmentedLength).put(encryptedUpperTransportPDU, offset, segmentedLength).array());
+ offset += segmentedLength;
+ lowerTransportPDUArray.put(segOffset, lowerTransportPDU);
+
+ }
+ return lowerTransportPDUArray;
+ }
+
+
+ private UnsegmentedAccessMessagePDU createUnsegmentedAccessMessage(byte[] upperTransportPDU, byte akf, byte aid) {
+ return new UnsegmentedAccessMessagePDU(akf, aid, upperTransportPDU);
+ }
+
+ private NetworkLayerPDU createNetworkPDU(byte[] transportPdu,
+ int ctl, int ttl, int src, int dst, int ivIndex, int sequenceNumber) {
+ NetworkLayerPDU networkLayerPDU = new NetworkLayerPDU(
+ new NetworkLayerPDU.NetworkEncryptionSuite(ivIndex, this.encryptionKey, this.privacyKey, this.nid)
+ );
+ networkLayerPDU.setIvi((byte) (ivIndex & 0x01));
+ networkLayerPDU.setNid(this.nid);
+ networkLayerPDU.setCtl((byte) ctl);
+ networkLayerPDU.setTtl((byte) ttl);
+ networkLayerPDU.setSeq(sequenceNumber);
+ networkLayerPDU.setSrc(src);
+ networkLayerPDU.setDst(dst);
+ networkLayerPDU.setTransportPDU(transportPdu);
+
+ // for every network pdu , sequence number should increase
+ increaseSequenceNumber();
+ return networkLayerPDU;
+ }
+
+ private ProxyConfigurationPDU createProxyConfigurationPdu(byte[] transportPdu, int src, int ivIndex, int sequenceNumber) {
+ ProxyConfigurationPDU networkLayerPDU = new ProxyConfigurationPDU(
+ new NetworkLayerPDU.NetworkEncryptionSuite(ivIndex, this.encryptionKey, this.privacyKey, this.nid)
+ );
+ networkLayerPDU.setIvi((byte) (ivIndex & 0x01));
+ networkLayerPDU.setNid(this.nid);
+ networkLayerPDU.setCtl(ProxyConfigurationPDU.ctl);
+ networkLayerPDU.setTtl(ProxyConfigurationPDU.ttl);
+ networkLayerPDU.setSeq(sequenceNumber);
+ networkLayerPDU.setSrc(src);
+ networkLayerPDU.setDst(ProxyConfigurationPDU.dst);
+ networkLayerPDU.setTransportPDU(transportPdu);
+
+ // for every network pdu , sequence number should increase
+ increaseSequenceNumber();
+ return networkLayerPDU;
+ }
+
+ private class SegmentAckMessageSentTask implements Runnable {
+ private int src;
+ private int ttl;
+
+ @Override
+ public void run() {
+ sendSegmentBlockAck(src, ttl);
+ }
+ }
+
+ private class SegmentedMessageTimeoutTask implements Runnable {
+ @Override
+ public void run() {
+ log("segmented message timeout");
+ stopSegmentedBlockAckWaiting(true, false);
+ }
+ }
+
+ private class SegmentBlockWaitingTask implements Runnable {
+ private int ctl;
+ private int ttl;
+ private int src;
+ private int dst;
+
+ public void resetParams(int ctl, int ttl, int src, int dst) {
+ this.ctl = ctl;
+ this.ttl = ttl;
+ this.src = src;
+ this.dst = dst;
+ }
+
+ @Override
+ public void run() {
+ resendSegmentedMessages(-1, 0);
+ }
+ }
+
+
+ private void log(String logMessage) {
+ log(logMessage, MeshLogger.LEVEL_DEBUG);
+ }
+
+ private void log(String logMessage, int level) {
+ MeshLogger.log(logMessage, LOG_TAG, level);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkingPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkingPDU.java
new file mode 100644
index 00000000..e7e2d82a
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NetworkingPDU.java
@@ -0,0 +1,37 @@
+/********************************************************************************************************
+ * @file NetworkingPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking;
+
+/**
+ * Created by kee on 2019/8/14.
+ */
+
+public interface NetworkingPDU {
+
+ /**
+ * parse PDU byte data to instance
+ *
+ * @return instance
+ */
+// T parse(byte[] data);
+ byte[] toByteArray();
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NonceGenerator.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NonceGenerator.java
new file mode 100644
index 00000000..2d57ee1d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/NonceGenerator.java
@@ -0,0 +1,99 @@
+/********************************************************************************************************
+ * @file NonceGenerator.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/12.
+ */
+
+public class NonceGenerator {
+
+ private static final int NONCE_LENGTH = 13;
+
+ /**
+ * Used with an encryption key for network authentication and encryption
+ */
+ private static final byte NONCE_TYPE_NETWORK = 0x00;
+
+ /**
+ * Used with an application key for upper transport authentication and encryption
+ */
+ private static final byte NONCE_TYPE_APPLICATION = 0x01;
+
+ /**
+ * Used with a device key for upper transport authentication and encryption
+ */
+ private static final byte NONCE_TYPE_DEVICE = 0x02;
+
+ /**
+ * Used with an encryption key for proxy authentication and encryption
+ */
+ private static final byte NONCE_TYPE_PROXY = 0x03;
+
+ private static final byte NONCE_PADDING = 0x00;
+
+ public static byte[] generateNetworkNonce(byte ctlTTL, byte[] sequenceNumber, int src, int ivIndex) {
+ final ByteBuffer networkNonce = ByteBuffer.allocate(13).order(ByteOrder.BIG_ENDIAN);
+ networkNonce.put(NONCE_TYPE_NETWORK); //Nonce typeValue
+ networkNonce.put(ctlTTL); // CTL and TTL
+ networkNonce.put(sequenceNumber);
+ networkNonce.putShort((short) src);
+ networkNonce.put(new byte[]{0x00, 0x00}); //PADDING
+ networkNonce.putInt(ivIndex);
+ return networkNonce.array();
+ }
+
+ /**
+ * output application or device nonce
+ *
+ * @param aszmic SZMIC if a Segmented Access message or 0 for all other message formats
+ * @param accessType if Application or Device command
+ */
+ public static byte[] generateAccessNonce(byte aszmic, byte[] sequenceNumber, int src, int dst, int ivIndex, AccessType accessType) {
+ ByteBuffer accessNonceBuf = ByteBuffer.allocate(NONCE_LENGTH).order(ByteOrder.BIG_ENDIAN);
+ byte type = accessType == AccessType.APPLICATION ? NONCE_TYPE_APPLICATION : NONCE_TYPE_DEVICE;
+ accessNonceBuf.put(type); //Nonce typeValue
+ accessNonceBuf.put((byte) ((aszmic << 7) | NONCE_PADDING)); //ASZMIC (SZMIC if a segmented access message) and PAD
+ accessNonceBuf.put(sequenceNumber);
+ accessNonceBuf.putShort((short) src);
+ accessNonceBuf.putShort((short) dst);
+ accessNonceBuf.putInt(ivIndex);
+ return accessNonceBuf.array();
+ }
+
+ /**
+ * output proxy nonce
+ */
+ public static byte[] generateProxyNonce(byte[] sequenceNumber, int src, int ivIndex) {
+ ByteBuffer applicationNonceBuffer = ByteBuffer.allocate(NONCE_LENGTH);
+ applicationNonceBuffer.put(NONCE_TYPE_PROXY); //Nonce typeValue
+ applicationNonceBuffer.put(NONCE_PADDING); //PAD
+ applicationNonceBuffer.put(sequenceNumber);
+ applicationNonceBuffer.putShort((short) src);
+ applicationNonceBuffer.put(new byte[]{NONCE_PADDING, NONCE_PADDING});
+ applicationNonceBuffer.putInt(ivIndex);
+ return applicationNonceBuffer.array();
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/beacon/MeshBeaconPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/beacon/MeshBeaconPDU.java
new file mode 100644
index 00000000..ad178675
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/beacon/MeshBeaconPDU.java
@@ -0,0 +1,41 @@
+/********************************************************************************************************
+ * @file MeshBeaconPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.beacon;
+
+import com.telink.ble.mesh.core.provisioning.pdu.PDU;
+
+/**
+ * Created by kee on 2019/11/18.
+ */
+
+public abstract class MeshBeaconPDU implements PDU {
+
+ public static final byte BEACON_TYPE_UNPROVISIONED_DEVICE = 0x00;
+
+ public static final byte BEACON_TYPE_SECURE_NETWORK = 0x01;
+
+ protected byte beaconType;
+
+ protected byte[] beaconData;
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/beacon/SecureNetworkBeacon.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/beacon/SecureNetworkBeacon.java
new file mode 100644
index 00000000..597f374f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/beacon/SecureNetworkBeacon.java
@@ -0,0 +1,189 @@
+/********************************************************************************************************
+ * @file SecureNetworkBeacon.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.beacon;
+
+import com.telink.ble.mesh.core.Encipher;
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.util.Arrays;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class SecureNetworkBeacon extends MeshBeaconPDU {
+
+ private static final int LENGTH_PAYLOAD = 22;
+
+ private static final int MASK_KEY_REFRESH = 0b01;
+
+ private static final int MASK_IV_UPDATE = 0b10;
+
+ private final byte beaconType = BEACON_TYPE_SECURE_NETWORK;
+
+ /**
+ * Contains the Key Refresh Flag and IV Update Flag
+ */
+ private byte flags;
+
+ /**
+ * Contains the value of the Network ID
+ * 8 bytes
+ */
+ private byte[] networkID;
+
+ /**
+ * Contains the current IV Index
+ * 4 bytes
+ * big endian
+ */
+ private int ivIndex;
+
+ /**
+ * Authenticates security network beacon
+ * 8 bytes
+ */
+ private byte[] authenticationValue;
+
+
+ /**
+ * @return if is key refreshing
+ */
+ public boolean isKeyRefreshing() {
+ return (flags & MASK_KEY_REFRESH) != 0;
+ }
+
+ /**
+ * @return if is iv updating
+ */
+ public boolean isIvUpdating() {
+ return (flags & MASK_IV_UPDATE) != 0;
+ }
+
+ public static SecureNetworkBeacon from(byte[] payload) {
+ if (payload.length != LENGTH_PAYLOAD) {
+ return null;
+ }
+ int index = 0;
+ final byte beaconType = payload[index++];
+ if (beaconType != BEACON_TYPE_SECURE_NETWORK) return null;
+ SecureNetworkBeacon beacon = new SecureNetworkBeacon();
+ beacon.flags = payload[index++];
+ beacon.networkID = new byte[8];
+ System.arraycopy(payload, index, beacon.networkID, 0, beacon.networkID.length);
+ index += beacon.networkID.length;
+ beacon.ivIndex = MeshUtils.bytes2Integer(payload, index, 4, ByteOrder.BIG_ENDIAN);
+ index += 4;
+ beacon.authenticationValue = new byte[8];
+ System.arraycopy(payload, index, beacon.authenticationValue, 0, beacon.authenticationValue.length);
+ return beacon;
+ }
+
+ public static SecureNetworkBeacon createIvUpdatingBeacon(int curIvIndex, byte[] networkId, byte[] beaconKey, boolean updating) {
+ SecureNetworkBeacon networkBeacon = new SecureNetworkBeacon();
+ networkBeacon.flags = (byte) (updating ? 0b10 : 0);
+ networkBeacon.networkID = networkId;
+ networkBeacon.ivIndex = updating ? curIvIndex + 1 : curIvIndex;
+
+ final int calLen = 1 + 8 + 4;
+ ByteBuffer buffer = ByteBuffer.allocate(calLen).order(ByteOrder.BIG_ENDIAN);
+ buffer.put(networkBeacon.flags);
+ buffer.put(networkBeacon.networkID);
+ buffer.putInt(networkBeacon.ivIndex);
+ byte[] auth = Encipher.aesCmac(buffer.array(), beaconKey);
+ byte[] authCal = new byte[8];
+ System.arraycopy(auth, 0, authCal, 0, authCal.length);
+ networkBeacon.authenticationValue = authCal;
+ return networkBeacon;
+ }
+
+ public boolean validateAuthValue(byte[] networkID, byte[] beaconKey) {
+ if (!Arrays.equals(this.networkID, networkID)) return false;
+ if (authenticationValue == null) return false;
+
+ // flags, networkId, ivIndex
+ final int calLen = 1 + 8 + 4;
+ ByteBuffer buffer = ByteBuffer.allocate(calLen).order(ByteOrder.BIG_ENDIAN);
+ buffer.put(flags);
+ buffer.put(networkID);
+ buffer.putInt(ivIndex);
+ byte[] auth = Encipher.aesCmac(buffer.array(), beaconKey);
+ byte[] authCal = new byte[8];
+ System.arraycopy(auth, 0, authCal, 0, authCal.length);
+ return Arrays.equals(authCal, this.authenticationValue);
+ }
+
+ @Override
+ public String toString() {
+ return "SecureNetworkBeacon{" +
+ "beaconType=" + beaconType +
+ ", flags=" + flags +
+ ", networkID=" + Arrays.bytesToHexString(networkID, "") +
+ ", ivIndex=0x" + String.format("%08X", ivIndex) +
+ ", authenticationValue=" + Arrays.bytesToHexString(authenticationValue, "") +
+ '}';
+ }
+
+ public byte getBeaconType() {
+ return beaconType;
+ }
+
+
+ public byte getFlags() {
+ return flags;
+ }
+
+ public void setFlags(byte flags) {
+ this.flags = flags;
+ }
+
+ public byte[] getNetworkID() {
+ return networkID;
+ }
+
+ public void setNetworkID(byte[] networkID) {
+ this.networkID = networkID;
+ }
+
+ public int getIvIndex() {
+ return ivIndex;
+ }
+
+ public void setIvIndex(int ivIndex) {
+ this.ivIndex = ivIndex;
+ }
+
+ public byte[] getAuthenticationValue() {
+ return authenticationValue;
+ }
+
+ public void setAuthenticationValue(byte[] authenticationValue) {
+ this.authenticationValue = authenticationValue;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ ByteBuffer buffer1 = ByteBuffer.allocate(LENGTH_PAYLOAD).order(ByteOrder.BIG_ENDIAN);
+ buffer1.put(beaconType).put(flags).put(networkID)
+ .putInt(ivIndex).put(authenticationValue);
+ return buffer1.array();
+
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/LowerTransportPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/LowerTransportPDU.java
new file mode 100644
index 00000000..2034db8c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/LowerTransportPDU.java
@@ -0,0 +1,63 @@
+/********************************************************************************************************
+ * @file LowerTransportPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.transport.lower;
+
+import com.telink.ble.mesh.core.networking.NetworkingPDU;
+
+/**
+ * big endian
+ * transport: access message, control message
+ * Created by kee on 2019/7/22.
+ */
+public abstract class LowerTransportPDU implements NetworkingPDU {
+
+ public static int TYPE_UNSEGMENTED_ACCESS_MESSAGE = 0xb00;
+
+ public static int TYPE_SEGMENTED_ACCESS_MESSAGE = 0xb01;
+
+ public static int TYPE_UNSEGMENTED_CONTROL_MESSAGE = 0xb10;
+
+ public static int TYPE_SEGMENTED_CONTROL_MESSAGE = 0xb11;
+
+
+ public static int SEG_TYPE_UNSEGMENTED = 0;
+
+ public static int SEG_TYPE_SEGMENTED = 1;
+
+ protected int seg;
+
+ /**
+ * get pdu typeValue
+ *
+ * @return PDU typeValue
+ */
+ public abstract int getType();
+
+ /**
+ * segmented state, determined by seg bit significant
+ *
+ * @return if is a segment pdu
+ */
+ public abstract boolean segmented();
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/SegmentAcknowledgmentMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/SegmentAcknowledgmentMessage.java
new file mode 100644
index 00000000..bd404c63
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/SegmentAcknowledgmentMessage.java
@@ -0,0 +1,123 @@
+/********************************************************************************************************
+ * @file SegmentAcknowledgmentMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.transport.lower;
+
+import com.telink.ble.mesh.core.MeshUtils;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/16.
+ */
+
+public class SegmentAcknowledgmentMessage extends UnsegmentedControlMessagePDU {
+ public static final int DATA_LEN = 7;
+
+ /**
+ * 1 bit
+ */
+ private final int seg = 0;
+
+ /**
+ * 7 bits
+ */
+ private final int opcode = 0x00;
+
+ /**
+ * The OBO field shall be set to 0 by a node that is directly addressed by the received message
+ * and shall be set to 1 by a Friend node that is acknowledging this message on behalf of a Low Power node.
+ *
+ * As provisioner, obo is always 0
+ * 1 bit
+ */
+ private final int obo = 0;
+
+ /**
+ * SeqZero of the Upper Transport PDU
+ */
+ private int seqZero;
+
+ private final int rfu = 0;
+
+ /**
+ * Block acknowledgment for segments
+ * 32 bits
+ * If bit n is set to 0, then segment n is not being acknowledged.
+ * Any bits for segments larger than SegN shall be set to 0 and ignored upon receipt.
+ */
+ private int blockAck = 0;
+
+ public boolean parse(byte[] lowerTransportData) {
+ if (lowerTransportData.length != DATA_LEN) return false;
+// int seqZero = ((lowerTransportData[1] & 0x7F) << 6) | ((lowerTransportData[2] & 0xFF) >> 2);
+ int seqZero = MeshUtils.bytes2Integer(new byte[]{lowerTransportData[1], lowerTransportData[2]}
+ , ByteOrder.BIG_ENDIAN);
+ seqZero = (seqZero & 0x7FFF) >> 2;
+ this.seqZero = seqZero;
+ this.blockAck = MeshUtils.bytes2Integer(new byte[]{
+ lowerTransportData[3],
+ lowerTransportData[4],
+ lowerTransportData[5],
+ lowerTransportData[6],
+ }, ByteOrder.BIG_ENDIAN);
+ return true;
+ }
+
+ public SegmentAcknowledgmentMessage() {
+ }
+
+ public SegmentAcknowledgmentMessage(int seqZero, int blockAck) {
+ this.seqZero = seqZero;
+ this.blockAck = blockAck;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ return ByteBuffer.allocate(DATA_LEN).order(ByteOrder.BIG_ENDIAN)
+ .put((byte) ((seg << 7) | opcode))
+ .put((byte) ((obo << 7) | ((seqZero >> 6) & 0x7F)))
+ .put((byte) (((seqZero << 2) & 0xFC) | rfu))
+ .putInt(blockAck).array();
+
+ }
+
+ @Override
+ public String toString() {
+ return "SegmentAcknowledgmentMessage{" +
+ "seg=" + seg +
+ ", opcode=" + opcode +
+ ", obo=" + obo +
+ ", seqZero=" + seqZero +
+ ", rfu=" + rfu +
+ ", blockAck=" + blockAck +
+ '}';
+ }
+
+ public int getSeqZero() {
+ return seqZero;
+ }
+
+ public int getBlockAck() {
+ return blockAck;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/SegmentedAccessMessagePDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/SegmentedAccessMessagePDU.java
new file mode 100644
index 00000000..71ece06e
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/SegmentedAccessMessagePDU.java
@@ -0,0 +1,175 @@
+/********************************************************************************************************
+ * @file SegmentedAccessMessagePDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.transport.lower;
+
+import com.telink.ble.mesh.core.networking.NetworkLayerPDU;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/9.
+ */
+
+public class SegmentedAccessMessagePDU extends LowerTransportPDU {
+
+
+ /**
+ * 1 = Segmented MeshCommand
+ */
+ private final byte seg = 1;
+
+ /**
+ * Application Key Flag
+ */
+ private byte akf;
+
+ /**
+ * Application key identifier
+ */
+ private byte aid;
+
+ /**
+ * Size of TransMIC
+ */
+ private int szmic;
+
+ /**
+ * Least significant bits of SeqAuth
+ */
+ private int seqZero;
+
+ /**
+ * Segment Offset number
+ */
+ private int segO;
+
+ /**
+ * Last Segment number
+ */
+ private int segN;
+
+ /**
+ * Segment m of the Upper Transport Access PDU
+ */
+ private byte[] segmentM;
+
+
+ @Override
+ public int getType() {
+ return TYPE_SEGMENTED_ACCESS_MESSAGE;
+ }
+
+ @Override
+ public boolean segmented() {
+ return true;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ int headerLength = 4;
+ final int akfAid = ((akf << 6) | aid);
+ int payloadLength = segmentM.length;
+ ByteBuffer resultBuffer = ByteBuffer.allocate(headerLength + payloadLength).order(ByteOrder.BIG_ENDIAN);
+ resultBuffer.put((byte) ((seg << 7) | akfAid));
+ resultBuffer.put((byte) ((szmic << 7) | ((seqZero >> 6) & 0x7F)));
+ resultBuffer.put((byte) (((seqZero << 2) & 0xFC) | ((segO >> 3) & 0x03)));
+ resultBuffer.put((byte) (((segO << 5) & 0xE0) | ((segN) & 0x1F)));
+ resultBuffer.put(segmentM);
+ return resultBuffer.array();
+ }
+
+ public boolean parse(NetworkLayerPDU networkLayerPDU) {
+ byte[] lowerTransportPdu = networkLayerPDU.getTransportPDU();
+ this.akf = (byte) ((lowerTransportPdu[0] >> 6) & 0x01);
+ this.aid = (byte) (lowerTransportPdu[0] & 0x3F);
+ this.szmic = (lowerTransportPdu[1] >> 7) & 0x01;
+ this.seqZero = ((lowerTransportPdu[1] & 0x7F) << 6) | ((lowerTransportPdu[2] & 0xFC) >> 2);
+ this.segO = ((lowerTransportPdu[2] & 0x03) << 3) | ((lowerTransportPdu[3] & 0xE0) >> 5);
+ this.segN = ((lowerTransportPdu[3]) & 0x1F);
+
+ this.segmentM = new byte[lowerTransportPdu.length - 4];
+ System.arraycopy(lowerTransportPdu, 4, this.segmentM, 0, this.segmentM.length);
+ return this.segmentM != null && this.segmentM.length >= 1;
+ }
+
+
+ public byte getSeg() {
+ return seg;
+ }
+
+ public byte getAkf() {
+ return akf;
+ }
+
+ public void setAkf(byte akf) {
+ this.akf = akf;
+ }
+
+ public byte getAid() {
+ return aid;
+ }
+
+ public void setAid(byte aid) {
+ this.aid = aid;
+ }
+
+ public int getSzmic() {
+ return szmic;
+ }
+
+ public void setSzmic(int szmic) {
+ this.szmic = szmic;
+ }
+
+ public int getSeqZero() {
+ return seqZero;
+ }
+
+ public void setSeqZero(int seqZero) {
+ this.seqZero = seqZero;
+ }
+
+ public int getSegO() {
+ return segO;
+ }
+
+ public void setSegO(int segO) {
+ this.segO = segO;
+ }
+
+ public int getSegN() {
+ return segN;
+ }
+
+ public void setSegN(int segN) {
+ this.segN = segN;
+ }
+
+ public byte[] getSegmentM() {
+ return segmentM;
+ }
+
+ public void setSegmentM(byte[] segmentM) {
+ this.segmentM = segmentM;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/SegmentedControlMessagePDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/SegmentedControlMessagePDU.java
new file mode 100644
index 00000000..e264111a
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/SegmentedControlMessagePDU.java
@@ -0,0 +1,104 @@
+/********************************************************************************************************
+ * @file SegmentedControlMessagePDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.transport.lower;
+
+import com.telink.ble.mesh.core.networking.NetworkLayerPDU;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/9.
+ */
+
+public class SegmentedControlMessagePDU extends LowerTransportPDU {
+
+
+ /**
+ * 1 = Segmented MeshCommand
+ */
+ private final byte seg = 1;
+
+ /**
+ * 0x00 = Reserved
+ * 0x01 to 0x7F = Opcode of the Transport Control message
+ */
+ private int opcode;
+
+ private int RFU = 0;
+
+ private int seqZero;
+
+ /**
+ * Segment Offset number
+ */
+ private int segO;
+
+ /**
+ * Last Segment number
+ */
+ private int segN;
+
+ /**
+ * Segment m of the Upper Transport Access PDU
+ */
+ private byte[] segmentM;
+
+
+ @Override
+ public int getType() {
+ return TYPE_SEGMENTED_ACCESS_MESSAGE;
+ }
+
+ @Override
+ public boolean segmented() {
+ return true;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ int headerLength = 4;
+ int payloadLength = segmentM.length;
+ ByteBuffer resultBuffer = ByteBuffer.allocate(headerLength + payloadLength).order(ByteOrder.BIG_ENDIAN);
+ resultBuffer.put((byte) ((seg << 7) | opcode));
+ resultBuffer.put((byte) ((RFU << 7) | ((seqZero >> 6) & 0x7F)));
+ resultBuffer.put((byte) (((seqZero << 2) & 0xFC) | ((segO >> 3) & 0x03)));
+ resultBuffer.put((byte) (((segO << 5) & 0xE0) | ((segN) & 0x1F)));
+ resultBuffer.put(segmentM);
+ return resultBuffer.array();
+ }
+
+ public boolean parse(NetworkLayerPDU networkLayerPDU) {
+ byte[] lowerTransportPdu = networkLayerPDU.getTransportPDU();
+ this.opcode = (byte) (lowerTransportPdu[0] & 0x7F);
+ this.RFU = (lowerTransportPdu[1] >> 7) & 0x01;
+ this.seqZero = ((lowerTransportPdu[1] & 0x7F) << 6) | ((lowerTransportPdu[2] & 0xFC) >> 2);
+ this.segO = ((lowerTransportPdu[2] & 0x03) << 3) | ((lowerTransportPdu[3] & 0xE0) >> 5);
+ this.segN = ((lowerTransportPdu[3]) & 0x1F);
+
+ this.segmentM = new byte[lowerTransportPdu.length - 4];
+ System.arraycopy(lowerTransportPdu, 4, this.segmentM, 0, this.segmentM.length);
+ return this.segmentM != null || this.segmentM.length >= 1;
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/TransportControlMessagePDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/TransportControlMessagePDU.java
new file mode 100644
index 00000000..f09e2463
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/TransportControlMessagePDU.java
@@ -0,0 +1,39 @@
+/********************************************************************************************************
+ * @file TransportControlMessagePDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.transport.lower;
+
+/**
+ * Created by kee on 2019/8/22.
+ */
+
+public abstract class TransportControlMessagePDU extends LowerTransportPDU {
+ public static final int CONTROL_MESSAGE_OPCODE_SEG_ACK = 0x00;
+
+
+ /*
+ other values defined in
+ spec#3.6.5.11 Summary of opcodes
+ */
+
+ public static final int CONTROL_MESSAGE_OPCODE_HEARTBEAT = 0x0A;
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/UnsegmentedAccessMessagePDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/UnsegmentedAccessMessagePDU.java
new file mode 100644
index 00000000..fee4efb2
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/UnsegmentedAccessMessagePDU.java
@@ -0,0 +1,129 @@
+/********************************************************************************************************
+ * @file UnsegmentedAccessMessagePDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.transport.lower;
+
+import com.telink.ble.mesh.core.networking.NetworkLayerPDU;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/9.
+ */
+
+public class UnsegmentedAccessMessagePDU extends LowerTransportPDU {
+
+ // segment
+ /**
+ * 1 bit
+ * 0: unsegmented , means a single PDU
+ * 1: segment
+ */
+ private final byte seg = 0;
+
+ /**
+ * 1 bit
+ * Application Key Flag
+ */
+ private byte akf;
+
+ /**
+ * 6 bits
+ * Application key identifier
+ */
+ private byte aid;
+
+ /**
+ * 40 to 120 bits
+ */
+ private byte[] upperTransportPDU;
+
+ public UnsegmentedAccessMessagePDU() {
+
+ }
+
+
+ public UnsegmentedAccessMessagePDU(byte akf, byte aid, byte[] upperTransportPDU) {
+ this.akf = akf;
+ this.aid = aid;
+ this.upperTransportPDU = upperTransportPDU;
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_UNSEGMENTED_ACCESS_MESSAGE;
+ }
+
+ @Override
+ public boolean segmented() {
+ return false;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ byte oct0 = (byte) ((seg << 7) | (akf << 6) | aid);
+ ByteBuffer lowerTransportBuffer = ByteBuffer.allocate(1 + upperTransportPDU.length).order(ByteOrder.BIG_ENDIAN);
+ lowerTransportBuffer.put(oct0);
+ lowerTransportBuffer.put(upperTransportPDU);
+ return lowerTransportBuffer.array();
+ }
+
+ public boolean parse(NetworkLayerPDU networkLayerPDU) {
+ byte[] lowerTransportData = networkLayerPDU.getTransportPDU();
+ byte header = lowerTransportData[0]; //Lower transport pdu starts here
+ this.akf = (byte) ((header >> 6) & 0x01);
+ this.aid = (byte) (header & 0x3F);
+ byte[] upperTransportPDU = new byte[lowerTransportData.length - 1];
+ System.arraycopy(lowerTransportData, 1, upperTransportPDU, 0, upperTransportPDU.length);
+ this.upperTransportPDU = upperTransportPDU;
+ return upperTransportPDU.length != 0;
+ }
+
+
+ public byte getSeg() {
+ return seg;
+ }
+
+ public byte getAkf() {
+ return akf;
+ }
+
+ public void setAkf(byte akf) {
+ this.akf = akf;
+ }
+
+ public byte getAid() {
+ return aid;
+ }
+
+ public void setAid(byte aid) {
+ this.aid = aid;
+ }
+
+ public byte[] getUpperTransportPDU() {
+ return upperTransportPDU;
+ }
+
+ public void setUpperTransportPDU(byte[] upperTransportPDU) {
+ this.upperTransportPDU = upperTransportPDU;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/UnsegmentedControlMessagePDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/UnsegmentedControlMessagePDU.java
new file mode 100644
index 00000000..77b11dda
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/lower/UnsegmentedControlMessagePDU.java
@@ -0,0 +1,72 @@
+/********************************************************************************************************
+ * @file UnsegmentedControlMessagePDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.transport.lower;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Created by kee on 2019/8/16.
+ */
+
+public class UnsegmentedControlMessagePDU extends LowerTransportPDU {
+
+ /**
+ * 1 bit
+ */
+ final int seg = 0;
+
+ /**
+ * 0x00 = Segment Acknowledgment
+ * 0x01 to 0x7F = Opcode of the Transport Control message
+ * 7 bits
+ */
+ private int opcode;
+
+ /**
+ * 0 ~ 88 bits
+ */
+ byte[] params;
+
+
+ @Override
+ public byte[] toByteArray() {
+ byte header = (byte) ((seg << 7) | (opcode));
+ if (params == null) {
+ return new byte[]{header};
+ }
+ ByteBuffer byteBuffer = ByteBuffer.allocate(1 + params.length);
+ byteBuffer.put(header).put(params);
+ return byteBuffer.array();
+ }
+
+
+
+ @Override
+ public int getType() {
+ return TYPE_UNSEGMENTED_CONTROL_MESSAGE;
+ }
+
+ @Override
+ public boolean segmented() {
+ return false;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/upper/UpperTransportAccessPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/upper/UpperTransportAccessPDU.java
new file mode 100644
index 00000000..5c4e2d95
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/upper/UpperTransportAccessPDU.java
@@ -0,0 +1,192 @@
+/********************************************************************************************************
+ * @file UpperTransportAccessPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.transport.upper;
+
+import android.util.SparseArray;
+
+import com.telink.ble.mesh.core.Encipher;
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.networking.AccessType;
+import com.telink.ble.mesh.core.networking.NonceGenerator;
+import com.telink.ble.mesh.core.networking.transport.lower.SegmentedAccessMessagePDU;
+import com.telink.ble.mesh.core.networking.transport.lower.UnsegmentedAccessMessagePDU;
+import com.telink.ble.mesh.util.MeshLogger;
+
+
+import java.nio.ByteOrder;
+import java.util.List;
+
+/**
+ * Created by kee on 2019/8/9.
+ */
+
+public class UpperTransportAccessPDU {
+ /**
+ * 384 bytes total
+ * 4 or 8 bytes transMIC
+ * transMIC
+ * for unsegmented message: 4 bytes
+ * for segmented message, determined by lower transport pdu:
+ * 4 bytes if SZMIC == 0, 8 bytes if SZMIC == 1
+ */
+ private byte[] encryptedPayload;
+
+
+ private byte[] decryptedPayload;
+
+ private UpperTransportEncryptionSuite mEncryptionSuite;
+
+ public UpperTransportAccessPDU(UpperTransportEncryptionSuite mEncryptionSuite) {
+ this.mEncryptionSuite = mEncryptionSuite;
+ }
+
+ public byte[] getEncryptedPayload() {
+ return encryptedPayload;
+ }
+
+ public byte[] getDecryptedPayload() {
+ return decryptedPayload;
+ }
+
+
+ public boolean parseAndDecryptSegmentedMessage(SparseArray messageBuffer, int sequenceNumber, int src, int dst) {
+ int len = 0;
+ for (int i = 0; i < messageBuffer.size(); i++) {
+ len += messageBuffer.get(i).getSegmentM().length;
+ }
+
+ byte[] upperTransportPdu = new byte[len];
+ int idx = 0;
+ int tmpLen;
+ for (int i = 0; i < messageBuffer.size(); i++) {
+ tmpLen = messageBuffer.get(i).getSegmentM().length;
+ System.arraycopy(messageBuffer.get(i).getSegmentM(), 0, upperTransportPdu, idx, tmpLen);
+ idx += tmpLen;
+ }
+
+// MeshLogger.log("upper pdu raw: " + Arrays.bytesToHexString(upperTransportPdu, ""));
+ this.encryptedPayload = upperTransportPdu;
+
+ SegmentedAccessMessagePDU message0 = messageBuffer.get(0);
+ this.decryptedPayload = decrypt(message0.getAkf(), message0.getAid(), message0.getSzmic(), sequenceNumber, src, dst);
+
+ return this.decryptedPayload != null;
+ }
+
+ public boolean parseAndDecryptUnsegmentedMessage(UnsegmentedAccessMessagePDU unsegmentedAccessMessagePDU, int sequenceNumber, int src, int dst) {
+ this.encryptedPayload = unsegmentedAccessMessagePDU.getUpperTransportPDU();
+ this.decryptedPayload = decrypt(unsegmentedAccessMessagePDU.getAkf(), unsegmentedAccessMessagePDU.getAid(), 0, sequenceNumber, src, dst);
+ return this.decryptedPayload != null;
+ }
+
+ public boolean encrypt(byte[] accessPduData, byte szmic, AccessType accessType, int seqNo, int src, int dst) {
+ this.decryptedPayload = accessPduData;
+ byte[] seqNoBuffer = MeshUtils.integer2Bytes(seqNo, 3, ByteOrder.BIG_ENDIAN);
+ byte[] nonce = NonceGenerator.generateAccessNonce(szmic, seqNoBuffer, src, dst, this.mEncryptionSuite.ivIndex, accessType);
+ int mic = MeshUtils.getMicSize(szmic);
+ byte[] key;
+ if (accessType == AccessType.APPLICATION) {
+ key = this.mEncryptionSuite.appKeyList.get(0);
+ } else {
+ key = this.mEncryptionSuite.deviceKey;
+ }
+ if (key == null) {
+ MeshLogger.e("upper transport encryption err: key null");
+ return false;
+ }
+ this.encryptedPayload = Encipher.ccm(this.decryptedPayload, key, nonce, mic, true);
+ return this.encryptedPayload != null;
+ }
+
+
+ private byte[] decrypt(
+ int akf,
+ byte aid,
+ int aszmic,
+ int sequenceNumber,
+ int src,
+ int dst) {
+ byte[] key;
+ // device key or application key
+ byte[] nonce = null;
+ byte[] seqNo = MeshUtils.sequenceNumber2Buffer(sequenceNumber);
+ if (AccessType.DEVICE.akf == akf) {
+ nonce = NonceGenerator.generateAccessNonce((byte) aszmic, seqNo, src, dst, this.mEncryptionSuite.ivIndex, AccessType.DEVICE);
+ key = this.mEncryptionSuite.deviceKey;
+ if (key == null) {
+ MeshLogger.e("decrypt err: device key null");
+ return null;
+ }
+ return decryptPayload(this.encryptedPayload, key, nonce, aszmic);
+ } else {
+
+ if (mEncryptionSuite.appKeyList != null) {
+ byte decAid;
+ byte[] decResult;
+ for (byte[] appKey :
+ mEncryptionSuite.appKeyList) {
+ decAid = MeshUtils.generateAid(appKey);
+ if (decAid == aid) {
+ if (nonce == null) {
+ nonce = NonceGenerator.generateAccessNonce((byte) aszmic, seqNo, src, dst, this.mEncryptionSuite.ivIndex, AccessType.APPLICATION);
+ }
+
+ decResult = decryptPayload(this.encryptedPayload, appKey, nonce, aszmic);
+ if (decResult != null) {
+ return decResult;
+ }
+ }
+ }
+ }
+
+ }
+
+ return null;
+ }
+
+ private byte[] decryptPayload(byte[] payload, byte[] key, byte[] nonce, int aszmic) {
+ if (aszmic == 1) {
+ return Encipher.ccm(payload, key, nonce, 8, false);
+ } else {
+ return Encipher.ccm(payload, key, nonce, 4, false);
+ }
+ }
+
+
+ public static class UpperTransportEncryptionSuite {
+ private List appKeyList;
+ private byte[] deviceKey;
+ private int ivIndex;
+
+ public UpperTransportEncryptionSuite(byte[] deviceKey, int ivIndex) {
+ this.deviceKey = deviceKey;
+ this.ivIndex = ivIndex;
+ }
+
+ public UpperTransportEncryptionSuite(List appKeyList, int ivIndex) {
+ this.appKeyList = appKeyList;
+ this.ivIndex = ivIndex;
+ }
+
+
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/upper/UpperTransportControlPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/upper/UpperTransportControlPDU.java
new file mode 100644
index 00000000..de30def3
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/networking/transport/upper/UpperTransportControlPDU.java
@@ -0,0 +1,30 @@
+/********************************************************************************************************
+ * @file UpperTransportControlPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.networking.transport.upper;
+
+/**
+ * Created by kee on 2019/8/9.
+ */
+
+public class UpperTransportControlPDU {
+ // todo
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/AuthenticationMethod.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/AuthenticationMethod.java
new file mode 100644
index 00000000..9e05a37d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/AuthenticationMethod.java
@@ -0,0 +1,39 @@
+/********************************************************************************************************
+ * @file AuthenticationMethod.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning;
+
+/**
+ * Created by kee on 2019/9/4.
+ */
+
+public enum AuthenticationMethod {
+ NoOOB((byte) 0x00),
+ StaticOOB((byte) 0x01);
+
+ // output oob and input oob are not supported
+
+ public final byte value;
+
+ AuthenticationMethod(byte value) {
+ this.value = value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/DeviceCapability.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/DeviceCapability.java
new file mode 100644
index 00000000..af44d4ae
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/DeviceCapability.java
@@ -0,0 +1,76 @@
+/********************************************************************************************************
+ * @file DeviceCapability.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning;
+
+/**
+ * Created by kee on 2018/12/11.
+ */
+
+public class DeviceCapability {
+ private static final int CPB_DATA_LEN = 11;
+
+ private byte[] rawData;
+
+ private DeviceCapability() {
+ }
+
+ public static DeviceCapability getCapability(byte[] data) {
+ if (data == null || data.length != CPB_DATA_LEN) {
+ return null;
+ }
+ DeviceCapability capability = new DeviceCapability();
+ capability.rawData = data;
+ return capability;
+ }
+
+ public int getElementCnt() {
+ return rawData[0];
+ }
+
+ public int getAlgorithms() {
+ return ((rawData[1] & 0xFF) << 8) | (rawData[2] & 0xFF);
+ }
+
+ public int getPublicKeyType() {
+ return rawData[3];
+ }
+
+ public int getStaticOOBType() {
+ return rawData[4];
+ }
+
+ public int getOutputOOBSize() {
+ return rawData[5];
+ }
+
+ public int getOutputOOBAction() {
+ return ((rawData[6] & 0xFF) << 8) | (rawData[7] & 0xFF);
+ }
+
+ public int getInputOOBSize() {
+ return rawData[8];
+ }
+
+ public int getInputOOBAction() {
+ return ((rawData[9] & 0xFF) << 8) | (rawData[10] & 0xFF);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/ProvisioningBridge.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/ProvisioningBridge.java
new file mode 100644
index 00000000..e67fc95b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/ProvisioningBridge.java
@@ -0,0 +1,43 @@
+/********************************************************************************************************
+ * @file ProvisioningBridge.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning;
+
+/**
+ * Created by kee on 2019/9/12.
+ */
+
+public interface ProvisioningBridge {
+
+ /**
+ * @param state provisioning state
+ * @param desc desc
+ */
+ void onProvisionStateChanged(int state, String desc);
+
+ /**
+ * gatt command prepared to sent
+ *
+ * @param type command type
+ * @param data data
+ */
+ void onCommandPrepared(byte type, byte[] data);
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/ProvisioningController.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/ProvisioningController.java
new file mode 100644
index 00000000..8bd68980
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/ProvisioningController.java
@@ -0,0 +1,675 @@
+/********************************************************************************************************
+ * @file ProvisioningController.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.telink.ble.mesh.core.Encipher;
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningCapabilityPDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningConfirmPDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningDataPDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningInvitePDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningPDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningPubKeyPDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningRandomPDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningRecordRequestPDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningRecordResponsePDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningRecordsGetPDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningRecordsListPDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningStartPDU;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningStatePDU;
+import com.telink.ble.mesh.core.proxy.ProxyPDU;
+import com.telink.ble.mesh.entity.ProvisioningDevice;
+import com.telink.ble.mesh.util.Arrays;
+import com.telink.ble.mesh.util.MeshLogger;
+
+import org.spongycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
+
+import java.nio.ByteBuffer;
+import java.security.KeyPair;
+
+import androidx.annotation.NonNull;
+
+/**
+ * provisioning
+ * OOB public key is not supported
+ * Auth Method inputOOB outputOOB is not supported
+ * Created by kee on 2019/7/31.
+ */
+
+public class ProvisioningController {
+ private final String LOG_TAG = "Provisioning";
+
+ /**
+ * provisioning state
+ * indicates current state in provisioning flow
+ * init state {@link #STATE_IDLE} means not in provisioning flow
+ * direction introduction
+ * P: provisioner, D: device
+ * invite(P->D)
+ * =>
+ * capability(D->P)
+ * =>
+ * start(P->D)
+ * =>
+ * pub_key(P->D)
+ * =>
+ * pub_key(D->P) (if use oob public key, skip)
+ * =>
+ * confirm(P->D)
+ * =>
+ * confirm(D->P)
+ * =>
+ * random(P->D)
+ * =>
+ * random(D->P)
+ * =>
+ * check confirm
+ * =>
+ * provisioning end
+ */
+ private int state = STATE_IDLE;
+
+ /**
+ * not in provisioning flow
+ */
+ public static final int STATE_IDLE = 0x1000;
+
+ public static final int STATE_RECORDS_GET = 0x0010;
+
+ public static final int STATE_RECORD_REQUEST = 0x0011;
+
+ /**
+ * sent provisioning invite pdu
+ */
+ public static final int STATE_INVITE = 0x1001;
+
+ /**
+ * received provisioning capability
+ */
+ public static final int STATE_CAPABILITY = 0x1002;
+
+ /**
+ * sent provisioning start
+ */
+ public static final int STATE_START = 0x1003;
+
+ /**
+ * sent provisioning pub key
+ */
+ public static final int STATE_PUB_KEY_SENT = 0x1004;
+
+ /**
+ * received provisioning pub key
+ */
+ public static final int STATE_PUB_KEY_RECEIVED = 0x1005;
+
+
+// public static final int STATE_INPUT_COMPLETE = 0x1005;
+
+ /**
+ * sent provisioning confirm
+ */
+ public static final int STATE_CONFIRM_SENT = 0x1006;
+
+ /**
+ * received provisioning confirm
+ */
+ public static final int STATE_CONFIRM_RECEIVED = 0x1007;
+
+ /**
+ * sent provisioning random
+ */
+ public static final int STATE_RANDOM_SENT = 0x1008;
+
+ /**
+ * received provisioning random
+ */
+ public static final int STATE_RANDOM_RECEIVED = 0x1009;
+
+ /**
+ * sent provisioning data
+ */
+ public static final int STATE_DATA = 0x100A;
+
+ /**
+ * received provisioning complete, success!
+ */
+ public static final int STATE_COMPLETE = 0x100B;
+
+ /**
+ * received provisioning fail, or params check err!
+ */
+ public static final int STATE_FAILED = 0x100C;
+
+
+ private static final byte[] AUTH_NO_OOB = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ private static final long TIMEOUT_PROVISIONING = 60 * 1000;
+
+ /**
+ * certificate record fragment size
+ */
+ private static final int MAX_FRAGMENT_SIZE = 20;
+
+ private Handler delayHandler;
+
+ private ProvisioningBridge mProvisioningBridge;
+
+ private int recordId = -1;
+
+ private int fragmentOffset = 0;
+
+ private byte[] recordData;
+
+ /**
+ * public key in certificate get by record response data
+ */
+ private byte[] recordPubKey;
+
+ private ProvisioningRecordsListPDU recordsListPDU;
+
+ private ProvisioningInvitePDU invitePDU;
+
+ private ProvisioningStartPDU startPDU;
+
+ private ProvisioningCapabilityPDU pvCapability;
+
+ private ProvisioningPubKeyPDU provisionerPubKeyPDU;
+
+ private ProvisioningPubKeyPDU devicePubKeyPDU;
+
+ private KeyPair provisionerKeyPair;
+
+ private byte[] deviceECDHSecret;
+
+ private byte[] provisionerRandom;
+
+ private byte[] deviceRandom;
+
+ private byte[] deviceConfirm;
+
+// private byte[] deviceKey;
+
+
+// private ProvisioningParams mProvisioningParams;
+
+ /**
+ * target device
+ */
+ private ProvisioningDevice mProvisioningDevice;
+
+ public ProvisioningController(HandlerThread handlerThread) {
+ this.delayHandler = new Handler(handlerThread.getLooper());
+ }
+
+ public void setProvisioningBridge(ProvisioningBridge provisioningBridge) {
+ this.mProvisioningBridge = provisioningBridge;
+ }
+
+ public ProvisioningDevice getProvisioningDevice() {
+ return mProvisioningDevice;
+ }
+
+ public void begin(@NonNull ProvisioningDevice device) {
+ log("begin -- " + Arrays.bytesToHexString(device.getDeviceUUID()));
+ this.mProvisioningDevice = device;
+ delayHandler.removeCallbacks(provisioningTimeoutTask);
+ delayHandler.postDelayed(provisioningTimeoutTask, TIMEOUT_PROVISIONING);
+
+
+ // draft feature
+
+
+ provisionInvite();
+ }
+
+ public void clear() {
+ if (delayHandler != null) {
+ delayHandler.removeCallbacks(provisioningTimeoutTask);
+ }
+ this.state = STATE_IDLE;
+ }
+
+ public void pushNotification(byte[] provisioningPdu) {
+ if (state == STATE_IDLE) {
+ log("received notification when idle", MeshLogger.LEVEL_WARN);
+ return;
+ }
+ log("provisioning pdu received: " + Arrays.bytesToHexString(provisioningPdu, ""));
+ int provisioningPduType = provisioningPdu[0];
+ byte[] provisioningData = new byte[provisioningPdu.length - 1];
+ System.arraycopy(provisioningPdu, 1, provisioningData, 0, provisioningData.length);
+ switch (provisioningPduType) {
+ case ProvisioningPDU.TYPE_CAPABILITIES:
+ onCapabilityReceived(provisioningData);
+ break;
+
+ case ProvisioningPDU.TYPE_PUBLIC_KEY:
+ onPubKeyReceived(provisioningData);
+ break;
+
+ case ProvisioningPDU.TYPE_CONFIRMATION:
+ onConfirmReceived(provisioningData);
+ break;
+
+ case ProvisioningPDU.TYPE_RANDOM:
+ onRandomReceived(provisioningData);
+ break;
+
+ case ProvisioningPDU.TYPE_COMPLETE:
+ onProvisionSuccess();
+ break;
+ case ProvisioningPDU.TYPE_FAILED:
+ onProvisionFail("failed notification received");
+ break;
+
+ case ProvisioningPDU.TYPE_RECORDS_LIST:
+ onRecordListReceived(provisioningData);
+ break;
+
+ case ProvisioningPDU.TYPE_RECORD_RESPONSE:
+ onRecordResponse(provisioningData);
+ break;
+ }
+ }
+
+ private void onProvisionSuccess() {
+ updateProvisioningState(STATE_COMPLETE, "Provision Success");
+ onProvisionComplete();
+ }
+
+ private void onProvisionComplete() {
+ this.state = STATE_IDLE;
+ delayHandler.removeCallbacks(provisioningTimeoutTask);
+ }
+
+ private byte[] getAuthValue() {
+ if (pvCapability.staticOOBSupported() && mProvisioningDevice.getAuthValue() != null) {
+ return mProvisioningDevice.getAuthValue();
+ } else {
+ return AUTH_NO_OOB;
+ }
+ }
+
+ private void updateProvisioningState(int state, String desc) {
+ log("provisioning state update: state -- " + state + " desc -- " + desc);
+ this.state = state;
+ if (mProvisioningBridge != null) {
+ mProvisioningBridge.onProvisionStateChanged(state, desc);
+ }
+ }
+
+ private void provisionRecordsGet() {
+ updateProvisioningState(STATE_RECORDS_GET, "Records Get");
+ ProvisioningRecordsGetPDU recordsGetPDU = new ProvisioningRecordsGetPDU();
+ sendProvisionPDU(recordsGetPDU);
+ }
+
+
+ private void provisionRecordRequest() {
+ log(String.format("Record Request recordID=%04X offset=%04X", recordId, fragmentOffset));
+ ProvisioningRecordRequestPDU recordRequestPDU =
+ new ProvisioningRecordRequestPDU(recordId, fragmentOffset, MAX_FRAGMENT_SIZE);
+ sendProvisionPDU(recordRequestPDU);
+ }
+
+ /**
+ * invite
+ */
+ private void provisionInvite() {
+ byte attention = 0;
+ invitePDU = new ProvisioningInvitePDU(attention);
+ updateProvisioningState(STATE_INVITE, "Invite");
+ sendProvisionPDU(invitePDU);
+ }
+
+
+ private void provisionStart(boolean isStaticOOB) {
+ startPDU = ProvisioningStartPDU.getSimple(isStaticOOB);
+ startPDU.setPublicKey(pvCapability.publicKeyType == 1 && recordPubKey != null);
+ updateProvisioningState(STATE_START, "Start - use static oob?" + isStaticOOB);
+ sendProvisionPDU(startPDU);
+ }
+
+ private void provisionSendPubKey() {
+ ProvisioningPubKeyPDU pubKeyPDU = getPublicKey();
+ updateProvisioningState(STATE_PUB_KEY_SENT, "Send Public Key");
+ sendProvisionPDU(pubKeyPDU);
+ }
+
+ public void onCapabilityReceived(byte[] capData) {
+ if (this.state != STATE_INVITE) {
+ log(" capability received when not inviting", MeshLogger.LEVEL_WARN);
+ return;
+ }
+ updateProvisioningState(STATE_CAPABILITY, "Capability Received");
+ pvCapability = ProvisioningCapabilityPDU.fromBytes(capData);
+ mProvisioningDevice.setDeviceCapability(pvCapability);
+ boolean useStaticOOB = pvCapability.staticOOBSupported();
+ if (useStaticOOB && mProvisioningDevice.getAuthValue() == null) {
+ if (mProvisioningDevice.isAutoUseNoOOB()) {
+ // use no oob
+ useStaticOOB = false;
+ } else {
+ onProvisionFail("authValue not found when device static oob supported!");
+ return;
+ }
+ }
+ provisionStart(useStaticOOB);
+ provisionSendPubKey();
+ if (pvCapability.publicKeyType == 1 && recordPubKey != null) {
+ onPubKeyReceived(recordPubKey);
+ }
+ }
+
+ private void onPubKeyReceived(byte[] pubKeyData) {
+ if (this.state != STATE_PUB_KEY_SENT) {
+ log(" pub key received when not pub key sent", MeshLogger.LEVEL_WARN);
+ return;
+ }
+
+ updateProvisioningState(STATE_PUB_KEY_RECEIVED, "Public Key received");
+ log("pub key received: " + Arrays.bytesToHexString(pubKeyData, ""));
+ devicePubKeyPDU = ProvisioningPubKeyPDU.fromBytes(pubKeyData);
+ deviceECDHSecret = Encipher.generateECDH(pubKeyData, provisionerKeyPair.getPrivate());
+ if (deviceECDHSecret == null) {
+ onProvisionFail("invalid public key");
+ return;
+ }
+ log("get secret: " + Arrays.bytesToHexString(deviceECDHSecret, ""));
+ sendConfirm();
+ }
+
+
+ private void sendConfirm() {
+ ProvisioningConfirmPDU confirmPDU = new ProvisioningConfirmPDU(getConfirm());
+ updateProvisioningState(STATE_CONFIRM_SENT, "Send confirm");
+ sendProvisionPDU(confirmPDU);
+ }
+
+
+ private byte[] getConfirm() {
+ byte[] confirmInput = confirmAssembly();
+ byte[] salt = Encipher.generateSalt(confirmInput);
+ byte[] confirmationKey = Encipher.k1(deviceECDHSecret, salt, Encipher.PRCK);
+
+ provisionerRandom = Arrays.generateRandom(16);
+ byte[] authValue = getAuthValue();
+
+ byte[] confirmData = new byte[provisionerRandom.length + authValue.length];
+ System.arraycopy(provisionerRandom, 0, confirmData, 0, provisionerRandom.length);
+ System.arraycopy(authValue, 0, confirmData, provisionerRandom.length, authValue.length);
+
+ return Encipher.aesCmac(confirmData, confirmationKey);
+ }
+
+ private void onConfirmReceived(byte[] confirm) {
+ if (this.state != STATE_CONFIRM_SENT) {
+ log(" confirm received when not confirm sent", MeshLogger.LEVEL_WARN);
+ return;
+ }
+
+ updateProvisioningState(STATE_CONFIRM_RECEIVED, "Confirm received");
+ deviceConfirm = confirm;
+ sendRandom();
+ }
+
+
+ private void onRandomReceived(byte[] random) {
+ if (this.state != STATE_RANDOM_SENT) {
+ log(" random received when not random sent", MeshLogger.LEVEL_WARN);
+ return;
+ }
+
+ updateProvisioningState(STATE_RANDOM_RECEIVED, "Random received");
+ deviceRandom = random;
+ boolean pass = checkDeviceConfirm(random);
+ if (pass) {
+ sendProvisionData();
+ } else {
+ onProvisionFail("device confirm check err!");
+ }
+ }
+
+ private void onRecordListReceived(byte[] recordsData) {
+ if (state != STATE_RECORDS_GET) {
+ log("record list received when not record list get", MeshLogger.LEVEL_WARN);
+ return;
+ }
+ // 0D 0000 0000 0001
+ this.recordsListPDU = ProvisioningRecordsListPDU.fromBytes(recordsData);
+ if (recordsListPDU.recordsList.size() < 2) {
+ onProvisionFail("Device Certificate not found");
+ return;
+ }
+
+ this.recordId = recordsListPDU.recordsList.get(1);
+ this.fragmentOffset = 0;
+ this.recordData = null;
+ this.recordPubKey = null;
+ updateProvisioningState(STATE_RECORD_REQUEST, "Record Request");
+ provisionRecordRequest();
+ }
+
+ private void onRecordResponse(byte[] recordResponseData) {
+ if (state != STATE_RECORD_REQUEST) {
+ log("record response received when not record request", MeshLogger.LEVEL_WARN);
+ return;
+ }
+ ProvisioningRecordResponsePDU responsePDU = ProvisioningRecordResponsePDU.fromBytes(recordResponseData);
+ log(responsePDU.toString());
+ if (responsePDU.status != ProvisioningRecordResponsePDU.STATUS_SUCCESS || responsePDU.data == null) {
+ onProvisionFail("record response error");
+ return;
+ }
+ compositeResponseData(responsePDU.data);
+
+ if (recordData.length >= responsePDU.totalLength) {
+ onRecordResponseComplete();
+ } else {
+ fragmentOffset = fragmentOffset + responsePDU.data.length;
+ provisionRecordRequest();
+ }
+ }
+
+
+ private void compositeResponseData(byte[] newRecordData) {
+ if (recordData == null) {
+ recordData = newRecordData;
+ } else {
+// recordData = ByteBuffer.allocate(recordData.length + newRecordData.length).put(recordData).put(newRecordData).array();
+ byte[] re = new byte[recordData.length + newRecordData.length];
+ System.arraycopy(recordData, 0, re, 0, recordData.length);
+ System.arraycopy(newRecordData, 0, re, recordData.length, newRecordData.length);
+ recordData = re;
+ }
+ }
+
+ private void onRecordResponseComplete() {
+ log("complete record: " + Arrays.bytesToHexString(recordData));
+ recordPubKey = Encipher.checkCertificate(recordData);
+ if (recordPubKey == null || recordPubKey.length != 64) {
+ onProvisionFail("certificate record check error");
+ } else {
+ log("public key in record: " + Arrays.bytesToHexString(recordPubKey));
+ provisionInvite();
+ }
+ }
+
+ private void onProvisionFail(String desc) {
+ updateProvisioningState(STATE_FAILED, desc);
+ onProvisionComplete();
+ }
+
+ private void sendProvisionData() {
+ byte[] pvData = createProvisioningData();
+ ProvisioningDataPDU provisioningDataPDU = new ProvisioningDataPDU(pvData);
+ updateProvisioningState(STATE_DATA, "Send provisioning data");
+ sendProvisionPDU(provisioningDataPDU);
+ }
+
+ private void sendRandom() {
+ ProvisioningRandomPDU randomPDU = new ProvisioningRandomPDU(provisionerRandom);
+ updateProvisioningState(STATE_RANDOM_SENT, "Send random");
+ sendProvisionPDU(randomPDU);
+ }
+
+
+ private ProvisioningPubKeyPDU getPublicKey() {
+
+ provisionerKeyPair = Encipher.generateKeyPair();
+ if (provisionerKeyPair != null) {
+ BCECPublicKey publicKey = (BCECPublicKey) provisionerKeyPair.getPublic();
+ byte[] x = publicKey.getQ().getXCoord().getEncoded();
+ byte[] y = publicKey.getQ().getYCoord().getEncoded();
+ provisionerPubKeyPDU = new ProvisioningPubKeyPDU();
+ provisionerPubKeyPDU.x = x;
+ provisionerPubKeyPDU.y = y;
+ log("get key x: " + Arrays.bytesToHexString(x, ":"));
+ log("get key y: " + Arrays.bytesToHexString(y, ":"));
+ return provisionerPubKeyPDU;
+ } else {
+ throw new RuntimeException("key pair generate err");
+ }
+ }
+
+ // assemble random value
+ public byte[] confirmAssembly() {
+ byte[] inviteData = invitePDU.toBytes();
+ byte[] capData = pvCapability.toBytes();
+ byte[] startData = startPDU.toBytes();
+
+ byte[] provisionerPubKey = provisionerPubKeyPDU.toBytes();
+
+ byte[] devicePubKey = devicePubKeyPDU.toBytes();
+
+ final int len = inviteData.length
+ + capData.length
+ + startData.length
+ + provisionerPubKey.length
+ + devicePubKey.length;
+ ByteBuffer buffer = ByteBuffer.allocate(len);
+ buffer.put(inviteData)
+ .put(capData)
+ .put(startData)
+ .put(provisionerPubKey)
+ .put(devicePubKey);
+
+ return buffer.array();
+ }
+
+ private boolean checkDeviceConfirm(byte[] random) {
+
+ byte[] confirmationInputs = confirmAssembly();
+ byte[] confirmationSalt = Encipher.generateSalt(confirmationInputs);
+
+ byte[] confirmationKey = Encipher.k1(deviceECDHSecret, confirmationSalt, Encipher.PRCK);
+ byte[] authenticationValue = getAuthValue();
+
+ ByteBuffer buffer = ByteBuffer.allocate(random.length + authenticationValue.length);
+ buffer.put(random);
+ buffer.put(authenticationValue);
+ final byte[] confirmationData = buffer.array();
+
+ final byte[] confirmationValue = Encipher.aesCmac(confirmationData, confirmationKey);
+
+ if (java.util.Arrays.equals(confirmationValue, deviceConfirm)) {
+ log("Confirmation values check pass");
+ return true;
+ } else {
+ log("Confirmation values check err", MeshLogger.LEVEL_WARN);
+ }
+
+ return false;
+ }
+
+
+ private byte[] createProvisioningData() {
+
+ byte[] confirmationInputs = confirmAssembly();
+
+ byte[] confirmationSalt = Encipher.generateSalt(confirmationInputs);
+
+ ByteBuffer saltBuffer = ByteBuffer.allocate(confirmationSalt.length + provisionerRandom.length + deviceRandom.length);
+ saltBuffer.put(confirmationSalt);
+ saltBuffer.put(provisionerRandom);
+ saltBuffer.put(deviceRandom);
+ byte[] provisioningSalt = Encipher.generateSalt(saltBuffer.array());
+
+ byte[] t = Encipher.aesCmac(deviceECDHSecret, provisioningSalt);
+ byte[] sessionKey = Encipher.aesCmac(Encipher.PRSK, t);
+
+ byte[] nonce = Encipher.k1(deviceECDHSecret, provisioningSalt, Encipher.PRSN);
+ ByteBuffer nonceBuffer = ByteBuffer.allocate(nonce.length - 3);
+ nonceBuffer.put(nonce, 3, nonceBuffer.limit());
+ byte[] sessionNonce = nonceBuffer.array();
+
+ mProvisioningDevice.setDeviceKey(Encipher.aesCmac(Encipher.PRDK, t));
+ log("device key: " + Arrays.bytesToHexString(mProvisioningDevice.getDeviceKey(), ":"));
+ log("provisioning data prepare: " + mProvisioningDevice.toString());
+ byte[] provisioningData = mProvisioningDevice.generateProvisioningData();
+
+ log("unencrypted provision data: " + Arrays.bytesToHexString(provisioningData, ":"));
+ byte[] enData = Encipher.ccm(provisioningData, sessionKey, sessionNonce, 8, true);
+ log("encrypted provision data: " + Arrays.bytesToHexString(enData, ":"));
+ return enData;
+ }
+
+ private void sendProvisionPDU(ProvisioningStatePDU pdu) {
+ byte[] data = pdu.toBytes();
+
+ byte[] re;
+ if (data == null || data.length == 0) {
+ re = new byte[]{pdu.getState()};
+ } else {
+ re = new byte[data.length + 1];
+ re[0] = pdu.getState();
+ System.arraycopy(data, 0, re, 1, data.length);
+ }
+ if (mProvisioningBridge != null) {
+ log("pdu prepared: " + Arrays.bytesToHexString(data, ":"));
+ mProvisioningBridge.onCommandPrepared(ProxyPDU.TYPE_PROVISIONING_PDU, re);
+ }
+ }
+
+
+ private Runnable provisioningTimeoutTask = new Runnable() {
+ @Override
+ public void run() {
+ onProvisionFail("provisioning timeout");
+ }
+ };
+
+ private void log(String logMessage) {
+ log(logMessage, MeshLogger.LEVEL_DEBUG);
+ }
+
+ private void log(String logMessage, int level) {
+ MeshLogger.log(logMessage, LOG_TAG, level);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/ProvisioningParams.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/ProvisioningParams.java
new file mode 100644
index 00000000..d04f92df
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/ProvisioningParams.java
@@ -0,0 +1,160 @@
+/********************************************************************************************************
+ * @file ProvisioningParams.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * @deprecated
+ * @see com.telink.ble.mesh.entity.ProvisioningDevice
+ */
+public class ProvisioningParams {
+
+ /**
+ * 16: key
+ * 2: key index
+ * 1: flags
+ * 4: iv index
+ * 2: unicast adr
+ */
+ private static final int DATA_PDU_LEN = 16 + 2 + 1 + 4 + 2;
+
+ private byte[] networkKey;
+
+ private int networkKeyIndex;
+
+ /*
+ * 0
+ Key Refresh Flag
+ 0: Key Refresh Phase 0 1: Key Refresh Phase 2
+ 1
+ IV Update Flag
+ 0: Normal operation 1: IV Update active
+ 2–7
+ Reserved for Future Use
+ */
+
+ /**
+ * 1 bit
+ */
+ private byte keyRefreshFlag;
+
+ /**
+ * 1 bit
+ */
+ private byte ivUpdateFlag;
+
+ /**
+ * 4 bytes
+ */
+ private int ivIndex;
+
+ /**
+ * unicast address for primary element
+ * 2 bytes
+ */
+ private int unicastAddress;
+
+
+ public static ProvisioningParams getDefault(byte[] networkKey, int networkKeyIndex, int ivIndex, int unicastAddress) {
+ ProvisioningParams params = new ProvisioningParams();
+ params.networkKey = networkKey;
+ params.networkKeyIndex = networkKeyIndex;
+ params.keyRefreshFlag = 0;
+ params.ivUpdateFlag = 0;
+ params.ivIndex = ivIndex;
+ params.unicastAddress = unicastAddress;
+ return params;
+ }
+
+ public static ProvisioningParams getSimple(byte[] networkKey, int unicastAddress) {
+ ProvisioningParams params = new ProvisioningParams();
+ params.networkKey = networkKey;
+ params.networkKeyIndex = 0;
+ params.keyRefreshFlag = 0;
+ params.ivUpdateFlag = 0;
+ params.ivIndex = 0;
+ params.unicastAddress = unicastAddress;
+ return params;
+ }
+
+
+ public byte[] toProvisioningData() {
+ byte flags = (byte) ((keyRefreshFlag & 0b01) | (ivUpdateFlag & 0b10));
+ ByteBuffer buffer = ByteBuffer.allocate(DATA_PDU_LEN).order(ByteOrder.BIG_ENDIAN);
+ buffer.put(networkKey)
+ .putShort((short) networkKeyIndex)
+ .put(flags)
+ .putInt(ivIndex)
+ .putShort((short) unicastAddress);
+ return buffer.array();
+ }
+
+ public byte[] getNetworkKey() {
+ return networkKey;
+ }
+
+ public void setNetworkKey(byte[] networkKey) {
+ this.networkKey = networkKey;
+ }
+
+ public int getNetworkKeyIndex() {
+ return networkKeyIndex;
+ }
+
+ public void setNetworkKeyIndex(int networkKeyIndex) {
+ this.networkKeyIndex = networkKeyIndex;
+ }
+
+ public byte getKeyRefreshFlag() {
+ return keyRefreshFlag;
+ }
+
+ public void setKeyRefreshFlag(byte keyRefreshFlag) {
+ this.keyRefreshFlag = keyRefreshFlag;
+ }
+
+ public byte getIvUpdateFlag() {
+ return ivUpdateFlag;
+ }
+
+ public void setIvUpdateFlag(byte ivUpdateFlag) {
+ this.ivUpdateFlag = ivUpdateFlag;
+ }
+
+ public int getIvIndex() {
+ return ivIndex;
+ }
+
+ public void setIvIndex(int ivIndex) {
+ this.ivIndex = ivIndex;
+ }
+
+ public int getUnicastAddress() {
+ return unicastAddress;
+ }
+
+ public void setUnicastAddress(int unicastAddress) {
+ this.unicastAddress = unicastAddress;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/PDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/PDU.java
new file mode 100644
index 00000000..2095d82f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/PDU.java
@@ -0,0 +1,34 @@
+/********************************************************************************************************
+ * @file PDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+/**
+ * Created by kee on 2019/7/18.
+ */
+
+public interface PDU {
+
+ /**
+ * @return pdu as byte array
+ */
+ byte[] toBytes();
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningCapabilityPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningCapabilityPDU.java
new file mode 100644
index 00000000..65e1726f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningCapabilityPDU.java
@@ -0,0 +1,156 @@
+/********************************************************************************************************
+ * @file ProvisioningCapabilityPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+/**
+ * Created by kee on 2019/7/18.
+ */
+// 03:01:
+// 02:00:01:00:00:00:00:00:00:00:00
+// from device
+public class ProvisioningCapabilityPDU implements ProvisioningStatePDU {
+
+ private static final int LEN = 11;
+
+ public byte[] rawData;
+
+
+ /**
+ * Number of elements supported by the device
+ * 1 byte
+ * 0: Prohibited
+ * 0x01-0xFF
+ */
+ public byte eleNum;
+
+ /**
+ * Supported algorithms and other capabilities
+ * 2 bytes
+ * bit-0: FIPS P-256 Elliptic Curve
+ * bit-1--15: Reserved for Future Use
+ */
+ public short algorithms;
+
+ /**
+ * Supported public key types
+ * 1 byte
+ * bit-0: Public Key OOB information available
+ * bit-1--7: Prohibited
+ */
+ public byte publicKeyType;
+
+ /**
+ * Supported static OOB Types
+ * 1 byte
+ * bit 0: Static OOB information available
+ * bit 1–7: Prohibited
+ */
+ public byte staticOOBType;
+
+ /**
+ * Maximum size of Output OOB supported
+ * 1 byte
+ * 0x00: The device does not support output OOB
+ * 0x01–0x08: Maximum size in octets supported by the device
+ * 0x09–0xFF: Reserved for Future Use
+ */
+ public byte outputOOBSize;
+
+ /**
+ * Supported Output OOB Actions
+ * 2 bytes
+ * bit-0: Blink
+ * bit-1: Beep
+ * bit-2: Vibrate
+ * bit-3: Output Numeric
+ * bit-4: Output Alphanumeric, Array of octets
+ * other bits are RFU
+ */
+ public short outputOOBAction;
+
+ /**
+ * Maximum size in octets of Input OOB supported
+ * 1 byte
+ * 0x00: The device does not support Input OOB
+ * 0x01–0x08: Maximum supported size in octets supported by the device
+ * 0x09–0xFF: Reserved for Future Use
+ */
+ public byte inputOOBSize;
+
+ /**
+ * Supported Input OOB Actions
+ * 2 bytes
+ * bit-0: Push
+ * bit-1: Twist
+ * bit-2:Input Number
+ * bit-3: Input Alphanumeric, Array of octets
+ * bit-4--15 Reserved for Future Use
+ */
+ public short inputOOBAction;
+
+ public static ProvisioningCapabilityPDU fromBytes(byte[] data) {
+ if (data == null || data.length < LEN) {
+ return null;
+ }
+
+ ProvisioningCapabilityPDU capability = new ProvisioningCapabilityPDU();
+ capability.rawData = data;
+ int index = 0;
+ capability.eleNum = data[index++];
+ capability.algorithms = (short) (((data[index++] & 0xFF) << 8) | (data[index++] & 0xFF));
+ capability.publicKeyType = data[index++];
+ capability.staticOOBType = data[index++];
+ capability.outputOOBSize = data[index++];
+ capability.outputOOBAction = (short) (((data[index++] & 0xFF) << 8) | (data[index++] & 0xFF));
+ capability.inputOOBSize = data[index++];
+ capability.inputOOBAction = (short) (((data[index++] & 0xFF) << 8) | (data[index] & 0xFF));
+ return capability;
+ }
+
+ @Override
+ public String toString() {
+ return "ProvisioningCapabilityPDU{" +
+ "eleNum=" + eleNum +
+ ", algorithms=" + algorithms +
+ ", publicKeyType=" + publicKeyType +
+ ", staticOOBType=" + staticOOBType +
+ ", outputOOBSize=" + outputOOBSize +
+ ", outputOOBAction=" + outputOOBAction +
+ ", inputOOBSize=" + inputOOBSize +
+ ", inputOOBAction=" + inputOOBAction +
+ '}';
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return rawData;
+ }
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_CAPABILITIES;
+ }
+
+ public boolean staticOOBSupported() {
+ return staticOOBType != 0;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningConfirmPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningConfirmPDU.java
new file mode 100644
index 00000000..b812a197
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningConfirmPDU.java
@@ -0,0 +1,46 @@
+/********************************************************************************************************
+ * @file ProvisioningConfirmPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+/**
+ * Created by kee on 2019/7/19.
+ */
+
+public class ProvisioningConfirmPDU implements ProvisioningStatePDU {
+
+
+ public byte[] confirm;
+
+ public ProvisioningConfirmPDU(byte[] confirm) {
+ this.confirm = confirm;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return confirm;
+ }
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_CONFIRMATION;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningDataPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningDataPDU.java
new file mode 100644
index 00000000..a6f358d5
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningDataPDU.java
@@ -0,0 +1,46 @@
+/********************************************************************************************************
+ * @file ProvisioningDataPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+/**
+ * Created by kee on 2019/7/19.
+ */
+
+public class ProvisioningDataPDU implements ProvisioningStatePDU {
+
+ // including mic
+ public byte[] encryptedData;
+
+ public ProvisioningDataPDU(byte[] encryptedData) {
+ this.encryptedData = encryptedData;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return encryptedData;
+ }
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_DATA;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningInvitePDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningInvitePDU.java
new file mode 100644
index 00000000..95bd5892
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningInvitePDU.java
@@ -0,0 +1,47 @@
+/********************************************************************************************************
+ * @file ProvisioningInvitePDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+/**
+ * Created by kee on 2019/7/19.
+ */
+
+public class ProvisioningInvitePDU implements ProvisioningStatePDU {
+
+
+ // Attention Timer state
+ public byte attentionDuration;
+
+ public ProvisioningInvitePDU(byte attentionDuration) {
+ this.attentionDuration = attentionDuration;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return new byte[]{attentionDuration};
+ }
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_INVITE;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningPDU.java
new file mode 100644
index 00000000..279773ba
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningPDU.java
@@ -0,0 +1,127 @@
+/********************************************************************************************************
+ * @file ProvisioningPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+/**
+ * Created by kee on 2019/7/18.
+ */
+// big endian
+public abstract class ProvisioningPDU implements PDU {
+
+ /**
+ * Invites a device to join a mesh network
+ */
+ public static final byte TYPE_INVITE = 0x00;
+
+ /**
+ * Indicates the capabilities of the device
+ */
+ public static final byte TYPE_CAPABILITIES = 0x01;
+
+ /**
+ * Indicates the provisioning method selected by the Provisioner based on the capabilities of the device
+ */
+ public static final byte TYPE_START = 0x02;
+
+ /**
+ * Contains the Public Key of the device or the Provisioner
+ */
+ public static final byte TYPE_PUBLIC_KEY = 0x03;
+
+ /**
+ * Indicates that the user has completed inputting a value
+ */
+ public static final byte TYPE_INPUT_COMPLETE = 0x04;
+
+ /**
+ * Contains the provisioning confirmation value of the device or the Provisioner
+ */
+ public static final byte TYPE_CONFIRMATION = 0x05;
+
+ /**
+ * Contains the provisioning random value of the device or the Provisioner
+ */
+ public static final byte TYPE_RANDOM = 0x06;
+
+ /**
+ * Includes the assigned unicast address of the primary element, a network key, NetKey Index, Flags and the IV Index
+ */
+ public static final byte TYPE_DATA = 0x07;
+
+ /**
+ * Indicates that provisioning is complete
+ */
+ public static final byte TYPE_COMPLETE = 0x08;
+
+ /**
+ * Indicates that provisioning was unsuccessful
+ */
+ public static final byte TYPE_FAILED = 0x09;
+
+ /**
+ * Indicates a request to retrieve a provisioning record fragment from the device
+ */
+ public static final byte TYPE_RECORD_REQUEST = 0x0A;
+
+ /**
+ * Contains a provisioning record fragment or an error status,
+ * sent in response to a Provisioning Record Request
+ */
+ public static final byte TYPE_RECORD_RESPONSE = 0x0B;
+
+ /**
+ * Indicates a request to retrieve the list of IDs of the provisioning records
+ * that the unprovisioned device supports.
+ */
+ public static final byte TYPE_RECORDS_GET = 0x0C;
+
+ /**
+ * Contains the list of IDs of the provisioning records that the unprovisioned device supports.
+ */
+ public static final byte TYPE_RECORDS_LIST = 0x0D;
+
+
+ /**
+ * including :
+ * padding : 2 bits 0b00
+ * typeValue : 6 bits
+ * 0x00 - 0x09 indicates provisioning state
+ * 0x0A–0xFF Reserved for Future Use
+ */
+ private byte type;
+
+ /**
+ * provisioning params
+ */
+ private byte[] params;
+
+ @Override
+ public byte[] toBytes() {
+ final int len = params == null ? 1 : 1 + params.length;
+ byte[] re = new byte[len];
+ re[0] = type;
+ if (params != null) {
+ System.arraycopy(params, 0, re, 1, params.length);
+ }
+ return re;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningPubKeyPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningPubKeyPDU.java
new file mode 100644
index 00000000..c52e33ce
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningPubKeyPDU.java
@@ -0,0 +1,65 @@
+/********************************************************************************************************
+ * @file ProvisioningPubKeyPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+
+/**
+ * Created by kee on 2019/7/18.
+ */
+
+public class ProvisioningPubKeyPDU implements ProvisioningStatePDU {
+ private static final int LEN = 64;
+ // 32 bytes
+ public byte[] x;
+ public byte[] y;
+
+ private byte[] rawData;
+
+ public static ProvisioningPubKeyPDU fromBytes(byte[] data) {
+ if (data.length != LEN) return null;
+
+ ProvisioningPubKeyPDU pubKeyPDU = new ProvisioningPubKeyPDU();
+ pubKeyPDU.rawData = data;
+ pubKeyPDU.x = new byte[32];
+ pubKeyPDU.y = new byte[32];
+
+ System.arraycopy(data, 0, pubKeyPDU.x, 0, 32);
+ System.arraycopy(data, 32, pubKeyPDU.y, 0, 32);
+
+ return pubKeyPDU;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ if (rawData != null) return rawData;
+ if (x == null || y == null) return null;
+ byte[] re = new byte[LEN];
+ System.arraycopy(x, 0, re, 0, x.length);
+ System.arraycopy(y, 0, re, 32, y.length);
+ return re;
+ }
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_PUBLIC_KEY;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRandomPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRandomPDU.java
new file mode 100644
index 00000000..8b023269
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRandomPDU.java
@@ -0,0 +1,45 @@
+/********************************************************************************************************
+ * @file ProvisioningRandomPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+/**
+ * Created by kee on 2019/7/19.
+ */
+
+public class ProvisioningRandomPDU implements ProvisioningStatePDU {
+
+ public byte[] random;
+
+ public ProvisioningRandomPDU(byte[] confirm) {
+ this.random = confirm;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return random;
+ }
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_RANDOM;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordRequestPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordRequestPDU.java
new file mode 100644
index 00000000..efc41ffe
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordRequestPDU.java
@@ -0,0 +1,68 @@
+/********************************************************************************************************
+ * @file ProvisioningRecordRequestPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * The Provisioner sends a Provisioning Record Request PDU to request a provisioning record fragment
+ */
+public class ProvisioningRecordRequestPDU implements ProvisioningStatePDU {
+
+ /**
+ * Identifies the provisioning record for which the request is made
+ * 2 bytes
+ */
+ public int recordID;
+
+ /**
+ * The starting offset of the requested fragment in the provisioning record data
+ * 2 bytes
+ */
+ public int fragmentOffset;
+
+ /**
+ * The maximum size of the provisioning record fragment that the Provisioner can receive
+ * 2 bytes
+ */
+ public int fragmentMaxSize;
+
+
+ public ProvisioningRecordRequestPDU(int recordID, int fragmentOffset, int fragmentMaxSize) {
+ this.recordID = recordID;
+ this.fragmentOffset = fragmentOffset;
+ this.fragmentMaxSize = fragmentMaxSize;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return ByteBuffer.allocate(6).order(ByteOrder.BIG_ENDIAN).putShort((short) recordID)
+ .putShort((short) fragmentOffset)
+ .putShort((short) fragmentMaxSize).array();
+ }
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_RECORD_REQUEST;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordResponsePDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordResponsePDU.java
new file mode 100644
index 00000000..25c41360
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordResponsePDU.java
@@ -0,0 +1,111 @@
+/********************************************************************************************************
+ * @file ProvisioningPubKeyPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.util.Arrays;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/7/18.
+ */
+
+public class ProvisioningRecordResponsePDU implements ProvisioningStatePDU {
+
+
+ /**
+ * status success
+ */
+ public static final byte STATUS_SUCCESS = 0x00;
+
+ /**
+ * status Requested Record Is Not Present
+ */
+ public static final byte STATUS_RECORD_NOT_PRESENT = 0x01;
+
+ /**
+ * status Requested Offset Is Out Of Bounds
+ */
+ public static final byte STATUS_OFFSET_OUT_OF_BOUNDS = 0x02;
+
+ public byte[] rawData;
+ /**
+ * Indicates whether or not the request was handled successfully
+ */
+ public byte status;
+
+ /**
+ *
+ */
+ public int recordID;
+
+ public int fragmentOffset;
+
+ public int totalLength;
+
+ public byte[] data;
+
+
+ public static ProvisioningRecordResponsePDU fromBytes(byte[] data) {
+
+ int index = 0;
+ ProvisioningRecordResponsePDU responsePDU = new ProvisioningRecordResponsePDU();
+ responsePDU.rawData = data;
+ responsePDU.status = data[index++];
+ responsePDU.recordID = MeshUtils.bytes2Integer(data, index, 2, ByteOrder.BIG_ENDIAN);
+ index += 2;
+
+ responsePDU.fragmentOffset = MeshUtils.bytes2Integer(data, index, 2, ByteOrder.BIG_ENDIAN);
+ index += 2;
+
+ responsePDU.totalLength = MeshUtils.bytes2Integer(data, index, 2, ByteOrder.BIG_ENDIAN);
+ index += 2;
+
+ responsePDU.data = new byte[data.length - index];
+ System.arraycopy(data, index, responsePDU.data, 0, responsePDU.data.length);
+ return responsePDU;
+ }
+
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_RECORD_RESPONSE;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return rawData;
+ }
+
+ @Override
+ public String toString() {
+ return "ProvisioningRecordResponsePDU{" +
+ "status=" + status +
+ ", recordID=" + recordID +
+ ", fragmentOffset=" + fragmentOffset +
+ ", totalLength=" + totalLength +
+ ", data=" + Arrays.bytesToHexString(data) +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordsGetPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordsGetPDU.java
new file mode 100644
index 00000000..e04f6efa
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordsGetPDU.java
@@ -0,0 +1,43 @@
+/********************************************************************************************************
+ * @file ProvisioningInvitePDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+/**
+ * Created by kee on 2019/7/19.
+ */
+
+public class ProvisioningRecordsGetPDU implements ProvisioningStatePDU {
+
+
+ public ProvisioningRecordsGetPDU() {
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return null;
+ }
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_RECORDS_GET;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordsListPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordsListPDU.java
new file mode 100644
index 00000000..d3cd711c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningRecordsListPDU.java
@@ -0,0 +1,86 @@
+/********************************************************************************************************
+ * @file ProvisioningPubKeyPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+
+import com.telink.ble.mesh.core.MeshUtils;
+
+import java.io.ByteArrayInputStream;
+import java.nio.ByteOrder;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Created by kee on 2019/7/18.
+ */
+
+public class ProvisioningRecordsListPDU implements ProvisioningStatePDU {
+
+
+ public byte[] rawData;
+ /**
+ * Bitmask indicating the provisioning extensions supported by the device
+ * 2 bytes
+ */
+ public int provisioningExtensions;
+
+ /**
+ * Lists the Record IDs of the provisioning records stored on the device
+ */
+ public List recordsList;
+
+ public static ProvisioningRecordsListPDU fromBytes(byte[] data) {
+
+ int index = 0;
+ ProvisioningRecordsListPDU recordsListPDU = new ProvisioningRecordsListPDU();
+ recordsListPDU.rawData = data;
+ recordsListPDU.provisioningExtensions = MeshUtils.bytes2Integer(data, index, 2, ByteOrder.BIG_ENDIAN);
+ index += 2;
+
+ if (data.length > index) {
+ final int listSize = (data.length - index) / 2;
+ recordsListPDU.recordsList = new ArrayList<>(listSize);
+ int recordID;
+ for (int i = 0; i < listSize; i++) {
+ recordID = MeshUtils.bytes2Integer(data, index, 2, ByteOrder.BIG_ENDIAN);
+ recordsListPDU.recordsList.add(recordID);
+ index += 2;
+ }
+ }
+ return recordsListPDU;
+
+ }
+
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_RECORDS_LIST;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return rawData;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningStartPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningStartPDU.java
new file mode 100644
index 00000000..ecfacf01
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningStartPDU.java
@@ -0,0 +1,98 @@
+/********************************************************************************************************
+ * @file ProvisioningStartPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+import com.telink.ble.mesh.core.provisioning.AuthenticationMethod;
+
+/**
+ * Created by kee on 2019/7/18.
+ */
+
+public class ProvisioningStartPDU implements ProvisioningStatePDU {
+ private static final int LEN = 5;
+
+ /**
+ * The algorithm used for provisioning
+ * 0x00: FIPS P-256 Elliptic Curve
+ * 0x01–0xFF: Reserved for Future Use
+ */
+ public byte algorithm;
+
+ /**
+ * Public Key used
+ * 0x00: No OOB Public Key is used
+ * 0x01: OOB Public Key is used
+ * 0x02–0xFF: Prohibited
+ */
+ public byte publicKey;
+
+ /**
+ * Authentication Method used
+ * 0x00: No OOB authentication is used
+ * 0x01: Static OOB authentication is used
+ * 0x02: Output OOB authentication is used
+ * 0x03: Input OOB authentication is used
+ * 0x04–0xFF: Prohibited
+ */
+ public byte authenticationMethod;
+
+ /**
+ * Selected Output OOB Action or Input OOB Action or 0x00
+ */
+ public byte authenticationAction;
+
+ /**
+ * Size of the Output OOB used or size of the Input OOB used or 0x00
+ */
+ public byte authenticationSize;
+
+ public static ProvisioningStartPDU getSimple(boolean staticOOBSupported) {
+ ProvisioningStartPDU startPDU = new ProvisioningStartPDU();
+ startPDU.algorithm = 0;
+ startPDU.publicKey = 0;
+ startPDU.authenticationMethod = staticOOBSupported ? AuthenticationMethod.StaticOOB.value :
+ AuthenticationMethod.NoOOB.value;
+ startPDU.authenticationAction = 0;
+ startPDU.authenticationSize = 0;
+ return startPDU;
+ }
+
+ public void setPublicKey(boolean publicKeyEnable) {
+ this.publicKey = (byte) (publicKeyEnable ? 1 : 0);
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return new byte[]{
+ algorithm,
+ publicKey,
+ authenticationMethod,
+ authenticationAction,
+ authenticationSize
+ };
+ }
+
+ @Override
+ public byte getState() {
+ return ProvisioningPDU.TYPE_START;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningStatePDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningStatePDU.java
new file mode 100644
index 00000000..01e6521b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/provisioning/pdu/ProvisioningStatePDU.java
@@ -0,0 +1,34 @@
+/********************************************************************************************************
+ * @file ProvisioningStatePDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.provisioning.pdu;
+
+/**
+ * Created by kee on 2019/7/18.
+ */
+
+public interface ProvisioningStatePDU extends PDU {
+ /**
+ * @return provision state
+ * @see ProvisioningPDU#type
+ */
+ byte getState();
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyAddAddressMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyAddAddressMessage.java
new file mode 100644
index 00000000..c3a2658f
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyAddAddressMessage.java
@@ -0,0 +1,56 @@
+/********************************************************************************************************
+ * @file ProxyAddAddressMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.proxy;
+
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Created by kee on 2019/8/26.
+ */
+
+public class ProxyAddAddressMessage extends ProxyConfigurationMessage {
+
+ private int[] addressArray;
+
+ public ProxyAddAddressMessage(@NonNull int[] addressArray) {
+ this.addressArray = addressArray;
+ }
+
+ @Override
+ public byte getOpcode() {
+ return OPCODE_ADD_ADDRESS;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ int len = 1 + addressArray.length * 2;
+ ByteBuffer buffer = ByteBuffer.allocate(len).order(ByteOrder.BIG_ENDIAN).put(getOpcode());
+ for (int address : addressArray) {
+ buffer.putShort((short) address);
+ }
+ return buffer.array();
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyConfigurationMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyConfigurationMessage.java
new file mode 100644
index 00000000..c0c9235a
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyConfigurationMessage.java
@@ -0,0 +1,60 @@
+/********************************************************************************************************
+ * @file ProxyConfigurationMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.proxy;
+
+/**
+ * Created by kee on 2019/8/26.
+ */
+
+public abstract class ProxyConfigurationMessage {
+
+
+ /**
+ * Set Filter Type
+ * Sent by a Proxy Client to set the proxy filter typeValue.
+ */
+ public static final byte OPCODE_SET_FILTER_TYPE = 0x00;
+
+ /**
+ * Add Addresses To Filter
+ * Sent by a Proxy Client to add addresses to the proxy filter list.
+ */
+ public static final byte OPCODE_ADD_ADDRESS = 0x01;
+
+ /**
+ * Remove Addresses From Filter
+ * Sent by a Proxy Client to remove addresses from the proxy filter list.
+ */
+ public static final byte OPCODE_REMOVE_ADDRESS = 0x02;
+
+ /**
+ * Filter Status
+ * Acknowledgment by a Proxy Server to a Proxy Client to report the status of the proxy filter list.
+ */
+ public static final byte OPCODE_FILTER_STATUS = 0x03;
+
+
+ public abstract byte getOpcode();
+
+ public abstract byte[] toByteArray();
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyConfigurationPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyConfigurationPDU.java
new file mode 100644
index 00000000..1c30b575
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyConfigurationPDU.java
@@ -0,0 +1,51 @@
+/********************************************************************************************************
+ * @file ProxyConfigurationPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.proxy;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.networking.NetworkLayerPDU;
+import com.telink.ble.mesh.core.networking.NonceGenerator;
+
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/26.
+ */
+
+public class ProxyConfigurationPDU extends NetworkLayerPDU {
+
+ public static final byte ctl = 1;
+
+ public static final byte ttl = 0;
+
+ public static final byte dst = 0x00;
+
+ public ProxyConfigurationPDU(NetworkEncryptionSuite encryptionSuite) {
+ super(encryptionSuite);
+ }
+
+ @Override
+ protected byte[] generateNonce() {
+ byte[] seqNo = MeshUtils.integer2Bytes(getSeq(), 3, ByteOrder.BIG_ENDIAN);
+ return NonceGenerator.generateProxyNonce(seqNo, getSrc(), this.encryptionSuite.ivIndex);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyFilterStatusMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyFilterStatusMessage.java
new file mode 100644
index 00000000..12c7a790
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyFilterStatusMessage.java
@@ -0,0 +1,79 @@
+/********************************************************************************************************
+ * @file ProxyFilterStatusMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.proxy;
+
+import com.telink.ble.mesh.core.MeshUtils;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Created by kee on 2019/8/26.
+ */
+public class ProxyFilterStatusMessage extends ProxyConfigurationMessage {
+
+ private static final int DATA_LEN = 4;
+ /**
+ * White list or black list.
+ */
+ private byte filterType;
+
+ /**
+ * Number of addresses in the proxy filter list.
+ */
+ private int listSize;
+
+ public static ProxyFilterStatusMessage fromBytes(byte[] data) {
+ if (data.length != DATA_LEN) {
+ return null;
+ }
+ ProxyFilterStatusMessage instance = new ProxyFilterStatusMessage();
+ int index = 0;
+ byte opcode = data[index++];
+ if (opcode != OPCODE_FILTER_STATUS) return null;
+ instance.filterType = data[index++];
+ instance.listSize = MeshUtils.bytes2Integer(data, index, 2, ByteOrder.BIG_ENDIAN);
+ return instance;
+ }
+
+ @Override
+ public byte getOpcode() {
+ return OPCODE_FILTER_STATUS;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ return ByteBuffer.allocate(DATA_LEN)
+ .order(ByteOrder.BIG_ENDIAN)
+ .put(filterType)
+ .putShort((short) listSize)
+ .array();
+ }
+
+ public byte getFilterType() {
+ return filterType;
+ }
+
+ public int getListSize() {
+ return listSize;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyFilterType.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyFilterType.java
new file mode 100644
index 00000000..9ce9d815
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyFilterType.java
@@ -0,0 +1,36 @@
+/********************************************************************************************************
+ * @file ProxyFilterType.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.proxy;
+
+/**
+ * Created by kee on 2019/8/26.
+ */
+
+public enum ProxyFilterType {
+ WhiteList((byte) 0),
+ BlackList((byte) 1);
+ public final byte value;
+
+ ProxyFilterType(byte value) {
+ this.value = value;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyPDU.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyPDU.java
new file mode 100644
index 00000000..7e11d3b7
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyPDU.java
@@ -0,0 +1,78 @@
+/********************************************************************************************************
+ * @file ProxyPDU.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.proxy;
+
+/**
+ * Created by kee on 2019/7/18.
+ */
+
+public abstract class ProxyPDU {
+
+ /**
+ * defines if message is segment
+ * 2 bits
+ */
+ public byte sar;
+
+ /**
+ * 6 bits
+ * defines data field content
+ */
+ public byte type;
+
+ public byte[] data;
+
+ /**
+ * get proxy pdu typeValue and SAR by ' data[0] & BITS_* '
+ */
+ public static final int BITS_TYPE = 0b00111111;
+
+ public static final int BITS_SAR = 0b11000000;
+
+
+ /**
+ * complete message
+ */
+ public static final byte SAR_COMPLETE = 0b00;
+
+ /**
+ * segment message
+ */
+ public static final byte SAR_SEG_FIRST = 0b01 << 6;
+
+ public static final byte SAR_SEG_CONTINUE = (byte) (0b10 << 6);
+
+ public static final byte SAR_SEG_LAST = (byte) (0b11 << 6);
+
+
+ /**
+ * PDU typeValue
+ */
+
+ public static final byte TYPE_NETWORK_PDU = 0x00;
+
+ public static final byte TYPE_MESH_BEACON = 0x01;
+
+ public static final byte TYPE_PROXY_CONFIGURATION = 0x02;
+
+ public static final byte TYPE_PROVISIONING_PDU = 0x03;
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyRemoveAddressMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyRemoveAddressMessage.java
new file mode 100644
index 00000000..bf57a06e
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxyRemoveAddressMessage.java
@@ -0,0 +1,56 @@
+/********************************************************************************************************
+ * @file ProxyRemoveAddressMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.proxy;
+
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Created by kee on 2019/8/26.
+ */
+
+public class ProxyRemoveAddressMessage extends ProxyConfigurationMessage {
+
+ private int[] addressArray;
+
+ public ProxyRemoveAddressMessage(@NonNull int[] addressArray) {
+ this.addressArray = addressArray;
+ }
+
+ @Override
+ public byte getOpcode() {
+ return OPCODE_REMOVE_ADDRESS;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ int len = 1 + addressArray.length * 2;
+ ByteBuffer buffer = ByteBuffer.allocate(len).order(ByteOrder.BIG_ENDIAN).put(getOpcode());
+ for (int address : addressArray) {
+ buffer.putShort((short) address);
+ }
+ return buffer.array();
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxySetFilterTypeMessage.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxySetFilterTypeMessage.java
new file mode 100644
index 00000000..bdd2df94
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/core/proxy/ProxySetFilterTypeMessage.java
@@ -0,0 +1,45 @@
+/********************************************************************************************************
+ * @file ProxySetFilterTypeMessage.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.core.proxy;
+
+/**
+ * Created by kee on 2019/8/26.
+ */
+
+public class ProxySetFilterTypeMessage extends ProxyConfigurationMessage {
+
+ private byte filterType;
+
+ public ProxySetFilterTypeMessage(byte filterType) {
+ this.filterType = filterType;
+ }
+
+ @Override
+ public byte getOpcode() {
+ return OPCODE_SET_FILTER_TYPE;
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ return new byte[]{getOpcode(), filterType};
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/AdvertisingDevice.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/AdvertisingDevice.java
new file mode 100644
index 00000000..e6576ea2
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/AdvertisingDevice.java
@@ -0,0 +1,90 @@
+/********************************************************************************************************
+ * @file AdvertisingDevice.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+
+package com.telink.ble.mesh.entity;
+
+import android.bluetooth.BluetoothDevice;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.util.MeshLogger;
+
+import java.util.Arrays;
+
+/**
+ * scanned devices
+ */
+public class AdvertisingDevice implements Parcelable {
+ public BluetoothDevice device;
+ public int rssi;
+ public byte[] scanRecord;
+
+ public AdvertisingDevice(BluetoothDevice device, int rssi, byte[] scanRecord) {
+ this.device = device;
+ this.rssi = rssi;
+ this.scanRecord = scanRecord;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public AdvertisingDevice createFromParcel(Parcel in) {
+ return new AdvertisingDevice(in);
+ }
+
+ @Override
+ public AdvertisingDevice[] newArray(int size) {
+ return new AdvertisingDevice[size];
+ }
+ };
+
+ public AdvertisingDevice(Parcel in) {
+ this.device = in.readParcelable(getClass().getClassLoader());
+ this.rssi = in.readInt();
+ this.scanRecord = new byte[in.readInt()];
+ in.readByteArray(this.scanRecord);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(this.device, 0);
+ dest.writeInt(this.rssi);
+ dest.writeInt(this.scanRecord.length);
+ dest.writeByteArray(this.scanRecord);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof AdvertisingDevice
+ && ((AdvertisingDevice) obj).device.equals(device)
+ && Arrays.equals(((AdvertisingDevice) obj).scanRecord, scanRecord);
+ }
+
+ @Override
+ public int hashCode() {
+ return device.hashCode();
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/BindingDevice.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/BindingDevice.java
new file mode 100644
index 00000000..59b66fd0
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/BindingDevice.java
@@ -0,0 +1,197 @@
+/********************************************************************************************************
+ * @file BindingDevice.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.access.BindingBearer;
+
+/**
+ * Created by kee on 2019/9/6.
+ */
+
+public class BindingDevice implements Parcelable {
+
+ /**
+ * network key index,
+ * if the index value is -1, it would be replaced by {@link com.telink.ble.mesh.foundation.MeshConfiguration#netKeyIndex}
+ */
+ private int netKeyIndex = -1;
+
+ /**
+ * device unicast address
+ */
+ private int meshAddress;
+
+ private byte[] deviceUUID;
+
+ /**
+ * model and appKey map, null means bind all models
+ */
+// private SparseIntArray modelAppKeyMap;
+
+ /**
+ * app key index, should be contained in NetworkingController#appKeyMap
+ */
+ private int appKeyIndex;
+
+ /**
+ * models bound at this key
+ */
+ private int[] models;
+
+ /**
+ * binding bearer
+ * {@link BindingBearer#GattOnly} and {@link BindingBearer#Any}
+ */
+ private BindingBearer bearer = BindingBearer.GattOnly;
+
+ /**
+ * default bound is private action defined by telink, for faster binding
+ * if valued by true, when node received app key, it will bind all models automatically;
+ */
+ private boolean defaultBound = false;
+
+ private CompositionData compositionData;
+
+ public BindingDevice() {
+ }
+
+ public BindingDevice(int meshAddress, byte[] deviceUUID, int appKeyIndex) {
+ this.meshAddress = meshAddress;
+ this.deviceUUID = deviceUUID;
+ this.appKeyIndex = appKeyIndex;
+ this.models = null;
+ this.bearer = BindingBearer.GattOnly;
+ }
+
+ public BindingDevice(int meshAddress, byte[] deviceUUID, int appKeyIndex, int[] models, BindingBearer bearer) {
+ this.meshAddress = meshAddress;
+ this.deviceUUID = deviceUUID;
+ this.appKeyIndex = appKeyIndex;
+ this.models = models;
+ this.bearer = bearer;
+ }
+
+ protected BindingDevice(Parcel in) {
+ netKeyIndex = in.readInt();
+ meshAddress = in.readInt();
+ deviceUUID = in.createByteArray();
+ appKeyIndex = in.readInt();
+ models = in.createIntArray();
+ defaultBound = in.readByte() != 0;
+ compositionData = in.readParcelable(CompositionData.class.getClassLoader());
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public BindingDevice createFromParcel(Parcel in) {
+ return new BindingDevice(in);
+ }
+
+ @Override
+ public BindingDevice[] newArray(int size) {
+ return new BindingDevice[size];
+ }
+ };
+
+ public int getNetKeyIndex() {
+ return netKeyIndex;
+ }
+
+ public void setNetKeyIndex(int netKeyIndex) {
+ this.netKeyIndex = netKeyIndex;
+ }
+
+ public int getMeshAddress() {
+ return meshAddress;
+ }
+
+ public void setMeshAddress(int meshAddress) {
+ this.meshAddress = meshAddress;
+ }
+
+ public byte[] getDeviceUUID() {
+ return deviceUUID;
+ }
+
+ public void setDeviceUUID(byte[] deviceUUID) {
+ this.deviceUUID = deviceUUID;
+ }
+
+ public int getAppKeyIndex() {
+ return appKeyIndex;
+ }
+
+ public void setAppKeyIndex(int appKeyIndex) {
+ this.appKeyIndex = appKeyIndex;
+ }
+
+ public int[] getModels() {
+ return models;
+ }
+
+ public void setModels(int[] models) {
+ this.models = models;
+ }
+
+ public BindingBearer getBearer() {
+ return bearer;
+ }
+
+ public void setBearer(BindingBearer bearer) {
+ this.bearer = bearer;
+ }
+
+ public boolean isDefaultBound() {
+ return defaultBound;
+ }
+
+ public void setDefaultBound(boolean defaultBound) {
+ this.defaultBound = defaultBound;
+ }
+
+ public CompositionData getCompositionData() {
+ return compositionData;
+ }
+
+ public void setCompositionData(CompositionData compositionData) {
+ this.compositionData = compositionData;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(netKeyIndex);
+ dest.writeInt(meshAddress);
+ dest.writeByteArray(deviceUUID);
+ dest.writeInt(appKeyIndex);
+ dest.writeIntArray(models);
+ dest.writeByte((byte) (defaultBound ? 1 : 0));
+ dest.writeParcelable(compositionData, flags);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/CompositionData.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/CompositionData.java
new file mode 100644
index 00000000..6fad2891
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/CompositionData.java
@@ -0,0 +1,320 @@
+/********************************************************************************************************
+ * @file CompositionData.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.message.MeshSigModel;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by kee on 2019/8/12.
+ */
+public class CompositionData implements Serializable, Parcelable {
+ /**
+ * bit 0 Relay feature support: 0 = False, 1 = True
+ */
+ private static final int FEATURE_RELAY = 0b0001;
+
+ /**
+ * bit 1 Proxy feature support: 0 = False, 1 = True
+ */
+ private static final int FEATURE_PROXY = 0b0010;
+
+ /**
+ * bit 2 Friend feature support: 0 = False, 1 = True
+ */
+ private static final int FEATURE_FRIEND = 0b0100;
+
+ /**
+ * bit 3 Low Power feature support: 0 = False, 1 = True
+ */
+ private static final int FEATURE_LOW_POWER = 0b1000;
+
+
+ /**
+ * Contains a 16-bit company identifier assigned by the Bluetooth SIG
+ */
+ public int cid;
+
+ /**
+ * Contains a 16-bit vendor-assigned product identifier
+ */
+ public int pid;
+
+ /**
+ * Contains a 16-bit vendor-assigned product version identifier
+ */
+ public int vid;
+
+ /**
+ * Contains a 16-bit value representing the minimum number of replay protection list entries in a device
+ */
+ public int crpl;
+
+ /**
+ * supported features
+ * 16 bits
+ */
+ public int features;
+
+ public List elements;
+
+ public CompositionData() {
+
+ }
+
+ protected CompositionData(Parcel in) {
+ cid = in.readInt();
+ pid = in.readInt();
+ vid = in.readInt();
+ crpl = in.readInt();
+ features = in.readInt();
+ }
+
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public CompositionData createFromParcel(Parcel in) {
+ return new CompositionData(in);
+ }
+
+ @Override
+ public CompositionData[] newArray(int size) {
+ return new CompositionData[size];
+ }
+ };
+
+ public static CompositionData from(byte[] data) {
+ int index = 0;
+ CompositionData cpsData = new CompositionData();
+ cpsData.cid = (data[index++] & 0xFF) | ((data[index++] & 0xFF) << 8);
+ cpsData.pid = (data[index++] & 0xFF) | ((data[index++] & 0xFF) << 8);
+ cpsData.vid = (data[index++] & 0xFF) | ((data[index++] & 0xFF) << 8);
+ cpsData.crpl = (data[index++] & 0xFF) | ((data[index++] & 0xFF) << 8);
+ cpsData.features = (data[index++] & 0xFF) | ((data[index++] & 0xFF) << 8);
+
+ cpsData.elements = new ArrayList<>();
+ while (index < data.length) {
+ Element element = new Element();
+ element.location = (data[index++] & 0xFF) | ((data[index++] & 0xFF) << 8);
+ element.sigNum = (data[index++] & 0xFF);
+ element.vendorNum = (data[index++] & 0xFF);
+
+ element.sigModels = new ArrayList<>();
+ for (int i = 0; i < element.sigNum; i++) {
+ element.sigModels.add((data[index++] & 0xFF) | ((data[index++] & 0xFF) << 8));
+ }
+
+ element.vendorModels = new ArrayList<>();
+ for (int j = 0; j < element.vendorNum; j++) {
+ //sample 11 02 01 00 cid: 11 02 modelId: 01 00 -> 0x00010211
+ element.vendorModels.add(((data[index++] & 0xFF)) | ((data[index++] & 0xFF) << 8) |
+ ((data[index++] & 0xFF) << 16) | ((data[index++] & 0xFF) << 24));
+ }
+
+ cpsData.elements.add(element);
+ }
+
+ return cpsData;
+ }
+
+ /**
+ * @param configExcept config model not include
+ * @deprecated
+ */
+ public List getAllModels(boolean configExcept) {
+ if (elements == null) return null;
+ List models = new ArrayList<>();
+ for (Element ele : elements) {
+ if (ele.sigModels != null) {
+ if (!configExcept) {
+ models.addAll(ele.sigModels);
+ } else {
+ for (int modelId : ele.sigModels) {
+ if (!MeshSigModel.isConfigurationModel(modelId)) {
+ models.add(modelId);
+ }
+ }
+ }
+
+ }
+ if (ele.vendorModels != null) {
+ models.addAll(ele.vendorModels);
+ }
+ }
+
+ return models;
+ }
+
+ public int getElementOffset(int modelId) {
+ int offset = 0;
+ for (Element ele : elements) {
+ if (ele.sigModels != null && ele.sigModels.contains(modelId)) {
+ return offset;
+ }
+ if (ele.vendorModels != null && ele.vendorModels.contains(modelId)) {
+ return offset;
+ }
+ offset++;
+ }
+ return -1;
+ }
+
+ public boolean relaySupport() {
+ return (features & FEATURE_RELAY) != 0;
+ }
+
+ public boolean proxySupport() {
+ return (features & FEATURE_PROXY) != 0;
+ }
+
+ public boolean friendSupport() {
+ return (features & FEATURE_FRIEND) != 0;
+ }
+
+ public boolean lowPowerSupport() {
+ return (features & FEATURE_LOW_POWER) != 0;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(cid);
+ dest.writeInt(pid);
+ dest.writeInt(vid);
+ dest.writeInt(crpl);
+ dest.writeInt(features);
+ dest.writeTypedList(elements);
+ }
+
+
+ public static class Element implements Serializable, Parcelable {
+
+ /**
+ * 2 bytes
+ * Contains a location descriptor
+ */
+ public int location;
+
+ /**
+ * 1 byte
+ * Contains a count of SIG Model IDs in this element
+ */
+ public int sigNum;
+
+ /**
+ * 1 byte
+ * Contains a count of Vendor Model IDs in this element
+ */
+ public int vendorNum;
+
+ /**
+ * Contains a sequence of NumS SIG Model IDs
+ */
+ public List sigModels;
+
+ /**
+ * Contains a sequence of NumV Vendor Model IDs
+ */
+ public List vendorModels;
+
+ public Element(){}
+
+ protected Element(Parcel in) {
+ location = in.readInt();
+ sigNum = in.readInt();
+ vendorNum = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public Element createFromParcel(Parcel in) {
+ return new Element(in);
+ }
+
+ @Override
+ public Element[] newArray(int size) {
+ return new Element[size];
+ }
+ };
+
+ public boolean containModel(int sigModelId) {
+ if (sigModels == null || sigModels.size() == 0) return false;
+ for (int modelId : sigModels) {
+ if (sigModelId == modelId) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(location);
+ dest.writeInt(sigNum);
+ dest.writeInt(vendorNum);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder elementInfo = new StringBuilder();
+ Element element;
+ for (int i = 0; i < elements.size(); i++) {
+ element = elements.get(i);
+ elementInfo.append("element ").append(i).append(" : \n");
+ elementInfo.append("SIG\n");
+ String sig;
+ for (int j = 0; j < element.sigModels.size(); j++) {
+ sig = String.format("%04X", element.sigModels.get(j));
+ elementInfo.append(sig).append("\n");
+ }
+ elementInfo.append("VENDOR\n");
+ for (int j = 0; j < element.vendorModels.size(); j++) {
+ elementInfo.append(String.format("%08X", element.vendorModels.get(j))).append("\n");
+ }
+ }
+
+ return "CompositionData{" +
+ "cid=" + String.format("%04X", cid) +
+ ", pid=" + String.format("%04X", pid) +
+ ", vid=" + String.format("%04X", vid) +
+ ", crpl=" + String.format("%04X", crpl) +
+ ", features=" + String.format("%04X", features) +
+ ", elements=" + elementInfo +
+ '}';
+ }
+}
+
+
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/ConnectionFilter.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/ConnectionFilter.java
new file mode 100644
index 00000000..2523a50b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/ConnectionFilter.java
@@ -0,0 +1,18 @@
+package com.telink.ble.mesh.entity;
+
+public class ConnectionFilter {
+ public static final int TYPE_MESH_ADDRESS = 0;
+ public static final int TYPE_MAC_ADDRESS = 1;
+ public static final int TYPE_DEVICE_NAME = 2;
+
+
+ public int type;
+
+ //
+ public Object target;
+
+ public ConnectionFilter(int type, Object target) {
+ this.type = type;
+ this.target = target;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/FastProvisioningConfiguration.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/FastProvisioningConfiguration.java
new file mode 100644
index 00000000..68aafca9
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/FastProvisioningConfiguration.java
@@ -0,0 +1,209 @@
+/********************************************************************************************************
+ * @file FastProvisioningConfiguration.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+import android.util.SparseIntArray;
+
+import androidx.annotation.NonNull;
+
+/**
+ * fast provisioning configurations
+ * Created by kee on 2020/03/09.
+ */
+
+public class FastProvisioningConfiguration {
+
+ /**
+ * 2000ms
+ */
+ public static final int DEFAULT_RESET_DELAY = 2000;
+
+ public static final int PID_ALL = 0xFFFF;
+
+ /**
+ * device default ivIndex
+ */
+ public static final int DEFAULT_IV_INDEX = 0x12345678;
+
+ /**
+ * device default network key
+ */
+ public static final byte[] DEFAULT_NETWORK_KEY = {0x7d, (byte) 0xd7, 0x36, 0x4c, (byte) 0xd8,
+ 0x42, (byte) 0xad, 0x18, (byte) 0xc1, 0x7c, 0x74, 0x65, 0x6c, 0x69, 0x6e, 0x6b};
+
+ /**
+ * device default app key
+ */
+ public static final byte[] DEFAULT_APP_KEY = {0x63, (byte) 0x96, 0x47, 0x71, 0x73, 0x4f,
+ (byte) 0xbd, 0x76, (byte) 0xe3, (byte) 0xb4, 0x74, 0x65, 0x6c, 0x69, 0x6e, 0x6b};
+
+ public static final int DEFAULT_NETWORK_KEY_INDEX = 0;
+
+ public static final int DEFAULT_APP_KEY_INDEX = 0;
+
+ private int resetDelay;
+
+ /**
+ * provisioning start address
+ */
+ private int provisioningIndex;
+
+ // element count for each pid
+ // key: pid
+ private SparseIntArray elementPidMap;
+// private int elementCount;
+//
+// private int pid;
+ /**
+ * pid used in params when scanning for fast-provisioning device
+ */
+ private int scanningPid;
+
+ /*****
+ * device default network params
+ *****/
+ private int ivIndex;
+
+ @NonNull
+ private byte[] defaultNetworkKey;
+
+ private int defaultNetworkKeyIndex = 0;
+
+ @NonNull
+ private byte[] defaultAppKey;
+
+ private int defaultAppKeyIndex = 0;
+
+ public static FastProvisioningConfiguration getDefault(int provisioningIndex, SparseIntArray elementPidMap) {
+ FastProvisioningConfiguration configuration = new FastProvisioningConfiguration();
+ configuration.resetDelay = DEFAULT_RESET_DELAY;
+ configuration.provisioningIndex = provisioningIndex;
+ configuration.elementPidMap = elementPidMap;
+ configuration.scanningPid = PID_ALL;
+ configuration.ivIndex = DEFAULT_IV_INDEX;
+ configuration.defaultNetworkKey = DEFAULT_NETWORK_KEY;
+ configuration.defaultNetworkKeyIndex = DEFAULT_NETWORK_KEY_INDEX;
+ configuration.defaultAppKey = DEFAULT_APP_KEY;
+ configuration.defaultAppKeyIndex = DEFAULT_APP_KEY_INDEX;
+ return configuration;
+ }
+
+ /**
+ * @return if pid exist in map
+ */
+ public boolean pidExist(int pid) {
+ if (elementPidMap != null) {
+ return elementPidMap.get(pid) != 0;
+ }
+ return false;
+ }
+
+ /**
+ * @param pid target pid
+ * @return 0 error
+ */
+ public int getElementCount(int pid) {
+ if (elementPidMap != null) {
+ return elementPidMap.get(pid);
+ }
+ return 0;
+ }
+
+ public int getProvisioningIndex() {
+ return provisioningIndex;
+ }
+
+ public void setProvisioningIndex(int provisioningIndex) {
+ this.provisioningIndex = provisioningIndex;
+ }
+
+ public void increaseProvisioningIndex(int elementCount) {
+ this.provisioningIndex += elementCount;
+ }
+
+ public SparseIntArray getElementPidMap() {
+ return elementPidMap;
+ }
+
+ public void setElementPidMap(SparseIntArray elementPidMap) {
+ this.elementPidMap = elementPidMap;
+ }
+
+ public int getScanningPid() {
+ return scanningPid;
+ }
+
+ public void setScanningPid(int scanningPid) {
+ this.scanningPid = scanningPid;
+ }
+
+ public int getIvIndex() {
+ return ivIndex;
+ }
+
+ public void setIvIndex(int ivIndex) {
+ this.ivIndex = ivIndex;
+ }
+
+ @NonNull
+ public byte[] getDefaultNetworkKey() {
+ return defaultNetworkKey;
+ }
+
+ public void setDefaultNetworkKey(@NonNull byte[] defaultNetworkKey) {
+ this.defaultNetworkKey = defaultNetworkKey;
+ }
+
+ public int getDefaultNetworkKeyIndex() {
+ return defaultNetworkKeyIndex;
+ }
+
+ public void setDefaultNetworkKeyIndex(int defaultNetworkKeyIndex) {
+ this.defaultNetworkKeyIndex = defaultNetworkKeyIndex;
+ }
+
+ @NonNull
+ public byte[] getDefaultAppKey() {
+ return defaultAppKey;
+ }
+
+ public void setDefaultAppKey(@NonNull byte[] defaultAppKey) {
+ this.defaultAppKey = defaultAppKey;
+ }
+
+ public int getDefaultAppKeyIndex() {
+ return defaultAppKeyIndex;
+ }
+
+ public void setDefaultAppKeyIndex(int defaultAppKeyIndex) {
+ this.defaultAppKeyIndex = defaultAppKeyIndex;
+ }
+
+ public int getResetDelay() {
+ return resetDelay;
+ }
+
+ public void setResetDelay(int resetDelay) {
+ this.resetDelay = resetDelay;
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/FastProvisioningDevice.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/FastProvisioningDevice.java
new file mode 100644
index 00000000..6cc9b17b
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/FastProvisioningDevice.java
@@ -0,0 +1,171 @@
+/********************************************************************************************************
+ * @file FastProvisioningDevice.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.util.Arrays;
+
+/**
+ * Model for provisioning flow
+ * Created by kee on 2019/9/4.
+ */
+// advertisingDevice is null
+public class FastProvisioningDevice implements Parcelable {
+
+ private int originAddress;
+
+ private int newAddress;
+
+ private int pid;
+
+ private int elementCount;
+
+ private byte[] mac;
+
+ private byte[] deviceKey;
+
+
+ public FastProvisioningDevice() {
+
+ }
+
+ public FastProvisioningDevice(int originAddress, int newAddress, int pid, int elementCount, byte[] mac) {
+ this.originAddress = originAddress;
+ this.newAddress = newAddress;
+ this.pid = pid;
+ this.elementCount = elementCount;
+ this.mac = Arrays.reverse(mac);
+ this.deviceKey = new byte[16];
+ System.arraycopy(mac, 0, deviceKey, 0, 6);
+ }
+
+ protected FastProvisioningDevice(Parcel in) {
+ originAddress = in.readInt();
+ newAddress = in.readInt();
+ pid = in.readInt();
+ elementCount = in.readInt();
+ mac = in.createByteArray();
+ deviceKey = in.createByteArray();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public FastProvisioningDevice createFromParcel(Parcel in) {
+ return new FastProvisioningDevice(in);
+ }
+
+ @Override
+ public FastProvisioningDevice[] newArray(int size) {
+ return new FastProvisioningDevice[size];
+ }
+ };
+
+ public byte[] getMac() {
+ return mac;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ FastProvisioningDevice device = (FastProvisioningDevice) o;
+ return java.util.Arrays.equals(mac, device.mac);
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Arrays.hashCode(mac);
+ }
+
+ public int getOriginAddress() {
+ return originAddress;
+ }
+
+ public void setOriginAddress(int originAddress) {
+ this.originAddress = originAddress;
+ }
+
+ public int getNewAddress() {
+ return newAddress;
+ }
+
+ public void setNewAddress(int newAddress) {
+ this.newAddress = newAddress;
+ }
+
+ public int getPid() {
+ return pid;
+ }
+
+ public void setPid(int pid) {
+ this.pid = pid;
+ }
+
+ public void setMac(byte[] mac) {
+ this.mac = mac;
+ }
+
+ public byte[] getDeviceKey() {
+ return deviceKey;
+ }
+
+ public void setDeviceKey(byte[] deviceKey) {
+ this.deviceKey = deviceKey;
+ }
+
+ public int getElementCount() {
+ return elementCount;
+ }
+
+ public void setElementCount(int elementCount) {
+ this.elementCount = elementCount;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(originAddress);
+ dest.writeInt(newAddress);
+ dest.writeInt(pid);
+ dest.writeInt(elementCount);
+ dest.writeByteArray(mac);
+ dest.writeByteArray(deviceKey);
+ }
+
+ @Override
+ public String toString() {
+ return "FastProvisioningDevice{" +
+ "originAddress=" + originAddress +
+ ", newAddress=" + newAddress +
+ ", pid=" + pid +
+ ", elementCount=" + elementCount +
+ ", mac=" + java.util.Arrays.toString(mac) +
+ ", deviceKey=" + java.util.Arrays.toString(deviceKey) +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/FirmwareUpdateConfiguration.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/FirmwareUpdateConfiguration.java
new file mode 100644
index 00000000..460c101d
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/FirmwareUpdateConfiguration.java
@@ -0,0 +1,111 @@
+/********************************************************************************************************
+ * @file FirmwareUpdateConfiguration.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+import java.util.List;
+
+/**
+ * Created by kee on 2019/9/6.
+ */
+
+public class FirmwareUpdateConfiguration {
+ private List updatingDevices;
+ private byte[] firmwareData;
+ private byte[] metadata;
+ private int appKeyIndex;
+ private int groupAddress;
+
+// private int companyId = 0x0211;
+
+// private int firmwareId = 0xFF000021;
+
+ private long blobId = 0x8877665544332211L;
+
+ private boolean singleAndDirect = false;
+
+ private int dleLength;
+
+ public FirmwareUpdateConfiguration(List updatingDevices,
+ byte[] firmwareData,
+ byte[] metadata,
+ int appKeyIndex,
+ int groupAddress) {
+ this.updatingDevices = updatingDevices;
+ this.firmwareData = firmwareData;
+ this.metadata = metadata;
+ this.appKeyIndex = appKeyIndex;
+ this.groupAddress = groupAddress;
+ }
+
+ public List getUpdatingDevices() {
+ return updatingDevices;
+ }
+
+ public byte[] getFirmwareData() {
+ return firmwareData;
+ }
+
+ public int getAppKeyIndex() {
+ return appKeyIndex;
+ }
+
+ public int getGroupAddress() {
+ return groupAddress;
+ }
+
+ public long getBlobId() {
+ return blobId;
+ }
+
+ public boolean isSingleAndDirect() {
+ return singleAndDirect;
+ }
+
+ public void setSingleAndDirect(boolean singleAndDirect) {
+ this.singleAndDirect = singleAndDirect;
+ }
+
+ public int getDleLength() {
+ return dleLength;
+ }
+
+ public void setDleLength(int dleLength) {
+ this.dleLength = dleLength;
+ }
+
+ public byte[] getMetadata() {
+ return metadata;
+ }
+
+ @Override
+ public String toString() {
+ return "FirmwareUpdateConfiguration{" +
+ "updatingDevices=" + updatingDevices.size() +
+ ", firmwareData=" + firmwareData.length +
+ ", metadata=" + metadata.length +
+ ", appKeyIndex=" + appKeyIndex +
+ ", groupAddress=" + groupAddress +
+
+ ", blobId=" + blobId +
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/MeshUpdatingDevice.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/MeshUpdatingDevice.java
new file mode 100644
index 00000000..f5f5f60c
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/MeshUpdatingDevice.java
@@ -0,0 +1,107 @@
+/********************************************************************************************************
+ * @file MeshUpdatingDevice.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Mesh firmware updating device
+ * Created by kee on 2019/10/10.
+ */
+public class MeshUpdatingDevice implements Parcelable {
+
+ public static final int STATE_INITIAL = 0;
+ public static final int STATE_SUCCESS = 1;
+ public static final int STATE_FAIL = 2;
+
+ /**
+ * unicast address
+ */
+ private int meshAddress;
+
+ /**
+ * element address at updating model
+ *
+ * @see com.telink.ble.mesh.core.message.MeshSigModel#SIG_MD_OBJ_TRANSFER_S
+ */
+ private int updatingEleAddress;
+
+ private int state = STATE_INITIAL;
+
+ public MeshUpdatingDevice() {
+ }
+
+ protected MeshUpdatingDevice(Parcel in) {
+ meshAddress = in.readInt();
+ updatingEleAddress = in.readInt();
+ state = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public MeshUpdatingDevice createFromParcel(Parcel in) {
+ return new MeshUpdatingDevice(in);
+ }
+
+ @Override
+ public MeshUpdatingDevice[] newArray(int size) {
+ return new MeshUpdatingDevice[size];
+ }
+ };
+
+ public int getMeshAddress() {
+ return meshAddress;
+ }
+
+ public void setMeshAddress(int meshAddress) {
+ this.meshAddress = meshAddress;
+ }
+
+ public int getUpdatingEleAddress() {
+ return updatingEleAddress;
+ }
+
+ public void setUpdatingEleAddress(int updatingEleAddress) {
+ this.updatingEleAddress = updatingEleAddress;
+ }
+
+ public int getState() {
+ return state;
+ }
+
+ public void setState(int state) {
+ this.state = state;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(meshAddress);
+ dest.writeInt(updatingEleAddress);
+ dest.writeInt(state);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/ModelPublication.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/ModelPublication.java
new file mode 100644
index 00000000..cd8316e7
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/ModelPublication.java
@@ -0,0 +1,194 @@
+/********************************************************************************************************
+ * @file ModelPublication.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+
+package com.telink.ble.mesh.entity;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * publication entity used when send publicationSet message or receive publication status message
+ * Created by kee on 2018/9/17.
+ */
+public final class ModelPublication implements Serializable, Parcelable {
+
+ public static final int CREDENTIAL_FLAG_DEFAULT = 0b1;
+
+ public static final int RFU_DEFAULT = 0x00;
+
+
+ // use default ttl in firmware
+ public static final int TTL_DEFAULT = 0xFF;
+
+ /**
+ * default retransmit: 0x15
+ * 0b 00010 101
+ * count: 0x05, step: 0x02
+ */
+ public static final int RETRANSMIT_COUNT_DEFAULT = 0x05;
+
+
+ public static final int RETRANSMIT_INTERVAL_STEP_DEFAULT = 0x02;
+
+
+ /**
+ * element address
+ * 16 bits
+ */
+ public int elementAddress;
+
+ /**
+ * 16 bits
+ */
+ public int publishAddress;
+
+ /**
+ * 12 bits
+ */
+ public int appKeyIndex;
+
+ /**
+ * 1 bit
+ */
+ public int credentialFlag = CREDENTIAL_FLAG_DEFAULT;
+
+ /**
+ * 3 bits
+ * reserved for future use
+ */
+ public int rfu = RFU_DEFAULT;
+
+ /**
+ * 8 bits
+ */
+ public int ttl = TTL_DEFAULT;
+
+ /**
+ * 8 bits
+ */
+ public byte period;
+
+ /**
+ * 3 bits
+ */
+ public int retransmitCount = RETRANSMIT_COUNT_DEFAULT;
+
+ /**
+ * 5 bits
+ */
+ public int retransmitIntervalSteps = RETRANSMIT_INTERVAL_STEP_DEFAULT;
+
+ /**
+ * 16 or 32 bits
+ */
+ public int modelId;
+
+ /**
+ * if sig model
+ * #modelId
+ */
+ public boolean sig;
+
+
+ protected ModelPublication(Parcel in) {
+ elementAddress = in.readInt();
+ publishAddress = in.readInt();
+ appKeyIndex = in.readInt();
+ credentialFlag = in.readInt();
+ rfu = in.readInt();
+ ttl = in.readInt();
+ period = in.readByte();
+ retransmitCount = in.readInt();
+ retransmitIntervalSteps = in.readInt();
+ modelId = in.readInt();
+ sig = in.readByte() != 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ModelPublication createFromParcel(Parcel in) {
+ return new ModelPublication(in);
+ }
+
+ @Override
+ public ModelPublication[] newArray(int size) {
+ return new ModelPublication[size];
+ }
+ };
+
+ public ModelPublication() {
+ }
+
+ public static ModelPublication createDefault(int elementAddress, int publishAddress, int appKeyIndex, long periodMillisecond, int modelId, boolean sig) {
+ ModelPublication instance = new ModelPublication();
+ instance.elementAddress = elementAddress;
+ instance.publishAddress = publishAddress;
+ instance.appKeyIndex = appKeyIndex;
+ instance.period = TransitionTime.fromTime(periodMillisecond).getValue();
+ instance.modelId = modelId;
+ instance.sig = sig;
+ return instance;
+ }
+
+ public byte[] toBytes() {
+ final int len = sig ? 11 : 13;
+ ByteBuffer bf = ByteBuffer.allocate(len).order(ByteOrder.LITTLE_ENDIAN);
+ bf
+ .putShort((short) elementAddress)
+ .putShort((short) publishAddress)
+ .putShort((short) ((appKeyIndex & 0xFFF) | ((credentialFlag & 0b01) << 12) | ((rfu & 0b111) << 13)))
+ .put((byte) ttl)
+ .put(period)
+ .put((byte) ((retransmitCount & 0b111) | (retransmitIntervalSteps << 3)));
+ if (sig) {
+ bf.putShort((short) modelId);
+ } else {
+ bf.putInt(modelId);
+ }
+ return bf.array();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(elementAddress);
+ dest.writeInt(publishAddress);
+ dest.writeInt(appKeyIndex);
+ dest.writeInt(credentialFlag);
+ dest.writeInt(rfu);
+ dest.writeInt(ttl);
+ dest.writeByte(period);
+ dest.writeInt(retransmitCount);
+ dest.writeInt(retransmitIntervalSteps);
+ dest.writeInt(modelId);
+ dest.writeByte((byte) (sig ? 1 : 0));
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/OnlineStatusInfo.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/OnlineStatusInfo.java
new file mode 100644
index 00000000..51ad8bec
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/OnlineStatusInfo.java
@@ -0,0 +1,74 @@
+/********************************************************************************************************
+ * @file OnlineStatusInfo.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+
+package com.telink.ble.mesh.entity;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * online status
+ */
+public class OnlineStatusInfo implements Parcelable {
+
+ public int address;
+
+// byte rsv; // 1 bit
+
+ // sn: 0 offline
+ public byte sn;
+
+ public byte[] status;
+
+ public OnlineStatusInfo() {
+ }
+
+ protected OnlineStatusInfo(Parcel in) {
+ address = in.readInt();
+ sn = in.readByte();
+ status = in.createByteArray();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public OnlineStatusInfo createFromParcel(Parcel in) {
+ return new OnlineStatusInfo(in);
+ }
+
+ @Override
+ public OnlineStatusInfo[] newArray(int size) {
+ return new OnlineStatusInfo[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(address);
+ dest.writeByte(sn);
+ dest.writeByteArray(status);
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/ProvisioningDevice.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/ProvisioningDevice.java
new file mode 100644
index 00000000..ce0ca5c2
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/ProvisioningDevice.java
@@ -0,0 +1,329 @@
+/********************************************************************************************************
+ * @file ProvisioningDevice.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+import android.bluetooth.BluetoothDevice;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.telink.ble.mesh.core.MeshUtils;
+import com.telink.ble.mesh.core.provisioning.pdu.ProvisioningCapabilityPDU;
+import com.telink.ble.mesh.util.Arrays;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Model for provisioning flow
+ * Created by kee on 2019/9/4.
+ */
+
+public class ProvisioningDevice implements Parcelable {
+
+ /**
+ * 16: key
+ * 2: key index
+ * 1: flags
+ * 4: iv index
+ * 2: unicast adr
+ */
+ private static final int DATA_PDU_LEN = 16 + 2 + 1 + 4 + 2;
+
+ private BluetoothDevice bluetoothDevice;
+
+ protected byte[] deviceUUID;
+
+
+ /**
+ * OOB Information
+ * Bit - Description
+ * 0 - Other
+ * 1 - Electronic / URI
+ * 2 - 2D machine-readable code
+ * 3 - Bar code
+ * 4 - Near Field Communication (NFC)
+ * 5 - Number
+ * 6 - String
+ * 7 - Support for certificate-based provisioning
+ * 8 - Support for provisioning records
+ * 9 - Reserved for Future Use
+ * 10 - Reserved for Future Use
+ * 11 - On box
+ * 12 - Inside box
+ * 13 - On piece of paper
+ * 14 - Inside manual
+ * 15 - On device
+ */
+ protected int oobInfo;
+
+ protected byte[] networkKey;
+
+ protected int networkKeyIndex;
+
+ /**
+ * 1 bit
+ */
+ protected byte keyRefreshFlag;
+
+ /**
+ * 1 bit
+ */
+ protected byte ivUpdateFlag;
+
+ /**
+ * 4 bytes
+ */
+ protected int ivIndex;
+
+ /**
+ * unicast address for primary element
+ * 2 bytes
+ */
+ protected int unicastAddress;
+
+
+ /**
+ * auth value for static oob AuthMethod
+ * {@link com.telink.ble.mesh.core.provisioning.AuthenticationMethod#StaticOOB}
+ */
+ protected byte[] authValue = null;
+
+ /**
+ * auto use no-OOB if auth value is null
+ */
+ protected boolean autoUseNoOOB = false;
+
+// private ProvisioningParams provisioningParams;
+
+ protected int provisioningState;
+
+ /**
+ * valued when generating provisioning data
+ */
+ protected byte[] deviceKey = null;
+
+ protected ProvisioningCapabilityPDU deviceCapability = null;
+
+ public ProvisioningDevice(BluetoothDevice bluetoothDevice, byte[] deviceUUID, int unicastAddress) {
+ this.bluetoothDevice = bluetoothDevice;
+ this.deviceUUID = deviceUUID;
+ this.unicastAddress = unicastAddress;
+ }
+
+ public ProvisioningDevice(BluetoothDevice bluetoothDevice, byte[] deviceUUID, byte[] networkKey, int networkKeyIndex, byte keyRefreshFlag, byte ivUpdateFlag, int ivIndex, int unicastAddress) {
+ this.bluetoothDevice = bluetoothDevice;
+ this.deviceUUID = deviceUUID;
+ this.networkKey = networkKey;
+ this.networkKeyIndex = networkKeyIndex;
+ this.keyRefreshFlag = keyRefreshFlag;
+ this.ivUpdateFlag = ivUpdateFlag;
+ this.ivIndex = ivIndex;
+ this.unicastAddress = unicastAddress;
+ }
+
+
+ public ProvisioningDevice() {
+ }
+
+ protected ProvisioningDevice(Parcel in) {
+ bluetoothDevice = in.readParcelable(BluetoothDevice.class.getClassLoader());
+ deviceUUID = in.createByteArray();
+ oobInfo = in.readInt();
+ networkKey = in.createByteArray();
+ networkKeyIndex = in.readInt();
+ keyRefreshFlag = in.readByte();
+ ivUpdateFlag = in.readByte();
+ ivIndex = in.readInt();
+ unicastAddress = in.readInt();
+ authValue = in.createByteArray();
+ provisioningState = in.readInt();
+ deviceKey = in.createByteArray();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ProvisioningDevice createFromParcel(Parcel in) {
+ return new ProvisioningDevice(in);
+ }
+
+ @Override
+ public ProvisioningDevice[] newArray(int size) {
+ return new ProvisioningDevice[size];
+ }
+ };
+
+ public byte[] generateProvisioningData() {
+ byte flags = (byte) ((keyRefreshFlag & 0b01) | (ivUpdateFlag & 0b10));
+ ByteBuffer buffer = ByteBuffer.allocate(DATA_PDU_LEN).order(ByteOrder.BIG_ENDIAN);
+ buffer.put(networkKey)
+ .putShort((short) networkKeyIndex)
+ .put(flags)
+ .putInt(ivIndex)
+ .putShort((short) unicastAddress);
+ return buffer.array();
+ }
+
+
+ public int getOobInfo() {
+ return oobInfo;
+ }
+
+ public void setOobInfo(int oobInfo) {
+ this.oobInfo = oobInfo;
+ }
+
+ public BluetoothDevice getBluetoothDevice() {
+ return bluetoothDevice;
+ }
+
+ public byte[] getDeviceUUID() {
+ return deviceUUID;
+ }
+
+ public byte[] getNetworkKey() {
+ return networkKey;
+ }
+
+ public void setNetworkKey(byte[] networkKey) {
+ this.networkKey = networkKey;
+ }
+
+ public int getNetworkKeyIndex() {
+ return networkKeyIndex;
+ }
+
+ public void setNetworkKeyIndex(int networkKeyIndex) {
+ this.networkKeyIndex = networkKeyIndex;
+ }
+
+ public byte getKeyRefreshFlag() {
+ return keyRefreshFlag;
+ }
+
+ public void setKeyRefreshFlag(byte keyRefreshFlag) {
+ this.keyRefreshFlag = keyRefreshFlag;
+ }
+
+ public byte getIvUpdateFlag() {
+ return ivUpdateFlag;
+ }
+
+ public void setIvUpdateFlag(byte ivUpdateFlag) {
+ this.ivUpdateFlag = ivUpdateFlag;
+ }
+
+ public int getIvIndex() {
+ return ivIndex;
+ }
+
+ public void setIvIndex(int ivIndex) {
+ this.ivIndex = ivIndex;
+ }
+
+ public int getUnicastAddress() {
+ return unicastAddress;
+ }
+
+ public byte[] getAuthValue() {
+ return authValue;
+ }
+
+ public void setAuthValue(byte[] authValue) {
+ this.authValue = authValue;
+ }
+
+ public int getProvisioningState() {
+ return provisioningState;
+ }
+
+ public void setProvisioningState(int provisioningState) {
+ this.provisioningState = provisioningState;
+ }
+
+ public byte[] getDeviceKey() {
+ return deviceKey;
+ }
+
+ public void setDeviceKey(byte[] deviceKey) {
+ this.deviceKey = deviceKey;
+ }
+
+ public ProvisioningCapabilityPDU getDeviceCapability() {
+ return deviceCapability;
+ }
+
+ public void setDeviceCapability(ProvisioningCapabilityPDU deviceCapability) {
+ this.deviceCapability = deviceCapability;
+ }
+
+ public void setUnicastAddress(int unicastAddress) {
+ this.unicastAddress = unicastAddress;
+ }
+
+ public boolean isAutoUseNoOOB() {
+ return autoUseNoOOB;
+ }
+
+ public void setAutoUseNoOOB(boolean autoUseNoOOB) {
+ this.autoUseNoOOB = autoUseNoOOB;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(bluetoothDevice, flags);
+ dest.writeByteArray(deviceUUID);
+ dest.writeInt(oobInfo);
+ dest.writeByteArray(networkKey);
+ dest.writeInt(networkKeyIndex);
+ dest.writeByte(keyRefreshFlag);
+ dest.writeByte(ivUpdateFlag);
+ dest.writeInt(ivIndex);
+ dest.writeInt(unicastAddress);
+ dest.writeByteArray(authValue);
+ dest.writeInt(provisioningState);
+ dest.writeByteArray(deviceKey);
+ }
+
+ @Override
+ public String toString() {
+ return "ProvisioningDevice{" +
+ "deviceUUID=" + Arrays.bytesToHexString(deviceUUID) +
+ ", oobInfo=0b" + Integer.toBinaryString(oobInfo) +
+ ", networkKey=" + Arrays.bytesToHexString(networkKey) +
+ ", networkKeyIndex=" + networkKeyIndex +
+ ", keyRefreshFlag=" + keyRefreshFlag +
+ ", ivUpdateFlag=" + ivUpdateFlag +
+ ", ivIndex=0x" + Long.toHexString(ivIndex) +
+ ", unicastAddress=0x" + Integer.toHexString(unicastAddress) +
+ ", authValue=" + Arrays.bytesToHexString(authValue) +
+ ", autoUseNoOOB=" + autoUseNoOOB +
+ ", provisioningState=" + provisioningState +
+ ", deviceKey=" + Arrays.bytesToHexString(deviceKey) +
+
+ '}';
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/RemoteProvisioningConfiguration.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/RemoteProvisioningConfiguration.java
new file mode 100644
index 00000000..25a3c747
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/RemoteProvisioningConfiguration.java
@@ -0,0 +1,92 @@
+/********************************************************************************************************
+ * @file RemoteProvisioningConfiguration.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+/**
+ * remote provisioning configurations
+ * Created by kee on 2019/11/27.
+ */
+
+public class RemoteProvisioningConfiguration {
+ // scan for 2 devices
+ private static final int DEFAULT_SCAN_LIMIT = 2;
+
+ // scan 3 seconds
+ private static final int DEFAULT_SCAN_TIMEOUT = 3;
+
+ // if app key binding needed
+ private boolean bindNeed = true;
+
+ // default bind
+ private boolean defaultBind = false;
+
+ private int scanLimit;
+
+ private int scanTimeout;
+
+ private int provisioningIndex;
+
+
+ public RemoteProvisioningConfiguration(int provisioningIndex) {
+ this.provisioningIndex = provisioningIndex;
+ }
+
+ public boolean isBindNeed() {
+ return bindNeed;
+ }
+
+ public void setBindNeed(boolean bindNeed) {
+ this.bindNeed = bindNeed;
+ }
+
+ public boolean isDefaultBind() {
+ return defaultBind;
+ }
+
+ public void setDefaultBind(boolean defaultBind) {
+ this.defaultBind = defaultBind;
+ }
+
+ public int getScanLimit() {
+ return scanLimit;
+ }
+
+ public void setScanLimit(int scanLimit) {
+ this.scanLimit = scanLimit;
+ }
+
+ public int getScanTimeout() {
+ return scanTimeout;
+ }
+
+ public void setScanTimeout(int scanTimeout) {
+ this.scanTimeout = scanTimeout;
+ }
+
+ public int getProvisioningIndex() {
+ return provisioningIndex;
+ }
+
+ public void setProvisioningIndex(int provisioningIndex) {
+ this.provisioningIndex = provisioningIndex;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/RemoteProvisioningDevice.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/RemoteProvisioningDevice.java
new file mode 100644
index 00000000..acce6012
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/RemoteProvisioningDevice.java
@@ -0,0 +1,120 @@
+/********************************************************************************************************
+ * @file RemoteProvisioningDevice.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+import android.os.Parcel;
+
+import com.telink.ble.mesh.core.message.rp.ScanReportStatusMessage;
+import com.telink.ble.mesh.util.Arrays;
+
+/**
+ * Model for provisioning flow
+ * Created by kee on 2019/9/4.
+ */
+// advertisingDevice is null
+public class RemoteProvisioningDevice extends ProvisioningDevice {
+
+ private byte rssi;
+
+ private byte[] uuid = null;
+
+ // proxy address
+ private int serverAddress;
+
+
+ public RemoteProvisioningDevice(byte rssi, byte[] uuid, int serverAddress) {
+ this.rssi = rssi;
+ this.uuid = uuid;
+ this.serverAddress = serverAddress;
+ }
+
+ protected RemoteProvisioningDevice(Parcel in) {
+ super(in);
+ rssi = in.readByte();
+ uuid = in.createByteArray();
+ serverAddress = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeByte(rssi);
+ dest.writeByteArray(uuid);
+ dest.writeInt(serverAddress);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public RemoteProvisioningDevice createFromParcel(Parcel in) {
+ return new RemoteProvisioningDevice(in);
+ }
+
+ @Override
+ public RemoteProvisioningDevice[] newArray(int size) {
+ return new RemoteProvisioningDevice[size];
+ }
+ };
+
+ public byte getRssi() {
+ return rssi;
+ }
+
+ public byte[] getUuid() {
+ return uuid;
+ }
+
+ public int getServerAddress() {
+ return serverAddress;
+ }
+
+ public void setRssi(byte rssi) {
+ this.rssi = rssi;
+ }
+
+ public void setUuid(byte[] uuid) {
+ this.uuid = uuid;
+ }
+
+ public void setServerAddress(int serverAddress) {
+ this.serverAddress = serverAddress;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RemoteProvisioningDevice device = (RemoteProvisioningDevice) o;
+ return java.util.Arrays.equals(uuid, device.uuid);
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Arrays.hashCode(uuid);
+ }
+
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/Scheduler.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/Scheduler.java
new file mode 100644
index 00000000..3551c610
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/Scheduler.java
@@ -0,0 +1,457 @@
+/********************************************************************************************************
+ * @file Scheduler.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * scheduler
+ * Created by kee on 2018/9/17.
+ * Mesh_Model_Specification v1.0.pdf#5.2.3.4
+ */
+public final class Scheduler implements Serializable ,Parcelable{
+
+ /**
+ * #ref builder desc
+ */
+ public static final int YEAR_ANY = 0x64;
+
+ public static final int DAY_ANY = 0x00;
+
+ public static final int HOUR_ANY = 0x18;
+
+ public static final int HOUR_RANDOM = 0x19;
+
+ public static final int MINUTE_ANY = 0x3C;
+ public static final int MINUTE_CYCLE_15 = 0x3D;
+ public static final int MINUTE_CYCLE_20 = 0x3E;
+ public static final int MINUTE_RANDOM = 0x3F;
+
+ public static final int SECOND_ANY = 0x3C;
+ public static final int SECOND_CYCLE_15 = 0x3D;
+ public static final int SECOND_CYCLE_20 = 0x3E;
+ public static final int SECOND_RANDOM = 0x3F;
+
+ public static final int ACTION_OFF = 0x0;
+ public static final int ACTION_ON = 0x1;
+ public static final int ACTION_SCENE = 0x2;
+ public static final int ACTION_NO = 0xF;
+
+ /**
+ * 4 bits
+ */
+ private byte index;
+
+ /**
+ * 76 bits
+ */
+ private Register register;
+
+ private Scheduler(byte index, Register register) {
+ this.index = index;
+ this.register = register;
+ }
+
+ /*public long getRegisterParam0() {
+ return index |
+ register.year << 4 |
+ register.month << 11 |
+ register.day << 23 |
+ register.hour << 28 |
+ register.minute << 33 |
+ register.second << 39 |
+ register.week << 45 |
+ register.action << 52 |
+ register.transTime << 56;
+ }
+
+ public int getRegisterParam1() {
+ return register.sceneId;
+ }*/
+
+ protected Scheduler(Parcel in) {
+ index = in.readByte();
+ register = in.readParcelable(Register.class.getClassLoader());
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public Scheduler createFromParcel(Parcel in) {
+ return new Scheduler(in);
+ }
+
+ @Override
+ public Scheduler[] newArray(int size) {
+ return new Scheduler[size];
+ }
+ };
+
+ public byte getIndex() {
+ return index;
+ }
+
+ public Register getRegister() {
+ return register;
+ }
+
+ public static Scheduler fromBytes(byte[] data) {
+ if (data == null || data.length != 10) return null;
+ byte index = (byte) (data[0] & 0x0F);
+ Register reg = new Register();
+ reg.year = (data[0] >> 4 & 0b1111) | ((data[1] & 0b111) << 4);
+ reg.month = (data[1] >> 3 & 0b11111) | ((data[2] & 0b1111111) << 5);
+ reg.day = (data[2] >> 7 & 0b1) | ((data[3] & 0b1111) << 1); // d3 4
+ reg.hour = (data[3] >> 4 & 0b1111) | ((data[4] & 0b1) << 4); // d4 1
+ reg.minute = ((data[4] >> 1) & 0b111111); // d4 7
+ reg.second = ((data[4] >> 7 & 0b1) | ((data[5] & 0b11111)) << 1); // d5 5
+ reg.week = ((data[5] >> 5 & 0b111) | ((data[6] & 0b1111)) << 3); // d6 4
+ reg.action = (data[6] >> 4 & 0b1111); // d6 8
+ reg.transTime = data[7] & 0xFF; // d7 8
+ reg.sceneId = (data[8] & 0xFF) | ((data[9] << 8) & 0xFF); // d8 d9
+ return new Scheduler(index, reg);
+ }
+
+ public byte[] toBytes() {
+ ByteBuffer byteBuffer = ByteBuffer.allocate(10).order(ByteOrder.LITTLE_ENDIAN);
+ byteBuffer.putLong(index |
+ register.year << 4 |
+ register.month << 11 |
+ register.day << 23 |
+ register.hour << 28 |
+ register.minute << 33 |
+ register.second << 39 |
+ register.week << 45 |
+ register.action << 52 |
+ register.transTime << 56)
+ .putShort((short) register.sceneId);
+ return byteBuffer.array();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte(index);
+ dest.writeParcelable(register, flags);
+ }
+
+ public static final class Builder {
+
+
+ /**
+ * 4 bits
+ * Index of the Schedule Register entry to set
+ * 0x0-0xF
+ */
+ private byte index = 1;
+
+ /**
+ * 7 bits
+ * 0x00–0x63: 2 least significant digits of the year
+ * 0x64: Any year
+ * All other values: Prohibited
+ */
+ private byte year = 0x00;
+
+ /**
+ * 12 bits
+ * bit 0-11 means Scheduled in
+ * January/February/March/April/May/June/July/August/September/October/November/December
+ */
+ private short month = 0b000000000000;
+
+ /**
+ * 5 bits
+ * 0x00 Any day
+ * 0x01–0x1F Day of the month, when number overflow, event occurs in the last day
+ */
+ private byte day = 0x00;
+
+ /**
+ * 5 bits
+ * 0x00–0x17: Hour of the day (00 to 23 hours)
+ * 0x18: Any hour of the day
+ * 0x19: Once a day (at a random hour)
+ * All other values: Prohibited
+ */
+ private byte hour = 0x00;
+
+ /**
+ * 6 bits
+ * 0x00–0x3B Minute of the hour (00 to 59)
+ * 0x3C Any minute of the hour
+ * 0x3D Every 15 minutes (minute modulo 15 is 0) (0, 15, 30, 45)
+ * 0x3E Every 20 minutes (minute modulo 20 is 0) (0, 20, 40)
+ * 0x3F Once an hour (at a random minute)
+ */
+ private byte minute = 0x00;
+
+ /**
+ * 6 bits
+ * 0x00–0x3B Second of the minute (00 to 59)
+ * 0x3C Any second of the minute
+ * 0x3D Every 15 seconds (minute modulo 15 is 0) (0, 15, 30, 45)
+ * 0x3E Every 20 seconds (minute modulo 20 is 0) (0, 20, 40)
+ * 0x3F Once an minute (at a random second)
+ */
+ private byte second = 0x00;
+
+ /**
+ * 7 bits
+ * bit 0-6 means
+ * Scheduled on Mondays/Tuesdays/Wednesdays/Thursdays/Fridays/Saturdays/Sundays
+ */
+ private byte week = 0b000000;
+
+ /**
+ * 4 bits
+ * 0x0 Turn Off
+ * 0x1 Turn On
+ * 0x2 Scene Recall
+ * 0xF No action
+ * All other values
+ * Reserved for Future Use
+ */
+ private byte action;
+
+ /**
+ * 8 bits
+ * #reference model spec 3.1.3.1
+ * bit 0-5 The number of Steps
+ * bit 6-7 Transition Step Resolution
+ */
+ private byte transTime;
+
+
+ /**
+ * 16 bit
+ * scene id
+ */
+ private short sceneId;
+
+ public Builder setIndex(byte index) {
+ this.index = index;
+ return this;
+ }
+
+ public Builder setYear(byte year) {
+ this.year = year;
+ return this;
+ }
+
+ public Builder setMonth(short month) {
+ this.month = month;
+ return this;
+ }
+
+ public Builder setDay(byte day) {
+ this.day = day;
+ return this;
+ }
+
+ public Builder setHour(byte hour) {
+ this.hour = hour;
+ return this;
+ }
+
+ public Builder setMinute(byte minute) {
+ this.minute = minute;
+ return this;
+ }
+
+ public Builder setSecond(byte second) {
+ this.second = second;
+ return this;
+ }
+
+ public Builder setWeek(byte week) {
+ this.week = week;
+ return this;
+ }
+
+ public Builder setAction(byte action) {
+ this.action = action;
+ return this;
+ }
+
+ public Builder setTransTime(byte transTime) {
+ this.transTime = transTime;
+ return this;
+ }
+
+ public Builder setSceneId(short sceneId) {
+ this.sceneId = sceneId;
+ return this;
+ }
+
+ public Scheduler build() {
+ Register register = new Register(
+ this.year,
+ this.month,
+ this.day,
+ this.hour,
+ this.minute,
+ this.second,
+ this.week,
+ this.action,
+ this.transTime,
+ this.sceneId
+ );
+ return new Scheduler(this.index, register);
+ }
+ }
+
+
+ public static class Register implements Serializable, Parcelable {
+ private long year;
+ private long month;
+ private long day;
+ private long hour;
+ private long minute;
+ private long second;
+ private long week;
+ private long action;
+ private long transTime;
+ private int sceneId;
+
+ private Register() {
+
+ }
+
+ private Register(byte year,
+ short month,
+ byte day,
+ byte hour,
+ byte minute,
+ byte second,
+ byte week,
+ byte action,
+ byte transTime,
+ int sceneId) {
+ this.year = year & 0xFF;
+ this.month = month & 0xFFFF;
+ this.day = day & 0xFF;
+ this.hour = hour & 0xFF;
+ this.minute = minute & 0xFF;
+ this.second = second & 0xFF;
+ this.week = week & 0xFF;
+ this.action = action & 0xFF;
+ this.transTime = transTime & 0xFF;
+ this.sceneId = sceneId & 0xFFFF;
+ }
+
+
+ protected Register(Parcel in) {
+ year = in.readLong();
+ month = in.readLong();
+ day = in.readLong();
+ hour = in.readLong();
+ minute = in.readLong();
+ second = in.readLong();
+ week = in.readLong();
+ action = in.readLong();
+ transTime = in.readLong();
+ sceneId = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public Register createFromParcel(Parcel in) {
+ return new Register(in);
+ }
+
+ @Override
+ public Register[] newArray(int size) {
+ return new Register[size];
+ }
+ };
+
+ public long getYear() {
+ return year;
+ }
+
+ public long getMonth() {
+ return month;
+ }
+
+ public long getDay() {
+ return day;
+ }
+
+ public long getHour() {
+ return hour;
+ }
+
+ public long getMinute() {
+ return minute;
+ }
+
+ public long getSecond() {
+ return second;
+ }
+
+ public long getWeek() {
+ return week;
+ }
+
+ public long getAction() {
+ return action;
+ }
+
+ public long getTransTime() {
+ return transTime;
+ }
+
+ public int getSceneId() {
+ return sceneId;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(year);
+ dest.writeLong(month);
+ dest.writeLong(day);
+ dest.writeLong(hour);
+ dest.writeLong(minute);
+ dest.writeLong(second);
+ dest.writeLong(week);
+ dest.writeLong(action);
+ dest.writeLong(transTime);
+ dest.writeInt(sceneId);
+ }
+ }
+
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/TransitionTime.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/TransitionTime.java
new file mode 100644
index 00000000..feff61cc
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/entity/TransitionTime.java
@@ -0,0 +1,112 @@
+/********************************************************************************************************
+ * @file TransitionTime.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.entity;
+
+/**
+ * Created by kee on 2019/2/25.
+ */
+
+public class TransitionTime {
+
+ // 6 bits
+ private byte number;
+
+ /**
+ * 2 bits
+ * 0b00
+ * The Default Transition Step Resolution is 100 milliseconds
+ * 0b01
+ * The Default Transition Step Resolution is 1 second
+ * 0b10
+ * The Default Transition Step Resolution is 10 seconds
+ * 0b11
+ * The Default Transition Step Resolution is 10 minutes
+ */
+ private byte step;
+ // 0b111111
+ private static final int MAX_STEP_VALUE = 0x3F;
+
+ private static final byte STEP_RESOLUTION_100_MILL = 0b00;
+ private static final byte STEP_RESOLUTION_1_SECOND = 0b01;
+ private static final byte STEP_RESOLUTION_10_SECOND = 0b10;
+ private static final byte STEP_RESOLUTION_10_MINUTE = 0b11;
+
+ private static final int PERIOD_STEP_100_MILL = 100;
+ private static final int PERIOD_STEP_1_SECOND = 1000;
+ private static final int PERIOD_STEP_10_SECOND = 10 * 1000;
+ private static final int PERIOD_STEP_10_MINUTE = 10 * 60 * 1000;
+
+ public TransitionTime(byte number, byte step) {
+ this.number = number;
+ this.step = step;
+ }
+
+ public static TransitionTime fromTime(long millisecond) {
+ byte step = 0, number = 0;
+ if (millisecond <= 0) {
+ step = 0;
+ number = 0;
+ } else if (millisecond <= MAX_STEP_VALUE * PERIOD_STEP_100_MILL) {
+ step = STEP_RESOLUTION_100_MILL;
+ number = (byte) (millisecond / PERIOD_STEP_100_MILL);
+ } else if (millisecond <= MAX_STEP_VALUE * PERIOD_STEP_1_SECOND) {
+ step = STEP_RESOLUTION_1_SECOND;
+ number = (byte) (millisecond / PERIOD_STEP_1_SECOND);
+ } else if (millisecond <= MAX_STEP_VALUE * PERIOD_STEP_10_SECOND) {
+ step = STEP_RESOLUTION_10_SECOND;
+ number = (byte) (millisecond / PERIOD_STEP_10_SECOND);
+ } else if (millisecond <= MAX_STEP_VALUE * PERIOD_STEP_10_MINUTE) {
+ step = STEP_RESOLUTION_10_MINUTE;
+ number = (byte) (millisecond / PERIOD_STEP_10_MINUTE);
+ }
+ return new TransitionTime(number, step);
+ }
+
+ public byte getValue() {
+ return (byte) ((step << 6) | number);
+ }
+
+ public byte getNumber() {
+ return number;
+ }
+
+ public byte getStep() {
+ return step;
+ }
+
+ public int getResolution() {
+ switch (step) {
+ case STEP_RESOLUTION_100_MILL:
+ return PERIOD_STEP_100_MILL;
+
+ case STEP_RESOLUTION_1_SECOND:
+ return PERIOD_STEP_1_SECOND;
+
+ case STEP_RESOLUTION_10_SECOND:
+ return PERIOD_STEP_10_SECOND;
+
+ case STEP_RESOLUTION_10_MINUTE:
+ return PERIOD_STEP_10_MINUTE;
+ }
+ return 0;
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/foundation/Event.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/foundation/Event.java
new file mode 100644
index 00000000..27b422dd
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/foundation/Event.java
@@ -0,0 +1,69 @@
+/********************************************************************************************************
+ * @file Event.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+
+package com.telink.ble.mesh.foundation;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public abstract class Event implements Parcelable {
+
+ protected Object sender;
+ protected T type;
+ protected ThreadMode threadMode = ThreadMode.Default;
+
+
+ public Event() {
+ }
+
+ public Event(Object sender, T type) {
+ this(sender, type, ThreadMode.Default);
+ }
+
+ public Event(Object sender, T type, ThreadMode threadMode) {
+ this.sender = sender;
+ this.type = type;
+ this.threadMode = threadMode;
+ }
+
+ public Object getSender() {
+ return sender;
+ }
+
+ public T getType() {
+ return type;
+ }
+
+ public ThreadMode getThreadMode() {
+ return this.threadMode;
+ }
+
+ public Event setThreadMode(ThreadMode mode) {
+ this.threadMode = mode;
+ return this;
+ }
+
+ public enum ThreadMode {
+ Background, Main, Default,
+ ;
+ }
+}
\ No newline at end of file
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/foundation/EventBus.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/foundation/EventBus.java
new file mode 100644
index 00000000..d0fe8867
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/foundation/EventBus.java
@@ -0,0 +1,235 @@
+/********************************************************************************************************
+ * @file EventBus.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+
+package com.telink.ble.mesh.foundation;
+
+import android.os.Handler;
+import android.os.Looper;
+
+
+import com.telink.ble.mesh.util.MeshLogger;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class EventBus {
+
+ private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
+ private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
+ private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
+ private static final int KEEP_ALIVE = 1;
+ private static final BlockingQueue sPoolWorkQueue =
+ new LinkedBlockingQueue<>(128);
+ private static final ThreadFactory sThreadFactory = new DefaultThreadFactory();
+
+ private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
+ TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); //Executors.newCachedThreadPool(new DefaultThreadFactory());
+
+ protected final Map>> mEventListeners = new ConcurrentHashMap<>();
+ protected final Queue> mEventQueue = new ConcurrentLinkedQueue<>();
+ protected final Handler mCurrentThreadHandler = new Handler(Looper.myLooper());
+ protected final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
+ private final Object mLock = new Object();
+ protected boolean processing = false;
+ private final Runnable task = new Runnable() {
+ @Override
+ public void run() {
+ processEvent();
+ }
+ };
+
+ public void addEventListener(T eventType, EventListener listener) {
+
+ synchronized (this.mEventListeners) {
+ List> listeners;
+
+ if (this.mEventListeners.containsKey(eventType)) {
+ listeners = this.mEventListeners.get(eventType);
+ } else {
+ listeners = new CopyOnWriteArrayList<>();
+ this.mEventListeners.put(eventType, listeners);
+ }
+
+ if (!listeners.contains(listener)) {
+ listeners.add(listener);
+ }
+ }
+ }
+
+ public void removeEventListener(EventListener listener) {
+ synchronized (this.mEventListeners) {
+ for (T eventType : this.mEventListeners.keySet()) {
+ this.removeEventListener(eventType, listener);
+ }
+ }
+ }
+
+ public void removeEventListener(T eventType, EventListener listener) {
+ synchronized (this.mEventListeners) {
+ if (this.mEventListeners.containsKey(eventType)) {
+ List> listeners = this.mEventListeners.get(eventType);
+ listeners.remove(listener);
+ }
+ }
+ }
+
+ public void removeEventListeners() {
+ synchronized (this.mEventListeners) {
+ for (T eventType : this.mEventListeners.keySet()) {
+ List> listeners = this.mEventListeners.get(eventType);
+ listeners.clear();
+ this.mEventListeners.remove(eventType);
+ }
+ }
+ }
+
+ public void dispatchEvent(final Event event) {
+// MeshLogger.log("event looper : " + event.getThreadMode());
+
+ this.mEventQueue.add(event);
+
+ MeshLogger.log("post event : " + event.getType() + "--" + event.getClass().getSimpleName());
+
+ synchronized (this.mLock) {
+ if (!this.processing)
+ this.processOnThread();
+ }
+ }
+
+ private void processOnThread() {
+
+ final Event event;
+
+ synchronized (mEventQueue) {
+ event = this.mEventQueue.peek();
+ if (event == null)
+ return;
+ }
+
+ switch (event.getThreadMode()) {
+ case Background:
+ EXECUTOR_SERVICE.execute(task);
+ break;
+ case Main:
+ mMainThreadHandler.post(task);
+ break;
+ case Default:
+ mCurrentThreadHandler.post(task);
+ break;
+
+ }
+ }
+
+ private void processEvent() {
+// MeshLogger.log("process on thread : " + Thread.currentThread().getName());
+
+ final Event event;
+
+ synchronized (mEventQueue) {
+ event = mEventQueue.poll();
+ if (event == null)
+ return;
+ }
+
+// MeshLogger.log("process event : " + event.getType() + "--" + event.getClass().getName());
+
+ T eventType = event.getType();
+ List> listeners = null;
+
+ synchronized (this.mEventListeners) {
+ if (this.mEventListeners.containsKey(eventType)) {
+ listeners = this.mEventListeners.get(eventType);
+ }
+ }
+
+ if (listeners != null && !listeners.isEmpty()) {
+ synchronized (this.mLock) {
+ this.processing = true;
+ }
+
+ for (EventListener listener : listeners) {
+ if (listener != null)
+ listener.performed(event);
+ }
+ }
+
+ this.processEventCompleted();
+ }
+
+ private void processEventCompleted() {
+ synchronized (this.mLock) {
+ this.processing = false;
+ }
+
+ if (!this.mEventQueue.isEmpty())
+ this.processOnThread();
+ }
+
+ private static class DefaultThreadFactory implements ThreadFactory {
+ private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
+ private final AtomicInteger threadNumber = new AtomicInteger(1);
+ private final ThreadGroup group;
+ private final String namePrefix;
+
+ DefaultThreadFactory() {
+ SecurityManager s = System.getSecurityManager();
+ group = (s != null) ? s.getThreadGroup() :
+ Thread.currentThread().getThreadGroup();
+ namePrefix = "pool-" +
+ POOL_NUMBER.getAndIncrement() +
+ "-thread-";
+ }
+
+ @Override
+ public Thread newThread(final Runnable r) {
+
+ Runnable run = new Runnable() {
+ @Override
+ public void run() {
+ android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
+ r.run();
+ }
+ };
+
+ Thread thread = new Thread(group, run,
+ namePrefix + threadNumber.getAndIncrement(),
+ 0);
+ if (thread.isDaemon())
+ thread.setDaemon(false);
+ if (thread.getPriority() != Thread.NORM_PRIORITY)
+ thread.setPriority(Thread.NORM_PRIORITY);
+
+ return thread;
+ }
+ }
+}
diff --git a/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/foundation/EventHandler.java b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/foundation/EventHandler.java
new file mode 100644
index 00000000..c6c959d6
--- /dev/null
+++ b/src/android/TelinkBleMeshLib/src/main/java/com/telink/ble/mesh/foundation/EventHandler.java
@@ -0,0 +1,26 @@
+/********************************************************************************************************
+ * @file EventHandler.java
+ *
+ * @brief for TLSR chips
+ *
+ * @author telink
+ * @date Sep. 30, 2010
+ *
+ * @par Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd.
+ * All rights reserved.
+ *
+ * The information contained herein is confidential and proprietary property of Telink
+ * Semiconductor (Shanghai) Co., Ltd. and is available under the terms
+ * of Commercial License Agreement between Telink Semiconductor (Shanghai)
+ * Co., Ltd. and the licensee in separate contract or the terms described here-in.
+ * This heading MUST NOT be removed from this file.
+ *
+ * Licensees are granted free, non-transferable use of the information in this
+ * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
+ *
+ *******************************************************************************************************/
+package com.telink.ble.mesh.foundation;
+
+public interface EventHandler {
+ void onEventHandle(Event