desc:移植串口通信Lib

main
xiaowusky 2 years ago
parent c69ec99c44
commit f3a207b7a9

@ -1,6 +1,4 @@
apply from: "${rootProject.rootDir}/buildCommon/commonLibConfig.gradle"
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
repositories { repositories {
google() google()
@ -8,7 +6,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.1.2' classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
} }

@ -0,0 +1,159 @@
project.ext {
sign = [
keystore_path : "../signature/innovationapp.jks",
keystore_pwd : "123456",
keystore_alias: "yinuo"
]
compileOptions = [
sourceCompatibility: JavaVersion.VERSION_1_8,
targetCompatibility: JavaVersion.VERSION_1_8,
]
versions = [
compileSdkVersion : 31,
buildToolsVersion : "33.0.3",
minSdkVersion : 23,
targetSdkVersion : 28,
versionCode : 1,
versionName : "1.0",
jvmTarget : "1.8",
appcompat : "1.2.0",
material : "1.2.1",
okhttp : "4.9.1",
retrofit : "2.9.0",
rxjava : "3.0.13",
rxandroid : "3.0.0",
kotlin : "1.5.10",
kotlin_android : "1.5.0",
converter_gson : '2.9.0',
retrofit_rxjava : "2.9.0",
room : "2.3.0",
jxl : "2.6.12",
navigation_fragment_ktx: "2.3.0",
navigation_ui_ktx : "2.3.0",
glide : "4.12.0",
photo_view : "2.3.0",
luban : "1.1.8",
gson : "2.8.6",
arouter : "1.5.2",
mmkv : "1.2.10",
okhttp_logger : "3.12.7",
lifecycle_process : "2.3.1",
]
dependencies = [
okhttp : "com.squareup.okhttp3:okhttp:${versions.okhttp}",
retrofit : "com.squareup.retrofit2:retrofit:${versions.retrofit}",
rxjava : "io.reactivex.rxjava3:rxjava:${versions.rxjava}",
rxandroid : "io.reactivex.rxjava3:rxandroid:${versions.rxandroid}",
okhttp_logger : "com.squareup.okhttp3:logging-interceptor:${versions.okhttp_logger}",
kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}",
kotlin_android : "org.jetbrains.kotlinx:kotlinx-coroutines-android:${versions.kotlin_android}",
converter_gson : "com.squareup.retrofit2:converter-gson:${versions.converter_gson}",
retrofit_rxjava : "com.squareup.retrofit2:adapter-rxjava3:${versions.retrofit_rxjava}",
room : "androidx.room:room-runtime:${versions.room}",
room_compiler : "androidx.room:room-compiler:${versions.room}",
room_ktx : "androidx.room:room-ktx:${versions.room}",
room_rxjava : "androidx.room:room-rxjava3:${versions.room}",
jxl : "net.sourceforge.jexcelapi:jxl:${versions.jxl}",
navigation_fragment_ktx: "androidx.navigation:navigation-fragment-ktx:${versions.navigation_fragment_ktx}",
navigation_ui_ktx : "androidx.navigation:navigation-ui-ktx:${versions.navigation_ui_ktx}",
navigation_arg : "androidx.navigation:navigation-safe-args-gradle-plugin:${versions.navigation_ui_ktx}",
glide : "com.github.bumptech.glide:glide:${versions.glide}",
gilde_integration : "com.github.bumptech.glide:okhttp3-integration:${versions.glide}",
annotationProcessor : "com.github.bumptech.glide:compiler:${versions.glide}",
photo_view : "com.github.chrisbanes:PhotoView:${versions.photo_view}",
luban : "top.zibin:Luban:${versions.luban}",
gson : "com.google.code.gson:gson:${versions.gson}",
arouter : "com.alibaba:arouter-api:${versions.arouter}",
arouter_compiler : "com.alibaba:arouter-compiler:${versions.arouter}",
mmkv : "com.tencent:mmkv-static:${versions.mmkv}",
lifecycle_process : "androidx.lifecycle:lifecycle-process:${versions.lifecycle_process}",
]
/**
* android project android {} default config
*/
setAndroidConfig = {
extension ->
extension.compileSdkVersion versions.compileSdkVersion
extension.defaultConfig {
minSdkVersion versions.minSdkVersion
targetSdkVersion versions.targetSdkVersion
versionCode versions.versionCode
versionName versions.vserionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
extension.compileOptions {
targetCompatibility = compileOptions.targetCompatibility
sourceCompatibility = compileOptions.sourceCompatibility
}
extension.kotlinOptions {
jvmTarget = versions.jvmTarget
}
}
/**
* android project dependencies {} default config
*/
setDependencies = {
extension ->
extension.implementation fileTree(include: ['*.jar'], dir: 'libs')
}
/**
* android library config
*/
setLibDefaultConfig = {
extension ->
extension.apply plugin: 'com.android.library'
extension.apply plugin: 'kotlin-android'
extension.apply plugin: 'kotlin-parcelize'
extension.apply plugin: 'kotlin-kapt'
extension.description "lib"
setAndroidConfig extension.android
setDependencies extension.dependencies
}
/**
* android application config
*/
setAppDefaultConfig = {
extension ->
extension.apply plugin: 'com.android.application'
extension.apply plugin: 'kotlin-android'
extension.apply plugin: 'kotlin-parcelize'
extension.apply plugin: 'kotlin-kapt'
extension.description "lib"
setAndroidConfig extension.android
setDependencies extension.dependencies
}
/**
* android library common config
*/
setArouterConfig = {
extension ->
extension.android.defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
// ARouter
extension.dependencies.implementation(rootProject.ext.dependencies.arouter) {
exclude group: 'com.android.support'
}
extension.dependencies.annotationProcessor rootProject.ext.dependencies.arouter_compiler
}
}

