diff --git a/app/src/main/java/com/ouxuan/oxface/device/OxGpio.java b/app/src/main/java/com/ouxuan/oxface/device/OxGpio.java deleted file mode 100644 index cb83707..0000000 --- a/app/src/main/java/com/ouxuan/oxface/device/OxGpio.java +++ /dev/null @@ -1,514 +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 Ox485 ox485; - 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()); - // 初始化Ox485实例 - ox485 = Ox485.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) { - // 初始化Ox485 - ox485.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; - ox485.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; - } - - // 使用Ox485进行通信 - ox485.sendHex485ForPeopleNum(new Ox485.PeopleNumCallback() { - @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 人数结果 - */ - public CompletableFuture sendHex485ForPeopleNumAsync() { - LogManager.logInfo(TAG, "异步获取摄像头人数"); - - CompletableFuture 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串口"); - ox485.checkIsNeedOpen485(); - } - - /** - * 发送自定义485 HEX命令 - * @param hexCommand HEX命令字符串 - */ - public void send485HexCommand(String hexCommand) { - LogManager.logInfo(TAG, "发送485 HEX命令: " + hexCommand); - // 使用Ox485的send485HexCommand方法 - ox485.send485HexCommand(hexCommand); - } - - /** - * 获取485串口状态 - * @return 串口状态描述 - */ - public String get485Status() { - // 使用Ox485的get485Status方法 - return ox485.get485Status(); - } - - /** - * 关闭485串口 - */ - public void close485SerialPort() { - LogManager.logInfo(TAG, "关闭485串口"); - // 使用Ox485的close485SerialPort方法 - ox485.close485SerialPort(); - } - - // ==================== 内部辅助方法 ==================== - - /** - * 申请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 (ox485 != null) { - ox485.release(); - } - } -} \ No newline at end of file