8 | * Created by leonxtp on 2017/9/17.
9 | * Modified by leonxtp on 2017/9/17
10 | */
11 |
12 | public class TimeOutHelper {
13 |
14 | private ITimeOut listener;
15 |
16 | private Handler timeoutHanldler = new Handler();
17 |
18 | private Runnable timer = new Runnable() {
19 |
20 | @Override
21 | public void run() {
22 | stopTimer();
23 | if (listener != null) {
24 | listener.onTimeOut();
25 | }
26 | }
27 | };
28 |
29 | public void startTimer(ITimeOut timeoutListener, long delay) {
30 | listener = timeoutListener;
31 | timeoutHanldler.postDelayed(timer, delay);
32 | }
33 |
34 | public void stopTimer() {
35 | timeoutHanldler.removeCallbacksAndMessages(null);
36 | }
37 |
38 | public void unRegisterListener() {
39 | listener = null;
40 | }
41 |
42 | public interface ITimeOut {
43 | void onTimeOut();
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/android/android_iap/ble/src/main/java/com/jt28/a6735/ble/request/ReceiverRequestQueue.java:
--------------------------------------------------------------------------------
1 | package com.jt28.a6735.ble.request;
2 |
3 | import android.util.Log;
4 |
5 | import com.jt28.a6735.ble.callback.OnReceiverCallback;
6 |
7 | import java.util.HashMap;
8 |
9 | /**
10 | * 描述:接收通知数据请求队列
11 | */
12 | public class ReceiverRequestQueue implements IRequestQueue
14 | * Created by leonxtp on 2017/9/17.
15 | * Modified by leonxtp on 2017/9/17
16 | */
17 |
18 | public class InputStreamSource {
19 |
20 | private static final int BUFFER_SIZE = 32 * 1024;
21 | private static final String ERROR_UNSUPPORTED_SCHEME = "Unsupported file source";
22 |
23 | InputStream getStream(Context context, String imageUri) throws IOException {
24 | switch (SourceScheme.ofUri(imageUri)) {
25 |
26 | case FILE:
27 | return getStreamFromFile(imageUri);
28 |
29 | case ASSETS:
30 | return getStreamFromAssets(context, imageUri);
31 |
32 | case UNKNOWN:
33 | default:
34 | return getStreamFromOtherSource(imageUri);
35 | }
36 | }
37 |
38 | private InputStream getStreamFromFile(String fileUri) throws IOException {
39 | String filePath = SourceScheme.FILE.crop(fileUri);
40 | Log.d("lhb","路径"+filePath);
41 | return new BufferedInputStream(new FileInputStream(filePath), BUFFER_SIZE);
42 | }
43 |
44 | private InputStream getStreamFromAssets(Context context, String fileUri) throws IOException {
45 | String filePath = SourceScheme.ASSETS.crop(fileUri);
46 | return context.getAssets().open(filePath);
47 | }
48 |
49 | private InputStream getStreamFromOtherSource(String fileUri) throws IOException {
50 | throw new UnsupportedOperationException(String.format(ERROR_UNSUPPORTED_SCHEME, fileUri));
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/android/android_iap/ymodem/src/main/java/com/jt28/a6735/ymodem/L.java:
--------------------------------------------------------------------------------
1 | package com.jt28.a6735.ymodem;
2 |
3 | import android.util.Log;
4 |
5 | public class L {
6 |
7 | private static final String TAG = "YMODEM";
8 |
9 | private L() {
10 | /* cannot be instantiated */
11 | throw new UnsupportedOperationException("cannot be instantiated");
12 | }
13 |
14 | private static final boolean DEBUGGING = true;
15 |
16 | public static void f(String msg) {
17 | if (DEBUGGING) {
18 | L.e(TAG, msg);
19 | }
20 | }
21 |
22 | // 下面四个是默认tag的函数
23 | public static void i(String msg) {
24 | if (DEBUGGING)
25 | L.i(TAG, msg);
26 | }
27 |
28 | public static void d(String msg) {
29 | if (DEBUGGING)
30 | L.d(TAG, msg);
31 | }
32 |
33 | public static void e(String msg) {
34 | if (DEBUGGING)
35 | L.e(TAG, msg);
36 | }
37 |
38 | public static void v(String msg) {
39 | if (DEBUGGING)
40 | L.v(TAG, msg);
41 | }
42 |
43 | public static void w(String msg) {
44 | if (DEBUGGING)
45 | L.w(TAG, msg);
46 | }
47 |
48 | // 下面是传入自定义tag的函数
49 | public static void i(String tag, String msg) {
50 | if (DEBUGGING)
51 | Log.i(tag, msg);
52 | }
53 |
54 | public static void d(String tag, String msg) {
55 | if (DEBUGGING)
56 | Log.d(tag, msg);
57 | }
58 |
59 | public static void e(String tag, String msg) {
60 | if (DEBUGGING)
61 | Log.e(tag, msg);
62 | }
63 |
64 | public static void v(String tag, String msg) {
65 | if (DEBUGGING)
66 | Log.v(tag, msg);
67 | }
68 |
69 | public static void w(String tag, String msg) {
70 | if (DEBUGGING)
71 | Log.w(tag, msg);
72 | }
73 |
74 | public static void e(String tag, String msg, Throwable throwable) {
75 | if (DEBUGGING)
76 | Log.e(tag, msg, throwable);
77 | }
78 |
79 | public static void wtf(String tag, String msg) {
80 | if (DEBUGGING)
81 | Log.wtf(tag, msg);
82 | }
83 |
84 | }
--------------------------------------------------------------------------------
/android/android_iap/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/android/android_iap/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 | * Created by leonxtp on 2017/9/16.
13 | * Modified by leonxtp on 2017/9/16
14 | */
15 |
16 | public class FileStreamThread extends Thread {
17 |
18 | private Context mContext;
19 | private InputStream inputStream = null;
20 | private DataRaderListener listener;
21 | private String filePath;
22 | private AtomicBoolean isDataAcknowledged = new AtomicBoolean(false);
23 | private boolean isKeepRunning = false;
24 | private int fileByteSize = 0;
25 |
26 | public FileStreamThread(Context mContext, String filePath, DataRaderListener listener) {
27 | this.mContext = mContext;
28 | this.filePath = filePath;
29 | this.listener = listener;
30 | }
31 |
32 | public int getFileByteSize() throws IOException {
33 | if (fileByteSize == 0 || inputStream == null) {
34 | initStream();
35 | }
36 | return fileByteSize;
37 | }
38 |
39 | @Override
40 | public void run() {
41 | try {
42 | prepareData();
43 | } catch (IOException e) {
44 | e.printStackTrace();
45 | }
46 | }
47 |
48 | private void prepareData() throws IOException {
49 | initStream();
50 | byte[] block = new byte[1024];
51 | int dataLength;
52 | byte blockSequence = 1;//The data package of a file is actually started from 1
53 | isDataAcknowledged.set(true);
54 | isKeepRunning = true;
55 | while (isKeepRunning) {
56 |
57 | if (!isDataAcknowledged.get()) {
58 | try {
59 | //We need to sleep for a while as the sending 1024 bytes data from ble would take several seconds
60 | //In my circumstances, this can be up to 3 seconds.
61 | Thread.sleep(100);
62 | } catch (InterruptedException e) {
63 | e.printStackTrace();
64 | }
65 | continue;
66 | }
67 |
68 | if ((dataLength = inputStream.read(block)) == -1) {
69 | L.f("The file data has all been read...");
70 | if (listener != null) {
71 | onStop();
72 | listener.onFinish();
73 | }
74 | break;
75 | }
76 |
77 | byte[] packige = YModemUtil.getDataPackage(block, dataLength, blockSequence);
78 |
79 | if (listener != null) {
80 | listener.onDataReady(packige);
81 | }
82 |
83 | blockSequence++;
84 | isDataAcknowledged.set(false);
85 | }
86 |
87 | }
88 |
89 | /**
90 | * When received response from the terminal ,we should keep the thread keep going
91 | */
92 | public void keepReading() {
93 | isDataAcknowledged.set(true);
94 | }
95 |
96 | public void release() {
97 | onStop();
98 | listener = null;
99 | }
100 |
101 | private void onStop() {
102 | isKeepRunning = false;
103 | isDataAcknowledged.set(false);
104 | fileByteSize = 0;
105 | onReadFinished();
106 | }
107 |
108 | private void initStream() {
109 | if (inputStream == null) {
110 | try {
111 | inputStream = YModemUtil.getInputStream(mContext, filePath);
112 | fileByteSize = inputStream.available();
113 | } catch (IOException e) {
114 | e.printStackTrace();
115 | }
116 | }
117 | }
118 |
119 | private void onReadFinished() {
120 | if (inputStream != null) {
121 | try {
122 | inputStream.close();
123 | inputStream = null;
124 | } catch (IOException e) {
125 | e.printStackTrace();
126 | }
127 | }
128 | }
129 |
130 | public interface DataRaderListener {
131 | void onDataReady(byte[] data);
132 |
133 | void onFinish();
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/android/android_iap/ymodem/src/main/java/com/jt28/a6735/ymodem/YModemUtil.java:
--------------------------------------------------------------------------------
1 | package com.jt28.a6735.ymodem;
2 |
3 | import android.content.Context;
4 |
5 | import java.io.ByteArrayOutputStream;
6 | import java.io.DataOutputStream;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.util.Arrays;
10 |
11 | /**
12 | * Util for encapsulating data package of ymodem protocol
13 | *
14 | * Created by leonxtp on 2017/9/16.
15 | * Modified by leonxtp on 2017/9/16
16 | */
17 |
18 | public class YModemUtil {
19 |
20 | /*This is my concrete ymodem start signal, customise it to your needs*/
21 | private static final String HELLO = "HELLO BOOTLOADER";
22 |
23 | private static final byte SOH = 0x01; /* Start Of Header with data size :128*/
24 | private static final byte STX = 0x02; /* Start Of Header with data size : 1024*/
25 | private static final byte EOT = 0x04; /* End Of Transmission */
26 | private static final byte CPMEOF = 0x1A;/* Fill the last package if not long enough */
27 |
28 | private static CRC16 crc16 = new CRC16();
29 |
30 | /**
31 | * Get the first package data for hello with a terminal
32 | */
33 | public static byte[] getYModelHello() {
34 | return HELLO.getBytes();
35 | }
36 |
37 | /**
38 | * Get the file name package data
39 | *
40 | * @param fileNameString file name in String
41 | * @param fileByteSize file byte size of int value
42 | * @param fileMd5String the md5 of the file in String
43 | */
44 | public static byte[] getFileNamePackage(String fileNameString,
45 | int fileByteSize,
46 | String fileMd5String) throws IOException {
47 |
48 | byte seperator = 0x0;
49 | String fileSize = fileByteSize + "";
50 | byte[] byteFileSize = fileSize.getBytes();
51 |
52 | byte[] fileNameBytes1 = concat(fileNameString.getBytes(),
53 | new byte[]{seperator},
54 | byteFileSize);
55 |
56 | byte[] fileNameBytes2 = Arrays.copyOf(concat(fileNameBytes1,
57 | new byte[]{seperator},
58 | fileMd5String.getBytes()), 128);
59 |
60 | byte seq = 0x00;
61 | return getDataPackage(fileNameBytes2, 128, seq);
62 | }
63 |
64 | /**
65 | * Get a encapsulated package data block
66 | *
67 | * @param block byte data array
68 | * @param dataLength the actual content length in the block without 0 filled in it.
69 | * @param sequence the package serial number
70 | * @return a encapsulated package data block
71 | */
72 | public static byte[] getDataPackage(byte[] block, int dataLength, byte sequence) throws IOException {
73 |
74 | byte[] header = getDataHeader(sequence, block.length == 1024 ? STX : SOH);
75 |
76 | //The last package, fill CPMEOF if the dataLength is not sufficient
77 | if (dataLength < block.length) {
78 | int startFil = dataLength;
79 | while (startFil < block.length) {
80 | block[startFil] = CPMEOF;
81 | startFil++;
82 | }
83 | }
84 |
85 | //We should use short size when writing into the data package as it only needs 2 bytes
86 | short crc = (short) crc16.calcCRC(block);
87 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
88 | DataOutputStream dos = new DataOutputStream(baos);
89 | dos.writeShort(crc);
90 | dos.close();
91 |
92 | byte[] crcBytes = baos.toByteArray();
93 |
94 | return concat(header, block, crcBytes);
95 | }
96 |
97 | /**
98 | * Get the EOT package
99 | */
100 | public static byte[] getEOT() {
101 | return new byte[]{EOT};
102 | }
103 |
104 | /**
105 | * Get the Last package
106 | */
107 | public static byte[] getEnd() throws IOException {
108 | byte seq = 0x00;
109 | return getDataPackage(new byte[128], 128, seq);
110 | }
111 |
112 | /**
113 | * Get InputStream from Assets, you can customize it from the other sources
114 | *
115 | * @param fileAbsolutePath absolute path of the file in asstes
116 | */
117 | public static InputStream getInputStream(Context context, String fileAbsolutePath) throws IOException {
118 | return new InputStreamSource().getStream(context, fileAbsolutePath);
119 | }
120 |
121 | private static byte[] getDataHeader(byte sequence, byte start) {
122 | //The serial number of the package increases Cyclically up to 256
123 | byte modSequence = (byte) (sequence % 0x256);
124 | byte complementSeq = (byte) ~modSequence;
125 |
126 | return concat(new byte[]{start},
127 | new byte[]{modSequence},
128 | new byte[]{complementSeq});
129 | }
130 |
131 | private static byte[] concat(byte[] a, byte[] b, byte[] c) {
132 | int aLen = a.length;
133 | int bLen = b.length;
134 | int cLen = c.length;
135 | byte[] concated = new byte[aLen + bLen + cLen];
136 | System.arraycopy(a, 0, concated, 0, aLen);
137 | System.arraycopy(b, 0, concated, aLen, bLen);
138 | System.arraycopy(c, 0, concated, aLen + bLen, cLen);
139 | return concated;
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/android/android_iap/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/android/android_iap/app/src/main/java/com/jt28/a6735/android_iap/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.jt28.a6735.android_iap;
2 |
3 | import android.os.Bundle;
4 | import android.os.Environment;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.widget.Button;
9 |
10 | import com.jt28.a6735.ymodem.YModem;
11 | import com.jt28.a6735.ymodem.YModemListener;
12 |
13 | import java.io.BufferedReader;
14 | import java.io.File;
15 | import java.io.FileReader;
16 | import java.util.Arrays;
17 |
18 | public class MainActivity extends AppCompatActivity {
19 | private String DEFAULT_FILENAME = "m_uip.hex";//"miniblink.hex";
20 | private Button read_hex;
21 |
22 | private YModem ymodem;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_main);
28 |
29 | read_hex = (Button) findViewById(R.id.id_read_hex);
30 | read_hex.setOnClickListener(new View.OnClickListener() {
31 | @Override
32 | public void onClick(View view) {
33 | try {
34 | File file = new File(Environment.getExternalStorageDirectory(),
35 | DEFAULT_FILENAME);
36 | Log.d("lhb","解析" + Environment.getExternalStorageDirectory().toString() + DEFAULT_FILENAME);
37 | BufferedReader br = new BufferedReader(new FileReader(file));
38 | String readline = "";
39 | StringBuffer sb = new StringBuffer();
40 |
41 | int besac_addr = 0;//写入基础地址
42 |
43 | while ((readline = br.readLine()) != null) {
44 | System.out.println("readline:" + readline);
45 | sb.append(readline);
46 |
47 | // Log.d("lhb","转换"+ Arrays.toString(readline.toCharArray()) + "长度" + readline.length());
48 |
49 | char[] read_c_l = readline.toCharArray();
50 | byte[] read_byte = new byte[read_c_l.length/2];
51 | int read_byte_count = 0;
52 | for(int i = 1;i < read_c_l.length;i+=2) {
53 | byte temp = charToByte(read_c_l[i+1]);
54 | temp += (byte) (charToByte(read_c_l[i]) << 4);
55 | read_byte[read_byte_count] = temp;
56 | read_byte_count++;
57 | }
58 |
59 | Log.d("lhb","解析" + Arrays.toString(read_byte) + "长度"+read_byte.length + read_c_l[0]);
60 |
61 | int check = 0;
62 | for(int i= 0;i < read_byte.length-1;i++){
63 | check += read_byte[i];
64 | }
65 | byte check_byte = (byte) (0x100 - (0x0000ff&check));
66 | if(check_byte == read_byte[read_byte.length-1]) {
67 | Log.d("lhb","校验通过");
68 | } else {
69 | Log.d("lhb","校验失败");
70 | }
71 |
72 | switch(read_byte[3]) {
73 | case 0x00:{//'00' Data Rrecord:用来记录数据,HEX文件的大部分记录都是数据记录
74 | int offset = read_byte[2];
75 | offset += (read_byte[1] << 8);
76 | besac_addr += offset;
77 | Log.d("lhb","记录数据-写入地址" + besac_addr);
78 | break;
79 | }
80 | case 0x01:{//'01' End of File Record:用来标识文件结束,放在文件的最后,标识HEX文件的结尾
81 | Log.d("lhb","文件结束");
82 | break;
83 | }
84 | case 0x02:{//'02' Extended Segment Address Record:用来标识扩展段地址的记录
85 | Log.d("lhb","扩展段地址");
86 | break;
87 | }
88 | case 0x03:{//'03' Start Segment Address Record:开始段地址记录
89 | Log.d("lhb","开始段地址记录");
90 | break;
91 | }
92 | case 0x04:{//'04' Extended Linear Address Record:用来标识扩展线性地址的记录
93 | int offset = read_byte[2];
94 | offset += (read_byte[1] << 8);
95 |
96 | besac_addr = read_byte[5];
97 | besac_addr += ((read_byte[4] << 8) << 16 ) + offset;
98 | Log.d("lhb","扩展线性地址的记录" + besac_addr);
99 | break;
100 | }
101 | case 0x05:{//'05' Start Linear Address Record:开始线性地址记录
102 | Log.d("lhb","开始线性地址记录");
103 | break;
104 | }
105 | }
106 | }
107 | br.close();
108 | System.out.println("读取成功:" + sb.toString());
109 | } catch (Exception e) {
110 | e.printStackTrace();
111 | }
112 | }
113 | });
114 | }
115 |
116 | private byte charToByte(char c) {
117 | return (byte) "0123456789ABCDEF".indexOf(c);
118 | }
119 |
120 | /**
121 | * 判断SDCard是否存在 [当没有外挂SD卡时,内置ROM也被识别为存在sd卡]
122 | *
123 | * @return
124 | */
125 | public static boolean isSdCardExist() {
126 | return Environment.getExternalStorageState().equals(
127 | Environment.MEDIA_MOUNTED);
128 | }
129 |
130 | private void startTransmission() {
131 |
132 | ymodem = new YModem.Builder()
133 | .with(this)
134 | .filePath("file:///sdcard/main.bin")
135 | .fileName("main.bin")
136 | .checkMd5("123")
137 | .callback(new YModemListener() {
138 | @Override
139 | public void onDataReady(byte[] data) {
140 | //send this data[] to your ble component here...
141 | Log.d("lhb","接收到" + Arrays.toString(data));
142 | }
143 |
144 | @Override
145 | public void onProgress(int currentSent, int total) {
146 | //the progress of the file data has transmitted
147 | Log.d("lhb","接收到2" + currentSent);
148 | }
149 |
150 | @Override
151 | public void onSuccess() {
152 | //we are well done with md5 checked
153 | Log.d("lhb","接收到4");
154 | }
155 |
156 | @Override
157 | public void onFailed(String reason) {
158 | //the task has failed for several times of trying
159 | }
160 | }).build();
161 |
162 | ymodem.start();
163 | }
164 |
165 | /**
166 | * When you received response from the ble terminal, tell ymodem
167 | */
168 | public void onDataReceivedFromBLE(byte[] data) {
169 | ymodem.onReceiveData(data);
170 | }
171 |
172 | /*stop the transmission*/
173 | public void onStopClick(View view) {
174 | ymodem.stop();
175 | }
176 |
177 | @Override
178 | protected void onDestroy() {
179 | super.onDestroy();
180 | //When the activity finished unexpected, just call stop ymodem
181 | ymodem.stop();
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/android/android_iap/ymodem/src/main/java/com/jt28/a6735/ymodem/YModem.java:
--------------------------------------------------------------------------------
1 | package com.jt28.a6735.ymodem;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 |
6 | import java.io.IOException;
7 | import java.util.Arrays;
8 |
9 | /**
10 | * THE YMODEM:
11 | * *SENDER: ANDROID APP *------------------------------------------* RECEIVER: BLE DEVICE*
12 | * HELLO BOOTLOADER ---------------------------------------------->*
13 | * <---------------------------------------------------------------* C
14 | * SOH 00 FF filename0fileSizeInByte0MD5[90] ZERO[38] CRC CRC----->*
15 | * <---------------------------------------------------------------* ACK C
16 | * STX 01 FE data[1024] CRC CRC ---------------------------------->*
17 | * <---------------------------------------------------------------* ACK
18 | * STX 02 FF data[1024] CRC CRC ---------------------------------->*
19 | * <---------------------------------------------------------------* ACK
20 | * ...
21 | * ...
22 | *
23 | * STX 08 F7 data[1000] CPMEOF[24] CRC CRC ----------------------->*
24 | * <---------------------------------------------------------------* ACK
25 | * EOT ----------------------------------------------------------->*
26 | * <---------------------------------------------------------------* ACK
27 | * SOH 00 FF ZERO[128] ------------------------------------------->*
28 | * <---------------------------------------------------------------* ACK
29 | * <---------------------------------------------------------------* MD5_OK
30 | *
31 | * Created by leonxtp on 2017/9/16.
32 | * Modified by leonxtp on 2017/9/16
33 | */
34 |
35 | public class YModem implements FileStreamThread.DataRaderListener {
36 |
37 | private static final int STEP_HELLO = 0x00;
38 | private static final int STEP_FILE_NAME = 0x01;
39 | private static final int STEP_FILE_BODY = 0x02;
40 | private static final int STEP_EOT = 0x03;
41 | private static final int STEP_END = 0x04;
42 | private static int CURR_STEP = STEP_HELLO;
43 |
44 | private static final byte ACK = 0x06; /* ACKnowlege */
45 | private static final byte NAK = 0x15; /* Negative AcKnowlege */
46 | private static final byte CAN = 0x18; /* CANcel character */
47 | private static final byte ST_C = 'C';
48 | private static final String MD5_OK = "MD5_OK";
49 | private static final String MD5_ERR = "MD5_ERR";
50 |
51 | private Context mContext;
52 | private String filePath;
53 | private String fileNameString = "LPK001_Android";
54 | private String fileMd5String = "63e7bb6eed1de3cece411a7e3e8e763b";
55 | private YModemListener listener;
56 |
57 | private TimeOutHelper timerHelper = new TimeOutHelper();
58 | private FileStreamThread streamThread;
59 |
60 | //bytes has been sent of this transmission
61 | private int bytesSent = 0;
62 | //package data of current sending, used for int case of fail
63 | private byte[] currSending = null;
64 | private int packageErrorTimes = 0;
65 | private static final int MAX_PACKAGE_SEND_ERROR_TIMES = 6;
66 | //the timeout interval for a single package
67 | private static final int PACKAGE_TIME_OUT = 6000;
68 |
69 | /**
70 | * Construct of the YModemBLE,you may don't need the fileMD5 checking,remove it
71 | *
72 | * @param filePath absolute path of the file
73 | * @param fileNameString file name for sending to the terminal
74 | * @param fileMd5String md5 for terminal checking after transmission finished
75 | * @param listener
76 | */
77 | public YModem(Context context, String filePath,
78 | String fileNameString, String fileMd5String,
79 | YModemListener listener) {
80 | this.filePath = filePath;
81 | this.fileNameString = fileNameString;
82 | this.fileMd5String = fileMd5String;
83 | this.mContext = context;
84 | this.listener = listener;
85 | }
86 |
87 | /**
88 | * Start the transmission
89 | */
90 | public void start() {
91 | sayHello();
92 | }
93 |
94 | /**
95 | * Stop the transmission when you don't need it or shut it down in accident
96 | */
97 | public void stop() {
98 | bytesSent = 0;
99 | currSending = null;
100 | packageErrorTimes = 0;
101 | if (streamThread != null) {
102 | streamThread.release();
103 | }
104 | timerHelper.stopTimer();
105 | timerHelper.unRegisterListener();
106 | }
107 |
108 | /**
109 | * Method for the outer caller when received data from the terminal
110 | */
111 | public void onReceiveData(byte[] respData) {
112 | //Stop the package timer
113 | timerHelper.stopTimer();
114 | Log.d("lhb","kk数据" + Arrays.toString(respData) + CURR_STEP);
115 | if (respData != null && respData.length > 0) {
116 | L.f("YModem received " + respData.length + " bytes.");
117 | switch (CURR_STEP) {
118 | case STEP_HELLO:
119 | handleHello(respData);
120 | break;
121 | case STEP_FILE_NAME:
122 | handleFileName(respData);
123 | break;
124 | case STEP_FILE_BODY:
125 | handleFileBody(respData);
126 | break;
127 | case STEP_EOT:
128 | handleEOT(respData);
129 | break;
130 | case STEP_END:
131 | handleEnd(respData);
132 | break;
133 | default:
134 | break;
135 | }
136 | } else {
137 | L.f("The terminal do responsed something, but received nothing??");
138 | }
139 | }
140 |
141 | /**
142 | * ==============================================================================
143 | * Methods for sending data begin
144 | * ==============================================================================
145 | */
146 | private void sayHello() {
147 | streamThread = new FileStreamThread(mContext, filePath, this);
148 | CURR_STEP = STEP_HELLO;
149 | L.f("sayHello!!!");
150 | byte[] hello = YModemUtil.getYModelHello();
151 | sendPackageData(hello);
152 | }
153 |
154 | private void sendFileName() {
155 | CURR_STEP = STEP_FILE_NAME;
156 | L.f("sendFileName");
157 | try {
158 | int fileByteSize = streamThread.getFileByteSize();
159 | byte[] fileNamePackage = YModemUtil.getFileNamePackage(fileNameString, fileByteSize
160 | , fileMd5String);
161 | sendPackageData(fileNamePackage);
162 | } catch (IOException e) {
163 | e.printStackTrace();
164 | }
165 | }
166 |
167 | private void startSendFileData() {
168 | CURR_STEP = STEP_FILE_BODY;
169 | L.f("startSendFileData");
170 | streamThread.start();
171 | }
172 |
173 | //Callback from the data reading thread when a data package is ready
174 | @Override
175 | public void onDataReady(byte[] data) {
176 | sendPackageData(data);
177 | }
178 |
179 | private void sendEOT() {
180 | CURR_STEP = STEP_EOT;
181 | L.f("sendEOT");
182 | if (listener != null) {
183 | listener.onDataReady(YModemUtil.getEOT());
184 | }
185 | }
186 |
187 | private void sendEND() {
188 | CURR_STEP = STEP_END;
189 | L.f("sendEND");
190 | if (listener != null) {
191 | try {
192 | listener.onDataReady(YModemUtil.getEnd());
193 | } catch (IOException e) {
194 | e.printStackTrace();
195 | }
196 | }
197 | }
198 |
199 | private void sendPackageData(byte[] packageData) {
200 | if (listener != null && packageData != null) {
201 | currSending = packageData;
202 | //Start the timer, it will be cancelled when reponse received,
203 | // or trigger the timeout and resend the current package data
204 | timerHelper.startTimer(timeoutListener, PACKAGE_TIME_OUT);
205 | listener.onDataReady(packageData);
206 | }
207 | }
208 |
209 | /**
210 | * ==============================================================================
211 | * Method for handling the response of a package
212 | * ==============================================================================
213 | */
214 | private void handleHello(byte[] value) {
215 | int character = value[0];
216 | if (character == ST_C) {//Receive "C" for "HELLO"
217 | L.f("Received 'C'");
218 | packageErrorTimes = 0;
219 | sendFileName();
220 | } else {
221 | handleOthers(character);
222 | }
223 | }
224 |
225 | //The file name package was responsed
226 | private void handleFileName(byte[] value) {
227 | if (value.length == 2 && value[0] == ACK && value[1] == ST_C) {//Receive 'ACK C' for file name
228 | L.f("Received 'ACK C'");
229 | packageErrorTimes = 0;
230 | startSendFileData();
231 | } else if (value[0] == ST_C) {//Receive 'C' for file name, this package should be resent
232 | L.f("Received 'C'");
233 | handlePackageFail("Received 'C' without 'ACK' after sent file name");
234 | } else {
235 | handleOthers(value[0]);
236 | }
237 | }
238 |
239 | private void handleFileBody(byte[] value) {
240 | if (value.length == 1 && value[0] == ACK) {//Receive ACK for file data
241 | L.f("Received 'ACK'");
242 | packageErrorTimes = 0;
243 | bytesSent += currSending.length;
244 | try {
245 | if (listener != null) {
246 | listener.onProgress(bytesSent, streamThread.getFileByteSize());
247 | }
248 | } catch (IOException e) {
249 | e.printStackTrace();
250 | }
251 | streamThread.keepReading();
252 |
253 | } else if (value.length == 1 && value[0] == ST_C) {
254 | L.f("Received 'C'");
255 | //Receive C for file data, the ymodem cannot handle this circumstance, transmission failed...
256 | handlePackageFail("Received 'C' after sent file data");
257 | } else {
258 | handleOthers(value[0]);
259 | }
260 | }
261 |
262 | private void handleEOT(byte[] value) {
263 | if (value[0] == ACK) {
264 | L.f("Received 'ACK'");
265 | packageErrorTimes = 0;
266 | sendEND();
267 | } else if (value[0] == ST_C) {//As we haven't received ACK, we should resend EOT
268 | handlePackageFail("Received 'C' after sent EOT");
269 | } else {
270 | handleOthers(value[0]);
271 | }
272 | }
273 |
274 | private void handleEnd(byte[] character) {
275 | Log.d("lhb","数据");
276 | if (character[0] == ACK) {//The last ACK represents that the transmission has been finished, but we should validate the file
277 | L.f("Received 'ACK'");
278 | packageErrorTimes = 0;
279 | } else if ((new String(character)).equals(MD5_OK)) {//The file data has been checked,Well Done!
280 | L.f("Received 'MD5_OK'");
281 | stop();
282 | if (listener != null) {
283 | listener.onSuccess();
284 | }
285 | } else if ((new String(character)).equals(MD5_ERR)) {//Oops...Transmission Failed...
286 | L.f("Received 'MD5_ERR'");
287 | stop();
288 | if (listener != null) {
289 | listener.onFailed("MD5 check failed!!!");
290 | }
291 | } else {
292 | handleOthers(character[0]);
293 | }
294 | }
295 |
296 | private void handleOthers(int character) {
297 | if (character == NAK) {//We need to resend this package as the terminal failed when checking the crc
298 | L.f("Received 'NAK'");
299 | handlePackageFail("Received NAK");
300 | } else if (character == CAN) {//Some big problem occurred, transmission failed...
301 | L.f("Received 'CAN'");
302 | if (listener != null) {
303 | listener.onFailed("Received CAN");
304 | }
305 | stop();
306 | }
307 | }
308 |
309 | //Handle a failed package data ,resend it up to MAX_PACKAGE_SEND_ERROR_TIMES times.
310 | //If still failed, then the transmission failed.
311 | private void handlePackageFail(String reason) {
312 | packageErrorTimes++;
313 | L.f("Fail:" + reason + " for " + packageErrorTimes + " times");
314 | if (packageErrorTimes < MAX_PACKAGE_SEND_ERROR_TIMES) {
315 | sendPackageData(currSending);
316 | } else {
317 | //Still, we stop the transmission, release the resources
318 | stop();
319 | if (listener != null) {
320 | listener.onFailed(reason);
321 | }
322 | }
323 | }
324 |
325 | /* The InputStream data reading thread was done */
326 | @Override
327 | public void onFinish() {
328 | sendEOT();
329 | }
330 |
331 | //The timeout listener
332 | private TimeOutHelper.ITimeOut timeoutListener = new TimeOutHelper.ITimeOut() {
333 | @Override
334 | public void onTimeOut() {
335 | L.f("------ time out ------");
336 | if (currSending != null) {
337 | handlePackageFail("package timeout...");
338 | }
339 | }
340 | };
341 |
342 | public static class Builder {
343 | private Context context;
344 | private String filePath;
345 | private String fileNameString;
346 | private String fileMd5String;
347 | private YModemListener listener;
348 |
349 | public Builder with(Context context) {
350 | this.context = context;
351 | return this;
352 | }
353 |
354 | public Builder filePath(String filePath) {
355 | this.filePath = filePath;
356 | return this;
357 | }
358 |
359 | public Builder fileName(String fileName) {
360 | this.fileNameString = fileName;
361 | return this;
362 | }
363 |
364 | public Builder checkMd5(String fileMd5String) {
365 | this.fileMd5String = fileMd5String;
366 | return this;
367 | }
368 |
369 | public Builder callback(YModemListener listener) {
370 | this.listener = listener;
371 | return this;
372 | }
373 |
374 | public YModem build() {
375 | return new YModem(context, filePath, fileNameString, fileMd5String, listener);
376 | }
377 |
378 | }
379 |
380 | }
381 |
--------------------------------------------------------------------------------
/android/android_iap/ble/src/main/java/com/jt28/a6735/ble/BleController.java:
--------------------------------------------------------------------------------
1 | package com.jt28.a6735.ble;
2 |
3 | import android.bluetooth.BluetoothAdapter;
4 | import android.bluetooth.BluetoothDevice;
5 | import android.bluetooth.BluetoothGatt;
6 | import android.bluetooth.BluetoothGattCallback;
7 | import android.bluetooth.BluetoothGattCharacteristic;
8 | import android.bluetooth.BluetoothGattDescriptor;
9 | import android.bluetooth.BluetoothGattService;
10 | import android.bluetooth.BluetoothManager;
11 | import android.bluetooth.BluetoothProfile;
12 | import android.content.Context;
13 | import android.os.Handler;
14 | import android.os.Looper;
15 | import android.util.Log;
16 |
17 | import com.jt28.a6735.ble.callback.BleDeviceScanCallback;
18 | import com.jt28.a6735.ble.callback.ConnectCallback;
19 | import com.jt28.a6735.ble.callback.OnReceiverCallback;
20 | import com.jt28.a6735.ble.callback.OnWriteCallback;
21 | import com.jt28.a6735.ble.callback.ScanCallback;
22 | import com.jt28.a6735.ble.request.ReceiverRequestQueue;
23 |
24 | import java.util.Arrays;
25 | import java.util.HashMap;
26 | import java.util.Iterator;
27 | import java.util.List;
28 | import java.util.Map;
29 | import java.util.Set;
30 | import java.util.UUID;
31 |
32 | /**
33 | * Description:
34 | * Author: Hansion www.hansion.win
35 | * Time: 2017/2/13 9:43
36 | */
37 | public class BleController {
38 |
39 | private static String LOGTAG = "H_Ble_Lib --> ";
40 |
41 | //BleCOntroller实例
42 | private static BleController sBleManager;
43 | private Context mContext;
44 |
45 | private BluetoothManager mBluetoothManager;
46 | private BluetoothAdapter mAdapter;
47 | private BluetoothGatt mBluetoothGatt;
48 | private BluetoothGattCharacteristic gattCharacteristic;
49 |
50 | private BleGattCallback mGattCallback;
51 | private OnWriteCallback writeCallback;
52 |
53 | private Handler mHandler = new Handler(Looper.getMainLooper());
54 |
55 | //发起连接是否有响应
56 | private boolean isConnectResponse = false;
57 | //获取到所有服务的集合
58 | private HashMap
12 |
17 |
22 |
27 |
54 |
56 |