oxFaceAndroid
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

470 lines
16 KiB

package com.ouxuan.oxface.device;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.ouxuan.oxface.utils.LogManager;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
/**
* 继电器控制器
* 基于GPIO控制继电器的开关操作
*
* @author AI Assistant
* @version 1.0
* @date 2024/09/11
*/
public class RelayController {
private static final String TAG = "RelayController";
// 第6批设备-默认GPIO路径
private static final String PWM_FLASH_OUT = "/sys/class/gpio/gpio114/direction";
private static final String PWM_FLASH = "/sys/class/gpio/gpio114/value";
// 第2批设备GPIO路径
// private static final String PWM_FLASH_OUT_2 = "/sys/class/gpio/gpio123/direction";
// private static final String PWM_FLASH_2 = "/sys/class/gpio/gpio123/value";
private static final String PWM_FLASH_OUT_2 = "/sys/class/gpio/gpio154/direction";
private static final String PWM_FLASH_2 = "/sys/class/gpio/gpio154/value";
// 第7批设备GPIO路径
private static final String PWM_FLASH_OUT_7 = "/sys/class/gpio/gpio88/direction";
private static final String PWM_FLASH_7 = "/sys/class/gpio/gpio88/value";
// GPIO操作命令
private static final byte[] OPEN_RELAY = {'1'};
private static final byte[] CLOSE_RELAY = {'0'};
private static final byte[] GPIO_OUT = {'o', 'u', 't'};
private static final byte[] GPIO_IN = {'i', 'n'};
// 设备类型
public static final String PAD_TYPE_DEFAULT = "pad_default";
public static final String PAD_TYPE_TWO = "pad_two";
public static final String PAD_TYPE_SEVEN = "pad_seven";
// 单例实例
private static volatile RelayController instance;
// Handler用于延时操作
private Handler handler;
// 第七批设备管理器
private DeviceType7Manager deviceType7Manager;
// 当前设备类型(5=第6批,6=第7批等)
private int deviceType = -1;
private RelayController() {
handler = new Handler(Looper.getMainLooper());
}
/**
* 初始化第七批设备管理器
* @param context Android上下文
* @return 是否初始化成功
*/
public boolean initDeviceType7Manager(Context context) {
deviceType7Manager = DeviceType7Manager.getInstance();
boolean success = deviceType7Manager.init(context);
if (success) {
LogManager.logInfo(TAG, "第七批设备管理器初始化成功");
} else {
LogManager.logError(TAG, "第七批设备管理器初始化失败");
}
return success;
}
/**
* 根据设备类型获取GPIO值文件路径
* @param deviceType 设备类型(5=第6批,6=第7批等)
* @return GPIO值文件路径
*/
private String getGpioValuePath(int deviceType) {
switch (deviceType) {
case 5: // 第6批设备
return PWM_FLASH;
case 6: // 第7批设备
return PWM_FLASH_7;
case 2: // 第2批设备(兼容旧逻辑)
return PWM_FLASH_2;
default: // 默认使用第6批设备路径
return PWM_FLASH;
}
}
/**
* 根据设备类型获取GPIO方向文件路径
* @param deviceType 设备类型(5=第6批,6=第7批等)
* @return GPIO方向文件路径
*/
private String getGpioDirectionPath(int deviceType) {
switch (deviceType) {
case 5: // 第6批设备
return PWM_FLASH_OUT;
case 6: // 第7批设备
return PWM_FLASH_OUT_7;
case 2: // 第2批设备(兼容旧逻辑)
return PWM_FLASH_OUT_2;
default: // 默认使用第6批设备路径
return PWM_FLASH_OUT;
}
}
/**
* 获取当前设备类型(兼容性方法,返回字符串类型)
* @return 设备类型字符串
*/
private String getCurrentPadType() {
// 根据设备类型返回对应的padType
if (deviceType == 6) {
return PAD_TYPE_SEVEN; // deviceType=6表示第7批设备,使用DeviceType7Manager
} else if (deviceType == 5) {
return PAD_TYPE_TWO; // deviceType=5表示第6批设备,使用第2批的GPIO路径
} else {
// 其他情况返回默认
return PAD_TYPE_DEFAULT;
}
}
/**
* 获取RelayController单例实例
* @return RelayController实例
*/
public static RelayController getInstance() {
if (instance == null) {
synchronized (RelayController.class) {
if (instance == null) {
instance = new RelayController();
}
}
}
return instance;
}
/**
* 设置设备类型
* @param deviceType 设备类型(5=第6批,6=第7批等)
*/
public void setDeviceType(int deviceType) {
this.deviceType = deviceType;
LogManager.logInfo(TAG, "设置设备类型: " + deviceType);
}
/**
* 设置GPIO方向为输出模式
* @param padType 设备类型(保留兼容性)
*/
private void setGpioDirection(String padType) {
if (PAD_TYPE_SEVEN.equals(padType) && deviceType7Manager != null) {
// 第七批设备使用DeviceType7Manager
deviceType7Manager.setGpioDirection(DeviceType7Manager.YxGpioConstants.GPIO_RELAY,
DeviceType7Manager.YxGpioConstants.GPIO_DIRECTION_OUTPUT);
} else {
// 其他设备使用文件操作,根据deviceType动态获取路径
FileOutputStream fos = null;
try {
String directionPath = getGpioDirectionPath(deviceType);
fos = new FileOutputStream(directionPath);
fos.write(GPIO_OUT);
LogManager.logInfo(TAG, "GPIO方向设置为输出模式成功, 设备类型: " + deviceType + ", 路径: " + directionPath);
} catch (Exception e) {
LogManager.logError(TAG, "设置GPIO方向失败, 设备类型: " + deviceType, e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
LogManager.logError(TAG, "关闭FileOutputStream失败", e);
}
}
}
}
}
/**
* 设置GPIO方向为输入模式
* @param padType 设备类型(保留兼容性)
*/
private void setGpioDirectionInput(String padType) {
FileOutputStream fos = null;
try {
String directionPath = getGpioDirectionPath(deviceType);
fos = new FileOutputStream(directionPath);
fos.write(GPIO_IN);
LogManager.logInfo(TAG, "GPIO方向设置为输入模式成功, 设备类型: " + deviceType + ", 路径: " + directionPath);
} catch (Exception e) {
LogManager.logError(TAG, "设置GPIO方向为输入模式失败, 设备类型: " + deviceType, e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
LogManager.logError(TAG, "关闭FileOutputStream失败", e);
}
}
}
}
/**
* 读取GPIO值
* @param padType 设备类型(保留兼容性)
* @return GPIO值字符串,失败返回null
*/
public String readGpioValue(String padType) {
if (PAD_TYPE_SEVEN.equals(padType) && deviceType7Manager != null) {
// 第七批设备使用DeviceType7Manager
int value = deviceType7Manager.getGpioValue(DeviceType7Manager.YxGpioConstants.GPIO_RELAY);
if (value == -1) {
LogManager.logError(TAG, "DeviceType7Manager读取GPIO值失败");
return null;
} else {
String strValue = String.valueOf(value);
LogManager.logInfo(TAG, "DeviceType7Manager读取GPIO值成功: " + strValue);
return strValue;
}
} else {
// 其他设备使用文件操作,根据deviceType动态获取路径
BufferedReader reader = null;
try {
String valuePath = getGpioValuePath(deviceType);
reader = new BufferedReader(new FileReader(valuePath));
String value = reader.readLine();
LogManager.logInfo(TAG, "读取GPIO值成功: " + value + ", 设备类型: " + deviceType + ", 路径: " + valuePath);
return value;
} catch (IOException e) {
LogManager.logError(TAG, "读取GPIO值失败, 设备类型: " + deviceType, e);
return null;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
LogManager.logError(TAG, "关闭BufferedReader失败", e);
}
}
}
}
}
/**
* 直接写入GPIO值到文件
* @param value 要写入的值
* @param valuePath GPIO值文件路径
* @return 是否成功
*/
private boolean writeGpioValueDirect(byte[] value, String valuePath) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(valuePath);
fos.write(value);
LogManager.logInfo(TAG, "GPIO值写入成功: " + valuePath + " -> " + new String(value));
return true;
} catch (IOException e) {
LogManager.logError(TAG, "GPIO值写入失败: " + valuePath + ", 错误: " + e.getMessage(), e);
return false;
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
LogManager.logError(TAG, "关闭FileOutputStream失败", e);
}
}
}
}
/**
* 写入GPIO值
* @param value 要写入的值
* @param padType 设备类型(保留兼容性)
* @return 是否成功
*/
private boolean writeGpioValue(byte[] value, String padType) {
if (PAD_TYPE_SEVEN.equals(padType) && deviceType7Manager != null) {
// 第七批设备使用DeviceType7Manager
int gpioValue = (value[0] == '1') ? DeviceType7Manager.YxGpioConstants.GpioState.HIGH : DeviceType7Manager.YxGpioConstants.GpioState.LOW;
boolean success = deviceType7Manager.setGpioValue(DeviceType7Manager.YxGpioConstants.GPIO_RELAY, gpioValue);
if (success) {
LogManager.logInfo(TAG, "DeviceType7Manager写入GPIO值成功: " + gpioValue);
} else {
LogManager.logError(TAG, "DeviceType7Manager写入GPIO值失败");
}
return success;
} else {
// 其他设备使用文件操作,根据deviceType动态获取路径
String valuePath = getGpioValuePath(deviceType);
// 第一次尝试
if (writeGpioValueDirect(value, valuePath)) {
return true;
}
// 如果失败,尝试设置GPIO方向后重试
LogManager.logWarning(TAG, "GPIO写入失败,尝试设置方向后重试, 设备类型: " + deviceType + ", 路径: " + valuePath);
setGpioDirection(padType);
// 第二次尝试
return writeGpioValueDirect(value, valuePath);
}
}
/**
* 1. 开启继电器(默认设备)
* @return 是否成功
*/
public boolean openRelay() {
return openRelay(getCurrentPadType());
}
/**
* 1. 开启继电器(指定设备类型)
* @param padType 设备类型
* @return 是否成功
*/
public boolean openRelay(String padType) {
LogManager.logInfo(TAG, "开启继电器, 设备类型: " + padType);
boolean success = writeGpioValue(OPEN_RELAY, padType);
if (success) {
LogManager.logInfo(TAG, "继电器开启成功");
} else {
LogManager.logError(TAG, "继电器开启失败");
}
return success;
}
/**
* 2. 关闭继电器(默认设备)
* @return 是否成功
*/
public boolean closeRelay() {
return closeRelay(getCurrentPadType());
}
/**
* 2. 关闭继电器(指定设备类型)
* @param padType 设备类型
* @return 是否成功
*/
public boolean closeRelay(String padType) {
LogManager.logInfo(TAG, "关闭继电器, 设备类型: " + padType);
boolean success = writeGpioValue(CLOSE_RELAY, padType);
if (success) {
LogManager.logInfo(TAG, "继电器关闭成功");
} else {
LogManager.logError(TAG, "继电器关闭失败");
}
return success;
}
/**
* 3. 开启继电器3秒后自动关闭(默认设备)
* @return 是否成功开启
*/
public boolean openRelayWithAutoClose() {
return openRelayWithAutoClose(PAD_TYPE_DEFAULT);
}
/**
* 3. 开启继电器3秒后自动关闭(指定设备类型)
* @param padType 设备类型
* @return 是否成功开启
*/
public boolean openRelayWithAutoClose(String padType) {
LogManager.logInfo(TAG, "开启继电器并设置3秒后自动关闭, 设备类型: " + padType);
// 先开启继电器
boolean openSuccess = openRelay(padType);
if (!openSuccess) {
LogManager.logError(TAG, "继电器开启失败,取消自动关闭计划");
return false;
}
// 3秒后自动关闭
handler.postDelayed(new Runnable() {
@Override
public void run() {
LogManager.logInfo(TAG, "3秒时间到,自动关闭继电器, 设备类型: " + padType);
closeRelay(padType);
}
}, 3000);
LogManager.logInfo(TAG, "继电器已开启,3秒后将自动关闭");
return true;
}
/**
* 开启继电器指定时间后自动关闭(扩展功能)
* @param padType 设备类型
* @param delayMillis 延时时间(毫秒)
* @return 是否成功开启
*/
public boolean openRelayWithAutoClose(String padType, long delayMillis) {
LogManager.logInfo(TAG, "开启继电器并设置" + delayMillis + "ms后自动关闭, 设备类型: " + padType);
// 先开启继电器
boolean openSuccess = openRelay(padType);
if (!openSuccess) {
LogManager.logError(TAG, "继电器开启失败,取消自动关闭计划");
return false;
}
// 指定时间后自动关闭
handler.postDelayed(new Runnable() {
@Override
public void run() {
LogManager.logInfo(TAG, delayMillis + "ms时间到,自动关闭继电器, 设备类型: " + padType);
closeRelay(padType);
}
}, delayMillis);
LogManager.logInfo(TAG, "继电器已开启," + delayMillis + "ms后将自动关闭");
return true;
}
/**
* 获取继电器当前状态
* @param padType 设备类型
* @return true为开启状态,false为关闭状态,null为读取失败
*/
public Boolean getRelayStatus(String padType) {
String value = readGpioValue(padType);
if (value == null) {
LogManager.logError(TAG, "无法读取继电器状态");
return null;
}
boolean isOpen = "1".equals(value.trim());
LogManager.logInfo(TAG, "继电器当前状态: " + (isOpen ? "开启" : "关闭") + ", 设备类型: " + padType);
return isOpen;
}
/**
* 获取第七批设备管理器实例
* @return DeviceType7Manager实例
*/
public DeviceType7Manager getDeviceType7Manager() {
return deviceType7Manager;
}
/**
* 释放资源
*/
public void release() {
if (handler != null) {
handler.removeCallbacksAndMessages(null);
}
if (deviceType7Manager != null) {
deviceType7Manager.release();
deviceType7Manager = null;
}
LogManager.logInfo(TAG, "RelayController资源已释放");
}
}