package m9z import ( "bytes" "fmt" "github.com/towgo/towgo/errors/terror" ) // 对应C的db_ble_extern_t结构体(简化版,使用bool型Enable) type BluetoothConfig struct { Enable bool // 离线监控使能(false=禁止,true=允许/0xAA) OfflineMin uint8 // 离线时间(分钟数) BleName string // 蓝牙名称(最大20字节) 不支持中文 } func BluetoothRead(deviceId string) (*BluetoothConfig, error) { // 1. 读取指令 cmd, err := ReadCmd(deviceId, bluetooth, "设备蓝牙配置读取") if err != nil { errMsg := fmt.Sprintf("读取设备%s蓝牙配置失败: %v", deviceId, err) return nil, terror.New(errMsg) } data := cmd.Data // 2. 校验基础长度(至少2字节:离线监控+离线时间) const minDataLen = 2 if len(data) < minDataLen { errMsg := fmt.Sprintf("蓝牙配置数据长度不足,至少需要%d字节,实际收到%d字节", minDataLen, len(data)) return nil, terror.New(errMsg) } // 3. 解析基础字段(固定2字节) var bleConfig BluetoothConfig bleConfig.Enable = data[0] == 0xAA // 0xAA对应true(允许),其他为false(禁止) bleConfig.OfflineMin = data[1] // 离线时间 // 4. 解析蓝牙名称(动态长度,最多20字节) nameBytes := data[2:] // 取基础字段后的所有字节 if len(nameBytes) > 20 { nameBytes = nameBytes[:20] // 超过20字节则截断 } // 去掉名称末尾的空字符(设备返回的结束符) bleConfig.BleName = string(bytes.TrimRight(nameBytes, "\x00")) return &bleConfig, nil } // BluetoothWrite 写入蓝牙配置到设备(修复所有核心问题) func BluetoothWrite(deviceId string, bleConfig *BluetoothConfig) error { // 1. 精准参数校验(拆分判断,提示语匹配) if bleConfig == nil { errMsg := "蓝牙配置结构体为nil,无法写入" return terror.New(errMsg) } nameBytes := []byte(bleConfig.BleName) if len(nameBytes) > 20 { errMsg := fmt.Sprintf("蓝牙名称超长,最大支持20字节,实际传入%d字节", len(nameBytes)) return terror.New(errMsg) } // 校验1:是否包含中文/非ASCII字符 if hasChinese(bleConfig.BleName) { errMsg := fmt.Sprintf("设备[%s]蓝牙名称包含中文/非ASCII字符,仅支持英文/数字/符号等ASCII字符", deviceId) return terror.New(errMsg) } // 2. 构造缓冲区:2字节基础字段 + 动态长度蓝牙名称 buf := make([]byte, 2) // 先初始化基础字段缓冲区 // 编码离线监控使能(Byte0:0=禁止,0xAA=允许) if bleConfig.Enable { buf[0] = 0xAA } else { buf[0] = 0x00 } // 编码离线时间(Byte1) buf[1] = bleConfig.OfflineMin // 追加蓝牙名称(仅追加一次,修复重复追加问题) buf = append(buf, nameBytes...) // 调试日志:打印最终缓冲区(长度+十六进制) //g.Log().Debugf("Bluetooth Write raw data: len=%d , hex=% X", len(buf), buf) // 3. 发送写入命令 writeResp, err := WriteCmd(deviceId, bluetooth, buf, "设备蓝牙配置写入") if err != nil { errMsg := fmt.Sprintf("设备[%s]蓝牙配置写入命令调用失败", deviceId) return terror.Wrapf(err, errMsg) } // 4. 检查写入响应状态(修复err为nil的问题) if !writeResp.Success { errMsg := fmt.Sprintf("设备[%s]蓝牙配置写入失败,响应状态为失败", deviceId) // 手动构造错误,避免Wrapf传入nil return terror.New(errMsg) } // 5. 写入成功日志(修复切片越界问题:用buf[2:]而非固定22) //bleNameStr := string(bytes.TrimRight(buf[2:], "\x00")) //g.Log().Infof("设备%s蓝牙配置写入成功,离线监控使能:%v,离线时间:%d分钟,蓝牙名称:%s", // deviceId, bleConfig.Enable, bleConfig.OfflineMin, bleNameStr) return nil } // hasChinese 辅助函数:判断字符串是否包含中文(或非ASCII字符) func hasChinese(s string) bool { for _, r := range s { // 中文Unicode范围:0x4E00-0x9FFF,同时拦截所有>127的非ASCII字符 if r > 127 || (r >= 0x4E00 && r <= 0x9FFF) { return true } } return false }