Files
StandardSence/StandardScene.Core/Chained/LoopMission.cs
T
2026-06-14 11:19:15 +08:00

164 lines
5.9 KiB
C#

using IoTClient.Clients.PLC;
using IoTClient.Common.Enums;
using LessokajiWeaverUtilities.Utilities;
using Newtonsoft.Json;
using SimpleLite.RCS;
using SimpleLite.RCS.CarTypes;
using SimpleCore.Library;
using StandardScene.Chained;
using StandardScene.Model;
using System.Collections.Concurrent;
using System.Threading;
using static StandardScene.Chained.AbstractLoopMission;
namespace StandardScene
{
public class LoopMissionStatus : AbstractLoopMissionStatus
{
}
[MissionType(Name = "环线进程", editor = typeof(LoopMission))]
[I18N.DocumentTranslation(Name = "Loop Mission", locale = "en")]
public class LoopMission : AbstractLoopMission
{
[JsonIgnore] public override MissionStatus status { get; set; } = new LoopMissionStatus();
[JsonIgnore] public Thread myThread;
[JsonIgnore] public bool started = false;
[JsonIgnore] private readonly ConcurrentDictionary<int, byte> _buttonTriggeredSiteIds = new ConcurrentDictionary<int, byte>();
public float ChargesocStandard = 30;
public float NoChargesocStandard = 80;
/// <summary>
/// API 触发:检查站点物料状态
/// </summary>
protected override ExternalTriggerResult OnApiTrigger(int currentSiteId, LoopTask task, Car car)
{
/* var site = SimpleLib.GetSite(currentSiteId);
if (site != null && site.fields.TryGetValue("hasMaterial", out var val) && val == "true")
{
// 物料存在,使用配置目标
return ExternalTriggerResult.UseConfigTarget();
}
return ExternalTriggerResult.Fail();*/
if (car.status.enums.TryGetValue("Soc", out var soc))
{
if (float.Parse(soc) <= ChargesocStandard)
{
//使用配置目标
return ExternalTriggerResult.UseConfigTarget();
}
}
/* var plcTarget = 17;
if (plcTarget > 0)
{
// PLC 指定了目标站点
return ExternalTriggerResult.UseTarget(plcTarget);
}*/
return ExternalTriggerResult.Fail();
}
/// <summary>
/// PLC 触发:根据 PLC 信号决定目标
/// </summary>
protected override ExternalTriggerResult OnPlcTrigger(int currentSiteId, LoopTask task, Car car)
{
//var plcTarget = ReadPlcTargetSite(currentSiteId);
SiemensClient client = new SiemensClient(SiemensVersion.S7_200Smart, "127.0.0.1", 103);
var M100 = client.ReadBoolean("M100").Value;
if (M100)
{
//使用配置目标
return ExternalTriggerResult.UseConfigTarget();
}
/* var plcTarget = 17;
if (plcTarget > 0)
{
// PLC 指定了目标站点
return ExternalTriggerResult.UseTarget(plcTarget);
}*/
return ExternalTriggerResult.Fail();
}
protected override ExternalTriggerResult OnChargeTrigger(int currentSiteId, LoopTask task, Car car)
{
//使用配置目标
return ExternalTriggerResult.UseConfigTarget();
if (car.status.enums.TryGetValue("Soc", out var soc))
{
if (float.Parse(soc) >= NoChargesocStandard)
{
//使用配置目标
return ExternalTriggerResult.UseConfigTarget();
}
}
}
/// <summary>
/// 供 ButtonMission 反射调用:登记一个需要按钮放行的站点。
/// 如果站点已经存在于字典中则忽略,避免重复放行信号堆积。
/// </summary>
/// <param name="siteId">需要放行的站点 ID,通常对应 LoopTask.CurrentStationId</param>
/// <returns>始终返回 true,表示本次按钮触发已被接受</returns>
public bool EnqueueButtonTriggerSite(int siteId)
{
if (siteId <= 0)
{
Diagnosis.Log($"按钮放行登记失败:无效站点 {siteId}", "LoopMission", true);
return false;
}
var car = FindCarArrivedAtSite(siteId);
if (car == null)
{
Diagnosis.Post($"按钮放行登记忽略:站点 {siteId} 当前没有到站车辆", "LoopMission", false);
return false;
}
if (_buttonTriggeredSiteIds.TryAdd(siteId, 0))
{
Diagnosis.Post($"按钮放行登记成功:站点 {siteId},车辆 {car.name}", "LoopMission", false);
}
else
{
Diagnosis.Post($"按钮放行已存在,忽略重复登记:站点 {siteId}", "LoopMission", false);
}
return true;
}
/// <summary>
/// 按钮盒触发:只有当前站点已被按钮登记过,才允许使用配置目标放行。
/// 命中后立即消费并删除,保证一次按钮只放行一次。
/// </summary>
protected override ExternalTriggerResult OnButtonTrigger(int currentSiteId, LoopTask task, Car car)
{
if (_buttonTriggeredSiteIds.TryRemove(currentSiteId, out _))
{
Diagnosis.Post($"按钮放行消费成功:站点 {currentSiteId},车辆 {car?.name}", "LoopMission", false);
return ExternalTriggerResult.UseConfigTarget();
}
return ExternalTriggerResult.Fail();
}
/* private int ReadPlcTargetSite(int siteId)
{
// 从 PLC 读取目标站点的业务逻辑
// 返回 0 表示未获取到有效目标
return 0;
}
*/
}
}