diff --git a/config/config.go b/config/config.go index da5d9b0..30d878a 100644 --- a/config/config.go +++ b/config/config.go @@ -190,11 +190,11 @@ type VehiclePCSimConfig2 struct { } type VehiclePCSimConfig struct { - TrainEnds bool `json:"trainEnds" description:"列车端点A?"` - Open bool `json:"open" description:"是否开启"` - PcSimIp string `json:"pcSimIp" description:"pc仿真平台通信ip"` - PcSimPort uint32 `json:"pcSimPort" description:"pc仿真平台通信端口"` - LocalTestingPort uint32 `json:"localTestingPort" description:"本地测试端口"` + TrainEnds bool `json:"trainEnds" description:"列车端点A?"` + Open bool `json:"open" description:"是否开启"` + PcSimIp string `json:"pcSimIp" description:"pc仿真平台通信ip"` + PcSimPort uint32 `json:"pcSimPort" description:"pc仿真平台通信端口"` + //LocalTestingPort uint32 `json:"localTestingPort" description:"本地测试端口"` } // CheckAddress 检测目标源地址目的地址是否在配置中 diff --git a/dto/data_proto/stationLayoutGraphics.pb.go b/dto/data_proto/stationLayoutGraphics.pb.go index 0de0aa6..15b7197 100644 --- a/dto/data_proto/stationLayoutGraphics.pb.go +++ b/dto/data_proto/stationLayoutGraphics.pb.go @@ -5403,8 +5403,8 @@ type LianSuoIndexData struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // 设备id - Index int32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` //设备联锁编号 + Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // 设备id + Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` //设备联锁编号 } func (x *LianSuoIndexData) Reset() { @@ -5439,14 +5439,14 @@ func (*LianSuoIndexData) Descriptor() ([]byte, []int) { return file_stationLayoutGraphics_proto_rawDescGZIP(), []int{54} } -func (x *LianSuoIndexData) GetId() int32 { +func (x *LianSuoIndexData) GetId() uint32 { if x != nil { return x.Id } return 0 } -func (x *LianSuoIndexData) GetIndex() int32 { +func (x *LianSuoIndexData) GetIndex() uint32 { if x != nil { return x.Index } @@ -6661,8 +6661,8 @@ var file_stationLayoutGraphics_proto_rawDesc = []byte{ 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x38, 0x0a, 0x10, 0x4c, 0x69, 0x61, 0x6e, 0x53, 0x75, 0x6f, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x44, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x83, 0x06, 0x0a, + 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x83, 0x06, 0x0a, 0x0b, 0x4c, 0x69, 0x61, 0x6e, 0x53, 0x75, 0x6f, 0x44, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x08, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x4c, 0x69, 0x61, diff --git a/protobuf/main.go b/protobuf/main.go index 3f78414..4295649 100644 --- a/protobuf/main.go +++ b/protobuf/main.go @@ -20,7 +20,7 @@ var ( func main() { //先安装以下插件 - //go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + //go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.33.0 protoFiles := getProtoFiles() // 编译proto文件为Go文件 diff --git a/rts-sim-testing-message b/rts-sim-testing-message index c1499de..0844608 160000 --- a/rts-sim-testing-message +++ b/rts-sim-testing-message @@ -1 +1 @@ -Subproject commit c1499de7bb6e41b56f53c982d516da30988fbd44 +Subproject commit 0844608c8674ec2988c06ba61e73e7b6afe7d660 diff --git a/third_party/can_btm/balise_detection.go b/third_party/can_btm/balise_detection.go index a1c709f..3c0c691 100644 --- a/third_party/can_btm/balise_detection.go +++ b/third_party/can_btm/balise_detection.go @@ -8,7 +8,6 @@ import ( "joylink.club/rtsssimulation/fi" "joylink.club/rtsssimulation/repository" "joylink.club/rtsssimulation/repository/model/proto" - "log/slog" "math" "sort" "sync" @@ -72,7 +71,7 @@ func (t *BaliseDetector) tryRebind(th *TrainHeadPositionInfo) { t.clearExpectedBalise() t.baliseCounter = 0 t.messageCounter = 0 - slog.Debug(fmt.Sprintf("列车[%s]与CAN-BTM绑定", t.trianId)) + //slog.Debug(fmt.Sprintf("列车[%s]与CAN-BTM绑定", t.trianId)) } } diff --git a/third_party/interlock/beijing11/interlock.go b/third_party/interlock/beijing11/interlock.go deleted file mode 100644 index f0c6963..0000000 --- a/third_party/interlock/beijing11/interlock.go +++ /dev/null @@ -1,63 +0,0 @@ -// Package beijing11 北京11号线联锁通信 -package beijing11 - -import ( - "encoding/json" - "fmt" - "joylink.club/bj-rtsts-server/config" - "joylink.club/bj-rtsts-server/third_party/udp" - "log/slog" - "sync" -) - -var ( - initMutex = sync.Mutex{} - logTag = "[北京11号线联锁通信]" - running = false - server udp.UdpServer -) - -func Start(interlockConfig *config.InterlockConfig) { - if interlockConfig == nil || interlockConfig.Ip == "" || !interlockConfig.Open { - return - } - if running { - return - } - initMutex.Lock() - defer initMutex.Unlock() - if running { - return - } - //UDP通信设施 - server = udp.NewServer(fmt.Sprintf(":%d", interlockConfig.LocalPort), func(b []byte) { - slog.Info(fmt.Sprintf("%s收到消息:%x", logTag, b)) - frame := &FromInterlockFrame{} - err := frame.Decode(b) - if err != nil { - slog.Error(fmt.Sprintf("%s解析数据出错:%s", logTag, err)) - } else { - marshal, err := json.Marshal(frame) - if err != nil { - slog.Error(fmt.Sprintf("%s解析为json出错:%s", logTag, err)) - } else { - slog.Info(fmt.Sprintf("%s解析为json:%s", logTag, string(marshal))) - } - } - }) - err := server.Listen() - if err != nil { - panic(fmt.Sprintf("%s启动UDP服务失败:%s", logTag, err)) - } - running = true -} - -func Stop() { - initMutex.Lock() - defer initMutex.Unlock() - running = false - if server != nil { - server.Close() - server = nil - } -} diff --git a/third_party/interlock/beijing11/repo.go b/third_party/interlock/beijing11/repo.go new file mode 100644 index 0000000..93bbb6a --- /dev/null +++ b/third_party/interlock/beijing11/repo.go @@ -0,0 +1,34 @@ +package beijing11 + +// StationDeviceIndexRepo 联锁站设备索引映射 +type StationDeviceIndexRepo struct { + StationName string + TurnoutMap map[uint32]string + PsdMap map[uint32]string + EsbMap map[uint32]string + HoldTrainMap map[uint32]string + SignalMap map[uint32]string + AxleSectionMap map[uint32]string + WrzfMap map[uint32]string + FymMap map[uint32]string + SpksMap map[uint32]string + CkmMap map[uint32]string + XcjMap map[uint32]string +} + +func NewStationDeviceIndexRepo() *StationDeviceIndexRepo { + return &StationDeviceIndexRepo{ + StationName: "", + TurnoutMap: make(map[uint32]string), + PsdMap: make(map[uint32]string), + EsbMap: make(map[uint32]string), + HoldTrainMap: make(map[uint32]string), + SignalMap: make(map[uint32]string), + AxleSectionMap: make(map[uint32]string), + WrzfMap: make(map[uint32]string), + FymMap: make(map[uint32]string), + SpksMap: make(map[uint32]string), + CkmMap: make(map[uint32]string), + XcjMap: make(map[uint32]string), + } +} diff --git a/third_party/interlock/beijing11/service.go b/third_party/interlock/beijing11/service.go new file mode 100644 index 0000000..24eb842 --- /dev/null +++ b/third_party/interlock/beijing11/service.go @@ -0,0 +1,107 @@ +// Package beijing11 北京11号线联锁通信 +package beijing11 + +import ( + "encoding/json" + "fmt" + "joylink.club/bj-rtsts-server/config" + "joylink.club/bj-rtsts-server/dto/data_proto" + "joylink.club/bj-rtsts-server/third_party/udp" + "joylink.club/bj-rtsts-server/ts/simulation/wayside/memory" + "log/slog" + "sync" +) + +const logTag = "[北京11号线联锁通信]" + +var ( + initMutex = sync.Mutex{} + running = false + server udp.UdpServer + sim *memory.VerifySimulation //启动服务所使用的仿真 + iConfig *config.InterlockConfig //启动服务使用的联锁配置 + //联锁区设备的联锁编号与uid的映射 + stationMap map[string]*StationDeviceIndexRepo +) + +func init() { + memory.RegisterListener(func(uidStructure *memory.StationUidStructure, data *data_proto.RtssGraphicStorage) { + //if data.LianSuoData == nil { + // return + //} + ////初始化所有集中站设备映射结构体 + //for _, station := range data.Stations { + // stationMap[station.StationName] = NewStationDeviceIndexRepo() + //} + ////填充 + //stationIdMap := uidStructure.StationIds + ////道岔 + //turnoutUidMap := uidStructure.TurnoutIds + //turnoutIndexMap := make(map[uint32]uint32) + //for _, turnout := range data.LianSuoData.Switchs { + // turnoutIndexMap[turnout.Id] = + //} + //for _, turnout := range data.Turnouts { + // for _, stationCid := range turnout.CentralizedStations { + // stationIdStruct := stationIdMap[stationCid] + // stationDeviceIndexRepo := stationMap[stationIdStruct.Code] + // stationDeviceIndexRepo.TurnoutMap[] + // } + //} + }) +} + +func Start(interlockConfig *config.InterlockConfig, simulation *memory.VerifySimulation) { + if interlockConfig == nil || interlockConfig.Ip == "" || !interlockConfig.Open { + return + } + if running { + return + } + initMutex.Lock() + defer initMutex.Unlock() + if running { + return + } + //UDP通信设施 + server = udp.NewServer(fmt.Sprintf(":%d", interlockConfig.LocalPort), func(b []byte) { + slog.Info(fmt.Sprintf("%s收到消息:%x", logTag, b)) + frame := &FromInterlockFrame{} + err := frame.Decode(b) + if err != nil { + slog.Error(fmt.Sprintf("%s解析数据出错:%s", logTag, err)) + } else { + marshal, err := json.Marshal(frame) + if err != nil { + slog.Error(fmt.Sprintf("%s解析为json出错:%s", logTag, err)) + } else { + slog.Info(fmt.Sprintf("%s解析为json:%s", logTag, string(marshal))) + } + } + }) + err := server.Listen() + if err != nil { + panic(fmt.Sprintf("%s启动UDP服务失败:%s", logTag, err)) + } + running = true + sim = simulation + iConfig = interlockConfig +} + +func Stop() { + initMutex.Lock() + defer initMutex.Unlock() + running = false + if server != nil { + server.Close() + server = nil + } +} + +//func CollectRelayInfo() *FromInterlockFrame { +// sim.World +//} +// +//func HandleDriveInfo(frame *FromInterlockFrame) { +// +//} diff --git a/third_party/interlock/beijing12/interlock.go b/third_party/interlock/beijing12/interlock.go index 7c6a562..a532a78 100644 --- a/third_party/interlock/beijing12/interlock.go +++ b/third_party/interlock/beijing12/interlock.go @@ -4,6 +4,7 @@ package beijing12 import ( "context" "fmt" + "joylink.club/bj-rtsts-server/third_party/tcp" "log/slog" "runtime/debug" "sync" @@ -11,12 +12,9 @@ import ( "joylink.club/bj-rtsts-server/config" "joylink.club/bj-rtsts-server/third_party/message" - "joylink.club/bj-rtsts-server/third_party/udp" ) -const ( - logTag = "[北京12号线联锁通信]" -) +const logTag = "[北京12号线联锁通信]" // 联锁代理通信接口 type InterlockMessageManager interface { @@ -30,8 +28,6 @@ type InterlockProxy interface { Start(manager InterlockMessageManager) // 停止联锁消息功能 Stop() - // 发送联锁采集消息 - SendCollectMessage(b []byte) } var interlockMap = make(map[string]InterlockProxy) @@ -47,8 +43,7 @@ func Default(c *config.InterlockConfig) InterlockProxy { } type interlockProxy struct { - driveInfoUdpServer udp.UdpServer - sendCollectUdpClient udp.UdpClient + tcpClient *tcp.TcpClient manager InterlockMessageManager collectInfoTaskCancel context.CancelFunc @@ -69,17 +64,17 @@ func (i *interlockProxy) Start(manager InterlockMessageManager) { return } if manager == nil { - panic("启动联锁消息服务错误: InterlockMessageManager不能为nil") + panic(fmt.Sprintf("%s启动联锁消息服务错误: InterlockMessageManager不能为nil", logTag)) } if i.manager != nil { - panic("启动联锁消息服务错误: 存在正在运行的任务") + panic(fmt.Sprintf("%s启动联锁消息服务错误: 存在正在运行的任务", logTag)) } i.manager = manager // 初始化客户端、服务端 i.initInterlockProxy() - ctx, cancle := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(context.Background()) go i.collectInfoStateTask(ctx) - i.collectInfoTaskCancel = cancle + i.collectInfoTaskCancel = cancel } // 采集电路状态发送间隔,单位ms @@ -92,7 +87,7 @@ var serialNumber uint8 func (i *interlockProxy) collectInfoStateTask(ctx context.Context) { defer func() { if err := recover(); err != nil { - slog.Error("定时发送道岔状态任务异常", "error", err, "stack", string(debug.Stack())) + slog.Error(logTag+"定时发送道岔状态任务异常", "error", err, "stack", string(debug.Stack())) debug.PrintStack() } }() @@ -106,11 +101,11 @@ func (i *interlockProxy) collectInfoStateTask(ctx context.Context) { if collectInfoState != nil { serialNumber++ collectInfoState.SetSerialNumber(serialNumber) - err := i.sendCollectUdpClient.SendMsg(collectInfoState) + err := i.tcpClient.Send(collectInfoState.Encode()) if err != nil { - slog.Error("向联锁发送继电器状态失败:", err) + slog.Error(fmt.Sprintf("%s向联锁发送继电器状态失败:%s", logTag, err)) } else { - slog.Info(fmt.Sprintf("向联锁发送继电器数据成功:%x", collectInfoState.Encode())) + slog.Info(fmt.Sprintf("%s向联锁发送继电器数据成功:%x", logTag, collectInfoState.Encode())) } } time.Sleep(time.Millisecond * InterlockMessageSendInterval) @@ -121,11 +116,9 @@ func (i *interlockProxy) Stop() { initMutex.Lock() defer initMutex.Unlock() delete(interlockMap, i.runConfig.Code) - if i.sendCollectUdpClient != nil { - i.sendCollectUdpClient.Close() - } - if i.driveInfoUdpServer != nil { - i.driveInfoUdpServer.Close() + i.collectInfoTaskCancel() + if i.tcpClient != nil { + i.tcpClient.Close() } if i.collectInfoTaskCancel != nil { i.collectInfoTaskCancel() @@ -133,12 +126,21 @@ func (i *interlockProxy) Stop() { i.manager = nil } -func (i *interlockProxy) SendCollectMessage(b []byte) { - i.sendCollectUdpClient.Send(b) +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) initInterlockProxy() { - i.sendCollectUdpClient = udp.NewClient(fmt.Sprintf("%v:%v", i.runConfig.Ip, i.runConfig.RemotePort)) - i.driveInfoUdpServer = udp.NewServer(fmt.Sprintf(":%d", i.runConfig.LocalPort), i.handleDriverInfo) - i.driveInfoUdpServer.Listen() +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) + } } diff --git a/third_party/tcp/tcp_client.go b/third_party/tcp/tcp_client.go index dacc61b..f7c481c 100644 --- a/third_party/tcp/tcp_client.go +++ b/third_party/tcp/tcp_client.go @@ -9,25 +9,26 @@ import ( ) type TcpClient struct { - conn *net.TCPConn - handler func(n int, data []byte) - ctx context.CancelFunc - conning bool - properties map[string]interface{} + conn *net.TCPConn + handler func(n int, data []byte) + ctx context.CancelFunc + conning bool } -func StartTcpClient(rAddr string, properties map[string]interface{}, handler func(n int, data []byte, clientProperties map[string]interface{}), readErr func(err error)) (*TcpClient, error) { +func StartTcpClient(rAddr string, handler func(n int, data []byte), readErr func(err error)) (*TcpClient, error) { raddr, addErr := net.ResolveTCPAddr("tcp", rAddr) if addErr != nil { return nil, addErr } conn, err := net.DialTCP("tcp", nil, raddr) ctx, ctxFun := context.WithCancel(context.Background()) - + client := &TcpClient{conn: conn, ctx: ctxFun} if err != nil { + client.ctx = ctxFun + client.conning = false return nil, err } - client := &TcpClient{conn: conn, ctx: ctxFun, properties: properties} + go func() { for { select { @@ -36,21 +37,25 @@ func StartTcpClient(rAddr string, properties map[string]interface{}, handler fun default: } data := make([]byte, 1024) - l, err := conn.Read(data) - if err != nil { - if opErr, ok := err.(*net.OpError); ok { + l, readDataErr := conn.Read(data) + if readDataErr != nil { + if opErr, ok := readDataErr.(*net.OpError); ok { slog.Error(fmt.Sprintf("TCP客户端[rAddr:%s]读取数据异常连接可能断开:", rAddr), opErr) client.conning = false - readErr(err) - } - if err == io.EOF { + readErr(readDataErr) + } else if readDataErr == io.EOF { slog.Warn(fmt.Sprintf("TCP客户端[rAddr:%s]断开连接:", rAddr)) client.conning = false - readErr(err) + readErr(readDataErr) + } else { + slog.Error(fmt.Sprintf("TCP客户端[rAddr:%s]读数据出错:%s", raddr, readDataErr)) + client.conning = false + readErr(readDataErr) } + return } client.conning = true - handler(l, data, client.properties) + handler(l, data) } }() client.conning = true @@ -73,12 +78,12 @@ func (c *TcpClient) IsConning() bool { func (c *TcpClient) Send(data []byte) error { if c == nil || c.conn == nil { - slog.Error("tcp client send error,conn is nil") - return fmt.Errorf("TCP未连接车载PC仿真") + //slog.Error("tcp client send error,conn is nil") + return fmt.Errorf("tcp client send error,conn is nil") } _, err := c.conn.Write(data) if err != nil { - slog.Error("tcp client send error", "error", err) + //slog.Error("tcp client send error", "error", err) return err } return nil diff --git a/third_party/train_pc_sim/example/main.go b/third_party/train_pc_sim/example/main.go index 63391f4..5818285 100644 --- a/third_party/train_pc_sim/example/main.go +++ b/third_party/train_pc_sim/example/main.go @@ -9,6 +9,7 @@ import ( "log/slog" "net" "strconv" + "strings" ) type TcpConnHandler = func(conn net.Conn) @@ -68,12 +69,13 @@ func StartTcpServer(port int, connHandler TcpConnHandler, msgHandler TcpMsgHandl return listen, err } -var serConn net.Conn +var serConnMap map[int]net.Conn = make(map[int]net.Conn) -func createServer(h TcpMsgHandler) { - StartTcpServer(5600, func(conn net.Conn) { +func createServer(port int, h TcpMsgHandler) { + StartTcpServer(port, func(conn net.Conn) { fmt.Println("TCP服务端接收到连接") - serConn = conn + serConnMap[port] = conn + }, h) } func connTrain() *message.TrainPcSimBaseMessage { @@ -162,20 +164,18 @@ func pcSimNumReportOut() *message.TrainPcSimBaseMessage { }) select {} }*/ - -func main() { - - createServer(func(n int, data []byte) { +func startService(port int) { + createServer(port, func(n int, data []byte) { msg := &message.TrainPcSimBaseMessage{} 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) + fmt.Println("接收驾驶端激活 port:", port) + } else if msg.Type == train_pc_sim.SENDER_TRAIN_TC_NOT_ACTIVE { - fmt.Println("接收驾驶端未激活") + fmt.Println("接收驾驶端未激活 port:", port) fmt.Println(pd) } else if msg.Type == train_pc_sim.SENDER_TRAIN_OUTR_INFO { fmt.Println(pd) @@ -194,31 +194,31 @@ func main() { case 4: tt = "制动状态" } - fmt.Println("接受列车输出数字量", tt, s) + fmt.Println("接受列车输出数字量", tt, s, port) fmt.Println(pd) } else if msg.Type == train_pc_sim.RECIVE_TRAIN_CREATE_REMOVE { state := msg.Data[0] if state == 0x01 { - fmt.Println("创建列车") + fmt.Println("创建列车 port:", port) } else if state == 0x00 { - fmt.Println("删除列车") + fmt.Println("删除列车 port:", port) } fmt.Println(pd) } else if msg.Type == train_pc_sim.SENDER_TRAIN_HAND_KEY_FORWARD { - fmt.Println("列车手柄向前") + fmt.Println("列车手柄向前 port:", port) fmt.Println(pd) } else if msg.Type == train_pc_sim.RECIVE_TRAIN_HAND_KEY_CANCLE_FORWARD { - fmt.Println("列车手柄取消向前") + fmt.Println("列车手柄取消向前 port:", port) fmt.Println(pd) } else if msg.Type == train_pc_sim.RECIVE_TRAIN_HAND_KEY_BACKWARD { - fmt.Println("列车手柄向后") + fmt.Println("列车手柄向后 port:", port) fmt.Println(pd) } else if msg.Type == train_pc_sim.RECIVE_TRAIN_HAND_KEY_CACLE_BACKWARD { - fmt.Println("列车手柄取消向后") + fmt.Println("列车手柄取消向后 port:", port) fmt.Println(pd) } else if msg.Type == train_pc_sim.RECIVE_TRAIN_BTM_HAS_DATA { - fmt.Println("有数据应答") + fmt.Println("有数据应答 port:", port) fmt.Println(pd) } else if msg.Type == train_pc_sim.RECIVE_TRAIN_BTM_NOT_DATA { @@ -231,18 +231,30 @@ func main() { }*/ }) +} +func main() { + port1 := 5600 + port2 := 5601 + go startService(port1) + go startService(port2) //reader := bufio.NewReader(os.Stdin) var command string for { - if serConn == nil { - continue - } + fmt.Scanln(&command) if command != "" { - fmt.Println(command) } - + strs := strings.Split(command, ",") + if len(strs) < 2 { + fmt.Println("eeeeeeee") + command = "" + continue + } + p1s, comm := strs[0], strs[1] + portInt, _ := strconv.Atoi(p1s) + serConn := serConnMap[portInt] + command = comm if command == "create-train" { msg := connTrain() serConn.Write(msg.Encode()) diff --git a/third_party/train_pc_sim/train_pc_sim.go b/third_party/train_pc_sim/train_pc_sim.go index fcfbc55..1cbef67 100644 --- a/third_party/train_pc_sim/train_pc_sim.go +++ b/third_party/train_pc_sim/train_pc_sim.go @@ -58,6 +58,40 @@ type TrainPcSimManage interface { // TrainBtmQuery 处理列车btm查询 TrainBtmQuery(connType state_proto.TrainConnState_TrainConnType, data []byte) } +type trainPcReciverData struct { + clientKey string + tcpClient *tcp.TcpClient + pcSimManage TrainPcSimManage +} + +func (rd *trainPcReciverData) receiverDataHandle(n int, data []byte) { + + connType := state_proto.TrainConnState_PC_SIM_A + if rd.clientKey == "B" { + connType = state_proto.TrainConnState_PC_SIM_B + } + baseMsg := &message.TrainPcSimBaseMessage{} + err := baseMsg.Decode(data) + if err != nil { + slog.Error("车载pc仿真接受数据解析失败 ") + return + } + + switch baseMsg.Type { + //case RECIVE_TRAIN_CREATE_REMOVE: + // pc.trainPcSimManage.TrainPcSimConnOrRemoveHandle(baseMsg.Data[0]) + case RECIVE_TRAIN_INTERFACE_CABINET_OUTR: + rd.pcSimManage.TrainPcSimDigitalOutInfoHandle(connType, baseMsg.Data) + case RECIVE_TRAIN_INTERFACE_CABINET_OUTR_BACK: + rd.pcSimManage.TrainPcSimDigitalReportHandle(connType, baseMsg.Data) + case RECIVE_TRAIN_QUERY_STATUS: + rd.pcSimManage.TrainBtmQuery(connType, baseMsg.Data) + case RECIVE_TRAIN_MOCK_DATA: + rd.pcSimManage.TrainPcSimMockInfo(connType, baseMsg.Data) + //case RECIVE_TRAIN_DOOR_MODE: + // pc.trainPcSimManage.TrainDoorModeHandle(baseMsg.Data[0]) + } +} const Name = "车载pc仿真" const CLIENT_KEY = "clientKey" @@ -97,35 +131,52 @@ func Default() TrainPcSim { type trainPcSimService struct { state tpapi.ThirdPartyApiServiceState //pcSimClient *tcp.TcpClient - pcSimClientMap map[string]*tcp.TcpClient - cancleContext context.CancelFunc - trainPcSimManage TrainPcSimManage - speedPlace *message.TrainSpeedPlaceReportMsg - configs []config.VehiclePCSimConfig + //pcSimClientMap map[string]*tcp.TcpClient + newPcSimclientMap map[string]*trainPcReciverData + cancleContext context.CancelFunc + trainPcSimManage TrainPcSimManage + speedPlace *message.TrainSpeedPlaceReportMsg + configs []config.VehiclePCSimConfig } // 接受来自pc仿真的消息 func (d *trainPcSimService) readError(err error) { slog.Error("连接车载pc仿真tcp服务断开", err) d.updateState(tpapi.ThirdPartyState_Broken) - } - -func (d *trainPcSimService) closeAllConn() { - for key, client := range d.pcSimClientMap { - if client != nil { - client.Close() +func (d *trainPcSimService) newCloseAllConn() { + for _, rd := range d.newPcSimclientMap { + if rd != nil { + rd.tcpClient.Close() } - delete(d.pcSimClientMap, key) } +} -} -func (d *trainPcSimService) closeConn(clientKey string) { - if d.pcSimClientMap[clientKey] != nil { - d.pcSimClientMap[clientKey].Close() - delete(d.pcSimClientMap, clientKey) +/* + func (d *trainPcSimService) closeAllConn() { + for key, client := range d.pcSimClientMap { + if client != nil { + client.Close() + } + delete(d.pcSimClientMap, key) + } + } +*/ +func (d *trainPcSimService) newCloseConn(clientKey string) { + rd := d.newPcSimclientMap[clientKey] + if rd != nil { + rd.tcpClient.Close() } } + +/* + func (d *trainPcSimService) closeConn(clientKey string) { + if d.pcSimClientMap[clientKey] != nil { + d.pcSimClientMap[clientKey].Close() + delete(d.pcSimClientMap, clientKey) + } + } +*/ func (d *trainPcSimService) findConfig(tcChar string) (*config.VehiclePCSimConfig, error) { configFlag := false if tcChar == "A" { @@ -144,13 +195,13 @@ func (d *trainPcSimService) findConfig(tcChar string) (*config.VehiclePCSimConfi return nil, fmt.Errorf("") } func (d *trainPcSimService) connTrainPcSim(ctx context.Context) { - //reconnIndex := 0 - //ctx, ctxFun := context.WithCancel(context.Background()) + go func() { for { select { case <-ctx.Done(): - d.closeAllConn() + //d.closeAllConn() + d.newCloseAllConn() return default: } @@ -160,15 +211,22 @@ func (d *trainPcSimService) connTrainPcSim(ctx context.Context) { clientKey := FindTrainPcSimClientKey(t) if clientKey == "" { slog.Error("未找到对应的pc仿真连接,trainId:", t.Id, "删除对应客户端") - d.closeConn(clientKey) + //d.closeConn(clientKey) + + d.newCloseConn(clientKey) continue } - client := d.pcSimClientMap[clientKey] - if !client.IsConning() { - client.Close() - d.initConn(clientKey) + //client := d.pcSimClientMap[clientKey] + rd := d.newPcSimclientMap[clientKey] + if rd == nil { + d.newPcSimclientMap[clientKey] = &trainPcReciverData{pcSimManage: d.trainPcSimManage, clientKey: clientKey, tcpClient: &tcp.TcpClient{}} + } + if !rd.tcpClient.IsConning() { + //client.Close() + d.newCloseConn(clientKey) + d.initConn(clientKey) } } } @@ -181,29 +239,45 @@ func (d *trainPcSimService) connTrainPcSim(ctx context.Context) { func (d *trainPcSimService) initConn(clientKey string) { - client := d.pcSimClientMap[clientKey] - if d.pcSimClientMap[clientKey] == nil { - client = &tcp.TcpClient{} - d.pcSimClientMap[clientKey] = client + rd := d.newPcSimclientMap[clientKey] + if rd == nil { + rd = &trainPcReciverData{pcSimManage: d.trainPcSimManage, clientKey: clientKey, tcpClient: &tcp.TcpClient{}} + d.newPcSimclientMap[clientKey] = rd } - config, _ := d.findConfig(clientKey) - addr := fmt.Sprintf("%v:%v", config.PcSimIp, config.PcSimPort) - properties := map[string]interface{}{ - CLIENT_KEY: clientKey, - } - fmt.Println(properties[CLIENT_KEY]) - client2, err := tcp.StartTcpClient(addr, properties, d.reivceData, d.readError) + cfg, _ := d.findConfig(clientKey) + addr := fmt.Sprintf("%v:%v", cfg.PcSimIp, cfg.PcSimPort) + + client2, err := tcp.StartTcpClient(addr, rd.receiverDataHandle, d.readError) if err != nil { slog.Error("车载pc连接失败 clientKey:", clientKey, "error:", err.Error()) d.updateState(tpapi.ThirdPartyState_Broken) - } else { - d.pcSimClientMap[clientKey] = client2 + rd.tcpClient = client2 } + + /*if d.pcSimClientMap[clientKey] != nil { + return + } + + cfg, _ := d.findConfig(clientKey) + addr := fmt.Sprintf("%v:%v", cfg.PcSimIp, cfg.PcSimPort) + + properties := map[string]interface{}{ + CLIENT_KEY: clientKey, + } + client2, err := tcp.StartTcpClient(addr, properties, d.reivceData, d.readError) + if err != nil { + slog.Error("车载pc连接失败 clientKey:", clientKey, "error:", err.Error()) + d.updateState(tpapi.ThirdPartyState_Broken) + } else { + d.pcSimClientMap[clientKey] = client2 + }*/ + } func (d *trainPcSimService) Start(pcSimManage TrainPcSimManage) { configs := pcSimManage.GetTrainPcSimConfig() - d.pcSimClientMap = map[string]*tcp.TcpClient{} + d.newPcSimclientMap = make(map[string]*trainPcReciverData) + //d.pcSimClientMap = map[string]*tcp.TcpClient{} if len(configs) <= 0 { slog.Info("车载pc仿真配置未开启") return @@ -218,7 +292,6 @@ func (d *trainPcSimService) Start(pcSimManage TrainPcSimManage) { slog.Info("车载pc仿真配置未开启") return } - d.configs = configs ctx, ctxFun := context.WithCancel(context.Background()) d.cancleContext = ctxFun @@ -235,7 +308,8 @@ func (d *trainPcSimService) Stop() { d.cancleContext() d.cancleContext = nil } - d.closeAllConn() + //d.closeAllConn() + d.newCloseAllConn() } func (d *trainPcSimService) CreateOrRemoveSpeedPLace(train *state_proto.TrainState) { if train.ConnState.Conn && (train.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_A || train.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_B) { @@ -248,18 +322,31 @@ func (d *trainPcSimService) CreateOrRemoveSpeedPLace(train *state_proto.TrainSta } func (d *trainPcSimService) CreateOrRemoveTrain(train *state_proto.TrainState, msgType byte, data []byte) error { clientKey := FindTrainPcSimClientKey(train) + log := "删除列车" if msgType == RECIVE_TRAIN_CREATE_REMOVE && data[0] == 0x01 { + log = "创建列车" d.initConn(clientKey) } - msg := &message.TrainPcSimBaseMessage{Data: data, Type: uint16(msgType)} - client := d.pcSimClientMap[clientKey] + rd := d.newPcSimclientMap[clientKey] + if rd != nil { + sd := msg.Encode() + slog.Info(fmt.Sprintf("%v-列车号:%v,发送数据:%v", log, train.Id, hex.EncodeToString(sd))) + err := rd.tcpClient.Send(sd) + if err != nil { + return err + } + if data[0] != 0x01 { + d.newCloseConn(clientKey) + } + } + /*client := d.pcSimClientMap[clientKey] err := client.Send(msg.Encode()) if data[0] != 0x01 { d.closeConn(clientKey) - } + }*/ - return err + return nil } // 依据文档80ms发送列车速度位置 @@ -274,15 +361,24 @@ func (d *trainPcSimService) sendTrainLocationAndSpeedTask(ctx context.Context) { for _, train := range trains { if train.ConnState.Conn && train.PluseCount != nil { clientKey := FindTrainPcSimClientKey(train) + rd := d.newPcSimclientMap[clientKey] - client := d.pcSimClientMap[clientKey] s1, s2 := train.PluseCount.PulseCount1, train.PluseCount.PulseCount2 d.speedPlace.ParsePulseCount1(s1, s2) data := d.speedPlace.Encode(train.TrainRunUp, s1, s2) bm := &message.TrainPcSimBaseMessage{Type: SENDER_TRAIN_LOCATION_INFO, Data: data} train.PluseCount.PulseCount1 = 0 train.PluseCount.PulseCount2 = 0 - client.Send(bm.Encode()) + rd.tcpClient.Send(bm.Encode()) + + /*client := d.pcSimClientMap[clientKey] + s1, s2 := train.PluseCount.PulseCount1, train.PluseCount.PulseCount2 + d.speedPlace.ParsePulseCount1(s1, s2) + data := d.speedPlace.Encode(train.TrainRunUp, s1, s2) + bm := &message.TrainPcSimBaseMessage{Type: SENDER_TRAIN_LOCATION_INFO, Data: data} + train.PluseCount.PulseCount1 = 0 + train.PluseCount.PulseCount2 = 0 + client.Send(bm.Encode())*/ } } @@ -296,7 +392,8 @@ func (d *trainPcSimService) SendDriverActive(train *state_proto.TrainState) { vobc := train.VobcState clientKey := FindTrainPcSimClientKey(train) - client := d.pcSimClientMap[clientKey] + //client := d.pcSimClientMap[clientKey] + rd := d.newPcSimclientMap[clientKey] defulatBuf := make([]byte, 0) msg := &message.TrainPcSimBaseMessage{Data: defulatBuf} if train.TrainRunUp { @@ -313,10 +410,11 @@ func (d *trainPcSimService) SendDriverActive(train *state_proto.TrainState) { } } da := msg.Encode() - slog.Info("发送驾驶激活 列车", train.Id, "数据", hex.EncodeToString(da)) - err := client.Send(da) + slog.Info("发送驾驶激活列车", train.Id, "数据", hex.EncodeToString(da)) + err := rd.tcpClient.Send(da) + //err := client.Send(da) if err != nil { - slog.Error("发送驾驶激活 列车", train.Id, "数据", hex.EncodeToString(da), err) + slog.Error("发送驾驶激活列车", train.Id, "数据", hex.EncodeToString(da), err) } } func (d *trainPcSimService) SendHandleSwitch(oldTraction, oldBrakeForce int64, tractionState bool, train *state_proto.TrainState) { @@ -324,7 +422,9 @@ func (d *trainPcSimService) SendHandleSwitch(oldTraction, oldBrakeForce int64, t if tc.Conn { vobc := train.VobcState clientKey := FindTrainPcSimClientKey(train) - client := d.pcSimClientMap[clientKey] + rd := d.newPcSimclientMap[clientKey] + + //client := d.pcSimClientMap[clientKey] msg := &message.TrainPcSimBaseMessage{} newTraction := vobc.TractionForce newBrake := -vobc.BrakeForce @@ -355,7 +455,8 @@ func (d *trainPcSimService) SendHandleSwitch(oldTraction, oldBrakeForce int64, t } da := msg.Encode() slog.Info("发送列车手柄消息", "clientKey", clientKey, "msg", hex.EncodeToString(da)) - err := client.Send(da) + err := rd.tcpClient.Send(da) + //err := client.Send(da) if err != nil { slog.Error("发送列车手柄消息失败", "clientKey", clientKey, "msg", hex.EncodeToString(da)) } @@ -373,11 +474,13 @@ func (d *trainPcSimService) SendTrainDirection(train *state_proto.TrainState, tr baseMsgs = append(baseMsgs, &message.TrainPcSimBaseMessage{Type: RECIVE_TRAIN_HAND_KEY_BACKWARD}) } clientKey := FindTrainPcSimClientKey(train) - client := d.pcSimClientMap[clientKey] + rd := d.newPcSimclientMap[clientKey] + //client := d.pcSimClientMap[clientKey] for _, msg := range baseMsgs { da := msg.Encode() slog.Info("发送列车方向列车", train.Id, "数据", hex.EncodeToString(da)) - err := client.Send(da) + err := rd.tcpClient.Send(da) + //err := client.Send(da) if err != nil { slog.Error("发送列车方向失败列车", train.Id, "数据", hex.EncodeToString(da)) } @@ -389,11 +492,13 @@ func (d *trainPcSimService) SendBaliseData(train *state_proto.TrainState, msgTyp msg.Type = msgType msg.Data = data clientKey := FindTrainPcSimClientKey(train) - client := d.pcSimClientMap[clientKey] + rd := d.newPcSimclientMap[clientKey] + + //client := d.pcSimClientMap[clientKey] da := msg.Encode() slog.Info("发送列车PC仿真应答器信息,数据", hex.EncodeToString(da)) - err := client.Send(da) + err := rd.tcpClient.Send(da) if err != nil { slog.Info("发送列车PC仿真应答器信息失败,数据", hex.EncodeToString(da)) } @@ -414,20 +519,23 @@ func (d *trainPcSimService) PublishTrainControlEvent(train *state_proto.TrainSta return } clientKey := FindTrainPcSimClientKey(train) - client := d.pcSimClientMap[clientKey] + rd := d.newPcSimclientMap[clientKey] + + //client := d.pcSimClientMap[clientKey] for _, event := range events { msg := &message.TrainPcSimBaseMessage{} msg.Type = SENDER_TRAIN_OUTR_INFO data := []byte{event.Command, event.Status} msg.Data = data - client.Send(msg.Encode()) + rd.tcpClient.Send(msg.Encode()) + //client.Send(msg.Encode()) //FireTrainControlEventType.Publish(world, &event) } } // 接受来自pc仿真的消息 -func (d *trainPcSimService) reivceData(len int, data []byte, properties map[string]interface{}) { +/*func (d *trainPcSimService) reivceData(len int, data []byte, properties map[string]interface{}) { clientKey := properties[CLIENT_KEY] ck := fmt.Sprintf("%v", clientKey) if d.pcSimClientMap[ck] == nil { @@ -460,4 +568,4 @@ func (d *trainPcSimService) reivceData(len int, data []byte, properties map[stri //case RECIVE_TRAIN_DOOR_MODE: // pc.trainPcSimManage.TrainDoorModeHandle(baseMsg.Data[0]) } -} +}*/ diff --git a/ts/simulation/wayside/memory/wayside_memory_map_init.go b/ts/simulation/wayside/memory/wayside_memory_map_init.go index 4947a52..ab7efa6 100644 --- a/ts/simulation/wayside/memory/wayside_memory_map_init.go +++ b/ts/simulation/wayside/memory/wayside_memory_map_init.go @@ -13,6 +13,15 @@ import ( "joylink.club/rtsssimulation/repository" ) +// 地图数据处理方法。目前用于不同通信协议所需数据的预处理 +type MapDataHandler func(uidStructure *StationUidStructure, data *data_proto.RtssGraphicStorage) + +var mapDataHandlerList = make([]MapDataHandler, 0) + +func RegisterListener(handler MapDataHandler) { + mapDataHandlerList = append(mapDataHandlerList, handler) +} + var giUidMap sync.Map type elementIdStructure struct { @@ -426,6 +435,10 @@ func initStationUid(data *data_proto.RtssGraphicStorage) *StationUidStructure { Uid: GenerateElementUid(city, lineId, nil, xcj.Code), } } + //通信协议预处理所需数据 + for _, handler := range mapDataHandlerList { + handler(gus, data) + } return gus } diff --git a/ts/simulation/wayside/memory/wayside_memory_train.go b/ts/simulation/wayside/memory/wayside_memory_train.go index 29e77fa..e7a999f 100644 --- a/ts/simulation/wayside/memory/wayside_memory_train.go +++ b/ts/simulation/wayside/memory/wayside_memory_train.go @@ -153,7 +153,7 @@ func TrainConnTypeUpdate(vs *VerifySimulation, ct *dto.TrainConnThirdDto) { connTypeName := "半实物" if tmpTrain.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_A { connTypeName = "车载pc仿真-A" - } else if tmpTrain.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_A { + } else if tmpTrain.ConnState.ConnType == state_proto.TrainConnState_PC_SIM_B { connTypeName = "车载pc仿真-B" } panic(sys_error.New(fmt.Sprintf("列车[%s]已经连接 [%v],此列车无法连接", k, connTypeName))) @@ -165,7 +165,7 @@ func TrainConnTypeUpdate(vs *VerifySimulation, ct *dto.TrainConnThirdDto) { train.ConnState.Conn = true train.ConnState.ConnType = ct.ConnType if ct.ConnType == state_proto.TrainConnState_PC_SIM_A || ct.ConnType == state_proto.TrainConnState_PC_SIM_B { - err := TrainPcSimConnOrRemoveHandle(train) + err := TrainPcSimConnOrRemoveHandle(train, true) if err != nil { train.ConnState.Conn = false train.ConnState.ConnType = state_proto.TrainConnState_NONE @@ -184,7 +184,7 @@ func TrainUnConn(vs *VerifySimulation, trainId string) { panic(sys_error.New(fmt.Sprintf("列车【%s】不存在", trainId))) } train := data.(*state_proto.TrainState) - err := TrainPcSimConnOrRemoveHandle(train) + err := TrainPcSimConnOrRemoveHandle(train, false) if err != nil { panic(sys_error.New("未连接车载PC仿真,无法断开连接")) } @@ -462,7 +462,7 @@ func removeTrain(vs *VerifySimulation, trainId string, train *state_proto.TrainS } if train.ConnState.Conn { train.ConnState.Conn = false - err = TrainPcSimConnOrRemoveHandle(train) + err = TrainPcSimConnOrRemoveHandle(train, false) if err != nil { train.ConnState.Conn = true return err diff --git a/ts/simulation/wayside/memory/wayside_simulation_train_pc.go b/ts/simulation/wayside/memory/wayside_simulation_train_pc.go index 449c60c..e743ac2 100644 --- a/ts/simulation/wayside/memory/wayside_simulation_train_pc.go +++ b/ts/simulation/wayside/memory/wayside_simulation_train_pc.go @@ -458,15 +458,14 @@ func (s *VerifySimulation) TrainPcSimDigitalReportHandle(connType state_proto.Tr } // 创建/删除列车 -func TrainPcSimConnOrRemoveHandle(train *state_proto.TrainState) error { +func TrainPcSimConnOrRemoveHandle(train *state_proto.TrainState, create bool) error { - var data byte = 0x01 - if train.ConnState.Conn == false { - data = 0x00 + var data byte = 0x00 + if create { + data = 0x01 } connState := train.ConnState if connState.ConnType == state_proto.TrainConnState_PC_SIM_A || connState.ConnType == state_proto.TrainConnState_PC_SIM_B { - crErr := train_pc_sim.Default().CreateOrRemoveTrain(train, train_pc_sim.RECIVE_TRAIN_CREATE_REMOVE, []byte{data}) if crErr != nil { return crErr diff --git a/ts/test_simulation_manage.go b/ts/test_simulation_manage.go index 076dde9..cd2d704 100644 --- a/ts/test_simulation_manage.go +++ b/ts/test_simulation_manage.go @@ -124,7 +124,7 @@ func runThirdParty(s *memory.VerifySimulation) error { for _, c := range s.GetInterlockCodes() { switch c.Line { case "11": - beijing11.Start(c) + beijing11.Start(c, s) default: beijing12.Default(c).Start(s) }