Browse Source

add Ox485

dev
赵明涛 2 days ago
parent
commit
911d70f21a
  1. 3
      app/build.gradle
  2. 83
      app/src/main/java/com/ouxuan/oxface/DebugActivity.java
  3. 118
      app/src/main/java/com/ouxuan/oxface/device/GateABController.java
  4. 406
      app/src/main/java/com/ouxuan/oxface/device/Ox485.java
  5. 7
      app/src/main/res/layout/activity_debug.xml

3
app/build.gradle

@ -91,6 +91,9 @@ dependencies {
// //
implementation "com.huawei.hms:scanplus:2.12.0.301" implementation "com.huawei.hms:scanplus:2.12.0.301"
//
implementation 'com.github.kongqw:SerialPortLibrary:2.1.1'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.ext:junit:1.1.5'

83
app/src/main/java/com/ouxuan/oxface/DebugActivity.java

@ -22,8 +22,9 @@ import com.baidu.idl.face.main.finance.listener.SdkInitListener;
import com.baidu.idl.face.main.finance.manager.FaceSDKManager; import com.baidu.idl.face.main.finance.manager.FaceSDKManager;
import com.ouxuan.oxface.device.DeviceUtils; import com.ouxuan.oxface.device.DeviceUtils;
import com.ouxuan.oxface.device.GateABController;
import com.ouxuan.oxface.device.HuaWeiScanManager; import com.ouxuan.oxface.device.HuaWeiScanManager;
import com.ouxuan.oxface.device.OxGpio;
import com.ouxuan.oxface.device.Ox485;
import com.ouxuan.oxface.device.RelayController; import com.ouxuan.oxface.device.RelayController;
import com.ouxuan.oxface.network.utils.NetworkUtils; import com.ouxuan.oxface.network.utils.NetworkUtils;
import com.ouxuan.oxface.utils.AutoStartManager; import com.ouxuan.oxface.utils.AutoStartManager;
@ -42,7 +43,8 @@ public class DebugActivity extends Activity {
private ScrollView logScrollView; private ScrollView logScrollView;
private AutoStartManager autoStartManager; private AutoStartManager autoStartManager;
private RelayController relayController; private RelayController relayController;
private OxGpio oxGpio;
private Ox485 ox485;
private GateABController gateABController;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -65,8 +67,10 @@ public class DebugActivity extends Activity {
private void initManagers() { private void initManagers() {
autoStartManager = AutoStartManager.getInstance(this); autoStartManager = AutoStartManager.getInstance(this);
relayController = RelayController.getInstance(); relayController = RelayController.getInstance();
oxGpio = OxGpio.getInstance();
oxGpio.initialize(this);
ox485 = Ox485.getInstance();
ox485.initialize(this);
gateABController = GateABController.getInstance();
gateABController.initialize(this);
} }
private void setupClickListeners() { private void setupClickListeners() {
@ -251,6 +255,15 @@ public class DebugActivity extends Activity {
test485PeopleNum(); test485PeopleNum();
} }
}); });
// AB门485测试按钮
Button btnTestGateAB485 = findViewById(R.id.btnTestGateAB485);
btnTestGateAB485.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testGateAB485PeopleNum();
}
});
} }
/** /**
@ -720,19 +733,19 @@ public class DebugActivity extends Activity {
private void test485PeopleNum() { private void test485PeopleNum() {
logMessage("开始485人数测试..."); logMessage("开始485人数测试...");
if (oxGpio == null) {
logMessage("OxGpio未初始化");
showToast("OxGpio未初始化");
if (ox485 == null) {
logMessage("Ox485未初始化");
showToast("Ox485未初始化");
return; return;
} }
try { try {
// 设置485模式开关为启用状态 // 设置485模式开关为启用状态
oxGpio.setGateCamera485OxOn(true);
ox485.setGateCamera485OxOn(true);
logMessage("已启用485模式"); logMessage("已启用485模式");
// 调用sendHex485ForPeopleNum方法 // 调用sendHex485ForPeopleNum方法
oxGpio.sendHex485ForPeopleNum(new OxGpio.PeopleNumCallback() {
ox485.sendHex485ForPeopleNum(new Ox485.PeopleNumCallback() {
@Override @Override
public void onSuccess(int peopleNum) { public void onSuccess(int peopleNum) {
logMessage("485人数获取成功: " + peopleNum + " 人"); logMessage("485人数获取成功: " + peopleNum + " 人");
@ -757,4 +770,56 @@ public class DebugActivity extends Activity {
showToast("485人数测试失败"); showToast("485人数测试失败");
} }
} }
/**
* 测试GateABController的485人数获取功能
*/
private void testGateAB485PeopleNum() {
logMessage("开始测试GateAB控制器485人数获取...");
if (gateABController == null) {
logMessage("GateABController未初始化");
showToast("GateABController未初始化");
return;
}
try {
// 获取当前配置信息
GateABController.GateABConfig config = gateABController.getCurrentConfig();
logMessage("AB门当前配置 - 485模式: " + config.gateCamera485OXOn);
// 检查485模式状态
boolean is485Enabled = gateABController.is485ModeEnabled();
logMessage("485模式状态: " + (is485Enabled ? "已启用" : "未启用"));
// 获取485状态信息
String status485 = gateABController.get485Status();
logMessage("485状态信息: " + status485);
// 调用GateABController的get485PeopleNum方法
gateABController.get485PeopleNum(new GateABController.PeopleNumCallback() {
@Override
public void onSuccess(int peopleNum) {
logMessage("GateAB 485人数获取成功: " + peopleNum + " 人");
Log.i(TAG, "GateAB 485人数获取成功: " + peopleNum + " 人");
showToast("GateAB 485人数获取成功: " + peopleNum + " 人");
}
@Override
public void onError(String errorMessage) {
logMessage("GateAB 485人数获取失败: " + errorMessage);
Log.e(TAG, "GateAB 485人数获取失败: " + errorMessage);
showToast("GateAB 485人数获取失败: " + errorMessage);
}
});
logMessage("已通过GateABController发送485人数查询请求,等待响应...");
showToast("通过GateAB查询485人数...");
} catch (Exception e) {
Log.e(TAG, "GateAB 485人数测试失败", e);
logMessage("GateAB 485人数测试失败: " + e.getMessage());
showToast("GateAB 485人数测试失败");
}
}
} }

