package ts import ( "fmt" "log/slog" "runtime" "strconv" "sync" "joylink.club/bj-rtsts-server/third_party/can_btm" cidcmodbus "joylink.club/bj-rtsts-server/third_party/cidc_modbus" "joylink.club/bj-rtsts-server/third_party/axle_device" "joylink.club/bj-rtsts-server/third_party/electrical_machinery" "joylink.club/bj-rtsts-server/message_server" "joylink.club/bj-rtsts-server/mqtt" "joylink.club/bj-rtsts-server/sys_error" "joylink.club/bj-rtsts-server/third_party/dynamics" "joylink.club/bj-rtsts-server/third_party/interlock" "joylink.club/bj-rtsts-server/third_party/semi_physical_train" "joylink.club/bj-rtsts-server/ts/simulation/wayside/memory" "joylink.club/bj-rtsts-server/dto" rtss_simulation "joylink.club/rtsssimulation" ) // 仿真存储集合 var simulationMap sync.Map // 创建前检查 func IsExistSimulation() bool { i := 0 simulationMap.Range(func(_, _ any) bool { i++ return true }) return i > 0 } // 创建仿真对象 func CreateSimulation(projectId int32, mapIds []int32, runConfig *dto.ProjectRunConfigDto) (string, error) { simulationId := createSimulationId(projectId) _, e := simulationMap.Load(simulationId) if !e && IsExistSimulation() { return "", sys_error.New("一套环境同时只能运行一个仿真") } if !e { verifySimulation, err := memory.CreateSimulation(projectId, mapIds, runConfig) if err != nil { return "", err } verifySimulation.SimulationId = simulationId // world构建 err = initWorld(verifySimulation) if err != nil { return "", err } // 第三方服务处理 err = runThirdParty(verifySimulation) if err != nil { verifySimulation.World.Close() return "", err } simulationMap.Store(simulationId, verifySimulation) // verifySimulation.Start() // 全部成功,启动仿真 verifySimulation.World.StartUp() // 启动仿真消息服务 message_server.Start(verifySimulation) } return simulationId, nil } // 删除仿真对象 func DestroySimulation(simulationId string) { s, e := simulationMap.Load(simulationId) if !e { return } simulationMap.Delete(simulationId) simulationInfo := s.(*memory.VerifySimulation) // simulationInfo.Destroy() // 停止ecs world simulationInfo.World.Close() message_server.Close(simulationInfo) // 发布销毁消息 message_server.PubSimulationDestroyMsg(simulationId) // 停止第三方 stopThirdParty(simulationInfo) } // 创建world func initWorld(s *memory.VerifySimulation) error { //创建仿真 w, err := rtss_simulation.NewSimulation(s.Repo) if err != nil { return sys_error.New(fmt.Sprintf("仿真创建失败: %s", err), err) } s.World = w // 保证World关闭 runtime.SetFinalizer(s, func(verifySimulation *memory.VerifySimulation) { slog.Info("---关闭仿真World---") verifySimulation.World.Close() }) return nil } // 运行仿真第三方模块 func runThirdParty(s *memory.VerifySimulation) error { // 动力学启动 err := dynamics.Default().Start(s) if err != nil { return err } // 半实物启动 semi_physical_train.Default().Start(s) // 联锁启动 for _, c := range s.GetInterlockCodes() { interlock.Default(c).Start(s) } // 计轴RSSP启动 axle_device.StartLineAllRsspAxleServices(s) // 电机UDP启动 electrical_machinery.Default().Start(s) // 车载BTM启动 can_btm.Default().Start(s) // 联锁驱采Modbus服务启动 err = cidcmodbus.Start(s) if err != nil { return err } return nil } // 停止仿真 func stopThirdParty(s *memory.VerifySimulation) { // 停止动力学接口功能 dynamics.Default().Stop() // 停止半实物 semi_physical_train.Default().Stop() // 联锁启动 for _, c := range s.GetInterlockCodes() { interlock.Default(c).Stop() } //计轴RSSP启动销毁 axle_device.StopLineAllRsspAxleServices() // 电机UDP停止 electrical_machinery.Default().Stop() // 车载BTM停止 can_btm.Default().Stop() // 联锁驱采Modbus服务停止 cidcmodbus.Stop() } func createSimulationId(projectId int32) string { // MQTT客户端id+项目 return mqtt.GetClientId() + "_" + strconv.Itoa(int(projectId)) } // 获取仿真列表 func ListAllSimulations() []*dto.SimulationInfoRspDto { var simArr []*dto.SimulationInfoRspDto simulationMap.Range(func(_, v any) bool { s := v.(*memory.VerifySimulation) simArr = append(simArr, &dto.SimulationInfoRspDto{ SimulationId: s.SimulationId, MapId: s.MapIds[0], MapIds: s.MapIds, ProjectId: s.ProjectId, ProjectRunConfigId: s.GetRunConfigId(), }) return true }) return simArr } // 根据仿真id查找仿真实例 func FindSimulation(simulationId string) *memory.VerifySimulation { m, e := simulationMap.Load(simulationId) if e { return m.(*memory.VerifySimulation) } return nil }