Merge remote-tracking branch 'origin/local-test' into local-test
# Conflicts: # dto/state_proto/device_state.pb.go # rts-sim-testing-message
This commit is contained in:
commit
859561b6a7
@ -354,7 +354,7 @@ func controlTrain(c *gin.Context) {
|
||||
panic(sys_error.New("修改列车控制参数失败,请求参数异常", err))
|
||||
}
|
||||
simulation := checkDeviceDataAndReturn(req.SimulationId)
|
||||
memory.ControlTrainUpdate(simulation, req)
|
||||
simulation.ControlTrainUpdate(req)
|
||||
c.JSON(http.StatusOK, "ok")
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc v4.23.1
|
||||
// source: common_data.proto
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc v4.23.1
|
||||
// source: ibpGraphics.proto
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc v4.23.1
|
||||
// source: picture.proto
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc v4.23.1
|
||||
// source: pslGraphics.proto
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc v4.23.1
|
||||
// source: relayCabinetLayoutGraphics.proto
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc v4.23.1
|
||||
// source: stationLayoutGraphics.proto
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc v4.23.1
|
||||
// source: tccGraphics.proto
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc v4.23.1
|
||||
// source: request.proto
|
||||
|
||||
@ -1680,7 +1680,7 @@ type TrainControl struct {
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
SimulationId string `protobuf:"bytes,1,opt,name=simulationId,proto3" json:"simulationId,omitempty"` // 仿真id
|
||||
TrainId uint32 `protobuf:"varint,2,opt,name=trainId,proto3" json:"trainId,omitempty"`
|
||||
TrainId string `protobuf:"bytes,2,opt,name=trainId,proto3" json:"trainId,omitempty"`
|
||||
DeviceId uint32 `protobuf:"varint,3,opt,name=deviceId,proto3" json:"deviceId,omitempty"` //设备id
|
||||
ControlType TrainControl_TrainControlType `protobuf:"varint,4,opt,name=controlType,proto3,enum=request.TrainControl_TrainControlType" json:"controlType,omitempty"`
|
||||
Button *TrainControl_EmergentButton `protobuf:"bytes,5,opt,name=button,proto3" json:"button,omitempty"` // 紧急制动
|
||||
@ -1728,11 +1728,11 @@ func (x *TrainControl) GetSimulationId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *TrainControl) GetTrainId() uint32 {
|
||||
func (x *TrainControl) GetTrainId() string {
|
||||
if x != nil {
|
||||
return x.TrainId
|
||||
}
|
||||
return 0
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *TrainControl) GetDeviceId() uint32 {
|
||||
@ -2444,7 +2444,7 @@ var file_request_proto_rawDesc = []byte{
|
||||
0x6f, 0x6c, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x49,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x49, 0x64,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x49, 0x64,
|
||||
0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x0b,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,19 +12,6 @@ import (
|
||||
|
||||
// 综合后备盘IBP消息服务
|
||||
func NewTrainControlMs(vs *memory.VerifySimulation, mapId int32) ms_api.MsgTask {
|
||||
/* var findMapId int32 = 0
|
||||
for _, d := range vs.MapIds {
|
||||
mapData := memory.QueryGiType(d)
|
||||
if mapData == data_proto.PictureType_TrainControlCab {
|
||||
findMapId = d
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if findMapId == 0 {
|
||||
slog.Error("未找到对应的列城控制图形")
|
||||
return nil
|
||||
}*/
|
||||
return ms_api.NewScheduleTask(fmt.Sprintf("地图[%d]列车控制", mapId), func() error {
|
||||
allTrainMap := &vs.Memory.Status.TrainStateMap
|
||||
allTrainMap.Range(func(key, value any) bool {
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 9bfc176447d3ec921ab0e52dd7471c02142c8063
|
||||
Subproject commit 208bcaedccf71e7bfd2535e2889ca4cf7c4bdbb6
|
42
third_party/can_btm/balise_btm.go
vendored
42
third_party/can_btm/balise_btm.go
vendored
@ -46,7 +46,7 @@ type btmCanetClient struct {
|
||||
//最近一次车载ATP系统查询帧CRC16校验结果,true-校验通过
|
||||
atpReqCrc16Check bool
|
||||
//btm系统时间,每次接收到ATP查询请求帧时同步一次时间
|
||||
btmTime btmClock
|
||||
btmTime BtmClock
|
||||
//数据流水号
|
||||
dsn byte
|
||||
//重发的数据
|
||||
@ -57,6 +57,7 @@ type btmCanetClient struct {
|
||||
|
||||
func (s *btmCanetClient) GetState() state_proto.BTMState {
|
||||
detector := s.baliseDetector
|
||||
|
||||
var telegram string
|
||||
info := detector.eq[len(detector.eq)-1]
|
||||
if /*detector.aboveBalise &&*/ info != nil && len(info.telegram) != 0 {
|
||||
@ -69,17 +70,19 @@ func (s *btmCanetClient) GetState() state_proto.BTMState {
|
||||
BaliseCount: uint32(detector.baliseCounter),
|
||||
MessageCounter: uint32(detector.messageCounter),
|
||||
Telegram: telegram,
|
||||
Distance: info.Distance,
|
||||
AboveBalise: detector.aboveBalise,
|
||||
}
|
||||
}
|
||||
|
||||
type btmClock struct {
|
||||
btmTk uint32 //与ATP系统同步的时间ms
|
||||
sysTk time.Time //本地系统时间
|
||||
type BtmClock struct {
|
||||
BtmTk uint32 //与ATP系统同步的时间ms
|
||||
SysTk time.Time //本地系统时间
|
||||
}
|
||||
|
||||
// 获取以btmTk为基准的当前时间ms
|
||||
func (c *btmClock) tkNow() uint32 {
|
||||
return c.btmTk + uint32(time.Now().UnixMilli()-c.sysTk.UnixMilli())
|
||||
func (c *BtmClock) TkNow() uint32 {
|
||||
return c.BtmTk + uint32(time.Now().UnixMilli()-c.SysTk.UnixMilli())
|
||||
}
|
||||
|
||||
type BtmCanetClient interface {
|
||||
@ -87,7 +90,7 @@ type BtmCanetClient interface {
|
||||
Stop()
|
||||
//HandleTrainHeadPositionInfo 处理收到列车位置信息
|
||||
HandleTrainHeadPositionInfo(w ecs.World, h *TrainHeadPositionInfo)
|
||||
//获取BTM显示状态
|
||||
//获取BTM显示状态 + btm最新的状态
|
||||
GetState() state_proto.BTMState
|
||||
}
|
||||
|
||||
@ -156,7 +159,7 @@ func (s *btmCanetClient) handleCanetFrames(cfs []byte) {
|
||||
dms := make([]*message.CanetFrame, 0, 16) //13个应答器报文数据帧+TimeA帧+TimeB帧+结束帧
|
||||
for cfi := 0; cfi < cfSum; cfi++ {
|
||||
cfStart := cfi * 13
|
||||
cf := message.NewCanetFrame(cfs[cfStart : cfStart+13])
|
||||
cf := message.NewCanetFrame(cfs[cfStart:cfStart+13], false)
|
||||
//
|
||||
switch cf.CanFrameType() {
|
||||
case message.CfReq:
|
||||
@ -206,8 +209,8 @@ func (s *btmCanetClient) dealWithAptReq(f *message.CanetFrame) {
|
||||
//处理查询请求
|
||||
//slog.Debug(fmt.Sprintf("处理查询请求:%s", atpReq.String()))
|
||||
//
|
||||
s.btmTime.btmTk = atpReq.Time
|
||||
s.btmTime.sysTk = now
|
||||
s.btmTime.BtmTk = atpReq.Time
|
||||
s.btmTime.SysTk = now
|
||||
s.atpReqSn = atpReq.FId.ID4
|
||||
s.atpReqCrc16Check = atpReq.Crc16CheckOk
|
||||
s.baliseDetector.powerAmplifierSwitch = atpReq.PowerAmplifierTurnOn
|
||||
@ -256,14 +259,14 @@ func (s *btmCanetClient) rspResendToAtp() {
|
||||
// 当未收到应答器报文时响应:时间同步帧、状态应答帧
|
||||
func (s *btmCanetClient) rspToAtp(sb *BtmAntennaScanningBaliseInfo) {
|
||||
//BTM状态
|
||||
statusF := message.NewBtmStatusRspFrame(s.atpReqSn)
|
||||
statusF := message.NewBtmStatusRspFrame(s.atpReqSn, false)
|
||||
btmStatus := s.createTrainBtmStatus()
|
||||
|
||||
statusF.AntennaFault = btmStatus.AntennaFault
|
||||
statusF.BaliseCounter = byte(btmStatus.BaliseCounter)
|
||||
statusF.MessageCounter = byte(btmStatus.MessageCounter)
|
||||
statusF.PowerAmplifierOn = btmStatus.PowerAmplifierOn
|
||||
statusF.TkTimeA = s.btmTime.tkNow()
|
||||
statusF.TkTimeA = s.btmTime.TkNow()
|
||||
statusF.PowerAmplifierFailure = btmStatus.PowerAmplifierFault
|
||||
statusF.DetailedCode = 0
|
||||
if btmStatus.AboveBalise {
|
||||
@ -271,16 +274,17 @@ func (s *btmCanetClient) rspToAtp(sb *BtmAntennaScanningBaliseInfo) {
|
||||
}
|
||||
statusF.AtpReqCrcCheckWrong = !s.atpReqCrc16Check
|
||||
statusF.Dsn = s.dsn
|
||||
|
||||
s.dsnAdd1()
|
||||
//
|
||||
//true-收到应答器报文
|
||||
isRcvTelegram := sb != nil && len(sb.telegram) > 0
|
||||
if isRcvTelegram { //当收到应答器报文时响应:时间同步帧、状态应答帧、数据帧
|
||||
statusDataCf, statusDataCfOk := message.CreateBtmRspFramesData(statusF, sb.telegram, false, s.btmTime.tkNow(), s.btmTime.tkNow(), s.btmTime.tkNow())
|
||||
statusDataCf, statusDataCfOk := message.CreateBtmRspFramesData(statusF, sb.telegram, false, s.btmTime.TkNow(), s.btmTime.TkNow(), s.btmTime.TkNow(), false)
|
||||
if statusDataCfOk {
|
||||
timeSyncF := message.NewBtmTimeSyncCheckFrame(s.atpReqSn)
|
||||
timeSyncF.T2 = s.btmTime.btmTk
|
||||
timeSyncF.T3 = s.btmTime.tkNow()
|
||||
timeSyncF := message.NewBtmTimeSyncCheckFrame(s.atpReqSn, false)
|
||||
timeSyncF.T2 = s.btmTime.BtmTk
|
||||
timeSyncF.T3 = s.btmTime.TkNow()
|
||||
s.sendCanetFrame(timeSyncF.Encode().Encode())
|
||||
//
|
||||
s.resendData = newResendData(statusDataCf)
|
||||
@ -289,9 +293,9 @@ func (s *btmCanetClient) rspToAtp(sb *BtmAntennaScanningBaliseInfo) {
|
||||
slog.Warn("BtmCanetClient应答帧、数据帧编码失败")
|
||||
}
|
||||
} else { //当未收到应答器报文时响应:时间同步帧、状态应答帧
|
||||
timeSyncF := message.NewBtmTimeSyncCheckFrame(s.atpReqSn)
|
||||
timeSyncF.T2 = s.btmTime.btmTk
|
||||
timeSyncF.T3 = s.btmTime.tkNow()
|
||||
timeSyncF := message.NewBtmTimeSyncCheckFrame(s.atpReqSn, false)
|
||||
timeSyncF.T2 = s.btmTime.BtmTk
|
||||
timeSyncF.T3 = s.btmTime.TkNow()
|
||||
s.sendCanetFrame(timeSyncF.Encode().Encode())
|
||||
//
|
||||
statusCf := statusF.Encode().Encode()
|
||||
|
3
third_party/can_btm/balise_detection.go
vendored
3
third_party/can_btm/balise_detection.go
vendored
@ -41,6 +41,7 @@ type BtmAntennaScanningBaliseInfo struct {
|
||||
Time time.Time //应答器预计被BTM天线激活的时刻
|
||||
active bool //true-激活过,即列车扫过
|
||||
telegram []byte //应答器报文
|
||||
Distance int64 //BTM天线中心到应答器的距离,mm
|
||||
}
|
||||
|
||||
// BaliseDetector 车载BTM天线,应答器探测器
|
||||
@ -185,7 +186,7 @@ func (t *BaliseDetector) timeScanNearestBalise(curTime time.Time, wd *component.
|
||||
s := float64(expectedBalise.Distance) / 1000
|
||||
st, ok := t.calculateBtmAntennaScanNextBaliseTime(curTime, curV, curAc, s)
|
||||
if ok {
|
||||
return &BtmAntennaScanningBaliseInfo{BaliseId: expectedBalise.BaliseId, Time: st}
|
||||
return &BtmAntennaScanningBaliseInfo{BaliseId: expectedBalise.BaliseId, Time: st, Distance: expectedBalise.Distance}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
20
third_party/message/can_btm_data.go
vendored
20
third_party/message/can_btm_data.go
vendored
@ -9,15 +9,18 @@ type BtmDataMessageFrame struct {
|
||||
FId CanFrameId
|
||||
//8字节,应答器报文片段
|
||||
Message []byte
|
||||
IsTrainPcSim bool
|
||||
}
|
||||
|
||||
func NewBtmDataMessageFrame(sn byte, offset byte) *BtmDataMessageFrame {
|
||||
func NewBtmDataMessageFrame(sn byte, offset byte, isTrainPcSim bool) *BtmDataMessageFrame {
|
||||
return &BtmDataMessageFrame{
|
||||
FId: *NewCanFrameId(CAN_ADDR_RSP_ATP, CAN_ADDR_RSP_BTM, 0x80+offset, sn),
|
||||
IsTrainPcSim: isTrainPcSim,
|
||||
}
|
||||
}
|
||||
func (f *BtmDataMessageFrame) Encode() *CanetFrame {
|
||||
cf := &CanetFrame{}
|
||||
cf.IsTrainPcSim = f.IsTrainPcSim
|
||||
cf.CanId = f.FId
|
||||
cf.CanLen = 8
|
||||
cf.FF = true
|
||||
@ -60,15 +63,18 @@ type BtmDataMessageTimeAFrame struct {
|
||||
TimeA uint32
|
||||
//CRC
|
||||
Crc32A uint32
|
||||
IsTrainPcSim bool
|
||||
}
|
||||
|
||||
func NewBtmDataMessageTimeAFrame(sn byte) *BtmDataMessageTimeAFrame {
|
||||
func NewBtmDataMessageTimeAFrame(sn byte, isTrainPcSim bool) *BtmDataMessageTimeAFrame {
|
||||
return &BtmDataMessageTimeAFrame{
|
||||
FId: *NewCanFrameId(CAN_ADDR_RSP_ATP, CAN_ADDR_RSP_BTM, 0x80+0x0d, sn),
|
||||
IsTrainPcSim: isTrainPcSim,
|
||||
}
|
||||
}
|
||||
func (f *BtmDataMessageTimeAFrame) Encode() *CanetFrame {
|
||||
cf := &CanetFrame{}
|
||||
cf.IsTrainPcSim = f.IsTrainPcSim
|
||||
cf.CanId = f.FId
|
||||
cf.CanLen = 8
|
||||
cf.FF = true
|
||||
@ -162,15 +168,18 @@ type BtmDataMessageTimeBFrame struct {
|
||||
TimeB uint32
|
||||
//CRC
|
||||
Crc32B uint32
|
||||
IsTrainPcSim bool
|
||||
}
|
||||
|
||||
func NewBtmDataMessageTimeBFrame(sn byte) *BtmDataMessageTimeBFrame {
|
||||
func NewBtmDataMessageTimeBFrame(sn byte, isTrainPcSim bool) *BtmDataMessageTimeBFrame {
|
||||
return &BtmDataMessageTimeBFrame{
|
||||
FId: *NewCanFrameId(CAN_ADDR_RSP_ATP, CAN_ADDR_RSP_BTM, 0x80+0x0e, sn),
|
||||
IsTrainPcSim: isTrainPcSim,
|
||||
}
|
||||
}
|
||||
func (f *BtmDataMessageTimeBFrame) Encode() *CanetFrame {
|
||||
cf := &CanetFrame{}
|
||||
cf.IsTrainPcSim = f.IsTrainPcSim
|
||||
cf.CanId = f.FId
|
||||
cf.CanLen = 8
|
||||
cf.FF = true
|
||||
@ -264,15 +273,18 @@ type BtmDataMessageEndFrame struct {
|
||||
//CRC32C校验包含对状态应答帧与数据帧的总校验,总共为8×17-4=132字节,4-即Crc32C
|
||||
//1个状态应答帧 + 13个BtmDataMessageFrame + 1个BtmDataMessageTimeAFrame + 1个BtmDataMessageTimeBFrame + 1个BtmDataMessageEndFrame
|
||||
Crc32C uint32
|
||||
IsTrainPcSim bool
|
||||
}
|
||||
|
||||
func NewBtmDataMessageEndFrame(sn byte) *BtmDataMessageEndFrame {
|
||||
func NewBtmDataMessageEndFrame(sn byte, isTrainPcSim bool) *BtmDataMessageEndFrame {
|
||||
return &BtmDataMessageEndFrame{
|
||||
FId: *NewCanFrameId(CAN_ADDR_RSP_ATP, CAN_ADDR_RSP_BTM, 0x80+0x7f, sn),
|
||||
IsTrainPcSim: isTrainPcSim,
|
||||
}
|
||||
}
|
||||
func (f *BtmDataMessageEndFrame) Encode() *CanetFrame {
|
||||
cf := &CanetFrame{}
|
||||
cf.IsTrainPcSim = f.IsTrainPcSim
|
||||
cf.CanId = f.FId
|
||||
cf.CanLen = 8
|
||||
cf.FF = true
|
||||
|
11
third_party/message/can_btm_rsp.go
vendored
11
third_party/message/can_btm_rsp.go
vendored
@ -8,16 +8,17 @@ import "log/slog"
|
||||
// 共17帧,17X12个字节,每个帧12字节
|
||||
// msg - 应答器报文
|
||||
// msgPackError - true BTM解包发生错误,则数据帧及CRC32A/B全填“0xFF”
|
||||
func CreateBtmRspFramesData(statusRsp *BtmStatusRspFrame, msg []byte, msgPackError bool, msgTimeA uint32, msgTimeB uint32, tkTimeB uint32) ([]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个字节
|
||||
return nil, false
|
||||
}
|
||||
//最近一次ATP查询请求序列号
|
||||
sn := statusRsp.FId.ID4
|
||||
//13个BtmDataMessageFrame [0x00,0x0c]
|
||||
//数据
|
||||
dms := make([]*BtmDataMessageFrame, 13)
|
||||
for mr := 0x00; mr <= 0x0c; mr++ {
|
||||
dms[mr] = NewBtmDataMessageFrame(sn, byte(mr))
|
||||
dms[mr] = NewBtmDataMessageFrame(sn, byte(mr), isTrainPcSim)
|
||||
dms[mr].Message = make([]byte, 8) //8字节数组,默认值0
|
||||
//
|
||||
if !msgPackError {
|
||||
@ -38,7 +39,7 @@ func CreateBtmRspFramesData(statusRsp *BtmStatusRspFrame, msg []byte, msgPackErr
|
||||
}
|
||||
}
|
||||
//
|
||||
dtA := NewBtmDataMessageTimeAFrame(sn)
|
||||
dtA := NewBtmDataMessageTimeAFrame(sn, isTrainPcSim)
|
||||
dtA.TimeA = msgTimeA
|
||||
if !msgPackError {
|
||||
var crc32AData []byte
|
||||
@ -49,7 +50,7 @@ func CreateBtmRspFramesData(statusRsp *BtmStatusRspFrame, msg []byte, msgPackErr
|
||||
dtA.Crc32A = 0xff_ff_ff_ff
|
||||
}
|
||||
//
|
||||
dtB := NewBtmDataMessageTimeBFrame(sn)
|
||||
dtB := NewBtmDataMessageTimeBFrame(sn, isTrainPcSim)
|
||||
dtB.TimeB = msgTimeB
|
||||
if !msgPackError {
|
||||
var crc32BData []byte
|
||||
@ -60,7 +61,7 @@ func CreateBtmRspFramesData(statusRsp *BtmStatusRspFrame, msg []byte, msgPackErr
|
||||
dtB.Crc32B = 0xff_ff_ff_ff
|
||||
}
|
||||
//
|
||||
end := NewBtmDataMessageEndFrame(sn)
|
||||
end := NewBtmDataMessageEndFrame(sn, isTrainPcSim)
|
||||
end.TkB = tkTimeB
|
||||
//
|
||||
statusCf := statusRsp.Encode()
|
||||
|
5
third_party/message/can_btm_status_rsp.go
vendored
5
third_party/message/can_btm_status_rsp.go
vendored
@ -27,11 +27,13 @@ type BtmStatusRspFrame struct {
|
||||
DetailedCode byte
|
||||
//有具体报文内容时TK A时刻填充为CD信号上升沿时刻,报文全零时TK A时刻填充为CD信号下降沿时刻。
|
||||
TkTimeA uint32
|
||||
IsTrainPcSim bool
|
||||
}
|
||||
|
||||
func NewBtmStatusRspFrame(sn byte) *BtmStatusRspFrame {
|
||||
func NewBtmStatusRspFrame(sn byte, isTrainPcSim bool) *BtmStatusRspFrame {
|
||||
return &BtmStatusRspFrame{
|
||||
FId: *NewCanFrameId(CAN_ADDR_RSP_ATP, CAN_ADDR_RSP_BTM, CAN_FRAME_STATUS_RSP, sn),
|
||||
IsTrainPcSim: isTrainPcSim,
|
||||
}
|
||||
}
|
||||
func (f *BtmStatusRspFrame) Decode(cf *CanetFrame) bool {
|
||||
@ -113,6 +115,7 @@ func (f *BtmStatusRspFrame) Decode(cf *CanetFrame) bool {
|
||||
}
|
||||
func (f *BtmStatusRspFrame) Encode() *CanetFrame {
|
||||
cf := &CanetFrame{}
|
||||
cf.IsTrainPcSim = f.IsTrainPcSim
|
||||
cf.CanId = f.FId
|
||||
cf.CanLen = 8
|
||||
cf.FF = true
|
||||
|
5
third_party/message/can_btm_time_sync_rsp.go
vendored
5
third_party/message/can_btm_time_sync_rsp.go
vendored
@ -15,11 +15,13 @@ type BtmTimeSyncCheckFrame struct {
|
||||
//T3时刻
|
||||
//BTM将在T3时刻发送回复帧给ATP,并保持流水号与ATP查询帧一致。
|
||||
T3 uint32
|
||||
IsTrainPcSim bool
|
||||
}
|
||||
|
||||
func NewBtmTimeSyncCheckFrame(sn byte) *BtmTimeSyncCheckFrame {
|
||||
func NewBtmTimeSyncCheckFrame(sn byte, isTrainPcSim bool) *BtmTimeSyncCheckFrame {
|
||||
return &BtmTimeSyncCheckFrame{
|
||||
FId: *NewCanFrameId(CAN_ADDR_RSP_ATP, CAN_ADDR_RSP_BTM, CAN_FRAME_TIME_SYNC_RSP, sn),
|
||||
IsTrainPcSim: isTrainPcSim,
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +78,7 @@ func (f *BtmTimeSyncCheckFrame) Decode(cf *CanetFrame) bool {
|
||||
}
|
||||
func (f *BtmTimeSyncCheckFrame) Encode() *CanetFrame {
|
||||
cf := &CanetFrame{}
|
||||
cf.IsTrainPcSim = f.IsTrainPcSim
|
||||
cf.CanId = f.FId
|
||||
cf.CanLen = 8
|
||||
cf.FF = true
|
||||
|
17
third_party/message/can_net.go
vendored
17
third_party/message/can_net.go
vendored
@ -13,15 +13,17 @@ type CanetFrame struct {
|
||||
CanLen byte //CAN帧数据长度[0,8],CanData中有效数据字节数
|
||||
CanId CanFrameId //CAN帧ID
|
||||
CanData []byte //CAN帧数据,8字节
|
||||
IsTrainPcSim bool //是否列车pc仿真
|
||||
}
|
||||
|
||||
func NewCanetFrame(buf []byte) *CanetFrame {
|
||||
cf := &CanetFrame{}
|
||||
func NewCanetFrame(buf []byte, isTrainPcSim bool) *CanetFrame {
|
||||
cf := &CanetFrame{IsTrainPcSim: isTrainPcSim}
|
||||
cf.Decode(buf)
|
||||
return cf
|
||||
}
|
||||
func (p *CanetFrame) Encode() []byte {
|
||||
buf := make([]byte, 0, 13)
|
||||
buf := make([]byte, 0)
|
||||
if !p.IsTrainPcSim {
|
||||
//canet200帧信息
|
||||
b1 := byte(0x00)
|
||||
if p.FF {
|
||||
@ -32,6 +34,7 @@ func (p *CanetFrame) Encode() []byte {
|
||||
}
|
||||
b1 |= p.CanLen & 0x0f
|
||||
buf = append(buf, b1)
|
||||
}
|
||||
//CAN 帧ID
|
||||
buf = append(buf, p.CanId.ID1)
|
||||
buf = append(buf, p.CanId.ID2)
|
||||
@ -44,13 +47,17 @@ func (p *CanetFrame) Encode() []byte {
|
||||
buf = append(buf, p.CanData...)
|
||||
return buf
|
||||
}
|
||||
|
||||
func (p *CanetFrame) Decode(buf []byte) {
|
||||
if len(buf) != 13 {
|
||||
panic("len(buf)!=13")
|
||||
}
|
||||
//
|
||||
if !p.IsTrainPcSim {
|
||||
p.FF = buf[0]&0x80 == 0x80
|
||||
p.RTR = buf[0]&0x40 == 0x40
|
||||
}
|
||||
|
||||
p.CanLen = buf[0] & 0x0f
|
||||
//1 2 3 4
|
||||
p.CanId.ID1 = buf[1]
|
||||
@ -62,8 +69,8 @@ func (p *CanetFrame) Decode(buf []byte) {
|
||||
}
|
||||
func (p *CanetFrame) String() string {
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString(fmt.Sprintf("CanetFrame FF = %t, RTR = %t, CanLen = %d, ID1 = 0x%0x, ID2 = 0x%0x, ID3 = 0x%0x, ID4 = 0x%0x,", p.FF, p.RTR, p.CanLen,
|
||||
p.CanId.ID1, p.CanId.ID2, p.CanId.ID3, p.CanId.ID4))
|
||||
sb.WriteString(fmt.Sprintf("CanetFrame FF = %t, RTR = %t, CanLen = %d, ID1 = 0x%0x, ID2 = 0x%0x, ID3 = 0x%0x, ID4 = 0x%0x, isTrainPcSim=%v", p.FF, p.RTR, p.CanLen,
|
||||
p.CanId.ID1, p.CanId.ID2, p.CanId.ID3, p.CanId.ID4, p.IsTrainPcSim))
|
||||
sb.WriteString("CanData = ")
|
||||
for _, d := range p.CanData {
|
||||
sb.WriteString(fmt.Sprintf(" 0x%0x ", d))
|
||||
|
57
third_party/tcp/tcp_client.go
vendored
Normal file
57
third_party/tcp/tcp_client.go
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
)
|
||||
|
||||
type TcpClient struct {
|
||||
conn *net.TCPConn
|
||||
handler func(n int, data []byte)
|
||||
}
|
||||
|
||||
func StartTcpClient(rAddr string, handler func(n int, data []byte)) (*TcpClient, error) {
|
||||
raddr, addErr := net.ResolveTCPAddr("tcp", rAddr)
|
||||
if addErr != nil {
|
||||
return nil, addErr
|
||||
}
|
||||
conn, err := net.DialTCP("tcp", nil, raddr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
data := make([]byte, 1024)
|
||||
l, err := conn.Read(data)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
slog.Warn(fmt.Sprintf("TCP客户端[rAddr:%s]断开连接:", rAddr))
|
||||
break
|
||||
}
|
||||
slog.Error(fmt.Sprintf("TCP客户端[rAddr:%s]读取数据异常:", rAddr), err)
|
||||
}
|
||||
handler(l, data)
|
||||
}
|
||||
}()
|
||||
return &TcpClient{conn: conn}, nil
|
||||
}
|
||||
func (c *TcpClient) Close() {
|
||||
if c.conn != nil {
|
||||
c.conn.Close()
|
||||
c.conn = nil
|
||||
slog.Info(fmt.Sprintf("TCP客户端[rAddr:%s]关闭连接", c.conn.RemoteAddr().String()))
|
||||
} else {
|
||||
slog.Info(fmt.Sprintf("TCP客户端[rAddr:%s]未连接", c.conn.RemoteAddr().String()))
|
||||
}
|
||||
}
|
||||
func (c *TcpClient) Send(data []byte) error {
|
||||
_, err := c.conn.Write(data)
|
||||
if err != nil {
|
||||
slog.Error("udp client send error", "error", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
14
third_party/tcp/tcp_message.go
vendored
Normal file
14
third_party/tcp/tcp_message.go
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
package tcp
|
||||
|
||||
type TcpMessageCodec interface {
|
||||
TcpMessageEncoder
|
||||
TcpMessageDecoder
|
||||
}
|
||||
|
||||
type TcpMessageEncoder interface {
|
||||
Encode() []byte
|
||||
}
|
||||
|
||||
type TcpMessageDecoder interface {
|
||||
Decode(data []byte) error
|
||||
}
|
190
third_party/train_pc_sim/train_pc_sim.go
vendored
Normal file
190
third_party/train_pc_sim/train_pc_sim.go
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
package train_pc_sim
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"joylink.club/bj-rtsts-server/config"
|
||||
"joylink.club/bj-rtsts-server/dto/state_proto"
|
||||
"joylink.club/bj-rtsts-server/third_party/tcp"
|
||||
"joylink.club/ecs"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TrainPcSim interface {
|
||||
Start(pcSimManage TrainPcSimManage)
|
||||
Stop()
|
||||
SendDriverActive(tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState)
|
||||
SendHandleSwitch(oldTraction, oldBrakeForce int64, tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState)
|
||||
SendBaliseData(msgType uint16, data []byte)
|
||||
PublishTrainControlEvent(world ecs.World, events []TrainControlEvent)
|
||||
}
|
||||
|
||||
type TrainPcSimManage interface {
|
||||
GetTrainPcSimConfig() config.VehiclePCSimConfig
|
||||
//4.4.1. 车载输出数字量信息报文内容
|
||||
TrainPcSimDigitalOutInfoHandle(data []byte)
|
||||
//4.4.2. 车载输出数字反馈量信息报文内容
|
||||
TrainPcSimDigitalReportHandle(data []byte)
|
||||
//创建/删除列车
|
||||
TrainPcSimConnOrRemoveHandle(state byte)
|
||||
//门模式
|
||||
TrainDoorModeHandle(state byte)
|
||||
TrainPcSimMockInfo(data []byte)
|
||||
|
||||
TrainBtmQuery(data []byte)
|
||||
}
|
||||
|
||||
var (
|
||||
initLock = &sync.Mutex{}
|
||||
singleObj *trainPcSimService
|
||||
)
|
||||
|
||||
func Default() TrainPcSim {
|
||||
defer initLock.Unlock()
|
||||
initLock.Lock()
|
||||
if singleObj == nil {
|
||||
singleObj = &trainPcSimService{}
|
||||
}
|
||||
return singleObj
|
||||
}
|
||||
|
||||
type trainPcSimService struct {
|
||||
pcSimClient *tcp.TcpClient
|
||||
cancleContext context.CancelFunc
|
||||
trainPcSimManage TrainPcSimManage
|
||||
}
|
||||
|
||||
func (pc *trainPcSimService) Start(pcSimManage TrainPcSimManage) {
|
||||
config := pcSimManage.GetTrainPcSimConfig()
|
||||
if config.PcSimIp == "" || !config.Open {
|
||||
slog.Info("车载pc仿真配置未开启")
|
||||
return
|
||||
}
|
||||
|
||||
client, err := tcp.StartTcpClient(fmt.Sprintf("%v:%v", config.PcSimIp, config.PcSimPort), pc.reivceData)
|
||||
if err != nil {
|
||||
slog.Error("连接车载pc平台失败", err)
|
||||
return
|
||||
}
|
||||
pc.pcSimClient = client
|
||||
ctx, ctxFun := context.WithCancel(context.Background())
|
||||
pc.cancleContext = ctxFun
|
||||
pc.trainPcSimManage = pcSimManage
|
||||
//vs := pcSimManage.(*memory.VerifySimulation)
|
||||
//FireTrainControlEventType.Subscribe(vs.World, pc.trainControlEventHandle)
|
||||
|
||||
go pc.sendTrainLocationAndSpeedTask(ctx)
|
||||
}
|
||||
func (pc *trainPcSimService) Stop() {
|
||||
if pc.cancleContext != nil {
|
||||
pc.cancleContext()
|
||||
pc.cancleContext = nil
|
||||
}
|
||||
pc.pcSimClient.Close()
|
||||
}
|
||||
|
||||
// 依据文档80ms发送列车速度位置
|
||||
func (pc *trainPcSimService) sendTrainLocationAndSpeedTask(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
/* trainStatus := acc.radarVobcManager.FindAccTrain()
|
||||
if trainStatus != nil {
|
||||
speedAcc := trainStatus.DynamicState.Acceleration
|
||||
t := speedAcc / accSpeedUnit
|
||||
acc.vobcClient.SendMsg(&message.Accelerometer{Acc: math.Float32bits(t)})
|
||||
}*/
|
||||
time.Sleep(time.Millisecond * 80)
|
||||
}
|
||||
}
|
||||
func (pc *trainPcSimService) SendDriverActive(tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState) {
|
||||
if tc.Conn && tc.ConnType == state_proto.TrainConnState_PC_SIM {
|
||||
defulatBuf := make([]byte, 0)
|
||||
msg := &TrainPcSimBaseMessage{Data: defulatBuf}
|
||||
if vobc.Tc1Active || vobc.Tc2Active {
|
||||
msg.Type = SENDER_TRAIN_TC_ACTIVE
|
||||
} else if vobc.Tc1Active == false && vobc.Tc2Active == false {
|
||||
msg.Type = SENDER_TRAIN_TC_NOT_ACTIVE
|
||||
}
|
||||
pc.pcSimClient.Send(msg.Encode())
|
||||
}
|
||||
}
|
||||
func (pc *trainPcSimService) SendHandleSwitch(oldTraction, oldBrakeForce int64, tc *state_proto.TrainConnState, vobc *state_proto.TrainVobcState) {
|
||||
if tc.Conn && tc.ConnType == state_proto.TrainConnState_PC_SIM {
|
||||
msg := &TrainPcSimBaseMessage{}
|
||||
newTraction := vobc.TractionForce
|
||||
newBrake := vobc.BrakeForce
|
||||
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 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 {
|
||||
slog.Error("")
|
||||
return
|
||||
}
|
||||
pc.pcSimClient.Send(msg.Encode())
|
||||
}
|
||||
}
|
||||
|
||||
func (pc *trainPcSimService) SendBaliseData(msgType uint16, data []byte) {
|
||||
msg := &TrainPcSimBaseMessage{}
|
||||
msg.Type = msgType
|
||||
msg.Data = data
|
||||
pc.pcSimClient.Send(msg.Encode())
|
||||
}
|
||||
|
||||
func (pc *trainPcSimService) trainControlEventHandle(w ecs.World, event TrainControlEvent) {
|
||||
msg := &TrainPcSimBaseMessage{}
|
||||
msg.Type = SENDER_TRAIN_OUTR_INFO
|
||||
data := []byte{event.Command, event.Status}
|
||||
msg.Data = data
|
||||
pc.pcSimClient.Send(msg.Encode())
|
||||
}
|
||||
func (pc *trainPcSimService) PublishTrainControlEvent(world ecs.World, events []TrainControlEvent) {
|
||||
if len(events) <= 0 {
|
||||
slog.Warn("")
|
||||
return
|
||||
}
|
||||
for _, event := range events {
|
||||
FireTrainControlEventType.Publish(world, &event)
|
||||
}
|
||||
}
|
||||
|
||||
// 接受来自pc仿真的消息
|
||||
func (pc *trainPcSimService) reivceData(len int, data []byte) {
|
||||
baseMsg := &TrainPcSimBaseMessage{}
|
||||
err := baseMsg.Decode(data)
|
||||
if err != nil {
|
||||
slog.Error("车载pc仿真接受数据解析失败 ")
|
||||
return
|
||||
}
|
||||
|
||||
switch baseMsg.Type {
|
||||
case RECIVE_TRAIN_CREATE_REMOVE:
|
||||
pc.trainPcSimManage.TrainPcSimConnOrRemoveHandle(data[0])
|
||||
case RECIVE_TRAIN_INTERFACE_CABINET_OUTR:
|
||||
pc.trainPcSimManage.TrainPcSimDigitalOutInfoHandle(data)
|
||||
case RECIVE_TRAIN_INTERFACE_CABINET_OUTR_BACK:
|
||||
pc.trainPcSimManage.TrainPcSimDigitalReportHandle(data)
|
||||
case RECIVE_TRAIN_QUERY_STATUS:
|
||||
pc.trainPcSimManage.TrainBtmQuery(data)
|
||||
case RECIVE_TRAIN_MOCK_DATA:
|
||||
pc.trainPcSimManage.TrainPcSimMockInfo(data)
|
||||
case RECIVE_TRAIN_DOOR_MODE:
|
||||
pc.trainPcSimManage.TrainDoorModeHandle(data[0])
|
||||
}
|
||||
|
||||
}
|
95
third_party/train_pc_sim/train_pc_sim_message.go
vendored
Normal file
95
third_party/train_pc_sim/train_pc_sim_message.go
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
package train_pc_sim
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/snksoft/crc"
|
||||
"joylink.club/bj-rtsts-server/third_party/message"
|
||||
)
|
||||
|
||||
const PC_SIM_HEADER = 0xEB
|
||||
|
||||
type TrainPcSimBaseMessage struct {
|
||||
Type uint16
|
||||
DataLen byte
|
||||
Data []byte
|
||||
Crc uint16 // 校验码
|
||||
}
|
||||
|
||||
// 编码
|
||||
func (tp *TrainPcSimBaseMessage) Encode() []byte {
|
||||
pack := make([]byte, 0)
|
||||
pack = append(pack, PC_SIM_HEADER)
|
||||
pack = binary.BigEndian.AppendUint16(pack, tp.Type)
|
||||
pack = append(pack, byte(len(tp.Data)))
|
||||
dataBufs := bytes.NewBuffer(tp.Data)
|
||||
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
|
||||
}
|
||||
|
||||
// 解码
|
||||
func (tp *TrainPcSimBaseMessage) Decode(data []byte) error {
|
||||
if len(data) < 3 {
|
||||
return fmt.Errorf("")
|
||||
}
|
||||
buf := bytes.NewBuffer(data)
|
||||
h, _ := buf.ReadByte()
|
||||
if h != PC_SIM_HEADER {
|
||||
return fmt.Errorf("")
|
||||
}
|
||||
var pcType uint16
|
||||
binary.Read(buf, binary.BigEndian, &pcType)
|
||||
len, _ := buf.ReadByte()
|
||||
if buf.Len() < int(len)+2 {
|
||||
return fmt.Errorf("")
|
||||
}
|
||||
var dd = make([]byte, 0, len)
|
||||
binary.Read(buf, binary.BigEndian, &dd)
|
||||
var crcCode uint16
|
||||
binary.Read(buf, binary.BigEndian, &crcCode)
|
||||
tp.Type = pcType
|
||||
tp.DataLen = len
|
||||
tp.Data = dd
|
||||
tp.Crc = crcCode
|
||||
return nil
|
||||
//crc.CalculateCRC(crc.CRC16, data)
|
||||
}
|
||||
|
||||
func IsTrue(d bool) byte {
|
||||
if d {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func IsTrueForByte(d byte) bool {
|
||||
if d == 1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 列车pc仿真btm查询
|
||||
type TrainPcSimBtmQueryFrame struct {
|
||||
message.CanetFrame //这里不是用 can 网络的前2帧
|
||||
}
|
||||
|
||||
// func (pc *TrainPcSimBtmQueryFrame) GetCanFrameId() message.CanFrameId {
|
||||
// return pc.CanId
|
||||
// }
|
||||
//
|
||||
// func (pc *TrainPcSimBtmQueryFrame) GetCanFrameData() []byte {
|
||||
// return pc.CanData
|
||||
// }
|
||||
func (q *TrainPcSimBtmQueryFrame) Decode(d []byte) error {
|
||||
q.CanId.ID1 = d[0]
|
||||
q.CanId.ID2 = d[1]
|
||||
q.CanId.ID3 = d[2]
|
||||
q.CanId.ID4 = d[3] >> 3
|
||||
//
|
||||
q.CanData = d[4:]
|
||||
return nil
|
||||
}
|
103
third_party/train_pc_sim/train_pc_sim_message_sender.go
vendored
Normal file
103
third_party/train_pc_sim/train_pc_sim_message_sender.go
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
package train_pc_sim
|
||||
|
||||
import (
|
||||
"joylink.club/ecs"
|
||||
)
|
||||
|
||||
const (
|
||||
//钥匙开关状态
|
||||
KEY_STATE = iota
|
||||
//手柄向前控制
|
||||
HANDLE_FORWORD
|
||||
//手柄向后控制
|
||||
HANDLE_BACKWORD
|
||||
//外部紧急制动反馈
|
||||
OUTER_EMERGENCY_BRAKE
|
||||
//列车制动状态
|
||||
TRAIN_BRAKE_STATE
|
||||
//开左门
|
||||
LEFT_OPEN_DOOR
|
||||
//关右门
|
||||
CLOSE_RIGHT_DOOR
|
||||
//关左门
|
||||
CLOSE_LEFT_DOOR
|
||||
//开右门
|
||||
OPEN_RIGHT_DOOR
|
||||
//折返按钮
|
||||
TURN_BACK
|
||||
//强制门允许
|
||||
FORCE_DOOR_ALLOW
|
||||
//模式降级按钮
|
||||
TRAIN_MODE_DOWN
|
||||
|
||||
//确认按钮
|
||||
CONFIRM
|
||||
//模式升级按钮
|
||||
TRAIN_MODE_UP
|
||||
//牵引制动手柄零位
|
||||
HANDLE_TO_ZERO
|
||||
//ATO发车按钮
|
||||
ATO_SEND_TRAIN
|
||||
|
||||
//列车完整性
|
||||
TRAIN_INTEGRITY
|
||||
//车载ATP/ATO旁路状态
|
||||
ATP_ATO_BYPASS_STATe
|
||||
//车辆牵引已切除状态
|
||||
TRAIN_TRACTION_CUTED
|
||||
//障碍物检测按钮
|
||||
OBSTACLE_CHECK
|
||||
//驾驶室激活反馈按钮
|
||||
DRIVER_ACTIVE_REPORT
|
||||
//制动重故障按钮
|
||||
BRAKE_HEAVY_FAULT
|
||||
//左门状态按钮
|
||||
LEFT_DOOR_STATE
|
||||
//右门状态按钮
|
||||
RIGHT_DOOR_STATE
|
||||
//唤醒按钮
|
||||
WAKE_UP
|
||||
//检修按钮
|
||||
OVERHAUL
|
||||
//欠压按钮
|
||||
UNDERVOLTAGE
|
||||
//休眠按钮
|
||||
SLEEP
|
||||
_
|
||||
//紧急手柄拉下
|
||||
EMERGENT_HANDLE_DOWN
|
||||
//车门锁闭状态
|
||||
DOOR_LOCK_STATE
|
||||
//逃生门状态
|
||||
LIFE_DOOR
|
||||
//车辆低压上电状态
|
||||
TRAIN_LOW_POWER
|
||||
//ATP上电按钮
|
||||
ATP_POWER_ON
|
||||
_
|
||||
//AA自动开关门
|
||||
DOOR_MODE_AA
|
||||
|
||||
//AM自开人关
|
||||
DOOR_MODE_AM
|
||||
//MM人开人关
|
||||
DOOR_MODE_MM
|
||||
)
|
||||
|
||||
type TrainControlEvent struct {
|
||||
Command byte
|
||||
Status byte
|
||||
}
|
||||
|
||||
var FireTrainControlEventType = ecs.NewEventType[TrainControlEvent]()
|
||||
|
||||
// 应答器组内序号
|
||||
// 唯一标识组内一个应答器,目前固定为1
|
||||
const PC_SIM_BALISE_NUM uint32 = 1
|
||||
|
||||
// 4.3.3. 应答器信息报文内容
|
||||
type TrainPcSimBtm struct {
|
||||
BaliseId uint32 //应答器组ID
|
||||
BaliseLocation float32 //应答器与车头发车位置的距离,单位cm
|
||||
BaliseData []byte //有数据的CAN数据报文
|
||||
}
|
49
third_party/train_pc_sim/train_pc_sim_message_type.go
vendored
Normal file
49
third_party/train_pc_sim/train_pc_sim_message_type.go
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
package train_pc_sim
|
||||
|
||||
const (
|
||||
//仿真系统车载pc仿真平台
|
||||
|
||||
//车辆输出数字量信息
|
||||
SENDER_TRAIN_OUTR_INFO = 0x00
|
||||
//速度位置信息
|
||||
sender_train_location_info = 0x01
|
||||
//驾驶室激活
|
||||
SENDER_TRAIN_TC_ACTIVE = 0x04
|
||||
//驾驶室未激活
|
||||
SENDER_TRAIN_TC_NOT_ACTIVE = 0x05
|
||||
|
||||
//手柄前进
|
||||
SENDER_TRAIN_HAND_KEY_FORWARD = 0x06
|
||||
|
||||
//车载pc仿真平台 仿真系统
|
||||
|
||||
//手柄取消前进(注1)
|
||||
RECIVE_TRAIN_HAND_KEY_CANCLE_FORWARD = 0x07
|
||||
//手柄后退
|
||||
RECIVE_TRAIN_HAND_KEY_BACKWARD = 0x08
|
||||
//手柄取消后退(注1)
|
||||
RECIVE_TRAIN_HAND_KEY_CACLE_BACKWARD = 0x09
|
||||
//有数据应答器
|
||||
RECIVE_TRAIN_BTM_HAS_DATA = 0x31
|
||||
|
||||
//无数据应答器
|
||||
RECIVE_TRAIN_BTM_NOT_DATA = 0x32
|
||||
|
||||
//清空所有预发应答器
|
||||
recive_train_btn_clear_all_pre_data = 0x33
|
||||
//创建/删除列车
|
||||
RECIVE_TRAIN_CREATE_REMOVE = 0x50
|
||||
|
||||
//门模式
|
||||
RECIVE_TRAIN_DOOR_MODE = 0x60
|
||||
|
||||
//车载接口柜输出数字量信息
|
||||
RECIVE_TRAIN_INTERFACE_CABINET_OUTR = 0x01
|
||||
//车载接口柜输出数字反馈量信息
|
||||
RECIVE_TRAIN_INTERFACE_CABINET_OUTR_BACK = 0x02
|
||||
//电流环模拟量
|
||||
RECIVE_TRAIN_MOCK_DATA = 0x03
|
||||
|
||||
//状态查询帧
|
||||
RECIVE_TRAIN_QUERY_STATUS = 0x04
|
||||
)
|
@ -139,7 +139,7 @@ func TrainConnTypeUpdate(vs *VerifySimulation, ct *dto.TrainConnThirdDto) {
|
||||
})
|
||||
}
|
||||
train := data.(*state_proto.TrainState)
|
||||
train.ConnState.Conn = conn
|
||||
//train.ConnState.Conn = conn
|
||||
train.ConnState.ConnType = ct.ConnType
|
||||
}
|
||||
|
||||
|
@ -1,118 +0,0 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"joylink.club/bj-rtsts-server/dto/request_proto"
|
||||
"joylink.club/bj-rtsts-server/dto/state_proto"
|
||||
"joylink.club/bj-rtsts-server/sys_error"
|
||||
)
|
||||
|
||||
/*func createTrainControl(vs *VerifySimulation) *state_proto.TrainControlState {
|
||||
var tccMapId int32
|
||||
for _, mapId := range vs.MapIds {
|
||||
picProType := QueryGiType(mapId)
|
||||
if picProType == data_proto.PictureType_TrainControlCab {
|
||||
tccMapId = mapId
|
||||
break
|
||||
}
|
||||
}
|
||||
if tccMapId == 0 {
|
||||
panic(sys_error.New("未找到列车控制相关图形数据"))
|
||||
}
|
||||
tcs := &state_proto.TrainControlState{
|
||||
ConnState: &state_proto.TrainConnState{Conn: false, ConnType: state_proto.TrainConnState_NONE},
|
||||
}
|
||||
tcc := QueryUidStructure[*TccUidStructure](tccMapId)
|
||||
for _, d := range tcc.ButtonIds {
|
||||
tcs.Buttons = append(tcs.Buttons, &state_proto.TrainControlState_TccButton{Id: d.CommonId, Code: d.Code})
|
||||
}
|
||||
for _, d := range tcc.Keys {
|
||||
tcs.Keys = append(tcs.Keys, &state_proto.TrainControlState_TccKey{Id: d.CommonId, Code: d.Code})
|
||||
}
|
||||
for _, d := range tcc.Handler {
|
||||
tcs.Handlers = append(tcs.Handlers, &state_proto.TrainControlState_TccHander{Id: d.CommonId, Code: d.Code})
|
||||
}
|
||||
return tcs
|
||||
}*/
|
||||
// 列车控制修改参数
|
||||
func ControlTrainUpdate(vs *VerifySimulation, ct *request_proto.TrainControl) {
|
||||
allTrainMap := &vs.Memory.Status.TrainStateMap
|
||||
data, ok := allTrainMap.Load(ct.TrainId)
|
||||
if !ok {
|
||||
panic(sys_error.New(fmt.Sprintf("列车【%s】不存在", ct.TrainId)))
|
||||
}
|
||||
sta := data.(*state_proto.TrainState)
|
||||
|
||||
if ct.ControlType == request_proto.TrainControl_EMERGENT_BUTTON {
|
||||
trainControlEB(sta, ct.Button, ct.DeviceId)
|
||||
} else if ct.ControlType == request_proto.TrainControl_DRIVER_KEY_SWITCH {
|
||||
trainControlDriverKey(sta, ct.DriverKey, ct.DeviceId)
|
||||
} else if ct.ControlType == request_proto.TrainControl_DIRECTION_KEY_SWITCH {
|
||||
trainControlDirKey(sta, ct.DirKey, ct.DeviceId)
|
||||
} else if ct.ControlType == request_proto.TrainControl_HANDLER {
|
||||
trainControlHandle(sta, ct.Handler, ct.DeviceId)
|
||||
}
|
||||
}
|
||||
func trainControlEB(trainState *state_proto.TrainState, request *request_proto.TrainControl_EmergentButton, deviceId uint32) {
|
||||
trainState.VobcState.EmergencyBrakingStatus = request.Active
|
||||
if trainState.Tcc.Ebutton == nil {
|
||||
trainState.Tcc.Ebutton = &state_proto.TrainControlState_EmergentButton{Id: deviceId, Passed: request.Active}
|
||||
} else {
|
||||
trainState.Tcc.Ebutton.Passed = request.Active
|
||||
}
|
||||
}
|
||||
func trainControlDirKey(trainState *state_proto.TrainState, request *request_proto.TrainControl_DirectionKeySwitch, deviceId uint32) {
|
||||
trainState.VobcState.DirectionForward = false
|
||||
trainState.VobcState.DirectionBackward = false
|
||||
if request.Val == 1 {
|
||||
trainState.VobcState.DirectionForward = true
|
||||
} else if request.Val == 0 {
|
||||
trainState.VobcState.DirectionBackward = false
|
||||
}
|
||||
if trainState.Tcc.DirKey == nil {
|
||||
trainState.Tcc.DirKey = &state_proto.TrainControlState_DirectionKeySwitch{Id: deviceId, Val: request.Val}
|
||||
} else {
|
||||
trainState.Tcc.DirKey.Val = request.Val
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func trainControlDriverKey(trainState *state_proto.TrainState, request *request_proto.TrainControl_DriverKeySwitch, deviceId uint32) {
|
||||
if request.Dt == request_proto.DriverType_ONE_END {
|
||||
trainState.VobcState.Tc1Active = request.Val
|
||||
} else if request.Dt == request_proto.DriverType_TWO_END {
|
||||
trainState.VobcState.Tc2Active = request.Val
|
||||
}
|
||||
var addNew = true
|
||||
for _, k := range trainState.Tcc.DriverKey {
|
||||
if k.Id == deviceId {
|
||||
k.Dt = request.Dt
|
||||
k.Id = deviceId
|
||||
k.Val = request.Val
|
||||
addNew = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if addNew {
|
||||
trainState.Tcc.DriverKey = append(trainState.Tcc.DriverKey, &state_proto.TrainControlState_DriverKeySwitch{Id: deviceId, Val: request.Val, Dt: request.Dt})
|
||||
}
|
||||
}
|
||||
func trainControlHandle(trainState *state_proto.TrainState, request *request_proto.TrainControl_PushHandler, deviceId uint32) {
|
||||
trainState.VobcState.TractionStatus = false
|
||||
trainState.VobcState.TractionForce = 0
|
||||
trainState.VobcState.BrakingStatus = false
|
||||
trainState.VobcState.BrakeForce = 0
|
||||
if request.Val > 0 {
|
||||
trainState.VobcState.TractionStatus = true
|
||||
trainState.VobcState.TractionForce = int64(request.Val)
|
||||
} else if request.Val < 0 {
|
||||
trainState.VobcState.BrakingStatus = true
|
||||
trainState.VobcState.BrakeForce = int64(request.Val)
|
||||
}
|
||||
if trainState.Tcc.DirKey == nil {
|
||||
trainState.Tcc.PushHandler = &state_proto.TrainControlState_PushHandler{Id: deviceId, Val: request.Val}
|
||||
} else {
|
||||
trainState.Tcc.PushHandler.Val = request.Val
|
||||
}
|
||||
|
||||
}
|
@ -134,10 +134,6 @@ func CreateSimulation(projectId int32, mapIds []int32, runConfig *dto.ProjectRun
|
||||
// return s.runState
|
||||
// }
|
||||
|
||||
func (s *VerifySimulation) GetTrainPcSimConfig() config.VehiclePCSimConfig {
|
||||
return s.runConfig.PcSimConfig
|
||||
}
|
||||
|
||||
// 获取仿真世界信息
|
||||
func (s *VerifySimulation) GetComIdByUid(uid string) uint32 {
|
||||
es := s.UidMap
|
||||
@ -391,11 +387,11 @@ func (s *VerifySimulation) HandleSemiPhysicalTrainControlMsg(b []byte) {
|
||||
return true
|
||||
}
|
||||
connState := train.ConnState
|
||||
if connState.Conn == true && connState.ConnType == state_proto.TrainConnState_VOBC {
|
||||
trainId, err := strconv.Atoi(train.Id)
|
||||
if err != nil {
|
||||
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
|
||||
}
|
||||
if connState.Conn == true && connState.ConnType == state_proto.TrainConnState_VOBC {
|
||||
d := append(b, uint8(trainId))
|
||||
// 发送给动力学
|
||||
dynamics.Default().SendTrainControlMessage(d)
|
||||
|
404
ts/simulation/wayside/memory/wayside_simulation_train_pc.go
Normal file
404
ts/simulation/wayside/memory/wayside_simulation_train_pc.go
Normal file
@ -0,0 +1,404 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"joylink.club/bj-rtsts-server/config"
|
||||
"joylink.club/bj-rtsts-server/const/balise_const"
|
||||
"joylink.club/bj-rtsts-server/dto/request_proto"
|
||||
"joylink.club/bj-rtsts-server/dto/state_proto"
|
||||
"joylink.club/bj-rtsts-server/sys_error"
|
||||
"joylink.club/bj-rtsts-server/third_party/can_btm"
|
||||
"joylink.club/bj-rtsts-server/third_party/message"
|
||||
train_pc_sim "joylink.club/bj-rtsts-server/third_party/train_pc_sim"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (s *VerifySimulation) GetTrainPcSimConfig() config.VehiclePCSimConfig {
|
||||
return s.runConfig.PcSimConfig
|
||||
}
|
||||
|
||||
// 列车控制
|
||||
func (s *VerifySimulation) ControlTrainUpdate(ct *request_proto.TrainControl) {
|
||||
allTrainMap := &s.Memory.Status.TrainStateMap
|
||||
data, ok := allTrainMap.Load(ct.TrainId)
|
||||
if !ok {
|
||||
panic(sys_error.New(fmt.Sprintf("列车【%s】不存在", ct.TrainId)))
|
||||
}
|
||||
sta := data.(*state_proto.TrainState)
|
||||
var tce []train_pc_sim.TrainControlEvent = nil
|
||||
if ct.ControlType == request_proto.TrainControl_EMERGENT_BUTTON {
|
||||
trainControlEB(sta, ct.Button, ct.DeviceId)
|
||||
} else if ct.ControlType == request_proto.TrainControl_DRIVER_KEY_SWITCH {
|
||||
tce = trainControlDriverKey(sta, ct.DriverKey, ct.DeviceId)
|
||||
train_pc_sim.Default().SendDriverActive(sta.ConnState, sta.VobcState)
|
||||
} else if ct.ControlType == request_proto.TrainControl_DIRECTION_KEY_SWITCH {
|
||||
trainControlDirKey(sta, ct.DirKey, ct.DeviceId)
|
||||
} else if ct.ControlType == request_proto.TrainControl_HANDLER {
|
||||
oldTraction := sta.VobcState.TractionForce
|
||||
oldBrakeForce := sta.VobcState.BrakeForce
|
||||
tce = trainControlHandle(sta, ct.Handler, ct.DeviceId)
|
||||
train_pc_sim.Default().SendHandleSwitch(oldTraction, oldBrakeForce, sta.ConnState, sta.VobcState)
|
||||
}
|
||||
|
||||
if !sta.ConnState.Conn && sta.ConnState.ConnType != state_proto.TrainConnState_PC_SIM {
|
||||
slog.Error("当前列车未连接车载pc仿真,", sta.Id)
|
||||
return
|
||||
}
|
||||
|
||||
train_pc_sim.Default().PublishTrainControlEvent(s.World, tce)
|
||||
|
||||
}
|
||||
|
||||
func trainControlEB(trainState *state_proto.TrainState, request *request_proto.TrainControl_EmergentButton, deviceId uint32) {
|
||||
trainState.VobcState.EmergencyBrakingStatus = request.Active
|
||||
if trainState.Tcc.Ebutton == nil {
|
||||
trainState.Tcc.Ebutton = &state_proto.TrainControlState_EmergentButton{Id: deviceId, Passed: request.Active}
|
||||
} else {
|
||||
trainState.Tcc.Ebutton.Passed = request.Active
|
||||
}
|
||||
}
|
||||
|
||||
// 列车方向
|
||||
func trainControlDirKey(trainState *state_proto.TrainState, request *request_proto.TrainControl_DirectionKeySwitch, deviceId uint32) {
|
||||
trainState.VobcState.DirectionForward = false
|
||||
trainState.VobcState.DirectionBackward = false
|
||||
if request.Val == 1 {
|
||||
trainState.VobcState.DirectionForward = true
|
||||
} else if request.Val == 0 {
|
||||
trainState.VobcState.DirectionBackward = false
|
||||
}
|
||||
if trainState.Tcc.DirKey == nil {
|
||||
trainState.Tcc.DirKey = &state_proto.TrainControlState_DirectionKeySwitch{Id: deviceId, Val: request.Val}
|
||||
} else {
|
||||
trainState.Tcc.DirKey.Val = request.Val
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 列车驾驶端激活
|
||||
func trainControlDriverKey(trainState *state_proto.TrainState, request *request_proto.TrainControl_DriverKeySwitch, deviceId uint32) []train_pc_sim.TrainControlEvent {
|
||||
if request.Dt == request_proto.DriverType_ONE_END {
|
||||
trainState.VobcState.Tc1Active = request.Val
|
||||
} else if request.Dt == request_proto.DriverType_TWO_END {
|
||||
trainState.VobcState.Tc2Active = request.Val
|
||||
}
|
||||
var addNew = true
|
||||
for _, k := range trainState.Tcc.DriverKey {
|
||||
if k.Id == deviceId {
|
||||
k.Id = deviceId
|
||||
k.Val = request.Val
|
||||
addNew = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if addNew {
|
||||
trainState.Tcc.DriverKey = append(trainState.Tcc.DriverKey, &state_proto.TrainControlState_DriverKeySwitch{Id: deviceId, Val: request.Val})
|
||||
}
|
||||
return []train_pc_sim.TrainControlEvent{{Command: train_pc_sim.KEY_STATE, Status: train_pc_sim.IsTrue(request.Val)}}
|
||||
|
||||
}
|
||||
|
||||
// 列车牵引控制
|
||||
func trainControlHandle(trainState *state_proto.TrainState, request *request_proto.TrainControl_PushHandler, deviceId uint32) []train_pc_sim.TrainControlEvent {
|
||||
trainState.VobcState.TractionStatus = false
|
||||
trainState.VobcState.TractionForce = 0
|
||||
trainState.VobcState.BrakingStatus = false
|
||||
trainState.VobcState.BrakeForce = 0
|
||||
tce := make([]train_pc_sim.TrainControlEvent, 0)
|
||||
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_FORWORD, Status: 0})
|
||||
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_BACKWORD, Status: 0})
|
||||
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_TO_ZERO, Status: 0})
|
||||
if request.Val > 0 {
|
||||
trainState.VobcState.TractionStatus = true
|
||||
trainState.VobcState.TractionForce = int64(request.Val)
|
||||
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_FORWORD, Status: 1})
|
||||
} else if request.Val < 0 {
|
||||
trainState.VobcState.BrakingStatus = true
|
||||
trainState.VobcState.BrakeForce = int64(request.Val)
|
||||
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_BACKWORD, Status: 1})
|
||||
} else {
|
||||
|
||||
tce = append(tce, train_pc_sim.TrainControlEvent{Command: train_pc_sim.HANDLE_TO_ZERO, Status: 1})
|
||||
}
|
||||
if trainState.Tcc.PushHandler == nil {
|
||||
trainState.Tcc.PushHandler = &state_proto.TrainControlState_PushHandler{Id: deviceId, Val: request.Val}
|
||||
} else {
|
||||
trainState.Tcc.PushHandler.Val = request.Val
|
||||
}
|
||||
return tce
|
||||
}
|
||||
func (s *VerifySimulation) findConnTrain(ct state_proto.TrainConnState_TrainConnType) *state_proto.TrainState {
|
||||
var findTrain *state_proto.TrainState
|
||||
s.Memory.Status.TrainStateMap.Range(func(k, v any) bool {
|
||||
train := v.(*state_proto.TrainState)
|
||||
connState := train.ConnState
|
||||
if connState.ConnType == ct {
|
||||
findTrain = train
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return findTrain
|
||||
}
|
||||
|
||||
// 4.4.1. 车载输出数字量信息报文内容
|
||||
func (s *VerifySimulation) TrainPcSimDigitalOutInfoHandle(data []byte) {
|
||||
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
|
||||
if train == nil {
|
||||
slog.Error("车载输出数字量,未找到连接车载pc仿真的列车")
|
||||
return
|
||||
}
|
||||
if !train.ConnState.Conn {
|
||||
slog.Error("车载输出数字量,,列车未连接车载pc仿真")
|
||||
return
|
||||
}
|
||||
buf := bytes.NewBuffer(data)
|
||||
vobc := train.VobcState
|
||||
cutTraction, _ := buf.ReadByte() //切牵引
|
||||
trainDoorOutLed, _ := buf.ReadByte() //车门外指示灯
|
||||
stopBrakeAppend, _ := buf.ReadByte() //停放制动施加
|
||||
emergentBrake, _ := buf.ReadByte() //紧急制动
|
||||
leftOpenDoor, _ := buf.ReadByte() //开左门允许
|
||||
rightOpenDoor, _ := buf.ReadByte() //开右门允许
|
||||
closeRightDoor, _ := buf.ReadByte() //关右门
|
||||
doorAlwaysClosed, _ := buf.ReadByte() //车门保持关闭
|
||||
localAtpControl, _ := buf.ReadByte() //本端ATP控车
|
||||
atoMode, _ := buf.ReadByte() //ATO模式
|
||||
atoTractionCommandOut, _ := buf.ReadByte() //ATO牵引命令输出
|
||||
atoTractionCommand1, _ := buf.ReadByte() //ATO牵引指令1
|
||||
atoTractionCommand2, _ := buf.ReadByte() //ATO牵引指令2
|
||||
atoTractionCommand3, _ := buf.ReadByte() //ATO牵引指令3
|
||||
atoBrakeCommand, _ := buf.ReadByte() //ATO制动命令输出
|
||||
skipCommand, _ := buf.ReadByte() //跳跃指令
|
||||
direction1, _ := buf.ReadByte() //列车方向1
|
||||
direction2, _ := buf.ReadByte() //列车方向2
|
||||
atoLazyCommandOut, _ := buf.ReadByte() //ATO惰行命令输出
|
||||
sleepCommand, _ := buf.ReadByte() //休眠指令
|
||||
wakeUpCommand, _ := buf.ReadByte() //唤醒指令
|
||||
toPullTrainLed, _ := buf.ReadByte() //ATO发车指示灯
|
||||
arLightCommand, _ := buf.ReadByte() //AR灯命令
|
||||
atoAlwaysBrake, _ := buf.ReadByte() //ATO保持制动
|
||||
atoOpenLeftDoor, _ := buf.ReadByte() //ATO开左门
|
||||
atoOpenRightDoor, _ := buf.ReadByte() //ATO开右门
|
||||
atoCloseLeftDoor, _ := buf.ReadByte() //ATO关左门
|
||||
ariverActive, _ := buf.ReadByte() //驾驶室激活
|
||||
noSpeedSigle, _ := buf.ReadByte() //零速信号
|
||||
famMode, _ := buf.ReadByte() //FAM模式
|
||||
camMode, _ := buf.ReadByte() //CAM模式
|
||||
trainStartedLed, _ := buf.ReadByte() //列车启动指示灯
|
||||
mostUseBrake, _ := buf.ReadByte() //常用制动
|
||||
splittingOut, _ := buf.ReadByte() //过分相输出
|
||||
modeRelay, _ := buf.ReadByte() //模式继电器
|
||||
tractionEffective, _ := buf.ReadByte() //牵引有效
|
||||
brakeEffective, _ := buf.ReadByte() //制动有效
|
||||
lifeDoorUsed, _ := buf.ReadByte() //逃生门使能
|
||||
brakeQuarantine, _ := buf.ReadByte() //制动隔离
|
||||
stopNotAllBrake, _ := buf.ReadByte() //停放制动缓解
|
||||
|
||||
vobc.TractionSafetyCircuit = train_pc_sim.IsTrueForByte(cutTraction)
|
||||
vobc.TrainDoorOutLed = train_pc_sim.IsTrueForByte(trainDoorOutLed) //? 说明暂无此属性
|
||||
vobc.ParkingBrakeStatus = train_pc_sim.IsTrueForByte(stopBrakeAppend)
|
||||
vobc.EmergencyBrakingStatus = train_pc_sim.IsTrueForByte(emergentBrake)
|
||||
vobc.LeftDoorOpenCommand = train_pc_sim.IsTrueForByte(leftOpenDoor)
|
||||
vobc.RightDoorOpenCommand = train_pc_sim.IsTrueForByte(rightOpenDoor)
|
||||
vobc.RightDoorCloseCommand = train_pc_sim.IsTrueForByte(closeRightDoor)
|
||||
vobc.AllDoorClose = train_pc_sim.IsTrueForByte(doorAlwaysClosed)
|
||||
vobc.LocalAtpControl = train_pc_sim.IsTrueForByte(localAtpControl) //?
|
||||
vobc.Ato = train_pc_sim.IsTrueForByte(atoMode)
|
||||
vobc.AtoTractionCommandOut = train_pc_sim.IsTrueForByte(atoTractionCommandOut) //?
|
||||
|
||||
vobc.AtoTractionCommand1 = train_pc_sim.IsTrueForByte(atoTractionCommand1) //?
|
||||
vobc.AtoTractionCommand2 = train_pc_sim.IsTrueForByte(atoTractionCommand2) //?
|
||||
vobc.AtoTractionCommand3 = train_pc_sim.IsTrueForByte(atoTractionCommand3) //?
|
||||
vobc.AtoBrakeCommand = train_pc_sim.IsTrueForByte(atoBrakeCommand) //?
|
||||
vobc.JumpStatus = train_pc_sim.IsTrueForByte(skipCommand)
|
||||
vobc.DirectionForward = train_pc_sim.IsTrueForByte(direction1)
|
||||
vobc.DirectionBackward = train_pc_sim.IsTrueForByte(direction2)
|
||||
|
||||
vobc.AtoLazyCommandOut = train_pc_sim.IsTrueForByte(atoLazyCommandOut) //?
|
||||
vobc.SleepBtn = train_pc_sim.IsTrueForByte(sleepCommand)
|
||||
vobc.WakeUpBtn = train_pc_sim.IsTrueForByte(wakeUpCommand)
|
||||
vobc.AtoSendTrainBtn = train_pc_sim.IsTrueForByte(toPullTrainLed)
|
||||
vobc.TurnbackStatus = train_pc_sim.IsTrueForByte(arLightCommand) //?
|
||||
vobc.AtoAlwaysBrake = train_pc_sim.IsTrueForByte(atoAlwaysBrake) //?
|
||||
vobc.AtoOpenLeftDoor = train_pc_sim.IsTrueForByte(atoOpenLeftDoor) //?
|
||||
vobc.AtoOpenRightDoor = train_pc_sim.IsTrueForByte(atoOpenRightDoor) //?
|
||||
vobc.AtoCloseLeftDoor = train_pc_sim.IsTrueForByte(atoCloseLeftDoor) //?
|
||||
vobc.Tc1Active = train_pc_sim.IsTrueForByte(ariverActive)
|
||||
vobc.NoSpeedSigle = train_pc_sim.IsTrueForByte(noSpeedSigle) //?
|
||||
vobc.Fam = train_pc_sim.IsTrueForByte(famMode)
|
||||
vobc.Cam = train_pc_sim.IsTrueForByte(camMode)
|
||||
vobc.TrainStartedLed = train_pc_sim.IsTrueForByte(trainStartedLed) //?
|
||||
vobc.MostUseBrake = train_pc_sim.IsTrueForByte(mostUseBrake) //? //常用制动
|
||||
vobc.SplittingOut = train_pc_sim.IsTrueForByte(splittingOut) //? //过分相输出
|
||||
vobc.ModeRelay = train_pc_sim.IsTrueForByte(modeRelay) //? //模式继电器
|
||||
vobc.TractionEffective = train_pc_sim.IsTrueForByte(tractionEffective) //? //牵引有效
|
||||
vobc.BrakeEffective = train_pc_sim.IsTrueForByte(brakeEffective) //? //制动有效
|
||||
vobc.LifeDoorState = train_pc_sim.IsTrueForByte(lifeDoorUsed) //逃生门使能
|
||||
vobc.BrakeQuarantine = train_pc_sim.IsTrueForByte(brakeQuarantine) //? //制动隔离
|
||||
vobc.StopNotAllBrake = train_pc_sim.IsTrueForByte(stopNotAllBrake) //? //停放制动缓解
|
||||
}
|
||||
|
||||
// 4.4.2. 车载输出数字反馈量信息报文内容
|
||||
func (s *VerifySimulation) TrainPcSimDigitalReportHandle(data []byte) {
|
||||
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
|
||||
if train == nil {
|
||||
slog.Error("车载输出数字反馈量信息,未找到连接车载pc仿真的列车")
|
||||
return
|
||||
}
|
||||
if !train.ConnState.Conn {
|
||||
slog.Error("车载输出数字反馈量信息,列车未连接车载pc仿真")
|
||||
return
|
||||
}
|
||||
vobc := train.VobcState
|
||||
buf := bytes.NewBuffer(data)
|
||||
localEndAct, _ := buf.ReadByte()
|
||||
direction1, _ := buf.ReadByte()
|
||||
direction2, _ := buf.ReadByte()
|
||||
|
||||
vobc.Tc1Active = train_pc_sim.IsTrueForByte(localEndAct) //本端驾驶室激活(钥匙)
|
||||
vobc.DirectionForward = train_pc_sim.IsTrueForByte(direction1) //方向手柄进位
|
||||
vobc.DirectionBackward = train_pc_sim.IsTrueForByte(direction2) //方向手柄退位
|
||||
}
|
||||
|
||||
// 创建/删除列车
|
||||
func (s *VerifySimulation) TrainPcSimConnOrRemoveHandle(state byte) {
|
||||
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
|
||||
if train == nil {
|
||||
slog.Error("创建删除列车,未找到连接车载pc仿真的列车")
|
||||
return
|
||||
}
|
||||
connState := train.ConnState
|
||||
if state == 0x01 {
|
||||
connState.Conn = true
|
||||
} else {
|
||||
connState.Conn = false
|
||||
}
|
||||
}
|
||||
|
||||
// 门模式
|
||||
func (s *VerifySimulation) TrainDoorModeHandle(state byte) {
|
||||
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
|
||||
if train == nil {
|
||||
slog.Error("车载pc仿真门模式,未找到连接车载pc仿真的列车")
|
||||
return
|
||||
}
|
||||
if !train.ConnState.Conn {
|
||||
slog.Error("车载pc仿真门模式,列车未连接车载pc仿真")
|
||||
return
|
||||
}
|
||||
switch state {
|
||||
case 0x00:
|
||||
//0x00表示自开自关(AA)
|
||||
train.VobcState.DoorModeAA = true
|
||||
case 0x01:
|
||||
//0x01表示自开人关(AM)
|
||||
train.VobcState.DoorModeAM = true
|
||||
case 0x02:
|
||||
//0x02表示人开人关(MM)
|
||||
train.VobcState.DoorModeMM = true
|
||||
}
|
||||
}
|
||||
|
||||
// 4.4.3. 车载输出模拟量信息报文内容(0x03)
|
||||
func (s *VerifySimulation) TrainPcSimMockInfo(data []byte) {
|
||||
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
|
||||
if train == nil {
|
||||
slog.Error("车载输出模拟量,未找到连接车载pc仿真的列车")
|
||||
return
|
||||
}
|
||||
if !train.ConnState.Conn {
|
||||
slog.Error("车载输出模拟量,列车未连接车载pc仿真")
|
||||
return
|
||||
}
|
||||
mockData := binary.BigEndian.Uint16(data)
|
||||
train.VobcState.MockInfo = uint32(mockData)
|
||||
}
|
||||
|
||||
// 4.4.4. 车载输出BTM查询同步帧报文内容(0x04)
|
||||
func (s *VerifySimulation) TrainBtmQuery(data []byte) {
|
||||
if len(data) < 12 {
|
||||
slog.Error("列车btm查询报文长度错误:", len(data))
|
||||
return
|
||||
}
|
||||
train := s.findConnTrain(state_proto.TrainConnState_PC_SIM)
|
||||
if train == nil {
|
||||
slog.Error("车载输出btm查询,未找到连接车载pc仿真的列车")
|
||||
return
|
||||
}
|
||||
if !train.ConnState.Conn {
|
||||
slog.Error("车载输出btm查询,列车未连接车载pc仿真")
|
||||
return
|
||||
}
|
||||
|
||||
trainAtm := message.NewCanetFrame(data, true)
|
||||
atpReq := &message.AtpRequestFrame{}
|
||||
if !atpReq.Decode(trainAtm) {
|
||||
slog.Warn("列车pc驾驶模拟-CanetFrame解码成AtpRequestFrame失败", "CanetFrame", trainAtm.String())
|
||||
return
|
||||
}
|
||||
cl := clock(atpReq)
|
||||
btmRepFrame := createBtmStatus(trainAtm.CanId.ID4, train.BtmState, atpReq, cl)
|
||||
if atpReq.ResendRequest == 2 {
|
||||
//重新发送
|
||||
if len(train.BtmState.BaliseTelegramForPcSimResend) > 0 {
|
||||
dd, _ := hex.DecodeString(train.BtmState.BaliseTelegramForPcSimResend)
|
||||
train_pc_sim.Default().SendBaliseData(train_pc_sim.RECIVE_TRAIN_BTM_HAS_DATA, dd)
|
||||
}
|
||||
} else {
|
||||
timeSyncF := message.NewBtmTimeSyncCheckFrame(trainAtm.CanId.ID4, true)
|
||||
timeSyncF.T2 = cl.BtmTk
|
||||
timeSyncF.T3 = cl.TkNow()
|
||||
telCount := strings.Count(train.BtmState.Telegram, "00")
|
||||
if telCount >= balise_const.UserTelegramByteLen {
|
||||
//无数据
|
||||
queryData := make([]byte, 0)
|
||||
queryData = append(queryData, btmRepFrame.Encode().Encode()...)
|
||||
queryData = append(queryData, timeSyncF.Encode().Encode()...)
|
||||
train_pc_sim.Default().SendBaliseData(train_pc_sim.RECIVE_TRAIN_BTM_NOT_DATA, queryData)
|
||||
} else {
|
||||
//有数据
|
||||
aliseData, _ := hex.DecodeString(train.BtmState.Telegram)
|
||||
statusDataCf, statusDataCfOk := message.CreateBtmRspFramesData(btmRepFrame, aliseData, false, cl.TkNow(), cl.TkNow(), cl.TkNow(), true)
|
||||
if statusDataCfOk {
|
||||
queryData := make([]byte, 0)
|
||||
queryData = append(queryData, btmRepFrame.Encode().Encode()...)
|
||||
queryData = append(queryData, timeSyncF.Encode().Encode()...)
|
||||
queryData = append(queryData, statusDataCf...) //数据帧包含结束帧
|
||||
train.BtmState.BaliseTelegramForPcSimResend = fmt.Sprintf("%X", statusDataCf)
|
||||
train_pc_sim.Default().SendBaliseData(train_pc_sim.RECIVE_TRAIN_BTM_HAS_DATA, queryData)
|
||||
} else {
|
||||
slog.Error("列车pc仿真 BtmCanetClient应答帧、数据帧编码失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createBtmStatus(canIdSn byte, btmState *state_proto.BTMState, atpReq *message.AtpRequestFrame, cl can_btm.BtmClock) *message.BtmStatusRspFrame {
|
||||
statusF := message.NewBtmStatusRspFrame(canIdSn, true)
|
||||
//btmStatus := aa(train, atpReq)
|
||||
|
||||
statusF.PowerAmplifierOn = true
|
||||
statusF.PowerAmplifierFailure = false
|
||||
statusF.AtpReqCrcCheckWrong = !atpReq.Crc16CheckOk
|
||||
statusF.AntennaFault = false
|
||||
statusF.BaliseCounter = byte(btmState.BaliseCount)
|
||||
statusF.MessageCounter = byte(btmState.MessageCounter)
|
||||
statusF.TkTimeA = cl.TkNow()
|
||||
statusF.DetailedCode = 0
|
||||
if btmState.AboveBalise {
|
||||
statusF.DetailedCode = 0x07
|
||||
}
|
||||
statusF.Dsn = byte(btmState.DataSerialNumber)
|
||||
return statusF
|
||||
}
|
||||
|
||||
func clock(atpReq *message.AtpRequestFrame) can_btm.BtmClock {
|
||||
now := time.Now()
|
||||
return can_btm.BtmClock{BtmTk: atpReq.Time, SysTk: now}
|
||||
}
|
Loading…
Reference in New Issue
Block a user