632 lines
24 KiB
Go
632 lines
24 KiB
Go
package message_server
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"reflect"
|
|
"runtime/debug"
|
|
"strings"
|
|
"time"
|
|
|
|
"joylink.club/bj-rtsts-server/dto/common_proto"
|
|
|
|
"joylink.club/bj-rtsts-server/dto/request_proto"
|
|
"joylink.club/bj-rtsts-server/dto/state_proto"
|
|
"joylink.club/rtsssimulation/repository/model/proto"
|
|
|
|
"joylink.club/bj-rtsts-server/dto/data_proto"
|
|
"joylink.club/bj-rtsts-server/message_server/ms_api"
|
|
"joylink.club/bj-rtsts-server/mqtt"
|
|
appcomponent "joylink.club/bj-rtsts-server/ts/simulation/app_component"
|
|
"joylink.club/bj-rtsts-server/ts/simulation/wayside/memory"
|
|
"joylink.club/ecs"
|
|
"joylink.club/rtsssimulation/component"
|
|
"joylink.club/rtsssimulation/entity"
|
|
)
|
|
|
|
// 信号平面布置图消息服务
|
|
|
|
func NewSfpMs(vs *memory.VerifySimulation, mapId int32) ms_api.MsgTask {
|
|
return ms_api.NewScheduleTask(fmt.Sprintf("信号平面布置图[%d]状态", mapId), func() error {
|
|
turnoutStates, err := collectTurnoutStates(vs, mapId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
signalStates, err := collectSignalStates(vs.World, mapId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
buttonStates, err := collectStationButtonStates(vs.World, mapId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
psdStates, err := collectPsdStates(vs.World, mapId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
sectionStates, err := collectSectionStates(vs.World, mapId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
platformStates, err := collectPlatformStates(vs.World, mapId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
trainState, err := collectTrainStates(vs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
baliseStates, err := collectBaliseStates(vs.World, mapId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ststes := &state_proto.PushedDevicesStatus{
|
|
All: true,
|
|
AllStatus: &state_proto.AllDevicesStatus{
|
|
TrainState: trainState,
|
|
SwitchState: turnoutStates,
|
|
SignalState: signalStates,
|
|
ButtonState: buttonStates,
|
|
PsdState: psdStates,
|
|
SectionState: sectionStates,
|
|
PlatformState: platformStates,
|
|
BaliseState: baliseStates,
|
|
},
|
|
}
|
|
mqtt.GetMsgClient().PubSfpState(vs.SimulationId, mapId, ststes)
|
|
return nil
|
|
}, 200*time.Millisecond)
|
|
}
|
|
|
|
// 收集应答器状态
|
|
func collectBaliseStates(world ecs.World, mapId int32) ([]*state_proto.BaliseState, error) {
|
|
uidStructure := memory.QueryUidStructure[*memory.StationUidStructure](mapId)
|
|
var transponderStates []*state_proto.BaliseState
|
|
for id, structure := range uidStructure.TransponderIds {
|
|
entry, ok := entity.GetEntityByUid(world, structure.Uid)
|
|
if ok {
|
|
baliseFixedTelegram := component.BaliseFixedTelegramType.Get(entry)
|
|
baliseState := &state_proto.BaliseState{
|
|
Id: id,
|
|
FixedTelegram: fmt.Sprintf("%X", baliseFixedTelegram.Telegram),
|
|
FixedUserTelegram: fmt.Sprintf("%X", baliseFixedTelegram.UserTelegram),
|
|
}
|
|
if entry.HasComponent(component.BaliseVariableTelegramType) {
|
|
baliseVariableTelegram := component.BaliseVariableTelegramType.Get(entry)
|
|
baliseState.VariableTelegram = fmt.Sprintf("%X", baliseVariableTelegram.Telegram)
|
|
baliseState.VariableUserTelegram = fmt.Sprintf("%X", baliseVariableTelegram.UserTelegram)
|
|
}
|
|
transponderStates = append(transponderStates, baliseState)
|
|
km := component.KmType.Get(entry)
|
|
baliseState.Km = &data_proto.KilometerSystem{
|
|
Kilometer: km.Value,
|
|
CoordinateSystem: km.CoordinateSystem,
|
|
}
|
|
if km.Direction == proto.Direction_LEFT {
|
|
baliseState.Km.Direction = data_proto.KilometerSystem_LEFT
|
|
} else if km.Direction == proto.Direction_RIGHT {
|
|
baliseState.Km.Direction = data_proto.KilometerSystem_RIGHT
|
|
}
|
|
}
|
|
}
|
|
return transponderStates, nil
|
|
}
|
|
|
|
// 收集屏蔽门状态
|
|
func collectPsdStates(world ecs.World, mapId int32) ([]*state_proto.PsdState, error) {
|
|
uidStructure := memory.QueryUidStructure[*memory.StationUidStructure](mapId)
|
|
data := memory.QueryGiData[*data_proto.RtssGraphicStorage](mapId)
|
|
var psdStateArr []*state_proto.PsdState
|
|
for _, door := range data.ScreenDoors {
|
|
did := memory.GetMapElementId(door.Common)
|
|
uid := uidStructure.PsdIds[did].Uid
|
|
psdEntry, ok := entity.GetEntityByUid(world, uid)
|
|
if ok {
|
|
list := component.AsdListType.Get(psdEntry).List
|
|
asdStates := make([]*state_proto.AsdState, len(list))
|
|
for i, asdEntry := range list {
|
|
asdState := component.AsdStateType.Get(asdEntry)
|
|
asdStates[i] = &state_proto.AsdState{
|
|
Code: int32(i + 1),
|
|
Kmdw: asdState.Kmdw,
|
|
Gmdw: asdState.Gmdw,
|
|
Mgj: asdState.Mgj,
|
|
}
|
|
}
|
|
var param *request_proto.PsdParam
|
|
if psdEntry.HasComponent(appcomponent.PsdParamType) {
|
|
param = appcomponent.PsdParamType.Get(psdEntry)
|
|
} else {
|
|
param = &request_proto.PsdParam{}
|
|
}
|
|
psdStateArr = append(psdStateArr, &state_proto.PsdState{
|
|
Id: did,
|
|
AsdStates: asdStates,
|
|
Mgj: component.PsdStateType.Get(psdEntry).Close,
|
|
Param: param,
|
|
Obstacle: component.PsdStateType.Get(psdEntry).Obstacle,
|
|
})
|
|
}
|
|
}
|
|
return psdStateArr, nil
|
|
}
|
|
|
|
// 收集区段状态
|
|
func collectSectionStates(world ecs.World, mapId int32) ([]*state_proto.SectionState, error) {
|
|
uidMap := memory.QueryMapUidMapByType(mapId, &data_proto.Section{})
|
|
var sectionArr []*state_proto.SectionState
|
|
for _, u := range uidMap {
|
|
s := handlerSectionState(world, u.Uid)
|
|
if s == nil {
|
|
continue
|
|
}
|
|
s.Id = u.CommonId
|
|
sectionArr = append(sectionArr, s)
|
|
}
|
|
return sectionArr, nil
|
|
}
|
|
|
|
func handlerSectionState(w ecs.World, uid string) *state_proto.SectionState {
|
|
entry, ok := entity.GetEntityByUid(w, uid)
|
|
if !ok {
|
|
//fmt.Printf("id=%s的信号机不存在", uid)
|
|
return nil
|
|
}
|
|
if entry.HasComponent(component.PhysicalSectionStateType) { //计轴区段
|
|
sectionState := &state_proto.SectionState{}
|
|
axleState := component.PhysicalSectionStateType.Get(entry)
|
|
sectionState.Occupied = axleState.Occ
|
|
sectionState.AxleFault = entry.HasComponent(component.AxleSectionFaultTag)
|
|
|
|
wd := entity.GetWorldData(w)
|
|
sectionModel := wd.Repo.FindPhysicalSection(uid)
|
|
faDcAxleDeviceEntry := entity.FindAxleManageDevice(wd, sectionModel.CentralizedStation())
|
|
if faDcAxleDeviceEntry != nil {
|
|
faDcAxleDevice := component.AxleManageDeviceType.Get(faDcAxleDeviceEntry)
|
|
axleRuntime := faDcAxleDevice.FindAdr(uid)
|
|
if axleRuntime != nil {
|
|
sectionState.AxleDrst = axleRuntime.Drst
|
|
sectionState.AxlePdrst = axleRuntime.Pdrst
|
|
}
|
|
}
|
|
return sectionState
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 收集车站按钮状态
|
|
func collectStationButtonStates(world ecs.World, mapId int32) ([]*state_proto.ButtonState, error) {
|
|
// 获取地图上的按钮状态
|
|
uidMap := memory.QueryMapUidMapByType(mapId, &data_proto.EsbButton{})
|
|
var btnStateArr []*state_proto.ButtonState
|
|
for _, u := range uidMap {
|
|
entry, ok := entity.GetEntityByUid(world, u.Uid)
|
|
if !ok {
|
|
return nil, fmt.Errorf("ESB按钮实体不存在: World id=%d, uid=%s", world.Id(), u.Uid)
|
|
}
|
|
if entry.HasComponent(component.ButtonTag) { // 按钮
|
|
bit := component.BitStateType.Get(entry)
|
|
btnStateArr = append(btnStateArr, &state_proto.ButtonState{Id: u.CommonId, Down: bit.Val})
|
|
}
|
|
}
|
|
return btnStateArr, nil
|
|
}
|
|
|
|
// 收集信号机状态
|
|
func collectSignalStates(world ecs.World, mapId int32) ([]*state_proto.SignalState, error) {
|
|
uidMap := memory.QueryMapUidMapByType(mapId, &data_proto.Signal{})
|
|
var signalArr []*state_proto.SignalState
|
|
for _, u := range uidMap {
|
|
s, err := handlerSignalState(world, u.Uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s.Id = u.CommonId
|
|
signalArr = append(signalArr, s)
|
|
}
|
|
return signalArr, nil
|
|
}
|
|
|
|
func handlerSignalState(w ecs.World, uid string) (*state_proto.SignalState, error) {
|
|
entry, ok := entity.GetEntityByUid(w, uid)
|
|
if !ok {
|
|
return nil, fmt.Errorf("信号机不存在: World id=%d, 信号机id=%s", w.Id(), uid)
|
|
}
|
|
if !entry.HasComponent(component.SignalLightsType) { //信号机灯列表
|
|
return nil, fmt.Errorf("信号机没有SignalLights组件: World id=%d, 信号机id=%s", w.Id(), uid)
|
|
}
|
|
signalState := &state_proto.SignalState{}
|
|
lights := component.SignalLightsType.Get(entry)
|
|
isL := false
|
|
isH := false
|
|
isU := false
|
|
isA := false
|
|
isB := false
|
|
for _, light := range lights.Lights {
|
|
switch {
|
|
case light.HasComponent(component.LdTag):
|
|
isL = component.BitStateType.Get(light).Val
|
|
case light.HasComponent(component.HdTag):
|
|
isH = component.BitStateType.Get(light).Val
|
|
case light.HasComponent(component.UdTag):
|
|
isU = component.BitStateType.Get(light).Val
|
|
case light.HasComponent(component.BdTag):
|
|
isB = component.BitStateType.Get(light).Val
|
|
case light.HasComponent(component.AdTag):
|
|
isA = component.BitStateType.Get(light).Val
|
|
}
|
|
}
|
|
if isH && isU {
|
|
signalState.Aspect = state_proto.Signal_HU
|
|
} else {
|
|
switch {
|
|
case isL:
|
|
signalState.Aspect = state_proto.Signal_L
|
|
case isH:
|
|
signalState.Aspect = state_proto.Signal_H
|
|
case isU:
|
|
signalState.Aspect = state_proto.Signal_U
|
|
case isB:
|
|
signalState.Aspect = state_proto.Signal_B
|
|
case isA:
|
|
signalState.Aspect = state_proto.Signal_A
|
|
}
|
|
}
|
|
if entry.HasComponent(appcomponent.SignalParamType) {
|
|
signalState.Param = appcomponent.SignalParamType.Get(entry)
|
|
} else {
|
|
signalState.Param = &request_proto.SignalParam{}
|
|
}
|
|
if entry.HasComponent(component.Signal2XH1ElectronicType) { // 2XH1信号机
|
|
signal2XH1 := component.Signal2XH1ElectronicType.Get(entry)
|
|
signalState.RelayStateMap = make(map[string]bool, 3)
|
|
signalState.RelayStateMap["DDJ"] = component.BitStateType.Get(signal2XH1.Z2XH1_DDJ).Val
|
|
signalState.RelayStateMap["LXJ"] = component.BitStateType.Get(signal2XH1.Z2XH1_LXJ).Val
|
|
signalState.RelayStateMap["DJ"] = component.BitStateType.Get(signal2XH1.Z2XH1_DJ).Val
|
|
} else if entry.HasComponent(component.Signal3XH1ElectronicType) { // 3XH1信号机
|
|
signal3XH1 := component.Signal3XH1ElectronicType.Get(entry)
|
|
signalState.RelayStateMap = make(map[string]bool, 6)
|
|
signalState.RelayStateMap["DDJ"] = component.BitStateType.Get(signal3XH1.Z3XH1_DDJ).Val
|
|
signalState.RelayStateMap["ZXJ"] = component.BitStateType.Get(signal3XH1.Z3XH1_ZXJ).Val
|
|
signalState.RelayStateMap["LXJ"] = component.BitStateType.Get(signal3XH1.Z3XH1_LXJ).Val
|
|
signalState.RelayStateMap["YXJ"] = component.BitStateType.Get(signal3XH1.Z3XH1_YXJ).Val
|
|
signalState.RelayStateMap["DJ"] = component.BitStateType.Get(signal3XH1.Z3XH1_DJ).Val
|
|
signalState.RelayStateMap["2DJ"] = component.BitStateType.Get(signal3XH1.Z3XH1_2DJ).Val
|
|
} else if entry.HasComponent(component.Signal3XH2ElectronicType) { // 3XH2信号机
|
|
signal3XH2 := component.Signal3XH2ElectronicType.Get(entry)
|
|
signalState.RelayStateMap = make(map[string]bool, 5)
|
|
signalState.RelayStateMap["DDJ"] = component.BitStateType.Get(signal3XH2.Z3XH2_DDJ).Val
|
|
signalState.RelayStateMap["LXJ"] = component.BitStateType.Get(signal3XH2.Z3XH2_LXJ).Val
|
|
signalState.RelayStateMap["YXJ"] = component.BitStateType.Get(signal3XH2.Z3XH2_YXJ).Val
|
|
signalState.RelayStateMap["DJ"] = component.BitStateType.Get(signal3XH2.Z3XH2_DJ).Val
|
|
signalState.RelayStateMap["2DJ"] = component.BitStateType.Get(signal3XH2.Z3XH2_2DJ).Val
|
|
} else if entry.HasComponent(component.Signal3XH3ElectronicType) { // 3XH3信号机
|
|
signal3XH3 := component.Signal3XH3ElectronicType.Get(entry)
|
|
signalState.RelayStateMap = make(map[string]bool, 5)
|
|
signalState.RelayStateMap["DDJ"] = component.BitStateType.Get(signal3XH3.Z3XH3_DDJ).Val
|
|
signalState.RelayStateMap["LXJ"] = component.BitStateType.Get(signal3XH3.Z3XH3_LXJ).Val
|
|
signalState.RelayStateMap["YXJ"] = component.BitStateType.Get(signal3XH3.Z3XH3_YXJ).Val
|
|
signalState.RelayStateMap["DJ"] = component.BitStateType.Get(signal3XH3.Z3XH3_DJ).Val
|
|
signalState.RelayStateMap["2DJ"] = component.BitStateType.Get(signal3XH3.Z3XH3_2DJ).Val
|
|
} else if entry.HasComponent(component.Signal3XH4ElectronicType) { // 3XH4信号机
|
|
signal3XH4 := component.Signal3XH4ElectronicType.Get(entry)
|
|
signalState.RelayStateMap = make(map[string]bool, 4)
|
|
signalState.RelayStateMap["DDJ"] = component.BitStateType.Get(signal3XH4.Z3XH4_DDJ).Val
|
|
signalState.RelayStateMap["LXJ"] = component.BitStateType.Get(signal3XH4.Z3XH4_LXJ).Val
|
|
signalState.RelayStateMap["ZXJ"] = component.BitStateType.Get(signal3XH4.Z3XH4_ZXJ).Val
|
|
signalState.RelayStateMap["DJ"] = component.BitStateType.Get(signal3XH4.Z3XH4_DJ).Val
|
|
}
|
|
return signalState, nil
|
|
}
|
|
|
|
// 收集列车状态
|
|
func collectTrainStates(vs *memory.VerifySimulation) ([]*state_proto.TrainMapState, error) {
|
|
allTrainMap := &vs.Memory.Status.TrainStateMap
|
|
var trainArr []*state_proto.TrainMapState
|
|
allTrainMap.Range(func(_, v any) bool {
|
|
trainArr = append(trainArr, convertTrainState(v.(*state_proto.TrainState)))
|
|
return true
|
|
})
|
|
return trainArr, nil
|
|
}
|
|
|
|
func convertTrainState(v *state_proto.TrainState) *state_proto.TrainMapState {
|
|
t := &state_proto.TrainMapState{
|
|
Id: v.Id,
|
|
Up: v.Up,
|
|
InitialSpeed: v.Speed,
|
|
TrainLength: v.TrainLength,
|
|
Show: v.Show,
|
|
HeadDeviceId: v.HeadDeviceId,
|
|
HeadOffset: v.HeadOffset,
|
|
DevicePort: v.DevicePort,
|
|
PointTo: v.PointTo,
|
|
RunDirection: v.RunDirection,
|
|
HeadDirection: v.HeadDirection,
|
|
TrainKilometer: v.TrainKilometer,
|
|
ControlDelayTime: v.ControlDelayTime,
|
|
WheelDiameter: v.WheelDiameter,
|
|
// 动力学
|
|
DynamicHeartbeat: v.DynamicState.Heartbeat,
|
|
HeadLinkId: v.DynamicState.HeadLinkId,
|
|
HeadLinkOffset: v.DynamicState.HeadLinkOffset,
|
|
TailLinkId: v.DynamicState.TailLinkId,
|
|
TailLinkOffset: v.DynamicState.TailLinkOffset,
|
|
OccupiedLinkIndex: v.DynamicState.OccupiedLinkIndex,
|
|
Slope: v.DynamicState.Slope,
|
|
Upslope: v.DynamicState.Upslope,
|
|
RunningUp: v.DynamicState.RunningUp,
|
|
RunningResistanceSum: v.DynamicState.RunningResistanceSum,
|
|
AirResistance: v.DynamicState.AirResistance,
|
|
RampResistance: v.DynamicState.RampResistance,
|
|
CurveResistance: v.DynamicState.CurveResistance,
|
|
Speed: v.DynamicState.Speed,
|
|
HeadSensorSpeed1: v.DynamicState.HeadSensorSpeed1,
|
|
HeadSensorSpeed2: v.DynamicState.HeadSensorSpeed2,
|
|
TailSensorSpeed1: v.DynamicState.TailSensorSpeed1,
|
|
TailSensorSpeed2: v.DynamicState.TailSensorSpeed2,
|
|
HeadRadarSpeed: v.DynamicState.HeadRadarSpeed,
|
|
TailRadarSpeed: v.DynamicState.TailRadarSpeed,
|
|
DynamicInterruption: v.DynamicState.UdpInterruption,
|
|
Acceleration: v.DynamicState.Acceleration,
|
|
Displacement: v.DynamicState.Displacement,
|
|
// 半实物
|
|
VobcLifeSignal: v.VobcState.LifeSignal,
|
|
Tc1Active: v.VobcState.Tc1Active,
|
|
Tc2Active: v.VobcState.Tc2Active,
|
|
DirectionForward: v.VobcState.DirectionForward,
|
|
DirectionBackward: v.VobcState.DirectionBackward,
|
|
TractionStatus: v.VobcState.TractionStatus,
|
|
BrakingStatus: v.VobcState.BrakingStatus,
|
|
EmergencyBrakingStatus: v.VobcState.EmergencyBrakingStatus,
|
|
TurnbackStatus: v.VobcState.TurnbackStatus,
|
|
JumpStatus: v.VobcState.JumpStatus,
|
|
Ato: v.VobcState.Ato,
|
|
Fam: v.VobcState.Fam,
|
|
Cam: v.VobcState.Cam,
|
|
TractionSafetyCircuit: v.VobcState.TractionSafetyCircuit,
|
|
ParkingBrakeStatus: v.VobcState.ParkingBrakeStatus,
|
|
MaintainBrakeStatus: v.VobcState.MaintainBrakeStatus,
|
|
TractionForce: v.VobcState.TractionForce,
|
|
BrakeForce: v.VobcState.BrakeForce,
|
|
TrainLoad: v.VobcState.TrainLoad,
|
|
LeftDoorOpenCommand: v.VobcState.LeftDoorOpenCommand,
|
|
RightDoorOpenCommand: v.VobcState.RightDoorOpenCommand,
|
|
LeftDoorCloseCommand: v.VobcState.LeftDoorCloseCommand,
|
|
RightDoorCloseCommand: v.VobcState.RightDoorCloseCommand,
|
|
AllDoorClose: v.VobcState.AllDoorClose,
|
|
VobcInterruption: v.VobcState.UdpInterruption,
|
|
TrainEndsA: convertEnds(v.TrainEndsA),
|
|
TrainEndsB: convertEnds(v.TrainEndsB),
|
|
}
|
|
trainConfig := &state_proto.TrainDynamicConfigMqtt{}
|
|
convertDynamicConfig(v.TrainDynamicConfig, trainConfig)
|
|
t.TrainDynamicConfig = trainConfig
|
|
return t
|
|
}
|
|
|
|
func convertDynamicConfig(config *common_proto.TrainDynamicConfig, dest *state_proto.TrainDynamicConfigMqtt) {
|
|
configType := reflect.TypeOf(config).Elem()
|
|
for index := 0; index < configType.NumField(); index++ {
|
|
field := configType.Field(index)
|
|
if field.IsExported() {
|
|
fieldName := field.Name
|
|
setVal(config, dest, fieldName)
|
|
}
|
|
}
|
|
}
|
|
|
|
func setVal(source, dest interface{}, fieldName string) {
|
|
destVal := reflect.ValueOf(dest).Elem().FieldByName(fieldName)
|
|
sourceType := reflect.ValueOf(source).Elem().FieldByName(fieldName)
|
|
sourceData := sourceType.Interface()
|
|
defer func() {
|
|
err := recover()
|
|
if err != nil {
|
|
slog.Error(fieldName, "赋值失败,源数据类型", sourceType.Kind().String(), "目标数据类型:", destVal.Kind().String(), " 异常错误提示:", err)
|
|
debug.PrintStack()
|
|
}
|
|
}()
|
|
|
|
if destVal.Kind() == reflect.String {
|
|
destVal.Set(reflect.ValueOf(fmt.Sprintf("%v", sourceData)))
|
|
} else {
|
|
destVal.Set(reflect.ValueOf(sourceData))
|
|
}
|
|
}
|
|
|
|
func convertEnds(ends *common_proto.TrainEndsState) *state_proto.TrainEndsStateMqtt {
|
|
return &state_proto.TrainEndsStateMqtt{SpeedSensorEnableA: ends.SpeedSensorEnableA,
|
|
SpeedSensorEnableB: ends.SpeedSensorEnableB,
|
|
RadarEnable: ends.RadarEnable,
|
|
RadarCheckSpeedDiff: floatToString(ends.RadarCheckSpeedDiff),
|
|
RadarCheckTime: ends.RadarCheckTime,
|
|
AccEnable: ends.AccEnable,
|
|
AccCheckSpeedDiff: floatToString(ends.AccCheckSpeedDiff),
|
|
AccCheckTime: ends.AccCheckTime,
|
|
}
|
|
|
|
}
|
|
func floatToString(f float32) string {
|
|
return fmt.Sprintf("%v", f)
|
|
}
|
|
|
|
// 收集道岔状态
|
|
func collectTurnoutStates(sim *memory.VerifySimulation, mapId int32) ([]*state_proto.SwitchState, error) {
|
|
uidMap := memory.QueryMapUidMapByType(mapId, &data_proto.Turnout{})
|
|
wd := entity.GetWorldData(sim.World)
|
|
var switchArr []*state_proto.SwitchState
|
|
for _, u := range uidMap {
|
|
entry, ok := entity.GetEntityByUid(sim.World, u.Uid)
|
|
if !ok {
|
|
return nil, fmt.Errorf("道岔不存在: World id=%d,道岔id=%s", sim.World.Id(), u.Uid)
|
|
}
|
|
if !entry.HasComponent(component.TurnoutPositionType) {
|
|
return nil, fmt.Errorf("道岔没有TurnoutPosition组件: World id=%d,道岔id=%s", sim.World.Id(), u.Uid)
|
|
}
|
|
pos := component.TurnoutPositionType.Get(entry)
|
|
s := &state_proto.SwitchState{
|
|
Id: u.CommonId,
|
|
Normal: pos.Db,
|
|
Reverse: pos.Fb,
|
|
Dw: pos.Dw,
|
|
Fw: pos.Fw,
|
|
}
|
|
if entry.HasComponent(appcomponent.PointsParamType) {
|
|
s.Param = appcomponent.PointsParamType.Get(entry)
|
|
} else {
|
|
s.Param = &request_proto.PointsParam{}
|
|
}
|
|
// // 强制(联锁驱动无效)
|
|
// s.Force = entry.HasComponent(component.TurnoutFaultCiqdType)
|
|
// // 失表
|
|
// s.Sb = entry.HasComponent(component.TurnoutFaultSbType)
|
|
// // 定位失表
|
|
// s.Dwsb = entry.HasComponent(component.TurnoutFaultDwsbType)
|
|
// // 反位失表
|
|
// s.Fwsb = entry.HasComponent(component.TurnoutFaultFwsbType)
|
|
// jc := false
|
|
// zzj := component.TurnoutZzjType.Get(entry)
|
|
// for _, e := range zzj.ZzjList {
|
|
// if e.HasComponent(component.TurnoutFaultJcType) {
|
|
// jc = true
|
|
// break
|
|
// }
|
|
// }
|
|
// // 挤岔
|
|
// s.Jc = jc
|
|
if entry.HasComponent(component.Zdj9TwoElectronicType) {
|
|
elec := component.Zdj9TwoElectronicType.Get(entry)
|
|
dcj := component.BitStateType.Get(elec.TDC_DCJ)
|
|
s.Dc = dcj.Val
|
|
qdc, err := wd.QueryQdBit(component.UidType.Get(elec.TDC_DCJ).Id)
|
|
if err == nil {
|
|
s.Qdc = qdc
|
|
}
|
|
fcj := component.BitStateType.Get(elec.TDC_FCJ)
|
|
s.Fc = fcj.Val
|
|
qfc, err := wd.QueryQdBit(component.UidType.Get(elec.TDC_FCJ).Id)
|
|
if err == nil {
|
|
s.Qfc = qfc
|
|
}
|
|
ycj := component.BitStateType.Get(elec.TDC_YCJ)
|
|
s.Yc = ycj.Val
|
|
qyc, err := wd.QueryQdBit(component.UidType.Get(elec.TDC_YCJ).Id)
|
|
if err == nil {
|
|
s.Qyc = qyc
|
|
}
|
|
}
|
|
// 查看道岔是否被占用
|
|
turnout := sim.Repo.FindTurnout(u.Uid)
|
|
if turnout == nil {
|
|
return nil, fmt.Errorf("道岔不存在: World id=%d,道岔id=%s", sim.World.Id(), u.Uid)
|
|
}
|
|
if turnout.GetPhysicalSection() == nil {
|
|
return nil, fmt.Errorf("道岔关联的物理区段不存在: World id=%d,道岔id=%s", sim.World.Id(), u.Uid)
|
|
}
|
|
sectionState := handlerSectionState(sim.World, turnout.GetPhysicalSection().Id())
|
|
s.Occupied = sectionState.Occupied
|
|
switchArr = append(switchArr, s)
|
|
}
|
|
return switchArr, nil
|
|
}
|
|
|
|
// 收集站台状态
|
|
func collectPlatformStates(world ecs.World, mapId int32) ([]*state_proto.PlatformState, error) {
|
|
var states []*state_proto.PlatformState
|
|
mapData := memory.QueryGiData[*data_proto.RtssGraphicStorage](mapId)
|
|
uidsMap := memory.QueryUidStructure[*memory.StationUidStructure](mapId)
|
|
platformScreenDoorMap := wrapScreenDoorToPlatform(mapData)
|
|
for _, platform := range mapData.Platforms {
|
|
pid := memory.GetMapElementId(platform.Common)
|
|
stationCommonId := platform.RefStationId
|
|
if stationCommonId == 0 {
|
|
return nil, fmt.Errorf("站台没有绑定车站:id=%v", pid)
|
|
}
|
|
uidInfo := uidsMap.StationIds[stationCommonId]
|
|
if uidInfo == nil {
|
|
return nil, fmt.Errorf("车站实体不存在uid映射:id=%v", stationCommonId)
|
|
}
|
|
entry, ok := entity.GetEntityByUid(world, uidInfo.Uid)
|
|
if !ok {
|
|
return nil, fmt.Errorf("车站实体不存在: World id=%d, uid=%s", world.Id(), uidInfo.Uid)
|
|
}
|
|
sta := &state_proto.PlatformState{Id: pid}
|
|
isX := strings.Contains(platform.Code, "下行站台") //下行站台
|
|
if entry.HasComponent(component.EmpElectronicType) { // 紧急停车继电器
|
|
empElectronic := component.EmpElectronicType.Get(entry)
|
|
deviceElectronic := empElectronic.EMPJMap[platform.GetRefEsbRelayCode()]
|
|
if deviceElectronic != nil {
|
|
sta.Empj = getRelayXqVal(deviceElectronic.EMPJ)
|
|
}
|
|
}
|
|
if entry.HasComponent(component.SpkElectronicType) { // SPKS继电器
|
|
spkElectronic := component.SpkElectronicType.Get(entry)
|
|
if isX {
|
|
if spkElectronic.SPKSXPLAJ != nil {
|
|
sta.SpksState = append(sta.SpksState, &state_proto.ReplyState{Code: "SPKSX旁路", Xh: getRelayXqVal(spkElectronic.SPKSXPLAJ)})
|
|
}
|
|
if spkElectronic.SPKSX1J != nil {
|
|
sta.SpksState = append(sta.SpksState, &state_proto.ReplyState{Code: "SPKS1", Xh: getRelayXqVal(spkElectronic.SPKSX1J)})
|
|
}
|
|
if spkElectronic.SPKSX3J != nil {
|
|
sta.SpksState = append(sta.SpksState, &state_proto.ReplyState{Code: "SPKS3", Xh: getRelayXqVal(spkElectronic.SPKSX3J)})
|
|
}
|
|
} else {
|
|
if spkElectronic.SPKSSPLAJ != nil {
|
|
sta.SpksState = append(sta.SpksState, &state_proto.ReplyState{Code: "SPKSS旁路", Xh: getRelayXqVal(spkElectronic.SPKSSPLAJ)})
|
|
}
|
|
if spkElectronic.SPKSS2J != nil {
|
|
sta.SpksState = append(sta.SpksState, &state_proto.ReplyState{Code: "SPKS2", Xh: getRelayXqVal(spkElectronic.SPKSS2J)})
|
|
}
|
|
if spkElectronic.SPKSS4J != nil {
|
|
sta.SpksState = append(sta.SpksState, &state_proto.ReplyState{Code: "SPKS4", Xh: getRelayXqVal(spkElectronic.SPKSS4J)})
|
|
}
|
|
}
|
|
}
|
|
psdId := platformScreenDoorMap[pid]
|
|
if psdId != 0 {
|
|
psdUid, ok := uidsMap.PsdIds[psdId]
|
|
if !ok {
|
|
continue
|
|
}
|
|
psdEntry, ok := entity.GetEntityByUid(world, psdUid.Uid)
|
|
if !ok {
|
|
return nil, fmt.Errorf("屏蔽门实体不存在: World id=%d, uid=%s", world.Id(), psdUid.Uid)
|
|
}
|
|
if psdEntry.HasComponent(component.PlatformMkxCircuitType) {
|
|
mkxCircuit := component.PlatformMkxCircuitType.Get(psdEntry)
|
|
mkxj := &state_proto.MkxJState{Code: psdUid.Code}
|
|
if mkxCircuit.PABJ != nil {
|
|
mkxj.ReplyState = append(mkxj.ReplyState, &state_proto.ReplyState{Code: "站台确认继电器", Xh: getRelayXqVal(mkxCircuit.PABJ)})
|
|
}
|
|
if mkxCircuit.PCBJ != nil {
|
|
mkxj.ReplyState = append(mkxj.ReplyState, &state_proto.ReplyState{Code: "站台关门继电器", Xh: getRelayXqVal(mkxCircuit.PCBJ)})
|
|
}
|
|
if mkxCircuit.POBJ != nil {
|
|
mkxj.ReplyState = append(mkxj.ReplyState, &state_proto.ReplyState{Code: "站台开门继电器", Xh: getRelayXqVal(mkxCircuit.POBJ)})
|
|
}
|
|
sta.MkxJState = mkxj
|
|
}
|
|
|
|
}
|
|
states = append(states, sta)
|
|
}
|
|
return states, nil
|
|
}
|
|
|
|
// 将屏蔽门关联到站台
|
|
func wrapScreenDoorToPlatform(mapData *data_proto.RtssGraphicStorage) map[uint32]uint32 {
|
|
platformMap := make(map[uint32]uint32, len(mapData.Platforms))
|
|
for _, s := range mapData.ScreenDoors {
|
|
platformMap[s.RefPlatformId] = memory.GetMapElementId(s.Common)
|
|
}
|
|
return platformMap
|
|
}
|
|
|
|
// 获取继电器吸起状态
|
|
func getRelayXqVal(entry *ecs.Entry) bool {
|
|
relay := component.BitStateType.Get(entry)
|
|
return relay.Val
|
|
}
|