Compare commits

...

2 Commits

Author SHA1 Message Date
tiger_zhou
088740408e Merge remote-tracking branch 'origin/develop' into develop 2024-05-24 09:00:53 +08:00
tiger_zhou
6b5932c617 列车pc仿真调整支持多个 2024-05-24 09:00:43 +08:00
7 changed files with 296 additions and 113 deletions

View File

@ -14,6 +14,9 @@
- viper 配置管理
- swagger 文档生成(基于[swaggo](https://github.com/swaggo/swag))(需要安装 go install github.com/swaggo/swag/cmd/swag@latest在项目根目录即 bj-rtsts-server-go执行 swag init然后启动项目即可启动后访问 http://{ip}:{port}/swagger/index.html
# 动力学
- dotnet.exe publish -r win-x64 -p:PublishSingleFile=true
# 开发说明
- 在 api 目录下添加路由及请求数据解析返回

View File

@ -72,7 +72,8 @@ type ThridPartyConfig struct {
CidcModbus []CidcModbusConfig `json:"cidcModbus" description:"联锁驱采Modbus接口配置"`
Radar RadarConfig `json:"radar" description:"车载雷达相关配置"`
Acc AccConfig `json:"acc" description:"车载加速计"`
PcSimConfig VehiclePCSimConfig `json:"pcSimConfig" description:"车载pc仿真平台通信"`
//PcSimConfig VehiclePCSimConfig `json:"pcSimConfig" description:"车载pc仿真平台通信"`
PcSimConfigs []VehiclePCSimConfig `json:"pcSimConfigs" description:"车载pc仿真平台通信"`
}
type RadarConfig struct {
Open bool `json:"open" description:"是否开启"`
@ -170,8 +171,16 @@ type RsspConfig struct {
RemoteUdpPort int `json:"remoteUdpPort" description:"远程服务器端口"` //远程服务器端口
LocalUdpPort int `json:"localUdpPort" description:"本地服务器端口"` //本地服务器端口
}
type VehiclePCSimConfig2 struct {
TrainEnds bool `json:"trainEnds" description:"列车端点A"`
Open bool `json:"open" description:"是否开启"`
PcSimIp string `json:"pcSimIp" description:"pc仿真平台通信ip"`
PcSimPort uint32 `json:"pcSimPort" description:"pc仿真平台通信端口"`
LocalTestingPort uint32 `json:"localTestingPort" description:"本地测试端口"`
}
type VehiclePCSimConfig struct {
TrainEnds bool `json:"trainEnds" description:"列车端点A?"`
Open bool `json:"open" description:"是否开启"`
PcSimIp string `json:"pcSimIp" description:"pc仿真平台通信ip"`
PcSimPort uint32 `json:"pcSimPort" description:"pc仿真平台通信端口"`

View File

@ -12,9 +12,11 @@ type TcpClient struct {
conn *net.TCPConn
handler func(n int, data []byte)
ctx context.CancelFunc
conning bool
properties map[string]interface{}
}
func StartTcpClient(rAddr string, handler func(n int, data []byte), readErr func(err error)) (*TcpClient, error) {
func StartTcpClient(rAddr string, properties map[string]interface{}, handler func(n int, data []byte, clientProperties map[string]interface{}), readErr func(err error)) (*TcpClient, error) {
raddr, addErr := net.ResolveTCPAddr("tcp", rAddr)
if addErr != nil {
return nil, addErr
@ -25,6 +27,7 @@ func StartTcpClient(rAddr string, handler func(n int, data []byte), readErr func
if err != nil {
return nil, err
}
client := &TcpClient{conn: conn, ctx: ctxFun, properties: properties}
go func() {
for {
select {
@ -37,17 +40,21 @@ func StartTcpClient(rAddr string, handler func(n int, data []byte), readErr func
if err != nil {
if opErr, ok := err.(*net.OpError); ok {
slog.Error(fmt.Sprintf("TCP客户端[rAddr:%s]读取数据异常连接可能断开:", rAddr), opErr)
client.conning = false
readErr(err)
}
if err == io.EOF {
slog.Warn(fmt.Sprintf("TCP客户端[rAddr:%s]断开连接:", rAddr))
client.conning = false
readErr(err)
}
}
handler(l, data)
client.conning = true
handler(l, data, client.properties)
}
}()
return &TcpClient{conn: conn, ctx: ctxFun}, nil
client.conning = true
return client, nil
}
func (c *TcpClient) Close() {
if c != nil && c.conn != nil {
@ -57,6 +64,12 @@ func (c *TcpClient) Close() {
c.conn = nil
}
}
func (c *TcpClient) IsConning() bool {
if c != nil && c.conn != nil {
return c.conning
}
return false
}
func (c *TcpClient) Send(data []byte) error {
if c == nil || c.conn == nil {

View File

@ -8,9 +8,7 @@ import (
"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"
)
@ -20,47 +18,57 @@ type TrainControlEvent struct {
Status byte
}
var FireTrainControlEventType = ecs.NewEventType[TrainControlEvent]()
//var FireTrainControlEventType = ecs.NewEventType[TrainControlEvent]()
type TrainPcSim interface {
tpapi.ThirdPartyApiService
Start(pcSimManage TrainPcSimManage)
Stop()
// SendDriverActive 发送驾驶端激活
SendDriverActive(tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState)
SendDriverActive(train *state_proto.TrainState)
// SendHandleSwitch 发送牵引制动手柄
SendHandleSwitch(oldTraction, oldBrakeForce int64, tractionState bool, tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState)
SendHandleSwitch(oldTraction, oldBrakeForce int64, tractionState bool, train *state_proto.TrainState)
// SendTrainDirection 列车运行方向
//因文档说明不清楚,在调用的时候目前是注释状态,现场调试可能会用到
SendTrainDirection(trainForward, trainBackward bool)
SendTrainDirection(train *state_proto.TrainState, trainForward, trainBackward bool)
//发送应答器信息数据
SendBaliseData(msgType uint16, data []byte)
SendBaliseData(train *state_proto.TrainState, msgType uint16, data []byte)
//发布列车控制的相关事件
PublishTrainControlEvent(events []TrainControlEvent)
PublishTrainControlEvent(train *state_proto.TrainState, events []TrainControlEvent)
// CreateOrRemoveSpeedPLace 创建或删除速度位置信息
CreateOrRemoveSpeedPLace(train *state_proto.TrainState)
// CreateOrRemoveTrain 创建或删除列车
CreateOrRemoveTrain(msgType byte, data []byte) error
CreateOrRemoveTrain(train *state_proto.TrainState, msgType byte, data []byte) error
}
type TrainPcSimManage interface {
GetTrainPcSimConfig() config.VehiclePCSimConfig
GetConnTrain() *state_proto.TrainState
GetTrainPcSimConfig() []config.VehiclePCSimConfig
//GetConnTrain() *state_proto.TrainState
GetConnTrain2() []*state_proto.TrainState
// TrainPcSimDigitalOutInfoHandle 4.4.1. 车载输出数字量信息报文内容
TrainPcSimDigitalOutInfoHandle(data []byte)
TrainPcSimDigitalOutInfoHandle(connType state_proto.TrainConnState_TrainConnType, data []byte)
// TrainPcSimDigitalReportHandle 4.4.2. 车载输出数字反馈量信息报文内容
TrainPcSimDigitalReportHandle(data []byte)
TrainPcSimDigitalReportHandle(connType state_proto.TrainConnState_TrainConnType, data []byte)
// TrainPcSimMockInfo 门模式
//TrainDoorModeHandle(state byte)
//处理列车pc仿真模拟量数据
TrainPcSimMockInfo(data []byte)
TrainPcSimMockInfo(connType state_proto.TrainConnState_TrainConnType, data []byte)
// TrainBtmQuery 处理列车btm查询
TrainBtmQuery(data []byte)
TrainBtmQuery(connType state_proto.TrainConnState_TrainConnType, data []byte)
}
const Name = "车载pc仿真"
const CLIENT_KEY = "clientKey"
func FindTrainPcSimClientKey(t *state_proto.TrainState) string {
if t.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_A {
return "A"
} else if t.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_B {
return "B"
}
return ""
}
func (d *trainPcSimService) Name() string {
return Name
}
@ -87,79 +95,148 @@ func Default() TrainPcSim {
type trainPcSimService struct {
state tpapi.ThirdPartyApiServiceState
pcSimClient *tcp.TcpClient
//pcSimClient *tcp.TcpClient
pcSimClientMap map[string]*tcp.TcpClient
cancleContext context.CancelFunc
trainPcSimManage TrainPcSimManage
speedPlace *message.TrainSpeedPlaceReportMsg
config config.VehiclePCSimConfig
configs []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())
func (d *trainPcSimService) closeAllConn() {
for key, client := range d.pcSimClientMap {
if client != nil {
client.Close()
}
delete(d.pcSimClientMap, key)
}
}
func (d *trainPcSimService) closeConn(clientKey string) {
if d.pcSimClientMap[clientKey] != nil {
d.pcSimClientMap[clientKey].Close()
delete(d.pcSimClientMap, clientKey)
}
}
func (d *trainPcSimService) findConfig(tcChar string) (*config.VehiclePCSimConfig, error) {
configFlag := false
if tcChar == "A" {
configFlag = true
} else if tcChar == "B" {
configFlag = false
} else {
return nil, fmt.Errorf("")
}
for _, config := range d.configs {
if config.Open && config.TrainEnds == configFlag {
return &config, nil
}
}
return nil, fmt.Errorf("")
}
func (d *trainPcSimService) connTrainPcSim(ctx context.Context) {
//reconnIndex := 0
//ctx, ctxFun := context.WithCancel(context.Background())
go func() {
for {
select {
case <-ctx.Done():
d.closeAllConn()
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)
trains := d.trainPcSimManage.GetConnTrain2()
if len(trains) > 0 {
for _, t := range trains {
clientKey := FindTrainPcSimClientKey(t)
if clientKey == "" {
slog.Error("未找到对应的pc仿真连接,trainId:", t.Id, "删除对应客户端")
d.closeConn(clientKey)
continue
}
} else {
d.pcSimClient = client
ctxFun()
return
client := d.pcSimClientMap[clientKey]
if !client.IsConning() {
client.Close()
d.initConn(clientKey)
}
}
}
time.Sleep(time.Second)
}
}()
}
func (d *trainPcSimService) initConn(clientKey string) {
client := d.pcSimClientMap[clientKey]
if d.pcSimClientMap[clientKey] == nil {
client = &tcp.TcpClient{}
d.pcSimClientMap[clientKey] = client
}
config, _ := d.findConfig(clientKey)
addr := fmt.Sprintf("%v:%v", config.PcSimIp, config.PcSimPort)
properties := map[string]interface{}{
CLIENT_KEY: clientKey,
}
fmt.Println(properties[CLIENT_KEY])
client2, err := tcp.StartTcpClient(addr, properties, d.reivceData, d.readError)
if err != nil {
d.updateState(tpapi.ThirdPartyState_Broken)
} else {
d.pcSimClientMap[clientKey] = client2
}
}
func (d *trainPcSimService) Start(pcSimManage TrainPcSimManage) {
config := pcSimManage.GetTrainPcSimConfig()
if config.PcSimIp == "" || !config.Open {
configs := pcSimManage.GetTrainPcSimConfig()
d.pcSimClientMap = map[string]*tcp.TcpClient{}
if len(configs) <= 0 {
slog.Info("车载pc仿真配置未开启")
return
}
d.config = config
d.connTrainPcSim()
allClosed := true
for _, c := range configs {
if !c.Open {
allClosed = false
}
}
if !allClosed {
slog.Info("车载pc仿真配置未开启")
return
}
d.configs = configs
ctx, ctxFun := context.WithCancel(context.Background())
d.cancleContext = ctxFun
d.trainPcSimManage = pcSimManage
d.connTrainPcSim(ctx)
//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()
}
d.closeAllConn()
}
func (d *trainPcSimService) CreateOrRemoveSpeedPLace(train *state_proto.TrainState) {
if train.ConnState.Conn {
if train.ConnState.Conn && (train.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_A || train.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_B) {
train.PluseCount = &state_proto.SensorSpeedPulseCount{}
d.speedPlace = &message.TrainSpeedPlaceReportMsg{TrainId: train.Id}
} else {
@ -167,10 +244,20 @@ func (d *trainPcSimService) CreateOrRemoveSpeedPLace(train *state_proto.TrainSta
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())
func (d *trainPcSimService) CreateOrRemoveTrain(train *state_proto.TrainState, msgType byte, data []byte) error {
clientKey := FindTrainPcSimClientKey(train)
if msgType == RECIVE_TRAIN_CREATE_REMOVE && data[0] == 0x01 {
d.initConn(clientKey)
}
msg := &message.TrainPcSimBaseMessage{Data: data, Type: uint16(msgType)}
client := d.pcSimClientMap[clientKey]
err := client.Send(msg.Encode())
if data[0] != 0x01 {
d.closeConn(clientKey)
}
return err
}
// 依据文档80ms发送列车速度位置
@ -181,36 +268,57 @@ func (d *trainPcSimService) sendTrainLocationAndSpeedTask(ctx context.Context) {
return
default:
}
train := d.trainPcSimManage.GetConnTrain()
if train != nil && train.ConnState.Conn && train.PluseCount != nil {
trains := d.trainPcSimManage.GetConnTrain2()
for _, train := range trains {
if train.ConnState.Conn && train.PluseCount != nil {
clientKey := FindTrainPcSimClientKey(train)
client := d.pcSimClientMap[clientKey]
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())
client.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 {
func (d *trainPcSimService) SendDriverActive(train *state_proto.TrainState) {
vobc := train.VobcState
clientKey := FindTrainPcSimClientKey(train)
client := d.pcSimClientMap[clientKey]
defulatBuf := make([]byte, 0)
msg := &message.TrainPcSimBaseMessage{Data: defulatBuf}
if vobc.Tc1Active || vobc.Tc2Active {
if train.TrainRunUp {
if vobc.Tc1Active {
msg.Type = SENDER_TRAIN_TC_ACTIVE
} else if vobc.Tc1Active == false && vobc.Tc2Active == false {
} else if vobc.Tc1Active == false {
msg.Type = SENDER_TRAIN_TC_NOT_ACTIVE
}
d.pcSimClient.Send(msg.Encode())
} else if !train.TrainRunUp {
if vobc.Tc2Active {
msg.Type = SENDER_TRAIN_TC_ACTIVE
} else if vobc.Tc2Active == false {
msg.Type = SENDER_TRAIN_TC_NOT_ACTIVE
}
}
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 {
client.Send(msg.Encode())
}
func (d *trainPcSimService) SendHandleSwitch(oldTraction, oldBrakeForce int64, tractionState bool, train *state_proto.TrainState) {
tc := train.ConnState
if tc.Conn {
vobc := train.VobcState
clientKey := FindTrainPcSimClientKey(train)
client := d.pcSimClientMap[clientKey]
msg := &message.TrainPcSimBaseMessage{}
newTraction := vobc.TractionForce
newBrake := -vobc.BrakeForce
@ -239,10 +347,10 @@ func (d *trainPcSimService) SendHandleSwitch(oldTraction, oldBrakeForce int64, t
msg.Type = RECIVE_TRAIN_HAND_KEY_BACKWARD
}
}
d.pcSimClient.Send(msg.Encode())
client.Send(msg.Encode())
}
}
func (d *trainPcSimService) SendTrainDirection(trainForward, trainBackward bool) {
func (d *trainPcSimService) SendTrainDirection(train *state_proto.TrainState, trainForward, trainBackward bool) {
baseMsgs := make([]*message.TrainPcSimBaseMessage, 0)
if !trainForward && !trainBackward {
@ -253,18 +361,22 @@ func (d *trainPcSimService) SendTrainDirection(trainForward, trainBackward bool)
} else if trainBackward {
baseMsgs = append(baseMsgs, &message.TrainPcSimBaseMessage{Type: RECIVE_TRAIN_HAND_KEY_BACKWARD})
}
clientKey := FindTrainPcSimClientKey(train)
client := d.pcSimClientMap[clientKey]
for _, msg := range baseMsgs {
d.pcSimClient.Send(msg.Encode())
client.Send(msg.Encode())
}
}
func (d *trainPcSimService) SendBaliseData(msgType uint16, data []byte) {
func (d *trainPcSimService) SendBaliseData(train *state_proto.TrainState, msgType uint16, data []byte) {
msg := &message.TrainPcSimBaseMessage{}
msg.Type = msgType
msg.Data = data
clientKey := FindTrainPcSimClientKey(train)
client := d.pcSimClientMap[clientKey]
//fmt.Println(fmt.Sprintf("%X", msg.Encode()))
d.pcSimClient.Send(msg.Encode())
client.Send(msg.Encode())
}
/*
@ -276,24 +388,37 @@ func (d *trainPcSimService) SendBaliseData(msgType uint16, data []byte) {
d.pcSimClient.Send(msg.Encode())
}
*/
func (d *trainPcSimService) PublishTrainControlEvent(events []TrainControlEvent) {
func (d *trainPcSimService) PublishTrainControlEvent(train *state_proto.TrainState, events []TrainControlEvent) {
if len(events) <= 0 {
slog.Warn("发布事件数量为空")
return
}
clientKey := FindTrainPcSimClientKey(train)
client := d.pcSimClientMap[clientKey]
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())
client.Send(msg.Encode())
//FireTrainControlEventType.Publish(world, &event)
}
}
// 接受来自pc仿真的消息
func (d *trainPcSimService) reivceData(len int, data []byte) {
func (d *trainPcSimService) reivceData(len int, data []byte, properties map[string]interface{}) {
clientKey := properties[CLIENT_KEY]
ck := fmt.Sprintf("%v", clientKey)
if d.pcSimClientMap[ck] == nil {
slog.Error(fmt.Sprintf("不存在%v的客户端,数据解析不予处理", ck))
return
}
connType := state_proto.TrainConnState_PC_SIM_A
if clientKey == "B" {
connType = state_proto.TrainConnState_PC_SIM_B
}
baseMsg := &message.TrainPcSimBaseMessage{}
err := baseMsg.Decode(data)
if err != nil {
@ -305,13 +430,13 @@ func (d *trainPcSimService) reivceData(len int, data []byte) {
//case RECIVE_TRAIN_CREATE_REMOVE:
// pc.trainPcSimManage.TrainPcSimConnOrRemoveHandle(baseMsg.Data[0])
case RECIVE_TRAIN_INTERFACE_CABINET_OUTR:
d.trainPcSimManage.TrainPcSimDigitalOutInfoHandle(baseMsg.Data)
d.trainPcSimManage.TrainPcSimDigitalOutInfoHandle(connType, baseMsg.Data)
case RECIVE_TRAIN_INTERFACE_CABINET_OUTR_BACK:
d.trainPcSimManage.TrainPcSimDigitalReportHandle(baseMsg.Data)
d.trainPcSimManage.TrainPcSimDigitalReportHandle(connType, baseMsg.Data)
case RECIVE_TRAIN_QUERY_STATUS:
d.trainPcSimManage.TrainBtmQuery(baseMsg.Data)
d.trainPcSimManage.TrainBtmQuery(connType, baseMsg.Data)
case RECIVE_TRAIN_MOCK_DATA:
d.trainPcSimManage.TrainPcSimMockInfo(baseMsg.Data)
d.trainPcSimManage.TrainPcSimMockInfo(connType, baseMsg.Data)
//case RECIVE_TRAIN_DOOR_MODE:
// pc.trainPcSimManage.TrainDoorModeHandle(baseMsg.Data[0])
}

View File

@ -151,8 +151,10 @@ func TrainConnTypeUpdate(vs *VerifySimulation, ct *dto.TrainConnThirdDto) {
tmpTrain := v.(*state_proto.TrainState)
if tmpTrain.ConnState.Conn {
connTypeName := "半实物"
if tmpTrain.ConnState.ConnType == state_proto.TrainConnState_PC_SIM {
connTypeName = "车载pc仿真"
if tmpTrain.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_A {
connTypeName = "车载pc仿真-A"
} else if tmpTrain.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_A {
connTypeName = "车载pc仿真-B"
}
panic(sys_error.New(fmt.Sprintf("列车[%s]已经连接 [%v],此列车无法连接", k, connTypeName)))
return false
@ -162,14 +164,14 @@ func TrainConnTypeUpdate(vs *VerifySimulation, ct *dto.TrainConnThirdDto) {
}
train.ConnState.Conn = true
train.ConnState.ConnType = ct.ConnType
if ct.ConnType == state_proto.TrainConnState_PC_SIM {
if ct.ConnType == state_proto.TrainConnState_PC_SIM_A || ct.ConnType == state_proto.TrainConnState_PC_SIM_B {
err := TrainPcSimConnOrRemoveHandle(train)
if err != nil {
train.ConnState.Conn = false
train.ConnState.ConnType = state_proto.TrainConnState_NONE
panic(sys_error.New(err.Error()))
}
train_pc_sim.Default().SendDriverActive(train.ConnState, train.VobcState)
train_pc_sim.Default().SendDriverActive(train)
}
}
@ -184,8 +186,8 @@ func TrainUnConn(vs *VerifySimulation, trainId string) {
train := data.(*state_proto.TrainState)
oldType := train.ConnState.ConnType
train.ConnState.Conn = false
train.ConnState.ConnType = state_proto.TrainConnState_NONE
if oldType == state_proto.TrainConnState_PC_SIM {
//train.ConnState.ConnType = state_proto.TrainConnState_NONE
if oldType == state_proto.TrainConnState_PC_SIM_A || oldType == state_proto.TrainConnState_PC_SIM_B {
err := TrainPcSimConnOrRemoveHandle(train)
if err != nil {
panic(sys_error.New("未连接车载PC仿真无法断开连接"))

View File

@ -494,14 +494,25 @@ func (s *VerifySimulation) CollectInterlockRelayInfo(code string) *message.Inter
}
return nil
}
// 获取列车可用连接半实物类型
func (s *VerifySimulation) FindTrainConnTypes() []dto.TrainConnTypeConfigDto {
typeConfig := make([]dto.TrainConnTypeConfigDto, 0)
if s.runConfig.Vobc.Open /*&& s.runConfig.Vobc.Ip != ""*/ {
typeConfig = append(typeConfig, dto.TrainConnTypeConfigDto{ConnType: state_proto.TrainConnState_VOBC})
}
if s.runConfig.PcSimConfig.Open /*&& s.runConfig.PcSimConfig.PcSimIp != ""*/ {
typeConfig = append(typeConfig, dto.TrainConnTypeConfigDto{ConnType: state_proto.TrainConnState_PC_SIM})
for _, pcSim := range s.runConfig.PcSimConfigs {
dto := dto.TrainConnTypeConfigDto{ConnType: state_proto.TrainConnState_PC_SIM_A}
if !pcSim.TrainEnds {
dd := &dto
dd.ConnType = state_proto.TrainConnState_PC_SIM_B
}
typeConfig = append(typeConfig, dto)
}
/* if s.runConfig.PcSimConfig.Open {
typeConfig = append(typeConfig, dto.TrainConnTypeConfigDto{ConnType: state_proto.TrainConnState_PC_SIM})
}*/
return typeConfig
}

View File

@ -18,8 +18,8 @@ import (
"time"
)
func (s *VerifySimulation) GetTrainPcSimConfig() config.VehiclePCSimConfig {
return s.runConfig.PcSimConfig
func (s *VerifySimulation) GetTrainPcSimConfig() []config.VehiclePCSimConfig {
return s.runConfig.PcSimConfigs
}
// 列车控制
@ -42,7 +42,7 @@ func ControlTrainUpdate(s *VerifySimulation, ct *request_proto.TrainControl) {
tce = trainControlEB(vobc, tcc, ct.Button, ct.DeviceId, tccGraphicData)
} else if ct.ControlType == request_proto.TrainControl_DRIVER_KEY_SWITCH {
tce = trainControlDriverKey(sta, ct.DriverKey, ct.DeviceId, tccGraphicData)
train_pc_sim.Default().SendDriverActive(sta.ConnState, sta.VobcState)
train_pc_sim.Default().SendDriverActive(sta)
} else if ct.ControlType == request_proto.TrainControl_DIRECTION_KEY_SWITCH {
tce = trainControlDirKey(sta.DynamicState.Speed, vobc, tcc, ct.DirKey, ct.DeviceId, tccGraphicData)
//此处先注释,根据现场调试情况 2024-4-16
@ -52,7 +52,7 @@ func ControlTrainUpdate(s *VerifySimulation, ct *request_proto.TrainControl) {
oldBrakeForce := sta.VobcState.BrakeForce
isTraction := ct.Handler.Val > 0 //是否制动
tce = trainControlHandle(vobc, tcc, ct.Handler, ct.DeviceId, tccGraphicData)
train_pc_sim.Default().SendHandleSwitch(oldTraction, oldBrakeForce, isTraction, sta.ConnState, sta.VobcState)
train_pc_sim.Default().SendHandleSwitch(oldTraction, oldBrakeForce, isTraction, sta)
}
if !vobc.DirectionForward && !vobc.DirectionBackward {
@ -62,8 +62,8 @@ func ControlTrainUpdate(s *VerifySimulation, ct *request_proto.TrainControl) {
if vobc.EmergencyBrakingStatus {
vobc.TractionForce = 0
}
if sta.ConnState.Conn && sta.ConnState.ConnType == state_proto.TrainConnState_PC_SIM && tce != nil {
train_pc_sim.Default().PublishTrainControlEvent(tce)
if sta.ConnState.Conn && (sta.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_A || sta.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_B) && tce != nil {
train_pc_sim.Default().PublishTrainControlEvent(sta, tce)
}
}
@ -226,8 +226,27 @@ func trainControlHandle(vobc *state_proto.TrainVobcState, tcc *state_proto.Train
return tce
}
func (s *VerifySimulation) GetConnTrain() *state_proto.TrainState {
/*func (s *VerifySimulation) GetConnTrain() *state_proto.TrainState {
return s.findConnTrain(state_proto.TrainConnState_PC_SIM)
}*/
func (s *VerifySimulation) GetConnTrain2() []*state_proto.TrainState {
return s.findConnTrain2(state_proto.TrainConnState_PC_SIM_A, state_proto.TrainConnState_PC_SIM_B)
}
func (s *VerifySimulation) findConnTrain2(ct1, ct2 state_proto.TrainConnState_TrainConnType) []*state_proto.TrainState {
var trains = make([]*state_proto.TrainState, 0)
s.Memory.Status.TrainStateMap.Range(func(k, v any) bool {
train := v.(*state_proto.TrainState)
if train.Show {
connState := train.ConnState
if connState.ConnType == ct1 || connState.ConnType == ct2 {
trains = append(trains, train)
}
}
return true
})
return trains
}
func (s *VerifySimulation) findConnTrain(ct state_proto.TrainConnState_TrainConnType) *state_proto.TrainState {
var findTrain *state_proto.TrainState
@ -244,8 +263,8 @@ func (s *VerifySimulation) findConnTrain(ct state_proto.TrainConnState_TrainConn
}
// 4.4.1. 车载输出数字量信息报文内容
func (s *VerifySimulation) TrainPcSimDigitalOutInfoHandle(data []byte) {
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
func (s *VerifySimulation) TrainPcSimDigitalOutInfoHandle(connType state_proto.TrainConnState_TrainConnType, data []byte) {
train := s.findConnTrain(connType)
if train == nil {
slog.Error("车载输出数字量未找到连接车载pc仿真的列车")
return
@ -407,8 +426,8 @@ func trainPcSimDigitalOutInfoHandleCode7_0(d byte, vobc *state_proto.TrainVobcSt
}
// 4.4.2. 车载输出数字反馈量信息报文内容
func (s *VerifySimulation) TrainPcSimDigitalReportHandle(data []byte) {
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
func (s *VerifySimulation) TrainPcSimDigitalReportHandle(connType state_proto.TrainConnState_TrainConnType, data []byte) {
train := s.findConnTrain(connType)
if train == nil {
slog.Error("车载输出数字反馈量信息,未找到连接车载pc仿真的列车")
return
@ -439,8 +458,9 @@ func TrainPcSimConnOrRemoveHandle(train *state_proto.TrainState) error {
if train.ConnState.Conn == false {
data = 0x00
}
if train.ConnState.ConnType == state_proto.TrainConnState_PC_SIM {
crErr := train_pc_sim.Default().CreateOrRemoveTrain(train_pc_sim.RECIVE_TRAIN_CREATE_REMOVE, []byte{data})
if train.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_A || train.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_B {
crErr := train_pc_sim.Default().CreateOrRemoveTrain(train, train_pc_sim.RECIVE_TRAIN_CREATE_REMOVE, []byte{data})
if crErr != nil {
return crErr
}
@ -469,8 +489,8 @@ func TrainPcSimConnOrRemoveHandle(train *state_proto.TrainState) error {
}*/
// 4.4.3. 车载输出模拟量信息报文内容(0x03)
func (s *VerifySimulation) TrainPcSimMockInfo(data []byte) {
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
func (s *VerifySimulation) TrainPcSimMockInfo(connType state_proto.TrainConnState_TrainConnType, data []byte) {
train := s.findConnTrain(connType)
if train == nil {
slog.Error("车载输出模拟量,未找到连接车载pc仿真的列车")
return
@ -484,12 +504,12 @@ func (s *VerifySimulation) TrainPcSimMockInfo(data []byte) {
}
// 4.4.4. 车载输出BTM查询同步帧报文内容0x04
func (s *VerifySimulation) TrainBtmQuery(data []byte) {
func (s *VerifySimulation) TrainBtmQuery(connType state_proto.TrainConnState_TrainConnType, data []byte) {
if len(data) < 12 {
slog.Error("列车btm查询报文长度错误:", len(data))
return
}
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
train := s.findConnTrain(connType)
if train == nil {
slog.Error("车载输出btm查询,未找到连接车载pc仿真的列车")
return
@ -511,7 +531,7 @@ func (s *VerifySimulation) TrainBtmQuery(data []byte) {
//重新发送
if len(train.BtmState.BaliseTelegramForPcSimResend) > 0 {
dd, _ := hex.DecodeString(train.BtmState.BaliseTelegramForPcSimResend)
train_pc_sim.Default().SendBaliseData(train_pc_sim.RECIVE_TRAIN_BTM_HAS_DATA, dd)
train_pc_sim.Default().SendBaliseData(train, train_pc_sim.RECIVE_TRAIN_BTM_HAS_DATA, dd)
}
} else {
timeSyncF := message.NewBtmTimeSyncCheckFrame(trainAtm.CanId.ID4, true)
@ -523,7 +543,7 @@ func (s *VerifySimulation) TrainBtmQuery(data []byte) {
queryData := make([]byte, 0)
queryData = append(queryData, btmRepFrame.Encode().Encode()...)
queryData = append(queryData, timeSyncF.Encode().Encode()...)
train_pc_sim.Default().SendBaliseData(train_pc_sim.RECIVE_TRAIN_BTM_NOT_DATA, queryData)
train_pc_sim.Default().SendBaliseData(train, train_pc_sim.RECIVE_TRAIN_BTM_NOT_DATA, queryData)
} else {
//有数据
aliseData, _ := hex.DecodeString(train.BtmState.Telegram)
@ -534,7 +554,7 @@ func (s *VerifySimulation) TrainBtmQuery(data []byte) {
queryData = append(queryData, timeSyncF.Encode().Encode()...)
queryData = append(queryData, statusDataCf...) //数据帧包含结束帧
train.BtmState.BaliseTelegramForPcSimResend = fmt.Sprintf("%X", statusDataCf)
train_pc_sim.Default().SendBaliseData(train_pc_sim.RECIVE_TRAIN_BTM_HAS_DATA, queryData)
train_pc_sim.Default().SendBaliseData(train, train_pc_sim.RECIVE_TRAIN_BTM_HAS_DATA, queryData)
} else {
slog.Error("列车pc仿真 BtmCanetClient应答帧、数据帧编码失败")
}