From fe387059329761448bea770ff4aaa95716ae09b7 Mon Sep 17 00:00:00 2001 From: NXX <447201003@qq> Date: Mon, 16 May 2022 13:43:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6MORKIC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BPASmartClient.DRCoffee/CommandHandler.cs | 85 +++ BPASmartClient.DRCoffee/MorkCStatus.cs | 76 ++ BPASmartClient.GSIceCream/CommandHandler.cs | 118 ++++ BPASmartClient.GSIceCream/MorkIStatus.cs | 131 ++++ BPASmartClient.Lebai/LebaiRobot.cs | 135 ++++ BPASmartClient.Model/BatchingInfoPar.cs | 21 + BPASmartClient.Model/单片机/SCChipEvent.cs | 14 + .../BPASmartClient.MorkT.csproj | 1 + BPASmartClient.MorkT/Control_MorkT.cs | 164 +++++ BPASmartClient.MorkT/Device_MorkT.cs | 36 - BPASmartClient.MorkT/GLV_MorkT.cs | 37 + BPASmartClient.MorkT/OrderLocInfo.cs | 22 + BPASmartClient.MorkT/PolymerBatching.cs | 122 ++++ BPASmartClient.SCChip/ChipStatus.cs | 132 ++++ BPASmartClient.SCChip/CommandHandler.cs | 197 ++++++ .../BPASmartClient.MORKIC.csproj | 23 + HBLConsole.MORKIC/Control_MORKIC.cs | 647 ++++++++++++++++++ HBLConsole.MORKIC/PolymerBatching.cs | 122 ++++ SmartClient.sln | 9 +- 19 files changed, 2055 insertions(+), 37 deletions(-) create mode 100644 BPASmartClient.DRCoffee/CommandHandler.cs create mode 100644 BPASmartClient.DRCoffee/MorkCStatus.cs create mode 100644 BPASmartClient.GSIceCream/CommandHandler.cs create mode 100644 BPASmartClient.GSIceCream/MorkIStatus.cs create mode 100644 BPASmartClient.Model/BatchingInfoPar.cs create mode 100644 BPASmartClient.MorkT/Control_MorkT.cs delete mode 100644 BPASmartClient.MorkT/Device_MorkT.cs create mode 100644 BPASmartClient.MorkT/GLV_MorkT.cs create mode 100644 BPASmartClient.MorkT/OrderLocInfo.cs create mode 100644 BPASmartClient.MorkT/PolymerBatching.cs create mode 100644 BPASmartClient.SCChip/ChipStatus.cs create mode 100644 BPASmartClient.SCChip/CommandHandler.cs create mode 100644 HBLConsole.MORKIC/BPASmartClient.MORKIC.csproj create mode 100644 HBLConsole.MORKIC/Control_MORKIC.cs create mode 100644 HBLConsole.MORKIC/PolymerBatching.cs diff --git a/BPASmartClient.DRCoffee/CommandHandler.cs b/BPASmartClient.DRCoffee/CommandHandler.cs new file mode 100644 index 00000000..7e05e827 --- /dev/null +++ b/BPASmartClient.DRCoffee/CommandHandler.cs @@ -0,0 +1,85 @@ + +using BPASmartClient.EventBus; +using BPASmartClient.Model; +using BPASmartClient.Model.咖啡机.Enum; +using BPASmartClient.SerialPort; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using static BPASmartClient.EventBus.EventBus; + +namespace BPASmartClient.DRCoffee +{ + /// + /// 指令封装 + /// + internal class CommandHandler + { + byte[] cmdAsk; + private SerialPortClient commProxy; + private DrCoffeePackage drinksOrder = new DrCoffeePackage(); + + public Action PauseAsk { get; set; } + /// + /// 初始化 + /// + internal void Init(SerialPortClient commProxy) + { + this.commProxy = commProxy; + + DrCoffeePackage package = new DrCoffeePackage(); + package.CommCmd = DrCoffeeCommCmd.饮品制作指令; + cmdAsk = DrCoffee.Packe(package); + drinksOrder.CommCmd = DrCoffeeCommCmd.饮品制作指令; + + EventBus.EventBus.GetInstance().Subscribe(0,MakeCoffeeEventHandle); + EventBus.EventBus.GetInstance().Subscribe(0, CancelMakeCoffeeEventHandle); + EventBus.EventBus.GetInstance().Subscribe(0, CoffeeCommCmdEventHandle); + + } + + private void CoffeeCommCmdEventHandle(IEvent @event, EventCallBackHandle callBack) + { + PauseAsk?.Invoke(true); + Thread.Sleep(200); + drinksOrder.CommCmd = ((DRCoffee_CoffeeCommCmdEvent)@event).CommCmd; + commProxy.SendData(DrCoffee.Packe(drinksOrder)); + Thread.Sleep(200); + PauseAsk?.Invoke(false); + } + + private void CancelMakeCoffeeEventHandle(IEvent @event, EventCallBackHandle callBack) + { + PauseAsk?.Invoke(true); + Thread.Sleep(200); + drinksOrder.CommCmd = DrCoffeeCommCmd.取消应用指令; + drinksOrder.DrinksCode = 0; + commProxy.SendData(DrCoffee.Packe(drinksOrder)); + Thread.Sleep(200); + PauseAsk?.Invoke(false); + } + + private void MakeCoffeeEventHandle(IEvent @event, EventCallBackHandle callBack) + { + PauseAsk?.Invoke(true); + Thread.Sleep(200); + drinksOrder.CommCmd = DrCoffeeCommCmd.饮品制作指令; + drinksOrder.DrinksCode = ((DRCoffee_MakeCoffeeEvent)@event).DrinkCode; + commProxy.SendData(DrCoffee.Packe(drinksOrder)); + + Thread.Sleep(200); + PauseAsk?.Invoke(false); + } + + /// + /// 发送状态询问 + /// + internal byte[] GetStatusAsk() + { + return cmdAsk; + } + } +} diff --git a/BPASmartClient.DRCoffee/MorkCStatus.cs b/BPASmartClient.DRCoffee/MorkCStatus.cs new file mode 100644 index 00000000..3c4555d8 --- /dev/null +++ b/BPASmartClient.DRCoffee/MorkCStatus.cs @@ -0,0 +1,76 @@ +using BPASmartClient.DRCoffee; +using BPASmartClient.EventBus; +using BPASmartClient.Helper; +using BPASmartClient.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.DRCoffee +{ + public class MorkCStatus : Singleton + { + private DRCoffee_CoffeEndCookEvent coffeEndCook = new DRCoffee_CoffeEndCookEvent(); + private DateTime lastRefreshTime = DateTime.MinValue; + /// + /// 是否在线 + /// + public bool OnLine { get { return DateTime.Now.Subtract(lastRefreshTime).TotalSeconds <= 3; } } + /// + /// 咖啡机状态 + /// + public DrCoffeeStatus CoffeeStatus { get; set; } + /// + /// 应用状态 + /// + public DrCoffeeAppStatus AppStatus { get; set; } + /// + /// 警告信息 + /// + public DrCoffeeWarning Warning { get; set; } + /// + /// 故障信息 + /// + public DrCoffeeFault Fault { get; set; } + + public bool CanDo + { + get + + { + if (!OnLine) + return false; + if (Warning != DrCoffeeWarning.无警告) + return false; + if (Fault != DrCoffeeFault.无故障) + return false; + return true; + } + } + + /// + /// 咖啡机状态解析 + /// + /// + public void ProcessPackage(DrCoffeePackage package) + { + if (CoffeeStatus == DrCoffeeStatus.Running && package.Status != DrCoffeeStatus.Running) + { + CoffeeStatus = package.Status; + coffeEndCook.Publish(); + } + else + { + CoffeeStatus = package.Status; + } + + AppStatus = package.ApplicationStatus; + Warning = package.Warning; + Fault = package.Fault; + + lastRefreshTime = DateTime.Now; + } + } +} diff --git a/BPASmartClient.GSIceCream/CommandHandler.cs b/BPASmartClient.GSIceCream/CommandHandler.cs new file mode 100644 index 00000000..1f58587b --- /dev/null +++ b/BPASmartClient.GSIceCream/CommandHandler.cs @@ -0,0 +1,118 @@ + +using BPASmartClient.EventBus; +using BPASmartClient.GSIceCream; +using BPASmartClient.Message; +using BPASmartClient.Model; +using BPASmartClient.Model.冰淇淋.Enum; +using BPASmartClient.SerialPort; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using static BPASmartClient.EventBus.EventBus; + +namespace BPASmartClient.DRCoffee +{ + /// + /// 指令封装 + /// + internal class CommandHandler + { + byte[] cmdHeartDW; + + private SerialPortClient commProxy; + private GSIceCream_EndCookEvent iceCreamEndCook = new GSIceCream_EndCookEvent(); + public Action PauseAsk { get; set; } + + /// + /// 初始化 + /// + internal void Init(SerialPortClient commProxy) + { + this.commProxy = commProxy; + ICMSG_Heart_DW heartDW = new ICMSG_Heart_DW(); + cmdHeartDW = IcPack.StructureToByte(heartDW); + EventBus.EventBus.GetInstance().Subscribe(0, ModeSetEventHandle); + EventBus.EventBus.GetInstance().Subscribe(0,DischargeEventHandle); + } + /// + /// 发送心跳 + /// + internal byte[] GetHeartDW() + { + return cmdHeartDW; + } + + + public void ModeSetEventHandle(IEvent @event, EventCallBackHandle callBack = null) + { + PauseAsk?.Invoke(true); + Thread.Sleep(200); + var data = IcPack.StructureToByte(ICMSG_MODE_DW.Build(((GSIceCream_ModeSetEvent)@event).Mode)); + commProxy.SendData(data); + Thread.Sleep(200); + PauseAsk?.Invoke(false); + MessageLog.GetInstance.Show(string.Format("设置模式[{0}]", ((GSIceCream_ModeSetEvent)@event).Mode)); + } + + public void DischargeEventHandle(IEvent @event, EventCallBackHandle callBack = null) + { + if (MorkIStatus.GetInstance().Fault != MORKI_FAULT.未发生故障) + { + MessageLog.GetInstance.Show(string.Format("当前存在故障[{0}%],不允许制作", MorkIStatus.GetInstance().Fault)); + callBack?.Invoke(false); + return; + } + if (MorkIStatus.GetInstance().CXB <= 86) + { + MessageLog.GetInstance.Show(string.Format("当前成型比[{0}%],低于86%,不允许制作", MorkIStatus.GetInstance().CXB)); + callBack?.Invoke(false); + return; + } + + bool modeRight = MorkIStatus.GetInstance().CurrentMode == MORKI_MODE.制冷模式; + + if (!modeRight) + { + PauseAsk?.Invoke(true); + Thread.Sleep(200); + + var temp = IcPack.StructureToByte(ICMSG_MODE_DW.Build(MORKI_MODE.制冷模式)); + commProxy.SendData(temp); + + Thread.Sleep(200); + PauseAsk?.Invoke(false); + MessageLog.GetInstance.Show(string.Format("出料操作->设置模式[{0}]", MORKI_MODE.制冷模式)); + + DateTime freeTime = DateTime.Now.AddSeconds(5); + while (DateTime.Now < freeTime) + { + Thread.Sleep(10); + modeRight = MorkIStatus.GetInstance().CurrentMode == MORKI_MODE.制冷模式; + if (modeRight) + break; + } + } + + if (modeRight) + { + PauseAsk?.Invoke(true); + Thread.Sleep(200); + var data = IcPack.StructureToByte(ICMSG_MODE_DW.Build(MORKI_MODE.打料)); + commProxy.SendData(data); + Thread.Sleep(200); + PauseAsk?.Invoke(false); + iceCreamEndCook.Publish(); + MessageLog.GetInstance.Show(string.Format("出料操作->设置模式[{0}]", MORKI_MODE.打料)); + callBack?.Invoke(true); + } + else + { + MessageLog.GetInstance.Show(string.Format("出料操作->模式切换失败,当前模式[{0}],不允许出料", MorkIStatus.GetInstance().CurrentMode)); + callBack?.Invoke(false); + } + } + } +} diff --git a/BPASmartClient.GSIceCream/MorkIStatus.cs b/BPASmartClient.GSIceCream/MorkIStatus.cs new file mode 100644 index 00000000..717a1b4d --- /dev/null +++ b/BPASmartClient.GSIceCream/MorkIStatus.cs @@ -0,0 +1,131 @@ +using BPASmartClient.GSIceCream; +using BPASmartClient.Helper; +using BPASmartClient.Message; +using BPASmartClient.Model.冰淇淋.Enum; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static BPASmartClient.GSIceCream.MessageDefine; + +namespace BPASmartClient.GSIceCream +{ + public class MorkIStatus : Singleton + { + private DateTime lastRefreshTime = DateTime.MinValue; + /// + /// 是否在线 + /// + public bool OnLine { get { return DateTime.Now.Subtract(lastRefreshTime).TotalSeconds <= 3; } } + /// + /// 预冷温度 + /// + public short YLWD { get; set; } + /// + /// 回气温度 + /// + public short HQWD { get; set; } + /// + /// 环境温度 + /// + public short HJWD { get; set; } + /// + /// 电流 + /// + public short DL { get; set; } + /// + /// 电压 + /// + public short DY { get; set; } + /// + /// 当前模式 + /// + public MORKI_MODE CurrentMode { get; set; } + /// + /// 故障 + /// + public MORKI_FAULT Fault { get; set; } + /// + /// 成型比 + /// + public byte CXB { get; set; } + /// + /// 成型比(门限) + /// + public byte CXB_Threshold { get; set; } + /// + /// 打料完成(完成为true,正在打料为false) + /// + public bool DLCompleted { get; set; } + + + public bool CanDo + { + get + { + if (!OnLine) + return false; + if (Fault != MORKI_FAULT.未发生故障) + return false; + if (CXB < CXB_Threshold) + return false; + return true; + } + } + + private void ProcessHeart(ICMSG_Heart_UP heartUpMsg) + { + CurrentMode = heartUpMsg.MS; + YLWD = BitConverter.ToInt16(new byte[] { heartUpMsg.YLWD_L, heartUpMsg.YLWD_H }, 0); + HQWD = BitConverter.ToInt16(new byte[] { heartUpMsg.HQWD_L, heartUpMsg.HQWD_H }, 0); + HJWD = BitConverter.ToInt16(new byte[] { heartUpMsg.HJWD_L, heartUpMsg.HJWD_H }, 0); + DL = BitConverter.ToInt16(new byte[] { heartUpMsg.DL_L, heartUpMsg.DL_H }, 0); + Fault = (MORKI_FAULT)BitConverter.ToInt16(new byte[] { heartUpMsg.GZ_L, heartUpMsg.GZ_H }, 0); + CXB = heartUpMsg.CXB; + DLCompleted = (heartUpMsg.DLTJ >> 4 & 1) == 1; + + if (RTrig.GetInstance("打料完成检测").Start(DLCompleted)) + { + MessageLog.GetInstance.Show("打料完成"); + } + + if (RTrig.GetInstance("打料中检测").Start(!DLCompleted)) + { + MessageLog.GetInstance.Show("打料中"); + } + //MessageLog.GetInstance.Show(string.Format("当前模式为:{0}", CurrentMode)); + + } + + private void ProcessModeUp(ICMSG_MODE_UP modeUpMsg) + { + MessageLog.GetInstance.Show(string.Format("模式返回为:{0}", modeUpMsg.Mode)); + } + + public void ProcessMsg(byte[] data) + { + lastRefreshTime = DateTime.Now; + try + { + if (data.Length < 5) + return; + switch (data[2]) + { + case (byte)IC_CMD.HEART: + var msg = IcPack.ByteToStructure(data.ToArray()); + ProcessHeart(msg); + break; + case (byte)IC_CMD.MODE: + var modeUp = IcPack.ByteToStructure(data.ToArray()); + ProcessModeUp(modeUp); + break; + } + } + catch (Exception ex) + { + + } + } + } +} diff --git a/BPASmartClient.Lebai/LebaiRobot.cs b/BPASmartClient.Lebai/LebaiRobot.cs index 8042c40f..58953747 100644 --- a/BPASmartClient.Lebai/LebaiRobot.cs +++ b/BPASmartClient.Lebai/LebaiRobot.cs @@ -67,6 +67,12 @@ namespace BPASmartClient.Lebai public const int SENCE_接3号冰淇淋 = 10041; public const int SENCE_放咖啡位置 = 10042; public const int SENCE_放冰淇淋位置 = 10043; + + //add 新加场景 + public const int SENCE_接咖啡_新 = 10051; + public const int SENCE_咖啡杯回原点 = 10050; + public const int SENCE_冰淇淋杯回原点 = 10049; + public const int SENCE_取咖啡出餐 = 10052; #endregion /// @@ -82,6 +88,10 @@ namespace BPASmartClient.Lebai /// public int OutputSingalValue { get; set; } + + private volatile static LebaiRobot _Instance; + public static LebaiRobot GetInstance => _Instance ?? (_Instance = new LebaiRobot()); + private LebaiRobot() { } private LebaiRobotClient client; private RobotData robotData; public bool IsIdle { get; set; } = false; @@ -110,6 +120,74 @@ namespace BPASmartClient.Lebai StartRobot(); MessageLog.GetInstance.Show("乐百机器人连接成功!"); } + /// + /// 机器人重连检测 + /// + /// + public void Reconnect(string ip) + { + if (client == null) + { + try + { + client = new LebaiRobotClient(ip); + } + catch (Exception) + { + + // throw; + } + } + check: + while (robotData != null) + { + + try + { + robotData = client.GetRobotData().Result; + } + catch (Exception) + { + robotData = null; + // throw; + } + } + MessageLog.GetInstance.Show("乐白机器人断开连接,准备重连"); + int num = 0; + while (num < 6 && robotData == null) + { + try + { + + robotData = client.GetRobotData().Result; + } + catch (Exception ex) + { + if (num == 5) + { + MessageLog.GetInstance.ShowEx(ex.ToString()); + } + } + + if (num < 5 && robotData == null) + { + Thread.Sleep(1000); + MessageLog.GetInstance.Show($"乐白机器人正在尝试第{num + 1}次重连...."); + } + else if (num >= 5 && robotData == null) + { + MessageLog.GetInstance.Show("乐白机器人重连失败,请检查硬件连接"); + //return; + } + num++; + } + if (robotData != null) + { + StartRobot(); + MessageLog.GetInstance.Show("乐白机器人重连成功"); + } + goto check; + } public void GetRobotModeStatus() { @@ -143,6 +221,63 @@ namespace BPASmartClient.Lebai } } + /// + /// 启动示教 + /// + public async void StartTeachMode() + { + try + { + if (robotData != null) + { + await client.TeachMode(); + MessageLog.GetInstance.Show("机器人切换为示教模式."); + } + } + catch (Exception ex) + { + MessageLog.GetInstance.ShowEx(ex.ToString()); + } + } + + /// + /// 结束示教 + /// + public async void EndtTeachMode() + { + try + { + if (robotData != null) + { + await client.EndTeachMode(); + MessageLog.GetInstance.Show("机器人切换为停止示教模式."); + } + } + catch (Exception ex) + { + MessageLog.GetInstance.ShowEx(ex.ToString()); + } + } + + /// + /// 机器人急停 + /// + public async void EStopRobot() + { + try + { + if (robotData != null) + { + await client.EStop(); + MessageLog.GetInstance.Show("机器人急停"); + } + } + catch (Exception ex) + { + MessageLog.GetInstance.ShowEx(ex.ToString()); + } + } + /// /// 获取抓手重量 /// diff --git a/BPASmartClient.Model/BatchingInfoPar.cs b/BPASmartClient.Model/BatchingInfoPar.cs new file mode 100644 index 00000000..dd56d51b --- /dev/null +++ b/BPASmartClient.Model/BatchingInfoPar.cs @@ -0,0 +1,21 @@ +using BPA.Message; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.Model +{ + public class BatchingInfoPar + { + /// + /// 订单物料信息 + /// + public OrderMaterialDelivery orderMaterialDelivery { get; set; } = new OrderMaterialDelivery(); + /// + /// 配方数据信息 + /// + public RecipeBoms recipeBoms { get; set; } = new RecipeBoms(); + } +} diff --git a/BPASmartClient.Model/单片机/SCChipEvent.cs b/BPASmartClient.Model/单片机/SCChipEvent.cs index a7e6f201..270d4e88 100644 --- a/BPASmartClient.Model/单片机/SCChipEvent.cs +++ b/BPASmartClient.Model/单片机/SCChipEvent.cs @@ -48,4 +48,18 @@ namespace BPASmartClient.Model.单片机 { public bool TurnOn { get; set; } } + /// + /// 检测有无杯子 + /// + public class ArticleExitsEvent : BaseEvent + { + + } + /// + /// 检测物品距离 + /// + public class ArticleDistEvent : BaseEvent + { + + } } diff --git a/BPASmartClient.MorkT/BPASmartClient.MorkT.csproj b/BPASmartClient.MorkT/BPASmartClient.MorkT.csproj index 0acaaf42..288c5e34 100644 --- a/BPASmartClient.MorkT/BPASmartClient.MorkT.csproj +++ b/BPASmartClient.MorkT/BPASmartClient.MorkT.csproj @@ -6,6 +6,7 @@ + diff --git a/BPASmartClient.MorkT/Control_MorkT.cs b/BPASmartClient.MorkT/Control_MorkT.cs new file mode 100644 index 00000000..cfacd727 --- /dev/null +++ b/BPASmartClient.MorkT/Control_MorkT.cs @@ -0,0 +1,164 @@ +using BPASmartClient.Device; +using BPASmartClient.EventBus; +using BPASmartClient.Lebai; +using BPASmartClient.Message; +using BPASmartClient.Model; +using BPASmartClient.Peripheral; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static BPASmartClient.EventBus.EventBus; + +namespace BPASmartClient.MorkT +{ + public class Control_MorkT : BaseDevice + { + public override global::BPA.Message.Enum.DeviceClientType DeviceType { get { return BPA.Message.Enum.DeviceClientType.MORKIC; } } + + GLV_MorkT morkT = new GLV_MorkT(); + + + + public override void DoMain() + { + ServerInit(); + DataParse(); + EventBus.EventBus.GetInstance().Subscribe(DeviceId, delegate (IEvent @event, EventCallBackHandle callBack) + { + if (morkT.MakeCoffeeOrder != null) + morkT.MakeCoffeeOrder.OrderStatus = 1; + }); + MessageLog.GetInstance.Show("MORKF 设备初始化完成"); + } + + public override void ResetProgram() + { + morkT = null; + morkT = new GLV_MorkT(); + } + + public override void MainTask() + { + } + + public override void ReadData() + { + morkT.lebai = LebaiRobot.GetInstance.GetValueAsync(); + LebaiRobot.GetInstance.GetRobotModeStatus(); + } + + + + public override void Stop() + { + } + + + private void ServerInit() + { + //物料信息 + EventBus.EventBus.GetInstance().Subscribe(DeviceId, delegate (IEvent @event, EventCallBackHandle callBack) + { + if (@event == null) return; + if (@event is MaterialDeliveryEvent material) + { + orderMaterialDelivery = material.orderMaterialDelivery; + } + }); + + //配方数据信息 + EventBus.EventBus.GetInstance().Subscribe(DeviceId, delegate (IEvent @event, EventCallBackHandle callBack) + { + if (@event == null) return; + if (@event is RecipeBomEvent recipe) + { + recipeBoms = recipe.recipeBoms; + } + }); + } + + /// + /// 数据解析 + /// + private void DataParse() + { + EventBus.EventBus.GetInstance().Subscribe(DeviceId, delegate (IEvent @event, EventCallBackHandle callBackHandle) + { + if (@event == null) return; + if (@event is DoOrderEvent order) + { + if (order.MorkOrder.GoodBatchings == null) return; + OrderCount++; + DeviceProcessLogShow($"接收到{OrderCount}次订单"); + //构建所有商品物料信息 + morkT.batchings = PolymerBatching.BuildAll(); + //商品类型 + GOODS_TYPE currentGoodsType = GOODS_TYPE.NEITHER; + string loc_Goods = string.Empty; + foreach (var item in order.MorkOrder.GoodBatchings) + { + var res = orderMaterialDelivery?.BatchingInfo?.FirstOrDefault(p => p.BatchingId == item.BatchingId); + if (res != null) + { + //验证商品是咖啡还是冰淇淋 + if (ValidateGoodsByBatching(res.BatchingLoc) != GOODS_TYPE.NEITHER) + { + //获取当前物料所属商品类型 + currentGoodsType = ValidateGoodsByBatching(res.BatchingLoc); + } + + //获取主料和容器位置 + if (morkT.batchings[res.BatchingLoc].BatchingClass == BATCHING_CLASS.MAIN_MATERIAL) loc_Goods = res.BatchingLoc; + + switch (currentGoodsType) + { + case GOODS_TYPE.COFFEE: + if (morkT.morkOrderPushesCoffee.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null) + { + morkT.morkOrderPushesCoffee.Enqueue(new OrderLocInfo() + { + SuborderId = order.MorkOrder.SuborderId, + BatchingId = res.BatchingId, + Loc = loc_Goods + }); + } + break; + case GOODS_TYPE.ICECREAM: + if (morkT.morkOrderPushesIceCream.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null) + { + morkT.morkOrderPushesIceCream.Enqueue(new OrderLocInfo() + { + SuborderId = order.MorkOrder.SuborderId, + BatchingId = res.BatchingId, + Loc = loc_Goods + }); + } + break; + case GOODS_TYPE.NEITHER: + DeviceProcessLogShow("未知的商品类型"); + break; + } + } + } + + } + }); + } + + /// + /// 验证当前是做咖啡还是做冰淇淋 + /// + /// 物料位置 + private GOODS_TYPE ValidateGoodsByBatching(string batchingLoc) + { + if (morkT.batchings.ContainsKey(batchingLoc)) + return morkT.batchings[batchingLoc].GoodsType; + return GOODS_TYPE.NEITHER; + } + + + + } +} diff --git a/BPASmartClient.MorkT/Device_MorkT.cs b/BPASmartClient.MorkT/Device_MorkT.cs deleted file mode 100644 index 268cdf05..00000000 --- a/BPASmartClient.MorkT/Device_MorkT.cs +++ /dev/null @@ -1,36 +0,0 @@ -using BPASmartClient.Device; -using BPASmartClient.Peripheral; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BPASmartClient.MorkT -{ - public class Device_MorkT : BaseDevice - { - public override global::BPA.Message.Enum.DeviceClientType DeviceType { get { return BPA.Message.Enum.DeviceClientType.MORKIC; } } - - public override void DoMain() - { - - } - - public override void MainTask() - { - } - - public override void ReadData() - { - } - - public override void ResetProgram() - { - } - - public override void Stop() - { - } - } -} diff --git a/BPASmartClient.MorkT/GLV_MorkT.cs b/BPASmartClient.MorkT/GLV_MorkT.cs new file mode 100644 index 00000000..8a09f07a --- /dev/null +++ b/BPASmartClient.MorkT/GLV_MorkT.cs @@ -0,0 +1,37 @@ +using Robotc; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.MorkT +{ + public class GLV_MorkT + { + /// + /// 咖啡订单队列 + /// + public ConcurrentQueue morkOrderPushesCoffee = new ConcurrentQueue(); + + /// + /// 冰淇淋订单队列 + /// + public ConcurrentQueue morkOrderPushesIceCream = new ConcurrentQueue(); + /// + /// 物料存放位置 + /// + public Dictionary batchings = new Dictionary(); + + /// + /// 当前正在制作咖啡 + /// + public OrderLocInfo MakeCoffeeOrder = new OrderLocInfo(); + + /// + /// 获取乐百机器人的数据 + /// + public SignalResult lebai = new SignalResult(); + } +} diff --git a/BPASmartClient.MorkT/OrderLocInfo.cs b/BPASmartClient.MorkT/OrderLocInfo.cs new file mode 100644 index 00000000..6199c5b3 --- /dev/null +++ b/BPASmartClient.MorkT/OrderLocInfo.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.MorkT +{ + public class OrderLocInfo + { + public string SuborderId { get; set; } + public string Loc { get; set; } + public ushort RecipeNumber { get; set; } + public int BatchingId { get; set; } + + public int OrderStatus { get; set; } + public OrderLocInfo() + { + OrderStatus = 0; + } + } +} diff --git a/BPASmartClient.MorkT/PolymerBatching.cs b/BPASmartClient.MorkT/PolymerBatching.cs new file mode 100644 index 00000000..79fd574d --- /dev/null +++ b/BPASmartClient.MorkT/PolymerBatching.cs @@ -0,0 +1,122 @@ + +using BPASmartClient.Lebai; +using BPASmartClient.Model.单片机.Enum; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.MorkT +{ + public enum GOODS_TYPE + { + NEITHER, + COFFEE, + ICECREAM, + } + + public enum BATCHING_CLASS + { + HOLDER, + MAIN_MATERIAL, + } + + public class PolymerBatching + { + internal const string ICE_MAIN_BATCHIN1_LOC = "52"; + internal const string ICE_MAIN_BATCHIN2_LOC = "53"; + internal const string ICE_MAIN_BATCHIN3_LOC = "54"; + internal const string COFFEE_HOLDER_LOC = "30"; + internal const string ICE_HOLDER_LOC = "51"; + public static Dictionary GOODS_TYPES = new Dictionary() { + {"1", GOODS_TYPE.COFFEE}, + {"2", GOODS_TYPE.COFFEE}, + {"3", GOODS_TYPE.COFFEE}, + {"4", GOODS_TYPE.COFFEE}, + {"5", GOODS_TYPE.COFFEE}, + {"6", GOODS_TYPE.COFFEE}, + {"7", GOODS_TYPE.COFFEE}, + {"8", GOODS_TYPE.COFFEE}, + {"9", GOODS_TYPE.COFFEE}, + {"10",GOODS_TYPE.COFFEE}, + {"11",GOODS_TYPE.COFFEE}, + {"12",GOODS_TYPE.COFFEE}, + {"13",GOODS_TYPE.COFFEE}, + {"14",GOODS_TYPE.COFFEE}, + {"15",GOODS_TYPE.COFFEE}, + {"16",GOODS_TYPE.COFFEE}, + {"17",GOODS_TYPE.COFFEE}, + {"18",GOODS_TYPE.COFFEE}, + {"19",GOODS_TYPE.COFFEE}, + {"20",GOODS_TYPE.COFFEE}, + {"21",GOODS_TYPE.COFFEE}, + {"22",GOODS_TYPE.COFFEE}, + {"23",GOODS_TYPE.COFFEE}, + {"24",GOODS_TYPE.COFFEE}, + {"25",GOODS_TYPE.COFFEE}, + {"30",GOODS_TYPE.COFFEE}, + {"51",GOODS_TYPE.ICECREAM}, + {ICE_MAIN_BATCHIN1_LOC,GOODS_TYPE.ICECREAM}, + {ICE_MAIN_BATCHIN2_LOC,GOODS_TYPE.ICECREAM}, + {ICE_MAIN_BATCHIN3_LOC,GOODS_TYPE.ICECREAM}, + }; + + public GOODS_TYPE GoodsType { get; set; } + public BATCHING_CLASS BatchingClass { get; set; } + private string loc; + + public string Loc + { + get { return loc; } + set + { + loc = value; + if (GOODS_TYPES.ContainsKey(loc)) + GoodsType = GOODS_TYPES[loc]; + switch (loc) + { + case COFFEE_HOLDER_LOC: + case ICE_HOLDER_LOC: + BatchingClass = BATCHING_CLASS.HOLDER; + break; + default: + BatchingClass = BATCHING_CLASS.MAIN_MATERIAL; + break; + } + } + } + + internal static Dictionary BuildAll() + { + Dictionary temp = new Dictionary(); + foreach (var item in GOODS_TYPES) + { + temp.Add(item.Key, new PolymerBatching() { Loc = item.Key }); + } + return temp; + } + + internal static IC_SE GetIceCreamSE(string loc, out int sence) + { + switch (loc) + { + case ICE_MAIN_BATCHIN1_LOC: + sence = LebaiRobot.SENCE_接1号冰淇淋; + return IC_SE.SE_1; + + case ICE_MAIN_BATCHIN2_LOC: + sence = LebaiRobot.SENCE_接2号冰淇淋; + return IC_SE.SE_2; + + case ICE_MAIN_BATCHIN3_LOC: + sence = LebaiRobot.SENCE_接3号冰淇淋; + return IC_SE.SE_3; + + default: + sence = LebaiRobot.SENCE_接1号冰淇淋; + return IC_SE.SE_1; + } + } + } +} diff --git a/BPASmartClient.SCChip/ChipStatus.cs b/BPASmartClient.SCChip/ChipStatus.cs new file mode 100644 index 00000000..9189085b --- /dev/null +++ b/BPASmartClient.SCChip/ChipStatus.cs @@ -0,0 +1,132 @@ +using BPASmartClient.Helper; +using BPASmartClient.Model.单片机.Enum; +using BPASmartClient.SCChip; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.SCChip +{ + public class ChipStatus : Singleton + { + private DateTime lastRefreshTime = DateTime.MinValue; + /// + /// 是否在线 + /// + public bool OnLine { get { return DateTime.Now.Subtract(lastRefreshTime).TotalSeconds <= 3; } } + /// + /// 取冰淇淋杯完成 + /// + public bool CompletedTake_CPU_CUP_ICECREAM { get; set; } + /// + /// 取咖啡杯完成 + /// + public bool CompletedTake_CPU_CUP_COFFEE { get; set; } + /// + /// 1号舵机打开完成 + /// + public bool CompletedOpen_SE_1 { get; set; } + /// + /// 2号舵机打开完成 + /// + public bool CompletedOpen_SE_2 { get; set; } + /// + /// 3号舵机打开完成 + /// + public bool CompletedOpen_SE_3 { get; set; } + /// + /// 1号舵机关闭完成 + /// + public bool CompletedClose_SE_1 { get; set; } + /// + /// 2号舵机关闭完成 + /// + public bool CompletedClose_SE_2 { get; set; } + /// + /// 3号舵机关闭完成 + /// + public bool CompletedClose_SE_3 { get; set; } + /// + /// 是否存在物品 + /// + public bool ArticleExits { get; set; } + /// + /// 物品距离 + /// + public byte ArticleDist { get; set; } + + public bool CanDo + { + get + { + if (!OnLine) + return false; + return true; + } + } + + public void ProcessMsg(ICChipPackage data) + { + try + { + switch (data.Cmd) + { + case IC_CMD.HEART_BEAT: + lastRefreshTime = DateTime.Now; + break; + case IC_CMD.TAKE_CUP: + switch ((IC_CUP)data.Value) + { + case IC_CUP.CUP_COFFEE: + CompletedTake_CPU_CUP_COFFEE = true; + break; + case IC_CUP.CUP_ICECREAM: + CompletedTake_CPU_CUP_ICECREAM = true; + break; + } + break; + case IC_CMD.OPEN_SE: + switch ((IC_SE)data.Value) + { + case IC_SE.SE_1: + CompletedOpen_SE_1 = true; + break; + case IC_SE.SE_2: + CompletedOpen_SE_2 = true; + break; + case IC_SE.SE_3: + CompletedOpen_SE_3 = true; + break; + } + break; + case IC_CMD.CLOSE_SE: + switch ((IC_SE)data.Value) + { + case IC_SE.SE_1: + CompletedClose_SE_1 = true; + break; + case IC_SE.SE_2: + CompletedClose_SE_2 = true; + break; + case IC_SE.SE_3: + CompletedClose_SE_3 = true; + break; + } + break; + case IC_CMD.ARTICLE_EXITS: + ArticleExits = data.Value > 0; + break; + case IC_CMD.ARTICLE_DIST: + ArticleDist = data.Value; + break; + } + } + catch (Exception ex) + { + + } + } + } +} diff --git a/BPASmartClient.SCChip/CommandHandler.cs b/BPASmartClient.SCChip/CommandHandler.cs new file mode 100644 index 00000000..e46f40e6 --- /dev/null +++ b/BPASmartClient.SCChip/CommandHandler.cs @@ -0,0 +1,197 @@ + +using BPASmartClient.EventBus; +using BPASmartClient.Model.单片机; +using BPASmartClient.Model.单片机.Enum; +using BPASmartClient.SCChip; +using BPASmartClient.SerialPort; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using static BPASmartClient.EventBus.EventBus; + +namespace BPASmartClient.SCChip +{ + /// + /// 指令封装 + /// + internal class CommandHandler + { + private SerialPortClient commProxy; + private ICChipPackage package = new ICChipPackage(); + + /// + /// 初始化 + /// + internal void Init(SerialPortClient commProxy) + { + this.commProxy = commProxy; + EventBus.EventBus.GetInstance().Subscribe(0,TakeCupEventHandle); + EventBus.EventBus.GetInstance().Subscribe(0, MakeIceCreamEventHandle); + EventBus.EventBus.GetInstance().Subscribe(0, StopMakeIceCreamEventHandle); + EventBus.EventBus.GetInstance().Subscribe(0, RotorSwitchEventHandle); + EventBus.EventBus.GetInstance().Subscribe(0, ArticleExitsEventHandle); + EventBus.EventBus.GetInstance().Subscribe(0, ArticleDistEventHandle); + } + + private void ArticleDistEventHandle(IEvent @event, EventCallBackHandle callBack) + { + package.Cmd = IC_CMD.ARTICLE_DIST; + commProxy.SendData(StructureToByte(package)); + } + + private void ArticleExitsEventHandle(IEvent @event, EventCallBackHandle callBack) + { + ChipStatus.GetInstance().ArticleExits = false; + package.Cmd = IC_CMD.ARTICLE_EXITS; + commProxy.SendData(StructureToByte(package)); + } + + private void StopMakeIceCreamEventHandle(IEvent @event, EventCallBackHandle callBack) + { + ChipStatus.GetInstance().ArticleDist = 0; + package.Cmd = (@event as SCChip_SESwitchCreamEvent).IsOpen ? IC_CMD.OPEN_SE : IC_CMD.CLOSE_SE; + package.Value = (byte)(@event as SCChip_SESwitchCreamEvent).SteeringEngine; + commProxy.SendData(StructureToByte(package)); + } + + private void RotorSwitchEventHandle(IEvent @event, EventCallBackHandle callBack) + { + package.Cmd = IC_CMD.ROTOR; + package.Value = (@event as SCChip_RotorSwitchEvent).TurnOn ? (byte)IC_ROTOR.OPEN_ROTOR : (byte)IC_ROTOR.CLOSE_ROTOR; + commProxy.SendData(StructureToByte(package)); + } + + private void MakeIceCreamEventHandle(IEvent @event, EventCallBackHandle callBack) + { + switch ((@event as SCChip_MakeIceCreamEvent).SteeringEngine) + { + case IC_SE.SE_1: + ChipStatus.GetInstance().CompletedOpen_SE_1 = false; + break; + case IC_SE.SE_2: + ChipStatus.GetInstance().CompletedOpen_SE_2 = false; + break; + case IC_SE.SE_3: + ChipStatus.GetInstance().CompletedOpen_SE_3 = false; + break; + } + package.Cmd = IC_CMD.OPEN_SE; + package.Value = (byte)(@event as SCChip_MakeIceCreamEvent).SteeringEngine; + commProxy.SendData(StructureToByte(package)); + + bool wait = true; + DateTime waitTimeout = DateTime.Now.AddSeconds(3); + while (wait) + { + wait = DateTime.Now < waitTimeout; + if (wait) + { + switch ((@event as SCChip_MakeIceCreamEvent).SteeringEngine) + { + case IC_SE.SE_1: + wait = !ChipStatus.GetInstance().CompletedOpen_SE_1; + break; + case IC_SE.SE_2: + wait = !ChipStatus.GetInstance().CompletedOpen_SE_2; + break; + case IC_SE.SE_3: + wait = !ChipStatus.GetInstance().CompletedOpen_SE_3; + break; + } + } + Thread.Sleep(10); + } + Thread.Sleep(2000); + package.Cmd = IC_CMD.CLOSE_SE; + package.Value = (byte)(@event as SCChip_MakeIceCreamEvent).SteeringEngine; + commProxy.SendData(StructureToByte(package)); + + wait = true; + waitTimeout = DateTime.Now.AddSeconds(3); + while (wait) + { + wait = DateTime.Now < waitTimeout; + if (wait) + { + switch ((@event as SCChip_MakeIceCreamEvent).SteeringEngine) + { + case IC_SE.SE_1: + wait = !ChipStatus.GetInstance().CompletedClose_SE_1; + break; + case IC_SE.SE_2: + wait = !ChipStatus.GetInstance().CompletedClose_SE_2; + break; + case IC_SE.SE_3: + wait = !ChipStatus.GetInstance().CompletedClose_SE_3; + break; + } + } + Thread.Sleep(10); + } + } + + private void TakeCupEventHandle(IEvent @event, EventCallBackHandle callBack) + { + switch ((@event as SCChip_TakeCupEvent).Cup) + { + case IC_CUP.CUP_ICECREAM: + ChipStatus.GetInstance().CompletedTake_CPU_CUP_ICECREAM = false; + break; + case IC_CUP.CUP_COFFEE: + ChipStatus.GetInstance().CompletedTake_CPU_CUP_COFFEE = false; + break; + } + package.Cmd = IC_CMD.TAKE_CUP; + package.Value = (byte)(@event as SCChip_TakeCupEvent).Cup; + commProxy.SendData(StructureToByte(package)); + + bool wait = true; + var waitTimeout = DateTime.Now.AddSeconds(3); + while (wait) + { + wait = DateTime.Now < waitTimeout; + if (wait) + { + switch ((@event as SCChip_TakeCupEvent).Cup) + { + case IC_CUP.CUP_ICECREAM: + wait = !ChipStatus.GetInstance().CompletedTake_CPU_CUP_ICECREAM; + break; + case IC_CUP.CUP_COFFEE: + wait = !ChipStatus.GetInstance().CompletedTake_CPU_CUP_COFFEE; + break; + } + } + Thread.Sleep(10); + } + } + + + private byte[] StructureToByte(ICChipPackage structure) + { + structure.Header = 0xAA; + structure.Sender = IC_SENDER.CONSOLE; + structure.End = 0xBB; + + int size = Marshal.SizeOf(typeof(ICChipPackage)); + byte[] buffer = new byte[size]; + IntPtr bufferIntPtr = Marshal.AllocHGlobal(size); + try + { + Marshal.StructureToPtr(structure, bufferIntPtr, true); + Marshal.Copy(bufferIntPtr, buffer, 0, size); + } + finally + { + Marshal.FreeHGlobal(bufferIntPtr); + } + return buffer; + } + + + } +} diff --git a/HBLConsole.MORKIC/BPASmartClient.MORKIC.csproj b/HBLConsole.MORKIC/BPASmartClient.MORKIC.csproj new file mode 100644 index 00000000..e444219e --- /dev/null +++ b/HBLConsole.MORKIC/BPASmartClient.MORKIC.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + + + + + + + + + + + + + + + + + + + diff --git a/HBLConsole.MORKIC/Control_MORKIC.cs b/HBLConsole.MORKIC/Control_MORKIC.cs new file mode 100644 index 00000000..090b8a61 --- /dev/null +++ b/HBLConsole.MORKIC/Control_MORKIC.cs @@ -0,0 +1,647 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.Threading; +using BPA.Message; +using Robotc; +using System.Collections.Concurrent; +using System.Diagnostics; +using BPA.Message.IOT; +using System.Threading.Tasks; +using BPASmartClient.Device; +using BPA.Message.Enum; +using BPASmartClient.DRCoffee; +using BPASmartClient.GSIceCream; +using BPASmartClient.Helper; +using BPASmartClient.Lebai; +using BPASmartClient.EventBus; +using BPASmartClient.Model.咖啡机.Enum; +using BPASmartClient.Message; +using BPASmartClient.Model.冰淇淋.Enum; +using BPASmartClient.Model.单片机.Enum; +using BPASmartClient.SCChip; +using BPASmartClient.Model; +using BPASmartClient.Model.单片机; +using static BPASmartClient.EventBus.EventBus; + +namespace BPASmartClient.MORKIC +{ + /* + * 冰淇淋咖啡机组合套装 + * 物料位置: + * 1:冰淇料 + * 2:冰淇淋杯 + * 5:咖啡 + * 6:咖啡杯 + */ + public class Control_MORKIC : BaseDevice + { + + //咖啡机主控程序 + private CoffeeMachine coffeeMachine; + //单片机主控程序 + private ICChipMachine icchipMachine; + //广绅单口冰淇淋机 + private IceCreamMachine iceCreamMachine; + //物料存放位置 + private Dictionary batchings = new Dictionary(); + /// + /// 获取乐百机器人的数据 + /// + SignalResult lebai = new SignalResult(); + /// + /// 咖啡位置是否有东西 + /// + private bool IsCoffeeMake=false; + + private bool enableFunny = false; + private DateTime lastRecvdOrder = DateTime.Now; + private bool working = false; + private bool IceIsOK = true; + + public void ConnectOk() + { + + } + /// + /// 当前正在制作咖啡 + /// + SimOrderData MakeCoffeeOrder = new SimOrderData(); + /// + /// 咖啡订单队列 + /// + ConcurrentQueue morkOrderPushesCoffee = new ConcurrentQueue(); + /// + /// 冰淇淋订单队列 + /// + ConcurrentQueue morkOrderPushesIceCream = new ConcurrentQueue(); + /// + /// 等待取餐的订单,只有一个 + /// + ConcurrentQueue WaitTakeMealOrder= new ConcurrentQueue(); + + public void Init() + { + + ActionManage.GetInstance.Register(new Action((s) => + { + if (s is DrCoffeeDrinksCode cf) + { + DoCoffee(new SimOrderData { Loc = ((int)cf).ToString() }); + } + else if (s is Dictionary ms) + { + if (ms.ContainsKey("Button")) + { + switch (ms["Button"]) + { + case "启动示教": + LebaiRobot.GetInstance.StartTeachMode(); + break; + case "停止示教": + LebaiRobot.GetInstance.EndtTeachMode(); + break; + case "启动机器人": + LebaiRobot.GetInstance.StartRobot(); + break; + case "急停": + LebaiRobot.GetInstance.EStopRobot(); + break; + default: + break; + } + } + } + }),"SimCoffee"); + + //构建所有商品物料信息 + batchings = PolymerBatching.BuildAll(); + + EventBus.EventBus.GetInstance().Subscribe(DeviceId, delegate (IEvent @event, EventCallBackHandle callBack) + { + if (MakeCoffeeOrder != null) + MakeCoffeeOrder.OrderStatus = 1; + }); + + System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None); + //一系列外围基础配置 + var com_Coffee = config.AppSettings.Settings["COM_Coffee"].Value; + var baud_Coffee = config.AppSettings.Settings["BAUD_Coffee"].Value; + var com_IceCream = config.AppSettings.Settings["COM_IceCream"].Value; + var baud_IceCream = config.AppSettings.Settings["BAUD_IceCream"].Value; + var iceCreamCXBThreshold = int.Parse(config.AppSettings.Settings["IceCream_CXB_Threshold"].Value); + + var com_ICChip = config.AppSettings.Settings["COM_ICChip"].Value; + var baud_ICChip = config.AppSettings.Settings["BAUD_IChip"].Value; + + + if (iceCreamCXBThreshold > 0) + { + //设置冰淇淋成型比 + MorkIStatus.GetInstance().CXB_Threshold = (byte)iceCreamCXBThreshold; + } + //咖啡机创建 + coffeeMachine = new CoffeeMachine(); + //单片机机创建 + icchipMachine = new ICChipMachine(); + //冰淇淋机创建 + iceCreamMachine = new IceCreamMachine(); + + Main(); + ReadRobotData(); + OrderMake(); + } + + private int NoOrderTime = 0; + + public override DeviceClientType DeviceType => throw new NotImplementedException(); + + //订单制作 + public void OrderMake() + { + ThreadManage.GetInstance().StartLong(new Action(() => + { + while (IsHealth &&(morkOrderPushesCoffee.Count > 0 || morkOrderPushesIceCream.Count>0 || IsCoffeeMake)) + { + working = true; NoOrderTime = 0; + //1.有咖啡订单 取杯去制作 + if (!IsCoffeeMake)//位置无杯子 + { + if (morkOrderPushesCoffee.Count>0 && morkOrderPushesCoffee.TryDequeue(out SimOrderData simOrder)) + { + IsCoffeeMake = true; MakeCoffeeOrder = simOrder; + MessageLog.GetInstance.Show($"开始制作 [咖啡] 订单[{simOrder.morkOrder.SortNum}]"); + DoCoffee(simOrder); + } + } + + if (!LebaiRobot.GetInstance.GetInput())//取餐口是否有餐饮 + { + //取餐位的订单完成 + if (WaitTakeMealOrder.TryDequeue(out SimOrderData waitOrder)) OrderChange(waitOrder.morkOrder.SuborderId, BPA.Message.Enum.ORDER_STATUS.COMPLETED_TAKE); + + + //1.制作冰淇淋 + if (morkOrderPushesIceCream.Count>0 && MorkIStatus.GetInstance().CurrentMode!= MORKI_MODE.制冷模式) new GSIceCream_ModeSetEvent() { Mode = MORKI_MODE.制冷模式 }.Publish(); + + if (MorkIStatus.GetInstance().CXB >= 86 && morkOrderPushesIceCream.Count > 0)//成型比大于80 我才会制作 + { + if (LebaiRobot.GetInstance.GetInput(3)) + { + if(IceIsOK) MessageLog.GetInstance.Show("请擦拭冰淇淋机出口"); + IceIsOK = false; + + } + else if(morkOrderPushesIceCream.TryDequeue(out SimOrderData order)) + { + IceIsOK = true; + MessageLog.GetInstance.Show($"开始制作 [冰淇淋] 订单[{order.morkOrder.SortNum}]"); + DoIceCream(order); + } + } + + //2.取咖啡到取餐口 + if (IsCoffeeMake) + { + if (MakeCoffeeOrder != null && MakeCoffeeOrder.OrderStatus == 1) + { + MessageLog.GetInstance.Show($"将咖啡移动到取餐位 [咖啡] 订单[{MakeCoffeeOrder.morkOrder.SortNum}]"); + DoCoffeeQC(MakeCoffeeOrder); + MakeCoffeeOrder = null; + IsCoffeeMake = false; + } + } + } + working = false; + lastRecvdOrder = DateTime.Now; + } + + if (IsHealth == false && (morkOrderPushesCoffee.Count > 0 || morkOrderPushesIceCream.Count > 0 || IsCoffeeMake)) + { + MessageLog.GetInstance.Show($"机器连接问题 订单,不允许制作,请检查设备连接后尝试," + + $"乐白:{LebaiRobot.GetInstance.IsConnected}咖啡机:{MorkIStatus.GetInstance().CanDo}单片机:{ChipStatus.GetInstance().CanDo}"); + + if (LebaiRobot.GetInstance.IsConnected && IsCoffeeMake && !LebaiRobot.GetInstance.GetInput())//乐白有订单 + { + MessageLog.GetInstance.Show($"将咖啡移动到取餐位 [咖啡] 订单[{MakeCoffeeOrder.morkOrder.SortNum}]"); + DoCoffeeQC(MakeCoffeeOrder); + MakeCoffeeOrder = null; + IsCoffeeMake = false; + } + } + + if (!LebaiRobot.GetInstance.GetInput()) + { + if (WaitTakeMealOrder.TryDequeue(out SimOrderData waitOrder)) OrderChange(waitOrder.morkOrder.SuborderId, BPA.Message.Enum.ORDER_STATUS.COMPLETED_TAKE); + } + + + Thread.Sleep(1000); + }),"订单制作"); + } + + private void OrderChange(string subid, ORDER_STATUS oRDER_STATUS) + { + EventBus.EventBus.GetInstance().Publish(new OrderStatusChangedEvent() { Status = oRDER_STATUS, SubOrderId = subid, deviceClientType = DeviceType }); + } + + public void Main() + { + //咖啡机开启主线程 + coffeeMachine.Start(); + //单片机开启主线程 + icchipMachine.Start(); + //冰淇淋机开启主线程 + iceCreamMachine.Start(); + new GSIceCream_ModeSetEvent() { Mode = MORKI_MODE.制冷模式 }.Publish(); + //开始心跳刷新,根据咖啡机及冰淇淋机来判断 + //ThreadManage.GetInstance().StartLong(new Action(() => + //{ + // GeneralConfig.Healthy = + // LebaiRobot.GetInstance.IsConnected && + // MorkCStatus.GetInstance().CanDo && + // ChipStatus.GetInstance().CanDo; + // //GeneralConfig.Healthy = true; + // Thread.Sleep(100); + //}), "MORK-IC心跳刷新"); + ThreadManage.GetInstance().Start(new Action(() => + { + while (!LebaiRobot.GetInstance.IsConnected) + { + Thread.Sleep(10); + } + //LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_欢迎); + }), "MORK-IC欢迎"); + + } + + public void DataParse(T order) + { + if (order is MorkOrderPush morkOrderPush) + { + //商品类型 + GOODS_TYPE currentGoodsType = GOODS_TYPE.NEITHER; + string loc_coffe = string.Empty; + string loc_cup = string.Empty; + #region 订单分类 + //遍历物料 + foreach (var item in morkOrderPush.GoodBatchings) + { + var res = Json.Data.orderMaterialDelivery.BatchingInfo.FirstOrDefault(p => p.BatchingId == item.BatchingId); + if (res != null) + { + //验证商品是咖啡还是冰淇淋 + if (ValidateGoodsByBatching(res.BatchingLoc) != GOODS_TYPE.NEITHER) + { + //获取当前物料所属商品类型 + currentGoodsType = ValidateGoodsByBatching(res.BatchingLoc); + } + //获取主料和容器位置 + switch (batchings[res.BatchingLoc].BatchingClass) + { + case BATCHING_CLASS.HOLDER: + loc_cup = res.BatchingLoc; + break; + case BATCHING_CLASS.MAIN_MATERIAL: + loc_coffe = res.BatchingLoc; + break; + } + } + } + //根据商品类型执行具体制作流程 + switch (currentGoodsType) + { + case GOODS_TYPE.COFFEE: + morkOrderPushesCoffee.Enqueue(new SimOrderData { Loc = loc_coffe,morkOrder = morkOrderPush }); + break; + case GOODS_TYPE.ICECREAM: + morkOrderPushesIceCream.Enqueue(new SimOrderData { Loc = loc_coffe,morkOrder = morkOrderPush }); + break; + case GOODS_TYPE.NEITHER: + MessageLog.GetInstance.Show("未知的商品类型"); + break; + } + #endregion + + + } + } + + /// + /// 验证当前是做咖啡还是做冰淇淋 + /// + /// 物料位置 + private GOODS_TYPE ValidateGoodsByBatching(string batchingLoc) + { + if (batchings.ContainsKey(batchingLoc)) + return batchings[batchingLoc].GoodsType; + return GOODS_TYPE.NEITHER; + } + + private void Wait(int value = 101) + { + while (!(lebai.Ok && lebai.Value == value)) + { + Thread.Sleep(5); + } + } + + /// + /// 做咖啡-接杯子 并且 回到 安全位置 + /// + private void DoCoffee(SimOrderData order) + { + #region 且时且多入场设备程序 + int checkeNum = 0; + // are.Reset(); + LebaiRobot.GetInstance.SetValue(0); + OrderChange(order.morkOrder.SuborderId, BPA.Message.Enum.ORDER_STATUS.COOKING); + //SimpleFactory.GetInstance.OrderChanged(order.morkOrder.SuborderId, BPA.Message.Enum.ORDER_STATUS.COOKING); + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_取咖啡杯); + Wait(); + new SCChip_TakeCupEvent() { Cup = IC_CUP.CUP_COFFEE }.Publish();//落碗控制 + Thread.Sleep(500); + MessageLog.GetInstance.Show("尝试取咖啡杯!"); + LebaiRobot.GetInstance.SetValue(1); + + int count = 2; + p: + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_咖啡杯检测); + Wait(); + LebaiRobot.GetInstance.SetValue(1); + + if (!LebaiRobot.GetInstance.GetInput()) + { + if (count >= 3) + { + //退出循环回到初始位置 + MessageLog.GetInstance.Show($"执行{count}次取咖啡杯,仍为成功,订单默认废弃,机器人回到初始位置!"); + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_咖啡杯回原点); + Wait(); + LebaiRobot.GetInstance.SetValue(1); + return; + } + MessageLog.GetInstance.Show("执行二次取咖啡杯"); + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_二次取咖啡杯); + Wait(); + new SCChip_TakeCupEvent() { Cup = IC_CUP.CUP_COFFEE }.Publish();//落碗控制 + LebaiRobot.GetInstance.SetValue(1); + count++; + goto p; + } + + MessageLog.GetInstance.Show("咖啡杯取杯完成"); + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_接咖啡_新); + Wait(); + LebaiRobot.GetInstance.SetValue(1); + //加场景 回初始位置 + new DRCoffee_MakeCoffeeEvent() { DrinkCode = (Model.咖啡机.Enum.DrCoffeeDrinksCode)int.Parse(order.Loc) }.Publish(); //接咖啡控制 + MessageLog.GetInstance.Show($"发送咖啡机制作{order.Loc}!"); + #endregion + + } + + /// + /// 将咖啡杯子 取走到 取餐口 + /// + private void DoCoffeeQC(SimOrderData order) + { + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_取咖啡出餐); + Wait(); + LebaiRobot.GetInstance.SetValue(1); + //订单状态改变:完成 + OrderChange(order.morkOrder.SuborderId, BPA.Message.Enum.ORDER_STATUS.COMPLETED_COOK); + //SimpleFactory.GetInstance.OrderChanged(order.morkOrder.SuborderId,BPA.Message.Enum.ORDER_STATUS.COMPLETED_COOK); + MessageLog.GetInstance.Show($"{order.morkOrder.GoodsName}等待取餐"); + WaitTakeMealOrder.Enqueue(order); + } + + /// + /// 做冰淇淋 + /// + private void DoIceCream(SimOrderData order) + { + //if (LebaiRobot.GetInstance.GetInput(3)) + //{ + // MessageLog.GetInstance.Show("请擦拭冰淇淋机出口"); + // return; + //} + + #region 且时且多入场设备程序 + int checkeNum = 0; + //are.Reset(); + LebaiRobot.GetInstance.SetValue(0); + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_取冰淇淋杯); + Wait(); + new SCChip_TakeCupEvent() { Cup = IC_CUP.CUP_ICECREAM }.Publish();//落碗控制 + Thread.Sleep(500); + MessageLog.GetInstance.Show("尝试取冰淇淋杯!"); + LebaiRobot.GetInstance.SetValue(1); + + int count = 2; + p: + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_冰淇淋杯检测); + Wait(); + + LebaiRobot.GetInstance.SetValue(1); + if (!LebaiRobot.GetInstance.GetInput()) + { + if (count >= 3) + { + //退出循环回到初始位置 + MessageLog.GetInstance.Show($"执行{count}次取冰淇淋杯,仍未成功,订单默认废弃,机器人回到初始位置!"); + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_冰淇淋杯回原点); + Wait(); + LebaiRobot.GetInstance.SetValue(1); + return; + } + MessageLog.GetInstance.Show($"执行{count}次取冰淇淋杯!"); + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_二次取冰淇淋杯); + new SCChip_TakeCupEvent() { Cup = IC_CUP.CUP_ICECREAM }.Publish();//落碗控制 + Wait(); + LebaiRobot.GetInstance.SetValue(1); + count++; + goto p; + } + MessageLog.GetInstance.Show("冰淇淋杯检测完成"); + + #region 通讯冰淇淋机 + + //制冷模式 + new GSIceCream_ModeSetEvent() { Mode = MORKI_MODE.制冷模式 }.Publish(); + LebaiRobot.GetInstance.SetValue(0); + OrderChange(order.morkOrder.SuborderId, BPA.Message.Enum.ORDER_STATUS.COOKING); + //SimpleFactory.GetInstance.OrderChanged(order.morkOrder.SuborderId, BPA.Message.Enum.ORDER_STATUS.COOKING); + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_接1号冰淇淋); + Wait(); + bool doItResult = true; + //出料 + new GSIceCream_DischargeEvent().Publish(delegate (object[] args) + { + doItResult = (bool)args[0]; + }); + if (doItResult) + { + IceCreamCookCheck(); + } + else + { + int count_1 = 0; + while (MorkIStatus.GetInstance().CXB <= 86) + { + Thread.Sleep(5); + count_1++; + if (count_1 >= 2000) + break; + } + IceCreamCookCheck(); + } + LebaiRobot.GetInstance.SetValue(1); + #endregion + + while (LebaiRobot.GetInstance.GetInput()) + { + Thread.Sleep(500); + } + LebaiRobot.GetInstance.Scene(LebaiRobot.SENCE_放冰淇淋位置); + + Wait(); + LebaiRobot.GetInstance.SetValue(1); + //订单状态改变:完成 + OrderChange(order.morkOrder.SuborderId, BPA.Message.Enum.ORDER_STATUS.COMPLETED_COOK); + //SimpleFactory.GetInstance.OrderChanged(order.morkOrder.SuborderId, BPA.Message.Enum.ORDER_STATUS.COMPLETED_COOK); + MessageLog.GetInstance.Show($"{order.morkOrder.GoodsName}等待取餐"); + WaitTakeMealOrder.Enqueue(order); + #endregion + + } + + /// + /// 冰淇淋制作 + /// + public void IceCreamCookCheck() + { + + int retry = 3; + DateTime beginTime = DateTime.Now; + while (!LebaiRobot.GetInstance.GetInput(3)) + { + if (retry <= 0 && DateTime.Now.Subtract(beginTime).TotalSeconds >= 10) + { + MessageLog.GetInstance.Show("超时未出料,重试次数用尽"); + break; + } + if (DateTime.Now.Subtract(beginTime).TotalSeconds > 5) + { + MessageLog.GetInstance.Show("超时未出料,重新发送打料指令"); + new GSIceCream_ModeSetEvent() { Mode = MORKI_MODE.打料 }.Publish(); + beginTime = DateTime.Now; + retry--; + } + Thread.Sleep(10); + } + MessageLog.GetInstance.Show("开始等待6s"); + Thread.Sleep(5000); + + } + + //private void CoffeEndCookHandle(IEvent @event, EventBus.EventCallBackHandle callBack) + //{ + // //are.Set(); + // if(MakeCoffeeOrder!=null) + // MakeCoffeeOrder.OrderStatus = 1; + //} + + public void ReadRobotData() + { + ThreadManage.GetInstance().StartLong(new Action(() => + { + lebai = LebaiRobot.GetInstance.GetValueAsync(); + LebaiRobot.GetInstance.GetRobotModeStatus(); + //LebaiRobot.GetInstance.GetInput(); + + + Thread.Sleep(100); + }), "乐百机器人数据读取", true); + } + + public void SimOrder(T simOrder) + { + + } + + /// + /// IOT 广播消息命令 + /// + public void IotBroadcast(T broadcast) + { + if (broadcast != null && broadcast is IOTCommandModel iOTCommand) + { + switch (iOTCommand.CommandName) + { + case 0://控制类 + if (iOTCommand.CommandValue != null) + { + if (iOTCommand.CommandValue.ContainsKey("SimOrder")) + { + //SimOrder(new SimOrderData { NoodleLoc = 1, BowlLoc = 10 }); + } + } + break; + case 1://设置属性 + + break; + case 2://通知消息 + + break; + default: + break; + } + } + } + + public override void DoMain() + { + + } + + public override void Stop() + { + throw new NotImplementedException(); + } + + public override void ReadData() + { + throw new NotImplementedException(); + } + + public override void MainTask() + { + throw new NotImplementedException(); + } + + public override void ResetProgram() + { + throw new NotImplementedException(); + } + } + + + public class SimOrderData + { + public string id { get; set; } + + public int OrderStatus { get; set; } + + public string Loc { get; set; } + + public MorkOrderPush morkOrder { get; set; } + + public SimOrderData() + { + id = Guid.NewGuid().ToString(); + OrderStatus=0; + } + } +} diff --git a/HBLConsole.MORKIC/PolymerBatching.cs b/HBLConsole.MORKIC/PolymerBatching.cs new file mode 100644 index 00000000..fcd0ec6f --- /dev/null +++ b/HBLConsole.MORKIC/PolymerBatching.cs @@ -0,0 +1,122 @@ + +using BPASmartClient.Lebai; +using BPASmartClient.Model.单片机.Enum; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.MORKIC +{ + internal enum GOODS_TYPE + { + NEITHER, + COFFEE, + ICECREAM, + } + + internal enum BATCHING_CLASS + { + HOLDER, + MAIN_MATERIAL, + } + + internal class PolymerBatching + { + internal const string ICE_MAIN_BATCHIN1_LOC = "52"; + internal const string ICE_MAIN_BATCHIN2_LOC = "53"; + internal const string ICE_MAIN_BATCHIN3_LOC = "54"; + internal const string COFFEE_HOLDER_LOC = "30"; + internal const string ICE_HOLDER_LOC = "51"; + public static Dictionary GOODS_TYPES = new Dictionary() { + {"1", GOODS_TYPE.COFFEE}, + {"2", GOODS_TYPE.COFFEE}, + {"3", GOODS_TYPE.COFFEE}, + {"4", GOODS_TYPE.COFFEE}, + {"5", GOODS_TYPE.COFFEE}, + {"6", GOODS_TYPE.COFFEE}, + {"7", GOODS_TYPE.COFFEE}, + {"8", GOODS_TYPE.COFFEE}, + {"9", GOODS_TYPE.COFFEE}, + {"10",GOODS_TYPE.COFFEE}, + {"11",GOODS_TYPE.COFFEE}, + {"12",GOODS_TYPE.COFFEE}, + {"13",GOODS_TYPE.COFFEE}, + {"14",GOODS_TYPE.COFFEE}, + {"15",GOODS_TYPE.COFFEE}, + {"16",GOODS_TYPE.COFFEE}, + {"17",GOODS_TYPE.COFFEE}, + {"18",GOODS_TYPE.COFFEE}, + {"19",GOODS_TYPE.COFFEE}, + {"20",GOODS_TYPE.COFFEE}, + {"21",GOODS_TYPE.COFFEE}, + {"22",GOODS_TYPE.COFFEE}, + {"23",GOODS_TYPE.COFFEE}, + {"24",GOODS_TYPE.COFFEE}, + {"25",GOODS_TYPE.COFFEE}, + {"30",GOODS_TYPE.COFFEE}, + {"51",GOODS_TYPE.ICECREAM}, + {ICE_MAIN_BATCHIN1_LOC,GOODS_TYPE.ICECREAM}, + {ICE_MAIN_BATCHIN2_LOC,GOODS_TYPE.ICECREAM}, + {ICE_MAIN_BATCHIN3_LOC,GOODS_TYPE.ICECREAM}, + }; + + public GOODS_TYPE GoodsType { get; set; } + public BATCHING_CLASS BatchingClass { get; set; } + private string loc; + + public string Loc + { + get { return loc; } + set + { + loc = value; + if (GOODS_TYPES.ContainsKey(loc)) + GoodsType = GOODS_TYPES[loc]; + switch (loc) + { + case COFFEE_HOLDER_LOC: + case ICE_HOLDER_LOC: + BatchingClass = BATCHING_CLASS.HOLDER; + break; + default: + BatchingClass = BATCHING_CLASS.MAIN_MATERIAL; + break; + } + } + } + + internal static Dictionary BuildAll() + { + Dictionary temp = new Dictionary(); + foreach (var item in GOODS_TYPES) + { + temp.Add(item.Key, new PolymerBatching() { Loc = item.Key }); + } + return temp; + } + + internal static IC_SE GetIceCreamSE(string loc, out int sence) + { + switch (loc) + { + case ICE_MAIN_BATCHIN1_LOC: + sence = LebaiRobot.SENCE_接1号冰淇淋; + return IC_SE.SE_1; + + case ICE_MAIN_BATCHIN2_LOC: + sence = LebaiRobot.SENCE_接2号冰淇淋; + return IC_SE.SE_2; + + case ICE_MAIN_BATCHIN3_LOC: + sence = LebaiRobot.SENCE_接3号冰淇淋; + return IC_SE.SE_3; + + default: + sence = LebaiRobot.SENCE_接1号冰淇淋; + return IC_SE.SE_1; + } + } + } +} diff --git a/SmartClient.sln b/SmartClient.sln index 1beeae52..4aaf5c88 100644 --- a/SmartClient.sln +++ b/SmartClient.sln @@ -74,7 +74,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lebai.SDK", "Lebai.SDK\Leba EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPASmartClient.PLC", "BPASmartClient.MORKSM.BK.PLC\BPASmartClient.PLC.csproj", "{7F04A788-38B5-42CB-B601-70C657C953B8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BPASmartClient.MorkF", "BPASmartClient.MorkF\BPASmartClient.MorkF.csproj", "{15FD3FF1-80F1-4274-945A-BA5EBA35999E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPASmartClient.MorkF", "BPASmartClient.MorkF\BPASmartClient.MorkF.csproj", "{15FD3FF1-80F1-4274-945A-BA5EBA35999E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BPASmartClient.MORKIC", "HBLConsole.MORKIC\BPASmartClient.MORKIC.csproj", "{31A3B51C-A4BB-4FEB-B712-38482F6D1667}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -194,6 +196,10 @@ Global {15FD3FF1-80F1-4274-945A-BA5EBA35999E}.Debug|Any CPU.Build.0 = Debug|Any CPU {15FD3FF1-80F1-4274-945A-BA5EBA35999E}.Release|Any CPU.ActiveCfg = Release|Any CPU {15FD3FF1-80F1-4274-945A-BA5EBA35999E}.Release|Any CPU.Build.0 = Release|Any CPU + {31A3B51C-A4BB-4FEB-B712-38482F6D1667}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {31A3B51C-A4BB-4FEB-B712-38482F6D1667}.Debug|Any CPU.Build.0 = Debug|Any CPU + {31A3B51C-A4BB-4FEB-B712-38482F6D1667}.Release|Any CPU.ActiveCfg = Release|Any CPU + {31A3B51C-A4BB-4FEB-B712-38482F6D1667}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -227,6 +233,7 @@ Global {3A55F68A-D526-4CFC-A5A6-B69FB76716C2} = {666CB1A9-562E-453A-A2C7-FD9D77CFDFDD} {7F04A788-38B5-42CB-B601-70C657C953B8} = {666CB1A9-562E-453A-A2C7-FD9D77CFDFDD} {15FD3FF1-80F1-4274-945A-BA5EBA35999E} = {9FB27073-61A0-4FE3-94DB-5FDDE062332F} + {31A3B51C-A4BB-4FEB-B712-38482F6D1667} = {9FB27073-61A0-4FE3-94DB-5FDDE062332F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {9AEC9B81-0222-4DE9-B642-D915C29222AC}