diff --git a/BPASmartClient.AGV/AGVHelper.cs b/BPASmartClient.AGV/AGVHelper.cs new file mode 100644 index 00000000..50e08d91 --- /dev/null +++ b/BPASmartClient.AGV/AGVHelper.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Net; +using System.Web; +using Newtonsoft.Json; +using System.Net.Http; + + +namespace BPASmartClient.AGV +{ + public class AGVHelper + { + public static AGVHelper _Instance { get; set; } + public static AGVHelper GetInstance => _Instance ?? (_Instance = new AGVHelper()); + + public AGVHelper() + { + + } + + public string HttpRequest(string url, string head, string body) + { + return PostData(url, head, body); + } + public string PostData(string url, string head, string body) + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + request.Method = "POST"; + request.Headers["header"] = head; + //request.Proxy = new WebProxy("192.168.1.12",80); + byte[] bytes = Encoding.UTF8.GetBytes(body); + request.ContentType = "application/json; charset=UTF-8"; ;//窗体数据被编码为名称/值对形式 + //request.ContentType = "application/json"; + request.ContentLength = bytes.Length; + Stream myResponseStream = request.GetRequestStream(); + myResponseStream.Write(bytes, 0, bytes.Length); + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + StreamReader myStreamReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8); + string retString = myStreamReader.ReadToEnd(); + myStreamReader.Close(); + myResponseStream.Close(); + + if (response != null) + { + response.Close(); + } + if (request != null) + { + request.Abort(); + } + return retString;//返回响应报文 + + + } + + } +} diff --git a/BPASmartClient.AGV/AGVLoadInteracteModel.cs b/BPASmartClient.AGV/AGVLoadInteracteModel.cs new file mode 100644 index 00000000..db147e31 --- /dev/null +++ b/BPASmartClient.AGV/AGVLoadInteracteModel.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.AGV +{ + /// + /// AGV上下料交互反馈接口(上游系统->快仓系统) + /// + internal class AGVLoadInteracteModel + { + public string agvCode { get; set;} + public string jobId { get; set; } + public string msgId { get; set; } + public bool? complete { get; set; } + } +} diff --git a/BPASmartClient.AGV/AGVModel.cs b/BPASmartClient.AGV/AGVModel.cs new file mode 100644 index 00000000..1665c1f6 --- /dev/null +++ b/BPASmartClient.AGV/AGVModel.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.AGV +{ + /// + /// AGV任务下发 + /// + internal class AGVModel + { + /// + /// 必填项 + /// + public string robotJobId { get; set; } + /// + /// 必填项 + /// + public long warehouseId { get; set; } + public string? robotJobGroupId { get; set; } + public int? sequence { get; set; } + /// + /// 必填项 + /// + public int jobPriority { get; set; } + /// + /// 必填项 + /// + public int jobPriorityType { get; set; } + public string? deadline { get; set; } + public string? agvType { get; set; } + public string? agvEndPoint { get; set; } + public bool? needOperation { get; set; } + public string? agvCode { get; set; } + public int? taskCountDown { get; set; } + public string? businessType { get; set; } + /// + /// 必填项 + /// + public string jobType { get; set; } + /// + /// 必填项 + /// + public IJobData jobData { get; set; } + + } +} diff --git a/BPASmartClient.AGV/AGVRequestUrl.cs b/BPASmartClient.AGV/AGVRequestUrl.cs new file mode 100644 index 00000000..20817893 --- /dev/null +++ b/BPASmartClient.AGV/AGVRequestUrl.cs @@ -0,0 +1,42 @@ +namespace BPASmartClient.AGV +{ + public class AGVRequestUrl + { + //public string HttpHeader { get; set; } + //public string TaskSendBody { get; set; } + public AGVRequestUrl(string IpAddress) + { + TaskSendUrl= $"http://{IpAddress}/api/quicktron/wcs/standardized.robot.job.submit"; + TaskCancelUrl= $"http://{IpAddress}/api/quicktron/wcs/standardized.robot.job.cancel"; + TaskCompleteUrl= $"http://{IpAddress}/api/quicktron/wcs/standardized.operation.notice"; + AGVInteracteUrl= $"http://{IpAddress}/api/quicktron/wcs/standardized.roller.job.upstream.response"; + } + + + #region Url汇总 + //各种AGV的移动及搬运任务。 + // 本接口请求参数包含公共字段及具体任务字段两部分组成。 + //支持批量任务下发。 + public string TaskSendUrl { get; set; } + + //货架搬运任务指令下发后,允许上游系统调用该接口取消移位任务,支持取消策略。不同车型允许取消的任务节点不同,具体信息见API文档 + public string TaskCancelUrl { get; set; } + + //工作站任务实操完成后调用该接口。如果bucket有其他任务去执行其他任务。在线工作站货架直接回库,离线工作站分配AGV回库。 + public string TaskCompleteUrl { get; set; } + + //1.辊筒AGV在手动上下料时请求上游交互后,上游下发的反馈接口 + //2.料箱AGV在任务下发需要和上游进行交互时调用此接口 + //3.翻板车AGV在投递点前确认时上游反馈接口 + public string AGVInteracteUrl { get; set; } + #endregion + } +} + + + + + + + + diff --git a/BPASmartClient.AGV/AGVTaskCancelModel.cs b/BPASmartClient.AGV/AGVTaskCancelModel.cs new file mode 100644 index 00000000..3c6b01e6 --- /dev/null +++ b/BPASmartClient.AGV/AGVTaskCancelModel.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.AGV +{ + /// + /// AGV任务取消 + /// + internal class AGVTaskCancelModel + { + public string robotJobId { get; set; } + public long warehouseId { get; set; } + public string? executeMode { get; set; } + public string? reason { get; set; } + } +} diff --git a/BPASmartClient.AGV/AGVTaskCompleteNotifyModel.cs b/BPASmartClient.AGV/AGVTaskCompleteNotifyModel.cs new file mode 100644 index 00000000..a6d5ff68 --- /dev/null +++ b/BPASmartClient.AGV/AGVTaskCompleteNotifyModel.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.AGV +{ + /// + /// AGV任务完成通知 + /// + internal class AGVTaskCompleteNotifyModel + { + public string? robotJobId { get; set; } + public string? bucketCode { get; set; } + public string? bucketslotCode { get; set; } + public long warehouseId { get; set; } + public bool? nullFlag { get; set; } + public string? jobId { get; set; } + } +} diff --git a/BPASmartClient.AGV/AGV_PointRollerJobData.cs b/BPASmartClient.AGV/AGV_PointRollerJobData.cs new file mode 100644 index 00000000..d2f638cd --- /dev/null +++ b/BPASmartClient.AGV/AGV_PointRollerJobData.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.AGV +{ + /// + /// 辊筒点到点搬运 + /// + internal class AGV_PointRollerJobData:IJobData + { + public string? containerCode { get; set; } + public string startPoint { get; set; } + public string endPoint { get; set; } + public bool autoLoad { get; set; } + public bool enableIOLoad { get; set; } + public bool autoUnload { get; set; } + public bool enableIOUnload { get; set; } + public long? loadEquipmentId { get; set; } = null; + public long? unloadEquipmentId { get; set; } = null; + public bool? loadInteractive { get; set; } + public int? loadHeight { get; set; } + public int? unloadHeight { get; set; } + } +} diff --git a/BPASmartClient.AGV/AGV_SlotRollerJobData.cs b/BPASmartClient.AGV/AGV_SlotRollerJobData.cs new file mode 100644 index 00000000..ffe47822 --- /dev/null +++ b/BPASmartClient.AGV/AGV_SlotRollerJobData.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.AGV +{ + /// + /// 辊筒货位到货位搬运 + /// + internal class AGV_SlotRollerJobData:IJobData + { + public string? containerCode { get; set; } + public string startIotCode { get; set; } + public string endSlotCode { get; set; } + public bool autoLoad { get; set; } + public bool enableIOLoad { get; set; } + public bool autoUnload { get; set; } + public bool enableIOUnload { get; set; } + public long? loadEquipmentId { get; set; } = null; + public long? unLoadEquipmentId { get; set; } = null; + + public bool? loadInteractive { get; set; } + } +} diff --git a/BPASmartClient.AGV/BPASmartClient.AGV.csproj b/BPASmartClient.AGV/BPASmartClient.AGV.csproj new file mode 100644 index 00000000..933c8b28 --- /dev/null +++ b/BPASmartClient.AGV/BPASmartClient.AGV.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/BPASmartClient.AGV/HttpRequestHeaderModel.cs b/BPASmartClient.AGV/HttpRequestHeaderModel.cs new file mode 100644 index 00000000..ab24a75d --- /dev/null +++ b/BPASmartClient.AGV/HttpRequestHeaderModel.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.AGV +{ + internal class HttpRequestHeaderModel + { + public string appKey { get; set; } + public string appSecret { get; set; } + public string requestId { get; set; } + public string timestamp { get; set; } + public string version { get; set; } + } +} diff --git a/BPASmartClient.AGV/HttpResponseData.cs b/BPASmartClient.AGV/HttpResponseData.cs new file mode 100644 index 00000000..9e843d58 --- /dev/null +++ b/BPASmartClient.AGV/HttpResponseData.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.AGV +{ + internal class HttpResponseData + { + public string code { get; set; } + public bool message { get; set; } + public string robotJobId { get; set; } + } +} diff --git a/BPASmartClient.AGV/HttpResponseModel.cs b/BPASmartClient.AGV/HttpResponseModel.cs new file mode 100644 index 00000000..5ac3cb22 --- /dev/null +++ b/BPASmartClient.AGV/HttpResponseModel.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.AGV +{ + internal class HttpResponseModel + { + public string code { get; set; } + public string message { get; set; } + public bool success { get; set; } + public HttpResponseData data { get; set; } + } +} diff --git a/BPASmartClient.AGV/JobData.cs b/BPASmartClient.AGV/JobData.cs new file mode 100644 index 00000000..6e482e07 --- /dev/null +++ b/BPASmartClient.AGV/JobData.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.AGV +{ + public interface IJobData + { + + } +} diff --git a/BPASmartClient.Business/BPASmartClient.Business.csproj b/BPASmartClient.Business/BPASmartClient.Business.csproj index 88631d12..517190e1 100644 --- a/BPASmartClient.Business/BPASmartClient.Business.csproj +++ b/BPASmartClient.Business/BPASmartClient.Business.csproj @@ -8,7 +8,7 @@ - + diff --git a/BPASmartClient.Business/Plugin/DeviceMgr.cs b/BPASmartClient.Business/Plugin/DeviceMgr.cs index cc2245e9..3a81e207 100644 --- a/BPASmartClient.Business/Plugin/DeviceMgr.cs +++ b/BPASmartClient.Business/Plugin/DeviceMgr.cs @@ -5,6 +5,7 @@ using BPASmartClient.Helper; using BPASmartClient.Http; using BPASmartClient.Message; using BPASmartClient.Model; +using BPASmartClient.Model.小炒机; using BPASmartClient.Peripheral; using Newtonsoft.Json; using System; @@ -128,6 +129,15 @@ namespace BPASmartClient.Business MessageLog.GetInstance.Show($"物料ID:=[{x.BatchingId}],{x.BatchingLoc}号位置:{x.BatchingCount}"); }); } + else if (PushType == 2)//小炒API流程获取,待定 + { + new StirFryGoodsEvent() + { + DeviceId = device.DeviceId, + stirFrymessage = JsonConvert.DeserializeObject(result) + }.Publish(); + MessageLog.GetInstance.Show("接收到【 API 】获取的小炒流程信息"); + } } catch (Exception ex) { diff --git a/BPASmartClient.Business/Plugin/OrderProxy.cs b/BPASmartClient.Business/Plugin/OrderProxy.cs index 04903d74..7e3b4e34 100644 --- a/BPASmartClient.Business/Plugin/OrderProxy.cs +++ b/BPASmartClient.Business/Plugin/OrderProxy.cs @@ -1,11 +1,14 @@ //#define test using BPA.Message; using BPA.Message.Enum; +using BPA.Models; +using BPASmartClient.Device; using BPASmartClient.EventBus; using BPASmartClient.Helper; using BPASmartClient.Http; using BPASmartClient.Message; using BPASmartClient.Model; +using BPASmartClient.Model.小炒机; using Newtonsoft.Json; using System; using System.Collections.Concurrent; @@ -99,6 +102,18 @@ namespace BPASmartClient.Business MessageLog.GetInstance.Show($"物料ID:=[{x.BatchingId}],{x.BatchingLoc}号位置:{x.BatchingCount}"); }); } + //小炒流程信息 + else if (message is StirFryPushMessage frybom) + { + IDevice device = deviceMgr.GetDevices().FirstOrDefault(x => x.DeviceId == 28); + new StirFryGoodsEvent() { + DeviceId = device.DeviceId, + stirFrymessage =frybom + }.Publish(); + MessageLog.GetInstance.Show("接受到【MQTT】的小炒流程信息"); + + + } }); EventBus.EventBus.GetInstance().Subscribe(0, OrderStatusChangedHandle); diff --git a/BPASmartClient.CustomResource/BPASmartClient.CustomResource.csproj b/BPASmartClient.CustomResource/BPASmartClient.CustomResource.csproj index 28267f47..c514ab2e 100644 --- a/BPASmartClient.CustomResource/BPASmartClient.CustomResource.csproj +++ b/BPASmartClient.CustomResource/BPASmartClient.CustomResource.csproj @@ -93,6 +93,8 @@ + + @@ -173,6 +175,7 @@ + @@ -203,6 +206,8 @@ + + PreserveNewest @@ -221,6 +226,7 @@ + @@ -229,7 +235,7 @@ - + diff --git a/BPASmartClient.CustomResource/Converters/StatusConverter.cs b/BPASmartClient.CustomResource/Converters/StatusConverter.cs new file mode 100644 index 00000000..f84cf7b8 --- /dev/null +++ b/BPASmartClient.CustomResource/Converters/StatusConverter.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows.Media; + +namespace BPASmartClient.CustomResource.Converters +{ + public class StatusConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + SolidColorBrush returnValue = Brushes.SandyBrown; + if (value != null && value is ushort statusValue) + { + switch (statusValue) + { + case 0: + returnValue = Brushes.SandyBrown; + break; + case 1: + returnValue = Brushes.Green; + break; + case 2: + returnValue = Brushes.Yellow; + break; + case 3: + returnValue = Brushes.Aqua; + break; + case 4: + returnValue = Brushes.Red; + break; + default: + break; + } + } + return returnValue; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/BPASmartClient.CustomResource/Image/工艺流程.jpg b/BPASmartClient.CustomResource/Image/工艺流程.jpg new file mode 100644 index 00000000..7863056e Binary files /dev/null and b/BPASmartClient.CustomResource/Image/工艺流程.jpg differ diff --git a/BPASmartClient.CustomResource/Image/工艺流程.png b/BPASmartClient.CustomResource/Image/工艺流程.png new file mode 100644 index 00000000..8a0e23ec Binary files /dev/null and b/BPASmartClient.CustomResource/Image/工艺流程.png differ diff --git a/BPASmartClient.CustomResource/Image/顶部切图/自动化产线上位机控制系统.png b/BPASmartClient.CustomResource/Image/顶部切图/自动化产线上位机控制系统.png new file mode 100644 index 00000000..245dd258 Binary files /dev/null and b/BPASmartClient.CustomResource/Image/顶部切图/自动化产线上位机控制系统.png differ diff --git a/BPASmartClient.CustomResource/Themes/Generic.xaml b/BPASmartClient.CustomResource/Themes/Generic.xaml index df62dff6..4bbc2757 100644 --- a/BPASmartClient.CustomResource/Themes/Generic.xaml +++ b/BPASmartClient.CustomResource/Themes/Generic.xaml @@ -15,10 +15,6 @@ BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" /> - + diff --git a/BPASmartClient.CustomResource/Themes/MyStyle.xaml b/BPASmartClient.CustomResource/Themes/MyStyle.xaml index 98e7661c..af345c01 100644 --- a/BPASmartClient.CustomResource/Themes/MyStyle.xaml +++ b/BPASmartClient.CustomResource/Themes/MyStyle.xaml @@ -181,6 +181,14 @@ + + diff --git a/BPASmartClient.CustomResource/UserControls/IcoButton.cs b/BPASmartClient.CustomResource/UserControls/IcoButton.cs index ddec3c05..aa8a72c3 100644 --- a/BPASmartClient.CustomResource/UserControls/IcoButton.cs +++ b/BPASmartClient.CustomResource/UserControls/IcoButton.cs @@ -72,6 +72,28 @@ namespace BPASmartClient.CustomResource.UserControls DependencyProperty.Register("Command", typeof(Action), typeof(IcoButton), new PropertyMetadata(default, new PropertyChangedCallback(OnPropertyChanged))); + + public Action CommandObj + { + get { return (Action)GetValue(CommandObjProperty); } + set { SetValue(CommandObjProperty, value); } + } + public static readonly DependencyProperty CommandObjProperty = + DependencyProperty.Register("CommandObj", typeof(Action), typeof(IcoButton), + new PropertyMetadata(default, new PropertyChangedCallback(OnPropertyChanged))); + + + //public object CommandPar + //{ + // get { return (object)GetValue(CommandParProperty); } + // set { SetValue(CommandParProperty, value); } + //} + //public static readonly DependencyProperty CommandParProperty = + // DependencyProperty.Register("CommandPar", typeof(object), typeof(IcoButton), + // new PropertyMetadata(default, new PropertyChangedCallback(OnPropertyChanged))); + + + public string Content { get { return (string)GetValue(ContentProperty); } @@ -110,13 +132,29 @@ namespace BPASmartClient.CustomResource.UserControls new PropertyMetadata(Brushes.Gray, new PropertyChangedCallback(OnPropertyChanged))); + public Brush EnableColor + { + get { return (Brush)GetValue(EnableColorProperty); } + set { SetValue(EnableColorProperty, value); } + } + public static readonly DependencyProperty EnableColorProperty = + DependencyProperty.Register("EnableColor", typeof(Brush), typeof(IcoButton), + new PropertyMetadata(Brushes.Gray, new PropertyChangedCallback(OnPropertyChanged))); + + + public override void OnApplyTemplate() { base.OnApplyTemplate(); var icon = base.GetTemplateChild("PART_icoText") as TextBlock; var content = base.GetTemplateChild("PART_content") as TextBlock; var gr = base.GetTemplateChild("PART_gr") as Grid; - + //if (!this.IsEnabled) + //{ + // this.Foreground = EnableColor; + // this.BorderBrush = EnableColor; + //} + //this.IsEnabledChanged += IcoButton_IsEnabledChanged; if (icon != null) { Binding binding = new Binding("IcoText"); @@ -141,6 +179,15 @@ namespace BPASmartClient.CustomResource.UserControls } } + private void IcoButton_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) + { + //if (!this.IsEnabled) + //{ + // this.Foreground = EnableColor; + // this.BorderBrush = EnableColor; + //} + } + /// /// 鼠标离开颜色 /// diff --git a/BPASmartClient.Device/BPASmartClient.Device.csproj b/BPASmartClient.Device/BPASmartClient.Device.csproj index 5e442528..5d81ef80 100644 --- a/BPASmartClient.Device/BPASmartClient.Device.csproj +++ b/BPASmartClient.Device/BPASmartClient.Device.csproj @@ -7,7 +7,7 @@ - + diff --git a/BPASmartClient.Modbus/ModbusTcp.cs b/BPASmartClient.Modbus/ModbusTcp.cs index a437ead2..f8380822 100644 --- a/BPASmartClient.Modbus/ModbusTcp.cs +++ b/BPASmartClient.Modbus/ModbusTcp.cs @@ -21,8 +21,8 @@ namespace BPASmartClient.Modbus private ModbusFactory modbusFactory; private IModbusMaster master; private TcpClient tcpClient; - private string IPAdress; - private int Port; + public string IPAdress; + public int Port; public Action ConnectOk { get; set; } @@ -49,11 +49,11 @@ namespace BPASmartClient.Modbus Port = port; modbusFactory = new ModbusFactory(); Connect(); - master.Transport.ReadTimeout = 2000;//读取超时时间 - master.Transport.WriteTimeout = 2000;//写入超时时间 - master.Transport.Retries = 10;//重试次数 if (Connected) { + master.Transport.ReadTimeout = 2000;//读取超时时间 + master.Transport.WriteTimeout = 2000;//写入超时时间 + master.Transport.Retries = 10;//重试次数 ConnectOk?.Invoke(); MessageLog.GetInstance.Show($"设备【{ip}:{port}】连接成功"); } @@ -92,7 +92,7 @@ namespace BPASmartClient.Modbus Thread.Sleep(3000); } } - if (ErrorFlag) MessageLog.GetInstance.Show("ModbusTcp 重连成功!"); + if (ErrorFlag && IsReconnect) MessageLog.GetInstance.Show("ModbusTcp 重连成功!"); } /// diff --git a/BPASmartClient.Model/BPASmartClient.Model.csproj b/BPASmartClient.Model/BPASmartClient.Model.csproj index 9a94b652..a939251d 100644 --- a/BPASmartClient.Model/BPASmartClient.Model.csproj +++ b/BPASmartClient.Model/BPASmartClient.Model.csproj @@ -17,7 +17,7 @@ - + diff --git a/BPASmartClient.Model/小炒机/StirFryGoodsEvent.cs b/BPASmartClient.Model/小炒机/StirFryGoodsEvent.cs new file mode 100644 index 00000000..cfabd6df --- /dev/null +++ b/BPASmartClient.Model/小炒机/StirFryGoodsEvent.cs @@ -0,0 +1,18 @@ +using BPA.Message; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.Model.小炒机 +{ + public class StirFryGoodsEvent : BaseEvent + { + + /// + /// 小炒信息 + /// + public StirFryPushMessage stirFrymessage { get; set; } = new StirFryPushMessage(); + } +} diff --git a/BPASmartClient.MorkF/BPASmartClient.MorkF.csproj b/BPASmartClient.MorkF/BPASmartClient.MorkF.csproj index 79c30eda..9e968e28 100644 --- a/BPASmartClient.MorkF/BPASmartClient.MorkF.csproj +++ b/BPASmartClient.MorkF/BPASmartClient.MorkF.csproj @@ -18,8 +18,4 @@ - - - - diff --git a/BPASmartClient.MorkF/Control_MorkF.cs b/BPASmartClient.MorkF/Control_MorkF.cs index 936678a5..7b50e106 100644 --- a/BPASmartClient.MorkF/Control_MorkF.cs +++ b/BPASmartClient.MorkF/Control_MorkF.cs @@ -8,18 +8,19 @@ using BPASmartClient.Model; using BPASmartClient.Model.PLC; using BPA.Models; using static BPASmartClient.EventBus.EventBus; - +using BPASmartClient.Model.小炒机; +using BPASmartClient.MorkF.Model; namespace BPASmartClient.MorkF { public class Control_MorkF : BaseDevice { - public override DeviceClientType DeviceType => DeviceClientType.MORKSF; + public override DeviceClientType DeviceType => DeviceClientType.MORKCS; public AutoResetEvent minorReset = new AutoResetEvent(false); public AutoResetEvent mainReset = new AutoResetEvent(false); GVL_MorkF morkF = new GVL_MorkF();//全局对象声明 public StirFryBom stirFryBom = new StirFryBom();//创建获取流程的对象 - StirFryGoods stirFryGoods = new StirFryGoods();//创建商品对象 + List stirFryGoods = new List();//创建商品对象 List resultorder = new List();//调试变量 /// /// 入口 @@ -321,9 +322,9 @@ namespace BPASmartClient.MorkF { //队列 string subId = Guid.NewGuid().ToString(); - morkF.TakeMaterialQueue.Enqueue(new OrderLocInfo() { SuborderId = subId, MaterialLoc = 1 });//A料 - morkF.TakeMaterialQueue.Enqueue(new OrderLocInfo() { SuborderId = subId, MaterialLoc = 2 });//B料 - morkF.TakeMaterialQueue.Enqueue(new OrderLocInfo() { SuborderId = subId, MaterialLoc = 3 });//C料 + morkF.TakeMaterialQueue.Enqueue(new OrderLocInfo() { SuborderId = subId, MaterialLoc = new List() { 1 } });//A料 + morkF.TakeMaterialQueue.Enqueue(new OrderLocInfo() { SuborderId = subId, MaterialLoc = new List() { 2 } });//B料 + morkF.TakeMaterialQueue.Enqueue(new OrderLocInfo() { SuborderId = subId, MaterialLoc = new List() { 3 } });//C料 morkF.TakePlateQueue.Enqueue(new OrderLocInfo() { SuborderId = subId }); resultorder.AddRange(new int[] { 1, 2, 3 }); morkF.listStirBom.Add(stirFryBom); @@ -388,6 +389,7 @@ namespace BPASmartClient.MorkF if (@event is MaterialDeliveryEvent material) { orderMaterialDelivery = material.orderMaterialDelivery; + } }); @@ -401,6 +403,130 @@ namespace BPASmartClient.MorkF WriteRecipeBoms(); } }); + //小炒流程信息 + EventBus.EventBus.GetInstance().Subscribe(DeviceId, delegate (IEvent @event, EventCallBackHandle callback) + { + if (@event == null) return; + if (@event is StirFryGoodsEvent stirFry) + { + stirFryGoods = stirFry.stirFrymessage.stirFryGoods; + MessageLog.GetInstance.Show("接收到小炒流程信息"); + //流程解析 + foreach (var item in stirFryGoods) + { + MessageLog.GetInstance.ShowEx($"执行菜谱{item.GoodsKey}"); + // morkF.listStirBom.Add(item.StirFryBomInfo);//添加订单制作流程 + foreach (var items in item.StirFryBomInfo.StirFryActions) + { + MessageLog.GetInstance.Show($"执行流程{items.Time}"); + foreach (var pro in items.RobotActions) + { + switch (pro) + { + case StirFryRobotAction.等待: + MessageLog.GetInstance.Show($"等待"); + break; + case StirFryRobotAction.清洗槽取锅: + MessageLog.GetInstance.Show($"清洗槽取锅"); + break; + case StirFryRobotAction.灶放锅: + MessageLog.GetInstance.Show($"灶放锅"); + break; + case StirFryRobotAction.清洗槽放锅: + MessageLog.GetInstance.Show($"清洗槽放锅"); + break; + case StirFryRobotAction.取A料: + MessageLog.GetInstance.Show($"取A料"); + break; + case StirFryRobotAction.取B料: + MessageLog.GetInstance.Show($"取B料"); + break; + case StirFryRobotAction.取C料: + MessageLog.GetInstance.Show($"取C料"); + break; + case StirFryRobotAction.加入A料: + MessageLog.GetInstance.Show($"加入A料"); + break; + case StirFryRobotAction.加入B料: + MessageLog.GetInstance.Show($"加入B料"); + break; + case StirFryRobotAction.加入C料: + MessageLog.GetInstance.Show($"加入C料"); + break; + case StirFryRobotAction.切换快速: + MessageLog.GetInstance.Show($"切换快速"); + break; + case StirFryRobotAction.切换中速: + MessageLog.GetInstance.Show($"切换中速"); + break; + case StirFryRobotAction.丢料盒: + MessageLog.GetInstance.Show($"丢料盒"); + break; + case StirFryRobotAction.倒菜: + MessageLog.GetInstance.Show($"倒菜"); + break; + case StirFryRobotAction.灶取锅: + MessageLog.GetInstance.Show($"灶取锅"); + break; + } + } + foreach (var pro in items.PotActions) + { + switch (pro) + { + case StirFryPotAction.NONE: + break; + case StirFryPotAction.加热: + MessageLog.GetInstance.Show($"加热"); + break; + case StirFryPotAction.大火t1s: + MessageLog.GetInstance.Show($"大火1s"); + break; + case StirFryPotAction.加油: + MessageLog.GetInstance.Show($"加油"); + break; + case StirFryPotAction.中火t2s: + MessageLog.GetInstance.Show($"中火2s"); + break; + case StirFryPotAction.小火持续: + MessageLog.GetInstance.Show($"小火持续"); + break; + case StirFryPotAction.中火持续: + MessageLog.GetInstance.Show($"中火持续"); + break; + case StirFryPotAction.大火持续: + MessageLog.GetInstance.Show($"大火持续"); + break; + case StirFryPotAction.停止火力: + MessageLog.GetInstance.Show($"停止火力"); + break; + case StirFryPotAction.搅拌臂上位: + MessageLog.GetInstance.Show($"搅拌臂上位"); + break; + case StirFryPotAction.搅拌臂中位: + MessageLog.GetInstance.Show($"搅拌臂中位"); + break; + case StirFryPotAction.搅拌臂下位: + MessageLog.GetInstance.Show($"搅拌臂下位"); + break; + case StirFryPotAction.低速旋转: + MessageLog.GetInstance.Show($"低速旋转"); + break; + case StirFryPotAction.快速旋转: + MessageLog.GetInstance.Show($"快速旋转"); + break; + case StirFryPotAction.停止旋转: + MessageLog.GetInstance.Show($"停止旋转"); + break; + } + } + } + } + + } + + }); + } private void OrderChange(string subid, ORDER_STATUS oRDER_STATUS) @@ -423,41 +549,34 @@ namespace BPASmartClient.MorkF if (order.MorkOrder.GoodBatchings == null) return; OrderCount++; DeviceProcessLogShow($"接收到{OrderCount}次订单"); - foreach (var item in order.MorkOrder.GoodBatchings) + + var res = stirFryGoods?.FirstOrDefault(p => p.GoodsKey == order.MorkOrder.RecipeId);//匹配订单对应制作流程 + if (res != null) { - var res = orderMaterialDelivery?.BatchingInfo?.FirstOrDefault(p => p.BatchingId == item.BatchingId); - if (res != null) + morkF.listStirBom.Add(res.StirFryBomInfo);//添加订单制作流程 + if (morkF.TakeMaterialQueue.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null) { - if (ushort.TryParse(res.BatchingLoc, out ushort loc)) - { - - //if (morkF.TakeMaterialQueue.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null) - //将一个商品的ABC料位置存入队列 - morkF.TakeMaterialQueue.Enqueue(new OrderLocInfo() { SuborderId = order.MorkOrder.SuborderId, BatchingId = res.BatchingId, MaterialLoc = ushort.Parse(res.BatchingLoc) }); - } - + morkF.TakeMaterialQueue.Enqueue(new OrderLocInfo() { SuborderId = order.MorkOrder.SuborderId, MaterialLoc = res.StirFryBomInfo.ALoc }); + morkF.TakeMaterialQueue.Enqueue(new OrderLocInfo() { SuborderId = order.MorkOrder.SuborderId, MaterialLoc = res.StirFryBomInfo.BLoc }); + morkF.TakeMaterialQueue.Enqueue(new OrderLocInfo() { SuborderId = order.MorkOrder.SuborderId, MaterialLoc = res.StirFryBomInfo.CLoc }); + } - //int index = 0; - //if (recipeBoms != null) - //{ - // index = Array.FindIndex(recipeBoms.RecipeIds?.ToArray(), p => p.RecipeId == order.MorkOrder.RecipeId); - // index++; - //} - if (morkF.TakePlateQueue.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null) - morkF.TakePlateQueue.Enqueue(new OrderLocInfo() - { - SuborderId = order.MorkOrder.SuborderId, - BatchingId = res.BatchingId - //RecipeNumber = (index >= 1 && index <= 10) ? (ushort)index : (ushort)0 - }); + //foreach (var item in order.MorkOrder.GoodBatchings) + //{ + if (morkF.TakePlateQueue.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null) + { + morkF.TakePlateQueue.Enqueue(new OrderLocInfo() + { + SuborderId = order.MorkOrder.SuborderId, + }); } + //} } - //根据ID 查找对应制作流程, - } + }); } //} @@ -572,7 +691,7 @@ namespace BPASmartClient.MorkF if (morkF.MainProcessWait) { if (morkF.MinorHasTakeMaterial) - { + { } else { @@ -582,7 +701,7 @@ namespace BPASmartClient.MorkF //阻塞辅流程 minorReset.WaitOne(); } - + } morkF.MinorProessStatus = true; morkF.MainProcessStatus = false; @@ -624,13 +743,13 @@ namespace BPASmartClient.MorkF case StirFryRobotAction.清洗槽取锅: TakePotTask();//执行取锅操作 break; - case StirFryRobotAction.加入A料: + case StirFryRobotAction.取A料: TakeBurdenATask();//执行取A料操作 break; - case StirFryRobotAction.加入B料: + case StirFryRobotAction.取B料: TakeBurdenATask();//执行取B料操作 break; - case StirFryRobotAction.加入C料: + case StirFryRobotAction.取C料: TakeBurdenCTask();//执行取C料操作 break; case StirFryRobotAction.灶取锅: @@ -708,7 +827,7 @@ namespace BPASmartClient.MorkF //阻塞主流程 mainReset.WaitOne(); } - + } morkF.MinorProessStatus = false; morkF.MainProcessStatus = true; @@ -771,27 +890,10 @@ namespace BPASmartClient.MorkF /// private void TurntableControl() { - //正常轮询 - //if (morkF.TakeMaterialQueue.Count > 0 && !morkF.TurnTableLock) - //{ - // var result = orderMaterialDelivery.BatchingInfo.Where(p => p.BatchingId == morkF.TakeMaterialQueue.ElementAt(0).BatchingId).ToList(); - - // if (result != null) - // { - // if (ushort.TryParse(result[0].BatchingLoc, out ushort loc)) - // { - // TurnMaterialStore(loc); - // DeviceProcessLogShow($"转台转到【{loc}】位置"); - // morkF.TurnTableLock = true; //取料完成后置false - // } - // } - // elseDeviceProcessLogShow("未找到可用的物料信息"); - //} - - //调试代码 - if (morkF.TakeMaterialQueue.Count > 0 && !morkF.TurnTableLock) + //模拟订单 + if (morkF.TakeMaterialQueue.Count > 0 && !morkF.TurnTableLock && General_Config.SimOrderAllow) { - // var result = orderMaterialDelivery.BatchingInfo.Where(p => p.BatchingId == morkF.TakeMaterialQueue.ElementAt(0).BatchingId).ToList(); + if (resultorder != null) { @@ -807,6 +909,25 @@ namespace BPASmartClient.MorkF } } + //正式订单 + if (morkF.TakeMaterialQueue.Count > 0 && !morkF.TurnTableLock) + { + //var result = orderMaterialDelivery.BatchingInfo.Where(p => p.BatchingId == morkF.TakeMaterialQueue.ElementAt(0).BatchingId).ToList(); + var materialLoc = morkF.TakeMaterialQueue.ElementAt(0).MaterialLoc; + if (materialLoc.Count != 0) + { + TurnMaterialStore(materialLoc[0]); + DeviceProcessLogShow($"转台转到【{materialLoc[0]}】位置"); + morkF.TurnTableLock = true; //取料完成后置false + + } + else + { + DeviceProcessLogShow("未找到可用的物料信息"); + } + + } + } @@ -885,12 +1006,12 @@ namespace BPASmartClient.MorkF if (morkF.MainProcessStatus) { morkF.MainProcessPotLoc = morkF.CurrentPutPotLoc; - DeviceProcessLogShow($"订单【{ morkF.MainCurrentOrderId}】执行取锅到灶台控制"); + DeviceProcessLogShow($"订单【{morkF.MainCurrentOrderId}】执行取锅到灶台控制"); } if (morkF.MinorProessStatus) { morkF.MinorProcessPotLoc = morkF.CurrentPutPotLoc; - DeviceProcessLogShow($"订单【{ morkF.MinorCurrentOrderId}】执行取锅到灶台控制"); + DeviceProcessLogShow($"订单【{morkF.MinorCurrentOrderId}】执行取锅到灶台控制"); } if (morkF.CurrentPutPotLoc == 1) { @@ -983,11 +1104,11 @@ namespace BPASmartClient.MorkF } if (morkF.TakeMaterialQueue.TryDequeue(out OrderLocInfo order)) { - loc = order.MaterialLoc; - TakeBurden(loc); + loc = order.MaterialLoc[0]; + TakeBurden(); TurnReset(loc);//转台复位 - DeviceProcessLogShow($"订单【{ order.SuborderId}】,执行到转台{loc}位置取料"); + DeviceProcessLogShow($"订单【{order.SuborderId}】,执行到转台{loc}位置取料"); } //等待取料完成 while (!morkF.TakeMaterialComplete) @@ -1016,11 +1137,11 @@ namespace BPASmartClient.MorkF } if (morkF.TakeMaterialQueue.TryDequeue(out OrderLocInfo order)) { - loc = order.MaterialLoc; - TakeBurden(loc); + loc = order.MaterialLoc[0]; + TakeBurden(); TurnReset(loc);//转台复位 - DeviceProcessLogShow($"订单【{ order.SuborderId}】,执行到转台{loc}位置取料"); + DeviceProcessLogShow($"订单【{order.SuborderId}】,执行到转台{loc}位置取料"); } //等待取料完成 while (!morkF.TakeMaterialComplete) @@ -1064,11 +1185,11 @@ namespace BPASmartClient.MorkF } if (morkF.TakeMaterialQueue.TryDequeue(out OrderLocInfo order)) { - loc = order.MaterialLoc; - TakeBurden(loc); + loc = order.MaterialLoc[0]; + TakeBurden(); TurnReset(loc);//转台复位 - DeviceProcessLogShow($"订单【{ order.SuborderId}】,执行到转台{loc}位置取料"); + DeviceProcessLogShow($"订单【{order.SuborderId}】,执行到转台{loc}位置取料"); } //等待取料完成 while (!morkF.TakeMaterialComplete) @@ -1097,11 +1218,11 @@ namespace BPASmartClient.MorkF } if (morkF.TakeMaterialQueue.TryDequeue(out OrderLocInfo order)) { - loc = order.MaterialLoc; - TakeBurden(loc); + loc = order.MaterialLoc[0]; + TakeBurden(); TurnReset(loc);//转台复位 - DeviceProcessLogShow($"订单【{ order.SuborderId}】,执行到转台{loc}位置取料"); + DeviceProcessLogShow($"订单【{order.SuborderId}】,执行到转台{loc}位置取料"); } //等待取料完成 while (!morkF.TakeMaterialComplete) @@ -1174,11 +1295,11 @@ namespace BPASmartClient.MorkF } if (morkF.TakeMaterialQueue.TryDequeue(out OrderLocInfo order)) { - loc = order.MaterialLoc; - TakeBurden(loc); + loc = order.MaterialLoc[0]; + TakeBurden(); TurnReset(loc);//转台复位 - DeviceProcessLogShow($"订单【{ order.SuborderId}】,执行到转台{loc}位置取料"); + DeviceProcessLogShow($"订单【{order.SuborderId}】,执行到转台{loc}位置取料"); } //等待取料完成 while (!morkF.TakeMaterialComplete) @@ -1207,11 +1328,11 @@ namespace BPASmartClient.MorkF } if (morkF.TakeMaterialQueue.TryDequeue(out OrderLocInfo order)) { - loc = order.MaterialLoc; - TakeBurden(loc); + loc = order.MaterialLoc[0]; + TakeBurden(); TurnReset(loc);//转台复位 - DeviceProcessLogShow($"订单【{ order.SuborderId}】,执行到转台{loc}位置取料"); + DeviceProcessLogShow($"订单【{order.SuborderId}】,执行到转台{loc}位置取料"); } //等待取料完成 while (!morkF.TakeMaterialComplete) @@ -1245,9 +1366,9 @@ namespace BPASmartClient.MorkF RobotOutMeal(); WriteData("M1.2", false);//供盘复位 if (morkF.MainProcessStatus) - DeviceProcessLogShow($"订单【{ morkF.MainCurrentOrderId}】执行取锅到清洗台控制"); + DeviceProcessLogShow($"订单【{morkF.MainCurrentOrderId}】执行取锅到清洗台控制"); if (morkF.MinorProessStatus) - DeviceProcessLogShow($"订单【{ morkF.MinorCurrentOrderId}】执行取锅到清洗台控制"); + DeviceProcessLogShow($"订单【{morkF.MinorCurrentOrderId}】执行取锅到清洗台控制"); } @@ -1271,7 +1392,7 @@ namespace BPASmartClient.MorkF { CleanModuleControl("Start", 2); } - DeviceProcessLogShow($"订单【{ morkF.MainCurrentOrderId}】执行清洗操作"); + DeviceProcessLogShow($"订单【{morkF.MainCurrentOrderId}】执行清洗操作"); morkF.MainProcessFlag = false; minorReset.Set(); } @@ -1286,7 +1407,7 @@ namespace BPASmartClient.MorkF { CleanModuleControl("Start", 2); } - DeviceProcessLogShow($"订单【{ morkF.MinorCurrentOrderId}】执行清洗操作"); + DeviceProcessLogShow($"订单【{morkF.MinorCurrentOrderId}】执行清洗操作"); morkF.MinorProcessFlag = false; mainReset.Set(); } @@ -1325,9 +1446,9 @@ namespace BPASmartClient.MorkF /// public void TurnDownStatusDetect() { - int potLoc= TurnMachineOrientControl("Down"); + int potLoc = TurnMachineOrientControl("Down"); - if (potLoc==1) + if (potLoc == 1) { while (!morkF.TurnMachineDownComplete)//等待翻转机下降完成 { @@ -1335,7 +1456,7 @@ namespace BPASmartClient.MorkF } WriteData("M8.3", false);//下降完成复位 } - if (potLoc==2) + if (potLoc == 2) { while (!morkF.SecondTurnMachineDownComplete)//等待翻转机下降完成 { @@ -1354,7 +1475,7 @@ namespace BPASmartClient.MorkF //} } - + /// /// 翻转机上升及状态检测 /// @@ -1367,7 +1488,7 @@ namespace BPASmartClient.MorkF TurnMachineOrientControl("Top");//翻转机上升 if (morkF.MainProcessStatus) { - if (morkF.MainProcessPotLoc==1) + if (morkF.MainProcessPotLoc == 1) { while (!morkF.TurnMachineUpComplete)//等待翻转机上升完成以及取料完成 { @@ -1392,14 +1513,14 @@ namespace BPASmartClient.MorkF } morkF.MainOrderMaterialCom = true; morkF.MainHasTakeMaterial = false; - DeviceProcessLogShow($"订单【{ morkF.MainCurrentOrderId}】,配料倒料完成"); + DeviceProcessLogShow($"订单【{morkF.MainCurrentOrderId}】,配料倒料完成"); } else //辅程准备阻塞 { morkF.MainProcessWait = true; } } - if (morkF.MainProcessPotLoc==2) + if (morkF.MainProcessPotLoc == 2) { while (!morkF.SecondTurnMachineUpComplete)//等待翻转机上升完成以及取料完成 { @@ -1424,12 +1545,12 @@ namespace BPASmartClient.MorkF } morkF.MainOrderMaterialCom = true; morkF.MainHasTakeMaterial = false; - DeviceProcessLogShow($"订单【{ morkF.MinorCurrentOrderId}】,配料倒料完成"); + DeviceProcessLogShow($"订单【{morkF.MinorCurrentOrderId}】,配料倒料完成"); } else //辅流程准备阻塞 { morkF.MainProcessWait = true; - } + } } } if (morkF.MinorProessStatus) @@ -1459,14 +1580,14 @@ namespace BPASmartClient.MorkF } morkF.MinorOrderMaterialCom = true; morkF.MinorHasTakeMaterial = false; - DeviceProcessLogShow($"订单【{ morkF.MainCurrentOrderId}】,配料倒料完成"); + DeviceProcessLogShow($"订单【{morkF.MainCurrentOrderId}】,配料倒料完成"); } else //主程准备阻塞 { morkF.MinorProcessWait = true; } } - if (morkF.MinorProcessPotLoc==2) + if (morkF.MinorProcessPotLoc == 2) { while (!morkF.SecondTurnMachineUpComplete)//等待翻转机上升完成以及取料完成 { @@ -1491,12 +1612,12 @@ namespace BPASmartClient.MorkF } morkF.MinorOrderMaterialCom = true; morkF.MinorHasTakeMaterial = false; - DeviceProcessLogShow($"订单【{ morkF.MinorCurrentOrderId}】,配料倒料完成"); + DeviceProcessLogShow($"订单【{morkF.MinorCurrentOrderId}】,配料倒料完成"); } else //主流程准备阻塞 { morkF.MinorProcessWait = true; - } + } } } //if (morkF.MainProcessStatus)//代表主流程执行的操作 @@ -1702,7 +1823,7 @@ namespace BPASmartClient.MorkF } FirstPotGears(number); } - if (morkF.MinorProcessPotLoc==2) + if (morkF.MinorProcessPotLoc == 2) { while (!morkF.SecondPotInPlace) { @@ -1712,9 +1833,9 @@ namespace BPASmartClient.MorkF } } if (morkF.MainProcessStatus) - DeviceProcessLogShow($"订单【{ morkF.MainCurrentOrderId}】执行取锅到灶台控制"); + DeviceProcessLogShow($"订单【{morkF.MainCurrentOrderId}】执行取锅到灶台控制"); if (morkF.MinorProessStatus) - DeviceProcessLogShow($"订单【{ morkF.MinorCurrentOrderId}】执行取锅到灶台控制"); + DeviceProcessLogShow($"订单【{morkF.MinorCurrentOrderId}】执行取锅到灶台控制"); } /// /// PLC转台控制 @@ -1818,7 +1939,7 @@ namespace BPASmartClient.MorkF Task.Delay(5).Wait(); } } - if (morkF.MainProcessPotLoc==2) + if (morkF.MainProcessPotLoc == 2) { while (!morkF.SecondPotInPlace) { @@ -1832,7 +1953,7 @@ namespace BPASmartClient.MorkF Task.Delay(5).Wait(); } } - + } if (morkF.MinorProessStatus) { @@ -1876,8 +1997,8 @@ namespace BPASmartClient.MorkF { switch (orientation) { - case "Top": WriteData("M8.0", true); break; - case "Down": WriteData("M8.2", true); break; + case "Top": WriteData("M8.0", true); break; + case "Down": WriteData("M8.2", true); break; } } public void SecondPotTurnMachine(string orientation) @@ -1895,7 +2016,7 @@ namespace BPASmartClient.MorkF /// public int TurnMachineOrientControl(string orientation) { - int potLoc=0; ; + int potLoc = 0; ; //switch (orientation) //{ // case "Top": if (morkF.MainProcessStatus) WriteData("M8.0", true); if (morkF.MinorProessStatus) WriteData("M8.4", true); break; @@ -1911,7 +2032,7 @@ namespace BPASmartClient.MorkF if (morkF.MainProcessPotLoc == 2) { SecondPotTurnMachine(orientation); - potLoc=2; + potLoc = 2; } } if (morkF.MinorProessStatus) @@ -1971,7 +2092,7 @@ namespace BPASmartClient.MorkF //} if (morkF.MainProcessStatus) { - if (morkF.MainProcessPotLoc==1) + if (morkF.MainProcessPotLoc == 1) { FirstPotTurnMachine(gear); } @@ -1982,7 +2103,7 @@ namespace BPASmartClient.MorkF } if (morkF.MinorProessStatus) { - if (morkF.MinorProcessPotLoc==1) + if (morkF.MinorProcessPotLoc == 1) { FirstPotTurnMachine(gear); } @@ -1996,7 +2117,7 @@ namespace BPASmartClient.MorkF /// /// 取A,B,C料 /// - public void TakeBurden(int loc) + public void TakeBurden() { if (morkF.MainProcessStatus && morkF.PotInPlace) WriteData("M14.1", true);//机器人倒料至1号锅 diff --git a/BPASmartClient.MorkF/GVL_MorkF.cs b/BPASmartClient.MorkF/GVL_MorkF.cs index a74c25d0..f9229946 100644 --- a/BPASmartClient.MorkF/GVL_MorkF.cs +++ b/BPASmartClient.MorkF/GVL_MorkF.cs @@ -10,6 +10,7 @@ namespace BPASmartClient.MorkF { internal class GVL_MorkF { + /// /// 初始化完成状态 /// diff --git a/BPASmartClient.MorkF/Model/General_Config.cs b/BPASmartClient.MorkF/Model/General_Config.cs new file mode 100644 index 00000000..39e2eb74 --- /dev/null +++ b/BPASmartClient.MorkF/Model/General_Config.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPASmartClient.MorkF.Model +{ + internal class General_Config + { + public static bool SimOrderAllow { get; set; } + } +} diff --git a/BPASmartClient.MorkF/OrderLocInfo.cs b/BPASmartClient.MorkF/OrderLocInfo.cs index d39a8a4e..4d171aa3 100644 --- a/BPASmartClient.MorkF/OrderLocInfo.cs +++ b/BPASmartClient.MorkF/OrderLocInfo.cs @@ -9,7 +9,7 @@ namespace BPASmartClient.MorkF internal class OrderLocInfo { public string SuborderId { get; set; } - public ushort MaterialLoc { get; set; }//物料位置 + public List MaterialLoc { get; set; } = new List();//物料A位置 public ushort RecipeNumber { get; set; } public int BatchingId { get; set; } } diff --git a/BPASmartClient.MorkF/View/DebugView.xaml b/BPASmartClient.MorkF/View/DebugView.xaml index 5ec519b6..9bac5ef9 100644 --- a/BPASmartClient.MorkF/View/DebugView.xaml +++ b/BPASmartClient.MorkF/View/DebugView.xaml @@ -36,6 +36,7 @@ + diff --git a/BPASmartClient.MorkF/View/DebugView.xaml.cs b/BPASmartClient.MorkF/View/DebugView.xaml.cs index 2812751f..397537de 100644 --- a/BPASmartClient.MorkF/View/DebugView.xaml.cs +++ b/BPASmartClient.MorkF/View/DebugView.xaml.cs @@ -25,6 +25,7 @@ namespace BPASmartClient.MorkF.View { InitializeComponent(); this.DataContext = new DebugViewModel(); + } } } diff --git a/BPASmartClient.MorkF/ViewModel/DebugViewModel.cs b/BPASmartClient.MorkF/ViewModel/DebugViewModel.cs index d7bf15cf..3ddf16ab 100644 --- a/BPASmartClient.MorkF/ViewModel/DebugViewModel.cs +++ b/BPASmartClient.MorkF/ViewModel/DebugViewModel.cs @@ -1,4 +1,5 @@ using BPASmartClient.Helper; +using BPASmartClient.MorkF.Model; using Microsoft.Toolkit.Mvvm.ComponentModel; using Microsoft.Toolkit.Mvvm.Input; using System; @@ -11,6 +12,7 @@ namespace BPASmartClient.MorkF.ViewModel { internal class DebugViewModel : ObservableObject { + public bool SimOrderEnable { get { return General_Config.SimOrderAllow; } set { General_Config.SimOrderAllow = value; OnPropertyChanged(); } } public RelayCommand PlcInite { get; set; } public RelayCommand SimulateOrder { get; set; } @@ -64,7 +66,8 @@ namespace BPASmartClient.MorkF.ViewModel public DebugViewModel() { PlcInite = new RelayCommand(() => { ActionManage.GetInstance.Send("InitCommand"); }); - SimulateOrder = new RelayCommand(() => { ActionManage.GetInstance.Send("SimultaorOrder"); }); + + SimulateOrder = new RelayCommand(() => {ActionManage.GetInstance.Send("SimultaorOrder"); }); MaterialOne= new RelayCommand(() => { ActionManage.GetInstance.Send("MaterialOne"); }); MaterialTwo = new RelayCommand(() => { ActionManage.GetInstance.Send("MaterialTwo"); }); MaterialThree = new RelayCommand(() => { ActionManage.GetInstance.Send("MaterialThree"); }); diff --git a/BPASmartClient.MorkM/Control_MORKM.cs b/BPASmartClient.MorkM/Control_MORKM.cs index 73ad82f5..89a9b841 100644 --- a/BPASmartClient.MorkM/Control_MORKM.cs +++ b/BPASmartClient.MorkM/Control_MORKM.cs @@ -15,6 +15,7 @@ using BPASmartClient.MorkM.Model; using System.Collections.ObjectModel; using BPASmartClient.Model.PLC; using BPASmartClient.MorkM.ViewModel; +using BPA.Message; namespace BPASmartClient.MorkM { @@ -800,6 +801,7 @@ namespace BPASmartClient.MorkM } }); + //配方数据信息 EventBus.EventBus.GetInstance().Subscribe(DeviceId, delegate (IEvent @event, EventCallBackHandle callBack) { @@ -811,7 +813,7 @@ namespace BPASmartClient.MorkM } }); } - + public override void DoMain() { MonitorViewModel.DeviceId = DeviceId; diff --git a/BPASmartClient.MorkS/Control_Morks.cs b/BPASmartClient.MorkS/Control_Morks.cs index 0e080003..e190d06d 100644 --- a/BPASmartClient.MorkS/Control_Morks.cs +++ b/BPASmartClient.MorkS/Control_Morks.cs @@ -18,6 +18,8 @@ using BPASmartClient.MorkS.Model; using System.Collections.ObjectModel; using BPASmartClient.MorkS.ViewModel; using BPASmartClient.Business; +using BPASmartClient.Model.小炒机; +using BPA.Models; namespace BPASmartClient.MorkS { @@ -113,8 +115,10 @@ namespace BPASmartClient.MorkS WriteRecipeBoms(); } }); + + } - + private void OrderChange(string subid, ORDER_STATUS oRDER_STATUS) { var res = mORKS.doOrderEvents.FirstOrDefault(p => p.MorkOrder.SuborderId == subid); diff --git a/BPASmartClient.MorkS/ViewModel/DebugViewModel.cs b/BPASmartClient.MorkS/ViewModel/DebugViewModel.cs index 05065bce..664bd3cf 100644 --- a/BPASmartClient.MorkS/ViewModel/DebugViewModel.cs +++ b/BPASmartClient.MorkS/ViewModel/DebugViewModel.cs @@ -8,6 +8,7 @@ using BPASmartClient.Model; using Microsoft.Toolkit.Mvvm.ComponentModel; using Microsoft.Toolkit.Mvvm.Input; using BPASmartClient.EventBus; +using BPASmartClient.MorkS.Model; namespace BPASmartClient.MorkS.ViewModel { diff --git a/BPASmartClient/App.config b/BPASmartClient/App.config index 4e21d83c..fc532a83 100644 --- a/BPASmartClient/App.config +++ b/BPASmartClient/App.config @@ -7,14 +7,14 @@ - + - + diff --git a/BPASmartClient/Control/GYLCControl.xaml b/BPASmartClient/Control/GYLCControl.xaml new file mode 100644 index 00000000..0e415989 --- /dev/null +++ b/BPASmartClient/Control/GYLCControl.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + diff --git a/BPASmartClient/Control/GYLCControl.xaml.cs b/BPASmartClient/Control/GYLCControl.xaml.cs new file mode 100644 index 00000000..cbe4884a --- /dev/null +++ b/BPASmartClient/Control/GYLCControl.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace BPASmartClient.Control +{ + /// + /// GYLCControl.xaml 的交互逻辑 + /// + public partial class GYLCControl : UserControl + { + public GYLCControl() + { + InitializeComponent(); + } + } +} diff --git a/BPASmartClient/MainWindow.xaml b/BPASmartClient/MainWindow.xaml index f78ced08..5a7f237d 100644 --- a/BPASmartClient/MainWindow.xaml +++ b/BPASmartClient/MainWindow.xaml @@ -116,7 +116,7 @@ @@ -152,6 +152,12 @@ Header="IOT监视" Tag="IOTView" /> + + + diff --git a/DosingSystem/DosingSystem.csproj b/DosingSystem/DosingSystem.csproj index 7dff77c7..ea23d1a5 100644 --- a/DosingSystem/DosingSystem.csproj +++ b/DosingSystem/DosingSystem.csproj @@ -14,7 +14,7 @@ - + diff --git a/DosingSystem/Model/DeviceInquire.cs b/DosingSystem/Model/DeviceInquire.cs index f1c0671d..1033f8ce 100644 --- a/DosingSystem/Model/DeviceInquire.cs +++ b/DosingSystem/Model/DeviceInquire.cs @@ -1,9 +1,11 @@ using BPASmartClient.Helper; +using BPASmartClient.Message; using BPASmartClient.Modbus; using DosingSystem.ViewModel; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Net.NetworkInformation; using System.Text; @@ -14,54 +16,68 @@ namespace DosingSystem.Model { public class DeviceInquire { - private volatile static DeviceInquire _Instance; public static DeviceInquire GetInstance => _Instance ?? (_Instance = new DeviceInquire()); private DeviceInquire() { } string IPSegment = "192.168.1."; - string NameAddress = "VW5000"; - int count = 0; - private static readonly object _lock = new object(); - ConcurrentDictionary modbusTcps = new ConcurrentDictionary(); - List InvalidIP = new List(); + string NameAddress = "VW0"; + + ConcurrentDictionary DeviceLists = new ConcurrentDictionary(); + List InvalidIP = new List();//无效 IP 集合 + List IPLists = new List();//启动 Ping 任务IP集合 + ConcurrentQueue IPQueues = new ConcurrentQueue();//pincomplete 完成队列 public void Init() { IpAddressLines(); ThreadManage.GetInstance().StartLong(new Action(() => { - if (count >= 255) IpAddressLines(); + if (IPQueues.Count >= IPLists.Count) + IpAddressLines(); Thread.Sleep(5000); }), "配料机设备上线监听", true); } - public ModbusTcp GetModbusTcp(string ip) + public DeviceStatus GetDevice(string ip) { - if (modbusTcps.ContainsKey(ip)) return modbusTcps[ip]; - else return default; + if (ip != null) + { + var res = DeviceLists.Values.FirstOrDefault(p => p.IpAddress == ip); + if (res != null) return res; + } + return new DeviceStatus(); } private void IpAddressLines() { + //for (int i = 1; i <= 255; i++) + //{ + // if (!InvalidIP.Contains($"{IPSegment}{i}")) + // { + // Ping myPing = new Ping(); + // myPing.PingCompleted += new PingCompletedEventHandler(_myPing_PingCompleted); + // string pingIP = $"{IPSegment}{i}"; + // myPing.SendAsync(pingIP, 1000, null); + // } + //} + //count = 0; + + IPLists.Clear(); + IPQueues.Clear(); for (int i = 1; i <= 255; i++) { if (!InvalidIP.Contains($"{IPSegment}{i}")) { - Ping myPing; - myPing = new Ping(); - myPing.PingCompleted += new PingCompletedEventHandler(_myPing_PingCompleted); - string pingIP = $"{IPSegment}{i}"; - myPing.SendAsync(pingIP, 1000, null); + IPLists.Add($"{IPSegment}{i}"); } } - count = 0; - } - - private void CompleteCount() - { - lock (_lock) - count++; + IPLists.ForEach((item) => + { + Ping myPing = new Ping(); + myPing.PingCompleted += new PingCompletedEventHandler(_myPing_PingCompleted); + myPing.SendAsync(item, 1000, null); + }); } private void _myPing_PingCompleted(object sender, PingCompletedEventArgs e) @@ -69,17 +85,20 @@ namespace DosingSystem.Model if (e.Reply.Status == IPStatus.Success) { string ip = e.Reply.Address.ToString(); - if (!modbusTcps.ContainsKey(ip)) + if (!DeviceLists.ContainsKey(ip)) { - modbusTcps.TryAdd(ip, new ModbusTcp()); - modbusTcps[ip].IsReconnect = false; - Task.Run(new Action(() => { modbusTcps[ip].ModbusTcpConnect(ip); })); + DeviceStatus DS = new DeviceStatus(); + DS.modbusTcp.IsReconnect = false; - modbusTcps[ip].ConnectOk = new Action(() => + Task.Run(new Action(() => { DS.modbusTcp.ModbusTcpConnect(ip, 508); })); + DS.modbusTcp.ConnectOk = new Action(() => { - string DeviceName = modbusTcps[ip].GetString(NameAddress, 10); + string DeviceName = DS.modbusTcp.GetString(NameAddress, 20); if (DeviceName.Length > 0) { + DeviceLists.TryAdd(ip, DS); + DeviceLists[ip].Init(DeviceName); + DeviceLists[ip].modbusTcp.IsReconnect = false; App.Current.Dispatcher.Invoke(new Action(() => { DeviceListViewModel.devices.Add(new Devices() @@ -87,6 +106,21 @@ namespace DosingSystem.Model DeviceName = DeviceName, IpAddress = ip }); + + for (int i = 0; i < Json.Data.Recipes.Count; i++) + { + for (int m = 0; m < Json.Data.Recipes.ElementAt(i).RawMaterials.Count; m++) + { + if (Json.Data.Recipes.ElementAt(i).RawMaterials.ElementAt(m).DeviceIp == ip) + { + Json.Data.Recipes.ElementAt(i).RawMaterials.ElementAt(m).RawMaterialName = DeviceName; + } + } + } + + if (!NewRecipeViewModel.RawMaterialNames.Contains(DeviceName)) + NewRecipeViewModel.RawMaterialNames.Add(DeviceName); + })); } else @@ -95,23 +129,90 @@ namespace DosingSystem.Model } }); - modbusTcps[ip].ConnectFail = new Action(() => + DS.modbusTcp.ConnectFail = new Action(() => { if (!InvalidIP.Contains(ip)) InvalidIP.Add(ip); + MessageLog.GetInstance.Show($"{ip}连接失败"); }); - modbusTcps[ip].Disconnect = new Action(() => + DS.modbusTcp.Disconnect = new Action(() => { if (InvalidIP.Contains(ip)) InvalidIP.Remove(ip); var res = DeviceListViewModel.devices.FirstOrDefault(P => P.IpAddress == ip); if (res != null && DeviceListViewModel.devices.Contains(res)) - App.Current.Dispatcher.Invoke(new Action(() => { DeviceListViewModel.devices.Remove(res); })); + App.Current.Dispatcher.Invoke(new Action(() => + { + DeviceListViewModel.devices.Remove(res); + if (!NewRecipeViewModel.RawMaterialNames.Contains(res.DeviceName)) + NewRecipeViewModel.RawMaterialNames.Remove(res.DeviceName); + })); + if (DeviceLists.ContainsKey(ip)) DeviceLists[ip].Dispose(); }); + } } - CompleteCount(); + IPQueues.Enqueue(e.Reply.Address.ToString()); + } + } + + public class DeviceStatus + { + + #region 对象属性声明 + public string DeviceName = String.Empty; + public string IpAddress => modbusTcp.IPAdress; + + /// + /// 设备状态 + /// + public RawMaterialDeviceStatus deviceStatus { get; set; } = new RawMaterialDeviceStatus(); + + public ModbusTcp modbusTcp = new ModbusTcp(); + + public bool IsConnected => modbusTcp.Connected; + #endregion + + public void Init(string DeviceName) + { + this.DeviceName = DeviceName; + if (modbusTcp.Connected) + { + ThreadManage.GetInstance().StartLong(new Action(() => + { + var res = this.modbusTcp.Read("VW100"); + if (res != null && res is ushort[] ushortValue) + { + if (ushortValue.Length >= 1) deviceStatus.RunStatus = ushortValue[0]; + } + Thread.Sleep(100); + }), $"{DeviceName} 开始监听", true); + } + } + + public void SetDeviceName(string name) + { + this.modbusTcp.Write("VW0", new ushort[20]); + this.modbusTcp.SetString("VW0", name); + } + + public void StatusReset() + { + this.modbusTcp.Write("VW100", (ushort)1); } + public void Dispose() + { + ThreadManage.GetInstance().StopTask($"{DeviceName} 开始监听"); + } + public void Start(float Value) + { + if (modbusTcp.Connected) + { + modbusTcp.SetReal("VW40", Value);//写入配方量 + modbusTcp.Write("M0.0", true);//设备启动写入 + } + } } + } diff --git a/DosingSystem/Model/LocaPar.cs b/DosingSystem/Model/LocaPar.cs new file mode 100644 index 00000000..ab3a8c56 --- /dev/null +++ b/DosingSystem/Model/LocaPar.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Collections.ObjectModel; +using DosingSystem.ViewModel; + +namespace DosingSystem.Model +{ + public class LocaPar + { + public ObservableCollection Recipes { get; set; } = new ObservableCollection(); + } +} diff --git a/DosingSystem/Model/RawMaterialDeviceStatus.cs b/DosingSystem/Model/RawMaterialDeviceStatus.cs new file mode 100644 index 00000000..820798b6 --- /dev/null +++ b/DosingSystem/Model/RawMaterialDeviceStatus.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DosingSystem.Model +{ + public class RawMaterialDeviceStatus + { + + /// + /// 原料类型 MW18 + /// 1:液体 + /// 2:膏体 + /// 3:粉体 + /// + public ushort RawMaterialType { get; set; } + + /// + /// 料仓重量反馈 MD40 + /// + public float WeightFeedback { get; set; } + + /// + /// 上限反馈 + /// + public bool UpLimitFeedback { get; set; } + + /// + /// 下限反馈 + /// + public bool DownLimitFeedback { get; set; } + + /// + /// 下料重量反馈 MD52 + /// + public float CutWeightFeedback { get; set; } + + /// + /// 设备运行状态 + /// + public ushort RunStatus { get; set; } + } +} diff --git a/DosingSystem/Model/RawMaterialModel.cs b/DosingSystem/Model/RawMaterialModel.cs new file mode 100644 index 00000000..3bad8fcb --- /dev/null +++ b/DosingSystem/Model/RawMaterialModel.cs @@ -0,0 +1,89 @@ +using Microsoft.Toolkit.Mvvm.ComponentModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DosingSystem.Model +{ + /// + /// 原料模块 + /// + public class RawMaterialModel : ObservableObject + { + /// + /// 原料名称 + /// + public string RawMaterialName { get { return _mRawMaterialName; } set { _mRawMaterialName = value; OnPropertyChanged(); } } + private string _mRawMaterialName; + + /// + /// 原料设备IP + /// + public string DeviceIp { get; set; } + + /// + /// 原料重量设置 + /// + public float RawMaterialWeight { get { return _mRawMaterialWeight; } set { _mRawMaterialWeight = value; OnPropertyChanged(); } } + private float _mRawMaterialWeight; + + /// + /// 原料类型 MW18 + /// 1:液体 + /// 2:膏体 + /// 3:粉体 + /// + [Newtonsoft.Json.JsonIgnore] + public ushort RawMaterialType { get { return _mRawMaterialType; } set { _mRawMaterialType = value; OnPropertyChanged(); } } + private ushort _mRawMaterialType; + + /// + /// 料仓重量反馈 MD40 + /// + [Newtonsoft.Json.JsonIgnore] + public float WeightFeedback { get { return _mWeightFeedback; } set { _mWeightFeedback = value; OnPropertyChanged(); } } + private float _mWeightFeedback; + + /// + /// 上限反馈 + /// + [Newtonsoft.Json.JsonIgnore] + public bool UpLimtFeedback { get { return _mUpLimtFeedback; } set { _mUpLimtFeedback = value; OnPropertyChanged(); } } + private bool _mUpLimtFeedback; + + /// + /// 下限反馈 + /// + [Newtonsoft.Json.JsonIgnore] + public bool DownLimtFeedback { get { return _mDownLimtFeedback; } set { _mDownLimtFeedback = value; OnPropertyChanged(); } } + private bool _mDownLimtFeedback; + + /// + /// 下料重量反馈 MD52 + /// + [Newtonsoft.Json.JsonIgnore] + public float UpLimtWeightFeedback { get { return _mUpLimtWeightFeedback; } set { _mUpLimtWeightFeedback = value; OnPropertyChanged(); } } + private float _mUpLimtWeightFeedback; + + + /// + /// 原料ID + /// + public string RawMaterialId { get { return _mRawMaterialId; } set { _mRawMaterialId = value; OnPropertyChanged(); } } + private string _mRawMaterialId; + + /// + /// 原料设备执行状态 + /// 1:准备就绪 + /// 2:等待接料 + /// 3:接料完成 + /// 4:设备异常 + /// + [Newtonsoft.Json.JsonIgnore] + public ushort RecipeStatus { get { return _mRecipeStatus; } set { _mRecipeStatus = value; OnPropertyChanged(); } } + private ushort _mRecipeStatus = 1; + + } +} diff --git a/DosingSystem/Model/RecipeModel.cs b/DosingSystem/Model/RecipeModel.cs new file mode 100644 index 00000000..58ca0f20 --- /dev/null +++ b/DosingSystem/Model/RecipeModel.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using DosingSystem.ViewModel; +using Microsoft.Toolkit.Mvvm.ComponentModel; + +namespace DosingSystem.Model +{ + /// + /// 配方模块 + /// + public class RecipeModel : ObservableObject + { + public bool IsEnable { get { return _mIsEnable; } set { _mIsEnable = value; OnPropertyChanged(); } } + private bool _mIsEnable = true; + + /// + /// 序号 + /// + public int SerialNum { get { return _mSerialNum; } set { _mSerialNum = value; OnPropertyChanged(); } } + private int _mSerialNum; + + /// + /// 配方名称 + /// + public string RecipeName { get { return _mRecipeName; } set { _mRecipeName = value; OnPropertyChanged(); } } + private string _mRecipeName; + + /// + /// 配方编码 + /// + public string RecipCode { get { return _mRecipCode; } set { _mRecipCode = value; OnPropertyChanged(); } } + private string _mRecipCode; + + [Newtonsoft.Json.JsonIgnore] + public AutoResetEvent Are { get; set; } = new AutoResetEvent(false); + + /// + /// 原料集合 + /// + public ObservableCollection RawMaterials { get; set; } = new ObservableCollection(); + + + + } +} diff --git a/DosingSystem/View/ChangeDeviceNameView.xaml b/DosingSystem/View/ChangeDeviceNameView.xaml new file mode 100644 index 00000000..0dea173e --- /dev/null +++ b/DosingSystem/View/ChangeDeviceNameView.xaml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +