zhuguifei
2026-01-14 b7ee99a71e88a08a09fe9daada6675a175d09be1
app/src/main/java/com/shlb/comb/activity/ParameterSettingActivity.java
@@ -36,35 +36,43 @@
public class ParameterSettingActivity extends BaseActivity {
    // 阈值设定相关控件
    private Spinner sp_threshold_mode;
    private EditText et_threshold_value;
    private Button btn_threshold_read;
    private Button btn_threshold_write;
    // 灵敏度设定相关控件
    private Spinner sp_sensitivity_mode;
    private EditText et_sensitivity_value;
    private Button btn_sensitivity_read;
    private Button btn_sensitivity_write;
    // 自检和复位按钮
    private Button btn_start_check;
    private Button btn_end_check;
    private Button btn_reset_mainboard;
    private Button btn_reset_sensor;
    // 日志和状态显示
    private TextView tv_log;
    private TextView tv_right_text;
    private androidx.cardview.widget.CardView cvLog;
    
    // New components
    // 自检监测网格和日志控件
    private RecyclerView rvGrid;
    private QMUIRoundButton btnReadData;
    private QMUIRoundButton btnClearLog;
    private ScrollView svLog;
    // 数据相关
    private GridAdapter mAdapter;
    private List<BoxStatus> boxStatusList = new ArrayList<>();
    private StringBuilder logBuilder = new StringBuilder();
    private boolean isSelfCheckMode = false;
    private String pendingSettingCmd = "";
    private boolean isSelfCheckMode = false;  // 标记当前是否处于自检模式
    private String pendingSettingCmd = "";  // 记录待处理的设定指令
    private Button currentOperatingButton; // 当前正在操作的按钮
    private String pendingToastMessage = null; // 待显示的Toast消息
    
    private SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
@@ -85,12 +93,12 @@
        sp_threshold_mode = findViewById(R.id.sp_threshold_mode);
        et_threshold_value = findViewById(R.id.et_threshold_value);
        btn_threshold_read = findViewById(R.id.btn_threshold_read);
        btn_threshold_write = findViewById(R.id.btn_threshold_write);
        sp_sensitivity_mode = findViewById(R.id.sp_sensitivity_mode);
        et_sensitivity_value = findViewById(R.id.et_sensitivity_value);
        btn_sensitivity_read = findViewById(R.id.btn_sensitivity_read);
        btn_sensitivity_write = findViewById(R.id.btn_sensitivity_write);
        btn_start_check = findViewById(R.id.btn_start_check);
@@ -99,15 +107,15 @@
        btn_reset_sensor = findViewById(R.id.btn_reset_sensor);
        tv_log = findViewById(R.id.tv_log);
        cvLog = findViewById(R.id.cv_log);
        tv_right_text = findViewById(R.id.tv_right_text);
        
        // Init new components
        // 初始化自检监测相关控件
        rvGrid = findViewById(R.id.rv_grid);
        // btnReadData was removed from layout
        btnClearLog = findViewById(R.id.btn_clear_log);
        svLog = findViewById(R.id.sv_log);
        
        // Log setup
        // 设置日志滚动视图的触摸监听,防止滑动冲突
        if (svLog != null) {
            svLog.setOnTouchListener((v, event) -> {
                v.getParent().requestDisallowInterceptTouchEvent(true);
@@ -118,6 +126,7 @@
            });
        }
        
