2023-12-27 18:11:27 +08:00
|
|
|
|
package iscs_sys
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"joylink.club/ecs"
|
|
|
|
|
"joylink.club/ecs/filter"
|
|
|
|
|
"joylink.club/rtsssimulation/component"
|
|
|
|
|
"joylink.club/rtsssimulation/entity"
|
|
|
|
|
"joylink.club/rtsssimulation/repository"
|
|
|
|
|
"joylink.club/rtsssimulation/repository/model/proto"
|
2023-12-29 17:00:26 +08:00
|
|
|
|
"log/slog"
|
2023-12-27 18:11:27 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// FluidDriverSystem 流体驱动系统
|
|
|
|
|
// 实现流体在设备、管线中流动
|
2023-12-29 17:00:26 +08:00
|
|
|
|
// 流体驱动源(风机、送风亭、泵)
|
2023-12-27 18:11:27 +08:00
|
|
|
|
type FluidDriverSystem struct {
|
2024-01-02 17:32:09 +08:00
|
|
|
|
query *ecs.Query //流体驱动源
|
|
|
|
|
drivePathMap map[string][]*SearchedPath //key pipePortId,value 驱动源驱动流体的路径
|
|
|
|
|
queryFluidPipe *ecs.Query
|
2023-12-27 18:11:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewFluidDriverSystem() *FluidDriverSystem {
|
|
|
|
|
return &FluidDriverSystem{
|
2024-01-02 17:32:09 +08:00
|
|
|
|
query: ecs.NewQuery(filter.Contains(component.UidType, component.FluidDriverType)),
|
|
|
|
|
queryFluidPipe: ecs.NewQuery(filter.Contains(component.UidType, component.FluidPipeType)),
|
2023-12-27 18:11:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 17:00:26 +08:00
|
|
|
|
// 获取流体流动路径
|
|
|
|
|
func (s *FluidDriverSystem) findFluidPath(fromDevice repository.Identity, fromDevicePortPipe repository.PipePort, fromIsStart bool) []*SearchedPath {
|
|
|
|
|
pipePortId := fromDevicePortPipe.PipePortId()
|
|
|
|
|
sp, ok := s.drivePathMap[pipePortId]
|
|
|
|
|
if !ok {
|
|
|
|
|
sp = newFluidDriverPathSearcher(fromDevice, fromDevicePortPipe, fromIsStart).search()
|
|
|
|
|
s.drivePathMap[pipePortId] = sp
|
|
|
|
|
}
|
|
|
|
|
return sp
|
2023-12-27 18:11:27 +08:00
|
|
|
|
}
|
|
|
|
|
func (s *FluidDriverSystem) Update(w ecs.World) {
|
|
|
|
|
wd := entity.GetWorldData(w)
|
|
|
|
|
s.query.Each(w, func(entry *ecs.Entry) {
|
|
|
|
|
fdId := component.UidType.Get(entry).Id
|
|
|
|
|
fd := component.FluidDriverType.Get(entry)
|
2023-12-29 17:00:26 +08:00
|
|
|
|
fluidDriverOn := fd.On
|
|
|
|
|
fdModel := wd.Repo.FindById(fdId)
|
|
|
|
|
if fdModel == nil {
|
|
|
|
|
fmt.Printf("==>>FluidDriver[%s]模型不存在\n", fdId)
|
2023-12-27 18:11:27 +08:00
|
|
|
|
} else {
|
2023-12-29 17:00:26 +08:00
|
|
|
|
switch fdModel.Type() {
|
|
|
|
|
case proto.DeviceType_DeviceType_Fan: //风机
|
|
|
|
|
{
|
|
|
|
|
fanModel := fdModel.(*repository.Fan)
|
|
|
|
|
fanOutPort := *fanModel.PortA
|
|
|
|
|
fanInPort := *fanModel.PortB
|
|
|
|
|
fanOutPath := s.findFluidPath(fanModel, fanOutPort, true)
|
|
|
|
|
fanInPath := s.findFluidPath(fanModel, fanInPort, false)
|
|
|
|
|
//
|
2024-01-02 17:32:09 +08:00
|
|
|
|
s.calculateFluid(w, fluidDriverOn, fanOutPath, fanInPath)
|
2023-12-29 17:00:26 +08:00
|
|
|
|
}
|
|
|
|
|
case proto.DeviceType_DeviceType_AirPavilion: //风亭,其中送风亭为动力源
|
2024-01-02 17:32:09 +08:00
|
|
|
|
{
|
|
|
|
|
apModel := fdModel.(*repository.AirPavilion)
|
|
|
|
|
if apModel.PavilionType == proto.AirPavilion_AirSupplyPavilion {
|
|
|
|
|
apOutPort := *apModel.PortA
|
|
|
|
|
apOutPath := s.findFluidPath(apModel, apOutPort, true)
|
|
|
|
|
s.calculateFluid(w, fluidDriverOn, apOutPath, nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
//
|
|
|
|
|
s.queryFluidPipe.Each(w, func(entry *ecs.Entry) {
|
|
|
|
|
pipe := component.FluidPipeType.Get(entry)
|
|
|
|
|
if len(pipe.Sources) > 0 {
|
|
|
|
|
directionAb := int8(0)
|
|
|
|
|
for _, ps := range pipe.Sources {
|
|
|
|
|
if ps.Direction.IsFlowAb() {
|
|
|
|
|
directionAb++
|
|
|
|
|
}
|
|
|
|
|
if ps.Direction.IsFlowBa() {
|
|
|
|
|
directionAb--
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if directionAb > 0 {
|
|
|
|
|
pipe.Direction = component.PipeFlowAb
|
|
|
|
|
} else if directionAb < 0 {
|
|
|
|
|
pipe.Direction = component.PipeFlowBa
|
|
|
|
|
} else {
|
|
|
|
|
pipe.Direction = component.PipeFlowNon
|
2023-12-29 17:00:26 +08:00
|
|
|
|
}
|
2024-01-02 17:32:09 +08:00
|
|
|
|
} else {
|
|
|
|
|
pipe.Direction = component.PipeFlowNon
|
|
|
|
|
pipe.FlowSpeed = 0
|
2023-12-27 18:11:27 +08:00
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 17:00:26 +08:00
|
|
|
|
// 计算流体在管线中的流动参数
|
2024-01-02 17:32:09 +08:00
|
|
|
|
func (s *FluidDriverSystem) calculateFluid(w ecs.World, fluidDriverOn bool, outPath []*SearchedPath, inPath []*SearchedPath) {
|
|
|
|
|
for _, out := range outPath {
|
|
|
|
|
s.clearFluidPathSources(w, out)
|
|
|
|
|
}
|
|
|
|
|
for _, in := range inPath {
|
|
|
|
|
s.clearFluidPathSources(w, in)
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
if fluidDriverOn {
|
|
|
|
|
var validOutPath, validInPath []*SearchedPath
|
|
|
|
|
for _, out := range outPath {
|
|
|
|
|
if s.isFluidPathUnblocked(out, w) {
|
|
|
|
|
validOutPath = append(validOutPath, out)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for _, in := range inPath {
|
|
|
|
|
if s.isFluidPathUnblocked(in, w) {
|
|
|
|
|
validInPath = append(validInPath, in)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
isValid := len(outPath) > 0 && len(inPath) > 0 && len(validInPath) > 0 && len(validOutPath) > 0 || len(outPath) > 0 && len(inPath) == 0 && len(inPath) > 0
|
|
|
|
|
if isValid {
|
|
|
|
|
wd := entity.GetWorldData(w)
|
|
|
|
|
for _, outSp := range validOutPath {
|
|
|
|
|
for _, outPipe := range outSp.ViaPipes {
|
|
|
|
|
pipeEntry := wd.EntityMap[outPipe.Device().Id()]
|
|
|
|
|
fluidPipe := component.FluidPipeType.Get(pipeEntry)
|
|
|
|
|
fluidPipe.Sources = append(fluidPipe.Sources, &component.SourceFlow{Direction: convertFlowDirection(outPipe)})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for _, inSp := range validInPath {
|
|
|
|
|
for _, inPipe := range inSp.ViaPipes {
|
|
|
|
|
pipeEntry := wd.EntityMap[inPipe.Device().Id()]
|
|
|
|
|
fluidPipe := component.FluidPipeType.Get(pipeEntry)
|
|
|
|
|
fluidPipe.Sources = append(fluidPipe.Sources, &component.SourceFlow{Direction: convertFlowDirection(inPipe)})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
func convertFlowDirection(sp repository.PipePort) component.PipeFlowDirection {
|
|
|
|
|
switch sp.Port() {
|
|
|
|
|
case proto.Port_A:
|
|
|
|
|
return component.PipeFlowAb
|
|
|
|
|
case proto.Port_B:
|
|
|
|
|
return component.PipeFlowBa
|
|
|
|
|
default:
|
|
|
|
|
return component.PipeFlowNon
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-29 17:00:26 +08:00
|
|
|
|
|
2024-01-02 17:32:09 +08:00
|
|
|
|
// 清空管线流体源
|
|
|
|
|
func (s *FluidDriverSystem) clearFluidPathSources(w ecs.World, path *SearchedPath) {
|
|
|
|
|
wd := entity.GetWorldData(w)
|
|
|
|
|
for _, pipe := range path.ViaPipes {
|
|
|
|
|
pipeEntry := wd.EntityMap[pipe.Device().Id()]
|
|
|
|
|
fluidPipe := component.FluidPipeType.Get(pipeEntry)
|
|
|
|
|
fluidPipe.Sources = fluidPipe.Sources[0:0]
|
|
|
|
|
}
|
2023-12-29 17:00:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 判断路径是否畅通
|
|
|
|
|
func (s *FluidDriverSystem) isFluidPathUnblocked(fp *SearchedPath, w ecs.World) bool {
|
|
|
|
|
for i := 0; i < len(fp.ViaPipes); i++ {
|
|
|
|
|
viaPipe := fp.ViaPipes[i]
|
|
|
|
|
viaDevice := viaPipe.Device().(*repository.Pipe).PortDevice(viaPipe.Port())
|
|
|
|
|
switch viaDevice.Device().Type() {
|
|
|
|
|
case proto.DeviceType_DeviceType_Environment: //默认畅通
|
|
|
|
|
case proto.DeviceType_DeviceType_PipeFitting: //默认畅通
|
|
|
|
|
case proto.DeviceType_DeviceType_AirPurificationDevice: //默认畅通
|
|
|
|
|
case proto.DeviceType_DeviceType_GasMixingChamber: //默认畅通
|
|
|
|
|
case proto.DeviceType_DeviceType_Valve:
|
|
|
|
|
if s.getValveOpenRate(w, viaDevice.Device().Id()) <= 0 { //阀门未开,路径阻塞
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
case proto.DeviceType_DeviceType_CombinationAirConditioner:
|
|
|
|
|
if !s.isCombinationAirConditionerRunning(w, viaDevice.Device().Id()) { //组合式空调未开,路径阻塞
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 组合式空调是否在运行
|
|
|
|
|
func (s *FluidDriverSystem) isCombinationAirConditionerRunning(w ecs.World, id string) bool {
|
|
|
|
|
wd := entity.GetWorldData(w)
|
|
|
|
|
entry, ok := wd.EntityMap[id]
|
|
|
|
|
if ok {
|
|
|
|
|
air := component.AirConditioningType.Get(entry)
|
|
|
|
|
return air.Running
|
|
|
|
|
} else {
|
|
|
|
|
slog.Warn(fmt.Sprintf("World中未找到组合式空调[%s]的实体", id))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取阀门开度
|
|
|
|
|
func (s *FluidDriverSystem) getValveOpenRate(w ecs.World, valveId string) uint8 {
|
|
|
|
|
wd := entity.GetWorldData(w)
|
|
|
|
|
entry, ok := wd.EntityMap[valveId]
|
|
|
|
|
if ok {
|
|
|
|
|
return component.ValveType.Get(entry).OpenRate
|
|
|
|
|
} else {
|
|
|
|
|
slog.Warn(fmt.Sprintf("World中未找到阀门[%s]的实体", valveId))
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////流体路径相关/////////////////////////////
|
|
|
|
|
|
|
|
|
|
type SearchedPath struct {
|
|
|
|
|
ViaPipes []repository.PipePort //路径所经过的有向管线
|
|
|
|
|
}
|
|
|
|
|
type fluidDriverPathSearcher struct {
|
|
|
|
|
fromDevice repository.Identity //起点设备
|
|
|
|
|
fromDevicePortPipe repository.PipePort //从起点设备的某个端口连接的管线的某个端口开始
|
|
|
|
|
fromIsStart bool //true-以设备输出口为起点;false-以设备输入口为起点
|
|
|
|
|
searchedPaths []*fluidPath //搜索到的路径
|
|
|
|
|
excludePipeIds []string //排除经过这些管线的路径
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newFluidDriverPathSearcher(fromDevice repository.Identity, fromDevicePortPipe repository.PipePort, fromIsStart bool) *fluidDriverPathSearcher {
|
|
|
|
|
return &fluidDriverPathSearcher{fromDevice: fromDevice, fromDevicePortPipe: fromDevicePortPipe, fromIsStart: fromIsStart}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *fluidDriverPathSearcher) search() []*SearchedPath {
|
|
|
|
|
var rt []*SearchedPath
|
|
|
|
|
if !s.exclude(s.fromDevicePortPipe.Device().Id()) {
|
|
|
|
|
searchContext := &fluidPath{}
|
|
|
|
|
searchContext.addPipe(s.fromDevicePortPipe)
|
|
|
|
|
s.doSearch(searchContext)
|
|
|
|
|
} else {
|
|
|
|
|
return rt
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
for _, fp := range s.searchedPaths {
|
|
|
|
|
fpLen := len(fp.viaPipes)
|
|
|
|
|
path := &SearchedPath{}
|
|
|
|
|
if !s.fromIsStart { //以输入口为起点,须反转搜索结果
|
|
|
|
|
for i := fpLen - 1; i >= 0; i-- {
|
|
|
|
|
viaPipe := fp.viaPipes[i]
|
|
|
|
|
path.ViaPipes = append(path.ViaPipes, viaPipe.ToOtherPort())
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for _, viaPipe := range fp.viaPipes {
|
|
|
|
|
path.ViaPipes = append(path.ViaPipes, viaPipe)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rt = append(rt, path)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
return rt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *fluidDriverPathSearcher) exclude(pipeId string) bool {
|
|
|
|
|
for _, excludePipeId := range s.excludePipeIds {
|
|
|
|
|
if excludePipeId == pipeId {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
func (s *fluidDriverPathSearcher) addSearchedPath(searchContext *fluidPath) {
|
|
|
|
|
s.searchedPaths = append(s.searchedPaths, searchContext)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 递归搜索
|
|
|
|
|
func (s *fluidDriverPathSearcher) doSearch(searchContext *fluidPath) {
|
|
|
|
|
nextViaPipes := searchContext.nextViaPathPipes()
|
|
|
|
|
lenNextPipes := len(nextViaPipes)
|
|
|
|
|
if lenNextPipes == 0 {
|
|
|
|
|
s.addSearchedPath(searchContext)
|
|
|
|
|
} else if lenNextPipes == 1 {
|
|
|
|
|
if !searchContext.viaPipe(nextViaPipes[0].Device().Id()) && !s.exclude(nextViaPipes[0].Device().Id()) {
|
|
|
|
|
searchContext.addPipe(nextViaPipes[0])
|
|
|
|
|
s.doSearch(searchContext)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for _, nextViaPipe := range nextViaPipes {
|
|
|
|
|
if searchContext.viaPipe(nextViaPipe.Device().Id()) { //舍弃回头路径
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if s.exclude(nextViaPipe.Device().Id()) { //舍弃排除路径
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
cp := searchContext.clone()
|
|
|
|
|
cp.addPipe(nextViaPipe)
|
|
|
|
|
s.doSearch(cp)
|
2023-12-27 18:11:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-29 17:00:26 +08:00
|
|
|
|
|
|
|
|
|
func (p *fluidPath) nextViaPathPipes() []repository.PipePort {
|
|
|
|
|
nextDevice := p.nextDevice()
|
|
|
|
|
switch nextDevice.Type() {
|
|
|
|
|
case proto.DeviceType_DeviceType_PipeFitting:
|
|
|
|
|
return p.nextDeviceViaPipes(nextDevice.(*repository.PipeFitting).Ports(), p.curPipe)
|
|
|
|
|
case proto.DeviceType_DeviceType_Valve:
|
|
|
|
|
return p.nextDeviceViaPipes(nextDevice.(*repository.Valve).Ports(), p.curPipe)
|
|
|
|
|
case proto.DeviceType_DeviceType_GasMixingChamber:
|
|
|
|
|
return p.nextGasMixingChamberViaPipes(nextDevice.(*repository.GasMixingChamber), p.curPipe)
|
|
|
|
|
case proto.DeviceType_DeviceType_CombinationAirConditioner:
|
|
|
|
|
return p.nextCombinationAirConditionerViaPipes(nextDevice.(*repository.CombinationAirConditioner), p.curPipe)
|
|
|
|
|
case proto.DeviceType_DeviceType_AirPurificationDevice:
|
|
|
|
|
return p.nextDeviceViaPipes(nextDevice.(*repository.AirPurificationDevice).Ports(), p.curPipe)
|
|
|
|
|
default:
|
|
|
|
|
slog.Warn("管线路径中的设备[%d]无法处理", nextDevice.Type())
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
func (p *fluidPath) nextDeviceViaPipes(deviceAllPipePorts []*repository.PipePort, preViaPipe repository.PipePort) []repository.PipePort {
|
|
|
|
|
var rt []repository.PipePort
|
|
|
|
|
findPreViaPipe := false
|
|
|
|
|
for _, pfPort := range deviceAllPipePorts {
|
|
|
|
|
if preViaPipe.Device().Id() != pfPort.Device().Id() {
|
|
|
|
|
rt = append(rt, *pfPort)
|
|
|
|
|
} else {
|
|
|
|
|
findPreViaPipe = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !findPreViaPipe { //校验数据
|
|
|
|
|
panic("preViaPipe没有与设备连接")
|
|
|
|
|
}
|
|
|
|
|
return rt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 组合式空调
|
|
|
|
|
func (p *fluidPath) nextCombinationAirConditionerViaPipes(nextDevice *repository.CombinationAirConditioner, preViaPipe repository.PipePort) []repository.PipePort {
|
|
|
|
|
var rt []repository.PipePort
|
|
|
|
|
if preViaPipe.Device().Id() == nextDevice.PortA.Device().Id() { //从组合式空调的A口进入
|
|
|
|
|
rt = append(rt, *nextDevice.PortB)
|
|
|
|
|
if nextDevice.PortC != nil {
|
|
|
|
|
rt = append(rt, *nextDevice.PortC)
|
|
|
|
|
}
|
|
|
|
|
return rt
|
|
|
|
|
} else if preViaPipe.Device().Id() == nextDevice.PortD.Device().Id() { //从组合式空调的D口进入
|
|
|
|
|
return rt
|
|
|
|
|
}
|
|
|
|
|
return rt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 静压箱
|
|
|
|
|
func (p *fluidPath) nextGasMixingChamberViaPipes(nextDevice *repository.GasMixingChamber, preViaPipe repository.PipePort) []repository.PipePort {
|
|
|
|
|
var rt []repository.PipePort
|
|
|
|
|
if nextDevice.IsInput(preViaPipe.Device().Id()) {
|
|
|
|
|
for _, out := range nextDevice.PortsB {
|
|
|
|
|
rt = append(rt, *out)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return rt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type fluidPath struct {
|
|
|
|
|
curPipe repository.PipePort //路径中当前有向管线
|
|
|
|
|
viaPipes []repository.PipePort //路径所经过的有向管线
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *fluidPath) addPipe(viaPipe repository.PipePort) {
|
|
|
|
|
p.viaPipes = append(p.viaPipes, viaPipe)
|
|
|
|
|
p.curPipe = viaPipe
|
|
|
|
|
}
|
|
|
|
|
func (p *fluidPath) viaPipe(pipeId string) bool {
|
|
|
|
|
for _, vp := range p.viaPipes {
|
|
|
|
|
if vp.Device().Id() == pipeId {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
func (p *fluidPath) clone() *fluidPath {
|
|
|
|
|
cp := &fluidPath{viaPipes: make([]repository.PipePort, 0, len(p.viaPipes)), curPipe: p.curPipe}
|
|
|
|
|
copy(cp.viaPipes, p.viaPipes)
|
|
|
|
|
return cp
|
|
|
|
|
}
|
|
|
|
|
func (p *fluidPath) nextDevice() repository.Identity {
|
|
|
|
|
if p.curPipe.Port() == proto.Port_A {
|
|
|
|
|
return p.curPipe.Device().(*repository.Pipe).PortB.Device()
|
|
|
|
|
} else {
|
|
|
|
|
return p.curPipe.Device().(*repository.Pipe).PortA.Device()
|
|
|
|
|
}
|
|
|
|
|
}
|