| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- package msgdata
- import (
- "bytes"
- "encoding/binary"
- "fmt"
- "pbx-api-gin/pkg/utils"
- )
- // Protocol 定义协议数据结构
- type Protocol struct {
- StartBytes [3]byte // 协议开始符
- SourceID uint8 // 源设备号
- DestinationID uint8 // 目的设备号
- MessageID uint8 // 消息号
- DataLength uint16 // 数据长度
- Data []byte // 数据
- Checksum uint8 // 异或校验码
- EndByte uint8 // 协议结束符
- }
- // NewProtocol 创建一个新的 Protocol 实例
- func NewProtocol() *Protocol {
- return &Protocol{
- StartBytes: [3]byte{0x7F, 0x8E, 0x9D},
- EndByte: 0xFE,
- }
- }
- // Encode 将 Protocol 结构体编码为字节切片
- func (p *Protocol) Encode() ([]byte, error) {
- // 初始化字节缓冲区
- var buf bytes.Buffer // 写入协议开始符
- buf.Write(p.StartBytes[:])
- //init src and dst ID
- p.SourceID = 0x02
- p.DestinationID = 0x01
- // 写入源设备号、目的设备号和消息号
- binary.Write(&buf, binary.BigEndian, p.SourceID)
- binary.Write(&buf, binary.BigEndian, p.DestinationID)
- binary.Write(&buf, binary.BigEndian, p.MessageID)
- // 写入数据长度
- binary.Write(&buf, binary.BigEndian, p.DataLength)
- // 写入数据
- buf.Write(p.Data[:])
- // 计算校验码
- checksum := p.CalculateChecksum()
- p.Checksum = checksum // 写入校验码
- binary.Write(&buf, binary.BigEndian, p.Checksum)
- // 写入协议结束符
- binary.Write(&buf, binary.BigEndian, p.EndByte)
- return buf.Bytes(), nil
- }
- // CalculateChecksum 计算校验码
- func (p *Protocol) CalculateChecksum() uint8 {
- // 初始化校验码
- checksum := uint8(0)
- // 跳过协议开始符
- data := append([]byte{byte(p.SourceID), byte(p.DestinationID), byte(p.MessageID)},
- append([]byte{byte(p.DataLength >> 8), byte(p.DataLength)}, p.Data...)...)
- // 计算校验码
- for _, b := range data {
- checksum ^= b
- }
- return checksum
- }
- // Decode 解码字节切片为 Protocol 结构体
- func Decode(data []byte) (*Protocol, error) {
- if len(data) < 10 { // 最小长度:3(StartBytes) +1(SourceID) +1(DestinationID) +1(MessageID) +2(DataLength) +1(Checksum) +1(EndByte)
- return nil, fmt.Errorf("data too short")
- }
- p := NewProtocol()
- // 读取协议开始符
- copy(p.StartBytes[:], data[:3])
- // 读取源设备号、目的设备号和消息号
- p.SourceID = data[3]
- p.DestinationID = data[4]
- p.MessageID = data[5]
- // 读取数据长度
- p.DataLength = binary.BigEndian.Uint16(data[6:8])
- // 读取数据
- dataLength := int(p.DataLength)
- if len(data) < 10+dataLength {
- return nil, fmt.Errorf("data length mismatch")
- }
- p.Data = data[8 : 8+dataLength]
- // 读取校验码
- p.Checksum = data[8+dataLength]
- // 读取协议结束符
- p.EndByte = data[9+dataLength]
- // 验证校验码
- if p.Checksum != p.CalculateChecksum() {
- return nil, fmt.Errorf("checksum mismatch")
- }
- return p, nil
- }
- func SubstrByRune(s string, start, length int) string {
- runes := []rune(s)
- if start >= len(runes) {
- return ""
- }
- end := start + length
- if end > len(runes) {
- end = len(runes)
- }
- return string(runes[start:end])
- }
- func ExtractPacket(buf *bytes.Buffer) ([]byte, error) {
- data := buf.Bytes()
- leng := buf.Len()
- //lfshook.NewLogger().Logger.Infof("========start=========ExtractPacket raw data len=%d, hex=%x", leng, data)
- // Step 1: 查找起始标记 0x7f 0x8e 0x9d
- startIdx := -1
- for i := 0; i <= len(data)-3; i++ { // <= len-3 防止越界
- if data[i] == 0x7f && data[i+1] == 0x8e && data[i+2] == 0x9d {
- startIdx = i
- break
- }
- }
- if startIdx == -1 {
- //无起始标记:保守策略——丢弃过长脏数据,保留最后 MAX_LOOKAHEAD 字节防漏包
- const MAX_LOOKAHEAD = 32
- if leng > MAX_LOOKAHEAD {
- buf.Next(leng - MAX_LOOKAHEAD)
- utils.LoggerDebug.Printf("No start marker found, trimmed buffer to last %d bytes .", MAX_LOOKAHEAD)
- }
- return nil, nil // 明确告知:需继续读取
- }
- // Step 2: 安全读取 DataLength(偏移 startIdx+6 ~ startIdx+8)
- if startIdx+8 > len(data) {
- utils.LoggerDebug.Printf("Data Error: startIdx=%d, need data[%d:%d] for DataLength but len=%d → insufficient data .",
- startIdx, startIdx+6, startIdx+8, len(data))
- return nil, nil // 数据不够,等下次读取
- }
- dataLen := binary.BigEndian.Uint16(data[startIdx+6 : startIdx+8])
- //lfshook.NewLogger().Logger.Infof("ExtractPacket datalen=%d (0x%04x) at offset %d", dataLen, dataLen, startIdx+6)
- // Step 3: 计算理论包结束位置:startIdx + 8(头长) + dataLen + 1(0xFE)
- endPosTheo := startIdx + 8 + int(dataLen) + 1
- if endPosTheo > len(data) {
- utils.LoggerDebug.Printf("Data Error: theoretical endPos=%d > data len=%d → need more data .", endPosTheo, len(data))
- return nil, nil // 包未收全,等下次读取
- }
- //lfshook.NewLogger().Logger.Infof("t=================end================%x", data[endPosTheo])
- // Step 4: 在 [startIdx+8+dataLen, endPosTheo] 范围内查找 0xFE(容错:允许在理论位置附近 1~2 字节浮动)
- searchStart := startIdx + 8 + int(dataLen)
- searchEnd := endPosTheo
- if searchEnd > len(data) {
- searchEnd = len(data) // 安全截断
- }
- endIdx := -1
- for i := searchStart; i <= searchEnd; i++ {
- if data[i] == 0xFE {
- endIdx = i
- break
- }
- }
- if endIdx == -1 {
- utils.LoggerDebug.Printf("Data Error: End tag 0xFE not found in expected range [%d,%d), dataLen=%d .", searchStart, searchEnd, dataLen)
- return nil, nil // 结束符缺失,但可能是延迟到达,继续等
- }
- //找到完整包:[startIdx, endIdx](含两端)
- packetLen := endIdx - startIdx + 1
- packet := make([]byte, packetLen)
- copy(packet, data[startIdx:endIdx+1])
- // 从 buffer 中移除已处理部分
- buf.Next(endIdx + 1)
- //lfshook.NewLogger().Logger.Infof("extracted packet len=%d, start=0x7f8e9d, end=0xFE", packetLen)
- //lfshook.NewLogger().Logger.Infof("=============return============== %x", packet)
- return packet, nil
- }
|