Compare commits

...

5 Commits

Author SHA1 Message Date
tiger_zhou
39f01066ad Merge remote-tracking branch 'origin/local-test' into local-test
Some checks failed
local-test分支打包构建docker并发布运行 / Docker-Build (push) Failing after 3m10s
2024-04-28 11:01:40 +08:00
tiger_zhou
4901c00199 仿真测试调试 2024-04-28 11:01:12 +08:00
tiger_zhou
20f9ac94c9 列车pc仿真调整 2024-04-19 16:55:51 +08:00
tiger_zhou
a13a01f99f 列车pc仿真调整 2024-04-18 11:18:26 +08:00
tiger_zhou
4666c84860 列车pc仿真调整 2024-04-18 11:14:05 +08:00
24 changed files with 833 additions and 276 deletions

View File

@ -61,17 +61,18 @@ type mqtt struct {
// 第三方配置结构 // 第三方配置结构
type ThridPartyConfig struct { type ThridPartyConfig struct {
Id int32 `json:"id"` Id int32 `json:"id"`
Dynamics DynamicsConfig `json:"dynamics" description:"动力学配置"` Dynamics DynamicsConfig `json:"dynamics" description:"动力学配置"`
Vobc VobcConfig `json:"vobc" description:"半实物配置"` Vobc VobcConfig `json:"vobc" description:"半实物配置"`
Interlocks []InterlockConfig `json:"interlock" description:"联锁配置"` Interlocks []InterlockConfig `json:"interlock" description:"联锁配置"`
RsspAxleCfgs []RsspAxleConfig `json:"rsspAxleCfgs" description:"所有联锁集中站计轴RSSP-I配置"` RsspAxleCfgs []RsspAxleConfig `json:"rsspAxleCfgs" description:"所有联锁集中站计轴RSSP-I配置"`
ElectricMachinery ElectricMachineryConfig `json:"electricMachinery" description:"电机配置"` //ElectricMachinery ElectricMachineryConfig `json:"electricMachinery" description:"电机配置"`
BtmCanet BtmCanetConfig `json:"btmCanet" description:"BTM关联的网关设备CANET配置"` ElectricMachinerys []ElectricMachineryConfig `json:"electricMachinerys" description:"电机配置"`
CidcModbus []CidcModbusConfig `json:"cidcModbus" description:"联锁驱采Modbus接口配置"` BtmCanet BtmCanetConfig `json:"btmCanet" description:"BTM关联的网关设备CANET配置"`
Radar RadarConfig `json:"radar" description:"车载雷达相关配置"` CidcModbus []CidcModbusConfig `json:"cidcModbus" description:"联锁驱采Modbus接口配置"`
Acc AccConfig `json:"acc" description:"车载加速计"` Radar RadarConfig `json:"radar" description:"车载雷达相关配置"`
PcSimConfig VehiclePCSimConfig `json:"pcSimConfig" description:"车载pc仿真平台通信"` Acc AccConfig `json:"acc" description:"车载加速计"`
PcSimConfig VehiclePCSimConfig `json:"pcSimConfig" description:"车载pc仿真平台通信"`
} }
type RadarConfig struct { type RadarConfig struct {
Open bool `json:"open" description:"是否开启"` Open bool `json:"open" description:"是否开启"`
@ -128,6 +129,7 @@ type ElectricMachineryConfig struct {
Ip string `json:"ip" description:"IP配置"` Ip string `json:"ip" description:"IP配置"`
RemotePort int `json:"remotePort" description:"远端接收信息端口"` RemotePort int `json:"remotePort" description:"远端接收信息端口"`
Open bool `json:"open" description:"是否开启"` Open bool `json:"open" description:"是否开启"`
EndPointA bool `json:"endPointA" description:"一号电机"`
} }
// BtmCanetConfig BTM CANET网关设备配置 // BtmCanetConfig BTM CANET网关设备配置

View File

@ -250,6 +250,10 @@ type TrainEndsState struct {
AccOutSpeed int32 `protobuf:"varint,9,opt,name=accOutSpeed,proto3" json:"accOutSpeed,omitempty"` AccOutSpeed int32 `protobuf:"varint,9,opt,name=accOutSpeed,proto3" json:"accOutSpeed,omitempty"`
// 雷达速度输出(米/秒) // 雷达速度输出(米/秒)
RadarOutSpeed int32 `protobuf:"varint,10,opt,name=radarOutSpeed,proto3" json:"radarOutSpeed,omitempty"` RadarOutSpeed int32 `protobuf:"varint,10,opt,name=radarOutSpeed,proto3" json:"radarOutSpeed,omitempty"`
// 记录雷达设置检测时间的时间点,用于计算周期内的数字
RadarCheckTimeOverAt int64 `protobuf:"varint,11,opt,name=radarCheckTimeOverAt,proto3" json:"radarCheckTimeOverAt,omitempty"`
// 记录加速度计设置检测时间的时间点,用于计算周期内的数字
AccCheckTimeOverAt int64 `protobuf:"varint,12,opt,name=accCheckTimeOverAt,proto3" json:"accCheckTimeOverAt,omitempty"`
} }
func (x *TrainEndsState) Reset() { func (x *TrainEndsState) Reset() {
@ -354,6 +358,20 @@ func (x *TrainEndsState) GetRadarOutSpeed() int32 {
return 0 return 0
} }
func (x *TrainEndsState) GetRadarCheckTimeOverAt() int64 {
if x != nil {
return x.RadarCheckTimeOverAt
}
return 0
}
func (x *TrainEndsState) GetAccCheckTimeOverAt() int64 {
if x != nil {
return x.AccCheckTimeOverAt
}
return 0
}
var File_common_data_proto protoreflect.FileDescriptor var File_common_data_proto protoreflect.FileDescriptor
var file_common_data_proto_rawDesc = []byte{ var file_common_data_proto_rawDesc = []byte{
@ -398,7 +416,7 @@ var file_common_data_proto_rawDesc = []byte{
0x73, 0x74, 0x6f, 0x70, 0x53, 0x69, 0x67, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x6c, 0x69, 0x64, 0x73, 0x74, 0x6f, 0x70, 0x53, 0x69, 0x67, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x6c, 0x69, 0x64,
0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x12, 0x1c, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x12, 0x1c,
0x0a, 0x09, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x4c, 0x6f, 0x61, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x4c, 0x6f, 0x61, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28,
0x05, 0x52, 0x09, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x4c, 0x6f, 0x61, 0x64, 0x22, 0xa4, 0x03, 0x0a, 0x05, 0x52, 0x09, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x4c, 0x6f, 0x61, 0x64, 0x22, 0x88, 0x04, 0x0a,
0x0e, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x45, 0x6e, 0x64, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x45, 0x6e, 0x64, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12,
0x2e, 0x0a, 0x12, 0x73, 0x70, 0x65, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x45, 0x6e, 0x2e, 0x0a, 0x12, 0x73, 0x70, 0x65, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x45, 0x6e,
0x61, 0x62, 0x6c, 0x65, 0x41, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x73, 0x70, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x73, 0x70, 0x65,
@ -425,10 +443,16 @@ var file_common_data_proto_rawDesc = []byte{
0x52, 0x0b, 0x61, 0x63, 0x63, 0x4f, 0x75, 0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x4f, 0x75, 0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x24, 0x0a,
0x0d, 0x72, 0x61, 0x64, 0x61, 0x72, 0x4f, 0x75, 0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x18, 0x0a, 0x0d, 0x72, 0x61, 0x64, 0x61, 0x72, 0x4f, 0x75, 0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x18, 0x0a,
0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x72, 0x61, 0x64, 0x61, 0x72, 0x4f, 0x75, 0x74, 0x53, 0x70, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x72, 0x61, 0x64, 0x61, 0x72, 0x4f, 0x75, 0x74, 0x53, 0x70,
0x65, 0x65, 0x64, 0x42, 0x2f, 0x5a, 0x2d, 0x6a, 0x6f, 0x79, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x63, 0x65, 0x65, 0x64, 0x12, 0x32, 0x0a, 0x14, 0x72, 0x61, 0x64, 0x61, 0x72, 0x43, 0x68, 0x65, 0x63,
0x6c, 0x75, 0x62, 0x2f, 0x62, 0x6a, 0x2d, 0x72, 0x74, 0x73, 0x74, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x41, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28,
0x76, 0x65, 0x72, 0x2f, 0x64, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x70, 0x03, 0x52, 0x14, 0x72, 0x61, 0x64, 0x61, 0x72, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x69, 0x6d,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x41, 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x61, 0x63, 0x63, 0x43, 0x68,
0x65, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x41, 0x74, 0x18, 0x0c, 0x20,
0x01, 0x28, 0x03, 0x52, 0x12, 0x61, 0x63, 0x63, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x69, 0x6d,
0x65, 0x4f, 0x76, 0x65, 0x72, 0x41, 0x74, 0x42, 0x2f, 0x5a, 0x2d, 0x6a, 0x6f, 0x79, 0x6c, 0x69,
0x6e, 0x6b, 0x2e, 0x63, 0x6c, 0x75, 0x62, 0x2f, 0x62, 0x6a, 0x2d, 0x72, 0x74, 0x73, 0x74, 0x73,
0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x64, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@ -99,14 +99,15 @@ type ConfigTrainEnds struct {
SpeedSensorEnableA bool `json:"speedSensorEnableA"` // 2端速度传感器是否有效 SpeedSensorEnableA bool `json:"speedSensorEnableA"` // 2端速度传感器是否有效
SpeedSensorEnableB bool `json:"speedSensorEnableB"` // 2端速度传感器是否有效 SpeedSensorEnableB bool `json:"speedSensorEnableB"` // 2端速度传感器是否有效
RadarEnable bool `json:"radarEnable"` // 雷达是否有效 RadarEnable bool `json:"radarEnable"` // 雷达是否有效
RadarCheckSpeedDiff float32 `json:"radarCheckSpeedDiff"` // 雷达测速数值 RadarCheckSpeedDiff float32 `json:"radarCheckSpeedDiff"` // 雷达测速数值(千米/小时)
RadarCheckTime int32 `json:"radarCheckTime"` // 雷达检测时间(秒) RadarCheckTime int32 `json:"radarCheckTime"` // 雷达检测时间(秒)
AccEnable bool `json:"accEnable"` // 加速计是否有效 AccEnable bool `json:"accEnable"` // 加速计是否有效
AccCheckSpeedDiff float32 `json:"accCheckSpeedDiff"` // 加速计速度差 AccCheckSpeedDiff float32 `json:"accCheckSpeedDiff"` // 加速计速度差
AccCheckTime int32 `json:"accCheckTime"` // 加速计储蓄时间 AccCheckTime int32 `json:"accCheckTime"` // 加速计储蓄时间
AccOutSpeed int32 `json:"accOutSpeed"` // 速传速度输出 AccOutSpeed int32 `json:"accOutSpeed"` // 速传速度输出(千米/小时)
RadarOutSpeed int32 `json:"radarOutSpeed"` // 雷达速度输出 RadarOutSpeed int32 `json:"radarOutSpeed"` // 雷达速度输出(千米/小时)
} }
type ConfigTrainData struct { type ConfigTrainData struct {
//Mass int32 `json:"mass" form:"mass"` // 列车的质量100=1ton //Mass int32 `json:"mass" form:"mass"` // 列车的质量100=1ton

View File

@ -1537,7 +1537,7 @@ func (x *TrainDynamicState) GetDisplacement() int32 {
return 0 return 0
} }
// vobc发过来的列车信息 // vobc发过来的列车信息 包括 (驾驶台和车载)
type TrainVobcState struct { type TrainVobcState struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache

View File

@ -511,9 +511,11 @@ func convertTrainState(v *state_proto.TrainState) *state_proto.TrainMapState {
convertDynamicConfig(v.TrainDynamicConfig, t.TrainDynamicConfig) convertDynamicConfig(v.TrainDynamicConfig, t.TrainDynamicConfig)
convertDynamicConfig(v.TrainEndsA, t.TrainEndsA) convertDynamicConfig(v.TrainEndsA, t.TrainEndsA)
convertDynamicConfig(v.TrainEndsB, t.TrainEndsB) convertDynamicConfig(v.TrainEndsB, t.TrainEndsB)
//now := time.Now().Unix()
return t return t
} }
func convertDynamicConfig(config, dest interface{}) { func convertDynamicConfig(config, dest interface{}) {
configType := reflect.TypeOf(config).Elem() configType := reflect.TypeOf(config).Elem()
for index := 0; index < configType.NumField(); index++ { for index := 0; index < configType.NumField(); index++ {

@ -1 +1 @@
Subproject commit acbfbf8b92d3702a9c0e6434f26fd6db2f57292d Subproject commit 121134778a38df672562fd8d1acb1482a327702f

View File

@ -11,7 +11,7 @@ import (
func TestAccUdp(t *testing.T) { func TestAccUdp(t *testing.T) {
fmt.Println("准备启动ACC服务...") fmt.Println("准备启动ACC服务...")
addr := fmt.Sprintf("%v:%v", "127.0.0.1", "8899") addr := fmt.Sprintf("%v:%v", "127.0.0.1", "9998")
server := udp.NewServer(addr, handle) server := udp.NewServer(addr, handle)
server.Listen() server.Listen()
select {} select {}
@ -23,6 +23,6 @@ func handle(d []byte) {
if err == nil { if err == nil {
jsonD, _ := json.Marshal(ri) jsonD, _ := json.Marshal(ri)
fmt.Println(string(jsonD)) fmt.Println("接受数据:", string(jsonD))
} }
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"joylink.club/bj-rtsts-server/config" "joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/dto/common_proto"
"joylink.club/bj-rtsts-server/dto/state_proto" "joylink.club/bj-rtsts-server/dto/state_proto"
"joylink.club/bj-rtsts-server/third_party/message" "joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp" "joylink.club/bj-rtsts-server/third_party/udp"
@ -15,6 +16,8 @@ import (
type AccVobc interface { type AccVobc interface {
Start(accManager AccVobcManager) Start(accManager AccVobcManager)
Stop() Stop()
SendAcc(acc *message.Accelerometer)
TrainAccSender(info *message.DynamicsTrainInfo, trainState *state_proto.TrainState)
} }
type AccVobcManager interface { type AccVobcManager interface {
@ -27,10 +30,10 @@ var (
singleObj *accVobcService singleObj *accVobcService
) )
const ( /*const (
accInterval = 15 accInterval = 15
accSpeedUnit = 9.8 accSpeedUnit = 9.8
) )*/
func Default() AccVobc { func Default() AccVobc {
defer initLock.Unlock() defer initLock.Unlock()
@ -52,13 +55,46 @@ func (acc *accVobcService) Start(accManager AccVobcManager) {
if config.RemoteIp == "" || config.RemotePort <= 0 || !config.Open { if config.RemoteIp == "" || config.RemotePort <= 0 || !config.Open {
} }
acc.vobcClient = udp.NewClient(fmt.Sprintf("%v:%v", config.RemoteIp, config.RemotePort)) acc.vobcClient = udp.NewClient(fmt.Sprintf("%v:%v", config.RemoteIp, config.RemotePort))
ctx, cancleFunc := context.WithCancel(context.Background())
acc.controlContext = cancleFunc
acc.radarVobcManager = accManager acc.radarVobcManager = accManager
go acc.sendTask(ctx)
} }
func (acc *accVobcService) sendTask(ctx context.Context) { func (avs *accVobcService) SendAcc(acc *message.Accelerometer) {
avs.vobcClient.Send(acc.Encode())
}
func (avs *accVobcService) TrainAccSender(info *message.DynamicsTrainInfo, trainState *state_proto.TrainState) {
if trainState.VobcState.Tc1Active && trainState.TrainEndsA.AccEnable {
s := parseAccSpeedData(info.Acceleration, trainState.TrainEndsA)
avs.SendAcc(&message.Accelerometer{Acc: s})
} else if trainState.VobcState.Tc2Active && trainState.TrainEndsB.AccEnable {
s := parseAccSpeedData(info.Acceleration, trainState.TrainEndsB)
avs.SendAcc(&message.Accelerometer{Acc: s})
} else {
avs.SendAcc(&message.Accelerometer{Acc: 0})
}
}
func parseAccSpeedData(accSpeed float32, trainEndState *common_proto.TrainEndsState) float32 {
//如果差值速度和速度输出都填写,那么就以速度输出为优先
//如果动力学速度-差值速度小于0呢么输出的就是0不能小于0
trainEndState.AccCheckTime = int32(trainEndState.AccCheckTimeOverAt - time.Now().Unix())
if trainEndState.AccCheckTime <= 0 {
//判断雷达检测时间是否到期
trainEndState.AccCheckTime = 0
if trainEndState.AccCheckTimeOverAt != 0 {
trainEndState.AccCheckSpeedDiff = 0
return accSpeed
}
}
if trainEndState.AccCheckSpeedDiff > 0 {
//如果雷达检测速度差值填写,那么就以速度差值为主
return float32(math.Abs(float64(accSpeed - trainEndState.AccCheckSpeedDiff)))
} else {
return accSpeed
}
}
/*func (acc *accVobcService) sendTask(ctx context.Context) {
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
@ -74,7 +110,7 @@ func (acc *accVobcService) sendTask(ctx context.Context) {
} }
time.Sleep(time.Millisecond * accInterval) time.Sleep(time.Millisecond * accInterval)
} }
} }*/
func (acc *accVobcService) Stop() { func (acc *accVobcService) Stop() {
if acc.controlContext != nil { if acc.controlContext != nil {

View File

@ -209,6 +209,7 @@ func (d *dynamics) TrainOperationConfig(req *message.TrainOperationConfig) error
return nil return nil
} }
data, _ := json.Marshal(req) data, _ := json.Marshal(req)
//fmt.Println(string(data))
url := d.buildUrl("/api/config/") url := d.buildUrl("/api/config/")
resp, err := d.httpClient.Post(url, "application/json", bytes.NewBuffer(data)) resp, err := d.httpClient.Post(url, "application/json", bytes.NewBuffer(data))
if err != nil { if err != nil {

View File

@ -2,6 +2,8 @@ package electrical_machinery
import ( import (
"fmt" "fmt"
"joylink.club/bj-rtsts-server/dto/common_proto"
"joylink.club/bj-rtsts-server/dto/state_proto"
"sync" "sync"
"joylink.club/bj-rtsts-server/config" "joylink.club/bj-rtsts-server/config"
@ -9,22 +11,30 @@ import (
"joylink.club/bj-rtsts-server/third_party/udp" "joylink.club/bj-rtsts-server/third_party/udp"
) )
const (
PointA = iota + 1
PointB
)
// 电机转速UDP // 电机转速UDP
type ElectricMachinery interface { type ElectricMachinery interface {
Start(manager ElectricMachineryMessageManager) // 启动电机转速UDP消息处理 Start(manager ElectricMachineryMessageManager) // 启动电机转速UDP消息处理
Stop() // 停止电机转速消息处理 Stop() // 停止电机转速消息处理
SendElectricMachineryMessage(info *message.ElectricMachinery) // 发送电机转速消息 SendElectricMachineryMessage(emMap map[int]*message.ElectricMachinery) // 发送电机转速消息
SendElectricMachineryMessage2(info *message.DynamicsTrainInfo, trainState *state_proto.TrainState) // 发送电机转速消息
} }
type ElectricMachineryMessageManager interface { type ElectricMachineryMessageManager interface {
GetElectricMachineryRunConfig() *config.ElectricMachineryConfig // 获取电机转速参数 GetElectricMachineryRunConfig() []config.ElectricMachineryConfig // 获取电机转速参数
} }
type electricalMachineryImpl struct { type electricalMachineryImpl struct {
electricalMachineryUdpClient udp.UdpClient //electricalMachineryUdpClient udp.UdpClient
manager ElectricMachineryMessageManager electricalMachineryUdpClientMap map[int]udp.UdpClient
runConfig *config.ElectricMachineryConfig manager ElectricMachineryMessageManager
runConfig []config.ElectricMachineryConfig
} }
func (s *electricalMachineryImpl) Start(manager ElectricMachineryMessageManager) { func (s *electricalMachineryImpl) Start(manager ElectricMachineryMessageManager) {
@ -35,7 +45,13 @@ func (s *electricalMachineryImpl) Start(manager ElectricMachineryMessageManager)
panic("启动电机转速消息服务错误: 存在正在运行的任务") panic("启动电机转速消息服务错误: 存在正在运行的任务")
} }
s.runConfig = manager.GetElectricMachineryRunConfig() s.runConfig = manager.GetElectricMachineryRunConfig()
if s.runConfig == nil || s.runConfig.Ip == "" || !s.runConfig.Open { allNotOpen := true
for _, c := range s.runConfig {
if &c == nil || c.Ip == "" || !c.Open {
allNotOpen = false
}
}
if allNotOpen {
return return
} }
// 初始化客户端、服务端 // 初始化客户端、服务端
@ -47,21 +63,81 @@ func (s *electricalMachineryImpl) Stop() {
initMutex.Lock() initMutex.Lock()
defer initMutex.Unlock() defer initMutex.Unlock()
_default = nil _default = nil
if s.electricalMachineryUdpClient != nil { //if s.electricalMachineryUdpClient != nil {
s.electricalMachineryUdpClient.Close() // s.electricalMachineryUdpClient.Close()
//}
for _, c := range s.electricalMachineryUdpClientMap {
if &c != nil {
c.Close()
}
} }
s.manager = nil s.manager = nil
} }
func (s *electricalMachineryImpl) SendElectricMachineryMessage(info *message.ElectricMachinery) { func (s *electricalMachineryImpl) SendElectricMachineryMessage(emMap map[int]*message.ElectricMachinery) {
if s.electricalMachineryUdpClient == nil { for key, em := range emMap {
return client := s.electricalMachineryUdpClientMap[key]
if client != nil {
err := client.Send(em.Encode())
if err != nil {
fmt.Println(err)
}
}
} }
s.electricalMachineryUdpClient.Send(info.Encode()) }
func (s *electricalMachineryImpl) SendElectricMachineryMessage2(info *message.DynamicsTrainInfo, trainState *state_proto.TrainState) {
collectSpeedMap := initEMMsg(trainState)
if trainState.VobcState.Tc1Active {
collectSpeed(info.HeadSpeed1, info.HeadSpeed2, trainState.TrainEndsA, collectSpeedMap)
} else if trainState.VobcState.Tc2Active {
collectSpeed(info.TailSpeed1, info.TailSpeed2, trainState.TrainEndsB, collectSpeedMap)
}
// 更新电机转速
s.SendElectricMachineryMessage(collectSpeedMap)
}
func collectSpeed(speed1, speed2 float32, endP *common_proto.TrainEndsState, resultMap map[int]*message.ElectricMachinery) {
pa := resultMap[PointA]
pb := resultMap[PointB]
if endP.SpeedSensorEnableA || endP.SpeedSensorEnableB {
if endP.AccOutSpeed > 0 {
pa.Speed = float32(endP.AccOutSpeed) / 3.6
pb.Speed = float32(endP.AccOutSpeed) / 3.6
} else {
if endP.SpeedSensorEnableA {
pa.Speed = speed1
}
if endP.SpeedSensorEnableB {
pb.Speed = speed2
}
}
}
}
func initEMMsg(trainState *state_proto.TrainState) map[int]*message.ElectricMachinery {
collectSpeedMap := map[int]*message.ElectricMachinery{
PointA: {
Speed: 0,
WheelDiameter: trainState.WheelDiameter,
IsBack: trainState.VobcState.DirectionBackward},
PointB: {Speed: 0,
WheelDiameter: trainState.WheelDiameter,
IsBack: trainState.VobcState.DirectionBackward},
}
return collectSpeedMap
} }
func (s *electricalMachineryImpl) initElectricalMachinery() { func (s *electricalMachineryImpl) initElectricalMachinery() {
s.electricalMachineryUdpClient = udp.NewClient(fmt.Sprintf("%v:%v", s.runConfig.Ip, s.runConfig.RemotePort)) for _, c := range s.runConfig {
if &c != nil && c.Ip != "" && c.Open {
ep := PointA
if !c.EndPointA {
ep = PointB
}
s.electricalMachineryUdpClientMap[ep] = udp.NewClient(fmt.Sprintf("%v:%v", c.Ip, c.RemotePort))
}
}
} }
var _default ElectricMachinery var _default ElectricMachinery

View File

@ -0,0 +1,25 @@
package electrical_machinery
import (
"fmt"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp"
"testing"
"time"
)
func TestServer(t *testing.T) {
udpServer := udp.NewServer(fmt.Sprintf("127.0.0.1:%d", 9999), handleCanetFrames)
udpServer.Listen()
select {}
}
func handleCanetFrames(d []byte) {
msg := &message.ElectricMachinery{}
msg.Decode(d)
}
func TestOther(t *testing.T) {
dd := 1714024680 - time.Now().Unix()
fmt.Println(dd)
fmt.Println(int32(dd))
}

View File

@ -1,9 +1,8 @@
package message package message
import ( import (
"bytes"
"encoding/binary"
"fmt" "fmt"
"math"
) )
const ( const (
@ -12,18 +11,33 @@ const (
) )
type Accelerometer struct { type Accelerometer struct {
Acc uint32 Acc float32
Aux byte
} }
const (
FullScaleG = 0x80000000 // 1g的Q31表示
DataMask = 0xC0 // 最高2位是数据位
ReadingMask = 0xFFFFC000 // 屏蔽标志位和编码位
)
func (acc *Accelerometer) Encode() []byte { func (acc *Accelerometer) Encode() []byte {
accData := uint32(math.Round(float64(acc.Acc) * float64(FullScaleG)))
d2 := byte(accData >> 16)
d1 := byte(accData >> 8)
D0 := byte(accData) & 0xFF
D0 |= byte((accData >> 18) & DataMask)
data := make([]byte, 0) data := make([]byte, 0)
data = append(data, accHeader) data = append(data, accHeader)
data = append(data, uaidDefault) data = append(data, uaidDefault)
acc.Acc = acc.Acc | 0x0000FF data = append(data, D0)
data = binary.LittleEndian.AppendUint32(data, acc.Acc) data = append(data, d1)
data = append(data, d2)
data = append(data, acc.Aux)
cs := checkSum(data) cs := checkSum(data)
data = append(data, ^cs+1) data = append(data, ^cs+1)
return data return data
} }
func checkSum(data []byte) byte { func checkSum(data []byte) byte {
@ -34,16 +48,16 @@ func checkSum(data []byte) byte {
return sum return sum
} }
func (acc *Accelerometer) Decode(data []byte) error { func (acc *Accelerometer) Decode(Packet []byte) error {
if len(data) < 7 { if len(Packet) < 7 {
return fmt.Errorf("") return fmt.Errorf("")
} }
buf := bytes.NewBuffer(data) data := uint32(Packet[4])<<16 | uint32(Packet[3])<<8 | uint32(Packet[2])
_, _ = buf.ReadByte() // 应用屏蔽以移除标志位和编码位
_, _ = buf.ReadByte() data &= ReadingMask
var dataInt uint32 = 0 // 将Q31值转换为float32加速度值g
binary.Read(buf, binary.LittleEndian, &dataInt) acceleration := float32(float32(data) * (1.0 / float32(FullScaleG)))
//newData := math.Float32frombits(dataInt & 0xffffc000)
acc.Acc = dataInt & 0xffffc000 fmt.Println(acceleration)
return nil return nil
} }

View File

@ -2,16 +2,17 @@ package message
import "log/slog" import "log/slog"
//BTM与ATP之间为双向通信ATP定时发送请求帧BTM在未接收到应答器报文时回复状态应答器帧和时间同步帧在接收到应答器报文时回复所有帧 // CreateBtmRspFramesData BTM与ATP之间为双向通信ATP定时发送请求帧BTM在未接收到应答器报文时回复状态应答器帧和时间同步帧在接收到应答器报文时回复所有帧
//
// CreateBtmRspFramesData 数据帧与状态应答帧同时发送给ATP // 数据帧与状态应答帧同时发送给ATP
//
// 共17帧17X12个字节每个帧12字节 // 共17帧17X12个字节每个帧12字节
// msg - 应答器报文 // msg - 应答器报文
// msgPackError - true BTM解包发生错误则数据帧及CRC32A/B全填“0xFF” // msgPackError - true BTM解包发生错误则数据帧及CRC32A/B全填“0xFF”
func CreateBtmRspFramesData(statusRsp *BtmStatusRspFrame, msg []byte, msgPackError bool, msgTimeA uint32, msgTimeB uint32, tkTimeB uint32, isTrainPcSim bool) ([]byte, bool) { func CreateBtmRspFramesData(statusRsp *BtmStatusRspFrame, msg []byte, msgPackError bool, msgTimeA uint32, msgTimeB uint32, tkTimeB uint32, isTrainPcSim bool) ([]byte, bool) {
if len(msg) > 104 { //数据帧最多存储13*8个字节 /* if len(msg) > 104 { //数据帧最多存储13*8个字节
return nil, false return nil, false
} }*/
//最近一次ATP查询请求序列号 //最近一次ATP查询请求序列号
sn := statusRsp.FId.ID4 sn := statusRsp.FId.ID4
//13个BtmDataMessageFrame [0x00,0x0c] //13个BtmDataMessageFrame [0x00,0x0c]
@ -93,6 +94,101 @@ func CreateBtmRspFramesData(statusRsp *BtmStatusRspFrame, msg []byte, msgPackErr
rt = append(rt, dtACf.Encode()...) rt = append(rt, dtACf.Encode()...)
rt = append(rt, dtBCf.Encode()...) rt = append(rt, dtBCf.Encode()...)
rt = append(rt, endCf.Encode()...) rt = append(rt, endCf.Encode()...)
if isTrainPcSim && len(rt) != 221 {
} else if len(rt) != 221 {
slog.Warn("len(rt)!=221")
return nil, false
}
return rt, true
}
func CreateBtmRspFramesDataForPcSim(statusRsp *BtmStatusRspFrame, msg []byte, msgPackError bool, msgTimeA uint32, msgTimeB uint32, tkTimeB uint32, isTrainPcSim bool) ([]byte, bool) {
if len(msg) > 128 { //数据帧最多存储13*8个字节
return nil, false
}
//最近一次ATP查询请求序列号
sn := statusRsp.FId.ID4
//13个BtmDataMessageFrame [0x00,0x0c]
//数据
dms := make([]*BtmDataMessageFrame, 14)
for mr := 0x00; mr <= 0x0E; mr++ {
dms[mr] = NewBtmDataMessageFrame(sn, byte(mr), isTrainPcSim)
dms[mr].Message = make([]byte, 8) //8字节数组默认值0
//
if !msgPackError {
mi := mr * 8
if mi < len(msg) { //数据帧中有<=8个字节数据
if mi+7 < len(msg) {
dms[mr].Message = msg[mi : mi+8]
} else {
for i, d := range msg[mi:] {
dms[mr].Message[i] = d
}
}
}
} else { //BTM解包发生错误则数据帧及CRC32A/B全填“0xFF”
for c := 0; c < 8; c++ {
dms[mr].Message[c] = 0xff
}
}
}
//
dtA := NewBtmDataMessageTimeAFrame(sn, isTrainPcSim)
//dtA.TimeA = msgTimeA
//if !msgPackError {
// var crc32AData []byte
// crc32AData = append(crc32AData, msg...)
// crc32AData = append(crc32AData, canTimeToBytes(dtA.TimeA)...)
// dtA.Crc32A = Can_Crc32(crc32AData) //CRC32A的校验范围是报文+时间戳A
//} else { //BTM解包发生错误则数据帧及CRC32A/B全填“0xFF”
// dtA.Crc32A = 0xff_ff_ff_ff
//}
//
dtB := NewBtmDataMessageTimeBFrame(sn, isTrainPcSim)
dtB.TimeB = msgTimeB
if !msgPackError {
var crc32BData []byte
crc32BData = append(crc32BData, msg...)
crc32BData = append(crc32BData, canTimeToBytes(dtB.TimeB)...)
dtB.Crc32B = Can_Crc32(crc32BData) //CRC32B的校验范围是报文+时间戳B
} else { //BTM解包发生错误则数据帧及CRC32A/B全填“0xFF”
dtB.Crc32B = 0xff_ff_ff_ff
}
//
end := NewBtmDataMessageEndFrame(sn, isTrainPcSim)
end.TkB = tkTimeB
//
statusCf := statusRsp.Encode()
dmsCfs := make([]*CanetFrame, 0, 13)
for _, dm := range dms {
dmsCfs = append(dmsCfs, dm.Encode())
}
dtACf := dtA.Encode()
dtBCf := dtB.Encode()
//
crc32cData := make([]byte, 0, 132)
crc32cData = append(crc32cData, statusCf.CanData...)
for _, dmCf := range dmsCfs {
crc32cData = append(crc32cData, dmCf.CanData...)
}
crc32cData = append(crc32cData, dtACf.CanData...)
crc32cData = append(crc32cData, dtBCf.CanData...)
crc32cData = append(crc32cData, canTimeToBytes(end.TkB)...)
//
end.Crc32C = Can_Crc32(crc32cData)
//
endCf := end.Encode()
//
rt := make([]byte, 0, 221) //17*13
rt = append(rt, statusCf.Encode()...)
for _, dmCf := range dmsCfs {
rt = append(rt, dmCf.Encode()...)
}
rt = append(rt, dtACf.Encode()...)
rt = append(rt, dtBCf.Encode()...)
rt = append(rt, endCf.Encode()...)
if len(rt) != 221 { if len(rt) != 221 {
slog.Warn("len(rt)!=221") slog.Warn("len(rt)!=221")
return nil, false return nil, false

View File

@ -49,16 +49,17 @@ func (p *CanetFrame) Encode() []byte {
} }
func (p *CanetFrame) Decode(buf []byte) { func (p *CanetFrame) Decode(buf []byte) {
if len(buf) != 13 {
panic("len(buf)!=13")
}
// //
if !p.IsTrainPcSim { if !p.IsTrainPcSim {
if len(buf) != 13 {
panic("len(buf)!=13")
}
p.FF = buf[0]&0x80 == 0x80 p.FF = buf[0]&0x80 == 0x80
p.RTR = buf[0]&0x40 == 0x40 p.RTR = buf[0]&0x40 == 0x40
p.CanLen = buf[0] & 0x0f
} }
p.CanLen = buf[0] & 0x0f
//1 2 3 4 //1 2 3 4
p.CanId.ID1 = buf[1] p.CanId.ID1 = buf[1]
p.CanId.ID2 = buf[2] p.CanId.ID2 = buf[2]

View File

@ -2,11 +2,12 @@ package message
import ( import (
"encoding/binary" "encoding/binary"
"fmt"
"math" "math"
) )
// 速度转转速计算公式: // 速度转转速计算公式:
// 转速=车速 ÷ 车轮周长 // 转速=车速(米/秒) ÷ 车轮周长(米)
// 车的轮径为d车速为v1电机转速为v2 // 车的轮径为d车速为v1电机转速为v2
// 公式为V2=V1÷πd×60 // 公式为V2=V1÷πd×60
type ElectricMachinery struct { type ElectricMachinery struct {
@ -17,16 +18,34 @@ type ElectricMachinery struct {
func (t *ElectricMachinery) Encode() []byte { func (t *ElectricMachinery) Encode() []byte {
b := []byte{0x01, 0x10, 0x60, 0xff, 0x00, 0x02, 0x04} b := []byte{0x01, 0x10, 0x60, 0xff, 0x00, 0x02, 0x04}
//hx := fmt.Sprintf("%X", b)
rotarySpeed := t.Speed * 60 / (float32(math.Pi) * float32(t.WheelDiameter) / 1000) rotarySpeed := t.Speed * 60 / (float32(math.Pi) * float32(t.WheelDiameter) / 1000)
//rotarySpeed := t.Speed / (float32(math.Pi) * float32(t.WheelDiameter) / 1000) * 60
var rotarySpeedData uint32
if t.IsBack { if t.IsBack {
b = binary.BigEndian.AppendUint32(b, uint32(0-rotarySpeed)) //b = binary.BigEndian.AppendUint32(b, uint32(0-rotarySpeed))
rotarySpeedData = uint32(0 - rotarySpeed)
} else { } else {
b = binary.BigEndian.AppendUint32(b, uint32(rotarySpeed)) //b = binary.BigEndian.AppendUint32(b, uint32(rotarySpeed))
rotarySpeedData = uint32(rotarySpeed)
} }
b = binary.BigEndian.AppendUint32(b, rotarySpeedData)
crc := chkcrc(b) // crc校验码 crc := chkcrc(b) // crc校验码
b = binary.BigEndian.AppendUint16(b, crc) b = binary.BigEndian.AppendUint16(b, crc)
//fmt.Println("发送:", hx, rotarySpeedData, crc)
return b return b
} }
func (t *ElectricMachinery) Decode(d []byte) error {
if len(d) != 13 {
return fmt.Errorf("")
}
h := d[:7]
data := binary.BigEndian.Uint32(d[7:11])
crc := binary.BigEndian.Uint16(d[11:13])
hx := fmt.Sprintf("%X", h)
fmt.Println("接收", hx, data, crc)
return nil
}
// 生成crc // 生成crc
func chkcrc(data []byte) uint16 { func chkcrc(data []byte) uint16 {

View File

@ -4,8 +4,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"strings" "math"
"sync/atomic"
) )
const ( const (
@ -13,7 +12,11 @@ const (
radar_head2 byte = 0xFC radar_head2 byte = 0xFC
) )
var autoInc = atomic.Int32{} var autoInc byte = 0
var (
fixed_speed = 0.009155
driftDefaultVal = 0.1
)
// 雷达与VOBC接口-雷达通讯协议 // 雷达与VOBC接口-雷达通讯协议
type RadarInfo struct { type RadarInfo struct {
@ -27,49 +30,65 @@ type RadarInfo struct {
Tail byte Tail byte
} }
func NewRadarSender(speed float32, forward bool, displacement uint16) *RadarInfo {
state := &RadarState{SwModel1: 1, SwModel0: 1, calculateBit: 1, signalQualityBit: 1, BlackoutBit: 0, DirectionState: 1, Direction: IsTrue(forward)}
ri := &RadarInfo{State: state}
ri.RealSpeed = uint16(math.Abs(float64(speed*3.6) / fixed_speed))
disMeter := float64(displacement / 100)
disMeterKM := float64(disMeter / 100)
if disMeter > 9999 {
ri.DriftCounterS1 = 9999
} else {
ri.DriftCounterS1 = uint16(disMeter)
}
if disMeterKM > 9999 {
ri.DriftCounterS2 = 9999
} else {
ri.DriftCounterS2 = uint16(disMeterKM)
}
return ri
}
type RadarState struct { type RadarState struct {
SourceState byte //原数据 SwModel1 byte
Model string // 天线模式 SwModel0 byte
SyntheticalState string //综合状态 calculateBit byte //计算状态位
DirState string //方向状态 signalQualityBit byte //信号质量标志位
Dir byte //方向 BlackoutBit byte //Blackout标志位
innerBit byte //内部使用
DirectionState byte //方向状态 1行驶方向有效 0行驶方向无效
Direction byte //行驶方向 1前向 0反向
}
func (r *RadarState) Encode() byte {
var state byte
state = setBit(state, 7, r.SwModel1)
state = setBit(state, 6, r.SwModel0)
state = setBit(state, 5, r.calculateBit)
state = setBit(state, 4, r.signalQualityBit)
state = setBit(state, 3, r.BlackoutBit)
state = setBit(state, 1, r.DirectionState)
state = setBit(state, 0, r.Direction)
return state
} }
func (r RadarInfo) Encode() []byte { func (r RadarInfo) Encode() []byte {
buf := make([]byte, 0) buf := make([]byte, 0)
buf = append(buf, radar_head1) buf = append(buf, radar_head1)
buf = append(buf, radar_head2) buf = append(buf, radar_head2)
if tmp := autoInc.Add(1); tmp >= 256 { autoInc = autoInc + 1
autoInc.Store(0) buf = append(buf, autoInc)
buf = append(buf, 0)
} else {
buf = append(buf, byte(tmp))
}
buf = binary.LittleEndian.AppendUint16(buf, r.RealSpeed) buf = binary.LittleEndian.AppendUint16(buf, r.RealSpeed)
buf = binary.LittleEndian.AppendUint16(buf, r.DriftCounterS1) buf = binary.LittleEndian.AppendUint16(buf, r.DriftCounterS1)
buf = binary.LittleEndian.AppendUint16(buf, r.DriftCounterS2) buf = binary.LittleEndian.AppendUint16(buf, r.DriftCounterS2)
//buf = append(buf, byte(r.RealSpeed>>8))
//buf = append(buf, byte(r.RealSpeed&0x00FF))
//buf = append(buf, byte(r.DriftCounterS1>>8))
//buf = append(buf, byte(r.DriftCounterS1&0x00FF))
//buf = append(buf, byte(r.DriftCounterS2>>8))
//buf = append(buf, byte(r.DriftCounterS2&0x00FF))
buf = append(buf, 0) buf = append(buf, 0)
buf = append(buf, 0) buf = append(buf, 0)
//6,7位 11
//3,4,5位 011 buf = append(buf, r.State.Encode())
// 1位 1
//0位 1
var state byte
state = setBit(state, 7, 1)
state = setBit(state, 6, 1)
state = setBit(state, 5, 1)
state = setBit(state, 4, 1)
state = setBit(state, 3, 0)
state = setBit(state, 1, 0)
state = setBit(state, 0, byte(r.State.Dir))
buf = append(buf, state)
var sum = 0 var sum = 0
for _, d := range buf { for _, d := range buf {
sum += int(d) sum += int(d)
@ -105,58 +124,19 @@ func (r *RadarInfo) Decode(data []byte) error {
if !(r.Tail == r.createTail()) { if !(r.Tail == r.createTail()) {
return fmt.Errorf("数据解析完成,但协议效验不通过") return fmt.Errorf("数据解析完成,但协议效验不通过")
} }
state.parseState()
return nil return nil
} }
func (s *RadarState) parseState() { func (s *RadarState) Decode(d byte) {
//第7位 == SW_Mode0, 第6位 == SW_Mode1 s.SwModel1 = GetBit(d, 7)
// 11:两个天线和双通道都OK s.SwModel0 = GetBit(d, 6)
// 10DRS05_Single-Mode 40度,50度的天线或通道故障 s.calculateBit = GetBit(d, 5)
// 01DRS05_Single-Mode 50度,40度的天线或通道故障 s.signalQualityBit = GetBit(d, 4)
// 00错误模式 双侧天线或通道都故障 s.BlackoutBit = GetBit(d, 3)
// 模式的工作差别工作在11.模式时效果最好。单模式10或01时可信度下降。 s.DirectionState = GetBit(d, 1)
arr := s.getBitsStateArr() s.Direction = GetBit(d, 0)
s.Model = bitStateStr(arr[6:])
// 第5位=计算状态位,第4位=信号质量标志位,第3位=Black5out标志位
// 110计算状态高质量
// 地面信号反射良好,高精度的信号计算
// 100 计算状态,低质量
// 地面信号反射一般,信号计算可能会有缺陷
// 001 处于Blackout 状态
// 车辆行驶时无地面反射信号,无法进行信号计算
// 000 信号搜寻状态
// 在整个频率范围内搜寻多普勒信号,此时的速度和位移信息无效,当频率搜寻正确后,会转为计算模式。
s.SyntheticalState = bitStateStr(arr[3:6])
// 第1位 =方向状态
// 1行驶方向有效
// 0行驶方向无效
s.DirState = bitStateStr(arr[1:2])
// 第0位 =行驶方向
// 1前向
// 0反向
s.Dir = arr[0:1][0]
} }
func (s *RadarState) getBitsStateArr() [8]byte {
//bits := make([]byte, 8)
var bits2 [8]byte = [8]byte{}
for i := 0; i < 8; i++ {
bit := s.SourceState >> uint(i) & 1
bits2[i] = bit
}
return bits2
}
func bitStateStr(data []byte) string {
var build = strings.Builder{}
for i := len(data) - 1; i >= 0; i-- {
build.WriteString(fmt.Sprintf("%v", data[i]))
}
/*for _, d := range data {
build.WriteString(fmt.Sprintf("%v", d))
}*/
return build.String()
}
func culDataSize(d uint16) int { func culDataSize(d uint16) int {
return int(d>>8) + int(d&0x00FF) return int(d>>8) + int(d&0x00FF)
} }
@ -169,7 +149,7 @@ func (r *RadarInfo) createTail() byte {
sum += culDataSize(r.DriftCounterS2) sum += culDataSize(r.DriftCounterS2)
sum += int(r.InnerCheck1) sum += int(r.InnerCheck1)
sum += int(r.InnerCheck2) sum += int(r.InnerCheck2)
sum += int(r.State.SourceState) sum += int(r.State.Encode())
return byte(^sum + 1) return byte(^sum + 1)
} }
@ -213,7 +193,9 @@ func readRadarState(buf *bytes.Buffer) *RadarState {
return nil, fmt.Errorf("") return nil, fmt.Errorf("")
}*/ }*/
state, _ := buf.ReadByte() state, _ := buf.ReadByte()
return &RadarState{SourceState: state} s := &RadarState{}
s.Decode(state)
return s
} }
func driftCounter(buf *bytes.Buffer) (uint16, error) { func driftCounter(buf *bytes.Buffer) (uint16, error) {

View File

@ -28,7 +28,6 @@ func (tp *TrainPcSimBaseMessage) Encode() []byte {
binary.Write(dataBufs, binary.BigEndian, tp.Data) binary.Write(dataBufs, binary.BigEndian, tp.Data)
data := dataBufs.Bytes() data := dataBufs.Bytes()
pack = append(pack, data...) pack = append(pack, data...)
pack = binary.BigEndian.AppendUint16(pack, uint16(crc.CalculateCRC(crc.CRC16, data))) pack = binary.BigEndian.AppendUint16(pack, uint16(crc.CalculateCRC(crc.CRC16, data)))
return pack return pack
} }
@ -109,6 +108,24 @@ func (tp *TrainSpeedPlaceReportMsg) Encode(runDir bool, s1, s2 uint32) []byte {
return data return data
} }
func (tp *TrainSpeedPlaceReportMsg) Decode(d []byte) {
buf := bytes.NewBuffer(d)
var runDir uint16
binary.Read(buf, binary.BigEndian, &runDir)
var s1 uint32
binary.Read(buf, binary.BigEndian, &s1)
var s2 uint32
binary.Read(buf, binary.BigEndian, &s2)
var c1 uint32
binary.Read(buf, binary.BigEndian, &c1)
var c2 uint32
binary.Read(buf, binary.BigEndian, &c2)
var ts uint32
binary.Read(buf, binary.BigEndian, &ts)
fmt.Println(runDir, s1, s2, c1, c2, ts)
}
// 轨旁向列车pc仿真发送的命令码 // 轨旁向列车pc仿真发送的命令码
const ( const (
//钥匙开关状态 //钥匙开关状态

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"joylink.club/bj-rtsts-server/config" "joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/dto/common_proto"
"joylink.club/bj-rtsts-server/dto/state_proto" "joylink.club/bj-rtsts-server/dto/state_proto"
"joylink.club/bj-rtsts-server/third_party/message" "joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp" "joylink.club/bj-rtsts-server/third_party/udp"
@ -16,11 +17,13 @@ import (
type RadarVobc interface { type RadarVobc interface {
Start(radar RadarVobcManager) Start(radar RadarVobcManager)
Stop() Stop()
SendMsg(ri *message.RadarInfo)
TrainSpeedSender(info *message.DynamicsTrainInfo, trainState *state_proto.TrainState)
} }
type RadarVobcManager interface { type RadarVobcManager interface {
GetRunRadarConfig() config.RadarConfig GetRunRadarConfig() config.RadarConfig
FindRadarTrain() *state_proto.TrainState //FindRadarTrain() *state_proto.TrainState
} }
const radar_interval = 15 const radar_interval = 15
@ -55,45 +58,90 @@ func (rv *radarVobc) Start(radar RadarVobcManager) {
} }
rv.vobcClient = udp.NewClient(fmt.Sprintf("%v:%v", config.RemoteIp, config.RemotePort)) rv.vobcClient = udp.NewClient(fmt.Sprintf("%v:%v", config.RemoteIp, config.RemotePort))
ctx, cancleFunc := context.WithCancel(context.Background()) //ctx, cancleFunc := context.WithCancel(context.Background())
rv.radarVobcTaskContext = cancleFunc //rv.radarVobcTaskContext = cancleFunc
rv.radarVobcManager = radar rv.radarVobcManager = radar
go rv.sendRadarInfo(ctx) //go rv.sendRadarInfo(ctx)
} }
// sendRadarInfo 发送速度,位移计数 给vobc // sendRadarInfo 发送速度,位移计数 给vobc
func (rv *radarVobc) sendRadarInfo(ctx context.Context) { func (rv *radarVobc) SendMsg(ri *message.RadarInfo) {
/*defer func() { rv.vobcClient.Send(ri.Encode())
slog.Error("") }
}()*/ func (rv *radarVobc) TrainSpeedSender(info *message.DynamicsTrainInfo, trainState *state_proto.TrainState) {
for { forward := trainState.VobcState.DirectionForward
select { if trainState.VobcState.Tc1Active && trainState.TrainEndsA.RadarEnable {
case <-ctx.Done(): s := parseRadarSpeedData(info.Speed, trainState.TrainEndsA)
return rv.SendMsg(message.NewRadarSender(s, forward, info.Displacement))
default: } else if trainState.VobcState.Tc2Active && trainState.TrainEndsB.RadarEnable {
} s := parseRadarSpeedData(info.Speed, trainState.TrainEndsB)
trainStatus := rv.radarVobcManager.FindRadarTrain() rv.SendMsg(message.NewRadarSender(s, forward, info.Displacement))
if trainStatus != nil { } else {
hourSpeed := float64(trainStatus.DynamicState.Speed / 100) rv.SendMsg(message.NewRadarSender(0, forward, 0))
trainDift := trainStatus.DynamicState.Displacement //slog.Error("列车行驶方向不确定或两端的雷达均未启用,发送雷达数据0", "列车前进=", trainState.VobcState.DirectionForward, "雷达启用A=", trainState.TrainEndsA.RadarEnable, "列车后退=", trainState.VobcState.DirectionBackward, "雷达启用B=", trainState.TrainEndsB.RadarEnable)
td := float64(trainDift / 1000) }
s1 := uint16(math.Round(td / driftDefaultVal)) }
s2 := uint16(math.Round(td / 1000 / driftDefaultVal))
ri := message.RadarInfo{RealSpeed: uint16(math.Round(hourSpeed / fixed_speed)), DriftCounterS1: s1, DriftCounterS2: s2} func parseRadarSpeedData(radarSpeed float32, trainEndState *common_proto.TrainEndsState) float32 {
ri.State = &message.RadarState{Dir: message.IsTrue(trainStatus.RunDirection)} //如果差值速度和速度输出都填写,那么就以速度输出为优先
rv.vobcClient.SendMsg(ri) //如果动力学速度-差值速度小于0呢么输出的就是0不能小于0
trainEndState.RadarCheckTime = int32(trainEndState.RadarCheckTimeOverAt - time.Now().Unix())
if trainEndState.RadarCheckTime <= 0 {
trainEndState.RadarCheckTime = 0
if trainEndState.RadarCheckTimeOverAt != 0 {
trainEndState.RadarCheckSpeedDiff = 0
trainEndState.RadarOutSpeed = 0
return radarSpeed
} }
time.Sleep(time.Millisecond * radar_interval)
} }
if trainEndState.RadarCheckSpeedDiff > 0 && trainEndState.RadarOutSpeed > 0 {
//如果雷达检测速度差值和速度输出都填写,那么就以速度输出为优先
return float32(trainEndState.RadarOutSpeed)
} else if trainEndState.RadarCheckSpeedDiff > 0 {
//如果雷达检测速度差值填写,那么就以速度差值为主
return float32(math.Abs(float64(radarSpeed - (trainEndState.RadarCheckSpeedDiff / 3.6))))
} else if trainEndState.RadarOutSpeed > 0 {
//如果雷达速度输出填写,那么就以速度输出为主
return float32(trainEndState.RadarOutSpeed) / 3.6
} else {
return radarSpeed
}
} }
// sendRadarInfo 发送速度,位移计数 给vobc
/*
func (rv *radarVobc) sendRadarInfo(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
}
trainStatus := rv.radarVobcManager.FindRadarTrain()
if trainStatus != nil {
hourSpeed := float64(trainStatus.DynamicState.Speed / 100)
trainDift := trainStatus.DynamicState.Displacement
td := float64(trainDift / 1000)
s1 := uint16(math.Round(td / driftDefaultVal))
s2 := uint16(math.Round(td / 1000 / driftDefaultVal))
ri := message.RadarInfo{RealSpeed: uint16(math.Round(hourSpeed / fixed_speed)), DriftCounterS1: s1, DriftCounterS2: s2}
ri.State = &message.RadarState{Dir: message.IsTrue(trainStatus.RunDirection)}
rv.vobcClient.SendMsg(ri)
}
time.Sleep(time.Millisecond * radar_interval)
}
}
*/
func (rv *radarVobc) Stop() { func (rv *radarVobc) Stop() {
if rv.radarVobcTaskContext != nil { /* if rv.radarVobcTaskContext != nil {
rv.radarVobcTaskContext() rv.radarVobcTaskContext()
rv.radarVobcTaskContext = nil rv.radarVobcTaskContext = nil
} }*/
if rv.vobcClient != nil { if rv.vobcClient != nil {
rv.vobcClient.Close() rv.vobcClient.Close()
rv.vobcClient = nil rv.vobcClient = nil

View File

@ -41,7 +41,7 @@ func StartTcpClient(rAddr string, handler func(n int, data []byte), readErr func
} }
if err == io.EOF { if err == io.EOF {
slog.Warn(fmt.Sprintf("TCP客户端[rAddr:%s]断开连接:", rAddr)) slog.Warn(fmt.Sprintf("TCP客户端[rAddr:%s]断开连接:", rAddr))
break readErr(err)
} }
} }
handler(l, data) handler(l, data)
@ -57,15 +57,16 @@ func (c *TcpClient) Close() {
c.conn = nil c.conn = nil
} }
} }
func (c *TcpClient) Send(data []byte) { func (c *TcpClient) Send(data []byte) error {
if c.conn == nil {
if c == nil || c.conn == nil {
slog.Error("tcp client send error,conn is nil") slog.Error("tcp client send error,conn is nil")
return return fmt.Errorf("TCP未连接车载PC仿真")
} }
_, err := c.conn.Write(data) _, err := c.conn.Write(data)
if err != nil { if err != nil {
slog.Error("tcp client send error", "error", err) slog.Error("tcp client send error", "error", err)
return err
} }
return nil
} }

View File

@ -1,12 +1,14 @@
package main package main
import ( import (
"encoding/binary"
"fmt" "fmt"
"io" "io"
"joylink.club/bj-rtsts-server/third_party/message" "joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/train_pc_sim" "joylink.club/bj-rtsts-server/third_party/train_pc_sim"
"log/slog" "log/slog"
"net" "net"
"strconv"
) )
type TcpConnHandler = func(conn net.Conn) type TcpConnHandler = func(conn net.Conn)
@ -33,14 +35,14 @@ func tcpRunAcceptTask(listen net.Listener, port int, connHandler TcpConnHandler,
func tcpRunReadTask(conn net.Conn, port int, msgHandler TcpMsgHandler) { func tcpRunReadTask(conn net.Conn, port int, msgHandler TcpMsgHandler) {
go func() { go func() {
defer func() { /* defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
slog.Error(fmt.Sprintf("TCP服务端[port:%d]读数据任务异常:", port), err) slog.Error(fmt.Sprintf("TCP服务端[port:%d]读数据任务异常:", port), err)
serConn.Close() serConn.Close()
serConn = nil serConn = nil
} }
}() }()*/
for { for {
data := make([]byte, 1024) data := make([]byte, 1024)
l, err := conn.Read(data) l, err := conn.Read(data)
@ -87,6 +89,72 @@ func changeDoorMode() *message.TrainPcSimBaseMessage {
return msg return msg
} }
func boolsToByte(flags [8]bool) byte {
var result uint8
for index, b := range flags {
if b {
result = result + (1 << index)
}
}
return result
}
func pcSimInfoOut() *message.TrainPcSimBaseMessage {
msg := &message.TrainPcSimBaseMessage{}
msg.Type = train_pc_sim.RECIVE_TRAIN_INTERFACE_CABINET_OUTR
data := make([]byte, 0)
data = append(data, boolsToByte([8]bool{false, false, false, false, false, false, false, false}))
data = append(data, boolsToByte([8]bool{false, false, false, false, false, false, false, false}))
data = append(data, boolsToByte([8]bool{false, false, false, false, false, false, false, false}))
data = append(data, boolsToByte([8]bool{false, false, false, false, false, false, false, false}))
data = append(data, boolsToByte([8]bool{true, false, false, false, false, false, false, false}))
msg.Data = data
return msg
}
func pcSimInfoOutReport() *message.TrainPcSimBaseMessage {
msg := &message.TrainPcSimBaseMessage{}
msg.Type = train_pc_sim.RECIVE_TRAIN_INTERFACE_CABINET_OUTR_BACK
data := make([]byte, 0)
data = append(data, boolsToByte([8]bool{true, true, false, false, false, false, false, false}))
msg.Data = data
return msg
}
var autoIncNo = 0
func queryBtm() *message.TrainPcSimBaseMessage {
msg := &message.TrainPcSimBaseMessage{}
msg.Type = train_pc_sim.RECIVE_TRAIN_QUERY_STATUS
autoIncNo = autoIncNo + 1
data := make([]byte, 0)
data = append(data, 0x62)
data = append(data, 0x81)
data = append(data, 0x02)
data = append(data, byte(autoIncNo)<<3)
data = append(data, boolsToByte([8]bool{true, true, false, false, false, false, false, false}))
data = append(data, 0) //速度低位
data = append(data, 0) //当前时间高位
data = append(data, 0) //当前时间
data = append(data, 0) //当前时间
data = append(data, 0) //当前时间低位
data = append(data, 0) //当前时间低位
data = append(data, 0) //CRC16-H(MSB
data = append(data, 0) //CRC16-L(LSB)
msg.Data = data
return msg
}
func pcSimNumReportOut() *message.TrainPcSimBaseMessage {
msg := &message.TrainPcSimBaseMessage{}
msg.Type = train_pc_sim.RECIVE_TRAIN_MOCK_DATA
sd := uint16(1234)
data := make([]byte, 2)
binary.BigEndian.PutUint16(data, sd)
msg.Data = data
return msg
}
// 测试创建连接 // 测试创建连接
/*func TestConn(t *testing.T) { /*func TestConn(t *testing.T) {
createServer(func(n int, data []byte) { createServer(func(n int, data []byte) {
@ -99,16 +167,68 @@ func main() {
createServer(func(n int, data []byte) { createServer(func(n int, data []byte) {
msg := &message.TrainPcSimBaseMessage{} msg := &message.TrainPcSimBaseMessage{}
msg.Decode(data) d := data[:n]
msg.Decode(d)
pd := fmt.Sprintf("%X", d)
if msg.Type == train_pc_sim.SENDER_TRAIN_TC_ACTIVE { if msg.Type == train_pc_sim.SENDER_TRAIN_TC_ACTIVE {
fmt.Println("接收驾驶端激活") fmt.Println("接收驾驶端激活")
fmt.Println(pd)
} else if msg.Type == train_pc_sim.SENDER_TRAIN_TC_NOT_ACTIVE { } else if msg.Type == train_pc_sim.SENDER_TRAIN_TC_NOT_ACTIVE {
fmt.Println("接收驾驶端未激活") fmt.Println("接收驾驶端未激活")
fmt.Println(pd)
} else if msg.Type == train_pc_sim.SENDER_TRAIN_OUTR_INFO { } else if msg.Type == train_pc_sim.SENDER_TRAIN_OUTR_INFO {
fmt.Println("接受列车输出数字量", msg.Data[0], msg.Data[1]) fmt.Println(pd)
t := msg.Data[0]
s := msg.Data[1]
tt := strconv.Itoa(int(t))
switch t {
case 0:
tt = "驾驶台"
case 1:
tt = "手柄向前"
case 2:
tt = "手柄向后"
case 14:
tt = "手柄归零"
case 4:
tt = "制动状态"
}
fmt.Println("接受列车输出数字量", tt, s)
fmt.Println(pd)
} else if msg.Type == train_pc_sim.RECIVE_TRAIN_CREATE_REMOVE { } else if msg.Type == train_pc_sim.RECIVE_TRAIN_CREATE_REMOVE {
fmt.Println("创建或删除列车") state := msg.Data[0]
} if state == 0x01 {
fmt.Println("创建列车")
} else if state == 0x00 {
fmt.Println("删除列车")
}
fmt.Println(pd)
} else if msg.Type == train_pc_sim.SENDER_TRAIN_HAND_KEY_FORWARD {
fmt.Println("列车手柄向前")
fmt.Println(pd)
} else if msg.Type == train_pc_sim.RECIVE_TRAIN_HAND_KEY_CANCLE_FORWARD {
fmt.Println("列车手柄取消向前")
fmt.Println(pd)
} else if msg.Type == train_pc_sim.RECIVE_TRAIN_HAND_KEY_BACKWARD {
fmt.Println("列车手柄向后")
fmt.Println(pd)
} else if msg.Type == train_pc_sim.RECIVE_TRAIN_HAND_KEY_CACLE_BACKWARD {
fmt.Println("列车手柄取消向后")
fmt.Println(pd)
} else if msg.Type == train_pc_sim.RECIVE_TRAIN_BTM_HAS_DATA {
fmt.Println("有数据应答")
fmt.Println(pd)
} else if msg.Type == train_pc_sim.RECIVE_TRAIN_BTM_NOT_DATA {
} /*else if msg.Type == train_pc_sim.SENDER_TRAIN_LOCATION_INFO {
fmt.Println("列车速度位置报告")
fmt.Println(pd)
mp := message.TrainSpeedPlaceReportMsg{}
mp.Decode(msg.Data)
}*/
}) })
//reader := bufio.NewReader(os.Stdin) //reader := bufio.NewReader(os.Stdin)
@ -129,6 +249,19 @@ func main() {
} else if command == "door-mode" { } else if command == "door-mode" {
msg := changeDoorMode() msg := changeDoorMode()
serConn.Write(msg.Encode()) serConn.Write(msg.Encode())
} else if command == "info-out" {
msg := pcSimInfoOut()
serConn.Write(msg.Encode())
} else if command == "info-out-report" {
msg := pcSimInfoOutReport()
serConn.Write(msg.Encode())
} else if command == "query-btm" {
msg := queryBtm()
serConn.Write(msg.Encode())
} else if command == "num-out" {
msg := pcSimNumReportOut()
serConn.Write(msg.Encode())
} }
command = "" command = ""
/*content, _ := reader.ReadString('\n') /*content, _ := reader.ReadString('\n')

View File

@ -10,6 +10,7 @@ import (
"joylink.club/bj-rtsts-server/third_party/tpapi" "joylink.club/bj-rtsts-server/third_party/tpapi"
"joylink.club/ecs" "joylink.club/ecs"
"log/slog" "log/slog"
"strconv"
"sync" "sync"
"time" "time"
) )
@ -27,7 +28,7 @@ type TrainPcSim interface {
//发送驾驶端激活 //发送驾驶端激活
SendDriverActive(tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState) SendDriverActive(tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState)
//发送牵引制动手柄 //发送牵引制动手柄
SendHandleSwitch(oldTraction, oldBrakeForce int64, isBrake bool, tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState) SendHandleSwitch(oldTraction, oldBrakeForce int64, tractionState bool, tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState)
//列车运行方向 //列车运行方向
//因文档说明不清楚,在调用的时候目前是注释状态,现场调试可能会用到 //因文档说明不清楚,在调用的时候目前是注释状态,现场调试可能会用到
SendTrainDirection(trainForward, trainBackward bool) SendTrainDirection(trainForward, trainBackward bool)
@ -38,7 +39,7 @@ type TrainPcSim interface {
CreateOrRemoveSpeedPLace(train *state_proto.TrainState) CreateOrRemoveSpeedPLace(train *state_proto.TrainState)
CreateOrRemoveTrain(msgType byte, data []byte) CreateOrRemoveTrain(msgType byte, data []byte) error
tpapi.ThirdPartyApiService tpapi.ThirdPartyApiService
} }
@ -102,18 +103,30 @@ func (d *trainPcSimService) readError(err error) {
} }
func (d *trainPcSimService) connTrainPcSim() { func (d *trainPcSimService) connTrainPcSim() {
reconnIndex := 0 reconnIndex := 0
for { ctx, ctxFun := context.WithCancel(context.Background())
client, err := tcp.StartTcpClient(fmt.Sprintf("%v:%v", d.config.PcSimIp, d.config.PcSimPort), d.reivceData, d.readError) go func() {
if err != nil { for {
reconnIndex++ select {
slog.Error("连接车载pc平台失败尝试=", reconnIndex, err) case <-ctx.Done():
d.updateState(tpapi.ThirdPartyState_Broken) return
} else { default:
d.pcSimClient = client }
return 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)
} }
time.Sleep(time.Second * 1) }()
}
} }
func (d *trainPcSimService) Start(wd ecs.World, pcSimManage TrainPcSimManage) { func (d *trainPcSimService) Start(wd ecs.World, pcSimManage TrainPcSimManage) {
config := pcSimManage.GetTrainPcSimConfig() config := pcSimManage.GetTrainPcSimConfig()
@ -127,7 +140,7 @@ func (d *trainPcSimService) Start(wd ecs.World, pcSimManage TrainPcSimManage) {
d.cancleContext = ctxFun d.cancleContext = ctxFun
d.trainPcSimManage = pcSimManage d.trainPcSimManage = pcSimManage
FireTrainControlEventType.Subscribe(wd, d.trainControlEventHandle) //FireTrainControlEventType.Subscribe(wd, d.trainControlEventHandle)
d.updateState(tpapi.ThirdPartyState_Normal) d.updateState(tpapi.ThirdPartyState_Normal)
go d.sendTrainLocationAndSpeedTask(ctx) go d.sendTrainLocationAndSpeedTask(ctx)
@ -153,9 +166,10 @@ func (d *trainPcSimService) CreateOrRemoveSpeedPLace(train *state_proto.TrainSta
d.speedPlace = nil d.speedPlace = nil
} }
} }
func (d *trainPcSimService) CreateOrRemoveTrain(msgType byte, data []byte) { func (d *trainPcSimService) CreateOrRemoveTrain(msgType byte, data []byte) error {
msg := &message.TrainPcSimBaseMessage{Data: data, Type: uint16(msgType)} msg := &message.TrainPcSimBaseMessage{Data: data, Type: uint16(msgType)}
d.pcSimClient.Send(msg.Encode()) return d.pcSimClient.Send(msg.Encode())
} }
// 依据文档80ms发送列车速度位置 // 依据文档80ms发送列车速度位置
@ -167,7 +181,8 @@ func (d *trainPcSimService) sendTrainLocationAndSpeedTask(ctx context.Context) {
default: default:
} }
train := d.trainPcSimManage.GetConnTrain() train := d.trainPcSimManage.GetConnTrain()
if train != nil && train.ConnState.Conn { if train != nil && train.ConnState.Conn && train.PluseCount != nil {
s1, s2 := train.PluseCount.PulseCount1, train.PluseCount.PulseCount2 s1, s2 := train.PluseCount.PulseCount1, train.PluseCount.PulseCount2
d.speedPlace.ParsePulseCount1(s1, s2) d.speedPlace.ParsePulseCount1(s1, s2)
data := d.speedPlace.Encode(train.RunDirection, s1, s2) data := d.speedPlace.Encode(train.RunDirection, s1, s2)
@ -193,26 +208,34 @@ func (d *trainPcSimService) SendDriverActive(tc *state_proto.TrainConnState, vob
d.pcSimClient.Send(msg.Encode()) d.pcSimClient.Send(msg.Encode())
} }
} }
func (d *trainPcSimService) SendHandleSwitch(oldTraction, oldBrakeForce int64, isBrake bool, tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState) { 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 { if tc.Conn && tc.ConnType == state_proto.TrainConnState_PC_SIM {
msg := &message.TrainPcSimBaseMessage{} msg := &message.TrainPcSimBaseMessage{}
newTraction := vobc.TractionForce newTraction := vobc.TractionForce
newBrake := vobc.BrakeForce newBrake := -vobc.BrakeForce
if isBrake { newOldBrakeForce := -oldBrakeForce
if newBrake < oldBrakeForce && newBrake == 0 { if tractionState {
//手柄取消后退 if newTraction <= oldTraction && newTraction == 0 {
msg.Type = RECIVE_TRAIN_HAND_KEY_CACLE_BACKWARD
} else if newBrake > oldBrakeForce {
//手柄后退
msg.Type = RECIVE_TRAIN_HAND_KEY_BACKWARD
}
} else {
if newTraction < oldTraction && newTraction == 0 {
//手柄取消前进 //手柄取消前进
msg.Type = RECIVE_TRAIN_HAND_KEY_CANCLE_FORWARD msg.Type = RECIVE_TRAIN_HAND_KEY_CANCLE_FORWARD
} else if newTraction > oldTraction { } else if newTraction > oldTraction {
//手柄前进 //手柄前进
msg.Type = SENDER_TRAIN_HAND_KEY_FORWARD 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()) d.pcSimClient.Send(msg.Encode())
@ -238,6 +261,8 @@ func (d *trainPcSimService) SendBaliseData(msgType uint16, data []byte) {
msg := &message.TrainPcSimBaseMessage{} msg := &message.TrainPcSimBaseMessage{}
msg.Type = msgType msg.Type = msgType
msg.Data = data msg.Data = data
//fmt.Println(fmt.Sprintf("%X", msg.Encode()))
d.pcSimClient.Send(msg.Encode()) d.pcSimClient.Send(msg.Encode())
} }
@ -254,7 +279,13 @@ func (d *trainPcSimService) PublishTrainControlEvent(world ecs.World, events []T
return return
} }
for _, event := range events { for _, event := range events {
FireTrainControlEventType.Publish(world, &event) 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)
} }
} }

View File

@ -5,6 +5,7 @@ import (
"joylink.club/bj-rtsts-server/dto/common_proto" "joylink.club/bj-rtsts-server/dto/common_proto"
"joylink.club/bj-rtsts-server/service" "joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/third_party/can_btm" "joylink.club/bj-rtsts-server/third_party/can_btm"
"joylink.club/bj-rtsts-server/third_party/train_pc_sim"
"log/slog" "log/slog"
"math" "math"
"reflect" "reflect"
@ -149,11 +150,15 @@ func TrainConnTypeUpdate(vs *VerifySimulation, ct *dto.TrainConnThirdDto) {
return true return true
}) })
} }
if ct.ConnType == state_proto.TrainConnState_PC_SIM {
err := TrainPcSimConnOrRemoveHandle(train)
if err != nil {
panic(sys_error.New("连接车载PC仿真失败"))
}
train_pc_sim.Default().SendDriverActive(train.ConnState, train.VobcState)
}
train.ConnState.Conn = true train.ConnState.Conn = true
train.ConnState.ConnType = ct.ConnType train.ConnState.ConnType = ct.ConnType
if train.ConnState.ConnType == state_proto.TrainConnState_PC_SIM {
TrainPcSimConnOrRemoveHandle(train)
}
} }
// 列车断开三方连接 // 列车断开三方连接
@ -168,8 +173,13 @@ func TrainUnConn(vs *VerifySimulation, trainId string) {
train.ConnState.Conn = false train.ConnState.Conn = false
train.ConnState.ConnType = state_proto.TrainConnState_NONE train.ConnState.ConnType = state_proto.TrainConnState_NONE
if oldType == state_proto.TrainConnState_PC_SIM { if oldType == state_proto.TrainConnState_PC_SIM {
TrainPcSimConnOrRemoveHandle(train) err := TrainPcSimConnOrRemoveHandle(train)
if err != nil {
panic(sys_error.New("未连接车载PC仿真无法断开连接"))
}
} }
train.ConnState.Conn = false
train.ConnState.ConnType = state_proto.TrainConnState_NONE
} }
func createOrUpdateStateDynamicConfig(trainState *state_proto.TrainState, configTrainData dto.ConfigTrainData, trainEndsA dto.ConfigTrainEnds, func createOrUpdateStateDynamicConfig(trainState *state_proto.TrainState, configTrainData dto.ConfigTrainData, trainEndsA dto.ConfigTrainEnds,
trainEndsB dto.ConfigTrainEnds) { trainEndsB dto.ConfigTrainEnds) {
@ -189,14 +199,17 @@ func copyTrainEnds(trainState *state_proto.TrainState, fieldName string, configD
} }
endsVal.SpeedSensorEnableA = configData.SpeedSensorEnableA endsVal.SpeedSensorEnableA = configData.SpeedSensorEnableA
endsVal.SpeedSensorEnableB = configData.SpeedSensorEnableB endsVal.SpeedSensorEnableB = configData.SpeedSensorEnableB
endsVal.AccOutSpeed = configData.AccOutSpeed
endsVal.RadarEnable = configData.RadarEnable endsVal.RadarEnable = configData.RadarEnable
endsVal.RadarCheckSpeedDiff = configData.RadarCheckSpeedDiff
endsVal.RadarCheckTime = configData.RadarCheckTime endsVal.RadarCheckTime = configData.RadarCheckTime
endsVal.RadarCheckSpeedDiff = configData.RadarCheckSpeedDiff
endsVal.RadarOutSpeed = configData.RadarOutSpeed
endsVal.AccEnable = configData.AccEnable endsVal.AccEnable = configData.AccEnable
endsVal.AccCheckSpeedDiff = configData.AccCheckSpeedDiff endsVal.AccCheckSpeedDiff = configData.AccCheckSpeedDiff
endsVal.AccCheckTime = configData.AccCheckTime endsVal.AccCheckTime = configData.AccCheckTime
endsVal.AccOutSpeed = configData.AccOutSpeed
endsVal.RadarOutSpeed = configData.RadarOutSpeed
} }
func UpdateConfigTrain(vs *VerifySimulation, ct *dto.ConfigTrainReqDto) { func UpdateConfigTrain(vs *VerifySimulation, ct *dto.ConfigTrainReqDto) {
@ -213,6 +226,26 @@ func UpdateConfigTrain(vs *VerifySimulation, ct *dto.ConfigTrainReqDto) {
trainState.TrainLength = ct.Length trainState.TrainLength = ct.Length
trainState.WheelDiameter = ct.WheelDiameter trainState.WheelDiameter = ct.WheelDiameter
requestDynamicConfig(ct) requestDynamicConfig(ct)
trainState.TrainEndsA.RadarCheckTimeOverAt = 0
trainState.TrainEndsB.RadarCheckTimeOverAt = 0
trainState.TrainEndsA.AccCheckTimeOverAt = 0
trainState.TrainEndsB.AccCheckTimeOverAt = 0
if ct.TrainEndsA.RadarCheckTime > 0 {
timeAt := time.Now().Add(time.Second * time.Duration(ct.TrainEndsA.RadarCheckTime)).Unix()
trainState.TrainEndsA.RadarCheckTimeOverAt = timeAt
}
if ct.TrainEndsB.RadarCheckTime > 0 {
timeAt := time.Now().Add(time.Second * time.Duration(ct.TrainEndsB.RadarCheckTime)).Unix()
trainState.TrainEndsB.RadarCheckTimeOverAt = timeAt
}
if ct.TrainEndsA.AccCheckTime > 0 {
timeAt := time.Now().Add(time.Second * time.Duration(ct.TrainEndsA.AccCheckTime)).Unix()
trainState.TrainEndsA.AccCheckTimeOverAt = timeAt
}
if ct.TrainEndsB.AccCheckTime > 0 {
timeAt := time.Now().Add(time.Second * time.Duration(ct.TrainEndsB.AccCheckTime)).Unix()
trainState.TrainEndsB.AccCheckTimeOverAt = timeAt
}
} }
func requestDynamicConfig(ct *dto.ConfigTrainReqDto) { func requestDynamicConfig(ct *dto.ConfigTrainReqDto) {
@ -318,6 +351,7 @@ func UpdateTrainStateByDynamics(vs *VerifySimulation, trainId string, info *mess
sta.DynamicState.RampResistance = float32(info.SlopeResistance) / 1000 sta.DynamicState.RampResistance = float32(info.SlopeResistance) / 1000
sta.DynamicState.CurveResistance = float32(info.CurveResistance) / 1000 sta.DynamicState.CurveResistance = float32(info.CurveResistance) / 1000
sta.DynamicState.Speed = speedParse(info.Speed) sta.DynamicState.Speed = speedParse(info.Speed)
sta.DynamicState.HeadSensorSpeed1 = speedParse(info.HeadSpeed1) sta.DynamicState.HeadSensorSpeed1 = speedParse(info.HeadSpeed1)
sta.DynamicState.HeadSensorSpeed2 = speedParse(info.HeadSpeed2) sta.DynamicState.HeadSensorSpeed2 = speedParse(info.HeadSpeed2)
sta.DynamicState.TailSensorSpeed1 = speedParse(info.TailSpeed1) sta.DynamicState.TailSensorSpeed1 = speedParse(info.TailSpeed1)
@ -325,6 +359,7 @@ func UpdateTrainStateByDynamics(vs *VerifySimulation, trainId string, info *mess
sta.DynamicState.HeadRadarSpeed = speedParse(info.HeadRadarSpeed) sta.DynamicState.HeadRadarSpeed = speedParse(info.HeadRadarSpeed)
sta.DynamicState.TailRadarSpeed = speedParse(info.TailRadarSpeed) sta.DynamicState.TailRadarSpeed = speedParse(info.TailRadarSpeed)
sta.DynamicState.Acceleration = info.Acceleration sta.DynamicState.Acceleration = info.Acceleration
sta.DynamicState.Displacement = int32(info.Displacement) sta.DynamicState.Displacement = int32(info.Displacement)
pluseCount(sta) pluseCount(sta)
return sta return sta
@ -334,24 +369,30 @@ func UpdateTrainStateByDynamics(vs *VerifySimulation, trainId string, info *mess
const RECEIVE_DYNAMIC_DATA_RATE = 15 const RECEIVE_DYNAMIC_DATA_RATE = 15
func formatSpeedTime(s int32) int32 { func formatSpeedTime(s int32) int32 {
d3, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", s), 64) //d3, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", s), 64)
return int32(math.Abs(math.Round(d3))) return int32(math.Abs(math.Round(float64(s))))
} }
func pluseCount(sta *state_proto.TrainState) { func pluseCount(sta *state_proto.TrainState) {
if sta.PluseCount == nil { if sta.PluseCount == nil {
return return
} }
if sta.RunDirection { if sta.RunDirection {
p1 := uint32(formatSpeedTime(sta.DynamicState.HeadSensorSpeed1 * RECEIVE_DYNAMIC_DATA_RATE))
p2 := uint32(formatSpeedTime(sta.DynamicState.HeadSensorSpeed2 * RECEIVE_DYNAMIC_DATA_RATE))
if sta.TrainEndsA.SpeedSensorEnableA { if sta.TrainEndsA.SpeedSensorEnableA {
sta.PluseCount.PulseCount1 += uint32(formatSpeedTime(sta.DynamicState.HeadSensorSpeed1 * RECEIVE_DYNAMIC_DATA_RATE)) sta.PluseCount.PulseCount1 = sta.PluseCount.PulseCount1 + p1
} else if sta.TrainEndsA.SpeedSensorEnableB { }
sta.PluseCount.PulseCount2 += uint32(formatSpeedTime(sta.DynamicState.HeadSensorSpeed2 * RECEIVE_DYNAMIC_DATA_RATE)) if sta.TrainEndsA.SpeedSensorEnableB {
sta.PluseCount.PulseCount2 = sta.PluseCount.PulseCount2 + p2
} }
} else { } else {
t1 := uint32(formatSpeedTime(sta.DynamicState.TailSensorSpeed1 * RECEIVE_DYNAMIC_DATA_RATE))
t2 := uint32(formatSpeedTime(sta.DynamicState.TailSensorSpeed2 * RECEIVE_DYNAMIC_DATA_RATE))
if sta.TrainEndsB.SpeedSensorEnableA { if sta.TrainEndsB.SpeedSensorEnableA {
sta.PluseCount.PulseCount1 += uint32(formatSpeedTime(sta.DynamicState.TailSensorSpeed1 * RECEIVE_DYNAMIC_DATA_RATE)) sta.PluseCount.PulseCount1 = sta.PluseCount.PulseCount1 + t1
} else if sta.TrainEndsB.SpeedSensorEnableB { }
sta.PluseCount.PulseCount2 += uint32(formatSpeedTime(sta.DynamicState.TailSensorSpeed2 * RECEIVE_DYNAMIC_DATA_RATE)) if sta.TrainEndsB.SpeedSensorEnableB {
sta.PluseCount.PulseCount2 = sta.PluseCount.PulseCount2 + t2
} }
} }
} }

View File

@ -4,20 +4,15 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log/slog"
"math"
"sort"
"strconv"
"strings"
"sync"
"joylink.club/bj-rtsts-server/config" "joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/dto" "joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/dto/data_proto" "joylink.club/bj-rtsts-server/dto/data_proto"
"joylink.club/bj-rtsts-server/dto/state_proto" "joylink.club/bj-rtsts-server/dto/state_proto"
"joylink.club/bj-rtsts-server/sys_error" "joylink.club/bj-rtsts-server/sys_error"
"joylink.club/bj-rtsts-server/third_party/acc"
"joylink.club/bj-rtsts-server/third_party/electrical_machinery" "joylink.club/bj-rtsts-server/third_party/electrical_machinery"
"joylink.club/bj-rtsts-server/third_party/message" "joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/radar"
"joylink.club/bj-rtsts-server/third_party/semi_physical_train" "joylink.club/bj-rtsts-server/third_party/semi_physical_train"
"joylink.club/ecs" "joylink.club/ecs"
"joylink.club/rtsssimulation/component" "joylink.club/rtsssimulation/component"
@ -25,6 +20,12 @@ import (
"joylink.club/rtsssimulation/fi" "joylink.club/rtsssimulation/fi"
"joylink.club/rtsssimulation/repository" "joylink.club/rtsssimulation/repository"
"joylink.club/rtsssimulation/repository/model/proto" "joylink.club/rtsssimulation/repository/model/proto"
"log/slog"
"math"
"sort"
"strconv"
"strings"
"sync"
) )
// 轨旁仿真定义 // 轨旁仿真定义
@ -281,18 +282,14 @@ func (s *VerifySimulation) HandleDynamicsTrainInfo(info *message.DynamicsTrainIn
return return
} }
train := t.(*state_proto.TrainState) train := t.(*state_proto.TrainState)
if train.ConnState.Conn && train.ConnState.ConnType == state_proto.TrainConnState_VOBC {
semi_physical_train.Default().SendTrainControlMessage(info)
}
// 更新列车状态 // 更新列车状态
trainState := UpdateTrainStateByDynamics(s, trainId, info) trainState := UpdateTrainStateByDynamics(s, trainId, info)
// 更新电机转速 if train.ConnState.Conn && train.ConnState.ConnType == state_proto.TrainConnState_VOBC {
electrical_machinery.Default().SendElectricMachineryMessage(&message.ElectricMachinery{ semi_physical_train.Default().SendTrainControlMessage(info)
Speed: info.Speed, electrical_machinery.Default().SendElectricMachineryMessage2(info, trainState)
WheelDiameter: trainState.WheelDiameter, radar.Default().TrainSpeedSender(info, trainState)
IsBack: trainState.VobcState.DirectionBackward, acc.Default().TrainAccSender(info, trainState)
}) }
} }
// 获取动力学配置信息 // 获取动力学配置信息
@ -509,8 +506,8 @@ func (s *VerifySimulation) FindTrainConnTypes() []dto.TrainConnTypeConfigDto {
} }
// 获取电机转速参数 // 获取电机转速参数
func (s *VerifySimulation) GetElectricMachineryRunConfig() *config.ElectricMachineryConfig { func (s *VerifySimulation) GetElectricMachineryRunConfig() []config.ElectricMachineryConfig {
return &s.runConfig.ElectricMachinery return s.runConfig.ElectricMachinerys
} }
// 初始化仿真运行配置 // 初始化仿真运行配置
@ -581,7 +578,7 @@ func (s *VerifySimulation) GetRunAccConfig() config.AccConfig {
} }
// FindRadarTrain 查找一个列车 只有1端雷达开启啊 // FindRadarTrain 查找一个列车 只有1端雷达开启啊
func (s *VerifySimulation) FindRadarTrain() *state_proto.TrainState { /*func (s *VerifySimulation) FindRadarTrain() *state_proto.TrainState {
var trainStatus *state_proto.TrainState var trainStatus *state_proto.TrainState
s.Memory.Status.TrainStateMap.Range(func(k any, v any) bool { s.Memory.Status.TrainStateMap.Range(func(k any, v any) bool {
val, ok := v.(*state_proto.TrainState) val, ok := v.(*state_proto.TrainState)
@ -590,18 +587,11 @@ func (s *VerifySimulation) FindRadarTrain() *state_proto.TrainState {
trainStatus = val trainStatus = val
return false return false
} }
/*if val.TrainEndsA.RadarEnable && val.TrainEndsB.RadarEnable {
return true
} else if val.TrainEndsA.RadarEnable || val.TrainEndsB.RadarEnable {
trainStatus = val
return false
}*/
} }
return true return true
}) })
return trainStatus return trainStatus
} }*/
// FindRadarTrain 查找一个列车 只有1端雷达开启啊 // FindRadarTrain 查找一个列车 只有1端雷达开启啊
func (s *VerifySimulation) FindAccTrain() *state_proto.TrainState { func (s *VerifySimulation) FindAccTrain() *state_proto.TrainState {

View File

@ -48,9 +48,9 @@ func ControlTrainUpdate(s *VerifySimulation, ct *request_proto.TrainControl) {
} else if ct.ControlType == request_proto.TrainControl_HANDLER { } else if ct.ControlType == request_proto.TrainControl_HANDLER {
oldTraction := sta.VobcState.TractionForce oldTraction := sta.VobcState.TractionForce
oldBrakeForce := sta.VobcState.BrakeForce oldBrakeForce := sta.VobcState.BrakeForce
isBrake := ct.Handler.Val < 0 //是否制动 isTraction := ct.Handler.Val > 0 //是否制动
tce = trainControlHandle(sta, ct.Handler, ct.DeviceId, tccGraphicData) tce = trainControlHandle(sta, ct.Handler, ct.DeviceId, tccGraphicData)
train_pc_sim.Default().SendHandleSwitch(oldTraction, oldBrakeForce, isBrake, sta.ConnState, sta.VobcState) train_pc_sim.Default().SendHandleSwitch(oldTraction, oldBrakeForce, isTraction, sta.ConnState, sta.VobcState)
} }
if sta.ConnState.Conn && sta.ConnState.ConnType == state_proto.TrainConnState_PC_SIM && tce != nil { if sta.ConnState.Conn && sta.ConnState.ConnType == state_proto.TrainConnState_PC_SIM && tce != nil {
@ -96,7 +96,10 @@ func trainControlDirKey(trainState *state_proto.TrainState, request *request_pro
} else { } else {
trainState.Tcc.DirKey.Val = request.Val trainState.Tcc.DirKey.Val = request.Val
} }
return nil tce := make([]train_pc_sim.TrainControlEvent, 0)
tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_FORWORD, Status: message.IsTrue(trainState.VobcState.DirectionForward)})
tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_BACKWORD, Status: message.IsTrue(trainState.VobcState.DirectionBackward)})
return tce
} }
// 列车驾驶端激活 // 列车驾驶端激活
@ -106,11 +109,20 @@ func trainControlDriverKey(trainState *state_proto.TrainState, request *request_
slog.Error("未找到对应的驾驶端激活设备deviceId:", deviceId) slog.Error("未找到对应的驾驶端激活设备deviceId:", deviceId)
return nil return nil
} }
if obj.Code == "SKQYS1" { if obj.Code == "SKQYS1" {
trainState.VobcState.Tc1Active = request.Val trainState.VobcState.Tc1Active = request.Val
} else if obj.Code == "SKQYS2" { } else if obj.Code == "SKQYS2" {
trainState.VobcState.Tc2Active = request.Val trainState.VobcState.Tc2Active = request.Val
} }
if trainState.VobcState.Tc1Active && trainState.VobcState.Tc2Active {
if obj.Code == "SKQYS1" {
trainState.VobcState.Tc1Active = false
} else if obj.Code == "SKQYS2" {
trainState.VobcState.Tc2Active = false
}
panic(sys_error.New("驾驶端不能同时激活"))
}
var addNew = true var addNew = true
for _, k := range trainState.Tcc.DriverKey { for _, k := range trainState.Tcc.DriverKey {
if k.Id == deviceId { if k.Id == deviceId {
@ -141,17 +153,18 @@ func trainControlHandle(trainState *state_proto.TrainState, request *request_pro
trainState.VobcState.BrakeForce = 0 trainState.VobcState.BrakeForce = 0
trainState.VobcState.MaintainBrakeStatus = false trainState.VobcState.MaintainBrakeStatus = false
tce := make([]train_pc_sim.TrainControlEvent, 0) tce := make([]train_pc_sim.TrainControlEvent, 0)
tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_FORWORD, Status: 0}) //tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_FORWORD, Status: 0})
tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_BACKWORD, Status: 0}) //tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_BACKWORD, Status: 0})
tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_TO_ZERO, Status: 0}) tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_TO_ZERO, Status: 0})
if request.Val > 0 { if request.Val > 0 {
trainState.VobcState.TractionStatus = true trainState.VobcState.TractionStatus = true
trainState.VobcState.TractionForce = int64(request.Val * 180) trainState.VobcState.TractionForce = int64(request.Val * 180)
tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_FORWORD, Status: 1}) //tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_FORWORD, Status: 1})
tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.TRAIN_BRAKE_STATE, Status: 0})
} else if request.Val < 0 { } else if request.Val < 0 {
trainState.VobcState.BrakingStatus = true trainState.VobcState.BrakingStatus = true
trainState.VobcState.BrakeForce = int64(-request.Val * 180) trainState.VobcState.BrakeForce = int64(-request.Val * 180)
tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_BACKWORD, Status: 1}) //tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.HANDLE_BACKWORD, Status: 1})
tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.TRAIN_BRAKE_STATE, Status: 1}) tce = append(tce, train_pc_sim.TrainControlEvent{Command: message.TRAIN_BRAKE_STATE, Status: 1})
} else { } else {
@ -372,13 +385,17 @@ func (s *VerifySimulation) TrainPcSimDigitalReportHandle(data []byte) {
} }
// 创建/删除列车 // 创建/删除列车
func TrainPcSimConnOrRemoveHandle(train *state_proto.TrainState) { func TrainPcSimConnOrRemoveHandle(train *state_proto.TrainState) error {
var data byte = 0x01 var data byte = 0x01
if train.ConnState.Conn == false { if train.ConnState.Conn == false {
data = 0x00 data = 0x00
} }
train_pc_sim.Default().CreateOrRemoveTrain(train_pc_sim.RECIVE_TRAIN_CREATE_REMOVE, []byte{data}) crErr := train_pc_sim.Default().CreateOrRemoveTrain(train_pc_sim.RECIVE_TRAIN_CREATE_REMOVE, []byte{data})
if crErr != nil {
return crErr
}
train_pc_sim.Default().CreateOrRemoveSpeedPLace(train) train_pc_sim.Default().CreateOrRemoveSpeedPLace(train)
return nil
} }
// 门模式 // 门模式