rts-sim-testing-service/ats/verify/simulation/simulation_manage.go

217 lines
6.6 KiB
Go

package simulation
import (
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/model/device"
"net"
"strings"
"fmt"
"go.uber.org/zap"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/dynamics"
"net/http"
"strconv"
"sync"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/memory"
"joylink.club/bj-rtsts-server/dto"
)
var simulationId_prefix = (func() string {
ip := "127.0.0.1"
addrList, err := net.InterfaceAddrs()
if err != nil {
panic(err)
}
for _, address := range addrList {
if ipNet, ok := address.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
ip = ipNet.IP.String()
}
}
}
ipArr := strings.Split(ip, ".")
return ipArr[2] + "_" + ipArr[3]
})()
func init() {
dynamics.RegisterTrainInfoHandler(func(info *dynamics.TrainInfo) {
for _, simulation := range GetSimulationArr() {
sta, ok := simulation.Memory.Status.TrainStateMap.Load(strconv.Itoa(int(info.Number)))
if ok {
memory.UpdateTrainState(simulation, convert(info, *sta.(*state.TrainState), memory.QueryMapVerifyStructure(simulation.MapId)))
break
}
}
})
}
// 仿真存储集合
var simulationMap sync.Map
// 创建仿真对象
func CreateSimulation(mapId int32) string {
simulationId := createSimulationId(mapId)
_, e := simulationMap.Load(simulationId)
if !e {
verifySimulation := memory.CreateSimulation(mapId, simulationId)
//通知动力学
httpCode, _, err := dynamics.SendSimulationStartReq(buildLineBaseInfo(memory.QueryMapVerifyStructure(verifySimulation.MapId)))
if httpCode != http.StatusOK || err != nil {
panic(dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
}
simulationMap.Store(simulationId, verifySimulation)
dynamicsRun(verifySimulation)
}
return simulationId
}
// 删除仿真对象
func DestroySimulation(simulationId string) {
//移除道岔状态发送
dynamics.Stop()
//通知动力学
httpCode, _, err := dynamics.SendSimulationEndReq()
if httpCode != http.StatusOK || err != nil {
panic(dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
}
simulationMap.Delete(simulationId)
}
// 创建时生成仿真Id
func createSimulationId(mapId int32) string {
// 当前服务器IP + 端口 + 地图
return simulationId_prefix + "_" + strconv.Itoa(config.Config.Server.Port) + "_" + strconv.Itoa(int(mapId))
}
// 获取仿真列表
func ListAllSimulations() []*dto.SimulationInfoRepDto {
simArr := []*dto.SimulationInfoRepDto{}
simulationMap.Range(func(k, v any) bool {
s := v.(*memory.VerifySimulation)
simArr = append(simArr, &dto.SimulationInfoRepDto{
SimulationId: s.SimulationId,
MapId: strconv.Itoa(int(s.MapId)),
})
return true
})
return simArr
}
// 根据仿真id查找仿真实例
func FindSimulation(simulationId string) *memory.VerifySimulation {
m, e := simulationMap.Load(simulationId)
if e {
return m.(*memory.VerifySimulation)
}
return nil
}
// 获取普通仿真数组
func GetSimulationArr() []*memory.VerifySimulation {
result := []*memory.VerifySimulation{}
simulationMap.Range(func(k, v any) bool {
result = append(result, v.(*memory.VerifySimulation))
return true
})
return result
}
func convert(info *dynamics.TrainInfo, sta state.TrainState, vs *memory.VerifyStructure) *state.TrainState {
zap.S().Debugf("原始消息:[%d-%d-%d]", info.Number, info.Link, info.LinkOffset)
modeller := vs.LinkModelMap[int32(info.Link)]
model := modeller.(*device.LinkModel)
for i, dp := range model.DevicePositions {
if uint32(dp.Offset) >= info.LinkOffset {
var minLinkRef *graphicData.RelatedRef
var minOffset int32
var maxOffset int32
if i == 0 {
minLinkRef = model.SectionLinkMap[dp.Device.GetGraphicId()]
minOffset = dp.Offset
maxOffset = model.DevicePositions[i+1].Offset
} else {
minLinkRef = model.SectionLinkMap[model.DevicePositions[i-1].Device.GetGraphicId()]
minOffset = model.DevicePositions[i-1].Offset
maxOffset = dp.Offset
}
switch minLinkRef.DevicePort {
case 0:
sta.HeadLinkId = minLinkRef.GetId()
sta.HeadLinkOffset = int64(info.LinkOffset - uint32(minOffset))
case 1:
sta.HeadLinkId = minLinkRef.GetId()
sta.HeadLinkOffset = int64(uint32(maxOffset) - info.LinkOffset)
}
break
}
}
zap.S().Debugf("转换后的消息:[%d-%s-%d]", info.Number, sta.HeadLinkId, sta.HeadLinkOffset)
sta.Slope = int32(info.Slope)
sta.Upslope = info.UpSlope
sta.RunningUp = info.Up
sta.RunningResistanceSum = float32(info.TotalResistance) / 1000
sta.AirResistance = float32(info.AirResistance) / 1000
sta.RampResistance = float32(info.SlopeResistance) / 1000
sta.CurveResistance = float32(info.CurveResistance) / 1000
sta.Speed = info.Speed * 3.6
sta.HeadSensorSpeed1 = info.HeadSpeed1 * 3.6
sta.HeadSensorSpeed2 = info.HeadSpeed2 * 3.6
sta.TailSensorSpeed1 = info.TailSpeed1 * 3.6
sta.TailSensorSpeed2 = info.TailSpeed2 * 3.6
sta.HeadRadarSpeed = info.HeadRadarSpeed * 3.6
sta.TailRadarSpeed = info.TailRadarSpeed * 3.6
return &sta
}
func dynamicsRun(verifySimulation *memory.VerifySimulation) {
_ = dynamics.Run(func() []*dynamics.TurnoutInfo {
stateSlice := memory.GetAllTurnoutState(verifySimulation)
var turnoutInfoSlice []*dynamics.TurnoutInfo
for _, sta := range stateSlice {
code64, err := strconv.ParseUint(sta.Id, 10, 16)
if err != nil {
zap.S().Error("id转uint16报错", err)
}
info := dynamics.TurnoutInfo{
Code: uint16(code64),
NPosition: sta.Normal,
RPosition: sta.Reverse,
}
turnoutInfoSlice = append(turnoutInfoSlice, &info)
}
return turnoutInfoSlice
})
}
func buildLineBaseInfo(vs *memory.VerifyStructure) *dynamics.LineBaseInfo {
var links []*dynamics.Link
for _, modeller := range vs.LinkModelMap {
link := modeller.(*device.LinkModel)
id, _ := strconv.Atoi(link.Index)
var aTurnoutId int
if link.ARelatedSwitchRef.SwitchDevice != nil {
aTurnoutId, _ = strconv.Atoi(link.ARelatedSwitchRef.SwitchDevice.GetIndex())
}
var bTurnoutId int
if link.BRelatedSwitchRef.SwitchDevice != nil {
bTurnoutId, _ = strconv.Atoi(link.BRelatedSwitchRef.SwitchDevice.GetIndex())
}
links = append(links, &dynamics.Link{
ID: int32(id),
Len: link.Length,
ARelTurnoutId: int32(aTurnoutId),
ARelTurnoutPoint: link.ARelatedSwitchRef.Port.Name(),
BRelTurnoutId: int32(bTurnoutId),
BRelTurnoutPoint: link.BRelatedSwitchRef.Port.Name(),
})
}
return &dynamics.LineBaseInfo{
LinkList: links,
SlopeList: nil,
CurveList: nil,
}
}