rts-sim-testing-service/third_party/train_pc_sim/train_pc_sim.go
2024-05-20 15:21:22 +08:00

319 lines
9.6 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 train_pc_sim
import (
"context"
"fmt"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/dto/state_proto"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/tcp"
"joylink.club/bj-rtsts-server/third_party/tpapi"
"joylink.club/ecs"
"log/slog"
"strconv"
"sync"
"time"
)
type TrainControlEvent struct {
Command byte
Status byte
}
var FireTrainControlEventType = ecs.NewEventType[TrainControlEvent]()
type TrainPcSim interface {
tpapi.ThirdPartyApiService
Start(pcSimManage TrainPcSimManage)
Stop()
// SendDriverActive 发送驾驶端激活
SendDriverActive(tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState)
// SendHandleSwitch 发送牵引制动手柄
SendHandleSwitch(oldTraction, oldBrakeForce int64, tractionState bool, tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState)
// SendTrainDirection 列车运行方向
//因文档说明不清楚,在调用的时候目前是注释状态,现场调试可能会用到
SendTrainDirection(trainForward, trainBackward bool)
//发送应答器信息数据
SendBaliseData(msgType uint16, data []byte)
//发布列车控制的相关事件
PublishTrainControlEvent(events []TrainControlEvent)
// CreateOrRemoveSpeedPLace 创建或删除速度位置信息
CreateOrRemoveSpeedPLace(train *state_proto.TrainState)
// CreateOrRemoveTrain 创建或删除列车
CreateOrRemoveTrain(msgType byte, data []byte) error
}
type TrainPcSimManage interface {
GetTrainPcSimConfig() config.VehiclePCSimConfig
GetConnTrain() *state_proto.TrainState
// TrainPcSimDigitalOutInfoHandle 4.4.1. 车载输出数字量信息报文内容
TrainPcSimDigitalOutInfoHandle(data []byte)
// TrainPcSimDigitalReportHandle 4.4.2. 车载输出数字反馈量信息报文内容
TrainPcSimDigitalReportHandle(data []byte)
// TrainPcSimMockInfo 门模式
//TrainDoorModeHandle(state byte)
//处理列车pc仿真模拟量数据
TrainPcSimMockInfo(data []byte)
// TrainBtmQuery 处理列车btm查询
TrainBtmQuery(data []byte)
}
const Name = "车载pc仿真"
func (d *trainPcSimService) Name() string {
return Name
}
func (d *trainPcSimService) State() tpapi.ThirdPartyApiServiceState {
return d.state
}
func (d *trainPcSimService) updateState(state tpapi.ThirdPartyApiServiceState) {
d.state = state
}
var (
initLock = &sync.Mutex{}
singleObj *trainPcSimService
)
func Default() TrainPcSim {
defer initLock.Unlock()
initLock.Lock()
if singleObj == nil {
singleObj = &trainPcSimService{}
}
return singleObj
}
type trainPcSimService struct {
state tpapi.ThirdPartyApiServiceState
pcSimClient *tcp.TcpClient
cancleContext context.CancelFunc
trainPcSimManage TrainPcSimManage
speedPlace *message.TrainSpeedPlaceReportMsg
config config.VehiclePCSimConfig
}
// 接受来自pc仿真的消息
func (d *trainPcSimService) readError(err error) {
slog.Error("连接车载pc仿真tcp服务断开", err)
d.updateState(tpapi.ThirdPartyState_Broken)
d.pcSimClient.Close()
d.connTrainPcSim()
}
func (d *trainPcSimService) connTrainPcSim() {
reconnIndex := 0
ctx, ctxFun := context.WithCancel(context.Background())
go func() {
for {
select {
case <-ctx.Done():
return
default:
}
d.pcSimClient.Close()
client, err := tcp.StartTcpClient(fmt.Sprintf("%v:%v", d.config.PcSimIp, d.config.PcSimPort), d.reivceData, d.readError)
if err != nil {
reconnIndex++
d.updateState(tpapi.ThirdPartyState_Broken)
if reconnIndex%10 == 0 {
slog.Error("连接车载pc平台失败尝试=", strconv.Itoa(reconnIndex), err)
}
} else {
d.pcSimClient = client
ctxFun()
return
}
time.Sleep(time.Second)
}
}()
}
func (d *trainPcSimService) Start(pcSimManage TrainPcSimManage) {
config := pcSimManage.GetTrainPcSimConfig()
if config.PcSimIp == "" || !config.Open {
slog.Info("车载pc仿真配置未开启")
return
}
d.config = config
d.connTrainPcSim()
ctx, ctxFun := context.WithCancel(context.Background())
d.cancleContext = ctxFun
d.trainPcSimManage = pcSimManage
//FireTrainControlEventType.Subscribe(wd, d.trainControlEventHandle)
d.updateState(tpapi.ThirdPartyState_Normal)
go d.sendTrainLocationAndSpeedTask(ctx)
}
func (d *trainPcSimService) Stop() {
d.updateState(tpapi.ThirdPartyState_Closed)
if d.cancleContext != nil {
d.cancleContext()
d.cancleContext = nil
}
if d.pcSimClient != nil {
//d.pcSimClient.
d.pcSimClient.Close()
}
}
func (d *trainPcSimService) CreateOrRemoveSpeedPLace(train *state_proto.TrainState) {
if train.ConnState.Conn {
train.PluseCount = &state_proto.SensorSpeedPulseCount{}
d.speedPlace = &message.TrainSpeedPlaceReportMsg{TrainId: train.Id}
} else {
train.PluseCount = nil
d.speedPlace = nil
}
}
func (d *trainPcSimService) CreateOrRemoveTrain(msgType byte, data []byte) error {
msg := &message.TrainPcSimBaseMessage{Data: data, Type: uint16(msgType)}
return d.pcSimClient.Send(msg.Encode())
}
// 依据文档80ms发送列车速度位置
func (d *trainPcSimService) sendTrainLocationAndSpeedTask(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
}
train := d.trainPcSimManage.GetConnTrain()
if train != nil && train.ConnState.Conn && train.PluseCount != nil {
s1, s2 := train.PluseCount.PulseCount1, train.PluseCount.PulseCount2
d.speedPlace.ParsePulseCount1(s1, s2)
data := d.speedPlace.Encode(train.TrainRunUp, s1, s2)
bm := &message.TrainPcSimBaseMessage{Type: SENDER_TRAIN_LOCATION_INFO, Data: data}
train.PluseCount.PulseCount1 = 0
train.PluseCount.PulseCount2 = 0
d.pcSimClient.Send(bm.Encode())
}
time.Sleep(time.Millisecond * 80)
}
}
// 发送驾驶激活
func (d *trainPcSimService) SendDriverActive(tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState) {
if tc.Conn && tc.ConnType == state_proto.TrainConnState_PC_SIM {
defulatBuf := make([]byte, 0)
msg := &message.TrainPcSimBaseMessage{Data: defulatBuf}
if vobc.Tc1Active || vobc.Tc2Active {
msg.Type = SENDER_TRAIN_TC_ACTIVE
} else if vobc.Tc1Active == false && vobc.Tc2Active == false {
msg.Type = SENDER_TRAIN_TC_NOT_ACTIVE
}
d.pcSimClient.Send(msg.Encode())
}
}
func (d *trainPcSimService) SendHandleSwitch(oldTraction, oldBrakeForce int64, tractionState bool, tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState) {
if tc.Conn && tc.ConnType == state_proto.TrainConnState_PC_SIM {
msg := &message.TrainPcSimBaseMessage{}
newTraction := vobc.TractionForce
newBrake := -vobc.BrakeForce
newOldBrakeForce := -oldBrakeForce
if tractionState {
if newTraction <= oldTraction && newTraction == 0 {
//手柄取消前进
msg.Type = RECIVE_TRAIN_HAND_KEY_CANCLE_FORWARD
} else if newTraction > oldTraction {
//手柄前进
msg.Type = SENDER_TRAIN_HAND_KEY_FORWARD
} else {
//手柄前进
msg.Type = SENDER_TRAIN_HAND_KEY_FORWARD
}
} else {
if newBrake >= newOldBrakeForce && newBrake == 0 {
//手柄取消后退
msg.Type = RECIVE_TRAIN_HAND_KEY_CACLE_BACKWARD
} else if newBrake < newOldBrakeForce {
//手柄后退
msg.Type = RECIVE_TRAIN_HAND_KEY_BACKWARD
} else {
//手柄后退
msg.Type = RECIVE_TRAIN_HAND_KEY_BACKWARD
}
}
d.pcSimClient.Send(msg.Encode())
}
}
func (d *trainPcSimService) SendTrainDirection(trainForward, trainBackward bool) {
baseMsgs := make([]*message.TrainPcSimBaseMessage, 0)
if !trainForward && !trainBackward {
baseMsgs = append(baseMsgs, &message.TrainPcSimBaseMessage{Type: RECIVE_TRAIN_HAND_KEY_CANCLE_FORWARD})
baseMsgs = append(baseMsgs, &message.TrainPcSimBaseMessage{Type: RECIVE_TRAIN_HAND_KEY_CACLE_BACKWARD})
} else if trainForward {
baseMsgs = append(baseMsgs, &message.TrainPcSimBaseMessage{Type: SENDER_TRAIN_HAND_KEY_FORWARD})
} else if trainBackward {
baseMsgs = append(baseMsgs, &message.TrainPcSimBaseMessage{Type: RECIVE_TRAIN_HAND_KEY_BACKWARD})
}
for _, msg := range baseMsgs {
d.pcSimClient.Send(msg.Encode())
}
}
func (d *trainPcSimService) SendBaliseData(msgType uint16, data []byte) {
msg := &message.TrainPcSimBaseMessage{}
msg.Type = msgType
msg.Data = data
//fmt.Println(fmt.Sprintf("%X", msg.Encode()))
d.pcSimClient.Send(msg.Encode())
}
/*
func (d *trainPcSimService) trainControlEventHandle( event TrainControlEvent) {
msg := &message.TrainPcSimBaseMessage{}
msg.Type = SENDER_TRAIN_OUTR_INFO
data := []byte{event.Command, event.Status}
msg.Data = data
d.pcSimClient.Send(msg.Encode())
}
*/
func (d *trainPcSimService) PublishTrainControlEvent(events []TrainControlEvent) {
if len(events) <= 0 {
slog.Warn("发布事件数量为空")
return
}
for _, event := range events {
msg := &message.TrainPcSimBaseMessage{}
msg.Type = SENDER_TRAIN_OUTR_INFO
data := []byte{event.Command, event.Status}
msg.Data = data
d.pcSimClient.Send(msg.Encode())
//FireTrainControlEventType.Publish(world, &event)
}
}
// 接受来自pc仿真的消息
func (d *trainPcSimService) reivceData(len int, data []byte) {
baseMsg := &message.TrainPcSimBaseMessage{}
err := baseMsg.Decode(data)
if err != nil {
slog.Error("车载pc仿真接受数据解析失败 ")
return
}
switch baseMsg.Type {
//case RECIVE_TRAIN_CREATE_REMOVE:
// pc.trainPcSimManage.TrainPcSimConnOrRemoveHandle(baseMsg.Data[0])
case RECIVE_TRAIN_INTERFACE_CABINET_OUTR:
d.trainPcSimManage.TrainPcSimDigitalOutInfoHandle(baseMsg.Data)
case RECIVE_TRAIN_INTERFACE_CABINET_OUTR_BACK:
d.trainPcSimManage.TrainPcSimDigitalReportHandle(baseMsg.Data)
case RECIVE_TRAIN_QUERY_STATUS:
d.trainPcSimManage.TrainBtmQuery(baseMsg.Data)
case RECIVE_TRAIN_MOCK_DATA:
d.trainPcSimManage.TrainPcSimMockInfo(baseMsg.Data)
//case RECIVE_TRAIN_DOOR_MODE:
// pc.trainPcSimManage.TrainDoorModeHandle(baseMsg.Data[0])
}
}