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

View File

@ -250,6 +250,10 @@ type TrainEndsState struct {
AccOutSpeed int32 `protobuf:"varint,9,opt,name=accOutSpeed,proto3" json:"accOutSpeed,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() {
@ -354,6 +358,20 @@ func (x *TrainEndsState) GetRadarOutSpeed() int32 {
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_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,
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,
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,
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,
@ -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,
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,
0x65, 0x65, 0x64, 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,
0x65, 0x65, 0x64, 0x12, 0x32, 0x0a, 0x14, 0x72, 0x61, 0x64, 0x61, 0x72, 0x43, 0x68, 0x65, 0x63,
0x6b, 0x54, 0x69, 0x6d, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x41, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28,
0x03, 0x52, 0x14, 0x72, 0x61, 0x64, 0x61, 0x72, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x69, 0x6d,
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 (

View File

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

View File

@ -1537,7 +1537,7 @@ func (x *TrainDynamicState) GetDisplacement() int32 {
return 0
}
// vobc发过来的列车信息
// vobc发过来的列车信息 包括 (驾驶台和车载)
type TrainVobcState struct {
state protoimpl.MessageState
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.TrainEndsA, t.TrainEndsA)
convertDynamicConfig(v.TrainEndsB, t.TrainEndsB)
//now := time.Now().Unix()
return t
}
func convertDynamicConfig(config, dest interface{}) {
configType := reflect.TypeOf(config).Elem()
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) {
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.Listen()
select {}
@ -23,6 +23,6 @@ func handle(d []byte) {
if err == nil {
jsonD, _ := json.Marshal(ri)
fmt.Println(string(jsonD))
fmt.Println("接受数据:", string(jsonD))
}
}

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"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/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp"
@ -15,6 +16,8 @@ import (
type AccVobc interface {
Start(accManager AccVobcManager)
Stop()
SendAcc(acc *message.Accelerometer)
TrainAccSender(info *message.DynamicsTrainInfo, trainState *state_proto.TrainState)
}
type AccVobcManager interface {
@ -27,10 +30,10 @@ var (
singleObj *accVobcService
)
const (
/*const (
accInterval = 15
accSpeedUnit = 9.8
)
)*/
func Default() AccVobc {
defer initLock.Unlock()
@ -52,13 +55,46 @@ func (acc *accVobcService) Start(accManager AccVobcManager) {
if config.RemoteIp == "" || config.RemotePort <= 0 || !config.Open {
}
acc.vobcClient = udp.NewClient(fmt.Sprintf("%v:%v", config.RemoteIp, config.RemotePort))
ctx, cancleFunc := context.WithCancel(context.Background())
acc.controlContext = cancleFunc
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 {
select {
case <-ctx.Done():
@ -74,7 +110,7 @@ func (acc *accVobcService) sendTask(ctx context.Context) {
}
time.Sleep(time.Millisecond * accInterval)
}
}
}*/
func (acc *accVobcService) Stop() {
if acc.controlContext != nil {

View File

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

View File

@ -2,6 +2,8 @@ package electrical_machinery
import (
"fmt"
"joylink.club/bj-rtsts-server/dto/common_proto"
"joylink.club/bj-rtsts-server/dto/state_proto"
"sync"
"joylink.club/bj-rtsts-server/config"
@ -9,22 +11,30 @@ import (
"joylink.club/bj-rtsts-server/third_party/udp"
)
const (
PointA = iota + 1
PointB
)
// 电机转速UDP
type ElectricMachinery interface {
Start(manager ElectricMachineryMessageManager) // 启动电机转速UDP消息处理
Stop() // 停止电机转速消息处理
SendElectricMachineryMessage(info *message.ElectricMachinery) // 发送电机转速消息
Start(manager ElectricMachineryMessageManager) // 启动电机转速UDP消息处理
Stop() // 停止电机转速消息处理
SendElectricMachineryMessage(emMap map[int]*message.ElectricMachinery) // 发送电机转速消息
SendElectricMachineryMessage2(info *message.DynamicsTrainInfo, trainState *state_proto.TrainState) // 发送电机转速消息
}
type ElectricMachineryMessageManager interface {
GetElectricMachineryRunConfig() *config.ElectricMachineryConfig // 获取电机转速参数
GetElectricMachineryRunConfig() []config.ElectricMachineryConfig // 获取电机转速参数
}
type electricalMachineryImpl struct {
electricalMachineryUdpClient udp.UdpClient
//electricalMachineryUdpClient udp.UdpClient
manager ElectricMachineryMessageManager
runConfig *config.ElectricMachineryConfig
electricalMachineryUdpClientMap map[int]udp.UdpClient
manager ElectricMachineryMessageManager
runConfig []config.ElectricMachineryConfig
}
func (s *electricalMachineryImpl) Start(manager ElectricMachineryMessageManager) {
@ -35,7 +45,13 @@ func (s *electricalMachineryImpl) Start(manager ElectricMachineryMessageManager)
panic("启动电机转速消息服务错误: 存在正在运行的任务")
}
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
}
// 初始化客户端、服务端
@ -47,21 +63,81 @@ func (s *electricalMachineryImpl) Stop() {
initMutex.Lock()
defer initMutex.Unlock()
_default = nil
if s.electricalMachineryUdpClient != nil {
s.electricalMachineryUdpClient.Close()
//if s.electricalMachineryUdpClient != nil {
// s.electricalMachineryUdpClient.Close()
//}
for _, c := range s.electricalMachineryUdpClientMap {
if &c != nil {
c.Close()
}
}
s.manager = nil
}
func (s *electricalMachineryImpl) SendElectricMachineryMessage(info *message.ElectricMachinery) {
if s.electricalMachineryUdpClient == nil {
return
func (s *electricalMachineryImpl) SendElectricMachineryMessage(emMap map[int]*message.ElectricMachinery) {
for key, em := range emMap {
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() {
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

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

View File

@ -2,16 +2,17 @@ package message
import "log/slog"
//BTM与ATP之间为双向通信ATP定时发送请求帧BTM在未接收到应答器报文时回复状态应答器帧和时间同步帧在接收到应答器报文时回复所有帧
// CreateBtmRspFramesData 数据帧与状态应答帧同时发送给ATP
// CreateBtmRspFramesData BTM与ATP之间为双向通信ATP定时发送请求帧BTM在未接收到应答器报文时回复状态应答器帧和时间同步帧在接收到应答器报文时回复所有帧
//
// 数据帧与状态应答帧同时发送给ATP
//
// 共17帧17X12个字节每个帧12字节
// msg - 应答器报文
// msgPackError - true BTM解包发生错误则数据帧及CRC32A/B全填“0xFF”
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
}
}*/
//最近一次ATP查询请求序列号
sn := statusRsp.FId.ID4
//13个BtmDataMessageFrame [0x00,0x0c]
@ -93,6 +94,101 @@ func CreateBtmRspFramesData(statusRsp *BtmStatusRspFrame, msg []byte, msgPackErr
rt = append(rt, dtACf.Encode()...)
rt = append(rt, dtBCf.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 {
slog.Warn("len(rt)!=221")
return nil, false

View File

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

View File

@ -2,11 +2,12 @@ package message
import (
"encoding/binary"
"fmt"
"math"
)
// 速度转转速计算公式:
// 转速=车速 ÷ 车轮周长
// 转速=车速(米/秒) ÷ 车轮周长(米)
// 车的轮径为d车速为v1电机转速为v2
// 公式为V2=V1÷πd×60
type ElectricMachinery struct {
@ -17,16 +18,34 @@ type ElectricMachinery struct {
func (t *ElectricMachinery) Encode() []byte {
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 / (float32(math.Pi) * float32(t.WheelDiameter) / 1000) * 60
var rotarySpeedData uint32
if t.IsBack {
b = binary.BigEndian.AppendUint32(b, uint32(0-rotarySpeed))
//b = binary.BigEndian.AppendUint32(b, uint32(0-rotarySpeed))
rotarySpeedData = uint32(0 - rotarySpeed)
} 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校验码
b = binary.BigEndian.AppendUint16(b, crc)
//fmt.Println("发送:", hx, rotarySpeedData, crc)
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
func chkcrc(data []byte) uint16 {

View File

@ -4,8 +4,7 @@ import (
"bytes"
"encoding/binary"
"fmt"
"strings"
"sync/atomic"
"math"
)
const (
@ -13,7 +12,11 @@ const (
radar_head2 byte = 0xFC
)
var autoInc = atomic.Int32{}
var autoInc byte = 0
var (
fixed_speed = 0.009155
driftDefaultVal = 0.1
)
// 雷达与VOBC接口-雷达通讯协议
type RadarInfo struct {
@ -27,49 +30,65 @@ type RadarInfo struct {
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 {
SourceState byte //原数据
Model string // 天线模式
SyntheticalState string //综合状态
DirState string //方向状态
Dir byte //方向
SwModel1 byte
SwModel0 byte
calculateBit byte //计算状态位
signalQualityBit 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 {
buf := make([]byte, 0)
buf = append(buf, radar_head1)
buf = append(buf, radar_head2)
if tmp := autoInc.Add(1); tmp >= 256 {
autoInc.Store(0)
buf = append(buf, 0)
} else {
buf = append(buf, byte(tmp))
}
autoInc = autoInc + 1
buf = append(buf, autoInc)
buf = binary.LittleEndian.AppendUint16(buf, r.RealSpeed)
buf = binary.LittleEndian.AppendUint16(buf, r.DriftCounterS1)
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)
//6,7位 11
//3,4,5位 011
// 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)
buf = append(buf, r.State.Encode())
var sum = 0
for _, d := range buf {
sum += int(d)
@ -105,58 +124,19 @@ func (r *RadarInfo) Decode(data []byte) error {
if !(r.Tail == r.createTail()) {
return fmt.Errorf("数据解析完成,但协议效验不通过")
}
state.parseState()
return nil
}
func (s *RadarState) parseState() {
//第7位 == SW_Mode0, 第6位 == SW_Mode1
// 11:两个天线和双通道都OK
// 10DRS05_Single-Mode 40度,50度的天线或通道故障
// 01DRS05_Single-Mode 50度,40度的天线或通道故障
// 00错误模式 双侧天线或通道都故障
// 模式的工作差别工作在11.模式时效果最好。单模式10或01时可信度下降。
arr := s.getBitsStateArr()
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) Decode(d byte) {
s.SwModel1 = GetBit(d, 7)
s.SwModel0 = GetBit(d, 6)
s.calculateBit = GetBit(d, 5)
s.signalQualityBit = GetBit(d, 4)
s.BlackoutBit = GetBit(d, 3)
s.DirectionState = GetBit(d, 1)
s.Direction = GetBit(d, 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 {
return int(d>>8) + int(d&0x00FF)
}
@ -169,7 +149,7 @@ func (r *RadarInfo) createTail() byte {
sum += culDataSize(r.DriftCounterS2)
sum += int(r.InnerCheck1)
sum += int(r.InnerCheck2)
sum += int(r.State.SourceState)
sum += int(r.State.Encode())
return byte(^sum + 1)
}
@ -213,7 +193,9 @@ func readRadarState(buf *bytes.Buffer) *RadarState {
return nil, fmt.Errorf("")
}*/
state, _ := buf.ReadByte()
return &RadarState{SourceState: state}
s := &RadarState{}
s.Decode(state)
return s
}
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)
data := dataBufs.Bytes()
pack = append(pack, data...)
pack = binary.BigEndian.AppendUint16(pack, uint16(crc.CalculateCRC(crc.CRC16, data)))
return pack
}
@ -109,6 +108,24 @@ func (tp *TrainSpeedPlaceReportMsg) Encode(runDir bool, s1, s2 uint32) []byte {
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仿真发送的命令码
const (
//钥匙开关状态

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"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/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp"
@ -16,11 +17,13 @@ import (
type RadarVobc interface {
Start(radar RadarVobcManager)
Stop()
SendMsg(ri *message.RadarInfo)
TrainSpeedSender(info *message.DynamicsTrainInfo, trainState *state_proto.TrainState)
}
type RadarVobcManager interface {
GetRunRadarConfig() config.RadarConfig
FindRadarTrain() *state_proto.TrainState
//FindRadarTrain() *state_proto.TrainState
}
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))
ctx, cancleFunc := context.WithCancel(context.Background())
rv.radarVobcTaskContext = cancleFunc
//ctx, cancleFunc := context.WithCancel(context.Background())
//rv.radarVobcTaskContext = cancleFunc
rv.radarVobcManager = radar
go rv.sendRadarInfo(ctx)
//go rv.sendRadarInfo(ctx)
}
// sendRadarInfo 发送速度,位移计数 给vobc
func (rv *radarVobc) sendRadarInfo(ctx context.Context) {
/*defer func() {
slog.Error("")
}()*/
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))
func (rv *radarVobc) SendMsg(ri *message.RadarInfo) {
rv.vobcClient.Send(ri.Encode())
}
func (rv *radarVobc) TrainSpeedSender(info *message.DynamicsTrainInfo, trainState *state_proto.TrainState) {
forward := trainState.VobcState.DirectionForward
if trainState.VobcState.Tc1Active && trainState.TrainEndsA.RadarEnable {
s := parseRadarSpeedData(info.Speed, trainState.TrainEndsA)
rv.SendMsg(message.NewRadarSender(s, forward, info.Displacement))
} else if trainState.VobcState.Tc2Active && trainState.TrainEndsB.RadarEnable {
s := parseRadarSpeedData(info.Speed, trainState.TrainEndsB)
rv.SendMsg(message.NewRadarSender(s, forward, info.Displacement))
} else {
rv.SendMsg(message.NewRadarSender(0, forward, 0))
//slog.Error("列车行驶方向不确定或两端的雷达均未启用,发送雷达数据0", "列车前进=", trainState.VobcState.DirectionForward, "雷达启用A=", trainState.TrainEndsA.RadarEnable, "列车后退=", trainState.VobcState.DirectionBackward, "雷达启用B=", trainState.TrainEndsB.RadarEnable)
}
}
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)
func parseRadarSpeedData(radarSpeed float32, trainEndState *common_proto.TrainEndsState) float32 {
//如果差值速度和速度输出都填写,那么就以速度输出为优先
//如果动力学速度-差值速度小于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() {
if rv.radarVobcTaskContext != nil {
/* if rv.radarVobcTaskContext != nil {
rv.radarVobcTaskContext()
rv.radarVobcTaskContext = nil
}
}*/
if rv.vobcClient != nil {
rv.vobcClient.Close()
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 {
slog.Warn(fmt.Sprintf("TCP客户端[rAddr:%s]断开连接:", rAddr))
break
readErr(err)
}
}
handler(l, data)
@ -57,15 +57,16 @@ func (c *TcpClient) Close() {
c.conn = nil
}
}
func (c *TcpClient) Send(data []byte) {
if c.conn == nil {
func (c *TcpClient) Send(data []byte) error {
if c == nil || c.conn == nil {
slog.Error("tcp client send error,conn is nil")
return
return fmt.Errorf("TCP未连接车载PC仿真")
}
_, err := c.conn.Write(data)
if err != nil {
slog.Error("tcp client send error", "error", err)
return err
}
return nil
}

View File

@ -1,12 +1,14 @@
package main
import (
"encoding/binary"
"fmt"
"io"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/train_pc_sim"
"log/slog"
"net"
"strconv"
)
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) {
go func() {
defer func() {
/* defer func() {
if err := recover(); err != nil {
slog.Error(fmt.Sprintf("TCP服务端[port:%d]读数据任务异常:", port), err)
serConn.Close()
serConn = nil
}
}()
}()*/
for {
data := make([]byte, 1024)
l, err := conn.Read(data)
@ -87,6 +89,72 @@ func changeDoorMode() *message.TrainPcSimBaseMessage {
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) {
createServer(func(n int, data []byte) {
@ -99,16 +167,68 @@ func main() {
createServer(func(n int, data []byte) {
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 {
fmt.Println("接收驾驶端激活")
fmt.Println(pd)
} else if msg.Type == train_pc_sim.SENDER_TRAIN_TC_NOT_ACTIVE {
fmt.Println("接收驾驶端未激活")
fmt.Println(pd)
} 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 {
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)
@ -129,6 +249,19 @@ func main() {
} else if command == "door-mode" {
msg := changeDoorMode()
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 = ""
/*content, _ := reader.ReadString('\n')

View File

@ -10,6 +10,7 @@ import (
"joylink.club/bj-rtsts-server/third_party/tpapi"
"joylink.club/ecs"
"log/slog"
"strconv"
"sync"
"time"
)
@ -27,7 +28,7 @@ type TrainPcSim interface {
//发送驾驶端激活
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)
@ -38,7 +39,7 @@ type TrainPcSim interface {
CreateOrRemoveSpeedPLace(train *state_proto.TrainState)
CreateOrRemoveTrain(msgType byte, data []byte)
CreateOrRemoveTrain(msgType byte, data []byte) error
tpapi.ThirdPartyApiService
}
@ -102,18 +103,30 @@ func (d *trainPcSimService) readError(err error) {
}
func (d *trainPcSimService) connTrainPcSim() {
reconnIndex := 0
for {
client, err := tcp.StartTcpClient(fmt.Sprintf("%v:%v", d.config.PcSimIp, d.config.PcSimPort), d.reivceData, d.readError)
if err != nil {
reconnIndex++
slog.Error("连接车载pc平台失败尝试=", reconnIndex, err)
d.updateState(tpapi.ThirdPartyState_Broken)
} else {
d.pcSimClient = client
return
ctx, ctxFun := context.WithCancel(context.Background())
go func() {
for {
select {
case <-ctx.Done():
return
default:
}
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) {
config := pcSimManage.GetTrainPcSimConfig()
@ -127,7 +140,7 @@ func (d *trainPcSimService) Start(wd ecs.World, pcSimManage TrainPcSimManage) {
d.cancleContext = ctxFun
d.trainPcSimManage = pcSimManage
FireTrainControlEventType.Subscribe(wd, d.trainControlEventHandle)
//FireTrainControlEventType.Subscribe(wd, d.trainControlEventHandle)
d.updateState(tpapi.ThirdPartyState_Normal)
go d.sendTrainLocationAndSpeedTask(ctx)
@ -153,9 +166,10 @@ func (d *trainPcSimService) CreateOrRemoveSpeedPLace(train *state_proto.TrainSta
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)}
d.pcSimClient.Send(msg.Encode())
return d.pcSimClient.Send(msg.Encode())
}
// 依据文档80ms发送列车速度位置
@ -167,7 +181,8 @@ func (d *trainPcSimService) sendTrainLocationAndSpeedTask(ctx context.Context) {
default:
}
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
d.speedPlace.ParsePulseCount1(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())
}
}
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 {
msg := &message.TrainPcSimBaseMessage{}
newTraction := vobc.TractionForce
newBrake := vobc.BrakeForce
if isBrake {
if newBrake < oldBrakeForce && newBrake == 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 {
newBrake := -vobc.BrakeForce
newOldBrakeForce := -oldBrakeForce
if tractionState {
if newTraction <= oldTraction && newTraction == 0 {
//手柄取消前进
msg.Type = RECIVE_TRAIN_HAND_KEY_CANCLE_FORWARD
} else if newTraction > oldTraction {
//手柄前进
msg.Type = SENDER_TRAIN_HAND_KEY_FORWARD
} else {
//手柄前进
msg.Type = SENDER_TRAIN_HAND_KEY_FORWARD
}
} else {
if newBrake >= newOldBrakeForce && newBrake == 0 {
//手柄取消后退
msg.Type = RECIVE_TRAIN_HAND_KEY_CACLE_BACKWARD
} else if newBrake < newOldBrakeForce {
//手柄后退
msg.Type = RECIVE_TRAIN_HAND_KEY_BACKWARD
} else {
//手柄后退
msg.Type = RECIVE_TRAIN_HAND_KEY_BACKWARD
}
}
d.pcSimClient.Send(msg.Encode())
@ -238,6 +261,8 @@ func (d *trainPcSimService) SendBaliseData(msgType uint16, data []byte) {
msg := &message.TrainPcSimBaseMessage{}
msg.Type = msgType
msg.Data = data
//fmt.Println(fmt.Sprintf("%X", msg.Encode()))
d.pcSimClient.Send(msg.Encode())
}
@ -254,7 +279,13 @@ func (d *trainPcSimService) PublishTrainControlEvent(world ecs.World, events []T
return
}
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/service"
"joylink.club/bj-rtsts-server/third_party/can_btm"
"joylink.club/bj-rtsts-server/third_party/train_pc_sim"
"log/slog"
"math"
"reflect"
@ -149,11 +150,15 @@ func TrainConnTypeUpdate(vs *VerifySimulation, ct *dto.TrainConnThirdDto) {
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.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.ConnType = state_proto.TrainConnState_NONE
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,
trainEndsB dto.ConfigTrainEnds) {
@ -189,14 +199,17 @@ func copyTrainEnds(trainState *state_proto.TrainState, fieldName string, configD
}
endsVal.SpeedSensorEnableA = configData.SpeedSensorEnableA
endsVal.SpeedSensorEnableB = configData.SpeedSensorEnableB
endsVal.AccOutSpeed = configData.AccOutSpeed
endsVal.RadarEnable = configData.RadarEnable
endsVal.RadarCheckSpeedDiff = configData.RadarCheckSpeedDiff
endsVal.RadarCheckTime = configData.RadarCheckTime
endsVal.RadarCheckSpeedDiff = configData.RadarCheckSpeedDiff
endsVal.RadarOutSpeed = configData.RadarOutSpeed
endsVal.AccEnable = configData.AccEnable
endsVal.AccCheckSpeedDiff = configData.AccCheckSpeedDiff
endsVal.AccCheckTime = configData.AccCheckTime
endsVal.AccOutSpeed = configData.AccOutSpeed
endsVal.RadarOutSpeed = configData.RadarOutSpeed
}
func UpdateConfigTrain(vs *VerifySimulation, ct *dto.ConfigTrainReqDto) {
@ -213,6 +226,26 @@ func UpdateConfigTrain(vs *VerifySimulation, ct *dto.ConfigTrainReqDto) {
trainState.TrainLength = ct.Length
trainState.WheelDiameter = ct.WheelDiameter
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) {
@ -318,6 +351,7 @@ func UpdateTrainStateByDynamics(vs *VerifySimulation, trainId string, info *mess
sta.DynamicState.RampResistance = float32(info.SlopeResistance) / 1000
sta.DynamicState.CurveResistance = float32(info.CurveResistance) / 1000
sta.DynamicState.Speed = speedParse(info.Speed)
sta.DynamicState.HeadSensorSpeed1 = speedParse(info.HeadSpeed1)
sta.DynamicState.HeadSensorSpeed2 = speedParse(info.HeadSpeed2)
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.TailRadarSpeed = speedParse(info.TailRadarSpeed)
sta.DynamicState.Acceleration = info.Acceleration
sta.DynamicState.Displacement = int32(info.Displacement)
pluseCount(sta)
return sta
@ -334,24 +369,30 @@ func UpdateTrainStateByDynamics(vs *VerifySimulation, trainId string, info *mess
const RECEIVE_DYNAMIC_DATA_RATE = 15
func formatSpeedTime(s int32) int32 {
d3, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", s), 64)
return int32(math.Abs(math.Round(d3)))
//d3, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", s), 64)
return int32(math.Abs(math.Round(float64(s))))
}
func pluseCount(sta *state_proto.TrainState) {
if sta.PluseCount == nil {
return
}
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 {
sta.PluseCount.PulseCount1 += uint32(formatSpeedTime(sta.DynamicState.HeadSensorSpeed1 * RECEIVE_DYNAMIC_DATA_RATE))
} else if sta.TrainEndsA.SpeedSensorEnableB {
sta.PluseCount.PulseCount2 += uint32(formatSpeedTime(sta.DynamicState.HeadSensorSpeed2 * RECEIVE_DYNAMIC_DATA_RATE))
sta.PluseCount.PulseCount1 = sta.PluseCount.PulseCount1 + p1
}
if sta.TrainEndsA.SpeedSensorEnableB {
sta.PluseCount.PulseCount2 = sta.PluseCount.PulseCount2 + p2
}
} 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 {
sta.PluseCount.PulseCount1 += uint32(formatSpeedTime(sta.DynamicState.TailSensorSpeed1 * RECEIVE_DYNAMIC_DATA_RATE))
} else if sta.TrainEndsB.SpeedSensorEnableB {
sta.PluseCount.PulseCount2 += uint32(formatSpeedTime(sta.DynamicState.TailSensorSpeed2 * RECEIVE_DYNAMIC_DATA_RATE))
sta.PluseCount.PulseCount1 = sta.PluseCount.PulseCount1 + t1
}
if sta.TrainEndsB.SpeedSensorEnableB {
sta.PluseCount.PulseCount2 = sta.PluseCount.PulseCount2 + t2
}
}
}

View File

@ -4,20 +4,15 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"log/slog"
"math"
"sort"
"strconv"
"strings"
"sync"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/dto/data_proto"
"joylink.club/bj-rtsts-server/dto/state_proto"
"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/message"
"joylink.club/bj-rtsts-server/third_party/radar"
"joylink.club/bj-rtsts-server/third_party/semi_physical_train"
"joylink.club/ecs"
"joylink.club/rtsssimulation/component"
@ -25,6 +20,12 @@ import (
"joylink.club/rtsssimulation/fi"
"joylink.club/rtsssimulation/repository"
"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
}
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)
// 更新电机转速
electrical_machinery.Default().SendElectricMachineryMessage(&message.ElectricMachinery{
Speed: info.Speed,
WheelDiameter: trainState.WheelDiameter,
IsBack: trainState.VobcState.DirectionBackward,
})
if train.ConnState.Conn && train.ConnState.ConnType == state_proto.TrainConnState_VOBC {
semi_physical_train.Default().SendTrainControlMessage(info)
electrical_machinery.Default().SendElectricMachineryMessage2(info, trainState)
radar.Default().TrainSpeedSender(info, trainState)
acc.Default().TrainAccSender(info, trainState)
}
}
// 获取动力学配置信息
@ -509,8 +506,8 @@ func (s *VerifySimulation) FindTrainConnTypes() []dto.TrainConnTypeConfigDto {
}
// 获取电机转速参数
func (s *VerifySimulation) GetElectricMachineryRunConfig() *config.ElectricMachineryConfig {
return &s.runConfig.ElectricMachinery
func (s *VerifySimulation) GetElectricMachineryRunConfig() []config.ElectricMachineryConfig {
return s.runConfig.ElectricMachinerys
}
// 初始化仿真运行配置
@ -581,7 +578,7 @@ func (s *VerifySimulation) GetRunAccConfig() config.AccConfig {
}
// FindRadarTrain 查找一个列车 只有1端雷达开启啊
func (s *VerifySimulation) FindRadarTrain() *state_proto.TrainState {
/*func (s *VerifySimulation) FindRadarTrain() *state_proto.TrainState {
var trainStatus *state_proto.TrainState
s.Memory.Status.TrainStateMap.Range(func(k any, v any) bool {
val, ok := v.(*state_proto.TrainState)
@ -590,18 +587,11 @@ func (s *VerifySimulation) FindRadarTrain() *state_proto.TrainState {
trainStatus = val
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 trainStatus
}
}*/
// FindRadarTrain 查找一个列车 只有1端雷达开启啊
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 {
oldTraction := sta.VobcState.TractionForce
oldBrakeForce := sta.VobcState.BrakeForce
isBrake := ct.Handler.Val < 0 //是否制动
isTraction := ct.Handler.Val > 0 //是否制动
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 {
@ -96,7 +96,10 @@ func trainControlDirKey(trainState *state_proto.TrainState, request *request_pro
} else {
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)
return nil
}
if obj.Code == "SKQYS1" {
trainState.VobcState.Tc1Active = request.Val
} else if obj.Code == "SKQYS2" {
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
for _, k := range trainState.Tcc.DriverKey {
if k.Id == deviceId {
@ -141,17 +153,18 @@ func trainControlHandle(trainState *state_proto.TrainState, request *request_pro
trainState.VobcState.BrakeForce = 0
trainState.VobcState.MaintainBrakeStatus = false
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_BACKWORD, 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_TO_ZERO, Status: 0})
if request.Val > 0 {
trainState.VobcState.TractionStatus = true
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 {
trainState.VobcState.BrakingStatus = true
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})
} 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
if train.ConnState.Conn == false {
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)
return nil
}
// 门模式