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.

121 lines
4.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package m9z
import (
"bytes"
"fmt"
"github.com/gogf/gf/v2/errors/gerror"
)
// 对应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, gerror.New(errMsg)
}
data := cmd.Data
// 2. 校验基础长度至少2字节离线监控+离线时间)
const minDataLen = 2
if len(data) < minDataLen {
errMsg := fmt.Sprintf("蓝牙配置数据长度不足,至少需要%d字节实际收到%d字节", minDataLen, len(data))
return nil, gerror.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 gerror.New(errMsg)
}
nameBytes := []byte(bleConfig.BleName)
if len(nameBytes) > 20 {
errMsg := fmt.Sprintf("蓝牙名称超长最大支持20字节实际传入%d字节", len(nameBytes))
return gerror.New(errMsg)
}
// 校验1是否包含中文/非ASCII字符
if hasChinese(bleConfig.BleName) {
errMsg := fmt.Sprintf("设备[%s]蓝牙名称包含中文/非ASCII字符仅支持英文/数字/符号等ASCII字符", deviceId)
return gerror.New(errMsg)
}
// 2. 构造缓冲区2字节基础字段 + 动态长度蓝牙名称
buf := make([]byte, 2) // 先初始化基础字段缓冲区
// 编码离线监控使能Byte00=禁止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 gerror.Wrapf(err, errMsg)
}
// 4. 检查写入响应状态修复err为nil的问题
if !writeResp.Success {
errMsg := fmt.Sprintf("设备[%s]蓝牙配置写入失败,响应状态为失败", deviceId)
// 手动构造错误避免Wrapf传入nil
return gerror.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
}