rts-sim-testing-service/third_party/can_btm/balise_btm.go

362 lines
10 KiB
Go
Raw Normal View History

2023-11-21 18:13:50 +08:00
package can_btm
import (
"fmt"
2023-11-24 15:20:05 +08:00
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/const/balise_const"
"joylink.club/bj-rtsts-server/dto/state_proto"
2023-11-21 18:13:50 +08:00
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp"
2023-12-05 09:37:34 +08:00
"joylink.club/ecs"
"joylink.club/rtsssimulation/entity"
2023-11-21 18:13:50 +08:00
"log/slog"
2023-11-22 11:22:37 +08:00
"sort"
"strings"
2023-11-24 15:20:05 +08:00
"sync"
"time"
2023-11-21 18:13:50 +08:00
)
2023-11-24 15:20:05 +08:00
//使用当有多个虚拟车时同一时刻只有一个虚拟车与CANET关联
// BtmCanetManager BTM CANET 管理器
type BtmCanetManager interface {
2023-12-05 09:37:34 +08:00
EvnWorld() ecs.World
2023-11-24 15:20:05 +08:00
//GetBtmCanetConfig 获取CANET配置信息
GetBtmCanetConfig() config.BtmCanetConfig
}
2023-11-21 18:13:50 +08:00
// btm与canet(网口-CAN口转换器)
type btmCanetClient struct {
2023-11-24 15:20:05 +08:00
bcm BtmCanetManager
2023-11-23 16:30:48 +08:00
//udp server
2023-11-21 18:13:50 +08:00
udpServer udp.UdpServer
2023-11-23 16:30:48 +08:00
//udp client
udpClient udp.UdpClient
//udp 本地侦听端口
localUdpPort int
//udp 远程端口
2023-11-21 18:13:50 +08:00
remoteUdpPort int
2023-11-23 16:30:48 +08:00
//udp 远程ip
remoteIp string
//最近一次车载ATP系统查询帧序号
atpReqSn byte
2023-11-30 09:57:20 +08:00
//btm最近一次接收到atp查询请求的时间
//当BTM超过150ms即3个周期没有收到atq下发的查询帧则清空报文缓冲区
atpReqTime *time.Time
2023-11-24 15:20:05 +08:00
//最近一次车载ATP系统查询帧CRC16校验结果,true-校验通过
2023-11-23 16:30:48 +08:00
atpReqCrc16Check bool
2023-11-24 15:20:05 +08:00
//btm系统时间,每次接收到ATP查询请求帧时同步一次时间
btmTime btmClock
//数据流水号
dsn byte
2023-11-24 16:01:28 +08:00
//重发的数据
resendData *resendData
2023-12-05 09:37:34 +08:00
//车载BTM天线探测应答器
baliseDetector *BaliseDetector
2023-11-24 15:20:05 +08:00
}
func (s *btmCanetClient) GetState() state_proto.BTMState {
detector := s.baliseDetector
var telegram string
info := detector.eq[len(detector.eq)-1]
if detector.aboveBalise && info != nil {
telegram = fmt.Sprintf("%X", info.telegram)
} else {
telegram = strings.Repeat("00", balise_const.UserTelegramByteLen)
}
return state_proto.BTMState{
DataSerialNumber: uint32(s.dsn),
BaliseCount: uint32(detector.baliseCounter),
MessageCounter: uint32(detector.messageCounter),
Telegram: telegram,
}
}
2023-11-24 15:20:05 +08:00
type btmClock struct {
btmTk uint32 //与ATP系统同步的时间ms
sysTk time.Time //本地系统时间
2023-11-22 11:22:37 +08:00
}
2023-11-24 15:20:05 +08:00
// 获取以btmTk为基准的当前时间ms
func (c *btmClock) tkNow() uint32 {
return c.btmTk + uint32(time.Now().UnixMilli()-c.sysTk.UnixMilli())
}
2023-11-22 11:22:37 +08:00
type BtmCanetClient interface {
2023-11-24 15:20:05 +08:00
Start(bcm BtmCanetManager)
2023-11-22 11:22:37 +08:00
Stop()
2023-12-05 09:37:34 +08:00
//HandleTrainHeadPositionInfo 处理收到列车位置信息
HandleTrainHeadPositionInfo(w ecs.World, h *TrainHeadPositionInfo)
//获取BTM显示状态
GetState() state_proto.BTMState
2023-11-22 11:22:37 +08:00
}
2023-11-21 18:13:50 +08:00
2023-11-24 15:20:05 +08:00
var (
btmClientLocker sync.Mutex
btmClient BtmCanetClient
)
func Default() BtmCanetClient {
btmClientLocker.Lock()
defer btmClientLocker.Unlock()
if btmClient == nil {
2023-12-05 09:37:34 +08:00
btmClient = &btmCanetClient{baliseDetector: &BaliseDetector{}}
2023-11-24 15:20:05 +08:00
}
return btmClient
2023-11-22 11:22:37 +08:00
}
2023-12-05 11:24:43 +08:00
// HandleTrainHeadPositionInfo 处理来自动力学的列车位置信息
2023-12-05 09:37:34 +08:00
func (s *btmCanetClient) HandleTrainHeadPositionInfo(w ecs.World, h *TrainHeadPositionInfo) {
//slog.Debug(h.String())
wd := entity.GetWorldData(w)
repo := wd.Repo
2023-12-05 13:49:22 +08:00
s.baliseDetector.detect(wd, repo, h)
2023-12-05 09:37:34 +08:00
}
2023-11-24 15:20:05 +08:00
func (s *btmCanetClient) Start(bcm BtmCanetManager) {
s.bcm = bcm
cfg := s.bcm.GetBtmCanetConfig()
2023-11-27 09:14:20 +08:00
//测试用
2023-11-28 13:30:10 +08:00
//cfg.Open = true
//cfg.RemoteUdpPort = 5555
//cfg.RemoteIp = "192.168.3.5"
//cfg.LocalUdpPort = 6666
2023-11-27 09:14:20 +08:00
//
2023-11-24 15:20:05 +08:00
if !cfg.Open {
return
}
s.localUdpPort = cfg.LocalUdpPort
s.remoteIp = cfg.RemoteIp
s.remoteUdpPort = cfg.RemoteUdpPort
2023-11-21 18:13:50 +08:00
//
2023-11-22 11:22:37 +08:00
s.udpServer = udp.NewServer(fmt.Sprintf(":%d", s.localUdpPort), s.handleCanetFrames)
2023-11-21 18:13:50 +08:00
s.udpServer.Listen()
//
s.udpClient = udp.NewClient(fmt.Sprintf("%s:%d", s.remoteIp, s.remoteUdpPort))
}
func (s *btmCanetClient) Stop() {
if s.udpServer != nil {
s.udpServer.Close()
2023-11-24 15:20:05 +08:00
s.udpServer = nil
2023-11-21 18:13:50 +08:00
}
if s.udpClient != nil {
s.udpClient.Close()
2023-11-24 15:20:05 +08:00
s.udpClient = nil
2023-11-21 18:13:50 +08:00
}
}
2023-11-22 11:22:37 +08:00
func (s *btmCanetClient) handleCanetFrames(cfs []byte) {
2023-11-29 14:10:25 +08:00
defer func() {
if e := recover(); e != nil {
slog.Debug(fmt.Sprintf("handleCanetFrames异常[%s]", e))
}
}()
2023-11-21 18:13:50 +08:00
//一个cannet 帧 13字节
if len(cfs) > 0 && len(cfs)%13 == 0 {
cfSum := len(cfs) / 13
2023-11-22 11:22:37 +08:00
dms := make([]*message.CanetFrame, 0, 16) //13个应答器报文数据帧+TimeA帧+TimeB帧+结束帧
2023-11-21 18:13:50 +08:00
for cfi := 0; cfi < cfSum; cfi++ {
cfStart := cfi * 13
cf := message.NewCanetFrame(cfs[cfStart : cfStart+13])
2023-11-22 11:22:37 +08:00
//
switch cf.CanFrameType() {
case message.CfReq:
s.dealWithAptReq(cf)
case message.CfStatusRsp:
s.dealWithBtmStatusRsp(cf)
case message.CfTimeSync:
s.dealWithBtmTimeSyncRsp(cf)
case message.CfMsg:
fallthrough
case message.CfMsgTimeA:
fallthrough
case message.CfMsgTimeB:
fallthrough
case message.CfMsgEnd:
dms = append(dms, cf)
default:
slog.Warn("CanetFrame帧没有具体对应的应用帧", "CannetFrame", cf.String())
} //switch
} //for
//将数据包按ID3即0x80+offset由小到大排序
sort.SliceStable(dms, func(i, j int) bool {
return dms[i].CanId.ID3 < dms[j].CanId.ID3
})
//有数据帧但是不足16帧
if len(dms) > 0 {
if len(dms) != 16 {
slog.Warn("接收到数据帧但数据帧数量不足16帧")
} else {
s.dealWithBtmDataFrames(dms)
}
2023-11-21 18:13:50 +08:00
}
2023-11-22 11:22:37 +08:00
2023-11-21 18:13:50 +08:00
} else {
slog.Warn("从cannet接收数据未满足条件len(cfs) > 0 && len(cfs)%13 == 0", "len(cfs)", len(cfs))
}
}
2023-11-22 11:22:37 +08:00
// 处理接收的ATP查询请求帧
func (s *btmCanetClient) dealWithAptReq(f *message.CanetFrame) {
2023-11-30 09:57:20 +08:00
now := time.Now()
2023-11-22 11:22:37 +08:00
atpReq := &message.AtpRequestFrame{}
if !atpReq.Decode(f) {
slog.Warn("CanetFrame解码成AtpRequestFrame失败", "CanetFrame", f.String())
2023-11-23 16:30:48 +08:00
return
2023-11-22 11:22:37 +08:00
}
//处理查询请求
2023-11-27 15:09:10 +08:00
//slog.Debug(fmt.Sprintf("处理查询请求:%s", atpReq.String()))
2023-11-23 16:30:48 +08:00
//
2023-11-24 15:20:05 +08:00
s.btmTime.btmTk = atpReq.Time
2023-12-06 10:23:00 +08:00
s.btmTime.sysTk = now
2023-11-23 16:30:48 +08:00
s.atpReqSn = atpReq.FId.ID4
s.atpReqCrc16Check = atpReq.Crc16CheckOk
2023-12-05 10:57:31 +08:00
s.baliseDetector.powerAmplifierSwitch = atpReq.PowerAmplifierTurnOn
2023-11-30 09:57:20 +08:00
//记录atp查询时间
s.atpReqTime = &now
2023-12-05 09:37:34 +08:00
//ATP 是否要求BTM 重发上一应答器报文
isResendRequest := atpReq.ResendRequest == 2 //0b10
if isResendRequest {
s.rspResendToAtp()
} else {
2023-12-05 13:49:22 +08:00
sb := s.baliseDetector.doScan()
2023-12-05 09:37:34 +08:00
if sb != nil {
slog.Debug(fmt.Sprintf("BTM经过应答器[%s],BTM与ATP时间差[%d]ms", sb.BaliseId, time.Now().UnixMilli()-sb.Time.UnixMilli()))
s.rspToAtp(sb)
2023-12-05 10:57:31 +08:00
} else {
s.rspToAtp(nil)
2023-12-05 09:37:34 +08:00
}
}
}
func (s *btmCanetClient) createTrainBtmStatus() *TrainBtmStatus {
return &TrainBtmStatus{
2023-12-05 10:57:31 +08:00
PowerAmplifierOn: s.baliseDetector.powerAmplifierSwitch,
2023-12-05 09:37:34 +08:00
PowerAmplifierFault: false,
2023-12-05 10:57:31 +08:00
AboveBalise: s.baliseDetector.aboveBalise,
2023-12-05 09:37:34 +08:00
AntennaFault: false,
2023-12-05 10:57:31 +08:00
BaliseCounter: s.baliseDetector.baliseCounter,
MessageCounter: s.baliseDetector.messageCounter,
2023-12-05 09:37:34 +08:00
}
2023-11-22 11:22:37 +08:00
}
2023-11-23 18:14:01 +08:00
// BTM发送响应给ATP
// 当收到应答器报文时响应:时间同步帧、状态应答帧、数据帧
// 当未收到应答器报文时响应:时间同步帧、状态应答帧
2023-12-05 09:37:34 +08:00
func (s *btmCanetClient) rspResendToAtp() {
2023-11-24 16:01:28 +08:00
//重发上一报文处理
2023-12-05 09:37:34 +08:00
if s.resendData != nil && s.resendData.canResend() {
2023-11-24 16:01:28 +08:00
s.resendData.countAdd1()
s.sendCanetFrame(s.resendData.data)
return
}
2023-12-05 09:37:34 +08:00
}
// BTM发送响应给ATP
// 当收到应答器报文时响应:时间同步帧、状态应答帧、数据帧
// 当未收到应答器报文时响应:时间同步帧、状态应答帧
func (s *btmCanetClient) rspToAtp(sb *BtmAntennaScanningBaliseInfo) {
2023-11-24 15:20:05 +08:00
//BTM状态
2023-11-23 18:14:01 +08:00
statusF := message.NewBtmStatusRspFrame(s.atpReqSn)
2023-12-05 09:37:34 +08:00
btmStatus := s.createTrainBtmStatus()
2023-11-24 15:20:05 +08:00
statusF.AntennaFault = btmStatus.AntennaFault
statusF.BaliseCounter = byte(btmStatus.BaliseCounter)
statusF.MessageCounter = byte(btmStatus.MessageCounter)
statusF.PowerAmplifierOn = btmStatus.PowerAmplifierOn
statusF.TkTimeA = s.btmTime.tkNow()
statusF.PowerAmplifierFailure = btmStatus.PowerAmplifierFault
statusF.DetailedCode = 0
if btmStatus.AboveBalise {
statusF.DetailedCode = 0x07
}
statusF.AtpReqCrcCheckWrong = !s.atpReqCrc16Check
statusF.Dsn = s.dsn
s.dsnAdd1()
//
2023-11-23 18:14:01 +08:00
//true-收到应答器报文
2023-12-05 10:57:31 +08:00
isRcvTelegram := sb != nil && len(sb.telegram) > 0
2023-11-23 18:14:01 +08:00
if isRcvTelegram { //当收到应答器报文时响应:时间同步帧、状态应答帧、数据帧
2023-12-05 10:57:31 +08:00
statusDataCf, statusDataCfOk := message.CreateBtmRspFramesData(statusF, sb.telegram, false, s.btmTime.tkNow(), s.btmTime.tkNow(), s.btmTime.tkNow())
2023-11-24 15:20:05 +08:00
if statusDataCfOk {
timeSyncF := message.NewBtmTimeSyncCheckFrame(s.atpReqSn)
timeSyncF.T2 = s.btmTime.btmTk
timeSyncF.T3 = s.btmTime.tkNow()
s.sendCanetFrame(timeSyncF.Encode().Encode())
//
2023-11-24 16:01:28 +08:00
s.resendData = newResendData(statusDataCf)
2023-11-24 15:20:05 +08:00
s.sendCanetFrame(statusDataCf)
} else {
slog.Warn("BtmCanetClient应答帧、数据帧编码失败")
}
2023-11-23 18:14:01 +08:00
} else { //当未收到应答器报文时响应:时间同步帧、状态应答帧
2023-11-24 15:20:05 +08:00
timeSyncF := message.NewBtmTimeSyncCheckFrame(s.atpReqSn)
timeSyncF.T2 = s.btmTime.btmTk
timeSyncF.T3 = s.btmTime.tkNow()
s.sendCanetFrame(timeSyncF.Encode().Encode())
//
2023-11-23 18:14:01 +08:00
statusCf := statusF.Encode().Encode()
s.sendCanetFrame(statusCf)
}
}
// 发送Canet帧一帧13字节
func (s *btmCanetClient) sendCanetFrame(cf []byte) {
s.udpClient.Send(cf)
}
2023-11-24 15:20:05 +08:00
func (s *btmCanetClient) dsnAdd1() {
if s.dsn >= 255 {
s.dsn = 0
} else {
s.dsn++
}
}
2023-11-23 18:14:01 +08:00
2023-11-24 16:01:28 +08:00
// 准备重发的状态应答帧和报文数据帧
type resendData struct {
data []byte //重发的数据
count int //重发次数
}
func newResendData(data []byte) *resendData {
return &resendData{
data: data,
count: 0,
}
}
func (r *resendData) canResend() bool {
return r.count <= 3
}
func (r *resendData) countAdd1() {
r.count++
}
2023-11-22 11:22:37 +08:00
//////////////////////////////////////////////////////////////////////////////////////////
// 处理接收的状态应答帧
func (s *btmCanetClient) dealWithBtmStatusRsp(f *message.CanetFrame) {
slog.Debug(fmt.Sprintf("接收到状态应答帧%s", f.String()))
}
// 处理接收的时间同步校验应答帧
func (s *btmCanetClient) dealWithBtmTimeSyncRsp(f *message.CanetFrame) {
slog.Debug(fmt.Sprintf("接收到时间同步校验应答帧%s", f.String()))
}
// 处理接收到的16帧数据帧
func (s *btmCanetClient) dealWithBtmDataFrames(dms []*message.CanetFrame) {
for _, dm := range dms {
slog.Debug(fmt.Sprintf("接收到数据帧%s", dm.String()))
}
}
2023-12-05 09:37:34 +08:00
//////////////////////////////////////////////////////////////////////
type TrainBtmStatus struct {
PowerAmplifierOn bool //BTM功率放大器是否开启
PowerAmplifierFault bool //BTM功率放大器是否有故障
AntennaFault bool //BTM应答器天线是否有故障
AboveBalise bool //BTM当前是否在应答器上方
BaliseCounter int //应答器计数(每过一个应答器加一,在同一个应答器内不变)
MessageCounter int //报文计数器(每解出一个应答器报文加一)
}