package memory import ( "encoding/hex" "fmt" "joylink.club/ecs" "strings" "joylink.club/bj-rtsts-server/dto" "joylink.club/bj-rtsts-server/dto/data_proto" "joylink.club/bj-rtsts-server/sys_error" "joylink.club/rtsssimulation/component" "joylink.club/rtsssimulation/component/component_data" "joylink.club/rtsssimulation/entity" "joylink.club/rtsssimulation/repository" "joylink.club/rtsssimulation/repository/model/proto" "joylink.club/rtsssimulation/util/number" "sort" ) // BalisePositionModify 应答器移位 func BalisePositionModify(simulation *VerifySimulation, req *dto.BaliseMoveReqDto) *sys_error.BusinessError { uid := QueryMapUidMapByType(req.MapId, &data_proto.Transponder{})[req.BaliseId].Uid transponder := simulation.Repo.FindTransponder(uid) if transponder == nil { return sys_error.New(fmt.Sprintf("未找到[mapId:%d id:%d]的应答器", req.MapId, req.BaliseId)) } //将请求参数中的公里标转为rtss仿真所用的公里标 km := &proto.Kilometer{ Value: req.Km.Kilometer, CoordinateSystem: req.Km.CoordinateSystem, } if req.Km.Direction == data_proto.KilometerSystem_LEFT { km.Direction = proto.Direction_LEFT } else if req.Km.Direction == data_proto.KilometerSystem_RIGHT { km.Direction = proto.Direction_RIGHT } else { panic(fmt.Sprintf("未知的公里标方向[%d]", req.Km.Direction)) } //将应答器所在Link的两端公里标转为请求参数中公里标的坐标系 link := transponder.LinkPosition().Link() akm, err := repository.ConvertKilometer(simulation.Repo, link.AKm(), km.CoordinateSystem) if err != nil { panic(sys_error.New("应答器所在Link的起点公里标转换失败")) } bkm, err := repository.ConvertKilometer(simulation.Repo, link.BKm(), km.CoordinateSystem) if err != nil { panic(sys_error.New("应答器所在Link的终点公里标转换失败")) } //筛选出Link上所有的应答器,并按公里标大小排序 var transponders []*repository.Transponder for _, device := range link.Devices() { t, ok := device.(*repository.Transponder) if ok { transponders = append(transponders, t) } } sort.Slice(transponders, func(i, j int) bool { aT := transponders[i] bT := transponders[j] aTKm, err := repository.ConvertKilometer(simulation.Repo, aT.Km(), km.CoordinateSystem) if err != nil { panic(sys_error.New(fmt.Sprintf("应答器[id:%s]公里标转换失败", aT.Id()))) } bTKm, err := repository.ConvertKilometer(simulation.Repo, bT.Km(), km.CoordinateSystem) if err != nil { panic(sys_error.New(fmt.Sprintf("应答器[id:%s]公里标转换失败", bT.Id()))) } return aTKm.Value < bTKm.Value }) //确保请求的公里标没有超出Link范围且在相邻的应答器之间 var minKm *proto.Kilometer var maxKm *proto.Kilometer if akm.Value < bkm.Value { minKm = akm maxKm = bkm } else { minKm = bkm maxKm = akm } for i, t := range transponders { if t == transponder { if i > 0 { minKm, err = repository.ConvertKilometer(simulation.Repo, transponders[i-1].Km(), km.CoordinateSystem) } if i < len(transponders)-1 { maxKm, err = repository.ConvertKilometer(simulation.Repo, transponders[i+1].Km(), km.CoordinateSystem) } } } //更新应答器公里标和Link位置 entry, _ := entity.GetEntityByUid(simulation.World, uid) if km.Value <= minKm.Value || km.Value >= maxKm.Value { return sys_error.New("位置设置错误,必须在相邻的应答器/道岔/轨道边界之间") } component.KmType.Set(entry, km) offset := number.Abs(km.Value - akm.Value) component.LinkPositionType.Set(entry, &component_data.LinkPosition{ LinkId: link.Id(), Offset: offset, }) return nil } // BalisePositionReset 应答器复位 func BalisePositionReset(simulation *VerifySimulation, req *dto.BaliseReqDto) *sys_error.BusinessError { uid := QueryMapUidMapByType(req.MapId, &data_proto.Transponder{})[req.BaliseId].Uid balise := simulation.Repo.FindTransponder(uid) if balise == nil { return sys_error.New(fmt.Sprintf("未找到[mapId:%d id:%d]的应答器", req.MapId, req.BaliseId)) } return balisePositionReset(simulation, balise) } // BaliseTelegramModify 修改应答器报文 func BaliseTelegramModify(simulation *VerifySimulation, req *dto.BaliseModifyTelegramReqDto) *sys_error.BusinessError { uid := QueryMapUidMapByType(req.MapId, &data_proto.Transponder{})[req.BaliseId].Uid entry, ok := entity.GetEntityByUid(simulation.World, uid) if !ok { return sys_error.New(fmt.Sprintf("没有[mapId:%d id:%d]的应答器", req.MapId, req.BaliseId)) } fixedTelegramLen := 256 if len(req.FixedTelegram) != fixedTelegramLen { return sys_error.New(fmt.Sprintf("固定报文长度必须为[%d]", fixedTelegramLen)) } fixedUserTelegramLen := 208 if len(req.FixedUserTelegram) != fixedUserTelegramLen { return sys_error.New(fmt.Sprintf("固定用户报文长度必须为[%d]", fixedUserTelegramLen)) } ft, err := hex.DecodeString(req.FixedTelegram) if err != nil { return sys_error.New("固定报文解析出错", err) } fut, err := hex.DecodeString(req.FixedUserTelegram) if err != nil { return sys_error.New("固定用户报文解析出错", err) } vt, err := hex.DecodeString(req.VariableTelegram) if err != nil { return sys_error.New("可变报文解析出错", err) } vut, err := hex.DecodeString(req.VariableUserTelegram) if err != nil { return sys_error.New("可变用户报文解析出错", err) } return sendEcsRequest(simulation.World, func() error { component.BaliseFixedTelegramType.SetValue(entry, component.BaliseTelegram{ Telegram: ft, UserTelegram: fut, }) if entry.HasComponent(component.BaliseVariableTelegramType) { component.BaliseVariableTelegramType.SetValue(entry, component.BaliseTelegram{ Telegram: vt, UserTelegram: vut, }) } return nil }) } // BaliseTelegramReset 重置应答器报文 func BaliseTelegramReset(simulation *VerifySimulation, req *dto.BaliseReqDto) *sys_error.BusinessError { uid := QueryMapUidMapByType(req.MapId, &data_proto.Transponder{})[req.BaliseId].Uid worldData := entity.GetWorldData(simulation.World) balise := worldData.Repo.FindTransponder(uid) if balise == nil { return sys_error.New(fmt.Sprintf("未找到[mapId:%d id:%d]的应答器", req.MapId, req.BaliseId)) } return baliseTelegramReset(simulation, balise) } // BaliseTelegramStop 应答器报文停止发送 func BaliseTelegramStop(simulation *VerifySimulation, req *dto.BaliseReqDto) *sys_error.BusinessError { uid := QueryMapUidMapByType(req.MapId, &data_proto.Transponder{})[req.BaliseId].Uid worldData := entity.GetWorldData(simulation.World) balise := worldData.Repo.FindTransponder(uid) if balise == nil { return sys_error.New(fmt.Sprintf("未找到[mapId:%d id:%d]的应答器", req.MapId, req.BaliseId)) } entry, _ := entity.GetEntityByUid(simulation.World, balise.Id()) return sendEcsRequest(simulation.World, func() error { component.BaliseWorkStateType.SetValue(entry, component.BaliseWorkState{Work: false}) return nil }) } // BaliseTelegramSend 应答器报文重新开始发送 func BaliseTelegramSend(simulation *VerifySimulation, req *dto.BaliseReqDto) *sys_error.BusinessError { uid := QueryMapUidMapByType(req.MapId, &data_proto.Transponder{})[req.BaliseId].Uid worldData := entity.GetWorldData(simulation.World) balise := worldData.Repo.FindTransponder(uid) if balise == nil { return sys_error.New(fmt.Sprintf("未找到[mapId:%d id:%d]的应答器", req.MapId, req.BaliseId)) } return baliseTelegramSend(simulation, balise) } // BaliseReset 重置应答器所有状态 func BaliseReset(simulation *VerifySimulation) *sys_error.BusinessError { var errs []error for _, balise := range simulation.Repo.ResponderList() { err := baliseTelegramReset(simulation, balise) if err != nil { errs = append(errs, err) } err = balisePositionReset(simulation, balise) if err != nil { errs = append(errs, err) } err = baliseTelegramSend(simulation, balise) if err != nil { errs = append(errs, err) } } if len(errs) > 0 { var userMsg []string for _, err := range errs { be, ok := err.(*sys_error.BusinessError) if ok { userMsg = append(userMsg, be.UserMsg) } } return sys_error.New(strings.Join(userMsg, "\n")) } return nil } func baliseTelegramSend(simulation *VerifySimulation, balise *repository.Transponder) *sys_error.BusinessError { entry, _ := entity.GetEntityByUid(simulation.World, balise.Id()) return sendEcsRequest(simulation.World, func() error { component.BaliseWorkStateType.SetValue(entry, component.BaliseWorkState{Work: false}) return nil }) } func balisePositionReset(simulation *VerifySimulation, balise *repository.Transponder) *sys_error.BusinessError { entry, _ := entity.GetEntityByUid(simulation.World, balise.Id()) component.KmType.Set(entry, balise.Km()) component.LinkPositionType.SetValue(entry, component_data.LinkPosition{ LinkId: balise.LinkPosition().Link().Id(), Offset: balise.LinkPosition().Offset(), }) return nil } func baliseTelegramReset(simulation *VerifySimulation, balise *repository.Transponder) *sys_error.BusinessError { entry, _ := entity.GetEntityByUid(simulation.World, balise.Id()) return sendEcsRequest(simulation.World, func() error { component.BaliseFixedTelegramType.SetValue(entry, component.BaliseTelegram{ Telegram: balise.FixedTelegram(), UserTelegram: balise.FixedUserTelegram(), }) if entry.HasComponent(component.BaliseVariableTelegramType) { component.BaliseVariableTelegramType.SetValue(entry, component.BaliseTelegram{}) } return nil }) } func sendEcsRequest(w ecs.World, request func() error) *sys_error.BusinessError { result := <-ecs.Request(w, func() ecs.Result[ecs.EmptyType] { err := request() if err != nil { return ecs.NewErrResult(err) } return ecs.NewOkEmptyResult() }) if result.Err != nil { return sys_error.New("仿真世界请求执行失败", result.Err) } return nil }