rts-sim-testing-service/third_party/semi_physical_train/balise_vobc.go
2024-09-25 11:19:18 +08:00

272 lines
9.2 KiB
Go

package semi_physical_train
import (
"context"
"encoding/hex"
"fmt"
"github.com/google/uuid"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/const/balise_const"
"joylink.club/bj-rtsts-server/dto/state_proto"
"joylink.club/bj-rtsts-server/third_party/can_btm"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp"
"log/slog"
"math"
"time"
"strings"
"sync"
)
type BtmVobcManage interface {
SemiPhysicalBaseManager
GetBtmVobcConfig() config.BtmVobcConfig
//GetAllTrain() []*state_proto.TrainState
}
type BtmVobcService interface {
Start(btmVobcManage BtmVobcManage)
Stop()
SendData(data []byte)
}
type BtmVobcClient struct {
calFun context.CancelFunc
client udp.UdpClient
server udp.UdpServer
manage BtmVobcManage
}
var (
btmVobcLocker sync.Mutex
btmVobcClient *BtmVobcClient
btmVobcBaliseLocker sync.Mutex
//最新接受数据时间
reviceTimeStamp int64
)
func BtmDefault() BtmVobcService {
defer btmVobcLocker.Unlock()
btmVobcLocker.Lock()
if btmVobcClient == nil {
btmVobcClient = &BtmVobcClient{}
}
return btmVobcClient
}
func (b *BtmVobcClient) Start(btmVobcManage BtmVobcManage) {
cfg := btmVobcManage.GetBtmVobcConfig()
if !cfg.Open {
slog.Info("11号线 btm 配置未开启...")
return
}
udpServer := udp.NewServer(fmt.Sprintf("%v:%d", cfg.LocalUdpIp, cfg.LocalUdpPort), b.handleBtmVobcFrames)
err := udpServer.Listen()
if err != nil {
slog.Error("11号线 btm 服务启动失败...")
return
}
//
udpClient := udp.NewClient(fmt.Sprintf("%s:%d", cfg.RemoteIp, cfg.RemoteUdpPort))
b.manage = btmVobcManage
b.server = udpServer
b.client = udpClient
reviceTimeStamp = time.Now().UnixMilli()
_, calFun := context.WithCancel(context.Background())
b.calFun = calFun
}
func (b *BtmVobcClient) vobcBtmQueryHandle(data []byte) {
train := b.manage.GetConnVobcTrain()
if train == nil {
slog.Error("vobc btm 未找到VOBC连接的列车...")
return
}
requestId := uuid.New().String()
frameType, dataText, err := message.BtmVobcDecode(data)
if err != nil {
slog.Error(fmt.Sprintf("%v,请求id:%v", err, requestId))
return
}
receiveDataTime := time.Now().UnixMilli()
if frameType == message.COMMAND_TYPE {
idCommand := &message.BtmVobcIdCommand{}
idCommand.Decode(dataText)
slog.Info(fmt.Sprintf("成功接受btm vobc的id命令帧,requestId:%v,接受时间:%v", requestId, receiveDataTime))
if train.VobcState.VobcBtmInfo == nil {
train.VobcState.VobcBtmInfo = &state_proto.TrainVobcState_VobcBtmInfo{BtmId: uint32(idCommand.BtmId), VobcId: uint32(idCommand.VobcId), VobcLifeId: idCommand.VobcLifeNum}
}
} else if train.VobcState.VobcBtmInfo != nil && frameType == message.REQUEST_TYPE {
slog.Info(fmt.Sprintf("成功接受btm vobc的请求帧,requestId:%v,接受时间(微秒):%v", requestId, receiveDataTime))
req := &message.BtmVobcReq{}
req.Decode(dataText)
b.requestFramePackets(requestId, req, train, receiveDataTime)
} 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 (b *BtmVobcClient) handleBtmVobcFrames(cfs []byte) {
/* reviceTimeStamp = time.Now().UnixMilli()
train := b.manage.GetConnVobcTrain()
if train == nil {
//slog.Error("vobc btm 未找到VOBC连接的列车...")
return
}
requestId := uuid.New().String()
slog.Info(fmt.Sprintf("获取到vobc btm原始数据:%v, requestId:%v", hex.EncodeToString(cfs), requestId))
frameType, dataText, err := message.BtmVobcDecode(cfs)
if err != nil {
slog.Error(fmt.Sprintf("%v,请求id:%v", err, requestId))
return
}
receiveDataTime := time.Now().UnixMicro()
decodePayMicoTime := (receiveDataTime - receiveDataTime) / 100
if frameType == message.COMMAND_TYPE {
idCommand := &message.BtmVobcIdCommand{}
idCommand.Decode(dataText)
slog.Info(fmt.Sprintf("成功接受btm vobc的id命令帧,requestId:%v,接受时间(微秒):%v", requestId, receiveDataTime))
b.packets(requestId, idCommand.VobcLifeNum, idCommand.AutoIdFrame, receiveDataTime, decodePayMicoTime, train.VobcBtm)
} else if frameType == message.REQUEST_TYPE {
slog.Info(fmt.Sprintf("成功接受btm vobc的请求帧,requestId:%v,接受时间(微秒):%v", requestId, receiveDataTime))
req := &message.BtmVobcReq{}
req.Decode(dataText)
b.RequestFramePackets(req.VobcLifeNum, req.AutoIdFrame, requestId, receiveDataTime, decodePayMicoTime, req, train.VobcBtm)
} 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
}
// 请求帧
func (b *BtmVobcClient) requestFramePackets(requestId string, req *message.BtmVobcReq, train *state_proto.TrainState, receiveTime int64) {
if req.FrameStatus == message.REQ_FRAME_STATUS_BOOT && req.MessageType == message.REQ_PACKETS_TYPE_BOOT {
//vobc 上电,清空应答器
can_btm.ClearBalise(train)
} else {
var (
btmState *state_proto.BTMState
dsn byte
matcher bool
)
ms := req.MessageSerial
if req.FrameStatus == message.REQ_FRAME_STATUS_ERROR {
//抢答器错误,重新发送
btmState, dsn, _, _ = can_btm.FindBaliseResend(train.BtmBaliseCacheA, false)
} else {
//判断 报文序列号与之前发送的 是否一致,不一致
//如果一致返回新的应答器,如果不一致返回之前发送的应答器,如果不一致并且没有找到之前发送的应答器,则返回新应答器
btmState, dsn, matcher = can_btm.FindBaliseByMessageSerial(train.BtmBaliseCacheA, false, req.MessageSerial)
if matcher {
if btmState != nil {
//正常应答
btmState.IsSend = true
ms = req.MessageSerial + 1
if ms > 255 {
ms = 1
}
}
} else {
//vobc 未收到应答器,重新发送
}
}
b.packets(requestId, btmState, ms, dsn, req.VobcLifeNum, receiveTime)
}
}
// 有应答器报文
func (b *BtmVobcClient) balisePackets(telegram, requestId string, messageSerial, dsn byte, vobcLifeNum uint32, receiveTime int64) {
data, e := hex.DecodeString(telegram)
if e != nil {
slog.Error(fmt.Sprintf("解析应答器报文失败应答器报文长度:%v", telegram), e)
return
}
//前沿时间
var fttl uint16 = 0
tmpFttl := int64(math.Abs(float64(time.Now().UnixMilli() - receiveTime)))
if tmpFttl >= 0xffff {
fttl = 0xffff
} else {
fttl = uint16(tmpFttl)
}
var bttl uint16 = 0
tmpBttl := int64(math.Abs(float64(time.Now().UnixMilli() - receiveTime)))
if tmpBttl >= 0xffff {
bttl = 0xffff
} else {
bttl = uint16(tmpBttl)
}
repTimeMicro := (time.Now().UnixMilli() - receiveTime) / 10
baliseMsg := &message.BtmVobcMessage{FontTtl: fttl, BtmStatus: message.BTM_STSTUS_NORMAL, DecodeTime: uint16(repTimeMicro),
BackTtl: bttl, ResponseTime: byte(repTimeMicro), MsgSerial: messageSerial, BtmMsg: data,
VobcLifeNum: vobcLifeNum, BaseBtmVobc: message.BaseBtmVobc{AutoIdFrame: dsn}}
baliseData := baliseMsg.Encode()
slog.Info(fmt.Sprintf("发送btm vobc 报文数据 报文序列id:%v 报文内容:%X 长度:%v ,requestId:%v", messageSerial, baliseData, len(baliseData), requestId))
err := b.client.Send(baliseData)
if err != nil {
slog.Error(fmt.Sprintf("发送btm vobc 报文数据 报文序列id:%v 报文内容:%X 长度:%v ,requestId:%v", messageSerial, baliseData, len(baliseData), requestId), err)
return
}
return
}
// 无应答器报文
func (b *BtmVobcClient) balisePacketsFree(requestId string, receiveTime int64, vobcLifeNum uint32, autoCommandId, messageSerial byte) {
repTimeMicro := (time.Now().UnixMicro() - receiveTime) / 10
freeMsg := &message.BtmVobcMsgFree{BtmStatus: message.BTM_STSTUS_NORMAL, Fun1: 0xffff, Fun2: 0x00CF, Fun3: uint16(0), Fun4: uint16(0),
FreeMsg: createFreeBalisePackets(), RespTime: byte(repTimeMicro), MsgSerial: messageSerial, VobcLifeNum: vobcLifeNum, BaseBtmVobc: message.BaseBtmVobc{AutoIdFrame: autoCommandId}}
freeData := freeMsg.Encode()
logStr := fmt.Sprintf("发送btm vobc 报文序列id:%v 空闲帧报文:%X 长度:%v ,requestId:%v", messageSerial, freeData, len(freeData), requestId)
slog.Info(logStr)
err := b.client.Send(freeData)
if err != nil {
slog.Error(logStr, err)
return
}
}
// 应答器报文或空报文
func (b *BtmVobcClient) packets(requestId string, btmState *state_proto.BTMState, messageSerial, dsn byte, vobcLifeNum uint32, receiveTime int64) {
if btmState == nil {
b.balisePacketsFree(requestId, receiveTime, vobcLifeNum, dsn, messageSerial)
} else {
b.balisePackets(btmState.Telegram, requestId, messageSerial, dsn, vobcLifeNum, receiveTime)
}
}
func (b *BtmVobcClient) SendData(data []byte) {
if b.client != nil {
slog.Info(fmt.Sprintf("发送btm vobc 报文:%v 长度:%v", hex.EncodeToString(data), len(data)))
err := b.client.Send(data)
if err != nil {
slog.Error("发送btm vobc 报文失败:", err)
return
}
}
}
func (b *BtmVobcClient) Stop() {
if b.server != nil {
b.calFun()
b.server.Close()
}
if b.client != nil {
b.client.Close()
}
}