@ -0,0 +1 @@
/build

@ -0,0 +1,22 @@
apply from: "${rootProject.rootDir}/buildCommon/commonLibConfig.gradle"
project.ext.setLibDefaultConfig project
android {
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding true
}
}
dependencies {
implementation 'com.aill:AndroidSerialPort:1.0.8'
}

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.common.serialport">
</manifest>

@ -0,0 +1,68 @@
package com.common.queue;
import android.util.Log;
import com.common.queue.Task.ITask;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class BlockTaskQueue {
private String TAG = "BlockTaskQueue";
private AtomicInteger mAtomicInteger = new AtomicInteger();
//阻塞队列
private final BlockingQueue<ITask> mTaskQueue = new PriorityBlockingQueue<>();
public BlockTaskQueue() {
}
//单例模式
// private static class BlockTaskQueueHolder {
// private final static BlockTaskQueue INSTANCE = new BlockTaskQueue();
// }
//
// public static BlockTaskQueue getInstance() {
// return BlockTaskQueueHolder.INSTANCE;
// }
/**
* Taskcomparable Taskcompare()
* 使AtomicInteger task sequence
* sequence
*/
public <T extends ITask> int add(T task) {
if (!mTaskQueue.contains(task)) {
task.setSequence(mAtomicInteger.incrementAndGet());
mTaskQueue.add(task);
Log.d(TAG, "\n add task " + task.toString());
}
return mTaskQueue.size();
}
public <T extends ITask> void remove(T task) {
if (mTaskQueue.contains(task)) {
Log.d(TAG, "\n" + "task has been finished. remove it from task queue");
mTaskQueue.remove(task);
}
if (mTaskQueue.size() == 0) {
mAtomicInteger.set(0);
}
}
public ITask poll() {
return mTaskQueue.poll();
}
public ITask take() throws InterruptedException {
return mTaskQueue.take();
}
public void clear() {
mTaskQueue.clear();
}
public int size() {
return mTaskQueue.size();
}
}

