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

1725 lines
54 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package memory
import (
"encoding/hex"
"encoding/json"
"fmt"
"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/acc"
"joylink.club/bj-rtsts-server/third_party/electrical_machinery"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/radar"
"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"
"log/slog"
"math"
"sort"
"strconv"
"strings"
"sync"
)
// 轨旁仿真定义
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]*DeviceRelationship
// 运行环境配置
runConfig *config.ThirdPartyConfig
}
// 轨旁仿真内存模型
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) 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
}
func (s *VerifySimulation) GetRunConfig() config.ThirdPartyConfig {
if s.runConfig == nil {
return config.ThirdPartyConfig{}
}
return *s.runConfig
}
// GetBtmCanetConfig 获取CANET配置信息
func (s *VerifySimulation) GetBtmCanetConfig() config.BtmCanetConfig {
return s.runConfig.BtmCanet
}
func (s *VerifySimulation) GetAllTrain() []*state_proto.TrainState {
return s.collectorAllTrain()
}
func (s *VerifySimulation) collectorAllTrain() []*state_proto.TrainState {
allTrain := make([]*state_proto.TrainState, 0)
s.Memory.Status.TrainStateMap.Range(func(k, v any) bool {
train := v.(*state_proto.TrainState)
if train.Show {
allTrain = append(allTrain, train)
}
return true
})
return allTrain
}
func (s *VerifySimulation) GetConnVobcTrain() *state_proto.TrainState {
return s.FindConnTrain(state_proto.TrainConnState_VOBC)
}
// GetBtmVobcConfig 获取11 号线 btm vobc配置信息
func (s *VerifySimulation) GetBtmVobcConfig() config.BtmVobcConfig {
return s.runConfig.BtmVobc
}
// GetSectionCodePoints 获取集中站的区段码表
func (s *VerifySimulation) GetSectionCodePoints(city string, lineId string, centralizedStation string) []*proto.CiSectionCodePoint {
stationUid := BuildUid(city, lineId, 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 := BuildUid(city, lineId, 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.FindPhysicalSectionsStatus(s.World, axleSectionIds)
if e != nil { //从仿真中收集计轴区段状态的失败列表
return nil, e
}
//slog.Debug("收集计轴区段状态", "仿真中计轴状态len", len(as))
//
stateMap := make(map[string]*fi.PhysicalSectionState)
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
}
// 处理动力学列车速度消息
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)
// 更新列车状态
trainState := UpdateTrainStateByDynamics(s, trainId, info)
vs := train.VobcState
if vs.TractionStatus {
//动力学之前是kn * 100 这里*10就是N
tf := float32(vs.TractionPower) / info.Speed
vs.TractionForce = int64(tf / 10)
}
if train.ConnState.Conn && train.ConnState.ConnType == state_proto.TrainConnState_VOBC {
semi_physical_train.Default().SendTrainControlMessage(info)
electrical_machinery.Default().SendElectricMachineryMessage2(info, trainState)
radar.Default().TrainSpeedSender(info, trainState)
acc.Default().TrainAccSender(info, trainState)
}
}
// 获取动力学配置信息
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
}
//train.DynamicState.Speed
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
}
// 处理接到的联锁消息
func (s *VerifySimulation) HandleInterlockDriverInfo(code string, driveBytes []byte) {
wd := entity.GetWorldData(s.World)
for _, m := range s.Repo.CiQcList() { // 获取继电器地图信息
if m.StationId != code {
continue
}
var driveInfo []bool
for _, b := range driveBytes {
for bit := 0; bit < 8; bit++ {
driveInfo = append(driveInfo, (b&(1<<bit)) != 0)
}
}
for i, b := range driveInfo {
qdData := m.QdList[i]
for _, relayId := range qdData.RefRelays {
if b {
}
err := wd.SetQdBit(relayId, b)
if err != nil {
slog.Error("联锁驱动数据设置出错", "error", err)
}
}
}
}
}
// 采集联锁中的继电器消息
func (s *VerifySimulation) CollectInterlockRelayInfo(code string) *message.InterlockSendMsgPkg {
station := s.Repo.FindStationByStationName(code)
if station == nil {
return nil
}
for _, m := range s.Repo.CiQcList() { // 获取继电器地图信息
if m.StationId != station.Id() {
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{TypeName: "半实物vobc", ConnType: state_proto.TrainConnState_VOBC})
}
for _, pcSim := range s.runConfig.PcSimConfigs {
typeConfig = append(typeConfig, dto.TrainConnTypeConfigDto{TypeName: pcSim.ConfigName, ConnType: state_proto.TrainConnState_PC_SIM})
}
/* if s.runConfig.PcSimConfig.Open {
typeConfig = append(typeConfig, dto.TrainConnTypeConfigDto{ConnType: state_proto.TrainConnState_PC_SIM})
}*/
return typeConfig
}
// 获取电机转速参数
func (s *VerifySimulation) GetElectricMachineryRunConfig() []config.ElectricMachineryConfig {
return s.runConfig.ElectricMachinerys
}
// 初始化仿真运行配置
func (s *VerifySimulation) initRunConfig(runConfig *dto.ProjectRunConfigDto) error {
if runConfig == nil || runConfig.ConfigContent == "" {
return nil
}
var configMap config.ThirdPartyConfig
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
}
}
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 := BuildUid(city, lineId, station)
relayMap := make(map[string]*proto.Relay)
for _, relay := range relayGi.Relays {
rid := GetMapElementId(relay.Common)
var defaultPos proto.Relay_Pos
switch relay.DefaultInitialPosition {
case data_proto.CjDataItem_Q:
defaultPos = proto.Relay_Pos_Q
case data_proto.CjDataItem_H:
defaultPos = proto.Relay_Pos_H
case data_proto.CjDataItem_NONE:
defaultPos = proto.Relay_Pos_None
}
repoRelay := &proto.Relay{
Id: relayUidStructure.RelayIds[rid].Uid,
Code: relay.Code,
Model: convertRelayModel(relay.NewModel),
StationId: stationUid,
DefaultPos: defaultPos,
}
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
}
sectionMap := make(map[string]*proto.PhysicalSection)
for _, section := range repo.PhysicalSections {
sectionMap[section.Id] = section
}
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[BuildUid(city, lineId, 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[BuildUid(city, lineId, 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[BuildUid(city, lineId, 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[BuildUid(city, lineId, 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[BuildUid(city, lineId, 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[BuildUid(city, lineId, 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,
})
}
}
case data_proto.RelatedRef_Section:
{
section, ok := sectionMap[GenerateElementUid(city, lineId, []string{station}, 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)
}
section.ElectronicComponentGroups = append(section.ElectronicComponentGroups,
&proto.ElectronicComponentGroup{
Code: group.Code,
ComponentIds: componentIds,
})
}
}
case data_proto.RelatedRef_Platform:
{
platform, ok := platformMap[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)
}
platform.ElectronicComponentGroups = append(platform.ElectronicComponentGroups,
&proto.ElectronicComponentGroup{
Code: group.Code,
ComponentIds: componentIds,
})
}
}
case data_proto.RelatedRef_LS:
{
egs := buildEgs(relationship.Combinationtypes, relayUidStructure)
ciecs.Deccs = append(ciecs.Deccs, &proto.DeviceEcc{
DeviceType: proto.DeviceType_DeviceType_LS,
Egs: egs,
})
}
}
}
//门控箱
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(), "DPB") || 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 := BuildUid(city, lineId, 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 centralizedStationIds []string
for _, station := range uidsMap.PhysicalSectionIds[data.Common.Id].CentralizedStations {
centralizedStationIds = append(centralizedStationIds, uidsMap.StationIds[station.Common.Id].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: centralizedStationIds,
}
repo.PhysicalSections = append(repo.PhysicalSections, physicalSection)
}
//计轴区段
for _, data := range storage.AxleCountingSections {
var axleCountingIds []string
if data.PaRef != nil {
axleCountingIds = append(axleCountingIds, uidsMap.AxlePointIds[data.PaRef.Id].Uid)
}
if data.PbRef != nil {
axleCountingIds = append(axleCountingIds, uidsMap.AxlePointIds[data.PbRef.Id].Uid)
}
var turnoutAndPos []*proto.TurnoutAndPos
for _, tp := range data.TurnoutPos {
var pos proto.Turnout_Pos
switch tp.Position {
case 0:
pos = proto.Turnout_Pos_N
case 1:
pos = proto.Turnout_Pos_R
default:
panic(fmt.Errorf("计轴区段[%s]未知的道岔位置:%d", uidsMap.AxleCountingSectionIds[data.Common.Id].Uid, tp.Position))
}
turnoutAndPos = append(turnoutAndPos, &proto.TurnoutAndPos{
TurnoutId: uidsMap.TurnoutIds[tp.Id].Uid,
Pos: pos,
})
}
repo.AxleCountingSections = append(repo.AxleCountingSections, &proto.AxleCountingSection{
Id: uidsMap.AxleCountingSectionIds[data.Common.Id].Uid,
AxleCountingIds: axleCountingIds,
TurnoutAndPos: turnoutAndPos,
})
}
//道岔
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,
LeuIndex: data.LeuIndex,
IndexInLeu: data.LeuInsideIndex,
}
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 _, calibration := range storage.KilometerMarkCalibrations {
repo.KilometerCalibrations = append(repo.KilometerCalibrations, &proto.KilometerCalibration{
Design: convertKm(calibration.DesignKm),
Actual: convertKm(calibration.ActualKm),
})
}
//// 初始化站场图按钮
//for _, data := range storage.EsbButtons {
// repo.Buttons = append(repo.Buttons, &proto.Button{
// Id: uidsMap.EsbIds[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.EsbIds[d] != nil { // 目前只处理按钮
// comp = &proto.ElectronicComponent{
// Id: uidsMap.EsbIds[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,
}
switch data.Type {
case data_proto.Platform_up:
platform.Direction = proto.Platform_Up
case data_proto.Platform_down:
platform.Direction = proto.Platform_Down
case data_proto.Platform_Unknown:
platform.Direction = proto.Platform_Unknown
}
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)
}
//ESB
for _, data := range storage.EsbButtons {
repo.Esbs = append(repo.Esbs, &proto.Esb{
Id: uidsMap.EsbIds[data.Common.Id].Uid,
PlatformId: uidsMap.PlatformIds[data.RefStand].Uid,
})
}
//SPKS
for _, data := range storage.SpksSwitchs {
repo.Spkss = append(repo.Spkss, &proto.Spks{
Id: uidsMap.SpksIds[data.Common.Id].Uid,
Code: data.Code,
PlatformId: uidsMap.PlatformIds[data.RefStand].Uid,
})
}
}
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
}