磁导航1.0内部交管和信号交互

This commit is contained in:
ykkokluo
2026-08-24 14:55:35 +08:00
parent cacc5fea5c
commit 244b0af6c8
60 changed files with 6395 additions and 294 deletions
@@ -16,7 +16,7 @@ using StandardScene.Utils;
namespace StandardScene.Signal
{
/// <summary>
/// 第三方信号交互进程(场景 <c>scene.signal</c> 的唯一 Mission)。
/// 第三方信号交互进程(场景 <c>scene.signal</c>:PLC 握手 / 放行;磁条交管见 <c>MagTrafficMission</c>)。
/// </summary>
/// <remarks>
/// <para>
@@ -65,9 +65,9 @@ namespace StandardScene.Signal
/// <summary>
/// 西门子系列,传给 IoTClient <c>SiemensVersion</c>。
/// 常用 <c>S7_1500</c> / <c>S7_1200</c> / <c>S7_300</c>;连字符会当成下划线解析
/// 机构表 PLC类型为「跟随进程」时使用本项;机构单独指定则用机构值
/// </summary>
[FieldMember] public string PlcVersion = "S7_1500";
[FieldMember] public SignalPlcType PlcVersion = SignalPlcType.S7_1500;
/// <summary>机构未单独填 Port 时使用的 S7 端口,默认 102。</summary>
[FieldMember] public int PlcPort = 102;
@@ -84,6 +84,9 @@ namespace StandardScene.Signal
/// <summary>握手点表路径。按站点配置 JGControl / PointControl / TimedCharging / RateFlowControl。</summary>
[FieldMember] public string HandshakePointsPath = @"Config\Signal\handshake-points.json";
/// <summary>机构工位表。相对路径只解析工作目录 Config/Signal。</summary>
[FieldMember] public string DocksPath = @"Config\Signal\station-docks.json";
/// <summary>Execute 成功后为 trueReloadConfig 仅在已启动时重启 Worker / 扫车。</summary>
[JsonIgnore] private bool _started;
@@ -126,6 +129,12 @@ namespace StandardScene.Signal
/// <summary>实际解析到的握手点文件绝对路径。</summary>
public string HandshakePointsFile { get; set; }
/// <summary>实际解析到的工位文件绝对路径。</summary>
public string DocksFile { get; set; }
/// <summary>工位 JSON 条数。</summary>
public int DockCount { get; set; }
/// <summary>各机构运行态快照,供监视列表展示。</summary>
public List<PlcStationSnapshot> Stations { get; set; } = new List<PlcStationSnapshot>();
}
@@ -170,23 +179,26 @@ namespace StandardScene.Signal
public void ReloadConfig()
{
var stationsFile = SignalConfigStore.Resolve(StationsPath);
var docksFile = SignalConfigStore.Resolve(DocksPath);
var releaseFile = SignalConfigStore.Resolve(ReleasePointsPath);
var handshakeFile = SignalConfigStore.Resolve(HandshakePointsPath);
var stations = SignalConfigStore.Load<PlcStationModel>(stationsFile);
var bundles = PlcConfigLoader.Load(stationsFile, docksFile);
var points = SignalConfigStore.Load<ReleasePointModel>(releaseFile);
var handshake = SignalConfigStore.Load<HandshakePointModel>(handshakeFile);
var st = (SignalInteractMissionStatus)status;
st.StationCount = stations.Count;
st.StationCount = bundles.Count;
st.DockCount = bundles.Sum(b => b.Docks.Count);
st.ReleasePointCount = points.Count;
st.HandshakePointCount = handshake.Count;
st.StationsFile = stationsFile;
st.DocksFile = docksFile;
st.ReleasePointsFile = releaseFile;
st.HandshakePointsFile = handshakeFile;
st.Stations = stations.Select(s => new PlcStationSnapshot { JgName = s.JgName }).ToList();
st.Stations = bundles.Select(b => new PlcStationSnapshot { JgName = b.Station.JgName }).ToList();
status.status = _started ? "运行中" : "配置已加载";
Diagnosis.Post(
$"信号配置已加载:机构 {stations.Count};握手点 {handshake.Count} @ {handshakeFile};放行点 {points.Count} @ {releaseFile}",
$"信号配置已加载:机构 {bundles.Count},工位 {st.DockCount} @ {docksFile};握手点 {handshake.Count} @ {handshakeFile};放行点 {points.Count} @ {releaseFile}",
"Signal", true);
if (_started)
@@ -224,6 +236,24 @@ namespace StandardScene.Signal
}
}
/// <summary>CycleGUI 独立窗体编辑工位表;主键为机构名+工位编号。</summary>
[MethodMember(Name = "打开工位列表", Description = "按 PlcStationDockModel 增删改工位点位")]
public void OpenDocks()
{
try
{
var path = SignalConfigStore.Resolve(DocksPath);
ModelListPanel<PlcStationDockModel>.Open(
"机构工位配置",
path,
x => x == null ? "" : $"{x.JgName}/{x.ResolvedDockId}");
}
catch (Exception ex)
{
CycleUiHelper.Alert("错误", $"打开工位列表失败:{ex.Message}");
}
}
/// <summary>CycleGUI 独立窗体编辑握手点;主键展示为「站点号 + 信号类型」。</summary>
[MethodMember(Name = "打开握手点列表", Description = "按站点配置 JGControl / PointControl / TimedCharging / RateFlowControl")]
public void OpenHandshakePoints()
@@ -266,7 +296,7 @@ namespace StandardScene.Signal
get
{
lock (_workerLock)
return _workers.Select(w => w.Runtime).ToList();
return _workers.SelectMany(w => w.Docks).ToList();
}
}
@@ -285,25 +315,28 @@ namespace StandardScene.Signal
/// <summary>
/// 先停全部旧连接,再按机构表为每个非空名称建 <see cref="PlcStationWorker"/>。
/// 机构 Port&lt;=0 时回退进程级 <see cref="PlcPort"/>。
/// 机构 Port&lt;=0 时回退进程级 <see cref="PlcPort"/>PLC类型跟随进程时用 <see cref="PlcVersion"/>
/// </summary>
private void RestartWorkers()
{
StopWorkers();
var stationsFile = SignalConfigStore.Resolve(StationsPath);
var stations = SignalConfigStore.Load<PlcStationModel>(stationsFile)
.Where(s => !string.IsNullOrWhiteSpace(s.JgName))
.ToList();
var bundles = PlcConfigLoader.Load(
SignalConfigStore.Resolve(StationsPath),
SignalConfigStore.Resolve(DocksPath));
var created = new List<PlcStationWorker>();
lock (_workerLock)
{
foreach (var station in stations)
foreach (var bundle in bundles)
{
var station = bundle.Station;
var port = station.Port > 0 ? station.Port : PlcPort;
var runtime = new PlcStationRuntime(station);
var session = new SiemensPlcSession(PlcVersion, station.Ip, port, PlcSlot);
var worker = new PlcStationWorker(runtime, session, PlcPollMs, RefreshStatus);
var sync = new object();
var runtimes = bundle.Docks
.Select(d => new PlcStationRuntime(station, d, sync))
.ToList();
var session = new SiemensPlcSession(ResolvePlcType(station), station.Ip, port, PlcSlot);
var worker = new PlcStationWorker(station, runtimes, session, sync, PlcPollMs, RefreshStatus);
_workers.Add(worker);
created.Add(worker);
}
@@ -315,6 +348,15 @@ namespace StandardScene.Signal
PushStatus();
}
/// <summary>机构选跟随进程(含旧 JSON 缺省 0)时用进程 PlcVersion;进程若也是跟随进程则按 S7_1500。</summary>
private string ResolvePlcType(PlcStationModel station)
{
var type = station.PlcType == SignalPlcType. ? PlcVersion : station.PlcType;
if (type == SignalPlcType.)
type = SignalPlcType.S7_1500;
return type.ToString();
}
/// <summary>清空列表后再 Stop,避免扫车在停连接过程中仍拿到旧 Runtime。</summary>
private void StopWorkers()
{
@@ -345,7 +387,7 @@ namespace StandardScene.Signal
{
List<PlcStationSnapshot> snaps;
lock (_workerLock)
snaps = _workers.Select(w => w.Runtime.ToSnapshot()).ToList();
snaps = _workers.SelectMany(w => w.Docks.Select(d => d.ToSnapshot())).ToList();
var st = (SignalInteractMissionStatus)status;
st.Stations = snaps;