118
app/src/main/java/com/ouxuan/oxface/device/GateABController.java

@ -45,6 +45,9 @@ public class GateABController {
private RelayController relayController; private RelayController relayController;
private Object udpController; // 预留UDP控制器接口 private Object udpController; // 预留UDP控制器接口
// 485通信控制器
private Ox485 ox485;
// 网络API服务 // 网络API服务
private PadApiService acControlApiService; private PadApiService acControlApiService;
@ -108,6 +111,7 @@ public class GateABController {
syncHandler = new Handler(Looper.getMainLooper()); syncHandler = new Handler(Looper.getMainLooper());
executorService = Executors.newSingleThreadExecutor(); executorService = Executors.newSingleThreadExecutor();
relayController = RelayController.getInstance(); relayController = RelayController.getInstance();
ox485 = Ox485.getInstance();
currentConfig = new GateABConfig(); currentConfig = new GateABConfig();
// 初始化中控网络服务 // 初始化中控网络服务
@ -154,6 +158,9 @@ public class GateABController {
this.context = context; this.context = context;
this.deviceDataManager = DeviceSelectDataManager.getInstance(context); this.deviceDataManager = DeviceSelectDataManager.getInstance(context);
// 初始化485通信模块
ox485.initialize(context);
// 启动配置同步 // 启动配置同步
startConfigSync(); startConfigSync();
@ -516,6 +523,12 @@ public class GateABController {
// 更新当前配置 // 更新当前配置
currentConfig = newConfig; currentConfig = newConfig;
// 同步485配置到Ox485实例
if (ox485 != null) {
ox485.setGateCamera485OxOn(newConfig.gateCamera485OXOn);
LogManager.logInfo(TAG, "485配置已同步: " + newConfig.gateCamera485OXOn);
}
if (configChanged) { if (configChanged) {
LogManager.logInfo(TAG, "配置发生变化,已更新: " + currentConfig.toString()); LogManager.logInfo(TAG, "配置发生变化,已更新: " + currentConfig.toString());
logConfigurationChanges(oldConfig, newConfig); logConfigurationChanges(oldConfig, newConfig);
@ -562,6 +575,10 @@ public class GateABController {
relayController.release(); relayController.release();
} }
if (ox485 != null) {
ox485.release();
}
LogManager.logInfo(TAG, "GateABController资源已释放"); LogManager.logInfo(TAG, "GateABController资源已释放");
} }
@ -627,4 +644,105 @@ public class GateABController {
LogManager.logInfo(TAG, "=================="); LogManager.logInfo(TAG, "==================");
} }
// ==================== 485人数检测相关方法 ====================
/**
* 获取485摄像头人数
* 对应uniapp中sendHex485ForPeopleNum方法
* @param callback 结果回调
*/
public void get485PeopleNum(PeopleNumCallback callback) {
LogManager.logInfo(TAG, "开始获取485摄像头人数");
if (ox485 == null) {
String errorMsg = "Ox485未初始化";
LogManager.logError(TAG, errorMsg);
if (callback != null) {
syncHandler.post(() -> callback.onError(errorMsg));
}
return;
}
// 检查485模式是否已启用
if (!currentConfig.gateCamera485OXOn) {
String errorMsg = "485模式未开启,请检查配置";
LogManager.logWarning(TAG, errorMsg);
if (callback != null) {
syncHandler.post(() -> callback.onError(errorMsg));
}
return;
}
// 调用Ox485获取人数
ox485.sendHex485ForPeopleNum(new Ox485.PeopleNumCallback() {
@Override
public void onSuccess(int peopleNum) {
LogManager.logInfo(TAG, "485人数获取成功: " + peopleNum + " 人");
if (callback != null) {
callback.onSuccess(peopleNum);
}
}
@Override
public void onError(String errorMessage) {
LogManager.logError(TAG, "485人数获取失败: " + errorMessage);
if (callback != null) {
callback.onError(errorMessage);
}
}
});
}
/**
* 异步获取485摄像头人数使用CompletableFuture
* @return CompletableFuture<Integer> 人数结果
*/
public java.util.concurrent.CompletableFuture<Integer> get485PeopleNumAsync() {
LogManager.logInfo(TAG, "异步获取485摄像头人数");
java.util.concurrent.CompletableFuture<Integer> future = new java.util.concurrent.CompletableFuture<>();
get485PeopleNum(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模式是否已启用
* @return true表示485模式已启用
*/
public boolean is485ModeEnabled() {
return currentConfig != null && currentConfig.gateCamera485OXOn;
}
/**
* 获取485状态信息
* @return 485状态描述
*/
public String get485Status() {
if (ox485 != null) {
return ox485.get485Status();
} else {
return "Ox485未初始化";
}
}
/**
* 485人数检测回调接口
*/
public interface PeopleNumCallback {
void onSuccess(int peopleNum);
void onError(String errorMessage);
}
} }

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

@ -0,0 +1,406 @@
package com.ouxuan.oxface.device;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.kongqw.serialportlibrary.SerialPortManager;
import com.kongqw.serialportlibrary.listener.OnSerialPortDataListener;
import com.kongqw.serialportlibrary.utils.ByteUtils;
import com.ouxuan.oxface.utils.LogManager;
import java.io.File;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* Ox485 串口通信模块
* 基于kongqw/SerialPortLibrary实现485通信功能
* 主要用于获取摄像头人数等485设备通信
*
* @author AI Assistant
* @version 1.0
* @date 2024/09/12
*/
public class Ox485 {
private static final String TAG = "Ox485";
// 485通信配置
private static final String DEFAULT_SERIAL_PORT_PATH = "/dev/ttyS6";
private static final int DEFAULT_BAUD_RATE = 9600;
private static final int DEFAULT_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 Ox485 instance;
// 485通信相关
private SerialPortManager serialPortManager;
private Handler mainHandler;
private boolean gateCamera485OxOn = false;
private Context context;
// 数据接收相关
private long lastRecvTime = 0;
private Handler timeoutHandler;
private Runnable timeoutRunnable;
/**
* 485通信回调接口
*/
public interface PeopleNumCallback {
void onSuccess(int peopleNum);
void onError(String errorMessage);
}
private Ox485() {
mainHandler = new Handler(Looper.getMainLooper());
timeoutHandler = new Handler(Looper.getMainLooper());
serialPortManager = new SerialPortManager();
}
/**
* 获取Ox485单例实例
* @return Ox485实例
*/
public static Ox485 getInstance() {
if (instance == null) {
synchronized (Ox485.class) {
if (instance == null) {
instance = new Ox485();
}
}
}
return instance;
}
/**
* 初始化Ox485模块
* @param context 上下文
*/
public void initialize(Context context) {
this.context = context;
LogManager.logInfo(TAG, "Ox485模块初始化完成");
}
/**
* 设置485模式开关
* @param enabled 是否启用485模式
*/
public void setGateCamera485OxOn(boolean enabled) {
this.gateCamera485OxOn = 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;
}
try {
// 检查串口是否已经打开
if (serialPortManager.isOpen()) {
LogManager.logInfo(TAG, "串口已打开,直接发送命令");
sendCommandAndWaitResponse(callback);
} else {
LogManager.logInfo(TAG, "串口未打开,尝试打开串口");
openSerialPortAndSend(callback);
}
} catch (Exception e) {
String errorMsg = "485通信异常: " + e.getMessage();
LogManager.logError(TAG, errorMsg, e);
if (callback != null) {
mainHandler.post(() -> callback.onError(errorMsg));
}
}
}
/**
* 打开串口并发送命令
* @param callback 结果回调
*/
private void openSerialPortAndSend(PeopleNumCallback callback) {
try {
// 配置串口参数
File serialPortFile = new File(DEFAULT_SERIAL_PORT_PATH);
boolean openResult = serialPortManager.openSerialPort(serialPortFile, DEFAULT_BAUD_RATE);
LogManager.logInfo(TAG, "串口打开结果: " + openResult + ", 路径: " + DEFAULT_SERIAL_PORT_PATH + ", 波特率: " + DEFAULT_BAUD_RATE);
if (!openResult) {
String errorMsg = "打开串口失败: " + DEFAULT_SERIAL_PORT_PATH;
LogManager.logError(TAG, errorMsg);
if (callback != null) {
mainHandler.post(() -> callback.onError(errorMsg));
}
return;
}
// 启动读写线程
serialPortManager.startReadThread(485);
serialPortManager.startSendThread();
// 发送命令并等待响应
sendCommandAndWaitResponse(callback);
} catch (Exception e) {
String errorMsg = "打开串口异常: " + e.getMessage();
LogManager.logError(TAG, errorMsg, e);
if (callback != null) {
mainHandler.post(() -> callback.onError(errorMsg));
}
}
}
/**
* 发送命令并等待响应
* @param callback 结果回调
*/
private void sendCommandAndWaitResponse(PeopleNumCallback callback) {
// 设置数据监听器
serialPortManager.setOnSerialPortDataListener(new OnSerialPortDataListener() {
@Override
public void onDataReceived(byte[] bytes) {
long timeInterval = (System.nanoTime() - lastRecvTime) / 1000000;
lastRecvTime = System.nanoTime();
String hexData = ByteUtils.bytesToHexString(bytes);
LogManager.logInfo(TAG, "接收到数据: " + hexData + ", 字节数组: " + java.util.Arrays.toString(bytes));
// 取消超时处理
cancelTimeout();
// 解析人数数据
int peopleNum = get485PeopleNum(bytes);
if (peopleNum >= 0) {
LogManager.logInfo(TAG, "485获取人数成功: " + peopleNum);
if (callback != null) {
mainHandler.post(() -> callback.onSuccess(peopleNum));
}
} else {
String errorMsg = "485数据解析失败,数据: " + hexData;
LogManager.logError(TAG, errorMsg);
if (callback != null) {
mainHandler.post(() -> callback.onError(errorMsg));
}
}
}
@Override
public void onDataSent(byte[] bytes) {
String hexData = ByteUtils.bytesToHexString(bytes);
LogManager.logInfo(TAG, "发送数据: " + hexData);
}
});
// 发送HEX命令
try {
byte[] hexBytes = hexStringToByteArray(HEX_COMMAND_GET_PEOPLE_NUM);
serialPortManager.sendBytes(hexBytes);
LogManager.logInfo(TAG, "发送485人数查询命令: " + HEX_COMMAND_GET_PEOPLE_NUM);
// 设置超时处理
setupTimeout(callback);
} catch (Exception e) {
String errorMsg = "发送485命令异常: " + e.getMessage();
LogManager.logError(TAG, errorMsg, e);
if (callback != null) {
mainHandler.post(() -> callback.onError(errorMsg));
}
}
}
/**
* 设置超时处理
* @param callback 结果回调
*/
private void setupTimeout(PeopleNumCallback callback) {
cancelTimeout(); // 先取消之前的超时任务
timeoutRunnable = () -> {
String errorMsg = "485人数查询超时";
LogManager.logError(TAG, errorMsg);
if (callback != null) {
callback.onError(errorMsg);
}
};
timeoutHandler.postDelayed(timeoutRunnable, TIMEOUT_485_MILLIS);
}
/**
* 取消超时处理
*/
private void cancelTimeout() {
if (timeoutHandler != null && timeoutRunnable != null) {
timeoutHandler.removeCallbacks(timeoutRunnable);
timeoutRunnable = null;
}
}
/**
* 解析485人数数据
* 对应uniapp中的get485PeopleNum方法
* @param arr 接收到的字节数组
* @return 人数-1表示解析失败
*/
private int get485PeopleNum(byte[] arr) {
LogManager.logDebug(TAG, "解析485人数数据: " + java.util.Arrays.toString(arr));
// 数据校验
if (arr == null) {
LogManager.logError(TAG, "485数据为空");
return -1;
}
if (arr.length != 9) {
LogManager.logError(TAG, "485数据长度错误,期望9字节,实际: " + arr.length + ", 数据: " + java.util.Arrays.toString(arr));
return -1;
}
// 检查第3个字节是否为4表示正确响应
if (arr[2] != 4) {
LogManager.logError(TAG, "485响应格式错误,第3字节应为4,实际: " + arr[2] + ", 数据: " + java.util.Arrays.toString(arr));
return -1;
}
// 提取第5个字节作为人数数据使用位掩码确保为无符号整数
int peopleNum = arr[4] & 0xFF;
LogManager.logInfo(TAG, "解析485人数成功: " + peopleNum);
return peopleNum;
}
/**
* 异步获取摄像头人数使用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串口");
if (!serialPortManager.isOpen()) {
LogManager.logInfo(TAG, "串口未打开,需要打开");
} else {
LogManager.logInfo(TAG, "串口已打开");
}
}
/**
* 发送自定义485 HEX命令
* @param hexCommand HEX命令字符串
*/
public void send485HexCommand(String hexCommand) {
LogManager.logInfo(TAG, "发送485 HEX命令: " + hexCommand);
try {
if (!serialPortManager.isOpen()) {
LogManager.logError(TAG, "串口未打开,无法发送命令");
return;
}
byte[] hexBytes = hexStringToByteArray(hexCommand);
serialPortManager.sendBytes(hexBytes);
LogManager.logInfo(TAG, "485命令发送完成");
} catch (Exception e) {
LogManager.logError(TAG, "发送485命令异常: " + e.getMessage(), e);
}
}
/**
* 获取485串口状态
* @return 串口状态描述
*/
public String get485Status() {
boolean isOpen = serialPortManager.isOpen();
String status = "串口状态: " + (isOpen ? "已打开" : "已关闭") +
", 路径: " + DEFAULT_SERIAL_PORT_PATH +
", 波特率: " + DEFAULT_BAUD_RATE +
", 485模式: " + (gateCamera485OxOn ? "已启用" : "未启用");
LogManager.logInfo(TAG, status);
return status;
}
/**
* 关闭485串口
*/
public void close485SerialPort() {
LogManager.logInfo(TAG, "关闭485串口");
try {
cancelTimeout();
if (serialPortManager != null) {
serialPortManager.close();
LogManager.logInfo(TAG, "485串口已关闭");
}
} catch (Exception e) {
LogManager.logError(TAG, "关闭485串口异常: " + e.getMessage(), e);
}
}
/**
* 释放资源
*/
public void release() {
LogManager.logInfo(TAG, "释放Ox485资源");
close485SerialPort();
}
/**
* HEX字符串转字节数组
* @param hexString HEX字符串
* @return 字节数组
*/
private byte[] hexStringToByteArray(String hexString) {
int len = hexString.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ Character.digit(hexString.charAt(i + 1), 16));
}
return data;
}
}

7
app/src/main/res/layout/activity_debug.xml

@ -239,13 +239,14 @@
android:layout_marginEnd="4dp" android:layout_marginEnd="4dp"
android:textSize="12sp" /> android:textSize="12sp" />
<!-- 占位按钮,保持布局对称 -->
<Button <Button
android:id="@+id/btnTestGateAB485"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:visibility="invisible"
android:layout_marginStart="4dp" />
android:text="AB门485测试"
android:layout_marginStart="4dp"
android:textSize="12sp" />
</LinearLayout> </LinearLayout>

Loading…
Cancel
Save