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

957 lines
31 KiB
Go
Raw Normal View History

2023-08-01 14:54:11 +08:00
package memory
import (
"fmt"
"log/slog"
"math"
2023-09-21 14:54:27 +08:00
"sort"
"strconv"
"strings"
2023-09-22 11:29:56 +08:00
"sync"
"time"
2023-09-21 14:54:27 +08:00
rtss_simulation "joylink.club/rtsssimulation"
2023-09-27 14:15:11 +08:00
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
2023-09-21 14:54:27 +08:00
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/third_party/dynamics"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/semi_physical_train"
2023-09-21 14:54:27 +08:00
"joylink.club/ecs"
"joylink.club/rtsssimulation/repository"
"joylink.club/rtsssimulation/repository/model/proto"
)
2023-08-01 14:54:11 +08:00
// 轨旁仿真定义
type VerifySimulation struct {
//地图id
2023-09-19 11:02:50 +08:00
MapIds []int32
// 项目ID
ProjectId int32
2023-08-01 14:54:11 +08:00
//仿真id
SimulationId string
//仿真内存数据
Memory *WaysideMemory
//模型仓库
Repo *repository.Repository
//Rtss仿真世界的id
2023-09-26 10:25:01 +08:00
WorldId ecs.WorldId
World ecs.World
2023-09-25 17:05:17 +08:00
//设备UID映射
uidMap map[string]*elementIdStructure
2023-08-01 14:54:11 +08:00
}
2023-09-22 11:29:56 +08:00
// 轨旁仿真内存模型
type WaysideMemory struct {
//可变状态数据:轨旁仿真模型状态(全量数据)
Status *VerifyStatus
// 要变更的状态:用户操作过的状态记录在这里,增量推送次数据
ChangeStatus *ChangeVerifyStatus
//状态保护锁
rwLock *sync.RWMutex
}
// 轨旁仿真模型状态
type VerifyStatus struct {
//道岔状态key为道岔id即索引 state.SwitchState
SwitchStateMap sync.Map
//轨道状态key为轨道id即索引 state.LinkState
LinkStateMap sync.Map
//列车状态key为列车id即索引 state.TrainState
TrainStateMap sync.Map
//计轴区段状态key为计轴区段的id即索引 state.SectionState
AxleSectionStateMap sync.Map
//物理区段状态key为物理区段id即索引 state.SectionState
PhysicalSectionStateMap sync.Map
//逻辑区段状态key为逻辑区段id即索引 state.SectionState
LogicSectionStateMap sync.Map
//信号机状态key为信号机id,即索引 state.SignalState
SignalStateMap sync.Map
}
// 轨旁仿真模型状态(变更)
type ChangeVerifyStatus struct {
VerifyStatus
//删除的列车ID列表
RemoveTrainId []string
}
func NewWaysideMemory() *WaysideMemory {
return &WaysideMemory{
Status: &VerifyStatus{},
ChangeStatus: &ChangeVerifyStatus{},
rwLock: &sync.RWMutex{},
}
}
2023-08-01 14:54:11 +08:00
// 创建仿真对象
func CreateSimulation(projectId int32, mapIds []int32) (*VerifySimulation, error) {
//构建Repository
sort.Slice(mapIds, func(i, j int) bool {
return mapIds[i] < mapIds[j]
})
var mapIdStrSlice []string
for _, id := range mapIds {
mapIdStrSlice = append(mapIdStrSlice, strconv.Itoa(int(id)))
}
repoId := strings.Join(mapIdStrSlice, "|")
repoVersion := "0.1"
repo := repository.FindRepository(repoId, repoVersion)
if repo == nil {
protoRepo, err := buildProtoRepository(mapIds)
if err != nil {
return nil, err
}
2023-09-25 11:09:56 +08:00
protoRepo.Id, protoRepo.Version = repoId, repoVersion
newRepo, err := repository.BuildRepository(protoRepo)
if err != nil {
return nil, err
}
repo = newRepo
}
2023-09-22 11:29:56 +08:00
// 目前用本地构建状态
worldMemory := NewWaysideMemory()
initWorldDeviceState(worldMemory.Status, repo)
2023-09-25 17:05:17 +08:00
// 构建所有UID映射关系
allUidMap := buildRepositoryAllUidsMap(mapIds, repo)
//创建仿真
// worldId := world.CreateSimulation(repo)
w := rtss_simulation.NewSimulation(repo)
2023-09-28 18:24:36 +08:00
w.StartUp()
2023-08-01 14:54:11 +08:00
verifySimulation := &VerifySimulation{
2023-09-19 11:02:50 +08:00
MapIds: mapIds,
ProjectId: projectId,
2023-09-22 11:29:56 +08:00
Memory: worldMemory,
Repo: repo,
World: w,
WorldId: w.Id(),
2023-09-25 17:05:17 +08:00
uidMap: allUidMap,
2023-09-19 11:02:50 +08:00
}
return verifySimulation, nil
2023-08-01 14:54:11 +08:00
}
// 获取全量状态
2023-09-21 16:22:55 +08:00
func (s *VerifySimulation) GetAllState(mapId int32) *state.PushedDevicesStatus {
2023-09-25 17:05:17 +08:00
giType := QueryGiType(mapId)
switch giType {
case graphicData.PictureType_StationLayout:
return &state.PushedDevicesStatus{
All: true,
AllStatus: &state.AllDevicesStatus{
SwitchState: GetMapAllTurnoutState(s, mapId),
TrainState: GetAllTrainState(s),
SignalState: GetMapAllSignalState(s, mapId),
2023-10-18 13:53:17 +08:00
ButtonState: GetMapAllStationButtonState(s, mapId),
},
}
case graphicData.PictureType_RelayCabinetLayout:
return &state.PushedDevicesStatus{
All: true,
AllStatus: &state.AllDevicesStatus{
ReplyState: GetMapAllRelayState(s, mapId),
},
}
2023-09-25 17:05:17 +08:00
}
return &state.PushedDevicesStatus{}
}
// 获取门控箱状态
func (s *VerifySimulation) GetAllPSLState(mapId int32, boxId string) *state.PushedDevicesStatus {
return &state.PushedDevicesStatus{
All: true,
AllStatus: &state.AllDevicesStatus{
2023-10-17 17:51:26 +08:00
ButtonState: []*state.ButtonState{},
},
}
}
// 获取车站IBP状态
func (s *VerifySimulation) GetAllIBPState(mapId int32, stationCode string) *state.PushedDevicesStatus {
2023-10-17 17:51:26 +08:00
return &state.PushedDevicesStatus{
2023-10-18 13:53:17 +08:00
All: true,
AllStatus: GetMapAllIBPState(s, mapId, stationCode),
2023-10-17 17:51:26 +08:00
}
}
2023-09-21 14:54:27 +08:00
// 获取仿真世界信息
2023-09-21 15:26:47 +08:00
func (s *VerifySimulation) GetSimulationWorld() ecs.World {
2023-10-09 15:04:48 +08:00
return s.World
2023-09-21 14:54:27 +08:00
}
2023-09-25 17:05:17 +08:00
// 获取仿真世界信息
func (s *VerifySimulation) GetComIdByUid(uid string) string {
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 (sim *VerifySimulation) BuildLineBaseInfo() *message.LineBaseInfo {
info := &message.LineBaseInfo{}
for _, model := range sim.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, _ := strconv.Atoi(sim.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, _ := strconv.Atoi(sim.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 sim.Repo.SlopeList() {
id, _ := strconv.Atoi(sim.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 sim.Repo.SectionalCurvatureList() {
id, _ := strconv.Atoi(sim.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 (s *VerifySimulation) CollectDynamicsTurnoutInfo() []*message.DynamicsTurnoutInfo {
stateSlice := GetAllTurnoutState(s)
var turnoutStates []*message.DynamicsTurnoutInfo
for _, sta := range stateSlice {
code64, err := strconv.ParseUint(sta.Id, 10, 16)
if err != nil {
slog.Error("id转uint16报错", err)
}
info := message.DynamicsTurnoutInfo{
Code: uint16(code64),
NPosition: sta.Dw,
RPosition: sta.Fw,
}
turnoutStates = append(turnoutStates, &info)
}
return turnoutStates
}
// 处理动力学列车速度消息
func (s *VerifySimulation) HandleDynamicsTrainInfo(info *message.DynamicsTrainInfo) {
sta, ok := s.Memory.Status.TrainStateMap.Load(strconv.Itoa(int(info.Number)))
if !ok {
return
}
// 给半实物仿真发送速度
semi_physical_train.Default().SendTrainControlMessage(info)
// 更新列车状态
UpdateTrainState(s, convert(info, sta.(*state.TrainState), s))
}
func convert(info *message.DynamicsTrainInfo, sta *state.TrainState, simulation *VerifySimulation) *state.TrainState {
delayTime := time.Now().UnixMilli() - sta.VobcState.UpdateTime
sta.ControlDelayTime = (int64(sta.VobcState.LifeSignal)-int64(info.VobcLifeSignal))*20 + delayTime
slog.Debug("收到动力学原始消息", "Number", info.Number, "Link", info.Link, "LinkOffset", info.LinkOffset)
id, port, offset, runDirection, pointTo, kilometer := QueryDeviceByCalcLink(simulation.Repo, strconv.Itoa(int(info.Link)), int64(info.LinkOffset), info.Up)
slog.Debug("处理动力学转换后的消息", "number", info.Number, "车头位置", id, "偏移", offset, "是否上行", runDirection, "是否ab", pointTo)
sta.HeadDeviceId = simulation.GetComIdByUid(id)
sta.DevicePort = port
sta.HeadOffset = offset
sta.PointTo = pointTo
sta.TrainKilometer = kilometer
sta.RunDirection = runDirection
//判定车头方向
sta.HeadDirection = runDirection
if sta.VobcState != nil {
if sta.VobcState.DirectionForward {
sta.HeadDirection = runDirection
} else if sta.VobcState.DirectionBackward {
sta.HeadDirection = !runDirection
}
}
if info.Speed < 0 {
sta.RunDirection = !sta.RunDirection
}
// 赋值动力学信息
sta.DynamicState.Heartbeat = int32(info.LifeSignal)
sta.DynamicState.HeadLinkId = strconv.Itoa(int(info.Link))
sta.DynamicState.HeadLinkOffset = int64(info.LinkOffset)
sta.DynamicState.Slope = int32(info.Slope)
sta.DynamicState.Upslope = info.UpSlope
sta.DynamicState.RunningUp = info.Up
sta.DynamicState.RunningResistanceSum = float32(info.TotalResistance) / 1000
sta.DynamicState.AirResistance = float32(info.AirResistance) / 1000
sta.DynamicState.RampResistance = float32(info.SlopeResistance) / 1000
sta.DynamicState.CurveResistance = float32(info.CurveResistance) / 1000
sta.DynamicState.Speed = speedParse(info.Speed)
sta.DynamicState.HeadSensorSpeed1 = speedParse(info.HeadSpeed1)
sta.DynamicState.HeadSensorSpeed2 = speedParse(info.HeadSpeed2)
sta.DynamicState.TailSensorSpeed1 = speedParse(info.TailSpeed1)
sta.DynamicState.TailSensorSpeed2 = speedParse(info.TailSpeed2)
sta.DynamicState.HeadRadarSpeed = speedParse(info.HeadRadarSpeed)
sta.DynamicState.TailRadarSpeed = speedParse(info.TailRadarSpeed)
sta.DynamicState.Acceleration = info.Acceleration
return sta
}
// 发送给前端的速度格式化
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.TrainState)
if !train.Show { // 下线列车
return false
}
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)
train.VobcState = controlMessage.ControlInfo
return true
})
}
func buildProtoRepository(mapIds []int32) (*proto.Repository, error) {
repo := &proto.Repository{}
var exceptStationGiMapIds []int32
//创建设备
for _, mapId := range mapIds {
giType := QueryGiType(mapId)
if giType == graphicData.PictureType_StationLayout {
stationGi := QueryGiData[*graphicData.RtssGraphicStorage](mapId)
fillProtoRepository(repo, stationGi, mapId)
} else {
exceptStationGiMapIds = append(exceptStationGiMapIds, mapId)
}
}
//构建并关联电子元件
for _, mapId := range exceptStationGiMapIds {
giType := QueryGiType(mapId)
if giType == graphicData.PictureType_RelayCabinetLayout {
relayGi := QueryGiData[*graphicData.RelayCabinetGraphicStorage](mapId)
buildAndRelateElectronicComponent(repo, relayGi, mapId)
}
}
return repo, nil
}
func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *graphicData.RelayCabinetGraphicStorage, mapId int32) {
uidsMap := queryUidStructure[*relayUidStructure](mapId)
city := relayGi.UniqueIdPrefix.City
lineId := relayGi.UniqueIdPrefix.LineId
station := relayGi.UniqueIdPrefix.BelongsConcentrationStation
for _, relay := range relayGi.Relays {
repo.Relays = append(repo.Relays, &proto.Relay{
2023-09-22 15:41:10 +08:00
Id: uidsMap.RelayIds[relay.Common.Id].Uid,
Code: relay.Code,
Model: convertRelayModel(relay.NewModel),
})
}
for _, pfp := range relayGi.PhaseFailureProtectors {
repo.PhaseFailureProtectors = append(repo.PhaseFailureProtectors, &proto.PhaseFailureProtector{
Id: uidsMap.RelayIds[pfp.Common.Id].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
}
for _, relationship := range relayGi.DeviceRelateRelayList {
2023-09-26 09:34:23 +08:00
switch relationship.DeviceType {
case graphicData.RelatedRef_Turnout:
turnout := turnoutMap[GenerateElementUid(city, lineId, []string{station}, relationship.Code)]
2023-09-26 10:25:01 +08:00
if turnout == nil {
continue
}
for _, group := range relationship.Combinationtypes {
var componentIds []string
for _, relayId := range group.RefRelays {
2023-09-27 14:15:11 +08:00
if uidsMap.RelayIds[relayId] == nil {
continue
}
componentIds = append(componentIds, uidsMap.RelayIds[relayId].Uid)
}
turnout.ElectronicComponentGroups = append(turnout.ElectronicComponentGroups,
&proto.ElectronicComponentGroup{
Code: group.Code,
ComponentIds: componentIds,
})
}
2023-09-26 09:34:23 +08:00
case graphicData.RelatedRef_signal:
signal := signalMap[GenerateElementUid(city, lineId, []string{station}, relationship.Code)]
2023-09-26 10:25:01 +08:00
if signal == nil {
continue
}
2023-10-16 14:06:47 +08:00
//信号机只有一个组合类型
if len(relationship.Combinationtypes) != 1 {
panic(fmt.Sprintf("信号机[%s]须有一个组合类型", signal.Id))
}
group := relationship.Combinationtypes[0]
var componentIds []string
for _, relayId := range group.RefRelays {
if uidsMap.RelayIds[relayId] == nil {
continue
}
2023-10-16 14:06:47 +08:00
componentIds = append(componentIds, uidsMap.RelayIds[relayId].Uid)
}
2023-10-16 14:06:47 +08:00
signal.Code = group.Code
signal.ElectronicComponentGroups = append(signal.ElectronicComponentGroups,
&proto.ElectronicComponentGroup{
Code: group.Code,
ComponentIds: componentIds,
})
case graphicData.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 {
2023-09-27 14:15:11 +08:00
if uidsMap.RelayIds[relayId] == nil {
continue
}
d.Components = append(d.Components, &proto.ElectronicComponent{
Id: uidsMap.RelayIds[relayId].Uid,
DeviceType: proto.DeviceType_DeviceType_Relay,
})
}
station.ElectronicGroup = append(station.ElectronicGroup, d)
}
}
}
}
func convertRelayModel(modelType graphicData.Relay_ModelType) proto.Relay_Model {
switch modelType {
case graphicData.Relay_Unknown:
return proto.Relay_Unknown
case graphicData.Relay_JPXC_1000:
return proto.Relay_JPXC_1000
case graphicData.Relay_JPXC_1700:
return proto.Relay_JPXC_1700
case graphicData.Relay_JWJXC_480:
return proto.Relay_JWJXC_480
case graphicData.Relay_JWJXC_H125_80:
return proto.Relay_JWJXC_H125_80
case graphicData.Relay_JWXC_1700:
return proto.Relay_JWXC_1700
case graphicData.Relay_JWXC_H340:
return proto.Relay_JWXC_H340
case graphicData.Relay_JYJXC_160_260:
return proto.Relay_JYJXC_160_260
case graphicData.Relay_JZXC_H18:
return proto.Relay_JZXC_H18
default:
panic(fmt.Sprintf("意料之外的继电器型号:%s", modelType))
}
}
2023-09-21 14:54:27 +08:00
func fillProtoRepository(repo *proto.Repository, storage *graphicData.RtssGraphicStorage, mapId int32) {
axleCountingMap := make(map[string]*graphicData.AxleCounting)
2023-09-22 15:15:04 +08:00
uidsMap := queryUidStructure[*stationUidStructure](mapId)
for _, data := range storage.AxleCountings {
axleCountingMap[data.Common.Id] = data
cpType := proto.CheckPointType_AxleCounter
2023-09-21 14:54:27 +08:00
if data.Type == graphicData.AxleCounting_SectionBoundary {
cpType = proto.CheckPointType_Boundary
}
cp := &proto.CheckPoint{
2023-09-21 17:57:50 +08:00
Id: data.Common.Id,
Km: convertKm(data.KilometerSystem),
Type: cpType,
DevicePorts: convertDevicePorts(data.AxleCountingRef),
}
2023-09-21 17:57:50 +08:00
repo.CheckPoints = append(repo.CheckPoints, converCheckPointUid(cp, uidsMap))
}
for _, data := range storage.Section {
var turnoutIds []string
if data.SectionType == graphicData.Section_TurnoutPhysical {
turnoutIds = findTurnoutIds(axleCountingMap, data.AxleCountings)
}
physicalSection := &proto.PhysicalSection{
2023-09-21 17:57:50 +08:00
Id: data.Common.Id,
ADevicePort: convertDevicePort(data.PaRef),
BDevicePort: convertDevicePort(data.PbRef),
TurnoutIds: turnoutIds,
}
2023-09-21 17:57:50 +08:00
repo.PhysicalSections = append(repo.PhysicalSections, converSectionUid(physicalSection, uidsMap))
}
for _, data := range storage.Turnouts {
var km *proto.Kilometer
for _, ks := range data.KilometerSystem {
if ks.Kilometer != 0 {
km = convertKm(ks)
break
}
}
2023-09-28 17:45:08 +08:00
var switchMachineType proto.Turnout_SwitchMachineType
switch data.SwitchMachineType {
case graphicData.Turnout_ZDJ9_Single:
switchMachineType = proto.Turnout_ZDJ9_Single
case graphicData.Turnout_ZDJ9_Double:
switchMachineType = proto.Turnout_ZDJ9_Double
}
turnout := &proto.Turnout{
2023-09-28 17:45:08 +08:00
Id: data.Common.Id,
Km: km,
ADevicePort: convertDevicePort(data.PaRef),
BDevicePort: convertDevicePort(data.PbRef),
CDevicePort: convertDevicePort(data.PcRef),
SwitchMachineType: switchMachineType,
}
2023-09-21 17:57:50 +08:00
repo.Turnouts = append(repo.Turnouts, converTurnoutUid(turnout, uidsMap))
}
for _, data := range storage.Signals {
var sectionId string
var turnoutPort *proto.DevicePort
switch data.RefDev.DeviceType {
case graphicData.RelatedRef_Section:
sectionId = data.RefDev.Id
case graphicData.RelatedRef_Turnout:
turnoutPort = convertDevicePort(data.RefDev)
}
signal := &proto.Signal{
2023-09-21 17:57:50 +08:00
Id: data.Common.Id,
Km: convertKm(data.KilometerSystem),
SectionId: sectionId,
TurnoutPort: turnoutPort,
}
2023-09-21 17:57:50 +08:00
repo.Signals = append(repo.Signals, converSignalUid(signal, uidsMap))
}
for _, data := range storage.Transponders {
var sectionId string
var turnoutPort *proto.DevicePort
switch data.TransponderRef.DeviceType {
case graphicData.RelatedRef_Section:
sectionId = data.TransponderRef.Id
case graphicData.RelatedRef_Turnout:
turnoutPort = convertDevicePort(data.TransponderRef)
}
responder := &proto.Transponder{
2023-09-21 17:57:50 +08:00
Id: data.Common.Id,
Km: convertKm(data.KilometerSystem),
SectionId: sectionId,
TurnoutPort: turnoutPort,
}
2023-09-21 17:57:50 +08:00
repo.Transponders = append(repo.Transponders, converTransponderUid(responder, uidsMap))
}
slopeKsMap := make(map[string]*graphicData.SlopeKiloMarker)
for _, data := range storage.SlopeKiloMarker {
slopeKsMap[data.Common.Id] = data
}
curveKsMap := make(map[string]*graphicData.CurvatureKiloMarker)
for _, data := range storage.CurvatureKiloMarker {
curveKsMap[data.Common.Id] = 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{
2023-09-21 17:57:50 +08:00
Id: data.Common.Id,
Kms: kms,
Degree: data.SlopeNumber,
}
2023-09-21 17:57:50 +08:00
repo.Slopes = append(repo.Slopes, converSlopeUid(slope, uidsMap))
}
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{
2023-09-21 17:57:50 +08:00
Id: data.Common.Id,
Kms: kms,
Radius: data.CurvatureNumber,
}
2023-09-21 17:57:50 +08:00
repo.SectionalCurvatures = append(repo.SectionalCurvatures, converCurvatureUid(slope, uidsMap))
}
2023-09-26 09:34:23 +08:00
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[data.Common.Id].Uid,
Code: data.Code,
ButtonType: proto.Button_Reset_Press,
})
}
// 车站关联关系
relateMap := make(map[string]*graphicData.StationRelateDevice)
for _, data := range storage.StationRelateDeviceList {
relateMap[data.Code] = data
}
// 处理车站信息
for _, data := range storage.Stations {
station := &proto.Station{
Id: uidsMap.StationIds[data.Common.Id].Uid,
Code: data.Code,
}
// 关联车站的设备
refs, ok := relateMap[data.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(uidsMap, station, repo, data.RefIbpMapCode)
repo.Stations = append(repo.Stations, station)
}
}
// 将IBP的设备关联到车站中
func handlerIBPDeviceToStation(uidsMap *stationUidStructure, station *proto.Station, repo *proto.Repository, ibpMap string) {
storage := getStorageIBPMapData(ibpMap)
if storage == nil {
return
}
ibpIdMap := uidsMap.IBPIds[station.Code] // 车站对应的UID集合
typeMap := make(map[string]proto.DeviceType) // 对应的设备类型
for _, data := range storage.IbpButtons { // 处理按钮
buttonType := proto.Button_NO_Reset_Press
if data.IsSelfReset {
buttonType = proto.Button_Reset_Press
}
b := &proto.Button{
Id: ibpIdMap[data.Common.Id].Uid,
Code: data.Code,
ButtonType: buttonType,
2023-10-18 14:09:36 +08:00
HasLight: data.HasLight,
}
typeMap[data.Common.Id] = proto.DeviceType_DeviceType_Button
repo.Buttons = append(repo.Buttons, b)
}
for _, data := range storage.IbpKeys { // 钥匙
b := &proto.Button{
Id: ibpIdMap[data.Common.Id].Uid,
Code: data.Code,
ButtonType: proto.Button_Key_Knob,
}
typeMap[data.Common.Id] = proto.DeviceType_DeviceType_Button
repo.Buttons = append(repo.Buttons, b)
}
for _, data := range storage.IbpAlarms { // 报警器
b := &proto.Alarm{
Id: ibpIdMap[data.Common.Id].Uid,
Code: data.Code,
}
typeMap[data.Common.Id] = proto.DeviceType_DeviceType_Alarm
repo.Alarms = append(repo.Alarms, b)
}
for _, data := range storage.IbpLights { // 指示灯
b := &proto.Light{
Id: ibpIdMap[data.Common.Id].Uid,
Code: data.Code,
Aspect: converIbpLightAspect(data.Color),
}
typeMap[data.Common.Id] = 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 := typeMap[d]
if !ok {
slog.Debug("IBP组合类型类型不确定id:%s", d)
continue
}
group.Components = append(group.Components, &proto.ElectronicComponent{
Id: ibpIdMap[d].Uid,
DeviceType: deviceType,
})
}
station.ElectronicGroup = append(station.ElectronicGroup, group)
}
}
}
// 将IBP的灯颜色转换成repo灯颜色
func converIbpLightAspect(color graphicData.IbpLight_IbpLightColor) proto.Light_LightAspect {
switch color {
case graphicData.IbpLight_white:
return proto.Light_B
case graphicData.IbpLight_red:
return proto.Light_H
case graphicData.IbpLight_green:
return proto.Light_L
case graphicData.IbpLight_blue:
return proto.Light_A
default:
panic(&dto.ErrorDto{Code: dto.ArgumentParseError, Message: "未知的灯颜色类型" + color.String()})
}
}
2023-09-22 15:15:04 +08:00
func converCheckPointUid(data *proto.CheckPoint, uidsMap *stationUidStructure) *proto.CheckPoint {
2023-09-21 17:57:50 +08:00
data.Id = uidsMap.AxlePointIds[data.Id].Uid
for _, c := range data.DevicePorts {
c.DeviceId = converRefUid(c.DeviceId, c.DeviceType, uidsMap)
}
return data
}
2023-09-22 15:15:04 +08:00
func converSectionUid(data *proto.PhysicalSection, uidsMap *stationUidStructure) *proto.PhysicalSection {
2023-09-21 17:57:50 +08:00
data.Id = uidsMap.PhysicalSectionIds[data.Id].Uid
if data.ADevicePort != nil {
data.ADevicePort.DeviceId = converRefUid(data.ADevicePort.DeviceId, data.ADevicePort.DeviceType, uidsMap)
}
if data.BDevicePort != nil {
data.BDevicePort.DeviceId = converRefUid(data.BDevicePort.DeviceId, data.BDevicePort.DeviceType, uidsMap)
}
tids := make([]string, len(data.TurnoutIds))
for i, tid := range data.TurnoutIds {
tids[i] = converRefUid(tid, proto.DeviceType_DeviceType_Turnout, uidsMap)
}
data.TurnoutIds = tids
return data
}
2023-09-22 15:15:04 +08:00
func converTurnoutUid(data *proto.Turnout, uidsMap *stationUidStructure) *proto.Turnout {
2023-09-21 17:57:50 +08:00
data.Id = uidsMap.TurnoutIds[data.Id].Uid
if data.ADevicePort != nil {
data.ADevicePort.DeviceId = converRefUid(data.ADevicePort.DeviceId, data.ADevicePort.DeviceType, uidsMap)
}
if data.BDevicePort != nil {
data.BDevicePort.DeviceId = converRefUid(data.BDevicePort.DeviceId, data.BDevicePort.DeviceType, uidsMap)
}
if data.CDevicePort != nil {
data.CDevicePort.DeviceId = converRefUid(data.CDevicePort.DeviceId, data.CDevicePort.DeviceType, uidsMap)
}
return data
}
2023-09-22 15:15:04 +08:00
func converSignalUid(data *proto.Signal, uidsMap *stationUidStructure) *proto.Signal {
2023-09-21 17:57:50 +08:00
data.Id = uidsMap.SignalIds[data.Id].Uid
if data.SectionId != "" {
data.SectionId = converRefUid(data.SectionId, proto.DeviceType_DeviceType_PhysicalSection, uidsMap)
}
if data.TurnoutPort != nil {
data.TurnoutPort.DeviceId = converRefUid(data.TurnoutPort.DeviceId, data.TurnoutPort.DeviceType, uidsMap)
}
return data
}
2023-09-22 15:15:04 +08:00
func converTransponderUid(data *proto.Transponder, uidsMap *stationUidStructure) *proto.Transponder {
2023-09-21 17:57:50 +08:00
data.Id = uidsMap.TransponderIds[data.Id].Uid
if data.SectionId != "" {
data.SectionId = converRefUid(data.SectionId, proto.DeviceType_DeviceType_PhysicalSection, uidsMap)
}
if data.TurnoutPort != nil {
data.TurnoutPort.DeviceId = converRefUid(data.TurnoutPort.DeviceId, data.TurnoutPort.DeviceType, uidsMap)
}
return data
}
2023-09-22 15:15:04 +08:00
func converSlopeUid(data *proto.Slope, uidsMap *stationUidStructure) *proto.Slope {
2023-09-21 17:57:50 +08:00
data.Id = uidsMap.SlopeIds[data.Id].Uid
return data
}
2023-09-22 15:15:04 +08:00
func converCurvatureUid(data *proto.SectionalCurvature, uidsMap *stationUidStructure) *proto.SectionalCurvature {
2023-09-21 17:57:50 +08:00
data.Id = uidsMap.CurvatureIds[data.Id].Uid
return data
}
2023-09-22 15:15:04 +08:00
func converRefUid(id string, d proto.DeviceType, uidsMap *stationUidStructure) string {
var elementId *elementIdStructure
2023-09-21 17:57:50 +08:00
switch d {
case proto.DeviceType_DeviceType_CheckPoint:
elementId = uidsMap.AxlePointIds[id]
case proto.DeviceType_DeviceType_PhysicalSection:
elementId = uidsMap.PhysicalSectionIds[id]
case proto.DeviceType_DeviceType_SectionalCurvature:
elementId = uidsMap.CurvatureIds[id]
case proto.DeviceType_DeviceType_Signal:
elementId = uidsMap.SignalIds[id]
case proto.DeviceType_DeviceType_Slope:
elementId = uidsMap.SlopeIds[id]
case proto.DeviceType_DeviceType_Transponder:
elementId = uidsMap.TransponderIds[id]
case proto.DeviceType_DeviceType_Turnout:
elementId = uidsMap.TurnoutIds[id]
default:
panic(&dto.ErrorDto{Code: dto.ArgumentParseError, Message: "异常的设备类型-" + d.String()})
}
return elementId.Uid
}
func convertKm(ks *graphicData.KilometerSystem) *proto.Kilometer {
var dir proto.Direction
switch ks.Direction {
case graphicData.Direction_LEFT:
dir = proto.Direction_LEFT
case graphicData.Direction_RIGHT:
dir = proto.Direction_RIGHT
}
return &proto.Kilometer{
Value: ks.Kilometer,
CoordinateSystem: ks.CoordinateSystem,
Direction: dir,
}
}
func convertDevicePort(ref *graphicData.RelatedRef) *proto.DevicePort {
if ref == nil {
return nil
}
var deviceType proto.DeviceType
var port proto.Port
switch ref.DevicePort {
case graphicData.RelatedRef_A:
port = proto.Port_A
case graphicData.RelatedRef_B:
port = proto.Port_B
case graphicData.RelatedRef_C:
port = proto.Port_C
}
switch ref.DeviceType {
case graphicData.RelatedRef_Section:
deviceType = proto.DeviceType_DeviceType_PhysicalSection
case graphicData.RelatedRef_Turnout:
deviceType = proto.DeviceType_DeviceType_Turnout
default:
panic(fmt.Sprintf("异常的设备类型-%s", ref.DeviceType))
}
return &proto.DevicePort{
DeviceId: ref.Id,
DeviceType: deviceType,
Port: port,
}
}
func convertDevicePorts(refList []*graphicData.RelatedRef) []*proto.DevicePort {
var dps []*proto.DevicePort
for _, ref := range refList {
dps = append(dps, convertDevicePort(ref))
}
return dps
}
func findTurnoutIds(axleCountingMap map[string]*graphicData.AxleCounting, axleIds []string) []string {
if len(axleIds) <= 2 {
return nil
}
turnoutMap := make(map[string]bool)
for _, axleId := range axleIds {
axle := axleCountingMap[axleId]
relTurnoutCount := 0
var turnoutId string
for _, ref := range axle.AxleCountingRef {
if ref.DeviceType == graphicData.RelatedRef_Turnout {
relTurnoutCount++
turnoutId = ref.Id
}
}
if relTurnoutCount == 1 {
turnoutMap[turnoutId] = true
}
}
var turnoutIds []string
2023-09-21 14:54:27 +08:00
for id := range turnoutMap {
turnoutIds = append(turnoutIds, id)
}
return turnoutIds
}
2023-09-22 11:29:56 +08:00
func initWorldDeviceState(status *VerifyStatus, repo *repository.Repository) {
initWorldTurnoutState(status, repo)
initWorldPhysicalSectionState(status, repo)
}
// 初始化道岔状态
func initWorldTurnoutState(status *VerifyStatus, repo *repository.Repository) {
for _, turnout := range repo.TurnoutList() {
id := turnout.Identity.Id()
status.SwitchStateMap.Store(id, &state.SwitchState{Id: id, Normal: true, Reverse: false})
}
}
// 初始化物理区段状态
func initWorldPhysicalSectionState(status *VerifyStatus, repo *repository.Repository) {
for _, section := range repo.PhysicalSectionList() {
id := section.Identity.Id()
status.PhysicalSectionStateMap.Store(id, &state.SectionState{Id: id, Occupied: false, Type: state.SectionType_Physic})
}
}