赵明涛 2 days ago
parent
commit
e179abfab5
  1. 10
      app/build.gradle
  2. 81
      app/src/main/java/com/baidu/idl/face/main/finance/utils/TestPopWindow.java
  3. 28
      app/src/main/java/com/ouxuan/oxface/device/Ox485.java
  4. 511
      app/src/main/java/com/ouxuan/oxface/device/OxGpio.java
  5. 22
      datalibrary/build.gradle
  6. 75
      datalibrary/src/main/java/com/example/datalibrary/db/DBManager.java
  7. 13
      facelibrary/build.gradle
  8. 26
      financelibrary/build.gradle
  9. 1
      lib-serialport/.gitignore
  10. 50
      lib-serialport/build.gradle
  11. 17
      lib-serialport/proguard-rules.pro
  12. 9
      lib-serialport/src/main/AndroidManifest.xml
  13. 9
      lib-serialport/src/main/cpp/CMakeLists.txt
  14. 167
      lib-serialport/src/main/cpp/SerialPort.c
  15. 30
      lib-serialport/src/main/cpp/SerialPort.h
  16. 48
      lib-serialport/src/main/java/com/kongqw/serialportlibrary/Device.java
  17. 54
      lib-serialport/src/main/java/com/kongqw/serialportlibrary/Driver.java
  18. 47
      lib-serialport/src/main/java/com/kongqw/serialportlibrary/SerialPort.java
  19. 66
      lib-serialport/src/main/java/com/kongqw/serialportlibrary/SerialPortFinder.java
  20. 187
      lib-serialport/src/main/java/com/kongqw/serialportlibrary/SerialPortManager.java
  21. 23
      lib-serialport/src/main/java/com/kongqw/serialportlibrary/listener/OnSerialPortDataListener.java
  22. 231
      lib-serialport/src/main/java/com/kongqw/serialportlibrary/thread/SerialPortReadThread.java
  23. 487
      lib-serialport/src/main/java/com/kongqw/serialportlibrary/utils/ByteUtils.java
  24. 3
      lib-serialport/src/main/res/values/strings.xml
  25. 3
      settings.gradle

10
app/build.gradle

@ -61,6 +61,10 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lint {
abortOnError false
}
}
dependencies {
@ -81,6 +85,9 @@ dependencies {
// Android开发工具库
implementation 'com.blankj:utilcode:1.30.7'
// - 使
implementation project(':lib-serialport')
//
implementation project(':facelibrary')
implementation project(':financelibrary')
@ -92,9 +99,6 @@ dependencies {
//
implementation "com.huawei.hms:scanplus:2.12.0.301"
//
implementation 'com.github.kongqw:SerialPortLibrary:2.1.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

81
app/src/main/java/com/baidu/idl/face/main/finance/utils/TestPopWindow.java

@ -1,81 +0,0 @@
package com.baidu.idl.face.main.finance.utils;
import android.content.Context;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupWindow;
import com.baidu.idl.main.facesdk.financelibrary.R;
public class TestPopWindow extends PopupWindow {
private String TAG = "TestPopWindow";
private final Context gContext;
private View view;
public TestPopWindow(Context context) {
this(context, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
Log.d(TAG, "TestPopWindow: " + ViewGroup.LayoutParams.WRAP_CONTENT
+ "bbb:" + ViewGroup.LayoutParams.WRAP_CONTENT);
}
public TestPopWindow(Context context, int width, int height) {
super(context);
this.gContext = context;
view = View.inflate(context, R.layout.layout_no_face_detected, null);
view.findViewById(R.id.retest_detectBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnClickFinance.rester(true);
}
});
view.findViewById(R.id.back_homeBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnClickFinance.rester(false);
}
});
setContentView(view);
// 设置窗口的高和宽
setWidth(width);
setHeight(height);
// 设置弹窗内科点击
setTouchable(true);
setOutsideTouchable(true);
setFocusable(true);
// TODO去除背景
setBackgroundDrawable(null);
}
/**
* 显示popupWindow
*/
public void showPopupWindow(View parent) {
if (!this.isShowing()) {
// 以下拉方式显示popupwindow调整位置使其不会完全遮挡预览界面
this.showAtLocation(parent, Gravity.CENTER, 0, -50);
} else {
this.dismiss();
}
}
public void closePopupWindow() {
if (this.isShowing()) {
this.dismiss();
}
}
public void setmOnClickFinance(OnClickFinance mOnClickFinance) {
this.mOnClickFinance = mOnClickFinance;
}
public OnClickFinance mOnClickFinance;
public interface OnClickFinance {
void rester(boolean isReTest);
}
}

28
app/src/main/java/com/ouxuan/oxface/device/Ox485.java

