[新增]11号线驾驶台与工装通信服务
This commit is contained in:
parent
cc71c128cf
commit
64a5989b71
|
@ -15,6 +15,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// AccVobc 加速度计通信服务接口
|
||||
type AccVobc interface {
|
||||
Start(accManager AccVobcManager)
|
||||
Stop()
|
||||
|
|
|
@ -18,7 +18,7 @@ const (
|
|||
PointB
|
||||
)
|
||||
|
||||
// 电机转速UDP
|
||||
// ElectricMachinery 速传通信服务接口
|
||||
type ElectricMachinery interface {
|
||||
Start(manager ElectricMachineryMessageManager) // 启动电机转速UDP消息处理
|
||||
Stop() // 停止电机转速消息处理
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
package beijing11
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/snksoft/crc"
|
||||
)
|
||||
|
||||
// HC初始化命令帧
|
||||
type hcInitFrame struct {
|
||||
timestamp hcTimestampPackage
|
||||
modeInfo modeInfoPackage
|
||||
timeSyncInfo timeSyncInfoPackage
|
||||
reqScSelfCheckInfo reqScSelfCheckInfoPackage
|
||||
}
|
||||
|
||||
func (h *hcInitFrame) encode() []byte {
|
||||
data := make([]byte, 0, 21)
|
||||
data = append(data, FrameHead)
|
||||
data = append(data, 0, 0) //帧长度占位
|
||||
data = append(data, h.timestamp.encode()...)
|
||||
data = append(data, h.modeInfo.encode()...)
|
||||
data = append(data, h.timeSyncInfo.encode()...)
|
||||
data = append(data, h.reqScSelfCheckInfo.encode()...)
|
||||
data = escape(data)
|
||||
binary.BigEndian.PutUint16(data[1:], uint16(len(data)-3)) //填充帧长度
|
||||
data = binary.BigEndian.AppendUint32(data, crc32(data))
|
||||
data = append(data, FrameTail)
|
||||
return data
|
||||
}
|
||||
|
||||
// SC初始化确认帧
|
||||
type scInitFrame struct {
|
||||
timestamp scTimestampPackage
|
||||
modeConfirm scModeConfirmPackage
|
||||
timeSyncConfirm scTimeSyncConfirmPackage
|
||||
scSelfCheckConfirm scSelfCheckConfirmPackage
|
||||
}
|
||||
|
||||
func (s *scInitFrame) decode(frame []byte) error {
|
||||
if frame[0] != FrameHead {
|
||||
return errors.New(fmt.Sprintf("SC初始化确认帧解析失败,帧头不对:%x", frame[0]))
|
||||
}
|
||||
if uint16(len(frame)-8) != binary.BigEndian.Uint16(frame[1:3]) {
|
||||
return errors.New(fmt.Sprintf("SC初始化确认帧解析失败,数据长度不对:期望[%x] 实际[%x]", binary.BigEndian.Uint16(frame[1:3]), len(frame)))
|
||||
}
|
||||
if binary.BigEndian.Uint32(frame[len(frame)-5:len(frame)-1]) != crc32(frame[:len(frame)-5]) {
|
||||
return errors.New(fmt.Sprintf("SC初始化确认帧解析失败,CRC校验不通过:期望[%x] 实际[%x]",
|
||||
crc32(frame[:len(frame)-5]), binary.BigEndian.Uint32(frame[len(frame)-5:len(frame)-1])))
|
||||
}
|
||||
start := 3
|
||||
err := s.timestamp.decode(frame[start : start+5])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 5
|
||||
err = s.modeConfirm.decode(frame[start : start+2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 2
|
||||
err = s.timeSyncConfirm.decode(frame[start : start+4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 4
|
||||
err = s.scSelfCheckConfirm.decode(frame[start : start+2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HC控制帧
|
||||
type hcControlFrame struct {
|
||||
timestamp hcTimestampPackage
|
||||
io1 []byte
|
||||
io2 []byte
|
||||
io3 []byte
|
||||
io4 []byte
|
||||
io5 []byte
|
||||
pwm1 hcPwmControlPackage
|
||||
pwm2 hcPwmControlPackage
|
||||
pwm3 hcPwmControlPackage
|
||||
pwm4 hcPwmControlPackage
|
||||
pwm5 hcPwmControlPackage
|
||||
pwm6 hcPwmControlPackage
|
||||
analog1 uint16
|
||||
analog2 uint16
|
||||
analog3 uint16
|
||||
analog4 uint16
|
||||
analog5 uint16
|
||||
analog6 uint16
|
||||
cd hcCDControlPackage
|
||||
output422 hc422ControlPackage
|
||||
output485 hc485ControlPackage
|
||||
}
|
||||
|
||||
func (h *hcControlFrame) encode() []byte {
|
||||
data := make([]byte, 0, 600)
|
||||
data = append(data, FrameHead)
|
||||
data = append(data, 0, 0) //帧长度占位
|
||||
data = append(data, h.timestamp.encode()...)
|
||||
data = append(data, HcIo1)
|
||||
data = append(data, h.io1...)
|
||||
data = append(data, HcIo2)
|
||||
data = append(data, h.io2...)
|
||||
data = append(data, HcIo3)
|
||||
data = append(data, h.io3...)
|
||||
data = append(data, HcIo4)
|
||||
data = append(data, h.io4...)
|
||||
data = append(data, HcIo5)
|
||||
data = append(data, h.io5...)
|
||||
data = append(data, HcPwm1)
|
||||
data = append(data, h.pwm1.encode()...)
|
||||
data = append(data, HcPwm2)
|
||||
data = append(data, h.pwm2.encode()...)
|
||||
data = append(data, HcPwm3)
|
||||
data = append(data, h.pwm3.encode()...)
|
||||
data = append(data, HcPwm4)
|
||||
data = append(data, h.pwm4.encode()...)
|
||||
data = append(data, HcPwm5)
|
||||
data = append(data, h.pwm5.encode()...)
|
||||
data = append(data, HcPwm6)
|
||||
data = append(data, h.pwm6.encode()...)
|
||||
data = append(data, HcAnalog1)
|
||||
data = binary.BigEndian.AppendUint16(data, h.analog1)
|
||||
data = append(data, HcAnalog2)
|
||||
data = binary.BigEndian.AppendUint16(data, h.analog2)
|
||||
data = append(data, HcAnalog3)
|
||||
data = binary.BigEndian.AppendUint16(data, h.analog3)
|
||||
data = append(data, HcAnalog4)
|
||||
data = binary.BigEndian.AppendUint16(data, h.analog4)
|
||||
data = append(data, HcAnalog5)
|
||||
data = binary.BigEndian.AppendUint16(data, h.analog5)
|
||||
data = append(data, HcAnalog6)
|
||||
data = binary.BigEndian.AppendUint16(data, h.analog6)
|
||||
data = append(data, h.cd.encode()...)
|
||||
data = append(data, h.output422.encode()...)
|
||||
data = append(data, h.output485.encode()...)
|
||||
data = escape(data)
|
||||
binary.BigEndian.PutUint16(data[1:], uint16(len(data)-3)) //填充帧长度
|
||||
data = binary.BigEndian.AppendUint32(data, crc32(data))
|
||||
data = append(data, FrameTail)
|
||||
return data
|
||||
}
|
||||
|
||||
// SC采集帧
|
||||
type scCollectFrame struct {
|
||||
timestamp scTimestampPackage
|
||||
io1 scIoPackage
|
||||
io2 scIoPackage
|
||||
io3 scIoPackage
|
||||
io4 scIoPackage
|
||||
io5 scIoPackage
|
||||
pwm1 scPwmPackage
|
||||
pwm2 scPwmPackage
|
||||
analog1 scAnalogPackage
|
||||
analog2 scAnalogPackage
|
||||
}
|
||||
|
||||
func (s *scCollectFrame) decode(frame []byte) error {
|
||||
if frame[0] != FrameHead {
|
||||
return errors.New(fmt.Sprintf("SC采集帧解析失败,帧头不对:%x", frame[0]))
|
||||
}
|
||||
if uint16(len(frame)-8) != binary.BigEndian.Uint16(frame[1:3]) {
|
||||
return errors.New(fmt.Sprintf("SC采集帧解析失败,数据长度不对:期望[%x] 实际[%x]", binary.BigEndian.Uint16(frame[1:3]), len(frame)))
|
||||
}
|
||||
if binary.BigEndian.Uint32(frame[len(frame)-5:len(frame)-1]) != crc32(frame[:len(frame)-5]) {
|
||||
return errors.New(fmt.Sprintf("SC采集帧解析失败,CRC校验不通过:期望[%x] 实际[%x]",
|
||||
crc32(frame[:len(frame)-5]), binary.BigEndian.Uint32(frame[len(frame)-5:len(frame)-1])))
|
||||
}
|
||||
start := 3
|
||||
err := s.timestamp.decode(frame[start : start+5])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 5
|
||||
err = s.io1.decode(frame[start : start+4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 4
|
||||
err = s.io2.decode(frame[start : start+4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 4
|
||||
err = s.io3.decode(frame[start : start+4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 4
|
||||
err = s.io4.decode(frame[start : start+4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 4
|
||||
err = s.io5.decode(frame[start : start+4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 4
|
||||
err = s.pwm1.decode(frame[start : start+4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 4
|
||||
err = s.pwm2.decode(frame[start : start+4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 4
|
||||
err = s.analog1.decode(frame[start : start+3])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start += 3
|
||||
err = s.analog2.decode(frame[start : start+3])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var crcHashParam = crc.NewHash(&crc.Parameters{
|
||||
Width: 32,
|
||||
Polynomial: 0x1EDC6F41,
|
||||
ReflectIn: false,
|
||||
ReflectOut: false,
|
||||
Init: 0,
|
||||
FinalXor: 0,
|
||||
})
|
||||
|
||||
func crc32(data []byte) uint32 {
|
||||
return uint32(crcHashParam.CalculateCRC(data))
|
||||
}
|
||||
|
||||
func escape(data []byte) []byte {
|
||||
var escapeByte byte = 0x7D
|
||||
var xorByte byte = 0x20
|
||||
newData := make([]byte, 0, len(data))
|
||||
newData = append(newData, data[:3]...)
|
||||
for _, b := range data[3:] {
|
||||
if b <= FrameTail && b >= escapeByte {
|
||||
newData = append(newData, escapeByte)
|
||||
newData = append(newData, b^xorByte)
|
||||
} else {
|
||||
newData = append(newData, b)
|
||||
}
|
||||
}
|
||||
return newData
|
||||
}
|
|
@ -0,0 +1,316 @@
|
|||
package beijing11
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
FrameHead byte = 0x7E
|
||||
FrameTail byte = 0x7F
|
||||
)
|
||||
|
||||
type PackHead = byte
|
||||
|
||||
const (
|
||||
HcTimestamp PackHead = iota + 1 //HC的时间戳
|
||||
HcModeInfo //模式信息包
|
||||
HcTimeSync //校时信息包
|
||||
HcReqScSelfCheck //索要SC自检信息包
|
||||
HcIo1 //开关量1输出控制信息包
|
||||
HcIo2 //开关量2输出控制信息包
|
||||
HcIo3 //开关量3输出控制信息包
|
||||
HcIo4 //开关量4输出控制信息包
|
||||
HcIo5 //开关量5输出控制信息包
|
||||
HcPwm1 //PWM1输出控制信息包
|
||||
HcPwm2 //PWM2输出控制信息包
|
||||
HcPwm3 //PWM3输出控制信息包
|
||||
HcPwm4 //PWM4输出控制信息包
|
||||
HcPwm5 //PWM5输出控制信息包
|
||||
HcPwm6 //PWM6输出控制信息包
|
||||
HcAnalog1 //模拟量1输出控制信息包
|
||||
HcAnalog2 //模拟量2输出控制信息包
|
||||
HcAnalog3 //模拟量3输出控制信息包
|
||||
HcAnalog4 //模拟量4输出控制信息包
|
||||
HcAnalog5 //模拟量5输出控制信息包
|
||||
HcAnalog6 //模拟量6输出控制信息包
|
||||
HcCD //CD信号输出控制信息包
|
||||
Hc422 //422信号输出控制信息包
|
||||
Hc485 //485信号输出控制信息包
|
||||
|
||||
ScTimestamp //SC的时间戳
|
||||
ScModeConfirm //模式确认信息包
|
||||
ScTimeSyncConfirm //校时确认包
|
||||
ScSelfCheckConfirm //SC自检信息包
|
||||
ScIo1 //开关量1输出控制信息包
|
||||
ScIo2 //开关量2输出控制信息包
|
||||
ScIo3 //开关量3输出控制信息包
|
||||
ScIo4 //开关量4输出控制信息包
|
||||
ScIo5 //开关量5输出控制信息包
|
||||
ScPwm1 //PWM1输出控制信息包
|
||||
ScPwm2 //PWM2输出控制信息包
|
||||
ScAnalog1 //模拟量1输出控制信息包
|
||||
ScAnalog2 //模拟量2输出控制信息包
|
||||
ScFaultInfo //故障信息包
|
||||
)
|
||||
|
||||
type Mode = byte
|
||||
|
||||
const (
|
||||
Invalid Mode = 0
|
||||
One = 1 //模式一(小型化型式试验)
|
||||
)
|
||||
|
||||
type PwmMode = byte
|
||||
|
||||
const (
|
||||
PwmMode_Invalid PwmMode = iota //无效
|
||||
PwmMode_One //输出模式1:1、2、3路PWM为一组,4、5、6路PWM为另一组,每组的3路PWM频率占空比相同,相位互差120°
|
||||
PwmMode_Two //输出模式2:1、2路PWM为一组,3、4,5、6路PWM为另外两组,每组的2路PWM频率占空比相同,相位互差180°
|
||||
PwmMode_Three //输出模式3:1、2、3、4、5、6路PWM可独立输出,每路的频率占空比相位不会相互约束。
|
||||
)
|
||||
|
||||
type hcTimestampPackage struct {
|
||||
timestamp uint32
|
||||
}
|
||||
|
||||
func (h *hcTimestampPackage) packHead() PackHead {
|
||||
return HcTimestamp
|
||||
}
|
||||
|
||||
func (h *hcTimestampPackage) encode() []byte {
|
||||
data := make([]byte, 0, 5)
|
||||
data = append(data, h.packHead())
|
||||
data = binary.BigEndian.AppendUint32(data, h.timestamp)
|
||||
return data
|
||||
}
|
||||
|
||||
type modeInfoPackage struct {
|
||||
mode Mode
|
||||
}
|
||||
|
||||
func (m *modeInfoPackage) packHead() PackHead {
|
||||
return HcModeInfo
|
||||
}
|
||||
|
||||
func (m *modeInfoPackage) encode() []byte {
|
||||
data := make([]byte, 0, 2)
|
||||
data = append(data, m.packHead())
|
||||
data = append(data, m.mode)
|
||||
return data
|
||||
}
|
||||
|
||||
type timeSyncInfoPackage struct {
|
||||
hour byte
|
||||
minute byte
|
||||
second byte
|
||||
}
|
||||
|
||||
func (t *timeSyncInfoPackage) packHead() PackHead {
|
||||
return HcTimeSync
|
||||
}
|
||||
|
||||
func (t *timeSyncInfoPackage) encode() []byte {
|
||||
data := make([]byte, 0, 4)
|
||||
data = append(data, t.packHead())
|
||||
data = append(data, t.hour)
|
||||
data = append(data, t.minute)
|
||||
data = append(data, t.second)
|
||||
return data
|
||||
}
|
||||
|
||||
type reqScSelfCheckInfoPackage struct {
|
||||
on bool
|
||||
}
|
||||
|
||||
func (r *reqScSelfCheckInfoPackage) packHead() PackHead {
|
||||
return HcReqScSelfCheck
|
||||
}
|
||||
|
||||
func (r *reqScSelfCheckInfoPackage) encode() []byte {
|
||||
data := make([]byte, 0, 2)
|
||||
data = append(data, r.packHead())
|
||||
if r.on {
|
||||
data = append(data, 0xAA)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
type hcPwmControlPackage struct {
|
||||
mode PwmMode
|
||||
frequency uint16
|
||||
duty byte
|
||||
}
|
||||
|
||||
func (p *hcPwmControlPackage) encode() []byte {
|
||||
data := make([]byte, 0, 4)
|
||||
data = append(data, p.mode)
|
||||
data = binary.BigEndian.AppendUint16(data, p.frequency)
|
||||
data = append(data, p.duty)
|
||||
return data
|
||||
}
|
||||
|
||||
type hcCDControlPackage struct {
|
||||
value byte
|
||||
}
|
||||
|
||||
func (c *hcCDControlPackage) headPack() byte {
|
||||
return HcCD
|
||||
}
|
||||
|
||||
func (c *hcCDControlPackage) encode() []byte {
|
||||
data := make([]byte, 0, 2)
|
||||
data = append(data, c.headPack())
|
||||
data = append(data, c.value)
|
||||
return data
|
||||
}
|
||||
|
||||
type hc422ControlPackage struct {
|
||||
id byte
|
||||
value []byte //长度256
|
||||
}
|
||||
|
||||
func (c *hc422ControlPackage) headPack() byte {
|
||||
return Hc422
|
||||
}
|
||||
|
||||
func (c *hc422ControlPackage) encode() []byte {
|
||||
data := make([]byte, 0, 258)
|
||||
data = append(data, c.headPack())
|
||||
data = append(data, c.id)
|
||||
data = append(data, c.value...)
|
||||
return data
|
||||
}
|
||||
|
||||
type hc485ControlPackage struct {
|
||||
id byte
|
||||
value []byte //长度256
|
||||
}
|
||||
|
||||
func (c *hc485ControlPackage) headPack() byte {
|
||||
return Hc485
|
||||
}
|
||||
|
||||
func (c *hc485ControlPackage) encode() []byte {
|
||||
data := make([]byte, 0, 258)
|
||||
data = append(data, c.headPack())
|
||||
data = append(data, c.id)
|
||||
data = append(data, c.value...)
|
||||
return data
|
||||
}
|
||||
|
||||
type scTimestampPackage struct {
|
||||
timestamp uint32
|
||||
}
|
||||
|
||||
func (s *scTimestampPackage) decode(data []byte) error {
|
||||
if len(data) != 5 || data[0] != ScTimestamp {
|
||||
return errors.New(fmt.Sprintf("数据有误,无法解析为Sc时间戳信息包:%x", data))
|
||||
}
|
||||
s.timestamp = binary.BigEndian.Uint32(data[1:])
|
||||
return nil
|
||||
}
|
||||
|
||||
type scModeConfirmPackage struct {
|
||||
mode Mode
|
||||
}
|
||||
|
||||
func (s *scModeConfirmPackage) decode(data []byte) error {
|
||||
if len(data) != 2 || data[0] != ScModeConfirm {
|
||||
return errors.New(fmt.Sprintf("数据有误,无法解析为模式确认信息包:%x", data))
|
||||
}
|
||||
s.mode = data[1]
|
||||
return nil
|
||||
}
|
||||
|
||||
type scTimeSyncConfirmPackage struct {
|
||||
hour byte
|
||||
minute byte
|
||||
second byte
|
||||
}
|
||||
|
||||
func (s *scTimeSyncConfirmPackage) decode(data []byte) error {
|
||||
if len(data) != 4 || data[0] != ScTimeSyncConfirm {
|
||||
return errors.New(fmt.Sprintf("数据有误,无法解析为时钟同步确认信息包:%x", data))
|
||||
}
|
||||
s.hour = data[1]
|
||||
s.minute = data[2]
|
||||
s.second = data[3]
|
||||
return nil
|
||||
}
|
||||
|
||||
type scSelfCheckConfirmPackage struct {
|
||||
result byte
|
||||
}
|
||||
|
||||
func (s *scSelfCheckConfirmPackage) decode(data []byte) error {
|
||||
if len(data) != 2 || data[0] != ScSelfCheckConfirm {
|
||||
return errors.New(fmt.Sprintf("数据有误,无法解析为自检确认信息包:%x", data))
|
||||
}
|
||||
s.result = data[1]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *scSelfCheckConfirmPackage) isNormal() bool {
|
||||
return s.result == 0xAA
|
||||
}
|
||||
|
||||
func (s *scSelfCheckConfirmPackage) isAbnormal() bool {
|
||||
return s.result == 0x55
|
||||
}
|
||||
|
||||
type scIoPackage struct {
|
||||
packHead byte
|
||||
value []byte //三个字节
|
||||
}
|
||||
|
||||
func (s *scIoPackage) decode(data []byte) error {
|
||||
if len(data) != 4 || data[0] < ScIo1 || data[0] > ScIo5 {
|
||||
return errors.New(fmt.Sprintf("数据有误,无法解析为IO信息包:%x", data))
|
||||
}
|
||||
s.packHead = data[0]
|
||||
s.value = data[1:]
|
||||
return nil
|
||||
}
|
||||
|
||||
type scPwmPackage struct {
|
||||
packHead byte
|
||||
frequency uint16
|
||||
duty byte
|
||||
}
|
||||
|
||||
func (s *scPwmPackage) decode(data []byte) error {
|
||||
if len(data) != 4 || data[0] < ScPwm1 || data[0] > ScPwm2 {
|
||||
return errors.New(fmt.Sprintf("数据有误,无法解析为PWM信息包:%x", data))
|
||||
}
|
||||
s.packHead = data[0]
|
||||
s.frequency = binary.BigEndian.Uint16(data[1:3])
|
||||
s.duty = data[3]
|
||||
return nil
|
||||
}
|
||||
|
||||
type scAnalogPackage struct {
|
||||
packHead byte
|
||||
current uint16
|
||||
}
|
||||
|
||||
func (s *scAnalogPackage) decode(data []byte) error {
|
||||
if len(data) != 3 || data[0] < ScAnalog1 || data[0] > ScAnalog2 {
|
||||
return errors.New(fmt.Sprintf("数据有误,无法解析为模拟量信息包:%x", data))
|
||||
}
|
||||
s.packHead = data[0]
|
||||
s.current = binary.BigEndian.Uint16(data[1:])
|
||||
return nil
|
||||
}
|
||||
|
||||
type scFaultPackage struct {
|
||||
selfCheck bool //自检是否正常
|
||||
selfCheckBeforeControl bool //开机时是否未收到索要自检信息包却收到上位机控制命令
|
||||
timeSync bool //时分秒校时是否正常
|
||||
output bool //输出反馈是否正常
|
||||
hcFrameFormatCorrect bool //收到HC帧格式是否正确
|
||||
hcTimestamp bool //按照协议规定检测HC时间戳(ms)是否错误
|
||||
crc bool //收到的信息CRC检验错误累计是否超过3次(超过3次为异常
|
||||
other bool //是否发生除上述情况外的其他故障
|
||||
}
|
|
@ -0,0 +1,432 @@
|
|||
package beijing11
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"joylink.club/bj-rtsts-server/dto/state_proto"
|
||||
"joylink.club/bj-rtsts-server/third_party/tpapi"
|
||||
"joylink.club/bj-rtsts-server/third_party/udp"
|
||||
"joylink.club/bj-rtsts-server/ts/simulation/wayside/memory"
|
||||
"log"
|
||||
"log/slog"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
logTag = "[北京11号线工装通信]"
|
||||
privateLogger *slog.Logger
|
||||
loggerInit sync.Once
|
||||
)
|
||||
|
||||
var (
|
||||
mu = sync.Mutex{} //启动任务时使用,避免重复启动任务
|
||||
serviceCtx *serviceContext //当前正在运行的服务
|
||||
)
|
||||
|
||||
type serviceContext struct {
|
||||
simulation *memory.VerifySimulation
|
||||
trainState *state_proto.TrainState
|
||||
cancelFunc context.CancelFunc
|
||||
client udp.UdpClient
|
||||
server udp.UdpServer
|
||||
|
||||
startTime time.Time //服务启动时间
|
||||
initFrame *hcInitFrame
|
||||
initComplete bool
|
||||
lastTime time.Time //接收到最后一条消息的时间
|
||||
|
||||
state tpapi.ThirdPartyApiServiceState
|
||||
}
|
||||
|
||||
func (s *serviceContext) Type() state_proto.SimulationThirdPartyApiService_Type {
|
||||
return state_proto.SimulationThirdPartyApiService_Train_pc_sim
|
||||
}
|
||||
|
||||
func (s *serviceContext) State() tpapi.ThirdPartyApiServiceState {
|
||||
return s.state
|
||||
}
|
||||
|
||||
func (s *serviceContext) FindAppendApiService() []tpapi.ThirdPartyApiService {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *serviceContext) TrueService() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *serviceContext) ServiceDesc() string {
|
||||
return logTag
|
||||
}
|
||||
|
||||
func Start(simulation *memory.VerifySimulation) {
|
||||
config := simulation.GetRunConfig().BtmVobc
|
||||
if !config.Open {
|
||||
return
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
client := udp.NewClient(fmt.Sprintf("%s:%d", config.RemoteIp, config.RemoteUdpPort))
|
||||
serviceCtx = &serviceContext{
|
||||
simulation: simulation,
|
||||
cancelFunc: cancelFunc,
|
||||
client: client,
|
||||
startTime: time.Now(),
|
||||
}
|
||||
udp.NewServer(fmt.Sprintf(":%d", config.LocalUdpPort), serviceCtx.handle)
|
||||
serviceCtx.runSendTask(ctx)
|
||||
logger().Info("与工装通信服务启动完毕")
|
||||
}
|
||||
|
||||
func Stop(simulation *memory.VerifySimulation) {
|
||||
if serviceCtx.simulation == simulation {
|
||||
serviceCtx.cancelFunc()
|
||||
if serviceCtx.client != nil {
|
||||
serviceCtx.client.Close()
|
||||
}
|
||||
if serviceCtx.server != nil {
|
||||
serviceCtx.server.Close()
|
||||
}
|
||||
serviceCtx = nil
|
||||
logger().Info("与工装通信服务关闭")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *serviceContext) handle(data []byte) {
|
||||
now := time.Now()
|
||||
if !s.initComplete {
|
||||
frame := &scInitFrame{}
|
||||
err := frame.decode(data)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
s.lastTime = now
|
||||
s.initComplete = true
|
||||
} else {
|
||||
frame := &scCollectFrame{}
|
||||
err := frame.decode(data)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
//校验时间
|
||||
if now.Sub(s.lastTime).Milliseconds() > 200 {
|
||||
logger().Error("SC消息超时")
|
||||
}
|
||||
s.lastTime = now
|
||||
//更新列车驾驶台状态
|
||||
s.handleIo(frame)
|
||||
}
|
||||
}
|
||||
|
||||
// 由于本系统只有一组控制台按钮,所以SC反馈的状态只有激活端的生效
|
||||
func (s *serviceContext) handleIo(frame *scCollectFrame) {
|
||||
sameBytes := make([]byte, 0, 4)
|
||||
graphicData := memory.FindTrainTccGraphicData(s.simulation)
|
||||
var end1 bool
|
||||
for _, key := range s.trainState.Tcc.DriverKey {
|
||||
if key.Val {
|
||||
knob, find := memory.FindTrainTccGraphicDataKey(graphicData, key.Id)
|
||||
if !find {
|
||||
return
|
||||
}
|
||||
if knob.Code == memory.SKQYS1 {
|
||||
end1 = true
|
||||
sameBytes = append(sameBytes, frame.io1.value[0], frame.io1.value[1])
|
||||
sameBytes = append(sameBytes, frame.io2.value...)
|
||||
} else {
|
||||
sameBytes = append(sameBytes, frame.io3.value[0], frame.io3.value[1])
|
||||
sameBytes = append(sameBytes, frame.io4.value...)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(sameBytes) == 0 { //未找到激活端
|
||||
return
|
||||
}
|
||||
|
||||
//io1/io3-byte1
|
||||
//ATO使能输出2(安全)/ATO使能输出1(安全)(缺失,ps:下面还有一个“ATO已激活”的点位)
|
||||
s.trainState.VobcState.TrainStartedLed = sameBytes[0]&1<<4 != 0 //车启动灯
|
||||
s.trainState.VobcState.NoSpeedSigle = sameBytes[0]&1<<3 != 0 //零速信号
|
||||
//右门解锁(缺失)
|
||||
//左门解锁(缺失)
|
||||
s.trainState.VobcState.TrainTractionCuted = sameBytes[0]&1 == 0 //牵引切断
|
||||
//io1/io3-byte2
|
||||
s.trainState.VobcState.EmergencyBrakingStatus = sameBytes[1]&1<<5 == 0 && sameBytes[1]&1<<4 == 0 //1端紧急(2)/1端紧急(1)
|
||||
s.trainState.VobcState.WakeUpBtn = sameBytes[1]&1<<3 != 0 //唤醒输出
|
||||
s.trainState.VobcState.SleepBtn = sameBytes[1]&1<<2 != 0 //休眠输出
|
||||
//io2/io4-byte1
|
||||
//空气制动隔离输出(缺失)
|
||||
//跳跃指令(缺失)
|
||||
s.trainState.VobcState.Cam = sameBytes[2]&1<<5 != 0 //CAM输出
|
||||
s.trainState.VobcState.Fam = sameBytes[2]&1<<4 != 0 //FAM输出
|
||||
s.trainState.VobcState.DirectionBackward = sameBytes[2]&1<<3 != 0 //方向向后指令
|
||||
s.trainState.VobcState.DirectionForward = sameBytes[2]&1<<2 != 0 //方向向前指令
|
||||
s.trainState.VobcState.LightDriverActive = true //驾驶室激活输出
|
||||
if end1 {
|
||||
s.trainState.VobcState.Tc1Active = true
|
||||
s.trainState.VobcState.Tc2Active = false
|
||||
} else {
|
||||
s.trainState.VobcState.Tc1Active = false
|
||||
s.trainState.VobcState.Tc2Active = true
|
||||
}
|
||||
//VBTC对端重启指令(缺失)
|
||||
//io2/io4-byte2
|
||||
s.trainState.VobcState.LeftDoorCloseCommand = sameBytes[3]&1<<7 != 0 //全列车左车门关闭输出(姑且认为全列车门==客室车门吧)
|
||||
s.trainState.VobcState.LeftDoorOpenCommand = sameBytes[3]&1<<6 != 0 //客室左车门开启输出
|
||||
s.trainState.VobcState.MaintainBrakeStatus = sameBytes[3]&1<<5 != 0 //保持制动
|
||||
s.trainState.VobcState.BrakeEffective = sameBytes[3]&1<<4 != 0 //制动状态
|
||||
s.trainState.VobcState.TractionStatus = sameBytes[3]&1<<3 != 0 //牵引状态
|
||||
s.trainState.VobcState.Ato = sameBytes[3]&1<<2 != 0 //ATO已激活
|
||||
s.trainState.VobcState.StopNotAllBrake = sameBytes[3]&1<<1 != 0 //停车制动缓解输出
|
||||
s.trainState.VobcState.ParkingBrakeStatus = sameBytes[3]&1<<0 != 0 //停车制动施加输出
|
||||
//io2/io4-byte3
|
||||
//行李车门右门使能
|
||||
//行李车门左门使能
|
||||
s.trainState.VobcState.RightDoorCloseCommand = sameBytes[4]&1<<1 != 0 //全列车右车门关闭输出
|
||||
s.trainState.VobcState.RightDoorOpenCommand = sameBytes[4]&1 != 0 //客室右车门开启输出
|
||||
}
|
||||
|
||||
func (s *serviceContext) runSendTask(ctx context.Context) {
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
logger().Error("数据发送任务出错,记录后重启", "error", err, "stack", string(debug.Stack()))
|
||||
s.runSendTask(ctx)
|
||||
}
|
||||
}()
|
||||
for range time.Tick(50 * time.Millisecond) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
if !s.initComplete {
|
||||
frame := s.buildHcInitFrame()
|
||||
s.send(frame.encode())
|
||||
} else {
|
||||
frame := s.buildHcControlFrame()
|
||||
s.send(frame.encode())
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *serviceContext) buildHcInitFrame() *hcInitFrame {
|
||||
frame := &hcInitFrame{}
|
||||
now := time.Now()
|
||||
frame.timestamp.timestamp = uint32(now.Sub(s.startTime).Milliseconds())
|
||||
frame.modeInfo.mode = One
|
||||
frame.timeSyncInfo.hour = byte(now.Hour())
|
||||
frame.timeSyncInfo.minute = byte(now.Minute())
|
||||
frame.timeSyncInfo.second = byte(now.Second())
|
||||
frame.reqScSelfCheckInfo.on = true
|
||||
return frame
|
||||
}
|
||||
|
||||
func (s *serviceContext) buildHcControlFrame() *hcControlFrame {
|
||||
frame := &hcControlFrame{}
|
||||
now := time.Now()
|
||||
frame.timestamp.timestamp = uint32(now.Sub(s.startTime).Milliseconds())
|
||||
graphicData := memory.FindTrainTccGraphicData(s.simulation)
|
||||
bytes1 := s.buildActivationIoBytes()
|
||||
bytes2 := s.buildUnactivatedIoBytes()
|
||||
|
||||
var findActivation bool
|
||||
for _, key := range s.trainState.Tcc.DriverKey {
|
||||
if key.Val {
|
||||
findActivation = true
|
||||
knob, find := memory.FindTrainTccGraphicDataKey(graphicData, key.Id)
|
||||
if !find {
|
||||
return nil
|
||||
}
|
||||
if knob.Code == memory.SKQYS1 {
|
||||
frame.io1 = bytes1[:3]
|
||||
frame.io2 = bytes1[3:6]
|
||||
frame.io3 = bytes2[:3]
|
||||
frame.io4 = bytes2[3:6]
|
||||
frame.io5 = []byte{bytes1[6], bytes2[6], 0}
|
||||
} else {
|
||||
frame.io1 = bytes2[:3]
|
||||
frame.io2 = bytes2[3:6]
|
||||
frame.io3 = bytes1[:3]
|
||||
frame.io4 = bytes1[3:6]
|
||||
frame.io5 = []byte{bytes2[6], bytes1[6], 0}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !findActivation {
|
||||
return nil
|
||||
}
|
||||
frame.pwm1 = hcPwmControlPackage{One, 0, 0}
|
||||
frame.pwm2 = hcPwmControlPackage{One, 0, 0}
|
||||
frame.pwm3 = hcPwmControlPackage{One, 0, 0}
|
||||
frame.pwm4 = hcPwmControlPackage{One, 0, 0}
|
||||
frame.pwm5 = hcPwmControlPackage{One, 0, 0}
|
||||
frame.pwm6 = hcPwmControlPackage{One, 0, 0}
|
||||
frame.analog1 = 0
|
||||
frame.analog2 = 0
|
||||
frame.analog3 = 0
|
||||
frame.analog4 = 0
|
||||
frame.analog5 = 0
|
||||
frame.analog6 = 0
|
||||
return frame
|
||||
}
|
||||
|
||||
func (s *serviceContext) send(data []byte) {
|
||||
if err := s.client.Send(data); err != nil {
|
||||
log.Println("数据发送任务出错", "error", err)
|
||||
}
|
||||
if err := s.client.Send(data); err != nil {
|
||||
log.Println("数据发送任务出错", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 构建激活端io字节数组
|
||||
func (s *serviceContext) buildActivationIoBytes() []byte {
|
||||
data := make([]byte, 7) //前6个字节对应io1/io2或者io3/io4,第7个字节对应激活端的io5
|
||||
graphicData := memory.FindTrainTccGraphicData(s.simulation)
|
||||
if graphicData == nil {
|
||||
return data
|
||||
}
|
||||
handlerZero := s.trainState.Tcc.PushHandler.Val == 0 //操纵杆在零位
|
||||
front := s.trainState.Tcc.SwitchKeyMap[memory.QHFXKZ].Val == 1 //方向手柄在向前位
|
||||
//io1/io3-byte3
|
||||
if handlerZero && front { //牵引制动手柄在零位且方向手柄在向前位
|
||||
data[2] += 1 << 7
|
||||
}
|
||||
if s.trainState.Tcc.LightMaps[memory.LIGHT_TFZDSJ].Val { //车辆保持制动已实施(是停车制动吗?)
|
||||
data[2] += 1 << 6
|
||||
}
|
||||
if !s.trainState.Tcc.Buttons[memory.JJZD].Passed { //车辆已实施紧急制动(低电平有效)
|
||||
data[2] += 1 << 5
|
||||
}
|
||||
if s.trainState.Tcc.LightMaps[memory.LIGHT_QQY].Val { //牵引已切除(高电平有效)
|
||||
data[2] += 1 << 4
|
||||
}
|
||||
data[2] += 1 << 3 //车门关闭且锁闭
|
||||
data[2] += 1 << 2 //列车完整性
|
||||
data[2] += 1 << 1 //司机钥匙激活信号
|
||||
data[2] += 1 //驾驶室激活状态
|
||||
//io1/io3-byte2
|
||||
if s.trainState.Tcc.Buttons[memory.ATOQD].Passed { //ATO启动按钮2已按下
|
||||
data[1] += 1 << 7
|
||||
}
|
||||
if s.trainState.Tcc.Buttons[memory.LIGHT_ATO_CLOSE_LEFT_DOOR].Passed { //左门关按钮按下
|
||||
data[1] += 1 << 6
|
||||
}
|
||||
if s.trainState.Tcc.Buttons[memory.LIGHT_ATO_OPEN_LEFT_DOOR].Passed { //左门开按钮按下
|
||||
data[1] += 1 << 5
|
||||
}
|
||||
data[1] += 1 << 3 //车辆紧急手柄激活(低电平有效)
|
||||
if s.trainState.Tcc.SwitchKeyMap[memory.QHFXKZ].Val == 0 { //方向手柄向后
|
||||
data[1] += 1 << 2
|
||||
}
|
||||
data[1] += 1 << 1 //逃生门状态
|
||||
if s.trainState.Tcc.Buttons[memory.MSQR].Passed { //确认按钮状态(是模式确认吗?)
|
||||
data[1] += 1
|
||||
}
|
||||
//io1/io3-byte1
|
||||
data[0] = data[2]
|
||||
//io2/io4-byte3
|
||||
if handlerZero && front { //牵引制动手柄在牵引位且方向向前
|
||||
data[5] += 1 << 6
|
||||
}
|
||||
if !s.trainState.Tcc.Buttons[memory.ZDZGZ].Passed { //制动重故障(低电平有效)
|
||||
data[5] += 1 << 5
|
||||
}
|
||||
if !s.trainState.Tcc.Buttons[memory.ZAWTGJC].Passed { //障碍物脱轨有效(低电平有效)
|
||||
data[5] += 1 << 4
|
||||
}
|
||||
//EUM开关激活(省略)
|
||||
if s.trainState.Tcc.Buttons[memory.LIGHT_ATO_CLOSE_RIGHT_DOOR].Passed { //右门关门按钮按下
|
||||
data[5] += 1 << 2
|
||||
}
|
||||
if s.trainState.Tcc.Buttons[memory.LIGHT_ATO_OPEN_RIGHT_DOOR].Passed { //右门开门按钮按下
|
||||
data[5] += 1 << 1
|
||||
}
|
||||
if s.trainState.Tcc.Buttons[memory.ZF].Passed { //AR按钮按下
|
||||
data[5] += 1
|
||||
}
|
||||
//io2/io4-byte2
|
||||
if s.trainState.Tcc.Buttons[memory.MSJJ].Passed { //模式选择下按钮按下
|
||||
data[4] += 1 << 7
|
||||
}
|
||||
if s.trainState.Tcc.Buttons[memory.MSSJ].Passed { //模式选择上按钮按下
|
||||
data[4] += 1 << 6
|
||||
}
|
||||
if s.trainState.Tcc.Buttons[memory.ATOQD].Passed { //ATO启动按钮1已按下
|
||||
data[4] += 1 << 5
|
||||
}
|
||||
if handlerZero && front { //牵引制动手柄在牵引位且方向向前
|
||||
data[4] += 1 << 2
|
||||
}
|
||||
if s.trainState.Tcc.Buttons[memory.ZDZGZ].Passed { //制动重故障(低电平有效)
|
||||
data[4] += 1 << 1
|
||||
}
|
||||
if s.trainState.Tcc.Buttons[memory.ZAWTGJC].Passed { //障碍物脱轨有效(低电平有效)
|
||||
data[4] += 1
|
||||
}
|
||||
//io2/io4-byte1
|
||||
switch s.trainState.Tcc.SwitchKeyMap[memory.MMS].Val {
|
||||
case 0: //人工开人工关
|
||||
data[3] += 1 << 5
|
||||
case 1: //自动开自动关
|
||||
data[3] += 1 << 6
|
||||
case 2: //自动开人工关
|
||||
data[3] += 1 << 7
|
||||
}
|
||||
//烟雾报警
|
||||
data[3] += 1 << 3 //车辆紧急手柄激活(低电平有效)
|
||||
if s.trainState.Tcc.SwitchKeyMap[memory.QHFXKZ].Val == 0 { //方向手柄向后
|
||||
data[3] += 1 << 2
|
||||
}
|
||||
data[3] += 1 << 1 //逃生门状态
|
||||
if s.trainState.Tcc.Buttons[memory.MSQR].Passed { //确认按钮状态(是模式确认吗?)
|
||||
data[3] += 1
|
||||
}
|
||||
//io5-byte2/byte1
|
||||
//低压上电检测(省略)
|
||||
data[6] += 1 << 3 //车辆上电按钮
|
||||
if s.trainState.Tcc.Buttons[memory.JX].Passed {
|
||||
data[6] += 1 << 2
|
||||
}
|
||||
//蓄电池欠压保护输入(省略)
|
||||
if s.trainState.Tcc.Buttons[memory.XM].Passed { //车辆休眠按钮
|
||||
data[6] += 1
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// 构建未激活端io字节数组
|
||||
func (s *serviceContext) buildUnactivatedIoBytes() []byte {
|
||||
data := make([]byte, 7) //前6个字节对应io1/io2或者io3/io4,第7个字节对应未激活端的io5
|
||||
data[2] += 1 << 7 //牵引制动手柄在零位且方向手柄在向前位
|
||||
data[2] += 1 << 5 //车辆已实施紧急制动(低电平有效)
|
||||
data[2] += 1 << 3 //车门关闭且锁闭
|
||||
data[2] += 1 << 2 //列车完整性
|
||||
data[1] += 1 << 3 //车辆紧急手柄激活(低电平有效)
|
||||
data[1] += 1 << 2 //逃生门状态
|
||||
data[0] = data[2]
|
||||
data[5] += 1 << 6 //牵引制动手柄在牵引位且方向向前
|
||||
data[5] += 1 << 5 //制动重故障(低电平有效)
|
||||
data[5] += 1 << 4 //障碍物脱轨有效(低电平有效)
|
||||
data[4] += 1 << 2 //牵引制动手柄在牵引位且方向向前
|
||||
data[4] += 1 << 1 //制动重故障(低电平有效)
|
||||
data[4] += 1 //障碍物脱轨有效(低电平有效)
|
||||
data[3] += 1 << 7 //自动开人工关
|
||||
data[3] += 1 << 3 //车辆紧急手柄激活(低电平有效)
|
||||
data[3] += 1 << 1 //逃生门状态
|
||||
return data
|
||||
}
|
||||
|
||||
func logger() *slog.Logger {
|
||||
loggerInit.Do(func() {
|
||||
privateLogger = slog.Default().With("tag", logTag)
|
||||
})
|
||||
return privateLogger
|
||||
}
|
|
@ -14,6 +14,7 @@ const (
|
|||
QHFXKZ = "QHFXKZ" //驾驶方向
|
||||
QYSB = "QYSB" //牵引制动手柄
|
||||
ATOQD = "ATOQD" //ato 启动
|
||||
MMS = "MMS" //门模式
|
||||
|
||||
ATPQCKG = "ATPQCKG" //ATP切除开关
|
||||
KZM = "KZM" //开左门按钮
|
||||
|
@ -54,7 +55,7 @@ const (
|
|||
)
|
||||
|
||||
// 获取列车控制图形数据
|
||||
func findTrainTccGraphicData(vs *VerifySimulation) *data_proto.TccGraphicStorage {
|
||||
func FindTrainTccGraphicData(vs *VerifySimulation) *data_proto.TccGraphicStorage {
|
||||
var tccGI *data_proto.TccGraphicStorage
|
||||
for _, id := range vs.MapIds {
|
||||
if QueryGiType(id) == data_proto.PictureType_TrainControlCab {
|
||||
|
@ -64,41 +65,41 @@ func findTrainTccGraphicData(vs *VerifySimulation) *data_proto.TccGraphicStorage
|
|||
}
|
||||
return tccGI
|
||||
}
|
||||
func findTrainTccGraphicDataButtons(tccG *data_proto.TccGraphicStorage) []*data_proto.TccButton {
|
||||
func FindTrainTccGraphicDataButtons(tccG *data_proto.TccGraphicStorage) []*data_proto.TccButton {
|
||||
return tccG.TccButtons
|
||||
}
|
||||
func findTrainTccGraphicDataKeys(tccG *data_proto.TccGraphicStorage) []*data_proto.TccKey {
|
||||
func FindTrainTccGraphicDataKeys(tccG *data_proto.TccGraphicStorage) []*data_proto.TccKey {
|
||||
return tccG.TccKeys
|
||||
}
|
||||
func findTrainTccGraphicDataHandlers(tccG *data_proto.TccGraphicStorage) []*data_proto.TccHandle {
|
||||
func FindTrainTccGraphicDataHandlers(tccG *data_proto.TccGraphicStorage) []*data_proto.TccHandle {
|
||||
return tccG.TccHandles
|
||||
}
|
||||
func findTrainTccGraphicDataButtonByCode(tccG *data_proto.TccGraphicStorage, deviceCode string) (*data_proto.TccButton, bool) {
|
||||
for _, d := range findTrainTccGraphicDataButtons(tccG) {
|
||||
func FindTrainTccGraphicDataButtonByCode(tccG *data_proto.TccGraphicStorage, deviceCode string) (*data_proto.TccButton, bool) {
|
||||
for _, d := range FindTrainTccGraphicDataButtons(tccG) {
|
||||
if d.Code == deviceCode {
|
||||
return d, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
func findTrainTccGraphicDataButton(tccG *data_proto.TccGraphicStorage, id uint32) (*data_proto.TccButton, bool) {
|
||||
for _, d := range findTrainTccGraphicDataButtons(tccG) {
|
||||
func FindTrainTccGraphicDataButton(tccG *data_proto.TccGraphicStorage, id uint32) (*data_proto.TccButton, bool) {
|
||||
for _, d := range FindTrainTccGraphicDataButtons(tccG) {
|
||||
if d.Common.Id == id {
|
||||
return d, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
func findTrainTccGraphicDataKey(tccG *data_proto.TccGraphicStorage, id uint32) (*data_proto.TccKey, bool) {
|
||||
for _, d := range findTrainTccGraphicDataKeys(tccG) {
|
||||
func FindTrainTccGraphicDataKey(tccG *data_proto.TccGraphicStorage, id uint32) (*data_proto.TccKey, bool) {
|
||||
for _, d := range FindTrainTccGraphicDataKeys(tccG) {
|
||||
if d.Common.Id == id {
|
||||
return d, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
func findTrainTccGraphicDataHandler(tccG *data_proto.TccGraphicStorage, id uint32) (*data_proto.TccHandle, bool) {
|
||||
for _, d := range findTrainTccGraphicDataHandlers(tccG) {
|
||||
func FindTrainTccGraphicDataHandler(tccG *data_proto.TccGraphicStorage, id uint32) (*data_proto.TccHandle, bool) {
|
||||
for _, d := range FindTrainTccGraphicDataHandlers(tccG) {
|
||||
if d.Common.Id == id {
|
||||
return d, true
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func ControlTrainUpdate(s *VerifySimulation, ct *request_proto.TrainControl) {
|
|||
if !ok {
|
||||
panic(sys_error.New(fmt.Sprintf("列车【%s】不存在", ct.TrainId)))
|
||||
}
|
||||
tccGraphicData := findTrainTccGraphicData(s)
|
||||
tccGraphicData := FindTrainTccGraphicData(s)
|
||||
if tccGraphicData == nil {
|
||||
slog.Error("列车控制未找到TCC图形数据")
|
||||
panic(sys_error.New("未找到TCC图形数据"))
|
||||
|
@ -89,7 +89,7 @@ func ControlTrainUpdate(s *VerifySimulation, ct *request_proto.TrainControl) {
|
|||
|
||||
func trainControlButton(train *state_proto.TrainState, deviceId uint32, active bool, tccGraphic *data_proto.TccGraphicStorage) []message.TrainPcSimBaseMessage {
|
||||
|
||||
if graphicBtn, ok := findTrainTccGraphicDataButton(tccGraphic, deviceId); ok {
|
||||
if graphicBtn, ok := FindTrainTccGraphicDataButton(tccGraphic, deviceId); ok {
|
||||
btn := train.Tcc.Buttons[graphicBtn.Code]
|
||||
if btn == nil {
|
||||
slog.Error("未找到对应的车载摁钮code:", graphicBtn.Code, "设备id:", deviceId)
|
||||
|
@ -356,7 +356,7 @@ func controlAtoSenderBtn(vobc *state_proto.TrainVobcState, active bool, tccBtn *
|
|||
|
||||
// 列车方向
|
||||
func trainControlDirKey(trainSpeed int32, vobc *state_proto.TrainVobcState, tcc *state_proto.TrainControlState, request *request_proto.TrainControl_SwitchKeyChange, deviceId uint32, tccGraphic *data_proto.TccGraphicStorage) []message.TrainPcSimBaseMessage {
|
||||
dirKey, find := findTrainTccGraphicDataKey(tccGraphic, deviceId)
|
||||
dirKey, find := FindTrainTccGraphicDataKey(tccGraphic, deviceId)
|
||||
if !find {
|
||||
slog.Error("未找到对应的列车方向键deviceId:", deviceId)
|
||||
panic(sys_error.New("未找到对应的列车方向键"))
|
||||
|
@ -380,7 +380,7 @@ func trainControlDirKey(trainSpeed int32, vobc *state_proto.TrainVobcState, tcc
|
|||
|
||||
// 列车驾驶端激活
|
||||
func trainControlDriverKey(train *state_proto.TrainState, request *request_proto.TrainControl_DriverKeySwitch, deviceId uint32, tccGraphic *data_proto.TccGraphicStorage) []message.TrainPcSimBaseMessage {
|
||||
obj, find := findTrainTccGraphicDataKey(tccGraphic, deviceId)
|
||||
obj, find := FindTrainTccGraphicDataKey(tccGraphic, deviceId)
|
||||
if !find {
|
||||
slog.Error("未找到对应的驾驶端激活设备deviceId:", deviceId)
|
||||
return nil
|
||||
|
@ -433,7 +433,7 @@ func trainControlDriverKey(train *state_proto.TrainState, request *request_proto
|
|||
|
||||
}
|
||||
func trainDoorModeChangeHandle(vobc *state_proto.TrainVobcState, tcc *state_proto.TrainControlState, request *request_proto.TrainControl_SwitchKeyChange, deviceId uint32, tccGraphic *data_proto.TccGraphicStorage) []message.TrainPcSimBaseMessage {
|
||||
sk, find := findTrainTccGraphicDataKey(tccGraphic, deviceId)
|
||||
sk, find := FindTrainTccGraphicDataKey(tccGraphic, deviceId)
|
||||
if !find {
|
||||
slog.Error("未找到对应的牵引制动手柄设备deviceId:", deviceId)
|
||||
return nil
|
||||
|
@ -536,7 +536,7 @@ func trainAtoControlTractionAndBrake(train *state_proto.TrainState) {
|
|||
|
||||
// 列车牵引控制
|
||||
func trainControlHandle(train *state_proto.TrainState, request *request_proto.TrainControl_PushHandler, deviceId uint32, tccGraphic *data_proto.TccGraphicStorage) []message.TrainPcSimBaseMessage {
|
||||
_, find := findTrainTccGraphicDataHandler(tccGraphic, deviceId)
|
||||
_, find := FindTrainTccGraphicDataHandler(tccGraphic, deviceId)
|
||||
if !find {
|
||||
slog.Error("未找到对应的牵引制动手柄设备deviceId:", deviceId)
|
||||
return nil
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"joylink.club/bj-rtsts-server/third_party/interlock/beijing12"
|
||||
"joylink.club/bj-rtsts-server/third_party/radar"
|
||||
"joylink.club/bj-rtsts-server/third_party/train_pc_sim"
|
||||
trainBeijing11 "joylink.club/bj-rtsts-server/third_party/train_pc_sim/beijing11"
|
||||
"joylink.club/rtsssimulation/fi"
|
||||
"log/slog"
|
||||
"runtime"
|
||||
|
@ -172,6 +173,8 @@ func runThirdParty(s *memory.VerifySimulation) error {
|
|||
train_pc_sim.Default().Start(s)
|
||||
//btm vobc
|
||||
semi_physical_train.BtmDefault().Start(s)
|
||||
//11号线工装通信
|
||||
trainBeijing11.Start(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -207,6 +210,8 @@ func stopThirdParty(s *memory.VerifySimulation) {
|
|||
//obsolete.StopLineAllRsspAxleServices()
|
||||
// 电机UDP停止
|
||||
electrical_machinery.Default().Stop()
|
||||
//11号线工装通信
|
||||
trainBeijing11.Stop(s)
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue