rts-sim-testing-service/third_party/interlock/beijing12/interlock.go
thesai d610a15fdb [新增]ecs物理区段增加区段电路组件及逻辑;
[修改]12号线联锁通信服务如果启动失败,则启动参数无法更换bug
2024-06-21 15:53:17 +08:00

159 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package beijing12 北京12号线联锁通信
package beijing12
import (
"context"
"fmt"
"joylink.club/bj-rtsts-server/third_party/tcp"
"log/slog"
"runtime/debug"
"sync"
"time"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/third_party/message"
)
const logTag = "[北京12号线联锁通信]"
// 联锁代理通信接口
type InterlockMessageManager interface {
CollectInterlockRelayInfo(code string) *message.InterlockSendMsgPkg
HandleInterlockDriverInfo(code string, b []byte)
}
// 联锁接口
type InterlockProxy interface {
// 启动联锁消息功能
Start(manager InterlockMessageManager)
// 停止联锁消息功能
Stop()
}
var interlockMap = make(map[string]InterlockProxy)
var initMutex sync.Mutex
//func Default(c *config.InterlockConfig) InterlockProxy {
// initMutex.Lock()
// defer initMutex.Unlock()
// if interlockMap[c.Code] == nil {
// interlockMap[c.Code] = &interlockProxy{runConfig: c}
// }
// return interlockMap[c.Code]
//}
func Start(c *config.InterlockConfig, manager InterlockMessageManager) {
proxy := &interlockProxy{runConfig: c}
proxy.Start(manager)
interlockMap[c.Code] = proxy
}
func Stop(c *config.InterlockConfig) {
proxy := interlockMap[c.Code]
if proxy != nil {
proxy.Stop()
}
}
type interlockProxy struct {
tcpClient *tcp.TcpClient
manager InterlockMessageManager
collectInfoTaskCancel context.CancelFunc
runConfig *config.InterlockConfig
}
// 驱动信息进行转发
func (i *interlockProxy) handleDriverInfo(b []byte) {
slog.Info(fmt.Sprintf("%s收到联锁驱动继电器数据%x", logTag, b))
handler := i.manager
if handler != nil {
handler.HandleInterlockDriverInfo(i.runConfig.Code, b)
}
}
func (i *interlockProxy) Start(manager InterlockMessageManager) {
if i.runConfig == nil || i.runConfig.Ip == "" || !i.runConfig.Open {
return
}
if manager == nil {
panic(fmt.Sprintf("%s启动联锁消息服务错误: InterlockMessageManager不能为nil", logTag))
}
if i.manager != nil {
panic(fmt.Sprintf("%s启动联锁消息服务错误: 存在正在运行的任务", logTag))
}
i.initInterlockProxy()
ctx, cancel := context.WithCancel(context.Background())
go i.collectInfoStateTask(ctx)
i.collectInfoTaskCancel = cancel
i.manager = manager
}
// 采集电路状态发送间隔,单位ms
const InterlockMessageSendInterval = 300
// 序列号
var serialNumber uint8
// 定时发送采集电路状态任务
func (i *interlockProxy) collectInfoStateTask(ctx context.Context) {
defer func() {
if err := recover(); err != nil {
slog.Error(logTag+"定时发送道岔状态任务异常", "error", err, "stack", string(debug.Stack()))
debug.PrintStack()
}
}()
for {
select {
case <-ctx.Done():
return
default:
}
collectInfoState := i.manager.CollectInterlockRelayInfo(i.runConfig.Code)
if collectInfoState != nil {
serialNumber++
collectInfoState.SetSerialNumber(serialNumber)
err := i.tcpClient.Send(collectInfoState.Encode())
if err != nil {
slog.Error(fmt.Sprintf("%s向联锁发送继电器状态失败%s", logTag, err))
} else {
slog.Info(fmt.Sprintf("%s向联锁发送继电器数据成功%x", logTag, collectInfoState.Encode()))
}
}
time.Sleep(time.Millisecond * InterlockMessageSendInterval)
}
}
func (i *interlockProxy) Stop() {
initMutex.Lock()
defer initMutex.Unlock()
delete(interlockMap, i.runConfig.Code)
i.collectInfoTaskCancel()
if i.tcpClient != nil {
i.tcpClient.Close()
}
if i.collectInfoTaskCancel != nil {
i.collectInfoTaskCancel()
}
i.manager = nil
}
func (i *interlockProxy) initInterlockProxy() {
client, err := tcp.StartTcpClient(fmt.Sprintf("%s:%d", i.runConfig.Ip, i.runConfig.RemotePort), i.handleDriveInfo, func(err error) {
slog.Error(fmt.Sprintf("%sTCP客户端读取数据出错终止通信服务%s", logTag, err))
i.Stop()
})
if err != nil {
panic(fmt.Sprintf("%s启动TCP客户端失败%s", logTag, err))
}
i.tcpClient = client
}
func (i *interlockProxy) handleDriveInfo(n int, data []byte) {
data = data[:n]
slog.Info(fmt.Sprintf("%s收到联锁驱动继电器数据%x", logTag, data))
if i.manager != nil {
i.manager.HandleInterlockDriverInfo(i.runConfig.Code, data)
}
}