msgdata.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package msgdata
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "pbx-api-gin/pkg/lfshook"
  7. )
  8. // Protocol 定义协议数据结构
  9. type Protocol struct {
  10. StartBytes [3]byte // 协议开始符
  11. SourceID uint8 // 源设备号
  12. DestinationID uint8 // 目的设备号
  13. MessageID uint8 // 消息号
  14. DataLength uint16 // 数据长度
  15. Data []byte // 数据
  16. Checksum uint8 // 异或校验码
  17. EndByte uint8 // 协议结束符
  18. }
  19. // NewProtocol 创建一个新的 Protocol 实例
  20. func NewProtocol() *Protocol {
  21. return &Protocol{
  22. StartBytes: [3]byte{0x7F, 0x8E, 0x9D},
  23. EndByte: 0xFE,
  24. }
  25. }
  26. // Encode 将 Protocol 结构体编码为字节切片
  27. func (p *Protocol) Encode() ([]byte, error) {
  28. // 初始化字节缓冲区
  29. var buf bytes.Buffer // 写入协议开始符
  30. buf.Write(p.StartBytes[:])
  31. //init src and dst ID
  32. p.SourceID = 0x02
  33. p.DestinationID = 0x01
  34. // 写入源设备号、目的设备号和消息号
  35. binary.Write(&buf, binary.BigEndian, p.SourceID)
  36. binary.Write(&buf, binary.BigEndian, p.DestinationID)
  37. binary.Write(&buf, binary.BigEndian, p.MessageID)
  38. // 写入数据长度
  39. binary.Write(&buf, binary.BigEndian, p.DataLength)
  40. // 写入数据
  41. buf.Write(p.Data[:])
  42. // 计算校验码
  43. checksum := p.CalculateChecksum()
  44. p.Checksum = checksum // 写入校验码
  45. binary.Write(&buf, binary.BigEndian, p.Checksum)
  46. // 写入协议结束符
  47. binary.Write(&buf, binary.BigEndian, p.EndByte)
  48. return buf.Bytes(), nil
  49. }
  50. // CalculateChecksum 计算校验码
  51. func (p *Protocol) CalculateChecksum() uint8 {
  52. // 初始化校验码
  53. checksum := uint8(0)
  54. // 跳过协议开始符
  55. data := append([]byte{byte(p.SourceID), byte(p.DestinationID), byte(p.MessageID)},
  56. append([]byte{byte(p.DataLength >> 8), byte(p.DataLength)}, p.Data...)...)
  57. // 计算校验码
  58. for _, b := range data {
  59. checksum ^= b
  60. }
  61. return checksum
  62. }
  63. // Decode 解码字节切片为 Protocol 结构体
  64. func Decode(data []byte) (*Protocol, error) {
  65. if len(data) < 10 { // 最小长度:3(StartBytes) +1(SourceID) +1(DestinationID) +1(MessageID) +2(DataLength) +1(Checksum) +1(EndByte)
  66. return nil, fmt.Errorf("data too short")
  67. }
  68. p := NewProtocol()
  69. // 读取协议开始符
  70. copy(p.StartBytes[:], data[:3])
  71. // 读取源设备号、目的设备号和消息号
  72. p.SourceID = data[3]
  73. p.DestinationID = data[4]
  74. p.MessageID = data[5]
  75. // 读取数据长度
  76. p.DataLength = binary.BigEndian.Uint16(data[6:8])
  77. // 读取数据
  78. dataLength := int(p.DataLength)
  79. if len(data) < 10+dataLength {
  80. return nil, fmt.Errorf("data length mismatch")
  81. }
  82. p.Data = data[8 : 8+dataLength]
  83. // 读取校验码
  84. p.Checksum = data[8+dataLength]
  85. // 读取协议结束符
  86. p.EndByte = data[9+dataLength]
  87. // 验证校验码
  88. if p.Checksum != p.CalculateChecksum() {
  89. return nil, fmt.Errorf("checksum mismatch")
  90. }
  91. return p, nil
  92. }
  93. func SubstrByRune(s string, start, length int) string {
  94. runes := []rune(s)
  95. if start >= len(runes) {
  96. return ""
  97. }
  98. end := start + length
  99. if end > len(runes) {
  100. end = len(runes)
  101. }
  102. return string(runes[start:end])
  103. }
  104. func ExtractPacket(buf *bytes.Buffer) ([]byte, error) {
  105. data := buf.Bytes()
  106. leng := buf.Len()
  107. //lfshook.NewLogger().Logger.Infof("========start=========ExtractPacket raw data len=%d, hex=%x", leng, data)
  108. // Step 1: 查找起始标记 0x7f 0x8e 0x9d
  109. startIdx := -1
  110. for i := 0; i <= len(data)-3; i++ { // <= len-3 防止越界
  111. if data[i] == 0x7f && data[i+1] == 0x8e && data[i+2] == 0x9d {
  112. startIdx = i
  113. break
  114. }
  115. }
  116. if startIdx == -1 {
  117. //无起始标记:保守策略——丢弃过长脏数据,保留最后 MAX_LOOKAHEAD 字节防漏包
  118. const MAX_LOOKAHEAD = 32
  119. if leng > MAX_LOOKAHEAD {
  120. buf.Next(leng - MAX_LOOKAHEAD)
  121. lfshook.NewLogger().Logger.Warnf("no start marker found, trimmed buffer to last %d bytes", MAX_LOOKAHEAD)
  122. }
  123. return nil, nil // 明确告知:需继续读取
  124. }
  125. // Step 2: 安全读取 DataLength(偏移 startIdx+6 ~ startIdx+8)
  126. if startIdx+8 > len(data) {
  127. lfshook.NewLogger().Logger.Infof("startIdx=%d, need data[%d:%d] for DataLength but len=%d → insufficient data",
  128. startIdx, startIdx+6, startIdx+8, len(data))
  129. return nil, nil // 数据不够,等下次读取
  130. }
  131. dataLen := binary.BigEndian.Uint16(data[startIdx+6 : startIdx+8])
  132. //lfshook.NewLogger().Logger.Infof("ExtractPacket datalen=%d (0x%04x) at offset %d", dataLen, dataLen, startIdx+6)
  133. // Step 3: 计算理论包结束位置:startIdx + 8(头长) + dataLen + 1(0xFE)
  134. endPosTheo := startIdx + 8 + int(dataLen) + 1
  135. if endPosTheo > len(data) {
  136. lfshook.NewLogger().Logger.Infof("theoretical endPos=%d > data len=%d → need more data", endPosTheo, len(data))
  137. return nil, nil // 包未收全,等下次读取
  138. }
  139. //lfshook.NewLogger().Logger.Infof("t=================end================%x", data[endPosTheo])
  140. // Step 4: 在 [startIdx+8+dataLen, endPosTheo] 范围内查找 0xFE(容错:允许在理论位置附近 1~2 字节浮动)
  141. searchStart := startIdx + 8 + int(dataLen)
  142. searchEnd := endPosTheo
  143. if searchEnd > len(data) {
  144. searchEnd = len(data) // 安全截断
  145. }
  146. endIdx := -1
  147. for i := searchStart; i <= searchEnd; i++ {
  148. if data[i] == 0xFE {
  149. endIdx = i
  150. break
  151. }
  152. }
  153. if endIdx == -1 {
  154. lfshook.NewLogger().Logger.Infof("0xFE not found in expected range [%d,%d), dataLen=%d", searchStart, searchEnd, dataLen)
  155. return nil, nil // 结束符缺失,但可能是延迟到达,继续等
  156. }
  157. //找到完整包:[startIdx, endIdx](含两端)
  158. packetLen := endIdx - startIdx + 1
  159. packet := make([]byte, packetLen)
  160. copy(packet, data[startIdx:endIdx+1])
  161. // 从 buffer 中移除已处理部分
  162. buf.Next(endIdx + 1)
  163. //lfshook.NewLogger().Logger.Infof("extracted packet len=%d, start=0x7f8e9d, end=0xFE", packetLen)
  164. //lfshook.NewLogger().Logger.Infof("=============return============== %x", packet)
  165. return packet, nil
  166. }