@ -0,0 +1,108 @@
package com.common.queue.Task;
import android.util.Log;
import com.common.queue.TaskScheduler;
import com.common.queue.BlockTaskQueue;
import java.lang.ref.WeakReference;
import java.util.concurrent.PriorityBlockingQueue;
public class BaseTask implements ITask {
private final String TAG = getClass().getSimpleName();
private TaskPriority mTaskPriority = TaskPriority.DEFAULT; //默认优先级
private int mSequence;// 入队次序
private Boolean mTaskStatus = false; // 标志任务状态,是否仍在展示
protected WeakReference<BlockTaskQueue> taskQueue;//阻塞队列
protected int duration = 0; //任务执行时间
//此队列用来实现任务时间不确定的队列阻塞功能
private PriorityBlockingQueue<Integer> blockQueue;
//构造函数
public BaseTask() {
taskQueue = new WeakReference<>(BlockTaskQueue.getInstance());
blockQueue = new PriorityBlockingQueue<>();
}
//入队实现
@Override
public void enqueue() {
TaskScheduler.getInstance().enqueue(this);
}
//执行任务方法此时标记为设为true并且将当前任务记录下来
@Override
public void doTask() {
mTaskStatus = true;
}
//任务执行完成,改变标记位,将任务在队列中移除,并且把记录清除
@Override
public void finishTask() {
this.mTaskStatus = false;
this.taskQueue.get().remove(this);
Log.d(TAG, taskQueue.get().size() + "");
}
//设置任务优先级实现
@Override
public ITask setPriority(TaskPriority mTaskPriority) {
this.mTaskPriority = mTaskPriority;
return this;
}
//设置任务执行时间
public ITask setDuration(int duration) {
this.duration = duration;
return this;
}
//获取任务优先级
@Override
public TaskPriority getPriority() {
return mTaskPriority;
}
//获取任务执行时间
@Override
public int getDuration() {
return duration;
}
//设置任务次序
@Override
public void setSequence(int mSequence) {
this.mSequence = mSequence;
}
//获取任务次序
@Override
public int getSequence() {
return mSequence;
}
// 获取任务状态
@Override
public boolean getStatus() {
return mTaskStatus;
}
//阻塞任务执行
@Override
public void blockTask() throws Exception {
blockQueue.take(); //如果队列里面没数据,就会一直阻塞
}
//解除阻塞
@Override
public void unLockBlock() {
blockQueue.add(1); //往里面随便添加一个数据,阻塞就会解除
}
/**
*
*
* TaskPriority.LOW < TaskPriority.DEFAULT < TaskPriority.HIGH
*
*/
@Override
public int compareTo(ITask another) {
final TaskPriority me = this.getPriority();
final TaskPriority it = another.getPriority();
return me == it ? this.getSequence() - another.getSequence() :
it.ordinal() - me.ordinal();
}
//输出一些信息
@Override
public String toString() {
return "task name : " + getClass().getSimpleName() + " sequence : " + mSequence + " TaskPriority : " + mTaskPriority;
}
}

@ -0,0 +1,51 @@
package com.common.queue.Task;
import android.util.Log;
public class DemoTask extends BaseTask {
String name;
public DemoTask(String name) {
this.name = name;
}
//执行任务方法,在这里实现你的任务具体内容
@Override
public void doTask() {
super.doTask();
Log.i("LogTask", "--doTask-" + name);
//如果这个Task的执行时间是不确定的比如上传图片那么在上传成功后需要手动调用
//unLockBlock方法解除阻塞例如
uploadImage(new UploadListener() {
@Override
public void onSuccess() {
unLockBlock();
}
});
}
private void uploadImage(UploadListener uploadListener) {
try {
// long seconds = getDuration();
long seconds = (long) (Math.random() * 10000);
Log.i("LogTask", "uploadImage milliseconds " + seconds);
Thread.sleep(seconds);
} catch (Exception e) {
e.printStackTrace();
}
uploadListener.onSuccess();
}
//任务执行完的回调,在这里你可以做些释放资源或者埋点之类的操作
@Override
public void finishTask() {
super.finishTask();
Log.i("LogTask", "--finishTask-" + name);
}
public interface UploadListener {
void onSuccess();
}
}

