rts-sim-testing-service/ts/simulation/wayside/memory/wayside_memory_transponder.go
thesai f1efd5a2f2 [补充]12号线联锁通信应答器数据解析;
[修改]联锁配置中的车站编号不再改为车站uid
2024-08-08 13:23:25 +08:00

277 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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{}, []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
}