using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Rs.MotionPlat.Flow; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; namespace Rs.MotionPlat.Commom { /// /// 排料通讯 /// public class Scheduling { /// /// 指令 /// public EInstruction Instruction { get; set; } /// /// 组ID /// public int GroupID { get; set; } /// /// 周转ID /// public int TurnoverID { get; set; } /// /// 发送或接收时间 /// public DateTime Time { get; set; } = DateTime.Now; public override string ToString() => JsonConvert.SerializeObject(this, new StringEnumConverter()); } public class SchedulingConnectionInfo : Scheduling { public EType Type { get; set; } public enum EType { Scheduling, ScannerMotion } } /// /// 上下料 /// public class SchedulingMaterial : Scheduling { public List ActionItems { get; set; } public SchedulingMaterial() { } } public struct ActionItem { /// /// 产品条码 /// public string SN; /// /// 取料信息 /// public ActionInfo Load; /// /// 放料信息 /// public ActionInfo To; public ActionItem(ActionInfo load, ActionInfo to,string _SN) { SN=_SN; Load = load; To = to; } } public struct ActionInfo { /// /// 类型 /// public TurnoverType Type; /// /// 分区名 /// public string RangeName; /// /// 层(仅多功能时用) /// public int Floor; /// /// 料盘索引(仅周转盘用) /// public int Index; public ActionInfo(TurnoverType type, int floor, string rangeName, int index) { Type = type; RangeName = rangeName; Floor = floor; Index = index; } } public class TurnoverInfos : Scheduling { /// /// 周转信息 /// public List Infos { get; set; } /// /// 跳过取放信息 /// public List SkipInfos { get; set; } } public class TurnoverInfo { #region 冗余字段 [JsonIgnore] public EInstruction Instruction; [JsonIgnore] public int GroupID; [JsonIgnore] public int TurnoverID; [JsonIgnore] public string GUID = string.Empty; [JsonIgnore] public ETaskMode taskMode = ETaskMode.Load; #endregion public string SN; /// /// 来源类型 /// public TurnoverType FromType; /// /// 来源料仓所在层,如是周转盘则为0 /// public int FromFloor; /// /// 来源索引 /// public int FromIndex; /// /// 目标类型 /// public TurnoverType ToType; /// /// 目标料仓所在层,如是周转盘则为0 /// public int ToFloor; /// /// 目标索引 /// public int ToIndex; /// /// 使用的吸嘴编号 /// public int SuckerNo; public bool Dealed; public TurnoverInfo(EInstruction _Instruction,int _GroupID,int _TurnoverID,string _SN,TurnoverType fromType, int fromFloor, int fromIndex, TurnoverType toType, int toFloor, int toIndex, int suckerNo,bool _Dealed=false) { Dealed = _Dealed; Instruction = _Instruction; GroupID = _GroupID; TurnoverID = _TurnoverID; SN = _SN; FromType = fromType; FromFloor = fromFloor; FromIndex = fromIndex; ToType = toType; ToFloor = toFloor; ToIndex = toIndex; SuckerNo = suckerNo; } public TurnoverInfo() { } } public struct SkipInfo { public TurnoverType Type; public int Floor; public int Index; public SkipCause Cause; public string Message; public SkipInfo(TurnoverType type, int floor, int index, SkipCause cause, string message) { Type = type; Floor = floor; Index = index; Cause = cause; Message = message; } } public enum SkipCause { Empty, Error } public enum TurnoverType { /// /// 未知 /// Unknown, /// /// 待测料仓 /// ToBeTested, /// /// OK仓 /// Passed, /// /// NG仓 /// Failed, /// /// 多功能仓 /// Multifunction, /// /// 周转盘 /// Turnover, /// /// 换料缓存 /// Buffer, /// /// 重测缓存盘 /// BufferTray, /// /// 清洗料盘 /// CleanPad, /// /// 测试治具 /// Tester } /// /// 取料失败 /// public class SchedulingTakingError : Scheduling { /// /// ID /// public int ID { get; set; } /// /// 周转类型 /// public TurnoverType Type { get; set; } /// /// 当前层 /// public int Floor { get; set; } /// /// 托盘索引 /// public int Index { get; set; } /// /// 使用的吸嘴索引 /// public int SuckerIndex { get; set; } = -1; /// /// 处理方式,中控返回时提供 /// public TakeErrorHandle Handle { get; set; } } public enum TakeErrorHandle { /// /// 重取 /// Retry, /// /// 跳过当前穴位 /// Skip, /// /// 结束本轮取料 /// End } public class SchedulingSiloBase : Scheduling { public ESiloType SiloType { get; set; } public EMultifunctionType MultifunctionType { get; set; } public enum ESiloType { /// /// 待测料仓 /// ToBeTested, /// /// OK仓 /// Passed, /// /// NG仓 /// Failed, /// /// 多功能仓 /// Multifunction } public enum EMultifunctionType { /// /// 无 /// None, /// /// 默认 /// Default, /// /// 第二层 /// Floor1, /// /// 第三层 /// Floor2, /// /// 第四层 /// Floor3 } } /// /// 托盘产品分区范围 /// public class TrayProductRange : SchedulingSiloBase { /// /// 该分区的名称 /// public string Name { get; set; } public int Left { get; set; } public int Top { get; set; } public int Right { get; set; } public int Bottom { get; set; } } public class SiloRearrange : SchedulingSiloBase { public enum EOrientation { Horizontal, Vertical } /// /// 排列方向 /// public EOrientation Orientation { get; set; } } public class SchedulingSilo : SchedulingSiloBase { public enum ESwitchOrientation { /// /// 切到下一个 /// Next, /// /// 切回上一个 /// Previous } public enum ESiloStatus { /// /// 停止 /// Stopped, /// /// 就绪 /// Standby, /// /// 切换中 /// Switching, /// /// 空,无料盘 /// None } /// /// 料仓状态 /// public ESiloStatus SiloStatus { get; set; } /// /// 切换方向 /// public ESwitchOrientation Orientation { get; set; } /// /// 料仓当前层 == 时无效 /// public int SiloFloor { get; set; } } public class SchedulingMoveScanner : Scheduling { /// /// 点位 1~32 (<= 100) 托盘穴位点位, 101~102 (>100) 托盘条码点位 /// public int Point { get; set; } } public class SchedulingMoveScannerResult : SchedulingMessage { /// /// 当前点位或移动中的目标点位 /// public int Point { get; set; } /// /// 当前移动状态 /// public EMoveState MoveState { get; set; } public enum EMoveState { /// /// 已到达 /// Ready, /// /// 移动中 /// Moving, /// /// 发生错误,无法恢复 /// Error, /// /// 中断,出现异常中断,可恢复 /// Interrupt } } /// /// 排料报警 /// //public class SchedulingAlarms : Scheduling //{ // /// // /// 报警项,如果item1 == item2 将会认作同一报警 // /// // public IList Alarms { get; set; } // public struct AlarmItem : IAlarmItem // { // /// // /// 报警序号 // /// // public int NO { get; set; } // /// // /// 引发报警的节点UID // /// // public long NodeUID { get; set; } // /// // /// 引发报警节点的穴位索引(如:周转盘穴位 3) // /// // public int? Index // { // readonly get => Indexes is HashSet list && list.Count > 0 ? list.Last() : null; // set // { // if (value is not int index) return; // HashSet list = Indexes ??= new(); // if (!list.Contains(index)) // { // list.Add(index); // } // } // } // /// // /// 引发报警的节点的穴位索引列表 // /// // public HashSet Indexes { get; set; } // /// // /// 报警标签 // /// // public string Tag { get; set; } // /// // /// 该报警是否会造成停机 // /// // public bool Pause { get; set; } // /// // /// 报警等级 // /// // public AlarmLevel Level { get; set; } // /// // /// 已在别的地方展示,只收录,不弹窗 // /// // public bool ShowElsewhere { get; set; } // /// // /// 报警消息英文版 // /// // public string EN { get; set; } // /// // /// 报警消息中文版 // /// // public string ZH { get; set; } // readonly IReadOnlySet IAlarmItem.Indexes => Indexes; // public readonly string GetMessage(CultureInfo culture) // { // return culture.TwoLetterISOLanguageName.ToLower() switch // { // "en" => EN, // _ => ZH, // }; // } // public readonly string ToDescription(CultureInfo culture) => $"{GetString(nameof(NO), culture)}: {NO} " // + $"{GetString(nameof(NodeUID), culture)}: {NodeUID} " // + $"{GetString(nameof(Index), culture)}: {Indexes.ToStringEx()} " // + $"{GetString(nameof(Tag), culture)}: {Tag} " // + $"{GetString(nameof(Pause), culture)}: {Pause} " // + $"{GetString(nameof(EN), culture)}: {EN} " // + $"{GetString(nameof(ZH), culture)}: {ZH}"; // public override readonly bool Equals(object obj) => obj is IAlarmItem other && Equals(other); // /// // /// 相等比较方法 // /// // /// // /// // public readonly bool Equals(IAlarmItem other) => NO == other.NO && NodeUID == other.NodeUID && SequenceEqual(Indexes, other.Indexes) && Tag == other.Tag; // public override readonly int GetHashCode() => HashCode.Combine(NO, NodeUID, Indexes, Tag); // public override readonly string ToString() => $"{Tag} No.{NO} {NodeUID} {Indexes.ToStringEx()} {ZH}"; // public static bool operator ==(AlarmItem left, AlarmItem right) => left.Equals(right); // public static bool operator !=(AlarmItem left, AlarmItem right) => !(left == right); // } // public SchedulingAlarms() { } // public SchedulingAlarms(params AlarmItem[] items) => Alarms = items; //} /// /// 排料状态信息 /// public class SchedulingStatusInfo : Scheduling { /// /// 查询或切换时的状态类型 /// public InfoType Type { get; set; } /// /// 查询时返回或切换时需要切换到的状态信息 /// public string Info { get; set; } public bool TryConvertInfoTo(out TEnum result) where TEnum : struct { try { if (typeof(TEnum).IsEnum) return Enum.TryParse(Info, true, out result); result = (TEnum)Convert.ChangeType(Info, typeof(TEnum)); return true; } catch { result = default; return false; } } public enum InfoType { /// /// 上下料状态, /// State, /// /// 设备运行状态, /// RunStatus, /// /// 运行模式, /// RunMode, /// /// 初始化状态, /// InitializeState, /// /// 物料分配模式(带料OR不带料), /// AssignMode, /// /// 温度, /// Temperature, /// /// 气压(double) /// AirPressure } } /// /// 排料消息 /// public class SchedulingMessage : Scheduling { /// /// 消息 /// public string Message { get; set; } } /// /// 中控状态 /// public class MachineState : SchedulingMessage { /// /// 设备状态 /// public ERunState State { get; set; } public MachineState() { } } /// /// 排料结果 /// public class SchedulingResult : SchedulingMessage { /// /// 结果 /// public bool Result { get; set; } = true; /// /// 设备状态 /// public ERunState State { get; set; } public SchedulingResult() { } } /// /// 排料弹窗请求 /// public class SchedulingMessageBox : SchedulingMessage { [Flags] public enum ETipButton { None = 0, Yes = 1 << 0, No = 1 << 1, Ok = 1 << 2, Cancel = 1 << 3, Retry = 1 << 4, Skip = 1 << 5, YesNo = Yes | No, OkCancel = Ok | Cancel, OkRetryCancel = Ok | Retry | Cancel, RetrySkip = Retry | Skip } /// /// 请求弹窗按钮,返回用户点击的按钮 /// public ETipButton Button { get; set; } = ETipButton.YesNo; /// /// 请求的ID,返回时将带上该id作为标识 /// public int ID { get; set; } /// /// 弹窗标题 /// public string Title { get; set; } /// /// 图片路径,如为null或则不显示图片 /// public string PicturePath { get; set; } /// /// 字体大小 /// public double FontSize { get; set; } = 15; /// /// 窗口宽度 /// public double WindowWidth { get; set; } = 800; /// /// 窗口高度 /// public double WindowHeight { get; set; } = 800; /// /// 倒计时,单位秒,小于0不启用 /// public int Countdown { get; set; } = System.Threading.Timeout.Infinite; /// /// 倒计时结束时按下的按钮 /// public ETipButton CountdownResult { get; set; } = ETipButton.Yes; public SchedulingMessageBox() { } } /// /// 指令 /// public enum EInstruction { /// /// 查询连接功能 发送: 回复: /// InquireConnectionInfo, /// /// 上下料 发送: 回复: /// LoadAndUnload, /// /// 排料机回传上下料结果 排料机发送 /// LoadAndUnloadResult, /// /// 取消当前 执行中的排料指令,发送: 回复: /// CancelLoadAndUnload, /// /// 查询状态 发送: 回复: /// InquireStatus, /// /// 切换状态 发送: 回复: /// SwitchStatus, /// /// 清除报警 发送: 回复: /// ClearAlarm, /// /// 获取配方列表 发送: 回复: /// GetRecipeList, /// /// 设置配方 发送: 回复: /// SetRecipe, /// /// 获取当前配方 发送: 回复: /// GetCurrentRecipe, /// /// 周转盘就绪查询 排料机发送 中控回复: /// TurnoverReady, /// /// 通知排料运行状态变更 发送 回复: /// ChangeState, /// /// 弹消息提示窗 排料机发送 中控回复: /// ShowMessage, /// /// 取消消息弹窗 排料机发送 中控回复: /// CloseMessage, /// /// 设备按钮按下 排料机发送 中控回复: , /// 其中内容为枚举.ToString() /// MachineButtonDown, /// /// 设备按钮松开 排料机发送 中控回复: , /// 其中内容为枚举.ToString() /// MachineButtonUp, /// /// 设置托盘产品分区范围 发送: 回复: /// TrayProductRange, /// /// 清空托盘产品分区范围 发送: 回复: /// ClearTrayProductRange, /// /// 请求切换料盘 发送 回复: /// RequestSwitchTray, /// /// 开始切换料盘 发送 回复: /// BeginSwitchTray, /// /// 查询料仓状态 发送 回复: /// InquireSiloStatus, /// /// 移动扫码枪 发送 回复收到的: /// MoveScanner, /// /// 查询移动扫码枪结果 发送 回复: /// InquireMoveScannerState, /// /// 设置报警 排料机发送 中控回复收到的 /// SetAlarms, /// /// 取消报警 排料机发送 中控回复收到的 /// CancelAlarms, /// /// 最后一盘, 发送 回复 /// IsLastBeforeTray, /// /// 结束上新, 发送 回复 /// EndInput, /// /// 取料失败, 排料机发送 回复, 里提供接下来该做的处理方式 /// TakingError, /// /// 取消取料失败, 排料机发送, 里提供接下来该做的处理方式 /// CancelTakingError, /// /// 重排料仓当前料盘物料方向 发送: 回复: /// Rearrange, /// /// 重排料仓当前料盘物料方向的结果 发送: /// RearrangeResult, /// /// 扫描条码, 中控发送 回复 /// ScanBarcode } /// /// 运行模式 /// public enum ERunMode { /// /// 手动 /// Manual, /// /// 自动 /// Automatic } /// /// 设备运行状态 /// public enum ERunStatus { /// /// 已开始 /// Started, /// /// 已停止 /// Stopped, /// /// 报警中 /// InAlarm, /// /// 急停中 /// EMGStop } /// /// 初始化状态 /// public enum EInitializeState { /// /// 未初始化 /// Uninitialized, /// /// 初始化中 /// Initializing, /// /// 已初始化 /// Initialized } /// /// 物料分配模式 /// public enum EAssignMode { /// /// 正常 /// Normal, /// /// 无料空跑 /// NoDevice } /// /// 设备按钮 /// public enum EMachineButton { Start, Stop, EMGStop, Initialize, Ok, Cancel, Retry, Skip, Lighting, Door } /// /// 上下料状态 /// public enum ERunState { /// /// 等待指令 /// Waiting, /// /// 忙碌中 /// Busying, /// /// 下料中 /// Unloading, /// /// 发生错误,无法恢复 /// Error, /// /// 中断,出现异常中断,可恢复 /// Interrupt } }