rts-sim-testing-service/third_party/axle_device/rssp_channel.go
walker 62b44a0cc6 添加UDP网络延时记录器
动力学和半实物接口添加UDP网络监控功能
2024-01-22 13:10:10 +08:00

316 lines
9.2 KiB
Go
Raw Permalink 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 axle_device
import (
"fmt"
"log/slog"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp"
)
// 铁路信号安全通信协议实现
// HandleUserData 回调应用层
type HandleUserData func([]byte)
// RsspChannel 实现rssp通信
type RsspChannel struct {
//udp
udpServer udp.UdpServer
//udp
udpClient udp.UdpClient
//回调应用层
handleUserData HandleUserData
//rssp安全通信配置
config *config.RsspConfig
//rssp时钟
rsspTimer *RsspTimer
//批次编号,发送序列号
sn *message.RsspSn
//安全通道1时间戳
ch1Ts *message.RsspLFSR
//安全通道2时间戳
ch2Ts *message.RsspLFSR
//最近一次接收到的报文的安全通道1时间戳
rcvCh1Ts uint32
//最近一次接收到的报文的安全通道2时间戳
rcvCh2Ts uint32
//最近一次接收到的报文的序列号
rcvSn uint32
//时序校验请求发送记录
sendSseRecord *SseFireRecord
}
func (s *RsspChannel) SetRcvUserDataCallback(handleUserData HandleUserData) {
s.handleUserData = handleUserData
}
func (s *RsspChannel) Init(config *config.RsspConfig) *RsspChannel {
s.config = config
s.rsspTimer = &RsspTimer{t: 0}
s.sn = message.NewRsspSn(1)
s.ch1Ts = message.NewRsspLFSR(message.RSSP_I_C1_TS, 32, s.config.SID1, false)
s.ch2Ts = message.NewRsspLFSR(message.RSSP_I_C2_TS, 32, s.config.SID2, false)
return s
}
// Start 启动安全通道
func (s *RsspChannel) Start() {
//
s.udpServer = udp.NewServer(fmt.Sprintf(":%d", s.config.LocalUdpPort), s.handleRsspMsg)
s.udpServer.Listen()
//
s.udpClient = udp.NewClient(fmt.Sprintf("%s:%d", s.config.RemoteIp, s.config.RemoteUdpPort))
}
// Stop 关闭安全通道
func (s *RsspChannel) Stop() {
if s.udpServer != nil {
s.udpServer.Close()
}
if s.udpClient != nil {
s.udpClient.Close()
}
}
// RsspTimer rssp时钟每一个tick周期为config.SendingPeriod
type RsspTimer struct {
t uint64
}
func (s *RsspTimer) tick() {
s.t++
}
func (s *RsspTimer) now() uint64 {
return s.t
}
// SseFireRecord 发送时序校验请求的记录
type SseFireRecord struct {
send *message.RsspSse //已经发送的时序校验请求
rsspTime uint64 //发送时序校验请求时的rssp时间
}
func (s *SseFireRecord) record(send *message.RsspSse, rsspTime uint64) {
s.send = send
s.rsspTime = rsspTime
}
func (s *SseFireRecord) clear() {
s.send = nil
s.rsspTime = 0
}
func (s *SseFireRecord) hasRecord() bool {
return s.send != nil
}
// 处理接收到的rssp报文
// 注意本函数由udp socket 协程执行
func (s *RsspChannel) handleRsspMsg(pack []byte) {
slog.Debug("接收到RSSP报文", "len", len(pack))
//报文头校验
head := &message.RsspHead{}
if !head.Parse(pack) { //解析报文头失败
slog.Debug("丢弃接收的RSSP报文解析报文头失败")
return
}
if !message.RsspHeadMcCheck(head) { //报文类别检测未通过
slog.Debug("丢弃接收的RSSP报文报文类别检测未通过")
return
}
if !message.RsspHeadPicCheck(head) { //协议交互类别检测未通过
slog.Debug("丢弃接收的RSSP报文协议交互类别检测未通过")
return
}
if !s.config.CheckAddress(head.Sa, head.Da) { //校验报文头中源地址和目的地址是否包含在已配置列表中
slog.Debug("丢弃接收的RSSP报文报文头中源地址或目的地址不在在已配置列表中")
return
}
//报文尾校验
if !message.RsspPackCrc16Check(pack) { //整个报文crc16校验未通过
slog.Debug("丢弃接收的RSSP报文报文尾CRC16校验未通过")
return
}
//解析得到RSD、SSE或SRE
rssp := message.ParseRsspPack(head, pack)
if rssp == nil { //解析具体rssp包失败
slog.Debug("丢弃接收的RSSP报文解析具体类别包失败")
return
}
//处理接收到的具体类别RSSP包
switch rssp.Type() {
case message.RSD_A:
fallthrough
case message.RSD_B:
s.handleRsspRsd(rssp.(*message.RsspRsd))
case message.SSE:
s.handleRsspSse(rssp.(*message.RsspSse))
case message.SSR:
s.handleRsspSsr(rssp.(*message.RsspSsr))
}
}
// 处理接收到的实时安全数据 RSD
func (s *RsspChannel) handleRsspRsd(rsd *message.RsspRsd) {
//slog.Debug("接收到的实时安全数据 RSD")
//如果为备机发送来的安全数据
if s.config.PicType == message.PIC_SLAVE { //备安全通道
slog.Debug("丢弃接收的RSSP-RSD报文舍弃在备安全通道中接收到的安全数据")
//备安全通道收到安全数据,表示该物理通道连接正常
return
}
//如果为主机发送来的安全数据
if s.config.PicType == message.PIC_MASTER { //主安全通道
if !rsd.IsMaster() {
slog.Debug("丢弃接收的RSSP-RSD报文舍弃在主安全通道中收到的非主机发送来的安全数据")
return
}
}
//序列号校验
//接收的序列号小于最近一次有效序列号则触发SSE时序校验
if rsd.Sn < s.rcvSn {
slog.Debug("丢弃接收的RSSP-RSD报文当前接收RSD的序列号小于最近一次接收的RSD的序列号触发SSE")
s.fireSse(rsd)
return
}
dSn := rsd.Sn - s.rcvSn
if dSn > s.config.Mtv {
slog.Debug("丢弃接收的RSSP-RSD报文当前接收RSD的序列号与最近一次接收的RSD的序列号差值过大触发SSE")
s.fireSse(rsd)
return
}
//SVC校验
c1Crc32 := message.Rssp_I_Crc32C1(rsd.Sad)
c1SidTs := c1Crc32 ^ rsd.Svc1 ^ message.RSSP_I_C1_SCW //T(n)
//
c2Crc32 := message.Rssp_I_Crc32C2(rsd.Sad)
c2SidTs := c2Crc32 ^ rsd.Svc2 ^ message.RSSP_I_C2_SCW //T(n)
//todo ... SVC校验待完善
_ = c1SidTs
_ = c2SidTs
//校验通过
//记录本次接收RSD的序列号和安全校验通道时间戳
s.rcvSn = rsd.Sn
s.rcvCh1Ts = c1SidTs ^ s.config.SID1
s.rcvCh2Ts = c2SidTs ^ s.config.SID2
//通知应用层接收应用数据
s.handleUserData(rsd.Sad)
}
// 触发时序校正请求
func (s *RsspChannel) fireSse(rsd *message.RsspRsd) {
s.sendSseRecord = &SseFireRecord{send: s.sendSse(), rsspTime: s.rsspTimer.now()}
}
// 接收到时序校正请求
func (s *RsspChannel) handleRsspSse(sse *message.RsspSse) {
if s.config.PicType != message.PIC_MASTER {
slog.Debug("丢弃接收的RSSP-SSE报文在非主安全通道中收到时序校正请求SSE")
return
}
//发送时序校正响应
s.sendSsr(sse)
}
// 接收到时序校正应答
func (s *RsspChannel) handleRsspSsr(ssr *message.RsspSsr) {
//SSR校验
if !s.sendSseRecord.hasRecord() {
slog.Debug("丢弃接收的RSSP-SSR报文未发起过SSE时序校正请求")
return
}
if s.rsspTimer.t-s.sendSseRecord.rsspTime > uint64(s.config.SsrRsspTimeout) {
slog.Debug("丢弃接收的RSSP-SSR报文等待SSE响应超时")
return
}
if ssr.SeSn != s.sendSseRecord.send.Sn {
slog.Debug("丢弃接收的RSSP-SSR报文SSR与SSE不对应")
return
}
//恢复时序?
s.rcvSn = ssr.SrSn
s.rcvCh1Ts = ssr.Tic1 ^ s.sendSseRecord.send.SeqEnq1 ^ s.config.SID1 ^ s.config.DataVer1
s.rcvCh2Ts = ssr.Tic2 ^ s.sendSseRecord.send.SeqEnq2 ^ s.config.SID2 ^ s.config.DataVer2
}
// NextPeriod 刷新与周期有关的:将序列号和时间戳更新到下一个值
func (s *RsspChannel) NextPeriod() {
s.sn.GetAndAdd()
s.ch1Ts.GetAndMove()
s.ch2Ts.GetAndMove()
s.rsspTimer.tick()
}
// 发送时序校正应答
func (s *RsspChannel) sendSsr(sse *message.RsspSse) {
ssr := &message.RsspSsr{}
//
ssr.Pic = message.PIC_MASTER
ssr.Mc = message.SSR
ssr.Sa = s.config.SrcAddr
ssr.Da = s.config.DstAddr
ssr.SrSn = s.sn.Get() //当前序列号
ssr.SeSn = sse.Sn
ssr.Tic1 = sse.SeqEnq1 ^ s.config.SID1 ^ s.ch1Ts.Get() ^ s.config.DataVer1
ssr.Tic2 = sse.SeqEnq2 ^ s.config.SID2 ^ s.ch2Ts.Get() ^ s.config.DataVer2
ssr.Dvn = 0x01 //预留固定值
//
rsspPack := ssr.Encode()
s.sendPack(rsspPack)
}
// 发送时序校正请求
func (s *RsspChannel) sendSse() *message.RsspSse {
sse := &message.RsspSse{}
//
sse.Pic = message.PIC_MASTER
sse.Mc = message.SSE
sse.Sa = s.config.SrcAddr
sse.Da = s.config.DstAddr
//时序校正请求,把最近一次接收到的报文中的序列号时间戳发送给发送方
sse.Sn = s.rcvSn
sse.SeqEnq1 = s.createSeqNeq(s.config.SID1, s.rcvCh1Ts)
sse.SeqEnq2 = s.createSeqNeq(s.config.SID2, s.rcvCh2Ts)
//
rsspPack := sse.Encode()
s.sendPack(rsspPack)
//
return sse
}
// SendUserData 发送用户数据即通过rssp安全通道发送应用层数据通过rssp的RSD报文发送
func (s *RsspChannel) SendUserData(userData []byte) {
rsd := &message.RsspRsd{}
rsd.Pic = s.config.PicType
if s.config.DeviceA {
rsd.Mc = message.RSD_A
} else {
rsd.Mc = message.RSD_B
}
rsd.Sa = s.config.SrcAddr
rsd.Da = s.config.DstAddr
//
rsd.Sn = s.sn.Get()
rsd.Sdl = uint16(len(userData) + 8)
//安全校验通道SVC_1
crc_c1 := message.Rssp_I_Crc32C1(userData)
rsd.Svc1 = s.createSvcCode(crc_c1, s.config.SID1, s.ch1Ts.Get(), message.RSSP_I_C1_SCW)
//安全校验通道SVC_2
crc_c2 := message.Rssp_I_Crc32C2(userData)
rsd.Svc1 = s.createSvcCode(crc_c2, s.config.SID2, s.ch2Ts.Get(), message.RSSP_I_C2_SCW)
rsd.Sad = userData
//
rsspPack := rsd.Encode()
s.sendPack(rsspPack)
}
func (s *RsspChannel) createSvcCode(crc32 uint32, sid uint32, ts uint32, scw uint32) uint32 {
return crc32 ^ sid ^ ts ^ scw
}
func (s *RsspChannel) createSeqNeq(sid uint32, ts uint32) uint32 {
return sid ^ ts
}
// 通过网络发送数据
func (s *RsspChannel) sendPack(rsspPack []byte) {
s.udpClient.Send(rsspPack)
}