        // 初始化日志内容
        if (logBuilder.length() > 0) {
            tv_log.setText(Html.fromHtml(logBuilder.toString()));
        } else {
@@ -130,25 +139,36 @@
    protected void initData() {
        updateBluetoothStatus();
        
        // Initialize box status list
        // 初始化30个格子的状态列表
        boxStatusList.clear();
        for (int i = 1; i <= 30; i++) {
            boxStatusList.add(new BoxStatus(i));
        }
        
        // Grid Setup
        // 设置网格布局:3行10列
        rvGrid.setLayoutManager(new GridLayoutManager(this, 10)); 
        mAdapter = new GridAdapter();
        rvGrid.setAdapter(mAdapter);
        
        // 如果蓝牙已连接,进入设定模式
        if (BleGlobalManager.getInstance().isConnected()) {
             sendCmdWithCrc(CMD.ENTER_SETTING);
             // sendCmdWithCrc(CMD.READ_DATA);
        }
    }
    @Override
    protected void onResume() {
        super.onResume();
        // 根据系统设置控制日志显示
        boolean isCmdLogEnabled = com.blankj.utilcode.util.SPUtils.getInstance().getBoolean("cmd_log_enabled", false);
        if (cvLog != null) {
            cvLog.setVisibility(isCmdLogEnabled ? View.VISIBLE : View.GONE);
        }
    }
    @Override
    protected void onDestroy() {
        // 页面销毁时退出设定模式
        if (BleGlobalManager.getInstance().isConnected()) {
            sendCmdWithCrc(CMD.EXIT_SETTING);
        }
@@ -162,27 +182,37 @@
            public void onClick(View v) {
                int id = v.getId();
                String action = "";
                if (id == R.id.btn_threshold_read) {
                    action = "读取阈值";
                    Toast.makeText(ParameterSettingActivity.this, "该功能暂未开放", Toast.LENGTH_SHORT).show();
                } else if (id == R.id.btn_threshold_write) {
                if (id == R.id.btn_threshold_write) {
                    handleThresholdWrite();
                } else if (id == R.id.btn_sensitivity_read) {
                    action = "读取灵敏度";
                    Toast.makeText(ParameterSettingActivity.this, "该功能暂未开放", Toast.LENGTH_SHORT).show();
                } else if (id == R.id.btn_sensitivity_write) {
                    handleSensitivityWrite();
                } else if (id == R.id.btn_start_check) {
                    action = "开始自检";
                    sendCmdWithCrc(CMD.WRITE_START_CHECK);
                    isSelfCheckMode = true;
                    if (BleGlobalManager.getInstance().isConnected()) {
                        currentOperatingButton = btn_start_check;
                        updateButtonState(currentOperatingButton, false);
                        action = "开始自检";
                        setAllGridGray();
                        sendCmdWithCrc(CMD.WRITE_START_CHECK);
                        isSelfCheckMode = true;
                    } else {
                        Toast.makeText(ParameterSettingActivity.this, "请先连接蓝牙", Toast.LENGTH_SHORT).show();
                    }
                } else if (id == R.id.btn_end_check) {
                    action = "结束自检";
                    sendCmdWithCrc(CMD.WRITE_END_CHECK);
                    isSelfCheckMode = false;
                    if (BleGlobalManager.getInstance().isConnected()) {
                        currentOperatingButton = btn_end_check;
                        updateButtonState(currentOperatingButton, false);
                        action = "结束自检";
                        setAllGridGray();
                        sendCmdWithCrc(CMD.WRITE_END_CHECK);
                        isSelfCheckMode = false;
                    } else {
                         Toast.makeText(ParameterSettingActivity.this, "请先连接蓝牙", Toast.LENGTH_SHORT).show();
                    }
                } else if (id == R.id.btn_reset_mainboard) {
                    currentOperatingButton = btn_reset_mainboard;
                    showResetConfirmDialog("确定要执行主板复位吗?", CMD.WRITE_BOARD_RESET);
                } else if (id == R.id.btn_reset_sensor) {
                    currentOperatingButton = btn_reset_sensor;
                    showResetConfirmDialog("确定要执行传感器复位吗?", CMD.WRITE_SENSOR_RESET);
                }
@@ -193,14 +223,59 @@
            }
        };
        btn_threshold_read.setOnClickListener(listener);
        btn_threshold_write.setOnClickListener(listener);
        btn_sensitivity_read.setOnClickListener(listener);
        btn_sensitivity_write.setOnClickListener(listener);
        btn_start_check.setOnClickListener(listener);
        btn_end_check.setOnClickListener(listener);
        btn_reset_mainboard.setOnClickListener(listener);
        btn_reset_sensor.setOnClickListener(listener);
        // 阈值模式选择监听,控制输入框是否可用
        sp_threshold_mode.setOnItemSelectedListener(new android.widget.AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(android.widget.AdapterView<?> parent, View view, int position, long id) {
                if (position == 0) {
                    // 一键设定,隐藏输入框 (使用INVISIBLE保留占位,防止按钮移位)
                    et_threshold_value.setVisibility(View.INVISIBLE);
                    et_threshold_value.setText("");
                } else {
                    // 单层设定,显示输入框
                    et_threshold_value.setVisibility(View.VISIBLE);
                    int maxLayer = com.blankj.utilcode.util.SPUtils.getInstance().getInt("layer_count", 30);
                    et_threshold_value.setHint("1-" + maxLayer);
                }
            }
            @Override
            public void onNothingSelected(android.widget.AdapterView<?> parent) {
            }
        });
        // 灵敏度模式选择监听,控制输入框是否可用
        sp_sensitivity_mode.setOnItemSelectedListener(new android.widget.AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(android.widget.AdapterView<?> parent, View view, int position, long id) {
                // 0: 批量增加, 1: 批量减少, 2: 单层增加, 3: 单层减少
                if (position == 0 || position == 1) {
                    // 批量操作,隐藏输入框
                    et_sensitivity_value.setVisibility(View.INVISIBLE);
                    et_sensitivity_value.setText("");
                } else {
                    // 单层操作,显示输入框
                    et_sensitivity_value.setVisibility(View.VISIBLE);
                    int maxLayer = com.blankj.utilcode.util.SPUtils.getInstance().getInt("layer_count", 30);
                    et_sensitivity_value.setHint("1-" + maxLayer);
                }
            }
            @Override
            public void onNothingSelected(android.widget.AdapterView<?> parent) {
            }
        });
        
