using SKMC.Api.Common; using SKMC.Api.Common.Tasks; using SKMC.Api.Motion.Control; using System; using System.Collections.Concurrent; using System.Collections.Generic; namespace SKMC.Api.Process.Model { /// ///

流程站点

///
每个流程站点由多个ProcessStep组成一个循环流程
///
public abstract class ProcessStation { protected static readonly ILogger log = LogFactory.Get(); /// /// 线性流程引擎 /// private readonly ProcessFlow processFlow = ObjectFactory.Create(); /// /// 持久化接口 /// protected readonly ProcessStorage processStorage = ObjectFactory.Create(); /// /// 流程站点管理器 /// public ProcessStationManager ProcessStationManager { get; set; } /// /// 物料状态, 使用物料类型、状态值组合 /// public ConcurrentDictionary MatStatuses { get; set; } = new ConcurrentDictionary(); /// /// 流程站点的内置数据集 /// public ConcurrentDictionary DataMapping { get; set; } = new ConcurrentDictionary(); /// /// 流程动作控制接口 /// protected readonly IMotionControl motionControl = ObjectFactory.Resolve(); private int id; public int Id { get { return id; } set { id = value; processFlow.Id = value; } } public string Name { get; set; } /// /// station复位时执行 /// public Action OnReset { get; set; } /// /// station复位结果, 0:复位成功 /// public int ResetResult { get; set; } = -1; /// /// station启动时执行 /// public Action OnStart { get; set; } /// /// station停止后执行 /// public Action OnStop { get; set; } /// /// station暂停后执行 /// public Action OnPause { get; set; } /// /// station暂停恢复后执行 /// public Action OnResume { get; set; } /// /// station恢复状态后执行 /// public Action OnRestore { get; set; } /// /// 每轮循环开始前执行 /// public Action OnPrepare { set => processFlow.OnPrepare = value; } /// /// 触发入料事件时执行 /// public Action Onload { get; set; } /// /// 完全收到物料准备开工时 /// public Action OnReady { get; set; } /// /// 触发出料事件后执行 /// public Action OnUnload { get; set; } /// /// 物料完全离开后执行 /// public Action OnExit { get; set; } /// /// 是否空闲(站内没有物料) /// public bool IsIdle { get; set; } /// /// 安全运行的判断条件 /// public Func SafeChecker { get; set; } /// /// 站点运行状态, 同设备状态, 见DeviceStatusEnum /// public int RunStatus { get; set; } /// /// 多工位序号, 同一类ProcessStation的多个实例, 使用该属性区分 /// public short StationIndex { get; set; } /// /// 获取流程步骤 /// /// 流程步骤Id /// public virtual ProcessStep Get(int processStepId) => processFlow.Get(processStepId); /// /// 注册流程步骤 /// /// 流程步骤 public virtual void Register(ProcessStep processStep) => processFlow.Register(processStep); /// /// 设置流程起始的步骤, 后续流程不变 /// /// 流程步骤 public virtual void SetFirst(ProcessStep processStep) => processFlow.SetFirst(processStep); /// /// 设置流程起始的步骤, 后续流程不变 /// /// 流程步骤Id public virtual void SetFirst(int processStepId) => processFlow.SetFirst(processStepId); /// /// 提交下个流程步骤 /// public virtual void PostAutoNext() => processFlow.PostAutoNext(); /// /// 提交指定的流程步骤 /// /// 流程步骤 public virtual void PostManual(ProcessStep processStep) => processFlow.PostManual(processStep); /// /// 提交指定的流程步骤 /// /// 流程步骤Id public virtual void PostManual(int processStepId) => processFlow.PostManual(Get(processStepId)); /// /// 直接调用一个流程步骤的Actions(自动模式的下一个) /// public virtual void CallAutoNext() => processFlow.CallAutoNext(); /// /// 直接调用一个流程步骤的Actions(手动模式指定) /// /// 流程步骤 public virtual void CallManual(ProcessStep processStep) => processFlow.CallManual(processStep); /// /// 直接调用一个流程步骤的Actions(手动模式指定) /// /// 流程步骤Id public virtual void CallManual(int processStepId) => processFlow.CallManual(Get(processStepId)); /// /// 获取数据对象 /// /// /// /// 流程站点的Id, 如果是本站则为-1 /// 是否从持久化获取, 如果为true并且从持久化获取成功, 将覆盖掉内存中已有的数据 /// public virtual T GetData(string key, int stationId = -1, bool fromStorage = false) { //if (fromStorage) LoadStationData(new[] { key }, true); //GetProcessStation(stationId).DataMapping.TryGetValue(key, out object dataVal); //return (T) dataVal; ProcessStation processStation = GetProcessStation(stationId); if (fromStorage) processStorage.LoadStationData(this, new[] { key }, true); if (processStation.DataMapping.ContainsKey(key)) { if (processStation.DataMapping[key] != null) { T t = (T)processStation.DataMapping[key]; return t; } } return default; } /// /// 获取数据对象并从数据集中删除 /// /// /// /// /// public virtual T TakeData(string key, int stationId = -1) { ProcessStation processStation = GetProcessStation(stationId); if (processStation.DataMapping.ContainsKey(key)) { if (processStation.DataMapping[key] != null) { T t = (T)processStation.DataMapping[key]; processStation.DataMapping.TryRemove(key, out _); return t; } } //return default; throw new KeyNotFoundException($"TakeData Failed, can't find key[{key}] from station[{processStation.Id}]"); } /// /// 添加数据对象 /// /// /// /// 流程站点的Id, 如果是本站则为-1 /// 是否持久化保存, 如果为true将覆盖掉持久化中已有的数据 public virtual void SetData(string key, object value, int stationId = -1, bool toStorage = false) { GetProcessStation(stationId).DataMapping.AddOrUpdate(key, value, (k, oldValue) => value); if (stationId == -1) stationId = Id; log.Debug($"Set Station[{stationId}] Data , key: {key}, value: {value}"); if (toStorage) { processStorage.SaveStationData(this, new[] { key }, true); } } /// /// 删除数据对象 /// /// /// 流程站点的Id, 如果是本站则为-1 /// 是否持久化同步删除 public virtual void RemoveData(string key, int stationId = -1, bool toStorage = false) { bool result = GetProcessStation(stationId).DataMapping.TryRemove(key, out _); if (result && toStorage) processStorage.DeleteStationData(this, new[] { key }); } /// /// 清除本站内的数据对象 /// public void ClearData(int stationId = -1, bool toStorage = false) { GetProcessStation(stationId).DataMapping.Clear(); if (toStorage) processStorage.DeleteStationDataAll(this); } /// /// 检查任务中断点是否触发 /// /// 触发中断后的动作 /// public virtual bool CheckTaskCancelled(Action onCancel = null) { TaskTokener.SetWaitPoint(Id); if (TaskTokener.IsCancelled(Id)) { onCancel?.Invoke(); return true; } return false; } /// /// 启动流程 /// public virtual void Start() { processFlow.Start(); TaskTokener.Add(Id); OnStart?.Invoke(); processFlow.PostFirst(); } /// /// 停止流程 /// 是否有后续停止动作 /// public virtual void Stop(bool hasAction = false) { processFlow.Stop(); TaskTokener.Stop(Id); if (hasAction) OnStop?.Invoke(); } /// /// 复位流程 /// public virtual void Reset() { processFlow.Reset(); TaskTokener.Add(Id); OnReset?.Invoke(); } /// /// 暂停流程 /// public virtual void Pause() { processFlow.Pause(); TaskTokener.Pause(Id); OnPause?.Invoke(); } /// /// 恢复流程 /// public virtual void Resume() { processFlow.Resume(); OnResume?.Invoke(); TaskTokener.Resume(Id); } public virtual void Restore() { OnRestore?.Invoke(); TaskTokener.Add(Id); } /// /// 获取流程站点的物料状态 /// /// 状态类型, 可以是物料也可以是站点 /// 流程站点的Id, 如果是本站则为-1 /// 是否从持久化获取, 如果为true并且从持久化获取成功, 将覆盖掉内存中已有的数据 /// public int GetStationStatus(int matType, int stationId = -1, bool fromStorage = false) { if (fromStorage) processStorage.LoadStationStatus(this, new[] { matType }, true); GetProcessStation(stationId).MatStatuses.TryGetValue(matType, out int statusVal); return statusVal; } /// /// 判断流程站点的物料状态是否在给定的物料状态值内 /// 只要满足其中一个状态值返回true, 全部不满足返回false /// /// 状态类型, 可以是物料也可以是站点 /// 流程站点的Id, 如果是本站则为-1 /// 需要比较的物料状态值集合 /// public bool CheckStationStatus(int matType, int stationId, int[] statusVals) { int statusVal = GetStationStatus(matType, stationId); bool checkResult = false; foreach (int val in statusVals) { if (val == statusVal) return true; } return checkResult; } /// /// 设置流程站点的物料状态 /// /// 状态类型, 可以是物料也可以是站点 /// 状态值 /// 站点Id, -1表示本站 /// 是否持久化保存, 如果为true将覆盖掉持久化中已有的数据 public void SetStationStatus(int matType, int status, int stationId = -1, bool toStorage = false) { int newStatus = GetProcessStation(stationId).MatStatuses.AddOrUpdate(matType, status, (key, oldValue) => status); if (stationId == -1) stationId = Id; log.Debug($"Set Station[{stationId}] Status, matType: {matType}, status check: {status == newStatus}, val: (expected:{status}, actual:{newStatus})"); if (toStorage) { processStorage.SaveStationStatus(this, new[] { matType }, true); } } /// /// 删除流程站点的物料状态 /// /// /// /// 是否同步删除持久化中的物料状态 public void RemoveStationStatus(int matType, int stationId = -1, bool toStorage = false) { bool result = GetProcessStation(stationId).MatStatuses.TryRemove(matType, out _); if (result && toStorage) processStorage.DeleteStationStatus(this, new[] { matType }); } /// /// 清除流程站点的所有状态 /// /// public void ClearStationStatus(int stationId = -1, bool toStorage = false) { GetProcessStation(stationId).MatStatuses.Clear(); if (toStorage) processStorage.DeleteStationStatusAll(this); } private ProcessStation GetProcessStation(int stationId = -1) { ProcessStation processStation = (stationId == -1) ? this : ProcessStationManager.Get(stationId); if (processStation == null) throw new ArgumentNullException($"Cannot Find stationId[{stationId}] Object"); return processStation; } } }