using System; using SimpleCore.Library; using StandardScene.Signal.Model; namespace StandardScene.Signal.Plc { /// /// 单个机构的运行态(不进 JSON)。扫车线程改写目标写字节,PLC Worker 负责真正下发。 /// /// /// 赋值 会把 置 false,下一拍 Worker 发现 /// 目标与回读不一致就会重写 PLC。回读与目标一致后再标成功,AutoLeave 才继续往下一状态走。 /// 所有读写应在 内进行。 /// public sealed class PlcStationRuntime { private SignalWriteValue _writeSignal; private SignalReadValue _readSignal; private SignalWriteValue _readWriteSignal; public PlcStationRuntime(PlcStationModel config) { Config = config ?? throw new ArgumentNullException(nameof(config)); } /// 本机构静态配置(IP、DB 地址、地标、机构类型)。 public PlcStationModel Config { get; } /// 扫车线程与 PLC Worker 共用运行态,写入时加此锁。 public object Sync { get; } = new object(); /// PLC→调度:允许进入 / 允许离开 / 无状态。变化时打诊断。 public SignalReadValue ReadSignal { get => _readSignal; set { if (_readSignal != value) Diagnosis.Log($"{Config.JgName} 读信号 {_readSignal} → {value}", "PLC", true); _readSignal = value; } } /// /// 调度→PLC 的目标写字节。赋值即视为尚未写成功,驱动 Worker 重写。 /// public SignalWriteValue WriteSignal { get => _writeSignal; set { if (_writeSignal != value) Diagnosis.Log($"{Config.JgName} 写信号 {_writeSignal} → {value}", "PLC", true); _writeSignal = value; WriteSuccess = false; } } /// 从写地址回读到的当前值,用来确认 PLC 是否已吃进目标字节。 public SignalWriteValue ReadWriteSignal { get => _readWriteSignal; set { if (_readWriteSignal != value) Diagnosis.Log($"{Config.JgName} 回读写值 {_readWriteSignal} → {value}", "PLC", true); _readWriteSignal = value; } } /// 已报到在机构内的 AGV 号;0 表示没有。Arrived / 上线自动到位 时写入。 public int InAgvNo { get; set; } /// 已获准进入、正在往机构开的 AGV 号;到位或离站清空后为 0。 public int RequestInAgvNo { get; set; } /// 最近一拍 PLC 读写是否成功。心跳或读写失败会立刻变 false。 public bool IsConnected { get; set; } /// 目标写字节是否已与 PLC 回读一致。改 WriteSignal 时自动清掉。 public bool WriteSuccess { get; set; } /// 内存侧心跳翻转标志,供监视面板看到 Worker 在跑;真正写 PLC 的是 HeartDb 位翻转。 public bool Heart { get; set; } /// 最近一次断线或周期异常原因,连接正常时清空。 public string LastError { get; set; } = ""; /// 拷贝一份给 MissionStatus / 监视列表,避免 UI 直接绑运行态。 public PlcStationSnapshot ToSnapshot() => new PlcStationSnapshot { JgName = Config.JgName, IsConnected = IsConnected, ReadSignal = ReadSignal.ToString(), WriteSignal = WriteSignal.ToString(), ReadWriteSignal = ReadWriteSignal.ToString(), InAgvNo = InAgvNo, RequestInAgvNo = RequestInAgvNo, WriteSuccess = WriteSuccess, Heart = Heart, LastError = LastError ?? "" }; } }