新link数据构建;与动力学通信使用新link;增加新旧link转换关系
This commit is contained in:
parent
300232fda4
commit
00b396d41c
@ -1,6 +1,8 @@
|
||||
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"
|
||||
|
||||
@ -39,7 +41,7 @@ func init() {
|
||||
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.UpdateTrainState(simulation, convert(info, *sta.(*state.TrainState), memory.QueryMapVerifyStructure(simulation.MapId)))
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -54,15 +56,14 @@ func CreateSimulation(mapId int32) string {
|
||||
simulationId := createSimulationId(mapId)
|
||||
_, e := simulationMap.Load(simulationId)
|
||||
if !e {
|
||||
////通知动力学
|
||||
//httpCode, _, err := dynamics.SendSimulationStartReq()
|
||||
//if httpCode != http.StatusOK || err != nil {
|
||||
// panic(dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
|
||||
//}
|
||||
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)
|
||||
//道岔状态发送
|
||||
startSendTurnoutInfo(simulationId, verifySimulation)
|
||||
dynamicsRun(verifySimulation)
|
||||
}
|
||||
return simulationId
|
||||
}
|
||||
@ -70,7 +71,7 @@ func CreateSimulation(mapId int32) string {
|
||||
// 删除仿真对象
|
||||
func DestroySimulation(simulationId string) {
|
||||
//移除道岔状态发送
|
||||
dynamics.RemoveTurnoutInfoSource(simulationId)
|
||||
dynamics.Stop()
|
||||
//通知动力学
|
||||
httpCode, _, err := dynamics.SendSimulationEndReq()
|
||||
if httpCode != http.StatusOK || err != nil {
|
||||
@ -118,9 +119,30 @@ func GetSimulationArr() []*memory.VerifySimulation {
|
||||
return result
|
||||
}
|
||||
|
||||
func convert(info *dynamics.TrainInfo, sta state.TrainState) *state.TrainState {
|
||||
sta.HeadLinkId = strconv.Itoa(int(info.Link))
|
||||
sta.HeadLinkOffset = int64(info.LinkOffset * 10)
|
||||
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 linkRef *graphicData.RelatedRef
|
||||
if i == 0 {
|
||||
linkRef = model.SectionLinkMap[dp.Device.GetGraphicId()]
|
||||
} else {
|
||||
linkRef = model.SectionLinkMap[model.DevicePositions[i-1].Device.GetGraphicId()]
|
||||
}
|
||||
switch linkRef.DevicePort {
|
||||
case 0:
|
||||
sta.HeadLinkId = linkRef.GetId()
|
||||
sta.HeadLinkOffset = int64(info.LinkOffset - uint32(dp.Offset))
|
||||
case 1:
|
||||
sta.HeadLinkId = linkRef.GetId()
|
||||
sta.HeadLinkOffset = int64(uint32(model.DevicePositions[i+1].Offset) - 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
|
||||
@ -138,8 +160,8 @@ func convert(info *dynamics.TrainInfo, sta state.TrainState) *state.TrainState {
|
||||
return &sta
|
||||
}
|
||||
|
||||
func startSendTurnoutInfo(simulationId string, verifySimulation *memory.VerifySimulation) {
|
||||
dynamics.AddTurnoutInfoSource(simulationId, func() []*dynamics.TurnoutInfo {
|
||||
func dynamicsRun(verifySimulation *memory.VerifySimulation) {
|
||||
_ = dynamics.Run(func() []*dynamics.TurnoutInfo {
|
||||
stateSlice := memory.GetAllTurnoutState(verifySimulation)
|
||||
var turnoutInfoSlice []*dynamics.TurnoutInfo
|
||||
for _, sta := range stateSlice {
|
||||
@ -157,3 +179,32 @@ func startSendTurnoutInfo(simulationId string, verifySimulation *memory.VerifySi
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
package face
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//设备模型基类
|
||||
// 设备模型基类
|
||||
type DeviceModel struct {
|
||||
//图形id,即由前端作图时生成,且全局唯一
|
||||
GraphicId string
|
||||
@ -10,29 +13,55 @@ type DeviceModel struct {
|
||||
Index string
|
||||
}
|
||||
|
||||
//判断是否同一个设备
|
||||
// 判断是否同一个设备
|
||||
func (dm *DeviceModel) IsSame(other *DeviceModel) bool {
|
||||
return strings.EqualFold(dm.GraphicId, other.GraphicId)
|
||||
}
|
||||
|
||||
//模型图形id
|
||||
// 模型图形id
|
||||
func (dm *DeviceModel) GetGraphicId() string {
|
||||
return dm.GraphicId
|
||||
}
|
||||
|
||||
//模型索引
|
||||
// 模型索引
|
||||
func (dm *DeviceModel) GetIndex() string {
|
||||
return dm.Index
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
//设备端口枚举定义
|
||||
// 设备端口枚举定义
|
||||
type PortEnum int8
|
||||
|
||||
//设备端口枚举值
|
||||
func (pe PortEnum) Name() string {
|
||||
switch pe {
|
||||
case A:
|
||||
return "A"
|
||||
case B:
|
||||
return "B"
|
||||
case C:
|
||||
return "C"
|
||||
default:
|
||||
panic(fmt.Sprintf("未知的PortEnum:%d", pe))
|
||||
}
|
||||
}
|
||||
|
||||
// 设备端口枚举值
|
||||
const (
|
||||
A PortEnum = iota
|
||||
B
|
||||
C
|
||||
)
|
||||
|
||||
func GetPortEnum(i int8) PortEnum {
|
||||
switch i {
|
||||
case int8(A):
|
||||
return A
|
||||
case int8(B):
|
||||
return B
|
||||
case int8(C):
|
||||
return C
|
||||
default:
|
||||
panic(fmt.Sprintf("未知的PortEnum:%d", i))
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package memory
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
@ -36,6 +37,8 @@ type VerifyStructure struct {
|
||||
LogicalSectionModelMap map[string]face.LogicalSectionModeller
|
||||
//信号机模型集合,key为索引编号
|
||||
SignalDeviceModelMap map[string]face.SignalDeviceModeller
|
||||
//Link模型集合,key为索引编号
|
||||
LinkModelMap map[int32]face.DeviceModeller
|
||||
}
|
||||
|
||||
// 设备地图ID对应map结构体(建立关系时便于查找使用),注意:这里的key 为 Common.Id !!!
|
||||
@ -61,6 +64,7 @@ func PublishMapVerifyStructure(graphic *model.PublishedGi) *VerifyStructure {
|
||||
PhysicalSectionModelMap: make(map[string]face.PhysicalSectionModeller),
|
||||
LogicalSectionModelMap: make(map[string]face.LogicalSectionModeller),
|
||||
SignalDeviceModelMap: make(map[string]face.SignalDeviceModeller),
|
||||
LinkModelMap: make(map[int32]face.DeviceModeller),
|
||||
}
|
||||
// 地图数据转为map存储,建立关系时方便使用
|
||||
graphicInfoMap := &GraphicInfoMapStructure{
|
||||
@ -120,6 +124,77 @@ func initGraphicStructure(graphicData *graphicData.RtssGraphicStorage, verifyStr
|
||||
initGraphicSignal(graphicData.Signals, verifyStructure, graphicDataMap)
|
||||
// 初始化计算link数据
|
||||
initCalcLink(graphicData.CalculateLink, verifyStructure, graphicDataMap)
|
||||
// 初始化Link信息
|
||||
initLink(graphicData.CalculateLink, verifyStructure, graphicDataMap, graphicData)
|
||||
}
|
||||
|
||||
func initLink(links []*graphicData.CalculateLink, vs *VerifyStructure, dataMap *GraphicInfoMapStructure, data *graphicData.RtssGraphicStorage) {
|
||||
axleTurnoutIdMap := make(map[string]face.AxlePointDeviceModeller)
|
||||
for _, modeller := range vs.AxlePointDeviceModelMap {
|
||||
axleTurnoutIdMap[modeller.GetGraphicId()] = modeller
|
||||
}
|
||||
for _, modeller := range vs.SwitchDeviceModelMap {
|
||||
axleTurnoutIdMap[modeller.GetGraphicId()] = modeller
|
||||
}
|
||||
for _, link := range links {
|
||||
sectionLinkMap := make(map[string]*graphicData.RelatedRef)
|
||||
//构建DevicePosition(DP)切片(暂时仅计轴和道岔)
|
||||
var dps []*ref.DevicePosition
|
||||
for _, dp := range link.DevicePositions {
|
||||
modeller := axleTurnoutIdMap[dp.DeviceId]
|
||||
if modeller == nil {
|
||||
continue
|
||||
}
|
||||
dps = append(dps, &ref.DevicePosition{
|
||||
Device: modeller,
|
||||
Offset: dp.Offset,
|
||||
})
|
||||
}
|
||||
//对DP切片按Offset排序
|
||||
sort.Slice(dps, func(i, j int) bool {
|
||||
return dps[i].Offset < dps[j].Offset
|
||||
})
|
||||
//构建SectionLinkMap
|
||||
for i := 1; i < len(dps); i++ {
|
||||
a := dps[i-1]
|
||||
b := dps[i]
|
||||
aId := a.Device.GetGraphicId()
|
||||
bId := b.Device.GetGraphicId()
|
||||
for _, sl := range data.SectionLinks {
|
||||
if aId == sl.ASimRef.Id && bId == sl.BSimRef.Id {
|
||||
sectionLinkMap[aId] = &graphicData.RelatedRef{
|
||||
DeviceType: 0, //这个字段用不到,所以随便赋值
|
||||
Id: strconv.Itoa(int(sl.Index)), //因为发给前端的是索引,所以这里用索引
|
||||
DevicePort: 0,
|
||||
}
|
||||
} else if aId == sl.BSimRef.Id && bId == sl.ASimRef.Id {
|
||||
sectionLinkMap[aId] = &graphicData.RelatedRef{
|
||||
DeviceType: 0, //这个字段用不到,所以随便赋值
|
||||
Id: strconv.Itoa(int(sl.Index)), //因为发给前端的是索引,所以这里用索引
|
||||
DevicePort: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vs.LinkModelMap[link.Index] = &device.LinkModel{
|
||||
DeviceModel: face.DeviceModel{
|
||||
GraphicId: link.Common.Id,
|
||||
Index: strconv.Itoa(int(link.Index)),
|
||||
},
|
||||
Length: link.Length,
|
||||
ARelatedSwitchRef: ref.SwitchRef{
|
||||
SwitchDevice: axleTurnoutIdMap[link.ARelatedRef.Id],
|
||||
Port: face.GetPortEnum(int8(link.ARelatedRef.DevicePort)),
|
||||
},
|
||||
BRelatedSwitchRef: ref.SwitchRef{
|
||||
SwitchDevice: axleTurnoutIdMap[link.BRelatedRef.Id],
|
||||
Port: face.GetPortEnum(int8(link.BRelatedRef.DevicePort)),
|
||||
},
|
||||
DevicePositions: dps,
|
||||
SectionLinkMap: sectionLinkMap,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化计轴信息
|
||||
|
@ -2,6 +2,8 @@ package memory
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/model/device"
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@ -25,14 +27,39 @@ func AddTrainState(simulation *VerifySimulation, status *state.TrainState) {
|
||||
status.Show = true
|
||||
//向动力学发送初始化请求
|
||||
trainIndex, _ := strconv.ParseUint(status.Id, 10, 16)
|
||||
linkIndex, _ := strconv.ParseUint(status.HeadLinkId, 10, 16)
|
||||
var linkIndex uint64
|
||||
var linkOffset uint32
|
||||
vs := QueryMapVerifyStructure(simulation.MapId)
|
||||
Outer:
|
||||
for _, modeller := range vs.LinkModelMap {
|
||||
link := modeller.(*device.LinkModel)
|
||||
for dId, sl := range link.SectionLinkMap {
|
||||
if sl.Id != status.HeadLinkId {
|
||||
continue
|
||||
}
|
||||
linkIndex, _ = strconv.ParseUint(link.Index, 10, 16)
|
||||
for i, dp := range link.DevicePositions {
|
||||
if dp.Device.GetGraphicId() == dId {
|
||||
switch sl.DevicePort {
|
||||
case 0:
|
||||
linkOffset = uint32(dp.Offset) + uint32(status.HeadLinkOffset)
|
||||
case 1:
|
||||
linkOffset = uint32(link.DevicePositions[i+1].Offset) - uint32(status.HeadLinkOffset)
|
||||
}
|
||||
break Outer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
httpCode, _, err := dynamics.SendInitTrainReq(&dynamics.InitTrainInfo{
|
||||
TrainIndex: uint16(trainIndex),
|
||||
LinkIndex: uint16(linkIndex),
|
||||
LinkOffset: uint16(status.HeadLinkOffset / 10),
|
||||
LinkOffset: linkOffset,
|
||||
Speed: uint16(math.Round(float64(status.Speed * 10))),
|
||||
Up: status.Up,
|
||||
})
|
||||
zap.S().Debugf("添加列车:[%d-%s-%d]", trainIndex, status.HeadLinkId, status.HeadLinkOffset)
|
||||
zap.S().Debugf("列车初始化:[%d-%d-%d]", trainIndex, linkIndex, linkOffset)
|
||||
if err != nil || httpCode != http.StatusOK {
|
||||
panic(dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package device
|
||||
|
||||
import (
|
||||
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
|
||||
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/face"
|
||||
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/model/ref"
|
||||
)
|
||||
|
||||
type LinkModel struct {
|
||||
face.DeviceModel
|
||||
//长度
|
||||
Length int32
|
||||
//A端连接的道岔端点
|
||||
ARelatedSwitchRef ref.SwitchRef
|
||||
//B端连接的道岔端点
|
||||
BRelatedSwitchRef ref.SwitchRef
|
||||
//Link上的设备及位置(将A、B端的道岔也填进来了)(按offset排序)
|
||||
DevicePositions []*ref.DevicePosition
|
||||
//key-在link上最小偏移量端点设备id,value-SectionLink端点
|
||||
SectionLinkMap map[string]*graphicData.RelatedRef
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package ref
|
||||
|
||||
import "joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/face"
|
||||
|
||||
type DevicePosition struct {
|
||||
Device face.DeviceModeller
|
||||
Offset int32
|
||||
}
|
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"joylink.club/bj-rtsts-server/config"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func SendInitTrainReq(info *InitTrainInfo) (int, *[]byte, error) {
|
||||
@ -13,7 +14,10 @@ func SendInitTrainReq(info *InitTrainInfo) (int, *[]byte, error) {
|
||||
uri := "/api/aerodynamics/init/train/"
|
||||
url := baseUrl + uri
|
||||
data, _ := json.Marshal(info)
|
||||
resp, err := http.Post(url, "application/json", bytes.NewBuffer(data))
|
||||
client := http.Client{
|
||||
Timeout: time.Second * 5,
|
||||
}
|
||||
resp, err := client.Post(url, "application/json", bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
s := err.Error()
|
||||
println(s)
|
||||
|
@ -3,7 +3,7 @@ package dynamics
|
||||
type InitTrainInfo struct {
|
||||
TrainIndex uint16 `json:"trainIndex"`
|
||||
LinkIndex uint16 `json:"linkIndex"`
|
||||
LinkOffset uint16 `json:"linkOffset"`
|
||||
LinkOffset uint32 `json:"linkOffset"`
|
||||
//单位0.1km/h
|
||||
Speed uint16 `json:"speed"`
|
||||
Up bool `json:"up"`
|
||||
@ -11,9 +11,9 @@ type InitTrainInfo struct {
|
||||
|
||||
// LineBaseInfo 线路基础信息,提供给动力学作为计算依据
|
||||
type LineBaseInfo struct {
|
||||
LinkList []Link `json:"linkList"`
|
||||
SlopeList []Slope `json:"slopeList"`
|
||||
CurveList []Curve `json:"curveList"`
|
||||
LinkList []*Link `json:"linkList"`
|
||||
SlopeList []*Slope `json:"slopeList"`
|
||||
CurveList []*Curve `json:"curveList"`
|
||||
}
|
||||
|
||||
type Link struct {
|
||||
|
122
dynamics/udp.go
122
dynamics/udp.go
@ -3,6 +3,7 @@ package dynamics
|
||||
import (
|
||||
"container/list"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/panjf2000/gnet/v2"
|
||||
"go.uber.org/zap"
|
||||
@ -13,44 +14,84 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
runSendTurnoutStateTask()
|
||||
}
|
||||
|
||||
var (
|
||||
m sync.Map
|
||||
)
|
||||
|
||||
type TurnoutInfoFunc func() []*TurnoutInfo
|
||||
|
||||
func runSendTurnoutStateTask() {
|
||||
var (
|
||||
running bool
|
||||
mutex sync.Mutex
|
||||
turnoutInfoFunc TurnoutInfoFunc
|
||||
//道岔消息生命信号
|
||||
turnoutLifeSignal uint16
|
||||
//列车消息生命信号
|
||||
trainLifeSignal uint16
|
||||
//列车生命信号是否初始化
|
||||
trainLifeSignalInit bool
|
||||
//用于处理生命信号循环使用产生的各种特殊处理
|
||||
limit uint16 = 10000
|
||||
)
|
||||
|
||||
func Run(tiFunc TurnoutInfoFunc) error {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
trainLifeSignalInit = false
|
||||
return runSendTurnoutStateTask(tiFunc)
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
turnoutInfoFunc = nil
|
||||
}
|
||||
|
||||
func runSendTurnoutStateTask(tiFunc TurnoutInfoFunc) error {
|
||||
if running {
|
||||
return nil
|
||||
}
|
||||
if tiFunc == nil {
|
||||
return errors.New("tiFunc不能为空")
|
||||
}
|
||||
turnoutInfoFunc = tiFunc
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("Recovered from panic:", r)
|
||||
}
|
||||
}()
|
||||
tick := time.Tick(50 * time.Millisecond)
|
||||
for range tick {
|
||||
m.Range(func(key, value any) bool {
|
||||
slice := value.(TurnoutInfoFunc)()
|
||||
for _, turnoutInfo := range slice {
|
||||
err := SendTurnoutInfo(turnoutInfo)
|
||||
if err != nil {
|
||||
zap.S().Error(err)
|
||||
}
|
||||
if turnoutInfoFunc == nil {
|
||||
continue
|
||||
}
|
||||
slice := turnoutInfoFunc()
|
||||
for _, turnoutInfo := range slice {
|
||||
turnoutInfo.lifeSignal = turnoutLifeSignal
|
||||
err := sendTurnoutInfo(turnoutInfo)
|
||||
if err != nil {
|
||||
zap.S().Error(err)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
turnoutLifeSignal++
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func AddTurnoutInfoSource(simId string, tiFunc TurnoutInfoFunc) {
|
||||
m.Store(simId, tiFunc)
|
||||
var handlerList list.List
|
||||
|
||||
type TrainInfoHandler func(info *TrainInfo)
|
||||
|
||||
func RegisterTrainInfoHandler(handler TrainInfoHandler) {
|
||||
handlerList.PushBack(handler)
|
||||
}
|
||||
|
||||
func RemoveTurnoutInfoSource(simId string) {
|
||||
m.Delete(simId)
|
||||
func RunUdpServer() {
|
||||
server := &udpServer{addr: fmt.Sprintf("udp://:%d", config.Config.Dynamics.UdpLocalPort), multicore: false}
|
||||
err := gnet.Run(server, server.addr, gnet.WithMulticore(server.multicore))
|
||||
zap.L().Fatal("udp服务启动失败", zap.Error(err))
|
||||
}
|
||||
|
||||
// SendTurnoutInfo 发送道岔信息
|
||||
func SendTurnoutInfo(info *TurnoutInfo) error {
|
||||
// sendTurnoutInfo 发送道岔信息
|
||||
func sendTurnoutInfo(info *TurnoutInfo) error {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
zap.S().Error("发送道岔信息失败", r)
|
||||
@ -70,6 +111,7 @@ func SendTurnoutInfo(info *TurnoutInfo) error {
|
||||
}
|
||||
}(conn)
|
||||
var data []byte
|
||||
data = binary.BigEndian.AppendUint16(data, info.lifeSignal)
|
||||
data = binary.BigEndian.AppendUint16(data, info.Code)
|
||||
var b byte
|
||||
if info.NPosition {
|
||||
@ -105,12 +147,28 @@ func (server *udpServer) OnBoot(eng gnet.Engine) gnet.Action {
|
||||
func (server *udpServer) OnTraffic(c gnet.Conn) gnet.Action {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
zap.S().Error("udp服务数据解析异常", r)
|
||||
zap.L().Error("udp服务数据解析异常", zap.Any("panic", r))
|
||||
}
|
||||
}()
|
||||
buf, _ := c.Next(-1)
|
||||
trainInfo := TrainInfo{}
|
||||
trainInfo.LifeSignal = binary.BigEndian.Uint16(buf[0:2])
|
||||
if !trainLifeSignalInit {
|
||||
trainLifeSignalInit = true
|
||||
trainLifeSignal = trainInfo.LifeSignal
|
||||
} else if trainLifeSignal < limit {
|
||||
if trainInfo.LifeSignal < trainLifeSignal || trainInfo.LifeSignal > trainLifeSignal-limit {
|
||||
return gnet.None
|
||||
}
|
||||
} else if trainLifeSignal < math.MaxUint16-10000 {
|
||||
if trainInfo.LifeSignal < trainLifeSignal {
|
||||
return gnet.None
|
||||
}
|
||||
} else {
|
||||
if trainInfo.LifeSignal < trainLifeSignal && trainInfo.LifeSignal > trainLifeSignal+10000 {
|
||||
return gnet.None
|
||||
}
|
||||
}
|
||||
trainInfo.Number = buf[2]
|
||||
trainInfo.Len = binary.BigEndian.Uint16(buf[3:5])
|
||||
trainInfo.Link = buf[5]
|
||||
@ -138,17 +196,3 @@ func (server *udpServer) OnTraffic(c gnet.Conn) gnet.Action {
|
||||
|
||||
return gnet.None
|
||||
}
|
||||
|
||||
var handlerList list.List
|
||||
|
||||
type TrainInfoHandler func(info *TrainInfo)
|
||||
|
||||
func RegisterTrainInfoHandler(handler TrainInfoHandler) {
|
||||
handlerList.PushBack(handler)
|
||||
}
|
||||
|
||||
func RunUdpServer() {
|
||||
server := &udpServer{addr: fmt.Sprintf("udp://:%d", config.Config.Dynamics.UdpLocalPort), multicore: false}
|
||||
err := gnet.Run(server, server.addr, gnet.WithMulticore(server.multicore))
|
||||
zap.L().Fatal("udp服务启动失败", zap.Error(err))
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package dynamics
|
||||
|
||||
type TurnoutInfo struct {
|
||||
Code uint16
|
||||
NPosition bool
|
||||
RPosition bool
|
||||
lifeSignal uint16
|
||||
Code uint16
|
||||
NPosition bool
|
||||
RPosition bool
|
||||
}
|
||||
|
||||
type TrainInfo struct {
|
||||
@ -21,7 +22,7 @@ type TrainInfo struct {
|
||||
Slope uint16
|
||||
//列车所在位置坡度走势(上/下坡)
|
||||
UpSlope bool
|
||||
//列车当前运行方向(上/下行)
|
||||
//列车当前运行方向(偏移量增大/减小方向)
|
||||
Up bool
|
||||
//实际运行阻力(总)(N)
|
||||
TotalResistance uint32
|
||||
|
@ -29,7 +29,7 @@ func TestSendTurnoutInfo(t *testing.T) {
|
||||
tick := time.Tick(50 * time.Millisecond)
|
||||
for range tick {
|
||||
for i := 1; i <= 9; i++ {
|
||||
SendTurnoutInfo(&TurnoutInfo{
|
||||
sendTurnoutInfo(&TurnoutInfo{
|
||||
Code: uint16(i),
|
||||
NPosition: true,
|
||||
RPosition: false,
|
||||
|
Loading…
Reference in New Issue
Block a user