diff --git a/BPASmartClient.JXJFoodSmallStation/App.xaml.cs b/BPASmartClient.JXJFoodSmallStation/App.xaml.cs index 249d610c..8348228b 100644 --- a/BPASmartClient.JXJFoodSmallStation/App.xaml.cs +++ b/BPASmartClient.JXJFoodSmallStation/App.xaml.cs @@ -37,7 +37,7 @@ namespace BPASmartClient.JXJFoodSmallStation } BPASmartClient.Helper.SystemHelper.GetInstance.CreateDesktopShortcut(); base.OnStartup(e); - + MenuInit(); DataInit(); Init(); @@ -53,7 +53,7 @@ namespace BPASmartClient.JXJFoodSmallStation mv.Close(); MainWindow = mv; } - private async void Init() + private async void Init() { await Task.Run(new Action(() => { @@ -153,7 +153,7 @@ namespace BPASmartClient.JXJFoodSmallStation AssemblyName = "BPASmartClient.JXJFoodSmallStation", ToggleWindowPath = "View.BomOfMaterialView" }); - + MenuManage.GetInstance.menuModels.Add(new MenuModel() { MainMenuIcon = "", @@ -187,7 +187,7 @@ namespace BPASmartClient.JXJFoodSmallStation AssemblyName = "BPASmartClient.JXJFoodSmallStation", ToggleWindowPath = "View.ManualFlowView" - }); + }); ManualControl.Add(new SubMenumodel() { SubMenuName = "机器人设备控制", diff --git a/BPASmartClient.JXJFoodSmallStation/Model/ProcessControl.cs b/BPASmartClient.JXJFoodSmallStation/Model/ProcessControl.cs index 6cfae563..08fbc907 100644 --- a/BPASmartClient.JXJFoodSmallStation/Model/ProcessControl.cs +++ b/BPASmartClient.JXJFoodSmallStation/Model/ProcessControl.cs @@ -90,7 +90,7 @@ namespace BPASmartClient.JXJFoodSmallStation.Model GVL_SmallStation.GetInstance.HeartBeatToPlc = !GVL_SmallStation.GetInstance.HeartBeatToPlc; HKDevice.HK_PLC_S7.Write("DB4.DBX0.0", GVL_SmallStation.GetInstance.HeartBeatToPlc); GVL_SmallStation.GetInstance.HeartBeatFromPlc = HKDevice.HK_PLC_S7.Read("DB45.DBX0.0"); - if (DeviceInquire.GetInstance.devices.Count < 15 && HKDevice.IsConnected && Json.Data.Recipes.Count > 0 && GVL_SmallStation.GetInstance.DisEnableStockBinAlarm == false && DateTime.Now.Subtract(StockBinAlarmTime).TotalSeconds >= 60 & !GVL_SmallStation.GetInstance.DisEnableStockAlarm) + if (DeviceInquire.GetInstance.devices.Count < 15 && HKDevice.IsConnected && Json.Data.Recipes.Count > 0 && GVL_SmallStation.GetInstance.DisEnableStockBinAlarm == false && DateTime.Now.Subtract(StockBinAlarmTime).TotalSeconds >= 60 & !GVL_SmallStation.GetInstance.DisEnableStockAlarm) { HKDevice.HK_PLC_S7.Write("DB44.DBX3.0", true); App.Current.Dispatcher.Invoke(() => @@ -268,7 +268,7 @@ namespace BPASmartClient.JXJFoodSmallStation.Model //GVL_SmallStation.GetInstance.Station2Cylinder = HKDevice.HK_PLC_S7.Read("DB3.DBX2.4"); //GVL_SmallStation.GetInstance.RobotStatus = HKDevice.HK_PLC_S7.Read("DB3.DBW100"); //GVL_SmallStation.GetInstance.RobotProgramNum = HKDevice.HK_PLC_S7.Read("DB3.DBB102"); - if (Json.Data.Recipes.Count <= 3) + if (Json.Data.Recipes.Count <= 3) { GVL_SmallStation.GetInstance.IsAllowSiemensSendRecipe = true; } @@ -312,11 +312,11 @@ namespace BPASmartClient.JXJFoodSmallStation.Model GVL_SmallStation.GetInstance.AGV_PutTray1Finish = false; } ushort AGV_Get = (ushort)SiemensDevice.XL_Status.AgvFinishGet; - if (AGV_Get.Get16bitValue(1)) + if (AGV_Get.Get16bitValue(1)) { - GVL_SmallStation.GetInstance.AGV_GetTray1Finish = true; + GVL_SmallStation.GetInstance.AGV_GetTray1Finish = true; } - else + else { GVL_SmallStation.GetInstance.AGV_GetTray1Finish = false; } @@ -331,12 +331,12 @@ namespace BPASmartClient.JXJFoodSmallStation.Model { string code = GVL_SmallStation.GetInstance.Order_CancelRecipeCode; int index = Array.FindIndex(Json.Data.Recipes.ToArray(), p => p.RecipeCode == code); - int[] cnt = new int[5] { -1,-1,-1,-1,-1}; + int[] cnt = new int[5] { -1, -1, -1, -1, -1 }; int index1 = -1; for (int i = 0; i < 5; i++) { - cnt[i]= Array.FindIndex(RecipeQueueTray[i].ToArray(), p => p == code); - if (cnt[i] >= 0) + cnt[i] = Array.FindIndex(RecipeQueueTray[i].ToArray(), p => p == code); + if (cnt[i] >= 0) { index1 = i; } @@ -351,7 +351,7 @@ namespace BPASmartClient.JXJFoodSmallStation.Model } else { - if (index1>=0) + if (index1 >= 0) { GVL_SmallStation.GetInstance.OrderCancelStep = 1; } @@ -378,9 +378,9 @@ namespace BPASmartClient.JXJFoodSmallStation.Model } break; case 2: - if (HKDevice.HK_PLC_S7.Read("DB3.DBX42."+index1)) + if (HKDevice.HK_PLC_S7.Read("DB3.DBX42." + index1)) { - if (GVL_SmallStation.GetInstance.Station1Cylinder == false) + if (GVL_SmallStation.GetInstance.Station1Cylinder == false) { GVL_SmallStation.GetInstance.OrderCancelStep = 3; MessageNotify.GetInstance.ShowRunLog($"PLC正在执行配料流程,取消订单:{code}"); @@ -541,7 +541,7 @@ namespace BPASmartClient.JXJFoodSmallStation.Model { for (int i = 0; i < 5; i++) { - if (GVL_SmallStation.GetInstance.NotUseSmallStation) + if (GVL_SmallStation.GetInstance.NotUseSmallStation) { if (RecipeQueueTray[i].Count == 0 && !RecipeQueueTray[0].Contains(data.RecipeCode) && !RecipeQueueTray[1].Contains(data.RecipeCode) && !RecipeQueueTray[2].Contains(data.RecipeCode) && !RecipeQueueTray[3].Contains(data.RecipeCode) && !RecipeQueueTray[4].Contains(data.RecipeCode)) { @@ -549,9 +549,9 @@ namespace BPASmartClient.JXJFoodSmallStation.Model MessageNotify.GetInstance.ShowRunLog($"本地配方配料 ,不使用小料配料,配方{data.RecipeCode},加入配方{i}"); } } - else if(GVL_SmallStation.GetInstance.PlcAllowIssueRecipe[i]) + else if (GVL_SmallStation.GetInstance.PlcAllowIssueRecipe[i]) { - if (RecipeQueueTray[i].Count==0 && !RecipeQueueTray[0].Contains(data.RecipeCode) && !RecipeQueueTray[1].Contains(data.RecipeCode) && !RecipeQueueTray[2].Contains(data.RecipeCode) && !RecipeQueueTray[3].Contains(data.RecipeCode) && !RecipeQueueTray[4].Contains(data.RecipeCode)) + if (RecipeQueueTray[i].Count == 0 && !RecipeQueueTray[0].Contains(data.RecipeCode) && !RecipeQueueTray[1].Contains(data.RecipeCode) && !RecipeQueueTray[2].Contains(data.RecipeCode) && !RecipeQueueTray[3].Contains(data.RecipeCode) && !RecipeQueueTray[4].Contains(data.RecipeCode)) { RecipeQueueTray[i].Enqueue(data.RecipeCode); MessageNotify.GetInstance.ShowRunLog($"本地配方配料 ,等待plc允许配料,配方{data.RecipeCode},加入配方{i}"); @@ -829,7 +829,7 @@ namespace BPASmartClient.JXJFoodSmallStation.Model HKDevice.HK_PLC_S7.Write("DB44.DBX3.0", true); App.Current.Dispatcher.Invoke(() => { - MessageNotify.GetInstance.ShowDialog($"{i}号仓配料误差过大,设置出料重量{ RemoteRecipes.ElementAt(index).RawMaterial.ElementAt(res).RawMaterialWeight * 1000}g,实际出料重量{RemoteRecipes.ElementAt(index).RawMaterial.ElementAt(res).Laying_Off_Weight}g,相差{AlarmRange}g,允许误差为{Math.Abs(Json.Data.deviceParModels.ElementAt(iIndex).ErrorRange)}g,请联系人工处理", DialogType.Warning); + MessageNotify.GetInstance.ShowDialog($"{i}号仓配料误差过大,设置出料重量{RemoteRecipes.ElementAt(index).RawMaterial.ElementAt(res).RawMaterialWeight * 1000}g,实际出料重量{RemoteRecipes.ElementAt(index).RawMaterial.ElementAt(res).Laying_Off_Weight}g,相差{AlarmRange}g,允许误差为{Math.Abs(Json.Data.deviceParModels.ElementAt(iIndex).ErrorRange)}g,请联系人工处理", DialogType.Warning); HKDevice.HK_PLC_S7.Write("DB44.DBX3.0", false); }); } @@ -983,7 +983,7 @@ namespace BPASmartClient.JXJFoodSmallStation.Model } } } - public void RegisterInit() + public void RegisterInit() { //手动控制气缸 DB5.DBX0.0~DB5.DBX4.5 ActionManage.GetInstance.Register(new Action((o) => @@ -1203,7 +1203,8 @@ namespace BPASmartClient.JXJFoodSmallStation.Model break; } } - App.Current.Dispatcher.Invoke(() => { + App.Current.Dispatcher.Invoke(() => + { Json.Data.Recipes.Add(new RemoteRecipeData() { RecipeName = recipe.RecipeName, @@ -1226,7 +1227,7 @@ namespace BPASmartClient.JXJFoodSmallStation.Model Json.Data.Recipes.Add(recipe); } }), "LocalSimulationRecipeIssue", true); - + //手动控制系统模式 ActionManage.GetInstance.Register(new Action(() => { HKDevice.HK_PLC_S7.Write("DB44.DBX0.0", true); }), "SystemStart", true); ActionManage.GetInstance.Register(new Action(() => { HKDevice.HK_PLC_S7.Write("DB44.DBX0.0", false); }), "SystemStop", true); @@ -1261,14 +1262,14 @@ namespace BPASmartClient.JXJFoodSmallStation.Model }), "BPASystemReset", true); //往海科PLC写值 - ActionManage.GetInstance.Register(new Action((o) => + ActionManage.GetInstance.Register(new Action((o) => { - if (o != null && o is HKDeviceWrite data) + if (o != null && o is HKDeviceWrite data) { - if (data.PlcVarType == PlcVarType.Bool) + if (data.PlcVarType == PlcVarType.Bool) { bool value = (bool)data.Value; - HKDevice.HK_PLC_S7.Write(data.Address , value); + HKDevice.HK_PLC_S7.Write(data.Address, value); } else if (data.PlcVarType == PlcVarType.Byte) { @@ -1352,9 +1353,9 @@ namespace BPASmartClient.JXJFoodSmallStation.Model HKDevice.HK_PLC_S7.Write("DB4.DBB1", (byte)Value); } }), "RobotSetProgramNum", true); - + } - public void DeviceConnect() + public void DeviceConnect() { try { diff --git a/BPASmartClient.JXJFoodSmallStation/Model/RawMaterial/DeviceInquire.cs b/BPASmartClient.JXJFoodSmallStation/Model/RawMaterial/DeviceInquire.cs index 8a093b5d..f978f85f 100644 --- a/BPASmartClient.JXJFoodSmallStation/Model/RawMaterial/DeviceInquire.cs +++ b/BPASmartClient.JXJFoodSmallStation/Model/RawMaterial/DeviceInquire.cs @@ -12,6 +12,7 @@ using System.Net.NetworkInformation; using System.Threading; using System.Threading.Tasks; using System.Configuration; +using System.Diagnostics; namespace BPASmartClient.JXJFoodSmallStation.Model { @@ -21,9 +22,9 @@ namespace BPASmartClient.JXJFoodSmallStation.Model public static DeviceInquire GetInstance => _Instance ?? (_Instance = new DeviceInquire()); private DeviceInquire() { } - string IPSegment = "107.107.2."; + string IPSegment = "107.107.2."; - ConcurrentDictionary DeviceLists = new ConcurrentDictionary(); + ConcurrentDictionary DeviceLists = new ConcurrentDictionary(); List InvalidIP = new List();//无效 IP 集合 List IPLists = new List();//启动 Ping 任务IP集合 ConcurrentQueue IPQueues = new ConcurrentQueue();//pincomplete 完成队列 @@ -57,14 +58,14 @@ namespace BPASmartClient.JXJFoodSmallStation.Model { devices.ElementAt(deviceIndex).DeviceName = DeviceLists.ElementAt(i).Value.DeviceName; } - if (!ThreadManage.GetInstance().IsContainsKey($"{deviceName} 开始监听")) + if (!ThreadManage.GetInstance().IsContainsKey($"{deviceName} 开始监听")) { DeviceLists[DeviceLists.ElementAt(i).Key].Init(deviceName); } } - + Thread.Sleep(200); - }), "设备状态监听",true); + }), "设备状态监听", true); } private void TestData() { @@ -169,7 +170,7 @@ namespace BPASmartClient.JXJFoodSmallStation.Model { IPLists.Add($"{IPSegment}{i + 69}"); } - + IPLists.ForEach((item) => { @@ -361,7 +362,7 @@ namespace BPASmartClient.JXJFoodSmallStation.Model //允许配料即产线气缸抬起,发送给味魔方 if (deviceStatus.DeviceNum >= 1 && deviceStatus.DeviceNum <= 15) { - if (GVL_SmallStation.GetInstance.plcReadDataDB3.StockBinAllowIssue[deviceStatus.DeviceNum-1]) + if (GVL_SmallStation.GetInstance.plcReadDataDB3.StockBinAllowIssue[deviceStatus.DeviceNum - 1]) { this.modbusTcp.Write("LW41", (ushort)1); GVL_SmallStation.GetInstance.StockBinCylinderStatus.SetBitValue((byte)(deviceStatus.DeviceNum), true); @@ -395,57 +396,85 @@ namespace BPASmartClient.JXJFoodSmallStation.Model ThreadManage.GetInstance().StopTask($"{DeviceName} 开始监听"); } + public void Start(float Value) { + //if (modbusTcp.Connected) + //{ + // var res = Json.Data.deviceParModels.FirstOrDefault(p => p.MaterialName == DeviceName); + // if (res != null) + // { + // prop1: + // modbusTcp.SetReal(DeviceAddress.SlowlyAddWeight, res.SlowlyAddWeight); + // var Value1 = (float)this.modbusTcp.GetReal(DeviceAddress.SlowlyAddWeight); + // if (Value1 != null && Value1.ToString() != res.SlowlyAddWeight.ToString()) goto prop1; + // prop2: + // modbusTcp.SetReal(DeviceAddress.PreCloseValveWeight, res.PreCloseValveWeight); + // var Value2 = (float)this.modbusTcp.GetReal(DeviceAddress.PreCloseValveWeight); + // if (Value2 != null && Value2.ToString() != res.PreCloseValveWeight.ToString()) goto prop2; + // prop3: + // modbusTcp.SetUint(DeviceAddress.RapidAcceleration, (uint)res.RapidAcceleration); + // var Value3 = this.modbusTcp.GetUint(DeviceAddress.RapidAcceleration); + // if (Value3 != null && Value3.ToString() != res.RapidAcceleration.ToString()) goto prop3; + // prop4: + // modbusTcp.SetUint(DeviceAddress.SlowAcceleration, (uint)res.SlowAcceleration); + // var Value4 = this.modbusTcp.GetUint(DeviceAddress.SlowAcceleration); + // if (Value4 != null && Value4.ToString() != res.SlowAcceleration.ToString()) goto prop4; + // prop5: + // modbusTcp.SetUint(DeviceAddress.ServoManualSpeed, (uint)res.ServoManualSpeed); + // var Value5 = this.modbusTcp.GetUint(DeviceAddress.ServoManualSpeed); + // if (Value5 != null && Value5.ToString() != res.ServoManualSpeed.ToString()) goto prop5; + // prop6: + // modbusTcp.SetUint(DeviceAddress.SiloUpperLimitWeight, (uint)res.SiloUpperLimitWeight); + // var Value6 = this.modbusTcp.GetUint(DeviceAddress.SiloUpperLimitWeight); + // if (Value6 != null && Value6.ToString() != res.SiloUpperLimitWeight.ToString()) goto prop6; + // prop7: + // modbusTcp.SetUint(DeviceAddress.LowerLimitWeightOfSilo, (uint)res.LowerLimitWeightOfSilo); + // var Value7 = this.modbusTcp.GetUint(DeviceAddress.LowerLimitWeightOfSilo); + // if (Value7 != null && Value7.ToString() != res.LowerLimitWeightOfSilo.ToString()) goto prop7; + // /*prop8: + // var Value8 = this.modbusTcp.GetUint(DeviceAddress.StirringSpeed); + // if (Value8 != null && Value8.ToString() != num.ToString()) goto prop8;*/ + // uint num = (uint)res.StirringSpeed * 100; + // modbusTcp.SetUint(DeviceAddress.StirringSpeed, num); + // MessageNotify.GetInstance.ShowRunLog($"{res.MaterialName},参数下发完成"); + // } + // int Count = 0; + //Start: + // Count++; + // modbusTcp.SetReal(DeviceAddress.WeightSet, Value);//写入原料重量 + // modbusTcp.Write(DeviceAddress.Start, (ushort)1);//设备启动写入 + // MessageNotify.GetInstance.ShowRunLog($"{DeviceName},设置重量:{Value},下发次数{Count},柔性味魔方开始配料"); + // Thread.Sleep(200); + // if (this.modbusTcp.ReadShort(DeviceAddress.DosingStatusFeedback) == (short)0 && Count <=10) goto Start; + //} + + + if (modbusTcp.Connected) { var res = Json.Data.deviceParModels.FirstOrDefault(p => p.MaterialName == DeviceName); if (res != null) { - prop1: modbusTcp.SetReal(DeviceAddress.SlowlyAddWeight, res.SlowlyAddWeight); - var Value1 = (float)this.modbusTcp.GetReal(DeviceAddress.SlowlyAddWeight); - if (Value1 != null && Value1.ToString() != res.SlowlyAddWeight.ToString()) goto prop1; - prop2: modbusTcp.SetReal(DeviceAddress.PreCloseValveWeight, res.PreCloseValveWeight); - var Value2 = (float)this.modbusTcp.GetReal(DeviceAddress.PreCloseValveWeight); - if (Value2 != null && Value2.ToString() != res.PreCloseValveWeight.ToString()) goto prop2; - prop3: modbusTcp.SetUint(DeviceAddress.RapidAcceleration, (uint)res.RapidAcceleration); - var Value3 = this.modbusTcp.GetUint(DeviceAddress.RapidAcceleration); - if (Value3 != null && Value3.ToString() != res.RapidAcceleration.ToString()) goto prop3; - prop4: modbusTcp.SetUint(DeviceAddress.SlowAcceleration, (uint)res.SlowAcceleration); - var Value4 = this.modbusTcp.GetUint(DeviceAddress.SlowAcceleration); - if (Value4 != null && Value4.ToString() != res.SlowAcceleration.ToString()) goto prop4; - prop5: modbusTcp.SetUint(DeviceAddress.ServoManualSpeed, (uint)res.ServoManualSpeed); - var Value5 = this.modbusTcp.GetUint(DeviceAddress.ServoManualSpeed); - if (Value5 != null && Value5.ToString() != res.ServoManualSpeed.ToString()) goto prop5; - prop6: modbusTcp.SetUint(DeviceAddress.SiloUpperLimitWeight, (uint)res.SiloUpperLimitWeight); - var Value6 = this.modbusTcp.GetUint(DeviceAddress.SiloUpperLimitWeight); - if (Value6 != null && Value6.ToString() != res.SiloUpperLimitWeight.ToString()) goto prop6; - prop7: modbusTcp.SetUint(DeviceAddress.LowerLimitWeightOfSilo, (uint)res.LowerLimitWeightOfSilo); - var Value7 = this.modbusTcp.GetUint(DeviceAddress.LowerLimitWeightOfSilo); - if (Value7 != null && Value7.ToString() != res.LowerLimitWeightOfSilo.ToString()) goto prop7; - /*prop8: - var Value8 = this.modbusTcp.GetUint(DeviceAddress.StirringSpeed); - if (Value8 != null && Value8.ToString() != num.ToString()) goto prop8;*/ - uint num = (uint)res.StirringSpeed * 100; - modbusTcp.SetUint(DeviceAddress.StirringSpeed, num); + modbusTcp.SetUint(DeviceAddress.StirringSpeed, (uint)res.StirringSpeed * 100); MessageNotify.GetInstance.ShowRunLog($"{res.MaterialName},参数下发完成"); } - int Count = 0; - Start: - Count++; modbusTcp.SetReal(DeviceAddress.WeightSet, Value);//写入原料重量 modbusTcp.Write(DeviceAddress.Start, (ushort)1);//设备启动写入 - MessageNotify.GetInstance.ShowRunLog($"{DeviceName},设置重量:{Value},下发次数{Count},柔性味魔方开始配料"); - Thread.Sleep(200); - if (this.modbusTcp.ReadShort(DeviceAddress.DosingStatusFeedback) == (short)0 && Count <=10) goto Start; + MessageNotify.GetInstance.ShowRunLog($"{DeviceName},设置重量:{Value},柔性味魔方开始配料"); } + + + + + } } } diff --git a/BPASmartClient.JXJFoodSmallStation/View/ManualControlView.xaml b/BPASmartClient.JXJFoodSmallStation/View/ManualControlView.xaml index be9d4c47..b65d8248 100644 --- a/BPASmartClient.JXJFoodSmallStation/View/ManualControlView.xaml +++ b/BPASmartClient.JXJFoodSmallStation/View/ManualControlView.xaml @@ -55,10 +55,10 @@ - - - - + + + + - - + + - - + + - - + + - - - + + + - - - - + + + + - - + + - - + + - - - - + + + + - - - - - + - - - - - + + + + + - + - - + + - - + + - - + - - + - - + + - - + + - - + - - - + + - - + + - - + - - + - - + + - - + + - - + - - - + + - - + + - - + - - + diff --git a/BPASmartClient.JXJFoodSmallStation/View/ManualFlowView.xaml b/BPASmartClient.JXJFoodSmallStation/View/ManualFlowView.xaml index 5622c4c9..4b6e9284 100644 --- a/BPASmartClient.JXJFoodSmallStation/View/ManualFlowView.xaml +++ b/BPASmartClient.JXJFoodSmallStation/View/ManualFlowView.xaml @@ -1,12 +1,14 @@ - + @@ -20,56 +22,59 @@ - + + Style="{StaticResource ImageButtonStyle}" + Visibility="{Binding VisibilityBtn1}" /> + Style="{StaticResource ImageButtonStyle}" + Visibility="{Binding VisibilityBtn2}" /> + Style="{StaticResource ImageButtonStyle}" + Visibility="{Binding VisibilityBtn3}" /> + Foreground="#FF2AB2E7" /> + Style="{StaticResource ImageButtonStyle}" /> + Style="{StaticResource ImageButtonStyle}" /> - + + Style="{StaticResource ImageButtonStyle}" /> + Style="{StaticResource ImageButtonStyle}" /> @@ -113,90 +121,292 @@ - - - - - + + + + + - - - - + + + + + + - - - - - - + + + + + + - - + + - - - + + + + Style="{StaticResource ImageButtonStyle}" /> - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + + Style="{StaticResource ImageButtonStyle}" /> + Style="{StaticResource ImageButtonStyle}" /> diff --git a/BPASmartClient.JXJFoodSmallStation/View/NewLocalRecipeView.xaml b/BPASmartClient.JXJFoodSmallStation/View/NewLocalRecipeView.xaml index 05c57b81..40a7fdf4 100644 --- a/BPASmartClient.JXJFoodSmallStation/View/NewLocalRecipeView.xaml +++ b/BPASmartClient.JXJFoodSmallStation/View/NewLocalRecipeView.xaml @@ -69,10 +69,13 @@ - - + + - + - + - + - +