diff --git a/ats/verify/simulation/simulation_manage.go b/ats/verify/simulation/simulation_manage.go index e0256aa..9eeec0c 100644 --- a/ats/verify/simulation/simulation_manage.go +++ b/ats/verify/simulation/simulation_manage.go @@ -57,7 +57,7 @@ func init() { } trainState := sta.(*state.TrainState) // 给半实物仿真发送速度 - vobc.SendTrainSpeedTask(math.Abs(float64(info.Speed * 36))) + vobc.SendTrainSpeedTask(convertVobc(info)) // 更新列车状态 memory.UpdateTrainState(simulation, convert(info, trainState, simulation)) } @@ -207,6 +207,21 @@ func convert(info *dynamics.TrainInfo, sta *state.TrainState, simulation *memory return sta } +// 转换成Vobc发送参数 +func convertVobc(info *dynamics.TrainInfo) *vobc.SendTrainInfo { + param := &vobc.SendTrainInfo{ + Speed: uint16(math.Abs(float64(info.Speed * 36))), + Upslope: info.UpSlope, + Slope: uint16(info.Slope), + Acceleration: uint16(info.Acceleration * 100), + TotalResistance: uint16(info.TotalResistance / 10), + AirResistance: uint16(info.AirResistance / 10), + SlopeResistance: uint16(info.SlopeResistance / 10), + CurveResistance: uint16(info.CurveResistance / 10), + } + return param +} + func dynamicsRun(verifySimulation *memory.VerifySimulation) { _ = dynamics.Run(func() []*dynamics.TurnoutInfo { stateSlice := memory.GetAllTurnoutState(verifySimulation) diff --git a/ats/verify/simulation/wayside/memory/wayside_memory_map.go b/ats/verify/simulation/wayside/memory/wayside_memory_map.go index 7f80ff3..9b228da 100644 --- a/ats/verify/simulation/wayside/memory/wayside_memory_map.go +++ b/ats/verify/simulation/wayside/memory/wayside_memory_map.go @@ -19,12 +19,14 @@ import ( var ( giTypeMap sync.Map + giNameMap sync.Map giDataMap sync.Map ) // 将发布的地图数据放入内存中 func PublishMapVerifyStructure(graphic *model.PublishedGi) { giTypeMap.Store(graphic.ID, graphicData.PictureType(graphic.Type)) + giNameMap.Store(graphic.Name, graphic.ID) var message proto.Message switch graphicData.PictureType(graphic.Type) { case graphicData.PictureType_StationLayout: @@ -92,6 +94,22 @@ func QueryEcsLinkByDeviceInfo(repo *repository.Repository, mapId int32, id strin } } +func getStorageIBPMapData(mapCode string) *graphicData.IBPGraphicStorage { + // 处理关联的IBP盘信息 + if mapCode == "" { + return nil + } + ibpId, ok := giNameMap.Load(mapCode) + if !ok { + return nil + } + ibpMapData, ok := giDataMap.Load(ibpId) + if !ok { + return nil + } + return ibpMapData.(*graphicData.IBPGraphicStorage) +} + // 根据物理区段上的偏移量(基于区段A端),找到所在link的linkId与偏移量 func sectionMapToEcsLink(repo *repository.Repository, id string, offset int64, runDirection bool) (int32, int64, bool, bool, int64) { section := repo.FindPhysicalSection(id) diff --git a/ats/verify/simulation/wayside/memory/wayside_memory_map_init.go b/ats/verify/simulation/wayside/memory/wayside_memory_map_init.go index 5628556..1faec15 100644 --- a/ats/verify/simulation/wayside/memory/wayside_memory_map_init.go +++ b/ats/verify/simulation/wayside/memory/wayside_memory_map_init.go @@ -2,7 +2,6 @@ package memory import ( "fmt" - "strconv" "sync" "joylink.club/bj-rtsts-server/ats/verify/protos/graphicData" @@ -161,21 +160,16 @@ func initStationUid(data *graphicData.RtssGraphicStorage) *stationUidStructure { Uid: GenerateElementUid(city, lineId, nil, s.Code), } // 处理关联的IBP盘信息 - if s.RefIbpMapCode == "" { - continue - } - ibpId, _ := strconv.Atoi(s.RefIbpMapCode) - ibpMapData, ok := giDataMap.Load(ibpId) - if !ok { - continue - } - initIBPUid(gus, city, lineId, s, ibpMapData.(*graphicData.IBPGraphicStorage)) + initIBPUid(gus, city, lineId, s, getStorageIBPMapData(s.RefIbpMapCode)) } return gus } // 处理IBP盘信息 func initIBPUid(gus *stationUidStructure, city, lineId string, station *graphicData.Station, data *graphicData.IBPGraphicStorage) { + if data == nil { + return + } // 设备所属组合 refMap := make(map[string]string) for _, r := range data.IbpRelatedDevices { @@ -196,24 +190,28 @@ func initIBPUid(gus *stationUidStructure, city, lineId string, station *graphicD for _, d := range data.IbpButtons { // ibp按钮 uidMap[d.Common.Id] = &elementIdStructure{ CommonId: d.Common.Id, + Code: d.Code, Uid: GenerateElementUid(city, lineId, []string{station.Code}, getCode(d.Common.Id, d.Code)), } } for _, d := range data.IbpKeys { // ibp钥匙 uidMap[d.Common.Id] = &elementIdStructure{ CommonId: d.Common.Id, + Code: d.Code, Uid: GenerateElementUid(city, lineId, []string{station.Code}, getCode(d.Common.Id, d.Code)), } } for _, d := range data.IbpAlarms { // ibp报警器 uidMap[d.Common.Id] = &elementIdStructure{ CommonId: d.Common.Id, + Code: d.Code, Uid: GenerateElementUid(city, lineId, []string{station.Code}, getCode(d.Common.Id, d.Code)), } } for _, d := range data.IbpLights { // ibp指示灯 uidMap[d.Common.Id] = &elementIdStructure{ CommonId: d.Common.Id, + Code: d.Code, Uid: GenerateElementUid(city, lineId, []string{station.Code}, getCode(d.Common.Id, d.Code)), } } diff --git a/ats/verify/simulation/wayside/memory/wayside_simulation.go b/ats/verify/simulation/wayside/memory/wayside_simulation.go index 8c07862..7d9d5fa 100644 --- a/ats/verify/simulation/wayside/memory/wayside_simulation.go +++ b/ats/verify/simulation/wayside/memory/wayside_simulation.go @@ -2,6 +2,7 @@ package memory import ( "fmt" + "log/slog" "sort" "strconv" "strings" @@ -213,6 +214,10 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *graphicD 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 { switch relationship.DeviceType { case graphicData.RelatedRef_Turnout: @@ -253,6 +258,24 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *graphicD 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 { + 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) + } } } } @@ -410,6 +433,133 @@ func fillProtoRepository(repo *proto.Repository, storage *graphicData.RtssGraphi 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, + } + 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()}) + } } func converCheckPointUid(data *proto.CheckPoint, uidsMap *stationUidStructure) *proto.CheckPoint { diff --git a/go.work.sum b/go.work.sum index 81b4853..eae645d 100644 --- a/go.work.sum +++ b/go.work.sum @@ -208,4 +208,5 @@ gorm.io/driver/clickhouse v0.5.0/go.mod h1:cIKAlFw+IVK75g0bDcm0M9qRA4EAgsn23Si+z gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg= gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/vobc/udp.go b/vobc/udp.go index d13eb79..527d169 100644 --- a/vobc/udp.go +++ b/vobc/udp.go @@ -113,16 +113,13 @@ func RunUdpServer() { } // 发送列车速度到VOBC -func SendTrainSpeedTask(speed float64) error { +func SendTrainSpeedTask(trainInfo *SendTrainInfo) error { if running { return nil } mutex.Lock() defer mutex.Unlock() - trainInfo := &SendTrainInfo{ - LifeSignal: sendTrainLifeSignal, - Speed: uint16(speed), - } + trainInfo.LifeSignal = sendTrainLifeSignal err := sendVobcMsg(encoderVobcTrainInfo(trainInfo)) if err != nil { slog.Error("发送Vobc信息失败", err) @@ -167,5 +164,18 @@ func encoderVobcTrainInfo(info *SendTrainInfo) []byte { var data []byte data = binary.BigEndian.AppendUint16(data, info.LifeSignal) data = binary.BigEndian.AppendUint16(data, info.Speed) + if info.Upslope { + data = append(data, 1<<7) + } else { + data = append(data, 0) + } + // 中间预留一位 + data = append(data, 0) + data = binary.BigEndian.AppendUint16(data, info.Acceleration) // 加速度 100 = 1 m/s*s + data = binary.BigEndian.AppendUint16(data, info.TotalResistance) // 实际运行阻力 100 = 1KN + data = binary.BigEndian.AppendUint16(data, info.AirResistance) // 空气阻力 100 = 1KN + data = binary.BigEndian.AppendUint16(data, info.SlopeResistance) // 坡道阻力 100 = 1KN + data = binary.BigEndian.AppendUint16(data, info.CurveResistance) // 曲线阻力 100 = 1KN + data = binary.BigEndian.AppendUint16(data, info.Slope) // 坡度值 1= 1‰ return data } diff --git a/vobc/udpData.go b/vobc/udpData.go index 0aaa645..dde312a 100644 --- a/vobc/udpData.go +++ b/vobc/udpData.go @@ -96,4 +96,18 @@ type SendTrainInfo struct { LifeSignal uint16 // 列车速度 10=1km/h Speed uint16 + // 上坡 + Upslope bool + // 坡度值 1= 1‰ + Slope uint16 + // 加速度 100 = 1 m/s*s + Acceleration uint16 + // 实际运行阻力 100 = 1KN + TotalResistance uint16 + // 空气阻力 100 = 1KN + AirResistance uint16 + // 坡道阻力 100 = 1KN + SlopeResistance uint16 + // 曲线阻力 100 = 1KN + CurveResistance uint16 }