        btnClearLog.setOnClickListener(v -> {
            logBuilder.setLength(0);
@@ -212,7 +287,7 @@
    private String getCmdDescription(String hex, Boolean isSent) {
        if (hex == null) return "";
        
        // Special handling for 3B (Enter/Exit Setting)
        // 进入/退出设定模式指令特殊处理
        if (hex.startsWith(CMD.ENTER_SETTING.substring(0, 8))) {
            if (hex.startsWith(CMD.ENTER_SETTING)) return "-进入设定";
            if (hex.startsWith(CMD.EXIT_SETTING)) return "-退出设定";
@@ -249,7 +324,7 @@
        String displayMsg = msg;
        String cmdDesc = "";
        
        // 如果是 hex 指令 (纯 0-9 A-F a-f),加空格格式化
        // 如果是十六进制指令,每两位加一个空格格式化显示
        if (msg.matches("^[0-9A-Fa-f]+$")) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < msg.length(); i += 2) {
@@ -267,8 +342,8 @@
        
        String logLine;
        if (isSent != null) {
            String color = isSent ? "#1890ff" : "#05aa87"; // Blue for sent, Green for received
            // 拼接到前缀后面: "发送-读站号: " 或 "收到-读站号: "
            // 发送指令用蓝色,接收数据用绿色
            String color = isSent ? "#1890ff" : "#05aa87";
            String prefix = (isSent ? "发送" : "收到") + cmdDesc + ": ";
            logLine = time + " <font color='" + color + "'>" + prefix + displayMsg + "</font><br>";
        } else {
@@ -278,7 +353,7 @@
        
        logBuilder.append(logLine);
        
        // Update UI
        // 更新日志显示并自动滚动到底部
        if (tv_log != null) {
            tv_log.setText(Html.fromHtml(logBuilder.toString()));
             if (svLog != null) {
@@ -287,7 +362,7 @@
        }
    }
    
    // Kept for backward compatibility if needed, but redirected to appendLog
    // 兼容旧代码的日志方法
    private void addLog(String message) {
        appendLog(message);
    }
@@ -298,7 +373,7 @@
            updateBluetoothStatus();
        } else if (event.getType() == UpdateEvent.Type.DEVICE_INFO) {
            String hex = event.getMsg();
            appendLog(hex, false); // false for received (Green)
            appendLog(hex, false);  // false表示接收的数据,显示为绿色
            parseAndRefresh(hex);
        }
    }
@@ -306,11 +381,13 @@
    private void parseAndRefresh(String hex) {
        if (hex == null) return;
        
        // 写入指令的返回 (A55A06开头)
        if (hex.startsWith("A55A06") && hex.length() >= 12) {
        // 处理写入指令的返回(A55A06开头)
        if (hex.startsWith(CMD.WRITE_SUFFIX) && hex.length() >= 12) {
             // 提取状态字节,01表示成功
             String statusHex = hex.substring(10, 12);
             boolean isSuccess = "01".equals(statusHex);
             // 处理进入设定模式的返回
             if (hex.startsWith(CMD.ENTER_SETTING.substring(0, 8))) {
                 if (isSuccess) {
                     appendLog("进入设定模式成功");
@@ -320,57 +397,108 @@
                 return;
             }
             
             // 处理退出设定模式的返回
             if (hex.startsWith(CMD.EXIT_SETTING.substring(0, 8))) {
                 appendLog("退出设定模式成功");
                 return;
             }
             // 处理阈值设定的返回
             if (hex.startsWith(CMD.WRITE_THRESHOLD_SETTING.substring(0, 8))) {
                 if (isSuccess) {
                     appendLog("阈值写入成功");
                     Toast.makeText(this, "阈值写入成功", Toast.LENGTH_SHORT).show();
                     pendingToastMessage = "阈值写入成功";
                     // 阈值写入成功后,等待500毫秒再读取数据
                     appendLog("500毫秒后读取阈值设定结果...");
                     new android.os.Handler().postDelayed(() -> {
                         sendCmdWithCrc(CMD.READ_DATA);
                     }, 500);
                 } else {
                     restoreCurrentButton();
                     appendLog("阈值写入失败");
                     Toast.makeText(this, "阈值写入失败", Toast.LENGTH_SHORT).show();
                 }
             } else if (hex.startsWith(CMD.WRITE_SENSITIVITY_SETTING.substring(0, 8))) {
                 // 处理灵敏度设定的返回
                 if (isSuccess) {
                     appendLog("灵敏度写入成功");
                     Toast.makeText(this, "灵敏度写入成功", Toast.LENGTH_SHORT).show();
                     pendingToastMessage = "灵敏度写入成功";
                     // 灵敏度写入成功后,等待500毫秒再读取数据
                     appendLog("500毫秒后读取灵敏度设定结果...");
                     new android.os.Handler().postDelayed(() -> {
                         sendCmdWithCrc(CMD.READ_DATA);
                     }, 500);
                 } else {
                     restoreCurrentButton();
                     appendLog("灵敏度写入失败");
                     Toast.makeText(this, "灵敏度写入失败", Toast.LENGTH_SHORT).show();
                 }
             } else if (hex.startsWith(CMD.WRITE_BOARD_RESET.substring(0, 8))) {
             } else if (hex.startsWith(CMD.WRITE_BOARD_RESET.substring(0, 8))) {
                 // 处理主板/传感器复位的返回
                 // 判断是主板复位还是传感器复位
                 boolean isBoardReset = pendingSettingCmd.equals(CMD.WRITE_BOARD_RESET);
                 String name = isBoardReset ? "主板复位" : "传感器复位";
                 
                 if (isSuccess) {
                     appendLog(name + "成功");
                     Toast.makeText(this, name + "成功", Toast.LENGTH_SHORT).show();
                     // 如果是主板复位成功,提示即将返回并跳转到实时监控页面
                     if (isBoardReset) {
                         Toast.makeText(this, "复位成功即将返回", Toast.LENGTH_SHORT).show();
                         appendLog("复位成功,2秒后返回实时监控页面...");
                         // 2秒后返回到实时监控页面
                         new android.os.Handler().postDelayed(() -> {
                             finish();  // 关闭当前页面,返回到实时监控页面
                         }, 2000);
                     } else {
                         // 传感器复位成功,提示并在500毫秒后读取数据
                         Toast.makeText(this, name + "成功", Toast.LENGTH_SHORT).show();
                         // 500毫秒后读取数据,通过现有的parseSelfCheckData解析
                         new android.os.Handler().postDelayed(() -> {
                             sendCmdWithCrc(CMD.READ_DATA);
                         }, 500);
                     }
                 } else {
                     restoreCurrentButton();
                     appendLog(name + "失败");
                     Toast.makeText(this, name + "失败", Toast.LENGTH_SHORT).show();
                 }
             }
        }
        // Check for Self Check command response
        // 处理自检指令的返回结果
        // 开始自检和结束自检的指令前缀相同,都是 CMD.WRITE_START_CHECK 的前8位
        if (hex.startsWith(CMD.WRITE_START_CHECK.substring(0, 8)) && hex.length() >= 12) {
             // 提取状态字节(第11-12位),01表示成功,其他表示失败
             String statusHex = hex.substring(10, 12);
             boolean isSuccess = "01".equals(statusHex);
             // 根据当前模式判断操作名称
             String opName = isSelfCheckMode ? "开始自检" : "结束自检";
             
             if (isSuccess) {
                 appendLog(opName + "成功");
                 Toast.makeText(this, opName + "成功", Toast.LENGTH_SHORT).show();
                 pendingToastMessage = opName + "成功";
                 
                 // If success and isSelfCheckMode, wait 5s then read data
                 // 根据不同的自检阶段,延迟不同时间后读取数据
                 if (isSelfCheckMode) {
                     appendLog("5秒后读取自检结果...");
                     // 开始自检成功后,等待 层数 * 1000 毫秒再读取数据
                     int layerCount = com.blankj.utilcode.util.SPUtils.getInstance().getInt("layer_count", 3);
                     long delay = layerCount * 1000L;
                     Toast.makeText(this, "开始自检,请等待" + layerCount + "秒", Toast.LENGTH_SHORT).show();
                     // 这个时间是为了让传感器完成自检动作
                     appendLog(delay + "毫秒后读取自检结果...");
                     new android.os.Handler().postDelayed(() -> {
                         sendCmdWithCrc(CMD.READ_DATA);
                     }, 5000);
                     }, delay);
                 } else {
                     // 结束自检成功后,等待500毫秒再读取数据
                     // 这个时间是为了让设备状态稳定后再读取最终结果
                     appendLog("500毫秒后读取自检结果...");
                     new android.os.Handler().postDelayed(() -> {
                         sendCmdWithCrc(CMD.READ_DATA);
                     }, 500);
                 }
             } else {
                 appendLog(opName + "失败");
@@ -378,69 +506,54 @@
             }
        }
        
        // Handle READ_DATA response for Self Check results
        // A55A0301...
        // 处理读取数据指令的返回结果,用于显示自检结果
        // 数据格式:A55A0301... 至少需要26位十六进制字符
        if (hex.startsWith(CMD.READ_DATA.substring(0, 8)) && hex.length() >= 26) {
             restoreCurrentButton();
             parseSelfCheckData(hex);
             if (pendingToastMessage != null) {
                 Toast.makeText(this, pendingToastMessage, Toast.LENGTH_SHORT).show();
                 pendingToastMessage = null;
             }
        }
    }
    
    /**
     * 解析自检数据并更新格子状态
     * @param hex 接收到的十六进制数据
     */
    private void parseSelfCheckData(String hex) {
        try {
             // 11th hex -> index 10-18 (8 chars)
             // 提取第11-18位(8个字符)作为第一部分数据
             String part1Hex = hex.substring(10, 18);
             long part1Bits = Long.parseLong(part1Hex, 16);
             
             // 18th hex -> index 18-26 (8 chars)
             // 提取第19-26位(8个字符)作为第二部分数据
             String part2Hex = hex.substring(18, 26);
             long part2Bits = Long.parseLong(part2Hex, 16);
             
             appendLog("自检数据解析: " + part1Hex + ", " + part2Hex);
             
             boolean hasChange = false;
             // 遍历所有格子,根据位数据判断自检结果
             for (BoxStatus box : boxStatusList) {
                 int bitIndex = box.id - 1;
                 int bitIndex = box.id - 1;  // 格子ID从1开始,位索引从0开始
                 if (bitIndex >= 0 && bitIndex < 32) {
                     // Determine success based on both bits
                     // Assuming both need to be 1, or following specific logic.
                     // Based on user request "11th and 18th hex", we check both.
                     // Usually part1 is Glass (Detection), part2 is Online.
                     // We'll assume success means bit is set in both (Online and Detected?)
                     // OR maybe just Online?
                     // Let's stick to combining them to be safe as user mentioned both.
                     // But if Self Check is just checking if it's working, maybe Online is enough?
                     // Let's use: Success = (part1 & 1) && (part2 & 1) ?
                     // Let's use bitwise AND of the two parts for the result.
                     // 提取对应位的值
                     boolean bit1 = ((part1Bits >> bitIndex) & 1) == 1;
                     boolean bit2 = ((part2Bits >> bitIndex) & 1) == 1;
                     
                     // If user meant "11th OR 18th", or "11th is this, 18th is that".
                     // Given "Success/Fail", I'll assume both must be valid.
                     // However, in normal operation:
                     // Glass=0, Online=1 -> Empty box, but sensor working.
                     // Glass=1, Online=1 -> Full box, sensor working.
                     // Online=0 -> Sensor broken/offline.
                     // If "Self Check" puts the sensor in a state where it should report "1" for Glass?
                     // If so, then we expect Glass=1 AND Online=1.
                     // If "Self Check" just checks health, then Glass might be 0.
                     // "确定哪些格子自检成功" (Determine which grids passed self-check).
                     // If I use bit1 && bit2:
                     // If a sensor is working but empty (Glass=0), it fails self-check?
                     // This implies Self Check expects a "1" signal.
                     // This is common in self-checks (force a signal).
                     // 两个位都为1表示自检成功,否则失败
                     if (bit1 && bit2) {
                         box.checkResult = 1; // Green
                         box.checkResult = 1;  // 成功,显示绿色
                     } else {
                         box.checkResult = 0; // Red
                         box.checkResult = 0;  // 失败,显示红色
                     }
                     hasChange = true;
                 }
             }
             
             // 如果有数据变化,刷新界面
             if (hasChange && mAdapter != null) {
                 mAdapter.notifyDataSetChanged();
                 appendLog("自检结果已更新");
@@ -452,7 +565,10 @@
        }
    }
    
    /**
     * 发送带CRC校验的指令
     * @param cmd 要发送的指令(不含CRC)
     */
    private void sendCmdWithCrc(String cmd) {
        if (!BleGlobalManager.getInstance().isConnected()) {
            Toast.makeText(this, "请先连接蓝牙", Toast.LENGTH_SHORT).show();
@@ -462,42 +578,50 @@
        
        byte[] cmdBytes = BleGlobalManager.hexStringToBytes(cmd);
        if (cmdBytes != null) {
            // 计算CRC校验码
            String crc = CRCutil.getCRC(cmdBytes);
            // Pad CRC to 4 chars if needed
            // CRC补齐到4位
            while (crc.length() < 4) {
                crc = "0" + crc;
            }
            String fullCmd = cmd + crc.toUpperCase();
            
            appendLog(fullCmd, true); // true for sent (Blue)
            appendLog(fullCmd, true);  // true表示发送的指令,显示为蓝色
            BleGlobalManager.getInstance().sendCmd(fullCmd);
        } else {
            appendLog("错误: 指令转换失败");
        }
    }
    /**
     * 处理阈值设定写入
     */
    private void handleThresholdWrite() {
        int position = sp_threshold_mode.getSelectedItemPosition();
        String inputValue = et_threshold_value.getText().toString().trim();
        String modeHex = "";
        String valueHex = "";
        
        if (position == 0) { // 一键设定
        if (position == 0) {
            // 一键设定
            modeHex = "00";
            valueHex = "00";
        } else if (position == 1) { // 单层设定
        } else if (position == 1) {
            // 单层设定
            modeHex = "01";
            int maxLayer = com.blankj.utilcode.util.SPUtils.getInstance().getInt("layer_count", 30);
            if (inputValue.isEmpty()) {
                Toast.makeText(this, "请输入阈值(1-30)", Toast.LENGTH_SHORT).show();
                Toast.makeText(this, "请输入阈值(1-" + maxLayer + ")", Toast.LENGTH_SHORT).show();
                return;
            }
            try {
                int val = Integer.parseInt(inputValue);
                if (val < 1 || val > 30) {
                    Toast.makeText(this, "阈值范围1-30", Toast.LENGTH_SHORT).show();
                if (val < 1 || val > maxLayer) {
                    Toast.makeText(this, "阈值范围1-" + maxLayer, Toast.LENGTH_SHORT).show();
                    return;
                }
                valueHex = String.format("%02X", val);
                // 单层设定时,输入参数需要减1
                valueHex = String.format("%02X", val - 1);
            } catch (NumberFormatException e) {
                Toast.makeText(this, "输入格式错误", Toast.LENGTH_SHORT).show();
                return;
@@ -506,19 +630,40 @@
            return;
        }
        
        // Construct pending command: CMD (32) + Len (02) + Mode + Value
        // CMD.WRITE_THRESHOLD_SETTING is "A55A063202"
        // 构造指令:CMD.WRITE_THRESHOLD_SETTING + 模式 + 值
        pendingSettingCmd = CMD.WRITE_THRESHOLD_SETTING + modeHex + valueHex;
        sendCmdWithCrc(pendingSettingCmd);
        if (BleGlobalManager.getInstance().isConnected()) {
            currentOperatingButton = btn_threshold_write;
            updateButtonState(currentOperatingButton, false);
            setAllGridGray();
            sendCmdWithCrc(pendingSettingCmd);
        } else {
            Toast.makeText(this, "请先连接蓝牙", Toast.LENGTH_SHORT).show();
        }
    }
    
    /**
     * 将所有格子设置为灰色(等待状态)
     */
    private void setAllGridGray() {
        for (BoxStatus box : boxStatusList) {
            box.checkResult = 2; // 2表示等待状态,显示灰色
        }
        if (mAdapter != null) {
            mAdapter.notifyDataSetChanged();
        }
    }
    /**
     * 处理灵敏度设定写入
     */
    private void handleSensitivityWrite() {
        int position = sp_sensitivity_mode.getSelectedItemPosition();
        String inputValue = et_sensitivity_value.getText().toString().trim();
        String modeHex = "";
        String valueHex = "";
        
        // 0: 批量增加(00), 1: 批量减少(01), 2: 单层增加(02), 3: 单层减少(03)
        // 模式:0=批量增加(00), 1=批量减少(01), 2=单层增加(02), 3=单层减少(03)
        if (position == 0) {
            modeHex = "00";
            valueHex = "00";
@@ -533,28 +678,37 @@
            return;
        }
        
        // 单层操作需要输入具体数值
        if (position == 2 || position == 3) {
            int maxLayer = com.blankj.utilcode.util.SPUtils.getInstance().getInt("layer_count", 30);
            if (inputValue.isEmpty()) {
                Toast.makeText(this, "请输入数值(1-30)", Toast.LENGTH_SHORT).show();
                Toast.makeText(this, "请输入数值(1-" + maxLayer + ")", Toast.LENGTH_SHORT).show();
                return;
            }
            try {
                int val = Integer.parseInt(inputValue);
                if (val < 1 || val > 30) {
                    Toast.makeText(this, "数值范围1-30", Toast.LENGTH_SHORT).show();
                if (val < 1 || val > maxLayer) {
                    Toast.makeText(this, "数值范围1-" + maxLayer, Toast.LENGTH_SHORT).show();
                    return;
                }
                valueHex = String.format("%02X", val);
                // 单层设定时,输入参数需要减1
                valueHex = String.format("%02X", val - 1);
            } catch (NumberFormatException e) {
                Toast.makeText(this, "输入格式错误", Toast.LENGTH_SHORT).show();
                return;
            }
        }
        
        // Construct pending command: CMD (33) + Len (02) + Mode + Value
        // CMD.WRITE_SENSITIVITY_SETTING is "A55A063302"
        // 构造指令:CMD.WRITE_SENSITIVITY_SETTING + 模式 + 值
        pendingSettingCmd = CMD.WRITE_SENSITIVITY_SETTING + modeHex + valueHex;
        sendCmdWithCrc(pendingSettingCmd);
        if (BleGlobalManager.getInstance().isConnected()) {
            currentOperatingButton = btn_sensitivity_write;
            updateButtonState(currentOperatingButton, false);
            setAllGridGray();
            sendCmdWithCrc(pendingSettingCmd);
        } else {
            Toast.makeText(this, "请先连接蓝牙", Toast.LENGTH_SHORT).show();
        }
    }
    private void updateBluetoothStatus() {
@@ -580,20 +734,25 @@
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                         pendingSettingCmd = cmd;
                         sendCmdWithCrc(cmd);
                         if (BleGlobalManager.getInstance().isConnected()) {
                             updateButtonState(currentOperatingButton, false);
                             pendingSettingCmd = cmd;
                             sendCmdWithCrc(cmd);
                         } else {
                             Toast.makeText(ParameterSettingActivity.this, "请先连接蓝牙", Toast.LENGTH_SHORT).show();
                         }
                    }
                })
                .setNegativeButton("取消", null)
                .show();
    }
    
    // Inner classes
    /**
     * 格子状态数据类
     */
    private static class BoxStatus {
        int id;
        // -1: Unknown/Initial (White), 0: Fail (Red), 1: Success (Green)
        int checkResult = -1;
        int id;  // 格子ID(1-30)
        int checkResult = -1;  // 自检结果:-1=未知(白色),0=失败(红色),1=成功(绿色),2=等待(灰色)
        
        public BoxStatus(int id) {
            this.id = id;
@@ -612,18 +771,17 @@
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            // Calculate Box ID based on 3 rows of 10, Right to Left logic as seen in image
            // Row 1 (pos 0-9): 10 ... 1
            // Row 2 (pos 10-19): 20 ... 11
            // Row 3 (pos 20-29): 30 ... 21
            // 计算格子ID:3行10列,从左到右排列
            // 第1行(位置0-9):1-10
            // 第2行(位置10-19):11-20
            // 第3行(位置20-29):21-30
            int row = position / 10;
            int col = position % 10;
            int boxId = (row + 1) * 10 - col;
            int boxId = row * 10 + col + 1;
            
            holder.tvBoxNumber.setText(String.valueOf(boxId));
            
            // Find status for this box
            // 查找对应格子的状态
            BoxStatus status = null;
            for (BoxStatus s : boxStatusList) {
                if (s.id == boxId) {
@@ -632,16 +790,24 @@
                }
            }
            
            // 根据自检结果设置背景颜色
            if (status != null) {
                if (status.checkResult == 1) {
                    // Success
                    holder.viewBox.setBackgroundResource(R.drawable.bg_box_full); // Green
                    // 自检成功,显示绿色
                    holder.viewBox.setBackgroundResource(R.drawable.bg_box_full);
                    holder.viewBox.getBackground().clearColorFilter();
                } else if (status.checkResult == 0) {
                    // Fail
                    holder.viewBox.setBackgroundResource(R.drawable.bg_box_error); // Red
                    // 自检失败,显示红色
                    holder.viewBox.setBackgroundResource(R.drawable.bg_box_error);
                    holder.viewBox.getBackground().clearColorFilter();
                } else if (status.checkResult == 2) {
                    // 等待状态,显示灰色
                    holder.viewBox.setBackgroundResource(R.drawable.bg_box_empty);
                    holder.viewBox.getBackground().setColorFilter(android.graphics.Color.GRAY, android.graphics.PorterDuff.Mode.MULTIPLY);
                } else {
                    // Unknown / Initial
                    holder.viewBox.setBackgroundResource(R.drawable.bg_box_empty); // White
                    // 未知状态,显示白色
                    holder.viewBox.setBackgroundResource(R.drawable.bg_box_empty);
                    holder.viewBox.getBackground().clearColorFilter();
                }
            }
        }
@@ -662,4 +828,25 @@
            }
        }
    }
    private void restoreCurrentButton() {
        if (currentOperatingButton != null) {
            updateButtonState(currentOperatingButton, true);
            currentOperatingButton = null;
        }
    }
    private void updateButtonState(Button btn, boolean enable) {
        if (btn == null) return;
        btn.setEnabled(enable);
        if (enable) {
            if (btn.getBackground() != null) {
                btn.getBackground().clearColorFilter();
            }
        } else {
            if (btn.getBackground() != null) {
                btn.getBackground().setColorFilter(android.graphics.Color.GRAY, android.graphics.PorterDuff.Mode.MULTIPLY);
            }
        }
    }
}