From 735e46893b5a384137b09bc6145b07b16b59e04e Mon Sep 17 00:00:00 2001 From: weizhihong Date: Tue, 24 Oct 2023 10:57:04 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E8=81=94=E9=94=81=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=A4=84=E7=90=86=E3=80=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wayside/memory/wayside_simulation.go | 29 ++++- config/bj_local.yml | 6 + config/config.go | 8 ++ config/dev.yml | 7 + config/test_local.yml | 8 +- rtss_simulation | 2 +- third_party/interlock/interlock.go | 120 ++++++++++++++++++ third_party/message/interlock.go | 47 +++++-- 8 files changed, 211 insertions(+), 16 deletions(-) create mode 100644 third_party/interlock/interlock.go diff --git a/ats/verify/simulation/wayside/memory/wayside_simulation.go b/ats/verify/simulation/wayside/memory/wayside_simulation.go index 688b605..bca18b9 100644 --- a/ats/verify/simulation/wayside/memory/wayside_simulation.go +++ b/ats/verify/simulation/wayside/memory/wayside_simulation.go @@ -21,6 +21,7 @@ import ( "joylink.club/bj-rtsts-server/third_party/message" "joylink.club/bj-rtsts-server/third_party/semi_physical_train" "joylink.club/ecs" + "joylink.club/rtsssimulation/fi" "joylink.club/rtsssimulation/repository" "joylink.club/rtsssimulation/repository/model/proto" ) @@ -391,14 +392,30 @@ func (s *VerifySimulation) HandleSemiPhysicalTrainControlMsg(b []byte) { // 处理接到的联锁消息 func (s *VerifySimulation) HandleDriverInfo(b []byte) { - + driverMsg := message.NewInterlockReceiveMsgPkg(0, 128, 8*131) + driverMsg.Decode(b) + driveState := driverMsg.DriveInfo + for x, lenght := 0, len(driveState); x < lenght/32; x++ { + for y := 0; y < 32; y++ { + fi.DriveCircuitStateChange(s.World, x, y, driveState[x*32+y]) + } + } } -//// 采集联锁中的继电器消息 -//func (s *VerifySimulation) CollectRelayInfo() *message.InterlockSendMsgPkg { -// -// return nil -//} +// 采集联锁中的继电器消息 +func (s *VerifySimulation) CollectRelayInfo() *message.InterlockSendMsgPkg { + msg := &message.InterlockSendMsgPkg{} + relayArr := make([]string, 256) + for index, id := range relayArr { + if index%2 == 0 { + msg.Info = append(msg.Info, fi.CollectXQCircuitState(s.World, id)) + } else { + msg.Info = append(msg.Info, fi.CollectLXCircuitState(s.World, id)) + + } + } + return msg +} func buildProtoRepository(mapIds []int32) (*proto.Repository, error) { repo := &proto.Repository{} diff --git a/config/bj_local.yml b/config/bj_local.yml index 6bc9d74..fed7d57 100644 --- a/config/bj_local.yml +++ b/config/bj_local.yml @@ -18,6 +18,12 @@ vobc: localPort: 10000 remotePort: 4000 open: true +# interlock +interlock: + ip: 10.60.1.59 + localPort: 10000 + remotePort: 4000 + open: true # 数据源 datasource: diff --git a/config/config.go b/config/config.go index 1facce2..4767b1a 100644 --- a/config/config.go +++ b/config/config.go @@ -20,6 +20,7 @@ type AppConfig struct { Messaging messaging Dynamics dynamics Vobc vobc + Interlock interlock } type server struct { Port int @@ -63,6 +64,13 @@ type vobc struct { Open bool } +type interlock struct { + Ip string + LocalPort int + RemotePort int + Open bool +} + var Config AppConfig var SimulationId_prefix = (func() string { diff --git a/config/dev.yml b/config/dev.yml index 719b521..7d0fd6d 100644 --- a/config/dev.yml +++ b/config/dev.yml @@ -18,6 +18,13 @@ vobc: localPort: 10000 remotePort: 4000 open: false +# interlock +interlock: + ip: 10.60.1.59 + localPort: 10000 + remotePort: 4000 + open: false + # 数据源 datasource: diff --git a/config/test_local.yml b/config/test_local.yml index 18c017d..346044b 100644 --- a/config/test_local.yml +++ b/config/test_local.yml @@ -18,7 +18,13 @@ vobc: localPort: 10000 remotePort: 4000 open: true - +# interlock +interlock: + ip: 10.60.1.59 + localPort: 10000 + remotePort: 4000 + open: true + # 数据源 datasource: # 数据库访问url diff --git a/rtss_simulation b/rtss_simulation index 3c65650..af7cb83 160000 --- a/rtss_simulation +++ b/rtss_simulation @@ -1 +1 @@ -Subproject commit 3c65650745096e41bb008c74db31aa943e41285a +Subproject commit af7cb83fa8e983fb1dabf4179fd0a7692e20bb16 diff --git a/third_party/interlock/interlock.go b/third_party/interlock/interlock.go new file mode 100644 index 0000000..234a001 --- /dev/null +++ b/third_party/interlock/interlock.go @@ -0,0 +1,120 @@ +package interlock + +import ( + "context" + "fmt" + "log/slog" + "runtime/debug" + "time" + + "joylink.club/bj-rtsts-server/config" + "joylink.club/bj-rtsts-server/third_party/message" + "joylink.club/bj-rtsts-server/third_party/udp" +) + +// 联锁代理通信接口 +type InterlockMessageManager interface { + CollectRelayInfo() *message.InterlockSendMsgPkg + HandleDriverInfo(b []byte) +} + +// 联锁接口 +type InterlockProxy interface { + // 启动联锁消息功能 + Start(manager InterlockMessageManager) + // 停止联锁消息功能 + Stop() + // 发送联锁采集消息 + SendCollectMessage(b []byte) +} + +var _default InterlockProxy + +func Default() InterlockProxy { + if !config.Config.Interlock.Open { // TODO + panic("联锁接口模块未开启") + } + return _default +} + +type interlockProxy struct { + driveInfoUdpServer udp.UdpServer + sendCollectUdpClient udp.UdpClient + + manager InterlockMessageManager + collectInfoTaskCancel context.CancelFunc +} + +// 驱动信息进行转发 +func (d *interlockProxy) handleDriverInfo(b []byte) { + handler := d.manager + if handler != nil { + handler.HandleDriverInfo(b) + } +} + +func (d *interlockProxy) Start(manager InterlockMessageManager) { + if manager == nil { + panic("启动联锁消息服务错误: InterlockMessageManager不能为nil") + } + if d.manager != nil { + panic("启动联锁消息服务错误: 存在正在运行的任务") + } + d.manager = manager + ctx, cancle := context.WithCancel(context.Background()) + go d.collectInfoStateTask(ctx) + d.collectInfoTaskCancel = cancle +} + +const ( + // 采集电路状态发送间隔,单位ms + InterlockMessageSendInterval = 50 +) + +// 定时发送采集电路状态任务 +func (d *interlockProxy) collectInfoStateTask(ctx context.Context) { + defer func() { + if err := recover(); err != nil { + slog.Error("定时发送道岔状态任务异常", "error", err, "stack", string(debug.Stack())) + debug.PrintStack() + } + }() + for { + select { + case <-ctx.Done(): + return + default: + } + collectInfoStates := d.manager.CollectRelayInfo() + d.sendCollectUdpClient.SendMsg(collectInfoStates) + time.Sleep(time.Millisecond * InterlockMessageSendInterval) + } +} + +func (d *interlockProxy) Stop() { + if d.collectInfoTaskCancel != nil { + d.collectInfoTaskCancel() + d.manager = nil + } +} + +func (d *interlockProxy) SendCollectMessage(b []byte) { + d.sendCollectUdpClient.Send(b) +} + +func newInterlockProxy() *interlockProxy { + d := &interlockProxy{ + sendCollectUdpClient: udp.NewClient(fmt.Sprintf("%v:%v", config.Config.Interlock.Ip, config.Config.Interlock.RemotePort)), + } + d.driveInfoUdpServer = udp.NewServer(fmt.Sprintf(":%d", config.Config.Interlock.LocalPort), d.handleDriverInfo) + d.driveInfoUdpServer.Listen() + return d +} + +func Init() { + if !config.Config.Interlock.Open { // TODO + return + } + slog.Info("初始化联锁接口模块") + _default = newInterlockProxy() +} diff --git a/third_party/message/interlock.go b/third_party/message/interlock.go index f868619..6fbdb76 100644 --- a/third_party/message/interlock.go +++ b/third_party/message/interlock.go @@ -52,27 +52,49 @@ func (t *InterlockMsgPkgTail) Decode(buf []byte) error { // 发送给联锁的采集数据 type InterlockSendMsgPkg struct { Header *InterlockMsgPkgHeader // 包头 - Info []byte // 发给联锁的状态数据 + Info []bool // 发给联锁的状态数据 Tail *InterlockMsgPkgTail // 包尾 } +var boolsToByteArrLen int = 8 + func (m *InterlockSendMsgPkg) Encode() []byte { var data []byte data = append(data, m.Header.Encode()...) - data = append(data, m.Info...) + for index, length, cycles := 0, len(m.Info), len(m.Info)/boolsToByteArrLen; index < cycles; index++ { + startIndex := index * boolsToByteArrLen + toByteArr := [8]bool{} + for i := 0; i < boolsToByteArrLen && startIndex < length; i++ { + startIndex = startIndex + i + toByteArr[i] = m.Info[startIndex+i] + } + data = append(data, boolsToByte(toByteArr)) + } data = append(data, m.Tail.Encode()...) return data } +// bool数组转byte +func boolsToByte(flags [8]bool) byte { + var result uint8 + for _, b := range flags { + result <<= 1 + if b { + result |= 1 + } + } + return result +} + // 收到联锁发来的驱动数据 type InterlockReceiveMsgPkg struct { toagent_len int32 et_out_num int32 tcc_output_len int32 Header *InterlockMsgPkgHeader // 包头 - syncZone []byte // 同步区状态 - driveInfo []byte // 驱动数据 - tccInfo []byte // 应答器报文 + SyncZone []bool // 同步区状态 + DriveInfo []bool // 驱动数据 + TccInfo []bool // 应答器报文 Tail *InterlockMsgPkgTail // 包尾 } @@ -94,16 +116,25 @@ func (t *InterlockReceiveMsgPkg) Decode(buf []byte) error { // 同步区状态 preIndex = lastIndex lastIndex = lastIndex + t.toagent_len - t.syncZone = buf[preIndex:lastIndex] + t.parseByte(t.SyncZone, buf, preIndex, lastIndex) // 驱动数据 preIndex = lastIndex lastIndex = lastIndex + t.et_out_num - t.driveInfo = buf[preIndex:lastIndex] + t.parseByte(t.DriveInfo, buf, preIndex, lastIndex) // 应答器报文 preIndex = lastIndex lastIndex = lastIndex + t.tcc_output_len - t.tccInfo = buf[preIndex:lastIndex] + t.parseByte(t.TccInfo, buf, preIndex, lastIndex) // 包尾 t.Tail.Decode(buf) return nil } + +func (t *InterlockReceiveMsgPkg) parseByte(r []bool, buf []byte, start, end int32) { + for i := start; i < end; i++ { + b := buf[i] + for bit := 7; bit >= 0; bit-- { + r = append(r, (b&(1<