├── app
├── .gitignore
├── libs
│ └── serialport-release.aar
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ └── activity_main.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── apacherio
│ │ │ └── jondy
│ │ │ └── annotationdemo
│ │ │ ├── BanknotesProtocol.java
│ │ │ ├── BaseProtocol.java
│ │ │ ├── MainActivity.java
│ │ │ └── BanknotesApi.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── apacherio
│ │ │ └── jondy
│ │ │ └── annotationdemo
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── apacherio
│ │ └── jondy
│ │ └── annotationdemo
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── bind-api
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── ljw
│ │ │ └── bind_api
│ │ │ ├── LJWProtocol.java
│ │ │ ├── ProtocolBean.java
│ │ │ └── RioBinder.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── apacherio
│ │ │ └── jondy
│ │ │ └── bind_api
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── apacherio
│ │ └── jondy
│ │ └── bind_api
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── okserialport
├── consumer-rules.pro
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── ljw
│ │ │ └── okserialport
│ │ │ └── serialport
│ │ │ ├── utils
│ │ │ ├── ApiExceptionCode.java
│ │ │ ├── OkSerialPortLog.java
│ │ │ ├── FlowManager.java
│ │ │ ├── IQueue.java
│ │ │ ├── BaseSerialPortException.java
│ │ │ ├── ReadType.java
│ │ │ ├── ServiceType.java
│ │ │ ├── ApiException.java
│ │ │ ├── ReadMessage.java
│ │ │ ├── Priority.java
│ │ │ ├── AbstractBlockingQueue.java
│ │ │ ├── BaseQueue.java
│ │ │ ├── CheckUtil.java
│ │ │ ├── AbstractTaskQueue.java
│ │ │ ├── CmdPack.java
│ │ │ ├── OrderAssembleUtil.java
│ │ │ ├── CRC16Utils.java
│ │ │ ├── CmdTask.java
│ │ │ ├── ResultDataParseUtils.java
│ │ │ └── ByteUtil.java
│ │ │ ├── callback
│ │ │ ├── SendResultCallback.java
│ │ │ ├── DataPackCallback.java
│ │ │ ├── SerialReadCallback.java
│ │ │ ├── AsyncDataCallback.java
│ │ │ ├── BaseDataCallback.java
│ │ │ ├── CommonCallback.java
│ │ │ └── SerialportConnectCallback.java
│ │ │ ├── bean
│ │ │ ├── ProtocolBean.java
│ │ │ ├── DataPack.java
│ │ │ ├── CmdBean.java
│ │ │ ├── BanknotesHeartBeatEntity.java
│ │ │ └── SerialPortParams.java
│ │ │ ├── core
│ │ │ ├── OkSerialPort_ProtocolManager.java
│ │ │ ├── OkSerialport.java
│ │ │ └── SerialPortSingletonMgr.java
│ │ │ └── proxy
│ │ │ ├── SyncServicesProxy.java
│ │ │ ├── SerialReadThread.java
│ │ │ └── AsyncServicesProxy.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── ljw
│ │ │ └── okserialport
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── ljw
│ │ └── okserialport
│ │ └── ExampleInstrumentedTest.java
├── libs
│ └── serialport-release.aar
├── proguard-rules.pro
└── build.gradle
├── bind-annotation
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── com
│ └── ljw
│ └── protocol
│ └── Protocol.java
├── bind-compiler
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── com
│ └── ljw
│ └── protocolcompiler
│ └── ProtocolProcessor.java
├── serialport-release.aar
├── settings.gradle
├── .idea
├── caches
│ ├── gradle_models.ser
│ └── build_file_checksums.ser
├── vcs.xml
├── misc.xml
├── runConfigurations.xml
├── modules.xml
├── gradle.xml
├── inspectionProfiles
│ └── Project_Default.xml
└── codeStyles
│ └── Project.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── gradlew
└── README.md
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/bind-api/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/okserialport/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bind-annotation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/bind-compiler/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/okserialport/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/serialport-release.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/serialport-release.aar
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':bind-annotation', ':bind-compiler', ':bind-api', ':okserialport'
2 |
--------------------------------------------------------------------------------
/.idea/caches/gradle_models.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/.idea/caches/gradle_models.ser
--------------------------------------------------------------------------------
/app/libs/serialport-release.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/libs/serialport-release.aar
--------------------------------------------------------------------------------
/bind-api/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | bind-api
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/okserialport/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OkSerialPort
3 |
4 |
--------------------------------------------------------------------------------
/okserialport/libs/serialport-release.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/okserialport/libs/serialport-release.aar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/okserialport/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/bind-api/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jarvie-cn/OkSerialPort/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AnnotationDemo
3 | 点击测试注解
4 |
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/bind-api/src/main/java/com/ljw/bind_api/LJWProtocol.java:
--------------------------------------------------------------------------------
1 | package com.ljw.bind_api;
2 |
3 | /**
4 | * Created by Administrator on 2018/2/11 0011.
5 | */
6 |
7 | public interface LJWProtocol {
8 | public void bind(T t);
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Feb 11 21:01:33 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/ApiExceptionCode.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | public interface ApiExceptionCode {
4 | String SERIAL_PORT_ERROR = "serial_port_error";
5 | String SERIAL_PORT_READ_OUT_TIME_ERROR = "read_out_time_error";
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/bind-annotation/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 | apply plugin: 'com.github.dcendents.android-maven' // 增加
3 | group='com.github.Jarvie-cn'
4 | dependencies {
5 | implementation fileTree(dir: 'libs', include: ['*.jar'])
6 | }
7 |
8 | sourceCompatibility = "1.7"
9 | targetCompatibility = "1.7"
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/callback/SendResultCallback.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.callback;
2 |
3 |
4 | import com.ljw.okserialport.serialport.bean.DataPack;
5 |
6 | /**
7 | * @author : LJW
8 | * @date : 2019/11/23
9 | * @desc :
10 | */
11 | public interface SendResultCallback extends CommonCallback{
12 | }
13 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/callback/DataPackCallback.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.callback;
2 |
3 |
4 | import com.ljw.okserialport.serialport.bean.DataPack;
5 |
6 | /**
7 | * @author : LJW
8 | * @date : 2019/11/22
9 | * @desc :
10 | */
11 | public interface DataPackCallback {
12 | void setDataPack(DataPack dataPack);
13 | }
14 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/callback/SerialReadCallback.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.callback;
2 |
3 |
4 | import com.ljw.okserialport.serialport.utils.ReadMessage;
5 |
6 | /**
7 | * @author : LJW
8 | * @date : 2019/11/22
9 | * @desc :
10 | */
11 | public interface SerialReadCallback {
12 | void onReadMessage(ReadMessage readMessage);
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/callback/AsyncDataCallback.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.callback;
2 |
3 |
4 | import com.ljw.okserialport.serialport.bean.DataPack;
5 |
6 | /**
7 | * @author : LJW
8 | * @date : 2019/11/22
9 | * @desc :
10 | */
11 | public interface AsyncDataCallback extends BaseDataCallback {
12 |
13 |
14 | /**
15 | * 主动收到回调(比如心跳包回调)
16 | */
17 | void onActivelyReceivedCommand(DataPack dataPack);
18 | }
19 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/callback/BaseDataCallback.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.callback;
2 |
3 | /**
4 | * @author : LJW
5 | * @date : 2019/11/22
6 | * @desc :
7 | */
8 | public interface BaseDataCallback {
9 | /**
10 | * 校验数据包
11 | *
12 | * @param received 接收数据
13 | * @param size 数据大小
14 | * @return 返回整理好的数据包
15 | */
16 | boolean checkData(byte[] received, int size, DataPackCallback dataPackCallback);
17 | }
18 |
--------------------------------------------------------------------------------
/bind-compiler/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 | apply plugin: 'com.github.dcendents.android-maven' // 增加
3 | group='com.github.Jarvie-cn'
4 | dependencies {
5 | implementation fileTree(include: ['*.jar'], dir: 'libs')
6 | implementation project(':bind-annotation')
7 | implementation 'com.google.auto.service:auto-service:1.0-rc2'
8 |
9 | }
10 | tasks.withType(JavaCompile) {
11 | options.encoding = "UTF-8"
12 | }
13 |
14 | sourceCompatibility = "1.7"
15 | targetCompatibility = "1.7"
16 |
--------------------------------------------------------------------------------
/okserialport/src/test/java/com/ljw/okserialport/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/callback/CommonCallback.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.callback;
2 |
3 |
4 | import com.ljw.okserialport.serialport.utils.BaseSerialPortException;
5 | import com.ljw.okserialport.serialport.utils.CmdPack;
6 |
7 | /**
8 | * 接口回调
9 | *
10 | * @param
11 | */
12 | public interface CommonCallback {
13 | void onStart(CmdPack cmdPack);
14 |
15 | void onSuccess(T t);
16 |
17 | void onFailed(BaseSerialPortException spException);
18 | }
19 |
--------------------------------------------------------------------------------
/bind-api/src/test/java/com/apacherio/jondy/bind_api/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.apacherio.jondy.bind_api;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/test/java/com/apacherio/jondy/annotationdemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.apacherio.jondy.annotationdemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/OkSerialPortLog.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * @author : LJW
7 | * @date : 2019/12/29
8 | * @desc :
9 | */
10 | public class OkSerialPortLog {
11 |
12 | public static boolean isDebug = false;
13 |
14 | public void setDebug(boolean debug) {
15 | isDebug = debug;
16 | }
17 |
18 |
19 | public static void e(String text){
20 | if (isDebug) {
21 | Log.e("OkSerialport",text);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/callback/SerialportConnectCallback.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.callback;
2 |
3 |
4 | import com.ljw.okserialport.serialport.bean.DataPack;
5 | import com.ljw.okserialport.serialport.utils.ApiException;
6 |
7 | /**
8 | * @author : LJW
9 | * @date : 2019/11/22
10 | * @desc :连接成功回调
11 | */
12 | public interface SerialportConnectCallback {
13 | void onError(ApiException apiException);
14 |
15 | void onOpenSerialPortSuccess();
16 |
17 | /**心跳上传回调*/
18 | void onHeatDataCallback(DataPack dataPack);
19 | }
20 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/FlowManager.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | public class FlowManager {
4 | private int flowWater = 0;
5 |
6 | private static FlowManager flowManager = new FlowManager();
7 |
8 | public static FlowManager get() {
9 | return flowManager;
10 | }
11 |
12 | public synchronized int getFlowWater() {
13 | if (flowWater >= 0xff) {
14 | flowWater = 0;
15 | } else {
16 | flowWater++;
17 | }
18 | return flowWater;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/bind-api/src/main/java/com/ljw/bind_api/ProtocolBean.java:
--------------------------------------------------------------------------------
1 | package com.ljw.bind_api;
2 |
3 | /**
4 | * @author : LJW
5 | * @date : 2019/12/27
6 | * @desc :
7 | */
8 | public class ProtocolBean {
9 | /**
10 | * 位置
11 | * */
12 | public int index;
13 | /**
14 | * 字节长度
15 | * */
16 | public int length;
17 |
18 | /**
19 | * 字节长度
20 | * */
21 | public byte value;
22 |
23 | public ProtocolBean(int index, int length, byte value) {
24 | this.index = index;
25 | this.length = length;
26 | this.value = value;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/IQueue.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | /**
4 | * @author : LJW
5 | * @date : 2019/11/22
6 | * @desc :
7 | */
8 | public interface IQueue extends Comparable {
9 | /**
10 | * 开始工作
11 | */
12 | void runTask();
13 |
14 | /**
15 | * 设置等级
16 | */
17 | void setPriority(@Priority int priority);
18 |
19 | int getPriority();
20 |
21 | /**
22 | * 一个序列标记
23 | */
24 | void setSequence(int sequence);
25 |
26 | /**
27 | * 获取序列标记
28 | */
29 | int getSequence();
30 |
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/bean/ProtocolBean.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.bean;
2 |
3 | /**
4 | * @author : LJW
5 | * @date : 2019/12/27
6 | * @desc :
7 | */
8 | public class ProtocolBean {
9 | /**
10 | * 位置
11 | * */
12 | public int index;
13 | /**
14 | * 字节长度
15 | * */
16 | public int length;
17 |
18 | /**
19 | * 字节长度
20 | * */
21 | public byte value;
22 |
23 | public ProtocolBean(int index, int length, byte value) {
24 | this.index = index;
25 | this.length = length;
26 | this.value = value;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/BaseSerialPortException.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | public class BaseSerialPortException extends ApiException {
4 | /**
5 | * 目标地址
6 | */
7 | private int address;
8 |
9 | public BaseSerialPortException(String code, String message, int address) {
10 | super(code, message);
11 | this.address = address;
12 | }
13 |
14 | public BaseSerialPortException(String code, Throwable message, int address) {
15 | super(code, message);
16 | this.address = address;
17 | }
18 |
19 | public int getAddress() {
20 | return address;
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/ReadType.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 |
4 | import android.support.annotation.IntDef;
5 |
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 |
9 | import static com.ljw.okserialport.serialport.utils.ReadType.CheckSendData;
10 | import static com.ljw.okserialport.serialport.utils.ReadType.ReadDataSuccess;
11 |
12 |
13 | @IntDef({CheckSendData, ReadDataSuccess})
14 | @Retention(RetentionPolicy.SOURCE)
15 | public @interface ReadType {
16 | /**
17 | * 检测发送数据包的回调
18 | */
19 | int CheckSendData = 0;
20 | /**
21 | * 读取数据成功
22 | */
23 | int ReadDataSuccess = 1;
24 |
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/bind-api/src/main/java/com/ljw/bind_api/RioBinder.java:
--------------------------------------------------------------------------------
1 | package com.ljw.bind_api;
2 |
3 | import android.app.Activity;
4 |
5 | /**
6 | * Created by Administrator on 2018/2/11 0011.
7 | */
8 |
9 | public class RioBinder {
10 | private static final String SUFFIX ="$ViewBinder";
11 | public static void bind(Activity target){
12 | Class> clazz = target.getClass();
13 | String className =clazz.getName()+SUFFIX;
14 | try {
15 | Class> binderClass = Class.forName("com.ljw.okserialport.LJWProtocolImp");
16 | // ViewBinder rioBind = (ViewBinder) binderClass.newInstance();
17 | // rioBind.bind(target);
18 | } catch (ClassNotFoundException e) {
19 | e.printStackTrace();
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1024m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/ServiceType.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 |
4 | import android.support.annotation.IntDef;
5 |
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 |
9 | import static com.ljw.okserialport.serialport.utils.ServiceType.AsyncServices;
10 | import static com.ljw.okserialport.serialport.utils.ServiceType.SyncServices;
11 |
12 |
13 | /**
14 | * @author : LJW
15 | * @date : 2019/11/22
16 | * @desc :
17 | */
18 | @IntDef({SyncServices, AsyncServices})
19 | @Retention(RetentionPolicy.SOURCE)
20 | public @interface ServiceType {
21 | /**
22 | * 同步服务,适用于485
23 | */
24 | int SyncServices = 0;
25 | /**
26 | * 异步服务适用于485和232
27 | */
28 | int AsyncServices = 1;
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/bind-api/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/okserialport/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/ApiException.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | public class ApiException extends RuntimeException {
4 | /**
5 | * 用String,若是int转下就是
6 | */
7 | private final String code;
8 |
9 | public ApiException(String code, String message) {
10 | super(message);
11 | this.code = code;
12 | }
13 |
14 | public ApiException(String code, Throwable message) {
15 | super(message);
16 | this.code = code;
17 | }
18 |
19 | /**
20 | * 异常码
21 | */
22 | public String getCode() {
23 | return code;
24 | }
25 |
26 | @Override
27 | public String toString() {
28 | return "ApiException{" +
29 | "code='" + code + '\'' + ",message='" + getMessage() + '\'' +
30 | '}';
31 | }
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/okserialport/src/androidTest/java/com/ljw/okserialport/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
23 |
24 | assertEquals("com.ljw.okserialport.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/bind-api/src/androidTest/java/com/apacherio/jondy/bind_api/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.apacherio.jondy.bind_api;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.apacherio.jondy.bind_api.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/apacherio/jondy/annotationdemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.apacherio.jondy.annotationdemo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.apacherio.jondy.annotationdemo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/bind-api/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 |
6 |
7 |
8 | defaultConfig {
9 | minSdkVersion 15
10 | targetSdkVersion 26
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(include: ['*.jar'], dir: 'libs')
29 | implementation 'com.android.support:appcompat-v7:26.1.0'
30 | testImplementation 'junit:junit:4.12'
31 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
32 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
33 | implementation project(':bind-annotation')
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/apacherio/jondy/annotationdemo/BanknotesProtocol.java:
--------------------------------------------------------------------------------
1 | package com.apacherio.jondy.annotationdemo;
2 |
3 |
4 | /**
5 | * @author : LJW
6 | * @date : 2019/11/22
7 | * @desc :纸币器 232协议
8 | */
9 | public class BanknotesProtocol extends BaseProtocol {
10 |
11 | /**
12 | * 心跳命令-纸币器状态主动上报
13 | */
14 | public static byte HEART_BEAT_CMD = (byte) 0x33;
15 | /**
16 | * 2.获取纸币器设备参数
17 | */
18 | public static byte GET_BANKNOTES_PARAM = (byte) 0x31;
19 | /**
20 | * 3.控制纸币器工作模式
21 | */
22 | public static byte CONTROL_WAY_SHIPMENT_CMD = (byte) 0x34;
23 | /**
24 | * .硬币器状态主动上报
25 | */
26 | public static byte COIN_HEART_BEAT_CMD = (byte) 0x0B;
27 | /**
28 | * 2.获取硬币器设备参数09H
29 | */
30 | public static byte GET_COIN_PARAM = (byte) 0x09;
31 | /**
32 | * 3.控制硬币器工作模式0CH
33 | */
34 | public static byte CONTROL_COIN_WORK_MODE = (byte) 0x0C;
35 | /**
36 | * 4.找零器动作0FH
37 | */
38 | public static byte CHANGE_ACTION = (byte) 0x0F;
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/ReadMessage.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 |
4 | import com.ljw.okserialport.serialport.bean.DataPack;
5 |
6 | /**
7 | * 收到的日志
8 | */
9 |
10 | public class ReadMessage {
11 |
12 | private String message;
13 | private int readType = -1;
14 | private DataPack dataPack;
15 |
16 | public ReadMessage(@ReadType int readType, String message, DataPack dataPack) {
17 | this.readType = readType;
18 | this.message = message;
19 | this.dataPack = dataPack;
20 | }
21 |
22 | public String getMessage() {
23 | return message;
24 | }
25 |
26 |
27 | public int getReadType() {
28 | return readType;
29 | }
30 |
31 | public void setReadType(@ReadType int readType) {
32 | this.readType = readType;
33 | }
34 |
35 | public DataPack getDataPack() {
36 | return dataPack;
37 | }
38 |
39 | public void setDataPack(DataPack dataPack) {
40 | this.dataPack = dataPack;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/Priority.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 |
4 | import android.support.annotation.IntDef;
5 |
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 |
9 | import static com.ljw.okserialport.serialport.utils.Priority.DEFAULT;
10 | import static com.ljw.okserialport.serialport.utils.Priority.HIGH;
11 | import static com.ljw.okserialport.serialport.utils.Priority.IMMEDTATELY;
12 | import static com.ljw.okserialport.serialport.utils.Priority.LOW;
13 |
14 |
15 | /**
16 | * @author : fangbingran
17 | * @aescription : 等级
18 | * @date : 2019/06/05 19:34
19 | */
20 | @IntDef({LOW, DEFAULT, HIGH, IMMEDTATELY})
21 | @Retention(RetentionPolicy.SOURCE)
22 | public @interface Priority {
23 | /**
24 | * 最低等级
25 | */
26 | int LOW = 0;
27 | /**
28 | * 默认等级
29 | */
30 | int DEFAULT = 1;
31 | /**
32 | * 高等级
33 | */
34 | int HIGH = 2;
35 | /**
36 | * 立即执行
37 | */
38 | int IMMEDTATELY = 3;
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
22 |
23 |
30 |
31 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/AbstractBlockingQueue.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | import java.util.concurrent.BlockingQueue;
4 |
5 |
6 | /**
7 | * @author : LJW
8 | * @date : 2019/11/22
9 | * @desc :
10 | */
11 | public class AbstractBlockingQueue extends Thread {
12 | private BlockingQueue mBlockingQueue;
13 | private boolean isRunning = true;
14 |
15 | public AbstractBlockingQueue(BlockingQueue blockingDeque) {
16 | this.mBlockingQueue = blockingDeque;
17 | }
18 |
19 | public void quit() {
20 | isRunning = false;
21 | interrupt();
22 | }
23 |
24 | @Override
25 | public void run() {
26 |
27 | while (isRunning) {
28 | IQueue iQueue;
29 | try {
30 | // 叫下一个进来,没有就等着。
31 | iQueue = mBlockingQueue.take();
32 | } catch (InterruptedException e) {
33 | if (!isRunning) {
34 | // 发生意外了,是下班状态的话就把服务关闭。
35 | interrupt();
36 | break; // 如果执行到break,后面的代码就无效了。
37 | }
38 | // 发生意外了,不是下班状态,那么Task服务继续等待。
39 | continue;
40 | }
41 |
42 | // 开始工作。
43 | iQueue.runTask();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/okserialport/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven' // 增加
3 | group='com.github.Jarvie-cn'
4 | android {
5 | compileSdkVersion 26
6 | // buildToolsVersion "29.0.2"
7 |
8 |
9 | defaultConfig {
10 | minSdkVersion 15
11 | targetSdkVersion 26
12 | versionCode 1
13 | versionName "1.0"
14 |
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | // consumerProguardFiles 'consumer-rules.pro'
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 |
26 | }
27 |
28 | repositories {
29 | flatDir { dirs 'libs' }
30 | maven { url 'https://jitpack.io' }
31 | }
32 |
33 | dependencies {
34 | implementation fileTree(dir: 'libs', include: ['*.jar'])
35 |
36 | //串口
37 | implementation(name: 'serialport-release', ext: 'aar')
38 |
39 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
40 | implementation 'io.reactivex.rxjava2:rxjava:2.1.14'
41 | implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
42 | //
43 | // implementation project(':bind-api')
44 | // implementation project(':bind-annotation')
45 | // annotationProcessor project(':bind-compiler')
46 | }
47 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/bean/DataPack.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.bean;
2 |
3 |
4 | import com.ljw.okserialport.serialport.utils.ByteUtil;
5 |
6 | /**
7 | * @author : LJW
8 | * @date : 2019/11/22
9 | * @desc :命令包
10 | */
11 | public class DataPack {
12 | private byte[] allPackData;
13 | private byte[] data;
14 | private byte[] command;
15 |
16 | @Override
17 | public String toString() {
18 | return "DataPack{" +
19 | "全部命令=" + ByteUtil.bytes2HexStr(allPackData) +
20 | ", 数据集=" + ByteUtil.bytes2HexStr(data) +
21 | ", 收到的命令码=" + ByteUtil.bytes2HexStr(command) +
22 | '}';
23 | }
24 |
25 | public DataPack(byte[] allPackData, byte[] data, byte[] command) {
26 | this.allPackData = allPackData;
27 | this.data = data;
28 | this.command = command;
29 | }
30 |
31 | public byte[] getAllPackData() {
32 | return allPackData;
33 | }
34 |
35 | public void setAllPackData(byte[] allPackData) {
36 | this.allPackData = allPackData;
37 | }
38 |
39 | public byte[] getData() {
40 | return data;
41 | }
42 |
43 | public void setData(byte[] data) {
44 | this.data = data;
45 | }
46 |
47 | public byte[] getCommand() {
48 | return command;
49 | }
50 |
51 | public void setCommand(byte[] command) {
52 | this.command = command;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/BaseQueue.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | /**
4 | * @author : LJW
5 | * @date : 2019/11/22
6 | * @desc :
7 | */
8 | public abstract class BaseQueue implements IQueue {
9 | private int priority = Priority.DEFAULT;
10 | private int sequence;
11 |
12 | @Override
13 | public void setPriority(@Priority int priority) {
14 | this.priority = priority;
15 | }
16 |
17 | @Override
18 | public int getPriority() {
19 | return priority;
20 | }
21 |
22 |
23 | @Override
24 | public void setSequence(int sequence) {
25 | this.sequence = sequence;
26 | }
27 |
28 | @Override
29 | public int getSequence() {
30 | return sequence;
31 | }
32 |
33 |
34 | @Override
35 | public String toString() {
36 | return "BaseQueue{" +
37 | "priority=" + priority +
38 | ", sequence=" + sequence +
39 | '}';
40 | }
41 |
42 | /**
43 | *
Description: compareTo(E)中传进来的E是另一个Task,如果当前Task比另一个Task更靠前就返回负数,如果比另一个Task靠后,那就返回正数,如果优先级相等,那就返回0。
44 | *
Author: fangbingran
45 | *
Date: 2018/5/9 23:29
46 | */
47 | @Override
48 | public int compareTo(IQueue another) {
49 | final int me = this.getPriority();
50 | final int it = another.getPriority();
51 | return me == it ? this.getSequence() - another.getSequence() :
52 | it - me;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/bean/CmdBean.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.bean;
2 |
3 |
4 | import com.ljw.okserialport.serialport.callback.SendResultCallback;
5 | import com.ljw.okserialport.serialport.utils.CmdPack;
6 |
7 | /**
8 | * @author : LJW
9 | * @date : 2019/11/22
10 | * @desc :
11 | */
12 | public class CmdBean {
13 |
14 | private CmdPack cmdPack;
15 | private String key;
16 | private SendResultCallback sendResultCallback;
17 | private long time;
18 |
19 | public CmdBean(CmdPack cmdPack, SendResultCallback sendResultCallback, String key, long time) {
20 | this.cmdPack = cmdPack;
21 | this.time = time;
22 | this.sendResultCallback = sendResultCallback;
23 | this.key = key;
24 | }
25 |
26 | public SendResultCallback getSendResultCallback() {
27 | return sendResultCallback;
28 | }
29 |
30 | public void setSendResultCallback(SendResultCallback sendResultCallback) {
31 | this.sendResultCallback = sendResultCallback;
32 | }
33 |
34 | public CmdPack getCmdPack() {
35 | return cmdPack;
36 | }
37 |
38 | public void setCmdPack(CmdPack cmdPack) {
39 | this.cmdPack = cmdPack;
40 | }
41 |
42 |
43 | public long getTime() {
44 | return time;
45 | }
46 |
47 | public void setTime(long time) {
48 | this.time = time;
49 | }
50 |
51 | public String getKey() {
52 | return key;
53 | }
54 |
55 | public void setKey(String key) {
56 | this.key = key;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/CheckUtil.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | /**
4 | * @author : LJW
5 | * @date : 2019/11/22
6 | * @desc :
7 | */
8 | public class CheckUtil {
9 | /**
10 | * @deprecated
11 | * 异或检验
12 | *(这个方法好像有点问题,使用下面的@{@link #getXOR(String)})
13 | * @param bytes
14 | * @return
15 | */
16 | public static String getXOR(byte[] bytes) {
17 | //byte[] bytes = stringToHexByte(source); //把普通字符串转换成十六进制字符串
18 | byte[] mByte = new byte[1];
19 |
20 | for (int i = 0; i < bytes.length - 1; i++) {
21 | if (i == 0) {
22 | mByte[0] = (byte) (bytes[i] ^ bytes[i + 1]);
23 | } else {
24 | mByte[0] = (byte) (mByte[0] ^ bytes[i + 1]);
25 | }
26 | }
27 |
28 | return ByteUtil.bytes2HexStr(mByte);
29 | }
30 |
31 |
32 | /**
33 | * 获取异或和,支持多字节
34 | *
35 | * @param hex
36 | * @return
37 | */
38 | public static String getXOR(String hex) {
39 | if (hex.length() == 0) {
40 | return null;
41 | }
42 | if (hex.length() % 2 != 0) {
43 | hex = "0" + hex;
44 | }
45 | int or = 0;
46 | for (int i = 0, size = hex.length(); i < size; i = i + 2) {
47 | String subHex = hex.substring(i, i + 2);
48 | or = or ^ Integer.parseInt(subHex, 16);
49 | }
50 | String xor = Integer.toHexString(or) + "";
51 | if (xor.length() == 1) {
52 | xor = "0" + xor;
53 | }
54 | return xor;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | defaultConfig {
6 | applicationId "com.apacherio.jondy.annotationdemo"
7 | minSdkVersion 15
8 | targetSdkVersion 26
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | //解决多包依赖显示使用注解
13 | javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | tasks.withType(JavaCompile) {
22 | options.encoding = "UTF-8"
23 | }
24 | }
25 | repositories {
26 | flatDir { dirs 'libs' }
27 | maven { url 'https://jitpack.io' }
28 | }
29 |
30 |
31 | dependencies {
32 | implementation fileTree(include: ['*.jar'], dir: 'libs')
33 | implementation 'com.android.support:appcompat-v7:26.1.0'
34 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
35 | testImplementation 'junit:junit:4.12'
36 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
37 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
38 |
39 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
40 | implementation 'io.reactivex.rxjava2:rxjava:2.1.14'
41 | implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
42 |
43 | //串口
44 | implementation(name: 'serialport-release', ext: 'aar')
45 | implementation project(':bind-annotation')
46 | annotationProcessor project(':bind-compiler')
47 | implementation project(':okserialport')
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/core/OkSerialPort_ProtocolManager.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.core;
2 |
3 | import com.ljw.okserialport.serialport.bean.ProtocolBean;
4 |
5 | import java.util.ArrayList;
6 | import java.util.HashMap;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | /**
11 | * @author : LJW
12 | * @date : 2019/12/30
13 | * @desc :
14 | */
15 | public class OkSerialPort_ProtocolManager {
16 |
17 | public static Map mProtocolMap = new HashMap<>();
18 | public static List mHeartCommands = new ArrayList<>();
19 |
20 | public static int DATALENFIRST ;
21 | public static int COMMANDINDEX ;
22 | public static int DATALENINDEX ;
23 | public static int DATAFIRST ;
24 | public static int COMMANDFIRST ;
25 | public static int RUNNINGNUMBERFIRST ;
26 | public static int FRAMEHEADERCOUNT ;
27 | public static int CHECKCODERULE ;
28 | public static int MINDALALEN ;
29 |
30 | private volatile static OkSerialPort_ProtocolManager instance;
31 |
32 | public static OkSerialPort_ProtocolManager getInstance() {
33 | if (instance == null) {
34 | synchronized (OkSerialPort_ProtocolManager.class) {
35 | if (instance == null) {
36 | instance = new OkSerialPort_ProtocolManager();
37 | }
38 | }
39 | }
40 | return instance;
41 | }
42 |
43 | public void bind(int commandindex,int datalenindex,int datalenfirst,int datafirst,int commandfirst,int runningnumberfirst,int frameheadercount,int checkcoderule,int mindalalen,Map map,List list){
44 | COMMANDINDEX = commandindex;
45 | DATALENINDEX = datalenindex;
46 | DATALENFIRST = datalenfirst;
47 | DATAFIRST = datafirst;
48 | COMMANDFIRST = commandfirst;
49 | RUNNINGNUMBERFIRST = runningnumberfirst;
50 | FRAMEHEADERCOUNT = frameheadercount;
51 | CHECKCODERULE = checkcoderule;
52 | MINDALALEN = mindalalen;
53 | mProtocolMap = map;
54 | mHeartCommands = list;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/AbstractTaskQueue.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | import java.util.concurrent.BlockingQueue;
4 | import java.util.concurrent.PriorityBlockingQueue;
5 | import java.util.concurrent.atomic.AtomicInteger;
6 |
7 | /**
8 | * @author : LJW
9 | * @date : 2019/11/22
10 | * @desc :
11 | */
12 | public class AbstractTaskQueue {
13 | /***AtomicInteger类,它的incrementAndGet()方法会每次递增1***/
14 | private AtomicInteger mAtomicInteger = new AtomicInteger();
15 | /**
16 | * 多个BlockingQueue。
17 | */
18 |
19 | private AbstractBlockingQueue[] mAbstractBlockingQueues;
20 |
21 | private BlockingQueue mTaskQueue;
22 |
23 | public AbstractTaskQueue(int size) {
24 | /*
25 | PriorityBlockingQueue所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数的Comparator决定的顺序.
26 |
27 | */
28 | mTaskQueue = new PriorityBlockingQueue<>();
29 | mAbstractBlockingQueues = new AbstractBlockingQueue[size];
30 |
31 | }
32 |
33 |
34 | /**
35 | * 开始工作。
36 | */
37 | public void start() {
38 | stop();
39 | // 把各个BlockingQueue启动,开始工作。
40 | for (int i = 0; i < mAbstractBlockingQueues.length; i++) {
41 | mAbstractBlockingQueues[i] = new AbstractBlockingQueue(mTaskQueue);
42 | mAbstractBlockingQueues[i].start();
43 | }
44 | }
45 |
46 | /**
47 | * 统一各个BlockingQueue退出。
48 | */
49 | public void stop() {
50 | if (mAbstractBlockingQueues != null) {
51 | for (AbstractBlockingQueue taskExecutor : mAbstractBlockingQueues) {
52 | if (taskExecutor != null) {
53 | taskExecutor.quit();
54 | }
55 | }
56 | }
57 | }
58 |
59 | /**
60 | * 添加一个任务。
61 | */
62 | public int add(T iQueue) {
63 | if (!mTaskQueue.contains(iQueue)) {
64 | iQueue.setSequence(mAtomicInteger.incrementAndGet());
65 | mTaskQueue.add(iQueue);
66 | }
67 | // 返回排的队的人数,公开透明,让外面的人看的有多少人在等着办事。
68 | return mTaskQueue.size();
69 | }
70 |
71 | public int size() {
72 | return mTaskQueue.size();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/proxy/SyncServicesProxy.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.proxy;
2 |
3 |
4 | import com.ljw.okserialport.serialport.callback.BaseDataCallback;
5 | import com.ljw.okserialport.serialport.callback.SendResultCallback;
6 | import com.ljw.okserialport.serialport.utils.AbstractTaskQueue;
7 | import com.ljw.okserialport.serialport.utils.CmdPack;
8 | import com.ljw.okserialport.serialport.utils.CmdTask;
9 |
10 | import java.io.BufferedInputStream;
11 | import java.io.IOException;
12 | import java.io.OutputStream;
13 |
14 | /**
15 | * @author : LJW
16 | * @date : 2019/11/22
17 | * @desc :
18 | */
19 | public class SyncServicesProxy {
20 | private AbstractTaskQueue mAbstractTaskQueue;
21 | private boolean isStart = false;
22 | private BaseDataCallback mBaseDataCallback;
23 | private OutputStream mOutputStream;
24 | private BufferedInputStream mBufferedInputStream;
25 |
26 | public SyncServicesProxy(OutputStream outputStream, BufferedInputStream bufferedInputStream, BaseDataCallback baseDataCallback) {
27 | mBaseDataCallback = baseDataCallback;
28 | mOutputStream = outputStream;
29 | mBufferedInputStream = bufferedInputStream;
30 | startTaskQueue();
31 | }
32 |
33 | private void startTaskQueue() {
34 | if (mAbstractTaskQueue == null) {
35 | mAbstractTaskQueue = new AbstractTaskQueue(1);
36 | }
37 | if (!isStart) {
38 | mAbstractTaskQueue.start();
39 | isStart = true;
40 | }
41 | }
42 |
43 | /**
44 | * 停止当前任务,释放线程
45 | */
46 | public void stopTaskQueue() {
47 | if (mAbstractTaskQueue != null && isStart) {
48 | mAbstractTaskQueue.stop();
49 | isStart = false;
50 | }
51 | }
52 |
53 | public void send(CmdPack cmdPack, SendResultCallback sendResultCallback) {
54 | CmdTask cmdTask = new CmdTask(cmdPack.getPriority(), sendResultCallback, cmdPack, mOutputStream, mBufferedInputStream, mBaseDataCallback);
55 | if (mAbstractTaskQueue == null) {
56 | startTaskQueue();
57 | }
58 | //加入等待任务里面
59 | mAbstractTaskQueue.add(cmdTask);
60 | }
61 |
62 | /**
63 | * 关闭
64 | */
65 | public void close() {
66 | if (mOutputStream != null) {
67 | try {
68 | mOutputStream.close();
69 | } catch (IOException e) {
70 | e.printStackTrace();
71 | }
72 | }
73 | if (mBufferedInputStream != null) {
74 | try {
75 | mBufferedInputStream.close();
76 | } catch (IOException e) {
77 | e.printStackTrace();
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/bind-annotation/src/main/java/com/ljw/protocol/Protocol.java:
--------------------------------------------------------------------------------
1 | package com.ljw.protocol;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * Created by Administrator on 2018/2/11 0011.
10 | */
11 | @Target(ElementType.FIELD)
12 | @Retention(RetentionPolicy.CLASS)
13 | public @interface Protocol {
14 | /**
15 | * 协议字段角标
16 | */
17 | int index() default -1;
18 |
19 | /**
20 | * 协议字段的字节长度长度,如果该字段的字节长度是不确定的那么就不需要赋值,比如:数据域
21 | */
22 | int length() default Integer.MAX_VALUE;
23 |
24 | /**
25 | * 值为byte类型
26 | * 协议字段的值,如果值是相对固定的就必须要赋值,如果不固定就不需要赋值,
27 | * 比如:命令码,流水,数据域数据等,
28 | * 这要里注意一下:
29 | * 如果你的协议里面有数据长度这个字段,那么也必须要赋值;
30 | * 如果你的协议数据长度只是计算数据域那么value = 0,
31 | * 数据长度包含其他比如命令码等,那么value = 命令码等字节长度;数据域的长度会动态计算的
32 | */
33 | byte value() default -1;
34 |
35 | /**
36 | * 命令码长度
37 | */
38 | int commandLen() default -1;
39 |
40 | /**
41 | * 目标地址长度
42 | */
43 | int targetAddressLen() default -1;
44 |
45 | /**
46 | * 原地址长度
47 | */
48 | int rawAddressLen() default -1;
49 |
50 | /**
51 | * 协议版本长度
52 | */
53 | int protocolLen() default -1;
54 |
55 | /**
56 | * 异或字节长度
57 | */
58 | int oxrLen() default -1;
59 |
60 | /**
61 | * 数据长度
62 | */
63 | int dateLen() default -1;
64 |
65 | /**
66 | * 通信协议最短字节不包含数据域(
67 | */
68 | int minPackLen() default -1;
69 |
70 | /**
71 | * 帧头1
72 | */
73 | byte frameHeader() default -1;
74 |
75 | /**
76 | * 帧头2
77 | */
78 | byte frameHeader2() default -1;
79 |
80 | /**
81 | * 数据长度字节开始位置
82 | */
83 | int dataLenFirst() default Integer.MAX_VALUE;
84 |
85 |
86 | /**
87 | * 数据字节默认起始位置
88 | */
89 | int dataFirst() default Integer.MAX_VALUE;
90 |
91 | /**
92 | * 命令码字节开始位置
93 | */
94 | int commandFirst() default Integer.MAX_VALUE;
95 |
96 | /**
97 | * 流水号字节开始位置
98 | */
99 | int runningNumberFirst() default Integer.MAX_VALUE;
100 | /**
101 | * 数据长度配置的角标位置
102 | */
103 | int dataLenIndex() default Integer.MAX_VALUE;
104 |
105 | /**
106 | * 命令码配置的角标位置
107 | */
108 | int commandIndex() default Integer.MAX_VALUE;
109 | /**
110 | * 安卓地址
111 | */
112 | byte androidAdress() default -1;
113 |
114 | /**
115 | * 主控板地址
116 | */
117 | byte hardwareAdress() default -1;
118 |
119 | /**
120 | * 版本协议
121 | */
122 | byte dealVersions() default -1;
123 |
124 | /**
125 | * 最小数据长度
126 | */
127 | int minDalaLen() default -1;
128 |
129 | /**
130 | * 帧头字节数
131 | */
132 | int frameHeaderCount() default -1;
133 |
134 | /**
135 | * 校验规则 0表示异或校验 1表示CRC16校验
136 | */
137 | int checkCodeRule() default -1;
138 |
139 | /**
140 | * 心跳命令
141 | */
142 | byte heartbeatCommand() default -1;
143 | }
144 |
--------------------------------------------------------------------------------
/app/src/main/java/com/apacherio/jondy/annotationdemo/BaseProtocol.java:
--------------------------------------------------------------------------------
1 | package com.apacherio.jondy.annotationdemo;
2 |
3 |
4 | import com.ljw.protocol.Protocol;
5 |
6 | /**
7 | * @author : LJW
8 | * @date : 2019/11/22
9 | * @desc :
10 | */
11 | public class BaseProtocol {
12 |
13 |
14 | /**
15 | * 帧头
16 | */
17 | @Protocol(index = 0, length = 1, value = (byte) 0x3B)
18 | public byte frameHeader ;
19 |
20 | @Protocol(index = 1, length = 1, value = (byte) 0xB3)
21 | public byte frameHeader2 ;
22 |
23 | /**
24 | * 原地址
25 | */
26 | @Protocol(index = 2, length = 1, value = 0)
27 | public int rawAddress;
28 |
29 |
30 | /**
31 | * 目标地址
32 | */
33 | @Protocol(index = 3, length = 1,value = 1)
34 | public int deviceAddress = 1;
35 |
36 | /**
37 | * 数据长度 这里注意,如果你也有这规则字段那么传值和我一样传,我这份协议协的数据长度是包含命令吗+版本协议+数据,
38 | * 等于是 1+1+n 前面两个字节长度是固定的所以传2,如果你是单数据的话那么传0
39 | *
40 | */
41 | @Protocol(index = 4, length = 1,value = 2)
42 | public int dateNumber;
43 |
44 |
45 | /**
46 | * 命令码
47 | */
48 | @Protocol(index = 5, length = 1)
49 | public int command ;
50 |
51 |
52 | /**
53 | * 协议版本
54 | */
55 | @Protocol(index = 6,length = 1, value = (byte) 0x10)
56 | public int dealVersions;
57 |
58 | /**
59 | * 数据
60 | */
61 | @Protocol(index = 7)
62 | public int data ;
63 |
64 | /**
65 | * 异或字节长度
66 | */
67 | @Protocol(index = 8, length = 1)
68 | public int OXR ;
69 |
70 |
71 | /** ---- end 按照文档协议配置结束 这部分根据自身协议自由配置 -----*/
72 |
73 | /** ----- 分割线 --------------*/
74 |
75 |
76 | /** ----- 下面这块注意!!,是必须要配置的 --------------*/
77 |
78 |
79 | /**
80 | * 读取数据长度这个字段字节开始位置角标从0开始,示例文档是在第5位,如果你的协议没有数据长度这个字段那么传-1
81 | */
82 | @Protocol(dataLenFirst = 4)
83 | public int dataLenStart;
84 |
85 | /**
86 | * 数据长度字段在你配置协议对应的角标位置 ,如果你的协议没有数据长度这个字段那么传-1
87 | */
88 | @Protocol(dataLenIndex = 4)
89 | public int dataLenIndex;
90 |
91 | /**
92 | * 读取数据这个字段开始字节位置,示例文档是第8位,如果你的协议没有数据这个字段那么传-1
93 | */
94 | @Protocol(dataFirst = 7)
95 | public int dataFirst ;
96 |
97 | /**
98 | * 读取命令码字节开始开始,例文档是第6位,如果你的协议没有这个字段那么传-1
99 | */
100 | @Protocol(commandFirst = 5)
101 | public int commandFirst = 5;
102 |
103 | /**
104 | * 命令码字段在你配置协议对应的角标位置,如果你的协议没有这个字段那么传-1
105 | */
106 | @Protocol(commandIndex = 5)
107 | public int commandIndex ;
108 |
109 | /**
110 | * 流水号起始位置 如果你的协议没有流水号这个字段那么传-1
111 | */
112 | @Protocol(runningNumberFirst = -1)
113 | public int runningNumberFirst = 5;
114 |
115 |
116 | /**
117 | * 帧头字节数
118 | */
119 | @Protocol(frameHeaderCount = 2)
120 | public static int frameHeaderCount;
121 | /**
122 | * 校验码规则 0表示异或校验 1表示CRC16校验
123 | */
124 | @Protocol(checkCodeRule = 0)
125 | public static int checkCodeRule;
126 |
127 |
128 | /**
129 | * 通信协议最短字节不包含数据域
130 | *比如示例的:(帧头(2字节) +源地址(1字节)+目标地址(1字节)+数据长度(1字节)+命令码(1字节)+数据(n字节)+异或校验(1字节))
131 | * 帧头 源地址 目标地址 数据长度 命令码 协议版本 数据 异或校验
132 | * 2个字节 1个字节 1个字节 1个字节 1个字节 1个字节 n个字节 1个字节
133 | */
134 | @Protocol(minDalaLen = 8)
135 | public static int minDalaLen;
136 |
137 | // /**
138 | // * 心跳命令
139 | // */
140 | // @Protocol(heartbeatCommand = (byte) 0x33)
141 | // public int heartbeatCommand1;
142 | // /**
143 | // * 心跳命令
144 | // */
145 | // @Protocol(heartbeatCommand = (byte) 0xB3)
146 | // public int heartbeatCommand2;
147 |
148 |
149 |
150 |
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/CmdPack.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 |
4 |
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * @author : LJW
10 | * @date : 2019/11/22
11 | * @desc :
12 | */
13 | public class CmdPack {
14 | private byte[] sendData;
15 | /**
16 | * 校验结果的命令码
17 | */
18 | private List checkCommand;
19 |
20 | /**
21 | * 发送数据超时时间,默认3000ms秒
22 | */
23 | private int sendOutTime = 3000;
24 | /**
25 | * 等待下一条数据超时时间默认300ms
26 | */
27 | private int waitOutTime = 300;
28 | /**
29 | * 任务等级,485才需要设置任务等级
30 | */
31 | private int priority = Priority.DEFAULT;
32 |
33 | private int destinationAddress;
34 |
35 | public CmdPack(int destinationAddress, byte[] sendData, List checkCommand) {
36 | this.sendData = sendData;
37 | this.checkCommand = checkCommand;
38 | this.destinationAddress = destinationAddress;
39 | }
40 |
41 | public CmdPack(int destinationAddress, byte[] sendData, List checkCommand, @Priority int priority) {
42 | this.sendData = sendData;
43 | this.checkCommand = checkCommand;
44 | this.priority = priority;
45 | this.destinationAddress = destinationAddress;
46 | }
47 |
48 | public CmdPack(byte[] sendData, List checkCommand, int sendOutTime, int waitOutTime) {
49 | this.sendData = sendData;
50 | this.checkCommand = checkCommand;
51 | this.sendOutTime = sendOutTime;
52 | this.waitOutTime = waitOutTime;
53 | }
54 |
55 | public CmdPack(byte[] sendData, List checkCommand) {
56 | this.sendData = sendData;
57 | this.checkCommand = checkCommand;
58 | }
59 |
60 | public String getCheckCommands() {
61 | StringBuilder command = new StringBuilder();
62 | if (checkCommand != null && checkCommand.size() > 0) {
63 | for (byte[] bytes : checkCommand) {
64 | command.append(",").append(ByteUtil.bytes2HexStr(bytes));
65 | }
66 | }
67 | return command.toString().replaceFirst(",", "");
68 | }
69 |
70 | public byte[] getSendData() {
71 | return sendData;
72 | }
73 |
74 | public String getStrSendData() {
75 | return ByteUtil.bytes2HexStr(sendData);
76 | }
77 |
78 | public int getIntSendData() {
79 | return ByteUtil.byteToInt(sendData);
80 | }
81 |
82 | public int getSendOutTime() {
83 | return sendOutTime;
84 | }
85 |
86 | public void setSendOutTime(int sendOutTime) {
87 | this.sendOutTime = sendOutTime;
88 | }
89 |
90 | public int getWaitOutTime() {
91 | return waitOutTime;
92 | }
93 |
94 | public void setWaitOutTime(int waitOutTime) {
95 | this.waitOutTime = waitOutTime;
96 | }
97 |
98 | public void setSendData(byte[] sendData) {
99 | this.sendData = sendData;
100 | }
101 |
102 | public List getCheckCommand() {
103 | return checkCommand;
104 | }
105 |
106 | public void setCheckCommand(List checkCommand) {
107 | this.checkCommand = checkCommand;
108 | }
109 |
110 | public int getPriority() {
111 | return priority;
112 | }
113 |
114 | public void setPriority(int priority) {
115 | this.priority = priority;
116 | }
117 |
118 | public int getDestinationAddress() {
119 | return destinationAddress;
120 | }
121 |
122 | public void setDestinationAddress(int destinationAddress) {
123 | this.destinationAddress = destinationAddress;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/OrderAssembleUtil.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | import android.text.TextUtils;
4 |
5 |
6 | import com.ljw.okserialport.serialport.bean.ProtocolBean;
7 | import com.ljw.okserialport.serialport.core.OkSerialPort_ProtocolManager;
8 |
9 | import java.util.Map;
10 |
11 |
12 | /**
13 | * @author : LJW
14 | * @date : 2019/11/22
15 | * @desc :数据拼装
16 | */
17 | public class OrderAssembleUtil {
18 |
19 | /**
20 | * 1个字节8Bit,int占4*8=32位的时候,最大可以赋值为:215
21 | */
22 | public static byte[] allCmd(byte[] cmd, String[] fillDatas, String data) {
23 | Map mProtocolMap;
24 | mProtocolMap = OkSerialPort_ProtocolManager.mProtocolMap;
25 |
26 | StringBuilder builder = new StringBuilder();
27 | int index = 0;
28 | int byteIndex = 0;
29 | for (int i = 0; i < mProtocolMap.keySet().size(); i++) {
30 | if (mProtocolMap.get(i).value == -1) {
31 |
32 | if (i == mProtocolMap.keySet().size() - 1) {
33 | //校验码
34 | if (OkSerialPort_ProtocolManager.CHECKCODERULE == 0) {
35 | builder.append(CheckUtil.getXOR(builder.toString()));
36 | } else {
37 | builder.append(CRC16Utils.getCRC16(builder.toString()));
38 | }
39 | } else if (byteIndex == OkSerialPort_ProtocolManager.COMMANDFIRST) {
40 | //命令码开始标识
41 | String command = ByteUtil.bytes2HexStr(cmd);
42 | builder.append(command);
43 | byteIndex = byteIndex + mProtocolMap.get(i).length;
44 |
45 | } else if (byteIndex == OkSerialPort_ProtocolManager.RUNNINGNUMBERFIRST) {
46 | //流水号
47 | builder.append(ByteUtil.integer2HexStr(FlowManager.get().getFlowWater(), mProtocolMap.get(i).length * 2));
48 | byteIndex = byteIndex + mProtocolMap.get(i).length;
49 |
50 | } else if (byteIndex == OkSerialPort_ProtocolManager.DATAFIRST) {
51 | //数据默认起始位置
52 | builder.append(data);
53 | int dataLength = TextUtils.isEmpty(data) ? 0 : data.length() / 2;
54 | byteIndex = byteIndex + dataLength;
55 | } else {
56 | int dataLength = TextUtils.isEmpty(fillDatas[index]) ? 0 : fillDatas[index].length() / 2;
57 | builder.append(fillDatas[index]);
58 | byteIndex = byteIndex + dataLength;
59 | index++;
60 | }
61 | } else {
62 | if (byteIndex == OkSerialPort_ProtocolManager.DATALENFIRST) {
63 | //数据长度标识
64 | int dataLength = TextUtils.isEmpty(data) ? 0 : data.length() / 2;
65 | String strDataLength = ByteUtil.integer2HexStr(dataLength +
66 | ByteUtil.byteToInt(new byte[]{mProtocolMap.get(i).value}), mProtocolMap.get(i).length * 2);
67 | builder.append(strDataLength);
68 | byteIndex = byteIndex + mProtocolMap.get(i).length;
69 | } else {
70 | builder.append(ByteUtil.integer2HexStr(ByteUtil.byteToInt(new byte[]{mProtocolMap.get(i).value}), mProtocolMap.get(i).length * 2));
71 | byteIndex = byteIndex + mProtocolMap.get(i).length;
72 | }
73 |
74 |
75 | }
76 |
77 |
78 | }
79 | OkSerialPortLog.e("发送:" + builder.toString());
80 | return ByteUtil.hexStr2bytes(builder.toString());
81 | }
82 |
83 |
84 | // public static byte[] allCmd(byte[] cmd, String[] data) {
85 | //
86 | // return allCmd(cmd, data);
87 | // }
88 | }
89 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | xmlns:android
14 |
15 | ^$
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | xmlns:.*
25 |
26 | ^$
27 |
28 |
29 | BY_NAME
30 |
31 |
32 |
33 |
34 |
35 |
36 | .*:id
37 |
38 | http://schemas.android.com/apk/res/android
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | .*:name
48 |
49 | http://schemas.android.com/apk/res/android
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | name
59 |
60 | ^$
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | style
70 |
71 | ^$
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | .*
81 |
82 | ^$
83 |
84 |
85 | BY_NAME
86 |
87 |
88 |
89 |
90 |
91 |
92 | .*
93 |
94 | http://schemas.android.com/apk/res/android
95 |
96 |
97 | ANDROID_ATTRIBUTE_ORDER
98 |
99 |
100 |
101 |
102 |
103 |
104 | .*
105 |
106 | .*
107 |
108 |
109 | BY_NAME
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/bean/BanknotesHeartBeatEntity.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.bean;
2 |
3 |
4 | import com.ljw.okserialport.serialport.utils.ByteUtil;
5 |
6 | /**
7 | * @author : LJW
8 | * @date : 2019/11/22
9 | * @desc :
10 | */
11 | public class BanknotesHeartBeatEntity {
12 | /**
13 | * 心跳数据包
14 | */
15 | private DataPack dataPack;
16 | /**
17 | * 流水号
18 | */
19 | private int pipelineNumber;
20 | /**
21 | * 出货的货道编号,范围1-8
22 | * 当Z1值>=0x80H时,解析如下:
23 | * bit7=1
24 | * bit6,bit5,bit4: 纸币路径
25 | * 000:钱箱
26 | * 001:退币位
27 | * 010:退还顾
28 | * 011:未用
29 | * 100:不接受
30 | * Bit3,bit2,bit1,bit0:纸币币种
31 | * 0000=1美元
32 | * 0001=5美元
33 | * 0010=10美元
34 | * 0011=20美元
35 | * 当Z1值<0x80H时,解析如下:
36 | * 01H (纸币器)电动机失效
37 | * 02H 传感器问题
38 | * 03H 纸币器忙,无法立即响应
39 | * 04H ROM校验和错
40 | * 05H 纸币器入口堵塞
41 | * 06H 正处于复位状态
42 | * 07H 处于 escrow位置的纸币被异常取走,纸
43 | * 币器将返回‘BILL RETURNED’消息
44 | * 08H钱植被打开或者移走
45 | * 09H 纸币器被 VMC或由于其它原因被禁用
46 | * 0AH 无效的退币请求
47 | * 0BH 纸币无法识别,不接受
48 | * 0CH 纸币异常移除
49 | */
50 | private int z1;
51 | private static final int OX80H = 128;
52 |
53 | public int getUs() {
54 | int usDollar = -1;
55 | if (z1 >= 128) {
56 | //10进制转成16进制
57 | String hexStr = ByteUtil.integer2HexStr(z1);
58 | //16进制转成足位的二进制字符串
59 | String binStr = ByteUtil.hexStr2BitArr(hexStr);
60 | //将char[]反转因为bit0在末尾
61 | String binTempStr = new StringBuilder(binStr).reverse().toString();
62 | //string-[0,1,1,1,0]
63 | char[] binCharArr = binTempStr.toCharArray();
64 | String bit654 = "" + binCharArr[4] + binCharArr[5] + binCharArr[6];
65 | if (bit654.equals("000")) {//钱箱
66 | String bit3210 = "" + binCharArr[3] + binCharArr[2] + binCharArr[1] + binCharArr[0];
67 | switch (bit3210) {//钱数
68 | case "0000":
69 | usDollar = 1;
70 | break;
71 | case "0001":
72 | usDollar = 5;
73 | break;
74 | case "0010":
75 | usDollar = 10;
76 | break;
77 | case "0011":
78 | usDollar = 20;
79 | break;
80 | }
81 | }
82 | }
83 | return usDollar;
84 | }
85 |
86 | public int getPipelineNumber() {
87 | return pipelineNumber;
88 | }
89 |
90 | public void setPipelineNumber(int pipelineNumber) {
91 | this.pipelineNumber = pipelineNumber;
92 | }
93 |
94 |
95 | public int getZ1() {
96 | return z1;
97 | }
98 |
99 | public void setZ1(int z1) {
100 | this.z1 = z1;
101 | }
102 |
103 | public DataPack getDataPack() {
104 | return dataPack;
105 | }
106 |
107 | public void setDataPack(DataPack dataPack) {
108 | this.dataPack = dataPack;
109 | if (dataPack != null && dataPack.getData().length > 0) {
110 | byte[] data = dataPack.getData();
111 | pipelineNumber = ByteUtil.byteToInt(
112 | ByteUtil.getBytes(data, 0, 1));
113 | z1 = ByteUtil.byteToInt(
114 | ByteUtil.getBytes(data, 1, 1));
115 |
116 | }
117 | }
118 |
119 |
120 | @Override
121 | public String toString() {
122 | return "BanknotesHeartBeatEntity{" +
123 | "dataPack=" + dataPack +
124 | ", pipelineNumber=" + pipelineNumber +
125 | ", z1=" + z1 +
126 | '}';
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/bean/SerialPortParams.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.bean;
2 |
3 |
4 | import com.ljw.okserialport.serialport.callback.SerialportConnectCallback;
5 | import com.ljw.okserialport.serialport.core.OkSerialPort_ProtocolManager;
6 | import com.ljw.okserialport.serialport.utils.ServiceType;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 |
12 | /**
13 | * @author : LJW
14 | * @date : 2019/11/22
15 | * @desc :
16 | */
17 | public class SerialPortParams {
18 |
19 | private int serviceType = ServiceType.AsyncServices;
20 | private String serviceName = "async-serial_services-thread";
21 | private String deviceAddress = "/dev/ttyS0";
22 | private int baudRate = 115200;
23 | private boolean isOpenHeart;
24 | private boolean isReconnect;
25 | private List heartCommand = new ArrayList<>();
26 |
27 | private SerialportConnectCallback callback;
28 |
29 |
30 | public SerialportConnectCallback getCallback() {
31 | return callback;
32 | }
33 |
34 | public void setCallback(SerialportConnectCallback callback) {
35 | this.callback = callback;
36 | }
37 |
38 | private SerialPortParams() {
39 | }
40 |
41 | public int getServiceType() {
42 | return serviceType;
43 | }
44 |
45 | public boolean isReconnect() {
46 | return isReconnect;
47 | }
48 |
49 | public void setReconnect(boolean reconnect) {
50 | isReconnect = reconnect;
51 | }
52 |
53 | public void setServiceType(int serviceType) {
54 | this.serviceType = serviceType;
55 | }
56 |
57 | public String getDeviceAddress() {
58 | return deviceAddress;
59 | }
60 |
61 | public void setDeviceAddress(String deviceAddress) {
62 | this.deviceAddress = deviceAddress;
63 | }
64 |
65 | public int getBaudRate() {
66 | return baudRate;
67 | }
68 |
69 | public void setBaudRate(int baudRate) {
70 | this.baudRate = baudRate;
71 | }
72 |
73 | public boolean isOpenHeart() {
74 | return isOpenHeart;
75 | }
76 |
77 | public void setOpenHeart(boolean openHeart) {
78 | isOpenHeart = openHeart;
79 | }
80 |
81 | public List getHeartCommand() {
82 | return heartCommand;
83 | }
84 |
85 | public void setHeartCommand(List heartCommand) {
86 | this.heartCommand = heartCommand;
87 | }
88 |
89 | public String getServiceName() {
90 | return serviceName;
91 | }
92 |
93 | public void setServiceName(String serviceName) {
94 | this.serviceName = serviceName;
95 | }
96 |
97 | public static class Builder {
98 | private SerialPortParams serialPortBean;
99 |
100 | public Builder() {
101 | serialPortBean = new SerialPortParams();
102 | }
103 |
104 | public Builder addDeviceAddress(String address) {
105 | serialPortBean.setDeviceAddress(address);
106 | return this;
107 | }
108 |
109 | public Builder addBaudRate(int baudRate) {
110 | serialPortBean.setBaudRate(baudRate);
111 | return this;
112 | }
113 |
114 | public Builder addHeartCommands(List heartCommands) {
115 | serialPortBean.setHeartCommand(heartCommands);
116 | return this;
117 | }
118 |
119 | public Builder callback(SerialportConnectCallback callback) {
120 | serialPortBean.setCallback(callback);
121 | return this;
122 | }
123 |
124 | public Builder isReconnect(boolean isReconnect) {
125 | serialPortBean.setReconnect(isReconnect);
126 | return this;
127 | }
128 |
129 | public SerialPortParams build() {
130 | if (serialPortBean.getHeartCommand() == null || serialPortBean.getHeartCommand().size() == 0) {
131 | serialPortBean.setHeartCommand(OkSerialPort_ProtocolManager.mHeartCommands);
132 | }
133 | if (serialPortBean.getHeartCommand().size() >0) {
134 | serialPortBean.setOpenHeart(true);
135 | }
136 | return serialPortBean;
137 | }
138 | }
139 |
140 | }
141 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/CRC16Utils.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | import java.io.UnsupportedEncodingException;
4 |
5 | public class CRC16Utils {
6 | /**
7 | * 字符串转十六进制字符串
8 | *
9 | * @param str
10 | * @return
11 | */
12 | public static String str2HexStr(String str) {
13 | char[] chars = "0123456789ABCDEF".toCharArray();
14 | StringBuilder sb = new StringBuilder("");
15 | byte[] bs = null;
16 | try {
17 | bs = str.getBytes("gb2312");
18 | } catch (UnsupportedEncodingException e) {
19 | e.printStackTrace();
20 | }
21 | int bit;
22 | for (int i = 0; i < bs.length; i++) {
23 | bit = (bs[i] & 0x0f0) >> 4;
24 | sb.append(chars[bit]);
25 | bit = bs[i] & 0x0f;
26 | sb.append(chars[bit]);
27 | }
28 | return sb.toString();
29 | }
30 |
31 | /**
32 | * 把字符串转换成十六进制字节数组
33 | *
34 | * @param hex
35 | * @return byte[]
36 | */
37 | public static byte[] stringToHexByte(String hex) {
38 | int len = (hex.length() / 2);
39 | byte[] result = new byte[len];
40 | char[] achar = hex.toCharArray();
41 | for (int i = 0; i < len; i++) {
42 | int pos = i * 2;
43 | result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
44 | }
45 | return result;
46 | }
47 |
48 | private static int toByte(char c) {
49 | byte b = (byte) "0123456789ABCDEF".indexOf(c);
50 | return b;
51 | }
52 |
53 | /**
54 | * 十六进制把字符串转换成十六进制字节数组
55 | *
56 | * @param src
57 | * @return
58 | */
59 | public static byte[] HexString2Bytes(String src) {
60 | if (null == src || 0 == src.length()) {
61 | return null;
62 | }
63 | byte[] ret = new byte[src.length() / 2];
64 | byte[] tmp = src.getBytes();
65 | for (int i = 0; i < (tmp.length / 2); i++) {
66 | ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
67 | }
68 | return ret;
69 | }
70 |
71 | public static byte uniteBytes(byte src0, byte src1) {
72 | byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 })).byteValue();
73 | _b0 = (byte) (_b0 << 4);
74 | byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 })).byteValue();
75 | byte ret = (byte) (_b0 ^ _b1);
76 | return ret;
77 | }
78 |
79 | /**
80 | * CRC检验
81 | *
82 | * @param source
83 | * @return
84 | */
85 | public static String getCRC16(String source) {
86 | int crc = 0xA1EC; // 初始值
87 | int polynomial = 0x1021; // 校验公式 0001 0000 0010 0001
88 | byte[] bytes = stringToHexByte(source); //把普通字符串转换成十六进制字符串
89 |
90 | for (byte b : bytes) {
91 | for (int i = 0; i < 8; i++) {
92 | boolean bit = ((b >> (7 - i) & 1) == 1);
93 | boolean c15 = ((crc >> 15 & 1) == 1);
94 | crc <<= 1;
95 | if (c15 ^ bit) crc ^= polynomial;
96 | }
97 | }
98 | crc &= 0xffff;
99 | StringBuilder result = new StringBuilder(Integer.toHexString(crc));
100 | while (result.length() < 4) { //CRC检验一般为4位,不足4位补0
101 | result.insert(0, "0");
102 | }
103 | return result.toString().toUpperCase();
104 | }
105 |
106 | /**
107 | * CRC检验
108 | *
109 | * @param source
110 | * @return
111 | */
112 | public static String getCRC16(byte[] source) {
113 | int crc = 0xA1EC; // 初始值
114 | int polynomial = 0x1021; // 校验公式 0001 0000 0010 0001
115 |
116 | for (byte b : source) {
117 | for (int i = 0; i < 8; i++) {
118 | boolean bit = ((b >> (7 - i) & 1) == 1);
119 | boolean c15 = ((crc >> 15 & 1) == 1);
120 | crc <<= 1;
121 | if (c15 ^ bit) crc ^= polynomial;
122 | }
123 | }
124 | crc &= 0xffff;
125 | StringBuilder result = new StringBuilder(Integer.toHexString(crc));
126 | while (result.length() < 4) { //CRC检验一般为4位,不足4位补0
127 | result.insert(0, "0");
128 | }
129 | return result.toString().toUpperCase();
130 | }
131 |
132 | /**
133 | * CRC检验
134 | *
135 | * @param source
136 | * @return
137 | */
138 | public static String getCRC16(byte[] source, int offset, int len) {
139 | int crc = 0xA1EC; // 初始值
140 | int polynomial = 0x1021; // 校验公式 0001 0000 0010 0001
141 |
142 | int end = offset + len;
143 | for (int i = offset; i < end; i++) {
144 | for (int j = 0; j < 8; j++) {
145 | boolean bit = ((source[i] >> (7 - j) & 1) == 1);
146 | boolean c15 = ((crc >> 15 & 1) == 1);
147 | crc <<= 1;
148 | if (c15 ^ bit) crc ^= polynomial;
149 | }
150 | }
151 | crc &= 0xffff;
152 | StringBuilder result = new StringBuilder(Integer.toHexString(crc));
153 | while (result.length() < 4) { //CRC检验一般为4位,不足4位补0
154 | result.insert(0, "0");
155 | }
156 | return result.toString().toUpperCase();
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/java/com/apacherio/jondy/annotationdemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.apacherio.jondy.annotationdemo;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.util.Log;
6 | import android.view.View;
7 |
8 | import com.ljw.okserialport.serialport.bean.DataPack;
9 | import com.ljw.okserialport.serialport.bean.SerialPortParams;
10 | import com.ljw.okserialport.serialport.callback.CommonCallback;
11 | import com.ljw.okserialport.serialport.callback.SendResultCallback;
12 | import com.ljw.okserialport.serialport.callback.SerialportConnectCallback;
13 | import com.ljw.okserialport.serialport.core.OkSerialport;
14 | import com.ljw.okserialport.serialport.utils.ApiException;
15 | import com.ljw.okserialport.serialport.utils.BaseSerialPortException;
16 | import com.ljw.okserialport.serialport.utils.ByteUtil;
17 | import com.ljw.okserialport.serialport.utils.CmdPack;
18 | import com.ljw.okserialport.serialport.utils.OkSerialPortLog;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 |
24 | public class MainActivity extends AppCompatActivity {
25 | /**
26 | * 3.控制纸币器工作模式
27 | */
28 | public static byte CONTROL_0A = (byte) 0x0A;
29 | public static byte CONTROL_06 = (byte) 0x06;
30 | public static byte CONTROL_09 = (byte) 0x09;
31 | public static byte CONTROL_03 = (byte) 0x01;
32 |
33 |
34 | @Override
35 | protected void onCreate(Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 | setContentView(R.layout.activity_main);
38 | OkSerialPortLog.isDebug = true;
39 | com.apacherio.jondy.annotationdemo.OkSerialPort_Protocol.bind();
40 | findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
41 | @Override
42 | public void onClick(View view) {
43 | BanknotesApi.get().executeCoinChange(1, new CommonCallback() {
44 | @Override
45 | public void onStart(CmdPack cmdPack) {
46 | Log.e("tag", "onStart ==== ");
47 | }
48 |
49 | @Override
50 | public void onSuccess(Integer integer) {
51 | Log.e("tag", "onSuccess ==== " + integer);
52 |
53 | }
54 |
55 | @Override
56 | public void onFailed(BaseSerialPortException dLCException) {
57 | Log.e("tag", "onFailed ==== " + dLCException.getMessage());
58 | }
59 | });
60 | }
61 | });
62 |
63 | findViewById(R.id.btn_1).setOnClickListener(new View.OnClickListener() {
64 | @Override
65 | public void onClick(View view) {
66 | BanknotesApi.get().controlCoinWorkMode(1, new CommonCallback() {
67 | @Override
68 | public void onStart(CmdPack cmdPack) {
69 | Log.e("tag", "onStart ==== ");
70 | }
71 |
72 | @Override
73 | public void onSuccess(Integer integer) {
74 | Log.e("tag", "onSuccess ==== " + integer);
75 | }
76 |
77 | @Override
78 | public void onFailed(BaseSerialPortException dLCException) {
79 | Log.e("tag", "onFailed ==== " + dLCException.getMessage());
80 | }
81 | });
82 | }
83 | });
84 | findViewById(R.id.btn_2).setOnClickListener(new View.OnClickListener() {
85 | @Override
86 | public void onClick(View view) {
87 | BanknotesApi.get().controlWorkMode(1, 1, 1, 1, new CommonCallback() {
88 | @Override
89 | public void onStart(CmdPack cmdPack) {
90 | Log.e("tag", "onStart ==== ");
91 | }
92 |
93 | @Override
94 | public void onSuccess(Integer integer) {
95 | Log.e("tag", "onSuccess ==== " + integer);
96 | }
97 |
98 | @Override
99 | public void onFailed(BaseSerialPortException dLCException) {
100 | Log.e("tag", "onFailed ==== " + dLCException.getMessage());
101 | }
102 | });
103 | }
104 | });
105 | List heartCommands = new ArrayList<>();
106 | heartCommands.add(new byte[]{CONTROL_09,CONTROL_03});
107 | OkSerialport.getInstance().open(new SerialPortParams.Builder()
108 | .addDeviceAddress("/dev/ttyS4")
109 | .addBaudRate(9600)
110 | .addHeartCommands(heartCommands)
111 | .isReconnect(true)
112 | .callback(new SerialportConnectCallback() {
113 | @Override
114 | public void onError(ApiException apiException) {
115 |
116 | }
117 |
118 | @Override
119 | public void onOpenSerialPortSuccess() {
120 | Log.e("ljw", "onOpenSerialPortSuccess" );
121 |
122 | }
123 |
124 | @Override
125 | public void onHeatDataCallback(DataPack dataPack) {
126 | String command = ByteUtil.bytes2HexStr(dataPack.getCommand());
127 | Log.e("ljw", "心跳上来的命令:" + command + ",对应的数据 = " + ByteUtil.bytes2HexStr(dataPack.getData()));
128 | }
129 | })
130 | .build());
131 |
132 | }
133 |
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/core/OkSerialport.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.core;
2 |
3 |
4 | import com.ljw.okserialport.serialport.bean.DataPack;
5 | import com.ljw.okserialport.serialport.bean.SerialPortParams;
6 | import com.ljw.okserialport.serialport.callback.AsyncDataCallback;
7 | import com.ljw.okserialport.serialport.callback.DataPackCallback;
8 | import com.ljw.okserialport.serialport.callback.SendResultCallback;
9 | import com.ljw.okserialport.serialport.callback.SerialportConnectCallback;
10 | import com.ljw.okserialport.serialport.utils.ApiException;
11 | import com.ljw.okserialport.serialport.utils.BaseSerialPortException;
12 | import com.ljw.okserialport.serialport.utils.CmdPack;
13 | import com.ljw.okserialport.serialport.utils.OrderAssembleUtil;
14 | import com.ljw.okserialport.serialport.utils.ResultDataParseUtils;
15 |
16 | import java.nio.ByteBuffer;
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | /**
21 | * @author : LJW
22 | * @date : 2019/11/22
23 | * @desc :串口管理类
24 | */
25 | public class OkSerialport {
26 |
27 | public int mSendOutTime = 7000;
28 | public int mWaitOutTime = 7000;
29 |
30 | private static OkSerialport instance;
31 |
32 | public OkSerialport() {
33 | }
34 |
35 | public static OkSerialport getInstance() {
36 | if (instance == null) {
37 | Class var0 = OkSerialport.class;
38 | synchronized(OkSerialport.class) {
39 | if (instance == null) {
40 | instance = new OkSerialport();
41 | }
42 | }
43 | }
44 |
45 | return instance;
46 | }
47 |
48 | public void open(final SerialPortParams initSerialPortBean){
49 | close();
50 | SerialPortSingletonMgr.get().init(initSerialPortBean, new AsyncDataCallback() {
51 | @Override
52 | public boolean checkData(byte[] received, int size, DataPackCallback dataPackCallback) {
53 | return ResultDataParseUtils.handleDataPack(byteBuffer, received, size, dataPackCallback);
54 | }
55 |
56 | ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
57 |
58 | @Override
59 | public void onActivelyReceivedCommand(DataPack dataPack) {
60 | if (initSerialPortBean.getCallback() != null) {
61 | initSerialPortBean.getCallback().onHeatDataCallback(dataPack);
62 | }
63 | }
64 | }, new SerialportConnectCallback() {
65 | @Override
66 | public void onError(ApiException apiException) {
67 |
68 | if (initSerialPortBean.isReconnect()) {
69 | open(initSerialPortBean);
70 | }
71 | if (initSerialPortBean.getCallback() != null) {
72 | initSerialPortBean.getCallback().onError(apiException);
73 | }
74 | }
75 |
76 | @Override
77 | public void onOpenSerialPortSuccess() {
78 | if (initSerialPortBean.getCallback() != null) {
79 | initSerialPortBean.getCallback().onOpenSerialPortSuccess();
80 | }
81 | }
82 |
83 | @Override
84 | public void onHeatDataCallback(DataPack dataPack) {
85 |
86 | }
87 | });
88 | }
89 |
90 |
91 |
92 | public void close() {
93 | SerialPortSingletonMgr.get().closeSerialPort();
94 | }
95 |
96 |
97 | public void setmSendOutTime(int mSendOutTime) {
98 | this.mSendOutTime = mSendOutTime;
99 | }
100 |
101 | public void setmWaitOutTime(int mWaitOutTime) {
102 | this.mWaitOutTime = mWaitOutTime;
103 | }
104 |
105 | /**
106 | * @param fillDatas 填充占位数据,没有则传null
107 | * @param data 数据
108 | * @param sendCommand 命令
109 | * @param sendResultCallback 发送回调
110 | */
111 | public void send(String[] fillDatas, String data, byte[] sendCommand, SendResultCallback sendResultCallback) {
112 | try {
113 | byte[] checkCommand = sendCommand;
114 | byte[] cmd = OrderAssembleUtil.allCmd(checkCommand, fillDatas, data);
115 | List checkCommands = new ArrayList<>();
116 | checkCommands.add(checkCommand);
117 | final CmdPack cmdPack = new CmdPack(0, cmd, checkCommands);
118 | cmdPack.setSendOutTime(mSendOutTime);
119 | cmdPack.setWaitOutTime(mWaitOutTime);
120 | SerialPortSingletonMgr.get().send(cmdPack, sendResultCallback);
121 | } catch (Exception e) {
122 | e.printStackTrace();
123 | if (sendResultCallback != null) {
124 | sendResultCallback.onFailed(new BaseSerialPortException("-1", "发送失败:" + e.getMessage(), 1));
125 | }
126 | }
127 | }
128 |
129 | /**
130 | * 心跳回答
131 | *
132 | * @param fillDatas 填充占位数据,没有则传null
133 | * @param data 数据
134 | * @param sendCommand 命令
135 | * @param sendResultCallback 发送回调
136 | */
137 | public void heartBeatReply(String[] fillDatas, String data, byte[] sendCommand, SendResultCallback sendResultCallback) {
138 | try {
139 | byte[] checkCommand = sendCommand;
140 | byte[] cmd = OrderAssembleUtil.allCmd(checkCommand, fillDatas, data);
141 | List checkCommands = new ArrayList<>();
142 | checkCommands.add(checkCommand);
143 | final CmdPack cmdPack = new CmdPack(0, cmd, checkCommands);
144 | cmdPack.setSendOutTime(1000);
145 | cmdPack.setWaitOutTime(50);
146 | SerialPortSingletonMgr.get().send(cmdPack, sendResultCallback);
147 | } catch (Exception e) {
148 | e.printStackTrace();
149 | if (sendResultCallback != null) {
150 | sendResultCallback.onFailed(new BaseSerialPortException("-1", "发送失败:" + e.getMessage(), 1));
151 | }
152 | }
153 | }
154 |
155 |
156 |
157 |
158 |
159 | }
160 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/proxy/SerialReadThread.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.proxy;
2 |
3 | import android.os.SystemClock;
4 | import android.text.TextUtils;
5 |
6 |
7 | import com.ljw.okserialport.serialport.bean.DataPack;
8 | import com.ljw.okserialport.serialport.callback.AsyncDataCallback;
9 | import com.ljw.okserialport.serialport.callback.BaseDataCallback;
10 | import com.ljw.okserialport.serialport.callback.DataPackCallback;
11 | import com.ljw.okserialport.serialport.callback.SerialReadCallback;
12 | import com.ljw.okserialport.serialport.utils.ByteUtil;
13 | import com.ljw.okserialport.serialport.utils.OkSerialPortLog;
14 | import com.ljw.okserialport.serialport.utils.ReadMessage;
15 | import com.ljw.okserialport.serialport.utils.ReadType;
16 |
17 | import java.io.BufferedInputStream;
18 | import java.io.IOException;
19 | import java.util.List;
20 |
21 |
22 | /**
23 | * 读串口线程
24 | */
25 | public class SerialReadThread extends Thread {
26 |
27 |
28 | private BufferedInputStream mBufferedInputStream;
29 | private BaseDataCallback mBaseDataCallback;
30 | private SerialReadCallback mSerialReadCallback;
31 | private boolean isActivelyReceivedCommand;
32 | private List mHeartCommand;
33 | /**
34 | * 记录一下发送后的时间,用来判断接收数据是否超时
35 | */
36 | private long checkSendDataTime = System.currentTimeMillis();
37 | private long errorTime = System.currentTimeMillis();
38 |
39 |
40 | public SerialReadThread(boolean isActivelyReceivedCommand, List heartCommand, BufferedInputStream bufferedInputStream,
41 | BaseDataCallback baseDataCallback, SerialReadCallback serialReadCallback) {
42 | mBufferedInputStream = bufferedInputStream;
43 | mBaseDataCallback = baseDataCallback;
44 | mSerialReadCallback = serialReadCallback;
45 | mHeartCommand = heartCommand;
46 | this.isActivelyReceivedCommand = isActivelyReceivedCommand;
47 | }
48 |
49 | @Override
50 | public void run() {
51 | byte[] received = new byte[1024];
52 | int size;
53 |
54 |
55 | while (true) {
56 | if (Thread.currentThread().isInterrupted()) {
57 | break;
58 | }
59 | try {
60 | int available = mBufferedInputStream.available();
61 | boolean isSend = false;
62 | if (available > 0) {
63 | size = mBufferedInputStream.read(received);
64 |
65 | if (size > 0) {
66 | isSend = onDataReceive(received, size);
67 | // 暂停一点时间,免得处理数据太快
68 | SystemClock.sleep(1);
69 | }
70 | } else {
71 | // 暂停一点时间,免得一直循环造成CPU占用率过高
72 | SystemClock.sleep(1);
73 | }
74 | if (!isSend && isTimeOut()) {
75 | if (mSerialReadCallback != null) {
76 | mSerialReadCallback.onReadMessage(new ReadMessage(ReadType.CheckSendData, "CheckSendData", null));
77 | }
78 | }
79 | } catch (IOException e) {
80 | if (isErrorTimeOut()) {
81 | if (mSerialReadCallback != null) {
82 | mSerialReadCallback.onReadMessage(new ReadMessage(ReadType.CheckSendData, "ReadDataError:" +
83 | "读取数据失败:" + e.toString(), null));
84 | }
85 | }
86 | }
87 | }
88 |
89 | }
90 |
91 | /**
92 | * 处理获取到的数据
93 | *
94 | * @param received
95 | * @param size
96 | */
97 | private boolean onDataReceive(byte[] received, int size) {
98 | return mBaseDataCallback.checkData(received, size, new DataPackCallback() {
99 | @Override
100 | public void setDataPack(DataPack dataPack) {
101 | if (dataPack != null) {
102 | OkSerialPortLog.e("接收数据:" + ByteUtil.bytes2HexStr(dataPack.getAllPackData()));
103 | if (isActivelyReceivedCommand && isActivelyReceivedCommand(dataPack)) {
104 | if (mBaseDataCallback instanceof AsyncDataCallback) {
105 | // LogPlus.e("心跳数据");
106 | OkSerialPortLog.e("心跳数据");
107 | ((AsyncDataCallback) mBaseDataCallback).onActivelyReceivedCommand(dataPack);
108 | }
109 | return;
110 | }else if (mSerialReadCallback != null) {//不是心跳数据
111 | OkSerialPortLog.e("不是心跳数据");
112 | mSerialReadCallback.onReadMessage(new ReadMessage(ReadType.ReadDataSuccess, "ReadDataSuccess", dataPack));
113 | }
114 |
115 | }
116 | }
117 | });
118 |
119 | }
120 |
121 | /**
122 | * 是否是主动收到命令
123 | *
124 | * @return
125 | */
126 | private boolean isActivelyReceivedCommand(DataPack dataPack) {
127 | if (mHeartCommand != null && mHeartCommand.size() > 0) {
128 | for (byte[] bytes : mHeartCommand) {
129 | String command = ByteUtil.bytes2HexStr(bytes);
130 | String readCommand = ByteUtil.bytes2HexStr(dataPack.getCommand());
131 | if (TextUtils.equals(command, readCommand)) {
132 | return true;
133 | }
134 | }
135 | }
136 | return false;
137 | }
138 |
139 | private boolean isTimeOut() {
140 | // 在规定时间内校验
141 | if (Math.abs(System.currentTimeMillis() - checkSendDataTime) > 100) {
142 | checkSendDataTime = System.currentTimeMillis();
143 | return true;
144 | }
145 | return false;
146 | }
147 |
148 | private boolean isErrorTimeOut() {
149 | // 在规定时间内校验
150 | if (Math.abs(System.currentTimeMillis() - errorTime) > 1000) {
151 | errorTime = System.currentTimeMillis();
152 | return true;
153 | }
154 | return false;
155 | }
156 |
157 | /**
158 | * 停止读线程
159 | */
160 | public void close() {
161 | try {
162 | mBufferedInputStream.close();
163 | } catch (IOException e) {
164 | OkSerialPortLog.e("异常:" + e.toString());
165 | } finally {
166 | super.interrupt();
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/app/src/main/java/com/apacherio/jondy/annotationdemo/BanknotesApi.java:
--------------------------------------------------------------------------------
1 | package com.apacherio.jondy.annotationdemo;
2 |
3 |
4 | import android.text.TextUtils;
5 |
6 | import com.ljw.okserialport.serialport.bean.DataPack;
7 | import com.ljw.okserialport.serialport.callback.CommonCallback;
8 | import com.ljw.okserialport.serialport.callback.SendResultCallback;
9 | import com.ljw.okserialport.serialport.core.OkSerialport;
10 | import com.ljw.okserialport.serialport.utils.BaseSerialPortException;
11 | import com.ljw.okserialport.serialport.utils.ByteUtil;
12 | import com.ljw.okserialport.serialport.utils.CmdPack;
13 |
14 | /**
15 | * @author : LJW
16 | * @date : 2019/11/23
17 | * @desc :232纸币器硬件方法
18 | */
19 | public class BanknotesApi {
20 |
21 |
22 | private volatile static BanknotesApi instance;
23 |
24 | public static BanknotesApi get() {
25 | if (instance == null) {
26 | synchronized (BanknotesApi.class) {
27 | if (instance == null) {
28 | instance = new BanknotesApi();
29 | }
30 | }
31 | }
32 | return instance;
33 | }
34 |
35 |
36 |
37 | public void executeCoinChange(int number, final CommonCallback commonCallback) {
38 | StringBuilder data = new StringBuilder();
39 | data.append(ByteUtil.integer2HexStr(2));
40 | data.append(ByteUtil.integer2HexStr(number * 2));
41 |
42 | String [] strings = new String[]{ByteUtil.integer2HexStr(1),ByteUtil.bytesToHexString(new byte[]{BanknotesProtocol.CHANGE_ACTION})};
43 | OkSerialport.getInstance().send(null,data.toString(),new byte[]{BanknotesProtocol.CHANGE_ACTION}, new SendResultCallback() {
44 | @Override
45 | public void onStart(CmdPack cmdPack) {
46 | if (commonCallback != null) {
47 | commonCallback.onStart(cmdPack);
48 | }
49 | }
50 |
51 | @Override
52 | public void onSuccess(DataPack dataPack) {
53 | if (commonCallback != null) {
54 | int result = -1;
55 | result = (ByteUtil.byteToInt(
56 | ByteUtil.getBytes(dataPack.getData(), 0, 1)));
57 | commonCallback.onSuccess(result);
58 | }
59 | }
60 |
61 | @Override
62 | public void onFailed(BaseSerialPortException dLCException) {
63 | if (commonCallback != null) {
64 | commonCallback.onFailed(dLCException);
65 | }
66 | }
67 | });
68 | }
69 |
70 |
71 | /**
72 | * 控制纸币器工作模式 让纸币器开始工作调用此命令,停止工作也调用此命令,所有参数传0即可
73 | *
74 | * @param us1 1 表示接收1美元的纸币 0 表示不接收
75 | * @param us5 1 表示接收5美元的纸币 0 表示不接收
76 | * @param us10 1 表示接收10美元的纸币 0 表示不接收
77 | * @param us20 1 表示接收20美元的纸币 0 表示不接收
78 | * @Callback 执行结果 int类型 00H=控制成功 FFH=控制失败
79 | */
80 | public void controlWorkMode(int us1, int us5, int us10, int us20, final CommonCallback commonCallback) {
81 | StringBuilder data = new StringBuilder();
82 | data.append(ByteUtil.integer2HexStr(0));
83 | String s = "0000" + us20 + us10 + us5 + us1;
84 | int i = ByteUtil.convertToDecimal(s);
85 | data.append(ByteUtil.integer2HexStr(i));
86 | data.append(ByteUtil.integer2HexStr(0));
87 | data.append(ByteUtil.integer2HexStr(0));
88 |
89 | String [] strings = new String[]{ByteUtil.integer2HexStr(1),ByteUtil.bytesToHexString(new byte[]{BanknotesProtocol.CONTROL_WAY_SHIPMENT_CMD})};
90 |
91 | OkSerialport.getInstance().send(null,data.toString(),new byte[]{BanknotesProtocol.CONTROL_WAY_SHIPMENT_CMD},new SendResultCallback() {
92 | @Override
93 | public void onStart(CmdPack cmdPack) {
94 | if (commonCallback != null) {
95 | commonCallback.onStart(cmdPack);
96 | }
97 | }
98 |
99 | @Override
100 | public void onSuccess(DataPack dataPack) {
101 | if (commonCallback != null) {
102 | int result = -1;
103 | result = (ByteUtil.byteToInt(
104 | ByteUtil.getBytes(dataPack.getData(), 0, 1)));
105 | commonCallback.onSuccess(result);
106 | }
107 | }
108 |
109 | @Override
110 | public void onFailed(BaseSerialPortException dLCException) {
111 | if (commonCallback != null) {
112 | commonCallback.onFailed(dLCException);
113 | }
114 | }
115 | });
116 | }
117 |
118 |
119 | /**
120 | * 控制硬币器工作模式0CH 让硬币器开始工作调用此命令,停止工作也调用此命令,所有参数传0即可
121 | *
122 | * @param cent25 1 表示接收25美分硬币 0表示不接收
123 | * @callback 执行结果 int类型 00H=控制成功 FFH=控制失败
124 | */
125 | public void controlCoinWorkMode(int cent25, final CommonCallback commonCallback) {
126 | StringBuilder data = new StringBuilder();
127 | data.append(ByteUtil.integer2HexStr(0));
128 |
129 | String s = "00000" + cent25 + cent25 + cent25;
130 | int i = ByteUtil.convertToDecimal(s);
131 | data.append(ByteUtil.integer2HexStr(i));
132 | data.append(ByteUtil.integer2HexStr(0));
133 | data.append(ByteUtil.integer2HexStr(0));
134 |
135 | String [] strings = new String[]{ByteUtil.integer2HexStr(1),ByteUtil.bytesToHexString(new byte[]{BanknotesProtocol.CONTROL_COIN_WORK_MODE})};
136 |
137 | OkSerialport.getInstance().heartBeatReply(null,data.toString(),new byte[]{BanknotesProtocol.CONTROL_COIN_WORK_MODE}, new SendResultCallback() {
138 | @Override
139 | public void onStart(CmdPack cmdPack) {
140 | if (commonCallback != null) {
141 | commonCallback.onStart(cmdPack);
142 | }
143 | }
144 |
145 | @Override
146 | public void onSuccess(DataPack dataPack) {
147 | if (commonCallback != null) {
148 | int result = -1;
149 | result = (ByteUtil.byteToInt(
150 | ByteUtil.getBytes(dataPack.getData(), 0, 1)));
151 | commonCallback.onSuccess(result);
152 | }
153 | }
154 |
155 | @Override
156 | public void onFailed(BaseSerialPortException dLCException) {
157 | if (commonCallback != null) {
158 | commonCallback.onFailed(dLCException);
159 | }
160 | }
161 | });
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/CmdTask.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 |
4 | import android.os.SystemClock;
5 |
6 |
7 | import com.ljw.okserialport.serialport.bean.DataPack;
8 | import com.ljw.okserialport.serialport.callback.BaseDataCallback;
9 | import com.ljw.okserialport.serialport.callback.DataPackCallback;
10 | import com.ljw.okserialport.serialport.callback.SendResultCallback;
11 |
12 | import java.io.BufferedInputStream;
13 | import java.io.IOException;
14 | import java.io.OutputStream;
15 |
16 | /**
17 | * @author : LJW
18 | * @date : 2019/11/22
19 | * @desc :
20 | */
21 | public class CmdTask extends BaseQueue {
22 | private SendResultCallback mSendResultCallback;
23 | private CmdPack mCmdPack;
24 | private BaseDataCallback mBaseDataCallback;
25 | private BufferedInputStream mBufferedInputStream;
26 | private OutputStream mOutputStream;
27 |
28 | public CmdTask(@Priority int priority, SendResultCallback mSendResultCallback, CmdPack mCmdPack, OutputStream outputStream,
29 | BufferedInputStream bufferedInputStream, BaseDataCallback baseDataCallback) {
30 | this.mSendResultCallback = mSendResultCallback;
31 | this.mCmdPack = mCmdPack;
32 | mBufferedInputStream = bufferedInputStream;
33 | mOutputStream = outputStream;
34 | this.mBaseDataCallback = baseDataCallback;
35 | setPriority(priority);
36 | }
37 |
38 | boolean isRunning = false;
39 |
40 | @Override
41 | public void runTask() {
42 | boolean isSend = sendData();
43 | if (!isSend) {
44 | return;
45 | }
46 | isRunning = true;
47 |
48 | int size;
49 | // 记录一下发送后的时间,用来判断接收数据是否超时
50 | long sendTime = System.currentTimeMillis();
51 | long waitTime = 0;
52 | while (isRunning) {
53 | try {
54 | if (mBufferedInputStream.available() > 0) {
55 | // 更新一下接收数据时间
56 | waitTime = System.currentTimeMillis();
57 | byte[] received = new byte[2048];
58 | size = mBufferedInputStream.read(received);
59 | mBaseDataCallback.checkData(received, size, new DataPackCallback() {
60 | @Override
61 | public void setDataPack(DataPack dataPack) {
62 | if (dataPack != null) {
63 | //命令码
64 | if (mCmdPack.getCheckCommand() == null || mCmdPack.getCheckCommand().size() == 0) {
65 | if (mSendResultCallback != null) {
66 | mSendResultCallback.onFailed(
67 | new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_ERROR, "248的校验命令不能为空,请设置CmdPack中的checkCommand",
68 | mCmdPack.getDestinationAddress()));
69 | }
70 | isRunning = false;
71 | return;
72 | }
73 | if (mCmdPack.getCheckCommand().size() > 1) {
74 | if (mSendResultCallback != null) {
75 | mSendResultCallback.onFailed(new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_ERROR,
76 | "248的校验命令不能超过一个,checkCommand:" + mCmdPack.getCheckCommands(), mCmdPack.getDestinationAddress()));
77 | }
78 | isRunning = false;
79 | return;
80 | }
81 | String command = ByteUtil.bytes2HexStr(mCmdPack.getCheckCommand().get(0));
82 | String readCommand = ByteUtil.bytes2HexStr(dataPack.getCommand());
83 | if (readCommand.equalsIgnoreCase(command)) {
84 | if (mSendResultCallback != null) {
85 | mSendResultCallback.onSuccess(dataPack);
86 | }
87 | } else {
88 | if (mSendResultCallback != null) {
89 | mSendResultCallback.onFailed(new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_ERROR,
90 | "命令码不同,获取到结果为:" + dataPack.toString() + "--校验命令码:" + command, mCmdPack.getDestinationAddress()));
91 | }
92 | }
93 | isRunning = false;
94 | return;
95 | }
96 | }
97 | });
98 | } else {
99 | // 暂停一点时间,免得一直循环造成CPU占用率过高
100 | SystemClock.sleep(1);
101 | }
102 | // 检查释放超时
103 | boolean isTimeOut = isTimeOut(sendTime, waitTime);
104 | if (isTimeOut) {
105 | if (mSendResultCallback != null) {
106 | mSendResultCallback.onFailed(
107 | new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_READ_OUT_TIME_ERROR, "读取超时", mCmdPack.getDestinationAddress()));
108 | }
109 | return;
110 | }
111 | } catch (IOException e) {
112 | if (mSendResultCallback != null) {
113 | mSendResultCallback.onFailed(
114 | new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_ERROR, e.toString(), mCmdPack.getDestinationAddress()));
115 | }
116 | isRunning = false;
117 | }
118 | }
119 | }
120 |
121 | private boolean isTimeOut(long sendTime, long waitTime) {
122 | // 表示一直没收到数据
123 | if (waitTime == 0) {
124 | long sendOffset = Math.abs(System.currentTimeMillis() - sendTime);
125 | return sendOffset > mCmdPack.getSendOutTime();
126 | } else {
127 | // 有接收到过数据,但是距离上一个数据已经超时
128 | long waitOffset = Math.abs(System.currentTimeMillis() - waitTime);
129 | return waitOffset > mCmdPack.getWaitOutTime();
130 | }
131 | }
132 |
133 | private boolean sendData() {
134 | try {
135 | if (mSendResultCallback != null) {
136 | mSendResultCallback.onStart(mCmdPack);
137 | }
138 | SystemClock.sleep(100);
139 | // LogPlus.e("发送码:" + ByteUtil.bytes2HexStr(mCmdPack.getSendData()));
140 | mOutputStream.write(mCmdPack.getSendData());
141 | } catch (IOException e) {
142 | if (mSendResultCallback != null) {
143 | mSendResultCallback.onFailed(
144 | new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_ERROR, "硬件错误:" + e.toString(), mCmdPack.getDestinationAddress()));
145 | }
146 | return false;
147 | }
148 | return true;
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/ResultDataParseUtils.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 |
4 | import com.ljw.okserialport.serialport.bean.DataPack;
5 | import com.ljw.okserialport.serialport.bean.ProtocolBean;
6 | import com.ljw.okserialport.serialport.callback.DataPackCallback;
7 | import com.ljw.okserialport.serialport.core.OkSerialPort_ProtocolManager;
8 |
9 | import java.nio.ByteBuffer;
10 | import java.util.Map;
11 |
12 |
13 | /**
14 | * @author : LJW
15 | * @date : 2019/11/22
16 | * @desc :数据解析
17 | */
18 | public class ResultDataParseUtils {
19 |
20 | public static boolean handleDataPack(ByteBuffer byteBuffer, byte[] received, int size, DataPackCallback dataPackCallback) {
21 | OkSerialPortLog.e("开始校验接收到的数据!!!");
22 | if (byteBuffer == null) {
23 | byteBuffer = ByteBuffer.allocate(1024);
24 | byteBuffer.clear();
25 | }
26 | //从received数组中的0到0+length区域读取数据并使用相对写写入此byteBuffer
27 | byteBuffer.put(received, 0, size);
28 | //limit = position;position = 0;mark = -1;
29 |
30 | // 将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态
31 | byteBuffer.flip();
32 | Map mProtocolMap;
33 | mProtocolMap = OkSerialPort_ProtocolManager.mProtocolMap;
34 | int readable;
35 | while ((readable = byteBuffer.remaining()) >= OkSerialPort_ProtocolManager.MINDALALEN) {
36 | //标记一下当前位置,调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置
37 | byteBuffer.mark();
38 | int frameStart = byteBuffer.position();
39 |
40 | boolean isPass = true;
41 |
42 | a:
43 | for (int i = 0; i < OkSerialPort_ProtocolManager.FRAMEHEADERCOUNT; i++) {
44 | byte head = byteBuffer.get();
45 | if (head != mProtocolMap.get(i).value) {
46 | isPass = false;
47 | OkSerialPortLog.e("帧头校验不通过!" + ByteUtil.bytes2HexStr(new byte[]{head}) + " ====== " + ByteUtil.bytes2HexStr(new byte[]{mProtocolMap.get(i).value}));
48 | break a;
49 | }
50 | }
51 | if (!isPass) {
52 | continue;
53 | }
54 |
55 | //校验数据域长度,数据域在第5个位置
56 | int datalenCount = 0;
57 | switch (OkSerialPort_ProtocolManager.mProtocolMap.get(OkSerialPort_ProtocolManager.DATALENINDEX).length) {
58 | case 1:
59 | datalenCount = ByteUtil.byteToInt(new byte[]{byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENFIRST)});
60 | break;
61 | case 2:
62 | datalenCount = ByteUtil.byteToInt(new byte[]{byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENFIRST), byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENFIRST + 1)});
63 |
64 | break;
65 | case 3:
66 | datalenCount = ByteUtil.byteToInt(new byte[]{byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENFIRST), byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENFIRST + 1), byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENFIRST + 2)});
67 | break;
68 | case 4:
69 | datalenCount = ByteUtil.byteToInt(new byte[]{byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENFIRST), byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENFIRST + 1), byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENFIRST + 2), byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENFIRST + 3)});
70 | break;
71 | default:
72 | break;
73 | }
74 | // byte[] len = new byte[]{byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENINDEX),byteBuffer.get(frameStart + OkSerialPort_ProtocolManager.DATALENINDEX + OkSerialPort_ProtocolManager.mProtocolMap.get(5).length)};
75 | //数据域长度(命令码+数据的长度) 减去默认的长度剩下就是数据长度
76 | OkSerialPortLog.e("数据长度:" + datalenCount);
77 | int dataLen = datalenCount - mProtocolMap.get(OkSerialPort_ProtocolManager.DATALENINDEX).value;
78 | OkSerialPortLog.e("去除后单纯的数据长度:" + dataLen);
79 |
80 | // 总数据长度(实际长度=最小长度(不包含数据域长度)+实际数据长度)
81 | int total = OkSerialPort_ProtocolManager.MINDALALEN + dataLen;
82 | OkSerialPortLog.e("整个包总数据长度:" + total);
83 | if (readable < total) {
84 | //重置处理的位置,跳出循环
85 | OkSerialPortLog.e("数据长度不合理:" + total + " ===== "+readable);
86 | byteBuffer.reset();
87 | break;
88 | }
89 | //回到头
90 | byteBuffer.reset();
91 | //获取整个包
92 | byte[] allPack = new byte[total];
93 | byteBuffer.get(allPack);
94 | int oXRLen = mProtocolMap.get(mProtocolMap.size() - 1).length;
95 | OkSerialPortLog.e("整个包数据= " + ByteUtil.bytes2HexStr(allPack));
96 |
97 | //校验码
98 | if (OkSerialPort_ProtocolManager.CHECKCODERULE == 0) {
99 | //异或的数据是第一位到最后
100 | String dataToXOR = CheckUtil.getXOR(ByteUtil.getBytes(allPack, 0, total - oXRLen));
101 | //获取数据包中的异或值
102 |
103 | String currentXOR = ByteUtil.bytes2HexStr(allPack, total - oXRLen, mProtocolMap.get(mProtocolMap.size() - 1).length);
104 | OkSerialPortLog.e("异或校验数据:" + dataToXOR + ",被校验数据:" + currentXOR);
105 |
106 | if (dataToXOR.equalsIgnoreCase(currentXOR)) {
107 | //获取数据码,根据数据,数据码在第六位,所以从8算起
108 | byte[] data = ByteUtil.getBytes(allPack, OkSerialPort_ProtocolManager.DATAFIRST, dataLen);
109 | byte[] commands = ByteUtil.getBytes(allPack, OkSerialPort_ProtocolManager.COMMANDFIRST, mProtocolMap.get(OkSerialPort_ProtocolManager.COMMANDINDEX).length);
110 | //最后清掉之前处理过的不合适的数据
111 | if (dataPackCallback != null) {
112 | dataPackCallback.setDataPack(new DataPack(allPack, data, commands));
113 | }
114 | } else {
115 | //不一致回调这次帧头之后
116 | byteBuffer.position(frameStart + mProtocolMap.get(mProtocolMap.size() - 1).length);
117 | }
118 | } else {
119 | // 计算crc16
120 | String check = CRC16Utils.getCRC16(allPack, 0, total - oXRLen);
121 | String recCheck = ByteUtil.bytes2HexStr(allPack, total - oXRLen, oXRLen).toUpperCase();
122 | OkSerialPortLog.e("异或校验数据:" + check + ",被校验数据:" + recCheck);
123 | // 校验通过
124 | if (check.equals(recCheck)) {
125 | //获取数据码,根据数据,数据码在第六位,所以从8算起
126 | byte[] data = ByteUtil.getBytes(allPack, OkSerialPort_ProtocolManager.DATAFIRST, dataLen);
127 | byte[] commands = ByteUtil.getBytes(allPack, OkSerialPort_ProtocolManager.COMMANDFIRST, mProtocolMap.get(OkSerialPort_ProtocolManager.COMMANDINDEX).length);
128 | //最后清掉之前处理过的不合适的数据
129 | if (dataPackCallback != null) {
130 | dataPackCallback.setDataPack(new DataPack(allPack, data, commands));
131 | }
132 | } else {
133 | //不一致回调这次帧头之后
134 | byteBuffer.position(frameStart + mProtocolMap.get(mProtocolMap.size() - 1).length);
135 | }
136 | }
137 |
138 |
139 | }
140 | //最后清掉之前处理过的不合适的数据
141 | byteBuffer.compact();
142 | return true;
143 | }
144 |
145 |
146 | }
147 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/core/SerialPortSingletonMgr.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.core;
2 |
3 |
4 | import android.serialport.SerialPort;
5 | import android.text.TextUtils;
6 |
7 |
8 | import com.ljw.okserialport.serialport.bean.SerialPortParams;
9 | import com.ljw.okserialport.serialport.callback.BaseDataCallback;
10 | import com.ljw.okserialport.serialport.callback.SendResultCallback;
11 | import com.ljw.okserialport.serialport.callback.SerialportConnectCallback;
12 | import com.ljw.okserialport.serialport.proxy.AsyncServicesProxy;
13 | import com.ljw.okserialport.serialport.proxy.SyncServicesProxy;
14 | import com.ljw.okserialport.serialport.utils.ApiException;
15 | import com.ljw.okserialport.serialport.utils.ApiExceptionCode;
16 | import com.ljw.okserialport.serialport.utils.BaseSerialPortException;
17 | import com.ljw.okserialport.serialport.utils.CmdPack;
18 | import com.ljw.okserialport.serialport.utils.ServiceType;
19 |
20 | import java.io.BufferedInputStream;
21 | import java.io.File;
22 | import java.io.IOException;
23 | import java.io.OutputStream;
24 |
25 | /**
26 | * @author : LJW
27 | * @date : 2019/11/22
28 | * @desc :
29 | */
30 | public class SerialPortSingletonMgr {
31 |
32 | private volatile static SerialPortSingletonMgr instance;
33 |
34 | public static SerialPortSingletonMgr get() {
35 | if (instance == null) {
36 | synchronized (SerialPortSingletonMgr.class) {
37 | if (instance == null) {
38 | instance = new SerialPortSingletonMgr();
39 | }
40 | }
41 | }
42 | return instance;
43 | }
44 | private SerialPort mSerialPort;
45 | private OutputStream mOutputStream;
46 | private BufferedInputStream mBufferedInputStream;
47 | private int mSerialPortType;
48 | private SyncServicesProxy mSyncServicesProxy;
49 | private AsyncServicesProxy mAsyncServicesProxy;
50 |
51 |
52 | public void init(SerialPortParams initSerialPortBean, BaseDataCallback baseDataCallback, SerialportConnectCallback connectCallback) {
53 | if (initSerialPortBean == null) {
54 | throw new ApiException(ApiExceptionCode.SERIAL_PORT_ERROR, "initSerialPortBean不为null");
55 | }
56 | if (TextUtils.isEmpty(initSerialPortBean.getDeviceAddress())) {
57 | throw new ApiException(ApiExceptionCode.SERIAL_PORT_ERROR, "串口地址不为null");
58 | }
59 | if (initSerialPortBean.getBaudRate() == 0) {
60 | throw new ApiException(ApiExceptionCode.SERIAL_PORT_ERROR, "波特率不为0");
61 | }
62 | if (baseDataCallback == null) {
63 | throw new ApiException(ApiExceptionCode.SERIAL_PORT_ERROR, "回调不可以为空,校验方法必须实现");
64 | }
65 | closeSerialPort();
66 | try {
67 | File device = new File(initSerialPortBean.getDeviceAddress());
68 | mSerialPort = new SerialPort(device, initSerialPortBean.getBaudRate(), 0);
69 | mOutputStream = mSerialPort.getOutputStream();
70 | if (mSerialPort.getInputStream() != null) {
71 | mBufferedInputStream = new BufferedInputStream(mSerialPort.getInputStream());
72 | }
73 | if (connectCallback != null) {
74 | connectCallback.onOpenSerialPortSuccess();
75 | }
76 | mSerialPortType = initSerialPortBean.getServiceType();
77 | if (mSerialPortType == ServiceType.SyncServices) {
78 | mSyncServicesProxy = new SyncServicesProxy(mOutputStream, mBufferedInputStream, baseDataCallback);
79 | } else if (mSerialPortType == ServiceType.AsyncServices) {
80 | mAsyncServicesProxy = new AsyncServicesProxy(initSerialPortBean.isOpenHeart(), initSerialPortBean.getHeartCommand(), mOutputStream, mBufferedInputStream, baseDataCallback);
81 | }
82 | } catch (Exception e) {
83 | if (connectCallback != null) {
84 | connectCallback.onError( new ApiException(ApiExceptionCode.SERIAL_PORT_ERROR, "串口打开异常:" + e.toString()));
85 | }
86 | mSerialPort = null;
87 | }
88 | }
89 |
90 | private void startTask() {
91 | if (mSerialPortType == ServiceType.SyncServices) {
92 | if (mSyncServicesProxy != null) {
93 | mSyncServicesProxy.stopTaskQueue();
94 | } else {
95 | }
96 | } else if (mSerialPortType == ServiceType.AsyncServices) {
97 | if (mAsyncServicesProxy != null) {
98 | mAsyncServicesProxy.stopTask();
99 | } else {
100 | // LogPlus.e("mSyncServicesProxy==null,串口初始化异常");
101 | }
102 | }
103 | }
104 |
105 | /**
106 | * 停止当前任务,释放线程
107 | */
108 | public void stopTask() {
109 | if (mSerialPortType == ServiceType.SyncServices) {
110 | if (mSyncServicesProxy != null) {
111 | mSyncServicesProxy.stopTaskQueue();
112 | } else {
113 | // LogPlus.e("mSyncServicesProxy==null,串口初始化异常");
114 | }
115 | } else if (mSerialPortType == ServiceType.AsyncServices) {
116 | if (mAsyncServicesProxy != null) {
117 | mAsyncServicesProxy.stopTask();
118 | } else {
119 | // LogPlus.e("mSyncServicesProxy==null,串口初始化异常");
120 | }
121 | }
122 | }
123 |
124 | public void send(CmdPack cmdPack, SendResultCallback sendResultCallback) {
125 | if (mSerialPort == null) {
126 | if (sendResultCallback != null) {
127 | sendResultCallback.onFailed(new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_ERROR, "串口打开失败!",cmdPack.getDestinationAddress()));
128 | }
129 | return;
130 | }
131 |
132 | if (mOutputStream == null) {
133 | if (sendResultCallback != null) {
134 | sendResultCallback.onFailed(new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_ERROR, "串口获取,OutputStream为null",cmdPack.getDestinationAddress()));
135 | }
136 | return;
137 | }
138 | if (mBufferedInputStream == null) {
139 | if (sendResultCallback != null) {
140 | sendResultCallback.onFailed(new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_ERROR, "串口获取,InputStream为null:",cmdPack.getDestinationAddress()));
141 | return;
142 | }
143 | }
144 | if (mSerialPortType == ServiceType.SyncServices) {
145 | if (mSyncServicesProxy != null) {
146 | mSyncServicesProxy.send(cmdPack, sendResultCallback);
147 | }
148 | } else if (mSerialPortType == ServiceType.AsyncServices) {
149 | if (mAsyncServicesProxy != null) {
150 | mAsyncServicesProxy.send(cmdPack, sendResultCallback);
151 | }
152 | }
153 | }
154 |
155 | /**
156 | * 关闭串口
157 | */
158 | public void closeSerialPort() {
159 | if (mSerialPort != null) {
160 | try {
161 | if (mSerialPort.getOutputStream() != null) {
162 | mSerialPort.getOutputStream().close();
163 | }
164 | } catch (IOException e) {
165 | e.printStackTrace();
166 | }
167 | try {
168 | if (mSerialPort.getInputStream() != null) {
169 | mSerialPort.getInputStream().close();
170 | }
171 | } catch (IOException e) {
172 | e.printStackTrace();
173 | }
174 | mSerialPort.close();
175 | mSerialPort = null;
176 | }
177 | if (mOutputStream != null) {
178 | try {
179 | mOutputStream.close();
180 | } catch (IOException e) {
181 | e.printStackTrace();
182 | }
183 | }
184 | if (mBufferedInputStream != null) {
185 | try {
186 | mBufferedInputStream.close();
187 | } catch (IOException e) {
188 | e.printStackTrace();
189 | }
190 | }
191 | if (mSyncServicesProxy != null) {
192 | mSyncServicesProxy.close();
193 | mSyncServicesProxy = null;
194 | }
195 | if (mAsyncServicesProxy != null) {
196 | mAsyncServicesProxy.close();
197 | mAsyncServicesProxy = null;
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OkSerialPort
2 | ### OkSerialPort 一个灵活简单易用的串口通讯框架,基于谷歌API SerialPort 结合RxJava和基于注解 使用APT技术,支持485 232,让使用者无需在繁琐的组装数据,大大提升开发效率。
3 |
4 | ### OkSerialPort 1.0版本 由于时间问题,所以框架还是存在很多可以改进的地方,有任何问题或建议欢迎交流:QQ:877867730
5 | # 打算使用OkSerialPort前需要知道的:
6 | ### 目前1.0版本 协议开头为帧头 最后为校验位(目前校验码支持 异或和CRC16),不支持取消
7 |
8 | ### 帧头 ... 自由配置 ... 校验码
9 |
10 | ### 如果你的协议规则和这个有出入,不建议使用
11 |
12 | # 使用
13 | ### 准备工作
14 |
15 | ### 拷贝serialport-release.aar到app工程的lib文件夹(文件在项目app-lib目录有,可以直接下载)
16 |
17 | ### 添加依赖
18 |
19 | ```javascript
20 |
21 | defaultConfig {
22 |
23 | //因为框架使用了注解,所以需要加上这个,不加会报错
24 | javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }
25 | }
26 |
27 | repositories {
28 | flatDir { dirs 'libs' }
29 | maven { url 'https://jitpack.io' }
30 | }
31 |
32 | dependencies {
33 | /**因为框架异步使用的RxJava,所以需要先依赖RxJava,如果你的项目中已经依赖,就不需要在依赖RxJava了*/
34 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
35 | implementation 'io.reactivex.rxjava2:rxjava:2.1.14'
36 | implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
37 |
38 | /**串口*/
39 | implementation(name: 'serialport-release', ext: 'aar')
40 | /**主角 串口通讯框架*/
41 | implementation 'com.github.Jarvie-cn:OkSerialPort:1.1.5'
42 | }
43 | ```
44 | ### 到目前为止就已经准备就绪了,接下来可以开始使用框架了
45 |
46 | ### 根据自己的协议配置协议
47 | ### 示例协议图片:
48 | http://tiebapic.baidu.com/forum/pic/item/c96733d12f2eb938fc782b8bc2628535e5dd6f36.jpg
49 |
50 | ### 上面图片是示例协议规则,那么根据这份协议规则如何配置,直接看代码
51 | ### 注解字段说明:
52 | ###### @Protocol(index = 0, length = 1, value = (byte) 0x3B)
53 |
54 | ###### index = 协议字段的顺序位置从0开始(这个是必须传的)
55 | ###### length = 协议字段的字节长度(如果字节长度不固定的,就不传,比如数据)
56 | ###### value = byte类型 协议字段的数据值,有些相对固定的值可以直接填入,而不确定的就不需要,比如命令码,数据,流水号,校验码等,不填入的话默认会使用-1当占位符,在发送的时候!千万记住!!按顺序!!将实际数据进行填充替换掉占位符数据
57 | ###### 占位符数据填充替换的原理类似于数据库使用原理一样:
58 | ```javascript
59 | String aql = “select name =? form table” ;
60 | String[] args = new String[]{"张三"};
61 | db.execSQL(sql,args) ;
62 | ```
63 | ####### 这里提一点,该框架目前版本:数据,命令码,流水号,校验码这几字段value不传,发送数据时会自动填充数据,其他自定义字段如果value没有赋值都需要在发送时填充数据
64 |
65 | #### 继续往下看,如何根据自身的协议规则来配置协议
66 | ```javascript
67 |
68 | /** 按照协议顺序配置 这里注意一下帧头,不管你的协议规定帧头多少个字节都需要一个字节一个字节配置,后面在指定帧头位数*/
69 | /**
70 | * 帧头
71 | */
72 | @Protocol(index = 0, length = 1, value = (byte) 0x3B)
73 | public byte frameHeader ;
74 |
75 | @Protocol(index = 1, length = 1, value = (byte) 0xB3)
76 | public byte frameHeader2 ;
77 |
78 | /**
79 | * 原地址
80 | */
81 | @Protocol(index = 2, length = 1, value = (byte) 0x00)
82 | public int rawAddress;
83 |
84 |
85 | /**
86 | * 目标地址,示例协议里面目标地址每次发送命令都会不一样,所以 value就不传值,默认会先用-1当占位数据,在发送的时候
87 | *需要真实的目标地址数据进行填充
88 | *在强调一次,该框架目前版本:数据,命令码,流水号,校验码这几字段value不传,发送数据时会自动填充数据,其他自定义字段如果value没有赋值都需要在发送时填充数据
89 | */
90 | @Protocol(index = 3, length = 1)
91 | public int deviceAddress ;
92 |
93 | /**
94 | * 数据长度 这里注意,如果你也有这规则字段那么传值和我一样传,我这份协议协的数据长度是包含命令吗+版本协议+数据,
95 | * 等于是 1+1+n 前面两个字节长度是固定的所以传2,如果你是单数据的话那么传0
96 | *
97 | */
98 | @Protocol(index = 4, length = 1,value = 2)
99 | public int dateNumber;
100 |
101 |
102 | /**
103 | * 命令码
104 | */
105 | @Protocol(index = 5, length = 1)
106 | public int command ;
107 |
108 |
109 | /**
110 | * 协议版本
111 | */
112 | @Protocol(index = 6,length = 1, value = (byte) 0x10)
113 | public int dealVersions;
114 |
115 | /**
116 | * 数据
117 | */
118 | @Protocol(index = 7)
119 | public int data ;
120 |
121 | /**
122 | * 异或字节
123 | */
124 | @Protocol(index = 8, length = 1)
125 | public int OXR ;
126 |
127 |
128 | /** ---- end 按照文档协议配置结束 这部分根据自身协议自由配置 -----*/
129 |
130 | /** ----- 分割线 --------------*/
131 |
132 |
133 | /** ----- 下面这块注意!!,是必须要配置的 --------------*/
134 |
135 | /**
136 | * 读取数据长度这个字段字节开始位置角标从0开始,示例文档是在第5位,如果你的协议没有数据长度这个字段那么传-1
137 | */
138 | @Protocol(dataLenFirst = 4)
139 | public int dataLenStart;
140 |
141 | /**
142 | * 数据长度字段在你配置协议对应的角标位置(就是上面index的值) ,如果你的协议没有数据长度这个字段那么传-1
143 | */
144 | @Protocol(dataLenIndex = 4)
145 | public int dataLenIndex;
146 |
147 | /**
148 | * 读取数据这个字段开始字节位置,示例文档是第8位,如果你的协议没有数据这个字段那么传-1
149 | */
150 | @Protocol(dataFirst = 7)
151 | public int dataFirst ;
152 |
153 | /**
154 | * 读取命令码字节开始开始,例文档是第6位,如果你的协议没有这个字段那么传-1
155 | */
156 | @Protocol(commandFirst = 5)
157 | public int commandFirst ;
158 |
159 | /**
160 | * 命令码字段在你配置协议对应的角标位置(就是上面index的值),如果你的协议没有这个字段那么传-1
161 | */
162 | @Protocol(commandIndex = 5)
163 | public int commandIndex ;
164 |
165 | /**
166 | * 流水号起始位置 如果你的协议没有流水号这个字段那么传-1
167 | */
168 | @Protocol(runningNumberFirst = -1)
169 | public int runningNumberFirst ;
170 |
171 |
172 | /**
173 | * 帧头字节数
174 | */
175 | @Protocol(frameHeaderCount = 2)
176 | public static int frameHeaderCount;
177 | /**
178 | * 校验码规则 0表示异或校验 1表示CRC16校验
179 | */
180 | @Protocol(checkCodeRule = 0)
181 | public static int checkCodeRule;
182 |
183 |
184 | /**
185 | * 通信协议最短字节不包含数据域
186 | *比如示例的:(帧头(2字节) +源地址(1字节)+目标地址(1字节)+数据长度(1字节)+命令码(1字节)+数据(n字节)+异或校验(1字节))
187 | * 帧头 源地址 目标地址 数据长度 命令码 协议版本 数据 异或校验
188 | * 2个字节 1个字节 1个字节 1个字节 1个字节 1个字节 n个字节 1个字节
189 | */
190 | @Protocol(minDalaLen = 8)
191 | public static int minDalaLen;
192 |
193 | /** ----- end 分割线 --------------*/
194 |
195 | ```
196 |
197 | ### 如果你的是232有心跳主动上传的,那么添加配置心跳命令的方式有两种自行选择一种就行了:
198 | #### 1,注解的形式添加:
199 | ```javascript
200 | /** ----- 如果你的是232有心跳上传,可以添加N个 --------------*/
201 | /**
202 | * 心跳命令1
203 | */
204 | @Protocol(heartbeatCommand = (byte) 0x33)
205 | public int heartbeatCommand1;
206 | /**
207 | * 心跳命令2
208 | */
209 | @Protocol(heartbeatCommand = (byte) 0xB3)
210 | public int heartbeatCommand2;
211 | ```
212 | #### 2,在打开串口方法中传入心跳命令集合:
213 |
214 |
215 | ### 我们的协议规则已经配置完毕了,接下来进入下一步
216 |
217 | ### 绑定协议规则
218 | ```javascript
219 | OkSerialPort_Protocol.bind();
220 | ```
221 |
222 | #### OkSerialPort_Protocol这个API是编译后才生成的,绑定协议规则要放在使用串口之前
223 |
224 | ## 打开串口
225 | ```javascript
226 | /**使用建造者模式,灵活配置参数*/
227 | OkSerialport.getInstance().open(new SerialPortParams.Builder()
228 | .addDeviceAddress("串口地址")//默认/dev/ttyS0
229 | .addBaudRate(波特率)//默认115200
230 | .addHeartCommands(心跳命令集合)
231 | .isReconnect(是否自动重连)//默认false
232 | .callback(new SerialportConnectCallback() {
233 | @Override
234 | public void onError(ApiException apiException) {
235 |
236 | }
237 |
238 | @Override
239 | public void onOpenSerialPortSuccess() {
240 | Log.e("ljw", "onOpenSerialPortSuccess" );
241 |
242 | }
243 |
244 | @Override
245 | public void onHeatDataCallback(DataPack dataPack) {
246 | String command = ByteUtil.bytes2HexStr(dataPack.getCommand());
247 | Log.e("ljw", "心跳上来的命令:" + command + ",对应的数据 = " + ByteUtil.bytes2HexStr(dataPack.getData()));
248 | }
249 | })
250 | .build());
251 | ```
252 |
253 | ## 发送命令
254 | #### 所有字符串数据格式全部必须为16进制,字节数必须准确
255 | ```javascript
256 | /**
257 | * @param fillDatas 填充占位数据(在配置协议规则时value没有赋值的)位置顺序从小到大不能错!!没有则传null
258 | * @param data 数据
259 | * @param sendCommand 命令
260 | * @param sendResultCallback 发送回调
261 | */
262 | String[] fillDatas = new String[]{"00"};//00就是配置协议时目标地址的实际数据值
263 | OkSerialport.getInstance().send(fillDatas,"0003",命令码,new SendResultCallback() {
264 | @Override
265 | public void onStart(CmdPack cmdPack) {
266 |
267 | }
268 |
269 | @Override
270 | public void onSuccess(DataPack dataPack) {
271 | //这里是子线程,如果有刷新UI的动作,记得切换回UI线程
272 | Log.e("数据" +dataPack.getData() )
273 | }
274 |
275 | @Override
276 | public void onFailed(BaseSerialPortException dLCException) {
277 |
278 | }
279 | });
280 | ```
281 | ### 一些其他方法
282 | ```javascript
283 | //设置发送超时时间
284 | setmSendOutTime();
285 | //设置读取超时时间
286 | setmWaitOutTime();
287 | //关闭串口
288 | close();
289 | //打开调试日志
290 | OkSerialPortLog.isDebug = true;
291 | ```
292 |
--------------------------------------------------------------------------------
/bind-compiler/src/main/java/com/ljw/protocolcompiler/ProtocolProcessor.java:
--------------------------------------------------------------------------------
1 | package com.ljw.protocolcompiler;
2 |
3 | import com.ljw.protocol.Protocol;
4 | import com.google.auto.service.AutoService;
5 |
6 | import java.io.IOException;
7 | import java.io.Writer;
8 | import java.util.ArrayList;
9 | import java.util.HashMap;
10 | import java.util.Iterator;
11 | import java.util.LinkedHashSet;
12 | import java.util.List;
13 | import java.util.Map;
14 | import java.util.Set;
15 |
16 | import javax.annotation.processing.AbstractProcessor;
17 | import javax.annotation.processing.Filer;
18 | import javax.annotation.processing.Messager;
19 | import javax.annotation.processing.ProcessingEnvironment;
20 | import javax.annotation.processing.Processor;
21 | import javax.annotation.processing.RoundEnvironment;
22 | import javax.lang.model.SourceVersion;
23 | import javax.lang.model.element.Element;
24 | import javax.lang.model.element.TypeElement;
25 | import javax.lang.model.element.VariableElement;
26 | import javax.lang.model.type.TypeMirror;
27 | import javax.lang.model.util.Elements;
28 | import javax.tools.JavaFileObject;
29 |
30 | /**
31 | * Created by Administrator on 2018/2/11 0011.
32 | */
33 | @AutoService(Processor.class)
34 | public class ProtocolProcessor extends AbstractProcessor {
35 | private Filer mFiler;
36 | private Messager mMessager;
37 | private Elements mElementsUtil;
38 |
39 | private static final String SUFFIX = "LJWProtocol";
40 |
41 |
42 | @Override
43 | public synchronized void init(ProcessingEnvironment processingEnv) {
44 | super.init(processingEnv);
45 | mFiler = processingEnv.getFiler();
46 | mElementsUtil = processingEnv.getElementUtils();
47 | mMessager = processingEnv.getMessager();
48 |
49 | }
50 |
51 | /*
52 | * Element 的子类有以下4种
53 | * VariableElement //一般代表成员变量
54 | * ExecutableElement //一般代表类中的方法
55 | * TypeElement //一般代表代表类
56 | * PackageElement //一般代表Package
57 | * */
58 |
59 | @Override
60 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
61 | Set extends Element> elementSet = roundEnv.getElementsAnnotatedWith(Protocol.class);
62 | // 收集信息,分类
63 | Map> cacheMap = new HashMap<>();
64 | for (Element element : elementSet) {
65 | VariableElement variableElement = (VariableElement) element;
66 | String className = getClassName(variableElement);
67 | System.out.print("遍历元素中");
68 | List filedList = cacheMap.get(className);
69 | if (null == filedList) {
70 | filedList = new ArrayList<>();
71 | cacheMap.put(className, filedList);
72 | }
73 | filedList.add(variableElement);
74 | }
75 | // 产生java文件
76 | Iterator iterator = cacheMap.keySet().iterator();
77 | while (iterator.hasNext()) {
78 | // 准备好生成java文件产生的信息
79 | // 获取class的名字
80 | String className = iterator.next();
81 | // 获取class中的所有成员属性
82 | List cacheElements = cacheMap.get(className);
83 | // 获取包名
84 | String packageName = getPackageName(cacheElements.get(0));
85 | // String packageName = "com.ljw.okserialport";
86 | // 获取最后生成文件的文件名:className+"$"+SUFFIX
87 | String bindViewClass = "OkSerialPort_Protocol";
88 | // 生成额外的文件,x写文件流
89 | Writer writer = null;
90 | try {
91 | JavaFileObject javaFileObject = mFiler.createSourceFile(bindViewClass);
92 | // 拼接字符串
93 | writer = javaFileObject.openWriter();
94 | // 获取简短新代理类名称
95 | String sampleClass = cacheElements.get(0).getEnclosingElement().getSimpleName().toString();
96 | String sampleBindViewClass = sampleClass + "$" + SUFFIX;
97 | writer.write(generateJavaCode(packageName, sampleBindViewClass, className, cacheElements));
98 | System.out.print("write the file");
99 | writer.close();
100 |
101 | } catch (IOException e) {
102 | e.printStackTrace();
103 | }
104 |
105 | }
106 |
107 |
108 | return false;
109 | }
110 |
111 | public String generateJavaCode(String mPackageName, String mProxyClassName, String className, List cacheElements) {
112 | StringBuilder builder = new StringBuilder();
113 | builder.append("package " + mPackageName).append(";\n\n");
114 | // builder.append("import com.ljw.bind_api.*;\n");
115 | builder.append("import java.util.*;\n");
116 | builder.append("import com.ljw.okserialport.serialport.bean.ProtocolBean;\n");
117 | builder.append("import com.ljw.okserialport.serialport.core.OkSerialPort_ProtocolManager;\n");
118 | // builder.append("public class ").append("LJWProtocolImp").append(" implements " + SUFFIX + "<" + className + ">");
119 | builder.append("public class ").append("OkSerialPort_Protocol");
120 | builder.append("\n{\n");
121 | builder.append("public static Map mProtocolMap = new HashMap<>();\n");
122 | builder.append("public static List mHeartCommands = new ArrayList<>();\n");
123 | generateMethod(builder, className, cacheElements);
124 | generateMethod2(builder, className, cacheElements);
125 | builder.append("\n}\n");
126 | return builder.toString();
127 | }
128 |
129 | private void generateMethod(StringBuilder builder, String className, List cacheElements) {
130 | for (VariableElement element : cacheElements) {
131 | Protocol bindView = element.getAnnotation(Protocol.class);
132 | int index = bindView.index();
133 | if (index == -1) {
134 | int frameHeader = bindView.frameHeader();
135 | if (frameHeader != -1) {//帧头
136 | builder.append("public static int FRAMEHEADER = " + frameHeader + ";\n");
137 | }
138 | int frameHeader2 = bindView.frameHeader2();
139 | if (frameHeader2 != -1) {//帧头
140 | builder.append("public static int FRAMEHEADER2 = " + frameHeader2 + ";\n");
141 | }
142 | int androidAdress = bindView.androidAdress();
143 | if (androidAdress != -1) {//安卓地址
144 | builder.append("public static int ANDROIDADRESS = " + androidAdress + ";\n");
145 | }
146 | int hardwareAdress = bindView.hardwareAdress();
147 | if (hardwareAdress != -1) {//主控板地址
148 | builder.append("public static int HARDWAREADRESS = " + hardwareAdress + ";\n");
149 | }
150 | int dealVersions = bindView.dealVersions();
151 | if (dealVersions != -1) {//协议版本
152 | builder.append("public static int DEALVERSIONS = " + dealVersions + ";\n");
153 | }
154 |
155 | int dataLenFirst = bindView.dataLenFirst();
156 | if (dataLenFirst != Integer.MAX_VALUE) {//数据长度字节起始位置
157 | builder.append("public static int DATALENFIRST = " + dataLenFirst + ";\n");
158 | }
159 |
160 | int dataLenIndex = bindView.dataLenIndex();
161 | if (dataLenIndex != Integer.MAX_VALUE) {//数据长度起始角标
162 | builder.append("public static int DATALENINDEX = " + dataLenIndex + ";\n");
163 | }
164 |
165 | int dataFirst = bindView.dataFirst();
166 | if (dataFirst != Integer.MAX_VALUE) {//数据域起始角标
167 | builder.append("public static int DATAFIRST = " + dataFirst + ";\n");
168 | }
169 | int commandFirst = bindView.commandFirst();
170 | if (commandFirst != Integer.MAX_VALUE) {//命令码起始角标
171 | builder.append("public static int COMMANDFIRST = " + commandFirst + ";\n");
172 | }
173 | int runningNumberFirst = bindView.runningNumberFirst();
174 | if (runningNumberFirst != Integer.MAX_VALUE) {////流水号起始角标
175 | builder.append("public static int RUNNINGNUMBERFIRST = " + runningNumberFirst + ";\n");
176 | }
177 | int commandIndex = bindView.commandIndex();
178 | if (commandIndex != Integer.MAX_VALUE) {////流水号起始角标
179 | builder.append("public static int COMMANDINDEX = " + commandIndex + ";\n");
180 | }
181 | int frameHeaderCount = bindView.frameHeaderCount();
182 | if (frameHeaderCount != -1) {//帧头字节数
183 | builder.append("public static int FRAMEHEADERCOUNT = " + frameHeaderCount + ";\n");
184 | }
185 | int minDalaLen = bindView.minDalaLen();
186 | if (minDalaLen != -1) {//最小数据命令长度
187 | builder.append("public static int MINDALALEN = " + minDalaLen + ";\n");
188 | }
189 | int checkCodeRule = bindView.checkCodeRule();
190 | if (checkCodeRule != -1) {//最小数据命令长度
191 | builder.append("public static int CHECKCODERULE = " + checkCodeRule + ";\n");
192 | }
193 | int commandLen = bindView.commandLen();
194 | if (commandLen != -1) {
195 | builder.append("public static int COMMANDLEN = " + commandLen + ";\n");
196 | }
197 | int protocolLen = bindView.protocolLen();
198 | if (protocolLen != -1) {
199 | builder.append("public static int PROTOCOLLEN = " + protocolLen + ";\n");
200 | }
201 |
202 | }
203 |
204 |
205 | }
206 |
207 | builder.append("public static void bind(){");
208 | builder.append("\n");
209 | builder.append("OkSerialPort_ProtocolManager.getInstance().bind(COMMANDINDEX,DATALENINDEX,DATALENFIRST,DATAFIRST,COMMANDFIRST,RUNNINGNUMBERFIRST,FRAMEHEADERCOUNT,CHECKCODERULE,MINDALALEN,mProtocolMap,mHeartCommands);");
210 | builder.append("\n");
211 | builder.append("}\n");
212 |
213 | }
214 |
215 | private void generateMethod2(StringBuilder builder, String className, List cacheElements) {
216 | builder.append("static {\n");
217 | for (VariableElement element : cacheElements) {
218 | Protocol bindView = element.getAnnotation(Protocol.class);
219 | int index = bindView.index();
220 | int length = bindView.length();
221 | byte value = bindView.value();
222 | if (index != -1) {
223 | builder.append("mProtocolMap.put(" + index + ",new ProtocolBean(" + index + "," + length + ",(byte)" + value + "));\n");
224 |
225 | }
226 |
227 | }
228 | for (VariableElement element : cacheElements) {
229 | Protocol bindView = element.getAnnotation(Protocol.class);
230 | byte heartbeatCommand = bindView.heartbeatCommand();
231 | if (heartbeatCommand != -1) {
232 | builder.append("mHeartCommands.add(new byte[]{(byte)"+heartbeatCommand+"});\n");
233 | }
234 |
235 | }
236 |
237 | builder.append("\n }\n");
238 |
239 |
240 | }
241 |
242 | private String getPackageName(VariableElement variableElement) {
243 | TypeElement typeElement = (TypeElement) variableElement.getEnclosingElement();
244 | // String packeName = mElementsUtil.getPackageOf(typeElement).getQualifiedName().toString();
245 | String packeName = processingEnv.getElementUtils().getPackageOf(typeElement).getQualifiedName().toString();
246 | return packeName;
247 | }
248 |
249 | private String getClassName(VariableElement element) {
250 | String packageName = getPackageName(element);
251 | TypeElement typeElement = (TypeElement) element.getEnclosingElement();
252 | String className = typeElement.getSimpleName().toString();
253 | return packageName + "." + className;
254 | }
255 |
256 | @Override
257 | public Set getSupportedAnnotationTypes() {
258 | Set annotations = new LinkedHashSet<>();
259 | annotations.add(Protocol.class.getCanonicalName());
260 | return annotations;
261 | // return super.getSupportedAnnotationTypes();
262 | }
263 |
264 | @Override
265 | public SourceVersion getSupportedSourceVersion() {
266 | return SourceVersion.latestSupported();
267 | // return super.getSupportedSourceVersion();
268 | }
269 |
270 |
271 | }
272 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/utils/ByteUtil.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.utils;
2 |
3 | import java.math.BigInteger;
4 | import java.nio.charset.StandardCharsets;
5 |
6 | /**
7 | * @author : LJW
8 | * @date : 2019/11/22
9 | * @desc :
10 | */
11 | public class ByteUtil {
12 | /**
13 | * 字节数组转换成对应的16进制表示的字符串
14 | *
15 | * @param src
16 | * @return
17 | */
18 | public static String bytes2HexStr(byte[] src) {
19 | StringBuilder builder = new StringBuilder();
20 | if (src == null || src.length <= 0) {
21 | return "";
22 | }
23 | char[] buffer = new char[2];
24 | for (int i = 0; i < src.length; i++) {
25 | buffer[0] = Character.forDigit((src[i] >>> 4) & 0x0F, 16);
26 | buffer[1] = Character.forDigit(src[i] & 0x0F, 16);
27 | builder.append(buffer);
28 | }
29 | return builder.toString().toUpperCase();
30 | }
31 |
32 | /**
33 | * ASCII, 字符串,以空字符结束
34 | *
35 | * @param hex
36 | * @return
37 | */
38 | public static String convertHexToString(String hex) {
39 |
40 | StringBuilder sb = new StringBuilder();
41 | StringBuilder temp = new StringBuilder();
42 |
43 | // 49204c6f7665204a617661 split into two characters 49, 20, 4c...
44 | for (int i = 0; i < hex.length() - 1; i += 2) {
45 |
46 | // grab the hex in pairs
47 | String output = hex.substring(i, (i + 2));
48 | // convert hex to decimal
49 | int decimal = Integer.parseInt(output, 16);
50 | // convert the decimal to character
51 | sb.append((char) decimal);
52 |
53 | temp.append(decimal);
54 | }
55 |
56 | return sb.toString();
57 | }
58 |
59 |
60 | /**
61 | * 字节数组(高位在前)转换成对应的非负整数
62 | *
63 | * @param ori 需要转换的字节数组
64 | * @param offset 目标位置偏移
65 | * @param len 目标数组长度
66 | * @return
67 | */
68 | public static int bytes2long(byte[] ori, int offset, int len) {
69 | int result = 0;
70 | for (int i = 0; i < len; i++) {
71 | result = result | ((0xff & ori[offset + i]) << (len - 1 - i) * 8);
72 | }
73 | return result;
74 | }
75 |
76 | /**
77 | * int转换为ASCII, 字符串,不够位数以空字符开头
78 | *
79 | * @param value
80 | * @param length 长度2 SLEN
81 | * @return
82 | */
83 | public static String convertStringAsciiToHex(int value, int length) {
84 |
85 | StringBuilder sb = new StringBuilder();
86 | StringBuilder temp = new StringBuilder();
87 | String strValue = value + "";
88 | for (int i = 0; i < strValue.length(); i++) {
89 | int ch = strValue.charAt(i);
90 | sb.append(Integer.toHexString(ch));
91 | }
92 | int result = length - strValue.length();
93 | if (result > 0) {
94 | for (int i = 0; i < result; i++) {
95 | //空字符串的ascii为32
96 | temp.append(Integer.toHexString(32));
97 | }
98 | }
99 | temp.append(sb.toString());
100 | return temp.toString();
101 |
102 | }
103 |
104 |
105 |
106 |
107 | /**
108 | * int类型转成高位在前的字节数组
109 | *
110 | * @param ori
111 | * @param arrayAmount 字节数组长度
112 | * @return
113 | */
114 | public static byte[] long2bytes(long ori, byte[] targetBytes, int offset, int arrayAmount) {
115 | for (int i = 0; i < arrayAmount; i++) {
116 | // 高位在前
117 | targetBytes[offset + i] = (byte) ((ori >>> (arrayAmount - i - 1) * 8) & 0xff);
118 | }
119 | return targetBytes;
120 | }
121 |
122 | /**
123 | * 十六进制字节数组转字符串
124 | *
125 | * @param src 目标数组
126 | * @param dec 起始位置8
127 | * @param length 长度2 SLEN
128 | * @return
129 | */
130 | public static String bytes2HexStr(byte[] src, int dec, int length) {
131 | byte[] temp = new byte[length];
132 | System.arraycopy(src, dec, temp, 0, length);
133 | return bytes2HexStr(temp);
134 | }
135 |
136 | /**
137 | * 获取十六进制字节数组
138 | *
139 | * @param src 目标数组
140 | * @param dec 起始位置8
141 | * @param length 长度2 SLEN
142 | * @return
143 | */
144 | public static byte[] getBytes(byte[] src, int dec, int length) {
145 | byte[] temp = new byte[length];
146 | System.arraycopy(src, dec, temp, 0, length);
147 | return temp;
148 | }
149 |
150 |
151 | /*
152 | 计算有误
153 | */
154 | @Deprecated
155 | public static float byte2Float(byte[] b) {
156 | int accum = 0;
157 | accum = accum | (b[0] & 0xff) << 0;
158 | accum = accum | (b[1] & 0xff) << 8;
159 | accum = accum | (b[2] & 0xff) << 16;
160 | accum = accum | (b[3] & 0xff) << 24;
161 | return Float.intBitsToFloat(accum);
162 | }
163 |
164 |
165 | /**
166 | * 16 进制转float (可能有小数的情况)
167 | */
168 | public static float hexStr2Float(String hexStr) {
169 | return Float.intBitsToFloat(new BigInteger(hexStr, 16).intValue());
170 | }
171 |
172 | /**
173 | * 16 进制转float (可能有小数的情况)
174 | */
175 | public static float hexStr2Float(byte[] b) {
176 | String hexStr = bytes2HexStr(b);
177 |
178 | return Float.intBitsToFloat(new BigInteger(hexStr, 16).intValue());
179 | }
180 |
181 | public static String formatBytes(byte[] b) {
182 | StringBuilder builder = new StringBuilder();
183 | for (byte item : b) {
184 | String hex = Integer.toHexString(item & 0xFF);
185 | if (hex.length() == 1) {
186 | hex = '0' + hex;
187 | }
188 | builder.append(hex.toUpperCase());
189 | builder.append(" ");
190 | }
191 | return builder.toString();
192 | }
193 |
194 | public static int byteToInt(byte[] b) {
195 | int mask = 0xff;
196 | int temp;
197 | int n = 0;
198 | for (int i = 0; i < b.length; i++) {
199 | n <<= 8;
200 | temp = b[i] & mask;
201 | n |= temp;
202 | }
203 | return n;
204 | }
205 |
206 | /**
207 | * 把十六进制表示的字节数组字符串,转换成十六进制字节数组
208 | *
209 | * @param
210 | * @return byte[]
211 | */
212 | public static byte[] hexStr2bytes(String hex) {
213 | int len = (hex.length() / 2);
214 | byte[] result = new byte[len];
215 | char[] achar = hex.toUpperCase().toCharArray();
216 | for (int i = 0; i < len; i++) {
217 | int pos = i * 2;
218 | result[i] = (byte) (hexChar2byte(achar[pos]) << 4 | hexChar2byte(achar[pos + 1]));
219 | }
220 | return result;
221 | }
222 |
223 | /**
224 | * 把16进制字符[0123456789abcde](含大小写)转成字节
225 | *
226 | * @param c
227 | * @return
228 | */
229 | private static int hexChar2byte(char c) {
230 | switch (c) {
231 | case '0':
232 | return 0;
233 | case '1':
234 | return 1;
235 | case '2':
236 | return 2;
237 | case '3':
238 | return 3;
239 | case '4':
240 | return 4;
241 | case '5':
242 | return 5;
243 | case '6':
244 | return 6;
245 | case '7':
246 | return 7;
247 | case '8':
248 | return 8;
249 | case '9':
250 | return 9;
251 | case 'a':
252 | case 'A':
253 | return 10;
254 | case 'b':
255 | case 'B':
256 | return 11;
257 | case 'c':
258 | case 'C':
259 | return 12;
260 | case 'd':
261 | case 'D':
262 | return 13;
263 | case 'e':
264 | case 'E':
265 | return 14;
266 | case 'f':
267 | case 'F':
268 | return 15;
269 | default:
270 | return -1;
271 | }
272 | }
273 |
274 | /**
275 | * 把十进制数字转换成足位的十六进制字符串,并补全空位
276 | *
277 | * @param num
278 | * @return
279 | */
280 | public static String integer2HexStr(int num) {
281 | return integer2HexStr(num, 2);
282 | }
283 |
284 | /**
285 | * 把十进制数字转换成足位的十六进制字符串,并补全空位
286 | *
287 | * @param num
288 | * @param strLength 字符串的长度
289 | * @return
290 | */
291 | public static String integer2HexStr(int num, int strLength) {
292 | String hexStr = Integer.toHexString(num).toUpperCase();
293 | StringBuilder stringBuilder = new StringBuilder(hexStr);
294 | while (stringBuilder.length() < strLength) {
295 | stringBuilder.insert(0, '0');
296 | }
297 | return stringBuilder.toString();
298 | }
299 |
300 | public static String hexStr2decimalStr(String hex) {
301 | return new BigInteger(hex, 16).toString(10);
302 | }
303 |
304 | private final static String hexStr = "0123456789ABCDEF";
305 | private final static String[] binaryArray =
306 | {"0000", "0001", "0010", "0011",
307 | "0100", "0101", "0110", "0111",
308 | "1000", "1001", "1010", "1011",
309 | "1100", "1101", "1110", "1111"};
310 |
311 | /**
312 | * @param hexString
313 | * @return 将十六进制转换为二进制字节数组 16-2
314 | */
315 | public static String hexStr2BitArr(String hexString) {
316 | //hexString的长度对2取整,作为bytes的长度
317 | int len = hexString.length() / 2;
318 | byte[] bytes = new byte[len];
319 | //字节高四位
320 | byte high = 0;
321 | //字节低四位
322 | byte low = 0;
323 | for (int i = 0; i < len; i++) {
324 | //右移四位得到高位
325 | high = (byte) ((hexStr.indexOf(hexString.charAt(2 * i))) << 4);
326 | low = (byte) hexStr.indexOf(hexString.charAt(2 * i + 1));
327 | //高地位做或运算
328 | bytes[i] = (byte) (high | low);
329 | }
330 | return bytes2BinStr(bytes);
331 | }
332 |
333 | public static int convertToDecimal(String binary) {
334 | return Integer.valueOf(binary, 2);
335 | }
336 |
337 |
338 | /**
339 | * @param
340 | * @return 二进制数组转换为二进制字符串 2-2
341 | */
342 | public static String bytes2BinStr(byte[] bArray) {
343 |
344 | StringBuilder outStr = new StringBuilder();
345 | int pos = 0;
346 | for (byte b : bArray) {
347 | //高四位
348 | pos = (b & 0xF0) >> 4;
349 | outStr.append(binaryArray[pos]);
350 | //低四位
351 | pos = b & 0x0F;
352 | outStr.append(binaryArray[pos]);
353 | }
354 | return outStr.toString();
355 | }
356 |
357 | /**
358 | * 16进制转2进制
359 | */
360 | public static String hexStringToByte(int strLength, String hex) {
361 | int i = Integer.parseInt(hex, 16);
362 | String str2 = Integer.toBinaryString(i);
363 | StringBuilder stringBuilder = new StringBuilder(str2);
364 | while (stringBuilder.length() < strLength) {
365 | stringBuilder.insert(0, '0');
366 | }
367 | return stringBuilder.toString();
368 | }
369 |
370 |
371 | public static String bytesToHexString(byte[] src) {
372 | StringBuilder stringBuilder = new StringBuilder();
373 | if (src == null || src.length <= 0) {
374 | return null;
375 | }
376 | for (int i = 0; i < src.length; i++) {
377 | int v = src[i] & 0xFF;
378 | String hv = Integer.toHexString(v);
379 |
380 | stringBuilder.append(i).append(":");
381 |
382 | if (hv.length() < 2) {
383 | stringBuilder.append(0);
384 | }
385 | stringBuilder.append(hv).append(";");
386 | }
387 | return stringBuilder.toString();
388 | }
389 |
390 | /**
391 | * 转16进制字符串
392 | *
393 | * @param str
394 | * @return
395 | */
396 | public static String hexString(String str, int length) {
397 | StringBuilder ret = new StringBuilder();
398 | byte[] b;
399 | b = str.getBytes(StandardCharsets.UTF_8);
400 | for (int i = b.length - 1; i >= 0; i--) {
401 | String hex = Integer.toHexString(b[i] & 0xFF);
402 | if (hex.length() == 1) {
403 | hex = '0' + hex;
404 | }
405 | ret.append(hex.toUpperCase());
406 | }
407 | while (ret.length() < length) {
408 | ret.insert(0, "0");
409 | }
410 | return ret.toString();
411 | }
412 |
413 | /**
414 | * 把十进制数字转换成足位的十六进制字符串,并补全空位
415 | *
416 | * @param num
417 | * @return
418 | */
419 | public static String decimal2fitHex(long num) {
420 | String hex = Long.toHexString(num).toUpperCase();
421 | if (hex.length() % 2 != 0) {
422 | return "0" + hex;
423 | }
424 | return hex.toUpperCase();
425 | }
426 |
427 | /**
428 | * 把十进制数字转换成足位的十六进制字符串,并补全空位
429 | *
430 | * @param num
431 | * @param strLength 字符串的长度
432 | * @return
433 | */
434 | public static String decimal2fitHex(long num, int strLength) {
435 | String hexStr = Long.toHexString(num).toUpperCase();
436 | StringBuilder stringBuilder = new StringBuilder(hexStr);
437 | while (stringBuilder.length() < strLength) {
438 | stringBuilder.insert(0, '0');
439 | }
440 | return stringBuilder.toString();
441 | }
442 |
443 | /**
444 | * @param hexString
445 | * @return 将十六进制转换为二进制字节数组 16-2
446 | */
447 | public static String hexStr2BinArr(String hexString) {
448 | //hexString的长度对2取整,作为bytes的长度
449 | int len = hexString.length() / 2;
450 | byte[] bytes = new byte[len];
451 | //字节高四位
452 | byte high = 0;
453 | //字节低四位
454 | byte low = 0;
455 | for (int i = 0; i < len; i++) {
456 | //右移四位得到高位
457 | high = (byte) ((hexStr.indexOf(hexString.charAt(2 * i))) << 4);
458 | low = (byte) hexStr.indexOf(hexString.charAt(2 * i + 1));
459 | //高地位做或运算
460 | bytes[i] = (byte) (high | low);
461 | }
462 | return bytes2BinStr(bytes);
463 | //return new BigInteger(1, bytes).toString(2);// 这里的1代表正数
464 | }
465 | }
466 |
--------------------------------------------------------------------------------
/okserialport/src/main/java/com/ljw/okserialport/serialport/proxy/AsyncServicesProxy.java:
--------------------------------------------------------------------------------
1 | package com.ljw.okserialport.serialport.proxy;
2 |
3 |
4 | import android.os.HandlerThread;
5 | import android.os.SystemClock;
6 | import android.text.TextUtils;
7 |
8 | import com.ljw.okserialport.serialport.bean.CmdBean;
9 | import com.ljw.okserialport.serialport.bean.DataPack;
10 | import com.ljw.okserialport.serialport.callback.BaseDataCallback;
11 | import com.ljw.okserialport.serialport.callback.SendResultCallback;
12 | import com.ljw.okserialport.serialport.callback.SerialReadCallback;
13 | import com.ljw.okserialport.serialport.utils.ApiExceptionCode;
14 | import com.ljw.okserialport.serialport.utils.BaseSerialPortException;
15 | import com.ljw.okserialport.serialport.utils.ByteUtil;
16 | import com.ljw.okserialport.serialport.utils.CmdPack;
17 | import com.ljw.okserialport.serialport.utils.OkSerialPortLog;
18 | import com.ljw.okserialport.serialport.utils.ReadMessage;
19 | import com.ljw.okserialport.serialport.utils.ReadType;
20 |
21 | import java.io.BufferedInputStream;
22 | import java.io.IOException;
23 | import java.io.OutputStream;
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | import io.reactivex.Observable;
28 | import io.reactivex.ObservableEmitter;
29 | import io.reactivex.ObservableOnSubscribe;
30 | import io.reactivex.Observer;
31 | import io.reactivex.Scheduler;
32 | import io.reactivex.android.schedulers.AndroidSchedulers;
33 | import io.reactivex.disposables.Disposable;
34 |
35 |
36 | /**
37 | * @author : LJW
38 | * @date : 2019/11/22
39 | * @desc :
40 | */
41 | public class AsyncServicesProxy {
42 | private boolean isStart = false;
43 | private BaseDataCallback mBaseDataCallback;
44 | private OutputStream mOutputStream;
45 | private BufferedInputStream mBufferedInputStream;
46 | private SerialReadThread mReadThread;
47 | private HandlerThread mWriteThread;
48 | private Scheduler mSendScheduler;
49 | private boolean isActivelyReceivedCommand;
50 | private List mHeartCommand;
51 | private List mList = new ArrayList<>();
52 |
53 | public AsyncServicesProxy(String name, boolean isActivelyReceivedCommand, List heartCommand, OutputStream outputStream,
54 | BufferedInputStream bufferedInputStream, BaseDataCallback baseDataCallback) {
55 | mBaseDataCallback = baseDataCallback;
56 | mOutputStream = outputStream;
57 | mBufferedInputStream = bufferedInputStream;
58 | mHeartCommand = heartCommand;
59 | this.isActivelyReceivedCommand = isActivelyReceivedCommand;
60 | startTask(name);
61 | }
62 |
63 | public AsyncServicesProxy(boolean isActivelyReceivedCommand, List heartCommand, OutputStream outputStream,
64 | BufferedInputStream bufferedInputStream, BaseDataCallback baseDataCallback) {
65 | mBaseDataCallback = baseDataCallback;
66 | mOutputStream = outputStream;
67 | mBufferedInputStream = bufferedInputStream;
68 | mHeartCommand = heartCommand;
69 | this.isActivelyReceivedCommand = isActivelyReceivedCommand;
70 | OkSerialPortLog.e( "是否开启了心跳:" + isActivelyReceivedCommand );
71 | startTask("");
72 | }
73 |
74 | public void startTask(String name) {
75 | if (mReadThread == null) {
76 | mReadThread =
77 | new SerialReadThread(isActivelyReceivedCommand, mHeartCommand, mBufferedInputStream, mBaseDataCallback, new SerialReadCallback() {
78 | @Override
79 | public void onReadMessage(ReadMessage readMessage) {
80 | // handleReadMessage(readMessage);
81 | onRead(readMessage);
82 | }
83 | });
84 | }
85 | if (mWriteThread == null) {
86 | if (TextUtils.isEmpty(name)) {
87 | name = "async-services-thread";
88 | }
89 | mWriteThread = new HandlerThread(name);
90 | }
91 | mWriteThread.start();
92 | if (mSendScheduler == null) {
93 | mSendScheduler = AndroidSchedulers.from(mWriteThread.getLooper());
94 | }
95 | if (!isStart) {
96 | mReadThread.start();
97 | isStart = true;
98 | }
99 | }
100 |
101 | /**
102 | * 停止当前任务,释放线程
103 | */
104 | public void stopTask() {
105 | if (isStart) {
106 | if (mReadThread != null) {
107 | mReadThread.close();
108 | }
109 | if (mWriteThread != null) {
110 | mWriteThread.quit();
111 | }
112 | isStart = false;
113 | }
114 | }
115 |
116 | private Disposable mDisposable, mReadDisposable;
117 |
118 | public void send(CmdPack cmdPack, SendResultCallback sendResultCallback) {
119 |
120 | long time = System.currentTimeMillis();
121 | // LogPlus.e("cmdPackTime=" + time + ",cmd=" + cmdPack.getDestinationAddress());
122 | // LogPlus.e("list 添加任务:" + cmdPack.getStrSendData() + "list.size():" + mList.size());
123 |
124 | if (mCmdBean != null) {
125 | synchronized (mList) {
126 | mList.add(new CmdBean(cmdPack, sendResultCallback, time + "", 0));
127 | }
128 | checkSendData();
129 | return;
130 | }
131 | mCmdBean = new CmdBean(cmdPack, sendResultCallback, time + "", 0);
132 | synchronized (mList) {
133 | mList.add(mCmdBean);
134 | }
135 | dispose();
136 | rxSendData().subscribeOn(mSendScheduler).subscribe(new Observer() {
137 | @Override
138 | public void onSubscribe(Disposable d) {
139 | mDisposable = d;
140 | //SerialPortLoggerFactory.info("发送数据+Disposable:" + d.isDisposed());
141 | }
142 |
143 | @Override
144 | public void onNext(CmdBean cmdBean) {
145 | //mCmdBean = cmdBean;
146 | // LogPlus.e("发送数据:" + ByteUtil.bytes2HexStr(cmdBean.getCmdPack().getSendData()));
147 | }
148 |
149 | @Override
150 | public void onError(Throwable e) {
151 | // Log.e("发送失败", e.toString());
152 | }
153 |
154 | @Override
155 | public void onComplete() {
156 |
157 | }
158 | });
159 | }
160 |
161 | private CmdBean mCmdBean;
162 |
163 | /**
164 | * (rx包裹)发送数据
165 | *
166 | * @return
167 | */
168 | private Observable rxSendData() {
169 | return Observable.create(new ObservableOnSubscribe() {
170 | @Override
171 | public void subscribe(ObservableEmitter emitter) throws Exception {
172 | try {
173 | if (mCmdBean != null) {
174 | if (mCmdBean.getSendResultCallback() != null) {
175 | mCmdBean.getSendResultCallback().onStart(mCmdBean.getCmdPack());
176 | }
177 | SystemClock.sleep(100);
178 | mOutputStream.write(mCmdBean.getCmdPack().getSendData());
179 | long time = System.currentTimeMillis();
180 | mCmdBean.setTime(time);
181 | emitter.onNext(mCmdBean);
182 | if (mCmdBean.getCmdPack().getCheckCommand() == null || mCmdBean.getCmdPack().getCheckCommand().size() == 0) {
183 | mCmdBean = null;
184 | removeCmdBean();
185 | nextSend();
186 | }
187 | }
188 | } catch (Exception e) {
189 | if (mCmdBean != null) {
190 | // LogPlus.e("发送:" + ByteUtil.bytes2HexStr(mCmdBean.getCmdPack().getSendData()) + " 失败," + e.toString());
191 | if (mCmdBean.getSendResultCallback() != null) {
192 | mCmdBean.getSendResultCallback()
193 | .onFailed(new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_ERROR, "硬件错误:" + e.toString(),
194 | mCmdBean.getCmdPack().getDestinationAddress()));
195 | }
196 | removeCmdBean();
197 | mCmdBean = null;
198 | nextSend();
199 | }
200 | if (!emitter.isDisposed()) {
201 | emitter.onError(e);
202 | return;
203 | }
204 | }
205 | emitter.onComplete();
206 | }
207 | });
208 | }
209 |
210 | /**
211 | * (rx包裹)发送数据
212 | *
213 | * @return
214 | */
215 | private Observable rxReadData(final ReadMessage readMessage) {
216 | return Observable.create(new ObservableOnSubscribe() {
217 | @Override
218 | public void subscribe(ObservableEmitter emitter) throws Exception {
219 | emitter.onNext(readMessage);
220 | emitter.onComplete();
221 | }
222 | });
223 | }
224 |
225 | private void removeCmdBean() {
226 | synchronized (mList) {
227 | if (mList.size() > 0) {
228 | // LogPlus.e("removeCmdBean :list.size:" + mList.size());
229 | mList.remove(0);
230 | }
231 | }
232 | }
233 |
234 | /**
235 | * 下一个数据发送
236 | */
237 | private synchronized void nextSend() {
238 | if (mList.size() == 0) {
239 | return;
240 | }
241 | //防止并发问题
242 | if (mCmdBean != null) {
243 | // LogPlus.e("防止并发问题,直接return");
244 | return;
245 | }
246 | mCmdBean = mList.get(0);
247 | dispose();
248 | rxSendData().subscribeOn(mSendScheduler).subscribe(new Observer() {
249 | @Override
250 | public void onSubscribe(Disposable d) {
251 | mDisposable = d;
252 | // SerialPortLoggerFactory.info("发送数据+Disposable:" + d.isDisposed());
253 | }
254 |
255 | @Override
256 | public void onNext(CmdBean cmdBean) {
257 | // LogPlus.e("发送码:" + ByteUtil.bytes2HexStr(cmdBean.getCmdPack().getSendData()));
258 | }
259 |
260 | @Override
261 | public void onError(Throwable e) {
262 | // Log.e("发送失败", e.toString());
263 | }
264 |
265 | @Override
266 | public void onComplete() {
267 |
268 | }
269 | });
270 | }
271 |
272 | /**
273 | * 处理数据
274 | */
275 | private synchronized void handleReadMessage(ReadMessage readMessage) {
276 | if (readMessage == null) {
277 | return;
278 | }
279 | disposeRead();
280 | rxReadData(readMessage).subscribeOn(mSendScheduler).subscribe(new Observer() {
281 | @Override
282 | public void onSubscribe(Disposable d) {
283 | mReadDisposable = d;
284 | // SerialPortLoggerFactory.info("发送数据+Disposable:" + d.isDisposed());
285 | }
286 |
287 | @Override
288 | public void onNext(ReadMessage cmdBean) {
289 | onRead(cmdBean);
290 | }
291 |
292 | @Override
293 | public void onError(Throwable e) {
294 | // Log.e("发送失败", e.toString());
295 | }
296 |
297 | @Override
298 | public void onComplete() {
299 |
300 | }
301 | });
302 | }
303 |
304 | private void dispose() {
305 | if (mDisposable != null && !mDisposable.isDisposed()) {
306 | mDisposable.dispose();
307 | // LogPlus.e("发送数据+Disposable释放");
308 | }
309 | mDisposable = null;
310 | }
311 |
312 | private void disposeRead() {
313 | if (mReadDisposable != null && !mReadDisposable.isDisposed()) {
314 | mReadDisposable.dispose();
315 | // LogPlus.e("接收数据+Disposable释放");
316 | }
317 | mReadDisposable = null;
318 | }
319 |
320 | /**
321 | * 关闭串口
322 | */
323 | public void close() {
324 | dispose();
325 | disposeRead();
326 | if (mOutputStream != null) {
327 | try {
328 | mOutputStream.close();
329 | } catch (IOException e) {
330 | e.printStackTrace();
331 | }
332 | }
333 | if (mBufferedInputStream != null) {
334 | try {
335 | mBufferedInputStream.close();
336 | } catch (IOException e) {
337 | e.printStackTrace();
338 | }
339 | }
340 | if (mReadThread != null) {
341 | mReadThread.close();
342 | }
343 | if (mWriteThread != null) {
344 | mWriteThread.quit();
345 | }
346 | }
347 |
348 | public void onRead(ReadMessage message) {
349 |
350 | if (message != null) {
351 | switch (message.getReadType()) {
352 | case ReadType.CheckSendData:
353 | checkSendData();
354 | break;
355 | case ReadType.ReadDataSuccess:
356 | if (message.getDataPack() != null) {
357 | checkReadDataSuccess(message.getDataPack());
358 | }
359 | break;
360 | default:
361 | }
362 | }
363 | }
364 |
365 | /**
366 | * 校验成功数据
367 | */
368 | private void checkReadDataSuccess(DataPack dataPack) {
369 | if (mCmdBean == null) {
370 | nextSend();
371 | return;
372 | }
373 | String readCommand = ByteUtil.bytes2HexStr(dataPack.getCommand());
374 | if (mCmdBean != null) {
375 | boolean isRemove = false;
376 | boolean isOnSuccess = false;
377 | List list = null;
378 | if (mCmdBean.getCmdPack() != null && mCmdBean.getCmdPack().getCheckCommand() != null) {
379 | list = mCmdBean.getCmdPack().getCheckCommand();
380 | for (int i = 0; i < list.size(); i++) {
381 | String command = ByteUtil.bytes2HexStr(list.get(i));
382 | if (TextUtils.equals(command, readCommand)) {
383 | isOnSuccess = true;
384 | if (i == list.size() - 1) {
385 | isRemove = true;
386 | }
387 | break;
388 | }
389 | if (i == list.size() - 1) {
390 | isRemove = true;
391 | }
392 | }
393 | }
394 | if (isOnSuccess) {
395 | if (mCmdBean.getSendResultCallback() != null) {
396 | mCmdBean.getSendResultCallback().onSuccess(dataPack);
397 | }
398 | }
399 | if (isRemove) {
400 | removeCmdBean();
401 | mCmdBean = null;
402 | nextSend();
403 | }
404 | }
405 | }
406 |
407 | /**
408 | * 校验发送数据
409 | */
410 | private void checkSendData() {
411 | if (mCmdBean == null) {
412 | nextSend();
413 | return;
414 | }
415 | if (mCmdBean.getTime() == 0) {
416 | return;
417 | }
418 | if (Math.abs(System.currentTimeMillis() - mCmdBean.getTime()) >= mCmdBean.getCmdPack().getSendOutTime()) {
419 | if (mCmdBean.getSendResultCallback() != null) {
420 | mCmdBean.getSendResultCallback()
421 | .onFailed(new BaseSerialPortException(ApiExceptionCode.SERIAL_PORT_READ_OUT_TIME_ERROR, "读取超时",
422 | mCmdBean.getCmdPack().getDestinationAddress()));
423 | }
424 | mCmdBean = null;
425 | removeCmdBean();
426 | nextSend();
427 | }
428 | }
429 | }
430 |
--------------------------------------------------------------------------------