83 lines
2.7 KiB
Go
83 lines
2.7 KiB
Go
package ble
|
||
|
||
import (
|
||
"device-ble/internal/interfaces"
|
||
"encoding/binary"
|
||
"encoding/json"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/google/uuid"
|
||
)
|
||
|
||
const (
|
||
MTU = 247 // 蓝牙模块 MTU 限制为 64 字节
|
||
Suffix = "\r\n" // AT 指令后缀 (2字节)
|
||
HeaderSize = 4 // 分包头部:2 字节索引 + 2 字节总包数
|
||
)
|
||
|
||
var Prefix string = "AT+QBLEGATTSNTFY=0,fff2," // AT 指令前缀 (20字节)
|
||
var MaxPayload int = MTU - len(Prefix) - len(Suffix) - HeaderSize // 实际载荷大小:247 - 20 - 2 - 4 = 221 字节
|
||
// Packet 分包结构
|
||
type Packet struct {
|
||
Index uint16 // 分包索引
|
||
Total uint16 // 总分包数
|
||
Payload []byte // 数据载荷
|
||
}
|
||
|
||
// splitIntoPackets 将数据分包
|
||
func splitIntoPackets(data []byte) []Packet {
|
||
var packets []Packet
|
||
totalPackets := (len(data) + MaxPayload - 1) / MaxPayload // 向上取整
|
||
|
||
for i := 0; i < len(data); i += MaxPayload {
|
||
end := i + MaxPayload
|
||
if end > len(data) {
|
||
end = len(data)
|
||
}
|
||
|
||
packet := Packet{
|
||
Index: uint16(i / MaxPayload),
|
||
Total: uint16(totalPackets),
|
||
Payload: data[i:end],
|
||
}
|
||
packets = append(packets, packet)
|
||
}
|
||
|
||
return packets
|
||
}
|
||
|
||
// SendJSONOverBLE 发送 JSON 数据的主要函数。
|
||
func SendJSONOverBLE(sq interfaces.SerialQueueInterface, jsonData interface{}) error {
|
||
// 这里需要传入logger参数,建议后续重构接口
|
||
// 目前先用fmt.Println模拟日志,后续可传入logger
|
||
tag := uuid.New().String()
|
||
dataBytes, err := json.Marshal(jsonData)
|
||
if err != nil {
|
||
return fmt.Errorf("JSON序列化失败: %v", err)
|
||
}
|
||
packets := splitIntoPackets(dataBytes)
|
||
for _, packet := range packets {
|
||
packetData := make([]byte, len(Prefix)+HeaderSize+len(packet.Payload)+len(Suffix))
|
||
copy(packetData, Prefix)
|
||
binary.BigEndian.PutUint16(packetData[len(Prefix):], packet.Index)
|
||
binary.BigEndian.PutUint16(packetData[len(Prefix)+2:], packet.Total)
|
||
copy(packetData[len(Prefix)+HeaderSize:], packet.Payload)
|
||
copy(packetData[len(Prefix)+HeaderSize+len(packet.Payload):], Suffix)
|
||
|
||
response, err := sq.SendCommand(packetData, 300*time.Millisecond, 1*time.Millisecond, 100*time.Millisecond)
|
||
if strings.Contains(response, "OK") {
|
||
fmt.Printf("⚡ 数据包: %v ⬇️ 子包: %d/%d 发送成功, size:%d bytes\n", tag, packet.Index+1, packet.Total, len(packetData))
|
||
} else if strings.Contains(response, "ERROR") {
|
||
fmt.Printf("⛔️ 数据包: %v ⬇️ 子包: %d/%d 发送失败\n", tag, packet.Index+1, packet.Total)
|
||
return err
|
||
} else {
|
||
fmt.Printf("❗❓ 数据包: %v ⬇️ 子包: %d/%d 未知回显:%v, error:%v\n", tag, packet.Index+1, packet.Total, response, err)
|
||
return err
|
||
}
|
||
}
|
||
fmt.Printf("✅️ All packets of Packet %v sent and verified.\n", tag)
|
||
return nil
|
||
}
|