using SKMC.Api.Common;
using SKMC.Api.Common.Logger;
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;
}
}
}