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} }