自动检测串口,检测时保证发送一次开机指令; 增加 acra
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
|
||||
|
||||
<application
|
||||
android:name=".MyApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*************************************************************************
|
||||
* 版权所有 (C) 2026宁波升维信息技术有限公司. 保留所有权利.
|
||||
*
|
||||
* 本软件是由 宁波升维信息技术有限公司 开发的。
|
||||
* 未经版权所有者明确授权,任何人不得使用、复制、修改、分发本软件及其相关文档。
|
||||
* 本软件包含机密和专有信息,未经授权不得向任何第三方披露。
|
||||
*************************************************************************/
|
||||
|
||||
package cn.ykbox.dashboard;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import org.acra.ACRA;
|
||||
import org.acra.config.CoreConfigurationBuilder;
|
||||
import org.acra.config.HttpSenderConfigurationBuilder;
|
||||
import org.acra.data.StringFormat;
|
||||
|
||||
public class MyApplication extends Application {
|
||||
public static final String TAG = "MyApplication";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
initLog();
|
||||
initAcra();
|
||||
}
|
||||
|
||||
|
||||
private void initLog() {
|
||||
|
||||
}
|
||||
|
||||
private void initAcra() {
|
||||
ACRA.init(this, new CoreConfigurationBuilder()
|
||||
.withBuildConfigClass(BuildConfig.class)
|
||||
.withReportFormat(StringFormat.JSON)
|
||||
.withPluginConfigurations(
|
||||
new HttpSenderConfigurationBuilder()
|
||||
.withBasicAuthLogin("u9UEf5W0giZOBrtR")
|
||||
.withBasicAuthPassword("B39uMIhh15cCoOK7")
|
||||
.withUri("http://acra.slackz.cn/report")
|
||||
.build()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package cn.ykbox.dashboard.activity;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
@@ -34,8 +35,10 @@ import java.util.Calendar;
|
||||
|
||||
import cn.ykbox.dashboard.ConfigReader;
|
||||
import cn.ykbox.dashboard.databinding.ActivityBuildingDashboardBinding;
|
||||
import cn.ykbox.dashboard.perferences.PreferenceConfiguration;
|
||||
import cn.ykbox.dashboard.receiver.CommandBroadcastReceiver;
|
||||
import cn.ykbox.dashboard.serial.SerialControlDevices;
|
||||
import cn.ykbox.dashboard.serial.SerialPortDetector;
|
||||
|
||||
public class BuildingDashboardActivity extends FullscreenActivity {
|
||||
private final static String TAG = "DashboardActivity";
|
||||
@@ -62,6 +65,9 @@ public class BuildingDashboardActivity extends FullscreenActivity {
|
||||
private ActivityBuildingDashboardBinding binding;
|
||||
private ActivityResultLauncher<Intent> settingsLauncher;
|
||||
|
||||
private SerialPortDetector detector;
|
||||
private ProgressDialog progressDialog;
|
||||
|
||||
private final View.OnTouchListener mDelayHideTouchListener = (view, motionEvent) -> {
|
||||
switch (motionEvent.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
@@ -86,6 +92,7 @@ public class BuildingDashboardActivity extends FullscreenActivity {
|
||||
super.setViews(binding.webview, binding.fullscreenContentControls);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
initSerialPort();
|
||||
initSettingsLauncher();
|
||||
initListener();
|
||||
initWebView();
|
||||
@@ -107,6 +114,95 @@ public class BuildingDashboardActivity extends FullscreenActivity {
|
||||
loadUrlWithRetry();
|
||||
}
|
||||
|
||||
private void initSerialPort() {
|
||||
String portPath = PreferenceConfiguration.getSerialPortPath(this);
|
||||
int baudRate = PreferenceConfiguration.getSerialPortBaudRate(this);
|
||||
|
||||
// 初始化串口检测器
|
||||
detector = new SerialPortDetector(portPath, baudRate);
|
||||
|
||||
// 每次启动都进行串口检测/验证
|
||||
// 参数 true 表示确保设备开机(发送两个命令)
|
||||
// 参数 false 表示仅检测串口(任一命令有响应即可)
|
||||
Log.i(TAG, "Starting serial port detection/verification...");
|
||||
startSerialPortDetection(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动串口检测
|
||||
* @param ensurePowerOn 是否确保设备开机
|
||||
*/
|
||||
private void startSerialPortDetection(boolean ensurePowerOn) {
|
||||
// 显示进度对话框
|
||||
progressDialog = new ProgressDialog(this);
|
||||
progressDialog.setTitle("串口检测");
|
||||
progressDialog.setMessage("正在检测串口...");
|
||||
progressDialog.setCancelable(false);
|
||||
progressDialog.show();
|
||||
|
||||
// 设置检测回调
|
||||
detector.setCallback(new SerialPortDetector.DetectionCallback() {
|
||||
@Override
|
||||
public void onDetectionStart() {
|
||||
Log.d(TAG, "Detection started");
|
||||
runOnUiThread(() -> {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.setMessage("开始检测串口...");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetectionProgress(String portPath, int current, int total) {
|
||||
Log.d(TAG, "Testing port " + current + "/" + total + ": " + portPath);
|
||||
runOnUiThread(() -> {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.setMessage("正在测试串口 " + current + "/" + total + "\n" + portPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetectionSuccess(String portPath) {
|
||||
Log.i(TAG, "Detection success: " + portPath);
|
||||
runOnUiThread(() -> {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
Toast.makeText(BuildingDashboardActivity.this,
|
||||
"串口检测成功!\n路径: " + portPath,
|
||||
Toast.LENGTH_LONG).show();
|
||||
|
||||
PreferenceConfiguration.setSerialPortPath(BuildingDashboardActivity.this, portPath);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetectionFailed() {
|
||||
Log.e(TAG, "Detection failed");
|
||||
runOnUiThread(() -> {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
// 可以显示错误界面或重试选项
|
||||
showDetectionFailedDialog();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 开始检测
|
||||
detector.startDetection(ensurePowerOn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示检测失败的对话框
|
||||
*/
|
||||
private void showDetectionFailedDialog() {
|
||||
Toast.makeText(BuildingDashboardActivity.this,
|
||||
"未找到有效的串口设备,请检查设备连接后重试。",
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private void loadUrlWithRetry() {
|
||||
Log.i("WebView", "Loading " + mainUrl);
|
||||
binding.webview.loadUrl(mainUrl);
|
||||
@@ -284,8 +380,6 @@ public class BuildingDashboardActivity extends FullscreenActivity {
|
||||
|
||||
try {
|
||||
JSONObject serialConfig = new JSONObject(serialConfigJson);
|
||||
String portPath = serialConfig.optString("DevicePath", "/dev/ttyS2");
|
||||
int baudRate = serialConfig.optInt("Baud", 9600);
|
||||
|
||||
if (serialConfig.has("Commands")) {
|
||||
JSONArray commands = serialConfig.getJSONArray("Commands");
|
||||
@@ -301,8 +395,6 @@ public class BuildingDashboardActivity extends FullscreenActivity {
|
||||
Intent intent = new Intent(this, CommandBroadcastReceiver.class);
|
||||
intent.setAction(CommandBroadcastReceiver.ACTION_SEND_COMMAND);
|
||||
intent.putExtra(CommandBroadcastReceiver.EXTRA_COMMAND_HEX, hex);
|
||||
intent.putExtra(CommandBroadcastReceiver.EXTRA_PORT_PATH, portPath);
|
||||
intent.putExtra(CommandBroadcastReceiver.EXTRA_BAUD_RATE, baudRate);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, i, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
|
||||
@@ -318,17 +410,14 @@ public class BuildingDashboardActivity extends FullscreenActivity {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
|
||||
Log.d(TAG, "setExactAndAllowWhileIdle, Set repeating alarm for " + time + " with command " + hex + " on port " + portPath + " at " + baudRate + " baud");
|
||||
Log.d(TAG, "setExactAndAllowWhileIdle, Set repeating alarm for " + time + " with command " + hex);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
|
||||
Log.d(TAG, "setExact, Set repeating alarm for " + time + " with command " + hex + " on port " + portPath + " at " + baudRate + " baud");
|
||||
Log.d(TAG, "setExact, Set repeating alarm for " + time + " with command " + hex);
|
||||
} else {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
|
||||
Log.d(TAG, "Set repeating alarm for " + time + " with command " + hex + " on port " + portPath + " at " + baudRate + " baud");
|
||||
Log.d(TAG, "Set repeating alarm for " + time + " with command " + hex);
|
||||
}
|
||||
|
||||
// alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,6 @@ public class StartActivity extends AppCompatActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// 开机后手动发送一次开启电源指令
|
||||
SerialControlDevices.sendCommand("/dev/ttyS2", 9600, "ACEAB400ED");
|
||||
|
||||
mContext = this;
|
||||
EdgeToEdge.enable(this);
|
||||
setContentView(R.layout.activity_start);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.ykbox.dashboard.perferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
/**
|
||||
* 配置管理
|
||||
* TODO 代码中零散的读取配置选项代码都集中到这里
|
||||
*/
|
||||
public class PreferenceConfiguration {
|
||||
private final static String TAG = "PreferenceConfiguration";
|
||||
|
||||
private static final String KEY_SERIAL_PORT_PATH = "k_serial_port_path";
|
||||
private static final String KEY_SERIAL_PORT_BAUD_RATE = "k_serial_baud";
|
||||
|
||||
public static String getSerialPortPath(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
return prefs.getString(KEY_SERIAL_PORT_PATH, "");
|
||||
}
|
||||
|
||||
public static void setSerialPortPath(Context context, String portPath) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
prefs.edit().putString(KEY_SERIAL_PORT_PATH, portPath).apply();
|
||||
}
|
||||
|
||||
public static int getSerialPortBaudRate(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String baud = prefs.getString(KEY_SERIAL_PORT_BAUD_RATE, "9600");
|
||||
return Integer.parseInt(baud);
|
||||
}
|
||||
}
|
||||
@@ -3,25 +3,29 @@ package cn.ykbox.dashboard.receiver;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import cn.ykbox.dashboard.perferences.PreferenceConfiguration;
|
||||
import cn.ykbox.dashboard.serial.SerialControlDevices;
|
||||
|
||||
public class CommandBroadcastReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = "CommandReceiver";
|
||||
public static final String ACTION_SEND_COMMAND = "cn.ykbox.dashboard.ACTION_SEND_COMMAND";
|
||||
public static final String EXTRA_COMMAND_HEX = "EXTRA_COMMAND_HEX";
|
||||
public static final String EXTRA_PORT_PATH = "EXTRA_PORT_PATH";
|
||||
public static final String EXTRA_BAUD_RATE = "EXTRA_BAUD_RATE"; // 新增:波特率的 Extra Key
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent != null && ACTION_SEND_COMMAND.equals(intent.getAction())) {
|
||||
String hexCommand = intent.getStringExtra(EXTRA_COMMAND_HEX);
|
||||
String portPath = intent.getStringExtra(EXTRA_PORT_PATH);
|
||||
int baudRate = intent.getIntExtra(EXTRA_BAUD_RATE, 9600);
|
||||
|
||||
if (hexCommand != null && !hexCommand.isEmpty() && portPath != null && !portPath.isEmpty()) {
|
||||
String portPath = PreferenceConfiguration.getSerialPortPath(context);
|
||||
int baudRate = PreferenceConfiguration.getSerialPortBaudRate(context);
|
||||
|
||||
if (hexCommand != null && !hexCommand.isEmpty() && !TextUtils.isEmpty(portPath)) {
|
||||
Log.d(TAG, "Received alarm to send command '" + hexCommand + "' to port '" + portPath + "' at " + baudRate + " baud");
|
||||
// 使用新的静态方法发送指令
|
||||
boolean success = SerialControlDevices.sendCommand(portPath, baudRate, hexCommand);
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
package cn.ykbox.dashboard.serial;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import android_serialport_api.SerialPortFinder;
|
||||
import tp.xmaihh.serialport.SerialHelper;
|
||||
import tp.xmaihh.serialport.bean.ComBean;
|
||||
|
||||
public class SerialPortDetector {
|
||||
private static final String TAG = "SerialPortDetector";
|
||||
// 测试命令
|
||||
private static final String TEST_CMD_OFF = "ACEAB500ED"; // 关闭设备
|
||||
private static final String TEST_CMD_ON = "ACEAB400ED"; // 打开设备
|
||||
|
||||
// 响应超时时间(毫秒)
|
||||
private static final long RESPONSE_TIMEOUT = 6000;
|
||||
|
||||
private DetectionCallback callback;
|
||||
private Handler mainHandler;
|
||||
|
||||
private String savedPath;
|
||||
private int baudRate;
|
||||
|
||||
public interface DetectionCallback {
|
||||
void onDetectionStart();
|
||||
void onDetectionProgress(String portPath, int current, int total);
|
||||
void onDetectionSuccess(String portPath);
|
||||
void onDetectionFailed();
|
||||
}
|
||||
|
||||
public SerialPortDetector(String savedPath, int baudRate) {
|
||||
this.savedPath = savedPath;
|
||||
this.baudRate = baudRate;
|
||||
this.mainHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
public void setCallback(DetectionCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始串口检测(智能检测)
|
||||
* 先验证已保存的串口,如果不可用再进行全局检测
|
||||
*/
|
||||
public void startDetection() {
|
||||
startDetection(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始串口检测(智能检测)
|
||||
* @param ensurePowerOn 是否确保设备开机(发送两个命令)
|
||||
*/
|
||||
public void startDetection(boolean ensurePowerOn) {
|
||||
new Thread(() -> {
|
||||
notifyDetectionStart();
|
||||
|
||||
if (!TextUtils.isEmpty(savedPath)) {
|
||||
Log.d(TAG, "Found saved serial port path: " + savedPath);
|
||||
Log.d(TAG, "Verifying saved port: " + savedPath);
|
||||
|
||||
// 验证已保存的串口是否可用
|
||||
if (testSerialPort(savedPath, baudRate, ensurePowerOn)) {
|
||||
Log.i(TAG, "Saved serial port is valid: " + savedPath);
|
||||
notifyDetectionSuccess(savedPath);
|
||||
return;
|
||||
} else {
|
||||
Log.w(TAG, "Saved serial port is invalid, starting full detection");
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "No saved serial port path, starting full detection");
|
||||
}
|
||||
|
||||
// 已保存的串口不可用或不存在,进行全局检测
|
||||
performFullDetection(ensurePowerOn);
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void performFullDetection(boolean ensurePowerOn) {
|
||||
SerialPortFinder finder = new SerialPortFinder();
|
||||
String[] devicePaths = finder.getAllDevicesPath();
|
||||
|
||||
if (devicePaths == null || devicePaths.length == 0) {
|
||||
Log.e(TAG, "No serial ports found");
|
||||
notifyDetectionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Found " + devicePaths.length + " serial ports");
|
||||
|
||||
// 遍历所有串口
|
||||
for (int i = 0; i < devicePaths.length; i++) {
|
||||
String portPath = devicePaths[i];
|
||||
notifyDetectionProgress(portPath, i + 1, devicePaths.length);
|
||||
|
||||
Log.d(TAG, "Testing port: " + portPath + " at " + baudRate + " baud");
|
||||
|
||||
if (testSerialPort(portPath, baudRate, ensurePowerOn)) {
|
||||
Log.i(TAG, "Serial port detected successfully: " + portPath);
|
||||
notifyDetectionSuccess(portPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Log.e(TAG, "No valid serial port found");
|
||||
notifyDetectionFailed();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试指定的串口
|
||||
* @param portPath 串口路径
|
||||
* @param baudRate 波特率
|
||||
* @param ensurePowerOn 是否确保设备开机(发送两个命令)
|
||||
*/
|
||||
private boolean testSerialPort(String portPath, int baudRate, boolean ensurePowerOn) {
|
||||
TestSerialHelper serialHelper = null;
|
||||
|
||||
try {
|
||||
serialHelper = new TestSerialHelper(portPath, baudRate);
|
||||
serialHelper.open();
|
||||
|
||||
if (ensurePowerOn) {
|
||||
// 需要确保设备开机,两个命令都要发送
|
||||
Log.d(TAG, "Ensuring device power on by sending both commands");
|
||||
|
||||
boolean cmd1Success = sendCommandAndWaitResponse(serialHelper, TEST_CMD_OFF);
|
||||
boolean cmd2Success = sendCommandAndWaitResponse(serialHelper, TEST_CMD_ON);
|
||||
|
||||
// 只要有一个命令收到有效响应就认为串口可用
|
||||
if (cmd1Success || cmd2Success) {
|
||||
Log.d(TAG, "Device responded (CMD1: " + cmd1Success + ", CMD2: " + cmd2Success + ")");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
// 只需要检测串口,任意一个命令有响应即可
|
||||
if (sendCommandAndWaitResponse(serialHelper, TEST_CMD_OFF)) {
|
||||
return true;
|
||||
}
|
||||
if (sendCommandAndWaitResponse(serialHelper, TEST_CMD_ON)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error testing port " + portPath + ": " + e.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
if (serialHelper != null) {
|
||||
try {
|
||||
serialHelper.close();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error closing port: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送命令并等待响应
|
||||
*/
|
||||
private boolean sendCommandAndWaitResponse(TestSerialHelper serialHelper, String command) {
|
||||
try {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicBoolean responseReceived = new AtomicBoolean(false);
|
||||
|
||||
serialHelper.setResponseListener((isValid) -> {
|
||||
if (isValid) {
|
||||
responseReceived.set(true);
|
||||
}
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
// 清空之前的响应标志
|
||||
serialHelper.resetResponse();
|
||||
|
||||
// 发送命令
|
||||
serialHelper.sendHex(command);
|
||||
Log.d(TAG, "Sent command: " + command);
|
||||
|
||||
// 等待响应
|
||||
boolean timeout = !latch.await(RESPONSE_TIMEOUT, TimeUnit.MILLISECONDS);
|
||||
|
||||
if (timeout) {
|
||||
Log.d(TAG, "Response timeout for command: " + command);
|
||||
return false;
|
||||
}
|
||||
|
||||
return responseReceived.get();
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Wait interrupted: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 回调通知方法
|
||||
private void notifyDetectionStart() {
|
||||
if (callback != null) {
|
||||
mainHandler.post(() -> callback.onDetectionStart());
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyDetectionProgress(String portPath, int current, int total) {
|
||||
if (callback != null) {
|
||||
mainHandler.post(() -> callback.onDetectionProgress(portPath, current, total));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyDetectionSuccess(String portPath) {
|
||||
if (callback != null) {
|
||||
mainHandler.post(() -> callback.onDetectionSuccess(portPath));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyDetectionFailed() {
|
||||
if (callback != null) {
|
||||
mainHandler.post(() -> callback.onDetectionFailed());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部测试用的 SerialHelper
|
||||
*/
|
||||
private static class TestSerialHelper extends SerialHelper {
|
||||
private ResponseListener responseListener;
|
||||
|
||||
public interface ResponseListener {
|
||||
void onResponse(boolean isValid);
|
||||
}
|
||||
|
||||
public TestSerialHelper(String sPort, int iBaudRate) {
|
||||
super(sPort, iBaudRate);
|
||||
}
|
||||
|
||||
public void setResponseListener(ResponseListener listener) {
|
||||
this.responseListener = listener;
|
||||
}
|
||||
|
||||
public void resetResponse() {
|
||||
// 重置响应状态,为下一次测试做准备
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDataReceived(ComBean comBean) {
|
||||
byte[] data = comBean.bRec;
|
||||
|
||||
// 检查是否为有效响应格式: DA XX XX XX XX ED
|
||||
if (isValidResponse(data)) {
|
||||
Log.d(TAG, "Valid response received: " + bytesToHex(data));
|
||||
if (responseListener != null) {
|
||||
responseListener.onResponse(true);
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Invalid response: " + bytesToHex(data));
|
||||
if (responseListener != null) {
|
||||
responseListener.onResponse(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查响应是否符合格式: DA XX XX XX XX ED
|
||||
*/
|
||||
private boolean isValidResponse(byte[] data) {
|
||||
if (data == null || data.length < 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查起始字节是否为 0xDA
|
||||
if ((data[0] & 0xFF) != 0xDA) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查结束字节是否为 0xED
|
||||
if ((data[data.length - 1] & 0xFF) != 0xED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节数组转十六进制字符串(用于日志)
|
||||
*/
|
||||
private String bytesToHex(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return "null";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02X ", b & 0xFF));
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,4 +13,17 @@
|
||||
app:entryValues="@array/url_end_point_values"
|
||||
app:defaultValue="@string/url_end_point_default_value" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="外部设备">
|
||||
<EditTextPreference
|
||||
app:key="k_serial_port_path"
|
||||
app:title="串口设备"
|
||||
app:defaultValue=""
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<EditTextPreference
|
||||
app:key="k_serial_baud"
|
||||
app:title="串口波特率"
|
||||
app:defaultValue="9600"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
Reference in New Issue
Block a user