rts-sim-testing-service/ts/simulation/wayside/memory/wayside_simulation_train_pc.go

405 lines
17 KiB
Go
Raw Normal View History

2024-04-02 18:20:10 +08:00
package memory
import (
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/const/balise_const"
"joylink.club/bj-rtsts-server/dto/request_proto"
"joylink.club/bj-rtsts-server/dto/state_proto"
"joylink.club/bj-rtsts-server/sys_error"
"joylink.club/bj-rtsts-server/third_party/can_btm"
"joylink.club/bj-rtsts-server/third_party/message"
train_pc_sim "joylink.club/bj-rtsts-server/third_party/train_pc_sim"
"log/slog"
"strings"
"time"
)
func (s *VerifySimulation) GetTrainPcSimConfig() config.VehiclePCSimConfig {
return s.runConfig.PcSimConfig
}
// 列车控制
func (s *VerifySimulation) ControlTrainUpdate(ct *request_proto.TrainControl) {
allTrainMap := &s.Memory.Status.TrainStateMap
data, ok := allTrainMap.Load(ct.TrainId)
if !ok {
panic(sys_error.New(fmt.Sprintf("列车【%s】不存在", ct.TrainId)))
}
sta := data.(*state_proto.TrainState)
var tce []train_pc_sim.TrainControlEvent = nil
if ct.ControlType == request_proto.TrainControl_EMERGENT_BUTTON {
trainControlEB(sta, ct.Button, ct.DeviceId)
} else if ct.ControlType == request_proto.TrainControl_DRIVER_KEY_SWITCH {
tce = trainControlDriverKey(sta, ct.DriverKey, ct.DeviceId)
train_pc_sim.Default().SendDriverActive(sta.ConnState, sta.VobcState)
} else if ct.ControlType == request_proto.TrainControl_DIRECTION_KEY_SWITCH {
trainControlDirKey(sta, ct.DirKey, ct.DeviceId)
} else if ct.ControlType == request_proto.TrainControl_HANDLER {
oldTraction := sta.VobcState.TractionForce
oldBrakeForce := sta.VobcState.BrakeForce
tce = trainControlHandle(sta, ct.Handler, ct.DeviceId)
train_pc_sim.Default().SendHandleSwitch(oldTraction, oldBrakeForce, sta.ConnState, sta.VobcState)
}
if !sta.ConnState.Conn && sta.ConnState.ConnType != state_proto.TrainConnState_PC_SIM {
slog.Error("当前列车未连接车载pc仿真,", sta.Id)
return
}
train_pc_sim.Default().PublishTrainControlEvent(s.World, tce)
}
func trainControlEB(trainState *state_proto.TrainState, request *request_proto.TrainControl_EmergentButton, deviceId uint32) {
trainState.VobcState.EmergencyBrakingStatus = request.Active
if trainState.Tcc.Ebutton == nil {
trainState.Tcc.Ebutton = &state_proto.TrainControlState_EmergentButton{Id: deviceId, Passed: request.Active}
} else {
trainState.Tcc.Ebutton.Passed = request.Active
}
}
// 列车方向
func trainControlDirKey(trainState *state_proto.TrainState, request *request_proto.TrainControl_DirectionKeySwitch, deviceId uint32) {
trainState.VobcState.DirectionForward = false
trainState.VobcState.DirectionBackward = false
if request.Val == 1 {
trainState.VobcState.DirectionForward = true
} else if request.Val == 0 {
trainState.VobcState.DirectionBackward = false
}
if trainState.Tcc.DirKey == nil {
trainState.Tcc.DirKey = &state_proto.TrainControlState_DirectionKeySwitch{Id: deviceId, Val: request.Val}
} else {
trainState.Tcc.DirKey.Val = request.Val
}
}
// 列车驾驶端激活
func trainControlDriverKey(trainState *state_proto.TrainState, request *request_proto.TrainControl_DriverKeySwitch, deviceId uint32) []train_pc_sim.TrainControlEvent {
if request.Dt == request_proto.DriverType_ONE_END {
trainState.VobcState.Tc1Active = request.Val
} else if request.Dt == request_proto.DriverType_TWO_END {
trainState.VobcState.Tc2Active = request.Val
}
var addNew = true
for _, k := range trainState.Tcc.DriverKey {
if k.Id == deviceId {
k.Id = deviceId
k.Val = request.Val
addNew = false
break
}
}
if addNew {
trainState.Tcc.DriverKey = append(trainState.Tcc.DriverKey, &state_proto.TrainControlState_DriverKeySwitch{Id: deviceId, Val: request.Val})
}
return []train_pc_sim.TrainControlEvent{{Command: train_pc_sim.KEY_STATE, Status: train_pc_sim.IsTrue(request.Val)}}
}
// 列车牵引控制
func trainControlHandle(trainState *state_proto.TrainState, request *request_proto.TrainControl_PushHandler, deviceId uint32) []train_pc_sim.TrainControlEvent {
trainState.VobcState.TractionStatus = false
trainState.VobcState.TractionForce = 0
trainState.VobcState.BrakingStatus = false
trainState.VobcState.BrakeForce = 0
tce := make([]train_pc_sim.TrainControlEvent, 0)
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_FORWORD, Status: 0})
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_BACKWORD, Status: 0})
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_TO_ZERO, Status: 0})
if request.Val > 0 {
trainState.VobcState.TractionStatus = true
trainState.VobcState.TractionForce = int64(request.Val)
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_FORWORD, Status: 1})
} else if request.Val < 0 {
trainState.VobcState.BrakingStatus = true
trainState.VobcState.BrakeForce = int64(request.Val)
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_BACKWORD, Status: 1})
} else {
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_TO_ZERO, Status: 1})
}
if trainState.Tcc.PushHandler == nil {
trainState.Tcc.PushHandler = &state_proto.TrainControlState_PushHandler{Id: deviceId, Val: request.Val}
} else {
trainState.Tcc.PushHandler.Val = request.Val
}
return tce
}
func (s *VerifySimulation) findConnTrain(ct state_proto.TrainConnState_TrainConnType) *state_proto.TrainState {
var findTrain *state_proto.TrainState
s.Memory.Status.TrainStateMap.Range(func(k, v any) bool {
train := v.(*state_proto.TrainState)
connState := train.ConnState
if connState.ConnType == ct {
findTrain = train
return false
}
return true
})
return findTrain
}
// 4.4.1. 车载输出数字量信息报文内容
func (s *VerifySimulation) TrainPcSimDigitalOutInfoHandle(data []byte) {
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
if train == nil {
slog.Error("车载输出数字量未找到连接车载pc仿真的列车")
return
}
if !train.ConnState.Conn {
slog.Error("车载输出数字量,,列车未连接车载pc仿真")
return
}
buf := bytes.NewBuffer(data)
vobc := train.VobcState
cutTraction, _ := buf.ReadByte() //切牵引
trainDoorOutLed, _ := buf.ReadByte() //车门外指示灯
stopBrakeAppend, _ := buf.ReadByte() //停放制动施加
emergentBrake, _ := buf.ReadByte() //紧急制动
leftOpenDoor, _ := buf.ReadByte() //开左门允许
rightOpenDoor, _ := buf.ReadByte() //开右门允许
closeRightDoor, _ := buf.ReadByte() //关右门
doorAlwaysClosed, _ := buf.ReadByte() //车门保持关闭
localAtpControl, _ := buf.ReadByte() //本端ATP控车
atoMode, _ := buf.ReadByte() //ATO模式
atoTractionCommandOut, _ := buf.ReadByte() //ATO牵引命令输出
atoTractionCommand1, _ := buf.ReadByte() //ATO牵引指令1
atoTractionCommand2, _ := buf.ReadByte() //ATO牵引指令2
atoTractionCommand3, _ := buf.ReadByte() //ATO牵引指令3
atoBrakeCommand, _ := buf.ReadByte() //ATO制动命令输出
skipCommand, _ := buf.ReadByte() //跳跃指令
direction1, _ := buf.ReadByte() //列车方向1
direction2, _ := buf.ReadByte() //列车方向2
atoLazyCommandOut, _ := buf.ReadByte() //ATO惰行命令输出
sleepCommand, _ := buf.ReadByte() //休眠指令
wakeUpCommand, _ := buf.ReadByte() //唤醒指令
toPullTrainLed, _ := buf.ReadByte() //ATO发车指示灯
arLightCommand, _ := buf.ReadByte() //AR灯命令
atoAlwaysBrake, _ := buf.ReadByte() //ATO保持制动
atoOpenLeftDoor, _ := buf.ReadByte() //ATO开左门
atoOpenRightDoor, _ := buf.ReadByte() //ATO开右门
atoCloseLeftDoor, _ := buf.ReadByte() //ATO关左门
ariverActive, _ := buf.ReadByte() //驾驶室激活
noSpeedSigle, _ := buf.ReadByte() //零速信号
famMode, _ := buf.ReadByte() //FAM模式
camMode, _ := buf.ReadByte() //CAM模式
trainStartedLed, _ := buf.ReadByte() //列车启动指示灯
mostUseBrake, _ := buf.ReadByte() //常用制动
splittingOut, _ := buf.ReadByte() //过分相输出
modeRelay, _ := buf.ReadByte() //模式继电器
tractionEffective, _ := buf.ReadByte() //牵引有效
brakeEffective, _ := buf.ReadByte() //制动有效
lifeDoorUsed, _ := buf.ReadByte() //逃生门使能
brakeQuarantine, _ := buf.ReadByte() //制动隔离
stopNotAllBrake, _ := buf.ReadByte() //停放制动缓解
vobc.TractionSafetyCircuit = train_pc_sim.IsTrueForByte(cutTraction)
vobc.TrainDoorOutLed = train_pc_sim.IsTrueForByte(trainDoorOutLed) //? 说明暂无此属性
vobc.ParkingBrakeStatus = train_pc_sim.IsTrueForByte(stopBrakeAppend)
vobc.EmergencyBrakingStatus = train_pc_sim.IsTrueForByte(emergentBrake)
vobc.LeftDoorOpenCommand = train_pc_sim.IsTrueForByte(leftOpenDoor)
vobc.RightDoorOpenCommand = train_pc_sim.IsTrueForByte(rightOpenDoor)
vobc.RightDoorCloseCommand = train_pc_sim.IsTrueForByte(closeRightDoor)
vobc.AllDoorClose = train_pc_sim.IsTrueForByte(doorAlwaysClosed)
vobc.LocalAtpControl = train_pc_sim.IsTrueForByte(localAtpControl) //?
vobc.Ato = train_pc_sim.IsTrueForByte(atoMode)
vobc.AtoTractionCommandOut = train_pc_sim.IsTrueForByte(atoTractionCommandOut) //?
vobc.AtoTractionCommand1 = train_pc_sim.IsTrueForByte(atoTractionCommand1) //?
vobc.AtoTractionCommand2 = train_pc_sim.IsTrueForByte(atoTractionCommand2) //?
vobc.AtoTractionCommand3 = train_pc_sim.IsTrueForByte(atoTractionCommand3) //?
vobc.AtoBrakeCommand = train_pc_sim.IsTrueForByte(atoBrakeCommand) //?
vobc.JumpStatus = train_pc_sim.IsTrueForByte(skipCommand)
vobc.DirectionForward = train_pc_sim.IsTrueForByte(direction1)
vobc.DirectionBackward = train_pc_sim.IsTrueForByte(direction2)
vobc.AtoLazyCommandOut = train_pc_sim.IsTrueForByte(atoLazyCommandOut) //?
vobc.SleepBtn = train_pc_sim.IsTrueForByte(sleepCommand)
vobc.WakeUpBtn = train_pc_sim.IsTrueForByte(wakeUpCommand)
vobc.AtoSendTrainBtn = train_pc_sim.IsTrueForByte(toPullTrainLed)
vobc.TurnbackStatus = train_pc_sim.IsTrueForByte(arLightCommand) //?
vobc.AtoAlwaysBrake = train_pc_sim.IsTrueForByte(atoAlwaysBrake) //?
vobc.AtoOpenLeftDoor = train_pc_sim.IsTrueForByte(atoOpenLeftDoor) //?
vobc.AtoOpenRightDoor = train_pc_sim.IsTrueForByte(atoOpenRightDoor) //?
vobc.AtoCloseLeftDoor = train_pc_sim.IsTrueForByte(atoCloseLeftDoor) //?
vobc.Tc1Active = train_pc_sim.IsTrueForByte(ariverActive)
vobc.NoSpeedSigle = train_pc_sim.IsTrueForByte(noSpeedSigle) //?
vobc.Fam = train_pc_sim.IsTrueForByte(famMode)
vobc.Cam = train_pc_sim.IsTrueForByte(camMode)
vobc.TrainStartedLed = train_pc_sim.IsTrueForByte(trainStartedLed) //?
vobc.MostUseBrake = train_pc_sim.IsTrueForByte(mostUseBrake) //? //常用制动
vobc.SplittingOut = train_pc_sim.IsTrueForByte(splittingOut) //? //过分相输出
vobc.ModeRelay = train_pc_sim.IsTrueForByte(modeRelay) //? //模式继电器
vobc.TractionEffective = train_pc_sim.IsTrueForByte(tractionEffective) //? //牵引有效
vobc.BrakeEffective = train_pc_sim.IsTrueForByte(brakeEffective) //? //制动有效
vobc.LifeDoorState = train_pc_sim.IsTrueForByte(lifeDoorUsed) //逃生门使能
vobc.BrakeQuarantine = train_pc_sim.IsTrueForByte(brakeQuarantine) //? //制动隔离
vobc.StopNotAllBrake = train_pc_sim.IsTrueForByte(stopNotAllBrake) //? //停放制动缓解
}
// 4.4.2. 车载输出数字反馈量信息报文内容
func (s *VerifySimulation) TrainPcSimDigitalReportHandle(data []byte) {
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
if train == nil {
slog.Error("车载输出数字反馈量信息,未找到连接车载pc仿真的列车")
return
}
if !train.ConnState.Conn {
slog.Error("车载输出数字反馈量信息,列车未连接车载pc仿真")
return
}
vobc := train.VobcState
buf := bytes.NewBuffer(data)
localEndAct, _ := buf.ReadByte()
direction1, _ := buf.ReadByte()
direction2, _ := buf.ReadByte()
vobc.Tc1Active = train_pc_sim.IsTrueForByte(localEndAct) //本端驾驶室激活(钥匙)
vobc.DirectionForward = train_pc_sim.IsTrueForByte(direction1) //方向手柄进位
vobc.DirectionBackward = train_pc_sim.IsTrueForByte(direction2) //方向手柄退位
}
// 创建/删除列车
func (s *VerifySimulation) TrainPcSimConnOrRemoveHandle(state byte) {
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
if train == nil {
slog.Error("创建删除列车未找到连接车载pc仿真的列车")
return
}
connState := train.ConnState
if state == 0x01 {
connState.Conn = true
} else {
connState.Conn = false
}
}
// 门模式
func (s *VerifySimulation) TrainDoorModeHandle(state byte) {
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
if train == nil {
slog.Error("车载pc仿真门模式未找到连接车载pc仿真的列车")
return
}
if !train.ConnState.Conn {
slog.Error("车载pc仿真门模式,列车未连接车载pc仿真")
return
}
switch state {
case 0x00:
//0x00表示自开自关AA
train.VobcState.DoorModeAA = true
case 0x01:
//0x01表示自开人关AM
train.VobcState.DoorModeAM = true
case 0x02:
//0x02表示人开人关MM
train.VobcState.DoorModeMM = true
}
}
// 4.4.3. 车载输出模拟量信息报文内容(0x03)
func (s *VerifySimulation) TrainPcSimMockInfo(data []byte) {
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
if train == nil {
slog.Error("车载输出模拟量,未找到连接车载pc仿真的列车")
return
}
if !train.ConnState.Conn {
slog.Error("车载输出模拟量,列车未连接车载pc仿真")
return
}
mockData := binary.BigEndian.Uint16(data)
train.VobcState.MockInfo = uint32(mockData)
}
// 4.4.4. 车载输出BTM查询同步帧报文内容0x04
func (s *VerifySimulation) TrainBtmQuery(data []byte) {
if len(data) < 12 {
slog.Error("列车btm查询报文长度错误:", len(data))
return
}
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
if train == nil {
slog.Error("车载输出btm查询,未找到连接车载pc仿真的列车")
return
}
if !train.ConnState.Conn {
slog.Error("车载输出btm查询,列车未连接车载pc仿真")
return
}
trainAtm := message.NewCanetFrame(data, true)
atpReq := &message.AtpRequestFrame{}
if !atpReq.Decode(trainAtm) {
slog.Warn("列车pc驾驶模拟-CanetFrame解码成AtpRequestFrame失败", "CanetFrame", trainAtm.String())
return
}
cl := clock(atpReq)
btmRepFrame := createBtmStatus(trainAtm.CanId.ID4, train.BtmState, atpReq, cl)
if atpReq.ResendRequest == 2 {
//重新发送
if len(train.BtmState.BaliseTelegramForPcSimResend) > 0 {
dd, _ := hex.DecodeString(train.BtmState.BaliseTelegramForPcSimResend)
train_pc_sim.Default().SendBaliseData(train_pc_sim.RECIVE_TRAIN_BTM_HAS_DATA, dd)
}
} else {
timeSyncF := message.NewBtmTimeSyncCheckFrame(trainAtm.CanId.ID4, true)
timeSyncF.T2 = cl.BtmTk
timeSyncF.T3 = cl.TkNow()
telCount := strings.Count(train.BtmState.Telegram, "00")
if telCount >= balise_const.UserTelegramByteLen {
//无数据
queryData := make([]byte, 0)
queryData = append(queryData, btmRepFrame.Encode().Encode()...)
queryData = append(queryData, timeSyncF.Encode().Encode()...)
train_pc_sim.Default().SendBaliseData(train_pc_sim.RECIVE_TRAIN_BTM_NOT_DATA, queryData)
} else {
//有数据
aliseData, _ := hex.DecodeString(train.BtmState.Telegram)
statusDataCf, statusDataCfOk := message.CreateBtmRspFramesData(btmRepFrame, aliseData, false, cl.TkNow(), cl.TkNow(), cl.TkNow(), true)
if statusDataCfOk {
queryData := make([]byte, 0)
queryData = append(queryData, btmRepFrame.Encode().Encode()...)
queryData = append(queryData, timeSyncF.Encode().Encode()...)
queryData = append(queryData, statusDataCf...) //数据帧包含结束帧
train.BtmState.BaliseTelegramForPcSimResend = fmt.Sprintf("%X", statusDataCf)
train_pc_sim.Default().SendBaliseData(train_pc_sim.RECIVE_TRAIN_BTM_HAS_DATA, queryData)
} else {
slog.Error("列车pc仿真 BtmCanetClient应答帧、数据帧编码失败")
}
}
}
}
func createBtmStatus(canIdSn byte, btmState *state_proto.BTMState, atpReq *message.AtpRequestFrame, cl can_btm.BtmClock) *message.BtmStatusRspFrame {
statusF := message.NewBtmStatusRspFrame(canIdSn, true)
//btmStatus := aa(train, atpReq)
statusF.PowerAmplifierOn = true
statusF.PowerAmplifierFailure = false
statusF.AtpReqCrcCheckWrong = !atpReq.Crc16CheckOk
statusF.AntennaFault = false
statusF.BaliseCounter = byte(btmState.BaliseCount)
statusF.MessageCounter = byte(btmState.MessageCounter)
statusF.TkTimeA = cl.TkNow()
statusF.DetailedCode = 0
if btmState.AboveBalise {
statusF.DetailedCode = 0x07
}
statusF.Dsn = byte(btmState.DataSerialNumber)
return statusF
}
func clock(atpReq *message.AtpRequestFrame) can_btm.BtmClock {
now := time.Now()
return can_btm.BtmClock{BtmTk: atpReq.Time, SysTk: now}
}