rts-sim-testing-service/vobc/udp.go

182 lines
5.0 KiB
Go

package vobc
import (
"container/list"
"encoding/binary"
"fmt"
"log/slog"
"math"
"net"
"sync"
"github.com/panjf2000/gnet/v2"
"go.uber.org/zap"
"joylink.club/bj-rtsts-server/config"
)
var (
running bool
mutex sync.Mutex
receiveTrainLifeSignal uint16 //接收列车消息生命信号
sendTrainLifeSignal uint16 //发送的列车消息生命信号
trainLifeSignalInit bool //列车生命信号是否初始化
limit uint16 = 10000 //用于处理生命信号循环使用产生的各种特殊处理
vobcMsgInfoChan chan []byte = make(chan []byte) //列车消息队列
//处理方法列表
handlerList list.List
)
func init() {
go func() {
for {
info := <-vobcMsgInfoChan
for e := handlerList.Front(); e != nil; e = e.Next() {
func() {
defer func() {
r := recover()
if r != nil {
slog.Error("列车信息处理函数报错")
}
}()
handler := e.Value.(VobcDataHandler)
handler(info)
}()
}
}
}()
}
type VobcDataHandler func([]byte)
type udpServer struct {
gnet.BuiltinEventEngine
eng gnet.Engine
addr string
multicore bool
}
// udp 启动时运行
func (server *udpServer) OnBoot(eng gnet.Engine) gnet.Action {
server.eng = eng
slog.Info("vobc udp server 启动", "multicore", server.multicore, "addr", server.addr)
return gnet.None
}
// OnTraffic 接收到数据后的解析
func (server *udpServer) OnTraffic(c gnet.Conn) gnet.Action {
defer func() {
if r := recover(); r != nil {
zap.L().Error("vobc udp服务数据解析异常", zap.Any("panic", r))
}
}()
buf, _ := c.Next(-1)
lifeSignal := binary.BigEndian.Uint16(buf[0:2])
if !trainLifeSignalInit {
trainLifeSignalInit = true
} else if receiveTrainLifeSignal < limit {
if lifeSignal < receiveTrainLifeSignal || lifeSignal > receiveTrainLifeSignal-limit {
slog.Debug("丢弃列车信息", "lifeSignal", lifeSignal, "trainLifeSignal", receiveTrainLifeSignal)
return gnet.None
}
} else if receiveTrainLifeSignal < math.MaxUint16-10000 {
if lifeSignal < receiveTrainLifeSignal {
slog.Debug("丢弃列车信息", "lifeSignal", lifeSignal, "trainLifeSignal", receiveTrainLifeSignal)
return gnet.None
}
} else {
if lifeSignal < receiveTrainLifeSignal && lifeSignal > receiveTrainLifeSignal+10000 {
slog.Debug("丢弃列车信息", "lifeSignal", lifeSignal, "trainLifeSignal", receiveTrainLifeSignal)
return gnet.None
}
}
receiveTrainLifeSignal = lifeSignal
// trainInfo := decoderVobcTrainInfo(buf)
//消息队列
vobcMsgInfoChan <- buf
return gnet.None
}
// 注册处理vobc处理方法
func RegisterTrainInfoHandler(handler VobcDataHandler) {
handlerList.PushBack(handler)
}
// 创建UDP服务
func RunUdpServer() {
if !config.Config.Vobc.Open {
return
}
server := &udpServer{addr: fmt.Sprintf("udp://:%d", config.Config.Vobc.LocalPort), multicore: false}
err := gnet.Run(server, server.addr, gnet.WithMulticore(server.multicore))
zap.L().Fatal("vobc udp服务启动失败", zap.Error(err))
}
// 发送列车速度到VOBC
func SendTrainSpeedTask(trainInfo *SendTrainInfo) error {
if running {
return nil
}
mutex.Lock()
defer mutex.Unlock()
trainInfo.LifeSignal = sendTrainLifeSignal
err := sendVobcMsg(encoderVobcTrainInfo(trainInfo))
if err != nil {
slog.Error("发送Vobc信息失败", err)
}
sendTrainLifeSignal++
return err
}
// UDP停止
func Stop() {
mutex.Lock()
defer mutex.Unlock()
running = false
}
// Vobc 消息发送消息
func sendVobcMsg(buf []byte) error {
defer func() {
if r := recover(); r != nil {
slog.Error("发送列车速度信息失败", r)
}
}()
addr := fmt.Sprintf("%v:%v", config.Config.Vobc.Ip, config.Config.Vobc.RemotePort)
remoteAddr, _ := net.ResolveUDPAddr("udp", addr)
conn, err := net.DialUDP("udp", nil, remoteAddr)
if err != nil {
slog.Error("UDP通信失败", err)
return err
}
defer func(conn *net.UDPConn) {
err := conn.Close()
if err != nil {
slog.Error("Vobc UDP连接关闭失败", err)
}
}(conn)
_, err = conn.Write(buf)
return err
}
// 将道岔转为动力学的消息
func encoderVobcTrainInfo(info *SendTrainInfo) []byte {
var data []byte
data = binary.BigEndian.AppendUint16(data, info.LifeSignal)
data = binary.BigEndian.AppendUint16(data, info.Speed)
if info.Upslope {
data = append(data, 1<<7)
} else {
data = append(data, 0)
}
// 中间预留一位
data = append(data, 0)
data = binary.BigEndian.AppendUint16(data, info.Acceleration) // 加速度 100 = 1 m/s*s
data = binary.BigEndian.AppendUint16(data, info.TotalResistance) // 实际运行阻力 100 = 1KN
data = binary.BigEndian.AppendUint16(data, info.AirResistance) // 空气阻力 100 = 1KN
data = binary.BigEndian.AppendUint16(data, info.SlopeResistance) // 坡道阻力 100 = 1KN
data = binary.BigEndian.AppendUint16(data, info.CurveResistance) // 曲线阻力 100 = 1KN
data = binary.BigEndian.AppendUint16(data, info.Slope) // 坡度值 1= 1‰
return data
}