@ -0,0 +1,41 @@
package com.common.queue.Task;
public interface ITask extends Comparable<ITask> {
// 将该任务插入队列
void enqueue();
// 执行具体任务的方法
void doTask();
// 任务执行完成后的回调方法
void finishTask();
// 设置任务优先级
ITask setPriority(TaskPriority mTaskPriority);
// 获取任务优先级
TaskPriority getPriority();
// 当优先级相同 按照插入顺序 先入先出 该方法用来标记插入顺序
void setSequence(int mSequence);
// 获取入队次序
int getSequence();
// 每个任务的状态,就是标记完成和未完成
boolean getStatus();
// 设置每个任务的执行时间,该方法用于任务执行时间确定的情况
ITask setDuration(int duration);
// 获取每个任务执行的时间
int getDuration();
// 阻塞任务执行,该方法用于任务执行时间不确定的情况
void blockTask() throws Exception;
// 解除阻塞任务,该方法用于任务执行时间不确定的情况
void unLockBlock();
}

@ -0,0 +1,30 @@
package com.common.queue.Task;
import java.lang.ref.WeakReference;
public class TaskEvent {
private WeakReference<ITask> mTask;
int mEventType;
public ITask getTask() {
return mTask.get();
}
public void setTask(ITask mTask) {
this.mTask = new WeakReference<>(mTask);
}
public int getEventType() {
return mEventType;
}
public void setEventType(int mEventType) {
this.mEventType = mEventType;
}
public static class EventType {
public static final int DO = 0X00;
public static final int FINISH = 0X01;
}
}

@ -0,0 +1,8 @@
package com.common.queue.Task;
// 优先级分为3种如注释所示他们的关系LOW < DEFAULT < HIGH
public enum TaskPriority {
LOW, //低
DEFAULT,//普通
HIGH, //高
}

