btm
This commit is contained in:
parent
1784f3a66b
commit
5a20d78aa3
|
@ -71,6 +71,7 @@ type ThridPartyConfig struct {
|
||||||
Interlocks []InterlockConfig `json:"interlock" description:"联锁配置"`
|
Interlocks []InterlockConfig `json:"interlock" description:"联锁配置"`
|
||||||
RsspAxleCfgs []RsspAxleConfig `json:"rsspAxleCfgs" description:"所有联锁集中站计轴RSSP-I配置"`
|
RsspAxleCfgs []RsspAxleConfig `json:"rsspAxleCfgs" description:"所有联锁集中站计轴RSSP-I配置"`
|
||||||
ElectricMachinery ElectricMachineryConfig `json:"electricMachinery" description:"电机配置"`
|
ElectricMachinery ElectricMachineryConfig `json:"electricMachinery" description:"电机配置"`
|
||||||
|
BtmCanet BtmCanetConfig `json:"btmCanet" description:"BTM关联的网关设备CANET配置"`
|
||||||
}
|
}
|
||||||
type DynamicsConfig struct {
|
type DynamicsConfig struct {
|
||||||
Ip string `json:"ip" description:"IP配置"`
|
Ip string `json:"ip" description:"IP配置"`
|
||||||
|
@ -99,6 +100,14 @@ type ElectricMachineryConfig struct {
|
||||||
Open bool `json:"open" description:"是否开启"`
|
Open bool `json:"open" description:"是否开启"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BtmCanetConfig BTM CANET网关设备配置
|
||||||
|
type BtmCanetConfig struct {
|
||||||
|
LocalUdpPort int `json:"localUdpPort" description:"本机监听接收UDP端口"`
|
||||||
|
RemoteIp string `json:"remoteIp" description:"CANET设备IP配置"`
|
||||||
|
RemoteUdpPort int `json:"remoteUdpPort" description:"CANET设备UDP端口"`
|
||||||
|
Open bool `json:"open" description:"是否开启"`
|
||||||
|
}
|
||||||
|
|
||||||
// RsspAxleConfig 计轴区段与联锁安全通信配置
|
// RsspAxleConfig 计轴区段与联锁安全通信配置
|
||||||
type RsspAxleConfig struct {
|
type RsspAxleConfig struct {
|
||||||
Open bool `json:"open" description:"是否开启"`
|
Open bool `json:"open" description:"是否开启"`
|
||||||
|
|
|
@ -2,17 +2,29 @@ package can_btm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"joylink.club/bj-rtsts-server/config"
|
||||||
"joylink.club/bj-rtsts-server/third_party/message"
|
"joylink.club/bj-rtsts-server/third_party/message"
|
||||||
"joylink.club/bj-rtsts-server/third_party/udp"
|
"joylink.club/bj-rtsts-server/third_party/udp"
|
||||||
"joylink.club/ecs"
|
"joylink.club/bj-rtsts-server/ts/simulation/wayside/memory"
|
||||||
"joylink.club/rtsssimulation/fi"
|
"joylink.club/rtsssimulation/fi"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"sort"
|
"sort"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//使用:当有多个虚拟车时,同一时刻只有一个虚拟车与CANET关联
|
||||||
|
|
||||||
|
// BtmCanetManager BTM CANET 管理器
|
||||||
|
type BtmCanetManager interface {
|
||||||
|
memory.VerifyEvn
|
||||||
|
//GetBtmCanetConfig 获取CANET配置信息
|
||||||
|
GetBtmCanetConfig() config.BtmCanetConfig
|
||||||
|
}
|
||||||
|
|
||||||
// btm与canet(网口-CAN口转换器)
|
// btm与canet(网口-CAN口转换器)
|
||||||
type btmCanetClient struct {
|
type btmCanetClient struct {
|
||||||
w ecs.World
|
bcm BtmCanetManager
|
||||||
//udp server
|
//udp server
|
||||||
udpServer udp.UdpServer
|
udpServer udp.UdpServer
|
||||||
//udp client
|
//udp client
|
||||||
|
@ -23,28 +35,53 @@ type btmCanetClient struct {
|
||||||
remoteUdpPort int
|
remoteUdpPort int
|
||||||
//udp 远程ip
|
//udp 远程ip
|
||||||
remoteIp string
|
remoteIp string
|
||||||
//该CANET关联的唯一列车的id
|
|
||||||
trainId string
|
|
||||||
//车载ATP系统当前时间ms
|
|
||||||
atpSystemTime uint32
|
|
||||||
//最近一次车载ATP系统查询帧序号
|
//最近一次车载ATP系统查询帧序号
|
||||||
atpReqSn byte
|
atpReqSn byte
|
||||||
//最近一次车载ATP系统查询帧CRC16校验结果
|
//最近一次车载ATP系统查询帧CRC16校验结果,true-校验通过
|
||||||
atpReqCrc16Check bool
|
atpReqCrc16Check bool
|
||||||
|
//btm系统时间,每次接收到ATP查询请求帧时同步一次时间
|
||||||
|
btmTime btmClock
|
||||||
|
//数据流水号
|
||||||
|
dsn byte
|
||||||
}
|
}
|
||||||
type BtmCanetClient interface {
|
type btmClock struct {
|
||||||
Start()
|
btmTk uint32 //与ATP系统同步的时间ms
|
||||||
Stop()
|
sysTk time.Time //本地系统时间
|
||||||
TrainId() string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBtmCanetClient(trainId string, remoteIp string, remoteUdpPort int, localUdpPort int) BtmCanetClient {
|
// 获取以btmTk为基准的当前时间ms
|
||||||
return &btmCanetClient{trainId: trainId, remoteIp: remoteIp, remoteUdpPort: remoteUdpPort, localUdpPort: localUdpPort}
|
func (c *btmClock) tkNow() uint32 {
|
||||||
|
return c.btmTk + uint32(time.Now().UnixMilli()-c.sysTk.UnixMilli())
|
||||||
}
|
}
|
||||||
func (s *btmCanetClient) TrainId() string {
|
|
||||||
return s.trainId
|
type BtmCanetClient interface {
|
||||||
|
Start(bcm BtmCanetManager)
|
||||||
|
Stop()
|
||||||
}
|
}
|
||||||
func (s *btmCanetClient) Start() {
|
|
||||||
|
var (
|
||||||
|
btmClientLocker sync.Mutex
|
||||||
|
btmClient BtmCanetClient
|
||||||
|
)
|
||||||
|
|
||||||
|
func Default() BtmCanetClient {
|
||||||
|
btmClientLocker.Lock()
|
||||||
|
defer btmClientLocker.Unlock()
|
||||||
|
if btmClient == nil {
|
||||||
|
btmClient = &btmCanetClient{}
|
||||||
|
}
|
||||||
|
return btmClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *btmCanetClient) Start(bcm BtmCanetManager) {
|
||||||
|
s.bcm = bcm
|
||||||
|
cfg := s.bcm.GetBtmCanetConfig()
|
||||||
|
if !cfg.Open {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.localUdpPort = cfg.LocalUdpPort
|
||||||
|
s.remoteIp = cfg.RemoteIp
|
||||||
|
s.remoteUdpPort = cfg.RemoteUdpPort
|
||||||
//
|
//
|
||||||
s.udpServer = udp.NewServer(fmt.Sprintf(":%d", s.localUdpPort), s.handleCanetFrames)
|
s.udpServer = udp.NewServer(fmt.Sprintf(":%d", s.localUdpPort), s.handleCanetFrames)
|
||||||
s.udpServer.Listen()
|
s.udpServer.Listen()
|
||||||
|
@ -55,9 +92,11 @@ func (s *btmCanetClient) Start() {
|
||||||
func (s *btmCanetClient) Stop() {
|
func (s *btmCanetClient) Stop() {
|
||||||
if s.udpServer != nil {
|
if s.udpServer != nil {
|
||||||
s.udpServer.Close()
|
s.udpServer.Close()
|
||||||
|
s.udpServer = nil
|
||||||
}
|
}
|
||||||
if s.udpClient != nil {
|
if s.udpClient != nil {
|
||||||
s.udpClient.Close()
|
s.udpClient.Close()
|
||||||
|
s.udpClient = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *btmCanetClient) handleCanetFrames(cfs []byte) {
|
func (s *btmCanetClient) handleCanetFrames(cfs []byte) {
|
||||||
|
@ -116,32 +155,69 @@ func (s *btmCanetClient) dealWithAptReq(f *message.CanetFrame) {
|
||||||
//处理查询请求
|
//处理查询请求
|
||||||
slog.Debug(fmt.Sprintf("处理查询请求:%s", atpReq.String()))
|
slog.Debug(fmt.Sprintf("处理查询请求:%s", atpReq.String()))
|
||||||
//
|
//
|
||||||
s.atpSystemTime = atpReq.Time
|
s.btmTime.btmTk = atpReq.Time
|
||||||
|
s.btmTime.sysTk = time.Now()
|
||||||
s.atpReqSn = atpReq.FId.ID4
|
s.atpReqSn = atpReq.FId.ID4
|
||||||
s.atpReqCrc16Check = atpReq.Crc16CheckOk
|
s.atpReqCrc16Check = atpReq.Crc16CheckOk
|
||||||
se := fi.TrainBalisePowerAmplifierSwitch(s.w, s.trainId, atpReq.PowerAmplifierTurnOn)
|
se := fi.TrainBalisePowerAmplifierSwitch(s.bcm.EvnWorld(), atpReq.PowerAmplifierTurnOn)
|
||||||
if se != nil {
|
if se != nil {
|
||||||
slog.Warn(fmt.Sprintf("列车[%s]车载BTM功率放大器开关控制异常[%s]", s.trainId, se.Error()))
|
slog.Warn(fmt.Sprintf("列车车载BTM功率放大器开关控制异常[%s]", se.Error()))
|
||||||
}
|
}
|
||||||
|
//ATP 是否要求BTM 重发上一应答器报文
|
||||||
|
isResendRequest := atpReq.ResendRequest == 2 //0b10
|
||||||
|
s.rspToAtp(isResendRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BTM发送响应给ATP
|
// BTM发送响应给ATP
|
||||||
// 当收到应答器报文时响应:时间同步帧、状态应答帧、数据帧
|
// 当收到应答器报文时响应:时间同步帧、状态应答帧、数据帧
|
||||||
// 当未收到应答器报文时响应:时间同步帧、状态应答帧
|
// 当未收到应答器报文时响应:时间同步帧、状态应答帧
|
||||||
func (s *btmCanetClient) rspToAtp() {
|
func (s *btmCanetClient) rspToAtp(isResendRequest bool) {
|
||||||
timeSyncF := message.NewBtmTimeSyncCheckFrame(s.atpReqSn)
|
//BTM状态
|
||||||
timeSyncCf := timeSyncF.Encode().Encode()
|
|
||||||
statusF := message.NewBtmStatusRspFrame(s.atpReqSn)
|
statusF := message.NewBtmStatusRspFrame(s.atpReqSn)
|
||||||
|
btmStatus, btmStatusErr := fi.FindTrainBaliseBtmStatus(s.bcm.EvnWorld())
|
||||||
|
if btmStatusErr != nil {
|
||||||
|
slog.Debug(fmt.Sprintf("从仿真获取BTM状态失败:%s", btmStatusErr.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
//
|
||||||
|
baliseTelegram, btSendErr := fi.BaliseTelegramForSend(s.bcm.EvnWorld())
|
||||||
|
if btSendErr != nil {
|
||||||
|
//slog.Debug(btSendErr.Error())
|
||||||
|
}
|
||||||
//true-收到应答器报文
|
//true-收到应答器报文
|
||||||
//todo
|
isRcvTelegram := baliseTelegram != nil
|
||||||
isRcvTelegram := false
|
|
||||||
|
|
||||||
if isRcvTelegram { //当收到应答器报文时响应:时间同步帧、状态应答帧、数据帧
|
if isRcvTelegram { //当收到应答器报文时响应:时间同步帧、状态应答帧、数据帧
|
||||||
s.sendCanetFrame(timeSyncCf)
|
statusDataCf, statusDataCfOk := message.CreateBtmRspFramesData(statusF, baliseTelegram.Telegram, false, s.btmTime.tkNow(), s.btmTime.tkNow(), s.btmTime.tkNow())
|
||||||
|
if statusDataCfOk {
|
||||||
|
timeSyncF := message.NewBtmTimeSyncCheckFrame(s.atpReqSn)
|
||||||
|
timeSyncF.T2 = s.btmTime.btmTk
|
||||||
|
timeSyncF.T3 = s.btmTime.tkNow()
|
||||||
|
s.sendCanetFrame(timeSyncF.Encode().Encode())
|
||||||
|
//
|
||||||
|
s.sendCanetFrame(statusDataCf)
|
||||||
|
} else {
|
||||||
|
slog.Warn("BtmCanetClient应答帧、数据帧编码失败")
|
||||||
|
}
|
||||||
} else { //当未收到应答器报文时响应:时间同步帧、状态应答帧
|
} else { //当未收到应答器报文时响应:时间同步帧、状态应答帧
|
||||||
|
timeSyncF := message.NewBtmTimeSyncCheckFrame(s.atpReqSn)
|
||||||
|
timeSyncF.T2 = s.btmTime.btmTk
|
||||||
|
timeSyncF.T3 = s.btmTime.tkNow()
|
||||||
|
s.sendCanetFrame(timeSyncF.Encode().Encode())
|
||||||
|
//
|
||||||
statusCf := statusF.Encode().Encode()
|
statusCf := statusF.Encode().Encode()
|
||||||
s.sendCanetFrame(timeSyncCf)
|
|
||||||
s.sendCanetFrame(statusCf)
|
s.sendCanetFrame(statusCf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,6 +226,13 @@ func (s *btmCanetClient) rspToAtp() {
|
||||||
func (s *btmCanetClient) sendCanetFrame(cf []byte) {
|
func (s *btmCanetClient) sendCanetFrame(cf []byte) {
|
||||||
s.udpClient.Send(cf)
|
s.udpClient.Send(cf)
|
||||||
}
|
}
|
||||||
|
func (s *btmCanetClient) dsnAdd1() {
|
||||||
|
if s.dsn >= 255 {
|
||||||
|
s.dsn = 0
|
||||||
|
} else {
|
||||||
|
s.dsn++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,11 @@ func (s *VerifySimulation) GetComIdByUid(uid string) string {
|
||||||
}
|
}
|
||||||
return es[uid].CommonId
|
return es[uid].CommonId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBtmCanetConfig 获取CANET配置信息
|
||||||
|
func (s *VerifySimulation) GetBtmCanetConfig() config.BtmCanetConfig {
|
||||||
|
return s.runConfig.BtmCanet
|
||||||
|
}
|
||||||
func (s *VerifySimulation) GetLineAllRsspAxleCfgs() []config.RsspAxleConfig {
|
func (s *VerifySimulation) GetLineAllRsspAxleCfgs() []config.RsspAxleConfig {
|
||||||
return s.runConfig.RsspAxleCfgs
|
return s.runConfig.RsspAxleCfgs
|
||||||
}
|
}
|
||||||
|
@ -502,6 +507,9 @@ func (s *VerifySimulation) GetRunConfigId() int32 {
|
||||||
}
|
}
|
||||||
return s.runConfig.Id
|
return s.runConfig.Id
|
||||||
}
|
}
|
||||||
|
func (s *VerifySimulation) EvnWorld() ecs.World {
|
||||||
|
return s.World
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化运行资源
|
// 初始化运行资源
|
||||||
func (s *VerifySimulation) initRepository() error {
|
func (s *VerifySimulation) initRepository() error {
|
||||||
|
@ -1501,3 +1509,8 @@ func convertToProtoBaliseType(bt graphicData.Transponder_TransponderTypeEnum) pr
|
||||||
panic(fmt.Sprintf("graphicData.Transponder_TransponderTypeEnum[%d]无法映射到proto.Transponder_Type", bt))
|
panic(fmt.Sprintf("graphicData.Transponder_TransponderTypeEnum[%d]无法映射到proto.Transponder_Type", bt))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyEvn 测试环境
|
||||||
|
type VerifyEvn interface {
|
||||||
|
EvnWorld() ecs.World
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"joylink.club/bj-rtsts-server/third_party/can_btm"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -117,6 +118,8 @@ func runThirdParty(s *memory.VerifySimulation) error {
|
||||||
axle_device.StartLineAllRsspAxleServices(s)
|
axle_device.StartLineAllRsspAxleServices(s)
|
||||||
// 电机UDP启动
|
// 电机UDP启动
|
||||||
electrical_machinery.Default().Start(s)
|
electrical_machinery.Default().Start(s)
|
||||||
|
// 车载BTM启动
|
||||||
|
can_btm.Default().Start(s)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +137,9 @@ func stopThirdParty(s *memory.VerifySimulation) {
|
||||||
axle_device.StopLineAllRsspAxleServices()
|
axle_device.StopLineAllRsspAxleServices()
|
||||||
// 电机UDP停止
|
// 电机UDP停止
|
||||||
electrical_machinery.Default().Stop()
|
electrical_machinery.Default().Stop()
|
||||||
|
// 车载BTM停止
|
||||||
|
can_btm.Default().Stop()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSimulationId(projectId int32) string {
|
func createSimulationId(projectId int32) string {
|
||||||
|
|
Loading…
Reference in New Issue