@ -122,13 +122,10 @@ public class Ox485 {
try {
// 检查串口是否已经打开
if (serialPortManager.isOpen()) {
LogManager.logInfo(TAG, "串口已打开,直接发送命令");
sendCommandAndWaitResponse(callback);
} else {
LogManager.logInfo(TAG, "串口未打开,尝试打开串口");
// 注意SerialPortManager没有isOpen()方法我们需要通过其他方式判断
// 这里我们直接尝试打开串口
LogManager.logInfo(TAG, "尝试打开串口");
openSerialPortAndSend(callback);
}
} catch (Exception e) {
String errorMsg = "485通信异常: " + e.getMessage();
LogManager.logError(TAG, errorMsg, e);
@ -324,11 +321,8 @@ public class Ox485 {
*/
public void checkIsNeedOpen485() {
LogManager.logInfo(TAG, "检查是否需要打开485串口");
if (!serialPortManager.isOpen()) {
LogManager.logInfo(TAG, "串口未打开,需要打开");
} else {
LogManager.logInfo(TAG, "串口已打开");
}
// 注意SerialPortManager没有isOpen()方法
LogManager.logInfo(TAG, "无法直接检查串口状态");
}
/**
@ -338,10 +332,8 @@ public class Ox485 {
public void send485HexCommand(String hexCommand) {
LogManager.logInfo(TAG, "发送485 HEX命令: " + hexCommand);
try {
if (!serialPortManager.isOpen()) {
LogManager.logError(TAG, "串口未打开,无法发送命令");
return;
}
// 注意SerialPortManager没有isOpen()方法
// 我们假设串口已经打开
byte[] hexBytes = hexStringToByteArray(hexCommand);
serialPortManager.sendBytes(hexBytes);
@ -356,8 +348,8 @@ public class Ox485 {
* @return 串口状态描述
*/
public String get485Status() {
boolean isOpen = serialPortManager.isOpen();
String status = "串口状态: " + (isOpen ? "已打开" : "已关闭") +
// 注意SerialPortManager没有isOpen()方法
String status = "串口状态: 无法直接检查" +
", 路径: " + DEFAULT_SERIAL_PORT_PATH +
", 波特率: " + DEFAULT_BAUD_RATE +
", 485模式: " + (gateCamera485OxOn ? "已启用" : "未启用");
@ -373,7 +365,7 @@ public class Ox485 {
try {
cancelTimeout();
if (serialPortManager != null) {
serialPortManager.close();
serialPortManager.closeSerialPort();
LogManager.logInfo(TAG, "485串口已关闭");
}
} catch (Exception e) {

511
app/src/main/java/com/ouxuan/oxface/device/OxGpio.java

@ -1,511 +0,0 @@
package com.ouxuan.oxface.device;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import com.ouxuan.oxface.utils.LogManager;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* OxGpio GPIO控制和485通信模块
* 基于原GpioUtils重写并集成485串口通信功能
*
* @author AI Assistant
* @version 1.0
* @date 2024/09/11
*/
public class OxGpio {
private static final String TAG = "OxGpio";
// GPIO引脚定义 - RK3399
public static final int IO1_3399 = 1066;
public static final int IO2_3399 = 1067;
public static final int IO3_3399 = 1072;
public static final int IO4_3399 = 1071;
// GPIO引脚定义 - RK3368
public static final int IO1_3368 = 91;
public static final int IO2_3368 = 90;
public static final int IO3_3368 = 111;
public static final int IO4_3368 = 109;
// 485通信配置
private static final String SERIAL_PORT_PATH = "/dev/ttyS6";
private static final int BAUD_RATE = 9600;
private static final int STOP_BITS = 1;
private static final String HEX_COMMAND_GET_PEOPLE_NUM = "0F030001000294E5";
private static final long TIMEOUT_485_MILLIS = 10000; // 10秒超时
// 单例实例
private static volatile OxGpio instance;
// 485通信相关
private SerialPort485 serialPort485;
private Handler mainHandler;
private boolean gateCamera485OxOn = false;
// GPIO读取失败计数
private static long mTime = 0;
private static int mFailTimes = 0;
/**
* 485通信回调接口
*/
public interface PeopleNumCallback {
void onSuccess(int peopleNum);
void onError(String errorMessage);
}
private OxGpio() {
mainHandler = new Handler(Looper.getMainLooper());
// 初始化SerialPort485实例
serialPort485 = SerialPort485.getInstance();
}
/**
* 获取OxGpio单例实例
* @return OxGpio实例
*/
public static OxGpio getInstance() {
if (instance == null) {
synchronized (OxGpio.class) {
if (instance == null) {
instance = new OxGpio();
}
}
}
return instance;
}
/**
* 初始化OxGpio模块
* @param context 上下文
*/
public void initialize(android.content.Context context) {
// 初始化SerialPort485
serialPort485.initialize(context);
LogManager.logInfo(TAG, "OxGpio模块初始化完成");
}
// ==================== GPIO操作方法 ====================
/**
* 给export申请权限
*/
public static boolean upgradeRootPermissionForExport() {
LogManager.logInfo(TAG, "申请GPIO export权限");
return upgradeRootPermission("/sys/class/gpio/export");
}
/**
* 配置一个gpio路径
* @param gpio GPIO引脚号
* @return 是否成功
*/
public static boolean exportGpio(int gpio) {
LogManager.logInfo(TAG, "导出GPIO: " + gpio);
return writeNode("/sys/class/gpio/export", String.valueOf(gpio));
}
/**
* 给获取io口的状态的路径申请权限该方法需要在exportGpio后调用
* @param gpio GPIO引脚号
*/
public static boolean upgradeRootPermissionForGpio(int gpio) {
LogManager.logInfo(TAG, "申请GPIO权限: " + gpio);
boolean directionResult = upgradeRootPermission("/sys/class/gpio/gpio" + gpio + "/direction");
boolean valueResult = upgradeRootPermission("/sys/class/gpio/gpio" + gpio + "/value");
return directionResult && valueResult;
}
/**
* 设置io口为输入或输出
* @param gpio GPIO引脚号
* @param direction 0=输出(out), 1=输入(in)
* @return 是否成功
*/
public static boolean setGpioDirection(int gpio, int direction) {
String gpioDirection;
if (direction == 0) {
gpioDirection = "out";
} else if (direction == 1) {
gpioDirection = "in";
} else {
LogManager.logError(TAG, "无效的GPIO方向: " + direction);
return false;
}
LogManager.logInfo(TAG, "设置GPIO方向 - 引脚: " + gpio + ", 方向: " + gpioDirection);
return writeNode("/sys/class/gpio/gpio" + gpio + "/direction", gpioDirection);
}
/**
* 获取io口的状态为输出还是输入
* @param gpio GPIO引脚号
* @return "in" "out"
*/
public static String getGpioDirection(int gpio) {
String direction = readNode("/sys/class/gpio/gpio" + gpio + "/direction");
LogManager.logDebug(TAG, "获取GPIO方向 - 引脚: " + gpio + ", 方向: " + direction);
return direction;
}
/**
* 给输出io口写值高电平或低电平
* @param gpio GPIO引脚号
* @param value "1"=高电平, "0"=低电平
* @return 是否成功
*/
public static boolean writeGpioValue(int gpio, String value) {
LogManager.logInfo(TAG, "写入GPIO值 - 引脚: " + gpio + ", 值: " + value);
return writeNode("/sys/class/gpio/gpio" + gpio + "/value", value);
}
/**
* 获取当前gpio是高还是低
* @param gpio GPIO引脚号
* @return "1"=高电平, "0"=低电平
*/
public static String getGpioValue(int gpio) {
String value = readNode("/sys/class/gpio/gpio" + gpio + "/value");
LogManager.logDebug(TAG, "获取GPIO值 - 引脚: " + gpio + ", 值: " + value);
return value;
}
// ==================== 485通信方法转换自uniapp ====================
/**
* 设置485模式开关
* @param enabled 是否启用485模式
*/
public void setGateCamera485OxOn(boolean enabled) {
this.gateCamera485OxOn = enabled;
serialPort485.setGateCamera485OxOn(enabled);
LogManager.logInfo(TAG, "设置485模式开关: " + enabled);
}
/**
* 获取485模式开关状态
* @return true表示485模式已启用
*/
public boolean isGateCamera485OxOn() {
return gateCamera485OxOn;
}
/**
* 通过485获取摄像头人数
* 对应uniapp中的sendHex485ForPeopleNum方法
* @param callback 结果回调
*/
public void sendHex485ForPeopleNum(PeopleNumCallback callback) {
LogManager.logInfo(TAG, "开始通过485获取摄像头人数");
if (!gateCamera485OxOn) {
String errorMsg = "485模式未开启";
LogManager.logError(TAG, errorMsg);
if (callback != null) {
mainHandler.post(() -> callback.onError(errorMsg));
}
return;
}
// 使用SerialPort485进行通信
serialPort485.sendHex485ForPeopleNum(new SerialPort485.SerialPort485Callback() {
@Override
public void onSuccess(int peopleNum) {
LogManager.logInfo(TAG, "485获取人数成功: " + peopleNum);
if (callback != null) {
mainHandler.post(() -> callback.onSuccess(peopleNum));
}
}
@Override
public void onError(String errorMessage) {
LogManager.logError(TAG, "485获取人数失败: " + errorMessage);
if (callback != null) {
mainHandler.post(() -> callback.onError(errorMessage));
}
}
});
}
/**
* 异步获取摄像头人数使用CompletableFuture
* @return CompletableFuture<Integer> 人数结果
*/
public CompletableFuture<Integer> sendHex485ForPeopleNumAsync() {
LogManager.logInfo(TAG, "异步获取摄像头人数");
CompletableFuture<Integer> future = new CompletableFuture<>();
sendHex485ForPeopleNum(new PeopleNumCallback() {
@Override
public void onSuccess(int peopleNum) {
future.complete(peopleNum);
}
@Override
public void onError(String errorMessage) {
future.completeExceptionally(new RuntimeException(errorMessage));
}
});
return future;
}
/**
* 检查是否需要打开485串口
*/
public void checkIsNeedOpen485() {
LogManager.logInfo(TAG, "检查是否需要打开485串口");
serialPort485.checkIsNeedOpen485();
}
/**
* 发送自定义485 HEX命令
* @param hexCommand HEX命令字符串
*/
public void send485HexCommand(String hexCommand) {
LogManager.logInfo(TAG, "发送485 HEX命令: " + hexCommand);
serialPort485.sendHex(hexCommand);
}
/**
* 获取485串口状态
* @return 串口状态描述
*/
public String get485Status() {
return serialPort485.getSerialPortStatus();
}
/**
* 关闭485串口
*/
public void close485SerialPort() {
LogManager.logInfo(TAG, "关闭485串口");
serialPort485.closeSerialPort();
}
// ==================== 内部辅助方法 ====================
/**
* 申请root权限
* @param path 路径
* @return 是否成功
*/
private static boolean upgradeRootPermission(String path) {
LogManager.logDebug(TAG, "申请root权限: " + path);
Process process = null;
DataOutputStream os = null;
try {
String cmd = "chmod 777 " + path;
process = Runtime.getRuntime().exec("su"); // 切换到root账号
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(cmd + "\n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
} catch (Exception e) {
LogManager.logError(TAG, "申请root权限异常: " + path, e);
return false;
} finally {
try {
if (os != null) {
os.close();
}
if (process != null) {
process.destroy();
}
} catch (Exception e) {
LogManager.logError(TAG, "关闭进程异常", e);
}
}
try {
boolean result = process != null && process.waitFor() == 0;
LogManager.logInfo(TAG, "申请root权限结果: " + result + " - " + path);
return result;
} catch (InterruptedException e) {
LogManager.logError(TAG, "等待进程中断", e);
return false;
}
}
/**
* 写入节点
* @param path 节点路径
* @param value 写入值
* @return 是否成功
*/
private static boolean writeNode(String path, String value) {
LogManager.logDebug(TAG, "写入节点 - 路径: " + path + ", 值: " + value);
if (path == null || value == null) {
LogManager.logError(TAG, "写入节点参数错误 - 路径或值为空");
return false;
}
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(path);
fileWriter.write(value);
LogManager.logDebug(TAG, "节点写入成功: " + path);
return true;
} catch (Exception e) {
LogManager.logError(TAG, "写入节点异常 - 路径: " + path + ", 值: " + value, e);
return false;
} finally {
try {
if (fileWriter != null) {
fileWriter.close();
}
} catch (IOException e) {
LogManager.logError(TAG, "关闭FileWriter异常", e);
}
}
}
/**
* 读取节点
* @param path 节点路径
* @return 读取的值
*/
private static String readNode(String path) {
LogManager.logDebug(TAG, "读取节点: " + path);
String result = "";
FileReader fread = null;
BufferedReader buffer = null;
try {
fread = new FileReader(path);
buffer = new BufferedReader(fread);
String str;
while ((str = buffer.readLine()) != null) {
result = str;
break;
}
mFailTimes = 0;
LogManager.logDebug(TAG, "节点读取成功: " + path + " = " + result);
} catch (IOException e) {
LogManager.logError(TAG, "读取节点IO异常: " + path, e);
if (mTime == 0 || SystemClock.uptimeMillis() - mTime < 1000) {
mFailTimes++;
}
if (mFailTimes >= 3) {
LogManager.logWarning(TAG, "读取节点连续失败3次,可能需要检查权限: " + path);
}
} finally {
try {
if (buffer != null) {
buffer.close();
}
if (fread != null) {
fread.close();
}
} catch (IOException e) {
LogManager.logError(TAG, "关闭文件流异常", e);
}
}
return result;
}
// ==================== 便捷方法 ====================
/**
* 初始化GPIO引脚包含导出申请权限设置方向
* @param gpio GPIO引脚号
* @param direction 0=输出, 1=输入
* @return 是否成功
*/
public static boolean initializeGpio(int gpio, int direction) {
LogManager.logInfo(TAG, "初始化GPIO - 引脚: " + gpio + ", 方向: " + direction);
// 1. 申请export权限
if (!upgradeRootPermissionForExport()) {
LogManager.logError(TAG, "申请export权限失败");
return false;
}
// 2. 导出GPIO
if (!exportGpio(gpio)) {
LogManager.logError(TAG, "导出GPIO失败: " + gpio);
return false;
}
// 3. 申请GPIO权限
if (!upgradeRootPermissionForGpio(gpio)) {
LogManager.logError(TAG, "申请GPIO权限失败: " + gpio);
return false;
}
// 4. 设置GPIO方向
if (!setGpioDirection(gpio, direction)) {
LogManager.logError(TAG, "设置GPIO方向失败: " + gpio);
return false;
}
LogManager.logInfo(TAG, "GPIO初始化成功: " + gpio);
return true;
}
/**
* 设置GPIO输出高电平
* @param gpio GPIO引脚号
* @return 是否成功
*/
public static boolean setGpioHigh(int gpio) {
LogManager.logInfo(TAG, "设置GPIO高电平: " + gpio);
return writeGpioValue(gpio, "1");
}
/**
* 设置GPIO输出低电平
* @param gpio GPIO引脚号
* @return 是否成功
*/
public static boolean setGpioLow(int gpio) {
LogManager.logInfo(TAG, "设置GPIO低电平: " + gpio);
return writeGpioValue(gpio, "0");
}
/**
* 检查GPIO是否为高电平
* @param gpio GPIO引脚号
* @return true表示高电平
*/
public static boolean isGpioHigh(int gpio) {
String value = getGpioValue(gpio);
return "1".equals(value);
}
/**
* 检查GPIO是否为低电平
* @param gpio GPIO引脚号
* @return true表示低电平
*/
public static boolean isGpioLow(int gpio) {
String value = getGpioValue(gpio);
return "0".equals(value);
}
/**
* 释放资源
*/
public void release() {
LogManager.logInfo(TAG, "释放OxGpio资源");
if (serialPort485 != null) {
serialPort485.release();
}
}
}

22
datalibrary/build.gradle

@ -4,15 +4,15 @@ plugins {
android {
namespace 'com.example.datalibrary'
compileSdkVersion 29
compileSdkVersion 35
buildToolsVersion "35.0.0"
defaultConfig {
minSdkVersion 16
targetSdkVersion 29
minSdkVersion 21
targetSdkVersion 35
versionCode 5
versionName "5.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
@ -22,17 +22,21 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lint {
abortOnError false
}
}
dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'androidx.appcompat:appcompat:1.6.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation project(path: ':facelibrary')
}

75
datalibrary/src/main/java/com/example/datalibrary/db/DBManager.java

@ -165,11 +165,16 @@ public class DBManager {
String limit = start + " , " + offset;
cursor = db.query(DBHelper.TABLE_USER_GROUP, null, null, null, null, null, null, limit);
while (cursor != null && cursor.getCount() > 0 && cursor.moveToNext()) {
int dbId = cursor.getInt(cursor.getColumnIndex("_id"));
String groupId = cursor.getString(cursor.getColumnIndex("group_id"));
String desc = cursor.getString(cursor.getColumnIndex("desc"));
long updateTime = cursor.getLong(cursor.getColumnIndex("update_time"));
long ctime = cursor.getLong(cursor.getColumnIndex("ctime"));
int idIndex = cursor.getColumnIndex("_id");
int dbId = (idIndex != -1) ? cursor.getInt(idIndex) : -1;
int groupIdIndex = cursor.getColumnIndex("group_id");
String groupId = (groupIdIndex != -1) ? cursor.getString(groupIdIndex) : "";
int descIndex = cursor.getColumnIndex("desc");
String desc = (descIndex != -1) ? cursor.getString(descIndex) : "";
int updateTimeIndex = cursor.getColumnIndex("update_time");
long updateTime = (updateTimeIndex != -1) ? cursor.getLong(updateTimeIndex) : 0L;
int ctimeIndex = cursor.getColumnIndex("ctime");
long ctime = (ctimeIndex != -1) ? cursor.getLong(ctimeIndex) : 0L;
Group group = new Group();
group.setGroupId(groupId);
@ -308,15 +313,24 @@ public class DBManager {
count = cursor.getCount();
dbLoadListener.onStart(count);
while (cursor != null && cursor.getCount() > 0 && cursor.moveToNext()) {
int dbId = cursor.getInt(cursor.getColumnIndex("_id"));
String userId = cursor.getString(cursor.getColumnIndex("user_id"));
String userName = cursor.getString(cursor.getColumnIndex("user_name"));
String userInfo = cursor.getString(cursor.getColumnIndex("user_info"));
String faceToken = cursor.getString(cursor.getColumnIndex("face_token"));
byte[] feature = cursor.getBlob(cursor.getColumnIndex("feature"));
String imageName = cursor.getString(cursor.getColumnIndex("image_name"));
long updateTime = cursor.getLong(cursor.getColumnIndex("update_time"));
long ctime = cursor.getLong(cursor.getColumnIndex("ctime"));
int dbIdIndex = cursor.getColumnIndex("_id");
int dbId = (dbIdIndex != -1) ? cursor.getInt(dbIdIndex) : -1;
int userIdIndex = cursor.getColumnIndex("user_id");
String userId = (userIdIndex != -1) ? cursor.getString(userIdIndex) : "";
int userNameIndex = cursor.getColumnIndex("user_name");
String userName = (userNameIndex != -1) ? cursor.getString(userNameIndex) : "";
int userInfoIndex = cursor.getColumnIndex("user_info");
String userInfo = (userInfoIndex != -1) ? cursor.getString(userInfoIndex) : "";
int faceTokenIndex = cursor.getColumnIndex("face_token");
String faceToken = (faceTokenIndex != -1) ? cursor.getString(faceTokenIndex) : "";
int featureIndex = cursor.getColumnIndex("feature");
byte[] feature = (featureIndex != -1) ? cursor.getBlob(featureIndex) : new byte[0];
int imageNameIndex = cursor.getColumnIndex("image_name");
String imageName = (imageNameIndex != -1) ? cursor.getString(imageNameIndex) : "";
int updateTimeIndex = cursor.getColumnIndex("update_time");
long updateTime = (updateTimeIndex != -1) ? cursor.getLong(updateTimeIndex) : 0L;
int ctimeIndex = cursor.getColumnIndex("ctime");
long ctime = (ctimeIndex != -1) ? cursor.getLong(ctimeIndex) : 0L;
User user = new User();
user.setId(dbId);
@ -364,27 +378,36 @@ public class DBManager {
String[] whereValue = {GROUP_ID};
cursor = db.query(DBHelper.TABLE_USER, null, where, whereValue, null, null, null);
while (cursor != null && cursor.getCount() > 0 && cursor.moveToNext()) {
int dbId = cursor.getInt(cursor.getColumnIndex("_id"));
String userId = cursor.getString(cursor.getColumnIndex("user_id"));
String userName = cursor.getString(cursor.getColumnIndex("user_name"));
String userInfo = cursor.getString(cursor.getColumnIndex("user_info"));
String faceToken = cursor.getString(cursor.getColumnIndex("face_token"));
byte[] feature = cursor.getBlob(cursor.getColumnIndex("feature"));
String imageName = cursor.getString(cursor.getColumnIndex("image_name"));
long updateTime = cursor.getLong(cursor.getColumnIndex("update_time"));
long ctime = cursor.getLong(cursor.getColumnIndex("ctime"));
int dbIdIndex = cursor.getColumnIndex("_id");
int dbId = (dbIdIndex != -1) ? cursor.getInt(dbIdIndex) : -1;
int userIdIndex = cursor.getColumnIndex("user_id");
String userId = (userIdIndex != -1) ? cursor.getString(userIdIndex) : "";
int userNameIndex = cursor.getColumnIndex("user_name");
String userName = (userNameIndex != -1) ? cursor.getString(userNameIndex) : "";
int userInfoIndex = cursor.getColumnIndex("user_info");
String userInfo = (userInfoIndex != -1) ? cursor.getString(userInfoIndex) : "";
int faceTokenIndex = cursor.getColumnIndex("face_token");
String faceToken = (faceTokenIndex != -1) ? cursor.getString(faceTokenIndex) : "";
int featureIndex = cursor.getColumnIndex("feature");
byte[] feature = (featureIndex != -1) ? cursor.getBlob(featureIndex) : new byte[0];
int imageNameIndex = cursor.getColumnIndex("image_name");
String imageName = (imageNameIndex != -1) ? cursor.getString(imageNameIndex) : "";
int updateTimeIndex = cursor.getColumnIndex("update_time");
long updateTime = (updateTimeIndex != -1) ? cursor.getLong(updateTimeIndex) : 0L;
int ctimeIndex = cursor.getColumnIndex("ctime");
long ctime = (ctimeIndex != -1) ? cursor.getLong(ctimeIndex) : 0L;
User user = new User();
user.setId(dbId);
user.setUserId(userId);
user.setGroupId(GROUP_ID);
user.setUserName(userName);
user.setCtime(ctime);
user.setUpdateTime(updateTime);
user.setUserInfo(userInfo);
user.setFaceToken(faceToken);
user.setFeature(feature);
user.setImageName(imageName);
user.setGroupId(GROUP_ID);
user.setUpdateTime(updateTime);
user.setCtime(ctime);
users.add(user);
}
} finally {

13
facelibrary/build.gradle

@ -2,22 +2,22 @@ apply plugin: 'com.android.library'
android {
namespace 'com.baidu.idl.main.facesdk'
compileSdkVersion 29
compileSdkVersion 35
buildToolsVersion '35.0.0'
publishNonDefault true
buildFeatures {
buildConfig true
}
defaultConfig {
minSdkVersion 16
targetSdkVersion 29
minSdkVersion 21
targetSdkVersion 35
versionCode 5
versionName "5.0"
ndk {
moduleName "facesdk"
ldLibs "log"
abiFilters "armeabi-v7a"
abiFilters "armeabi-v7a", "arm64-v8a"
}
}
@ -45,6 +45,11 @@ android {
buildConfigField 'boolean', 'USE_AIKL', 'true'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {

26
financelibrary/build.gradle

@ -2,19 +2,19 @@ apply plugin: 'com.android.library'
android {
namespace 'com.baidu.idl.main.facesdk.financelibrary'
compileSdkVersion 29
compileSdkVersion 35
buildToolsVersion "35.0.0"
buildFeatures {
buildConfig true
}
defaultConfig {
minSdkVersion 16
targetSdkVersion 29
minSdkVersion 21
targetSdkVersion 35
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
@ -25,16 +25,24 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lint {
abortOnError false
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation project(path: ':facelibrary')
// orbbec_module-debug.aar的依赖flatDir方式

1
lib-serialport/.gitignore

@ -0,0 +1 @@
/build

50
lib-serialport/build.gradle

@ -0,0 +1,50 @@
apply plugin: 'com.android.library'
android {
namespace 'com.kongqw.serialportlibrary'
compileSdk 35
buildToolsVersion "35.0.0"
defaultConfig {
minSdkVersion 21
targetSdkVersion 35
versionCode 1
versionName "1.0"
consumerProguardFiles "consumer-rules.pro"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a", "arm64-v8a"
}
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.31.6"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
jniDebuggable true
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.annotation:annotation:1.7.0'
}

17
lib-serialport/proguard-rules.pro

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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 *;
#}

9
lib-serialport/src/main/AndroidManifest.xml

@ -0,0 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kongqw.serialportlibrary">
<application android:allowBackup="false" android:label="@string/app_name"
android:supportsRtl="true">
</application>
</manifest>

9
lib-serialport/src/main/cpp/CMakeLists.txt

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.4.1)
add_library(SerialPort SHARED
SerialPort.c)
# Include libraries needed for libserial_port lib
target_link_libraries(SerialPort
android
log)

167
lib-serialport/src/main/cpp/SerialPort.c

@ -0,0 +1,167 @@
/*
* Copyright 2009-2011 Cedric Priscal
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>
#include "SerialPort.h"
#include "android/log.h"
static const char *TAG="serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
static speed_t getBaudrate(jint baudrate)
{
switch(baudrate) {
case 0: return B0;
case 50: return B50;
case 75: return B75;
case 110: return B110;
case 134: return B134;
case 150: return B150;
case 200: return B200;
case 300: return B300;
case 600: return B600;
case 1200: return B1200;
case 1800: return B1800;
case 2400: return B2400;
case 4800: return B4800;
case 9600: return B9600;
case 19200: return B19200;
case 38400: return B38400;
case 57600: return B57600;
case 115200: return B115200;
case 230400: return B230400;
case 460800: return B460800;
case 500000: return B500000;
case 576000: return B576000;
case 921600: return B921600;
case 1000000: return B1000000;
case 1152000: return B1152000;
case 1500000: return B1500000;
case 2000000: return B2000000;
case 2500000: return B2500000;
case 3000000: return B3000000;
case 3500000: return B3500000;
case 4000000: return B4000000;
default: return -1;
}
}
/*
* Class: android_serialport_SerialPort
* Method: open
* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_com_kongqw_serialportlibrary_SerialPort_open
(JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags)
{
int fd;
speed_t speed;
jobject mFileDescriptor;
/* Check arguments */
{
speed = getBaudrate(baudrate);
if (speed == -1) {
/* TODO: throw an exception */
LOGE("Invalid baudrate");
return NULL;
}
}
/* Opening device */
{
jboolean iscopy;
const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
fd = open(path_utf, O_RDWR | flags);
LOGD("open() fd = %d", fd);
(*env)->ReleaseStringUTFChars(env, path, path_utf);
if (fd == -1)
{
/* Throw an exception */
LOGE("Cannot open port");
/* TODO: throw an exception */
return NULL;
}
}
/* Configure device */
{
struct termios cfg;
LOGD("Configuring serial port");
if (tcgetattr(fd, &cfg))
{
LOGE("tcgetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
}
cfmakeraw(&cfg);
cfsetispeed(&cfg, speed);
cfsetospeed(&cfg, speed);
if (tcsetattr(fd, TCSANOW, &cfg))
{
LOGE("tcsetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
}
}
/* Create a corresponding file descriptor */
{
jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
(*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);
}
return mFileDescriptor;
}
/*
* Class: cedric_serial_SerialPort
* Method: close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_kongqw_serialportlibrary_SerialPort_close
(JNIEnv *env, jobject thiz)
{
jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");
jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");
jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);
LOGD("close(fd = %d)", descriptor);
close(descriptor);
}

30
lib-serialport/src/main/cpp/SerialPort.h

@ -0,0 +1,30 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_serialport_api_SerialPort */
#ifndef _Included_qingwei_kong_serialportlibrary_SerialPort
#define _Included_qingwei_kong_serialportlibrary_SerialPort
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: android_serialport_api_SerialPort
* Method: open
* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_com_kongqw_serialportlibrary_SerialPort_open
(JNIEnv *, jclass, jstring, jint, jint);
/*
* Class: android_serialport_api_SerialPort
* Method: close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_kongqw_serialportlibrary_SerialPort_close
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

48
lib-serialport/src/main/java/com/kongqw/serialportlibrary/Device.java

@ -0,0 +1,48 @@
package com.kongqw.serialportlibrary;
import java.io.File;
import java.io.Serializable;
/**
* Created by Kongqw on 2017/11/13.
* Device
*/
public class Device implements Serializable{
private static final String TAG = Device.class.getSimpleName();
private String name;
private String root;
private File file;
public Device(String name, String root, File file) {
this.name = name;
this.root = root;
this.file = file;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRoot() {
return root;
}
public void setRoot(String root) {
this.root = root;
}
public File getFile() {
return file;
}
public void setFile(File path) {
this.file = file;
}
}

54
lib-serialport/src/main/java/com/kongqw/serialportlibrary/Driver.java

@ -0,0 +1,54 @@
package com.kongqw.serialportlibrary;
import android.util.Log;
import java.io.File;
import java.util.ArrayList;
/**
* Created by Kongqw on 2017/11/13.
* Driver
*/
public class Driver {
private static final String TAG = Driver.class.getSimpleName();
private String mDriverName;
private String mDeviceRoot;
public Driver(String name, String root) {
mDriverName = name;
mDeviceRoot = root;
}
public ArrayList<File> getDevices() {
ArrayList<File> devices = new ArrayList<>();
File dev = new File("/dev");
if (!dev.exists()) {
Log.i(TAG, "getDevices: " + dev.getAbsolutePath() + " 不存在");
return devices;
}
if (!dev.canRead()) {
Log.i(TAG, "getDevices: " + dev.getAbsolutePath() + " 没有读取权限");
return devices;
}
File[] files = dev.listFiles();
int i;
for (i = 0; i < files.length; i++) {
if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {
Log.d(TAG, "Found new device: " + files[i]);
devices.add(files[i]);
}
}
return devices;
}
public String getName() {
return mDriverName;
}
}

47
lib-serialport/src/main/java/com/kongqw/serialportlibrary/SerialPort.java

@ -0,0 +1,47 @@
package com.kongqw.serialportlibrary;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
public class SerialPort {
static {
System.loadLibrary("SerialPort");
}
private static final String TAG = SerialPort.class.getSimpleName();
/**
* 文件设置最高权限 777 可读 可写 可执行
*
* @param file 文件
* @return 权限修改是否成功
*/
boolean chmod777(File file) {
if (null == file || !file.exists()) {
// 文件不存在
return false;
}
try {
// 获取ROOT权限
Process su = Runtime.getRuntime().exec("/system/bin/su");
// 修改文件属性为 [可读 可写 可执行]
String cmd = "chmod 777 " + file.getAbsolutePath() + "\n" + "exit\n";
su.getOutputStream().write(cmd.getBytes());
if (0 == su.waitFor() && file.canRead() && file.canWrite() && file.canExecute()) {
return true;
}
} catch (IOException | InterruptedException e) {
// 没有ROOT权限
e.printStackTrace();
}
return false;
}
// 打开串口
protected native FileDescriptor open(String path, int baudRate, int flags);
// 关闭串口
protected native void close();
}

66
lib-serialport/src/main/java/com/kongqw/serialportlibrary/SerialPortFinder.java

@ -0,0 +1,66 @@
package com.kongqw.serialportlibrary;
import android.util.Log;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.ArrayList;
public class SerialPortFinder {
private static final String TAG = SerialPortFinder.class.getSimpleName();
private static final String DRIVERS_PATH = "/proc/tty/drivers";
private static final String SERIAL_FIELD = "serial";
public SerialPortFinder() {
File file = new File(DRIVERS_PATH);
boolean b = file.canRead();
Log.i(TAG, "SerialPortFinder: file.canRead() = " + b);
}
/**
* 获取 Drivers
*
* @return Drivers
* @throws IOException IOException
*/
private ArrayList<Driver> getDrivers() throws IOException {
ArrayList<Driver> drivers = new ArrayList<>();
LineNumberReader lineNumberReader = new LineNumberReader(new FileReader(DRIVERS_PATH));
String readLine;
while ((readLine = lineNumberReader.readLine()) != null) {
String driverName = readLine.substring(0, 0x15).trim();
String[] fields = readLine.split(" +");
if ((fields.length >= 5) && (fields[fields.length - 1].equals(SERIAL_FIELD))) {
Log.d(TAG, "Found new driver " + driverName + " on " + fields[fields.length - 4]);
drivers.add(new Driver(driverName, fields[fields.length - 4]));
}
}
return drivers;
}
/**
* 获取串口
*
* @return 串口
*/
public ArrayList<Device> getDevices() {
ArrayList<Device> devices = new ArrayList<>();
try {
ArrayList<Driver> drivers = getDrivers();
for (Driver driver : drivers) {
String driverName = driver.getName();
ArrayList<File> driverDevices = driver.getDevices();
for (File file : driverDevices) {
String devicesName = file.getName();
devices.add(new Device(devicesName, driverName, file));
}
}
} catch (IOException e) {
e.printStackTrace();
}
return devices;
}
}

187
lib-serialport/src/main/java/com/kongqw/serialportlibrary/SerialPortManager.java

@ -0,0 +1,187 @@
package com.kongqw.serialportlibrary;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import com.kongqw.serialportlibrary.listener.OnSerialPortDataListener;
import com.kongqw.serialportlibrary.thread.SerialPortReadThread;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by Kongqw on 2017/11/13.
* SerialPortManager
*/
public class SerialPortManager extends SerialPort {
private static final String TAG = SerialPortManager.class.getSimpleName();
private FileInputStream mFileInputStream;
private FileOutputStream mFileOutputStream;
private FileDescriptor mFd;
private OnSerialPortDataListener mOnSerialPortDataListener;
private HandlerThread mSendingHandlerThread;
private Handler mSendingHandler;
private SerialPortReadThread mSerialPortReadThread;
/**
* 打开串口
*
* @param device 串口设备
* @param baudRate 波特率
* @return 打开是否成功
*/
public boolean openSerialPort(File device, int baudRate) {
Log.i(TAG, "openSerialPort: " + String.format("打开串口 %s 波特率 %s", device.getPath(), baudRate));
// 校验串口权限
if (!device.canRead() || !device.canWrite()) {
boolean chmod777 = chmod777(device);
if (!chmod777) {
Log.i(TAG, "openSerialPort: 没有读写权限");
return false;
}
}
try {
mFd = open(device.getAbsolutePath(), baudRate, 0);
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
Log.i(TAG, "openSerialPort: 串口已经打开 " + mFd);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 关闭串口
*/
public void closeSerialPort() {
if (null != mFd) {
close();
mFd = null;
}
// 停止发送消息的线程
stopSendThread();
// 停止接收消息的线程
stopReadThread();
if (null != mFileInputStream) {
try {
mFileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
mFileInputStream = null;
}
if (null != mFileOutputStream) {
try {
mFileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
mFileOutputStream = null;
}
mOnSerialPortDataListener = null;
}
/**
* 添加数据通信监听
*
* @param listener listener
* @return SerialPortManager
*/
public SerialPortManager setOnSerialPortDataListener(OnSerialPortDataListener listener) {
mOnSerialPortDataListener = listener;
return this;
}
/**
* 开启发送消息的线程
*/
public void startSendThread() {
// 开启发送消息的线程
mSendingHandlerThread = new HandlerThread("mSendingHandlerThread");
mSendingHandlerThread.start();
// Handler
mSendingHandler = new Handler(mSendingHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
byte[] sendBytes = (byte[]) msg.obj;
if (null != mFileOutputStream && null != sendBytes && 0 < sendBytes.length) {
try {
mFileOutputStream.write(sendBytes);
if (null != mOnSerialPortDataListener) {
mOnSerialPortDataListener.onDataSent(sendBytes);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
}
/**
* 停止发送消息线程
*/
public void stopSendThread() {
mSendingHandler = null;
if (null != mSendingHandlerThread) {
mSendingHandlerThread.interrupt();
mSendingHandlerThread.quit();
mSendingHandlerThread = null;
}
}
/**
* 开启接收消息的线程
*/
public void startReadThread(int type) {
mSerialPortReadThread = new SerialPortReadThread(mFileInputStream, type) {
@Override
public void onDataReceived(byte[] bytes) {
if (null != mOnSerialPortDataListener) {
mOnSerialPortDataListener.onDataReceived(bytes);
}
}
};
mSerialPortReadThread.startRead();
}
/**
* 停止接收消息的线程
*/
public void stopReadThread() {
if (null != mSerialPortReadThread) {
mSerialPortReadThread.stopRead();
}
}
/**
* 发送数据
*
* @param sendBytes 发送数据
* @return 发送是否成功
*/
public boolean sendBytes(byte[] sendBytes) {
if (null != mFd && null != mFileInputStream && null != mFileOutputStream) {
if (null != mSendingHandler) {
Message message = Message.obtain();
message.obj = sendBytes;
return mSendingHandler.sendMessage(message);
}
}
return false;
}
}

23
lib-serialport/src/main/java/com/kongqw/serialportlibrary/listener/OnSerialPortDataListener.java

@ -0,0 +1,23 @@
package com.kongqw.serialportlibrary.listener;
/**
* Created by Kongqw on 2017/11/14.
* 串口消息监听
*/
public interface OnSerialPortDataListener {
/**
* 数据接收
*
* @param bytes 接收到的数据
*/
void onDataReceived(byte[] bytes);
/**
* 数据发送
*
* @param bytes 发送的数据
*/
void onDataSent(byte[] bytes);
}

231
lib-serialport/src/main/java/com/kongqw/serialportlibrary/thread/SerialPortReadThread.java

@ -0,0 +1,231 @@
package com.kongqw.serialportlibrary.thread;
import android.util.Log;
import com.kongqw.serialportlibrary.utils.ByteUtils;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by Kongqw on 2017/11/14.
* 串口消息读取线程
*/
public abstract class SerialPortReadThread extends Thread {
public abstract void onDataReceived(byte[] bytes);
private InputStream mInputStream;
private final byte[] mReadBuffer;
public boolean isStopThread = false;
private int type = 0;
public SerialPortReadThread(InputStream inputStream, int type) {
mInputStream = inputStream;
mReadBuffer = new byte[1024];
this.type = type;
}
@Override
public void run() {
super.run();
if (type == 485) {
Log.e("ReadThread", "type 485");
while (!isStopThread) {
try {
if (null == mInputStream) {
return;
}
Log.e("ReadThread", "type 1111");
int size = mInputStream.read(mReadBuffer);
Log.e("ReadThread size", size + "");
if (size <= 0) {
return;
}
Log.e("ReadThread", "type 2222");
byte[] readBytes = new byte[size];
System.arraycopy(mReadBuffer, 0, readBytes, 0, size);
onDataReceived(readBytes);
Log.e("ReadThread", "onDataReceived");
} catch (IOException e) {
e.printStackTrace();
return;
}
}
} else {
int rLen = 0;
int dLen = 0;
byte[] crc = new byte[]{0};
byte[] tmp1 = new byte[]{0};
byte[] tmp2 = new byte[]{0};
while (!isStopThread) {
try {
if (mInputStream == null) {
return;
}
if (!isHead()) {
continue;
}
crc[0] = 0x55;
crc[0] ^= 0xAA;
//接收 cmd
rLen = recvBuffer(tmp1, 1, 600);
if (rLen != 1) {
continue;
}
crc[0] ^= tmp1[0];
if (tmp1[0] == 0x30) {
//接收 数据长度
rLen = recvBuffer(tmp1, 1, 600);
if (rLen != 1) {
continue;
}
//接收 数据长度
rLen = recvBuffer(tmp2, 1, 600);
if (rLen != 1) {
continue;
}
crc[0] ^= tmp1[0];
crc[0] ^= tmp2[0];
dLen = tmp1[0] & 0xff;
dLen |= ((tmp2[0] << 8) & 0xffff);
//dLen = ((uint)(tmp1[0])) | (tmp2[0] << 8);
byte[] data = new byte[dLen];
if (dLen > 0) {
rLen = recvBuffer(data, dLen, 600);
if (rLen != dLen) {
continue;
}
}
//接收 crc
rLen = recvBuffer(tmp1, 1, 600);
if (rLen != 1) {
continue;
}
for (int i = 0; i < dLen; i++) {
crc[0] ^= data[i];
}
//crc校验
if (!ByteUtils.bytesToHexString(tmp1).equals(ByteUtils.bytesToHexString(crc))) {
continue;
}
onDataReceived(data);
} else {
Log.e("idhead", "no 0x30");
}
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
}
public void startRead() {
isStopThread = false;
start();
}
public void stopRead() {
isStopThread = true;
}
/**
* 关闭线程 释放资源
*/
public void release() {
stopRead();
if (null != mInputStream) {
try {
mInputStream.close();
mInputStream = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
private int recvBuffer(byte[] buffer, int size, int msTimeout) {
long stime = System.currentTimeMillis();
int rLen = 0, offset = 0;
byte[] rBuffer = new byte[1024];
byte[] cache = new byte[1024];
try {
do {
if (mInputStream.available() <= 0) {
Thread.sleep(10);
continue;
}
rLen = mInputStream.read(rBuffer, 0, Math.min(size, rBuffer.length));
if (rLen <= 0) {
Thread.sleep(10);
continue;
}
stime = System.currentTimeMillis();
if (offset + rLen > cache.length) {
byte[] tmp = new byte[offset];
System.arraycopy(cache, 0, tmp, 0, offset);
cache = new byte[(offset + rLen) * 2];
System.arraycopy(tmp, 0, cache, 0, offset);
}
System.arraycopy(rBuffer, 0, cache, offset, rLen);
offset += rLen;
if (offset >= size) {
System.arraycopy(cache, 0, buffer, 0, size);
break;
}
} while (msTimeout > 0 && System.currentTimeMillis() - stime < msTimeout);
} catch (Exception e) {
return offset;
}
return offset;
}
private boolean isHead() {
byte[] head1 = new byte[]{0};
byte[] head2 = new byte[]{0};
while (true) {
if (head1[0] != (byte) 0x55) {
int rLen = recvBuffer(head1, 1, 500);
if (rLen != 1) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
continue;
}
}
int rLen = recvBuffer(head2, 1, 500);
if (rLen != 1) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
continue;
}
if (head1[0] != (byte) 0x55) {
head1[0] = head2[0];
continue;
}
if (head2[0] != (byte) 0xAA) {
head1[0] = head2[0];
continue;
}
return true;
}
}
}

487
lib-serialport/src/main/java/com/kongqw/serialportlibrary/utils/ByteUtils.java

@ -0,0 +1,487 @@
package com.kongqw.serialportlibrary.utils;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
/**
* @author wangsir
* <p>
* 2017年9月21日
*/
public class ByteUtils {
/**
* 将int转为高端字节序排列的byte数组Java内存存放顺序
*
* @param n
* @return
*/
public static byte[] int2ByteArray(int n) {
byte[] byteArray = null;
try {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(byteOut);
dataOut.writeInt(n);
byteArray = byteOut.toByteArray();
Arrays.toString(byteArray);
} catch (IOException e) {
e.printStackTrace();
}
return byteArray;
}
/**
* 将int转为高字节在前低字节在后的byte数组
*
* @param n int
* @return byte[]
*/
public static byte[] int2Hbytes(int n) {
byte[] b = new byte[4];
b[3] = (byte) (n & 0xff);
b[2] = (byte) (n >> 8 & 0xff);
b[1] = (byte) (n >> 16 & 0xff);
b[0] = (byte) (n >> 24 & 0xff);
return b;
}
/**
* 将int转为高字节在前低字节在后的byte数组,一字节
*
* @param n int
* @return byte[]
*/
public static byte[] int2Hbytes1byte(int n) {
byte[] b = new byte[1];
b[0] = (byte) (n & 0xff);
return b;
}
/**
* 将short转为高字节在前低字节在后的byte数组
*
* @param n short
* @return byte[]
*/
public static byte[] short2Hbytes(short n) {
byte[] b = new byte[2];
b[1] = (byte) (n & 0xff);
b[0] = (byte) (n >> 8 & 0xff);
return b;
}
/**
* 以下 是整型数 网络字节序的 byte[] 数组之间的转换
*
* @param n
* @return
*/
public static byte[] long2Hbytes(long n) {
byte[] b = new byte[8];
b[7] = (byte) (n & 0xff);
b[6] = (byte) (n >> 8 & 0xff);
b[5] = (byte) (n >> 16 & 0xff);
b[4] = (byte) (n >> 24 & 0xff);
b[3] = (byte) (n >> 32 & 0xff);
b[2] = (byte) (n >> 40 & 0xff);
b[1] = (byte) (n >> 48 & 0xff);
b[0] = (byte) (n >> 56 & 0xff);
return b;
}
public static byte[] long2H6bytes(long n) {
byte[] b = new byte[6];
b[5] = (byte) (n & 0xff);
b[4] = (byte) (n >> 8 & 0xff);
b[3] = (byte) (n >> 16 & 0xff);
b[2] = (byte) (n >> 24 & 0xff);
b[1] = (byte) (n >> 32 & 0xff);
b[0] = (byte) (n >> 40 & 0xff);
return b;
}
public static byte[] long2H4bytes(long n) {
byte[] b = new byte[4];
b[3] = (byte) (n & 0xff);
b[2] = (byte) (n >> 8 & 0xff);
b[1] = (byte) (n >> 16 & 0xff);
b[0] = (byte) (n >> 24 & 0xff);
return b;
}
public static byte[] unlong2H4bytes(long n) {
byte[] b = new byte[4];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
b[2] = (byte) (n >> 16 & 0xff);
b[3] = (byte) (n >> 24 & 0xff);
return b;
}
/**
* 合并数组
*
* @param first
* @param rest
* @return
*/
public static byte[] concatBytes(byte[] first, byte[]... rest) {
int totalLength = first.length;
for (byte[] array : rest) {
if (null != array) {
totalLength += array.length;
}
}
byte[] result = Arrays.copyOf(first, totalLength);
int offset = first.length;
for (byte[] array : rest) {
if (null != array) {
System.arraycopy(array, 0, result, offset, array.length);
offset += array.length;
}
}
return result;
}
/**
* byte数组转为十六进制字符串
*
* @param bytes
* @return
*/
public static String byte2Hex(byte[] bytes) {
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xff & bytes[i]);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
/**
* Convert hex string to byte[]
*
* @param hexString the hex string
* @return byte[]
*/
public static byte[] hex2Byte(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase().replace(" ", "");
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
/**
* Convert char to byte
*
* @param c char
* @return byte
*/
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
/**
* 输入流转为字节数组
*/
public static byte[] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
return output.toByteArray();
}
/**
* bytes字符串转换为Byte值
*
* @param src src Byte字符串每个Byte之间没有分隔符
* @return byte[]
*/
public static byte[] hexStr2Bytes(String src) {
int m = 0, n = 0;
int l = src.length() / 2;
byte[] ret = new byte[l];
for (int i = 0; i < l; i++) {
m = i * 2 + 1;
n = m + 1;
ret[i] = Byte.decode("0x" + src.substring(i * 2, m) + src.substring(m, n));
}
return ret;
}
// /**
// * 字节数组转换成16进制字符串
// * @param bytes 字节数组
// * @return 16进制字符串
// */
// public static String hexEncode(byte[] bytes) {
// if (bytes == null || bytes.length <= 0) {
// return null;
// }
// return new String(Hex.encodeHex(bytes)); //Hex.encodeHex(bytes, false)
// }
//
// /**
// * 16进制字符串转换成字节数组
// * @param hexStr 16进制字符串
// * @return 字节数组
// */
// public static byte[] hexDecode(String hexStr) {
// if (hexStr == null || "".equals(hexStr)) {
// return null;
// }
// try {
// char[] cs = hexStr.toCharArray();
// return Hex.decodeHex(cs);
// } catch (DecoderException e) {
// e.printStackTrace();
// }
// return null;
// }
/**
* 字符串转换成十六进制字符串
*
* @param s s为待转换的ASCII字符串
*/
public static String str2HexStr(String s) {
String str = "";
for (int i = 0; i < s.length(); i++) {
int ch = (int) s.charAt(i);
String s4 = Integer.toHexString(ch);
str = str + s4;
}
return str;
}
public static String int2HexStr(Integer n) {
String str = Integer.toHexString(n);
while (str.length() < 18) {
str = "0" + str;
}
return str.toUpperCase();
}
public static String binaryToHex(String bin) {
String str = Long.toHexString(Long.parseLong(bin, 2));
while (str.length() < 4) {
str = "0" + str;
}
return str.toUpperCase();
}
/**
* 16进制的字符串转byte数组
*
* @param src
* @return
*/
public static byte[] str16ToBytes(String src) {
int w = 0;
byte[] bytes_2 = new byte[src.length() / 2];
for (int i = 0; i < src.length(); i++) {
String zz = src.substring(i, i + 2);
byte aaa = (byte) Integer.parseInt(zz, 16);
bytes_2[w] = aaa;
i++;
w = w + 1;
}
return bytes_2;
}
/**
* 16进制转10进制数字
*
* @param src
* @return
*/
public static int str16ToInt10(String src) {
return Integer.parseInt(src, 16);
}
/**
* 16进制转10进制数字
*
* @param src
* @return
*/
public static long str16ToLong10(String src) {
return Long.parseLong(src, 16);
}
public static String convertStringToHex(String str) {
char[] chars = str.toCharArray();
StringBuffer hex = new StringBuffer();
for (int i = 0; i < chars.length; i++) {
hex.append(Integer.toHexString((int) chars[i]));
}
return hex.toString();
}
public static String convertHexToString(String hex) {
hex = hex.replace(" ", "");
StringBuilder sb = new StringBuilder();
StringBuilder temp = new StringBuilder();
//49204c6f7665204a617661 split into two characters 49, 20, 4c...
for (int i = 0; i < hex.length() - 1; i += 2) {
//grab the hex in pairs
String output = hex.substring(i, (i + 2));
//convert hex to decimal
int decimal = Integer.parseInt(output, 16);
//convert the decimal to character
sb.append((char) decimal);
temp.append(decimal);
}
return sb.toString();
}
/**
* @param
* @ClassName
* @Description : 功能说明
* @Return :
* @Author : li
* @Date : 2021/3/25 13:48
*/
public static byte[] hexStringToByteArray(String hexString) {
hexString = hexString.replaceAll(" ", "");
int len = hexString.length();
byte[] bytes = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
// 两位一组表示一个字节,把这样表示的16进制字符串还原成一个字节
bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
.digit(hexString.charAt(i + 1), 16));
}
return bytes;
}
/**
* @param
* @ClassName
* @Description : 功能说明
* @Return :
* @Author : li
* @Date : 2021/3/25 13:48
*/
public static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
/**
* 从16进制字符串中获取2进制为1的序列号
*
* @param src
* @return
*/
public static ArrayList Str16Get1(String src) {
byte[] b_p = ByteUtils.str16ToBytes(src);
ArrayList list = new ArrayList<>();
int w = 0;
for (int i = 0; i < src.length() / 2; i++) {
for (int j = 7; j >= 0; j--) {
if ((b_p[i] & (1 << j)) != 0) {
int pp = i * 8 + 8 - j;
System.out.println("pppp=======" + pp);
list.add(w, pp);
w = w + 1;
} else {
}
}
}
return list;
}
/**
* 异或校验
*
* @param bytes
* @return
*/
public static byte[] bytesXorCrc(byte[] bytes) {
byte[] crc = new byte[1];// 异或校验
crc[0] = bytes[0];
for (int i = 1; i < bytes.length; i++) {
crc[0] ^= bytes[i];
}
return crc;
}
/**
* 和校验
*
* @param data
* @return
*/
public static String makeChecksum(String data) {
data = data.replace(" ", "");
if (data == null || data.equals("")) {
return "";
}
int total = 0;
int len = data.length();
int num = 0;
while (num < len) {
String s = data.substring(num, num + 2);
total += Integer.parseInt(s, 16);
num = num + 2;
}
/**
* 用256求余最大是255即16进制的FF
*/
int mod = total % 256;
String hex = Integer.toHexString(mod);
len = hex.length();
// 如果不够校验位的长度补0,这里用的是两位校验
if (len < 2) {
hex = "0" + hex;
}
hex = hex.toUpperCase();
if (hex.equals("7E")) {
hex = "7F 01";
} else if (hex.equals("7F")) {
hex = "7F 02";
}
return hex;
}
}

3
lib-serialport/src/main/res/values/strings.xml

@ -0,0 +1,3 @@
<resources>
<string name="app_name">SerialPortLibrary</string>
</resources>

3
settings.gradle

@ -25,4 +25,5 @@ include ':app'
include ':facelibrary'
include ':financelibrary'
include ':datalibrary'
include ':oxplugin_padface'
// include ':oxplugin_padface'
include ':lib-serialport'
Loading…
Cancel
Save