277 lines
10 KiB
Go
277 lines
10 KiB
Go
package memory
|
||
|
||
import (
|
||
"encoding/hex"
|
||
"fmt"
|
||
"joylink.club/bj-rtsts-server/const/balise_const"
|
||
"joylink.club/ecs"
|
||
"joylink.club/rtsssimulation/fi"
|
||
"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的两端公里标转为请求参数中公里标的坐标系
|
||
linkPosition := transponder.LinkPosition()
|
||
link := 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))
|
||
}
|
||
if len(req.FixedTelegram) != balise_const.TelegramHexLen {
|
||
return sys_error.New(fmt.Sprintf("固定报文长度必须为[%d]", balise_const.TelegramHexLen))
|
||
}
|
||
if len(req.FixedUserTelegram) != balise_const.UserTelegramHexLen {
|
||
return sys_error.New(fmt.Sprintf("固定用户报文长度必须为[%d]", balise_const.UserTelegramHexLen))
|
||
}
|
||
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)
|
||
}
|
||
|
||
// AllBaliseTelegramReset 重置应答器所有状态
|
||
func AllBaliseTelegramReset(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: true})
|
||
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())
|
||
linkPosition := balise.LinkPosition()
|
||
component.LinkPositionType.SetValue(entry, component_data.LinkPosition{
|
||
LinkId: linkPosition.Link().Id(),
|
||
Offset: linkPosition.Offset(),
|
||
})
|
||
return nil
|
||
}
|
||
|
||
func baliseTelegramReset(simulation *VerifySimulation, balise *repository.Transponder) *sys_error.BusinessError {
|
||
err := fi.BaliseUpdateFixedTelegram(simulation.World, balise.Id(), balise.FixedTelegram(), balise.FixedUserTelegram())
|
||
if err != nil {
|
||
return sys_error.New("重置应答器报文失败", err)
|
||
}
|
||
err = fi.BaliseCancelForceVariableTelegram(simulation.World, balise.Id())
|
||
if err != nil {
|
||
return sys_error.New("重置应答器报文失败", err)
|
||
}
|
||
err = fi.BaliseUpdateVariableTelegram(simulation.World, balise.Id(), []byte{}, false)
|
||
if err != nil {
|
||
return sys_error.New("重置应答器报文失败", err)
|
||
}
|
||
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
|
||
}
|