2024-05-29 11:48:04 +08:00
|
|
|
|
package message
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
"encoding/hex"
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/snksoft/crc"
|
|
|
|
|
"log/slog"
|
|
|
|
|
"strconv"
|
|
|
|
|
"sync"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
TRAIN_BTM_ENDA = 0x75E1
|
|
|
|
|
TRAIN_BTM_ENDB = 0x75E2
|
|
|
|
|
ID_COMMAND_TYPE = 0xF8 //命令帧
|
|
|
|
|
REQT_TYPE = 0xE6 //请求帧
|
|
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
COMMAND_TYPE = 0x90 //ID 命令帧 VOBC→BTM20 字节
|
|
|
|
|
REQUEST_TYPE = 0x91 //请求帧 VOBC→BTM34 字节
|
|
|
|
|
MESSAGE_TYPE = 0x92 //报文帧 BTM→VOBC 135 字节
|
|
|
|
|
FREE_MESSAGE_TYPE = 0x94 //空闲帧 BTM→VOBC 135 字节
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var PACKAGE_HEAD = []byte{0xFF, 0xFE}
|
|
|
|
|
var PACKAGE_END = []byte{0xFF, 0xFD}
|
|
|
|
|
|
|
|
|
|
func BtmVobcDecode(packData []byte) (byte, []byte, error) {
|
|
|
|
|
head := packData[:2]
|
|
|
|
|
end := packData[len(packData)-2:]
|
2024-06-06 17:57:30 +08:00
|
|
|
|
|
2024-05-29 11:48:04 +08:00
|
|
|
|
if !bytes.Equal(head, PACKAGE_HEAD) || !bytes.Equal(end, PACKAGE_END) {
|
|
|
|
|
slog.Error("btm vobc 数据包头或包尾尾错误", hex.EncodeToString(packData))
|
|
|
|
|
return 0, nil, fmt.Errorf("btm vobc 数据包头或包尾尾错误")
|
|
|
|
|
}
|
|
|
|
|
data := packData[2 : len(packData)-2]
|
|
|
|
|
command := data[0]
|
|
|
|
|
if command != ID_COMMAND_TYPE && command != REQT_TYPE {
|
|
|
|
|
slog.Error("btm vobc 解析未知命令帧", strconv.FormatInt(int64(command), 16), command)
|
|
|
|
|
return 0, nil, fmt.Errorf("btm vobc 解析未知命令帧")
|
|
|
|
|
}
|
|
|
|
|
dataText := data[1:]
|
2024-06-06 17:57:30 +08:00
|
|
|
|
if command == ID_COMMAND_TYPE {
|
|
|
|
|
|
|
|
|
|
frameType := dataText[0]
|
|
|
|
|
return frameType, dataText, nil
|
|
|
|
|
} else if command == REQT_TYPE {
|
|
|
|
|
newDatatext, _ := TranslateFromFFFE(dataText)
|
|
|
|
|
rssp := &RsspRsd{}
|
|
|
|
|
rsspErr := rssp.Decode(newDatatext)
|
|
|
|
|
if rsspErr != nil {
|
|
|
|
|
//slog.Error("解析请求帧rssp-i失败,元数据:", hex.EncodeToString(cfs), "错误信息:", rsspErr.Error())
|
|
|
|
|
return 0, nil, fmt.Errorf("解析请求帧rssp-i失败")
|
|
|
|
|
}
|
|
|
|
|
return rssp.Sad[0], rssp.Sad, nil
|
|
|
|
|
}
|
|
|
|
|
return 0, nil, fmt.Errorf("btm vobc 解析未知命令帧")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
WAIT_FF_C1 = 0x00
|
|
|
|
|
WAIT_FF_C2 = 0x01
|
|
|
|
|
WAIT_NO_FF = 0x02
|
|
|
|
|
WAIT_FF_POS = 0x03
|
|
|
|
|
ABNORMAL_STATE = 0x04
|
2024-05-29 11:48:04 +08:00
|
|
|
|
|
2024-06-06 17:57:30 +08:00
|
|
|
|
/*FFFE数据接收状态*/
|
|
|
|
|
COM_WAIT_START_FF = 0x00
|
|
|
|
|
COM_WAIT_START_FE = 0x01
|
|
|
|
|
COM_WAIT_STOP_FF = 0x02
|
|
|
|
|
COM_WAIT_STOP_FD = 0x03
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func aa(src []byte, dest []byte) uint16 {
|
|
|
|
|
var (
|
|
|
|
|
SrcPos, TgtPos, Pos1, Pos2, iii, Gap uint16
|
|
|
|
|
Got1stFF uint8
|
|
|
|
|
)
|
|
|
|
|
srouceLen := uint16(len(src))
|
|
|
|
|
for SrcPos = 0; SrcPos < srouceLen; SrcPos++ {
|
|
|
|
|
if Got1stFF == 1 {
|
|
|
|
|
if src[SrcPos] == 0xff {
|
|
|
|
|
//Got2ndFF = 1
|
|
|
|
|
Pos2 = SrcPos
|
|
|
|
|
dest[TgtPos] = byte(Pos2 - Pos1)
|
|
|
|
|
TgtPos++
|
2024-05-29 11:48:04 +08:00
|
|
|
|
|
2024-06-06 17:57:30 +08:00
|
|
|
|
for iii = Pos1 + 1; iii < Pos2; iii++ {
|
|
|
|
|
dest[TgtPos] = src[iii]
|
|
|
|
|
TgtPos++
|
|
|
|
|
}
|
|
|
|
|
Got1stFF = 0
|
|
|
|
|
//Got2ndFF = 0
|
|
|
|
|
Pos1 = 0
|
|
|
|
|
Pos2 = 0
|
|
|
|
|
Gap = 0
|
|
|
|
|
} else {
|
|
|
|
|
/*已遇到前一个FF,且当前遇到非FF*/
|
|
|
|
|
Gap++
|
|
|
|
|
if 252 == Gap {
|
|
|
|
|
Got1stFF = 0
|
|
|
|
|
Gap = 0
|
|
|
|
|
dest[TgtPos] = 0
|
|
|
|
|
TgtPos++
|
|
|
|
|
for iii = Pos1 + 1; iii <= SrcPos; iii++ {
|
|
|
|
|
dest[TgtPos] = src[iii]
|
|
|
|
|
TgtPos++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-29 11:48:04 +08:00
|
|
|
|
} else {
|
2024-06-06 17:57:30 +08:00
|
|
|
|
/*尚未遇到前一个FF*/
|
|
|
|
|
dest[TgtPos] = src[SrcPos]
|
|
|
|
|
TgtPos++
|
|
|
|
|
if 0xFF == src[SrcPos] {
|
|
|
|
|
/*遇到前一个FF*/
|
|
|
|
|
Got1stFF = 1
|
|
|
|
|
Pos1 = SrcPos
|
|
|
|
|
Gap = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if 1 == Got1stFF {
|
|
|
|
|
dest[TgtPos] = 0
|
|
|
|
|
TgtPos++
|
|
|
|
|
for iii = Pos1 + 1; iii < srouceLen; iii++ {
|
|
|
|
|
dest[TgtPos] = src[iii]
|
|
|
|
|
TgtPos++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return TgtPos
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TranslateFromFFFE(pSrc []byte) ([]byte, uint16) {
|
|
|
|
|
var (
|
|
|
|
|
srcPos, tgtPos, nonFFCount, nextFFPos uint16
|
|
|
|
|
char uint8
|
|
|
|
|
state int
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if len(pSrc) == 0 {
|
|
|
|
|
return nil, 0 // 入参错误
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pTgt := make([]byte, len(pSrc)) // 预分配与输入等长的缓冲区
|
|
|
|
|
tgtPos = 0
|
|
|
|
|
state = WAIT_FF_C1
|
|
|
|
|
nonFFCount = 0
|
|
|
|
|
|
|
|
|
|
for srcPos = 0; srcPos < uint16(len(pSrc)); srcPos++ {
|
|
|
|
|
char = pSrc[srcPos]
|
|
|
|
|
switch state {
|
|
|
|
|
case WAIT_FF_C1:
|
|
|
|
|
if char == 0xFF {
|
|
|
|
|
pTgt[tgtPos] = char
|
|
|
|
|
tgtPos++
|
|
|
|
|
state = WAIT_FF_C2
|
|
|
|
|
} else {
|
|
|
|
|
pTgt[tgtPos] = char
|
|
|
|
|
tgtPos++
|
|
|
|
|
}
|
|
|
|
|
case WAIT_FF_C2:
|
|
|
|
|
if char == 0xFD || char == 0xFE || char == 0xFF {
|
|
|
|
|
state = ABNORMAL_STATE
|
|
|
|
|
} else {
|
|
|
|
|
if char == 0 {
|
|
|
|
|
state = WAIT_NO_FF
|
|
|
|
|
} else if char == 1 {
|
|
|
|
|
pTgt[tgtPos] = 0xFF
|
|
|
|
|
tgtPos++
|
|
|
|
|
state = WAIT_FF_C1
|
|
|
|
|
} else {
|
|
|
|
|
nextFFPos = srcPos + uint16(char) - 1
|
|
|
|
|
state = WAIT_FF_POS
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case WAIT_NO_FF:
|
|
|
|
|
nonFFCount++
|
|
|
|
|
if char == 0xFF && nonFFCount < 252 {
|
|
|
|
|
state = ABNORMAL_STATE
|
|
|
|
|
} else {
|
|
|
|
|
pTgt[tgtPos] = char
|
|
|
|
|
tgtPos++
|
|
|
|
|
if nonFFCount == 252 {
|
|
|
|
|
nonFFCount = 0
|
|
|
|
|
state = WAIT_FF_C1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case WAIT_FF_POS:
|
|
|
|
|
if char == 0xFF {
|
|
|
|
|
state = ABNORMAL_STATE
|
|
|
|
|
} else {
|
|
|
|
|
pTgt[tgtPos] = char
|
|
|
|
|
tgtPos++
|
|
|
|
|
if srcPos == nextFFPos {
|
|
|
|
|
pTgt[tgtPos] = 0xFF
|
|
|
|
|
tgtPos++
|
|
|
|
|
state = WAIT_FF_C1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
state = ABNORMAL_STATE
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if state == ABNORMAL_STATE {
|
|
|
|
|
tgtPos = 0
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 退出时的状态判断
|
|
|
|
|
if state == WAIT_FF_C2 || state == WAIT_FF_POS {
|
|
|
|
|
tgtPos = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pTgt[:tgtPos], tgtPos
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TranslateToFFFE 对给定的字节切片进行FFFE转义处理
|
|
|
|
|
func TranslateToFFFE(src []byte) ([]byte, error) {
|
|
|
|
|
if src == nil {
|
|
|
|
|
return nil, fmt.Errorf("source data is nil")
|
|
|
|
|
}
|
|
|
|
|
var tgt []byte
|
|
|
|
|
var pos1, pos2 int
|
|
|
|
|
var gap int
|
|
|
|
|
var got1stFF bool
|
|
|
|
|
|
|
|
|
|
for i, b := range src {
|
|
|
|
|
if got1stFF {
|
|
|
|
|
if b == 0xFF {
|
|
|
|
|
// 已遇到前一个FF,且当前又遇到FF
|
|
|
|
|
got1stFF = false
|
|
|
|
|
pos2 = i
|
|
|
|
|
if gap > 252 {
|
|
|
|
|
// 间隙过大,特殊处理
|
|
|
|
|
tgt = append(tgt, 0)
|
|
|
|
|
tgt = append(tgt, src[pos1+1:pos2]...)
|
|
|
|
|
} else {
|
|
|
|
|
// 写入间隙长度
|
|
|
|
|
tgt = append(tgt, byte(gap))
|
|
|
|
|
// 写入间隙中的字节
|
|
|
|
|
tgt = append(tgt, src[pos1+1:pos2]...)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 已遇到前一个FF,且当前遇到非FF,增加gap计数
|
|
|
|
|
gap++
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 尚未遇到前一个FF
|
|
|
|
|
tgt = append(tgt, b)
|
|
|
|
|
if b == 0xFF {
|
|
|
|
|
// 遇到前一个FF
|
|
|
|
|
got1stFF = true
|
|
|
|
|
pos1 = i
|
|
|
|
|
gap = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果在数据末尾遇到了FF且没有第二个FF
|
|
|
|
|
if got1stFF {
|
|
|
|
|
if gap > 252 {
|
|
|
|
|
tgt = append(tgt, 0)
|
|
|
|
|
tgt = append(tgt, src[pos1+1:]...)
|
|
|
|
|
} else {
|
|
|
|
|
tgt = append(tgt, 0)
|
|
|
|
|
tgt = append(tgt, src[pos1+1:len(src)]...)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tgt, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TranslateToFFFE 将数据进行FFFE转义处理(不加头FFFE及尾FFFD)。
|
2024-06-18 17:10:21 +08:00
|
|
|
|
/*func TranslateToFFFE2(pSrc []byte) []byte {
|
2024-06-06 17:57:30 +08:00
|
|
|
|
var (
|
|
|
|
|
srcPos, tgtPos, pos1, pos2, iii uint16
|
|
|
|
|
gap uint16
|
|
|
|
|
got1stFF bool
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if pSrc == nil {
|
|
|
|
|
return nil // 入口参数错误
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pTgt := make([]byte, 0, len(pSrc)*2) // 预分配空间以应对最坏情况
|
|
|
|
|
|
|
|
|
|
for srcPos = 0; srcPos < uint16(len(pSrc)); srcPos++ {
|
|
|
|
|
if got1stFF {
|
|
|
|
|
if pSrc[srcPos] == 0xFF {
|
|
|
|
|
// 已遇到前一个FF,且当前又遇到FF
|
|
|
|
|
|
|
|
|
|
pos2 = srcPos
|
|
|
|
|
pTgt = append(pTgt, byte(pos2-pos1))
|
|
|
|
|
tgtPos++
|
|
|
|
|
|
|
|
|
|
for iii = pos1 + 1; iii < pos2; iii++ {
|
|
|
|
|
pTgt = append(pTgt, pSrc[iii])
|
|
|
|
|
tgtPos++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got1stFF = false
|
|
|
|
|
pos1, pos2, gap = 0, 0, 0
|
|
|
|
|
} else {
|
|
|
|
|
// 已遇到前一个FF,且当前遇到非FF
|
|
|
|
|
gap++
|
|
|
|
|
if gap == 252 {
|
|
|
|
|
got1stFF, gap = false, 0
|
|
|
|
|
pTgt = append(pTgt, 0)
|
|
|
|
|
tgtPos++
|
|
|
|
|
|
|
|
|
|
for iii = pos1 + 1; iii <= srcPos; iii++ {
|
|
|
|
|
pTgt = append(pTgt, pSrc[iii])
|
|
|
|
|
tgtPos++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 尚未遇到前一个FF
|
|
|
|
|
pTgt = append(pTgt, pSrc[srcPos])
|
|
|
|
|
tgtPos++
|
|
|
|
|
|
|
|
|
|
if pSrc[srcPos] == 0xFF {
|
|
|
|
|
// 遇到前一个FF
|
|
|
|
|
got1stFF = true
|
|
|
|
|
pos1 = srcPos
|
|
|
|
|
gap = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 已经遇到了前一个FF, 且源数据已到了末尾仍未遇到后一个FF
|
|
|
|
|
if got1stFF {
|
|
|
|
|
pTgt = append(pTgt, 0)
|
|
|
|
|
tgtPos++
|
|
|
|
|
|
|
|
|
|
for iii = pos1 + 1; iii < uint16(len(pSrc)); iii++ {
|
|
|
|
|
pTgt = append(pTgt, pSrc[iii])
|
|
|
|
|
tgtPos++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 截取实际使用的部分返回
|
|
|
|
|
return pTgt[:tgtPos]
|
|
|
|
|
}
|
2024-06-18 17:10:21 +08:00
|
|
|
|
*/
|
2024-06-06 17:57:30 +08:00
|
|
|
|
func TranslateToFFFE3(pSrc []uint8, SrcLen uint16) ([]byte, uint16) {
|
|
|
|
|
var (
|
|
|
|
|
SrcPos, TgtPos, Pos1, Pos2, iii uint16
|
|
|
|
|
Gap uint16
|
|
|
|
|
Got1stFF uint8
|
|
|
|
|
pTgt []uint8
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if pSrc == nil {
|
|
|
|
|
fmt.Println("入口参数错误")
|
|
|
|
|
return nil, 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pTgt = make([]uint8, 0, SrcLen*2) // 预分配足够的空间以避免频繁扩容
|
|
|
|
|
TgtPos = 0
|
|
|
|
|
|
|
|
|
|
for SrcPos = 0; SrcPos < SrcLen; SrcPos++ {
|
|
|
|
|
if Got1stFF == 1 {
|
|
|
|
|
if pSrc[SrcPos] == 0xFF {
|
|
|
|
|
// 已遇到前一个FF,且当前又遇到FF
|
|
|
|
|
//Got2ndFF = 1
|
|
|
|
|
Pos2 = SrcPos
|
|
|
|
|
pTgt = append(pTgt, uint8(Pos2-Pos1-1))
|
|
|
|
|
TgtPos++
|
|
|
|
|
|
|
|
|
|
for iii = Pos1 + 1; iii < Pos2; iii++ {
|
|
|
|
|
pTgt = append(pTgt, pSrc[iii])
|
|
|
|
|
TgtPos++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Got1stFF = 0
|
|
|
|
|
//Got2ndFF = 0
|
|
|
|
|
Pos1 = 0
|
|
|
|
|
Pos2 = 0
|
|
|
|
|
Gap = 0
|
|
|
|
|
} else {
|
|
|
|
|
// 已遇到前一个FF,且当前遇到非FF
|
|
|
|
|
Gap++
|
|
|
|
|
if Gap == 252 {
|
|
|
|
|
Got1stFF = 0
|
|
|
|
|
Gap = 0
|
|
|
|
|
pTgt = append(pTgt, 0)
|
|
|
|
|
TgtPos++
|
|
|
|
|
|
|
|
|
|
for iii = Pos1 + 1; iii <= SrcPos; iii++ {
|
|
|
|
|
pTgt = append(pTgt, pSrc[iii])
|
|
|
|
|
TgtPos++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 尚未遇到前一个FF
|
|
|
|
|
pTgt = append(pTgt, pSrc[SrcPos])
|
|
|
|
|
TgtPos++
|
|
|
|
|
if pSrc[SrcPos] == 0xFF {
|
|
|
|
|
// 遇到前一个FF
|
|
|
|
|
Got1stFF = 1
|
|
|
|
|
Pos1 = SrcPos
|
|
|
|
|
Gap = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 已经遇到了前一个FF, 且源数据已到了末尾仍未遇到后一个FF
|
|
|
|
|
if Got1stFF == 1 {
|
|
|
|
|
pTgt = append(pTgt, 0)
|
|
|
|
|
TgtPos++
|
|
|
|
|
|
|
|
|
|
for iii = Pos1 + 1; iii < SrcLen; iii++ {
|
|
|
|
|
pTgt = append(pTgt, pSrc[iii])
|
|
|
|
|
TgtPos++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pTgt, TgtPos
|
2024-05-29 11:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type BaseBtmVobc struct {
|
|
|
|
|
Frame byte //帧类型
|
|
|
|
|
FrameLen byte //帧长定义为 TEXT+CRC32,ID 命令帧为 20 字节;
|
|
|
|
|
AutoIdFrame byte // 无论何时传输数据,该数都在 1-255 范围内递增,在错误重传时也是递增的,255 之后是 1,不使用 0;
|
|
|
|
|
Crc32 uint32
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 17:57:30 +08:00
|
|
|
|
func baseDecode(d []byte) (BaseBtmVobc, *bytes.Buffer) {
|
|
|
|
|
buf := bytes.NewBuffer(d)
|
|
|
|
|
|
|
|
|
|
frame, _ := buf.ReadByte()
|
|
|
|
|
frameLen, _ := buf.ReadByte()
|
|
|
|
|
autoIdFrame, _ := buf.ReadByte()
|
2024-05-29 11:48:04 +08:00
|
|
|
|
crc32 := binary.BigEndian.Uint32(d[len(d)-4:])
|
2024-06-06 17:57:30 +08:00
|
|
|
|
|
|
|
|
|
return BaseBtmVobc{Frame: frame, FrameLen: frameLen, Crc32: crc32, AutoIdFrame: autoIdFrame}, buf
|
2024-05-29 11:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
func baseEncode(source []byte) []byte {
|
|
|
|
|
data := make([]byte, 0)
|
|
|
|
|
crc32 := crc.CalculateCRC(crc.CRC32, source)
|
|
|
|
|
newSource := binary.BigEndian.AppendUint32(source, uint32(crc32))
|
2024-06-06 17:57:30 +08:00
|
|
|
|
|
|
|
|
|
f2 := make([]byte, len(newSource)*2)
|
|
|
|
|
lens := aa(newSource, f2)
|
|
|
|
|
fffeData := f2[:lens]
|
2024-05-29 11:48:04 +08:00
|
|
|
|
data = append(data, PACKAGE_HEAD...)
|
2024-06-06 17:57:30 +08:00
|
|
|
|
data = append(data, fffeData...)
|
2024-05-29 11:48:04 +08:00
|
|
|
|
data = append(data, PACKAGE_END...)
|
|
|
|
|
return data
|
|
|
|
|
}
|
2024-06-18 17:10:21 +08:00
|
|
|
|
|
|
|
|
|
/*func TranslateToFFFE4(pSrc []byte, pTgt []byte) (int, error) {
|
2024-06-06 17:57:30 +08:00
|
|
|
|
if pSrc == nil || pTgt == nil {
|
|
|
|
|
return 0, fmt.Errorf("pSrc or pTgt is nil")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srcLen := len(pSrc)
|
|
|
|
|
tgtLen := 0
|
|
|
|
|
pos1 := -1 // 前一个FF的位置
|
|
|
|
|
gap := 0 // 两个FF之间的字节数
|
|
|
|
|
|
|
|
|
|
for i, b := range pSrc {
|
|
|
|
|
if pos1 != -1 {
|
|
|
|
|
if b == 0xFF {
|
|
|
|
|
// 遇到了第二个FF
|
|
|
|
|
pTgt[tgtLen] = byte(i - pos1 - 1) // 减1是因为不包括第一个FF
|
|
|
|
|
tgtLen++
|
|
|
|
|
|
|
|
|
|
// 复制pos1和当前位置之间的数据
|
|
|
|
|
copy(pTgt[tgtLen:tgtLen+gap], pSrc[pos1+1:i])
|
|
|
|
|
tgtLen += gap
|
|
|
|
|
|
|
|
|
|
// 重置状态
|
|
|
|
|
pos1 = -1
|
|
|
|
|
gap = 0
|
|
|
|
|
} else {
|
|
|
|
|
// 计数两个FF之间的字节数
|
|
|
|
|
gap++
|
|
|
|
|
if gap == 252 {
|
|
|
|
|
// 如果gap超过252,则写入一个0并复制数据
|
|
|
|
|
pTgt[tgtLen] = 0
|
|
|
|
|
tgtLen++
|
|
|
|
|
copy(pTgt[tgtLen:tgtLen+gap], pSrc[pos1+1:i])
|
|
|
|
|
tgtLen += gap
|
|
|
|
|
// 重置状态
|
|
|
|
|
pos1 = -1
|
|
|
|
|
gap = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 尚未遇到前一个FF
|
|
|
|
|
pTgt[tgtLen] = b
|
|
|
|
|
tgtLen++
|
|
|
|
|
if b == 0xFF {
|
|
|
|
|
// 遇到了第一个FF
|
|
|
|
|
pos1 = i
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果数据以FF结尾,但没有第二个FF
|
|
|
|
|
if pos1 != -1 {
|
|
|
|
|
pTgt[tgtLen] = 0
|
|
|
|
|
tgtLen++
|
|
|
|
|
// 复制pos1之后的数据
|
|
|
|
|
copy(pTgt[tgtLen:tgtLen+srcLen-pos1-1], pSrc[pos1+1:])
|
|
|
|
|
tgtLen += srcLen - pos1 - 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tgtLen, nil
|
|
|
|
|
}
|
2024-06-18 17:10:21 +08:00
|
|
|
|
*/
|
2024-05-29 11:48:04 +08:00
|
|
|
|
// ID 命令帧的正文
|
|
|
|
|
type BtmVobcIdCommand struct {
|
|
|
|
|
BaseBtmVobc
|
|
|
|
|
BtmId uint16 //VOBC 向 BTM 分配的 ID,暂定 0x75E1 或者0x75A2,其他无效;
|
|
|
|
|
VobcId uint16 //暂定 0x5511,其他无效
|
|
|
|
|
VobcLifeNum uint32 //7~10 1~FFFFFFFF,0 不使用
|
|
|
|
|
yuliu []byte //11-15 预留字节
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *BtmVobcIdCommand) Decode(data []byte) {
|
2024-06-06 17:57:30 +08:00
|
|
|
|
base, buf := baseDecode(data)
|
2024-05-29 11:48:04 +08:00
|
|
|
|
b.BaseBtmVobc = base
|
2024-06-06 17:57:30 +08:00
|
|
|
|
var btmId uint16
|
|
|
|
|
var vobcId uint16
|
|
|
|
|
var lifeNum uint32
|
|
|
|
|
binary.Read(buf, binary.BigEndian, &btmId)
|
|
|
|
|
binary.Read(buf, binary.BigEndian, &vobcId)
|
|
|
|
|
binary.Read(buf, binary.BigEndian, &lifeNum)
|
|
|
|
|
|
|
|
|
|
b.BtmId = btmId
|
|
|
|
|
b.VobcId = vobcId
|
|
|
|
|
b.VobcLifeNum = lifeNum
|
2024-05-29 11:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 17:57:30 +08:00
|
|
|
|
const (
|
|
|
|
|
REQ_FRAME_STATUS_OK = 0x06
|
|
|
|
|
REQ_FRAME_STATUS_ERROR = 0x15
|
|
|
|
|
REQ_FRAME_STATUS_BOOT = 0x00
|
|
|
|
|
REQ_PACKETS_TYPE_FREE = 0x05
|
|
|
|
|
REQ_PACKETS_TYPE_MSG = 0x0A
|
|
|
|
|
REQ_PACKETS_TYPE_BOOT = 0x00
|
|
|
|
|
)
|
|
|
|
|
|
2024-05-29 11:48:04 +08:00
|
|
|
|
// 请求帧的正文
|
|
|
|
|
type BtmVobcReq struct {
|
|
|
|
|
BaseBtmVobc
|
|
|
|
|
FrameStatus byte //帧正确/不正确 06h:帧正确15h:不正确00h:开机状态填00 其它无效
|
|
|
|
|
MessageType byte // 空闲/报文数据 05h:空闲0Ah:报文数据00h:开机状态填00 其它无效
|
|
|
|
|
MessageSerial byte //报文序列号 1-255;开机时使用0
|
|
|
|
|
yuliu []byte //预留字节(10 字节)
|
|
|
|
|
VobcLifeNum uint32 // VOBC 周期号 1~FFFFFFFF,0 不使用
|
|
|
|
|
TimeStamp []byte //年月日时分秒各占一个字节
|
|
|
|
|
Speed uint16 //速度 单位:cm/s
|
|
|
|
|
VobcLifeWalkDistance uint16 //VOBC 周期走行距离 单位:cm
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 17:57:30 +08:00
|
|
|
|
const (
|
|
|
|
|
a = 0x06
|
|
|
|
|
b = 0x15
|
|
|
|
|
)
|
|
|
|
|
|
2024-05-29 11:48:04 +08:00
|
|
|
|
func (b *BtmVobcReq) Decode(data []byte) {
|
2024-06-06 17:57:30 +08:00
|
|
|
|
base, buf := baseDecode(data)
|
|
|
|
|
|
2024-05-29 11:48:04 +08:00
|
|
|
|
b.BaseBtmVobc = base
|
2024-06-06 17:57:30 +08:00
|
|
|
|
|
|
|
|
|
b.FrameStatus, _ = buf.ReadByte()
|
|
|
|
|
b.MessageType, _ = buf.ReadByte()
|
|
|
|
|
b.MessageSerial, _ = buf.ReadByte()
|
|
|
|
|
var tyuli = make([]byte, 10)
|
|
|
|
|
buf.Read(tyuli)
|
|
|
|
|
//b.yuliu = data[5:15]
|
|
|
|
|
var lifeNum uint32
|
|
|
|
|
ts := make([]byte, 6)
|
|
|
|
|
var speed uint16
|
|
|
|
|
var walkDis uint16
|
|
|
|
|
binary.Read(buf, binary.BigEndian, &lifeNum)
|
|
|
|
|
buf.Read(ts)
|
|
|
|
|
binary.Read(buf, binary.BigEndian, &speed)
|
|
|
|
|
binary.Read(buf, binary.BigEndian, &walkDis)
|
|
|
|
|
b.VobcLifeNum = lifeNum
|
|
|
|
|
b.TimeStamp = ts
|
|
|
|
|
b.Speed = speed
|
|
|
|
|
b.VobcLifeWalkDistance = walkDis
|
2024-05-29 11:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var MESSAGE_AUTO_ID byte = 1
|
|
|
|
|
var MESSAGE_SERIAL byte = 1
|
|
|
|
|
var lock sync.Mutex
|
|
|
|
|
|
|
|
|
|
func getAutoId() byte {
|
|
|
|
|
defer lock.Unlock()
|
|
|
|
|
lock.Lock()
|
|
|
|
|
if MESSAGE_AUTO_ID <= 0 {
|
|
|
|
|
MESSAGE_AUTO_ID = 1
|
|
|
|
|
} else if MESSAGE_AUTO_ID > 255 {
|
|
|
|
|
MESSAGE_AUTO_ID = 1
|
|
|
|
|
}
|
|
|
|
|
MESSAGE_AUTO_ID += 1
|
|
|
|
|
return MESSAGE_AUTO_ID
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 17:57:30 +08:00
|
|
|
|
func GetAutoMessageId() byte {
|
2024-05-29 11:48:04 +08:00
|
|
|
|
defer lock.Unlock()
|
|
|
|
|
lock.Lock()
|
|
|
|
|
if MESSAGE_SERIAL <= 0 {
|
|
|
|
|
MESSAGE_SERIAL = 1
|
|
|
|
|
} else if MESSAGE_SERIAL > 255 {
|
|
|
|
|
MESSAGE_SERIAL = 1
|
|
|
|
|
}
|
|
|
|
|
MESSAGE_SERIAL += 1
|
|
|
|
|
return MESSAGE_SERIAL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
btm_status_ok = 0x00
|
|
|
|
|
btm_status_warn = 0x04
|
|
|
|
|
)
|
|
|
|
|
|
2024-06-18 17:10:21 +08:00
|
|
|
|
var mesage_yuliu = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0} //11~19 预留
|
|
|
|
|
var yuliu3 = []byte{0, 0, 0, 0, 0, 0} //8~13 保留
|
2024-05-29 11:48:04 +08:00
|
|
|
|
|
2024-06-06 17:57:30 +08:00
|
|
|
|
const (
|
|
|
|
|
BTM_STSTUS_NORMAL = 0x00
|
|
|
|
|
BTM_STSTUS_WARN = 0x04
|
|
|
|
|
)
|
|
|
|
|
|
2024-05-29 11:48:04 +08:00
|
|
|
|
// 报文帧的正文
|
|
|
|
|
type BtmVobcMessage struct {
|
|
|
|
|
BaseBtmVobc
|
|
|
|
|
FontTtl uint16 //前沿 TTL 时间 单位为 ms,溢出为0xffff,高字节在前;车体及应答器器地面环境理想情况下误差小于 5ms
|
|
|
|
|
MsgSerial byte //报文序列号 1-255;不使用 0
|
|
|
|
|
BtmStatus byte //BTM 工作状态 00H-工作正常;04H-警告 BTM 有轻微故障(单套故障,整机能工作),向BDMS 汇报;FFH-BTM 故障,不能正常工作;在MMI进行故障提示并向ATS 汇报
|
|
|
|
|
Enter1 byte //1 通道好码率 0~100
|
|
|
|
|
Enter2 byte //2 通道好码率 0~100
|
|
|
|
|
DecodeTime uint16 //解码时间:从包络前沿到解码成功的时间,单位0.1ms。
|
|
|
|
|
yuliu []byte //11~19 预留 填 0
|
|
|
|
|
BackTtl uint16 //后沿 TTL 时间单位为 ms,溢出为0xffff,高字节在前;车体及应答器器地面环境理想情况下误差小于 5ms.
|
|
|
|
|
BtmMsg []byte //22~125 应答器报文
|
|
|
|
|
ResponseTime byte //0~150,其他非法,单位0.1ms 误差小于 3ms
|
|
|
|
|
VobcLifeNum uint32 //VOBC 周期号 1~FFFFFFFF,0 不使用。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *BtmVobcMessage) Encode() []byte {
|
|
|
|
|
|
|
|
|
|
data := make([]byte, 0)
|
|
|
|
|
buf := bytes.NewBuffer(data)
|
2024-06-06 17:57:30 +08:00
|
|
|
|
|
2024-05-29 11:48:04 +08:00
|
|
|
|
binary.Write(buf, binary.BigEndian, byte(MESSAGE_TYPE))
|
|
|
|
|
binary.Write(buf, binary.BigEndian, byte(0x87))
|
2024-06-06 17:57:30 +08:00
|
|
|
|
//binary.Write(buf, binary.BigEndian, b.AutoIdFrame)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, getAutoId())
|
2024-05-29 11:48:04 +08:00
|
|
|
|
binary.Write(buf, binary.BigEndian, b.FontTtl)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.MsgSerial)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.BtmStatus)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, byte(100)) //b.Enter1
|
|
|
|
|
binary.Write(buf, binary.BigEndian, byte(100)) //b.Enter2
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.DecodeTime)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, mesage_yuliu)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.BackTtl)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.BtmMsg)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.ResponseTime)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.VobcLifeNum)
|
|
|
|
|
|
|
|
|
|
return baseEncode(buf.Bytes())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type BtmVobcMsgFree struct {
|
|
|
|
|
BaseBtmVobc
|
|
|
|
|
//yuliu1 byte
|
|
|
|
|
//yuliu2 byte
|
|
|
|
|
MsgSerial byte //1-255;开机时为0
|
|
|
|
|
BtmStatus byte //BTM 工作状态 00H-工作正常;04H-警告 BTM 有轻微故障(单套故障,整机能工作),向BDMS 汇报;FFH-BTM 故障,不能正常工作;在MMI 进行故障提示并向ATS 汇报
|
|
|
|
|
WorkTemperature byte
|
|
|
|
|
//yuliu3 []byte //8~13 保留 填 0
|
|
|
|
|
|
|
|
|
|
//0-1 位 功放 1 电流状态 功放电流状态:“1”-欠流;“2”- 过流 ;“3”-正常(欠流和过流仅作为功放状态参考)
|
|
|
|
|
//2-3 位 功放 1 电压状态 功放电压状态:“1”-欠压;“2”- 过压 ;“3”-正常(欠压和过压仅作为功放状态参考)
|
|
|
|
|
//4-5 位 (预留) 功放 2 电流状态 功放电流状态:“1”-欠流;“2”- 过流 ;“3”-正常(欠流和过流仅作为功放状态参考)
|
|
|
|
|
//6-7 位 功放 2 电压状 功放电压状态:“1”-欠压;“2”- 过压 ;“3”-正常(欠压和过压仅作为功放状态参考)
|
|
|
|
|
//8-9 位 天线 1 状态 天线 1 状态:“1”-故障;“3”-正常。
|
|
|
|
|
//10-11 位 线缆 1 状态 线缆 1 状态:“1”-开路;“2”-短路;“3”-正常。
|
|
|
|
|
//12-13 位 (预留) 天线 2 状态 天线 2 状态:“1”-故障;“3”-正常。
|
|
|
|
|
//14-15 位 (预留) 线缆 2 状态 线缆 2 状态:“1”-开路;“2”-短路;“3”-正常。
|
|
|
|
|
Fun1 uint16 //第 14-15 字节(功放板、天线状态)
|
|
|
|
|
//第 0 位 上行自检码检测通道 1 状态:“1”-正常;“0”-故障。(故障时,检查处理器板和接收板)
|
|
|
|
|
//第 1 位 上行自检码检测通道 2 状态:“1”-正常;“0”-故障。(故障时,检查处理器板和接收板)
|
|
|
|
|
//第 2 位 FSK 连接线状态通道 1状态:“1”-正常;“0”-故障。
|
|
|
|
|
//第 3 位 FSK 连接线状态通道 2状态:“1”-正常;“0”-故障。
|
|
|
|
|
//第 4-5 位 保留 保留
|
|
|
|
|
//第 6-7 位 接收板状态 状态:“0”-双通道故障;“1”-单通道故障;“3”-正常第
|
|
|
|
|
//8-15位保留 保留
|
|
|
|
|
Fun2 uint16 //第 16-17 字节(接收板状态)
|
|
|
|
|
//第 0-1 位 通 道 1-24V 状态 状态:“1”-过压;“2”-欠压;“3”-正常;(欠压和过压仅作为电源板状态参考)
|
|
|
|
|
//第 2-3 位 通 道 2-24V 状态 状态:“1”-过压;“2”-欠压;“3”-正常;(欠压和过压仅作为电源板状态参考)
|
|
|
|
|
//第 4 位 通 道 1-23V 状态 状态:“1”-正常;“0”-故障。
|
|
|
|
|
//第 5 位 通 道 2-23V 状态 状态:“1”-正常;“0”-故障。
|
|
|
|
|
//第 6-13位保留 保留
|
|
|
|
|
//第 14-15位 电源板状态 电源板状态:“0”-故障;“1”-单通道故障;“2”-单通道故障;“3”- 正常。
|
|
|
|
|
Fun3 uint16 //第 18-19 字节(电源板状态)
|
|
|
|
|
//第 0-1 位 板卡 ID 槽位号 “0”-1 号板卡;“1”-2 号板卡;“2”-3 号板卡;“3”-4 号板卡机箱正面从右往左顺序为处理器板1,2,3(预留),4(预留),同一个通信周期只有一个板卡报警
|
|
|
|
|
//第 2-3 位 工作温度状态 “0”-过高;“1”-温度报警;“2”-未知;“3”-正常。
|
|
|
|
|
//其他位保留 注:保留位全部为1
|
|
|
|
|
Fun4 uint16 //第 20-21 字节(处理器板)
|
|
|
|
|
|
|
|
|
|
FreeMsg []byte //22~125 空闲数据 全填 00H
|
|
|
|
|
RespTime byte //响应时间 0~150,其他非法,单位0.1ms
|
|
|
|
|
VobcLifeNum uint32 //VOBC 周期号 1~FFFFFFFF,0 不使用。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *BtmVobcMsgFree) Encode() []byte {
|
|
|
|
|
data := make([]byte, 0)
|
|
|
|
|
buf := bytes.NewBuffer(data)
|
2024-06-06 17:57:30 +08:00
|
|
|
|
|
2024-05-29 11:48:04 +08:00
|
|
|
|
binary.Write(buf, binary.BigEndian, byte(FREE_MESSAGE_TYPE))
|
|
|
|
|
binary.Write(buf, binary.BigEndian, byte(0x87))
|
2024-06-06 17:57:30 +08:00
|
|
|
|
binary.Write(buf, binary.BigEndian, getAutoId())
|
|
|
|
|
//binary.Write(buf, binary.BigEndian, b.AutoIdFrame)
|
2024-05-29 11:48:04 +08:00
|
|
|
|
binary.Write(buf, binary.BigEndian, byte(0)) //保留
|
|
|
|
|
binary.Write(buf, binary.BigEndian, byte(0)) //保留
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.MsgSerial)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.BtmStatus)
|
2024-06-06 18:56:25 +08:00
|
|
|
|
//binary.Write(buf, binary.BigEndian, b.WorkTemperature)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, byte(35))
|
2024-05-29 11:48:04 +08:00
|
|
|
|
binary.Write(buf, binary.BigEndian, yuliu3)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.Fun1)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.Fun2)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.Fun3)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.Fun4)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.FreeMsg)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.RespTime)
|
|
|
|
|
binary.Write(buf, binary.BigEndian, b.VobcLifeNum)
|
|
|
|
|
|
|
|
|
|
return baseEncode(buf.Bytes())
|
|
|
|
|
}
|