From 5fa53459815e95ade5614d2f1539eb2be2b0f289 Mon Sep 17 00:00:00 2001 From: thesai <1021828630@qq.com> Date: Wed, 7 Aug 2024 14:53:57 +0800 Subject: [PATCH] =?UTF-8?q?[=E8=A1=A5=E5=85=85]11=E5=8F=B7=E7=BA=BF?= =?UTF-8?q?=E8=81=94=E9=94=81=E9=80=9A=E4=BF=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config.go | 1 + rts-sim-module | 2 +- rts-sim-testing-message | 2 +- third_party/interlock/beijing11/msg.go | 180 +++++--- third_party/interlock/beijing11/msg_test.go | 2 +- third_party/interlock/beijing11/repo.go | 70 +-- third_party/interlock/beijing11/service.go | 409 +++++++++++++----- .../wayside/memory/wayside_memory_map_init.go | 350 ++++++++------- .../wayside/memory/wayside_simulation.go | 125 +++--- ts/test_simulation_manage.go | 2 +- 10 files changed, 710 insertions(+), 433 deletions(-) diff --git a/config/config.go b/config/config.go index f4b7dba..fda4bae 100644 --- a/config/config.go +++ b/config/config.go @@ -126,6 +126,7 @@ type InterlockConfig struct { RemotePort int `json:"remotePort" description:"远端接收采集信息端口"` Code string `json:"code" description:"所属集中站"` Line string `json:"line" description:"联锁通信协议所属线路"` + Period int `json:"period" description:"采集任务执行周期(ms)"` } type ElectricMachineryConfig struct { Ip string `json:"ip" description:"IP配置"` diff --git a/rts-sim-module b/rts-sim-module index 3182e86..86c0288 160000 --- a/rts-sim-module +++ b/rts-sim-module @@ -1 +1 @@ -Subproject commit 3182e867c12d73bd4c75182459d3b9fae670653c +Subproject commit 86c02883c4993bf829599c7516862009077d586b diff --git a/rts-sim-testing-message b/rts-sim-testing-message index 0c2a761..47ecc9c 160000 --- a/rts-sim-testing-message +++ b/rts-sim-testing-message @@ -1 +1 @@ -Subproject commit 0c2a7613104f859e83091d1f6379e6e2fa1990ad +Subproject commit 47ecc9c79f31758a6421dab4a7099690a3c7b649 diff --git a/third_party/interlock/beijing11/msg.go b/third_party/interlock/beijing11/msg.go index 5ea7561..171cb9c 100644 --- a/third_party/interlock/beijing11/msg.go +++ b/third_party/interlock/beijing11/msg.go @@ -4,11 +4,24 @@ import ( "encoding/binary" ) +const ( //不知道对不对,问也不回,先瞎写吧 + ON = 0x55 //按钮-按下;道岔-定位;屏蔽门-关门;计轴区段-占用 + OFF = 0xAA //按钮-抬起;道岔-反位;屏蔽门-开门;计轴区段-出清 +) + +func GetStateByte(state bool) byte { + if state { + return ON + } else { + return OFF + } +} + // FromInterlockFrame 来自联锁的数据帧 type FromInterlockFrame struct { Len uint16 - InterlockCode uint16 //联锁ID - WaysideCode uint16 //轨旁ID + InterlockCode uint16 //联锁编号(联锁->轨旁:OC的编号,轨旁->联锁:联锁站编号) + WaysideCode uint16 //轨旁编号 TurnoutData *DeviceData //道岔数据 PSDData *DeviceData //屏蔽门数据 ESBData *ESBData //紧急停车按钮数据 @@ -187,75 +200,66 @@ type DeviceCmd struct { // ToInterlockFrame 发往联锁的数据帧 type ToInterlockFrame struct { - Len uint16 - WaysideCode uint16 - InterlockCode uint16 - TurnoutData *ToInterlockTurnoutData //道岔数据 - PSDData *ToInterlockPSDData //屏蔽门数据 - ESBData *ToInterlockESBData //紧急停车按钮数据 - HoldTrainData *ToInterlockHoldTrainData //扣车按钮数据 - SignalData *ToInterlockSignalData //信号机数据 - AxleSectionData *ToInterlockAxleSectionData //计轴区段数据 - WrzfData *ToInterlockWrzfData //无人折返数据 - FymData *ToInterlockFymData //防淹门数据 - SPKSData *ToInterlockSPKSData //SPKS数据 - CkmData *ToInterlockCkmData //车库门数据 - XcjData *ToInterlockXcjData //洗车机数据 + WaysideCode uint16 + InterlockCode uint16 + TurnoutStates []*TurnoutState //道岔状态 + PsdStates []*PSDState //屏蔽门状态 + ESBStates []*ESBState //紧急停车按钮状态 + //HoldTrainData []*HoldTrainState //扣车按钮状态(数量0) + SignalStates []*SignalState //信号机状态 + AxleSectionStates []*AxleSectionState //计轴区段状态 + //WrzfData []*WrzfState //无人折返状态(数量0) + //FymData []*FymState //防淹门状态(数量0) + SPKSStates []*SPKSState //SPKS状态 + //CkmData []*CkmState //车库门状态(数量0) + //XcjData []*XcjState //洗车机状态(无) } -type ToInterlockTurnoutData struct { - Num uint16 //该联锁集中区包含的道岔数量 - StateList []*TurnoutState -} - -type ToInterlockPSDData struct { - Num uint16 //该联锁集中区包含的屏蔽门数量 - StateList []*PSDState -} - -type ToInterlockESBData struct { - Num uint16 //紧急停车按钮数量 - StateList []*ESBState -} - -type ToInterlockHoldTrainData struct { - Num uint16 //扣车数量 - StateList []*HoldTrainState -} - -type ToInterlockSignalData struct { - Num uint16 //该联锁集中区信号机的数量 - StateList []*SignalState -} - -type ToInterlockAxleSectionData struct { - Num uint16 //该联锁集中区计轴区段的数量 - StateList []*AxleSectionState -} - -type ToInterlockWrzfData struct { - Num uint16 //该联锁集中区无人折返的数量 - StateList []*WrzfState -} - -type ToInterlockFymData struct { - Num uint16 //该联锁集中区防��门的数量 - StateList []*FymState -} - -type ToInterlockSPKSData struct { - Num uint16 //SPKS数量 - StateList []*SPKSState -} - -type ToInterlockCkmData struct { - Num uint16 //车库门数量 - StateList []*CkmState -} - -type ToInterlockXcjData struct { - Num uint16 //洗车机数量 - StateList []*XcjState +func (t *ToInterlockFrame) encode() []byte { + data := make([]byte, 0, 128) + data = append(data, 0x83) //报文类型 + data = append(data, 0, 0) //报文长度占位 + data = binary.BigEndian.AppendUint16(data, t.WaysideCode) + data = binary.BigEndian.AppendUint16(data, t.InterlockCode) + //道岔 + data = binary.BigEndian.AppendUint16(data, uint16(len(t.TurnoutStates))) + for _, state := range t.TurnoutStates { + data = state.encode(data) + } + //屏蔽门 + data = binary.BigEndian.AppendUint16(data, uint16(len(t.PsdStates))) + for _, state := range t.PsdStates { + data = state.encode(data) + } + //紧急停车 + data = binary.BigEndian.AppendUint16(data, uint16(len(t.ESBStates))) + for _, state := range t.ESBStates { + data = state.encode(data) + } + //扣车,数量0 + data = binary.BigEndian.AppendUint16(data, 0) + //信号机状态 + binary.BigEndian.AppendUint16(data, uint16(len(t.SignalStates))) + for _, state := range t.SignalStates { + data = state.encode(data) + } + //计轴区段 + binary.BigEndian.AppendUint16(data, uint16(len(t.AxleSectionStates))) + for _, state := range t.AxleSectionStates { + data = state.encode(data) + } + //无人折返,数量0 + data = binary.BigEndian.AppendUint16(data, 0) + //防淹门,数量0 + data = binary.BigEndian.AppendUint16(data, 0) + //SPKS + data = binary.BigEndian.AppendUint16(data, uint16(len(t.SPKSStates))) + for _, state := range t.SPKSStates { + data = state.encode(data) + } + //车库门,数量0 + data = binary.BigEndian.AppendUint16(data, 0) + return data } type TurnoutState struct { @@ -266,6 +270,12 @@ type TurnoutState struct { Current2 byte //转辙机2电流值,单位A } +func (s *TurnoutState) encode(data []byte) []byte { + data = binary.BigEndian.AppendUint16(data, s.Id) + data = append(data, s.State, s.Alarm, s.Current1, s.Current2) + return data +} + type PSDState struct { Id uint16 //屏蔽门ID State byte //屏蔽门开关门状态 @@ -275,11 +285,23 @@ type PSDState struct { DPB byte //DPB状态 } +func (s *PSDState) encode(data []byte) []byte { + data = binary.BigEndian.AppendUint16(data, s.Id) + data = append(data, s.State, s.Hsjc, s.PCB, s.POB, s.DPB) + return data +} + type ESBState struct { Id uint16 //紧急停车ID State byte //紧急停车按钮状态 PlState byte //紧急停车按钮旁路状态 - ESS byte //ESS状态(按下55,抬起aa) + //ESS byte //ESS状态(按下55,抬起aa)(解析驱动数据,没有此状态对应的驱动) +} + +func (s *ESBState) encode(data []byte) []byte { + data = binary.BigEndian.AppendUint16(data, s.Id) + data = append(data, s.State, s.PlState) + return data } type HoldTrainState struct { @@ -296,11 +318,23 @@ type SignalState struct { Current byte //信号机当前亮灯的电流值 } +func (s *SignalState) encode(data []byte) []byte { + data = binary.BigEndian.AppendUint16(data, s.Id) + data = append(data, s.State, s.Current) + return data +} + type AxleSectionState struct { Id uint16 //计轴区段Id State byte //计轴区段的采集状态 } +func (s *AxleSectionState) encode(data []byte) []byte { + data = binary.BigEndian.AppendUint16(data, s.Id) + data = append(data, s.State) + return data +} + type WrzfState struct { Id uint16 //无人折返ID State byte //无人折返的采集状态 @@ -318,6 +352,12 @@ type SPKSState struct { PlState byte //SPKSPL按钮状态 } +func (s *SPKSState) encode(data []byte) []byte { + data = binary.BigEndian.AppendUint16(data, s.Id) + data = append(data, s.State, s.PlState) + return data +} + type CkmState struct { Id uint16 //车库门ID State byte //车库门采集状态 diff --git a/third_party/interlock/beijing11/msg_test.go b/third_party/interlock/beijing11/msg_test.go index 6a38504..9556f1b 100644 --- a/third_party/interlock/beijing11/msg_test.go +++ b/third_party/interlock/beijing11/msg_test.go @@ -43,7 +43,7 @@ func TestFromInterlockFrame_Decode(t *testing.T) { } marshal, _ := json.Marshal(f) fmt.Println(string(marshal)) - //if f.InterlockCode != interlockCode { + //if f.WaysideCode != interlockCode { // t.Error() //} //if f.WaysideCode != waysideCode { diff --git a/third_party/interlock/beijing11/repo.go b/third_party/interlock/beijing11/repo.go index 20d0162..28ee667 100644 --- a/third_party/interlock/beijing11/repo.go +++ b/third_party/interlock/beijing11/repo.go @@ -1,35 +1,49 @@ package beijing11 -// StationDeviceIndexRepo 联锁站设备索引映射 -// key为联锁编号,val为uid -type StationDeviceIndexRepo struct { - StationName string - TurnoutMap map[uint32]string - PsdMap map[uint32]string - EsbMap map[uint32]string - HoldTrainMap map[uint32]string - SignalMap map[uint32]string - AxleSectionMap map[uint32]string - WrzfMap map[uint32]string - FymMap map[uint32]string - SpksMap map[uint32]string - CkmMap map[uint32]string - XcjMap map[uint32]string +// StationDeviceIndexTable 联锁站设备索引表 +type StationDeviceIndexTable struct { + StationName string //地图数据中车站的Code属性 + WaysideCode string //通信数据中的“轨旁编号” + TurnoutMap map[uint32]*Row + PsdMap map[uint32]*Row + EsbMap map[uint32]*Row + HoldTrainMap map[uint32]*Row + SignalMap map[uint32]*Row + AxleSectionMap map[uint32]*Row + WrzfMap map[uint32]*Row + FymMap map[uint32]*Row + SpksMap map[uint32]*Row + CkmMap map[uint32]*Row + XcjMap map[uint32]*Row } -func NewStationDeviceIndexRepo() *StationDeviceIndexRepo { - return &StationDeviceIndexRepo{ +func NewStationDeviceIndexTable() *StationDeviceIndexTable { + return &StationDeviceIndexTable{ StationName: "", - TurnoutMap: make(map[uint32]string), - PsdMap: make(map[uint32]string), - EsbMap: make(map[uint32]string), - HoldTrainMap: make(map[uint32]string), - SignalMap: make(map[uint32]string), - AxleSectionMap: make(map[uint32]string), - WrzfMap: make(map[uint32]string), - FymMap: make(map[uint32]string), - SpksMap: make(map[uint32]string), - CkmMap: make(map[uint32]string), - XcjMap: make(map[uint32]string), + WaysideCode: "", + TurnoutMap: make(map[uint32]*Row), + PsdMap: make(map[uint32]*Row), + EsbMap: make(map[uint32]*Row), + HoldTrainMap: make(map[uint32]*Row), + SignalMap: make(map[uint32]*Row), + AxleSectionMap: make(map[uint32]*Row), + WrzfMap: make(map[uint32]*Row), + FymMap: make(map[uint32]*Row), + SpksMap: make(map[uint32]*Row), + CkmMap: make(map[uint32]*Row), + XcjMap: make(map[uint32]*Row), } } + +type Row struct { + commonId uint32 //地图中设备的ID + uid string //模型仓库中的设备模型ID + index uint16 //联锁通信中的设备ID + relateDeviceMap map[string]string //此设备关联的其它设备 key-查找设备所用的标识,val-uid +} + +const ( + POB = "POB" + PCB = "PCB" + DPB = "DPB" +) diff --git a/third_party/interlock/beijing11/service.go b/third_party/interlock/beijing11/service.go index c3c6a6f..038ba53 100644 --- a/third_party/interlock/beijing11/service.go +++ b/third_party/interlock/beijing11/service.go @@ -2,133 +2,342 @@ package beijing11 import ( - "encoding/json" + "context" "fmt" "joylink.club/bj-rtsts-server/config" "joylink.club/bj-rtsts-server/dto/data_proto" "joylink.club/bj-rtsts-server/third_party/udp" "joylink.club/bj-rtsts-server/ts/simulation/wayside/memory" + "joylink.club/rtsssimulation/component" + "joylink.club/rtsssimulation/entity" "log/slog" + "runtime/debug" "sync" + "time" ) -const logTag = "[北京11号线联锁通信]" - var ( - initMutex = sync.Mutex{} - running = false - server udp.UdpServer - sim *memory.VerifySimulation //启动服务所使用的仿真 - iConfig *config.InterlockConfig //启动服务使用的联锁配置 - //联锁区设备的联锁编号与uid的映射 - stationMap map[string]*StationDeviceIndexRepo + logTag = "[北京11号线联锁通信]" + privateLogger *slog.Logger + loggerInit sync.Once ) -func init() { - memory.RegisterListener(func(uidStructure *memory.StationUidStructure, data *data_proto.RtssGraphicStorage) { - //if data.LianSuoData == nil { - // return - //} - ////初始化所有集中站设备映射结构体;建立车站和集中站的comId映射关系 - //station_concentration_map := make(map[uint32]uint32) - //for _, station := range data.Stations { - // if station.ConcentrationStations { - // stationMap[station.StationName] = NewStationDeviceIndexRepo() - // for _, manageStation := range station.ManageStations { - // station_concentration_map[manageStation] = station.Common.Id - // } - // } - //} - ////建立站台和集中站的comId映射 - //platform_station_map := make(map[uint32]uint32) - //for _, platform := range data.Platforms { - // platform_station_map[platform.Common.Id] = station_concentration_map[platform.RefStationId] - //} - ////填充 - //stationIdMap := uidStructure.StationIds - ////道岔 - //turnoutUidMap := uidStructure.TurnoutIds - //turnoutIndexMap := make(map[uint32]uint32) - //for _, turnout := range data.LianSuoData.Switchs { - // turnoutIndexMap[turnout.Id] = turnout.Index - //} - //for _, turnout := range data.Turnouts { - // for _, stationComId := range turnout.CentralizedStations { - // stationIdStruct := stationIdMap[stationComId] - // stationDeviceIndexRepo := stationMap[stationIdStruct.Code] - // index := turnoutIndexMap[turnout.Common.Id] - // stationDeviceIndexRepo.TurnoutMap[index] = turnoutUidMap[turnout.Common.Id].Uid - // } - //} - ////屏蔽门 - //psdUidMap := uidStructure.PsdIds - //psdIndexMap := make(map[uint32]uint32) - //for _, psd := range data.LianSuoData.ScreenDoors { - // psdIndexMap[psd.Id] = psd.Index - //} - //for _, psd := range data.ScreenDoors { - // stationComId := platform_station_map[psd.RefPlatformId] - // stationIdStruct := stationIdMap[stationComId] - // stationDeviceIndexRepo := stationMap[stationIdStruct.Code] - // index := psdIndexMap[psd.Common.Id] - // stationDeviceIndexRepo.PsdMap[index] = psdUidMap[psd.Common.Id].Uid - //} - ////紧急停车 - //uidStructure. - }) +var ( + mu = sync.Mutex{} //启动任务时使用,避免重复启动任务 + serviceContextMap = make(map[string]*serviceContext) //每个集中站的服务上下文,key-集中站code +) + +type serviceContext struct { + cancelFunc context.CancelFunc //用来结束各个协程的函数 + client udp.UdpClient //向联锁发送数据的客户端 + server udp.UdpServer //接收联锁数据的服务端 + sim *memory.VerifySimulation //启动服务所使用的仿真 + iConfig *config.InterlockConfig //启动服务使用的联锁配置 + deviceTable *StationDeviceIndexTable //联锁站的设备ID表,key-车站名 } func Start(interlockConfig *config.InterlockConfig, simulation *memory.VerifySimulation) { if interlockConfig == nil || interlockConfig.Ip == "" || !interlockConfig.Open { return } - if running { + mu.Lock() + defer mu.Unlock() + //制表 + table := makeTable(simulation, interlockConfig.Code) + if table == nil { //当前仿真内没有11号线联锁通信所需数据 return } - initMutex.Lock() - defer initMutex.Unlock() - if running { - return + serviceCtx := serviceContextMap[interlockConfig.Code] + if serviceCtx != nil { + panic(fmt.Sprintf("%s重复启动联锁站[%s]通信服务", logTag, interlockConfig.Code)) } - //UDP通信设施 - server = udp.NewServer(fmt.Sprintf(":%d", interlockConfig.LocalPort), func(b []byte) { - slog.Info(fmt.Sprintf("%s收到消息:%x", logTag, b)) - frame := &FromInterlockFrame{} - err := frame.Decode(b) - if err != nil { - slog.Error(fmt.Sprintf("%s解析数据出错:%s", logTag, err)) - } else { - marshal, err := json.Marshal(frame) - if err != nil { - slog.Error(fmt.Sprintf("%s解析为json出错:%s", logTag, err)) - } else { - slog.Info(fmt.Sprintf("%s解析为json:%s", logTag, string(marshal))) - } - } - }) + //UDP客户端 + client := udp.NewClient(fmt.Sprintf("%s:%d", interlockConfig.Ip, interlockConfig.RemotePort)) + + ctx, cancelFunc := context.WithCancel(context.Background()) + serviceCtx = &serviceContext{ + cancelFunc: cancelFunc, + client: client, + sim: simulation, + iConfig: interlockConfig, + deviceTable: table, + } + //UDP服务端 + server := udp.NewServer(fmt.Sprintf(":%d", interlockConfig.LocalPort), serviceCtx.handleDriveMsg) + serviceCtx.server = server err := server.Listen() if err != nil { panic(fmt.Sprintf("%s启动UDP服务失败:%s", logTag, err)) } - running = true - sim = simulation - iConfig = interlockConfig + + serviceCtx.runCollectTask(ctx) + serviceContextMap[interlockConfig.Code] = serviceCtx } -func Stop() { - initMutex.Lock() - defer initMutex.Unlock() - running = false - if server != nil { - server.Close() - server = nil +func (s *serviceContext) handleDriveMsg(data []byte) { + logger().Info(fmt.Sprintf("收到消息:%x", data)) + frame := &FromInterlockFrame{} + err := frame.Decode(data) + if err != nil { + logger().Error("解析数据出错", "error", err) + return + } + +} + +func Stop(stationCode string) { + mu.Lock() + defer mu.Unlock() + context := serviceContextMap[stationCode] + if context != nil { + if context.client != nil { + context.client.Close() + } + if context.server != nil { + context.server.Close() + } + delete(serviceContextMap, stationCode) } } -//func CollectRelayInfo() *FromInterlockFrame { -// sim.World -//} -// -//func HandleDriveInfo(frame *FromInterlockFrame) { -// -//} +func makeTable(sim *memory.VerifySimulation, stationCode string) *StationDeviceIndexTable { + for _, mapId := range sim.MapIds { + giType := memory.QueryGiType(mapId) + if giType != data_proto.PictureType_StationLayout { + continue + } + stationGi := memory.QueryGiData[*data_proto.RtssGraphicStorage](mapId) + if stationGi.LianSuoData == nil { + continue + } + + uids := memory.QueryUidStructure[*memory.StationUidStructure](mapId) + table := NewStationDeviceIndexTable() + //道岔 + for _, data := range stationGi.LianSuoData.Switchs { + for _, station := range uids.TurnoutIds[data.Id].CentralizedStations { + if station.Code == stationCode { + table.TurnoutMap[data.Id] = &Row{ + commonId: data.Id, + uid: uids.TurnoutIds[data.Id].Uid, + index: uint16(data.Index), + relateDeviceMap: nil, + } + } + } + } + //屏蔽门 + for _, data := range stationGi.LianSuoData.ScreenDoors { + for _, station := range uids.PsdIds[data.Id].CentralizedStations { + if station.Code == stationCode { + relateDeviceMap := make(map[string]string) + for _, mkx := range sim.Repo.MkxList() { + if mkx.Psd().Id() == uids.PsdIds[data.Id].Uid { + relateDeviceMap[POB] = mkx.Pobj().Id() + relateDeviceMap[PCB] = mkx.Pcbj().Id() + relateDeviceMap[DPB] = mkx.Pabj().Id() + } + } + table.PsdMap[data.Id] = &Row{ + commonId: data.Id, + uid: uids.PsdIds[data.Id].Uid, + index: uint16(data.Index), + relateDeviceMap: relateDeviceMap, + } + } + } + } + //紧急停车 + for _, data := range stationGi.LianSuoData.EsbButtons { + for _, station := range uids.EsbIds[data.Id].CentralizedStations { + if station.Code == stationCode { + table.EsbMap[data.Id] = &Row{ + commonId: data.Id, + uid: uids.EsbIds[data.Id].Uid, + index: uint16(data.Index), + relateDeviceMap: nil, + } + } + } + } + //扣车,实际数据中数量为0 + //信号机 + for _, data := range stationGi.LianSuoData.Signals { + for _, station := range uids.SignalIds[data.Id].CentralizedStations { + if station.Code == stationCode { + table.SignalMap[data.Id] = &Row{ + commonId: data.Id, + uid: uids.SignalIds[data.Id].Uid, + index: uint16(data.Index), + relateDeviceMap: nil, + } + } + } + } + //计轴区段 + for _, data := range stationGi.LianSuoData.Sections { + for _, station := range uids.PhysicalSectionIds[data.Id].CentralizedStations { + if station.Code == stationCode { + table.AxleSectionMap[data.Id] = &Row{ + commonId: data.Id, + uid: uids.PhysicalSectionIds[data.Id].Uid, + index: uint16(data.Index), + relateDeviceMap: nil, + } + } + } + } + //无人折返,实际数据中数量为0 + //防淹门,实际数据中数量为0 + //人员防护 + for _, data := range stationGi.LianSuoData.SpksSwitchs { + for _, station := range uids.SpksIds[data.Id].CentralizedStations { + if station.Code == stationCode { + table.SpksMap[data.Id] = &Row{ + commonId: data.Id, + uid: uids.SpksIds[data.Id].Uid, + index: uint16(data.Index), + relateDeviceMap: nil, + } + } + } + } + //车库门,实际数据中数量为0 + //洗车机,实际数据中没有 + return table + } + return nil +} + +func (s *serviceContext) runCollectTask(ctx context.Context) { + go func() { + defer func() { + if err := recover(); err != nil { + logger().Error("状态收集任务出错,记录后重启", "error", err, "stack", string(debug.Stack())) + s.runCollectTask(nil) + } + }() + }() + for range time.Tick(time.Duration(s.iConfig.Period) * time.Millisecond) { + select { + case <-ctx.Done(): + return + default: + frame := s.collectDeviceState() + err := s.client.Send(frame.encode()) + if err != nil { + logger().Error("向联锁发送数据失败", "error", err) + } + } + } +} + +func (s *serviceContext) collectDeviceState() *ToInterlockFrame { + wd := entity.GetWorldData(s.sim.World) + frame := &ToInterlockFrame{} + //道岔 + for _, row := range s.deviceTable.TurnoutMap { + entry := wd.EntityMap[row.uid] + pos := component.TurnoutPositionType.Get(entry) + state := GetStateByte(pos.Db) + var current1 byte + var current2 byte + if entry.HasComponent(component.TurnoutZzjType) { + zzjList := component.TurnoutZzjType.Get(entry).ZzjList + for i, zzj := range zzjList { + speed := component.FixedPositionTransformType.Get(zzj).Speed + if speed != 0 { + switch i { + case 0: + current1 = 100 + case 1: + current2 = 100 + } + } + } + } + frame.TurnoutStates = append(frame.TurnoutStates, &TurnoutState{ + Id: row.index, + State: state, + Alarm: 0, + Current1: current1, + Current2: current2, + }) + } + //屏蔽门 + for _, row := range s.deviceTable.PsdMap { + entry := wd.EntityMap[row.uid] + psdState := component.PsdStateType.Get(entry) + mkxBytes := make([]byte, 0, 3) + for _, mkxRelayUid := range []string{row.relateDeviceMap[POB], row.relateDeviceMap[PCB], row.relateDeviceMap[DPB]} { + if mkxRelayUid == "" { + continue + } + mkxBytes = append(mkxBytes, GetStateByte(component.BitStateType.Get(wd.EntityMap[mkxRelayUid]).Val)) + } + frame.PsdStates = append(frame.PsdStates, &PSDState{ + Id: row.index, + State: GetStateByte(psdState.Close), + Hsjc: GetStateByte(psdState.InterlockRelease), + PCB: mkxBytes[0], + POB: mkxBytes[1], + DPB: mkxBytes[2], + }) + } + //紧急停车 + for _, row := range s.deviceTable.EsbMap { + esb := s.sim.Repo.FindEsb(row.uid) + relay := wd.EntityMap[esb.RelayId()] + pla := wd.EntityMap[esb.PlaId()] + frame.ESBStates = append(frame.ESBStates, &ESBState{ + Id: row.index, + State: GetStateByte(!component.BitStateType.Get(relay).Val), + PlState: GetStateByte(component.BitStateType.Get(pla).Val), + }) + } + //信号机 + for _, row := range s.deviceTable.SignalMap { + entry := wd.EntityMap[row.uid] + lights := component.SignalLightsType.Get(entry) + var current byte + for _, light := range lights.Lights { + if component.BitStateType.Get(light).Val { + current = 100 + break + } + } + frame.SignalStates = append(frame.SignalStates, &SignalState{ + Id: row.index, + State: 0, //目前还不知道每种显示对应什么字节,先这样 + Current: current, + }) + } + //计轴区段 + for _, row := range s.deviceTable.AxleSectionMap { + entry := wd.EntityMap[row.uid] + axleManager := component.AxleManagerType.Get(entry) + frame.AxleSectionStates = append(frame.AxleSectionStates, &AxleSectionState{ + Id: row.index, + State: GetStateByte(axleManager.Occupied), + }) + } + //SPKS + for _, row := range s.deviceTable.SpksMap { + spks := s.sim.Repo.FindSpks(row.uid) + relay := wd.EntityMap[spks.Relay()] + pla := wd.EntityMap[spks.PlaId()] + frame.SPKSStates = append(frame.SPKSStates, &SPKSState{ + Id: row.index, + State: GetStateByte(component.BitStateType.Get(relay).Val), + PlState: GetStateByte(component.BitStateType.Get(pla).Val), + }) + } + return frame +} + +func logger() *slog.Logger { + loggerInit.Do(func() { + privateLogger = slog.Default().With("tag", logTag) + }) + return privateLogger +} diff --git a/ts/simulation/wayside/memory/wayside_memory_map_init.go b/ts/simulation/wayside/memory/wayside_memory_map_init.go index e069168..cc43109 100644 --- a/ts/simulation/wayside/memory/wayside_memory_map_init.go +++ b/ts/simulation/wayside/memory/wayside_memory_map_init.go @@ -13,59 +13,60 @@ import ( "joylink.club/rtsssimulation/repository" ) -// 地图数据处理方法。目前用于不同通信协议所需数据的预处理 -type MapDataHandler func(uidStructure *StationUidStructure, data *data_proto.RtssGraphicStorage) - -var mapDataHandlerList = make([]MapDataHandler, 0) - -func RegisterListener(handler MapDataHandler) { - mapDataHandlerList = append(mapDataHandlerList, handler) -} - var giUidMap sync.Map -type elementIdStructure struct { +// 设备的联系 +type DeviceRelationship struct { CommonId uint32 Code string Uid string + //设备所属集中站(此字段暂时仅给急需的设备赋值了) + CentralizedStations []*data_proto.Station +} + +func (d *DeviceRelationship) GetCentralizedStations() []*data_proto.Station { + if d == nil { + return nil + } + return d.CentralizedStations } // 列车控制 type TccUidStructure struct { - ButtonIds map[uint32]*elementIdStructure - Keys map[uint32]*elementIdStructure - Handler map[uint32]*elementIdStructure + ButtonIds map[uint32]*DeviceRelationship + Keys map[uint32]*DeviceRelationship + Handler map[uint32]*DeviceRelationship } // 数组为Index为 common.ButtonCode, index, uid type StationUidStructure struct { - AxlePointIds map[uint32]*elementIdStructure - TurnoutIds map[uint32]*elementIdStructure - PhysicalSectionIds map[uint32]*elementIdStructure - SignalIds map[uint32]*elementIdStructure - TransponderIds map[uint32]*elementIdStructure - SlopeIds map[uint32]*elementIdStructure - CurvatureIds map[uint32]*elementIdStructure - ButtonIds map[uint32]*elementIdStructure - StationIds map[uint32]*elementIdStructure - PlatformIds map[uint32]*elementIdStructure - PsdIds map[uint32]*elementIdStructure - PslIds map[uint32]*elementIdStructure - SpksSwitchIds map[uint32]*elementIdStructure - IbpIds map[uint32]*elementIdStructure - CkmIds map[uint32]*elementIdStructure - XcjIds map[uint32]*elementIdStructure + AxlePointIds map[uint32]*DeviceRelationship + TurnoutIds map[uint32]*DeviceRelationship + PhysicalSectionIds map[uint32]*DeviceRelationship + SignalIds map[uint32]*DeviceRelationship + TransponderIds map[uint32]*DeviceRelationship + SlopeIds map[uint32]*DeviceRelationship + CurvatureIds map[uint32]*DeviceRelationship + EsbIds map[uint32]*DeviceRelationship + StationIds map[uint32]*DeviceRelationship + PlatformIds map[uint32]*DeviceRelationship + PsdIds map[uint32]*DeviceRelationship + PslIds map[uint32]*DeviceRelationship + SpksIds map[uint32]*DeviceRelationship + IbpIds map[uint32]*DeviceRelationship + CkmIds map[uint32]*DeviceRelationship + XcjIds map[uint32]*DeviceRelationship } type RelayUidStructure struct { - RelayIds map[uint32]*elementIdStructure + RelayIds map[uint32]*DeviceRelationship } type IBPUidStructure struct { - IbpButtonIds map[uint32]*elementIdStructure - IbpAlarmIds map[uint32]*elementIdStructure - IbpKeyIds map[uint32]*elementIdStructure - IbpLightIds map[uint32]*elementIdStructure + IbpButtonIds map[uint32]*DeviceRelationship + IbpAlarmIds map[uint32]*DeviceRelationship + IbpKeyIds map[uint32]*DeviceRelationship + IbpLightIds map[uint32]*DeviceRelationship } // 获取继电器的关联关系 @@ -93,10 +94,11 @@ func getMapELementCode(id uint32, code ...string) string { return strconv.Itoa(int(id)) } -// 获取关联的车站名 -func handleRefStationName(stationMap map[uint32]*data_proto.Station, sid []uint32) []string { +// 获取车站信息 +func findStationInfos(stationMap map[uint32]*data_proto.Station, stationIds []uint32) ([]string, []*data_proto.Station) { var stationNames []string - for _, id := range sid { + var stations []*data_proto.Station + for _, id := range stationIds { if id == 0 { continue } @@ -104,8 +106,9 @@ func handleRefStationName(stationMap map[uint32]*data_proto.Station, sid []uint3 continue } stationNames = append(stationNames, stationMap[id].StationName) + stations = append(stations, stationMap[id]) } - return stationNames + return stationNames, stations } // 获取UID的前缀信息 @@ -249,22 +252,22 @@ func filterOtherLineDevice(data *data_proto.RtssGraphicStorage) { // 初始化平面布置图 UID func initStationUid(data *data_proto.RtssGraphicStorage) *StationUidStructure { gus := &StationUidStructure{ - AxlePointIds: make(map[uint32]*elementIdStructure, len(data.AxleCountings)), - TurnoutIds: make(map[uint32]*elementIdStructure, len(data.Turnouts)), - PhysicalSectionIds: make(map[uint32]*elementIdStructure, len(data.Section)), - SignalIds: make(map[uint32]*elementIdStructure, len(data.Signals)), - TransponderIds: make(map[uint32]*elementIdStructure, len(data.Transponders)), - SlopeIds: make(map[uint32]*elementIdStructure, len(data.Slopes)), - CurvatureIds: make(map[uint32]*elementIdStructure, len(data.Curvatures)), - ButtonIds: make(map[uint32]*elementIdStructure, len(data.EsbButtons)), - StationIds: make(map[uint32]*elementIdStructure, len(data.Stations)), - PlatformIds: make(map[uint32]*elementIdStructure, len(data.Platforms)), - PsdIds: make(map[uint32]*elementIdStructure, len(data.ScreenDoors)), - PslIds: make(map[uint32]*elementIdStructure, len(data.GateBoxs)), - //SpksSwitchIds: make(map[uint32]*elementIdStructure, len(data.SpksSwitchs)), - IbpIds: make(map[uint32]*elementIdStructure, len(data.IbpBoxs)), - CkmIds: make(map[uint32]*elementIdStructure, len(data.GarageDoors)), - XcjIds: make(map[uint32]*elementIdStructure, len(data.CarWashings)), + AxlePointIds: make(map[uint32]*DeviceRelationship, len(data.AxleCountings)), + TurnoutIds: make(map[uint32]*DeviceRelationship, len(data.Turnouts)), + PhysicalSectionIds: make(map[uint32]*DeviceRelationship, len(data.Section)), + SignalIds: make(map[uint32]*DeviceRelationship, len(data.Signals)), + TransponderIds: make(map[uint32]*DeviceRelationship, len(data.Transponders)), + SlopeIds: make(map[uint32]*DeviceRelationship, len(data.Slopes)), + CurvatureIds: make(map[uint32]*DeviceRelationship, len(data.Curvatures)), + EsbIds: make(map[uint32]*DeviceRelationship, len(data.EsbButtons)), + StationIds: make(map[uint32]*DeviceRelationship, len(data.Stations)), + PlatformIds: make(map[uint32]*DeviceRelationship, len(data.Platforms)), + PsdIds: make(map[uint32]*DeviceRelationship, len(data.ScreenDoors)), + PslIds: make(map[uint32]*DeviceRelationship, len(data.GateBoxs)), + SpksIds: make(map[uint32]*DeviceRelationship, len(data.SpksSwitchs)), + IbpIds: make(map[uint32]*DeviceRelationship, len(data.IbpBoxs)), + CkmIds: make(map[uint32]*DeviceRelationship, len(data.GarageDoors)), + XcjIds: make(map[uint32]*DeviceRelationship, len(data.CarWashings)), } city, lineId, _ := getUIdPrefix(data.UniqueIdPrefix) // 处理车站信息 @@ -273,81 +276,135 @@ func initStationUid(data *data_proto.RtssGraphicStorage) *StationUidStructure { eid := GetMapElementId(s.Common) stationName := getMapELementCode(eid, s.StationName, s.Code) stationMap[eid] = s - gus.StationIds[eid] = &elementIdStructure{ + gus.StationIds[eid] = &DeviceRelationship{ CommonId: eid, Code: stationName, - Uid: GenerateElementUid(city, lineId, nil, stationName), + Uid: BuildUid(city, lineId, stationName), + } + } + for _, station := range data.Stations { + if station.ConcentrationStations { + for _, subStation := range station.ManageStations { + gus.StationIds[subStation].CentralizedStations = append(gus.StationIds[subStation].CentralizedStations, station) + } } } // 初始化计轴信息 for _, a := range data.AxleCountings { eid := GetMapElementId(a.Common) code := getMapELementCode(eid, a.Code) - stationNames := handleRefStationName(stationMap, a.CentralizedStations) - gus.AxlePointIds[eid] = &elementIdStructure{ - CommonId: eid, - Code: code, - Uid: GenerateElementUid(city, lineId, stationNames, code), + cenStationNames, cenStations := findStationInfos(stationMap, a.CentralizedStations) + gus.AxlePointIds[eid] = &DeviceRelationship{ + CommonId: eid, + Code: code, + Uid: GenerateElementUid(city, lineId, cenStationNames, code), + CentralizedStations: cenStations, } } // 初始化道岔信息 for _, t := range data.Turnouts { eid := GetMapElementId(t.Common) code := getMapELementCode(eid, t.Code) - stationNames := handleRefStationName(stationMap, t.CentralizedStations) - gus.TurnoutIds[eid] = &elementIdStructure{ - CommonId: eid, - Code: code, - Uid: GenerateElementUid(city, lineId, stationNames, code), + cenStationNames, cenStations := findStationInfos(stationMap, t.CentralizedStations) + gus.TurnoutIds[eid] = &DeviceRelationship{ + CommonId: eid, + Code: code, + Uid: GenerateElementUid(city, lineId, cenStationNames, code), + CentralizedStations: cenStations, } } // 初始化物理区段信息 for _, s := range data.Section { eid := GetMapElementId(s.Common) code := getMapELementCode(eid, s.Code) - stationNames := handleRefStationName(stationMap, s.CentralizedStations) - gus.PhysicalSectionIds[eid] = &elementIdStructure{ - CommonId: eid, - Code: code, - Uid: GenerateElementUid(city, lineId, stationNames, code), + cenStationNames, cenStations := findStationInfos(stationMap, s.CentralizedStations) + gus.PhysicalSectionIds[eid] = &DeviceRelationship{ + CommonId: eid, + Code: code, + Uid: GenerateElementUid(city, lineId, cenStationNames, code), + CentralizedStations: cenStations, } } // 初始化信号机信息 for _, s := range data.Signals { eid := GetMapElementId(s.Common) code := getMapELementCode(eid, s.Code) - stationNames := handleRefStationName(stationMap, s.CentralizedStations) - gus.SignalIds[eid] = &elementIdStructure{ - CommonId: eid, - Code: code, - Uid: GenerateElementUid(city, lineId, stationNames, code), + cenStationNames, cenStations := findStationInfos(stationMap, s.CentralizedStations) + gus.SignalIds[eid] = &DeviceRelationship{ + CommonId: eid, + Code: code, + Uid: GenerateElementUid(city, lineId, cenStationNames, code), + CentralizedStations: cenStations, } } // 初始化应答器 for _, t := range data.Transponders { eid := GetMapElementId(t.Common) code := getMapELementCode(eid, t.Code) - stationNames := handleRefStationName(stationMap, t.CentralizedStations) - gus.TransponderIds[eid] = &elementIdStructure{ - CommonId: eid, - Code: code, - Uid: GenerateElementUid(city, lineId, stationNames, code), + cenStationNames, cenStations := findStationInfos(stationMap, t.CentralizedStations) + gus.TransponderIds[eid] = &DeviceRelationship{ + CommonId: eid, + Code: code, + Uid: GenerateElementUid(city, lineId, cenStationNames, code), + CentralizedStations: cenStations, } } // 初始化坡度 for _, s := range data.Slopes { eid := GetMapElementId(s.Common) - gus.SlopeIds[eid] = &elementIdStructure{ + gus.SlopeIds[eid] = &DeviceRelationship{ CommonId: eid, - Uid: GenerateElementUid(city, lineId, nil, strconv.Itoa(int(eid))), + Uid: BuildUid(city, lineId, strconv.Itoa(int(eid))), } } // 初始化曲线 for _, c := range data.Curvatures { eid := GetMapElementId(c.Common) - gus.CurvatureIds[eid] = &elementIdStructure{ + gus.CurvatureIds[eid] = &DeviceRelationship{ CommonId: eid, - Uid: GenerateElementUid(city, lineId, nil, strconv.Itoa(int(eid))), + Uid: BuildUid(city, lineId, strconv.Itoa(int(eid))), + } + } + // 站台 + platformMap := make(map[uint32]*data_proto.Platform) + for _, platform := range data.Platforms { + comId := platform.Common.Id + platformMap[comId] = platform + gus.PlatformIds[comId] = &DeviceRelationship{ + CommonId: comId, + Code: platform.Code, + Uid: BuildUid(city, lineId, platform.Code), + CentralizedStations: gus.StationIds[platform.RefStationId].GetCentralizedStations(), + } + } + // 屏蔽门 + for _, door := range data.ScreenDoors { + comId := door.Common.Id + gus.PsdIds[comId] = &DeviceRelationship{ + CommonId: comId, + Code: door.Code, + Uid: BuildUid(city, lineId, gus.PlatformIds[door.RefPlatformId].Code, door.Code), + CentralizedStations: gus.PlatformIds[door.RefPlatformId].GetCentralizedStations(), + } + } + // 紧急停车 + for _, esb := range data.EsbButtons { + comId := esb.Common.Id + gus.EsbIds[comId] = &DeviceRelationship{ + CommonId: comId, + Code: esb.Code, + Uid: BuildUid(city, lineId, gus.PlatformIds[esb.RefStand].Code, esb.Code), + CentralizedStations: gus.PlatformIds[esb.RefStand].GetCentralizedStations(), + } + } + // SPKS + for _, spks := range data.SpksSwitchs { + commonId := spks.Common.Id + gus.SpksIds[commonId] = &DeviceRelationship{ + CommonId: commonId, + Code: spks.Code, + Uid: BuildUid(city, lineId, gus.PlatformIds[spks.RefStand].Code, spks.Code), + CentralizedStations: gus.PlatformIds[spks.RefStand].GetCentralizedStations(), } } //处理车站关联的组合信息 @@ -360,62 +417,25 @@ func initStationUid(data *data_proto.RtssGraphicStorage) *StationUidStructure { } } } - // 初始化站场图按钮 - for _, b := range data.EsbButtons { - eid := GetMapElementId(b.Common) - p := refMap[eid] - code := b.Code - if p != nil { - code = p.deviceCode + "_" + p.typeCode + "_" + b.Code - } - gus.ButtonIds[eid] = &elementIdStructure{ - CommonId: eid, - Code: b.Code, - Uid: GenerateElementUid(city, lineId, nil, code), - } - } - // 站台 - platformMap := make(map[uint32]*data_proto.Platform) - for _, platform := range data.Platforms { - eid := GetMapElementId(platform.Common) - platformMap[eid] = platform - gus.PlatformIds[eid] = &elementIdStructure{ - CommonId: eid, - Code: platform.Code, - Uid: GenerateElementUid(city, lineId, nil, platform.Code), - } - } - // 屏蔽门 - for _, door := range data.ScreenDoors { - station := stationMap[platformMap[door.RefPlatformId].GetRefStationId()] - if station == nil { //线路数据有问题 - continue - } - eid := GetMapElementId(door.Common) - gus.PsdIds[eid] = &elementIdStructure{ - CommonId: eid, - Code: door.Code, - Uid: GenerateElementUid(city, lineId, []string{station.StationName}, door.Code), - } - } + // PSL for _, box := range data.PslBoxs { stationName := stationMap[platformMap[box.RefPlatformId].RefStationId].StationName eid := GetMapElementId(box.Common) - gus.PslIds[eid] = &elementIdStructure{ + gus.PslIds[eid] = &DeviceRelationship{ CommonId: eid, Code: box.Code, - Uid: GenerateElementUid(city, lineId, []string{stationName}, box.Code), + Uid: BuildUid(city, lineId, stationName, box.Code), } } // IBP for _, box := range data.IbpBoxs { stationName := stationMap[box.RefStationId].StationName eid := GetMapElementId(box.Common) - gus.IbpIds[eid] = &elementIdStructure{ + gus.IbpIds[eid] = &DeviceRelationship{ CommonId: eid, Code: box.Code, - Uid: GenerateElementUid(city, lineId, []string{stationName}, box.Code), + Uid: BuildUid(city, lineId, stationName, box.Code), } } // 车库门 @@ -429,27 +449,23 @@ func initStationUid(data *data_proto.RtssGraphicStorage) *StationUidStructure { // 洗车机 for _, xcj := range data.CarWashings { eid := GetMapElementId(xcj.Common) - gus.XcjIds[eid] = &elementIdStructure{ + gus.XcjIds[eid] = &DeviceRelationship{ CommonId: eid, Code: xcj.Code, - Uid: GenerateElementUid(city, lineId, nil, xcj.Code), + Uid: BuildUid(city, lineId, xcj.Code), } } - //通信协议预处理所需数据 - for _, handler := range mapDataHandlerList { - handler(gus, data) - } return gus } func fillCkmInfo(ckm *data_proto.GarageDoor, gus *StationUidStructure, city string, lineId string) { eid := GetMapElementId(ckm.Common) - gus.CkmIds[eid] = &elementIdStructure{ + gus.CkmIds[eid] = &DeviceRelationship{ CommonId: eid, Code: ckm.Code, - Uid: GenerateElementUid(city, lineId, nil, ckm.Code), + Uid: BuildUid(city, lineId, ckm.Code), } - gus.PslIds[eid] = &elementIdStructure{ + gus.PslIds[eid] = &DeviceRelationship{ CommonId: eid, Code: ckm.Code, Uid: BuildUid(city, lineId, ckm.Code, "PSL"), @@ -458,22 +474,22 @@ func fillCkmInfo(ckm *data_proto.GarageDoor, gus *StationUidStructure, city stri // 初始化列车控制 func initTccUid(tcc *data_proto.TccGraphicStorage) *TccUidStructure { - tc := &TccUidStructure{ButtonIds: make(map[uint32]*elementIdStructure), Keys: make(map[uint32]*elementIdStructure), Handler: make(map[uint32]*elementIdStructure)} + tc := &TccUidStructure{ButtonIds: make(map[uint32]*DeviceRelationship), Keys: make(map[uint32]*DeviceRelationship), Handler: make(map[uint32]*DeviceRelationship)} for _, d := range tcc.TccButtons { id := GetMapElementId(d.Common) - tc.ButtonIds[id] = &elementIdStructure{CommonId: id, + tc.ButtonIds[id] = &DeviceRelationship{CommonId: id, Code: d.Code} } for _, d := range tcc.TccKeys { id := GetMapElementId(d.Common) - tc.Keys[id] = &elementIdStructure{CommonId: id, + tc.Keys[id] = &DeviceRelationship{CommonId: id, Code: d.Code} } for _, d := range tcc.TccHandles { id := GetMapElementId(d.Common) - tc.Handler[id] = &elementIdStructure{CommonId: id, + tc.Handler[id] = &DeviceRelationship{CommonId: id, Code: d.Code} } @@ -483,7 +499,7 @@ func initTccUid(tcc *data_proto.TccGraphicStorage) *TccUidStructure { // 初始化继电器柜 UID func initRelayCabinetUid(data *data_proto.RelayCabinetGraphicStorage) *RelayUidStructure { rus := &RelayUidStructure{ - RelayIds: make(map[uint32]*elementIdStructure, len(data.Relays)), + RelayIds: make(map[uint32]*DeviceRelationship, len(data.Relays)), } // 继电器所属设备 refMap := make(map[uint32]*deviceRelateUidPriex, len(data.Relays)) @@ -507,14 +523,16 @@ func initRelayCabinetUid(data *data_proto.RelayCabinetGraphicStorage) *RelayUidS if p != nil { code = p.deviceCode + "_" + p.typeCode + "_" + r.Code } - stationArr := []string{station} + var uid string if p != nil && (p.isStation || p.isPSD) { - stationArr = nil + uid = BuildUid(city, lineId, code) + } else { + uid = BuildUid(city, lineId, station, code) } - rus.RelayIds[eid] = &elementIdStructure{ + rus.RelayIds[eid] = &DeviceRelationship{ CommonId: eid, Code: r.Code, - Uid: GenerateElementUid(city, lineId, stationArr, code), + Uid: uid, } } for _, r := range data.PhaseFailureProtectors { @@ -524,14 +542,14 @@ func initRelayCabinetUid(data *data_proto.RelayCabinetGraphicStorage) *RelayUidS if p != nil { code = p.deviceCode + "_" + p.typeCode + "_" + r.Code } - stationArr := []string{station} + stationName := station if p != nil && (p.isStation || p.isPSD) { - stationArr = nil + stationName = "" } - rus.RelayIds[eid] = &elementIdStructure{ + rus.RelayIds[eid] = &DeviceRelationship{ CommonId: eid, Code: r.Code, - Uid: GenerateElementUid(city, lineId, stationArr, code), + Uid: BuildUid(city, lineId, stationName, code), } } return rus @@ -540,10 +558,10 @@ func initRelayCabinetUid(data *data_proto.RelayCabinetGraphicStorage) *RelayUidS // 初始化IBP地图UID func initIBPUid(data *data_proto.IBPGraphicStorage) *IBPUidStructure { rus := &IBPUidStructure{ - IbpButtonIds: make(map[uint32]*elementIdStructure), - IbpAlarmIds: make(map[uint32]*elementIdStructure), - IbpKeyIds: make(map[uint32]*elementIdStructure), - IbpLightIds: make(map[uint32]*elementIdStructure), + IbpButtonIds: make(map[uint32]*DeviceRelationship), + IbpAlarmIds: make(map[uint32]*DeviceRelationship), + IbpKeyIds: make(map[uint32]*DeviceRelationship), + IbpLightIds: make(map[uint32]*DeviceRelationship), } //处理继电器关联信息 refMap := make(map[uint32]string) @@ -564,7 +582,7 @@ func initIBPUid(data *data_proto.IBPGraphicStorage) *IBPUidStructure { // 处理按钮Uid for _, d := range data.IbpButtons { eid := GetMapElementId(d.Common) - rus.IbpButtonIds[eid] = &elementIdStructure{ + rus.IbpButtonIds[eid] = &DeviceRelationship{ CommonId: eid, Code: d.Code, Uid: "button_" + codeFun(eid, d.Code), @@ -573,7 +591,7 @@ func initIBPUid(data *data_proto.IBPGraphicStorage) *IBPUidStructure { // 处理钥匙Uid for _, d := range data.IbpKeys { eid := GetMapElementId(d.Common) - rus.IbpKeyIds[eid] = &elementIdStructure{ + rus.IbpKeyIds[eid] = &DeviceRelationship{ CommonId: eid, Code: d.Code, Uid: "key_" + codeFun(eid, d.Code), @@ -582,7 +600,7 @@ func initIBPUid(data *data_proto.IBPGraphicStorage) *IBPUidStructure { // 处理报警器Uid for _, d := range data.IbpAlarms { eid := GetMapElementId(d.Common) - rus.IbpAlarmIds[eid] = &elementIdStructure{ + rus.IbpAlarmIds[eid] = &DeviceRelationship{ CommonId: eid, Code: d.Code, Uid: "alarm_" + codeFun(eid, d.Code), @@ -591,7 +609,7 @@ func initIBPUid(data *data_proto.IBPGraphicStorage) *IBPUidStructure { // 处理指示灯Uid for _, d := range data.IbpLights { eid := GetMapElementId(d.Common) - rus.IbpLightIds[eid] = &elementIdStructure{ + rus.IbpLightIds[eid] = &DeviceRelationship{ CommonId: eid, Code: d.Code, Uid: "light_" + codeFun(eid, d.Code), @@ -601,12 +619,12 @@ func initIBPUid(data *data_proto.IBPGraphicStorage) *IBPUidStructure { } // 构建仿真内所有地图UID映射信号布置图ID,这里为了解决多地图时根据UID反向寻找,避免多次循环地图,直接获取平面布置图元素 -func buildRepositoryAllUidsMap(mapIds []int32, repo *repository.Repository) map[string]*elementIdStructure { +func buildRepositoryAllUidsMap(mapIds []int32, repo *repository.Repository) map[string]*DeviceRelationship { mapLen := len(repo.CheckPointList()) + len(repo.PhysicalSectionList()) + len(repo.SignalList()) + len(repo.TurnoutList()) + len(repo.ResponderList()) + len(repo.SlopeList()) + len(repo.SectionalCurvatureList()) - allUidMap := make(map[string]*elementIdStructure, mapLen) - saveToAllUidMap := func(es map[uint32]*elementIdStructure) { + allUidMap := make(map[string]*DeviceRelationship, mapLen) + saveToAllUidMap := func(es map[uint32]*DeviceRelationship) { for _, e := range es { allUidMap[e.Uid] = e } @@ -625,8 +643,8 @@ func buildRepositoryAllUidsMap(mapIds []int32, repo *repository.Repository) map[ saveToAllUidMap(u.TurnoutIds) saveToAllUidMap(u.SlopeIds) saveToAllUidMap(u.CurvatureIds) - saveToAllUidMap(u.ButtonIds) - saveToAllUidMap(u.SpksSwitchIds) + saveToAllUidMap(u.EsbIds) + saveToAllUidMap(u.SpksIds) saveToAllUidMap(u.StationIds) continue } @@ -644,7 +662,7 @@ func QueryUidStructure[T *StationUidStructure | *RelayUidStructure | *IBPUidStru } // 获取设备类型获取对应字段 -func getUidMapByType(uidData any, m interface{}) map[uint32]*elementIdStructure { +func getUidMapByType(uidData any, m interface{}) map[uint32]*DeviceRelationship { switch m.(type) { case *data_proto.AxleCounting: return (uidData.(*StationUidStructure)).AxlePointIds @@ -663,11 +681,11 @@ func getUidMapByType(uidData any, m interface{}) map[uint32]*elementIdStructure case *data_proto.Relay: return (uidData.(*RelayUidStructure)).RelayIds case *data_proto.EsbButton: - return (uidData.(*StationUidStructure)).ButtonIds + return (uidData.(*StationUidStructure)).EsbIds case *data_proto.Station: return (uidData.(*StationUidStructure)).StationIds case *data_proto.SpksSwitch: - return (uidData.(*StationUidStructure)).SpksSwitchIds + return (uidData.(*StationUidStructure)).SpksIds case *data_proto.ScreenDoor: return (uidData.(*StationUidStructure)).PsdIds case *data_proto.PslBox: @@ -684,7 +702,7 @@ func getUidMapByType(uidData any, m interface{}) map[uint32]*elementIdStructure } // 根据地图ID跟设备类型获取UID集合 -func QueryMapUidMapByType(mapId int32, m interface{}) map[uint32]*elementIdStructure { +func QueryMapUidMapByType(mapId int32, m interface{}) map[uint32]*DeviceRelationship { uidData, ok := giUidMap.Load(mapId) if !ok { panic(&dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("地图【id:%d】不存在uid缓存", mapId)}) diff --git a/ts/simulation/wayside/memory/wayside_simulation.go b/ts/simulation/wayside/memory/wayside_simulation.go index d456f3f..09b0047 100644 --- a/ts/simulation/wayside/memory/wayside_simulation.go +++ b/ts/simulation/wayside/memory/wayside_simulation.go @@ -43,7 +43,7 @@ type VerifySimulation struct { //Rtss仿真世界的 World ecs.World //设备UID映射 key-uid - UidMap map[string]*elementIdStructure + UidMap map[string]*DeviceRelationship // 运行环境配置 runConfig *config.ThirdPartyConfig } @@ -114,26 +114,6 @@ func CreateSimulation(projectId int32, mapIds []int32, runConfig *dto.ProjectRun 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 @@ -185,7 +165,7 @@ func (s *VerifySimulation) GetBtmVobcConfig() config.BtmVobcConfig { // GetSectionCodePoints 获取集中站的区段码表 func (s *VerifySimulation) GetSectionCodePoints(city string, lineId string, centralizedStation string) []*proto.CiSectionCodePoint { - stationUid := GenerateElementUid(city, lineId, nil, centralizedStation) + stationUid := BuildUid(city, lineId, centralizedStation) ref := s.Repo.GetCentralizedStationRef(stationUid) if ref == nil { return nil @@ -196,7 +176,7 @@ func (s *VerifySimulation) GetSectionCodePoints(city string, lineId string, cent // CollectSectionStatus 收集仿真中计轴区段状态 func (s *VerifySimulation) CollectSectionStatus(city string, lineId string, centralizedStation string) ([]*message.SectionStatusMsg, error) { - stationUid := GenerateElementUid(city, lineId, nil, centralizedStation) + stationUid := BuildUid(city, lineId, centralizedStation) // codePoints := s.GetSectionCodePoints(city, lineId, centralizedStation) if len(codePoints) <= 0 { @@ -682,7 +662,7 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *data_pro city := relayGi.UniqueIdPrefix.City lineId := relayGi.UniqueIdPrefix.LineId station := relayGi.UniqueIdPrefix.BelongsConcentrationStation - stationUid := GenerateElementUid(city, lineId, nil, station) + stationUid := BuildUid(city, lineId, station) relayMap := make(map[string]*proto.Relay) for _, relay := range relayGi.Relays { rid := GetMapElementId(relay.Common) @@ -751,7 +731,7 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *data_pro for _, relationship := range relayGi.DeviceRelateRelayList { switch relationship.DeviceType { case data_proto.RelatedRef_Turnout: - turnout := turnoutMap[GenerateElementUid(city, lineId, []string{station}, relationship.Code)] + turnout := turnoutMap[BuildUid(city, lineId, station, relationship.Code)] if turnout == nil { continue } @@ -770,7 +750,7 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *data_pro }) } case data_proto.RelatedRef_signal: - signal := signalMap[GenerateElementUid(city, lineId, []string{station}, relationship.Code)] + signal := signalMap[BuildUid(city, lineId, station, relationship.Code)] if signal == nil { continue } @@ -793,7 +773,7 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *data_pro ComponentIds: componentIds, }) case data_proto.RelatedRef_station: - station := stationMap[GenerateElementUid(city, lineId, nil, relationship.Code)] + station := stationMap[BuildUid(city, lineId, relationship.Code)] if station == nil { continue } @@ -811,7 +791,7 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *data_pro station.ElectronicGroup = append(station.ElectronicGroup, d) } case data_proto.RelatedRef_ScreenDoor: - psd, ok := psdMap[GenerateElementUid(city, lineId, nil, relationship.Code)] + psd, ok := psdMap[BuildUid(city, lineId, relationship.Code)] if !ok { continue } @@ -855,7 +835,7 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *data_pro } case data_proto.RelatedRef_GarageDoor, data_proto.RelatedRef_FloodGate: //车库门||防淹门 { - ckm, ok := ckmMap[GenerateElementUid(city, lineId, nil, relationship.Code)] + ckm, ok := ckmMap[BuildUid(city, lineId, relationship.Code)] if !ok { continue } @@ -876,7 +856,7 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *data_pro } case data_proto.RelatedRef_CarWashing: { - xcj, ok := xcjMap[GenerateElementUid(city, lineId, nil, relationship.Code)] + xcj, ok := xcjMap[BuildUid(city, lineId, relationship.Code)] if !ok { continue } @@ -968,7 +948,7 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *data_pro 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") { + } else if strings.Contains(relay.GetCode(), "PAB") || strings.Contains(relay.GetCode(), "DPB") { mkx.PabjId = relay.Id } else if strings.Contains(relay.GetCode(), "WRZF") { mkx.WrzfjId = relay.Id @@ -981,7 +961,7 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *data_pro } } // 处理该集中站采集、驱动配置信息 - centralizedStationId := GenerateElementUid(city, lineId, nil, station) + centralizedStationId := BuildUid(city, lineId, station) ref := queryCentralizedStationRef(centralizedStationId, repo) ref.CjList = append(ref.CjList, handlerRelayGiCj(relayUidStructure, centralizedStationId, relayGi.CiCjList)...) sortQcTable(ref.CjList) @@ -1301,19 +1281,19 @@ func fillProtoRepository(repo *proto.Repository, storage *data_proto.RtssGraphic 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 - } + //// 初始化站场图按钮 + //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 { @@ -1322,26 +1302,26 @@ func fillProtoRepository(repo *proto.Repository, storage *data_proto.RtssGraphic 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) - } - } + //// 关联车站的设备 + //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) @@ -1447,6 +1427,21 @@ func fillProtoRepository(repo *proto.Repository, storage *data_proto.RtssGraphic } 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.StationIds[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.StationIds[data.RefStand].Uid, + }) + } } func fillCkmOrFym(repo *proto.Repository, doors []*data_proto.GarageDoor, uidsMap *StationUidStructure) { diff --git a/ts/test_simulation_manage.go b/ts/test_simulation_manage.go index 6606a5d..dfc17c9 100644 --- a/ts/test_simulation_manage.go +++ b/ts/test_simulation_manage.go @@ -160,7 +160,7 @@ func stopThirdParty(s *memory.VerifySimulation) { for _, c := range s.GetInterlockCodes() { switch c.Line { case "11": - beijing11.Stop() + beijing11.Stop(c.Code) default: beijing12.Stop(c) }