package memory import ( "encoding/hex" "encoding/json" "fmt" "log/slog" "math" "sort" "strconv" "strings" "sync" "joylink.club/bj-rtsts-server/config" "joylink.club/bj-rtsts-server/dto" "joylink.club/bj-rtsts-server/dto/data_proto" "joylink.club/bj-rtsts-server/dto/state_proto" "joylink.club/bj-rtsts-server/sys_error" "joylink.club/bj-rtsts-server/third_party/electrical_machinery" "joylink.club/bj-rtsts-server/third_party/message" "joylink.club/bj-rtsts-server/third_party/semi_physical_train" "joylink.club/ecs" "joylink.club/rtsssimulation/component" "joylink.club/rtsssimulation/entity" "joylink.club/rtsssimulation/fi" "joylink.club/rtsssimulation/repository" "joylink.club/rtsssimulation/repository/model/proto" ) // 轨旁仿真定义 type VerifySimulation struct { //地图id MapIds []int32 // 项目ID ProjectId int32 //仿真id SimulationId string //仿真内存数据 Memory *WaysideMemory //模型仓库 Repo *repository.Repository //Rtss仿真世界的 World ecs.World //设备UID映射 key-uid UidMap map[string]*elementIdStructure // 运行环境配置 runConfig *config.ThridPartyConfig } // 轨旁仿真内存模型 type WaysideMemory struct { //可变状态数据:轨旁仿真模型状态(全量数据) Status *VerifyStatus // 要变更的状态:用户操作过的状态记录在这里,增量推送次数据 ChangeStatus *ChangeVerifyStatus //状态保护锁 rwLock *sync.RWMutex } // 轨旁仿真模型状态 type VerifyStatus struct { //道岔状态,key为道岔id即索引 state_proto.SwitchState SwitchStateMap sync.Map //轨道状态,key为轨道id即索引 state_proto.LinkState LinkStateMap sync.Map //列车状态,key为列车id即索引 state_proto.TrainState TrainStateMap sync.Map //计轴区段状态,key为计轴区段的id即索引 state_proto.SectionState AxleSectionStateMap sync.Map //物理区段状态,key为物理区段id即索引 state_proto.SectionState PhysicalSectionStateMap sync.Map //逻辑区段状态,key为逻辑区段id即索引 state_proto.SectionState LogicSectionStateMap sync.Map //信号机状态,key为信号机id,即索引 state_proto.SignalState SignalStateMap sync.Map } // 轨旁仿真模型状态(变更) type ChangeVerifyStatus struct { VerifyStatus //删除的列车ID列表 RemoveTrainId []string } func NewWaysideMemory() *WaysideMemory { return &WaysideMemory{ Status: &VerifyStatus{}, ChangeStatus: &ChangeVerifyStatus{}, rwLock: &sync.RWMutex{}, } } // 创建仿真对象 func CreateSimulation(projectId int32, mapIds []int32, runConfig *dto.ProjectRunConfigDto) (*VerifySimulation, error) { // 地图信息 sort.Slice(mapIds, func(i, j int) bool { return QueryGiType(mapIds[i]) < QueryGiType(mapIds[j]) }) verifySimulation := &VerifySimulation{ ProjectId: projectId, MapIds: mapIds, } // 设置运行环境 err := verifySimulation.initRunConfig(runConfig) if err != nil { return nil, err } // 构建Repository err = verifySimulation.initRepository() if err != nil { return nil, err } return verifySimulation, nil } // // 启动 // func (s *VerifySimulation) Start() { // s.runState = state_proto.SimulationStatus_START // } // // 销毁 // func (s *VerifySimulation) Destroy() { // s.runState = state_proto.SimulationStatus_DESTROY // } // // 暂停 // func (s *VerifySimulation) Pause() { // s.runState = state_proto.SimulationStatus_PAUSE // } // // 获取状态 // func (s *VerifySimulation) GetRunState() state_proto.SimulationStatus_SimulationState { // return s.runState // } // 获取仿真世界信息 func (s *VerifySimulation) GetComIdByUid(uid string) uint32 { es := s.UidMap if es == nil { panic(&dto.ErrorDto{Code: dto.DataNotExist, Message: "无映射信息"}) } if es[uid] == nil { panic(&dto.ErrorDto{Code: dto.DataNotExist, Message: "无【uid】映射信息"}) } return es[uid].CommonId } // GetBtmCanetConfig 获取CANET配置信息 func (s *VerifySimulation) GetBtmCanetConfig() config.BtmCanetConfig { return s.runConfig.BtmCanet } func (s *VerifySimulation) GetLineAllRsspAxleCfgs() []config.RsspAxleConfig { return s.runConfig.RsspAxleCfgs } // GetSectionCodePoints 获取集中站的区段码表 func (s *VerifySimulation) GetSectionCodePoints(city string, lineId string, centralizedStation string) []*proto.CiSectionCodePoint { stationUid := GenerateElementUid(city, lineId, nil, centralizedStation) ref := s.Repo.GetCentralizedStationRef(stationUid) if ref == nil { return nil } // return ref.SectionCodePoints } // CollectSectionStatus 收集仿真中计轴区段状态 func (s *VerifySimulation) CollectSectionStatus(city string, lineId string, centralizedStation string) ([]*message.SectionStatusMsg, error) { stationUid := GenerateElementUid(city, lineId, nil, centralizedStation) // codePoints := s.GetSectionCodePoints(city, lineId, centralizedStation) if len(codePoints) <= 0 { return nil, fmt.Errorf("没有找到GetCentralizedStationRef[%s]的区段码表为空", stationUid) } //slog.Debug("收集计轴区段状态", "区段码表len", len(codePoints)) // var msg []*message.SectionStatusMsg var axleSectionIds []string for _, section := range codePoints { axleSectionIds = append(axleSectionIds, section.SectionId) } // //slog.Debug("收集计轴区段状态", "计轴区段len", len(axleSectionIds), "axleSectionIds", axleSectionIds) as, e := fi.FindAxleSectionsStatus(s.World, axleSectionIds) if e != nil { //从仿真中收集计轴区段状态的失败列表 return nil, e } //slog.Debug("收集计轴区段状态", "仿真中计轴状态len", len(as)) // stateMap := make(map[string]*fi.AxleSectionState) for _, a := range as { stateMap[a.Id] = a } // sort.SliceStable(codePoints, func(i, j int) bool { return codePoints[i].Row < codePoints[j].Row }) // for _, codePoint := range codePoints { sectionState, find := stateMap[codePoint.SectionId] if find { state_proto := &message.SectionStatusMsg{} state_proto.Rac = sectionState.Rac state_proto.Rjt = sectionState.Rjt state_proto.Rjo = sectionState.Rjo state_proto.Occ = sectionState.Occ state_proto.Clr = sectionState.Clr msg = append(msg, state_proto) } else { return nil, fmt.Errorf("仿真中没有对应区段[%s]的状态", codePoint.SectionId) } } // //slog.Debug("收集计轴区段状态", "区段计轴msgLen", len(msg)) return msg, nil } // 采集动力学道岔状态 func (s *VerifySimulation) CollectDynamicsTurnoutInfo() *message.DynamicsTurnoutInfo { turnoutState := &message.DynamicsTurnoutInfo{} for _, turnout := range s.Repo.TurnoutList() { sta := s.UidMap[turnout.Id()] if sta == nil { continue } entry, ok := entity.GetEntityByUid(s.World, turnout.Id()) if !ok { slog.Warn(fmt.Sprintf("id=%s的道岔不存在", turnout.Id())) return nil } if !entry.HasComponent(component.TurnoutPositionType) { return nil } pos := component.TurnoutPositionType.Get(entry) turnoutState.TurnoutInfos = append(turnoutState.TurnoutInfos, &message.TurnoutInfo{ Code: uint16(sta.CommonId), NPosition: pos.Dw, RPosition: pos.Fw, }) } return turnoutState } // HandleSectionCmdMsg 计轴设备接收到联锁发送来的控制命令 func (s *VerifySimulation) HandleSectionCmdMsg(city string, lineId string, centralizedStation string, msg *message.SectionCmdMsgPack) { stationUid := GenerateElementUid(city, lineId, nil, centralizedStation) ref := s.Repo.GetCentralizedStationRef(stationUid) if ref == nil { slog.Warn(fmt.Sprintf("没有找到GetCentralizedStationRef [%s]", stationUid)) return } // codePoints := ref.SectionCodePoints if len(codePoints) != len(msg.Scs) { slog.Warn(fmt.Sprintf("本地配置区段码表个数[%d] != 联锁发送集中站[%s]的区段命令个数[%d]", len(codePoints), stationUid, len(msg.Scs))) return } // var cpSectionMap = make(map[int]*proto.CiSectionCodePoint) for _, cp := range codePoints { cpSectionMap[int(cp.Row)] = cp } // var cmds []*fi.AxleSectionCmd for index, cmdMsg := range msg.Scs { cp := cpSectionMap[index] cmd := &fi.AxleSectionCmd{} cmd.SectionId = cp.SectionId cmd.Drst = cmdMsg.Drst cmd.Pdrst = cmdMsg.Pdrst cmds = append(cmds, cmd) } fi.AxleSectionRstDrive(s.World, cmds) } // 处理动力学列车速度消息 func (s *VerifySimulation) HandleDynamicsTrainInfo(info *message.DynamicsTrainInfo) { trainId := strconv.Itoa(int(info.Number)) t, ok := s.Memory.Status.TrainStateMap.Load(trainId) if !ok { return } train := t.(*state_proto.TrainState) if train.ConnState.Conn && train.ConnState.ConnType == state_proto.TrainConnState_VOBC { semi_physical_train.Default().SendTrainControlMessage(info) } // 更新列车状态 trainState := UpdateTrainStateByDynamics(s, trainId, info) // 更新电机转速 electrical_machinery.Default().SendElectricMachineryMessage(&message.ElectricMachinery{ Speed: info.Speed, WheelDiameter: trainState.WheelDiameter, IsBack: trainState.VobcState.DirectionBackward, }) } // 获取动力学配置信息 func (s *VerifySimulation) GetDynamicsRunConfig() *config.DynamicsConfig { return &s.runConfig.Dynamics } func (s *VerifySimulation) GetCidcModbusConfig() []config.CidcModbusConfig { return s.runConfig.CidcModbus } // 获取动力学运行资源 func (s *VerifySimulation) GetDynamicsRunRepository() *message.LineBaseInfo { info := &message.LineBaseInfo{} for _, model := range s.Repo.LinkList() { id, _ := strconv.Atoi(model.Id()) link := &message.Link{ ID: int32(id), Len: int32(model.Length()), } info.LinkList = append(info.LinkList, link) if model.ARelation() != nil { turnoutId := s.GetComIdByUid(model.ARelation().Device().Id()) link.ARelTurnoutId = int32(turnoutId) switch model.ARelation().Port() { case proto.Port_A: link.ARelTurnoutPoint = "A" case proto.Port_B: link.ARelTurnoutPoint = "B" case proto.Port_C: link.ARelTurnoutPoint = "C" } } if model.BRelation() != nil { turnoutId := s.GetComIdByUid(model.BRelation().Device().Id()) link.BRelTurnoutId = int32(turnoutId) switch model.BRelation().Port() { case proto.Port_A: link.BRelTurnoutPoint = "A" case proto.Port_B: link.BRelTurnoutPoint = "B" case proto.Port_C: link.BRelTurnoutPoint = "C" } } } for _, model := range s.Repo.SlopeList() { id := s.GetComIdByUid(model.Id()) slope := &message.Slope{ ID: int32(id), StartLinkOffset: int32(model.StartLinkPosition().Offset()), EndLinkOffset: int32(model.EndLinkPosition().Offset()), DegreeTrig: model.Degree(), } info.SlopeList = append(info.SlopeList, slope) startLinkId, _ := strconv.Atoi(model.StartLinkPosition().Link().Id()) slope.StartLinkId = int32(startLinkId) endLinkId, _ := strconv.Atoi(model.EndLinkPosition().Link().Id()) slope.EndLinkId = int32(endLinkId) } for _, model := range s.Repo.SectionalCurvatureList() { id := s.GetComIdByUid(model.Id()) curve := &message.Curve{ ID: int32(id), StartLinkOffset: int32(model.StartLinkPosition().Offset()), EndLinkOffset: int32(model.EndLinkPosition().Offset()), Curvature: model.Radius(), } info.CurveList = append(info.CurveList, curve) startLinkId, _ := strconv.Atoi(model.StartLinkPosition().Link().Id()) curve.StartLinkId = int32(startLinkId) endLinkId, _ := strconv.Atoi(model.EndLinkPosition().Link().Id()) curve.EndLinkId = int32(endLinkId) } return info } // 发送给前端的速度格式化 func speedParse(speed float32) int32 { return int32(math.Abs(float64(speed * 3.6 * 100))) } // 处理半实物仿真列车控制消息 func (s *VerifySimulation) HandleSemiPhysicalTrainControlMsg(b []byte) { s.Memory.Status.TrainStateMap.Range(func(_, value any) bool { train := value.(*state_proto.TrainState) if !train.Show { // 下线列车 return true } connState := train.ConnState if connState.Conn == true && connState.ConnType == state_proto.TrainConnState_VOBC { /*trainId, err := strconv.Atoi(train.Id) if err != nil { panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()}) }*/ // 存放至列车中 //接收半实物列车控制不单独发送动力学,由动力学统一发送 //d := append(b, uint8(trainId)) //dynamics.Default().SendTrainControlMessage(d) controlMessage := &message.TrainControlMsg{} controlMessage.Decode(b) controlMessage.TrainId = train.Id controlMessage.FromVobc = true train.VobcState = controlMessage.ControlInfo return false } return true }) } func (s *VerifySimulation) CollectTrainControlState() []message.TrainControlMsg { cms := make([]message.TrainControlMsg, 0) s.Memory.Status.TrainStateMap.Range(func(_, value any) bool { train := value.(*state_proto.TrainState) if !train.Show { // 下线列车 return true } vobc := false if train.ConnState.Conn == true && train.ConnState.ConnType == state_proto.TrainConnState_VOBC { vobc = true } cms = append(cms, message.TrainControlMsg{ControlInfo: train.VobcState, TrainId: train.Id, FromVobc: vobc}) return true }) return cms } // 获取半实物运行配置信息 func (s *VerifySimulation) GetSemiPhysicalRunConfig() *config.VobcConfig { return &s.runConfig.Vobc } // 获取所有联锁配置唯一Code func (s *VerifySimulation) GetInterlockCodes() []*config.InterlockConfig { stationMap := make(map[string]string) for _, station := range s.Repo.StationList() { stationMap[station.GetCode()] = station.Id() } var configs []*config.InterlockConfig for _, c := range s.runConfig.Interlocks { if stationMap[c.Code] == "" || !c.Open { continue } configs = append(configs, &config.InterlockConfig{ Code: stationMap[c.Code], Ip: c.Ip, LocalPort: c.LocalPort, RemotePort: c.RemotePort, Open: c.Open, }) } return configs } // 处理接到的联锁消息 func (s *VerifySimulation) HandleInterlockDriverInfo(code string, b []byte) { for _, m := range s.Repo.CiQcList() { // 获取继电器地图信息 if m.StationId != code { continue } driverMsg := message.NewInterlockReceiveMsgPkg(0, len(m.QdList), len(m.TransponderId)) driverMsg.Decode(b) driveState := driverMsg.DriveInfo for i, r := range m.QdList { ds := driveState[i] for _, b := range r.RefRelays { slog.Debug("继电器位【%s】获取到驱动状态【%v】", b, ds) } } return } } // 采集联锁中的继电器消息 func (s *VerifySimulation) CollectInterlockRelayInfo(code string) *message.InterlockSendMsgPkg { for _, m := range s.Repo.CiQcList() { // 获取继电器地图信息 if m.StationId != code { continue } if len(m.CjList) == 0 { return nil } collectInfo := make([]bool, len(m.CjList)) for i, l := range m.CjList { if l == nil || len(l.RefRelays) == 0 { continue } rs := true for _, j := range l.RefRelays { if j.Q { rs = rs && CollectXQCircuitState(s.World, j.RelayId) } else { rs = rs && CollectLXCircuitState(s.World, j.RelayId) } if !rs { break } } collectInfo[i] = rs } return message.NewInterlockSendMsgPkg(collectInfo) } return nil } func (s *VerifySimulation) FindTrainConnTypes() []dto.TrainConnTypeConfigDto { typeConfig := make([]dto.TrainConnTypeConfigDto, 0) if s.runConfig.Vobc.Open /*&& s.runConfig.Vobc.Ip != ""*/ { typeConfig = append(typeConfig, dto.TrainConnTypeConfigDto{ConnType: state_proto.TrainConnState_VOBC}) } if s.runConfig.PcSimConfig.Open /*&& s.runConfig.PcSimConfig.PcSimIp != ""*/ { typeConfig = append(typeConfig, dto.TrainConnTypeConfigDto{ConnType: state_proto.TrainConnState_PC_SIM}) } return typeConfig } // 获取电机转速参数 func (s *VerifySimulation) GetElectricMachineryRunConfig() *config.ElectricMachineryConfig { return &s.runConfig.ElectricMachinery } // 初始化仿真运行配置 func (s *VerifySimulation) initRunConfig(runConfig *dto.ProjectRunConfigDto) error { if runConfig == nil || runConfig.ConfigContent == "" { return nil } var configMap config.ThridPartyConfig err := json.Unmarshal([]byte(runConfig.ConfigContent), &configMap) if err != nil { return sys_error.New("配置信息格式错误", err) } s.runConfig = &configMap s.runConfig.Id = runConfig.Id return nil } // 获取仿真运行参数ID func (s *VerifySimulation) GetRunConfigId() int32 { if s.runConfig == nil { return 0 } return s.runConfig.Id } func (s *VerifySimulation) EvnWorld() ecs.World { return s.World } // 初始化运行资源 func (s *VerifySimulation) initRepository() error { // 构建Repository var mapIdStrSlice []string var mapVersion []string for _, id := range s.MapIds { mapIdStrSlice = append(mapIdStrSlice, strconv.Itoa(int(id))) mapVersion = append(mapVersion, strconv.Itoa(int(QueryGiVersion(id)))) } repoId := strings.Join(mapIdStrSlice, "|") repoVersion := strings.Join(mapVersion, ".") repo := repository.FindRepository(repoId, repoVersion) if repo == nil { protoRepo, err := buildProtoRepository(s.MapIds) if err != nil { return sys_error.New("数据错误", err) } protoRepo.Id, protoRepo.Version = repoId, repoVersion newRepo, err := repository.BuildRepository(protoRepo) if err != nil { return sys_error.New("数据错误", err) } repo = newRepo } s.Repo = repo s.Memory = NewWaysideMemory() // 构建所有UID映射关系, s.UidMap = buildRepositoryAllUidsMap(s.MapIds, s.Repo) return nil } // GetRunRadarConfig 获取雷达配置信息 func (s *VerifySimulation) GetRunRadarConfig() config.RadarConfig { return s.runConfig.Radar } // GetRunAccConfig 获取加速计配置信息 func (s *VerifySimulation) GetRunAccConfig() config.AccConfig { return s.runConfig.Acc } // FindRadarTrain 查找一个列车 只有1端雷达开启啊 func (s *VerifySimulation) FindRadarTrain() *state_proto.TrainState { var trainStatus *state_proto.TrainState s.Memory.Status.TrainStateMap.Range(func(k any, v any) bool { val, ok := v.(*state_proto.TrainState) if ok { if val.TrainEndsA.RadarEnable || val.TrainEndsB.RadarEnable { trainStatus = val return false } /*if val.TrainEndsA.RadarEnable && val.TrainEndsB.RadarEnable { return true } else if val.TrainEndsA.RadarEnable || val.TrainEndsB.RadarEnable { trainStatus = val return false }*/ } return true }) return trainStatus } // FindRadarTrain 查找一个列车 只有1端雷达开启啊 func (s *VerifySimulation) FindAccTrain() *state_proto.TrainState { var trainStatus *state_proto.TrainState s.Memory.Status.TrainStateMap.Range(func(k any, v any) bool { val, ok := v.(*state_proto.TrainState) if ok { if val.TrainEndsA.AccEnable && val.TrainEndsB.AccEnable { //trainStatus = val //return false return true } else if val.TrainEndsA.AccEnable || val.TrainEndsB.AccEnable { trainStatus = val return false } } return true }) return trainStatus } func buildProtoRepository(mapIds []int32) (*proto.Repository, error) { repo := &proto.Repository{} var exceptStationGiMapIds []int32 //创建设备 for _, mapId := range mapIds { giType := QueryGiType(mapId) if giType == data_proto.PictureType_StationLayout { stationGi := QueryGiData[*data_proto.RtssGraphicStorage](mapId) fillProtoRepository(repo, stationGi, mapId) } else { exceptStationGiMapIds = append(exceptStationGiMapIds, mapId) } } //构建并关联电子元件 for _, mapId := range exceptStationGiMapIds { giType := QueryGiType(mapId) if giType == data_proto.PictureType_RelayCabinetLayout { relayGi := QueryGiData[*data_proto.RelayCabinetGraphicStorage](mapId) buildAndRelateElectronicComponent(repo, relayGi, mapId) } } //构建信号平面图中物理区段码表与集中站的关系 for _, mapId := range mapIds { giType := QueryGiType(mapId) if giType == data_proto.PictureType_StationLayout { stationGi := QueryGiData[*data_proto.RtssGraphicStorage](mapId) buildSectionCodePoint(repo, stationGi, mapId) } } return repo, nil } func buildSectionCodePoint(repo *proto.Repository, storage *data_proto.RtssGraphicStorage, mapId int32) { // city := storage.UniqueIdPrefix.City // lineId := storage.UniqueIdPrefix.LineId uidsMap := QueryUidStructure[*StationUidStructure](mapId) for _, sscp := range storage.SectionCodePointList { centralizedStation := sscp.CentralizedStation sectionGIds := sscp.SectionIds centralizedStationId := uidsMap.StationIds[centralizedStation].Uid // GenerateElementUid(city, lineId, nil, centralizedStation) ref := queryCentralizedStationRef(centralizedStationId, repo) var ccs []*proto.CiSectionCodePoint for sectionPoint, sectionGId := range sectionGIds { cc := &proto.CiSectionCodePoint{} cc.Row = int32(sectionPoint) cc.SectionId = QueryUidByMidAndComId(mapId, sectionGId, &data_proto.Section{}) ccs = append(ccs, cc) } ref.SectionCodePoints = ccs } } func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *data_proto.RelayCabinetGraphicStorage, mapId int32) { relayUidStructure := QueryUidStructure[*RelayUidStructure](mapId) city := relayGi.UniqueIdPrefix.City lineId := relayGi.UniqueIdPrefix.LineId station := relayGi.UniqueIdPrefix.BelongsConcentrationStation stationUid := GenerateElementUid(city, lineId, nil, station) relayMap := make(map[string]*proto.Relay) for _, relay := range relayGi.Relays { rid := GetMapElementId(relay.Common) repoRelay := &proto.Relay{ Id: relayUidStructure.RelayIds[rid].Uid, Code: relay.Code, Model: convertRelayModel(relay.NewModel), StationId: stationUid, } repo.Relays = append(repo.Relays, repoRelay) relayMap[repoRelay.Id] = repoRelay } for _, pfp := range relayGi.PhaseFailureProtectors { pid := GetMapElementId(pfp.Common) repo.PhaseFailureProtectors = append(repo.PhaseFailureProtectors, &proto.PhaseFailureProtector{ Id: relayUidStructure.RelayIds[pid].Uid, Code: pfp.Code, }) } turnoutMap := make(map[string]*proto.Turnout) for _, turnout := range repo.Turnouts { turnoutMap[turnout.Id] = turnout } signalMap := make(map[string]*proto.Signal) for _, signal := range repo.Signals { signalMap[signal.Id] = signal } stationMap := make(map[string]*proto.Station) for _, station := range repo.Stations { stationMap[station.Id] = station } psdMap := make(map[string]*proto.Psd) for _, psd := range repo.Psds { psdMap[psd.Id] = psd } platformMap := make(map[string]*proto.Platform) for _, platform := range repo.Platforms { platformMap[platform.Id] = platform } ckmMap := make(map[string]*proto.Ckm) for _, ckm := range repo.Ckms { ckmMap[ckm.Id] = ckm } xcjMap := make(map[string]*proto.Xcj) for _, xcj := range repo.Xcjs { xcjMap[xcj.Id] = xcj } ciecs := stationMap[stationUid] //联锁集中站 if ciecs == nil { panic(fmt.Errorf("联锁集中站[%s]不存在", stationUid)) } for _, relationship := range relayGi.DeviceRelateRelayList { switch relationship.DeviceType { case data_proto.RelatedRef_Turnout: turnout := turnoutMap[GenerateElementUid(city, lineId, []string{station}, relationship.Code)] if turnout == nil { continue } for _, group := range relationship.Combinationtypes { var componentIds []string for _, relayId := range group.RefRelays { if relayUidStructure.RelayIds[relayId] == nil { continue } componentIds = append(componentIds, relayUidStructure.RelayIds[relayId].Uid) } turnout.ElectronicComponentGroups = append(turnout.ElectronicComponentGroups, &proto.ElectronicComponentGroup{ Code: group.Code, ComponentIds: componentIds, }) } case data_proto.RelatedRef_signal: signal := signalMap[GenerateElementUid(city, lineId, []string{station}, relationship.Code)] if signal == nil { continue } //信号机只有一个组合类型 if len(relationship.Combinationtypes) != 1 { panic(fmt.Sprintf("信号机[%s]须有一个组合类型", signal.Id)) } group := relationship.Combinationtypes[0] var componentIds []string for _, relayId := range group.RefRelays { if relayUidStructure.RelayIds[relayId] == nil { continue } componentIds = append(componentIds, relayUidStructure.RelayIds[relayId].Uid) } signal.Code = group.Code signal.ElectronicComponentGroups = append(signal.ElectronicComponentGroups, &proto.ElectronicComponentGroup{ Code: group.Code, ComponentIds: componentIds, }) case data_proto.RelatedRef_station: station := stationMap[GenerateElementUid(city, lineId, nil, relationship.Code)] if station == nil { continue } for _, group := range relationship.Combinationtypes { d := &proto.ElectronicGroup{Code: group.Code} for _, relayId := range group.RefRelays { if relayUidStructure.RelayIds[relayId] == nil { continue } d.Components = append(d.Components, &proto.ElectronicComponent{ Id: relayUidStructure.RelayIds[relayId].Uid, DeviceType: proto.DeviceType_DeviceType_Relay, }) } station.ElectronicGroup = append(station.ElectronicGroup, d) } case data_proto.RelatedRef_ScreenDoor: psd, ok := psdMap[GenerateElementUid(city, lineId, nil, relationship.Code)] if !ok { continue } for _, group := range relationship.Combinationtypes { var componentIds []string for _, relayId := range group.RefRelays { if relayUidStructure.RelayIds[relayId] == nil { continue } componentIds = append(componentIds, relayUidStructure.RelayIds[relayId].Uid) } psd.ElectronicComponentGroups = append(psd.ElectronicComponentGroups, &proto.ElectronicComponentGroup{ Code: group.Code, ComponentIds: componentIds, }) } case data_proto.RelatedRef_SignalFaultAlarm: // 信号机故障报警仪设备组合 { egs := buildEgs(relationship.Combinationtypes, relayUidStructure) ciecs.Deccs = append(ciecs.Deccs, &proto.DeviceEcc{ DeviceType: proto.DeviceType_DeviceType_SignalFaultAlarm, Egs: egs, }) } case data_proto.RelatedRef_Breakers: // 断路器 { egs := buildEgs(relationship.Combinationtypes, relayUidStructure) ciecs.Deccs = append(ciecs.Deccs, &proto.DeviceEcc{ DeviceType: proto.DeviceType_DeviceType_Breakers, Egs: egs, }) } case data_proto.RelatedRef_PowerScreen: // 电源屏 { egs := buildEgs(relationship.Combinationtypes, relayUidStructure) ciecs.Deccs = append(ciecs.Deccs, &proto.DeviceEcc{ DeviceType: proto.DeviceType_DeviceType_PowerScreen, Egs: egs, }) } case data_proto.RelatedRef_GarageDoor, data_proto.RelatedRef_FloodGate: //车库门||防淹门 { ckm, ok := ckmMap[GenerateElementUid(city, lineId, nil, relationship.Code)] if !ok { continue } for _, group := range relationship.Combinationtypes { var componentIds []string for _, relayId := range group.RefRelays { if relayUidStructure.RelayIds[relayId] == nil { continue } componentIds = append(componentIds, relayUidStructure.RelayIds[relayId].Uid) } ckm.ElectronicComponentGroups = append(ckm.ElectronicComponentGroups, &proto.ElectronicComponentGroup{ Code: group.Code, ComponentIds: componentIds, }) } } case data_proto.RelatedRef_CarWashing: { xcj, ok := xcjMap[GenerateElementUid(city, lineId, nil, relationship.Code)] if !ok { continue } for _, group := range relationship.Combinationtypes { var componentIds []string for _, relayId := range group.RefRelays { if relayUidStructure.RelayIds[relayId] == nil { continue } componentIds = append(componentIds, relayUidStructure.RelayIds[relayId].Uid) } xcj.ElectronicComponentGroups = append(xcj.ElectronicComponentGroups, &proto.ElectronicComponentGroup{ Code: group.Code, ComponentIds: componentIds, }) } } } } //门控箱 for _, mkx := range repo.Mkxs { platform := platformMap[psdMap[mkx.PsdId].GetPlatformId()] station := stationMap[platform.GetStationId()] var s string if strings.Contains(platform.GetCode(), "上行") { s = "S" } else if strings.Contains(platform.GetCode(), "下行") { s = "X" } else { continue } for _, group := range station.ElectronicGroup { if group.Code == "MKX" { for _, component := range group.Components { relay := relayMap[component.Id] if strings.Contains(relay.GetCode(), s) { if strings.Contains(relay.GetCode(), "PCB") { mkx.PcbjId = relay.Id } else if strings.Contains(relay.GetCode(), "POB") { mkx.PobjId = relay.Id } else if strings.Contains(relay.GetCode(), "PAB") || strings.Contains(relay.GetCode(), "PDB") { mkx.PabjId = relay.Id } else if strings.Contains(relay.GetCode(), "WRZF") { mkx.WrzfjId = relay.Id } else if strings.Contains(relay.GetCode(), "QKQR") { mkx.QkqrjId = relay.Id } } } } } } // 处理该集中站采集、驱动配置信息 centralizedStationId := GenerateElementUid(city, lineId, nil, station) ref := queryCentralizedStationRef(centralizedStationId, repo) ref.CjList = append(ref.CjList, handlerRelayGiCj(relayUidStructure, centralizedStationId, relayGi.CiCjList)...) sortQcTable(ref.CjList) ref.QdList = append(ref.QdList, handlerRelayGiQd(relayUidStructure, centralizedStationId, relayGi.CiQdList)...) sortQcTable(ref.QdList) } func buildEgs(cts []*data_proto.Combinationtype, relayUidStructure *RelayUidStructure) []*proto.ElectronicComponentGroup { var egs []*proto.ElectronicComponentGroup for _, ct := range cts { d := &proto.ElectronicComponentGroup{Code: ct.Code} for _, relayId := range ct.RefRelays { if relayUidStructure.RelayIds[relayId] == nil { continue } d.ComponentIds = append(d.ComponentIds, relayUidStructure.RelayIds[relayId].Uid) } egs = append(egs, d) } return egs } type IQcTable interface { GetRow() int32 GetCol() int32 } func sortQcTable[T IQcTable](s []T) { sort.SliceStable(s, func(i, j int) bool { a := s[i] b := s[j] if a.GetCol() < b.GetCol() { return true } else if a.GetCol() > b.GetCol() { return false } else { if a.GetRow() < b.GetRow() { return true } else { return false } } }) } // 查询集中站配置信息 func queryCentralizedStationRef(stationId string, repo *proto.Repository) *proto.CentralizedStationRef { var ref *proto.CentralizedStationRef for _, r := range repo.CentralizedStationRefs { if r.StationId == stationId { ref = r break } } if ref == nil { ref = &proto.CentralizedStationRef{StationId: stationId} repo.CentralizedStationRefs = append(repo.CentralizedStationRefs, ref) } return ref } // 处理继电器采集信息 func handlerRelayGiCj(uidsMap *RelayUidStructure, stationId string, ciCj *data_proto.CiCj) []*proto.CjData { if ciCj == nil { return nil } // 采集信息 dataLenght := len(ciCj.CjList) * int(ciCj.DsCount) if dataLenght == 0 { return nil } cjList := make([]*proto.CjData, dataLenght) index := 0 for ci, col := range ciCj.CjList { for ri, row := range col.BitList { r := &proto.CjData{Row: int32(ri), Col: int32(ci)} if len(row.RefRelays) > 0 { for _, j := range row.RefRelays { u := uidsMap.RelayIds[j.RelayId] if u == nil { panic(sys_error.New(fmt.Sprintf("集中站【id:%s】不存在继电器的【comId:%d】UID映射关系", stationId, j.RelayId))) } d := &proto.CjDataItem{RelayId: u.Uid} if j.Position == data_proto.CjDataItem_H { d.Q = false } else { d.Q = true } r.RefRelays = append(r.RefRelays, d) } } cjList[index] = r index++ } } return cjList } // 处理继电器驱动信息 func handlerRelayGiQd(uidsMap *RelayUidStructure, stationId string, ciQd *data_proto.CiQd) []*proto.QdData { if ciQd == nil { return nil } // 驱动信息 dataLenght := len(ciQd.QdList) * int(ciQd.DsCount) if dataLenght == 0 { return nil } qdList := make([]*proto.QdData, dataLenght) index := 0 for ci, col := range ciQd.QdList { for ri, row := range col.BitList { r := &proto.QdData{Row: int32(ri), Col: int32(ci)} if len(row.RefRelays) > 0 { for _, j := range row.RefRelays { u := uidsMap.RelayIds[j] if u == nil { panic(sys_error.New(fmt.Sprintf("集中站【id:%s】不存在继电器的【comId:%d】UID映射关系", stationId, j))) } r.RefRelays = append(r.RefRelays, u.Uid) } } qdList[index] = r index++ } } return qdList } func convertRelayModel(modelType data_proto.Relay_ModelType) proto.Relay_Model { switch modelType { case data_proto.Relay_Unknown: return proto.Relay_Unknown case data_proto.Relay_JPXC_1000: return proto.Relay_JPXC_1000 case data_proto.Relay_JPXC_1700: return proto.Relay_JPXC_1700 case data_proto.Relay_JWJXC_480: return proto.Relay_JWJXC_480 case data_proto.Relay_JWJXC_H125_80: return proto.Relay_JWJXC_H125_80 case data_proto.Relay_JWXC_1700: return proto.Relay_JWXC_1700 case data_proto.Relay_JWXC_H340: return proto.Relay_JWXC_H340 case data_proto.Relay_JYJXC_160_260: return proto.Relay_JYJXC_160_260 case data_proto.Relay_JZXC_H18: return proto.Relay_JZXC_H18 default: panic(fmt.Sprintf("意料之外的继电器型号:%s", modelType)) } } func fillProtoRepository(repo *proto.Repository, storage *data_proto.RtssGraphicStorage, mapId int32) { repo.MainCoordinateSystem = storage.UniqueIdPrefix.MainCoordinateSystem axleCountingMap := make(map[uint32]*data_proto.AxleCounting) uidsMap := QueryUidStructure[*StationUidStructure](mapId) //计轴 for _, data := range storage.AxleCountings { id := GetMapElementId(data.Common) axleCountingMap[id] = data cpType := proto.CheckPointType_AxleCounter if data.Type == data_proto.AxleCounting_SectionBoundary { cpType = proto.CheckPointType_Boundary } cp := &proto.CheckPoint{ Id: uidsMap.AxlePointIds[id].Uid, Km: convertKm(data.KilometerSystem), Type: cpType, } for _, ref := range data.AxleCountingRef { cp.DevicePorts = append(cp.DevicePorts, convertDevicePort(ref, uidsMap)) } repo.CheckPoints = append(repo.CheckPoints, cp) } //区段 for _, data := range storage.Section { var turnoutUids []string if data.SectionType == data_proto.Section_TurnoutPhysical { turnoutIds := findTurnoutIds(axleCountingMap, data.AxleCountings) for _, tid := range turnoutIds { turnoutUids = append(turnoutUids, uidsMap.TurnoutIds[tid].Uid) } } var centralizedStation string if len(data.CentralizedStations) > 0 { s := uidsMap.StationIds[data.CentralizedStations[0]] if s != nil { centralizedStation = s.Code } } physicalSection := &proto.PhysicalSection{ Id: uidsMap.PhysicalSectionIds[GetMapElementId(data.Common)].Uid, ADevicePort: convertDevicePort(data.PaRef, uidsMap), BDevicePort: convertDevicePort(data.PbRef, uidsMap), TurnoutIds: turnoutUids, CentralizedStation: centralizedStation, } repo.PhysicalSections = append(repo.PhysicalSections, physicalSection) } //道岔 for _, data := range storage.Turnouts { var km *proto.Kilometer for _, ks := range data.KilometerSystem { if ks.Kilometer != 0 { km = convertKm(ks) break } } turnout := &proto.Turnout{ Id: uidsMap.TurnoutIds[GetMapElementId(data.Common)].Uid, Km: km, ADevicePort: convertDevicePort(data.PaRef, uidsMap), BDevicePort: convertDevicePort(data.PbRef, uidsMap), CDevicePort: convertDevicePort(data.PcRef, uidsMap), } switch data.SwitchMachineType { case data_proto.Turnout_ZDJ9_Single: turnout.SwitchMachineType = proto.Turnout_ZDJ9_Single case data_proto.Turnout_ZDJ9_Double: turnout.SwitchMachineType = proto.Turnout_ZDJ9_Double } repo.Turnouts = append(repo.Turnouts, turnout) } //信号机 for _, data := range storage.Signals { signal := &proto.Signal{ Id: uidsMap.SignalIds[GetMapElementId(data.Common)].Uid, Km: convertKm(data.KilometerSystem), Model: convertToProtoSignalModel(data.Mt), } switch data.RefDev.DeviceType { case data_proto.RelatedRef_Section: signal.SectionId = uidsMap.PhysicalSectionIds[data.RefDev.Id].Uid case data_proto.RelatedRef_Turnout: signal.TurnoutPort = convertDevicePort(data.RefDev, uidsMap) } repo.Signals = append(repo.Signals, signal) } stm := make(map[string][]string) //应答器 for _, data := range storage.Transponders { fixedTelegram, err := hex.DecodeString(data.FixedTelegram) if err != nil { slog.Error(fmt.Sprintf("解析应答器[%s]的固定报文出错:", err.Error())) } fixedUserTelegram, err := hex.DecodeString(data.FixedUserTelegram) if err != nil { slog.Error(fmt.Sprintf("解析应答器[%s]的固定用户报文出错:", err.Error())) } responder := &proto.Transponder{ Id: uidsMap.TransponderIds[GetMapElementId(data.Common)].Uid, Km: convertKm(data.KilometerSystem), FixedTelegram: fixedTelegram, Type: convertToProtoBaliseType(data.Type), FixedUserTelegram: fixedUserTelegram, } switch data.TransponderRef.DeviceType { case data_proto.RelatedRef_Section: responder.SectionId = uidsMap.PhysicalSectionIds[data.TransponderRef.Id].Uid case data_proto.RelatedRef_Turnout: responder.TurnoutPort = convertDevicePort(data.TransponderRef, uidsMap) } for _, stationId := range data.CentralizedStations { var stationName string if uidsMap.StationIds[stationId] == nil { stationName = uidsMap.StationIds[stationId].Code } stm[stationName] = append(stm[stationName], responder.Id) } repo.Transponders = append(repo.Transponders, responder) } slopeKsMap := make(map[uint32]*data_proto.SlopeKiloMarker) //坡度公里标 for _, data := range storage.SlopeKiloMarker { slopeKsMap[GetMapElementId(data.Common)] = data } //坡度 for _, data := range storage.Slopes { var kms []*proto.Kilometer for _, id := range data.RefDeviceId { kms = append(kms, convertKm(slopeKsMap[id].KilometerSystem[0])) } slope := &proto.Slope{ Id: uidsMap.SlopeIds[GetMapElementId(data.Common)].Uid, Kms: kms, Degree: data.SlopeNumber, } repo.Slopes = append(repo.Slopes, slope) } curveKsMap := make(map[uint32]*data_proto.CurvatureKiloMarker) //曲度公里标 for _, data := range storage.CurvatureKiloMarker { curveKsMap[GetMapElementId(data.Common)] = data } //曲度 for _, data := range storage.Curvatures { var kms []*proto.Kilometer for _, id := range data.RefDeviceId { kms = append(kms, convertKm(curveKsMap[id].KilometerSystem[0])) } slope := &proto.SectionalCurvature{ Id: uidsMap.CurvatureIds[GetMapElementId(data.Common)].Uid, Kms: kms, Radius: data.CurvatureNumber, } repo.SectionalCurvatures = append(repo.SectionalCurvatures, slope) } //公里标转换 for _, data := range storage.KilometerConvertList { repo.KilometerConverts = append(repo.KilometerConverts, &proto.KilometerConvert{ KmA: convertKm(data.KmA), KmB: convertKm(data.KmB), SameTrend: data.SameTrend, }) } // 初始化站场图按钮 for _, data := range storage.EsbButtons { repo.Buttons = append(repo.Buttons, &proto.Button{ Id: uidsMap.ButtonIds[GetMapElementId(data.Common)].Uid, Code: data.Code, ButtonType: proto.Button_Reset_Press, }) } // 车站关联关系 relateMap := make(map[string]*data_proto.StationRelateDevice) for _, data := range storage.StationRelateDeviceList { relateMap[data.Code] = data } // 处理车站信息 repoStationMap := make(map[uint32]*proto.Station) for _, data := range storage.Stations { station := &proto.Station{ Id: uidsMap.StationIds[GetMapElementId(data.Common)].Uid, Code: data.StationName, } repoStationMap[GetMapElementId(data.Common)] = station // 关联车站的设备 refs, ok := relateMap[station.Code] if ok { for _, c := range refs.Combinationtypes { group := &proto.ElectronicGroup{Code: c.Code} for _, d := range c.RefDevices { var comp *proto.ElectronicComponent if uidsMap.ButtonIds[d] != nil { // 目前只处理按钮 comp = &proto.ElectronicComponent{ Id: uidsMap.ButtonIds[d].Uid, DeviceType: proto.DeviceType_DeviceType_Button, } } else { continue } group.Components = append(group.Components, comp) } station.ElectronicGroup = append(station.ElectronicGroup, group) } } //// 处理车站关联IBP的设备 //handlerIBPDeviceToStation(station, repo, data.RefIbpMapCode) repo.Stations = append(repo.Stations, station) // 处理集中站的信息 if stm[station.Code] != nil { ref := queryCentralizedStationRef(station.Id, repo) ref.TransponderId = append(ref.TransponderId, stm[station.Code]...) } } //站台 platformMap := make(map[uint32]*data_proto.Platform) for _, data := range storage.Platforms { platformId := GetMapElementId(data.Common) platformMap[platformId] = data platform := &proto.Platform{ Id: uidsMap.PlatformIds[platformId].Uid, Code: data.Code, } repo.Platforms = append(repo.Platforms, platform) platform.StationId = uidsMap.StationIds[data.RefStationId].Uid platform.PhysicalSectionId = uidsMap.PhysicalSectionIds[data.RefSectionId].Uid } //屏蔽门 platformId_psdUid_map := make(map[uint32]string) for _, data := range storage.ScreenDoors { var asdGroups []*proto.AsdGroup for _, group := range storage.ScreenDoorConfig.ScreenDoorGroupList { asdGroups = append(asdGroups, &proto.AsdGroup{ Group: group.TrainGroupAmount, Start: group.StartSmallDoor, End: group.EndSmallDoor, }) } psd := &proto.Psd{ Id: uidsMap.PsdIds[GetMapElementId(data.Common)].Uid, AsdAmount: storage.ScreenDoorConfig.SonDoorAmount, AsdGroups: asdGroups, PlatformId: uidsMap.PlatformIds[data.RefPlatformId].Uid, } platformId_psdUid_map[data.GetRefPlatformId()] = psd.Id repo.Psds = append(repo.Psds, psd) } //屏蔽门PSL for _, data := range storage.PslBoxs { boxUidInfo := uidsMap.PslIds[GetMapElementId(data.Common)] mkx := &proto.Mkx{ Id: boxUidInfo.Uid, PsdId: platformId_psdUid_map[data.RefPlatformId], } repo.Mkxs = append(repo.Mkxs, mkx) _, pslStorage := QueryGiDataByName[*data_proto.PslGraphicStorage](data.RefPslMapCode) for _, button := range pslStorage.PslButtons { repoButton := &proto.Button{ Id: boxUidInfo.Uid + "_" + button.Code, Code: button.Code, ButtonType: proto.Button_Reset_Press, HasLight: true, } repo.Buttons = append(repo.Buttons, repoButton) switch button.Code { case "PCB": mkx.PcbaId = repoButton.Id case "PCBPL": mkx.PcbplaId = repoButton.Id case "POB": mkx.PobaId = repoButton.Id case "POBPL": mkx.PobplaId = repoButton.Id case "PAB": mkx.PabaId = repoButton.Id case "PABPL": mkx.PabplaId = repoButton.Id case "WRZF": mkx.WrzfaId = repoButton.Id case "WRZFPL": mkx.WrzfplaId = repoButton.Id case "QKQR": mkx.QkqraId = repoButton.Id case "QKQRPL": mkx.QkqrplaId = repoButton.Id case "MPL": mkx.MplaId = repoButton.Id case "JXTCPLA": mkx.JxtcplaId = repoButton.Id } } } //IBP for _, data := range storage.IbpBoxs { boxUidInfo := uidsMap.IbpIds[data.Common.Id] station := repoStationMap[data.RefStationId] handlerIBPDeviceToStation(station, boxUidInfo.Uid, repo, data.RefIbpMapCode) } //车库门和车库门PSL fillCkmOrFym(repo, storage.GarageDoors, uidsMap) //防淹门和防淹门PSL fillCkmOrFym(repo, storage.FloodGates, uidsMap) //洗车机 for _, data := range storage.CarWashings { xcj := &proto.Xcj{ Id: uidsMap.XcjIds[data.Common.Id].Uid, NumSegments: data.DuanNum, } repo.Xcjs = append(repo.Xcjs, xcj) } } func fillCkmOrFym(repo *proto.Repository, doors []*data_proto.GarageDoor, uidsMap *StationUidStructure) { for _, data := range doors { //车库门 ckmId := GetMapElementId(data.Common) ckm := &proto.Ckm{ Id: uidsMap.CkmIds[ckmId].Uid, } repo.Ckms = append(repo.Ckms, ckm) //车库门PSL pslUid := uidsMap.PslIds[ckmId].Uid ckmPsl := &proto.CkmPsl{ Id: pslUid, CkmId: uidsMap.CkmIds[ckmId].Uid, } repo.CkmPsls = append(repo.CkmPsls, ckmPsl) _, pslStorage := QueryGiDataByName[*data_proto.PslGraphicStorage](data.RefPslMapCode) for _, button := range pslStorage.PslButtons { repoButton := &proto.Button{ Id: pslUid + "_" + button.Code, Code: button.Code, ButtonType: proto.Button_Reset_Press, HasLight: true, } repo.Buttons = append(repo.Buttons, repoButton) switch button.Code { case "KMA": ckmPsl.KmaId = repoButton.Id case "GMA": ckmPsl.GmaId = repoButton.Id case "MPLA": ckmPsl.MplaId = repoButton.Id case "MMSA": ckmPsl.MmsaId = repoButton.Id } } } } // 将IBP的设备关联到车站中 func handlerIBPDeviceToStation(station *proto.Station, ibpBoxUid string, repo *proto.Repository, ibpMapCode string) { mapId, storage := QueryGiDataByName[*data_proto.IBPGraphicStorage](ibpMapCode) if storage == nil { return } uidMap := QueryUidStructure[*IBPUidStructure](mapId) deviceMap := make(map[uint32]*proto.ElectronicComponent) // 对应的设备类型 for _, data := range storage.IbpButtons { // 处理按钮 id := GetMapElementId(data.Common) b := &proto.Button{ Id: ibpBoxUid + "_" + uidMap.IbpButtonIds[id].Uid, Code: data.Code, ButtonType: proto.Button_NO_Reset_Press, HasLight: data.HasLight, } if data.IsSelfReset { b.ButtonType = proto.Button_Reset_Press } deviceMap[id] = &proto.ElectronicComponent{ Id: b.Id, DeviceType: proto.DeviceType_DeviceType_Button, } repo.Buttons = append(repo.Buttons, b) } for _, data := range storage.IbpKeys { // 钥匙 id := GetMapElementId(data.Common) b := &proto.Key{ Id: ibpBoxUid + "_" + uidMap.IbpKeyIds[id].Uid, Code: data.Code, Gear: 2, } deviceMap[id] = &proto.ElectronicComponent{ Id: b.Id, DeviceType: proto.DeviceType_DeviceType_Key, } repo.Keys = append(repo.Keys, b) } for _, data := range storage.IbpAlarms { // 报警器 id := GetMapElementId(data.Common) b := &proto.Alarm{ Id: ibpBoxUid + "_" + uidMap.IbpAlarmIds[id].Uid, Code: data.Code, } deviceMap[id] = &proto.ElectronicComponent{ Id: b.Id, DeviceType: proto.DeviceType_DeviceType_Alarm, } repo.Alarms = append(repo.Alarms, b) } for _, data := range storage.IbpLights { // 指示灯, id := GetMapElementId(data.Common) b := &proto.Light{ Id: ibpBoxUid + "_" + uidMap.IbpLightIds[id].Uid, Code: data.Code, } deviceMap[id] = &proto.ElectronicComponent{ Id: b.Id, DeviceType: proto.DeviceType_DeviceType_Light, } repo.Lights = append(repo.Lights, b) } for _, data := range storage.IbpRelatedDevices { // 组信息 for _, c := range data.Combinationtypes { group := &proto.ElectronicGroup{Code: c.Code} for _, d := range c.RefDevices { deviceType, ok := deviceMap[d] if !ok { slog.Debug("IBP组合类型类型不存在设备id:%s", d) continue } group.Components = append(group.Components, deviceType) } station.ElectronicGroup = append(station.ElectronicGroup, group) } } } func convertKm(ks *data_proto.KilometerSystem) *proto.Kilometer { var dir proto.Direction switch ks.Direction { case data_proto.KilometerSystem_LEFT: dir = proto.Direction_LEFT case data_proto.KilometerSystem_RIGHT: dir = proto.Direction_RIGHT } return &proto.Kilometer{ Value: ks.Kilometer, CoordinateSystem: ks.CoordinateSystem, Direction: dir, } } func convertDevicePort(ref *data_proto.RelatedRef, uidsMap *StationUidStructure) *proto.DevicePort { if ref == nil { return nil } var port proto.Port switch ref.DevicePort { case data_proto.RelatedRef_A: port = proto.Port_A case data_proto.RelatedRef_B: port = proto.Port_B case data_proto.RelatedRef_C: port = proto.Port_C } var elementId string var deviceType proto.DeviceType switch ref.DeviceType { case data_proto.RelatedRef_Section: deviceType = proto.DeviceType_DeviceType_PhysicalSection elementId = uidsMap.PhysicalSectionIds[ref.Id].Uid case data_proto.RelatedRef_Turnout: deviceType = proto.DeviceType_DeviceType_Turnout elementId = uidsMap.TurnoutIds[ref.Id].Uid default: panic(fmt.Sprintf("异常的设备类型-%s", ref.DeviceType)) } return &proto.DevicePort{ DeviceId: elementId, DeviceType: deviceType, Port: port, } } func findTurnoutIds(axleCountingMap map[uint32]*data_proto.AxleCounting, axleIds []uint32) []uint32 { if len(axleIds) <= 2 { return nil } turnoutMap := make(map[uint32]int) for _, axleId := range axleIds { axle := axleCountingMap[axleId] for _, ref := range axle.AxleCountingRef { if ref.DeviceType == data_proto.RelatedRef_Turnout { turnoutMap[ref.Id] = turnoutMap[ref.Id] + 1 } } } var turnoutIds []uint32 for id, num := range turnoutMap { if num > 1 { turnoutIds = append(turnoutIds, id) } } return turnoutIds } /* enum Model{ HL = 0; //2XH-1 红绿 HLU_FU = 1; //2XH-1 红绿黄,封黄灯,无引导 HLU_DU_YY = 2; //3XH-1 红绿黄,不封灯,有单黄,带引导 HLU_YY = 3; //3XH-2或JDXH 红绿黄,不封灯,无单黄,带引导 HLU_FL_DU_YY = 4;//3XH-3 红绿黄,封绿灯,有单黄,带引导 HLU_DU = 5; //3XH-4 红绿黄,不封灯,有单黄,无引导 AB = 6; //DXCH 蓝白 HBU_DU = 7; //JCKXH 红白黄,不封灯,有单黄,无引导 } */ func convertToProtoSignalModel(gSmt data_proto.Signal_Model) proto.Signal_Model { switch gSmt { case data_proto.Signal_HL: return proto.Signal_HL case data_proto.Signal_HLU_FU: return proto.Signal_HLU_FU case data_proto.Signal_HLU_DU_YY: return proto.Signal_HLU_DU_YY case data_proto.Signal_HLU_YY: return proto.Signal_HLU_YY case data_proto.Signal_HLU_FL_DU_YY: return proto.Signal_HLU_FL_DU_YY case data_proto.Signal_HLU_DU: return proto.Signal_HLU_DU case data_proto.Signal_AB: return proto.Signal_AB case data_proto.Signal_HBU_DU: return proto.Signal_HBU_DU default: panic(fmt.Sprintf("data_proto.Signal_Model[%d]无法映射到proto.Signal_Model", gSmt)) } } func convertToProtoBaliseType(bt data_proto.Transponder_TransponderTypeEnum) proto.Transponder_Type { switch bt { case data_proto.Transponder_FB: return proto.Transponder_FB case data_proto.Transponder_WB: return proto.Transponder_WB case data_proto.Transponder_DB: return proto.Transponder_DB case data_proto.Transponder_VB: return proto.Transponder_VB case data_proto.Transponder_IB: return proto.Transponder_IB default: panic(fmt.Sprintf("data_proto.Transponder_TransponderTypeEnum[%d]无法映射到proto.Transponder_Type", bt)) } } // VerifyEvn 测试环境 type VerifyEvn interface { EvnWorld() ecs.World }