@ -0,0 +1,100 @@
package com.common.queue;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import com.common.queue.Task.TaskEvent;
import com.common.queue.Task.ITask;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TaskExecutor {
private final String TAG = "ShowTaskExecutor";
private BlockTaskQueue taskQueue;
private TaskHandler mTaskHandler;
private boolean isRunning = true;
private static final int MSG_EVENT_DO = 0;
private static final int MSG_EVENT_FINISH = 1;
public TaskExecutor(BlockTaskQueue taskQueue) {
this.taskQueue = taskQueue;
mTaskHandler = new TaskHandler();
}
//开始遍历任务队列
public void start() {
Executors.newSingleThreadExecutor().execute(new Runnable() {
@Override
public void run() {
try {
while (isRunning) { //死循环
ITask iTask;
iTask = taskQueue.take(); //取任务
if (iTask != null) {
//执行任务
TaskEvent doEvent = new TaskEvent();
doEvent.setTask(iTask);
doEvent.setEventType(TaskEvent.EventType.DO);
mTaskHandler.obtainMessage(MSG_EVENT_DO, doEvent).sendToTarget();
//一直阻塞,直到任务执行完
if (iTask.getDuration()!=0) {
TimeUnit.MILLISECONDS.sleep(iTask.getDuration());
}else {
iTask.blockTask();
}
//完成任务
TaskEvent finishEvent = new TaskEvent();
finishEvent.setTask(iTask);
finishEvent.setEventType(TaskEvent.EventType.FINISH);
mTaskHandler.obtainMessage(MSG_EVENT_FINISH, finishEvent).sendToTarget();
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
}
//根据不同的消息回调不同的方法。
private static class TaskHandler extends Handler {
TaskHandler() {
super(Looper.getMainLooper());
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
TaskEvent taskEvent = (TaskEvent) msg.obj;
if (msg.what == MSG_EVENT_DO && taskEvent.getEventType() == TaskEvent.EventType.DO) {
taskEvent.getTask().doTask();
}
if (msg.what == MSG_EVENT_FINISH && taskEvent.getEventType() == TaskEvent.EventType.FINISH) {
taskEvent.getTask().finishTask();
}
}
}
public void startRunning() {
isRunning = true;
}
public void pauseRunning() {
isRunning = false;
}
public boolean isRunning() {
return isRunning;
}
public void resetExecutor() {
isRunning = true;
taskQueue.clear();
}
public void clearExecutor() {
pauseRunning();
taskQueue.clear();
}
}

@ -0,0 +1,44 @@
package com.common.queue;
import com.common.queue.Task.ITask;
public class TaskScheduler {
private final String TAG = "TaskScheduler";
private BlockTaskQueue mTaskQueue = new BlockTaskQueue();
private TaskExecutor mExecutor;
// private static class ShowDurationHolder {
// private final static TaskScheduler INSTANCE = new TaskScheduler();
// }
public TaskScheduler() {
initExecutor();
}
private void initExecutor() {
mExecutor = new TaskExecutor(mTaskQueue);
mExecutor.start();
}
// public static TaskScheduler getInstance() {
// return ShowDurationHolder.INSTANCE;
// }
public void enqueue(ITask task) {
//因为TaskScheduler这里写成单例如果isRunning改成false的话不判断一下就会一直都是false
if (!mExecutor.isRunning()) {
mExecutor.startRunning();
}
//按照优先级插入队列 依次播放
mTaskQueue.add(task);
}
public void resetExecutor() {
mExecutor.resetExecutor();
}
public void clearExecutor() {
mExecutor.clearExecutor();
}
}

@ -0,0 +1,103 @@
package com.common.serialport
import android.util.Log
import com.aill.androidserialport.SerialPort
import com.common.serialport.inter.SerialPortHelper
import com.common.queue.TaskScheduler
import java.io.IOException
class EasySerialPort(
private val portPath: String,
private val baudRate: Int,
private val mReceiver: (ByteArray) -> Unit
) : Runnable {
private var mPort: SerialPort? = null
private var startReceiveMsg = true
private var autoRetryConnect = false
init {
openSerialPort();
}
private fun openSerialPort() {
mPort = SerialPortHelper.openSerialPort(portPath, baudRate)
mPort?.let {
startReceiveMsg = true
Thread(this).start()
}
}
/**
* 关闭串口
*/
open fun closePort() {
startReceiveMsg = false
SerialPortHelper.closePort(mPort)
}
/**
* 循环读消息
*/
override fun run() {
while (startReceiveMsg) {
try {
val ips = mPort?.inputStream
val readByte = ips?.available()?.let { ByteArray(it) }
readByte?.let {
val size = ips.read(it)
if (size > 0) {
mReceiver.invoke(readByte)
}
}
} catch (e: IOException) {
Log.e(
"EasySerialPort",
"read msg error; path = " + portPath + ", error msg = " + e.message
)
e.printStackTrace()
if (autoRetryConnect) {
closePort()
openSerialPort()
}
}
}
}
/**
* 写消息
*/
open fun write(data: ByteArray) {
val task = SendMsgTask(data) {
try {
val outputStream = mPort?.outputStream
outputStream?.write(it)
outputStream?.flush()
} catch (e: IOException) {
Log.e(
"EasySerialPort",
"write msg error; path = " + portPath + ", error msg = " + e.message
)
e.printStackTrace()
if (autoRetryConnect) {
closePort()
openSerialPort()
}
}
}
TaskScheduler.getInstance().enqueue(task)
}
/**
* 开始自动重连
*/
open fun enableAutoConnect() {
this.autoRetryConnect = true
}
/**
* 关闭自动重连
*/
open fun disableAutoConnect() {
this.autoRetryConnect = true
}
}

@ -0,0 +1,14 @@
package com.common.serialport
import com.common.queue.Task.BaseTask
class SendMsgTask(private val byteArray: ByteArray, private val action: (ByteArray) -> Unit) :
BaseTask() {
override fun doTask() {
super.doTask()
action.invoke(byteArray)
unLockBlock()
}
}

@ -0,0 +1,10 @@
package com.common.serialport.inter
import com.aill.androidserialport.SerialPort
interface IHelper {
fun openSerialPort(portPath: String, baudrate: Int): SerialPort?;
fun closePort(port: SerialPort?);
}

@ -0,0 +1,29 @@
package com.common.serialport.inter
import android.util.Log
import com.aill.androidserialport.SerialPort
import java.io.File
import java.io.IOException
object SerialPortHelper : IHelper {
override fun openSerialPort(portPath: String, baudrate: Int): SerialPort? {
try {
return SerialPort(File(portPath), baudrate, 0);
} catch (e: IOException) {
e.printStackTrace()
Log.e("SerialPortHelper", "open port error; " + e.message)
}
return null;
}
override fun closePort(port: SerialPort?) {
try {
port?.close()
port?.inputStream?.close()
port?.outputStream?.close()
} catch (e: Exception) {
e.printStackTrace()
Log.e("SerialPortHelper", "closePort error; " + e.message)
}
}
}

@ -0,0 +1,70 @@
package com.common.serialport.utils
import com.common.serialport.EasySerialPort
/**
* @author xiaowusky
* 操作串口工具类
* 可以同时处理多个串口操作
*/
object CommonPortUtils {
private val portMaps = HashMap<String, EasySerialPort?>()
/**
* 打开串口
* @param portPath 串口地址
* @param baudRate 波特率
* @param mReceiver 接收消息回调
*/
fun openPort(
portPath: String,
baudRate: Int,
mReceiver: (ByteArray) -> Unit
) {
if (portMaps.containsKey(portPath)) {
return
}
val easyPort = EasySerialPort(portPath, baudRate, mReceiver)
portMaps.put(portPath, easyPort)
}
/**
* 发送消息
* @param portPath 串口地址
* @param data 消息byte数组
*/
fun sendMsg(portPath: String, data: ByteArray) {
SinglePortUtils.easyPort?.write(data)
}
/**
* 发送消息
* @param portPath 串口地址
* @param data String类型消息内部会toByteArray
*/
fun sendMsg(portPath: String, data: String) {
SinglePortUtils.easyPort?.write(data.toByteArray())
}
/**
* 释放某个串口
* @param portPath 串口地址
*/
fun release(portPath: String) {
if (portMaps.containsKey(portPath)) {
portMaps.get(portPath)?.closePort()
}
portMaps.remove(portPath)
}
/**
* 释放所有串口
*/
fun releaseAll() {
portMaps.forEach {
it.value?.closePort()
}
portMaps.clear()
}
}

@ -0,0 +1,139 @@
package com.common.serialport.utils;
import java.util.ArrayList;
import java.util.List;
/**
*
* Created by Administrator on 2016/6/2.
*/
public class DataUtils {
//-------------------------------------------------------
// 判断奇数或偶数位运算最后一位是1则为奇数为0是偶数
public static int isOdd(int num) {
return num & 1;
}
//-------------------------------------------------------
//Hex字符串转int
public static int HexToInt(String inHex) {
return Integer.parseInt(inHex, 16);
}
public static String IntToHex(int intHex){
return Integer.toHexString(intHex);
}
//-------------------------------------------------------
//Hex字符串转byte
public static byte HexToByte(String inHex) {
return (byte) Integer.parseInt(inHex, 16);
}
//-------------------------------------------------------
//1字节转2个Hex字符
public static String Byte2Hex(Byte inByte) {
return String.format("%02x", new Object[]{inByte}).toUpperCase();
}
//-------------------------------------------------------
//字节数组转转hex字符串
public static String ByteArrToHex(byte[] inBytArr) {
StringBuilder strBuilder = new StringBuilder();
for (byte valueOf : inBytArr) {
strBuilder.append(Byte2Hex(Byte.valueOf(valueOf)));
strBuilder.append(" ");
}
return strBuilder.toString();
}
//-------------------------------------------------------
//字节数组转转hex字符串可选长度
public static String ByteArrToHex(byte[] inBytArr, int offset, int byteCount) {
StringBuilder strBuilder = new StringBuilder();
int j = byteCount;
for (int i = offset; i < j; i++) {
strBuilder.append(Byte2Hex(Byte.valueOf(inBytArr[i])));
}
return strBuilder.toString();
}
//-------------------------------------------------------
//转hex字符串转字节数组
public static byte[] HexToByteArr(String inHex) {
byte[] result;
int hexlen = inHex.length();
if (isOdd(hexlen) == 1) {
hexlen++;
result = new byte[(hexlen / 2)];
inHex = "0" + inHex;
} else {
result = new byte[(hexlen / 2)];
}
int j = 0;
for (int i = 0; i < hexlen; i += 2) {
result[j] = HexToByte(inHex.substring(i, i + 2));
j++;
}
return result;
}
/**
*
*
* @param inputString
* @param length
* @return
*/
public static List<String> getDivLines(String inputString, int length) {
List<String> divList = new ArrayList<>();
int remainder = (inputString.length()) % length;
// 一共要分割成几段
int number = (int) Math.floor((inputString.length()) / length);
for (int index = 0; index < number; index++) {
String childStr = inputString.substring(index * length, (index + 1) * length);
divList.add(childStr);
}
if (remainder > 0) {
String cStr = inputString.substring(number * length, inputString.length());
divList.add(cStr);
}
return divList;
}
/**
*
*
* @param val value
* @return
*/
public static String twoByte(String val) {
if (val.length() > 4) {
val = val.substring(0, 4);
} else {
int l = 4 - val.length();
for (int i = 0; i < l; i++) {
val = "0" + val;
}
}
return val;
}
/**
*
*
* @param cmd
* @return
*/
public static String sum(String cmd) {
List<String> cmdList = DataUtils.getDivLines(cmd, 2);
int sumInt = 0;
for (String c : cmdList) {
sumInt += DataUtils.HexToInt(c);
}
String sum = DataUtils.IntToHex(sumInt);
sum = DataUtils.twoByte(sum);
cmd += sum;
return cmd.toUpperCase();
}
}

@ -0,0 +1,51 @@
package com.common.serialport.utils
import com.common.serialport.EasySerialPort
/**
* @author xiaowusky
* 操作单个串口工具类
*/
object SinglePortUtils {
var easyPort: EasySerialPort? = null
/**
* 初始化参数
* @param portPath 串口地址
* @param baudRate 波特率
* @param mReceiver 接收消息回调
*/
fun initParams(
portPath: String,
baudRate: Int,
mReceiver: (ByteArray) -> Unit
) {
easyPort = EasySerialPort(portPath, baudRate, mReceiver)
}
/**
* 发送消息
* @param portPath 串口地址
* @param data 消息byte数组
*/
fun sendMsg(data: ByteArray) {
easyPort?.write(data)
}
/**
* 发送消息
* @param portPath 串口地址
* @param data String类型消息内部会toByteArray
*/
fun sendMsg(data: String) {
easyPort?.write(data.toByteArray())
}
/**
* 释放串口
*/
fun release(){
easyPort?.closePort()
}
}

@ -1,3 +1,4 @@
include ':myapplication' //, ':libuvccamera-release' include ':myapplication' //, ':libuvccamera-release'
include ':library' include ':library'
include ':ijkplayer-java' include ':ijkplayer-java'
include ':commonSPort'

Loading…
Cancel
Save