360 lines
10 KiB
Go
360 lines
10 KiB
Go
package message_server
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
"joylink.club/bj-rtsts-server/message_server/ms_api"
|
|
"joylink.club/bj-rtsts-server/ts/protos/graphicData"
|
|
"joylink.club/bj-rtsts-server/ts/protos/state"
|
|
"joylink.club/bj-rtsts-server/ts/simulation/wayside/memory"
|
|
"joylink.club/ecs"
|
|
"joylink.club/rtsssimulation/component"
|
|
"joylink.club/rtsssimulation/entity"
|
|
)
|
|
|
|
// 信号平面布置图消息服务
|
|
type SfpMs struct {
|
|
vs *memory.VerifySimulation
|
|
mapId int32
|
|
channel string
|
|
}
|
|
|
|
func NewSfpMs(vs *memory.VerifySimulation, mapId int32) *SfpMs {
|
|
return &SfpMs{
|
|
vs: vs,
|
|
mapId: mapId,
|
|
channel: fmt.Sprintf("simulation-%s_%d-devices-status", vs.SimulationId, mapId),
|
|
}
|
|
}
|
|
|
|
// 获取通道名
|
|
func (ms *SfpMs) GetChannel() string {
|
|
return ms.channel
|
|
}
|
|
|
|
// 发送消息间隔时间,单位ms
|
|
func (ms *SfpMs) GetInterval() time.Duration {
|
|
return 200 * time.Millisecond
|
|
}
|
|
|
|
// 定时发送的消息
|
|
func (ms *SfpMs) OnTick() ([]*ms_api.TopicMsg, error) {
|
|
turnoutStates, err := ms.collectTurnoutStates()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
trainStates, err := ms.collectTrainStates()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
signalStates, err := ms.collectSignalStates()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buttonStates, err := ms.collectStationButtonStates()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
psdStates, err := ms.collectPsdStates()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sectionStates, err := ms.collectSectionStates()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
spksStates, err := ms.collectSpksStates()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ststes := &state.PushedDevicesStatus{
|
|
All: true,
|
|
AllStatus: &state.AllDevicesStatus{
|
|
SwitchState: turnoutStates,
|
|
TrainState: trainStates,
|
|
SignalState: signalStates,
|
|
ButtonState: buttonStates,
|
|
PsdState: psdStates,
|
|
SectionState: sectionStates,
|
|
SpksState: spksStates,
|
|
},
|
|
}
|
|
b, err := proto.Marshal(ststes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("信号布置图设备状态消息服务数据序列化失败, %s", err)
|
|
}
|
|
return []*ms_api.TopicMsg{ms_api.NewTopicMsg(ms.channel, b)}, nil
|
|
}
|
|
|
|
func (ms *SfpMs) OnError(err error) {
|
|
// TODO: 错误处理
|
|
}
|
|
|
|
// 收集屏蔽门状态
|
|
func (ms *SfpMs) collectPsdStates() ([]*state.PsdState, error) {
|
|
world := ms.vs.World
|
|
uidStructure := memory.QueryUidStructure[*memory.StationUidStructure](ms.mapId)
|
|
data := memory.QueryGiData[*graphicData.RtssGraphicStorage](ms.mapId)
|
|
var psdStateArr []*state.PsdState
|
|
for _, door := range data.ScreenDoors {
|
|
uid := uidStructure.PsdIds[door.Common.Id].Uid
|
|
psdEntry, ok := entity.GetEntityByUid(world, uid)
|
|
if ok {
|
|
list := component.AsdListType.Get(psdEntry).List
|
|
asdStates := make([]*state.AsdState, len(list), len(list))
|
|
for i, asdEntry := range list {
|
|
asdState := component.AsdStateType.Get(asdEntry)
|
|
asdStates[i] = &state.AsdState{
|
|
Code: strconv.Itoa(i + 1),
|
|
Kmdw: asdState.Kmdw,
|
|
Gmdw: asdState.Gmdw,
|
|
Mgj: asdState.Mgj,
|
|
}
|
|
}
|
|
psdStateArr = append(psdStateArr, &state.PsdState{
|
|
Id: door.Common.Id,
|
|
AsdStates: asdStates,
|
|
Mgj: component.PsdStateType.Get(psdEntry).Close,
|
|
})
|
|
}
|
|
}
|
|
return psdStateArr, nil
|
|
}
|
|
|
|
// 收集区段状态
|
|
func (ms *SfpMs) collectSectionStates() ([]*state.SectionState, error) {
|
|
uidMap := memory.QueryMapUidMapByType(ms.mapId, &graphicData.Section{})
|
|
var sectionArr []*state.SectionState
|
|
for _, u := range uidMap {
|
|
s := handlerSectionState(ms.vs.World, u.Uid)
|
|
if s == nil {
|
|
continue
|
|
}
|
|
s.Id = u.CommonId
|
|
sectionArr = append(sectionArr, s)
|
|
}
|
|
return sectionArr, nil
|
|
}
|
|
|
|
func handlerSectionState(w ecs.World, uid string) *state.SectionState {
|
|
entry, ok := entity.GetEntityByUid(w, uid)
|
|
if !ok {
|
|
//fmt.Printf("id=%s的信号机不存在", uid)
|
|
return nil
|
|
}
|
|
if entry.HasComponent(component.AxleSectionType) { //计轴区段
|
|
sectionState := &state.SectionState{}
|
|
axleState := component.AxleSectionType.Get(entry)
|
|
sectionFault := component.AxleSectionFaultType.Get(entry)
|
|
sectionState.Occupied = axleState.Occ
|
|
sectionState.AxleFault = sectionFault.SectionFault
|
|
return sectionState
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 收集车站按钮状态
|
|
func (ms *SfpMs) collectStationButtonStates() ([]*state.ButtonState, error) {
|
|
// 获取地图上的按钮状态
|
|
uidMap := memory.QueryMapUidMapByType(ms.mapId, &graphicData.EsbButton{})
|
|
var btnStateArr []*state.ButtonState
|
|
for _, u := range uidMap {
|
|
entry, ok := entity.GetEntityByUid(ms.vs.World, u.Uid)
|
|
if !ok {
|
|
return nil, fmt.Errorf("ESB按钮实体不存在: World id=%d, uid=%s", ms.vs.World.Id(), u.Uid)
|
|
}
|
|
if entry.HasComponent(component.ButtonTag) { // 按钮
|
|
bit := component.BitStateType.Get(entry)
|
|
btnStateArr = append(btnStateArr, &state.ButtonState{Id: u.CommonId, Down: bit.Val})
|
|
}
|
|
}
|
|
return btnStateArr, nil
|
|
}
|
|
|
|
// 收集信号机状态
|
|
func (ms *SfpMs) collectSignalStates() ([]*state.SignalState, error) {
|
|
uidMap := memory.QueryMapUidMapByType(ms.mapId, &graphicData.Signal{})
|
|
var signalArr []*state.SignalState
|
|
for _, u := range uidMap {
|
|
s, err := handlerSignalState(ms.vs.World, u.Uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s.Id = u.CommonId
|
|
signalArr = append(signalArr, s)
|
|
}
|
|
return signalArr, nil
|
|
}
|
|
|
|
func handlerSignalState(w ecs.World, uid string) (*state.SignalState, error) {
|
|
entry, ok := entity.GetEntityByUid(w, uid)
|
|
if !ok {
|
|
return nil, fmt.Errorf("信号机不存在: World id=%d, 信号机id=%s", w.Id(), uid)
|
|
}
|
|
if !entry.HasComponent(component.SignalLightsType) { //信号机灯列表
|
|
return nil, fmt.Errorf("信号机没有SignalLights组件: World id=%d, 信号机id=%s", w.Id(), uid)
|
|
}
|
|
signalState := &state.SignalState{}
|
|
lights := component.SignalLightsType.Get(entry)
|
|
isL := false
|
|
isH := false
|
|
isU := false
|
|
isA := false
|
|
isB := false
|
|
for _, light := range lights.Lights {
|
|
switch {
|
|
case light.HasComponent(component.LdTag):
|
|
isL = component.BitStateType.Get(light).Val
|
|
case light.HasComponent(component.HdTag):
|
|
isH = component.BitStateType.Get(light).Val
|
|
case light.HasComponent(component.UdTag):
|
|
isU = component.BitStateType.Get(light).Val
|
|
case light.HasComponent(component.BdTag):
|
|
isB = component.BitStateType.Get(light).Val
|
|
case light.HasComponent(component.AdTag):
|
|
isA = component.BitStateType.Get(light).Val
|
|
}
|
|
}
|
|
if isH && isU {
|
|
signalState.Aspect = state.Signal_HU
|
|
} else {
|
|
switch {
|
|
case isL:
|
|
signalState.Aspect = state.Signal_L
|
|
case isH:
|
|
signalState.Aspect = state.Signal_H
|
|
case isU:
|
|
signalState.Aspect = state.Signal_U
|
|
case isB:
|
|
signalState.Aspect = state.Signal_B
|
|
case isA:
|
|
signalState.Aspect = state.Signal_A
|
|
}
|
|
}
|
|
return signalState, nil
|
|
}
|
|
|
|
// 收集列车状态
|
|
func (ms *SfpMs) collectTrainStates() ([]*state.TrainState, error) {
|
|
allTrainMap := &ms.vs.Memory.Status.TrainStateMap
|
|
var trainArr []*state.TrainState
|
|
allTrainMap.Range(func(_, v any) bool {
|
|
trainArr = append(trainArr, v.(*state.TrainState))
|
|
return true
|
|
})
|
|
return trainArr, nil
|
|
}
|
|
|
|
// 收集道岔状态
|
|
func (ms *SfpMs) collectTurnoutStates() ([]*state.SwitchState, error) {
|
|
s := ms.vs
|
|
uidMap := memory.QueryMapUidMapByType(ms.mapId, &graphicData.Turnout{})
|
|
var switchArr []*state.SwitchState
|
|
for _, u := range uidMap {
|
|
entry, ok := entity.GetEntityByUid(s.World, u.Uid)
|
|
if !ok {
|
|
return nil, fmt.Errorf("道岔不存在: World id=%d,道岔id=%s", s.World.Id(), u.Uid)
|
|
}
|
|
if !entry.HasComponent(component.TurnoutPositionType) {
|
|
return nil, fmt.Errorf("道岔没有TurnoutPosition组件: World id=%d,道岔id=%s", s.World.Id(), u.Uid)
|
|
}
|
|
pos := component.TurnoutPositionType.Get(entry)
|
|
s := &state.SwitchState{
|
|
Id: u.CommonId,
|
|
Normal: pos.Db,
|
|
Reverse: pos.Fb,
|
|
Dw: pos.Dw,
|
|
Fw: pos.Fw,
|
|
}
|
|
// 强制(联锁驱动无效)
|
|
s.Force = entry.HasComponent(component.TurnoutFaultCiqdType)
|
|
// 失表
|
|
s.Sb = entry.HasComponent(component.TurnoutFaultSbType)
|
|
// 定位失表
|
|
s.Dwsb = entry.HasComponent(component.TurnoutFaultDwsbType)
|
|
// 反位失表
|
|
s.Fwsb = entry.HasComponent(component.TurnoutFaultFwsbType)
|
|
// 挤岔
|
|
s.Jc = entry.HasComponent(component.TurnoutFaultJcType)
|
|
|
|
// if entry.HasComponent(component.Zdj9TwoElectronicType) {
|
|
// elec := component.Zdj9TwoElectronicType.Get(entry)
|
|
|
|
// }
|
|
switchArr = append(switchArr, s)
|
|
}
|
|
return switchArr, nil
|
|
}
|
|
|
|
// 人员防护开关状态
|
|
func (ms *SfpMs) collectSpksStates() ([]*state.SpksState, error) {
|
|
uidsMap := memory.QueryUidStructure[*memory.StationUidStructure](ms.mapId)
|
|
var states []*state.SpksState
|
|
for _, stationUid := range uidsMap.StationIds {
|
|
entry, ok := entity.GetEntityByUid(ms.vs.World, stationUid.Uid)
|
|
if !ok {
|
|
return nil, fmt.Errorf("车站实体不存在: World id=%d, uid=%s", ms.vs.World.Id(), stationUid.Uid)
|
|
}
|
|
if entry.HasComponent(component.SpkElectronicType) {
|
|
spkElectronic := component.SpkElectronicType.Get(entry)
|
|
// 下行
|
|
xplj := getRelayXqVal(spkElectronic.SPKSXPLAJ)
|
|
xplb := getIbpBtnVal(spkElectronic.SPKSXPLA_BTN)
|
|
states = append(states, createSpksState(spkElectronic.SPKSX1J_KEY, spkElectronic.SPKSX1J, spkElectronic.SPKSX1D, xplb, xplj, ms.vs))
|
|
states = append(states, createSpksState(spkElectronic.SPKSX3J_KEY, spkElectronic.SPKSX3J, spkElectronic.SPKSX3D, xplb, xplj, ms.vs))
|
|
// 上行
|
|
splj := getRelayXqVal(spkElectronic.SPKSSPLAJ)
|
|
splb := getIbpBtnVal(spkElectronic.SPKSSPLA_BTN)
|
|
states = append(states, createSpksState(spkElectronic.SPKSS2J_KEY, spkElectronic.SPKSS2J, spkElectronic.SPKSS2D, splb, splj, ms.vs))
|
|
states = append(states, createSpksState(spkElectronic.SPKSS4J_KEY, spkElectronic.SPKSS4J, spkElectronic.SPKSS4D, splb, splj, ms.vs))
|
|
}
|
|
}
|
|
return states, nil
|
|
}
|
|
|
|
// 创建实体
|
|
func createSpksState(k, j, d *ecs.Entry, pl, pj bool, s *memory.VerifySimulation) *state.SpksState {
|
|
uid := getEntryId(k)
|
|
return &state.SpksState{
|
|
Id: s.GetComIdByUid(uid),
|
|
Open: getIbpKeyVal(k),
|
|
Xh: getRelayXqVal(j),
|
|
Light: getLightTdVal(d),
|
|
Pl: pl,
|
|
Pljxh: pj,
|
|
}
|
|
}
|
|
|
|
// 获取实体ID
|
|
func getEntryId(entry *ecs.Entry) string {
|
|
id := component.UidType.Get(entry)
|
|
return id.Id
|
|
}
|
|
|
|
// 获取按钮状态
|
|
func getIbpBtnVal(entry *ecs.Entry) bool {
|
|
btn := component.BitStateType.Get(entry)
|
|
return btn.Val
|
|
}
|
|
|
|
// 获取按钮状态
|
|
func getIbpKeyVal(entry *ecs.Entry) bool {
|
|
btn := component.GearStateType.Get(entry)
|
|
return btn.Val == 1
|
|
}
|
|
|
|
// 获取继电器吸起状态
|
|
func getRelayXqVal(entry *ecs.Entry) bool {
|
|
relay := component.BitStateType.Get(entry)
|
|
return relay.Val
|
|
}
|
|
|
|
// 设置信号灯通电
|
|
func getLightTdVal(entry *ecs.Entry) bool {
|
|
light := component.BitStateType.Get(entry)
|
|
return light.Val
|
|
}
|