rts-sim-testing-service/third_party/btm_vobc/btm_vobc.go

379 lines
13 KiB
Go
Raw Normal View History

2024-05-29 11:48:04 +08:00
package btm_vobc
import (
"context"
2024-05-29 13:34:50 +08:00
"encoding/hex"
2024-06-06 17:57:30 +08:00
"encoding/json"
2024-05-29 13:34:50 +08:00
"fmt"
2024-06-06 17:57:30 +08:00
"github.com/google/uuid"
"github.com/snksoft/crc"
2024-05-29 13:34:50 +08:00
"joylink.club/bj-rtsts-server/config"
2024-06-06 17:57:30 +08:00
"joylink.club/bj-rtsts-server/const/balise_const"
"joylink.club/bj-rtsts-server/dto/state_proto"
2024-05-29 13:34:50 +08:00
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp"
"log/slog"
2024-06-06 17:57:30 +08:00
"math"
"reflect"
"strconv"
"time"
"strings"
2024-05-29 11:48:04 +08:00
"sync"
)
type BtmVobcManage interface {
2024-05-29 13:34:50 +08:00
GetBtmVobcConfig() config.BtmVobcConfig
2024-06-06 18:56:25 +08:00
GetAllTrain() []*state_proto.TrainState
GetConnVobcTrain() *state_proto.TrainState
2024-05-29 11:48:04 +08:00
}
type BtmVobcService interface {
2024-05-29 13:34:50 +08:00
Start(btmVobcManage BtmVobcManage)
2024-05-29 11:48:04 +08:00
Stop()
2024-05-29 13:34:50 +08:00
SendData(data []byte)
2024-06-06 17:57:30 +08:00
AppendBaliseMsgForTrain(vobcBtm *state_proto.VobcBtmState, baliseId string, baliseSource []byte, arriveTime int64)
UpdateTrainLeave(vobcBtm *state_proto.VobcBtmState, baliseId string, leaveTime int64)
RemoveBaliseFirst(vobcBtm *state_proto.VobcBtmState)
2024-05-29 11:48:04 +08:00
}
type BtmVobcClient struct {
calFun context.CancelFunc
2024-05-29 13:34:50 +08:00
client udp.UdpClient
server udp.UdpServer
manage BtmVobcManage
2024-05-29 11:48:04 +08:00
}
var (
2024-06-06 17:57:30 +08:00
btmVobcLocker sync.Mutex
btmVobcClient *BtmVobcClient
btmVobcBaliseLocker sync.Mutex
//最新接受数据时间
reviceTimeStamp int64
2024-05-29 11:48:04 +08:00
)
func Default() BtmVobcService {
defer btmVobcLocker.Unlock()
btmVobcLocker.Lock()
if btmVobcClient == nil {
btmVobcClient = &BtmVobcClient{}
}
return btmVobcClient
}
2024-06-06 17:57:30 +08:00
// 缓存列车经过的应答器报文
func (b *BtmVobcClient) AppendBaliseMsgForTrain(vobcBtm *state_proto.VobcBtmState, baliseId string, baliseSource []byte, arriveTime int64) {
defer btmVobcBaliseLocker.Unlock()
btmVobcBaliseLocker.Lock()
baliseHex := hex.EncodeToString(baliseSource)
tel := &state_proto.VobcBtmState_TelegramState{Telegram: baliseHex, BaliseId: baliseId, ArriveTime: arriveTime}
if len(vobcBtm.TelegramState) == 0 {
vobcBtm.TelegramState = append(vobcBtm.TelegramState, tel)
} else {
bs := crc.CalculateCRC(crc.CRC32, baliseSource)
exists := false
for _, d := range vobcBtm.TelegramState {
sd, _ := hex.DecodeString(d.Telegram)
t := crc.CalculateCRC(crc.CRC32, sd)
if t == bs {
exists = true
}
}
if !exists {
if len(vobcBtm.TelegramState) >= 8 {
vobcBtm.TelegramState = append(vobcBtm.TelegramState[1:], tel)
} else {
vobcBtm.TelegramState = append(vobcBtm.TelegramState, tel)
}
}
}
}
func (b *BtmVobcClient) UpdateTrainLeave(vobcBtm *state_proto.VobcBtmState, baliseId string, leaveTime int64) {
defer btmVobcBaliseLocker.Unlock()
btmVobcBaliseLocker.Lock()
if vobcBtm.TelegramState == nil || len(vobcBtm.TelegramState) == 0 {
return
}
for _, bs := range vobcBtm.TelegramState {
if bs.BaliseId == baliseId {
bs.LeaveTime = leaveTime
}
}
}
func (b *BtmVobcClient) RemoveBaliseFirst(vobcBtm *state_proto.VobcBtmState) {
defer btmVobcBaliseLocker.Unlock()
btmVobcBaliseLocker.Lock()
if vobcBtm.TelegramState == nil || len(vobcBtm.TelegramState) == 0 {
return
}
vobcBtm.TelegramState = vobcBtm.TelegramState[1:]
}
2024-05-29 13:34:50 +08:00
func (b *BtmVobcClient) Start(btmVobcManage BtmVobcManage) {
cfg := btmVobcManage.GetBtmVobcConfig()
if !cfg.Open {
slog.Info("11号线 btm vobc配置未开启...")
return
}
2024-05-29 13:55:21 +08:00
udpServer := udp.NewServer(fmt.Sprintf("%v:%d", cfg.LocalUdpIp, cfg.LocalUdpPort), b.handleBtmVobcFrames)
2024-05-29 13:34:50 +08:00
err := udpServer.Listen()
if err != nil {
slog.Error("11号线 btm VOBC 服务启动失败...")
return
}
//
udpClient := udp.NewClient(fmt.Sprintf("%s:%d", cfg.RemoteIp, cfg.RemoteUdpPort))
b.manage = btmVobcManage
b.server = udpServer
b.client = udpClient
2024-06-06 17:57:30 +08:00
reviceTimeStamp = time.Now().UnixMilli()
ctx, calFun := context.WithCancel(context.Background())
b.calFun = calFun
go b.checkTrainTTLIsOver(ctx)
2024-05-29 11:48:04 +08:00
}
2024-06-06 17:57:30 +08:00
func (b *BtmVobcClient) checkTrainTTLIsOver(ctx context.Context) {
defer btmVobcBaliseLocker.Unlock()
btmVobcBaliseLocker.Lock()
for {
select {
case <-ctx.Done():
return
default:
}
if time.Now().UnixMilli()-reviceTimeStamp < 1000 {
return
}
2024-06-12 17:45:47 +08:00
trains := b.manage.GetAllTrain()
if len(trains) > 0 {
slog.Info("检测网络中断情况 前沿ttl 超时...")
newTel := make([]*state_proto.VobcBtmState_TelegramState, 0)
for _, train := range b.manage.GetAllTrain() {
for _, state := range train.VobcBtm.TelegramState {
if time.Now().UnixMilli()-state.ArriveTime < 1000 {
newTel = append(newTel, state)
}
2024-06-06 17:57:30 +08:00
}
}
2024-06-06 18:56:25 +08:00
}
2024-06-12 17:45:47 +08:00
2024-06-06 17:57:30 +08:00
time.Sleep(time.Second * 1)
}
2024-05-29 11:48:04 +08:00
2024-06-06 17:57:30 +08:00
}
2024-05-29 13:34:50 +08:00
func (b *BtmVobcClient) handleBtmVobcFrames(cfs []byte) {
2024-06-06 17:57:30 +08:00
reviceTimeStamp = time.Now().UnixMilli()
2024-06-06 18:56:25 +08:00
train := b.manage.GetConnVobcTrain()
2024-06-06 17:57:30 +08:00
if train == nil {
2024-06-12 16:22:31 +08:00
//slog.Error("vobc btm 未找到VOBC连接的列车...")
2024-06-06 17:57:30 +08:00
return
}
requestId := uuid.New().String()
slog.Info(fmt.Sprintf("获取到vobc btm原始数据:%v, requestId:%v", hex.EncodeToString(cfs), requestId))
2024-05-29 13:34:50 +08:00
frameType, dataText, err := message.BtmVobcDecode(cfs)
if err != nil {
2024-06-06 17:57:30 +08:00
slog.Error(fmt.Sprintf("%v,请求id:%v", err, requestId))
2024-05-29 13:34:50 +08:00
return
}
2024-06-06 17:57:30 +08:00
receiveDataTime := time.Now().UnixMicro()
decodePayMicoTime := (receiveDataTime - receiveDataTime) / 100
2024-05-29 13:34:50 +08:00
if frameType == message.COMMAND_TYPE {
idCommand := &message.BtmVobcIdCommand{}
idCommand.Decode(dataText)
2024-06-06 17:57:30 +08:00
slog.Info(fmt.Sprintf("成功接受btm vobc的id命令帧,requestId:%v,接受时间(微秒):%v", requestId, receiveDataTime))
2024-06-12 17:45:47 +08:00
b.packets(requestId, idCommand.VobcLifeNum, idCommand.AutoIdFrame, receiveDataTime, decodePayMicoTime, train.VobcBtm)
2024-06-06 17:57:30 +08:00
2024-05-29 13:34:50 +08:00
} else if frameType == message.REQUEST_TYPE {
2024-06-06 17:57:30 +08:00
slog.Info(fmt.Sprintf("成功接受btm vobc的请求帧,requestId:%v,接受时间(微秒):%v", requestId, receiveDataTime))
2024-05-29 13:34:50 +08:00
req := &message.BtmVobcReq{}
req.Decode(dataText)
2024-06-12 17:45:47 +08:00
b.RequestFramePackets(req.VobcLifeNum, req.AutoIdFrame, requestId, receiveDataTime, decodePayMicoTime, req, train.VobcBtm)
2024-06-06 17:57:30 +08:00
} else {
slog.Error(fmt.Sprintf("btm vobc 解析未知命令帧类型:0x%v,原始数据:%v,长度:%v,requestId:%v", strconv.FormatInt(int64(frameType), 16), hex.EncodeToString(cfs), len(cfs), requestId))
return
}
}
func createFreeBalisePacketString() string {
return strings.Repeat("00", balise_const.UserTelegramByteLen)
}
func createFreeBalisePackets() []byte {
str := createFreeBalisePacketString()
d, _ := hex.DecodeString(str)
return d
}
const MAX_SEND_COUNT = 3
// 请求帧
2024-06-12 17:45:47 +08:00
func (b *BtmVobcClient) RequestFramePackets(vobcLifeNum uint32, autoId byte, requestId string, receiveTime int64, decodePayMicoTime int64, req *message.BtmVobcReq, vobcbtm *state_proto.VobcBtmState) {
2024-06-06 17:57:30 +08:00
if req.FrameStatus == message.REQ_FRAME_STATUS_BOOT && req.MessageType == message.REQ_PACKETS_TYPE_BOOT {
slog.Info(fmt.Sprintf("接受请求帧,准备发送空闲帧数据 帧状态:0x%v,消息类型:0x%v ,requestId:%v", strconv.FormatInt(int64(req.FrameStatus), 16), strconv.FormatInt(int64(req.MessageType), 16), requestId))
vobcbtm.TelegramState = make([]*state_proto.VobcBtmState_TelegramState, 0)
vobcbtm.History = make(map[uint32]*state_proto.VobcBtmState_VobcBtmHistoryState)
2024-06-12 17:45:47 +08:00
b.packets(requestId, vobcLifeNum, autoId, receiveTime, decodePayMicoTime, vobcbtm)
2024-06-06 17:57:30 +08:00
} else if req.FrameStatus == message.REQ_FRAME_STATUS_OK {
//帧正确,删除之前发送的数据
slog.Info(fmt.Sprintf("接受请求帧帧正确删除之前发送的数据requestId:%v", requestId))
delete(vobcbtm.History, uint32(req.MessageSerial))
} else if req.FrameStatus == message.REQ_FRAME_STATUS_ERROR {
//帧不正确 重新发送2次如果2次后仍然不正确则删除之前发送的数据
dd := vobcbtm.History[uint32(req.MessageSerial)]
if dd.SendCount > MAX_SEND_COUNT {
slog.Info(fmt.Sprintf("接受请求帧帧不正确重发超过2次删除之前发送的数据,准备发送新数据 requestId:%v", requestId))
sendBalisePacket := dd.BalisePacket
delete(vobcbtm.History, uint32(req.MessageSerial))
if vobcbtm.TelegramState[0].Telegram == sendBalisePacket {
b.RemoveBaliseFirst(vobcbtm)
}
if len(vobcbtm.TelegramState) == 0 {
b.balisePacketsFree(requestId, time.Now().UnixMicro(), req.VobcLifeNum, req.AutoIdFrame, vobcbtm)
} else {
b.balisePackets(requestId, vobcbtm.TelegramState[0], receiveTime, decodePayMicoTime, req.VobcLifeNum, req.AutoIdFrame, vobcbtm)
}
} else {
dd.SendCount = dd.SendCount + 1
if dd.IsFreePacket {
freeMsg := &message.BtmVobcMsgFree{}
if b.unmarshalJson(dd.SendTelegram, freeMsg) == nil {
freeMsg.FreeMsg = createFreeBalisePackets()
repeatData := freeMsg.Encode()
logStr := fmt.Sprintf("重新发送空闲帧数据,发送次数:%v,帧系列id:%v,数据:%v,requestId:%v", dd.SendCount, freeMsg.MsgSerial, hex.EncodeToString(repeatData), requestId)
slog.Info(logStr)
err := b.client.Send(repeatData)
if err != nil {
slog.Error(logStr, err)
}
}
} else {
packetMsg := &message.BtmVobcMessage{}
if b.unmarshalJson(dd.SendTelegram, packetMsg) == nil {
balise, _ := hex.DecodeString(dd.BalisePacket)
packetMsg.BtmMsg = balise
baliseData := packetMsg.Encode()
logStr := fmt.Sprintf("重新发送空闲帧数据,发送次数:%v,帧系列id:%v 数据:%v ,requestId:%v", dd.SendCount, packetMsg.MsgSerial, hex.EncodeToString(baliseData), requestId)
slog.Info(logStr)
err := b.client.Send(baliseData)
if err != nil {
slog.Error(logStr, err)
}
}
}
}
}
}
func (b *BtmVobcClient) unmarshalJson(jsonStr string, obj any) error {
err := json.Unmarshal([]byte(jsonStr), obj)
if err != nil {
slog.Error(fmt.Sprintf("vobc btm 数据转换失败 source:%v,对象:%v", jsonStr, reflect.TypeOf(obj).Name()))
return err
}
return nil
}
2024-06-06 18:56:25 +08:00
// 有应答器报文
2024-06-06 17:57:30 +08:00
func (b *BtmVobcClient) balisePackets(requestId string, tel *state_proto.VobcBtmState_TelegramState, receiveTime int64, decodePayMicoTime int64, vobcLifeNum uint32, autoCommandId byte, vobcbtm *state_proto.VobcBtmState) {
data, e := hex.DecodeString(tel.Telegram)
if e != nil {
slog.Error(fmt.Sprintf("解析应答器报文失败应答器报文长度:%v", tel.Telegram), e)
return
}
if len(data) < balise_const.UserTelegramByteLen {
for i := 0; i < balise_const.UserTelegramByteLen-len(data); i++ {
data = append(data, 0)
}
}
//前沿时间
var fttl uint16 = 0
tmpFttl := int64(math.Abs(float64(time.Now().UnixMilli() - tel.ArriveTime)))
if tmpFttl >= 0xffff {
fttl = 0xffff
} else {
fttl = uint16(tmpFttl)
}
var bttl uint16 = 0
tmpBttl := int64(math.Abs(float64(time.Now().UnixMilli() - tel.ArriveTime)))
if tmpBttl >= 0xffff {
bttl = 0xffff
} else {
bttl = uint16(tmpBttl)
}
repTimeMicro := (receiveTime - time.Now().UnixMicro()) / 100
baliseMsg := &message.BtmVobcMessage{FontTtl: fttl, BtmStatus: message.BTM_STSTUS_NORMAL, DecodeTime: uint16(decodePayMicoTime),
BackTtl: bttl, ResponseTime: byte(repTimeMicro), MsgSerial: message.GetAutoMessageId(),
VobcLifeNum: vobcLifeNum, BaseBtmVobc: message.BaseBtmVobc{AutoIdFrame: autoCommandId}}
u32MsgId := uint32(baliseMsg.MsgSerial)
jsonArr, _ := json.Marshal(baliseMsg)
baliseMsg.BtmMsg = data
baliseData := baliseMsg.Encode()
baliseMsgHex := hex.EncodeToString(baliseData)
vobcbtm.History[u32MsgId] = &state_proto.VobcBtmState_VobcBtmHistoryState{SendCount: 1, PacketSendId: u32MsgId, VobcLifeNum: vobcLifeNum,
IsFreePacket: false, SendTelegram: string(jsonArr), BalisePacket: tel.Telegram}
logStr := fmt.Sprintf("发送btm vobc 报文数据 报文序列id:%v 报文内容:%v 长度:%v ,requestId:%v", u32MsgId, baliseMsgHex, len(baliseData), requestId)
slog.Info(logStr)
err := b.client.Send(baliseData)
if err != nil {
slog.Error(logStr, err)
2024-05-29 13:34:50 +08:00
return
2024-06-06 17:57:30 +08:00
}
return
2024-05-29 13:34:50 +08:00
}
2024-06-06 18:56:25 +08:00
// 无应答器报文
2024-06-06 17:57:30 +08:00
func (b *BtmVobcClient) balisePacketsFree(requestId string, receiveTime int64, vobcLifeNum uint32, autoCommandId byte, vobcbtm *state_proto.VobcBtmState) {
repTimeMicro := (receiveTime - time.Now().UnixMicro()) / 100
data := createFreeBalisePackets()
2024-06-06 18:56:25 +08:00
freeMsg := &message.BtmVobcMsgFree{BtmStatus: message.BTM_STSTUS_NORMAL, Fun1: 0xffff, Fun2: 0x00CF, Fun3: uint16(0), Fun4: uint16(0),
2024-06-06 17:57:30 +08:00
FreeMsg: data, RespTime: byte(repTimeMicro), MsgSerial: message.GetAutoMessageId(), VobcLifeNum: vobcLifeNum, BaseBtmVobc: message.BaseBtmVobc{AutoIdFrame: autoCommandId}}
u32MsgId := uint32(freeMsg.MsgSerial)
jsonArr, _ := json.Marshal(freeMsg)
vobcbtm.History[u32MsgId] = &state_proto.VobcBtmState_VobcBtmHistoryState{SendCount: 1, PacketSendId: u32MsgId, VobcLifeNum: vobcLifeNum, IsFreePacket: true, SendTelegram: string(jsonArr)}
freeData := freeMsg.Encode()
dataEncode := hex.EncodeToString(freeData)
logStr := fmt.Sprintf("发送btm vobc 报文序列id:%v 空闲帧报文:%v 长度:%v ,requestId:%v", u32MsgId, dataEncode, len(freeData), requestId)
slog.Info(logStr)
err := b.client.Send(freeData)
if err != nil {
slog.Error(logStr, err)
return
}
}
// 应答器报文或空报文
2024-06-12 17:45:47 +08:00
func (b *BtmVobcClient) packets(requestId string, vobcLifeNum uint32, autoIdFrame byte, receiveTime int64, decodePayMicoTime int64, vobcbtm *state_proto.VobcBtmState) {
2024-06-06 17:57:30 +08:00
if len(vobcbtm.TelegramState) == 0 {
2024-06-12 17:45:47 +08:00
b.balisePacketsFree(requestId, receiveTime, vobcLifeNum, autoIdFrame, vobcbtm)
2024-06-06 17:57:30 +08:00
} else {
2024-06-12 17:45:47 +08:00
b.balisePackets(requestId, vobcbtm.TelegramState[0], receiveTime, decodePayMicoTime, vobcLifeNum, autoIdFrame, vobcbtm)
2024-06-06 17:57:30 +08:00
}
}
2024-05-29 13:34:50 +08:00
func (b *BtmVobcClient) SendData(data []byte) {
if b.client != nil {
2024-06-06 17:57:30 +08:00
slog.Info(fmt.Sprintf("发送btm vobc 报文:%v 长度:%v", hex.EncodeToString(data), len(data)))
2024-05-29 13:34:50 +08:00
err := b.client.Send(data)
if err != nil {
slog.Error("发送btm vobc 报文失败:", err)
return
}
}
}
func (b *BtmVobcClient) Stop() {
if b.server != nil {
2024-06-06 17:57:30 +08:00
b.calFun()
2024-05-29 13:34:50 +08:00
b.server.Close()
}
if b.client != nil {
b.client.Close()
}
2024-05-29 11:48:04 +08:00
}