diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/BuildingDashboardActivity.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/BuildingDashboardActivity.java index 50eb46e..6958a05 100644 --- a/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/BuildingDashboardActivity.java +++ b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/BuildingDashboardActivity.java @@ -37,7 +37,6 @@ 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 { @@ -104,8 +103,11 @@ public class BuildingDashboardActivity extends FullscreenActivity { super.onResume(); SharedPreferences pre = PreferenceManager.getDefaultSharedPreferences(this); - mainUrl = pre.getString("k_url_prefix", "http://172.18.22.211:8002/Dashboard"); - configUrl = mainUrl + "/data/config.json"; + String urlPrefix = pre.getString("k_url_prefix", "http://172.18.22.211:8002/Dashboard"); + String urlPath = pre.getString("k_url_path", "/index.html"); + + mainUrl = urlPrefix + urlPath; + configUrl = urlPrefix + "/data/config.json"; Log.i(TAG, "Main: " + mainUrl); Log.i(TAG, "Config: " + configUrl); @@ -137,11 +139,12 @@ public class BuildingDashboardActivity extends FullscreenActivity { new Thread(() -> { detector.sendPowerOffCommand(); try { - Thread.sleep(3000); // 等待 3 秒 + Thread.sleep(5000); // 等待 5 秒 } catch (InterruptedException e) { Log.e(TAG, "Sleep interrupted", e); } - detector.sendPowerOnCommand(); + int loop = PreferenceConfiguration.getSerialCmdLoop(this); + detector.sendPowerOnCommand(loop); }).start(); } } @@ -176,7 +179,7 @@ public class BuildingDashboardActivity extends FullscreenActivity { Log.d(TAG, "Testing port " + current + "/" + total + ": " + portPath); runOnUiThread(() -> { if (progressDialog != null) { - progressDialog.setMessage("正在测试串口 " + current + "/" + total + "\n" + portPath); + progressDialog.setMessage("正在测试串口路径: " + portPath + "\n" + current + "/" + total); } }); } diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/SettingsActivity.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/SettingsActivity.java index eae4efe..563e20c 100644 --- a/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/SettingsActivity.java +++ b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/SettingsActivity.java @@ -1,14 +1,13 @@ package cn.ykbox.dashboard.activity; -import android.content.SharedPreferences; import android.os.Bundle; import android.text.TextUtils; -import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.preference.EditTextPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; @@ -80,7 +79,15 @@ public class SettingsActivity extends AppCompatActivity { .setTitle("确认清除") .setMessage("确定要清除当前串口设备路径吗?") .setPositiveButton("确定", (dialog, which) -> { + // 清空 PreferenceConfiguration.setSerialPortPath(requireContext(), ""); + + // 刷新 + Preference serialPortPathPref = findPreference("k_serial_port_path"); + if (serialPortPathPref != null) { + String newValue = PreferenceConfiguration.getSerialPortPath(requireContext()); + ((EditTextPreference) serialPortPathPref).setText(newValue); + } }) .setNegativeButton("取消", null) .show(); @@ -96,7 +103,7 @@ public class SettingsActivity extends AppCompatActivity { } SerialPortDetector detector = new SerialPortDetector(portPath, baudRate); - detector.sendPowerOnCommand(); + detector.sendPowerOnCommand(1); } diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/StartActivity.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/StartActivity.java index 725490a..0e689fb 100644 --- a/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/StartActivity.java +++ b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/StartActivity.java @@ -12,7 +12,6 @@ import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import cn.ykbox.dashboard.R; -import cn.ykbox.dashboard.serial.SerialControlDevices; public class StartActivity extends AppCompatActivity { private Context mContext; diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/perferences/PreferenceConfiguration.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/perferences/PreferenceConfiguration.java index 7e0921a..ebc1314 100644 --- a/app_dashboard/src/main/java/cn/ykbox/dashboard/perferences/PreferenceConfiguration.java +++ b/app_dashboard/src/main/java/cn/ykbox/dashboard/perferences/PreferenceConfiguration.java @@ -33,6 +33,10 @@ public class PreferenceConfiguration { public static boolean getSendPowerOnCmd(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - return prefs.getBoolean(KEY_SEND_POWER_ON_CMD, false); + return prefs.getBoolean(KEY_SEND_POWER_ON_CMD, true); + } + + public static int getSerialCmdLoop(Context context) { + return 3; } } diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/receiver/CommandBroadcastReceiver.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/receiver/CommandBroadcastReceiver.java index d985648..eeff483 100644 --- a/app_dashboard/src/main/java/cn/ykbox/dashboard/receiver/CommandBroadcastReceiver.java +++ b/app_dashboard/src/main/java/cn/ykbox/dashboard/receiver/CommandBroadcastReceiver.java @@ -3,14 +3,11 @@ 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; +import cn.ykbox.dashboard.serial.SerialPortDetector; public class CommandBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "CommandReceiver"; @@ -24,11 +21,12 @@ public class CommandBroadcastReceiver extends BroadcastReceiver { String portPath = PreferenceConfiguration.getSerialPortPath(context); int baudRate = PreferenceConfiguration.getSerialPortBaudRate(context); + int loop = PreferenceConfiguration.getSerialCmdLoop(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); + boolean success = SerialPortDetector.sendCommand(portPath, baudRate, hexCommand, loop); if (!success) { Log.e(TAG, "Failed to send command via broadcast receiver."); } diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialControlDevices.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialControlDevices.java deleted file mode 100644 index ee41528..0000000 --- a/app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialControlDevices.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.ykbox.dashboard.serial; - -import android.util.Log; -import tp.xmaihh.serialport.SerialHelper; - -/** - * @description: 通过串口设置班牌的功能。本类提供一个静态方法用于发送单次命令。 - * @author: Hu Zhang - * @date: 2024/1/5 - **/ -public class SerialControlDevices { - private static final String TAG = "SerialControlDevices"; - - /** - * 私有构造函数,防止外部实例化此类。 - */ - private SerialControlDevices() {} - - /** - * 打开指定串口,发送十六进制命令,然后立即关闭串口。 - * - * @param portPath 串口的设备路径 (例如, "/dev/ttyS2"). - * @param hexCommand 要发送的十六进制格式的命令字符串. - * @return 如果命令发送成功则返回 true, 否则返回 false. - */ - public static boolean sendCommand(String portPath, int baud, String hexCommand) { - if (portPath == null || portPath.isEmpty() || hexCommand == null || hexCommand.isEmpty()) { - Log.e(TAG, "Port path or command is empty."); - return false; - } - - // 每次调用都创建一个新的 SerialHelper 实例 - SerialHelper serialHelper = new SerialHelper(portPath, baud) { - @Override - protected void onDataReceived(tp.xmaihh.serialport.bean.ComBean ComRecData) { - // 可以在这里处理返回的数据,但对于单次发送任务,通常不需要 - // Log.d(TAG, "Received data from " + portPath + ": " + new String(ComRecData.bRec)); - } - }; - - try { - serialHelper.open(); - serialHelper.sendHex(hexCommand); - Log.d(TAG, "Successfully sent command '" + hexCommand + "' to port '" + portPath + "'"); - return true; - } catch (Exception e) { - Log.e(TAG, "Error sending command to port " + portPath, e); - return false; - } finally { - serialHelper.close(); - } - } -} \ No newline at end of file diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialPortDetector.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialPortDetector.java index a6d7c96..692dfa5 100644 --- a/app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialPortDetector.java +++ b/app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialPortDetector.java @@ -20,7 +20,7 @@ public class SerialPortDetector { private static final String TEST_CMD_ON = "ACEAB400ED"; // 打开设备 // 响应超时时间(毫秒) - private static final long RESPONSE_TIMEOUT = 6000; + private static final long RESPONSE_TIMEOUT = 4000; private DetectionCallback callback; private Handler mainHandler; @@ -35,6 +35,44 @@ public class SerialPortDetector { void onDetectionFailed(); } + /** + * 打开指定串口,发送十六进制命令,然后立即关闭串口。 + * + * @param portPath 串口的设备路径 (例如, "/dev/ttyS2"). + * @param hexCommand 要发送的十六进制格式的命令字符串. + * @return 如果命令发送成功则返回 true, 否则返回 false. + */ + public static boolean sendCommand(String portPath, int baud, String hexCommand, int loop) { + if (portPath == null || portPath.isEmpty() || hexCommand == null || hexCommand.isEmpty()) { + Log.e(TAG, "Port path or command is empty."); + return false; + } + + // 每次调用都创建一个新的 SerialHelper 实例 + SerialHelper serialHelper = new SerialHelper(portPath, baud) { + @Override + protected void onDataReceived(tp.xmaihh.serialport.bean.ComBean ComRecData) { + // 可以在这里处理返回的数据,但对于单次发送任务,通常不需要 + // Log.d(TAG, "Received data from " + portPath + ": " + new String(ComRecData.bRec)); + } + }; + + try { + serialHelper.open(); + for(int i = 0; i < loop; i ++) { + serialHelper.sendHex(hexCommand); + Thread.sleep(1000); + } + Log.d(TAG, "Successfully sent command '" + hexCommand + "' to port '" + portPath + "'"); + return true; + } catch (Exception e) { + Log.e(TAG, "Error sending command to port " + portPath, e); + return false; + } finally { + serialHelper.close(); + } + } + public SerialPortDetector(String savedPath, int baudRate) { this.savedPath = savedPath; this.baudRate = baudRate; @@ -55,15 +93,18 @@ public class SerialPortDetector { /** * 发送打开设备指令到已保存的串口(不等待响应) */ - public void sendPowerOnCommand() { - sendCommand(TEST_CMD_ON); + public void sendPowerOnCommand(int loop) { + sendCommand(TEST_CMD_ON, loop); + } + private void sendCommand(String commandHex) { + sendCommand(commandHex, 1); } /** * 发送指令到已保存的串口(不等待响应) * @param commandHex 十六进制命令字符串 */ - private void sendCommand(String commandHex) { + private void sendCommand(String commandHex, int loop) { if (TextUtils.isEmpty(savedPath)) { Log.w(TAG, "No serial port path configured"); return; @@ -74,7 +115,12 @@ public class SerialPortDetector { try { serialHelper = new SimpleSerialHelper(savedPath, baudRate); serialHelper.open(); - serialHelper.sendHex(commandHex); + + for(int i = 0; i < loop; i ++) { + serialHelper.sendHex(commandHex); + Thread.sleep(1000); + } + Log.d(TAG, "Sent command: " + commandHex); } catch (Exception e) { Log.e(TAG, "Error sending command: " + e.getMessage()); @@ -146,6 +192,13 @@ public class SerialPortDetector { Log.d(TAG, "Testing port: " + portPath + " at " + baudRate + " baud"); + // 老设备没有反馈,如果测试成功,很快就进入下个测试,导致用户看不清串口路径,这里添加延时 + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + Log.e(TAG, "Sleep interrupted", e); + } + if (testSerialPort(portPath, baudRate, ensurePowerOn)) { Log.i(TAG, "Serial port detected successfully: " + portPath); notifyDetectionSuccess(portPath); @@ -172,6 +225,7 @@ public class SerialPortDetector { if (ensurePowerOn) { // 需要确保设备开机,两个命令都要发送 + // Log.d(TAG, "Ensuring device power on by sending both commands"); boolean cmd1Success = sendCommandAndWaitResponse(serialHelper, TEST_CMD_OFF); @@ -326,24 +380,22 @@ public class SerialPortDetector { } /** - * 检查响应是否符合格式: DA XX XX XX XX ED + * 检查响应是否符合格式: DA XX XX XX XX ED 或者 AC XX XX XX XX ED */ private boolean isValidResponse(byte[] data) { if (data == null || data.length < 6) { return false; } - // 检查起始字节是否为 0xDA - if ((data[0] & 0xFF) != 0xDA) { + // 检查起始字节是否为 0xDA 或 0xAC + int head = data[0] & 0xFF; + if (head != 0xDA && head != 0xAC) { return false; } // 检查结束字节是否为 0xED - if ((data[data.length - 1] & 0xFF) != 0xED) { - return false; - } - - return true; + int end = data[data.length - 1] & 0xFF; + return end == 0xED; } /** diff --git a/app_dashboard/src/main/res/xml/root_preferences.xml b/app_dashboard/src/main/res/xml/root_preferences.xml index bcf5bb5..38e4305 100644 --- a/app_dashboard/src/main/res/xml/root_preferences.xml +++ b/app_dashboard/src/main/res/xml/root_preferences.xml @@ -1,31 +1,37 @@ - + + app:summary="用于拼接网页和配置文件链接,网页:{URL前缀}/{URL路径},配置文件:{URL前缀}/data/config.json" /> + + app:useSimpleSummaryProvider="true" + app:isPreferenceVisible="false"/> + app:title="APP 启动时重启电源插座" + app:summary="APP 启动时先关闭电源,5秒后再打开电源" + app:defaultValue="true" />